Codebase list haxe / b75902f
New upstream version 4.3.0 Andy Li 9 months ago
1316 changed file(s) with 35408 addition(s) and 13418 deletion(s). Raw diff Collapse all Expand all
0 // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
1 // https://github.com/microsoft/vscode-dev-containers/tree/v0.202.5/containers/docker-from-docker-compose
2 {
3 "name": "haxe",
4 "dockerComposeFile": "docker-compose.yml",
5 "service": "workspace",
6 "workspaceFolder": "/workspace",
7
8 // Use this environment variable if you need to bind mount your local source code into a new container.
9 "remoteEnv": {
10 "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
11 },
12
13 // Set *default* container specific settings.json values on container create.
14 "settings": {},
15
16 "extensions": [
17 "nadako.vshaxe",
18 "ms-azuretools.vscode-docker",
19 "earthly.earthfile-syntax-highlighting",
20 ],
21
22 "remoteUser": "vscode"
23 }
0 version: '3'
1 services:
2 workspace:
3 image: ghcr.io/haxefoundation/haxe_devcontainer:development
4 init: true
5 volumes:
6 - /var/run/docker.sock:/var/run/docker-host.sock
7 - ..:/workspace:cached
8 environment:
9 - EARTHLY_BUILDKIT_HOST=tcp://earthly:8372
10 - EARTHLY_USE_INLINE_CACHE=true
11 - EARTHLY_SAVE_INLINE_CACHE=true
12 user: vscode
13 entrypoint: /usr/local/share/docker-init.sh
14 command: sleep infinity
15 earthly:
16 image: earthly/buildkitd:v0.6.13
17 privileged: true
18 environment:
19 - BUILDKIT_TCP_TRANSPORT_ENABLED=true
20 expose:
21 - 8372
22 volumes:
23 # https://docs.earthly.dev/docs/guides/using-the-earthly-docker-images/buildkit-standalone#earthly_tmp_dir
24 - earthly-tmp:/tmp/earthly:rw
25
26 volumes:
27 earthly-tmp:
0 #!/usr/bin/env bash
1 #-------------------------------------------------------------------------------------------------------------
2 # Copyright (c) Microsoft Corporation. All rights reserved.
3 # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
4 #-------------------------------------------------------------------------------------------------------------
5 #
6 # Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/common.md
7 # Maintainer: The VS Code and Codespaces Teams
8 #
9 # Syntax: ./common-debian.sh [install zsh flag] [username] [user UID] [user GID] [upgrade packages flag] [install Oh My Zsh! flag] [Add non-free packages]
10
11 set -e
12
13 INSTALL_ZSH=${1:-"true"}
14 USERNAME=${2:-"automatic"}
15 USER_UID=${3:-"automatic"}
16 USER_GID=${4:-"automatic"}
17 UPGRADE_PACKAGES=${5:-"true"}
18 INSTALL_OH_MYS=${6:-"true"}
19 ADD_NON_FREE_PACKAGES=${7:-"false"}
20 SCRIPT_DIR="$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)"
21 MARKER_FILE="/usr/local/etc/vscode-dev-containers/common"
22
23 if [ "$(id -u)" -ne 0 ]; then
24 echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
25 exit 1
26 fi
27
28 # Ensure that login shells get the correct path if the user updated the PATH using ENV.
29 rm -f /etc/profile.d/00-restore-env.sh
30 echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
31 chmod +x /etc/profile.d/00-restore-env.sh
32
33 # If in automatic mode, determine if a user already exists, if not use vscode
34 if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
35 USERNAME=""
36 POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
37 for CURRENT_USER in ${POSSIBLE_USERS[@]}; do
38 if id -u ${CURRENT_USER} > /dev/null 2>&1; then
39 USERNAME=${CURRENT_USER}
40 break
41 fi
42 done
43 if [ "${USERNAME}" = "" ]; then
44 USERNAME=vscode
45 fi
46 elif [ "${USERNAME}" = "none" ]; then
47 USERNAME=root
48 USER_UID=0
49 USER_GID=0
50 fi
51
52 # Load markers to see which steps have already run
53 if [ -f "${MARKER_FILE}" ]; then
54 echo "Marker file found:"
55 cat "${MARKER_FILE}"
56 source "${MARKER_FILE}"
57 fi
58
59 # Ensure apt is in non-interactive to avoid prompts
60 export DEBIAN_FRONTEND=noninteractive
61
62 # Function to call apt-get if needed
63 apt_get_update_if_needed()
64 {
65 if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
66 echo "Running apt-get update..."
67 apt-get update
68 else
69 echo "Skipping apt-get update."
70 fi
71 }
72
73 # Run install apt-utils to avoid debconf warning then verify presence of other common developer tools and dependencies
74 if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
75
76 package_list="apt-utils \
77 openssh-client \
78 gnupg2 \
79 dirmngr \
80 iproute2 \
81 procps \
82 lsof \
83 htop \
84 net-tools \
85 psmisc \
86 curl \
87 wget \
88 rsync \
89 ca-certificates \
90 unzip \
91 zip \
92 nano \
93 vim-tiny \
94 less \
95 jq \
96 lsb-release \
97 apt-transport-https \
98 dialog \
99 libc6 \
100 libgcc1 \
101 libkrb5-3 \
102 libgssapi-krb5-2 \
103 libicu[0-9][0-9] \
104 liblttng-ust0 \
105 libstdc++6 \
106 zlib1g \
107 locales \
108 sudo \
109 ncdu \
110 man-db \
111 strace \
112 manpages \
113 manpages-dev \
114 init-system-helpers"
115
116 # Needed for adding manpages-posix and manpages-posix-dev which are non-free packages in Debian
117 if [ "${ADD_NON_FREE_PACKAGES}" = "true" ]; then
118 # Bring in variables from /etc/os-release like VERSION_CODENAME
119 . /etc/os-release
120 sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list
121 sed -i -E "s/deb-src http:\/\/(deb|httredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list
122 sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list
123 sed -i -E "s/deb-src http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list
124 sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list
125 sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list
126 sed -i "s/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list
127 sed -i "s/deb-src http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list
128 # Handle bullseye location for security https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html
129 sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list
130 sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list
131 echo "Running apt-get update..."
132 apt-get update
133 package_list="${package_list} manpages-posix manpages-posix-dev"
134 else
135 apt_get_update_if_needed
136 fi
137
138 # Install libssl1.1 if available
139 if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then
140 package_list="${package_list} libssl1.1"
141 fi
142
143 # Install appropriate version of libssl1.0.x if available
144 libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '')
145 if [ "$(echo "$LIlibssl_packageBSSL" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then
146 if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then
147 # Debian 9
148 package_list="${package_list} libssl1.0.2"
149 elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then
150 # Ubuntu 18.04, 16.04, earlier
151 package_list="${package_list} libssl1.0.0"
152 fi
153 fi
154
155 echo "Packages to verify are installed: ${package_list}"
156 apt-get -y install --no-install-recommends ${package_list} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 )
157
158 # Install git if not already installed (may be more recent than distro version)
159 if ! type git > /dev/null 2>&1; then
160 apt-get -y install --no-install-recommends git
161 fi
162
163 PACKAGES_ALREADY_INSTALLED="true"
164 fi
165
166 # Get to latest versions of all packages
167 if [ "${UPGRADE_PACKAGES}" = "true" ]; then
168 apt_get_update_if_needed
169 apt-get -y upgrade --no-install-recommends
170 apt-get autoremove -y
171 fi
172
173 # Ensure at least the en_US.UTF-8 UTF-8 locale is available.
174 # Common need for both applications and things like the agnoster ZSH theme.
175 if [ "${LOCALE_ALREADY_SET}" != "true" ] && ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then
176 echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
177 locale-gen
178 LOCALE_ALREADY_SET="true"
179 fi
180
181 # Create or update a non-root user to match UID/GID.
182 group_name="${USERNAME}"
183 if id -u ${USERNAME} > /dev/null 2>&1; then
184 # User exists, update if needed
185 if [ "${USER_GID}" != "automatic" ] && [ "$USER_GID" != "$(id -g $USERNAME)" ]; then
186 group_name="$(id -gn $USERNAME)"
187 groupmod --gid $USER_GID ${group_name}
188 usermod --gid $USER_GID $USERNAME
189 fi
190 if [ "${USER_UID}" != "automatic" ] && [ "$USER_UID" != "$(id -u $USERNAME)" ]; then
191 usermod --uid $USER_UID $USERNAME
192 fi
193 else
194 # Create user
195 if [ "${USER_GID}" = "automatic" ]; then
196 groupadd $USERNAME
197 else
198 groupadd --gid $USER_GID $USERNAME
199 fi
200 if [ "${USER_UID}" = "automatic" ]; then
201 useradd -s /bin/bash --gid $USERNAME -m $USERNAME
202 else
203 useradd -s /bin/bash --uid $USER_UID --gid $USERNAME -m $USERNAME
204 fi
205 fi
206
207 # Add add sudo support for non-root user
208 if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then
209 echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME
210 chmod 0440 /etc/sudoers.d/$USERNAME
211 EXISTING_NON_ROOT_USER="${USERNAME}"
212 fi
213
214 # ** Shell customization section **
215 if [ "${USERNAME}" = "root" ]; then
216 user_rc_path="/root"
217 else
218 user_rc_path="/home/${USERNAME}"
219 fi
220
221 # Restore user .bashrc defaults from skeleton file if it doesn't exist or is empty
222 if [ ! -f "${user_rc_path}/.bashrc" ] || [ ! -s "${user_rc_path}/.bashrc" ] ; then
223 cp /etc/skel/.bashrc "${user_rc_path}/.bashrc"
224 fi
225
226 # Restore user .profile defaults from skeleton file if it doesn't exist or is empty
227 if [ ! -f "${user_rc_path}/.profile" ] || [ ! -s "${user_rc_path}/.profile" ] ; then
228 cp /etc/skel/.profile "${user_rc_path}/.profile"
229 fi
230
231 # .bashrc/.zshrc snippet
232 rc_snippet="$(cat << 'EOF'
233
234 if [ -z "${USER}" ]; then export USER=$(whoami); fi
235 if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi
236
237 # Display optional first run image specific notice if configured and terminal is interactive
238 if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then
239 if [ -f "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" ]; then
240 cat "/usr/local/etc/vscode-dev-containers/first-run-notice.txt"
241 elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then
242 cat "/workspaces/.codespaces/shared/first-run-notice.txt"
243 fi
244 mkdir -p "$HOME/.config/vscode-dev-containers"
245 # Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it
246 ((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &)
247 fi
248
249 # Set the default git editor if not already set
250 if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then
251 if [ "${TERM_PROGRAM}" = "vscode" ]; then
252 if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then
253 export GIT_EDITOR="code-insiders --wait"
254 else
255 export GIT_EDITOR="code --wait"
256 fi
257 fi
258 fi
259
260 EOF
261 )"
262
263 # code shim, it fallbacks to code-insiders if code is not available
264 cat << 'EOF' > /usr/local/bin/code
265 #!/bin/sh
266
267 get_in_path_except_current() {
268 which -a "$1" | grep -A1 "$0" | grep -v "$0"
269 }
270
271 code="$(get_in_path_except_current code)"
272
273 if [ -n "$code" ]; then
274 exec "$code" "$@"
275 elif [ "$(command -v code-insiders)" ]; then
276 exec code-insiders "$@"
277 else
278 echo "code or code-insiders is not installed" >&2
279 exit 127
280 fi
281 EOF
282 chmod +x /usr/local/bin/code
283
284 # systemctl shim - tells people to use 'service' if systemd is not running
285 cat << 'EOF' > /usr/local/bin/systemctl
286 #!/bin/sh
287 set -e
288 if [ -d "/run/systemd/system" ]; then
289 exec /bin/systemctl/systemctl "$@"
290 else
291 echo '\n"systemd" is not running in this container due to its overhead.\nUse the "service" command to start services intead. e.g.: \n\nservice --status-all'
292 fi
293 EOF
294 chmod +x /usr/local/bin/systemctl
295
296 # Codespaces bash and OMZ themes - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme
297 codespaces_bash="$(cat \
298 <<'EOF'
299
300 # Codespaces bash prompt theme
301 __bash_prompt() {
302 local userpart='`export XIT=$? \
303 && [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \
304 && [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`'
305 local gitbranch='`\
306 if [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \
307 export BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null); \
308 if [ "${BRANCH}" != "" ]; then \
309 echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \
310 && if git ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \
311 echo -n " \[\033[1;33m\]✗"; \
312 fi \
313 && echo -n "\[\033[0;36m\]) "; \
314 fi; \
315 fi`'
316 local lightblue='\[\033[1;34m\]'
317 local removecolor='\[\033[0m\]'
318 PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ "
319 unset -f __bash_prompt
320 }
321 __bash_prompt
322
323 EOF
324 )"
325
326 codespaces_zsh="$(cat \
327 <<'EOF'
328 # Codespaces zsh prompt theme
329 __zsh_prompt() {
330 local prompt_username
331 if [ ! -z "${GITHUB_USER}" ]; then
332 prompt_username="@${GITHUB_USER}"
333 else
334 prompt_username="%n"
335 fi
336 PROMPT="%{$fg[green]%}${prompt_username} %(?:%{$reset_color%}➜ :%{$fg_bold[red]%}➜ )" # User/exit code arrow
337 PROMPT+='%{$fg_bold[blue]%}%(5~|%-1~/…/%3~|%4~)%{$reset_color%} ' # cwd
338 PROMPT+='$([ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ] && git_prompt_info)' # Git status
339 PROMPT+='%{$fg[white]%}$ %{$reset_color%}'
340 unset -f __zsh_prompt
341 }
342 ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[cyan]%}(%{$fg_bold[red]%}"
343 ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} "
344 ZSH_THEME_GIT_PROMPT_DIRTY=" %{$fg_bold[yellow]%}✗%{$fg_bold[cyan]%})"
345 ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg_bold[cyan]%})"
346 __zsh_prompt
347
348 EOF
349 )"
350
351 # Add RC snippet and custom bash prompt
352 if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then
353 echo "${rc_snippet}" >> /etc/bash.bashrc
354 echo "${codespaces_bash}" >> "${user_rc_path}/.bashrc"
355 echo 'export PROMPT_DIRTRIM=4' >> "${user_rc_path}/.bashrc"
356 if [ "${USERNAME}" != "root" ]; then
357 echo "${codespaces_bash}" >> "/root/.bashrc"
358 echo 'export PROMPT_DIRTRIM=4' >> "/root/.bashrc"
359 fi
360 chown ${USERNAME}:${group_name} "${user_rc_path}/.bashrc"
361 RC_SNIPPET_ALREADY_ADDED="true"
362 fi
363
364 # Optionally install and configure zsh and Oh My Zsh!
365 if [ "${INSTALL_ZSH}" = "true" ]; then
366 if ! type zsh > /dev/null 2>&1; then
367 apt_get_update_if_needed
368 apt-get install -y zsh
369 fi
370 if [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then
371 echo "${rc_snippet}" >> /etc/zsh/zshrc
372 ZSH_ALREADY_INSTALLED="true"
373 fi
374
375 # Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme.
376 # See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script.
377 oh_my_install_dir="${user_rc_path}/.oh-my-zsh"
378 if [ ! -d "${oh_my_install_dir}" ] && [ "${INSTALL_OH_MYS}" = "true" ]; then
379 template_path="${oh_my_install_dir}/templates/zshrc.zsh-template"
380 user_rc_file="${user_rc_path}/.zshrc"
381 umask g-w,o-w
382 mkdir -p ${oh_my_install_dir}
383 git clone --depth=1 \
384 -c core.eol=lf \
385 -c core.autocrlf=false \
386 -c fsck.zeroPaddedFilemode=ignore \
387 -c fetch.fsck.zeroPaddedFilemode=ignore \
388 -c receive.fsck.zeroPaddedFilemode=ignore \
389 "https://github.com/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1
390 echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file}
391 sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="codespaces"/g' ${user_rc_file}
392
393 mkdir -p ${oh_my_install_dir}/custom/themes
394 echo "${codespaces_zsh}" > "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme"
395 # Shrink git while still enabling updates
396 cd "${oh_my_install_dir}"
397 git repack -a -d -f --depth=1 --window=1
398 # Copy to non-root user if one is specified
399 if [ "${USERNAME}" != "root" ]; then
400 cp -rf "${user_rc_file}" "${oh_my_install_dir}" /root
401 chown -R ${USERNAME}:${group_name} "${user_rc_path}"
402 fi
403 fi
404 fi
405
406 # Persist image metadata info, script if meta.env found in same directory
407 meta_info_script="$(cat << 'EOF'
408 #!/bin/sh
409 . /usr/local/etc/vscode-dev-containers/meta.env
410
411 # Minimal output
412 if [ "$1" = "version" ] || [ "$1" = "image-version" ]; then
413 echo "${VERSION}"
414 exit 0
415 elif [ "$1" = "release" ]; then
416 echo "${GIT_REPOSITORY_RELEASE}"
417 exit 0
418 elif [ "$1" = "content" ] || [ "$1" = "content-url" ] || [ "$1" = "contents" ] || [ "$1" = "contents-url" ]; then
419 echo "${CONTENTS_URL}"
420 exit 0
421 fi
422
423 #Full output
424 echo
425 echo "Development container image information"
426 echo
427 if [ ! -z "${VERSION}" ]; then echo "- Image version: ${VERSION}"; fi
428 if [ ! -z "${DEFINITION_ID}" ]; then echo "- Definition ID: ${DEFINITION_ID}"; fi
429 if [ ! -z "${VARIANT}" ]; then echo "- Variant: ${VARIANT}"; fi
430 if [ ! -z "${GIT_REPOSITORY}" ]; then echo "- Source code repository: ${GIT_REPOSITORY}"; fi
431 if [ ! -z "${GIT_REPOSITORY_RELEASE}" ]; then echo "- Source code release/branch: ${GIT_REPOSITORY_RELEASE}"; fi
432 if [ ! -z "${BUILD_TIMESTAMP}" ]; then echo "- Timestamp: ${BUILD_TIMESTAMP}"; fi
433 if [ ! -z "${CONTENTS_URL}" ]; then echo && echo "More info: ${CONTENTS_URL}"; fi
434 echo
435 EOF
436 )"
437 if [ -f "${SCRIPT_DIR}/meta.env" ]; then
438 mkdir -p /usr/local/etc/vscode-dev-containers/
439 cp -f "${SCRIPT_DIR}/meta.env" /usr/local/etc/vscode-dev-containers/meta.env
440 echo "${meta_info_script}" > /usr/local/bin/devcontainer-info
441 chmod +x /usr/local/bin/devcontainer-info
442 fi
443
444 # Write marker file
445 mkdir -p "$(dirname "${MARKER_FILE}")"
446 echo -e "\
447 PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\
448 LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\
449 EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\
450 RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\
451 ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}"
452
453 echo "Done!"
0 #!/usr/bin/env bash
1 #-------------------------------------------------------------------------------------------------------------
2 # Copyright (c) Microsoft Corporation. All rights reserved.
3 # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
4 #-------------------------------------------------------------------------------------------------------------
5 #
6 # Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker.md
7 # Maintainer: The VS Code and Codespaces Teams
8 #
9 # Syntax: ./docker-debian.sh [enable non-root docker socket access flag] [source socket] [target socket] [non-root user] [use moby] [CLI version]
10
11 ENABLE_NONROOT_DOCKER=${1:-"true"}
12 SOURCE_SOCKET=${2:-"/var/run/docker-host.sock"}
13 TARGET_SOCKET=${3:-"/var/run/docker.sock"}
14 USERNAME=${4:-"automatic"}
15 USE_MOBY=${5:-"true"}
16 DOCKER_VERSION=${6:-"latest"}
17 MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
18 DOCKER_DASH_COMPOSE_VERSION="1"
19
20 set -e
21
22 if [ "$(id -u)" -ne 0 ]; then
23 echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
24 exit 1
25 fi
26
27 # Determine the appropriate non-root user
28 if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
29 USERNAME=""
30 POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
31 for CURRENT_USER in ${POSSIBLE_USERS[@]}; do
32 if id -u ${CURRENT_USER} > /dev/null 2>&1; then
33 USERNAME=${CURRENT_USER}
34 break
35 fi
36 done
37 if [ "${USERNAME}" = "" ]; then
38 USERNAME=root
39 fi
40 elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
41 USERNAME=root
42 fi
43
44 # Get central common setting
45 get_common_setting() {
46 if [ "${common_settings_file_loaded}" != "true" ]; then
47 curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
48 common_settings_file_loaded=true
49 fi
50 if [ -f "/tmp/vsdc-settings.env" ]; then
51 local multi_line=""
52 if [ "$2" = "true" ]; then multi_line="-z"; fi
53 local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
54 if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
55 fi
56 echo "$1=${!1}"
57 }
58
59 # Function to run apt-get if needed
60 apt_get_update_if_needed()
61 {
62 if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
63 echo "Running apt-get update..."
64 apt-get update
65 else
66 echo "Skipping apt-get update."
67 fi
68 }
69
70 # Checks if packages are installed and installs them if not
71 check_packages() {
72 if ! dpkg -s "$@" > /dev/null 2>&1; then
73 apt_get_update_if_needed
74 apt-get -y install --no-install-recommends "$@"
75 fi
76 }
77
78 # Figure out correct version of a three part version number is not passed
79 find_version_from_git_tags() {
80 local variable_name=$1
81 local requested_version=${!variable_name}
82 if [ "${requested_version}" = "none" ]; then return; fi
83 local repository=$2
84 local prefix=${3:-"tags/v"}
85 local separator=${4:-"."}
86 local last_part_optional=${5:-"false"}
87 if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then
88 local escaped_separator=${separator//./\\.}
89 local last_part
90 if [ "${last_part_optional}" = "true" ]; then
91 last_part="(${escaped_separator}[0-9]+)?"
92 else
93 last_part="${escaped_separator}[0-9]+"
94 fi
95 local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$"
96 local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)"
97 if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then
98 declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)"
99 else
100 set +e
101 declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")"
102 set -e
103 fi
104 fi
105 if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then
106 echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2
107 exit 1
108 fi
109 echo "${variable_name}=${!variable_name}"
110 }
111
112 # Ensure apt is in non-interactive to avoid prompts
113 export DEBIAN_FRONTEND=noninteractive
114
115 # Install dependencies
116 check_packages apt-transport-https curl ca-certificates gnupg2 dirmngr
117 if ! type git > /dev/null 2>&1; then
118 apt_get_update_if_needed
119 apt-get -y install git
120 fi
121
122 # Source /etc/os-release to get OS info
123 . /etc/os-release
124 # Fetch host/container arch.
125 architecture="$(dpkg --print-architecture)"
126
127 # Set up the necessary apt repos (either Microsoft's or Docker's)
128 if [ "${USE_MOBY}" = "true" ]; then
129
130 cli_package_name="moby-cli"
131
132 # Import key safely and import Microsoft apt repo
133 get_common_setting MICROSOFT_GPG_KEYS_URI
134 curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
135 echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list
136 else
137 # Name of proprietary engine package
138 cli_package_name="docker-ce-cli"
139
140 # Import key safely and import Docker apt repo
141 curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg
142 echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
143 fi
144
145 # Refresh apt lists
146 apt-get update
147
148 # Soft version matching for CLI
149 if [ "${DOCKER_VERSION}" = "latest" ] || [ "${DOCKER_VERSION}" = "lts" ] || [ "${DOCKER_VERSION}" = "stable" ]; then
150 # Empty, meaning grab whatever "latest" is in apt repo
151 cli_version_suffix=""
152 else
153 # Fetch a valid version from the apt-cache (eg: the Microsoft repo appends +azure, breakfix, etc...)
154 docker_version_dot_escaped="${DOCKER_VERSION//./\\.}"
155 docker_version_dot_plus_escaped="${docker_version_dot_escaped//+/\\+}"
156 # Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/
157 docker_version_regex="^(.+:)?${docker_version_dot_plus_escaped}([\\.\\+ ~:-]|$)"
158 set +e # Don't exit if finding version fails - will handle gracefully
159 cli_version_suffix="=$(apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")"
160 set -e
161 if [ -z "${cli_version_suffix}" ] || [ "${cli_version_suffix}" = "=" ]; then
162 echo "(!) No full or partial Docker / Moby version match found for \"${DOCKER_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:"
163 apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+'
164 exit 1
165 fi
166 echo "cli_version_suffix ${cli_version_suffix}"
167 fi
168
169 # Install Docker / Moby CLI if not already installed
170 if type docker > /dev/null 2>&1; then
171 echo "Docker / Moby CLI already installed."
172 else
173 if [ "${USE_MOBY}" = "true" ]; then
174 apt-get -y install --no-install-recommends moby-cli${cli_version_suffix} moby-buildx
175 apt-get -y install --no-install-recommends moby-compose || echo "(*) Package moby-compose (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping."
176 else
177 apt-get -y install --no-install-recommends docker-ce-cli${cli_version_suffix}
178 fi
179 fi
180
181 # Install Docker Compose if not already installed and is on a supported architecture
182 if type docker-compose > /dev/null 2>&1; then
183 echo "Docker Compose already installed."
184 else
185 TARGET_COMPOSE_ARCH="$(uname -m)"
186 if [ "${TARGET_COMPOSE_ARCH}" = "amd64" ]; then
187 TARGET_COMPOSE_ARCH="x86_64"
188 fi
189 if [ "${TARGET_COMPOSE_ARCH}" != "x86_64" ]; then
190 # Use pip to get a version that runns on this architecture
191 if ! dpkg -s python3-minimal python3-pip libffi-dev python3-venv > /dev/null 2>&1; then
192 apt_get_update_if_needed
193 apt-get -y install python3-minimal python3-pip libffi-dev python3-venv
194 fi
195 export PIPX_HOME=/usr/local/pipx
196 mkdir -p ${PIPX_HOME}
197 export PIPX_BIN_DIR=/usr/local/bin
198 export PYTHONUSERBASE=/tmp/pip-tmp
199 export PIP_CACHE_DIR=/tmp/pip-tmp/cache
200 pipx_bin=pipx
201 if ! type pipx > /dev/null 2>&1; then
202 pip3 install --disable-pip-version-check --no-cache-dir --user pipx
203 pipx_bin=/tmp/pip-tmp/bin/pipx
204 fi
205 ${pipx_bin} install --pip-args '--no-cache-dir --force-reinstall' docker-compose
206 rm -rf /tmp/pip-tmp
207 else
208 find_version_from_git_tags DOCKER_DASH_COMPOSE_VERSION "https://github.com/docker/compose" "tags/"
209 echo "(*) Installing docker-compose ${DOCKER_DASH_COMPOSE_VERSION}..."
210 curl -fsSL "https://github.com/docker/compose/releases/download/${DOCKER_DASH_COMPOSE_VERSION}/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose
211 chmod +x /usr/local/bin/docker-compose
212 fi
213 fi
214
215 # If init file already exists, exit
216 if [ -f "/usr/local/share/docker-init.sh" ]; then
217 exit 0
218 fi
219 echo "docker-init doesnt exist, adding..."
220
221 # By default, make the source and target sockets the same
222 if [ "${SOURCE_SOCKET}" != "${TARGET_SOCKET}" ]; then
223 touch "${SOURCE_SOCKET}"
224 ln -s "${SOURCE_SOCKET}" "${TARGET_SOCKET}"
225 fi
226
227 # Add a stub if not adding non-root user access, user is root
228 if [ "${ENABLE_NONROOT_DOCKER}" = "false" ] || [ "${USERNAME}" = "root" ]; then
229 echo '/usr/bin/env bash -c "\$@"' > /usr/local/share/docker-init.sh
230 chmod +x /usr/local/share/docker-init.sh
231 exit 0
232 fi
233
234 # If enabling non-root access and specified user is found, setup socat and add script
235 chown -h "${USERNAME}":root "${TARGET_SOCKET}"
236 if ! dpkg -s socat > /dev/null 2>&1; then
237 apt_get_update_if_needed
238 apt-get -y install socat
239 fi
240 tee /usr/local/share/docker-init.sh > /dev/null \
241 << EOF
242 #!/usr/bin/env bash
243 #-------------------------------------------------------------------------------------------------------------
244 # Copyright (c) Microsoft Corporation. All rights reserved.
245 # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
246 #-------------------------------------------------------------------------------------------------------------
247
248 set -e
249
250 SOCAT_PATH_BASE=/tmp/vscr-docker-from-docker
251 SOCAT_LOG=\${SOCAT_PATH_BASE}.log
252 SOCAT_PID=\${SOCAT_PATH_BASE}.pid
253
254 # Wrapper function to only use sudo if not already root
255 sudoIf()
256 {
257 if [ "\$(id -u)" -ne 0 ]; then
258 sudo "\$@"
259 else
260 "\$@"
261 fi
262 }
263
264 # Log messages
265 log()
266 {
267 echo -e "[\$(date)] \$@" | sudoIf tee -a \${SOCAT_LOG} > /dev/null
268 }
269
270 echo -e "\n** \$(date) **" | sudoIf tee -a \${SOCAT_LOG} > /dev/null
271 log "Ensuring ${USERNAME} has access to ${SOURCE_SOCKET} via ${TARGET_SOCKET}"
272
273 # If enabled, try to add a docker group with the right GID. If the group is root,
274 # fall back on using socat to forward the docker socket to another unix socket so
275 # that we can set permissions on it without affecting the host.
276 if [ "${ENABLE_NONROOT_DOCKER}" = "true" ] && [ "${SOURCE_SOCKET}" != "${TARGET_SOCKET}" ] && [ "${USERNAME}" != "root" ] && [ "${USERNAME}" != "0" ]; then
277 SOCKET_GID=\$(stat -c '%g' ${SOURCE_SOCKET})
278 if [ "\${SOCKET_GID}" != "0" ]; then
279 log "Adding user to group with GID \${SOCKET_GID}."
280 if [ "\$(cat /etc/group | grep :\${SOCKET_GID}:)" = "" ]; then
281 sudoIf groupadd --gid \${SOCKET_GID} docker-host
282 fi
283 # Add user to group if not already in it
284 if [ "\$(id ${USERNAME} | grep -E "groups.*(=|,)\${SOCKET_GID}\(")" = "" ]; then
285 sudoIf usermod -aG \${SOCKET_GID} ${USERNAME}
286 fi
287 else
288 # Enable proxy if not already running
289 if [ ! -f "\${SOCAT_PID}" ] || ! ps -p \$(cat \${SOCAT_PID}) > /dev/null; then
290 log "Enabling socket proxy."
291 log "Proxying ${SOURCE_SOCKET} to ${TARGET_SOCKET} for vscode"
292 sudoIf rm -rf ${TARGET_SOCKET}
293 (sudoIf socat UNIX-LISTEN:${TARGET_SOCKET},fork,mode=660,user=${USERNAME} UNIX-CONNECT:${SOURCE_SOCKET} 2>&1 | sudoIf tee -a \${SOCAT_LOG} > /dev/null & echo "\$!" | sudoIf tee \${SOCAT_PID} > /dev/null)
294 else
295 log "Socket proxy already running."
296 fi
297 fi
298 log "Success"
299 fi
300
301 # Execute whatever commands were passed in (if any). This allows us
302 # to set this script to ENTRYPOINT while still executing the default CMD.
303 set +e
304 exec "\$@"
305 EOF
306 chmod +x /usr/local/share/docker-init.sh
307 chown ${USERNAME}:root /usr/local/share/docker-init.sh
308 echo "Done!"
0 .github
1 .vscode
2 Earthfile
3 extra/doc
4 bin
5 out
0 name: Cancel previous jobs
1 on:
2 workflow_run:
3 workflows: ["CI"]
4 types:
5 - requested
6 jobs:
7 cancel:
8 runs-on: ubuntu-latest
9 steps:
10 - name: Cancel previous runs
11 uses: styfle/cancel-workflow-action@0.11.0
12 with:
13 workflow_id: ${{ github.event.workflow.id }}
44 on: [push, pull_request]
55
66 jobs:
7 cancel:
8 name: "Cancel previous runs"
9 runs-on: ubuntu-18.04
10 timeout-minutes: 3
11 steps:
12 - uses: styfle/cancel-workflow-action@0.3.1
13 with:
14 workflow_id: 1447568
15 access_token: ${{ github.token }}
16
177 windows64-build:
188 runs-on: windows-latest
199 env:
2010 ACTIONS_ALLOW_UNSECURE_COMMANDS: true
2111 PLATFORM: windows64
2212 OPAMYES: 1
13 OPAMROOT: D:\.opam
2314 CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin/
2415 ARCH: 64
2516 MINGW_ARCH: x86_64
3021 with:
3122 submodules: recursive
3223
33 - name: Install Neko using snapshot from S3 (Unix)
34 if: ${{ !startsWith(env.PLATFORM, 'windows') }}
35 run: |
36 set -ex
37
24 - name: Use GNU Tar from msys
25 run: |
26 echo "C:\msys64\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
27 rm C:\msys64\usr\bin\bash.exe
28
29 - name: Cache opam
30 id: cache-opam
31 uses: actions/cache@v3.0.11
32 with:
33 path: D:\.opam
34 key: ${{ runner.os }}64-${{ hashFiles('./opam', './libs/') }}
35
36 - name: Install Neko from S3
37 shell: pwsh
38 run: |
39 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
40 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
41 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
42 echo "$NEKOPATH" >> $env:GITHUB_PATH
43 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
44
45 - name: Print Neko version
46 run: neko -version 2>&1
47
48 - name: choco install nsis
49 uses: nick-invision/retry@v1
50 with:
51 timeout_minutes: 10
52 max_attempts: 10
53 command: choco install --no-progress nsis.portable --version 3.02 -y
54 - name: choco install things
55 shell: pwsh
56 run: choco install --no-progress curl wget 7zip.portable -y
57 - name: Prepend Chocolatey path
58 shell: pwsh
59 run: Write-Host "::add-path::C:\ProgramData\chocolatey\bin"
60
61 - name: Install OCaml
62 shell: pwsh
63 run: |
64 Set-PSDebug -Trace 1
65 curl.exe -fsSL -o cygwin-setup.exe --retry 3 $($env:CYGWIN_SETUP)
66 Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $($env:CYG_ROOT) -l C:/tmp -s $($env:CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre2-devel -P mbedtls-devel -P mingw64-$($env:MINGW_ARCH)-zlib -P mingw64-$($env:MINGW_ARCH)-gcc-core -P mingw64-$($env:MINGW_ARCH)-pcre2" -Wait -RedirectStandardOutput cygwin-setup-out.txt
67 Get-Content cygwin-setup-out.txt
68 curl.exe -fsSL -o "opam.tar.xz" --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.2/opam$($env:ARCH).tar.xz
69 curl.exe -fsSL -o "libmbedtls.tar.xz" --retry 3 https://github.com/Simn/mingw64-mbedtls/releases/download/2.16.3/mingw64-$($env:MINGW_ARCH)-mbedtls-2.16.3-1.tar.xz
70 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'curl -L https://cpanmin.us | perl - App::cpanminus')
71 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm IPC::System::Simple module')
72 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm String::ShellQuote')
73 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'echo "$OLDPWD"')
74 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -C / -xvf libmbedtls.tar.xz')
75 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -xf opam.tar.xz')
76 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && bash opam${ARCH}/install.sh')
77
78 - name: Install OCaml libraries
79 if: steps.cache-opam.outputs.cache-hit != 'true'
80 shell: pwsh
81 run: |
82 Set-PSDebug -Trace 1
83 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam init mingw "https://github.com/fdopen/opam-repository-mingw.git#opam2" --comp 4.07.0+mingw${ARCH}c --switch 4.07.0+mingw${ARCH}c --auto-setup --yes 2>&1')
84 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam update --yes 2>&1')
85 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam pin add haxe . --kind=path --no-action --yes 2>&1')
86 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam install haxe --deps-only --yes 2>&1')
87 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam list')
88 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'ocamlopt -v')
89
90 - name: Expose mingw dll files
91 shell: pwsh
92 run: Write-Host "::add-path::${env:CYG_ROOT}/usr/$($env:MINGW_ARCH)-w64-mingw32/sys-root/mingw/bin"
93
94 # required to be able to retrieve the revision
95 - name: Mark directory as safe
96 shell: pwsh
97 run: |
98 Set-PSDebug -Trace 1
99 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'git config --global --add safe.directory "$OLDPWD"')
100
101 - name: Set ADD_REVISION=1 for non-release
102 if: ${{ !startsWith(github.ref, 'refs/tags/') }}
103 shell: pwsh
104 run: echo "ADD_REVISION=1" >> $Env:GITHUB_ENV
105
106 - name: Build Haxe
107 shell: pwsh
108 run: |
109 Set-PSDebug -Trace 1
110 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win -j`nproc` haxe 2>&1')
111 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win haxelib 2>&1')
112 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -f Makefile.win echo_package_files package_bin package_installer_win package_choco 2>&1')
113 dir out
114 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && cygcheck ./haxe.exe')
115 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && cygcheck ./haxelib.exe')
116 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && ls ./out')
117
118 - name: Upload artifact
119 uses: actions/upload-artifact@v1.0.0
120 with:
121 name: win${{env.ARCH}}Binaries
122 path: out
123
124
125 windows-build:
126 runs-on: windows-latest
127 env:
128 ACTIONS_ALLOW_UNSECURE_COMMANDS: true
129 PLATFORM: windows
130 OPAMYES: 1
131 OPAMROOT: D:\.opam
132 CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin-archive/20221123
133 ARCH: 32
134 MINGW_ARCH: i686
135 CYGWIN_SETUP: https://cygwin.com/setup-x86.exe
136 CYG_ROOT: C:/cygwin
137 steps:
138 - uses: actions/checkout@main
139 with:
140 submodules: recursive
141
142 - name: Use GNU Tar from msys
143 run: |
144 echo "C:\msys64\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
145 rm C:\msys64\usr\bin\bash.exe
146
147 - name: Cache opam
148 id: cache-opam
149 uses: actions/cache@v3.0.11
150 with:
151 path: D:\.opam
152 key: ${{ runner.os }}32-${{ hashFiles('./opam', './libs/') }}
153
154 - name: Install Neko from S3
155 shell: pwsh
156 run: |
157 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
158 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
159 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
160 echo "$NEKOPATH" >> $env:GITHUB_PATH
161 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
162
163 - name: Print Neko version
164 run: neko -version 2>&1
165
166 - name: choco install nsis
167 uses: nick-invision/retry@v1
168 with:
169 timeout_minutes: 10
170 max_attempts: 10
171 command: choco install --no-progress nsis.portable --version 3.02 -y
172 - name: choco install things
173 shell: pwsh
174 run: choco install --no-progress curl wget 7zip.portable -y
175 - name: Prepend Chocolatey path
176 shell: pwsh
177 run: Write-Host "::add-path::C:\ProgramData\chocolatey\bin"
178
179 - name: Install OCaml
180 shell: pwsh
181 run: |
182 Set-PSDebug -Trace 1
183 curl.exe -fsSL -o cygwin-setup.exe --retry 3 $($env:CYGWIN_SETUP)
184 Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $($env:CYG_ROOT) -l C:/tmp -s $($env:CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre2-devel -P mbedtls-devel -P mingw64-$($env:MINGW_ARCH)-zlib -P mingw64-$($env:MINGW_ARCH)-gcc-core -P mingw64-$($env:MINGW_ARCH)-pcre2 --allow-unsupported-windows" -Wait -RedirectStandardOutput cygwin-setup-out.txt
185 Get-Content cygwin-setup-out.txt
186 & "$($env:CYG_ROOT)/bin/bash.exe" @('--norc', '--noprofile', '/etc/postinstall/ca-certificates.sh')
187 curl.exe -fsSL -o "opam.tar.xz" --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.2/opam$($env:ARCH).tar.xz
188 curl.exe -fsSL -o "libmbedtls.tar.xz" --retry 3 https://github.com/Simn/mingw64-mbedtls/releases/download/2.16.3/mingw64-$($env:MINGW_ARCH)-mbedtls-2.16.3-1.tar.xz
189 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'curl -L https://cpanmin.us | perl - App::cpanminus')
190 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm IPC::System::Simple module')
191 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm String::ShellQuote')
192 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'echo "$OLDPWD"')
193 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -C / -xvf libmbedtls.tar.xz')
194 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -xf opam.tar.xz')
195 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && bash opam${ARCH}/install.sh')
196
197 - name: Install OCaml libraries
198 if: steps.cache-opam.outputs.cache-hit != 'true'
199 shell: pwsh
200 run: |
201 Set-PSDebug -Trace 1
202 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam init mingw "https://github.com/fdopen/opam-repository-mingw.git#opam2" --comp 4.07.0+mingw${ARCH}c --switch 4.07.0+mingw${ARCH}c --auto-setup --yes 2>&1')
203 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam update --yes 2>&1')
204 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam pin add haxe . --kind=path --no-action --yes 2>&1')
205 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam install haxe --deps-only --yes 2>&1')
206 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam list')
207 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'ocamlopt -v')
208
209 - name: Expose mingw dll files
210 shell: pwsh
211 run: Write-Host "::add-path::${env:CYG_ROOT}/usr/$($env:MINGW_ARCH)-w64-mingw32/sys-root/mingw/bin"
212
213 # required to be able to retrieve the revision
214 - name: Mark directory as safe
215 shell: pwsh
216 run: |
217 Set-PSDebug -Trace 1
218 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'git config --global --add safe.directory "$OLDPWD"')
219
220 - name: Set ADD_REVISION=1 for non-release
221 if: ${{ !startsWith(github.ref, 'refs/tags/') }}
222 shell: pwsh
223 run: echo "ADD_REVISION=1" >> $Env:GITHUB_ENV
224
225 - name: Build Haxe
226 shell: pwsh
227 run: |
228 Set-PSDebug -Trace 1
229 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win -j`nproc` haxe 2>&1')
230 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win haxelib 2>&1')
231 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -f Makefile.win echo_package_files package_bin package_installer_win package_choco 2>&1')
232 dir out
233 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && cygcheck ./haxe.exe')
234 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && cygcheck ./haxelib.exe')
235 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && ls ./out')
236
237 - name: Upload artifact
238 uses: actions/upload-artifact@v1.0.0
239 with:
240 name: win${{env.ARCH}}Binaries
241 path: out
242
243
244 linux-build:
245 runs-on: ubuntu-20.04
246 env:
247 PLATFORM: linux64
248 OPAMYES: 1
249 steps:
250 - uses: actions/checkout@main
251 with:
252 submodules: recursive
253
254 - name: Cache opam
255 id: cache-opam
256 uses: actions/cache@v3.0.11
257 with:
258 path: ~/.opam/
259 key: ${{ runner.os }}-${{ hashFiles('./opam', './libs/') }}-2
260
261 - name: Install Neko from S3
262 run: |
263 set -ex
264
38265 curl -sSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o $RUNNER_TEMP/neko_latest.tar.gz
39266 tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
40267 NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
44271 sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
45272 sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
46273 echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
47
48 - name: Install Neko using snapshot from S3 (Windows)
49 if: ${{ startsWith(env.PLATFORM, 'windows') }}
50 shell: pwsh
51 run: |
52 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
53 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
54 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
55 echo "$NEKOPATH" >> $env:GITHUB_PATH
56 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
57
274
58275 - name: Print Neko version
59276 run: neko -version 2>&1
60
61 - name: choco install nsis
62 uses: nick-invision/retry@v1
63 with:
64 timeout_minutes: 10
65 max_attempts: 10
66 command: choco install --no-progress nsis.portable --version 3.02 -y
67 - name: choco install things
68 shell: pwsh
69 run: choco install --no-progress curl wget 7zip.portable -y
70 - name: Prepend Chocolatey path
71 shell: pwsh
72 run: Write-Host "::add-path::C:\ProgramData\chocolatey\bin"
73
74 - name: Install OCaml and OCaml libraries
75 shell: pwsh
76 run: |
77 Set-PSDebug -Trace 1
78 curl.exe -fsSL -o cygwin-setup.exe --retry 3 $($env:CYGWIN_SETUP)
79 Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $($env:CYG_ROOT) -l C:/tmp -s $($env:CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre-devel -P mbedtls-devel -P mingw64-$($env:MINGW_ARCH)-zlib -P mingw64-$($env:MINGW_ARCH)-gcc-core -P mingw64-$($env:MINGW_ARCH)-pcre" -Wait
80 curl.exe -fsSL -o "opam.tar.xz" --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.2/opam$($env:ARCH).tar.xz
81 curl.exe -fsSL -o "libmbedtls.tar.xz" --retry 3 https://github.com/Simn/mingw64-mbedtls/releases/download/2.16.3/mingw64-$($env:MINGW_ARCH)-mbedtls-2.16.3-1.tar.xz
82 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'curl -L https://cpanmin.us | perl - App::cpanminus')
83 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm IPC::System::Simple module')
84 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm String::ShellQuote')
85 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'echo "$OLDPWD"')
86 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -C / -xvf libmbedtls.tar.xz')
87 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -xf opam.tar.xz')
88 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && bash opam${ARCH}/install.sh')
89 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam init mingw "https://github.com/fdopen/opam-repository-mingw.git#opam2" --comp 4.07.0+mingw${ARCH}c --switch 4.07.0+mingw${ARCH}c --auto-setup --yes 2>&1')
90 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam update --yes 2>&1')
91 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam pin add haxe . --kind=path --no-action --yes 2>&1')
92 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam pin add ctypes 0.17.1 --yes 2>&1')
93 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam install haxe --deps-only --yes 2>&1')
94 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam list')
95 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'ocamlopt -v')
96
97 - name: Expose mingw dll files
98 shell: pwsh
99 run: Write-Host "::add-path::${env:CYG_ROOT}/usr/$($env:MINGW_ARCH)-w64-mingw32/sys-root/mingw/bin"
100
277
278
279 - name: Install dependencies
280 run: |
281 set -ex
282 sudo add-apt-repository ppa:avsm/ppa -y # provides OPAM 2
283 sudo add-apt-repository ppa:haxe/ocaml -y # provides newer version of mbedtls
284 sudo apt-get update -qqy
285 sudo apt-get install -qqy ocaml-nox camlp5 opam libpcre2-dev zlib1g-dev libgtk2.0-dev libmbedtls-dev ninja-build libstring-shellquote-perl libipc-system-simple-perl
286
287 - name: Install OCaml libraries
288 if: steps.cache-opam.outputs.cache-hit != 'true'
289 run: |
290 set -ex
291 opam init # --disable-sandboxing
292 opam update
293 opam pin add haxe . --no-action
294 opam install haxe --deps-only --assume-depexts
295 opam list
296 ocamlopt -v
297
101298 - name: Set ADD_REVISION=1 for non-release
102299 if: ${{ !startsWith(github.ref, 'refs/tags/') }}
103 shell: pwsh
104 run: echo "ADD_REVISION=1" >> $Env:GITHUB_ENV
105
300 run: echo "ADD_REVISION=1" >> $GITHUB_ENV
301
106302 - name: Build Haxe
107 shell: pwsh
108 run: |
109 Set-PSDebug -Trace 1
110 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win -j`nproc` haxe 2>&1')
111 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win haxelib 2>&1')
112 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -f Makefile.win echo_package_files package_bin package_installer_win package_choco 2>&1')
113 dir out
114 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && cygcheck ./haxe.exe')
115 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && cygcheck ./haxelib.exe')
116 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && ls ./out')
117
303 run: |
304 set -ex
305 eval $(opam env)
306 opam config exec -- make -s -j`nproc` STATICLINK=1 haxe
307 opam config exec -- make -s haxelib
308 make -s package_unix
309 ls -l out
310 ldd -v ./haxe
311 ldd -v ./haxelib
312
313 # https://stackoverflow.com/questions/58033366/how-to-get-current-branch-within-github-actions
314 - name: Extract branch name
315 id: extract_branch
316 shell: bash
317 run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
318
319 - name: Build xmldoc
320 run: |
321 set -ex
322 make -s xmldoc
323 cat >extra/doc/info.json <<EOL
324 {
325 "commit": "$GITHUB_SHA",
326 "branch": "${{ steps.extract_branch.outputs.branch }}"
327 }
328 EOL
329
118330 - name: Upload artifact
119331 uses: actions/upload-artifact@v1.0.0
120332 with:
121 name: win${{env.ARCH}}Binaries
333 name: linuxBinaries
122334 path: out
123
124
125 windows-build:
126 runs-on: windows-latest
335
336 - name: Upload xmldoc artifact
337 uses: actions/upload-artifact@v1.0.0
338 with:
339 name: xmldoc
340 path: extra/doc
341
342 linux-test:
343 needs: linux-build
344 runs-on: ubuntu-20.04
127345 env:
128 ACTIONS_ALLOW_UNSECURE_COMMANDS: true
129 PLATFORM: windows
130 OPAMYES: 1
131 CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin/
132 ARCH: 32
133 MINGW_ARCH: i686
134 CYGWIN_SETUP: https://cygwin.com/setup-x86.exe
135 CYG_ROOT: C:/cygwin
346 PLATFORM: linux64
347 TEST: ${{matrix.target}}
348 HXCPP_COMPILE_CACHE: ~/hxcache
349 HAXE_STD_PATH: /usr/local/share/haxe/std
350 strategy:
351 fail-fast: false
352 matrix:
353 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, lua, flash, neko]
354 include:
355 - target: hl
356 APT_PACKAGES: cmake ninja-build libturbojpeg-dev
357 - target: cpp
358 APT_PACKAGES: gcc-multilib g++-multilib
359 - target: lua
360 APT_PACKAGES: ncurses-dev
361 - target: flash
362 APT_PACKAGES: libglib2.0-0 libgtk2.0-0 libfreetype6 xvfb
136363 steps:
137364 - uses: actions/checkout@main
138365 with:
139366 submodules: recursive
140
141 - name: Install Neko using snapshot from S3 (Unix)
142 if: ${{ !startsWith(env.PLATFORM, 'windows') }}
143 run: |
144 set -ex
145
367 - uses: actions/download-artifact@v1
368 with:
369 name: linuxBinaries
370
371 - name: Install Neko from S3
372 run: |
373 set -ex
374
146375 curl -sSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o $RUNNER_TEMP/neko_latest.tar.gz
147376 tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
148377 NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
152381 sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
153382 sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
154383 echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
155
156 - name: Install Neko using snapshot from S3 (Windows)
157 if: ${{ startsWith(env.PLATFORM, 'windows') }}
158 shell: pwsh
159 run: |
160 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
161 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
162 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
163 echo "$NEKOPATH" >> $env:GITHUB_PATH
164 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
165
384
166385 - name: Print Neko version
167386 run: neko -version 2>&1
168
169 - name: choco install nsis
170 uses: nick-invision/retry@v1
171 with:
172 timeout_minutes: 10
173 max_attempts: 10
174 command: choco install --no-progress nsis.portable --version 3.02 -y
175 - name: choco install things
176 shell: pwsh
177 run: choco install --no-progress curl wget 7zip.portable -y
178 - name: Prepend Chocolatey path
179 shell: pwsh
180 run: Write-Host "::add-path::C:\ProgramData\chocolatey\bin"
181
182 - name: Install OCaml and OCaml libraries
183 shell: pwsh
184 run: |
185 Set-PSDebug -Trace 1
186 curl.exe -fsSL -o cygwin-setup.exe --retry 3 $($env:CYGWIN_SETUP)
187 Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $($env:CYG_ROOT) -l C:/tmp -s $($env:CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre-devel -P mbedtls-devel -P mingw64-$($env:MINGW_ARCH)-zlib -P mingw64-$($env:MINGW_ARCH)-gcc-core -P mingw64-$($env:MINGW_ARCH)-pcre" -Wait
188 curl.exe -fsSL -o "opam.tar.xz" --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.2/opam$($env:ARCH).tar.xz
189 curl.exe -fsSL -o "libmbedtls.tar.xz" --retry 3 https://github.com/Simn/mingw64-mbedtls/releases/download/2.16.3/mingw64-$($env:MINGW_ARCH)-mbedtls-2.16.3-1.tar.xz
190 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'curl -L https://cpanmin.us | perl - App::cpanminus')
191 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm IPC::System::Simple module')
192 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm String::ShellQuote')
193 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'echo "$OLDPWD"')
194 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -C / -xvf libmbedtls.tar.xz')
195 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -xf opam.tar.xz')
196 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && bash opam${ARCH}/install.sh')
197 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam init mingw "https://github.com/fdopen/opam-repository-mingw.git#opam2" --comp 4.07.0+mingw${ARCH}c --switch 4.07.0+mingw${ARCH}c --auto-setup --yes 2>&1')
198 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam update --yes 2>&1')
199 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam pin add haxe . --kind=path --no-action --yes 2>&1')
200 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam pin add ctypes 0.17.1 --yes 2>&1')
201 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam install haxe --deps-only --yes 2>&1')
202 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam list')
203 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'ocamlopt -v')
204
205 - name: Expose mingw dll files
206 shell: pwsh
207 run: Write-Host "::add-path::${env:CYG_ROOT}/usr/$($env:MINGW_ARCH)-w64-mingw32/sys-root/mingw/bin"
208
209 - name: Set ADD_REVISION=1 for non-release
210 if: ${{ !startsWith(github.ref, 'refs/tags/') }}
211 shell: pwsh
212 run: echo "ADD_REVISION=1" >> $Env:GITHUB_ENV
213
214 - name: Build Haxe
215 shell: pwsh
216 run: |
217 Set-PSDebug -Trace 1
218 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win -j`nproc` haxe 2>&1')
219 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win haxelib 2>&1')
220 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -f Makefile.win echo_package_files package_bin package_installer_win package_choco 2>&1')
221 dir out
222 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && cygcheck ./haxe.exe')
223 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && cygcheck ./haxelib.exe')
224 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && ls ./out')
225
226 - name: Upload artifact
227 uses: actions/upload-artifact@v1.0.0
228 with:
229 name: win${{env.ARCH}}Binaries
230 path: out
231
232
233 linux-build:
234 runs-on: ubuntu-18.04
387
388
389 - name: Setup Haxe
390 run: |
391 sudo apt install -qqy libmbedtls-dev
392
393 set -ex
394 tar -xf linuxBinaries/*_bin.tar.gz -C linuxBinaries --strip-components=1
395 sudo mkdir -p /usr/local/bin/
396 sudo mkdir -p /usr/local/share/haxe/
397 sudo ln -s `pwd`/linuxBinaries/haxe /usr/local/bin/haxe
398 sudo ln -s `pwd`/linuxBinaries/haxelib /usr/local/bin/haxelib
399 sudo ln -s `pwd`/linuxBinaries/std /usr/local/share/haxe/std
400
401 - name: Print Haxe version
402 run: haxe -version
403
404 - name: Setup haxelib
405 run: |
406 set -ex
407 mkdir ~/haxelib
408 haxelib setup ~/haxelib
409
410 - name: Install apt packages
411 if: matrix.APT_PACKAGES
412 run: |
413 set -ex
414 sudo apt update -qqy
415 sudo apt install -qqy ${{matrix.APT_PACKAGES}}
416
417 - name: Flash setup
418 if: matrix.target == 'flash'
419 run: export DISPLAY=:99.0
420
421 - name: Test
422 run: haxe RunCi.hxml
423 working-directory: ${{github.workspace}}/tests
424
425 test-docgen:
426 needs: linux-build
427 runs-on: ubuntu-20.04
235428 env:
236429 PLATFORM: linux64
237 OPAMYES: 1
430 HXCPP_COMPILE_CACHE: ~/hxcache
238431 steps:
239432 - uses: actions/checkout@main
240433 with:
241434 submodules: recursive
242435
243 - name: Install Neko using snapshot from S3 (Unix)
244 if: ${{ !startsWith(env.PLATFORM, 'windows') }}
245 run: |
246 set -ex
247
436 - uses: actions/download-artifact@v1
437 with:
438 name: linuxBinaries
439
440 - name: Download xmldoc artifact
441 uses: actions/download-artifact@v2
442 with:
443 name: xmldoc
444 path: xmldoc
445
446 - name: Install Neko from S3
447 run: |
448 set -ex
449
248450 curl -sSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o $RUNNER_TEMP/neko_latest.tar.gz
249451 tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
250452 NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
254456 sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
255457 sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
256458 echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
257
258 - name: Install Neko using snapshot from S3 (Windows)
259 if: ${{ startsWith(env.PLATFORM, 'windows') }}
260 shell: pwsh
261 run: |
262 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
263 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
264 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
265 echo "$NEKOPATH" >> $env:GITHUB_PATH
266 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
267
459
268460 - name: Print Neko version
269461 run: neko -version 2>&1
270
271 - name: Install dependencies
272 run: |
273 set -ex
274 sudo add-apt-repository ppa:avsm/ppa -y # provides OPAM 2
275 sudo add-apt-repository ppa:haxe/ocaml -y # provides newer version of mbedtls
276 sudo apt-get update -qqy
277 sudo apt-get install -qqy ocaml-nox camlp5 opam libpcre3-dev zlib1g-dev libgtk2.0-dev libmbedtls-dev ninja-build libstring-shellquote-perl
278
279 - name: Install OCaml libraries
280 run: |
281 set -ex
282 opam init # --disable-sandboxing
283 opam update
284 opam pin add haxe . --no-action
285 opam install haxe --deps-only --assume-depexts
286 opam list
287 ocamlopt -v
288
462
463
464 - name: Setup Haxe
465 run: |
466 sudo apt install -qqy libmbedtls-dev
467
468 set -ex
469 tar -xf linuxBinaries/*_bin.tar.gz -C linuxBinaries --strip-components=1
470 sudo mkdir -p /usr/local/bin/
471 sudo mkdir -p /usr/local/share/haxe/
472 sudo ln -s `pwd`/linuxBinaries/haxe /usr/local/bin/haxe
473 sudo ln -s `pwd`/linuxBinaries/haxelib /usr/local/bin/haxelib
474 sudo ln -s `pwd`/linuxBinaries/std /usr/local/share/haxe/std
475
476 - name: Print Haxe version
477 run: haxe -version
478
479 - name: Setup haxelib
480 run: |
481 set -ex
482 mkdir ~/haxelib
483 haxelib setup ~/haxelib
484
485 - name: Test documentation generation
486 run: |
487 set -ex
488 haxelib git dox https://github.com/HaxeFoundation/dox.git
489 haxelib git hxtemplo https://github.com/Simn/hxtemplo.git
490 haxelib git hxargs https://github.com/Simn/hxargs.git
491 haxelib git markdown https://github.com/dpeek/haxe-markdown.git
492 haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp.git
493 cd $(haxelib libpath hxcpp)/tools/hxcpp
494 haxe compile.hxml
495 cd -
496 haxe dox.hxml
497 mkdir resources
498 cp ../../src-json/* resources
499 cpp/Dox -i ../../xmldoc -ex microsoft -ex javax -ex cs.internal -theme $(haxelib libpath dox)/themes/default
500 working-directory: ${{github.workspace}}/tests/docgen
501
502 linux-arm64:
503 runs-on: ubuntu-20.04
504 permissions:
505 packages: write
506 env:
507 FORCE_COLOR: 1
508 steps:
509 - name: Login to GitHub Container Registry
510 uses: docker/login-action@v1
511 with:
512 registry: ghcr.io
513 username: ${{ github.actor }}
514 password: ${{ secrets.GITHUB_TOKEN }}
515
516 - name: Install Earthly
517 run: sudo /bin/sh -c 'wget https://github.com/earthly/earthly/releases/download/v0.6.13/earthly-linux-amd64 -O /usr/local/bin/earthly && chmod +x /usr/local/bin/earthly && /usr/local/bin/earthly bootstrap --with-autocomplete'
518
519 - name: Set up QEMU
520 id: qemu
521 uses: docker/setup-qemu-action@v1
522 with:
523 image: tonistiigi/binfmt:latest
524 platforms: all
525
526 - uses: actions/checkout@main
527 with:
528 submodules: recursive
529
530 - name: Set CONTAINER_ vars
531 run: |
532 echo "CONTAINER_REG=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV;
533 echo "CONTAINER_TAG=$(echo ${{ github.ref_name }} | sed -e 's/[^A-Za-z0-9\.]/-/g')" >> $GITHUB_ENV;
534
535 - name: Build devcontainer
536 run: earthly --platform=linux/arm64 +devcontainer --IMAGE_NAME="ghcr.io/${CONTAINER_REG}_devcontainer" --IMAGE_TAG="${CONTAINER_TAG}-arm64" --IMAGE_CACHE="ghcr.io/haxefoundation/haxe_devcontainer:development-arm64"
537 env:
538 EARTHLY_PUSH: "${{ github.event_name == 'push' }}"
539 EARTHLY_USE_INLINE_CACHE: true
540 EARTHLY_SAVE_INLINE_CACHE: true
541
289542 - name: Set ADD_REVISION=1 for non-release
290543 if: ${{ !startsWith(github.ref, 'refs/tags/') }}
291544 run: echo "ADD_REVISION=1" >> $GITHUB_ENV
292
293 - name: Build Haxe
294 run: |
295 set -ex
296 eval $(opam env)
297 opam config exec -- make -s -j`nproc` STATICLINK=1 haxe
298 opam config exec -- make -s haxelib
299 make -s package_unix
300 ls -l out
301 ldd -v ./haxe
302 ldd -v ./haxelib
303
304 # https://stackoverflow.com/questions/58033366/how-to-get-current-branch-within-github-actions
305 - name: Extract branch name
306 id: extract_branch
307 shell: bash
308 run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
309
310 - name: Build xmldoc
311 run: |
312 set -ex
313 make -s xmldoc
314 cat >extra/doc/info.json <<EOL
315 {
316 "commit": "$GITHUB_SHA",
317 "branch": "${{ steps.extract_branch.outputs.branch }}"
318 }
319 EOL
320
321 - name: Upload xmldoc artifact
322 uses: actions/upload-artifact@v1.0.0
323 with:
324 name: xmldoc
325 path: extra/doc
326
545
546 - name: Build
547 run: earthly --platform=linux/arm64 +build --ADD_REVISION="$ADD_REVISION" --SET_SAFE_DIRECTORY="true"
548 env:
549 EARTHLY_PUSH: "${{ github.event_name == 'push' }}"
550 EARTHLY_REMOTE_CACHE: "ghcr.io/${{env.CONTAINER_REG}}_cache:build-${{env.CONTAINER_TAG}}-arm64"
551
327552 - name: Upload artifact
328553 uses: actions/upload-artifact@v1.0.0
329554 with:
330 name: linuxBinaries
331 path: out
332
555 name: linuxArm64Binaries
556 path: out/linux/arm64
333557
334558 mac-build:
335559 runs-on: macos-latest
342566 with:
343567 submodules: recursive
344568
345 - name: Install Neko using snapshot from S3 (Unix)
346 if: ${{ !startsWith(env.PLATFORM, 'windows') }}
347 run: |
348 set -ex
349
569 - name: Cache opam
570 id: cache-opam
571 uses: actions/cache@v3.0.11
572 with:
573 path: ~/.opam/
574 key: ${{ runner.os }}-${{ hashFiles('./opam', './libs/') }}-2
575
576 - name: Install Neko from S3
577 run: |
578 set -ex
579
350580 curl -sSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o $RUNNER_TEMP/neko_latest.tar.gz
351581 tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
352582 NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
356586 sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
357587 sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
358588 echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
359
360 - name: Install Neko using snapshot from S3 (Windows)
361 if: ${{ startsWith(env.PLATFORM, 'windows') }}
362 shell: pwsh
363 run: |
364 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
365 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
366 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
367 echo "$NEKOPATH" >> $env:GITHUB_PATH
368 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
369
589
370590 - name: Print Neko version
371591 run: neko -version 2>&1
372
592
373593 - name: Install dependencies
374594 env:
375 ZLIB_VERSION: 1.2.11
595 # For compatibility with macOS 10.13
596 ZLIB_VERSION: 1.2.13
376597 MBEDTLS_VERSION: 2.25.0
377 PCRE_VERSION: 10.39
598 PCRE2_VERSION: 10.42
378599 run: |
379600 set -ex
380601 brew uninstall openssl@1.0.2t || echo
384605 brew update
385606 # brew unlink python@2
386607 brew bundle --file=tests/Brewfile --no-upgrade || brew link --overwrite awscli
608 brew install libunistring
387609 brew install cpanminus
388610 cpanm IPC::System::Simple
389611 cpanm String::ShellQuote
391613 cd zlib-$ZLIB_VERSION
392614 ./configure
393615 make && make install
616 cd ..
394617 curl -L https://github.com/ARMmbed/mbedtls/archive/v$MBEDTLS_VERSION.tar.gz | tar xz
395618 cd mbedtls-$MBEDTLS_VERSION
396619 make && make install
397 curl -L https://github.com/PhilipHazel/pcre2/releases/download/pcre2-10.39/pcre2-$PCRE_VERSION.tar.gz | tar xz
398 cd pcre2-$PCRE_VERSION
399 ./configure --enable-utf8 --enable-pcre2-8 --enable-pcre2-16 --enable-pcre2-32 --enable-unicode-properties --enable-pcregrep-libz --enable-pcregrep-libbz2 --enable-jit
620 cd ..
621 curl -L https://github.com/PCRE2Project/pcre2/releases/download/pcre2-$PCRE2_VERSION/pcre2-$PCRE2_VERSION.tar.gz | tar xz
622 cd pcre2-$PCRE2_VERSION
623 ./configure --enable-unicode --enable-pcre2-8 --enable-pcre2-16 --enable-pcre2-32 --enable-unicode-properties --enable-pcre2grep-libz --enable-pcre2grep-libbz2 --enable-jit
400624 make && make install
401
402
625 cd ..
626
627
403628 - name: Install OCaml libraries
629 if: steps.cache-opam.outputs.cache-hit != 'true'
404630 run: |
405631 set -ex
406632 opam init # --disable-sandboxing
413639 opam install haxe --deps-only --assume-depexts
414640 opam list
415641 ocamlopt -v
416
642
417643 - name: Set ADD_REVISION=1 for non-release
418644 if: ${{ !startsWith(github.ref, 'refs/tags/') }}
419645 run: echo "ADD_REVISION=1" >> $GITHUB_ENV
420
646
421647 - name: Build Haxe
422648 run: |
423649 set -ex
424650 eval $(opam env)
425 opam config exec -- make -s -j`sysctl -n hw.ncpu` STATICLINK=1 "LIB_PARAMS=/usr/local/lib/libz.a /usr/local/lib/libpcre.a /usr/local/lib/libmbedtls.a /usr/local/lib/libmbedcrypto.a /usr/local/lib/libmbedx509.a -cclib '-framework Security -framework CoreFoundation'" haxe
651 opam config exec -- make -s -j`sysctl -n hw.ncpu` STATICLINK=1 "LIB_PARAMS=/usr/local/lib/libz.a /usr/local/lib/libpcre2-8.a /usr/local/lib/libmbedtls.a /usr/local/lib/libmbedcrypto.a /usr/local/lib/libmbedx509.a -cclib '-framework Security -framework CoreFoundation'" haxe
426652 opam config exec -- make -s haxelib
427653 make -s package_unix package_installer_mac
428654 ls -l out
429655 otool -L ./haxe
430656 otool -L ./haxelib
431
657
432658 - name: Upload artifact
433659 uses: actions/upload-artifact@v1.0.0
434660 with:
435661 name: macBinaries
436662 path: out
437
663
438664
439665 windows64-test:
440666 needs: windows64-build
448674 strategy:
449675 fail-fast: false
450676 matrix:
451 # TODO enable lua after https://github.com/HaxeFoundation/haxe/issues/5024
452 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, neko]
677 # TODO enable lua after https://github.com/HaxeFoundation/haxe/issues/10919
678 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, flash, neko]
453679 steps:
454680 - uses: actions/checkout@main
455681 with:
458684 with:
459685 name: win${{env.ARCH}}Binaries
460686
461 - name: Install Neko using snapshot from S3 (Unix)
462 if: ${{ !startsWith(env.PLATFORM, 'windows') }}
463 run: |
464 set -ex
465
466 curl -sSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o $RUNNER_TEMP/neko_latest.tar.gz
467 tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
468 NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
469 sudo mkdir -p /usr/local/bin
470 sudo mkdir -p /usr/local/lib/neko
471 sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools} /usr/local/bin/
472 sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
473 sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
474 echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
475
476 - name: Install Neko using snapshot from S3 (Windows)
477 if: ${{ startsWith(env.PLATFORM, 'windows') }}
687 - name: Install Neko from S3
478688 shell: pwsh
479689 run: |
480690 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
482692 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
483693 echo "$NEKOPATH" >> $env:GITHUB_PATH
484694 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
485
695
486696 - name: Print Neko version
487697 run: neko -version 2>&1
488
698
489699 # - name: Quick test
490700 # shell: pwsh
491701 # run: |
492702 # $DOWNLOADDIR="./win$($env:ARCH)Binaries"
493703 # new-item -Name $DOWNLOADDIR -ItemType directory
494704 # Invoke-WebRequest https://build.haxe.org/builds/haxe/$env:PLATFORM/haxe_latest.zip -OutFile $DOWNLOADDIR/haxe_bin.zip
495
705
496706 - name: Setup Haxe
497707 shell: pwsh
498708 run: |
502712 $HAXEPATH = Get-ChildItem $DOWNLOADDIR/haxe_*_* -Directory
503713 Write-Host "::add-path::$HAXEPATH"
504714 Write-Host "::set-env name=HAXELIB_ROOT::$HAXEPATH\lib"
505
715
506716 - name: Print Haxe version
507717 shell: pwsh
508718 run: haxe -version
509
719
510720 - name: "Make Python 3 be available as python3 in the cmdline"
511721 shell: pwsh
512722 run: |
515725 $py3path = $pypath.replace("python.exe","python3.exe")
516726 cmd /c mklink $py3path $pypath
517727 python3 -V
518
728
519729 - name: Install hererocks
520730 if: matrix.target == 'lua'
521731 shell: cmd
523733 pip install hererocks
524734 hererocks lua53 -l5.3 -rlatest
525735 call lua53/bin/activate
526
736
737 - name: Install wget
738 if: matrix.target == 'flash'
739 shell: cmd
740 run: |
741 choco install wget
742 wget --version
743
527744 - name: Setup haxelib
528745 shell: pwsh
529746 run: |
530747 mkdir "$env:HAXELIB_ROOT"
531748 haxelib setup "$env:HAXELIB_ROOT"
532
749
533750 - name: Test
534751 shell: pwsh
535752 run: haxe RunCi.hxml
536753 working-directory: ${{github.workspace}}/tests
537
754
538755
539756 windows-test:
540757 needs: windows-build
549766 fail-fast: false
550767 matrix:
551768 # TODO jvm: https://github.com/HaxeFoundation/haxe/issues/8601
552 # TODO enable lua after https://github.com/HaxeFoundation/haxe/issues/5024
553 target: [macro, js, hl, cpp, java, cs, php, python, neko]
769 # TODO enable lua after https://github.com/HaxeFoundation/haxe/issues/10919
770 target: [macro, js, hl, cpp, java, cs, php, python, flash, neko]
554771 steps:
555772 - uses: actions/checkout@main
556773 with:
559776 with:
560777 name: win${{env.ARCH}}Binaries
561778
562 - name: Install Neko using snapshot from S3 (Unix)
563 if: ${{ !startsWith(env.PLATFORM, 'windows') }}
564 run: |
565 set -ex
566
779 - name: Install Neko from S3
780 shell: pwsh
781 run: |
782 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
783 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
784 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
785 echo "$NEKOPATH" >> $env:GITHUB_PATH
786 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
787
788 - name: Print Neko version
789 run: neko -version 2>&1
790
791 # - name: Quick test
792 # shell: pwsh
793 # run: |
794 # $DOWNLOADDIR="./win$($env:ARCH)Binaries"
795 # new-item -Name $DOWNLOADDIR -ItemType directory
796 # Invoke-WebRequest https://build.haxe.org/builds/haxe/$env:PLATFORM/haxe_latest.zip -OutFile $DOWNLOADDIR/haxe_bin.zip
797
798 - name: Setup Haxe
799 shell: pwsh
800 run: |
801 $DOWNLOADDIR="./win$($env:ARCH)Binaries"
802 Expand-Archive $DOWNLOADDIR/*_bin.zip -DestinationPath $DOWNLOADDIR
803 Set-PSDebug -Trace 1
804 $HAXEPATH = Get-ChildItem $DOWNLOADDIR/haxe_*_* -Directory
805 Write-Host "::add-path::$HAXEPATH"
806 Write-Host "::set-env name=HAXELIB_ROOT::$HAXEPATH\lib"
807
808 - name: Print Haxe version
809 shell: pwsh
810 run: haxe -version
811
812 - name: "Make Python 3 be available as python3 in the cmdline"
813 shell: pwsh
814 run: |
815 Set-PSDebug -Trace 1
816 $pypath = python -c "import sys; print(sys.executable)"
817 $py3path = $pypath.replace("python.exe","python3.exe")
818 cmd /c mklink $py3path $pypath
819 python3 -V
820
821 - name: Install hererocks
822 if: matrix.target == 'lua'
823 shell: cmd
824 run: |
825 pip install hererocks
826 hererocks lua53 -l5.3 -rlatest
827 call lua53/bin/activate
828
829 - name: Install wget
830 if: matrix.target == 'flash'
831 shell: cmd
832 run: |
833 choco install wget
834 wget --version
835
836 - name: Setup haxelib
837 shell: pwsh
838 run: |
839 mkdir "$env:HAXELIB_ROOT"
840 haxelib setup "$env:HAXELIB_ROOT"
841
842 - name: Test
843 shell: pwsh
844 run: haxe RunCi.hxml
845 working-directory: ${{github.workspace}}/tests
846
847
848 mac-test:
849 needs: mac-build
850 runs-on: macos-latest
851 env:
852 PLATFORM: mac
853 TEST: ${{matrix.target}}
854 HXCPP_COMPILE_CACHE: ~/hxcache
855 HAXE_STD_PATH: /usr/local/share/haxe/std
856 strategy:
857 fail-fast: false
858 matrix:
859 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, flash, neko]
860 include:
861 - target: hl
862 BREW_PACKAGES: ninja
863 steps:
864 - uses: actions/checkout@main
865 with:
866 submodules: recursive
867 - uses: actions/download-artifact@v1
868 with:
869 name: macBinaries
870
871 - name: Install Neko from S3
872 run: |
873 set -ex
874
567875 curl -sSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o $RUNNER_TEMP/neko_latest.tar.gz
568876 tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
569877 NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
573881 sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
574882 sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
575883 echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
576
577 - name: Install Neko using snapshot from S3 (Windows)
578 if: ${{ startsWith(env.PLATFORM, 'windows') }}
579 shell: pwsh
580 run: |
581 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
582 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
583 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
584 echo "$NEKOPATH" >> $env:GITHUB_PATH
585 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
586
884
587885 - name: Print Neko version
588886 run: neko -version 2>&1
589
590 # - name: Quick test
591 # shell: pwsh
592 # run: |
593 # $DOWNLOADDIR="./win$($env:ARCH)Binaries"
594 # new-item -Name $DOWNLOADDIR -ItemType directory
595 # Invoke-WebRequest https://build.haxe.org/builds/haxe/$env:PLATFORM/haxe_latest.zip -OutFile $DOWNLOADDIR/haxe_bin.zip
596
597 - name: Setup Haxe
598 shell: pwsh
599 run: |
600 $DOWNLOADDIR="./win$($env:ARCH)Binaries"
601 Expand-Archive $DOWNLOADDIR/*_bin.zip -DestinationPath $DOWNLOADDIR
602 Set-PSDebug -Trace 1
603 $HAXEPATH = Get-ChildItem $DOWNLOADDIR/haxe_*_* -Directory
604 Write-Host "::add-path::$HAXEPATH"
605 Write-Host "::set-env name=HAXELIB_ROOT::$HAXEPATH\lib"
606
607 - name: Print Haxe version
608 shell: pwsh
609 run: haxe -version
610
611 - name: "Make Python 3 be available as python3 in the cmdline"
612 shell: pwsh
613 run: |
614 Set-PSDebug -Trace 1
615 $pypath = python -c "import sys; print(sys.executable)"
616 $py3path = $pypath.replace("python.exe","python3.exe")
617 cmd /c mklink $py3path $pypath
618 python3 -V
619
620 - name: Install hererocks
621 if: matrix.target == 'lua'
622 shell: cmd
623 run: |
624 pip install hererocks
625 hererocks lua53 -l5.3 -rlatest
626 call lua53/bin/activate
627
628 - name: Setup haxelib
629 shell: pwsh
630 run: |
631 mkdir "$env:HAXELIB_ROOT"
632 haxelib setup "$env:HAXELIB_ROOT"
633
634 - name: Test
635 shell: pwsh
636 run: haxe RunCi.hxml
637 working-directory: ${{github.workspace}}/tests
638
639
640 linux-test:
641 needs: linux-build
642 runs-on: ubuntu-18.04
643 env:
644 PLATFORM: linux64
645 TEST: ${{matrix.target}}
646 HXCPP_COMPILE_CACHE: ~/hxcache
647 strategy:
648 fail-fast: false
649 matrix:
650 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, lua, neko] #flash9
651 include:
652 - target: js
653 # SAUCE: 1
654 # SAUCE_TUNNEL_ID: 'linux-test'
655 # SAUCE_BUILD: '${{env.GITHUB_RUN_NUMBER}}' # $(Build.BuildNumber)
656 - target: hl
657 APT_PACKAGES: cmake ninja-build libturbojpeg-dev
658 - target: cpp
659 APT_PACKAGES: gcc-multilib g++-multilib
660 - target: lua
661 APT_PACKAGES: ncurses-dev
662 # - target: flash9
663 # APT_PACKAGES: libglib2.0-0 libfreetype6 xvfb
664 steps:
665 - uses: actions/checkout@main
666 with:
667 submodules: recursive
668 - uses: actions/download-artifact@v1
669 with:
670 name: linuxBinaries
671
672 - name: Install Neko using snapshot from S3 (Unix)
673 if: ${{ !startsWith(env.PLATFORM, 'windows') }}
674 run: |
675 set -ex
676
677 curl -sSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o $RUNNER_TEMP/neko_latest.tar.gz
678 tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
679 NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
680 sudo mkdir -p /usr/local/bin
681 sudo mkdir -p /usr/local/lib/neko
682 sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools} /usr/local/bin/
683 sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
684 sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
685 echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
686
687 - name: Install Neko using snapshot from S3 (Windows)
688 if: ${{ startsWith(env.PLATFORM, 'windows') }}
689 shell: pwsh
690 run: |
691 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
692 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
693 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
694 echo "$NEKOPATH" >> $env:GITHUB_PATH
695 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
696
697 - name: Print Neko version
698 run: neko -version 2>&1
699
700 - name: Setup Haxe
701 run: |
702 # mkdir ./linuxBinaries
703 # curl -sSL https://build.haxe.org/builds/haxe/linux64/haxe_latest.tar.gz -o ./linuxBinaries/haxe_bin.tar.gz
704
705 sudo apt install -qqy libmbedtls-dev
706
707 set -ex
708 tar -xf linuxBinaries/*_bin.tar.gz -C linuxBinaries --strip-components=1
709 sudo mkdir -p /usr/local/bin/
710 sudo mkdir -p /usr/local/share/haxe/
711 sudo ln -s `pwd`/linuxBinaries/haxe /usr/local/bin/haxe
712 sudo ln -s `pwd`/linuxBinaries/haxelib /usr/local/bin/haxelib
713 sudo ln -s `pwd`/linuxBinaries/std /usr/local/share/haxe/std
714
715 - name: Print Haxe version
716 run: haxe -version
717
718 - name: Setup haxelib
719 run: |
720 set -ex
721 mkdir ~/haxelib
722 haxelib setup ~/haxelib
723
724 - name: Install apt packages
725 if: matrix.APT_PACKAGES
726 run: |
727 set -ex
728 sudo apt update -qqy
729 sudo apt install -qqy ${{matrix.APT_PACKAGES}}
730
731 # - name: Flash setup
732 # if: matrix.target == 'flash9'
733 # run: export DISPLAY=:99.0
734
735 - name: Test
736 if: success() && !(matrix.SAUCE && matrix.SAUCE_ACCESS_KEY)
737 run: haxe RunCi.hxml
738 working-directory: ${{github.workspace}}/tests
739
740 - name: Test (with SauceLabs)
741 if: matrix.target == 'js' && success() && matrix.SAUCE && matrix.SAUCE_ACCESS_KEY
742 run: haxe RunCi.hxml
743 working-directory: ${{github.workspace}}/tests
744 env:
745 SAUCE_ACCESS_KEY: matrix.SAUCE_ACCESS_KEY
746
747
748 mac-test:
749 needs: mac-build
750 runs-on: macos-latest
751 env:
752 PLATFORM: mac
753 TEST: ${{matrix.target}}
754 HXCPP_COMPILE_CACHE: ~/hxcache
755 strategy:
756 fail-fast: false
757 matrix:
758 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, lua, neko] #flash9
759 include:
760 - target: hl
761 BREW_PACKAGES: ninja
762 steps:
763 - uses: actions/checkout@main
764 with:
765 submodules: recursive
766 - uses: actions/download-artifact@v1
767 with:
768 name: macBinaries
769
770 - name: Install Neko using snapshot from S3 (Unix)
771 if: ${{ !startsWith(env.PLATFORM, 'windows') }}
772 run: |
773 set -ex
774
775 curl -sSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o $RUNNER_TEMP/neko_latest.tar.gz
776 tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
777 NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
778 sudo mkdir -p /usr/local/bin
779 sudo mkdir -p /usr/local/lib/neko
780 sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools} /usr/local/bin/
781 sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
782 sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
783 echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
784
785 - name: Install Neko using snapshot from S3 (Windows)
786 if: ${{ startsWith(env.PLATFORM, 'windows') }}
787 shell: pwsh
788 run: |
789 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
790 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
791 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
792 echo "$NEKOPATH" >> $env:GITHUB_PATH
793 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
794
795 - name: Print Neko version
796 run: neko -version 2>&1
797
887
798888 - name: Setup Haxe
799889 run: |
800890 # mkdir ./macBinaries
801891 # curl -sSL https://build.haxe.org/builds/haxe/mac/haxe_latest.tar.gz -o ./macBinaries/haxe_bin.tar.gz
802
892
803893 set -ex
804894 tar -xf macBinaries/*_bin.tar.gz -C macBinaries --strip-components=1
805895 sudo mkdir -p /usr/local/bin/
807897 sudo ln -s `pwd`/macBinaries/haxe /usr/local/bin/haxe
808898 sudo ln -s `pwd`/macBinaries/haxelib /usr/local/bin/haxelib
809899 sudo ln -s `pwd`/macBinaries/std /usr/local/share/haxe/std
810
900
811901 - name: Print Haxe version
812902 run: haxe -version
813
903
814904 - name: Setup haxelib
815905 run: |
816906 set -ex
817907 mkdir ~/haxelib
818908 haxelib setup ~/haxelib
819
909
820910 - name: Install homebrew packages
821911 if: matrix.BREW_PACKAGES
822912 run: brew install ${{matrix.BREW_PACKAGES}}
823
913
824914 - name: Test
825915 run: |
826916 # disable invalid Unicode filenames on APFS
827917 echo "" > sys/compile-fs.hxml
828918 haxe RunCi.hxml
829919 working-directory: ${{github.workspace}}/tests
830
920
831921
832922 deploy:
833 if: github.event_name != 'pull_request'
834 needs: [linux-test, mac-test, windows-test, windows64-test]
835 runs-on: ubuntu-18.04
923 if: success() && github.repository_owner == 'HaxeFoundation' && github.event_name != 'pull_request'
924 needs: [linux-test, linux-arm64, mac-test, windows-test, windows64-test]
925 runs-on: ubuntu-20.04
836926 steps:
837927 # this is only needed for to get `COMMIT_DATE`...
838928 # maybe https://github.community/t/expose-commit-timestamp-in-the-github-context-data/16460/3
861951 AWS_ACCESS_KEY_ID: ${{ secrets.HXBUILDS_AWS_ACCESS_KEY_ID }}
862952 AWS_SECRET_ACCESS_KEY: ${{ secrets.HXBUILDS_AWS_SECRET_ACCESS_KEY }}
863953 HXBUILDS_S3ADDR: ${{ secrets.HXBUILDS_S3ADDR }}
954 AWS_EC2_METADATA_DISABLED: true
864955 run: |
865956 set -ex
866957 COMMIT_HASH_SHORT=${GITHUB_SHA:0:7}
867958 COMMIT_DATE=`TZ=UTC git show --quiet --date='format-local:%Y-%m-%d' --format="%cd"`
868959 FILE_NAME=haxe_${COMMIT_DATE}_${{ steps.extract_branch.outputs.branch }}_${COMMIT_HASH_SHORT}
869960 aws s3 cp linuxBinaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/linux64/${FILE_NAME}.tar.gz
961 aws s3 cp linuxArm64Binaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/linux-arm64/${FILE_NAME}.tar.gz
870962 aws s3 cp macBinaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/mac/${FILE_NAME}.tar.gz
871963 aws s3 cp macBinaries/*_installer.tar.gz ${HXBUILDS_S3ADDR}/haxe/mac-installer/${FILE_NAME}.tar.gz
872964 aws s3 cp win64Binaries/*_bin.zip ${HXBUILDS_S3ADDR}/haxe/windows64/${FILE_NAME}.zip
883975 AWS_ACCESS_KEY_ID: ${{ secrets.HXBUILDS_AWS_ACCESS_KEY_ID }}
884976 AWS_SECRET_ACCESS_KEY: ${{ secrets.HXBUILDS_AWS_SECRET_ACCESS_KEY }}
885977 HXBUILDS_S3ADDR: ${{ secrets.HXBUILDS_S3ADDR }}
978 AWS_EC2_METADATA_DISABLED: true
886979 run: |
887980 set -ex
888981 aws s3 cp linuxBinaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/linux64/haxe_latest.tar.gz
982 aws s3 cp linuxArm64Binaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/linux-arm64/haxe_latest.tar.gz
889983 aws s3 cp macBinaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/mac/haxe_latest.tar.gz
890984 aws s3 cp macBinaries/*_installer.tar.gz ${HXBUILDS_S3ADDR}/haxe/mac-installer/haxe_latest.tar.gz
891985 aws s3 cp win64Binaries/*_bin.zip ${HXBUILDS_S3ADDR}/haxe/windows64/haxe_latest.zip
902996 aws s3 cp ${HXBUILDS_S3ADDR}/haxe/windows-choco/${FILE_NAME} ${HXBUILDS_S3ADDR}/haxe/windows-choco/haxe_latest.nupkg --acl public-read --website-redirect "${HXBUILDS_S3PATH}/haxe/windows-choco/${FILE_NAME}"
903997
904998 deploy_apidoc:
905 if: github.event_name != 'pull_request' # TODO: also only when `GHP_REMOTE` is present
906 needs: [linux-test, mac-test, windows-test, windows64-test]
907 runs-on: ubuntu-18.04
908 steps:
999 if: success() && github.repository_owner == 'HaxeFoundation' && github.event_name != 'pull_request'
1000 needs: [linux-test, linux-arm64, mac-test, windows-test, windows64-test]
1001 runs-on: ubuntu-20.04
1002 steps:
1003 - name: Install dependencies
1004 run: |
1005 set -ex
1006 sudo apt-get install -qqy libc6
1007
9091008 - name: Download Haxe
9101009 uses: actions/download-artifact@v2
9111010 with:
99 This repository is about the Haxe compiler itself and the Haxe standard library. Here's an overview of repositories that are part of the Haxe ecosystem:
1010
1111 * The haxelib command line tool or lib.haxe.org: <https://github.com/HaxeFoundation/haxelib/issues>
12 * Something on try.haxe.org: <https://github.com/clemos/try-haxe/issues>
12 * Something on try.haxe.org: <https://github.com/HaxeFoundation/try.haxe.org/issues>
1313 * Something under haxe.org/manual: <https://github.com/HaxeFoundation/HaxeManual/issues>
1414 * Something on api.haxe.org: For content this is probably the right repository. If it's about the representation, try <https://github.com/HaxeFoundation/dox/issues> instead.
1515 * Something else on haxe.org: <https://github.com/HaxeFoundation/haxe.org/issues>
16
17 ## Submitting a Pull-Request
18
19 Thank you for your interest in contributing to Haxe! Haxe is a
20 community-driven project and your help is vital and appreciated!
21
22 When preparing to submit a pull-request, please make your PR as easy
23 as possible for core devs to evaluate and merge. To that end:
24
25 * In your PR comments, include:
26
27 * the reason for your proposed changes (What problem are you fixing?)
28 * some possible solutions, and rationale for the one you chose
29 * a summary of the code changes in your PR
30 * any pros and cons to note about the solution you implemented
31 * links to any relevant GitHub issues, PR's, and/or forum
32 discussions
33
34 * If you've found and fixed a bug, have you also included a
35 corresponding test for it?
36 * Does your code formatting match that of the rest of the project?
37 * If your changes require updates to the documentation, does your PR
38 include those as well?
39
40 Please also bear the following in mind:
41
42 * Evaluating PR's takes time and effort. Even taking a look at a PR
43 in order to request more info or clarification is not zero-cost.
44 * Most members of the core team are volunteers too, and at any given time
45 are typically already busy working on other areas of Haxe.
46 * It's no fun providing negative feedback to a PR. The better you
47 can craft and champion your PR, the more likely it is to be
48 speedily evaluated.
49
50
51 ## Debugging Hints
52
53 ### Using a debugger
54
55 To debug the Haxe compiler, you can use either a system debugger (`gdb`/`lldb`), or [ocamldebug](http://caml.inria.fr/pub/docs/manual-ocaml/debugger.html). `ocamldebug` provides a better debugging experience. To use it, uncomment `(modes byte)` from [src/dune](src/dune) and recompile.
56
57 ### Using printf
58
59 To print information about a type, you can add the following before most lines:
60
61 ```ocaml
62 Printf.printf "%s\n" (s_type_kind t);
63 ```
64
65 There are lots of other stringifying functions, search for "Printing" in `src/core/type.ml` and scroll down to find them.
6616
6717 ## Other remarks:
6818
6919 - 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.
7020 - 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.
71 - We're keeping this page quite short so there's a higher chance that people actually read it.
21 - We're keeping this page quite short so there's a higher chance that people actually read it.
0 VERSION 0.6
1 FROM mcr.microsoft.com/vscode/devcontainers/base:0-bionic
2 ARG DEVCONTAINER_IMAGE_NAME_DEFAULT=ghcr.io/haxefoundation/haxe_devcontainer
3
4 ARG USERNAME=vscode
5 ARG USER_UID=1000
6 ARG USER_GID=$USER_UID
7
8 ARG WORKDIR=/workspace
9 RUN mkdir -m 777 "$WORKDIR"
10 WORKDIR "$WORKDIR"
11
12 ARG --required TARGETARCH
13
14 devcontainer-library-scripts:
15 RUN curl -fsSLO https://raw.githubusercontent.com/microsoft/vscode-dev-containers/main/script-library/common-debian.sh
16 RUN curl -fsSLO https://raw.githubusercontent.com/microsoft/vscode-dev-containers/main/script-library/docker-debian.sh
17 SAVE ARTIFACT --keep-ts *.sh AS LOCAL .devcontainer/library-scripts/
18
19 devcontainer:
20 # Avoid warnings by switching to noninteractive
21 ENV DEBIAN_FRONTEND=noninteractive
22
23 ARG INSTALL_ZSH="false"
24 ARG UPGRADE_PACKAGES="true"
25 ARG ENABLE_NONROOT_DOCKER="true"
26 ARG USE_MOBY="false"
27 COPY .devcontainer/library-scripts/common-debian.sh .devcontainer/library-scripts/docker-debian.sh /tmp/library-scripts/
28 RUN apt-get update \
29 && /bin/bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "true" "true" \
30 && /bin/bash /tmp/library-scripts/docker-debian.sh "${ENABLE_NONROOT_DOCKER}" "/var/run/docker-host.sock" "/var/run/docker.sock" "${USERNAME}" "${USE_MOBY}" \
31 # Clean up
32 && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts/
33
34 # Setting the ENTRYPOINT to docker-init.sh will configure non-root access
35 # to the Docker socket. The script will also execute CMD as needed.
36 ENTRYPOINT [ "/usr/local/share/docker-init.sh" ]
37 CMD [ "sleep", "infinity" ]
38
39 # Configure apt and install packages
40 RUN apt-get update \
41 && apt-get install -qqy --no-install-recommends apt-utils dialog 2>&1 \
42 && apt-get install -qqy --no-install-recommends \
43 iproute2 \
44 procps \
45 sudo \
46 bash-completion \
47 build-essential \
48 curl \
49 wget \
50 software-properties-common \
51 direnv \
52 tzdata \
53 # install docker engine for using `WITH DOCKER`
54 docker-ce \
55 # install node
56 && curl -sL https://deb.nodesource.com/setup_16.x | bash - \
57 && apt-get install -qqy --no-install-recommends nodejs=16.* \
58 # install ocaml and other haxe compiler deps
59 && add-apt-repository ppa:avsm/ppa \
60 && add-apt-repository ppa:haxe/ocaml \
61 && apt-get install -qqy --no-install-recommends \
62 ocaml-nox \
63 camlp5 \
64 opam \
65 libpcre2-dev \
66 zlib1g-dev \
67 libgtk2.0-dev \
68 libmbedtls-dev \
69 ninja-build \
70 libstring-shellquote-perl \
71 libipc-system-simple-perl \
72 #
73 # Clean up
74 && apt-get autoremove -y \
75 && apt-get clean -y \
76 && rm -rf /var/lib/apt/lists/*
77
78 # Switch back to dialog for any ad-hoc use of apt-get
79 ENV DEBIAN_FRONTEND=
80
81 DO +INSTALL_NEKO
82
83 COPY +earthly/earthly /usr/local/bin/
84 RUN earthly bootstrap --no-buildkit --with-autocomplete
85
86 USER $USERNAME
87
88 # Do not show git branch in bash prompt because it's slow
89 # https://github.com/microsoft/vscode-dev-containers/issues/1196#issuecomment-988388658
90 RUN git config --global codespaces-theme.hide-status 1
91
92 # Install OCaml libraries
93 COPY opam .
94 RUN opam init --disable-sandboxing
95 RUN opam install . --yes --deps-only --no-depexts
96 RUN opam list
97 RUN ocamlopt -v
98
99 USER root
100
101 ARG IMAGE_NAME="$DEVCONTAINER_IMAGE_NAME_DEFAULT"
102 ARG IMAGE_TAG="development"
103 ARG IMAGE_CACHE="$IMAGE_NAME:$IMAGE_TAG"
104 SAVE IMAGE --cache-from="$IMAGE_CACHE" --push "$IMAGE_NAME:$IMAGE_TAG"
105
106 devcontainer-multiarch-amd64:
107 ARG IMAGE_NAME="$DEVCONTAINER_IMAGE_NAME_DEFAULT"
108 ARG IMAGE_TAG="development"
109 FROM --platform=linux/amd64 +devcontainer --IMAGE_NAME="$IMAGE_NAME" --IMAGE_TAG="$IMAGE_TAG-amd64"
110 SAVE IMAGE --push "$IMAGE_NAME:$IMAGE_TAG"
111
112 devcontainer-multiarch-arm64:
113 ARG IMAGE_NAME="$DEVCONTAINER_IMAGE_NAME_DEFAULT"
114 ARG IMAGE_TAG="development"
115 FROM --platform=linux/arm64 +devcontainer --IMAGE_NAME="$IMAGE_NAME" --IMAGE_TAG="$IMAGE_TAG-arm64"
116 SAVE IMAGE --push "$IMAGE_NAME:$IMAGE_TAG"
117
118 devcontainer-multiarch:
119 BUILD +devcontainer-multiarch-amd64
120 BUILD +devcontainer-multiarch-arm64
121
122 # Usage:
123 # COPY +earthly/earthly /usr/local/bin/
124 # RUN earthly bootstrap --no-buildkit --with-autocomplete
125 earthly:
126 ARG --required TARGETARCH
127 RUN curl -fsSL https://github.com/earthly/earthly/releases/download/v0.6.13/earthly-linux-${TARGETARCH} -o /usr/local/bin/earthly \
128 && chmod +x /usr/local/bin/earthly
129 SAVE ARTIFACT /usr/local/bin/earthly
130
131 INSTALL_PACKAGES:
132 COMMAND
133 ARG PACKAGES
134 RUN apt-get update -qqy && \
135 apt-get install -qqy --no-install-recommends $PACKAGES && \
136 apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/*
137
138 INSTALL_NEKO:
139 COMMAND
140 ARG NEKOPATH=/neko
141 COPY +neko/* "$NEKOPATH/"
142 ARG PREFIX=/usr/local
143 RUN bash -c "ln -s \"$NEKOPATH\"/{neko,nekoc,nekoml,nekotools} \"$PREFIX/bin/\""
144 RUN bash -c "ln -s \"$NEKOPATH\"/libneko.* \"$PREFIX/lib/\""
145 RUN mkdir -p "$PREFIX/lib/neko/"
146 RUN bash -c "ln -s \"$NEKOPATH\"/*.ndll \"$PREFIX/lib/neko/\""
147 RUN ldconfig
148
149 INSTALL_HAXE:
150 COMMAND
151 ARG PREFIX=/usr/local
152 COPY +build/haxe +build/haxelib "$PREFIX/bin/"
153 COPY std "$PREFIX/share/haxe/std"
154
155 try-neko:
156 DO +INSTALL_NEKO
157 RUN neko -version
158 RUN nekotools
159
160 try-haxe:
161 DO +INSTALL_NEKO
162 DO +INSTALL_HAXE
163 RUN haxe --version
164 RUN haxelib version
165
166 neko:
167 RUN set -ex && \
168 case "$TARGETARCH" in \
169 amd64) PLATFORM=linux64;; \
170 arm64) PLATFORM=linux-arm64;; \
171 *) exit 1;; \
172 esac && \
173 curl -fsSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o neko_latest.tar.gz && \
174 tar -xf neko_latest.tar.gz && \
175 mv `echo neko-*-*` /tmp/neko-unpacked
176 SAVE ARTIFACT /tmp/neko-unpacked/*
177 SAVE IMAGE --cache-hint
178
179 build:
180 FROM +devcontainer
181
182 USER $USERNAME
183
184 # Build Haxe
185 COPY --dir extra libs plugins src* std dune* Makefile* .
186
187 # the Makefile calls git to get commit sha
188 COPY .git .git
189 ARG SET_SAFE_DIRECTORY="false"
190 IF [ "$SET_SAFE_DIRECTORY" = "true" ]
191 RUN git config --global --add safe.directory "$WORKDIR"
192 END
193
194 ARG ADD_REVISION
195 ENV ADD_REVISION=$ADD_REVISION
196 RUN opam config exec -- make -s -j`nproc` STATICLINK=1 haxe && ldd -v ./haxe
197 RUN opam config exec -- make -s haxelib && ldd -v ./haxelib
198 RUN make -s package_unix && ls -l out
199
200 ARG TARGETPLATFORM
201 SAVE ARTIFACT --keep-ts ./out/* AS LOCAL out/$TARGETPLATFORM/
202 SAVE ARTIFACT --keep-ts ./haxe AS LOCAL out/$TARGETPLATFORM/
203 SAVE ARTIFACT --keep-ts ./haxelib AS LOCAL out/$TARGETPLATFORM/
204 SAVE IMAGE --cache-hint
205
206 build-multiarch:
207 ARG ADD_REVISION
208 BUILD --platform=linux/amd64 --platform=linux/arm64 +build --ADD_REVISION=$ADD_REVISION
209
210 xmldoc:
211 DO +INSTALL_NEKO
212 DO +INSTALL_HAXE
213
214 COPY --dir extra .
215
216 WORKDIR extra
217 RUN haxelib newrepo
218 RUN haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp
219 RUN haxelib git hxjava https://github.com/HaxeFoundation/hxjava
220 RUN haxelib git hxcs https://github.com/HaxeFoundation/hxcs
221 RUN haxe doc.hxml
222
223 ARG COMMIT
224 ARG BRANCH
225 RUN echo "{\"commit\":\"$COMMIT\",\"branch\":\"$BRANCH\"}" > doc/info.json
226
227 SAVE ARTIFACT --keep-ts ./doc AS LOCAL extra/doc
228
229 test-environment:
230 # we use a sightly newer ubuntu for easier installation of the target runtimes (e.g. php)
231 FROM ubuntu:focal
232 DO +INSTALL_NEKO
233 DO +INSTALL_HAXE
234
235 ENV DEBIAN_FRONTEND=noninteractive
236 DO +INSTALL_PACKAGES --PACKAGES="ca-certificates curl wget git build-essential locales sqlite3"
237
238 # Node.js is required as there are tests that use it (search "-cmd node")
239 RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash - && \
240 apt-get install -qqy nodejs && \
241 apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/*
242
243 # set locale
244 RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
245 ENV LANG=en_US.UTF-8
246 ENV LANGUAGE=en_US:en
247 ENV LC_ALL=en_US.UTF-8
248
249 SAVE IMAGE --cache-hint
250
251 test-environment-java:
252 FROM +test-environment
253 DO +INSTALL_PACKAGES --PACKAGES="default-jdk"
254 SAVE IMAGE --cache-hint
255
256 test-environment-js:
257 # somehow js tests require hxjava which in turns require javac
258 FROM +test-environment-java
259
260 test-environment-python:
261 FROM +test-environment
262 DO +INSTALL_PACKAGES --PACKAGES="python3"
263 SAVE IMAGE --cache-hint
264
265 test-environment-php:
266 FROM +test-environment
267 DO +INSTALL_PACKAGES --PACKAGES="php-cli php-mbstring php-sqlite3"
268 SAVE IMAGE --cache-hint
269
270 test-environment-cs:
271 FROM +test-environment
272 DO +INSTALL_PACKAGES --PACKAGES="mono-devel mono-mcs"
273 SAVE IMAGE --cache-hint
274
275 test-environment-hl:
276 FROM +test-environment
277 DO +INSTALL_PACKAGES --PACKAGES="cmake ninja-build libturbojpeg-dev libpng-dev zlib1g-dev libvorbis-dev libsqlite3-dev"
278 SAVE IMAGE --cache-hint
279
280 test-environment-lua:
281 # hererocks uses pip
282 FROM +test-environment-python
283 DO +INSTALL_PACKAGES --PACKAGES="libssl-dev libreadline-dev python3-pip unzip libpcre2-dev cmake"
284 RUN ln -s /root/.local/bin/hererocks /bin/
285 SAVE IMAGE --cache-hint
286
287 test-environment-cpp:
288 FROM +test-environment
289
290 ARG TARGETPLATFORM
291
292 IF [ "$TARGETPLATFORM" = "linux/amd64" ]
293 DO +INSTALL_PACKAGES --PACKAGES="g++-multilib"
294 ELSE IF [ "$TARGETPLATFORM" = "linux/arm64" ]
295 DO +INSTALL_PACKAGES --PACKAGES="g++-multilib-arm-linux-gnueabi"
296 ELSE
297 RUN echo "Unsupported platform $TARGETPLATFORM" && exit 1
298 END
299
300 SAVE IMAGE --cache-hint
301
302 test-environment-flash:
303 # apache flex requires java
304 FROM +test-environment-java
305 # requirements for running flash player
306 DO +INSTALL_PACKAGES --PACKAGES="libglib2.0-0 libfreetype6 xvfb libxcursor1 libnss3 libgtk2.0-0"
307 SAVE IMAGE --cache-hint
308
309 RUN_CI:
310 COMMAND
311 COPY tests tests
312 RUN mkdir /haxelib && haxelib setup /haxelib
313 WORKDIR tests
314 ARG --required TEST
315 ENV TEST="$TEST"
316 RUN haxe RunCi.hxml
317
318 test-macro:
319 FROM +test-environment
320 ARG GITHUB_ACTIONS
321 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
322 DO +RUN_CI --TEST=macro
323
324 test-neko:
325 FROM +test-environment
326 ARG GITHUB_ACTIONS
327 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
328 DO +RUN_CI --TEST=neko
329
330 test-js:
331 FROM +test-environment-js
332 ARG GITHUB_ACTIONS
333 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
334 DO +RUN_CI --TEST=js
335
336 test-hl:
337 FROM +test-environment-hl
338 ARG GITHUB_ACTIONS
339 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
340 DO +RUN_CI --TEST=hl
341
342 test-cpp:
343 FROM +test-environment-cpp
344 ARG GITHUB_ACTIONS
345 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
346 DO +RUN_CI --TEST=cpp
347
348 test-java:
349 FROM +test-environment-java
350 ARG GITHUB_ACTIONS
351 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
352 DO +RUN_CI --TEST=java
353
354 test-jvm:
355 FROM +test-environment-java
356 ARG GITHUB_ACTIONS
357 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
358 DO +RUN_CI --TEST=jvm
359
360 test-cs:
361 FROM +test-environment-cs
362 ARG GITHUB_ACTIONS
363 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
364 DO +RUN_CI --TEST=cs
365
366 test-php:
367 FROM +test-environment-php
368 ARG GITHUB_ACTIONS
369 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
370 DO +RUN_CI --TEST=php
371
372 test-python:
373 FROM +test-environment-python
374 ARG GITHUB_ACTIONS
375 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
376 DO +RUN_CI --TEST=python
377
378 test-lua:
379 FROM +test-environment-lua
380 ARG GITHUB_ACTIONS
381 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
382 DO +RUN_CI --TEST=lua
383
384 test-flash:
385 FROM +test-environment-flash
386 ARG GITHUB_ACTIONS
387 ENV GITHUB_ACTIONS=$GITHUB_ACTIONS
388 DO +RUN_CI --TEST=flash
389
390 test-all:
391 ARG TARGETPLATFORM
392
393 BUILD +test-macro
394 BUILD +test-neko
395 BUILD +test-php
396 BUILD +test-python
397 BUILD +test-java
398 BUILD +test-jvm
399 BUILD +test-cs
400 BUILD +test-cpp
401 BUILD +test-lua
402 BUILD +test-js
403 BUILD +test-flash
404
405 IF [ "$TARGETPLATFORM" = "linux/amd64" ]
406 BUILD +test-hl # FIXME: hl can't compile on arm64 (JIT issue?)
407 END
408
409 github-actions:
410 DO +INSTALL_NEKO
411 DO +INSTALL_HAXE
412 RUN mkdir -p "$WORKDIR"/.github/workflows
413 COPY extra/github-actions extra/github-actions
414 WORKDIR extra/github-actions
415 RUN haxe build.hxml
416 SAVE ARTIFACT --keep-ts "$WORKDIR"/.github/workflows AS LOCAL .github/workflows
417
418 ghcr-login:
419 LOCALLY
420 RUN echo "$GITHUB_CR_PAT" | docker login ghcr.io -u "$GITHUB_USERNAME" --password-stdin
5858 HAXE_VERSION=$(shell $(CURDIR)/$(HAXE_OUTPUT) -version 2>&1 | awk '{print $$1;}')
5959 HAXE_VERSION_SHORT=$(shell echo "$(HAXE_VERSION)" | grep -oE "^[0-9]+\.[0-9]+\.[0-9]+")
6060
61 NEKO_VERSION=2.3.0
62 NEKO_MAJOR_VERSION=$(shell echo "$(NEKO_VERSION)" | grep -oE "^[0-9]+")
63 NEKO_VERSION_TAG=v$(shell echo "$(NEKO_VERSION)" | sed "s/\./-/g")
64
6165 ifneq ($(STATICLINK),0)
62 LIB_PARAMS= -cclib '-Wl,-Bstatic -lpcre -lz -lmbedtls -lmbedx509 -lmbedcrypto -Wl,-Bdynamic '
66 LIB_PARAMS= -cclib '-Wl,-Bstatic -lpcre2-8 -lz -lmbedtls -lmbedx509 -lmbedcrypto -Wl,-Bdynamic '
6367 else
64 LIB_PARAMS?= -cclib -lpcre -cclib -lz -cclib -lmbedtls -cclib -lmbedx509 -cclib -lmbedcrypto
68 LIB_PARAMS?= -cclib -lpcre2-8 -cclib -lz -cclib -lmbedtls -cclib -lmbedx509 -cclib -lmbedcrypto
6569 endif
6670 ifeq ($(SYSTEM_NAME),Mac)
6771 LIB_PARAMS+= -cclib '-framework Security -framework CoreFoundation'
164168 mkdir -p $(INSTALLER_TMP_DIR)
165169
166170 $(INSTALLER_TMP_DIR)/neko-osx64.tar.gz: $(INSTALLER_TMP_DIR)
167 wget -nv https://github.com/HaxeFoundation/neko/releases/download/v2-3-0/neko-2.3.0-osx64.tar.gz -O installer/neko-osx64.tar.gz
171 wget -nv https://github.com/HaxeFoundation/neko/releases/download/$(NEKO_VERSION_TAG)/neko-$(NEKO_VERSION)-osx64.tar.gz -O installer/neko-osx64.tar.gz
168172
169173 # Installer
170174
172176 $(eval OUTFILE := $(shell pwd)/$(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_installer.tar.gz)
173177 $(eval PACKFILE := $(shell pwd)/$(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_bin.tar.gz)
174178 $(eval VERSION := $(shell $(CURDIR)/$(HAXE_OUTPUT) -version 2>&1))
175 $(eval NEKOVER := $(shell neko -version 2>&1))
176179 bash -c "rm -rf $(INSTALLER_TMP_DIR)/{resources,pkg,tgz,haxe.tar.gz}"
177180 mkdir $(INSTALLER_TMP_DIR)/resources
178181 # neko - unpack to change the dir name
185188 cd $(INSTALLER_TMP_DIR)/resources && tar -zcvf haxe.tar.gz haxe
186189 # scripts
187190 cp -rf extra/mac-installer/* $(INSTALLER_TMP_DIR)/resources
191 sed -i '' 's/%%NEKO_VERSION%%/$(NEKO_VERSION)/g' $(INSTALLER_TMP_DIR)/resources/scripts/neko-postinstall.sh
192 sed -i '' 's/%%NEKO_MAJOR_VERSION%%/$(NEKO_MAJOR_VERSION)/g' $(INSTALLER_TMP_DIR)/resources/scripts/neko-postinstall.sh
188193 cd $(INSTALLER_TMP_DIR)/resources && tar -zcvf scripts.tar.gz scripts
189194 # installer structure
190195 mkdir -p $(INSTALLER_TMP_DIR)/pkg
200205 sed -i '' 's/%%VERSION%%/$(VERSION)/g' PackageInfo ;\
201206 sed -i '' 's/%%VERSTRING%%/$(VERSION)/g' PackageInfo ;\
202207 sed -i '' 's/%%VERLONG%%/$(VERSION)/g' PackageInfo ;\
203 sed -i '' 's/%%NEKOVER%%/$(NEKOVER)/g' PackageInfo ;\
208 sed -i '' 's/%%NEKOVER%%/$(NEKO_VERSION)/g' PackageInfo ;\
204209 cd .. ;\
205210 sed -i '' 's/%%VERSION%%/$(VERSION)/g' Distribution ;\
206211 sed -i '' 's/%%VERSTRING%%/$(VERSION)/g' Distribution ;\
207212 sed -i '' 's/%%VERLONG%%/$(VERSION)/g' Distribution ;\
208 sed -i '' 's/%%NEKOVER%%/$(NEKOVER)/g' Distribution ;\
213 sed -i '' 's/%%NEKOVER%%/$(NEKO_VERSION)/g' Distribution ;\
209214 sed -i '' 's/%%INSTKB%%/$$INSTKBH/g' Distribution"
210215 # repackage
211216 cd $(INSTALLER_TMP_DIR)/pkg; xar --compression none -cf ../$(PACKAGE_FILE_NAME).pkg *
4242 endif
4343
4444 ifeq ($(STATICLINK),0)
45 LIB_PARAMS = -cclib -lpcre -cclib -lz -cclib -lcrypt32 -cclib -lmbedtls -cclib -lmbedcrypto -cclib -lmbedx509
45 LIB_PARAMS = -cclib -lpcre2-8 -cclib -lz -cclib -lcrypt32 -cclib -lmbedtls -cclib -lmbedcrypto -cclib -lmbedx509
4646 endif
4747
4848 PACKAGE_FILES=$(HAXE_OUTPUT) $(HAXELIB_OUTPUT) std \
4949 "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep zlib1.dll | sed -e 's/^\s*//')" \
50 "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libpcre-1.dll | sed -e 's/^\s*//')" \
50 "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libpcre2-8-0.dll | sed -e 's/^\s*//')" \
5151 "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedcrypto.dll | sed -e 's/^\s*//')" \
5252 "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedtls.dll | sed -e 's/^\s*//')" \
5353 "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedx509.dll | sed -e 's/^\s*//')"
7474 mkdir -p OUTPUT
7575 7z x -y out/$(PACKAGE_FILE_NAME)_bin.zip -oout > log.txt || type log.txt
7676 mv out/$(PACKAGE_FILE_NAME) out/choco
77 sed -e 's/@SNAPSHOT_VERSION@/$(HAXE_VERSION_SHORT)-SNAP$(COMMIT_DATE)/g' extra/choco/haxe.nuspec > out/choco/haxe.nuspec
77 cp extra/choco/haxe.nuspec out/choco/haxe.nuspec
78 sed -i 's/@SNAPSHOT_VERSION@/$(HAXE_VERSION_SHORT)-SNAP$(COMMIT_DATE)/g' out/choco/haxe.nuspec
79 sed -i 's/@NEKO_VERSION@/$(NEKO_VERSION)/g' out/choco/haxe.nuspec
7880 cd out/choco && choco pack
7981 mv out/choco/haxe.*.nupkg out
8082 rm -rf out/choco
8183
8284 $(INSTALLER_TMP_DIR)/neko-win.zip: $(INSTALLER_TMP_DIR)
83 wget -nv https://github.com/HaxeFoundation/neko/releases/download/v2-3-0/neko-2.3.0-win$(NEKO_ARCH_STR).zip -O installer/neko-win.zip
85 wget -nv https://github.com/HaxeFoundation/neko/releases/download/$(NEKO_VERSION_TAG)/neko-$(NEKO_VERSION)-win$(NEKO_ARCH_STR).zip -O installer/neko-win.zip
8486
8587 package_installer_win: $(INSTALLER_TMP_DIR)/neko-win.zip package_win
8688 $(eval OUTFILE := $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_installer.zip)
103105 sed -i "s/%%VERSION%%/$(HAXE_VERSION_SHORT)/g" $(INSTALLER_TMP_DIR)/installer.nsi
104106 sed -i "s/%%VERSTRING%%/$(HAXE_VERSION)/g" $(INSTALLER_TMP_DIR)/installer.nsi
105107 sed -i "s/%%VERLONG%%/$(HAXE_VERSION)/g" $(INSTALLER_TMP_DIR)/installer.nsi
108 sed -i "s/%%NEKO_VERSION%%/$(NEKO_VERSION)/g" $(INSTALLER_TMP_DIR)/installer.nsi
106109 cd $(INSTALLER_TMP_DIR) && makensis installer.nsi
107110 7z a -r -tzip $(OUTFILE) $(INSTALLER_TMP_DIR)/*.exe
108111 dir $(PACKAGE_OUT_DIR)
0 (lang dune 1.11)
0 (lang dune 3.0)
11 (name haxe)
22
33 (package
66
77 (package
88 (name haxe_prebuild)
9 )
9 )
3535 To install the native libraries, use the appropriate system package manager.
3636
3737 * Mac OS X
38 * Use [Homebrew](https://brew.sh/), `brew install zlib pcre`.
38 * Use [Homebrew](https://brew.sh/), `brew install zlib pcre2`.
3939 * Debian / Ubuntu
40 * `sudo apt install libpcre3-dev zlib1g-dev`.
40 * `sudo apt install libpcre2-dev zlib1g-dev libmbedtls-dev`.
4141 * Windows (Cygwin)
42 * Run the Cygwin [setup-x86_64.exe](https://cygwin.com/install.html) against the Cygwin installation directory. Install `make`, `git`, `zlib-devel`, `libpcre-devel`, `mingw64-x86_64-gcc-core`, `mingw64-x86_64-zlib`, and `mingw64-x86_64-pcre`. You may need to select "Not Installed" in the dropdown list to see the packages. Copy `zlib1.dll` and `libpcre-1.dll` from `path/to/cygwin/usr/x86_64-w64-mingw32/sys-root/mingw/bin` to the checked out Haxe source directory.
42 * Run the Cygwin [setup-x86_64.exe](https://cygwin.com/install.html) against the Cygwin installation directory. Install `make`, `git`, `zlib-devel`, `libpcre2-devel`, `mingw64-x86_64-gcc-core`, `mingw64-x86_64-zlib`, and `mingw64-x86_64-pcre2`. You may need to select "Not Installed" in the dropdown list to see the packages. Copy `zlib1.dll` and `libpcre2-8-0.dll` from `path/to/cygwin/usr/x86_64-w64-mingw32/sys-root/mingw/bin` to the checked out Haxe source directory.
4343 * Install Neko by either
4444 * Download the [Neko binaries](https://nekovm.org/download/), and add the extracted directory to the beginning of PATH.
4545 * Install the [Chocolatey Neko package](https://chocolatey.org/packages/neko).
0 2023-04-06 4.3.0
1
2 New features:
3
4 all : support defaults for type parameters (#10518)
5 all : support @:op(a()) on abstracts (#10119)
6 all : support abstract keyword to reference the abstract (#10513)
7 all : support static var at expression-level (#10555)
8 all : support ?. safe navigation operator (#10561)
9 all : added ?? null coalescing operator (#10428)
10 all : add -w compiler option to configure warnings (#10612)
11 all : added new error reporting modes (#10863)
12 all : support custom metadata and defines (#10858)
13
14 General improvements:
15
16 all : made various optimizations in the analyzer
17 all : made various improvements to diagnostics
18 all : made various improvements to null-safety
19 all : optimize `.bind` for instance methods (#10737)
20 all : improved various parser error messages
21 all : improved compilation server performance
22 all : improved code generation for try/catch (#10519)
23 all : infer property accessor type from the property (#10569)
24 all : improved inference of local functions typed against abstracts (#10336)
25 all : improved completion on module-level fields
26 all : improved handling of native libraries on the compilation server
27 all : improved performance when generating locals (#10648)
28 all : made Std.parseInt more consistent across targets (#10664)
29 all : infer null literals as Null<?> (#7736)
30 all : made field access errors more consistent (#10896)
31 all : consistently allow trailing commas (#11009)
32 all : migrated all relevant targets to PCRE2 (#10491)
33 all : made analyzer reconstruct do-while loops (#7979)
34 all : improved restrictions on init macros (#11043)
35 all : improved positions of @:structInit fields (#9318)
36 macro : support map literals in Context.makeExpr (#10259)
37 macro : added haxe.macro.Compiler.getConfiguration() (#10871)
38 macro : added withImports and withOption to haxe.macro.Context
39 macro : added getMacroStack and onAfterInitMacros to haxe.macro.Context (#11043)
40 macro : added haxe.macro.Context.makeMonomorph (#10728)
41 eval : added dictionary mode to objects, increasing performance in some cases (#10284)
42 eval : fixed Sys.exit handling messing up the compilation server (#10642)
43 eval : added -D eval-print-depth and -D eval-pretty-print (#10952, #10963)
44 cpp : supported type parameters on extern classes (#10415)
45 cpp : haxe.Int64 improvements (#9935)
46 cpp : non-blocking process exit code reading (#10321)
47 js : improved type names for debugger (#10894)
48 lua : added SSL implementation (#10593)
49 lua : fixed String API when -D no-inline was in place (#11057)
50 lua : non-zero exit code in case of uncaught exception (#11082)
51 java : deal with default implementations when loading extern libraries (#10466)
52 jvm : improved closure naming (#10571)
53 jvm : supported --jvm dir (#10614)
54 jvm : added some missing TShort and TFloat handling (#10722)
55 jvm : added experimental support for functional interfaces (#11019)
56 php : added and fixed several extern functions
57
58 Standard Library:
59
60 all : added atomic operations to several targets (#10610)
61 all : added Vector.fill (#10687)
62 sys : added sys.thread.Condition and Semaphore (#10503)
63 sys : added Http.getResponseHeaderValues to deal with multiple values of same key (#10812)
64 sys : make Sys.environment consistent between targets (#10460)
65 sys : consistent way to unset environment variables with Sys.putEnv (#10402)
66
67 Bugfixes:
68
69 all : properly disallowed macro reification in invalid places (#10883)
70 all : fixed behavior when extending abstract classes with final fields (#10139)
71 all : addressed some issues with constructor inlining (#10304)
72 all : fixed pattern matcher bug related to null-guards (#10291)
73 all : fixed weird parser behavior on first offset in files (#10322)
74 all : fixed various issues related to the final modifier
75 all : fixed various issues related to overload handling
76 all : fixed precedence of => vs. ?: (#10455)
77 all : made error positions in structure declarations more accurate (#9584)
78 all : brought back proper check when accessing super fields (#10521)
79 all : fixed @:publicFields on abstracts (#10541)
80 all : inherited some metadata to @:generic implementation classes (#10557)
81 all : fixed various problems in EventLoop and MainLoop
82 all : fixed infinite recursion from invalid inheritance (#10245)
83 all : fixed strange interaction between static extensions and macro functions (#10587)
84 all : fixed problems with @:generic on the compilation server (#10635)
85 all : fixed Context.onTypeNotFound being called multiple times for the same thing (#10678)
86 all : fixed type parameter problem involving abstract classes and interfaces (#10748)
87 all : fixed #if (a != b) yielding true for nonexistent values (#10868)
88 all : fixed interaction between @:generic and abstract class (#10735)
89 all : fixed @:using loading types too eagerly (#10107)
90 all : fixed parser ignoring subsequent documentation comments (#10171)
91 all : fixed parser function messing up unrelated file state in some cases (#10763)
92 all : unified Map printing to always use [] (#9260)
93 cpp : fixed problem with cpp.Pointer being used in enum arguments (#10831)
94 macro : improved handling of macro this expressions (#10793)
95 eval : fixed bit shift operations > 31 (#10752)
96 eval : fixed Bytes.toString causing an internal exception (#10623)
97 jvm : fixed @:native processing (#10280)
98 jvm : fixed Type.getEnumConstructs on native enums (#10508)
99 jvm : fixed @:volatile being ignored (#10594)
100 jvm : fixed some hashing issue when pattern matching on emojis (#10720)
101 jvm : fixed stack handling on return return (#10743)
102 hl : fixed various code generation problems
103 python : fixed SslSocket for newer python versions (#8401)
104 python : fixed syntax issue related to Vector (#11060)
105
0106 2021-03-06 4.2.5:
1107
2108 New features:
9331039 Bugfixes:
9341040
9351041 php7: fix Reflect.field() for strings (#6276)
936 php7: fix `@:enum abstract` generation without `-dce full` (#6175)
1042 php7: fix `@:enum abstract` generation without `-dce full` (#6175)
9371043 php7: fix using enum constructor with arguments as a call argument (#6177)
9381044 php7: fix `null` property access (#6281)
9391045 php7: fix setting values in a map stored in another map (#6257)
9791085
9801086 all : fixed DCE issue with interface fields (#6502)
9811087 cpp : fixed return typing for embedded closures (#6121)
982 php7: fixed `@:enum abstract` generation without `-dce full` (#6175)
1088 php7: fixed `@:enum abstract` generation without `-dce full` (#6175)
9831089 php7: fixed using enum constructor with arguments as a call argument (#6177)
9841090 php7: fixed accessing methods on dynamic values (#6211)
9851091 php7: fixed `null` property access (#6281)
16951801 all : allow to access root package with std prefix (std.Type for example)
16961802 all : added haxe.EnumFlags
16971803 sys : io.File.getChar/stdin/stdout/stderr are now in Sys class
1698 cpp : Reflect.getField and Reflect.setField no longer call property functions. Use Reflect.getProperty and Refelect.setProperty instead.
1804 cpp : Reflect.getField and Reflect.setField no longer call property functions. Use Reflect.getProperty and Refelect.setProperty instead.
16991805 cpp : Default arguments now use Null<T> for performance increase and interface compatibility
17001806 cpp : Added metadata options for injecting native cpp code into headers, classes and functions
17011807 php : added php.Lib.mail
9898 case "haxe.remoting.SyncSocketConnection": if( !(Context.defined("neko") || Context.defined("php") || Context.defined("cpp")) ) continue;
9999 case "neko.vm.Ui" | "sys.db.Sqlite" | "sys.db.Mysql" if ( Context.defined("interp") ): continue;
100100 case "sys.db.Sqlite" | "sys.db.Mysql" | "cs.db.AdoNet" if ( Context.defined("cs") ): continue;
101 case "haxe.atomic.AtomicBool" if(!Context.defined("target.atomics")): continue;
102 case "haxe.atomic.AtomicInt" if(!Context.defined("target.atomics")): continue;
103 case "haxe.atomic.AtomicObject" if(!Context.defined("target.atomics") || Context.defined("js") || Context.defined("cpp")): continue;
101104 }
102105 Context.getModule(cl);
103106 } else if( sys.FileSystem.isDirectory(p + "/" + file) )
1616 <requireLicenseAcceptance>false</requireLicenseAcceptance>
1717 <summary>Haxe is an open source toolkit based on a modern, high level, strictly typed programming language, a cross-compiler, a complete cross-platform standard library and ways to access each platform's native capabilities.</summary>
1818 <description>Haxe is an open source toolkit based on a modern, high level, strictly typed programming language, a cross-compiler, a complete cross-platform standard library and ways to access each platform's native capabilities.
19
19
2020 This package will install haxe and haxelib. After installation, you should run `haxelib setup %path%;`, where `%path%` is the haxelib repository folder for placing third-party libraries. The folder should be created manually before running the command.</description>
2121 <releaseNotes>https://github.com/HaxeFoundation/haxe/blob/master/extra/CHANGES.txt</releaseNotes>
2222 <tags>haxe programming development foss cross-platform</tags>
2323 <dependencies>
24 <dependency id="neko" version="2.1.0" />
24 <dependency id="neko" version="@NEKO_VERSION@" />
2525 </dependencies>
2626 </metadata>
27 </package>
27 </package>
2323 final path = reg.matched(2);
2424 final template = File.getContent('./$path');
2525 final lines = template.split("\n");
26 for (i in 0...lines.length) lines[i] = spaces + lines[i];
26 for (i in 0...lines.length)
27 lines[i] = (spaces + lines[i]).rtrim();
2728 lines.join("\n");
2829 });
2930
+0
-61
extra/github-actions/build-linux.yml less more
0 - name: Install dependencies
1 run: |
2 set -ex
3 sudo add-apt-repository ppa:avsm/ppa -y # provides OPAM 2
4 sudo add-apt-repository ppa:haxe/ocaml -y # provides newer version of mbedtls
5 sudo apt-get update -qqy
6 sudo apt-get install -qqy ocaml-nox camlp5 opam libpcre3-dev zlib1g-dev libgtk2.0-dev libmbedtls-dev ninja-build libstring-shellquote-perl
7
8 - name: Install OCaml libraries
9 run: |
10 set -ex
11 opam init # --disable-sandboxing
12 opam update
13 opam pin add haxe . --no-action
14 opam install haxe --deps-only --assume-depexts
15 opam list
16 ocamlopt -v
17
18 - name: Set ADD_REVISION=1 for non-release
19 if: ${{ !startsWith(github.ref, 'refs/tags/') }}
20 run: echo "ADD_REVISION=1" >> $GITHUB_ENV
21
22 - name: Build Haxe
23 run: |
24 set -ex
25 eval $(opam env)
26 opam config exec -- make -s -j`nproc` STATICLINK=1 haxe
27 opam config exec -- make -s haxelib
28 make -s package_unix
29 ls -l out
30 ldd -v ./haxe
31 ldd -v ./haxelib
32
33 # https://stackoverflow.com/questions/58033366/how-to-get-current-branch-within-github-actions
34 - name: Extract branch name
35 id: extract_branch
36 shell: bash
37 run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
38
39 - name: Build xmldoc
40 run: |
41 set -ex
42 make -s xmldoc
43 cat >extra/doc/info.json <<EOL
44 {
45 "commit": "$GITHUB_SHA",
46 "branch": "${{ steps.extract_branch.outputs.branch }}"
47 }
48 EOL
49
50 - name: Upload xmldoc artifact
51 uses: actions/upload-artifact@v1.0.0
52 with:
53 name: xmldoc
54 path: extra/doc
55
56 - name: Upload artifact
57 uses: actions/upload-artifact@v1.0.0
58 with:
59 name: linuxBinaries
60 path: out
00 - name: Install dependencies
11 env:
2 ZLIB_VERSION: 1.2.11
2 # For compatibility with macOS 10.13
3 ZLIB_VERSION: 1.2.13
34 MBEDTLS_VERSION: 2.25.0
4 PCRE_VERSION: 10.39
5 PCRE2_VERSION: 10.42
56 run: |
67 set -ex
78 brew uninstall openssl@1.0.2t || echo
1112 brew update
1213 # brew unlink python@2
1314 brew bundle --file=tests/Brewfile --no-upgrade || brew link --overwrite awscli
15 brew install libunistring
1416 brew install cpanminus
1517 cpanm IPC::System::Simple
1618 cpanm String::ShellQuote
1820 cd zlib-$ZLIB_VERSION
1921 ./configure
2022 make && make install
23 cd ..
2124 curl -L https://github.com/ARMmbed/mbedtls/archive/v$MBEDTLS_VERSION.tar.gz | tar xz
2225 cd mbedtls-$MBEDTLS_VERSION
2326 make && make install
24 curl -L https://github.com/PhilipHazel/pcre2/releases/download/pcre2-10.39/pcre2-$PCRE_VERSION.tar.gz | tar xz
25 cd pcre2-$PCRE_VERSION
26 ./configure --enable-utf8 --enable-pcre2-8 --enable-pcre2-16 --enable-pcre2-32 --enable-unicode-properties --enable-pcregrep-libz --enable-pcregrep-libbz2 --enable-jit
27 cd ..
28 curl -L https://github.com/PCRE2Project/pcre2/releases/download/pcre2-$PCRE2_VERSION/pcre2-$PCRE2_VERSION.tar.gz | tar xz
29 cd pcre2-$PCRE2_VERSION
30 ./configure --enable-unicode --enable-pcre2-8 --enable-pcre2-16 --enable-pcre2-32 --enable-unicode-properties --enable-pcre2grep-libz --enable-pcre2grep-libbz2 --enable-jit
2731 make && make install
32 cd ..
2833
2934
3035 - name: Install OCaml libraries
36 if: steps.cache-opam.outputs.cache-hit != 'true'
3137 run: |
3238 set -ex
3339 opam init # --disable-sandboxing
4955 run: |
5056 set -ex
5157 eval $(opam env)
52 opam config exec -- make -s -j`sysctl -n hw.ncpu` STATICLINK=1 "LIB_PARAMS=/usr/local/lib/libz.a /usr/local/lib/libpcre.a /usr/local/lib/libmbedtls.a /usr/local/lib/libmbedcrypto.a /usr/local/lib/libmbedx509.a -cclib '-framework Security -framework CoreFoundation'" haxe
58 opam config exec -- make -s -j`sysctl -n hw.ncpu` STATICLINK=1 "LIB_PARAMS=/usr/local/lib/libz.a /usr/local/lib/libpcre2-8.a /usr/local/lib/libmbedtls.a /usr/local/lib/libmbedcrypto.a /usr/local/lib/libmbedx509.a -cclib '-framework Security -framework CoreFoundation'" haxe
5359 opam config exec -- make -s haxelib
5460 make -s package_unix package_installer_mac
5561 ls -l out
0 - name: choco install nsis
1 uses: nick-invision/retry@v1
2 with:
3 timeout_minutes: 10
4 max_attempts: 10
5 command: choco install --no-progress nsis.portable --version 3.02 -y
6 - name: choco install things
0 - name: Expose mingw dll files
71 shell: pwsh
8 run: choco install --no-progress curl wget 7zip.portable -y
9 - name: Prepend Chocolatey path
10 shell: pwsh
11 run: Write-Host "::add-path::C:\ProgramData\chocolatey\bin"
2 run: Write-Host "::add-path::${env:CYG_ROOT}/usr/$($env:MINGW_ARCH)-w64-mingw32/sys-root/mingw/bin"
123
13 - name: Install OCaml and OCaml libraries
4 # required to be able to retrieve the revision
5 - name: Mark directory as safe
146 shell: pwsh
157 run: |
168 Set-PSDebug -Trace 1
17 curl.exe -fsSL -o cygwin-setup.exe --retry 3 $($env:CYGWIN_SETUP)
18 Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $($env:CYG_ROOT) -l C:/tmp -s $($env:CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre-devel -P mbedtls-devel -P mingw64-$($env:MINGW_ARCH)-zlib -P mingw64-$($env:MINGW_ARCH)-gcc-core -P mingw64-$($env:MINGW_ARCH)-pcre" -Wait
19 curl.exe -fsSL -o "opam.tar.xz" --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.2/opam$($env:ARCH).tar.xz
20 curl.exe -fsSL -o "libmbedtls.tar.xz" --retry 3 https://github.com/Simn/mingw64-mbedtls/releases/download/2.16.3/mingw64-$($env:MINGW_ARCH)-mbedtls-2.16.3-1.tar.xz
21 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'curl -L https://cpanmin.us | perl - App::cpanminus')
22 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm IPC::System::Simple module')
23 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm String::ShellQuote')
24 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'echo "$OLDPWD"')
25 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -C / -xvf libmbedtls.tar.xz')
26 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -xf opam.tar.xz')
27 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && bash opam${ARCH}/install.sh')
28 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam init mingw "https://github.com/fdopen/opam-repository-mingw.git#opam2" --comp 4.07.0+mingw${ARCH}c --switch 4.07.0+mingw${ARCH}c --auto-setup --yes 2>&1')
29 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam update --yes 2>&1')
30 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam pin add haxe . --kind=path --no-action --yes 2>&1')
31 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam pin add ctypes 0.17.1 --yes 2>&1')
32 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam install haxe --deps-only --yes 2>&1')
33 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam list')
34 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'ocamlopt -v')
35
36 - name: Expose mingw dll files
37 shell: pwsh
38 run: Write-Host "::add-path::${env:CYG_ROOT}/usr/$($env:MINGW_ARCH)-w64-mingw32/sys-root/mingw/bin"
9 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'git config --global --add safe.directory "$OLDPWD"')
3910
4011 - name: Set ADD_REVISION=1 for non-release
4112 if: ${{ !startsWith(github.ref, 'refs/tags/') }}
0 - name: Cache opam
1 id: cache-opam
2 uses: actions/cache@v3.0.11
3 with:
4 path: ~/.opam/
5 key: ${{ runner.os }}-${{ hashFiles('./opam', './libs/') }}-2
0 - name: Install Neko from S3
1 run: |
2 set -ex
3
4 curl -sSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o $RUNNER_TEMP/neko_latest.tar.gz
5 tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
6 NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
7 sudo mkdir -p /usr/local/bin
8 sudo mkdir -p /usr/local/lib/neko
9 sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools} /usr/local/bin/
10 sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
11 sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
12 echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
13
14 - name: Print Neko version
15 run: neko -version 2>&1
0 - name: Install Neko from S3
1 shell: pwsh
2 run: |
3 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
4 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
5 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
6 echo "$NEKOPATH" >> $env:GITHUB_PATH
7 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
8
9 - name: Print Neko version
10 run: neko -version 2>&1
+0
-27
extra/github-actions/install-neko.yml less more
0 - name: Install Neko using snapshot from S3 (Unix)
1 if: ${{ !startsWith(env.PLATFORM, 'windows') }}
2 run: |
3 set -ex
4
5 curl -sSL https://build.haxe.org/builds/neko/$PLATFORM/neko_latest.tar.gz -o $RUNNER_TEMP/neko_latest.tar.gz
6 tar -xf $RUNNER_TEMP/neko_latest.tar.gz -C $RUNNER_TEMP
7 NEKOPATH=`echo $RUNNER_TEMP/neko-*-*`
8 sudo mkdir -p /usr/local/bin
9 sudo mkdir -p /usr/local/lib/neko
10 sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools} /usr/local/bin/
11 sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
12 sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
13 echo "NEKOPATH=$NEKOPATH" >> $GITHUB_ENV
14
15 - name: Install Neko using snapshot from S3 (Windows)
16 if: ${{ startsWith(env.PLATFORM, 'windows') }}
17 shell: pwsh
18 run: |
19 Invoke-WebRequest https://build.haxe.org/builds/neko/$env:PLATFORM/neko_latest.zip -OutFile $env:RUNNER_TEMP/neko_latest.zip
20 Expand-Archive $env:RUNNER_TEMP/neko_latest.zip -DestinationPath $env:RUNNER_TEMP
21 $NEKOPATH = Get-ChildItem $env:RUNNER_TEMP/neko-*-*
22 echo "$NEKOPATH" >> $env:GITHUB_PATH
23 echo "NEKOPATH=$NEKOPATH" >> $env:GITHUB_ENV
24
25 - name: Print Neko version
26 run: neko -version 2>&1
0 - name: choco install nsis
1 uses: nick-invision/retry@v1
2 with:
3 timeout_minutes: 10
4 max_attempts: 10
5 command: choco install --no-progress nsis.portable --version 3.02 -y
6 - name: choco install things
7 shell: pwsh
8 run: choco install --no-progress curl wget 7zip.portable -y
9 - name: Prepend Chocolatey path
10 shell: pwsh
11 run: Write-Host "::add-path::C:\ProgramData\chocolatey\bin"
0 - name: Install OCaml libraries
1 if: steps.cache-opam.outputs.cache-hit != 'true'
2 shell: pwsh
3 run: |
4 Set-PSDebug -Trace 1
5 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam init mingw "https://github.com/fdopen/opam-repository-mingw.git#opam2" --comp 4.07.0+mingw${ARCH}c --switch 4.07.0+mingw${ARCH}c --auto-setup --yes 2>&1')
6 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam update --yes 2>&1')
7 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam pin add haxe . --kind=path --no-action --yes 2>&1')
8 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam install haxe --deps-only --yes 2>&1')
9 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'opam list')
10 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'ocamlopt -v')
0 - name: Install OCaml
1 shell: pwsh
2 run: |
3 Set-PSDebug -Trace 1
4 curl.exe -fsSL -o cygwin-setup.exe --retry 3 $($env:CYGWIN_SETUP)
5 Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $($env:CYG_ROOT) -l C:/tmp -s $($env:CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre2-devel -P mbedtls-devel -P mingw64-$($env:MINGW_ARCH)-zlib -P mingw64-$($env:MINGW_ARCH)-gcc-core -P mingw64-$($env:MINGW_ARCH)-pcre2 --allow-unsupported-windows" -Wait -RedirectStandardOutput cygwin-setup-out.txt
6 Get-Content cygwin-setup-out.txt
7 & "$($env:CYG_ROOT)/bin/bash.exe" @('--norc', '--noprofile', '/etc/postinstall/ca-certificates.sh')
8 curl.exe -fsSL -o "opam.tar.xz" --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.2/opam$($env:ARCH).tar.xz
9 curl.exe -fsSL -o "libmbedtls.tar.xz" --retry 3 https://github.com/Simn/mingw64-mbedtls/releases/download/2.16.3/mingw64-$($env:MINGW_ARCH)-mbedtls-2.16.3-1.tar.xz
10 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'curl -L https://cpanmin.us | perl - App::cpanminus')
11 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm IPC::System::Simple module')
12 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm String::ShellQuote')
13 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'echo "$OLDPWD"')
14 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -C / -xvf libmbedtls.tar.xz')
15 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -xf opam.tar.xz')
16 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && bash opam${ARCH}/install.sh')
0 - name: Install OCaml
1 shell: pwsh
2 run: |
3 Set-PSDebug -Trace 1
4 curl.exe -fsSL -o cygwin-setup.exe --retry 3 $($env:CYGWIN_SETUP)
5 Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $($env:CYG_ROOT) -l C:/tmp -s $($env:CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre2-devel -P mbedtls-devel -P mingw64-$($env:MINGW_ARCH)-zlib -P mingw64-$($env:MINGW_ARCH)-gcc-core -P mingw64-$($env:MINGW_ARCH)-pcre2" -Wait -RedirectStandardOutput cygwin-setup-out.txt
6 Get-Content cygwin-setup-out.txt
7 curl.exe -fsSL -o "opam.tar.xz" --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.2/opam$($env:ARCH).tar.xz
8 curl.exe -fsSL -o "libmbedtls.tar.xz" --retry 3 https://github.com/Simn/mingw64-mbedtls/releases/download/2.16.3/mingw64-$($env:MINGW_ARCH)-mbedtls-2.16.3-1.tar.xz
9 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'curl -L https://cpanmin.us | perl - App::cpanminus')
10 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm IPC::System::Simple module')
11 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cpanm String::ShellQuote')
12 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'echo "$OLDPWD"')
13 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -C / -xvf libmbedtls.tar.xz')
14 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -xf opam.tar.xz')
15 & "$($env:CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && bash opam${ARCH}/install.sh')
+0
-46
extra/github-actions/test-linux.yml less more
0 - name: Setup Haxe
1 run: |
2 # mkdir ./linuxBinaries
3 # curl -sSL https://build.haxe.org/builds/haxe/linux64/haxe_latest.tar.gz -o ./linuxBinaries/haxe_bin.tar.gz
4
5 sudo apt install -qqy libmbedtls-dev
6
7 set -ex
8 tar -xf linuxBinaries/*_bin.tar.gz -C linuxBinaries --strip-components=1
9 sudo mkdir -p /usr/local/bin/
10 sudo mkdir -p /usr/local/share/haxe/
11 sudo ln -s `pwd`/linuxBinaries/haxe /usr/local/bin/haxe
12 sudo ln -s `pwd`/linuxBinaries/haxelib /usr/local/bin/haxelib
13 sudo ln -s `pwd`/linuxBinaries/std /usr/local/share/haxe/std
14
15 - name: Print Haxe version
16 run: haxe -version
17
18 - name: Setup haxelib
19 run: |
20 set -ex
21 mkdir ~/haxelib
22 haxelib setup ~/haxelib
23
24 - name: Install apt packages
25 if: matrix.APT_PACKAGES
26 run: |
27 set -ex
28 sudo apt update -qqy
29 sudo apt install -qqy ${{matrix.APT_PACKAGES}}
30
31 # - name: Flash setup
32 # if: matrix.target == 'flash9'
33 # run: export DISPLAY=:99.0
34
35 - name: Test
36 if: success() && !(matrix.SAUCE && matrix.SAUCE_ACCESS_KEY)
37 run: haxe RunCi.hxml
38 working-directory: ${{github.workspace}}/tests
39
40 - name: Test (with SauceLabs)
41 if: matrix.target == 'js' && success() && matrix.SAUCE && matrix.SAUCE_ACCESS_KEY
42 run: haxe RunCi.hxml
43 working-directory: ${{github.workspace}}/tests
44 env:
45 SAUCE_ACCESS_KEY: matrix.SAUCE_ACCESS_KEY
3535 hererocks lua53 -l5.3 -rlatest
3636 call lua53/bin/activate
3737
38 - name: Install wget
39 if: matrix.target == 'flash'
40 shell: cmd
41 run: |
42 choco install wget
43 wget --version
44
3845 - name: Setup haxelib
3946 shell: pwsh
4047 run: |
33 on: [push, pull_request]
44
55 jobs:
6 cancel:
7 name: "Cancel previous runs"
8 runs-on: ubuntu-18.04
9 timeout-minutes: 3
10 steps:
11 - uses: styfle/cancel-workflow-action@0.3.1
12 with:
13 workflow_id: 1447568
14 access_token: ${{ github.token }}
15
166 windows64-build:
177 runs-on: windows-latest
188 env:
199 ACTIONS_ALLOW_UNSECURE_COMMANDS: true
2010 PLATFORM: windows64
2111 OPAMYES: 1
12 OPAMROOT: D:\.opam
2213 CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin/
2314 ARCH: 64
2415 MINGW_ARCH: x86_64
2920 with:
3021 submodules: recursive
3122
32 @import install-neko.yml
23 - name: Use GNU Tar from msys
24 run: |
25 echo "C:\msys64\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
26 rm C:\msys64\usr\bin\bash.exe
27
28 - name: Cache opam
29 id: cache-opam
30 uses: actions/cache@v3.0.11
31 with:
32 path: D:\.opam
33 key: ${{ runner.os }}64-${{ hashFiles('./opam', './libs/') }}
34
35 @import install-neko-windows.yml
36 @import install-nsis.yml
37 @import install-ocaml-windows64.yml
38 @import install-ocaml-libs-windows.yml
3339 @import build-windows.yml
3440
3541 windows-build:
3844 ACTIONS_ALLOW_UNSECURE_COMMANDS: true
3945 PLATFORM: windows
4046 OPAMYES: 1
41 CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin/
47 OPAMROOT: D:\.opam
48 CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin-archive/20221123
4249 ARCH: 32
4350 MINGW_ARCH: i686
4451 CYGWIN_SETUP: https://cygwin.com/setup-x86.exe
4855 with:
4956 submodules: recursive
5057
51 @import install-neko.yml
58 - name: Use GNU Tar from msys
59 run: |
60 echo "C:\msys64\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
61 rm C:\msys64\usr\bin\bash.exe
62
63 - name: Cache opam
64 id: cache-opam
65 uses: actions/cache@v3.0.11
66 with:
67 path: D:\.opam
68 key: ${{ runner.os }}32-${{ hashFiles('./opam', './libs/') }}
69
70 @import install-neko-windows.yml
71 @import install-nsis.yml
72 @import install-ocaml-windows.yml
73 @import install-ocaml-libs-windows.yml
5274 @import build-windows.yml
5375
5476 linux-build:
55 runs-on: ubuntu-18.04
77 runs-on: ubuntu-20.04
5678 env:
5779 PLATFORM: linux64
5880 OPAMYES: 1
6183 with:
6284 submodules: recursive
6385
64 @import install-neko.yml
65 @import build-linux.yml
86 @import cache-opam.yml
87 @import install-neko-unix.yml
88
89 - name: Install dependencies
90 run: |
91 set -ex
92 sudo add-apt-repository ppa:avsm/ppa -y # provides OPAM 2
93 sudo add-apt-repository ppa:haxe/ocaml -y # provides newer version of mbedtls
94 sudo apt-get update -qqy
95 sudo apt-get install -qqy ocaml-nox camlp5 opam libpcre2-dev zlib1g-dev libgtk2.0-dev libmbedtls-dev ninja-build libstring-shellquote-perl libipc-system-simple-perl
96
97 - name: Install OCaml libraries
98 if: steps.cache-opam.outputs.cache-hit != 'true'
99 run: |
100 set -ex
101 opam init # --disable-sandboxing
102 opam update
103 opam pin add haxe . --no-action
104 opam install haxe --deps-only --assume-depexts
105 opam list
106 ocamlopt -v
107
108 - name: Set ADD_REVISION=1 for non-release
109 if: ${{ !startsWith(github.ref, 'refs/tags/') }}
110 run: echo "ADD_REVISION=1" >> $GITHUB_ENV
111
112 - name: Build Haxe
113 run: |
114 set -ex
115 eval $(opam env)
116 opam config exec -- make -s -j`nproc` STATICLINK=1 haxe
117 opam config exec -- make -s haxelib
118 make -s package_unix
119 ls -l out
120 ldd -v ./haxe
121 ldd -v ./haxelib
122
123 # https://stackoverflow.com/questions/58033366/how-to-get-current-branch-within-github-actions
124 - name: Extract branch name
125 id: extract_branch
126 shell: bash
127 run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
128
129 - name: Build xmldoc
130 run: |
131 set -ex
132 make -s xmldoc
133 cat >extra/doc/info.json <<EOL
134 {
135 "commit": "$GITHUB_SHA",
136 "branch": "${{ steps.extract_branch.outputs.branch }}"
137 }
138 EOL
139
140 - name: Upload artifact
141 uses: actions/upload-artifact@v1.0.0
142 with:
143 name: linuxBinaries
144 path: out
145
146 - name: Upload xmldoc artifact
147 uses: actions/upload-artifact@v1.0.0
148 with:
149 name: xmldoc
150 path: extra/doc
151
152 linux-test:
153 needs: linux-build
154 runs-on: ubuntu-20.04
155 env:
156 PLATFORM: linux64
157 TEST: ${{matrix.target}}
158 HXCPP_COMPILE_CACHE: ~/hxcache
159 HAXE_STD_PATH: /usr/local/share/haxe/std
160 strategy:
161 fail-fast: false
162 matrix:
163 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, lua, flash, neko]
164 include:
165 - target: hl
166 APT_PACKAGES: cmake ninja-build libturbojpeg-dev
167 - target: cpp
168 APT_PACKAGES: gcc-multilib g++-multilib
169 - target: lua
170 APT_PACKAGES: ncurses-dev
171 - target: flash
172 APT_PACKAGES: libglib2.0-0 libgtk2.0-0 libfreetype6 xvfb
173 steps:
174 - uses: actions/checkout@main
175 with:
176 submodules: recursive
177 - uses: actions/download-artifact@v1
178 with:
179 name: linuxBinaries
180
181 @import install-neko-unix.yml
182
183 - name: Setup Haxe
184 run: |
185 sudo apt install -qqy libmbedtls-dev
186
187 set -ex
188 tar -xf linuxBinaries/*_bin.tar.gz -C linuxBinaries --strip-components=1
189 sudo mkdir -p /usr/local/bin/
190 sudo mkdir -p /usr/local/share/haxe/
191 sudo ln -s `pwd`/linuxBinaries/haxe /usr/local/bin/haxe
192 sudo ln -s `pwd`/linuxBinaries/haxelib /usr/local/bin/haxelib
193 sudo ln -s `pwd`/linuxBinaries/std /usr/local/share/haxe/std
194
195 - name: Print Haxe version
196 run: haxe -version
197
198 - name: Setup haxelib
199 run: |
200 set -ex
201 mkdir ~/haxelib
202 haxelib setup ~/haxelib
203
204 - name: Install apt packages
205 if: matrix.APT_PACKAGES
206 run: |
207 set -ex
208 sudo apt update -qqy
209 sudo apt install -qqy ${{matrix.APT_PACKAGES}}
210
211 - name: Flash setup
212 if: matrix.target == 'flash'
213 run: export DISPLAY=:99.0
214
215 - name: Test
216 run: haxe RunCi.hxml
217 working-directory: ${{github.workspace}}/tests
218
219 test-docgen:
220 needs: linux-build
221 runs-on: ubuntu-20.04
222 env:
223 PLATFORM: linux64
224 HXCPP_COMPILE_CACHE: ~/hxcache
225 steps:
226 - uses: actions/checkout@main
227 with:
228 submodules: recursive
229
230 - uses: actions/download-artifact@v1
231 with:
232 name: linuxBinaries
233
234 - name: Download xmldoc artifact
235 uses: actions/download-artifact@v2
236 with:
237 name: xmldoc
238 path: xmldoc
239
240 @import install-neko-unix.yml
241
242 - name: Setup Haxe
243 run: |
244 sudo apt install -qqy libmbedtls-dev
245
246 set -ex
247 tar -xf linuxBinaries/*_bin.tar.gz -C linuxBinaries --strip-components=1
248 sudo mkdir -p /usr/local/bin/
249 sudo mkdir -p /usr/local/share/haxe/
250 sudo ln -s `pwd`/linuxBinaries/haxe /usr/local/bin/haxe
251 sudo ln -s `pwd`/linuxBinaries/haxelib /usr/local/bin/haxelib
252 sudo ln -s `pwd`/linuxBinaries/std /usr/local/share/haxe/std
253
254 - name: Print Haxe version
255 run: haxe -version
256
257 - name: Setup haxelib
258 run: |
259 set -ex
260 mkdir ~/haxelib
261 haxelib setup ~/haxelib
262
263 - name: Test documentation generation
264 run: |
265 set -ex
266 haxelib git dox https://github.com/HaxeFoundation/dox.git
267 haxelib git hxtemplo https://github.com/Simn/hxtemplo.git
268 haxelib git hxargs https://github.com/Simn/hxargs.git
269 haxelib git markdown https://github.com/dpeek/haxe-markdown.git
270 haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp.git
271 cd $(haxelib libpath hxcpp)/tools/hxcpp
272 haxe compile.hxml
273 cd -
274 haxe dox.hxml
275 mkdir resources
276 cp ../../src-json/* resources
277 cpp/Dox -i ../../xmldoc -ex microsoft -ex javax -ex cs.internal -theme $(haxelib libpath dox)/themes/default
278 working-directory: ${{github.workspace}}/tests/docgen
279
280 linux-arm64:
281 runs-on: ubuntu-20.04
282 permissions:
283 packages: write
284 env:
285 FORCE_COLOR: 1
286 steps:
287 - name: Login to GitHub Container Registry
288 uses: docker/login-action@v1
289 with:
290 registry: ghcr.io
291 username: ${{ github.actor }}
292 password: ${{ secrets.GITHUB_TOKEN }}
293
294 - name: Install Earthly
295 run: sudo /bin/sh -c 'wget https://github.com/earthly/earthly/releases/download/v0.6.13/earthly-linux-amd64 -O /usr/local/bin/earthly && chmod +x /usr/local/bin/earthly && /usr/local/bin/earthly bootstrap --with-autocomplete'
296
297 - name: Set up QEMU
298 id: qemu
299 uses: docker/setup-qemu-action@v1
300 with:
301 image: tonistiigi/binfmt:latest
302 platforms: all
303
304 - uses: actions/checkout@main
305 with:
306 submodules: recursive
307
308 - name: Set CONTAINER_ vars
309 run: |
310 echo "CONTAINER_REG=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV;
311 echo "CONTAINER_TAG=$(echo ${{ github.ref_name }} | sed -e 's/[^A-Za-z0-9\.]/-/g')" >> $GITHUB_ENV;
312
313 - name: Build devcontainer
314 run: earthly --platform=linux/arm64 +devcontainer --IMAGE_NAME="ghcr.io/${CONTAINER_REG}_devcontainer" --IMAGE_TAG="${CONTAINER_TAG}-arm64" --IMAGE_CACHE="ghcr.io/haxefoundation/haxe_devcontainer:development-arm64"
315 env:
316 EARTHLY_PUSH: "${{ github.event_name == 'push' }}"
317 EARTHLY_USE_INLINE_CACHE: true
318 EARTHLY_SAVE_INLINE_CACHE: true
319
320 - name: Set ADD_REVISION=1 for non-release
321 if: ${{ !startsWith(github.ref, 'refs/tags/') }}
322 run: echo "ADD_REVISION=1" >> $GITHUB_ENV
323
324 - name: Build
325 run: earthly --platform=linux/arm64 +build --ADD_REVISION="$ADD_REVISION" --SET_SAFE_DIRECTORY="true"
326 env:
327 EARTHLY_PUSH: "${{ github.event_name == 'push' }}"
328 EARTHLY_REMOTE_CACHE: "ghcr.io/${{env.CONTAINER_REG}}_cache:build-${{env.CONTAINER_TAG}}-arm64"
329
330 - name: Upload artifact
331 uses: actions/upload-artifact@v1.0.0
332 with:
333 name: linuxArm64Binaries
334 path: out/linux/arm64
66335
67336 mac-build:
68337 runs-on: macos-latest
75344 with:
76345 submodules: recursive
77346
78 @import install-neko.yml
347 @import cache-opam.yml
348 @import install-neko-unix.yml
79349 @import build-mac.yml
80350
81351 windows64-test:
90360 strategy:
91361 fail-fast: false
92362 matrix:
93 # TODO enable lua after https://github.com/HaxeFoundation/haxe/issues/5024
94 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, neko]
363 # TODO enable lua after https://github.com/HaxeFoundation/haxe/issues/10919
364 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, flash, neko]
95365 steps:
96366 - uses: actions/checkout@main
97367 with:
100370 with:
101371 name: win${{env.ARCH}}Binaries
102372
103 @import install-neko.yml
373 @import install-neko-windows.yml
104374 @import test-windows.yml
105375
106376 windows-test:
116386 fail-fast: false
117387 matrix:
118388 # TODO jvm: https://github.com/HaxeFoundation/haxe/issues/8601
119 # TODO enable lua after https://github.com/HaxeFoundation/haxe/issues/5024
120 target: [macro, js, hl, cpp, java, cs, php, python, neko]
389 # TODO enable lua after https://github.com/HaxeFoundation/haxe/issues/10919
390 target: [macro, js, hl, cpp, java, cs, php, python, flash, neko]
121391 steps:
122392 - uses: actions/checkout@main
123393 with:
126396 with:
127397 name: win${{env.ARCH}}Binaries
128398
129 @import install-neko.yml
399 @import install-neko-windows.yml
130400 @import test-windows.yml
131401
132 linux-test:
133 needs: linux-build
134 runs-on: ubuntu-18.04
135 env:
136 PLATFORM: linux64
402 mac-test:
403 needs: mac-build
404 runs-on: macos-latest
405 env:
406 PLATFORM: mac
137407 TEST: ${{matrix.target}}
138408 HXCPP_COMPILE_CACHE: ~/hxcache
409 HAXE_STD_PATH: /usr/local/share/haxe/std
139410 strategy:
140411 fail-fast: false
141412 matrix:
142 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, lua, neko] #flash9
143 include:
144 - target: js
145 # SAUCE: 1
146 # SAUCE_TUNNEL_ID: 'linux-test'
147 # SAUCE_BUILD: '${{env.GITHUB_RUN_NUMBER}}' # $(Build.BuildNumber)
148 - target: hl
149 APT_PACKAGES: cmake ninja-build libturbojpeg-dev
150 - target: cpp
151 APT_PACKAGES: gcc-multilib g++-multilib
152 - target: lua
153 APT_PACKAGES: ncurses-dev
154 # - target: flash9
155 # APT_PACKAGES: libglib2.0-0 libfreetype6 xvfb
156 steps:
157 - uses: actions/checkout@main
158 with:
159 submodules: recursive
160 - uses: actions/download-artifact@v1
161 with:
162 name: linuxBinaries
163
164 @import install-neko.yml
165 @import test-linux.yml
166
167 mac-test:
168 needs: mac-build
169 runs-on: macos-latest
170 env:
171 PLATFORM: mac
172 TEST: ${{matrix.target}}
173 HXCPP_COMPILE_CACHE: ~/hxcache
174 strategy:
175 fail-fast: false
176 matrix:
177 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, lua, neko] #flash9
413 target: [macro, js, hl, cpp, 'java,jvm', cs, php, python, flash, neko]
178414 include:
179415 - target: hl
180416 BREW_PACKAGES: ninja
186422 with:
187423 name: macBinaries
188424
189 @import install-neko.yml
425 @import install-neko-unix.yml
190426 @import test-mac.yml
191427
192428 deploy:
193 if: github.event_name != 'pull_request'
194 needs: [linux-test, mac-test, windows-test, windows64-test]
195 runs-on: ubuntu-18.04
429 if: success() && github.repository_owner == 'HaxeFoundation' && github.event_name != 'pull_request'
430 needs: [linux-test, linux-arm64, mac-test, windows-test, windows64-test]
431 runs-on: ubuntu-20.04
196432 steps:
197433 # this is only needed for to get `COMMIT_DATE`...
198434 # maybe https://github.community/t/expose-commit-timestamp-in-the-github-context-data/16460/3
221457 AWS_ACCESS_KEY_ID: ${{ secrets.HXBUILDS_AWS_ACCESS_KEY_ID }}
222458 AWS_SECRET_ACCESS_KEY: ${{ secrets.HXBUILDS_AWS_SECRET_ACCESS_KEY }}
223459 HXBUILDS_S3ADDR: ${{ secrets.HXBUILDS_S3ADDR }}
460 AWS_EC2_METADATA_DISABLED: true
224461 run: |
225462 set -ex
226463 COMMIT_HASH_SHORT=${GITHUB_SHA:0:7}
227464 COMMIT_DATE=`TZ=UTC git show --quiet --date='format-local:%Y-%m-%d' --format="%cd"`
228465 FILE_NAME=haxe_${COMMIT_DATE}_${{ steps.extract_branch.outputs.branch }}_${COMMIT_HASH_SHORT}
229466 aws s3 cp linuxBinaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/linux64/${FILE_NAME}.tar.gz
467 aws s3 cp linuxArm64Binaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/linux-arm64/${FILE_NAME}.tar.gz
230468 aws s3 cp macBinaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/mac/${FILE_NAME}.tar.gz
231469 aws s3 cp macBinaries/*_installer.tar.gz ${HXBUILDS_S3ADDR}/haxe/mac-installer/${FILE_NAME}.tar.gz
232470 aws s3 cp win64Binaries/*_bin.zip ${HXBUILDS_S3ADDR}/haxe/windows64/${FILE_NAME}.zip
243481 AWS_ACCESS_KEY_ID: ${{ secrets.HXBUILDS_AWS_ACCESS_KEY_ID }}
244482 AWS_SECRET_ACCESS_KEY: ${{ secrets.HXBUILDS_AWS_SECRET_ACCESS_KEY }}
245483 HXBUILDS_S3ADDR: ${{ secrets.HXBUILDS_S3ADDR }}
484 AWS_EC2_METADATA_DISABLED: true
246485 run: |
247486 set -ex
248487 aws s3 cp linuxBinaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/linux64/haxe_latest.tar.gz
488 aws s3 cp linuxArm64Binaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/linux-arm64/haxe_latest.tar.gz
249489 aws s3 cp macBinaries/*_bin.tar.gz ${HXBUILDS_S3ADDR}/haxe/mac/haxe_latest.tar.gz
250490 aws s3 cp macBinaries/*_installer.tar.gz ${HXBUILDS_S3ADDR}/haxe/mac-installer/haxe_latest.tar.gz
251491 aws s3 cp win64Binaries/*_bin.zip ${HXBUILDS_S3ADDR}/haxe/windows64/haxe_latest.zip
262502 aws s3 cp ${HXBUILDS_S3ADDR}/haxe/windows-choco/${FILE_NAME} ${HXBUILDS_S3ADDR}/haxe/windows-choco/haxe_latest.nupkg --acl public-read --website-redirect "${HXBUILDS_S3PATH}/haxe/windows-choco/${FILE_NAME}"
263503
264504 deploy_apidoc:
265 if: github.event_name != 'pull_request' # TODO: also only when `GHP_REMOTE` is present
266 needs: [linux-test, mac-test, windows-test, windows64-test]
267 runs-on: ubuntu-18.04
268 steps:
505 if: success() && github.repository_owner == 'HaxeFoundation' && github.event_name != 'pull_request'
506 needs: [linux-test, linux-arm64, mac-test, windows-test, windows64-test]
507 runs-on: ubuntu-20.04
508 steps:
509 - name: Install dependencies
510 run: |
511 set -ex
512 sudo apt-get install -qqy libc6
513
269514 - name: Download Haxe
270515 uses: actions/download-artifact@v2
271516 with:
0 ## 4.1.0 (2023-04-06)
1
2 - Added support for documenting custom defines and metadata ([#573](https://github.com/HaxeFoundation/haxelib/pull/573))
3 - Fixed a segmentation fault on Linux systems
4
5 ## 4.0.3 (2023-02-27)
6 - Fixed large git installations hanging on windows ([#585](https://github.com/HaxeFoundation/haxelib/pull/585))
7 - Corrected license in haxelib.json ([#535](https://github.com/HaxeFoundation/haxelib/pull/535))
8
09 ## 4.0.2 (2019-11-11)
110 - Fixed too strict requirements to haxelib.json data for private libs ([#484](https://github.com/HaxeFoundation/haxelib/issues/484))
211
00 {
11 "name": "haxelib",
22 "url" : "https://lib.haxe.org/documentation/",
3 "license": "GPL",
3 "license": "MIT",
44 "tags": ["haxelib", "core"],
55 "description": "The haxelib client",
66 "classPath": "src",
7 "version": "4.0.2",
8 "releasenote": " * Fixed too strict requirements to haxelib.json data for private libs (#484)",
7 "version": "4.1.0",
8 "releasenote": "Added support for documenting custom defines and metadata (#573)",
99 "contributors": ["HaxeFoundation", "back2dos", "ncannasse", "jason", "Simn", "nadako", "andyli"]
1010 }
Binary diff not shown
4343 "description": "Project's dependencies",
4444 "patternProperties": {
4545 "^[A-Za-z0-9_.-]{3,}$": { "$ref": "#/definitions/dependencyVersion" }
46 },
47 "additionalProperties": false
48 },
49 "documentation": {
50 "type": "object",
51 "description": "Project's documentation resources",
52 "properties": {
53 "defines": {
54 "type": "string",
55 "description": "Relative path to json file describing this project's custom defines"
56 },
57 "metadata": {
58 "type": "string",
59 "description": "Relative path to json file describing this project's custom metadata"
60 }
4661 },
4762 "additionalProperties": false
4863 },
170170 var contributors : Array<String>;
171171 @:optional var tags : Array<String>;
172172 @:optional var dependencies : Dependencies;
173 @:optional var main:String;
173 @:optional var main : String;
174 @:optional var documentation : LibraryDocumentation;
175 }
176
177 /** Documentation data held in the `documentation` field of the `haxelib.json` file. **/
178 typedef LibraryDocumentation = {
179 @:optional var defines : String;
180 @:optional var metadata : String;
181 }
182
183 /** Metadata documentation data as should be declared in the json linked in the
184 * `documentation.metadata` field of the `haxelib.json` file. **/
185 typedef MetadataDocumentation = {
186 var metadata : String;
187 var doc : String;
188 @:optional var platforms : Array<String>;
189 @:optional var params : Array<String>;
190 @:optional var targets : Array<String>;
191 @:optional var links : Array<String>;
192 }
193
194 /** Define documentation data as should be declared in the json linked in the
195 * `documentation.defines` field of the `haxelib.json` file. **/
196 typedef DefineDocumentation = {
197 var define : String;
198 var doc : String;
199 @:optional var platforms : Array<String>;
200 @:optional var params : Array<String>;
201 @:optional var links : Array<String>;
174202 }
175203
176204 @:enum abstract License(String) to String {
327355 }
328356 throw 'Class path `${infos.classPath}` not found';
329357 }
358 }
359
360 /** Throws an exception if files referenced in `documentation` field of an `infos` do not exist or are invalid **/
361 public static function checkDocumentation( zip : List<Entry>, infos : Infos ) {
362 if (infos.documentation == null) return;
363
364 var hasDefines = infos.documentation.defines != null;
365 var hasMetadata = infos.documentation.metadata != null;
366 if (!hasDefines && !hasMetadata) return;
367
368 var basePath = Data.locateBasePath(zip);
369 var definesPath = hasDefines ? basePath + infos.documentation.defines : null;
370 var metadataPath = hasMetadata ? basePath + infos.documentation.metadata : null;
371 var definesFound = false;
372 var metadataFound = false;
373
374 for (f in zip) {
375 if (hasDefines && StringTools.startsWith(f.fileName, definesPath)) {
376 definesFound = true;
377 try {
378 var jsondata = Reader.unzip(f).toString();
379 var defines:Array<DefineDocumentation> = Json.parse(jsondata);
380 Validator.validate(defines);
381 } catch (_:Dynamic) {
382 throw 'Defines documentation json file does not match expected format';
383 }
384 } else if (hasMetadata && StringTools.startsWith(f.fileName, metadataPath)) {
385 metadataFound = true;
386 try {
387 var jsondata = Reader.unzip(f).toString();
388 var metas:Array<MetadataDocumentation> = Json.parse(jsondata);
389 Validator.validate(metas);
390 } catch (_:Dynamic) {
391 throw 'Metadata documentation json file does not match expected format';
392 }
393 }
394
395 if ((!hasDefines || definesFound) && (!hasMetadata || metadataFound)) break;
396 }
397
398 if (hasDefines && !definesFound) throw 'Json file `${infos.documentation.defines}` not found';
399 if (hasMetadata && !metadataFound) throw 'Json file `${infos.documentation.metadata}` not found';
330400 }
331401
332402 public static function readData( jsondata: String, check : CheckLevel ) : Infos {
633633
634634 var infos = Data.readInfos(zip,true);
635635 Data.checkClassPath(zip, infos);
636 Data.checkDocumentation(zip, infos);
636637
637638 var user:String = infos.contributors[0];
638639
15011502 Sys.println(dir);
15021503
15031504 Sys.println("-D " + d.project + "="+d.info.version);
1505
1506 if (d.info.documentation != null) {
1507 var doc = d.info.documentation;
1508
1509 // we'll have to change this to "4.3.0" after the release
1510 if (haxeVersion() >= SemVer.ofString("4.3.0-rc.1")) {
1511 // custom defines if defined
1512 if (doc.defines != null && doc.defines != "") {
1513 var path = Path.join([d.dir, doc.defines]);
1514 Sys.println('--macro registerDefinesDescriptionFile(\'$path\', \'${d.info.name}\')');
1515 }
1516
1517 // custom metadatas if defined
1518 if (doc.metadata != null && doc.metadata != "") {
1519 var path = Path.join([d.dir, doc.metadata]);
1520 Sys.println('--macro registerMetadataDescriptionFile(\'$path\', \'${d.info.name}\')');
1521 }
1522 }
1523 }
15041524 }
15051525 }
15061526
2121 package haxelib.client;
2222
2323 import sys.FileSystem;
24 #if haxe4
25 import sys.thread.Thread;
26 import sys.thread.Lock;
27 #else
28 import neko.vm.Thread;
29 import neko.vm.Lock;
30 #end
2431 using haxelib.client.Vcs;
2532
2633 interface IVcs {
150157 code: -1,
151158 out: Std.string(e)
152159 }
153 }
154 var out = p.stdout.readAll().toString();
155 var err = p.stderr.readAll().toString();
156 if (settings.debug && out != "")
157 Sys.println(out);
158 if (settings.debug && err != "")
159 Sys.stderr().writeString(err);
160 var code = p.exitCode();
161 var ret = {
162 code: code,
163 out: code == 0 ? out : err
164 };
160 };
161 var ret = if (Sys.systemName() == "Windows") {
162 var streamsLock = new sys.thread.Lock();
163 function readFrom(stream:haxe.io.Input, to: {value: String}) {
164 to.value = stream.readAll().toString();
165 streamsLock.release();
166 }
167
168 var out = {value: ""};
169 var err = {value: ""};
170 Thread.create(readFrom.bind(p.stdout, out));
171 Thread.create(readFrom.bind(p.stderr, err));
172
173 var code = p.exitCode();
174 for (_ in 0...2) {
175 // wait until we finish reading from both streams
176 streamsLock.wait();
177 }
178
179 if (settings.debug && out.value != "")
180 Sys.println(out.value);
181 if (settings.debug && err.value != "")
182 Sys.stderr().writeString(err.value);
183
184 {
185 code: code,
186 out: code == 0 ? out.value : err.value
187 };
188 } else {
189 var out = p.stdout.readAll().toString();
190 var err = p.stderr.readAll().toString();
191 if (settings.debug && out != "")
192 Sys.println(out);
193 if (settings.debug && err != "")
194 Sys.stderr().writeString(err);
195 var code = p.exitCode();
196 {
197 code: code,
198 out: code == 0 ? out : err
199 };
200 };
165201 p.close();
166202 return ret;
167203 }
0 {
1 "name": "BadDefineJson",
2 "url" : "http://example.org",
3 "license": "GPL",
4 "tags": ["bar", "test"],
5 "description": "This project is an example of an haxelib project",
6 "version": "1.0.0",
7 "releasenote": "Initial release, everything is working correctly",
8 "documentation": {
9 "defines": "doc/defines.json"
10 },
11 "contributors": ["Bar"]
12 }
0 {
1 "name": "BadMetaJson",
2 "url" : "http://example.org",
3 "license": "GPL",
4 "tags": ["bar", "test"],
5 "description": "This project is an example of an haxelib project",
6 "version": "1.0.0",
7 "releasenote": "Initial release, everything is working correctly",
8 "documentation": {
9 "metadata": "doc/meta.json"
10 },
11 "contributors": ["Bar"]
12 }
0 {
1 "name": "BadMetaJson2",
2 "url" : "http://example.org",
3 "license": "GPL",
4 "tags": ["bar", "test"],
5 "description": "This project is an example of an haxelib project",
6 "version": "1.0.0",
7 "releasenote": "Initial release, everything is working correctly",
8 "documentation": {
9 "metadata": "doc/meta.json"
10 },
11 "contributors": ["Bar"]
12 }
0 [
1 {
2 "define": "test",
3 "doc": "Test define"
4 },
5 {
6 "define": "test2",
7 "doc": "Test define 2",
8 "platforms": ["eval"],
9 "params": ["foo"],
10 "links": ["https://example.com"]
11 }
12 ]
0 [
1 {
2 "metadata": ":test",
3 "doc": "Some test metadata"
4 },
5 {
6 "metadata": ":test2",
7 "doc": "Some other test metadata",
8 "platforms": ["eval"],
9 "params": ["foo"],
10 "links": ["https://example.com"],
11 "targets": ["TClass", "TClassField"]
12 }
13 ]
0 {
1 "name": "DocumentationFiles",
2 "url" : "http://example.org",
3 "license": "GPL",
4 "tags": ["bar", "test"],
5 "description": "This project is an example of an haxelib project",
6 "version": "1.0.0",
7 "releasenote": "Initial release, everything is working correctly",
8 "documentation": {
9 "metadata": "doc/meta.json",
10 "defines": "doc/defines.json"
11 },
12 "contributors": ["Bar"]
13 }
0 {
1 "name": "MissingMetaJson",
2 "url" : "http://example.org",
3 "license": "GPL",
4 "tags": ["bar", "test"],
5 "description": "This project is an example of an haxelib project",
6 "version": "1.0.0",
7 "releasenote": "Initial release, everything is working correctly",
8 "documentation": {
9 "metadata": "doc/meta.json"
10 },
11 "contributors": ["Bar"]
12 }
100100 e;
101101 }
102102 assertEquals( ok, true );
103 }
104
105 public function testCheckDocumentation() {
106 var results = [
107 "DocumentationFiles" => true,
108 "BadMetaJson" => false,
109 "BadMetaJson2" => false,
110 "BadDefineJson" => false
111 ];
112
113 for (r in results.keys()) {
114 var zip = Reader.readZip(new BytesInput(File.getBytes('test/libraries/lib$r.zip')));
115 var info = Data.readInfos(zip, CheckData);
116
117 try {
118 Data.checkDocumentation(zip,info);
119 assertTrue(results.get(r));
120 } catch (e:Dynamic) {
121 assertFalse(results.get(r));
122 }
123 }
103124 }
104125
105126 public function testReadDataWithCheck() {
Binary diff not shown
2020 !define VERLONG "%%VERLONG%%"
2121
2222 ; Define Neko info
23 !define NEKO_VERSION "2.3.0"
23 !define NEKO_VERSION "%%NEKO_VERSION%%"
2424
2525 ; Installer details
2626 VIAddVersionKey "CompanyName" "Haxe Foundation"
1414 ln -s /usr/local/lib/neko/nekoml /usr/local/bin/nekoml
1515 ln -s /usr/local/lib/neko/nekotools /usr/local/bin/nekotools
1616 ln -s /usr/local/lib/neko/libneko.dylib /usr/local/lib/libneko.dylib
17 ln -s /usr/local/lib/neko/libneko.2.dylib /usr/local/lib/libneko.2.dylib
18 ln -s /usr/local/lib/neko/libneko.2.1.0.dylib /usr/local/lib/libneko.2.1.0.dylib
17 ln -s /usr/local/lib/neko/libneko.%%NEKO_MAJOR_VERSION%%.dylib /usr/local/lib/libneko.%%NEKO_MAJOR_VERSION%%.dylib
18 ln -s /usr/local/lib/neko/libneko.%%NEKO_VERSION%%.dylib /usr/local/lib/libneko.%%NEKO_VERSION%%.dylib
22 - Check that haxelib is working
33 - Make sure to update the haxelib submodule
44 - Check that the run-time haxelibs are ready for release: hxcpp, hxjava, hxcs
5 - Check that the osx & windows installers has the latest neko release in "Makefile" and "Makefile.win" files
5 - Check that the NEKO_VERSION variable in the "Makefile" is set to the latest Neko version
66
77 # Making the release
88
00 OCAMLOPT = ocamlopt
11 OCAMLC = ocamlc
22 TARGET_FLAG = all
3 LIBS=extlib-leftovers extc neko javalib ilib swflib ttflib objsize pcre ziplib
3 LIBS=extlib-leftovers extc neko javalib ilib swflib ttflib objsize pcre2 ziplib
44
55 all: $(LIBS)
66 $(LIBS):
1515 $(MAKE) -C swflib clean
1616 $(MAKE) -C ttflib clean
1717 $(MAKE) -C objsize clean
18 $(MAKE) -C pcre clean
18 $(MAKE) -C pcre2 clean
1919 $(MAKE) -C ziplib clean
2020
2121 .PHONY: all clean $(LIBS)
22 (library
33 (name extc)
44 (libraries extlib)
5 (c_names extc_stubs)
5 (foreign_stubs
6 (language c)
7 (names extc_stubs))
68 (modules extc)
79 (wrapped false)
810 )
911
1012 (library
1113 (name extproc)
12 (c_names process_stubs)
14 (foreign_stubs
15 (language c)
16 (names process_stubs))
1317 (modules process)
1418 (wrapped false)
15 )
19 )
351351 let parse_access_flags ch all_flags =
352352 let fl = read_ui16 ch in
353353 let flags = ref [] in
354 let fbit = ref 0 in
355 List.iter (fun f ->
356 if fl land (1 lsl !fbit) <> 0 then begin
354 List.iteri (fun fbit f ->
355 if fl land (1 lsl fbit) <> 0 then begin
357356 flags := f :: !flags;
358357 if f = JUnusable then error ("Unusable flag: " ^ string_of_int fl)
359 end;
360 incr fbit
358 end
361359 ) all_flags;
362360 (*if fl land (0x4000 - (1 lsl !fbit)) <> 0 then error ("Invalid access flags " ^ string_of_int fl);*)
363361 !flags
11
22 (library
33 (name mbedtls)
4 (c_names
5 mbedtls_stubs
6 )
4 (foreign_stubs
5 (language c)
6 (names mbedtls_stubs))
77 (wrapped false)
8 )
8 )
+0
-40
libs/objsize/alloc.c less more
0 #if (!defined(ALLOC_PRF) || !defined(ALLOC_TYPE))
1 #error
2 #endif
3
4 #include "util.h"
5 #include <stdlib.h>
6 #include <stdio.h>
7
8
9 ALLOC_TYPE* ALLOC_PRF(_alloc)(size_t count)
10 {
11 return malloc(count * sizeof(ALLOC_TYPE));
12 }
13
14 void ALLOC_PRF(_free)(ALLOC_TYPE* arr)
15 {
16 free(arr);
17 }
18
19 ALLOC_TYPE* ALLOC_PRF(_realloc)(ALLOC_TYPE* arr, size_t count)
20 {
21 size_t newsz = count * sizeof(ALLOC_TYPE);
22 ALLOC_TYPE* newarr = realloc(arr, newsz);
23 if (count != 0 && newarr == NULL)
24 {
25 static char msg[128];
26 sprintf
27 ( msg
28 , "realloc(%p, %u*%u=%u) failed: to provide an alternative behaviour."
29 , arr, (unsigned int) count, (unsigned int) sizeof(ALLOC_TYPE)
30 , (unsigned int) newsz
31 );
32 ABORT(msg);
33 };
34 return newarr;
35 }
36
37
38 #undef ALLOC_PRF
39 #undef ALLOC_TYPE
0 #if (!defined(ALLOC_PRF) || !defined(ALLOC_TYPE))
1 #error
2 #endif
3
4 #include "util.h"
5 #include <stdlib.h>
6 #include <stdio.h>
7
8
9 ALLOC_TYPE* ALLOC_PRF(_alloc)(size_t count)
10 {
11 return malloc(count * sizeof(ALLOC_TYPE));
12 }
13
14 void ALLOC_PRF(_free)(ALLOC_TYPE* arr)
15 {
16 free(arr);
17 }
18
19 ALLOC_TYPE* ALLOC_PRF(_realloc)(ALLOC_TYPE* arr, size_t count)
20 {
21 size_t newsz = count * sizeof(ALLOC_TYPE);
22 ALLOC_TYPE* newarr = realloc(arr, newsz);
23 if (count != 0 && newarr == NULL)
24 {
25 static char msg[128];
26 sprintf
27 ( msg
28 , "realloc(%p, %u*%u=%u) failed: to provide an alternative behaviour."
29 , arr, (unsigned int) count, (unsigned int) sizeof(ALLOC_TYPE)
30 , (unsigned int) newsz
31 );
32 ABORT(msg);
33 };
34 return newarr;
35 }
36
37
38 #undef ALLOC_PRF
39 #undef ALLOC_TYPE
+0
-103
libs/objsize/bitarray.c less more
0 #if ((!defined(PRF)))
1 #error
2 #endif
3
4 #define BITS_OF_CHAR 8
5
6 /*
7 size_t PRF(_sizebytes)(size_t n);
8 TYPE PRF(_get)(TYPE arr[], size_t i);
9 void PRF(_set)(TYPE arr[], size_t i, TYPE val);
10 */
11
12 #define ALPRF(x) bitarrayalloc##x
13
14 #define ALLOC_TYPE unsigned char
15 #define ALLOC_PRF(x) ALPRF(x)
16 #include "alloc.c"
17
18
19 size_t wordalign(size_t n)
20 {
21 size_t al = sizeof(int);
22 size_t m = al % n;
23 if (m == 0)
24 {
25 return n;
26 }
27 else
28 {
29 return n + al - m;
30 }
31 }
32
33
34 size_t PRF(_sizebytes)(size_t n)
35 {
36 return wordalign(n/BITS_OF_CHAR);
37 }
38
39
40 unsigned char* PRF(_alloc)(size_t count)
41 {
42 return ALPRF(_alloc)(PRF(_sizebytes)(count));
43 }
44
45
46 void PRF(_free)(unsigned char* arr)
47 {
48 ALPRF(_free)(arr);
49 }
50
51
52 unsigned char* PRF(_realloc)(unsigned char* arr, size_t newcount)
53 {
54 return ALPRF(_realloc)(arr, PRF(_sizebytes)(newcount));
55 }
56
57
58 #define LVAL(arr, i) ((arr)[(i)/BITS_OF_CHAR])
59 #define MASK(i) (1<<((i)%BITS_OF_CHAR))
60
61 int PRF(_get)(unsigned char arr[], size_t i)
62 {
63 return ((LVAL(arr,i) & MASK(i)) ? 1 : 0);
64 }
65
66 void PRF(_set)(unsigned char arr[], size_t i, int val)
67 {
68 unsigned char mask = MASK(i);
69 if (val)
70 {
71 LVAL(arr,i) |= mask;
72 }
73 else
74 {
75 LVAL(arr,i) &= ~mask;
76 }
77 return;
78 }
79
80 void PRF(_init)(unsigned char arr[], size_t sz, int val)
81 {
82 size_t bytesize = sz/BITS_OF_CHAR;
83 size_t i;
84 unsigned char valbyte = val ? (-1) : 0;
85 for (i=0; i<bytesize; ++i)
86 {
87 arr[i] = valbyte;
88 };
89 i *= BITS_OF_CHAR;
90 while(i < sz)
91 {
92 PRF(_set)(arr, i, val);
93 ++i;
94 };
95 return;
96 }
97
98
99 #undef MASK
100 #undef LVAL
101
102 #undef PRF
0 #if ((!defined(PRF)))
1 #error
2 #endif
3
4 #define BITS_OF_CHAR 8
5
6 /*
7 size_t PRF(_sizebytes)(size_t n);
8 TYPE PRF(_get)(TYPE arr[], size_t i);
9 void PRF(_set)(TYPE arr[], size_t i, TYPE val);
10 */
11
12 #define ALPRF(x) bitarrayalloc##x
13
14 #define ALLOC_TYPE unsigned char
15 #define ALLOC_PRF(x) ALPRF(x)
16 #include "alloc.h"
17
18
19 size_t wordalign(size_t n)
20 {
21 size_t al = sizeof(int);
22 size_t m = al % n;
23 if (m == 0)
24 {
25 return n;
26 }
27 else
28 {
29 return n + al - m;
30 }
31 }
32
33
34 size_t PRF(_sizebytes)(size_t n)
35 {
36 return wordalign(n/BITS_OF_CHAR);
37 }
38
39
40 unsigned char* PRF(_alloc)(size_t count)
41 {
42 return ALPRF(_alloc)(PRF(_sizebytes)(count));
43 }
44
45
46 void PRF(_free)(unsigned char* arr)
47 {
48 ALPRF(_free)(arr);
49 }
50
51
52 unsigned char* PRF(_realloc)(unsigned char* arr, size_t newcount)
53 {
54 return ALPRF(_realloc)(arr, PRF(_sizebytes)(newcount));
55 }
56
57
58 #define LVAL(arr, i) ((arr)[(i)/BITS_OF_CHAR])
59 #define MASK(i) (1<<((i)%BITS_OF_CHAR))
60
61 int PRF(_get)(unsigned char arr[], size_t i)
62 {
63 return ((LVAL(arr,i) & MASK(i)) ? 1 : 0);
64 }
65
66 void PRF(_set)(unsigned char arr[], size_t i, int val)
67 {
68 unsigned char mask = MASK(i);
69 if (val)
70 {
71 LVAL(arr,i) |= mask;
72 }
73 else
74 {
75 LVAL(arr,i) &= ~mask;
76 }
77 return;
78 }
79
80 void PRF(_init)(unsigned char arr[], size_t sz, int val)
81 {
82 size_t bytesize = sz/BITS_OF_CHAR;
83 size_t i;
84 unsigned char valbyte = val ? (-1) : 0;
85 for (i=0; i<bytesize; ++i)
86 {
87 arr[i] = valbyte;
88 };
89 i *= BITS_OF_CHAR;
90 while(i < sz)
91 {
92 PRF(_set)(arr, i, val);
93 ++i;
94 };
95 return;
96 }
97
98
99 #undef MASK
100 #undef LVAL
101
102 #undef PRF
66
77
88 #define PRF(x) bitarray##x
9 #include "bitarray.c"
9 #include "bitarray.h"
1010
1111 #include "util.h"
1212
11
22 (library
33 (name objsize)
4 (c_names c_objsize)
5 (c_flags (-I../../../../libs/objsize)) ; TODO: This is stupid
4 (foreign_stubs (language c) (names c_objsize) (flags -O1 -W -Wall -Werror -fPIC))
5 (flags :standard -warn-error -a+8)
66 (wrapped false)
7 (modules objsize)
8 )
7 (modules objsize))
+0
-28
libs/pcre/Makefile less more
0 ALL_CFLAGS = $(CFLAGS) -I pcre
1 LIBS =
2 OCAMLOPT=ocamlopt
3 OCAMLC=ocamlc
4 SRC = pcre.ml pcre_stubs.c
5
6 all: bytecode native
7
8 bytecode: pcre.cma
9
10 native: pcre.cmxa
11
12 pcre.cma: pcre_stubs.o pcre.ml
13 $(OCAMLC) -safe-string -a -o pcre.cma $(LIBS) pcre.ml
14
15 pcre.cmxa: pcre.ml pcre_stubs.o
16 $(OCAMLOPT) -safe-string -a -o pcre.cmxa $(LIBS) pcre.ml
17
18 pcre_stubs.o: pcre_stubs.c
19 $(OCAMLC) -safe-string $(ALL_CFLAGS) pcre_stubs.c
20
21 clean:
22 rm -f pcre.cma pcre.cmi pcre.cmx pcre.cmxa pcre.o pcre.obj pcre_stubs.obj pcre_stubs.o
23 rm -f pcre.a libpcre.a libpcre.lib pcre.cmo
24
25 .PHONY: all bytecode native clean
26 Makefile: ;
27 $(SRC): ;
+0
-7
libs/pcre/dune less more
0 (include_subdirs no)
1
2 (library
3 (name pcre)
4 (c_names pcre_stubs)
5 (wrapped false)
6 )
+0
-1034
libs/pcre/pcre.ml less more
0 (*
1 PCRE-OCAML - Perl Compatibility Regular Expressions for OCaml
2 Copyright (C) 1999- Markus Mottl
3 email: markus.mottl@gmail.com
4 WWW: http://www.ocaml.info
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13 You should have received a copy of the GNU Lesser General Public
14 License along with this library; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 *)
17
18 (* Public exceptions and their registration with the C runtime *)
19
20 let string_copy str = str
21 let buffer_add_subbytes = Buffer.add_subbytes
22
23 type error =
24 | Partial
25 | BadPartial
26 | BadPattern of string * int
27 | BadUTF8
28 | BadUTF8Offset
29 | MatchLimit
30 | RecursionLimit
31 | InternalError of string
32
33 exception Error of error
34 exception Backtrack
35 exception Regexp_or of string * error
36
37 (* Puts exceptions into global C-variables for fast retrieval *)
38 external pcre_ocaml_init : unit -> unit = "pcre_ocaml_init"
39
40 (* Registers exceptions with the C runtime and caches polymorphic variants *)
41 let () =
42 Callback.register_exception "Pcre.Error" (Error (InternalError ""));
43 Callback.register_exception "Pcre.Backtrack" Backtrack;
44 pcre_ocaml_init ()
45
46
47 (* Compilation and runtime flags and their conversion functions *)
48
49 type icflag = int
50 type irflag = int
51
52 (* Compilation flags *)
53
54 type cflag =
55 [
56 | `CASELESS
57 | `MULTILINE
58 | `DOTALL
59 | `EXTENDED
60 | `ANCHORED
61 | `DOLLAR_ENDONLY
62 | `EXTRA
63 | `UNGREEDY
64 | `UTF8
65 | `NO_UTF8_CHECK
66 | `NO_AUTO_CAPTURE
67 | `AUTO_CALLOUT
68 | `FIRSTLINE
69 | `UCP
70 ]
71
72 let int_of_cflag = function
73 | `CASELESS -> 0x0001
74 | `MULTILINE -> 0x0002
75 | `DOTALL -> 0x0004
76 | `EXTENDED -> 0x0008
77 | `ANCHORED -> 0x0010
78 | `DOLLAR_ENDONLY -> 0x0020
79 | `EXTRA -> 0x0040
80 | `UNGREEDY -> 0x0200
81 | `UTF8 -> 0x0800
82 | `NO_AUTO_CAPTURE -> 0x1000
83 | `NO_UTF8_CHECK -> 0x2000
84 | `AUTO_CALLOUT -> 0x4000
85 | `FIRSTLINE -> 0x40000
86 | `UCP -> 0x20000000
87
88 let coll_icflag icflag flag = int_of_cflag flag lor icflag
89 let cflags flags = List.fold_left coll_icflag 0 flags
90
91 let cflag_of_int = function
92 | 0x0001 -> `CASELESS
93 | 0x0002 -> `MULTILINE
94 | 0x0004 -> `DOTALL
95 | 0x0008 -> `EXTENDED
96 | 0x0010 -> `ANCHORED
97 | 0x0020 -> `DOLLAR_ENDONLY
98 | 0x0040 -> `EXTRA
99 | 0x0200 -> `UNGREEDY
100 | 0x0800 -> `UTF8
101 | 0x1000 -> `NO_AUTO_CAPTURE
102 | 0x2000 -> `NO_UTF8_CHECK
103 | 0x4000 -> `AUTO_CALLOUT
104 | 0x40000 -> `FIRSTLINE
105 | 0x20000000 -> `UCP
106 | _ -> failwith "Pcre.cflag_list: unknown compilation flag"
107
108 let all_cflags =
109 [
110 0x0001; 0x0002; 0x0004; 0x0008; 0x0010; 0x0020;
111 0x0040; 0x0200; 0x0800; 0x1000; 0x2000; 0x4000; 0x40000;
112 0x20000000
113 ]
114
115 let cflag_list icflags =
116 let coll flag_list flag =
117 if icflags land flag <> 0 then cflag_of_int flag :: flag_list
118 else flag_list in
119 List.fold_left coll [] all_cflags
120
121
122 (* Runtime flags *)
123
124 type rflag =
125 [
126 | `ANCHORED
127 | `NOTBOL
128 | `NOTEOL
129 | `NOTEMPTY
130 | `PARTIAL
131 ]
132
133 let int_of_rflag = function
134 | `ANCHORED -> 0x0010
135 | `NOTBOL -> 0x0080
136 | `NOTEOL -> 0x0100
137 | `NOTEMPTY -> 0x0400
138 | `PARTIAL -> 0x8000
139
140 let coll_irflag irflag flag = int_of_rflag flag lor irflag
141 let rflags flags = List.fold_left coll_irflag 0 flags
142
143 let rflag_of_int = function
144 | 0x0010 -> `ANCHORED
145 | 0x0080 -> `NOTBOL
146 | 0x0100 -> `NOTEOL
147 | 0x0400 -> `NOTEMPTY
148 | 0x8000 -> `PARTIAL
149 | _ -> failwith "Pcre.rflag_list: unknown runtime flag"
150
151 let all_rflags = [0x0010; 0x0080; 0x0100; 0x0400; 0x8000]
152
153 let rflag_list irflags =
154 let coll flag_list flag =
155 if irflags land flag <> 0 then rflag_of_int flag :: flag_list
156 else flag_list in
157 List.fold_left coll [] all_rflags
158
159
160 (* Information on the PCRE-configuration (build-time options) *)
161
162 external pcre_version : unit -> string = "pcre_version_stub"
163
164 external pcre_config_utf8 : unit -> bool = "pcre_config_utf8_stub" [@@noalloc]
165
166 external pcre_config_newline :
167 unit -> char = "pcre_config_newline_stub" [@@noalloc]
168
169 external pcre_config_link_size :
170 unit -> int = "pcre_config_link_size_stub" [@@noalloc]
171
172 external pcre_config_match_limit :
173 unit -> int = "pcre_config_match_limit_stub" [@@noalloc]
174
175 external pcre_config_match_limit_recursion :
176 unit -> int = "pcre_config_match_limit_recursion_stub" [@@noalloc]
177
178 external pcre_config_stackrecurse :
179 unit -> bool = "pcre_config_stackrecurse_stub" [@@noalloc]
180
181 let version = pcre_version ()
182 let config_utf8 = pcre_config_utf8 ()
183 let config_newline = pcre_config_newline ()
184 let config_link_size = pcre_config_link_size ()
185 let config_match_limit = pcre_config_match_limit ()
186 let config_match_limit_recursion = pcre_config_match_limit_recursion ()
187 let config_stackrecurse = pcre_config_stackrecurse ()
188
189
190 (* Information on patterns *)
191
192 type firstbyte_info =
193 [ `Char of char
194 | `Start_only
195 | `ANCHORED ]
196
197 type study_stat =
198 [ `Not_studied
199 | `Studied
200 | `Optimal ]
201
202 type regexp
203
204 external options : regexp -> icflag = "pcre_options_stub"
205 external size : regexp -> int = "pcre_size_stub"
206 external studysize : regexp -> int = "pcre_studysize_stub"
207 external capturecount : regexp -> int = "pcre_capturecount_stub"
208 external backrefmax : regexp -> int = "pcre_backrefmax_stub"
209 external namecount : regexp -> int = "pcre_namecount_stub"
210 external names : regexp -> string array = "pcre_names_stub"
211 external nameentrysize : regexp -> int = "pcre_nameentrysize_stub"
212 external firstbyte : regexp -> firstbyte_info = "pcre_firstbyte_stub"
213 external firsttable : regexp -> string option = "pcre_firsttable_stub"
214 external lastliteral : regexp -> char option = "pcre_lastliteral_stub"
215 external study_stat : regexp -> study_stat = "pcre_study_stat_stub" [@@noalloc]
216
217
218 (* Compilation of patterns *)
219
220 type chtables
221
222 external maketables : unit -> chtables = "pcre_maketables_stub"
223
224 (* Internal use only! *)
225 external pcre_study : regexp -> unit = "pcre_study_stub"
226
227 external compile :
228 icflag -> chtables option -> string -> regexp = "pcre_compile_stub"
229
230 external get_match_limit : regexp -> int option = "pcre_get_match_limit_stub"
231
232 (* Internal use only! *)
233 external set_imp_match_limit :
234 regexp -> int -> regexp = "pcre_set_imp_match_limit_stub" [@@noalloc]
235
236 external get_match_limit_recursion :
237 regexp -> int option = "pcre_get_match_limit_recursion_stub"
238
239 (* Internal use only! *)
240 external set_imp_match_limit_recursion :
241 regexp -> int -> regexp = "pcre_set_imp_match_limit_recursion_stub" [@@noalloc]
242
243 let regexp
244 ?(study = true) ?limit ?limit_recursion
245 ?(iflags = 0) ?flags ?chtables pat =
246 let rex =
247 match flags with
248 | Some flag_list -> compile (cflags flag_list) chtables pat
249 | _ -> compile iflags chtables pat
250 in
251 if study then pcre_study rex;
252 let rex =
253 match limit with
254 | None -> rex
255 | Some lim -> set_imp_match_limit rex lim
256 in
257 match limit_recursion with
258 | None -> rex
259 | Some lim -> set_imp_match_limit_recursion rex lim
260
261 let regexp_or
262 ?study ?limit ?limit_recursion ?(iflags = 0) ?flags ?chtables pats =
263 let check pat =
264 try ignore (regexp ~study:false ~iflags ?flags ?chtables pat)
265 with Error error -> raise (Regexp_or (pat, error))
266 in
267 List.iter check pats;
268 let big_pat =
269 let cnv pat = "(?:" ^ pat ^ ")" in
270 String.concat "|" (List.rev (List.rev_map cnv pats))
271 in
272 regexp ?study ?limit ?limit_recursion ~iflags ?flags ?chtables big_pat
273
274 let bytes_unsafe_blit_string str str_ofs bts bts_ofs len =
275 let str_bts = Bytes.unsafe_of_string str in
276 Bytes.unsafe_blit str_bts str_ofs bts bts_ofs len
277
278 let string_unsafe_sub str ofs len =
279 let res = Bytes.create len in
280 bytes_unsafe_blit_string str ofs res 0 len;
281 Bytes.unsafe_to_string res
282
283 let quote s =
284 let len = String.length s in
285 let buf = Bytes.create (len lsl 1) in
286 let pos = ref 0 in
287 for i = 0 to len - 1 do
288 match String.unsafe_get s i with
289 | '\\' | '^' | '$' | '.' | '[' | '|'
290 | '(' | ')' | '?' | '*' | '+' | '{' as c ->
291 Bytes.unsafe_set buf !pos '\\';
292 incr pos;
293 Bytes.unsafe_set buf !pos c;
294 incr pos
295 | c -> Bytes.unsafe_set buf !pos c; incr pos
296 done;
297 string_unsafe_sub (Bytes.unsafe_to_string buf) 0 !pos
298
299
300 (* Matching of patterns and subpattern extraction *)
301
302 (* Default regular expression when none is provided by the user *)
303 let def_rex = regexp "\\s+"
304
305 type substrings = string * int array
306
307 type callout_data =
308 {
309 callout_number : int;
310 substrings : substrings;
311 start_match : int;
312 current_position : int;
313 capture_top : int;
314 capture_last : int;
315 pattern_position : int;
316 next_item_length : int;
317 }
318
319 type callout = callout_data -> unit
320
321 let get_subject (subj, _) = subj
322
323 let num_of_subs (_, ovector) = Array.length ovector / 3
324
325 let get_offset_start ovector str_num =
326 if str_num < 0 || str_num >= Array.length ovector / 3 then
327 invalid_arg "Pcre.get_offset_start: illegal offset";
328 let offset = str_num lsl 1 in
329 offset, Array.unsafe_get ovector offset
330
331 let get_substring_aux (subj, ovector) offset start =
332 if start < 0 then raise Not_found
333 else
334 string_unsafe_sub subj start (Array.unsafe_get ovector (offset + 1) - start)
335
336 let get_substring (_, ovector as substrings) str_num =
337 let offset, start = get_offset_start ovector str_num in
338 get_substring_aux substrings offset start
339
340 let get_substring_ofs (_subj, ovector) str_num =
341 let offset, start = get_offset_start ovector str_num in
342 if start < 0 then raise Not_found
343 else start, Array.unsafe_get ovector (offset + 1)
344
345 let unsafe_get_substring (_, ovector as substrings) str_num =
346 let offset = str_num lsl 1 in
347 try get_substring_aux substrings offset (Array.unsafe_get ovector offset)
348 with Not_found -> ""
349
350 let get_substrings ?(full_match = true) (_, ovector as substrings) =
351 if full_match then
352 Array.init (Array.length ovector / 3) (unsafe_get_substring substrings)
353 else
354 let len = (Array.length ovector / 3) - 1 in
355 Array.init len (fun n -> unsafe_get_substring substrings (n + 1))
356
357 let unsafe_get_opt_substring (_, ovector as substrings) str_num =
358 let offset = str_num lsl 1 in
359 try
360 let start = Array.unsafe_get ovector offset in
361 let str = get_substring_aux substrings offset start in
362 Some str
363 with Not_found -> None
364
365 let get_opt_substrings ?(full_match = true) (_, ovector as substrings) =
366 if full_match then
367 Array.init (Array.length ovector / 3) (unsafe_get_opt_substring substrings)
368 else
369 let len = (Array.length ovector / 3) - 1 in
370 Array.init len (fun n -> unsafe_get_opt_substring substrings (n + 1))
371
372 external get_stringnumber :
373 regexp -> string -> int = "pcre_get_stringnumber_stub"
374
375 let get_named_substring rex name substrings =
376 get_substring substrings (get_stringnumber rex name)
377
378 let get_named_substring_ofs rex name substrings =
379 get_substring_ofs substrings (get_stringnumber rex name)
380
381 external unsafe_pcre_exec :
382 irflag ->
383 regexp ->
384 pos : int ->
385 subj_start : int ->
386 subj : string ->
387 int array ->
388 callout option ->
389 unit = "pcre_exec_stub_bc" "pcre_exec_stub"
390
391 let make_ovector rex =
392 let subgroups1 = capturecount rex + 1 in
393 let subgroups2 = subgroups1 lsl 1 in
394 subgroups2, Array.make (subgroups1 + subgroups2) 0
395
396 let pcre_exec ?(iflags = 0) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
397 ?callout subj =
398 let rex = match pat with Some str -> regexp str | _ -> rex in
399 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
400 let _, ovector = make_ovector rex in
401 unsafe_pcre_exec iflags rex ~pos ~subj_start:0 ~subj ovector callout;
402 ovector
403
404 let exec ?iflags ?flags ?rex ?pat ?pos ?callout subj =
405 subj, pcre_exec ?iflags ?flags ?rex ?pat ?pos ?callout subj
406
407 let next_match ?iflags ?flags ?rex ?pat ?(pos = 0) ?callout (subj, ovector) =
408 let pos = Array.unsafe_get ovector 1 + pos in
409 let subj_len = String.length subj in
410 if pos < 0 || pos > subj_len then
411 invalid_arg "Pcre.next_match: illegal offset";
412 subj, pcre_exec ?iflags ?flags ?rex ?pat ~pos ?callout subj
413
414 let rec copy_lst ar n = function
415 | [] -> ar
416 | h :: t -> Array.unsafe_set ar n h; copy_lst ar (n - 1) t
417
418 let exec_all ?(iflags = 0) ?flags ?(rex = def_rex) ?pat ?pos ?callout subj =
419 let rex = match pat with Some str -> regexp str | _ -> rex in
420 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
421 let (_, ovector as sstrs) = exec ~iflags ~rex ?pos ?callout subj in
422 let null_flags = iflags lor 0x0400 in
423 let subj_len = String.length subj in
424 let rec loop pos (subj, ovector as sstrs) n lst =
425 let maybe_ovector =
426 try
427 let first = Array.unsafe_get ovector 0 in
428 if first = pos && Array.unsafe_get ovector 1 = pos then
429 if pos = subj_len then None
430 else Some (pcre_exec ~iflags:null_flags ~rex ~pos ?callout subj)
431 else Some (pcre_exec ~iflags ~rex ~pos ?callout subj)
432 with Not_found -> None in
433 match maybe_ovector with
434 | Some ovector ->
435 let new_pos = Array.unsafe_get ovector 1 in
436 loop new_pos (subj, ovector) (n + 1) (sstrs :: lst)
437 | None -> copy_lst (Array.make (n + 1) sstrs) (n - 1) lst in
438 loop (Array.unsafe_get ovector 1) sstrs 0 []
439
440 let extract ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
441 get_substrings ?full_match (exec ?iflags ?flags ?rex ?pat ?pos ?callout subj)
442
443 let extract_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
444 get_opt_substrings
445 ?full_match (exec ?iflags ?flags ?rex ?pat ?pos ?callout subj)
446
447 let extract_all ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
448 let many_sstrs = exec_all ?iflags ?flags ?rex ?pat ?pos ?callout subj in
449 Array.map (get_substrings ?full_match) many_sstrs
450
451 let extract_all_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
452 let many_sstrs = exec_all ?iflags ?flags ?rex ?pat ?pos ?callout subj in
453 Array.map (get_opt_substrings ?full_match) many_sstrs
454
455 let pmatch ?iflags ?flags ?rex ?pat ?pos ?callout subj =
456 try ignore (pcre_exec ?iflags ?flags ?rex ?pat ?pos ?callout subj); true
457 with Not_found -> false
458
459
460 (* String substitution *)
461
462 (* Elements of a substitution pattern *)
463 type subst =
464 | SubstString of int * int (* Denotes a substring in the substitution *)
465 | Backref of int (* nth backreference ($0 is program name!) *)
466 | Match (* The whole matched string *)
467 | PreMatch (* The string before the match *)
468 | PostMatch (* The string after the match *)
469 | LastParenMatch (* The last matched group *)
470
471 (* Information on substitution patterns *)
472 type substitution = string (* The substitution string *)
473 * int (* Highest group number of backreferences *)
474 * bool (* Makes use of "LastParenMatch" *)
475 * subst list (* The list of substitution elements *)
476
477 (* Only used internally in "subst" *)
478 exception FoundAt of int
479
480 let zero = Char.code '0'
481
482 let subst str =
483 let max_br = ref 0 in
484 let with_lp = ref false in
485 let lix = String.length str - 1 in
486 let rec loop acc n =
487 if lix < n then acc
488 else
489 try
490 for i = n to lix do
491 if String.unsafe_get str i = '$' then raise (FoundAt i)
492 done;
493 SubstString (n, lix - n + 1) :: acc
494 with FoundAt i ->
495 if i = lix then SubstString (n, lix - n + 1) :: acc
496 else
497 let i1 = i + 1 in
498 let acc = if n = i then acc else SubstString (n, i - n) :: acc in
499 match String.unsafe_get str i1 with
500 | '0'..'9' as c ->
501 let subpat_nr = ref (Char.code c - zero) in
502 (try
503 for j = i1 + 1 to lix do
504 let c = String.unsafe_get str j in
505 if c >= '0' && c <= '9' then
506 subpat_nr := 10 * !subpat_nr + Char.code c - zero
507 else raise (FoundAt j)
508 done;
509 max_br := max !subpat_nr !max_br;
510 Backref !subpat_nr :: acc
511 with FoundAt j ->
512 max_br := max !subpat_nr !max_br;
513 loop (Backref !subpat_nr :: acc) j)
514 | '!' -> loop acc (i1 + 1)
515 | '$' -> loop (SubstString (i1, 1) :: acc) (i1 + 1)
516 | '&' -> loop (Match :: acc) (i1 + 1)
517 | '`' -> loop (PreMatch :: acc) (i1 + 1)
518 | '\'' -> loop (PostMatch :: acc) (i1 + 1)
519 | '+' ->
520 with_lp := true;
521 loop (LastParenMatch :: acc) (i1 + 1)
522 | _ -> loop acc i1 in
523 let subst_lst = loop [] 0 in
524 str, !max_br, !with_lp, subst_lst
525
526 let def_subst = subst ""
527
528 (* Calculates a list of tuples (str, offset, len) which contain
529 substrings to be copied on substitutions. Internal use only! *)
530 let calc_trans_lst subgroups2 ovector subj templ subst_lst =
531 let prefix_len = Array.unsafe_get ovector 0 in
532 let last = Array.unsafe_get ovector 1 in
533 let coll (res_len, trans_lst as accu) =
534 let return_lst (_str, _ix, len as el) =
535 if len = 0 then accu else res_len + len, el :: trans_lst in
536 function
537 | SubstString (ix, len) -> return_lst (templ, ix, len)
538 | Backref 0 ->
539 let prog_name = Sys.argv.(0) in
540 return_lst (prog_name, 0, String.length prog_name)
541 | Backref n ->
542 let offset = n lsl 1 in
543 let start = Array.unsafe_get ovector offset in
544 let len = Array.unsafe_get ovector (offset + 1) - start in
545 return_lst (subj, start, len)
546 | Match -> return_lst (subj, prefix_len, last - prefix_len)
547 | PreMatch -> return_lst (subj, 0, prefix_len)
548 | PostMatch -> return_lst (subj, last, String.length subj - last)
549 | LastParenMatch ->
550 let subgroups2_2 = subgroups2 - 2 in
551 let pos = ref subgroups2_2 in
552 let ix = ref (Array.unsafe_get ovector subgroups2_2) in
553 while !ix < 0 do
554 let pos_2 = !pos - 2 in
555 pos := pos_2;
556 ix := Array.unsafe_get ovector pos_2
557 done;
558 return_lst (subj, !ix, Array.unsafe_get ovector (!pos + 1) - !ix) in
559 List.fold_left coll (0, []) subst_lst
560
561 let replace ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
562 ?(pos = 0) ?(itempl = def_subst) ?templ ?callout subj =
563 let rex = match pat with Some str -> regexp str | _ -> rex in
564 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
565 let templ, max_br, with_lp, subst_lst =
566 match templ with
567 | Some str -> subst str
568 | _ -> itempl in
569 let subj_len = String.length subj in
570 if pos < 0 || pos > subj_len then invalid_arg "Pcre.replace: illegal offset";
571 let subgroups2, ovector = make_ovector rex in
572 let nsubs = (subgroups2 lsr 1) - 1 in
573 if max_br > nsubs then
574 failwith "Pcre.replace: backreference denotes nonexistent subpattern";
575 if with_lp && nsubs = 0 then failwith "Pcre.replace: no backreferences";
576 let rec loop full_len trans_lsts cur_pos =
577 if
578 cur_pos > subj_len ||
579 try
580 unsafe_pcre_exec
581 iflags rex ~pos:cur_pos ~subj_start:0 ~subj
582 ovector callout;
583 false
584 with Not_found -> true
585 then
586 let postfix_len = max (subj_len - cur_pos) 0 in
587 let left = pos + full_len in
588 let res = Bytes.create (left + postfix_len) in
589 bytes_unsafe_blit_string subj 0 res 0 pos;
590 bytes_unsafe_blit_string subj cur_pos res left postfix_len;
591 let inner_coll ofs (templ, ix, len) =
592 bytes_unsafe_blit_string templ ix res ofs len; ofs + len in
593 let coll ofs (res_len, trans_lst) =
594 let new_ofs = ofs - res_len in
595 let _ = List.fold_left inner_coll new_ofs trans_lst in
596 new_ofs in
597 let _ = List.fold_left coll left trans_lsts in
598 Bytes.unsafe_to_string res
599 else
600 let first = Array.unsafe_get ovector 0 in
601 let len = first - cur_pos in
602 let res_len, _ as trans_lst_el =
603 calc_trans_lst subgroups2 ovector subj templ subst_lst in
604 let trans_lsts =
605 if len > 0 then
606 trans_lst_el :: (len, [(subj, cur_pos, len)]) :: trans_lsts
607 else trans_lst_el :: trans_lsts in
608 let full_len = full_len + len + res_len in
609 let next = first + 1 in
610 let last = Array.unsafe_get ovector 1 in
611 if last < next then
612 if first < subj_len then
613 let new_trans_lsts = (1, [(subj, cur_pos + len, 1)]) :: trans_lsts in
614 loop (full_len + 1) new_trans_lsts next
615 else loop full_len trans_lsts next
616 else loop full_len trans_lsts last in
617 loop 0 [] pos
618
619 let qreplace ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
620 ?(pos = 0) ?(templ = "") ?callout subj =
621 let rex = match pat with Some str -> regexp str | _ -> rex in
622 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
623 let subj_len = String.length subj in
624 if pos < 0 || pos > subj_len then invalid_arg "Pcre.qreplace: illegal offset";
625 let templ_len = String.length templ in
626 let _, ovector = make_ovector rex in
627 let rec loop full_len subst_lst cur_pos =
628 if
629 cur_pos > subj_len ||
630 try
631 unsafe_pcre_exec
632 iflags rex ~pos:cur_pos ~subj_start:0 ~subj ovector callout;
633 false
634 with Not_found -> true
635 then
636 let postfix_len = max (subj_len - cur_pos) 0 in
637 let left = pos + full_len in
638 let res = Bytes.create (left + postfix_len) in
639 bytes_unsafe_blit_string subj 0 res 0 pos;
640 bytes_unsafe_blit_string subj cur_pos res left postfix_len;
641 let coll ofs = function
642 | Some (substr, ix, len) ->
643 let new_ofs = ofs - len in
644 bytes_unsafe_blit_string substr ix res new_ofs len;
645 new_ofs
646 | None ->
647 let new_ofs = ofs - templ_len in
648 bytes_unsafe_blit_string templ 0 res new_ofs templ_len;
649 new_ofs in
650 let _ = List.fold_left coll left subst_lst in
651 Bytes.unsafe_to_string res
652 else
653 let first = Array.unsafe_get ovector 0 in
654 let len = first - cur_pos in
655 let subst_lst =
656 if len > 0 then None :: Some (subj, cur_pos, len) :: subst_lst
657 else None :: subst_lst in
658 let last = Array.unsafe_get ovector 1 in
659 let full_len = full_len + len + templ_len in
660 let next = first + 1 in
661 if last < next then
662 if first < subj_len then
663 loop (full_len + 1) (Some (subj, cur_pos + len, 1) :: subst_lst) next
664 else loop full_len subst_lst next
665 else loop full_len subst_lst last in
666 loop 0 [] pos
667
668 let substitute_substrings ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
669 ?(pos = 0) ?callout ~subst subj =
670 let rex = match pat with Some str -> regexp str | _ -> rex in
671 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
672 let subj_len = String.length subj in
673 if pos < 0 || pos > subj_len then invalid_arg "Pcre.substitute: illegal offset";
674 let _, ovector = make_ovector rex in
675 let rec loop full_len subst_lst cur_pos =
676 if
677 cur_pos > subj_len ||
678 try
679 unsafe_pcre_exec
680 iflags rex ~pos:cur_pos ~subj_start:0 ~subj ovector callout;
681 false
682 with Not_found -> true
683 then
684 let postfix_len = max (subj_len - cur_pos) 0 in
685 let left = pos + full_len in
686 let res = Bytes.create (left + postfix_len) in
687 bytes_unsafe_blit_string subj 0 res 0 pos;
688 bytes_unsafe_blit_string subj cur_pos res left postfix_len;
689 let coll ofs (templ, ix, len) =
690 let new_ofs = ofs - len in
691 bytes_unsafe_blit_string templ ix res new_ofs len;
692 new_ofs in
693 let _ = List.fold_left coll left subst_lst in
694 Bytes.unsafe_to_string res
695 else
696 let first = Array.unsafe_get ovector 0 in
697 let len = first - cur_pos in
698 let templ = subst (subj, ovector) in
699 let templ_len = String.length templ in
700 let subst_lst =
701 if len > 0 then
702 (templ, 0, templ_len) :: (subj, cur_pos, len) :: subst_lst
703 else (templ, 0, templ_len) :: subst_lst in
704 let last = Array.unsafe_get ovector 1 in
705 let full_len = full_len + len + templ_len in
706 let next = first + 1 in
707 if last < next then
708 if first < subj_len then
709 loop (full_len + 1) ((subj, cur_pos + len, 1) :: subst_lst) next
710 else loop full_len subst_lst next
711 else loop full_len subst_lst last in
712 loop 0 [] pos
713
714 let substitute ?iflags ?flags ?rex ?pat ?pos ?callout ~subst:str_subst subj =
715 let subst (subj, ovector) =
716 let first = Array.unsafe_get ovector 0 in
717 let last = Array.unsafe_get ovector 1 in
718 str_subst (string_unsafe_sub subj first (last - first)) in
719 substitute_substrings ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj
720
721 let replace_first ?(iflags = 0) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
722 ?(itempl = def_subst) ?templ ?callout subj =
723 let rex = match pat with Some str -> regexp str | _ -> rex in
724 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
725 let templ, max_br, with_lp, subst_lst =
726 match templ with
727 | Some str -> subst str
728 | _ -> itempl in
729 let subgroups2, ovector = make_ovector rex in
730 let nsubs = (subgroups2 lsr 1) - 1 in
731 if max_br > nsubs then
732 failwith "Pcre.replace_first: backreference denotes nonexistent subpattern";
733 if with_lp && nsubs = 0 then failwith "Pcre.replace_first: no backreferences";
734 try
735 unsafe_pcre_exec iflags rex ~pos ~subj_start:0 ~subj ovector callout;
736 let res_len, trans_lst =
737 calc_trans_lst subgroups2 ovector subj templ subst_lst in
738 let first = Array.unsafe_get ovector 0 in
739 let last = Array.unsafe_get ovector 1 in
740 let rest = String.length subj - last in
741 let res = Bytes.create (first + res_len + rest) in
742 bytes_unsafe_blit_string subj 0 res 0 first;
743 let coll ofs (templ, ix, len) =
744 bytes_unsafe_blit_string templ ix res ofs len; ofs + len in
745 let ofs = List.fold_left coll first trans_lst in
746 bytes_unsafe_blit_string subj last res ofs rest;
747 Bytes.unsafe_to_string res
748 with Not_found -> string_copy subj
749
750 let qreplace_first ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
751 ?(pos = 0) ?(templ = "") ?callout subj =
752 let rex = match pat with Some str -> regexp str | _ -> rex in
753 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
754 let _, ovector = make_ovector rex in
755 try
756 unsafe_pcre_exec iflags rex ~pos ~subj_start:0 ~subj ovector callout;
757 let first = Array.unsafe_get ovector 0 in
758 let last = Array.unsafe_get ovector 1 in
759 let len = String.length templ in
760 let rest = String.length subj - last in
761 let postfix_start = first + len in
762 let res = Bytes.create (postfix_start + rest) in
763 bytes_unsafe_blit_string subj 0 res 0 first;
764 bytes_unsafe_blit_string templ 0 res first len;
765 bytes_unsafe_blit_string subj last res postfix_start rest;
766 Bytes.unsafe_to_string res
767 with Not_found -> string_copy subj
768
769 let substitute_substrings_first ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
770 ?(pos = 0) ?callout ~subst subj =
771 let rex = match pat with Some str -> regexp str | _ -> rex in
772 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
773 let _, ovector = make_ovector rex in
774 try
775 unsafe_pcre_exec iflags rex ~pos ~subj_start:0 ~subj ovector callout;
776 let subj_len = String.length subj in
777 let prefix_len = Array.unsafe_get ovector 0 in
778 let last = Array.unsafe_get ovector 1 in
779 let templ = subst (subj, ovector) in
780 let postfix_len = subj_len - last in
781 let templ_len = String.length templ in
782 let postfix_start = prefix_len + templ_len in
783 let res = Bytes.create (postfix_start + postfix_len) in
784 bytes_unsafe_blit_string subj 0 res 0 prefix_len;
785 bytes_unsafe_blit_string templ 0 res prefix_len templ_len;
786 bytes_unsafe_blit_string subj last res postfix_start postfix_len;
787 Bytes.unsafe_to_string res
788 with Not_found -> string_copy subj
789
790 let substitute_first ?iflags ?flags ?rex ?pat ?pos
791 ?callout ~subst:str_subst subj =
792 let subst (subj, ovector) =
793 let first = Array.unsafe_get ovector 0 in
794 let last = Array.unsafe_get ovector 1 in
795 str_subst (string_unsafe_sub subj first (last - first)) in
796 substitute_substrings_first
797 ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj
798
799
800 (* Splitting *)
801
802 let internal_psplit flags rex max pos callout subj =
803 let subj_len = String.length subj in
804 if subj_len = 0 then []
805 else if max = 1 then [string_copy subj]
806 else
807 let subgroups2, ovector = make_ovector rex in
808
809 (* Adds contents of subgroups to the string accumulator *)
810 let handle_subgroups strs =
811 let strs = ref strs in
812 let i = ref 2 in
813 while !i < subgroups2 do
814 let first = Array.unsafe_get ovector !i in
815 incr i;
816 let last = Array.unsafe_get ovector !i in
817 let str =
818 if first < 0 then ""
819 else string_unsafe_sub subj first (last - first) in
820 strs := str :: !strs; incr i
821 done;
822 !strs in
823
824 (* Performs the recursive split *)
825 let rec loop strs cnt pos prematch =
826 let len = subj_len - pos in
827 if len < 0 then strs
828 else
829 (* Checks termination due to max restriction *)
830 if cnt = 0 then
831 if prematch &&
832 try
833 unsafe_pcre_exec
834 flags rex ~pos ~subj_start:pos ~subj ovector callout;
835 true
836 with Not_found -> false
837 then
838 let last = Array.unsafe_get ovector 1 in
839 let strs = handle_subgroups strs in
840 string_unsafe_sub subj last (subj_len - last) :: strs
841 else string_unsafe_sub subj pos len :: strs
842
843 (* Calculates next accumulator state for splitting *)
844 else
845 if
846 try
847 unsafe_pcre_exec
848 flags rex ~pos ~subj_start:pos ~subj ovector callout;
849 false
850 with Not_found -> true
851 then string_unsafe_sub subj pos len :: strs
852 else
853 let first = Array.unsafe_get ovector 0 in
854 let last = Array.unsafe_get ovector 1 in
855 if first = pos then
856 if last = pos then
857 let strs = if prematch then handle_subgroups strs else strs in
858 if len = 0 then "" :: strs
859 else if
860 try
861 unsafe_pcre_exec
862 (flags lor 0x0410) rex ~pos ~subj_start:pos ~subj
863 ovector callout;
864 true
865 with Not_found -> false
866 then
867 let new_strs = handle_subgroups ("" :: strs) in
868 loop new_strs (cnt - 1) (Array.unsafe_get ovector 1) false
869 else
870 let new_strs = string_unsafe_sub subj pos 1 :: strs in
871 loop new_strs (cnt - 1) (pos + 1) true
872 else
873 if prematch then loop (handle_subgroups strs) cnt last false
874 else loop (handle_subgroups ("" :: strs)) (cnt - 1) last false
875 else
876 let new_strs = string_unsafe_sub subj pos (first - pos) :: strs in
877 loop (handle_subgroups new_strs) (cnt - 1) last false in
878 loop [] (max - 1) pos false
879
880 let rec strip_all_empty = function "" :: t -> strip_all_empty t | l -> l
881
882 external isspace : char -> bool = "pcre_isspace_stub" [@@noalloc]
883
884 let rec find_no_space ix len str =
885 if ix = len || not (isspace (String.unsafe_get str ix)) then ix
886 else find_no_space (ix + 1) len str
887
888 let split ?(iflags = 0) ?flags ?rex ?pat ?(pos = 0) ?(max = 0) ?callout subj =
889 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
890 let res =
891 match pat, rex with
892 | Some str, _ -> internal_psplit iflags (regexp str) max pos callout subj
893 | _, Some rex -> internal_psplit iflags rex max pos callout subj
894 | _ ->
895 (* special case for Perl-splitting semantics *)
896 let len = String.length subj in
897 if pos > len || pos < 0 then failwith "Pcre.split: illegal offset";
898 let new_pos = find_no_space pos len subj in
899 internal_psplit iflags def_rex max new_pos callout subj in
900 List.rev (if max = 0 then strip_all_empty res else res)
901
902 let asplit ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj =
903 Array.of_list (split ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj)
904
905
906 (* Full splitting *)
907
908 type split_result = Text of string
909 | Delim of string
910 | Group of int * string
911 | NoGroup
912
913 let rec strip_all_empty_full = function
914 | Delim _ :: rest -> strip_all_empty_full rest
915 | l -> l
916
917 let full_split ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
918 ?(pos = 0) ?(max = 0) ?callout subj =
919 let rex = match pat with Some str -> regexp str | _ -> rex in
920 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
921 let subj_len = String.length subj in
922 if subj_len = 0 then []
923 else if max = 1 then [Text (string_copy subj)]
924 else
925 let subgroups2, ovector = make_ovector rex in
926
927 (* Adds contents of subgroups to the string accumulator *)
928 let handle_subgroups strs =
929 let strs = ref strs in
930 let i = ref 2 in
931 while !i < subgroups2 do
932 let group_nr = !i lsr 1 in
933 let first = Array.unsafe_get ovector !i in
934 incr i;
935 let last = Array.unsafe_get ovector !i in
936 let str =
937 if first < 0 then NoGroup
938 else
939 let group_str = string_unsafe_sub subj first (last - first) in
940 Group (group_nr, group_str) in
941 strs := str :: !strs; incr i
942 done;
943 !strs in
944
945 (* Performs the recursive split *)
946 let rec loop strs cnt pos prematch =
947 let len = subj_len - pos in
948 if len < 0 then strs
949 else
950 (* Checks termination due to max restriction *)
951 if cnt = 0 then
952 if prematch &&
953 try
954 unsafe_pcre_exec
955 iflags rex ~pos ~subj_start:pos ~subj ovector callout;
956 true
957 with Not_found -> false
958 then
959 let first = Array.unsafe_get ovector 0 in
960 let last = Array.unsafe_get ovector 1 in
961 let delim = Delim (string_unsafe_sub subj first (last - first)) in
962 Text (string_unsafe_sub subj last (subj_len - last))
963 :: handle_subgroups (delim :: strs)
964 else
965 if len = 0 then strs
966 else Text (string_unsafe_sub subj pos len) :: strs
967
968 (* Calculates next accumulator state for splitting *)
969 else
970 if
971 try
972 unsafe_pcre_exec
973 iflags rex ~pos ~subj_start:pos ~subj ovector callout;
974 false
975 with Not_found -> true
976 then
977 if len = 0 then strs
978 else Text (string_unsafe_sub subj pos len) :: strs
979 else
980 let first = Array.unsafe_get ovector 0 in
981 let last = Array.unsafe_get ovector 1 in
982 if first = pos then
983 if last = pos then
984 if len = 0 then handle_subgroups (Delim "" :: strs)
985 else
986 let empty_groups = handle_subgroups [] in
987 if
988 try
989 unsafe_pcre_exec
990 (iflags lor 0x0410) rex ~pos ~subj_start:pos ~subj
991 ovector callout;
992 true
993 with Not_found -> false
994 then
995 let first = Array.unsafe_get ovector 0 in
996 let last = Array.unsafe_get ovector 1 in
997 let delim =
998 Delim (string_unsafe_sub subj first (last - first)) in
999 let new_strs =
1000 handle_subgroups (
1001 delim :: (if prematch then strs
1002 else empty_groups @ (Delim "" :: strs))) in
1003 loop new_strs (cnt - 1) last false
1004 else
1005 let new_strs =
1006 Text (string_unsafe_sub subj pos 1)
1007 :: empty_groups @ Delim "" :: strs in
1008 loop new_strs (cnt - 1) (pos + 1) true
1009 else
1010 let delim =
1011 Delim (string_unsafe_sub subj first (last - first)) in
1012 loop (handle_subgroups (delim :: strs)) cnt last false
1013 else
1014 let delim = Delim (string_unsafe_sub subj first (last - first)) in
1015 let pre_strs =
1016 Text (string_unsafe_sub subj pos (first - pos)) :: strs in
1017 loop
1018 (handle_subgroups (delim :: pre_strs)) (cnt - 1) last false in
1019 let res = loop [] (max - 1) pos true in
1020 List.rev (if max = 0 then strip_all_empty_full res else res)
1021
1022
1023 (* Additional convenience functions useful in combination with this library *)
1024
1025 let foreach_line ?(ic = stdin) f =
1026 try while true do f (input_line ic) done with End_of_file -> ()
1027
1028 let foreach_file filenames f =
1029 let do_with_file filename =
1030 let file = open_in filename in
1031 try f filename file; close_in file
1032 with exn -> close_in file; raise exn in
1033 List.iter do_with_file filenames
+0
-736
libs/pcre/pcre_stubs.c less more
0 /*
1 PCRE-OCAML - Perl Compatibility Regular Expressions for OCaml
2
3 Copyright (C) 1999- Markus Mottl
4 email: markus.mottl@gmail.com
5 WWW: http://www.ocaml.info
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #if defined(_WIN32)
23 # if defined(_DLL)
24 # define PCREextern __declspec(dllexport)
25 # else
26 # define PCREextern
27 # endif
28 #endif
29
30 #if _WIN64
31 typedef long long *ovec_dst_ptr;
32 #else
33 typedef long *ovec_dst_ptr;
34 #endif
35
36 #if __GNUC__ >= 3
37 # define inline inline __attribute__ ((always_inline))
38 # define __unused __attribute__ ((unused))
39 #else
40 # define __unused
41 # define inline
42 #endif
43
44 #include <ctype.h>
45 #include <string.h>
46 #include <stdio.h>
47
48 #include <caml/mlvalues.h>
49 #include <caml/alloc.h>
50 #include <caml/memory.h>
51 #include <caml/fail.h>
52 #include <caml/callback.h>
53
54 #include "pcre.h"
55
56 /* Error codes as defined for pcre 7.9, undefined in pcre 4.5 */
57 #ifndef PCRE_ERROR_PARTIAL
58 #define PCRE_ERROR_PARTIAL (-12)
59 #endif
60 #ifndef PCRE_ERROR_BADPARTIAL
61 #define PCRE_ERROR_BADPARTIAL (-13)
62 #endif
63 #ifndef PCRE_ERROR_RECURSIONLIMIT
64 #define PCRE_ERROR_RECURSIONLIMIT (-21)
65 #endif
66
67 typedef const unsigned char *chartables; /* Type of chartable sets */
68
69 /* Contents of callout data */
70 struct cod {
71 long subj_start; /* Start of subject string */
72 value *v_substrings_p; /* Pointer to substrings matched so far */
73 value *v_cof_p; /* Pointer to callout function */
74 value v_exn; /* Possible exception raised by callout function */
75 };
76
77 /* Cache for exceptions */
78 static value *pcre_exc_Error = NULL; /* Exception [Error] */
79 static value *pcre_exc_Backtrack = NULL; /* Exception [Backtrack] */
80
81 /* Cache for polymorphic variants */
82 static value var_Start_only; /* Variant [`Start_only] */
83 static value var_ANCHORED; /* Variant [`ANCHORED] */
84 static value var_Char; /* Variant [`Char char] */
85 static value var_Not_studied; /* Variant [`Not_studied] */
86 static value var_Studied; /* Variant [`Studied] */
87 static value var_Optimal; /* Variant [`Optimal] */
88
89 static value None = Val_int(0);
90
91 /* Converts subject offsets from C-integers to OCaml-Integers.
92
93 This is a bit tricky, because there are 32- and 64-bit platforms around
94 and OCaml chooses the larger possibility for representing integers when
95 available (also in arrays) - not so the PCRE!
96 */
97 static inline void copy_ovector(
98 long subj_start, const int *ovec_src, ovec_dst_ptr ovec_dst, int subgroups2)
99 {
100 if (subj_start == 0)
101 while (subgroups2--) {
102 *ovec_dst = Val_int(*ovec_src);
103 --ovec_src; --ovec_dst;
104 }
105 else
106 while (subgroups2--) {
107 *ovec_dst = Val_long(*ovec_src + subj_start);
108 --ovec_src; --ovec_dst;
109 }
110 }
111
112 /* Callout handler */
113 static int pcre_callout_handler(pcre_callout_block* cb)
114 {
115 struct cod *cod = (struct cod *) cb->callout_data;
116
117 if (cod != NULL) {
118 /* Callout is available */
119 value v_res;
120
121 /* Set up parameter array */
122 value v_callout_data = caml_alloc_small(8, 0);
123
124 const value v_substrings = *cod->v_substrings_p;
125
126 const int capture_top = cb->capture_top;
127 int subgroups2 = capture_top << 1;
128 const int subgroups2_1 = subgroups2 - 1;
129
130 const int *ovec_src = cb->offset_vector + subgroups2_1;
131 ovec_dst_ptr ovec_dst = &Field(Field(v_substrings, 1), 0) + subgroups2_1;
132 long subj_start = cod->subj_start;
133
134 copy_ovector(subj_start, ovec_src, ovec_dst, subgroups2);
135
136 Field(v_callout_data, 0) = Val_int(cb->callout_number);
137 Field(v_callout_data, 1) = v_substrings;
138 Field(v_callout_data, 2) = Val_int(cb->start_match + subj_start);
139 Field(v_callout_data, 3) = Val_int(cb->current_position + subj_start);
140 Field(v_callout_data, 4) = Val_int(capture_top);
141 Field(v_callout_data, 5) = Val_int(cb->capture_last);
142 Field(v_callout_data, 6) = Val_int(cb->pattern_position);
143 Field(v_callout_data, 7) = Val_int(cb->next_item_length);
144
145 /* Perform callout */
146 v_res = caml_callback_exn(*cod->v_cof_p, v_callout_data);
147
148 if (Is_exception_result(v_res)) {
149 /* Callout raised an exception */
150 const value v_exn = Extract_exception(v_res);
151 if (Field(v_exn, 0) == *pcre_exc_Backtrack) return 1;
152 cod->v_exn = v_exn;
153 return PCRE_ERROR_CALLOUT;
154 }
155 }
156
157 return 0;
158 }
159
160 /* Fetchs the named OCaml-values + caches them and
161 calculates + caches the variant hash values */
162 CAMLprim value pcre_ocaml_init(value __unused v_unit)
163 {
164 pcre_exc_Error = caml_named_value("Pcre.Error");
165 pcre_exc_Backtrack = caml_named_value("Pcre.Backtrack");
166
167 var_Start_only = caml_hash_variant("Start_only");
168 var_ANCHORED = caml_hash_variant("ANCHORED");
169 var_Char = caml_hash_variant("Char");
170 var_Not_studied = caml_hash_variant("Not_studied");
171 var_Studied = caml_hash_variant("Studied");
172 var_Optimal = caml_hash_variant("Optimal");
173
174 pcre_callout = &pcre_callout_handler;
175
176 return Val_unit;
177 }
178
179 /* Finalizing deallocation function for chartable sets */
180 static void pcre_dealloc_tables(value v_table)
181 { (pcre_free)((void *) Field(v_table, 1)); }
182
183 /* Finalizing deallocation function for compiled regular expressions */
184 static void pcre_dealloc_regexp(value v_rex)
185 {
186 void *extra = (void *) Field(v_rex, 2);
187 (pcre_free)((void *) Field(v_rex, 1));
188 if (extra != NULL)
189 #ifdef PCRE_STUDY_JIT_COMPILE
190 pcre_free_study(extra);
191 #else
192 pcre_free(extra);
193 #endif
194 }
195
196 /* Makes OCaml-string from PCRE-version */
197 CAMLprim value pcre_version_stub(value __unused v_unit)
198 {
199 return caml_copy_string((char *) pcre_version());
200 }
201
202
203 /* Raising exceptions */
204
205 static inline void raise_pcre_error(value v_arg) Noreturn;
206 static inline void raise_partial() Noreturn;
207 static inline void raise_bad_partial() Noreturn;
208 static inline void raise_bad_utf8() Noreturn;
209 static inline void raise_bad_utf8_offset() Noreturn;
210 static inline void raise_match_limit() Noreturn;
211 static inline void raise_recursion_limit() Noreturn;
212 static inline void raise_bad_pattern(const char *msg, int pos) Noreturn;
213 static inline void raise_internal_error(char *msg) Noreturn;
214
215 static inline void raise_pcre_error(value v_arg)
216 { caml_raise_with_arg(*pcre_exc_Error, v_arg); }
217
218 static inline void raise_partial() { raise_pcre_error(Val_int(0)); }
219 static inline void raise_bad_partial() { raise_pcre_error(Val_int(1)); }
220 static inline void raise_bad_utf8() { raise_pcre_error(Val_int(2)); }
221 static inline void raise_bad_utf8_offset() { raise_pcre_error(Val_int(3)); }
222 static inline void raise_match_limit() { raise_pcre_error(Val_int(4)); }
223 static inline void raise_recursion_limit() { raise_pcre_error(Val_int(5)); }
224
225 static inline void raise_bad_pattern(const char *msg, int pos)
226 {
227 CAMLparam0();
228 CAMLlocal1(v_msg);
229 value v_arg;
230 v_msg = caml_copy_string(msg);
231 v_arg = caml_alloc_small(2, 0);
232 Field(v_arg, 0) = v_msg;
233 Field(v_arg, 1) = Val_int(pos);
234 raise_pcre_error(v_arg);
235 CAMLnoreturn;
236 }
237
238 static inline void raise_internal_error(char *msg)
239 {
240 CAMLparam0();
241 CAMLlocal1(v_msg);
242 value v_arg;
243 v_msg = caml_copy_string(msg);
244 v_arg = caml_alloc_small(1, 1);
245 Field(v_arg, 0) = v_msg;
246 raise_pcre_error(v_arg);
247 CAMLnoreturn;
248 }
249
250 /* PCRE pattern compilation */
251
252 /* Makes compiled regular expression from compilation options, an optional
253 value of chartables and the pattern string */
254 CAMLprim value pcre_compile_stub(value v_opt, value v_tables, value v_pat)
255 {
256 value v_rex; /* Final result -> value of type [regexp] */
257 const char *error = NULL; /* pointer to possible error message */
258 int error_ofs = 0; /* offset in the pattern at which error occurred */
259
260 /* If v_tables = [None], then pointer to tables is NULL, otherwise
261 set it to the appropriate value */
262 chartables tables =
263 (v_tables == None) ? NULL : (chartables) Field(Field(v_tables, 0), 1);
264
265 /* Compiles the pattern */
266 pcre *regexp = pcre_compile(String_val(v_pat), Int_val(v_opt), &error,
267 &error_ofs, tables);
268
269 /* Raises appropriate exception with [BadPattern] if the pattern
270 could not be compiled */
271 if (regexp == NULL) raise_bad_pattern(error, error_ofs);
272
273 /* GC will do a full cycle every 1_000_000 regexp allocations (a typical
274 regexp probably consumes less than 100 bytes -> maximum of 100_000_000
275 bytes unreclaimed regexps) */
276 v_rex = caml_alloc_final(4, pcre_dealloc_regexp, 1, 1000000);
277
278 /* Field[1]: compiled regular expression (Field[0] is finalizing
279 function! See above!) */
280 Field(v_rex, 1) = (value) regexp;
281
282 /* Field[2]: extra information about regexp when it has been studied
283 successfully */
284 Field(v_rex, 2) = (value) NULL;
285
286 /* Field[3]: If 0 -> regexp has not yet been studied
287 1 -> regexp has already been studied */
288 Field(v_rex, 3) = 0;
289
290 return v_rex;
291 }
292
293 /* Studies a regexp */
294 CAMLprim value pcre_study_stub(value v_rex)
295 {
296 /* If it has not yet been studied */
297 if (! (int) Field(v_rex, 3)) {
298 const char *error = NULL;
299 pcre_extra *extra = pcre_study((pcre *) Field(v_rex, 1), 0, &error);
300 if (error != NULL) caml_invalid_argument((char *) error);
301 Field(v_rex, 2) = (value) extra;
302 Field(v_rex, 3) = Val_int(1);
303 }
304 return v_rex;
305 }
306
307 /* Sets a match limit recursion for a regular expression imperatively */
308 CAMLprim value pcre_set_imp_match_limit_recursion_stub(value v_rex, value v_lim)
309 {
310 pcre_extra *extra = (pcre_extra *) Field(v_rex, 2);
311 if (extra == NULL) {
312 extra = pcre_malloc(sizeof(pcre_extra));
313 extra->flags = PCRE_EXTRA_MATCH_LIMIT_RECURSION;
314 Field(v_rex, 2) = (value) extra;
315 } else {
316 unsigned long *flags_ptr = &extra->flags;
317 *flags_ptr = PCRE_EXTRA_MATCH_LIMIT_RECURSION | *flags_ptr;
318 }
319 extra->match_limit_recursion = Int_val(v_lim);
320 return v_rex;
321 }
322
323 /* Gets the match limit recursion of a regular expression if it exists */
324 CAMLprim value pcre_get_match_limit_recursion_stub(value v_rex)
325 {
326 pcre_extra *extra = (pcre_extra *) Field(v_rex, 2);
327 if (extra == NULL) return None;
328 if (extra->flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) {
329 value v_lim = Val_int(extra->match_limit_recursion);
330 value v_res = caml_alloc_small(1, 0);
331 Field(v_res, 0) = v_lim;
332 return v_res;
333 }
334 return None;
335 }
336
337 /* Sets a match limit for a regular expression imperatively */
338 CAMLprim value pcre_set_imp_match_limit_stub(value v_rex, value v_lim)
339 {
340 pcre_extra *extra = (pcre_extra *) Field(v_rex, 2);
341 if (extra == NULL) {
342 extra = pcre_malloc(sizeof(pcre_extra));
343 extra->flags = PCRE_EXTRA_MATCH_LIMIT;
344 Field(v_rex, 2) = (value) extra;
345 } else {
346 unsigned long *flags_ptr = &extra->flags;
347 *flags_ptr = PCRE_EXTRA_MATCH_LIMIT | *flags_ptr;
348 }
349 extra->match_limit = Int_val(v_lim);
350 return v_rex;
351 }
352
353 /* Gets the match limit of a regular expression if it exists */
354 CAMLprim value pcre_get_match_limit_stub(value v_rex)
355 {
356 pcre_extra *extra = (pcre_extra *) Field(v_rex, 2);
357 if (extra == NULL) return None;
358 if (extra->flags & PCRE_EXTRA_MATCH_LIMIT) {
359 value v_lim = Val_int(extra->match_limit);
360 value v_res = caml_alloc_small(1, 0);
361 Field(v_res, 0) = v_lim;
362 return v_res;
363 }
364 return None;
365 }
366
367 /* Performs the call to the pcre_fullinfo function */
368 static inline int pcre_fullinfo_stub(value v_rex, int what, void *where)
369 {
370 return pcre_fullinfo((pcre *) Field(v_rex, 1), (pcre_extra *) Field(v_rex, 2),
371 what, where);
372 }
373
374 /* Some stubs for info-functions */
375
376 /* Generic macro for getting integer results from pcre_fullinfo */
377 #define make_info(tp, cnv, name, option) \
378 CAMLprim value pcre_##name##_stub(value v_rex) \
379 { \
380 tp options; \
381 const int ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_##option, &options); \
382 if (ret != 0) raise_internal_error("pcre_##name##_stub"); \
383 return cnv(options); \
384 }
385
386 make_info(unsigned long, Val_long, options, OPTIONS)
387 make_info(size_t, Val_long, size, SIZE)
388 make_info(size_t, Val_long, studysize, STUDYSIZE)
389 make_info(int, Val_int, capturecount, CAPTURECOUNT)
390 make_info(int, Val_int, backrefmax, BACKREFMAX)
391 make_info(int, Val_int, namecount, NAMECOUNT)
392 make_info(int, Val_int, nameentrysize, NAMEENTRYSIZE)
393
394 CAMLprim value pcre_firstbyte_stub(value v_rex)
395 {
396 int firstbyte;
397 const int ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_FIRSTBYTE, &firstbyte);
398
399 if (ret != 0) raise_internal_error("pcre_firstbyte_stub");
400
401 switch (firstbyte) {
402 case -1 : return var_Start_only; break; /* [`Start_only] */
403 case -2 : return var_ANCHORED; break; /* [`ANCHORED] */
404 default :
405 if (firstbyte < 0 ) /* Should not happen */
406 raise_internal_error("pcre_firstbyte_stub");
407 else {
408 value v_firstbyte;
409 /* Allocates the non-constant constructor [`Char of char] and fills
410 in the appropriate value */
411 v_firstbyte = caml_alloc_small(2, 0);
412 Field(v_firstbyte, 0) = var_Char;
413 Field(v_firstbyte, 1) = Val_int(firstbyte);
414 return v_firstbyte;
415 }
416 }
417 }
418
419 CAMLprim value pcre_firsttable_stub(value v_rex)
420 {
421 const unsigned char *ftable;
422
423 int ret =
424 pcre_fullinfo_stub(v_rex, PCRE_INFO_FIRSTTABLE, (void *) &ftable);
425
426 if (ret != 0) raise_internal_error("pcre_firsttable_stub");
427
428 if (ftable == NULL) return None;
429 else {
430 value v_res, v_res_str;
431 char *ptr;
432 int i;
433
434 Begin_roots1(v_rex);
435 v_res_str = caml_alloc_string(32);
436 End_roots();
437
438 ptr = String_val(v_res_str);
439 for (i = 0; i <= 31; ++i) { *ptr = *ftable; ++ptr; ++ftable; }
440
441 Begin_roots1(v_res_str);
442 /* Allocates [Some string] from firsttable */
443 v_res = caml_alloc_small(1, 0);
444 End_roots();
445
446 Field(v_res, 0) = v_res_str;
447
448 return v_res;
449 }
450 }
451
452 CAMLprim value pcre_lastliteral_stub(value v_rex)
453 {
454 int lastliteral;
455 const int ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_LASTLITERAL,
456 &lastliteral);
457
458 if (ret != 0) raise_internal_error("pcre_lastliteral_stub");
459
460 if (lastliteral == -1) return None;
461 if (lastliteral < 0) raise_internal_error("pcre_lastliteral_stub");
462 else {
463 /* Allocates [Some char] */
464 value v_res = caml_alloc_small(1, 0);
465 Field(v_res, 0) = Val_int(lastliteral);
466 return v_res;
467 }
468 }
469
470 CAMLprim value pcre_study_stat_stub(value v_rex)
471 {
472 /* Generates the appropriate constant constructor [`Optimal] or
473 [`Studied] if regexp has already been studied */
474 if (Field(v_rex, 3))
475 return ((pcre_extra *) Field(v_rex, 2) == NULL) ? var_Optimal : var_Studied;
476
477 return var_Not_studied; /* otherwise [`Not_studied] */
478 }
479
480 static inline void handle_exec_error(char *loc, const int ret) Noreturn;
481
482 static inline void handle_exec_error(char *loc, const int ret)
483 {
484 switch (ret) {
485 /* Dedicated exceptions */
486 case PCRE_ERROR_NOMATCH : caml_raise_not_found();
487 case PCRE_ERROR_PARTIAL : raise_partial();
488 case PCRE_ERROR_MATCHLIMIT : raise_match_limit();
489 case PCRE_ERROR_BADPARTIAL : raise_bad_partial();
490 case PCRE_ERROR_BADUTF8 : raise_bad_utf8();
491 case PCRE_ERROR_BADUTF8_OFFSET : raise_bad_utf8_offset();
492 case PCRE_ERROR_RECURSIONLIMIT : raise_recursion_limit();
493 /* Unknown error */
494 default : {
495 char err_buf[100];
496 snprintf(err_buf, 100, "%s: unhandled PCRE error code: %d", loc, ret);
497 raise_internal_error(err_buf);
498 }
499 }
500 }
501
502 static inline void handle_pcre_exec_result(
503 int *ovec, value v_ovec, long ovec_len, long subj_start, int ret)
504 {
505 ovec_dst_ptr ocaml_ovec = (ovec_dst_ptr) &Field(v_ovec, 0);
506 const int subgroups2 = ret * 2;
507 const int subgroups2_1 = subgroups2 - 1;
508 const int *ovec_src = ovec + subgroups2_1;
509 ovec_dst_ptr ovec_clear_stop = ocaml_ovec + (ovec_len * 2) / 3;
510 ovec_dst_ptr ovec_dst = ocaml_ovec + subgroups2_1;
511 copy_ovector(subj_start, ovec_src, ovec_dst, subgroups2);
512 while (++ovec_dst < ovec_clear_stop) *ovec_dst = -1;
513 }
514
515 /* Executes a pattern match with runtime options, a regular expression, a
516 matching position, the start of the the subject string, a subject string,
517 a number of subgroup offsets, an offset vector and an optional callout
518 function */
519 CAMLprim value pcre_exec_stub(value v_opt, value v_rex, value v_pos,
520 value v_subj_start, value v_subj,
521 value v_ovec, value v_maybe_cof)
522 {
523 int ret;
524 long
525 pos = Long_val(v_pos),
526 len = caml_string_length(v_subj),
527 subj_start = Long_val(v_subj_start);
528 long ovec_len = Wosize_val(v_ovec);
529
530 if (pos > len || pos < subj_start)
531 caml_invalid_argument("Pcre.pcre_exec_stub: illegal position");
532
533 if (subj_start > len || subj_start < 0)
534 caml_invalid_argument("Pcre.pcre_exec_stub: illegal subject start");
535
536 pos -= subj_start;
537 len -= subj_start;
538
539 {
540 const pcre *code = (pcre *) Field(v_rex, 1); /* Compiled pattern */
541 const pcre_extra *extra = (pcre_extra *) Field(v_rex, 2); /* Extra info */
542 const char *ocaml_subj =
543 String_val(v_subj) + subj_start; /* Subject string */
544 const int opt = Int_val(v_opt); /* Runtime options */
545
546 /* Special case when no callout functions specified */
547 if (v_maybe_cof == None) {
548 int *ovec = (int *) &Field(v_ovec, 0);
549
550 /* Performs the match */
551 ret = pcre_exec(code, extra, ocaml_subj, len, pos, opt, ovec, ovec_len);
552
553 if (ret < 0) handle_exec_error("pcre_exec_stub", ret);
554 else handle_pcre_exec_result(ovec, v_ovec, ovec_len, subj_start, ret);
555 }
556
557 /* There are callout functions */
558 else {
559 value v_cof = Field(v_maybe_cof, 0);
560 value v_substrings;
561 char *subj = caml_stat_alloc(sizeof(char) * len);
562 int *ovec = caml_stat_alloc(sizeof(int) * ovec_len);
563 struct cod cod = { 0, (value *) NULL, (value *) NULL, (value) NULL };
564 struct pcre_extra new_extra =
565 #ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION
566 # ifdef PCRE_EXTRA_MARK
567 # ifdef PCRE_EXTRA_EXECUTABLE_JIT
568 { PCRE_EXTRA_CALLOUT_DATA, NULL, 0, NULL, NULL, 0, NULL, NULL };
569 # else
570 { PCRE_EXTRA_CALLOUT_DATA, NULL, 0, NULL, NULL, 0, NULL };
571 # endif
572 # else
573 { PCRE_EXTRA_CALLOUT_DATA, NULL, 0, NULL, NULL, 0 };
574 # endif
575 #else
576 { PCRE_EXTRA_CALLOUT_DATA, NULL, 0, NULL, NULL };
577 #endif
578
579 cod.subj_start = subj_start;
580 memcpy(subj, ocaml_subj, len);
581
582 Begin_roots4(v_rex, v_cof, v_substrings, v_ovec);
583 Begin_roots1(v_subj);
584 v_substrings = caml_alloc_small(2, 0);
585 End_roots();
586
587 Field(v_substrings, 0) = v_subj;
588 Field(v_substrings, 1) = v_ovec;
589
590 cod.v_substrings_p = &v_substrings;
591 cod.v_cof_p = &v_cof;
592 new_extra.callout_data = &cod;
593
594 if (extra == NULL) {
595 ret = pcre_exec(code, &new_extra, subj, len, pos, opt, ovec,
596 ovec_len);
597 }
598 else {
599 new_extra.flags = PCRE_EXTRA_CALLOUT_DATA | extra->flags;
600 new_extra.study_data = extra->study_data;
601 new_extra.match_limit = extra->match_limit;
602 new_extra.tables = extra->tables;
603 #ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION
604 new_extra.match_limit_recursion = extra->match_limit_recursion;
605 #endif
606
607 ret = pcre_exec(code, &new_extra, subj, len, pos, opt, ovec,
608 ovec_len);
609 }
610
611 caml_stat_free(subj);
612 End_roots();
613
614 if (ret < 0) {
615 caml_stat_free(ovec);
616 if (ret == PCRE_ERROR_CALLOUT) caml_raise(cod.v_exn);
617 else handle_exec_error("pcre_exec_stub(callout)", ret);
618 } else {
619 handle_pcre_exec_result(ovec, v_ovec, ovec_len, subj_start, ret);
620 caml_stat_free(ovec);
621 }
622 }
623 }
624
625 return Val_unit;
626 }
627
628 /* Byte-code hook for pcre_exec_stub
629 Needed, because there are more than 5 arguments */
630 CAMLprim value pcre_exec_stub_bc(value *argv, int __unused argn)
631 {
632 return pcre_exec_stub(argv[0], argv[1], argv[2], argv[3],
633 argv[4], argv[5], argv[6]);
634 }
635
636 /* Generates a new set of chartables for the current locale (see man
637 page of PCRE */
638 CAMLprim value pcre_maketables_stub(value __unused v_unit)
639 {
640 /* GC will do a full cycle every 1_000_000 table set allocations (one
641 table set consumes 864 bytes -> maximum of 864_000_000 bytes unreclaimed
642 table sets) */
643 const value v_res = caml_alloc_final(2, pcre_dealloc_tables, 1, 1000000);
644 Field(v_res, 1) = (value) pcre_maketables();
645 return v_res;
646 }
647
648 /* Wraps around the isspace-function */
649 CAMLprim value pcre_isspace_stub(value v_c)
650 {
651 return Val_bool(isspace(Int_val(v_c)));
652 }
653
654 /* Returns number of substring associated with a name */
655 CAMLprim value pcre_get_stringnumber_stub(value v_rex, value v_name)
656 {
657 const int ret = pcre_get_stringnumber((pcre *) Field(v_rex, 1),
658 String_val(v_name));
659 if (ret == PCRE_ERROR_NOSUBSTRING)
660 caml_invalid_argument("Named string not found");
661
662 return Val_int(ret);
663 }
664
665 /* Returns array of names of named substrings in a regexp */
666 CAMLprim value pcre_names_stub(value v_rex)
667 {
668 CAMLparam0();
669 CAMLlocal1(v_res);
670 int name_count;
671 int entry_size;
672 const char *tbl_ptr;
673 int i;
674
675 int ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_NAMECOUNT, &name_count);
676 if (ret != 0) raise_internal_error("pcre_names_stub: namecount");
677
678 ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_NAMEENTRYSIZE, &entry_size);
679 if (ret != 0) raise_internal_error("pcre_names_stub: nameentrysize");
680
681 ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_NAMETABLE, &tbl_ptr);
682 if (ret != 0) raise_internal_error("pcre_names_stub: nametable");
683
684 v_res = caml_alloc(name_count, 0);
685
686 for (i = 0; i < name_count; ++i) {
687 value v_name = caml_copy_string(tbl_ptr + 2);
688 Store_field(v_res, i, v_name);
689 tbl_ptr += entry_size;
690 }
691
692 CAMLreturn(v_res);
693 }
694
695 /* Generic stub for getting integer results from pcre_config */
696 static inline int pcre_config_int(int what)
697 {
698 int ret;
699 pcre_config(what, (void *) &ret);
700 return ret;
701 }
702
703 /* Generic stub for getting long integer results from pcre_config */
704 static inline int pcre_config_long(int what)
705 {
706 long ret;
707 pcre_config(what, (void *) &ret);
708 return ret;
709 }
710
711 /* Some stubs for config-functions */
712
713 /* Returns boolean indicating UTF8-support */
714 CAMLprim value pcre_config_utf8_stub(value __unused v_unit)
715 { return Val_bool(pcre_config_int(PCRE_CONFIG_UTF8)); }
716
717 /* Returns character used as newline */
718 CAMLprim value pcre_config_newline_stub(value __unused v_unit)
719 { return Val_int(pcre_config_int(PCRE_CONFIG_NEWLINE)); }
720
721 /* Returns number of bytes used for internal linkage of regular expressions */
722 CAMLprim value pcre_config_link_size_stub(value __unused v_unit)
723 { return Val_int(pcre_config_int(PCRE_CONFIG_LINK_SIZE)); }
724
725 /* Returns boolean indicating use of stack recursion */
726 CAMLprim value pcre_config_stackrecurse_stub(value __unused v_unit)
727 { return Val_bool(pcre_config_int(PCRE_CONFIG_STACKRECURSE)); }
728
729 /* Returns default limit for calls to internal matching function */
730 CAMLprim value pcre_config_match_limit_stub(value __unused v_unit)
731 { return Val_long(pcre_config_long(PCRE_CONFIG_MATCH_LIMIT)); }
732
733 /* Returns default limit for calls to internal matching function */
734 CAMLprim value pcre_config_match_limit_recursion_stub(value __unused v_unit)
735 { return Val_long(pcre_config_long(PCRE_CONFIG_MATCH_LIMIT_RECURSION)); }
0 ALL_CFLAGS = $(CFLAGS) -I pcre2
1 LIBS =
2 OCAMLOPT=ocamlopt
3 OCAMLC=ocamlc
4 SRC = pcre2.ml pcre2_stubs.c
5
6 all: bytecode native
7
8 bytecode: pcre2.cma
9
10 native: pcre2.cmxa
11
12 pcre2.cma: pcre2_stubs.o pcre2.ml
13 $(OCAMLC) -safe-string -a -o pcre2.cma $(LIBS) pcre2.ml
14
15 pcre2.cmxa: pcre2.ml pcre2_stubs.o
16 $(OCAMLOPT) -safe-string -a -o pcre2.cmxa $(LIBS) pcre2.ml
17
18 pcre2_stubs.o: pcre2_stubs.c
19 $(OCAMLC) -safe-string $(ALL_CFLAGS) pcre2_stubs.c
20
21 clean:
22 rm -f pcre2.cma pcre2.cmi pcre2.cmx pcre2.cmxa pcre2.o pcre2.obj pcre2_stubs.obj pcre2_stubs.o
23 rm -f pcre2.a libpcre2-8.a libpcre2-8.lib pcre2.cmo
24
25 .PHONY: all bytecode native clean
26 Makefile: ;
27 $(SRC): ;
0 (include_subdirs no)
1
2 (library
3 (name pcre2)
4 (foreign_stubs
5 (language c)
6 (names pcre2_stubs))
7 (wrapped false)
8 )
0 (*
1 PCRE2-OCAML - Perl Compatibility Regular Expressions for OCaml
2
3 Copyright (C) 1999- Markus Mottl
4 email: markus.mottl@gmail.com
5 WWW: http://www.ocaml.info
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *)
21
22 (* Public exceptions and their registration with the C runtime *)
23
24 type error =
25 | Partial
26 | BadPattern of string * int
27 | BadUTF
28 | BadUTFOffset
29 | MatchLimit
30 | DepthLimit
31 | WorkspaceSize
32 | InternalError of string
33
34 exception Error of error
35 exception Backtrack
36 exception Regexp_or of string * error
37
38 (* Puts exceptions into global C-variables for fast retrieval *)
39 external pcre2_ocaml_init : unit -> unit = "pcre2_ocaml_init"
40
41 (* Registers exceptions with the C runtime and caches polymorphic variants *)
42 let () =
43 Callback.register_exception "Pcre2.Error" (Error (InternalError ""));
44 Callback.register_exception "Pcre2.Backtrack" Backtrack;
45 pcre2_ocaml_init ()
46
47
48 (* Compilation and runtime flags and their conversion functions *)
49
50 type icflag = int64
51 type irflag = int64
52
53 (* Compilation flags *)
54
55 type cflag =
56 [
57 | `ALLOW_EMPTY_CLASS
58 | `ALT_BSUX
59 | `ALT_CIRCUMFLEX
60 | `ALT_VERBNAMES
61 | `ANCHORED
62 | `AUTO_CALLOUT
63 | `CASELESS
64 | `DOLLAR_ENDONLY
65 | `DOTALL
66 | `DUPNAMES
67 | `ENDANCHORED
68 | `EXTENDED
69 | `EXTENDED_MORE
70 | `FIRSTLINE
71 | `LITERAL
72 | `MATCH_INVALID_UTF
73 | `MATCH_UNSET_BACKREF
74 | `MULTILINE
75 | `NEVER_BACKSLASH_C
76 | `NEVER_UCP
77 | `NEVER_UTF
78 | `NO_AUTO_CAPTURE
79 | `NO_AUTO_POSSESS
80 | `NO_DOTSTAR_ANCHOR
81 | `NO_START_OPTIMIZE
82 | `NO_UTF_CHECK
83 | `UCP
84 | `UNGREEDY
85 | `USE_OFFSET_LIMIT
86 | `UTF
87 ]
88
89 let int_of_cflag = function
90 | `ALLOW_EMPTY_CLASS -> 0x00000001L
91 | `ALT_BSUX -> 0x00000002L
92 | `AUTO_CALLOUT -> 0x00000004L
93 | `CASELESS -> 0x00000008L
94 | `DOLLAR_ENDONLY -> 0x00000010L
95 | `DOTALL -> 0x00000020L
96 | `DUPNAMES -> 0x00000040L
97 | `EXTENDED -> 0x00000080L
98 | `FIRSTLINE -> 0x00000100L
99 | `MATCH_UNSET_BACKREF -> 0x00000200L
100 | `MULTILINE -> 0x00000400L
101 | `NEVER_UCP -> 0x00000800L
102 | `NEVER_UTF -> 0x00001000L
103 | `NO_AUTO_CAPTURE -> 0x00002000L
104 | `NO_AUTO_POSSESS -> 0x00004000L
105 | `NO_DOTSTAR_ANCHOR -> 0x00008000L
106 | `NO_START_OPTIMIZE -> 0x00010000L
107 | `UCP -> 0x00020000L
108 | `UNGREEDY -> 0x00040000L
109 | `UTF -> 0x00080000L
110 | `NEVER_BACKSLASH_C -> 0x00100000L
111 | `ALT_CIRCUMFLEX -> 0x00200000L
112 | `ALT_VERBNAMES -> 0x00400000L
113 | `USE_OFFSET_LIMIT -> 0x00800000L
114 | `EXTENDED_MORE -> 0x01000000L
115 | `LITERAL -> 0x02000000L
116 | `MATCH_INVALID_UTF -> 0x04000000L
117 | `ENDANCHORED -> 0x20000000L
118 | `NO_UTF_CHECK -> 0x40000000L
119 | `ANCHORED -> 0x80000000L
120
121
122 let coll_icflag icflag flag = Int64.logor (int_of_cflag flag) icflag
123 let cflags flags = List.fold_left coll_icflag 0L flags
124
125 let cflag_of_int = function
126 | 0x00000001L -> `ALLOW_EMPTY_CLASS
127 | 0x00000002L -> `ALT_BSUX
128 | 0x00000004L -> `AUTO_CALLOUT
129 | 0x00000008L -> `CASELESS
130 | 0x00000010L -> `DOLLAR_ENDONLY
131 | 0x00000020L -> `DOTALL
132 | 0x00000040L -> `DUPNAMES
133 | 0x00000080L -> `EXTENDED
134 | 0x00000100L -> `FIRSTLINE
135 | 0x00000200L -> `MATCH_UNSET_BACKREF
136 | 0x00000400L -> `MULTILINE
137 | 0x00000800L -> `NEVER_UCP
138 | 0x00001000L -> `NEVER_UTF
139 | 0x00002000L -> `NO_AUTO_CAPTURE
140 | 0x00004000L -> `NO_AUTO_POSSESS
141 | 0x00008000L -> `NO_DOTSTAR_ANCHOR
142 | 0x00010000L -> `NO_START_OPTIMIZE
143 | 0x00020000L -> `UCP
144 | 0x00040000L -> `UNGREEDY
145 | 0x00080000L -> `UTF
146 | 0x00100000L -> `NEVER_BACKSLASH_C
147 | 0x00200000L -> `ALT_CIRCUMFLEX
148 | 0x00400000L -> `ALT_VERBNAMES
149 | 0x00800000L -> `USE_OFFSET_LIMIT
150 | 0x01000000L -> `EXTENDED_MORE
151 | 0x02000000L -> `LITERAL
152 | 0x04000000L -> `MATCH_INVALID_UTF
153 | 0x20000000L -> `ENDANCHORED
154 | 0x40000000L -> `NO_UTF_CHECK
155 | 0x80000000L -> `ANCHORED
156 | _ -> failwith "Pcre2.cflag_list: unknown compilation flag"
157
158 let all_cflags =
159 [
160 0x00000001L; 0x00000002L; 0x00000004L; 0x00000008L;
161 0x00000010L; 0x00000020L; 0x00000040L; 0x00000080L;
162 0x00000100L; 0x00000200L; 0x00000400L; 0x00000800L;
163 0x00001000L; 0x00002000L; 0x00004000L; 0x00008000L;
164 0x00010000L; 0x00020000L; 0x00040000L; 0x00080000L;
165 0x00100000L; 0x00200000L; 0x00400000L; 0x00800000L;
166 0x01000000L; 0x02000000L; 0x04000000L;
167 0x20000000L; 0x40000000L; 0x80000000L;
168 ]
169
170 let cflag_list icflags =
171 let coll flag_list flag =
172 if Int64.equal (Int64.logand icflags flag) 0L then flag_list
173 else cflag_of_int flag :: flag_list in
174 List.fold_left coll [] all_cflags
175
176
177 (* Runtime flags *)
178
179 type rflag =
180 [
181 | `ANCHORED
182 | `COPY_MATCHED_SUBJECT
183 | `DFA_RESTART
184 | `DFA_SHORTEST
185 | `ENDANCHORED
186 | `NOTBOL
187 | `NOTEOL
188 | `NOTEMPTY
189 | `NOTEMPTY_ATSTART
190 | `NO_JIT
191 | `NO_UTF_CHECK
192 | `PARTIAL_HARD
193 | `PARTIAL_SOFT
194 ]
195
196 let int_of_rflag = function
197 | `NOTBOL -> 0x00000001L
198 | `NOTEOL -> 0x00000002L
199 | `NOTEMPTY -> 0x00000004L
200 | `NOTEMPTY_ATSTART -> 0x00000008L
201 | `PARTIAL_SOFT -> 0x00000010L
202 | `PARTIAL_HARD -> 0x00000020L
203 | `DFA_RESTART -> 0x00000040L
204 | `DFA_SHORTEST -> 0x00000080L
205 | `NO_JIT -> 0x00002000L
206 | `COPY_MATCHED_SUBJECT -> 0x00004000L
207 | `ENDANCHORED -> 0x20000000L
208 | `NO_UTF_CHECK -> 0x40000000L
209 | `ANCHORED -> 0x80000000L
210
211 let coll_irflag irflag flag = Int64.logor (int_of_rflag flag) irflag
212 let rflags flags = List.fold_left coll_irflag 0L flags
213
214 let rflag_of_int = function
215 | 0x00000001L -> `NOTBOL
216 | 0x00000002L -> `NOTEOL
217 | 0x00000004L -> `NOTEMPTY
218 | 0x00000008L -> `NOTEMPTY_ATSTART
219 | 0x00000010L -> `PARTIAL_SOFT
220 | 0x00000020L -> `PARTIAL_HARD
221 | 0x00000040L -> `DFA_RESTART
222 | 0x00000080L -> `DFA_SHORTEST
223 | 0x00002000L -> `NO_JIT
224 | 0x00004000L -> `COPY_MATCHED_SUBJECT
225 | 0x20000000L -> `ENDANCHORED
226 | 0x40000000L -> `NO_UTF_CHECK
227 | 0x80000000L -> `ANCHORED
228 | _ -> failwith "Pcre2.rflag_list: unknown runtime flag"
229
230 let all_rflags =
231 [
232 0x00000001L; 0x00000002L; 0x00000004L; 0x00000008L;
233 0x00000010L; 0x00000020L; 0x00000040L; 0x00000080L;
234 0x00002000L; 0x00004000L;
235 0x20000000L; 0x40000000L; 0x80000000L;
236 ]
237
238 let rflag_list irflags =
239 let coll flag_list flag =
240 if Int64.equal (Int64.logand irflags flag) 0L then flag_list
241 else rflag_of_int flag :: flag_list in
242 List.fold_left coll [] all_rflags
243
244
245 (* Information on the PCRE2-configuration (build-time options) *)
246
247 external pcre2_version : unit -> string = "pcre2_version_stub"
248
249 external pcre2_config_unicode : unit -> bool
250 = "pcre2_config_unicode_stub" [@@noalloc]
251
252 external pcre2_config_newline : unit -> char
253 = "pcre2_config_newline_stub" [@@noalloc]
254
255 external pcre2_config_link_size : unit -> (int [@untagged])
256 = "pcre2_config_link_size_stub_bc" "pcre2_config_link_size_stub" [@@noalloc]
257
258 external pcre2_config_match_limit : unit -> (int [@untagged])
259 = "pcre2_config_match_limit_stub_bc" "pcre2_config_match_limit_stub"
260 [@@noalloc]
261
262 external pcre2_config_depth_limit : unit -> (int [@untagged])
263 = "pcre2_config_depth_limit_stub_bc" "pcre2_config_depth_limit_stub"
264 [@@noalloc]
265
266 external pcre2_config_stackrecurse :
267 unit -> bool = "pcre2_config_stackrecurse_stub" [@@noalloc]
268
269 let version = pcre2_version ()
270 let config_unicode = pcre2_config_unicode ()
271 let config_newline = pcre2_config_newline ()
272 let config_link_size = pcre2_config_link_size ()
273 let config_match_limit = pcre2_config_match_limit ()
274 let config_depth_limit = pcre2_config_depth_limit ()
275 let config_stackrecurse = pcre2_config_stackrecurse ()
276
277
278 (* Information on patterns *)
279
280 type firstcodeunit_info =
281 [ `Char of char
282 | `Start_only
283 | `ANCHORED ]
284
285 type regexp
286
287 external options : regexp -> (icflag [@unboxed])
288 = "pcre2_argoptions_stub_bc" "pcre2_argoptions_stub"
289
290 external size : regexp -> (int [@untagged])
291 = "pcre2_size_stub_bc" "pcre2_size_stub"
292
293 external capturecount : regexp -> (int [@untagged])
294 = "pcre2_capturecount_stub_bc" "pcre2_capturecount_stub"
295
296 external backrefmax : regexp -> (int [@untagged])
297 = "pcre2_backrefmax_stub_bc" "pcre2_backrefmax_stub"
298
299 external namecount : regexp -> (int [@untagged])
300 = "pcre2_namecount_stub_bc" "pcre2_namecount_stub"
301
302 external nameentrysize : regexp -> (int [@untagged])
303 = "pcre2_nameentrysize_stub_bc" "pcre2_nameentrysize_stub"
304
305 external names : regexp -> string array = "pcre2_names_stub"
306 external firstcodeunit : regexp -> firstcodeunit_info = "pcre2_firstcodeunit_stub"
307 external lastcodeunit : regexp -> char option = "pcre2_lastcodeunit_stub"
308
309 (* Compilation of patterns *)
310
311 type chtables
312
313 external maketables : unit -> chtables = "pcre2_maketables_stub"
314
315 external compile : (icflag [@unboxed]) -> chtables option -> string -> regexp
316 = "pcre2_compile_stub_bc" "pcre2_compile_stub"
317
318 (* external get_match_limit : regexp -> int option = "pcre2_get_match_limit_stub" *)
319
320 (* Internal use only! *)
321 external set_imp_match_limit : regexp -> (int [@untagged]) -> regexp
322 = "pcre2_set_imp_match_limit_stub_bc" "pcre2_set_imp_match_limit_stub"
323 [@@noalloc]
324
325 (* external get_depth_limit :
326 regexp -> int option = "pcre2_get_depth_limit_stub" *)
327
328 (* Internal use only! *)
329 external set_imp_depth_limit : regexp -> (int [@untagged]) -> regexp
330 = "pcre2_set_imp_depth_limit_stub_bc" "pcre2_set_imp_depth_limit_stub"
331 [@@noalloc]
332
333 (* TODO implement jit using new pcre2_jit_compile api *)
334 let regexp
335 (* ?(jit_compile = false) *)
336 ?limit ?depth_limit
337 ?(iflags = 0L) ?flags ?chtables pat =
338 let rex =
339 match flags with
340 | Some flag_list -> compile (cflags flag_list) chtables pat
341 | _ -> compile iflags chtables pat
342 in
343 let rex =
344 match limit with
345 | None -> rex
346 | Some lim -> set_imp_match_limit rex lim
347 in
348 match depth_limit with
349 | None -> rex
350 | Some lim -> set_imp_depth_limit rex lim
351
352 let regexp_or
353 (* ?jit_compile *) ?limit ?depth_limit ?(iflags = 0L) ?flags ?chtables pats =
354 let check pat =
355 try ignore (regexp ~iflags ?flags ?chtables pat)
356 with Error error -> raise (Regexp_or (pat, error))
357 in
358 List.iter check pats;
359 let big_pat =
360 let cnv pat = "(?:" ^ pat ^ ")" in
361 String.concat "|" (List.rev (List.rev_map cnv pats))
362 in
363 regexp (* ?jit_compile *) ?limit ?depth_limit ~iflags ?flags ?chtables big_pat
364
365 let bytes_unsafe_blit_string str str_ofs bts bts_ofs len =
366 let str_bts = Bytes.unsafe_of_string str in
367 Bytes.unsafe_blit str_bts str_ofs bts bts_ofs len
368
369 let string_unsafe_sub str ofs len =
370 let res = Bytes.create len in
371 bytes_unsafe_blit_string str ofs res 0 len;
372 Bytes.unsafe_to_string res
373
374 let quote s =
375 let len = String.length s in
376 let buf = Bytes.create (len lsl 1) in
377 let pos = ref 0 in
378 for i = 0 to len - 1 do
379 match String.unsafe_get s i with
380 | '\\' | '^' | '$' | '.' | '[' | '|'
381 | '(' | ')' | '?' | '*' | '+' | '{' as c ->
382 Bytes.unsafe_set buf !pos '\\';
383 incr pos;
384 Bytes.unsafe_set buf !pos c;
385 incr pos
386 | c -> Bytes.unsafe_set buf !pos c; incr pos
387 done;
388 string_unsafe_sub (Bytes.unsafe_to_string buf) 0 !pos
389
390
391 (* Matching of patterns and subpattern extraction *)
392
393 (* Default regular expression when none is provided by the user *)
394 let def_rex = regexp (* ~jit_compile:true *) "\\s+"
395
396 type substrings = string * int array
397
398 type callout_data =
399 {
400 callout_number : int;
401 substrings : substrings;
402 start_match : int;
403 current_position : int;
404 capture_top : int;
405 capture_last : int;
406 pattern_position : int;
407 next_item_length : int;
408 }
409
410 type callout = callout_data -> unit
411
412 let get_subject (subj, _) = subj
413
414 let num_of_subs (_, ovector) = Array.length ovector / 3
415
416 let get_offset_start ovector str_num =
417 if str_num < 0 || str_num >= Array.length ovector / 3 then
418 invalid_arg "Pcre2.get_offset_start: illegal offset";
419 let offset = str_num lsl 1 in
420 offset, Array.unsafe_get ovector offset
421
422 let get_substring_aux (subj, ovector) offset start =
423 if start < 0 then raise Not_found
424 else
425 string_unsafe_sub subj start (Array.unsafe_get ovector (offset + 1) - start)
426
427 let get_substring (_, ovector as substrings) str_num =
428 let offset, start = get_offset_start ovector str_num in
429 get_substring_aux substrings offset start
430
431 let get_substring_ofs (_subj, ovector) str_num =
432 let offset, start = get_offset_start ovector str_num in
433 if start < 0 then raise Not_found
434 else start, Array.unsafe_get ovector (offset + 1)
435
436 let unsafe_get_substring (_, ovector as substrings) str_num =
437 let offset = str_num lsl 1 in
438 try get_substring_aux substrings offset (Array.unsafe_get ovector offset)
439 with Not_found -> ""
440
441 let get_substrings ?(full_match = true) (_, ovector as substrings) =
442 if full_match then
443 Array.init (Array.length ovector / 3) (unsafe_get_substring substrings)
444 else
445 let len = (Array.length ovector / 3) - 1 in
446 Array.init len (fun n -> unsafe_get_substring substrings (n + 1))
447
448 let unsafe_get_opt_substring (_, ovector as substrings) str_num =
449 let offset = str_num lsl 1 in
450 try
451 let start = Array.unsafe_get ovector offset in
452 let str = get_substring_aux substrings offset start in
453 Some str
454 with Not_found -> None
455
456 let get_opt_substrings ?(full_match = true) (_, ovector as substrings) =
457 if full_match then
458 Array.init (Array.length ovector / 3) (unsafe_get_opt_substring substrings)
459 else
460 let len = (Array.length ovector / 3) - 1 in
461 Array.init len (fun n -> unsafe_get_opt_substring substrings (n + 1))
462
463 external get_stringnumber : regexp -> string -> (int [@untagged])
464 =
465 "pcre2_substring_number_from_name_stub_bc"
466 "pcre2_substring_number_from_name_stub"
467
468 let get_named_substring rex name substrings =
469 get_substring substrings (get_stringnumber rex name)
470
471 let get_named_substring_ofs rex name substrings =
472 get_substring_ofs substrings (get_stringnumber rex name)
473
474 external unsafe_pcre2_match :
475 (irflag [@unboxed]) ->
476 regexp ->
477 pos : (int [@untagged]) ->
478 subj_start : (int [@untagged]) ->
479 subj : string ->
480 int array ->
481 callout option ->
482 unit = "pcre2_match_stub_bc" "pcre2_match_stub"
483
484 let make_ovector rex =
485 let subgroups1 = capturecount rex + 1 in
486 let subgroups2 = subgroups1 lsl 1 in
487 subgroups2, Array.make (subgroups1 + subgroups2) 0
488
489 external unsafe_pcre2_dfa_match :
490 (irflag [@unboxed]) ->
491 regexp ->
492 pos : (int [@untagged]) ->
493 subj_start : (int [@untagged]) ->
494 subj : string ->
495 int array ->
496 callout option ->
497 workspace : int array ->
498 unit = "pcre2_dfa_match_stub_bc" "pcre2_match_stub0"
499
500 let pcre2_dfa_match ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
501 ?callout ?(workspace = Array.make 20 0) subj =
502 let rex = match pat with Some str -> regexp str | _ -> rex in
503 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
504 let _, ovector = make_ovector rex in
505 unsafe_pcre2_dfa_match
506 iflags rex ~pos ~subj_start:0 ~subj ovector callout ~workspace;
507 ovector
508
509 let pcre2_match ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
510 ?callout subj =
511 let rex = match pat with Some str -> regexp str | _ -> rex in
512 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
513 let _, ovector = make_ovector rex in
514 unsafe_pcre2_match iflags rex ~pos ~subj_start:0 ~subj ovector callout;
515 ovector
516
517 let exec ?iflags ?flags ?rex ?pat ?pos ?callout subj =
518 subj, pcre2_match ?iflags ?flags ?rex ?pat ?pos ?callout subj
519
520 let next_match ?iflags ?flags ?rex ?pat ?(pos = 0) ?callout (subj, ovector) =
521 let pos = Array.unsafe_get ovector 1 + pos in
522 let subj_len = String.length subj in
523 if pos < 0 || pos > subj_len then
524 invalid_arg "Pcre2.next_match: illegal offset";
525 subj, pcre2_match ?iflags ?flags ?rex ?pat ~pos ?callout subj
526
527 let rec copy_lst ar n = function
528 | [] -> ar
529 | h :: t -> Array.unsafe_set ar n h; copy_lst ar (n - 1) t
530
531 let exec_all ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?pos ?callout subj =
532 let rex = match pat with Some str -> regexp str | _ -> rex in
533 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
534 let (_, ovector as sstrs) = exec ~iflags ~rex ?pos ?callout subj in
535 let null_flags = Int64.logor iflags 0x00000004L in (* `NOTEMPTY *)
536 let subj_len = String.length subj in
537 let rec loop pos (subj, ovector as sstrs) n lst =
538 let maybe_ovector =
539 try
540 let first = Array.unsafe_get ovector 0 in
541 if first = pos && Array.unsafe_get ovector 1 = pos then
542 if pos = subj_len then None
543 else Some (pcre2_match ~iflags:null_flags ~rex ~pos ?callout subj)
544 else Some (pcre2_match ~iflags ~rex ~pos ?callout subj)
545 with Not_found -> None in
546 match maybe_ovector with
547 | Some ovector ->
548 let new_pos = Array.unsafe_get ovector 1 in
549 loop new_pos (subj, ovector) (n + 1) (sstrs :: lst)
550 | None -> copy_lst (Array.make (n + 1) sstrs) (n - 1) lst in
551 loop (Array.unsafe_get ovector 1) sstrs 0 []
552
553 let extract ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
554 get_substrings ?full_match (exec ?iflags ?flags ?rex ?pat ?pos ?callout subj)
555
556 let extract_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
557 get_opt_substrings
558 ?full_match (exec ?iflags ?flags ?rex ?pat ?pos ?callout subj)
559
560 let extract_all ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
561 let many_sstrs = exec_all ?iflags ?flags ?rex ?pat ?pos ?callout subj in
562 Array.map (get_substrings ?full_match) many_sstrs
563
564 let extract_all_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
565 let many_sstrs = exec_all ?iflags ?flags ?rex ?pat ?pos ?callout subj in
566 Array.map (get_opt_substrings ?full_match) many_sstrs
567
568 let pmatch ?iflags ?flags ?rex ?pat ?pos ?callout subj =
569 try ignore (pcre2_match ?iflags ?flags ?rex ?pat ?pos ?callout subj); true
570 with Not_found -> false
571
572
573 (* String substitution *)
574
575 (* Elements of a substitution pattern *)
576 type subst =
577 | SubstString of int * int (* Denotes a substring in the substitution *)
578 | Backref of int (* nth backreference ($0 is program name!) *)
579 | Match (* The whole matched string *)
580 | PreMatch (* The string before the match *)
581 | PostMatch (* The string after the match *)
582 | LastParenMatch (* The last matched group *)
583
584 (* Information on substitution patterns *)
585 type substitution = string (* The substitution string *)
586 * int (* Highest group number of backreferences *)
587 * bool (* Makes use of "LastParenMatch" *)
588 * subst list (* The list of substitution elements *)
589
590 (* Only used internally in "subst" *)
591 exception FoundAt of int
592
593 let zero = Char.code '0'
594
595 let subst str =
596 let max_br = ref 0 in
597 let with_lp = ref false in
598 let lix = String.length str - 1 in
599 let rec loop acc n =
600 if lix < n then acc
601 else
602 try
603 for i = n to lix do
604 if String.unsafe_get str i = '$' then raise (FoundAt i)
605 done;
606 SubstString (n, lix - n + 1) :: acc
607 with FoundAt i ->
608 if i = lix then SubstString (n, lix - n + 1) :: acc
609 else
610 let i1 = i + 1 in
611 let acc = if n = i then acc else SubstString (n, i - n) :: acc in
612 match String.unsafe_get str i1 with
613 | '0'..'9' as c ->
614 let subpat_nr = ref (Char.code c - zero) in
615 (try
616 for j = i1 + 1 to lix do
617 let c = String.unsafe_get str j in
618 if c >= '0' && c <= '9' then
619 subpat_nr := 10 * !subpat_nr + Char.code c - zero
620 else raise (FoundAt j)
621 done;
622 max_br := max !subpat_nr !max_br;
623 Backref !subpat_nr :: acc
624 with FoundAt j ->
625 max_br := max !subpat_nr !max_br;
626 loop (Backref !subpat_nr :: acc) j)
627 | '!' -> loop acc (i1 + 1)
628 | '$' -> loop (SubstString (i1, 1) :: acc) (i1 + 1)
629 | '&' -> loop (Match :: acc) (i1 + 1)
630 | '`' -> loop (PreMatch :: acc) (i1 + 1)
631 | '\'' -> loop (PostMatch :: acc) (i1 + 1)
632 | '+' ->
633 with_lp := true;
634 loop (LastParenMatch :: acc) (i1 + 1)
635 | _ -> loop acc i1 in
636 let subst_lst = loop [] 0 in
637 str, !max_br, !with_lp, subst_lst
638
639 let def_subst = subst ""
640
641 (* Calculates a list of tuples (str, offset, len) which contain
642 substrings to be copied on substitutions. Internal use only! *)
643 let calc_trans_lst subgroups2 ovector subj templ subst_lst =
644 let prefix_len = Array.unsafe_get ovector 0 in
645 let last = Array.unsafe_get ovector 1 in
646 let coll (res_len, trans_lst as accu) =
647 let return_lst (_str, _ix, len as el) =
648 if len = 0 then accu else res_len + len, el :: trans_lst in
649 function
650 | SubstString (ix, len) -> return_lst (templ, ix, len)
651 | Backref 0 ->
652 let prog_name = Sys.argv.(0) in
653 return_lst (prog_name, 0, String.length prog_name)
654 | Backref n ->
655 let offset = n lsl 1 in
656 let start = Array.unsafe_get ovector offset in
657 let len = Array.unsafe_get ovector (offset + 1) - start in
658 return_lst (subj, start, len)
659 | Match -> return_lst (subj, prefix_len, last - prefix_len)
660 | PreMatch -> return_lst (subj, 0, prefix_len)
661 | PostMatch -> return_lst (subj, last, String.length subj - last)
662 | LastParenMatch ->
663 let subgroups2_2 = subgroups2 - 2 in
664 let pos = ref subgroups2_2 in
665 let ix = ref (Array.unsafe_get ovector subgroups2_2) in
666 while !ix < 0 do
667 let pos_2 = !pos - 2 in
668 pos := pos_2;
669 ix := Array.unsafe_get ovector pos_2
670 done;
671 return_lst (subj, !ix, Array.unsafe_get ovector (!pos + 1) - !ix) in
672 List.fold_left coll (0, []) subst_lst
673
674 let replace ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat
675 ?(pos = 0) ?(itempl = def_subst) ?templ ?callout subj =
676 let rex = match pat with Some str -> regexp str | _ -> rex in
677 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
678 let templ, max_br, with_lp, subst_lst =
679 match templ with
680 | Some str -> subst str
681 | _ -> itempl in
682 let subj_len = String.length subj in
683 if pos < 0 || pos > subj_len then invalid_arg "Pcre2.replace: illegal offset";
684 let subgroups2, ovector = make_ovector rex in
685 let nsubs = (subgroups2 lsr 1) - 1 in
686 if max_br > nsubs then
687 failwith "Pcre2.replace: backreference denotes nonexistent subpattern";
688 if with_lp && nsubs = 0 then failwith "Pcre2.replace: no backreferences";
689 let rec loop full_len trans_lsts cur_pos =
690 if
691 cur_pos > subj_len ||
692 try
693 unsafe_pcre2_match
694 iflags rex ~pos:cur_pos ~subj_start:0 ~subj
695 ovector callout;
696 false
697 with Not_found -> true
698 then
699 let postfix_len = max (subj_len - cur_pos) 0 in
700 let left = pos + full_len in
701 let res = Bytes.create (left + postfix_len) in
702 bytes_unsafe_blit_string subj 0 res 0 pos;
703 bytes_unsafe_blit_string subj cur_pos res left postfix_len;
704 let inner_coll ofs (templ, ix, len) =
705 bytes_unsafe_blit_string templ ix res ofs len; ofs + len in
706 let coll ofs (res_len, trans_lst) =
707 let new_ofs = ofs - res_len in
708 let _ = List.fold_left inner_coll new_ofs trans_lst in
709 new_ofs in
710 let _ = List.fold_left coll left trans_lsts in
711 Bytes.unsafe_to_string res
712 else
713 let first = Array.unsafe_get ovector 0 in
714 let len = first - cur_pos in
715 let res_len, _ as trans_lst_el =
716 calc_trans_lst subgroups2 ovector subj templ subst_lst in
717 let trans_lsts =
718 if len > 0 then
719 trans_lst_el :: (len, [(subj, cur_pos, len)]) :: trans_lsts
720 else trans_lst_el :: trans_lsts in
721 let full_len = full_len + len + res_len in
722 let next = first + 1 in
723 let last = Array.unsafe_get ovector 1 in
724 if last < next then
725 if first < subj_len then
726 let new_trans_lsts = (1, [(subj, cur_pos + len, 1)]) :: trans_lsts in
727 loop (full_len + 1) new_trans_lsts next
728 else loop full_len trans_lsts next
729 else loop full_len trans_lsts last in
730 loop 0 [] pos
731
732 let qreplace ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat
733 ?(pos = 0) ?(templ = "") ?callout subj =
734 let rex = match pat with Some str -> regexp str | _ -> rex in
735 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
736 let subj_len = String.length subj in
737 if pos < 0 || pos > subj_len then invalid_arg "Pcre2.qreplace: illegal offset";
738 let templ_len = String.length templ in
739 let _, ovector = make_ovector rex in
740 let rec loop full_len subst_lst cur_pos =
741 if
742 cur_pos > subj_len ||
743 try
744 unsafe_pcre2_match
745 iflags rex ~pos:cur_pos ~subj_start:0 ~subj ovector callout;
746 false
747 with Not_found -> true
748 then
749 let postfix_len = max (subj_len - cur_pos) 0 in
750 let left = pos + full_len in
751 let res = Bytes.create (left + postfix_len) in
752 bytes_unsafe_blit_string subj 0 res 0 pos;
753 bytes_unsafe_blit_string subj cur_pos res left postfix_len;
754 let coll ofs = function
755 | Some (substr, ix, len) ->
756 let new_ofs = ofs - len in
757 bytes_unsafe_blit_string substr ix res new_ofs len;
758 new_ofs
759 | None ->
760 let new_ofs = ofs - templ_len in
761 bytes_unsafe_blit_string templ 0 res new_ofs templ_len;
762 new_ofs in
763 let _ = List.fold_left coll left subst_lst in
764 Bytes.unsafe_to_string res
765 else
766 let first = Array.unsafe_get ovector 0 in
767 let len = first - cur_pos in
768 let subst_lst =
769 if len > 0 then None :: Some (subj, cur_pos, len) :: subst_lst
770 else None :: subst_lst in
771 let last = Array.unsafe_get ovector 1 in
772 let full_len = full_len + len + templ_len in
773 let next = first + 1 in
774 if last < next then
775 if first < subj_len then
776 loop (full_len + 1) (Some (subj, cur_pos + len, 1) :: subst_lst) next
777 else loop full_len subst_lst next
778 else loop full_len subst_lst last in
779 loop 0 [] pos
780
781 let substitute_substrings ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat
782 ?(pos = 0) ?callout ~subst subj =
783 let rex = match pat with Some str -> regexp str | _ -> rex in
784 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
785 let subj_len = String.length subj in
786 if pos < 0 || pos > subj_len then invalid_arg "Pcre2.substitute: illegal offset";
787 let _, ovector = make_ovector rex in
788 let rec loop full_len subst_lst cur_pos =
789 if
790 cur_pos > subj_len ||
791 try
792 unsafe_pcre2_match
793 iflags rex ~pos:cur_pos ~subj_start:0 ~subj ovector callout;
794 false
795 with Not_found -> true
796 then
797 let postfix_len = max (subj_len - cur_pos) 0 in
798 let left = pos + full_len in
799 let res = Bytes.create (left + postfix_len) in
800 bytes_unsafe_blit_string subj 0 res 0 pos;
801 bytes_unsafe_blit_string subj cur_pos res left postfix_len;
802 let coll ofs (templ, ix, len) =
803 let new_ofs = ofs - len in
804 bytes_unsafe_blit_string templ ix res new_ofs len;
805 new_ofs in
806 let _ = List.fold_left coll left subst_lst in
807 Bytes.unsafe_to_string res
808 else
809 let first = Array.unsafe_get ovector 0 in
810 let len = first - cur_pos in
811 let templ = subst (subj, ovector) in
812 let templ_len = String.length templ in
813 let subst_lst =
814 if len > 0 then
815 (templ, 0, templ_len) :: (subj, cur_pos, len) :: subst_lst
816 else (templ, 0, templ_len) :: subst_lst in
817 let last = Array.unsafe_get ovector 1 in
818 let full_len = full_len + len + templ_len in
819 let next = first + 1 in
820 if last < next then
821 if first < subj_len then
822 loop (full_len + 1) ((subj, cur_pos + len, 1) :: subst_lst) next
823 else loop full_len subst_lst next
824 else loop full_len subst_lst last in
825 loop 0 [] pos
826
827 let substitute ?iflags ?flags ?rex ?pat ?pos ?callout ~subst:str_subst subj =
828 let subst (subj, ovector) =
829 let first = Array.unsafe_get ovector 0 in
830 let last = Array.unsafe_get ovector 1 in
831 str_subst (string_unsafe_sub subj first (last - first)) in
832 substitute_substrings ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj
833
834 let replace_first ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
835 ?(itempl = def_subst) ?templ ?callout subj =
836 let rex = match pat with Some str -> regexp str | _ -> rex in
837 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
838 let templ, max_br, with_lp, subst_lst =
839 match templ with
840 | Some str -> subst str
841 | _ -> itempl in
842 let subgroups2, ovector = make_ovector rex in
843 let nsubs = (subgroups2 lsr 1) - 1 in
844 if max_br > nsubs then
845 failwith "Pcre2.replace_first: backreference denotes nonexistent subpattern";
846 if with_lp && nsubs = 0 then failwith "Pcre2.replace_first: no backreferences";
847 try
848 unsafe_pcre2_match iflags rex ~pos ~subj_start:0 ~subj ovector callout;
849 let res_len, trans_lst =
850 calc_trans_lst subgroups2 ovector subj templ subst_lst in
851 let first = Array.unsafe_get ovector 0 in
852 let last = Array.unsafe_get ovector 1 in
853 let rest = String.length subj - last in
854 let res = Bytes.create (first + res_len + rest) in
855 bytes_unsafe_blit_string subj 0 res 0 first;
856 let coll ofs (templ, ix, len) =
857 bytes_unsafe_blit_string templ ix res ofs len; ofs + len in
858 let ofs = List.fold_left coll first trans_lst in
859 bytes_unsafe_blit_string subj last res ofs rest;
860 Bytes.unsafe_to_string res
861 with Not_found -> subj
862
863 let qreplace_first ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat
864 ?(pos = 0) ?(templ = "") ?callout subj =
865 let rex = match pat with Some str -> regexp str | _ -> rex in
866 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
867 let _, ovector = make_ovector rex in
868 try
869 unsafe_pcre2_match iflags rex ~pos ~subj_start:0 ~subj ovector callout;
870 let first = Array.unsafe_get ovector 0 in
871 let last = Array.unsafe_get ovector 1 in
872 let len = String.length templ in
873 let rest = String.length subj - last in
874 let postfix_start = first + len in
875 let res = Bytes.create (postfix_start + rest) in
876 bytes_unsafe_blit_string subj 0 res 0 first;
877 bytes_unsafe_blit_string templ 0 res first len;
878 bytes_unsafe_blit_string subj last res postfix_start rest;
879 Bytes.unsafe_to_string res
880 with Not_found -> subj
881
882 let substitute_substrings_first ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat
883 ?(pos = 0) ?callout ~subst subj =
884 let rex = match pat with Some str -> regexp str | _ -> rex in
885 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
886 let _, ovector = make_ovector rex in
887 try
888 unsafe_pcre2_match iflags rex ~pos ~subj_start:0 ~subj ovector callout;
889 let subj_len = String.length subj in
890 let prefix_len = Array.unsafe_get ovector 0 in
891 let last = Array.unsafe_get ovector 1 in
892 let templ = subst (subj, ovector) in
893 let postfix_len = subj_len - last in
894 let templ_len = String.length templ in
895 let postfix_start = prefix_len + templ_len in
896 let res = Bytes.create (postfix_start + postfix_len) in
897 bytes_unsafe_blit_string subj 0 res 0 prefix_len;
898 bytes_unsafe_blit_string templ 0 res prefix_len templ_len;
899 bytes_unsafe_blit_string subj last res postfix_start postfix_len;
900 Bytes.unsafe_to_string res
901 with Not_found -> subj
902
903 let substitute_first ?iflags ?flags ?rex ?pat ?pos
904 ?callout ~subst:str_subst subj =
905 let subst (subj, ovector) =
906 let first = Array.unsafe_get ovector 0 in
907 let last = Array.unsafe_get ovector 1 in
908 str_subst (string_unsafe_sub subj first (last - first)) in
909 substitute_substrings_first
910 ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj
911
912
913 (* Splitting *)
914
915 let internal_psplit flags rex max pos callout subj =
916 let subj_len = String.length subj in
917 if subj_len = 0 then []
918 else if max = 1 then [subj]
919 else
920 let subgroups2, ovector = make_ovector rex in
921
922 (* Adds contents of subgroups to the string accumulator *)
923 let handle_subgroups strs =
924 let strs = ref strs in
925 let i = ref 2 in
926 while !i < subgroups2 do
927 let first = Array.unsafe_get ovector !i in
928 incr i;
929 let last = Array.unsafe_get ovector !i in
930 let str =
931 if first < 0 then ""
932 else string_unsafe_sub subj first (last - first) in
933 strs := str :: !strs; incr i
934 done;
935 !strs in
936
937 (* Performs the recursive split *)
938 let rec loop strs cnt pos prematch =
939 let len = subj_len - pos in
940 if len < 0 then strs
941 else
942 (* Checks termination due to max restriction *)
943 if cnt = 0 then
944 if prematch &&
945 try
946 unsafe_pcre2_match
947 flags rex ~pos ~subj_start:pos ~subj ovector callout;
948 true
949 with Not_found -> false
950 then
951 let last = Array.unsafe_get ovector 1 in
952 let strs = handle_subgroups strs in
953 string_unsafe_sub subj last (subj_len - last) :: strs
954 else string_unsafe_sub subj pos len :: strs
955
956 (* Calculates next accumulator state for splitting *)
957 else
958 if
959 try
960 unsafe_pcre2_match
961 flags rex ~pos ~subj_start:pos ~subj ovector callout;
962 false
963 with Not_found -> true
964 then string_unsafe_sub subj pos len :: strs
965 else
966 let first = Array.unsafe_get ovector 0 in
967 let last = Array.unsafe_get ovector 1 in
968 if first = pos then
969 if last = pos then
970 let strs = if prematch then handle_subgroups strs else strs in
971 if len = 0 then "" :: strs
972 else if
973 try
974 unsafe_pcre2_match
975 (* `ANCHORED | `NOTEMPTY *)
976 (Int64.logor flags 0x80000004L) rex ~pos ~subj_start:pos ~subj
977 ovector callout;
978 true
979 with Not_found -> false
980 then
981 let new_strs = handle_subgroups ("" :: strs) in
982 loop new_strs (cnt - 1) (Array.unsafe_get ovector 1) false
983 else
984 let new_strs = string_unsafe_sub subj pos 1 :: strs in
985 loop new_strs (cnt - 1) (pos + 1) true
986 else
987 if prematch then loop (handle_subgroups strs) cnt last false
988 else loop (handle_subgroups ("" :: strs)) (cnt - 1) last false
989 else
990 let new_strs = string_unsafe_sub subj pos (first - pos) :: strs in
991 loop (handle_subgroups new_strs) (cnt - 1) last false in
992 loop [] (max - 1) pos false
993
994 let rec strip_all_empty = function "" :: t -> strip_all_empty t | l -> l
995
996 external isspace : char -> bool = "pcre2_isspace_stub" [@@noalloc]
997
998 let rec find_no_space ix len str =
999 if ix = len || not (isspace (String.unsafe_get str ix)) then ix
1000 else find_no_space (ix + 1) len str
1001
1002 let split ?(iflags = 0L) ?flags ?rex ?pat ?(pos = 0) ?(max = 0) ?callout subj =
1003 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
1004 let res =
1005 match pat, rex with
1006 | Some str, _ -> internal_psplit iflags (regexp str) max pos callout subj
1007 | _, Some rex -> internal_psplit iflags rex max pos callout subj
1008 | _ ->
1009 (* special case for Perl-splitting semantics *)
1010 let len = String.length subj in
1011 if pos > len || pos < 0 then failwith "Pcre2.split: illegal offset";
1012 let new_pos = find_no_space pos len subj in
1013 internal_psplit iflags def_rex max new_pos callout subj in
1014 List.rev (if max = 0 then strip_all_empty res else res)
1015
1016 let asplit ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj =
1017 Array.of_list (split ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj)
1018
1019
1020 (* Full splitting *)
1021
1022 type split_result = Text of string
1023 | Delim of string
1024 | Group of int * string
1025 | NoGroup
1026
1027 let rec strip_all_empty_full = function
1028 | Delim _ :: rest -> strip_all_empty_full rest
1029 | l -> l
1030
1031 let full_split ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat
1032 ?(pos = 0) ?(max = 0) ?callout subj =
1033 let rex = match pat with Some str -> regexp str | _ -> rex in
1034 let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
1035 let subj_len = String.length subj in
1036 if subj_len = 0 then []
1037 else if max = 1 then [Text (subj)]
1038 else
1039 let subgroups2, ovector = make_ovector rex in
1040
1041 (* Adds contents of subgroups to the string accumulator *)
1042 let handle_subgroups strs =
1043 let strs = ref strs in
1044 let i = ref 2 in
1045 while !i < subgroups2 do
1046 let group_nr = !i lsr 1 in
1047 let first = Array.unsafe_get ovector !i in
1048 incr i;
1049 let last = Array.unsafe_get ovector !i in
1050 let str =
1051 if first < 0 then NoGroup
1052 else
1053 let group_str = string_unsafe_sub subj first (last - first) in
1054 Group (group_nr, group_str) in
1055 strs := str :: !strs; incr i
1056 done;
1057 !strs in
1058
1059 (* Performs the recursive split *)
1060 let rec loop strs cnt pos prematch =
1061 let len = subj_len - pos in
1062 if len < 0 then strs
1063 else
1064 (* Checks termination due to max restriction *)
1065 if cnt = 0 then
1066 if prematch &&
1067 try
1068 unsafe_pcre2_match
1069 iflags rex ~pos ~subj_start:pos ~subj ovector callout;
1070 true
1071 with Not_found -> false
1072 then
1073 let first = Array.unsafe_get ovector 0 in
1074 let last = Array.unsafe_get ovector 1 in
1075 let delim = Delim (string_unsafe_sub subj first (last - first)) in
1076 Text (string_unsafe_sub subj last (subj_len - last))
1077 :: handle_subgroups (delim :: strs)
1078 else
1079 if len = 0 then strs
1080 else Text (string_unsafe_sub subj pos len) :: strs
1081
1082 (* Calculates next accumulator state for splitting *)
1083 else
1084 if
1085 try
1086 unsafe_pcre2_match
1087 iflags rex ~pos ~subj_start:pos ~subj ovector callout;
1088 false
1089 with Not_found -> true
1090 then
1091 if len = 0 then strs
1092 else Text (string_unsafe_sub subj pos len) :: strs
1093 else
1094 let first = Array.unsafe_get ovector 0 in
1095 let last = Array.unsafe_get ovector 1 in
1096 if first = pos then
1097 if last = pos then
1098 if len = 0 then handle_subgroups (Delim "" :: strs)
1099 else
1100 let empty_groups = handle_subgroups [] in
1101 if
1102 try
1103 unsafe_pcre2_match
1104 (* `ANCHORED | `NOTEMPTY *)
1105 (Int64.logor iflags 0x80000004L) rex ~pos ~subj_start:pos ~subj
1106 ovector callout;
1107 true
1108 with Not_found -> false
1109 then
1110 let first = Array.unsafe_get ovector 0 in
1111 let last = Array.unsafe_get ovector 1 in
1112 let delim =
1113 Delim (string_unsafe_sub subj first (last - first)) in
1114 let new_strs =
1115 handle_subgroups (
1116 delim :: (if prematch then strs
1117 else empty_groups @ (Delim "" :: strs))) in
1118 loop new_strs (cnt - 1) last false
1119 else
1120 let new_strs =
1121 Text (string_unsafe_sub subj pos 1)
1122 :: empty_groups @ Delim "" :: strs in
1123 loop new_strs (cnt - 1) (pos + 1) true
1124 else
1125 let delim =
1126 Delim (string_unsafe_sub subj first (last - first)) in
1127 loop (handle_subgroups (delim :: strs)) cnt last false
1128 else
1129 let delim = Delim (string_unsafe_sub subj first (last - first)) in
1130 let pre_strs =
1131 Text (string_unsafe_sub subj pos (first - pos)) :: strs in
1132 loop
1133 (handle_subgroups (delim :: pre_strs)) (cnt - 1) last false in
1134 let res = loop [] (max - 1) pos true in
1135 List.rev (if max = 0 then strip_all_empty_full res else res)
1136
1137
1138 (* Additional convenience functions useful in combination with this library *)
1139
1140 let foreach_line ?(ic = stdin) f =
1141 try while true do f (input_line ic) done with End_of_file -> ()
1142
1143 let foreach_file filenames f =
1144 let do_with_file filename =
1145 let file = open_in filename in
1146 try f filename file; close_in file
1147 with exn -> close_in file; raise exn in
1148 List.iter do_with_file filenames
0 /*
1 PCRE2-OCAML - Perl Compatibility Regular Expressions for OCaml
2
3 Copyright (C) 1999- Markus Mottl
4 email: markus.mottl@gmail.com
5 WWW: http://www.ocaml.info
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #if defined(_WIN32)
23 # define snprintf _snprintf
24 # if defined(_DLL)
25 # define PCREextern __declspec(dllexport)
26 # else
27 # define PCREextern
28 # endif
29 #endif
30
31 #if _WIN64
32 typedef long long *caml_int_ptr;
33 #else
34 typedef long *caml_int_ptr;
35 #endif
36
37 #if __GNUC__ >= 3
38 # define __unused __attribute__ ((unused))
39 #else
40 # define __unused
41 #endif
42
43 #include <ctype.h>
44 #include <string.h>
45 #include <stdio.h>
46
47 #include <caml/mlvalues.h>
48 #include <caml/alloc.h>
49 #include <caml/memory.h>
50 #include <caml/fail.h>
51 #include <caml/callback.h>
52 #include <caml/custom.h>
53
54 #define PCRE2_CODE_UNIT_WIDTH 8
55
56 #include <pcre2.h>
57
58 typedef const unsigned char *chartables; /* Type of chartable sets */
59
60 /* Contents of callout data */
61 struct cod {
62 long subj_start; /* Start of subject string */
63 value *v_substrings_p; /* Pointer to substrings matched so far */
64 value *v_cof_p; /* Pointer to callout function */
65 value v_exn; /* Possible exception raised by callout function */
66 };
67
68 /* Cache for exceptions */
69 static const value *pcre2_exc_Error = NULL; /* Exception [Error] */
70 static const value *pcre2_exc_Backtrack = NULL; /* Exception [Backtrack] */
71
72 /* Cache for polymorphic variants */
73 static value var_Start_only; /* Variant [`Start_only] */
74 static value var_ANCHORED; /* Variant [`ANCHORED] */
75 static value var_Char; /* Variant [`Char char] */
76
77 static value None = Val_int(0);
78
79 /* Data associated with OCaml values of PCRE regular expression */
80 struct pcre2_ocaml_regexp { pcre2_code *rex; pcre2_match_context *mcontext; };
81
82 #define Pcre2_ocaml_regexp_val(v) \
83 ((struct pcre2_ocaml_regexp *) Data_custom_val(v))
84
85 #define get_rex(v) Pcre2_ocaml_regexp_val(v)->rex
86 #define get_mcontext(v) Pcre2_ocaml_regexp_val(v)->mcontext
87
88 #define set_rex(v, r) Pcre2_ocaml_regexp_val(v)->rex = r
89 #define set_mcontext(v, c) Pcre2_ocaml_regexp_val(v)->mcontext = c
90
91 /* Data associated with OCaml values of PCRE tables */
92 struct pcre2_ocaml_tables { chartables tables; };
93
94 #define Pcre2_ocaml_tables_val(v) \
95 ((struct pcre2_ocaml_tables *) Data_custom_val(v))
96
97 #define get_tables(v) Pcre2_ocaml_tables_val(v)->tables
98 #define set_tables(v, t) Pcre2_ocaml_tables_val(v)->tables = t
99
100 /* Converts subject offsets from C-integers to OCaml-Integers.
101
102 This is a bit tricky, because there are 32- and 64-bit platforms around
103 and OCaml chooses the larger possibility for representing integers when
104 available (also in arrays) - not so the PCRE!
105 */
106 static inline void copy_ovector(
107 long subj_start, const size_t* ovec_src, caml_int_ptr ovec_dst, uint32_t subgroups2)
108 {
109 if (subj_start == 0)
110 while (subgroups2--) {
111 *ovec_dst = Val_int(*ovec_src);
112 --ovec_src; --ovec_dst;
113 }
114 else
115 while (subgroups2--) {
116 *ovec_dst = Val_long(*ovec_src + subj_start);
117 --ovec_src; --ovec_dst;
118 }
119 }
120
121 /* Callout handler */
122 static int pcre2_callout_handler(pcre2_callout_block* cb, struct cod* cod)
123 {
124 if (cod != NULL) {
125 /* Callout is available */
126 value v_res;
127
128 /* Set up parameter array */
129 value v_callout_data = caml_alloc_small(8, 0);
130
131 const value v_substrings = *cod->v_substrings_p;
132
133 const uint32_t capture_top = cb->capture_top;
134 uint32_t subgroups2 = capture_top << 1;
135 const uint32_t subgroups2_1 = subgroups2 - 1;
136
137 const size_t *ovec_src = cb->offset_vector + subgroups2_1;
138 caml_int_ptr ovec_dst = &Field(Field(v_substrings, 1), 0) + subgroups2_1;
139 long subj_start = cod->subj_start;
140
141 copy_ovector(subj_start, ovec_src, ovec_dst, subgroups2);
142
143 Field(v_callout_data, 0) = Val_int(cb->callout_number);
144 Field(v_callout_data, 1) = v_substrings;
145 Field(v_callout_data, 2) = Val_int(cb->start_match + subj_start);
146 Field(v_callout_data, 3) = Val_int(cb->current_position + subj_start);
147 Field(v_callout_data, 4) = Val_int(capture_top);
148 Field(v_callout_data, 5) = Val_int(cb->capture_last);
149 Field(v_callout_data, 6) = Val_int(cb->pattern_position);
150 Field(v_callout_data, 7) = Val_int(cb->next_item_length);
151
152 /* Perform callout */
153 v_res = caml_callback_exn(*cod->v_cof_p, v_callout_data);
154
155 if (Is_exception_result(v_res)) {
156 /* Callout raised an exception */
157 const value v_exn = Extract_exception(v_res);
158 if (Field(v_exn, 0) == *pcre2_exc_Backtrack) return 1;
159 cod->v_exn = v_exn;
160 return PCRE2_ERROR_CALLOUT;
161 }
162 }
163
164 return 0;
165 }
166
167 /* Fetches the named OCaml-values + caches them and
168 calculates + caches the variant hash values */
169 CAMLprim value pcre2_ocaml_init(value __unused v_unit)
170 {
171 pcre2_exc_Error = caml_named_value("Pcre2.Error");
172 pcre2_exc_Backtrack = caml_named_value("Pcre2.Backtrack");
173
174 var_Start_only = caml_hash_variant("Start_only");
175 var_ANCHORED = caml_hash_variant("ANCHORED");
176 var_Char = caml_hash_variant("Char");
177
178 return Val_unit;
179 }
180
181 /* Finalizing deallocation function for chartable sets */
182 static void pcre2_dealloc_tables(value v_tables)
183 {
184 #if PCRE2_MINOR >= 34
185 pcre2_maketables_free(NULL, get_tables(v_tables));
186 #else
187 free((void*)get_tables(v_tables));
188 #endif
189 }
190
191 /* Finalizing deallocation function for compiled regular expressions */
192 static void pcre2_dealloc_regexp(value v_rex)
193 {
194 pcre2_code_free(get_rex(v_rex));
195 pcre2_match_context_free(get_mcontext(v_rex));
196 }
197
198
199 /* Raising exceptions */
200
201 CAMLnoreturn_start
202 static inline void raise_pcre2_error(value v_arg)
203 CAMLnoreturn_end;
204
205 CAMLnoreturn_start
206 static inline void raise_partial()
207 CAMLnoreturn_end;
208
209 CAMLnoreturn_start
210 static inline void raise_bad_utf()
211 CAMLnoreturn_end;
212
213 CAMLnoreturn_start
214 static inline void raise_bad_utf_offset()
215 CAMLnoreturn_end;
216
217 CAMLnoreturn_start
218 static inline void raise_match_limit()
219 CAMLnoreturn_end;
220
221 CAMLnoreturn_start
222 static inline void raise_depth_limit()
223 CAMLnoreturn_end;
224
225 CAMLnoreturn_start
226 static inline void raise_workspace_size()
227 CAMLnoreturn_end;
228
229 CAMLnoreturn_start
230 static inline void raise_bad_pattern(int code, size_t pos)
231 CAMLnoreturn_end;
232
233 CAMLnoreturn_start
234 static inline void raise_internal_error(char *msg)
235 CAMLnoreturn_end;
236
237 static inline void raise_pcre2_error(value v_arg)
238 { caml_raise_with_arg(*pcre2_exc_Error, v_arg); }
239
240 static inline void raise_partial() { raise_pcre2_error(Val_int(0)); }
241 static inline void raise_bad_utf() { raise_pcre2_error(Val_int(1)); }
242 static inline void raise_bad_utf_offset() { raise_pcre2_error(Val_int(2)); }
243 static inline void raise_match_limit() { raise_pcre2_error(Val_int(3)); }
244 static inline void raise_depth_limit() { raise_pcre2_error(Val_int(4)); }
245 static inline void raise_workspace_size() { raise_pcre2_error(Val_int(5)); }
246
247 static inline void raise_bad_pattern(int code, size_t pos)
248 {
249 CAMLparam0();
250 CAMLlocal1(v_msg);
251 value v_arg;
252 v_msg = caml_alloc_string(128);
253 pcre2_get_error_message(code, (PCRE2_UCHAR *)String_val(v_msg), 128);
254 v_arg = caml_alloc_small(2, 0);
255 Field(v_arg, 0) = v_msg;
256 Field(v_arg, 1) = Val_int(pos);
257 raise_pcre2_error(v_arg);
258 CAMLnoreturn;
259 }
260
261 static inline void raise_internal_error(char *msg)
262 {
263 CAMLparam0();
264 CAMLlocal1(v_msg);
265 value v_arg;
266 v_msg = caml_copy_string(msg);
267 v_arg = caml_alloc_small(1, 1);
268 Field(v_arg, 0) = v_msg;
269 raise_pcre2_error(v_arg);
270 CAMLnoreturn;
271 }
272
273 /* PCRE pattern compilation */
274
275 static struct custom_operations regexp_ops = {
276 "pcre2_ocaml_regexp",
277 pcre2_dealloc_regexp,
278 custom_compare_default,
279 custom_hash_default,
280 custom_serialize_default,
281 custom_deserialize_default,
282 custom_compare_ext_default
283 };
284
285 /* Makes compiled regular expression from compilation options, an optional
286 value of chartables and the pattern string */
287
288 CAMLprim value pcre2_compile_stub(int64_t v_opt, value v_tables, value v_pat)
289 {
290 value v_rex; /* Final result -> value of type [regexp] */
291 int error_code = 0; /* error code for potential error */
292 size_t error_ofs = 0; /* offset in the pattern at which error occurred */
293 size_t length = caml_string_length(v_pat);
294
295 pcre2_compile_context* ccontext = NULL;
296 /* If v_tables = [None], then pointer to tables is NULL, otherwise
297 set it to the appropriate value */
298 if (v_tables != None) {
299 ccontext = pcre2_compile_context_create(NULL);
300 pcre2_set_character_tables(ccontext, get_tables(Field(v_tables, 0)));
301 }
302
303 /* Compiles the pattern */
304 pcre2_code* regexp = pcre2_compile((PCRE2_SPTR)String_val(v_pat), length, v_opt,
305 &error_code, &error_ofs, ccontext);
306
307 pcre2_compile_context_free(ccontext);
308
309 /* Raises appropriate exception with [BadPattern] if the pattern
310 could not be compiled */
311 if (regexp == NULL) raise_bad_pattern(error_code, error_ofs);
312
313 /* GC will do a full cycle every 1_000_000 regexp allocations (a typical
314 regexp probably consumes less than 100 bytes -> maximum of 100_000_000
315 bytes unreclaimed regexps) */
316 v_rex =
317 caml_alloc_custom(&regexp_ops,
318 sizeof(struct pcre2_ocaml_regexp), 1, 1000000);
319
320 set_rex(v_rex, regexp);
321 set_mcontext(v_rex, pcre2_match_context_create(NULL));
322
323 return v_rex;
324 }
325
326 CAMLprim value pcre2_compile_stub_bc(value v_opt, value v_tables, value v_pat)
327 {
328 return pcre2_compile_stub(Long_val(v_opt), v_tables, v_pat);
329 }
330
331 /* Gets the depth limit of a regular expression if it exists */
332 /* CAMLprim value pcre2_get_depth_limit_stub(value v_rex); */
333
334 /* Gets the match limit of a regular expression if it exists */
335 /* CAMLprim value pcre2_get_match_limit_stub(value v_rex); */
336
337
338 /* Sets a match limit for a regular expression imperatively */
339
340 CAMLprim value pcre2_set_imp_match_limit_stub(value v_rex, value v_lim) {
341 pcre2_match_context* mcontext = get_mcontext(v_rex);
342 pcre2_set_match_limit(mcontext, v_lim);
343 return v_rex;
344 }
345
346 CAMLprim value pcre2_set_imp_match_limit_stub_bc(value v_rex, value v_lim)
347 {
348 return pcre2_set_imp_match_limit_stub(v_rex, Int_val(v_lim));
349 }
350
351
352 /* Sets a depth limit for a regular expression imperatively */
353
354 CAMLprim value pcre2_set_imp_depth_limit_stub(value v_rex, intnat v_lim) {
355 pcre2_match_context* mcontext = get_mcontext(v_rex);
356 pcre2_set_depth_limit(mcontext, v_lim);
357 return v_rex;
358 }
359
360 CAMLprim value pcre2_set_imp_depth_limit_stub_bc(value v_rex, value v_lim)
361 {
362 return pcre2_set_imp_depth_limit_stub(v_rex, Int_val(v_lim));
363 }
364
365
366 /* Performs the call to the pcre2_pattern_info function */
367 static inline int pcre2_pattern_info_stub(value v_rex, int what, void* where)
368 {
369 return pcre2_pattern_info(get_rex(v_rex), what, where);
370 }
371
372 /* Some stubs for info-functions */
373
374 /* Generic macro for getting integer results from pcre2_pattern_info */
375 #define make_intnat_info(tp, name, option) \
376 CAMLprim intnat pcre2_##name##_stub(value v_rex) \
377 { \
378 tp options; \
379 const int ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_##option, &options); \
380 if (ret != 0) raise_internal_error("pcre2_##name##_stub"); \
381 return options; \
382 } \
383 \
384 CAMLprim value pcre2_##name##_stub_bc(value v_rex) \
385 { return Val_int(pcre2_##name##_stub(v_rex)); }
386
387 make_intnat_info(size_t, size, SIZE)
388 make_intnat_info(int, capturecount, CAPTURECOUNT)
389 make_intnat_info(int, backrefmax, BACKREFMAX)
390 make_intnat_info(int, namecount, NAMECOUNT)
391 make_intnat_info(int, nameentrysize, NAMEENTRYSIZE)
392
393 CAMLprim int64_t pcre2_argoptions_stub(value v_rex)
394 {
395 uint32_t options;
396 const int ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_ARGOPTIONS, &options);
397 if (ret != 0) raise_internal_error("pcre2_##name##_stub");
398 return (int64_t)options;
399 }
400
401 CAMLprim value pcre2_argoptions_stub_bc(value v_rex)
402 { return Val_long(pcre2_argoptions_stub(v_rex)); }
403
404 CAMLprim value pcre2_firstcodeunit_stub(value v_rex)
405 {
406 uint32_t firstcodetype;
407 const int ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_FIRSTCODETYPE, &firstcodetype);
408
409 if (ret != 0) raise_internal_error("pcre2_firstcodeunit_stub");
410
411 switch (firstcodetype) {
412 case 2 : return var_Start_only; break; /* [`Start_only] */
413 case 0 : return var_ANCHORED; break; /* [`ANCHORED] */
414 case 1: {
415 uint32_t firstcodeunit;
416 const int ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_FIRSTCODEUNIT, &firstcodeunit);
417 if (ret != 0) raise_internal_error("pcre2_firstcodeunit_stub");
418
419 value v_firstbyte;
420 /* Allocates the non-constant constructor [`Char of char] and fills
421 in the appropriate value */
422 v_firstbyte = caml_alloc_small(2, 0);
423 Field(v_firstbyte, 0) = var_Char;
424 Field(v_firstbyte, 1) = Val_int(firstcodeunit);
425
426 return v_firstbyte;
427 break;
428 }
429 default: /* Should not happen */
430 raise_internal_error("pcre2_firstcodeunit_stub");
431 }
432 }
433
434 CAMLprim value pcre2_lastcodeunit_stub(value v_rex)
435 {
436 uint32_t lastcodetype;
437 const int ret =
438 pcre2_pattern_info_stub(v_rex, PCRE2_INFO_LASTCODETYPE, &lastcodetype);
439
440 if (ret != 0) raise_internal_error("pcre2_lastcodeunit_stub");
441
442 if (lastcodetype == 0) return None;
443 if (lastcodetype != 1) raise_internal_error("pcre2_lastcodeunit_stub");
444 else {
445 /* Allocates [Some char] */
446 value v_res = caml_alloc_small(1, 0);
447 uint32_t lastcodeunit;
448 const int ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_LASTCODEUNIT, &lastcodeunit);
449 if (ret != 0) raise_internal_error("pcre2_lastcodeunit_stub");
450 Field(v_res, 0) = Val_int(lastcodeunit);
451 return v_res;
452 }
453 }
454
455 CAMLnoreturn_start
456 static inline void handle_match_error(char *loc, const int ret)
457 CAMLnoreturn_end;
458
459 static inline void handle_match_error(char *loc, const int ret)
460 {
461 switch (ret) {
462 /* Dedicated exceptions */
463 case PCRE2_ERROR_NOMATCH : caml_raise_not_found();
464 case PCRE2_ERROR_PARTIAL : raise_partial();
465 case PCRE2_ERROR_MATCHLIMIT : raise_match_limit();
466 case PCRE2_ERROR_BADUTFOFFSET : raise_bad_utf_offset();
467 case PCRE2_ERROR_DEPTHLIMIT : raise_depth_limit();
468 case PCRE2_ERROR_DFA_WSSIZE : raise_workspace_size();
469 default : {
470 if (PCRE2_ERROR_UTF8_ERR21 <= ret && ret <= PCRE2_ERROR_UTF8_ERR1)
471 raise_bad_utf();
472 /* Unknown error */
473 char err_buf[100];
474 snprintf(err_buf, 100, "%s: unhandled PCRE2 error code: %d", loc, ret);
475 raise_internal_error(err_buf);
476 }
477 }
478 }
479
480 static inline void handle_pcre2_match_result(
481 size_t *ovec, value v_ovec, size_t ovec_len, long subj_start, uint32_t ret)
482 {
483 caml_int_ptr ocaml_ovec = (caml_int_ptr) &Field(v_ovec, 0);
484 const uint32_t subgroups2 = ret * 2;
485 const uint32_t subgroups2_1 = subgroups2 - 1;
486 const size_t *ovec_src = ovec + subgroups2_1;
487 caml_int_ptr ovec_clear_stop = ocaml_ovec + (ovec_len * 2) / 3;
488 caml_int_ptr ovec_dst = ocaml_ovec + subgroups2_1;
489 copy_ovector(subj_start, ovec_src, ovec_dst, subgroups2);
490 while (++ovec_dst < ovec_clear_stop) *ovec_dst = -1;
491 }
492
493 /* Executes a pattern match with runtime options, a regular expression, a
494 matching position, the start of the the subject string, a subject string,
495 a number of subgroup offsets, an offset vector and an optional callout
496 function */
497
498 CAMLprim value pcre2_match_stub0(
499 int64_t v_opt, value v_rex, intnat v_pos, intnat v_subj_start, value v_subj,
500 value v_ovec, value v_maybe_cof, value v_workspace)
501 {
502 int ret;
503 int is_dfa = v_workspace != (value) NULL;
504 long
505 pos = v_pos,
506 subj_start = v_subj_start;
507 size_t
508 ovec_len = Wosize_val(v_ovec),
509 len = caml_string_length(v_subj);
510
511 if (pos > (long)len || pos < subj_start)
512 caml_invalid_argument("Pcre2.pcre2_match_stub: illegal position");
513
514 if (subj_start > (long)len || subj_start < 0)
515 caml_invalid_argument("Pcre2.pcre2_match_stub: illegal subject start");
516
517 pos -= subj_start;
518 len -= subj_start;
519
520 {
521 const pcre2_code *code = get_rex(v_rex); /* Compiled pattern */
522 pcre2_match_context* mcontext = get_mcontext(v_rex); /* Match context */
523 PCRE2_SPTR ocaml_subj = (PCRE2_SPTR)String_val(v_subj) + subj_start; /* Subject string */
524
525 pcre2_match_data* match_data = pcre2_match_data_create_from_pattern(code, NULL);
526
527 /* Special case when no callout functions specified */
528 if (v_maybe_cof == None) {
529 /* Performs the match */
530 if (is_dfa)
531 ret =
532 pcre2_dfa_match(code, ocaml_subj, len, pos, v_opt, match_data, mcontext,
533 (int *) &Field(v_workspace, 0), Wosize_val(v_workspace));
534 else
535 ret = pcre2_match(code, ocaml_subj, len, pos, v_opt, match_data, mcontext);
536
537 size_t *ovec = pcre2_get_ovector_pointer(match_data);
538
539 if (ret < 0) {
540 pcre2_match_data_free(match_data);
541 handle_match_error("pcre2_match_stub", ret);
542 } else {
543 handle_pcre2_match_result(ovec, v_ovec, ovec_len, subj_start, ret);
544 }
545 }
546
547 /* There are callout functions */
548 else {
549 value v_cof = Field(v_maybe_cof, 0);
550 value v_substrings;
551 PCRE2_UCHAR* subj = caml_stat_alloc(sizeof(char) * len);
552 int workspace_len;
553 int *workspace;
554 struct cod cod = { 0, (value *) NULL, (value *) NULL, (value) NULL };
555 pcre2_match_context* new_mcontext = pcre2_match_context_copy(mcontext);
556
557 pcre2_set_callout(new_mcontext, (int (*)(pcre2_callout_block_8*, void*))&pcre2_callout_handler, &cod);
558
559 cod.subj_start = subj_start;
560 memcpy(subj, ocaml_subj, len);
561
562 Begin_roots4(v_rex, v_cof, v_substrings, v_ovec);
563 Begin_roots1(v_subj);
564 v_substrings = caml_alloc_small(2, 0);
565 End_roots();
566
567 Field(v_substrings, 0) = v_subj;
568 Field(v_substrings, 1) = v_ovec;
569
570 cod.v_substrings_p = &v_substrings;
571 cod.v_cof_p = &v_cof;
572
573 if (is_dfa) {
574 workspace_len = Wosize_val(v_workspace);
575 workspace = caml_stat_alloc(sizeof(int) * workspace_len);
576 ret =
577 pcre2_dfa_match(code, subj, len, pos, v_opt, match_data, new_mcontext,
578 (int *) &Field(v_workspace, 0), workspace_len);
579 } else
580 ret =
581 pcre2_match(code, subj, len, pos, v_opt, match_data, new_mcontext);
582
583 caml_stat_free(subj);
584 End_roots();
585
586 pcre2_match_context_free(new_mcontext);
587 size_t* ovec = pcre2_get_ovector_pointer(match_data);
588 if (ret < 0) {
589 if (is_dfa) caml_stat_free(workspace);
590 pcre2_match_data_free(match_data);
591 if (ret == PCRE2_ERROR_CALLOUT) caml_raise(cod.v_exn);
592 else handle_match_error("pcre2_match_stub(callout)", ret);
593 } else {
594 handle_pcre2_match_result(ovec, v_ovec, ovec_len, subj_start, ret);
595 if (is_dfa) {
596 caml_int_ptr ocaml_workspace_dst =
597 (caml_int_ptr) &Field(v_workspace, 0);
598 const int *workspace_src = workspace;
599 const int *workspace_src_stop = workspace + workspace_len;
600 while (workspace_src != workspace_src_stop) {
601 *ocaml_workspace_dst = *workspace_src;
602 ocaml_workspace_dst++;
603 workspace_src++;
604 }
605 caml_stat_free(workspace);
606 }
607 }
608 }
609 pcre2_match_data_free(match_data);
610 }
611
612 return Val_unit;
613 }
614
615 CAMLprim value pcre2_match_stub(
616 int64_t v_opt, value v_rex, intnat v_pos, intnat v_subj_start, value v_subj,
617 value v_ovec, value v_maybe_cof)
618 {
619 return pcre2_match_stub0(v_opt, v_rex, v_pos, v_subj_start, v_subj,
620 v_ovec, v_maybe_cof, (value) NULL);
621 }
622
623 /* Byte-code hook for pcre2_match_stub
624 Needed, because there are more than 5 arguments */
625 CAMLprim value pcre2_match_stub_bc(value *argv, int __unused argn)
626 {
627 return
628 pcre2_match_stub0(
629 Long_val(argv[0]), argv[1], Int_val(argv[2]), Int_val(argv[3]),
630 argv[4], argv[5], argv[6], (value) NULL);
631 }
632
633 /* Byte-code hook for pcre2_dfa_match_stub
634 Needed, because there are more than 5 arguments */
635 CAMLprim value pcre2_dfa_match_stub_bc(value *argv, int __unused argn)
636 {
637 return
638 pcre2_match_stub0(
639 Long_val(argv[0]), argv[1], Int_val(argv[2]), Int_val(argv[3]),
640 argv[4], argv[5], argv[6], argv[7]);
641 }
642
643 static struct custom_operations tables_ops = {
644 "pcre2_ocaml_tables",
645 pcre2_dealloc_tables,
646 custom_compare_default,
647 custom_hash_default,
648 custom_serialize_default,
649 custom_deserialize_default,
650 custom_compare_ext_default
651 };
652
653 /* Generates a new set of chartables for the current locale (see man
654 page of PCRE */
655 CAMLprim value pcre2_maketables_stub(value __unused v_unit)
656 {
657 /* GC will do a full cycle every 1_000_000 table set allocations (one
658 table set consumes 864 bytes -> maximum of 864_000_000 bytes unreclaimed
659 table sets) */
660 const value v_tables =
661 caml_alloc_custom(
662 &tables_ops, sizeof(struct pcre2_ocaml_tables), 1, 1000000);
663 set_tables(v_tables, pcre2_maketables(NULL));
664 return v_tables;
665 }
666
667 /* Wraps around the isspace-function */
668 CAMLprim value pcre2_isspace_stub(value v_c)
669 {
670 return Val_bool(isspace(Int_val(v_c)));
671 }
672
673
674 /* Returns number of substring associated with a name */
675
676 CAMLprim intnat pcre2_substring_number_from_name_stub(value v_rex, value v_name)
677 {
678 const int ret = pcre2_substring_number_from_name(get_rex(v_rex), (PCRE2_SPTR)String_val(v_name));
679 if (ret == PCRE2_ERROR_NOSUBSTRING)
680 caml_invalid_argument("Named string not found");
681
682 return ret;
683 }
684
685 CAMLprim value pcre2_substring_number_from_name_stub_bc(value v_rex, value v_name)
686 {
687 return Val_int(pcre2_substring_number_from_name_stub(v_rex, v_name));
688 }
689
690
691 /* Returns array of names of named substrings in a regexp */
692 CAMLprim value pcre2_names_stub(value v_rex)
693 {
694 CAMLparam1(v_rex);
695 CAMLlocal1(v_res);
696 uint32_t name_count;
697 uint32_t entry_size;
698 const char *tbl_ptr;
699 uint32_t i;
700
701 int ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_NAMECOUNT, &name_count);
702 if (ret != 0) raise_internal_error("pcre2_names_stub: namecount");
703
704 ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_NAMEENTRYSIZE, &entry_size);
705 if (ret != 0) raise_internal_error("pcre2_names_stub: nameentrysize");
706
707 ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_NAMETABLE, &tbl_ptr);
708 if (ret != 0) raise_internal_error("pcre2_names_stub: nametable");
709
710 v_res = caml_alloc(name_count, 0);
711
712 for (i = 0; i < name_count; ++i) {
713 value v_name = caml_copy_string(tbl_ptr + 2);
714 Store_field(v_res, i, v_name);
715 tbl_ptr += entry_size;
716 }
717
718 CAMLreturn(v_res);
719 }
720
721 /* Generic stub for getting integer results from pcre2_config */
722 static inline int pcre2_config_int(int what)
723 {
724 int ret;
725 pcre2_config(what, (void *) &ret);
726 return ret;
727 }
728
729 /* Generic stub for getting long integer results from pcre2_config */
730 static inline long pcre2_config_long(int what)
731 {
732 long ret;
733 pcre2_config(what, (void *) &ret);
734 return ret;
735 }
736
737
738 /* Some stubs for config-functions */
739
740 /* Makes OCaml-string from PCRE-version */
741 CAMLprim value pcre2_version_stub(value __unused v_unit) {
742 CAMLparam1(v_unit);
743 CAMLlocal1(v_version);
744 v_version = caml_alloc_string(32);
745
746 pcre2_config(PCRE2_CONFIG_VERSION, (void *)String_val(v_version));
747
748 CAMLreturn(v_version);
749 }
750
751 /* Returns boolean indicating unicode support */
752 CAMLprim value pcre2_config_unicode_stub(value __unused v_unit)
753 { return Val_bool(pcre2_config_int(PCRE2_CONFIG_UNICODE)); }
754
755
756 /* Returns character used as newline */
757 CAMLprim value pcre2_config_newline_stub(value __unused v_unit)
758 { return Val_int(pcre2_config_int(PCRE2_CONFIG_NEWLINE)); }
759
760
761 /* Returns number of bytes used for internal linkage of regular expressions */
762
763 CAMLprim intnat pcre2_config_link_size_stub(value __unused v_unit)
764 { return pcre2_config_int(PCRE2_CONFIG_LINKSIZE); }
765
766 CAMLprim value pcre2_config_link_size_stub_bc(value v_unit)
767 { return Val_int(pcre2_config_link_size_stub(v_unit)); }
768
769
770 /* Returns default limit for calls to internal matching function */
771
772 CAMLprim intnat pcre2_config_match_limit_stub(value __unused v_unit)
773 { return pcre2_config_long(PCRE2_CONFIG_MATCHLIMIT); }
774
775 CAMLprim value pcre2_config_match_limit_stub_bc(value v_unit)
776 { return Val_int(pcre2_config_match_limit_stub(v_unit)); }
777
778
779 /* Returns default limit for depth of nested backtracking */
780
781 CAMLprim intnat pcre2_config_depth_limit_stub(value __unused v_unit)
782 { return pcre2_config_long(PCRE2_CONFIG_DEPTHLIMIT); }
783
784 CAMLprim value pcre2_config_depth_limit_stub_bc(value v_unit)
785 { return Val_int(pcre2_config_depth_limit_stub(v_unit)); }
786
787
788 /* Returns boolean indicating use of stack recursion */
789 CAMLprim intnat pcre2_config_stackrecurse_stub(value __unused v_unit)
790 { return Val_bool(pcre2_config_int(PCRE2_CONFIG_STACKRECURSE)); }
885885 Array.iter (browse_field ctx) s.hls_fields;
886886 browse_method ctx s.hls_method;
887887 ) t;
888 let classes = List.sort (fun c1 c2 -> c1.hlc_index - c2.hlc_index) (List.rev !classes) in
888889 let methods = List.sort (fun m1 m2 -> m1.hlmt_index - m2.hlmt_index) (List.rev !methods) in
889890 (* done *)
890891 let rec ctx = {
897898 fnames = new_lookup flatten_name;
898899 fmetas = new_lookup flatten_meta;
899900 fmethods = new_index_lookup methods flatten_method;
900 fclasses = new_index_lookup (List.rev !classes) flatten_class;
901 fclasses = new_index_lookup classes flatten_class;
901902 fjumps = [];
902903 ffunctions = [];
903904 } in
00 opam-version: "2.0"
11 name: "haxe"
2 version: "4.2.4"
2 version: "4.3.0"
33 synopsis: "Multi-target universal programming language"
44 description: """
55 Haxe is an open source toolkit based on a modern,
2121 "ocaml" {>= "4.02"}
2222 "ocamlfind" {build}
2323 "dune" {>= "1.11"}
24 "camlp5" {build & = "8.00~alpha05"}
24 "camlp5" {build & = "8.00"}
2525 "sedlex" {>= "2.0"}
2626 "xml-light"
27 "extlib" {>= "1.7.6"}
27 "extlib" {>= "1.7.8"}
2828 "ptmap" {>= "2.0.0"}
2929 "sha"
30 "conf-libpcre"
30 "conf-libpcre2-8"
3131 "conf-zlib"
32 "conf-mbedtls"
3332 "conf-neko"
34 "luv" {<= "0.5.8"} (* see https://github.com/aantron/luv/issues/121 *)
35 ]
33 "luv"
34 ]
7373 "/"
7474 else
7575 "-x" ^ (string_of_int (Char.code chr))) name
76
77 let update_cache_dependencies t =
78 let visited_anons = ref [] in
79 let rec check_t m t = match t with
80 | TInst(c,tl) ->
81 add_dependency m c.cl_module;
82 List.iter (check_t m) tl;
83 | TEnum(en,tl) ->
84 add_dependency m en.e_module;
85 List.iter (check_t m) tl;
86 | TType(t,tl) ->
87 add_dependency m t.t_module;
88 List.iter (check_t m) tl;
89 | TAbstract(a,tl) ->
90 add_dependency m a.a_module;
91 List.iter (check_t m) tl;
92 | TFun(targs,tret) ->
93 List.iter (fun (_,_,t) -> check_t m t) targs;
94 check_t m tret;
95 | TAnon an ->
96 if not (List.memq an !visited_anons) then begin
97 visited_anons := an :: !visited_anons;
98 PMap.iter (fun _ cf -> check_field m cf) an.a_fields
99 end
100 | TMono r ->
101 (match r.tm_type with
102 | Some t -> check_t m t
103 | _ -> ())
104 | TLazy f ->
105 check_t m (lazy_type f)
106 | TDynamic t ->
107 if t == t_dynamic then
108 ()
109 else
110 check_t m t
111 and check_field m cf =
112 check_t m cf.cf_type
113 in
114 match t with
115 | TClassDecl c ->
116 List.iter (check_field c.cl_module) c.cl_ordered_statics;
117 List.iter (check_field c.cl_module) c.cl_ordered_fields;
118 (match c.cl_constructor with None -> () | Some cf -> check_field c.cl_module cf);
119 | _ ->
120 ()
12176
12277 (* -------------------------------------------------------------------------- *)
12378 (* FIX OVERRIDES *)
168123 have to detect this case and change the variable (issue #2712). *)
169124 begin match follow v.v_type with
170125 | TInst({cl_kind = KTypeParameter [tc]} as cp,_) when com.platform = Flash ->
171 if List.mem_assoc (snd cp.cl_path) c.cl_params then raise (Unify_error [])
126 if List.exists (fun tp -> tp.ttp_name = (snd cp.cl_path)) c.cl_params then raise (Unify_error [])
172127 | _ ->
173128 ()
174129 end;
256211 is_volatile (lazy_type f)
257212 | TType (t,tl) ->
258213 (match t.t_path with
259 | _ -> is_volatile (apply_params t.t_params tl t.t_type))
214 | _ -> is_volatile (apply_typedef t tl))
260215 | _ ->
261216 false
262217
264264 | Some IChar i
265265 | Some IByte i
266266 | Some IShort i ->
267 [Meta.CsNative, [EConst (Int (string_of_int i) ), p], p ], Int64.of_int i
267 [Meta.CsNative, [EConst (Int (string_of_int i, None) ), p], p ], Int64.of_int i
268268 | Some IInt i ->
269 [Meta.CsNative, [EConst (Int (Int32.to_string i) ), p], p ], Int64.of_int32 i
269 [Meta.CsNative, [EConst (Int (Int32.to_string i, None) ), p], p ], Int64.of_int32 i
270270 | Some IFloat32 f | Some IFloat64 f ->
271271 [], Int64.of_float f
272272 | Some IInt64 i ->
322322 | CInitOnly | CLiteral -> true, acc
323323 | _ -> readonly,acc
324324 ) (false,[cff_access]) field.fflags.ff_contract in
325 if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
325 if Common.raw_defined ctx.ncom "net_loader_debug" then
326326 Printf.printf "\t%sfield %s : %s\n" (if List.mem_assoc AStatic acc then "static " else "") cff_name (IlMetaDebug.ilsig_s field.fsig.ssig);
327327 let kind = match readonly with
328328 | true ->
362362 else
363363 acc
364364 in
365 if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
365 if Common.raw_defined ctx.ncom "net_loader_debug" then
366366 Printf.printf "\tevent %s : %s\n" name (IlMetaDebug.ilsig_s ev.esig.ssig);
367367 let acc = add_m acc ev.eadd in
368368 let acc = add_m acc ev.eremove in
399399 (APrivate,null_pos), ((Meta.Protected, [], p) :: meta)
400400 | FAPublic -> (APublic,null_pos), meta
401401 | _ ->
402 if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
402 if Common.raw_defined ctx.ncom "net_loader_debug" then
403403 Printf.printf "\tmethod %s (skipped) : %s\n" cff_name (IlMetaDebug.ilsig_s m.msig.ssig);
404404 raise Exit
405405 in
411411 | _ -> acc, is_final
412412 ) ([acc],None) m.mflags.mf_contract in
413413 let acc = (AOverload,p) :: acc in
414 if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
414 if Common.raw_defined ctx.ncom "net_loader_debug" then
415415 Printf.printf "\t%smethod %s : %s\n" (if !is_static then "static " else "") cff_name (IlMetaDebug.ilsig_s m.msig.ssig);
416416
417417 let acc = match is_final with
472472 tp_name = "M" ^ string_of_int t.tnumber,null_pos;
473473 tp_params = [];
474474 tp_constraints = None;
475 tp_default = None;
475476 tp_meta = [];
476477 }
477478 ) m.mtypes in
550551 | _ -> "never");
551552 | Some _ -> "set"
552553 in
553 if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
554 if Common.raw_defined ctx.ncom "net_loader_debug" then
554555 Printf.printf "\tproperty %s (%s,%s) : %s\n" prop.pname get set (IlMetaDebug.ilsig_s prop.psig.ssig);
555556 let ilsig = match prop.psig.snorm with
556557 | LMethod (_,ret,[]) -> ret
593594 mke (ECast( mke (EUntyped( mke (ECall( mke (EConst(Ident name)) p, args )) p )) p , None)) p
594595
595596 let mk_this_call name p args =
596 mke (ECall( mke (EField(mke (EConst(Ident "this")) p ,name)) p, args )) p
597 mke (ECall( mke (efield(mke (EConst(Ident "this")) p ,name)) p, args )) p
597598
598599 let mk_metas metas p =
599600 List.map (fun m -> m,[],p) metas
642643 tp_name = ("T" ^ string_of_int t.tnumber),null_pos;
643644 tp_params = [];
644645 tp_constraints = None;
646 tp_default = None;
645647 tp_meta = [];
646648 }
647649 ) ilcls.ctypes in
650652 let clsname = match ilcls.cpath with
651653 | (ns,inner,n) -> get_clsname ctx (ns,inner,"Delegate_"^n)
652654 in
653 let expr = (ECall( (EField( (EConst(Ident (clsname)),p), fn_name ),p), [(EConst(Ident"arg1"),p);(EConst(Ident"arg2"),p)]),p) in
655 let expr = (ECall( (efield( (EConst(Ident (clsname)),p), fn_name ),p), [(EConst(Ident"arg1"),p);(EConst(Ident"arg2"),p)]),p) in
654656 FFun {
655657 f_params = types;
656658 f_args = [("arg1",null_pos),false,[],Some (abs_type,null_pos),None;("arg2",null_pos),false,[],Some (abs_type,null_pos),None];
716718 | _ ->
717719 let flags = ref [HExtern] in
718720 (* todo: instead of CsNative, use more specific definitions *)
719 if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then begin
721 if Common.raw_defined ctx.ncom "net_loader_debug" then begin
720722 let sup = match ilcls.csuper with | None -> [] | Some c -> [IlMetaDebug.ilsig_s c.ssig] in
721723 let sup = sup @ List.map (fun i -> IlMetaDebug.ilsig_s i.ssig) ilcls.cimplements in
722724 print_endline ("converting " ^ ilpath_s ilcls.cpath ^ " : " ^ (String.concat ", " sup))
815817 tp_name = "T" ^ string_of_int p.tnumber,null_pos;
816818 tp_params = [];
817819 tp_constraints = None;
820 tp_default = None;
818821 tp_meta = [];
819822 }) ilcls.ctypes
820823 in
11401143 let cache = IlMetaReader.create_cache () in
11411144 let meta = IlMetaReader.read_meta_tables ctx clr_header cache in
11421145 close_in (r.PeReader.ch);
1143 if PMap.mem "net_loader_debug" com.defines.Define.values then
1146 if Common.raw_defined com "net_loader_debug" then
11441147 print_endline ("for lib " ^ file_path);
11451148 let il_typedefs = Hashtbl.copy meta.il_typedefs in
11461149 Hashtbl.clear meta.il_typedefs;
11471150
11481151 Hashtbl.iter (fun _ td ->
11491152 let path = IlMetaTools.get_path (TypeDef td) in
1150 if PMap.mem "net_loader_debug" com.defines.Define.values then
1153 if Common.raw_defined com "net_loader_debug" then
11511154 Printf.printf "found %s\n" (s_type_path (self#netpath_to_hx path));
11521155 Hashtbl.replace com.net_path_map (self#netpath_to_hx path) path;
11531156 Hashtbl.replace meta.il_typedefs path td
11891192 let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
11901193 let cp = ref [] in
11911194 let rec build path = try
1192 if PMap.mem "net_loader_debug" com.defines.Define.values then
1195 if Common.raw_defined com "net_loader_debug" then
11931196 Printf.printf "looking up %s\n" (s_type_path path);
11941197 match self#lookup path with
11951198 | Some({csuper = Some{snorm = LClass( (["System"],[],("Delegate"|"MulticastDelegate")),_)}} as cls)
12401243
12411244 let before_generate com =
12421245 (* netcore version *)
1243 let netcore_ver = try Some(PMap.find "netcore_ver" com.defines.Define.values) with Not_found -> None in
1246 let netcore_ver = try Some(Common.defined_value com Define.NetcoreVer) with Not_found -> None in
12441247
12451248 (* net version *)
12461249 let net_ver =
12471250 try
1248 let ver = PMap.find "net_ver" com.defines.Define.values in
1251 let ver = Common.defined_value com Define.NetVer in
12491252 try int_of_string ver with Failure _ -> raise (Arg.Bad "Invalid value for -D net-ver. Expected format: xx (e.g. 20, 35, 40, 45, 50)")
12501253 with Not_found when netcore_ver != None ->
12511254 (* 4.7 was released around .NET core 2.1 *)
12731276
12741277 (* net target *)
12751278 let net_target = try
1276 String.lowercase (PMap.find "net_target" com.defines.Define.values)
1279 String.lowercase (Common.defined_value com Define.NetTarget)
12771280 with | Not_found ->
12781281 "net"
12791282 in
184184 ) l1 l2
185185 with
186186 Unify_error l -> Type.error (cannot_unify a b :: l))
187 | TDynamic a , TDynamic b ->
187 | TDynamic None , TDynamic None ->
188 ()
189 | TDynamic (Some a) , TDynamic (Some b) ->
188190 type_eq gen param a b
189191 | TAnon a1, TAnon a2 ->
190192 (try
624626 match arglist, elist with
625627 | [], [] -> true
626628 | [(_,_,t)], elist when ExtType.is_rest (follow t) ->
627 let is_rest_array arg_t =
628 Type.fast_eq (Abstract.follow_with_abstracts t) (Abstract.follow_with_abstracts arg_t)
629 in
630 (match elist with
631 | [arg_t] when is_rest_array arg_t -> true
632 | _ ->
633 match follow t with
634 | TAbstract ({ a_path = ["haxe"],"Rest" }, [t1]) ->
635 let t1 = run_follow gen t1 in
636 (try
637 List.iter (fun et -> unify et t1) elist;
638 true
639 with Unify_error _ ->
640 false
641 )
642 | _ -> die "" __LOC__
629 (match follow t with
630 | TAbstract ({ a_path = ["haxe"],"Rest" } as a, [t1]) ->
631 let is_rest_array arg_t =
632 let boxed = TAbstract (a, [get_boxed gen t1]) in
633 Type.fast_eq (Abstract.follow_with_abstracts boxed) (Abstract.follow_with_abstracts arg_t)
634 in
635 (match elist with
636 | [arg_t] when is_rest_array arg_t -> true
637 | _ ->
638 let t1 = run_follow gen t1 in
639 (try
640 List.iter (fun et -> unify et t1) elist;
641 true
642 with Unify_error _ ->
643 false
644 )
645 )
646 | _ -> die "" __LOC__
643647 )
644648 | (_,_,t) :: arglist, et :: elist ->
645649 (try
647651 unify et t;
648652 check_arg arglist elist
649653 with Unify_error el ->
650 (* List.iter (fun el -> gen.gcon.warning (Error.unify_error_msg (print_context()) el) p) el; *)
651654 false
652655 )
653656 | _ ->
738741
739742 (* this function will receive the original function argument, the applied function argument and the original function parameters. *)
740743 (* from this info, it will infer the applied tparams for the function *)
741 let infer_params pos (original_args:((string * bool * t) list * t)) (applied_args:((string * bool * t) list * t)) (params:(string * t) list) calls_parameters_explicitly : tparams =
744 let infer_params pos (original_args:((string * bool * t) list * t)) (applied_args:((string * bool * t) list * t)) (params:typed_type_param list) calls_parameters_explicitly : tparams =
742745 match params with
743746 | [] -> []
744747 | _ ->
765768 | [Cannot_unify (b, TAbstract(a,params))] ->
766769 let a = apply_params a.a_params params a.a_this in
767770 if not (shallow_eq a b) then
768 gen.gcon.warning ("This expression may be invalid") pos
771 gen.gwarning WGenerator ("This expression may be invalid") pos
769772 | _ ->
770 gen.gcon.warning ("This expression may be invalid") pos
773 gen.gwarning WGenerator ("This expression may be invalid") pos
771774 )
772775 | Invalid_argument _ ->
773 gen.gcon.warning ("This expression may be invalid") pos
776 gen.gwarning WGenerator ("This expression may be invalid") pos
774777 );
775778
776779 List.map (fun t ->
822825 (* f,f.cf_type, false *)
823826 select_overload gen e1.etype ((f.cf_type,f) :: List.map (fun f -> f.cf_type,f) f.cf_overloads) [] [], true
824827 | _ ->
825 gen.gcon.warning "Overloaded classfield typed as anonymous" ecall.epos;
828 gen.gwarning WGenerator "Overloaded classfield typed as anonymous" ecall.epos;
826829 (cf, actual_t, true), true
827830 in
828831
845848 end;
846849 { cf_orig with cf_name = cf.cf_name },actual_t,false
847850 | None ->
848 gen.gcon.warning "Cannot find matching overload" ecall.epos;
851 gen.gwarning WGenerator "Cannot find matching overload" ecall.epos;
849852 cf, actual_t, true
850853 else
851854 cf,actual_t,error
927930 elist);
928931 }, elist
929932 with Invalid_argument _ ->
930 gen.gcon.warning ("This expression may be invalid" ) ecall.epos;
933 gen.gwarning WGenerator ("This expression may be invalid" ) ecall.epos;
931934 { ecall with eexpr = TCall({ e1 with eexpr = TField(!ef, f) }, elist) }, elist
932935 in
933936 let new_ecall = if fparams <> [] then gen.gparam_func_call new_ecall { e1 with eexpr = TField(!ef, f) } fparams elist else new_ecall in
957960 *)
958961 | _ ->
959962 let pt = match e with | None -> real_type | Some _ -> snd (get_fun e1.etype) in
960 let _params = match follow pt with | TEnum(_, p) -> p | _ -> gen.gcon.warning (debug_expr e1) e1.epos; die "" __LOC__ in
963 let _params = match follow pt with | TEnum(_, p) -> p | _ -> gen.gwarning WGenerator (debug_expr e1) e1.epos; die "" __LOC__ in
961964 let args, ret = get_fun efield.ef_type in
962965 let actual_t = TFun(List.map (fun (n,o,t) -> (n,o,gen.greal_type t)) args, gen.greal_type ret) in
963966 (*
11411144 let base_type = match follow et with
11421145 | TInst({ cl_path = ([], "Array") } as cl, bt) -> gen.greal_type_param (TClassDecl cl) bt
11431146 | _ ->
1144 gen.gcon.warning (debug_type et) e.epos;
1147 gen.gwarning WGenerator (debug_type et) e.epos;
11451148 (match gen.gcurrent_class with
11461149 | Some cl -> print_endline (s_type_path cl.cl_path)
11471150 | _ -> ());
11851188 ) (wrap_rest_args gen (TFun (args,rt)) eparams e.epos) args in
11861189 { e with eexpr = TCall(ef, eparams) }
11871190 with | Not_found ->
1188 gen.gcon.warning "No overload found for this constructor call" e.epos;
1191 gen.gwarning WGenerator "No overload found for this constructor call" e.epos;
11891192 { e with eexpr = TCall(ef, List.map run eparams) })
11901193 | TCall (ef, eparams) ->
11911194 (match ef.etype with
12131216 ) (wrap_rest_args gen (TFun (args,rt)) eparams e.epos) args in
12141217 { e with eexpr = TNew(cl, tparams, eparams) }
12151218 with | Not_found ->
1216 gen.gcon.warning "No overload found for this constructor call" e.epos;
1219 gen.gwarning WGenerator "No overload found for this constructor call" e.epos;
12171220 { e with eexpr = TNew(cl, tparams, List.map run eparams) })
12181221 | TUnop((Increment | Decrement) as op, flag, ({ eexpr = TArray (arr, idx) } as e2))
12191222 when (match follow arr.etype with TInst({ cl_path = ["cs"],"NativeArray" },_) -> true | _ -> false) ->
282282 List.filter (fun t -> not (List.memq t acc)) (cl :: params) @ acc;
283283 | TFun (params,tret) ->
284284 List.fold_left get_type_params acc ( tret :: List.map (fun (_,_,t) -> t) params )
285 | TDynamic t ->
286 (match t with | TDynamic _ -> acc | _ -> get_type_params acc t)
285 | TDynamic None ->
286 acc
287 | TDynamic (Some t) ->
288 get_type_params acc t
287289 | TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) ->
288290 get_type_params acc ( Abstract.get_underlying_type a pl)
289291 | TAnon a ->
290292 PMap.fold (fun cf acc ->
291 let params = List.map (fun (_,t) -> match follow t with
293 let params = List.map (fun tp -> match follow tp.ttp_type with
292294 | TInst(c,_) -> c
293295 | _ -> die "" __LOC__) cf.cf_params
294296 in
395397 in
396398
397399 (*let cltypes = List.map (fun cl -> (snd cl.cl_path, TInst(map_param cl, []) )) tparams in*)
398 let cltypes = List.map (fun cl -> (snd cl.cl_path, TInst(cl, []) )) tparams in
400 let cltypes = List.map (fun cl -> mk_type_param (snd cl.cl_path) (TInst(cl, [])) None) tparams in
399401
400402 (* create a new class that extends abstract function class, with a ctor implementation that will setup all captured variables *)
401403 let cfield = match gen.gcurrent_classfield with
425427
426428 let mk_this v pos =
427429 {
428 (mk_field_access gen { eexpr = TConst TThis; etype = TInst(cls, List.map snd cls.cl_params); epos = pos } v.v_name pos)
430 (mk_field_access gen { eexpr = TConst TThis; etype = TInst(cls, extract_param_types cls.cl_params); epos = pos } v.v_name pos)
429431 with etype = v.v_type
430432 }
431433 in
475477 eexpr = TCall({
476478 eexpr = TField({
477479 eexpr = TConst TThis;
478 etype = TInst(cls, List.map snd cls.cl_params);
480 etype = TInst(cls, extract_param_types cls.cl_params);
479481 epos = pos;
480 }, FInstance(cls, List.map snd cls.cl_params, cf));
482 }, FInstance(cls, extract_param_types cls.cl_params, cf));
481483 etype = cf.cf_type;
482484 epos = pos;
483485 }, List.map (fun (v,_) -> mk_local v pos) tfunc.tf_args);
616618 | TInst(c,_), TInst(c2,_) -> c == c2
617619 | _ -> false
618620 in
619 let passoc = List.map2 (fun (_,t) m -> t,m) types monos in
620 let cltparams = List.map (fun (_,t) ->
621 let passoc = List.map2 (fun tp m -> tp.ttp_type,m) types monos in
622 let cltparams = List.map (fun tp ->
621623 try
622 snd (List.find (fun (t2,_) -> same_cl t t2) passoc)
623 with | Not_found -> t) cls.cl_params
624 snd (List.find (fun (t2,_) -> same_cl tp.ttp_type t2) passoc)
625 with | Not_found -> tp.ttp_type) cls.cl_params
624626 in
625627 { e with eexpr = TNew(cls, cltparams, List.rev captured) }
626628 with
627629 | Not_found ->
628630 if in_tparam then begin
629 gen.gcon.warning "This expression may be invalid" e.epos;
631 gen.gwarning WGenerator "This expression may be invalid" e.epos;
630632 e
631633 end else
632634 (* It is possible that we are recursively calling a function
641643 (Meta.Custom(":tparamcall"), [], e.epos), e
642644 ) }
643645 | Unify_error el ->
644 List.iter (fun el -> gen.gcon.warning (Error.unify_error_msg (print_context()) el) e.epos) el;
645 gen.gcon.warning "This expression may be invalid" e.epos;
646 List.iter (fun el -> gen.gwarning WGenerator (Error.unify_error_msg (print_context()) el) e.epos) el;
647 gen.gwarning WGenerator "This expression may be invalid" e.epos;
646648 e
647649 )
648650 (* (handle_anon_func:texpr->tfunc->texpr) (dynamic_func_call:texpr->texpr->texpr list->texpr) *)
898900
899901 let map_base_classfields cl map_fn =
900902 let pos = cl.cl_pos in
901 let this_t = TInst(cl,List.map snd cl.cl_params) in
903 let this_t = TInst(cl,extract_param_types cl.cl_params) in
902904 let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in
903905 let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in
904906
10901092 loop arity []
10911093 in
10921094
1093 let this = mk (TConst TThis) (TInst (cl, List.map snd cl.cl_params)) pos in
1095 let this = mk (TConst TThis) (TInst (cl, extract_param_types cl.cl_params)) pos in
10941096 let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in
10951097
10961098 let mk_invoke_switch i api =
118118 { e with eexpr = TBinop (op, mk_cast com.basic.tbool (run e1), mk_cast com.basic.tbool (run e2)) }
119119 | OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr ->
120120 { e with eexpr = TBinop (op, mk_cast com.basic.tint (run e1), mk_cast com.basic.tint (run e2)) }
121 | OpAssign | OpAssignOp _ | OpInterval | OpArrow | OpIn ->
121 | OpAssign | OpAssignOp _ | OpInterval | OpArrow | OpIn | OpNullCoal ->
122122 Globals.die "" __LOC__)
123123
124124 | TUnop (Increment as op, flag, e1)
9898
9999 (match gen.gcon.platform with
100100 | Cs when Common.defined gen.gcon Define.CoreApiSerialize ->
101 cl.cl_meta <- ( Meta.Meta, [ (EField( (EConst (Ident "System"), null_pos ), "Serializable" ), null_pos) ], null_pos ) :: cl.cl_meta
101 cl.cl_meta <- ( Meta.Meta, [ (efield( (EConst (Ident "System"), null_pos ), "Serializable" ), null_pos) ], null_pos ) :: cl.cl_meta
102102 | _ -> ());
103103 let c_types =
104104 if handle_type_params then
105 List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) en.e_params
105 List.map (fun tp -> {tp with ttp_type=TInst (map_param (get_cl_t tp.ttp_type), [])}) en.e_params
106106 else
107107 []
108108 in
120120 | TFun(params,ret) ->
121121 let dup_types =
122122 if handle_type_params then
123 List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) en.e_params
123 List.map (fun tp -> {tp with ttp_type = TInst (map_param (get_cl_t tp.ttp_type), [])}) en.e_params
124124 else
125125 []
126126 in
127127
128128 let ef_type =
129 let fn, types = if handle_type_params then snd, dup_types else (fun _ -> t_dynamic), en.e_params in
129 let fn, types = if handle_type_params then extract_param_type, dup_types else (fun _ -> t_dynamic), en.e_params in
130130 let t = apply_params en.e_params (List.map fn types) ef.ef_type in
131131 apply_params ef.ef_params (List.map fn ef.ef_params) t
132132 in
143143 eexpr = TFunction({
144144 tf_args = tf_args;
145145 tf_type = ret;
146 tf_expr = mk_block ( mk_return { eexpr = TNew(cl,List.map snd dup_types, [make_int gen.gcon.basic old_i pos; arr_decl] ); etype = TInst(cl, List.map snd dup_types); epos = pos } );
146 tf_expr = mk_block ( mk_return { eexpr = TNew(cl,extract_param_types dup_types, [make_int gen.gcon.basic old_i pos; arr_decl] ); etype = TInst(cl, extract_param_types dup_types); epos = pos } );
147147 });
148148 etype = ef_type;
149149 epos = pos
6060 ) c.cl_ordered_fields;
6161 md
6262 | TClassDecl c when not (has_class_flag c CExtern) ->
63 let this = { eexpr = TConst TThis; etype = TInst(c,List.map snd c.cl_params); epos = c.cl_pos } in
63 let this = { eexpr = TConst TThis; etype = TInst(c,extract_param_types c.cl_params); epos = c.cl_pos } in
6464 (* look through all interfaces, and try to find a type that applies exactly *)
6565 let rec loop_iface (iface:tclass) itl =
6666 List.iter (fun (s,stl) -> loop_iface s (List.map (apply_params iface.cl_params itl) stl)) iface.cl_implements;
8080 Overloads.same_overload_args ~get_vmtype ftype t f f2
8181 ) overloads
8282 | _ :: _ ->
83 (match field_access gen (TInst(c, List.map snd c.cl_params)) f.cf_name with
83 (match field_access gen (TInst(c, extract_param_types c.cl_params)) f.cf_name with
8484 | FClassField(_,_,_,f2,false,t,_) -> t,f2 (* if it's not an overload, all functions should have the same signature *)
8585 | _ -> raise Not_found)
8686 | [] -> raise Not_found
8787 in
8888 replace_mono t2;
8989 (* if we find a function with the exact type of real_ftype, it means this interface has already been taken care of *)
90 if not (type_iseq (get_real_fun gen (apply_params f2.cf_params (List.map snd f.cf_params) t2)) real_ftype) then begin
90 if not (type_iseq (get_real_fun gen (apply_params f2.cf_params (extract_param_types f.cf_params) t2)) real_ftype) then begin
9191 (match f.cf_kind with | Method (MethNormal | MethInline) -> () | _ -> raise Not_found);
9292 let t2 = get_real_fun gen t2 in
9393 if List.length f.cf_params <> List.length f2.cf_params then raise Not_found;
9494 replace_mono t2;
95 match follow (apply_params f2.cf_params (List.map snd f.cf_params) t2), follow real_ftype with
95 match follow (apply_params f2.cf_params (extract_param_types f.cf_params) t2), follow real_ftype with
9696 | TFun(a1,r1), TFun(a2,r2) when not implement_explicitly && not (type_iseq r1 r2) && Overloads.same_overload_args ~get_vmtype real_ftype t2 f f2 ->
9797 (* different return types are the trickiest cases to deal with *)
9898 (* check for covariant return type *)
106106 (* we only have to worry about non-covariant issues *)
107107 if not is_covariant then begin
108108 (* override return type and cast implemented function *)
109 let args, newr = match follow t2, follow (apply_params f.cf_params (List.map snd f2.cf_params) real_ftype) with
109 let args, newr = match follow t2, follow (apply_params f.cf_params (extract_param_types f2.cf_params) real_ftype) with
110110 | TFun(a,_), TFun(_,r) -> a,r
111111 | _ -> Globals.die "" __LOC__
112112 in
132132 let vars = List.map (fun (n,_,t) -> alloc_var n t) a2 in
133133
134134 let args = List.map2 (fun v (_,_,t) -> mk_cast t (mk_local v f2.cf_pos)) vars a1 in
135 let field = { eexpr = TField(this, FInstance(c,List.map snd c.cl_params,f2)); etype = TFun(a1,r1); epos = p } in
135 let field = { eexpr = TField(this, FInstance(c,extract_param_types c.cl_params,f2)); etype = TFun(a1,r1); epos = p } in
136136 let call = { eexpr = TCall(field, args); etype = r1; epos = p } in
137137 (* let call = gen.gparam_func_call call field (List.map snd f.cf_params) args in *)
138138 let is_void = ExtType.is_void r2 in
220220 eexpr = TCall(
221221 {
222222 eexpr = TField(
223 { eexpr = TConst TThis; etype = TInst(c, List.map snd c.cl_params); epos = p },
224 FInstance(c,List.map snd c.cl_params,f));
223 { eexpr = TConst TThis; etype = TInst(c, extract_param_types c.cl_params); epos = p },
224 FInstance(c,extract_param_types c.cl_params,f));
225225 etype = f.cf_type;
226226 epos = p
227227 },
109109 | TLazy f ->
110110 lazy_type f
111111 | TType (t,tl) ->
112 apply_params t.t_params tl t.t_type
112 apply_typedef t tl
113113 | TAbstract({a_path = [],"Null"},[t]) ->
114114 t
115115 | _ ->
382382 gclasses : gen_classes;
383383
384384 gtools : gen_tools;
385
386 gwarning : Warning.warning -> string -> pos -> unit;
385387
386388 (*
387389 module filters run before module filters and they should generate valid haxe syntax as a result.
572574
573575 let rec gen = {
574576 gcon = con;
577 gwarning = (fun w msg p ->
578 let options = Option.map_default (fun c -> Warning.from_meta c.cl_meta) [] gen.gcurrent_class in
579 let options = options @ Option.map_default (fun cf -> Warning.from_meta cf.cf_meta) [] gen.gcurrent_classfield in
580 con.warning w options msg p
581 );
575582 gentry_point = get_entry_point con;
576583 gclasses = {
577584 cl_reflect = get_cl (get_type ([], "Reflect"));
611618
612619 greal_field_types = Hashtbl.create 0;
613620 ghandle_cast = (fun to_t from_t e -> mk_cast to_t e);
614 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));
621 gon_unsafe_cast = (fun t t2 pos -> (gen.gwarning WGenerator ("Type " ^ (debug_type t2) ^ " is being cast to the unrelated type " ^ (s_type (print_context()) t)) pos));
615622 gneeds_box = (fun t -> false);
616623 gspecial_needs_cast = (fun to_t from_t -> false);
617624 gsupported_conversions = Hashtbl.create 0;
664671 | TLazy f ->
665672 follow_f (lazy_type f)
666673 | TType (t,tl) ->
667 follow_f (apply_params t.t_params tl t.t_type)
674 follow_f (apply_typedef t tl)
668675 | TAbstract({a_path = [],"Null"},[t]) ->
669676 follow_f t
670677 | _ -> Some t
722729 ()
723730
724731 let run_filters gen =
725 let last_error = gen.gcon.error in
732 let last_error = gen.gcon.located_error in
726733 let has_errors = ref false in
727 gen.gcon.error <- (fun msg pos -> has_errors := true; last_error msg pos);
734 gen.gcon.located_error <- (fun ?(depth=0) msg -> has_errors := true; last_error ~depth msg);
728735 (* first of all, we have to make sure that the filters won't trigger a major Gc collection *)
729736 let t = Timer.timer ["gencommon_filters"] in
730737 (if Common.defined gen.gcon Define.GencommonDebug then debug_mode := true else debug_mode := false);
812819
813820 reorder_modules gen;
814821 t();
815 if !has_errors then raise (Abort("Compilation aborted with errors",null_pos))
822 if !has_errors then abort "Compilation aborted with errors" null_pos
816823
817824 (* ******************************************* *)
818825 (* basic generation module that source code compilation implementations can use *)
9961003 mk (TCall (mk (TIdent "__array__") t_dynamic pos, el)) (gen.gclasses.nativearray t) pos
9971004
9981005
1006 let get_boxed gen t =
1007 let get path =
1008 try type_of_module_type (Hashtbl.find gen.gtypes path)
1009 with Not_found -> t
1010 in
1011 match follow t with
1012 | TAbstract({ a_path = ([],"Bool") }, []) ->
1013 get (["java";"lang"], "Boolean")
1014 | TAbstract({ a_path = ([],"Float") }, []) ->
1015 get (["java";"lang"], "Double")
1016 | TAbstract({ a_path = ([],"Int") }, []) ->
1017 get (["java";"lang"], "Integer")
1018 | TAbstract({ a_path = (["java"],"Int8") }, []) ->
1019 get (["java";"lang"], "Byte")
1020 | TAbstract({ a_path = (["java"],"Int16") }, []) ->
1021 get (["java";"lang"], "Short")
1022 | TAbstract({ a_path = (["java"],"Char16") }, []) ->
1023 get (["java";"lang"], "Character")
1024 | TAbstract({ a_path = ([],"Single") }, []) ->
1025 get (["java";"lang"], "Float")
1026 | TAbstract({ a_path = (["java"],"Int64") }, [])
1027 | TAbstract({ a_path = (["haxe"],"Int64") }, []) ->
1028 get (["java";"lang"], "Long")
1029 | _ -> t
1030
9991031 (**
10001032 Wraps rest arguments into a native array.
10011033 E.g. transforms params from `callee(param, rest1, rest2, ..., restN)` into
10151047 | _ ->
10161048 match Abstract.follow_with_abstracts t with
10171049 | TInst ({ cl_path = _,"NativeArray" }, [t1]) ->
1018 let pos = punion_el (List.map (fun e -> ((),e.epos)) params) in
1019 let t1 = if Common.defined gen.gcon Define.EraseGenerics then t_dynamic else t1 in
1020 [mk_nativearray_decl gen t1 params pos]
1050 let t1 = if Common.defined gen.gcon Define.EraseGenerics then t_dynamic else get_boxed gen t1 in
1051 [mk_nativearray_decl gen t1 params (punion_el p params)]
10211052 | _ ->
10221053 die ~p "Unexpected rest arguments type" __LOC__
10231054 )
10431074 | TClassDecl _
10441075 | TEnumDecl _
10451076 | TAbstractDecl _ -> md
1046 | TTypeDecl tdecl -> match (follow_func (TType(tdecl, List.map snd tdecl.t_params))) with
1077 | TTypeDecl tdecl -> match (follow_func (TType(tdecl, extract_param_types tdecl.t_params))) with
10471078 | TInst(cl,_) -> TClassDecl cl
10481079 | TEnum(e,_) -> TEnumDecl e
10491080 | TType(t,_) -> TTypeDecl t
11631194 loop_cl (depth+1) sup tl tlch
11641195 ) c.cl_implements
11651196 in
1166 loop_cl 0 orig_cl (List.map snd orig_cl.cl_params) (List.map snd orig_cl.cl_params);
1197 loop_cl 0 orig_cl (extract_param_types orig_cl.cl_params) (extract_param_types orig_cl.cl_params);
11671198 match !chosen with
11681199 | None ->
11691200 None
12591290 | _ when PMap.mem field gen.gbase_class_fields ->
12601291 let cf = PMap.find field gen.gbase_class_fields in
12611292 FClassField(gen.gclasses.cl_dyn, [t_dynamic], gen.gclasses.cl_dyn, cf, false, cf.cf_type, cf.cf_type)
1262 | TDynamic t -> FDynamicField t
1293 | TDynamic t -> FDynamicField (match t with None -> t_dynamic | Some t -> t)
12631294 | TMono _ -> FDynamicField t_dynamic
12641295 | _ -> FNotFound
12651296
12711302 in
12721303 let p = match follow (run_follow gen t) with
12731304 | TInst(_,p) -> p
1274 | _ -> List.map snd cl.cl_params
1305 | _ -> extract_param_types cl.cl_params
12751306 in
12761307 FClassField(cl,p,cl,cf,static,cf.cf_type,cf.cf_type)
12771308 | _ -> field_access gen t (field_name field)
5454 | TMono r -> (match r.tm_type with | Some t -> is_null_t gen t | None -> None)
5555 | TLazy f -> is_null_t gen (lazy_type f)
5656 | TType (t, tl) ->
57 is_null_t gen (apply_params t.t_params tl t.t_type)
57 is_null_t gen (apply_typedef t tl)
5858 | _ -> None
5959
6060 let follow_addon gen t =
6969 | None -> e :: acc
7070 | Some add_expr -> add_expr :: e :: acc
7171
72 let handle_class com cl =
72 let handle_class gen cl =
73 let com = gen.gcon in
7374 let init = match cl.cl_init with
7475 | None -> []
7576 | Some i -> [i]
7778 let init = List.fold_left (fun acc cf ->
7879 match cf.cf_kind with
7980 | Var v when Meta.has Meta.ReadOnly cf.cf_meta ->
80 if v.v_write <> AccNever && not (Meta.has Meta.CoreApi cl.cl_meta) then com.warning "@:readOnly variable declared without `never` setter modifier" cf.cf_pos;
81 if v.v_write <> AccNever && not (Meta.has Meta.CoreApi cl.cl_meta) then gen.gwarning WGenerator "@:readOnly variable declared without `never` setter modifier" cf.cf_pos;
8182 (match cf.cf_expr with
82 | None -> com.warning "Uninitialized readonly variable" cf.cf_pos
83 | Some e -> ensure_simple_expr com e);
83 | None -> gen.gwarning WGenerator "Uninitialized readonly variable" cf.cf_pos
84 | Some e -> ensure_simple_expr gen.gcon e);
8485 acc
8586 | Var _
8687 | Method MethDynamic when Type.is_physical_field cf ->
114115 let vars, funs = List.fold_left (fun (acc_vars,acc_funs) cf ->
115116 match cf.cf_kind with
116117 | Var v when Meta.has Meta.ReadOnly cf.cf_meta ->
117 if v.v_write <> AccNever && not (Meta.has Meta.CoreApi cl.cl_meta) then com.warning "@:readOnly variable declared without `never` setter modifier" cf.cf_pos;
118 if v.v_write <> AccNever && not (Meta.has Meta.CoreApi cl.cl_meta) then gen.gwarning WGenerator "@:readOnly variable declared without `never` setter modifier" cf.cf_pos;
118119 Option.may (ensure_simple_expr com) cf.cf_expr;
119120 (acc_vars,acc_funs)
120121 | Var _
122123 let is_var = match cf.cf_kind with Var _ -> true | _ -> false in
123124 (match cf.cf_expr, cf.cf_params with
124125 | Some e, [] ->
125 let var = mk (TField ((mk (TConst TThis) (TInst (cl, List.map snd cl.cl_params)) cf.cf_pos), FInstance(cl, List.map snd cl.cl_params, cf))) cf.cf_type cf.cf_pos in
126 let var = mk (TField ((mk (TConst TThis) (TInst (cl, extract_param_types cl.cl_params)) cf.cf_pos), FInstance(cl, extract_param_types cl.cl_params, cf))) cf.cf_type cf.cf_pos in
126127 let ret = binop Ast.OpAssign var e cf.cf_type cf.cf_pos in
127128 cf.cf_expr <- None;
128129 let is_override = has_class_field_flag cf CfOverride in
138139 | Some e, _ ->
139140 let params = List.map (fun _ -> t_dynamic) cf.cf_params in
140141 let fn = apply_params cf.cf_params params in
141 let var = mk (TField ((mk (TConst TThis) (TInst (cl, List.map snd cl.cl_params)) cf.cf_pos), FInstance(cl, List.map snd cl.cl_params, cf))) cf.cf_type cf.cf_pos in
142 let var = mk (TField ((mk (TConst TThis) (TInst (cl, extract_param_types cl.cl_params)) cf.cf_pos), FInstance(cl, extract_param_types cl.cl_params, cf))) cf.cf_type cf.cf_pos in
142143 let rec change_expr e =
143144 Type.map_expr_type (change_expr) fn (fun v -> v.v_type <- fn v.v_type; v) e
144145 in
172173 ctor
173174 | None ->
174175 try
175 let sctor, sup, stl = OverloadingConstructor.prev_ctor cl (List.map snd cl.cl_params) in
176 let sctor, sup, stl = OverloadingConstructor.prev_ctor cl (extract_param_types cl.cl_params) in
176177 let ctor = OverloadingConstructor.clone_ctors com sctor sup stl cl in
177178 cl.cl_constructor <- Some ctor;
178179 ctor
223224 List.iter process (ctors :: ctors.cf_overloads)
224225 )
225226
226 let mod_filter com md =
227 let mod_filter gen md =
227228 match md with
228229 | TClassDecl cl when not (has_class_flag cl CExtern) ->
229 handle_class com cl
230 handle_class gen cl
230231 | _ -> ()
231232
232233 let name = "init_funcs"
233234 let priority = solve_deps name [DBefore OverloadingConstructor.priority]
234235
235236 let configure gen =
236 let run = (fun md -> mod_filter gen.gcon md; md) in
237 let run = (fun md -> mod_filter gen md; md) in
237238 gen.gmodule_filters#add name (PCustom priority) run
7070 cl.cl_ordered_fields <- fields;
7171
7272 List.iter (fun cf ->
73 match field_access gen (TInst(cl,List.map snd cl.cl_params)) cf.cf_name with
73 match field_access gen (TInst(cl,extract_param_types cl.cl_params)) cf.cf_name with
7474 | FNotFound | FDynamicField _ ->
7575 cl.cl_ordered_fields <- cf :: cl.cl_ordered_fields;
7676 cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields
113113 | false ->
114114 let static_ctor_name = make_static_ctor_name cl in
115115 (* create the static constructor *)
116 let ctor_types = List.map (fun (s,t) -> (s, TInst(map_param (get_cl_t t), []))) cl.cl_params in
117 let ctor_type_params = List.map snd ctor_types in
118 List.iter (function (_,TInst(c,[])) -> (
116 let ctor_types = List.map (fun tp -> {tp with ttp_type = TInst(map_param (get_cl_t tp.ttp_type), [])}) cl.cl_params in
117 let ctor_type_params = extract_param_types ctor_types in
118 List.iter (function {ttp_type=TInst(c,[])} -> (
119119 match c.cl_kind with
120120 | KTypeParameter (hd :: tail) ->
121121 let before = hd :: tail in
123123 c.cl_kind <- KTypeParameter(after)
124124 | _ -> ())
125125 | _ -> ()) ctor_types;
126 let me = alloc_var "__hx_this" (TInst(cl, List.map snd ctor_types)) in
126 let me = alloc_var "__hx_this" (TInst(cl, extract_param_types ctor_types)) in
127127 add_var_flag me VCaptured;
128128
129129 let fn_args, _ = get_fun ctor.cf_type in
130 let ctor_params = List.map snd ctor_types in
130 let ctor_params = extract_param_types ctor_types in
131131 let fn_type = TFun((me.v_name,false, me.v_type) :: List.map (fun (n,o,t) -> (n,o,apply_params cl.cl_params ctor_params t)) fn_args, com.basic.tvoid) in
132132 let cur_tf_args = match ctor.cf_expr with
133133 | Some { eexpr = TFunction(tf) } -> tf.tf_args
200200 | None -> [], ctor.cf_pos
201201 | Some super -> [super], super.epos
202202 in
203 let el_args =
204 let rec loop fn_args cur_args =
205 match cur_args with
206 | [] -> []
207 | (v,_) :: cur_args ->
208 let local = mk_local v p in
209 match fn_args, cur_args with
210 | [_,_,t], [] when ExtType.is_rest (follow t) ->
211 [mk (TUnop(Spread,Prefix,local)) v.v_type p]
212 | [], _ ->
213 local :: loop fn_args cur_args
214 | _ :: fn_args, _ ->
215 local :: loop fn_args cur_args
216 in
217 loop fn_args cur_tf_args
218 in
203219 let block_contents = block_contents @ [{
204220 eexpr = TCall(
205221 {
206222 eexpr = TField(
207223 Texpr.Builder.make_static_this cl p,
208224 FStatic(cl, static_ctor));
209 etype = apply_params static_ctor.cf_params (List.map snd cl.cl_params) static_ctor.cf_type;
225 etype = apply_params static_ctor.cf_params (extract_param_types cl.cl_params) static_ctor.cf_type;
210226 epos = p
211227 },
212 [{ eexpr = TConst TThis; etype = TInst(cl, List.map snd cl.cl_params); epos = p }]
213 @ List.map (fun (v,_) -> mk_local v p) cur_tf_args
228 [{ eexpr = TConst TThis; etype = TInst(cl, extract_param_types cl.cl_params); epos = p }]
229 @ el_args
214230 );
215231 etype = com.basic.tvoid;
216232 epos = p
233249 let super_call =
234250 {
235251 eexpr = TCall(
236 { eexpr = TConst TSuper; etype = TInst(cl, List.map snd cl.cl_params); epos = ctor.cf_pos },
252 { eexpr = TConst TSuper; etype = TInst(cl, extract_param_types cl.cl_params); epos = ctor.cf_pos },
237253 List.map (fun (v,_) -> mk_local v ctor.cf_pos) tf_args);
238254 etype = com.basic.tvoid;
239255 epos = ctor.cf_pos;
311327 ctor
312328 | None ->
313329 try
314 let sctor, sup, stl = prev_ctor cl (List.map snd cl.cl_params) in
330 let sctor, sup, stl = prev_ctor cl (extract_param_types cl.cl_params) in
315331 (* we'll make constructors that will only call super() *)
316332 let ctor = clone_ctors com sctor sup stl cl in
317333 cl.cl_constructor <- Some ctor;
366382 | Some (sup,_) ->
367383 try
368384 ignore (get_last_empty sup);
369 let esuper = mk (TConst TSuper) (TInst (cl, List.map snd cl.cl_params)) cl.cl_pos in
385 let esuper = mk (TConst TSuper) (TInst (cl, extract_param_types cl.cl_params)) cl.cl_pos in
370386 [mk (TCall (esuper, [empty_ctor_expr])) basic.tvoid cl.cl_pos]
371387 with Not_found ->
372388 try
373389 (* super type is native: find super constructor with least arguments *)
374 let sctor, sup, stl = prev_ctor cl (List.map snd cl.cl_params) in
390 let sctor, sup, stl = prev_ctor cl (extract_param_types cl.cl_params) in
375391 let rec loop remaining (best,n) =
376392 match remaining with
377393 | [] -> best
9393 let rec follow_all_md md =
9494 let t = match md with
9595 | TClassDecl { cl_kind = KAbstractImpl a } ->
96 TAbstract(a, List.map snd a.a_params)
96 TAbstract(a, extract_param_types a.a_params)
9797 | TClassDecl c ->
98 TInst(c, List.map snd c.cl_params)
98 TInst(c, extract_param_types c.cl_params)
9999 | TEnumDecl e ->
100 TEnum(e, List.map snd e.e_params)
100 TEnum(e, extract_param_types e.e_params)
101101 | TTypeDecl t ->
102 TType(t, List.map snd t.t_params)
102 TType(t, extract_param_types t.t_params)
103103 | TAbstractDecl a ->
104 TAbstract(a, List.map snd a.a_params)
104 TAbstract(a, extract_param_types a.a_params)
105105 in
106106 Abstract.follow_with_abstracts t
107107
308308 if not ret then begin
309309 match md with
310310 | TClassDecl c ->
311 let set_hxgeneric (_,param) = match follow param with
311 let set_hxgeneric tp = match follow tp.ttp_type with
312312 | TInst(c,_) ->
313313 c.cl_meta <- (Meta.NativeGeneric, [], c.cl_pos) :: c.cl_meta
314314 | _ -> ()
396396 let create_stub_casts gen cl cast_cfield =
397397 (* go through superclasses and interfaces *)
398398 let p = cl.cl_pos in
399 let this = { eexpr = TConst TThis; etype = (TInst(cl, List.map snd cl.cl_params)); epos = p } in
399 let this = { eexpr = TConst TThis; etype = (TInst(cl, extract_param_types cl.cl_params)); epos = p } in
400400
401401 let rec loop curcls params level reverse_params =
402402 if (level <> 0 || (has_class_flag curcls CInterface) || (has_class_flag curcls CAbstract) ) && params <> [] && is_hxgeneric (TClassDecl curcls) then begin
403 let cparams = List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) curcls.cl_params in
403 let cparams = List.map (fun tp -> {tp with ttp_type=TInst (map_param (get_cl_t tp.ttp_type), [])}) curcls.cl_params in
404404 let name = get_cast_name curcls in
405405 if not (PMap.mem name cl.cl_fields) then begin
406406 let reverse_params = List.map (apply_params curcls.cl_params params) reverse_params in
407407 let cfield = mk_class_field name (TFun([], t_dynamic)) false cl.cl_pos (Method MethNormal) cparams in
408 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
408 let field = { eexpr = TField(this, FInstance(cl,extract_param_types cl.cl_params, cast_cfield)); etype = apply_params cast_cfield.cf_params reverse_params cast_cfield.cf_type; epos = p } in
409409 let call =
410410 {
411411 eexpr = TCall(field, []);
445445 loop iface (iface_params) level (get_reverse iface iface_params);
446446 ) curcls.cl_implements
447447 in
448 loop cl (List.map snd cl.cl_params) 0 (List.map snd cl.cl_params)
448 loop cl (extract_param_types cl.cl_params) 0 (extract_param_types cl.cl_params)
449449
450450 (*
451451 Creates a cast classfield, with the desired name
459459 let create_cast_cfield gen cl name =
460460 reset_temps();
461461 let basic = gen.gcon.basic in
462 let cparams = List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) cl.cl_params in
462 let cparams = List.map (fun tp -> {tp with ttp_type = TInst (map_param (get_cl_t tp.ttp_type), [])}) cl.cl_params in
463463 let cfield = mk_class_field name (TFun([], t_dynamic)) false cl.cl_pos (Method MethNormal) cparams in
464 let params = List.map snd cparams in
465
466 let fields = get_fields gen cl (List.map snd cl.cl_params) params [] in
464 let params = extract_param_types cparams in
465
466 let fields = get_fields gen cl (extract_param_types cl.cl_params) params [] in
467467 let fields = List.filter (fun (cf,_,_) -> Type.is_physical_field cf) fields in
468468
469469 (* now create the contents of the function *)
489489
490490 let new_me_var = alloc_var "new_me" (TInst (cl, params)) in
491491 let local_new_me = mk_local new_me_var pos in
492 let this = mk (TConst TThis) (TInst (cl, List.map snd cl.cl_params)) pos in
492 let this = mk (TConst TThis) (TInst (cl, extract_param_types cl.cl_params)) pos in
493493 let field_var = alloc_var "field" basic.tstring in
494494 let local_field = mk_local field_var pos in
495495 let i_var = alloc_var "i" basic.tint in
509509 in
510510 List.map (fun (cf, t_cl, t_cf) ->
511511 let t_cf = follow (gen.greal_type t_cf) in
512 let this_field = mk (TField (this, FInstance (cl, List.map snd cl.cl_params, cf))) t_cl pos in
512 let this_field = mk (TField (this, FInstance (cl, extract_param_types cl.cl_params, cf))) t_cl pos in
513513 let expr =
514514 binop
515515 OpAssign
516 (mk (TField (local_new_me, FInstance(cl, List.map snd cl.cl_params, cf))) t_cf pos)
516 (mk (TField (local_new_me, FInstance(cl, extract_param_types cl.cl_params, cf))) t_cf pos)
517517 (try (Hashtbl.find gen.gtparam_cast (get_path t_cf)) this_field t_cf with Not_found ->
518518 (* if not found tparam cast, it shouldn't be a valid hxgeneric *)
519519 print_endline ("Could not find a gtparam_cast for " ^ (String.concat "." (fst (get_path t_cf)) ^ "." ^ (snd (get_path t_cf))));
550550 tf_type = t_dynamic;
551551 tf_expr = mk (TBlock [
552552 (* if (typeof(T) == typeof(T2)) return this *)
553 mk (TIf (mk_typehandle_cond (List.map snd cl.cl_params) params, mk_return this, None)) basic.tvoid pos;
553 mk (TIf (mk_typehandle_cond (extract_param_types cl.cl_params) params, mk_return this, None)) basic.tvoid pos;
554554 (* var new_me = /*special create empty with tparams construct*/ *)
555555 mk (TVar (new_me_var, Some (gen.gtools.r_create_empty cl params pos))) basic.tvoid pos;
556556 (* var fields = Reflect.fields(this); *)
586586 let create_static_cast_cf gen iface cf =
587587 let p = iface.cl_pos in
588588 let basic = gen.gcon.basic in
589 let cparams = List.map (fun (s,t) -> ("To_" ^ s, TInst (map_param (get_cl_t t), []))) cf.cf_params in
589 let cparams = List.map (fun tp -> {tp with ttp_name = "To_" ^ tp.ttp_name;ttp_type = TInst (map_param (get_cl_t tp.ttp_type), [])}) cf.cf_params in
590590 let me_type = TInst(iface,[]) in
591591 let cfield = mk_class_field ~static:true "__hx_cast" (TFun(["me",false,me_type], t_dynamic)) false iface.cl_pos (Method MethNormal) (cparams) in
592 let params = List.map snd cparams in
592 let params = extract_param_types cparams in
593593
594594 let me = alloc_var "me" me_type in
595 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
595 let field = { eexpr = TField(mk_local me p, FInstance(iface, extract_param_types iface.cl_params, cf)); etype = apply_params cf.cf_params params cf.cf_type; epos = p } in
596596 let call =
597597 {
598598 eexpr = TCall(field, []);
633633 let implement_stub_cast cthis iface tl =
634634 let name = get_cast_name iface in
635635 if not (PMap.mem name cthis.cl_fields) then begin
636 let cparams = List.map (fun (s,t) -> ("To_" ^ s, TInst(map_param (get_cl_t t), []))) iface.cl_params in
636 let cparams = List.map (fun tp -> {tp with ttp_name = "To_" ^ tp.ttp_name;ttp_type = TInst(map_param (get_cl_t tp.ttp_type), [])}) iface.cl_params in
637637 let field = mk_class_field name (TFun([],t_dynamic)) false iface.cl_pos (Method MethNormal) cparams in
638 let this = { eexpr = TConst TThis; etype = TInst(cthis, List.map snd cthis.cl_params); epos = cthis.cl_pos } in
638 let this = { eexpr = TConst TThis; etype = TInst(cthis, extract_param_types cthis.cl_params); epos = cthis.cl_pos } in
639639 field.cf_expr <- Some {
640640 etype = TFun([],t_dynamic);
641641 epos = this.epos;
671671 iface.cl_meta <-
672672 (Meta.HxGen, [], cl.cl_pos)
673673 ::
674 (Meta.Custom "generic_iface", [(EConst(Int(string_of_int(List.length cl.cl_params))), cl.cl_pos)], cl.cl_pos)
674 (Meta.Custom "generic_iface", [(EConst(Int(string_of_int(List.length cl.cl_params), None)), cl.cl_pos)], cl.cl_pos)
675675 ::
676676 iface.cl_meta;
677677 Hashtbl.add ifaces cl.cl_path iface;
765765 false)
766766 | _ -> false
767767 in
768 let unifies = unifies && not (PMap.mem "cs_safe_casts" gen.gcon.defines.Define.values) in
768 let unifies = unifies && not (Common.raw_defined gen.gcon "cs_safe_casts") in
769769 (match follow t with
770770 | TInst(cl, p1 :: pl) when is_hxgeneric (TClassDecl cl) && not unifies && not (Meta.has Meta.Enum cl.cl_meta) ->
771771 let iface = Hashtbl.find ifaces cl.cl_path in
245245 let call_super ctx fn_args ret_t cf cl this_t pos =
246246 {
247247 eexpr = TCall({
248 eexpr = TField({ eexpr = TConst(TSuper); etype = this_t; epos = pos }, FInstance(cl,List.map snd cl.cl_params,cf));
248 eexpr = TField({ eexpr = TConst(TSuper); etype = this_t; epos = pos }, FInstance(cl,extract_param_types cl.cl_params,cf));
249249 etype = TFun(fun_args fn_args, ret_t);
250250 epos = pos;
251251 }, List.map (fun (v,_) -> mk_local v pos) fn_args);
279279 ]
280280 in
281281
282 let this_t = TInst(cl, List.map snd cl.cl_params) in
282 let this_t = TInst(cl, extract_param_types cl.cl_params) in
283283 let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in
284284 let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in
285285
466466
467467 let get_delete_field ctx cl is_dynamic =
468468 let pos = cl.cl_pos in
469 let this_t = TInst(cl, List.map snd cl.cl_params) in
469 let this_t = TInst(cl, extract_param_types cl.cl_params) in
470470 let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in
471471 let gen = ctx.rcf_gen in
472472 let basic = gen.gcon.basic in
686686 let pos = cl.cl_pos in
687687 let is_override = is_override cl in
688688
689 (* let this = { eexpr = TConst(TThis); etype = TInst(cl, List.map snd cl.cl_params); epos = pos } in *)
689 (* let this = { eexpr = TConst(TThis); etype = TInst(cl, extract_param_types cl.cl_params); epos = pos } in *)
690690
691691 let mk_throw str pos =
692692 let e = ctx.rcf_mk_exception str pos in
805805 let handle_prop = alloc_var "handleProperties" basic.tbool in
806806 let handle_prop_local = mk_local handle_prop pos in
807807
808 let this = { eexpr = TConst TThis; etype = TInst(cl, List.map snd cl.cl_params); epos = pos } in
808 let this = { eexpr = TConst TThis; etype = TInst(cl, extract_param_types cl.cl_params); epos = pos } in
809809 let mk_this_call_raw name fun_t params =
810810 { eexpr = TCall( { (mk_field_access gen this name pos) with etype = fun_t; }, params ); etype = snd (get_fun fun_t); epos = pos }
811811 in
816816
817817 let maybe_cast e = e in
818818
819 let t = TInst(cl, List.map snd cl.cl_params) in
819 let t = TInst(cl, extract_param_types cl.cl_params) in
820820
821821 (* if it's not latest hxgen class -> check super *)
822822 let mk_do_default args do_default =
828828 fun () ->
829829 mk_return {
830830 eexpr = TCall(
831 { eexpr = TField({ eexpr = TConst TSuper; etype = t; epos = pos }, FInstance(cl, List.map snd cl.cl_params, cfield)); etype = !fun_type; epos = pos },
831 { eexpr = TField({ eexpr = TConst TSuper; etype = t; epos = pos }, FInstance(cl, extract_param_types cl.cl_params, cfield)); etype = !fun_type; epos = pos },
832832 (List.map (fun (v,_) -> mk_local v pos) args) );
833833 etype = if is_float then basic.tfloat else t_dynamic;
834834 epos = pos;
848848 in
849849
850850 let do_field cf cf_type =
851 let get_field ethis = { eexpr = TField (ethis, FInstance(cl, List.map snd cl.cl_params, cf)); etype = cf_type; epos = pos } in
851 let get_field ethis = { eexpr = TField (ethis, FInstance(cl, extract_param_types cl.cl_params, cf)); etype = cf_type; epos = pos } in
852852 let this = { eexpr = TConst(TThis); etype = t; epos = pos } in
853853 let value_local = if is_float then match follow cf_type with
854854 | TInst({ cl_kind = KTypeParameter _ }, _) ->
935935 eexpr = TIf(
936936 handle_prop_local,
937937 mk_this_call_raw ("get_" ^ cf.cf_name) (TFun(["value",false,cf.cf_type], cf.cf_type)) [],
938 Some { eexpr = TField (ethis, FInstance(cl, List.map snd cl.cl_params, cf)); etype = cf_type; epos = pos }
938 Some { eexpr = TField (ethis, FInstance(cl, extract_param_types cl.cl_params, cf)); etype = cf_type; epos = pos }
939939 );
940940 etype = cf_type;
941941 epos = pos;
942942 }
943943 | Var _
944 | Method MethDynamic -> { eexpr = TField (ethis, FInstance(cl,List.map snd cl.cl_params,cf)); etype = cf_type; epos = pos }
944 | Method MethDynamic -> { eexpr = TField (ethis, FInstance(cl,extract_param_types cl.cl_params,cf)); etype = cf_type; epos = pos }
945945 | _ ->
946 { eexpr = TField (this, FClosure(Some (cl,List.map snd cl.cl_params), cf)); etype = cf_type; epos = pos }
946 { eexpr = TField (this, FClosure(Some (cl,extract_param_types cl.cl_params), cf)); etype = cf_type; epos = pos }
947947 in
948948
949949 let do_field cf cf_type =
10761076 *)
10771077 let exprs =
10781078 if is_override cl then
1079 let tparams = List.map snd cl.cl_params in
1079 let tparams = extract_param_types cl.cl_params in
10801080 let esuper = mk (TConst TSuper) (TInst(cl, tparams)) pos in
10811081 let efield = mk (TField (esuper, FInstance (cl, tparams, cf))) t pos in
10821082 [mk (TCall (efield, [base_arr])) basic.tvoid pos]
11391139 let all_args = field_args @ [ dynamic_arg, None ] in
11401140 let fun_t = TFun(fun_args all_args, t_dynamic) in
11411141
1142 let this_t = TInst(cl, List.map snd cl.cl_params) in
1142 let this_t = TInst(cl, extract_param_types cl.cl_params) in
11431143 let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in
11441144
11451145 let mk_this_call_raw name fun_t params =
12791279 let pos = cl.cl_pos in
12801280 let gen = ctx.rcf_gen in
12811281
1282 let this_t = TInst(cl, List.map snd cl.cl_params) in
1282 let this_t = TInst(cl, extract_param_types cl.cl_params) in
12831283 let this = { eexpr = TConst(TThis); etype = this_t ; epos = pos } in
12841284 let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in
12851285
13381338 let field_args, _ = field_type_args ctx pos in
13391339 let obj_arg = alloc_var "target" (TInst(ctx.rcf_object_iface, [])) in
13401340
1341 let this_t = TInst(cl, List.map snd cl.cl_params) in
1341 let this_t = TInst(cl, extract_param_types cl.cl_params) in
13421342 let this = { eexpr = TConst(TThis); etype = this_t ; epos = pos } in
13431343 let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in
13441344
4646 | _ -> Globals.die "" __LOC__
4747 in
4848
49 let iter_types (nt,t) =
50 let cls = get_cls t in
49 let iter_types tp =
50 let cls = get_cls tp.ttp_type in
5151 let orig = cls.cl_path in
5252 check_type (snd orig) (fun name -> cls.cl_path <- (fst orig, name))
5353 in
5454
5555 let save_params save params =
56 List.fold_left (fun save (_,t) ->
57 let cls = get_cls t in
58 (cls.cl_path,t) :: save) save params
56 List.fold_left (fun save tp ->
57 let cls = get_cls tp.ttp_type in
58 (cls.cl_path,tp.ttp_type) :: save) save params
5959 in
6060
6161 List.iter (function
6262 | TParenthesis(e) | TMeta(_,e) -> get_constant_expr e
6363 | _ -> None
6464
65 let init com java_mode =
65 let init gen java_mode =
6666 let should_warn = false in
6767
6868 let do_warn =
69 if should_warn then com.warning "Unreachable code" else (fun pos -> ())
69 if should_warn then gen.gwarning WGenerator "Unreachable code" else (fun pos -> ())
7070 in
7171
7272 let return_loop expr kind =
207207 let priority = min_dep -. 100.0
208208
209209 let configure gen java_mode =
210 let run = init gen.gcon java_mode in
210 let run = init gen java_mode in
211211 gen.gsyntax_filters#add "unreachable_synf" (PCustom priority) run
121121 ) args in
122122 node "f" (("a",names) :: values) (List.map gen_type (args @ [r]))
123123 | TAnon a -> node "a" [] (pmap (fun f -> gen_field [] { f with cf_flags = unset_flag f.cf_flags (int_of_class_field_flag CfPublic) }) a.a_fields)
124 | TDynamic t2 -> node "d" [] (if t == t2 then [] else [gen_type t2])
124 | TDynamic None -> node "d" [] []
125 | TDynamic (Some t2) -> node "d" [] [gen_type t2]
125126 | TLazy f -> gen_type (lazy_type f)
126127
127128 and gen_type_decl n t pl =
156157 in
157158 att,get_value_meta f.cf_meta
158159 ) in
159 let att = (match f.cf_params with [] -> att | l -> ("params", String.concat ":" (List.map (fun (n,_) -> n) l)) :: att) in
160 let att = (match f.cf_params with [] -> att | l -> ("params", String.concat ":" (List.map extract_param_name l)) :: att) in
160161 let overloads = match List.map (gen_field []) f.cf_overloads with
161162 | [] -> []
162163 | nl -> [node "overloads" [] nl]
199200 let mpriv = (if priv then [("private","1")] else []) in
200201 let mpath = (if m.m_path <> path then [("module",snd (gen_path m.m_path false))] else []) in
201202 let file = (if ipos && pos <> null_pos then [("file",pos.pfile)] else []) in
202 gen_path path priv :: ("params", String.concat ":" (List.map fst params)) :: (file @ mpriv @ mpath)
203 gen_path path priv :: ("params", String.concat ":" (List.map extract_param_name params)) :: (file @ mpriv @ mpath)
203204
204205 let gen_class_path name (c,pl) =
205206 node name [("path",s_type_path (tpath (TClassDecl c)))] (List.map gen_type pl)
215216 match t with
216217 | TClassDecl c ->
217218 let stats = List.filter (fun cf ->
218 cf.cf_name <> "__meta__" && not (Meta.has Meta.GenericInstance cf.cf_meta)
219 cf.cf_name <> "__meta__" && not (Meta.has Meta.GenericInstance cf.cf_meta) && not (Meta.has Meta.NoDoc cf.cf_meta)
219220 ) c.cl_ordered_statics in
220221 let stats = List.map (gen_field ["static","1"]) stats in
221222 let fields = List.filter (fun cf ->
252253 let doc = gen_doc_opt a.a_doc in
253254 let meta = gen_meta a.a_meta in
254255 let mk_cast t = node "icast" [] [gen_type t] in
255 let mk_field_cast (t,cf) = node "icast" ["field",cf.cf_name] [gen_type t] in
256 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
257 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
256 let mk_field_cast (t,cf) = if Meta.has Meta.NoDoc cf.cf_meta then None else Some (node "icast" ["field",cf.cf_name] [gen_type t]) in
257 let sub = (match a.a_from,a.a_from_field with [],[] -> [] | l1,l2 -> [node "from" [] ((List.map mk_cast l1) @ (ExtList.List.filter_map mk_field_cast l2))]) in
258 let super = (match a.a_to,a.a_to_field with [],[] -> [] | l1,l2 -> [node "to" [] ((List.map mk_cast l1) @ (ExtList.List.filter_map mk_field_cast l2))]) in
258259 let impl = (match a.a_impl with None -> [] | Some c -> [node "impl" [] [gen_type_decl com pos (TClassDecl c)]]) in
259260 let this = [node "this" [] [gen_type a.a_this]] in
260261 node "abstract" (gen_type_params pos a.a_private (tpath t) a.a_params a.a_pos m) (sub @ this @ super @ doc @ meta @ impl)
3434 is_std : bool;
3535 }
3636
37 exception ConversionError of string * pos
38
39 let error s p = raise (ConversionError (s, p))
37 exception ConversionError of located
38
39 let error s p = raise (ConversionError (located s p))
4040
4141 let is_haxe_keyword = function
4242 | "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true
171171 let convert_constant ctx p const =
172172 Option.map_default (function
173173 | ConstString s -> Some (EConst (String(s,SDoubleQuotes)), p)
174 | ConstInt i -> Some (EConst (Int (Printf.sprintf "%ld" i)), p)
175 | ConstFloat f | ConstDouble f -> Some (EConst (Float (Printf.sprintf "%E" f)), p)
174 | ConstInt i -> Some (EConst (Int (Printf.sprintf "%ld" i, None)), p)
175 | ConstFloat f | ConstDouble f -> Some (EConst (Float (Printf.sprintf "%E" f, None)), p)
176176 | _ -> None) None const
177177
178178 let convert_constraints ctx p tl = match tl with
191191 tp_name = jname_to_hx name,null_pos;
192192 tp_params = [];
193193 tp_constraints = convert_constraints ctx p constraints;
194 tp_default = None;
194195 tp_meta = [];
195196 }
196197
213214 else match fst jc.cpath with
214215 | ("java" | "javax" | "org") :: _ -> true
215216 | _ -> false
217
218 (**
219 `haxe.Rest<T>` auto-boxes primitive types.
220 That means we can't use it as varargs for extern methods.
221 E.g externs with `int` varargs are represented as `int[]` at run time
222 while `haxe.Rest<Int>` is actually `java.lang.Integer[]`.
223 *)
224 let is_eligible_for_haxe_rest_args arg_type =
225 match arg_type with
226 | TByte | TChar | TDouble | TFloat | TInt | TLong | TShort | TBool -> false
227 | _ -> true
216228
217229 let convert_java_enum ctx p pe =
218230 let meta = ref (get_canonical ctx p (fst pe.cpath) (snd pe.cpath) :: [Meta.Native, [EConst (String (real_java_path ctx pe.cpath,SDoubleQuotes) ), p], p ]) in
253265 in
254266 let jf_constant = ref field.jf_constant in
255267 let readonly = ref false in
268 let is_varargs = ref false in
256269
257270 List.iter (function
258271 | JPublic -> cff_access := (APublic,null_pos) :: !cff_access
273286 (* | JSynchronized -> cff_meta := (Meta.Synchronized, [], p) :: !cff_meta *)
274287 | JVolatile -> cff_meta := (Meta.Volatile, [], p) :: !cff_meta
275288 | JTransient -> cff_meta := (Meta.Transient, [], p) :: !cff_meta
276 (* | JVarArgs -> cff_meta := (Meta.VarArgs, [], p) :: !cff_meta *)
289 | JVarArgs -> is_varargs := true
277290 | JAbstract when not is_interface ->
278291 cff_access := (AAbstract, p) :: !cff_access
279292 | _ -> ()
340353 | c :: others -> ctx.jtparams <- (c @ field.jf_types) :: others
341354 | [] -> ctx.jtparams <- field.jf_types :: []);
342355 let i = ref 0 in
356 let args_count = List.length args in
343357 let args = List.map (fun s ->
344358 incr i;
345 (local_names !i,null_pos), false, [], Some(convert_signature ctx p s,null_pos), None
359 let hx_sig =
360 match s with
361 | TArray (s1,_) when !is_varargs && !i = args_count && is_eligible_for_haxe_rest_args s1 ->
362 mk_type_path ctx (["haxe"], "Rest") [TPType (convert_signature ctx p s1,null_pos)]
363 | _ ->
364 convert_signature ctx null_pos s
365 in
366 (local_names !i,null_pos), false, [], Some(hx_sig,null_pos), None
346367 ) args in
347368 let t = Option.map_default (convert_signature ctx p) (mk_type_path ctx ([], "Void") []) ret in
348369 cff_access := (AOverload,p) :: !cff_access;
352373 tp_name = name,null_pos;
353374 tp_params = [];
354375 tp_constraints = convert_constraints ctx p (ext :: impl);
376 tp_default = None;
355377 tp_meta = [];
356378 }
357379 | (name, None, impl) ->
359381 tp_name = name,null_pos;
360382 tp_params = [];
361383 tp_constraints = convert_constraints ctx p impl;
384 tp_default = None;
362385 tp_meta = [];
363386 }
364387 ) field.jf_types in
372395 })
373396 | _ -> error "Method signature was expected" p
374397 in
398 if field.jf_code <> None && is_interface then cff_meta := (Meta.JavaDefault,[],cff_pos) :: !cff_meta;
375399 let cff_name, cff_meta =
376400 match String.get cff_name 0 with
377401 | '%' ->
390414 String.concat "_" parts,
391415 (Meta.Native, [EConst (String (cff_name,SDoubleQuotes) ), cff_pos], cff_pos) :: !cff_meta
392416 in
393 if PMap.mem "java_loader_debug" ctx.jcom.defines.Define.values then
417 if Common.raw_defined ctx.jcom "java_loader_debug" then
394418 Printf.printf "\t%s%sfield %s : %s\n" (if List.mem_assoc AStatic !cff_access then "static " else "") (if List.mem_assoc AOverride !cff_access then "override " else "") cff_name (s_sig field.jf_signature);
395419
396420 {
432456 [convert_java_enum ctx p jc]
433457 | false ->
434458 let flags = ref [HExtern] in
435 if PMap.mem "java_loader_debug" ctx.jcom.defines.Define.values then begin
459 if Common.raw_defined ctx.jcom "java_loader_debug" then begin
436460 let sup = jc.csuper :: jc.cinterfaces in
437461 print_endline ("converting " ^ (if List.mem JAbstract jc.cflags then "abstract " else "") ^ JData.path_s jc.cpath ^ " : " ^ (String.concat ", " (List.map s_sig sup)));
438462 end;
12411265
12421266 let before_generate con =
12431267 let java_ver = try
1244 int_of_string (PMap.find "java_ver" con.defines.Define.values)
1268 int_of_string (Common.defined_value con Define.JavaVer)
12451269 with | Not_found ->
12461270 Common.define_value con Define.JavaVer "7";
12471271 7
195195
196196 let parse_formal_type_params s = match s.[0] with
197197 | '<' ->
198 let rec read_id i =
199 match s.[i] with
200 | ':' | '>' -> i
201 | _ -> read_id (i + 1)
198 let rec read_id i = match s.[i] with
199 | ':' | '>' -> i
200 | _ -> read_id (i + 1)
202201 in
203202 let len = String.length s in
204203 let rec parse_params idx acc =
205 let idi = read_id (idx + 1) in
206 let id = String.sub s (idx + 1) (idi - idx - 1) in
207 (* next must be a : *)
208 (match s.[idi] with | ':' -> () | _ -> failwith ("Invalid formal type signature character: " ^ Char.escaped s.[idi] ^ " ; from " ^ s));
209 let ext, l = match s.[idi + 1] with
210 | ':' | '>' -> None, idi + 1
211 | _ ->
212 let sgn, l = parse_signature_part (String.sub s (idi + 1) (len - idi - 1)) in
213 Some sgn, l + idi + 1
214 in
215 let rec loop idx acc =
216 match s.[idx] with
217 | ':' ->
218 let ifacesig, ifacei = parse_signature_part (String.sub s (idx + 1) (len - idx - 1)) in
219 loop (idx + ifacei + 1) (ifacesig :: acc)
220 | _ -> acc, idx
221 in
222 let ifaces, idx = loop l [] in
223 let acc = (id, ext, ifaces) :: acc in
224 if s.[idx] = '>' then List.rev acc, idx + 1 else parse_params (idx - 1) acc
204 let idi = read_id (idx + 1) in
205 let id = String.sub s (idx + 1) (idi - idx - 1) in
206 (* next must be a : *)
207 (match s.[idi] with | ':' -> () | _ -> failwith ("Invalid formal type signature character: " ^ Char.escaped s.[idi] ^ " ; from " ^ s));
208 let ext, l = match s.[idi + 1] with
209 | ':' | '>' ->
210 None, idi + 1
211 | _ ->
212 let sgn, l = parse_signature_part (String.sub s (idi + 1) (len - idi - 1)) in
213 Some sgn, l + idi + 1
214 in
215 let rec loop idx acc =
216 match s.[idx] with
217 | ':' ->
218 let ifacesig, ifacei = parse_signature_part (String.sub s (idx + 1) (len - idx - 1)) in
219 loop (idx + ifacei + 1) (ifacesig :: acc)
220 | _ ->
221 acc, idx
222 in
223 let ifaces, idx = loop l [] in
224 let acc = (id, ext, ifaces) :: acc in
225 if s.[idx] = '>' then List.rev acc, idx + 1 else parse_params (idx - 1) acc
225226 in
226227 parse_params 0 []
227228 | _ -> [], 0
719720 tp_name = (name,p);
720721 tp_params = [];
721722 tp_meta = [];
723 tp_default = None;
722724 tp_constraints = match constraints with
723725 | [] -> None
724 | _ -> Some (CTIntersection constraints,p)
726 | _ -> Some (CTIntersection constraints,p);
725727 } in
726728 tp
727729
757759 PMap.add s (ct_type_param s) acc
758760 ) acc params
759761
762 (**
763 `haxe.Rest<T>` auto-boxes primitive types.
764 That means we can't use it as varargs for extern methods.
765 E.g externs with `int` varargs are represented as `int[]` at run time
766 while `haxe.Rest<Int>` is actually `java.lang.Integer[]`.
767 *)
768 let is_eligible_for_haxe_rest_args arg_type =
769 match arg_type with
770 | TByte | TChar | TDouble | TFloat | TInt | TLong | TShort | TBool -> false
771 | _ -> true
772
760773 let convert_field ctx is_method (jc : jclass) (is_interface : bool) (jf : jfield) p =
761774 let ctx = {
762775 type_params = type_param_lut ctx.type_params jf.jf_types;
777790 add_access (AOverride,null_pos);
778791 | _ -> ()
779792 ) ann
793 | AttrCode _ when is_interface ->
794 add_meta (Meta.JavaDefault,[],p)
780795 | _ -> ()
781796 ) jf.jf_attributes;
782797 let add_native_meta () =
844859 begin match jf.jf_descriptor with
845860 | TMethod(args,ret) ->
846861 let local_names = extract_local_names() in
862 let args_count = List.length args
863 and is_varargs = AccessFlags.has_flag jf.jf_flags MVarargs in
847864 let convert_arg i jsig =
848865 let name = local_names (i + 1) in
849 ((name,p),false,[],Some (convert_signature ctx p jsig,p),None)
866 let hx_sig =
867 match jsig with
868 | TArray (jsig1,_) when is_varargs && i + 1 = args_count && is_eligible_for_haxe_rest_args jsig1 ->
869 mk_type_path (["haxe"], "Rest") [TPType (convert_signature ctx p jsig1,p)]
870 | _ ->
871 convert_signature ctx p jsig
872 in
873 ((name,p),false,[],Some (hx_sig,p),None)
850874 in
851875 let f = {
852876 f_params = List.map (fun tp -> convert_type_parameter ctx tp p) jf.jf_types;
1111 let rec loop params1 params2 = match params1,params2 with
1212 | [],[] ->
1313 true
14 | (n1,t1) :: params1,(n2,t2) :: params2 ->
15 let constraints_equal t1 t2 = match follow t1,t2 with
14 | tp1 :: params1,tp2 :: params2 ->
15 let constraints_equal t1 t2 = match follow t1,follow t2 with
1616 | TInst({cl_kind = KTypeParameter tl1},_),TInst({cl_kind = KTypeParameter tl2},_) ->
1717 Ast.safe_for_all2 f_eq tl1 tl2
1818 | _ ->
1919 false
2020 in
21 n1 = n2 && constraints_equal t1 t2 && loop params1 params2
21 tp1.ttp_name = tp2.ttp_name && constraints_equal tp1.ttp_type tp2.ttp_type && loop params1 params2
2222 | [],_
2323 | _,[] ->
2424 false
3838 loop tl1 tl2
3939 in
4040 let compare_types () =
41 let t1 = follow (apply_params f1.cf_params (List.map (fun (_,t) -> t) f2.cf_params) t1) in
41 let t1 = follow (apply_params f1.cf_params (extract_param_types f2.cf_params) t1) in
4242 match t1,follow t2 with
4343 | TFun(tl1,_),TFun(tl2,_) ->
4444 compare_arguments tl1 tl2
8383
8484 let get_overloads (com : Common.context) c i =
8585 try
86 Hashtbl.find com.overload_cache (c.cl_path,i)
86 com.overload_cache#find (c.cl_path,i)
8787 with Not_found ->
8888 let l = collect_overloads (fun t -> t) c i in
89 Hashtbl.add com.overload_cache (c.cl_path,i) l;
89 com.overload_cache#add (c.cl_path,i) l;
9090 l
9191
9292 (** Overload resolution **)
105105 t
106106 | TAbstract(a,tl) -> simplify_t (Abstract.get_underlying_type a tl)
107107 | TType(t, tl) ->
108 simplify_t (apply_params t.t_params tl t.t_type)
108 simplify_t (apply_typedef t tl)
109109 | TMono r -> (match r.tm_type with
110110 | Some t -> simplify_t t
111111 | None -> t_dynamic)
257257 in
258258 (* convert compatible into ( rate * compatible_type ) list *)
259259 let rec mk_rate acc elist args = match elist, args with
260 | [], [] -> acc
261 | _ :: elist, (_,true,_) :: args -> mk_rate acc elist args
260 | [], [] ->
261 acc,false
262 | _ :: elist, (_,true,_) :: args ->
263 mk_rate acc elist args
262264 | elist, [n,o,t] when ExtType.is_rest (follow t) ->
263265 let t = match follow t with
264266 | TAbstract({a_path=["haxe"],"Rest"},[t]) -> t
265267 | _ -> die "" __LOC__
266268 in
267269 let rates = List.map (rate_arg t) elist in
268 acc @ rates
270 acc @ rates,true
269271 | e :: elist, (n,o,t) :: args ->
270272 mk_rate ((rate_arg t e) :: acc) elist args
271273 | [],_ ->
272274 (* this can happen on pf_pad_nulls = false targets, see #10434 *)
273 acc
275 acc,false
274276 | _ -> die "" __LOC__
275277 in
276278
277 let rated = ref [] in
278 List.iter (fun fcc -> match fcc.fc_type with
279 | TFun(args,ret) -> (try
280 rated := ( fcc, mk_rate [] fcc.fc_args args ) :: !rated
281 with | Not_found -> ())
282 | _ -> die "" __LOC__
283 ) compatible;
284
285 let rec loop best rem = match best, rem with
286 | _, [] -> best
287 | [], r1 :: rem -> loop [r1] rem
288 | (bover, bargs) :: b1, (rover, rargs) :: rem ->
289 if is_best bargs rargs then
290 loop best rem
291 else if is_best rargs bargs then
292 loop (loop b1 [rover,rargs]) rem
293 else (* equally specific *)
294 loop ( (rover,rargs) :: best ) rem
295 in
296
297 let r = loop [] !rated in
298 List.map fst r
279 let rec loop best l = match l with
280 | [] ->
281 begin match best with
282 | Some(_,_,l) -> List.rev l
283 | None -> []
284 end
285 | fcc :: l ->
286 let args,ret = match follow fcc.fc_type with
287 | TFun(args,ret) -> args,ret
288 | _ -> die "" __LOC__
289 in
290 begin try
291 let (rate,is_rest) = mk_rate [] fcc.fc_args args in
292 let (best_rate,best_is_rest,best_l) = match best with
293 | None ->
294 (* If it's the first one, assume it's the best *)
295 (rate,is_rest,[fcc])
296 | Some(best_rate,best_is_rest,best_l) ->
297 if is_best rate best_rate then
298 (rate,is_rest,[fcc])
299 else if is_best best_rate rate then
300 (best_rate,best_is_rest,best_l)
301 (* If they are equal, we prefer the one without Rest (issue #10205) *)
302 else if is_rest && not best_is_rest then
303 (best_rate,best_is_rest,best_l)
304 else if not is_rest && best_is_rest then
305 (rate,is_rest,[fcc])
306 else
307 (best_rate,best_is_rest,fcc :: best_l)
308 in
309 loop (Some(best_rate,best_is_rest,best_l)) l
310 with Not_found ->
311 loop best l
312 end
313 in
314 loop None compatible
299315 end
269269 | HVBool b ->
270270 Some (Ident (if b then "true" else "false"))
271271 | HVInt i | HVUInt i ->
272 Some (Int (Int32.to_string i))
272 Some (Int (Int32.to_string i, None))
273273 | HVFloat f ->
274 Some (Float (Numeric.float_repres f))
274 Some (Float (Numeric.float_repres f, None))
275275 ) in
276276 match v with
277277 | None -> None
544544
545545 let parse_swf com file =
546546 let t = Timer.timer ["read";"swf"] in
547 let is_swc = file_extension file = "swc" || file_extension file = "ane" in
547 let is_swc = Path.file_extension file = "swc" || Path.file_extension file = "ane" in
548548 let ch = if is_swc then begin
549549 let zip = Zip.open_in file in
550550 try
568568 IO.close_in ch;
569569 List.iter (fun t ->
570570 match t.tdata with
571 | TActionScript3 (id,as3) when not com.debug && not com.display.DisplayTypes.DisplayMode.dms_display ->
571 | TActionScript3 (id,as3) ->
572572 t.tdata <- TActionScript3 (id,remove_debug_infos as3)
573573 | _ -> ()
574574 ) tags;
0 open Globals
1 open Common
2 open CompilationContext
3
4 let limit_string s offset =
5 let rest = 80 - offset in
6 let words = ExtString.String.nsplit s " " in
7 let rec loop i words = match words with
8 | word :: words ->
9 if String.length word + i + 1 > rest then (Printf.sprintf "\n%*s" offset "") :: word :: loop (String.length word) words
10 else (if i = 0 then "" else " ") :: word :: loop (i + 1 + String.length word) words
11 | [] ->
12 []
13 in
14 String.concat "" (loop 0 words)
15
16 let usage_string ?(print_cat=true) arg_spec usage =
17 let make_label = fun names hint -> Printf.sprintf "%s %s" (String.concat ", " names) hint in
18 let args = (List.filter (fun (cat, ok, dep, spec, hint, doc) -> (List.length ok) > 0) arg_spec) in
19 let cat_order = ["Target";"Compilation";"Optimization";"Debug";"Batch";"Services";"Compilation Server";"Target-specific";"Miscellaneous"] in
20 let cats = List.filter (fun x -> List.mem x (List.map (fun (cat, _, _, _, _, _) -> cat) args)) cat_order in
21 let max_length = List.fold_left max 0 (List.map String.length (List.map (fun (_, ok, _, _, hint, _) -> make_label ok hint) args)) in
22 usage ^ (String.concat "\n" (List.flatten (List.map (fun cat -> (if print_cat then ["\n"^cat^":"] else []) @ (List.map (fun (cat, ok, dep, spec, hint, doc) ->
23 let label = make_label ok hint in
24 Printf.sprintf " %s%s %s" label (String.make (max_length - (String.length label)) ' ') doc
25 ) (List.filter (fun (cat', _, _, _, _, _) -> (if List.mem cat' cat_order then cat' else "Miscellaneous") = cat) args))) cats)))
26
27 let process_args arg_spec =
28 List.flatten(List.map (fun (cat, ok, dep, spec, hint, doc) ->
29 (* official argument names *)
30 (List.map (fun (arg) -> (arg, spec, doc)) ok) @
31 let dep_fun arg spec = () in
32 let dep_spec arg spec = match spec with
33 | Arg.String f -> Arg.String (fun x -> dep_fun arg spec; f x)
34 | Arg.Unit f -> Arg.Unit (fun x -> dep_fun arg spec; f x)
35 | Arg.Bool f -> Arg.Bool (fun x -> dep_fun arg spec; f x)
36 | _ -> spec in
37 (List.map (fun (arg) -> (arg, dep_spec arg spec, doc)) dep)
38 ) arg_spec)
39
40 let parse_args com =
41 let usage = Printf.sprintf
42 "Haxe Compiler %s - (C)2005-2022 Haxe Foundation\nUsage: haxe%s <target> [options] [hxml files and dot paths...]\n"
43 s_version_full (if Sys.os_type = "Win32" then ".exe" else "")
44 in
45 let actx = {
46 classes = [([],"Std")];
47 xml_out = None;
48 json_out = None;
49 cmds = [];
50 config_macros = [];
51 no_output = false;
52 did_something = false;
53 force_typing = false;
54 pre_compilation = [];
55 interp = false;
56 jvm_flag = false;
57 swf_version = false;
58 native_libs = [];
59 raise_usage = (fun () -> ());
60 display_arg = None;
61 deprecations = [];
62 } in
63 let add_deprecation s =
64 actx.deprecations <- s :: actx.deprecations
65 in
66 let add_native_lib file extern = actx.native_libs <- (file,extern) :: actx.native_libs in
67 let basic_args_spec = [
68 ("Target",["--js"],["-js"],Arg.String (set_platform com Js),"<file>","generate JavaScript code into target file");
69 ("Target",["--lua"],["-lua"],Arg.String (set_platform com Lua),"<file>","generate Lua code into target file");
70 ("Target",["--swf"],["-swf"],Arg.String (set_platform com Flash),"<file>","generate Flash SWF bytecode into target file");
71 ("Target",["--neko"],["-neko"],Arg.String (set_platform com Neko),"<file>","generate Neko bytecode into target file");
72 ("Target",["--php"],["-php"],Arg.String (fun dir ->
73 actx.classes <- (["php"],"Boot") :: actx.classes;
74 set_platform com Php dir;
75 ),"<directory>","generate PHP code into target directory");
76 ("Target",["--cpp"],["-cpp"],Arg.String (fun dir ->
77 set_platform com Cpp dir;
78 ),"<directory>","generate C++ code into target directory");
79 ("Target",["--cppia"],["-cppia"],Arg.String (fun file ->
80 Common.define com Define.Cppia;
81 set_platform com Cpp file;
82 ),"<file>","generate Cppia bytecode into target file");
83 ("Target",["--cs"],["-cs"],Arg.String (fun dir ->
84 set_platform com Cs dir;
85 ),"<directory>","generate C# code into target directory");
86 ("Target",["--java"],["-java"],Arg.String (fun dir ->
87 set_platform com Java dir;
88 ),"<directory>","generate Java code into target directory");
89 ("Target",["--jvm"],[],Arg.String (fun dir ->
90 Common.define com Define.Jvm;
91 actx.jvm_flag <- true;
92 set_platform com Java dir;
93 ),"<file>","generate JVM bytecode into target file");
94 ("Target",["--python"],["-python"],Arg.String (fun dir ->
95 set_platform com Python dir;
96 ),"<file>","generate Python code into target file");
97 ("Target",["--hl"],["-hl"],Arg.String (fun file ->
98 set_platform com Hl file;
99 ),"<file>","generate HashLink .hl bytecode or .c code into target file");
100 ("Target",[],["-x"], Arg.String (fun cl ->
101 let cpath = Path.parse_type_path cl in
102 (match com.main_class with
103 | Some c -> if cpath <> c then raise (Arg.Bad "Multiple --main classes specified")
104 | None -> com.main_class <- Some cpath);
105 actx.classes <- cpath :: actx.classes;
106 Common.define com Define.Interp;
107 set_platform com (!Globals.macro_platform) "";
108 actx.interp <- true;
109 ),"<class>","interpret the program using internal macro system");
110 ("Target",["--interp"],[], Arg.Unit (fun() ->
111 Common.define com Define.Interp;
112 set_platform com (!Globals.macro_platform) "";
113 actx.interp <- true;
114 ),"","interpret the program using internal macro system");
115 ("Target",["--run"],[], Arg.Unit (fun() ->
116 raise (Arg.Bad "--run requires an argument: a Haxe module name")
117 ), "<module> [args...]","interpret a Haxe module with command line arguments");
118 ("Compilation",["-p";"--class-path"],["-cp"],Arg.String (fun path ->
119 com.class_path <- Path.add_trailing_slash path :: com.class_path
120 ),"<path>","add a directory to find source files");
121 ("Compilation",["-m";"--main"],["-main"],Arg.String (fun cl ->
122 if com.main_class <> None then raise (Arg.Bad "Multiple --main classes specified");
123 let cpath = Path.parse_type_path cl in
124 com.main_class <- Some cpath;
125 actx.classes <- cpath :: actx.classes
126 ),"<class>","select startup class");
127 ("Compilation",["-L";"--library"],["-lib"],Arg.String (fun _ -> ()),"<name[:ver]>","use a haxelib library");
128 ("Compilation",["-D";"--define"],[],Arg.String (fun var ->
129 let flag, value = try let split = ExtString.String.split var "=" in (fst split, Some (snd split)) with _ -> var, None in
130 match value with
131 | Some value -> Common.external_define_value com flag value
132 | None -> Common.external_define com flag;
133 ),"<var[=value]>","define a conditional compilation flag");
134 ("Debug",["-v";"--verbose"],[],Arg.Unit (fun () ->
135 com.verbose <- true
136 ),"","turn on verbose mode");
137 ("Debug",["--debug"],["-debug"], Arg.Unit (fun() ->
138 Common.define com Define.Debug;
139 com.debug <- true;
140 ),"","add debug information to the compiled code");
141 ("Miscellaneous",["--version"],["-version"],Arg.Unit (fun() ->
142 com.info s_version_full null_pos;
143 actx.did_something <- true;
144 ),"","print version and exit");
145 ("Miscellaneous", ["-h";"--help"], ["-help"], Arg.Unit (fun () ->
146 raise (Arg.Help "")
147 ),"","show extended help information");
148 ("Miscellaneous",["--help-defines"],[], Arg.Unit (fun() ->
149 let all,max_length = Define.get_documentation_list com.user_defines in
150 let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
151 List.iter (fun msg -> com.print (msg ^ "\n")) all;
152 actx.did_something <- true
153 ),"","print help for all compiler specific defines");
154 ("Miscellaneous",["--help-user-defines"],[], Arg.Unit (fun() ->
155 actx.did_something <- true;
156 com.callbacks#add_after_init_macros (fun() ->
157 let all,max_length = Define.get_user_documentation_list com.user_defines in
158 let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
159 List.iter (fun msg -> com.print (msg ^ "\n")) all;
160 exit 0
161 )
162 ),"","print help for all user defines");
163 ("Miscellaneous",["--help-metas"],[], Arg.Unit (fun() ->
164 let all,max_length = Meta.get_documentation_list com.user_metas in
165 let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
166 List.iter (fun msg -> com.print (msg ^ "\n")) all;
167 actx.did_something <- true
168 ),"","print help for all compiler metadatas");
169 ("Miscellaneous",["--help-user-metas"],[], Arg.Unit (fun() ->
170 actx.did_something <- true;
171 com.callbacks#add_after_init_macros (fun() ->
172 let all,max_length = Meta.get_user_documentation_list com.user_metas in
173 let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
174 List.iter (fun msg -> com.print (msg ^ "\n")) all;
175 exit 0
176 )
177 ),"","print help for all user metadatas");
178 ] in
179 let adv_args_spec = [
180 ("Optimization",["--dce"],["-dce"],Arg.String (fun mode ->
181 (match mode with
182 | "std" | "full" | "no" -> ()
183 | _ -> raise (Arg.Bad "Invalid DCE mode, expected std | full | no"));
184 Common.define_value com Define.Dce mode
185 ),"[std|full|no]","set the dead code elimination mode (default std)");
186 ("Target-specific",["--swf-version"],["-swf-version"],Arg.Float (fun v ->
187 if not actx.swf_version || com.flash_version < v then com.flash_version <- v;
188 actx.swf_version <- true;
189 ),"<version>","change the SWF version");
190 ("Target-specific",["--swf-header"],["-swf-header"],Arg.String (fun h ->
191 add_deprecation "-swf-header has been deprecated, use -D swf-header instead";
192 define_value com Define.SwfHeader h
193 ),"<header>","define SWF header (width:height:fps:color)");
194 ("Target-specific",["--flash-strict"],[],Arg.Unit (fun () ->
195 add_deprecation "--flash-strict has been deprecated, use -D flash-strict instead";
196 Common.define com Define.FlashStrict
197 ), "","more type strict flash API");
198 ("Target-specific",["--swf-lib"],["-swf-lib"],Arg.String (fun file ->
199 add_native_lib file false;
200 ),"<file>","add the SWF library to the compiled SWF");
201 ("Target-specific",[],["--neko-lib-path"],Arg.String (fun dir ->
202 com.neko_lib_paths <- dir :: com.neko_lib_paths
203 ),"<directory>","add the neko library path");
204 ("Target-specific",["--swf-lib-extern"],["-swf-lib-extern"],Arg.String (fun file ->
205 add_native_lib file true;
206 ),"<file>","use the SWF library for type checking");
207 ("Target-specific",["--java-lib"],["-java-lib"],Arg.String (fun file ->
208 add_native_lib file false;
209 ),"<file>","add an external JAR or directory of JAR files");
210 ("Target-specific",["--java-lib-extern"],[],Arg.String (fun file ->
211 add_native_lib file true;
212 ),"<file>","use an external JAR or directory of JAR files for type checking");
213 ("Target-specific",["--net-lib"],["-net-lib"],Arg.String (fun file ->
214 add_native_lib file false;
215 ),"<file>[@std]","add an external .NET DLL file");
216 ("Target-specific",["--net-std"],["-net-std"],Arg.String (fun file ->
217 Dotnet.add_net_std com file
218 ),"<file>","add a root std .NET DLL search path");
219 ("Target-specific",["--c-arg"],["-c-arg"],Arg.String (fun arg ->
220 com.c_args <- arg :: com.c_args
221 ),"<arg>","pass option <arg> to the native Java/C# compiler");
222 ("Compilation",["-r";"--resource"],["-resource"],Arg.String (fun res ->
223 let file, name = (match ExtString.String.nsplit res "@" with
224 | [file; name] -> file, name
225 | [file] -> file, file
226 | _ -> raise (Arg.Bad "Invalid Resource format, expected file@name")
227 ) in
228 let file = (try Common.find_file com file with Not_found -> file) in
229 let data = (try
230 let s = Std.input_file ~bin:true file in
231 if String.length s > 12000000 then raise Exit;
232 s;
233 with
234 | Sys_error _ -> failwith ("Resource file not found: " ^ file)
235 | _ -> failwith ("Resource '" ^ file ^ "' excess the maximum size of 12MB")
236 ) in
237 if Hashtbl.mem com.resources name then failwith ("Duplicate resource name " ^ name);
238 Hashtbl.add com.resources name data
239 ),"<file>[@name]","add a named resource file");
240 ("Debug",["--prompt"],["-prompt"], Arg.Unit (fun() -> Helper.prompt := true),"","prompt on error");
241 ("Compilation",["--cmd"],["-cmd"], Arg.String (fun cmd ->
242 actx.cmds <- Helper.unquote cmd :: actx.cmds
243 ),"<command>","run the specified command after successful compilation");
244 ("Optimization",["--no-traces"],[], Arg.Unit (fun () ->
245 add_deprecation "--no-traces has been deprecated, use -D no-traces instead";
246 Common.define com Define.NoTraces
247 ), "","don't compile trace calls in the program");
248 ("Batch",["--next"],[], Arg.Unit (fun() -> die "" __LOC__), "","separate several haxe compilations");
249 ("Batch",["--each"],[], Arg.Unit (fun() -> die "" __LOC__), "","append preceding parameters to all Haxe compilations separated by --next");
250 ("Services",["--display"],[], Arg.String (fun input ->
251 actx.display_arg <- Some input;
252 ),"","display code tips");
253 ("Services",["--xml"],["-xml"],Arg.String (fun file ->
254 actx.xml_out <- Some file
255 ),"<file>","generate XML types description");
256 ("Services",["--json"],[],Arg.String (fun file ->
257 actx.json_out <- Some file
258 ),"<file>","generate JSON types description");
259 ("Optimization",["--no-output"],[], Arg.Unit (fun() -> actx.no_output <- true),"","compiles but does not generate any file");
260 ("Debug",["--times"],[], Arg.Unit (fun() -> Timer.measure_times := true),"","measure compilation times");
261 ("Optimization",["--no-inline"],[],Arg.Unit (fun () ->
262 add_deprecation "--no-inline has been deprecated, use -D no-inline instead";
263 Common.define com Define.NoInline
264 ), "","disable inlining");
265 ("Optimization",["--no-opt"],[], Arg.Unit (fun() ->
266 com.foptimize <- false;
267 Common.define com Define.NoOpt;
268 ), "","disable code optimizations");
269 ("Compilation",["--remap"],[], Arg.String (fun s ->
270 let pack, target = (try ExtString.String.split s ":" with _ -> raise (Arg.Bad "Invalid remap format, expected source:target")) in
271 com.package_rules <- PMap.add pack (Remap target) com.package_rules;
272 ),"<package:target>","remap a package to another one");
273 ("Compilation",["--macro"],[], Arg.String (fun e ->
274 actx.force_typing <- true;
275 actx.config_macros <- e :: actx.config_macros
276 ),"<macro>","call the given macro before typing anything else");
277 ("Compilation Server",["--server-listen"],["--wait"], Arg.String (fun hp ->
278 die "" __LOC__
279 ),"[[host:]port]|stdio]","wait on the given port (or use standard i/o) for commands to run");
280 ("Compilation Server",["--server-connect"],[], Arg.String (fun hp ->
281 die "" __LOC__
282 ),"[host:]port]","connect to the given port and wait for commands to run");
283 ("Compilation Server",["--connect"],[],Arg.String (fun _ ->
284 die "" __LOC__
285 ),"<[host:]port>","connect on the given port and run commands there");
286 ("Compilation",["-C";"--cwd"],[], Arg.String (fun dir ->
287 (try Unix.chdir dir with _ -> raise (Arg.Bad ("Invalid directory: " ^ dir)));
288 actx.did_something <- true;
289 ),"<directory>","set current working directory");
290 ("Compilation",["--haxelib-global"],[], Arg.Unit (fun () -> ()),"","pass --global argument to haxelib");
291 ("Compilation",["-w"],[], Arg.String (fun s ->
292 let p = { pfile = "-w " ^ s; pmin = 0; pmax = 0 } in
293 let l = Warning.parse_options s p in
294 com.warning_options <- l :: com.warning_options
295 ),"<warning list>","enable or disable specific warnings");
296 ] in
297 let args_callback cl =
298 begin try
299 let path,name = Path.parse_path cl in
300 if StringHelper.starts_uppercase_identifier name then
301 actx.classes <- (path,name) :: actx.classes
302 else begin
303 actx.force_typing <- true;
304 actx.config_macros <- (Printf.sprintf "include('%s', true, null, null, true)" cl) :: actx.config_macros;
305 end
306 with Failure _ when ignore_error com ->
307 ()
308 end
309 in
310 let all_args = (basic_args_spec @ adv_args_spec) in
311 let all_args_spec = process_args all_args in
312 let process args =
313 let current = ref 0 in
314 (try
315 let rec loop acc args = match args with
316 | "--display" :: arg :: args ->
317 loop (arg :: "--display" :: acc) args
318 | arg :: args ->
319 loop (Helper.expand_env arg :: acc) args
320 | [] ->
321 List.rev acc
322 in
323 let args = loop [] args in
324 Arg.parse_argv ~current (Array.of_list ("" :: args)) all_args_spec args_callback "";
325 with
326 | Arg.Help _ ->
327 raise (Helper.HelpMessage (usage_string all_args usage))
328 | Arg.Bad msg ->
329 let first_line = List.nth (Str.split (Str.regexp "\n") msg) 0 in
330 let new_msg = (Printf.sprintf "%s" first_line) in
331 let r = Str.regexp "unknown option [`']?\\([-A-Za-z]+\\)[`']?" in
332 try
333 ignore(Str.search_forward r msg 0);
334 let s = Str.matched_group 1 msg in
335 let sl = List.map (fun (s,_,_) -> s) all_args_spec in
336 let sl = StringError.get_similar s sl in
337 begin match sl with
338 | [] -> raise Not_found
339 | _ ->
340 let spec = List.filter (fun (_,sl',sl'',_,_,_) ->
341 List.exists (fun s -> List.mem s sl) (sl' @ sl'')
342 ) all_args in
343 let new_msg = (Printf.sprintf "%s\nDid you mean:\n%s" first_line (usage_string ~print_cat:false spec "")) in
344 raise (Arg.Bad new_msg)
345 end;
346 with Not_found ->
347 raise (Arg.Bad new_msg));
348 if com.platform = Globals.Cpp && not (Define.defined com.defines DisableUnicodeStrings) && not (Define.defined com.defines HxcppSmartStings) then begin
349 Define.define com.defines HxcppSmartStings;
350 end;
351 if Define.raw_defined com.defines "gen_hx_classes" then begin
352 (* TODO: this is something we're gonna remove once we have something nicer for generating flash externs *)
353 actx.force_typing <- true;
354 actx.pre_compilation <- (fun() ->
355 let process_lib lib =
356 if not (lib#has_flag NativeLibraries.FlagIsStd) then
357 List.iter (fun path -> if path <> (["java";"lang"],"String") then actx.classes <- path :: actx.classes) lib#list_modules
358 in
359 List.iter process_lib com.native_libs.net_libs;
360 List.iter process_lib com.native_libs.swf_libs;
361 List.iter process_lib com.native_libs.java_libs;
362 ) :: actx.pre_compilation;
363 actx.xml_out <- Some "hx"
364 end;
365 in
366 actx.raise_usage <- (fun () -> raise (Helper.HelpMessage (usage_string basic_args_spec usage)));
367 (* Handle CLI arguments *)
368 process com.args;
369 actx
0 open Globals
1 open Ast
2 open Json
3 open Type
4 open Define
5
6 type cached_file = {
7 c_file_path : string;
8 c_time : float;
9 c_package : string list;
10 c_decls : type_decl list;
11 mutable c_module_name : string option;
12 mutable c_pdi : Parser.parser_display_information;
13 }
14
15 type cached_directory = {
16 c_path : string;
17 mutable c_mtime : float;
18 }
19
20 type cached_native_lib = {
21 c_nl_mtime : float;
22 c_nl_files : (path,Ast.package) Hashtbl.t;
23 }
24
25 class context_cache (index : int) = object(self)
26 val files : (Path.UniqueKey.t,cached_file) Hashtbl.t = Hashtbl.create 0
27 val modules : (path,module_def) Hashtbl.t = Hashtbl.create 0
28 val removed_files = Hashtbl.create 0
29 val mutable json = JNull
30 val mutable initialized = false
31
32 (* files *)
33
34 method find_file key =
35 Hashtbl.find files key
36
37 method cache_file key path time data pdi =
38 Hashtbl.replace files key { c_file_path = path; c_time = time; c_package = fst data; c_decls = snd data; c_module_name = None; c_pdi = pdi }
39
40 method remove_file key =
41 try
42 let f = Hashtbl.find files key in
43 Hashtbl.remove files key;
44 Hashtbl.replace removed_files key f.c_file_path
45 with Not_found -> ()
46
47 (* Like remove_file, but doesn't keep track of the file *)
48 method remove_file_for_real key =
49 Hashtbl.remove files key
50
51 (* modules *)
52
53 method find_module path =
54 Hashtbl.find modules path
55
56 method find_module_opt path =
57 Hashtbl.find_opt modules path
58
59 method cache_module path value =
60 Hashtbl.replace modules path value
61
62 (* initialization *)
63
64 method is_initialized = initialized
65 method set_initialized value = initialized <- value
66
67 method get_index = index
68 method get_files = files
69 method get_modules = modules
70 method get_removed_files = removed_files
71
72 method get_json = json
73 method set_json j = json <- j
74
75 (* Pointers for memory inspection. *)
76 method get_pointers : unit array =
77 [|Obj.magic files;Obj.magic modules|]
78 end
79
80 let create_directory path mtime = {
81 c_path = path;
82 c_mtime = mtime;
83 }
84
85 class virtual server_task (id : string list) (priority : int) = object(self)
86 method private virtual execute : unit
87
88 method run : unit =
89 let t = Timer.timer ("server" :: "task" :: id) in
90 Std.finally t (fun () -> self#execute) ()
91
92 method get_priority = priority
93 method get_id = id
94 end
95
96 class arbitrary_task (id : string list) (priority : int) (f : unit -> unit) = object(self)
97 inherit server_task id priority
98
99 method private execute =
100 f ()
101 end
102
103 class cache = object(self)
104 val contexts : (string,context_cache) Hashtbl.t = Hashtbl.create 0
105 val mutable context_list = []
106 val haxelib : (string list, string list) Hashtbl.t = Hashtbl.create 0
107 val directories : (string, cached_directory list) Hashtbl.t = Hashtbl.create 0
108 val native_libs : (string,cached_native_lib) Hashtbl.t = Hashtbl.create 0
109 val mutable tasks : (server_task PriorityQueue.t) = PriorityQueue.Empty
110
111 (* contexts *)
112
113 method get_context sign =
114 try
115 Hashtbl.find contexts sign
116 with Not_found ->
117 let cache = new context_cache (Hashtbl.length contexts) in
118 context_list <- cache :: context_list;
119 Hashtbl.add contexts sign cache;
120 cache
121
122 method add_info sign desc platform class_path defines =
123 let cc = self#get_context sign in
124 let jo = JObject [
125 "index",JInt cc#get_index;
126 "desc",JString desc;
127 "platform",JString (platform_name platform);
128 "classPaths",JArray (List.map (fun s -> JString s) class_path);
129 "signature",JString (Digest.to_hex sign);
130 "defines",JArray (PMap.foldi (fun k v acc -> JObject [
131 "key",JString k;
132 "value",JString v;
133 ] :: acc) defines.values []);
134 ] in
135 cc#set_json jo;
136 cc#get_index
137
138 method get_contexts = context_list
139
140 (* files *)
141
142 method remove_files file =
143 Hashtbl.iter (fun _ cc-> cc#remove_file file) contexts
144
145 method get_context_files signs =
146 Hashtbl.fold (fun sign cc acc ->
147 if List.mem sign signs then Hashtbl.fold (fun file cfile acc -> (file,cfile) :: acc) cc#get_files acc
148 else acc
149 ) contexts []
150
151 method get_files =
152 Hashtbl.fold (fun sign cc acc ->
153 Hashtbl.fold (fun file cfile acc -> (sign,file,cfile) :: acc) cc#get_files acc
154 ) contexts []
155
156 (* modules *)
157
158 method iter_modules f =
159 Hashtbl.iter (fun _ cc ->
160 Hashtbl.iter (fun _ m ->
161 f m
162 ) cc#get_modules
163 ) contexts
164
165 method get_modules =
166 Hashtbl.fold (fun _ cc acc ->
167 Hashtbl.fold (fun _ m acc ->
168 m :: acc
169 ) cc#get_modules acc
170 ) contexts []
171
172 method taint_modules file_key reason =
173 Hashtbl.iter (fun _ cc ->
174 Hashtbl.iter (fun _ m ->
175 if Path.UniqueKey.lazy_key m.m_extra.m_file = file_key then m.m_extra.m_cache_state <- MSBad (Tainted reason)
176 ) cc#get_modules
177 ) contexts
178
179 (* haxelibs *)
180
181 method find_haxelib key =
182 Hashtbl.find haxelib key
183
184 method cache_haxelib key value =
185 Hashtbl.replace haxelib key value
186
187 (* directories *)
188
189 method find_directories key =
190 Hashtbl.find directories key
191
192 method add_directories key value =
193 Hashtbl.replace directories key value
194
195 method remove_directory key value =
196 try
197 let current = self#find_directories key in
198 Hashtbl.replace directories key (List.filter (fun dir -> dir.c_path <> value) current);
199 with Not_found ->
200 ()
201
202 method has_directory key value =
203 try
204 List.exists (fun dir -> dir.c_path = value) (self#find_directories key)
205 with Not_found ->
206 false
207
208 method add_directory key value =
209 try
210 let current = self#find_directories key in
211 self#add_directories key (value :: current)
212 with Not_found ->
213 self#add_directories key [value]
214
215 method clear_directories key =
216 Hashtbl.remove directories key
217
218 (* native lib *)
219
220 method add_native_lib key files timestamp =
221 Hashtbl.replace native_libs key { c_nl_files = files; c_nl_mtime = timestamp }
222
223 method get_native_lib key =
224 try Some (Hashtbl.find native_libs key)
225 with Not_found -> None
226
227 (* tasks *)
228
229 method add_task (task : server_task) : unit =
230 tasks <- PriorityQueue.insert tasks task#get_priority task
231
232 method has_task =
233 not (PriorityQueue.is_empty tasks)
234
235 method get_task =
236 let (_,task,queue) = PriorityQueue.extract tasks in
237 tasks <- queue;
238 task
239
240 method run_tasks recursive f =
241 let rec loop acc =
242 let current = tasks in
243 tasks <- Empty;
244 let f (ran_task,acc) prio task =
245 if f task then begin
246 task#run;
247 (true,acc)
248 end else
249 ran_task,PriorityQueue.insert acc prio task
250 in
251 let ran_task,folded = PriorityQueue.fold current f (false,acc) in
252 if recursive && ran_task then loop folded
253 else folded
254 in
255 tasks <- PriorityQueue.merge tasks (loop PriorityQueue.Empty);
256
257 (* Pointers for memory inspection. *)
258 method get_pointers : unit array =
259 [|Obj.magic contexts;Obj.magic haxelib;Obj.magic directories;Obj.magic native_libs|]
260
261 end
262
263 type t = cache
264
265 type context_options =
266 | NormalContext
267 | MacroContext
268 | NormalAndMacroContext
269
270 let get_module_name_of_cfile file cfile = match cfile.c_module_name with
271 | None ->
272 let name = Path.module_name_of_file file in
273 cfile.c_module_name <- Some name;
274 name
275 | Some name ->
276 name
0 open Globals
1
2 exception Abort
3
4 type server_mode =
5 | SMNone
6 | SMListen of string
7 | SMConnect of string
8
9 type arg_context = {
10 mutable classes : Globals.path list;
11 mutable xml_out : string option;
12 mutable json_out : string option;
13 mutable cmds : string list;
14 mutable config_macros : string list;
15 mutable no_output : bool;
16 mutable did_something : bool;
17 mutable force_typing : bool;
18 mutable pre_compilation : (unit -> unit) list;
19 mutable interp : bool;
20 mutable jvm_flag : bool;
21 mutable swf_version : bool;
22 mutable native_libs : (string * bool) list;
23 mutable raise_usage : unit -> unit;
24 mutable display_arg : string option;
25 mutable deprecations : string list;
26 }
27
28 type communication = {
29 write_out : string -> unit;
30 write_err : string -> unit;
31 flush : compilation_context -> unit;
32 exit : int -> unit;
33 is_server : bool;
34 }
35
36 and compilation_context = {
37 com : Common.context;
38 mutable messages : compiler_message list;
39 mutable has_next : bool;
40 mutable has_error : bool;
41 comm : communication;
42 }
43
44 type compilation_callbacks = {
45 before_anything : compilation_context -> unit;
46 after_arg_parsing : compilation_context -> unit;
47 after_compilation : compilation_context -> unit;
48 }
49
50 type server_accept = unit -> (bool * (bool -> string option) * (string -> unit) * (unit -> unit))
51
52 type server_api = {
53 cache : CompilationCache.t;
54 callbacks : compilation_callbacks;
55 on_context_create : unit -> int;
56 init_wait_socket : string -> int -> server_accept;
57 init_wait_connect : string -> int -> server_accept;
58 init_wait_stdio : unit -> server_accept;
59 wait_loop : bool -> server_accept -> int;
60 do_connect : string -> int -> string list -> unit;
61 }
62
63 let message ctx msg =
64 ctx.messages <- msg :: ctx.messages
65
66 let error ctx ?(depth=0) msg p =
67 message ctx (make_compiler_message msg p depth DKCompilerMessage Error);
68 ctx.has_error <- true
69
70 let located_error ctx ?(depth=0) msg = match (extract_located msg) with
71 | [] -> ()
72 | (msg,p) :: tl ->
73 error ~depth ctx msg p;
74 List.iter (fun (msg,p) -> error ~depth:(depth+1) ctx msg p) tl
0 open Globals
1 open Common
2 open CompilationContext
3
4 let run_or_diagnose ctx f arg =
5 let com = ctx.com in
6 let handle_diagnostics ?(depth = 0) msg kind =
7 ctx.has_error <- true;
8 add_diagnostics_message ~depth com msg kind Error;
9 DisplayOutput.emit_diagnostics ctx.com
10 in
11 if is_diagnostics com then begin try
12 f arg
13 with
14 | Error.Error(msg,p,depth) ->
15 handle_diagnostics ~depth (Error.error_msg p msg) DKCompilerMessage
16 | Parser.Error(msg,p) ->
17 handle_diagnostics (located (Parser.error_msg msg) p) DKParserError
18 | Lexer.Error(msg,p) ->
19 handle_diagnostics (located (Lexer.error_msg msg) p) DKParserError
20 end
21 else
22 f arg
23
24 let run_command ctx cmd =
25 let t = Timer.timer ["command";cmd] in
26 (* TODO: this is a hack *)
27 let cmd = if ctx.comm.is_server then begin
28 let h = Hashtbl.create 0 in
29 Hashtbl.add h "__file__" ctx.com.file;
30 Hashtbl.add h "__platform__" (platform_name ctx.com.platform);
31 Helper.expand_env ~h:(Some h) cmd
32 end else
33 cmd
34 in
35 let len = String.length cmd in
36 let result =
37 if len > 3 && String.sub cmd 0 3 = "cd " then begin
38 Sys.chdir (String.sub cmd 3 (len - 3));
39 0
40 (* Emit stderr as a server message in server mode *)
41 end else begin
42 let pout, pin, perr = Unix.open_process_full cmd (Unix.environment()) in
43 let bout = Bytes.create 1024 in
44 let berr = Bytes.create 1024 in
45 let rec read_content channel buf f =
46 begin try
47 let i = input channel buf 0 1024 in
48 if i > 0 then begin
49 f (Bytes.unsafe_to_string (Bytes.sub buf 0 i));
50 read_content channel buf f
51 end
52 with Unix.Unix_error _ ->
53 ()
54 end
55 in
56 let tout = Thread.create (fun() -> read_content pout bout ctx.comm.write_out) () in
57 let terr = Thread.create (fun() -> read_content perr berr ctx.comm.write_err) () in
58 Thread.join tout;
59 Thread.join terr;
60 let result = (match Unix.close_process_full (pout,pin,perr) with Unix.WEXITED c | Unix.WSIGNALED c | Unix.WSTOPPED c -> c) in
61 result
62 end
63 in
64 t();
65 result
66
67 module Setup = struct
68 let initialize_target ctx com actx =
69 let add_std dir =
70 com.class_path <- List.filter (fun s -> not (List.mem s com.std_path)) com.class_path @ List.map (fun p -> p ^ dir ^ "/_std/") com.std_path @ com.std_path
71 in
72 match com.platform with
73 | Cross ->
74 (* no platform selected *)
75 set_platform com Cross "";
76 "?"
77 | Flash ->
78 let rec loop = function
79 | [] -> ()
80 | (v,_) :: _ when v > com.flash_version -> ()
81 | (v,def) :: l ->
82 Common.raw_define com ("flash" ^ def);
83 loop l
84 in
85 loop Common.flash_versions;
86 com.package_rules <- PMap.remove "flash" com.package_rules;
87 add_std "flash";
88 "swf"
89 | Neko ->
90 add_std "neko";
91 "n"
92 | Js ->
93 let es_version =
94 try
95 int_of_string (Common.defined_value com Define.JsEs)
96 with
97 | Not_found ->
98 (Common.define_value com Define.JsEs "5"; 5)
99 | _ ->
100 0
101 in
102
103 if es_version < 3 || es_version = 4 then (* we don't support ancient and there's no 4th *)
104 failwith "Invalid -D js-es value";
105
106 if es_version >= 5 then Common.raw_define com "js_es5"; (* backward-compatibility *)
107
108 add_std "js";
109 "js"
110 | Lua ->
111 add_std "lua";
112 "lua"
113 | Php ->
114 add_std "php";
115 "php"
116 | Cpp ->
117 Common.define_value com Define.HxcppApiLevel "430";
118 add_std "cpp";
119 if Common.defined com Define.Cppia then
120 actx.classes <- (Path.parse_path "cpp.cppia.HostClasses" ) :: actx.classes;
121 "cpp"
122 | Cs ->
123 Dotnet.before_generate com;
124 add_std "cs"; "cs"
125 | Java ->
126 Java.before_generate com;
127 if defined com Define.Jvm then begin
128 add_std "jvm";
129 com.package_rules <- PMap.remove "jvm" com.package_rules;
130 end;
131 add_std "java";
132 "java"
133 | Python ->
134 add_std "python";
135 if not (Common.defined com Define.PythonVersion) then
136 Common.define_value com Define.PythonVersion "3.3";
137 "python"
138 | Hl ->
139 add_std "hl";
140 if not (Common.defined com Define.HlVer) then Define.define_value com.defines Define.HlVer (try Std.input_file (Common.find_file com "hl/hl_version") with Not_found -> die "" __LOC__);
141 "hl"
142 | Eval ->
143 add_std "eval";
144 "eval"
145
146 let create_typer_context ctx native_libs =
147 let com = ctx.com in
148 Common.log com ("Classpath: " ^ (String.concat ";" com.class_path));
149 let buffer = Buffer.create 64 in
150 Buffer.add_string buffer "Defines: ";
151 PMap.iter (fun k v -> match v with
152 | "1" -> Printf.bprintf buffer "%s;" k
153 | _ -> Printf.bprintf buffer "%s=%s;" k v
154 ) com.defines.values;
155 Buffer.truncate buffer (Buffer.length buffer - 1);
156 Common.log com (Buffer.contents buffer);
157 Typecore.type_expr_ref := (fun ?(mode=MGet) ctx e with_type -> Typer.type_expr ~mode ctx e with_type);
158 com.callbacks#run com.callbacks#get_before_typer_create;
159 (* Native lib pass 1: Register *)
160 let fl = List.map (fun (file,extern) -> NativeLibraryHandler.add_native_lib com file extern) (List.rev native_libs) in
161 (* Native lib pass 2: Initialize *)
162 List.iter (fun f -> f()) fl;
163 Typer.create com
164
165 let executable_path() =
166 Extc.executable_path()
167
168 let get_std_class_paths () =
169 try
170 let p = Sys.getenv "HAXE_STD_PATH" in
171 let rec loop = function
172 | drive :: path :: l ->
173 if String.length drive = 1 && ((drive.[0] >= 'a' && drive.[0] <= 'z') || (drive.[0] >= 'A' && drive.[0] <= 'Z')) then
174 (drive ^ ":" ^ path) :: loop l
175 else
176 drive :: loop (path :: l)
177 | l ->
178 l
179 in
180 let parts = Str.split_delim (Str.regexp "[;:]") p in
181 "" :: List.map Path.add_trailing_slash (loop parts)
182 with Not_found ->
183 let base_path = Path.get_real_path (try executable_path() with _ -> "./") in
184 if Sys.os_type = "Unix" then
185 let prefix_path = Filename.dirname base_path in
186 let lib_path = Filename.concat prefix_path "lib" in
187 let share_path = Filename.concat prefix_path "share" in
188 [
189 "";
190 Path.add_trailing_slash (Filename.concat lib_path "haxe/std");
191 Path.add_trailing_slash (Filename.concat lib_path "haxe/extraLibs");
192 Path.add_trailing_slash (Filename.concat share_path "haxe/std");
193 Path.add_trailing_slash (Filename.concat share_path "haxe/extraLibs");
194 Path.add_trailing_slash (Filename.concat base_path "std");
195 Path.add_trailing_slash (Filename.concat base_path "extraLibs")
196 ]
197 else
198 [
199 "";
200 Path.add_trailing_slash (Filename.concat base_path "std");
201 Path.add_trailing_slash (Filename.concat base_path "extraLibs")
202 ]
203
204 let setup_common_context ctx =
205 let com = ctx.com in
206 ctx.com.print <- ctx.comm.write_out;
207 Common.define_value com Define.HaxeVer (Printf.sprintf "%.3f" (float_of_int Globals.version /. 1000.));
208 Common.raw_define com "haxe3";
209 Common.raw_define com "haxe4";
210 Common.define_value com Define.Haxe s_version;
211 Common.raw_define com "true";
212 Common.define_value com Define.Dce "std";
213 com.info <- (fun ?(depth=0) msg p -> message ctx (make_compiler_message msg p depth DKCompilerMessage Information));
214 com.warning <- (fun ?(depth=0) w options msg p ->
215 match Warning.get_mode w (com.warning_options @ options) with
216 | WMEnable ->
217 let wobj = Warning.warning_obj w in
218 let msg = if wobj.w_generic then
219 msg
220 else
221 Printf.sprintf "(%s) %s" wobj.w_name msg
222 in
223 message ctx (make_compiler_message msg p depth DKCompilerMessage Warning)
224 | WMDisable ->
225 ()
226 );
227 com.located_error <- located_error ctx;
228 com.error <- (fun ?(depth = 0) msg p -> com.located_error ~depth (located msg p));
229 let filter_messages = (fun keep_errors predicate -> (List.filter (fun cm ->
230 (match cm.cm_severity with
231 | MessageSeverity.Error -> keep_errors;
232 | Information | Warning | Hint -> predicate cm;)
233 ) (List.rev ctx.messages))) in
234 com.get_messages <- (fun () -> (List.map (fun cm ->
235 (match cm.cm_severity with
236 | MessageSeverity.Error -> die "" __LOC__;
237 | Information | Warning | Hint -> cm;)
238 ) (filter_messages false (fun _ -> true))));
239 com.filter_messages <- (fun predicate -> (ctx.messages <- (List.rev (filter_messages true predicate))));
240 com.run_command <- run_command ctx;
241 com.class_path <- get_std_class_paths ();
242 com.std_path <- List.filter (fun p -> ExtString.String.ends_with p "std/" || ExtString.String.ends_with p "std\\") com.class_path
243
244 end
245
246 (** Creates the typer context and types [classes] into it. *)
247 let do_type ctx tctx actx =
248 let com = tctx.Typecore.com in
249 let t = Timer.timer ["typing"] in
250 let cs = com.cs in
251 CommonCache.maybe_add_context_sign cs com "before_init_macros";
252 com.stage <- CInitMacrosStart;
253 List.iter (MacroContext.call_init_macro tctx) (List.rev actx.config_macros);
254 com.stage <- CInitMacrosDone;
255 CommonCache.lock_signature com "after_init_macros";
256 com.callbacks#run com.callbacks#get_after_init_macros;
257 run_or_diagnose ctx (fun () ->
258 if com.display.dms_kind <> DMNone then DisplayTexpr.check_display_file tctx cs;
259 List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath null_pos)) (List.rev actx.classes);
260 Finalization.finalize tctx;
261 ) ();
262 com.stage <- CTypingDone;
263 (* If we are trying to find references, let's syntax-explore everything we know to check for the
264 identifier we are interested in. We then type only those modules that contain the identifier. *)
265 begin match com.display.dms_kind with
266 | (DMUsage _ | DMImplementation) -> FindReferences.find_possible_references tctx cs;
267 | _ -> ()
268 end;
269 t()
270
271 let finalize_typing ctx tctx =
272 let t = Timer.timer ["finalize"] in
273 let com = ctx.com in
274 com.stage <- CFilteringStart;
275 let main, types, modules = run_or_diagnose ctx Finalization.generate tctx in
276 com.main <- main;
277 com.types <- types;
278 com.modules <- modules;
279 t()
280
281 let filter ctx tctx =
282 let t = Timer.timer ["filters"] in
283 DeprecationCheck.run ctx.com;
284 Filters.run ctx.com tctx ctx.com.main;
285 t()
286
287 let compile ctx actx =
288 let com = ctx.com in
289 (* Set up display configuration *)
290 DisplayProcessing.process_display_configuration ctx;
291 let display_file_dot_path = DisplayProcessing.process_display_file com actx in
292 (* Initialize target: This allows access to the appropriate std packages and sets the -D defines. *)
293 let ext = Setup.initialize_target ctx com actx in
294 com.config <- get_config com; (* make sure to adapt all flags changes defined after platform *)
295 let t = Timer.timer ["init"] in
296 List.iter (fun f -> f()) (List.rev (actx.pre_compilation));
297 t();
298 com.stage <- CInitialized;
299 if actx.classes = [([],"Std")] && not actx.force_typing then begin
300 if actx.cmds = [] && not actx.did_something then actx.raise_usage();
301 end else begin
302 (* Actual compilation starts here *)
303 let tctx = Setup.create_typer_context ctx actx.native_libs in
304 com.stage <- CTyperCreated;
305 let display_file_dot_path = DisplayProcessing.maybe_load_display_file_before_typing tctx display_file_dot_path in
306 begin try
307 do_type ctx tctx actx
308 with TypeloadParse.DisplayInMacroBlock ->
309 ignore(DisplayProcessing.load_display_module_in_macro tctx display_file_dot_path true);
310 end;
311 DisplayProcessing.handle_display_after_typing ctx tctx display_file_dot_path;
312 finalize_typing ctx tctx;
313 DisplayProcessing.handle_display_after_finalization ctx tctx display_file_dot_path;
314 filter ctx tctx;
315 if ctx.has_error then raise Abort;
316 Generate.check_auxiliary_output com actx;
317 com.stage <- CGenerationStart;
318 if not actx.no_output then Generate.generate ctx tctx ext actx;
319 com.stage <- CGenerationDone;
320 end;
321 Sys.catch_break false;
322 com.callbacks#run com.callbacks#get_after_generation;
323 if not actx.no_output then begin
324 List.iter (fun c ->
325 let r = run_command ctx c in
326 if r <> 0 then failwith ("Command failed with error " ^ string_of_int r)
327 ) (List.rev actx.cmds)
328 end
329
330 let compile_safe ctx f =
331 let com = ctx.com in
332 try
333 f ()
334 with
335 | Abort ->
336 ()
337 | Error.Fatal_error (m,depth) ->
338 located_error ~depth ctx m
339 | Common.Abort msg ->
340 located_error ctx msg
341 | Lexer.Error (m,p) ->
342 error ctx (Lexer.error_msg m) p
343 | Parser.Error (m,p) ->
344 error ctx (Parser.error_msg m) p
345 | Typecore.Forbid_package ((pack,m,p),pl,pf) ->
346 if !Parser.display_mode <> DMNone && ctx.has_next then begin
347 ctx.has_error <- false;
348 ctx.messages <- [];
349 end else begin
350 error ctx (Printf.sprintf "You cannot access the %s package while %s (for %s)" pack (if pf = "macro" then "in a macro" else "targeting " ^ pf) (s_type_path m) ) p;
351 List.iter (error ~depth:1 ctx (Error.compl_msg "referenced here")) (List.rev pl);
352 end
353 | Error.Error (Stack stack,_,depth) -> (match stack with
354 | [] -> ()
355 | (e,p) :: stack -> begin
356 located_error ~depth ctx (Error.error_msg p e);
357 List.iter (fun (e,p) -> located_error ~depth:(depth+1) ctx (Error.error_msg p e)) stack;
358 end)
359 | Error.Error (m,p,depth) ->
360 located_error ~depth ctx (Error.error_msg p m)
361 | Generic.Generic_Exception(m,p) ->
362 error ctx m p
363 | Arg.Bad msg ->
364 error ctx ("Error: " ^ msg) null_pos
365 | Failure msg when not Helper.is_debug_run ->
366 error ctx ("Error: " ^ msg) null_pos
367 | Helper.HelpMessage msg ->
368 com.info msg null_pos
369 | Parser.TypePath (p,c,is_import,pos) ->
370 DisplayOutput.handle_type_path_exception ctx p c is_import pos
371 | Parser.SyntaxCompletion(kind,subj) ->
372 DisplayOutput.handle_syntax_completion com kind subj;
373 error ctx ("Error: No completion point was found") null_pos
374 | DisplayException.DisplayException dex ->
375 DisplayOutput.handle_display_exception ctx dex
376 | Out_of_memory | EvalExceptions.Sys_exit _ | Hlinterp.Sys_exit _ | DisplayProcessingGlobals.Completion _ as exc ->
377 (* We don't want these to be caught by the catchall below *)
378 raise exc
379 | e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" with _ -> true) && not Helper.is_debug_run ->
380 error ctx (Printexc.to_string e) null_pos
381
382 let finalize ctx =
383 ctx.comm.flush ctx;
384 (* In server mode any open libs are closed by the lib_build_task. In offline mode
385 we should do it here to be safe. *)
386 if not ctx.comm.is_server then begin
387 List.iter (fun lib -> lib#close) ctx.com.native_libs.java_libs;
388 List.iter (fun lib -> lib#close) ctx.com.native_libs.net_libs;
389 List.iter (fun lib -> lib#close) ctx.com.native_libs.swf_libs;
390 end
391
392 let catch_completion_and_exit ctx callbacks run =
393 try
394 run ctx;
395 if ctx.has_error then 1 else 0
396 with
397 | DisplayProcessingGlobals.Completion str ->
398 callbacks.after_compilation ctx;
399 ServerMessage.completion str;
400 ctx.comm.write_err str;
401 0
402 | EvalExceptions.Sys_exit i | Hlinterp.Sys_exit i ->
403 if i <> 0 then ctx.has_error <- true;
404 finalize ctx;
405 i
406
407 let process_actx ctx actx =
408 DisplayProcessing.process_display_arg ctx actx;
409 List.iter (fun s ->
410 ctx.com.warning WDeprecated [] s null_pos
411 ) actx.deprecations
412
413 let compile_ctx callbacks ctx =
414 let run ctx =
415 callbacks.before_anything ctx;
416 Setup.setup_common_context ctx;
417 compile_safe ctx (fun () ->
418 let actx = Args.parse_args ctx.com in
419 process_actx ctx actx;
420 callbacks.after_arg_parsing ctx;
421 compile ctx actx;
422 );
423 finalize ctx;
424 callbacks.after_compilation ctx;
425 in
426 if ctx.has_error then begin
427 finalize ctx;
428 1 (* can happen if process_params fails already *)
429 end else
430 catch_completion_and_exit ctx callbacks run
431
432 let create_context comm cs compilation_step params = {
433 com = Common.create compilation_step cs version params;
434 messages = [];
435 has_next = false;
436 has_error = false;
437 comm = comm;
438 }
439
440 module HighLevel = struct
441 let add_libs libs args cs has_display =
442 let global_repo = List.exists (fun a -> a = "--haxelib-global") args in
443 let fail msg =
444 raise (Arg.Bad msg)
445 in
446 let call_haxelib() =
447 let t = Timer.timer ["haxelib"] in
448 let cmd = "haxelib" ^ (if global_repo then " --global" else "") ^ " path " ^ String.concat " " libs in
449 let pin, pout, perr = Unix.open_process_full cmd (Unix.environment()) in
450 let lines = Std.input_list pin in
451 let err = Std.input_list perr in
452 let ret = Unix.close_process_full (pin,pout,perr) in
453 if ret <> Unix.WEXITED 0 then fail (match lines, err with
454 | [], [] -> "Failed to call haxelib (command not found ?)"
455 | [], [s] when ExtString.String.ends_with (ExtString.String.strip s) "Module not found: path" -> "The haxelib command has been strip'ed, please install it again"
456 | _ -> String.concat "\n" (lines@err));
457 t();
458 lines
459 in
460 match libs with
461 | [] ->
462 []
463 | _ ->
464 let lines =
465 try
466 (* if we are compiling, really call haxelib since library path might have changed *)
467 if not has_display then raise Not_found;
468 cs#find_haxelib libs
469 with Not_found -> try
470 let lines = call_haxelib() in
471 cs#cache_haxelib libs lines;
472 lines
473 with Unix.Unix_error(code,msg,arg) ->
474 fail ((Printf.sprintf "%s (%s)" (Unix.error_message code) arg))
475 in
476 let lines = List.fold_left (fun acc l ->
477 let l = ExtString.String.strip l in
478 if l = "" then
479 acc
480 else if l.[0] <> '-' then
481 "-cp" :: l :: acc
482 else match (try ExtString.String.split l " " with _ -> l, "") with
483 | ("-L",dir) ->
484 "--neko-lib-path" :: (String.sub l 3 (String.length l - 3)) :: acc
485 | param, value ->
486 let acc = if value <> "" then value :: acc else acc in
487 let acc = param :: acc in
488 acc
489 ) [] (List.rev lines) in
490 lines
491
492 (* Returns a list of contexts, but doesn't do anything yet *)
493 let process_params server_api create each_params has_display is_server pl =
494 let curdir = Unix.getcwd () in
495 let added_libs = Hashtbl.create 0 in
496 let server_mode = ref SMNone in
497 let create_context args =
498 let ctx = create (server_api.on_context_create()) args in
499 (* --cwd triggers immediately, so let's reset *)
500 Unix.chdir curdir;
501 ctx
502 in
503 let rec find_subsequent_libs acc args = match args with
504 | ("-L" | "--library" | "-lib") :: name :: args ->
505 find_subsequent_libs (name :: acc) args
506 | _ ->
507 List.rev acc,args
508 in
509 let rec loop acc = function
510 | [] ->
511 [],Some (create_context (!each_params @ (List.rev acc)))
512 | "--next" :: l when acc = [] -> (* skip empty --next *)
513 loop [] l
514 | "--next" :: l ->
515 let ctx = create_context (!each_params @ (List.rev acc)) in
516 ctx.has_next <- true;
517 l,Some ctx
518 | "--each" :: l ->
519 each_params := List.rev acc;
520 loop [] l
521 | "--cwd" :: dir :: l | "-C" :: dir :: l ->
522 (* we need to change it immediately since it will affect hxml loading *)
523 (try Unix.chdir dir with _ -> raise (Arg.Bad ("Invalid directory: " ^ dir)));
524 (* Push the --cwd arg so the arg processor know we did something. *)
525 loop (dir :: "--cwd" :: acc) l
526 | "--connect" :: hp :: l ->
527 if is_server then
528 (* If we are already connected, ignore (issue #10813) *)
529 loop acc l
530 else begin
531 let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in
532 server_api.do_connect host (try int_of_string port with _ -> raise (Arg.Bad "Invalid port")) ((List.rev acc) @ l);
533 [],None
534 end
535 | "--server-connect" :: hp :: l ->
536 server_mode := SMConnect hp;
537 loop acc l
538 | ("--server-listen" | "--wait") :: hp :: l ->
539 server_mode := SMListen hp;
540 loop acc l
541 | "--run" :: cl :: args ->
542 let acc = cl :: "-x" :: acc in
543 let ctx = create_context (!each_params @ (List.rev acc)) in
544 ctx.com.sys_args <- args;
545 [],Some ctx
546 | ("-L" | "--library" | "-lib") :: name :: args ->
547 let libs,args = find_subsequent_libs [name] args in
548 let libs = List.filter (fun l -> not (Hashtbl.mem added_libs l)) libs in
549 List.iter (fun l -> Hashtbl.add added_libs l ()) libs;
550 let lines = add_libs libs pl server_api.cache has_display in
551 loop acc (lines @ args)
552 | ("--jvm" | "--java" | "-java" as arg) :: dir :: args ->
553 loop_lib arg dir "hxjava" acc args
554 | ("--cs" | "-cs" as arg) :: dir :: args ->
555 loop_lib arg dir "hxcs" acc args
556 | arg :: l ->
557 match List.rev (ExtString.String.nsplit arg ".") with
558 | "hxml" :: _ :: _ when (match acc with "-cmd" :: _ | "--cmd" :: _ -> false | _ -> true) ->
559 let acc, l = (try acc, Helper.parse_hxml arg @ l with Not_found -> (arg ^ " (file not found)") :: acc, l) in
560 loop acc l
561 | _ ->
562 loop (arg :: acc) l
563 and loop_lib arg dir lib acc args =
564 loop (dir :: arg :: acc) ("-lib" :: lib :: args)
565 in
566 let args,ctx = loop [] pl in
567 args,!server_mode,ctx
568
569 let execute_ctx server_api ctx server_mode =
570 begin match server_mode with
571 | SMListen hp ->
572 (* parse for com.verbose *)
573 ignore(Args.parse_args ctx.com);
574 let accept = match hp with
575 | "stdio" ->
576 server_api.init_wait_stdio()
577 | _ ->
578 let host, port = Helper.parse_host_port hp in
579 server_api.init_wait_socket host port
580 in
581 server_api.wait_loop ctx.com.verbose accept
582 | SMConnect hp ->
583 ignore(Args.parse_args ctx.com);
584 let host, port = Helper.parse_host_port hp in
585 let accept = server_api.init_wait_connect host port in
586 server_api.wait_loop ctx.com.verbose accept
587 | SMNone ->
588 compile_ctx server_api.callbacks ctx
589 end
590
591 let entry server_api comm args =
592 let create = create_context comm server_api.cache in
593 let each_args = ref [] in
594 let has_display = ref false in
595 (* put --display in front if it was last parameter *)
596 let args = match List.rev args with
597 | file :: "--display" :: pl when file <> "memory" ->
598 has_display := true;
599 "--display" :: file :: List.rev pl
600 | _ ->
601 args
602 in
603 let rec loop args =
604 let args,server_mode,ctx = try
605 process_params server_api create each_args !has_display comm.is_server args
606 with Arg.Bad msg ->
607 let ctx = create 0 args in
608 error ctx ("Error: " ^ msg) null_pos;
609 [],SMNone,Some ctx
610 in
611 let code = match ctx with
612 | Some ctx ->
613 execute_ctx server_api ctx server_mode
614 | None ->
615 (* caused by --connect *)
616 0
617 in
618 if code = 0 && args <> [] && not !has_display then
619 loop args
620 else
621 code
622 in
623 let code = loop args in
624 comm.exit code
625 end
11 open Ast
22 open Common
33 open Filename
4 open CompilationServer
54 open Timer
65 open DisplayTypes.DisplayMode
76 open DisplayTypes.CompletionResultKind
1615 open CompletionModuleType
1716 open Typecore
1817 open Genjson
18 open CompilationContext
19 open DisplayProcessingGlobals
1920
2021 (* Old XML stuff *)
2122
6970 | ITPackage(path,_) -> "package",snd path,"",None
7071 | ITModule path -> "type",snd path,"",None
7172 | ITMetadata meta ->
72 let s,(doc,_) = Meta.get_info meta in
73 let s,(doc,_),_ = Meta.get_info meta in
7374 "metadata","@" ^ s,"",doc_from_string doc
7475 | ITTimer(name,value) -> "timer",name,"",doc_from_string value
7576 | ITLiteral s ->
207208
208209 (* Mode processing *)
209210
210 exception Completion of string
211
212 let unquote v =
213 let len = String.length v in
214 if len > 0 then
215 match v.[0], v.[len - 1] with
216 | '"', '"'
217 | '\'', '\'' -> String.sub v 1 (len - 2)
218 | _ -> v
219 else v
220
221 let handle_display_argument com file_pos pre_compilation did_something =
222 match file_pos with
223 | "classes" ->
224 pre_compilation := (fun() -> raise (Parser.TypePath (["."],None,true,null_pos))) :: !pre_compilation;
225 | "keywords" ->
226 raise (Completion (print_keywords ()))
227 | "memory" ->
228 did_something := true;
229 (try Memory.display_memory com with e -> prerr_endline (Printexc.get_backtrace ()));
230 | "diagnostics" ->
231 com.display <- DisplayMode.create (DMDiagnostics []);
232 Parser.display_mode := DMDiagnostics [];
233 | _ ->
234 let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format: " ^ file_pos) in
235 let file = unquote file in
236 let file_unique = com.file_keys#get file in
237 let pos, smode = try ExtString.String.split pos "@" with _ -> pos,"" in
238 let mode = match smode with
239 | "position" ->
240 DMDefinition
241 | "usage" ->
242 DMUsage (false,false,false)
243 (*| "rename" ->
244 DMUsage true*)
245 | "package" ->
246 DMPackage
247 | "type" ->
248 DMHover
249 | "toplevel" ->
250 DMDefault
251 | "module-symbols" ->
252 DMModuleSymbols None;
253 | "diagnostics" ->
254 DMDiagnostics [file_unique];
255 | "statistics" ->
256 DMStatistics
257 | "signature" ->
258 DMSignature
259 | "" ->
260 DMDefault
261 | _ ->
262 let smode,arg = try ExtString.String.split smode "@" with _ -> pos,"" in
263 match smode with
264 | "resolve" ->
265 DMResolve arg
266 | "workspace-symbols" ->
267 DMModuleSymbols (Some arg)
268 | _ ->
269 DMDefault
270 in
271 let pos = try int_of_string pos with _ -> failwith ("Invalid format: " ^ pos) in
272 com.display <- DisplayMode.create mode;
273 Parser.display_mode := mode;
274 if not com.display.dms_full_typing then Common.define_value com Define.Display (if smode <> "" then smode else "1");
275 DisplayPosition.display_position#set {
276 pfile = Path.get_full_path file;
277 pmin = pos;
278 pmax = pos;
279 }
280
281 let file_input_marker = Path.get_full_path "? input"
282
283 type display_path_kind =
284 | DPKNormal of path
285 | DPKMacro of path
286 | DPKDirect of string
287 | DPKInput of string
288 | DPKNone
289
290 let process_display_file com classes =
291 let get_module_path_from_file_path com spath =
292 let rec loop = function
293 | [] -> None
294 | cp :: l ->
295 let cp = (if cp = "" then "./" else cp) in
296 let c = Path.add_trailing_slash (Path.get_real_path cp) in
297 let clen = String.length c in
298 if clen < String.length spath && String.sub spath 0 clen = c then begin
299 let path = String.sub spath clen (String.length spath - clen) in
300 (try
301 let path = Path.parse_path path in
302 (match loop l with
303 | Some x as r when String.length (s_type_path x) < String.length (s_type_path path) -> r
304 | _ -> Some path)
305 with _ -> loop l)
306 end else
307 loop l
308 in
309 loop com.class_path
310 in
311 match com.display.dms_display_file_policy with
312 | DFPNo ->
313 DPKNone
314 | DFPOnly when (DisplayPosition.display_position#get).pfile = file_input_marker ->
315 classes := [];
316 com.main_class <- None;
317 begin match !TypeloadParse.current_stdin with
318 | Some input ->
319 TypeloadParse.current_stdin := None;
320 DPKInput input
321 | None ->
322 DPKNone
323 end
324 | dfp ->
325 if dfp = DFPOnly then begin
326 classes := [];
327 com.main_class <- None;
328 end;
329 let real = Path.get_real_path (DisplayPosition.display_position#get).pfile in
330 let path = match get_module_path_from_file_path com real with
331 | Some path ->
332 if com.display.dms_kind = DMPackage then raise_package (fst path);
333 let path = match ExtString.String.nsplit (snd path) "." with
334 | [name;"macro"] ->
335 (* If we have a .macro.hx path, don't add the file to classes because the compiler won't find it.
336 This can happen if we're completing in such a file. *)
337 DPKMacro (fst path,name)
338 | [name] ->
339 classes := path :: !classes;
340 DPKNormal path
341 | [name;target] ->
342 let path = fst path, name in
343 classes := path :: !classes;
344 DPKNormal path
345 | e ->
346 die "" __LOC__
347 in
348 path
349 | None ->
350 if not (Sys.file_exists real) then failwith "Display file does not exist";
351 (match List.rev (ExtString.String.nsplit real Path.path_sep) with
352 | file :: _ when file.[0] >= 'a' && file.[0] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter")
353 | _ -> ());
354 DPKDirect real
355 in
356 Common.log com ("Display file : " ^ real);
357 Common.log com ("Classes found : [" ^ (String.concat "," (List.map s_type_path !classes)) ^ "]");
358 path
359
360 let load_display_file_standalone ctx file =
361 let com = ctx.com in
362 let pack,decls = TypeloadParse.parse_module_file com file null_pos in
363 let path = Path.FilePath.parse file in
364 let name = match path.file_name with
365 | None -> "?DISPLAY"
366 | Some name -> name
367 in
368 begin match path.directory with
369 | None -> ()
370 | Some dir ->
371 (* Chop off number of package parts from the dir and use that as class path. *)
372 let parts = ExtString.String.nsplit dir (if path.backslash then "\\" else "/") in
373 let parts = List.rev (ExtList.List.drop (List.length pack) (List.rev parts)) in
374 let dir = ExtString.String.join (if path.backslash then "\\" else "/") parts in
375 com.class_path <- dir :: com.class_path
376 end;
377 ignore(TypeloadModule.type_module ctx (pack,name) file ~dont_check_path:true decls null_pos)
378
379 let load_display_content_standalone ctx input =
380 let com = ctx.com in
381 let file = file_input_marker in
382 let p = {pfile = file; pmin = 0; pmax = 0} in
383 let parsed = TypeloadParse.parse_file_from_string com file p input in
384 let pack,decls = TypeloadParse.handle_parser_result com p parsed in
385 ignore(TypeloadModule.type_module ctx (pack,"?DISPLAY") file ~dont_check_path:true decls p)
386
387 let promote_type_hints tctx =
388 let rec explore_type_hint (md,p,t) =
389 match t with
390 | TMono r -> (match r.tm_type with None -> () | Some t -> explore_type_hint (md,p,t))
391 | TLazy f -> explore_type_hint (md,p,lazy_type f)
392 | TInst(({cl_name_pos = pn;cl_path = (_,name)}),_)
393 | TEnum(({e_name_pos = pn;e_path = (_,name)}),_)
394 | TType(({t_name_pos = pn;t_path = (_,name)}),_)
395 | TAbstract(({a_name_pos = pn;a_path = (_,name)}),_) ->
396 md.m_type_hints <- (p,pn) :: md.m_type_hints;
397 | TDynamic _ -> ()
398 | TFun _ | TAnon _ -> ()
399 in
400 List.iter explore_type_hint tctx.g.type_hints
401
402 let process_global_display_mode com tctx =
403 promote_type_hints tctx;
404 match com.display.dms_kind with
405 | DMUsage (with_definition,_,_) ->
406 FindReferences.find_references tctx com with_definition
407 | DMImplementation ->
408 FindReferences.find_implementations tctx com
409 | DMDiagnostics _ ->
410 Diagnostics.run com
411 | DMStatistics ->
412 let stats = Statistics.collect_statistics tctx [SFFile (DisplayPosition.display_position#get).pfile] true in
413 raise_statistics (Statistics.Printer.print_statistics stats)
414 | DMModuleSymbols (Some "") -> ()
415 | DMModuleSymbols filter ->
416 let symbols = match CompilationServer.get() with
417 | None -> []
418 | Some cs ->
419 let l = cs#get_context_files ((Define.get_signature com.defines) :: (match com.get_macros() with None -> [] | Some com -> [Define.get_signature com.defines])) in
420 List.fold_left (fun acc (file_key,cfile) ->
421 let file = cfile.CompilationServer.c_file_path in
422 if (filter <> None || DisplayPosition.display_position#is_in_file (com.file_keys#get file)) then
423 (file,DocumentSymbols.collect_module_symbols (Some (file,get_module_name_of_cfile file cfile)) (filter = None) (cfile.c_package,cfile.c_decls)) :: acc
424 else
425 acc
426 ) [] l
427 in
428 raise_module_symbols (DocumentSymbols.Printer.print_module_symbols com symbols filter)
429 | _ -> ()
430
431211 let find_doc t =
432212 let doc = match follow t with
433213 | TAnon an ->
474254 ()
475255 | _ ->
476256 let l = List.map make_ci_keyword l in
477 match com.json_out with
257 match com.Common.json_out with
478258 | None ->
479259 let b = Buffer.create 0 in
480260 Buffer.add_string b "<il>\n";
487267 raise (Completion s)
488268 | Some api ->
489269 let ctx = Genjson.create_context ~jsonrpc:api.jsonrpc GMFull in
490 api.send_result(fields_to_json ctx l kind subj)
270 api.send_result(fields_to_json ctx l kind subj)
271
272 let handle_display_exception_old ctx dex = match dex with
273 | DisplayPackage pack ->
274 DisplayPosition.display_position#reset;
275 raise (Completion (String.concat "." pack))
276 | DisplayFields r ->
277 DisplayPosition.display_position#reset;
278 let fields = if !Timer.measure_times then begin
279 Timer.close_times();
280 (List.map (fun (name,value) ->
281 CompletionItem.make_ci_timer ("@TIME " ^ name) value
282 ) (get_timer_fields !Helper.start_time)) @ r.fitems
283 end else
284 r.fitems
285 in
286 let s = match r.fkind with
287 | CRToplevel _
288 | CRTypeHint
289 | CRExtends
290 | CRImplements
291 | CRStructExtension _
292 | CRImport
293 | CRUsing
294 | CRNew
295 | CRPattern _
296 | CRTypeRelation
297 | CRTypeDecl ->
298 print_toplevel fields
299 | CRField _
300 | CRStructureField
301 | CRMetadata
302 | CROverride ->
303 print_fields fields
304 in
305 raise (Completion s)
306 | DisplayHover ({hitem = {CompletionItem.ci_type = Some (t,_)}} as hover) ->
307 DisplayPosition.display_position#reset;
308 let doc = CompletionItem.get_documentation hover.hitem in
309 raise (Completion (print_type t hover.hpos doc))
310 | DisplaySignatures (signatures,_,display_arg,_) ->
311 DisplayPosition.display_position#reset;
312 if ctx.com.display.dms_kind = DMSignature then
313 raise (Completion (print_signature signatures display_arg))
314 else
315 raise (Completion (print_signatures signatures))
316 | DisplayPositions pl ->
317 DisplayPosition.display_position#reset;
318 raise (Completion (print_positions pl))
319 | ModuleSymbols s | Metadata s ->
320 DisplayPosition.display_position#reset;
321 raise (Completion s)
322 | DisplayHover _ | DisplayNoResult ->
323 raise (Completion "")
324
325 let handle_display_exception_json ctx dex api =
326 match dex with
327 | DisplayHover _ | DisplayPositions _ | DisplayFields _ | DisplayPackage _ | DisplaySignatures _ ->
328 DisplayPosition.display_position#reset;
329 let ctx = DisplayJson.create_json_context api.jsonrpc (match dex with DisplayFields _ -> true | _ -> false) in
330 api.send_result (DisplayException.to_json ctx dex)
331 | DisplayNoResult ->
332 api.send_result JNull
333 | _ ->
334 handle_display_exception_old ctx dex
335
336 let handle_display_exception ctx dex = match ctx.com.json_out with
337 | Some api ->
338 handle_display_exception_json ctx dex api
339 | None ->
340 handle_display_exception_old ctx dex
341
342 let handle_type_path_exception ctx p c is_import pos =
343 let open DisplayTypes.CompletionResultKind in
344 let com = ctx.com in
345 let fields =
346 try begin match c with
347 | None ->
348 DisplayPath.TypePathHandler.complete_type_path com p
349 | Some (c,cur_package) ->
350 let ctx = Typer.create com in
351 DisplayPath.TypePathHandler.complete_type_path_inner ctx p c cur_package is_import
352 end with Common.Abort msg ->
353 located_error ctx msg;
354 None
355 in
356 begin match ctx.com.json_out,fields with
357 | None,None ->
358 ()
359 | None,Some fields ->
360 raise (Completion (print_fields fields))
361 | Some api,None when is_legacy_completion com ->
362 api.send_result JNull
363 | Some api,fields ->
364 let fields = Option.default [] fields in
365 let ctx = DisplayJson.create_json_context api.jsonrpc false in
366 let path = match List.rev p with
367 | name :: pack -> List.rev pack,name
368 | [] -> [],""
369 in
370 let kind = CRField ((CompletionItem.make_ci_module path,pos,None,None)) in
371 api.send_result (DisplayException.fields_to_json ctx fields kind (DisplayTypes.make_subject None pos));
372 end
373
374 let emit_diagnostics com =
375 let dctx = Diagnostics.run com in
376 let s = Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics com dctx) in
377 DisplayPosition.display_position#reset;
378 raise (Completion s)
379
380 let emit_statistics tctx =
381 let stats = Statistics.collect_statistics tctx [SFFile (DisplayPosition.display_position#get).pfile] true in
382 let s = Statistics.Printer.print_statistics stats in
383 raise (Completion s)
0 open Globals
1 open Common
2 open CompilationContext
3 open DisplayProcessingGlobals
4
5 type display_path_kind =
6 | DPKNormal of path
7 | DPKMacro of path
8 | DPKDirect of string
9 | DPKInput of string
10 | DPKNone
11
12 (* 1. Argument processing from --display *)
13
14 let handle_display_argument_old com file_pos actx =
15 match file_pos with
16 | "classes" ->
17 actx.pre_compilation <- (fun() -> raise (Parser.TypePath (["."],None,true,null_pos))) :: actx.pre_compilation;
18 | "keywords" ->
19 raise (Completion (DisplayOutput.print_keywords ()))
20 | "memory" ->
21 actx.did_something <- true;
22 (try Memory.display_memory com with e -> prerr_endline (Printexc.get_backtrace ()));
23 | "diagnostics" ->
24 com.report_mode <- RMDiagnostics []
25 | _ ->
26 let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format: " ^ file_pos) in
27 let file = Helper.unquote file in
28 let file_unique = com.file_keys#get file in
29 let pos, smode = try ExtString.String.split pos "@" with _ -> pos,"" in
30 let create mode =
31 Parser.display_mode := mode;
32 DisplayTypes.DisplayMode.create mode
33 in
34 let dm = match smode with
35 | "position" ->
36 create DMDefinition
37 | "usage" ->
38 create (DMUsage (false,false,false))
39 | "package" ->
40 create DMPackage
41 | "type" ->
42 create DMHover
43 | "toplevel" ->
44 create DMDefault
45 | "module-symbols" ->
46 create (DMModuleSymbols None)
47 | "diagnostics" ->
48 com.report_mode <- RMDiagnostics [file_unique];
49 let dm = create DMNone in
50 {dm with dms_display_file_policy = DFPAlso; dms_per_file = true}
51 | "statistics" ->
52 com.report_mode <- RMStatistics;
53 let dm = create DMNone in
54 {dm with dms_display_file_policy = DFPAlso; dms_error_policy = EPIgnore; dms_per_file = true}
55 | "signature" ->
56 create DMSignature
57 | "" ->
58 create DMDefault
59 | _ ->
60 let smode,arg = try ExtString.String.split smode "@" with _ -> pos,"" in
61 match smode with
62 | "workspace-symbols" ->
63 create (DMModuleSymbols (Some arg))
64 | _ ->
65 create DMDefault
66 in
67 let pos = try int_of_string pos with _ -> failwith ("Invalid format: " ^ pos) in
68 com.display <- dm;
69 if not com.display.dms_full_typing then Common.define_value com Define.Display (if smode <> "" then smode else "1");
70 DisplayPosition.display_position#set {
71 pfile = Path.get_full_path file;
72 pmin = pos;
73 pmax = pos;
74 }
75
76 let process_display_arg ctx actx =
77 match actx.display_arg with
78 | Some input ->
79 let input = String.trim input in
80 if String.length input > 0 && (input.[0] = '[' || input.[0] = '{') then begin
81 actx.did_something <- true;
82 actx.force_typing <- true;
83 DisplayJson.parse_input ctx.com input Timer.measure_times
84 end else
85 handle_display_argument_old ctx.com input actx;
86 | None ->
87 ()
88
89 (* 2. Compilation start, setup display configuration in context *)
90
91 let process_display_configuration ctx =
92 let com = ctx.com in
93 if is_diagnostics com then begin
94 com.info <- (fun ?depth s p ->
95 add_diagnostics_message ?depth com (located s p) DKCompilerMessage Information
96 );
97 com.warning <- (fun ?depth w options s p ->
98 match Warning.get_mode w (com.warning_options @ options) with
99 | WMEnable ->
100 add_diagnostics_message ?depth com (located s p) DKCompilerMessage Warning
101 | WMDisable ->
102 ()
103 );
104 end;
105 Lexer.old_format := Common.defined com Define.OldErrorFormat;
106 if !Lexer.old_format && !Parser.in_display then begin
107 let p = DisplayPosition.display_position#get in
108 (* convert byte position to utf8 position *)
109 try
110 let content = Std.input_file ~bin:true (Path.get_real_path p.pfile) in
111 let pos = Extlib_leftovers.UTF8.length (String.sub content 0 p.pmin) in
112 DisplayPosition.display_position#set { p with pmin = pos; pmax = pos }
113 with _ ->
114 () (* ignore *)
115 end
116
117 let process_display_file com actx =
118 let get_module_path_from_file_path com spath =
119 let rec loop = function
120 | [] -> None
121 | cp :: l ->
122 let cp = (if cp = "" then "./" else cp) in
123 let c = Path.add_trailing_slash (Path.get_real_path cp) in
124 let clen = String.length c in
125 if clen < String.length spath && String.sub spath 0 clen = c then begin
126 let path = String.sub spath clen (String.length spath - clen) in
127 (try
128 let path = Path.parse_path path in
129 (match loop l with
130 | Some x as r when String.length (s_type_path x) < String.length (s_type_path path) -> r
131 | _ -> Some path)
132 with _ -> loop l)
133 end else
134 loop l
135 in
136 loop com.class_path
137 in
138 match com.display.dms_display_file_policy with
139 | DFPNo ->
140 DPKNone
141 | DFPOnly when (DisplayPosition.display_position#get).pfile = file_input_marker ->
142 actx.classes <- [];
143 com.main_class <- None;
144 begin match !TypeloadParse.current_stdin with
145 | Some input ->
146 TypeloadParse.current_stdin := None;
147 DPKInput input
148 | None ->
149 DPKNone
150 end
151 | dfp ->
152 if dfp = DFPOnly then begin
153 actx.classes <- [];
154 com.main_class <- None;
155 end;
156 let real = Path.get_real_path (DisplayPosition.display_position#get).pfile in
157 let path = match get_module_path_from_file_path com real with
158 | Some path ->
159 if com.display.dms_kind = DMPackage then DisplayException.raise_package (fst path);
160 let path = match ExtString.String.nsplit (snd path) "." with
161 | [name;"macro"] ->
162 (* If we have a .macro.hx path, don't add the file to classes because the compiler won't find it.
163 This can happen if we're completing in such a file. *)
164 DPKMacro (fst path,name)
165 | [name] ->
166 actx.classes <- path :: actx.classes;
167 DPKNormal path
168 | [name;target] ->
169 let path = fst path, name in
170 actx.classes <- path :: actx.classes;
171 DPKNormal path
172 | e ->
173 die "" __LOC__
174 in
175 path
176 | None ->
177 if not (Sys.file_exists real) then failwith "Display file does not exist";
178 (match List.rev (ExtString.String.nsplit real Path.path_sep) with
179 | file :: _ when file.[0] >= 'a' && file.[0] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter")
180 | _ -> ());
181 DPKDirect real
182 in
183 Common.log com ("Display file : " ^ real);
184 Common.log com ("Classes found : [" ^ (String.concat "," (List.map s_type_path actx.classes)) ^ "]");
185 path
186
187 (* 3. Loaders for display file that might be called *)
188
189 let load_display_module_in_macro tctx display_file_dot_path clear = match display_file_dot_path with
190 | Some cpath ->
191 let p = null_pos in
192 begin try
193 let open Typecore in
194 let _, mctx = MacroContext.get_macro_context tctx p in
195 (* Tricky stuff: We want to remove the module from our lookups and load it again in
196 display mode. This covers some cases like --macro typing it in non-display mode (issue #7017). *)
197 if clear then begin
198 begin try
199 let m = mctx.com.module_lut#find cpath in
200 mctx.com.module_lut#remove cpath;
201 mctx.com.type_to_module#remove cpath;
202 List.iter (fun mt ->
203 let ti = Type.t_infos mt in
204 mctx.com.module_lut#remove ti.mt_path;
205 mctx.com.type_to_module#remove ti.mt_path;
206 ) m.m_types
207 with Not_found ->
208 ()
209 end;
210 end;
211 let _ = MacroContext.load_macro_module tctx cpath true p in
212 Finalization.finalize mctx;
213 Some mctx
214 with DisplayException.DisplayException _ | Parser.TypePath _ as exc ->
215 raise exc
216 | _ ->
217 None
218 end
219 | None ->
220 None
221
222 let load_display_file_standalone (ctx : Typecore.typer) file =
223 let com = ctx.com in
224 let pack,decls = TypeloadParse.parse_module_file com file null_pos in
225 let path = Path.FilePath.parse file in
226 let name = match path.file_name with
227 | None -> "?DISPLAY"
228 | Some name -> name
229 in
230 begin match path.directory with
231 | None -> ()
232 | Some dir ->
233 (* Chop off number of package parts from the dir and use that as class path. *)
234 let parts = ExtString.String.nsplit dir (if path.backslash then "\\" else "/") in
235 let parts = List.rev (ExtList.List.drop (List.length pack) (List.rev parts)) in
236 let dir = ExtString.String.join (if path.backslash then "\\" else "/") parts in
237 com.class_path <- dir :: com.class_path
238 end;
239 ignore(TypeloadModule.type_module ctx (pack,name) file ~dont_check_path:true decls null_pos)
240
241 let load_display_content_standalone (ctx : Typecore.typer) input =
242 let com = ctx.com in
243 let file = file_input_marker in
244 let p = {pfile = file; pmin = 0; pmax = 0} in
245 let parsed = TypeloadParse.parse_file_from_string com file p input in
246 let pack,decls = TypeloadParse.handle_parser_result com p parsed in
247 ignore(TypeloadModule.type_module ctx (pack,"?DISPLAY") file ~dont_check_path:true decls p)
248
249 (* 4. Display processing before typing *)
250
251 let maybe_load_display_file_before_typing tctx display_file_dot_path = match display_file_dot_path with
252 | DPKMacro path ->
253 ignore(load_display_module_in_macro tctx (Some path) true);
254 Some path
255 | DPKNormal path ->
256 Some path
257 | DPKNone ->
258 None
259 | DPKDirect file ->
260 load_display_file_standalone tctx file;
261 None
262 | DPKInput input ->
263 load_display_content_standalone tctx input;
264 None
265
266 (* 5. Display processing after typing *)
267
268 let handle_display_after_typing ctx tctx display_file_dot_path =
269 let com = ctx.com in
270 if ctx.com.display.dms_kind = DMNone & ctx.has_error then raise Abort;
271 begin match ctx.com.display.dms_kind,!Parser.delayed_syntax_completion with
272 | DMDefault,Some(kind,subj) -> DisplayOutput.handle_syntax_completion com kind subj
273 | _ -> ()
274 end;
275 if ctx.com.display.dms_exit_during_typing then begin
276 if ctx.has_next || ctx.has_error then raise Abort;
277 (* If we didn't find a completion point, load the display file in macro mode. *)
278 if com.display_information.display_module_has_macro_defines then
279 ignore(load_display_module_in_macro tctx display_file_dot_path true);
280 let no_completion_point_found = "No completion point was found" in
281 match com.json_out with
282 | Some _ ->
283 raise (DisplayException.DisplayException DisplayNoResult)
284 | None ->
285 failwith no_completion_point_found;
286 end
287
288 (* 6. Display processing after finalization *)
289
290 let promote_type_hints (tctx : Typecore.typer) =
291 let open Type in
292 let rec explore_type_hint (md,p,t) =
293 match t with
294 | TMono r -> (match r.tm_type with None -> () | Some t -> explore_type_hint (md,p,t))
295 | TLazy f -> explore_type_hint (md,p,lazy_type f)
296 | TInst(({cl_name_pos = pn;cl_path = (_,name)}),_)
297 | TEnum(({e_name_pos = pn;e_path = (_,name)}),_)
298 | TType(({t_name_pos = pn;t_path = (_,name)}),_)
299 | TAbstract(({a_name_pos = pn;a_path = (_,name)}),_) ->
300 md.m_type_hints <- (p,pn) :: md.m_type_hints;
301 | TDynamic _ -> ()
302 | TFun _ | TAnon _ -> ()
303 in
304 List.iter explore_type_hint tctx.g.type_hints
305
306 let process_global_display_mode com tctx =
307 promote_type_hints tctx;
308 match com.display.dms_kind with
309 | DMUsage (with_definition,_,_) ->
310 FindReferences.find_references tctx com with_definition
311 | DMImplementation ->
312 FindReferences.find_implementations tctx com
313 | DMModuleSymbols (Some "") -> ()
314 | DMModuleSymbols filter ->
315 let open CompilationCache in
316 let cs = com.cs in
317 let symbols =
318 let l = cs#get_context_files ((Define.get_signature com.defines) :: (match com.get_macros() with None -> [] | Some com -> [Define.get_signature com.defines])) in
319 List.fold_left (fun acc (file_key,cfile) ->
320 let file = cfile.c_file_path in
321 if (filter <> None || DisplayPosition.display_position#is_in_file (com.file_keys#get file)) then
322 (file,DocumentSymbols.collect_module_symbols (Some (file,get_module_name_of_cfile file cfile)) (filter = None) (cfile.c_package,cfile.c_decls)) :: acc
323 else
324 acc
325 ) [] l
326 in
327 DisplayException.raise_module_symbols (DocumentSymbols.Printer.print_module_symbols com symbols filter)
328 | _ -> ()
329
330 let handle_display_after_finalization ctx tctx display_file_dot_path =
331 let com = ctx.com in
332 (* Special case for diagnostics: We don't want to load the display file in macro mode because there's a chance it might not be
333 macro-compatible. This means that we might some macro-specific diagnostics, but I don't see what we could do about that. *)
334 let should_load_in_macro =
335 (* Special case for the special case: If the display file has a block which becomes active if `macro` is defined, we can safely
336 type the module in macro context. (#8682). *)
337 not (is_diagnostics com) || com.display_information.display_module_has_macro_defines
338 in
339 if ctx.com.display.dms_force_macro_typing && should_load_in_macro then begin
340 match load_display_module_in_macro tctx display_file_dot_path false with
341 | None -> ()
342 | Some mctx ->
343 (* We don't need a full macro flush here because we're not going to run any macros. *)
344 let _, types, modules = Finalization.generate mctx in
345 mctx.Typecore.com.types <- types;
346 mctx.Typecore.com.Common.modules <- modules
347 end;
348 process_global_display_mode com tctx;
349 begin match com.report_mode with
350 | RMDiagnostics _ ->
351 DisplayOutput.emit_diagnostics com
352 | RMStatistics ->
353 DisplayOutput.emit_statistics tctx
354 | RMNone ->
355 ()
356 end
0 exception Completion of string
1
2 let file_input_marker = Path.get_full_path "? input"
0 open Globals
1 open CompilationContext
2
3 let check_auxiliary_output com actx =
4 begin match actx.xml_out with
5 | None -> ()
6 | Some "hx" ->
7 Genhxold.generate com
8 | Some file ->
9 Common.log com ("Generating xml: " ^ file);
10 Path.mkdir_from_path file;
11 Genxml.generate com file
12 end;
13 begin match actx.json_out with
14 | None -> ()
15 | Some file ->
16 Common.log com ("Generating json : " ^ file);
17 Path.mkdir_from_path file;
18 Genjson.generate com.types file
19 end
20
21
22 let parse_swf_header ctx h = match ExtString.String.nsplit h ":" with
23 | [width; height; fps] ->
24 Some (int_of_string width,int_of_string height,float_of_string fps,0xFFFFFF)
25 | [width; height; fps; color] ->
26 let color = if ExtString.String.starts_with color "0x" then color else "0x" ^ color in
27 Some (int_of_string width, int_of_string height, float_of_string fps, int_of_string color)
28 | _ ->
29 error ctx "Invalid SWF header format, expected width:height:fps[:color]" null_pos;
30 None
31
32 let delete_file f = try Sys.remove f with _ -> ()
33
34 let generate ctx tctx ext actx =
35 let com = tctx.Typecore.com in
36 (* check file extension. In case of wrong commandline, we don't want
37 to accidentaly delete a source file. *)
38 if Path.file_extension com.file = ext then delete_file com.file;
39 if com.platform = Flash || com.platform = Cpp || com.platform = Hl then List.iter (Codegen.fix_overrides com) com.types;
40 if Common.defined com Define.Dump then begin
41 Codegen.Dump.dump_types com;
42 Option.may Codegen.Dump.dump_types (com.get_macros())
43 end;
44 if Common.defined com Define.DumpDependencies then begin
45 Codegen.Dump.dump_dependencies com;
46 if not com.is_macro_context then match tctx.Typecore.g.Typecore.macros with
47 | None -> ()
48 | Some(_,ctx) -> Codegen.Dump.dump_dependencies ~target_override:(Some "macro") ctx.Typecore.com
49 end;
50 begin match com.platform with
51 | Neko | Hl | Eval when actx.interp -> ()
52 | Cpp when Common.defined com Define.Cppia -> ()
53 | Cpp | Cs | Php -> Path.mkdir_from_path (com.file ^ "/.")
54 | Java when not actx.jvm_flag -> Path.mkdir_from_path (com.file ^ "/.")
55 | _ -> Path.mkdir_from_path com.file
56 end;
57 if actx.interp then
58 Std.finally (Timer.timer ["interp"]) MacroContext.interpret tctx
59 else if com.platform = Cross then
60 ()
61 else begin
62 let generate,name = match com.platform with
63 | Flash ->
64 let header = try
65 parse_swf_header ctx (Common.defined_value com Define.SwfHeader)
66 with Not_found ->
67 None
68 in
69 Genswf.generate header,"swf"
70 | Neko ->
71 Genneko.generate,"neko"
72 | Js ->
73 Genjs.generate,"js"
74 | Lua ->
75 Genlua.generate,"lua"
76 | Php ->
77 Genphp7.generate,"php"
78 | Cpp ->
79 Gencpp.generate,"cpp"
80 | Cs ->
81 Gencs.generate,"cs"
82 | Java ->
83 if Common.defined com Jvm then
84 Genjvm.generate actx.jvm_flag,"java"
85 else
86 Genjava.generate,"java"
87 | Python ->
88 Genpy.generate,"python"
89 | Hl ->
90 Genhl.generate,"hl"
91 | Eval ->
92 (fun _ -> MacroContext.interpret tctx),"eval"
93 | Cross ->
94 die "" __LOC__
95 in
96 Common.log com ("Generating " ^ name ^ ": " ^ com.file);
97 let t = Timer.timer ["generate";name] in
98 generate com;
99 t()
100 end
4040 trailing l means list (but we also use natural plurals such as "metas")
4141 semantic suffixes may be used freely (e.g. e1, e_if, e')
4242 *)
43 open Extlib_leftovers
44 open Printf
45 open Common
46 open DisplayTypes.DisplayMode
47 open DisplayTypes.CompletionResultKind
48 open DisplayException
49 open Type
5043 open Server
51 open Globals
52 open Filename
5344
54 exception Abort
55 exception HelpMessage of string
56
57 let executable_path() =
58 Extc.executable_path()
59
60 let message ctx msg =
61 ctx.messages <- msg :: ctx.messages
62
63 let deprecated = []
64
65 let limit_string s offset =
66 let rest = 80 - offset in
67 let words = ExtString.String.nsplit s " " in
68 let rec loop i words = match words with
69 | word :: words ->
70 if String.length word + i + 1 > rest then (Printf.sprintf "\n%*s" offset "") :: word :: loop (String.length word) words
71 else (if i = 0 then "" else " ") :: word :: loop (i + 1 + String.length word) words
72 | [] ->
73 []
74 in
75 String.concat "" (loop 0 words)
76
77 let error ctx msg p =
78 let msg = try List.assoc msg deprecated with Not_found -> msg in
79 message ctx (CMError(msg,p));
80 ctx.has_error <- true
81
82 let reserved_flags = [
83 "true";"false";"null";"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python";
84 "swc";"macro";"sys";"static";"utf16";"haxe";"haxe_ver"
85 ]
86
87 let reserved_flag_namespaces = ["target"]
88
89 let delete_file f = try Sys.remove f with _ -> ()
90
91 let expand_env ?(h=None) path =
92 let r = Str.regexp "%\\([A-Za-z0-9_]+\\)%" in
93 Str.global_substitute r (fun s ->
94 let key = Str.matched_group 1 s in
95 try
96 Sys.getenv key
97 with Not_found -> try
98 match h with
99 | None -> raise Not_found
100 | Some h -> Hashtbl.find h key
101 with Not_found ->
102 "%" ^ key ^ "%"
103 ) path
104
105 let add_libs com libs =
106 let global_repo = List.exists (fun a -> a = "--haxelib-global") com.args in
107 let call_haxelib() =
108 let t = Timer.timer ["haxelib"] in
109 let cmd = "haxelib" ^ (if global_repo then " --global" else "") ^ " path " ^ String.concat " " libs in
110 let pin, pout, perr = Unix.open_process_full cmd (Unix.environment()) in
111 let lines = Std.input_list pin in
112 let err = Std.input_list perr in
113 let ret = Unix.close_process_full (pin,pout,perr) in
114 if ret <> Unix.WEXITED 0 then failwith (match lines, err with
115 | [], [] -> "Failed to call haxelib (command not found ?)"
116 | [], [s] when ExtString.String.ends_with (ExtString.String.strip s) "Module not found: path" -> "The haxelib command has been strip'ed, please install it again"
117 | _ -> String.concat "\n" (lines@err));
118 t();
119 lines
120 in
121 match libs with
122 | [] -> []
123 | _ ->
124 let lines = match CompilationServer.get() with
125 | Some cs ->
126 (try
127 (* if we are compiling, really call haxelib since library path might have changed *)
128 if not com.display.dms_display then raise Not_found;
129 cs#find_haxelib libs
130 with Not_found ->
131 let lines = call_haxelib() in
132 cs#cache_haxelib libs lines;
133 lines)
134 | _ -> call_haxelib()
135 in
136 let extra_args = ref [] in
137 let lines = List.fold_left (fun acc l ->
138 let l = ExtString.String.strip l in
139 if l = "" then acc else
140 if l.[0] <> '-' then l :: acc else
141 match (try ExtString.String.split l " " with _ -> l, "") with
142 | ("-L",dir) ->
143 com.neko_libs <- String.sub l 3 (String.length l - 3) :: com.neko_libs;
144 acc
145 | param, value ->
146 extra_args := param :: !extra_args;
147 if value <> "" then extra_args := value :: !extra_args;
148 acc
149 ) [] lines in
150 com.class_path <- lines @ com.class_path;
151 List.rev !extra_args
152
153 let run_command ctx cmd =
154 let h = Hashtbl.create 0 in
155 Hashtbl.add h "__file__" ctx.com.file;
156 Hashtbl.add h "__platform__" (platform_name ctx.com.platform);
157 let t = Timer.timer ["command"] in
158 let cmd = expand_env ~h:(Some h) cmd in
159 let len = String.length cmd in
160 let result =
161 if len > 3 && String.sub cmd 0 3 = "cd " then begin
162 Sys.chdir (String.sub cmd 3 (len - 3));
163 0
164 (* Emit stderr as a server message in server mode *)
165 end else if CompilationServer.runs() then begin
166 let binary_string s =
167 if not Globals.is_windows then s else String.concat "\n" (Str.split (Str.regexp "\r\n") s)
168 in
169 let pout, pin, perr = Unix.open_process_full cmd (Unix.environment()) in
170 let bout = Buffer.create 0 in
171 let berr = Buffer.create 0 in
172 let read_content channel buf =
173 Buffer.add_string buf (IO.read_all (IO.input_channel channel));
174 in
175 let tout = Thread.create (fun() -> read_content pout bout) () in
176 read_content perr berr;
177 Thread.join tout;
178 let result = (match Unix.close_process_full (pout,pin,perr) with Unix.WEXITED c | Unix.WSIGNALED c | Unix.WSTOPPED c -> c) in
179 let serr = binary_string (Buffer.contents berr) in
180 let sout = binary_string (Buffer.contents bout) in
181 if serr <> "" then ctx.messages <- CMError((if serr.[String.length serr - 1] = '\n' then String.sub serr 0 (String.length serr - 1) else serr),null_pos) :: ctx.messages;
182 if sout <> "" then ctx.com.print (sout ^ "\n");
183 result
184 (* Direct pass-through of std streams for normal compilation *)
185 end else begin
186 match Unix.system cmd with
187 | WEXITED c | WSIGNALED c | WSTOPPED c -> c
188 end
189 in
190 t();
191 result
192
193 module Initialize = struct
194 let set_platform com pf file =
195 if com.platform <> Cross then failwith "Multiple targets";
196 Common.init_platform com pf;
197 com.file <- file;
198 if (pf = Flash) && file_extension file = "swc" then Common.define com Define.Swc
199
200 let initialize_target ctx com classes =
201 let add_std dir =
202 com.class_path <- List.filter (fun s -> not (List.mem s com.std_path)) com.class_path @ List.map (fun p -> p ^ dir ^ "/_std/") com.std_path @ com.std_path
203 in
204 match com.platform with
205 | Cross ->
206 (* no platform selected *)
207 set_platform com Cross "";
208 "?"
209 | Flash ->
210 let rec loop = function
211 | [] -> ()
212 | (v,_) :: _ when v > com.flash_version -> ()
213 | (v,def) :: l ->
214 Common.raw_define com ("flash" ^ def);
215 loop l
216 in
217 loop Common.flash_versions;
218 Common.raw_define com "flash";
219 com.package_rules <- PMap.remove "flash" com.package_rules;
220 add_std "flash";
221 "swf"
222 | Neko ->
223 add_std "neko";
224 "n"
225 | Js ->
226 let es_version =
227 try
228 int_of_string (Common.defined_value com Define.JsEs)
229 with
230 | Not_found ->
231 (Common.define_value com Define.JsEs "5"; 5)
232 | _ ->
233 0
234 in
235
236 if es_version < 3 || es_version = 4 then (* we don't support ancient and there's no 4th *)
237 failwith "Invalid -D js-es value";
238
239 if es_version >= 5 then Common.raw_define com "js-es5"; (* backward-compatibility *)
240
241 add_std "js";
242 "js"
243 | Lua ->
244 add_std "lua";
245 "lua"
246 | Php ->
247 add_std "php";
248 "php"
249 | Cpp ->
250 Common.define_value com Define.HxcppApiLevel "400";
251 add_std "cpp";
252 if Common.defined com Define.Cppia then
253 classes := (Path.parse_path "cpp.cppia.HostClasses" ) :: !classes;
254 "cpp"
255 | Cs ->
256 let old_flush = ctx.flush in
257 ctx.flush <- (fun () ->
258 com.native_libs.net_libs <- [];
259 old_flush()
260 );
261 Dotnet.before_generate com;
262 add_std "cs"; "cs"
263 | Java ->
264 let old_flush = ctx.flush in
265 ctx.flush <- (fun () ->
266 List.iter (fun java_lib -> java_lib#close) com.native_libs.java_libs;
267 com.native_libs.java_libs <- [];
268 old_flush()
269 );
270 Java.before_generate com;
271 if defined com Define.Jvm then begin
272 add_std "jvm";
273 com.package_rules <- PMap.remove "jvm" com.package_rules;
274 end;
275 add_std "java";
276 "java"
277 | Python ->
278 add_std "python";
279 if not (Common.defined com Define.PythonVersion) then
280 Common.define_value com Define.PythonVersion "3.3";
281 "python"
282 | Hl ->
283 add_std "hl";
284 if not (Common.defined com Define.HlVer) then Define.define_value com.defines Define.HlVer (try Std.input_file (Common.find_file com "hl/hl_version") with Not_found -> die "" __LOC__);
285 "hl"
286 | Eval ->
287 add_std "eval";
288 "eval"
289 end
290
291 let generate tctx ext interp jvm_flag swf_header =
292 let com = tctx.Typecore.com in
293 (* check file extension. In case of wrong commandline, we don't want
294 to accidentaly delete a source file. *)
295 if file_extension com.file = ext then delete_file com.file;
296 if com.platform = Flash || com.platform = Cpp || com.platform = Hl then List.iter (Codegen.fix_overrides com) com.types;
297 if Common.defined com Define.Dump then begin
298 Codegen.Dump.dump_types com;
299 Option.may Codegen.Dump.dump_types (com.get_macros())
300 end;
301 if Common.defined com Define.DumpDependencies then begin
302 Codegen.Dump.dump_dependencies com;
303 if not tctx.Typecore.in_macro then match tctx.Typecore.g.Typecore.macros with
304 | None -> ()
305 | Some(_,ctx) -> Codegen.Dump.dump_dependencies ~target_override:(Some "macro") ctx.Typecore.com
306 end;
307 begin match com.platform with
308 | Neko | Hl | Eval when interp -> ()
309 | Cpp when Common.defined com Define.Cppia -> ()
310 | Cpp | Cs | Php -> Path.mkdir_from_path (com.file ^ "/.")
311 | Java when not jvm_flag -> Path.mkdir_from_path (com.file ^ "/.")
312 | _ -> Path.mkdir_from_path com.file
313 end;
314 if interp then
315 Std.finally (Timer.timer ["interp"]) MacroContext.interpret tctx
316 else if com.platform = Cross then
317 ()
318 else begin
319 let generate,name = match com.platform with
320 | Flash ->
321 Genswf.generate swf_header,"swf"
322 | Neko ->
323 Genneko.generate,"neko"
324 | Js ->
325 Genjs.generate,"js"
326 | Lua ->
327 Genlua.generate,"lua"
328 | Php ->
329 Genphp7.generate,"php"
330 | Cpp ->
331 Gencpp.generate,"cpp"
332 | Cs ->
333 Gencs.generate,"cs"
334 | Java ->
335 if Common.defined com Jvm then
336 Genjvm.generate jvm_flag,"java"
337 else
338 Genjava.generate,"java"
339 | Python ->
340 Genpy.generate,"python"
341 | Hl ->
342 Genhl.generate,"hl"
343 | Eval ->
344 (fun _ -> MacroContext.interpret tctx),"eval"
345 | Cross ->
346 die "" __LOC__
347 in
348 Common.log com ("Generating " ^ name ^ ": " ^ com.file);
349 let t = Timer.timer ["generate";name] in
350 generate com;
351 t()
352 end
353
354 let get_std_class_paths () =
355 try
356 let p = Sys.getenv "HAXE_STD_PATH" in
357 let rec loop = function
358 | drive :: path :: l ->
359 if String.length drive = 1 && ((drive.[0] >= 'a' && drive.[0] <= 'z') || (drive.[0] >= 'A' && drive.[0] <= 'Z')) then
360 (drive ^ ":" ^ path) :: loop l
361 else
362 drive :: loop (path :: l)
363 | l ->
364 l
365 in
366 let parts = Str.split_delim (Str.regexp "[;:]") p in
367 "" :: List.map Path.add_trailing_slash (loop parts)
368 with Not_found ->
369 let base_path = Path.get_real_path (try executable_path() with _ -> "./") in
370 if Sys.os_type = "Unix" then
371 let prefix_path = Filename.dirname base_path in
372 let lib_path = Filename.concat prefix_path "lib" in
373 let share_path = Filename.concat prefix_path "share" in
374 [
375 "";
376 Path.add_trailing_slash (Filename.concat lib_path "haxe/std");
377 Path.add_trailing_slash (Filename.concat lib_path "haxe/extraLibs");
378 Path.add_trailing_slash (Filename.concat share_path "haxe/std");
379 Path.add_trailing_slash (Filename.concat share_path "haxe/extraLibs");
380 Path.add_trailing_slash (Filename.concat base_path "std");
381 Path.add_trailing_slash (Filename.concat base_path "extraLibs")
382 ]
383 else
384 [
385 "";
386 Path.add_trailing_slash (Filename.concat base_path "std");
387 Path.add_trailing_slash (Filename.concat base_path "extraLibs")
388 ]
389
390 let setup_common_context ctx com =
391 Common.define_value com Define.HaxeVer (Printf.sprintf "%.3f" (float_of_int Globals.version /. 1000.));
392 Common.raw_define com "haxe3";
393 Common.raw_define com "haxe4";
394 Common.define_value com Define.Haxe (s_version false);
395 Common.define_value com Define.Dce "std";
396 com.info <- (fun msg p -> message ctx (CMInfo(msg,p)));
397 com.warning <- (fun msg p -> message ctx (CMWarning(msg,p)));
398 com.error <- error ctx;
399 let filter_messages = (fun keep_errors predicate -> (List.filter (fun msg ->
400 (match msg with
401 | CMError(_,_) -> keep_errors;
402 | CMInfo(_,_) | CMWarning(_,_) -> predicate msg;)
403 ) (List.rev ctx.messages))) in
404 com.get_messages <- (fun () -> (List.map (fun msg ->
405 (match msg with
406 | CMError(_,_) -> die "" __LOC__;
407 | CMInfo(_,_) | CMWarning(_,_) -> msg;)
408 ) (filter_messages false (fun _ -> true))));
409 com.filter_messages <- (fun predicate -> (ctx.messages <- (List.rev (filter_messages true predicate))));
410 if CompilationServer.runs() then com.run_command <- run_command ctx;
411 com.class_path <- get_std_class_paths ();
412 com.std_path <- List.filter (fun p -> ExtString.String.ends_with p "std/" || ExtString.String.ends_with p "std\\") com.class_path
413
414 let process_args arg_spec =
415 (* Takes a list of arg specs including some custom info, and generates a
416 list in the format Arg.parse_argv wants. Handles multiple official or
417 deprecated names for the same arg; deprecated versions will display a
418 warning. *)
419 List.flatten(List.map (fun (cat, ok, dep, spec, hint, doc) ->
420 (* official argument names *)
421 (List.map (fun (arg) -> (arg, spec, doc)) ok) @
422 (* deprecated argument names *)
423 (* let dep_msg arg = (Printf.sprintf "WARNING: %s is deprecated" arg) ^ (if List.length ok > 0 then (Printf.sprintf ". Use %s instead" (String.concat "/" ok)) else "") in *)
424 (* For now, these warnings are a noop. Can replace this function to
425 enable error output: *)
426 (* let dep_fun = prerr_endline (dep_msg arg) in *)
427 let dep_fun arg spec = () in
428 let dep_spec arg spec = match spec with
429 | Arg.String f -> Arg.String (fun x -> dep_fun arg spec; f x)
430 | Arg.Unit f -> Arg.Unit (fun x -> dep_fun arg spec; f x)
431 | Arg.Bool f -> Arg.Bool (fun x -> dep_fun arg spec; f x)
432 | _ -> spec in
433 (List.map (fun (arg) -> (arg, dep_spec arg spec, doc)) dep)
434 ) arg_spec)
435
436 let usage_string ?(print_cat=true) arg_spec usage =
437 let make_label = fun names hint -> Printf.sprintf "%s %s" (String.concat ", " names) hint in
438 let args = (List.filter (fun (cat, ok, dep, spec, hint, doc) -> (List.length ok) > 0) arg_spec) in
439 let cat_order = ["Target";"Compilation";"Optimization";"Debug";"Batch";"Services";"Compilation Server";"Target-specific";"Miscellaneous"] in
440 let cats = List.filter (fun x -> List.mem x (List.map (fun (cat, _, _, _, _, _) -> cat) args)) cat_order in
441 let max_length = List.fold_left max 0 (List.map String.length (List.map (fun (_, ok, _, _, hint, _) -> make_label ok hint) args)) in
442 usage ^ (String.concat "\n" (List.flatten (List.map (fun cat -> (if print_cat then ["\n"^cat^":"] else []) @ (List.map (fun (cat, ok, dep, spec, hint, doc) ->
443 let label = make_label ok hint in
444 Printf.sprintf " %s%s %s" label (String.make (max_length - (String.length label)) ' ') doc
445 ) (List.filter (fun (cat', _, _, _, _, _) -> (if List.mem cat' cat_order then cat' else "Miscellaneous") = cat) args))) cats)))
446
447 let process_display_configuration ctx =
448 let com = ctx.com in
449 if com.display.dms_kind <> DMNone then begin
450 com.warning <-
451 if com.display.dms_error_policy = EPCollect then
452 (fun s p -> add_diagnostics_message com s p DKCompilerError DisplayTypes.DiagnosticsSeverity.Warning)
453 else
454 (fun msg p -> message ctx (CMWarning(msg,p)));
455 com.error <- error ctx;
456 end;
457 Lexer.old_format := Common.defined com Define.OldErrorFormat;
458 if !Lexer.old_format && !Parser.in_display then begin
459 let p = DisplayPosition.display_position#get in
460 (* convert byte position to utf8 position *)
461 try
462 let content = Std.input_file ~bin:true (Path.get_real_path p.pfile) in
463 let pos = UTF8.length (String.sub content 0 p.pmin) in
464 DisplayPosition.display_position#set { p with pmin = pos; pmax = pos }
465 with _ ->
466 () (* ignore *)
467 end
468
469 let run_or_diagnose com f arg =
470 let handle_diagnostics msg p kind =
471 add_diagnostics_message com msg p kind DisplayTypes.DiagnosticsSeverity.Error;
472 Diagnostics.run com;
473 in
474 match com.display.dms_kind with
475 | DMDiagnostics _ ->
476 begin try
477 f arg
478 with
479 | Error.Error(msg,p) ->
480 handle_diagnostics (Error.error_msg msg) p DisplayTypes.DiagnosticsKind.DKCompilerError
481 | Parser.Error(msg,p) ->
482 handle_diagnostics (Parser.error_msg msg) p DisplayTypes.DiagnosticsKind.DKParserError
483 | Lexer.Error(msg,p) ->
484 handle_diagnostics (Lexer.error_msg msg) p DisplayTypes.DiagnosticsKind.DKParserError
485 end
486 | _ ->
487 f arg
488
489 let create_typer_context ctx native_libs =
490 let com = ctx.com in
491 ctx.setup();
492 Common.log com ("Classpath: " ^ (String.concat ";" com.class_path));
493 Common.log com ("Defines: " ^ (String.concat ";" (PMap.foldi (fun k v acc -> (match v with "1" -> k | _ -> k ^ "=" ^ v) :: acc) com.defines.Define.values [])));
494 Typecore.type_expr_ref := (fun ?(mode=MGet) ctx e with_type -> Typer.type_expr ~mode ctx e with_type);
495 List.iter (fun f -> f ()) (List.rev com.callbacks#get_before_typer_create);
496 (* Native lib pass 1: Register *)
497 let fl = List.map (fun (file,extern) -> NativeLibraryHandler.add_native_lib com file extern) (List.rev native_libs) in
498 (* Native lib pass 2: Initialize *)
499 List.iter (fun f -> f()) fl;
500 Typer.create com
501
502 (** Creates the typer context and types [classes] into it. *)
503 let do_type tctx config_macros classes =
504 let com = tctx.Typecore.com in
505 let t = Timer.timer ["typing"] in
506 Option.may (fun cs -> CommonCache.maybe_add_context_sign cs com "before_init_macros") (CompilationServer.get ());
507 com.stage <- CInitMacrosStart;
508 List.iter (MacroContext.call_init_macro tctx) (List.rev config_macros);
509 com.stage <- CInitMacrosDone;
510 CommonCache.lock_signature com "after_init_macros";
511 List.iter (fun f -> f ()) (List.rev com.callbacks#get_after_init_macros);
512 run_or_diagnose com (fun () ->
513 if com.display.dms_kind <> DMNone then Option.may (DisplayTexpr.check_display_file tctx) (CompilationServer.get ());
514 List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath null_pos)) (List.rev classes);
515 Finalization.finalize tctx;
516 ) ();
517 com.stage <- CTypingDone;
518 (* If we are trying to find references, let's syntax-explore everything we know to check for the
519 identifier we are interested in. We then type only those modules that contain the identifier. *)
520 begin match !CompilationServer.instance,com.display.dms_kind with
521 | Some cs,(DMUsage _ | DMImplementation) -> FindReferences.find_possible_references tctx cs;
522 | _ -> ()
523 end;
524 t()
525
526 let load_display_module_in_macro tctx display_file_dot_path clear = match display_file_dot_path with
527 | Some cpath ->
528 let p = null_pos in
529 begin try
530 let open Typecore in
531 let _, mctx = MacroContext.get_macro_context tctx p in
532 (* Tricky stuff: We want to remove the module from our lookups and load it again in
533 display mode. This covers some cases like --macro typing it in non-display mode (issue #7017). *)
534 if clear then begin
535 begin try
536 let m = Hashtbl.find mctx.g.modules cpath in
537 Hashtbl.remove mctx.g.modules cpath;
538 Hashtbl.remove mctx.g.types_module cpath;
539 List.iter (fun mt ->
540 let ti = t_infos mt in
541 Hashtbl.remove mctx.g.modules ti.mt_path;
542 Hashtbl.remove mctx.g.types_module ti.mt_path;
543 ) m.m_types
544 with Not_found ->
545 ()
546 end;
547 end;
548 let _ = MacroContext.load_macro_module tctx cpath true p in
549 Finalization.finalize mctx;
550 Some mctx
551 with DisplayException _ | Parser.TypePath _ as exc ->
552 raise exc
553 | _ ->
554 None
555 end
556 | None ->
557 None
558
559 let handle_display ctx tctx display_file_dot_path =
560 let com = ctx.com in
561 if not ctx.com.display.dms_display && ctx.has_error then raise Abort;
562 begin match ctx.com.display.dms_kind,!Parser.delayed_syntax_completion with
563 | DMDefault,Some(kind,subj) -> DisplayOutput.handle_syntax_completion com kind subj
564 | _ -> ()
565 end;
566 if ctx.com.display.dms_exit_during_typing then begin
567 if ctx.has_next || ctx.has_error then raise Abort;
568 (* If we didn't find a completion point, load the display file in macro mode. *)
569 if com.display_information.display_module_has_macro_defines then
570 ignore(load_display_module_in_macro tctx display_file_dot_path true);
571 let no_completion_point_found = "No completion point was found" in
572 match com.json_out with
573 | Some _ -> (match ctx.com.display.dms_kind with
574 | DMDefault -> raise (DisplayException(DisplayFields None))
575 | DMSignature -> raise (DisplayException(DisplaySignatures None))
576 | DMHover -> raise (DisplayException(DisplayHover None))
577 | DMDefinition | DMTypeDefinition -> raise_positions []
578 | _ -> failwith no_completion_point_found)
579 | None ->
580 failwith no_completion_point_found;
581 end
582
583 let filter ctx tctx display_file_dot_path =
584 let com = ctx.com in
585 com.stage <- CFilteringStart;
586 let t = Timer.timer ["filters"] in
587 let main, types, modules = run_or_diagnose com Finalization.generate tctx in
588 com.main <- main;
589 com.types <- types;
590 com.modules <- modules;
591 (* Special case for diagnostics: We don't want to load the display file in macro mode because there's a chance it might not be
592 macro-compatible. This means that we might some macro-specific diagnostics, but I don't see what we could do about that. *)
593 let should_load_in_macro = match ctx.com.display.dms_kind with
594 (* Special case for the special case: If the display file has a block which becomes active if `macro` is defined, we can safely
595 type the module in macro context. (#8682). *)
596 | DMDiagnostics _ -> com.display_information.display_module_has_macro_defines
597 | _ -> true
598 in
599 if ctx.com.display.dms_force_macro_typing && should_load_in_macro then begin
600 match load_display_module_in_macro tctx display_file_dot_path false with
601 | None -> ()
602 | Some mctx ->
603 (* We don't need a full macro flush here because we're not going to run any macros. *)
604 let _, types, modules = Finalization.generate mctx in
605 mctx.Typecore.com.types <- types;
606 mctx.Typecore.com.Common.modules <- modules
607 end;
608 DisplayOutput.process_global_display_mode com tctx;
609 DeprecationCheck.run com;
610 Filters.run com tctx main;
611 t()
612
613 let check_auxiliary_output com xml_out json_out =
614 begin match xml_out with
615 | None -> ()
616 | Some "hx" ->
617 Genhxold.generate com
618 | Some file ->
619 Common.log com ("Generating xml: " ^ file);
620 Path.mkdir_from_path file;
621 Genxml.generate com file
622 end;
623 begin match json_out with
624 | None -> ()
625 | Some file ->
626 Common.log com ("Generating json : " ^ file);
627 Path.mkdir_from_path file;
628 Genjson.generate com.types file
629 end
630
631 let parse_host_port hp =
632 let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in
633 let port = try int_of_string port with _ -> raise (Arg.Bad "Invalid port") in
634 host, port
635
636 let rec process_params create pl =
637 let each_params = ref [] in
638 let rec loop acc = function
639 | [] ->
640 let ctx = create (!each_params @ (List.rev acc)) in
641 init ctx;
642 ctx.flush()
643 | "--next" :: l when acc = [] -> (* skip empty --next *)
644 loop [] l
645 | "--next" :: l ->
646 let ctx = create (!each_params @ (List.rev acc)) in
647 ctx.has_next <- true;
648 init ctx;
649 ctx.flush();
650 loop [] l
651 | "--each" :: l ->
652 each_params := List.rev acc;
653 loop [] l
654 | "--cwd" :: dir :: l | "-C" :: dir :: l ->
655 (* we need to change it immediately since it will affect hxml loading *)
656 (try Unix.chdir dir with _ -> raise (Arg.Bad ("Invalid directory: " ^ dir)));
657 (* Push the --cwd arg so the arg processor know we did something. *)
658 loop (dir :: "--cwd" :: acc) l
659 | "--connect" :: hp :: l ->
660 (match CompilationServer.get() with
661 | None ->
662 let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in
663 do_connect host (try int_of_string port with _ -> raise (Arg.Bad "Invalid port")) ((List.rev acc) @ l)
664 | Some _ ->
665 (* already connected : skip *)
666 loop acc l)
667 | "--run" :: cl :: args ->
668 let acc = cl :: "-x" :: acc in
669 let ctx = create (!each_params @ (List.rev acc)) in
670 ctx.com.sys_args <- args;
671 init ctx;
672 ctx.flush()
673 | arg :: l ->
674 match List.rev (ExtString.String.nsplit arg ".") with
675 | "hxml" :: _ when (match acc with "-cmd" :: _ | "--cmd" :: _ -> false | _ -> true) ->
676 let acc, l = (try acc, parse_hxml arg @ l with Not_found -> (arg ^ " (file not found)") :: acc, l) in
677 loop acc l
678 | _ -> loop (arg :: acc) l
679 in
680 (* put --display in front if it was last parameter *)
681 let pl = (match List.rev pl with
682 | file :: "--display" :: pl when file <> "memory" -> "--display" :: file :: List.rev pl
683 | _ -> pl
684 ) in
685 loop [] pl
686
687 and init ctx =
688 let usage = Printf.sprintf
689 "Haxe Compiler %s - (C)2005-2020 Haxe Foundation\nUsage: haxe%s <target> [options] [hxml files and dot paths...]\n"
690 (s_version true) (if Sys.os_type = "Win32" then ".exe" else "")
691 in
692 let com = ctx.com in
693 let classes = ref [([],"Std")] in
694 try
695 set_binary_mode_out stdout true;
696 set_binary_mode_out stderr true;
697 let xml_out = ref None in
698 let json_out = ref None in
699 let swf_header = ref None in
700 let cmds = ref [] in
701 let config_macros = ref [] in
702 let cp_libs = ref [] in
703 let added_libs = Hashtbl.create 0 in
704 let no_output = ref false in
705 let did_something = ref false in
706 let force_typing = ref false in
707 let pre_compilation = ref [] in
708 let interp = ref false in
709 let jvm_flag = ref false in
710 let swf_version = ref false in
711 let native_libs = ref [] in
712 let add_native_lib file extern = native_libs := (file,extern) :: !native_libs in
713 setup_common_context ctx com;
714 let define f = Arg.Unit (fun () -> Common.define com f) in
715 let process_ref = ref (fun args -> ()) in
716 let process_libs() =
717 let libs = List.filter (fun l -> not (Hashtbl.mem added_libs l)) (List.rev !cp_libs) in
718 cp_libs := [];
719 List.iter (fun l -> Hashtbl.add added_libs l ()) libs;
720 (* immediately process the arguments to insert them at the place -lib was defined *)
721 match add_libs com libs with
722 | [] -> ()
723 | args -> (!process_ref) args
724 in
725 (* category, official names, deprecated names, arg spec, usage hint, doc *)
726 let basic_args_spec = [
727 ("Target",["--js"],["-js"],Arg.String (Initialize.set_platform com Js),"<file>","generate JavaScript code into target file");
728 ("Target",["--lua"],["-lua"],Arg.String (Initialize.set_platform com Lua),"<file>","generate Lua code into target file");
729 ("Target",["--swf"],["-swf"],Arg.String (Initialize.set_platform com Flash),"<file>","generate Flash SWF bytecode into target file");
730 ("Target",["--neko"],["-neko"],Arg.String (Initialize.set_platform com Neko),"<file>","generate Neko bytecode into target file");
731 ("Target",["--php"],["-php"],Arg.String (fun dir ->
732 classes := (["php"],"Boot") :: !classes;
733 Initialize.set_platform com Php dir;
734 ),"<directory>","generate PHP code into target directory");
735 ("Target",["--cpp"],["-cpp"],Arg.String (fun dir ->
736 Initialize.set_platform com Cpp dir;
737 ),"<directory>","generate C++ code into target directory");
738 ("Target",["--cppia"],["-cppia"],Arg.String (fun file ->
739 Common.define com Define.Cppia;
740 Initialize.set_platform com Cpp file;
741 ),"<file>","generate Cppia bytecode into target file");
742 ("Target",["--cs"],["-cs"],Arg.String (fun dir ->
743 cp_libs := "hxcs" :: !cp_libs;
744 Initialize.set_platform com Cs dir;
745 ),"<directory>","generate C# code into target directory");
746 ("Target",["--java"],["-java"],Arg.String (fun dir ->
747 cp_libs := "hxjava" :: !cp_libs;
748 Initialize.set_platform com Java dir;
749 ),"<directory>","generate Java code into target directory");
750 ("Target",["--jvm"],[],Arg.String (fun dir ->
751 cp_libs := "hxjava" :: !cp_libs;
752 Common.define com Define.Jvm;
753 jvm_flag := true;
754 Initialize.set_platform com Java dir;
755 ),"<file>","generate JVM bytecode into target file");
756 ("Target",["--python"],["-python"],Arg.String (fun dir ->
757 Initialize.set_platform com Python dir;
758 ),"<file>","generate Python code into target file");
759 ("Target",["--hl"],["-hl"],Arg.String (fun file ->
760 Initialize.set_platform com Hl file;
761 ),"<file>","generate HashLink .hl bytecode or .c code into target file");
762 ("Target",[],["-x"], Arg.String (fun cl ->
763 let cpath = Path.parse_type_path cl in
764 (match com.main_class with
765 | Some c -> if cpath <> c then raise (Arg.Bad "Multiple --main classes specified")
766 | None -> com.main_class <- Some cpath);
767 classes := cpath :: !classes;
768 Common.define com Define.Interp;
769 Initialize.set_platform com (!Globals.macro_platform) "";
770 interp := true;
771 ),"<class>","interpret the program using internal macro system");
772 ("Target",["--interp"],[], Arg.Unit (fun() ->
773 Common.define com Define.Interp;
774 Initialize.set_platform com (!Globals.macro_platform) "";
775 interp := true;
776 ),"","interpret the program using internal macro system");
777 ("Target",["--run"],[], Arg.Unit (fun() ->
778 raise (Arg.Bad "--run requires an argument: a Haxe module name")
779 ), "<module> [args...]","interpret a Haxe module with command line arguments");
780 ("Compilation",["-p";"--class-path"],["-cp"],Arg.String (fun path ->
781 process_libs();
782 com.class_path <- Path.add_trailing_slash path :: com.class_path
783 ),"<path>","add a directory to find source files");
784 ("Compilation",["-m";"--main"],["-main"],Arg.String (fun cl ->
785 if com.main_class <> None then raise (Arg.Bad "Multiple --main classes specified");
786 let cpath = Path.parse_type_path cl in
787 com.main_class <- Some cpath;
788 classes := cpath :: !classes
789 ),"<class>","select startup class");
790 ("Compilation",["-L";"--library"],["-lib"],Arg.String (fun l ->
791 cp_libs := l :: !cp_libs;
792 Common.raw_define com l;
793 ),"<name[:ver]>","use a haxelib library");
794 ("Compilation",["-D";"--define"],[],Arg.String (fun var ->
795 let flag = try fst (ExtString.String.split var "=") with _ -> var in
796 let raise_reserved description =
797 raise (Arg.Bad (description ^ " and cannot be defined from the command line"))
798 in
799 if List.mem flag reserved_flags then raise_reserved (Printf.sprintf "`%s` is a reserved compiler flag" flag);
800 List.iter (fun ns ->
801 if ExtString.String.starts_with flag (ns ^ ".") then raise_reserved (Printf.sprintf "`%s` uses the reserved compiler flag namespace `%s.*`" flag ns)
802 ) reserved_flag_namespaces;
803 Common.raw_define com var;
804 ),"<var[=value]>","define a conditional compilation flag");
805 ("Debug",["-v";"--verbose"],[],Arg.Unit (fun () ->
806 com.verbose <- true
807 ),"","turn on verbose mode");
808 ("Debug",["--debug"],["-debug"], Arg.Unit (fun() ->
809 Common.define com Define.Debug;
810 com.debug <- true;
811 ),"","add debug information to the compiled code");
812 ("Miscellaneous",["--version"],["-version"],Arg.Unit (fun() ->
813 com.info (s_version true) null_pos;
814 did_something := true;
815 ),"","print version and exit");
816 ("Miscellaneous", ["-h";"--help"], ["-help"], Arg.Unit (fun () ->
817 raise (Arg.Help "")
818 ),"","show extended help information");
819 ("Miscellaneous",["--help-defines"],[], Arg.Unit (fun() ->
820 let all,max_length = Define.get_documentation_list() in
821 let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
822 List.iter (fun msg -> ctx.com.print (msg ^ "\n")) all;
823 did_something := true
824 ),"","print help for all compiler specific defines");
825 ("Miscellaneous",["--help-metas"],[], Arg.Unit (fun() ->
826 let all,max_length = Meta.get_documentation_list() in
827 let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
828 List.iter (fun msg -> ctx.com.print (msg ^ "\n")) all;
829 did_something := true
830 ),"","print help for all compiler metadatas");
831 ] in
832 let adv_args_spec = [
833 ("Optimization",["--dce"],["-dce"],Arg.String (fun mode ->
834 (match mode with
835 | "std" | "full" | "no" -> ()
836 | _ -> raise (Arg.Bad "Invalid DCE mode, expected std | full | no"));
837 Common.define_value com Define.Dce mode
838 ),"[std|full|no]","set the dead code elimination mode (default std)");
839 ("Target-specific",["--swf-version"],["-swf-version"],Arg.Float (fun v ->
840 if not !swf_version || com.flash_version < v then com.flash_version <- v;
841 swf_version := true;
842 ),"<version>","change the SWF version");
843 (* FIXME: replace with -D define *)
844 ("Target-specific",["--swf-header"],["-swf-header"],Arg.String (fun h ->
845 try
846 swf_header := Some (match ExtString.String.nsplit h ":" with
847 | [width; height; fps] ->
848 (int_of_string width,int_of_string height,float_of_string fps,0xFFFFFF)
849 | [width; height; fps; color] ->
850 let color = if ExtString.String.starts_with color "0x" then color else "0x" ^ color in
851 (int_of_string width, int_of_string height, float_of_string fps, int_of_string color)
852 | _ -> raise Exit)
853 with
854 _ -> raise (Arg.Bad "Invalid SWF header format, expected width:height:fps[:color]")
855 ),"<header>","define SWF header (width:height:fps:color)");
856 ("Target-specific",["--flash-strict"],[], define Define.FlashStrict, "","more type strict flash API");
857 ("Target-specific",["--swf-lib"],["-swf-lib"],Arg.String (fun file ->
858 process_libs(); (* linked swf order matters, and lib might reference swf as well *)
859 add_native_lib file false;
860 ),"<file>","add the SWF library to the compiled SWF");
861 (* FIXME: replace with -D define *)
862 ("Target-specific",["--swf-lib-extern"],["-swf-lib-extern"],Arg.String (fun file ->
863 add_native_lib file true;
864 ),"<file>","use the SWF library for type checking");
865 ("Target-specific",["--java-lib"],["-java-lib"],Arg.String (fun file ->
866 add_native_lib file false;
867 ),"<file>","add an external JAR or directory of JAR files");
868 ("Target-specific",["--java-lib-extern"],[],Arg.String (fun file ->
869 add_native_lib file true;
870 ),"<file>","use an external JAR or directory of JAR files for type checking");
871 ("Target-specific",["--net-lib"],["-net-lib"],Arg.String (fun file ->
872 add_native_lib file false;
873 ),"<file>[@std]","add an external .NET DLL file");
874 ("Target-specific",["--net-std"],["-net-std"],Arg.String (fun file ->
875 Dotnet.add_net_std com file
876 ),"<file>","add a root std .NET DLL search path");
877 (* FIXME: replace with -D define *)
878 ("Target-specific",["--c-arg"],["-c-arg"],Arg.String (fun arg ->
879 com.c_args <- arg :: com.c_args
880 ),"<arg>","pass option <arg> to the native Java/C# compiler");
881 ("Compilation",["-r";"--resource"],["-resource"],Arg.String (fun res ->
882 let file, name = (match ExtString.String.nsplit res "@" with
883 | [file; name] -> file, name
884 | [file] -> file, file
885 | _ -> raise (Arg.Bad "Invalid Resource format, expected file@name")
886 ) in
887 let file = (try Common.find_file com file with Not_found -> file) in
888 let data = (try
889 let s = Std.input_file ~bin:true file in
890 if String.length s > 12000000 then raise Exit;
891 s;
892 with
893 | Sys_error _ -> failwith ("Resource file not found: " ^ file)
894 | _ -> failwith ("Resource '" ^ file ^ "' excess the maximum size of 12MB")
895 ) in
896 if Hashtbl.mem com.resources name then failwith ("Duplicate resource name " ^ name);
897 Hashtbl.add com.resources name data
898 ),"<file>[@name]","add a named resource file");
899 ("Debug",["--prompt"],["-prompt"], Arg.Unit (fun() -> prompt := true),"","prompt on error");
900 ("Compilation",["--cmd"],["-cmd"], Arg.String (fun cmd ->
901 cmds := DisplayOutput.unquote cmd :: !cmds
902 ),"<command>","run the specified command after successful compilation");
903 (* FIXME: replace with -D define *)
904 ("Optimization",["--no-traces"],[], define Define.NoTraces, "","don't compile trace calls in the program");
905 ("Batch",["--next"],[], Arg.Unit (fun() -> die "" __LOC__), "","separate several haxe compilations");
906 ("Batch",["--each"],[], Arg.Unit (fun() -> die "" __LOC__), "","append preceding parameters to all Haxe compilations separated by --next");
907 ("Services",["--display"],[], Arg.String (fun input ->
908 let input = String.trim input in
909 if String.length input > 0 && (input.[0] = '[' || input.[0] = '{') then begin
910 did_something := true;
911 force_typing := true;
912 DisplayJson.parse_input com input Timer.measure_times
913 end else
914 DisplayOutput.handle_display_argument com input pre_compilation did_something;
915 ),"","display code tips");
916 ("Services",["--xml"],["-xml"],Arg.String (fun file ->
917 xml_out := Some file
918 ),"<file>","generate XML types description");
919 ("Services",["--json"],[],Arg.String (fun file ->
920 json_out := Some file
921 ),"<file>","generate JSON types description");
922 ("Optimization",["--no-output"],[], Arg.Unit (fun() -> no_output := true),"","compiles but does not generate any file");
923 ("Debug",["--times"],[], Arg.Unit (fun() -> Timer.measure_times := true),"","measure compilation times");
924 ("Optimization",["--no-inline"],[], define Define.NoInline, "","disable inlining");
925 ("Optimization",["--no-opt"],[], Arg.Unit (fun() ->
926 com.foptimize <- false;
927 Common.define com Define.NoOpt;
928 ), "","disable code optimizations");
929 ("Compilation",["--remap"],[], Arg.String (fun s ->
930 let pack, target = (try ExtString.String.split s ":" with _ -> raise (Arg.Bad "Invalid remap format, expected source:target")) in
931 com.package_rules <- PMap.add pack (Remap target) com.package_rules;
932 ),"<package:target>","remap a package to another one");
933 ("Compilation",["--macro"],[], Arg.String (fun e ->
934 force_typing := true;
935 config_macros := e :: !config_macros
936 ),"<macro>","call the given macro before typing anything else");
937 ("Compilation Server",["--server-listen"],["--wait"], Arg.String (fun hp ->
938 let accept = match hp with
939 | "stdio" ->
940 Server.init_wait_stdio()
941 | _ ->
942 let host, port = parse_host_port hp in
943 init_wait_socket host port
944 in
945 wait_loop process_params com.verbose accept
946 ),"[[host:]port]|stdio]","wait on the given port (or use standard i/o) for commands to run");
947 ("Compilation Server",["--server-connect"],[], Arg.String (fun hp ->
948 let host, port = parse_host_port hp in
949 let accept = Server.init_wait_connect host port in
950 wait_loop process_params com.verbose accept
951 ),"[host:]port]","connect to the given port and wait for commands to run");
952 ("Compilation Server",["--connect"],[],Arg.String (fun _ ->
953 die "" __LOC__
954 ),"<[host:]port>","connect on the given port and run commands there");
955 ("Compilation",["-C";"--cwd"],[], Arg.String (fun dir ->
956 (* This is handled by process_params, but passed through so we know we did something. *)
957 did_something := true;
958 ),"<directory>","set current working directory");
959 ("Compilation",["--haxelib-global"],[], Arg.Unit (fun () -> ()),"","pass --global argument to haxelib");
960 ] in
961 let args_callback cl =
962 begin try
963 let path,name = Path.parse_path cl in
964 if StringHelper.starts_uppercase_identifier name then
965 classes := (path,name) :: !classes
966 else begin
967 force_typing := true;
968 config_macros := (Printf.sprintf "include('%s', true, null, null, true)" cl) :: !config_macros;
969 end
970 with Failure _ when ctx.com.display.dms_display ->
971 ()
972 end
973 in
974 let all_args = (basic_args_spec @ adv_args_spec) in
975 let all_args_spec = process_args all_args in
976 let process args =
977 let current = ref 0 in
978 (try
979 let rec loop acc args = match args with
980 | "--display" :: arg :: args ->
981 loop (arg :: "--display" :: acc) args
982 | arg :: args ->
983 loop (expand_env arg :: acc) args
984 | [] ->
985 List.rev acc
986 in
987 let args = loop [] args in
988 Arg.parse_argv ~current (Array.of_list ("" :: args)) all_args_spec args_callback "";
989 with
990 | Arg.Help _ ->
991 raise (HelpMessage (usage_string all_args usage))
992 | Arg.Bad msg ->
993 let first_line = List.nth (Str.split (Str.regexp "\n") msg) 0 in
994 let new_msg = (Printf.sprintf "%s" first_line) in
995 let r = Str.regexp "unknown option [`']?\\([-A-Za-z]+\\)[`']?" in
996 try
997 ignore(Str.search_forward r msg 0);
998 let s = Str.matched_group 1 msg in
999 let sl = List.map (fun (s,_,_) -> s) all_args_spec in
1000 let sl = StringError.get_similar s sl in
1001 begin match sl with
1002 | [] -> raise Not_found
1003 | _ ->
1004 let spec = List.filter (fun (_,sl',sl'',_,_,_) ->
1005 List.exists (fun s -> List.mem s sl) (sl' @ sl'')
1006 ) all_args in
1007 let new_msg = (Printf.sprintf "%s\nDid you mean:\n%s" first_line (usage_string ~print_cat:false spec "")) in
1008 raise (Arg.Bad new_msg)
1009 end;
1010 with Not_found ->
1011 raise (Arg.Bad new_msg));
1012 if com.platform = Globals.Cpp && not (Define.defined com.defines DisableUnicodeStrings) && not (Define.defined com.defines HxcppSmartStings) then begin
1013 Define.define com.defines HxcppSmartStings;
1014 end;
1015 if Define.raw_defined com.defines "gen_hx_classes" then begin
1016 (* TODO: this is something we're gonna remove once we have something nicer for generating flash externs *)
1017 force_typing := true;
1018 pre_compilation := (fun() ->
1019 let process_lib lib =
1020 if not (lib#has_flag NativeLibraries.FlagIsStd) then
1021 List.iter (fun path -> if path <> (["java";"lang"],"String") then classes := path :: !classes) lib#list_modules
1022 in
1023 List.iter process_lib com.native_libs.net_libs;
1024 List.iter process_lib com.native_libs.swf_libs;
1025 List.iter process_lib com.native_libs.java_libs;
1026 ) :: !pre_compilation;
1027 xml_out := Some "hx"
1028 end;
1029 in
1030 process_ref := process;
1031 (* Handle CLI arguments *)
1032 process ctx.com.args;
1033 (* Process haxelibs *)
1034 process_libs();
1035 (* Set up display configuration *)
1036 process_display_configuration ctx;
1037 let display_file_dot_path = DisplayOutput.process_display_file com classes in
1038 (* Initialize target: This allows access to the appropriate std packages and sets the -D defines. *)
1039 let ext = Initialize.initialize_target ctx com classes in
1040 (* if we are at the last compilation step, allow all packages accesses - in case of macros or opening another project file *)
1041 if com.display.dms_display then begin match com.display.dms_kind with
1042 | DMDefault | DMUsage _ -> ()
1043 | _ -> 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;
1044 end;
1045 com.config <- get_config com; (* make sure to adapt all flags changes defined after platform *)
1046 let t = Timer.timer ["init"] in
1047 List.iter (fun f -> f()) (List.rev (!pre_compilation));
1048 t();
1049 com.stage <- CInitialized;
1050 if !classes = [([],"Std")] && not !force_typing then begin
1051 if !cmds = [] && not !did_something then raise (HelpMessage (usage_string basic_args_spec usage));
1052 end else begin
1053 (* Actual compilation starts here *)
1054 let tctx = create_typer_context ctx !native_libs in
1055 com.stage <- CTyperCreated;
1056 let display_file_dot_path = match display_file_dot_path with
1057 | DPKMacro path ->
1058 ignore(load_display_module_in_macro tctx (Some path) true);
1059 Some path
1060 | DPKNormal path ->
1061 Some path
1062 | DPKNone ->
1063 None
1064 | DPKDirect file ->
1065 DisplayOutput.load_display_file_standalone tctx file;
1066 None
1067 | DPKInput input ->
1068 DisplayOutput.load_display_content_standalone tctx input;
1069 None
1070 in
1071 begin try
1072 do_type tctx !config_macros !classes;
1073 with TypeloadParse.DisplayInMacroBlock ->
1074 ignore(load_display_module_in_macro tctx display_file_dot_path true);
1075 end;
1076 handle_display ctx tctx display_file_dot_path;
1077 filter ctx tctx display_file_dot_path;
1078 if ctx.has_error then raise Abort;
1079 check_auxiliary_output com !xml_out !json_out;
1080 com.stage <- CGenerationStart;
1081 if not !no_output then generate tctx ext !interp !jvm_flag !swf_header;
1082 com.stage <- CGenerationDone;
1083 end;
1084 Sys.catch_break false;
1085 List.iter (fun f -> f()) (List.rev com.callbacks#get_after_generation);
1086 if not !no_output then begin
1087 List.iter (fun c ->
1088 let r = run_command ctx c in
1089 if r <> 0 then failwith ("Command failed with error " ^ string_of_int r)
1090 ) (List.rev !cmds)
1091 end
1092 with
1093 | Abort ->
1094 ()
1095 | Error.Fatal_error (m,p) ->
1096 error ctx m p
1097 | Common.Abort (m,p) ->
1098 error ctx m p
1099 | Lexer.Error (m,p) ->
1100 error ctx (Lexer.error_msg m) p
1101 | Parser.Error (m,p) ->
1102 error ctx (Parser.error_msg m) p
1103 | Typecore.Forbid_package ((pack,m,p),pl,pf) ->
1104 if !Parser.display_mode <> DMNone && ctx.has_next then begin
1105 ctx.has_error <- false;
1106 ctx.messages <- [];
1107 end else begin
1108 error ctx (Printf.sprintf "You cannot access the %s package while %s (for %s)" pack (if pf = "macro" then "in a macro" else "targeting " ^ pf) (s_type_path m) ) p;
1109 List.iter (error ctx (Error.compl_msg "referenced here")) (List.rev pl);
1110 end
1111 | Error.Error (m,p) ->
1112 error ctx (Error.error_msg m) p
1113 | Generic.Generic_Exception(m,p) ->
1114 error ctx m p
1115 | Arg.Bad msg ->
1116 error ctx ("Error: " ^ msg) null_pos
1117 | Failure msg when not is_debug_run ->
1118 error ctx ("Error: " ^ msg) null_pos
1119 | HelpMessage msg ->
1120 com.info msg null_pos
1121 | DisplayException(DisplayHover _ | DisplayPositions _ | DisplayFields _ | DisplayPackage _ | DisplaySignatures _ as de) when ctx.com.json_out <> None ->
1122 begin
1123 DisplayPosition.display_position#reset;
1124 match ctx.com.json_out with
1125 | Some api ->
1126 let ctx = DisplayJson.create_json_context api.jsonrpc (match de with DisplayFields _ -> true | _ -> false) in
1127 api.send_result (DisplayException.to_json ctx de)
1128 | _ -> die "" __LOC__
1129 end
1130 (* | Parser.TypePath (_,_,_,p) when ctx.com.json_out <> None ->
1131 begin match com.json_out with
1132 | Some (f,_) ->
1133 let tctx = Typer.create ctx.com in
1134 let fields = DisplayToplevel.collect tctx true Typecore.NoValue in
1135 let jctx = Genjson.create_context Genjson.GMMinimum in
1136 f (DisplayException.fields_to_json jctx fields CRImport (Some (Parser.cut_pos_at_display p)) false)
1137 | _ -> die "" __LOC__
1138 end *)
1139 | DisplayException(DisplayPackage pack) ->
1140 DisplayPosition.display_position#reset;
1141 raise (DisplayOutput.Completion (String.concat "." pack))
1142 | DisplayException(DisplayFields Some r) ->
1143 DisplayPosition.display_position#reset;
1144 let fields = if !Timer.measure_times then begin
1145 Timer.close_times();
1146 (List.map (fun (name,value) ->
1147 CompletionItem.make_ci_timer ("@TIME " ^ name) value
1148 ) (DisplayOutput.get_timer_fields !start_time)) @ r.fitems
1149 end else
1150 r.fitems
1151 in
1152 let s = match r.fkind with
1153 | CRToplevel _
1154 | CRTypeHint
1155 | CRExtends
1156 | CRImplements
1157 | CRStructExtension _
1158 | CRImport
1159 | CRUsing
1160 | CRNew
1161 | CRPattern _
1162 | CRTypeRelation
1163 | CRTypeDecl ->
1164 DisplayOutput.print_toplevel fields
1165 | CRField _
1166 | CRStructureField
1167 | CRMetadata
1168 | CROverride ->
1169 DisplayOutput.print_fields fields
1170 in
1171 raise (DisplayOutput.Completion s)
1172 | DisplayException(DisplayHover Some ({hitem = {CompletionItem.ci_type = Some (t,_)}} as hover)) ->
1173 DisplayPosition.display_position#reset;
1174 let doc = CompletionItem.get_documentation hover.hitem in
1175 raise (DisplayOutput.Completion (DisplayOutput.print_type t hover.hpos doc))
1176 | DisplayException(DisplaySignatures Some (signatures,_,display_arg,_)) ->
1177 DisplayPosition.display_position#reset;
1178 if ctx.com.display.dms_kind = DMSignature then
1179 raise (DisplayOutput.Completion (DisplayOutput.print_signature signatures display_arg))
1180 else
1181 raise (DisplayOutput.Completion (DisplayOutput.print_signatures signatures))
1182 | DisplayException(DisplayPositions pl) ->
1183 DisplayPosition.display_position#reset;
1184 raise (DisplayOutput.Completion (DisplayOutput.print_positions pl))
1185 | Parser.TypePath (p,c,is_import,pos) ->
1186 let fields =
1187 try begin match c with
1188 | None ->
1189 DisplayPath.TypePathHandler.complete_type_path com p
1190 | Some (c,cur_package) ->
1191 let ctx = Typer.create com in
1192 DisplayPath.TypePathHandler.complete_type_path_inner ctx p c cur_package is_import
1193 end with Common.Abort(msg,p) ->
1194 error ctx msg p;
1195 None
1196 in
1197 begin match ctx.com.json_out,fields with
1198 | None,None ->
1199 ()
1200 | None,Some fields ->
1201 raise (DisplayOutput.Completion (DisplayOutput.print_fields fields))
1202 | Some api,None when is_legacy_completion com ->
1203 api.send_result JNull
1204 | Some api,fields ->
1205 let fields = Option.default [] fields in
1206 let ctx = DisplayJson.create_json_context api.jsonrpc false in
1207 let path = match List.rev p with
1208 | name :: pack -> List.rev pack,name
1209 | [] -> [],""
1210 in
1211 let kind = CRField ((CompletionItem.make_ci_module path,pos,None,None)) in
1212 api.send_result (DisplayException.fields_to_json ctx fields kind (DisplayTypes.make_subject None pos));
1213 end
1214 | Parser.SyntaxCompletion(kind,subj) ->
1215 DisplayOutput.handle_syntax_completion com kind subj;
1216 error ctx ("Error: No completion point was found") null_pos
1217 | DisplayException(DisplayDiagnostics dctx) ->
1218 let s = Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics dctx) in
1219 DisplayPosition.display_position#reset;
1220 raise (DisplayOutput.Completion s)
1221 | DisplayException(ModuleSymbols s | Statistics s | Metadata s) ->
1222 DisplayPosition.display_position#reset;
1223 raise (DisplayOutput.Completion s)
1224 | EvalExceptions.Sys_exit i | Hlinterp.Sys_exit i ->
1225 ctx.flush();
1226 if !Timer.measure_times then Timer.report_times prerr_endline;
1227 exit i
1228 | DisplayOutput.Completion _ as exc ->
1229 raise exc
1230 | Out_of_memory as exc ->
1231 raise exc
1232 | e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" || CompilationServer.runs() with _ -> true) && not is_debug_run ->
1233 error ctx (Printexc.to_string e) null_pos
1234
1235 ;;
1236 let other = Timer.timer ["other"] in
45 let other = Timer.timer ["other"];;
123746 Sys.catch_break true;
1238 MacroContext.setup();
123947
124048 let args = List.tl (Array.to_list Sys.argv) in
1241 (try
1242 let server = Sys.getenv "HAXE_COMPILATION_SERVER" in
1243 let host, port = (try ExtString.String.split server ":" with _ -> "127.0.0.1", server) in
1244 do_connect host (try int_of_string port with _ -> failwith "Invalid HAXE_COMPILATION_SERVER port") args
1245 with Not_found -> try
1246 process_params create_context args
1247 with DisplayOutput.Completion c ->
1248 prerr_endline c;
1249 exit 0
1250 | Arg.Bad msg ->
1251 prerr_endline ("Error: " ^ msg);
1252 exit 1
1253 );
1254 other();
1255 if !Timer.measure_times then Timer.report_times prerr_endline
49 set_binary_mode_out stdout true;
50 set_binary_mode_out stderr true;
51 let sctx = ServerCompilationContext.create false in
52 Server.process sctx (Communication.create_stdio ()) args;
53 other()
0 exception HelpMessage of string
1
2 let is_debug_run = try Sys.getenv "HAXEDEBUG" = "1" with _ -> false
3
4 let start_time = ref (Timer.get_time())
5
6 let prompt = ref false
7
8 let expand_env ?(h=None) path =
9 let r = Str.regexp "%\\([A-Za-z0-9_]+\\)%" in
10 Str.global_substitute r (fun s ->
11 let key = Str.matched_group 1 s in
12 try
13 Sys.getenv key
14 with Not_found -> try
15 match h with
16 | None -> raise Not_found
17 | Some h -> Hashtbl.find h key
18 with Not_found ->
19 "%" ^ key ^ "%"
20 ) path
21
22 let unquote v =
23 let len = String.length v in
24 if len > 0 then
25 match v.[0], v.[len - 1] with
26 | '"', '"'
27 | '\'', '\'' -> String.sub v 1 (len - 2)
28 | _ -> v
29 else v
30
31 let parse_hxml_data data =
32 let lines = Str.split (Str.regexp "[\r\n]+") data in
33 List.concat (List.map (fun l ->
34 let l = unquote (ExtString.String.strip l) in
35 if l = "" || l.[0] = '#' then
36 []
37 else if l.[0] = '-' then
38 try
39 let a, b = ExtString.String.split l " " in
40 [unquote a; unquote (ExtString.String.strip b)]
41 with
42 _ -> [l]
43 else
44 [l]
45 ) lines)
46
47 let parse_hxml file =
48 let ch = IO.input_channel (try open_in_bin file with _ -> raise Not_found) in
49 let data = IO.read_all ch in
50 IO.close_in ch;
51 parse_hxml_data data
52
53 let parse_host_port hp =
54 let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in
55 let port = try int_of_string port with _ -> raise (Arg.Bad "Invalid port") in
56 host, port
0 open Unix
1
2 (* path helpers *)
3 let as_exe name =
4 if Sys.unix then name else name ^ ".exe"
5
6 let find_program name =
7 let name = as_exe name in
8 let pathKey = try Sys.getenv "Path" with Not_found -> "PATH" in
9 let path = try Sys.getenv pathKey with Not_found -> "" in
10 let pathComponents = Str.split (Str.regexp (if Sys.unix then ":" else ";")) path in
11 let sep = if Sys.unix then "/" else "\\" in
12 if Sys.file_exists (Sys.getcwd() ^ sep ^ name) then
13 Sys.getcwd() ^ sep ^ name
14 else
15 let indir = List.find (fun dir -> Sys.file_exists (dir ^ sep ^ name)) pathComponents in
16 indir ^ sep ^ name
17 (* end path helpers *)
18
19 (*
20 ocaml<4.08/4.12 compat
21 https://github.com/ocaml/ocaml/blob/4.08/otherlibs/unix/unix.ml
22 open_process_args_in
23 open_process_args_out
24 open_process_args
25 open_process_args_full
26 The _pid part of the function names, as well as the pid argument,
27 are not needed in the real Unix functions present in 4.08
28 If ocaml >=4.08 but <4.12 is used, the path lookup should still be
29 performed, as this isn't performed by the ocaml function until 4.12.
30 *)
31 let open_process_args_in_pid prog args =
32 let prog = try find_program prog with Not_found -> prog in
33 let (in_read, in_write) = pipe ~cloexec:true () in
34 let inchan = in_channel_of_descr in_read in
35 let pid =
36 begin
37 try
38 create_process prog args stdin in_write stderr
39 with e ->
40 close_in inchan;
41 close in_write;
42 raise e
43 end in
44 close in_write;
45 (inchan, pid)
46
47 let open_process_args_out_pid prog args =
48 let prog = try find_program prog with Not_found -> prog in
49 let (out_read, out_write) = pipe ~cloexec:true () in
50 let outchan = out_channel_of_descr out_write in
51 let pid =
52 begin
53 try
54 create_process prog args out_read stdout stderr
55 with e ->
56 close_out outchan;
57 close out_read;
58 raise e
59 end in
60 close out_read;
61 (outchan, pid)
62
63 let open_process_args_pid prog args =
64 let prog = try find_program prog with Not_found -> prog in
65 let (in_read, in_write) = pipe ~cloexec:true () in
66 let (out_read, out_write) =
67 try pipe ~cloexec:true ()
68 with e ->
69 close in_read; close in_write;
70 raise e in
71 let inchan = in_channel_of_descr in_read in
72 let outchan = out_channel_of_descr out_write in
73 let pid =
74 begin
75 try
76 create_process prog args out_read in_write stderr
77 with e ->
78 close out_read; close out_write;
79 close in_read; close in_write;
80 raise e
81 end in
82 close out_read;
83 close in_write;
84 (inchan, outchan, pid)
85
86 let open_process_args_full_pid prog args env =
87 let prog = try find_program prog with Not_found -> prog in
88 let (in_read, in_write) = pipe ~cloexec:true () in
89 let (out_read, out_write) =
90 try pipe ~cloexec:true ()
91 with e ->
92 close in_read; close in_write;
93 raise e in
94 let (err_read, err_write) =
95 try pipe ~cloexec:true ()
96 with e ->
97 close in_read; close in_write;
98 close out_read; close out_write;
99 raise e in
100 let inchan = in_channel_of_descr in_read in
101 let outchan = out_channel_of_descr out_write in
102 let errchan = in_channel_of_descr err_read in
103 let pid =
104 begin
105 try
106 create_process_env prog args env out_read in_write err_write
107 with e ->
108 close out_read; close out_write;
109 close in_read; close in_write;
110 close err_read; close err_write;
111 raise e
112 end in
113 close out_read;
114 close in_write;
115 close err_write;
116 (inchan, outchan, errchan, pid)
117
118 let rec waitpid_non_intr pid =
119 try waitpid [] pid
120 with Unix_error (EINTR, _, _) -> waitpid_non_intr pid
121
122 let close_process_in_pid (inchan, pid) =
123 close_in inchan;
124 snd(waitpid_non_intr pid)
125
126 let close_process_out_pid (outchan, pid) =
127 (* The application may have closed [outchan] already to signal
128 end-of-input to the process. *)
129 begin try close_out outchan with Sys_error _ -> () end;
130 snd(waitpid_non_intr pid)
131
132 let close_process_pid (inchan, outchan, pid) =
133 close_in inchan;
134 begin try close_out outchan with Sys_error _ -> () end;
135 snd(waitpid_non_intr pid)
136
137 let close_process_full_pid (inchan, outchan, errchan, pid) =
138 close_in inchan;
139 begin try close_out outchan with Sys_error _ -> () end;
140 close_in errchan;
141 snd(waitpid_non_intr pid)
142 (* end ocaml<4.08/4.12 compat *)
143
144 let command cmd args =
145 let args = Array.of_list (cmd::args) in
146 let pin, pout, pid = open_process_args_pid cmd args in
147 let ret = close_process_pid (pin,pout,pid) in
148 match ret with
149 | Unix.WEXITED code -> code
150 | _ -> 255
0 open Globals
1 open Ast
2 open Typecore
3 open Type
4 open TypeloadModule
5 open TypeloadFields
6
7 exception Fail of string
8
9 type retyping_context = {
10 typer : typer;
11 print_stack : string list;
12 }
13
14 let fail rctx s =
15 let stack = String.concat " " (List.rev rctx.print_stack) in
16 raise (Fail (Printf.sprintf "%s: %s" stack s))
17
18 let disable_typeloading rctx ctx f =
19 let old = ctx.g.load_only_cached_modules in
20 ctx.g.load_only_cached_modules <- true;
21 try
22 Std.finally (fun () -> ctx.g.load_only_cached_modules <- old) f ()
23 with (Error.Error (Module_not_found path,_,_)) ->
24 fail rctx (Printf.sprintf "Could not load [Module %s]" (s_type_path path))
25
26 let pair_type th t = match th with
27 | None ->
28 TExprToExpr.convert_type t,null_pos
29 | Some t ->
30 t
31
32 let pair_class_field rctx ctx cctx fctx cf cff p =
33 match cff.cff_kind with
34 | FFun fd ->
35 let targs,tret = match follow cf.cf_type with
36 | TFun(args,ret) ->
37 args,ret
38 | _ ->
39 fail rctx "Type change"
40 in
41 let args = try
42 List.map2 (fun (name,opt,meta,th,eo) (_,_,t) ->
43 (name,opt,meta,Some (pair_type th t),eo)
44 ) fd.f_args targs
45 with Invalid_argument _ ->
46 fail rctx "Type change"
47 in
48 let ret = pair_type fd.f_type tret in
49 let fd = {
50 fd with
51 f_args = args;
52 f_type = Some ret
53 } in
54 let load_args_ret () =
55 setup_args_ret ctx cctx fctx (fst cff.cff_name) fd p
56 in
57 let args,ret = disable_typeloading rctx ctx load_args_ret in
58 let t = TFun(args#for_type,ret) in
59 (fun () ->
60 (* This is the only part that should actually modify anything. *)
61 cf.cf_type <- t;
62 TypeBinding.bind_method ctx cctx fctx cf t args ret fd.f_expr (match fd.f_expr with Some e -> snd e | None -> cff.cff_pos);
63 if ctx.com.display.dms_full_typing then
64 remove_class_field_flag cf CfPostProcessed;
65 )
66 | FVar(th,eo) | FProp(_,_,th,eo) ->
67 let th = Some (pair_type th cf.cf_type) in
68 let t = disable_typeloading rctx ctx (fun () -> load_variable_type_hint ctx fctx eo (pos cff.cff_name) th) in
69 (fun () ->
70 cf.cf_type <- t;
71 TypeBinding.bind_var ctx cctx fctx cf eo;
72 if ctx.com.display.dms_full_typing then
73 remove_class_field_flag cf CfPostProcessed;
74 )
75
76 let pair_classes rctx context_init c d p =
77 let rctx = {rctx with
78 print_stack = (Printf.sprintf "[Class %s]" (s_type_path c.cl_path)) :: rctx.print_stack
79 } in
80 c.cl_restore();
81 (* TODO: What do we do with build macros? *)
82 let cctx = create_class_context c context_init p in
83 let ctx = create_typer_context_for_class rctx.typer cctx p in
84 let _ =
85 let rctx = {rctx with
86 print_stack = (Printf.sprintf "[Relations]") :: rctx.print_stack
87 } in
88 let has_extends = ref false in
89 let implements = ref c.cl_implements in
90 List.iter (function
91 | HExtends(path,p) ->
92 has_extends := true;
93 begin match c.cl_super with
94 | None ->
95 fail rctx (Printf.sprintf "parent %s appeared" (Ast.Printer.s_complex_type_path "" (path,p)))
96 | Some(c,tl) ->
97 let th = pair_type (Some(CTPath path,p)) (TInst(c,tl)) in
98 ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false th))
99 end
100 | HImplements(path,p) ->
101 begin match !implements with
102 | (c,tl) :: rest ->
103 (* TODO: I think this should somehow check if it's actually the same interface. There could be cases
104 where the order changes or something like that... Maybe we can compare the loaded type.
105 However, this doesn't matter until we start retyping invalidated modules.
106 *)
107 implements := rest;
108 let th = pair_type (Some(CTPath path,p)) (TInst(c,tl)) in
109 ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false th));
110 | [] ->
111 fail rctx (Printf.sprintf "interface %s appeared" (Ast.Printer.s_complex_type_path "" (path,p)))
112 end
113 | _ ->
114 ()
115 ) d.d_flags;
116 (* TODO: There are probably cases where the compiler generates a cl_super even though it's not in syntax *)
117 if not !has_extends then begin match c.cl_super with
118 | None -> ()
119 | Some(c,_) -> fail rctx (Printf.sprintf "parent %s disappeared" (s_type_path c.cl_path))
120 end;
121 begin match !implements with
122 | (c,_) :: _ -> fail rctx (Printf.sprintf "interface %s disappeared" (s_type_path c.cl_path))
123 | [] -> ()
124 end
125 in
126 let fl = List.map (fun cff ->
127 let name = fst cff.cff_name in
128 let rctx = {rctx with
129 print_stack = (Printf.sprintf "[Field %s]" name) :: rctx.print_stack
130 } in
131 let display_modifier = Typeload.check_field_access ctx cff in
132 let fctx = create_field_context cctx cff ctx.is_display_file display_modifier in
133 let cf = match fctx.field_kind with
134 | FKConstructor ->
135 begin match c.cl_constructor with
136 | None ->
137 fail rctx "Constructor not found"
138 | Some cf ->
139 cf
140 end
141 | FKNormal ->
142 begin try
143 PMap.find name (if fctx.is_static then c.cl_statics else c.cl_fields)
144 with Not_found ->
145 fail rctx "Field not found"
146 end
147 | FKInit ->
148 fail rctx "TODO"
149 in
150 pair_class_field rctx ctx cctx fctx cf cff p
151 ) d.d_data in
152 fl @ [fun () -> TypeloadFields.finalize_class ctx cctx]
153
154 let pair_enums ctx rctx en d =
155 let ctx = { ctx with type_params = en.e_params } in
156 let rctx = {rctx with
157 print_stack = (Printf.sprintf "[Enum %s]" (s_type_path en.e_path)) :: rctx.print_stack
158 } in
159 List.iter (fun eff ->
160 let name = fst eff.ec_name in
161 let rctx = {rctx with
162 print_stack = (Printf.sprintf "[Field %s]" name) :: rctx.print_stack
163 } in
164 let ef = try
165 PMap.find name en.e_constrs
166 with Not_found ->
167 fail rctx "Field not found"
168 in
169 let th = pair_type eff.ec_type ef.ef_type in
170 ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false th))
171 ) d.d_data;
172 []
173
174 let pair_typedefs ctx rctx td d =
175 let rctx = {rctx with
176 print_stack = (Printf.sprintf "[Typedef %s]" (s_type_path td.t_path)) :: rctx.print_stack
177 } in
178 let ctx = { ctx with type_params = td.t_params } in
179 ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false d.d_data));
180 []
181
182 let pair_abstracts ctx rctx context_init a d p =
183 let rctx = {rctx with
184 print_stack = (Printf.sprintf "[Abstract %s]" (s_type_path a.a_path)) :: rctx.print_stack
185 } in
186 match a.a_impl with
187 | Some c ->
188 c.cl_restore();
189 let cctx = create_class_context c context_init p in
190 let ctx = create_typer_context_for_class rctx.typer cctx p in
191 let fl = List.map (fun cff ->
192 let cff = TypeloadFields.transform_abstract_field2 ctx a cff in
193 let name = fst cff.cff_name in
194 let rctx = {rctx with
195 print_stack = (Printf.sprintf "[Field %s]" name) :: rctx.print_stack
196 } in
197 let display_modifier = Typeload.check_field_access ctx cff in
198 let fctx = create_field_context cctx cff ctx.is_display_file display_modifier in
199 let cf = try
200 PMap.find name c.cl_statics
201 with Not_found ->
202 fail rctx "Field not found"
203 in
204 pair_class_field rctx ctx cctx fctx cf cff p
205 ) d.d_data in
206 fl @ [fun () -> TypeloadFields.finalize_class ctx cctx]
207 | None ->
208 (* ?*)
209 []
210
211 let attempt_retyping ctx m p =
212 let com = ctx.com in
213 let file,_,_,decls = TypeloadParse.parse_module' com m.m_path p in
214 let ctx = create_typer_context_for_module ctx m in
215 let rctx = {
216 typer = ctx;
217 print_stack = [Printf.sprintf "[Module %s]" (s_type_path m.m_path)];
218 } in
219 (* log rctx 0 (Printf.sprintf "Retyping module %s" (s_type_path m.m_path)); *)
220 let context_init = new TypeloadFields.context_init in
221 let find_type name = try
222 List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types
223 with Not_found ->
224 fail rctx (Printf.sprintf "Type %s not found" name)
225 in
226 let rec loop acc decls = match decls with
227 | [] ->
228 List.rev acc
229 | (d,p) :: decls ->
230 begin match d with
231 | EImport (path,mode) ->
232 ImportHandling.init_import ctx context_init path mode p;
233 ImportHandling.commit_import ctx path mode p;
234 loop acc decls
235 | EUsing path ->
236 ImportHandling.init_using ctx context_init path p;
237 loop acc decls
238 | EClass c ->
239 let mt = find_type (fst c.d_name) in
240 loop ((d,mt) :: acc) decls
241 | EEnum en ->
242 let mt = find_type (fst en.d_name) in
243 loop ((d,mt) :: acc) decls
244 | ETypedef td ->
245 let mt = find_type (fst td.d_name) in
246 loop ((d,mt) :: acc) decls
247 | EAbstract a ->
248 let mt = find_type (fst a.d_name) in
249 loop ((d,mt) :: acc) decls
250 | _ ->
251 loop acc decls
252 end;
253 in
254 try
255 m.m_extra.m_cache_state <- MSUnknown;
256 let pairs = loop [] decls in
257 let fl = List.map (fun (d,mt) -> match d,mt with
258 | EClass d,TClassDecl c ->
259 pair_classes rctx context_init c d p
260 | EEnum d,TEnumDecl en ->
261 pair_enums ctx rctx en d
262 | ETypedef d,TTypeDecl td ->
263 pair_typedefs ctx rctx td d
264 | EAbstract d,TAbstractDecl a ->
265 pair_abstracts ctx rctx context_init a d p
266 | _ ->
267 fail rctx "?"
268 ) pairs in
269 (* If we get here we know that the everything is ok. *)
270 delay ctx PConnectField (fun () -> context_init#run);
271 List.iter (fun fl ->
272 List.iter (fun f -> f()) fl
273 ) fl;
274 m.m_extra.m_cache_state <- MSGood;
275 m.m_extra.m_time <- Common.file_time file;
276 None
277 with Fail s ->
278 Some s
0 open Extlib_leftovers
01 open Printf
12 open Globals
23 open Ast
34 open Common
4 open CompilationServer
5 open DisplayTypes.DisplayMode
5 open CompilationCache
66 open Timer
77 open Type
8 open DisplayOutput
8 open DisplayProcessingGlobals
99 open Json
10
11 exception Dirty of path
10 open Compiler
11 open CompilationContext
12
13 exception Dirty of module_skip_reason
1214 exception ServerError of string
1315
14 let prompt = ref false
15 let start_time = ref (Timer.get_time())
16
17 let is_debug_run = try Sys.getenv "HAXEDEBUG" = "1" with _ -> false
18
19 type context = {
20 com : Common.context;
21 mutable flush : unit -> unit;
22 mutable setup : unit -> unit;
23 mutable messages : compiler_message list;
24 mutable has_next : bool;
25 mutable has_error : bool;
26 }
16 let has_error ctx =
17 ctx.has_error || ctx.com.Common.has_error
2718
2819 let check_display_flush ctx f_otherwise = match ctx.com.json_out with
2920 | None ->
30 begin match ctx.com.display.dms_kind with
31 | DMDiagnostics _->
32 List.iter (fun msg ->
33 let msg,p,kind = match msg with
34 | CMInfo(msg,p) -> msg,p,DisplayTypes.DiagnosticsSeverity.Information
35 | CMWarning(msg,p) -> msg,p,DisplayTypes.DiagnosticsSeverity.Warning
36 | CMError(msg,p) -> msg,p,DisplayTypes.DiagnosticsSeverity.Error
37 in
38 add_diagnostics_message ctx.com msg p DisplayTypes.DiagnosticsKind.DKCompilerError kind
21 if is_diagnostics ctx.com then begin
22 List.iter (fun cm ->
23 add_diagnostics_message ~depth:cm.cm_depth ctx.com (located cm.cm_message cm.cm_pos) cm.cm_kind cm.cm_severity
3924 ) (List.rev ctx.messages);
4025 raise (Completion (Diagnostics.print ctx.com))
41 | _ ->
26 end else
4227 f_otherwise ()
43 end
4428 | Some api ->
45 if ctx.has_error then begin
46 let errors = List.map (fun msg ->
47 let msg,p,i = match msg with
48 | CMInfo(msg,p) -> msg,p,3
49 | CMWarning(msg,p) -> msg,p,2
50 | CMError(msg,p) -> msg,p,1
51 in
29 if has_error ctx then begin
30 let errors = List.map (fun cm ->
5231 JObject [
53 "severity",JInt i;
54 "location",Genjson.generate_pos_as_location p;
55 "message",JString msg;
32 "severity",JInt (MessageSeverity.to_int cm.cm_severity);
33 "location",Genjson.generate_pos_as_location cm.cm_pos;
34 "message",JString cm.cm_message;
5635 ]
5736 ) (List.rev ctx.messages) in
5837 api.send_error errors
5938 end
6039
61 let default_flush ctx =
62 check_display_flush ctx (fun () ->
63 List.iter
64 (fun msg -> match msg with
65 | CMInfo _ -> print_endline (compiler_message_string msg)
66 | CMWarning _ | CMError _ -> prerr_endline (compiler_message_string msg)
67 )
68 (List.rev ctx.messages);
69 if ctx.has_error && !prompt then begin
70 print_endline "Press enter to exit...";
71 ignore(read_line());
72 end;
73 if ctx.has_error then exit 1
74 )
75
76 let create_context params =
77 let ctx = {
78 com = Common.create version (s_version true) params;
79 flush = (fun()->());
80 setup = (fun()->());
81 messages = [];
82 has_next = false;
83 has_error = false;
84 } in
85 ctx.flush <- (fun() -> default_flush ctx);
86 ctx
87
88 let parse_hxml_data data =
89 let lines = Str.split (Str.regexp "[\r\n]+") data in
90 List.concat (List.map (fun l ->
91 let l = unquote (ExtString.String.strip l) in
92 if l = "" || l.[0] = '#' then
93 []
94 else if l.[0] = '-' then
95 try
96 let a, b = ExtString.String.split l " " in
97 [unquote a; unquote (ExtString.String.strip b)]
98 with
99 _ -> [l]
100 else
101 [l]
102 ) lines)
103
104 let parse_hxml file =
105 let ch = IO.input_channel (try open_in_bin file with _ -> raise Not_found) in
106 let data = IO.read_all ch in
107 IO.close_in ch;
108 parse_hxml_data data
109
110 let ssend sock str =
111 let rec loop pos len =
112 if len = 0 then
113 ()
114 else
115 let s = Unix.send sock str pos len [] in
116 loop (pos + s) (len - s)
117 in
118 loop 0 (Bytes.length str)
119
12040 let current_stdin = ref None
12141
12242 let parse_file cs com file p =
123 let cc = CommonCache.get_cache cs com in
43 let cc = CommonCache.get_cache com in
12444 let ffile = Path.get_full_path file
12545 and fkey = com.file_keys#get file in
12646 let is_display_file = DisplayPosition.display_position#is_in_file (com.file_keys#get ffile) in
15070 end else begin try
15171 (* We assume that when not in display mode it's okay to cache stuff that has #if display
15272 checks. The reasoning is that non-display mode has more information than display mode. *)
153 if not com.display.dms_display then raise Not_found;
73 if com.display.dms_full_typing then raise Not_found;
15474 let ident = Hashtbl.find Parser.special_identifier_files fkey in
15575 Printf.sprintf "not cached, using \"%s\" define" ident,true
15676 with Not_found ->
16383 ) () in
16484 data
16585
166 module ServerCompilationContext = struct
167 type t = {
168 (* If true, prints some debug information *)
169 verbose : bool;
170 (* The list of changed directories per-signature *)
171 changed_directories : (Digest.t,cached_directory list) Hashtbl.t;
172 (* A reference to the compilation server instance *)
173 cs : CompilationServer.t;
174 (* A list of class paths per-signature *)
175 class_paths : (Digest.t,string list) Hashtbl.t;
176 (* Increased for each typed module *)
177 mutable mark_loop : int;
178 (* Increased for each compilation *)
179 mutable compilation_step : int;
180 (* The [mark_loop] value at which we started the current compilation *)
181 mutable compilation_mark : int;
182 (* A list of delays which are run after compilation *)
183 mutable delays : (unit -> unit) list;
184 (* True if it's an actual compilation, false if it's a display operation *)
185 mutable was_compilation : bool;
86 open ServerCompilationContext
87
88 module Communication = struct
89 type error_context = {
90 mutable last_positions : pos IntMap.t;
91 mutable max_lines : int IntMap.t;
92 mutable gutter : int IntMap.t;
93 mutable previous : (pos * MessageSeverity.t * int) option;
18694 }
18795
188 let create verbose cs = {
189 verbose = verbose;
190 cs = cs;
191 class_paths = Hashtbl.create 0;
192 changed_directories = Hashtbl.create 0;
193 compilation_step = 0;
194 compilation_mark = 0;
195 mark_loop = 0;
196 delays = [];
197 was_compilation = false;
96 let create_error_context () = {
97 last_positions = IntMap.empty;
98 max_lines = IntMap.empty;
99 gutter = IntMap.empty;
100 previous = None;
198101 }
199102
200 let add_delay sctx f =
201 sctx.delays <- f :: sctx.delays
202
203 let run_delays sctx =
204 let fl = sctx.delays in
205 sctx.delays <- [];
206 List.iter (fun f -> f()) fl
207
208 let reset sctx =
209 Hashtbl.clear sctx.changed_directories;
210 sctx.was_compilation <- false
103 let error_printer file line = Printf.sprintf "%s:%d:" file line
104
105 let resolve_source file l1 p1 l2 p2 =
106 let ch = open_in_bin file in
107 let curline = ref 1 in
108 let lines = ref [] in
109 let rec loop p line =
110 let inc i line =
111 if (!curline >= l1) && (!curline <= l2) then lines := (!curline, line) :: !lines;
112 curline := !curline + 1;
113 (i, "")
114 in
115
116 let input_char_or_done ch line =
117 try input_char ch with End_of_file -> begin
118 ignore(inc 0 line);
119 raise End_of_file
120 end
121 in
122
123 try
124 let read_char line = match input_char_or_done ch line with
125 | '\n' -> inc 1 line
126 | '\r' ->
127 ignore(input_char_or_done ch line);
128 inc 2 line
129 | c -> begin
130 let line = ref (line ^ (String.make 1 c)) in
131 let rec skip n =
132 if n > 0 then begin
133 let c = input_char_or_done ch !line in
134 line := !line ^ (String.make 1 c);
135 skip (n - 1)
136 end
137 in
138
139 let code = int_of_char c in
140 if code < 0xC0 then ()
141 else if code < 0xE0 then skip 1
142 else if code < 0xF0 then skip 2
143 else skip 3;
144
145 (1, !line)
146 end
147 in
148
149 let (delta, line) = read_char line in
150 loop (p + delta) line
151 with End_of_file ->
152 close_in ch;
153 in
154
155 loop 0 "";
156 List.rev !lines
157
158 let resolve_file ctx f =
159 let ext = Common.extension f in
160 let second_ext = Common.extension (Common.remove_extension f) in
161 let platform_ext = "." ^ (platform_name_macro ctx) in
162 if platform_ext = second_ext then
163 (Common.remove_extension (Common.remove_extension f)) ^ ext
164 else
165 f
166
167 let compiler_pretty_message_string ctx ectx cm =
168 match cm.cm_message with
169 (* Filter some messages that don't add much when using this message renderer *)
170 | "End of overload failure reasons" -> None
171 | _ -> begin
172 ectx.last_positions <- (IntMap.add cm.cm_depth cm.cm_pos ectx.last_positions);
173 let is_null_pos = cm.cm_pos = null_pos || cm.cm_pos.pmin = -1 in
174 let is_unknown_file f = f = "" || f = "?" in
175
176 (* Extract informations from position *)
177 let l1, p1, l2, p2, epos, lines =
178 if is_null_pos then begin
179 let epos = if is_unknown_file cm.cm_pos.pfile then "(unknown position)" else cm.cm_pos.pfile in
180 (-1, -1, -1, -1, epos, [])
181 end else begin
182 let f = resolve_file ctx.com cm.cm_pos.pfile in
183 let f =
184 try Common.find_file ctx.com f
185 with Not_found -> failwith ("File not found '" ^ cm.cm_pos.pfile ^ "'")
186 in
187
188 let l1, p1, l2, p2 = Lexer.get_pos_coords cm.cm_pos in
189 let lines = resolve_source f l1 p1 l2 p2 in
190 let epos = Lexer.get_error_pos error_printer cm.cm_pos in
191 (l1, p1, l2, p2, epos, lines)
192 end in
193
194 (* If 4 lines or less, display all; if more, crop the middle *)
195 let lines = match lines with
196 | _ :: (_ :: (_ :: (_ :: []))) -> lines
197 | hd :: (_ :: (_ :: (_ :: l))) ->
198 let _,line = hd in
199 let indent = ref 0 in
200 let found = ref false in
201
202 while (not !found) && (!indent < (String.length line - 1)) do
203 found := not (Lexer.is_whitespace (String.unsafe_get line !indent));
204 indent := !indent + 1
205 done;
206
207 [hd; (0, (String.make (!indent+1) ' ') ^ "[...]"); List.hd (List.rev l)]
208 | _ -> lines
209 in
210
211 let parent_pos =
212 if cm.cm_depth = 0 then null_pos
213 else (try IntMap.find (cm.cm_depth-1) ectx.last_positions with Not_found -> null_pos)
214 in
215
216 let prev_pos,prev_sev,prev_nl = match ectx.previous with
217 | None -> (None, None, 0)
218 | Some (p, sev, depth) -> (Some p, Some sev, depth)
219 in
220
221 let sev_changed = prev_sev = None || Some cm.cm_severity <> prev_sev in
222 let pos_changed = (prev_pos = None || cm.cm_pos <> Option.get prev_pos || (cm.cm_depth <> prev_nl && cm.cm_depth <> prev_nl + 1)) && (parent_pos = null_pos || cm.cm_pos <> parent_pos) in
223 let file_changed = prev_pos = None || (pos_changed && match (cm.cm_pos.pfile, (Option.get prev_pos).pfile) with
224 | (f1, f2) when (is_unknown_file f1) && (is_unknown_file f2) -> false
225 | (f1, f2) -> f1 <> f2
226 ) in
227
228 let display_heading = cm.cm_depth = 0 || sev_changed || file_changed in
229 let display_source = cm.cm_depth = 0 || sev_changed || pos_changed in
230 let display_pos_marker = (not is_null_pos) && (cm.cm_depth = 0 || sev_changed || pos_changed) in
231
232 let gutter_len = (try String.length (Printf.sprintf "%d" (IntMap.find cm.cm_depth ectx.max_lines)) with Not_found -> 0) + 2 in
233
234 let no_color = Define.defined ctx.com.defines Define.NoColor in
235 let c_reset = if no_color then "" else "\x1b[0m" in
236 let c_bold = if no_color then "" else "\x1b[1m" in
237 let c_dim = if no_color then "" else "\x1b[2m" in
238
239 let (c_sev, c_sev_bg) = if no_color then ("", "") else match cm.cm_severity with
240 | MessageSeverity.Warning -> ("\x1b[33m", "\x1b[30;43m")
241 | Information | Hint -> ("\x1b[34m", "\x1b[30;44m")
242 | Error -> ("\x1b[31m", "\x1b[30;41m")
243 in
244
245 let sev_label = if cm.cm_depth > 0 then " -> " else Printf.sprintf
246 (if no_color then "[%s]" else " %s ")
247 (match cm.cm_severity with
248 | MessageSeverity.Warning -> "WARNING"
249 | Information -> "INFO"
250 | Hint -> "HINT"
251 | Error -> "ERROR"
252 ) in
253
254 let out = ref "" in
255
256 if display_heading then
257 out := Printf.sprintf "%s%s\n\n"
258 (* Severity heading *)
259 (c_sev_bg ^ sev_label ^ c_reset ^ " ")
260 (* File + line pointer *)
261 epos;
262
263 (* Error source *)
264 if display_source then out := List.fold_left (fun out (l, line) ->
265 let nb_len = String.length (string_of_int l) in
266
267 (* Replace tabs with 1 space to avoid column misalignments *)
268 let line = String.concat " " (ExtString.String.nsplit line "\t") in
269 let len = String.length line in
270
271 out ^ Printf.sprintf "%s%s | %s\n"
272 (* left-padded line number *)
273 (String.make (gutter_len-nb_len-1) ' ')
274 (if l = 0 then "-" else Printf.sprintf "%d" l)
275 (* Source code at that line *)
276 (
277 if l = 0 then
278 c_dim ^ line ^ c_reset
279 else if l1 = l2 then
280 (if p1 > 1 then c_dim ^ (String.sub line 0 (p1-1)) else "")
281 ^ c_reset ^ c_bold ^ (String.sub line (p1-1) (p2-p1))
282 ^ c_reset ^ c_dim ^ (String.sub line (p2-1) (len - p2 + 1))
283 ^ c_reset
284 else begin
285 (if (l = l1) then
286 (if p1 > 1 then c_dim ^ (String.sub line 0 (p1-1)) else "")
287 ^ c_reset ^ c_bold ^ (String.sub line (p1-1) (len-p1+1))
288 ^ c_reset
289 else if (l = l2) then
290 (if p2 > 1 then c_bold ^ (String.sub line 0 (p2-1)) else "")
291 ^ c_reset ^ c_dim ^ (String.sub line (p2-1) (len-p2+1))
292 ^ c_reset
293 else c_bold ^ line ^ c_reset)
294 end
295 )
296 ) !out lines;
297
298 (* Error position marker *)
299 if display_pos_marker then
300 out := Printf.sprintf "%s%s|%s\n"
301 !out
302 (String.make gutter_len ' ')
303 (if l1 = l2 then String.make p1 ' ' ^ c_sev ^ String.make (if p1 = p2 then 1 else p2-p1) '^' ^ c_reset else "");
304
305 (* Error message *)
306 out := List.fold_left (fun out str -> Printf.sprintf "%s%s| %s\n"
307 out
308 (String.make gutter_len ' ')
309 (* Remove "... " prefix *)
310 (if (ExtString.String.starts_with str "... ") then String.sub str 4 ((String.length str) - 4) else str)
311 ) !out (ExtString.String.nsplit cm.cm_message "\n");
312
313 ectx.previous <- Some ((if is_null_pos then null_pos else cm.cm_pos), cm.cm_severity, cm.cm_depth);
314 ectx.gutter <- (IntMap.add cm.cm_depth gutter_len ectx.gutter);
315
316 (* Indent sub errors *)
317 let rec indent ?(acc=0) depth =
318 if depth = 0 then acc
319 else indent ~acc:(acc + try IntMap.find (depth-1) ectx.gutter with Not_found -> 3) (depth-1)
320 in
321
322 Some (
323 if cm.cm_depth > 0 then String.concat "\n" (List.map (fun str -> match str with
324 | "" -> ""
325 | _ -> (String.make (indent cm.cm_depth) ' ') ^ str
326 ) (ExtString.String.nsplit !out "\n"))
327 else !out
328 )
329 end
330
331 let compiler_message_string ctx ectx cm =
332 let str = match cm.cm_severity with
333 | MessageSeverity.Warning -> "Warning : " ^ cm.cm_message
334 | Information | Error | Hint -> cm.cm_message
335 in
336
337 if cm.cm_pos = null_pos then
338 Some str
339 else begin
340 let epos = Lexer.get_error_pos error_printer cm.cm_pos in
341 let str =
342 let lines =
343 match (ExtString.String.nsplit str "\n") with
344 | first :: rest -> first :: List.map Error.compl_msg rest
345 | l -> l
346 in
347 String.concat ("\n" ^ epos ^ " : ") lines
348 in
349 Some (Printf.sprintf "%s : %s" epos str)
350 end
351
352 let compiler_indented_message_string ctx ectx cm =
353 match cm.cm_message with
354 (* Filter some messages that don't add much when using this message renderer *)
355 | "End of overload failure reasons" -> None
356 | _ ->
357 let str = match cm.cm_severity with
358 | MessageSeverity.Warning -> "Warning : " ^ cm.cm_message
359 | Information -> "Info : " ^ cm.cm_message
360 | Error | Hint -> cm.cm_message
361 in
362
363 if cm.cm_pos = null_pos then
364 Some str
365 else begin
366 let epos = Lexer.get_error_pos error_printer cm.cm_pos in
367 let lines =
368 match (ExtString.String.nsplit str "\n") with
369 | first :: rest -> (cm.cm_depth, first) :: List.map (fun msg -> (cm.cm_depth+1, msg)) rest
370 | l -> [(cm.cm_depth, List.hd l)]
371 in
372 let rm_prefix str = if (ExtString.String.starts_with str "... ") then String.sub str 4 ((String.length str) - 4) else str in
373 Some (String.concat "\n" (List.map (fun (depth, msg) -> (String.make (depth*2) ' ') ^ epos ^ " : " ^ (rm_prefix msg)) lines))
374 end
375
376 let get_max_line max_lines messages =
377 List.fold_left (fun max_lines cm ->
378 let _,_,l2,_ = Lexer.get_pos_coords cm.cm_pos in
379 let old = try IntMap.find cm.cm_depth max_lines with Not_found -> 0 in
380
381 if l2 > old then IntMap.add cm.cm_depth l2 max_lines
382 else max_lines
383 ) max_lines messages
384
385 let display_messages ctx on_message = begin
386 let ectx = create_error_context () in
387 ectx.max_lines <- get_max_line ectx.max_lines ctx.messages;
388
389 let get_formatter def default =
390 let format_mode = Define.defined_value_safe ~default ctx.com.defines def in
391 match format_mode with
392 | "pretty" -> compiler_pretty_message_string ctx ectx
393 | "indent" -> compiler_indented_message_string ctx ectx
394 | "classic" -> compiler_message_string ctx ectx
395 | m -> begin
396 let def = Define.get_define_key def in
397 error ctx (Printf.sprintf "Invalid message reporting mode: \"%s\", expected classic | pretty | indent (for -D %s)." m def) null_pos;
398 compiler_message_string ctx ectx
399 end
400 in
401
402 let message_formatter = get_formatter Define.MessageReporting "classic" in
403 let log_formatter = get_formatter Define.MessagesLogFormat "indent" in
404
405 let log_messages = ref (Define.defined ctx.com.defines Define.MessagesLogFile) in
406 let log_message = ref None in
407 let close_logs = ref None in
408
409 if !log_messages then begin
410 try begin
411 let buf = Rbuffer.create 16000 in
412
413 let file = Define.defined_value ctx.com.defines Define.MessagesLogFile in
414 let chan =
415 Path.mkdir_from_path file;
416 open_out_bin file
417 in
418
419 log_message := (Some (fun msg ->
420 match (log_formatter msg) with
421 | None -> ()
422 | Some str -> Rbuffer.add_string buf (str ^ "\n")));
423
424 close_logs := (Some (fun () ->
425 Rbuffer.output_buffer chan buf;
426 Rbuffer.clear buf;
427 close_out chan
428 ));
429 end with
430 | Failure e | Sys_error e -> begin
431 let def = Define.get_define_key Define.MessagesLogFile in
432 error ctx (Printf.sprintf "Error opening log file: %s. Logging to file disabled (-D %s)" e def) null_pos;
433 log_messages := false;
434 end
435 end;
436
437 List.iter (fun cm ->
438 if !log_messages then (Option.get !log_message) cm;
439
440 match (message_formatter cm) with
441 | None -> ()
442 | Some str -> on_message cm.cm_severity str
443 ) (List.rev ctx.messages);
444
445 if !log_messages then (Option.get !close_logs) ();
446 end
447
448 let create_stdio () =
449 let rec self = {
450 write_out = (fun s ->
451 print_string s;
452 flush stdout;
453 );
454 write_err = (fun s ->
455 prerr_string s;
456 );
457 flush = (fun ctx ->
458 display_messages ctx (fun sev output ->
459 match sev with
460 | MessageSeverity.Information -> print_endline output
461 | Warning | Error | Hint -> prerr_endline output
462 );
463
464 if has_error ctx && !Helper.prompt then begin
465 print_endline "Press enter to exit...";
466 ignore(read_line());
467 end;
468 flush stdout;
469 );
470 exit = (fun code ->
471 if code = 0 then begin
472 Timer.close_times();
473 if !Timer.measure_times then Timer.report_times (fun s -> self.write_err (s ^ "\n"));
474 end;
475 exit code;
476 );
477 is_server = false;
478 } in
479 self
480
481 let create_pipe sctx write = {
482 write_out = (fun s ->
483 write ("\x01" ^ String.concat "\x01" (ExtString.String.nsplit s "\n") ^ "\n")
484 );
485 write_err = (fun s ->
486 write s
487 );
488 flush = (fun ctx ->
489 check_display_flush ctx (fun () ->
490 display_messages ctx (fun _ output ->
491 write (output ^ "\n");
492 ServerMessage.message output;
493 );
494
495 sctx.was_compilation <- ctx.com.display.dms_full_typing;
496 if has_error ctx then begin
497 measure_times := false;
498 write "\x02\n"
499 end
500 )
501 );
502 exit = (fun i ->
503 ()
504 );
505 is_server = true;
506 }
211507 end
212
213 open ServerCompilationContext
214508
215509 let stat dir =
216510 (Unix.stat (Path.remove_trailing_slash dir)).Unix.st_mtime
238532 if not (cs#has_directory sign dir) then begin
239533 let time = stat dir in
240534 ServerMessage.added_directory com "" dir;
241 cs#add_directory sign (CompilationServer.create_directory dir time)
535 cs#add_directory sign (CompilationCache.create_directory dir time)
242536 end;
243537 ) sub_dirs;
244 (CompilationServer.create_directory dir.c_path time') :: acc
538 (CompilationCache.create_directory dir.c_path time') :: acc
245539 end else
246540 acc
247541 with Unix.Unix_error _ ->
261555 let add_dir path =
262556 try
263557 let time = stat path in
264 dirs := CompilationServer.create_directory path time :: !dirs
558 dirs := CompilationCache.create_directory path time :: !dirs
265559 with Unix.Unix_error _ ->
266560 ()
267561 in
284578 [Some m'] where [m'] is the module responsible for [m] not being reusable. *)
285579 let check_module sctx ctx m p =
286580 let com = ctx.Typecore.com in
287 let cc = CommonCache.get_cache sctx.cs com in
581 let cc = CommonCache.get_cache com in
288582 let content_changed m file =
289583 let fkey = ctx.com.file_keys#get file in
290584 try
303597 let time = file_time file in
304598 if time > m.m_extra.m_time then begin
305599 ServerMessage.module_path_changed com "" (m,time,file);
306 raise Not_found
600 raise (Dirty (Shadowed file))
307601 end
308602 end
309603 ) paths
310604 in
311 let mark = sctx.mark_loop in
312 let start_mark = sctx.compilation_mark in
605 let start_mark = sctx.compilation_step in
606 let unknown_state_modules = ref [] in
313607 let rec check m =
314608 let check_module_path () =
315609 let directories = get_changed_directories sctx ctx in
317611 | MFake | MImport -> () (* don't get classpath *)
318612 | MExtern ->
319613 (* if we have a file then this will override our extern type *)
320 let has_file = (try check_module_shadowing directories m; false with Not_found -> true) in
321 if has_file then begin
322 if sctx.verbose then print_endline ("A file is masking the library file " ^ s_type_path m.m_path); (* TODO *)
323 raise Not_found;
324 end;
614 check_module_shadowing directories m;
325615 let rec loop = function
326616 | [] ->
327617 if sctx.verbose then print_endline ("No library file was found for " ^ s_type_path m.m_path); (* TODO *)
328 raise Not_found (* no extern registration *)
618 raise (Dirty LibraryChanged)
329619 | (file,load) :: l ->
330620 match load m.m_path p with
331 | None -> loop l
621 | None ->
622 loop l
332623 | Some _ ->
333624 if com.file_keys#get file <> (Path.UniqueKey.lazy_key m.m_extra.m_file) then begin
334625 if sctx.verbose then print_endline ("Library file was changed for " ^ s_type_path m.m_path); (* TODO *)
335 raise Not_found;
626 raise (Dirty LibraryChanged)
336627 end
337628 in
338629 loop com.load_extern_type
339 | MCode -> check_module_shadowing directories m
340 | MMacro when ctx.Typecore.in_macro -> check_module_shadowing directories m
630 | MCode ->
631 check_module_shadowing directories m
632 | MMacro when com.is_macro_context ->
633 check_module_shadowing directories m
341634 | MMacro ->
342635 (*
343636 Creating another context while the previous one is incomplete means we have an infinite loop in the compiler.
345638 Prevents spending another 5 hours for debugging.
346639 @see https://github.com/HaxeFoundation/haxe/issues/8174
347640 *)
348 if not ctx.g.complete && ctx.in_macro then
641 if not ctx.g.complete && ctx.com.is_macro_context then
349642 raise (ServerError ("Infinite loop in Haxe server detected. "
350643 ^ "Probably caused by shadowing a module of the standard library. "
351644 ^ "Make sure shadowed module does not pull macro context."));
364657 end else begin
365658 ServerMessage.not_cached com "" m;
366659 if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules (Path.UniqueKey.lazy_key m.m_extra.m_file);
367 raise Not_found;
660 raise (Dirty (FileChanged file))
368661 end
369662 end
370663 in
371664 let check_dependencies () =
372665 PMap.iter (fun _ m2 -> match check m2 with
373666 | None -> ()
374 | Some path -> raise (Dirty path)
667 | Some reason -> raise (Dirty (DependencyDirty(m2.m_path,reason)))
375668 ) m.m_extra.m_deps;
376669 in
377 begin match m.m_extra.m_dirty with
378 | Some path ->
379 Some path
380 | None ->
381 if m.m_extra.m_mark = mark then
382 None
383 else try
384 let old_mark = m.m_extra.m_mark in
385 m.m_extra.m_mark <- mark;
386 if old_mark <= start_mark then begin
387 if not (has_policy NoCheckShadowing) then check_module_path();
388 if not (has_policy NoCheckFileTimeModification) || file_extension (Path.UniqueKey.lazy_path m.m_extra.m_file) <> "hx" then check_file();
389 end;
670 let check () =
671 try
672 if not (has_policy NoCheckShadowing) then check_module_path();
673 if not (has_policy NoCheckFileTimeModification) || Path.file_extension (Path.UniqueKey.lazy_path m.m_extra.m_file) <> "hx" then check_file();
390674 if not (has_policy NoCheckDependencies) then check_dependencies();
391675 None
392676 with
393 | Not_found ->
394 m.m_extra.m_dirty <- Some m.m_path;
395 Some m.m_path
396 | Dirty path ->
397 m.m_extra.m_dirty <- Some path;
398 Some path
399 end
400 in
401 check m
677 | Dirty reason ->
678 Some reason
679 in
680 (* If the module mark matches our compilation mark, we are done *)
681 if m.m_extra.m_checked = start_mark then begin match m.m_extra.m_cache_state with
682 | MSGood | MSUnknown ->
683 None
684 | MSBad reason ->
685 Some reason
686 end else begin
687 (* Otherwise, set to current compilation mark for recursion *)
688 m.m_extra.m_checked <- start_mark;
689 let dirty = match m.m_extra.m_cache_state with
690 | MSBad reason ->
691 (* If we are already dirty, stick to it. *)
692 Some reason
693 | MSUnknown ->
694 (* This should not happen because any MSUnknown module is supposed to have the current m_checked. *)
695 die "" __LOC__
696 | MSGood ->
697 (* Otherwise, run the checks *)
698 m.m_extra.m_cache_state <- MSUnknown;
699 check ()
700 in
701 let dirty = match dirty with
702 | Some (DependencyDirty _) when has_policy Retype ->
703 let result = Retyper.attempt_retyping ctx m p in
704 begin match result with
705 | None ->
706 ServerMessage.retyper_ok com "" m;
707 None
708 | Some reason ->
709 ServerMessage.retyper_fail com "" m reason;
710 dirty
711 end
712 | _ ->
713 dirty
714 in
715 (* Update the module now. It will use this dirty status for the remainder of this compilation. *)
716 begin match dirty with
717 | Some reason ->
718 (* Update the state if we're dirty. *)
719 m.m_extra.m_cache_state <- MSBad reason;
720 | None ->
721 (* We cannot update if we're clean because at this point it might just be an assumption.
722 Instead We add the module to a list which is updated at the end of handling this subgraph. *)
723 unknown_state_modules := m :: !unknown_state_modules;
724 end;
725 dirty
726 end
727 in
728 let state = check m in
729 begin match state with
730 | None ->
731 (* If the entire subgraph is clean, we can set all modules to good state *)
732 List.iter (fun m -> m.m_extra.m_cache_state <- MSGood) !unknown_state_modules;
733 | Some _ ->
734 (* Otherwise, unknown state module may or may not be dirty. We didn't check everything eagerly, so we have
735 to make sure that the module is checked again if it appears in a different check. This is achieved by
736 setting m_checked to a lower value and assuming Good state again. *)
737 List.iter (fun m -> match m.m_extra.m_cache_state with
738 | MSUnknown ->
739 m.m_extra.m_checked <- start_mark - 1;
740 m.m_extra.m_cache_state <- MSGood;
741 | MSGood | MSBad _ ->
742 ()
743 ) !unknown_state_modules
744 end;
745 state
402746
403747 (* Adds module [m] and all its dependencies (recursively) from the cache to the current compilation
404748 context. *)
405749 let add_modules sctx ctx m p =
406750 let com = ctx.Typecore.com in
407751 let rec add_modules tabs m0 m =
408 if m.m_extra.m_added < sctx.compilation_step then begin
752 if m.m_extra.m_added < ctx.com.compilation_step then begin
409753 (match m0.m_extra.m_kind, m.m_extra.m_kind with
410754 | MCode, MMacro | MMacro, MCode ->
411755 (* this was just a dependency to check : do not add to the context *)
412756 PMap.iter (Hashtbl.replace com.resources) m.m_extra.m_binded_res;
413757 | _ ->
758 m.m_extra.m_added <- ctx.com.compilation_step;
414759 ServerMessage.reusing com tabs m;
415 m.m_extra.m_added <- sctx.compilation_step;
416760 List.iter (fun t ->
417 match t with
418 | TClassDecl c -> c.cl_restore()
419 | TEnumDecl e ->
420 let rec loop acc = function
421 | [] -> ()
422 | (Meta.RealPath,[Ast.EConst (Ast.String(path,_)),_],_) :: l ->
423 e.e_path <- Ast.parse_path path;
424 e.e_meta <- (List.rev acc) @ l;
425 | x :: l -> loop (x::acc) l
426 in
427 loop [] e.e_meta
428 | TAbstractDecl a ->
429 a.a_meta <- List.filter (fun (m,_,_) -> m <> Meta.ValueUsed) a.a_meta
430 | _ -> ()
761 (t_infos t).mt_restore()
431762 ) m.m_types;
432 TypeloadModule.add_module ctx m p;
763 TypeloadModule.ModuleLevel.add_module ctx m p;
433764 PMap.iter (Hashtbl.replace com.resources) m.m_extra.m_binded_res;
434765 PMap.iter (fun _ m2 -> add_modules (tabs ^ " ") m0 m2) m.m_extra.m_deps
435766 )
442773 let type_module sctx (ctx:Typecore.typer) mpath p =
443774 let t = Timer.timer ["server";"module cache"] in
444775 let com = ctx.Typecore.com in
445 let cc = CommonCache.get_cache sctx.cs com in
446 sctx.mark_loop <- sctx.mark_loop + 1;
776 let cc = CommonCache.get_cache com in
447777 try
448778 let m = cc#find_module mpath in
449779 let tcheck = Timer.timer ["server";"module cache";"check"] in
450780 begin match check_module sctx ctx m p with
451781 | None -> ()
452 | Some path ->
453 ServerMessage.skipping_dep com "" (m,path);
782 | Some reason ->
783 ServerMessage.skipping_dep com "" (m,(Printer.s_module_skip_reason reason));
454784 tcheck();
455785 raise Not_found;
456786 end;
464794 t();
465795 None
466796
467 (* Sets up the per-compilation context. *)
468 let create sctx write params =
797 let before_anything sctx ctx =
798 ensure_macro_setup sctx
799
800 let after_arg_parsing sctx ctx =
801 let com = ctx.com in
469802 let cs = sctx.cs in
470 let maybe_cache_context com =
471 if com.display.dms_full_typing then begin
472 CommonCache.cache_context sctx.cs com;
473 ServerMessage.cached_modules com "" (List.length com.modules);
803 let sign = Define.get_signature com.defines in
804 ServerMessage.defines com "";
805 ServerMessage.signature com "" sign;
806 ServerMessage.display_position com "" (DisplayPosition.display_position#get);
807 try
808 if (Hashtbl.find sctx.class_paths sign) <> com.class_path then begin
809 ServerMessage.class_paths_changed com "";
810 Hashtbl.replace sctx.class_paths sign com.class_path;
811 cs#clear_directories sign;
812 (cs#get_context sign)#set_initialized false;
813 end;
814 with Not_found ->
815 Hashtbl.add sctx.class_paths sign com.class_path;
816 ()
817
818 let after_compilation sctx ctx =
819 if not (has_error ctx) then
820 maybe_cache_context sctx ctx.com
821
822 let mk_length_prefixed_communication allow_nonblock chin chout =
823 let sin = Unix.descr_of_in_channel chin in
824 let chin = IO.input_channel chin in
825 let chout = IO.output_channel chout in
826
827 let bout = Buffer.create 0 in
828
829 let block () = Unix.clear_nonblock sin in
830 let unblock () = Unix.set_nonblock sin in
831
832 let read_nonblock _ =
833 let len = IO.read_i32 chin in
834 Some (IO.really_nread_string chin len)
835 in
836 let read = if allow_nonblock then fun do_block ->
837 if do_block then begin
838 block();
839 read_nonblock true;
840 end else begin
841 let c0 =
842 unblock();
843 try
844 Some (IO.read_byte chin)
845 with
846 | Sys_blocked_io
847 (* TODO: We're supposed to catch Sys_blocked_io only, but that doesn't work on my PC... *)
848 | Sys_error _ ->
849 None
850 in
851 begin match c0 with
852 | Some c0 ->
853 block(); (* We got something, make sure we block until we're done. *)
854 let c1 = IO.read_byte chin in
855 let c2 = IO.read_byte chin in
856 let c3 = IO.read_byte chin in
857 let len = c3 lsl 24 + c2 lsl 16 + c1 lsl 8 + c0 in
858 Some (IO.really_nread_string chin len)
859 | None ->
860 None
861 end
474862 end
475 in
476 let ctx = create_context params in
477 ctx.flush <- (fun() ->
478 sctx.compilation_step <- sctx.compilation_step + 1;
479 sctx.compilation_mark <- sctx.mark_loop;
480 check_display_flush ctx (fun () ->
481 List.iter
482 (fun msg ->
483 let s = compiler_message_string msg in
484 write (s ^ "\n");
485 ServerMessage.message s;
486 )
487 (List.rev ctx.messages);
488 sctx.was_compilation <- ctx.com.display.dms_full_typing;
489 if ctx.has_error then begin
490 measure_times := false;
491 write "\x02\n"
492 end else maybe_cache_context ctx.com;
493 )
494 );
495 ctx.setup <- (fun() ->
496 let sign = Define.get_signature ctx.com.defines in
497 ServerMessage.defines ctx.com "";
498 ServerMessage.signature ctx.com "" sign;
499 ServerMessage.display_position ctx.com "" (DisplayPosition.display_position#get);
500 try
501 if (Hashtbl.find sctx.class_paths sign) <> ctx.com.class_path then begin
502 ServerMessage.class_paths_changed ctx.com "";
503 Hashtbl.replace sctx.class_paths sign ctx.com.class_path;
504 cs#clear_directories sign;
505 (cs#get_context sign)#set_initialized false;
863 else read_nonblock in
864
865 let write = Buffer.add_string bout in
866
867 let close = fun() ->
868 flush stdout;
869 IO.write_i32 chout (Buffer.length bout);
870 IO.nwrite_string chout (Buffer.contents bout);
871 IO.flush chout
872 in
873
874 fun () ->
875 Buffer.clear bout;
876 allow_nonblock, read, write, close
877
878 let ssend sock str =
879 let rec loop pos len =
880 if len = 0 then
881 ()
882 else
883 let s = Unix.send sock str pos len [] in
884 loop (pos + s) (len - s)
885 in
886 loop 0 (Bytes.length str)
887
888 (* The accept-function to wait for a stdio connection. *)
889 let init_wait_stdio() =
890 set_binary_mode_in stdin true;
891 set_binary_mode_out stderr true;
892 mk_length_prefixed_communication false stdin stderr
893
894 (* The connect function to connect to [host] at [port] and send arguments [args]. *)
895 let do_connect host port args =
896 let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
897 (try Unix.connect sock (Unix.ADDR_INET (Unix.inet_addr_of_string host,port)) with _ -> failwith ("Couldn't connect on " ^ host ^ ":" ^ string_of_int port));
898 let rec display_stdin args =
899 match args with
900 | [] -> ""
901 | "-D" :: ("display_stdin" | "display-stdin") :: _ ->
902 let accept = init_wait_stdio() in
903 let _, read, _, _ = accept() in
904 Option.default "" (read true)
905 | _ :: args ->
906 display_stdin args
907 in
908 let args = ("--cwd " ^ Unix.getcwd()) :: args in
909 let s = (String.concat "" (List.map (fun a -> a ^ "\n") args)) ^ (display_stdin args) in
910 ssend sock (Bytes.of_string (s ^ "\000"));
911 let has_error = ref false in
912 let rec print line =
913 match (if line = "" then '\x00' else line.[0]) with
914 | '\x01' ->
915 print_string (String.concat "\n" (List.tl (ExtString.String.nsplit line "\x01")));
916 flush stdout
917 | '\x02' ->
918 has_error := true;
919 | _ ->
920 prerr_endline line;
921 in
922 let buf = Buffer.create 0 in
923 let process() =
924 let lines = ExtString.String.nsplit (Buffer.contents buf) "\n" in
925 (* the last line ends with \n *)
926 let lines = (match List.rev lines with "" :: l -> List.rev l | _ -> lines) in
927 List.iter print lines;
928 in
929 let tmp = Bytes.create 1024 in
930 let rec loop() =
931 let b = Unix.recv sock tmp 0 1024 [] in
932 Buffer.add_subbytes buf tmp 0 b;
933 if b > 0 then begin
934 if Bytes.get tmp (b - 1) = '\n' then begin
935 process();
936 Buffer.reset buf;
506937 end;
507 with Not_found ->
508 Hashtbl.add sctx.class_paths sign ctx.com.class_path;
509 ()
510 );
511 ctx.com.print <- (fun str -> write ("\x01" ^ String.concat "\x01" (ExtString.String.nsplit str "\n") ^ "\n"));
512 ctx
513
514 (* Resets the state for a new compilation *)
515 let init_new_compilation sctx =
516 ServerCompilationContext.reset sctx;
517 Parser.reset_state();
518 return_partial_type := false;
519 measure_times := false;
520 Hashtbl.clear DeprecationCheck.warned_positions;
521 close_times();
522 stats.s_files_parsed := 0;
523 stats.s_classes_built := 0;
524 stats.s_methods_typed := 0;
525 stats.s_macros_called := 0;
526 Hashtbl.clear Timer.htimers;
527 sctx.compilation_step <- sctx.compilation_step + 1;
528 sctx.compilation_mark <- sctx.mark_loop;
529 start_time := get_time()
530
531 let cleanup () =
532 begin match !MacroContext.macro_interp_cache with
533 | Some interp -> EvalContext.GlobalState.cleanup interp
534 | None -> ()
535 end
536
537 let gc_heap_stats () =
538 let stats = Gc.quick_stat() in
539 stats.major_words,stats.heap_words
540
541 let fmt_percent f =
542 int_of_float (f *. 100.)
543
544 module Tasks = struct
545 class gc_task (max_working_memory : float) (heap_size : float) = object(self)
546 inherit server_task ["gc"] 100
547
548 method private execute =
549 let t0 = get_time() in
550 let stats = Gc.stat() in
551 let live_words = float_of_int stats.live_words in
552 (* Maximum heap size needed for the last X compilations = sum of what's live + max working memory. *)
553 let needed_max = live_words +. max_working_memory in
554 (* Additional heap percentage needed = what's live / max of what was live. *)
555 let percent_needed = (1. -. live_words /. needed_max) in
556 (* Effective cache size percentage = what's live / heap size. *)
557 let percent_used = live_words /. heap_size in
558 (* Set allowed space_overhead to the maximum of what we needed during the last X compilations. *)
559 let new_space_overhead = int_of_float ((percent_needed +. 0.05) *. 100.) in
560 let old_gc = Gc.get() in
561 Gc.set { old_gc with Gc.space_overhead = new_space_overhead; };
562 (* Compact if less than 80% of our heap words consist of the cache and there's less than 50% overhead. *)
563 let do_compact = percent_used < 0.8 && percent_needed < 0.5 in
564 begin if do_compact then
565 Gc.compact()
566 else
567 Gc.full_major();
568 end;
569 Gc.set old_gc;
570 ServerMessage.gc_stats (get_time() -. t0) stats do_compact new_space_overhead
571 end
572
573 class class_maintenance_task (cs : CompilationServer.t) (c : tclass) = object(self)
574 inherit server_task ["module maintenance"] 70
575
576 method private execute =
577 let rec field cf =
578 (* Unset cf_expr. This holds the optimized version for generators, which we don't need to persist. If
579 we compile again, the semi-optimized expression will be restored by calling cl_restore(). *)
580 cf.cf_expr <- None;
581 List.iter field cf.cf_overloads
582 in
583 (* What we're doing here at the moment is free, so we can just do it in one task. If this ever gets more expensive,
584 we should spawn a task per-field. *)
585 List.iter field c.cl_ordered_fields;
586 List.iter field c.cl_ordered_statics;
587 Option.may field c.cl_constructor;
588 end
589
590 class module_maintenance_task (cs : CompilationServer.t) (m : module_def) = object(self)
591 inherit server_task ["module maintenance"] 80
592
593 method private execute =
594 List.iter (fun mt -> match mt with
595 | TClassDecl c ->
596 cs#add_task (new class_maintenance_task cs c)
597 | _ ->
598 ()
599 ) m.m_types
600 end
601
602 class server_exploration_task (cs : CompilationServer.t) = object(self)
603 inherit server_task ["server explore"] 90
604
605 method private execute =
606 cs#iter_modules (fun m -> cs#add_task (new module_maintenance_task cs m))
607 end
608 end
938 loop();
939 end
940 in
941 loop();
942 process();
943 if !has_error then exit 1
944
945 let enable_cache_mode sctx =
946 TypeloadModule.type_module_hook := type_module sctx;
947 MacroContext.macro_enable_cache := true;
948 ServerCompilationContext.ensure_macro_setup sctx;
949 TypeloadParse.parse_hook := parse_file sctx.cs
950
951 let rec process sctx comm args =
952 let t0 = get_time() in
953 ServerMessage.arguments args;
954 reset sctx;
955 let api = {
956 on_context_create = (fun () ->
957 sctx.compilation_step <- sctx.compilation_step + 1;
958 sctx.compilation_step;
959 );
960 cache = sctx.cs;
961 callbacks = {
962 before_anything = before_anything sctx;
963 after_arg_parsing = after_arg_parsing sctx;
964 after_compilation = after_compilation sctx;
965 };
966 init_wait_socket = init_wait_socket;
967 init_wait_connect = init_wait_connect;
968 init_wait_stdio = init_wait_stdio;
969 wait_loop = wait_loop;
970 do_connect = do_connect;
971 } in
972 Compiler.HighLevel.entry api comm args;
973 run_delays sctx;
974 ServerMessage.stats stats (get_time() -. t0)
609975
610976 (* The server main loop. Waits for the [accept] call to then process the sent compilation
611977 parameters through [process_params]. *)
612 let wait_loop process_params verbose accept =
978 and wait_loop verbose accept =
613979 if verbose then ServerMessage.enable_all ();
614980 Sys.catch_break false; (* Sys can never catch a break *)
615981 (* Create server context and set up hooks for parsing and typing *)
616 let cs = CompilationServer.create () in
617 let sctx = ServerCompilationContext.create verbose cs in
618 TypeloadModule.type_module_hook := type_module sctx;
619 MacroContext.macro_enable_cache := true;
620 TypeloadParse.parse_hook := parse_file cs;
982 let sctx = ServerCompilationContext.create verbose in
983 let cs = sctx.cs in
984 enable_cache_mode sctx;
621985 let ring = Ring.create 10 0. in
986 let gc_heap_stats () =
987 let stats = Gc.quick_stat() in
988 stats.major_words,stats.heap_words
989 in
622990 let heap_stats_start = ref (gc_heap_stats()) in
623991 let update_heap () =
624992 (* On every compilation: Track how many words were allocated for this compilation (working memory). *)
6371005 (* Main loop: accept connections and process arguments *)
6381006 while true do
6391007 let support_nonblock, read, write, close = accept() in
640 let process s =
641 let t0 = get_time() in
642 let hxml =
643 try
644 let idx = String.index s '\001' in
645 current_stdin := Some (String.sub s (idx + 1) ((String.length s) - idx - 1));
646 (String.sub s 0 idx)
647 with Not_found ->
648 s
649 in
650 let data = parse_hxml_data hxml in
651 ServerMessage.arguments data;
652 init_new_compilation sctx;
653 begin try
654 let create = create sctx write in
655 (* Pass arguments to normal handling in main.ml *)
656 process_params create data;
657 close_times();
658 if !measure_times then report_times (fun s -> write (s ^ "\n"))
659 with
660 | Completion str ->
661 ServerMessage.completion str;
662 write str
663 | Arg.Bad msg ->
664 print_endline ("Error: " ^ msg);
665 end;
666 run_delays sctx;
667 ServerMessage.stats stats (get_time() -. t0)
668 in
6691008 begin try
6701009 (* Read arguments *)
6711010 let rec loop block =
6721011 match read block with
673 | Some data ->
674 process data
1012 | Some s ->
1013 let hxml =
1014 try
1015 let idx = String.index s '\001' in
1016 current_stdin := Some (String.sub s (idx + 1) ((String.length s) - idx - 1));
1017 (String.sub s 0 idx)
1018 with Not_found ->
1019 s
1020 in
1021 let data = Helper.parse_hxml_data hxml in
1022 process sctx (Communication.create_pipe sctx write) data
6751023 | None ->
6761024 if not cs#has_task then
6771025 (* If there is no pending task, turn into blocking mode. *)
6891037 let estr = Printexc.to_string e in
6901038 ServerMessage.uncaught_error estr;
6911039 (try write ("\x02\n" ^ estr); with _ -> ());
692 if is_debug_run then print_endline (estr ^ "\n" ^ Printexc.get_backtrace());
1040 if Helper.is_debug_run then print_endline (estr ^ "\n" ^ Printexc.get_backtrace());
6931041 if e = Out_of_memory then begin
6941042 close();
6951043 exit (-1);
7051053 while cs#has_task do cs#get_task#run done
7061054 else if sctx.was_compilation then
7071055 cs#add_task (new Tasks.server_exploration_task cs)
708 done
709
710 let mk_length_prefixed_communication allow_nonblock chin chout =
711 let sin = Unix.descr_of_in_channel chin in
712 let chin = IO.input_channel chin in
713 let chout = IO.output_channel chout in
714
715 let bout = Buffer.create 0 in
716
717 let block () = Unix.clear_nonblock sin in
718 let unblock () = Unix.set_nonblock sin in
719
720 let read_nonblock _ =
721 let len = IO.read_i32 chin in
722 Some (IO.really_nread_string chin len)
723 in
724 let read = if allow_nonblock then fun do_block ->
725 if do_block then begin
726 block();
727 read_nonblock true;
728 end else begin
729 let c0 =
730 unblock();
731 try
732 Some (IO.read_byte chin)
733 with
734 | Sys_blocked_io
735 (* TODO: We're supposed to catch Sys_blocked_io only, but that doesn't work on my PC... *)
736 | Sys_error _ ->
737 None
738 in
739 begin match c0 with
740 | Some c0 ->
741 block(); (* We got something, make sure we block until we're done. *)
742 let c1 = IO.read_byte chin in
743 let c2 = IO.read_byte chin in
744 let c3 = IO.read_byte chin in
745 let len = c3 lsl 24 + c2 lsl 16 + c1 lsl 8 + c0 in
746 Some (IO.really_nread_string chin len)
747 | None ->
748 None
749 end
750 end
751 else read_nonblock in
752
753 let write = Buffer.add_string bout in
754
755 let close = fun() ->
756 IO.write_i32 chout (Buffer.length bout);
757 IO.nwrite_string chout (Buffer.contents bout);
758 IO.flush chout
759 in
760
761 fun () ->
762 Buffer.clear bout;
763 allow_nonblock, read, write, close
764
765 (* The accept-function to wait for a stdio connection. *)
766 let init_wait_stdio() =
767 set_binary_mode_in stdin true;
768 set_binary_mode_out stderr true;
769 mk_length_prefixed_communication false stdin stderr
1056 done;
1057 0
7701058
7711059 (* Connect to given host/port and return accept function for communication *)
772 let init_wait_connect host port =
1060 and init_wait_connect host port =
7731061 let host = Unix.inet_addr_of_string host in
7741062 let chin, chout = Unix.open_connection (Unix.ADDR_INET (host,port)) in
7751063 mk_length_prefixed_communication true chin chout
7761064
7771065 (* The accept-function to wait for a socket connection. *)
778 let init_wait_socket host port =
1066 and init_wait_socket host port =
7791067 let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
7801068 (try Unix.setsockopt sock Unix.SO_REUSEADDR true with _ -> ());
7811069 (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));
8161104 false, read, write, close
8171105 ) in
8181106 accept
819
820 (* The connect function to connect to [host] at [port] and send arguments [args]. *)
821 let do_connect host port args =
822 let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
823 (try Unix.connect sock (Unix.ADDR_INET (Unix.inet_addr_of_string host,port)) with _ -> failwith ("Couldn't connect on " ^ host ^ ":" ^ string_of_int port));
824 let rec display_stdin args =
825 match args with
826 | [] -> ""
827 | "-D" :: ("display_stdin" | "display-stdin") :: _ ->
828 let accept = init_wait_stdio() in
829 let _, read, _, _ = accept() in
830 Option.default "" (read true)
831 | _ :: args ->
832 display_stdin args
833 in
834 let args = ("--cwd " ^ Unix.getcwd()) :: args in
835 let s = (String.concat "" (List.map (fun a -> a ^ "\n") args)) ^ (display_stdin args) in
836 ssend sock (Bytes.of_string (s ^ "\000"));
837 let has_error = ref false in
838 let rec print line =
839 match (if line = "" then '\x00' else line.[0]) with
840 | '\x01' ->
841 print_string (String.concat "\n" (List.tl (ExtString.String.nsplit line "\x01")));
842 flush stdout
843 | '\x02' ->
844 has_error := true;
845 | _ ->
846 prerr_endline line;
847 in
848 let buf = Buffer.create 0 in
849 let process() =
850 let lines = ExtString.String.nsplit (Buffer.contents buf) "\n" in
851 (* the last line ends with \n *)
852 let lines = (match List.rev lines with "" :: l -> List.rev l | _ -> lines) in
853 List.iter print lines;
854 in
855 let tmp = Bytes.create 1024 in
856 let rec loop() =
857 let b = Unix.recv sock tmp 0 1024 [] in
858 Buffer.add_subbytes buf tmp 0 b;
859 if b > 0 then begin
860 if Bytes.get tmp (b - 1) = '\n' then begin
861 process();
862 Buffer.reset buf;
863 end;
864 loop();
865 end
866 in
867 loop();
868 process();
869 if !has_error then exit 1
0 open Globals
1 open Common
2 open Timer
3 open CompilationCache
4
5 type t = {
6 (* If true, prints some debug information *)
7 verbose : bool;
8 (* The list of changed directories per-signature *)
9 changed_directories : (Digest.t,cached_directory list) Hashtbl.t;
10 (* A reference to the compilation server instance *)
11 cs : CompilationCache.t;
12 (* A list of class paths per-signature *)
13 class_paths : (Digest.t,string list) Hashtbl.t;
14 (* Increased for each compilation *)
15 mutable compilation_step : int;
16 (* A list of delays which are run after compilation *)
17 mutable delays : (unit -> unit) list;
18 (* True if it's an actual compilation, false if it's a display operation *)
19 mutable was_compilation : bool;
20 (* True if the macro context has been set up *)
21 mutable macro_context_setup : bool;
22 }
23
24 let create verbose = {
25 verbose = verbose;
26 cs = new CompilationCache.cache;
27 class_paths = Hashtbl.create 0;
28 changed_directories = Hashtbl.create 0;
29 compilation_step = 0;
30 delays = [];
31 was_compilation = false;
32 macro_context_setup = false;
33 }
34
35 let add_delay sctx f =
36 sctx.delays <- f :: sctx.delays
37
38 let run_delays sctx =
39 let fl = sctx.delays in
40 sctx.delays <- [];
41 List.iter (fun f -> f()) fl
42
43 (* Resets the state for a new compilation *)
44 let reset sctx =
45 Hashtbl.clear sctx.changed_directories;
46 sctx.was_compilation <- false;
47 Parser.reset_state();
48 return_partial_type := false;
49 measure_times := false;
50 Hashtbl.clear DeprecationCheck.warned_positions;
51 close_times();
52 stats.s_files_parsed := 0;
53 stats.s_classes_built := 0;
54 stats.s_methods_typed := 0;
55 stats.s_macros_called := 0;
56 Hashtbl.clear Timer.htimers;
57 Helper.start_time := get_time()
58
59 let maybe_cache_context sctx com =
60 if com.display.dms_full_typing then begin
61 CommonCache.cache_context sctx.cs com;
62 ServerMessage.cached_modules com "" (List.length com.modules);
63 end
64
65 let ensure_macro_setup sctx =
66 if not sctx.macro_context_setup then begin
67 sctx.macro_context_setup <- true;
68 MacroContext.setup();
69 end
70
71 let cleanup () = match !MacroContext.macro_interp_cache with
72 | Some interp -> EvalContext.GlobalState.cleanup interp
73 | None -> ()
00 open Globals
11 open Common
2 open CompilationServer
2 open CompilationCache
33 open Type
44 open Json
55
1212 mutable print_parsed : bool;
1313 mutable print_removed_directory : bool;
1414 mutable print_reusing : bool;
15 mutable print_retyping : bool;
1516 mutable print_skipping_dep : bool;
1617 mutable print_unchanged_content : bool;
1718 mutable print_cached_modules : bool;
3738 print_parsed = false;
3839 print_removed_directory = false;
3940 print_reusing = false;
41 print_retyping = false;
4042 print_skipping_dep = false;
4143 print_unchanged_content = false;
4244 print_cached_modules = false;
5557
5658 let sign_string com =
5759 let sign = Define.get_signature com.defines in
58 let cs = CompilationServer.force () in
60 let cs = com.cs in
5961 let sign_id = (cs#get_context sign)#get_index in
6062 Printf.sprintf "%2i,%3s: " sign_id (short_platform_name com.platform)
6163
8486 let reusing com tabs m =
8587 if config.print_reusing then print_endline (Printf.sprintf "%s%sreusing %s" (sign_string com) tabs (s_type_path m.m_path))
8688
87 let skipping_dep com tabs (m,path) =
88 if config.print_skipping_dep then print_endline (Printf.sprintf "%sskipping %s%s" (sign_string com) (s_type_path m.m_path) (if m.m_path = path then "" else Printf.sprintf "(%s)" (s_type_path path)))
89 let retyper_ok com tabs m =
90 if config.print_retyping then print_endline (Printf.sprintf "%s%sretyped %s" (sign_string com) tabs (s_type_path m.m_path))
91
92 let retyper_fail com tabs m reason =
93 if config.print_retyping then begin
94 print_endline (Printf.sprintf "%s%sfailed retyping %s" (sign_string com) tabs (s_type_path m.m_path));
95 print_endline (Printf.sprintf "%s%s%s" (sign_string com) (tabs ^ " ") reason);
96 end
97
98 let skipping_dep com tabs (m,reason) =
99 if config.print_skipping_dep then print_endline (Printf.sprintf "%sskipping %s (%s)" (sign_string com) (s_type_path m.m_path) reason)
89100
90101 let unchanged_content com tabs file =
91102 if config.print_unchanged_content then print_endline (Printf.sprintf "%s%s changed time not but content, reusing" (sign_string com) file)
104115
105116 let defines com tabs =
106117 if config.print_defines then begin
107 let defines = PMap.foldi (fun k v acc -> (k ^ "=" ^ v) :: acc) com.defines.Define.values [] in
108 print_endline ("Defines " ^ (String.concat "," (List.sort compare defines)))
118 let buffer = Buffer.create 64 in
119 Buffer.add_string buffer "Defines ";
120 PMap.iter (Printf.bprintf buffer "%s=%s,") com.defines.values;
121 Buffer.truncate buffer (Buffer.length buffer - 1);
122 print_endline (Buffer.contents buffer)
109123 end
110124
111125 let signature com tabs sign =
150164 config.print_parsed <- true;
151165 config.print_removed_directory <- true;
152166 config.print_reusing <- true;
167 config.print_retyping <- true;
153168 config.print_skipping_dep <- true;
154169 config.print_unchanged_content <- true;
155170 config.print_cached_modules <- true;
173188 | "parsed" -> config.print_parsed <- value;
174189 | "removedDirectory" -> config.print_removed_directory <- value;
175190 | "reusing" -> config.print_reusing <- value;
191 | "retyping" -> config.print_retyping <- value;
176192 | "skippingDep" -> config.print_skipping_dep <- value;
177193 | "unchangedContent" -> config.print_unchanged_content <- value;
178194 | "cachedModules" -> config.print_cached_modules <- value;
186202 | "socketMessage" -> config.print_socket_message <- value;
187203 | "uncaughtError" -> config.print_uncaught_error <- value;
188204 | "newContext" -> config.print_new_context <- value;
189 | _ -> raise Not_found
205 | _ -> raise Not_found
0
1 open Type
2 open CompilationCache
3
4 class gc_task (max_working_memory : float) (heap_size : float) = object(self)
5 inherit server_task ["gc"] 100
6
7 method private execute =
8 let t0 = Timer.get_time() in
9 let stats = Gc.stat() in
10 let live_words = float_of_int stats.live_words in
11 (* Maximum heap size needed for the last X compilations = sum of what's live + max working memory. *)
12 let needed_max = live_words +. max_working_memory in
13 (* Additional heap percentage needed = what's live / max of what was live. *)
14 let percent_needed = (1. -. live_words /. needed_max) in
15 (* Effective cache size percentage = what's live / heap size. *)
16 let percent_used = live_words /. heap_size in
17 (* Set allowed space_overhead to the maximum of what we needed during the last X compilations. *)
18 let new_space_overhead = int_of_float ((percent_needed +. 0.05) *. 100.) in
19 let old_gc = Gc.get() in
20 Gc.set { old_gc with Gc.space_overhead = new_space_overhead; };
21 (* Compact if less than 80% of our heap words consist of the cache and there's less than 50% overhead. *)
22 let do_compact = percent_used < 0.8 && percent_needed < 0.5 in
23 begin if do_compact then
24 Gc.compact()
25 else
26 Gc.full_major();
27 end;
28 Gc.set old_gc;
29 ServerMessage.gc_stats (Timer.get_time() -. t0) stats do_compact new_space_overhead
30 end
31
32 class class_maintenance_task (cs : CompilationCache.t) (c : tclass) = object(self)
33 inherit server_task ["module maintenance"] 70
34
35 method private execute =
36 let rec field cf =
37 (* Unset cf_expr. This holds the optimized version for generators, which we don't need to persist. If
38 we compile again, the semi-optimized expression will be restored by calling cl_restore(). *)
39 cf.cf_expr <- None;
40 List.iter field cf.cf_overloads
41 in
42 (* What we're doing here at the moment is free, so we can just do it in one task. If this ever gets more expensive,
43 we should spawn a task per-field. *)
44 List.iter field c.cl_ordered_fields;
45 List.iter field c.cl_ordered_statics;
46 Option.may field c.cl_constructor;
47 end
48
49 class module_maintenance_task (cs : CompilationCache.t) (m : module_def) = object(self)
50 inherit server_task ["module maintenance"] 80
51
52 method private execute =
53 List.iter (fun mt -> match mt with
54 | TClassDecl c ->
55 cs#add_task (new class_maintenance_task cs c)
56 | _ ->
57 ()
58 ) m.m_types
59 end
60
61 class server_exploration_task (cs : CompilationCache.t) = object(self)
62 inherit server_task ["server explore"] 90
63
64 method private execute =
65 cs#iter_modules (fun m -> cs#add_task (new module_maintenance_task cs m))
66 end
1818 | None -> type_expr ctx (EConst (Ident "null"),p) WithType.value
1919 in
2020 ctx.with_type_stack <- List.tl ctx.with_type_stack;
21 let e = try cast_or_unify_raise ctx t e p with Error(Unify _,_) -> raise Not_found in
21 let e = try cast_or_unify_raise ctx t e p with Error(Unify _,_,_) -> raise Not_found in
2222 f();
2323 e
2424 | _ -> die "" __LOC__
3434 if cf.cf_kind = Method MethMacro then begin
3535 match cast_stack.rec_stack with
3636 | previous_from :: _ when previous_from == cf ->
37 raise (Error (Unify [cannot_unify eright.etype tleft], eright.epos));
37 (try
38 Type.unify_custom uctx eright.etype tleft;
39 with Unify_error l ->
40 raise (Error (Unify l, eright.epos,0)))
3841 | _ -> ()
3942 end;
40 if cf == ctx.curfield || rec_stack_memq cf cast_stack then error "Recursive implicit cast" p;
43 if cf == ctx.curfield || rec_stack_memq cf cast_stack then typing_error "Recursive implicit cast" p;
4144 rec_stack_loop cast_stack cf f ()
4245 in
4346 let make (a,tl,(tcf,cf)) =
8386 in
8487 loop2 a.a_to
8588 end
89 | TInst(c,tl), TFun _ when has_class_flag c CFunctionalInterface ->
90 let cf = ctx.g.functional_interface_lut#find c.cl_path in
91 unify_raise_custom uctx eright.etype (apply_params c.cl_params tl cf.cf_type) p;
92 eright
8693 | _ ->
8794 raise Not_found
8895 end
98105 try
99106 do_check_cast ctx uctx tleft eright p
100107 with Not_found ->
101 unify_raise_custom uctx ctx eright.etype tleft p;
108 unify_raise_custom uctx eright.etype tleft p;
102109 eright
103110
104111 and cast_or_unify ctx tleft eright p =
105112 try
106113 cast_or_unify_raise ctx tleft eright p
107 with Error (Unify l,p) ->
114 with Error (Unify l,p,_) ->
108115 raise_or_display ctx l p;
109116 eright
110117
111 let find_array_access_raise ctx a pl e1 e2o p =
112 let is_set = e2o <> None in
113 let ta = apply_params a.a_params pl a.a_this in
118 let prepare_array_access_field ctx a pl cf p =
119 let monos = List.map (fun _ -> spawn_monomorph ctx p) cf.cf_params in
120 let map t = apply_params a.a_params pl (apply_params cf.cf_params monos t) in
121 let check_constraints () =
122 List.iter2 (fun m tp -> match follow tp.ttp_type with
123 | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
124 List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> Type.unify m (map tc) ) constr
125 | _ -> ()
126 ) monos cf.cf_params;
127 in
128 let get_ta() =
129 let ta = apply_params a.a_params pl a.a_this in
130 if has_class_field_flag cf CfImpl then ta
131 else TAbstract(a,pl)
132 in
133 map,check_constraints,get_ta
134
135 let find_array_read_access_raise ctx a pl e1 p =
114136 let rec loop cfl =
115137 match cfl with
116138 | [] -> raise Not_found
117139 | cf :: cfl ->
118 let monos = List.map (fun _ -> spawn_monomorph ctx p) cf.cf_params in
119 let map t = apply_params a.a_params pl (apply_params cf.cf_params monos t) in
120 let check_constraints () =
121 List.iter2 (fun m (name,t) -> match follow t with
122 | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
123 List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> Type.unify m (map tc) ) constr
124 | _ -> ()
125 ) monos cf.cf_params;
126 in
127 let get_ta() =
128 if has_class_field_flag cf CfImpl then ta
129 else TAbstract(a,pl)
130 in
140 let map,check_constraints,get_ta = prepare_array_access_field ctx a pl cf p in
131141 match follow (map cf.cf_type) with
132 | TFun([(_,_,tab);(_,_,ta1);(_,_,ta2)],r) as tf when is_set ->
133 begin try
134 Type.unify tab (get_ta());
135 let e1 = cast_or_unify_raise ctx ta1 e1 p in
136 let e2o = match e2o with None -> None | Some e2 -> Some (cast_or_unify_raise ctx ta2 e2 p) in
137 check_constraints();
138 cf,tf,r,e1,e2o
139 with Unify_error _ | Error (Unify _,_) ->
140 loop cfl
141 end
142 | TFun([(_,_,tab);(_,_,ta1)],r) as tf when not is_set ->
142 | TFun((_,_,tab) :: (_,_,ta1) :: args,r) as tf when is_empty_or_pos_infos args ->
143143 begin try
144144 Type.unify tab (get_ta());
145145 let e1 = cast_or_unify_raise ctx ta1 e1 p in
146146 check_constraints();
147 cf,tf,r,e1,None
148 with Unify_error _ | Error (Unify _,_) ->
147 cf,tf,r,e1
148 with Unify_error _ | Error (Unify _,_,_) ->
149149 loop cfl
150150 end
151151 | _ -> loop cfl
152152 in
153153 loop a.a_array
154154
155 let find_array_access ctx a tl e1 e2o p =
156 try find_array_access_raise ctx a tl e1 e2o p
155 let find_array_write_access_raise ctx a pl e1 e2 p =
156 let rec loop cfl =
157 match cfl with
158 | [] -> raise Not_found
159 | cf :: cfl ->
160 let map,check_constraints,get_ta = prepare_array_access_field ctx a pl cf p in
161 match follow (map cf.cf_type) with
162 | TFun((_,_,tab) :: (_,_,ta1) :: (_,_,ta2) :: args,r) as tf when is_empty_or_pos_infos args ->
163 begin try
164 Type.unify tab (get_ta());
165 let e1 = cast_or_unify_raise ctx ta1 e1 p in
166 let e2 = cast_or_unify_raise ctx ta2 e2 p in
167 check_constraints();
168 cf,tf,r,e1,e2
169 with Unify_error _ | Error (Unify _,_,_) ->
170 loop cfl
171 end
172 | _ -> loop cfl
173 in
174 loop a.a_array
175
176 let find_array_read_access ctx a tl e1 p =
177 try
178 find_array_read_access_raise ctx a tl e1 p
157179 with Not_found ->
158180 let s_type = s_type (print_context()) in
159 match e2o with
160 | None ->
161 error (Printf.sprintf "No @:arrayAccess function for %s accepts argument of %s" (s_type (TAbstract(a,tl))) (s_type e1.etype)) p
162 | Some e2 ->
163 error (Printf.sprintf "No @:arrayAccess function for %s accepts arguments of %s and %s" (s_type (TAbstract(a,tl))) (s_type e1.etype) (s_type e2.etype)) p
181 typing_error (Printf.sprintf "No @:arrayAccess function for %s accepts argument of %s" (s_type (TAbstract(a,tl))) (s_type e1.etype)) p
182
183 let find_array_write_access ctx a tl e1 e2 p =
184 try
185 find_array_write_access_raise ctx a tl e1 e2 p
186 with Not_found ->
187 let s_type = s_type (print_context()) in
188 typing_error (Printf.sprintf "No @:arrayAccess function for %s accepts arguments of %s and %s" (s_type (TAbstract(a,tl))) (s_type e1.etype) (s_type e2.etype)) p
164189
165190 let find_multitype_specialization com a pl p =
166191 let uctx = default_unification_context in
176201 stack := t :: !stack;
177202 match follow t with
178203 | TAbstract ({ a_path = [],"Class" },_) ->
179 error (Printf.sprintf "Cannot use %s as key type to Map because Class<T> is not comparable on JavaScript" (s_type (print_context()) t1)) p;
204 typing_error (Printf.sprintf "Cannot use %s as key type to Map because Class<T> is not comparable on JavaScript" (s_type (print_context()) t1)) p;
180205 | TEnum(en,tl) ->
181206 PMap.iter (fun _ ef -> ignore(loop ef.ef_type)) en.e_constrs;
182207 Type.map loop t
193218 if List.exists (fun t -> has_mono t) definitive_types then begin
194219 let at = apply_params a.a_params pl a.a_this in
195220 let st = s_type (print_context()) at in
196 error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
221 typing_error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
197222 end;
198223 t
199224 with Not_found ->
200225 let at = apply_params a.a_params pl a.a_this in
201226 let st = s_type (print_context()) at in
202227 if has_mono at then
203 error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
228 typing_error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
204229 else
205 error ("Abstract " ^ (s_type_path a.a_path) ^ " has no @:to function that accepts " ^ st) p;
230 typing_error ("Abstract " ^ (s_type_path a.a_path) ^ " has no @:to function that accepts " ^ st) p;
206231 in
207232 cf, follow m
208233
214239 let's construct the underlying type. *)
215240 match Abstract.get_underlying_type a pl with
216241 | TInst(c,tl) as t -> {e with eexpr = TNew(c,tl,el); etype = t}
217 | _ -> error ("Cannot construct " ^ (s_type (print_context()) (TAbstract(a,pl)))) e.epos
242 | _ -> typing_error ("Cannot construct " ^ (s_type (print_context()) (TAbstract(a,pl)))) e.epos
218243 end else begin
219244 (* a TNew of an abstract implementation is only generated if it is a multi type abstract *)
220245 let cf,m = find_multitype_specialization ctx.com a pl e.epos in
226251 | TAbstract({a_impl = Some c} as a,tl) ->
227252 begin try
228253 let cf = PMap.find "toString" c.cl_statics in
229 make_static_call ctx c cf a tl [e1] ctx.t.tstring e.epos
254 let call() = make_static_call ctx c cf a tl [e1] ctx.t.tstring e.epos in
255 if not ctx.allow_transform then
256 { e1 with etype = ctx.t.tstring; epos = e.epos }
257 else if not (is_nullable e1.etype) then
258 call()
259 else begin
260 let p = e.epos in
261 let chk_null = mk (TBinop (Ast.OpEq, e1, mk (TConst TNull) e1.etype p)) ctx.com.basic.tbool p in
262 mk (TIf (chk_null, mk (TConst (TString "null")) ctx.com.basic.tstring p, Some (call()))) ctx.com.basic.tstring p
263 end
230264 with Not_found ->
231265 e
232266 end
314348 in
315349 loop ctx e
316350 ;;
317 Typecore.cast_or_unify_raise_ref := cast_or_unify_raise
351 Typecore.cast_or_unify_raise_ref := cast_or_unify_raise
1717 *)
1818 open Extlib_leftovers
1919 open Ast
20 open CompilationServer
2120 open Type
2221 open Globals
2322 open Define
2423 open NativeLibraries
24 open Warning
2525
2626 type package_rule =
2727 | Forbidden
4444 s_methods_typed : int ref;
4545 s_macros_called : int ref;
4646 }
47
48 type compiler_message =
49 | CMInfo of string * pos
50 | CMWarning of string * pos
51 | CMError of string * pos
52
53 let compiler_message_string msg =
54 let (str,p) = match msg with
55 | CMInfo(str,p) | CMError(str,p) -> (str,p)
56 | CMWarning(str,p) -> ("Warning : " ^ str, p)
57 in
58 if p = null_pos then
59 str
60 else begin
61 let error_printer file line = Printf.sprintf "%s:%d:" file line in
62 let epos = Lexer.get_error_pos error_printer p in
63 let str =
64 let lines =
65 match (ExtString.String.nsplit str "\n") with
66 | first :: rest -> first :: List.map Error.compl_msg rest
67 | l -> l
68 in
69 String.concat ("\n" ^ epos ^ " : ") lines
70 in
71 Printf.sprintf "%s : %s" epos str
72 end
7347
7448 (**
7549 The capture policy tells which handling we make of captured locals
9064 ec_native_throws : path list;
9165 (* Base types which may be caught from Haxe code without wrapping. *)
9266 ec_native_catches : path list;
67 (*
68 Hint exceptions filter to avoid wrapping for targets, which can throw/catch any type
69 Ignored on targets with a specific native base type for exceptions.
70 *)
71 ec_avoid_wrapping : bool;
9372 (* Path of a native class or interface, which can be used for wildcard catches. *)
9473 ec_wildcard_catch : path;
9574 (*
183162 pf_exceptions : exceptions_config;
184163 (** the scoping of local variables *)
185164 pf_scoping : var_scoping_config;
165 (** target supports atomic operations via haxe.Atomic **)
166 pf_supports_atomics : bool;
186167 }
187168
188169 class compiler_callbacks = object(self)
189 val mutable before_typer_create = [];
190 val mutable after_init_macros = [];
170 val before_typer_create = ref [];
171 val after_init_macros = ref [];
191172 val mutable after_typing = [];
192 val mutable before_save = [];
193 val mutable after_save = [];
194 val mutable after_filters = [];
195 val mutable after_generation = [];
173 val before_save = ref [];
174 val after_save = ref [];
175 val after_filters = ref [];
176 val after_generation = ref [];
196177 val mutable null_safety_report = [];
197178
198179 method add_before_typer_create (f : unit -> unit) : unit =
199 before_typer_create <- f :: before_typer_create
180 before_typer_create := f :: !before_typer_create
200181
201182 method add_after_init_macros (f : unit -> unit) : unit =
202 after_init_macros <- f :: after_init_macros
183 after_init_macros := f :: !after_init_macros
203184
204185 method add_after_typing (f : module_type list -> unit) : unit =
205186 after_typing <- f :: after_typing
206187
207188 method add_before_save (f : unit -> unit) : unit =
208 before_save <- f :: before_save
189 before_save := f :: !before_save
209190
210191 method add_after_save (f : unit -> unit) : unit =
211 after_save <- f :: after_save
192 after_save := f :: !after_save
212193
213194 method add_after_filters (f : unit -> unit) : unit =
214 after_filters <- f :: after_filters
195 after_filters := f :: !after_filters
215196
216197 method add_after_generation (f : unit -> unit) : unit =
217 after_generation <- f :: after_generation
198 after_generation := f :: !after_generation
218199
219200 method add_null_safety_report (f : (string*pos) list -> unit) : unit =
220201 null_safety_report <- f :: null_safety_report
202
203 method run r =
204 match !r with
205 | [] ->
206 ()
207 | l ->
208 r := [];
209 List.iter (fun f -> f()) (List.rev l);
210 self#run r
221211
222212 method get_before_typer_create = before_typer_create
223213 method get_after_init_macros = after_init_macros
242232 end
243233
244234 type shared_display_information = {
245 mutable diagnostics_messages : (string * pos * DisplayTypes.DiagnosticsKind.t * DisplayTypes.DiagnosticsSeverity.t) list;
235 mutable diagnostics_messages : (string * pos * MessageKind.t * MessageSeverity.t * int (* depth *)) list;
246236 }
247237
248238 type display_information = {
280270 | CGenerationStart (* Generation is about to begin. *)
281271 | CGenerationDone (* Generation just finished. *)
282272
273 type report_mode =
274 | RMNone
275 | RMDiagnostics of Path.UniqueKey.t list
276 | RMStatistics
277
278 class virtual ['key,'value] lookup = object(self)
279 method virtual add : 'key -> 'value -> unit
280 method virtual remove : 'key -> unit
281 method virtual find : 'key -> 'value
282 method virtual iter : ('key -> 'value -> unit) -> unit
283 method virtual fold : 'acc . ('key -> 'value -> 'acc -> 'acc) -> 'acc -> 'acc
284 method virtual mem : 'key -> bool
285 method virtual clear : unit
286 end
287
288 class ['key,'value] pmap_lookup = object(self)
289 inherit ['key,'value] lookup
290 val mutable lut : ('key,'value) PMap.t = PMap.empty
291
292 method add (key : 'key) (value : 'value) =
293 lut <- PMap.add key value lut
294
295 method remove (key : 'key) =
296 lut <- PMap.remove key lut
297
298 method find (key : 'key) : 'value =
299 PMap.find key lut
300
301 method iter (f : 'key -> 'value -> unit) =
302 PMap.iter f lut
303
304 method fold : 'acc . ('key -> 'value -> 'acc -> 'acc) -> 'acc -> 'acc = fun f acc ->
305 PMap.foldi f lut acc
306
307 method mem (key : 'key) =
308 PMap.mem key lut
309
310 method clear =
311 lut <- PMap.empty
312 end
313
314 class ['key,'value] hashtbl_lookup = object(self)
315 inherit ['key,'value] lookup
316 val lut : ('key,'value) Hashtbl.t = Hashtbl.create 0
317
318 method add (key : 'key) (value : 'value) =
319 Hashtbl.replace lut key value
320
321 method remove (key : 'key) =
322 Hashtbl.remove lut key
323
324 method find (key : 'key) : 'value =
325 Hashtbl.find lut key
326
327 method iter (f : 'key -> 'value -> unit) =
328 Hashtbl.iter f lut
329
330 method fold : 'acc . ('key -> 'value -> 'acc -> 'acc) -> 'acc -> 'acc = fun f acc ->
331 Hashtbl.fold f lut acc
332
333 method mem (key : 'key) =
334 Hashtbl.mem lut key
335
336 method clear =
337 Hashtbl.clear lut
338 end
339
283340 type context = {
341 compilation_step : int;
284342 mutable stage : compiler_stage;
285 mutable cache : context_cache option;
343 cs : CompilationCache.t;
344 mutable cache : CompilationCache.context_cache option;
345 is_macro_context : bool;
346 mutable json_out : json_api option;
286347 (* config *)
287348 version : int;
288349 args : string list;
289 shared : shared_context;
290 display_information : display_information;
291350 mutable sys_args : string list;
292351 mutable display : DisplayTypes.DisplayMode.settings;
293352 mutable debug : bool;
299358 mutable class_path : string list;
300359 mutable main_class : path option;
301360 mutable package_rules : (string,package_rule) PMap.t;
302 mutable error : string -> pos -> unit;
303 mutable info : string -> pos -> unit;
304 mutable warning : string -> pos -> unit;
361 mutable report_mode : report_mode;
362 (* communication *)
363 mutable print : string -> unit;
364 mutable error : ?depth:int -> string -> pos -> unit;
365 mutable located_error : ?depth:int -> located -> unit;
366 mutable info : ?depth:int -> string -> pos -> unit;
367 mutable warning : ?depth:int -> warning -> Warning.warning_option list list -> string -> pos -> unit;
368 mutable warning_options : Warning.warning_option list list;
305369 mutable get_messages : unit -> compiler_message list;
306370 mutable filter_messages : (compiler_message -> bool) -> unit;
371 mutable run_command : string -> int;
372 mutable run_command_args : string -> string list -> int;
373 (* typing setup *)
307374 mutable load_extern_type : (string * (path -> pos -> Ast.package option)) list; (* allow finding types which are not in sources *)
308375 callbacks : compiler_callbacks;
309376 defines : Define.define;
310 mutable print : string -> unit;
377 mutable user_defines : (string, Define.user_define) Hashtbl.t;
378 mutable user_metas : (string, Meta.user_meta) Hashtbl.t;
311379 mutable get_macros : unit -> context option;
312 mutable run_command : string -> int;
313 file_lookup_cache : (string,string option) Hashtbl.t;
380 (* typing state *)
381 shared : shared_context;
382 display_information : display_information;
383 file_lookup_cache : (string,string option) lookup;
314384 file_keys : file_keys;
315 readdir_cache : (string * string,(string array) option) Hashtbl.t;
316 parser_cache : (string,(type_def * pos) list) Hashtbl.t;
317 module_to_file : (path,string) Hashtbl.t;
318 cached_macros : (path * string,(((string * bool * t) list * t * tclass * Type.tclass_field) * module_def)) Hashtbl.t;
319 mutable stored_typed_exprs : (int, texpr) PMap.t;
385 readdir_cache : (string * string,(string array) option) lookup;
386 parser_cache : (string,(type_def * pos) list) lookup;
387 module_to_file : (path,string) lookup;
388 cached_macros : (path * string,(((string * bool * t) list * t * tclass * Type.tclass_field) * module_def)) lookup;
389 stored_typed_exprs : (int, texpr) lookup;
390 overload_cache : ((path * string),(Type.t * tclass_field) list) lookup;
391 module_lut : (path,module_def) lookup;
392 module_nonexistent_lut : (path,bool) lookup;
393 type_to_module : (path,path) lookup;
394 mutable has_error : bool;
320395 pass_debug_messages : string DynArray.t;
321 overload_cache : ((path * string),(Type.t * tclass_field) list) Hashtbl.t;
322396 (* output *)
323397 mutable file : string;
324 mutable flash_version : float;
325398 mutable features : (string,bool) Hashtbl.t;
326399 mutable modules : Type.module_def list;
327400 mutable main : Type.texpr option;
328401 mutable types : Type.module_type list;
329402 mutable resources : (string,string) Hashtbl.t;
330 mutable neko_libs : string list;
403 (* target-specific *)
404 mutable flash_version : float;
405 mutable neko_lib_paths : string list;
331406 mutable include_files : (string * string) list;
332407 mutable native_libs : native_libraries;
333408 mutable net_std : string list;
334409 net_path_map : (path,string list * string list * string) Hashtbl.t;
335410 mutable c_args : string list;
336411 mutable js_gen : (unit -> unit) option;
337 mutable json_out : json_api option;
338 (* typing *)
412 (* misc *)
339413 mutable basic : basic_types;
340414 memory_marker : float array;
341415 }
342416
343 exception Abort of string * pos
417 exception Abort of located
418
419 let ignore_error com =
420 let b = com.display.dms_error_policy = EPIgnore in
421 if b then
422 if b then com.has_error <- true;
423 b
344424
345425 (* Defines *)
346426
369449 let define_value com k v =
370450 Define.define_value com.defines k v
371451
372 let raw_defined_value com k =
373 Define.raw_defined_value com.defines k
452 let convert_define k =
453 String.concat "_" (ExtString.String.nsplit k "-")
454
455 let external_defined ctx k =
456 Define.raw_defined ctx.defines (convert_define k)
457
458 let external_defined_value ctx k =
459 Define.raw_defined_value ctx.defines (convert_define k)
460
461 let reserved_flags = [
462 "true";"false";"null";"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python";
463 "swc";"macro";"sys";"static";"utf16";"haxe";"haxe_ver"
464 ]
465
466 let reserved_flag_namespaces = ["target"]
467
468 let convert_and_validate k =
469 let converted_flag = convert_define k in
470 let raise_reserved description =
471 raise (Arg.Bad (description ^ " and cannot be defined from the command line"))
472 in
473 if List.mem converted_flag reserved_flags then
474 raise_reserved (Printf.sprintf "`%s` is a reserved compiler flag" k);
475 List.iter (fun ns ->
476 if ExtString.String.starts_with converted_flag (ns ^ ".") then
477 raise_reserved (Printf.sprintf "`%s` uses the reserved compiler flag namespace `%s.*`" k ns)
478 ) reserved_flag_namespaces;
479 converted_flag
480
481 let external_define_value ctx k v =
482 raw_define_value ctx.defines (convert_and_validate k) v
483
484 (* TODO: Temporary function until #8690, remove after *)
485 let external_define_value_no_check ctx k v =
486 Define.raw_define_value ctx.defines (convert_define k) v
487
488 let external_define ctx k =
489 Define.raw_define ctx.defines (convert_and_validate k)
490
491 (* TODO: Temporary function until #8690, remove after *)
492 let external_define_no_check ctx k =
493 Define.raw_define ctx.defines (convert_define k)
494
495 let defines_for_external ctx =
496 PMap.foldi (fun k v acc ->
497 let added_underscore = PMap.add k v acc in
498 match ExtString.String.nsplit k "_" with
499 | [_] -> added_underscore
500 | split -> PMap.add (String.concat "-" split) v added_underscore;
501 ) ctx.defines.values PMap.empty
374502
375503 let get_es_version com =
376504 try int_of_string (defined_value com Define.JsEs) with _ -> 0
418546 ec_native_catches = [];
419547 ec_wildcard_catch = (["StdTypes"],"Dynamic");
420548 ec_base_throw = (["StdTypes"],"Dynamic");
549 ec_avoid_wrapping = true;
421550 ec_special_throw = fun _ -> false;
422551 };
423552 pf_scoping = {
424553 vs_scope = BlockScope;
425554 vs_flags = [];
426 }
555 };
556 pf_supports_atomics = false;
427557 }
428558
429559 let get_config com =
430 let defined f = PMap.mem (fst (Define.infos f)) com.defines.values in
560 let defined f = PMap.mem (Define.get_define_key f) com.defines.values in
431561 match com.platform with
432562 | Cross ->
433563 default_config
446576 ["js";"lib"],"Error";
447577 ["haxe"],"Exception";
448578 ];
579 ec_avoid_wrapping = false;
449580 };
450581 pf_scoping = {
451582 vs_scope = if es6 then BlockScope else FunctionScope;
452583 vs_flags =
453584 (if defined Define.JsUnflatten then ReserveAllTopLevelSymbols else ReserveAllTypesFlat)
454585 :: if es6 then [NoShadowing; SwitchCasesNoBlocks;] else [VarHoisting; NoCatchVarShadowing];
455 }
586 };
587 pf_supports_atomics = true;
456588 }
457589 | Lua ->
458590 {
461593 pf_capture_policy = CPLoopVars;
462594 pf_uses_utf16 = false;
463595 pf_supports_rest_args = true;
596 pf_exceptions = { default_config.pf_exceptions with
597 ec_avoid_wrapping = false;
598 }
464599 }
465600 | Neko ->
466601 {
491626 ["flash";"errors"],"Error";
492627 ["haxe"],"Exception";
493628 ];
629 ec_avoid_wrapping = false;
494630 };
495631 pf_scoping = {
496632 vs_scope = FunctionScope;
529665 pf_supports_threads = true;
530666 pf_supports_unicode = (defined Define.Cppia) || not (defined Define.DisableUnicodeStrings);
531667 pf_scoping = { default_config.pf_scoping with
532 vs_flags = [NoShadowing]
533 }
668 vs_flags = [NoShadowing];
669 vs_scope = FunctionScope;
670 };
671 pf_supports_atomics = true;
534672 }
535673 | Cs ->
536674 {
541679 pf_supports_threads = true;
542680 pf_supports_rest_args = true;
543681 pf_this_before_super = false;
544 pf_exceptions = {
682 pf_exceptions = { default_config.pf_exceptions with
545683 ec_native_throws = [
546684 ["cs";"system"],"Exception";
547685 ["haxe"],"Exception";
558696 vs_scope = FunctionScope;
559697 vs_flags = [NoShadowing]
560698 };
699 pf_supports_atomics = true;
561700 }
562701 | Java ->
563702 {
587726 {
588727 vs_scope = FunctionScope;
589728 vs_flags = [NoShadowing; ReserveAllTopLevelSymbols; ReserveNames(["_"])];
590 }
729 };
730 pf_supports_atomics = true;
591731 }
592732 | Python ->
593733 {
618758 pf_capture_policy = CPWrapRef;
619759 pf_pad_nulls = true;
620760 pf_supports_threads = true;
621 pf_exceptions = { default_config.pf_exceptions with
622 ec_native_throws = [
623 ["haxe"],"Exception";
624 ];
625 ec_native_catches = [
626 ["haxe"],"Exception";
627 ];
628 }
761 pf_supports_atomics = true;
629762 }
630763 | Eval ->
631764 {
639772
640773 let memory_marker = [|Unix.time()|]
641774
642 let create version s_version args =
775 let create compilation_step cs version args =
643776 let m = Type.mk_mono() in
644 let defines =
645 PMap.add "true" "1" (
646 PMap.add "source_header" ("Generated by Haxe " ^ s_version) PMap.empty
647 )
648 in
649 {
777 let rec com = {
778 compilation_step = compilation_step;
779 cs = cs;
650780 cache = None;
651781 stage = CCreated;
652782 version = version;
671801 config = default_config;
672802 print = (fun s -> print_string s; flush stdout);
673803 run_command = Sys.command;
804 run_command_args = (fun s args -> com.run_command (Printf.sprintf "%s %s" s (String.concat " " args)));
674805 std_path = [];
675806 class_path = [];
676807 main_class = None;
679810 types = [];
680811 callbacks = new compiler_callbacks;
681812 modules = [];
813 module_lut = new hashtbl_lookup;
814 module_nonexistent_lut = new hashtbl_lookup;
815 type_to_module = new hashtbl_lookup;
682816 main = None;
683817 flash_version = 10.;
684818 resources = Hashtbl.create 0;
686820 native_libs = create_native_libs();
687821 net_path_map = Hashtbl.create 0;
688822 c_args = [];
689 neko_libs = [];
823 neko_lib_paths = [];
690824 include_files = [];
691825 js_gen = None;
692826 load_extern_type = [];
693827 defines = {
694828 defines_signature = None;
695 values = defines;
829 values = PMap.empty;
696830 };
831 user_defines = Hashtbl.create 0;
832 user_metas = Hashtbl.create 0;
697833 get_macros = (fun() -> None);
698 info = (fun _ _ -> die "" __LOC__);
699 warning = (fun _ _ -> die "" __LOC__);
700 error = (fun _ _ -> die "" __LOC__);
834 info = (fun ?depth _ _ -> die "" __LOC__);
835 warning = (fun ?depth _ _ _ -> die "" __LOC__);
836 warning_options = [];
837 error = (fun ?depth _ _ -> die "" __LOC__);
838 located_error = (fun ?depth _ -> die "" __LOC__);
701839 get_messages = (fun() -> []);
702840 filter_messages = (fun _ -> ());
703841 pass_debug_messages = DynArray.create();
704 overload_cache = Hashtbl.create 0;
705842 basic = {
706843 tvoid = m;
707844 tint = m;
708845 tfloat = m;
709846 tbool = m;
710 tnull = (fun _ -> die "" __LOC__);
847 tnull = (fun _ -> die "Could use locate abstract Null<T> (was it redefined?)" __LOC__);
711848 tstring = m;
712 tarray = (fun _ -> die "" __LOC__);
849 tarray = (fun _ -> die "Could not locate class Array<T> (was it redefined?)" __LOC__);
713850 };
714 file_lookup_cache = Hashtbl.create 0;
851 file_lookup_cache = new hashtbl_lookup;
715852 file_keys = new file_keys;
716 readdir_cache = Hashtbl.create 0;
717 module_to_file = Hashtbl.create 0;
718 stored_typed_exprs = PMap.empty;
719 cached_macros = Hashtbl.create 0;
853 readdir_cache = new hashtbl_lookup;
854 module_to_file = new hashtbl_lookup;
855 stored_typed_exprs = new hashtbl_lookup;
856 cached_macros = new hashtbl_lookup;
720857 memory_marker = memory_marker;
721 parser_cache = Hashtbl.create 0;
858 parser_cache = new hashtbl_lookup;
859 overload_cache = new hashtbl_lookup;
722860 json_out = None;
723 }
861 has_error = false;
862 report_mode = RMNone;
863 is_macro_context = false;
864 } in
865 com
866
867 let is_diagnostics com = match com.report_mode with
868 | RMDiagnostics _ -> true
869 | _ -> false
870
871 let disable_report_mode com =
872 let old = com.report_mode in
873 com.report_mode <- RMNone;
874 (fun () -> com.report_mode <- old)
724875
725876 let log com str =
726877 if com.verbose then com.print (str ^ "\n")
727878
728 let clone com =
879 let clone com is_macro_context =
729880 let t = com.basic in
730881 { com with
731882 cache = None;
732883 basic = { t with tvoid = t.tvoid };
733884 main_class = None;
734885 features = Hashtbl.create 0;
735 file_lookup_cache = Hashtbl.create 0;
736 readdir_cache = Hashtbl.create 0;
737 parser_cache = Hashtbl.create 0;
738 module_to_file = Hashtbl.create 0;
739886 callbacks = new compiler_callbacks;
740887 display_information = {
741888 unresolved_identifiers = [];
747894 defines_signature = com.defines.defines_signature;
748895 };
749896 native_libs = create_native_libs();
750 overload_cache = Hashtbl.create 0;
897 is_macro_context = is_macro_context;
898 file_lookup_cache = new hashtbl_lookup;
899 readdir_cache = new hashtbl_lookup;
900 parser_cache = new hashtbl_lookup;
901 module_to_file = new hashtbl_lookup;
902 overload_cache = new hashtbl_lookup;
903 module_lut = new hashtbl_lookup;
904 type_to_module = new hashtbl_lookup;
751905 }
752906
753907 let file_time file = Extc.filetime file
754
755 let file_extension file =
756 match List.rev (ExtString.String.nsplit file ".") with
757 | e :: _ -> String.lowercase e
758 | [] -> ""
759908
760909 let flash_versions = List.map (fun v ->
761910 let maj = int_of_float v in
791940 com.package_rules <- List.fold_left forbid com.package_rules ("jvm" :: (List.map platform_name platforms));
792941 com.config <- get_config com;
793942 if com.config.pf_static then begin
794 raw_define_value com.defines "target.static" "true";
943 raw_define com "target.static";
795944 define com Define.Static;
796945 end;
797946 if com.config.pf_sys then begin
798 raw_define_value com.defines "target.sys" "true";
947 raw_define com "target.sys";
799948 define com Define.Sys
800949 end else
801950 com.package_rules <- PMap.add "sys" Forbidden com.package_rules;
802951 if com.config.pf_uses_utf16 then begin
803 raw_define_value com.defines "target.utf16" "true";
952 raw_define com "target.utf16";
804953 define com Define.Utf16;
805954 end;
806955 if com.config.pf_supports_threads then begin
807 raw_define_value com.defines "target.threaded" "true";
956 raw_define com "target.threaded";
808957 end;
809958 if com.config.pf_supports_unicode then begin
810 raw_define_value com.defines "target.unicode" "true";
959 raw_define com "target.unicode";
811960 end;
812961 raw_define_value com.defines "target.name" name;
813 raw_define com name
962 raw_define com name;
963 if com.config.pf_supports_atomics then begin
964 raw_define com "target.atomics"
965 end
966
967 let set_platform com pf file =
968 if com.platform <> Cross then failwith "Multiple targets";
969 init_platform com pf;
970 com.file <- file;
971 if (pf = Flash) && Path.file_extension file = "swc" then define com Define.Swc;
972 (* Set the source header, unless the user has set one already or the platform sets a custom one *)
973 if not (defined com Define.SourceHeader) && (pf <> Hl) then
974 define_value com Define.SourceHeader ("Generated by Haxe " ^ s_version_full)
814975
815976 let add_feature com f =
816977 Hashtbl.replace com.features f true
8621023 with Not_found ->
8631024 ()
8641025
865 let abort msg p = raise (Abort (msg,p))
1026 let abort_located ?depth msg = raise (Abort msg)
1027 let abort ?depth msg p = abort_located ~depth (located msg p)
8661028
8671029 let platform ctx p = ctx.platform = p
8681030
8691031 let platform_name_macro com =
8701032 if defined com Define.Macro then "macro" else platform_name com.platform
1033
1034 let remove_extension file =
1035 try String.sub file 0 (String.rindex file '.')
1036 with Not_found -> file
1037
1038 let extension file =
1039 try
1040 let dot_pos = String.rindex file '.' in
1041 String.sub file dot_pos (String.length file - dot_pos)
1042 with Not_found -> file
8711043
8721044 let cache_directory ctx class_path dir f_dir =
8731045 let platform_ext = "." ^ (platform_name_macro ctx)
8741046 and is_loading_core_api = defined ctx Define.CoreApi in
875 let remove_extension file =
876 try String.sub file 0 (String.rindex file '.')
877 with Not_found -> file
878 in
879 let extension file =
880 try
881 let dot_pos = String.rindex file '.' in
882 String.sub file dot_pos (String.length file - dot_pos)
883 with Not_found -> file
884 in
8851047 let dir_listing =
8861048 try Some (Sys.readdir dir);
8871049 with Sys_error _ -> None
8881050 in
889 Hashtbl.add ctx.readdir_cache (class_path,dir) dir_listing;
1051 ctx.readdir_cache#add (class_path,dir) dir_listing;
8901052 (*
8911053 This function is invoked for each file in the `dir`.
8921054 Each file is checked if it's specific for current platform
9201082 - or this is a platform-specific file for `representation`
9211083 - this `representation` was never found before
9221084 *)
923 if is_loading_core_api || is_platform_specific || not (Hashtbl.mem ctx.file_lookup_cache representation) then begin
1085 if is_loading_core_api || is_platform_specific || not (ctx.file_lookup_cache#mem representation) then begin
9241086 let full_path = if dir = "." then file_own_name else dir ^ "/" ^ file_own_name in
925 Hashtbl.replace ctx.file_lookup_cache representation (Some full_path);
1087 ctx.file_lookup_cache#add representation (Some full_path);
9261088 end
9271089 in
9281090 Option.may (Array.iter prepare_file) dir_listing
9291091
9301092 let find_file ctx f =
9311093 try
932 match Hashtbl.find ctx.file_lookup_cache f with
1094 match ctx.file_lookup_cache#find f with
9331095 | None -> raise Exit
9341096 | Some f -> f
9351097 with
9361098 | Exit ->
9371099 raise Not_found
9381100 | Not_found when Path.is_absolute_path f ->
939 Hashtbl.add ctx.file_lookup_cache f (Some f);
1101 ctx.file_lookup_cache#add f (Some f);
9401102 f
9411103 | Not_found ->
9421104 let f_dir = Filename.dirname f in
9481110 let dir = Filename.dirname file in
9491111 (* If we have seen the directory before, we can assume that the file isn't in there because the else case
9501112 below would have added it to `file_lookup_cache`, which we check before we get here. *)
951 if Hashtbl.mem ctx.readdir_cache (p,dir) then
1113 if ctx.readdir_cache#mem (p,dir) then
9521114 loop (had_empty || p = "") l
9531115 else begin
9541116 cache_directory ctx p dir f_dir;
9551117 (* Caching might have located the file we're looking for, so check the lookup cache again. *)
9561118 try
957 begin match Hashtbl.find ctx.file_lookup_cache f with
1119 begin match ctx.file_lookup_cache#find f with
9581120 | Some f -> f
9591121 | None -> raise Not_found
9601122 end
9631125 end
9641126 in
9651127 let r = try Some (loop false ctx.class_path) with Not_found -> None in
966 Hashtbl.add ctx.file_lookup_cache f r;
1128 ctx.file_lookup_cache#add f r;
9671129 match r with
9681130 | None -> raise Not_found
9691131 | Some f -> f
10661228 loop 0;
10671229 Buffer.contents b
10681230
1069 let add_diagnostics_message com s p kind sev =
1231 let add_diagnostics_message ?(depth = 0) com msg kind sev =
1232 if sev = MessageSeverity.Error then com.has_error <- true;
10701233 let di = com.shared.shared_display_information in
1071 di.diagnostics_messages <- (s,p,kind,sev) :: di.diagnostics_messages
1234 match (extract_located msg) with
1235 | [] -> ()
1236 | (s,p) :: [] ->
1237 di.diagnostics_messages <- (s,p,kind,sev,depth) :: di.diagnostics_messages
1238 | (s,p) :: stack ->
1239 let stack_diag = (List.map (fun (s,p) -> (s,p,kind,sev,depth+1)) (List.rev stack)) in
1240 di.diagnostics_messages <- stack_diag @ ((s,p,kind,sev,depth) :: di.diagnostics_messages)
1241
1242 let located_display_error com ?(depth = 0) msg =
1243 if is_diagnostics com then
1244 add_diagnostics_message ~depth com msg MessageKind.DKCompilerMessage MessageSeverity.Error
1245 else
1246 com.located_error msg ~depth
1247
1248 let display_error com ?(depth = 0) msg p =
1249 located_display_error com ~depth (Globals.located msg p)
10721250
10731251 open Printer
1074
1075 let dump_context com = s_record_fields "" [
1076 "version",string_of_int com.version;
1077 "args",s_list ", " (fun s -> s) com.args;
1078 "debug",string_of_bool com.debug;
1079 "platform",platform_name com.platform;
1080 "std_path",s_list ", " (fun s -> s) com.std_path;
1081 "class_path",s_list ", " (fun s -> s) com.class_path;
1082 "defines",s_pmap (fun s -> s) (fun s -> s) com.defines.values;
1083 "defines_signature",s_opt (fun s -> Digest.to_hex s) com.defines.defines_signature;
1084 ]
10851252
10861253 let dump_path com =
10871254 Define.defined_value_safe ~default:"dump" com.defines Define.DumpPath
10881255
10891256 let adapt_defines_to_macro_context defines =
1090 let values = ref defines.values in
1091 List.iter (fun p -> values := PMap.remove (Globals.platform_name p) !values) Globals.platforms;
1092 let to_remove = List.map (fun d -> fst (Define.infos d)) [Define.NoTraces] in
1093 let to_remove = to_remove @ List.map (fun (_,d) -> "flash" ^ d) flash_versions in
1094 values := PMap.foldi (fun k v acc -> if List.mem k to_remove then acc else PMap.add k v acc) !values PMap.empty;
1095 values := PMap.add "macro" "1" !values;
1096 values := PMap.add (platform_name !Globals.macro_platform) "1" !values;
1097 {values = !values; defines_signature = None }
1257 let to_remove = List.map Globals.platform_name Globals.platforms in
1258 let to_remove = List.fold_left (fun acc d -> Define.get_define_key d :: acc) to_remove [Define.NoTraces] in
1259 let to_remove = List.fold_left (fun acc (_, d) -> ("flash" ^ d) :: acc) to_remove flash_versions in
1260 let macro_defines = {
1261 values = PMap.foldi (fun k v acc ->
1262 if List.mem k to_remove then acc else PMap.add k v acc) defines.values PMap.empty;
1263 defines_signature = None
1264 } in
1265 Define.define macro_defines Define.Macro;
1266 Define.raw_define macro_defines (platform_name !Globals.macro_platform);
1267 macro_defines
1268
1269 let adapt_defines_to_display_context defines =
1270 let defines = adapt_defines_to_macro_context defines in
1271 Define.define defines Define.Display;
1272 defines
10981273
10991274 let is_legacy_completion com = match com.json_out with
11001275 | None -> true
00 open Globals
11 open Common
2 open CompilationServer
32 open Type
3
4 class lib_build_task cs file ftime lib = object(self)
5 inherit CompilationCache.server_task ["build_lib";lib#get_name] 60
6
7 method private execute =
8 (* Created lookup and eagerly read each known type. *)
9 lib#load;
10 let h = Hashtbl.create 0 in
11 List.iter (fun path ->
12 if not (Hashtbl.mem h path) then begin
13 let p = { pfile = file ^ " @ " ^ Globals.s_type_path path; pmin = 0; pmax = 0; } in
14 try begin match lib#build path p with
15 | Some r -> Hashtbl.add h path r
16 | None -> ()
17 end with _ ->
18 ()
19 end
20 ) lib#list_modules;
21 lib#close;
22 (* Save and set up lookup. *)
23 cs#add_native_lib file h ftime;
24 end
425
526 let handle_native_lib com lib =
627 com.native_libs.all_libs <- lib#get_file_path :: com.native_libs.all_libs;
728 com.load_extern_type <- com.load_extern_type @ [lib#get_file_path,lib#build];
8 match get() with
9 | Some cs when not (Define.raw_defined com.defines "haxe.noNativeLibsCache") ->
29 if not (Define.raw_defined com.defines "haxe.noNativeLibsCache") then begin
30 let cs = com.cs in
1031 let init () =
1132 let file = lib#get_file_path in
12 let key = file in
1333 let ftime = file_time file in
14 begin match cs#get_native_lib key with
34 begin match cs#get_native_lib file with
1535 | Some lib when ftime <= lib.c_nl_mtime ->
1636 (* Cached lib is good, set up lookup into cached files. *)
17 lib.c_nl_files;
37 Some lib.c_nl_files;
1838 | _ ->
19 (* Cached lib is outdated or doesn't exist yet, read library. *)
20 lib#load;
21 (* Created lookup and eagerly read each known type. *)
22 let h = Hashtbl.create 0 in
23 List.iter (fun path ->
24 if not (Hashtbl.mem h path) then begin
25 let p = { pfile = file ^ " @ " ^ Globals.s_type_path path; pmin = 0; pmax = 0; } in
26 try begin match lib#build path p with
27 | Some r -> Hashtbl.add h path r
28 | None -> ()
29 end with _ ->
30 ()
31 end
32 ) lib#list_modules;
33 (* Save and set up lookup. *)
34 cs#add_native_lib key h ftime;
35 h;
39 (* Cached lib is outdated or doesn't exist yet, register build task. *)
40 cs#add_task (new lib_build_task cs file ftime lib);
41 None
3642 end;
3743 in
3844 (fun () ->
3945 let lut = init() in
40 let build path p =
41 try Some (Hashtbl.find lut path)
42 with Not_found -> None
43 in
44 com.load_extern_type <- List.map (fun (name,f) ->
45 name,if name = lib#get_file_path then build else f
46 ) com.load_extern_type
46 match lut with
47 | Some lut ->
48 let build path p =
49 try Some (Hashtbl.find lut path)
50 with Not_found -> None
51 in
52 com.load_extern_type <- List.map (fun (name,f) ->
53 name,if name = lib#get_file_path then build else f
54 ) com.load_extern_type
55 | None ->
56 lib#load
4757 )
48 | _ ->
58 end else
4959 (* Offline mode, just read library as usual. *)
5060 (fun () -> lib#load)
5161
5262 (* context *)
5363
54 let get_cache cs com = match com.Common.cache with
64 let get_cache com = match com.Common.cache with
5565 | None ->
5666 let sign = Define.get_signature com.defines in
57 cs#get_context sign
67 com.cs#get_context sign
5868 | Some cache ->
5969 cache
6070
6171 let rec cache_context cs com =
62 let cc = get_cache cs com in
72 let cc = get_cache com in
6373 let sign = Define.get_signature com.defines in
6474 let cache_module m =
6575 (* If we have a signature mismatch, look-up cache for module. Physical equality check is fine as a heueristic. *)
7585 let sign = Define.get_signature com.defines in
7686 ignore(cs#add_info sign desc com.platform com.class_path com.defines)
7787
78 let lock_signature com name = match CompilationServer.get() with
79 | Some cs ->
80 maybe_add_context_sign cs com name;
81 com.cache <- Some (get_cache cs com)
82 | None ->
83 ()
88 let lock_signature com name =
89 let cs = com.cs in
90 maybe_add_context_sign cs com name;
91 com.cache <- Some (get_cache com)
+0
-282
src/context/compilationServer.ml less more
0 open Globals
1 open Ast
2 open Json
3 open Type
4 open Define
5
6 type cached_file = {
7 c_file_path : string;
8 c_time : float;
9 c_package : string list;
10 c_decls : type_decl list;
11 mutable c_module_name : string option;
12 mutable c_pdi : Parser.parser_display_information;
13 }
14
15 type cached_directory = {
16 c_path : string;
17 mutable c_mtime : float;
18 }
19
20 type cached_native_lib = {
21 c_nl_mtime : float;
22 c_nl_files : (path,Ast.package) Hashtbl.t;
23 }
24
25 class context_cache (index : int) = object(self)
26 val files : (Path.UniqueKey.t,cached_file) Hashtbl.t = Hashtbl.create 0
27 val modules : (path,module_def) Hashtbl.t = Hashtbl.create 0
28 val removed_files = Hashtbl.create 0
29 val mutable json = JNull
30 val mutable initialized = false
31
32 (* files *)
33
34 method find_file key =
35 Hashtbl.find files key
36
37 method cache_file key path time data pdi =
38 Hashtbl.replace files key { c_file_path = path; c_time = time; c_package = fst data; c_decls = snd data; c_module_name = None; c_pdi = pdi }
39
40 method remove_file key =
41 try
42 let f = Hashtbl.find files key in
43 Hashtbl.remove files key;
44 Hashtbl.replace removed_files key f.c_file_path
45 with Not_found -> ()
46
47 (* Like remove_file, but doesn't keep track of the file *)
48 method remove_file_for_real key =
49 Hashtbl.remove files key
50
51 (* modules *)
52
53 method find_module path =
54 Hashtbl.find modules path
55
56 method cache_module path value =
57 Hashtbl.replace modules path value
58
59 (* initialization *)
60
61 method is_initialized = initialized
62 method set_initialized value = initialized <- value
63
64 method get_index = index
65 method get_files = files
66 method get_modules = modules
67 method get_removed_files = removed_files
68
69 method get_json = json
70 method set_json j = json <- j
71
72 (* Pointers for memory inspection. *)
73 method get_pointers : unit array =
74 [|Obj.magic files;Obj.magic modules|]
75 end
76
77 let create_directory path mtime = {
78 c_path = path;
79 c_mtime = mtime;
80 }
81
82 class virtual server_task (id : string list) (priority : int) = object(self)
83 method private virtual execute : unit
84
85 method run : unit =
86 let t = Timer.timer ("server" :: "task" :: id) in
87 Std.finally t (fun () -> self#execute) ()
88
89 method get_priority = priority
90 method get_id = id
91 end
92
93 class cache = object(self)
94 val contexts : (string,context_cache) Hashtbl.t = Hashtbl.create 0
95 val mutable context_list = []
96 val haxelib : (string list, string list) Hashtbl.t = Hashtbl.create 0
97 val directories : (string, cached_directory list) Hashtbl.t = Hashtbl.create 0
98 val native_libs : (string,cached_native_lib) Hashtbl.t = Hashtbl.create 0
99 val mutable tasks : (server_task PriorityQueue.t) = PriorityQueue.Empty
100
101 (* contexts *)
102
103 method get_context sign =
104 try
105 Hashtbl.find contexts sign
106 with Not_found ->
107 let cache = new context_cache (Hashtbl.length contexts) in
108 context_list <- cache :: context_list;
109 Hashtbl.add contexts sign cache;
110 cache
111
112 method add_info sign desc platform class_path defines =
113 let cc = self#get_context sign in
114 let jo = JObject [
115 "index",JInt cc#get_index;
116 "desc",JString desc;
117 "platform",JString (platform_name platform);
118 "classPaths",JArray (List.map (fun s -> JString s) class_path);
119 "signature",JString (Digest.to_hex sign);
120 "defines",JArray (PMap.foldi (fun k v acc -> JObject [
121 "key",JString k;
122 "value",JString v;
123 ] :: acc) defines.values []);
124 ] in
125 cc#set_json jo;
126 cc#get_index
127
128 method get_contexts = context_list
129
130 (* files *)
131
132 method remove_files file =
133 Hashtbl.iter (fun _ cc-> cc#remove_file file) contexts
134
135 method get_context_files signs =
136 Hashtbl.fold (fun sign cc acc ->
137 if List.mem sign signs then Hashtbl.fold (fun file cfile acc -> (file,cfile) :: acc) cc#get_files acc
138 else acc
139 ) contexts []
140
141 method get_files =
142 Hashtbl.fold (fun sign cc acc ->
143 Hashtbl.fold (fun file cfile acc -> (sign,file,cfile) :: acc) cc#get_files acc
144 ) contexts []
145
146 (* modules *)
147
148 method iter_modules f =
149 Hashtbl.iter (fun _ cc ->
150 Hashtbl.iter (fun _ m ->
151 f m
152 ) cc#get_modules
153 ) contexts
154
155 method get_modules =
156 Hashtbl.fold (fun _ cc acc ->
157 Hashtbl.fold (fun _ m acc ->
158 m :: acc
159 ) cc#get_modules acc
160 ) contexts []
161
162 method taint_modules file_key =
163 Hashtbl.iter (fun _ cc ->
164 Hashtbl.iter (fun _ m ->
165 if Path.UniqueKey.lazy_key m.m_extra.m_file = file_key then m.m_extra.m_dirty <- Some m.m_path
166 ) cc#get_modules
167 ) contexts
168
169 (* haxelibs *)
170
171 method find_haxelib key =
172 Hashtbl.find haxelib key
173
174 method cache_haxelib key value =
175 Hashtbl.replace haxelib key value
176
177 (* directories *)
178
179 method find_directories key =
180 Hashtbl.find directories key
181
182 method add_directories key value =
183 Hashtbl.replace directories key value
184
185 method remove_directory key value =
186 try
187 let current = self#find_directories key in
188 Hashtbl.replace directories key (List.filter (fun dir -> dir.c_path <> value) current);
189 with Not_found ->
190 ()
191
192 method has_directory key value =
193 try
194 List.exists (fun dir -> dir.c_path = value) (self#find_directories key)
195 with Not_found ->
196 false
197
198 method add_directory key value =
199 try
200 let current = self#find_directories key in
201 self#add_directories key (value :: current)
202 with Not_found ->
203 self#add_directories key [value]
204
205 method clear_directories key =
206 Hashtbl.remove directories key
207
208 (* native lib *)
209
210 method add_native_lib key files timestamp =
211 Hashtbl.replace native_libs key { c_nl_files = files; c_nl_mtime = timestamp }
212
213 method get_native_lib key =
214 try Some (Hashtbl.find native_libs key)
215 with Not_found -> None
216
217 (* tasks *)
218
219 method add_task (task : server_task) : unit =
220 tasks <- PriorityQueue.insert tasks task#get_priority task
221
222 method has_task =
223 not (PriorityQueue.is_empty tasks)
224
225 method get_task =
226 let (_,task,queue) = PriorityQueue.extract tasks in
227 tasks <- queue;
228 task
229
230 method run_tasks recursive f =
231 let rec loop acc =
232 let current = tasks in
233 tasks <- Empty;
234 let f (ran_task,acc) prio task =
235 if f task then begin
236 task#run;
237 (true,acc)
238 end else
239 ran_task,PriorityQueue.insert acc prio task
240 in
241 let ran_task,folded = PriorityQueue.fold current f (false,acc) in
242 if recursive && ran_task then loop folded
243 else folded
244 in
245 tasks <- PriorityQueue.merge tasks (loop PriorityQueue.Empty);
246
247 (* Pointers for memory inspection. *)
248 method get_pointers : unit array =
249 [|Obj.magic contexts;Obj.magic haxelib;Obj.magic directories;Obj.magic native_libs|]
250
251 end
252
253 type t = cache
254
255 type context_options =
256 | NormalContext
257 | MacroContext
258 | NormalAndMacroContext
259
260 let instance : t option ref = ref None
261
262 let create () =
263 let cs = new cache in
264 instance := Some cs;
265 cs
266
267 let get () =
268 !instance
269
270 let runs () =
271 !instance <> None
272
273 let force () = match !instance with None -> die "" __LOC__ | Some i -> i
274
275 let get_module_name_of_cfile file cfile = match cfile.c_module_name with
276 | None ->
277 let name = Path.module_name_of_file file in
278 cfile.c_module_name <- Some name;
279 name
280 | Some name ->
281 name
33 open Ast
44
55 let curclass = ref null_class
6 let curfield = ref null_field
67
78 let warned_positions = Hashtbl.create 0
89
1011 let pkey p = (p.pfile,p.pmin) in
1112 if not (Hashtbl.mem warned_positions (pkey p_usage)) then begin
1213 Hashtbl.add warned_positions (pkey p_usage) (s,p_usage);
13 match com.display.dms_kind with
14 | DMDiagnostics _ -> ()
15 | _ -> com.warning s p_usage;
14 if not (is_diagnostics com) then begin
15 let options = Warning.from_meta (!curclass.cl_meta @ !curfield.cf_meta) in
16 com.warning WDeprecated options s p_usage;
17 end
1618 end
1719
1820 let print_deprecation_message com meta s p_usage =
8082 in
8183 expr e
8284
83 let run_on_field com cf = match cf.cf_expr with None -> () | Some e -> run_on_expr com e
85 let run_on_field com cf =
86 match cf.cf_expr with
87 | None ->
88 ()
89 | Some e ->
90 curfield := cf;
91 run_on_expr com e;
92 curfield := null_field
8493
8594 let run com =
8695 List.iter (fun t -> match t with
1010 let add_removable_code ctx s p prange =
1111 ctx.removable_code <- (s,p,prange) :: ctx.removable_code
1212
13 let is_diagnostics_run com p = DiagnosticsPrinter.is_diagnostics_file (com.file_keys#get p.pfile)
13 let error_in_diagnostics_run com p =
14 let b = DiagnosticsPrinter.is_diagnostics_file com (com.file_keys#get p.pfile) in
15 if b then com.has_error <- true;
16 b
1417
1518 let find_unused_variables com e =
1619 let vars = Hashtbl.create 0 in
3942 let check_other_things com e =
4043 let had_effect = ref false in
4144 let no_effect p =
42 add_diagnostics_message com "This code has no effect" p DKCompilerError DiagnosticsSeverity.Warning;
45 add_diagnostics_message com (located "This code has no effect" p) DKCompilerMessage Warning;
4346 in
4447 let pointless_compound s p =
45 add_diagnostics_message com (Printf.sprintf "This %s has no effect, but some of its sub-expressions do" s) p DKCompilerError DiagnosticsSeverity.Warning;
48 add_diagnostics_message com (located (Printf.sprintf "This %s has no effect, but some of its sub-expressions do" s) p) DKCompilerMessage Warning;
4649 in
4750 let rec compound s el p =
4851 let old = !had_effect in
9699 check_other_things com e;
97100 DeprecationCheck.run_on_expr ~force:true com e
98101
99 let prepare com =
100 let dctx = {
101 removable_code = [];
102 import_positions = PMap.empty;
103 dead_blocks = Hashtbl.create 0;
104 diagnostics_messages = [];
105 unresolved_identifiers = [];
106 missing_fields = PMap.empty;
107 } in
102 let collect_diagnostics dctx com =
103 let open CompilationCache in
108104 List.iter (function
109 | TClassDecl c when DiagnosticsPrinter.is_diagnostics_file (com.file_keys#get c.cl_pos.pfile) ->
105 | TClassDecl c when DiagnosticsPrinter.is_diagnostics_file com (com.file_keys#get c.cl_pos.pfile) ->
110106 List.iter (prepare_field dctx com) c.cl_ordered_fields;
111107 List.iter (prepare_field dctx com) c.cl_ordered_statics;
112108 (match c.cl_constructor with None -> () | Some cf -> prepare_field dctx com cf);
115111 ) com.types;
116112 let handle_dead_blocks com = match com.cache with
117113 | Some cc ->
118 let macro_defines = adapt_defines_to_macro_context com.defines in
119 let display_defines = {macro_defines with values = PMap.add "display" "1" macro_defines.values} in
114 let display_defines = adapt_defines_to_display_context com.defines in
120115 let is_true defines e =
121116 ParserEntry.is_true (ParserEntry.eval defines e)
122117 in
123118 Hashtbl.iter (fun file_key cfile ->
124 if DisplayPosition.display_position#is_in_file (com.file_keys#get cfile.CompilationServer.c_file_path) then begin
125 let dead_blocks = cfile.CompilationServer.c_pdi.pd_dead_blocks in
119 if DisplayPosition.display_position#is_in_file (com.file_keys#get cfile.c_file_path) then begin
120 let dead_blocks = cfile.c_pdi.pd_dead_blocks in
126121 let dead_blocks = List.filter (fun (_,e) -> not (is_true display_defines e)) dead_blocks in
127122 try
128123 let dead_blocks2 = Hashtbl.find dctx.dead_blocks file_key in
136131 | None ->
137132 ()
138133 in
139 handle_dead_blocks com;
134 handle_dead_blocks com
135
136 let prepare com =
137 let dctx = {
138 removable_code = [];
139 import_positions = PMap.empty;
140 dead_blocks = Hashtbl.create 0;
141 diagnostics_messages = [];
142 unresolved_identifiers = [];
143 missing_fields = PMap.empty;
144 } in
145 if not (List.exists (fun (_,_,_,sev,_) -> sev = MessageSeverity.Error) com.shared.shared_display_information.diagnostics_messages) then
146 collect_diagnostics dctx com;
140147 let process_modules com =
141148 List.iter (fun m ->
142149 PMap.iter (fun p b ->
170177 dctx
171178
172179 let secure_generated_code ctx e =
173 if is_diagnostics_run ctx.com e.epos then mk (TMeta((Meta.Extern,[],e.epos),e)) e.etype e.epos else e
180 (* This causes problems and sucks in general... need a different solution. But I forgot which problem this solved anyway. *)
181 (* mk (TMeta((Meta.Extern,[],e.epos),e)) e.etype e.epos *)
182 e
174183
175184 let print com =
176185 let dctx = prepare com in
177 Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics dctx)
186 Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics com dctx)
178187
179188 let run com =
180189 let dctx = prepare com in
181 DisplayException.raise_diagnostics dctx
190 dctx
11 open Common
22 open Json
33 open DisplayTypes
4 open DiagnosticsKind
54 open DisplayTypes
65 open Type
76 open Genjson
8
9 type t = DiagnosticsKind.t * pos
10
11 let is_diagnostics_file file_key =
12 match (!Parser.display_mode) with
13 | DMDiagnostics [] -> true
14 | DMDiagnostics file_keys -> List.exists (fun key' -> file_key = key') file_keys
7 open MessageKind
8
9 type t = {
10 diag_kind : MessageKind.t;
11 diag_pos : pos;
12 diag_severity : MessageSeverity.t;
13 diag_args : Json.t;
14 mutable diag_related_information : (pos * int * string) list;
15 }
16
17 let make_diagnostic kd p sev args = {
18 diag_kind = kd;
19 diag_pos = p;
20 diag_severity = sev;
21 diag_args = args;
22 diag_related_information = [];
23 }
24
25 let is_diagnostics_file com file_key =
26 match com.report_mode with
27 | RMDiagnostics [] -> true
28 | RMDiagnostics file_keys -> List.exists (fun key' -> file_key = key') file_keys
1529 | _ -> false
1630
1731 module UnresolvedIdentifierSuggestion = struct
2842 open CompletionItem
2943 open CompletionModuleType
3044
31 let json_of_diagnostics dctx =
32 let diag = Hashtbl.create 0 in
33 let add append dk p sev args =
45 let json_of_diagnostics com dctx =
46 let diagnostics = Hashtbl.create 0 in
47 let current = ref None in
48 let add append diag =
49 let p = diag.diag_pos in
3450 let file = if p = null_pos then p.pfile else Path.get_real_path p.pfile in
35 let diag = try
36 Hashtbl.find diag file
51 let fdiag = try
52 Hashtbl.find diagnostics file
3753 with Not_found ->
38 let d = Hashtbl.create 0 in
39 Hashtbl.add diag file d;
54 let d = [] in
55 Hashtbl.add diagnostics file d;
4056 d
4157 in
42 if append || not (Hashtbl.mem diag p) then
43 Hashtbl.add diag p (dk,p,sev,args)
58 if append || (List.find_opt (fun diag -> diag.diag_pos = p) fdiag) = None then
59 Hashtbl.replace diagnostics file (diag :: fdiag)
4460 in
4561 let file_keys = new Common.file_keys in
4662 let add dk p sev args =
5167 | DKInactiveBlock ->
5268 false
5369 | DKUnresolvedIdentifier
54 | DKCompilerError
70 | DKCompilerMessage
5571 | DKParserError
5672 | DKMissingFields ->
5773 true
5874 in
59 if p = null_pos || is_diagnostics_file (file_keys#get p.pfile) then add append dk p sev args
75 if p = null_pos || is_diagnostics_file com (file_keys#get p.pfile) then begin
76 let diag = make_diagnostic dk p sev args in
77 current := Some diag;
78 add append diag
79 end else current := None
6080 in
6181 List.iter (fun (s,p,suggestions) ->
6282 let suggestions = ExtList.List.filter_map (fun (s,item,r) ->
7696 "name",JString s;
7797 ])
7898 ) suggestions in
79 add DKUnresolvedIdentifier p DiagnosticsSeverity.Error (JArray suggestions);
99 add DKUnresolvedIdentifier p MessageSeverity.Error (JArray suggestions);
80100 ) dctx.unresolved_identifiers;
81 List.iter (fun (s,p,kind,sev) ->
82 add kind p sev (JString s)
101 List.iter (fun (s,p,kind,sev,depth) -> match (depth, !current) with
102 | d, Some diag when d > 0 ->
103 let lines = ExtString.String.nsplit s "\n" in
104 (match lines with
105 | [] -> ()
106 | s :: sub ->
107 let related = List.fold_left (fun acc s -> (p,d,Error.compl_msg s) :: acc) diag.diag_related_information sub in
108 diag.diag_related_information <- (p,d,s) :: related;
109 )
110 | 0, _ ->
111 add kind p sev (JString s)
112 | _ ->
113 (* Do not add errors with depth greater than one as top level diagnostic. *)
114 (* This could happen when running diagnostics for a file that is wentioned in *)
115 (* sub errors of a file not included for diagnostics. *)
116 ()
83117 ) (List.rev dctx.diagnostics_messages);
84118 PMap.iter (fun p (mt,mfl) ->
85119 let jctx = create_context GMMinimum in
142176 "moduleFile",jstring (Path.UniqueKey.lazy_path (t_infos mt).mt_module.m_extra.m_file);
143177 "entries",jarray l
144178 ] in
145 add DKMissingFields p DiagnosticsSeverity.Error j
179 add DKMissingFields p MessageSeverity.Error j
146180 ) dctx.missing_fields;
147181 (* non-append from here *)
148 Hashtbl.iter (fun _ (s,p) ->
149 add DKDeprecationWarning p DiagnosticsSeverity.Warning (JString s);
150 ) DeprecationCheck.warned_positions;
182 begin match Warning.get_mode WDeprecated com.warning_options with
183 | WMEnable ->
184 Hashtbl.iter (fun _ (s,p) ->
185 add DKDeprecationWarning p MessageSeverity.Warning (JString s);
186 ) DeprecationCheck.warned_positions;
187 | WMDisable ->
188 ()
189 end;
151190 PMap.iter (fun p r ->
152 if not !r then add DKUnusedImport p DiagnosticsSeverity.Warning (JArray [])
191 if not !r then add DKUnusedImport p MessageSeverity.Warning (JArray [])
153192 ) dctx.import_positions;
154193 List.iter (fun (s,p,prange) ->
155 add DKRemovableCode p DiagnosticsSeverity.Warning (JObject ["description",JString s;"range",if prange = null_pos then JNull else Genjson.generate_pos_as_range prange])
194 add DKRemovableCode p MessageSeverity.Warning (JObject ["description",JString s;"range",if prange = null_pos then JNull else Genjson.generate_pos_as_range prange])
156195 ) dctx.removable_code;
157196 Hashtbl.iter (fun file ranges ->
158197 List.iter (fun (p,e) ->
161200 "string",JString (Ast.Printer.s_expr e)
162201 ]
163202 ] in
164 add DKInactiveBlock p DiagnosticsSeverity.Hint jo
203 add DKInactiveBlock p MessageSeverity.Hint jo
165204 ) ranges
166205 ) dctx.dead_blocks;
167206 let jl = Hashtbl.fold (fun file diag acc ->
168 let jl = Hashtbl.fold (fun _ (dk,p,sev,jargs) acc ->
207 let jl = List.rev_map (fun diag ->
169208 (JObject [
170 "kind",JInt (DiagnosticsKind.to_int dk);
171 "severity",JInt (DiagnosticsSeverity.to_int sev);
172 "range",Genjson.generate_pos_as_range p;
173 "args",jargs
174 ]) :: acc
175 ) diag [] in
209 "kind",JInt (MessageKind.to_int diag.diag_kind);
210 "severity",JInt (MessageSeverity.to_int diag.diag_severity);
211 "range",Genjson.generate_pos_as_range diag.diag_pos;
212 "args",diag.diag_args;
213 "relatedInformation",JArray (
214 List.rev_map (fun (pos,depth,msg) -> (JObject [
215 "location",Genjson.generate_pos_as_location pos;
216 "depth",JInt depth;
217 "message",JString msg;
218 ])) diag.diag_related_information
219 )
220 ])
221 ) diag in
176222 (JObject [
177223 "file",if file = "?" then JNull else JString file;
178224 "diagnostics",JArray jl
179225 ]) :: acc
180 ) diag [] in
226 ) diagnostics [] in
181227 let js = JArray jl in
182 js
228 js
6969 let loop e =
7070 (* print_endline (Printf.sprintf "%i-%i: %s" (pos e).pmin (pos e).pmax (Ast.s_expr e)); *)
7171 match fst e with
72 | EFunction(FKNamed((_,p),_),_) when is_annotated p && is_completion ->
73 raise Exit
7274 | EVars vl when is_annotated (pos e) && is_completion ->
7375 let rec loop2 acc mark vl = match vl with
7476 | v :: vl ->
108108 (* For constructors, we care about the class name so we don't end up looking for "new". *)
109109 snd c.cl_path,SKConstructor cf
110110 | _,(Self (TClassDecl c) | Parent(TClassDecl c)) ->
111 cf.cf_name,SKField (cf,Some c.cl_path)
111 cf.cf_name,SKField (cf,Some c)
112112 | _ ->
113113 cf.cf_name,SKField (cf,None)
114114 in
120120 cf
121121 in
122122 let cf = match origin,scope,follow cf.cf_type with
123 | Self (TClassDecl c),CFSConstructor,TFun(tl,_) -> {cf with cf_type = TFun(tl,TInst(c,List.map snd c.cl_params))}
123 | Self (TClassDecl c),CFSConstructor,TFun(tl,_) -> {cf with cf_type = TFun(tl,TInst(c,extract_param_types c.cl_params))}
124124 | _ -> cf
125125 in
126126 let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) cf.cf_type in
144144 begin match meta with
145145 | Meta.Custom _ | Meta.Dollar _ -> ()
146146 | _ ->
147 if com.json_out = None then begin match Meta.get_documentation meta with
147 if com.json_out = None then begin match Meta.get_documentation com.user_metas meta with
148148 | None -> ()
149149 | Some (_,s) ->
150150 raise_metadata ("<metadata>" ^ s ^ "</metadata>")
152152 raise_hover (make_ci_metadata meta) None p
153153 end
154154 | DMDefault ->
155 let all = Meta.get_all() in
155 let all = Meta.get_all com.user_metas in
156156 let all = List.map make_ci_metadata all in
157 let subject = if meta = Meta.Last then None else Some (Meta.to_string meta) in
157 let subject = if meta = Meta.HxCompletion then None else Some (Meta.to_string meta) in
158158 raise_fields all CRMetadata (make_subject subject p);
159159 | _ ->
160160 ()
66
77 exception DisplayException of display_exception_kind
88
9 let raise_diagnostics s = raise (DisplayException(DisplayDiagnostics s))
10 let raise_statistics s = raise (DisplayException(Statistics s))
119 let raise_module_symbols s = raise (DisplayException(ModuleSymbols s))
1210 let raise_metadata s = raise (DisplayException(Metadata s))
13 let raise_signatures l isig iarg kind = raise (DisplayException(DisplaySignatures(Some(l,isig,iarg,kind))))
14 let raise_hover item expected p = raise (DisplayException(DisplayHover(Some {hitem = item;hpos = p;hexpected = expected})))
11 let raise_signatures l isig iarg kind = raise (DisplayException(DisplaySignatures((l,isig,iarg,kind))))
12 let raise_hover item expected p = raise (DisplayException(DisplayHover({hitem = item;hpos = p;hexpected = expected})))
1513 let raise_positions pl = raise (DisplayException(DisplayPositions pl))
16 let raise_fields ckl cr subj = raise (DisplayException(DisplayFields(Some({fitems = ckl;fkind = cr;fsubject = subj}))))
14 let raise_fields ckl cr subj = raise (DisplayException(DisplayFields({fitems = ckl;fkind = cr;fsubject = subj})))
1715 let raise_package sl = raise (DisplayException(DisplayPackage sl))
1816
1917 (* global state *)
158156
159157 let to_json ctx de =
160158 match de with
161 | Statistics _
162159 | ModuleSymbols _
163160 | Metadata _ -> die "" __LOC__
164 | DisplaySignatures None ->
165 jnull
166 | DisplayDiagnostics dctx ->
167 DiagnosticsPrinter.json_of_diagnostics dctx
168 | DisplaySignatures Some(sigs,isig,iarg,kind) ->
161 | DisplaySignatures(sigs,isig,iarg,kind) ->
169162 (* We always want full info for signatures *)
170163 let ctx = Genjson.create_context GMFull in
171164 let fsig ((_,signature),doc) =
183176 "signatures",jlist fsig sigs;
184177 "kind",jint sigkind;
185178 ]
186 | DisplayHover None ->
187 jnull
188 | DisplayHover (Some hover) ->
179 | DisplayHover hover ->
189180 let named_source_kind = function
190181 | WithType.FunctionArgument name -> (0, name)
191182 | WithType.StructureField name -> (1, name)
224215 ]
225216 | DisplayPositions pl ->
226217 jarray (List.map generate_pos_as_location pl)
227 | DisplayFields None ->
228 jnull
229 | DisplayFields Some r ->
218 | DisplayFields r ->
230219 fields_to_json ctx r.fitems r.fkind r.fsubject
231220 | DisplayPackage pack ->
232 jarray (List.map jstring pack)
221 jarray (List.map jstring pack)
222 | DisplayNoResult ->
223 jnull
2727 open Display
2828
2929 let get_submodule_fields ctx path =
30 let m = Hashtbl.find ctx.g.modules path in
30 let m = ctx.com.module_lut#find path in
3131 let tl = List.filter (fun t -> path <> (t_infos t).mt_path && not (t_infos t).mt_private) m.m_types in
3232 let tl = List.map (fun mt ->
3333 make_ci_type (CompletionItem.CompletionModuleType.of_module_type mt) ImportStatus.Imported None
4545 | _ ->
4646 t
4747 in
48 let rec dup t = Type.map dup t in
49 let handle_field c f acc =
50 let f = { f with cf_type = opt_type f.cf_type } in
51 let monos = List.map (fun _ -> spawn_monomorph ctx p) f.cf_params in
52 let map = apply_params f.cf_params monos in
53 match follow (map f.cf_type) with
54 | TFun((_,_,TType({t_path=["haxe";"macro"], "ExprOf"}, [t])) :: args, ret)
55 | TFun((_,_,t) :: args, ret) ->
56 begin try
57 let e = TyperBase.unify_static_extension ctx {e with etype = dup e.etype} t p in
58 List.iter2 (fun m tp -> match follow tp.ttp_type with
59 | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
60 List.iter (fun tc -> unify_raise m (map tc) e.epos) constr
61 | _ -> ()
62 ) monos f.cf_params;
63 if not (can_access ctx c f true) || follow e.etype == t_dynamic && follow t != t_dynamic then
64 acc
65 else begin
66 let f = prepare_using_field f in
67 let f = { f with cf_params = []; cf_flags = set_flag f.cf_flags (int_of_class_field_flag CfPublic); cf_type = TFun(args,ret) } in
68 let decl = match c.cl_kind with
69 | KAbstractImpl a -> TAbstractDecl a
70 | _ -> TClassDecl c
71 in
72 let origin = StaticExtension(decl) in
73 let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta f.cf_meta) f.cf_type in
74 let item = make_ci_class_field (CompletionClassField.make f CFSMember origin true) (f.cf_type,ct) in
75 PMap.add f.cf_name item acc
76 end
77 with Error (Unify _,_,_) | Unify_error _ ->
78 acc
79 end
80 | _ ->
81 acc
82 in
4883 let rec loop acc = function
4984 | [] ->
5085 acc
5186 | (c,_) :: l ->
52 let rec dup t = Type.map dup t in
5387 let acc = List.fold_left (fun acc f ->
5488 if Meta.has Meta.NoUsing f.cf_meta || Meta.has Meta.NoCompletion f.cf_meta || has_class_field_flag f CfImpl || PMap.mem f.cf_name acc then
5589 acc
56 else begin
57 let f = { f with cf_type = opt_type f.cf_type } in
58 let monos = List.map (fun _ -> spawn_monomorph ctx p) f.cf_params in
59 let map = apply_params f.cf_params monos in
60 match follow (map f.cf_type) with
61 | TFun((_,_,TType({t_path=["haxe";"macro"], "ExprOf"}, [t])) :: args, ret)
62 | TFun((_,_,t) :: args, ret) ->
63 begin try
64 let e = TyperBase.unify_static_extension ctx {e with etype = dup e.etype} t p in
65 List.iter2 (fun m (name,t) -> match follow t with
66 | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] ->
67 List.iter (fun tc -> unify_raise ctx m (map tc) e.epos) constr
68 | _ -> ()
69 ) monos f.cf_params;
70 if not (can_access ctx c f true) || follow e.etype == t_dynamic && follow t != t_dynamic then
71 acc
72 else begin
73 let f = prepare_using_field f in
74 let f = { f with cf_params = []; cf_flags = set_flag f.cf_flags (int_of_class_field_flag CfPublic); cf_type = TFun(args,ret) } in
75 let decl = match c.cl_kind with
76 | KAbstractImpl a -> TAbstractDecl a
77 | _ -> TClassDecl c
78 in
79 let origin = StaticExtension(decl) in
80 let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta f.cf_meta) f.cf_type in
81 let item = make_ci_class_field (CompletionClassField.make f CFSMember origin true) (f.cf_type,ct) in
82 PMap.add f.cf_name item acc
83 end
84 with Error (Unify _,_) | Unify_error _ ->
85 acc
86 end
87 | _ ->
88 acc
89 end
90 else
91 List.fold_left (fun acc f -> handle_field c f acc) acc (f :: f.cf_overloads)
9092 ) acc c.cl_ordered_statics in
9193 loop acc l
9294 in
77 open Timer
88 open Genjson
99 open Type
10 open DisplayProcessingGlobals
1011
1112 (* Generate the JSON of our times. *)
1213 let json_of_times root =
3839 Genjson.create_context ~jsonrpc:jsonrpc (if may_resolve && !supports_resolve then GMMinimum else GMFull)
3940
4041 let send_string j =
41 raise (DisplayOutput.Completion j)
42 raise (Completion j)
4243
4344 let send_json json =
4445 send_string (string_of_json json)
4546
46 class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationServer.t) = object(self)
47 class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationCache.t) = object(self)
4748 val cs = cs;
4849
4950 method get_cs = cs
5758 let file = jsonrpc#get_opt_param (fun () ->
5859 let file = jsonrpc#get_string_param "file" in
5960 Path.get_full_path file
60 ) DisplayOutput.file_input_marker in
61 ) file_input_marker in
6162 let pos = if requires_offset then jsonrpc#get_int_param "offset" else (-1) in
6263 TypeloadParse.current_stdin := jsonrpc#get_opt_param (fun () ->
6364 let s = jsonrpc#get_string_param "contents" in
8182 }
8283
8384 let handler =
84 let open CompilationServer in
85 let open CompilationCache in
8586 let h = Hashtbl.create 0 in
8687 let l = [
8788 "initialize", (fun hctx ->
167168 );
168169 "server/contexts", (fun hctx ->
169170 let l = List.map (fun cc -> cc#get_json) hctx.display#get_cs#get_contexts in
171 let l = List.filter (fun json -> json <> JNull) l in
170172 hctx.send_result (jarray l)
171173 );
172174 "server/modules", (fun hctx ->
186188 with Not_found ->
187189 hctx.send_error [jstring "No such module"]
188190 in
189 hctx.send_result (generate_module () m)
191 hctx.send_result (generate_module cc m)
192 );
193 "server/type", (fun hctx ->
194 let sign = Digest.from_hex (hctx.jsonrpc#get_string_param "signature") in
195 let path = Path.parse_path (hctx.jsonrpc#get_string_param "modulePath") in
196 let typeName = hctx.jsonrpc#get_string_param "typeName" in
197 let cc = hctx.display#get_cs#get_context sign in
198 let m = try
199 cc#find_module path
200 with Not_found ->
201 hctx.send_error [jstring "No such module"]
202 in
203 let rec loop mtl = match mtl with
204 | [] ->
205 hctx.send_error [jstring "No such type"]
206 | mt :: mtl ->
207 begin match mt with
208 | TClassDecl c -> c.cl_restore()
209 | _ -> ()
210 end;
211 let infos = t_infos mt in
212 if snd infos.mt_path = typeName then begin
213 let ctx = Genjson.create_context GMMinimum in
214 hctx.send_result (Genjson.generate_module_type ctx mt)
215 end else
216 loop mtl
217 in
218 loop m.m_types
219 );
220 "server/typeContexts", (fun hctx ->
221 let path = Path.parse_path (hctx.jsonrpc#get_string_param "modulePath") in
222 let typeName = hctx.jsonrpc#get_string_param "typeName" in
223 let contexts = hctx.display#get_cs#get_contexts in
224
225 hctx.send_result (jarray (List.fold_left (fun acc cc ->
226 match cc#find_module_opt path with
227 | None -> acc
228 | Some(m) ->
229 let rec loop mtl = match mtl with
230 | [] ->
231 acc
232 | mt :: mtl ->
233 begin match mt with
234 | TClassDecl c -> c.cl_restore()
235 | _ -> ()
236 end;
237 if snd (t_infos mt).mt_path = typeName then
238 cc#get_json :: acc
239 else
240 loop mtl
241 in
242 loop m.m_types
243 ) [] contexts))
190244 );
191245 "server/moduleCreated", (fun hctx ->
192246 let file = hctx.jsonrpc#get_string_param "file" in
217271 let file = hctx.jsonrpc#get_string_param "file" in
218272 let fkey = hctx.com.file_keys#get file in
219273 let cs = hctx.display#get_cs in
220 cs#taint_modules fkey;
274 cs#taint_modules fkey "server/invalidate";
221275 cs#remove_files fkey;
222276 hctx.send_result jnull
223277 );
278332 let jsonrpc = new jsonrpc_handler input in
279333
280334 let send_result json =
335 flush stdout;
336 flush stderr;
281337 let fl = [
282338 "result",json;
283339 "timestamp",jfloat (Unix.gettimeofday ());
309365 jsonrpc = jsonrpc
310366 });
311367
312 let cs = match CompilationServer.get() with
313 | Some cs -> cs
314 | None -> send_error [jstring "compilation server not running for some reason"];
315 in
368 let cs = com.cs in
316369
317370 let display = new display_handler jsonrpc com cs in
318371
5252 else
5353 packages := f :: !packages
5454 end;
55 end else if file_extension f = "hx" && f <> "import.hx" then begin
55 end else if Path.file_extension f = "hx" && f <> "import.hx" then begin
5656 let c = Filename.chop_extension f in
5757 try
5858 ignore(String.index c '.')
44 open Typecore
55 open DisplayPosition
66 open CompletionItem
7 open CompilationServer
7 open CompilationCache
88 open ClassFieldOrigin
99
1010 let find_field_by_position sc p =
1717 if pos eff.ec_name = p then true else false
1818 ) sc.d_data
1919
20 let find_class_by_position cfile p =
20 let find_class_by_position decls p =
2121 let rec loop dl = match dl with
2222 | (EClass c,_) :: dl when pos c.d_name = p -> c
2323 | _ :: dl -> loop dl
2424 | [] -> raise Not_found
2525 in
26 loop cfile.c_decls
26 loop decls
2727
28 let find_enum_by_position cfile p =
28 let find_module_static_by_position decls p =
29 let rec loop dl = match dl with
30 | (EStatic d,_) :: dl when pos d.d_name = p -> d
31 | _ :: dl -> loop dl
32 | [] -> raise Not_found
33 in
34 loop decls
35
36 let find_enum_by_position decls p =
2937 let rec loop dl = match dl with
3038 | (EEnum en,_) :: dl when pos en.d_name = p -> en
3139 | _ :: dl -> loop dl
3240 | [] -> raise Not_found
3341 in
34 loop cfile.c_decls
42 loop decls
3543
36 let find_typedef_by_position cfile p =
44 let find_typedef_by_position decls p =
3745 let rec loop dl = match dl with
3846 | (ETypedef td,_) :: dl when pos td.d_name = p -> td
3947 | _ :: dl -> loop dl
4048 | [] -> raise Not_found
4149 in
42 loop cfile.c_decls
50 loop decls
4351
44 let find_abstract_by_position cfile p =
52 let find_abstract_by_position decls p =
4553 let rec loop dl = match dl with
4654 | (EAbstract a,_) :: dl when pos a.d_name = p -> a
4755 | _ :: dl -> loop dl
4856 | [] -> raise Not_found
4957 in
50 loop cfile.c_decls
58 loop decls
5159
52 let check_display_field ctx sc c cf =
53 let cff = find_field_by_position sc cf.cf_name_pos in
60 let actually_check_display_field ctx c cff p =
5461 let context_init = new TypeloadFields.context_init in
55 let ctx,cctx = TypeloadFields.create_class_context ctx c context_init cf.cf_pos in
62 let cctx = TypeloadFields.create_class_context c context_init p in
63 let ctx = TypeloadFields.create_typer_context_for_class ctx cctx p in
5664 let cff = TypeloadFields.transform_field (ctx,cctx) c cff (ref []) (pos cff.cff_name) in
57 let ctx,fctx = TypeloadFields.create_field_context (ctx,cctx) c cff in
65 let display_modifier = Typeload.check_field_access ctx cff in
66 let fctx = TypeloadFields.create_field_context cctx cff true display_modifier in
5867 let cf = TypeloadFields.init_field (ctx,cctx,fctx) cff in
5968 flush_pass ctx PTypeField "check_display_field";
6069 ignore(follow cf.cf_type)
6170
62 let check_display_class ctx cc cfile c =
71 let check_display_field ctx sc c cf =
72 let cff = find_field_by_position sc cf.cf_name_pos in
73 actually_check_display_field ctx c cff cf.cf_pos
74
75 let check_display_class ctx decls c =
6376 let check_field sc cf =
6477 if display_position#enclosed_in cf.cf_pos then
6578 check_display_field ctx sc c cf;
7184 in
7285 match c.cl_kind with
7386 | KAbstractImpl a ->
74 let sa = find_abstract_by_position cfile c.cl_name_pos in
87 let sa = find_abstract_by_position decls c.cl_name_pos in
7588 let check_field = check_field sa in
7689 List.iter check_field c.cl_ordered_statics;
7790 | _ ->
78 let sc = find_class_by_position cfile c.cl_name_pos in
79 ignore(Typeload.type_type_params ctx c.cl_path (fun() -> c.cl_params) null_pos sc.d_params);
91 let sc = find_class_by_position decls c.cl_name_pos in
92 ignore(Typeload.type_type_params ctx TPHType c.cl_path (fun() -> c.cl_params) null_pos sc.d_params);
8093 List.iter (function
8194 | (HExtends(ct,p) | HImplements(ct,p)) when display_position#enclosed_in p ->
8295 ignore(Typeload.load_instance ~allow_display:true ctx (ct,p) false)
88101 List.iter check_field c.cl_ordered_fields;
89102 Option.may check_field c.cl_constructor
90103
91 let check_display_enum ctx cc cfile en =
92 let se = find_enum_by_position cfile en.e_name_pos in
93 ignore(Typeload.type_type_params ctx en.e_path (fun() -> en.e_params) null_pos se.d_params);
104 let check_display_enum ctx decls en =
105 let se = find_enum_by_position decls en.e_name_pos in
106 ignore(Typeload.type_type_params ctx TPHType en.e_path (fun() -> en.e_params) null_pos se.d_params);
94107 PMap.iter (fun _ ef ->
95108 if display_position#enclosed_in ef.ef_pos then begin
96109 let sef = find_enum_field_by_position se ef.ef_name_pos in
97 ignore(TypeloadModule.load_enum_field ctx en (TEnum (en,List.map snd en.e_params)) (ref false) (ref 0) sef)
110 ignore(TypeloadModule.TypeLevel.load_enum_field ctx en (TEnum (en,extract_param_types en.e_params)) (ref false) (ref 0) sef)
98111 end
99112 ) en.e_constrs
100113
101 let check_display_typedef ctx cc cfile td =
102 let st = find_typedef_by_position cfile td.t_name_pos in
103 ignore(Typeload.type_type_params ctx td.t_path (fun() -> td.t_params) null_pos st.d_params);
114 let check_display_typedef ctx decls td =
115 let st = find_typedef_by_position decls td.t_name_pos in
116 ignore(Typeload.type_type_params ctx TPHType td.t_path (fun() -> td.t_params) null_pos st.d_params);
104117 ignore(Typeload.load_complex_type ctx true st.d_data)
105118
106 let check_display_abstract ctx cc cfile a =
107 let sa = find_abstract_by_position cfile a.a_name_pos in
108 ignore(Typeload.type_type_params ctx a.a_path (fun() -> a.a_params) null_pos sa.d_params);
119 let check_display_abstract ctx decls a =
120 let sa = find_abstract_by_position decls a.a_name_pos in
121 ignore(Typeload.type_type_params ctx TPHType a.a_path (fun() -> a.a_params) null_pos sa.d_params);
109122 List.iter (function
110123 | (AbOver(ct,p) | AbFrom(ct,p) | AbTo(ct,p)) when display_position#enclosed_in p ->
111124 ignore(Typeload.load_complex_type ctx true (ct,p))
113126 ()
114127 ) sa.d_flags
115128
116 let check_display_module_fields ctx cfile m =
129 let check_display_module_fields ctx decls m =
117130 Option.may (fun c ->
118 let sc = find_class_by_position cfile c.cl_name_pos in
119131 List.iter (fun cf ->
120 if display_position#enclosed_in cf.cf_pos then
121 check_display_field ctx sc c cf;
132 if display_position#enclosed_in cf.cf_pos then begin
133 let cff = find_module_static_by_position decls cf.cf_name_pos in
134 actually_check_display_field ctx c (TypeloadModule.field_of_static_definition cff cf.cf_pos) cf.cf_pos;
135 end;
122136 DisplayEmitter.check_display_metadata ctx cf.cf_meta
123137 ) c.cl_ordered_statics
124138 ) m.m_statics
125139
126 let check_display_module ctx cc cfile m =
140 let check_display_module ctx decls m =
127141 let imports = List.filter (function
128142 | (EImport _ | EUsing _),_ -> true
129143 | _ -> false
130 ) cfile.c_decls in
131 let imports = TypeloadModule.handle_import_hx ctx m imports null_pos in
144 ) decls in
145 let imports = TypeloadModule.ModuleLevel.handle_import_hx ctx m imports null_pos in
132146 let ctx = TypeloadModule.type_types_into_module ctx m imports null_pos in
133147 List.iter (fun md ->
134148 let infos = t_infos md in
136150 DisplayEmitter.display_module_type ctx md infos.mt_name_pos;
137151 begin if display_position#enclosed_in infos.mt_pos then match md with
138152 | TClassDecl c ->
139 check_display_class ctx cc cfile c
153 check_display_class ctx decls c
140154 | TEnumDecl en ->
141 check_display_enum ctx cc cfile en
155 check_display_enum ctx decls en
142156 | TTypeDecl td ->
143 check_display_typedef ctx cc cfile td
157 check_display_typedef ctx decls td
144158 | TAbstractDecl a ->
145 check_display_abstract ctx cc cfile a
159 check_display_abstract ctx decls a
146160 end;
147161 DisplayEmitter.check_display_metadata ctx infos.mt_meta
148162 ) m.m_types;
149 check_display_module_fields ctx cfile m
163 check_display_module_fields ctx decls m
150164
151165 let check_display_file ctx cs =
152166 match ctx.com.cache with
160174 invalid (issue #8991). *)
161175 begin match !TypeloadModule.type_module_hook ctx path null_pos with
162176 | None -> raise Not_found
163 | Some m -> check_display_module ctx cc cfile m
177 | Some m -> check_display_module ctx cfile.c_decls m
164178 end
165179 with Not_found ->
166 if ctx.com.display.dms_display then begin
167 let fkey = DisplayPosition.display_position#get_file_key in
168 (* force parsing again : if the completion point have been changed *)
169 cs#remove_files fkey;
170 cs#taint_modules fkey;
171 end;
180 let fkey = DisplayPosition.display_position#get_file_key in
181 (* force parsing again : if the completion point have been changed *)
182 cs#remove_files fkey;
183 cs#taint_modules fkey "check_display_file";
172184 end
173185 | None ->
174186 ()
1717 *)
1818 open Ast
1919 open Common
20 open CompilationServer
20 open CompilationCache
2121 open Type
2222 open Typecore
2323 open CompletionItem
2626 open Genjson
2727 open Globals
2828
29 (* Merges argument and return types from macro and non-macro context, preferring the one that isn't Dynamic.
30 WARNING: Merging types from boths contexts like this is dangerous. The resuling type must never be
31 persisted on the compilation server, or else the compiler gets COVID. *)
32 let perform_type_voodoo t tl' tr' =
33 match t with
34 | TFun(tl,tr) ->
35 let rec loop acc tl tl' = match tl,tl' with
36 | ((_,_,t1) as a1 :: tl),((_,_,t1') as a1' :: tl') ->
37 let a = if t1 == t_dynamic then a1' else a1 in
38 loop (a :: acc) tl tl'
39 | _ -> (List.rev acc) @ tl'
40 in
41 let tl = loop [] tl tl' in
42 TFun(tl,if tr == t_dynamic then tr' else tr')
43 | _ ->
44 TFun(tl',tr')
45
2946 let maybe_resolve_macro_field ctx t c cf =
3047 try
3148 if cf.cf_kind <> Method MethMacro then raise Exit;
3249 let (tl,tr,c,cf) = ctx.g.do_load_macro ctx false c.cl_path cf.cf_name null_pos in
33 (TFun(tl,tr)),c,cf
50 let t = perform_type_voodoo t tl tr in
51 t,{cf with cf_type = t}
3452 with _ ->
35 t,c,cf
53 t,cf
3654
3755 let exclude : string list ref = ref []
3856
39 class explore_class_path_task cs com recursive f_pack f_module dir pack = object(self)
57 class explore_class_path_task com checked recursive f_pack f_module dir pack = object(self)
4058 inherit server_task ["explore";dir] 50
4159 val platform_str = platform_name_macro com
4260
4361 method private execute : unit =
62 let unique_dir = Path.UniqueKey.create dir in
4463 let dot_path = (String.concat "." (List.rev pack)) in
45 if (List.mem dot_path !exclude) then
64 if (List.mem dot_path !exclude) || Hashtbl.mem checked unique_dir then
4665 ()
4766 else try
67 Hashtbl.add checked unique_dir true;
4868 let entries = Sys.readdir dir in
4969 Array.iter (fun file ->
5070 match file with
5979 with Not_found ->
6080 f_pack (List.rev pack,file);
6181 if recursive then begin
62 let task = new explore_class_path_task cs com recursive f_pack f_module (dir ^ file ^ "/") (file :: pack) in
63 begin match cs with
64 | None -> task#run
65 | Some cs' -> cs'#add_task task
66 end
82 (new explore_class_path_task com checked recursive f_pack f_module (dir ^ file ^ "/") (file :: pack))#run
6783 end
6884 end
6985 | _ ->
93109 end
94110
95111 let explore_class_paths com timer class_paths recursive f_pack f_module =
96 let cs = CompilationServer.get() in
112 let cs = com.cs in
97113 let t = Timer.timer (timer @ ["class path exploration"]) in
114 let checked = Hashtbl.create 0 in
98115 let tasks = List.map (fun dir ->
99 new explore_class_path_task cs com recursive f_pack f_module dir []
116 new explore_class_path_task com checked recursive f_pack f_module dir []
100117 ) class_paths in
101 begin match cs with
102 | None -> List.iter (fun task -> task#run) tasks
103 | Some cs -> List.iter (fun task -> cs#add_task task) tasks
104 end;
118 let task = new arbitrary_task ["explore"] 50 (fun () ->
119 List.iter (fun task -> task#run) tasks
120 ) in
121 cs#add_task task;
105122 t()
106123
107124 let read_class_paths com timer =
109126 (* Don't parse the display file as that would maybe overwrite the content from stdin with the file contents. *)
110127 if not (DisplayPosition.display_position#is_in_file (com.file_keys#get file)) then begin
111128 let file,_,pack,_ = Display.parse_module' com path Globals.null_pos in
112 match CompilationServer.get() with
113 | Some cs when pack <> fst path ->
129 if pack <> fst path then begin
114130 let file_key = com.file_keys#get file in
115 (CommonCache.get_cache cs com)#remove_file_for_real file_key
116 | _ ->
117 ()
131 (CommonCache.get_cache com)#remove_file_for_real file_key
132 end
118133 end
119134 )
120135
121136 let init_or_update_server cs com timer_name =
122 let cc = CommonCache.get_cache cs com in
137 let cc = CommonCache.get_cache com in
123138 if not cc#is_initialized then begin
124139 cc#set_initialized true;
125140 read_class_paths com timer_name
288303 let add_field scope origin cf =
289304 let origin,cf = match origin with
290305 | Self (TClassDecl c) ->
291 let _,c,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in
306 let _,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in
292307 Self (TClassDecl c),cf
293308 | StaticImport (TClassDecl c) ->
294 let _,c,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in
309 let _,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in
295310 StaticImport (TClassDecl c),cf
296311 | Parent (TClassDecl c) ->
297 let _,c,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in
312 let _,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in
298313 Parent (TClassDecl c),cf
299314 | StaticExtension (TClassDecl c) ->
300 let _,c,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in
315 let _,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in
301316 StaticExtension (TClassDecl c),cf
302317 | _ ->
303318 origin,cf
310325 in
311326 (* member fields *)
312327 if ctx.curfun <> FunStatic then begin
313 let all_fields = Type.TClass.get_all_fields ctx.curclass (List.map snd ctx.curclass.cl_params) in
328 let all_fields = Type.TClass.get_all_fields ctx.curclass (extract_param_types ctx.curclass.cl_params) in
314329 PMap.iter (fun _ (c,cf) ->
315330 let origin = if c == ctx.curclass then Self (TClassDecl c) else Parent (TClassDecl c) in
316331 maybe_add_field CFSMember origin cf
362377 ()
363378 in
364379 List.iter enum_ctors ctx.m.curmod.m_types;
365 List.iter enum_ctors (List.map fst ctx.m.module_types);
380 List.iter enum_ctors (List.map fst ctx.m.module_imports);
366381
367382 (* enum constructors of expected type *)
368383 begin match with_type with
384399 | _ -> TClassDecl c,make_ci_class_field
385400 in
386401 let origin = StaticImport decl in
387 add (make (CompletionClassField.make cf CFSStatic origin is_qualified) (tpair ~values:(get_value_meta cf.cf_meta) cf.cf_type)) (Some name)
402 if can_access ctx c cf true && not (Meta.has Meta.NoCompletion cf.cf_meta) then begin
403 add (make (CompletionClassField.make cf CFSStatic origin is_qualified) (tpair ~values:(get_value_meta cf.cf_meta) cf.cf_type)) (Some name)
404 end
388405 in
389406 match resolve_typedef mt with
390407 | TClassDecl c -> class_import c;
405422 add (make_ci_literal "false" (tpair ctx.com.basic.tbool)) (Some "false");
406423 begin match ctx.curfun with
407424 | FunMember | FunConstructor | FunMemberClassLocal ->
408 let t = TInst(ctx.curclass,List.map snd ctx.curclass.cl_params) in
425 let t = TInst(ctx.curclass,extract_param_types ctx.curclass.cl_params) in
409426 add (make_ci_literal "this" (tpair t)) (Some "this");
410427 begin match ctx.curclass.cl_super with
411428 | Some(c,tl) -> add (make_ci_literal "super" (tpair (TInst(c,tl)))) (Some "super")
412429 | None -> ()
413430 end
431 | FunMemberAbstract ->
432 let t = TInst(ctx.curclass,extract_param_types ctx.curclass.cl_params) in
433 add (make_ci_literal "abstract" (tpair t)) (Some "abstract");
414434 | _ ->
415435 ()
416436 end;
429449 end;
430450
431451 (* type params *)
432 List.iter (fun (s,t) -> match follow t with
452 List.iter (fun tp -> match follow tp.ttp_type with
433453 | TInst(c,_) ->
434 add (make_ci_type_param c (tpair t)) (Some (snd c.cl_path))
454 add (make_ci_type_param c (tpair tp.ttp_type)) (Some (snd c.cl_path))
435455 | _ -> die "" __LOC__
436456 ) ctx.type_params;
437457
439459 List.iter add_type ctx.m.curmod.m_types;
440460
441461 (* module imports *)
442 List.iter add_type (List.rev_map fst ctx.m.module_types); (* reverse! *)
462 List.iter add_type (List.rev_map fst ctx.m.module_imports); (* reverse! *)
443463
444464 (* types from files *)
445 begin match !CompilationServer.instance with
446 | None ->
447 (* offline: explore class paths *)
448 let class_paths = ctx.com.class_path in
449 let class_paths = List.filter (fun s -> s <> "") class_paths in
450 explore_class_paths ctx.com ["display";"toplevel"] class_paths true add_package (fun file path ->
451 if not (path_exists cctx path) then begin
452 let _,decls = Display.parse_module ctx path Globals.null_pos in
453 ignore(process_decls (fst path) (snd path) decls)
454 end
455 )
456 | Some cs ->
457 (* online: iter context files *)
458 init_or_update_server cs ctx.com ["display";"toplevel"];
459 let cc = CommonCache.get_cache cs ctx.com in
460 let files = cc#get_files in
461 (* Sort files by reverse distance of their package to our current package. *)
462 let files = Hashtbl.fold (fun file cfile acc ->
463 let i = pack_similarity curpack cfile.c_package in
464 ((file,cfile),i) :: acc
465 ) files [] in
466 let files = List.sort (fun (_,i1) (_,i2) -> -compare i1 i2) files in
467 let check_package pack = match List.rev pack with
468 | [] -> ()
469 | s :: sl -> add_package (List.rev sl,s)
470 in
471 List.iter (fun ((file_key,cfile),_) ->
472 let module_name = CompilationServer.get_module_name_of_cfile cfile.c_file_path cfile in
473 let dot_path = s_type_path (cfile.c_package,module_name) in
474 (* In legacy mode we only show toplevel types. *)
475 if is_legacy_completion && cfile.c_package <> [] then begin
476 (* And only toplevel packages. *)
477 match cfile.c_package with
478 | [s] -> add_package ([],s)
479 | _ -> ()
480 end else if (List.exists (fun e -> ExtString.String.starts_with dot_path (e ^ ".")) !exclude) then
481 ()
482 else begin
483 Hashtbl.replace ctx.com.module_to_file (cfile.c_package,module_name) cfile.c_file_path;
484 if process_decls cfile.c_package module_name cfile.c_decls then check_package cfile.c_package;
485 end
486 ) files;
487 List.iter (fun file ->
488 match cs#get_native_lib file with
489 | Some lib ->
490 Hashtbl.iter (fun path (pack,decls) ->
491 if process_decls pack (snd path) decls then check_package pack;
492 ) lib.c_nl_files
493 | None ->
494 ()
495 ) ctx.com.native_libs.all_libs
496 end;
465 let cs = ctx.com.cs in
466 (* online: iter context files *)
467 init_or_update_server cs ctx.com ["display";"toplevel"];
468 let cc = CommonCache.get_cache ctx.com in
469 let files = cc#get_files in
470 (* Sort files by reverse distance of their package to our current package. *)
471 let files = Hashtbl.fold (fun file cfile acc ->
472 let i = pack_similarity curpack cfile.c_package in
473 ((file,cfile),i) :: acc
474 ) files [] in
475 let files = List.sort (fun (_,i1) (_,i2) -> -compare i1 i2) files in
476 let check_package pack = match List.rev pack with
477 | [] -> ()
478 | s :: sl -> add_package (List.rev sl,s)
479 in
480 List.iter (fun ((file_key,cfile),_) ->
481 let module_name = CompilationCache.get_module_name_of_cfile cfile.c_file_path cfile in
482 let dot_path = s_type_path (cfile.c_package,module_name) in
483 (* In legacy mode we only show toplevel types. *)
484 if is_legacy_completion && cfile.c_package <> [] then begin
485 (* And only toplevel packages. *)
486 match cfile.c_package with
487 | [s] -> add_package ([],s)
488 | _ -> ()
489 end else if (List.exists (fun e -> ExtString.String.starts_with dot_path (e ^ ".")) !exclude) then
490 ()
491 else begin
492 ctx.com.module_to_file#add (cfile.c_package,module_name) cfile.c_file_path;
493 if process_decls cfile.c_package module_name cfile.c_decls then check_package cfile.c_package;
494 end
495 ) files;
496 List.iter (fun file ->
497 match cs#get_native_lib file with
498 | Some lib ->
499 Hashtbl.iter (fun path (pack,decls) ->
500 if process_decls pack (snd path) decls then check_package pack;
501 ) lib.c_nl_files
502 | None ->
503 ()
504 ) ctx.com.native_libs.all_libs;
497505
498506 (* packages *)
499507 Hashtbl.iter (fun path _ ->
33 open Common
44 open Type
55 open Typecore
6 open CompilationServer
76 open ImportHandling
87
98 let find_possible_references tctx cs =
2928 Display.ReferencePosition.reset();
3029 usages
3130
32 let collect_reference_positions com =
33 let name,pos,kind = Display.ReferencePosition.get () in
31 (* This probably exists somewhere already but I can't find it *)
32 let is_var_field cf = match cf.cf_kind with
33 | Method _ -> false
34 | Var _ -> true
35
36 let rec collect_reference_positions com (name,pos,kind) =
3437 match kind, com.display.dms_kind with
35 | SKField (cf,Some cl_path), DMUsage (_,find_descendants,find_base) when (find_descendants || find_base) && not (has_class_field_flag cf CfStatic) ->
38 | SKField (cf,Some c),DMUsage (_,find_descendants,_) when find_descendants && is_var_field cf ->
39 let d = DynArray.create () in
40 DynArray.add d (name,pos,kind);
41 begin match cf.cf_kind with
42 | Var vk ->
43 let host = FieldAccess.get_host c cf in
44 let check r mode = match r with
45 | AccCall ->
46 begin match FieldAccess.find_accessor_for_field host cf cf.cf_type mode with
47 | AccessorFound (cf_acc,new_host) ->
48 let c_host = FieldAccess.get_host_class_raise new_host in
49 let new_ref = (cf_acc.cf_name,cf_acc.cf_name_pos,SKField(cf_acc,Some c_host)) in
50 DynArray.add d new_ref;
51 List.iter (DynArray.add d) (collect_reference_positions com new_ref)
52 | _ ->
53 ()
54 end
55 | _ ->
56 ()
57 in
58 check vk.v_read MGet;
59 check vk.v_write (MSet None);
60 | _ ->
61 ()
62 end;
63 DynArray.to_list d
64 | SKField (cf,Some c), DMUsage (_,find_descendants,find_base) when (find_descendants || find_base) && not (has_class_field_flag cf CfStatic) ->
3665 let collect() =
3766 let c =
3867 let rec loop = function
3968 | [] -> raise Exit
40 | TClassDecl c :: _ when c.cl_path = cl_path -> c
69 | TClassDecl c' :: _ when c.cl_path = c'.cl_path -> c'
4170 | _ :: types -> loop types
4271 in
4372 loop com.types
71100 | [] -> [cf,c]
72101 | pairs -> pairs
73102 in
74 let full_pos p = { p with pfile = Path.get_full_path p.pfile } in
103 let full_pos p = if p = null_pos then null_pos else { p with pfile = Path.get_full_path p.pfile } in
75104 if find_descendants then
76105 let extends child_cls (_,c) = extends child_cls c in
77106 List.fold_left (fun acc t ->
79108 | TClassDecl child_cls when List.exists (extends child_cls) field_class_pairs ->
80109 (try
81110 let cf = PMap.find cf.cf_name child_cls.cl_fields in
82 (name,full_pos cf.cf_name_pos,SKField (cf,Some child_cls.cl_path)) :: acc
111 (name,full_pos cf.cf_name_pos,SKField (cf,Some child_cls)) :: acc
83112 with Not_found -> acc
84113 )
85114 | _ ->
86115 acc
87116 ) [] com.types
88117 else
89 List.map (fun (cf,c) -> name,full_pos cf.cf_name_pos,SKField (cf,Some c.cl_path)) field_class_pairs;
118 List.map (fun (cf,c) -> name,full_pos cf.cf_name_pos,SKField (cf,Some c)) field_class_pairs;
90119 in
91120 (try collect()
92121 with Exit -> [name,pos,kind])
98127 List.fold_left (fun acc (_,p,_) ->
99128 if p = null_pos then acc
100129 else Statistics.SFPos p :: acc
101 ) [] (collect_reference_positions com)
130 ) [] (collect_reference_positions com (Display.ReferencePosition.get ()))
102131 in
103132 let usages = find_references tctx com with_definition pos_filters in
104133 let usages =
11 open Ast
22 open DisplayPosition
33 open Common
4 open Type
5 open Error
46 open Typecore
57
68 type import_display_kind =
5254 let r = PMap.find p ctx.m.curmod.m_extra.m_display.m_import_positions in
5355 r := true
5456 with Not_found ->
55 ()
57 ()
58
59 let commit_import ctx path mode p =
60 ctx.m.import_statements <- (path,mode) :: ctx.m.import_statements;
61 if Filename.basename p.pfile <> "import.hx" then add_import_position ctx p path
62
63 let init_import ctx context_init path mode p =
64 let rec loop acc = function
65 | x :: l when is_lower_ident (fst x) -> loop (x::acc) l
66 | rest -> List.rev acc, rest
67 in
68 let pack, rest = loop [] path in
69 (match rest with
70 | [] ->
71 (match mode with
72 | IAll ->
73 ctx.m.wildcard_packages <- (List.map fst pack,p) :: ctx.m.wildcard_packages
74 | _ ->
75 (match List.rev path with
76 (* p spans `import |` (to the display position), so we take the pmax here *)
77 | [] -> DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue true) CRImport (DisplayTypes.make_subject None {p with pmin = p.pmax})
78 | (_,p) :: _ -> Error.typing_error "Module name must start with an uppercase letter" p))
79 | (tname,p2) :: rest ->
80 let p1 = (match pack with [] -> p2 | (_,p1) :: _ -> p1) in
81 let p_type = punion p1 p2 in
82 let md = ctx.g.do_load_module ctx (List.map fst pack,tname) p_type in
83 let types = md.m_types in
84 let no_private (t,_) = not (t_infos t).mt_private in
85 let error_private p = typing_error "Importing private declarations from a module is not allowed" p in
86 let chk_private t p = if ctx.m.curmod != (t_infos t).mt_module && (t_infos t).mt_private then error_private p in
87 let has_name name t = snd (t_infos t).mt_path = name in
88
89 let fail_usefully name p =
90 let target_kind,candidates = match String.get name 0 with
91 (* TODO: cleaner way to get module fields? *)
92 | 'a'..'z' -> "field", PMap.foldi (fun n _ acc -> n :: acc) (try (Option.get md.m_statics).cl_statics with | _ -> PMap.empty) []
93 | _ -> "type", List.map (fun mt -> snd (t_infos mt).mt_path) types
94 in
95 typing_error (StringError.string_error name
96 candidates
97 ("Module " ^ s_type_path md.m_path ^ " does not define " ^ target_kind ^ " " ^ name)
98 ) p
99 in
100
101 let find_type tname = List.find (has_name tname) types in
102 let get_type tname =
103 let t = try
104 find_type tname
105 with Not_found ->
106 fail_usefully tname p_type
107 in
108 chk_private t p_type;
109 t
110 in
111 let rebind t name p =
112 if not (name.[0] >= 'A' && name.[0] <= 'Z') then
113 typing_error "Type aliases must start with an uppercase letter" p;
114 let _, _, f = ctx.g.do_build_instance ctx t p_type in
115 (* create a temp private typedef, does not register it in module *)
116 let t_path = (fst md.m_path @ ["_" ^ snd md.m_path],name) in
117 let t_type = f (extract_param_types (t_infos t).mt_params) in
118 let mt = TTypeDecl {(mk_typedef ctx.m.curmod t_path p p t_type) with
119 t_private = true;
120 t_params = (t_infos t).mt_params
121 } in
122 if ctx.is_display_file && DisplayPosition.display_position#enclosed_in p then
123 DisplayEmitter.display_module_type ctx mt p;
124 mt
125 in
126 let add_static_init t name s =
127 let name = (match name with None -> s | Some (n,_) -> n) in
128 match resolve_typedef t with
129 | TClassDecl c | TAbstractDecl {a_impl = Some c} ->
130 ignore(c.cl_build());
131 ignore(PMap.find s c.cl_statics);
132 ctx.m.module_globals <- PMap.add name (TClassDecl c,s,p) ctx.m.module_globals
133 | TEnumDecl e ->
134 ignore(PMap.find s e.e_constrs);
135 ctx.m.module_globals <- PMap.add name (TEnumDecl e,s,p) ctx.m.module_globals
136 | _ ->
137 raise Not_found
138 in
139 (match mode with
140 | INormal | IAsName _ ->
141 let name = (match mode with IAsName n -> Some n | _ -> None) in
142 (match rest with
143 | [] ->
144 (match name with
145 | None ->
146 ctx.m.module_imports <- List.filter no_private (List.map (fun t -> t,p) types) @ ctx.m.module_imports;
147 Option.may (fun c ->
148 context_init#add (fun () ->
149 ignore(c.cl_build());
150 List.iter (fun cf ->
151 if has_class_field_flag cf CfPublic then
152 ctx.m.module_globals <- PMap.add cf.cf_name (TClassDecl c,cf.cf_name,p) ctx.m.module_globals
153 ) c.cl_ordered_statics
154 );
155 ) md.m_statics
156 | Some(newname,pname) ->
157 ctx.m.module_imports <- (rebind (get_type tname) newname pname,p) :: ctx.m.module_imports);
158 | [tsub,p2] ->
159 let pu = punion p1 p2 in
160 (try
161 let tsub = List.find (has_name tsub) types in
162 chk_private tsub pu;
163 ctx.m.module_imports <- ((match name with None -> tsub | Some(n,pname) -> rebind tsub n pname),p) :: ctx.m.module_imports
164 with Not_found ->
165 (* this might be a static property, wait later to check *)
166 let find_main_type_static () =
167 try
168 let tmain = find_type tname in
169 begin try
170 add_static_init tmain name tsub
171 with Not_found ->
172 let parent,target_kind,candidates = match resolve_typedef tmain with
173 | TClassDecl c ->
174 "Class<" ^ (s_type_path c.cl_path) ^ ">",
175 "field",
176 PMap.foldi (fun name _ acc -> name :: acc) c.cl_statics []
177 | TAbstractDecl {a_impl = Some c} ->
178 "Abstract<" ^ (s_type_path md.m_path) ^ ">",
179 "field",
180 PMap.foldi (fun name _ acc -> name :: acc) c.cl_statics []
181 | TEnumDecl e ->
182 "Enum<" ^ s_type_path md.m_path ^ ">",
183 "field",
184 PMap.foldi (fun name _ acc -> name :: acc) e.e_constrs []
185 | _ ->
186 "Module " ^ s_type_path md.m_path,
187 "field or subtype",
188 (* TODO: cleaner way to get module fields? *)
189 PMap.foldi (fun n _ acc -> n :: acc) (try (Option.get md.m_statics).cl_statics with | _ -> PMap.empty) []
190 in
191
192 display_error ctx.com (StringError.string_error tsub candidates (parent ^ " has no " ^ target_kind ^ " " ^ tsub)) p
193 end
194 with Not_found ->
195 fail_usefully tsub p
196 in
197 context_init#add (fun() ->
198 match md.m_statics with
199 | Some c ->
200 (try
201 ignore(c.cl_build());
202 let rec loop fl =
203 match fl with
204 | [] -> raise Not_found
205 | cf :: rest ->
206 if cf.cf_name = tsub then
207 if not (has_class_field_flag cf CfPublic) then
208 error_private p
209 else
210 let imported_name = match name with None -> tsub | Some (n,pname) -> n in
211 ctx.m.module_globals <- PMap.add imported_name (TClassDecl c,tsub,p) ctx.m.module_globals;
212 else
213 loop rest
214 in
215 loop c.cl_ordered_statics
216 with Not_found ->
217 find_main_type_static ())
218 | None ->
219 find_main_type_static ()
220 )
221 )
222 | (tsub,p2) :: (fname,p3) :: rest ->
223 (match rest with
224 | [] -> ()
225 | (n,p) :: _ -> typing_error ("Unexpected " ^ n) p);
226 let tsub = get_type tsub in
227 context_init#add (fun() ->
228 try
229 add_static_init tsub name fname
230 with Not_found ->
231 display_error ctx.com (s_type_path (t_infos tsub).mt_path ^ " has no field " ^ fname) (punion p p3)
232 );
233 )
234 | IAll ->
235 let t = (match rest with
236 | [] -> get_type tname
237 | [tsub,_] -> get_type tsub
238 | _ :: (n,p) :: _ -> typing_error ("Unexpected " ^ n) p
239 ) in
240 context_init#add (fun() ->
241 match resolve_typedef t with
242 | TClassDecl c
243 | TAbstractDecl {a_impl = Some c} ->
244 ignore(c.cl_build());
245 PMap.iter (fun _ cf -> if not (has_meta Meta.NoImportGlobal cf.cf_meta) then ctx.m.module_globals <- PMap.add cf.cf_name (TClassDecl c,cf.cf_name,p) ctx.m.module_globals) c.cl_statics
246 | TEnumDecl e ->
247 PMap.iter (fun _ c -> if not (has_meta Meta.NoImportGlobal c.ef_meta) then ctx.m.module_globals <- PMap.add c.ef_name (TEnumDecl e,c.ef_name,p) ctx.m.module_globals) e.e_constrs
248 | _ ->
249 typing_error "No statics to import from this type" p
250 )
251 ))
252
253 let handle_using ctx path p =
254 let t = match List.rev path with
255 | (s1,_) :: (s2,_) :: sl ->
256 if is_lower_ident s2 then mk_type_path ((List.rev (s2 :: List.map fst sl)),s1)
257 else mk_type_path ~sub:s1 (List.rev (List.map fst sl),s2)
258 | (s1,_) :: sl ->
259 mk_type_path (List.rev (List.map fst sl),s1)
260 | [] ->
261 DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue true) CRUsing (DisplayTypes.make_subject None {p with pmin = p.pmax});
262 in
263 let types = (match t.tsub with
264 | None ->
265 let md = ctx.g.do_load_module ctx (t.tpackage,t.tname) p in
266 let types = List.filter (fun t -> not (t_infos t).mt_private) md.m_types in
267 Option.map_default (fun c -> (TClassDecl c) :: types) types md.m_statics
268 | Some _ ->
269 let t = ctx.g.do_load_type_def ctx p t in
270 [t]
271 ) in
272 (* delay the using since we need to resolve typedefs *)
273 let filter_classes types =
274 let rec loop acc types = match types with
275 | td :: l ->
276 (match resolve_typedef td with
277 | TClassDecl c | TAbstractDecl({a_impl = Some c}) ->
278 loop ((c,p) :: acc) l
279 | td ->
280 loop acc l)
281 | [] ->
282 acc
283 in
284 loop [] types
285 in
286 types,filter_classes
287
288 let init_using ctx context_init path p =
289 let types,filter_classes = handle_using ctx path p in
290 (* do the import first *)
291 ctx.m.module_imports <- (List.map (fun t -> t,p) types) @ ctx.m.module_imports;
292 context_init#add (fun() -> ctx.m.module_using <- filter_classes types @ ctx.m.module_using)
9898 | _,None -> raise Not_found
9999 in
100100 let var_decl v = declare (SKVariable v) v.v_pos in
101 let patch_string_pos p s = { p with pmin = p.pmax - String.length s } in
102101 let related_fields = Hashtbl.create 0 in
103102 let field_reference co cf p =
104103 let p1 = patch_string_pos p cf.cf_name in
234233 if (has_class_flag c CInterface) then
235234 collect_implementations c;
236235 let field cf =
237 if cf.cf_pos.pmin > c.cl_name_pos.pmin then declare (SKField (cf,Some c.cl_path)) cf.cf_name_pos;
236 if cf.cf_pos.pmin > c.cl_name_pos.pmin then declare (SKField (cf,Some c)) cf.cf_name_pos;
238237 if with_expressions then begin
239238 let _ = follow cf.cf_type in
240239 match cf.cf_expr with None -> () | Some e -> collect_references c e
5555 begin match e with
5656 | EConst(Ident s) ->
5757 check KIdent s
58 | EField(e1,s) ->
58 | EField(e1,s,_) ->
5959 expr e1;
6060 check KAnyField s;
6161 | EVars vl ->
159159 ) decls
160160
161161 let explore_uncached_modules tctx cs symbols =
162 let open CompilationCache in
162163 DisplayToplevel.init_or_update_server cs tctx.com ["display";"references"];
163 let cc = CommonCache.get_cache cs tctx.com in
164 let cc = CommonCache.get_cache tctx.com in
164165 let files = cc#get_files in
165166 let modules = cc#get_modules in
166167 let t = Timer.timer ["display";"references";"candidates"] in
167168 let acc = Hashtbl.fold (fun file_key cfile acc ->
168 let module_name = CompilationServer.get_module_name_of_cfile cfile.CompilationServer.c_file_path cfile in
169 let module_name = get_module_name_of_cfile cfile.c_file_path cfile in
169170 if Hashtbl.mem modules (cfile.c_package,module_name) then
170171 acc
171172 else try
00 open Globals
1 open CompilationServer
1 open CompilationCache
22 open Common
33 open Type
44 open Genjson
9292 let size v =
9393 fmt_size (mem_size v)
9494
95 let get_memory_json (cs : CompilationServer.t) mreq =
95 let get_memory_json (cs : CompilationCache.t) mreq =
9696 begin match mreq with
9797 | MCache ->
9898 let old_gc = Gc.get() in
236236 let mem = Gc.stat() in
237237 print ("Total Allocated Memory " ^ fmt_size (mem.Gc.heap_words * (Sys.word_size asr 8)));
238238 print ("Free Memory " ^ fmt_size (mem.Gc.free_words * (Sys.word_size asr 8)));
239 (match get() with
240 | None ->
241 print "No cache found";
242 | Some c ->
243 print ("Total cache size " ^ size c);
244 (* print (" haxelib " ^ size c.c_haxelib); *)
245 (* print (" parsed ast " ^ size c.c_files ^ " (" ^ string_of_int (Hashtbl.length c.c_files) ^ " files stored)"); *)
246 (* print (" typed modules " ^ size c.c_modules ^ " (" ^ string_of_int (Hashtbl.length c.c_modules) ^ " modules stored)"); *)
247 let module_list = c#get_modules in
248 let all_modules = List.fold_left (fun acc m -> PMap.add m.m_id m acc) PMap.empty module_list in
249 let modules = List.fold_left (fun acc m ->
250 let (size,r) = get_module_memory c all_modules m in
251 (m,size,r) :: acc
252 ) [] module_list in
253 let cur_key = ref "" and tcount = ref 0 and mcount = ref 0 in
254 List.iter (fun (m,size,(reached,deps,out,leaks)) ->
255 let key = m.m_extra.m_sign in
256 if key <> !cur_key then begin
257 print (Printf.sprintf (" --- CONFIG %s ----------------------------") (Digest.to_hex key));
258 cur_key := key;
259 end;
260 print (Printf.sprintf " %s : %s" (s_type_path m.m_path) (fmt_size size));
261 (if reached then try
262 incr mcount;
263 let lcount = ref 0 in
264 let leak l =
265 incr lcount;
266 incr tcount;
267 print (Printf.sprintf " LEAK %s" l);
268 if !lcount >= 3 && !tcount >= 100 && not verbose then begin
269 print (Printf.sprintf " ...");
270 raise Exit;
271 end;
272 in
273 List.iter leak leaks;
274 with Exit ->
275 ());
276 if verbose then begin
277 print (Printf.sprintf " %d total deps" (List.length deps));
278 PMap.iter (fun _ md ->
279 print (Printf.sprintf " dep %s%s" (s_type_path md.m_path) (module_sign key md));
280 ) m.m_extra.m_deps;
281 end;
282 flush stdout
283 ) (List.sort (fun (m1,s1,_) (m2,s2,_) ->
284 let k1 = m1.m_extra.m_sign and k2 = m2.m_extra.m_sign in
285 if k1 = k2 then s1 - s2 else if k1 > k2 then 1 else -1
286 ) modules);
287 if !mcount > 0 then print ("*** " ^ string_of_int !mcount ^ " modules have leaks !");
288 print "Cache dump complete")
239 let c = com.cs in
240 print ("Total cache size " ^ size c);
241 (* print (" haxelib " ^ size c.c_haxelib); *)
242 (* print (" parsed ast " ^ size c.c_files ^ " (" ^ string_of_int (Hashtbl.length c.c_files) ^ " files stored)"); *)
243 (* print (" typed modules " ^ size c.c_modules ^ " (" ^ string_of_int (Hashtbl.length c.c_modules) ^ " modules stored)"); *)
244 let module_list = c#get_modules in
245 let all_modules = List.fold_left (fun acc m -> PMap.add m.m_id m acc) PMap.empty module_list in
246 let modules = List.fold_left (fun acc m ->
247 let (size,r) = get_module_memory c all_modules m in
248 (m,size,r) :: acc
249 ) [] module_list in
250 let cur_key = ref "" and tcount = ref 0 and mcount = ref 0 in
251 List.iter (fun (m,size,(reached,deps,out,leaks)) ->
252 let key = m.m_extra.m_sign in
253 if key <> !cur_key then begin
254 print (Printf.sprintf (" --- CONFIG %s ----------------------------") (Digest.to_hex key));
255 cur_key := key;
256 end;
257 print (Printf.sprintf " %s : %s" (s_type_path m.m_path) (fmt_size size));
258 (if reached then try
259 incr mcount;
260 let lcount = ref 0 in
261 let leak l =
262 incr lcount;
263 incr tcount;
264 print (Printf.sprintf " LEAK %s" l);
265 if !lcount >= 3 && !tcount >= 100 && not verbose then begin
266 print (Printf.sprintf " ...");
267 raise Exit;
268 end;
269 in
270 List.iter leak leaks;
271 with Exit ->
272 ());
273 if verbose then begin
274 print (Printf.sprintf " %d total deps" (List.length deps));
275 PMap.iter (fun _ md ->
276 print (Printf.sprintf " dep %s%s" (s_type_path md.m_path) (module_sign key md));
277 ) m.m_extra.m_deps;
278 end;
279 flush stdout
280 ) (List.sort (fun (m1,s1,_) (m2,s2,_) ->
281 let k1 = m1.m_extra.m_sign and k2 = m2.m_extra.m_sign in
282 if k1 = k2 then s1 - s2 else if k1 > k2 then 1 else -1
283 ) modules);
284 if !mcount > 0 then print ("*** " ^ string_of_int !mcount ^ " modules have leaks !");
285 print "Cache dump complete"
2828 | "true" | "inferredPure" -> Pure
2929 | "false" -> Impure
3030 | "expect" -> ExpectPure p
31 | _ -> error ("Unsupported purity value " ^ s ^ ", expected true or false") p
31 | _ -> typing_error ("Unsupported purity value " ^ s ^ ", expected true or false") p
3232 end
3333 | (_,[],_) ->
3434 Pure
3535 | (_,_,p) ->
36 error "Unsupported purity value" p
36 typing_error "Unsupported purity value" p
3737 end
3838 with Not_found ->
3939 MaybePure
5959
6060 type typer_module = {
6161 curmod : module_def;
62 mutable module_types : (module_type * pos) list;
62 mutable module_imports : (module_type * pos) list;
6363 mutable module_using : (tclass * pos) list;
6464 mutable module_globals : (string, (module_type * string * pos)) PMap.t;
6565 mutable wildcard_packages : (string list * pos) list;
66 mutable module_imports : import list;
66 mutable import_statements : import list;
6767 }
6868
6969 type typer_globals = {
70 types_module : (path, path) Hashtbl.t;
71 modules : (path , module_def) Hashtbl.t;
7270 mutable delayed : (typer_pass * (unit -> unit) list) list;
7371 mutable debug_delayed : (typer_pass * ((unit -> unit) * string * typer) list) list;
7472 doinline : bool;
73 retain_meta : bool;
7574 mutable core_api : typer option;
7675 mutable macros : ((unit -> unit) * typer) option;
7776 mutable std : module_def;
78 mutable hook_generate : (unit -> unit) list;
7977 type_patches : (path, (string * bool, type_patch) Hashtbl.t * type_patch) Hashtbl.t;
8078 mutable global_metadata : (string list * metadata_entry * (bool * bool * bool)) list;
8179 mutable module_check_policies : (string list * module_check_policy list * bool) list;
8381 (* Indicates that Typer.create() finished building this instance *)
8482 mutable complete : bool;
8583 mutable type_hints : (module_def_display * pos * t) list;
84 mutable load_only_cached_modules : bool;
85 functional_interface_lut : (path,tclass_field) lookup;
8686 (* api *)
8787 do_inherit : typer -> Type.tclass -> pos -> (bool * placed_type_path) -> bool;
8888 do_create : Common.context -> typer;
9090 do_load_macro : typer -> bool -> path -> string -> pos -> ((string * bool * t) list * t * tclass * Type.tclass_field);
9191 do_load_module : typer -> path -> pos -> module_def;
9292 do_load_type_def : typer -> pos -> type_path -> module_type;
93 do_optimize : typer -> texpr -> texpr;
94 do_build_instance : typer -> module_type -> pos -> ((string * t) list * path * (t list -> t));
93 do_build_instance : typer -> module_type -> pos -> (typed_type_param list * path * (t list -> t));
9594 do_format_string : typer -> string -> pos -> Ast.expr;
96 do_finalize : typer -> unit;
97 do_generate : typer -> (texpr option * module_type list * module_def list);
9895 do_load_core_class : typer -> tclass -> tclass;
9996 }
10097
105102 g : typer_globals;
106103 mutable bypass_accessor : int;
107104 mutable meta : metadata;
108 mutable this_stack : texpr list;
109105 mutable with_type_stack : WithType.t list;
110106 mutable call_argument_stack : expr list list;
111107 (* variable *)
116112 (* per-class *)
117113 mutable curclass : tclass;
118114 mutable tthis : t;
119 mutable type_params : (string * t) list;
115 mutable type_params : type_params;
120116 mutable get_build_infos : unit -> (module_type * t list * class_field list) option;
121117 (* per-function *)
118 mutable allow_inline : bool;
119 mutable allow_transform : bool;
122120 mutable curfield : tclass_field;
123121 mutable untyped : bool;
124122 mutable in_function : bool;
125123 mutable in_loop : bool;
126124 mutable in_display : bool;
127 mutable in_macro : bool;
128125 mutable macro_depth : int;
129126 mutable curfun : current_fun;
130127 mutable ret : t;
136133 mutable delayed_display : DisplayTypes.display_exception_kind option;
137134 mutable monomorphs : monomorphs;
138135 (* events *)
139 mutable on_error : typer -> string -> pos -> unit;
140136 memory_marker : float array;
141137 }
142138
172168 (* The expression on which the field is accessed. For abstracts, this is a type expression
173169 to the implementation class. *)
174170 fa_on : texpr;
175 (* The field being accessed. *)
171 (* The field being accessed. Note that in case of overloads, this might refer to the main field which
172 hosts other overloads in its cf_overloads. *)
176173 fa_field : tclass_field;
177174 (* The host of the field. *)
178175 fa_host : field_host;
189186 se_access : field_access;
190187 }
191188
189 type dot_path_part_case =
190 | PUppercase
191 | PLowercase
192
193 type dot_path_part = {
194 name : string;
195 case : dot_path_part_case;
196 pos : pos
197 }
198
192199 exception Forbid_package of (string * path * pos) * pos list * string
193200
194 exception WithTypeError of error_msg * pos
201 exception WithTypeError of error_msg * pos * int (* depth *)
195202
196203 let memory_marker = [|Unix.time()|]
197204
202209 let type_block_ref : (typer -> expr list -> WithType.t -> pos -> texpr) ref = ref (fun _ _ _ _ -> die "" __LOC__)
203210 let unify_min_ref : (typer -> texpr list -> t) ref = ref (fun _ _ -> die "" __LOC__)
204211 let unify_min_for_type_source_ref : (typer -> texpr list -> WithType.with_type_source option -> t) ref = ref (fun _ _ _ -> die "" __LOC__)
205 let analyzer_run_on_expr_ref : (Common.context -> texpr -> texpr) ref = ref (fun _ _ -> die "" __LOC__)
212 let analyzer_run_on_expr_ref : (Common.context -> string -> texpr -> texpr) ref = ref (fun _ _ _ -> die "" __LOC__)
206213 let cast_or_unify_raise_ref : (typer -> ?uctx:unification_context option -> Type.t -> texpr -> pos -> texpr) ref = ref (fun _ ?uctx _ _ _ -> assert false)
207 let type_generic_function_ref : (typer -> field_access -> texpr list -> expr list -> WithType.t -> pos -> texpr) ref = ref (fun _ _ _ _ _ _ -> assert false)
214 let type_generic_function_ref : (typer -> field_access -> (unit -> texpr) field_call_candidate -> WithType.t -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> assert false)
208215
209216 let pass_name = function
210217 | PBuildModule -> "build-module"
215222 | PForce -> "force"
216223 | PFinal -> "final"
217224
218 let display_error ctx msg p = match ctx.com.display.DisplayMode.dms_error_policy with
219 | DisplayMode.EPShow | DisplayMode.EPIgnore -> ctx.on_error ctx msg p
220 | DisplayMode.EPCollect -> add_diagnostics_message ctx.com msg p DisplayTypes.DiagnosticsKind.DKCompilerError DisplayTypes.DiagnosticsSeverity.Error
225 let warning ?(depth=0) ctx w msg p =
226 let options = (Warning.from_meta ctx.curclass.cl_meta) @ (Warning.from_meta ctx.curfield.cf_meta) in
227 ctx.com.warning ~depth w options msg p
221228
222229 let make_call ctx e el t p = (!make_call_ref) ctx e el t p
223230
250257
251258 let raise_or_display ctx l p =
252259 if ctx.untyped then ()
253 else if ctx.in_call_args then raise (WithTypeError(Unify l,p))
254 else display_error ctx (error_msg (Unify l)) p
260 else if ctx.in_call_args then raise (WithTypeError(Unify l,p,0))
261 else located_display_error ctx.com (error_msg p (Unify l))
255262
256263 let raise_or_display_message ctx msg p =
257 if ctx.in_call_args then raise (WithTypeError (Custom msg,p))
258 else display_error ctx msg p
264 if ctx.in_call_args then raise (WithTypeError (Custom msg,p,0))
265 else display_error ctx.com msg p
259266
260267 let unify ctx t1 t2 p =
261268 try
264271 Unify_error l ->
265272 raise_or_display ctx l p
266273
267 let unify_raise_custom uctx (ctx : typer) t1 t2 p =
274 let unify_raise_custom uctx t1 t2 p =
268275 try
269276 Type.unify_custom uctx t1 t2
270277 with
271278 Unify_error l ->
272279 (* no untyped check *)
273 raise (Error (Unify l,p))
280 raise (Error (Unify l,p,0))
274281
275282 let unify_raise = unify_raise_custom default_unification_context
276283
281288 let add_local ctx k n t p =
282289 let v = alloc_var k n t p in
283290 if Define.defined ctx.com.defines Define.WarnVarShadowing && n <> "_" then begin
284 try
285 let v' = PMap.find n ctx.locals in
286 (* ignore std lib *)
287 if not (List.exists (ExtLib.String.starts_with p.pfile) ctx.com.std_path) then begin
288 ctx.com.warning "This variable shadows a previously declared variable" p;
289 ctx.com.warning (compl_msg "Previous variable was here") v'.v_pos
291 match k with
292 | VUser _ ->
293 begin try
294 let v' = PMap.find n ctx.locals in
295 (* ignore std lib *)
296 if not (List.exists (ExtLib.String.starts_with p.pfile) ctx.com.std_path) then begin
297 warning ctx WVarShadow "This variable shadows a previously declared variable" p;
298 warning ~depth:1 ctx WVarShadow (compl_msg "Previous variable was here") v'.v_pos
299 end
300 with Not_found ->
301 ()
290302 end
291 with Not_found ->
303 | _ ->
292304 ()
293305 end;
294306 ctx.locals <- PMap.add n v ctx.locals;
296308
297309 let display_identifier_error ctx ?prepend_msg msg p =
298310 let prepend = match prepend_msg with Some s -> s ^ " " | _ -> "" in
299 display_error ctx (prepend ^ msg) p
311 display_error ctx.com (prepend ^ msg) p
300312
301313 let check_identifier_name ?prepend_msg ctx name kind p =
302314 if starts_with name '$' then
323335 try
324336 List.iter (fun part -> Path.check_package_name part) pack;
325337 with Failure msg ->
326 display_error ctx ("\"" ^ (StringHelper.s_escape (String.concat "." pack)) ^ "\" is not a valid package name:") p;
327 display_error ctx msg p
338 display_error ctx.com ("\"" ^ (StringHelper.s_escape (String.concat "." pack)) ^ "\" is not a valid package name:") p;
339 display_error ctx.com msg p
328340
329341 let check_local_variable_name ctx name origin p =
330342 match name with
348360 let gen_local_prefix = "`"
349361
350362 let gen_local ctx t p =
351 (* ensure that our generated local does not mask an existing one *)
352 let rec loop n =
353 let nv = (if n = 0 then gen_local_prefix else gen_local_prefix ^ string_of_int n) in
354 if PMap.mem nv ctx.locals then
355 loop (n+1)
356 else
357 nv
358 in
359 add_local ctx VGenerated (loop 0) t p
363 add_local ctx VGenerated "`" t p
360364
361365 let is_gen_local v =
362366 String.unsafe_get v.v_name 0 = String.unsafe_get gen_local_prefix 0
384388 (p,[f]) :: (p2,l) :: rest
385389 in
386390 ctx.g.delayed <- loop ctx.g.delayed
391
392 let delay_if_mono ctx p t f = match follow t with
393 | TMono _ ->
394 delay ctx p f
395 | _ ->
396 f()
387397
388398 let rec flush_pass ctx p (where:string) =
389399 match ctx.g.delayed with
411421 r := lazy_available t;
412422 t
413423 with
414 | Error (m,p) ->
415 raise (Fatal_error ((error_msg m),p))
424 | Error (m,p,depth) ->
425 raise (Fatal_error ((error_msg p m),depth))
416426 );
417427 if force then delay ctx PForce (fun () -> ignore(lazy_type r));
418428 r
432442 Hashtbl.add fake_modules key mdep;
433443 mdep
434444 ) in
435 Hashtbl.replace ctx.g.modules mdep.m_path mdep;
445 ctx.com.module_lut#add mdep.m_path mdep;
436446 mdep
437447
438 let push_this ctx e = match e.eexpr with
439 | TConst ((TInt _ | TFloat _ | TString _ | TBool _) as ct) ->
440 (EConst (tconst_to_const ct),e.epos),fun () -> ()
441 | _ ->
442 ctx.this_stack <- e :: ctx.this_stack;
443 let er = EMeta((Meta.This,[],e.epos), (EConst(Ident "this"),e.epos)),e.epos in
444 er,fun () -> ctx.this_stack <- List.tl ctx.this_stack
445
446 let is_removable_field ctx f =
448 let is_removable_field com f =
447449 not (has_class_field_flag f CfOverride) && (
448450 has_class_field_flag f CfExtern || has_class_field_flag f CfGeneric
449451 || (match f.cf_kind with
450452 | Var {v_read = AccRequire (s,_)} -> true
451 | Method MethMacro -> not ctx.in_macro
453 | Method MethMacro -> not com.is_macro_context
452454 | _ -> false)
453455 )
454456
471473 in
472474 let rec expr_path acc e =
473475 match fst e with
474 | EField (e,f) -> expr_path (f :: acc) e
476 | EField (e,f,_) -> expr_path (f :: acc) e
475477 | EConst (Ident n) -> n :: acc
476478 | _ -> []
477479 in
509511 in
510512 loop c.cl_meta || loop f.cf_meta
511513 in
512 let cur_paths = ref [] in
514 let module_path = ctx.curclass.cl_module.m_path in
515 let cur_paths = ref [fst module_path @ [snd module_path], false] in
513516 let rec loop c is_current_path =
514517 cur_paths := (make_path c ctx.curfield, is_current_path) :: !cur_paths;
515518 begin match c.cl_super with
526529 || (
527530 (* if our common ancestor declare/override the field, then we can access it *)
528531 let allowed f = extends ctx.curclass c || (List.exists (has Meta.Allow c f) !cur_paths) in
529 if is_constr
530 then (match c.cl_constructor with
532 if is_constr then (
533 match c.cl_constructor with
531534 | Some cf ->
532535 if allowed cf then true
533536 else if cf.cf_expr = None then false (* maybe it's an inherited auto-generated constructor *)
534537 else raise Not_found
535538 | _ -> false
536 )
537 else try allowed (PMap.find cf.cf_name (if stat then c.cl_statics else c.cl_fields)) with Not_found -> false
539 ) else
540 try allowed (PMap.find cf.cf_name (if stat then c.cl_statics else c.cl_fields))
541 with Not_found -> false
538542 )
539543 || (match c.cl_super with
540544 | Some (csup,_) -> loop csup
551555
552556 let check_field_access ctx c f stat p =
553557 if not ctx.untyped && not (can_access ctx c f stat) then
554 display_error ctx ("Cannot access private field " ^ f.cf_name) p
558 display_error ctx.com ("Cannot access private field " ^ f.cf_name) p
555559
556560 (** removes the first argument of the class field's function type and all its overloads *)
557561 let prepare_using_field cf = match follow cf.cf_type with
558562 | TFun((_,_,tf) :: args,ret) ->
559563 let rec loop acc overloads = match overloads with
560564 | ({cf_type = TFun((_,_,tfo) :: args,ret)} as cfo) :: l ->
561 let tfo = apply_params cfo.cf_params (List.map snd cfo.cf_params) tfo in
565 let tfo = apply_params cfo.cf_params (extract_param_types cfo.cf_params) tfo in
562566 (* ignore overloads which have a different first argument *)
563567 if type_iseq tf tfo then loop ({cfo with cf_type = TFun(args,ret)} :: acc) l else loop acc l
564568 | _ :: l ->
585589 end
586590 | _ -> ())
587591
592 let field_to_type_path com e =
593 let rec loop e pack name = match e with
594 | EField(e,f,_),p when Char.lowercase (String.get f 0) <> String.get f 0 -> (match name with
595 | [] | _ :: [] ->
596 loop e pack (f :: name)
597 | _ -> (* too many name paths *)
598 display_error com ("Unexpected " ^ f) p;
599 raise Exit)
600 | EField(e,f,_),_ ->
601 loop e (f :: pack) name
602 | EConst(Ident f),_ ->
603 let pack, name, sub = match name with
604 | [] ->
605 let fchar = String.get f 0 in
606 if Char.uppercase fchar = fchar then
607 pack, f, None
608 else begin
609 display_error com "A class name must start with an uppercase letter" (snd e);
610 raise Exit
611 end
612 | [name] ->
613 f :: pack, name, None
614 | [name; sub] ->
615 f :: pack, name, Some sub
616 | _ ->
617 die "" __LOC__
618 in
619 { tpackage=pack; tname=name; tparams=[]; tsub=sub }
620 | _,pos ->
621 display_error com "Unexpected expression when building strict meta" pos;
622 raise Exit
623 in
624 loop e [] []
625
588626 let safe_mono_close ctx m p =
589627 try
590628 Monomorph.close m
610648 "fc_type",s_type pctx fcc.fc_type;
611649 "fc_field",Printf.sprintf "%s: %s" fcc.fc_field.cf_name (s_type pctx fcc.fc_field.cf_type)
612650 ]
651
652
653 let relative_path ctx file =
654 let slashes path = String.concat "/" (ExtString.String.nsplit path "\\") in
655 let fpath = slashes (Path.get_full_path file) in
656 let fpath_lower = String.lowercase fpath in
657 let flen = String.length fpath_lower in
658 let rec loop = function
659 | [] -> file
660 | path :: l ->
661 let spath = String.lowercase (slashes path) in
662 let slen = String.length spath in
663 if slen > 0 && slen < flen && String.sub fpath_lower 0 slen = spath then String.sub fpath slen (flen - slen) else loop l
664 in
665 loop ctx.com.Common.class_path
666
667 let mk_infos ctx p params =
668 let file = if ctx.com.is_macro_context then p.pfile else if Common.defined ctx.com Define.AbsolutePath then Path.get_full_path p.pfile else relative_path ctx p.pfile in
669 (EObjectDecl (
670 (("fileName",null_pos,NoQuotes) , (EConst (String(file,SDoubleQuotes)) , p)) ::
671 (("lineNumber",null_pos,NoQuotes) , (EConst (Int (string_of_int (Lexer.get_error_line p), None)),p)) ::
672 (("className",null_pos,NoQuotes) , (EConst (String (s_type_path ctx.curclass.cl_path,SDoubleQuotes)),p)) ::
673 if ctx.curfield.cf_name = "" then
674 params
675 else
676 (("methodName",null_pos,NoQuotes), (EConst (String (ctx.curfield.cf_name,SDoubleQuotes)),p)) :: params
677 ) ,p)
678
679 let rec is_pos_infos = function
680 | TMono r ->
681 (match r.tm_type with
682 | Some t -> is_pos_infos t
683 | _ -> false)
684 | TLazy f ->
685 is_pos_infos (lazy_type f)
686 | TType ({ t_path = ["haxe"] , "PosInfos" },[]) ->
687 true
688 | TType (t,tl) ->
689 is_pos_infos (apply_typedef t tl)
690 | TAbstract({a_path=[],"Null"},[t]) ->
691 is_pos_infos t
692 | _ ->
693 false
694
695 let is_empty_or_pos_infos args =
696 match args with
697 | [_,true,t] -> is_pos_infos t
698 | [] -> true
699 | _ -> false
700
701 let get_next_stored_typed_expr_id =
702 let uid = ref 0 in
703 (fun() -> incr uid; !uid)
704
705 let get_stored_typed_expr com id =
706 let e = com.stored_typed_exprs#find id in
707 Texpr.duplicate_tvars e
708
709 let store_typed_expr com te p =
710 let id = get_next_stored_typed_expr_id() in
711 com.stored_typed_exprs#add id te;
712 let eid = (EConst (Int (string_of_int id, None))), p in
713 id,((EMeta ((Meta.StoredTypedExpr,[],null_pos), eid)),p)
714
715 let push_this ctx e = match e.eexpr with
716 | TConst ((TInt _ | TFloat _ | TString _ | TBool _) as ct) ->
717 (EConst (tconst_to_const ct),e.epos),fun () -> ()
718 | _ ->
719 let id,er = store_typed_expr ctx.com e e.epos in
720 er,fun () -> ctx.com.stored_typed_exprs#remove id
613721
614722 (* -------------- debug functions to activate when debugging typer passes ------------------------------- *)
615723 (*/*
684792 | [] -> ""
685793 | l -> " ??PENDING[" ^ String.concat ";" (List.map (fun (_,i,_) -> i) l) ^ "]"
686794
687 let display_error ctx msg p =
795 let display_error ctx.com msg p =
688796 debug ctx ("ERROR " ^ msg);
689 display_error ctx msg p
797 display_error ctx.com msg p
798
799 let located_display_error ctx.com msg =
800 debug ctx ("ERROR " ^ msg);
801 located_display_error ctx.com msg
690802
691803 let make_pass ?inf ctx f =
692804 let inf = (match inf with None -> pass_infos ctx ctx.pass | Some inf -> inf) in
747859 r := lazy_available t;
748860 t
749861 with
750 | Error (m,p) ->
751 raise (Fatal_error ((error_msg m),p))
862 | Error (m,p,depth) ->
863 raise (Fatal_error ((error_msg m),p,depth))
752864 ));
753865 if force then delay ctx PForce (fun () -> ignore(lazy_type r));
754866 r
8282 | EMeta((Meta.Custom ":followWithAbstracts",_,_),e1) ->
8383 loop follow_with_abstracts e1;
8484 | _ ->
85 error "Type parameter expected" (pos e)
85 typing_error "Type parameter expected" (pos e)
8686 in
8787 loop (fun t -> t) e
8888 ) el;
8989 let definitive_types = ref [] in
90 let tl = List.map2 (fun (n,_) t ->
90 let tl = List.map2 (fun tp t ->
9191 try
92 let t = (Hashtbl.find relevant n) t in
92 let t = (Hashtbl.find relevant tp.ttp_name) t in
9393 definitive_types := t :: !definitive_types;
9494 t
9595 with Not_found ->
118118 | TAbstract({a_path=([],"Null")} as a,[t1]) ->
119119 TAbstract(a,[loop t1])
120120 | TType (t,tl) ->
121 loop (apply_params t.t_params tl t.t_type)
121 loop (apply_typedef t tl)
122122 | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) ->
123123 if rec_stack_exists (fast_eq t) underlying_type_stack then begin
124124 let pctx = print_context() in
125125 let s = String.concat " -> " (List.map (fun t -> s_type pctx t) (List.rev (t :: underlying_type_stack.rec_stack))) in
126 error ("Abstract chain detected: " ^ s) a.a_pos
126 typing_error ("Abstract chain detected: " ^ s) a.a_pos
127127 end;
128128 get_underlying_type a tl
129129 | _ ->
9090 | OpInterval
9191 | OpArrow
9292 | OpIn
93 | OpNullCoal
9394
9495 type unop =
9596 | Increment
105106 (* | SMarkup *)
106107
107108 type constant =
108 | Int of string
109 | Float of string
109 | Int of string * string option
110 | Float of string * string option
110111 | String of string * string_literal_kind
111112 | Ident of string
112113 | Regexp of string * string
129130 | PClose
130131 | Dot
131132 | DblDot
133 | QuestionDot
132134 | Arrow
133135 | IntInterval of string
134136 | Sharp of string
195197 | DKMarked
196198 | DKPattern of bool
197199
200 and efield_kind =
201 | EFNormal
202 | EFSafe
203
198204 and expr_def =
199205 | EConst of constant
200206 | EArray of expr * expr
201207 | EBinop of binop * expr * expr
202 | EField of expr * string
208 | EField of expr * string * efield_kind
203209 | EParenthesis of expr
204210 | EObjectDecl of ((string * pos * quote_status) * expr) list
205211 | EArrayDecl of expr list
222228 | ECast of expr * type_hint option
223229 | EIs of expr * type_hint
224230 | EDisplay of expr * display_kind
225 | EDisplayNew of placed_type_path
226231 | ETernary of expr * expr * expr
227232 | ECheckType of expr * type_hint
228233 | EMeta of metadata_entry * expr
233238 tp_name : placed_name;
234239 tp_params : type_param list;
235240 tp_constraints : type_hint option;
241 tp_default : type_hint option;
236242 tp_meta : metadata;
237243 }
238244
313319 and evar = {
314320 ev_name : placed_name;
315321 ev_final : bool;
322 ev_static : bool;
316323 ev_type : type_hint option;
317324 ev_expr : expr option;
318325 ev_meta : metadata;
386393 raise (Invalid_argument "Empty module name is not allowed");
387394 { tpackage = pack; tname = name; tsub = sub; tparams = params; }
388395
389 let mk_evar ?(final=false) ?(t:type_hint option) ?eo ?(meta=[]) name =
396 let mk_evar ?(final=false) ?(static=false) ?(t:type_hint option) ?eo ?(meta=[]) name =
390397 {
391398 ev_name = name;
392399 ev_final = final;
400 ev_static = static;
393401 ev_type = t;
394402 ev_expr = eo;
395403 ev_meta = meta;
458466 | x :: l -> List.rev l, x
459467
460468 let s_constant = function
461 | Int s -> s
462 | Float s -> s
469 | Int (s, None) -> s
470 | Int (s, Some suffix) -> s ^ suffix
471 | Float (s, None) -> s
472 | Float (s, Some suffix) -> s ^ suffix
463473 | String(s,qs) ->
464474 begin match qs with
465475 | SDoubleQuotes -> "\"" ^ StringHelper.s_escape s ^ "\""
555565 | OpInterval -> "..."
556566 | OpArrow -> "=>"
557567 | OpIn -> " in "
568 | OpNullCoal -> "??"
558569
559570 let s_unop = function
560571 | Increment -> "++"
582593 | PClose -> ")"
583594 | Dot -> "."
584595 | DblDot -> ":"
596 | QuestionDot -> "?."
585597 | Arrow -> "->"
586598 | IntInterval s -> s ^ "..."
587599 | Sharp s -> "#" ^ s
591603 | Spread -> "..."
592604
593605 exception Invalid_escape_sequence of char * int * (string option)
606
607 let efield (e,s) =
608 EField(e,s,EFNormal)
594609
595610 let unescape s =
596611 let b = Buffer.create 0 in
691706 ),p
692707 and tparamdecl t =
693708 let constraints = opt type_hint t.tp_constraints in
709 let default = opt type_hint t.tp_default in
694710 let params = List.map tparamdecl t.tp_params in
695 { tp_name = t.tp_name; tp_constraints = constraints; tp_params = params; tp_meta = t.tp_meta }
711 { tp_name = t.tp_name; tp_constraints = constraints; tp_default = default; tp_params = params; tp_meta = t.tp_meta }
696712 and func f =
697713 let params = List.map tparamdecl f.f_params in
698714 let args = List.map (fun (n,o,m,t,e) ->
720736 let e1 = loop e1 in
721737 let e2 = loop e2 in
722738 EBinop (op,e1,e2)
723 | EField (e,f) -> EField (loop e, f)
739 | EField (e,f,efk) -> EField (loop e, f, efk)
724740 | EParenthesis e -> EParenthesis (loop e)
725741 | EObjectDecl fl -> EObjectDecl (List.map (fun (k,e) -> k,loop e) fl)
726742 | EArrayDecl el -> EArrayDecl (List.map loop el)
782798 let t = type_hint t in
783799 EIs (e,t)
784800 | EDisplay (e,f) -> EDisplay (loop e,f)
785 | EDisplayNew t -> EDisplayNew (tpath t)
786801 | ETernary (e1,e2,e3) ->
787802 let e1 = loop e1 in
788803 let e2 = loop e2 in
800815 let opt eo = match eo with None -> () | Some e -> loop e in
801816 let exprs = List.iter loop in
802817 match e with
803 | EConst _ | EContinue | EBreak | EDisplayNew _ | EReturn None -> ()
804 | EParenthesis e1 | EField(e1,_) | EUnop(_,_,e1) | EReturn(Some e1) | EThrow e1 | EMeta(_,e1)
818 | EConst _ | EContinue | EBreak | EReturn None -> ()
819 | EParenthesis e1 | EField(e1,_,_) | EUnop(_,_,e1) | EReturn(Some e1) | EThrow e1 | EMeta(_,e1)
805820 | ECheckType(e1,_) | EDisplay(e1,_) | ECast(e1,_) | EIs(e1,_) | EUntyped e1 -> loop e1;
806821 | EArray(e1,e2) | EBinop(_,e1,e2) | EFor(e1,e2) | EWhile(e1,e2,_) | EIf(e1,e2,None) -> loop e1; loop e2;
807822 | ETernary(e1,e2,e3) | EIf(e1,e2,Some e3) -> loop e1; loop e2; loop e3;
841856 | EConst c -> s_constant c
842857 | EArray (e1,e2) -> s_expr_inner tabs e1 ^ "[" ^ s_expr_inner tabs e2 ^ "]"
843858 | EBinop (op,e1,e2) -> s_expr_inner tabs e1 ^ " " ^ s_binop op ^ " " ^ s_expr_inner tabs e2
844 | EField (e,f) -> s_expr_inner tabs e ^ "." ^ f
859 | EField (e,f,efk) -> s_expr_inner tabs e ^ (match efk with EFNormal -> "." | EFSafe -> "?.") ^ f
845860 | EParenthesis e -> "(" ^ (s_expr_inner tabs e) ^ ")"
846861 | EObjectDecl fl -> "{ " ^ (String.concat ", " (List.map (fun ((n,_,qs),e) -> (s_object_key_name n qs) ^ " : " ^ (s_expr_inner tabs e)) fl)) ^ " }"
847862 | EArrayDecl el -> "[" ^ s_expr_list tabs el ", " ^ "]"
876891 | ECheckType (e,(t,_)) -> "(" ^ s_expr_inner tabs e ^ " : " ^ s_complex_type tabs t ^ ")"
877892 | EMeta (m,e) -> s_metadata tabs m ^ " " ^ s_expr_inner tabs e
878893 | EDisplay (e1,dk) -> Printf.sprintf "#DISPLAY(%s, %s)" (s_expr_inner tabs e1) (s_display_kind dk)
879 | EDisplayNew tp -> Printf.sprintf "#DISPLAY_NEW(%s)" (s_complex_type_path tabs tp)
880894 and s_expr_list tabs el sep =
881895 (String.concat sep (List.map (s_expr_inner tabs) el))
882896 and s_complex_type_path tabs (t,_) =
9941008 let rec string_list_of_expr_path_raise (e,p) =
9951009 match e with
9961010 | EConst (Ident i) -> [i]
997 | EField (e,f) -> f :: string_list_of_expr_path_raise e
1011 | EField (e,f,_) -> f :: string_list_of_expr_path_raise e
9981012 | _ -> raise Exit
9991013
10001014 let rec string_pos_list_of_expr_path_raise (e,p) =
10011015 match e with
10021016 | EConst (Ident i) -> [i,p]
1003 | EField (e,f) -> (f,p) :: string_pos_list_of_expr_path_raise e (* wrong p? *)
1017 | EField (e,f,_) -> (f,p) :: string_pos_list_of_expr_path_raise e (* wrong p? *)
10041018 | _ -> raise Exit
10051019
10061020 let expr_of_type_path (sl,s) p =
10081022 | [] -> (EConst(Ident s),p)
10091023 | s1 :: sl ->
10101024 let e1 = (EConst(Ident s1),p) in
1011 let e = List.fold_left (fun e s -> (EField(e,s),p)) e1 sl in
1012 EField(e,s),p
1025 let e = List.fold_left (fun e s -> (efield(e,s),p)) e1 sl in
1026 efield(e,s),p
10131027
10141028 let match_path recursive sl sl_pattern =
1015 let rec loop sl1 sl2 = match sl1,sl2 with
1029 let rec loop top sl1 sl2 = match sl1,sl2 with
10161030 | [],[] ->
10171031 true
10181032 (* always recurse into types of package paths *)
10191033 | (s1 :: s11 :: _),[s2] when is_lower_ident s2 && not (is_lower_ident s11)->
10201034 s1 = s2
1021 | [_],[""] ->
1035 | [_],[] when top ->
10221036 true
1023 | _,([] | [""]) ->
1037 | _,[] ->
10241038 recursive
10251039 | [],_ ->
10261040 false
10271041 | (s1 :: sl1),(s2 :: sl2) ->
1028 s1 = s2 && loop sl1 sl2
1042 s1 = s2 && loop false sl1 sl2
10291043 in
1030 loop sl sl_pattern
1044 loop true sl sl_pattern
10311045
10321046 let full_dot_path2 mpath tpath =
10331047 if mpath = tpath then
10801094 add ("EBinop " ^ (s_binop op));
10811095 loop e1;
10821096 loop e2;
1083 | EField(e1,s) ->
1097 | EField(e1,s,_) ->
10841098 add ("EField " ^ s);
10851099 loop e1
10861100 | EParenthesis e1 ->
11831197 add "ECheckType";
11841198 loop e1;
11851199 | EMeta((m,_,_),e1) ->
1186 add ("EMeta " ^ fst (Meta.get_info m));
1200 add ("EMeta " ^ (Meta.to_string m));
11871201 loop e1
1188 | EDisplayNew _ ->
1189 die "" __LOC__
11901202 in
11911203 loop' "" e;
11921204 Buffer.contents buf
12371249 | [] ->
12381250 []
12391251 in
1240 loop metas
1252 loop metas
1253
1254 let get_meta_string meta key =
1255 let rec loop = function
1256 | [] -> None
1257 | (k,[EConst (String(name,_)),_],_) :: _ when k = key -> Some name
1258 | _ :: l -> loop l
1259 in
1260 loop meta
55 mutable defines_signature : string option;
66 }
77
8 let get_documentation_list() =
8 type user_define = {
9 doc : string;
10 flags : define_parameter list;
11 source : string option;
12 }
13
14 let register_user_define user_defines s data =
15 Hashtbl.replace user_defines s data
16
17 type define_origin =
18 | Compiler
19 | UserDefined of string option
20
21 let infos ?user_defines d = match (user_defines,d) with
22 | (Some(user_defines), Custom(s)) when (Hashtbl.mem user_defines s) ->
23 let infos = Hashtbl.find user_defines s in
24 (s, (infos.doc, infos.flags), (UserDefined infos.source))
25 | (_, Custom(s)) ->
26 (s, ("", []), Compiler)
27 | _ ->
28 let def,infos = DefineList.infos d in
29 (def, infos, Compiler)
30
31 let get_define_key d =
32 match (infos d) with (s,_,_) -> s
33
34 let get_documentation user_defines d =
35 let t, (doc,flags), origin = infos ~user_defines:user_defines d in
36 let params = ref [] and pfs = ref [] in
37 List.iter (function
38 | HasParam s -> params := s :: !params
39 | Platforms fl -> pfs := fl @ !pfs
40 | Link _ -> ()
41 ) flags;
42 let params = (match List.rev !params with
43 | [] -> ""
44 | l -> "<" ^ String.concat ">, <" l ^ "> "
45 ) in
46 let origin = match origin with
47 | UserDefined Some s -> " (from " ^ s ^ ")"
48 | Compiler | UserDefined None -> ""
49 in
50 let pfs = platform_list_help (List.rev !pfs) in
51 (String.concat "-" (ExtString.String.nsplit t "_")), params ^ doc ^ pfs ^ origin
52
53 let get_documentation_list user_defines =
954 let m = ref 0 in
1055 let rec loop i =
1156 let d = Obj.magic i in
1257 if d <> Last then begin
13 let t, (doc,flags) = infos d in
14 let params = ref [] and pfs = ref [] in
15 List.iter (function
16 | HasParam s -> params := s :: !params
17 | Platforms fl -> pfs := fl @ !pfs
18 | Link _ -> ()
19 ) flags;
20 let params = (match List.rev !params with
21 | [] -> ""
22 | l -> "<" ^ String.concat ">, <" l ^ "> "
23 ) in
24 let pfs = platform_list_help (List.rev !pfs) in
25 if String.length t > !m then m := String.length t;
26 ((String.concat "-" (ExtString.String.nsplit t "_")),params ^ doc ^ pfs) :: (loop (i + 1))
58 let (str,desc) = get_documentation user_defines d in
59 if String.length str > !m then m := String.length str;
60 (str,desc) :: loop (i + 1)
2761 end else
2862 []
2963 in
3064 let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in
3165 all,!m
3266
33 let raw_defined ctx v =
34 PMap.mem v ctx.values
67 let get_user_documentation_list user_defines =
68 let m = ref 0 in
69 let user_defines_list = (Hashtbl.fold (fun d _ acc ->
70 let (str,desc) = get_documentation user_defines (Custom d) in
71 if String.length str > !m then m := String.length str;
72 (str,desc) :: acc
73 ) user_defines []) in
3574
36 let defined ctx v =
37 raw_defined ctx (fst (infos v))
75 let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) user_defines_list in
76 all,!m
77
78 let raw_defined ctx k =
79 PMap.mem k ctx.values
80
81 let defined ctx k =
82 raw_defined ctx (get_define_key k)
3883
3984 let raw_defined_value ctx k =
4085 PMap.find k ctx.values
4186
4287 let defined_value ctx v =
43 raw_defined_value ctx (fst (infos v))
88 raw_defined_value ctx (get_define_key v)
4489
4590 let defined_value_safe ?default ctx v =
4691 try defined_value ctx v
4893
4994 let raw_define_value ctx k v =
5095 ctx.values <- PMap.add k v ctx.values;
51 let k = String.concat "_" (ExtString.String.nsplit k "-") in
52 ctx.values <- PMap.add k v ctx.values;
5396 ctx.defines_signature <- None
5497
55 let raw_define ctx v =
56 let k,v = try ExtString.String.split v "=" with _ -> v,"1" in
57 raw_define_value ctx k v
98 let define_value ctx k v =
99 raw_define_value ctx (get_define_key k) v
58100
59 let define_value ctx k v =
60 raw_define ctx (fst (infos k) ^ "=" ^ v)
101 let raw_define ctx k =
102 raw_define_value ctx k "1"
61103
62 let define ctx v =
63 raw_define ctx (fst (infos v))
104 let define ctx k =
105 raw_define_value ctx (get_define_key k) "1"
64106
65107 let get_signature def =
66108 match def.defines_signature with
74116 Note that we should removed flags like use_rtti_doc here.
75117 *)
76118 | "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" | "display_stdin"
119 | "message_reporting" | "messages_log_file" | "messages_log_format" | "no_color"
77120 | "dump" | "dump_dependencies" | "dump_ignore_var_ids" -> acc
78121 | _ -> (k ^ "=" ^ v) :: acc
79122 ) def.values [] in
213213 false,false,false,kind,ctor
214214 | TAbstractDecl a ->
215215 let kind = if a.a_enum then EnumAbstract else Abstract in
216 let is_extern,is_final,is_abstract,ctor = match Abstract.follow_with_forward_ctor (TAbstract(a,List.map snd a.a_params)) with
216 let is_extern,is_final,is_abstract,ctor = match Abstract.follow_with_forward_ctor (TAbstract(a,extract_param_types a.a_params)) with
217217 | TInst(c,_) -> let is_extern,is_final,is_abstract,_,ctor = ctor_info (TClassDecl c) in is_extern,is_final,is_abstract,ctor
218218 | TAbstract(a,_) -> false,false,false,actor a
219219 | _ -> false,false,false,No
222222 in
223223 let is_extern,is_final,is_abstract,kind,ctor = ctor_info mt in
224224 let infos = t_infos mt in
225 let convert_type_param (s,t) = match follow t with
225 let convert_type_param tp = match follow tp.ttp_type with
226226 | TInst(c,_) -> {
227 tp_name = s,null_pos;
227 tp_name = tp.ttp_name,null_pos;
228228 tp_params = [];
229229 tp_constraints = None; (* TODO? *)
230 tp_default = None; (* TODO? *)
230231 tp_meta = c.cl_meta
231232 }
232233 | _ ->
504505 ct_fields = PMap.fold (fun cf acc -> afield cf :: acc) an.a_fields [];
505506 ct_status = !(an.a_status);
506507 }
507 | TDynamic t ->
508 CTDynamic (if t == t_dynamic then None else Some (from_type PMap.empty t))
508 | TDynamic None ->
509 CTDynamic None
510 | TDynamic (Some t) ->
511 CTDynamic (Some (from_type PMap.empty t))
509512 in
510513 from_type values t
511514 end
757760 ]
758761 | ITMetadata meta ->
759762 let open Meta in
760 let name,(doc,params) = Meta.get_info meta in
763 let name,(doc,params),origin = Meta.get_info meta in
761764 let name = "@" ^ name in
762765 let usage_to_string = function
763766 | TClass -> "TClass"
770773 | TExpr -> "TExpr"
771774 | TTypeParameter -> "TTypeParameter"
772775 | TVariable -> "TVariable"
776 in
777 let origin = match origin with
778 | Compiler -> Some "haxe compiler"
779 | UserDefined s -> s
773780 in
774781 let rec loop internal params platforms targets links l = match l with
775782 | HasParam s :: l -> loop internal (s :: params) platforms targets links l
788795 "targets",jlist jstring targets;
789796 "internal",jbool internal;
790797 "links",jlist jstring links;
798 "origin",jopt jstring origin;
791799 ]
792800 | ITKeyword kwd ->"Keyword",jobject [
793801 "name",jstring (s_keyword kwd)
826834 | Some t ->
827835 ("type",CompletionType.to_json ctx (snd t)) :: jindex
828836 )
829 )
837 )
6060 container_name = container_name;
6161 deprecated = deprecated;
6262 }
63 end
64
65 module DiagnosticsSeverity = struct
66 type t =
67 | Error
68 | Warning
69 | Information
70 | Hint
71
72 let to_int = function
73 | Error -> 1
74 | Warning -> 2
75 | Information -> 3
76 | Hint -> 4
77 end
78
79 module DiagnosticsKind = struct
80 type t =
81 | DKUnusedImport
82 | DKUnresolvedIdentifier
83 | DKCompilerError
84 | DKRemovableCode
85 | DKParserError
86 | DKDeprecationWarning
87 | DKInactiveBlock
88 | DKMissingFields
89
90 let to_int = function
91 | DKUnusedImport -> 0
92 | DKUnresolvedIdentifier -> 1
93 | DKCompilerError -> 2
94 | DKRemovableCode -> 3
95 | DKParserError -> 4
96 | DKDeprecationWarning -> 5
97 | DKInactiveBlock -> 6
98 | DKMissingFields -> 7
9963 end
10064
10165 module CompletionResultKind = struct
210174 | DMDefinition
211175 | DMTypeDefinition
212176 | DMImplementation
213 | DMResolve of string
214177 | DMPackage
215178 | DMHover
216179 | DMModuleSymbols of string option
217 | DMDiagnostics of Path.UniqueKey.t list
218 | DMStatistics
219180 | DMSignature
220181
221182 type error_policy =
222183 | EPIgnore
223 | EPCollect
224184 | EPShow
225185
226186 type display_file_policy =
230190
231191 type settings = {
232192 dms_kind : t;
233 dms_display : bool;
234193 dms_full_typing : bool;
235194 dms_force_macro_typing : bool;
236195 dms_error_policy : error_policy;
243202
244203 let default_display_settings = {
245204 dms_kind = DMDefault;
246 dms_display = true;
247205 dms_full_typing = false;
248206 dms_force_macro_typing = false;
249207 dms_error_policy = EPIgnore;
256214
257215 let default_compilation_settings = {
258216 dms_kind = DMNone;
259 dms_display = false;
260217 dms_full_typing = true;
261218 dms_force_macro_typing = true;
262219 dms_error_policy = EPShow;
271228 let settings = { default_display_settings with dms_kind = dm } in
272229 match dm with
273230 | DMNone -> default_compilation_settings
274 | DMDefault | DMDefinition | DMTypeDefinition | DMResolve _ | DMPackage | DMHover | DMSignature -> settings
231 | DMDefault | DMDefinition | DMTypeDefinition | DMPackage | DMHover | DMSignature -> settings
275232 | DMUsage _ | DMImplementation -> { settings with
276233 dms_full_typing = true;
277234 dms_force_macro_typing = true;
284241 dms_force_macro_typing = false;
285242 dms_per_file = true;
286243 }
287 | DMDiagnostics files -> { default_compilation_settings with
288 dms_kind = DMDiagnostics files;
289 dms_error_policy = EPCollect;
290 dms_display_file_policy = if files = [] then DFPNo else DFPAlso;
291 dms_per_file = true;
292 }
293 | DMStatistics -> { settings with
294 dms_full_typing = true;
295 dms_inline = false;
296 dms_display_file_policy = DFPAlso;
297 dms_exit_during_typing = false;
298 dms_force_macro_typing = true;
299 dms_per_file = true;
300 }
301244
302245 let to_string = function
303246 | DMNone -> "none"
305248 | DMDefinition -> "position"
306249 | DMTypeDefinition -> "type-definition"
307250 | DMImplementation -> "implementation"
308 | DMResolve s -> "resolve " ^ s
309251 | DMPackage -> "package"
310252 | DMHover -> "type"
311253 | DMUsage (true,_,_) -> "rename"
312254 | DMUsage (false,_,_) -> "references"
313255 | DMModuleSymbols None -> "module-symbols"
314256 | DMModuleSymbols (Some s) -> "workspace-symbols " ^ s
315 | DMDiagnostics _ -> "diagnostics"
316 | DMStatistics -> "statistics"
317257 | DMSignature -> "signature"
318258 end
319259
323263 | SKEnum of tenum
324264 | SKTypedef of tdef
325265 | SKAbstract of tabstract
326 | SKField of tclass_field * path option (* path - class path *)
266 | SKField of tclass_field * tclass option
327267 | SKConstructor of tclass_field
328268 | SKEnumField of tenum_field
329269 | SKVariable of tvar
391331 mutable import_positions : (pos,bool ref) PMap.t;
392332 mutable dead_blocks : (Path.UniqueKey.t,(pos * expr) list) Hashtbl.t;
393333 mutable unresolved_identifiers : (string * pos * (string * CompletionItem.t * int) list) list;
394 mutable diagnostics_messages : (string * pos * DiagnosticsKind.t * DiagnosticsSeverity.t) list;
334 mutable diagnostics_messages : (string * pos * MessageKind.t * MessageSeverity.t * int (* depth *)) list;
395335 mutable missing_fields : (pos,(module_type * (missing_fields_diagnostics list ref))) PMap.t;
396336 }
397337
398338 type display_exception_kind =
399 | DisplayDiagnostics of diagnostics_context
400 | Statistics of string
401339 | ModuleSymbols of string
402340 | Metadata of string
403 | DisplaySignatures of (((tsignature * CompletionItem.CompletionType.ct_function) * documentation) list * int * int * signature_kind) option
404 | DisplayHover of hover_result option
341 | DisplaySignatures of (((tsignature * CompletionItem.CompletionType.ct_function) * documentation) list * int * int * signature_kind)
342 | DisplayHover of hover_result
405343 | DisplayPositions of pos list
406 | DisplayFields of fields_result option
407 | DisplayPackage of string list
344 | DisplayFields of fields_result
345 | DisplayPackage of string list
346 | DisplayNoResult
77 (targets defineList.ml)
88 (deps ../../src-json/define.json)
99 (action (with-stdout-to defineList.ml (run %{bin:haxe_prebuild} define ../../src-json/define.json)))
10 )
11
12 (rule
13 (targets warningList.ml)
14 (deps ../../src-json/warning.json)
15 (action (with-stdout-to warningList.ml (run %{bin:haxe_prebuild} warning ../../src-json/warning.json)))
1016 )
1616 | Unify of unify_error list
1717 | Custom of string
1818 | Unknown_ident of string
19 | Stack of error_msg * error_msg
19 | Stack of (error_msg * Globals.pos) list
2020 | Call_error of call_error
2121 | No_constructor of module_type
2222 | Abstract_class of module_type
2525 | Private_type
2626 | Not_defined
2727
28 exception Fatal_error of string * Globals.pos
29 exception Error of error_msg * Globals.pos
28 exception Fatal_error of Globals.located * int (* depth *)
29 exception Error of error_msg * Globals.pos * int (* depth *)
3030
3131 let string_source t = match follow t with
3232 | TInst(c,tl) -> PMap.foldi (fun s _ acc -> s :: acc) (TClass.get_all_fields c tl) []
4242 Should be called for each complementary error message.
4343 *)
4444 let compl_msg s = "... " ^ s
45 let rec compl_located_msg = function
46 | Message (s,p) -> Message (compl_msg s,p)
47 | Stack stack -> Stack (List.map compl_located_msg stack)
4548
4649 let unify_error_msg ctx err = match err with
4750 | Cannot_unify (t1,t2) ->
101104 mutable acc_expected : TType.t;
102105 mutable acc_actual : TType.t;
103106 mutable acc_messages : unify_error list;
107 mutable acc_extra : unify_error list;
104108 mutable acc_next : access option;
105109 }
106110
117121 acc_expected = expected;
118122 acc_actual = actual;
119123 acc_messages = [];
124 acc_extra = [];
120125 acc_next = None;
121126 } in
122127 let root_acc = make_acc Root t_dynamic t_dynamic in
123128 let current_acc = ref root_acc in
124129 let add_message msg =
125130 !current_acc.acc_messages <- msg :: !current_acc.acc_messages
131 in
132 let add_extra msg =
133 !current_acc.acc_extra <- msg :: !current_acc.acc_extra
126134 in
127135 let add_access kind =
128136 let acc = make_acc kind t_dynamic t_dynamic in
142150 add_access FunctionReturn;
143151 | Invariant_parameter i ->
144152 add_access (TypeParameter i);
153 | Unify_custom _ ->
154 add_extra err
145155 | _ ->
146156 add_message err
147157 ) l;
187197 let fl = PMap.fold (fun f acc -> ((if Meta.has Meta.Optional f.cf_meta then " ?" else " ") ^ f.cf_name) :: acc) a.a_fields [] in
188198 "{" ^ String.concat "," fl ^ " }"
189199 end
190 | TDynamic t2 ->
191 "Dynamic" ^ s_type_params ctx (if t == t2 then [] else [t2])
200 | TDynamic None ->
201 "Dynamic"
202 | TDynamic (Some t2) ->
203 "Dynamic" ^ s_type_params ctx [t2]
192204 | TLazy f ->
193205 s_type ctx (lazy_type f)
194206
261273 in
262274 match access.acc_next with
263275 | None ->
264 String.concat "\n" (List.rev_map (unify_error_msg ctx) access.acc_messages)
276 String.concat "\n" (List.rev_map (unify_error_msg ctx) (access.acc_extra @ access.acc_messages))
265277 | Some access_next ->
266278 let slhs,srhs = loop access_next access in
267279 Printf.sprintf "error: %s\nhave: %s\nwant: %s" (Buffer.contents message_buffer) slhs srhs
268280 end
269281
270 let rec error_msg = function
271 | Module_not_found m -> "Type not found : " ^ s_type_path m
272 | Type_not_found (m,t,Private_type) -> "Cannot access private type " ^ t ^ " in module " ^ s_type_path m
273 | Type_not_found (m,t,Not_defined) -> "Module " ^ s_type_path m ^ " does not define type " ^ t
274 | Unify l -> BetterErrors.better_error_message l
275 | Unknown_ident s -> "Unknown identifier : " ^ s
276 | Custom s -> s
277 | Stack (m1,m2) -> error_msg m1 ^ "\n" ^ error_msg m2
278 | Call_error err -> s_call_error err
279 | No_constructor mt -> (s_type_path (t_infos mt).mt_path ^ " does not have a constructor")
280 | Abstract_class mt -> (s_type_path (t_infos mt).mt_path) ^ " is abstract and cannot be constructed"
281
282 and s_call_error = function
282 let rec error_msg p = function
283 | Module_not_found m -> located ("Type not found : " ^ s_type_path m) p
284 | Type_not_found (m,t,Private_type) -> located ("Cannot access private type " ^ t ^ " in module " ^ s_type_path m) p
285 | Type_not_found (m,t,Not_defined) -> located ("Module " ^ s_type_path m ^ " does not define type " ^ t) p
286 | Unify l -> located (BetterErrors.better_error_message l) p
287 | Unknown_ident s -> located ("Unknown identifier : " ^ s) p
288 | Custom s -> located s p
289 | Stack stack -> located_stack (List.map (fun (e,p) -> error_msg p e) stack)
290 | Call_error err -> s_call_error p err
291 | No_constructor mt -> located (s_type_path (t_infos mt).mt_path ^ " does not have a constructor") p
292 | Abstract_class mt -> located (s_type_path (t_infos mt).mt_path ^ " is abstract and cannot be constructed") p
293
294 and s_call_error p = function
283295 | Not_enough_arguments tl ->
284296 let pctx = print_context() in
285 "Not enough arguments, expected " ^ (String.concat ", " (List.map (fun (n,_,t) -> n ^ ":" ^ (short_type pctx t)) tl))
286 | Too_many_arguments -> "Too many arguments"
287 | Could_not_unify err -> error_msg err
288 | Cannot_skip_non_nullable s -> "Cannot skip non-nullable argument " ^ s
289
290 let error msg p = raise (Error (Custom msg,p))
291
292 let raise_error err p = raise (Error(err,p))
297 located ("Not enough arguments, expected " ^ (String.concat ", " (List.map (fun (n,_,t) -> n ^ ":" ^ (short_type pctx t)) tl))) p
298 | Too_many_arguments -> located "Too many arguments" p
299 | Could_not_unify err -> error_msg p err
300 | Cannot_skip_non_nullable s -> located ("Cannot skip non-nullable argument " ^ s) p
301
302 let typing_error ?(depth=0) msg p = raise (Error (Custom msg,p,depth))
303 let located_typing_error ?(depth=0) msg =
304 let err = match msg with
305 | Message (msg,p) -> Custom msg
306 | Stack _ -> Stack (List.map (fun (msg,p) -> (Custom msg,p)) (extract_located msg))
307 in
308 raise (Error (err,(extract_located_pos msg),depth))
309
310 let raise_typing_error ?(depth=0) err p = raise (Error(err,p,depth))
293311
294312 let error_require r p =
295313 if r = "" then
296 error "This field is not available with the current compilation flags" p
314 typing_error "This field is not available with the current compilation flags" p
297315 else
298316 let r = if r = "sys" then
299317 "a system platform (php,neko,cpp,etc.)"
304322 with _ ->
305323 "'" ^ r ^ "' to be enabled"
306324 in
307 error ("Accessing this field requires " ^ r) p
308
309 let invalid_assign p = error "Invalid assign" p
325 typing_error ("Accessing this field requires " ^ r) p
326
327 let invalid_assign p = typing_error "Invalid assign" p
44 }
55
66 type path = string list * string
7 type located =
8 | Message of string * pos
9 | Stack of located list
710
811 module IntMap = Ptmap
912 module StringMap = Map.Make(struct type t = string let compare = String.compare end)
2326 | Hl
2427 | Eval
2528
26 let version = 4205
29 let version = 4300
2730 let version_major = version / 1000
2831 let version_minor = (version mod 1000) / 100
2932 let version_revision = (version mod 100)
3033 let version_pre = None
34
35 let null_pos = { pfile = "?"; pmin = -1; pmax = -1 }
36
37 let located msg p = Message (msg,p)
38 let located_stack stack = Stack stack
39
40 let rec extract_located = function
41 | Message (msg,p) -> [(msg, p)]
42 | Stack stack -> List.fold_left (fun acc s -> acc @ (extract_located s)) [] stack
43
44 let rec relocate msg p = match msg with
45 | Message (msg,_) -> Message (msg,p)
46 | Stack [] -> Stack []
47 | Stack (hd :: tl) -> Stack ((relocate hd p) :: tl)
48
49 let rec extract_located_pos = function
50 | Message (_,p) -> p
51 | Stack [] -> null_pos
52 | Stack (hd :: _) -> extract_located_pos hd
3153
3254 let macro_platform = ref Neko
3355
4971 Eval;
5072 ]
5173
74 (** Expected to match `haxe.display.Display.Platform`. *)
5275 let platform_name = function
5376 | Cross -> "cross"
5477 | Js -> "js"
6386 | Hl -> "hl"
6487 | Eval -> "eval"
6588
89 let parse_platform = function
90 | "cross" -> Cross
91 | "js" -> Js
92 | "lua" -> Lua
93 | "neko" -> Neko
94 | "flash" -> Flash
95 | "php" -> Php
96 | "cpp" -> Cpp
97 | "cs" -> Cs
98 | "java" -> Java
99 | "python" -> Python
100 | "hl" -> Hl
101 | "eval" -> Eval
102 | p -> raise (failwith ("invalid platform " ^ p))
103
66104 let platform_list_help = function
67105 | [] -> ""
68106 | [p] -> " (" ^ platform_name p ^ " only)"
69107 | pl -> " (for " ^ String.concat "," (List.map platform_name pl) ^ ")"
70108
71 let null_pos = { pfile = "?"; pmin = -1; pmax = -1 }
72
73109 let mk_zero_range_pos p = { p with pmax = p.pmin }
74110
75111 let s_type_path (p,s) = match p with [] -> s | _ -> String.concat "." p ^ "." ^ s
81117 Printf.sprintf "%s: characters %d-%d" p.pfile p.pmin p.pmax
82118 )
83119
84 let s_version with_build =
120 let s_version =
85121 let pre = Option.map_default (fun pre -> "-" ^ pre) "" version_pre in
86 let build =
87 match with_build, Version.version_extra with
88 | true, Some (_,build) -> "+" ^ build
89 | _, _ -> ""
90 in
91 Printf.sprintf "%d.%d.%d%s%s" version_major version_minor version_revision pre build
122 Printf.sprintf "%d.%d.%d%s" version_major version_minor version_revision pre
123
124 let s_version_full =
125 match Version.version_extra with
126 | Some (_,build) -> s_version ^ "+" ^ build
127 | _ -> s_version
128
129
130 let patch_string_pos p s = { p with pmin = p.pmax - String.length s }
92131
93132 (**
94133 Terminates compiler process and prints user-friendly instructions about filing an issue.
110149 try snd (ExtString.String.split backtrace "\n")
111150 with ExtString.Invalid_string -> backtrace
112151 in
113 let ver = s_version true
152 let ver = s_version_full
114153 and os_type = if Sys.unix then "unix" else "windows" in
115154 Printf.eprintf "%s\nHaxe: %s; OS type: %s;\n%s\n%s" msg ver os_type ml_loc backtrace;
116 assert false
155 assert false
156
157 module MessageSeverity = struct
158 type t =
159 | Error
160 | Warning
161 | Information
162 | Hint
163
164 let to_int = function
165 | Error -> 1
166 | Warning -> 2
167 | Information -> 3
168 | Hint -> 4
169 end
170
171 module MessageKind = struct
172 type t =
173 | DKUnusedImport
174 | DKUnresolvedIdentifier
175 | DKCompilerMessage
176 | DKRemovableCode
177 | DKParserError
178 | DKDeprecationWarning
179 | DKInactiveBlock
180 | DKMissingFields
181
182 let to_int = function
183 | DKUnusedImport -> 0
184 | DKUnresolvedIdentifier -> 1
185 | DKCompilerMessage -> 2
186 | DKRemovableCode -> 3
187 | DKParserError -> 4
188 | DKDeprecationWarning -> 5
189 | DKInactiveBlock -> 6
190 | DKMissingFields -> 7
191 end
192
193 type compiler_message = {
194 cm_message : string;
195 cm_pos : pos;
196 cm_depth : int;
197 cm_kind : MessageKind.t;
198 cm_severity : MessageSeverity.t;
199 }
200
201 let make_compiler_message msg p depth kind sev = {
202 cm_message = msg;
203 cm_pos = p;
204 cm_depth = depth;
205 cm_kind = kind;
206 cm_severity = sev;
207 }
208
209 let i32_31 = Int32.of_int 31
66 let rec loop (e,p) =
77 match e with
88 | EConst (Ident s) when s <> "" -> [s]
9 | EField (e,s) -> s :: loop e
10 | _ -> Error.error "Invalid target expression for @:inheritDoc" p
9 | EField (e,s,_) -> s :: loop e
10 | _ -> Error.typing_error "Invalid target expression for @:inheritDoc" p
1111 in
1212 match loop e with
1313 | sub_name :: type_name :: pack when not (is_lower_ident type_name) ->
1515 | type_name :: pack ->
1616 (List.rev pack, type_name), None
1717 | [] ->
18 Error.error "Invalid target path for @:inheritDoc" (snd e)
18 Error.typing_error "Invalid target path for @:inheritDoc" (snd e)
1919
2020 let rec get_constructor c =
2121 match c.cl_constructor, c.cl_super with
147147 | OpInterval -> "OpInterval",None
148148 | OpArrow -> "OpArrow",None
149149 | OpIn -> "OpIn",None
150 | OpNullCoal -> "OpNullCoal",None
150151 in
151152 generate_adt ctx (Some (["haxe";"macro"],"Binop")) name args
152153
175176
176177 and generate_metadata ctx ml =
177178 let ml = List.filter (fun (m,_,_) ->
178 let (_,(_,flags)) = Meta.get_info m in
179 let (_,(_,flags),_) = Meta.get_info m in
179180 not (List.mem UsedInternally flags)
180181 ) ml in
181182 jlist (generate_metadata_entry ctx) ml
217218 let t = lazy_type f in
218219 (* return_partial_type := false; *)
219220 loop t
220 | TDynamic t -> "TDynamic",Some (if t == t_dynamic then jnull else generate_type ctx t)
221 | TDynamic None -> "TDynamic", Some jnull
222 | TDynamic (Some t) -> "TDynamic",Some (generate_type ctx t)
221223 | TInst(c,tl) -> "TInst",Some (generate_type_path_with_params ctx c.cl_module.m_path c.cl_path tl c.cl_meta)
222224 | TEnum(en,tl) -> "TEnum",Some (generate_type_path_with_params ctx en.e_module.m_path en.e_path tl en.e_meta)
223225 | TType(td,tl) -> "TType",Some (generate_type_path_with_params ctx td.t_module.m_path td.t_path tl td.t_meta)
273275
274276 (* type parameter *)
275277
276 and generate_type_parameter ctx (s,t) =
277 let generate_constraints () = match follow t with
278 and generate_type_parameter ctx tp =
279 let generate_constraints () = match follow tp.ttp_type with
278280 | TInst({cl_kind = KTypeParameter tl},_) -> generate_types ctx tl
279281 | _ -> die "" __LOC__
280282 in
281283 jobject [
282 "name",jstring s;
284 "name",jstring tp.ttp_name;
283285 "constraints",generate_constraints ();
286 "defaultType",jopt (generate_type ctx) tp.ttp_default;
284287 ]
285288
286289 (* texpr *)
703706
704707 (* module *)
705708
706 let generate_module ctx m =
709 let generate_module cc m =
707710 jobject [
708711 "id",jint m.m_id;
709712 "path",generate_module_path m.m_path;
710713 "types",jlist (fun mt -> generate_type_path m.m_path (t_infos mt).mt_path (t_infos mt).mt_meta) m.m_types;
711714 "file",jstring (Path.UniqueKey.lazy_path m.m_extra.m_file);
712715 "sign",jstring (Digest.to_hex m.m_extra.m_sign);
716 "cacheState",jstring (match m.m_extra.m_cache_state with
717 | MSGood -> "Good"
718 | MSBad reason -> Printer.s_module_skip_reason reason
719 | MSUnknown -> "Unknown");
713720 "dependencies",jarray (PMap.fold (fun m acc -> (jobject [
714721 "path",jstring (s_type_path m.m_path);
715722 "sign",jstring (Digest.to_hex m.m_extra.m_sign);
716723 ]) :: acc) m.m_extra.m_deps []);
724 "dependents",jarray (List.map (fun m -> (jobject [
725 "path",jstring (s_type_path m.m_path);
726 "sign",jstring (Digest.to_hex m.m_extra.m_sign);
727 ])) (Hashtbl.fold (fun _ m' acc ->
728 if PMap.mem m.m_id m'.m_extra.m_deps then m' :: acc
729 else acc
730 ) cc#get_modules []));
717731 ]
718732
719733 let create_context ?jsonrpc gm = {
731745 let ch = open_out_bin file in
732746 Json.write_json (output_string ch) json;
733747 close_out ch;
734 t()
748 t()
99 | (m2,_,_) :: l when m = m2 -> l
1010 | x :: l -> x :: remove m l
1111
12 let to_string m = fst (get_info m)
12 type user_meta = {
13 doc : string;
14 flags : meta_parameter list;
15 source : string option;
16 }
17
18 type meta_origin =
19 | Compiler
20 | UserDefined of string option
21
22 let register_user_meta user_metas s data =
23 Hashtbl.replace user_metas s data
24
25 let get_info ?user_metas m = match (user_metas,m) with
26 | (Some(user_metas), Custom(s)) when (Hashtbl.mem user_metas s) ->
27 let infos = Hashtbl.find user_metas s in
28 (s, (infos.doc, infos.flags), (UserDefined infos.source))
29 | _ ->
30 let meta,infos = MetaList.get_info m in
31 (meta, infos, Compiler)
32
33 let to_string m = match (get_info m) with (s,_,_) -> s
1334
1435 let hmeta =
1536 let h = Hashtbl.create 0 in
1637 let rec loop i =
1738 let m = Obj.magic i in
1839 if m <> Last then begin
19 Hashtbl.add h (fst (get_info m)) m;
40 Hashtbl.add h (to_string m) m;
2041 loop (i + 1);
2142 end;
2243 in
3152 | '$' -> Dollar (String.sub s 1 (String.length s - 1))
3253 | _ -> Custom s
3354
34 let get_documentation d =
35 let t, (doc,flags) = get_info d in
55 let get_documentation user_metas d =
56 let t, (doc,flags), origin = get_info ~user_metas:user_metas d in
3657 if not (List.mem UsedInternally flags) then begin
3758 let params = ref [] and used = ref [] and pfs = ref [] in
3859 List.iter (function
4768 | l -> "(<" ^ String.concat ">, <" l ^ ">) "
4869 ) in
4970 let pfs = platform_list_help (List.rev !pfs) in
71 let origin = match origin with
72 | UserDefined Some s -> " (from " ^ s ^ ")"
73 | Compiler | UserDefined None -> ""
74 in
5075 let str = "@" ^ t in
51 Some (str,params ^ doc ^ pfs)
76 Some (str,params ^ doc ^ pfs ^ origin)
5277 end else
5378 None
5479
55 let get_documentation_list () =
80 let get_documentation_list user_metas =
5681 let m = ref 0 in
5782 let rec loop i =
5883 let d = Obj.magic i in
59 if d <> Last then begin match get_documentation d with
84 if d <> Last then begin match get_documentation user_metas d with
6085 | None -> loop (i + 1)
6186 | Some (str,desc) ->
6287 if String.length str > !m then m := String.length str;
6792 let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in
6893 all,!m
6994
70 let get_all () =
71 let rec loop i =
95 let get_all user_metas =
96 let rec loop i acc =
7297 let d = Obj.magic i in
73 if d <> Last then d :: loop (i + 1)
74 else []
98 if d <> Last then d :: loop (i + 1) acc
99 else acc
75100 in
76 loop 0
101
102 let all = loop 0 (Hashtbl.fold (fun str _ acc -> (Custom str) :: acc) user_metas []) in
103 List.sort (fun m1 m2 -> String.compare (to_string m1) (to_string m2)) all
104
105 let get_user_documentation_list user_metas =
106 let m = ref 0 in
107 let user_meta_list = (Hashtbl.fold (fun meta _ acc ->
108 begin match get_documentation user_metas (Custom meta) with
109 | None -> acc
110 | Some (str, desc) ->
111 if String.length str > !m then m := String.length str;
112 (str,desc) :: acc
113 end
114 ) user_metas []) in
115
116 let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) user_meta_list in
117 all,!m
77118
78119 let copy_from_to m src dst =
79120 try (get m src) :: dst
80 with Not_found -> dst
121 with Not_found -> dst
4444 Printf.sprintf "%.18g" f
4545 in valid_float_lexeme float_val
4646
47 let is_whitespace code =
48 code > 8 && code < 14
49
4750 let parse_float s =
4851 let rec loop sp i =
4952 if i = String.length s then (if sp = 0 then s else String.sub s sp (i - sp)) else
5053 match String.unsafe_get s i with
5154 | ' ' when sp = i -> loop (sp + 1) (i + 1)
55 | c when sp = i && is_whitespace (Char.code c) -> loop (sp + 1) (i + 1)
5256 | '0'..'9' | '-' | '+' | 'e' | 'E' | '.' -> loop sp (i + 1)
5357 | _ -> String.sub s sp (i - sp)
5458 in
6367 | '0'..'9' | 'a'..'f' | 'A'..'F' -> loop_hex sp (i + 1)
6468 | _ -> String.sub s sp (i - sp)
6569 in
66 let rec loop sp i digits_count =
70 let rec loop_dec sp i =
6771 if i = String.length s then (if sp = 0 then s else String.sub s sp (i - sp)) else
6872 match String.unsafe_get s i with
69 | '0'..'9' -> loop sp (i + 1) (digits_count + 1)
70 | ' ' | '+' when sp = i -> loop (sp + 1) (i + 1) digits_count
71 | c when sp = i && Char.code c > 8 && Char.code c < 14 -> loop (sp + 1) (i + 1) digits_count
72 | '-' when i = sp -> loop sp (i + 1) digits_count
73 | ('x' | 'X') when digits_count = 1 && String.get s (i - 1) = '0' -> loop_hex sp (i + 1)
73 | '0'..'9' -> loop_dec sp (i + 1)
7474 | _ -> String.sub s sp (i - sp)
7575 in
76 Int32.of_string (loop 0 0 0)
76 let handle_digits sp i =
77 if i + 1 < String.length s && String.get s i = '0' &&
78 (String.get s (i + 1) = 'x' || String.get s (i + 1) = 'X')
79 then loop_hex sp (i + 2)
80 else loop_dec sp i
81 in
82 let rec loop sp =
83 if sp = String.length s then "" else
84 match String.unsafe_get s sp with
85 | ' ' -> loop (sp + 1)
86 | '+' -> handle_digits (sp + 1) (sp + 1)
87 | '-' -> handle_digits sp (sp + 1)
88 | c when is_whitespace (Char.code c) -> loop (sp + 1)
89 | _ -> handle_digits sp sp
90 in
91 Int32.of_string (loop 0)
375375 let full_dot_path pack mname tname =
376376 if tname = mname then (pack,mname) else (pack @ [mname],tname)
377377
378 let file_extension file =
379 match List.rev (ExtString.String.nsplit file ".") with
380 | e :: _ -> String.lowercase e
381 | [] -> ""
382
378383 module FilePath = struct
379384 type t = {
380385 directory : string option;
9090
9191 let mk_mono() = TMono (!monomorph_create_ref ())
9292
93 let rec t_dynamic = TDynamic t_dynamic
93 let t_dynamic = TDynamic None
9494
9595 let mk_anon ?fields status =
9696 let fields = match fields with Some fields -> fields | None -> PMap.empty in
134134 cl_descendants = [];
135135 }
136136
137 let mk_typedef m path pos name_pos t =
138 {
139 t_path = path;
140 t_module = m;
141 t_pos = pos;
142 t_name_pos = name_pos;
143 t_private = false;
144 t_doc = None;
145 t_meta = [];
146 t_params = [];
147 t_using = [];
148 t_type = t;
149 t_restore = (fun () -> ());
150 }
151
137152 let module_extra file sign time kind policy =
138153 {
139154 m_file = Path.UniqueKey.create_lazy file;
143158 m_type_hints = [];
144159 m_import_positions = PMap.empty;
145160 };
146 m_dirty = None;
161 m_cache_state = MSGood;
147162 m_added = 0;
148 m_mark = 0;
163 m_checked = 0;
149164 m_time = time;
150165 m_processed = 0;
151166 m_deps = PMap.empty;
200215 a_meta = [];
201216 a_params = [];
202217 a_using = [];
218 a_restore = (fun () -> ());
203219 a_ops = [];
204220 a_unops = [];
205221 a_impl = None;
211227 a_array = [];
212228 a_read = None;
213229 a_write = None;
230 a_call = None;
214231 a_enum = false;
215232 }
216233
217 let add_dependency m mdep =
218 if m != null_module && m != mdep then m.m_extra.m_deps <- PMap.add mdep.m_id mdep m.m_extra.m_deps
234 let add_dependency ?(skip_postprocess=false) m mdep =
235 if m != null_module && m != mdep then begin
236 m.m_extra.m_deps <- PMap.add mdep.m_id mdep m.m_extra.m_deps;
237 (* In case the module is cached, we'll have to run post-processing on it again (issue #10635) *)
238 if not skip_postprocess then m.m_extra.m_processed <- 0
239 end
219240
220241 let arg_name (a,_) = a.v_name
221242
272293 let ft = lazy_type f in
273294 let ft2 = loop ft in
274295 if ft == ft2 then t else ft2
275 | TDynamic t2 ->
276 if t == t2 then t else TDynamic (loop t2)
296 | TDynamic None ->
297 t
298 | TDynamic (Some t2) ->
299 TDynamic (Some (loop t2))
277300
278301 let iter loop t =
279302 match t with
299322 | TLazy f ->
300323 let ft = lazy_type f in
301324 loop ft
302 | TDynamic t2 ->
303 if t != t2 then loop t2
325 | TDynamic None ->
326 ()
327 | TDynamic (Some t2) ->
328 loop t2
304329
305330 let duplicate t =
306331 let monos = ref [] in
318343 in
319344 loop t
320345
346 let dynamify_monos t =
347 let rec loop t =
348 match t with
349 | TMono { tm_type = None } ->
350 t_dynamic
351 | _ ->
352 map loop t
353 in
354 loop t
355
321356 exception ApplyParamsRecursion
322357
323358 (* substitute parameters with other types *)
328363 let rec loop l1 l2 =
329364 match l1, l2 with
330365 | [] , [] -> []
331 | (x,TLazy f) :: l1, _ -> loop ((x,lazy_type f) :: l1) l2
332 | (_,t1) :: l1 , t2 :: l2 -> (t1,t2) :: loop l1 l2
366 | {ttp_type = TLazy f} as tp :: l1, _ -> loop ({tp with ttp_type = lazy_type f} :: l1) l2
367 | tp :: l1 , t2 :: l2 -> (tp.ttp_type,t2) :: loop l1 l2
333368 | _ -> die "" __LOC__
334369 in
335370 let subst = loop cparams params in
426461 t
427462 else
428463 ft2
429 | TDynamic t2 ->
430 if t == t2 then
431 t
432 else
433 TDynamic (loop t2)
464 | TDynamic None ->
465 t
466 | TDynamic (Some t2) ->
467 TDynamic (Some (loop t2))
434468 in
435469 loop t
470
471 let apply_typedef td tl =
472 apply_params td.t_params tl td.t_type
436473
437474 let monomorphs eparams t =
438475 apply_params eparams (List.map (fun _ -> mk_mono()) eparams) t
461498 | TLazy f ->
462499 follow (lazy_type f)
463500 | TType (t,tl) ->
464 follow (apply_params t.t_params tl t.t_type)
501 follow (apply_typedef t tl)
465502 | TAbstract({a_path = [],"Null"},[t]) ->
466503 follow t
467504 | _ -> t
475512 | TAbstract _ | TEnum _ | TInst _ | TFun _ | TAnon _ | TDynamic _ ->
476513 t
477514 | TType (t,tl) ->
478 apply_params t.t_params tl t.t_type
515 apply_typedef t tl
479516 | TLazy f ->
480517 lazy_type f
481518
488525 | TLazy f ->
489526 follow_without_null (lazy_type f)
490527 | TType (t,tl) ->
491 follow_without_null (apply_params t.t_params tl t.t_type)
528 follow_without_null (apply_typedef t tl)
492529 | _ -> t
493530
494531 let rec follow_without_type t =
520557 | _ -> is_nullable (lazy_type f)
521558 )
522559 | TType (t,tl) ->
523 is_nullable ~no_lazy (apply_params t.t_params tl t.t_type)
560 is_nullable ~no_lazy (apply_typedef t tl)
524561 | TFun _ ->
525562 false
526563 (*
551588 | _ -> is_null (lazy_type f)
552589 )
553590 | TType (t,tl) ->
554 is_null ~no_lazy (apply_params t.t_params tl t.t_type)
591 is_null ~no_lazy (apply_typedef t tl)
555592 | _ ->
556593 false
557594
564601 | TLazy f ->
565602 is_explicit_null (lazy_type f)
566603 | TType (t,tl) ->
567 is_explicit_null (apply_params t.t_params tl t.t_type)
604 is_explicit_null (apply_typedef t tl)
568605 | _ ->
569606 false
570607
591628 ) in
592629 mk e e2.etype (punion e1.epos e2.epos)
593630
631 let extract_param_type tp = tp.ttp_type
632 let extract_param_types = List.map extract_param_type
633 let extract_param_name tp = tp.ttp_name
634 let lookup_param n l =
635 let rec loop l = match l with
636 | [] ->
637 raise Not_found
638 | tp :: l ->
639 if n = tp.ttp_name then tp.ttp_type else loop l
640 in
641 loop l
642
643 let mk_type_param n t def = {
644 ttp_name = n;
645 ttp_type = t;
646 ttp_default = def;
647 }
648
594649 let type_of_module_type = function
595 | TClassDecl c -> TInst (c,List.map snd c.cl_params)
596 | TEnumDecl e -> TEnum (e,List.map snd e.e_params)
597 | TTypeDecl t -> TType (t,List.map snd t.t_params)
598 | TAbstractDecl a -> TAbstract (a,List.map snd a.a_params)
650 | TClassDecl c -> TInst (c,extract_param_types c.cl_params)
651 | TEnumDecl e -> TEnum (e,extract_param_types e.e_params)
652 | TTypeDecl t -> TType (t,extract_param_types t.t_params)
653 | TAbstractDecl a -> TAbstract (a,extract_param_types a.a_params)
599654
600655 let rec module_type_of_type = function
601656 | TInst(c,_) -> TClassDecl c
611666 raise Exit
612667
613668 let tconst_to_const = function
614 | TInt i -> Int (Int32.to_string i)
615 | TFloat s -> Float s
669 | TInt i -> Int (Int32.to_string i, None)
670 | TFloat s -> Float (s, None)
616671 | TString s -> String(s,SDoubleQuotes)
617672 | TBool b -> Ident (if b then "true" else "false")
618673 | TNull -> Ident "null"
799854 let var_extra params e = {
800855 v_params = params;
801856 v_expr = e;
802 }
857 }
3434 | TAbstract (a,pl) ->
3535 tpath a.a_path a.a_module.m_path (List.map tparam pl)
3636 | TFun (args,ret) ->
37 CTFunction (List.map (fun (_,_,t) -> convert_type' t) args, (convert_type' ret))
37 CTFunction (List.map (fun (n,o,t) ->
38 let ct = convert_type' t in
39 let ct = if n = "" then ct else CTNamed((n,null_pos),ct),null_pos in
40 if o then CTOptional ct,null_pos else ct
41 ) args, (convert_type' ret))
3842 | TAnon a ->
3943 begin match !(a.a_status) with
4044 | Statics c -> tpath ([],"Class") ([],"Class") [TPType (tpath c.cl_path c.cl_path [],null_pos)]
4145 | EnumStatics e -> tpath ([],"Enum") ([],"Enum") [TPType (tpath e.e_path e.e_path [],null_pos)]
4246 | _ ->
4347 CTAnonymous (PMap.foldi (fun _ f acc ->
48 let access = ref [] in
49 let add flag =
50 access := (flag,null_pos) :: !access;
51 in
52 if has_class_field_flag f CfPublic then add APublic else add APrivate;
53 if has_class_field_flag f CfFinal then add AFinal;
54 if has_class_field_flag f CfExtern then add AExtern;
55 let kind = match (f.cf_kind,follow f.cf_type) with
56 | (Var v,ret) ->
57 let var_access_to_string va get_or_set = match va with
58 | AccNormal | AccCtor | AccInline | AccRequire _ -> "default"
59 | AccNo -> "null"
60 | AccNever -> "never"
61 | AccCall -> get_or_set
62 in
63 let read = (var_access_to_string v.v_read "get",null_pos) in
64 let write = (var_access_to_string v.v_write "set",null_pos) in
65 FProp (read,write,mk_type_hint f.cf_type null_pos,None)
66 | Method _,TFun(args,ret) ->
67 FFun({
68 f_params = [];
69 f_args = List.map (fun (n,o,t) ->
70 ((n,null_pos),o,[],Some (convert_type t,null_pos),None)
71 ) args;
72 f_type = Some (convert_type ret,null_pos);
73 f_expr = None;
74 })
75 | _ ->
76 die "" __LOC__
77 in
4478 {
4579 cff_name = f.cf_name,null_pos;
46 cff_kind = FVar (mk_type_hint f.cf_type null_pos,None);
80 cff_kind = kind;
4781 cff_pos = f.cf_pos;
4882 cff_doc = f.cf_doc;
4983 cff_meta = f.cf_meta;
50 cff_access = [];
84 cff_access = !access;
5185 } :: acc
5286 ) a.a_fields [])
5387 end
54 | (TDynamic t2) as t ->
55 tpath ([],"Dynamic") ([],"Dynamic") (if t == t_dynamic then [] else [tparam t2])
88 | TDynamic None ->
89 tpath ([],"Dynamic") ([],"Dynamic") []
90 | TDynamic (Some t2) ->
91 tpath ([],"Dynamic") ([],"Dynamic") [tparam t2]
5692 | TLazy f ->
5793 convert_type (lazy_type f)
5894
90126 | TLocal v -> EConst (mk_ident v.v_name)
91127 | TArray (e1,e2) -> EArray (convert_expr e1,convert_expr e2)
92128 | TBinop (op,e1,e2) -> EBinop (op, convert_expr e1, convert_expr e2)
93 | TField (e,f) -> EField (convert_expr e, field_name f)
129 | TField (e,f) -> EField (convert_expr e, field_name f, EFNormal)
94130 | TTypeExpr t -> fst (mk_path (full_type_path t) e.epos)
95131 | TParenthesis e -> EParenthesis (convert_expr e)
96132 | TObjectDecl fl -> EObjectDecl (List.map (fun (k,e) -> k, convert_expr e) fl)
207243 let rec loop t = match t with
208244 | TInst(c,_) -> check c.cl_meta
209245 | TEnum(en,_) -> check en.e_meta
210 | TType(t,tl) -> check t.t_meta || (loop (apply_params t.t_params tl t.t_type))
246 | TType(t,tl) -> check t.t_meta || (loop (apply_typedef t tl))
211247 | TAbstract(a,_) -> check a.a_meta
212248 | TLazy f -> loop (lazy_type f)
213249 | TMono r ->
226262
227263 let no_meta = []
228264
229 let class_module_type c = {
230 t_path = [],"Class<" ^ (s_type_path c.cl_path) ^ ">" ;
231 t_module = c.cl_module;
232 t_doc = None;
233 t_pos = c.cl_pos;
234 t_name_pos = null_pos;
235 t_type = mk_anon ~fields:c.cl_statics (ref (Statics c));
236 t_private = true;
237 t_params = [];
238 t_using = [];
239 t_meta = no_meta;
240 }
241
242 let enum_module_type m path p = {
243 t_path = [], "Enum<" ^ (s_type_path path) ^ ">";
244 t_module = m;
245 t_doc = None;
246 t_pos = p;
247 t_name_pos = null_pos;
248 t_type = mk_mono();
249 t_private = true;
250 t_params = [];
251 t_using = [];
252 t_meta = [];
253 }
254
255 let abstract_module_type a tl = {
256 t_path = [],Printf.sprintf "Abstract<%s%s>" (s_type_path a.a_path) (s_type_params (ref []) tl);
257 t_module = a.a_module;
258 t_doc = None;
259 t_pos = a.a_pos;
260 t_name_pos = null_pos;
261 t_type = mk_anon (ref (AbstractStatics a));
262 t_private = true;
263 t_params = [];
264 t_using = [];
265 t_meta = no_meta;
266 }
265 let class_module_type c =
266 let path = ([],"Class<" ^ (s_type_path c.cl_path) ^ ">") in
267 let t = mk_anon ~fields:c.cl_statics (ref (Statics c)) in
268 { (mk_typedef c.cl_module path c.cl_pos null_pos t) with t_private = true}
269
270 let enum_module_type m path p =
271 let path = ([], "Enum<" ^ (s_type_path path) ^ ">") in
272 let t = mk_mono() in
273 {(mk_typedef m path p null_pos t) with t_private = true}
274
275 let abstract_module_type a tl =
276 let path = ([],Printf.sprintf "Abstract<%s%s>" (s_type_path a.a_path) (s_type_params (ref []) tl)) in
277 let t = mk_anon (ref (AbstractStatics a)) in
278 {(mk_typedef a.a_module path a.a_pos null_pos t) with t_private = true}
267279
268280 module TClass = struct
269281 let get_member_fields' self_too c0 tl =
286298 loop PMap.empty c0 tl
287299
288300 let get_all_super_fields c =
289 get_member_fields' false c (List.map snd c.cl_params)
301 get_member_fields' false c (extract_param_types c.cl_params)
290302
291303 let get_all_fields c tl =
292304 get_member_fields' true c tl
8686 let fl = PMap.fold (fun f acc -> ((if Meta.has Meta.Optional f.cf_meta then " ?" else " ") ^ f.cf_name ^ " : " ^ s_type ctx f.cf_type) :: acc) a.a_fields [] in
8787 "{" ^ String.concat "," fl ^ " }"
8888 end
89 | TDynamic t2 ->
90 "Dynamic" ^ s_type_params ctx (if t == t2 then [] else [t2])
89 | TDynamic None ->
90 "Dynamic"
91 | TDynamic (Some t2) ->
92 "Dynamic" ^ s_type_params ctx [t2]
9193 | TLazy f ->
9294 s_type ctx (lazy_type f)
9395
486488 let s_metadata metadata =
487489 s_list " " s_metadata_entry metadata
488490
489 let s_type_param (s,t) = match follow t with
491 let s_type_param tp = match follow tp.ttp_type with
490492 | TInst({cl_kind = KTypeParameter tl1},tl2) ->
491 begin match tl1 with
492 | [] -> s
493 | _ -> Printf.sprintf "%s:%s" s (String.concat " & " (List.map s_type tl1))
493 let s = match tl1 with
494 | [] -> tp.ttp_name
495 | _ -> Printf.sprintf "%s:%s" tp.ttp_name (String.concat " & " (List.map s_type tl1))
496 in
497 begin match tp.ttp_default with
498 | None ->
499 s
500 | Some t ->
501 Printf.sprintf "%s = %s" s (s_type t)
494502 end
495503 | _ -> die "" __LOC__
496504
497505 let s_type_params tl =
498506 s_list ", " s_type_param tl
507
508 let s_flags flags all_flags =
509 let _,l = List.fold_left (fun (i,acc) name ->
510 if has_flag flags i then (i + 1,name :: acc) else (i + 1,acc)
511 ) (0,[]) all_flags in
512 String.concat " " l
513
514 let s_tclass_field_flags flags =
515 s_flags flags flag_tclass_field_names
499516
500517 let s_tclass_field tabs cf =
501518 s_record_fields tabs [
508525 "cf_kind",s_kind cf.cf_kind;
509526 "cf_params",s_type_params cf.cf_params;
510527 "cf_expr",s_opt (s_expr_ast true "\t\t" s_type) cf.cf_expr;
528 "cf_flags",s_tclass_field_flags cf.cf_flags;
511529 ]
512530
513531 let s_tclass tabs c =
615633 | MExtern -> "MExtern"
616634 | MImport -> "MImport"
617635
636 let s_module_skip_reason reason =
637 let rec loop stack = function
638 | DependencyDirty(path,reason) ->
639 (Printf.sprintf "%s%s - %s" (if stack = [] then "DependencyDirty " else "") (s_type_path path) (if List.mem path stack then "rec" else loop (path :: stack) reason))
640 | Tainted cause -> "Tainted " ^ cause
641 | FileChanged file -> "FileChanged " ^ file
642 | Shadowed file -> "Shadowed " ^ file
643 | LibraryChanged -> "LibraryChanged"
644 in
645 loop [] reason
646
647 let s_module_cache_state = function
648 | MSGood -> "Good"
649 | MSBad reason -> "Bad: " ^ (s_module_skip_reason reason)
650 | MSUnknown -> "Unknown"
651
618652 let s_module_def_extra tabs me =
619653 s_record_fields tabs [
620654 "m_file",Path.UniqueKey.lazy_path me.m_file;
621655 "m_sign",me.m_sign;
622656 "m_time",string_of_float me.m_time;
623 "m_dirty",s_opt s_type_path me.m_dirty;
657 "m_cache_state",s_module_cache_state me.m_cache_state;
624658 "m_added",string_of_int me.m_added;
625 "m_mark",string_of_int me.m_mark;
659 "m_checked",string_of_int me.m_checked;
626660 "m_deps",s_pmap string_of_int (fun m -> snd m.m_path) me.m_deps;
627661 "m_processed",string_of_int me.m_processed;
628662 "m_kind",s_module_kind me.m_kind;
2929 | CheckFileContentModification
3030 | NoCheckDependencies
3131 | NoCheckShadowing
32 | Retype
33
34 type module_skip_reason =
35 | DependencyDirty of path * module_skip_reason
36 | Tainted of string
37 | FileChanged of string
38 | Shadowed of string
39 | LibraryChanged
40
41 type module_cache_state =
42 | MSGood
43 | MSBad of module_skip_reason
44 | MSUnknown
3245
3346 type t =
3447 | TMono of tmono
3750 | TType of tdef * tparams
3851 | TFun of tsignature
3952 | TAnon of tanon
40 | TDynamic of t
53 | TDynamic of t option
4154 | TLazy of tlazy ref
4255 | TAbstract of tabstract * tparams
4356
7689
7790 and tparams = t list
7891
79 and type_params = (string * t) list
92 and typed_type_param = {
93 ttp_name : string;
94 ttp_type : t;
95 ttp_default : t option;
96 }
97
98 and type_params = typed_type_param list
8099
81100 and tconstant =
82101 | TInt of int32
106125 | VInlined
107126 | VInlinedConstructorVariable
108127 | VExtractorVariable
128 | VAbstractThis
109129
110130 and tvar = {
111131 mutable v_id : int;
192212 mutable cf_kind : field_kind;
193213 mutable cf_params : type_params;
194214 mutable cf_expr : texpr option;
195 mutable cf_expr_unoptimized : tfunc option;
215 mutable cf_expr_unoptimized : texpr option;
196216 mutable cf_overloads : tclass_field list;
197217 mutable cf_flags : int;
198218 }
220240 mutable mt_meta : metadata;
221241 mt_params : type_params;
222242 mutable mt_using : (tclass * pos) list;
243 mutable mt_restore : unit -> unit;
223244 }
224245
225246 and tclass = {
232253 mutable cl_meta : metadata;
233254 mutable cl_params : type_params;
234255 mutable cl_using : (tclass * pos) list;
256 mutable cl_restore : unit -> unit;
235257 (* do not insert any fields above *)
236258 mutable cl_kind : tclass_kind;
237259 mutable cl_flags : int;
247269 mutable cl_init : texpr option;
248270
249271 mutable cl_build : unit -> build_state;
250 mutable cl_restore : unit -> unit;
251272 (*
252273 These are classes which directly extend or directly implement this class.
253274 Populated automatically in post-processing step (Filters.run)
276297 mutable e_meta : metadata;
277298 mutable e_params : type_params;
278299 mutable e_using : (tclass * pos) list;
300 mutable e_restore : unit -> unit;
279301 (* do not insert any fields above *)
280302 e_type : tdef;
281303 mutable e_extern : bool;
293315 mutable t_meta : metadata;
294316 mutable t_params : type_params;
295317 mutable t_using : (tclass * pos) list;
318 mutable t_restore : unit -> unit;
296319 (* do not insert any fields above *)
297320 mutable t_type : t;
298321 }
307330 mutable a_meta : metadata;
308331 mutable a_params : type_params;
309332 mutable a_using : (tclass * pos) list;
333 mutable a_restore : unit -> unit;
310334 (* do not insert any fields above *)
311335 mutable a_ops : (Ast.binop * tclass_field) list;
312336 mutable a_unops : (Ast.unop * unop_flag * tclass_field) list;
319343 mutable a_array : tclass_field list;
320344 mutable a_read : tclass_field option;
321345 mutable a_write : tclass_field option;
346 mutable a_call : tclass_field option;
322347 a_enum : bool;
323348 }
324349
348373 m_display : module_def_display;
349374 mutable m_check_policy : module_check_policy list;
350375 mutable m_time : float;
351 mutable m_dirty : path option;
376 mutable m_cache_state : module_cache_state;
352377 mutable m_added : int;
353 mutable m_mark : int;
378 mutable m_checked : int;
379 mutable m_processed : int;
354380 mutable m_deps : (int,module_def) PMap.t;
355 mutable m_processed : int;
356381 mutable m_kind : module_kind;
357382 mutable m_binded_res : (string, string) PMap.t;
358383 mutable m_if_feature : (string *(tclass * tclass_field * bool)) list;
391416 | CFinal
392417 | CInterface
393418 | CAbstract
419 | CFunctionalInterface
394420
395421 type flag_tclass_field =
396422 | CfPublic
404430 | CfImpl
405431 | CfEnum
406432 | CfGeneric
433 | CfDefault (* Interface field with default implementation (only valid on Java) *)
434 | CfPostProcessed (* Marker to indicate the field has been post-processed *)
435
436 (* Order has to match declaration for printing*)
437 let flag_tclass_field_names = [
438 "CfPublic";"CfStatic";"CfExtern";"CfFinal";"CfModifiesThis";"CfOverride";"CfAbstract";"CfOverload";"CfImpl";"CfEnum";"CfGeneric";"CfDefault"
439 ]
407440
408441 type flag_tvar =
409442 | VCaptured
411444 | VUsed (* used by the analyzer *)
412445 | VAssigned
413446 | VCaught
447 | VStatic
259259
260260 let spawn_constrained_monos map params =
261261 let checks = DynArray.create () in
262 let monos = List.map (fun (s,t) ->
262 let monos = List.map (fun tp ->
263263 let mono = create () in
264 begin match follow t with
264 begin match follow tp.ttp_type with
265265 | TInst ({ cl_kind = KTypeParameter constr; cl_path = path },_) when constr <> [] ->
266266 DynArray.add checks (mono,constr,s_type_path path)
267267 | _ ->
295295 | TEnum (_,tl) -> List.exists loop tl
296296 | TInst (_,tl) | TType (_,tl) | TAbstract (_,tl) -> List.exists loop tl
297297 | TFun (tl,t) -> List.exists (fun (_,_,t) -> loop t) tl || loop t
298 | TDynamic t2 ->
299 if t == t2 then
300 false
301 else
302 loop t2
298 | TDynamic None ->
299 false
300 | TDynamic (Some t2) ->
301 loop t2
303302 | TLazy f ->
304303 loop (lazy_type f)
305304 | TAnon a ->
507506 (match t.tm_type with
508507 | None -> if param = EqCoreType || not (link t b a) then error [cannot_unify a b]
509508 | Some t -> type_eq uctx a t)
510 | TDynamic a , TDynamic b ->
509 | TDynamic None, TDynamic None ->
510 ()
511 | TDynamic (Some a) , TDynamic (Some b) ->
511512 type_eq uctx a b
512513 | _ , _ when a == t_dynamic && param = EqBothDynamic ->
513514 ()
834835 with Not_found ->
835836 error [has_no_field a "new"]
836837 end
837 | TDynamic t , _ ->
838 if t == a && uctx.allow_dynamic_to_cast then
838 | TDynamic None , _ ->
839 if uctx.allow_dynamic_to_cast then
839840 ()
840 else (match b with
841 | TDynamic t2 ->
842 if t2 != b then
841 else begin match b with
842 | TDynamic None ->
843 ()
844 | _ ->
845 error [cannot_unify a b]
846 end
847 | TDynamic (Some t1) , _ ->
848 begin match b with
849 | TDynamic None ->
850 ()
851 | TDynamic (Some t2) ->
852 if t2 != t1 then
843853 (try
844 type_eq {uctx with equality_kind = EqRightDynamic} t t2
854 type_eq {uctx with equality_kind = EqRightDynamic} t1 t2
845855 with
846856 Unify_error l -> error (cannot_unify a b :: l));
847857 | TAbstract(bb,tl) ->
848858 unify_from uctx a b bb tl
849859 | _ ->
850 error [cannot_unify a b])
851 | _ , TDynamic t ->
852 if t == b then
853 ()
854 else (match a with
855 | TDynamic t2 ->
856 if t2 != a then
857 (try
858 type_eq {uctx with equality_kind = EqRightDynamic} t t2
859 with
860 Unify_error l -> error (cannot_unify a b :: l));
860 error [cannot_unify a b]
861 end
862 | _ , TDynamic None ->
863 ()
864 | _ , TDynamic (Some t1) ->
865 begin match a with
861866 | TAnon an ->
862867 (try
863868 (match !(an.a_status) with
865870 | _ -> ());
866871 PMap.iter (fun _ f ->
867872 try
868 type_eq uctx (field_type f) t
873 type_eq uctx (field_type f) t1
869874 with Unify_error l ->
870875 error (invalid_field f.cf_name :: l)
871876 ) an.a_fields
874879 | TAbstract(aa,tl) ->
875880 unify_to uctx a b aa tl
876881 | _ ->
877 error [cannot_unify a b])
882 error [cannot_unify a b]
883 end
878884 | TAbstract (aa,tl), _ ->
879885 unify_to uctx a b aa tl
880886 | TInst ({ cl_kind = KTypeParameter ctl } as c,pl), TAbstract (bb,tl) ->
911917 Not_found ->
912918 match !(a1.a_status) with
913919 | Const when Meta.has Meta.Optional f2.cf_meta ->
914 ()
920 a1.a_fields <- PMap.add f2.cf_name f2 a1.a_fields
915921 | _ ->
916922 error [has_no_field a n];
917923 ) a2.a_fields;
10111017 let unify_func = get_abstract_unify_func uctx EqStrict in
10121018 let athis = map ab.a_this in
10131019 (* we cannot allow implicit casts when the this type is not completely known yet *)
1020 if Meta.has Meta.MultiType ab.a_meta && has_mono athis then raise (Unify_error []);
10141021 with_variance uctx (type_eq {uctx with equality_kind = EqStrict}) athis (map ta);
10151022 unify_func (map t) b;
10161023 | _ -> die "" __LOC__)
10231030 let unify_nested t1 t2 = with_variance (get_nested_context uctx) f t1 t2 in
10241031 let unify_tls tl1 tl2 = List.iter2 unify_nested tl1 tl2 in
10251032 let get_this_type ab tl = follow_without_type (apply_params ab.a_params tl ab.a_this) in
1026 let get_defined_type td tl = follow_without_type (apply_params td.t_params tl td.t_type) in
1033 let get_defined_type td tl = follow_without_type (apply_typedef td tl) in
10271034 let compare_underlying () = type_eq {uctx with equality_underlying = true; equality_kind = EqBothDynamic} t1 t2 in
10281035 let unifies_abstract uctx a b ab tl ats =
10291036 try
11391146 loop t);
11401147 tl := t :: !tl;
11411148 | TType (td,pl) ->
1142 loop (apply_params td.t_params pl td.t_type);
1149 loop (apply_typedef td pl);
11431150 (* prioritize the most generic definition *)
11441151 tl := t :: !tl;
11451152 | TLazy f -> loop (lazy_type f)
11831190 let common_types = collect_base_types t0 in
11841191 unify_min' uctx common_types tl
11851192 end
1193
1194 type unification_matrix_state =
1195 | STop
1196 | SType of t
1197 | SBottom
1198
1199 class unification_matrix (arity : int) = object(self)
1200 val values = Array.make arity STop
1201
1202 method join (t : t) (at : int) =
1203 match values.(at) with
1204 | STop ->
1205 values.(at) <- SType t
1206 | SBottom ->
1207 ()
1208 | SType t' ->
1209 if not (type_iseq t t') then values.(at) <- SBottom
1210
1211 method get_type (at : int) =
1212 match values.(at) with
1213 | SType t ->
1214 Some t
1215 | _ ->
1216 None
1217
1218 method dump =
1219 let pctx = print_context() in
1220 let s_unification_matrix_state = function
1221 | STop -> "STop"
1222 | SType t -> "SType " ^ (s_type pctx t)
1223 | SBottom -> "SBottom"
1224 in
1225 String.concat " ; " (List.map s_unification_matrix_state (Array.to_list values))
1226 end
1227
11861228 ;;
11871229 unify_ref := unify_custom;;
11881230 unify_min_ref := UnifyMinT.unify_min;;
504504 | TFloat f -> mk (TConst (TFloat f)) basic.tfloat p
505505 | TBool b -> mk (TConst (TBool b)) basic.tbool p
506506 | TNull -> mk (TConst TNull) (basic.tnull (mk_mono())) p
507 | _ -> error "Unsupported constant" p
507 | _ -> typing_error "Unsupported constant" p
508508
509509 let field e name t p =
510510 let f =
565565 with Exit ->
566566 true
567567
568 let replace_separators s c =
569 String.concat c (ExtString.String.nsplit s "_")
570
568571 let type_constant basic c p =
569572 match c with
570 | Int s ->
571 if String.length s > 10 && String.sub s 0 2 = "0x" then error "Invalid hexadecimal integer" p;
573 | Int (s,_) ->
574 if String.length s > 10 && String.sub s 0 2 = "0x" then typing_error "Invalid hexadecimal integer" p;
572575 (try mk (TConst (TInt (Int32.of_string s))) basic.tint p
573576 with _ -> mk (TConst (TFloat s)) basic.tfloat p)
574 | Float f -> mk (TConst (TFloat f)) basic.tfloat p
577 | Float (f,_) -> mk (TConst (TFloat f)) basic.tfloat p
575578 | String(s,qs) -> mk (TConst (TString s)) basic.tstring p (* STRINGTODO: qs? *)
576579 | Ident "true" -> mk (TConst (TBool true)) basic.tbool p
577580 | Ident "false" -> mk (TConst (TBool false)) basic.tbool p
578581 | Ident "null" -> mk (TConst TNull) (basic.tnull (mk_mono())) p
579 | Ident t -> error ("Invalid constant : " ^ t) p
580 | Regexp _ -> error "Invalid constant" p
582 | Ident t -> typing_error ("Invalid constant : " ^ t) p
583 | Regexp _ -> typing_error "Invalid constant" p
581584
582585 let rec type_constant_value basic (e,p) =
583586 match e with
590593 | EArrayDecl el ->
591594 mk (TArrayDecl (List.map (type_constant_value basic) el)) (basic.tarray t_dynamic) p
592595 | _ ->
593 error "Constant value expected" p
596 typing_error "Constant value expected" p
594597
595598 let is_constant_value basic e =
596 try (ignore (type_constant_value basic e); true) with Error (Custom _,_) -> false
599 try (ignore (type_constant_value basic e); true) with Error (Custom _,_,_) -> false
597600
598601 let for_remap basic v e1 e2 p =
599602 let v' = alloc_var v.v_kind v.v_name e1.etype e1.epos in
600603 let ev' = mk (TLocal v') e1.etype e1.epos in
601604 let t1 = (Abstract.follow_with_abstracts e1.etype) in
602 let ehasnext = mk (TField(ev',try quick_field t1 "hasNext" with Not_found -> error (s_type (print_context()) t1 ^ "has no field hasNext()") p)) (tfun [] basic.tbool) e1.epos in
605 let ehasnext = mk (TField(ev',try quick_field t1 "hasNext" with Not_found -> typing_error (s_type (print_context()) t1 ^ "has no field hasNext()") p)) (tfun [] basic.tbool) e1.epos in
603606 let ehasnext = mk (TCall(ehasnext,[])) basic.tbool ehasnext.epos in
604607 let enext = mk (TField(ev',quick_field t1 "next")) (tfun [] v.v_type) e1.epos in
605608 let enext = mk (TCall(enext,[])) v.v_type e1.epos in
634637 let make_meta_field ml =
635638 let h = Hashtbl.create 0 in
636639 mk (TObjectDecl (List.map (fun (f,el,p) ->
637 if Hashtbl.mem h f then error ("Duplicate metadata '" ^ f ^ "'") p;
640 if Hashtbl.mem h f then typing_error ("Duplicate metadata '" ^ f ^ "'") p;
638641 Hashtbl.add h f ();
639642 (f,null_pos,NoQuotes), mk (match el with [] -> TConst TNull | _ -> TArrayDecl (List.map (type_constant_value api) el)) (api.tarray t_dynamic) p
640643 ) ml)) t_dynamic p
756759 add "TCast";
757760 loop e1;
758761 | TMeta((m,_,_),e1) ->
759 add ("TMeta " ^ fst (Meta.get_info m));
762 add ("TMeta " ^ (Meta.to_string m));
760763 loop e1
761764 in
762765 loop' tabs e;
817820 | { eexpr = TCast _ } as result -> result
818821 | result when require_cast -> { e with eexpr = TCast(result,None) }
819822 | result -> result
823
824 (**
825 Returns a position spanning from the first expr to the last expr in `el`.
826 Returns `default_pos` if `el` is empty or values of `pfile` of the first and
827 the last positions are different.
828 *)
829 let punion_el default_pos el =
830 match el with
831 | [] -> default_pos
832 | [{ epos = p }] -> p
833 | { epos = first } :: { epos = last } :: el ->
834 let rec loop = function
835 | [] -> last
836 | [{ epos = last }] -> last
837 | _ :: el -> loop el
838 in
839 let last = loop el in
840 if first.pfile <> last.pfile then
841 default_pos
842 else
843 punion first last
844
845 let is_exhaustive e1 def =
846 let rec loop e1 = match e1.eexpr with
847 | TMeta((Meta.Exhaustive,_,_),_) -> true
848 | TMeta(_, e1) | TParenthesis e1 -> loop e1
849 | _ -> false
850 in
851 def <> None || loop e1
852
853 let rec is_true_expr e1 = match e1.eexpr with
854 | TConst(TBool true) -> true
855 | TParenthesis e1 -> is_true_expr e1
856 | _ -> false
857
858 let rec is_false_expr e1 = match e1.eexpr with
859 | TConst(TBool false) -> true
860 | TParenthesis e1 -> is_false_expr e1
861 | _ -> false
862
863 module DeadEnd = struct
864 exception BreakOrContinue
865
866 (*
867 Checks if execution of provided expression is guaranteed to be terminated with `return`, `throw`, `break` or `continue`.
868 *)
869 let has_dead_end e =
870 let rec loop e =
871 let in_loop e =
872 try
873 loop e
874 with BreakOrContinue ->
875 false
876 in
877 match e.eexpr with
878 | TContinue | TBreak ->
879 raise BreakOrContinue
880 | TThrow e1 ->
881 loop e1 || true
882 | TReturn (Some e1) ->
883 loop e1 || true (* recurse first, could be `return continue` *)
884 | TReturn None ->
885 true
886 | TFunction _ ->
887 false (* This isn't executed, so don't recurse *)
888 | TIf (cond, if_body, Some else_body) ->
889 loop cond || loop if_body && loop else_body
890 | TIf (cond, _, None) ->
891 loop cond
892 | TSwitch(e1, cases, def) ->
893 let check_exhaustive () =
894 (is_exhaustive e1 def) && List.for_all (fun (el,e) ->
895 List.exists loop el ||
896 loop e
897 ) cases &&
898 Option.map_default (loop ) true def (* true because we know it's exhaustive *)
899 in
900 loop e1 || check_exhaustive ()
901 | TFor(_, e1, _) ->
902 loop e1
903 | TBinop(OpBoolAnd, e1, e2) ->
904 loop e1 || is_true_expr e1 && loop e2
905 | TBinop(OpBoolOr, e1, e2) ->
906 loop e1 || is_false_expr e1 && loop e2
907 | TWhile(cond, body, flag) ->
908 loop cond || ((flag = DoWhile || is_true_expr cond) && in_loop body)
909 | TTry(e1,[]) ->
910 loop e1
911 | TTry(_,catches) ->
912 (* The try expression is irrelevant because we have to conservatively assume that
913 anything could throw control flow into the catch expressions. *)
914 List.for_all (fun (_,e) -> loop e) catches
915 | _ ->
916 check_expr loop e
917 in
918 try
919 loop e
920 with BreakOrContinue ->
921 true
922 end
0 open Globals
1 open Error
2 include WarningList
3
4 type warning_mode =
5 | WMEnable
6 | WMDisable
7
8 type warning_option = {
9 wo_warning : warning;
10 wo_mode : warning_mode;
11 }
12
13 let parse_options s ps lexbuf =
14 let fail msg p =
15 Error.typing_error msg {p with pmin = ps.pmin + p.pmin; pmax = ps.pmin + p.pmax}
16 in
17 let parse_string s p =
18 begin try
19 from_string s
20 with Exit ->
21 fail (Printf.sprintf "Unknown warning: %s" s) p
22 end
23 in
24 let parse_warning () = match Lexer.token lexbuf with
25 | Const (Ident s),p ->
26 parse_string s p
27 | (_,p) ->
28 fail "Expected identifier" p
29 in
30 let add acc mode warning =
31 { wo_warning = warning; wo_mode = mode } :: acc
32 in
33 let rec next acc = match Lexer.token lexbuf with
34 | Binop OpAdd,_ ->
35 next (add acc WMEnable (parse_warning()))
36 | Binop OpSub,_ ->
37 next (add acc WMDisable (parse_warning()))
38 | Eof,_ ->
39 List.rev acc
40 | (_,p) ->
41 fail "Expected + or -" p
42 in
43 next []
44
45 let parse_options s ps =
46 let restore = Lexer.reinit ps.pfile in
47 Std.finally (fun () ->
48 restore()
49 ) (fun () ->
50 let lexbuf = Sedlexing.Utf8.from_string s in
51 parse_options s ps lexbuf
52 ) ()
53
54 let from_meta ml =
55 let parse_arg e = match fst e with
56 | Ast.EConst (String(s,_)) ->
57 let p = snd e in
58 parse_options s {p with pmin = p.pmin + 1; pmax = p.pmax - 1} (* pmin is on the quote *)
59 | _ ->
60 Error.typing_error "String expected" (snd e)
61 in
62 let rec loop acc ml = match ml with
63 | (Meta.HaxeWarning,args,_) :: ml ->
64 let acc = List.fold_left (fun acc arg ->
65 (parse_arg arg) :: acc
66 ) acc args in
67 loop acc ml
68 | _ :: ml ->
69 loop acc ml
70 | [] ->
71 List.rev acc
72 in
73 loop [] ml
74
75 let get_mode w (l : warning_option list list) =
76 let rec matches w id =
77 id = w || match (warning_obj w).w_parent with
78 | None -> false
79 | Some w' -> matches w' id
80 in
81 let rec loop mode l = match l with
82 | [] ->
83 mode
84 | l2 :: l ->
85 let rec loop2 mode l = match l with
86 | [] ->
87 mode
88 | opt :: l ->
89 let mode = if matches w opt.wo_warning then opt.wo_mode else mode in
90 loop2 mode l
91 in
92 loop (loop2 mode l2) l
93 in
94 loop WMEnable (* ? *) l
88 (library
99 (name haxe)
1010 (libraries
11 extc extproc extlib_leftovers ilib javalib mbedtls neko objsize pcre swflib ttflib ziplib
11 extc extproc extlib_leftovers ilib javalib mbedtls neko objsize pcre2 swflib ttflib ziplib
1212 json
13 unix str threads dynlink
13 unix str bigarray threads dynlink
1414 xml-light extlib ptmap sha
1515 luv
1616 )
6060 List.iter (change_func com cl) cf.cf_overloads;
6161
6262 match cf.cf_kind, follow cf.cf_type with
63 | _ when has_class_field_flag cf CfPostProcessed ->
64 ()
6365 | Var _, _ | Method MethDynamic, _ ->
6466 ()
6567 | _, TFun(args, ret) ->
77 open Error
88
99 let haxe_exception_type_path = (["haxe"],"Exception")
10 let value_exception_type_path = (["haxe"],"ValueException")
1011
1112 type context = {
1213 typer : typer;
1415 config : exceptions_config;
1516 wildcard_catch_type : Type.t;
1617 base_throw_type : Type.t;
18 throws_anything : bool;
19 catches_anything : bool;
1720 haxe_exception_class : tclass;
1821 haxe_exception_type : Type.t;
1922 haxe_native_stack_trace : tclass;
23 value_exception_type : Type.t;
24 value_exception_class : tclass;
2025 }
2126
2227 let is_dynamic t =
3035 let haxe_exception_static_call ctx method_name args p =
3136 let method_field =
3237 try PMap.find method_name ctx.haxe_exception_class.cl_statics
33 with Not_found -> error ("haxe.Exception has no field " ^ method_name) p
38 with Not_found -> typing_error ("haxe.Exception has no field " ^ method_name) p
3439 in
3540 let return_type =
3641 match follow method_field.cf_type with
3742 | TFun(_,t) -> t
38 | _ -> error ("haxe.Exception." ^ method_name ^ " is not a function and cannot be called") p
43 | _ -> typing_error ("haxe.Exception." ^ method_name ^ " is not a function and cannot be called") p
3944 in
4045 add_dependency ctx.typer.curclass.cl_module ctx.haxe_exception_class.cl_module;
4146 make_static_call ctx.typer ctx.haxe_exception_class method_field (fun t -> t) args return_type p
5156 match follow cf.cf_type with
5257 | TFun(_,t) -> t
5358 | _ ->
54 error ((s_type (print_context()) haxe_exception.etype) ^ "." ^ method_name ^ " is not a function and cannot be called") p
59 typing_error ((s_type (print_context()) haxe_exception.etype) ^ "." ^ method_name ^ " is not a function and cannot be called") p
5560 in
5661 make_call ctx.typer efield args rt p
57 | _ -> error ((s_type (print_context()) haxe_exception.etype) ^ "." ^ method_name ^ " is expected to be an instance method") p
62 | _ -> typing_error ((s_type (print_context()) haxe_exception.etype) ^ "." ^ method_name ^ " is expected to be an instance method") p
5863
5964 (**
6065 Generate `Std.isOfType(e, t)`
6469 let std_cls =
6570 match Typeload.load_type_raise ctx.typer ([],"Std") "Std" p with
6671 | TClassDecl cls -> cls
67 | _ -> error "Std is expected to be a class" p
72 | _ -> typing_error "Std is expected to be a class" p
6873 in
6974 let isOfType_field =
7075 try PMap.find "isOfType" std_cls.cl_statics
71 with Not_found -> error ("Std has no field isOfType") p
76 with Not_found -> typing_error ("Std has no field isOfType") p
7277 in
7378 let return_type =
7479 match follow isOfType_field.cf_type with
7580 | TFun(_,t) -> t
76 | _ -> error ("Std.isOfType is not a function and cannot be called") p
81 | _ -> typing_error ("Std.isOfType is not a function and cannot be called") p
7782 in
7883 let type_expr = { eexpr = TTypeExpr(module_type_of_type t); etype = t; epos = p } in
7984 make_static_call ctx.typer std_cls isOfType_field (fun t -> t) [e; type_expr] return_type p
101106 (**
102107 Check if `t` can be thrown without wrapping.
103108 *)
104 let rec is_native_throw cfg t =
105 is_in_list t cfg.ec_native_throws
109 let rec is_native_throw ctx t =
110 ctx.throws_anything || is_in_list t ctx.config.ec_native_throws
106111
107112 (**
108113 Check if `t` can be caught without wrapping.
109114 *)
110 let rec is_native_catch cfg t =
111 is_in_list t cfg.ec_native_catches
115 let rec is_native_catch ctx t =
116 ctx.catches_anything || is_in_list t ctx.config.ec_native_catches
117
118 (**
119 Check if `t` can be used for a Haxe-specific wildcard catch.
120 E.g `catch(e:Dynamic)` or `catch(e:haxe.Exception)`
121 *)
122 let is_haxe_wildcard_catch ctx t =
123 let t = Abstract.follow_with_abstracts t in
124 t == t_dynamic || fast_eq ctx.haxe_exception_type t
112125
113126 (**
114127 Check if `cls` is or extends (if `check_parent=true`) `haxe.Exception`
145158 | _ -> check_expr contains_throw_or_try e
146159
147160 (**
161 Check if expression represents an exception wrapped with `haxe.Exception.thrown`
162 *)
163 let is_wrapped_exception e =
164 match e.eexpr with
165 | TMeta ((Meta.WrappedException, _, _), _) -> true
166 | _ -> false
167
168 (**
148169 Returns `true` if `e` has to be wrapped with `haxe.Exception.thrown(e)`
149170 to be thrown.
150171 *)
151 let requires_wrapped_throw cfg e =
152 if cfg.ec_special_throw e then
172 let requires_wrapped_throw ctx e =
173 if ctx.throws_anything || is_wrapped_exception e || ctx.config.ec_special_throw e then
153174 false
154175 else
155176 (*
165186 | _ -> true
166187 in
167188 is_stored_haxe_exception()
168 || (not (is_native_throw cfg e.etype) && not (is_haxe_exception e.etype))
189 || (not (is_native_throw ctx e.etype) && not (is_haxe_exception e.etype))
169190
170191 (**
171192 Generate a throw of a native exception.
172193 *)
173194 let throw_native ctx e_thrown t p =
174195 let e_native =
175 if requires_wrapped_throw ctx.config e_thrown then
196 if requires_wrapped_throw ctx e_thrown then
176197 let thrown = haxe_exception_static_call ctx "thrown" [e_thrown] p in
177 if is_dynamic ctx.base_throw_type then thrown
178 else mk_cast thrown ctx.base_throw_type p
198 let wrapped =
199 if is_dynamic ctx.base_throw_type then thrown
200 else mk_cast thrown ctx.base_throw_type p
201 in
202 mk (TMeta ((Meta.WrappedException,[],p),wrapped)) thrown.etype p
179203 else
180204 e_thrown
181205 in
229253 | None ->
230254 mk (TBlock[]) ctx.basic.tvoid p
231255 end
256
257 (**
258 Transforms the set of catch-blocks into `if(Std.is(e, ExceptionType)`-fest.
259
260 `t` - the type of `try...catch` expression under transformation.
261 *)
262 let catches_to_ifs ctx catches t p =
263 match catches with
264 | [] -> []
265 | ((first_v, first_body) :: _) as rest ->
266 let catch_var = alloc_var VGenerated "`" ctx.wildcard_catch_type first_v.v_pos in
267 add_var_flag catch_var VCaught;
268 let catch_local = mk (TLocal catch_var) catch_var.v_type catch_var.v_pos in
269 let body =
270 let catch = new catch ctx catch_local p in
271 let rec transform = function
272 | (v, body) :: rest ->
273 let current_t = Abstract.follow_with_abstracts v.v_type in
274 let var_used = is_var_used v body in
275 (* catch(e:ExtendsHaxeError) *)
276 if is_haxe_exception current_t then
277 let condition =
278 (* catch(e:haxe.Exception) is a wildcard catch *)
279 if fast_eq ctx.haxe_exception_type current_t then
280 mk (TConst (TBool true)) ctx.basic.tbool v.v_pos
281 else
282 std_is ctx (catch#get_haxe_exception v.v_pos) v.v_type v.v_pos
283 in
284 let body =
285 if var_used then
286 mk (TBlock [
287 (* var v:ExceptionType = cast haxe_exception_local; *)
288 mk (TVar (v, Some (mk_cast (catch#get_haxe_exception v.v_pos) v.v_type v.v_pos))) ctx.basic.tvoid v.v_pos;
289 body
290 ]) body.etype body.epos
291 else
292 body
293 in
294 compose condition body rest
295 (* catch(e:Dynamic) *)
296 else if current_t == t_dynamic then
297 begin
298 set_needs_exception_stack catch_var;
299 (* this is a wildcard catch *)
300 let condition = mk (TConst (TBool true)) ctx.basic.tbool v.v_pos in
301 let body =
302 mk (TBlock [
303 if var_used then
304 (* `var v:Dynamic = catch_local;` or `var v:Dynamic = haxe_exception_local.unwrap();` *)
305 let e =
306 if ctx.catches_anything then catch_local
307 else catch#unwrap v.v_pos
308 in
309 mk (TVar (v, Some e)) ctx.basic.tvoid v.v_pos
310 else
311 mk (TBlock[]) ctx.basic.tvoid v.v_pos;
312 body
313 ]) body.etype body.epos
314 in
315 compose condition body rest
316 end
317 (* catch(e:NativeWildcardException) *)
318 else if fast_eq ctx.wildcard_catch_type current_t then
319 begin
320 set_needs_exception_stack catch_var;
321 (* this is a wildcard catch *)
322 let condition = mk (TConst (TBool true)) ctx.basic.tbool v.v_pos in
323 let body =
324 mk (TBlock [
325 (* var v:NativeWildcardException = catch_var; *)
326 if var_used then
327 mk (TVar (v, Some catch_local)) ctx.basic.tvoid v.v_pos
328 else
329 mk (TBlock[]) ctx.basic.tvoid v.v_pos;
330 body
331 ]) body.etype body.epos
332 in
333 compose condition body rest
334 end
335 (* catch(e:AnythingElse) *)
336 else begin
337 set_needs_exception_stack catch_var;
338 let condition =
339 (* Std.isOfType(haxe_exception_local.unwrap(), ExceptionType) *)
340 std_is ctx (catch#unwrap v.v_pos) v.v_type v.v_pos
341 in
342 let body =
343 mk (TBlock [
344 (* var v:ExceptionType = cast haxe_exception_local.unwrap() *)
345 if var_used then
346 mk (TVar (v, Some (mk_cast (catch#unwrap v.v_pos) v.v_type v.v_pos))) ctx.basic.tvoid v.v_pos
347 else
348 mk (TBlock[]) ctx.basic.tvoid v.v_pos;
349 body
350 ]) body.etype body.epos
351 in
352 compose condition body rest
353 end
354 | [] -> mk (TThrow catch_local) t p
355 and compose condition body rest_catches =
356 let else_body =
357 match rest_catches with
358 | [] -> mk (TThrow catch_local) (mk_mono()) p
359 | _ -> transform rest_catches
360 in
361 mk (TIf(condition, body, Some else_body)) t p
362 in
363 let transformed_catches = transform rest in
364 (* haxe.Exception.caught(catch_var) *)
365 let exprs = [
366 (* var haxe_exception_local = haxe.Exception.caught(catch_var); *)
367 catch#declare_haxe_exception catch_var.v_pos;
368 (* var unwrapped_local = haxe_exception_local.unwrap(); *)
369 catch#declare_unwrap catch_var.v_pos;
370 transformed_catches
371 ] in
372 mk (TBlock exprs) t p
373 in (* let body = *)
374 [(catch_var,body)]
375
376 (**
377 Transforms set of catches into
378 ```
379 catch(e:ValueException) {
380 if(Std.isOfType(e.value, Exception1)) {
381 <...>
382 } else if(Std.isOfType(e.value, Exception2)) {
383 <...>
384 } else <...>
385 }
386 ```
387 *)
388 let catches_as_value_exception ctx non_value_exception_catches value_exception_catch t p =
389 match non_value_exception_catches, value_exception_catch with
390 | [], None ->
391 die ~p "Nothing to transform into ValueException catch" __LOC__
392 | [], Some catch ->
393 catch
394 | (first_v,_) :: _, _ ->
395 let catch_var =
396 match value_exception_catch with
397 | Some (catch_var, _) ->
398 catch_var
399 | None ->
400 let catch_var = alloc_var VGenerated "`" ctx.value_exception_type first_v.v_pos in
401 add_var_flag catch_var VCaught;
402 catch_var
403 in
404 let catch_local =
405 mk (TLocal catch_var) catch_var.v_type catch_var.v_pos
406 in
407 (* catch_local.value *)
408 let catch_local_value =
409 let cf =
410 try PMap.find "value" ctx.value_exception_class.cl_fields
411 with Not_found -> die "haxe.ValueException is missing field \"value\"" __LOC__
412 in
413 mk (TField (catch_local, FInstance (ctx.value_exception_class,[],cf))) cf.cf_type catch_local.epos
414 in
415 let rec traverse catches final_else =
416 match catches with
417 | [] -> final_else
418 | (v,body) :: rest ->
419 set_needs_exception_stack catch_var;
420 (* Std.isOfType(catch_local.value, ExceptionType) *)
421 let condition = std_is ctx catch_local_value v.v_type v.v_pos in
422 let body =
423 mk (TBlock [
424 (* var v:ExceptionType = cast catch_local.value *)
425 if is_var_used v body then
426 mk (TVar (v, Some (mk_cast catch_local_value v.v_type v.v_pos))) ctx.basic.tvoid v.v_pos
427 else
428 mk (TBlock[]) ctx.basic.tvoid v.v_pos;
429 body
430 ]) body.etype body.epos
431 in
432 mk (TIf (condition,body,Some (traverse rest final_else))) t p
433 in
434 let final_else =
435 Option.map_default
436 (fun (_,body) -> body)
437 (mk (TThrow catch_local) t_dynamic p)
438 value_exception_catch
439 in
440 (catch_var, traverse non_value_exception_catches final_else)
232441
233442 (**
234443 Transform user-written `catches` to a set of catches, which would not require
258467 ```
259468 *)
260469 let catch_native ctx catches t p =
261 let rec transform = function
262 | [] -> []
470 let rec transform handle_as_value_exception value_exception_catch catches =
471 match catches with
472 | [] ->
473 (match handle_as_value_exception, value_exception_catch with
474 | [], None ->
475 []
476 | [], Some catch ->
477 catches_to_ifs ctx [catch] t p
478 | _, _ ->
479 [catches_as_value_exception ctx handle_as_value_exception None t p]
480 @ Option.map_default (fun catch -> catches_to_ifs ctx [catch] t p) [] value_exception_catch
481 )
482 (* Haxe-specific wildcard catches should go to if-fest because they need additional handling *)
483 | (v,_) :: _ when is_haxe_wildcard_catch ctx v.v_type ->
484 (match handle_as_value_exception with
485 | [] ->
486 catches_to_ifs ctx catches t p
487 | _ ->
488 catches_as_value_exception ctx handle_as_value_exception None t p
489 :: catches_to_ifs ctx catches t p
490 )
491 | (v,_) as current :: rest when ctx.catches_anything && fast_eq ctx.value_exception_type (Abstract.follow_with_abstracts v.v_type) ->
492 catches_as_value_exception ctx handle_as_value_exception (Some current) t p
493 :: transform [] (Some (Option.default current value_exception_catch)) rest
263494 (* Keep catches for native exceptions intact *)
264 | (v,_) as current :: rest when (is_native_catch ctx.config v.v_type)
265 (*
266 In case haxe.Exception extends native exception on current target.
267 We don't want it to be generated as a native catch.
268 *)
269 && not (fast_eq ctx.haxe_exception_type (follow v.v_type)) ->
270 current :: (transform rest)
271 (* Everything else falls into `if(Std.is(e, ExceptionType)`-fest *)
272 | ((first_v, first_body) :: _) as rest ->
273 let catch_var = alloc_var VGenerated "`" ctx.wildcard_catch_type first_v.v_pos in
274 add_var_flag catch_var VCaught;
275 let catch_local = mk (TLocal catch_var) catch_var.v_type catch_var.v_pos in
276 let body =
277 let catch = new catch ctx catch_local p in
278 let rec transform = function
279 | (v, body) :: rest ->
280 let current_t = Abstract.follow_with_abstracts v.v_type in
281 let var_used = is_var_used v body in
282 (* catch(e:ExtendsHaxeError) *)
283 if is_haxe_exception current_t then
284 let condition =
285 (* catch(e:haxe.Exception) is a wildcard catch *)
286 if fast_eq ctx.haxe_exception_type current_t then
287 mk (TConst (TBool true)) ctx.basic.tbool v.v_pos
288 else begin
289 std_is ctx (catch#get_haxe_exception v.v_pos) v.v_type v.v_pos
290 end
291 in
292 let body =
293 if var_used then
294 mk (TBlock [
295 (* var v:ExceptionType = cast haxe_exception_local; *)
296 mk (TVar (v, Some (mk_cast (catch#get_haxe_exception v.v_pos) v.v_type v.v_pos))) ctx.basic.tvoid v.v_pos;
297 body
298 ]) body.etype body.epos
299 else
300 body
301 in
302 compose condition body rest
303 (* catch(e:Dynamic) *)
304 else if current_t == t_dynamic then
305 begin
306 set_needs_exception_stack catch_var;
307 (* this is a wildcard catch *)
308 let condition = mk (TConst (TBool true)) ctx.basic.tbool v.v_pos in
309 let body =
310 mk (TBlock [
311 (* var v:Dynamic = haxe_exception_local.unwrap(); *)
312 if var_used then
313 mk (TVar (v, Some (catch#unwrap v.v_pos))) ctx.basic.tvoid v.v_pos
314 else
315 mk (TBlock[]) ctx.basic.tvoid v.v_pos;
316 body
317 ]) body.etype body.epos
318 in
319 compose condition body rest
320 end
321 (* catch(e:NativeWildcardException) *)
322 else if fast_eq ctx.wildcard_catch_type current_t then
323 begin
324 set_needs_exception_stack catch_var;
325 (* this is a wildcard catch *)
326 let condition = mk (TConst (TBool true)) ctx.basic.tbool v.v_pos in
327 let body =
328 mk (TBlock [
329 (* var v:NativeWildcardException = catch_var; *)
330 if var_used then
331 mk (TVar (v, Some catch_local)) ctx.basic.tvoid v.v_pos
332 else
333 mk (TBlock[]) ctx.basic.tvoid v.v_pos;
334 body
335 ]) body.etype body.epos
336 in
337 compose condition body rest
338 end
339 (* catch(e:AnythingElse) *)
340 else begin
341 set_needs_exception_stack catch_var;
342 let condition =
343 (* Std.isOfType(haxe_exception_local.unwrap(), ExceptionType) *)
344 std_is ctx (catch#unwrap v.v_pos) v.v_type v.v_pos
345 in
346 let body =
347 mk (TBlock [
348 (* var v:ExceptionType = cast haxe_exception_local.unwrap() *)
349 if var_used then
350 mk (TVar (v, Some (mk_cast (catch#unwrap v.v_pos) v.v_type v.v_pos))) ctx.basic.tvoid v.v_pos
351 else
352 mk (TBlock[]) ctx.basic.tvoid v.v_pos;
353 body
354 ]) body.etype body.epos
355 in
356 compose condition body rest
357 end
358 | [] -> mk (TThrow catch_local) t p
359 and compose condition body rest_catches =
360 let else_body =
361 match rest_catches with
362 | [] -> mk (TThrow catch_local) (mk_mono()) p
363 | _ -> transform rest_catches
364 in
365 mk (TIf(condition, body, Some else_body)) t p
366 in
367 let transformed_catches = transform rest in
368 (* haxe.Exception.caught(catch_var) *)
369 let exprs = [
370 (* var haxe_exception_local = haxe.Exception.caught(catch_var); *)
371 catch#declare_haxe_exception catch_var.v_pos;
372 (* var unwrapped_local = haxe_exception_local.unwrap(); *)
373 catch#declare_unwrap catch_var.v_pos;
374 transformed_catches
375 ] in
376 mk (TBlock exprs) t p
377 in (* let body = *)
378 [(catch_var,body)]
495 | (v,_) as current :: rest when (is_native_catch ctx v.v_type) ->
496 let handle_as_value_exception =
497 (*
498 If current target can catch any type natively, then we also need
499 to check if `new haxe.ValueException(value)` with the same type of
500 `value` was thrown. That is, we should be able to catch `throw 'error'`
501 and `throw new ValueException('error')` with a single `catch(e:String)`
502 expression in user's code to be consistent with targets which can't
503 catch arbitrary types.
504 *)
505 if ctx.catches_anything && not (is_haxe_exception v.v_type) then
506 current :: handle_as_value_exception
507 else
508 handle_as_value_exception
509 in
510 current :: (transform handle_as_value_exception value_exception_catch rest)
511 (* everything else goes to if-fest *)
512 | catches ->
513 catches_to_ifs ctx (handle_as_value_exception @ catches) t p
379514 in
380 transform catches
515 transform [] None catches
381516
382517 (**
383518 Transform `throw` and `try..catch` expressions.
406541 and haxe_exception_type, haxe_exception_class =
407542 match Typeload.load_instance tctx (tp haxe_exception_type_path) true with
408543 | TInst(cls,_) as t -> t,cls
409 | _ -> error "haxe.Exception is expected to be a class" null_pos
544 | _ -> typing_error "haxe.Exception is expected to be a class" null_pos
545 and value_exception_type, value_exception_class =
546 match Typeload.load_instance tctx (tp value_exception_type_path) true with
547 | TInst(cls,_) as t -> t,cls
548 | _ -> typing_error "haxe.ValueException is expected to be a class" null_pos
410549 and haxe_native_stack_trace =
411550 match Typeload.load_instance tctx (tp (["haxe"],"NativeStackTrace")) true with
412551 | TInst(cls,_) -> cls
413552 | TAbstract({ a_impl = Some cls },_) -> cls
414 | _ -> error "haxe.NativeStackTrace is expected to be a class or an abstract" null_pos
553 | _ -> typing_error "haxe.NativeStackTrace is expected to be a class or an abstract" null_pos
554 in
555 let is_path_of_dynamic (pack,name) =
556 name = "Dynamic" && (pack = [] || pack = ["StdTypes"])
415557 in
416558 let ctx = {
417559 typer = tctx;
419561 config = config;
420562 wildcard_catch_type = wildcard_catch_type;
421563 base_throw_type = base_throw_type;
564 throws_anything = is_path_of_dynamic config.ec_base_throw && config.ec_avoid_wrapping;
565 catches_anything = is_path_of_dynamic config.ec_wildcard_catch && config.ec_avoid_wrapping;
422566 haxe_exception_class = haxe_exception_class;
423567 haxe_exception_type = haxe_exception_type;
424568 haxe_native_stack_trace = haxe_native_stack_trace;
569 value_exception_type = value_exception_type;
570 value_exception_class = value_exception_class;
425571 } in
426572 let rec run e =
427573 match e.eexpr with
454600 match Typeload.load_type_def tctx null_pos tp with
455601 | TClassDecl cls -> cls
456602 | TAbstractDecl { a_impl = Some cls } -> cls
457 | _ -> error "haxe.NativeStackTrace is expected to be a class or an abstract" null_pos
603 | _ -> typing_error "haxe.NativeStackTrace is expected to be a class or an abstract" null_pos
458604 in
459605 let rec contains_insertion_points e =
460606 match e.eexpr with
470616 if has_feature tctx.com "haxe.NativeStackTrace.exceptionStack" then
471617 let method_field =
472618 try PMap.find "saveStack" native_stack_trace_cls.cl_statics
473 with Not_found -> error ("haxe.NativeStackTrace has no field saveStack") null_pos
619 with Not_found -> typing_error ("haxe.NativeStackTrace has no field saveStack") null_pos
474620 in
475621 let return_type =
476622 match follow method_field.cf_type with
477623 | TFun(_,t) -> t
478 | _ -> error ("haxe.NativeStackTrace." ^ method_field.cf_name ^ " is not a function and cannot be called") null_pos
624 | _ -> typing_error ("haxe.NativeStackTrace." ^ method_field.cf_name ^ " is not a function and cannot be called") null_pos
479625 in
480626 let catch_local = mk (TLocal catch_var) catch_var.v_type catch_var.v_pos in
481627 begin
529675 let this = { eexpr = TConst(TThis); etype = t; epos = p } in
530676 let faccess =
531677 try quick_field t "__shiftStack"
532 with Not_found -> error "haxe.Exception has no field __shiftStack" p
678 with Not_found -> typing_error "haxe.Exception has no field __shiftStack" p
533679 in
534680 match faccess with
535681 | FInstance (_,_,cf) ->
538684 match follow cf.cf_type with
539685 | TFun(_,t) -> t
540686 | _ ->
541 error "haxe.Exception.__shiftStack is not a function and cannot be called" cf.cf_name_pos
687 typing_error "haxe.Exception.__shiftStack is not a function and cannot be called" cf.cf_name_pos
542688 in
543689 make_call tctx efield [] rt p
544 | _ -> error "haxe.Exception.__shiftStack is expected to be an instance method" p
690 | _ -> typing_error "haxe.Exception.__shiftStack is expected to be an instance method" p
545691 in
546692 TypeloadFunction.add_constructor tctx cls true cls.cl_name_pos;
547693 Option.may (fun cf -> ignore(follow cf.cf_type)) cls.cl_constructor;
6565 { e with eexpr = TFunction f }
6666 | _ -> e
6767
68 module LocalStatic = struct
69 let promote_local_static ctx lut v eo =
70 let name = Printf.sprintf "%s_%s" ctx.curfield.cf_name v.v_name in
71 begin try
72 let cf = PMap.find name ctx.curclass.cl_statics in
73 display_error ctx.com (Printf.sprintf "The expanded name of this local (%s) conflicts with another static field" name) v.v_pos;
74 typing_error ~depth:1 "Conflicting field was found here" cf.cf_name_pos;
75 with Not_found ->
76 let cf = mk_field name ~static:true v.v_type v.v_pos v.v_pos in
77 begin match eo with
78 | None ->
79 ()
80 | Some e ->
81 let rec loop e = match e.eexpr with
82 | TLocal _ | TFunction _ ->
83 typing_error "Accessing local variables in static initialization is not allowed" e.epos
84 | TConst (TThis | TSuper) ->
85 typing_error "Accessing `this` in static initialization is not allowed" e.epos
86 | TReturn _ | TBreak | TContinue ->
87 typing_error "This kind of control flow in static initialization is not allowed" e.epos
88 | _ ->
89 iter loop e
90 in
91 loop e;
92 cf.cf_expr <- Some e
93 end;
94 TClass.add_field ctx.curclass cf;
95 Hashtbl.add lut v.v_id cf
96 end
97
98 let find_local_static lut v =
99 Hashtbl.find lut v.v_id
100
101 let run ctx e =
102 let local_static_lut = Hashtbl.create 0 in
103 let c = ctx.curclass in
104 let rec run e = match e.eexpr with
105 | TBlock el ->
106 let el = ExtList.List.filter_map (fun e -> match e.eexpr with
107 | TVar(v,eo) when has_var_flag v VStatic ->
108 promote_local_static ctx local_static_lut v eo;
109 None
110 | _ ->
111 Some (run e)
112 ) el in
113 { e with eexpr = TBlock el }
114 | TLocal v when has_var_flag v VStatic ->
115 begin try
116 let cf = find_local_static local_static_lut v in
117 Texpr.Builder.make_static_field c cf e.epos
118 with Not_found ->
119 typing_error (Printf.sprintf "Could not find local static %s (id %i)" v.v_name v.v_id) e.epos
120 end
121 | _ ->
122 Type.map_expr run e
123 in
124 run e
125 end
126
68127 (* -------------------------------------------------------------------------- *)
69128 (* CHECK LOCAL VARS INIT *)
70129
71 let check_local_vars_init com e =
130 let check_local_vars_init ctx e =
72131 let intersect vl1 vl2 =
73132 PMap.mapi (fun v t -> t && PMap.find v vl2) vl1
74133 in
83142 in
84143 let declared = ref [] in
85144 let outside_vars = ref IntMap.empty in
145 (* Set variables which belong to current function *)
146 let set_all_vars vars =
147 vars := PMap.mapi (fun id is_set -> if IntMap.mem id !outside_vars then is_set else true) !vars
148 in
86149 let rec loop vars e =
87150 match e.eexpr with
88151 | TLocal v ->
89152 let init = (try PMap.find v.v_id !vars with Not_found -> true) in
90153 if not init then begin
91154 if IntMap.mem v.v_id !outside_vars then
92 if v.v_name = "this" then com.warning "this might be used before assigning a value to it" e.epos
93 else com.warning ("Local variable " ^ v.v_name ^ " might be used before being initialized") e.epos
155 if v.v_name = "this" then warning ctx WVarInit "this might be used before assigning a value to it" e.epos
156 else warning ctx WVarInit ("Local variable " ^ v.v_name ^ " might be used before being initialized") e.epos
94157 else
95 if v.v_name = "this" then error "Missing this = value" e.epos
96 else error ("Local variable " ^ v.v_name ^ " used without being initialized") e.epos
158 if v.v_name = "this" then typing_error "Missing this = value" e.epos
159 else typing_error ("Local variable " ^ v.v_name ^ " used without being initialized") e.epos
97160 end
98161 | TVar (v,eo) ->
99162 begin
114177 restore vars old_vars (List.rev !declared);
115178 declared := old;
116179 | TBinop (OpAssign,{ eexpr = TLocal v },e) when PMap.mem v.v_id !vars ->
117 loop vars e;
118 vars := PMap.add v.v_id true !vars
180 begin match (Texpr.skip e).eexpr with
181 | TFunction _ ->
182 (* We can be sure that the function doesn't execute immediately, so it's fine to
183 consider the local initialized (issue #9919). *)
184 vars := PMap.add v.v_id true !vars;
185 loop vars e;
186 | _ ->
187 loop vars e;
188 vars := PMap.add v.v_id true !vars
189 end
119190 | TIf (e1,e2,eo) ->
120191 loop vars e1;
121192 let vbase = !vars in
173244 join vars cvars)
174245 (* mark all reachable vars as initialized, since we don't exit the block *)
175246 | TBreak | TContinue | TReturn None ->
176 vars := PMap.map (fun _ -> true) !vars
247 set_all_vars vars
177248 | TThrow e | TReturn (Some e) ->
178249 loop vars e;
179 vars := PMap.map (fun _ -> true) !vars
250 set_all_vars vars
180251 | TFunction tf ->
181252 let old = !outside_vars in
182253 (* Mark all known variables as "outside" so we can ignore their initialization state within the function.
193264
194265 let mark_switch_break_loops e =
195266 let add_loop_label n e =
196 { e with eexpr = TMeta ((Meta.LoopLabel,[(EConst(Int(string_of_int n)),e.epos)],e.epos), e) }
267 { e with eexpr = TMeta ((Meta.LoopLabel,[(EConst(Int(string_of_int n, None)),e.epos)],e.epos), e) }
197268 in
198269 let in_switch = ref false in
199270 let did_found = ref (-1) in
273344 match e.eexpr with
274345 | TField ({ eexpr = TTypeExpr _ }, _) -> ()
275346 | TTypeExpr(TClassDecl {cl_kind = KAbstractImpl a}) when not (Meta.has Meta.RuntimeValue a.a_meta) ->
276 error "Cannot use abstract as value" e.epos
347 typing_error "Cannot use abstract as value" e.epos
277348 | _ -> Type.iter loop e
278349 in
279350 loop e;
281352
282353 (* PASS 1 end *)
283354
284 (* Saves a class state so it can be restored later, e.g. after DCE or native path rewrite *)
285 let save_class_state ctx t = match t with
286 | TClassDecl c ->
287 let vars = ref [] in
288 let rec save_vars e =
289 let add v = vars := (v, v.v_type) :: !vars in
290 match e.eexpr with
291 | TFunction fn ->
292 List.iter (fun (v, _) -> add v) fn.tf_args;
293 save_vars fn.tf_expr
294 | TVar (v, e) ->
295 add v;
296 Option.may save_vars e
297 | _ ->
298 iter save_vars e
299 in
300 let mk_field_restore f =
301 Option.may save_vars f.cf_expr;
302 let rec mk_overload_restore f =
303 f.cf_name,f.cf_kind,f.cf_expr,f.cf_type,f.cf_meta,f.cf_params
304 in
305 ( f,mk_overload_restore f, List.map (fun f -> f,mk_overload_restore f) f.cf_overloads )
306 in
307 let restore_field (f,res,overloads) =
308 let restore_field (f,(name,kind,expr,t,meta,params)) =
309 f.cf_name <- name; f.cf_kind <- kind; f.cf_expr <- expr; f.cf_type <- t; f.cf_meta <- meta; f.cf_params <- params;
310 f
311 in
312 let f = restore_field (f,res) in
313 f.cf_overloads <- List.map restore_field overloads;
314 f
315 in
316 let mk_pmap lst =
317 List.fold_left (fun pmap f -> PMap.add f.cf_name f pmap) PMap.empty lst
318 in
319
320 let meta = c.cl_meta and path = c.cl_path and ext = (has_class_flag c CExtern) in
321 let sup = c.cl_super and impl = c.cl_implements in
322 let csr = Option.map (mk_field_restore) c.cl_constructor in
323 let ofr = List.map (mk_field_restore) c.cl_ordered_fields in
324 let osr = List.map (mk_field_restore) c.cl_ordered_statics in
325 let init = c.cl_init in
326 Option.may save_vars init;
327 c.cl_restore <- (fun() ->
328 c.cl_super <- sup;
329 c.cl_implements <- impl;
330 c.cl_meta <- meta;
331 if ext then add_class_flag c CExtern else remove_class_flag c CExtern;
332 c.cl_path <- path;
333 c.cl_init <- init;
334 c.cl_ordered_fields <- List.map restore_field ofr;
335 c.cl_ordered_statics <- List.map restore_field osr;
336 c.cl_fields <- mk_pmap c.cl_ordered_fields;
337 c.cl_statics <- mk_pmap c.cl_ordered_statics;
338 c.cl_constructor <- Option.map restore_field csr;
339 c.cl_descendants <- [];
340 List.iter (fun (v, t) -> v.v_type <- t) !vars;
341 )
342 | _ ->
343 ()
344
345355 (* PASS 2 begin *)
346356
347 let remove_generic_base ctx t = match t with
357 let remove_generic_base t = match t with
348358 | TClassDecl c when is_removable_class c ->
349359 add_class_flag c CExtern;
350360 | _ ->
352362
353363 (* Removes extern and macro fields, also checks for Void fields *)
354364
355 let remove_extern_fields ctx t = match t with
365 let remove_extern_fields com t = match t with
356366 | TClassDecl c ->
357 if not (Common.defined ctx.com Define.DocGen) then begin
367 if not (Common.defined com Define.DocGen) then begin
358368 c.cl_ordered_fields <- List.filter (fun f ->
359 let b = is_removable_field ctx f in
369 let b = is_removable_field com f in
360370 if b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
361371 not b
362372 ) c.cl_ordered_fields;
363373 c.cl_ordered_statics <- List.filter (fun f ->
364 let b = is_removable_field ctx f in
374 let b = is_removable_field com f in
365375 if b then c.cl_statics <- PMap.remove f.cf_name c.cl_statics;
366376 not b
367377 ) c.cl_ordered_statics;
377387 let check_private_path ctx t = match t with
378388 | TClassDecl c when c.cl_private ->
379389 let rpath = (fst c.cl_module.m_path,"_" ^ snd c.cl_module.m_path) in
380 if Hashtbl.mem ctx.g.types_module rpath then error ("This private class name will clash with " ^ s_type_path rpath) c.cl_pos;
390 if ctx.com.type_to_module#mem rpath then typing_error ("This private class name will clash with " ^ s_type_path rpath) c.cl_pos;
381391 | _ ->
382392 ()
383393
384394 (* Rewrites class or enum paths if @:native metadata is set *)
385 let apply_native_paths ctx t =
395 let apply_native_paths t =
386396 let get_real_name meta name =
387397 let name',p = get_native_name meta in
388398 (Meta.RealPath,[Ast.EConst (Ast.String (name,SDoubleQuotes)), p], p), name'
447457 ()
448458
449459 (* Adds the __rtti field if required *)
450 let add_rtti ctx t =
460 let add_rtti com t =
451461 let rec has_rtti c =
452462 Meta.has Meta.Rtti c.cl_meta || match c.cl_super with None -> false | Some (csup,_) -> has_rtti csup
453463 in
454464 match t with
455465 | TClassDecl c when has_rtti c && not (PMap.mem "__rtti" c.cl_statics) ->
456 let f = mk_field ~static:true "__rtti" ctx.t.tstring c.cl_pos null_pos in
457 let str = Genxml.gen_type_string ctx.com t in
466 let f = mk_field ~static:true "__rtti" com.basic.tstring c.cl_pos null_pos in
467 let str = Genxml.gen_type_string com t in
458468 f.cf_expr <- Some (mk (TConst (TString str)) f.cf_type c.cl_pos);
459469 c.cl_ordered_statics <- f :: c.cl_ordered_statics;
460470 c.cl_statics <- PMap.add f.cf_name f c.cl_statics;
462472 ()
463473
464474 (* Adds member field initializations as assignments to the constructor *)
465 let add_field_inits locals ctx t =
475 let add_field_inits cl_path locals com t =
466476 let apply c =
467 let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_params)) c.cl_pos in
477 let ethis = mk (TConst TThis) (TInst (c,extract_param_types c.cl_params)) c.cl_pos in
468478 (* TODO: we have to find a variable name which is not used in any of the functions *)
469479 let v = alloc_var VGenerated "_g" ethis.etype ethis.epos in
470480 let need_this = ref false in
481491 match cf.cf_expr with
482492 | None -> die "" __LOC__
483493 | Some e ->
484 let lhs = mk (TField({ ethis with epos = cf.cf_pos },FInstance (c,List.map snd c.cl_params,cf))) cf.cf_type cf.cf_pos in
494 let lhs = mk (TField({ ethis with epos = cf.cf_pos },FInstance (c,extract_param_types c.cl_params,cf))) cf.cf_type cf.cf_pos in
485495 cf.cf_expr <- None;
486496 mk (TBinop(OpAssign,lhs,e)) cf.cf_type e.epos
487497 ) inits in
488498 let el = if !need_this then (mk (TVar((v, Some ethis))) ethis.etype ethis.epos) :: el else el in
489499 let cf = match c.cl_constructor with
490500 | None ->
491 let ct = TFun([],ctx.com.basic.tvoid) in
501 let ct = TFun([],com.basic.tvoid) in
492502 let ce = mk (TFunction {
493503 tf_args = [];
494 tf_type = ctx.com.basic.tvoid;
495 tf_expr = mk (TBlock el) ctx.com.basic.tvoid c.cl_pos;
504 tf_type = com.basic.tvoid;
505 tf_expr = mk (TBlock el) com.basic.tvoid c.cl_pos;
496506 }) ct c.cl_pos in
497507 let ctor = mk_field "new" ct c.cl_pos null_pos in
498508 ctor.cf_kind <- Method MethNormal;
501511 match cf.cf_expr with
502512 | Some { eexpr = TFunction f } ->
503513 let bl = match f.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in
504 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
514 let ce = mk (TFunction {f with tf_expr = mk (TBlock (el @ bl)) com.basic.tvoid c.cl_pos }) cf.cf_type cf.cf_pos in
505515 {cf with cf_expr = Some ce };
506516 | _ ->
507517 die "" __LOC__
508518 in
509 let config = AnalyzerConfig.get_field_config ctx.com c cf in
510 Analyzer.Run.run_on_field ctx config c cf;
519 let config = AnalyzerConfig.get_field_config com c cf in
520 remove_class_field_flag cf CfPostProcessed;
521 Analyzer.Run.run_on_field com config c cf;
522 add_class_field_flag cf CfPostProcessed;
511523 (match cf.cf_expr with
512524 | Some e ->
513525 (* This seems a bit expensive, but hopefully constructor expressions aren't that massive. *)
514 let e = RenameVars.run ctx locals e in
515 let e = Optimizer.sanitize ctx.com e in
526 let e = RenameVars.run cl_path locals e in
527 let e = Optimizer.sanitize com e in
516528 cf.cf_expr <- Some e
517529 | _ ->
518530 ());
525537 ()
526538
527539 (* Adds the __meta__ field if required *)
528 let add_meta_field ctx t = match t with
540 let add_meta_field com t = match t with
529541 | TClassDecl c ->
530 (match Texpr.build_metadata ctx.com.basic t with
542 (match Texpr.build_metadata com.basic t with
531543 | None -> ()
532544 | Some e ->
533 add_feature ctx.com "has_metadata";
545 add_feature com "has_metadata";
534546 let cf = mk_field ~static:true "__meta__" e.etype e.epos null_pos in
535547 cf.cf_expr <- Some e;
536 let can_deal_with_interface_metadata () = match ctx.com.platform with
548 let can_deal_with_interface_metadata () = match com.platform with
537549 | Cs | Java -> false
538550 | _ -> true
539551 in
543555 let ncls = mk_class c.cl_module path c.cl_pos null_pos in
544556 ncls.cl_ordered_statics <- cf :: ncls.cl_ordered_statics;
545557 ncls.cl_statics <- PMap.add cf.cf_name cf ncls.cl_statics;
546 ctx.com.types <- ctx.com.types @ [ TClassDecl ncls ];
558 com.types <- com.types @ [ TClassDecl ncls ];
547559 c.cl_meta <- (Meta.Custom ":hasMetadata",[],e.epos) :: c.cl_meta
548560 end else begin
549561 c.cl_ordered_statics <- cf :: c.cl_ordered_statics;
561573 | TClassDecl cl when not (has_class_flag cl CExtern) ->
562574 let check fields f =
563575 match f.cf_kind with
564 | Var { v_read = AccNormal; v_write = AccNormal } when Meta.has Meta.Event f.cf_meta ->
565 if (has_class_field_flag f CfPublic) then error "@:event fields must be private" f.cf_pos;
576 | Var { v_read = AccNormal; v_write = AccNormal } when Meta.has Meta.Event f.cf_meta && not (has_class_field_flag f CfPostProcessed) ->
577 if (has_class_field_flag f CfPublic) then typing_error "@:event fields must be private" f.cf_pos;
566578
567579 (* prevent generating reflect helpers for the event in gencommon *)
568580 f.cf_meta <- (Meta.SkipReflection, [], f.cf_pos) :: f.cf_meta;
571583 let tmeth = (tfun [f.cf_type] com.basic.tvoid) in
572584
573585 let process_event_method name =
574 let m = try PMap.find name fields with Not_found -> error ("Missing event method: " ^ name) f.cf_pos in
586 let m = try PMap.find name fields with Not_found -> typing_error ("Missing event method: " ^ name) f.cf_pos in
575587
576588 (* check method signature *)
577589 begin
602614 ()
603615
604616 (* Removes interfaces tagged with @:remove metadata *)
605 let check_remove_metadata ctx t = match t with
617 let check_remove_metadata t = match t with
606618 | TClassDecl c ->
607619 c.cl_implements <- List.filter (fun (c,_) -> not (Meta.has Meta.Remove c.cl_meta)) c.cl_implements;
608620 | _ ->
609621 ()
610622
611623 (* Checks for Void class fields *)
612 let check_void_field ctx t = match t with
624 let check_void_field t = match t with
613625 | TClassDecl c ->
614626 let check f =
615 match follow f.cf_type with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed" f.cf_pos | _ -> ();
627 match follow f.cf_type with TAbstract({a_path=[],"Void"},_) -> typing_error "Fields of type Void are not allowed" f.cf_pos | _ -> ();
616628 in
617629 List.iter check c.cl_ordered_fields;
618630 List.iter check c.cl_ordered_statics;
622634 (* Interfaces have no 'super', but can extend many other interfaces.
623635 This makes the first extended (implemented) interface the super for efficiency reasons (you can get one for 'free')
624636 and leaves the remaining ones as 'implemented' *)
625 let promote_first_interface_to_super ctx t = match t with
637 let promote_first_interface_to_super t = match t with
626638 | TClassDecl c when (has_class_flag c CInterface) ->
627639 begin match c.cl_implements with
628640 | ({ cl_path = ["cpp";"rtti"],_ },_ ) :: _ -> ()
634646 | _ ->
635647 ()
636648
637 let commit_features ctx t =
649 let commit_features com t =
638650 let m = (t_infos t).mt_module in
639651 Hashtbl.iter (fun k v ->
640 Common.add_feature ctx.com k;
652 Common.add_feature com k;
641653 ) m.m_extra.m_features
642654
643655 let check_reserved_type_paths ctx t =
644656 let check path pos =
645 if List.mem path ctx.com.config.pf_reserved_type_paths then
646 ctx.com.warning ("Type path " ^ (s_type_path path) ^ " is reserved on this target") pos
657 if List.mem path ctx.com.config.pf_reserved_type_paths then begin
658 warning ctx WReservedTypePath ("Type path " ^ (s_type_path path) ^ " is reserved on this target") pos
659 end
647660 in
648661 match t with
649662 | TClassDecl c when not (has_class_flag c CExtern) -> check c.cl_path c.cl_pos
652665
653666 (* PASS 3 end *)
654667
655 let pp_counter = ref 1
656
657 let is_cached t =
668 let is_cached com t =
658669 let m = (t_infos t).mt_module.m_extra in
659 if m.m_processed = 0 then m.m_processed <- !pp_counter;
660 m.m_processed <> !pp_counter
670 m.m_processed <> 0 && m.m_processed < com.compilation_step
661671
662672 let apply_filters_once ctx filters t =
663 if not (is_cached t) then run_expression_filters None ctx filters t
664
665 let next_compilation() =
666 incr pp_counter
673 if not (is_cached ctx.com t) then run_expression_filters None ctx filters t
667674
668675 let iter_expressions fl mt =
669676 match mt with
705712 loop e
706713 end
707714
715 let destruction tctx detail_times main locals =
716 let com = tctx.com in
717 let t = filter_timer detail_times ["type 2"] in
718 (* PASS 2: type filters pre-DCE *)
719 List.iter (fun t ->
720 remove_generic_base t;
721 remove_extern_fields com t;
722 (* check @:remove metadata before DCE so it is ignored there (issue #2923) *)
723 check_remove_metadata t;
724 ) com.types;
725 t();
726 com.stage <- CDceStart;
727 let t = filter_timer detail_times ["dce"] in
728 (* DCE *)
729 let dce_mode = try Common.defined_value com Define.Dce with _ -> "no" in
730 let dce_mode = match dce_mode with
731 | "full" -> if Common.defined com Define.Interp then Dce.DceNo else DceFull
732 | "std" -> DceStd
733 | "no" -> DceNo
734 | _ -> failwith ("Unknown DCE mode " ^ dce_mode)
735 in
736 Dce.run com main dce_mode;
737 t();
738 com.stage <- CDceDone;
739 (* PASS 3: type filters post-DCE *)
740 List.iter
741 (run_expression_filters
742 ~ignore_processed_status:true
743 (timer_label detail_times [])
744 tctx
745 (* This has to run after DCE, or otherwise its condition always holds. *)
746 ["insert_save_stacks",Exceptions.insert_save_stacks tctx]
747 )
748 com.types;
749 let type_filters = [
750 Exceptions.patch_constructors tctx; (* TODO: I don't believe this should load_instance anything at this point... *)
751 check_private_path tctx;
752 apply_native_paths;
753 add_rtti com;
754 (match com.platform with | Java | Cs -> (fun _ -> ()) | _ -> (fun mt -> add_field_inits tctx.curclass.cl_path locals com mt));
755 (match com.platform with Hl -> (fun _ -> ()) | _ -> add_meta_field com);
756 check_void_field;
757 (match com.platform with | Cpp -> promote_first_interface_to_super | _ -> (fun _ -> ()));
758 commit_features com;
759 (if com.config.pf_reserved_type_paths <> [] then check_reserved_type_paths tctx else (fun _ -> ()));
760 ] in
761 let type_filters = match com.platform with
762 | Cs -> type_filters @ [ fun t -> InterfaceProps.run t ]
763 | _ -> type_filters
764 in
765 let t = filter_timer detail_times ["type 3"] in
766 List.iter (fun t ->
767 begin match t with
768 | TClassDecl c ->
769 tctx.curclass <- c
770 | _ ->
771 ()
772 end;
773 List.iter (fun f -> f t) type_filters
774 ) com.types;
775 t();
776 com.callbacks#run com.callbacks#get_after_filters;
777 com.stage <- CFilteringDone
778
779 let update_cache_dependencies com t =
780 let visited_anons = ref [] in
781 let rec check_t m t = match t with
782 | TInst(c,tl) ->
783 add_dependency m c.cl_module;
784 List.iter (check_t m) tl;
785 | TEnum(en,tl) ->
786 add_dependency m en.e_module;
787 List.iter (check_t m) tl;
788 | TType(t,tl) ->
789 add_dependency m t.t_module;
790 List.iter (check_t m) tl;
791 | TAbstract(a,tl) ->
792 add_dependency m a.a_module;
793 List.iter (check_t m) tl;
794 | TFun(targs,tret) ->
795 List.iter (fun (_,_,t) -> check_t m t) targs;
796 check_t m tret;
797 | TAnon an ->
798 if not (List.memq an !visited_anons) then begin
799 visited_anons := an :: !visited_anons;
800 PMap.iter (fun _ cf -> check_t m cf.cf_type) an.a_fields
801 end
802 | TMono r ->
803 begin match r.tm_type with
804 | Some t ->
805 check_t m t
806 | _ ->
807 (* Bind any still open monomorph that's part of a signature to Dynamic now (issue #10653) *)
808 Monomorph.do_bind r t_dynamic;
809 end
810 | TLazy f ->
811 check_t m (lazy_type f)
812 | TDynamic None ->
813 ()
814 | TDynamic (Some t) ->
815 check_t m t
816 in
817 let rec check_field m cf =
818 check_t m cf.cf_type;
819 List.iter (check_field m) cf.cf_overloads
820 in
821 match t with
822 | TClassDecl c ->
823 List.iter (check_field c.cl_module) c.cl_ordered_statics;
824 List.iter (check_field c.cl_module) c.cl_ordered_fields;
825 (match c.cl_constructor with None -> () | Some cf -> check_field c.cl_module cf);
826 | _ ->
827 ()
828
829 (* Saves a class state so it can be restored later, e.g. after DCE or native path rewrite *)
830 let save_class_state ctx t =
831 (* Update m_processed here. This means that nothing should add a dependency afterwards because
832 then the module is immediately considered uncached again *)
833 (t_infos t).mt_module.m_extra.m_processed <- ctx.com.compilation_step;
834 match t with
835 | TClassDecl c ->
836 let vars = ref [] in
837 let rec save_vars e =
838 let add v = vars := (v, v.v_type) :: !vars in
839 match e.eexpr with
840 | TFunction fn ->
841 List.iter (fun (v, _) -> add v) fn.tf_args;
842 save_vars fn.tf_expr
843 | TVar (v, e) ->
844 add v;
845 Option.may save_vars e
846 | _ ->
847 iter save_vars e
848 in
849 let mk_field_restore f =
850 Option.may save_vars f.cf_expr;
851 let rec mk_overload_restore f =
852 add_class_field_flag f CfPostProcessed;
853 f.cf_name,f.cf_kind,f.cf_expr,f.cf_type,f.cf_meta,f.cf_params
854 in
855 ( f,mk_overload_restore f, List.map (fun f -> f,mk_overload_restore f) f.cf_overloads )
856 in
857 let restore_field (f,res,overloads) =
858 let restore_field (f,(name,kind,expr,t,meta,params)) =
859 f.cf_name <- name; f.cf_kind <- kind; f.cf_expr <- expr; f.cf_type <- t; f.cf_meta <- meta; f.cf_params <- params;
860 f
861 in
862 let f = restore_field (f,res) in
863 f.cf_overloads <- List.map restore_field overloads;
864 f
865 in
866 let mk_pmap lst =
867 List.fold_left (fun pmap f -> PMap.add f.cf_name f pmap) PMap.empty lst
868 in
869
870 let meta = c.cl_meta and path = c.cl_path and ext = (has_class_flag c CExtern) in
871 let sup = c.cl_super and impl = c.cl_implements in
872 let csr = Option.map (mk_field_restore) c.cl_constructor in
873 let ofr = List.map (mk_field_restore) c.cl_ordered_fields in
874 let osr = List.map (mk_field_restore) c.cl_ordered_statics in
875 let init = c.cl_init in
876 Option.may save_vars init;
877 c.cl_restore <- (fun() ->
878 c.cl_super <- sup;
879 c.cl_implements <- impl;
880 c.cl_meta <- meta;
881 if ext then add_class_flag c CExtern else remove_class_flag c CExtern;
882 c.cl_path <- path;
883 c.cl_init <- init;
884 c.cl_ordered_fields <- List.map restore_field ofr;
885 c.cl_ordered_statics <- List.map restore_field osr;
886 c.cl_fields <- mk_pmap c.cl_ordered_fields;
887 c.cl_statics <- mk_pmap c.cl_ordered_statics;
888 c.cl_constructor <- Option.map restore_field csr;
889 c.cl_descendants <- [];
890 List.iter (fun (v, t) -> v.v_type <- t) !vars;
891 )
892 | TEnumDecl en ->
893 let path = en.e_path in
894 en.e_restore <- (fun () ->
895 let rec loop acc = function
896 | [] ->
897 en.e_path <- path;
898 | (Meta.RealPath,[Ast.EConst (Ast.String(path,_)),_],_) :: l ->
899 en.e_path <- Ast.parse_path path;
900 en.e_meta <- (List.rev acc) @ l;
901 | x :: l -> loop (x::acc) l
902 in
903 loop [] en.e_meta
904 )
905 | TTypeDecl td ->
906 let path = td.t_path in
907 td.t_restore <- (fun () ->
908 td.t_path <- path
909 );
910 | TAbstractDecl a ->
911 let path = a.a_path in
912 a.a_restore <- (fun () ->
913 a.a_path <- path;
914 a.a_meta <- List.filter (fun (m,_,_) -> m <> Meta.ValueUsed) a.a_meta
915 )
916
708917 let run com tctx main =
709918 let detail_times = Common.defined com DefineList.FilterTimes in
710919 let new_types = List.filter (fun t ->
711 let cached = is_cached t in
920 let cached = is_cached com t in
712921 begin match t with
713922 | TClassDecl cls ->
714923 List.iter (fun (iface,_) -> add_descendant iface cls) cls.cl_implements;
719928 (* Save cf_expr_unoptimized early: We want to inline with the original expression
720929 on the next compilation. *)
721930 if not cached then begin
722 let field cf = match cf.cf_expr with
723 | Some {eexpr = TFunction tf} -> cf.cf_expr_unoptimized <- Some tf
724 | _ -> ()
931 let field cf =
932 cf.cf_expr_unoptimized <- cf.cf_expr
725933 in
726934 List.iter field cls.cl_ordered_fields;
727935 List.iter field cls.cl_ordered_statics;
731939 end;
732940 not cached
733941 ) com.types in
942 (* IMPORTANT:
943 There may be types in new_types which have already been post-processed, but then had their m_processed flag unset
944 because they received an additional dependency. This could happen in cases such as @:generic methods in #10635.
945 It is important that all filters from here up to save_class_state only process fields which do not have the
946 CfPostProcessed flag set.
947
948 This is mostly covered by run_expression_filters already, but any new additions which don't utilize that have to
949 be aware of this.
950 *)
734951 NullSafety.run com new_types;
735952 (* PASS 1: general expression filters *)
736953 let filters = [
740957 ] in
741958 List.iter (run_expression_filters (timer_label detail_times ["expr 0"]) tctx filters) new_types;
742959 let filters = [
960 "local_statics",LocalStatic.run tctx;
743961 "fix_return_dynamic_from_void_function",fix_return_dynamic_from_void_function tctx true;
744 "check_local_vars_init",check_local_vars_init tctx.com;
962 "check_local_vars_init",check_local_vars_init tctx;
745963 "check_abstract_as_value",check_abstract_as_value;
746964 "Tre",if defined com Define.AnalyzerOptimize then Tre.run tctx else (fun e -> e);
747965 "reduce_expression",Optimizer.reduce_expression tctx;
779997 List.iter (fun f -> List.iter f new_types) filters;
780998 t();
781999 com.stage <- CAnalyzerStart;
782 if com.platform <> Cross then Analyzer.Run.run_on_types tctx new_types;
1000 if com.platform <> Cross then Analyzer.Run.run_on_types com new_types;
7831001 com.stage <- CAnalyzerDone;
7841002 let locals = RenameVars.init com in
7851003 let filters = [
7871005 "add_final_return",if com.config.pf_add_final_return then add_final_return else (fun e -> e);
7881006 "RenameVars",(match com.platform with
7891007 | Eval -> (fun e -> e)
790 | _ -> RenameVars.run tctx locals);
1008 | _ -> (fun e -> RenameVars.run tctx.curclass.cl_path locals e));
7911009 "mark_switch_break_loops",mark_switch_break_loops;
7921010 ] in
7931011 List.iter (run_expression_filters (timer_label detail_times ["expr 2"]) tctx filters) new_types;
794 next_compilation();
7951012 let t = filter_timer detail_times ["callbacks"] in
796 List.iter (fun f -> f()) (List.rev com.callbacks#get_before_save); (* macros onGenerate etc. *)
1013 com.callbacks#run com.callbacks#get_before_save; (* macros onGenerate etc. *)
7971014 t();
7981015 com.stage <- CSaveStart;
7991016 let t = filter_timer detail_times ["save state"] in
800 List.iter (save_class_state tctx) new_types;
1017 List.iter (fun mt ->
1018 update_cache_dependencies com mt;
1019 save_class_state tctx mt
1020 ) new_types;
8011021 t();
8021022 com.stage <- CSaveDone;
8031023 let t = filter_timer detail_times ["callbacks"] in
804 List.iter (fun f -> f()) (List.rev com.callbacks#get_after_save); (* macros onGenerate etc. *)
1024 com.callbacks#run com.callbacks#get_after_save; (* macros onGenerate etc. *)
8051025 t();
806 let t = filter_timer detail_times ["type 2"] in
807 (* PASS 2: type filters pre-DCE *)
808 List.iter (fun t ->
809 remove_generic_base tctx t;
810 remove_extern_fields tctx t;
811 Codegen.update_cache_dependencies t;
812 (* check @:remove metadata before DCE so it is ignored there (issue #2923) *)
813 check_remove_metadata tctx t;
814 ) com.types;
815 t();
816 com.stage <- CDceStart;
817 let t = filter_timer detail_times ["dce"] in
818 (* DCE *)
819 let dce_mode = try Common.defined_value com Define.Dce with _ -> "no" in
820 let dce_mode = match dce_mode with
821 | "full" -> if Common.defined com Define.Interp then Dce.DceNo else DceFull
822 | "std" -> DceStd
823 | "no" -> DceNo
824 | _ -> failwith ("Unknown DCE mode " ^ dce_mode)
825 in
826 Dce.run com main dce_mode;
827 t();
828 com.stage <- CDceDone;
829 (* PASS 3: type filters post-DCE *)
830 List.iter
831 (run_expression_filters
832 (timer_label detail_times [])
833 tctx
834 ["insert_save_stacks",Exceptions.insert_save_stacks tctx]
835 )
836 new_types;
837 let type_filters = [
838 Exceptions.patch_constructors;
839 check_private_path;
840 apply_native_paths;
841 add_rtti;
842 (match com.platform with | Java | Cs -> (fun _ _ -> ()) | _ -> add_field_inits locals);
843 (match com.platform with Hl -> (fun _ _ -> ()) | _ -> add_meta_field);
844 check_void_field;
845 (match com.platform with | Cpp -> promote_first_interface_to_super | _ -> (fun _ _ -> ()) );
846 commit_features;
847 (if com.config.pf_reserved_type_paths <> [] then check_reserved_type_paths else (fun _ _ -> ()));
848 ] in
849 let type_filters = match com.platform with
850 | Cs -> type_filters @ [ fun _ t -> InterfaceProps.run t ]
851 | _ -> type_filters
852 in
853 let t = filter_timer detail_times ["type 3"] in
854 List.iter (fun t -> List.iter (fun f -> f tctx t) type_filters) com.types;
855 t();
856 List.iter (fun f -> f()) (List.rev com.callbacks#get_after_filters);
857 com.stage <- CFilteringDone
1026 destruction tctx detail_times main locals
2525 (match c.cl_super with
2626 | Some (c,_) -> is_removable_class c
2727 | _ -> false) ||
28 List.exists (fun (_,t) -> match follow t with
28 List.exists (fun tp -> match follow tp.ttp_type with
2929 | TInst(c,_) ->
3030 has_ctor_constraint c || Meta.has Meta.Const c.cl_meta
3131 | _ ->
4747 in
4848 List.exists (fun d -> loop_inheritance d) cls.cl_descendants
4949
50 let run_expression_filters time_details ctx filters t =
50 let run_expression_filters ?(ignore_processed_status=false) time_details ctx filters t =
5151 let run e =
5252 List.fold_left
5353 (fun e (filter_name,f) ->
6565 | TClassDecl c when is_removable_class c -> ()
6666 | TClassDecl c ->
6767 ctx.curclass <- c;
68 ctx.m <- TypeloadModule.make_curmod ctx c.cl_module;
6869 let rec process_field f =
69 ctx.curfield <- f;
70 (match f.cf_expr with
71 | Some e when not (is_removable_field ctx f) ->
72 f.cf_expr <- Some (rec_stack_loop AbstractCast.cast_stack f run e);
73 | _ -> ());
70 if ignore_processed_status || not (has_class_field_flag f CfPostProcessed) then begin
71 ctx.curfield <- f;
72 (match f.cf_expr with
73 | Some e when not (is_removable_field ctx.com f) ->
74 f.cf_expr <- Some (rec_stack_loop AbstractCast.cast_stack f run e);
75 | _ -> ());
76 end;
7477 List.iter process_field f.cf_overloads
7578 in
7679 List.iter process_field c.cl_ordered_fields;
279279 Rename `v` if needed
280280 *)
281281 let maybe_rename_var rc reserved (v,overlaps) =
282 let commit name =
283 v.v_meta <- (Meta.RealPath,[EConst (String(v.v_name,SDoubleQuotes)),null_pos],null_pos) :: v.v_meta;
284 v.v_name <- name
285 in
282286 (* chop escape char for all local variables generated *)
283287 if is_gen_local v then begin
284288 let name = String.sub v.v_name 1 (String.length v.v_name - 1) in
285 v.v_name <- "_g" ^ (Str.replace_first trailing_numbers "" name)
289 commit ("_g" ^ (Str.replace_first trailing_numbers "" name))
286290 end;
287291 let name = ref v.v_name in
288292 let count = ref 0 in
294298 incr count;
295299 name := v.v_name ^ (string_of_int !count);
296300 done;
297 v.v_name <- !name;
301 commit !name;
298302 if rc.rc_no_shadowing || (has_var_flag v VCaptured && rc.rc_hoisting) then reserve reserved v.v_name
299303
300304 (**
310314 (**
311315 Rename local variables in `e` expression if needed.
312316 *)
313 let run ctx ri e =
317 let run cl_path ri e =
314318 (try
315319 let rc = {
316320 rc_scope = ri.ri_scope;
321325 rc_reserved = ri.ri_reserved;
322326 } in
323327 if ri.ri_reserve_current_top_level_symbol then begin
324 match ctx.curclass.cl_path with
328 match cl_path with
325329 | s :: _,_ | [],s -> reserve_ctx rc s
326330 end;
327331 let scope = create_scope None in
2626 away by default.
2727 *)
2828 let follow = Abstract.follow_with_abstracts
29
30 let replace_float_separators s = Texpr.replace_separators s ""
2931
3032 (*
3133 Code for generating source files.
415417 | x -> x
416418 ;;
417419
420 let make_path_absolute path pos =
421 try
422 if (String.sub path 0 2) = "./" then begin
423 let base = if (Filename.is_relative pos.pfile) then
424 Filename.concat (Sys.getcwd()) pos.pfile
425 else
426 pos.pfile
427 in
428 Path.normalize_path (Filename.concat (Filename.dirname base) (String.sub path 2 ((String.length path) -2)))
429 end else
430 path
431 with Invalid_argument _ -> path
432 ;;
433
418434 let get_meta_string meta key =
419435 let rec loop = function
420436 | [] -> ""
424440 loop meta
425441 ;;
426442
427
428
429443 let get_meta_string_path meta key =
430444 let rec loop = function
431445 | [] -> ""
432446 | (k,[Ast.EConst (Ast.String(name,_)),_], pos) :: _ when k=key->
433 (try
434 if (String.sub name 0 2) = "./" then begin
435 let base = if (Filename.is_relative pos.pfile) then
436 Filename.concat (Sys.getcwd()) pos.pfile
437 else
438 pos.pfile
439 in
440 Path.normalize_path (Filename.concat (Filename.dirname base) (String.sub name 2 ((String.length name) -2) ))
441 end else
442 name
443 with Invalid_argument _ -> name)
447 make_path_absolute name pos
444448 | _ :: l -> loop l
445449 in
446450 loop meta
447451 ;;
448452
453 let get_all_meta_string_path meta_list key =
454 let extract_path pos expr =
455 match expr with
456 | (Ast.EConst (Ast.String(name, _)), _) -> make_path_absolute name pos
457 | _ -> "" in
458 let extract_meta meta =
459 match meta with
460 | (k, exprs, pos) when k = key -> Some (extract_path pos (List.hd exprs))
461 | _ -> None in
462 ExtList.List.filter_map extract_meta meta_list
463 ;;
449464
450465 let get_meta_string_full_filename meta key =
451466 let rec loop = function
694709 | _ -> false );
695710 ;;
696711
712 let is_extern_enum enum_def =
713 (enum_def.e_extern) || (has_meta_key enum_def.e_meta Meta.Extern)
714 ;;
715
697716 let is_native_class class_def =
698717 ((is_extern_class class_def) || (is_native_gen_class class_def)) && (not (is_internal_class class_def.cl_path))
718 ;;
719
720 let cpp_enum_path_of enum =
721 (*
722 let rename = get_meta_string enum.e_meta Meta.Native in
723 if rename <> "" then
724 rename
725 else
726 *)
727 let globalNamespace = if (get_meta_string enum.e_meta Meta.Native)<>"" then "" else "::" in
728 globalNamespace ^ (join_class_path_remap enum.e_path "::")
699729 ;;
700730
701731 (* Get a string to represent a type.
752782 (join_class_path_remap klass.cl_path "::") ^ " *"
753783 (* Normal class *)
754784 | _ when is_native_class klass ->
755 join_class_path_remap klass.cl_path "::"
785 let class_params = match params with
786 | [] -> ""
787 | _ -> "<" ^ (String.concat "," (List.map type_string params)) ^ ">" in
788 (join_class_path_remap klass.cl_path "::") ^ class_params
756789 | _ ->
757790 let globalNamespace = if (get_meta_string klass.cl_meta Meta.Native)<>"" then "" else "::" in
758791 globalNamespace ^ (join_class_path_remap klass.cl_path "::") ^ suffix
775808 | TAbstract ({ a_path = [],"Bool" },_) -> "Dynamic" ^ suffix
776809 | t when type_has_meta_key t Meta.NotNull -> "Dynamic" ^ suffix
777810 | _ -> type_string_suff suffix t remap)
778 | TEnum (enum,params) -> "::" ^ (join_class_path_remap enum.e_path "::") ^ suffix
811 | TEnum (enum,_) -> (cpp_enum_path_of enum) ^ suffix
779812 | TInst (klass,params) -> (class_string klass suffix params remap)
780813 | TType (type_def,params) ->
781814 (match type_def.t_path with
803836 | _ -> die "" __LOC__)
804837 | ["cpp"] , "Function" ->
805838 "::cpp::Function< " ^ (cpp_function_signature_params params ) ^ " >"
806 | _ -> type_string_suff suffix (apply_params type_def.t_params params type_def.t_type) remap
839 | _ -> type_string_suff suffix (apply_typedef type_def params) remap
807840 )
808841 | TFun (args,haxe_type) -> "Dynamic" ^ suffix
809842 | TAnon a -> "Dynamic"
13651398 | TCppNativePointer of tclass
13661399 | TCppVariant
13671400 | TCppCode of tcpp
1368 | TCppInst of tclass
1401 | TCppInst of tclass * tcpp list
13691402 | TCppInterface of tclass
13701403 | TCppProtocol of tclass
13711404 | TCppClass
16331666 name
16341667 else
16351668 "::hx::Native< " ^ name ^ "* >";
1636 | TCppInst klass ->
1637 (cpp_class_path_of klass) ^ (if is_native_class klass then "" else suffix)
1669 | TCppInst (klass, p) ->
1670 (cpp_class_path_of klass p) ^ (if is_native_class klass then "" else suffix)
16381671 | TCppInterface klass when suffix="_obj" ->
1639 (cpp_class_path_of klass) ^ suffix
1672 (cpp_class_path_of klass []) ^ suffix
16401673 | TCppInterface _ -> "::Dynamic"
16411674 | TCppClass -> "::hx::Class" ^ suffix;
16421675 | TCppGlobal -> "::Dynamic";
16621695 and tcpp_to_string tcpp =
16631696 tcpp_to_string_suffix "" tcpp
16641697
1665 and cpp_class_path_of klass =
1666 let globalNamespace = if (get_meta_string klass.cl_meta Meta.Native)<>"" then " " else " ::" in
1667 globalNamespace ^ (join_class_path_remap klass.cl_path "::")
1698 and cpp_class_path_of klass params =
1699 match (get_meta_string klass.cl_meta Meta.Native)<>"" with
1700 | true ->
1701 let typeParams = match params with
1702 | [] -> ""
1703 | _ -> "<" ^ String.concat "," (List.map tcpp_to_string params) ^ ">" in
1704 (" " ^ (join_class_path_remap klass.cl_path "::") ^ typeParams)
1705 | false -> " ::" ^ (join_class_path_remap klass.cl_path "::")
16681706 ;;
16691707
16701708
16711709 let cpp_const_type cval = match cval with
16721710 | TInt i -> CppInt(i) , TCppScalar("int")
16731711 | TBool b -> CppBool(b) , TCppScalar("bool")
1674 | TFloat f -> CppFloat(f) , TCppScalar("Float")
1712 | TFloat f -> CppFloat(replace_float_separators f) , TCppScalar("Float")
16751713 | TString s -> CppString(s) , TCppString
16761714 | _ -> (* TNull, TThis & TSuper should already be handled *)
16771715 CppNull, TCppNull
16871725
16881726 let is_cpp_array_implementer cppType =
16891727 match cppType with
1690 | TCppInst (klass)
1728 | TCppInst (klass, _)
16911729 | TCppInterface (klass) ->
16921730 (match klass.cl_array_access with
16931731 | Some _ -> true
17061744 let rec const_float_of expr =
17071745 match expr.eexpr with
17081746 | TConst TInt x -> Printf.sprintf "%ld" x
1709 | TConst TFloat x -> x
1747 | TConst TFloat x -> (replace_float_separators x)
17101748 | TConst TBool x -> if x then "1" else "0"
17111749 | TParenthesis e -> const_float_of e
17121750 | _ -> raise Not_found
17251763 match t with
17261764 | TCppFunction _ -> true
17271765 | TCppStruct _-> false
1728 | TCppInst (class_def) -> (has_meta_key class_def.cl_meta Meta.StructAccess)
1766 | TCppInst (class_def, _) -> (has_meta_key class_def.cl_meta Meta.StructAccess)
17291767 | TCppReference (r) -> cpp_is_struct_access r
17301768 | _ -> false
17311769 ;;
17321770
1771 let rec cpp_is_native_array_access t =
1772 match t with
1773 | TCppStruct s -> cpp_is_native_array_access s
1774 | TCppReference s -> cpp_is_native_array_access s
1775 | TCppInst ({ cl_array_access = Some _ } as klass, _) when is_extern_class klass && has_meta_key klass.cl_meta Meta.NativeArrayAccess -> true
1776 | _ -> false
1777 ;;
17331778
17341779 let cpp_is_dynamic_type = function
17351780 | TCppDynamic | TCppObject | TCppVariant | TCppWrapped _ | TCppGlobal | TCppNull
17721817
17731818 | TType (type_def,params) ->
17741819 cpp_type_from_path stack ctx type_def.t_path params (fun () ->
1775 cpp_type_of stack ctx (apply_params type_def.t_params params type_def.t_type) )
1820 cpp_type_of stack ctx (apply_typedef type_def params) )
17761821
17771822 | TFun _ -> TCppObject
17781823 | TAnon _ -> TCppObject
19291974 else if (has_class_flag klass CInterface) then
19301975 TCppInterface(klass)
19311976 else if (has_class_flag klass CExtern) && (not (is_internal_class klass.cl_path) ) then
1932 TCppInst(klass)
1977 let tcpp_params = List.map (cpp_type_of stack ctx) params in
1978 TCppInst(klass, tcpp_params)
19331979 else
1934 TCppInst(klass)
1980 let tcpp_params = List.map (cpp_type_of stack ctx) params in
1981 TCppInst(klass, tcpp_params)
19351982 )
19361983
19371984 let cpp_type_of ctx = cpp_type_of [] ctx
19612008 let is_cpp_objc_type cpptype = match cpptype with
19622009 | TCppObjC(_) -> true;
19632010 | _ -> false
1964 ;;
1965
1966
1967 let cpp_enum_path_of enum =
1968 (*
1969 let rename = get_meta_string enum.e_meta Meta.Native in
1970 if rename <> "" then
1971 rename
1972 else
1973 *)
1974 let globalNamespace = if (get_meta_string enum.e_meta Meta.Native)<>"" then "" else "::" in
1975 globalNamespace ^ (join_class_path_remap enum.e_path "::")
19762011 ;;
19772012
19782013
20542089 | TCppScalar "Int"
20552090 | TCppScalar "bool"
20562091 | TCppScalar "Float" -> t
2092 | TCppScalar "::cpp::Int64" -> TCppScalar("Int64")
20572093 | TCppScalar "double"
20582094 | TCppScalar "float" -> TCppScalar("Float")
20592095 | TCppScalar _ -> TCppScalar("int")
20702106 | _ -> cpp_variant_type_of t;
20712107 ;;
20722108
2073 let cpp_base_type_of t =
2109 let enum_getter_type t =
20742110 match cpp_variant_type_of t with
2075 | TCppDynamic -> "Object"
20762111 | TCppString -> "String"
2077 | TCppVoidStar -> "Pointer"
20782112 | TCppScalar "int" -> "Int"
20792113 | TCppScalar "bool" -> "Bool"
20802114 | TCppScalar x -> x
22052239 (ctx.ctx_debug_level<=1) || (match var.v_kind with VUser _ -> false | _ -> true) ||
22062240 match cpp_type_of ctx var.v_type with
22072241 | TCppStar _ | TCppReference _ -> true
2208 | TCppInst (class_def) when (has_meta_key class_def.cl_meta Meta.StructAccess) -> true
2209 | TCppInst (class_def) when (has_meta_key class_def.cl_meta Meta.Unreflective) -> true
2242 | TCppInst (class_def, _) when (has_meta_key class_def.cl_meta Meta.StructAccess) -> true
2243 | TCppInst (class_def, _) when (has_meta_key class_def.cl_meta Meta.Unreflective) -> true
22102244 | _->
22112245 let name = cpp_var_debug_name_of var in
22122246 (String.length name) >4 && (String.sub name 0 4) = "_hx_"
22242258 let only_stack_access ctx haxe_type =
22252259 let tcpp = cpp_type_of ctx haxe_type in
22262260 match tcpp with
2227 | TCppInst(klass) -> has_meta_key klass.cl_meta Meta.StackOnly
2261 | TCppInst(klass, _) -> has_meta_key klass.cl_meta Meta.StackOnly
22282262 | _ -> false;
22292263 ;;
22302264
22462280 let is_map_get_call obj member =
22472281 member.cf_name="get" &&
22482282 (match obj.cpptype with
2249 | TCppInst({cl_path=(["haxe";"ds"],"IntMap")}) -> true
2250 | TCppInst({cl_path=(["haxe";"ds"],"StringMap")}) -> true
2251 | TCppInst({cl_path=(["haxe";"ds"],"ObjectMap")}) -> true
2283 | TCppInst({cl_path=(["cpp"],"Int64Map")}, _) -> true
2284 | TCppInst({cl_path=(["haxe";"ds"],"IntMap")}, _) -> true
2285 | TCppInst({cl_path=(["haxe";"ds"],"StringMap")}, _) -> true
2286 | TCppInst({cl_path=(["haxe";"ds"],"ObjectMap")}, _) -> true
22522287 | _ -> false
22532288 )
22542289 ;;
22562291 let is_map_set_call obj member =
22572292 member.cf_name="set" &&
22582293 (match obj.cpptype with
2259 | TCppInst({cl_path=(["haxe";"ds"],"IntMap")}) -> true
2260 | TCppInst({cl_path=(["haxe";"ds"],"StringMap")}) -> true
2261 | TCppInst({cl_path=(["haxe";"ds"],"ObjectMap")}) -> true
2294 | TCppInst({cl_path=(["cpp"],"Int64Map")}, _) -> true
2295 | TCppInst({cl_path=(["haxe";"ds"],"IntMap")}, _) -> true
2296 | TCppInst({cl_path=(["haxe";"ds"],"StringMap")}, _) -> true
2297 | TCppInst({cl_path=(["haxe";"ds"],"ObjectMap")}, _) -> true
22622298 | _ -> false
22632299 )
22642300 ;;
22772313 | TCppReference(_) | TCppStar(_) | TCppStruct(_) -> false
22782314 | _ ->
22792315 (match inferredType with
2316 | TCppInst (cls, _) when is_extern_class cls -> false
2317 | TCppEnum e when is_extern_enum e -> false
22802318 | TCppInst _
22812319 | TCppClass
22822320 | TCppEnum _
23332371
23342372 let is_object_element ctx member_type =
23352373 match member_type with
2336 | TCppInst x
2374 | TCppInst (x, _)
23372375 | TCppInterface x
23382376 -> not (is_extern_class x)
23392377 | TCppDynamic
27402778 let fname, cppType = match return_type with
27412779 | TCppVoid | TCppScalar("bool") -> (if forCppia then "getBool" else "get_bool"), return_type
27422780 | TCppScalar("int") -> (if forCppia then "getInt" else "get_int"), return_type
2781 | TCppScalar("::cpp::Int64") -> (if forCppia then "getInt64" else "get_int64"), return_type
27432782 | TCppScalar("Float") -> (if forCppia then "getFloat" else "get_float"), return_type
27442783 | TCppString -> (if forCppia then "getString" else "get_string"), return_type
27452784 | _ -> "get", TCppDynamic
27592798 let fname = match retypedArgs with
27602799 | [_;{cpptype=TCppScalar("bool")}] -> "setBool"
27612800 | [_;{cpptype=TCppScalar("int")}] -> "setInt"
2801 | [_;{cpptype=TCppScalar("::cpp::Int64")}] -> "setInt64"
27622802 | [_;{cpptype=TCppScalar("Float")}] -> "setFloat"
27632803 | [_;{cpptype=TCppString}] -> "setString"
27642804 | _ -> "set"
27792819 *)
27802820
27812821 (* Other functions ... *)
2822 | CppFunction( FuncInstance(_, InstStruct, {cf_type=TFun(arg_types,_)}) as func, return_type) ->
2823 (* For struct access classes use the types of the arguments instead of the function argument types *)
2824 (* In the case of generic extern classes a TFun arg type could be `MyClass.T` instead of the real type *)
2825 let map_args func_arg passed_arg =
2826 let (name, opt, _) = func_arg in
2827 name, opt, passed_arg.etype in
2828 let real_types = List.map2 map_args arg_types args in
2829 let arg_types = List.map (fun (_,opt,t) -> cpp_tfun_arg_type_of ctx opt t) real_types in
2830 let retypedArgs = retype_function_args args arg_types in
2831 CppCall(func,retypedArgs), return_type
2832
27822833 | CppFunction( FuncInstance(_,_,{cf_type=TFun(arg_types,_)} ) as func, returnType )
27832834 | CppFunction( FuncStatic(_,_,{cf_type=TFun(arg_types,_)} ) as func, returnType )
27842835 | CppFunction( FuncThis({cf_type=TFun(arg_types,_)},_ ) as func, returnType ) ->
28402891 let arg_types, _ = cpp_function_type_of_args_ret ctx constructor_type in
28412892 let retypedArgs = retype_function_args args arg_types in
28422893 let created_type = cpp_type_of expr.etype in
2843 gc_stack := !gc_stack || (match created_type with | TCppInst(t) -> not (is_native_class t) | _ -> false );
2894 gc_stack := !gc_stack || (match created_type with | TCppInst(t, _) -> not (is_native_class t) | _ -> false );
28442895 CppCall( FuncNew(created_type), retypedArgs), created_type
28452896
28462897 | TFunction func ->
28822933 CppClosure(result), TCppDynamic
28832934
28842935 | TArray (e1,e2) ->
2885 let retypedObj = retype TCppDynamic e1 in
2886 let retypedIdx = retype (TCppScalar("int")) e2 in
2887 let arrayExpr, elemType = (match retypedObj.cpptype with
2888 | TCppScalarArray scalar ->
2889 CppArray( ArrayTyped(retypedObj,retypedIdx,scalar) ), scalar
2890 | TCppPointer (_,elem) ->
2891 CppArray( ArrayPointer(retypedObj, retypedIdx) ), elem
2892 | TCppRawPointer (_,elem) ->
2893 CppArray( ArrayRawPointer(retypedObj, retypedIdx) ), elem
2894 | TCppObjectArray TCppDynamic ->
2895 CppArray( ArrayObject(retypedObj,retypedIdx,TCppDynamic) ), TCppDynamic
2896 | TCppObjectArray elem ->
2897 CppArray( ArrayObject(retypedObj,retypedIdx,elem) ), elem
2898 | TCppInst({cl_array_access = Some _ } as klass) ->
2899 CppArray( ArrayImplements(klass, retypedObj,retypedIdx) ), cpp_type_of expr.etype
2900 | TCppDynamicArray ->
2901 CppArray( ArrayVirtual(retypedObj, retypedIdx) ), TCppDynamic
2902 | _ ->
2903 CppArray( ArrayDynamic(retypedObj, retypedIdx) ), TCppDynamic
2904 ) in
2936 let arrayExpr, elemType = match cpp_is_native_array_access (cpp_type_of e1.etype) with
2937 | true ->
2938 let retypedObj = retype TCppUnchanged e1 in
2939 let retypedIdx = retype (TCppScalar("int")) e2 in
2940 CppArray( ArrayRawPointer(retypedObj, retypedIdx) ), cpp_type_of expr.etype
2941 | false ->
2942 let retypedObj = retype TCppDynamic e1 in
2943 let retypedIdx = retype (TCppScalar("int")) e2 in
2944 (match retypedObj.cpptype with
2945 | TCppScalarArray scalar ->
2946 CppArray( ArrayTyped(retypedObj,retypedIdx,scalar) ), scalar
2947 | TCppPointer (_,elem) ->
2948 CppArray( ArrayPointer(retypedObj, retypedIdx) ), elem
2949 | TCppRawPointer (_,elem) ->
2950 CppArray( ArrayRawPointer(retypedObj, retypedIdx) ), elem
2951 | TCppObjectArray TCppDynamic ->
2952 CppArray( ArrayObject(retypedObj,retypedIdx,TCppDynamic) ), TCppDynamic
2953 | TCppObjectArray elem ->
2954 CppArray( ArrayObject(retypedObj,retypedIdx,elem) ), elem
2955 | TCppInst({cl_array_access = Some _ } as klass, _) ->
2956 CppArray( ArrayImplements(klass, retypedObj,retypedIdx) ), cpp_type_of expr.etype
2957 | TCppDynamicArray ->
2958 CppArray( ArrayVirtual(retypedObj, retypedIdx) ), TCppDynamic
2959 | _ ->
2960 CppArray( ArrayDynamic(retypedObj, retypedIdx) ), TCppDynamic)
2961 in
29052962 let returnType = cpp_type_of expr.etype in
29062963 if cpp_can_static_cast elemType returnType then
29072964 CppCastStatic(mk_cppexpr arrayExpr returnType, returnType), returnType
29092966 arrayExpr, elemType
29102967
29112968 | TTypeExpr module_type ->
2912 let path = t_path module_type in
2969 (* If we try and use the coreType / runtimeValue cpp.Int64 abstract with Class<T> then we get a class decl of the abstract *)
2970 (* as that abstract has functions in its declaration *)
2971 (* Intercept it and replace it with the path of the actual int64 type so the generated cpp is correct *)
2972 let path = match module_type with
2973 | TClassDecl ({ cl_path = ["cpp";"_Int64"],"Int64_Impl_" }) -> ["cpp"],"Int64"
2974 | _ -> t_path module_type in
29132975 CppClassOf(path, is_native_gen_module module_type), TCppClass
29142976
29152977 | TBinop (op,left,right) ->
31743236 end else if (cppExpr.cpptype=TCppVariant || cppExpr.cpptype=TCppDynamic || cppExpr.cpptype==TCppObject) then begin
31753237 match return_type with
31763238 | TCppUnchanged -> cppExpr
3177 | TCppInst(t) when (has_meta_key t.cl_meta Meta.StructAccess) ->
3178 let structType = TCppStruct( TCppInst(t) ) in
3239 | TCppInst(t, _) when (has_meta_key t.cl_meta Meta.StructAccess) ->
3240 let structType = TCppStruct( TCppInst(t, []) ) in
31793241 let structCast = mk_cppexpr (CppCast(cppExpr,structType)) structType in
3180 mk_cppexpr (CppCast(structCast,(TCppInst t))) (TCppInst t)
3242 mk_cppexpr (CppCast(structCast,(TCppInst (t, [])))) (TCppInst (t, []))
31813243
31823244 | TCppObjectArray _
31833245 | TCppScalarArray _
32653327 | TCppStar(t,const), TCppStruct _ ->
32663328 mk_cppexpr (CppDereference(cppExpr)) return_type
32673329
3268 | TCppInst(t), TCppStar _ when (is_native_class t) && (match cppExpr.cppexpr with
3330 | TCppInst(t, _), TCppStar _ when (is_native_class t) && (match cppExpr.cppexpr with
32693331 | CppCall(FuncNew(_), _) -> true
32703332 | _ -> false) ->
32713333 mk_cppexpr (CppNewNative(cppExpr)) return_type
32823344 | t, TCppProtocol protocol ->
32833345 mk_cppexpr (CppCastProtocol(cppExpr,protocol)) return_type
32843346
3285 | TCppInst(t), TCppDynamic when (has_meta_key t.cl_meta Meta.StructAccess) ->
3286 let structType = TCppStruct( TCppInst(t) ) in
3347 | TCppInst(t, _), TCppDynamic when (has_meta_key t.cl_meta Meta.StructAccess) ->
3348 let structType = TCppStruct( TCppInst(t, []) ) in
32873349 let structCast = mk_cppexpr (CppCast(cppExpr,structType)) structType in
32883350 mk_cppexpr (CppCast(structCast,TCppDynamic)) TCppDynamic
32893351
33323394 let default_value_string ctx value =
33333395 match value.eexpr with
33343396 | TConst (TInt i) -> Printf.sprintf "%ld" i
3335 | TConst (TFloat float_as_string) -> "((Float)" ^ float_as_string ^ ")"
3397 | TConst (TFloat float_as_string) -> "((Float)" ^ (replace_float_separators float_as_string) ^ ")"
33363398 | TConst (TString s) -> strq ctx s
33373399 | TConst (TBool b) -> (if b then "true" else "false")
33383400 | TConst TNull -> "null()"
35793641 expr.cpppos);
35803642 out " ]"
35813643
3582 | CppCall(FuncNew( TCppInst klass), args) when can_quick_alloc klass ->
3583 out ((cpp_class_path_of klass) ^ "_obj::__alloc( HX_CTX ");
3644 | CppCall(FuncNew( TCppInst (klass, p)), args) when can_quick_alloc klass ->
3645 out ((cpp_class_path_of klass p) ^ "_obj::__alloc( HX_CTX ");
35843646 List.iter (fun arg -> out ","; gen arg ) args;
35853647 out (")")
35863648
36343696 | FuncEnumConstruct(enum,field) ->
36353697 out ((string_of_path enum.e_path) ^ "::" ^ (cpp_enum_name_of field));
36363698
3637 | FuncSuperConstruct(TCppInst klass) when is_native_class klass ->
3699 | FuncSuperConstruct(TCppInst (klass, _)) when is_native_class klass ->
36383700 doCall := false;
36393701
36403702 | FuncSuperConstruct _ ->
36413703 out ((if not ctx.ctx_real_this_ptr then "__this->" else "") ^ "super::__construct")
36423704
3643 | FuncSuper(_,TCppInst(klass),field) when is_native_class klass ->
3644 out ((cpp_class_path_of klass) ^ "::" ^ (cpp_member_name_of field));
3705 | FuncSuper(_,TCppInst(klass, p),field) when is_native_class klass ->
3706 out ((cpp_class_path_of klass p) ^ "::" ^ (cpp_member_name_of field));
36453707
36463708 | FuncSuper(this,_,field) ->
36473709 out ( (if this==ThisReal then "this->" else "__->") ^ "super::" ^ (cpp_member_name_of field) )
36523714 | TCppDynamicArray -> "::cpp::VirtualArray_obj::__new"
36533715 | TCppObjectArray _ -> "::Array_obj< ::Dynamic>::__new"
36543716 | TCppScalarArray(value) -> "::Array_obj< " ^ (tcpp_to_string value) ^ " >::__new"
3655 | TCppObjC klass -> (cpp_class_path_of klass) ^ "_obj::__new"
3656 | TCppNativePointer klass -> "new " ^ (cpp_class_path_of klass);
3657 | TCppInst klass when is_native_class klass -> cpp_class_path_of klass
3658 | TCppInst klass -> (cpp_class_path_of klass) ^ "_obj::__new"
3717 | TCppObjC klass -> (cpp_class_path_of klass []) ^ "_obj::__new"
3718 | TCppNativePointer klass -> "new " ^ (cpp_class_path_of klass []);
3719 | TCppInst (klass, p) when is_native_class klass -> cpp_class_path_of klass p
3720 | TCppInst (klass, p) -> (cpp_class_path_of klass p) ^ "_obj::__new"
36593721 | TCppClass -> "::hx::Class_obj::__new";
36603722 | TCppFunction _ -> tcpp_to_string newType
36613723 | _ -> abort ("Unknown 'new' target " ^ (tcpp_to_string newType)) expr.cpppos
39193981
39203982 | CppEnumParameter(obj,field,index) ->
39213983 let valueType = cpp_type_of ctx (get_nth_type field index) in
3922 let baseType = cpp_base_type_of valueType in
3984 let baseType = enum_getter_type valueType in
39233985 gen obj;
39243986 if cpp_is_dynamic_type obj.cpptype then
39253987 out ".StaticCast< ::hx::EnumBase >()";
42174279 | OpInterval -> "..."
42184280 | OpArrow -> "->"
42194281 | OpIn -> " in "
4282 | OpNullCoal -> "??"
42204283 | OpAssign | OpAssignOp _ -> abort "Unprocessed OpAssign" pos
42214284
42224285 and gen_closure closure =
44564519
44574520 let needsWrapper t = match t with
44584521 | TCppStar _ -> true
4459 | TCppInst(t) -> has_meta_key t.cl_meta Meta.StructAccess
4522 | TCppInst(t, _) -> has_meta_key t.cl_meta Meta.StructAccess
44604523 | _ -> false
44614524 in
44624525 let orig_debug = ctx.ctx_debug_level in
45024565 match return_type with
45034566 | TCppStar _ ->
45044567 output "return (cpp::Pointer<const void *>) "
4505 | TCppInst(t) when has_meta_key t.cl_meta Meta.StructAccess ->
4568 | TCppInst(t, _) when has_meta_key t.cl_meta Meta.StructAccess ->
45064569 output ("return (cpp::Struct< " ^ (tcpp_to_string return_type) ^ " >) ");
45074570 | _ -> output "return ";
45084571 end;
45184581 (match arg with
45194582 | TCppStar (t,const) ->
45204583 output ("(cpp::" ^ (if const then "Const" else "") ^"Pointer<" ^ (tcpp_to_string t)^" >) ")
4521 | TCppInst(t) when has_meta_key t.cl_meta Meta.StructAccess ->
4584 | TCppInst(t, _) when has_meta_key t.cl_meta Meta.StructAccess ->
45224585 output ("(cpp::Struct< " ^ (tcpp_to_string arg) ^ " >) ");
45234586 | _ -> () );
45244587 output ("a" ^ (string_of_int i));
47124775 output (if return_type="Void" then "void" else return_type );
47134776 output (" " ^ remap_name ^ "(" );
47144777 output (ctx_arg_list ctx tl "" );
4715 output ") = 0;\n";
4778 output (") " ^ (if return_type="void" then "{}" else "{ return 0; }" ) ^ "\n");
47164779 if doDynamic then
47174780 output (" ::Dynamic " ^ remap_name ^ "_dyn();\n" );
47184781 | _ when has_decl ->
47654828 let find_referenced_types_flags ctx obj field_name super_deps constructor_deps header_only for_depends include_super_args =
47664829 let types = ref PMap.empty in
47674830 if for_depends then begin
4768 let include_file = get_meta_string_path (t_infos obj).mt_meta Meta.Depend in
4769 if (include_file<>"") then
4770 types := (PMap.add ( path_of_string include_file ) true !types);
4831 let include_files = get_all_meta_string_path (t_infos obj).mt_meta Meta.Depend in
4832 let include_adder = fun inc -> types := (PMap.add ( path_of_string inc ) true !types) in
4833 List.iter include_adder include_files;
47714834 end;
47724835 let rec add_type_flag isNative in_path =
47734836 if ( not (PMap.mem in_path !types)) then begin
47814844 in
47824845 let add_extern_type decl =
47834846 let tinfo = t_infos decl in
4784 let include_file = get_meta_string_path tinfo.mt_meta (if for_depends then Meta.Depend else Meta.Include) in
4785 if (include_file<>"") then
4786 add_type ( path_of_string include_file )
4847 let include_files = get_all_meta_string_path tinfo.mt_meta (if for_depends then Meta.Depend else Meta.Include) in
4848 if List.length include_files > 0 then
4849 List.iter (fun inc -> add_type(path_of_string inc)) include_files
47874850 else if (not for_depends) && (has_meta_key tinfo.mt_meta Meta.Include) then
47884851 add_type tinfo.mt_path
47894852 in
47914854 let add_extern_class klass =
47924855 add_extern_type (TClassDecl klass)
47934856 in
4857 let add_extern_enum enum =
4858 add_extern_type (TEnumDecl enum)
4859 in
47944860 let add_native_gen_class klass =
4795 let include_file = get_meta_string_path klass.cl_meta (if for_depends then Meta.Depend else Meta.Include) in
4796 if (include_file<>"") then
4797 add_type ( path_of_string include_file )
4861 let include_files = get_all_meta_string_path klass.cl_meta (if for_depends then Meta.Depend else Meta.Include) in
4862 if List.length include_files > 0 then
4863 List.iter (fun inc -> add_type ( path_of_string inc )) include_files
47984864 else if for_depends then
47994865 add_type klass.cl_path
48004866 else begin
48134879 visited := in_type :: !visited;
48144880 begin match follow in_type with
48154881 | TMono r -> (match r.tm_type with None -> () | Some t -> visit_type t)
4816 | TEnum (enum,params) -> add_type enum.e_path
4882 | TEnum (enum,_) ->
4883 (match is_extern_enum enum with
4884 | true -> add_extern_enum enum
4885 | false -> add_type enum.e_path)
48174886 (* If a class has a template parameter, then we treat it as dynamic - except
48184887 for the Array, Class, FastIterator or Pointer classes, for which we do a fully typed object *)
48194888 | TInst (klass,params) ->
48224891 | (["cpp"],"Pointer") | (["cpp"],"ConstPointer") | (["cpp"],"Function")
48234892 | (["cpp"],"RawPointer") | (["cpp"],"RawConstPointer") -> List.iter visit_type params
48244893 | _ when is_native_gen_class klass -> add_native_gen_class klass
4825 | _ when is_extern_class klass -> add_extern_class klass
4894 | _ when is_extern_class klass ->
4895 add_extern_class klass;
4896 List.iter visit_type params;
48264897 | _ -> (match klass.cl_kind with KTypeParameter _ -> () | _ -> add_type klass.cl_path);
48274898 )
48284899 | TAbstract (a,params) when is_scalar_abstract a ->
48424913 | TTypeExpr type_def -> ( match type_def with
48434914 | TClassDecl class_def when is_native_gen_class class_def -> add_native_gen_class class_def
48444915 | TClassDecl class_def when is_extern_class class_def -> add_extern_class class_def
4916 | TEnumDecl enum_def when is_extern_enum enum_def -> add_extern_enum enum_def
48454917 | _ -> add_type (t_path type_def)
48464918 )
48474919
58295901 in
58305902 (match find_super_args [function_def.tf_expr.eexpr] with
58315903 | Some args ->
5832 out ("\n:" ^ (cpp_class_path_of klass) ^ "(");
5904 out ("\n:" ^ (cpp_class_path_of klass []) ^ "(");
58335905 let sep = ref "" in
58345906 List.iter (fun arg ->
58355907 out !sep; sep := ",";
58835955 cpp_file#write_h "\n";
58845956
58855957 output_cpp ( get_class_code class_def Meta.CppFileCode );
5886 let inc = get_meta_string_path class_def.cl_meta Meta.CppInclude in
5887 if (inc<>"") then
5888 output_cpp ("#include \"" ^ inc ^ "\"\n");
5958 let includes = get_all_meta_string_path class_def.cl_meta Meta.CppInclude in
5959 let printer = fun inc -> output_cpp ("#include \"" ^ inc ^ "\"\n") in
5960 List.iter printer includes;
58895961
58905962 gen_open_namespace output_cpp class_path;
58915963 output_cpp "\n";
61376209
61386210 let toCommon t f value =
61396211 t ^ "( " ^ ( match cpp_type_of ctx f.cf_type with
6140 | TCppInst(t) as inst when (has_meta_key t.cl_meta Meta.StructAccess)
6212 | TCppInst(t, _) as inst when (has_meta_key t.cl_meta Meta.StructAccess)
61416213 -> "cpp::Struct< " ^ (tcpp_to_string inst) ^ " >( " ^ value ^ " )"
61426214 | TCppStar(t,_) -> "cpp::Pointer<void *>( " ^ value ^ " )"
61436215 | _ -> value
61856257
61866258 let castable f =
61876259 match cpp_type_of ctx f.cf_type with
6188 | TCppInst(t) as inst when (has_meta_key t.cl_meta Meta.StructAccess)
6260 | TCppInst(t, _) as inst when (has_meta_key t.cl_meta Meta.StructAccess)
61896261 -> "cpp::Struct< " ^ (tcpp_to_string inst) ^ " > "
61906262 | TCppStar(t,_) -> "cpp::Pointer< " ^ ( tcpp_to_string t ) ^ " >"
61916263 | _ -> ctx_type_string ctx f.cf_type
65026574 let class_name_text = join_class_path class_path "." in
65036575
65046576 (* Initialise static in boot function ... *)
6505 if (not (has_class_flag class_def CInterface) && not nativeGen) && not (has_class_flag class_def CAbstract) then begin
6577 if (not (has_class_flag class_def CInterface) && not nativeGen) then begin
65066578 (* Remap the specialised "extern" classes back to the generic names *)
65076579 output_cpp ("::hx::Class " ^ class_name ^ "::__mClass;\n\n");
65086580 if (scriptable) then begin
65266598 in
65276599
65286600 output_cpp ("void " ^ class_name ^ "::__register()\n{\n");
6529 output_cpp ("\t" ^ class_name ^ " _hx_dummy;\n");
6530 output_cpp ("\t" ^ class_name ^ "::_hx_vtable = *(void **)&_hx_dummy;\n");
6601 if (not (has_class_flag class_def CAbstract)) then begin
6602 output_cpp ("\t" ^ class_name ^ " _hx_dummy;\n");
6603 output_cpp ("\t" ^ class_name ^ "::_hx_vtable = *(void **)&_hx_dummy;\n");
6604 end;
65316605 output_cpp ("\t::hx::Static(__mClass) = new ::hx::Class_obj();\n");
65326606 output_cpp ("\t__mClass->mName = " ^ (strq class_name_text) ^ ";\n");
65336607 output_cpp ("\t__mClass->mSuper = &super::__SGetClass();\n");
6534 output_cpp ("\t__mClass->mConstructEmpty = &__CreateEmpty;\n");
6535 output_cpp ("\t__mClass->mConstructArgs = &__Create;\n");
6608 if (not (has_class_flag class_def CAbstract)) then begin
6609 output_cpp ("\t__mClass->mConstructEmpty = &__CreateEmpty;\n");
6610 output_cpp ("\t__mClass->mConstructArgs = &__Create;\n");
6611 end;
65366612 output_cpp ("\t__mClass->mGetStaticField = &" ^ (
65376613 if (has_get_static_field class_def) then class_name ^ "::__GetStatic;\n" else "::hx::Class_obj::GetNoStaticField;\n" ));
65386614 output_cpp ("\t__mClass->mSetStaticField = &" ^ (
66346710 (match class_def.cl_super with
66356711 | Some super ->
66366712 let klass = fst super in
6637 let include_file = get_meta_string_path klass.cl_meta Meta.Include in
6638 h_file#add_include (if include_file="" then klass.cl_path else path_of_string include_file)
6713 let include_files = get_all_meta_string_path klass.cl_meta Meta.Include in
6714 if List.length include_files > 0 then
6715 List.iter (fun inc -> h_file#add_include (path_of_string inc)) include_files
6716 else
6717 h_file#add_include klass.cl_path
66396718 | _ -> () );
66406719
66416720 (* And any interfaces ... *)
66426721 List.iter (fun imp->
66436722 let interface = fst imp in
6644 let include_file = get_meta_string_path interface.cl_meta Meta.Include in
6645 h_file#add_include (if include_file="" then interface.cl_path else path_of_string include_file) )
6723 let include_files = get_all_meta_string_path interface.cl_meta Meta.Include in
6724 if List.length include_files > 0 then
6725 List.iter (fun inc -> h_file#add_include (path_of_string inc)) include_files
6726 else
6727 h_file#add_include interface.cl_path)
66466728 (real_interfaces class_def.cl_implements);
66476729
66486730 (* Only need to forward-declare classes that are mentioned in the header file
66526734 output_h "\n";
66536735
66546736 output_h ( get_class_code class_def Meta.HeaderCode );
6655 let inc = get_meta_string_path class_def.cl_meta Meta.HeaderInclude in
6656 if (inc<>"") then
6657 output_h ("#include \"" ^ inc ^ "\"\n");
6737 let includes = get_all_meta_string_path class_def.cl_meta Meta.HeaderInclude in
6738 let printer = fun inc -> output_h ("#include \"" ^ inc ^ "\"\n") in
6739 List.iter printer includes;
66586740
66596741 gen_open_namespace output_h class_path;
66606742 output_h "\n\n";
67096791 output_h ("\t\tstatic " ^ptr_name^ " __alloc(::hx::Ctx *_hx_ctx" ^
67106792 (if constructor_type_args="" then "" else "," ^constructor_type_args) ^");\n");
67116793 end;
6712 output_h ("\t\tstatic void * _hx_vtable;\n");
6713 output_h ("\t\tstatic Dynamic __CreateEmpty();\n");
6714 output_h ("\t\tstatic Dynamic __Create(::hx::DynamicArray inArgs);\n");
6794 if (not (has_class_flag class_def CAbstract)) then begin
6795 output_h ("\t\tstatic void * _hx_vtable;\n");
6796 output_h ("\t\tstatic Dynamic __CreateEmpty();\n");
6797 output_h ("\t\tstatic Dynamic __Create(::hx::DynamicArray inArgs);\n");
6798 end;
67156799 if (List.length dynamic_functions > 0) then
67166800 output_h ("\t\tstatic void __alloc_dynamic_functions(::hx::Ctx *_hx_alloc," ^ class_name ^ " *_hx_obj);\n");
67176801 if (scriptable) then
69337017 output_string buildfile "<include name=\"${HXCPP}/build-tool/BuildCommon.xml\"/>\n";
69347018 output_string buildfile build_extra;
69357019 if (Common.defined common_ctx Define.HxcppSmartStings) then
6936 output_string buildfile ("<error value=\"Hxcpp is out of date - please update\" unlessApi=\"400\" />\n");
7020 output_string buildfile ("<error value=\"Hxcpp is out of date - please update\" unlessApi=\"" ^ api_string ^ "\" />\n");
69377021 output_string buildfile "</xml>\n";
69387022 close_out buildfile;;
69397023
69407024 let write_build_options common_ctx filename defines =
69417025 let writer = cached_source_writer common_ctx filename in
7026 let write_define name value = writer#write (Printf.sprintf "%s=%s\n" name value) in
69427027 PMap.iter ( fun name value -> match name with
69437028 | "true" | "sys" | "dce" | "cpp" | "debug" -> ()
6944 | _ -> writer#write (name ^ "="^(escape_command value)^ "\n" ) ) defines;
6945 let cmd = Unix.open_process_in "haxelib path hxcpp" in
6946 writer#write ("hxcpp=" ^ (Pervasives.input_line cmd));
6947 Pervasives.ignore (Unix.close_process_in cmd);
7029 | _ -> write_define name (escape_command value)) defines;
7030 let pin,pid = Process_helper.open_process_args_in_pid "haxelib" [|"haxelib"; "path"; "hxcpp"|] in
7031 set_binary_mode_in pin false;
7032 write_define "hxcpp" (Pervasives.input_line pin);
7033 Pervasives.ignore (Process_helper.close_process_in_pid (pin,pid));
69487034 writer#close;;
69497035
69507036 let create_member_types common_ctx =
70857171 | TCppProtocol _ -> "cpp.ObjC.Protocol"
70867172 | TCppNativePointer klass -> "cpp.Pointer." ^ (join_class_path klass.cl_path ".")
70877173 | TCppInterface klass -> (join_class_path klass.cl_path ".")
7088 | TCppInst klass -> (join_class_path klass.cl_path ".")
7174 | TCppInst (klass, _) -> (join_class_path klass.cl_path ".")
70897175 | TCppClass -> "Class"
70907176 | TCppGlobal -> "?global";
70917177 | TCppNull -> "null";
72947380 | IaBinOp OpInterval -> ("...", 121)
72957381 | IaBinOp OpArrow -> ("=>", 122)
72967382 | IaBinOp OpIn -> (" in ", 123)
7383 | IaBinOp OpNullCoal -> ("??", 124)
72977384 | IaBinOp OpAssignOp OpAdd -> ("+=", 201)
72987385 | IaBinOp OpAssignOp OpMult -> ("*=", 202)
72997386 | IaBinOp OpAssignOp OpDiv -> ("/=", 203)
73117398 | IaBinOp OpAssignOp OpMod -> ("%=", 220)
73127399
73137400 | IaBinOp OpAssignOp OpIn
7401 | IaBinOp OpAssignOp OpNullCoal
73147402 | IaBinOp OpAssignOp OpInterval
73157403 | IaBinOp OpAssignOp OpAssign
73167404 | IaBinOp OpAssignOp OpEq
74327520 end
74337521 method constText c = match c with
74347522 | TInt i -> (this#op IaConstInt) ^ (Printf.sprintf "%ld " i)
7435 | TFloat f -> (this#op IaConstFloat) ^ (this#stringText f)
7523 | TFloat f -> (this#op IaConstFloat) ^ (this#stringText (replace_float_separators f))
74367524 | TString s -> (this#op IaConstString) ^ (this#stringText s)
74377525 | TBool true -> (this#op IaConstTrue)
74387526 | TBool false -> (this#op IaConstFalse)
79818069 | FuncEnumConstruct(enum,field) ->
79828070 this#write ((this#op IaCreateEnum) ^ (this#enumText enum) ^ " " ^ (this#stringText field.ef_name) ^ argN ^
79838071 (this#commentOf field.ef_name) ^ "\n");
7984 | FuncSuperConstruct(TCppInst klass) when (is_native_gen_class klass) && (is_native_class klass) ->
8072 | FuncSuperConstruct(TCppInst (klass, _)) when (is_native_gen_class klass) && (is_native_class klass) ->
79858073 abort "Unsupported super for native class constructor" expression.cpppos;
79868074 | FuncSuperConstruct childType ->
79878075 this#write ((this#op IaCallSuperNew) ^ (this#astType childType) ^ " " ^ argN ^ "\n");
7988 | FuncSuper(_,TCppInst(klass),_) when (is_native_gen_class klass) && (is_native_class klass) ->
8076 | FuncSuper(_,TCppInst(klass, _),_) when (is_native_gen_class klass) && (is_native_class klass) ->
79898077 abort "Unsupported super for native class method" expression.cpppos;
79908078 | FuncSuper(_,objType,field) ->
79918079 this#write ( (this#op IaCallSuper) ^ (this#astType objType) ^ " " ^ (this#stringText field.cf_name) ^
83538441 let generate_cppia ctx =
83548442 let common_ctx = ctx.ctx_common in
83558443 let debug = ctx.ctx_debug_level in
8444 Path.mkdir_from_path common_ctx.file;
83568445 let script = new script_writer ctx common_ctx.file common_ctx.debug in
83578446 ignore (script#stringId "");
83588447 ignore (script#typeId "");
85528641 | _ -> "output" in
85538642
85548643 write_build_data common_ctx (common_ctx.file ^ "/Build.xml") !exe_classes !main_deps (!boot_enums@ !boot_classes) !build_xml !extern_src output_name;
8555 let cmd_defines = ref "" in
8556 PMap.iter ( fun name value -> match name with
8557 | "true" | "sys" | "dce" | "cpp" | "debug" -> ()
8558 | _ -> cmd_defines := !cmd_defines ^ " -D" ^ name ^ "=\"" ^ (escape_command value) ^ "\"" ) common_ctx.defines.Define.values;
85598644 write_build_options common_ctx (common_ctx.file ^ "/Options.txt") common_ctx.defines.Define.values;
85608645 if ( not (Common.defined common_ctx Define.NoCompilation) ) then begin
85618646 let t = Timer.timer ["generate";"cpp";"native compilation"] in
85628647 let old_dir = Sys.getcwd() in
85638648 Sys.chdir common_ctx.file;
8564 let cmd = ref "haxelib run hxcpp Build.xml haxe" in
8565 if (common_ctx.debug) then cmd := !cmd ^ " -Ddebug";
8566 cmd := !cmd ^ !cmd_defines;
8567 cmd := List.fold_left (fun cmd path -> cmd ^ " -I\"" ^ (escape_command path) ^ "\"" ) !cmd common_ctx.class_path;
8568 common_ctx.print (!cmd ^ "\n");
8569 if common_ctx.run_command !cmd <> 0 then failwith "Build failed";
8649 let cmd = ref ["run"; "hxcpp"; "Build.xml"; "haxe"] in
8650 if (common_ctx.debug) then cmd := !cmd @ ["-Ddebug"];
8651 PMap.iter ( fun name value -> match name with
8652 | "true" | "sys" | "dce" | "cpp" | "debug" -> ();
8653 | _ -> cmd := !cmd @ [Printf.sprintf "-D%s=\"%s\"" name (escape_command value)];
8654 ) common_ctx.defines.values;
8655 List.iter (fun path -> cmd := !cmd @ [Printf.sprintf "-I%s" (escape_command path)]) common_ctx.class_path;
8656 common_ctx.print ("haxelib " ^ (String.concat " " !cmd) ^ "\n");
8657 if common_ctx.run_command_args "haxelib" !cmd <> 0 then failwith "Build failed";
85708658 Sys.chdir old_dir;
85718659 t()
85728660 end
85828670 generate_source ctx
85838671 end
85848672 ;;
8585
8586
109109 match t with
110110 | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ )
111111 | TAbstract( { a_path = ([], "Null") }, _ ) -> true
112 | TType( t, tl ) -> is_null (apply_params t.t_params tl t.t_type)
112 | TType( t, tl ) -> is_null (apply_typedef t tl)
113113 | TMono r ->
114114 (match r.tm_type with
115115 | Some t -> is_null t
157157 | [],Method (MethNormal | MethDynamic | MethInline) ->
158158 (match cf.cf_expr, follow cf.cf_type with
159159 | Some ({ eexpr = TFunction fn } as method_expr), TFun (args, return_type) ->
160 let type_params = List.map snd cl.cl_params in
160 let type_params = extract_param_types cl.cl_params in
161161 let rec collect_overloads tf_args_rev args_rev default_values_rev =
162162 match tf_args_rev, args_rev with
163163 | (_, Some default_value) :: rest_tf_args_rev, _ :: rest_args_rev ->
13681368 | _ -> ()
13691369 *)
13701370 | TFloat s ->
1371 let s = Texpr.replace_separators s "" in
13711372 let len = String.length s in
13721373 let rec loop i prev_c =
13731374 if i >= len then begin
14651466 )
14661467 | TParenthesis e ->
14671468 write w "("; expr_s w e; write w ")"
1468 | TMeta ((Meta.LoopLabel,[(EConst(Int n),_)],_), e) ->
1469 | TMeta ((Meta.LoopLabel,[(EConst(Int (n, _)),_)],_), e) ->
14691470 (match e.eexpr with
14701471 | TFor _ | TWhile _ ->
14711472 expr_s w e;
18881889 let rec gen_fpart_attrib w = function
18891890 | EConst( Ident i ), _ ->
18901891 write w i
1891 | EField( ef, f ), _ ->
1892 | EField( ef, f, _ ), _ ->
18921893 gen_fpart_attrib w ef;
18931894 write w ".";
18941895 write w f
18981899
18991900 let rec gen_spart w = function
19001901 | EConst c, p -> (match c with
1901 | Int s | Float s | Ident s ->
1902 | Int (s, _) | Float (s, _) | Ident s ->
19021903 write w s
19031904 | String(s,_) ->
19041905 write w "\"";
19051906 write w (escape s);
19061907 write w "\""
19071908 | _ -> gen.gcon.error "Invalid expression inside @:meta metadata" p)
1908 | EField( ef, f ), _ ->
1909 | EField( ef, f, _ ), _ ->
19091910 gen_spart w ef;
19101911 write w ".";
19111912 write w f
20122013 let combination_error c1 c2 =
20132014 gen.gcon.error ("The " ^ (get_constraint c1) ^ " constraint cannot be combined with the " ^ (get_constraint c2) ^ " constraint.") cl.cl_pos in
20142015
2015 let params = sprintf "<%s>" (String.concat ", " (List.map (fun (_, tcl) -> get_param_name tcl) cl_params)) in
2016 let params = sprintf "<%s>" (String.concat ", " (List.map (fun tp -> get_param_name tp.ttp_type) cl_params)) in
20162017 let params_extends =
20172018 if hxgen || not (Meta.has (Meta.NativeGen) cl.cl_meta) then
20182019 [""]
20192020 else
2020 List.fold_left (fun acc (name, t) ->
2021 List.fold_left (fun acc {ttp_name=name;ttp_type=t} ->
20212022 match run_follow gen t with
20222023 | TInst({cl_kind = KTypeParameter constraints}, _) when constraints <> [] ->
20232024 (* base class should come before interface constraints *)
23262327 let modifiers = if is_abstract then "abstract" :: modifiers else modifiers in
23272328 let visibility, is_virtual = if is_explicit_iface then "",false else if visibility = "private" then "private",false else visibility, is_virtual in
23282329 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
2329 let cf_type = if is_override && not is_overload && not (has_class_field_flag cf CfOverload) then match field_access gen (TInst(cl, List.map snd cl.cl_params)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> die "" __LOC__ else cf.cf_type in
2330 let cf_type = if is_override && not is_overload && not (has_class_field_flag cf CfOverload) then match field_access gen (TInst(cl, extract_param_types cl.cl_params)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> die "" __LOC__ else cf.cf_type in
23302331 let ret_type, args = match follow cf_type with | TFun (strbtl, t) -> (t, strbtl) | _ -> die "" __LOC__ in
23312332 gen_nocompletion w cf.cf_meta;
23322333
24342435 let args,ret = get_fun cf.cf_type in
24352436 match args with
24362437 | [_,_,idx] -> pairs := PMap.add (t_s idx) ( t_s ret, Some cf, None ) !pairs
2437 | _ -> gen.gcon.warning "The __get function must have exactly one argument (the index)" cf.cf_pos
2438 | _ -> gen.gwarning WGenerator "The __get function must have exactly one argument (the index)" cf.cf_pos
24382439 ) (get :: get.cf_overloads)
24392440 with | Not_found -> ());
24402441 (try
24452446 | [_,_,idx; _,_,v] -> (try
24462447 let vt, g, _ = PMap.find (t_s idx) !pairs in
24472448 let tvt = t_s v in
2448 if vt <> tvt then gen.gcon.warning "The __get function of same index has a different type from this __set function" cf.cf_pos;
2449 if vt <> tvt then gen.gwarning WGenerator "The __get function of same index has a different type from this __set function" cf.cf_pos;
24492450 pairs := PMap.add (t_s idx) (vt, g, Some cf) !pairs
24502451 with | Not_found ->
24512452 pairs := PMap.add (t_s idx) (t_s v, None, Some cf) !pairs)
24522453 | _ ->
2453 gen.gcon.warning "The __set function must have exactly two arguments (index, value)" cf.cf_pos
2454 gen.gwarning WGenerator "The __set function must have exactly two arguments (index, value)" cf.cf_pos
24542455 ) (set :: set.cf_overloads)
24552456 with | Not_found -> ());
24562457 PMap.iter (fun idx (v, get, set) ->
25672568 let this = if static then
25682569 make_static_this cl f.cf_pos
25692570 else
2570 { eexpr = TConst TThis; etype = TInst(cl,List.map snd cl.cl_params); epos = f.cf_pos }
2571 { eexpr = TConst TThis; etype = TInst(cl,extract_param_types cl.cl_params); epos = f.cf_pos }
25712572 in
25722573 print w "public %s%s %s" (if static then "static " else "") (t_s f.cf_type) (Dotnet.netname_to_hx f.cf_name);
25732574 begin_block w;
26322633 else
26332634 "object" :: (loop (pred i) acc)
26342635 in
2635 let tparams = loop (match m with [(EConst(Int s),_)] -> int_of_string s | _ -> die "" __LOC__) [] in
2636 let tparams = loop (match m with [(EConst(Int (s, _)),_)] -> int_of_string s | _ -> die "" __LOC__) [] in
26362637 cl.cl_meta <- (Meta.Meta, [
26372638 EConst(String("global::haxe.lang.GenericInterface(typeof(global::" ^ module_s (TClassDecl cl) ^ "<" ^ String.concat ", " tparams ^ ">))",SDoubleQuotes) ), cl.cl_pos
26382639 ], cl.cl_pos) :: cl.cl_meta
27542755
27552756 let events, nonprops = !events, !nonprops in
27562757
2757 let t = TInst(cl, List.map snd cl.cl_params) in
2758 let t = TInst(cl, extract_param_types cl.cl_params) in
27582759 let find_prop name = try
27592760 List.assoc name !props
27602761 with | Not_found -> match field_access gen t name with
2761 | FClassField (_,_,decl,v,_,t,_) when is_extern_prop (TInst(cl,List.map snd cl.cl_params)) name ->
2762 | FClassField (_,_,decl,v,_,t,_) when is_extern_prop (TInst(cl,extract_param_types cl.cl_params)) name ->
27622763 let ret = ref (v,t,None,None) in
27632764 props := (name, ret) :: !props;
27642765 ret
31323133
31333134 add_cast_handler gen;
31343135 if not erase_generics then
3135 RealTypeParams.configure gen (fun e t -> gen.gcon.warning ("Cannot cast to " ^ (debug_type t)) e.epos; mk_cast t e) ifaces (get_cl (get_type gen (["haxe";"lang"], "IGenericObject")))
3136 RealTypeParams.configure gen (fun e t -> gen.gwarning WGenerator ("Cannot cast to " ^ (debug_type t)) e.epos; mk_cast t e) ifaces (get_cl (get_type gen (["haxe";"lang"], "IGenericObject")))
31363137 else
31373138 RealTypeParams.RealTypeParamsModf.configure gen (RealTypeParams.RealTypeParamsModf.set_only_hxgeneric gen);
31383139
34623463 let net_lib = List.find (function net_lib -> is_some (net_lib#lookup (["haxe";"lang"], "FieldLookup"))) gen.gcon.native_libs.net_libs in
34633464 let name = net_lib#get_name in
34643465 if not (Common.defined gen.gcon Define.DllImport) then begin
3465 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;
3466 gen.gwarning WGenerator ("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;
34663467 raise Not_found
34673468 end;
34683469 if not (List.exists (function net_lib -> net_lib#get_name = name) haxe_libs) then
3469 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;
3470 gen.gwarning WGenerator ("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;
34703471 (* it has; in this case, we need to add the used fields on each __init__ *)
34713472 add_class_flag flookup_cl CExtern;
34723473 let hashs_by_path = Hashtbl.create !nhash in
35463547 if ( not (Common.defined gen.gcon Define.NoCompilation) ) then begin
35473548 let old_dir = Sys.getcwd() in
35483549 Sys.chdir gen.gcon.file;
3549 let cmd = "haxelib run hxcs hxcs_build.txt --haxe-version " ^ (string_of_int gen.gcon.version) ^ " --feature-level 1" in
3550 let cmd =
3550 let cmd = "haxelib" in
3551 let args = ["run"; "hxcs"; "hxcs_build.txt"; "--haxe-version"; (string_of_int gen.gcon.version); "--feature-level"; "1"] in
3552 let args =
35513553 match gen.gentry_point with
35523554 | Some (name,_,_) ->
35533555 let name = if gen.gcon.debug then name ^ "-Debug" else name in
3554 cmd ^ " --out " ^ gen.gcon.file ^ "/bin/" ^ name
3556 args@["--out"; gen.gcon.file ^ "/bin/" ^ name]
35553557 | _ ->
3556 cmd
3558 args
35573559 in
3558 print_endline cmd;
3559 if gen.gcon.run_command cmd <> 0 then failwith "Build failed";
3560 print_endline (cmd ^ " " ^ (String.concat " " args));
3561 if gen.gcon.run_command_args cmd args <> 0 then failwith "Build failed";
35603562 Sys.chdir old_dir;
35613563 end
35623564
149149
150150 let is_array_class name =
151151 match name with
152 | "hl.types.ArrayDyn" | "hl.types.ArrayBytes_Int" | "hl.types.ArrayBytes_Float" | "hl.types.ArrayObj" | "hl.types.ArrayBytes_F32" | "hl.types.ArrayBytes_hl_UI16" -> true
152 | "hl.types.ArrayDyn" | "hl.types.ArrayBytes_Int" | "hl.types.ArrayBytes_Float" | "hl.types.ArrayObj" | "hl.types.ArrayBytes_hl_F32" | "hl.types.ArrayBytes_hl_UI16" -> true
153153 | _ -> false
154154
155155 let is_array_type t =
354354 let fake_tnull =
355355 {null_abstract with
356356 a_path = [],"Null";
357 a_params = ["T",t_dynamic];
357 a_params = [{ttp_name = "T"; ttp_type = t_dynamic; ttp_default = None}];
358358 }
359359
360360 let get_rec_cache ctx t none_callback not_found_callback =
379379 let t =
380380 get_rec_cache ctx t
381381 (fun() -> abort "Unsupported recursive type" td.t_pos)
382 (fun tref -> to_type ~tref ctx (apply_params td.t_params tl td.t_type))
382 (fun tref -> to_type ~tref ctx (apply_typedef td tl))
383383 in
384384 (match td.t_path with
385385 | ["haxe";"macro"], name -> Hashtbl.replace ctx.macro_typedefs name t; t
394394 | TAnon a when (match !(a.a_status) with Statics _ | EnumStatics _ -> true | _ -> false) ->
395395 (match !(a.a_status) with
396396 | Statics c ->
397 class_type ctx c (List.map snd c.cl_params) true
397 class_type ctx c (extract_param_types c.cl_params) true
398398 | EnumStatics e ->
399399 enum_class ctx e
400400 | _ -> die "" __LOC__)
643643 | Method MethDynamic when has_class_field_flag f CfOverride ->
644644 Some (try fst (get_index f.cf_name p) with Not_found -> die "" __LOC__)
645645 | _ ->
646 let fid = add_field f.cf_name (fun() -> to_type ctx f.cf_type) in
646 let fid = add_field f.cf_name (fun() ->
647 let t = to_type ctx f.cf_type in
648 if has_meta (Meta.Custom ":packed") f.cf_meta then begin
649 (match t with HStruct _ -> () | _ -> abort "Packed field should be struct" f.cf_pos);
650 HPacked t
651 end else t
652 ) in
647653 Some fid
648654 ) in
649655 match f.cf_kind, fid with
760766 and class_global ?(resolve=true) ctx c =
761767 let static = c != ctx.base_class in
762768 let c = if resolve && is_array_type (HObj { null_proto with pname = s_type_path c.cl_path }) then ctx.array_impl.abase else c in
763 let c = resolve_class ctx c (List.map snd c.cl_params) static in
769 let c = resolve_class ctx c (extract_param_types c.cl_params) static in
764770 let t = class_type ctx c [] static in
765771 alloc_global ctx ("$" ^ s_type_path c.cl_path) t, t
766772
24832489 free ctx r;
24842490 binop r r b;
24852491 r))
2486 | OpInterval | OpArrow | OpIn ->
2492 | OpInterval | OpArrow | OpIn | OpNullCoal ->
24872493 die "" __LOC__)
24882494 | TUnop (Not,_,v) ->
24892495 let tmp = alloc_tmp ctx HBool in
25062512 | HUI8 -> 0xFFl
25072513 | HUI16 -> 0xFFFFl
25082514 | HI32 -> 0xFFFFFFFFl
2509 | _ -> abort (tstr t) e.epos
2515 | _ -> abort ("Unsupported " ^ tstr t) e.epos
25102516 ) in
25112517 hold ctx r;
25122518 let r2 = alloc_tmp ctx t in
26452651 ctx.m.mloop_trys <- oldtrys;
26462652 alloc_tmp ctx HVoid
26472653 | TCast ({ eexpr = TCast (v,None) },None) when not (is_number (to_type ctx e.etype)) ->
2648 (* coalesce double casts into a single runtime check - temp fix for Map accesses *)
2649 eval_expr ctx { e with eexpr = TCast(v,None) }
2654 (* coalesce double casts into a single runtime check - temp fix for Map accesses *)
2655 eval_expr ctx { e with eexpr = TCast(v,None) }
26502656 | TCast (v,None) ->
26512657 let t = to_type ctx e.etype in
26522658 let rv = eval_expr ctx v in
33173323 add_native lib name
33183324 | (Meta.HlNative,[(EConst(String(lib,_)),_)] ,_ ) :: _ ->
33193325 add_native lib f.cf_name
3320 | (Meta.HlNative,[(EConst(Float(ver)),_)] ,_ ) :: _ ->
3326 | (Meta.HlNative,[(EConst(Float(ver,_)),_)] ,_ ) :: _ ->
33213327 let cur_ver = (try Common.defined_value ctx.com Define.HlVer with Not_found -> "") in
33223328 if cur_ver < ver then
33233329 let gen_content() =
33453351 | Method m ->
33463352 let gen_content = if f.cf_name <> "new" then None else Some (fun() ->
33473353
3348 let o = (match class_type ctx c (List.map snd c.cl_params) false with
3354 let o = (match class_type ctx c (extract_param_types c.cl_params) false with
33493355 | HObj o | HStruct o -> o
33503356 | _ -> die "" __LOC__
33513357 ) in
33873393 if f.cf_name = "toString" && not (has_class_field_flag f CfOverride) && not (PMap.mem "__string" c.cl_fields) && is_to_string f.cf_type then begin
33883394 let p = f.cf_pos in
33893395 (* function __string() return this.toString().bytes *)
3390 let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_params)) p in
3391 let tstr = mk (TCall (mk (TField (ethis,FInstance(c,List.map snd c.cl_params,f))) f.cf_type p,[])) ctx.com.basic.tstring p in
3396 let ethis = mk (TConst TThis) (TInst (c,extract_param_types c.cl_params)) p in
3397 let tstr = mk (TCall (mk (TField (ethis,FInstance(c,extract_param_types c.cl_params,f))) f.cf_type p,[])) ctx.com.basic.tstring p in
33923398 let cstr, cf_bytes = (try (match ctx.com.basic.tstring with TInst(c,_) -> c, PMap.find "bytes" c.cl_fields | _ -> die "" __LOC__) with Not_found -> die "" __LOC__) in
33933399 let estr = mk (TReturn (Some (mk (TField (tstr,FInstance (cstr,[],cf_bytes))) cf_bytes.cf_type p))) ctx.com.basic.tvoid p in
33943400 ignore(make_fun ctx (s_type_path c.cl_path,"__string") (alloc_fun_path ctx c.cl_path "__string") { tf_expr = estr; tf_args = []; tf_type = cf_bytes.cf_type; } (Some c) None)
34363442
34373443 let gen_content() =
34383444
3439 op ctx (OCall0 (alloc_tmp ctx HVoid, alloc_fun_path ctx ([],"Type") "init"));
3445 let is_init = alloc_tmp ctx HBool in
3446 op ctx (OCall0 (is_init, alloc_fun_path ctx ([],"Type") "init"));
3447 hold ctx is_init;
34403448
34413449 (* init class values *)
34423450 List.iter (fun t ->
34473455
34483456 let g, ct = class_global ~resolve:false ctx c in
34493457 let ctype = if c == ctx.array_impl.abase then ctx.array_impl.aall else c in
3450 let t = class_type ctx ctype (List.map snd ctype.cl_params) false in
3458 let t = class_type ctx ctype (extract_param_types ctype.cl_params) false in
34513459
34523460 let index name =
34533461 match ct with
36083616 ()
36093617
36103618 ) types;
3619
3620 let j = jump ctx (fun d -> OJTrue (is_init,d)) in
3621 op ctx (ORet (alloc_tmp ctx HVoid));
3622 j();
3623 free ctx is_init;
36113624 in
36123625 (* init class statics *)
36133626 let init_exprs = ref [] in
36753688 let write_index = write_index_gen byte in
36763689
36773690 let rec write_type t =
3678 write_index (try PMap.find t htypes with Not_found -> die "" __LOC__)
3691 write_index (try PMap.find t htypes with Not_found -> die (tstr t) __LOC__)
36793692 in
36803693
36813694 let write_op op =
38283841 write_index p.pid;
38293842 (match p.psuper with
38303843 | None -> write_index (-1)
3831 | Some t -> write_type (HObj t));
3844 | Some tsup -> write_type (match t with HObj _ -> HObj tsup | _ -> HStruct tsup));
38323845 (match p.pclassglobal with
38333846 | None -> write_index 0
38343847 | Some g -> write_index (g + 1));
38693882 ) e.efields
38703883 | HNull t ->
38713884 byte 19;
3885 write_type t
3886 | HPacked t ->
3887 byte 22;
38723888 write_type t
38733889 ) all_types;
38743890
39683984 let ctx = {
39693985 com = com;
39703986 is_macro = is_macro;
3971 optimize = not (Common.raw_defined com "hl-no-opt");
3987 optimize = not (Common.raw_defined com "hl_no_opt");
39723988 dump_out = if dump then Some (IO.output_channel (open_out_bin "dump/hlopt.txt")) else None;
39733989 m = method_context 0 HVoid null_capture false;
39743990 cints = new_lookup();
40884104
40894105 let generate com =
40904106 let dump = Common.defined com Define.Dump in
4091 let hl_check = Common.raw_defined com "hl-check" in
4107 let hl_check = Common.raw_defined com "hl_check" in
40924108
40934109 let sign = make_context_sign com in
40944110 if sign = !prev_sign && not dump && not hl_check then begin
41084124 Hlcode.dump (fun s -> output_string ch (s ^ "\n")) code;
41094125 close_out ch;
41104126 end;
4111 (*if Common.raw_defined com "hl-dump-spec" then begin
4127 (*if Common.raw_defined com "hl_dump_spec" then begin
41124128 let ch = open_out_bin "dump/hlspec.txt" in
41134129 let write s = output_string ch (s ^ "\n") in
41144130 Array.iter (fun f ->
41314147 "\"" ^ Buffer.contents b ^ "\""
41324148 in
41334149
4134 if file_extension com.file = "c" then begin
4150 if Path.file_extension com.file = "c" then begin
41354151 let gnames = Array.create (Array.length code.globals) "" in
41364152 PMap.iter (fun n i -> gnames.(i) <- n) ctx.cglobals.map;
4153 if not (Common.defined com Define.SourceHeader) then begin
4154 let version_major = com.version / 1000 in
4155 let version_minor = (com.version mod 1000) / 100 in
4156 let version_revision = (com.version mod 100) in
4157 Common.define_value com Define.SourceHeader (Printf.sprintf "Generated by HLC %d.%d.%d (HL v%d)" version_major version_minor version_revision code.version);
4158 end;
41374159 Hl2c.write_c com com.file code gnames;
41384160 let t = Timer.timer ["nativecompile";"hl"] in
4139 if not (Common.defined com Define.NoCompilation) && com.run_command ("haxelib run hashlink build " ^ escape_command com.file) <> 0 then failwith "Build failed";
4161 if not (Common.defined com Define.NoCompilation) && com.run_command_args "haxelib" ["run";"hashlink";"build";escape_command com.file] <> 0 then failwith "Build failed";
41404162 t();
41414163 end else begin
41424164 let ch = IO.output_string() in
4143 write_code ch code (not (Common.raw_defined com "hl-no-debug"));
4165 write_code ch code (not (Common.raw_defined com "hl_no_debug"));
41444166 let str = IO.close_out ch in
41454167 let ch = open_out_bin com.file in
41464168 output_string ch str;
41514173 Hlopt.clean_cache();
41524174 t();
41534175 if Common.raw_defined com "run" then begin
4154 if com.run_command ("haxelib run hashlink run " ^ escape_command com.file) <> 0 then failwith "Failed to run HL";
4176 if com.run_command_args "haxelib" ["run";"hashlink";"run";escape_command com.file] <> 0 then failwith "Failed to run HL";
41554177 end;
41564178 if Common.defined com Define.Interp then
41574179 try
103103 "{" ^ String.concat ", " fields ^ "}"
104104 | TLazy f ->
105105 stype (lazy_type f)
106 | TDynamic t2 ->
107 if t == t2 then "Dynamic" else "Dynamic<" ^ stype t2 ^ ">"
106 | TDynamic None ->
107 "Dynamic"
108 | TDynamic (Some t2) ->
109 "Dynamic<" ^ stype t2 ^ ">"
108110 | TFun ([],ret) ->
109111 "() -> " ^ ftype ret
110112 | TFun (args,ret) ->
179181 | [] -> Ident "null"
180182 | (Meta.DefParam,[(EConst (String(p,_)),_);(EConst v,_)],_) :: _ when p = a ->
181183 (match v with
182 | Float "1.#QNAN" -> Float "0./*NaN*/"
183 | Float "4294967295." -> Int "0xFFFFFFFF"
184 | Int "16777215" -> Int "0xFFFFFF"
185 | Float x ->
184 | Float ("1.#QNAN", _) -> Float ("0./*NaN*/", None)
185 | Float ("4294967295.", _) -> Int ("0xFFFFFFFF", None)
186 | Int ("16777215", _) -> Int ("0xFFFFFF", None)
187 | Float (x, _) ->
186188 (try
187189 let f = float_of_string x in
188190 let s = string_of_int (int_of_float f) in
189 if s ^ "." = x then Int s else v
191 if s ^ "." = x then Int (s, None) else v
190192 with _ ->
191193 v)
192194 | _ -> v)
197199 | _ ->
198200 die "" __LOC__
199201 ) in
200 let tparams = (match f.cf_params with [] -> "" | l -> "<" ^ String.concat "," (List.map fst l) ^ ">") in
202 let tparams = (match f.cf_params with [] -> "" | l -> "<" ^ String.concat "," (List.map extract_param_name l) ^ ">") in
201203 p "function %s%s(%s) : %s" name tparams (String.concat ", " (List.map sparam params)) (stype ret);
202204 );
203205 p ";\n";
207209 | TClassDecl c ->
208210 print_meta c.cl_meta;
209211 let finalmod = if (has_class_flag c CFinal) then "final " else "" in
210 p "extern %s%s %s" finalmod (if (has_class_flag c CInterface) then "interface" else "class") (stype (TInst (c,List.map snd c.cl_params)));
212 p "extern %s%s %s" finalmod (if (has_class_flag c CInterface) then "interface" else "class") (stype (TInst (c,extract_param_types c.cl_params)));
211213 let ext = (match c.cl_super with
212214 | None -> []
213215 | Some (c,pl) -> [" extends " ^ stype (TInst (c,pl))]
248250 p "}\n";
249251 | TEnumDecl e ->
250252 print_meta e.e_meta;
251 p "extern enum %s {\n" (stype (TEnum(e,List.map snd e.e_params)));
253 p "extern enum %s {\n" (stype (TEnum(e,extract_param_types e.e_params)));
252254 List.iter (fun n ->
253255 let c = PMap.find n e.e_constrs in
254256 p "\t%s" c.ef_name;
260262 p "}\n"
261263 | TTypeDecl t ->
262264 print_meta t.t_meta;
263 p "typedef %s = " (stype (TType (t,List.map snd t.t_params)));
265 p "typedef %s = " (stype (TType (t,extract_param_types t.t_params)));
264266 p "%s" (stype t.t_type);
265267 p "\n";
266268 | TAbstractDecl a ->
269271 p "extern ";
270272 let is_enum = a.a_enum in
271273 if is_enum then p "enum ";
272 p "abstract %s" (stype (TAbstract (a,List.map snd a.a_params)));
274 p "abstract %s" (stype (TAbstract (a,extract_param_types a.a_params)));
273275 if not (Meta.has Meta.CoreType a.a_meta) then p "(%s)" (stype a.a_this);
274276 p " {\n";
275277 Option.may (fun c ->
10831083 Some t
10841084 | TAbstract (({ a_path = [],"Null" } as tab),[t2]) ->
10851085 Some (TAbstract(tab,[gen.gfollow#run_f t2]))
1086 | TType ({ t_path = ["haxe";"_Rest"],"NativeRest" } as td, [t2]) ->
1087 Some (gen.gfollow#run_f (follow (TType (td,[get_boxed gen t2]))))
1088 | TAbstract ({ a_path = ["haxe"],"Rest" } as a, [t2]) ->
1089 Some (gen.gfollow#run_f ( Abstract.get_underlying_type a [get_boxed gen t2]) )
10861090 | TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) ->
10871091 Some (gen.gfollow#run_f ( Abstract.get_underlying_type a pl) )
10881092 | TAbstract( { a_path = ([], "EnumValue") }, _ )
11371141 | TAbstract( { a_path = (["java"], "Int64") }, [] )
11381142 | TAbstract( { a_path = (["haxe"], "Int64") }, [] ) ->
11391143 TInst(cl_long, [])
1140 | _ -> (match follow t with
1141 | TInst( { cl_kind = KTypeParameter _ }, []) ->
1142 t_dynamic
1143 | _ -> real_type t
1144 )
1144 | _ ->
1145 real_type t
11451146 )
11461147 | TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) ->
11471148 real_type (Abstract.get_underlying_type a pl)
15191520 | TTypeExpr mt -> write w (md_s e.epos mt)
15201521 | TParenthesis e ->
15211522 write w "("; expr_s w e; write w ")"
1522 | TMeta ((Meta.LoopLabel,[(EConst(Int n),_)],_), e) ->
1523 | TMeta ((Meta.LoopLabel,[(EConst(Int (n, _)),_)],_), e) ->
15231524 (match e.eexpr with
15241525 | TFor _ | TWhile _ ->
15251526 print w "label%s:" n;
15291530 | _ -> die "" __LOC__)
15301531 | TMeta (_,e) ->
15311532 expr_s w e
1533 | TCall ({ eexpr = TField(_, FStatic({ cl_path = (["haxe";"_Rest"],"Rest_Impl_") }, { cf_name = "createNative" })) }, el) ->
1534 (match follow e.etype with
1535 | TInst (cls, params) ->
1536 expr_s w { e with eexpr = TNew(cls,params,el) }
1537 | _ -> die ~p:e.epos "Unexpected return type of haxe.Rest.createNative" __LOC__)
15321538 | TCall ({ eexpr = TIdent "__array__" }, el)
15331539 | TCall ({ eexpr = TField(_, FStatic({ cl_path = (["java"],"NativeArray") }, { cf_name = "make" })) }, el)
15341540 | TArrayDecl el when t_has_type_param e.etype ->
18141820 let rec gen_fpart_attrib w = function
18151821 | EConst( Ident i ), _ ->
18161822 write w i
1817 | EField( ef, f ), _ ->
1823 | EField( ef, f, _ ), _ ->
18181824 gen_fpart_attrib w ef;
18191825 write w ".";
18201826 write w f
18241830
18251831 let rec gen_spart w = function
18261832 | EConst c, p -> (match c with
1827 | Int s | Float s | Ident s ->
1833 | Int (s, _) | Float (s, _) | Ident s ->
18281834 write w s
18291835 | String(s,_) ->
18301836 write w "\"";
18311837 write w (escape s);
18321838 write w "\""
18331839 | _ -> gen.gcon.error "Invalid expression inside @:meta metadata" p)
1834 | EField( ef, f ), _ ->
1840 | EField( ef, f, _ ), _ ->
18351841 gen_spart w ef;
18361842 write w ".";
18371843 write w f
18991905 | [] ->
19001906 ("","")
19011907 | _ ->
1902 let params = sprintf "<%s>" (String.concat ", " (List.map (fun (_, tcl) -> match follow tcl with | TInst(cl, _) -> snd cl.cl_path | _ -> die "" __LOC__) cl_params)) in
1903 let params_extends = List.fold_left (fun acc (name, t) ->
1908 let params = sprintf "<%s>" (String.concat ", " (List.map (fun tp -> match follow tp.ttp_type with | TInst(cl, _) -> snd cl.cl_path | _ -> die "" __LOC__) cl_params)) in
1909 let params_extends = List.fold_left (fun acc {ttp_name=name;ttp_type=t} ->
19041910 match run_follow gen t with
19051911 | TInst (cl, p) ->
19061912 (match cl.cl_implements with
19911997 let modifiers = if is_abstract then "abstract" :: modifiers else modifiers in
19921998 let visibility, is_virtual = if is_explicit_iface then "",false else visibility, is_virtual in
19931999 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
1994 let cf_type = if is_override && not is_overload && not (has_class_field_flag cf CfOverload) then match field_access gen (TInst(cl, List.map snd cl.cl_params)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> die "" __LOC__ else cf.cf_type in
1995
1996 let params = List.map snd cl.cl_params in
2000 let cf_type = if is_override && not is_overload && not (has_class_field_flag cf CfOverload) then match field_access gen (TInst(cl, extract_param_types cl.cl_params)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> die "" __LOC__ else cf.cf_type in
2001
2002 let params = extract_param_types cl.cl_params in
19972003 let ret_type, args, has_rest_args = match follow cf_type, follow cf.cf_type with
19982004 | TFun (strbtl, t), TFun(rargs, _) ->
19992005 let ret_type = apply_params cl.cl_params params (real_type t)
20832089 newline w
20842090 in
20852091
2092 let gen_class_field w ?(is_overload=false) is_static cl is_final cf =
2093 (* This should probably be handled somewhere earlier in the unholy gencommon machinery, but whatever *)
2094 if not (has_class_field_flag cf CfExtern) then gen_class_field w ~is_overload is_static cl is_final cf
2095 in
2096
20862097 let gen_class w cl =
20872098 let cf_filters = [ handle_throws ] in
20882099 List.iter (fun f -> List.iter (f gen) cl.cl_ordered_fields) cf_filters;
26922703 if ( not (Common.defined gen.gcon Define.NoCompilation) ) then begin
26932704 let old_dir = Sys.getcwd() in
26942705 Sys.chdir gen.gcon.file;
2695 let cmd = "haxelib run hxjava hxjava_build.txt --haxe-version " ^ (string_of_int gen.gcon.version) ^ " --feature-level 1" in
2696 let cmd =
2706 let cmd = "haxelib" in
2707 let args = ["run";"hxjava";"hxjava_build.txt";"--haxe-version";(string_of_int gen.gcon.version);"--feature-level";"1"] in
2708 let args =
26972709 match gen.gentry_point with
26982710 | Some (name,_,_) ->
26992711 let name = if gen.gcon.debug then name ^ "-Debug" else name in
2700 cmd ^ " --out " ^ gen.gcon.file ^ "/" ^ name
2712 args @ ["--out";gen.gcon.file ^ "/" ^ name]
27012713 | _ ->
2702 cmd
2703 in
2704 print_endline cmd;
2705 if gen.gcon.run_command cmd <> 0 then failwith "Build failed";
2714 args
2715 in
2716 print_endline (cmd ^ " " ^ (String.concat " " args));
2717 if gen.gcon.run_command_args cmd args <> 0 then failwith "Build failed";
27062718 Sys.chdir old_dir;
27072719 end
27082720
715715 spr ctx "(";
716716 gen_value ctx e;
717717 spr ctx ")";
718 | TMeta ((Meta.LoopLabel,[(EConst(Int n),_)],_), e) ->
718 | TMeta ((Meta.LoopLabel,[(EConst(Int (n, _)),_)],_), e) ->
719719 (match e.eexpr with
720720 | TWhile _ | TFor _ ->
721721 print ctx "_hx_loop%s: " n;
13311331
13321332 let p = s_path ctx cl_path in
13331333 let dotp = dot_path cl_path in
1334
13351334 let added_to_hxClasses = ctx.has_resolveClass && not is_abstract_impl in
13361335
1337 if ctx.js_modern || not added_to_hxClasses then
1336 (* Do not add to $hxClasses on same line as declaration to make sure not to trip js debugger *)
1337 (* when it tries to get a string representation of a class. Will be added below *)
1338 if ctx.com.debug || ctx.js_modern || not added_to_hxClasses then
13381339 print ctx "%s = " p
13391340 else
13401341 print ctx "%s = $hxClasses[\"%s\"] = " p dotp;
13411342
1342 process_expose c.cl_meta (fun () -> dotp) (fun s -> print ctx "$hx_exports%s = " (path_to_brackets s));
1343 if not ctx.com.debug then
1344 process_expose c.cl_meta (fun () -> dotp) (fun s -> print ctx "$hx_exports%s = " (path_to_brackets s));
13431345
13441346 if is_abstract_impl then begin
13451347 (* abstract implementations only contain static members and don't need to have constructor functions *)
13531355
13541356 newline ctx;
13551357
1356 if ctx.js_modern && added_to_hxClasses then begin
1358 if (ctx.js_modern || ctx.com.debug) && added_to_hxClasses then begin
13571359 print ctx "$hxClasses[\"%s\"] = %s" dotp p;
13581360 newline ctx;
13591361 end;
1362
1363 if ctx.com.debug then
1364 process_expose c.cl_meta (fun () -> dotp) (fun s -> begin
1365 print ctx "$hx_exports%s = %s" (path_to_brackets s) p;
1366 newline ctx;
1367 end);
13601368
13611369 if not is_abstract_impl then begin
13621370 generate_class___name__ ctx cl_path;
20812089 newline ctx;
20822090 end;
20832091 if has_feature ctx "use.$arrayPush" then begin
2084 print ctx "function $arrayPush(x) { this.push(x); }";
2092 print ctx "function $arrayPush(x) { return this.push(x); }";
20852093 newline ctx
20862094 end;
20872095 if has_feature ctx "$global.$haxeUID" then begin
3939 let is_really_int t =
4040 not (is_nullable t) && ExtType.is_int (follow t)
4141
42 (* Due to @:native, the usual String path doesn't match *)
43 let is_string t = match t with
44 | TInst({cl_path=([],"String") | (["java";"lang"],"String")},_) -> true
45 | _ -> false
46
4247 let get_construction_mode c cf =
4348 if Meta.has Meta.HxGen cf.cf_meta then ConstructInitPlusNew
4449 else ConstructInit
4550
51 class virtual jvm_output = object(self)
52 method virtual add_entry : string -> string -> unit
53 method virtual close : unit
54 end
55
4656 (* Haxe *)
4757
4858 type generation_context = {
4959 com : Common.context;
50 jar : Zip.out_file;
60 out : jvm_output;
5161 t_runtime_exception : Type.t;
5262 entry_point : (tclass * texpr) option;
5363 t_exception : Type.t;
5464 t_throwable : Type.t;
55 mutable anon_identification : jsignature tanon_identification;
65 anon_identification : jsignature tanon_identification;
5666 mutable preprocessor : jsignature preprocessor;
5767 default_export_config : export_config;
5868 typed_functions : JvmFunctions.typed_functions;
6171 detail_times : bool;
6272 mutable timer : Timer.timer;
6373 mutable typedef_interfaces : jsignature typedef_interfaces;
64 mutable current_field_info : field_generation_info option;
6574 jar_compression_level : int;
6675 dynamic_level : int;
6776 }
6877
6978 type ret =
70 | RValue of jsignature option
79 | RValue of jsignature option * string option
7180 | RVoid
7281 | RReturn
7382
97106 gctx.timer <- sub;
98107 sub#run_finally f (fun () -> gctx.timer <- old)
99108 end
109
110 class jar_output
111 (jar_path : string)
112 (compression_level : int)
113 = object(self)
114 inherit jvm_output
115 val jar = Zip.open_out jar_path
116
117 method add_entry (content : string) (name : string) =
118 Zip.add_entry ~level:compression_level content jar name
119
120 method close =
121 Zip.close_out jar
122 end
123
124 class file_output
125 (base_path : string)
126 = object(self)
127 inherit jvm_output
128
129 method add_entry (content : string) (name : string) =
130 let path = base_path ^ name in
131 Path.mkdir_from_path path;
132 let ch = open_out_bin path in
133 output_string ch content;
134 close_out ch
135
136 method close =
137 ()
138 end
100139
101140 open NativeSignatures
102141
128167 | [t] -> TArray(jsignature_of_type t,None)
129168 | _ -> die "" __LOC__
130169 end
131 | ["haxe"],"Rest" -> TArray(object_sig,None)
132170 | [],"Dynamic" ->
133171 object_sig
134172 | [],("Class" | "Enum") ->
156194 TObject((["haxe";"root"],"Array"),[TType(WNone,t)])
157195 | TInst({cl_path = (["java"],"NativeArray")},[t]) ->
158196 TArray(jsignature_of_type t,None)
159 | TInst({cl_kind = KTypeParameter [t]},_) -> jsignature_of_type t
197 | TInst({cl_kind = KTypeParameter [t]},_) when t != t_dynamic -> jsignature_of_type t
160198 | TInst({cl_kind = KTypeParameter _; cl_path = (_,name)},_) -> TTypeParameter name
161199 | TInst({cl_path = ["_Class"],"Class_Impl_"},_) -> java_class_sig
162200 | TInst({cl_path = ["_Enum"],"Enum_Impl_"},_) -> java_class_sig
173211 | TType(td,tl) ->
174212 begin match gctx.typedef_interfaces#get_interface_class td.t_path with
175213 | Some c -> TObject(c.cl_path,[])
176 | None -> jsignature_of_type (apply_params td.t_params tl td.t_type)
214 | None -> jsignature_of_type (apply_typedef td tl)
177215 end
178216 | TLazy f -> jsignature_of_type (lazy_type f)
179217
203241 l
204242
205243 module AnnotationHandler = struct
206 let generate_annotations builder meta =
244 let convert_annotations meta =
207245 let parse_path e =
208 let sl = try string_list_of_expr_path_raise e with Exit -> Error.error "Field expression expected" (pos e) in
246 let sl = try string_list_of_expr_path_raise e with Exit -> Error.typing_error "Field expression expected" (pos e) in
209247 let path = match sl with
210248 | s :: sl -> List.rev sl,s
211 | _ -> Error.error "Field expression expected" (pos e)
249 | _ -> Error.typing_error "Field expression expected" (pos e)
212250 in
213251 path
214252 in
215253 let rec parse_value e = match fst e with
216 | EConst (Int s) -> AInt (Int32.of_string s)
217 | EConst (Float s) -> ADouble (float_of_string s)
254 | EConst (Int (s, _)) -> AInt (Int32.of_string s)
255 | EConst (Float (s, _)) -> ADouble (float_of_string s)
218256 | EConst (String(s,_)) -> AString s
219257 | EConst (Ident "true") -> ABool true
220258 | EConst (Ident "false") -> ABool false
221259 | EArrayDecl el -> AArray (List.map parse_value el)
222 | EField(e1,s) ->
260 | EField(e1,s,_) ->
223261 let path = parse_path e1 in
224262 AEnum(object_path_sig path,s)
225 | _ -> Error.error "Expected value expression" (pos e)
226 in
227 let parse_value_pair e = match fst e with
263 | ECall(e1, el) ->
264 let path = parse_path e1 in
265 let _,name = ExtString.String.replace (snd path) "." "$" in
266 let path = (fst path, name) in
267 let values = List.map parse_value_pair el in
268 AAnnotation(TObject(path, []),values)
269
270 | _ -> Error.typing_error "Expected value expression" (pos e)
271 and parse_value_pair e = match fst e with
228272 | EBinop(OpAssign,(EConst(Ident s),_),e1) ->
229273 s,parse_value e1
230274 | _ ->
231 Error.error "Assignment expression expected" (pos e)
275 Error.typing_error "Assignment expression expected" (pos e)
232276 in
233277 let parse_expr e = match fst e with
234278 | ECall(e1,el) ->
238282 let values = List.map parse_value_pair el in
239283 path,values
240284 | _ ->
241 Error.error "Call expression expected" (pos e)
242 in
243 List.iter (fun (m,el,_) -> match m,el with
285 Error.typing_error "Call expression expected" (pos e)
286 in
287 ExtList.List.filter_map (fun (m,el,_) -> match m,el with
244288 | Meta.Meta,[e] ->
245289 let path,annotation = parse_expr e in
246290 let path = match path with
247291 | [],name -> ["haxe";"root"],name
248292 | _ -> path
249293 in
250 builder#add_annotation path annotation;
294 Some(path,annotation)
251295 | _ ->
252 ()
296 None
253297 ) meta
298
299 let generate_annotations builder meta =
300 List.iter (fun (path,annotation) ->
301 builder#add_annotation path annotation
302 ) (convert_annotations meta)
254303 end
255304
256305 let enum_ctor_sig =
294343 let t = Timer.timer ["jvm";"write"] in
295344 let ch = IO.output_bytes() in
296345 JvmWriter.write_jvm_class ch jc;
297 Zip.add_entry ~level:gctx.jar_compression_level (Bytes.unsafe_to_string (IO.close_out ch)) gctx.jar path;
346 gctx.out#add_entry (Bytes.unsafe_to_string (IO.close_out ch)) path;
298347 t()
299348
300349 let is_const_int_pattern (el,_) =
370419 | _ ->
371420 die "" __LOC__
372421 in
373 let jm_invoke = wf#generate_invoke args ret in
422 let jm_invoke = wf#generate_invoke args ret [] in
374423 let vars = List.map (fun (name,jsig) ->
375424 jm_invoke#add_local name jsig VarArgument
376425 ) args in
416465 [jsig_this]
417466 )
418467
419 let rvalue_any = RValue None
420 let rvalue_sig jsig = RValue (Some jsig)
421 let rvalue_type gctx t = RValue (Some (jsignature_of_type gctx t))
422
423 class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return_type : jsignature option) = object(self)
468 let rvalue_any = RValue(None,None)
469 let rvalue_sig jsig = RValue (Some jsig,None)
470 let rvalue_type gctx t name = RValue (Some (jsignature_of_type gctx t),name)
471
472 class texpr_to_jvm
473 (gctx : generation_context)
474 (field_info : field_generation_info option)
475 (jc : JvmClass.builder)
476 (jm : JvmMethod.builder)
477 (return_type : jsignature option)
478 = object(self)
424479 val com = gctx.com
425480 val code = jm#get_code
426481 val pool : JvmConstantPool.constant_pool = jc#get_pool
490545 jm#cast vt
491546
492547 method cast_expect ret t = match ret with
493 | RValue (Some jsig) -> jm#cast jsig
548 | RValue (Some jsig,_) -> jm#cast jsig
494549 | _ -> self#cast t
495550
496551 method make_static_closure_field (name : string) (jc_closure : JvmClass.builder) =
499554 jm_init#construct ConstructInit jc_closure#get_this_path (fun () -> []);
500555 jm_init#putstatic jc_closure#get_this_path jf_closure#get_name jf_closure#get_jsig;
501556
502 method tfunction e tf =
557 method tfunction ret e tf =
503558 let outside,accesses_this = Texpr.collect_captured_vars e in
504559 let env = List.map (fun v ->
505560 v.v_id,(v.v_name,self#vtype v.v_type)
506561 ) outside in
507562 let env = if accesses_this then ((0,("this",jc#get_jsig)) :: env) else env in
508563 let context = List.map snd env in
509 let wf = new JvmFunctions.typed_function gctx.typed_functions FuncLocal jc jm context in
564 let name = match ret with
565 | RValue(_,Some s) -> Some s
566 | _ -> None
567 in
568 let wf = new JvmFunctions.typed_function gctx.typed_functions (FuncLocal name) jc jm context in
510569 let jc_closure = wf#get_class in
511570 ignore(wf#generate_constructor (env <> []));
571 let filter = match ret with
572 | RValue (Some (TObject(path,_)),_) -> [path]
573 | _ -> []
574 in
512575 let args,ret =
513576 let args = List.map (fun (v,eo) ->
514577 (* TODO: Can we do this differently? *)
517580 ) tf.tf_args in
518581 args,(return_of_type gctx tf.tf_type)
519582 in
520 let jm_invoke = wf#generate_invoke args ret in
521 let handler = new texpr_to_jvm gctx jc_closure jm_invoke ret in
583 let jm_invoke = wf#generate_invoke args ret filter in
584 let handler = new texpr_to_jvm gctx field_info jc_closure jm_invoke ret in
522585 handler#set_env env;
523586 let args = List.map (fun (v,eo) ->
524587 handler#add_local v VarArgument,v,eo
594657 let wf = new JvmFunctions.typed_function gctx.typed_functions (FuncStatic(path,name)) jc jm [] in
595658 let jc_closure = wf#get_class in
596659 ignore(wf#generate_constructor false);
597 let jm_invoke = wf#generate_invoke args ret in
660 let jm_invoke = wf#generate_invoke args ret [] in
598661 let vars = List.map (fun (name,jsig) ->
599662 jm_invoke#add_local name jsig VarArgument
600663 ) args in
9441007
9451008 method do_compare op =
9461009 match code#get_stack#get_stack_items 2 with
947 | [TInt | TByte | TChar | TBool;TInt | TByte | TChar | TBool] ->
1010 | [TInt | TByte | TChar | TShort | TBool;TInt | TByte | TChar | TShort | TBool] ->
9481011 let op = flip_cmp_op op in
9491012 CmpSpecial (code#if_icmp op)
9501013 | [TObject((["java";"lang"],"String"),[]);TObject((["java";"lang"],"String"),[])] ->
12891352 self#boolop (self#binop_compare op e1 e2)
12901353 | OpAssign,_ ->
12911354 let f () =
1292 self#texpr (rvalue_type gctx e1.etype) e2;
1355 self#texpr (rvalue_type gctx e1.etype None) e2;
12931356 self#cast e1.etype;
12941357 in
12951358 self#read_write ret AKNone e1 f
13341397 | TDouble ->
13351398 code#dconst 1.;
13361399 if op = Increment then code#dadd else code#dsub
1400 | TFloat ->
1401 code#fconst 1.;
1402 if op = Increment then code#fadd else code#fsub
13371403 | TByte | TShort | TInt ->
13381404 code#iconst Int32.one;
13391405 if op = Increment then code#iadd else code#isub;
13501416 begin match jsig with
13511417 | TLong -> code#lneg;
13521418 | TDouble -> code#dneg;
1419 | TFloat -> code#fneg;
13531420 | TByte | TShort | TInt -> code#ineg;
13541421 | _ -> jm#invokestatic haxe_jvm_path "opNeg" (method_sig [object_sig] (Some object_sig))
13551422 end;
13601427 (fun () -> code#bconst false)
13611428 (fun () -> code#bconst true)
13621429 | Spread, _ ->
1363 self#texpr (rvalue_type gctx e.etype) e
1430 self#texpr (rvalue_type gctx e.etype None) e
13641431 | NegBits,_ ->
13651432 let jsig = jsignature_of_type gctx (follow e.etype) in
13661433 self#texpr rvalue_any e;
13951462 | TUnop (Spread,_,e) ->
13961463 self#texpr (rvalue_sig jsig) e
13971464 | _ ->
1398 self#new_native_array (get_boxed_type (jsignature_of_type gctx t1)) (e :: el)
1465 self#new_native_array (jsignature_of_type gctx t1) (e :: el)
13991466 );
14001467 List.rev (jsig :: acc)
14011468 | _ ->
14121479 (match Type.follow t with
14131480 | TAbstract({a_path = ["haxe"],"Rest"},[t1]) ->
14141481 let jsig = jsignature_of_type gctx t in
1415 self#new_native_array (get_boxed_type (jsignature_of_type gctx t1)) [];
1482 self#new_native_array (jsignature_of_type gctx t1) [];
14161483 List.rev (jsig :: acc)
14171484 | _ -> List.rev acc)
14181485 | _,[] -> List.rev acc
14481515 self#expect_reference_type;
14491516 let path = match jsignature_of_type gctx (type_of_module_type mt) with
14501517 | TObject(path,_) -> path
1451 | _ -> Error.error "Class expected" pe
1518 | _ -> Error.typing_error "Class expected" pe
14521519 in
14531520 code#instanceof path;
14541521 Some TBool
1455 | _ -> Error.error "Type expression expected" e1.epos
1522 | _ -> Error.typing_error "Type expression expected" e1.epos
14561523 end;
14571524 | TField(_,FStatic({cl_path = (["java";"lang"],"Math")},{cf_name = ("isNaN" | "isFinite") as name})) ->
14581525 begin match el with
15111578 self#new_native_array jsig el;
15121579 Some (array_sig jsig)
15131580 | _ ->
1514 Error.error (Printf.sprintf "Bad __array__ type: %s" (s_type (print_context()) tr)) e1.epos;
1581 Error.typing_error (Printf.sprintf "Bad __array__ type: %s" (s_type (print_context()) tr)) e1.epos;
1582 end
1583 | TField(_,FStatic({cl_path = (["haxe"],"EnumTools")}, {cf_name = "values"})) ->
1584 begin match el with
1585 | [e1] ->
1586 let jsig_ret = array_sig (object_path_sig object_path) in
1587 let meth = gctx.typed_functions#register_signature [] (Some jsig_ret) in
1588 let jsig_meth = (method_sig meth.dargs meth.dret) in
1589 self#read (fun () -> jm#cast jsig_meth) e1 (FDynamic "values");
1590 jm#invokevirtual haxe_function_path meth.name jsig_meth;
1591 Some jsig_ret
1592 | _ ->
1593 die "" __LOC__
15151594 end
15161595 | TField(e1,FStatic(c,({cf_kind = Method (MethNormal | MethInline)} as cf))) ->
15171596 let tl,tr = self#call_arguments cf.cf_type el in
15791658 invoke e1.etype
15801659 end
15811660 | TConst TSuper ->
1582 let c,cf = match gctx.current_field_info with
1661 let c,cf = match field_info with
15831662 | Some ({super_call_fields = hd :: tl} as info) ->
15841663 info.super_call_fields <- tl;
15851664 hd
15861665 | _ ->
1587 Error.error "Something went wrong" e1.epos
1666 Error.typing_error "Something went wrong" e1.epos
15881667 in
15891668 let kind = get_construction_mode c cf in
15901669 begin match kind with
16501729 end
16511730 | _ ->
16521731 self#texpr rvalue_any e1;
1653 invoke e1.etype;
1732 let t = match e1.eexpr with
1733 | TLocal ({v_extra = Some {v_params = l}} as v) when l <> [] ->
1734 (* If we call a local variable with type parameters, we want to use the general (unapplied)
1735 type, which is the variable type itself. This is necessary for some special situations
1736 like the Rest<T> case in issue #10906. *)
1737 v.v_type
1738 | _ ->
1739 e1.etype
1740 in
1741 invoke t;
16541742 in
16551743 match need_val ret,tro with
16561744 | false,Some _ -> code#pop
17281816 method const ret t ct = match ct with
17291817 | Type.TInt i32 ->
17301818 begin match ret with
1731 | RValue (Some (TLong | TObject((["java";"lang"],"Long"),_))) -> code#lconst (Int64.of_int32 i32)
1732 | RValue (Some (TDouble | TObject((["java";"lang"],"Double"),_))) -> code#dconst (Int32.to_float i32)
1819 | RValue (Some (TLong | TObject((["java";"lang"],"Long"),_)),_) -> code#lconst (Int64.of_int32 i32)
1820 | RValue (Some (TDouble | TObject((["java";"lang"],"Double"),_)),_) -> code#dconst (Int32.to_float i32)
17331821 | _ -> code#iconst i32
17341822 end
17351823 | TFloat f ->
17361824 begin match ret with
1737 | RValue (Some (TFloat | TObject((["java";"lang"],"Float"),_))) -> code#fconst (float_of_string f)
1825 | RValue (Some (TFloat | TObject((["java";"lang"],"Float"),_)),_) -> code#fconst (float_of_string f)
17381826 | _ -> code#dconst (float_of_string f)
17391827 end
17401828 | TBool true -> code#bconst true
17661854 code#set_line (Lexer.get_error_line e.epos);
17671855 match e.eexpr with
17681856 | TVar(v,Some e1) ->
1769 self#texpr (rvalue_type gctx v.v_type) e1;
1857 self#texpr (rvalue_type gctx v.v_type (Some v.v_name)) e1;
17701858 self#cast v.v_type;
17711859 let _,_,store = self#add_local v VarWillInit in
17721860 store()
17861874 | Not | Neg | NegBits when not (need_val ret) -> self#texpr ret e1
17871875 | _ -> self#unop ret op flag e1
17881876 end
1789 | TBinop(OpAdd,e1,e2) when ExtType.is_string (follow e.etype) ->
1877 | TBinop(OpAdd,e1,e2) when is_string (follow e.etype) ->
17901878 let string_builder_path = (["java";"lang"],"StringBuilder") in
17911879 let string_builder_sig = object_path_sig string_builder_path in
17921880 jm#construct ConstructInit string_builder_path (fun () -> []);
17931881 let rec loop e = match e.eexpr with
1794 | TBinop(OpAdd,e1,e2) when ExtType.is_string (follow e.etype) ->
1882 | TBinop(OpAdd,e1,e2) when is_string (follow e.etype) ->
17951883 loop e1;
17961884 loop e2;
17971885 | _ ->
18411929 )
18421930 | TSwitch(e1,cases,def) ->
18431931 self#switch ret e1 cases def
1844 | TWhile(e1,e2,flag) -> (* TODO: do-while *)
1932 | TWhile(e1,e2,flag) ->
18451933 block_exits <- ExitLoop :: block_exits;
18461934 let is_true_loop = match (Texpr.skip e1).eexpr with TConst (TBool true) -> true | _ -> false in
18471935 let continue_label = jm#spawn_label "continue" in
18481936 let break_label = jm#spawn_label "break" in
18491937 let body_label = jm#spawn_label "body" in
1938 let restore = jm#start_branch in
1939 if flag = DoWhile then begin
1940 body_label#goto;
1941 restore();
1942 end;
18501943 let old_continue = continue in
18511944 continue <- Some continue_label;
18521945 let old_break = break in
18531946 break <- Some break_label;
18541947 continue_label#here;
1855 let restore = jm#start_branch in
18561948 if not is_true_loop then self#condition false e1 body_label break_label;
18571949 let pop_scope = jm#push_scope in
18581950 body_label#here;
19021994 )
19031995 | TNew(c,tl,el) ->
19041996 begin match OverloadResolution.maybe_resolve_constructor_overload c tl el with
1905 | None -> Error.error "Could not find overload" e.epos
1997 | None -> Error.typing_error "Could not find overload" e.epos
19061998 | Some (c',cf,_) ->
19071999 let f () =
19082000 let tl,_ = self#call_arguments cf.cf_type el in
19152007 jm#return;
19162008 | TReturn (Some e1) ->
19172009 self#texpr rvalue_any e1;
1918 let jsig = Option.get return_type in
1919 jm#cast jsig;
1920 self#emit_block_exits false;
1921 jm#return;
2010 if not (jm#is_terminated) then begin
2011 let jsig = Option.get return_type in
2012 jm#cast jsig;
2013 self#emit_block_exits false;
2014 jm#return;
2015 end
19222016 | TFunction tf ->
1923 self#tfunction e tf
2017 self#tfunction ret e tf
19242018 | TArrayDecl el when not (need_val ret) ->
19252019 List.iter (self#texpr ret) el
19262020 | TArrayDecl el ->
20032097 self#cast e.etype;
20042098 | TThrow e1 ->
20052099 self#texpr rvalue_any e1;
2006 if not (Exceptions.is_haxe_exception e1.etype) && not (does_unify e1.etype gctx.t_runtime_exception) then begin
2007 let exc = new haxe_exception gctx e1.etype in
2008 if not (List.exists (fun exc' -> exc#is_assignable_to exc') caught_exceptions) then
2009 jm#add_thrown_exception exc#get_native_path;
2010 end;
2011 code#athrow;
2012 jm#set_terminated true
2100 (* There could be something like `throw throw`, so we should only throw if we aren't terminated (issue #10363) *)
2101 if not (jm#is_terminated) then begin
2102 if not (Exceptions.is_haxe_exception e1.etype) && not (does_unify e1.etype gctx.t_runtime_exception) then begin
2103 let exc = new haxe_exception gctx e1.etype in
2104 if not (List.exists (fun exc' -> exc#is_assignable_to exc') caught_exceptions) then
2105 jm#add_thrown_exception exc#get_native_path;
2106 end;
2107 code#athrow;
2108 jm#set_terminated true
2109 end
20132110 | TObjectDecl fl ->
2014 let td = gctx.anon_identification#identify true e.etype in
2015 begin match follow e.etype,td with
2016 (* The guard is here because in the case of quoted fields like `"a-b"`, the field is not part of the
2017 type. In this case we have to do full dynamic construction. *)
2018 | TAnon an,Some pfm when List.for_all (fun ((name,_,_),_) -> PMap.mem name an.a_fields) fl ->
2019 let fl' = convert_fields gctx pfm in
2111 let had_invalid_field_name = ref false in
2112 (* We cannot rely on e.etype because it might have optional field shit, so we need to build a concrete type from the fields... *)
2113 let fields = List.fold_left (fun acc ((name,_,_),e) ->
2114 let cf = mk_field name e.etype e.epos e.epos in
2115 if not (Lexer.is_valid_identifier name) then had_invalid_field_name := true;
2116 PMap.add name cf acc
2117 ) PMap.empty fl in
2118 let t = mk_anon ~fields (ref Closed) in
2119 let td = gctx.anon_identification#identify true t in
2120 begin match td with
2121 | Some pfm when not !had_invalid_field_name ->
2122 let lut = Hashtbl.create 0 in
20202123 jm#construct ConstructInit pfm.pfm_path (fun () ->
2021 (* We have to respect declaration order, so let's temp var where necessary *)
2022 let rec loop fl fl' ok acc = match fl,fl' with
2023 | ((name,_,_),e) :: fl,(name',jsig) :: fl' ->
2024 if ok && name = name' then begin
2124 (* Step 1: Expressions in order with temp vars *)
2125 let rec loop fl = match fl with
2126 | ((name,_,_),e) :: fl ->
2127 let jsig = self#vtype e.etype in
2128 let load = match (Texpr.skip e).eexpr with
2129 | TConst _ | TTypeExpr _ | TFunction _ ->
2130 (fun () -> self#texpr rvalue_any e)
2131 | _ ->
2132 let _,load,save = jm#add_local (Printf.sprintf "_hx_tmp_%s" name) jsig VarWillInit in
20252133 self#texpr rvalue_any e;
2026 jm#cast jsig;
2027 loop fl fl' ok acc
2028 end else begin
2029 let load = match (Texpr.skip e).eexpr with
2030 | TConst _ | TTypeExpr _ | TFunction _ ->
2031 (fun () -> self#texpr rvalue_any e)
2032 | _ ->
2033 let _,load,save = jm#add_local (Printf.sprintf "_hx_tmp_%s" name) (self#vtype e.etype) VarWillInit in
2034 self#texpr rvalue_any e;
2035 save();
2036 load
2037 in
2038 loop fl fl' false ((name,load) :: acc)
2039 end
2040 | [],[] ->
2041 acc
2042 | (_,e) :: fl,[] ->
2043 self#texpr RVoid e;
2044 loop fl fl' ok acc
2045 | [],(_,jsig) :: fl' ->
2046 jm#load_default_value jsig;
2047 loop [] fl' ok acc
2134 save();
2135 load
2136 in
2137 Hashtbl.add lut name load;
2138 loop fl;
2139 | [] ->
2140 ()
20482141 in
2049 let vars = loop fl fl' true [] in
2050 let vars = List.sort (fun (name1,_) (name2,_) -> compare name1 name2) vars in
2051 List.iter (fun (name,load) ->
2142 loop fl;
2143 (* Step 2: Fields in order of constructor arguments *)
2144 let order = List.sort (fun ((name1,_,_),_) ((name2,_,_),_) -> compare name1 name2) fl in
2145 List.map (fun ((name,_,_),_) ->
2146 let load = Hashtbl.find lut name in
20522147 load();
2053 if List.mem_assoc name fl' then jm#cast (List.assoc name fl')
2054 ) vars;
2055 List.map snd fl';
2148 let cf = PMap.find name pfm.pfm_fields in
2149 let jsig = self#vtype cf.cf_type in
2150 jm#cast jsig;
2151 jsig
2152 ) order;
20562153 )
20572154 | _ ->
20582155 jm#construct ConstructInit haxe_dynamic_object_path (fun () -> []);
20652162 ) fl;
20662163 end
20672164 | TIdent _ ->
2068 Error.error (s_expr_ast false "" (s_type (print_context())) e) e.epos;
2165 Error.typing_error (s_expr_ast false "" (s_type (print_context())) e) e.epos;
20692166
20702167 (* api *)
20712168
22372334 | None ->
22382335 ()
22392336 end else begin
2240 let _,_,cf_super = raw_class_field (fun cf -> cf.cf_type) c_sup (List.map snd c_sup.cl_params) cf.cf_name in
2337 let _,_,cf_super = raw_class_field (fun cf -> cf.cf_type) c_sup (extract_param_types c_sup.cl_params) cf.cf_name in
22412338 compare_fields cf cf_super
22422339 end
22432340 in
22782375 let _,load,_ = jm_empty_ctor#add_local "_" haxe_empty_constructor_sig VarArgument in
22792376 jm_empty_ctor#load_this;
22802377 if c.cl_constructor = None then begin
2281 let handler = new texpr_to_jvm gctx jc jm_empty_ctor None in
2378 let handler = new texpr_to_jvm gctx None jc jm_empty_ctor None in
22822379 DynArray.iter (fun e ->
22832380 handler#texpr RVoid e;
22842381 ) field_inits;
22932390 jm_empty_ctor#call_super_ctor ConstructInit jsig_empty
22942391 end;
22952392 if c.cl_constructor = None then begin
2296 let handler = new texpr_to_jvm gctx jc jm_empty_ctor None in
2393 let handler = new texpr_to_jvm gctx None jc jm_empty_ctor None in
22972394 DynArray.iter (fun e ->
22982395 handler#texpr RVoid e;
22992396 ) delayed_field_inits;
23062403 PMap.iter (fun _ (c,cf) ->
23072404 let cmode = get_construction_mode c cf in
23082405 let jm = jc#spawn_method (if cmode = ConstructInit then "<init>" else "new") (jsignature_of_type gctx cf.cf_type) [MPublic] in
2309 let handler = new texpr_to_jvm gctx jc jm None in
2406 let handler = new texpr_to_jvm gctx None jc jm None in
23102407 jm#load_this;
23112408 DynArray.iter (fun e ->
23122409 handler#texpr RVoid e;
23252422 with Not_found ->
23262423 ()
23272424
2328 method generate_expr gctx jc jm e is_method scmode mtype =
2425 method generate_expr gctx field_info jc jm e scmode mtype =
23292426 let e,args,tr = match e.eexpr with
2330 | TFunction tf when is_method ->
2427 | TFunction tf ->
23312428 tf.tf_expr,tf.tf_args,(return_of_type gctx tf.tf_type)
23322429 | _ ->
23332430 e,[],None
23342431 in
2335 let handler = new texpr_to_jvm gctx jc jm tr in
2432 let handler = new texpr_to_jvm gctx field_info jc jm tr in
23362433 List.iter (fun (v,_) ->
2337 ignore(handler#add_local v VarArgument);
2434 let slot,_,_ = handler#add_local v VarArgument in
2435 let annot = AnnotationHandler.convert_annotations v.v_meta in
2436 match annot with
2437 | [] ->
2438 ()
2439 | _ ->
2440 jm#add_argument_annotation slot annot;
23382441 ) args;
23392442 jm#finalize_arguments;
23402443 begin match mtype with
23612464 handler#texpr RReturn e
23622465
23632466 method generate_method gctx jc c mtype cf =
2364 gctx.current_field_info <- gctx.preprocessor#get_field_info cf.cf_meta;
23652467 let jsig = jsignature_of_type gctx cf.cf_type in
23662468 let flags = if Meta.has Meta.Private cf.cf_meta then [MPrivate] else if Meta.has Meta.Protected cf.cf_meta then [MProtected] else [MPublic] in
23672469 let flags = if (has_class_flag c CInterface) then MAbstract :: flags else flags in
23852487 begin match cf.cf_expr with
23862488 | None -> ()
23872489 | Some e ->
2388 self#generate_expr gctx jc jm e true scmode mtype;
2490 let field_info = gctx.preprocessor#get_field_info cf.cf_meta in
2491 self#generate_expr gctx field_info jc jm e scmode mtype;
23892492 end;
23902493 begin match cf.cf_params with
23912494 | [] when c.cl_params = [] ->
23922495 ()
23932496 | _ ->
2394 let stl = String.concat "" (List.map (fun (n,_) ->
2395 Printf.sprintf "%s:Ljava/lang/Object;" n
2497 let stl = String.concat "" (List.map (fun tp ->
2498 Printf.sprintf "%s:Ljava/lang/Object;" tp.ttp_name
23962499 ) cf.cf_params) in
23972500 let ssig = generate_method_signature true (jsignature_of_type gctx cf.cf_type) in
23982501 let s = if cf.cf_params = [] then ssig else Printf.sprintf "<%s>%s" stl ssig in
24062509 let flags = if Meta.has Meta.Private cf.cf_meta then [FdPrivate] else if Meta.has Meta.Protected cf.cf_meta then [FdProtected] else [FdPublic] in
24072510 let flags = if mtype = MStatic then FdStatic :: flags else flags in
24082511 let flags = if Meta.has Meta.JvmSynthetic cf.cf_meta then FdSynthetic :: flags else flags in
2512 let flags = if Meta.has Meta.Volatile cf.cf_meta then FdVolatile :: flags else flags in
24092513 let jm = jc#spawn_field cf.cf_name jsig flags in
24102514 let default e =
24112515 let p = null_pos in
24262530 default e;
24272531 end;
24282532 | Some e when mtype <> MStatic ->
2429 let tl = List.map snd c.cl_params in
2533 let tl = extract_param_types c.cl_params in
24302534 let ethis = mk (TConst TThis) (TInst(c,tl)) null_pos in
24312535 let efield = mk (TField(ethis,FInstance(c,tl,cf))) cf.cf_type null_pos in
24322536 let eop = mk (TBinop(OpAssign,efield,e)) cf.cf_type null_pos in
24472551 | _ ->
24482552 default e;
24492553 end;
2450 let ssig = generate_signature true (jsignature_of_type gctx cf.cf_type) in
2451 let offset = jc#get_pool#add_string ssig in
2452 jm#add_attribute (AttributeSignature offset)
2554 let jsig = jsignature_of_type gctx cf.cf_type in
2555 (* see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.4 *)
2556 begin match jsig with
2557 | TObject _ | TArray _ | TTypeParameter _ ->
2558 let ssig = generate_signature true jsig in
2559 let offset = jc#get_pool#add_string ssig in
2560 jm#add_attribute (AttributeSignature offset);
2561 | _ ->
2562 ()
2563 end;
2564 AnnotationHandler.generate_annotations (jm :> JvmBuilder.base_builder) cf.cf_meta;
24532565
24542566 method generate_main e =
24552567 let jsig = method_sig [array_sig string_sig] None in
24602572 jm#putstatic (["haxe";"root"],"Sys") "_args" (TArray(string_sig,None))
24612573 end;
24622574 jm#invokestatic (["haxe"; "java"], "Init") "init" (method_sig [] None);
2463 self#generate_expr gctx jc jm e true SCNone MStatic;
2575 self#generate_expr gctx None jc jm e SCNone MStatic;
24642576 if not jm#is_terminated then jm#return
24652577
24662578 method private generate_fields =
24672579 let field mtype cf = match cf.cf_kind with
24682580 | Method (MethNormal | MethInline) ->
24692581 List.iter (fun cf ->
2470 self#generate_method gctx jc c mtype cf
2582 if not (has_class_field_flag cf CfExtern) then self#generate_method gctx jc c mtype cf
24712583 ) (cf :: List.filter (fun cf -> has_class_field_flag cf CfOverload) cf.cf_overloads)
24722584 | _ ->
24732585 if not (has_class_flag c CInterface) && is_physical_field cf then self#generate_field gctx jc c mtype cf
24882600 ()
24892601 | Some e ->
24902602 let jm = jc#get_static_init_method in
2491 let handler = new texpr_to_jvm gctx jc jm None in
2603 let handler = new texpr_to_jvm gctx None jc jm None in
24922604 handler#texpr RReturn (mk_block e);
24932605 end
24942606
24952607 method private generate_signature =
2496 jc#set_type_parameters (List.map (fun (n,t) ->
2497 let jsigs = match follow t with
2608 jc#set_type_parameters (List.map (fun tp ->
2609 let jsigs = match follow tp.ttp_type with
24982610 | TInst({cl_kind = KTypeParameter tl},_) ->
24992611 List.map (fun t ->
25002612 get_boxed_type (jsignature_of_type gctx t)
25022614 | _ ->
25032615 []
25042616 in
2505 (n,jsigs)
2617 (tp.ttp_name,jsigs)
25062618 ) c.cl_params);
25072619 match c.cl_super with
25082620 | Some(c,tl) -> jc#set_super_parameters (List.map (jtype_argument_of_type gctx []) tl)
25402652 let generate_enum_equals gctx (jc_ctor : JvmClass.builder) =
25412653 let jm_equals,load = generate_equals_function jc_ctor (haxe_enum_sig object_sig) in
25422654 let code = jm_equals#get_code in
2543 let jm_equals_handler = new texpr_to_jvm gctx jc_ctor jm_equals (Some TBool) in
2655 let jm_equals_handler = new texpr_to_jvm gctx None jc_ctor jm_equals (Some TBool) in
25442656 let is_haxe_enum jsig = match jsig with
25452657 | TObject(path,_) ->
25462658 Hashtbl.mem gctx.enum_paths path
26942806 ()
26952807 | Some e ->
26962808 ignore(jc_enum#spawn_field "__meta__" object_sig [FdStatic;FdPublic]);
2697 let handler = new texpr_to_jvm gctx jc_enum jm_clinit None in
2809 let handler = new texpr_to_jvm gctx None jc_enum jm_clinit None in
26982810 handler#texpr rvalue_any e;
26992811 jm_clinit#putstatic jc_enum#get_this_path "__meta__" object_sig
27002812 end;
28052917 end else if fst mt.mt_path = [] then
28062918 mt.mt_path <- make_root mt.mt_path
28072919
2920 let check_single_method_interface gctx c =
2921 let rec loop m l = match l with
2922 | [] ->
2923 m
2924 | cf :: l ->
2925 if not (has_class_field_flag cf CfDefault) then begin match m with
2926 | None ->
2927 loop (Some cf) l
2928 | Some _ ->
2929 None
2930 end else
2931 loop m l
2932 in
2933 match loop None c.cl_ordered_fields with
2934 | None ->
2935 ()
2936 | Some cf ->
2937 match jsignature_of_type gctx cf.cf_type with
2938 | TMethod(args,ret) ->
2939 JvmFunctions.JavaFunctionalInterfaces.add args ret c.cl_path cf.cf_name (List.map extract_param_name (c.cl_params @ cf.cf_params));
2940 | _ ->
2941 ()
2942
28082943 let preprocess gctx =
28092944 let rec has_runtime_meta = function
28102945 | (Meta.Custom s,_,_) :: _ when String.length s > 0 && s.[0] <> ':' ->
28342969 match mt with
28352970 | TClassDecl c ->
28362971 if not (has_class_flag c CInterface) then gctx.preprocessor#preprocess_class c
2972 else check_single_method_interface gctx c;
28372973 | _ -> ()
28382974 ) gctx.com.types;
28392975 (* find typedef-interface implementations *)
28512987 | Some (jarname,cl,expr) -> jarname, Some (cl,expr)
28522988 | None -> "jar",None
28532989 in
2854 let jar_dir,jar_path = if jvm_flag then begin
2855 match path.file_name with
2856 | Some _ ->
2857 begin match path.directory with
2858 | None ->
2859 "./","./" ^ com.file
2860 | Some dir ->
2861 mkdir_from_path dir;
2862 add_trailing_slash dir,com.file
2863 end
2864 | None ->
2865 failwith "Please specify an output file name"
2866 end else begin
2867 let jar_name = if com.debug then jar_name ^ "-Debug" else jar_name in
2868 let jar_dir = add_trailing_slash com.file in
2869 let jar_path = Printf.sprintf "%s%s.jar" jar_dir jar_name in
2870 jar_dir,jar_path
2871 end in
2872 let anon_identification = new tanon_identification haxe_dynamic_object_path in
28732990 let compression_level = try
28742991 int_of_string (Define.defined_value com.defines Define.JvmCompressionLevel)
28752992 with _ ->
28762993 6
28772994 in
28782995 if compression_level < 0 || compression_level > 9 then failwith "Invalid value for -D jvm.compression-level: Must be >=0 and <= 9";
2996 let create_jar path =
2997 new jar_output path compression_level
2998 in
2999 let out_dir,out = if jvm_flag then begin
3000 match path.file_name with
3001 | Some _ ->
3002 begin match path.directory with
3003 | None ->
3004 "./",create_jar ("./" ^ com.file)
3005 | Some dir ->
3006 mkdir_from_path dir;
3007 add_trailing_slash dir,create_jar com.file
3008 end
3009 | None -> match path.directory with
3010 | Some dir ->
3011 let dir = add_trailing_slash dir in
3012 dir,new file_output dir
3013 | None ->
3014 failwith "Please specify an output file name"
3015 end else begin
3016 let jar_name = if com.debug then jar_name ^ "-Debug" else jar_name in
3017 let jar_dir = add_trailing_slash com.file in
3018 let jar_path = Printf.sprintf "%s%s.jar" jar_dir jar_name in
3019 jar_dir,create_jar jar_path
3020 end in
3021 let anon_identification = new tanon_identification haxe_dynamic_object_path in
28793022 let dynamic_level = try
28803023 int_of_string (Define.defined_value com.defines Define.JvmDynamicLevel)
28813024 with _ ->
28843027 if dynamic_level < 0 || dynamic_level > 2 then failwith "Invalid value for -D jvm.dynamic-level: Must be >=0 and <= 2";
28853028 let gctx = {
28863029 com = com;
2887 jar = Zip.open_out jar_path;
3030 out = out;
28883031 t_runtime_exception = TInst(resolve_class com (["java";"lang"],"RuntimeException"),[]);
28893032 entry_point = entry_point;
28903033 t_exception = TInst(resolve_class com (["java";"lang"],"Exception"),[]);
28953038 typed_functions = new JvmFunctions.typed_functions;
28963039 closure_paths = Hashtbl.create 0;
28973040 enum_paths = Hashtbl.create 0;
2898 current_field_info = None;
28993041 default_export_config = {
29003042 export_debug = true;
29013043 };
2902 detail_times = Common.Define.raw_defined com.defines "jvm-times";
3044 detail_times = Common.raw_defined com "jvm_times";
29033045 timer = new Timer.timer ["generate";"java"];
29043046 jar_compression_level = compression_level;
29053047 dynamic_level = dynamic_level;
29063048 } in
2907 gctx.anon_identification <- anon_identification;
29083049 gctx.preprocessor <- new preprocessor com.basic (jsignature_of_type gctx);
29093050 gctx.typedef_interfaces <- new typedef_interfaces gctx.preprocessor#get_infos anon_identification;
29103051 gctx.typedef_interfaces#add_interface_rewrite (["haxe";"root"],"Iterator") (["java";"util"],"Iterator") true;
29113052 let class_paths = ExtList.List.filter_map (fun java_lib ->
29123053 if java_lib#has_flag NativeLibraries.FlagIsStd || java_lib#has_flag FlagIsExtern then None
29133054 else begin
2914 let dir = Printf.sprintf "%slib/" jar_dir in
3055 let dir = Printf.sprintf "%slib/" out_dir in
29153056 Path.mkdir_from_path dir;
29163057 let name = FilePath.name_and_extension (FilePath.parse java_lib#get_file_path) in
29173058 let ch_in = open_in_bin java_lib#get_file_path in
29253066 ) com.native_libs.java_libs in
29263067 Hashtbl.iter (fun name v ->
29273068 let filename = Codegen.escape_res_name name true in
2928 Zip.add_entry ~level:gctx.jar_compression_level v gctx.jar filename;
3069 gctx.out#add_entry v filename;
29293070 ) com.resources;
29303071 let generate_real_types () =
29313072 List.iter (generate_module_type gctx) com.types;
29463087 (match class_paths with [] -> "" | _ -> "\nClass-Path: " ^ (String.concat " " class_paths)) ^
29473088 "\n\n"
29483089 in
2949 Zip.add_entry ~level:gctx.jar_compression_level manifest_content gctx.jar "META-INF/MANIFEST.MF";
2950
2951 Zip.close_out gctx.jar
3090 gctx.out#add_entry manifest_content "META-INF/MANIFEST.MF";
3091 gctx.out#close;
5555 mutable os_fields : object_store list;
5656 }
5757
58 let replace_float_separators s = Texpr.replace_separators s ""
5859
5960 let debug_expression expression =
6061 " --[[ " ^ Type.s_expr_kind expression ^ " --]] "
7576 (match args with
7677 | [ EConst (String(s,_)), _ ] -> [s]
7778 | [] -> [path]
78 | _ -> error "Invalid @:expose parameters" pos)
79 | _ -> typing_error "Invalid @:expose parameters" pos)
7980 with Not_found -> []
8081
8182 let dot_path = Globals.s_type_path
157158 newline ctx
158159 end)
159160
160 let unsupported p = error "This expression cannot be compiled to Lua" p
161 let unsupported p = typing_error "This expression cannot be compiled to Lua" p
161162
162163 let basename path =
163164 try
220221
221222 let is_dot_access e cf =
222223 match follow(e.etype), cf with
223 | TInst (c,_), FInstance(_,_,icf) when (Meta.has Meta.LuaDotMethod c.cl_meta || Meta.has Meta.LuaDotMethod icf.cf_meta)->
224 true;
224 | TInst (c, _), FInstance(_, _, icf) -> (match icf.cf_kind with
225 | Var _ ->
226 true
227 | Method _ when Meta.has Meta.LuaDotMethod c.cl_meta ->
228 true
229 | Method _ when Meta.has Meta.LuaDotMethod icf.cf_meta ->
230 true
231 | Method _ ->
232 false)
225233 | _ ->
226234 false
227235
323331
324332 let gen_constant ctx p = function
325333 | TInt i -> print ctx "%ld" i
326 | TFloat s -> spr ctx s
334 | TFloat s -> spr ctx (replace_float_separators s)
327335 | TString s -> begin
328336 add_feature ctx "use.string";
329337 print ctx "\"%s\"" (s_escape_lua s)
343351
344352 and gen_argument ?(reflect=false) ctx e = begin
345353 match e.eexpr with
346 | TField (x,((FInstance (_,_,f)| FAnon(f) | FClosure(_,f)))) when (is_function_type e.etype) ->
354 | TField (x, ((FInstance (_, _, f) | FAnon(f) | FClosure(_,f)) as i)) when ((is_function_type e.etype) && (not(is_dot_access x i))) ->
347355 (
348356 if reflect then (
349357 add_feature ctx "use._hx_funcToField";
375383 (match e.eexpr , el with
376384 | TConst TSuper , params ->
377385 (match ctx.current.cl_super with
378 | None -> error "Missing api.setCurrentClass" e.epos
386 | None -> typing_error "Missing api.setCurrentClass" e.epos
379387 | Some (c,_) ->
380388 print ctx "%s.super(%s" (ctx.type_accessor (TClassDecl c)) (this ctx);
381389 List.iter (fun p -> print ctx ","; gen_argument ctx p) params;
383391 );
384392 | TField ({ eexpr = TConst TSuper },f) , params ->
385393 (match ctx.current.cl_super with
386 | None -> error "Missing api.setCurrentClass" e.epos
394 | None -> typing_error "Missing api.setCurrentClass" e.epos
387395 | Some (c,_) ->
388396 let name = field_name f in
389397 print ctx "%s.prototype%s(%s" (ctx.type_accessor (TClassDecl c)) (field name) (this ctx);
436444 if List.length(fields) > 0 then incr count;
437445 | { eexpr = TConst(TNull)} -> ()
438446 | _ ->
439 error "__lua_table__ only accepts array or anonymous object arguments" e.epos;
447 typing_error "__lua_table__ only accepts array or anonymous object arguments" e.epos;
440448 )) el;
441449 spr ctx "})";
442450 | TIdent "__lua__", [{ eexpr = TConst (TString code) }] ->
556564 gen_value ctx cond;
557565 ctx.iife_assign <- false
558566
559 and gen_loop ctx label cond e =
567 and gen_loop ctx cond do_while e =
560568 let old_in_loop = ctx.in_loop in
561569 ctx.in_loop <- true;
562570 let old_handle_continue = ctx.handle_continue in
563571 let will_continue = has_continue e in
564572 ctx.handle_continue <- has_continue e;
565573 ctx.break_depth <- ctx.break_depth + 1;
566 if will_continue then begin
574 if will_continue then
567575 println ctx "local _hx_continue_%i = false;" ctx.break_depth;
568 end;
576 if do_while then
577 println ctx "local _hx_do_first_%i = true;" ctx.break_depth;
569578 let b = open_block ctx in
570 print ctx "%s " label;
579 print ctx "while ";
571580 gen_cond ctx cond;
581 if do_while then
582 print ctx " or _hx_do_first_%i" ctx.break_depth;
572583 print ctx " do ";
584 if do_while then
585 newline ctx;
586 println ctx "_hx_do_first_%i = false;" ctx.break_depth;
573587 if will_continue then print ctx "repeat ";
574588 gen_block_element ctx e;
575589 if will_continue then begin
625639 match t with
626640 TAbstract(_,p) | TInst(_,p) ->
627641 if List.exists ttype_multireturn p then
628 error "MultiReturns must not be type parameters" pos
642 typing_error "MultiReturns must not be type parameters" pos
629643 else
630644 ()
631645 | _ ->
715729 spr ctx (id ^ "_" ^ (ident v.v_name) ^ "_" ^ (field_name f));
716730 | _ ->
717731 Globals.die "" __LOC__);
732 | TField (_, (FStatic ({cl_path = [],""},_) as f)) ->
733 spr ctx (ident (field_name f))
718734 | TField (x,f) ->
719735 gen_value ctx x;
720736 let name = field_name f in
943959 gen_value ctx e;
944960 spr ctx (Ast.s_unop op)
945961 | TWhile (cond,e,Ast.NormalWhile) ->
946 gen_loop ctx "while" cond e
962 gen_loop ctx cond false e;
947963 | TWhile (cond,e,Ast.DoWhile) ->
948 gen_block_element ctx e;
949 newline ctx;
950 gen_loop ctx "while" cond e
964 gen_loop ctx cond true e;
951965 | TObjectDecl [] ->
952966 spr ctx "_hx_e()";
953967 ctx.separator <- true
11811195 gen_expr ctx e
11821196 | TMeta (_,e1) ->
11831197 gen_value ctx e1
1198 | TCall ({eexpr = (TField (e, (FInstance _ as s)))}, el) when (is_string_expr e) ->
1199 spr ctx ("String.prototype." ^ (field_name s));
1200 gen_paren_arguments ctx (e :: el)
11841201 | TCall (e,el) ->
11851202 gen_call ctx e el
11861203 | TReturn _
12611278
12621279 and gen_tbinop ctx op e1 e2 =
12631280 (match op, e1.eexpr, e2.eexpr with
1264 | Ast.OpAssign, TField(e3, FInstance _), TFunction f ->
1281 | Ast.OpAssign, TField(e3, (FInstance _ as ci)), TFunction f ->
12651282 gen_expr ctx e1;
12661283 spr ctx " = " ;
1267 print ctx "function(%s) " (String.concat "," ("self" :: List.map ident (List.map arg_name f.tf_args)));
1284 let fn_args = List.map ident (List.map arg_name f.tf_args) in
1285 print ctx "function(%s) " (String.concat ","
1286 (if is_dot_access e3 ci
1287 then fn_args
1288 else "self" :: fn_args));
12681289 let fblock = fun_block ctx f e1.epos in
12691290 (match fblock.eexpr with
12701291 | TBlock el ->
12961317 gen_value ctx e1;
12971318 spr ctx " = ";
12981319 gen_value ctx e3;
1299 | TField(e3, (FInstance _| FClosure _ | FAnon _ ) ), TField(e4, (FClosure _| FStatic _ | FAnon _) ) ->
1320 | TField(e3, (FClosure _ | FAnon _)), TField(e4, (FClosure _ | FStatic _ | FAnon _)) ->
13001321 gen_value ctx e1;
13011322 print ctx " %s " (Ast.s_binop op);
13021323 add_feature ctx "use._hx_funcToField";
13031324 spr ctx "_hx_funcToField(";
13041325 gen_value ctx e2;
13051326 spr ctx ")";
1306 | TField(_, FInstance _ ), TLocal t when (is_function_type t.v_type) ->
1327 | TField(e3, (FInstance _ as lhs)), TField(e4, (FInstance _ as rhs)) when not (is_dot_access e3 lhs) && (is_dot_access e4 rhs) ->
1328 gen_value ctx e1;
1329 print ctx " %s " (Ast.s_binop op);
1330 add_feature ctx "use._hx_funcToField";
1331 spr ctx "_hx_funcToField(";
1332 gen_value ctx e2;
1333 spr ctx ")";
1334 | TField(e3, (FInstance _ as ci)), TField(e4, (FClosure _ | FStatic _ | FAnon _)) when not (is_dot_access e3 ci) ->
1335 gen_value ctx e1;
1336 print ctx " %s " (Ast.s_binop op);
1337 add_feature ctx "use._hx_funcToField";
1338 spr ctx "_hx_funcToField(";
1339 gen_value ctx e2;
1340 spr ctx ")";
1341 | TField(e3, (FInstance _ as ci)), TLocal t when ((is_function_type t.v_type) && (not (is_dot_access e3 ci))) ->
13071342 gen_value ctx e1;
13081343 print ctx " %s " (Ast.s_binop op);
13091344 add_feature ctx "use._hx_funcToField";
14401475 spr ctx "do return end"
14411476 | Some e ->
14421477 (match e.eexpr with
1443 | TField (e2, ((FClosure (_, tcf) | FAnon tcf |FInstance (_,_,tcf)))) when (is_function_type tcf.cf_type) ->
1478 | TField (e2, ((FAnon tcf | FInstance (_,_,tcf)) as t)) when ((is_function_type tcf.cf_type) && (not(is_dot_access e2 t)))->
14441479 (* See issue #6259 *)
14451480 add_feature ctx "use._hx_bind";
14461481 spr ctx "do return ";
14831518 match c with
14841519 | _ when Meta.has Meta.MultiReturn c.cl_meta ->
14851520 if not (has_class_flag c CExtern) then
1486 error "MultiReturns must be externs" c.cl_pos
1521 typing_error "MultiReturns must be externs" c.cl_pos
14871522 else if List.length c.cl_ordered_statics > 0 then
1488 error "MultiReturns must not contain static fields" c.cl_pos
1523 typing_error "MultiReturns must not contain static fields" c.cl_pos
14891524 else if (List.exists (fun cf -> match cf.cf_kind with Method _ -> true | _-> false) c.cl_ordered_fields) then
1490 error "MultiReturns must not contain methods" c.cl_pos;
1525 typing_error "MultiReturns must not contain methods" c.cl_pos;
14911526 | {cl_super = Some(csup,_)} when Meta.has Meta.MultiReturn csup.cl_meta ->
1492 error "Cannot extend a MultiReturn" c.cl_pos
1527 typing_error "Cannot extend a MultiReturn" c.cl_pos
14931528 | _ -> ()
14941529
14951530
14961531 let check_field_name c f =
14971532 match f.cf_name with
14981533 | "prototype" | "__proto__" | "constructor" ->
1499 error ("The field name '" ^ f.cf_name ^ "' is not allowed in Lua") (match f.cf_expr with None -> c.cl_pos | Some e -> e.epos);
1534 typing_error ("The field name '" ^ f.cf_name ^ "' is not allowed in Lua") (match f.cf_expr with None -> c.cl_pos | Some e -> e.epos);
15001535 | _ -> ()
15011536
15021537 (* convert a.b.c to ["a"]["b"]["c"] *)
15841619 ctx.current <- c;
15851620 ctx.id_counter <- 0;
15861621 (match c.cl_path with
1587 | [],"Function" -> error "This class redefines a native one" c.cl_pos
1622 | [],"Function" -> typing_error "This class redefines a native one" c.cl_pos
15881623 | _ -> ());
15891624 let p = s_path ctx c.cl_path in
15901625 let hxClasses = has_feature ctx "Type.resolveClass" in
17821817 | [(EConst(String(module_name,_)),_) ; (EConst(String(object_path,_)),_)] ->
17831818 print ctx "%s = _G.require(\"%s\").%s" p module_name object_path
17841819 | _ ->
1785 error "Unsupported @:luaRequire format" mp);
1820 typing_error "Unsupported @:luaRequire format" mp);
17861821
17871822 newline ctx
17881823
17971832 if p = "Std" && c.cl_ordered_statics = [] then
17981833 ()
17991834 else if (not (has_class_flag c CExtern)) && Meta.has Meta.LuaDotMethod c.cl_meta then
1800 error "LuaDotMethod is valid for externs only" c.cl_pos
1835 typing_error "LuaDotMethod is valid for externs only" c.cl_pos
18011836 else if not (has_class_flag c CExtern) then
18021837 generate_class ctx c;
18031838 check_multireturn ctx c;
18491884 lua_jit = Common.defined com Define.LuaJit;
18501885 lua_vanilla = Common.defined com Define.LuaVanilla;
18511886 lua_ver = try
1852 float_of_string (PMap.find "lua_ver" com.defines.Define.values)
1887 float_of_string (Common.defined_value com Define.LuaVer)
18531888 with | Not_found -> 5.2;
18541889 } in
18551890 ctx.type_accessor <- (fun t ->
19101945 e
19111946 | TReturn Some(e2) ->
19121947 if is_multireturn e2.etype then
1913 error "You cannot return a multireturn type from a haxe function" e2.epos
1948 typing_error "You cannot return a multireturn type from a haxe function" e2.epos
19141949 else
19151950 Type.map_expr loop e;
19161951 (*
20562091 println ctx "_hx_array_mt.__index = Array.prototype";
20572092 newline ctx;
20582093
2094 (* Functions to support auto-run of libuv loop *)
2095 print_file (Common.find_file com "lua/_lua/_hx_luv.lua");
2096
20592097 let b = open_block ctx in
20602098 (* Localize init variables inside a do-block *)
20612099 println ctx "local _hx_static_init = function()";
21072145 print_file (Common.find_file com "lua/_lua/_hx_dyn_add.lua");
21082146 end;
21092147
2148 print_file (Common.find_file com "lua/_lua/_hx_handle_error.lua");
2149
21102150 println ctx "_hx_static_init();";
21112151
21122152 List.iter (generate_enumMeta_fields ctx) com.types;
21132153
21142154 Option.may (fun e ->
2115 spr ctx "_G.xpcall(";
2116 (match e.eexpr with
2117 | TCall(e2,[]) ->
2118 gen_value ctx e2;
2119 | _->
2155 spr ctx "local success, err = _G.xpcall(";
2156 let luv_run =
2157 (* Runs libuv loop if needed *)
2158 mk_lua_code ctx.com.basic "_hx_luv.run()" [] ctx.com.basic.tvoid Globals.null_pos
2159 in
21202160 let fn =
21212161 {
21222162 tf_args = [];
21232163 tf_type = com.basic.tvoid;
2124 tf_expr = mk (TBlock [e]) com.basic.tvoid e.epos;
2164 tf_expr = mk (TBlock [e;luv_run]) com.basic.tvoid e.epos;
21252165 }
21262166 in
2127 gen_value ctx { e with eexpr = TFunction fn; etype = TFun ([],com.basic.tvoid) }
2128 );
2129 spr ctx ", _hx_error)";
2130 newline ctx
2167 gen_value ctx { e with eexpr = TFunction fn; etype = TFun ([],com.basic.tvoid) };
2168 println ctx ", _hx_handle_error)";
2169 println ctx "if not success then _G.error(err) end";
21312170 ) com.main;
21322171
21332172 if anyExposed then
21362175 let ch = open_out_bin com.file in
21372176 output_string ch (Buffer.contents ctx.buf);
21382177 close_out ch
2139
171171 with _ ->
172172 if ctx.version < 2 then abort "This integer is too big to be compiled to a Neko 31-bit integer. Please use a Float instead" pe;
173173 (EConst (Int32 i),p))
174 | TFloat f -> (EConst (Float f),p)
174 | TFloat f -> (EConst (Float (Texpr.replace_separators f "")),p)
175175 | TString s -> call p (field p (ident p "String") "new") [gen_big_string ctx p s]
176176 | TBool b -> (EConst (if b then True else False),p)
177177 | TNull -> null p
661661 | libs ->
662662 (*
663663 var @s = $loader.loadprim("std@sys_string",0)();
664 var @env = $loader.loadprim("std@get_env",1);
665 var @b = if( @s == "Windows" )
666 @env("HAXEPATH") + "\\lib\\"
667 else try $loader.loadprim("std@file_contents",1)(@env("HOME")+"/.haxelib") + "/"
668 catch e
669 if( @s == "Linux" )
670 if( $loader(loadprim("std@sys_exists",1))("/usr/lib/haxe/lib") )
671 "/usr/lib/haxe/lib"
672 else
673 "/usr/share/haxe/lib/"
674 else
675 "/usr/local/lib/haxe/lib/";
676 if( try $loader.loadprim("std@sys_file_type",1)(".haxelib") == "dir" catch e false ) @b = $loader.loadprim("std@file_full_path",1)(".haxelib") + "/";
677 if( $loader.loadprim("std@sys_is64",0)() ) @s = @s + 64;
678 @b = @b + "/"
664 if( $version() >= 240 )
665 @s = @s + switch $loader.loadprim("std@sys_cpu_arch",0)() {
666 "arm64" => "Arm64"
667 "arm" => "Arm"
668 "x86_64" => "64"
669 default => ""
670 };
671 else if( $loader.loadprim("std@sys_is64",0)() )
672 @s = @s + 64;
673 @s = @s + "/";
679674 *)
680675 let p = null_pos in
681676 let es = ident p "@s" in
688683 let boot = [
689684 (EVars [
690685 "@s",Some (call p (loadp "sys_string" 0) []);
691 "@env",Some (loadp "get_env" 1);
692 "@b", Some (EIf (op "==" es (str p "Windows"),
693 op "+" (call p (ident p "@env") [str p "HAXEPATH"]) (str p "\\lib\\"),
694 Some (ETry (
695 op "+" (call p (loadp "file_contents" 1) [op "+" (call p (ident p "@env") [str p "HOME"]) (str p "/.haxelib")]) (str p "/"),
696 "e",
697 (EIf (op "==" es (str p "Linux"),
698 (EIf (call p (loadp "sys_exists" 1) [ str p "/usr/lib/haxe/lib" ],
699 str p "/usr/lib/haxe/lib/",
700 Some (str p "/usr/share/haxe/lib/")),p),
701 Some (str p "/usr/local/lib/haxe/lib/")
702 ),p)
703 ),p)
704 ),p);
705686 ],p);
706 (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);
707 (EIf (call p (loadp "sys_is64" 0) [],op "=" es (op "+" es (int p 64)),None),p);
687 (EIf (op ">=" (builtin p "version") (int p 240),
688 (op "=" es (op "+" es (ESwitch (call p (loadp "sys_cpu_arch" 0) [],[
689 (str p "arm64", str p "Arm64");
690 (str p "arm", str p "Arm");
691 (str p "x86_64", str p "64");
692 ], Some (str p "")),p))),
693 Some (EIf (call p (loadp "sys_is64" 0) [],op "=" es (op "+" es (int p 64)),None),p)
694 ),p);
708695 op "=" es (op "+" es (str p "/"));
709696 ] in
710697 let lpath = field p (builtin p "loader") "path" in
711698 boot @ List.map (fun dir ->
712 let full_path = dir.[0] = '/' || dir.[1] = ':' in
713699 let dstr = str p dir in
714700 (*
715701 // for each lib dir
716 $loader.path = $array($loader.path,@b+dir+@s);
702 $loader.path = $array(dir+@s,$loader.path);
717703 *)
718 op "=" lpath (call p (builtin p "array") [op "+" (if full_path then dstr else op "+" (ident p "@b") dstr) (ident p "@s"); lpath])
704 op "=" lpath (call p (builtin p "array") [op "+" dstr (ident p "@s"); lpath])
719705 ) libs
720706
721707 let new_context com ver macros =
786772 let generate com =
787773 Hashtbl.clear files;
788774 let ctx = new_context com (if Common.defined com Define.NekoV1 then 1 else 2) false in
789 let libs = (EBlock (generate_libs_init com.neko_libs) , { psource = "<header>"; pline = 1; }) in
775 let libs = (EBlock
776 (if Common.defined com Define.NekoNoHaxelibPaths then []
777 else generate_libs_init com.neko_lib_paths),
778 { psource = "<header>"; pline = 1; }
779 ) in
790780 let el = build ctx com.types in
791781 let emain = (match com.main with None -> [] | Some e -> [gen_expr ctx e]) in
792782 let e = (EBlock ((header()) @ libs :: el @ emain), null_pos) in
809799 in
810800 abort msg (loop 0)
811801 end;
812 let command cmd = try com.run_command cmd with _ -> -1 in
802 let command cmd args = try com.run_command_args cmd args with _ -> -1 in
813803 let neko_file = (try Filename.chop_extension com.file with _ -> com.file) ^ ".neko" in
814804 if source || use_nekoc then begin
815805 let ch = IO.output_channel (open_out_bin neko_file) in
816806 Binast.write ch e;
817807 IO.close_out ch;
818808 end;
819 if use_nekoc && command ("nekoc" ^ (if ctx.version > 1 then " -version " ^ string_of_int ctx.version else "") ^ " \"" ^ neko_file ^ "\"") <> 0 then failwith "Neko compilation failure";
809 if use_nekoc && command "nekoc" (if ctx.version > 1 then ["-version"; (string_of_int ctx.version); neko_file] else [neko_file]) <> 0 then failwith "Neko compilation failure";
820810 if source then begin
821 if command ("nekoc -p \"" ^ neko_file ^ "\"") <> 0 then failwith "Failed to print neko code";
811 if command "nekoc" ["-p"; neko_file] <> 0 then failwith "Failed to print neko code";
822812 Sys.remove neko_file;
823813 Sys.rename ((try Filename.chop_extension com.file with _ -> com.file) ^ "2.neko") neko_file;
824814 end
11401140 List.iter
11411141 (fun ctx_type ->
11421142 let wrapper = get_wrapper ctx_type in
1143 Hashtbl.add ctx.pgc_namespaces_types_cache wrapper#get_namespace wrapper#get_name
1143 Hashtbl.add ctx.pgc_namespaces_types_cache wrapper#get_namespace (StringHelper.uppercase wrapper#get_name)
11441144 )
11451145 ctx.pgc_common.types;
11461146 Hashtbl.find_all ctx.pgc_namespaces_types_cache namespace
11471147 | types -> types
11481148 in
1149 List.mem as_name types
1149 List.mem (StringHelper.uppercase as_name) types
11501150 && (namespace, as_name) <> type_path
11511151
11521152 (**
23862386 match fields with
23872387 | [] -> self#write ("new " ^ (self#use hxanon_type_path) ^ "()")
23882388 | _ ->
2389 let inits,args_exprs,args_names =
2390 List.fold_left (fun (inits,args_exprs,args_names) ((name,p,quotes), e) ->
2391 let field,arg_name =
2392 if quotes = NoQuotes then name,name
2393 else "{" ^ (quote_string name) ^ "}", "_hx_" ^ (string_of_int (List.length args_exprs))
2394 in
2395 (field,mk (TIdent ("$"^arg_name)) e.etype p) :: inits, e :: args_exprs, arg_name :: args_names
2396 ) ([],[],[]) fields
2397 in
2398 let anon_name, declare_class =
2399 let key = List.map (fun ((name,_,_),_) -> name) fields in
2400 try
2401 Hashtbl.find ctx.pgc_anons key, false
2402 with Not_found ->
2403 let name = "_HxAnon_" ^ self#get_name ^ (string_of_int (Hashtbl.length ctx.pgc_anons)) in
2404 Hashtbl.add ctx.pgc_anons key name;
2405 name, true
2406 in
2407 self#write ("new " ^ anon_name ^ "(");
2408 write_args self#write self#write_expr (List.rev args_exprs);
2409 self#write ")";
2410 if declare_class then begin
2411 (* save writer's state *)
2412 let original_buffer = buffer
2413 and original_indentation = self#get_indentation in
2414 let sm_pointer_before_body = get_sourcemap_pointer sourcemap in
2415 (* generate a class for this anon *)
2416 buffer <- ctx.pgc_bottom_buffer;
2417 self#set_indentation 0;
2418 self#write ("\nclass " ^ anon_name ^ " extends " ^ (self#use hxanon_type_path) ^ " {\n");
2419 self#indent_more;
2420 self#write_with_indentation "function __construct(";
2421 write_args self#write (fun name -> self#write ("$" ^ name)) (List.rev args_names);
2422 self#write ") {\n";
2423 self#indent_more;
2424 List.iter (fun (field,e) ->
2425 self#write_with_indentation "$this->";
2426 self#write field;
2427 self#write " = ";
2428 self#write_expr e;
2429 self#write ";\n";
2430 ) (List.rev inits);
2431 self#indent_less;
2432 self#write_line "}";
2433 self#indent_less;
2434 self#write_with_indentation "}\n";
2435 (* restore writer's state *)
2436 buffer <- original_buffer;
2437 self#set_indentation original_indentation;
2438 set_sourcemap_pointer sourcemap sm_pointer_before_body
2439 end
2389 self#write ("new " ^ (self#use hxanon_type_path) ^ "(");
2390 self#write_assoc_array_decl fields;
2391 self#write ")"
24402392 (**
24412393 Writes specified type to output buffer depending on type of expression.
24422394 *)
36863638 (* Generate `__toString()` if not defined by user, but has `toString()` *)
36873639 self#write_toString_if_required
36883640 method private write_toString_if_required =
3689 if PMap.exists "toString" cls.cl_fields then
3641 try
3642 let toString = PMap.find "toString" cls.cl_fields in
36903643 if (not (has_class_flag cls CInterface)) && (not (PMap.exists "__toString" cls.cl_statics)) && (not (PMap.exists "__toString" cls.cl_fields)) then
36913644 begin
36923645 writer#write_empty_lines;
36933646 writer#indent 1;
36943647 writer#write_line "public function __toString() {";
36953648 writer#indent_more;
3696 writer#write_line "return $this->toString();";
3649 let callee_str = match toString.cf_kind with
3650 | Var _ -> "($this->toString)"
3651 | Method _ -> "$this->toString"
3652 in
3653 writer#write_line ("return " ^ callee_str ^ "();");
36973654 writer#indent_less;
36983655 writer#write_line "}"
36993656 end
3657 with Not_found -> ()
37003658 (**
37013659 Check if this class requires constructor to be generated even if there is no user-defined one
37023660 *)
38693827 let (args, return_type) = get_function_signature field in
38703828 List.iter (fun (arg_name, _, _) -> writer#declared_local_var arg_name) args;
38713829 self#write_doc (DocMethod (args, return_type, (gen_doc_text_opt field.cf_doc))) field.cf_meta;
3872 writer#write_with_indentation ((get_visibility field.cf_meta) ^ " function " ^ (field_name field));
3830 let visibility_kwd = get_visibility field.cf_meta in
3831 writer#write_with_indentation (visibility_kwd ^ " function " ^ (field_name field));
38733832 (match field.cf_expr with
38743833 | None -> (* interface *)
38753834 writer#write " (";
38763835 write_args writer#write (writer#write_arg true) (fix_tsignature_args args);
38773836 writer#write ");\n";
38783837 | Some { eexpr = TFunction fn } -> (* normal class *)
3879 writer#write " (";
3880 write_args writer#write writer#write_function_arg (fix_tfunc_args fn.tf_args);
3881 writer#write ")\n";
3838 let write_args() =
3839 writer#write " (";
3840 write_args writer#write writer#write_function_arg (fix_tfunc_args fn.tf_args);
3841 writer#write ")\n"
3842 in
3843 write_args();
38823844 writer#write_line "{";
38833845 writer#indent_more;
38843846 writer#write_indentation;
3885 let field_access = "$this->" ^ (field_name field)
3886 and default_value = "$this->__hx__default__" ^ (field_name field) in
3887 writer#write ("if (" ^ field_access ^ " !== " ^ default_value ^ ") return call_user_func_array(" ^ field_access ^ ", func_get_args());\n");
3888 writer#write_fake_block fn.tf_expr;
3847 let field_access = "$this->" ^ (field_name field) in
3848 writer#write ("return call_user_func_array(" ^ field_access ^ ", func_get_args());\n");
38893849 writer#indent_less;
38903850 writer#write_line "}";
38913851 (* Don't forget to create a field for default value *)
3892 writer#write_statement ("protected $__hx__default__" ^ (field_name field))
3852 writer#write_indentation;
3853 writer#write (visibility_kwd ^ " function __hx__default__" ^ (field_name field));
3854 write_args();
3855 writer#write_line "{";
3856 writer#indent_more;
3857 writer#write_fake_block fn.tf_expr;
3858 writer#indent_less;
3859 writer#write_line "}"
38933860 | _ -> fail field.cf_pos __LOC__
38943861 );
38953862 (**
39063873 *)
39073874 method private write_instance_initialization =
39083875 let init_dynamic_method field =
3909 let field_name = field_name field in
3910 let default_field = "$this->__hx__default__" ^ field_name in
3911 writer#write_line ("if (!" ^ default_field ^ ") {");
3912 writer#indent_more;
3913 writer#write_statement (default_field ^ " = new " ^ (writer#use hxclosure_type_path) ^ "($this, '" ^ field_name ^ "')");
3914 writer#write_statement ("if ($this->" ^ field_name ^ " === null) $this->" ^ field_name ^ " = " ^ default_field);
3915 writer#indent_less;
3916 writer#write_line "}"
3876 let field_name = field_name field
3877 and hx_closure = writer#use hxclosure_type_path in
3878 writer#write_statement ("if ($this->" ^ field_name ^ " === null) $this->" ^ field_name ^ " = new " ^ hx_closure ^ "($this, '__hx__default__" ^ field_name ^ "')");
39173879 in
39183880 List.iter
39193881 (fun field ->
6868 let h = Hashtbl.create 0 in
6969 List.iter (fun s -> Hashtbl.add h s ()) [
7070 "and"; "as"; "assert"; "async"; "await"; "break"; "class"; "continue"; "def"; "del"; "elif"; "else"; "except"; "exec"; "finally"; "for";
71 "from"; "global"; "if"; "import"; "in"; "is"; "lambda"; "not"; "or"; "pass"; " raise"; "return"; "try"; "while";
71 "from"; "global"; "if"; "import"; "in"; "is"; "lambda"; "not"; "or"; "pass"; "raise"; "return"; "try"; "while";
7272 "with"; "yield"; "None"; "True"; "False";
7373 ];
7474 h
10801080 | OpShr -> ">>"
10811081 | OpUShr -> ">>"
10821082 | OpMod -> "%"
1083 | OpInterval | OpArrow | OpIn | OpAssignOp _ -> die "" __LOC__
1083 | OpInterval | OpArrow | OpIn | OpNullCoal | OpAssignOp _ -> die "" __LOC__
10841084
10851085 let print_string s =
10861086 Printf.sprintf "\"%s\"" (StringHelper.s_escape s)
13411341 | TParenthesis e1 ->
13421342 Printf.sprintf "(%s)" (print_expr pctx e1)
13431343 | TObjectDecl fl ->
1344 let fl2 = ref fl in
1345 begin match follow e.etype with
1346 | TAnon an ->
1347 PMap.iter (fun s cf ->
1348 if not (Expr.field_mem_assoc s fl) then fl2 := ((s,null_pos,NoQuotes),null cf.cf_type cf.cf_pos) :: !fl2
1349 ) an.a_fields
1350 | _ ->
1351 ()
1352 end;
1353 Printf.sprintf "_hx_AnonObject(%s)" (print_exprs_named pctx ", " !fl2)
1344 Printf.sprintf "_hx_AnonObject(%s)" (print_exprs_named pctx ", " fl)
13541345 | TArrayDecl el ->
13551346 Printf.sprintf "[%s]" (print_exprs pctx ", " el)
13561347 | TCall(e1,el) ->
15001491 let interpolate () =
15011492 Codegen.interpolate_code pctx.pc_com code tl (Buffer.add_string buf) (fun e -> Buffer.add_string buf (print_expr pctx e)) ecode.epos
15021493 in
1503 let old = pctx.pc_com.error in
1504 pctx.pc_com.error <- abort;
1505 Std.finally (fun() -> pctx.pc_com.error <- old) interpolate ();
1494 let old = pctx.pc_com.located_error in
1495 pctx.pc_com.located_error <- abort_located;
1496 Std.finally (fun() -> pctx.pc_com.located_error <- old) interpolate ();
15061497 Buffer.contents buf
15071498 | ("python_Syntax._pythonCode"), [e] ->
15081499 print_expr pctx e
18901881 let py_metas = filter_py_metas cf.cf_meta in
18911882 begin match cf.cf_expr with
18921883 | Some ({eexpr = TFunction f} as ef) ->
1893 let ethis = mk (TConst TThis) (TInst(c,List.map snd c.cl_params)) cf.cf_pos in
1884 let ethis = mk (TConst TThis) (TInst(c,extract_param_types c.cl_params)) cf.cf_pos in
18941885 let assigned_fields = ref [] in
18951886 (* Collect all fields that are assigned to but panic out as soon as `this`,
18961887 `super`, `return` or `throw` appears (regardless of control flow). *)
140140 begin try
141141 Some (Hashtbl.find pfms td.t_path)
142142 with Not_found ->
143 self#identify accept_anons (apply_params td.t_params tl td.t_type)
143 self#identify accept_anons (apply_typedef td tl)
144144 end
145145 | TMono {tm_type = Some t} ->
146146 self#identify accept_anons t
194194
195195 method get_class_info (c : tclass) =
196196 let rec loop ml = match ml with
197 | (Meta.Custom ":jvm.classInfo",[(EConst (Int s),_)],_) :: _ ->
197 | (Meta.Custom ":jvm.classInfo",[(EConst (Int (s, _)),_)],_) :: _ ->
198198 DynArray.get class_infos (int_of_string s)
199199 | _ :: ml ->
200200 loop ml
205205 implicit_ctors = PMap.empty;
206206 } in
207207 DynArray.add class_infos infos;
208 c.cl_meta <- (Meta.Custom ":jvm.classInfo",[(EConst (Int (string_of_int index)),null_pos)],null_pos) :: c.cl_meta;
208 c.cl_meta <- (Meta.Custom ":jvm.classInfo",[(EConst (Int (string_of_int index, None)),null_pos)],null_pos) :: c.cl_meta;
209209 infos
210210 in
211211 loop c.cl_meta
240240
241241 method get_field_info (ml : metadata) =
242242 let rec loop ml = match ml with
243 | (Meta.Custom ":jvm.fieldInfo",[(EConst (Int s),_)],_) :: _ ->
243 | (Meta.Custom ":jvm.fieldInfo",[(EConst (Int (s, _)),_)],_) :: _ ->
244244 Some (DynArray.get field_infos (int_of_string s))
245245 | _ :: ml ->
246246 loop ml
277277 in
278278 loop csup;
279279 (c,cf)
280 | None -> Error.error "Could not find overload constructor" e.epos
280 | None -> Error.typing_error "Could not find overload constructor" e.epos
281281 in
282282 let find_super_ctor el =
283283 let _,cf = find_super_ctor el in
366366 let info = self#preprocess_constructor_expr c cf e in
367367 let index = DynArray.length field_infos in
368368 DynArray.add field_infos info;
369 cf.cf_meta <- (Meta.Custom ":jvm.fieldInfo",[(EConst (Int (string_of_int index)),null_pos)],null_pos) :: cf.cf_meta;
369 cf.cf_meta <- (Meta.Custom ":jvm.fieldInfo",[(EConst (Int (string_of_int index, None)),null_pos)],null_pos) :: cf.cf_meta;
370370 if not (Meta.has Meta.HxGen cf.cf_meta) then begin
371371 let rec loop next c =
372372 if (has_class_flag c CExtern) then make_native cf
412412
413413 method private implements (c : tclass) (path_interface : path) =
414414 let info = infos#get_class_info c in
415 match info.typedef_implements with
415 List.exists (fun (c,_) ->
416 c.cl_path = path_interface
417 ) c.cl_implements
418 || match info.typedef_implements with
416419 | None ->
417420 false
418421 | Some l ->
423426 | Some (c,_) -> self#implements_recursively c path
424427 | None -> false
425428
426 method private make_interface_class (pfm : 'a path_field_mapping) =
429 method private make_interface_class (pfm : 'a path_field_mapping) (path : path) (is_extern : bool) =
427430 let path_inner = (fst pfm.pfm_path,snd pfm.pfm_path ^ "$Interface") in
428431 try
429432 Hashtbl.find interfaces path_inner
435438 acc
436439 ) pfm.pfm_fields PMap.empty in
437440 if PMap.is_empty fields then raise (Unify_error [Unify_custom "no fields"]);
438 let path,is_extern = try Hashtbl.find interface_rewrites pfm.pfm_path with Not_found -> path_inner,false in
439441 let c = mk_class null_module path null_pos null_pos in
440442 add_class_flag c CInterface;
441443 c.cl_fields <- fields;
449451 | Some(c,_) -> self#process_class c
450452 | None -> ()
451453 end;
452 let tc = TInst(c,List.map snd c.cl_params) in
454 let tc = TInst(c,extract_param_types c.cl_params) in
455 (* TODO: this entire architecture looks slightly retarded because typedef_implements is only modified at the end of the
456 loop, which I think could cause items to be missed. *)
453457 let l = Hashtbl.fold (fun _ pfm acc ->
454458 let path = pfm.pfm_path in
455459 let path_inner = (fst path,snd path ^ "$Interface") in
456460 try
461 let path_inner,is_extern = try Hashtbl.find interface_rewrites pfm.pfm_path with Not_found -> path_inner,false in
457462 if self#implements_recursively c path_inner then raise (Unify_error [Unify_custom "already implemented"]);
458463 anon_identification#unify tc pfm;
459 let ci = self#make_interface_class pfm in
464 let ci = self#make_interface_class pfm path_inner is_extern in
460465 c.cl_implements <- (ci,[]) :: c.cl_implements;
461466 (* print_endline (Printf.sprintf "%s IMPLEMENTS %s" (s_type_path c.cl_path) (s_type_path path_inner)); *)
462467 (ci :: acc)
8383 | TAnon a ->
8484 PMap.iter (fun _ f -> add_type_rec (t::l) f.cf_type) a.a_fields
8585 | TDynamic t2 ->
86 add_type_rec (t::l) t2;
86 add_type_rec (t::l) (match t2 with None -> t_dynamic | Some t2 -> t2);
8787 | TLazy f ->
8888 add_type_rec l (lazy_type f)
8989 | TMono r ->
147147 (match c.cl_super with
148148 | None -> add_path ([],"Object") DKInherit;
149149 | Some x -> add_inherit x);
150 List.iter (fun (_,t) ->
150 List.iter (fun tp ->
151151 (* add type-parameters constraints dependencies *)
152 match follow t with
152 match follow tp.ttp_type with
153153 | TInst (c,_) -> List.iter add_inherit c.cl_implements
154154 | _ -> ()
155155 ) c.cl_params;
342342 (match h.Png.png_color with
343343 | Png.ClTrueColor (Png.TBits8,Png.NoAlpha) ->
344344 if h.Png.png_width * h.Png.png_height * 4 > Sys.max_string_length then begin
345 com.warning "Flash will loose some color information for this file, add alpha channel to preserve it" p;
345 com.warning WGenerator [] "Flash will loose some color information for this file, add alpha channel to preserve it" p;
346346 raise Exit;
347347 end;
348348 let data = Extc.unzip (Png.data png) in
219219 | TType ({ t_path = [],"UInt" },[]) ->
220220 t
221221 | TType (t,tl) ->
222 follow_basic (apply_params t.t_params tl t.t_type)
222 follow_basic (apply_typedef t tl)
223223 | TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
224224 follow_basic (apply_params a.a_params pl a.a_this)
225225 | _ -> t
14251425 end
14261426 | TIdent s ->
14271427 abort ("Unbound variable " ^ s) e.epos
1428 and args_as_array ctx mandatory_args spread_arg =
1428 and args_as_array ctx mandatory_args spread_arg p =
14291429 match mandatory_args with
14301430 | [] ->
14311431 spread_arg
14321432 | _ ->
1433 let p = punion_el (List.map (fun e -> ((),e.epos)) mandatory_args) in
1433 let p = punion_el p mandatory_args in
14341434 let array = mk (TArrayDecl mandatory_args) (ctx.com.basic.tarray t_dynamic) p in
14351435 let concat = mk (TField (array,FDynamic "concat")) t_dynamic spread_arg.epos in
14361436 mk (TCall (concat,[spread_arg])) (ctx.com.basic.tarray t_dynamic) (punion p spread_arg.epos)
14431443 and t_array_dyn = ctx.com.basic.tarray t_dynamic in
14441444 let t = TFun (["thisArg",false,t_dynamic; "argArray",false,t_array_dyn],r) in
14451445 let apply = mk (TField (e,FDynamic "apply")) t e.epos in
1446 gen_call ctx retval apply [null; args_as_array ctx (List.rev el_rev) rest] r
1446 gen_call ctx retval apply [null; args_as_array ctx (List.rev el_rev) rest e.epos] r
14471447 (* normal call without `...rest` *)
14481448 | _ ->
14491449 match e.eexpr , el with
18281828 gen_op A3OLt
18291829 | OpLte ->
18301830 gen_op A3OLte
1831 | OpInterval | OpArrow | OpIn ->
1831 | OpInterval | OpArrow | OpIn | OpNullCoal ->
18321832 die "" __LOC__
18331833
18341834 and gen_expr ctx retval e =
22522252 }
22532253
22542254 let maybe_gen_instance_getter ctx c f acc alloc_slot =
2255 let tl = List.map snd c.cl_params in
2255 let tl = extract_param_types c.cl_params in
22562256 maybe_gen_instance_accessor ctx c tl f acc alloc_slot MK3Getter
22572257 (mk_instance_getter_func c tl c tl f)
22582258 (fun prop_cf -> ([],prop_cf.cf_type))
22732273 }
22742274
22752275 let maybe_gen_instance_setter ctx c f acc alloc_slot =
2276 let tl = List.map snd c.cl_params in
2276 let tl = extract_param_types c.cl_params in
22772277 maybe_gen_instance_accessor ctx c tl f acc alloc_slot MK3Setter
22782278 (mk_instance_setter_func ctx.com c tl c tl f)
22792279 (fun prop_cf -> ([(mk_varg prop_cf.cf_type,None)],ctx.com.basic.tvoid))
23752375 | _ -> false
23762376 in
23772377
2378 let tl = List.map snd cl.cl_params in
2378 let tl = extract_param_types cl.cl_params in
23792379 let fields = ref [] in
23802380 Hashtbl.iter (fun name (read, write, native) ->
23812381 match Type.class_field cl tl name with
25252525 if read = AccCall then begin
25262526 try
25272527 begin
2528 let tl = List.map snd c.cl_params in
2528 let tl = extract_param_types c.cl_params in
25292529 match Type.class_field c tl ("get_" ^ f.cf_name) with
25302530 | Some (actual_cl, actual_tl), _, getter_cf when actual_cl != c ->
25312531 let func = mk_instance_getter_func c tl actual_cl actual_tl getter_cf f in
25502550 if write = AccCall then begin
25512551 try
25522552 begin
2553 let tl = List.map snd c.cl_params in
2553 let tl = extract_param_types c.cl_params in
25542554 match Type.class_field c tl ("set_" ^ f.cf_name) with
25552555 | Some (actual_cl, actual_tl), _, setter_cf when actual_cl != c ->
25562556 let func = mk_instance_setter_func ctx.com c tl actual_cl actual_tl setter_cf f in
7777 mutable file_prefix : string;
7878 mutable fun_index : int;
7979 mutable type_module : (ttype, code_module) PMap.t;
80 gcon : Common.context;
8081 }
8182
8283 let sprintf = Printf.sprintf
123124 if Hashtbl.mem keywords ("_" ^ n) then "__" ^ n else n
124125
125126 let is_gc_ptr = function
126 | HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HType | HRef _ | HMethod _ -> false
127 | HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HType | HRef _ | HMethod _ | HPacked _ -> false
127128 | HBytes | HDyn | HFun _ | HObj _ | HArray | HVirtual _ | HDynObj | HAbstract _ | HEnum _ | HNull _ | HStruct _ -> true
128129
129130 let is_ptr = function
152153 | HEnum _ -> "venum",1
153154 | HNull _ -> "vdynamic",1
154155 | HMethod _ -> "void",1
156 | HPacked t ->
157 let name,v = ctype_no_ptr t in
158 "struct _" ^ name, v
155159
156160 let ctype t =
157161 let t, nptr = ctype_no_ptr t in
198202 | HNull _ -> "HNULL"
199203 | HMethod _ -> "HMETHOD"
200204 | HStruct _ -> "HSTRUCT"
205 | HPacked _ -> "HPACKED"
201206
202207 let var_type n t =
203208 ctype t ^ " " ^ ident n
222227 h
223228
224229 let type_name ctx t =
225 try PMap.find t ctx.htypes with Not_found -> Globals.die "" __LOC__
230 try PMap.find t ctx.htypes with Not_found -> Globals.die (tstr t) __LOC__
226231
227232 let define ctx s =
228233 if not (Hashtbl.mem ctx.hdefines s) then begin
244249 | HVirtual vp when not (PMap.exists t ctx.defined_types) ->
245250 ctx.defined_types <- PMap.add t () ctx.defined_types;
246251 Array.iter (fun (_,_,t) -> define_type ctx t) vp.vfields
252 | HPacked t ->
253 define_type ctx t
247254 | HEnum _ | HObj _ | HStruct _ | HVirtual _ ->
248255 ()
249256
290297 let obj_field fid name =
291298 if name = "" then unamed_field fid else ident name
292299
300 let bom = "\xEF\xBB\xBF"
301
293302 let close_file ctx =
294 let str = Buffer.contents ctx.out in
303 let out = Buffer.contents ctx.out in
295304 let defines = List.rev ctx.defines in
296 let str = (match defines with [] -> str | l -> String.concat "\n" l ^ "\n\n" ^ str) in
305 let content = (match defines with [] -> out | l -> String.concat "\n" l ^ "\n\n" ^ out) in
306 let str = if ctx.curfile = "hlc.json" then content else bom ^ content in
297307 ctx.defines <- [];
298308 ctx.defined_types <- PMap.empty;
299309 Hashtbl.clear ctx.hdefines;
310320 close_out ch;
311321 end
312322
313 let bom = "\xEF\xBB\xBF"
314
315323 let define_global ctx g =
316324 let t = ctx.hlcode.globals.(g) in
317325 define_type ctx t;
336344
337345 let open_file ctx file =
338346 if ctx.curfile <> "" then close_file ctx;
339 let version_major = ctx.version / 1000 in
340 let version_minor = (ctx.version mod 1000) / 100 in
341 let version_revision = (ctx.version mod 100) in
342 if file <> "hlc.json" then define ctx (sprintf "%s// Generated by HLC %d.%d.%d (HL v%d)" bom version_major version_minor version_revision ctx.hlcode.version);
347 if file <> "hlc.json" then
348 Codegen.map_source_header ctx.gcon (fun s -> define ctx (sprintf "// %s" s));
343349 ctx.curfile <- file;
344350 ctx.fun_index <- 0;
345351 ctx.file_prefix <- (short_digest file) ^ "_"
548554 let assign = reg r ^ " = " in
549555 if tsame t rt then assign else
550556 if not (safe_cast t rt) then Globals.die "" __LOC__
551 else assign ^ "(" ^ ctype rt ^ ")"
557 else
558 let cast = assign ^ "(" ^ ctype rt ^ ")" in
559 (match t with HPacked _ -> cast ^ "&" | _ -> cast)
552560 in
553561
554562 let ocall r fid args =
567575 in
568576
569577 let type_value_opt t =
570 match t with HF32 | HF64 -> "" | _ -> "," ^ type_value t
578 match t with HF32 | HF64 | HI64 -> "" | _ -> "," ^ type_value t
571579 in
572580
573581 let dyn_call r f pl =
734742 one way for comparisons
735743 *)
736744 match rtype a, rtype b with
737 | (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool), (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool) ->
745 | (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64), (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64) ->
738746 phys_compare()
739747 | HType, HType ->
740748 sexpr "if( hl_same_type(%s,%s) %s 0 ) {} else goto %s" (reg a) (reg b) (s_comp op) (label d)
10951103 let e = Str.regexp "[^A-Za-z0-9_]+" in
10961104 (fun str -> Str.global_replace e "_" str)
10971105
1106 let native_name str =
1107 if str.[0] = '?' then String.sub str 1 (String.length str - 1) else str
1108
10981109 let make_types_idents htypes =
10991110 let types_descs = ref PMap.empty in
11001111 let rec make_desc t =
11071118 DFun (List.map make_desc tl, make_desc t, false)
11081119 | HObj p | HStruct p ->
11091120 DNamed p.pname
1121 | HPacked t ->
1122 (match make_desc t with
1123 | DNamed n -> DNamed ("packed_" ^ n)
1124 | _ -> Globals.die "" __LOC__)
11101125 | HAbstract (n,_) ->
11111126 DNamed n
11121127 | HEnum e when e.ename = "" ->
11241139 Array.iteri (fun i (f,_,t) -> arr.(i) <- (f,make_desc t)) vp.vfields;
11251140 td
11261141 in
1142 let hashes = Hashtbl.create 0 in
11271143 let make_sign d =
1128 String.sub (Digest.to_hex (Digest.bytes (Marshal.to_bytes d [Marshal.Compat_32]))) 0 7
1144 let dig = Digest.to_hex (Digest.bytes (Marshal.to_bytes d [Marshal.Compat_32])) in
1145 let h = String.sub dig 0 7 in
1146 let h = if Hashtbl.mem hashes h then dig else h in
1147 Hashtbl.add hashes h ();
1148 h
11291149 in
11301150 let rec desc_string d =
11311151 match d with
11811201 Array.iter (fun (lib,name,t,idx) ->
11821202 let fname =
11831203 let lib = code.strings.(lib) in
1184 let lib = if lib = "std" then "hl" else lib in
1185 lib ^ "_" ^ code.strings.(name)
1204 let lib = if lib.[0] = '?' then String.sub lib 1 (String.length lib - 1) else lib in
1205 let lib = if lib = "std" then "hl" else lib in
1206 let str = lib ^ "_" ^ code.strings.(name) in
1207 (* create wrappers defines for invalid definitions *)
1208 if str = "hl_tls_get" then str ^ "_w" else str
11861209 in
11871210 match t with
11881211 | HFun (args, t) ->
14291452 file_prefix = "";
14301453 fun_index = 0;
14311454 type_module = PMap.empty;
1455 gcon = com;
14321456 } in
14331457 let modules = make_modules ctx all_types in
14341458
14411465 define ctx "// Abstract decls";
14421466 let rec get_abstracts = function
14431467 | [] -> []
1468 | HAbstract (("hl_tls" | "hl_mutex" | "hl_thread"), _) :: l -> get_abstracts l (* ignore / defined in hl.h already *)
14441469 | HAbstract (name,_) :: l -> name :: get_abstracts l
14451470 | _ :: l -> get_abstracts l
14461471 in
14521477 let sorted_natives = Array.copy code.natives in
14531478 Array.sort (fun n1 n2 -> let mk (lib,name,_,_) = code.strings.(lib), code.strings.(name) in compare (mk n1) (mk n2)) sorted_natives;
14541479 Array.iter (fun (lib,_,_,idx) ->
1455 Hashtbl.replace native_libs code.strings.(lib) ();
1480 let name = code.strings.(lib) in
1481 let name = if name.[0] = '?' then String.sub name 1 (String.length name - 1) else name in
1482 Hashtbl.replace native_libs name ();
14561483 let ft = ctx.ftable.(idx) in
14571484 define_type ctx (HFun (ft.fe_args,ft.fe_ret));
1458 sexpr "HL_API %s %s(%s)" (ctype ft.fe_ret) ft.fe_name (args_repr ft.fe_args);
1485 match ft.fe_name with
1486 | "hl_tls_get_w" ->
1487 define ctx "#define hl_tls_get_w(tls) ((vdynamic*)hl_tls_get(tls))";
1488 | "hl_tls_set" ->
1489 () (* don't redefine *)
1490 | _ ->
1491 sexpr "HL_API %s %s(%s)" (ctype ft.fe_ret) ft.fe_name (args_repr ft.fe_args);
14591492 ) sorted_natives;
14601493 line "#endif";
14611494 line "";
15871620 string_of_int (Array.length o.pproto);
15881621 string_of_int (List.length o.pbindings);
15891622 sprintf "(const uchar*)%s" (string ctx o.pid);
1590 (match o.psuper with None -> "NULL" | Some c -> type_value ctx (HObj c));
1623 (match o.psuper with None -> "NULL" | Some c -> type_value ctx (match t with HObj _ -> HObj c | _ -> HStruct c));
15911624 fields;
15921625 proto;
15931626 bindings
16601693 define_global ctx g;
16611694 sexpr "obj%s.global_value = (void**)&%s" name gnames.(g));
16621695 sexpr "%s.obj = &obj%s" name name
1663 | HNull r | HRef r ->
1696 | HNull r | HRef r | HPacked r ->
16641697 sexpr "%s.tparam = %s" (type_name ctx t) (type_value ctx r)
16651698 | HEnum e ->
16661699 let name = type_name ctx t in
17191752 open_file ctx "hl/functions.c";
17201753 define ctx "#define HLC_BOOT";
17211754 define ctx "#include <hlc.h>";
1722 sexpr "void *hl_functions_ptrs[] = {%s}" (String.concat "," (List.map (fun f -> define_function ctx f.fe_index) (Array.to_list ctx.ftable)));
1755 sexpr "void *hl_functions_ptrs[] = {%s}" (String.concat ",\\\n\t" (List.map (fun f ->
1756 let name = define_function ctx f.fe_index in
1757 if name = "hl_tls_get_w" then "hl_tls_get" else name
1758 ) (Array.to_list ctx.ftable)));
17231759 let rec loop i =
17241760 if i = Array.length ctx.ftable then [] else
17251761 let ft = ctx.ftable.(i) in
17271763 define ctx (sprintf "extern hl_type %s;" n);
17281764 ("&" ^ n) :: loop (i + 1)
17291765 in
1730 sexpr "hl_type *hl_functions_types[] = {%s}" (String.concat "," (loop 0));
1766 sexpr "hl_type *hl_functions_types[] = {%s}" (String.concat ",\\\n\t" (loop 0));
17311767 line "";
17321768 Array.iter (fun f ->
17331769 if f.fe_module = None then (match f.fe_decl with None -> () | Some f -> generate_function ctx f);
17791815 block ctx;
17801816 sline "\"version\" : %d," ctx.version;
17811817 sline "\"libs\" : [%s]," (String.concat "," (Hashtbl.fold (fun k _ acc -> sprintf "\"%s\"" k :: acc) native_libs []));
1782 sline "\"defines\" : {%s\n\t}," (String.concat "," (PMap.foldi (fun k v acc -> sprintf "\n\t\t\"%s\" : \"%s\"" (String.escaped k) (String.escaped v) :: acc) com.Common.defines.Define.values []));
1818 let defines = Buffer.create 64 in
1819 PMap.iter (fun key value ->
1820 Printf.bprintf defines "\n\t\t\"%s\" : \"%s\"," (String.escaped key) (String.escaped value);
1821 ) com.defines.values;
1822 Buffer.truncate defines (Buffer.length defines - 1);
1823 sline "\"defines\" : {%s\n\t}," (Buffer.contents defines);
17831824 sline "\"files\" : [%s\n\t]" (String.concat "," (List.map (sprintf "\n\t\t\"%s\"") ctx.cfiles));
17841825 unblock ctx;
17851826 line "}";
17861827
17871828 close_file ctx
1788
4747 | HNull of ttype
4848 | HMethod of ttype list * ttype
4949 | HStruct of class_proto
50 | HPacked of ttype
5051
5152 and class_proto = {
5253 pname : string;
255256 let is_nullable t =
256257 match t with
257258 | HBytes | HDyn | HFun _ | HObj _ | HArray | HVirtual _ | HDynObj | HAbstract _ | HEnum _ | HNull _ | HRef _ | HType | HMethod _ | HStruct _ -> true
258 | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HVoid -> false
259 | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HVoid | HPacked _ -> false
259260
260261 let is_struct = function
261 | HStruct _ -> true
262 | HStruct _ | HPacked _ -> true
262263 | _ -> false
263264
264265 let is_int = function
331332 p.pname = p2.pname || (match p.psuper with None -> false | Some p -> loop p)
332333 in
333334 loop p1
335 | HPacked t1, HStruct _ ->
336 safe_cast t1 t2
334337 | HFun (args1,t1), HFun (args2,t2) when List.length args1 = List.length args2 ->
335338 List.for_all2 (fun t1 t2 -> safe_cast t2 t1 || (t1 = HDyn && is_dynamic t2)) args1 args2 && safe_cast t1 t2
336339 | _ ->
381384 let types = ref PMap.empty in
382385 let arr = DynArray.create() in
383386 let rec get_type t =
384 (match t with HObj { psuper = Some p } -> get_type (HObj p) | _ -> ());
387 (match t with
388 | HObj { psuper = Some p } -> get_type (HObj p)
389 | HStruct { psuper = Some p } -> get_type (HStruct p)
390 | _ -> ());
385391 if PMap.mem t !types then () else
386392 let index = DynArray.length arr in
387393 DynArray.add arr t;
461467 | HEnum e ->
462468 "enum(" ^ e.ename ^ ")"
463469 | HNull t -> "null(" ^ tstr t ^ ")"
470 | HPacked t -> "packed(" ^ tstr t ^ ")"
464471
465472 let ostr fstr o =
466473 match o with
564571 | ORefData (r,d) -> Printf.sprintf "refdata %d, %d" r d
565572 | ORefOffset (r,r2,off) -> Printf.sprintf "refoffset %d, %d, %d" r r2 off
566573 | ONop s -> if s = "" then "nop" else "nop " ^ s
567
568574 let fundecl_name f = if snd f.fpath = "" then "fun$" ^ (string_of_int f.findex) else (fst f.fpath) ^ "." ^ (snd f.fpath)
569575
570576 let dump pr code =
10821082 | HEnum _ -> 18
10831083 | HNull _ -> 19
10841084 | HMethod _ -> 20
1085 | HStruct _ -> 21)))
1085 | HStruct _ -> 21
1086 | HPacked _ -> 22)))
10861087 | _ -> Globals.die "" __LOC__);
10871088 | ORef (r,v) ->
10881089 set r (VRef (RStack (v + spos),rtype v))
15321533 (match !cached_sys_name with
15331534 | Some n -> n
15341535 | None ->
1535 let ic = Unix.open_process_in "uname" in
1536 let ic, pid = Process_helper.open_process_args_in_pid "uname" [| "uname" |] in
15361537 let uname = (match input_line ic with
15371538 | "Darwin" -> "Mac"
15381539 | n -> n
15391540 ) in
1540 close_in ic;
1541 Pervasives.ignore (Process_helper.close_process_in_pid (ic, pid));
15411542 cached_sys_name := Some uname;
15421543 uname)
15431544 | "Win32" | "Cygwin" -> "Windows"
25442545 reg r (rtype r2);
25452546 reg off HI32;
25462547 | ONop _ ->
2547 ()
2548 ();
25482549 ) f.code
25492550 (* TODO : check that all path correctly initialize NULL values and reach a return *)
25502551 in
745745 r.ralias <- r;
746746 r
747747 ) in
748
749 let is_packed_field o fid =
750 match f.regs.(o) with
751 | HStruct p | HObj p ->
752 let ft = (try snd (resolve_field p fid) with Not_found -> assert false) in
753 (match ft with
754 | HPacked _ -> true
755 | _ -> false)
756 | _ ->
757 false
758 in
759
748760 (*
749761 let print_state i s =
750762 let state_str s =
855867 do_read o;
856868 do_write v;
857869 state.(v).rnullcheck <- state.(o).rnullcheck
870 | OField (r,o,fid) when (match f.regs.(r) with HStruct _ -> true | _ -> false) ->
871 do_read o;
872 do_write r;
873 if is_packed_field o fid then state.(r).rnullcheck <- true;
874 | OGetThis (r,fid) when (match f.regs.(r) with HStruct _ -> true | _ -> false) ->
875 do_write r;
876 if is_packed_field 0 fid then state.(r).rnullcheck <- true;
858877 | _ ->
859878 opcode_fx (fun r read ->
860879 if read then do_read r else do_write r
8484 | AttributeInnerClasses of jvm_inner_class array
8585 | AttributeEnclosingMethod of jvm_constant_pool_index * jvm_constant_pool_index
8686 | AttributeRuntimeVisibleAnnotations of j_annotation array
87 | AttributeRuntimeVisibleParameterAnnotations of j_annotation array array
8788 | AttributeBootstrapMethods of j_bootstrap_method array
8889
8990 let write_verification_type ch = function
165166 | ValClass i ->
166167 write_ui16 ch i
167168 | ValAnnotation a ->
168 write_annotation ch ann
169 write_annotation ch a
169170 | ValArray annl ->
170171 write_array16 ch loop annl
171172 in
234235 | AttributeRuntimeVisibleAnnotations al ->
235236 write_array16 ch write_annotation al;
236237 "RuntimeVisibleAnnotations"
238 | AttributeRuntimeVisibleParameterAnnotations al ->
239 write_byte ch (Array.length al);
240 Array.iter (write_array16 ch write_annotation) al;
241 "RuntimeVisibleParameterAnnotations"
237242 | AttributeBootstrapMethods a ->
238243 write_array16 ch (fun _ bm ->
239244 write_ui16 ch bm.bm_method_ref;
244249 {
245250 attr_index = pool#add (ConstUtf8 name);
246251 attr_data = IO.close_out ch
247 }
252 }
2828 | ABool of bool
2929 | AEnum of jsignature * string
3030 | AArray of annotation_kind list
31 | AAnnotation of jsignature * annotation
3132
3233 and annotation = (string * annotation_kind) list
3334
3435 type export_config = {
3536 export_debug : bool;
3637 }
38
39 let convert_annotations pool annotations =
40 let rec process_annotation (jsig, l) =
41 let offset = pool#add_string (generate_signature false jsig) in
42 let l = List.map (fun (name,ak) ->
43 let offset = pool#add_string name in
44 let rec loop ak = match ak with
45 | AInt i32 ->
46 'I',ValConst(pool#add (ConstInt i32))
47 | ADouble f ->
48 'D',ValConst(pool#add (ConstDouble f))
49 | AString s ->
50 's',ValConst(pool#add_string s)
51 | ABool b ->
52 'Z',ValConst(pool#add (ConstInt (if b then Int32.one else Int32.zero)))
53 | AEnum(jsig,name) ->
54 'e',ValEnum(pool#add_string (generate_signature false jsig),pool#add_string name)
55 | AArray l ->
56 let l = List.map (fun ak -> loop ak) l in
57 '[',ValArray(Array.of_list l)
58 | AAnnotation (jsig, a) ->
59 let ann = process_annotation (jsig, a) in
60 '@',ValAnnotation(ann)
61
62 in
63 offset,loop ak
64 ) l in
65 {
66 ann_type = offset;
67 ann_elements = Array.of_list l;
68 }
69 in
70 let a = Array.map process_annotation annotations in
71 a
3772
3873 class base_builder = object(self)
3974 val mutable access_flags = 0
5388 method private commit_annotations pool =
5489 if DynArray.length annotations > 0 then begin
5590 let open JvmAttribute in
56 let a = DynArray.to_array annotations in
57 let a = Array.map (fun (jsig,l) ->
58 let offset = pool#add_string (generate_signature false jsig) in
59 let l = List.map (fun (name,ak) ->
60 let offset = pool#add_string name in
61 let rec loop ak = match ak with
62 | AInt i32 ->
63 'I',ValConst(pool#add (ConstInt i32))
64 | ADouble f ->
65 'D',ValConst(pool#add (ConstDouble f))
66 | AString s ->
67 's',ValConst(pool#add_string s)
68 | ABool b ->
69 'Z',ValConst(pool#add (ConstInt (if b then Int32.one else Int32.zero)))
70 | AEnum(jsig,name) ->
71 'e',ValEnum(pool#add_string (generate_signature false jsig),pool#add_string name)
72 | AArray l ->
73 let l = List.map (fun ak -> loop ak) l in
74 '[',ValArray(Array.of_list l)
75 in
76 offset,loop ak
77 ) l in
78 {
79 ann_type = offset;
80 ann_elements = Array.of_list l;
81 }
82 ) a in
91 let a = convert_annotations pool (DynArray.to_array annotations) in
8392 self#add_attribute (AttributeRuntimeVisibleAnnotations a)
8493 end
8594
8695 method export_attributes (pool : JvmConstantPool.constant_pool) =
8796 DynArray.to_array (DynArray.map (write_attribute pool) attributes)
88 end
97 end
3939 val methods = DynArray.create ()
4040 val method_sigs = Hashtbl.create 0
4141 val inner_classes = Hashtbl.create 0
42 val closure_ids_per_name = Hashtbl.create 0
4243 val mutable spawned_methods = []
4344 val mutable static_init_method = None
4445 val mutable source_file = None
7677
7778 method has_method (name : string) (jsig : jsignature) =
7879 Hashtbl.mem method_sigs (name,generate_method_signature false jsig)
80
81 method get_next_closure_id (name : string) =
82 try
83 let r = Hashtbl.find closure_ids_per_name name in
84 incr r;
85 !r
86 with Not_found ->
87 let r = ref 0 in
88 Hashtbl.add closure_ids_per_name name r;
89 !r
7990
8091 method spawn_inner_class (jm : JvmMethod.builder option) (path_super : jpath) (name : string option) =
8192 let path = match name with
280280 end
281281
282282 type typed_function_kind =
283 | FuncLocal
283 | FuncLocal of string option
284284 | FuncMember of jpath * string
285285 | FuncStatic of jpath * string
286286
293293 jparams : string list;
294294 }
295295
296 let java_functional_interfaces =
297 let juf = ["java";"util";"function"] in
298 let tp name = TTypeParameter name in
299 [
300 {
301 jargs = [];
302 jret = None;
303 jpath = ["java";"lang"],"Runnable";
304 jname = "run";
305 jparams = []
306 };
307 {
308 jargs = [tp "T"];
309 jret = None;
310 jpath = juf,"Consumer";
311 jname = "accept";
312 jparams = ["T"]
313 };
314 {
315 jargs = [tp "T";tp "U"];
316 jret = None;
317 jpath = juf,"BiConsumer";
318 jname = "accept";
319 jparams = ["T";"U"]
320 };
321 {
322 jargs = [tp "T"];
323 jret = Some (tp "R");
324 jpath = juf,"Function";
325 jname = "apply";
326 jparams = ["T";"R"]
327 };
328 ]
296 let java_functional_interfaces = DynArray.create ()
297
298 let add args ret path name params =
299 let jfi = {
300 jargs = args;
301 jret = ret;
302 jpath = path;
303 jname = name;
304 jparams = params;
305 } in
306 DynArray.add java_functional_interfaces jfi
329307
330308 let unify jfi args ret =
331309 let rec loop params want have = match want,have with
356334 None
357335
358336
359 let find_compatible args ret =
360 ExtList.List.filter_map (fun jfi ->
361 if jfi.jparams = [] then begin
362 if jfi.jargs = args && jfi.jret = ret then
363 Some (jfi,[])
364 else None
337 let find_compatible args ret filter =
338 DynArray.fold_left (fun acc jfi ->
339 if filter = [] || List.mem jfi.jpath filter then begin
340 if jfi.jparams = [] then begin
341 if jfi.jargs = args && jfi.jret = ret then
342 (jfi,[]) :: acc
343 else
344 acc
345 end else match unify jfi args ret with
346 | Some x ->
347 x :: acc
348 | None ->
349 acc
365350 end else
366 unify jfi args ret
367 ) java_functional_interfaces
351 acc
352 ) [] java_functional_interfaces
368353 end
369354
370355 open JavaFunctionalInterfaces
381366
382367 val jc_closure =
383368 let name = match kind with
384 | FuncLocal ->
385 Printf.sprintf "Closure_%s_%i" (patch_name host_method#get_name) host_method#get_next_closure_id
369 | FuncLocal s ->
370 let name = patch_name host_method#get_name in
371 let name = match s with
372 | None -> name
373 | Some s -> name ^ "_" ^ s
374 in
375 Printf.sprintf "Closure_%s_%i" name (host_class#get_next_closure_id name)
386376 | FuncStatic(path,name) ->
387377 Printf.sprintf "%s_%s" (snd path) (patch_name name)
388378 | FuncMember(path,name) ->
405395 jm_ctor#return;
406396 jm_ctor
407397
408 method generate_invoke (args : (string * jsignature) list) (ret : jsignature option)=
398 method generate_invoke (args : (string * jsignature) list) (ret : jsignature option) (functional_interface_filter : jpath list) =
409399 let arg_sigs = List.map snd args in
410400 let meth = functions#register_signature arg_sigs ret in
411401 let jsig_invoke = method_sig arg_sigs ret in
418408 end
419409 in
420410 let spawn_forward_function meth_from meth_to is_bridge =
421 let flags = [MPublic] in
422 let flags = if is_bridge then MBridge :: MSynthetic :: flags else flags in
423 let jm_invoke_next = jc_closure#spawn_method meth_from.name (method_sig meth_from.dargs meth_from.dret) flags in
424 functions#make_forward_method jc_closure jm_invoke_next meth_from meth_to;
411 let msig = method_sig meth_from.dargs meth_from.dret in
412 if not (jc_closure#has_method meth_from.name msig) then begin
413 let flags = [MPublic] in
414 let flags = if is_bridge then MBridge :: MSynthetic :: flags else flags in
415 let jm_invoke_next = jc_closure#spawn_method meth_from.name msig flags in
416 functions#make_forward_method jc_closure jm_invoke_next meth_from meth_to;
417 end
425418 in
426419 let check_functional_interfaces meth =
427420 try
428 let l = JavaFunctionalInterfaces.find_compatible meth.dargs meth.dret in
421 let l = JavaFunctionalInterfaces.find_compatible meth.dargs meth.dret functional_interface_filter in
429422 List.iter (fun (jfi,params) ->
430423 add_interface jfi.jpath params;
431424 spawn_forward_function {meth with name=jfi.jname} meth false;
3030 | _ -> Int32.mul a (pow a (b - 1))
3131
3232 let java_hash s =
33 let high_surrogate c = (c lsr 10) + 0xD7C0 in
34 let low_surrogate c = (c land 0x3FF) lor 0xDC00 in
3335 let h = ref Int32.zero in
34 let l = UTF8.length s in
35 let i31 = Int32.of_int 31 in
36 let i = ref 0 in
37 UTF8.iter (fun char ->
38 let char = Int32.of_int (UCharExt.uint_code char) in
39 h := Int32.add !h (Int32.mul char (pow i31 (l - (!i + 1))));
40 incr i;
41 ) s;
36 let thirtyone = Int32.of_int 31 in
37 (try
38 UTF8.validate s;
39 UTF8.iter (fun c ->
40 let c = (UCharExt.code c) in
41 if c > 0xFFFF then
42 (h := Int32.add (Int32.mul thirtyone !h)
43 (Int32.of_int (high_surrogate c));
44 h := Int32.add (Int32.mul thirtyone !h)
45 (Int32.of_int (low_surrogate c)))
46 else
47 h := Int32.add (Int32.mul thirtyone !h)
48 (Int32.of_int c)
49 ) s
50 with UTF8.Malformed_code ->
51 String.iter (fun c ->
52 h := Int32.add (Int32.mul thirtyone !h)
53 (Int32.of_int (Char.code c))) s
54 );
4255 !h
4356
4457 module HashtblList = struct
140153 val mutable stack_frames = []
141154 val mutable exceptions = []
142155 val mutable argument_locals = []
156 val mutable argument_annotations = Hashtbl.create 0
143157 val mutable thrown_exceptions = Hashtbl.create 0
144 val mutable closure_count = 0
145158 val mutable regex_count = 0
146159
147160 (* per-frame *)
189202 | None -> JvmVerificationTypeInfo.VTop
190203 | _ -> JvmVerificationTypeInfo.of_signature jc#get_pool t
191204 ) locals
192
193 method get_next_closure_id =
194 let id = closure_count in
195 closure_count <- closure_count + 1;
196 id
197205
198206 method get_next_regex_id =
199207 let id = regex_count in
10011009 method replace_top jsig =
10021010 code#get_stack#replace jsig
10031011
1012 method add_argument_annotation (slot : int) (a : (path * annotation) list) =
1013 let a = Array.of_list (List.map (fun (path,annot) -> TObject(path,[]),annot) a) in
1014 Hashtbl.add argument_annotations slot a
1015
10041016 (** This function has to be called once all arguments are declared. *)
10051017 method finalize_arguments =
10061018 argument_locals <- locals
11221134 end;
11231135 if Hashtbl.length thrown_exceptions > 0 then
11241136 self#add_attribute (AttributeExceptions (Array.of_list (Hashtbl.fold (fun k _ c -> k :: c) thrown_exceptions [])));
1137 if Hashtbl.length argument_annotations > 0 then begin
1138 let l = List.length argument_locals in
1139 let offset = if self#has_method_flag MStatic then 0 else 1 in
1140 let a = Array.init (l - offset) (fun i ->
1141 try
1142 let annot = Hashtbl.find argument_annotations (i + offset) in
1143 convert_annotations jc#get_pool annot
1144 with Not_found ->
1145 [||]
1146 ) in
1147 DynArray.add attributes (AttributeRuntimeVisibleParameterAnnotations a)
1148 end;
11251149 let attributes = self#export_attributes jc#get_pool in
11261150 let offset_name = jc#get_pool#add_string name in
11271151 let jsig = generate_method_signature false jsig in
11381162 assert (code#get_fp = 0);
11391163 assert (not was_exported);
11401164 was_exported <- true;
1165 self#commit_annotations jc#get_pool;
11411166 let attributes = self#export_attributes jc#get_pool in
11421167 let offset_name = jc#get_pool#add_string name in
11431168 let jsig = generate_signature false jsig in
286286 mutable evals : eval IntMap.t;
287287 mutable exception_stack : (pos * env_kind) list;
288288 max_stack_depth : int;
289 max_print_depth : int;
290 print_indentation : string option;
289291 }
290292
291293 module GlobalState = struct
352354
353355 let call_function f vl = f vl
354356
355 let object_fields o =
356 IntMap.fold (fun key index acc ->
357 (key,(o.ofields.(index))) :: acc
358 ) o.oproto.pinstance_names []
357 let object_fields o = match o.oproto with
358 | OProto proto ->
359 IntMap.fold (fun key index acc ->
360 (key,(o.ofields.(index))) :: acc
361 ) proto.pinstance_names []
362 | ODictionary d ->
363 IntMap.fold (fun k v acc -> (k,v) :: acc) d []
359364
360365 let instance_fields i =
361366 IntMap.fold (fun name key acc ->
398403 let exc v = throw v null_pos
399404
400405 let exc_string str = exc (vstring (EvalString.create_ascii str))
406
407 let exc_string_p str p = throw (vstring (EvalString.create_ascii str)) p
401408
402409 let error_message = exc_string
403410
498505
499506 let get_static_prototype ctx path p =
500507 try get_static_prototype_raise ctx path
501 with Not_found -> Error.error (Printf.sprintf "[%i] Type not found: %s" ctx.ctx_id (rev_hash path)) p
508 with Not_found -> Error.typing_error (Printf.sprintf "[%i] Type not found: %s" ctx.ctx_id (rev_hash path)) p
502509
503510 let get_static_prototype_as_value ctx path p =
504511 (get_static_prototype ctx path p).pvalue
508515
509516 let get_instance_prototype ctx path p =
510517 try get_instance_prototype_raise ctx path
511 with Not_found -> Error.error (Printf.sprintf "[%i] Instance prototype not found: %s" ctx.ctx_id (rev_hash path)) p
518 with Not_found -> Error.typing_error (Printf.sprintf "[%i] Instance prototype not found: %s" ctx.ctx_id (rev_hash path)) p
512519
513520 let get_instance_constructor_raise ctx path =
514521 IntMap.find path ctx.constructors
515522
516523 let get_instance_constructor ctx path p =
517524 try get_instance_constructor_raise ctx path
518 with Not_found -> Error.error (Printf.sprintf "[%i] Instance constructor not found: %s" ctx.ctx_id (rev_hash path)) p
525 with Not_found -> Error.typing_error (Printf.sprintf "[%i] Instance constructor not found: %s" ctx.ctx_id (rev_hash path)) p
519526
520527 let get_special_instance_constructor_raise ctx path =
521528 Hashtbl.find (get_ctx()).builtins.constructor_builtins path
525532
526533 let get_proto_field_index proto name =
527534 try get_proto_field_index_raise proto name
528 with Not_found -> Error.error (Printf.sprintf "Field index for %s not found on prototype %s" (rev_hash name) (rev_hash proto.ppath)) null_pos
535 with Not_found -> Error.typing_error (Printf.sprintf "Field index for %s not found on prototype %s" (rev_hash name) (rev_hash proto.ppath)) null_pos
529536
530537 let get_instance_field_index_raise proto name =
531538 IntMap.find name proto.pinstance_names
532539
533540 let get_instance_field_index proto name p =
534541 try get_instance_field_index_raise proto name
535 with Not_found -> Error.error (Printf.sprintf "Field index for %s not found on prototype %s" (rev_hash name) (rev_hash proto.ppath)) p
542 with Not_found -> Error.typing_error (Printf.sprintf "Field index for %s not found on prototype %s" (rev_hash name) (rev_hash proto.ppath)) p
536543
537544 let is v path =
538545 if path = key_Dynamic then
196196 eval.debug_state <- old;
197197 raise exc
198198
199 exception NoValueExpr
200
199201 let rec expr_to_value ctx env e =
200202 let rec loop e = match fst e with
201203 | EConst cst ->
202204 begin match cst with
203205 | String(s,_) -> EvalString.create_unknown s
204 | Int s -> VInt32 (Int32.of_string s)
205 | Float s -> VFloat (float_of_string s)
206 | Int (s,_) -> VInt32 (Int32.of_string s)
207 | Float (s,_) -> VFloat (float_of_string s)
206208 | Ident "true" -> VTrue
207209 | Ident "false" -> VFalse
208210 | Ident "null" -> VNull
209211 | Ident s ->
210212 let value = resolve_ident ctx env s in
211213 value
212 | _ -> raise Exit
214 | _ -> raise NoValueExpr
213215 end
214216 | EArray(e1,eidx) ->
215217 let v1 = loop e1 in
216218 let vidx = loop eidx in
217 let idx = match vidx with VInt32 i -> Int32.to_int i | _ -> raise Exit in
219 let idx = match vidx with VInt32 i -> Int32.to_int i | _ -> raise NoValueExpr in
218220 begin match v1 with
219221 | VArray va -> EvalArray.get va idx
220222 | VVector vv -> Array.get vv idx
221223 | VEnumValue ev -> Array.get ev.eargs idx
222 | _ -> raise Exit
223 end
224 | EField(e1,s) ->
224 | _ -> raise NoValueExpr
225 end
226 | EField(e1,s,_) ->
225227 let v1 = loop e1 in
226228 let s' = hash s in
227229 begin match v1 with
256258 let v2 = loop e2 in
257259 write_expr ctx env e1 v2;
258260 | OpAssignOp op ->
259 raise Exit (* Nobody does that, right? *)
261 raise NoValueExpr
260262 | OpBoolAnd ->
261263 if is_true (loop e1) then loop e2
262264 else VFalse
263265 | OpBoolOr ->
264266 if is_true (loop e1) then VTrue
265267 else loop e2
268 | OpInterval | OpArrow | OpIn | OpNullCoal ->
269 raise NoValueExpr
266270 | _ ->
267271 let v1 = loop e1 in
268272 let v2 = loop e2 in
269273 let p = pos e in
270 (try get_binop_fun op p with _ -> raise Exit) v1 v2
274 (get_binop_fun op p) v1 v2
271275 end
272276 | EUnop(op,flag,e1) ->
273277 begin match op with
280284 begin match loop e1 with
281285 | VFloat f -> VFloat (-.f)
282286 | VInt32 i -> vint32 (Int32.neg i)
283 | _ -> raise Exit
287 | _ -> raise NoValueExpr
284288 end
285289 | NegBits ->
286290 op_sub (pos e) (vint32 (Int32.minus_one)) (loop e1)
287291 | Increment | Decrement | Spread ->
288 raise Exit
292 raise NoValueExpr
289293 end
290294 | ECall(e1,el) ->
291295 begin match fst e1 with
292 | EField(ethis,s) ->
296 | EField(ethis,s,_) ->
293297 let vthis = loop ethis in
294298 let v1 = EvalField.field vthis (hash s) in
295299 let vl = List.map loop el in
358362 let vc = loop2 ctx.toplevel ["Type";"createInstance"] in
359363 safe_call env.env_eval (call_value vc) [v1;encode_array vl]
360364 | ETry _ | ESwitch _ | EFunction _ | EFor _ | EDisplay _
361 | EDisplayNew _ | ECast(_,Some _) | EIs _ ->
362 raise Exit
365 | ECast(_,Some _) | EIs _ ->
366 raise NoValueExpr
363367 in
364368 loop e
365369
366370 and write_expr ctx env expr value =
367371 begin match fst expr with
368 | EField(e1,s) ->
372 | EField(e1,s,_) ->
369373 let s' = hash s in
370374 let v1 = expr_to_value ctx env e1 in
371375 begin match v1 with
393397 env.env_locals.(slot) <- value;
394398 value
395399 with Not_found ->
396 raise Exit
400 raise NoValueExpr
397401 end
398402 | EArray(e1,e2) ->
399403 let v1 = expr_to_value ctx env e1 in
400404 let vidx = expr_to_value ctx env e2 in
401 let idx = match vidx with VInt32 i -> Int32.to_int i | _ -> raise Exit in
405 let idx = match vidx with VInt32 i -> Int32.to_int i | _ -> raise NoValueExpr in
402406 begin match v1 with
403407 | VArray va -> EvalArray.set va idx value
404408 | VVector vv -> Array.set vv idx value
405409 | VEnumValue ev -> Array.set ev.eargs idx value
406 | _ -> raise Exit
410 | _ -> raise NoValueExpr
407411 end;
408412 value
409413 | _ ->
410 raise Exit
414 raise NoValueExpr
411415 end
412416
413417 let expr_to_value_safe ctx env e =
414418 try expr_to_value ctx env e
415 with Exit -> VNull
419 with NoValueExpr -> VNull
2222 let v = try
2323 f()
2424 with
25 | NoValueExpr ->
26 vnull
2527 | RunTimeException(v,stack,p) ->
2628 prerr_endline (EvalExceptions.get_exc_error_message ctx v stack p);
2729 vnull
8888
8989 let emit_const v _ = v
9090
91 let emit_null_check exec p env = match exec env with
92 | VNull -> throw_string "Null Access" p
93 | v -> v
94
9195 let emit_new_array env =
9296 encode_array_instance (EvalArray.create [||])
9397
94 let emit_new_vector_int i env =
95 encode_vector_instance (Array.make i vnull)
98 let emit_new_vector_int i p env =
99 if i < 0 then exc_string_p "Vector size must be >= 0" p;
100 let a = try
101 Array.make i vnull
102 with Invalid_argument _ ->
103 exc_string_p (Printf.sprintf "Not enough memory to allocate Vector of size %i" i) p;
104 in
105 encode_vector_instance a
96106
97107 let emit_new_vector exec p env =
98 encode_vector_instance (Array.make (decode_int_p (exec env) p) vnull)
108 let i = decode_int_p (exec env) p in
109 emit_new_vector_int i p env
99110
100111 let emit_special_instance f execs env =
101112 let vl = List.map (apply env) execs in
106117 Array.iter (fun (i,exec) -> a.(i) <- exec env) fa;
107118 vobject {
108119 ofields = a;
109 oproto = proto;
120 oproto = OProto proto;
110121 }
111122
112123 let emit_array_declaration execs env =
407418 let emit_anon_field_read exec proto i name p env =
408419 match vresolve (exec env) with
409420 | VObject o ->
410 if proto == o.oproto then o.ofields.(i)
411 else object_field o name
421 begin match o.oproto with
422 | OProto proto' when proto' == proto ->
423 o.ofields.(i)
424 | _ ->
425 object_field o name
426 end
412427 | VNull -> throw_string "field access on null" p
413428 | v -> field v name
414429
480495 let v2 = exec2 env in
481496 begin match vresolve v1 with
482497 | VObject o ->
483 if proto == o.oproto then begin
498 begin match o.oproto with
499 | OProto proto' when proto' == proto ->
484500 o.ofields.(i) <- v2;
485 end else set_object_field o name v2
486 | VNull -> throw_string "field access on null" p
501 | _ ->
502 set_object_field o name v2
503 end
504 | VNull ->
505 throw_string "field access on null" p
487506 | _ ->
488507 set_field v1 name v2;
489508 end;
140140 let proto,sorted = ctx.get_object_prototype ctx l in
141141 vobject {
142142 ofields = Array.of_list (List.map snd sorted);
143 oproto = proto;
143 oproto = OProto proto;
144144 }
145145
146146 let encode_obj_s l =
160160 let open MacroApi in
161161 let key = match i with
162162 | IExpr -> key_haxe_macro_ExprDef
163 | IEFieldKind -> key_haxe_macro_EFieldKind
163164 | IBinop -> key_haxe_macro_Binop
164165 | IUnop -> key_haxe_macro_Unop
165166 | IConst -> key_haxe_macro_Constant
180181 | IImportMode -> key_haxe_macro_ImportMode
181182 | IQuoteStatus -> key_haxe_macro_QuoteStatus
182183 | IDisplayKind -> key_haxe_macro_DisplayKind
184 | IDisplayMode -> key_haxe_macro_DisplayMode
185 | ICapturePolicy -> key_haxe_macro_CapturePolicy
186 | IVarScope -> key_haxe_macro_VarScope
187 | IVarScopingFlags -> key_haxe_macro_VarScopingFlags
188 | IPackageRule -> key_haxe_macro_PackageRule
183189 | IMessage -> key_haxe_macro_Message
184190 | IFunctionKind -> key_haxe_macro_FunctionKind
185191 | IStringLiteralKind -> key_haxe_macro_StringLiteralKind
324330 let encode_nullable encode_value o =
325331 match o with
326332 | Some v -> encode_value v
327 | None -> VNull
333 | None -> VNull
6666 let uncaught_exception_string v p extra =
6767 (Printf.sprintf "%s : Uncaught exception %s%s" (format_pos p) (value_string v) extra)
6868
69 let get_exc_error_stack ctx stack =
70 let pl = List.map (fun env -> {pfile = rev_hash env.env_info.pfile;pmin = env.env_leave_pmin; pmax = env.env_leave_pmax}) stack in
71 List.filter (fun p -> p <> null_pos) pl
72
6973 let get_exc_error_message ctx v stack p =
70 let pl = List.map (fun env -> {pfile = rev_hash env.env_info.pfile;pmin = env.env_leave_pmin; pmax = env.env_leave_pmax}) stack in
71 let pl = List.filter (fun p -> p <> null_pos) pl in
74 let pl = get_exc_error_stack ctx stack in
7275 match pl with
7376 | [] ->
7477 uncaught_exception_string v p ""
115118 final();
116119 Some v
117120 with
118 | RunTimeException(v,stack,p') ->
121 | RunTimeException(v,eval_stack,p') ->
119122 eval.caught_exception <- vnull;
120123 Option.may (build_exception_stack ctx) env;
121124 eval.env <- env;
122125 if is v key_haxe_macro_Error then begin
123126 let v1 = field v key_exception_message in
124127 let v2 = field v key_pos in
128 let v3 = field v key_child_errors in
129 let stack = match v3 with
130 | VArray sub ->
131 List.map (fun v ->
132 if is v key_haxe_macro_Error then begin
133 let v1 = field v key_exception_message in
134 let v2 = match (field v key_pos) with
135 | VInstance {ikind=IPos p} -> p
136 | _ -> null_pos
137 in
138 (Error.Custom (value_string v1), v2)
139 end else
140 Error.typing_error "Something went wrong" null_pos
141 ) (EvalArray.to_list sub)
142 | _ -> []
143 in
125144 reset_ctx();
126145 final();
127146 match v1 with
142161 )
143162 | _ -> null_pos
144163 in
145 raise (Error.Error (Error.Custom s.sstring,p))
164 (match stack with
165 | [] -> raise (Error.Error (Error.Custom s.sstring,p,0))
166 | _ -> raise (Error.Error (Stack ((Error.Custom (s.sstring),p) :: stack),p,0))
167 );
146168 | _ ->
147 Error.error "Something went wrong" null_pos
169 Error.typing_error "Something went wrong" null_pos
148170 end else begin
149171 (* Careful: We have to get the message before resetting the context because toString() might access it. *)
150 let stack = match stack with
172 let stack = match eval_stack with
151173 | [] -> []
152174 | l when p' = null_pos -> l (* If the exception position is null_pos, we're "probably" in a built-in function. *)
153175 | _ :: l -> l (* Otherwise, ignore topmost frame position. *)
154176 in
155 let msg = get_exc_error_message ctx v stack (if p' = null_pos then p else p') in
177 let stack = get_exc_error_stack ctx stack in
156178 reset_ctx();
157179 final();
158 Error.error msg null_pos
180 let p = if p' = null_pos then p else p' in
181 raise (Error.Error (Stack (
182 (Error.Custom ("Uncaught exception " ^ (value_string v)),p)
183 :: (List.map (fun p -> ((Error.Custom "Called from here"),p)) stack)
184 ),p,0))
159185 end
160186 | MacroApi.Abort ->
161187 final();
3636 let instance_field vi name =
3737 vi.ifields.(get_instance_field_index_raise vi.iproto name)
3838
39 let object_field_raise o name =
40 o.ofields.(get_instance_field_index_raise o.oproto name)
39 let object_field_raise o name = match o.oproto with
40 | OProto proto ->
41 o.ofields.(get_instance_field_index_raise proto name)
42 | ODictionary l ->
43 IntMap.find name l
4144
4245 let object_field o name =
4346 try object_field_raise o name with Not_found -> vnull
9393 let key_sys_io_FileInput = hash "sys.io.FileInput"
9494 let key_haxe_io_Eof = hash "haxe.io.Eof"
9595 let key_haxe_macro_ExprDef = hash "haxe.macro.ExprDef"
96 let key_haxe_macro_EFieldKind = hash "haxe.macro.EFieldKind"
9697 let key_haxe_macro_Binop = hash "haxe.macro.Binop"
9798 let key_haxe_macro_Unop = hash "haxe.macro.Unop"
9899 let key_haxe_macro_Constant = hash "haxe.macro.Constant"
113114 let key_haxe_macro_ImportMode = hash "haxe.macro.ImportMode"
114115 let key_haxe_macro_QuoteStatus = hash "haxe.macro.QuoteStatus"
115116 let key_haxe_macro_DisplayKind = hash "haxe.macro.DisplayKind"
117 let key_haxe_macro_DisplayMode = hash "haxe.macro.DisplayMode"
118 let key_haxe_macro_CapturePolicy = hash "haxe.macro.CapturePolicy"
119 let key_haxe_macro_VarScope = hash "haxe.macro.VarScope"
120 let key_haxe_macro_VarScopingFlags = hash "haxe.macro.VarScopingFlags"
121 let key_haxe_macro_PackageRule = hash "haxe.macro.PackageRule"
116122 let key_haxe_macro_Message = hash "haxe.macro.Message"
117123 let key_haxe_macro_FunctionKind = hash "haxe.macro.FunctionKind"
118124 let key_haxe_macro_StringLiteralKind = hash "haxe.macro.StringLiteralKind"
196202 let key_kind = hash "kind"
197203 let key_end = hash "end"
198204 let key_events = hash "events"
205 let key_child_errors = hash "childErrors"
199206 let key_isInternal = hash "isInternal"
200207 let key_physical = hash "physical"
201208 let key_address = hash "address"
202209 let key_netmask = hash "netmask"
203210 let key_previous = hash "previous"
204 let key_current = hash "current"
211 let key_current = hash "current"
2828 let high = decode_i32 (vi.ifields.(get_instance_field_index_raise vi.iproto key_high))
2929 and low = decode_i32 (vi.ifields.(get_instance_field_index_raise vi.iproto key_low)) in
3030 let high64 = GInt64.shift_left (Int32.to_int64 high) 32
31 and low64 = Int32.to_int64 low in
31 and low64 = GInt64.logand (Int32.to_int64 low) 0xffffffffL in
3232 GInt64.logor high64 low64
3333 | _ ->
3434 unexpected_value v "haxe.Int64"
266266 let i = decode_i64 v in
267267 VInt64 (Int64.lognot i)
268268 );
269 ]
269 ]
234234 List.iter (fun var -> ignore(get_capture_slot jit var)) jit_closure.captures_outside_scope;
235235 let captures = ExtList.List.filter_map (fun (i,vid,declared) ->
236236 if declared then None
237 else Some (i,fst (try Hashtbl.find jit.captures vid with Not_found -> Error.error "Something went wrong" e.epos))
237 else Some (i,fst (try Hashtbl.find jit.captures vid with Not_found -> Error.typing_error "Something went wrong" e.epos))
238238 ) captures in
239239 let mapping = Array.of_list captures in
240240 emit_closure ctx mapping eci hasret exec fl
428428 let i = get_proto_field_index proto name in
429429 lazy (match proto.pfields.(i) with VFunction (f,_) -> f | v -> cannot_call v e.epos)
430430 in
431 let jit_with_null_check ef =
432 let exec = jit_expr jit false ef in
433 emit_null_check exec ef.epos
434 in
431435 let instance_call c =
432 let exec = jit_expr jit false ef in
436 let exec = jit_with_null_check ef in
433437 let proto = get_instance_prototype ctx (path_hash c.cl_path) ef.epos in
434438 let v = lazy_proto_field proto in
435439 emit_proto_field_call v (exec :: execs) e.epos
436440 in
437441 let default () =
438 let exec = jit_expr jit false ef in
442 let exec = jit_with_null_check ef in
439443 emit_method_call exec name execs e.epos
440444 in
441445 begin match fa with
471475 end else
472476 default()
473477 | _ ->
474 let exec = jit_expr jit false ef in
478 let exec = jit_with_null_check ef in
475479 emit_field_call exec name execs e.epos
476480 end
477481 | TConst TSuper ->
506510 | TNew({cl_path=["eval"],"Vector"},_,[e1]) ->
507511 begin match e1.eexpr with
508512 | TConst (TInt i32) ->
509 emit_new_vector_int (Int32.to_int i32)
513 emit_new_vector_int (Int32.to_int i32) e1.epos
510514 | _ ->
511515 let exec1 = jit_expr jit false e1 in
512516 emit_new_vector exec1 e1.epos
632636 | TParenthesis e1 | TMeta(_,e1) | TCast(e1,None) ->
633637 loop e1
634638 | TIdent s ->
635 Error.error ("Unknown identifier: " ^ s) e.epos
639 Error.typing_error ("Unknown identifier: " ^ s) e.epos
636640 in
637641 let f = loop e in
638642 begin match ctx.debug.debug_socket with
9191 | `ENOTTY -> 75
9292 | `EFTYPE -> 76
9393 | `EILSEQ -> 77
94 | `EOVERFLOW -> 78
95 | `ESOCKTNOSUPPORT -> 79
9496 )
9597
9698 let decode_uv_error v : Error.t =
173175 | 75 -> `ENOTTY
174176 | 76 -> `EFTYPE
175177 | 77 -> `EILSEQ
178 | 78 -> `EOVERFLOW
179 | 79 -> `ESOCKTNOSUPPORT
176180 | _ -> unexpected_value v "eval.luv.UVError"
177181
178182 let luv_exception e =
541545 Error.set_on_unhandled_exception (fun ex ->
542546 let msg =
543547 match ex with
544 | HaxeError.Error (Custom msg,_) ->
548 | HaxeError.Error (Custom msg,_,_) ->
545549 (* Eval interpreter rethrows runtime exceptions as `Custom "Exception message\nException stack"` *)
546550 (try fst (ExtString.String.split msg "\n")
547551 with _ -> msg)
548 | HaxeError.Error (err,_) -> HaxeError.error_msg err
552 | HaxeError.Error (err,p,_) ->
553 (* TODO hook global error reporting *)
554 (match (extract_located (HaxeError.error_msg p err)) with
555 | [] -> ""
556 | (s,_) :: [] -> s
557 | (s,_) :: stack ->
558 List.fold_left (fun acc (s,p) ->
559 Printf.sprintf "%s%s\n" acc (Lexer.get_error_pos (Printf.sprintf "%s:%d: ") p)
560 ) (s ^ "\n") stack
561 );
549562 | _ -> Printexc.to_string ex
550563 in
551564 let e = create_haxe_exception ~stack:(get_ctx()).exception_stack msg in
15781591 end
15791592
15801593 let file_fields = [
1581 "get_stdin", VHandle (HFile File.stdin);
1582 "get_stdout", VHandle (HFile File.stdout);
1583 "get_stderr", VHandle (HFile File.stderr);
1594 "stdin", VHandle (HFile File.stdin);
1595 "stdout", VHandle (HFile File.stdout);
1596 "stderr", VHandle (HFile File.stderr);
15841597 "createRequest", vfun0 (fun() ->
15851598 VHandle (HFileRequest (File.Request.make()))
15861599 );
21392152 let name = decode_string v1
21402153 and value = decode_native_string v2 in
21412154 encode_unit_result (Env.setenv name ~value)
2155 );
2156 "unsetEnv", vfun1 (fun v ->
2157 let name = decode_string v in
2158 encode_unit_result (Env.unsetenv name)
21422159 );
21432160 "environ", vfun0 (fun() ->
21442161 let encode env =
122122 (* eval *)
123123 toplevel = vobject {
124124 ofields = [||];
125 oproto = fake_proto key_eval_toplevel;
125 oproto = OProto (fake_proto key_eval_toplevel);
126126 };
127127 eval = eval;
128128 evals = evals;
129129 exception_stack = [];
130130 max_stack_depth = int_of_string (Common.defined_value_safe ~default:"1000" com Define.EvalCallStackDepth);
131 max_print_depth = int_of_string (Common.defined_value_safe ~default:"5" com Define.EvalPrintDepth);
132 print_indentation = match Common.defined_value_safe com Define.EvalPrettyPrint
133 with | "" -> None | "1" -> Some " " | indent -> Some indent;
131134 } in
132135 if debug.support_debugger && not !GlobalState.debugger_initialized then begin
133136 (* Let's wait till the debugger says we're good to continue. This allows it to finish configuration.
147150 | _ ->
148151 let msg =
149152 match ex with
150 | Error.Error (err,_) -> Error.error_msg err
153 | Error.Error (err,p,_) ->
154 (* TODO hook global error reporting *)
155 (match (extract_located (Error.error_msg p err)) with
156 | [] -> ""
157 | (s,_) :: [] -> s
158 | (s,_) :: stack ->
159 List.fold_left (fun acc (s,p) ->
160 Printf.sprintf "%s%s\n" acc (Lexer.get_error_pos (Printf.sprintf "%s:%d: ") p)
161 ) (s ^ "\n") stack
162 );
151163 | _ -> Printexc.to_string ex
152164 in
153165 Printf.eprintf "%s\n" msg;
397409 let add_types ctx types ready =
398410 if not ctx.had_error then ignore(catch_exceptions ctx (fun () -> ignore(add_types ctx types ready)) null_pos)
399411
400 let compiler_error msg pos =
412 let make_runtime_error msg pos =
401413 let vi = encode_instance key_haxe_macro_Error in
402414 match vi with
403415 | VInstance i ->
404 let msg = EvalString.create_unknown msg in
405 set_instance_field i key_exception_message msg;
416 let s = EvalString.create_unknown msg in
417 set_instance_field i key_exception_message s;
406418 set_instance_field i key_pos (encode_pos pos);
407 set_instance_field i key_native_exception msg;
408 let ctx = get_ctx() in
409 let eval = get_eval ctx in
410 (match eval.env with
411 | Some _ ->
412 let stack = EvalStackTrace.make_stack_value (call_stack eval) in
413 set_instance_field i key_native_stack stack;
414 | None -> ());
415 exc vi
419 set_instance_field i key_native_exception s;
420 vi
416421 | _ ->
417422 die "" __LOC__
423
424 let compiler_error msg =
425 let pos = extract_located_pos msg in
426 let items = extract_located msg in
427 let vi = make_runtime_error (fst (List.hd items)) pos in
428 match vi with
429 | VInstance i ->
430 (match items with
431 | [] | _ :: [] ->
432 let ctx = get_ctx() in
433 let eval = get_eval ctx in
434 (match eval.env with
435 | Some _ ->
436 let stack = EvalStackTrace.make_stack_value (call_stack eval) in
437 set_instance_field i key_native_stack stack;
438 | None -> ());
439
440 | (hd :: stack) ->
441 let stack = List.map (fun (s,p) -> make_runtime_error s p) stack in
442 set_instance_field i key_child_errors (encode_array stack);
443 );
444
445 exc vi
446 | _ ->
447 die "" __LOC__
418448
419449 let rec value_to_expr v p =
420450 let path i =
423453 let rec loop = function
424454 | [] -> die "" __LOC__
425455 | [name] -> (EConst (Ident name),p)
426 | name :: l -> (EField (loop l,name),p)
456 | name :: l -> (efield (loop l,name),p)
427457 in
428458 let t = t_infos t in
429459 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]))
438468 | VNull -> (EConst (Ident "null"),p)
439469 | VTrue -> (EConst (Ident "true"),p)
440470 | VFalse -> (EConst (Ident "false"),p)
441 | VInt32 i -> (EConst (Int (Int32.to_string i)),p)
471 | VInt32 i -> (EConst (Int (Int32.to_string i,None)),p)
442472 | VFloat f -> haxe_float f p
443473 | VString s -> (EConst (String(s.sstring,SDoubleQuotes)),p)
444474 | VArray va -> (EArrayDecl (List.map (fun v -> value_to_expr v p) (EvalArray.to_list va)),p)
458488 | PEnum names -> fst (List.nth names e.eindex)
459489 | _ -> die "" __LOC__
460490 in
461 (EField (expr, name), p)
491 (efield (expr, name), p)
462492 in
463493 begin
464494 match e.eargs with
469499 end
470500 | VInstance {ikind = IIntMap m} ->
471501 let el = IntHashtbl.fold (fun k v acc ->
472 let e_key = (EConst (Int (string_of_int k)),p) in
502 let e_key = (EConst (Int (string_of_int k, None)),p) in
473503 (make_map_entry e_key v) :: acc
474504 ) m [] in
475505 (EArrayDecl el,p)
554584 | _ -> error "expected Bool" v
555585 end
556586 | TType(t,tl) ->
557 loop tabs (apply_params t.t_params tl t.t_type) v
587 loop tabs (apply_typedef t tl) v
558588 | TAbstract({a_path=["haxe";"macro"],"Position"},_) ->
559589 begin match v with
560590 | VInstance {ikind=IPos _} -> f "#pos"
3838 let ctx = get_ctx() in
3939 let proto,fields = ctx.get_object_prototype (get_ctx()) fields in
4040 o.ofields <- Array.of_list (List.map snd fields);
41 o.oproto <- proto
41 o.oproto <- OProto proto
4242
4343 (* Calls *)
4444
5858 vi.ifields.(get_instance_field_index_raise vi.iproto name) <- v2
5959
6060 let set_object_field o name v2 =
61 try
62 o.ofields.(get_instance_field_index_raise o.oproto name) <- v2;
63 with Not_found ->
64 let fields = IntMap.fold (fun name i acc -> (name,o.ofields.(i)) :: acc) o.oproto.pinstance_names [] in
65 let fields = (name,v2) :: fields in
66 update_object_prototype o fields
61 match o.oproto with
62 | OProto proto ->
63 begin try
64 o.ofields.(get_instance_field_index_raise proto name) <- v2;
65 with Not_found ->
66 let fields = IntMap.fold (fun name i acc -> (name,o.ofields.(i)) :: acc) proto.pinstance_names [] in
67 let fields = (name,v2) :: fields in
68 update_object_prototype o fields
69 end
70 | ODictionary d ->
71 o.oproto <- ODictionary (IntMap.add name v2 d)
72
73 (* Turns prototypes into dictionaries if the field doesn't exist. *)
74 let set_object_field_runtime o name v2 =
75 let update_dictionary d =
76 IntMap.add name v2 d
77 in
78 let make_dictionary proto =
79 IntMap.map (fun i -> o.ofields.(i)) proto.pinstance_names
80 in
81 match o.oproto with
82 | OProto proto ->
83 begin try
84 o.ofields.(get_instance_field_index_raise proto name) <- v2;
85 with Not_found ->
86 let d = make_dictionary proto in
87 let d = update_dictionary d in
88 o.oproto <- ODictionary d
89 end
90 | ODictionary d ->
91 let d = update_dictionary d in
92 o.oproto <- ODictionary d
6793
6894 let set_bytes_length_field v1 v2 =
6995 match v1 with
86112 | VInstance {ikind = IBytes _} -> set_bytes_length_field v1 v2
87113 | VInstance vi -> set_instance_field vi name v2
88114 | _ -> unexpected_value v1 "object"
115
116 let set_field_runtime v1 name v2 = match vresolve v1 with
117 | VObject o -> set_object_field_runtime o name v2
118 | _ -> set_field v1 name v2
89119
90120 (* Equality/compare *)
91121
217247 | _ -> invalid_binop OpXor v1 v2 p
218248
219249 let op_shl p v1 v2 = match v1,v2 with
220 | VInt32 i1,VInt32 i2 -> vint32 (Int32.shift_left i1 (Int32.to_int i2))
250 | VInt32 i1,VInt32 i2 ->
251 let i2 = Int32.logand i2 i32_31 in
252 let i2 = Int32.to_int i2 in
253 vint32 (Int32.shift_left i1 i2)
221254 | _ -> invalid_binop OpShl v1 v2 p
222255
223256 let op_shr p v1 v2 = match v1,v2 with
224 | VInt32 i1,VInt32 i2 -> vint32 (Int32.shift_right i1 (Int32.to_int i2))
257 | VInt32 i1,VInt32 i2 ->
258 let i2 = Int32.logand i2 i32_31 in
259 let i2 = Int32.to_int i2 in
260 vint32 (Int32.shift_right i1 i2)
225261 | _ -> invalid_binop OpShr v1 v2 p
226262
227263 let op_ushr p v1 v2 = match v1,v2 with
228 | VInt32 i1,VInt32 i2 -> vint32 (Int32.shift_right_logical i1 (Int32.to_int i2))
264 | VInt32 i1,VInt32 i2 ->
265 let i2 = Int32.logand i2 i32_31 in
266 let i2 = Int32.to_int i2 in
267 vint32 (Int32.shift_right_logical i1 i2)
229268 | _ -> invalid_binop OpUShr v1 v2 p
230269
231270 let op_mod p v1 v2 = match v1,v2 with
253292 | OpShr -> op_shr p
254293 | OpUShr -> op_ushr p
255294 | OpMod -> op_mod p
256 | OpAssign | OpBoolAnd | OpBoolOr | OpAssignOp _ | OpInterval | OpArrow | OpIn -> die "" __LOC__
295 | OpAssign | OpBoolAnd | OpBoolOr | OpAssignOp _ | OpInterval | OpArrow | OpIn | OpNullCoal -> die ~p "" __LOC__
257296
258297 let prepare_callback v n =
259298 match v with
4848
4949 let s_hash key = create_ascii (EvalHash.rev_hash key)
5050
51 let rec s_object depth o =
51 let rec indent buf s n =
52 match n with
53 | 0 -> ()
54 | _ -> begin
55 Buffer.add_string buf s;
56 indent buf s (n - 1)
57 end
58
59 let rec s_object depth indent_level o =
5260 let fields = object_fields o in
5361 let buf = Buffer.create 0 in
62 let inner_indent_level = indent_level + 1 in
63
5464 Buffer.add_string buf "{";
65 (match (get_ctx()).print_indentation with
66 | None -> ()
67 | Some s -> begin
68 Buffer.add_string buf "\n";
69 indent buf s inner_indent_level
70 end);
71
5572 List.iteri (fun i (k,v) ->
56 if i > 0 then Buffer.add_string buf ", ";
73 if i > 0 then begin
74 match (get_ctx()).print_indentation with
75 | None -> Buffer.add_string buf ", "
76 | Some s -> begin
77 Buffer.add_string buf ",\n";
78 indent buf s inner_indent_level
79 end;
80 end;
81
5782 Buffer.add_string buf (rev_hash k);
5883 Buffer.add_string buf ": ";
59 Buffer.add_string buf (s_value depth v).sstring;
84 Buffer.add_string buf (s_value ~indent_level:inner_indent_level depth v).sstring;
6085 ) fields;
86
87 (match (get_ctx()).print_indentation with
88 | None -> ()
89 | Some s -> begin
90 Buffer.add_string buf "\n";
91 indent buf s indent_level
92 end);
93
6194 Buffer.add_string buf "}";
6295 let s = Buffer.contents buf in
6396 create_with_length s (try UTF8.length s with _ -> String.length s)
6497
65 and s_array depth va =
98 and s_array depth indent_level va =
6699 join empty_string [
67100 rbkopen;
68 EvalArray.join va (s_value depth) rcomma;
101 EvalArray.join va (s_value ~indent_level depth) rcomma;
69102 rbkclose;
70103 ]
71104
72 and s_vector depth vv =
105 and s_vector depth indent_level vv =
73106 join empty_string [
74107 rbkopen;
75 EvalArray.join (EvalArray.create vv) (s_value depth) rcomma;
108 EvalArray.join (EvalArray.create vv) (s_value ~indent_level depth) rcomma;
76109 rbkclose;
77110 ]
78111
84117 end
85118 with Not_found -> "#unknown"
86119
87 and s_enum_value depth ve =
120 and s_enum_value depth indent_level ve =
88121 let name = s_enum_ctor_name ve in
89122 match ve.eargs with
90123 | [||] -> create_ascii name
92125 join empty_string [
93126 create_ascii name;
94127 rpopen;
95 join rcomma (Array.to_list (Array.map (s_value (depth + 1)) vl));
128 join rcomma (Array.to_list (Array.map (s_value ~indent_level (depth + 1)) vl));
96129 rpclose;
97130 ]
98131
101134 | PEnum _ -> join empty_string [create_ascii "Enum<"; s_hash proto.ppath; rgt]
102135 | PInstance | PObject -> die "" __LOC__
103136
104 and s_value depth v =
137 and s_value ?(indent_level=0) depth v =
105138 let call_to_string () =
106139 let vf = field_raise v EvalHash.key_toString in
107 s_value (depth + 1) (call_value_on v vf [])
140 s_value ~indent_level (depth + 1) (call_value_on v vf [])
108141 in
109 if depth > 5 then rstop
142 if depth > (get_ctx()).max_print_depth then rstop
110143 else match v with
111144 | VNull -> rnull
112145 | VInt32 i32 -> create_ascii(Int32.to_string i32)
121154 | VFunction (f,_) -> rfun
122155 | VFieldClosure _ -> rclosure
123156 | VHandle _ -> rhandle
124 | VEnumValue ve -> s_enum_value depth ve
157 | VEnumValue ve -> s_enum_value depth indent_level ve
125158 | VString s -> s
126159 | VNativeString s -> create_unknown_vstring s
127 | VArray va -> s_array (depth + 1) va
128 | VVector vv -> s_vector (depth + 1) vv
160 | VArray va -> s_array (depth + 1) indent_level va
161 | VVector vv -> s_vector (depth + 1) indent_level vv
129162 | VInstance {ikind=IDate d} -> s_date d
130163 | VInstance {ikind=IPos p} -> create_ascii ("#pos(" ^ Lexer.get_error_pos (Printf.sprintf "%s:%d:") p ^ ")") (* STODO: not ascii? *)
131164 | VInstance {ikind=IRegex r} -> r.r_rex_string
132165 | VInstance i -> (try call_to_string () with Not_found -> s_hash i.iproto.ppath)
133 | VObject o -> (try call_to_string () with Not_found -> s_object (depth + 1) o)
134 | VLazy f -> s_value depth (!f())
166 | VObject o -> (try call_to_string () with Not_found -> s_object (depth + 1) indent_level o)
167 | VLazy f -> s_value ~indent_level depth (!f())
135168 | VPrototype proto ->
136169 try
137170 call_to_string()
288288
289289 let get_object_prototype ctx l =
290290 let l = List.sort (fun (i1,_) (i2,_) -> if i1 = i2 then 0 else if i1 < i2 then -1 else 1) l in
291 let sfields = String.concat "," (List.map (fun (i,_) -> (Printf.sprintf ":%s" (rev_hash i))) l) in
292 let name = hash (Printf.sprintf "eval.object.Object[%s]" sfields) in
293 try
294 IntMap.find name ctx.instance_prototypes,l
295 with Not_found ->
296 let pctx = PrototypeBuilder.create ctx name None PObject None in
297 List.iter (fun (name,_) -> PrototypeBuilder.add_instance_field pctx name (lazy vnull)) l;
298 let proto = fst (PrototypeBuilder.finalize pctx) in
299 ctx.instance_prototypes <- IntMap.add name proto ctx.instance_prototypes;
300 proto,l
291 let proto =
292 let sfields = String.concat "," (List.map (fun (i,_) -> (Printf.sprintf ":%s" (rev_hash i))) l) in
293 let name = hash (Printf.sprintf "eval.object.Object[%s]" sfields) in
294 try
295 IntMap.find name ctx.instance_prototypes
296 with Not_found ->
297 let pctx = PrototypeBuilder.create ctx name None PObject None in
298 List.iter (fun (name,_) -> PrototypeBuilder.add_instance_field pctx name (lazy vnull)) l;
299 let proto = fst (PrototypeBuilder.finalize pctx) in
300 ctx.instance_prototypes <- IntMap.add name proto ctx.instance_prototypes;
301 proto
302 in
303 proto,l
301304
302305 let add_types ctx types ready =
303306 let t = Timer.timer [(if ctx.is_macro then "macro" else "interp");"add_types"] in
238238 )
239239
240240 let toString = vifun0 (fun vthis ->
241 vstring (s_array 0 (this vthis))
241 vstring (s_array 0 0 (this vthis))
242242 )
243243
244244 let unshift = vifun1 (fun vthis v ->
439439 )
440440
441441 let toString = vifun0 (fun vthis ->
442 (create_unknown (Bytes.to_string (this vthis)))
442 let this = this vthis in
443 try
444 UTF8.validate (Bytes.unsafe_to_string this);
445 (create_unknown (Bytes.to_string this))
446 with UTF8.Malformed_code ->
447 exc_string "Invalid string"
443448 )
444449 end
445450
753758 end
754759
755760 module StdEReg = struct
756 open Pcre
761 open Pcre2
757762
758763 let create r opt =
759 let open Pcre in
764 let open Pcre2 in
760765 let string_of_pcre_error = function
761766 | BadPattern(s,i) -> Printf.sprintf "at %i: %s" i s
762767 | Partial -> "Partial"
763 | BadPartial -> "BadPartial"
764 | BadUTF8 -> "BadUTF8"
765 | BadUTF8Offset -> "BadUTF8Offset"
768 | BadUTF -> "BadUTF"
769 | BadUTFOffset -> "BadUTFOffset"
766770 | MatchLimit -> "MatchLimit"
767 | RecursionLimit -> "RecursionLimit"
771 | DepthLimit -> "DepthLimit"
772 | WorkspaceSize -> "WorkspaceSize"
768773 | InternalError s -> "InternalError: " ^ s
769774 in
770775 let global = ref false in
776781 | 'g' -> global := true; None
777782 | c -> failwith ("Unsupported regexp option '" ^ String.make 1 c ^ "'")
778783 ) (ExtString.String.explode opt) in
779 let flags = `UTF8 :: `UCP :: flags in
784 let flags = `UTF :: `UCP :: flags in
780785 let rex = try regexp ~flags r with Error error -> failwith (string_of_pcre_error error) in
781786 let pcre = {
782787 r = rex;
843848
844849 let match' = vifun1 (fun vthis s ->
845850 let this = this vthis in
846 let open Pcre in
851 let open Pcre2 in
847852 let s = decode_string s in
848853 this.r_string <- s;
849854 try
850 let a = exec_all ~iflags:0x2000 ~rex:this.r s in
855 let a = exec_all ~flags:[`NO_UTF_CHECK] ~rex:this.r s in
851856 this.r_groups <- a;
852857 vtrue
853858 with Not_found ->
854859 this.r_groups <- [||];
855860 vfalse
856 | Pcre.Error _ ->
861 | Pcre2.Error _ ->
857862 exc_string "PCRE Error (invalid unicode string?)"
858863 )
859864
907912 begin try
908913 if pos + len > String.length s then raise Not_found;
909914 let str = String.sub s 0 (pos + len) in
910 let a = Pcre.exec_all ~iflags:0x2000 ~rex:this.r ~pos str in
915 let a = Pcre2.exec_all ~flags:[`NO_UTF_CHECK] ~rex:this.r ~pos str in
911916 this.r_string <- s;
912917 this.r_groups <- a;
913918 vtrue
920925 let this = this vthis in
921926 let s = decode_string s in
922927 let by = decode_string by in
923 let s = (if this.r_global then Pcre.replace else Pcre.replace_first) ~iflags:0x2000 ~rex:this.r ~templ:by s in
928 let s = (if this.r_global then Pcre2.replace else Pcre2.replace_first) ~flags:[`NO_UTF_CHECK] ~rex:this.r ~templ:by s in
924929 create_unknown s
925930 )
926931
937942 let sub = String.sub s first (last - first) in
938943 DynArray.add acc (create_unknown sub)
939944 in
940 let exec = Pcre.exec ~iflags:0x2000 ~rex:this.r in
945 let exec = Pcre2.exec ~flags:[`NO_UTF_CHECK] ~rex:this.r in
941946 let step pos =
942947 try
943948 let substrings = exec ~pos s in
944 let (first,last) = Pcre.get_substring_ofs substrings 0 in
949 let (first,last) = Pcre2.get_substring_ofs substrings 0 in
945950 add !copy_offset first;
946951 copy_offset := last;
947952 let next_start = if pos = last then last + 1 else last in
13951400
13961401 let resolve = vfun1 (fun name ->
13971402 let name = decode_string name in
1398 let h = catch_unix_error Unix.gethostbyname name in
1403 let h = try Unix.gethostbyname name with Not_found -> exc_string (Printf.sprintf "Could not resolve host %s" name) in
13991404 let addr = catch_unix_error Unix.string_of_inet_addr h.h_addr_list.(0) in
14001405 let a, b, c, d = Scanf.sscanf addr "%d.%d.%d.%d" (fun a b c d -> a,b,c,d) in
14011406 vint32 (Int32.logor (Int32.shift_left (Int32.of_int a) 24) (Int32.of_int (d lor (c lsl 8) lor (b lsl 16))))
15371542 let l = IntHashtbl.fold (fun key vvalue acc ->
15381543 (join empty_string [create_ascii (string_of_int key); create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in
15391544 let s = join rcomma l in
1540 let s = join empty_string [rbropen;s;rbrclose] in
1545 let s = join empty_string [rbkopen;s;rbkclose] in
15411546 vstring s
15421547 )
15431548
15961601 let l = StringHashtbl.fold (fun _ (key,vvalue) acc ->
15971602 (join empty_string [key; create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in
15981603 let s = join rcomma l in
1599 let s = join empty_string [rbropen;s;rbrclose] in
1604 let s = join empty_string [rbkopen;s;rbkclose] in
16001605 vstring s
16011606 )
16021607
16541659 let l = ValueHashtbl.fold (fun key vvalue acc ->
16551660 (join empty_string [s_value 0 key; create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in
16561661 let s = join rcomma l in
1657 let s = join empty_string [rbropen;s;rbrclose] in
1662 let s = join empty_string [rbkopen;s;rbkclose] in
16581663 vstring s
16591664 )
16601665
18811886 let name = hash (decode_vstring name).sstring in
18821887 match vresolve o with
18831888 | VObject o ->
1884 let found = ref false in
1885 let fields = IntMap.fold (fun name' i acc ->
1886 if name = name' then begin
1887 found := true;
1888 acc
1889 begin match o.oproto with
1890 | OProto proto ->
1891 let found = ref false in
1892 let fields = IntMap.fold (fun name' i acc ->
1893 if name = name' then begin
1894 found := true;
1895 acc
1896 end else
1897 (name',o.ofields.(i)) :: acc
1898 ) proto.pinstance_names [] in
1899 if !found then begin
1900 update_object_prototype o fields;
1901 vtrue
18891902 end else
1890 (name',o.ofields.(i)) :: acc
1891 ) o.oproto.pinstance_names [] in
1892 if !found then begin
1893 update_object_prototype o fields;
1894 vtrue
1895 end else
1896 vfalse
1903 vfalse
1904 | ODictionary d ->
1905 let has = IntMap.mem name d in
1906 if has then o.oproto <- ODictionary (IntMap.remove name d);
1907 vbool has
1908 end
18971909 | _ ->
18981910 vfalse
18991911 )
19301942 let hasField = vfun2 (fun o field ->
19311943 let name = hash (decode_vstring field).sstring in
19321944 let b = match vresolve o with
1933 | VObject o -> IntMap.mem name o.oproto.pinstance_names
1945 | VObject o ->
1946 begin match o.oproto with
1947 | OProto proto -> IntMap.mem name proto.pinstance_names
1948 | ODictionary d -> IntMap.mem name d
1949 end
19341950 | VInstance vi -> IntMap.mem name vi.iproto.pinstance_names || IntMap.mem name vi.iproto.pnames
19351951 | VPrototype proto -> IntMap.mem name proto.pnames
1936 | _ -> unexpected_value o "object"
1952 | _ -> false (* issue #10993 *)
19371953 in
19381954 vbool b
19391955 )
19591975 )
19601976
19611977 let setField = vfun3 (fun o name v ->
1962 (try set_field o (hash (decode_vstring name).sstring) v with Not_found -> ()); vnull
1978 (try set_field_runtime o (hash (decode_vstring name).sstring) v with Not_found -> ()); vnull
19631979 )
19641980
19651981 let setProperty = vfun3 (fun o name v ->
19681984 let vset = field o name_set in
19691985 if vset <> VNull then call_value_on o vset [v]
19701986 else begin
1971 (try set_field o (hash name.sstring) v with Not_found -> ());
1987 (try set_field_runtime o (hash name.sstring) v with Not_found -> ());
19721988 vnull
19731989 end
19741990 )
25732589 )
25742590
25752591 let exit = vfun1 (fun code ->
2576 (* TODO: Borrowed from interp.ml *)
2577 if (get_ctx()).curapi.use_cache() then raise (Error.Fatal_error ("",Globals.null_pos));
25782592 raise (Sys_exit(decode_int code));
25792593 )
25802594
26252639 | _ -> vnull
26262640 )
26272641
2628 let putEnv = vfun2 (fun s v ->
2629 let s = decode_string s in
2630 let v = decode_string v in
2631 catch_unix_error Unix.putenv s v;
2632 vnull
2642 let putEnv = vfun2 (fun s -> function
2643 | v when v = vnull ->
2644 let _ = Luv.Env.unsetenv (decode_string s) in vnull
2645 | v ->
2646 let s = decode_string s in
2647 let v = decode_string v in
2648 catch_unix_error Unix.putenv s v;
2649 vnull
26332650 )
26342651
26352652 let setCwd = vfun1 (fun s ->
26672684 (match !cached_sys_name with
26682685 | Some n -> n
26692686 | None ->
2670 let ic = catch_unix_error Unix.open_process_in "uname" in
2687 let ic, pid = catch_unix_error Process_helper.open_process_args_in_pid "uname" [| "uname" |] in
26712688 let uname = (match input_line ic with
26722689 | "Darwin" -> "Mac"
26732690 | n -> n
26742691 ) in
2675 close_in ic;
2692 Pervasives.ignore (Process_helper.close_process_in_pid (ic, pid));
26762693 cached_sys_name := Some uname;
26772694 uname)
26782695 | "Win32" | "Cygwin" -> "Windows"
33303347 Hashtbl.add h key_Array (fun () -> encode_array_instance (EvalArray.create [||]));
33313348 Hashtbl.add h key_eval_Vector (fun () -> encode_vector_instance (Array.make 0 vnull));
33323349 Hashtbl.add h key_Date (fun () -> encode_instance key_Date ~kind:(IDate 0.));
3333 Hashtbl.add h key_EReg (fun () -> encode_instance key_EReg ~kind:(IRegex {r = Pcre.regexp ""; r_rex_string = create_ascii "~//"; r_global = false; r_string = ""; r_groups = [||]}));
3350 Hashtbl.add h key_EReg (fun () -> encode_instance key_EReg ~kind:(IRegex {r = Pcre2.regexp ""; r_rex_string = create_ascii "~//"; r_global = false; r_string = ""; r_groups = [||]}));
33343351 Hashtbl.add h key_String (fun () -> v_empty_string);
33353352 Hashtbl.add h key_haxe_ds_StringMap (fun () -> encode_instance key_haxe_ds_StringMap ~kind:(IStringMap (StringHashtbl.create ())));
33363353 Hashtbl.add h key_haxe_ds_IntMap (fun () -> encode_instance key_haxe_ds_IntMap ~kind:(IIntMap (IntHashtbl.create ())));
38223839 init_fields builtins (["eval";"luv";"_Prepare"], "Prepare_Impl_") EvalLuv.prepare_fields [];
38233840 init_fields builtins (["eval";"luv";"_Check"], "Check_Impl_") EvalLuv.check_fields [];
38243841 init_fields builtins (["eval";"luv"], "Version") EvalLuv.version_fields [];
3825 EvalSsl.init_fields init_fields builtins
3842 EvalSsl.init_fields init_fields builtins
7474 end
7575
7676 type vregex = {
77 r : Pcre.regexp;
77 r : Pcre2.regexp;
7878 r_rex_string : vstring;
7979 r_global : bool;
8080 mutable r_string : string;
81 mutable r_groups : Pcre.substrings array;
81 mutable r_groups : Pcre2.substrings array;
8282 }
8383
8484 type vzlib = {
153153 (* The fields of the object known when it is created. *)
154154 mutable ofields : value array;
155155 (* The prototype of the object. *)
156 mutable oproto : vprototype;
157 }
156 mutable oproto : vobject_proto;
157 }
158
159 and vobject_proto =
160 | OProto of vprototype
161 | ODictionary of value IntMap.t
158162
159163 and vprototype = {
160164 (* The path of the prototype. Using rev_hash on this gives the original dot path. *)
00 open Ast
1 open DisplayTypes.DisplayMode
12 open Type
23 open Common
4 open DefineList
5 open MetaList
6 open Globals
37
48 exception Invalid_expr
59 exception Abort
10
11 type compiler_options = {
12 opt_inlining : bool option;
13 opt_transform : bool option;
14 }
615
716 (**
817 Our access to the compiler from the macro api
1120 type 'value compiler_api = {
1221 pos : Globals.pos;
1322 get_com : unit -> Common.context;
23 get_macro_stack : unit -> pos list;
24 init_macros_done : unit -> bool;
1425 get_type : string -> Type.t option;
1526 get_module : string -> Type.t list;
27 after_init_macros : (unit -> unit) -> unit;
1628 after_typing : (module_type list -> unit) -> unit;
1729 on_generate : (Type.t list -> unit) -> bool -> unit;
1830 after_generate : (unit -> unit) -> unit;
1931 on_type_not_found : (string -> 'value) -> unit;
2032 parse_string : string -> Globals.pos -> bool -> Ast.expr;
33 parse : 'a . ((Ast.token * Globals.pos) Stream.t -> 'a) -> string -> 'a;
2134 type_expr : Ast.expr -> Type.texpr;
2235 resolve_type : Ast.complex_type -> Globals.pos -> t;
23 type_macro_expr : Ast.expr -> Type.texpr;
2436 store_typed_expr : Type.texpr -> Ast.expr;
2537 allow_package : string -> unit;
2638 type_patch : string -> string -> bool -> string option -> unit;
4355 format_string : string -> Globals.pos -> Ast.expr;
4456 cast_or_unify : Type.t -> texpr -> Globals.pos -> bool;
4557 add_global_metadata : string -> string -> (bool * bool * bool) -> pos -> unit;
58 register_define : string -> Define.user_define -> unit;
59 register_metadata : string -> Meta.user_meta -> unit;
4660 add_module_check_policy : string list -> int list -> bool -> int -> unit;
4761 decode_expr : 'value -> Ast.expr;
4862 encode_expr : Ast.expr -> 'value;
4963 encode_ctype : Ast.type_hint -> 'value;
5064 decode_type : 'value -> t;
5165 flush_context : (unit -> t) -> t;
66 info : ?depth:int -> string -> pos -> unit;
67 warning : ?depth:int -> Warning.warning -> string -> pos -> unit;
68 display_error : ?depth:int -> (string -> pos -> unit);
69 with_imports : 'a . import list -> placed_name list list -> (unit -> 'a) -> 'a;
70 with_options : 'a . compiler_options -> (unit -> 'a) -> 'a;
5271 }
5372
5473
5574 type enum_type =
5675 | IExpr
76 | IEFieldKind
5777 | IBinop
5878 | IUnop
5979 | IConst
7494 | IQuoteStatus
7595 | IImportMode
7696 | IDisplayKind
97 | IDisplayMode
98 | ICapturePolicy
99 | IVarScope
100 | IVarScopingFlags
101 | IPackageRule
77102 | IMessage
78103 | IFunctionKind
79104 | IStringLiteralKind
130155 val encode_ref : 'a -> ('a -> value) -> (unit -> string) -> value
131156 val decode_ref : value -> 'a
132157
133 val compiler_error : string -> Globals.pos -> 'a
158 val compiler_error : Globals.located -> 'a
134159 val error_message : string -> 'a
135160 val value_to_expr : value -> Globals.pos -> Ast.expr
136161 val value_signature : value -> string
149174 val get_api_call_pos : unit -> pos
150175 end
151176
152 let enum_name = function
153 | IExpr -> "ExprDef"
154 | IBinop -> "Binop"
155 | IUnop -> "Unop"
156 | IConst -> "Constant"
157 | ITParam -> "TypeParam"
158 | ICType -> "ComplexType"
159 | IField -> "FieldType"
160 | IType -> "Type"
161 | IFieldKind -> "FieldKind"
162 | IMethodKind -> "MethodKind"
163 | IVarAccess -> "VarAccess"
164 | IAccess -> "Access"
165 | IClassKind -> "ClassKind"
166 | ITypedExpr -> "TypedExprDef"
167 | ITConstant -> "TConstant"
168 | IModuleType -> "ModuleType"
169 | IFieldAccess -> "FieldAccess"
170 | IAnonStatus -> "AnonStatus"
171 | IImportMode -> "ImportMode"
172 | IQuoteStatus -> "QuoteStatus"
173 | IDisplayKind -> "DisplayKind"
174 | IMessage -> "Message"
175 | IFunctionKind -> "FunctionKind"
176 | IStringLiteralKind -> "StringLiteralKind"
177
178 let all_enums =
179 let last = IImportMode in
180 let rec loop i =
181 let e : enum_type = Obj.magic i in
182 if e = last then [e] else e :: loop (i + 1)
183 in
184 loop 0
185
186
187177 let s_type_path = Globals.s_type_path
188178
189179 (* convert float value to haxe expression, handling inf/-inf/nan *)
190180 let haxe_float f p =
191181 let std = (Ast.EConst (Ast.Ident "std"), p) in
192 let math = (Ast.EField (std, "Math"), p) in
182 let math = (efield (std, "Math"), p) in
193183 if (f = infinity) then
194 (Ast.EField (math, "POSITIVE_INFINITY"), p)
184 (efield (math, "POSITIVE_INFINITY"), p)
195185 else if (f = neg_infinity) then
196 (Ast.EField (math, "NEGATIVE_INFINITY"), p)
186 (efield (math, "NEGATIVE_INFINITY"), p)
197187 else if (f <> f) then
198 (Ast.EField (math, "NaN"), p)
188 (efield (math, "NaN"), p)
199189 else
200 (Ast.EConst (Ast.Float (Numeric.float_repres f)), p)
190 (Ast.EConst (Ast.Float (Numeric.float_repres f, None)), p)
201191
202192 (* ------------------------------------------------------------------------------------------------------------- *)
203193 (* Our macro api functor *)
225215
226216 let encode_const c =
227217 let tag, pl = match c with
228 | Int s -> 0, [encode_string s]
229 | Float s -> 1, [encode_string s]
218 | Int (s, suffix) -> 0, [encode_string s;null encode_string suffix]
219 | Float (s, suffix) -> 1, [encode_string s;null encode_string suffix]
230220 | String(s,qs) -> 2, [encode_string s;encode_string_literal_kind qs]
231221 | Ident s -> 3, [encode_string s]
232222 | Regexp (s,opt) -> 4, [encode_string s;encode_string opt]
259249 | OpInterval -> 21, []
260250 | OpArrow -> 22, []
261251 | OpIn -> 23, []
252 | OpNullCoal -> 24, []
262253 in
263254 encode_enum IBinop tag pl
264255
288279 let encode_placed_name (s,p) =
289280 encode_string s
290281
291 let rec encode_path (t,p) =
282 (* Globals.path *)
283 let encode_path (p,n) =
284 encode_obj [
285 "pack", encode_array (List.map encode_string p);
286 "name", encode_string n;
287 ]
288
289 (* Ast.placed_type_path *)
290 let rec encode_ast_path (t,p) =
292291 let fields = [
293292 "pack", encode_array (List.map encode_string t.tpackage);
294293 "name", encode_string t.tname;
348347 and encode_ctype t =
349348 let tag, pl = match fst t with
350349 | CTPath p ->
351 0, [encode_path (p,Globals.null_pos)]
350 0, [encode_ast_path (p,Globals.null_pos)]
352351 | CTFunction (pl,r) ->
353352 1, [encode_array (List.map encode_ctype pl);encode_ctype r]
354353 | CTAnonymous fl ->
356355 | CTParent t ->
357356 3, [encode_ctype t]
358357 | CTExtend (tl,fields) ->
359 4, [encode_array (List.map encode_path tl); encode_array (List.map encode_field fields)]
358 4, [encode_array (List.map encode_ast_path tl); encode_array (List.map encode_field fields)]
360359 | CTOptional t ->
361360 5, [encode_ctype t]
362361 | CTNamed (n,t) ->
404403 in
405404 encode_enum ~pos:None IDisplayKind tag pl
406405
407 and encode_message msg =
408 let tag, pl = match msg with
409 | CMInfo(msg,p) -> 0, [(encode_string msg); (encode_pos p)]
410 | CMWarning(msg,p) -> 1, [(encode_string msg); (encode_pos p)]
411 | CMError(_,_) -> Globals.die "" __LOC__
406 and encode_display_mode dm =
407 let tag, pl = match dm with
408 | DMNone -> 0, []
409 | DMDefault -> 1, []
410 | DMDefinition -> 2, []
411 | DMTypeDefinition -> 3, []
412 | DMImplementation -> 4, []
413 | DMPackage -> 5, []
414 | DMHover -> 6, []
415 | DMUsage (withDefinition,findDescendants,findBase) -> 7, [(vbool withDefinition); (vbool findDescendants); (vbool findBase)]
416 | DMModuleSymbols None -> 8, []
417 | DMModuleSymbols (Some s) -> 9, [(encode_string s)]
418 | DMSignature -> 10, []
419 in
420 encode_enum ~pos:None IDisplayMode tag pl
421
422 (** encoded to haxe.display.Display.Platform, an enum abstract of String *)
423 and encode_platform p =
424 encode_string (platform_name p)
425
426 and encode_platform_config pc =
427 encode_obj [
428 "staticTypeSystem", vbool pc.pf_static;
429 "sys", vbool pc.pf_sys;
430 "capturePolicy", encode_capture_policy pc.pf_capture_policy;
431 "padNulls", vbool pc.pf_pad_nulls;
432 "addFinalReturn", vbool pc.pf_add_final_return;
433 "overloadFunctions", vbool pc.pf_overload;
434 "canSkipNonNullableArgument", vbool pc.pf_can_skip_non_nullable_argument;
435 "reservedTypePaths", encode_array (List.map encode_path pc.pf_reserved_type_paths);
436 "supportsFunctionEquality", vbool pc.pf_supports_function_equality;
437 "usesUtf16", vbool pc.pf_uses_utf16;
438 "thisBeforeSuper", vbool pc.pf_this_before_super;
439 "supportsThreads", vbool pc.pf_supports_threads;
440 "supportsUnicode", vbool pc.pf_supports_unicode;
441 "supportsRestArgs", vbool pc.pf_supports_rest_args;
442 "exceptions", encode_exceptions_config pc.pf_exceptions;
443 "scoping", encode_var_scoping_config pc.pf_scoping;
444 "supportsAtomics", vbool pc.pf_supports_atomics;
445 ]
446
447 and encode_capture_policy cp =
448 let tag = match cp with
449 | CPNone -> 0
450 | CPWrapRef -> 1
451 | CPLoopVars -> 2
452 in
453 encode_enum ~pos:None ICapturePolicy tag []
454
455 and encode_var_scoping_config vsc =
456 encode_obj [
457 "scope", encode_var_scope vsc.vs_scope;
458 "flags", encode_array (List.map encode_var_scoping_flags vsc.vs_flags);
459 ]
460
461 and encode_var_scope vs =
462 let tag = match vs with
463 | FunctionScope -> 0
464 | BlockScope -> 1
465 in
466 encode_enum ~pos:None IVarScope tag []
467
468 and encode_var_scoping_flags vsf =
469 let tag, pl = match vsf with
470 | VarHoisting -> 0, []
471 | NoShadowing -> 1, []
472 | NoCatchVarShadowing -> 2, []
473 | ReserveCurrentTopLevelSymbol -> 3, []
474 | ReserveAllTopLevelSymbols -> 4, []
475 | ReserveAllTypesFlat -> 5, []
476 | ReserveNames (names) -> 6, [encode_array (List.map encode_string names)]
477 | SwitchCasesNoBlocks -> 7, []
478 in
479 encode_enum ~pos:None IVarScopingFlags tag pl
480
481 and encode_exceptions_config ec =
482 encode_obj [
483 "nativeThrows", encode_array (List.map encode_path ec.ec_native_throws);
484 "nativeCatches", encode_array (List.map encode_path ec.ec_native_catches);
485 "avoidWrapping", vbool ec.ec_avoid_wrapping;
486 "wildcardCatch", encode_path ec.ec_wildcard_catch;
487 "baseThrow", encode_path ec.ec_base_throw;
488 (* skipping "specialThrow" since cannot use "decode_texpr" here *)
489 ]
490
491 and encode_package_rule pr =
492 let tag, pl = match pr with
493 | Forbidden -> 0, []
494 | Directory (path) -> 1, [encode_string path]
495 | Remap (path) -> 2, [encode_string path]
496 in
497 encode_enum ~pos:None IPackageRule tag pl
498
499 and encode_message cm =
500 let tag, pl = match cm.cm_severity with
501 | Globals.MessageSeverity.Information -> 0, [(encode_string cm.cm_message); (encode_pos cm.cm_pos)]
502 | Warning | Hint -> 1, [(encode_string cm.cm_message); (encode_pos cm.cm_pos)]
503 | Error -> Globals.die "" __LOC__
412504 in
413505 encode_enum ~pos:None IMessage tag pl
506
507 and encode_efield_kind efk =
508 let i = match efk with
509 | EFNormal -> 0
510 | EFSafe -> 1
511 in
512 encode_enum IEFieldKind i []
414513
415514 and encode_expr e =
416515 let rec loop (e,p) =
421520 1, [loop e1;loop e2]
422521 | EBinop (op,e1,e2) ->
423522 2, [encode_binop op;loop e1;loop e2]
424 | EField (e,f) ->
425 3, [loop e;encode_string f]
523 | EField (e,f,efk) ->
524 3, [loop e;encode_string f;encode_efield_kind efk]
426525 | EParenthesis e ->
427526 4, [loop e]
428527 | EObjectDecl fl ->
437536 | ECall (e,el) ->
438537 7, [loop e;encode_array (List.map loop el)]
439538 | ENew (p,el) ->
440 8, [encode_path p; encode_array (List.map loop el)]
539 8, [encode_ast_path p; encode_array (List.map loop el)]
441540 | EUnop (op,flag,e) ->
442541 9, [encode_unop op; vbool (match flag with Prefix -> false | Postfix -> true); loop e]
443542 | EVars vl ->
446545 "name",encode_placed_name v.ev_name;
447546 "name_pos",encode_pos (pos v.ev_name);
448547 "isFinal",vbool v.ev_final;
548 "isStatic",vbool v.ev_static;
449549 "type",null encode_ctype v.ev_type;
450550 "expr",null loop v.ev_expr;
451551 "meta",encode_meta_content v.ev_meta;
494594 23, [loop e; null encode_ctype t]
495595 | EDisplay (e,dk) ->
496596 24, [loop e; encode_display_kind dk]
497 | EDisplayNew t ->
498 25, [encode_path t]
499597 | ETernary (econd,e1,e2) ->
500 26, [loop econd;loop e1;loop e2]
598 25, [loop econd;loop e1;loop e2]
501599 | ECheckType (e,t) ->
502 27, [loop e; encode_ctype t]
600 26, [loop e; encode_ctype t]
503601 | EMeta (m,e) ->
504 28, [encode_meta_entry m;loop e]
602 27, [encode_meta_entry m;loop e]
505603 | EIs (e,t) ->
506 29, [loop e;encode_ctype t]
604 28, [loop e;encode_ctype t]
507605 in
508606 encode_obj [
509607 "pos", encode_pos p;
548646
549647 let decode_const c =
550648 match decode_enum c with
551 | 0, [s] -> Int (decode_string s)
552 | 1, [s] -> Float (decode_string s)
649 | 0, [s;suffix] ->
650 let decoded_suffix = opt decode_string suffix in
651 (match decoded_suffix with
652 | None | Some "i32" | Some "i64" | Some "u32" ->
653 Int (decode_string s, decoded_suffix)
654 | Some other ->
655 raise Invalid_expr)
656 | 1, [s;suffix] ->
657 let decoded_suffix = opt decode_string suffix in
658 (match decoded_suffix with
659 | None | Some "f64" ->
660 Float (decode_string s, opt decode_string suffix)
661 | Some other ->
662 raise Invalid_expr)
553663 | 2, [s;qs] -> String (decode_string s,decode_string_literal_kind qs)
554664 | 3, [s] -> Ident (decode_string s)
555665 | 4, [s;opt] -> Regexp (decode_string s, decode_string opt)
582692 | 21, [] -> OpInterval
583693 | 22,[] -> OpArrow
584694 | 23,[] -> OpIn
695 | 24,[] -> OpNullCoal
585696 | _ -> raise Invalid_expr
586697
587698 let decode_unop op =
613724 let decode_opt_array f v =
614725 if v = vnull then [] else List.map f (decode_array v)
615726
616 let rec decode_path t =
727 (* Ast.placed_type_path *)
728 let rec decode_ast_path t =
617729 let p = field t "pos" in
618730 let pack = List.map decode_string (decode_array (field t "pack"))
619731 and name = decode_string (field t "name")
632744
633745 and decode_tparam_decl v =
634746 let vconstraints = field v "constraints" in
747 let vdefault = field v "defaultType" in
635748 {
636749 tp_name = decode_placed_name (field v "name_pos") (field v "name");
637750 tp_constraints = if vconstraints = vnull then None else (match decode_array vconstraints with
639752 | [t] -> Some (decode_ctype t)
640753 | tl -> Some (CTIntersection (List.map decode_ctype tl),Globals.null_pos)
641754 );
755 tp_default = opt decode_ctype vdefault;
642756 tp_params = decode_tparams (field v "params");
643757 tp_meta = decode_meta_content (field v "meta");
644758 }
709823 let (i,args),p = decode_enum_with_pos t in
710824 (match i,args with
711825 | 0, [p] ->
712 CTPath (fst (decode_path p))
826 CTPath (fst (decode_ast_path p))
713827 | 1, [a;r] ->
714828 CTFunction (List.map decode_ctype (decode_array a), decode_ctype r)
715829 | 2, [fl] ->
717831 | 3, [t] ->
718832 CTParent (decode_ctype t)
719833 | 4, [tl;fl] ->
720 CTExtend (List.map decode_path (decode_array tl), List.map decode_field (decode_array fl))
834 CTExtend (List.map decode_ast_path (decode_array tl), List.map decode_field (decode_array fl))
721835 | 5, [t] ->
722836 CTOptional (decode_ctype t)
723837 | 6, [n;t] ->
753867 EArray (loop e1, loop e2)
754868 | 2, [op;e1;e2] ->
755869 EBinop (decode_op op, loop e1, loop e2)
756 | 3, [e;f] ->
757 EField (loop e, decode_string f)
870 | 3, [e;f;efk] ->
871 let efk = if efk == vnull then
872 EFNormal
873 else match decode_enum efk with
874 | 0,[] -> EFNormal
875 | 1,[] -> EFSafe
876 | _ -> raise Invalid_expr
877 in
878 EField (loop e, decode_string f, efk)
758879 | 4, [e] ->
759880 EParenthesis (loop e)
760881 | 5, [a] ->
774895 | 7, [e;el] ->
775896 ECall (loop e,List.map loop (decode_array el))
776897 | 8, [t;el] ->
777 ENew (decode_path t,List.map loop (decode_array el))
898 ENew (decode_ast_path t,List.map loop (decode_array el))
778899 | 9, [op;f;e] ->
779900 EUnop (decode_unop op,(if decode_bool f then Postfix else Prefix),loop e)
780901 | 10, [vl] ->
781902 EVars (List.map (fun v ->
782903 let vfinal = field v "isFinal" in
783904 let final = if vfinal == vnull then false else decode_bool vfinal in
905 let vstatic = field v "isStatic" in
906 let static = if vstatic == vnull then false else decode_bool vstatic in
784907 let vmeta = field v "meta" in
785908 let meta = if vmeta == vnull then [] else decode_meta_content vmeta in
786909 let name = (decode_placed_name (field v "name_pos") (field v "name"))
787910 and t = opt decode_ctype (field v "type")
788911 and eo = opt loop (field v "expr") in
789 mk_evar ~final ?t ?eo ~meta name
912 mk_evar ~final ~static ?t ?eo ~meta name
790913 ) (decode_array vl))
791914 | 11, [kind;f] ->
792915 EFunction (decode_function_kind kind,decode_fun f)
802925 let cases = List.map (fun c ->
803926 (List.map loop (decode_array (field c "values")),opt loop (field c "guard"),opt loop (field c "expr"),maybe_decode_pos (field c "pos"))
804927 ) (decode_array cases) in
805 ESwitch (loop e,cases,opt (fun v -> (if field v "expr" = vnull then None else Some (decode_expr v)),Globals.null_pos) eo)
928 ESwitch (loop e,cases,opt (fun v -> (if field v "expr" = vnull then None else Some (decode_expr v)),p) eo)
806929 | 17, [e;catches] ->
807930 let catches = List.map (fun c ->
808931 ((decode_placed_name (field c "name_pos") (field c "name")),(opt decode_ctype (field c "type")),loop (field c "expr"),maybe_decode_pos (field c "pos"))
822945 ECast (loop e,opt decode_ctype t)
823946 | 24, [e;dk] ->
824947 EDisplay (loop e,decode_display_kind dk)
825 | 25, [t] ->
826 EDisplayNew (decode_path t)
827 | 26, [e1;e2;e3] ->
948 | 25, [e1;e2;e3] ->
828949 ETernary (loop e1,loop e2,loop e3)
829 | 27, [e;t] ->
950 | 26, [e;t] ->
830951 ECheckType (loop e, (decode_ctype t))
831 | 28, [m;e] ->
952 | 27, [m;e] ->
832953 EMeta (decode_meta_entry m,loop e)
833 | 29, [e;t] ->
954 | 28, [e;t] ->
834955 EIs (loop e,decode_ctype t)
835956 | _ ->
836957 raise Invalid_expr
9011022 ] @ fields)
9021023
9031024 and encode_type_params tl =
904 encode_array (List.map (fun (n,t) -> encode_obj ["name",encode_string n;"t",encode_type t]) tl)
1025 encode_array (List.map (fun tp ->
1026 encode_obj [
1027 "name",encode_string tp.ttp_name;
1028 "t",encode_type tp.ttp_type;
1029 "defaultType",(match tp.ttp_default with None -> vnull | Some t -> encode_type t);
1030 ]
1031 ) tl)
9051032
9061033 and encode_tenum e =
9071034 encode_mtype (TEnumDecl e) [
9161043 "type", encode_type a.a_this;
9171044 "impl", (match a.a_impl with None -> vnull | Some c -> encode_clref c);
9181045 "binops", encode_array (List.map (fun (op,cf) -> encode_obj [ "op",encode_binop op; "field",encode_cfield cf]) a.a_ops);
919 "unops", encode_array (List.map (fun (op,postfix,cf) -> encode_obj [ "op",encode_unop op; "isPostfix",vbool (match postfix with Postfix -> true | Prefix -> false); "field",encode_cfield cf]) a.a_unops);
1046 "unops", encode_array (List.map (fun (op,postfix,cf) -> encode_obj [ "op",encode_unop op; "postFix",vbool (match postfix with Postfix -> true | Prefix -> false); "field",encode_cfield cf]) a.a_unops);
9201047 "from", encode_array ((List.map (fun t -> encode_obj [ "t",encode_type t; "field",vnull]) a.a_from) @ (List.map (fun (t,cf) -> encode_obj [ "t",encode_type t; "field",encode_cfield cf]) a.a_from_field));
9211048 "to", encode_array ((List.map (fun t -> encode_obj [ "t",encode_type t; "field",vnull]) a.a_to) @ (List.map (fun (t,cf) -> encode_obj [ "t",encode_type t; "field",encode_cfield cf]) a.a_to_field));
9221049 "array", encode_array (List.map encode_cfield a.a_array);
10831210 4 , [encode_array pl; encode_type ret]
10841211 | TAnon a ->
10851212 5, [encode_ref a encode_tanon (fun() -> "<anonymous>")]
1086 | TDynamic tsub as t ->
1087 if t == t_dynamic then
1088 6, [vnull]
1089 else
1090 6, [encode_type tsub]
1213 | TDynamic None ->
1214 6, [vnull]
1215 | TDynamic (Some tsub) ->
1216 6, [encode_type tsub]
10911217 | TLazy f ->
10921218 loop (lazy_type f)
10931219 | TAbstract (a, pl) ->
11311257 | 3, [t; pl] -> TType (decode_ref t, List.map decode_type (decode_array pl))
11321258 | 4, [pl; r] -> TFun (List.map (fun p -> decode_string (field p "name"), decode_bool (field p "opt"), decode_type (field p "t")) (decode_array pl), decode_type r)
11331259 | 5, [a] -> TAnon (decode_ref a)
1134 | 6, [t] -> if t = vnull then t_dynamic else TDynamic (decode_type t)
1260 | 6, [t] -> if t = vnull then t_dynamic else TDynamic (Some (decode_type t))
11351261 | 7, [f] -> TLazy (decode_lazytype f)
11361262 | 8, [a; pl] -> TAbstract (decode_ref a, List.map decode_type (decode_array pl))
11371263 | _ -> raise Invalid_expr
12831409 | _ -> raise Invalid_expr
12841410
12851411 let decode_type_params v =
1286 List.map (fun v -> decode_string (field v "name"),decode_type (field v "t")) (decode_array v)
1412 List.map (fun v ->
1413 let name = decode_string (field v "name") in
1414 let t = decode_type (field v "t") in
1415 let default = opt decode_type (field v "defaultType") in
1416 mk_type_param name t default
1417 ) (decode_array v)
12871418
12881419 let decode_tvar v =
12891420 (Obj.obj (decode_unsafe (field v "$")) : tvar)
13831514
13841515 and decode_texpr v =
13851516 let rec loop v =
1386 mk (decode (field v "expr")) (decode_type (field v "t")) (decode_pos (field v "pos"))
1387 and decode e =
1517 let p = decode_pos (field v "pos") in
1518 mk (decode (field v "expr") p) (decode_type (field v "t")) p
1519 and decode e p =
13881520 match decode_enum e with
13891521 | 0, [c] -> TConst(decode_tconst c)
13901522 | 1, [v] -> TLocal(decode_tvar v)
13931525 | 4, [v1;fa] -> TField(loop v1,decode_field_access fa)
13941526 | 5, [mt] -> TTypeExpr(decode_module_type mt)
13951527 | 6, [v1] -> TParenthesis(loop v1)
1396 | 7, [v] -> TObjectDecl(List.map (fun v -> (decode_string (field v "name"),Globals.null_pos,NoQuotes),loop (field v "expr")) (decode_array v))
1528 | 7, [v] -> TObjectDecl(List.map (fun v -> (decode_string (field v "name"),p,NoQuotes),loop (field v "expr")) (decode_array v))
13971529 | 8, [vl] -> TArrayDecl(List.map loop (decode_array vl))
13981530 | 9, [v1;vl] -> TCall(loop v1,List.map loop (decode_array vl))
13991531 | 10, [c;tl;vl] -> TNew(decode_ref c,List.map decode_type (decode_array tl),List.map loop (decode_array vl))
14681600 in
14691601 EEnum (mk (if isExtern then [EExtern] else []) (List.map conv fields))
14701602 | 1, [] ->
1471 ETypedef (mk (if isExtern then [EExtern] else []) (CTAnonymous fields,Globals.null_pos))
1603 ETypedef (mk (if isExtern then [EExtern] else []) (CTAnonymous fields,pos))
14721604 | 2, [ext;impl;interf;final;abstract] ->
14731605 let flags = if isExtern then [HExtern] else [] in
14741606 let is_interface = decode_opt_bool interf in
14751607 let is_final = decode_opt_bool final in
14761608 let is_abstract = decode_opt_bool abstract in
1477 let interfaces = (match opt (fun v -> List.map decode_path (decode_array v)) impl with Some l -> l | _ -> [] ) in
1478 let flags = (match opt decode_path ext with None -> flags | Some t -> HExtends t :: flags) in
1609 let interfaces = (match opt (fun v -> List.map decode_ast_path (decode_array v)) impl with Some l -> l | _ -> [] ) in
1610 let flags = (match opt decode_ast_path ext with None -> flags | Some t -> HExtends t :: flags) in
14791611 let flags = if is_interface then begin
14801612 let flags = HInterface :: flags in
14811613 List.map (fun t -> HExtends t) interfaces @ flags
15601692 "current_pos", vfun0 (fun() ->
15611693 encode_pos (get_api()).pos
15621694 );
1563 "error", vfun2 (fun msg p ->
1695 "get_macro_stack", vfun0 (fun () ->
1696 let stack = ((get_api()).get_macro_stack ()) in
1697 encode_array (List.map encode_pos stack)
1698 );
1699 "init_macros_done", vfun0 (fun () ->
1700 vbool ((get_api()).init_macros_done ())
1701 );
1702 "error", vfun3 (fun msg p depth ->
15641703 let msg = decode_string msg in
15651704 let p = decode_pos p in
1566 (ccom()).error msg p;
1705 let depth = decode_int depth in
1706 (get_api()).display_error ~depth msg p;
15671707 raise Abort
15681708 );
1569 "fatal_error", vfun2 (fun msg p ->
1709 "fatal_error", vfun3 (fun msg p depth ->
15701710 let msg = decode_string msg in
15711711 let p = decode_pos p in
1572 raise (Error.Fatal_error (msg,p))
1573 );
1574 "warning", vfun2 (fun msg p ->
1712 let depth = decode_int depth in
1713 raise (Error.Fatal_error ((Globals.located msg p),depth))
1714 );
1715 "report_error", vfun3 (fun msg p depth ->
15751716 let msg = decode_string msg in
15761717 let p = decode_pos p in
1577 (ccom()).warning msg p;
1578 vnull
1579 );
1580 "info", vfun2 (fun msg p ->
1718 let depth = decode_int depth in
1719 (get_api()).display_error ~depth msg p;
1720 vnull
1721 );
1722 "warning", vfun3 (fun msg p depth ->
15811723 let msg = decode_string msg in
15821724 let p = decode_pos p in
1583 (ccom()).info msg p;
1725 let depth = decode_int depth in
1726 (get_api()).warning ~depth WUser msg p;
1727 vnull
1728 );
1729 "info", vfun3 (fun msg p depth ->
1730 let msg = decode_string msg in
1731 let p = decode_pos p in
1732 let depth = decode_int depth in
1733 (get_api()).info ~depth msg p;
15841734 vnull
15851735 );
15861736 "get_messages", vfun0 (fun() ->
16031753 "define", vfun2 (fun s v ->
16041754 let s = decode_string s in
16051755 let com = ccom() in
1606 if com.stage <> CInitMacrosStart then begin
1607 let v = if v = vnull then "" else ", " ^ (decode_string v) in
1608 com.warning ("Should be used in initialization macros only: haxe.macro.Compiler.define(" ^ s ^ v ^ ")") Globals.null_pos;
1609 end;
1610 let v = if v = vnull then "" else "=" ^ (decode_string v) in
1611 Common.raw_define com (s ^ v);
1756 (* TODO: use external_define and external_define_value for #8690 *)
1757 if v = vnull then
1758 Common.external_define_no_check com s
1759 else
1760 Common.external_define_value_no_check com s (decode_string v);
16121761 vnull
16131762 );
16141763 "defined", vfun1 (fun s ->
1615 vbool (Common.raw_defined (ccom()) (decode_string s))
1764 vbool (Common.external_defined (ccom()) (decode_string s))
16161765 );
16171766 "defined_value", vfun1 (fun s ->
1618 try encode_string (Common.raw_defined_value (ccom()) (decode_string s)) with Not_found -> vnull
1767 try encode_string (Common.external_defined_value (ccom()) (decode_string s)) with Not_found -> vnull
16191768 );
16201769 "get_defines", vfun0 (fun() ->
1621 encode_string_map encode_string (ccom()).defines.Define.values
1770 encode_string_map encode_string (Common.defines_for_external (ccom()))
16221771 );
16231772 "get_type", vfun1 (fun s ->
16241773 let tname = decode_string s in
16291778 "get_module", vfun1 (fun s ->
16301779 encode_array (List.map encode_type ((get_api()).get_module (decode_string s)))
16311780 );
1781 "on_after_init_macros", vfun1 (fun f ->
1782 let f = prepare_callback f 1 in
1783 (get_api()).after_init_macros (fun tl -> ignore(f []));
1784 vnull
1785 );
16321786 "on_after_typing", vfun1 (fun f ->
16331787 let f = prepare_callback f 1 in
16341788 (get_api()).after_typing (fun tl -> ignore(f [encode_array (List.map encode_module_type tl)]));
17011855 );
17021856 "add_global_metadata_impl", vfun5 (fun s1 s2 b1 b2 b3 ->
17031857 (get_api()).add_global_metadata (decode_string s1) (decode_string s2) (decode_bool b1,decode_bool b2,decode_bool b3) (get_api_call_pos());
1858 vnull
1859 );
1860 "register_define_impl", vfun2 (fun d src ->
1861 let flags : define_parameter list = [] in
1862
1863 let platforms = decode_opt_array decode_string (field d "platforms") in
1864 let flags = match platforms with
1865 | [] -> flags
1866 | _ ->(Platforms (List.map (fun p -> (Globals.parse_platform p)) platforms)) :: flags
1867 in
1868
1869 let params = decode_opt_array decode_string (field d "params") in
1870 let flags = List.append flags (List.map (fun p -> (HasParam p : define_parameter)) params) in
1871
1872 let links = decode_opt_array decode_string (field d "links") in
1873 let flags = List.append flags (List.map (fun l -> (Link l : define_parameter)) links) in
1874
1875 (get_api()).register_define (decode_string (field d "define")) {
1876 doc = decode_string (field d "doc");
1877 flags = flags;
1878 source = opt decode_string src;
1879 };
1880 vnull
1881 );
1882 "register_metadata_impl", vfun2 (fun m src ->
1883 let flags : meta_parameter list = [] in
1884
1885 let platforms = decode_opt_array decode_string (field m "platforms") in
1886 let flags =
1887 if (List.length platforms) = 0 then flags
1888 else (Platforms (List.map (fun p -> (Globals.parse_platform p)) platforms)) :: flags
1889 in
1890
1891 let targets = decode_opt_array decode_string (field m "targets") in
1892 let flags =
1893 if (List.length targets) = 0 then flags
1894 else (UsedOn (List.map MetaList.parse_meta_usage targets)) :: flags
1895 in
1896
1897 let params = decode_opt_array decode_string (field m "params") in
1898 let flags = List.append flags (List.map (fun p -> HasParam p) params) in
1899
1900 let links = decode_opt_array decode_string (field m "links") in
1901 let flags = List.append flags (List.map (fun l -> Link l) links) in
1902
1903 (get_api()).register_metadata (decode_string (field m "metadata")) {
1904 doc = decode_string (field m "doc");
1905 flags = flags;
1906 source = opt decode_string src;
1907 };
17041908 vnull
17051909 );
17061910 "set_custom_js_generator", vfun1 (fun f ->
17581962 );
17591963 "flush_disk_cache", vfun0 (fun () ->
17601964 let com = (get_api()).get_com() in
1761 Hashtbl.clear com.file_lookup_cache;
1762 Hashtbl.clear com.readdir_cache;
1965 com.file_lookup_cache#clear;
1966 com.readdir_cache#clear;
17631967 vnull
17641968 );
17651969 "get_pos_infos", vfun1 (fun p ->
18302034 | TAbstract _ | TEnum _ | TInst _ | TFun _ | TAnon _ | TDynamic _ ->
18312035 t
18322036 | TType (t,tl) ->
1833 apply_params t.t_params tl t.t_type
2037 apply_typedef t tl
18342038 | TLazy f ->
18352039 lazy_type f
18362040 in
18472051 (get_api()).define_type v (opt decode_string m);
18482052 vnull
18492053 );
2054 "make_monomorph", vfun0 (fun() ->
2055 let t = TMono (Monomorph.create ()) in
2056 encode_type t
2057 );
18502058 "define_module", vfun4 (fun path vl ui ul ->
1851 (get_api()).define_module (decode_string path) (decode_array vl) (List.map decode_import (decode_array ui)) (List.map fst (List.map decode_path (decode_array ul)));
2059 (get_api()).define_module (decode_string path) (decode_array vl) (List.map decode_import (decode_array ui)) (List.map fst (List.map decode_ast_path (decode_array ul)));
18522060 vnull
18532061 );
18542062 "add_class_path", vfun1 (fun cp ->
18552063 let com = ccom() in
18562064 let cp = decode_string cp in
1857 if com.stage <> CInitMacrosStart then
1858 com.warning ("Should be used in initialization macros only: haxe.macro.Compiler.addClassPath(" ^ cp ^ ")") Globals.null_pos;
18592065 let cp = Path.add_trailing_slash cp in
18602066 com.class_path <- cp :: com.class_path;
18612067 (match com.get_macros() with
18632069 mcom.class_path <- cp :: mcom.class_path;
18642070 | None ->
18652071 ());
1866 Hashtbl.clear com.file_lookup_cache;
1867 Hashtbl.clear com.readdir_cache;
2072 com.file_lookup_cache#clear;
2073 com.readdir_cache#clear;
18682074 vnull
18692075 );
18702076 "add_native_lib", vfun1 (fun file ->
18712077 let file = decode_string file in
18722078 let com = ccom() in
1873 if com.stage <> CInitMacrosStart then
1874 com.warning ("Should be used in initialization macros only: haxe.macro.Compiler.addNativeLib(" ^ file ^ ")") Globals.null_pos;
18752079 NativeLibraryHandler.add_native_lib com file false ();
18762080 vnull
18772081 );
19012105 let e = decode_texpr e in
19022106 encode_expr ((get_api()).store_typed_expr e)
19032107 );
2108 "type_and_store_expr", vfun1 (fun e ->
2109 let api = get_api() in
2110 let te = (api.type_expr (decode_expr e)) in
2111 let v_e = encode_expr (api.store_typed_expr te) in
2112 let v_to_string () = (s_type (print_context())) te.etype in
2113 encode_obj ["expr",v_e;"type",encode_ref te.etype encode_type v_to_string]
2114 );
19042115 "get_output", vfun0 (fun() ->
19052116 encode_string (ccom()).file
19062117 );
19152126 else
19162127 encode_obj ["file",encode_string p.Globals.pfile;"pos",vint p.Globals.pmin]
19172128 );
2129 "get_display_mode", vfun0 (fun() ->
2130 encode_display_mode !Parser.display_mode
2131 );
2132 "get_configuration", vfun0 (fun() ->
2133 let com = ccom() in
2134 encode_obj [
2135 "version", vint com.version;
2136 "args", encode_array (List.map encode_string com.args);
2137 "debug", vbool com.debug;
2138 "verbose", vbool com.verbose;
2139 "foptimize", vbool com.foptimize;
2140 "platform", encode_platform com.platform;
2141 "platformConfig", encode_platform_config com.config;
2142 "stdPath", encode_array (List.map encode_string com.std_path);
2143 "mainClass", (match com.main_class with None -> vnull | Some path -> encode_path path);
2144 "packageRules", encode_string_map encode_package_rule com.package_rules;
2145 ]
2146 );
2147 "get_main_expr", vfun0 (fun() ->
2148 match (ccom()).main with None -> vnull | Some e -> encode_texpr e
2149 );
2150 "get_module_types", vfun0 (fun() ->
2151 encode_array (List.map encode_module_type (ccom()).types)
2152 );
2153 "type_to_module_type", vfun1 (fun(t) ->
2154 encode_module_type (module_type_of_type (decode_type t))
2155 );
2156 "module_type_to_type", vfun1 (fun(t) ->
2157 encode_type (type_of_module_type (decode_module_type t))
2158 );
19182159 "apply_params", vfun3 (fun tpl tl t ->
19192160 let tl = List.map decode_type (decode_array tl) in
1920 let tpl = List.map (fun v -> decode_string (field v "name"), decode_type (field v "t")) (decode_array tpl) in
2161 let tpl = List.map (fun v ->
2162 let name = decode_string (field v "name") in
2163 let t = decode_type (field v "t") in
2164 let default = None in (* we don't care here *)
2165 mk_type_param name t default
2166 ) (decode_array tpl) in
19212167 let rec map t = match t with
19222168 | TInst({cl_kind = KTypeParameter _},_) ->
19232169 begin try
19242170 (* use non-physical equality check here to make apply_params work *)
1925 snd (List.find (fun (_,t2) -> type_iseq t t2) tpl)
2171 extract_param_type (List.find (fun tp2 -> type_iseq t tp2.ttp_type) tpl)
19262172 with Not_found ->
19272173 Type.map map t
19282174 end
19502196 vnull
19512197 );
19522198 "server_invalidate_files", vfun1 (fun a ->
1953 let cs = match CompilationServer.get() with Some cs -> cs | None -> failwith "compilation server not running" in
19542199 let com = ccom() in
2200 let cs = com.cs in
19552201 List.iter (fun v ->
19562202 let s = decode_string v in
19572203 let s = com.file_keys#get s in
1958 cs#taint_modules s;
2204 cs#taint_modules s "server_invalidate_files";
19592205 cs#remove_files s;
19602206 ) (decode_array a);
19612207 vnull
20022248 match map (fun t -> decode_type (fn [encode_type t])) (TAnon a) with
20032249 | TAnon a -> encode_ref a encode_tanon (fun() -> "<anonymous>")
20042250 | _ -> Globals.die "" __LOC__
2005 )
2251 );
2252 "with_imports", vfun3(fun imports usings f ->
2253 let imports = List.map decode_string (decode_array imports) in
2254 let imports = List.map ((get_api()).parse (fun s -> Grammar.parse_import' s Globals.null_pos)) imports in
2255 let usings = List.map decode_string (decode_array usings) in
2256 let usings = List.map ((get_api()).parse (fun s -> Grammar.parse_using' s Globals.null_pos)) usings in
2257 let f = prepare_callback f 0 in
2258 (get_api()).with_imports imports usings (fun () -> f [])
2259 );
2260 "with_options", vfun2(fun opts f ->
2261 let o = {
2262 opt_inlining = opt decode_bool (field opts "allowInlining");
2263 opt_transform = opt decode_bool (field opts "allowTransform");
2264 } in
2265 let f = prepare_callback f 0 in
2266 (get_api()).with_options o (fun() -> f []);
2267 );
2268 "set_var_name", vfun2(fun v name ->
2269 let v = decode_tvar v in
2270 let name = decode_string name in
2271 v.v_name <- name;
2272 vnull;
2273 );
2274 "send_json", vfun1 (fun json ->
2275 begin match (ccom()).json_out with
2276 | Some api ->
2277 let json = decode_string json in
2278 let lexbuf = Sedlexing.Utf8.from_string json in
2279 let parse = Json.Reader.read_json lexbuf in
2280 api.send_result parse;
2281 vbool true
2282 | None ->
2283 vbool false
2284 end
2285 );
20062286 ]
2007
2008
20092287 end
670670 add_var_flag v VUsed;
671671 (try expr (get_var_value ctx.graph v) with Not_found -> ());
672672 begin match Ssa.get_reaching_def ctx.graph v with
673 | None -> use (get_var_origin ctx.graph v)
674 | Some v -> use v;
673 | None ->
674 (* We don't want to fully recurse for the origin variable because we don't care about its
675 reaching definition (issue #10972). Simply marking it as being used should be sufficient. *)
676 let v' = get_var_origin ctx.graph v in
677 if not (is_used v') then
678 add_var_flag v' VUsed
679 | Some v ->
680 use v;
675681 end
676682 end
677683 and expr e = match e.eexpr with
683689 | _ ->
684690 Type.iter expr e
685691 in
686 let bb_marked = ref [] in
687692 let rec mark bb =
688 bb_marked := bb :: !bb_marked;
693 add_block_flag bb BlockDce;
689694 DynArray.iter expr bb.bb_el;
690695 DynArray.iter expr bb.bb_phi;
691696 terminator_iter expr bb.bb_terminator;
693698 if not (has_flag edge FlagDce) then begin
694699 edge.cfg_flags <- FlagDce :: edge.cfg_flags;
695700 if not ctx.config.const_propagation || has_flag edge FlagExecutable then
696 mark edge.cfg_from;
701 mark edge.cfg_to;
697702 end
698 ) bb.bb_incoming
699 in
700 mark ctx.graph.g_exit;
703 ) bb.bb_outgoing
704 in
705 mark ctx.graph.g_root;
701706 let rec sweep e = match e.eexpr with
702707 | TBinop(OpAssign,{eexpr = TLocal v},e2) | TVar(v,Some e2) when not (keep v) ->
703708 if has_side_effect e2 then
709714 | _ ->
710715 Type.map_expr sweep e
711716 in
712 List.iter (fun bb ->
713 dynarray_map sweep bb.bb_el;
714 bb.bb_terminator <- terminator_map sweep bb.bb_terminator;
715 ) !bb_marked;
717 Graph.iter_dom_tree ctx.graph (fun bb ->
718 if has_block_flag bb BlockDce then begin
719 dynarray_map sweep bb.bb_el;
720 bb.bb_terminator <- terminator_map sweep bb.bb_terminator;
721 end
722 )
716723 end
717724
718725 module Debug = struct
742749 | BKFunctionBegin _ -> "<function-begin>\n"
743750 | BKFunctionEnd -> "<function-end>\n"
744751 | BKLoopHead -> "<loop-head>\n"
752 | BKCatch v -> Printf.sprintf "<catch %s<%i>>" v.v_name v.v_id
753 | BKException -> "<exc>"
745754 | _ -> ""
746755 in
747756 Printf.fprintf ch "n%i [shape=box,label=\"%s%s\"];\n" bb.bb_id s_kind (s_escape s)
780789 edge bb_then "then";
781790 edge bb_else "else";
782791 edge bb_next "next";
783 | SEWhile(bb_head,bb_body,bb_next,_) ->
784 edge bb_head "loop-head";
792 | SEWhile(bb_body,bb_next,_) ->
785793 edge bb_body "loop-body";
786794 edge bb_next "next";
787795 | SEMerge bb_next ->
930938 open AnalyzerConfig
931939 open Graph
932940
933 let with_timer detailed s f =
934 let timer = Timer.timer (if detailed then "analyzer" :: s else ["analyzer"]) in
941 let with_timer level identifier s f =
942 let name = match level with
943 | 0 -> ["analyzer"]
944 | 1 -> "analyzer" :: s
945 | 2 when identifier = "" -> "analyzer" :: s
946 | 2 -> "analyzer" :: s @ [identifier]
947 | _ -> ["analyzer"] (* whatever *)
948 in
949 let timer = Timer.timer name in
935950 let r = f() in
936951 timer();
937952 r
938953
939 let create_analyzer_context com config e =
954 let create_analyzer_context com config identifier e =
940955 let g = Graph.create e.etype e.epos in
941956 let ctx = {
942957 com = com;
945960 (* For CPP we want to use variable names which are "probably" not used by users in order to
946961 avoid problems with the debugger, see https://github.com/HaxeFoundation/hxcpp/issues/365 *)
947962 temp_var_name = (match com.platform with Cpp -> "_hx_tmp" | _ -> "tmp");
963 with_timer = (fun s f ->
964 with_timer config.detail_times identifier s f
965 );
966 identifier = identifier;
948967 entry = g.g_unreachable;
949968 has_unbound = false;
950969 loop_counter = 0;
951970 loop_stack = [];
952971 debug_exprs = [];
953972 name_stack = [];
973 did_optimize = false;
954974 } in
955975 ctx
956976
959979
960980 let there actx e =
961981 if actx.com.debug then add_debug_expr actx "initial" e;
962 let e = with_timer actx.config.detail_times ["->";"filter-apply"] (fun () -> TexprFilter.apply actx.com e) in
982 let e = actx.with_timer ["->";"filter-apply"] (fun () -> TexprFilter.apply actx.com e) in
963983 if actx.com.debug then add_debug_expr actx "after filter-apply" e;
964984 let tf,t,is_real_function = match e.eexpr with
965985 | TFunction tf ->
971991 let tf = { tf_args = []; tf_type = t; tf_expr = e; } in
972992 tf,tfun [] t,false
973993 in
974 with_timer actx.config.detail_times ["->";"from-texpr"] (fun () -> AnalyzerTexprTransformer.from_tfunction actx tf t e.epos);
994 actx.with_timer ["->";"from-texpr"] (fun () -> AnalyzerTexprTransformer.from_tfunction actx tf t e.epos);
975995 is_real_function
976996
977997 let back_again actx is_real_function =
978 let e = with_timer actx.config.detail_times ["<-";"to-texpr"] (fun () -> AnalyzerTexprTransformer.to_texpr actx) in
998 let e = actx.with_timer ["<-";"to-texpr"] (fun () -> AnalyzerTexprTransformer.to_texpr actx) in
979999 if actx.com.debug then add_debug_expr actx "after to-texpr" e;
9801000 DynArray.iter (fun vi ->
9811001 vi.vi_var.v_extra <- vi.vi_extra;
9821002 ) actx.graph.g_var_infos;
983 let e = if actx.config.fusion then with_timer actx.config.detail_times ["<-";"fusion"] (fun () -> Fusion.apply actx.com actx.config e) else e in
1003 let e = if actx.config.fusion then actx.with_timer ["<-";"fusion"] (fun () -> Fusion.apply actx e) else e in
9841004 if actx.com.debug then add_debug_expr actx "after fusion" e;
985 let e = with_timer actx.config.detail_times ["<-";"cleanup"] (fun () -> Cleanup.apply actx.com e) in
1005 let e = actx.with_timer ["<-";"cleanup"] (fun () -> Cleanup.apply actx.com e) in
9861006 if actx.com.debug then add_debug_expr actx "after cleanup" e;
9871007 let e = if is_real_function then
9881008 e
10361056
10371057 let run_on_expr actx e =
10381058 let is_real_function = there actx e in
1039 with_timer actx.config.detail_times ["->";"idom"] (fun () -> Graph.infer_immediate_dominators actx.graph);
1040 with_timer actx.config.detail_times ["->";"infer_scopes"] (fun () -> Graph.infer_scopes actx.graph);
1041 with_timer actx.config.detail_times ["->";"var writes"] (fun () -> Graph.infer_var_writes actx.graph);
1059 actx.with_timer ["->";"idom"] (fun () -> Graph.infer_immediate_dominators actx.graph);
1060 actx.with_timer ["->";"infer_scopes"] (fun () -> Graph.infer_scopes actx.graph);
1061 actx.with_timer ["->";"var writes"] (fun () -> Graph.infer_var_writes actx.graph);
10421062 if actx.com.debug then Graph.check_integrity actx.graph;
10431063 if actx.config.optimize && not actx.has_unbound then begin
1044 with_timer actx.config.detail_times ["optimize";"ssa-apply"] (fun () -> Ssa.apply actx);
1045 if actx.config.const_propagation then with_timer actx.config.detail_times ["optimize";"const-propagation"] (fun () -> ConstPropagation.apply actx);
1046 if actx.config.copy_propagation then with_timer actx.config.detail_times ["optimize";"copy-propagation"] (fun () -> CopyPropagation.apply actx);
1047 with_timer actx.config.detail_times ["optimize";"local-dce"] (fun () -> LocalDce.apply actx);
1064 actx.did_optimize <- true;
1065 actx.with_timer ["optimize";"ssa-apply"] (fun () -> Ssa.apply actx);
1066 if actx.config.const_propagation then actx.with_timer ["optimize";"const-propagation"] (fun () -> ConstPropagation.apply actx);
1067 if actx.config.copy_propagation then actx.with_timer ["optimize";"copy-propagation"] (fun () -> CopyPropagation.apply actx);
1068 actx.with_timer ["optimize";"local-dce"] (fun () -> LocalDce.apply actx);
10481069 end;
10491070 back_again actx is_real_function
10501071
1051 let rec reduce_control_flow ctx e =
1052 let e = Type.map_expr (reduce_control_flow ctx) e in
1053 Optimizer.reduce_control_flow ctx e
1054
1055 let run_on_field ctx config c cf = match cf.cf_expr with
1056 | Some e when not (is_ignored cf.cf_meta) && not (Typecore.is_removable_field ctx cf) ->
1057 let config = update_config_from_meta ctx.Typecore.com config cf.cf_meta in
1058 let actx = create_analyzer_context ctx.Typecore.com config e in
1072 let rec reduce_control_flow com e =
1073 let e = Type.map_expr (reduce_control_flow com) e in
1074 Optimizer.reduce_control_flow com e
1075
1076 let run_on_field com config c cf = match cf.cf_expr with
1077 | Some e when not (is_ignored cf.cf_meta) && not (Typecore.is_removable_field com cf) && not (has_class_field_flag cf CfPostProcessed) ->
1078 let config = update_config_from_meta com config cf.cf_meta in
1079 let actx = create_analyzer_context com config (Printf.sprintf "%s.%s" (s_type_path c.cl_path) cf.cf_name) e in
10591080 let debug() =
10601081 print_endline (Printf.sprintf "While analyzing %s.%s" (s_type_path c.cl_path) cf.cf_name);
10611082 List.iter (fun (s,e) ->
10661087 Debug.dot_debug actx c cf;
10671088 print_endline (Printf.sprintf "dot graph written to %s" (String.concat "/" (Debug.get_dump_path actx c cf)));
10681089 in
1090 let maybe_debug () = match config.debug_kind with
1091 | DebugNone -> ()
1092 | DebugDot -> Debug.dot_debug actx c cf;
1093 | DebugFull -> debug()
1094 in
10691095 let e = try
10701096 run_on_expr actx e
10711097 with
10721098 | Error.Error _ | Abort _ | Sys.Break as exc ->
1099 maybe_debug();
10731100 raise exc
10741101 | exc ->
10751102 debug();
10761103 raise exc
10771104 in
1078 let e = reduce_control_flow ctx e in
1079 begin match config.debug_kind with
1080 | DebugNone -> ()
1081 | DebugDot -> Debug.dot_debug actx c cf;
1082 | DebugFull -> debug()
1083 end;
1105 let e = reduce_control_flow com e in
1106 maybe_debug();
10841107 cf.cf_expr <- Some e;
10851108 | _ -> ()
10861109
1087 let run_on_field ctx config c cf =
1088 run_on_field ctx config c cf;
1089 List.iter (run_on_field ctx config c) cf.cf_overloads
1090
1091 let run_on_class ctx config c =
1092 let config = update_config_from_meta ctx.Typecore.com config c.cl_meta in
1110 let run_on_field com config c cf =
1111 run_on_field com config c cf;
1112 List.iter (run_on_field com config c) cf.cf_overloads
1113
1114 let run_on_class com config c =
1115 let config = update_config_from_meta com config c.cl_meta in
10931116 let process_field stat cf = match cf.cf_kind with
10941117 | Var _ when not stat -> ()
1095 | _ -> run_on_field ctx config c cf
1118 | _ -> run_on_field com config c cf
10961119 in
10971120 List.iter (process_field false) c.cl_ordered_fields;
10981121 List.iter (process_field true) c.cl_ordered_statics;
11061129 | Some e ->
11071130 let tf = { tf_args = []; tf_type = e.etype; tf_expr = e; } in
11081131 let e = mk (TFunction tf) (tfun [] e.etype) e.epos in
1109 let actx = create_analyzer_context ctx.Typecore.com {config with optimize = false} e in
1132 let actx = create_analyzer_context com {config with optimize = false} (Printf.sprintf "%s.__init__" (s_type_path c.cl_path)) e in
11101133 let e = run_on_expr actx e in
11111134 let e = match e.eexpr with
11121135 | TFunction tf -> tf.tf_expr
11151138 c.cl_init <- Some e
11161139 end
11171140
1118 let run_on_type ctx config t =
1141 let run_on_type com config t =
11191142 match t with
11201143 | TClassDecl c when (is_ignored c.cl_meta) -> ()
1121 | TClassDecl c -> run_on_class ctx config c
1144 | TClassDecl c -> run_on_class com config c
11221145 | TEnumDecl _ -> ()
11231146 | TTypeDecl _ -> ()
11241147 | TAbstractDecl _ -> ()
11251148
1126 let run_on_types ctx types =
1127 let com = ctx.Typecore.com in
1149 let run_on_types com types =
11281150 let config = get_base_config com in
1129 with_timer config.detail_times ["other"] (fun () ->
1151 with_timer config.detail_times "" ["other"] (fun () ->
11301152 if config.optimize && config.purity_inference then
1131 with_timer config.detail_times ["optimize";"purity-inference"] (fun () -> Purity.infer com);
1132 List.iter (run_on_type ctx config) types
1153 with_timer config.detail_times "" ["optimize";"purity-inference"] (fun () -> Purity.infer com);
1154 List.iter (run_on_type com config) types
11331155 )
11341156 end
11351157 ;;
1136 Typecore.analyzer_run_on_expr_ref := (fun com e ->
1158 Typecore.analyzer_run_on_expr_ref := (fun com identifier e ->
11371159 let config = AnalyzerConfig.get_base_config com in
11381160 (* We always want to optimize because const propagation might be required to obtain
11391161 a constant expression for inline field initializations (see issue #4977). *)
11401162 let config = {config with AnalyzerConfig.optimize = true} in
1141 let actx = Run.create_analyzer_context com config e in
1163 let actx = Run.create_analyzer_context com config identifier e in
11421164 Run.run_on_expr actx e
11431165 )
3434 fusion : bool;
3535 purity_inference : bool;
3636 debug_kind : debug_kind;
37 detail_times : bool;
37 detail_times : int;
3838 user_var_fusion : bool;
3939 fusion_debug : bool;
4040 }
6464 let get_base_config com =
6565 {
6666 optimize = Common.defined com Define.AnalyzerOptimize;
67 const_propagation = not (Common.raw_defined com "analyzer-no-const-propagation");
68 copy_propagation = not (Common.raw_defined com "analyzer-no-copy-propagation");
69 local_dce = not (Common.raw_defined com "analyzer-no-local-dce");
70 fusion = not (Common.raw_defined com "analyzer-no-fusion");
71 purity_inference = not (Common.raw_defined com "analyzer-no-purity-inference");
67 const_propagation = not (Common.raw_defined com "analyzer_no_const_propagation");
68 copy_propagation = not (Common.raw_defined com "analyzer_no_copy_propagation");
69 local_dce = not (Common.raw_defined com "analyzer_no_local_dce");
70 fusion = not (Common.raw_defined com "analyzer_no_fusion");
71 purity_inference = not (Common.raw_defined com "analyzer_no_purity_inference");
7272 debug_kind = DebugNone;
73 detail_times = Common.raw_defined com "analyzer-times";
74 user_var_fusion = (match com.platform with Flash | Java -> false | _ -> true) && (Common.raw_defined com "analyzer-user-var-fusion" || (not com.debug && not (Common.raw_defined com "analyzer-no-user-var-fusion")));
73 detail_times = (try int_of_string (Common.defined_value_safe com ~default:"0" Define.AnalyzerTimes) with _ -> 0);
74 user_var_fusion = (match com.platform with Flash | Java -> false | _ -> true) && (Common.raw_defined com "analyzer_user_var_fusion" || (not com.debug && not (Common.raw_defined com "analyzer_no_user_var_fusion")));
7575 fusion_debug = false;
7676 }
7777
78 let update_config_from_meta com config meta =
78 let update_config_from_meta com config ml =
7979 List.fold_left (fun config meta -> match meta with
8080 | (Meta.Analyzer,el,_) ->
8181 List.fold_left (fun config e -> match fst e with
9898 | "fusion_debug" -> { config with fusion_debug = true }
9999 | "as_var" -> config
100100 | _ ->
101 com.warning (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);
101 let options = Warning.from_meta ml in
102 com.warning WOptimizer options (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);
102103 config
103104 end
104105 | _ ->
105106 let s = Ast.Printer.s_expr e in
106 com.warning (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);
107 let options = Warning.from_meta ml in
108 com.warning WOptimizer options (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);
107109 config
108110 ) config el
109111 | (Meta.HasUntyped,_,_) ->
110112 {config with optimize = false}
111113 | _ ->
112114 config
113 ) config meta
115 ) config ml
114116
115117 let get_class_config com c =
116118 let config = get_base_config com in
2323 open Globals
2424
2525 let s_expr_pretty e = s_expr_pretty false "" false (s_type (print_context())) e
26
27 let rec is_true_expr e1 = match e1.eexpr with
28 | TConst(TBool true) -> true
29 | TParenthesis e1 -> is_true_expr e1
30 | _ -> false
3126
3227 let is_stack_allocated c = Meta.has Meta.StructAccess c.cl_meta
3328
166161 | TLazy f ->
167162 is_nullable_or_whatever (lazy_type f)
168163 | TType (t,tl) ->
169 is_nullable_or_whatever (apply_params t.t_params tl t.t_type)
164 is_nullable_or_whatever (apply_typedef t tl)
170165 | TFun _ ->
171166 false
172167 | TInst ({ cl_kind = KTypeParameter _ },_) ->
503498 | OpAssignOp _
504499 | OpInterval
505500 | OpIn
501 | OpNullCoal
506502 | OpArrow ->
507503 false
508504
517513 | Cs when is_null e1.etype || is_null e2.etype -> false (* C# hates OpAssignOp on Null<T> *)
518514 | _ -> true
519515
520 let apply com config e =
516 let apply actx e =
517 let config = actx.AnalyzerTypes.config in
518 let com = actx.com in
521519 let state = new fusion_state in
522 state#infer_from_texpr e;
520 actx.with_timer ["<-";"fusion";"infer_from_texpr"] (fun () -> state#infer_from_texpr e);
523521 (* Handles block-level expressions, e.g. by removing side-effect-free ones and recursing into compound constructs like
524522 array or object declarations. The resulting element list is reversed.
525523 INFO: `el` is a reversed list of expressions in a block.
583581 | [] ->
584582 acc
585583 in
584 let block_element ?(loop_bottom=false) acc el =
585 actx.with_timer ["<-";"fusion";"block_element"] (fun () -> block_element ~loop_bottom acc el)
586 in
586587 let can_be_fused v e =
587588 let num_uses = state#get_reads v in
588589 let num_writes = state#get_writes v in
589590 let can_be_used_as_value = can_be_used_as_value com e in
590591 let is_compiler_generated = match v.v_kind with VUser _ | VInlined -> false | _ -> true in
591592 let has_type_params = match v.v_extra with Some ve when ve.v_params <> [] -> true | _ -> false in
593 let rec is_impure_extern e = match e.eexpr with
594 | TField(ef,(FStatic(cl,cf) | FInstance(cl,_,cf))) when has_class_flag cl CExtern ->
595 not (
596 Meta.has Meta.CoreApi cl.cl_meta ||
597 PurityState.is_pure cl cf
598 )
599 | _ -> check_expr is_impure_extern e
600 in
601 let is_impure_extern = (is_impure_extern e) in
602 let has_variable_semantics = ExtType.has_variable_semantics v.v_type in
603 let is_variable_expression = (match e.eexpr with TLocal { v_kind = VUser _ } -> false | _ -> true) in
592604 let b = num_uses <= 1 &&
593605 num_writes = 0 &&
594606 can_be_used_as_value &&
595607 not (
596 ExtType.has_variable_semantics v.v_type &&
597 (match e.eexpr with TLocal { v_kind = VUser _ } -> false | _ -> true)
598 ) &&
599 (is_compiler_generated || config.optimize && config.fusion && config.user_var_fusion && not has_type_params)
608 has_variable_semantics &&
609 is_variable_expression
610 ) && (
611 is_compiler_generated ||
612 config.optimize && config.fusion && config.user_var_fusion && not has_type_params && not is_impure_extern
613 )
600614 in
601615 if config.fusion_debug then begin
602616 print_endline (Printf.sprintf "\nFUSION: %s\n\tvar %s<%i> = %s" (if b then "true" else "false") v.v_name v.v_id (s_expr_pretty e));
603 print_endline (Printf.sprintf "CONDITION:\n\tnum_uses:%i <= 1 && num_writes:%i = 0 && can_be_used_as_value:%b && (is_compiler_generated:%b || config.optimize:%b && config.fusion:%b && config.user_var_fusion:%b)"
604 num_uses num_writes can_be_used_as_value is_compiler_generated config.optimize config.fusion config.user_var_fusion)
617 print_endline (Printf.sprintf "CONDITION:\n\tnum_uses:%i <= 1 && num_writes:%i = 0 && can_be_used_as_value:%b && not (has_variable_semantics:%b && e.eexpr=TLocal:%b) (is_compiler_generated:%b || config.optimize:%b && config.fusion:%b && config.user_var_fusion:%b && not has_type_params:%b && not is_impuare_extern:%b)"
618 num_uses num_writes can_be_used_as_value has_variable_semantics is_variable_expression is_compiler_generated config.optimize config.fusion config.user_var_fusion has_type_params is_impure_extern)
605619 end;
606620 b
621 in
622 let handle_assigned_local v1 e1 el =
623 let found = ref false in
624 let blocked = ref false in
625 let ir = InterferenceReport.from_texpr e1 in
626 if config.fusion_debug then print_endline (Printf.sprintf "INTERFERENCE: %s\nINTO: %s"
627 (InterferenceReport.to_string ir) (Type.s_expr_pretty true "" false (s_type (print_context())) (mk (TBlock el) t_dynamic null_pos)));
628 (* This function walks the AST in order of evaluation and tries to find an occurrence of v1. If successful, that occurrence is
629 replaced with e1. If there's an interference "on the way" the replacement is canceled. *)
630 let rec replace e =
631 let explore e =
632 let old = !blocked in
633 blocked := true;
634 let e = replace e in
635 blocked := old;
636 e
637 in
638 let handle_el' el =
639 (* This mess deals with the fact that the order of evaluation is undefined for call
640 arguments on these targets. Even if we find a replacement, we pretend that we
641 didn't in order to find possible interferences in later call arguments. *)
642 let temp_found = false in
643 let really_found = ref !found in
644 let el = List.map (fun e ->
645 found := temp_found;
646 let e = replace e in
647 if !found then really_found := true;
648 e
649 ) el in
650 found := !really_found;
651 el
652 in
653 let handle_el = if not (target_handles_side_effect_order com) then handle_el' else List.map replace in
654 let handle_call e2 el = match com.platform with
655 | Neko ->
656 (* Neko has this reversed at the moment (issue #4787) *)
657 let el = List.map replace el in
658 let e2 = replace e2 in
659 e2,el
660 | Cpp ->
661 let e2 = replace e2 in
662 let el = handle_el el in
663 e2,el
664 | _ ->
665 let e2 = replace e2 in
666 let el = List.map replace el in
667 e2,el
668 in
669 if !found then e else match e.eexpr with
670 | TWhile _ | TTry _ ->
671 raise Exit
672 | TFunction _ ->
673 e
674 | TIf(e1,e2,eo) ->
675 let e1 = replace e1 in
676 if not !found && (has_state_write ir || has_any_field_write ir || has_any_var_write ir) then raise Exit;
677 let e2 = replace e2 in
678 let eo = Option.map replace eo in
679 {e with eexpr = TIf(e1,e2,eo)}
680 | TSwitch(e1,cases,edef) ->
681 let e1 = match com.platform with
682 | Lua | Python -> explore e1
683 | _ -> replace e1
684 in
685 if not !found then raise Exit;
686 {e with eexpr = TSwitch(e1,cases,edef)}
687 (* locals *)
688 | TLocal v2 when v1 == v2 && not !blocked ->
689 found := true;
690 if type_change_ok com v1.v_type e1.etype then e1 else mk (TCast(e1,None)) v1.v_type e.epos
691 | TLocal v ->
692 if has_var_write ir v || ((has_var_flag v VCaptured || ExtType.has_reference_semantics v.v_type) && (has_state_write ir)) then raise Exit;
693 e
694 | TBinop(OpAssign,({eexpr = TLocal v} as e1),e2) ->
695 let e2 = replace e2 in
696 if not !found && has_var_read ir v then raise Exit;
697 {e with eexpr = TBinop(OpAssign,e1,e2)}
698 (* Never fuse into write-positions (issue #7298) *)
699 | TBinop(OpAssignOp _,{eexpr = TLocal v2},_) | TUnop((Increment | Decrement),_,{eexpr = TLocal v2}) when v1 == v2 ->
700 raise Exit
701 | TBinop(OpAssignOp _ as op,({eexpr = TLocal v} as e1),e2) ->
702 let e2 = replace e2 in
703 if not !found && (has_var_read ir v || has_var_write ir v) then raise Exit;
704 {e with eexpr = TBinop(op,e1,e2)}
705 | TUnop((Increment | Decrement),_,{eexpr = TLocal v}) when has_var_read ir v || has_var_write ir v ->
706 raise Exit
707 (* fields *)
708 | TField(e1,fa) ->
709 let e1 = replace e1 in
710 if not !found && not (is_read_only_field_access e1 fa) && (has_field_write ir (field_name fa) || has_state_write ir) then raise Exit;
711 {e with eexpr = TField(e1,fa)}
712 | TBinop(OpAssign,({eexpr = TField(e1,fa)} as ef),e2) ->
713 let e1 = replace e1 in
714 let e2 = replace e2 in
715 if not !found && (has_field_read ir (field_name fa) || has_state_read ir) then raise Exit;
716 {e with eexpr = TBinop(OpAssign,{ef with eexpr = TField(e1,fa)},e2)}
717 | TBinop(OpAssignOp _ as op,({eexpr = TField(e1,fa)} as ef),e2) ->
718 let e1 = replace e1 in
719 let s = field_name fa in
720 if not !found && (has_field_write ir s || has_state_write ir) then raise Exit;
721 let e2 = replace e2 in
722 if not !found && (has_field_read ir s || has_state_read ir) then raise Exit;
723 {e with eexpr = TBinop(op,{ef with eexpr = TField(e1,fa)},e2)}
724 | TUnop((Increment | Decrement),_,{eexpr = TField(e1,fa)}) when has_field_read ir (field_name fa) || has_state_read ir
725 || has_field_write ir (field_name fa) || has_state_write ir ->
726 raise Exit
727 (* array *)
728 | TArray(e1,e2) ->
729 let e1 = replace e1 in
730 let e2 = replace e2 in
731 if not !found && has_state_write ir then raise Exit;
732 {e with eexpr = TArray(e1,e2)}
733 | TBinop(OpAssign,({eexpr = TArray(e1,e2)} as ef),e3) ->
734 let e1 = replace e1 in
735 let e2 = replace e2 in
736 let e3 = replace e3 in
737 if not !found && (has_state_read ir) then raise Exit;
738 {e with eexpr = TBinop(OpAssign,{ef with eexpr = TArray(e1,e2)},e3)}
739 | TBinop(OpAssignOp _ as op,({eexpr = TArray(e1,e2)} as ef),e3) ->
740 let e1 = replace e1 in
741 let e2 = replace e2 in
742 if not !found && has_state_write ir then raise Exit;
743 let e3 = replace e3 in
744 if not !found && has_state_read ir then raise Exit;
745 {e with eexpr = TBinop(op,{ef with eexpr = TArray(e1,e2)},e3)}
746 | TUnop((Increment | Decrement),_,{eexpr = TArray _}) when has_state_read ir || has_state_write ir ->
747 raise Exit
748 (* state *)
749 | TCall({eexpr = TIdent s},el) when not (is_unbound_call_that_might_have_side_effects s el) ->
750 e
751 | TNew(c,tl,el) when (match c.cl_constructor with Some cf when PurityState.is_pure c cf -> true | _ -> false) ->
752 let el = handle_el el in
753 if not !found && (has_state_write ir || has_any_field_write ir) then raise Exit;
754 {e with eexpr = TNew(c,tl,el)}
755 | TNew(c,tl,el) ->
756 let el = handle_el el in
757 if not !found && (has_state_write ir || has_state_read ir || has_any_field_read ir || has_any_field_write ir) then raise Exit;
758 {e with eexpr = TNew(c,tl,el)}
759 | TCall({eexpr = TField(_,FEnum _)} as ef,el) ->
760 let el = handle_el el in
761 {e with eexpr = TCall(ef,el)}
762 | TCall({eexpr = TField(_,fa)} as ef,el) when PurityState.is_pure_field_access fa ->
763 let ef,el = handle_call ef el in
764 if not !found && (has_state_write ir || has_any_field_write ir) then raise Exit;
765 {e with eexpr = TCall(ef,el)}
766 | TCall(e1,el) ->
767 let e1,el = match e1.eexpr with
768 | TIdent s when s <> "`trace" && s <> "__int__" -> e1,el
769 | _ -> handle_call e1 el
770 in
771 if not !found && (((has_state_read ir || has_any_field_read ir)) || has_state_write ir || has_any_field_write ir) then raise Exit;
772 {e with eexpr = TCall(e1,el)}
773 | TObjectDecl fl ->
774 (* The C# generator has trouble with evaluation order in structures (#7531). *)
775 let el = (match com.platform with Cs -> handle_el' | _ -> handle_el) (List.map snd fl) in
776 if not !found && (has_state_write ir || has_any_field_write ir) then raise Exit;
777 {e with eexpr = TObjectDecl (List.map2 (fun (s,_) e -> s,e) fl el)}
778 | TArrayDecl el ->
779 let el = handle_el el in
780 (*if not !found && (has_state_write ir || has_any_field_write ir) then raise Exit;*)
781 {e with eexpr = TArrayDecl el}
782 | TBinop(op,e1,e2) when (match com.platform with Cpp -> true | _ -> false) ->
783 let e1 = replace e1 in
784 let temp_found = !found in
785 found := false;
786 let e2 = replace e2 in
787 found := !found || temp_found;
788 {e with eexpr = TBinop(op,e1,e2)}
789 | _ ->
790 Type.map_expr replace e
791 in
792 let replace e =
793 actx.with_timer ["<-";"fusion";"fuse";"replace"] (fun () -> replace e)
794 in
795 begin try
796 let rec loop acc el = match el with
797 | e :: el ->
798 let e = replace e in
799 if !found then (List.rev (e :: acc)) @ el
800 else loop (e :: acc) el
801 | [] ->
802 List.rev acc
803 in
804 let el = loop [] el in
805 if not !found then raise Exit;
806 state#changed;
807 state#dec_reads v1;
808 if config.fusion_debug then print_endline (Printf.sprintf "YES: %s" (s_expr_pretty (mk (TBlock el) t_dynamic null_pos)));
809 Some el
810 with Exit ->
811 if config.fusion_debug then print_endline (Printf.sprintf "NO: %s" (Printexc.get_backtrace()));
812 None
813 end
607814 in
608815 let rec fuse acc el = match el with
609816 | ({eexpr = TVar(v1,None)} as e1) :: {eexpr = TBinop(OpAssign,{eexpr = TLocal v2},e2)} :: el when v1 == v2 ->
677884 with Exit ->
678885 fuse (ev :: acc) el
679886 end
887
680888 | ({eexpr = TVar(v1,Some e1)} as ev) :: el when can_be_fused v1 e1 ->
681 let found = ref false in
682 let blocked = ref false in
683 let ir = InterferenceReport.from_texpr e1 in
684 if config.fusion_debug then print_endline (Printf.sprintf "INTERFERENCE: %s\nINTO: %s"
685 (InterferenceReport.to_string ir) (Type.s_expr_pretty true "" false (s_type (print_context())) (mk (TBlock el) t_dynamic null_pos)));
686 (* This function walks the AST in order of evaluation and tries to find an occurrence of v1. If successful, that occurrence is
687 replaced with e1. If there's an interference "on the way" the replacement is canceled. *)
688 let rec replace e =
689 let explore e =
690 let old = !blocked in
691 blocked := true;
692 let e = replace e in
693 blocked := old;
694 e
695 in
696 let handle_el' el =
697 (* This mess deals with the fact that the order of evaluation is undefined for call
698 arguments on these targets. Even if we find a replacement, we pretend that we
699 didn't in order to find possible interferences in later call arguments. *)
700 let temp_found = false in
701 let really_found = ref !found in
702 let el = List.map (fun e ->
703 found := temp_found;
704 let e = replace e in
705 if !found then really_found := true;
706 e
707 ) el in
708 found := !really_found;
709 el
710 in
711 let handle_el = if not (target_handles_side_effect_order com) then handle_el' else List.map replace in
712 let handle_call e2 el = match com.platform with
713 | Neko ->
714 (* Neko has this reversed at the moment (issue #4787) *)
715 let el = List.map replace el in
716 let e2 = replace e2 in
717 e2,el
718 | Cpp ->
719 let e2 = replace e2 in
720 let el = handle_el el in
721 e2,el
722 | _ ->
723 let e2 = replace e2 in
724 let el = List.map replace el in
725 e2,el
726 in
727 if !found then e else match e.eexpr with
728 | TWhile _ | TTry _ ->
889 begin match el with
890 | ({eexpr = TUnop((Increment | Decrement) as op,Prefix,{eexpr = TLocal v1})} as e2) :: el ->
891 let found = ref false in
892 let rec replace e = match e.eexpr with
893 | TLocal v2 when v1 == v2 ->
894 if !found then raise Exit;
895 found := true;
896 {e with eexpr = TUnop(op,Postfix,e)}
897 | TIf _ | TSwitch _ | TTry _ | TWhile _ | TFor _ ->
729898 raise Exit
730 | TFunction _ ->
731 e
732 | TIf(e1,e2,eo) ->
733 let e1 = replace e1 in
734 if not !found && (has_state_write ir || has_any_field_write ir || has_any_var_write ir) then raise Exit;
735 let e2 = replace e2 in
736 let eo = Option.map replace eo in
737 {e with eexpr = TIf(e1,e2,eo)}
738 | TSwitch(e1,cases,edef) ->
739 let e1 = match com.platform with
740 | Lua | Python -> explore e1
741 | _ -> replace e1
742 in
743 if not !found then raise Exit;
744 {e with eexpr = TSwitch(e1,cases,edef)}
745 (* locals *)
746 | TLocal v2 when v1 == v2 && not !blocked ->
747 found := true;
748 if type_change_ok com v1.v_type e1.etype then e1 else mk (TCast(e1,None)) v1.v_type e.epos
749 | TLocal v ->
750 if has_var_write ir v || ((has_var_flag v VCaptured || ExtType.has_reference_semantics v.v_type) && (has_state_write ir)) then raise Exit;
751 e
752 | TBinop(OpAssign,({eexpr = TLocal v} as e1),e2) ->
753 let e2 = replace e2 in
754 if not !found && has_var_read ir v then raise Exit;
755 {e with eexpr = TBinop(OpAssign,e1,e2)}
756 (* Never fuse into write-positions (issue #7298) *)
757 | TBinop(OpAssignOp _,{eexpr = TLocal v2},_) | TUnop((Increment | Decrement),_,{eexpr = TLocal v2}) when v1 == v2 ->
758 raise Exit
759 | TBinop(OpAssignOp _ as op,({eexpr = TLocal v} as e1),e2) ->
760 let e2 = replace e2 in
761 if not !found && (has_var_read ir v || has_var_write ir v) then raise Exit;
762 {e with eexpr = TBinop(op,e1,e2)}
763 | TUnop((Increment | Decrement),_,{eexpr = TLocal v}) when has_var_read ir v || has_var_write ir v ->
764 raise Exit
765 (* fields *)
766 | TField(e1,fa) ->
767 let e1 = replace e1 in
768 if not !found && not (is_read_only_field_access e1 fa) && (has_field_write ir (field_name fa) || has_state_write ir) then raise Exit;
769 {e with eexpr = TField(e1,fa)}
770 | TBinop(OpAssign,({eexpr = TField(e1,fa)} as ef),e2) ->
771 let e1 = replace e1 in
772 let e2 = replace e2 in
773 if not !found && (has_field_read ir (field_name fa) || has_state_read ir) then raise Exit;
774 {e with eexpr = TBinop(OpAssign,{ef with eexpr = TField(e1,fa)},e2)}
775 | TBinop(OpAssignOp _ as op,({eexpr = TField(e1,fa)} as ef),e2) ->
776 let e1 = replace e1 in
777 let s = field_name fa in
778 if not !found && (has_field_write ir s || has_state_write ir) then raise Exit;
779 let e2 = replace e2 in
780 if not !found && (has_field_read ir s || has_state_read ir) then raise Exit;
781 {e with eexpr = TBinop(op,{ef with eexpr = TField(e1,fa)},e2)}
782 | TUnop((Increment | Decrement),_,{eexpr = TField(e1,fa)}) when has_field_read ir (field_name fa) || has_state_read ir
783 || has_field_write ir (field_name fa) || has_state_write ir ->
784 raise Exit
785 (* array *)
786 | TArray(e1,e2) ->
787 let e1 = replace e1 in
788 let e2 = replace e2 in
789 if not !found && has_state_write ir then raise Exit;
790 {e with eexpr = TArray(e1,e2)}
791 | TBinop(OpAssign,({eexpr = TArray(e1,e2)} as ef),e3) ->
792 let e1 = replace e1 in
793 let e2 = replace e2 in
794 let e3 = replace e3 in
795 if not !found && (has_state_read ir) then raise Exit;
796 {e with eexpr = TBinop(OpAssign,{ef with eexpr = TArray(e1,e2)},e3)}
797 | TBinop(OpAssignOp _ as op,({eexpr = TArray(e1,e2)} as ef),e3) ->
798 let e1 = replace e1 in
799 let e2 = replace e2 in
800 if not !found && has_state_write ir then raise Exit;
801 let e3 = replace e3 in
802 if not !found && has_state_read ir then raise Exit;
803 {e with eexpr = TBinop(op,{ef with eexpr = TArray(e1,e2)},e3)}
804 | TUnop((Increment | Decrement),_,{eexpr = TArray _}) when has_state_read ir || has_state_write ir ->
805 raise Exit
806 (* state *)
807 | TCall({eexpr = TIdent s},el) when not (is_unbound_call_that_might_have_side_effects s el) ->
808 e
809 | TNew(c,tl,el) when (match c.cl_constructor with Some cf when PurityState.is_pure c cf -> true | _ -> false) ->
810 let el = handle_el el in
811 if not !found && (has_state_write ir || has_any_field_write ir) then raise Exit;
812 {e with eexpr = TNew(c,tl,el)}
813 | TNew(c,tl,el) ->
814 let el = handle_el el in
815 if not !found && (has_state_write ir || has_state_read ir || has_any_field_read ir || has_any_field_write ir) then raise Exit;
816 {e with eexpr = TNew(c,tl,el)}
817 | TCall({eexpr = TField(_,FEnum _)} as ef,el) ->
818 let el = handle_el el in
819 {e with eexpr = TCall(ef,el)}
820 | TCall({eexpr = TField(_,fa)} as ef,el) when PurityState.is_pure_field_access fa ->
821 let ef,el = handle_call ef el in
822 if not !found && (has_state_write ir || has_any_field_write ir) then raise Exit;
823 {e with eexpr = TCall(ef,el)}
824 | TCall(e1,el) ->
825 let e1,el = match e1.eexpr with
826 | TIdent s when s <> "`trace" && s <> "__int__" -> e1,el
827 | _ -> handle_call e1 el
828 in
829 if not !found && (((has_state_read ir || has_any_field_read ir)) || has_state_write ir || has_any_field_write ir) then raise Exit;
830 {e with eexpr = TCall(e1,el)}
831 | TObjectDecl fl ->
832 (* The C# generator has trouble with evaluation order in structures (#7531). *)
833 let el = (match com.platform with Cs -> handle_el' | _ -> handle_el) (List.map snd fl) in
834 if not !found && (has_state_write ir || has_any_field_write ir) then raise Exit;
835 {e with eexpr = TObjectDecl (List.map2 (fun (s,_) e -> s,e) fl el)}
836 | TArrayDecl el ->
837 let el = handle_el el in
838 (*if not !found && (has_state_write ir || has_any_field_write ir) then raise Exit;*)
839 {e with eexpr = TArrayDecl el}
840 | TBinop(op,e1,e2) when (match com.platform with Cpp -> true | _ -> false) ->
841 let e1 = replace e1 in
842 let temp_found = !found in
843 found := false;
844 let e2 = replace e2 in
845 found := !found || temp_found;
846 {e with eexpr = TBinop(op,e1,e2)}
847899 | _ ->
848900 Type.map_expr replace e
849 in
850 begin try
851 let rec loop acc el = match el with
852 | e :: el ->
853 let e = replace e in
854 if !found then (List.rev (e :: acc)) @ el
855 else loop (e :: acc) el
856 | [] ->
857 List.rev acc
858901 in
859 let el = loop [] el in
860 if not !found then raise Exit;
861 state#changed;
862 state#dec_reads v1;
863 if config.fusion_debug then print_endline (Printf.sprintf "YES: %s" (s_expr_pretty (mk (TBlock el) t_dynamic null_pos)));
864 fuse acc el
865 with Exit ->
866 if config.fusion_debug then print_endline (Printf.sprintf "NO: %s" (Printexc.get_backtrace()));
867 begin match el with
868 | ({eexpr = TUnop((Increment | Decrement) as op,Prefix,{eexpr = TLocal v1})} as e2) :: el ->
869 let found = ref false in
870 let rec replace e = match e.eexpr with
871 | TLocal v2 when v1 == v2 ->
872 if !found then raise Exit;
873 found := true;
874 {e with eexpr = TUnop(op,Postfix,e)}
875 | TIf _ | TSwitch _ | TTry _ | TWhile _ | TFor _ ->
876 raise Exit
877 | _ ->
878 Type.map_expr replace e
879 in
880 begin try
881 let ev = replace ev in
882 if not !found then raise Exit;
883 state#changed;
884 fuse acc (ev :: el)
885 with Exit ->
886 fuse (ev :: acc) (e2 :: el)
887 end
888 | _ ->
902 begin try
903 let ev = replace ev in
904 if not !found then raise Exit;
905 state#changed;
906 fuse acc (ev :: el)
907 with Exit ->
908 fuse (ev :: acc) (e2 :: el)
909 end
910 | _ ->
911 begin match handle_assigned_local v1 e1 el with
912 | Some el ->
913 fuse acc el
914 | None ->
889915 fuse (ev :: acc) el
890916 end
891917 end
938964 | [] ->
939965 acc
940966 in
967 let fuse acc el =
968 actx.with_timer ["<-";"fusion";"fuse"] (fun () -> fuse [] el)
969 in
941970 let rec loop e = match e.eexpr with
942971 | TWhile(condition,{ eexpr = TBlock el; etype = t; epos = p },flag) ->
943972 let condition = loop condition
10021031 | TWhile(e1,e2,NormalWhile) ->
10031032 let e1 = loop e1 in
10041033 let e2 = loop e2 in
1034 let rec has_continue e = match e.eexpr with
1035 | TContinue ->
1036 true
1037 | _ ->
1038 check_expr has_continue e
1039 in
1040 let has_continue = has_continue e2 in
10051041 begin match e2.eexpr with
10061042 | TBlock ({eexpr = TIf(e1,({eexpr = TBlock[{eexpr = TBreak}]} as eb),None)} :: el2) ->
10071043 let e1 = Texpr.skip e1 in
10081044 let e1 = match e1.eexpr with TUnop(_,_,e1) -> e1 | _ -> {e1 with eexpr = TUnop(Not,Prefix,e1)} in
10091045 {e with eexpr = TWhile(e1,{eb with eexpr = TBlock el2},NormalWhile)}
10101046 | TBlock el ->
1047 let do_while = ref None in
1048 let locals = ref IntMap.empty in
1049 let rec collect_vars e = match e.eexpr with
1050 | TVar(v,e1) ->
1051 locals := IntMap.add v.v_id true !locals;
1052 Option.may collect_vars e1
1053 | _ ->
1054 Type.iter collect_vars e
1055 in
1056 let rec references_local e = match e.eexpr with
1057 | TLocal v when IntMap.mem v.v_id !locals -> true
1058 | _ -> check_expr references_local e
1059 in
1060 let can_do = match com.platform with Hl -> false | _ -> true in
10111061 let rec loop2 el = match el with
1062 | [{eexpr = TBreak}] when is_true_expr e1 && can_do && not has_continue ->
1063 do_while := Some (Texpr.Builder.make_bool com.basic true e1.epos);
1064 []
1065 | [{eexpr = TIf(econd,{eexpr = TBlock[{eexpr = TBreak}]},None)}] when is_true_expr e1 && not (references_local econd) && can_do && not has_continue ->
1066 do_while := Some econd;
1067 []
10121068 | {eexpr = TBreak | TContinue | TReturn _ | TThrow _} as e :: el ->
10131069 [e]
10141070 | e :: el ->
1071 collect_vars e;
10151072 e :: (loop2 el)
10161073 | [] ->
10171074 []
10181075 in
10191076 let el = loop2 el in
1020 {e with eexpr = TWhile(e1,{e2 with eexpr = TBlock el},NormalWhile)}
1077 begin match !do_while with
1078 | None ->
1079 {e with eexpr = TWhile(e1,{e2 with eexpr = TBlock el},NormalWhile)}
1080 | Some econd ->
1081 let econd = {econd with eexpr = TUnop(Not,Prefix,econd)} in
1082 {e with eexpr = TWhile(econd,{e2 with eexpr = TBlock el},DoWhile)}
1083 end;
10211084 | _ ->
10221085 {e with eexpr = TWhile(e1,e2,NormalWhile)}
10231086 end
11781241 apply_to_class com c
11791242 with Purity_conflict(impure,p) ->
11801243 com.error "Impure field overrides/implements field which was explicitly marked as @:pure" impure.pn_field.cf_pos;
1181 Error.error (Error.compl_msg "Pure field is here") p;
1244 Error.typing_error ~depth:1 (Error.compl_msg "Pure field is here") p;
11821245 end
11831246 | _ -> ()
11841247 ) com.types;
8484 if is_unbound_call_that_might_have_side_effects s el then ctx.has_unbound <- true;
8585 in
8686 let no_void t p =
87 if ExtType.is_void (follow t) then Error.error "Cannot use Void as value" p
87 if ExtType.is_void (follow t) then Error.typing_error "Cannot use Void as value" p
8888 in
8989 let push_name s =
9090 ctx.name_stack <- s :: ctx.name_stack;
9191 (fun () -> ctx.name_stack <- List.tl ctx.name_stack)
92 in
93 let check_ref v e = if ExtType.has_reference_semantics v.v_type then match (Texpr.skip e).eexpr with
94 | TLocal v' -> add_var_flag v' VCaptured
95 | _ -> ()
9296 in
9397 let rec value' bb e = match e.eexpr with
9498 | TLocal _ | TIdent _ ->
98102 | TBlock [e1] ->
99103 value bb e1
100104 | TBlock _ | TIf _ | TSwitch _ | TTry _ ->
101 bind_to_temp bb false e
105 bind_to_temp bb e
102106 | TCall({eexpr = TIdent s},el) when is_really_unbound s ->
103107 check_unbound_call s el;
104108 bb,e
174178 let bb = block_element bb e in
175179 bb,mk (TConst TNull) t_dynamic e.epos
176180 | TVar _ | TFor _ | TWhile _ ->
177 Error.error "Cannot use this expression as value" e.epos
181 Error.typing_error "Cannot use this expression as value" e.epos
178182 and value bb e =
179183 let bb,e = value' bb e in
180184 no_void e.etype e.epos;
200204 if bb == g.g_unreachable then
201205 bb,acc
202206 else begin
203 let bb,value = if aff || opt then bind_to_temp bb aff e else value bb e in
207 let bb,value = if aff || opt then bind_to_temp bb e else value bb e in
204208 bb,(value :: acc)
205209 end
206210 ) (bb,[]) el in
207211 bb,List.rev values
208 and bind_to_temp ?(v=None) bb sequential e =
212 and bind_to_temp ?(v=None) bb e =
209213 let is_probably_not_affected e e1 fa = match fa with
210214 | FAnon cf | FInstance (_,_,cf) | FStatic (_,cf) | FClosure (_,cf) when cf.cf_kind = Method MethNormal -> true
211215 | FStatic(_,{cf_kind = Method MethDynamic}) -> false
308312 | _ ->
309313 if ExtType.has_variable_semantics t then begin
310314 let v = alloc_var VGenerated "tmp" t e.epos in
311 let bb',e = bind_to_temp ~v:(Some v) !bb false e in
315 let bb',e = bind_to_temp ~v:(Some v) !bb e in
312316 bb := bb';
313317 e
314318 end else
320324 | e1 :: el -> bb,{e with eexpr = TCall(e1,el)}
321325 | _ -> die "" __LOC__
322326 and array_assign_op bb op e ea e1 e2 e3 =
323 let bb,e1 = bind_to_temp bb false e1 in
324 let bb,e2 = bind_to_temp bb false e2 in
327 let bb,e1 = bind_to_temp bb e1 in
328 let bb,e2 = bind_to_temp bb e2 in
325329 let ea = {ea with eexpr = TArray(e1,e2)} in
326 let bb,e4 = bind_to_temp bb false ea in
327 let bb,e3 = bind_to_temp bb false e3 in
330 let bb,e4 = bind_to_temp bb ea in
331 let bb,e3 = bind_to_temp bb e3 in
328332 let eop = {e with eexpr = TBinop(op,e4,e3)} in
329333 add_texpr bb {e with eexpr = TBinop(OpAssign,ea,eop)};
330334 bb,ea
331335 and field_assign_op bb op e ef e1 fa e2 =
332336 let bb,e1 = match fa with
333337 | FInstance(c,_,_) | FClosure(Some(c,_),_) when is_stack_allocated c -> bb,e1
334 | _ -> bind_to_temp bb false e1
338 | _ -> bind_to_temp bb e1
335339 in
336340 let ef = {ef with eexpr = TField(e1,fa)} in
337 let bb,e3 = bind_to_temp bb false ef in
338 let bb,e2 = bind_to_temp bb false e2 in
341 let bb,e3 = bind_to_temp bb ef in
342 let bb,e2 = bind_to_temp bb e2 in
339343 let eop = {e with eexpr = TBinop(op,e3,e2)} in
340344 add_texpr bb {e with eexpr = TBinop(OpAssign,ef,eop)};
341345 bb,ef
345349 add_texpr bb e;
346350 bb
347351 | TVar(v,Some e1) ->
352 check_ref v e1;
348353 declare_var_and_assign bb v e1 e.epos
349354 | TBinop(OpAssign,({eexpr = TLocal v} as e1),e2) ->
355 check_ref v e2;
350356 let assign e =
351357 mk (TBinop(OpAssign,e1,e)) e.etype e.epos
352358 in
363369 (* branching *)
364370 | TMeta((Meta.MergeBlock,_,_),{eexpr = TBlock el}) ->
365371 block_el bb el
372 | TBlock [] when (ExtType.is_void (follow e.etype)) ->
373 bb
366374 | TBlock el ->
367375 let bb_sub = create_node BKSub e.etype e.epos in
368376 add_cfg_edge bb bb_sub CFGGoto;
380388 bb_sub_next
381389 end
382390 | TIf(e1,e2,None) ->
383 let bb,e1 = bind_to_temp bb false e1 in
391 let bb,e1 = bind_to_temp bb e1 in
384392 if bb == g.g_unreachable then
385393 bb
386394 else begin
397405 bb_next
398406 end
399407 | TIf(e1,e2,Some e3) ->
400 let bb,e1 = bind_to_temp bb false e1 in
408 let bb,e1 = bind_to_temp bb e1 in
401409 if bb == g.g_unreachable then
402410 bb
403411 else begin
423431 end
424432 end
425433 | TSwitch(e1,cases,edef) ->
426 let is_exhaustive = edef <> None || is_exhaustive e1 in
427 let bb,e1 = bind_to_temp bb false e1 in
434 let is_exhaustive = is_exhaustive e1 edef in
435 let bb,e1 = bind_to_temp bb e1 in
428436 bb.bb_terminator <- TermCondBranch e1;
429437 let reachable = ref [] in
430438 let make_case e =
461469 bb_next
462470 end
463471 | TWhile(e1,e2,NormalWhile) ->
464 let bb_loop_pre = create_node BKNormal e1.etype e1.epos in
472 let bb_loop_pre = create_node BKLoopHead e1.etype e1.epos in
465473 add_cfg_edge bb bb_loop_pre CFGGoto;
466474 set_syntax_edge bb (SEMerge bb_loop_pre);
467475 close_node bb;
468 let bb_loop_head = create_node BKLoopHead e1.etype e1.epos in
469 add_cfg_edge bb_loop_pre bb_loop_head CFGGoto;
470 let close = begin_loop bb bb_loop_head in
476 let close = begin_loop bb bb_loop_pre in
471477 let bb_loop_body = create_node BKNormal e2.etype e2.epos in
472478 let bb_loop_body_next = block bb_loop_body e2 in
473479 let bb_breaks = close() in
480486 create_node BKNormal bb.bb_type bb.bb_pos
481487 in
482488 List.iter (fun bb -> add_cfg_edge bb bb_next CFGGoto) bb_breaks;
483 set_syntax_edge bb_loop_pre (SEWhile(bb_loop_head,bb_loop_body,bb_next,e.epos));
489 set_syntax_edge bb_loop_pre (SEWhile(bb_loop_body,bb_next,e.epos));
490 bb_loop_pre.bb_terminator <- TermCondBranch e1;
491 if bb_loop_body_next != g.g_unreachable then add_cfg_edge bb_loop_body_next bb_loop_pre CFGGoto;
492 add_cfg_edge bb_loop_pre bb_loop_body CFGGoto;
493 close_node bb_loop_body_next;
484494 close_node bb_loop_pre;
485 bb_loop_pre.bb_terminator <- TermCondBranch e1;
486 if bb_loop_body_next != g.g_unreachable then add_cfg_edge bb_loop_body_next bb_loop_head CFGGoto;
487 add_cfg_edge bb_loop_head bb_loop_body CFGGoto;
488 close_node bb_loop_body_next;
489 close_node bb_loop_head;
490495 bb_next;
491496 | TTry(e1,catches) ->
492497 let bb_try = create_node BKNormal e1.etype e1.epos in
678683 []
679684 else begin
680685 let block bb = block_to_texpr ctx bb in
686 let live bb = not ctx.did_optimize || not ctx.config.local_dce || has_block_flag bb BlockDce in
687 let if_live bb = if live bb then Some bb else None in
681688 let rec loop bb se =
689 let get_terminator() = match bb.bb_terminator with
690 | TermCondBranch e1 -> e1
691 | _ -> die "" __LOC__
692 in
682693 match se with
683694 | SESubBlock(bb_sub,bb_next) ->
684695 Some bb_next,Some (block bb_sub)
687698 | SENone ->
688699 None,terminator_to_texpr_maybe bb.bb_terminator
689700 | SETry(bb_try,_,bbl,bb_next,p) ->
690 Some bb_next,Some (mk (TTry(block bb_try,List.map (fun (v,bb) -> v,block bb) bbl)) ctx.com.basic.tvoid p)
691 | se ->
692 let e1 = match bb.bb_terminator with
693 | TermCondBranch e1 -> e1
694 | _ -> die "" __LOC__
695 in
696 let bb_next,e1_def,t,p = match se with
697 | SEIfThen(bb_then,bb_next,p) -> Some bb_next,TIf(e1,block bb_then,None),ctx.com.basic.tvoid,p
698 | SEIfThenElse(bb_then,bb_else,bb_next,t,p) -> Some bb_next,TIf(e1,block bb_then,Some (block bb_else)),t,p
699 | SESwitch(bbl,bo,bb_next,p) -> Some bb_next,TSwitch(e1,List.map (fun (el,bb) -> el,block bb) bbl,Option.map block bo),ctx.com.basic.tvoid,p
700 | SEWhile(_,bb_body,bb_next,p) ->
701 let e2 = block bb_body in
702 Some bb_next,TWhile(e1,e2,NormalWhile),ctx.com.basic.tvoid,p
703 | _ -> abort (Printf.sprintf "Invalid node exit: %s" (s_expr_pretty e1)) bb.bb_pos
704 in
705 bb_next,Some (mk e1_def t p)
701 if_live bb_next,Some (mk (TTry(block bb_try,List.map (fun (v,bb) -> v,block bb) bbl)) ctx.com.basic.tvoid p)
702 | SEIfThen(bb_then,bb_next,p) ->
703 if_live bb_next,Some (mk (TIf(get_terminator(),block bb_then,None)) ctx.com.basic.tvoid p)
704 | SEIfThenElse(bb_then,bb_else,bb_next,t,p) ->
705 if_live bb_next,Some (mk (TIf(get_terminator(),block bb_then,Some (block bb_else))) t p)
706 | SEWhile(bb_body,bb_next,p) ->
707 let e2 = block bb_body in
708 if_live bb_next,Some (mk (TWhile(get_terminator(),e2,NormalWhile)) ctx.com.basic.tvoid p)
709 | SESwitch(bbl,bo,bb_next,p) ->
710 Some bb_next,Some (mk (TSwitch(get_terminator(),List.map (fun (el,bb) -> el,block bb) bbl,Option.map block bo)) ctx.com.basic.tvoid p)
706711 in
707712 let bb_next,e_term = loop bb bb.bb_syntax_edge in
708713 let el = DynArray.to_list bb.bb_el in
741746 | OpAdd | OpMult | OpDiv | OpSub | OpAnd
742747 | OpOr | OpXor | OpShl | OpShr | OpUShr | OpMod ->
743748 true
744 | OpAssignOp _ | OpInterval | OpArrow | OpIn | OpAssign | OpEq
749 | OpAssignOp _ | OpInterval | OpArrow | OpIn | OpNullCoal | OpAssign | OpEq
745750 | OpNotEq | OpGt | OpGte | OpLt | OpLte | OpBoolAnd | OpBoolOr ->
746751 false
747752 in
771776 mk (TFunction {tf with tf_expr = e}) t p
772777
773778 let to_texpr ctx =
774 func ctx ctx.entry.bb_id
779 func ctx ctx.entry.bb_id
4242 | BKUnreachable (* The unique unreachable block *)
4343 | BKCatch of tvar (* A catch block *)
4444
45 type flag_block =
46 | BlockDce
47
4548 type cfg_edge_Flag =
4649 | FlagExecutable (* Used by constant propagation to handle live edges *)
4750 | FlagDce (* Used by DCE to keep track of handled edges *)
6669 | SEIfThenElse of t * t * t * Type.t * pos (* `if` with "then", "else" and "next" *)
6770 | SESwitch of (texpr list * t) list * t option * t * pos (* `switch` with cases, "default" and "next" *)
6871 | SETry of t * t * (tvar * t) list * t * pos (* `try` with "exc", catches and "next" *)
69 | SEWhile of t * t * t * pos (* `while` with "head", "body" and "next" *)
72 | SEWhile of t * t * pos (* `while` with "body" and "next" *)
7073 | SESubBlock of t * t (* "sub" with "next" *)
7174 | SEMerge of t (* Merge to same block *)
7275 | SENone (* No syntax exit *)
9295 bb_pos : pos; (* The block position *)
9396 bb_kind : block_kind; (* The block kind *)
9497 mutable bb_closed : bool; (* Whether or not the block has been closed *)
98 mutable bb_flags : int;
9599 (* elements *)
96100 bb_el : texpr DynArray.t; (* The block expressions *)
97101 bb_phi : texpr DynArray.t; (* SSA-phi expressions *)
114118 | LUEl of int
115119 | LUTerm
116120
121 let int_of_block_flag (flag : flag_block) =
122 Obj.magic flag
123
124 let add_block_flag bb (flag : flag_block) =
125 bb.bb_flags <- set_flag bb.bb_flags (int_of_block_flag flag)
126
127 let remove_block_flag bb (flag : flag_block) =
128 bb.bb_flags <- unset_flag bb.bb_flags (int_of_block_flag flag)
129
130 let has_block_flag bb (flag : flag_block) =
131 has_flag bb.bb_flags (int_of_block_flag flag)
132
117133 let s_block_kind = function
118134 | BKRoot -> "BKRoot"
119135 | BKNormal -> "BKNormal"
176192 bb_type = t;
177193 bb_pos = p;
178194 bb_closed = false;
195 bb_flags = 0;
179196 bb_el = DynArray.create();
180197 bb_phi = DynArray.create();
181198 bb_terminator = TermNone;
555572 loop scopes' bb_exc;
556573 List.iter (fun (_,bb_catch) -> loop (next_scope scopes) bb_catch) catches;
557574 loop scopes bb_next
558 | SEWhile(bb_head,bb_body,bb_next,_) ->
575 | SEWhile(bb_body,bb_next,_) ->
559576 let scopes' = next_scope scopes in
560 loop scopes' bb_head;
561577 loop scopes' bb_body;
562578 loop scopes bb_next;
563579 | SESubBlock(bb_sub,bb_next) ->
577593 config : AnalyzerConfig.t;
578594 graph : Graph.t;
579595 temp_var_name : string;
596 with_timer : 'a . string list -> (unit -> 'a) -> 'a;
597 identifier : string;
580598 mutable entry : BasicBlock.t;
581599 mutable has_unbound : bool;
582600 mutable loop_counter : int;
583601 mutable loop_stack : int list;
584602 mutable debug_exprs : (string * texpr) list;
585603 mutable name_stack : string list;
604 mutable did_optimize : bool;
586605 }
298298 | TType(tt,tl) ->
299299 if not (List.exists (fun t2 -> Type.fast_eq t t2) dce.ts_stack) then begin
300300 dce.ts_stack <- t :: dce.ts_stack;
301 to_string dce (apply_params tt.t_params tl tt.t_type)
301 to_string dce (apply_typedef tt tl)
302302 end
303303 | TAbstract({a_impl = Some c} as a,tl) ->
304304 if Meta.has Meta.CoreType a.a_meta then
311311 | _ -> ())
312312 | TLazy f ->
313313 to_string dce (lazy_type f)
314 | TDynamic t ->
315 if t == t_dynamic then
316 ()
317 else
318 to_string dce t
319 | TEnum _ | TFun _ | TAnon _ | TAbstract({a_impl = None},_) ->
314 | TDynamic (Some t) ->
315 to_string dce t
316 | TEnum _ | TFun _ | TAnon _ | TAbstract({a_impl = None},_) | TDynamic None ->
320317 (* if we to_string these it does not imply that we need all its sub-types *)
321318 ()
322319
584581 check_and_add_feature dce "unsafe_string_concat";
585582 expr dce e1;
586583 expr dce e2;
587 | TArray(({etype = TDynamic t} as e1),e2) when t == t_dynamic ->
584 | TArray(({etype = TDynamic None} as e1),e2) ->
588585 check_and_add_feature dce "dynamic_array_read";
589586 expr dce e1;
590587 expr dce e2;
591 | TBinop( (OpAssign | OpAssignOp _), ({eexpr = TArray({etype = TDynamic t},_)} as e1), e2) when t == t_dynamic ->
588 | TBinop( (OpAssign | OpAssignOp _), ({eexpr = TArray({etype = TDynamic None},_)} as e1), e2) ->
592589 check_and_add_feature dce "dynamic_array_write";
593590 expr dce e1;
594591 expr dce e2;
66 open Error
77
88 let needs_inline ctx is_extern_class cf =
9 cf.cf_kind = Method MethInline
9 cf.cf_kind = Method MethInline && ctx.allow_inline
1010 && (ctx.g.doinline || is_extern_class || has_class_field_flag cf CfExtern)
1111
1212 let mk_untyped_call name p params =
111111
112112 let api_inline ctx c field params p =
113113 let mk_typeexpr path =
114 let m = (try Hashtbl.find ctx.g.modules path with Not_found -> die "" __LOC__) in
114 let m = (try ctx.com.module_lut#find path with Not_found -> die "" __LOC__) in
115115 add_dependency ctx.m.curmod m;
116116 Option.get (ExtList.List.find_map (function
117117 | TClassDecl cl when cl.cl_path = path -> Some (make_static_this cl p)
253253 let t = if cf.cf_name = "_new" then
254254 return_type
255255 else if call_args = [] then
256 error "Invalid abstract implementation function" cf.cf_pos
256 typing_error "Invalid abstract implementation function" cf.cf_pos
257257 else
258258 follow (List.hd call_args).etype
259259 in
307307 try
308308 Hashtbl.find locals v.v_id
309309 with Not_found ->
310 let v' = alloc_var (match v.v_kind with VUser _ -> VInlined | k -> k) v.v_name v.v_type v.v_pos in
310 let name = Option.default v.v_name (get_meta_string v.v_meta Meta.RealPath) in
311 let v' = alloc_var (match v.v_kind with VUser _ -> VInlined | k -> k) name v.v_type v.v_pos in
311312 v'.v_extra <- v.v_extra;
312313 let i = {
313314 i_var = v;
367368 in
368369 try loop e; true with Exit -> false
369370 in
370 let rec is_writable e =
371 let rec check_write e =
371372 match e.eexpr with
372 | TField _ | TEnumParameter _ | TLocal _ | TArray _ -> true
373 | TCast(e1,None) -> is_writable e1
374 | _ -> false
373 | TLocal v when has_var_flag v VFinal ->
374 typing_error "Cannot modify abstract value of final local" p
375 | TField(_,fa) ->
376 begin match extract_field fa with
377 | Some cf when has_class_field_flag cf CfFinal ->
378 typing_error "Cannot modify abstract value of final field" p
379 | _ ->
380 ()
381 end
382 | TLocal _ | TEnumParameter _ | TArray _ ->
383 ()
384 | TCast(e1,None) ->
385 check_write e1
386 | _ ->
387 typing_error "Cannot modify the abstract value, store it into a local first" p;
375388 in
376389 let vars = List.fold_left (fun acc (i,e) ->
377390 let accept vik =
385398 (i.i_subst,Some e) :: acc
386399 in
387400 if i.i_abstract_this && i.i_write then begin
388 if not (is_writable e) then error "Cannot modify the abstract value, store it into a local first" p;
401 check_write e;
389402 accept VIInline
390403 end else if i.i_force_temp || (i.i_captured && not (is_constant e)) then
391404 reject()
396409 | TLocal _ | TConst _ ->
397410 if not i.i_write then VIInline else VIDoNotInline
398411 | TFunction _ ->
399 if i.i_write then error "Cannot modify a closure parameter inside inline method" p;
412 if i.i_write then typing_error "Cannot modify a closure parameter inside inline method" p;
400413 if i.i_read <= 1 then VIInline else VIInlineIfCalled
401414 | _ ->
402415 if not i.i_write && (i.i_read + i.i_called) <= 1 then VIInline else VIDoNotInline
582595 let e = Diagnostics.secure_generated_code ctx e in
583596 if has_params then begin
584597 let mt = map_type cf.cf_type in
585 let unify_func () = unify_raise ctx mt (TFun (tl,tret)) p in
598 let unify_func () = unify_raise mt (TFun (tl,tret)) p in
586599 (match follow ethis.etype with
587600 | TAnon a -> (match !(a.a_status) with
588601 | Statics {cl_kind = KAbstractImpl a } when has_class_field_flag cf CfImpl ->
589602 if cf.cf_name <> "_new" then begin
590603 (* the first argument must unify with a_this for abstract implementation functions *)
591604 let tb = (TFun(("",false,map_type a.a_this) :: (List.tl tl),tret)) in
592 unify_raise ctx mt tb p
605 unify_raise mt tb p
593606 end
594607 | _ -> unify_func())
595608 | _ -> unify_func());
688701 l.i_read <- l.i_read + (if !in_loop then 2 else 1);
689702 { e with eexpr = TLocal l.i_subst }
690703 | None ->
691 error "Could not inline `this` outside of an instance context" po
704 typing_error "Could not inline `this` outside of an instance context" po
692705 )
693706 | TVar (v,eo) ->
694707 { e with eexpr = TVar ((state#declare v).i_subst,opt (map false false) eo)}
696709 if not term then begin
697710 match cf.cf_kind with
698711 | Method MethInline ->
699 error "Cannot inline a not final return" po
712 typing_error "Cannot inline a not final return" po
700713 | _ ->
701 error ("Function " ^ cf.cf_name ^ " cannot be inlined because of a not final return") p
714 typing_error ("Function " ^ cf.cf_name ^ " cannot be inlined because of a not final return") p
702715 end;
703716 (match eo with
704717 | None -> mk (TConst TNull) f.tf_type p
721734 in_loop := old;
722735 { e with eexpr = TWhile (cond,eloop,flag) }
723736 | TSwitch (e1,cases,def) when term ->
724 let term = term && (def <> None || is_exhaustive e1) in
737 let term = term && (is_exhaustive e1 def) in
725738 let cases = List.map (fun (el,e) ->
726739 let el = List.map (map false false) el in
727740 el, map term false e
815828 | TInst({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction tf})} as cf)} as c,_) ->
816829 begin match type_inline_ctor ctx c cf tf ethis el po with
817830 | Some e -> map term false e
818 | None -> error "Could not inline super constructor call" po
831 | None -> typing_error "Could not inline super constructor call" po
819832 end
820 | _ -> error "Cannot inline function containing super" po
833 | _ -> typing_error "Cannot inline function containing super" po
821834 end
822835 | TCall(e1,el) ->
823836 state#set_side_effect;
825838 let el = List.map (map false false) el in
826839 {e with eexpr = TCall(e1,el)}
827840 | TConst TSuper ->
828 error "Cannot inline function containing super" po
841 typing_error "Cannot inline function containing super" po
829842 | TMeta((Meta.Ast,_,_) as m,e1) when term ->
830843 (* Special case for @:ast-wrapped TSwitch nodes: If the recursion alters the type of the TSwitch node, we also want
831844 to alter the type of the TMeta node. *)
863876 (* Same as type_inline, but modifies the function body to add field inits *)
864877 and type_inline_ctor ctx c cf tf ethis el po =
865878 let field_inits =
866 let cparams = List.map snd c.cl_params in
879 let cparams = extract_param_types c.cl_params in
867880 let ethis = mk (TConst TThis) (TInst (c,cparams)) c.cl_pos in
868881 let el = List.fold_left (fun acc cf ->
869882 match cf.cf_kind,cf.cf_expr with
901914 let cf =
902915 try PMap.find "of" c.cl_statics
903916 with Not_found -> die ~p:c.cl_name_pos "Can't find haxe.Rest.of function" __LOC__
904 and p = punion_el (List.map (fun e -> (),e.epos) params) in
917 and p = punion_el p params in
905918 (* [param1, param2, ...] *)
906919 (* If we don't know the type (e.g. the rest argument is a field type parameter) then we need
907920 to find a common type via unify_min. *)
121121 | IOKCtor(ioc) ->
122122 List.iter (fun v -> if v.v_id < 0 then cancel_v v p) io.io_dependent_vars;
123123 if ioc.ioc_forced then begin
124 display_error ctx "Forced inline constructor could not be inlined" io.io_pos;
125 display_error ctx (compl_msg "Cancellation happened here") p;
124 display_error ctx.com "Forced inline constructor could not be inlined" io.io_pos;
125 display_error ~depth:1 ctx.com (compl_msg "Cancellation happened here") p;
126126 end
127127 | _ -> ()
128128 end
226226 let e = Type.map_expr (mark_ctors ~force_inline:is_meta_inline) e in
227227 let mark() =
228228 incr curr_io_id;
229 let id_expr = (EConst(Int (string_of_int !curr_io_id)), e.epos) in
229 let id_expr = (EConst(Int (string_of_int !curr_io_id, None)), e.epos) in
230230 let meta = (Meta.InlineObject, [id_expr], e.epos) in
231231 mk (TMeta(meta, e)) e.etype e.epos
232232 in
315315 let iv_is_const iv = match iv.iv_kind with IVKField(_,_,Some(_)) -> true | _ -> false in
316316 if is_lvalue && iv_is_const fiv then raise Not_found;
317317 if fiv.iv_closed then raise Not_found;
318 if not captured || (not is_lvalue && fiv.iv_state == IVSUnassigned) then cancel_iv fiv efield.epos;
318 if not is_lvalue && fiv.iv_state == IVSUnassigned then (
319 warning ctx WConstructorInliningCancelled ("Constructor inlining cancelled because of use of uninitialized member field " ^ fname) ethis.epos;
320 raise Not_found
321 );
322 if not captured then cancel_iv fiv efield.epos;
319323 IOFInlineVar(fiv)
320324 with Not_found ->
321325 cancel_iv iv efield.epos;
394398 Some iv
395399 | _ ->
396400 List.iter (fun v -> cancel_v v v.v_pos) argvs;
397 if is_extern_ctor c cf then display_error ctx "Extern constructor could not be inlined" e.epos;
401 if is_extern_ctor c cf then display_error ctx.com "Extern constructor could not be inlined" e.epos;
398402 None
399403 end
400404 | TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some _} as cf)} as c,_,pl),_ when is_extern_ctor c cf ->
401 error "Extern constructor could not be inlined" e.epos;
405 typing_error "Extern constructor could not be inlined" e.epos;
402406 | TObjectDecl fl, _ when captured && fl <> [] && List.for_all (fun((s,_,_),_) -> Lexer.is_valid_identifier s) fl ->
403407 let v = alloc_var VGenerated "inlobj" e.etype e.epos in
404408 let ev = mk (TLocal v) v.v_type e.epos in
434438 handle_default_case e
435439 in
436440 match e.eexpr with
437 | TMeta((Meta.Inline,_,_),{eexpr = TMeta((Meta.InlineObject, [(EConst(Int (id_str)), _)], _), e)}) ->
441 | TMeta((Meta.Inline,_,_),{eexpr = TMeta((Meta.InlineObject, [(EConst(Int (id_str, None)), _)], _), e)}) ->
438442 let io_id = int_of_string id_str in
439443 handle_inline_object_case io_id true e
440 | TMeta((Meta.InlineObject, [(EConst(Int (id_str)), _)], _), e) ->
444 | TMeta((Meta.InlineObject, [(EConst(Int (id_str, None)), _)], _), e) ->
441445 let io_id = int_of_string id_str in
442446 handle_inline_object_case io_id false e
443447 | TVar(v,None) -> ignore(add v IVKLocal); None
527531 List.iter (fun ca -> ignore(analyze_aliases false ca)) call_args;
528532 None
529533 end
534 | TFunction tf ->
535 analyze_aliases true tf.tf_expr
530536 | _ ->
531537 handle_default_case e
532538 in
587593 end
588594 in
589595 match e.eexpr with
590 | TMeta((Meta.InlineObject, [(EConst(Int (id_str)), _)], _), e) ->
596 | TMeta((Meta.InlineObject, [(EConst(Int (id_str, _)), _)], _), e) ->
591597 let io_id = int_of_string id_str in
592598 begin try
593599 let io = get_io io_id in
5454 | OpBoolAnd -> 14, left
5555 | OpBoolOr -> 15, left
5656 | OpArrow -> 16, left
57 | OpNullCoal -> 17, right
5758 | OpAssignOp OpAssign -> 18, right (* mimics ?: *)
5859 | OpAssign | OpAssignOp _ -> 19, right
5960
197198 List.iter (fun (cl,_) ->
198199 List.iter (fun e ->
199200 match e.eexpr with
200 | TCall ({ eexpr = TField (_,FEnum _) },_) -> error "Not-constant enum in switch cannot be matched" e.epos
201 | TCall ({ eexpr = TField (_,FEnum _) },_) -> typing_error "Not-constant enum in switch cannot be matched" e.epos
201202 | _ -> ()
202203 ) cl
203204 ) cases;
236237 ) (true,0) el in
237238 b
238239
240 let rec extract_constant_value e = match e.eexpr with
241 | TConst (TInt _ | TFloat _ | TString _ | TBool _ | TNull) ->
242 Some e
243 | TConst (TThis | TSuper) ->
244 None
245 | TField(_,FStatic(c,({cf_kind = Var {v_write = AccNever}} as cf))) ->
246 begin match cf.cf_expr with
247 | Some e ->
248 (* Don't care about inline, if we know the value it makes no difference. *)
249 extract_constant_value e
250 | None ->
251 None
252 end
253 | TField(_,FEnum _) ->
254 Some e
255 | TParenthesis e1 ->
256 extract_constant_value e1
257 | _ ->
258 None
259
239260 let check_constant_switch e1 cases def =
240261 let rec loop e1 cases = match cases with
241262 | (el,e) :: cases ->
242 if List.exists (Texpr.equal e1) el then Some e
243 else loop e1 cases
263 (* Map everything first so that we find unknown things eagerly. *)
264 let el = List.map (fun e2 -> match extract_constant_value e2 with
265 | Some e2 -> e2
266 | None -> raise Exit
267 ) el in
268 if List.exists (fun e2 ->
269 Texpr.equal e1 e2
270 ) el then
271 Some e
272 else
273 loop e1 cases
244274 | [] ->
245275 begin match def with
246276 | None -> None
247277 | Some e -> Some e
248278 end
249279 in
280 let is_empty e = match e.eexpr with
281 | TBlock [] -> true
282 | _ -> false
283 in
284 let is_empty_def () = match def with
285 | None -> true
286 | Some e -> is_empty e
287 in
250288 match Texpr.skip e1 with
251289 | {eexpr = TConst ct} as e1 when (match ct with TSuper | TThis -> false | _ -> true) ->
252 loop e1 cases
290 begin try
291 loop e1 cases
292 with Exit ->
293 None
294 end
253295 | _ ->
254 None
255
256 let reduce_control_flow ctx e = match e.eexpr with
296 if List.for_all (fun (_,e) -> is_empty e) cases && is_empty_def() then
297 Some e1
298 else
299 None
300
301 let reduce_control_flow com e = match e.eexpr with
257302 | TIf ({ eexpr = TConst (TBool t) },e1,e2) ->
258303 (if t then e1 else match e2 with None -> { e with eexpr = TBlock [] } | Some e -> e)
259304 | TWhile ({ eexpr = TConst (TBool false) },sub,flag) ->
278323 (try List.nth el i with Failure _ -> e)
279324 | TCast(e1,None) ->
280325 (* TODO: figure out what's wrong with these targets *)
281 let require_cast = match ctx.com.platform with
326 let require_cast = match com.platform with
282327 | Cpp | Flash -> true
283 | Java -> defined ctx.com Define.Jvm
284 | Cs -> defined ctx.com Define.EraseGenerics || defined ctx.com Define.FastCast
328 | Java -> defined com Define.Jvm
329 | Cs -> defined com Define.EraseGenerics || defined com Define.FastCast
285330 | _ -> false
286331 in
287332 Texpr.reduce_unsafe_casts ~require_cast e e.etype
299344 let cf = mk_field "" ef.etype e.epos null_pos in
300345 let ethis = mk (TConst TThis) t_dynamic e.epos in
301346 let rt = (match follow ef.etype with TFun (_,rt) -> rt | _ -> die "" __LOC__) in
302 let inl = (try type_inline ctx cf func ethis el rt None e.epos ~self_calling_closure:true false with Error (Custom _,_) -> None) in
347 let inl = (try type_inline ctx cf func ethis el rt None e.epos ~self_calling_closure:true false with Error (Custom _,_,_) -> None) in
303348 (match inl with
304349 | None -> reduce_expr ctx e
305350 | Some e -> reduce_loop ctx e)
308353 | Some {eexpr = TFunction tf} ->
309354 let config = inline_config (Some cl) cf el e.etype in
310355 let rt = (match follow e1.etype with TFun (_,rt) -> rt | _ -> die "" __LOC__) in
311 let inl = (try type_inline ctx cf tf ef el rt config e.epos false with Error (Custom _,_) -> None) in
356 let inl = (try type_inline ctx cf tf ef el rt config e.epos false with Error (Custom _,_,_) -> None) in
312357 (match inl with
313358 | None -> reduce_expr ctx e
314359 | Some e ->
324369 reduce_expr ctx e
325370 end
326371 | _ ->
327 reduce_expr ctx (reduce_control_flow ctx e))
372 reduce_expr ctx (reduce_control_flow ctx.com e))
328373
329374 let reduce_expression ctx e =
330375 if ctx.com.foptimize then
373418 | None -> None
374419 | Some e -> make_constant_expression ctx e)
375420 with Not_found -> None) *)
376 | _ -> None
421 | _ -> None
1919 loop e; false
2020 with Exit ->
2121 true
22
23 let rec is_exhaustive e1 = match e1.eexpr with
24 | TMeta((Meta.Exhaustive,_,_),_) -> true
25 | TMeta(_, e1) | TParenthesis e1 -> is_exhaustive e1
26 | _ -> false
27
2822
2923 let is_read_only_field_access e fa = match fa with
3024 | FEnum _ ->
135129 | OpAnd -> opt Int32.logand
136130 | OpOr -> opt Int32.logor
137131 | OpXor -> opt Int32.logxor
138 | OpShl -> opt (fun a b -> Int32.shift_left a (Int32.to_int b))
139 | OpShr -> opt (fun a b -> Int32.shift_right a (Int32.to_int b))
140 | OpUShr -> opt (fun a b -> Int32.shift_right_logical a (Int32.to_int b))
132 | OpShl -> opt (fun a b -> Int32.shift_left a (Int32.to_int (Int32.logand b i32_31)))
133 | OpShr -> opt (fun a b -> Int32.shift_right a (Int32.to_int (Int32.logand b i32_31)))
134 | OpUShr -> opt (fun a b -> Int32.shift_right_logical a (Int32.to_int (Int32.logand b i32_31)))
141135 | OpEq -> ebool (=)
142136 | OpNotEq -> ebool (<>)
143137 | OpGt -> ebool (>)
214208 | OpAssign,_ ->
215209 e
216210 | _ ->
217 error "You cannot directly compare enums with arguments. Use either `switch`, `match` or `Type.enumEq`" e.epos
211 typing_error "You cannot directly compare enums with arguments. Use either `switch`, `match` or `Type.enumEq`" e.epos
218212 end
219213 | _ ->
220214 e)
3939
4040 let rec psep sep f = parser
4141 | [< r = psep_nonempty sep f >] -> r
42 | [< >] -> []
43
44 let rec psep_trailing sep f = parser
45 | [< v = f; '(sep2,_) when sep2 = sep; l = psep_trailing sep f >] -> v :: l
46 | [< v = f >] -> [v]
4247 | [< >] -> []
4348
4449 let pignore f =
106111 | [< '(Semicolon,p) >] -> p
107112 | [< s >] ->
108113 syntax_error Missing_semicolon s (next_pos s)
114
115 let check_redundant_var p1 = parser
116 | [< '(Kwd Var),p2; s >] ->
117 syntax_error (Custom "`final var` is not supported, use `final` instead") ~pos:(Some (punion p1 p2)) s ();
118 | [< >] ->
119 ()
109120
110121 let parsing_macro_cond = ref false
111122
222233 | [< '(Kwd Using,p1) >] -> parse_using s p1
223234 | [< doc = get_doc; meta = parse_meta; c = parse_common_flags; s >] ->
224235 match s with parser
225 | [< '(Kwd Function,p1); name = dollar_ident; pl = parse_constraint_params; '(POpen,_); args = psep Comma parse_fun_param; '(PClose,_); t = popt parse_type_hint; s >] ->
236 | [< '(Kwd Function,p1); name = dollar_ident; pl = parse_constraint_params; '(POpen,_); args = psep_trailing Comma parse_fun_param; '(PClose,_); t = popt parse_type_hint; s >] ->
226237 let e, p2 = (match s with parser
227238 | [< e = expr; s >] ->
228239 ignore(semicolon s);
335346 d_data = fl;
336347 }, punion p1 p2)
337348
338 and parse_import s p1 =
349 and parse_import' s p1 =
339350 let rec loop pn acc =
340351 match s with parser
341352 | [< '(Dot,p) >] ->
352363 loop pn (("extern",p) :: acc)
353364 | [< '(Kwd Function,p) >] ->
354365 loop pn (("function",p) :: acc)
355 | [< '(Binop OpMult,_); '(Semicolon,p2) >] ->
356 p2, List.rev acc, IAll
366 | [< '(Binop OpMult,_) >] ->
367 List.rev acc, IAll
357368 | [< >] ->
358369 ignore(popt semicolon s);
359 syntax_error (Expected ["identifier"]) s (p,List.rev acc,INormal)
370 syntax_error (Expected ["identifier"]) s (List.rev acc,INormal)
360371 end
361 | [< '(Semicolon,p2) >] ->
362 p2, List.rev acc, INormal
363 | [< '(Kwd In,_); '(Const (Ident name),pname); '(Semicolon,p2) >] ->
364 p2, List.rev acc, IAsName(name,pname)
365 | [< '(Const (Ident "as"),_); '(Const (Ident name),pname); '(Semicolon,p2) >] ->
366 p2, List.rev acc, IAsName(name,pname)
367 | [< >] ->
368 syntax_error (Expected [".";";";"as"]) s ((last_pos s),List.rev acc,INormal)
369 in
370 let p2, path, mode = (match s with parser
372 | [< '(Kwd In,_); '(Const (Ident name),pname) >] ->
373 List.rev acc, IAsName(name,pname)
374 | [< '(Const (Ident "as"),_); '(Const (Ident name),pname) >] ->
375 List.rev acc, IAsName(name,pname)
376 | [< >] ->
377 List.rev acc,INormal
378 in
379 let path, mode = (match s with parser
371380 | [< '(Const (Ident name),p) >] -> loop p [name,p]
372381 | [< >] ->
373382 if would_skip_display_position p1 true s then
374 (display_position#with_pos p1,[],INormal)
383 ([],INormal)
375384 else
376 syntax_error (Expected ["identifier"]) s (p1,[],INormal)
385 syntax_error (Expected ["identifier"]) s ([],INormal)
377386 ) in
387 (path,mode)
388
389 and parse_import s p1 =
390 let (path,mode) = parse_import' s p1 in
391 let p2 = match s with parser
392 | [< '(Semicolon,p2) >] ->
393 p2
394 | [< >] ->
395 if would_skip_display_position p1 true s then
396 display_position#with_pos p1
397 else
398 syntax_error (Expected [".";";";"as"]) s (last_pos s)
399 in
378400 (EImport (path,mode),punion p1 p2)
379401
380 and parse_using s p1 =
402 and parse_using' s p1 =
381403 let rec loop pn acc =
382404 match s with parser
383405 | [< '(Dot,p) >] ->
392414 | [< '(Kwd Function,p) >] ->
393415 loop pn (("function",p) :: acc)
394416 | [< >] ->
395 syntax_error (Expected ["identifier"]) s (p,List.rev acc);
417 syntax_error (Expected ["identifier"]) s (List.rev acc);
396418 end
397 | [< '(Semicolon,p2) >] ->
398 p2,List.rev acc
399 | [< >] ->
400 syntax_error (Expected [".";";"]) s ((last_pos s),List.rev acc)
401 in
402 let p2, path = (match s with parser
419 | [< >] ->
420 List.rev acc
421 in
422 match s with parser
403423 | [< '(Const (Ident name),p) >] -> loop p [name,p]
404424 | [< >] ->
405425 if would_skip_display_position p1 true s then
406 (display_position#with_pos p1,[])
426 []
407427 else
408 syntax_error (Expected ["identifier"]) s (p1,[])
409 ) in
428 syntax_error (Expected ["identifier"]) s []
429
430 and parse_using s p1 =
431 let path = parse_using' s p1 in
432 let p2 = match s with parser
433 | [< '(Semicolon,p2) >] ->
434 p2
435 | [< >] ->
436 if would_skip_display_position p1 true s then
437 display_position#with_pos p1
438 else
439 syntax_error (Expected [".";";"]) s (last_pos s)
440 in
410441 (EUsing path,punion p1 p2)
411442
412443 and parse_abstract_relations s =
474505 | Kwd New :: Kwd Function :: _ when fdecl ->
475506 junk_tokens (k - 2);
476507 true
477 | Kwd Macro :: _ | Kwd Public :: _ | Kwd Static :: _ | Kwd Var :: _ | Kwd Override :: _ | Kwd Dynamic :: _ | Kwd Inline :: _ | Kwd Overload :: _ when fdecl ->
508 | Kwd Macro :: _ | Kwd Public :: _ | Kwd Static :: _ | Kwd Var :: _ | Kwd Final :: _ | Kwd Override :: _ | Kwd Dynamic :: _ | Kwd Inline :: _ | Kwd Overload :: _ when fdecl ->
478509 junk_tokens (k - 1);
479510 true
480511 | BrClose :: _ when tdecl ->
550581 end
551582
552583 and parse_meta_params pname s = match s with parser
553 | [< '(POpen,p) when p.pmin = pname.pmax; params = psep Comma parse_meta_argument_expr; >] ->
584 | [< '(POpen,p) when p.pmin = pname.pmax; params = psep_trailing Comma parse_meta_argument_expr; >] ->
554585 ignore(expect_unless_resume_p PClose s);
555586 params
556587 | [< >] -> []
557588
558589 and parse_meta_entry = parser
559590 [< '(At,p1); s >] ->
560 let meta = check_resume p1 (fun () -> Some (Meta.Last,[],p1)) (fun () -> None) in
591 let meta = check_resume p1 (fun () -> Some (Meta.HxCompletion,[],p1)) (fun () -> None) in
561592 match s with parser
562593 | [< name,p = parse_meta_name p1; params = parse_meta_params p >] -> (name,params,punion p1 p)
563594 | [< >] -> match meta with None -> serror() | Some meta -> meta
579610
580611 and parse_meta_name p1 = parser
581612 | [< '(DblDot,p) when p.pmin = p1.pmax; s >] ->
582 let meta = check_resume p (fun () -> Some (Meta.Last,p)) (fun() -> None) in
613 let meta = check_resume p (fun () -> Some (Meta.HxCompletion,p)) (fun() -> None) in
583614 begin match s with parser
584615 | [< name,p2 = parse_meta_name_2 p [] >] -> (Meta.parse (rev_concat "." name)),p2
585616 | [< >] -> match meta with None -> raise Stream.Failure | Some meta -> meta
619650 and parse_complex_type s = parse_complex_type_maybe_named false s
620651
621652 and parse_complex_type_maybe_named allow_named = parser
622 | [< '(POpen,p1); tl = psep Comma (parse_complex_type_maybe_named true); '(PClose,p2); s >] ->
653 | [< '(POpen,p1); tl = psep_trailing Comma (parse_complex_type_maybe_named true); '(PClose,p2); s >] ->
623654 begin match tl with
624655 | [] | [(CTNamed _,_)] ->
625656 (* it was () or (a:T) - clearly a new function type syntax, proceed with parsing return type *)
848879 match s with parser
849880 | [< name, p1 = ident; params = parse_constraint_params; s >] ->
850881 let args = (match s with parser
851 | [< '(POpen,_); l = psep Comma parse_enum_param; '(PClose,_) >] -> l
882 | [< '(POpen,_); l = psep_trailing Comma parse_enum_param; '(PClose,_) >] -> l
852883 | [< >] -> []
853884 ) in
854885 let t = popt parse_type_hint s in
871902 | [< name, _ = ident; t = parse_type_hint >] -> (name,false,t)
872903
873904 and parse_function_field doc meta al = parser
874 | [< '(Kwd Function,p1); name = parse_fun_name; pl = parse_constraint_params; '(POpen,_); args = psep Comma parse_fun_param; '(PClose,_); t = popt parse_type_hint; s >] ->
905 | [< '(Kwd Function,p1); name = parse_fun_name; pl = parse_constraint_params; '(POpen,_); args = psep_trailing Comma parse_fun_param; '(PClose,_); t = popt parse_type_hint; s >] ->
875906 let e, p2 = (match s with parser
876907 | [< e = expr; s >] ->
877908 ignore(semicolon s);
929960 name,punion p1 p2,FVar (t,e),al,meta
930961 end
931962 | [< '(Kwd Final,p1) >] ->
963 check_redundant_var p1 s;
932964 begin match s with parser
933965 | [< opt,name = questionable_dollar_ident; t = popt parse_type_hint; e,p2 = parse_var_field_assignment >] ->
934966 let meta = check_optional opt name in
10271059 let meta = parse_meta s in
10281060 match s with parser
10291061 | [< name = type_name; s >] ->
1030 let params = (match s with parser
1031 | [< >] -> []
1032 ) in
10331062 let cto = (match s with parser
10341063 | [< '(DblDot,_); s >] ->
10351064 (match s with parser
1036 | [< '(POpen,p1); t = parse_complex_type; '(PClose,p2) >] -> Some t
1065 | [< t = parse_complex_type >] -> Some t
1066 | [< >] -> serror())
1067 | [< >] -> None
1068 ) in
1069 let default = (match s with parser
1070 | [< '(Binop OpAssign,_); s >] ->
1071 (match s with parser
10371072 | [< t = parse_complex_type >] -> Some t
10381073 | [< >] -> serror())
10391074 | [< >] -> None
10401075 ) in
10411076 {
10421077 tp_name = name;
1043 tp_params = params;
1078 tp_params = [];
10441079 tp_constraints = cto;
1080 tp_default = default;
10451081 tp_meta = meta;
10461082 }
10471083 | [< >] ->
11041140 and block_with_pos acc p s =
11051141 block_with_pos' acc parse_block_elt p s
11061142
1143 and parse_block_var = parser
1144 | [< '(Kwd Var,p1); vl = parse_var_decls false p1; p2 = semicolon >] ->
1145 (vl,punion p1 p2)
1146 | [< '(Kwd Final,p1); s >] ->
1147 check_redundant_var p1 s;
1148 match s with parser
1149 | [< vl = parse_var_decls true p1; p2 = semicolon >] ->
1150 (vl,punion p1 p2)
1151 | [< >] ->
1152 serror();
1153
11071154 and parse_block_elt = parser
1108 | [< '(Kwd Var,p1); vl = parse_var_decls false p1; p2 = semicolon >] ->
1109 (EVars vl,punion p1 p2)
1110 | [< '(Kwd Final,p1); vl = parse_var_decls true p1; p2 = semicolon >] ->
1111 (EVars vl,punion p1 p2)
1155 | [< (vl,p) = parse_block_var >] ->
1156 (EVars vl,p)
11121157 | [< '(Kwd Inline,p1); s >] ->
11131158 begin match s with parser
11141159 | [< '(Kwd Function,_); e = parse_function p1 true; _ = semicolon >] -> e
11151160 | [< e = secure_expr; _ = semicolon >] -> make_meta Meta.Inline [] e p1
11161161 | [< >] -> serror()
1162 end
1163 | [< '(Kwd Static,p); s >] ->
1164 begin match s with parser
1165 | [< (vl,p) = parse_block_var >] ->
1166 let vl = List.map (fun ev -> {ev with ev_static = true}) vl in
1167 (EVars vl,p)
1168 | [<>] -> syntax_error (Expected ["var";"final"]) s (mk_null_expr p)
11171169 end
11181170 | [< '(Binop OpLt,p1); s >] ->
11191171 let e = handle_xml_literal p1 in
11831235 let meta = parse_meta s in
11841236 match s with parser
11851237 | [< name, p = dollar_ident; t = popt parse_type_hint >] -> (meta,name,final,t,p)
1238 | [< >] ->
1239 (* This nonsense is here for the var @ case in issue #9639 *)
1240 let rec loop meta = match meta with
1241 | (Meta.HxCompletion,_,p) :: _ -> (meta,"",false,None,null_pos)
1242 | _ :: meta -> loop meta
1243 | [] -> no_keyword "variable name" s
1244 in
1245 loop meta
11861246
11871247 and parse_var_assignment = parser
11881248 | [< '(Binop OpAssign,p1); s >] ->
12201280 (ECheckType (t,(CTPath (mk_type_path ~sub:"ComplexType" (["haxe";"macro"],"Expr")),null_pos)),p)
12211281 | [< '(Kwd Var,p1); vl = psep Comma (parse_var_decl false) >] ->
12221282 reify_expr (EVars vl,p1) !in_macro
1223 | [< '(Kwd Final,p1); vl = psep Comma (parse_var_decl true) >] ->
1224 reify_expr (EVars vl,p1) !in_macro
1283 | [< '(Kwd Final,p1); s >] ->
1284 check_redundant_var p1 s;
1285 begin match s with parser
1286 | [< vl = psep Comma (parse_var_decl true) >] ->
1287 reify_expr (EVars vl,p1) !in_macro
1288 | [< >] ->
1289 serror()
1290 end
12251291 | [< d = parse_class None [] [] false >] ->
12261292 let _,_,to_type = reify !in_macro in
12271293 (ECheckType (to_type d,(CTPath (mk_type_path ~sub:"TypeDefinition" (["haxe";"macro"],"Expr")),null_pos)),p)
12281294 | [< e = secure_expr >] ->
12291295 reify_expr e !in_macro
12301296
1231 and parse_function p1 inl = parser
1232 | [< name = popt dollar_ident; pl = parse_constraint_params; '(POpen,_); al = psep Comma parse_fun_param; '(PClose,_); t = popt parse_type_hint; s >] ->
1297 and parse_function p1 inl s =
1298 let name = match s with parser
1299 | [< name = dollar_ident >] -> Some name
1300 | [< >] -> None
1301 in
1302 let pl = parse_constraint_params s in
1303 match s with parser
1304 | [< '(POpen,_); al = psep_trailing Comma parse_fun_param; '(PClose,_); t = popt parse_type_hint; s >] ->
12331305 let make e =
12341306 let f = {
12351307 f_params = pl;
12401312 EFunction ((match name with None -> FKAnonymous | Some (name,pn) -> FKNamed ((name,pn),inl)),f), punion p1 (pos e)
12411313 in
12421314 make (secure_expr s)
1315 | [< >] ->
1316 (* Generate pseudo function to avoid toplevel-completion (issue #10691). We check against p1 here in order to cover cases
1317 like `function a|b` *)
1318 if would_skip_display_position p1 false s then begin
1319 let null_func =
1320 let f = {
1321 f_params = [];
1322 f_type = None;
1323 f_args = [];
1324 f_expr = None
1325 } in
1326 let p = punion p1 (next_pos s) in
1327 let name = ("_hx_magic",p) in
1328 EFunction(FKNamed(name,inl),f),p
1329 in
1330 null_func
1331 end else
1332 serror()
12431333
12441334 and arrow_expr = parser
12451335 | [< '(Arrow,_); e = expr >] -> e
13071397 expr_next (EConst (Ident (s_keyword k)), p) s
13081398 | [< '(Kwd Macro,p); s >] ->
13091399 begin match s with parser
1310 | [< '(Dot,pd); e = parse_field (EConst (Ident "macro"),p) pd >] -> e
1400 | [< '(Dot,pd); e = parse_field (EConst (Ident "macro"),p) EFNormal pd >] -> e
13111401 | [< e = parse_macro_expr p >] -> e
13121402 | [< >] -> serror()
13131403 end
13141404 | [< '(Kwd Var,p1); v = parse_var_decl false >] -> (EVars [v],p1)
1315 | [< '(Kwd Final,p1); v = parse_var_decl true >] -> (EVars [v],p1)
1405 | [< '(Kwd Final,p1); s >] ->
1406 check_redundant_var p1 s;
1407 begin match s with parser
1408 | [< v = parse_var_decl true >] ->
1409 (EVars [v],p1)
1410 | [< >] ->
1411 serror()
1412 end
13161413 | [< '(Const c,p); s >] -> expr_next (EConst c,p) s
13171414 | [< '(Kwd This,p); s >] -> expr_next (EConst (Ident "this"),p) s
1415 | [< '(Kwd Abstract,p); s >] -> expr_next (EConst (Ident "abstract"),p) s
13181416 | [< '(Kwd True,p); s >] -> expr_next (EConst (Ident "true"),p) s
13191417 | [< '(Kwd False,p); s >] -> expr_next (EConst (Ident "false"),p) s
13201418 | [< '(Kwd Null,p); s >] -> expr_next (EConst (Ident "null"),p) s
13411439 | [< '(POpen,p1); s >] -> (match s with parser
13421440 | [< '(PClose,p2); er = arrow_expr; >] ->
13431441 arrow_function p1 [] er s
1344 | [< '(Question,p2); al = psep Comma parse_fun_param; '(PClose,_); er = arrow_expr; >] ->
1442 | [< '(Question,p2); al = psep_trailing Comma parse_fun_param; '(PClose,_); er = arrow_expr; >] ->
13451443 let al = (match al with | (np,_,_,topt,e) :: al -> (np,true,[],topt,e) :: al | _ -> die "" __LOC__ ) in
13461444 arrow_function p1 al er s
13471445 | [< e = expr; s >] -> (match s with parser
13481446 | [< '(PClose,p2); s >] -> expr_next (EParenthesis e, punion p1 p2) s
1349 | [< '(Comma,pc); al = psep Comma parse_fun_param; '(PClose,_); er = arrow_expr; >] ->
1447 | [< '(Comma,pc); al = psep_trailing Comma parse_fun_param; '(PClose,_); er = arrow_expr; >] ->
13501448 arrow_function p1 ((arrow_first_param e s) :: al) er s
13511449 | [< t,pt = parse_type_hint; s >] -> (match s with parser
13521450 | [< '(PClose,p2); s >] -> expr_next (EParenthesis (ECheckType(e,(t,pt)),punion p1 p2), punion p1 p2) s
1353 | [< '(Comma,pc); al = psep Comma parse_fun_param; '(PClose,_); er = arrow_expr; >] ->
1451 | [< '(Comma,pc); al = psep_trailing Comma parse_fun_param; '(PClose,_); er = arrow_expr; >] ->
13541452 let (np,_) = arrow_ident_checktype e in
13551453 arrow_function p1 ((np,false,[],(Some(t,pt)),None) :: al) er s
13561454 | [< '((Binop OpAssign),p2); ea1 = expr; s >] ->
13621460 (match s with parser
13631461 | [< '(PClose,p2); er = arrow_expr; >] ->
13641462 with_args [] er
1365 | [< '(Comma,pc); al = psep Comma parse_fun_param; '(PClose,_); er = arrow_expr; >] ->
1463 | [< '(Comma,pc); al = psep_trailing Comma parse_fun_param; '(PClose,_); er = arrow_expr; >] ->
13661464 with_args al er
13671465 | [< >] -> serror())
13681466 | [< >] -> serror())
14511549 syntax_error (Expected ["{"]) s (ESwitch(e,[],None),punion p1 (pos e))
14521550 end
14531551 | [< '(Kwd Try,p1); e = secure_expr; cl,p2 = parse_catches e [] (pos e) >] -> (ETry (e,cl),punion p1 p2)
1454 | [< '(IntInterval i,p1); e2 = expr >] -> make_binop OpInterval (EConst (Int i),p1) e2
1552 | [< '(IntInterval i,p1); e2 = expr >] -> make_binop OpInterval (EConst (Int (i, None)),p1) e2
14551553 | [< '(Kwd Untyped,p1); e = secure_expr >] -> (EUntyped e,punion p1 (pos e))
14561554 | [< '(Dollar v,p); s >] -> expr_next (EConst (Ident ("$"^v)),p) s
14571555 | [< '(Kwd Inline,p); e = secure_expr >] -> make_meta Meta.Inline [] e p
14681566 (match fst e1 with
14691567 | EConst(Ident n) -> expr_next (EMeta((Meta.from_string n,[],snd e1),eparam), punion p1 p2) s
14701568 | _ -> die "" __LOC__)
1471 | [< '(Dot,p); e = parse_field e1 p >] -> e
1569 | [< '(Dot,p); e = parse_field e1 EFNormal p >] -> e
1570 | [< '(QuestionDot,p); e = parse_field e1 EFSafe p >] -> e
14721571 | [< '(POpen,p1); e = parse_call_params (fun el p2 -> (ECall(e1,el)),punion (pos e1) p2) p1; s >] -> expr_next e s
14731572 | [< '(BkOpen,p1); e2 = secure_expr; s >] ->
14741573 let p2 = expect_unless_resume_p BkClose s in
14751574 let e2 = check_signature_mark e2 p1 p2 in
14761575 expr_next (EArray (e1,e2), punion (pos e1) p2) s
14771576 | [< '(Arrow,pa); s >] ->
1478 let er = expr s in
1577 let er = secure_expr s in
14791578 arrow_function (snd e1) [arrow_first_param e1 s] er s
14801579 | [< '(Binop OpGt,p1); s >] ->
14811580 (match s with parser
15091608 expr_next e_is s
15101609 | [< >] -> e1
15111610
1512 and parse_field e1 p s =
1611 and parse_field e1 efk p s =
15131612 check_resume p (fun () -> (EDisplay (e1,DKDot),p)) (fun () ->
15141613 begin match s with parser
1515 | [< '(Kwd Macro,p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,"macro") , punion (pos e1) p2) s
1516 | [< '(Kwd Extern,p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,"extern") , punion (pos e1) p2) s
1517 | [< '(Kwd Function,p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,"function") , punion (pos e1) p2) s
1518 | [< '(Kwd New,p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,"new") , punion (pos e1) p2) s
1519 | [< '(Kwd k,p2) when !parsing_macro_cond && p.pmax = p2.pmin; s >] -> expr_next (EField (e1,s_keyword k) , punion (pos e1) p2) s
1520 | [< '(Const (Ident f),p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,f) , punion (pos e1) p2) s
1521 | [< '(Dollar v,p2); s >] -> expr_next (EField (e1,"$"^v) , punion (pos e1) p2) s
1614 | [< '(Kwd Macro,p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,"macro",efk) , punion (pos e1) p2) s
1615 | [< '(Kwd Extern,p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,"extern",efk) , punion (pos e1) p2) s
1616 | [< '(Kwd Function,p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,"function",efk) , punion (pos e1) p2) s
1617 | [< '(Kwd New,p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,"new",efk) , punion (pos e1) p2) s
1618 | [< '(Kwd k,p2) when !parsing_macro_cond && p.pmax = p2.pmin; s >] -> expr_next (EField (e1,s_keyword k,efk) , punion (pos e1) p2) s
1619 | [< '(Const (Ident f),p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,f,efk) , punion (pos e1) p2) s
1620 | [< '(Dollar v,p2); s >] -> expr_next (EField (e1,"$"^v,efk) , punion (pos e1) p2) s
15221621 | [< >] ->
15231622 (* turn an integer followed by a dot into a float *)
15241623 match e1 with
1525 | (EConst (Int v),p2) when p2.pmax = p.pmin -> expr_next (EConst (Float (v ^ ".")),punion p p2) s
1624 | (EConst (Int (v, None)),p2) when p2.pmax = p.pmin -> expr_next (EConst (Float (v ^ ".", None)),punion p p2) s
15261625 | _ -> serror()
15271626 end
15281627 )
15331632
15341633 and expr_or_var = parser
15351634 | [< '(Kwd Var,p1); np = dollar_ident; >] -> EVars [mk_evar np],punion p1 (snd np)
1536 | [< '(Kwd Final,p1); np = dollar_ident; >] -> EVars [mk_evar ~final:true np],punion p1 (snd np)
1635 | [< '(Kwd Final,p1); s >] ->
1636 check_redundant_var p1 s;
1637 begin match s with parser
1638 | [< np = dollar_ident; >] ->
1639 EVars [mk_evar ~final:true np],punion p1 (snd np)
1640 | [< >] ->
1641 serror()
1642 end
15371643 | [< e = secure_expr >] -> e
15381644
15391645 and parse_switch_cases eswitch cases = parser
15751681
15761682 and parse_call_params f p1 s =
15771683 if not !in_display_file then begin
1578 let el = psep Comma expr s in
1684 let el = psep_trailing Comma expr s in
15791685 match s with parser
15801686 | [< '(PClose,p2) >] -> f el p2
15811687 | [< >] ->
15981704 | [< '(PClose,p2) >] ->
15991705 let e = check_signature_mark e p1 p2 in
16001706 f (List.rev (e :: acc)) p2
1707 | [< '(Comma,p2); '(PClose,p3) >] ->
1708 let e = check_signature_mark e p1 p3 in
1709 f (List.rev (e :: acc)) p3
16011710 | [< '(Comma,p2) >] ->
16021711 let e = check_signature_mark e p1 p2 in
16031712 parse_next_param (e :: acc) p2
16321741 let rec validate_macro_cond s e = match fst e with
16331742 | EConst (Ident _)
16341743 | EConst (String _)
1635 | EConst (Int _)
1636 | EConst (Float _)
1744 | EConst (Int (_, _))
1745 | EConst (Float (_, _))
16371746 -> e
16381747 | EUnop (op,p,e1) -> (EUnop (op, p, validate_macro_cond s e1), snd e)
16391748 | EBinop (op,e1,e2) -> (EBinop(op, (validate_macro_cond s e1), (validate_macro_cond s e2)), snd e)
16401749 | EParenthesis (e1) -> (EParenthesis (validate_macro_cond s e1), snd e)
1641 | EField(e1,name) -> (EField(validate_macro_cond s e1,name), snd e)
1750 | EField(e1,name,efk) -> (EField(validate_macro_cond s e1,name,efk), snd e)
16421751 | ECall ((EConst (Ident _),_) as i, args) -> (ECall (i,List.map (validate_macro_cond s) args),snd e)
16431752 | _ -> syntax_error (Custom ("Invalid conditional expression")) ~pos:(Some (pos e)) s ((EConst (Ident "false"),(pos e)))
16441753
16551764 parse_macro_ident t p s
16561765 | [< '(Const (String(s,qs)),p) >] ->
16571766 None, (EConst (String(s,qs)),p)
1658 | [< '(Const (Int i),p) >] ->
1659 None, (EConst (Int i),p)
1660 | [< '(Const (Float f),p) >] ->
1661 None, (EConst (Float f),p)
1767 | [< '(Const (Int (i, s)),p) >] ->
1768 None, (EConst (Int (i, s)),p)
1769 | [< '(Const (Float (f, s)),p) >] ->
1770 None, (EConst (Float (f, s)),p)
16621771 | [< '(Kwd k,p) >] ->
16631772 parse_macro_ident (s_keyword k) p s
16641773 | [< '(Unop op,p); tk, e = parse_macro_cond >] ->
16691778 cond
16701779 with e ->
16711780 parsing_macro_cond := false;
1672 raise e
1781 raise e
7272 llastindex = 0;
7373 }
7474
75 let copy_file source dest =
76 dest.lline <- source.lline;
77 dest.lmaxline <- source.lmaxline;
78 dest.llines <- source.llines;
79 dest.lalines <- source.lalines;
80 dest.llast <- source.llast;
81 dest.llastindex <- source.llastindex
82
83 let print_file file =
84 let sllines = String.concat ";" (List.map (fun (i1,i2) -> Printf.sprintf "(%i,%i)" i1 i2) file.llines) in
85 let slalines = String.concat ";" (Array.to_list (Array.map (fun (i1,i2) -> Printf.sprintf "(%i,%i)" i1 i2) file.lalines)) in
86 Printf.sprintf "lfile: %s\nlline: %i\nlmaxline: %i\nllines: [%s]\nlalines: [%s]\nllast: %i\nllastindex: %i" file.lfile file.lline file.lmaxline sllines slalines file.llast file.llastindex
7587
7688 let cur = ref (make_file "")
7789
110122 with Exit ->
111123 false
112124
125 let split_suffix s is_int =
126 let len = String.length s in
127 let rec loop i pivot =
128 if i = len then begin
129 match pivot with
130 | None ->
131 (s,None)
132 | Some pivot ->
133 (* There might be a _ at the end of the literal because we allow _f64 and such *)
134 let literal_length = if String.unsafe_get s (pivot - 1) = '_' then pivot - 1 else pivot in
135 let literal = String.sub s 0 literal_length in
136 let suffix = String.sub s pivot (len - pivot) in
137 (literal, Some suffix)
138 end else begin
139 let c = String.unsafe_get s i in
140 match c with
141 | 'i' | 'u' ->
142 loop (i + 1) (Some i)
143 | 'f' when not is_int ->
144 loop (i + 1) (Some i)
145 | _ ->
146 loop (i + 1) pivot
147 end
148 in
149 loop 0 None
150
151 let split_int_suffix s =
152 let (literal,suffix) = split_suffix s true in
153 Const (Int (literal,suffix))
154
155 let split_float_suffix s =
156 let (literal,suffix) = split_suffix s false in
157 Const (Float (literal,suffix))
158
113159 let init file =
114160 let f = make_file file in
115161 cur := f;
117163
118164 let save() =
119165 !cur
166
167 let reinit file =
168 let old_file = try Some (Hashtbl.find all_files file) with Not_found -> None in
169 let old_cur = !cur in
170 init file;
171 (fun () ->
172 cur := old_cur;
173 Option.may (Hashtbl.replace all_files file) old_file;
174 )
120175
121176 let restore c =
122177 cur := c
298353
299354 let idtype = [%sedlex.regexp? Star '_', 'A'..'Z', Star ('_' | 'a'..'z' | 'A'..'Z' | '0'..'9')]
300355
301 let integer = [%sedlex.regexp? ('1'..'9', Star ('0'..'9')) | '0']
356 let digit = [%sedlex.regexp? '0'..'9']
357 let sep_digit = [%sedlex.regexp? Opt '_', digit]
358 let integer_digits = [%sedlex.regexp? (digit, Star sep_digit)]
359 let hex_digit = [%sedlex.regexp? '0'..'9'|'a'..'f'|'A'..'F']
360 let sep_hex_digit = [%sedlex.regexp? Opt '_', hex_digit]
361 let hex_digits = [%sedlex.regexp? (hex_digit, Star sep_hex_digit)]
362 let integer = [%sedlex.regexp? ('1'..'9', Star sep_digit) | '0']
363
364 let integer_suffix = [%sedlex.regexp? Opt '_', ('i'|'u'), Plus integer]
365
366 let float_suffix = [%sedlex.regexp? Opt '_', 'f', Plus integer]
302367
303368 (* https://www.w3.org/TR/xml/#sec-common-syn plus '$' for JSX *)
304369 let xml_name_start_char = [%sedlex.regexp? '$' | ':' | 'A'..'Z' | '_' | 'a'..'z' | 0xC0 .. 0xD6 | 0xD8 .. 0xF6 | 0xF8 .. 0x2FF | 0x370 .. 0x37D | 0x37F .. 0x1FFF | 0x200C .. 0x200D | 0x2070 .. 0x218F | 0x2C00 .. 0x2FEF | 0x3001 .. 0xD7FF | 0xF900 .. 0xFDCF | 0xFDF0 .. 0xFFFD | 0x10000 .. 0xEFFFF]
318383 | Plus (Chars " \t") -> token lexbuf
319384 | "\r\n" -> newline lexbuf; token lexbuf
320385 | '\n' | '\r' -> newline lexbuf; token lexbuf
321 | "0x", Plus ('0'..'9'|'a'..'f'|'A'..'F') -> mk lexbuf (Const (Int (lexeme lexbuf)))
322 | integer -> mk lexbuf (Const (Int (lexeme lexbuf)))
323 | integer, '.', Plus '0'..'9' -> mk lexbuf (Const (Float (lexeme lexbuf)))
324 | '.', Plus '0'..'9' -> mk lexbuf (Const (Float (lexeme lexbuf)))
325 | integer, ('e'|'E'), Opt ('+'|'-'), Plus '0'..'9' -> mk lexbuf (Const (Float (lexeme lexbuf)))
326 | integer, '.', Star '0'..'9', ('e'|'E'), Opt ('+'|'-'), Plus '0'..'9' -> mk lexbuf (Const (Float (lexeme lexbuf)))
386 | "0x", Plus hex_digits, Opt integer_suffix ->
387 mk lexbuf (split_int_suffix (lexeme lexbuf))
388 | integer, Opt integer_suffix ->
389 mk lexbuf (split_int_suffix (lexeme lexbuf))
390 | integer, float_suffix ->
391 mk lexbuf (split_float_suffix (lexeme lexbuf))
392 | integer, '.', Plus integer_digits, Opt float_suffix -> mk lexbuf (split_float_suffix (lexeme lexbuf))
393 | '.', Plus integer_digits, Opt float_suffix -> mk lexbuf (split_float_suffix (lexeme lexbuf))
394 | integer, ('e'|'E'), Opt ('+'|'-'), Plus integer_digits, Opt float_suffix -> mk lexbuf (split_float_suffix (lexeme lexbuf))
395 | integer, '.', Star digit, ('e'|'E'), Opt ('+'|'-'), Plus integer_digits, Opt float_suffix -> mk lexbuf (split_float_suffix (lexeme lexbuf))
327396 | integer, "..." ->
328397 let s = lexeme lexbuf in
329398 mk lexbuf (IntInterval (String.sub s 0 (String.length s - 3)))
344413 | "<<=" -> mk lexbuf (Binop (OpAssignOp OpShl))
345414 | "||=" -> mk lexbuf (Binop (OpAssignOp OpBoolOr))
346415 | "&&=" -> mk lexbuf (Binop (OpAssignOp OpBoolAnd))
416 | "??=" -> mk lexbuf (Binop (OpAssignOp OpNullCoal))
347417 (*//| ">>=" -> mk lexbuf (Binop (OpAssignOp OpShr)) *)
348418 (*//| ">>>=" -> mk lexbuf (Binop (OpAssignOp OpUShr)) *)
349419 | "==" -> mk lexbuf (Binop OpEq)
363433 | ":" -> mk lexbuf DblDot
364434 | "," -> mk lexbuf Comma
365435 | "." -> mk lexbuf Dot
436 | "?." -> mk lexbuf QuestionDot
366437 | "%" -> mk lexbuf (Binop OpMod)
367438 | "&" -> mk lexbuf (Binop OpAnd)
368439 | "|" -> mk lexbuf (Binop OpOr)
378449 | "}" -> mk lexbuf BrClose
379450 | "(" -> mk lexbuf POpen
380451 | ")" -> mk lexbuf PClose
452 | "??" -> mk lexbuf (Binop OpNullCoal)
381453 | "?" -> mk lexbuf Question
382454 | "@" -> mk lexbuf At
383455
635707 try
636708 not_xml ctx 0 (name <> "") (* don't allow self-closing fragments *)
637709 with Exit ->
638 error Unterminated_markup p
710 error Unterminated_markup p
6666 exception SyntaxCompletion of syntax_completion * DisplayTypes.completion_subject
6767
6868 let error_msg = function
69 | Unexpected (Kwd k) -> "Unexpected keyword \""^(s_keyword k)^"\""
6970 | Unexpected t -> "Unexpected "^(s_token t)
7071 | Duplicate_default -> "Duplicate default"
7172 | Missing_semicolon -> "Missing ;"
190191 | None -> None
191192 | Some (d,pos) ->
192193 last_doc := None;
193 if pos = p.pmin then Some d else None
194 Some d
194195
195196 let unsupported_decl_flag decl flag pos =
196197 let msg = (s_decl_flag flag) ^ " modifier is not supported for " ^ decl in
269270 | OpInterval -> 7, left
270271 | OpBoolAnd -> 8, left
271272 | OpBoolOr -> 9, left
272 | OpArrow -> 10, right
273 | OpArrow | OpNullCoal -> 10, right
273274 | OpAssign | OpAssignOp _ -> 11, right
274275
275 let is_not_assign = function
276 | OpAssign | OpAssignOp _ -> false
276 let is_higher_than_ternary = function
277 | OpAssign | OpAssignOp _ | OpArrow -> false
277278 | _ -> true
278279
279280 let swap op1 op2 =
286287 | EBinop (_op,_e,_e2) when swap op _op ->
287288 let _e = make_binop op e _e in
288289 EBinop (_op,_e,_e2) , punion (pos _e) (pos _e2)
289 | ETernary (e1,e2,e3) when is_not_assign op ->
290 | ETernary (e1,e2,e3) when is_higher_than_ternary op ->
290291 let e = make_binop op e e1 in
291292 ETernary (e,e2,e3) , punion (pos e) (pos e3)
292293 | _ ->
300301 | EBinop (bop,e,e2) -> EBinop (bop, make_unop op e p1 , e2) , (punion p1 p2)
301302 | ETernary (e1,e2,e3) -> ETernary (make_unop op e1 p1 , e2, e3), punion p1 p2
302303 | EIs (e, t) -> EIs (make_unop op e p1, t), punion p1 p2
303 | EConst (Int i) when op = Neg -> EConst (Int (neg i)),punion p1 p2
304 | EConst (Float j) when op = Neg -> EConst (Float (neg j)),punion p1 p2
304 | EConst (Int (i, suffix)) when op = Neg -> EConst (Int (neg i, suffix)),punion p1 p2
305 | EConst (Float (j, suffix)) when op = Neg -> EConst (Float (neg j, suffix)),punion p1 p2
305306 | _ -> EUnop (op,Prefix,e), punion p1 p2
306307
307308 let rec make_meta name params ((v,p2) as e) p1 =
397398 if pmax <= p.pmin && pmin >= p.pmax then begin
398399 let so,p = match Stream.peek s with
399400 | Some((Const(Ident name),p)) when display_position#enclosed_in p -> (Some name),p
400 | Some(e,p) -> print_endline (s_token e); None,p
401 | Some(e,p) -> None,p
401402 | _ -> None,p
402403 in
403404 delay_syntax_completion (SCTypeDecl mode) so p
418419 end
419420
420421 let convert_abstract_flags flags =
421 ExtList.List.filter_map decl_flag_to_abstract_flag flags
422 ExtList.List.filter_map decl_flag_to_abstract_flag flags
423
424 let no_keyword what s =
425 match Stream.peek s with
426 | Some (Kwd kwd,p) -> error (Custom ("Keyword " ^ (s_keyword kwd) ^ " cannot be used as " ^ what)) p
427 | _ -> raise Stream.Failure
7171 | EConst (Ident i) ->
7272 (try TString (Define.raw_defined_value ctx i) with Not_found -> TNull)
7373 | EConst (String(s,_)) -> TString s
74 | EConst (Int i) -> TFloat (float_of_string i)
75 | EConst (Float f) -> TFloat (float_of_string f)
74 | EConst (Int (i, _)) -> TFloat (float_of_string i)
75 | EConst (Float (f, _)) -> TFloat (float_of_string f)
7676 | ECall ((EConst (Ident "version"),_),[(EConst (String(s,_)), p)]) -> parse_version s p
7777 | EBinop (OpBoolAnd, e1, e2) -> TBool (is_true (eval ctx e1) && is_true (eval ctx e2))
7878 | EBinop (OpBoolOr, e1, e2) -> TBool (is_true (eval ctx e1) || is_true(eval ctx e2))
8686 in
8787 (match op with
8888 | OpEq -> compare (=)
89 | OpNotEq -> compare (<>)
89 | OpNotEq -> TBool (not (is_true (compare (=))))
9090 | OpGt -> compare (>)
9191 | OpGte -> compare (>=)
9292 | OpLt -> compare (<)
242242 match fst tk with
243243 | Comment s ->
244244 (* if encloses_resume (pos tk) then syntax_completion SCComment (pos tk); *)
245 let tk = next_token() in
246245 let l = String.length s in
247246 if l > 0 && s.[0] = '*' then last_doc := Some (String.sub s 1 (l - (if l > 1 && s.[l-1] = '*' then 2 else 1)), (snd tk).pmin);
247 let tk = next_token() in
248248 tk
249249 | CommentLine s ->
250250 if !in_display_file then begin
251251 let p = pos tk in
252252 (* Completion at the / should not pick up the comment (issue #9133) *)
253253 let p = if is_completion() then {p with pmin = p.pmin + 1} else p in
254 if display_position#enclosed_in p then syntax_completion SCComment None (pos tk);
254 (* The > 0 check is to deal with the special case of line comments at the beginning of the file (issue #10322) *)
255 if display_position#enclosed_in p && p.pmin > 0 then syntax_completion SCComment None (pos tk);
255256 end;
256257 next_token()
257258 | Sharp "end" ->
288289 | _ -> error Unimplemented (snd tk))
289290 | Sharp "line" ->
290291 let line = (match next_token() with
291 | (Const (Int s),p) -> (try int_of_string s with _ -> error (Custom ("Could not parse ridiculous line number " ^ s)) p)
292 | (Const (Int (s, _)),p) -> (try int_of_string s with _ -> error (Custom ("Could not parse ridiculous line number " ^ s)) p)
292293 | (t,p) -> error (Unexpected t) p
293294 ) in
294295 !(Lexer.cur).Lexer.lline <- line - 1;
386387 let parse_string entry com s p error inlined =
387388 let old = Lexer.save() in
388389 let old_file = (try Some (Hashtbl.find Lexer.all_files p.pfile) with Not_found -> None) in
390 let restore_file_data =
391 let f = Lexer.make_file old.lfile in
392 Lexer.copy_file old f;
393 (fun () ->
394 Lexer.copy_file f old
395 )
396 in
389397 let old_display = display_position#get in
390398 let old_in_display_file = !in_display_file in
391399 let old_syntax_errors = !syntax_errors in
399407 in_display_file := old_in_display_file;
400408 end;
401409 syntax_errors := old_syntax_errors;
402 Lexer.restore old
410 Lexer.restore old;
411 (* String parsing might mutate lexer_file information, e.g. from newline() calls. Here we
412 restore the actual file data (issue #10763). *)
413 restore_file_data()
403414 in
404415 if inlined then
405416 Lexer.init p.pfile
2929 | _ -> (ECall (constr,vl),pmin)
3030 in
3131 let to_const c p =
32 let cst n v = mk_enum "Constant" n [EConst (String(v,SDoubleQuotes)),p] p in
3332 match c with
34 | Int i -> cst "CInt" i
33 | Int (i, suffix) ->
34 let suffix = match suffix with None -> (EConst (Ident "null"),p) | Some s -> (EConst (String (s, SDoubleQuotes)),p) in
35 mk_enum "Constant" "CInt" [(EConst (String(i,SDoubleQuotes)),p);suffix] p
3536 | String(s,qs) ->
3637 let qs = mk_enum "StringLiteralKind" (match qs with SDoubleQuotes -> "DoubleQuotes" | SSingleQuotes -> "SingleQuotes") [] p in
3738 mk_enum "Constant" "CString" [(EConst (String(s,SDoubleQuotes)),p);qs] p
38 | Float s -> cst "CFloat" s
39 | Ident s -> cst "CIdent" s
39 | Float (f, suffix) ->
40 let suffix = match suffix with None -> (EConst (Ident "null"),p) | Some s -> (EConst (String (s, SDoubleQuotes)),p) in
41 mk_enum "Constant" "CFloat" [(EConst (String(f,SDoubleQuotes)),p);suffix] p
42 | Ident s -> mk_enum "Constant" "CIdent" [EConst (String(s,SDoubleQuotes)),p] p
4043 | Regexp (r,o) -> mk_enum "Constant" "CRegexp" [(EConst (String(r,SDoubleQuotes)),p);(EConst (String(o,SDoubleQuotes)),p)] p
4144 in
4245 let rec to_binop o p =
6669 | OpInterval -> op "OpInterval"
6770 | OpArrow -> op "OpArrow"
6871 | OpIn -> op "OpIn"
72 | OpNullCoal -> op "OpNullCoal"
6973 in
7074 let to_string s p =
7175 let len = String.length s in
112116 type parameters. *)
113117 let ea = to_array to_tparam t.tparams p in
114118 let fields = [
115 ("pack", (EField(ei,"pack"),p));
116 ("name", (EField(ei,"name"),p));
117 ("sub", (EField(ei,"sub"),p));
119 ("pack", (efield(ei,"pack"),p));
120 ("name", (efield(ei,"name"),p));
121 ("sub", (efield(ei,"sub"),p));
118122 ("params", ea);
119123 ] in
120124 to_obj fields p
219223 p
220224 | None ->
221225 let file = (EConst (String(p.pfile,SDoubleQuotes)),p) in
222 let pmin = (EConst (Int (string_of_int p.pmin)),p) in
223 let pmax = (EConst (Int (string_of_int p.pmax)),p) in
226 let pmin = (EConst (Int ((string_of_int p.pmin), None)),p) in
227 let pmax = (EConst (Int ((string_of_int p.pmax), None)),p) in
224228 if in_macro then
225229 (EUntyped (ECall ((EConst (Ident "$__mk_pos__"),p),[file;pmin;pmax]),p),p)
226230 else
229233 match !cur_pos with
230234 | Some p -> p
231235 | None when in_macro -> to_pos p
232 | None -> (ECall ((EField ((EField ((EField ((EConst (Ident "haxe"),p),"macro"),p),"Context"),p),"makePosition"),p),[to_pos p]),p)
236 | None -> (ECall ((efield ((efield ((efield ((EConst (Ident "haxe"),p),"macro"),p),"Context"),p),"makePosition"),p),[to_pos p]),p)
233237 and to_expr_array a p = match a with
234238 | [EMeta ((Meta.Dollar "a",[],_),e1),_] -> (match fst e1 with EArrayDecl el -> to_expr_array el p | _ -> e1)
235239 | _ -> to_array to_expr a p
249253 expr "EArray" [loop e1;loop e2]
250254 | EBinop (op,e1,e2) ->
251255 expr "EBinop" [to_binop op p; loop e1; loop e2]
252 | EField (e,s) ->
253 let p = {p with pmin = p.pmax - String.length s} in
254 expr "EField" [loop e; to_string s p]
256 | EField (e,s,efk) ->
257 let p = patch_string_pos p s in
258 let efk = match efk with
259 | EFNormal -> "Normal"
260 | EFSafe -> "Safe"
261 in
262 expr "EField" [loop e; to_string s p; mk_enum "EFieldKind" efk [] p]
255263 | EParenthesis e ->
256264 expr "EParenthesis" [loop e]
257265 | EObjectDecl fl ->
286294 "type", to_opt to_type_hint v.ev_type p;
287295 "expr", to_opt to_expr v.ev_expr p;
288296 "isFinal",to_bool v.ev_final p;
297 "isStatic",to_bool v.ev_static p;
289298 "meta",to_meta v.ev_meta p;
290299 ] in
291300 to_obj fields p
332341 expr "EIs" [loop e; to_type_hint ct p]
333342 | EDisplay (e,dk) ->
334343 expr "EDisplay" [loop e; to_display_kind dk p]
335 | EDisplayNew t ->
336 expr "EDisplayNew" [to_tpath t p]
337344 | ETernary (e1,e2,e3) ->
338345 expr "ETernary" [loop e1;loop e2;loop e3]
339346 | ECheckType (e1,ct) ->
352359 | EParenthesis (ECheckType (e2, (CTPath{tname="String";tpackage=[]},_)),_) -> expr "EConst" [mk_enum "Constant" "CString" [e2] (pos e2)]
353360 | EParenthesis (ECheckType (e2, (CTPath{tname="Int";tpackage=[]},_)),_) -> expr "EConst" [mk_enum "Constant" "CInt" [e2] (pos e2)]
354361 | EParenthesis (ECheckType (e2, (CTPath{tname="Float";tpackage=[]},_)),_) -> expr "EConst" [mk_enum "Constant" "CFloat" [e2] (pos e2)]
355 | _ -> (ECall ((EField ((EField ((EField ((EConst (Ident "haxe"),p),"macro"),p),"Context"),p),"makeExpr"),p),[e; to_enc_pos (pos e)]),p)
362 | EConst (Int (s, Some "i64")) ->
363 expr "EConst" [mk_enum "Constant" "CInt" [ (EConst(String (s, SDoubleQuotes)),(pos e1)); (EConst(String ("i64", SDoubleQuotes)),(pos e1)) ] (pos e1)]
364 | _ ->
365 (ECall ((efield ((efield ((efield ((EConst (Ident "haxe"),p),"macro"),p),"Context"),p),"makeExpr"),p),[e1; to_enc_pos (pos e1)]),p)
356366 end
357367 | Meta.Dollar "i", _ ->
358368 expr "EConst" [mk_enum "Constant" "CIdent" [e1] (pos e1)]
359369 | Meta.Dollar "p", _ ->
360 (ECall ((EField ((EField ((EField ((EConst (Ident "haxe"),p),"macro"),p),"MacroStringTools"),p),"toFieldExpr"),p),[e]),p)
370 (ECall ((efield ((efield ((efield ((EConst (Ident "haxe"),p),"macro"),p),"MacroStringTools"),p),"toFieldExpr"),p),[e1]),p)
361371 | Meta.Pos, [pexpr] ->
362372 let old = !cur_pos in
363373 cur_pos := Some pexpr;
371381 "name", to_placed_name t.tp_name;
372382 "params", (EArrayDecl (List.map (to_tparam_decl p) t.tp_params),p);
373383 "meta", to_meta t.tp_meta p;
374 "constraints", (EArrayDecl (match t.tp_constraints with None -> [] | Some th -> [to_ctype th p]),p)
384 "constraints", (EArrayDecl (match t.tp_constraints with None -> [] | Some th -> [to_ctype th p]),p);
385 "defaultType", to_opt to_ctype t.tp_default p;
375386 ] p
376387 and to_type_def (t,p) =
377388 match t with
00 open Globals
11 open Ast
22 open Type
3 open Common
34 open Typecore
45 open Error
56 open FieldAccess
1112 | _ when has_class_field_flag cf CfExtern -> true
1213 | _ -> false
1314
14 let relative_path ctx file =
15 let slashes path = String.concat "/" (ExtString.String.nsplit path "\\") in
16 let fpath = slashes (Path.get_full_path file) in
17 let fpath_lower = String.lowercase fpath in
18 let flen = String.length fpath_lower in
19 let rec loop = function
20 | [] -> file
21 | path :: l ->
22 let spath = String.lowercase (slashes path) in
23 let slen = String.length spath in
24 if slen > 0 && slen < flen && String.sub fpath_lower 0 slen = spath then String.sub fpath slen (flen - slen) else loop l
25 in
26 loop ctx.com.Common.class_path
27
28 let mk_infos ctx p params =
29 let file = if ctx.in_macro then p.pfile else if Common.defined ctx.com Define.AbsolutePath then Path.get_full_path p.pfile else relative_path ctx p.pfile in
30 (EObjectDecl (
31 (("fileName",null_pos,NoQuotes) , (EConst (String(file,SDoubleQuotes)) , p)) ::
32 (("lineNumber",null_pos,NoQuotes) , (EConst (Int (string_of_int (Lexer.get_error_line p))),p)) ::
33 (("className",null_pos,NoQuotes) , (EConst (String (s_type_path ctx.curclass.cl_path,SDoubleQuotes)),p)) ::
34 if ctx.curfield.cf_name = "" then
35 params
36 else
37 (("methodName",null_pos,NoQuotes), (EConst (String (ctx.curfield.cf_name,SDoubleQuotes)),p)) :: params
38 ) ,p)
39
40 let rec is_pos_infos = function
41 | TMono r ->
42 (match r.tm_type with
43 | Some t -> is_pos_infos t
44 | _ -> false)
45 | TLazy f ->
46 is_pos_infos (lazy_type f)
47 | TType ({ t_path = ["haxe"] , "PosInfos" },[]) ->
48 true
49 | TType (t,tl) ->
50 is_pos_infos (apply_params t.t_params tl t.t_type)
51 | TAbstract({a_path=[],"Null"},[t]) ->
52 is_pos_infos t
53 | _ ->
54 false
55
5615 let rec unify_call_args ctx el args r callp inline force_inline in_overload =
5716 let call_error err p =
58 raise (Error (Call_error err,p))
17 raise (Error (Call_error err,p,0))
5918 in
6019 let arg_error ul name opt p =
61 let err = Stack (ul,Custom ("For " ^ (if opt then "optional " else "") ^ "function argument '" ^ name ^ "'")) in
20 let msg = ("For " ^ (if opt then "optional " else "") ^ "function argument '" ^ name ^ "'") in
21 let err = match ul with
22 | Stack s -> Stack (s @ [(Custom msg,p)])
23 | Unify l -> Unify (l @ [(Unify_custom msg)])
24 | Custom parent -> Custom (parent ^ "\n" ^ msg)
25 | _ -> Stack [(ul,p); (Custom (compl_msg msg), p)]
26 in
6227 call_error (Could_not_unify err) p
6328 in
6429 let mk_pos_infos t =
8247 let handle_errors fn =
8348 try
8449 fn()
85 with Error(l,p) when (match l with Call_error _ | Module_not_found _ -> false | _ -> true) ->
86 raise (WithTypeError (l,p))
50 with Error(l,p,nl) when (match l with Call_error _ | Module_not_found _ -> false | _ -> true) ->
51 raise (WithTypeError (l,p,nl))
8752 in
8853 (* let force_inline, is_extern = match cf with Some(TInst(c,_),f) -> is_forced_inline (Some c) f, (has_class_flag c CExtern) | _ -> false, false in *)
8954 let type_against name t e =
10166 []
10267 | _,[name,false,TAbstract({ a_path = ["cpp"],"Rest" },[t])] ->
10368 (try List.map (fun e -> type_against name t e) el
104 with WithTypeError(ul,p) -> arg_error ul name false p)
69 with WithTypeError(ul,p,_) -> arg_error ul name false p)
10570 | _,[name,false,t] when ExtType.is_rest (follow t) ->
10671 begin match follow t with
10772 | TAbstract({a_path=(["haxe"],"Rest")},[arg_t]) ->
12085 match el with
12186 | [(EUnop (Spread,Prefix,e),p)] ->
12287 (try [mk (TUnop (Spread, Prefix, type_against name t e)) t p]
123 with WithTypeError(ul,p) -> arg_error ul name false p)
88 with WithTypeError(ul,p,_) -> arg_error ul name false p)
12489 | _ when ExtType.is_mono (follow arg_t) ->
12590 (try
12691 let el = type_rest mk_mono in
127 unify ctx (unify_min ctx el) arg_t (punion_el (List.map (fun e -> ((),e.epos)) el));
92 unify ctx (unify_min ctx el) arg_t (punion_el callp el);
12893 el
129 with WithTypeError(ul,p) ->
94 with WithTypeError(ul,p,_) ->
13095 arg_error ul name false p)
13196 | _ ->
13297 (try
13398 type_rest (fun() -> arg_t)
134 with WithTypeError(ul,p) ->
99 with WithTypeError(ul,p,_) ->
135100 arg_error ul name false p)
136101 (* for other platforms make sure rest arguments are wrapped in an array *)
137102 else begin
138103 match el with
139104 | [(EUnop (Spread,Prefix,e),p)] ->
140105 (try [type_against name t e]
141 with WithTypeError(ul,p) -> arg_error ul name false p)
106 with WithTypeError(ul,p,_) -> arg_error ul name false p)
142107 | [] ->
143108 (try [type_against name t (EArrayDecl [],callp)]
144 with WithTypeError(ul,p) -> arg_error ul name false p)
109 with WithTypeError(ul,p,_) -> arg_error ul name false p)
145110 | (_,p1) :: _ ->
146111 let p =
147112 List.fold_left (fun p (e1,p2) ->
161126 do_type (ECheckType(e,(CTPath tp, p)),p) (* ([arg1, arg2...]:Array<Dynamic>) *)
162127 end else
163128 do_type e
164 with WithTypeError(ul,p) ->
129 with WithTypeError(ul,p,_) ->
165130 arg_error ul name false p
166131 )
167132 end
171136 | [],(_,false,_) :: _ ->
172137 call_error (Not_enough_arguments args) callp
173138 | [],(name,true,t) :: args ->
174 begin match loop [] args with
139 if not ctx.allow_transform then begin
140 ignore(loop [] args);
141 []
142 end else begin match loop [] args with
175143 | [] when not (inline && (ctx.g.doinline || force_inline)) && not ctx.com.config.pf_pad_nulls ->
176144 if is_pos_infos t then [mk_pos_infos t]
177145 else []
182150 | (e,p) :: el, [] ->
183151 begin match List.rev !skipped with
184152 | [] ->
185 if ctx.is_display_file && not (Diagnostics.is_diagnostics_run ctx.com p) then begin
153 if ctx.is_display_file && not (Diagnostics.error_in_diagnostics_run ctx.com p) then begin
186154 ignore(type_expr ctx (e,p) WithType.value);
187155 ignore(loop el [])
188156 end;
190158 | (s,ul,p) :: _ -> arg_error ul s true p
191159 end
192160 | e :: el,(name,opt,t) :: args ->
161 let might_skip = List.length el < List.length args in
193162 begin try
194163 let e = type_against name t e in
195164 e :: loop el args
196165 with
197 WithTypeError (ul,p)->
198 if opt && List.length el < List.length args then
166 WithTypeError (ul,p,_)->
167 if opt && might_skip then
199168 let e_def = skip name ul t p in
200169 e_def :: loop (e :: el) args
201170 else
235204 match args,el with
236205 | [], _ :: _ ->
237206 let call_error = Call_error(Too_many_arguments) in
238 raise(Error(call_error,call_pos))
207 raise(Error(call_error,call_pos,0))
239208 | _, [] ->
240209 List.rev acc_args,args
241210 | ((_,opt,t0) as arg) :: args,e :: el ->
242211 begin try
243 unify_raise ctx (tmap e.etype) t0 e.epos;
244 with Error(Unify _ as msg,p) ->
212 unify_raise (tmap e.etype) t0 e.epos;
213 with Error(Unify _ as msg,p,nl) ->
245214 let call_error = Call_error(Could_not_unify msg) in
246 raise(Error(call_error,p))
215 raise(Error(call_error,p,nl))
247216 end;
248217 loop (arg :: acc_args) (fun t -> t) args el
249218 in
297266 | Some s -> new Javadoc.javadoc s
298267 in
299268 match de with
300 | DisplayHover (Some hover) ->
269 | DisplayHover hover ->
301270 begin match hover.hexpected with
302271 | Some (WithType(t,Some si)) ->
303272 let si = match si with
343312 in
344313 make_field_call_candidate el ret monos tf cf (mk_call,extract_delayed_display())
345314 | t ->
346 error (s_type (print_context()) t ^ " cannot be called") p
315 typing_error (s_type (print_context()) t ^ " cannot be called") p
347316 in
348317 let maybe_raise_unknown_ident cerr p =
349 let rec loop err =
318 let rec loop err p =
350319 match err with
351 | Unknown_ident _ -> error (error_msg err) p
352 | Stack (e1,e2) -> (loop e1; loop e2)
320 | Unknown_ident _ -> located_typing_error (error_msg p err)
321 | Stack stack -> List.iter (fun (e,p) -> loop e p) stack
353322 | _ -> ()
354323 in
355 match cerr with Could_not_unify err -> loop err | _ -> ()
324 match cerr with Could_not_unify err -> loop err p | _ -> ()
356325 in
357326 let attempt_calls candidates =
358327 let rec loop candidates = match candidates with
370339 candidate :: candidates,failures
371340 end else
372341 [candidate],[]
373 with Error ((Call_error cerr as err),p) ->
342 with Error ((Call_error cerr as err),p,_) ->
374343 List.iter (fun (m,t,constr) ->
375344 if t != m.tm_type then m.tm_type <- t;
376345 if constr != m.tm_down_constraints then m.tm_down_constraints <- constr;
405374 if overload_kind = OverloadProper then maybe_check_access cf;
406375 begin try
407376 commit_delayed_display (attempt_call cf false)
408 with Error _ when ctx.com.display.dms_error_policy = EPIgnore ->
377 with Error _ when Common.ignore_error ctx.com ->
409378 fail_fun();
410379 end
411380 | _ ->
416385 Option.may (fun de ->
417386 raise_augmented_display_exception cf de;
418387 ) delayed_display;
419 cf,error_msg err,p
388 cf,error_msg p err
420389 ) failures in
421 let failures = remove_duplicates (fun (_,msg1,_) (_,msg2,_) -> msg1 <> msg2) failures in
390 let failures = remove_duplicates (fun (_,msg1) (_,msg2) -> msg1 <> msg2) failures in
422391 begin match failures with
423 | [_,msg,p] ->
424 error msg p
392 | [_,msg] ->
393 located_typing_error msg
425394 | _ ->
426 display_error ctx "Could not find a suitable overload, reasons follow" p;
427 List.iter (fun (cf,msg,p2) ->
428 display_error ctx ("Overload resolution failed for " ^ (s_type (print_context()) cf.cf_type)) p;
429 display_error ctx msg p2;
395 display_error ctx.com "Could not find a suitable overload, reasons follow" p;
396 List.iter (fun (cf,msg) ->
397 display_error ~depth:1 ctx.com ("Overload resolution failed for " ^ (s_type (print_context()) cf.cf_type)) p;
398 located_display_error ~depth:2 ctx.com msg;
430399 ) failures;
431 error "End of overload failure reasons" p
400 typing_error ~depth:1 "End of overload failure reasons" p
432401 end
433402 in
434403 if overload_kind = OverloadProper then begin match Overloads.Resolution.reduce_compatible candidates with
437406 maybe_check_access fcc.fc_field;
438407 commit_delayed_display fcc
439408 | fcc :: l ->
440 display_error ctx "Ambiguous overload, candidates follow" p;
409 display_error ctx.com "Ambiguous overload, candidates follow" p;
441410 let st = s_type (print_context()) in
442411 List.iter (fun fcc ->
443 display_error ctx (Printf.sprintf "... %s" (st fcc.fc_type)) fcc.fc_field.cf_name_pos;
412 display_error ~depth:1 ctx.com (compl_msg (st fcc.fc_type)) fcc.fc_field.cf_name_pos;
444413 ) (fcc :: l);
445414 commit_delayed_display fcc
446415 end else begin match List.rev candidates with
455424 (p : pos)
456425 =
457426 let is_set = match mode with MSet _ -> true | _ -> false in
458 let check_assign () = if is_set && ctx.com.display.dms_error_policy <> EPIgnore then invalid_assign p in
427 let check_assign () = if is_set && not (Common.ignore_error ctx.com) then invalid_assign p in
459428
460429 object(self)
461430
462431 method private make_field_call (fa : field_access) (el_typed : texpr list) (el : expr list) =
463432 let fcc = unify_field_call ctx fa el_typed el p fa.fa_inline in
464 if has_class_field_flag fcc.fc_field CfAbstract then begin match fa.fa_on.eexpr with
465 | TConst TSuper -> display_error ctx (Printf.sprintf "abstract method %s cannot be accessed directly" fcc.fc_field.cf_name) p;
466 | _ -> ()
467 end;
468 fcc.fc_data()
433 if has_class_field_flag fcc.fc_field CfGeneric then begin
434 !type_generic_function_ref ctx fa fcc with_type p
435 end else begin
436 if has_class_field_flag fcc.fc_field CfAbstract then begin match fa.fa_on.eexpr with
437 | TConst TSuper -> display_error ctx.com (Printf.sprintf "abstract method %s cannot be accessed directly" fcc.fc_field.cf_name) p;
438 | _ -> ()
439 end;
440 fcc.fc_data()
441 end
469442
470443 method private macro_call (ethis : texpr) (cf : tclass_field) (el : expr list) =
471 if ctx.macro_depth > 300 then error "Stack overflow" p;
444 if ctx.macro_depth > 300 then typing_error "Stack overflow" p;
472445 ctx.macro_depth <- ctx.macro_depth + 1;
473446 ctx.with_type_stack <- with_type :: ctx.with_type_stack;
474447 let ethis_f = ref (fun () -> ()) in
502475 in
503476 ctx.macro_depth <- ctx.macro_depth - 1;
504477 ctx.with_type_stack <- List.tl ctx.with_type_stack;
505 let old = ctx.on_error in
506 ctx.on_error <- (fun ctx msg ep ->
478 let old = ctx.com.located_error in
479 ctx.com.located_error <- (fun ?(depth = 0) msg ->
480 let ep = extract_located_pos msg in
507481 (* display additional info in the case the error is not part of our original call *)
508482 if ep.pfile <> p.pfile || ep.pmax < p.pmin || ep.pmin > p.pmax then begin
509483 locate_macro_error := false;
510 old ctx msg ep;
484 old ~depth (if ep = null_pos then (relocate msg p) else msg);
511485 locate_macro_error := true;
512 ctx.com.error (compl_msg "Called from macro here") p;
486 if ep <> null_pos then old ~depth:(depth+1) (located (compl_msg "Called from macro here") p);
513487 end else
514 old ctx msg ep;
488 old ~depth msg;
515489 );
516490 let e = try
517491 f()
518492 with exc ->
519 ctx.on_error <- old;
493 ctx.com.located_error <- old;
520494 !ethis_f();
521495 raise exc
522496 in
523497 let e = Diagnostics.secure_generated_code ctx e in
524 ctx.on_error <- old;
498 ctx.com.located_error <- old;
525499 !ethis_f();
526500 e
527501
529503 used with actual expression calls and not with something like field calls. *)
530504 method expr_call (e : texpr) (el_typed : texpr list) (el : expr list) =
531505 check_assign();
506 let default t =
507 let el = el_typed @ List.map (fun e -> type_expr ctx e WithType.value) el in
508 let t = if t == t_dynamic then
509 t_dynamic
510 else if ctx.untyped then
511 mk_mono()
512 else
513 typing_error (s_type (print_context()) e.etype ^ " cannot be called") e.epos
514 in
515 mk (TCall (e,el)) t p
516 in
532517 let rec loop t = match follow t with
533518 | TFun (args,r) ->
534519 let args_typed,args_left = unify_typed_args ctx (fun t -> t) args el_typed p in
536521 let el = el_typed @ el in
537522 let r = match tfunc with TFun(_,r) -> r | _ -> die "" __LOC__ in
538523 mk (TCall (e,el)) r p
539 | TAbstract(a,tl) when Meta.has Meta.Callable a.a_meta ->
540 loop (Abstract.get_underlying_type a tl)
524 | TAbstract(a,tl) as t ->
525 let check_callable () =
526 if Meta.has Meta.Callable a.a_meta then
527 loop (Abstract.get_underlying_type a tl)
528 else
529 default t
530 in
531 begin match a.a_call,a.a_impl with
532 | Some cf,Some c ->
533 let e_static = Builder.make_static_this c e.epos in
534 let fa = FieldAccess.create e_static cf (FHAbstract(a,tl,c)) false e.epos in
535 self#field_call fa (e :: el_typed) el
536 | _ ->
537 check_callable();
538 end
541539 | TMono _ ->
542540 let t = mk_mono() in
543541 let el = el_typed @ List.map (fun e -> type_expr ctx e WithType.value) el in
544542 unify ctx (tfun (List.map (fun e -> e.etype) el) t) e.etype e.epos;
545543 mk (TCall (e,el)) t p
546544 | t ->
547 let el = el_typed @ List.map (fun e -> type_expr ctx e WithType.value) el in
548 let t = if t == t_dynamic then
549 t_dynamic
550 else if ctx.untyped then
551 mk_mono()
552 else
553 error (s_type (print_context()) e.etype ^ " cannot be called") e.epos
554 in
555 mk (TCall (e,el)) t p
545 default t
556546 in
557547 loop e.etype
558548
581571 let name = Printf.sprintf "%s_%s" (if is_set then "set" else "get") fa.fa_field.cf_name in
582572 make_call ctx (mk (TField (e,quick_field_dynamic e.etype name)) tf p) el_typed t p
583573 | _ ->
584 error "Could not resolve accessor" p
574 typing_error "Could not resolve accessor" p
585575
586576 (* Calls the field represented by `fa` with the typed arguments `el_typed` and the syntactic arguments `el`.
587577
588578 This function inspects the nature of the field being called and dispatches the call accordingly:
589579
590 * If the field is `@:generic`, call `type_generic_function`.
591580 * If the field is a non-macro method, call it via `make_field_call`.
592581 * If the field is a property, resolve the accessor (depending on `mode`) and recurse onto it.
593582 * Otherwise, call the field as a normal expression via `expr_call`.
596585 match fa.fa_field.cf_kind with
597586 | Method (MethNormal | MethInline | MethDynamic) ->
598587 check_assign();
599 if has_class_field_flag fa.fa_field CfGeneric then begin
600 !type_generic_function_ref ctx fa el_typed el with_type p
601 end else
602 self#make_field_call fa el_typed el
588 self#make_field_call fa el_typed el
603589 | Method MethMacro ->
604590 begin match el_typed with
605591 | [] ->
606592 self#macro_call fa.fa_on fa.fa_field el
607593 | el_typed ->
608 let cur = ctx.this_stack in
609 let el' = List.map (fun e -> fst (push_this ctx e)) el_typed in
594 let el',fl = List.split (List.map (fun e -> push_this ctx e) el_typed) in
610595 let e = self#macro_call fa.fa_on fa.fa_field (el' @ el) in
611 ctx.this_stack <- cur;
596 List.iter (fun f -> f()) fl;
612597 e
613598 end;
614599 | Var v ->
640625 e
641626 end
642627 | _ ->
643 e
628 e
99 open CallUnification
1010
1111 let make_call ctx e params t ?(force_inline=false) p =
12 let params =
13 match follow e.etype with
14 | TFun (expected_args,_) ->
15 (match List.rev expected_args with
16 | (_,true,t) :: rest when is_pos_infos t && List.length rest = List.length params ->
17 let infos = mk_infos ctx p [] in
18 params @ [type_expr ctx infos (WithType.with_type t)]
19 | _ -> params
20 )
21 | _ -> params
22 in
1223 try
1324 let ethis,cl,f = match e.eexpr with
1425 | TField (ethis,fa) ->
3546 PMap.mem f.cf_name c.cl_fields
3647 || List.exists has_override c.cl_descendants
3748 in
38 if List.exists has_override c.cl_descendants then error (Printf.sprintf "Cannot force inline-call to %s because it is overridden" f.cf_name) p
49 if List.exists has_override c.cl_descendants then typing_error (Printf.sprintf "Cannot force inline-call to %s because it is overridden" f.cf_name) p
3950 )
4051 end;
4152 let config = Inline.inline_config cl f params t in
5162 (* Current method needs to infer CfModifiesThis flag, since we are calling a method, which modifies `this` *)
5263 add_class_field_flag ctx.curfield CfModifiesThis
5364 else
54 error ("Abstract 'this' value can only be modified inside an inline function. '" ^ f.cf_name ^ "' modifies 'this'") p;
65 typing_error ("Abstract 'this' value can only be modified inside an inline function. '" ^ f.cf_name ^ "' modifies 'this'") p;
5566 | _ -> ()
5667 );
57 let params = List.map (ctx.g.do_optimize ctx) params in
68 let params = List.map (Optimizer.reduce_expression ctx) params in
5869 let force_inline = is_forced_inline cl f in
5970 (match f.cf_expr_unoptimized,f.cf_expr with
60 | Some fd,_
71 | Some {eexpr = TFunction fd},_
6172 | None,Some { eexpr = TFunction fd } ->
6273 (match Inline.type_inline ctx f fd ethis params t config p force_inline with
6374 | None ->
64 if force_inline then error "Inline could not be done" p;
75 if force_inline then typing_error "Inline could not be done" p;
6576 raise Exit;
6677 | Some e -> e)
6778 | _ ->
7485 with Exit ->
7586 mk (TCall (e,params)) t p
7687
77 let mk_array_get_call ctx (cf,tf,r,e1,e2o) c ebase p = match cf.cf_expr with
88 let mk_array_get_call ctx (cf,tf,r,e1) c ebase p = match cf.cf_expr with
7889 | None when not (has_class_field_flag cf CfExtern) ->
79 if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx "Recursive array get method" p;
90 if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx.com "Recursive array get method" p;
8091 mk (TArray(ebase,e1)) r p
8192 | _ ->
8293 let et = type_module_type ctx (TClassDecl c) None p in
8394 let ef = mk (TField(et,(FStatic(c,cf)))) tf p in
8495 make_call ctx ef [ebase;e1] r p
8596
86 let mk_array_set_call ctx (cf,tf,r,e1,e2o) c ebase p =
87 let evalue = match e2o with None -> die "" __LOC__ | Some e -> e in
97 let mk_array_set_call ctx (cf,tf,r,e1,evalue) c ebase p =
8898 match cf.cf_expr with
8999 | None when not (has_class_field_flag cf CfExtern) ->
90 if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx "Recursive array set method" p;
100 if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx.com "Recursive array set method" p;
91101 let ea = mk (TArray(ebase,e1)) r p in
92102 mk (TBinop(OpAssign,ea,evalue)) r p
93103 | _ ->
99109 | TAbstract(a,tl) when has_class_field_flag sea.se_access.fa_field CfImpl -> apply_params a.a_params tl a.a_this
100110 | _ -> sea.se_this.etype
101111
102 let rec acc_get ctx g p =
112 let rec acc_get ctx g =
103113 let inline_read fa =
104114 let cf = fa.fa_field in
115 let p = fa.fa_pos in
105116 (* do not create a closure for static calls *)
106117 let apply_params = match fa.fa_host with
107118 | FHStatic c ->
154165 let e_def = FieldAccess.get_field_expr fa FRead in
155166 begin match follow fa.fa_on.etype with
156167 | TInst (c,_) when chk_class c ->
157 display_error ctx "Can't create closure on an extern inline member method" p;
168 display_error ctx.com "Can't create closure on an extern inline member method" p;
158169 e_def
159170 | TAnon a ->
160171 begin match !(a.a_status) with
161172 | Statics c when has_class_field_flag cf CfExtern ->
162 display_error ctx "Cannot create closure on @:extern inline method" p;
173 display_error ctx.com "Cannot create closure on @:extern inline method" p;
163174 e_def
164175 | Statics c when chk_class c -> wrap_extern c
165176 | _ -> e_def
173184 let tf = apply_params cf.cf_type in
174185 if not (type_iseq tf e.etype) then mk (TCast(e,None)) tf e.epos
175186 else e
176 | Var _,None when ctx.com.display.dms_display ->
177 FieldAccess.get_field_expr fa FRead
178187 | Var _,None ->
179 error "Recursive inline is not supported" p
188 typing_error "Recursive inline is not supported" p
180189 end
181190 in
182 let dispatcher () = new call_dispatcher ctx MGet WithType.value p in
191 let dispatcher p = new call_dispatcher ctx MGet WithType.value p in
183192 match g with
184 | AKNo f -> error ("Field " ^ f ^ " cannot be accessed for reading") p
193 | AKNo(_,p) -> typing_error ("This expression cannot be accessed for reading") p
185194 | AKExpr e -> e
195 | AKSafeNav sn ->
196 (* generate null-check branching for the safe navigation chain *)
197 let eobj = sn.sn_base in
198 let enull = Builder.make_null eobj.etype sn.sn_pos in
199 let eneq = Builder.binop OpNotEq eobj enull ctx.t.tbool sn.sn_pos in
200 let ethen = acc_get ctx sn.sn_access in
201 let tnull = ctx.t.tnull ethen.etype in
202 let ethen = if not (is_nullable ethen.etype) then
203 mk (TCast(ethen,None)) tnull ethen.epos
204 else
205 ethen
206 in
207 let eelse = Builder.make_null tnull sn.sn_pos in
208 let eif = mk (TIf(eneq,ethen,Some eelse)) tnull sn.sn_pos in
209 (match sn.sn_temp_var with
210 | None -> eif
211 | Some evar -> { eif with eexpr = TBlock [evar; eif] })
186212 | AKAccess _ -> die "" __LOC__
187213 | AKResolve(sea,name) ->
188 (dispatcher ())#resolve_call sea name
214 (dispatcher sea.se_access.fa_pos)#resolve_call sea name
189215 | AKUsingAccessor sea | AKUsingField sea when ctx.in_display ->
190216 (* Generate a TField node so we can easily match it for position/usage completion (issue #1968) *)
191217 let e_field = FieldAccess.get_field_expr sea.se_access FGet in
203229 if ctx.in_display then
204230 FieldAccess.get_field_expr fa FRead
205231 else
206 error "Invalid macro access" p
232 typing_error "Invalid macro access" fa.fa_pos
207233 | _ ->
208234 if fa.fa_inline then
209235 inline_read fa
211237 FieldAccess.get_field_expr fa FRead
212238 end
213239 | AKAccessor fa ->
214 (dispatcher())#field_call fa [] []
240 (dispatcher fa.fa_pos)#field_call fa [] []
215241 | AKUsingAccessor sea ->
216 (dispatcher())#field_call sea.se_access [sea.se_this] []
242 (dispatcher sea.se_access.fa_pos)#field_call sea.se_access [sea.se_this] []
217243 | AKUsingField sea ->
218244 let e = sea.se_this in
219245 let e_field = FieldAccess.get_field_expr sea.se_access FGet in
220246 (* build a closure with first parameter applied *)
221247 (match follow e_field.etype with
222248 | TFun ((_,_,t0) :: args,ret) ->
249 let p = sea.se_access.fa_pos in
223250 let te = abstract_using_param_type sea in
224251 unify ctx te t0 e.epos;
225252 let tcallb = TFun (args,ret) in
244271 make_call ctx ewrap [e] tcallb p
245272 | _ -> die "" __LOC__)
246273
247 let build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p =
274 let check_dynamic_super_method_call ctx fa p =
275 match fa with
276 | { fa_on = { eexpr = TConst TSuper } ; fa_field = { cf_kind = Method MethDynamic; cf_name = name } } ->
277 ctx.com.error ("Cannot call super." ^ name ^ " since it's a dynamic method") p
278 | _ ->
279 ()
280
281 let rec build_call_access ctx acc el mode with_type p =
282 let get_accessor_to_call fa args =
283 let dispatch = new call_dispatcher ctx MGet WithType.value fa.fa_pos in
284 dispatch#field_call fa args []
285 in
248286 let dispatch = new call_dispatcher ctx mode with_type p in
249287 match acc with
250288 | AKField fa ->
251 dispatch#field_call fa [] el
289 check_dynamic_super_method_call ctx fa p;
290 AKExpr (dispatch#field_call fa [] el)
252291 | AKUsingField sea ->
253292 let eparam = sea.se_this in
254 dispatch#field_call sea.se_access [eparam] el
293 let e = dispatch#field_call sea.se_access [eparam] el in
294 let e = match sea.se_access.fa_host with
295 | FHAbstract _ when not ctx.allow_transform ->
296 (* transform XXXImpl.field(this,args) back into this.field(args) *)
297 (match e.eexpr with
298 | TCall ({ eexpr = TField(_,name) } as f, abs :: el) -> { e with eexpr = TCall(mk (TField(abs,name)) t_dynamic f.epos, el) }
299 | _ -> assert false)
300 | _ ->
301 e
302 in
303 AKExpr e
255304 | AKResolve(sea,name) ->
256 dispatch#expr_call (dispatch#resolve_call sea name) [] el
257 | AKNo _ | AKAccess _ ->
258 ignore(acc_get ctx acc p);
259 error ("Unexpected access mode, please report this: " ^ (s_access_kind acc)) p
305 AKExpr (dispatch#expr_call (dispatch#resolve_call sea name) [] el)
306 | AKNo(_,p) ->
307 typing_error "This expression cannot be called" p
308 | AKAccess _ ->
309 typing_error "This expression cannot be called" p
260310 | AKAccessor fa ->
261 let e = dispatch#field_call fa [] [] in
262 dispatch#expr_call e [] el
311 let e = get_accessor_to_call fa [] in
312 AKExpr (dispatch#expr_call e [] el)
263313 | AKUsingAccessor sea ->
264 let e = dispatch#field_call sea.se_access [sea.se_this] [] in
265 dispatch#expr_call e [] el
314 let e = get_accessor_to_call sea.se_access [sea.se_this] in
315 AKExpr (dispatch#expr_call e [] el)
266316 | AKExpr e ->
267 dispatch#expr_call e [] el
317 AKExpr (dispatch#expr_call e [] el)
318 | AKSafeNav sn ->
319 (* pack the call inside the safe navigation chain *)
320 AKSafeNav { sn with sn_access = build_call_access ctx sn.sn_access el mode with_type p }
321
322 let build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p =
323 acc_get ctx (build_call_access ctx acc el mode with_type p)
268324
269325 let rec needs_temp_var e =
270326 match e.eexpr with
273329 | _ -> true
274330
275331 let call_to_string ctx ?(resume=false) e =
332 if not ctx.allow_transform then
333 { e with etype = ctx.t.tstring }
334 else
276335 let gen_to_string e =
277336 (* Ignore visibility of the toString field. *)
278337 ctx.meta <- (Meta.PrivateAccess,[],e.epos) :: ctx.meta;
314373 in
315374 let rec loop args params given_args missing_args ordered_args = match args, params with
316375 | [], [] -> given_args,missing_args,ordered_args
317 | [], _ -> error "Too many callback arguments" p
376 | [], _ -> typing_error "Too many callback arguments" p
318377 | (n,o,t) :: args , [] when o ->
319378 let a = if is_pos_infos t then
320379 let infos = mk_infos ctx p [] in
321380 ordered_args @ [type_expr ctx infos (WithType.with_argument t n)]
322 else if ctx.com.config.pf_pad_nulls then
381 else if ctx.com.config.pf_pad_nulls && ctx.allow_transform then
323382 (ordered_args @ [(mk (TConst TNull) t_dynamic p)])
324383 else
325384 ordered_args
326385 in
327386 loop args [] given_args missing_args a
328387 | (n,o,t) :: _ , (EConst(Ident "_"),p) :: _ when not ctx.com.config.pf_can_skip_non_nullable_argument && o && not (is_nullable t) ->
329 error "Usage of _ is not supported for optional non-nullable arguments" p
388 typing_error "Usage of _ is not supported for optional non-nullable arguments" p
330389 | (n,o,t) :: args , ([] as params)
331390 | (n,o,t) :: args , (EConst(Ident "_"),_) :: params ->
332391 let v = alloc_var VGenerated (alloc_name n) (if o then ctx.t.tnull t else t) p in
348407 e,var_decls
349408 | TField(_,(FStatic(_,cf) | FInstance(_,_,cf))) when is_immutable_method cf ->
350409 e,var_decls
410 | TField(eobj,FClosure(Some (cl,tp), cf)) when is_immutable_method cf ->
411 (*
412 if we're binding an instance method, we don't really need to create a closure for it,
413 since we'll create a closure for the binding anyway, instead store the instance and
414 call its method inside a bind-generated closure
415 *)
416 let vobj = alloc_var VGenerated "`" eobj.etype eobj.epos in
417 let var_decl = mk (TVar(vobj, Some eobj)) ctx.t.tvoid eobj.epos in
418 let eobj = { eobj with eexpr = TLocal vobj } in
419 { e with eexpr = TField(eobj, FInstance (cl, tp, cf)) }, var_decl :: var_decls
351420 | _ ->
352421 let e_var = alloc_var VGenerated "`" e.etype e.epos in
353422 (mk (TLocal e_var) e.etype e.epos), (mk (TVar(e_var,Some e)) ctx.t.tvoid e.epos) :: var_decls
384453 AKAccess (a,pl,c,e1,e2)
385454 | _ ->
386455 has_abstract_array_access := true;
387 let e = mk_array_get_call ctx (AbstractCast.find_array_access ctx a pl e2 None p) c e1 p in
388 AKExpr e
456 let f = AbstractCast.find_array_read_access ctx a pl e2 p in
457 if not ctx.allow_transform then
458 let _,_,r,_ = f in
459 AKExpr { eexpr = TArray(e1,e2); epos = p; etype = r }
460 else begin
461 let e = mk_array_get_call ctx f c e1 p in
462 AKExpr e
463 end
389464 end
390465 | _ -> raise Not_found)
391466 with Not_found ->
408483 let pt = spawn_monomorph ctx p in
409484 let t = ctx.t.tarray pt in
410485 begin try
411 unify_raise ctx et t p
412 with Error(Unify _,_) ->
486 unify_raise et t p
487 with Error(Unify _,_,_) ->
413488 if not ctx.untyped then begin
414489 let msg = if !has_abstract_array_access then
415490 "No @:arrayAccess function accepts an argument of " ^ (s_type (print_context()) e2.etype)
434509 let rec loop access path = match path with
435510 | [] ->
436511 access
437 | [(name,_,p)] ->
438 let e = acc_get ctx access p in
439 type_field_default_cfg ctx e name p mode with_type
440 | (name,_,p) :: path ->
441 let e = acc_get ctx access p in
442 let access = type_field_default_cfg ctx e name p MGet WithType.value in
512 | part :: path ->
513 let e = acc_get ctx access in
514 let mode, with_type =
515 if path <> [] then
516 (* intermediate field access are just reading the value *)
517 MGet, WithType.value
518 else
519 mode, with_type
520 in
521 let access = type_field_default_cfg ctx e part.name part.pos mode with_type in
443522 loop access path
444523 in
445 loop access path
524 loop access path
1111 (* Used as lhs, no semantic difference to FGet. *)
1212 | FWrite
1313
14 type accessor_resolution =
14 type 'a accessor_resolution =
1515 (* Accessor was found. *)
16 | AccessorFound of field_access
16 | AccessorFound of 'a
1717 (* Accessor was not found, but access was made on anonymous structure. *)
1818 | AccessorAnon
1919 (* Accessor was not found. *)
3535 | FHInstance(c,tl) -> FInstance(c,tl,cf)
3636 | FHAbstract(a,tl,c) -> FStatic(c,cf)
3737 | FHAnon -> FAnon cf
38
39 let get_host c cf =
40 if has_class_field_flag cf CfStatic then
41 FHStatic c
42 else match c.cl_kind with
43 | KAbstractImpl a ->
44 FHAbstract(a,extract_param_types a.a_params,c)
45 | _ ->
46 FHInstance(c,extract_param_types c.cl_params)
47
48 let get_host_class_raise = function
49 | FHStatic c -> c
50 | FHInstance(c,_) -> c
51 | FHAbstract(_,_,c) -> c
52 | FHAnon -> raise Not_found
3853
3954 (* Returns the mapping function to apply type parameters. *)
4055 let get_map_function fa = match fa.fa_host with
7489 in
7590 mk (TField(fa.fa_on,fa')) t fa.fa_pos
7691
77 (* Resolves the accessor on the field access, using the provided `mode`. *)
78 let resolve_accessor fa mode = match fa.fa_field.cf_kind with
92 let find_accessor_for_field host cf t mode = match cf.cf_kind with
7993 | Var v ->
8094 begin match (match mode with MSet _ -> v.v_write | _ -> v.v_read) with
8195 | AccCall ->
82 let name = (match mode with MSet _ -> "set_" | _ -> "get_") ^ fa.fa_field.cf_name in
96 let name = (match mode with MSet _ -> "set_" | _ -> "get_") ^ cf.cf_name in
8397 let forward cf_acc new_host =
84 create fa.fa_on cf_acc new_host fa.fa_inline fa.fa_pos
98 (cf_acc,new_host)
8599 in
86 begin match fa.fa_host with
100 begin match host with
87101 | FHStatic c ->
88102 begin try
89 AccessorFound (forward (PMap.find name c.cl_statics) fa.fa_host)
103 AccessorFound (forward (PMap.find name c.cl_statics) host)
90104 with Not_found ->
91105 (* TODO: Check if this is correct, there's a case in hxcpp's VirtualArray *)
92106 AccessorAnon
94108 | FHInstance(c,tl) ->
95109 begin try
96110 (* Accessors can be overridden, so we have to check the actual type. *)
97 let c,tl = match follow fa.fa_on.etype with
111 let c,tl = match follow t with
98112 | TInst(c,tl) -> c,tl
99113 | _ -> c,tl
100114 in
109123 end
110124 | FHAbstract(a,tl,c) ->
111125 begin try
112 AccessorFound (forward (PMap.find name c.cl_statics) fa.fa_host)
126 AccessorFound (forward (PMap.find name c.cl_statics) host)
113127 with Not_found ->
114128 AccessorAnon
115129 end
121135 end
122136 | _ ->
123137 AccessorInvalid
138
139 (* Resolves the accessor on the field access, using the provided `mode`. *)
140 let resolve_accessor fa mode =
141 let forward cf_acc new_host =
142 create fa.fa_on cf_acc new_host fa.fa_inline fa.fa_pos
143 in
144 match find_accessor_for_field fa.fa_host fa.fa_field fa.fa_on.etype mode with
145 | AccessorFound(cf_acc,new_host) ->
146 AccessorFound (forward cf_acc new_host)
147 | AccessorInvalid ->
148 AccessorInvalid
149 | AccessorAnon ->
150 AccessorAnon
151 | AccessorNotFound ->
152 AccessorNotFound
124153
125154 let get_constructor_access c tl p =
126155 try
138167 in
139168 create e_static cf fh false p
140169 with Not_found ->
141 raise_error (No_constructor (match c.cl_kind with
170 raise_typing_error (No_constructor (match c.cl_kind with
142171 | KAbstractImpl a -> TAbstractDecl a
143172 | _ -> TClassDecl c
144173 )) p
7272 apply_params l monos f.cf_type
7373
7474 let no_abstract_constructor c p =
75 if has_class_flag c CAbstract then raise_error (Abstract_class (TClassDecl c)) p
75 if has_class_flag c CAbstract then raise_typing_error (Abstract_class (TClassDecl c)) p
7676
7777 let check_constructor_access ctx c f p =
78 if (Meta.has Meta.CompilerGenerated f.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p;
79 if not (can_access ctx c f true || extends ctx.curclass c) && not ctx.untyped then display_error ctx (Printf.sprintf "Cannot access private constructor of %s" (s_class_path c)) p
78 if (Meta.has Meta.CompilerGenerated f.cf_meta) then located_display_error ctx.com (error_msg p (No_constructor (TClassDecl c)));
79 if not (can_access ctx c f true || extends ctx.curclass c) && not ctx.untyped then display_error ctx.com (Printf.sprintf "Cannot access private constructor of %s" (s_class_path c)) p
8080
8181 let check_no_closure_meta ctx cf fa mode p =
8282 match mode with
8888 Meta.has Meta.NoClosure cl_meta
8989 || Meta.has Meta.NoClosure f.cf_meta
9090 then
91 error ("Method " ^ f.cf_name ^ " cannot be used as a value") p
91 typing_error ("Method " ^ f.cf_name ^ " cannot be used as a value") p
9292 | _ -> ()
9393 in
9494 begin match cf.cf_kind with
104104 | _ ->
105105 ()
106106
107 (* Note: `p` is the position of the field access expression. *)
108107 let field_access ctx mode f fh e pfield =
109108 let pfull = punion e.epos pfield in
110109 let is_set = match mode with MSet _ -> true | _ -> false in
111110 check_no_closure_meta ctx f fh mode pfield;
112111 let bypass_accessor = if ctx.bypass_accessor > 0 then (ctx.bypass_accessor <- ctx.bypass_accessor - 1; true) else false in
113 let make_access inline = FieldAccess.create e f fh inline pfull in
112 let make_access inline = FieldAccess.create e f fh (inline && ctx.allow_inline) pfull in
114113 match f.cf_kind with
115114 | Method m ->
116115 let normal () = AKField(make_access false) in
117 if is_set && m <> MethDynamic && not ctx.untyped then error "Cannot rebind this method : please use 'dynamic' before method declaration" pfield;
116 if is_set && m <> MethDynamic && not ctx.untyped then typing_error "Cannot rebind this method : please use 'dynamic' before method declaration" pfield;
118117 let maybe_check_visibility c static =
119118 (* For overloads we have to resolve the actual field before we can check accessibility. *)
120119 begin match mode with
126125 in
127126 let default () =
128127 match m, mode with
129 | MethInline, _ when ctx.g.doinline ->
128 | MethInline, _ when ctx.g.doinline && ctx.allow_inline ->
130129 AKField (make_access true)
131130 | MethMacro, MGet ->
132 display_error ctx "Macro functions must be called immediately" pfield; normal()
131 display_error ctx.com "Macro functions must be called immediately" pfield; normal()
133132 | _ , MGet ->
134 if has_class_field_flag f CfGeneric then display_error ctx "Cannot create closure on generic function" pfield;
133 if has_class_field_flag f CfGeneric then display_error ctx.com "Cannot create closure on generic function" pfield;
135134 normal()
136135 | _ ->
137136 normal()
138137 in
139138 begin match fh with
140139 | FHInstance(c,tl) ->
141 if e.eexpr = TConst TSuper then (match mode,f.cf_kind with
142 | MGet,Var {v_read = AccCall }
143 | MSet _,Var {v_write = AccCall }
144 | MCall _,Var {v_read = AccCall } ->
140 if e.eexpr = TConst TSuper then begin match mode with
141 | MSet _ | MGet ->
142 display_error ctx.com "Cannot create closure on super method" pfield
143 | MCall _ ->
145144 ()
146 | MCall _, Var _ ->
147 display_error ctx "Cannot access superclass variable for calling: needs to be a proper method" pfield
148 | MCall _, _ ->
149 ()
150 | MGet,Var _
151 | MSet _,Var _ when ctx.com.platform = Flash && has_class_flag c CExtern ->
152 ()
153 | _, Method _ ->
154 display_error ctx "Cannot create closure on super method" pfield
155 | _ ->
156 display_error ctx "Normal variables cannot be accessed with 'super', use 'this' instead" pfield);
145 end;
157146 (* We need the actual class type (i.e. a potential child class) for visibility checks. *)
158147 begin match follow e.etype with
159148 | TInst(c,_) ->
183172 | _ ->
184173 ()
185174 end;
175 if e.eexpr = TConst TSuper then begin match mode with
176 | MGet | MCall _ when v.v_read = AccCall ->
177 ()
178 | MSet _ when v.v_write = AccCall ->
179 ()
180 | _ ->
181 display_error ctx.com "Normal variables cannot be accessed with 'super', use 'this' instead" pfield;
182 end;
186183 | FHAnon ->
187184 ()
188185 end;
189186 let normal inline =
190187 AKField (make_access inline)
188 in
189 let normal_failure ()=
190 AKNo((normal false),pfield)
191191 in
192192 match (match mode with MGet | MCall _ -> v.v_read | MSet _ -> v.v_write) with
193193 | AccNo when not (Meta.has Meta.PrivateAccess ctx.meta) ->
197197 | TAnon a ->
198198 (match !(a.a_status) with
199199 | Statics c2 when ctx.curclass == c2 || can_access ctx c2 { f with cf_flags = unset_flag f.cf_flags (int_of_class_field_flag CfPublic) } true -> normal false
200 | _ -> if ctx.untyped then normal false else AKNo f.cf_name)
200 | _ -> if ctx.untyped then normal false else normal_failure())
201201 | _ ->
202 if ctx.untyped then normal false else AKNo f.cf_name)
202 if ctx.untyped then normal false else normal_failure())
203203 | AccNormal | AccNo ->
204204 normal false
205 | AccCall when ctx.in_display && DisplayPosition.display_position#enclosed_in pfull ->
205 | AccCall when (not ctx.allow_transform) || (ctx.in_display && DisplayPosition.display_position#enclosed_in pfull) ->
206206 normal false
207207 | AccCall ->
208208 let m = (match mode with MSet _ -> "set_" | _ -> "get_") ^ f.cf_name in
220220 )
221221 in
222222 if bypass_accessor then (
223 (match e.eexpr with TLocal _ when Common.defined ctx.com Define.Haxe3Compat -> ctx.com.warning "Field set has changed here in Haxe 4: call setter explicitly to keep Haxe 3.x behaviour" pfield | _ -> ());
223 (match e.eexpr with TLocal _ when Common.defined ctx.com Define.Haxe3Compat -> warning ctx WTemp "Field set has changed here in Haxe 4: call setter explicitly to keep Haxe 3.x behaviour" pfield | _ -> ());
224224 if not (is_physical_field f) then begin
225 display_error ctx "This field cannot be accessed because it is not a real variable" pfield;
226 display_error ctx "Add @:isVar here to enable it" f.cf_pos;
225 display_error ctx.com "This field cannot be accessed because it is not a real variable" pfield;
226 display_error ctx.com "Add @:isVar here to enable it" f.cf_pos;
227227 end;
228228 normal false
229229 )
235235 AKAccessor (make_access false)
236236 end
237237 | AccNever ->
238 if ctx.untyped then normal false else AKNo f.cf_name
238 if ctx.untyped then normal false else normal_failure()
239239 | AccInline ->
240240 normal true
241241 | AccCtor ->
242 let is_child_of_abstract c =
243 has_class_flag c CAbstract && extends ctx.curclass c
244 in
242245 (match ctx.curfun, fh with
243 | FunConstructor, FHInstance(c,_) when c == ctx.curclass -> normal false
244 | _ -> AKNo f.cf_name
246 | FunConstructor, FHInstance(c,_) when c == ctx.curclass || is_child_of_abstract c -> normal false
247 | _ -> normal_failure()
245248 )
246249 | AccRequire (r,msg) ->
247250 match msg with
248251 | None -> error_require r pfield
249 | Some msg -> error msg pfield
252 | Some msg -> typing_error msg pfield
250253
251254 let class_field ctx c tl name p =
252255 raw_class_field (fun f -> field_type ctx c tl f p) c tl name
281284 let _,el,_ = Meta.get meta a.a_meta in
282285 if el <> [] && not (List.exists (fun e -> match fst e with
283286 | EConst (Ident i' | String (i',_)) -> i' = i
284 | _ -> error "Identifier or string expected as argument to @:forward" (pos e)
287 | _ -> typing_error "Identifier or string expected as argument to @:forward" (pos e)
285288 ) el) then raise Not_found;
286289 f()
287290 in
293296 type_field_by_forward f Meta.Forward a
294297 in
295298 let type_field_by_typedef f e td tl =
296 f e (follow_without_type (apply_params td.t_params tl td.t_type))
299 f e (follow_without_type (apply_typedef td tl))
297300 in
298301 let type_field_by_interfaces e c =
299302 (* For extern lib types we didn't go through check_interfaces and check_abstract_class, which handles some field
327330 | TAnon a ->
328331 (try
329332 let f = PMap.find i a.a_fields in
330 if has_class_field_flag f CfImpl && not (has_class_field_flag f CfEnum) then display_error ctx "Cannot access non-static abstract field statically" pfield;
333 if has_class_field_flag f CfImpl && not (has_class_field_flag f CfEnum) then display_error ctx.com "Cannot access non-static abstract field statically" pfield;
331334 match !(a.a_status) with
332335 | EnumStatics en ->
333336 let c = try PMap.find f.cf_name en.e_constrs with Not_found -> die "" __LOC__ in
434437 end
435438 | _ ->
436439 check()
437 with Unify_error el | Error (Unify el,_) ->
440 with Unify_error el | Error (Unify el,_,_) ->
438441 check_constant_struct := !check_constant_struct || List.exists (function
439442 | Has_extra_field _ -> true
440443 | _ -> false
511514 in
512515 loop c tl
513516 with Not_found when PMap.mem i c.cl_statics ->
514 error ("Cannot access static field " ^ i ^ " from a class instance") pfield;
517 typing_error ("Cannot access static field " ^ i ^ " from a class instance") pfield;
515518 )
516519 | TDynamic t ->
517 AKExpr (mk (TField (e,FDynamic i)) t p)
520 AKExpr (mk (TField (e,FDynamic i)) (match t with None -> t_dynamic | Some t -> t) p)
518521 | TAbstract (a,tl) ->
519522 (try
520523 if not (TypeFieldConfig.allow_resolve cfg) then raise Not_found;
525528 with Not_found -> try
526529 type_field_by_forward_member type_field_by_fallback e a tl
527530 with Not_found when not (has_class_field_flag (PMap.find i (find_some a.a_impl).cl_statics) CfImpl) ->
528 error ("Invalid call to static function " ^ i ^ " through abstract instance") pfield
531 typing_error ("Invalid call to static function " ^ i ^ " through abstract instance") pfield
529532 )
530533 | _ -> raise Not_found
531534 in
550553 | TInst ({ cl_kind = KAbstractImpl a },_)
551554 | TAbstract (a,_) when has_special_field a ->
552555 (* the abstract field is not part of the field list, which is only true when it has no expression (issue #2344) *)
553 display_error ctx ("Field " ^ i ^ " cannot be called directly because it has no expression") pfield;
556 display_error ctx.com ("Field " ^ i ^ " cannot be called directly because it has no expression") pfield;
554557 | TAnon { a_status = { contents = Statics c } } when PMap.mem i c.cl_fields ->
555 display_error ctx ("Static access to instance field " ^ i ^ " is not allowed") pfield;
558 display_error ctx.com ("Static access to instance field " ^ i ^ " is not allowed") pfield;
556559 | _ ->
557560 let tthis = e.etype in
558561 try
559 if not (Diagnostics.is_diagnostics_run ctx.com pfield) then raise Exit;
562 if not (Diagnostics.error_in_diagnostics_run ctx.com pfield) then raise Exit;
560563 DisplayFields.handle_missing_field_raise ctx tthis i mode with_type pfield
561564 with Exit ->
562 display_error ctx (StringError.string_error i (string_source tthis) (s_type (print_context()) tthis ^ " has no field " ^ i)) pfield
565 display_error ctx.com (StringError.string_error i (string_source tthis) (s_type (print_context()) tthis ^ " has no field " ^ i)) pfield
563566 end;
564567 AKExpr (mk (TField (e,FDynamic i)) (spawn_monomorph ctx p) p)
565568
625628 PMap.add cf.cf_name cf fields
626629 | _ ->
627630 fields
628 ) c.cl_fields PMap.empty
631 ) c.cl_fields PMap.empty
2222 | None ->
2323 raise Not_found
2424 | Some c ->
25 p := c.cl_pos;
25 p := c.cl_name_pos;
2626 c, PMap.find "main" c.cl_statics
2727 with Not_found -> try
2828 let t = Typeload.find_type_in_module_raise ctx m name null_pos in
2929 match t with
3030 | TEnumDecl _ | TTypeDecl _ | TAbstractDecl _ ->
31 error ("Invalid -main : " ^ s_type_path path ^ " is not a class") null_pos
31 typing_error ("Invalid -main : " ^ s_type_path path ^ " is not a class") null_pos
3232 | TClassDecl c ->
33 p := c.cl_pos;
33 p := c.cl_name_pos;
3434 c, PMap.find "main" c.cl_statics
3535 with Not_found ->
36 error ("Invalid -main : " ^ s_type_path path ^ " does not have static function main") !p
36 typing_error ("Invalid -main : " ^ s_type_path path ^ " does not have static function main") !p
3737 in
3838 let ft = Type.field_type f in
3939 let fmode, r =
4040 match follow ft with
4141 | TFun ([],r) -> FStatic (c,f), r
42 | _ -> error ("Invalid -main : " ^ s_type_path path ^ " has invalid main function") c.cl_pos
43 in
44 if not (ExtType.is_void (follow r)) then error (Printf.sprintf "Return type of main function should be Void (found %s)" (s_type (print_context()) r)) f.cf_name_pos;
42 | _ -> typing_error ("Invalid -main : " ^ s_type_path path ^ " has invalid main function") c.cl_pos
43 in
44 if not (ExtType.is_void (follow r)) then typing_error (Printf.sprintf "Return type of main function should be Void (found %s)" (s_type (print_context()) r)) f.cf_name_pos;
4545 f.cf_meta <- (Dce.mk_keep_meta f.cf_pos) :: f.cf_meta;
4646 let emain = type_module_type ctx (TClassDecl c) None null_pos in
4747 let main = mk (TCall (mk (TField (emain,fmode)) ft null_pos,[])) r null_pos in
8585 ()
8686 | fl ->
8787 let rec loop handled_types =
88 let all_types = Hashtbl.fold (fun _ m acc -> m.m_types @ acc) ctx.g.modules [] in
88 let all_types = ctx.com.module_lut#fold (fun _ m acc -> m.m_types @ acc) [] in
8989 match (List.filter (fun mt -> not (List.memq mt handled_types)) all_types) with
9090 | [] ->
9191 ()
101101 | Done
102102 | NotYet
103103
104 let sort_types com modules =
104 let sort_types com (modules : (path,module_def) lookup) =
105105 let types = ref [] in
106106 let states = Hashtbl.create 0 in
107107 let state p = try Hashtbl.find states p with Not_found -> NotYet in
112112 match state p with
113113 | Done -> ()
114114 | Generating ->
115 com.warning ("Warning : maybe loop in static generation of " ^ s_type_path p) (t_infos t).mt_pos;
115 com.warning WStaticInitOrder [] ("Warning : maybe loop in static generation of " ^ s_type_path p) (t_infos t).mt_pos;
116116 | NotYet ->
117117 Hashtbl.add states p Generating;
118118 let t = (match t with
192192 ) c.cl_statics
193193
194194 in
195 let sorted_modules = List.sort (fun m1 m2 -> compare m1.m_path m2.m_path) (Hashtbl.fold (fun _ m acc -> m :: acc) modules []) in
195 let sorted_modules = List.sort (fun m1 m2 -> compare m1.m_path m2.m_path) (modules#fold (fun _ m acc -> m :: acc) []) in
196196 List.iter (fun m -> List.iter loop m.m_types) sorted_modules;
197197 List.rev !types, sorted_modules
198198
199199 let generate ctx =
200 let types,modules = sort_types ctx.com ctx.g.modules in
200 let types,modules = sort_types ctx.com ctx.com.module_lut in
201201 get_main ctx types,types,modules
9191 | TDynamic _ | TMono _ ->
9292 (* try to find something better than a dynamic value to iterate on *)
9393 dynamic_iterator := Some e;
94 raise (Error (Unify [Unify_custom "Avoid iterating on a dynamic value"], p))
94 raise (Error (Unify [Unify_custom "Avoid iterating on a dynamic value"], p, 0))
9595 | _ -> e
96 with Error (Unify _,_) ->
96 with Error (Unify _,_,depth) ->
9797 let try_last_resort after =
9898 try
9999 match last_resort with
105105 let try_acc acc =
106106 let acc_expr = build_call ctx acc [] WithType.value e.epos in
107107 try
108 unify_raise ctx acc_expr.etype t acc_expr.epos;
108 unify_raise acc_expr.etype t acc_expr.epos;
109109 acc_expr
110 with Error (Unify(l),p) ->
110 with Error (Unify(l),p,n) ->
111111 try_last_resort (fun () ->
112112 match !dynamic_iterator with
113113 | Some e -> e
114114 | None ->
115115 if resume then raise Not_found;
116 display_error ctx "Field iterator has an invalid type" acc_expr.epos;
117 display_error ctx (error_msg (Unify l)) p;
116 display_error ~depth ctx.com "Field iterator has an invalid type" acc_expr.epos;
117 located_display_error ~depth:(depth+1) ctx.com (error_msg p (Unify l));
118118 mk (TConst TNull) t_dynamic p
119119 )
120120 in
153153 (try
154154 (* first try: do we have an @:arrayAccess getter field? *)
155155 let todo = mk (TConst TNull) ctx.t.tint p in
156 let cf,_,r,_,_ = AbstractCast.find_array_access_raise ctx a tl todo None p in
156 let cf,_,r,_ = AbstractCast.find_array_read_access_raise ctx a tl todo p in
157157 let get_next e_base e_index t p =
158158 make_static_call ctx c cf (apply_params a.a_params tl) [e_base;e_index] r p
159159 in
171171
172172 let of_texpr ?(resume=false) ctx e unroll p =
173173 let dynamic_iterator e =
174 display_error ctx "You can't iterate on a Dynamic value, please specify Iterator or Iterable" e.epos;
174 display_error ctx.com "You can't iterate on a Dynamic value, please specify Iterator or Iterable" e.epos;
175175 IteratorDynamic,e,t_dynamic
176176 in
177177 let check_iterator () =
259259 {
260260 it_kind = it;
261261 it_type = pt;
262 it_expr = e1;
262 it_expr = if not ctx.allow_transform then e else e1;
263263 }
264264
265265 let to_texpr ctx v iterator e2 p =
279279 | TBinop (OpAssignOp _,{ eexpr = TLocal l },_)
280280 | TUnop (Increment,_,{ eexpr = TLocal l })
281281 | TUnop (Decrement,_,{ eexpr = TLocal l }) when List.memq l vl ->
282 error "Loop variable cannot be modified" e.epos
282 typing_error "Loop variable cannot be modified" e.epos
283283 | _ ->
284284 Type.iter loop e
285285 in
314314 mk (TBlock el) t_void p
315315 in
316316 match iterator.it_kind with
317 | _ when not ctx.allow_transform ->
318 mk (TFor(v,e1,e2)) t_void p
317319 | IteratorIntUnroll(offset,length,ascending) ->
318320 check_loop_var_modification [v] e2;
319 if not ascending then error "Cannot iterate backwards" p;
321 if not ascending then typing_error "Cannot iterate backwards" p;
320322 let el = ExtList.List.init length (fun i ->
321323 let ei = make_int ctx.t (if ascending then i + offset else offset - i) p in
322324 let rec loop e = match e.eexpr with
329331 mk (TBlock el) t_void p
330332 | IteratorIntConst(a,b,ascending) ->
331333 check_loop_var_modification [v] e2;
332 if not ascending then error "Cannot iterate backwards" p;
334 if not ascending then typing_error "Cannot iterate backwards" p;
333335 let v_index = gen_local ctx t_int a.epos in
334336 let evar_index = mk (TVar(v_index,Some a)) t_void a.epos in
335337 let ev_index = make_local v_index v_index.v_pos in
459461 let rec loop_ident dko e1 = match e1 with
460462 | EConst(Ident i),p -> i,p,dko
461463 | EDisplay(e1,dk),_ -> loop_ident (Some dk) e1
462 | _ -> error "Identifier expected" (pos e1)
464 | _ -> typing_error "Identifier expected" (pos e1)
463465 in
464466 let rec loop dko e1 = match fst e1 with
465467 | EBinop(OpIn,e1,e2) ->
474476 | Some dk -> ignore(handle_display ctx e1 dk MGet WithType.value);
475477 | None -> ()
476478 end;
477 error "For expression should be 'v in expr'" (snd it)
479 typing_error "For expression should be 'v in expr'" (snd it)
478480 in
479481 let ik,e1 = loop None it in
480482 let e1 = type_expr ctx e1 WithType.value in
502504 | IKKeyValue((ikey,pkey,dkokey),(ivalue,pvalue,dkovalue)) ->
503505 (match follow e1.etype with
504506 | TDynamic _ | TMono _ ->
505 display_error ctx "You can't iterate on a Dynamic value, please specify KeyValueIterator or KeyValueIterable" e1.epos;
507 display_error ctx.com "You can't iterate on a Dynamic value, please specify KeyValueIterator or KeyValueIterable" e1.epos;
506508 | _ -> ()
507509 );
508510 let e1,pt = IterationKind.check_iterator ctx "keyValueIterator" e1 e1.epos in
512514 let enext = build_call ctx (type_field_default_cfg ctx etmp "next" etmp.epos (MCall []) WithType.value (* WITHTYPETODO *)) [] WithType.value etmp.epos in
513515 let v = gen_local ctx pt e1.epos in
514516 let ev = make_local v v.v_pos in
515 let ekey = Calls.acc_get ctx (type_field_default_cfg ctx ev "key" ev.epos MGet WithType.value) ev.epos in
516 let evalue = Calls.acc_get ctx (type_field_default_cfg ctx ev "value" ev.epos MGet WithType.value) ev.epos in
517 let ekey = Calls.acc_get ctx (type_field_default_cfg ctx ev "key" ev.epos MGet WithType.value) in
518 let evalue = Calls.acc_get ctx (type_field_default_cfg ctx ev "value" ev.epos MGet WithType.value) in
517519 let vkey = add_local_with_origin ctx TVOForVariable ikey ekey.etype pkey in
518520 let vvalue = add_local_with_origin ctx TVOForVariable ivalue evalue.etype pvalue in
519521 let e2 = type_expr ctx e2 NoValue in
22 open Type
33 open Typecore
44 open Error
5
6 let type_opt ctx is_core_api is_abstract_method p t =
7 let c = ctx.curclass in
8 match t with
9 | None when (has_class_flag c CExtern) || (has_class_flag c CInterface) ->
10 display_error ctx "Type required for extern classes and interfaces" p;
11 t_dynamic
12 | None when is_core_api ->
13 display_error ctx "Type required for core api classes" p;
14 t_dynamic
15 | None when is_abstract_method ->
16 display_error ctx "Type required for abstract functions" p;
17 t_dynamic
18 | _ ->
19 Typeload.load_type_hint ctx p t
205
216 let type_function_arg ctx t e opt p =
227 (* TODO https://github.com/HaxeFoundation/haxe/issues/8461 *)
3722 | Some e ->
3823 let p = pos e in
3924 let e = if do_display then Display.ExprPreprocessing.process_expr ctx.com e else e in
40 let e = ctx.g.do_optimize ctx (type_expr ctx e (WithType.with_type t)) in
25 let e = Optimizer.reduce_expression ctx (type_expr ctx e (WithType.with_type t)) in
4126 unify ctx e.etype t p;
4227 let rec loop e = match e.eexpr with
4328 | TConst _ -> Some e
4530 | TField({eexpr = TTypeExpr _},FStatic({cl_kind = KAbstractImpl a},cf)) when a.a_enum && has_class_field_flag cf CfEnum -> Some e
4631 | TCast(e,None) -> loop e
4732 | _ ->
48 if ctx.com.display.dms_kind = DMNone || ctx.com.display.dms_inline && ctx.com.display.dms_error_policy = EPCollect then
49 display_error ctx "Parameter default value should be constant" p;
33 if ctx.com.display.dms_kind = DMNone || Common.is_diagnostics ctx.com then
34 Common.display_error ctx.com "Default argument value should be constant" p;
5035 None
5136 in
5237 loop e
5338
5439 class function_arguments
5540 (ctx : typer)
56 (type_arg : bool -> type_hint option -> pos -> Type.t)
41 (type_arg : int -> bool -> type_hint option -> pos -> Type.t)
5742 (is_extern : bool)
5843 (do_display : bool)
5944 (abstract_this : Type.t option)
6045 (syntax : (placed_name * bool * metadata * type_hint option * expr option) list)
6146 =
6247 let with_default =
63 let l = List.map (fun ((name,pn),opt,m,t,eo) ->
64 let t = type_arg opt t pn in
48 let l = List.mapi (fun i ((name,pn),opt,_,t,eo) ->
49 let t = type_arg i opt t pn in
6550 let t,eo = type_function_arg ctx t eo opt pn in
6651 (name,eo,t)
6752 ) syntax in
9075
9176 method private check_rest (is_last : bool) (eo : expr option) (opt : bool) (t : Type.t) (pn : pos) =
9277 if ExtType.is_rest (follow t) then begin
93 if opt then error "Rest argument cannot be optional" pn;
94 begin match eo with None -> () | Some (_,p) -> error "Rest argument cannot have default value" p end;
95 if not is_last then error "Rest should only be used for the last function argument" pn;
78 if opt then typing_error "Rest argument cannot be optional" pn;
79 begin match eo with None -> () | Some (_,p) -> typing_error "Rest argument cannot have default value" p end;
80 if not is_last then typing_error "Rest should only be used for the last function argument" pn;
9681 end
9782
9883 (* Returns the `(tvar * texpr option) list` for `tf_args`. Also checks the validity of argument names and whether or not
10186 | Some l ->
10287 l
10388 | None ->
104 let make_local name t meta pn =
105 let v = alloc_var (VUser TVOArgument) name t pn in
89 let make_local name kind t meta pn =
90 let v = alloc_var kind name t pn in
10691 v.v_meta <- v.v_meta @ meta;
10792 v
10893 in
10994 let rec loop acc is_abstract_this syntax typed = match syntax,typed with
11095 | syntax,(name,_,t) :: typed when is_abstract_this ->
111 let v = make_local name t [] null_pos in
96 let v = make_local name VAbstractThis t [] null_pos in
11297 v.v_meta <- (Meta.This,[],null_pos) :: v.v_meta;
11398 loop ((v,None) :: acc) false syntax typed
11499 | ((_,pn),opt,m,_,_) :: syntax,(name,eo,t) :: typed ->
115100 delay ctx PTypeField (fun() -> self#check_rest (typed = []) eo opt t pn);
116101 if not is_extern then check_local_variable_name ctx name TVOArgument pn;
117102 let eo = type_function_arg_value ctx t eo do_display in
118 let v = make_local name t m pn in
103 let v = make_local name (VUser TVOArgument) t m pn in
119104 if do_display && DisplayPosition.display_position#enclosed_in pn then
120105 DisplayEmitter.display_variable ctx v pn;
121106 loop ((v,eo) :: acc) false syntax typed
149134 List.iter (fun (v,_) ->
150135 ctx.locals <- PMap.add v.v_name v ctx.locals
151136 ) self#for_expr
152 end
137 end
2626 let rec loop l1 l2 =
2727 match l1, l2 with
2828 | [] , [] -> []
29 | (x,TLazy f) :: l1, _ -> loop ((x,lazy_type f) :: l1) l2
30 | (_,t1) :: l1 , t2 :: l2 ->
29 | ({ttp_type=TLazy f} as tp) :: l1, _ -> loop ({tp with ttp_type=lazy_type f} :: l1) l2
30 | tp1 :: l1 , t2 :: l2 ->
3131 let t,eo = generic_check_const_expr ctx t2 in
32 (t1,(t,eo)) :: loop l1 l2
32 (tp1.ttp_type,(t,eo)) :: loop l1 l2
3333 | _ -> die "" __LOC__
3434 in
3535 let name =
36 String.concat "_" (List.map2 (fun (s,_) t ->
36 String.concat "_" (List.map2 (fun {ttp_name=s} t ->
3737 let rec subst s = "_" ^ string_of_int (Char.code (String.get (Str.matched_string s) 0)) ^ "_" in
3838 let ident_safe = Str.global_substitute (Str.regexp "[^a-zA-Z0-9_]") subst in
3939 let s_type_path_underscore (p,s) = match p with [] -> s | _ -> String.concat "_" p ^ "_" ^ s in
110110 let fa = try
111111 quick_field t cf.cf_name
112112 with Not_found ->
113 error (Printf.sprintf "Type %s has no field %s (possible typing order issue)" (s_type (print_context()) t) cf.cf_name) e.epos
113 typing_error (Printf.sprintf "Type %s has no field %s (possible typing order issue)" (s_type (print_context()) t) cf.cf_name) e.epos
114114 in
115115 build_expr {e with eexpr = TField(e1,fa)}
116116 end;
127127 let eo = loop gctx.subst in
128128 begin match eo with
129129 | Some e -> e
130 | None -> error "Only Const type parameters can be used as value" e.epos
130 | None -> typing_error "Only Const type parameters can be used as value" e.epos
131131 end
132132 with Not_found ->
133133 e
154154 let t = Typeload.load_instance ctx (mk_type_path (pack,name),p) true in
155155 match t with
156156 | TInst(cg,_) -> cg
157 | _ -> error ("Cannot specialize @:generic static method because the generated type name is already used: " ^ name) p
158 with Error(Module_not_found path,_) when path = (pack,name) ->
159 let m = (try Hashtbl.find ctx.g.modules (Hashtbl.find ctx.g.types_module c.cl_path) with Not_found -> die "" __LOC__) in
157 | _ -> typing_error ("Cannot specialize @:generic static method because the generated type name is already used: " ^ name) p
158 with Error(Module_not_found path,_,_) when path = (pack,name) ->
159 let m = (try ctx.com.module_lut#find (ctx.com.type_to_module#find c.cl_path) with Not_found -> die "" __LOC__) in
160160 let mg = {
161161 m_id = alloc_mid();
162162 m_path = (pack,name);
167167 gctx.mg <- Some mg;
168168 let cg = mk_class mg (pack,name) c.cl_pos c.cl_name_pos in
169169 mg.m_types <- [TClassDecl cg];
170 Hashtbl.add ctx.g.modules mg.m_path mg;
170 ctx.com.module_lut#add mg.m_path mg;
171171 add_dependency mg m;
172172 add_dependency ctx.m.curmod mg;
173173 cg
174174
175 let rec build_generic ctx c p tl =
175 let set_type_parameter_dependencies mg tl =
176 (* ensure that type parameters are set in dependencies *)
177 let dep_stack = ref [] in
178 let rec loop t =
179 if not (List.memq t !dep_stack) then begin
180 dep_stack := t :: !dep_stack;
181 match t with
182 | TInst (c,tl) -> add_dep c.cl_module tl
183 | TEnum (e,tl) -> add_dep e.e_module tl
184 | TType (t,tl) -> add_dep t.t_module tl
185 | TAbstract (a,tl) -> add_dep a.a_module tl
186 | TMono r ->
187 (match r.tm_type with
188 | None -> ()
189 | Some t -> loop t)
190 | TLazy f ->
191 loop (lazy_type f);
192 | TDynamic None ->
193 ()
194 | TDynamic (Some t2) ->
195 loop t2
196 | TAnon a ->
197 PMap.iter (fun _ f -> loop f.cf_type) a.a_fields
198 | TFun (args,ret) ->
199 List.iter (fun (_,_,t) -> loop t) args;
200 loop ret
201 end
202 and add_dep m tl =
203 add_dependency mg m;
204 List.iter loop tl
205 in
206 List.iter loop tl
207
208 let rec build_generic_class ctx c p tl =
176209 let pack = fst c.cl_path in
177210 let recurse = ref false in
178211 let rec check_recursive t =
181214 (match c2.cl_kind with
182215 | KTypeParameter tl ->
183216 if not (TypeloadCheck.is_generic_parameter ctx c2) && has_ctor_constraint c2 then
184 error "Type parameters with a constructor cannot be used non-generically" p;
217 typing_error "Type parameters with a constructor cannot be used non-generically" p;
185218 recurse := true
186219 | _ -> ());
187220 List.iter check_recursive tl;
198231 let t = Typeload.load_instance ctx (mk_type_path (pack,name),p) false in
199232 match t with
200233 | TInst({ cl_kind = KGenericInstance (csup,_) },_) when c == csup -> t
201 | _ -> error ("Cannot specialize @:generic because the generated type name is already used: " ^ name) p
202 with Error(Module_not_found path,_) when path = (pack,name) ->
203 let m = (try Hashtbl.find ctx.g.modules (Hashtbl.find ctx.g.types_module c.cl_path) with Not_found -> die "" __LOC__) in
204 (* let ctx = { ctx with m = { ctx.m with module_types = m.m_types @ ctx.m.module_types } } in *)
234 | _ -> typing_error ("Cannot specialize @:generic because the generated type name is already used: " ^ name) p
235 with Error(Module_not_found path,_,_) when path = (pack,name) ->
236 let m = (try ctx.com.module_lut#find (ctx.com.type_to_module#find c.cl_path) with Not_found -> die "" __LOC__) in
205237 ignore(c.cl_build()); (* make sure the super class is already setup *)
206238 let mg = {
207239 m_id = alloc_mid();
212244 } in
213245 gctx.mg <- Some mg;
214246 let cg = mk_class mg (pack,name) c.cl_pos c.cl_name_pos in
247 cg.cl_meta <- List.filter (fun (m,_,_) -> match m with
248 | Meta.Access | Allow
249 | Final
250 | Hack
251 | Internal
252 | Keep
253 | NoClosure | NullSafety
254 | Pure
255 | Struct | StructInit
256 | Using ->
257 true
258 | _ ->
259 false
260 ) c.cl_meta;
261 cg.cl_meta <- (Meta.NoDoc,[],null_pos) :: cg.cl_meta;
215262 mg.m_types <- [TClassDecl cg];
216 Hashtbl.add ctx.g.modules mg.m_path mg;
263 ctx.com.module_lut#add mg.m_path mg;
217264 add_dependency mg m;
218265 add_dependency ctx.m.curmod mg;
219 (* ensure that type parameters are set in dependencies *)
220 let dep_stack = ref [] in
221 let rec loop t =
222 if not (List.memq t !dep_stack) then begin
223 dep_stack := t :: !dep_stack;
224 match t with
225 | TInst (c,tl) -> add_dep c.cl_module tl
226 | TEnum (e,tl) -> add_dep e.e_module tl
227 | TType (t,tl) -> add_dep t.t_module tl
228 | TAbstract (a,tl) -> add_dep a.a_module tl
229 | TMono r ->
230 (match r.tm_type with
231 | None -> ()
232 | Some t -> loop t)
233 | TLazy f ->
234 loop (lazy_type f);
235 | TDynamic t2 ->
236 if t == t2 then () else loop t2
237 | TAnon a ->
238 PMap.iter (fun _ f -> loop f.cf_type) a.a_fields
239 | TFun (args,ret) ->
240 List.iter (fun (_,_,t) -> loop t) args;
241 loop ret
242 end
243 and add_dep m tl =
244 add_dependency mg m;
245 List.iter loop tl
246 in
247 List.iter loop tl;
266 set_type_parameter_dependencies mg tl;
248267 let build_field cf_old =
249268 (* We have to clone the type parameters (issue #4672). We cannot substitute the constraints immediately because
250269 we need the full substitution list first. *)
251 let param_subst,params = List.fold_left (fun (subst,params) (s,t) -> match follow t with
270 let param_subst,params = List.fold_left (fun (subst,params) tp -> match follow tp.ttp_type with
252271 | TInst(c,tl) as t ->
253272 let t2 = TInst({c with cl_module = mg;},tl) in
254 (t,(t2,None)) :: subst,(s,t2) :: params
273 (t,(t2,None)) :: subst,({tp with ttp_type=t2}) :: params
255274 | _ -> die "" __LOC__
256275 ) ([],[]) cf_old.cf_params in
257276 let gctx = {gctx with subst = param_subst @ gctx.subst} in
258277 let cf_new = {cf_old with cf_pos = cf_old.cf_pos} in (* copy *)
278 remove_class_field_flag cf_new CfPostProcessed;
259279 (* Type parameter constraints are substituted here. *)
260 cf_new.cf_params <- List.rev_map (fun (s,t) -> match follow t with
280 cf_new.cf_params <- List.rev_map (fun tp -> match follow tp.ttp_type with
261281 | TInst({cl_kind = KTypeParameter tl1} as c,_) ->
262282 let tl1 = List.map (generic_substitute_type gctx) tl1 in
263283 c.cl_kind <- KTypeParameter tl1;
264 s,t
284 tp (* TPTODO: weird mapping *)
265285 | _ -> die "" __LOC__
266286 ) params;
267287 let f () =
270290 begin try (match cf_old.cf_expr with
271291 | None ->
272292 begin match cf_old.cf_kind with
273 | Method _ when not (has_class_flag c CInterface) && not (has_class_flag c CExtern) ->
274 display_error ctx (Printf.sprintf "Field %s has no expression (possible typing order issue)" cf_new.cf_name) cf_new.cf_pos;
275 display_error ctx (Printf.sprintf "While building %s" (s_type_path cg.cl_path)) p;
293 | Method _ when not (has_class_flag c CInterface) && not (has_class_flag c CExtern) && not (has_class_field_flag cf_old CfAbstract) ->
294 display_error ctx.com (Printf.sprintf "Field %s has no expression (possible typing order issue)" cf_new.cf_name) cf_new.cf_pos;
295 display_error ctx.com (Printf.sprintf "While building %s" (s_type_path cg.cl_path)) p;
276296 | _ ->
277297 ()
278298 end
279299 | Some e ->
280300 cf_new.cf_expr <- Some (generic_substitute_expr gctx e)
281301 ) with Unify_error l ->
282 error (error_msg (Unify l)) cf_new.cf_pos
302 located_typing_error (error_msg cf_new.cf_pos (Unify l))
283303 end;
284304 t
285305 in
287307 let t = spawn_monomorph ctx p in
288308 r := lazy_processing (fun() -> t);
289309 let t0 = f() in
290 unify_raise ctx t0 t p;
310 unify_raise t0 t p;
291311 link_dynamic t0 t;
292312 t
293 ) "build_generic" in
313 ) "build_generic_class" in
294314 cf_new.cf_type <- TLazy r;
295315 cf_new
296316 in
297 if c.cl_init <> None then error "This class can't be generic" p;
317 if c.cl_init <> None then typing_error "This class can't be generic" p;
298318 List.iter (fun cf -> match cf.cf_kind with
299 | Method MethMacro when not ctx.in_macro -> ()
300 | _ -> error "A generic class can't have static fields" cf.cf_pos
319 | Method MethMacro when not ctx.com.is_macro_context -> ()
320 | _ -> typing_error "A generic class can't have static fields" cf.cf_pos
301321 ) c.cl_ordered_statics;
302322 cg.cl_super <- (match c.cl_super with
303323 | None -> None
306326 let cs,pl = TypeloadCheck.Inheritance.check_extends ctx c ts p in
307327 match cs.cl_kind with
308328 | KGeneric ->
309 (match build_generic ctx cs p pl with
329 (match build_generic_class ctx cs p pl with
310330 | TInst (cs,pl) -> Some (cs,pl)
311331 | _ -> die "" __LOC__)
312332 | _ -> Some(cs,pl)
313333 );
314334 TypeloadFunction.add_constructor ctx cg false p;
315335 cg.cl_kind <- KGenericInstance (c,tl);
316 cg.cl_meta <- (Meta.NoDoc,[],null_pos) :: cg.cl_meta;
317 if has_meta Meta.Keep c.cl_meta then cg.cl_meta <- (Meta.Keep,[],null_pos) :: cg.cl_meta;
318336 if (has_class_flag c CInterface) then add_class_flag cg CInterface;
337 if (has_class_flag c CAbstract) then add_class_flag cg CAbstract;
319338 cg.cl_constructor <- (match cg.cl_constructor, c.cl_constructor, c.cl_super with
320339 | _, Some cf, _ -> Some (build_field cf)
321340 | Some ctor, _, _ -> Some ctor
322341 | None, None, None -> None
323 | _ -> error "Please define a constructor for this class in order to use it as generic" c.cl_pos
342 | _ -> typing_error "Please define a constructor for this class in order to use it as generic" c.cl_pos
324343 );
325344 cg.cl_implements <- List.map (fun (i,tl) ->
326345 (match follow (generic_substitute_type gctx (TInst (i, List.map (generic_substitute_type gctx) tl))) with
340359 TInst (cg,[])
341360 end
342361
343 let type_generic_function ctx fa el_typed el with_type p =
362 let type_generic_function ctx fa fcc with_type p =
344363 let c,stat = match fa.fa_host with
345364 | FHInstance(c,tl) -> c,false
346365 | FHStatic c -> c,true
347366 | FHAbstract(a,tl,c) -> c,true
348367 | _ -> die "" __LOC__
349368 in
350 let cf = fa.fa_field in
351 if cf.cf_params = [] then error "Function has no type parameters and cannot be generic" p;
352 let fcc = CallUnification.unify_field_call ctx fa el_typed el p false in
369 let cf = fcc.fc_field in
370 if cf.cf_params = [] then typing_error "Function has no type parameters and cannot be generic" p;
353371 begin match with_type with
354372 | WithType.WithType(t,_) -> unify ctx fcc.fc_ret t p
355373 | _ -> ()
364382 let gctx = make_generic ctx cf.cf_params monos p in
365383 let name = cf.cf_name ^ "_" ^ gctx.name in
366384 let unify_existing_field tcf pcf = try
367 unify_raise ctx tcf fcc.fc_type p
368 with Error(Unify _,_) as err ->
369 display_error ctx ("Cannot create field " ^ name ^ " due to type mismatch") p;
370 display_error ctx (compl_msg "Conflicting field was defined here") pcf;
385 unify_raise tcf fcc.fc_type p
386 with Error(Unify _,_,depth) as err ->
387 display_error ~depth ctx.com ("Cannot create field " ^ name ^ " due to type mismatch") p;
388 display_error ~depth:(depth+1) ctx.com (compl_msg "Conflicting field was defined here") pcf;
371389 raise err
372390 in
373391 let fa = try
394412 ignore(follow cf.cf_type);
395413 let rec check e = match e.eexpr with
396414 | TNew({cl_kind = KTypeParameter _} as c,_,_) when not (TypeloadCheck.is_generic_parameter ctx c) ->
397 display_error ctx "Only generic type parameters can be constructed" e.epos;
398 display_error ctx "While specializing this call" p;
415 display_error ctx.com "Only generic type parameters can be constructed" e.epos;
416 display_error ctx.com "While specializing this call" p;
399417 | _ ->
400418 Type.iter check e
401419 in
402420 cf2.cf_expr <- (match cf.cf_expr with
403421 | None ->
404 display_error ctx "Recursive @:generic function" p; None;
422 display_error ctx.com "Recursive @:generic function" p; None;
405423 | Some e ->
406424 let e = generic_substitute_expr gctx e in
407425 check e;
417435 if stat then begin
418436 if Meta.has Meta.GenericClassPerMethod c.cl_meta then begin
419437 let c = static_method_container gctx c cf p in
438 set_type_parameter_dependencies c.cl_module monos;
420439 let cf2 = try
421440 let cf2 = PMap.find cf.cf_name c.cl_statics in
422441 unify_existing_field cf2.cf_type cf2.cf_pos;
430449 in
431450 {fa with fa_host = FHStatic c;fa_field = cf2;fa_on = Builder.make_static_this c p}
432451 end else begin
452 set_type_parameter_dependencies c.cl_module monos;
433453 let cf2 = mk_cf2 name in
434454 c.cl_statics <- PMap.add cf2.cf_name cf2 c.cl_statics;
435455 c.cl_ordered_statics <- cf2 :: c.cl_ordered_statics;
437457 {fa with fa_field = cf2}
438458 end
439459 end else begin
460 set_type_parameter_dependencies c.cl_module monos;
440461 let cf2 = mk_cf2 name in
441462 if has_class_field_flag cf CfOverride then add_class_field_flag cf2 CfOverride;
442463 c.cl_fields <- PMap.add cf2.cf_name cf2 c.cl_fields;
445466 {fa with fa_field = cf2}
446467 end
447468 in
448 let e = FieldAccess.get_field_expr fa FCall in
449 make_call ctx e el fcc.fc_ret p
469 let dispatch = new CallUnification.call_dispatcher ctx (MCall []) with_type p in
470 dispatch#field_call fa el []
450471 with Generic_Exception (msg,p) ->
451 error msg p)
472 typing_error msg p)
452473
453474 ;;
454 Typecore.type_generic_function_ref := type_generic_function
475 Typecore.type_generic_function_ref := type_generic_function
66 let get_macro_path ctx e args p =
77 let rec loop e =
88 match fst e with
9 | EField (e,f) -> f :: loop e
9 | EField (e,f,_) -> f :: loop e
1010 | EConst (Ident i) -> [i]
11 | _ -> error "Invalid macro call" p
11 | _ -> typing_error "Invalid macro call" p
1212 in
1313 let path = match e with
1414 | (EConst(Ident i)),_ ->
1818 with Not_found -> try
1919 (t_infos (let path,_,_ = PMap.find i ctx.m.module_globals in path)).mt_path
2020 with Not_found ->
21 error "Invalid macro call" p
21 typing_error "Invalid macro call" p
2222 in
2323 i :: (snd path) :: (fst path)
2424 | _ ->
2626 in
2727 (match path with
2828 | meth :: cl :: path -> (List.rev path,cl), meth, args
29 | _ -> error "Invalid macro call" p)
29 | _ -> typing_error "Invalid macro call" p)
3030
3131 let build_macro_type ctx pl p =
3232 let path, field, args = (match pl with
3434 | [TInst ({ cl_kind = KExpr (EArrayDecl [ECall (e,args),_],_) },_)] ->
3535 get_macro_path ctx e args p
3636 | _ ->
37 error "MacroType requires a single expression call parameter" p
37 typing_error "MacroType requires a single expression call parameter" p
3838 ) in
3939 let old = ctx.ret in
4040 let t = (match ctx.g.do_macro ctx MMacroType path field args p with
4848 let path, field, args =
4949 let build_expr =
5050 try Meta.get Meta.GenericBuild c.cl_meta
51 with Not_found -> error ((s_type_path c.cl_path) ^ " is missing @:genericBuild meta. Was it removed by a macro?") p
51 with Not_found -> typing_error ((s_type_path c.cl_path) ^ " is missing @:genericBuild meta. Was it removed by a macro?") p
5252 in
5353 match build_expr with
5454 | _,[ECall(e,args),_],_ -> get_macro_path ctx e args p
55 | _ -> error "genericBuild requires a single expression call parameter" p
55 | _ -> typing_error "genericBuild requires a single expression call parameter" p
5656 in
5757 let old = ctx.ret,ctx.get_build_infos in
5858 ctx.get_build_infos <- (fun() -> Some (TClassDecl c, pl, cfl));
7676 let t = spawn_monomorph ctx p in
7777 r := lazy_processing (fun() -> t);
7878 let tf = (f()) in
79 unify_raise ctx tf t p;
79 unify_raise tf t p;
8080 link_dynamic t tf;
8181 (match tf with
8282 | TInst (c, _) -> ignore(c.cl_build())
9090 let ft = (fun pl ->
9191 match c.cl_kind with
9292 | KGeneric ->
93 build (fun () -> Generic.build_generic ctx c p pl) "build_generic"
93 build (fun () -> Generic.build_generic_class ctx c p pl) "build_generic"
9494 | KMacroType ->
9595 build (fun () -> build_macro_type ctx pl p) "macro_type"
9696 | KGenericBuild cfl ->
5252 let errors = Interp.handle_decoding_error (output_string ch) v t in
5353 List.iter (fun (s,i) -> Printf.fprintf ch "\nline %i: %s" i s) (List.rev errors);
5454 close_out ch;
55 error (Printf.sprintf "Expected %s but got %s (see %s.txt for details)" expected (Interp.value_string v) (String.concat "/" path)) p
56
57 let get_next_stored_typed_expr_id =
58 let uid = ref 0 in
59 (fun() -> incr uid; !uid)
60
61 let get_stored_typed_expr com id =
62 let e = PMap.find id com.stored_typed_exprs in
63 Texpr.duplicate_tvars e
55 typing_error (Printf.sprintf "Expected %s but got %s (see %s.txt for details)" expected (Interp.value_string v) (String.concat "/" path)) p
6456
6557 let get_type_patch ctx t sub =
6658 let new_patch() =
9082
9183 let typing_timer ctx need_type f =
9284 let t = Timer.timer ["typing"] in
93 let old = ctx.com.error and oldp = ctx.pass and oldlocals = ctx.locals in
85 let old = ctx.com.located_error and oldp = ctx.pass and oldlocals = ctx.locals in
86 let restore_report_mode = disable_report_mode ctx.com in
9487 (*
9588 disable resumable errors... unless we are in display mode (we want to reach point of completion)
9689 *)
97 (*if ctx.com.display = DMNone then ctx.com.error <- (fun e p -> raise (Error(Custom e,p)));*) (* TODO: review this... *)
98 ctx.com.error <- (fun e p -> raise (Error(Custom e,p)));
90 (*if ctx.com.display = DMNone then ctx.com.located_error <- (fun e p -> raise (Error(Custom e,p)));*) (* TODO: review this... *)
91 let rec located_to_error = function
92 | Message (e,p) -> (Custom e,p)
93 | Stack stack -> (Stack (List.map located_to_error stack),null_pos)
94 in
95
96 ctx.com.located_error <- (fun ?(depth=0) msg ->
97 let (e,p) = located_to_error msg in
98 raise (Error (e,p,depth)));
99
99100 if need_type && ctx.pass < PTypeField then begin
100101 ctx.pass <- PTypeField;
101102 flush_pass ctx PBuildClass "typing_timer";
102103 end;
103104 let exit() =
104105 t();
105 ctx.com.error <- old;
106 ctx.com.located_error <- old;
106107 ctx.pass <- oldp;
107108 ctx.locals <- oldlocals;
109 restore_report_mode ();
108110 in
109111 try
110112 let r = f() in
111113 exit();
112114 r
113 with Error (ekind,p) ->
115 with Error (ekind,p,_) ->
114116 exit();
115 Interp.compiler_error (error_msg ekind) p
116 | WithTypeError (l,p) ->
117 Interp.compiler_error (error_msg p ekind)
118 | WithTypeError (l,p,_) ->
117119 exit();
118 Interp.compiler_error (error_msg l) p
120 Interp.compiler_error (error_msg p l)
119121 | e ->
120122 exit();
121123 raise e
125127 let make_macro_api ctx p =
126128 let parse_expr_string s p inl =
127129 typing_timer ctx false (fun() ->
128 match ParserEntry.parse_expr_string ctx.com.defines s p error inl with
130 match ParserEntry.parse_expr_string ctx.com.defines s p typing_error inl with
129131 | ParseSuccess(data,true,_) when inl -> data (* ignore errors when inline-parsing in display file *)
130132 | ParseSuccess(data,_,_) -> data
131133 | ParseError _ -> raise MacroApi.Invalid_expr)
132134 in
133135 let parse_metadata s p =
134136 try
135 match ParserEntry.parse_string Grammar.parse_meta ctx.com.defines s null_pos error false with
137 match ParserEntry.parse_string Grammar.parse_meta ctx.com.defines s null_pos typing_error false with
136138 | ParseSuccess(meta,_,_) -> meta
137 | ParseError(_,_,_) -> error "Malformed metadata string" p
139 | ParseError(_,_,_) -> typing_error "Malformed metadata string" p
138140 with _ ->
139 error "Malformed metadata string" p
141 typing_error "Malformed metadata string" p
140142 in
141143 {
142144 MacroApi.pos = p;
143145 MacroApi.get_com = (fun() -> ctx.com);
146 MacroApi.get_macro_stack = (fun () ->
147 let envs = Interp.call_stack (Interp.get_eval (Interp.get_ctx ())) in
148 let envs = match envs with
149 | _ :: envs -> envs (* Skip call to getMacroStack() *)
150 | _ -> envs
151 in
152 List.map (fun (env:Interp.env) -> {pfile = EvalHash.rev_hash env.env_info.pfile;pmin = env.env_leave_pmin; pmax = env.env_leave_pmax}) envs
153 );
154 MacroApi.init_macros_done = (fun () -> ctx.com.stage >= CInitMacrosDone);
144155 MacroApi.get_type = (fun s ->
145156 typing_timer ctx false (fun() ->
146157 let path = parse_path s in
153164 try
154165 let m = Some (Typeload.load_instance ctx (tp,p) true) in
155166 m
156 with Error (Module_not_found _,p2) when p == p2 ->
167 with Error (Module_not_found _,p2,_) when p == p2 ->
157168 None
158169 )
159170 );
165176 let path = parse_path s in
166177 let m = List.map type_of_module_type (TypeloadModule.load_module ctx path p).m_types in
167178 m
179 )
180 );
181 MacroApi.after_init_macros = (fun f ->
182 ctx.com.callbacks#add_after_init_macros (fun () ->
183 let t = macro_timer ctx ["afterInitMacros"] in
184 f ();
185 t()
168186 )
169187 );
170188 MacroApi.after_typing = (fun f ->
199217 ];
200218 );
201219 MacroApi.parse_string = parse_expr_string;
220 MacroApi.parse = (fun entry s ->
221 match ParserEntry.parse_string entry ctx.com.defines s null_pos typing_error false with
222 | ParseSuccess(r,_,_) -> r
223 | ParseError(_,(msg,p),_) -> Parser.error msg p
224 );
202225 MacroApi.type_expr = (fun e ->
203226 typing_timer ctx true (fun() -> type_expr ctx e WithType.value)
204227 );
205 MacroApi.type_macro_expr = (fun e ->
206 let e = typing_timer ctx true (fun() -> type_expr ctx e WithType.value) in
207 let rec loop e = match e.eexpr with
208 | TField(_,FStatic(c,({cf_kind = Method _} as cf))) -> ignore(!load_macro_ref ctx false c.cl_path cf.cf_name e.epos)
209 | _ -> Type.iter loop e
210 in
211 loop e;
212 e
213 );
214228 MacroApi.flush_context = (fun f ->
215229 typing_timer ctx true f
216230 );
217231 MacroApi.store_typed_expr = (fun te ->
218232 let p = te.epos in
219 let id = get_next_stored_typed_expr_id() in
220 ctx.com.stored_typed_exprs <- PMap.add id te ctx.com.stored_typed_exprs;
221 let eid = (EConst (Int (string_of_int id))), p in
222 (EMeta ((Meta.StoredTypedExpr,[],p), eid)), p
233 snd (Typecore.store_typed_expr ctx.com te p)
223234 );
224235 MacroApi.allow_package = (fun v -> Common.allow_package ctx.com v);
225236 MacroApi.type_patch = (fun t f s v ->
226237 typing_timer ctx false (fun() ->
227238 let v = (match v with None -> None | Some s ->
228 match ParserEntry.parse_string Grammar.parse_complex_type ctx.com.defines s null_pos error false with
239 match ParserEntry.parse_string Grammar.parse_complex_type ctx.com.defines s null_pos typing_error false with
229240 | ParseSuccess((ct,_),_,_) -> Some ct
230241 | ParseError(_,(msg,p),_) -> Parser.error msg p (* p is null_pos, but we don't have anything else here... *)
231242 ) in
281292 List.map fst ctx.m.module_using;
282293 );
283294 MacroApi.get_local_imports = (fun() ->
284 ctx.m.module_imports;
295 ctx.m.import_statements;
285296 );
286297 MacroApi.get_local_vars = (fun () ->
287298 ctx.locals;
309320 let mnew = TypeloadModule.type_module ctx ~dont_check_path:(has_native_meta) m (Path.UniqueKey.lazy_path mdep.m_extra.m_file) [tdef,pos] pos in
310321 mnew.m_extra.m_kind <- if is_macro then MMacro else MFake;
311322 add_dependency mnew mdep;
323 ctx.com.module_nonexistent_lut#clear;
312324 in
313325 add false ctx;
314326 (* if we are adding a class which has a macro field, we also have to add it to the macro context (issue #1497) *)
315 if not ctx.in_macro then match tdef with
327 if not ctx.com.is_macro_context then match tdef with
316328 | EClass c when List.exists (fun cff -> (Meta.has Meta.Macro cff.cff_meta || List.mem_assoc AMacro cff.cff_access)) c.d_data ->
317329 add true mctx
318330 | _ ->
332344 let types = imports @ usings @ types in
333345 let mpath = Ast.parse_path m in
334346 begin try
335 let m = Hashtbl.find ctx.g.modules mpath in
347 let m = ctx.com.module_lut#find mpath in
336348 ignore(TypeloadModule.type_types_into_module ctx m types pos)
337349 with Not_found ->
338350 let mnew = TypeloadModule.type_module ctx mpath (Path.UniqueKey.lazy_path ctx.m.curmod.m_extra.m_file) types pos in
339351 mnew.m_extra.m_kind <- MFake;
340352 add_dependency mnew ctx.m.curmod;
353 ctx.com.module_nonexistent_lut#clear;
341354 end
342355 );
343356 MacroApi.module_dependency = (fun mpath file ->
364377 try
365378 ignore(AbstractCast.cast_or_unify_raise ctx t e p);
366379 true
367 with Error (Unify _,_) ->
380 with Error (Unify _,_,_) ->
368381 false
369382 )
370383 );
378391 MacroApi.add_module_check_policy = (fun sl il b i ->
379392 let add ctx =
380393 ctx.g.module_check_policies <- (List.fold_left (fun acc s -> (ExtString.String.nsplit s ".",List.map Obj.magic il,b) :: acc) ctx.g.module_check_policies sl);
381 Hashtbl.iter (fun _ m -> m.m_extra.m_check_policy <- TypeloadModule.get_policy ctx m.m_path) ctx.g.modules;
394 ctx.com.module_lut#iter (fun _ m -> m.m_extra.m_check_policy <- TypeloadModule.get_policy ctx.g m.m_path);
382395 in
383396 let add_macro ctx = match ctx.g.macros with
384397 | None -> ()
385398 | Some(_,mctx) -> add mctx;
386399 in
400 let open CompilationCache in
387401 match Obj.magic i with
388 | CompilationServer.NormalContext -> add ctx
389 | CompilationServer.MacroContext -> add_macro ctx
390 | CompilationServer.NormalAndMacroContext -> add ctx; add_macro ctx;
391 );
402 | NormalContext -> add ctx
403 | MacroContext -> add_macro ctx
404 | NormalAndMacroContext -> add ctx; add_macro ctx;
405 );
406 MacroApi.register_define = (fun s data -> Define.register_user_define ctx.com.user_defines s data);
407 MacroApi.register_metadata = (fun s data -> Meta.register_user_meta ctx.com.user_metas s data);
392408 MacroApi.decode_expr = Interp.decode_expr;
393409 MacroApi.encode_expr = Interp.encode_expr;
394410 MacroApi.encode_ctype = Interp.encode_ctype;
395411 MacroApi.decode_type = Interp.decode_type;
412 MacroApi.display_error = display_error ctx.com;
413 MacroApi.with_imports = (fun imports usings f ->
414 let old_globals = ctx.m.module_globals in
415 let old_imports = ctx.m.module_imports in
416 let old_using = ctx.m.module_using in
417 let run () =
418 let context_init = new TypeloadFields.context_init in
419 List.iter (fun (path,mode) ->
420 ImportHandling.init_import ctx context_init path mode null_pos
421 ) imports;
422 List.iter (fun path ->
423 ImportHandling.init_using ctx context_init path null_pos
424 ) usings;
425 context_init#run;
426 f()
427 in
428 let restore () =
429 ctx.m.module_globals <- old_globals;
430 ctx.m.module_imports <- old_imports;
431 ctx.m.module_using <- old_using;
432 in
433 Std.finally restore run ()
434 );
435 MacroApi.with_options = (fun opts f ->
436 let old_inline = ctx.allow_inline in
437 let old_transform = ctx.allow_transform in
438 (match opts.opt_inlining with
439 | None -> ()
440 | Some v -> ctx.allow_inline <- v);
441 (match opts.opt_transform with
442 | None -> ()
443 | Some v -> ctx.allow_transform <- v);
444 let restore() =
445 ctx.allow_inline <- old_inline;
446 ctx.allow_transform <- old_transform;
447 in
448 Std.finally restore f ()
449 );
450 MacroApi.info = (fun ?(depth=0) msg p ->
451 ctx.com.info ~depth msg p
452 );
453 MacroApi.warning = (fun ?(depth=0) w msg p ->
454 warning ~depth ctx w msg p
455 );
396456 }
397457
398458 let rec init_macro_interp ctx mctx mint =
399459 let p = null_pos in
400460 ignore(TypeloadModule.load_module mctx (["haxe";"macro"],"Expr") p);
401461 ignore(TypeloadModule.load_module mctx (["haxe";"macro"],"Type") p);
402 flush_macro_context mint ctx;
403462 Interp.init mint;
404463 if !macro_enable_cache && not (Common.defined mctx.com Define.NoMacroCache) then begin
405464 macro_interp_cache := Some mint;
408467 and flush_macro_context mint ctx =
409468 let t = macro_timer ctx ["flush"] in
410469 let mctx = (match ctx.g.macros with None -> die "" __LOC__ | Some (_,mctx) -> mctx) in
411 ctx.g.do_finalize mctx;
412 let _, types, modules = ctx.g.do_generate mctx in
470 Finalization.finalize mctx;
471 let _, types, modules = Finalization.generate mctx in
413472 mctx.com.types <- types;
414473 mctx.com.Common.modules <- modules;
415474 (* we should maybe ensure that all filters in Main are applied. Not urgent atm *)
424483 let's save the minimal amount of information we need
425484 *)
426485 let minimal_restore t =
486 if (t_infos t).mt_module.m_extra.m_processed = 0 then
487 (t_infos t).mt_module.m_extra.m_processed <- mctx.com.compilation_step;
488
427489 match t with
428490 | TClassDecl c ->
429491 let mk_field_restore f =
448510 ()
449511 in
450512 let type_filters = [
451 Filters.remove_generic_base mctx;
513 Filters.remove_generic_base;
452514 Exceptions.patch_constructors mctx;
453 Filters.add_field_inits (RenameVars.init mctx.com) mctx;
515 (fun mt -> Filters.add_field_inits mctx.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt);
454516 minimal_restore;
455 Filters.apply_native_paths mctx
517 Filters.apply_native_paths
456518 ] in
457519 let ready = fun t ->
458520 Filters.apply_filters_once mctx expr_filters t;
459521 List.iter (fun f -> f t) type_filters
460522 in
461523 (try Interp.add_types mint types ready
462 with Error (e,p) -> t(); raise (Fatal_error(error_msg e,p)));
463 t();
464 Filters.next_compilation()
524 with Error (e,p,n) -> t(); raise (Fatal_error(error_msg p e,n)));
525 t()
465526
466527 let create_macro_interp ctx mctx =
467528 let com2 = mctx.com in
474535 Interp.do_reuse mint (make_macro_api ctx null_pos);
475536 mint, (fun() -> ())
476537 ) in
477 let on_error = com2.error in
478 com2.error <- (fun e p ->
538 let on_error = com2.located_error in
539 com2.located_error <- (fun ?(depth = 0) msg ->
479540 Interp.set_error (Interp.get_ctx()) true;
480541 macro_interp_cache := None;
481 on_error e p
542 on_error ~depth msg
482543 );
483544 let macro = ((fun() -> Interp.select mint), mctx) in
484545 ctx.g.macros <- Some macro;
493554 select();
494555 api, ctx
495556 | None ->
496 let com2 = Common.clone ctx.com in
557 let com2 = Common.clone ctx.com true in
497558 ctx.com.get_macros <- (fun() -> Some com2);
498559 com2.package_rules <- PMap.empty;
499560 com2.main_class <- None;
500561 (* Inherit most display settings, but require normal typing. *)
501 com2.display <- {ctx.com.display with dms_kind = DMNone; dms_display = false; dms_full_typing = true; dms_force_macro_typing = true; dms_inline = true; };
562 com2.display <- {ctx.com.display with dms_kind = DMNone; dms_full_typing = true; dms_force_macro_typing = true; dms_inline = true; };
502563 com2.class_path <- List.filter (fun s -> not (ExtString.String.exists s "/_std/")) com2.class_path;
503564 let name = platform_name !Globals.macro_platform in
504565 com2.class_path <- List.map (fun p -> p ^ name ^ "/_std/") com2.std_path @ com2.class_path;
514575
515576 let load_macro_module ctx cpath display p =
516577 let api, mctx = get_macro_context ctx p in
517 let m = (try Hashtbl.find ctx.g.types_module cpath with Not_found -> cpath) in
578 let m = (try ctx.com.type_to_module#find cpath with Not_found -> cpath) in
518579 (* Temporarily enter display mode while typing the macro. *)
519580 let old = mctx.com.display in
520581 if display then mctx.com.display <- ctx.com.display;
522583 api.MacroApi.current_macro_module <- (fun() -> mloaded);
523584 mctx.m <- {
524585 curmod = mloaded;
525 module_types = [];
586 module_imports = [];
526587 module_using = [];
527588 module_globals = PMap.empty;
528589 wildcard_packages = [];
529 module_imports = [];
590 import_statements = [];
530591 };
531592 mloaded,(fun () -> mctx.com.display <- old)
532593
533594 let load_macro' ctx display cpath f p =
534595 let api, mctx = get_macro_context ctx p in
535596 let mint = Interp.get_ctx() in
536 let (meth,mloaded) = try Hashtbl.find mctx.com.cached_macros (cpath,f) with Not_found ->
597 let (meth,mloaded) = try mctx.com.cached_macros#find (cpath,f) with Not_found ->
537598 let t = macro_timer ctx ["typing";s_type_path cpath ^ "." ^ f] in
538599 let mpath, sub = (match List.rev (fst cpath) with
539600 | name :: pack when name.[0] >= 'A' && name.[0] <= 'Z' -> (List.rev pack,name), Some (snd cpath)
542603 let mloaded,restore = load_macro_module ctx mpath display p in
543604 let cl, meth =
544605 try
545 if sub <> None then raise Not_found;
606 if sub <> None || mloaded.m_path <> cpath then raise Not_found;
546607 match mloaded.m_statics with
547608 | None -> raise Not_found
548609 | Some c ->
549 mctx.g.do_finalize mctx;
610 Finalization.finalize mctx;
550611 c, PMap.find f c.cl_statics
551612 with Not_found ->
552613 let name = Option.default (snd mpath) sub in
553614 let path = fst mpath, name in
554 let mt = try List.find (fun t2 -> (t_infos t2).mt_path = path) mloaded.m_types with Not_found -> raise_error (Type_not_found (mloaded.m_path,name,Not_defined)) p in
615 let mt = try List.find (fun t2 -> (t_infos t2).mt_path = path) mloaded.m_types with Not_found -> raise_typing_error (Type_not_found (mloaded.m_path,name,Not_defined)) p in
555616 match mt with
556617 | TClassDecl c ->
557 mctx.g.do_finalize mctx;
558 c, (try PMap.find f c.cl_statics with Not_found -> error ("Method " ^ f ^ " not found on class " ^ s_type_path cpath) p)
559 | _ -> error "Macro should be called on a class" p
618 Finalization.finalize mctx;
619 c, (try PMap.find f c.cl_statics with Not_found -> typing_error ("Method " ^ f ^ " not found on class " ^ s_type_path cpath) p)
620 | _ -> typing_error "Macro should be called on a class" p
560621 in
561622 api.MacroApi.current_macro_module <- (fun() -> mloaded);
562 let meth = (match follow meth.cf_type with TFun (args,ret) -> (args,ret,cl,meth),mloaded | _ -> error "Macro call should be a method" p) in
623 let meth = (match follow meth.cf_type with TFun (args,ret) -> (args,ret,cl,meth),mloaded | _ -> typing_error "Macro call should be a method" p) in
563624 restore();
564 if not ctx.in_macro then flush_macro_context mint ctx;
565 Hashtbl.add mctx.com.cached_macros (cpath,f) meth;
625 if not ctx.com.is_macro_context then flush_macro_context mint ctx;
626 mctx.com.cached_macros#add (cpath,f) meth;
566627 mctx.m <- {
567628 curmod = null_module;
568 module_types = [];
629 module_imports = [];
569630 module_using = [];
570631 module_globals = PMap.empty;
571632 wildcard_packages = [];
572 module_imports = [];
633 import_statements = [];
573634 };
574635 t();
575636 meth
628689 let cttype = mk_type_path (["haxe";"macro"],"Type") in
629690 let ttype = Typeload.load_instance mctx (cttype,p) false in
630691 try
631 unify_raise mctx mret ttype mpos;
692 unify_raise mret ttype mpos;
632693 (* TODO: enable this again in the future *)
633 (* ctx.com.warning "Returning Type from @:genericBuild macros is deprecated, consider returning ComplexType instead" p; *)
634 with Error (Unify _,_) ->
694 (* warning ctx WDeprecated "Returning Type from @:genericBuild macros is deprecated, consider returning ComplexType instead" p; *)
695 with Error (Unify _,_,_) ->
635696 let cttype = mk_type_path ~sub:"ComplexType" (["haxe";"macro"],"Expr") in
636697 let ttype = Typeload.load_instance mctx (cttype,p) false in
637 unify_raise mctx mret ttype mpos;
698 unify_raise mret ttype mpos;
638699 );
639700 (*
640701 if the function's last argument is of Array<Expr>, split the argument list and use [] for unify_call_args
665726 force default parameter types to haxe.macro.Expr, and if success allow to pass any value type since it will be encoded
666727 *)
667728 let eargs = List.map (fun (n,o,t) ->
668 try unify_raise mctx t expr p; (n, o, t_dynamic), MAExpr
669 with Error (Unify _,_) -> match follow t with
729 try unify_raise t expr p; (n, o, t_dynamic), MAExpr
730 with Error (Unify _,_,_) -> match follow t with
670731 | TFun _ ->
671 (n,o,t_dynamic), MAFunction
732 (n,o,t), MAFunction
672733 | _ ->
673734 (n,o,t), MAOther
674735 ) margs in
680741 let constants = List.map (fun e ->
681742 let p = snd e in
682743 let e =
744 let rec is_function e = match fst e with
745 | EFunction _ -> true
746 | EParenthesis e1 | ECast(e1,_) | EMeta(_,e1) -> is_function e1
747 | _ -> false
748 in
683749 if Texpr.is_constant_value ctx.com.basic e then
684750 (* temporarily disable format strings processing for macro call argument typing since we want to pass raw constants *)
685751 let rec loop e =
688754 | _ -> Ast.map_expr loop e
689755 in
690756 loop e
757 else if is_function e then
758 (* If we pass a function expression we don't want to type it as part of `unify_call_args` because that result just gets
759 discarded. Use null here so it passes, then do the actual typing in the MAFunction part below. *)
760 (EConst (Ident "null"),p)
691761 else
692762 (* if it's not a constant, let's make something that is typed as haxe.macro.Expr - for nice error reporting *)
693763 (ECheckType ((EConst (Ident "null"),p), (CTPath ctexpr,p)), p)
694764 in
695765 (* let's track the index by doing [e][index] (we will keep the expression type this way) *)
696766 incr index;
697 (EArray ((EArrayDecl [e],p),(EConst (Int (string_of_int (!index))),p)),p)
767 (EArray ((EArrayDecl [e],p),(EConst (Int (string_of_int (!index), None)),p)),p)
698768 ) el in
699769 let elt = fst (CallUnification.unify_call_args mctx constants (List.map fst eargs) t_dynamic p false false false) in
700 List.map2 (fun (_,mct) e ->
770 List.map2 (fun ((n,_,t),mct) e ->
701771 let e, et = (match e.eexpr with
702772 (* get back our index and real expression *)
703773 | TArray ({ eexpr = TArrayDecl [e] }, { eexpr = TConst (TInt index) }) -> List.nth el (Int32.to_int index), e
710780 | MAExpr ->
711781 Interp.encode_expr e
712782 | MAFunction ->
713 let e = ictx.Interp.curapi.MacroApi.type_macro_expr e in
783 let e = type_expr mctx e (WithType.with_argument t n) in
784 unify mctx e.etype t e.epos;
714785 begin match Interp.eval_expr ictx e with
715786 | Some v -> v
716787 | None -> Interp.vnull
758829 in
759830 safe_decode ctx v expected mret p process
760831 in
761 let e = if ctx.in_macro then
832 let e = if ctx.com.is_macro_context then
762833 Some (EThrow((EConst(String("macro-in-macro",SDoubleQuotes))),p),p)
763834 else
764835 call()
769840 let mctx, (margs,_,mclass,mfield), call = load_macro ctx false path meth p in
770841 mctx.curclass <- null_class;
771842 let el, _ = CallUnification.unify_call_args mctx args margs t_dynamic p false false false in
772 call (List.map (fun e -> try Interp.make_const e with Exit -> error "Parameter should be a constant" e.epos) el)
843 call (List.map (fun e -> try Interp.make_const e with Exit -> typing_error "Argument should be a constant" e.epos) el)
773844
774845 let call_init_macro ctx e =
775846 let p = { pfile = "--macro " ^ e; pmin = -1; pmax = -1 } in
776847 let e = try
777 if String.get e (String.length e - 1) = ';' then error "Unexpected ;" p;
778 begin match ParserEntry.parse_expr_string ctx.com.defines e p error false with
848 if String.get e (String.length e - 1) = ';' then typing_error "Unexpected ;" p;
849 begin match ParserEntry.parse_expr_string ctx.com.defines e p typing_error false with
779850 | ParseSuccess(data,_,_) -> data
780851 | ParseError(_,(msg,p),_) -> (Parser.error msg p)
781852 end
782853 with err ->
783 display_error ctx ("Could not parse `" ^ e ^ "`") p;
854 display_error ctx.com ("Could not parse `" ^ e ^ "`") p;
784855 raise err
785856 in
786857 match fst e with
787858 | ECall (e,args) ->
788859 let rec loop e =
789860 match fst e with
790 | EField (e,f) -> f :: loop e
861 | EField (e,f,_) -> f :: loop e
791862 | EConst (Ident i) -> [i]
792 | _ -> error "Invalid macro call" p
863 | _ -> typing_error "Invalid macro call" p
793864 in
794865 let path, meth = (match loop e with
795866 | [meth] -> (["haxe";"macro"],"Compiler"), meth
796867 | [meth;"server"] -> (["haxe";"macro"],"CompilationServer"), meth
797868 | meth :: cl :: path -> (List.rev path,cl), meth
798 | _ -> error "Invalid macro call" p) in
869 | _ -> typing_error "Invalid macro call" p) in
799870 ignore(call_macro ctx path meth args p);
800871 | _ ->
801 error "Invalid macro call" p
872 typing_error "Invalid macro call" p
802873
803874 let interpret ctx =
804875 let mctx = Interp.create ctx.com (make_macro_api ctx null_pos) false in
811882 Interp.setup Interp.macro_api
812883
813884 let type_stored_expr ctx e1 =
814 let id = match e1 with (EConst (Int s),_) -> int_of_string s | _ -> die "" __LOC__ in
885 let id = match e1 with (EConst (Int (s, _)),_) -> int_of_string s | _ -> die "" __LOC__ in
815886 get_stored_typed_expr ctx.com id
816887
817888 ;;
1010 (* REMOTING PROXYS *)
1111
1212 let extend_remoting ctx c t p async prot =
13 if c.cl_super <> None then error "Cannot extend several classes" p;
13 if c.cl_super <> None then typing_error "Cannot extend several classes" p;
1414 (* remove forbidden packages *)
1515 let rules = ctx.com.package_rules in
1616 ctx.com.package_rules <- PMap.foldi (fun key r acc -> match r with Forbidden -> acc | _ -> PMap.add key r acc) rules PMap.empty;
2121 let t = (try
2222 load_type_def ctx p (mk_type_path (fst path,new_name))
2323 with
24 Error (Module_not_found _,p2) when p == p2 ->
24 Error (Module_not_found _,p2,_) when p == p2 ->
2525 (* build it *)
2626 Common.log ctx.com ("Building proxy for " ^ s_type_path path);
2727 let file, decls = (try
2828 TypeloadParse.parse_module ctx path p
2929 with
30 | Not_found -> ctx.com.package_rules <- rules; error ("Could not load proxy module " ^ s_type_path path ^ (if fst path = [] then " (try using absolute path)" else "")) p
30 | Not_found -> ctx.com.package_rules <- rules; typing_error ("Could not load proxy module " ^ s_type_path path ^ (if fst path = [] then " (try using absolute path)" else "")) p
3131 | e -> ctx.com.package_rules <- rules; raise e) in
3232 ctx.com.package_rules <- rules;
3333 let base_fields = [
4040 acc
4141 else match f.cff_kind with
4242 | FFun fd when (is_public || List.mem_assoc APublic f.cff_access) && not (List.mem_assoc AStatic f.cff_access) ->
43 if List.exists (fun (_,_,_,t,_) -> t = None) fd.f_args then error ("Field " ^ fst f.cff_name ^ " type is not complete and cannot be used by RemotingProxy") p;
43 if List.exists (fun (_,_,_,t,_) -> t = None) fd.f_args then typing_error ("Field " ^ fst f.cff_name ^ " type is not complete and cannot be used by RemotingProxy") p;
4444 let eargs = [EArrayDecl (List.map (fun ((a,_),_,_,_,_) -> (EConst (Ident a),p)) fd.f_args),p] in
4545 let ftype = (match fd.f_type with Some (CTPath { tpackage = []; tname = "Void" },_) -> None | _ -> fd.f_type) in
4646 let fargs, eargs = if async then match ftype with
5252 let id = (EConst (String (fst f.cff_name,SDoubleQuotes)), p) in
5353 let id = if prot then id else ECall ((EConst (Ident "__unprotect__"),p),[id]),p in
5454 let expr = ECall (
55 (EField (
56 (ECall ((EField ((EConst (Ident "__cnx"),p),"resolve"),p),[id]),p),
55 (efield (
56 (ECall ((efield ((EConst (Ident "__cnx"),p),"resolve"),p),[id]),p),
5757 "call")
5858 ,p),eargs),p
5959 in
8080 try
8181 List.find (fun tdecl -> snd (t_path tdecl) = new_name) m.m_types
8282 with Not_found ->
83 error ("Module " ^ s_type_path path ^ " does not define type " ^ t.tname) p
83 typing_error ("Module " ^ s_type_path path ^ " does not define type " ^ t.tname) p
8484 ) in
8585 match t with
8686 | TClassDecl c2 when c2.cl_params = [] -> ignore(c2.cl_build()); c.cl_super <- Some (c2,[]);
87 | _ -> error "Remoting proxy must be a class without parameters" p
87 | _ -> typing_error "Remoting proxy must be a class without parameters" p
8888
8989 let on_inherit ctx c p (is_extends,tp) =
9090 if not is_extends then
3838 (ExtList.List.make left other) @ [middle] @ (ExtList.List.make right other)
3939
4040 let type_field_access ctx ?(resume=false) e name =
41 Calls.acc_get ctx (Fields.type_field (Fields.TypeFieldConfig.create resume) ctx e name e.epos MGet WithType.value) e.epos
41 Calls.acc_get ctx (Fields.type_field (Fields.TypeFieldConfig.create resume) ctx e name e.epos MGet WithType.value)
4242
4343 let unapply_type_parameters params monos =
4444 let unapplied = ref [] in
45 List.iter2 (fun (_,t1) t2 ->
45 List.iter2 (fun tp1 t2 ->
4646 match t2,follow t2 with
4747 | TMono m1,TMono m2 ->
4848 unapplied := (m1,m1.tm_type) :: !unapplied;
49 Monomorph.bind m1 t1;
49 Monomorph.bind m1 tp1.ttp_type;
5050 | _ -> ()
5151 ) params monos;
5252 !unapplied
6767 | TInst(c,_) -> loop (TClassDecl c)
6868 | TEnum(en,_) -> loop (TEnumDecl en)
6969 | TAbstract(a,_) -> loop (TAbstractDecl a)
70 | _ -> error "Cannot use this type as a value" p
70 | _ -> typing_error "Cannot use this type as a value" p
7171 end
72 | _ -> error "Cannot use this type as a value" p
72 | _ -> typing_error "Cannot use this type as a value" p
7373 in
7474 Typeload.load_instance ctx ({tname=loop mt;tpackage=[];tsub=None;tparams=[]},p) true
7575
131131 | ConArray i -> make_int ctx.com.basic i p
132132 | ConTypeExpr mt -> TyperBase.type_module_type ctx mt None p
133133 | ConStatic(c,cf) -> make_static_field c cf p
134 | ConFields _ -> error "Something went wrong" p
134 | ConFields _ -> typing_error "Something went wrong" p
135135
136136 let hash con = Hashtbl.hash (fst con)
137137 end
182182 let ctx = pctx.ctx in
183183 let p = pos e in
184184 let fail () =
185 error ("Unrecognized pattern: " ^ (Ast.Printer.s_expr e)) p
185 typing_error ("Unrecognized pattern: " ^ (Ast.Printer.s_expr e)) p
186186 in
187187 let unify_expected t' =
188188 unify ctx t' t p
189189 in
190190 let verror name p =
191 error (Printf.sprintf "Variable %s must appear exactly once in each sub-pattern" name) p
191 typing_error (Printf.sprintf "Variable %s must appear exactly once in each sub-pattern" name) p
192192 in
193193 let add_local final name p =
194194 let is_wildcard_local = name = "_" in
195 if not is_wildcard_local && pctx.is_postfix_match then error "Pattern variables are not allowed in .match patterns" p;
196 if not is_wildcard_local && PMap.mem name pctx.current_locals then error (Printf.sprintf "Variable %s is bound multiple times" name) p;
195 if not is_wildcard_local && pctx.is_postfix_match then typing_error "Pattern variables are not allowed in .match patterns" p;
196 if not is_wildcard_local && PMap.mem name pctx.current_locals then typing_error (Printf.sprintf "Variable %s is bound multiple times" name) p;
197197 match pctx.or_locals with
198198 | Some map when not is_wildcard_local ->
199199 let v,p = try PMap.find name map with Not_found -> verror name p in
218218 let con_type_expr mt p = ConTypeExpr mt,p in
219219 let con_array i p = ConArray i,p in
220220 let con_fields fl p = ConFields fl,p in
221 let get_enumerable_idents () = match follow t with
222 | TEnum(en,_) ->
223 en.e_names
224 | TAbstract({a_impl = Some c} as a,pl) when a.a_enum ->
225 ExtList.List.filter_map (fun cf ->
226 if has_class_field_flag cf CfImpl && has_class_field_flag cf CfEnum then Some cf.cf_name else None
227 ) c.cl_ordered_statics
228 | _ ->
229 []
230 in
221231 let check_expr e =
222232 let rec loop e = match e.eexpr with
223233 | TField(_,FEnum(en,ef)) ->
230240 PatConstructor(con_const ct e.epos,[])
231241 | TCast(e1,None) ->
232242 loop e1
233 | TField _ ->
243 | TField (ef,f) ->
244 let s = field_name f in
245 begin match StringError.get_similar s (get_enumerable_idents()) with
246 | [] -> ()
247 | l ->
248 let tpath = match follow t with
249 | TEnum (e,tl) -> s_type_path e.e_path ^ "."
250 | TAbstract (a,tl) -> s_type_path a.a_path ^ "."
251 | _ -> ""
252 in
253 let fields = List.map (fun (el) -> tpath ^ el) l in
254 warning pctx.ctx WTyper ("Potential typo detected (expected similar values are " ^ (String.concat ", " fields) ^ ")") p
255 end;
234256 raise (Bad_pattern "Only inline or read-only (default, never) fields can be used as a pattern")
235257 | TTypeExpr mt ->
236258 PatConstructor(con_type_expr mt e.epos,[])
246268 if pctx.is_postfix_match then DKMarked else DKPattern toplevel
247269 in
248270 let catch_errors () =
249 let old = ctx.on_error in
250 ctx.on_error <- (fun _ _ _ ->
271 let old = ctx.com.located_error in
272 let restore_report_mode = disable_report_mode ctx.com in
273 ctx.com.located_error <- (fun ?depth _ ->
251274 raise Exit
252275 );
253276 (fun () ->
254 ctx.on_error <- old
277 restore_report_mode();
278 ctx.com.located_error <- old
255279 )
256280 in
257281 let try_typing e =
289313 with _ ->
290314 restore();
291315 if not (is_lower_ident s) && (match s.[0] with '`' | '_' -> false | _ -> true) then begin
292 display_error ctx "Pattern variables must be lower-case" p;
316 display_error ctx.com ("Unknown identifier : " ^ s ^ ", pattern variables must be lower-case or with `var ` prefix") p;
293317 end;
294 let sl = match follow t with
295 | TEnum(en,_) ->
296 en.e_names
297 | TAbstract({a_impl = Some c} as a,pl) when a.a_enum ->
298 ExtList.List.filter_map (fun cf ->
299 if has_class_field_flag cf CfImpl && has_class_field_flag cf CfEnum then Some cf.cf_name else None
300 ) c.cl_ordered_statics
301 | _ ->
302 []
303 in
304 begin match StringError.get_similar s sl with
318 begin match StringError.get_similar s (get_enumerable_idents()) with
305319 | [] ->
306320 ()
307321 (* if toplevel then
308 pctx.ctx.com.warning (Printf.sprintf "`case %s` has been deprecated, use `case var %s` instead" s s) p *)
309 | l -> pctx.ctx.com.warning ("Potential typo detected (expected similar values are " ^ (String.concat ", " l) ^ "). Consider using `var " ^ s ^ "` instead") p
322 warning pctx.ctx (Printf.sprintf "`case %s` has been deprecated, use `case var %s` instead" s s) p *)
323 | l -> warning pctx.ctx WTyper ("Potential typo detected (expected similar values are " ^ (String.concat ", " l) ^ "). Consider using `var " ^ s ^ "` instead") p
310324 end;
311325 let v = add_local false s p in
312326 PatVariable v
321335 let e = loop e in
322336 pctx.in_reification <- old;
323337 e
324 | EConst((Ident ("false" | "true") | Int _ | String _ | Float _) as ct) ->
338 | EConst((Ident ("false" | "true") | Int (_,_) | String _ | Float (_,_)) as ct) ->
339 begin match ct with
340 | String (value,kind) when kind = Ast.SSingleQuotes ->
341 let e = ctx.g.do_format_string ctx value p in
342 begin match e with
343 | EBinop _, p -> typing_error "String interpolation is not allowed in case patterns" p;
344 | _ -> ()
345 end;
346 | _ -> ()
347 end;
325348 let p = pos e in
326349 let e = Texpr.type_constant ctx.com.basic ct p in
327350 unify_expected e.etype;
331354 begin match follow t with
332355 | TFun(ta,tr) when tr == fake_tuple_type ->
333356 if i = "_" then PatTuple(List.map (fun (_,_,t) -> (PatAny,pos e)) ta)
334 else error "Cannot bind matched tuple to variable, use _ instead" p
357 else typing_error "Cannot bind matched tuple to variable, use _ instead" p
335358 | _ ->
336359 if i = "_" then PatAny
337360 else handle_ident i (pos e)
364387 | [],[] ->
365388 []
366389 | [],_ ->
367 error "Not enough arguments" p
390 typing_error "Not enough arguments" p
368391 | _,[] ->
369 error "Too many arguments" p
392 typing_error "Too many arguments" p
370393 in
371394 let patterns = loop el args in
372395 ignore(unapply_type_parameters ef.ef_params monos);
379402 try_typing e
380403 with
381404 | Exit -> fail()
382 | Bad_pattern s -> error s p
405 | Bad_pattern s -> typing_error s p
383406 end
384407 | EArrayDecl el ->
385408 let rec pattern seen t = match follow t with
389412 let pat = make pctx false t e in
390413 pat :: loop el tl
391414 | [],[] -> []
392 | [],_ -> error "Not enough arguments" p
393 | (_,p) :: _,[] -> error "Too many arguments" p
415 | [],_ -> typing_error "Not enough arguments" p
416 | (_,p) :: _,[] -> typing_error "Too many arguments" p
394417 in
395418 let patterns = loop el tl in
396419 PatTuple patterns
400423 ) el in
401424 PatConstructor(con_array (List.length patterns) (pos e),patterns)
402425 | TAbstract(a,tl) as t when not (List.exists (fun t' -> shallow_eq t t') seen) ->
403 begin match TyperBase.get_abstract_froms a tl with
426 begin match TyperBase.get_abstract_froms ctx a tl with
404427 | [t2] -> pattern (t :: seen) t2
405428 | _ -> fail()
406429 end
445468 collect_field cf (apply_params a.a_params tl cf.cf_type) filter
446469 ) c.cl_ordered_statics;
447470 | _ ->
448 error (Printf.sprintf "Cannot field-match against %s" (s_type t)) (pos e)
471 typing_error (Printf.sprintf "Cannot field-match against %s" (s_type t)) (pos e)
449472 in
450473 collect_fields t None;
451474 let is_matchable cf =
462485 else
463486 patterns,fields
464487 ) ([],[]) !known_fields in
465 List.iter (fun ((s,_,_),e) -> if not (List.mem s fields) then error (Printf.sprintf "%s has no field %s" (s_type t) s) (pos e)) fl;
488 List.iter (fun ((s,_,_),e) -> if not (List.mem s fields) then typing_error (Printf.sprintf "%s has no field %s" (s_type t) s) (pos e)) fl;
466489 PatConstructor(con_fields fields (pos e),patterns)
467490 | EBinop(OpOr,e1,e2) ->
468491 let pctx1 = {pctx with current_locals = PMap.empty} in
550573 let e2 = collapse_case el in
551574 EBinop(OpOr,e,e2),punion (pos e) (pos e2)
552575 | [] ->
553 error "case without pattern" p
576 typing_error "case without pattern" p
554577 in
555578 let e = collapse_case el in
556579 let monos = List.map (fun _ -> mk_mono()) ctx.type_params in
908931
909932 (* Sane part *)
910933
911 let check_case com p (case,bindings,patterns) =
934 let check_case ctx p (case,bindings,patterns) =
912935 let p = List.map (fun (_,_,patterns) -> patterns) p in
913936 match u' p (copy p) (copy p) patterns [] [] with
914 | False -> com.warning "This case is unused" case.case_pos
915 | Pos p -> com.warning "This pattern is unused" p
937 | False -> Typecore.warning ctx WUnusedPattern "This case is unused" case.case_pos
938 | Pos p -> Typecore.warning ctx WUnusedPattern "This pattern is unused" p
916939 | True -> ()
917940
918 let check com cases =
941 let check ctx cases =
919942 ignore(List.fold_left (fun acc (case,bindings,patterns) ->
920 check_case com acc (case,bindings,patterns);
943 check_case ctx acc (case,bindings,patterns);
921944 if case.case_guard = None then acc @ [case,bindings,patterns] else acc
922945 ) [] cases)
923946 end
9871010 | ConArray i ->
9881011 ExtList.List.init i (fun i ->
9891012 let ei = make_int mctx.ctx.com.basic i e.epos in
990 Calls.acc_get mctx.ctx (Calls.array_access mctx.ctx e ei MGet e.epos) e.epos
1013 Calls.acc_get mctx.ctx (Calls.array_access mctx.ctx e ei MGet e.epos)
9911014 )
9921015 | ConConst _ | ConTypeExpr _ | ConStatic _ ->
9931016 []
11181141 | [],[] ->
11191142 bindings
11201143 | [],e :: _ ->
1121 error "Invalid match: Not enough patterns" e.epos
1144 typing_error "Invalid match: Not enough patterns" e.epos
11221145 | (_,p) :: _,[] ->
1123 error "Invalid match: Too many patterns" p
1146 typing_error "Invalid match: Too many patterns" p
11241147 in
11251148 let bindings = loop patterns subjects bindings in
11261149 if bindings = [] then dt else bind mctx (List.rev bindings) dt
11451168 | PatBind(v,pat1) -> loop ((v,pos pat,subject) :: bindings) pat1
11461169 | PatVariable _ | PatAny -> ()
11471170 | PatExtractor _ -> raise Extractor
1148 | _ -> error ("Unexpected pattern: " ^ (Pattern.to_string pat)) case.case_pos;
1171 | _ -> typing_error ("Unexpected pattern: " ^ (Pattern.to_string pat)) case.case_pos;
11491172 in
11501173 loop bindings (List.hd patterns)
11511174 ) cases;
11521175 let sigma = ConTable.fold (fun con arg_positions acc -> (con,ConTable.mem unguarded con,arg_positions) :: acc) sigma [] in
1176 let sigma = List.sort (fun ((_,p1),_,_) ((_,p2),_,_) -> p1.pmin - p2.pmin) sigma in
11531177 sigma,List.rev !null
11541178 in
11551179 let sigma,null = get_column_sigma cases in
12571281 switch mctx subject [] dt_fail
12581282 | _ ->
12591283 let dt = compile mctx subjects cases in
1260 Useless.check mctx.ctx.com cases;
1284 Useless.check mctx.ctx cases;
12611285 match vars with
12621286 | [] -> dt
12631287 | _ -> bind mctx vars dt
12741298 | SKValue
12751299 | SKEnum
12761300 | SKLength
1277
1278 exception Not_exhaustive
12791301
12801302 let s_subject v_lookup s e =
12811303 let rec loop top s e = match e.eexpr with
13411363 t_dynamic
13421364 in
13431365 let t = match fst con with
1344 | ConEnum(en,_) -> TEnum(en,List.map snd en.e_params)
1366 | ConEnum(en,_) -> TEnum(en,extract_param_types en.e_params)
13451367 | ConArray _ -> ctx.t.tarray t_dynamic
13461368 | ConConst ct ->
13471369 begin match ct with
13511373 | TBool _ -> ctx.t.tbool
13521374 | _ -> fail()
13531375 end
1354 | ConStatic({cl_kind = KAbstractImpl a},_) -> (TAbstract(a,List.map snd a.a_params))
1376 | ConStatic({cl_kind = KAbstractImpl a},_) -> (TAbstract(a,extract_param_types a.a_params))
13551377 | ConTypeExpr mt -> get_general_module_type ctx mt e.epos
13561378 | ConFields _ | ConStatic _ -> fail()
13571379 in
14081430 | _ -> kind = SKValue
14091431 in
14101432 List.iter (fun (con,unguarded,dt) ->
1411 if not (compatible_kind con) then error "Incompatible pattern" dt.dt_pos;
1433 if not (compatible_kind con) then typing_error "Incompatible pattern" dt.dt_pos;
14121434 if unguarded then ConTable.remove h con
14131435 ) cases;
14141436 let unmatched = ConTable.fold (fun con _ acc -> con :: acc) h [] in
14391461 | [] -> "_"
14401462 | _ -> String.concat " | " (List.sort Pervasives.compare sl)
14411463 in
1442 error (Printf.sprintf "Unmatched patterns: %s" (s_subject v_lookup s e_subject)) e_subject.epos
1464 typing_error (Printf.sprintf "Unmatched patterns: %s" (s_subject v_lookup s e_subject)) e_subject.epos
1465
1466 type dt_recursion =
1467 | Toplevel
1468 | AfterSwitch
1469 | Deep
14431470
14441471 let to_texpr ctx t_switch match_debug with_type dt =
14451472 let v_lookup = ref IntMap.empty in
14471474 let p = dt.dt_pos in
14481475 let c_type = match follow (Typeload.load_instance ctx (mk_type_path (["std"],"Type"),p) true) with TInst(c,_) -> c | t -> die "" __LOC__ in
14491476 let mk_index_call e =
1450 if not ctx.in_macro && not ctx.com.display.DisplayMode.dms_full_typing then
1477 if not ctx.com.is_macro_context && not ctx.com.display.DisplayMode.dms_full_typing then
14511478 (* If we are in display mode there's a chance that these fields don't exist. Let's just use a
14521479 (correctly typed) neutral value because it doesn't actually matter. *)
14531480 mk (TConst (TInt (Int32.of_int 0))) ctx.t.tint e.epos
14551482 mk (TEnumIndex e) com.basic.tint e.epos
14561483 in
14571484 let mk_name_call e =
1458 if not ctx.in_macro && not ctx.com.display.DisplayMode.dms_full_typing then
1485 if not ctx.com.is_macro_context && not ctx.com.display.DisplayMode.dms_full_typing then
14591486 mk (TConst (TString "")) ctx.t.tstring e.epos
14601487 else
14611488 let cf = PMap.find "enumConstructor" c_type.cl_statics in
14621489 make_static_call ctx c_type cf (fun t -> t) [e] com.basic.tstring e.epos
14631490 in
1464 let rec loop toplevel params dt = match dt.dt_texpr with
1491 let rec loop dt_rec params dt = match dt.dt_texpr with
14651492 | Some e ->
1466 e
1493 Some e
14671494 | None ->
14681495 let e = match dt.dt_t with
14691496 | Leaf case ->
14701497 begin match case.case_expr with
1471 | Some e -> e
1472 | None -> mk (TBlock []) ctx.t.tvoid case.case_pos
1498 | Some e -> Some e
1499 | None -> Some (mk (TBlock []) ctx.t.tvoid case.case_pos)
14731500 end
14741501 | Switch(_,[(ConFields _,_),_,dt],_) -> (* TODO: Can we improve this by making it more general? *)
1475 loop false params dt
1502 loop dt_rec params dt
14761503 | Switch(e_subject,cases,default) ->
1504 let dt_rec',toplevel = match dt_rec with
1505 | Toplevel -> AfterSwitch,true
1506 | AfterSwitch | Deep -> Deep,false
1507 in
14771508 let e_subject,unmatched,kind,finiteness = all_ctors ctx e_subject cases in
14781509 let unmatched = ExtList.List.filter_map (unify_constructor ctx params e_subject.etype) unmatched in
1479 let loop toplevel params dt =
1480 try Some (loop false params dt)
1481 with Not_exhaustive -> match with_type,finiteness with
1510 let loop params dt = match loop dt_rec' params dt with
1511 | None ->
1512 begin match with_type,finiteness with
14821513 | WithType.NoValue,Infinite when toplevel -> None
14831514 | _,CompileTimeFinite when unmatched = [] -> None
1484 | _ when ctx.com.display.DisplayMode.dms_error_policy = DisplayMode.EPIgnore -> None
1515 | _ when ignore_error ctx.com -> None
14851516 | _ -> report_not_exhaustive !v_lookup e_subject unmatched
1517 end
1518 | Some e ->
1519 Some e
14861520 in
14871521 let cases = ExtList.List.filter_map (fun (con,_,dt) -> match unify_constructor ctx params e_subject.etype con with
14881522 | Some(_,params) -> Some (con,dt,params)
15051539 | [],RunTimeFinite ->
15061540 None
15071541 | _ ->
1508 loop toplevel params default
1542 loop params default
15091543 in
15101544 let cases = ExtList.List.filter_map (fun (cons,dt,params) ->
1511 let eo = loop toplevel params dt in
1545 let eo = loop params dt in
15121546 begin match eo with
15131547 | None -> None
15141548 | Some e -> Some (List.map (Constructor.to_texpr ctx match_debug) (List.sort Constructor.compare cons),e)
15201554 | SKEnum -> if match_debug then mk_name_call e_subject else mk_index_call e_subject
15211555 | SKLength -> type_field_access ctx e_subject "length"
15221556 in
1523 begin match cases,e_default,with_type with
1557 let e = match cases,e_default,with_type with
15241558 | [_,e2],None,_ when (match finiteness with RunTimeFinite -> true | _ -> false) && not is_nullable_subject ->
15251559 {e2 with etype = t_switch}
15261560 | [[e1],e2],Some _,_
15451579 e_subject
15461580 in
15471581 mk (TSwitch(e_subject,cases,e_default)) t_switch dt.dt_pos
1548 end
1582 in
1583 Some e
15491584 | Guard(e,dt1,dt2) ->
1550 let e_then = loop false params dt1 in
1551 begin try
1552 let e_else = loop false params dt2 in
1553 mk (TIf(e,e_then,Some e_else)) t_switch (punion e_then.epos e_else.epos)
1554 with Not_exhaustive when with_type = NoValue ->
1555 mk (TIf(e,e_then,None)) ctx.t.tvoid (punion e.epos e_then.epos)
1585 (* Normal guards are considered toplevel if we're in the toplevel switch. *)
1586 let toplevel = match dt_rec with
1587 | Toplevel | AfterSwitch -> true
1588 | Deep -> false
1589 in
1590 let e_then = loop dt_rec params dt1 in
1591 begin match e_then with
1592 | None ->
1593 None
1594 | Some e_then ->
1595 let e_else = loop dt_rec params dt2 in
1596 begin match e_else with
1597 | Some e_else ->
1598 Some (mk (TIf(e,e_then,Some e_else)) t_switch (punion e_then.epos e_else.epos))
1599 | None ->
1600 if with_type = NoValue && toplevel then
1601 Some (mk (TIf(e,e_then,None)) ctx.t.tvoid (punion e.epos e_then.epos))
1602 else
1603 None
1604 end
15561605 end
15571606 | GuardNull(e,dt1,dt2) ->
1607 let toplevel = match dt_rec with
1608 | Toplevel -> true
1609 | Deep | AfterSwitch -> false
1610 in
15581611 let e_null = make_null e.etype e.epos in
15591612 let f_op e = mk (TBinop(OpEq,e,e_null)) ctx.t.tbool e.epos in
1560 let f = try
1561 let rec loop2 acc dt = match dt.dt_t with
1562 | GuardNull(e,dt1,dt3) when Decision_tree.equal_dt dt2 dt3 ->
1563 loop2 ((f_op e) :: acc) dt1
1564 | Guard(e,dt1,dt3) when Decision_tree.equal_dt dt2 dt3 ->
1565 loop2 (e :: acc) dt1
1566 | _ ->
1567 List.rev acc,dt
1568 in
1569 let conds,dt1 = loop2 [] dt1 in
1570 let e_then = loop toplevel params dt1 in
1571 (fun () ->
1572 let e_else = loop toplevel params dt2 in
1573 let e_cond = List.fold_left (fun e1 e2 -> binop OpBoolAnd e1 e2 ctx.t.tbool (punion e1.epos e2.epos)) (f_op e) conds in
1574 mk (TIf(e_cond,e_then,Some e_else)) t_switch (punion e_then.epos e_else.epos)
1575 )
1576 with Not_exhaustive ->
1577 if toplevel then (fun () -> loop toplevel params dt2)
1578 else if ctx.com.display.DisplayMode.dms_error_policy = DisplayMode.EPIgnore then (fun () -> mk (TConst TNull) (mk_mono()) dt2.dt_pos)
1579 else report_not_exhaustive !v_lookup e [(ConConst TNull,dt.dt_pos),dt.dt_pos]
1613 let rec loop2 acc dt = match dt.dt_t with
1614 | GuardNull(e,dt1,dt3) when Decision_tree.equal_dt dt2 dt3 ->
1615 loop2 ((f_op e) :: acc) dt1
1616 | Guard(e,dt1,dt3) when Decision_tree.equal_dt dt2 dt3 ->
1617 loop2 (e :: acc) dt1
1618 | _ ->
1619 List.rev acc,dt
15801620 in
1581 f()
1621 let conds,dt1 = loop2 [] dt1 in
1622 let e_cond = List.fold_left (fun e1 e2 -> binop OpBoolAnd e1 e2 ctx.t.tbool (punion e1.epos e2.epos)) (f_op e) conds in
1623 let e_then = loop dt_rec params dt1 in
1624 begin match e_then with
1625 | None ->
1626 if toplevel then
1627 loop dt_rec params dt2
1628 else if ignore_error ctx.com then
1629 Some (mk (TConst TNull) (mk_mono()) dt2.dt_pos)
1630 else
1631 report_not_exhaustive !v_lookup e [(ConConst TNull,dt.dt_pos),dt.dt_pos]
1632 | Some e_then ->
1633 let e_else = loop dt_rec params dt2 in
1634 begin match e_else with
1635 | None ->
1636 if toplevel then
1637 Some (mk (TIf(e_cond,e_then,None)) t_switch e_then.epos)
1638 else
1639 report_not_exhaustive !v_lookup e []
1640 | Some e_else ->
1641 Some (mk (TIf(e_cond,e_then,Some e_else)) t_switch (punion e_then.epos e_else.epos))
1642 end
1643 end
15821644 | Bind(bl,dt) ->
15831645 let el = List.map (fun (v,p,e) ->
15841646 v_lookup := IntMap.add v.v_id e !v_lookup;
15851647 mk (TVar(v,Some e)) com.basic.tvoid p
15861648 ) bl in
1587 let e = loop toplevel params dt in
1588 mk (TBlock (el @ [e])) e.etype dt.dt_pos
1649 let e = loop dt_rec params dt in
1650 Option.map (fun e -> mk (TBlock (el @ [e])) e.etype dt.dt_pos) e;
15891651 | Fail ->
1590 raise Not_exhaustive
1652 None
15911653 in
1592 dt.dt_texpr <- Some e;
1654 dt.dt_texpr <- e;
15931655 e
15941656 in
1595 let params = List.map snd ctx.type_params in
1596 let e = loop true params dt in
1597 Texpr.duplicate_tvars e
1657 let params = extract_param_types ctx.type_params in
1658 let e = loop Toplevel params dt in
1659 match e with
1660 | None ->
1661 typing_error "Unmatched patterns: _" p;
1662 | Some e ->
1663 Texpr.duplicate_tvars e
15981664 end
15991665
16001666 module Match = struct
16711737 print_endline (Decision_tree.to_string dt);
16721738 print_endline "DECISION TREE END";
16731739 end;
1674 let e = try
1740 let e =
16751741 let t_switch = infer_switch_type() in
16761742 (match tmono with
16771743 | Some t when allow_min_void && ExtType.is_void (follow t) -> ()
16791745 | _ -> ()
16801746 );
16811747 TexprConverter.to_texpr ctx t_switch match_debug with_type dt
1682 with TexprConverter.Not_exhaustive ->
1683 error "Unmatched patterns: _" p;
16841748 in
16851749 if match_debug then begin
16861750 print_endline "TEXPR BEGIN";
6969 (**
7070 Check for explicit `Null<>` typing
7171 *)
72 let rec is_nullable_type = function
72 let rec is_nullable_type ?(dynamic_is_nullable=false) = function
7373 | TMono r ->
7474 (match r.tm_type with None -> false | Some t -> is_nullable_type t)
7575 | TAbstract ({ a_path = ([],"Null") },[t]) ->
7676 true
77 | TAbstract ({ a_path = ([],"Any") },[]) ->
78 false
7779 | TAbstract (a,tl) when not (Meta.has Meta.CoreType a.a_meta) ->
7880 is_nullable_type (apply_params a.a_params tl a.a_this)
7981 | TLazy f ->
8082 is_nullable_type (lazy_type f)
8183 | TType (t,tl) ->
82 is_nullable_type (apply_params t.t_params tl t.t_type)
84 is_nullable_type (apply_typedef t tl)
85 | (TDynamic _) as t ->
86 dynamic_is_nullable && t == t_dynamic
8387 | _ ->
8488 false
89 (*
90 (**
91 Check if `callee` represents `trace`
92 *)
93 let is_trace_expr callee =
94 match callee.eexpr with
95 | TIdent "`trace" -> true
96 | _ -> false *)
97
8598
8699 (**
87100 If `expr` is a TCast or TMeta, returns underlying expression (recursively bypassing nested casts).
234247 | _, TMono t ->
235248 (match t.tm_type with None -> () | Some t -> self#unify a t)
236249 | TType (t,tl), _ ->
237 self#unify_rec a b (fun() -> self#unify (apply_params t.t_params tl t.t_type) b)
250 self#unify_rec a b (fun() -> self#unify (apply_typedef t tl) b)
238251 | _, TType (t,tl) ->
239 self#unify_rec a b (fun() -> self#unify a (apply_params t.t_params tl t.t_type))
252 self#unify_rec a b (fun() -> self#unify a (apply_typedef t tl))
240253 | TAbstract (abstr,tl), _ when not (Meta.has Meta.CoreType abstr.a_meta) ->
241254 self#unify (apply_params abstr.a_params tl abstr.a_this) b
242255 | _, TAbstract (abstr,tl) when not (Meta.has Meta.CoreType abstr.a_meta) ->
307320 end
308321
309322 (**
310 Checks if execution of provided expression is guaranteed to be terminated with `return`, `throw`, `break` or `continue`.
311 *)
312 let rec is_dead_end e =
313 match e.eexpr with
314 | TThrow _ -> true
315 | TReturn _ -> true
316 | TBreak -> true
317 | TContinue -> true
318 | TWhile (_, body, DoWhile) -> is_dead_end body
319 | TIf (_, if_body, Some else_body) -> is_dead_end if_body && is_dead_end else_body
320 | TBlock exprs -> List.exists is_dead_end exprs
321 | TMeta (_, e) -> is_dead_end e
322 | TCast (e, _) -> is_dead_end e
323 | _ -> false
324
325 (**
326323 Check if `expr` is a `trace` (not a call, but identifier itself)
327324 *)
328325 let is_trace expr =
340337 | TAbstract ({ a_path = ([],"Null") }, [t]) -> unfold_null t
341338 | TAbstract (abstr,tl) when not (Meta.has Meta.CoreType abstr.a_meta) -> unfold_null (apply_params abstr.a_params tl abstr.a_this)
342339 | TLazy f -> unfold_null (lazy_type f)
343 | TType (t,tl) -> unfold_null (apply_params t.t_params tl t.t_type)
340 | TType (t,tl) -> unfold_null (apply_typedef t tl)
344341 | _ -> t
345342
346343 (**
356353 | FDynamic name -> name
357354 | FClosure (_, { cf_name = name }) -> name
358355 | FEnum (_, { ef_name = name }) -> name
359
360 let rec can_pass_type src dst =
361 if is_nullable_type src && not (is_nullable_type dst) then
362 false
363 else
364 (* TODO *)
365 match dst with
366 | TMono r -> (match r.tm_type with None -> true | Some t -> can_pass_type src t)
367 | TEnum (_, params) -> true
368 | TInst _ -> true
369 | TType (t, tl) -> can_pass_type src (apply_params t.t_params tl t.t_type)
370 | TFun _ -> true
371 | TAnon _ -> true
372 | TDynamic _ -> true
373 | TLazy _ -> true
374 | TAbstract ({ a_path = ([],"Null") }, [t]) -> true
375 | TAbstract _ -> true
376356
377357 (**
378358 Collect nullable local vars which are checked against `null`.
772752 scopes <- scope :: scopes;
773753 List.iter (fun (v, _) -> scope#declare_var v) fn.tf_args
774754 (**
755 Should be called upon standalone block declaration.
756 *)
757 method block_declared =
758 let scope = new safety_scope mode STNormal self#get_current_scope#get_safe_locals self#get_current_scope#get_never_safe in
759 scopes <- scope :: scopes
760 (**
775761 Should be called upon entering a loop.
776762 *)
777763 method loop_declared e =
920906 self#get_current_scope#reset_to initial_safe;
921907 (** execute `else_body` with known not-null variables *)
922908 let handle_dead_end body safe_vars =
923 if is_dead_end body then
909 if DeadEnd.has_dead_end body then
924910 List.iter self#get_current_scope#add_to_safety safe_vars
925911 in
926912 (match else_body with
10561042 | TReturn (Some e) -> self#is_nullable_expr e
10571043 | TBinop ((OpAssign | OpAssignOp _), _, right) -> self#is_nullable_expr right
10581044 | TBlock exprs ->
1059 (match exprs with
1045 local_safety#block_declared;
1046 let rec traverse exprs =
1047 match exprs with
1048 | [] -> false
1049 | [e] -> self#is_nullable_expr e
1050 | e :: exprs ->
1051 (match e.eexpr with
1052 | TVar (v,_) -> local_safety#declare_var v
1053 | _ -> ()
1054 );
1055 traverse exprs
1056 in
1057 let is_nullable = traverse exprs in
1058 local_safety#scope_closed;
1059 is_nullable
1060 (* (match exprs with
10601061 | [] -> false
10611062 | _ -> self#is_nullable_expr (List.hd (List.rev exprs))
1062 )
1063 ) *)
10631064 | TIf _ ->
10641065 let nullable = ref false in
10651066 let check body = nullable := !nullable || self#is_nullable_expr body in
10841085 with Not_found -> false)
10851086 fields
10861087 | _, _ ->
1087 if self#is_nullable_expr expr && not (is_nullable_type to_type) then
1088 if self#is_nullable_expr expr && not (is_nullable_type ~dynamic_is_nullable:true to_type) then
10881089 false
10891090 else begin
10901091 let expr_type = unfold_null expr.etype in
10981099 true
10991100 | e ->
11001101 fail ~msg:"Null safety unification failure" expr.epos __POS__
1101 (* can_pass_type expr.etype to_type *)
11021102 end
11031103 (**
11041104 Should be called for the root expressions of a method or for then initialization expressions of fields.
11491149 Check expressions in a block
11501150 *)
11511151 method private check_block exprs p =
1152 match exprs with
1153 | [] -> ()
1154 | e :: rest ->
1155 self#check_expr e;
1156 self#check_block rest p
1152 local_safety#block_declared;
1153 let rec traverse exprs =
1154 match exprs with
1155 | [] -> ()
1156 | e :: rest ->
1157 self#check_expr e;
1158 traverse rest
1159 in
1160 traverse exprs;
1161 local_safety#scope_closed
11571162 (**
11581163 Don't allow to use nullable values as items in declaration of not-nullable arrays
11591164 *)
88 open Fields
99 open FieldAccess
1010
11 class value_reference (ctx : typer) =
12
13 object(self)
14 val vars = DynArray.create ()
15
16 method get_vars = DynArray.to_list vars
17
18 method as_var name e =
19 let v = alloc_var VGenerated name e.etype e.epos in
20 DynArray.add vars (v,e);
21 mk (TLocal v) v.v_type v.v_pos
22
23 method private get_expr_aux depth name e =
24 let rec loop depth name e = match (Texpr.skip e).eexpr with
25 | TLocal _ | TTypeExpr _ | TConst _ ->
26 e
27 | TField(ef,fa) when depth = 0 ->
28 let ef = loop (depth + 1) "fh" ef in
29 {e with eexpr = TField(ef,fa)}
30 | TArray(e1,e2) when depth = 0 ->
31 let e1 = loop (depth + 1) "base" e1 in
32 let e2 = loop (depth + 1) "index" e2 in
33 {e with eexpr = TArray(e1,e2)}
34 | _ ->
35 self#as_var name e
36 in
37 loop depth name e
38
39 method get_expr name e =
40 self#get_expr_aux 0 name e
41
42 method get_expr_part name e =
43 self#get_expr_aux 1 name e
44
45 method to_texpr e =
46 begin match self#get_vars with
47 | [] ->
48 e
49 | vl ->
50 let el = List.map (fun (v,e) ->
51 mk (TVar(v,Some e)) ctx.t.tvoid v.v_pos
52 ) vl in
53 let e = mk (TBlock (el @ [e])) e.etype e.epos in
54 {e with eexpr = TMeta((Meta.MergeBlock,[],null_pos),e)}
55 end
56
57 method to_texpr_el el e =
58 let vl = self#get_vars in
59 let el_vars = List.map (fun (v,e) ->
60 mk (TVar(v,Some e)) ctx.t.tvoid v.v_pos
61 ) vl in
62 let e = mk (TBlock (el_vars @ el @ [e])) e.etype e.epos in
63 {e with eexpr = TMeta((Meta.MergeBlock,[],null_pos),e)}
64 end
11 let check_error ctx err p depth = match err with
12 | Module_not_found ([],name) when Diagnostics.error_in_diagnostics_run ctx.com p ->
13 DisplayToplevel.handle_unresolved_identifier ctx name p true
14 | _ ->
15 Common.located_display_error ~depth ctx.com (error_msg p err)
6516
6617 module BinopResult = struct
6718
13081 let get_type br = match br with
13182 | BinopNormal bn -> bn.binop_type
13283 | BinopSpecial(e,_) -> e.etype
84
85 let needs_assign = function
86 | BinopNormal _ -> true
87 | BinopSpecial(_,needs_assign) -> needs_assign
13388 end
13489
13590 let check_assign ctx e =
136 if ctx.com.display.dms_error_policy <> EPIgnore then match e.eexpr with
137 | TLocal v when has_var_flag v VFinal ->
138 error "Cannot assign to final" e.epos
91 match e.eexpr with
92 | TLocal v when has_var_flag v VFinal && not (Common.ignore_error ctx.com) ->
93 typing_error "Cannot assign to final" e.epos
13994 | TLocal {v_extra = None} | TArray _ | TField _ | TIdent _ ->
14095 ()
14196 | TConst TThis | TTypeExpr _ when ctx.untyped ->
14297 ()
14398 | _ ->
144 invalid_assign e.epos
99 if not (Common.ignore_error ctx.com) then
100 invalid_assign e.epos
145101
146102 type type_class =
147103 | KInt
245201 | KInt | KFloat | KString -> e
246202 | KUnk | KDyn | KNumParam _ | KStrParam _ | KOther ->
247203 let std = type_type ctx ([],"Std") e.epos in
248 let acc = acc_get ctx (type_field_default_cfg ctx std "string" e.epos (MCall []) with_type) e.epos in
204 let acc = acc_get ctx (type_field_default_cfg ctx std "string" e.epos (MCall []) with_type) in
249205 ignore(follow acc.etype);
250206 let acc = (match acc.eexpr with TField (e,FClosure (Some (c,tl),f)) -> { acc with eexpr = TField (e,FInstance (c,tl,f)) } | _ -> acc) in
251207 make_call ctx acc [e] ctx.t.tstring e.epos
252208 | KAbstract (a,tl) ->
253209 try
254210 AbstractCast.cast_or_unify_raise ctx tstring e p
255 with Error (Unify _,_) ->
211 with Error (Unify _,_,_) ->
256212 loop (Abstract.get_underlying_type a tl)
257213 in
258214 loop e.etype
333289 | KOther, _
334290 | _ , KOther ->
335291 let pr = print_context() in
336 error ("Cannot add " ^ s_type pr e1.etype ^ " and " ^ s_type pr e2.etype) p
292 typing_error ("Cannot add " ^ s_type pr e1.etype ^ " and " ^ s_type pr e2.etype) p
337293 )
338294 | OpAnd
339295 | OpOr
377333 | OpNotEq ->
378334 let e1,e2 = try
379335 (* we only have to check one type here, because unification fails if one is Void and the other is not *)
380 (match follow e2.etype with TAbstract({a_path=[],"Void"},_) -> error "Cannot compare Void" p | _ -> ());
336 (match follow e2.etype with TAbstract({a_path=[],"Void"},_) -> typing_error "Cannot compare Void" p | _ -> ());
381337 AbstractCast.cast_or_unify_raise ctx e2.etype e1 p,e2
382 with Error (Unify _,_) ->
338 with Error (Unify _,_,_) ->
383339 e1,AbstractCast.cast_or_unify ctx e1.etype e2 p
384340 in
385341 if not ctx.com.config.pf_supports_function_equality then begin match e1.eexpr, e2.eexpr with
386342 | TConst TNull , _ | _ , TConst TNull -> ()
387343 | _ ->
388344 match follow e1.etype, follow e2.etype with
389 | TFun _ , _ | _, TFun _ -> ctx.com.warning "Comparison of function values is unspecified on this target, use Reflect.compareMethods instead" p
345 | TFun _ , _ | _, TFun _ -> warning ctx WClosureCompare "Comparison of function values is unspecified on this target, use Reflect.compareMethods instead" p
390346 | _ -> ()
391347 end;
392348 mk_op e1 e2 ctx.t.tbool
425381 | KOther , _
426382 | _ , KOther ->
427383 let pr = print_context() in
428 error ("Cannot compare " ^ s_type pr e1.etype ^ " and " ^ s_type pr e2.etype) p
384 typing_error ("Cannot compare " ^ s_type pr e1.etype ^ " and " ^ s_type pr e2.etype) p
429385 );
430386 mk_op e1 e2 ctx.t.tbool
431387 | OpBoolAnd
440396 unify ctx e2.etype tint e2.epos;
441397 BinopSpecial (mk (TNew ((match t with TInst (c,[]) -> c | _ -> die "" __LOC__),[],[e1;e2])) t p,false)
442398 | OpArrow ->
443 error "Unexpected =>" p
399 typing_error "Unexpected =>" p
444400 | OpIn ->
445 error "Unexpected in" p
401 typing_error "Unexpected in" p
402 | OpNullCoal
446403 | OpAssign
447404 | OpAssignOp _ ->
448405 die "" __LOC__
451408 let map = apply_params a.a_params tl in
452409 let make op_cf cf e1 e2 tret needs_assign swapped =
453410 if cf.cf_expr = None && not (has_class_field_flag cf CfExtern) then begin
454 if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx "Recursive operator method" p;
411 if not (Meta.has Meta.NoExpr cf.cf_meta) then Common.display_error ctx.com "Recursive operator method" p;
455412 if not (Meta.has Meta.CoreType a.a_meta) then begin
456413 (* for non core-types we require that the return type is compatible to the native result type *)
457414 let result = make_binop ctx op {e1 with etype = Abstract.follow_with_abstracts e1.etype} {e1 with etype = Abstract.follow_with_abstracts e2.etype} is_assign_op with_type p in
458415 let t_expected = BinopResult.get_type result in
459416 begin try
460 unify_raise ctx tret t_expected p
461 with Error (Unify _,_) ->
417 unify_raise tret t_expected p
418 with Error (Unify _,_,depth) ->
462419 match follow tret with
463420 | TAbstract(a,tl) when type_iseq (Abstract.get_underlying_type a tl) t_expected ->
464421 ()
465422 | _ ->
466423 let st = s_type (print_context()) in
467 error (Printf.sprintf "The result of this operation (%s) is not compatible with declared return type %s" (st t_expected) (st tret)) p
424 typing_error ~depth (Printf.sprintf "The result of this operation (%s) is not compatible with declared return type %s" (st t_expected) (st tret)) p
468425 end;
469426 end;
470 BinopResult.create_normal op e1 e2 tret needs_assign swapped p
427 (*
428 If the `@:op`-field has no expr, then user wants the semantics of an underlying type.
429 which is supposed to make an assignment for AssignOp's.
430 Hence we use `is_assign_op` here instead of `needs_assign`.
431 *)
432 BinopResult.create_normal op e1 e2 tret is_assign_op swapped p
471433 end else if swapped then begin
472434 let vr = new value_reference ctx in
473435 let e2' = vr#as_var "lhs" e2 in
487449 | _ ->
488450 ()
489451 end;
490 let rec loop find_op ol = match ol with
452 let rec loop find_op ol =
453 match ol with
491454 | (op_cf,cf) :: ol when op_cf = find_op ->
492455 let is_impl = has_class_field_flag cf CfImpl in
493 begin match follow cf.cf_type with
494 | TFun([(_,_,t1);(_,_,t2)],tret) ->
456 begin
457 match follow cf.cf_type with
458 | TFun((_,_,t1) :: (_,_,t2) :: pos_infos, tret) ->
459 (match pos_infos with
460 | [] -> ()
461 | [_,true,t] when is_pos_infos t -> ()
462 | _ -> die ~p:cf.cf_pos ("Unexpected arguments list of function " ^ cf.cf_name) __LOC__
463 );
495464 let check e1 e2 swapped =
496465 let map_arguments () =
497466 let monos = Monomorph.spawn_constrained_monos (fun t -> t) cf.cf_params in
526495 in
527496 begin try
528497 check e1 e2 false
529 with Error (Unify _,_) | Unify_error _ -> try
498 with Error (Unify _,_,_) | Unify_error _ -> try
530499 if not (Meta.has Meta.Commutative cf.cf_meta) then raise Not_found;
531500 check e2 e1 true
532 with Not_found | Error (Unify _,_) | Unify_error _ ->
501 with Not_found | Error (Unify _,_,_) | Unify_error _ ->
533502 loop find_op ol
534503 end
535504 | _ ->
583552
584553 let type_assign ctx e1 e2 with_type p =
585554 let e1 = !type_access_ref ctx (fst e1) (snd e1) (MSet (Some e2)) with_type in
586 let type_rhs with_type = type_expr ctx e2 with_type in
555 let type_rhs with_type = try
556 type_expr ctx e2 with_type
557 with Error(e,p,depth) ->
558 check_error ctx e p depth;
559 Texpr.Builder.make_null t_dynamic (pos e2)
560 in
587561 let assign_to e1 =
588562 let e2 = type_rhs (WithType.with_type e1.etype) in
589563 let e2 = AbstractCast.cast_or_unify ctx e1.etype e2 p in
590564 check_assign ctx e1;
591565 (match e1.eexpr , e2.eexpr with
592 | TLocal i1 , TLocal i2 when i1 == i2 -> error "Assigning a value to itself" p
566 | TLocal i1 , TLocal i2 when i1 == i2 -> typing_error "Assigning a value to itself" p
593567 | TField ({ eexpr = TConst TThis },FInstance (_,_,f1)) , TField ({ eexpr = TConst TThis },FInstance (_,_,f2)) when f1 == f2 ->
594 error "Assigning a value to itself" p
568 typing_error "Assigning a value to itself" p
595569 | _ , _ -> ());
596570 mk (TBinop (OpAssign,e1,e2)) e1.etype p
597571 in
598572 match e1 with
599 | AKNo s -> error ("Cannot access field or identifier " ^ s ^ " for writing") p
600 | AKUsingField _ ->
601 error "Invalid operation" p
573 | AKNo(_,p) ->
574 typing_error "This expression cannot be accessed for writing" p
575 | AKUsingField _ | AKSafeNav _ ->
576 typing_error "Invalid operation" p
602577 | AKExpr { eexpr = TLocal { v_kind = VUser TVOLocalFunction; v_name = name } } ->
603 error ("Cannot access function " ^ name ^ " for writing") p
578 typing_error ("Cannot access function " ^ name ^ " for writing") p
604579 | AKField fa ->
605580 let ef = FieldAccess.get_field_expr fa FWrite in
606581 assign_to ef
611586 dispatcher#accessor_call fa [] [e2]
612587 | AKAccess(a,tl,c,ebase,ekey) ->
613588 let e2 = type_rhs WithType.value in
614 mk_array_set_call ctx (AbstractCast.find_array_access ctx a tl ekey (Some e2) p) c ebase p
589 mk_array_set_call ctx (AbstractCast.find_array_write_access ctx a tl ekey e2 p) c ebase p
615590 | AKResolve(sea,name) ->
616591 let eparam = sea.se_this in
617592 let e_name = Texpr.Builder.make_string ctx.t name null_pos in
619594 | AKUsingAccessor sea ->
620595 let fa_set = match FieldAccess.resolve_accessor sea.se_access (MSet (Some e2)) with
621596 | AccessorFound fa -> fa
622 | _ -> error "Could not resolve accessor" p
597 | _ -> typing_error "Could not resolve accessor" p
623598 in
624599 let dispatcher = new call_dispatcher ctx (MCall [e2]) with_type p in
625600 dispatcher#field_call fa_set [sea.se_this] [e2]
660635 let type_assign_op ctx op e1 e2 with_type p =
661636 let field_rhs_by_name op name ev with_type =
662637 let access_get = type_field_default_cfg ctx ev name p MGet with_type in
663 let e_get = acc_get ctx access_get p in
664 e_get.etype,type_binop2 ctx op e_get e2 true (WithType.with_type e_get.etype) p
638 let e_get = acc_get ctx access_get in
639 e_get.etype,type_binop2 ctx op e_get e2 true WithType.value p
665640 in
666641 let field_rhs op cf ev =
667642 field_rhs_by_name op cf.cf_name ev (WithType.with_type cf.cf_type)
668643 in
669644 let assign vr e r_rhs =
670 check_assign ctx e;
645 if BinopResult.needs_assign r_rhs then check_assign ctx e;
671646 let assign e_rhs =
672647 let e_rhs = AbstractCast.cast_or_unify ctx e.etype e_rhs p in
673648 match e_rhs.eexpr with
689664 vr#to_texpr e
690665 in
691666 (match !type_access_ref ctx (fst e1) (snd e1) (MSet (Some e2)) with_type with
692 | AKNo s ->
667 | AKNo(_,p) ->
693668 (* try abstract operator overloading *)
694 (try type_non_assign_op ctx op e1 e2 true true with_type p
695 with Not_found -> error ("Cannot access field or identifier " ^ s ^ " for writing") p
696 )
697 | AKUsingField _ ->
698 error "Invalid operation" p
669 begin try
670 type_non_assign_op ctx op e1 e2 true true with_type p
671 with Not_found ->
672 typing_error "This expression cannot be accessed for writing" p
673 end
674 | AKUsingField _ | AKSafeNav _ ->
675 typing_error "Invalid operation" p
699676 | AKExpr e ->
700677 let e,vr = process_lhs_expr ctx "lhs" e in
701 let e_rhs = type_binop2 ctx op e e2 true (WithType.with_type e.etype) p in
678 let e_rhs = type_binop2 ctx op e e2 true WithType.value p in
702679 assign vr e e_rhs
703680 | AKField fa ->
704681 let vr = new value_reference ctx in
717694 let t_lhs,e_rhs = field_rhs op fa.fa_field ef in
718695 set vr sea.se_access t_lhs e_rhs [ef]
719696 | AKAccess(a,tl,c,ebase,ekey) ->
720 let cf_get,tf_get,r_get,ekey,_ = AbstractCast.find_array_access ctx a tl ekey None p in
697 let cf_get,tf_get,r_get,ekey = AbstractCast.find_array_read_access ctx a tl ekey p in
721698 (* bind complex keys to a variable so they do not make it into the output twice *)
722699 let save = save_locals ctx in
723700 let maybe_bind_to_temp e = match Optimizer.make_constant_expression ctx e with
729706 in
730707 let ekey,ekey' = maybe_bind_to_temp ekey in
731708 let ebase,ebase' = maybe_bind_to_temp ebase in
732 let eget = mk_array_get_call ctx (cf_get,tf_get,r_get,ekey,None) c ebase p in
733 let eget = type_binop2 ctx op eget e2 true (WithType.with_type eget.etype) p in
709 let eget = mk_array_get_call ctx (cf_get,tf_get,r_get,ekey) c ebase p in
710 let eget = type_binop2 ctx op eget e2 true WithType.value p in
734711 let vr = new value_reference ctx in
735712 let eget = BinopResult.to_texpr vr eget (fun e -> e) in
736713 unify ctx eget.etype r_get p;
737 let cf_set,tf_set,r_set,ekey,eget = AbstractCast.find_array_access ctx a tl ekey (Some eget) p in
738 let eget = match eget with None -> die "" __LOC__ | Some e -> e in
714 let cf_set,tf_set,r_set,ekey,eget = AbstractCast.find_array_write_access ctx a tl ekey eget p in
739715 let et = type_module_type ctx (TClassDecl c) None p in
740716 let e = match cf_set.cf_expr,cf_get.cf_expr with
741717 | None,None ->
751727 | el -> mk (TBlock el) r_set p
752728 end
753729 | _ ->
754 error "Invalid array access getter/setter combination" p
730 typing_error "Invalid array access getter/setter combination" p
755731 in
756732 save();
757733 vr#to_texpr e
771747 | OpAssign ->
772748 type_assign ctx e1 e2 with_type p
773749 | OpAssignOp (OpBoolAnd | OpBoolOr) ->
774 error "The operators ||= and &&= are not supported" p
750 typing_error "The operators ||= and &&= are not supported" p
775751 | OpAssignOp op ->
776752 type_assign_op ctx op e1 e2 with_type p
777753 | _ ->
814790 raise Not_found
815791 in
816792 let unexpected_spread p =
817 error "Spread unary operator is only allowed for unpacking the last argument in a call with rest arguments" p
793 typing_error "Spread unary operator is only allowed for unpacking the last argument in a call with rest arguments" p
818794 in
819795 let make e =
820796 let check_int () =
828804 in
829805 let t = match op with
830806 | Not ->
831 if flag = Postfix then error "Postfix ! is not supported" p;
807 if flag = Postfix then Common.display_error ctx.com "Postfix ! is not supported" p;
832808 unify ctx e.etype ctx.t.tbool e.epos;
833809 ctx.t.tbool
834810 | NegBits ->
856832 unexpected_spread p
857833 | Not | Neg | NegBits ->
858834 let access_get = !type_access_ref ctx (fst e) (snd e) MGet WithType.value (* WITHTYPETODO *) in
859 let e = acc_get ctx access_get p in
835 let e = acc_get ctx access_get in
860836 find_overload_or_make e
861837 | Increment | Decrement ->
862838 let binop = if op = Increment then OpAdd else OpSub in
870846 in
871847 let read_on vr ef fa =
872848 let access_get = type_field_default_cfg ctx ef fa.fa_field.cf_name p MGet WithType.value in
873 let e_lhs = acc_get ctx access_get p in
849 let e_lhs = acc_get ctx access_get in
874850 let e_lhs,e_out = maybe_tempvar_postfix vr e_lhs in
875851 e_lhs,e_out
876852 in
880856 in
881857 let access_set = !type_access_ref ctx (fst e) (snd e) (MSet None) WithType.value (* WITHTYPETODO *) in
882858 match access_set with
883 | AKNo name ->
884 error ("The field or identifier " ^ name ^ " is not accessible for writing") p
859 | AKNo(acc,p) ->
860 begin try
861 try_abstract_unop_overloads (acc_get ctx acc)
862 with Not_found ->
863 typing_error "This expression cannot be accessed for writing" p
864 end
885865 | AKExpr e ->
886866 find_overload_or_make e
887867 | AKField fa ->
894874 find_overload_or_make e,None
895875 | _ ->
896876 let e_set = FieldAccess.get_field_expr {fa with fa_on = ef} FWrite in
897 let e_lhs = acc_get ctx access_get p in
877 let e_lhs = acc_get ctx access_get in
898878 let e_lhs,e_out = maybe_tempvar_postfix vr e_lhs in
899879 let e_op = mk (TBinop(binop,e_lhs,e_one)) e_lhs.etype p in
900880 mk (TBinop(OpAssign,e_set,e_op)) e_set.etype p,e_out
923903 let evar_key = mk (TVar(v_key,Some ekey)) ctx.com.basic.tvoid ekey.epos in
924904 let ekey = mk (TLocal v_key) ekey.etype ekey.epos in
925905 (* get *)
926 let e_get = mk_array_get_call ctx (AbstractCast.find_array_access_raise ctx a tl ekey None p) c ebase p in
906 let e_get = mk_array_get_call ctx (AbstractCast.find_array_read_access_raise ctx a tl ekey p) c ebase p in
927907 let v_get = alloc_var VGenerated "tmp" e_get.etype e_get.epos in
928908 let ev_get = mk (TLocal v_get) v_get.v_type p in
929909 let evar_get = mk (TVar(v_get,Some e_get)) ctx.com.basic.tvoid p in
931911 let e_one = mk (TConst (TInt (Int32.of_int 1))) ctx.com.basic.tint p in
932912 let e_op = mk (TBinop((if op = Increment then OpAdd else OpSub),ev_get,e_one)) ev_get.etype p in
933913 (* set *)
934 let e_set = mk_array_set_call ctx (AbstractCast.find_array_access_raise ctx a tl ekey (Some e_op) p) c ebase p in
914 let e_set = mk_array_set_call ctx (AbstractCast.find_array_write_access_raise ctx a tl ekey e_op p) c ebase p in
935915 let el = evar_key :: evar_get :: e_set :: (if flag = Postfix then [ev_get] else []) in
936916 mk (TBlock el) e_set.etype p
937917 with Not_found ->
938 let e = mk_array_get_call ctx (AbstractCast.find_array_access ctx a tl ekey None p) c ebase p in
918 let e = mk_array_get_call ctx (AbstractCast.find_array_read_access ctx a tl ekey p) c ebase p in
939919 find_overload_or_make e
940920 end
941 | AKUsingField _ | AKResolve _ ->
942 error "Invalid operation" p
921 | AKUsingField _ | AKResolve _ | AKSafeNav _ ->
922 typing_error "Invalid operation" p
9191 resolve_instance_overload is_ctor map_type c cf.cf_name el
9292 else match unify_cf map_type c cf el with
9393 | Some fcc -> Some (fcc.fc_data)
94 | None -> Some(c,cf,List.map snd cf.cf_params)
94 | None -> Some(c,cf,extract_param_types cf.cf_params)
9595
9696 let maybe_resolve_constructor_overload c tl el =
9797 let cf,c,tl = get_constructor_class c tl in
0 open Globals
1 open Ast
2 open Type
3 open Common
4 open Typecore
5
6 let get_native_repr md pos =
7 let path, meta = match md with
8 | TClassDecl cl -> cl.cl_path, cl.cl_meta
9 | TEnumDecl e -> e.e_path, e.e_meta
10 | TTypeDecl t -> t.t_path, t.t_meta
11 | TAbstractDecl a -> a.a_path, a.a_meta
12 in
13 let rec loop acc = function
14 | (Meta.JavaCanonical,[EConst(String(pack,_)),_; EConst(String(name,_)),_],_) :: _ ->
15 ExtString.String.nsplit pack ".", name
16 | (Meta.Native,[EConst(String(name,_)),_],_) :: meta ->
17 loop (Ast.parse_path name) meta
18 | _ :: meta ->
19 loop acc meta
20 | [] ->
21 acc
22 in
23 let pack, name = loop path meta in
24 match pack with
25 | [] ->
26 (EConst(Ident(name)), pos)
27 | hd :: tl ->
28 let rec loop pack expr = match pack with
29 | hd :: tl ->
30 loop tl (efield(expr,hd),pos)
31 | [] ->
32 (efield(expr,name),pos)
33 in
34 loop tl (EConst(Ident(hd)),pos)
35
36 let rec process_meta_argument ?(toplevel=true) ctx expr = match expr.eexpr with
37 | TField(e,f) ->
38 (efield(process_meta_argument ~toplevel:false ctx e,field_name f),expr.epos)
39 | TConst(TInt i) ->
40 (EConst(Int (Int32.to_string i, None)), expr.epos)
41 | TConst(TFloat f) ->
42 (EConst(Float (f, None)), expr.epos)
43 | TConst(TString s) ->
44 (EConst(String(s,SDoubleQuotes)), expr.epos)
45 | TConst TNull ->
46 (EConst(Ident "null"), expr.epos)
47 | TConst(TBool b) ->
48 (EConst(Ident (string_of_bool b)), expr.epos)
49 | TCast(e,_) | TMeta(_,e) | TParenthesis(e) ->
50 process_meta_argument ~toplevel ctx e
51 | TTypeExpr md when toplevel ->
52 let p = expr.epos in
53 if ctx.com.platform = Cs then
54 (ECall( (EConst(Ident "typeof"), p), [get_native_repr md expr.epos] ), p)
55 else
56 (efield(get_native_repr md expr.epos, "class"), p)
57 | TTypeExpr md ->
58 get_native_repr md expr.epos
59 | _ ->
60 display_error ctx.com "This expression is too complex to be a strict metadata argument" expr.epos;
61 (EConst(Ident "null"), expr.epos)
62
63 let handle_fields ctx fields_to_check with_type_expr =
64 List.map (fun ((name,_,_),expr) ->
65 let pos = snd expr in
66 let field = (efield(with_type_expr,name), pos) in
67 let fieldexpr = (EConst(Ident name),pos) in
68 let left_side = match ctx.com.platform with
69 | Cs -> field
70 | Java -> (ECall(field,[]),pos)
71 | _ -> die "" __LOC__
72 in
73
74 let left = type_expr ctx left_side NoValue in
75 let right = type_expr ctx expr (WithType.with_type left.etype) in
76 unify ctx left.etype right.etype (snd expr);
77 (EBinop(Ast.OpAssign,fieldexpr,process_meta_argument ctx right), pos)
78 ) fields_to_check
79
80 let make_meta ctx texpr extra =
81 match texpr.eexpr with
82 | TNew(c,_,el) ->
83 ECall(get_native_repr (TClassDecl c) texpr.epos, (List.map (process_meta_argument ctx) el) @ extra), texpr.epos
84 | TTypeExpr(md) ->
85 ECall(get_native_repr md texpr.epos, extra), texpr.epos
86 | _ ->
87 display_error ctx.com "Unexpected expression" texpr.epos; die "" __LOC__
88
89 let get_strict_meta ctx meta params pos =
90 let pf = ctx.com.platform in
91 let changed_expr, fields_to_check, ctype = match params with
92 | [ECall(ef, el),p] ->
93 let tpath = field_to_type_path ctx.com ef in
94 begin match pf with
95 | Cs ->
96 let el, fields = match List.rev el with
97 | (EObjectDecl(decl),_) :: el ->
98 List.rev el, decl
99 | _ ->
100 el, []
101 in
102 (ENew((tpath,snd ef), el), p), fields, CTPath tpath
103 | Java ->
104 let fields = match el with
105 | [EObjectDecl(fields),_] ->
106 fields
107 | [] ->
108 []
109 | (_,p) :: _ ->
110 display_error ctx.com "Object declaration expected" p;
111 []
112 in
113 ef, fields, CTPath tpath
114 | _ ->
115 Error.typing_error "@:strict is not supported on this target" p
116 end
117 | [EConst(Ident i),p as expr] ->
118 let tpath = { tpackage=[]; tname=i; tparams=[]; tsub=None } in
119 if pf = Cs then
120 (ENew((tpath,p), []), p), [], CTPath tpath
121 else
122 expr, [], CTPath tpath
123 | [ (EField(_),p as field) ] ->
124 let tpath = field_to_type_path ctx.com field in
125 if pf = Cs then
126 (ENew((tpath,p), []), p), [], CTPath tpath
127 else
128 field, [], CTPath tpath
129 | _ ->
130 display_error ctx.com "A @:strict metadata must contain exactly one parameter. Please check the documentation for more information" pos;
131 raise Exit
132 in
133 let texpr = type_expr ctx changed_expr NoValue in
134 let with_type_expr = (ECheckType( (EConst (Ident "null"), pos), (ctype,null_pos) ), pos) in
135 let extra = handle_fields ctx fields_to_check with_type_expr in
136 meta, [make_meta ctx texpr extra], pos
137
138 let check_strict_meta ctx metas =
139 let pf = ctx.com.platform in
140 match pf with
141 | Cs | Java ->
142 let ret = ref [] in
143 List.iter (function
144 | Meta.AssemblyStrict,params,pos -> (try
145 ret := get_strict_meta ctx Meta.AssemblyMeta params pos :: !ret
146 with | Exit -> ())
147 | Meta.Strict,params,pos -> (try
148 ret := get_strict_meta ctx Meta.Meta params pos :: !ret
149 with | Exit -> ())
150 | _ -> ()
151 ) metas;
152 !ret
153 | _ -> []
5757 try
5858 let _,p2 = List.find (fun (access',_) -> access = access') acc in
5959 if p1 <> null_pos && p2 <> null_pos then begin
60 display_error ctx (Printf.sprintf "Duplicate access modifier %s" (Ast.s_access access)) p1;
61 display_error ctx (compl_msg "Previously defined here") p2;
60 display_error ctx.com (Printf.sprintf "Duplicate access modifier %s" (Ast.s_access access)) p1;
61 display_error ~depth:1 ctx.com (compl_msg "Previously defined here") p2;
6262 end;
6363 loop p1 acc l
6464 with Not_found -> match access with
6565 | APublic | APrivate ->
6666 begin try
6767 let _,p2 = List.find (fun (access',_) -> match access' with APublic | APrivate -> true | _ -> false) acc in
68 display_error ctx (Printf.sprintf "Conflicting access modifier %s" (Ast.s_access access)) p1;
69 display_error ctx (compl_msg "Conflicts with this") p2;
68 display_error ctx.com (Printf.sprintf "Conflicting access modifier %s" (Ast.s_access access)) p1;
69 display_error ~depth:1 ctx.com (compl_msg "Conflicts with this") p2;
7070 loop p1 acc l
7171 with Not_found ->
7272 loop p1 ((access,p1) :: acc) l
9191 let infos = t_infos mt in
9292 if snd infos.mt_path = tname then
9393 if ctx.m.curmod != infos.mt_module && infos.mt_private then
94 raise_error (Type_not_found (m.m_path,tname,Private_type)) p
94 raise_typing_error (Type_not_found (m.m_path,tname,Private_type)) p
9595 else
9696 true
9797 else
9898 false
9999 ) m.m_types
100100 with Not_found ->
101 raise_error (Type_not_found (m.m_path,tname,Not_defined)) p
101 raise_typing_error (Type_not_found (m.m_path,tname,Not_defined)) p
102102
103103 (* raises Module_not_found or Type_not_found *)
104104 let load_type_raise ctx mpath tname p =
108108 (* raises Not_found *)
109109 let load_type ctx mpath tname p = try
110110 load_type_raise ctx mpath tname p
111 with Error((Module_not_found _ | Type_not_found _),p2) when p = p2 ->
111 with Error((Module_not_found _ | Type_not_found _),p2,_) when p = p2 ->
112112 raise Not_found
113113
114114 (** since load_type_def and load_instance are used in PASS2, they should not access the structure of a type **)
125125 List.find path_matches ctx.m.curmod.m_types
126126 with Not_found ->
127127 (* Check the local imports *)
128 let t,pi = List.find (fun (t2,pi) -> path_matches t2) ctx.m.module_types in
128 let t,pi = List.find (fun (t2,pi) -> path_matches t2) ctx.m.module_imports in
129129 ImportHandling.mark_import_position ctx pi;
130130 t
131131
141141 let m =
142142 try
143143 ctx.g.do_load_module ctx path p
144 with Error (Module_not_found mpath,_) when mpath = path ->
144 with Error (Module_not_found mpath,_,_) when mpath = path ->
145145 raise Not_found
146146 in
147147 let r = f m ~resume:true in
162162 let m =
163163 try
164164 ctx.g.do_load_module ctx path p
165 with Error (Module_not_found mpath,_) when resume && mpath = path ->
165 with Error (Module_not_found mpath,_,_) when resume && mpath = path ->
166166 raise Not_found
167167 in
168168 f m ~resume:resume
171171 let m =
172172 try
173173 ctx.g.do_load_module ctx path p
174 with Error (Module_not_found mpath,_) when mpath = path ->
174 with Error (Module_not_found mpath,_,_) when mpath = path ->
175175 raise Not_found
176176 in
177177 f m ~resume:true;
199199 let load_module ctx path p =
200200 try
201201 ctx.g.do_load_module ctx path p
202 with Error (Module_not_found mpath,_) as exc when mpath = path ->
202 with Error (Module_not_found mpath,_,_) as exc when mpath = path ->
203203 match path with
204204 | ("std" :: pack, name) ->
205205 ctx.g.do_load_module ctx (pack,name) p
253253 let cf2 = PMap.find cf1.cf_name fields in
254254 let st = s_type (print_context()) in
255255 if not (type_iseq cf1.cf_type cf2.cf_type) then begin
256 display_error ctx ("Cannot redefine field " ^ cf1.cf_name ^ " with different type") p;
257 display_error ctx ("First type was " ^ (st cf1.cf_type)) cf1.cf_pos;
258 error ("Second type was " ^ (st cf2.cf_type)) cf2.cf_pos
256 display_error ctx.com ("Cannot redefine field " ^ cf1.cf_name ^ " with different type") p;
257 display_error ctx.com ("First type was " ^ (st cf1.cf_type)) cf1.cf_pos;
258 typing_error ("Second type was " ^ (st cf2.cf_type)) cf2.cf_pos
259259 end else
260260 true
261261 with Not_found ->
269269 else fields
270270 ) a.a_fields fields
271271 | _ ->
272 error "Can only extend structures" p
272 typing_error "Can only extend structures" p
273273 in
274274 let fields = List.fold_left mk_extension PMap.empty tl in
275275 let tl = List.map (fun (t,_) -> t) tl in
284284 List.iter (fun ti ->
285285 let ti = map ti in
286286 try
287 unify_raise ctx t ti p
288 with Error(Unify l,p) ->
287 unify_raise t ti p
288 with Error(Unify l,p,depth) ->
289289 let fail() =
290 if not ctx.untyped then display_error ctx (error_msg (Unify (Constraint_failure (s_type_path c.cl_path) :: l))) p;
290 if not ctx.untyped then located_display_error ~depth ctx.com (error_msg p (Unify (Constraint_failure (s_type_path c.cl_path) :: l)));
291291 in
292292 match follow t with
293293 | TInst({cl_kind = KExpr e},_) ->
294294 let e = type_expr {ctx with locals = PMap.empty} e (WithType.with_type ti) in
295 begin try unify_raise ctx e.etype ti p
296 with Error (Unify _,_) -> fail() end
295 begin try unify_raise e.etype ti p
296 with Error (Unify _,_,_) -> fail() end
297297 | _ ->
298298 fail()
299299
303303 let rec load_instance' ctx (t,p) allow_no_params =
304304 let t = try
305305 if t.tpackage <> [] || t.tsub <> None then raise Not_found;
306 let pt = List.assoc t.tname ctx.type_params in
307 if t.tparams <> [] then error ("Class type parameter " ^ t.tname ^ " can't have parameters") p;
306 let pt = lookup_param t.tname ctx.type_params in
307 if t.tparams <> [] then typing_error ("Class type parameter " ^ t.tname ^ " can't have parameters") p;
308308 pt
309309 with Not_found ->
310310 let mt = load_type_def ctx p t in
327327 | _ -> false,false,false
328328 in
329329 let types , path , f = ctx.g.do_build_instance ctx mt p in
330 let is_rest = is_generic_build && (match types with ["Rest",_] -> true | _ -> false) in
330 let is_rest = is_generic_build && (match types with [{ttp_name="Rest"}] -> true | _ -> false) in
331331 if allow_no_params && t.tparams = [] && not is_rest then begin
332332 let monos = Monomorph.spawn_constrained_monos (fun t -> t) types in
333333 f (monos)
334334 end else if path = ([],"Dynamic") then
335335 match t.tparams with
336336 | [] -> t_dynamic
337 | [TPType t] -> TDynamic (load_complex_type ctx true t)
338 | _ -> error "Too many parameters for Dynamic" p
337 | [TPType t] -> TDynamic (Some (load_complex_type ctx true t))
338 | _ -> typing_error "Too many parameters for Dynamic" p
339339 else begin
340340 let is_java_rest = ctx.com.platform = Java && is_extern in
341341 let is_rest = is_rest || is_java_rest in
344344 | TPExpr e ->
345345 let name = (match fst e with
346346 | EConst (String(s,_)) -> "S" ^ s
347 | EConst (Int i) -> "I" ^ i
348 | EConst (Float f) -> "F" ^ f
347 | EConst (Int (_,_) as c) -> "I" ^ s_constant c
348 | EConst (Float (_,_) as c) -> "F" ^ s_constant c
349349 | EDisplay _ ->
350350 ignore(type_expr ctx e WithType.value);
351351 "Expr"
358358 in
359359 let checks = DynArray.create () in
360360 let rec loop tl1 tl2 is_rest = match tl1,tl2 with
361 | t :: tl1,(name,t2) :: tl2 ->
361 | t :: tl1,({ttp_name=name;ttp_type=t2}) :: tl2 ->
362362 let t,pt = load_param t in
363363 let check_const c =
364364 let is_expression = (match t with TInst ({ cl_kind = KExpr _ },_) -> true | _ -> false) in
366366 let accepts_expression = name = "Rest" in
367367 if is_expression then begin
368368 if not expects_expression && not accepts_expression then
369 error "Constant value unexpected here" p
369 typing_error "Constant value unexpected here" p
370370 end else if expects_expression then
371 error "Type parameter is expected to be a constant value" p
371 typing_error "Type parameter is expected to be a constant value" p
372372 in
373373 let is_rest = is_rest || name = "Rest" && is_generic_build in
374374 let t = match follow t2 with
384384 t :: loop tl1 tl2 is_rest
385385 | [],[] ->
386386 []
387 | [],["Rest",_] when is_generic_build ->
387 | [],[{ttp_name="Rest"}] when is_generic_build ->
388388 []
389 | [],(_,t) :: tl ->
389 | [],({ttp_type=t;ttp_default=def}) :: tl ->
390390 if is_java_rest then
391391 t_dynamic :: loop [] tl is_rest
392 else if ctx.com.display.dms_error_policy = EPIgnore then
393 t :: loop [] tl is_rest
394 else
395 error ("Not enough type parameters for " ^ s_type_path path) p
392 else begin match def with
393 | None ->
394 if ignore_error ctx.com then
395 t :: loop [] tl is_rest
396 else
397 typing_error ("Not enough type parameters for " ^ s_type_path path) p
398 | Some t ->
399 t :: loop [] tl is_rest
400 end
396401 | t :: tl,[] ->
397402 let t,pt = load_param t in
398403 if is_rest then
399404 t :: loop tl [] true
400 else if ctx.com.display.dms_error_policy = EPIgnore then
405 else if ignore_error ctx.com then
401406 []
402407 else
403 error ("Too many type parameters for " ^ s_type_path path) pt
408 typing_error ("Too many type parameters for " ^ s_type_path path) pt
404409 in
405410 let params = loop t.tparams types false in
406411 if not is_rest then begin
431436 let t = load_instance' ctx tp allow_no_params in
432437 if allow_display then DisplayEmitter.check_display_type ctx t tp;
433438 t
434 with Error (Module_not_found path,_) when ctx.macro_depth <= 0 && (ctx.com.display.dms_kind = DMDefault) && DisplayPosition.display_position#enclosed_in pn ->
439 with Error (Module_not_found path,_,_) when ctx.macro_depth <= 0 && (ctx.com.display.dms_kind = DMDefault) && DisplayPosition.display_position#enclosed_in pn ->
435440 let s = s_type_path path in
436 DisplayToplevel.collect_and_raise ctx TKType NoValue CRTypeHint (s,pn) {pn with pmin = pn.pmax - String.length s;}
441 DisplayToplevel.collect_and_raise ctx TKType NoValue CRTypeHint (s,pn) (patch_string_pos pn s)
437442
438443 (*
439444 build an instance from a complex type
443448 | CTParent t -> load_complex_type ctx allow_display t
444449 | CTPath { tpackage = ["$"]; tname = "_hx_mono" } -> spawn_monomorph ctx p
445450 | CTPath t -> load_instance ~allow_display ctx (t,p) false
446 | CTOptional _ -> error "Optional type not allowed here" p
447 | CTNamed _ -> error "Named type not allowed here" p
451 | CTOptional _ -> typing_error "Optional type not allowed here" p
452 | CTNamed _ -> typing_error "Named type not allowed here" p
448453 | CTIntersection tl ->
449454 let tl = List.map (fun (t,pn) ->
450455 try
451456 (load_complex_type ctx allow_display (t,pn),pn)
452 with DisplayException(DisplayFields Some({fkind = CRTypeHint} as r)) ->
457 with DisplayException(DisplayFields ({fkind = CRTypeHint} as r)) ->
453458 let l = List.filter (fun item -> match item.ci_kind with
454459 | ITType({kind = Struct},_) -> true
455460 | _ -> false
471476 let mk_extension (t,p) =
472477 match follow t with
473478 | TInst ({cl_kind = KTypeParameter _},_) ->
474 error "Cannot structurally extend type parameters" p
479 typing_error "Cannot structurally extend type parameters" p
475480 | TMono _ ->
476 error "Loop found in cascading signatures definitions. Please change order/import" p
481 typing_error "Loop found in cascading signatures definitions. Please change order/import" p
477482 | TAnon a2 ->
478483 PMap.iter (fun _ cf -> ignore(is_redefined ctx cf a2.a_fields p)) a.a_fields;
479484 mk_anon ~fields:(PMap.foldi PMap.add a.a_fields a2.a_fields) (ref (Extend [t]))
480 | _ -> error "Can only extend structures" p
485 | _ -> typing_error "Can only extend structures" p
481486 in
482487 let loop (t,p) = match follow t with
483488 | TAnon a2 ->
486491 a.a_fields <- PMap.add f cf a.a_fields
487492 ) a2.a_fields
488493 | _ ->
489 error "Can only extend structures" p
494 typing_error "Can only extend structures" p
490495 in
491496 let il = List.map (fun (t,pn) ->
492497 try
493498 (load_instance ctx ~allow_display (t,pn) false,pn)
494 with DisplayException(DisplayFields Some({fkind = CRTypeHint} as r)) ->
499 with DisplayException(DisplayFields ({fkind = CRTypeHint} as r)) ->
495500 let l = List.filter (fun item -> match item.ci_kind with
496501 | ITType({kind = Struct},_) -> true
497502 | _ -> false
518523 let displayed_field = ref None in
519524 let rec loop acc f =
520525 let n = fst f.cff_name in
526 let pf = snd f.cff_name in
521527 let p = f.cff_pos in
522 if PMap.mem n acc then error ("Duplicate field declaration : " ^ n) p;
528 if PMap.mem n acc then typing_error ("Duplicate field declaration : " ^ n) pf;
523529 let topt = function
524 | None -> error ("Explicit type required for field " ^ n) p
530 | None -> typing_error ("Explicit type required for field " ^ n) p
525531 | Some t -> load_complex_type ctx allow_display t
526532 in
527 if n = "new" then ctx.com.warning "Structures with new are deprecated, use haxe.Constraints.Constructible instead" p;
533 if n = "new" then warning ctx WDeprecated "Structures with new are deprecated, use haxe.Constraints.Constructible instead" p;
528534 let no_expr = function
529535 | None -> ()
530 | Some (_,p) -> error "Expression not allowed here" p
536 | Some (_,p) -> typing_error "Expression not allowed here" p
531537 in
532538 let pub = ref true in
533539 let dyn = ref false in
540546 | APrivate ->
541547 let p = pos a in
542548 if Filename.basename p.pfile <> "NativeIterable.hx" then (* Terrible workaround for #7436 *)
543 ctx.com.warning "private structure fields are deprecated" p;
549 warning ctx WDeprecated "private structure fields are deprecated" p;
544550 pub := false;
545551 | ADynamic when (match f.cff_kind with FFun _ -> true | _ -> false) -> dyn := true
546552 | AFinal -> final := true
547 | AStatic | AOverride | AInline | ADynamic | AMacro | AExtern | AAbstract | AOverload as a -> error ("Invalid access " ^ Ast.s_access a) p
553 | AStatic | AOverride | AInline | ADynamic | AMacro | AExtern | AAbstract | AOverload as a -> typing_error ("Invalid access " ^ Ast.s_access a) p
548554 ) f.cff_access;
549555 let t , access = (match f.cff_kind with
550556 | FVar(t,e) when !final ->
551557 no_expr e;
552 let t = (match t with None -> error "Type required for structure property" p | Some t -> t) in
558 let t = (match t with None -> typing_error "Type required for structure property" p | Some t -> t) in
553559 load_complex_type ctx allow_display t, Var { v_read = AccNormal; v_write = AccNever }
554560 | FVar (Some (CTPath({tpackage=[];tname="Void"}),_), _) | FProp (_,_,Some (CTPath({tpackage=[];tname="Void"}),_),_) ->
555 error "Fields of type Void are not allowed in structures" p
561 typing_error "Fields of type Void are not allowed in structures" p
556562 | FVar (t, e) ->
557563 no_expr e;
558564 topt t, Var { v_read = AccNormal; v_write = AccNormal }
578584 | x when get && x = "get_" ^ n -> AccCall
579585 | x when not get && x = "set_" ^ n -> AccCall
580586 | _ ->
581 error "Custom property access is no longer supported in Haxe 3" f.cff_pos;
587 typing_error "Custom property access is no longer supported in Haxe 3" f.cff_pos;
582588 in
583 let t = (match t with None -> error "Type required for structure property" p | Some t -> t) in
589 let t = (match t with None -> typing_error "Type required for structure property" p | Some t -> t) in
584590 load_complex_type ctx allow_display t, Var { v_read = access i1 true; v_write = access i2 false }
585591 ) in
586592 let t = if Meta.has Meta.Optional f.cff_meta then ctx.t.tnull t else t in
621627 and load_complex_type ctx allow_display (t,pn) =
622628 try
623629 load_complex_type' ctx allow_display (t,pn)
624 with Error(Module_not_found(([],name)),p) as exc ->
625 if Diagnostics.is_diagnostics_run ctx.com p then begin
630 with Error(Module_not_found(([],name)),p,_) as exc ->
631 if Diagnostics.error_in_diagnostics_run ctx.com p then begin
626632 delay ctx PForce (fun () -> DisplayToplevel.handle_unresolved_identifier ctx name p true);
627633 t_dynamic
628 end else if ctx.com.display.dms_display && not (DisplayPosition.display_position#enclosed_in pn) then
634 end else if ignore_error ctx.com && not (DisplayPosition.display_position#enclosed_in pn) then
629635 t_dynamic
630636 else
631637 raise exc
640646 cf.cf_meta <- List.filter (fun m ->
641647 match m with
642648 | (Meta.Overload,[(EFunction (kind,f),p)],_) ->
643 (match kind with FKNamed _ -> error "Function name must not be part of @:overload" p | _ -> ());
644 (match f.f_expr with Some (EBlock [], _) -> () | _ -> error "Overload must only declare an empty method body {}" p);
649 (match kind with FKNamed _ -> typing_error "Function name must not be part of @:overload" p | _ -> ());
650 (match f.f_expr with Some (EBlock [], _) -> () | _ -> typing_error "Overload must only declare an empty method body {}" p);
645651 (match cf.cf_kind with
646 | Method MethInline -> error "Cannot @:overload inline function" p
652 | Method MethInline -> typing_error "Cannot @:overload inline function" p
647653 | _ -> ());
648654 let old = ctx.type_params in
649 (match cf.cf_params with
650 | [] -> ()
651 | l -> ctx.type_params <- List.filter (fun t -> not (List.mem t l)) ctx.type_params);
652 let params = (!type_function_params_rec) ctx f cf.cf_name p in
655 begin match cf.cf_params with
656 | [] ->
657 ()
658 | l ->
659 ctx.type_params <- List.filter (fun t ->
660 not (List.mem t l) (* TODO: this still looks suspicious *)
661 ) ctx.type_params
662 end;
663 let params : type_params = (!type_function_params_rec) ctx f cf.cf_name p in
653664 ctx.type_params <- params @ ctx.type_params;
654 let topt = function None -> error "Explicit type required" p | Some t -> load_complex_type ctx true t in
665 let topt = function None -> typing_error "Explicit type required" p | Some t -> load_complex_type ctx true t in
655666 let args =
656667 List.map
657668 (fun ((a,_),opt,_,t,cto) ->
668679 false
669680 | (Meta.Overload,[],_) when ctx.com.config.pf_overload ->
670681 add_class_field_flag cf CfOverload;
671 let topt (n,_,t) = match t with | TMono t when t.tm_type = None -> error ("Explicit type required for overload functions\n... For function argument '" ^ n ^ "'") cf.cf_pos | _ -> () in
682 let topt (n,_,t) = match t with | TMono t when t.tm_type = None -> typing_error ("Explicit type required for overload functions\n... For function argument '" ^ n ^ "'") cf.cf_pos | _ -> () in
672683 (match follow cf.cf_type with
673684 | TFun (args,_) -> List.iter topt args
674685 | _ -> () (* could be a variable *));
675686 true
676687 | (Meta.Overload,[],p) ->
677 error "This platform does not support this kind of overload declaration. Try @:overload(function()... {}) instead" p
688 typing_error "This platform does not support this kind of overload declaration. Try @:overload(function()... {}) instead" p
678689 | (Meta.Overload,_,p) ->
679 error "Invalid @:overload metadata format" p
690 typing_error "Invalid @:overload metadata format" p
680691 | _ ->
681692 true
682693 ) cf.cf_meta;
688699 let old_deps = ctx.g.std.m_extra.m_deps in
689700 ctx.m <- {
690701 curmod = ctx.g.std;
691 module_types = [];
702 module_imports = [];
692703 module_using = [];
693704 module_globals = PMap.empty;
694705 wildcard_packages = [];
695 module_imports = [];
706 import_statements = [];
696707 };
697708 ctx.type_params <- [];
698709 (fun() ->
725736 add_dependency ctx.m.curmod t.t_module;
726737 if List.length t.t_params <> 1 then die "" __LOC__;
727738 let pt = mk_mono() in
728 apply_params t.t_params [pt] t.t_type, pt
739 apply_typedef t [pt], pt
729740 | _ ->
730741 die "" __LOC__
731742
742753 (* ---------------------------------------------------------------------- *)
743754 (* PASS 1 & 2 : Module and Class Structure *)
744755
745 let field_to_type_path ctx e =
746 let rec loop e pack name = match e with
747 | EField(e,f),p when Char.lowercase (String.get f 0) <> String.get f 0 -> (match name with
748 | [] | _ :: [] ->
749 loop e pack (f :: name)
750 | _ -> (* too many name paths *)
751 display_error ctx ("Unexpected " ^ f) p;
752 raise Exit)
753 | EField(e,f),_ ->
754 loop e (f :: pack) name
755 | EConst(Ident f),_ ->
756 let pack, name, sub = match name with
757 | [] ->
758 let fchar = String.get f 0 in
759 if Char.uppercase fchar = fchar then
760 pack, f, None
761 else begin
762 display_error ctx "A class name must start with an uppercase letter" (snd e);
763 raise Exit
764 end
765 | [name] ->
766 f :: pack, name, None
767 | [name; sub] ->
768 f :: pack, name, Some sub
769 | _ ->
770 die "" __LOC__
771 in
772 { tpackage=pack; tname=name; tparams=[]; tsub=sub }
773 | _,pos ->
774 display_error ctx "Unexpected expression when building strict meta" pos;
775 raise Exit
776 in
777 loop e [] []
778
779 let rec type_type_param ?(enum_constructor=false) ctx path get_params p tp =
756 type type_param_host =
757 | TPHType
758 | TPHConstructor
759 | TPHMethod
760 | TPHEnumConstructor
761
762 let rec type_type_param ctx host path get_params p tp =
780763 let n = fst tp.tp_name in
781764 let c = mk_class ctx.m.curmod (fst path @ [snd path],n) (pos tp.tp_name) (pos tp.tp_name) in
782 c.cl_params <- type_type_params ctx c.cl_path get_params p tp.tp_params;
765 c.cl_params <- type_type_params ctx host c.cl_path get_params p tp.tp_params;
783766 c.cl_kind <- KTypeParameter [];
784767 c.cl_meta <- tp.Ast.tp_meta;
785 if enum_constructor then c.cl_meta <- (Meta.EnumConstructorParam,[],null_pos) :: c.cl_meta;
786 let t = TInst (c,List.map snd c.cl_params) in
768 if host = TPHEnumConstructor then c.cl_meta <- (Meta.EnumConstructorParam,[],null_pos) :: c.cl_meta;
769 let t = TInst (c,extract_param_types c.cl_params) in
787770 if ctx.is_display_file && DisplayPosition.display_position#enclosed_in (pos tp.tp_name) then
788771 DisplayEmitter.display_type ctx t (pos tp.tp_name);
772 let default = match tp.tp_default with
773 | None ->
774 None
775 | Some ct ->
776 let t = load_complex_type ctx true ct in
777 begin match host with
778 | TPHType ->
779 ()
780 | TPHConstructor
781 | TPHMethod
782 | TPHEnumConstructor ->
783 display_error ctx.com "Default type parameters are only supported on types" (pos ct)
784 end;
785 Some t
786 in
789787 match tp.tp_constraints with
790788 | None ->
791 n, t
789 mk_type_param n t default
792790 | Some th ->
793791 let r = exc_protect ctx (fun r ->
794792 r := lazy_processing (fun() -> t);
795793 let ctx = { ctx with type_params = ctx.type_params @ get_params() } in
796 let constr = match fst th with
794 let rec loop th = match fst th with
797795 | CTIntersection tl -> List.map (load_complex_type ctx true) tl
796 | CTParent ct -> loop ct
798797 | _ -> [load_complex_type ctx true th]
799798 in
799 let constr = loop th in
800800 (* check against direct recursion *)
801801 let rec loop t =
802802 match follow t with
803 | TInst (c2,_) when c == c2 -> error "Recursive constraint parameter is not allowed" p
803 | TInst (c2,_) when c == c2 -> typing_error "Recursive constraint parameter is not allowed" p
804804 | TInst ({ cl_kind = KTypeParameter cl },_) ->
805805 List.iter loop cl
806806 | _ ->
810810 c.cl_kind <- KTypeParameter constr;
811811 t
812812 ) "constraint" in
813 n, TLazy r
814
815 and type_type_params ?(enum_constructor=false) ctx path get_params p tpl =
813 mk_type_param n (TLazy r) default
814
815 and type_type_params ctx host path get_params p tpl =
816816 let names = ref [] in
817817 List.map (fun tp ->
818 if List.exists (fun name -> name = fst tp.tp_name) !names then display_error ctx ("Duplicate type parameter name: " ^ fst tp.tp_name) (pos tp.tp_name);
818 if List.exists (fun name -> name = fst tp.tp_name) !names then display_error ctx.com ("Duplicate type parameter name: " ^ fst tp.tp_name) (pos tp.tp_name);
819819 names := (fst tp.tp_name) :: !names;
820 type_type_param ~enum_constructor ctx path get_params p tp
820 type_type_param ctx host path get_params p tp
821821 ) tpl
822822
823823 let load_core_class ctx c =
824824 let ctx2 = (match ctx.g.core_api with
825825 | None ->
826 let com2 = Common.clone ctx.com in
826 let com2 = Common.clone ctx.com ctx.com.is_macro_context in
827827 com2.defines.Define.values <- PMap.empty;
828828 Common.define com2 Define.CoreApi;
829829 Common.define com2 Define.Sys;
830830 Define.raw_define_value com2.defines "target.threaded" "true"; (* hack because we check this in sys.thread classes *)
831 if ctx.in_macro then Common.define com2 Define.Macro;
831 if ctx.com.is_macro_context then Common.define com2 Define.Macro;
832832 com2.class_path <- ctx.com.std_path;
833833 if com2.display.dms_check_core_api then com2.display <- {com2.display with dms_check_core_api = false};
834834 CommonCache.lock_signature com2 "load_core_class";
853853 let init_core_api ctx c =
854854 let ccore = load_core_class ctx c in
855855 begin try
856 List.iter2 (fun (n1,t1) (n2,t2) -> match follow t1, follow t2 with
856 List.iter2 (fun tp1 tp2 -> match follow tp1.ttp_type, follow tp2.ttp_type with
857857 | TInst({cl_kind = KTypeParameter l1},_),TInst({cl_kind = KTypeParameter l2},_) ->
858858 begin try
859859 List.iter2 (fun t1 t2 -> type_eq EqCoreType t2 t1) l1 l2
860860 with
861861 | Invalid_argument _ ->
862 error "Type parameters must have the same number of constraints as core type" c.cl_pos
862 typing_error "Type parameters must have the same number of constraints as core type" c.cl_pos
863863 | Unify_error l ->
864 display_error ctx ("Type parameter " ^ n2 ^ " has different constraint than in core type") c.cl_pos;
865 display_error ctx (error_msg (Unify l)) c.cl_pos
864 display_error ctx.com ("Type parameter " ^ tp2.ttp_name ^ " has different constraint than in core type") c.cl_pos;
865 located_display_error ctx.com (error_msg c.cl_pos (Unify l));
866866 end
867867 | t1,t2 ->
868868 Printf.printf "%s %s" (s_type (print_context()) t1) (s_type (print_context()) t2);
869869 die "" __LOC__
870870 ) ccore.cl_params c.cl_params;
871871 with Invalid_argument _ ->
872 error "Class must have the same number of type parameters as core type" c.cl_pos
872 typing_error "Class must have the same number of type parameters as core type" c.cl_pos
873873 end;
874874 (match c.cl_doc with
875875 | None -> c.cl_doc <- ccore.cl_doc
877877 let compare_fields f f2 =
878878 let p = (match f2.cf_expr with None -> c.cl_pos | Some e -> e.epos) in
879879 (try
880 type_eq EqCoreType (apply_params ccore.cl_params (List.map snd c.cl_params) f.cf_type) f2.cf_type
880 type_eq EqCoreType (apply_params ccore.cl_params (extract_param_types c.cl_params) f.cf_type) f2.cf_type
881881 with Unify_error l ->
882 display_error ctx ("Field " ^ f.cf_name ^ " has different type than in core type") p;
883 display_error ctx (error_msg (Unify l)) p);
884 if (has_class_field_flag f2 CfPublic) <> (has_class_field_flag f CfPublic) then error ("Field " ^ f.cf_name ^ " has different visibility than core type") p;
882 display_error ctx.com ("Field " ^ f.cf_name ^ " has different type than in core type") p;
883 located_display_error ctx.com (error_msg p (Unify l)));
884 if (has_class_field_flag f2 CfPublic) <> (has_class_field_flag f CfPublic) then typing_error ("Field " ^ f.cf_name ^ " has different visibility than core type") p;
885885 (match f2.cf_doc with
886886 | None -> f2.cf_doc <- f.cf_doc
887887 | Some _ -> ());
890890 | Method MethInline, Method MethNormal -> () (* allow to add 'inline' *)
891891 | Method MethNormal, Method MethInline -> () (* allow to disable 'inline' *)
892892 | _ ->
893 error ("Field " ^ f.cf_name ^ " has different property access than core type") p;
893 typing_error ("Field " ^ f.cf_name ^ " has different property access than core type") p;
894894 end;
895895 (match follow f.cf_type, follow f2.cf_type with
896896 | TFun (pl1,_), TFun (pl2,_) ->
897 if List.length pl1 != List.length pl2 then error "Argument count mismatch" p;
897 if List.length pl1 != List.length pl2 then typing_error "Argument count mismatch" p;
898898 List.iter2 (fun (n1,_,_) (n2,_,_) ->
899 if n1 <> n2 then error ("Method parameter name '" ^ n2 ^ "' should be '" ^ n1 ^ "'") p;
899 if n1 <> n2 then typing_error ("Method parameter name '" ^ n2 ^ "' should be '" ^ n1 ^ "'") p;
900900 ) pl1 pl2;
901901 | _ -> ());
902902 in
903903 let check_fields fcore fl =
904904 PMap.iter (fun i f ->
905905 if not (has_class_field_flag f CfPublic) then () else
906 let f2 = try PMap.find f.cf_name fl with Not_found -> error ("Missing field " ^ i ^ " required by core type") c.cl_pos in
906 let f2 = try PMap.find f.cf_name fl with Not_found -> typing_error ("Missing field " ^ i ^ " required by core type") c.cl_pos in
907907 compare_fields f f2;
908908 ) fcore;
909909 PMap.iter (fun i f ->
910910 let p = (match f.cf_expr with None -> c.cl_pos | Some e -> e.epos) in
911 if (has_class_field_flag f CfPublic) && not (Meta.has Meta.Hack f.cf_meta) && not (PMap.mem f.cf_name fcore) && not (has_class_field_flag f CfOverride) then error ("Public field " ^ i ^ " is not part of core type") p;
911 if (has_class_field_flag f CfPublic) && not (Meta.has Meta.Hack f.cf_meta) && not (PMap.mem f.cf_name fcore) && not (has_class_field_flag f CfOverride) then typing_error ("Public field " ^ i ^ " is not part of core type") p;
912912 ) fl;
913913 in
914914 check_fields ccore.cl_fields c.cl_fields;
918918 | Some cf, _ when not (has_class_field_flag cf CfPublic) -> ()
919919 | Some f, Some f2 -> compare_fields f f2
920920 | None, Some cf when not (has_class_field_flag cf CfPublic) -> ()
921 | _ -> error "Constructor differs from core type" c.cl_pos)
921 | _ -> typing_error "Constructor differs from core type" c.cl_pos)
922922
923923 let string_list_of_expr_path (e,p) =
924924 try string_list_of_expr_path_raise (e,p)
925 with Exit -> error "Invalid path" p
926
927 let handle_using ctx path p =
928 let t = match List.rev path with
929 | (s1,_) :: (s2,_) :: sl ->
930 if is_lower_ident s2 then mk_type_path ((List.rev (s2 :: List.map fst sl)),s1)
931 else mk_type_path ~sub:s1 (List.rev (List.map fst sl),s2)
932 | (s1,_) :: sl ->
933 mk_type_path (List.rev (List.map fst sl),s1)
934 | [] ->
935 DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue true) CRUsing (DisplayTypes.make_subject None {p with pmin = p.pmax});
936 in
937 let types = (match t.tsub with
938 | None ->
939 let md = ctx.g.do_load_module ctx (t.tpackage,t.tname) p in
940 let types = List.filter (fun t -> not (t_infos t).mt_private) md.m_types in
941 Option.map_default (fun c -> (TClassDecl c) :: types) types md.m_statics
942 | Some _ ->
943 let t = load_type_def ctx p t in
944 [t]
945 ) in
946 (* delay the using since we need to resolve typedefs *)
947 let filter_classes types =
948 let rec loop acc types = match types with
949 | td :: l ->
950 (match resolve_typedef td with
951 | TClassDecl c | TAbstractDecl({a_impl = Some c}) ->
952 loop ((c,p) :: acc) l
953 | td ->
954 loop acc l)
955 | [] ->
956 acc
957 in
958 loop [] types
959 in
960 types,filter_classes
925 with Exit -> typing_error "Invalid path" p
3636
3737 let is_generic_parameter ctx c =
3838 (* first check field parameters, then class parameters *)
39 let name = snd c.cl_path in
3940 try
40 ignore (List.assoc (snd c.cl_path) ctx.curfield.cf_params);
41 ignore(lookup_param name ctx.curfield.cf_params);
4142 has_class_field_flag ctx.curfield CfGeneric
4243 with Not_found -> try
43 ignore(List.assoc (snd c.cl_path) ctx.type_params);
44 ignore(lookup_param name ctx.type_params);
4445 (match ctx.curclass.cl_kind with | KGeneric -> true | _ -> false);
4546 with Not_found ->
4647 false
4748
48 let valid_redefinition ctx f1 t1 f2 t2 = (* child, parent *)
49 let valid_redefinition ctx map1 map2 f1 t1 f2 t2 = (* child, parent *)
4950 let valid t1 t2 =
5051 Type.unify t1 t2;
5152 if is_null t1 <> is_null t2 || ((follow t1) == t_dynamic && (follow t2) != t_dynamic) then raise (Unify_error [Cannot_unify (t1,t2)]);
6061 | [], [] -> t1, t2
6162 | l1, l2 when List.length l1 = List.length l2 ->
6263 let to_check = ref [] in
63 let monos = List.map2 (fun (name,p1) (_,p2) ->
64 (match follow p1, follow p2 with
64 (* TPTODO: defaults *)
65 let monos = List.map2 (fun tp1 tp2 ->
66 (match follow tp1.ttp_type, follow tp2.ttp_type with
6567 | TInst ({ cl_kind = KTypeParameter ct1 } as c1,pl1), TInst ({ cl_kind = KTypeParameter ct2 } as c2,pl2) ->
6668 (match ct1, ct2 with
6769 | [], [] -> ()
7072 let check monos =
7173 List.iter2 (fun t1 t2 ->
7274 try
73 let t1 = apply_params l1 monos (apply_params c1.cl_params pl1 t1) in
74 let t2 = apply_params l2 monos (apply_params c2.cl_params pl2 t2) in
75 let t1 = apply_params l1 monos (apply_params c1.cl_params pl1 (map2 t1)) in
76 let t2 = apply_params l2 monos (apply_params c2.cl_params pl2 (map1 t2)) in
7577 type_eq EqStrict t1 t2
7678 with Unify_error l ->
7779 raise (Unify_error (Unify_custom "Constraints differ" :: l))
8183 | _ ->
8284 raise (Unify_error [Unify_custom "Different number of constraints"]))
8385 | _ -> ());
84 TInst (mk_class null_module ([],name) null_pos null_pos,[])
86 TInst (mk_class null_module ([],tp1.ttp_name) null_pos null_pos,[])
8587 ) l1 l2 in
8688 List.iter (fun f -> f monos) !to_check;
8789 apply_params l1 monos t1, apply_params l2 monos t2
145147 | [] ->
146148 raise Not_found
147149 | _ ->
148 error "String expected" mp
150 typing_error "String expected" mp
149151
150152 let check_native_name_override ctx child base =
151153 let error base_pos child_pos =
152 display_error ctx ("Field " ^ child.cf_name ^ " has different @:native value than in superclass") child_pos;
153 display_error ctx (compl_msg "Base field is defined here") base_pos
154 display_error ctx.com ("Field " ^ child.cf_name ^ " has different @:native value than in superclass") child_pos;
155 display_error ~depth:1 ctx.com (compl_msg "Base field is defined here") base_pos
154156 in
155157 try
156158 let child_name, child_pos = get_native_name child.cf_meta in
165167 let check_overriding ctx c f =
166168 match c.cl_super with
167169 | None ->
168 if has_class_field_flag f CfOverride then display_error ctx ("Field " ^ f.cf_name ^ " is declared 'override' but doesn't override any field") f.cf_pos
170 if has_class_field_flag f CfOverride then display_error ctx.com ("Field " ^ f.cf_name ^ " is declared 'override' but doesn't override any field") f.cf_pos
169171 | _ when (has_class_flag c CExtern) && Meta.has Meta.CsNative c.cl_meta -> () (* -net-lib specific: do not check overrides on extern CsNative classes *)
170172 | Some (csup,params) ->
171173 let p = f.cf_name_pos in
172174 let i = f.cf_name in
173175 let check_field f get_super_field is_overload = try
174176 (if is_overload && not (has_class_field_flag f CfOverload) then
175 display_error ctx ("Missing overload declaration for field " ^ i) p);
177 display_error ctx.com ("Missing overload declaration for field " ^ i) p);
176178 let f_has_override = has_class_field_flag f CfOverride in
177179 let t, f2 = get_super_field csup i in
178180 check_native_name_override ctx f f2;
182184 | _ -> ());
183185 if has_class_field_flag f2 CfAbstract then begin
184186 if f_has_override then
185 display_error ctx ("Field " ^ i ^ " is declared 'override' but parent field " ^ i ^ " is 'abstract' and does not provide any implementation to override") p
187 display_error ctx.com ("Field " ^ i ^ " is declared 'override' but parent field " ^ i ^ " is 'abstract' and does not provide any implementation to override") p
186188 else
187189 add_class_field_flag f CfOverride (* our spec requires users to not "override" abstract functions, but our implementation depends on implementations to be declared with "override" ¯\_(ツ)_/¯ *)
188190 end;
189191 if (has_class_field_flag f2 CfOverload && not (has_class_field_flag f CfOverload)) then
190 display_error ctx ("Field " ^ i ^ " should be declared with overload since it was already declared as overload in superclass") p
192 display_error ctx.com ("Field " ^ i ^ " should be declared with overload since it was already declared as overload in superclass") p
191193 else if not f_has_override && not (has_class_field_flag f2 CfAbstract) then begin
192194 if has_class_flag c CExtern then add_class_field_flag f CfOverride
193 else display_error ctx ("Field " ^ i ^ " should be declared with 'override' since it is inherited from superclass " ^ s_type_path csup.cl_path) p
195 else display_error ctx.com ("Field " ^ i ^ " should be declared with 'override' since it is inherited from superclass " ^ s_type_path csup.cl_path) p
194196 end else if not (has_class_field_flag f CfPublic) && (has_class_field_flag f2 CfPublic) then
195 display_error ctx ("Field " ^ i ^ " has less visibility (public/private) than superclass one") p
197 display_error ctx.com ("Field " ^ i ^ " has less visibility (public/private) than superclass one") p
196198 else (match f.cf_kind, f2.cf_kind with
197199 | _, Method MethInline ->
198 display_error ctx ("Field " ^ i ^ " is inlined and cannot be overridden") p
200 display_error ctx.com ("Field " ^ i ^ " is inlined and cannot be overridden") p
199201 | a, b when a = b -> ()
200202 | Method MethInline, Method MethNormal ->
201203 () (* allow to redefine a method as inlined *)
202204 | _ ->
203 display_error ctx ("Field " ^ i ^ " has different property access than in superclass") p);
204 if (has_class_field_flag f2 CfFinal) then display_error ctx ("Cannot override final method " ^ i) p;
205 display_error ctx.com ("Field " ^ i ^ " has different property access than in superclass") p);
206 if (has_class_field_flag f2 CfFinal) then display_error ctx.com ("Cannot override final method " ^ i) p;
205207 try
206208 let t = apply_params csup.cl_params params t in
207 valid_redefinition ctx f f.cf_type f2 t;
209 let map = TClass.get_map_function csup params in
210 valid_redefinition ctx map map f f.cf_type f2 t;
208211 with
209212 Unify_error l ->
210 display_error ctx ("Field " ^ i ^ " overrides parent class with different or incomplete type") p;
211 display_error ctx (compl_msg "Base field is defined here") f2.cf_name_pos;
212 display_error ctx (compl_msg (error_msg (Unify l))) p;
213 display_error ctx.com ("Field " ^ i ^ " overrides parent class with different or incomplete type") p;
214 display_error ~depth:1 ctx.com (compl_msg "Base field is defined here") f2.cf_name_pos;
215 located_display_error ~depth:1 ctx.com (compl_located_msg (error_msg p (Unify l)));
213216 with
214217 Not_found ->
215218 if has_class_field_flag f CfOverride then
223226 ) fields [] in
224227 StringError.string_error i fields ("Field " ^ i ^ " is declared 'override' but doesn't override any field")
225228 end in
226 display_error ctx msg p
229 display_error ctx.com msg p
227230 in
228231 if has_class_field_flag f CfOverload then begin
229232 let overloads = Overloads.get_overloads ctx.com csup i in
231234 (* check if any super class fields are vars *)
232235 match f2.cf_kind with
233236 | Var _ ->
234 display_error ctx ("A variable named '" ^ f2.cf_name ^ "' was already declared in a superclass") f.cf_pos
237 display_error ctx.com ("A variable named '" ^ f2.cf_name ^ "' was already declared in a superclass") f.cf_pos
235238 | _ -> ()
236239 ) overloads;
237240 List.iter (fun f ->
250253 let class_field_no_interf c i =
251254 try
252255 let f = PMap.find i c.cl_fields in
253 f.cf_type , f
256 (fun t -> t),f.cf_type , f
254257 with Not_found ->
255258 match c.cl_super with
256259 | None ->
258261 | Some (c,tl) ->
259262 (* rec over class_field *)
260263 let _, t , f = raw_class_field (fun f -> f.cf_type) c tl i in
261 apply_params c.cl_params tl t , f
264 let map = TClass.get_map_function c tl in
265 map,apply_params c.cl_params tl t , f
262266
263267 let rec return_flow ctx e =
264268 let error() =
265 display_error ctx (Printf.sprintf "Missing return: %s" (s_type (print_context()) ctx.ret)) e.epos; raise Exit
269 display_error ctx.com (Printf.sprintf "Missing return: %s" (s_type (print_context()) ctx.ret)) e.epos; raise Exit
266270 in
267271 let return_flow = return_flow ctx in
268 let rec uncond e = match e.eexpr with
269 | TIf _ | TWhile _ | TSwitch _ | TTry _ | TFunction _ -> ()
270 | TReturn _ | TThrow _ -> raise Exit
271 | _ -> Type.iter uncond e
272 in
273 let has_unconditional_flow e = try uncond e; false with Exit -> true in
274272 match e.eexpr with
275273 | TReturn _ | TThrow _ -> ()
276274 | TParenthesis e | TMeta(_,e) ->
279277 let rec loop = function
280278 | [] -> error()
281279 | [e] -> return_flow e
282 | e :: _ when has_unconditional_flow e -> ()
280 | e :: _ when DeadEnd.has_dead_end e -> ()
283281 | _ :: l -> loop l
284282 in
285283 loop el
304302 in
305303 loop e
306304 | _ ->
307 error()
305 if not (DeadEnd.has_dead_end e) then error()
308306
309307 let check_global_metadata ctx meta f_add mpath tpath so =
310308 let sl1 = full_dot_path2 mpath tpath in
318316 let check_module_types ctx m p t =
319317 let t = t_infos t in
320318 try
321 let m2 = Hashtbl.find ctx.g.types_module t.mt_path in
322 if m.m_path <> m2 && String.lowercase (s_type_path m2) = String.lowercase (s_type_path m.m_path) then error ("Module " ^ s_type_path m2 ^ " is loaded with a different case than " ^ s_type_path m.m_path) p;
323 error ("Type name " ^ s_type_path t.mt_path ^ " is redefined from module " ^ s_type_path m2) p
319 let path2 = ctx.com.type_to_module#find t.mt_path in
320 if m.m_path <> path2 && String.lowercase (s_type_path path2) = String.lowercase (s_type_path m.m_path) then typing_error ("Module " ^ s_type_path path2 ^ " is loaded with a different case than " ^ s_type_path m.m_path) p;
321 let m2 = ctx.com.module_lut#find path2 in
322 let hex1 = Digest.to_hex m.m_extra.m_sign in
323 let hex2 = Digest.to_hex m2.m_extra.m_sign in
324 let s = if hex1 = hex2 then hex1 else Printf.sprintf "was %s, is %s" hex2 hex1 in
325 typing_error (Printf.sprintf "Type name %s is redefined from module %s (%s)" (s_type_path t.mt_path) (s_type_path path2) s) p
324326 with
325327 Not_found ->
326 Hashtbl.add ctx.g.types_module t.mt_path m.m_path
328 ctx.com.type_to_module#add t.mt_path m.m_path
327329
328330 module Inheritance = struct
329331 let is_basic_class_path path = match path with
332334
333335 let check_extends ctx c t p = match follow t with
334336 | TInst (csup,params) ->
335 if is_basic_class_path csup.cl_path && not ((has_class_flag c CExtern) && (has_class_flag csup CExtern)) then error "Cannot extend basic class" p;
336 if extends csup c then error "Recursive class" p;
337 if is_basic_class_path csup.cl_path && not ((has_class_flag c CExtern) && (has_class_flag csup CExtern)) then typing_error "Cannot extend basic class" p;
338 if extends csup c then typing_error "Recursive class" p;
337339 begin match csup.cl_kind with
338340 | KTypeParameter _ ->
339 if is_generic_parameter ctx csup then error "Extending generic type parameters is no longer allowed in Haxe 4" p;
340 error "Cannot extend type parameters" p
341 if is_generic_parameter ctx csup then typing_error "Extending generic type parameters is no longer allowed in Haxe 4" p;
342 typing_error "Cannot extend type parameters" p
341343 | _ -> csup,params
342344 end
343 | _ -> error "Should extend by using a class" p
345 | _ -> typing_error "Should extend by using a class" p
344346
345347 let rec check_interface ctx missing c intf params =
346348 List.iter (fun (i2,p2) ->
347349 check_interface ctx missing c i2 (List.map (apply_params intf.cl_params params) p2)
348350 ) intf.cl_implements;
349351 let p = c.cl_name_pos in
350 let rec check_field i f =
352 let check_field f =
351353 let t = (apply_params intf.cl_params params f.cf_type) in
352354 let is_overload = ref false in
355 let make_implicit_field () =
356 let cf = {f with cf_overloads = []; cf_type = apply_params intf.cl_params params f.cf_type} in
357 begin try
358 let cf' = PMap.find cf.cf_name c.cl_fields in
359 ctx.com.overload_cache#remove (c.cl_path,f.cf_name);
360 cf'.cf_overloads <- cf :: cf'.cf_overloads
361 with Not_found ->
362 TClass.add_field c cf
363 end;
364 cf
365 in
366 let is_method () = match f.cf_kind with
367 | Method _ -> true
368 | Var _ -> false
369 in
353370 try
354 let t2, f2 = class_field_no_interf c i in
371 let map2, t2, f2 = class_field_no_interf c f.cf_name in
355372 let t2, f2 =
356373 if f2.cf_overloads <> [] || has_class_field_flag f2 CfOverload then
357 let overloads = Overloads.get_overloads ctx.com c i in
374 let overloads = Overloads.get_overloads ctx.com c f.cf_name in
358375 is_overload := true;
359376 List.find (fun (t1,f1) -> Overloads.same_overload_args t t1 f f1) overloads
360377 else
369386 | MethMacro -> 2
370387 in
371388 if (has_class_field_flag f CfPublic) && not (has_class_field_flag f2 CfPublic) && not (Meta.has Meta.CompilerGenerated f.cf_meta) then
372 display_error ctx ("Field " ^ i ^ " should be public as requested by " ^ s_type_path intf.cl_path) p
389 display_error ctx.com ("Field " ^ f.cf_name ^ " should be public as requested by " ^ s_type_path intf.cl_path) p
373390 else if not (unify_kind f2.cf_kind f.cf_kind) || not (match f.cf_kind, f2.cf_kind with Var _ , Var _ -> true | Method m1, Method m2 -> mkind m1 = mkind m2 | _ -> false) then
374 display_error ctx ("Field " ^ i ^ " has different property access than in " ^ s_type_path intf.cl_path ^ " (" ^ s_kind f2.cf_kind ^ " should be " ^ s_kind f.cf_kind ^ ")") p
391 display_error ctx.com ("Field " ^ f.cf_name ^ " has different property access than in " ^ s_type_path intf.cl_path ^ " (" ^ s_kind f2.cf_kind ^ " should be " ^ s_kind f.cf_kind ^ ")") p
375392 else try
376 valid_redefinition ctx f2 t2 f (apply_params intf.cl_params params f.cf_type)
393 let map1 = TClass.get_map_function intf params in
394 valid_redefinition ctx map1 map2 f2 t2 f (apply_params intf.cl_params params f.cf_type)
377395 with
378396 Unify_error l ->
379397 if not (Meta.has Meta.CsNative c.cl_meta && (has_class_flag c CExtern)) then begin
380 display_error ctx ("Field " ^ i ^ " has different type than in " ^ s_type_path intf.cl_path) p;
381 display_error ctx (compl_msg "Interface field is defined here") f.cf_pos;
382 display_error ctx (compl_msg (error_msg (Unify l))) p;
398 display_error ctx.com ("Field " ^ f.cf_name ^ " has different type than in " ^ s_type_path intf.cl_path) p;
399 display_error ~depth:1 ctx.com (compl_msg "Interface field is defined here") f.cf_pos;
400 located_display_error ~depth:1 ctx.com (compl_located_msg (error_msg p (Unify l)));
383401 end
384402 )
385 with
386 | Not_found when (has_class_flag c CAbstract) ->
387 let cf = {f with cf_overloads = []} in
403 with Not_found ->
404 if (has_class_flag c CAbstract) && is_method() then begin
405 let cf = make_implicit_field () in
388406 add_class_field_flag cf CfAbstract;
389 begin try
390 let cf' = PMap.find cf.cf_name c.cl_fields in
391 Hashtbl.remove ctx.com.overload_cache (c.cl_path,i);
392 cf'.cf_overloads <- cf :: cf'.cf_overloads
393 with Not_found ->
394 TClass.add_field c cf
395 end
396 | Not_found when not (has_class_flag c CInterface) ->
397 if Diagnostics.is_diagnostics_run ctx.com c.cl_pos then
407 end else if has_class_field_flag f CfDefault then begin
408 let cf = make_implicit_field () in
409 cf.cf_expr <- None;
410 add_class_field_flag cf CfExtern;
411 add_class_field_flag cf CfOverride;
412 end else if not (has_class_flag c CInterface) then begin
413 if Diagnostics.error_in_diagnostics_run ctx.com c.cl_pos then
398414 DynArray.add missing (f,t)
399415 else begin
400416 let msg = if !is_overload then
401417 let ctx = print_context() in
402418 let args = match follow f.cf_type with | TFun(args,_) -> String.concat ", " (List.map (fun (n,o,t) -> (if o then "?" else "") ^ n ^ " : " ^ (s_type ctx t)) args) | _ -> die "" __LOC__ in
403 "No suitable overload for " ^ i ^ "( " ^ args ^ " ), as needed by " ^ s_type_path intf.cl_path ^ " was found"
419 "No suitable overload for " ^ f.cf_name ^ "( " ^ args ^ " ), as needed by " ^ s_type_path intf.cl_path ^ " was found"
404420 else
405 ("Field " ^ i ^ " needed by " ^ s_type_path intf.cl_path ^ " is missing")
421 ("Field " ^ f.cf_name ^ " needed by " ^ s_type_path intf.cl_path ^ " is missing")
406422 in
407 display_error ctx msg p
423 display_error ctx.com msg p
408424 end
409 | Not_found -> ()
410 in
411 let check_field i cf =
412 check_field i cf;
425 end
426 in
427 let check_field _ cf =
428 check_field cf;
413429 if has_class_field_flag cf CfOverload then
414 List.iter (check_field i) (List.rev cf.cf_overloads)
430 List.iter check_field (List.rev cf.cf_overloads)
415431 in
416432 PMap.iter check_field intf.cl_fields
417433
460476 match !missing with
461477 | [] ->
462478 ()
463 | l when Diagnostics.is_diagnostics_run ctx.com c.cl_pos ->
479 | l when Diagnostics.error_in_diagnostics_run ctx.com c.cl_pos ->
464480 let diag = {
465481 mf_pos = c.cl_name_pos;
466482 mf_on = TClassDecl c;
471487 display.module_diagnostics <- MissingFields diag :: display.module_diagnostics
472488 | l ->
473489 let singular = match l with [_] -> true | _ -> false in
474 display_error ctx (Printf.sprintf "This class extends abstract class %s but doesn't implement the following method%s" (s_type_path csup.cl_path) (if singular then "" else "s")) c.cl_name_pos;
475 display_error ctx (Printf.sprintf "Implement %s or make %s abstract as well" (if singular then "it" else "them") (s_type_path c.cl_path)) c.cl_name_pos;
490 display_error ctx.com (Printf.sprintf "This class extends abstract class %s but doesn't implement the following method%s" (s_type_path csup.cl_path) (if singular then "" else "s")) c.cl_name_pos;
491 display_error ctx.com (Printf.sprintf "Implement %s or make %s abstract as well" (if singular then "it" else "them") (s_type_path c.cl_path)) c.cl_name_pos;
476492 let pctx = print_context() in
477493 List.iter (fun (cf,_) ->
478494 let s = match follow cf.cf_type with
481497 | t ->
482498 s_type pctx t
483499 in
484 display_error ctx (Printf.sprintf "... %s(%s)" cf.cf_name s) cf.cf_name_pos
500 display_error ~depth:1 ctx.com (compl_msg (Printf.sprintf "%s(%s)" cf.cf_name s)) cf.cf_name_pos
485501 ) (List.rev !missing)
486502
487503 let set_heritance ctx c herits p =
495511 | _ -> ()
496512 ) csup.cl_meta;
497513 if has_class_flag csup CFinal && not (((has_class_flag csup CExtern) && Meta.has Meta.Hack c.cl_meta) || (match c.cl_kind with KTypeParameter _ -> true | _ -> false)) then
498 error ("Cannot extend a final " ^ if (has_class_flag c CInterface) then "interface" else "class") p;
514 typing_error ("Cannot extend a final " ^ if (has_class_flag c CInterface) then "interface" else "class") p;
499515 in
500516 let check_cancel_build csup =
501517 match csup.cl_build() with
520536 let lt = try
521537 List.find path_matches ctx.m.curmod.m_types
522538 with Not_found ->
523 let t,pi = List.find (fun (lt,_) -> path_matches lt) ctx.m.module_types in
539 let t,pi = List.find (fun (lt,_) -> path_matches lt) ctx.m.module_imports in
524540 ImportHandling.mark_import_position ctx pi;
525541 t
526542 in
536552 let herits = List.filter (ctx.g.do_inherit ctx c p) herits in
537553 (* Pass 1: Check and set relations *)
538554 let check_herit t is_extends p =
555 let rec check_interfaces_or_delay () =
556 match c.cl_build() with
557 | BuildMacro pending ->
558 (* Ok listen... we're still building this class, which means we can't check its interfaces yet. However,
559 we do want to check them at SOME point. So we use this pending list which was maybe designed for this
560 purpose. However, we STILL have to delay the check because at the time pending is handled, the class
561 is not built yet. See issue #10847. *)
562 pending := (fun () -> delay ctx PConnectField check_interfaces_or_delay) :: !pending
563 | _ ->
564 check_interfaces ctx c
565 in
539566 if is_extends then begin
540 if c.cl_super <> None then error "Cannot extend several classes" p;
567 if c.cl_super <> None then typing_error "Cannot extend several classes" p;
541568 let csup,params = check_extends ctx c t p in
542569 if (has_class_flag c CInterface) then begin
543 if not (has_class_flag csup CInterface) then error "Cannot extend by using a class" p;
570 if not (has_class_flag csup CInterface) then typing_error "Cannot extend by using a class" p;
544571 c.cl_implements <- (csup,params) :: c.cl_implements;
545572 if not !has_interf then begin
546 if not is_lib then delay ctx PConnectField (fun() -> check_interfaces ctx c);
573 if not is_lib then delay ctx PConnectField check_interfaces_or_delay;
547574 has_interf := true;
548575 end
549576 end else begin
550 if (has_class_flag csup CInterface) then error "Cannot extend by using an interface" p;
577 if (has_class_flag csup CInterface) then typing_error "Cannot extend by using an interface" p;
551578 c.cl_super <- Some (csup,params)
552579 end;
553580 (fun () ->
556583 )
557584 end else begin match follow t with
558585 | TInst ({ cl_path = [],"ArrayAccess" } as ca,[t]) when (has_class_flag ca CExtern) ->
559 if c.cl_array_access <> None then error "Duplicate array access" p;
586 if c.cl_array_access <> None then typing_error "Duplicate array access" p;
560587 c.cl_array_access <- Some t;
561588 (fun () -> ())
562589 | TInst (intf,params) ->
563 if extends intf c then error "Recursive class" p;
564 if (has_class_flag c CInterface) then error "Interfaces cannot implement another interface (use extends instead)" p;
565 if not (has_class_flag intf CInterface) then error "You can only implement an interface" p;
590 if extends intf c then typing_error "Recursive class" p;
591 if (has_class_flag c CInterface) then typing_error "Interfaces cannot implement another interface (use extends instead)" p;
592 if not (has_class_flag intf CInterface) then typing_error "You can only implement an interface" p;
566593 c.cl_implements <- (intf, params) :: c.cl_implements;
567594 if not !has_interf && not is_lib && not (Meta.has (Meta.Custom "$do_not_check_interf") c.cl_meta) then begin
568 delay ctx PConnectField (fun() -> check_interfaces ctx c);
595 delay ctx PConnectField check_interfaces_or_delay;
569596 has_interf := true;
570597 end;
571598 (fun () ->
573600 process_meta intf;
574601 )
575602 | TDynamic t ->
576 if c.cl_dynamic <> None then error "Cannot have several dynamics" p;
577 if not (has_class_flag c CExtern) then display_error ctx "In haxe 4, implements Dynamic is only supported on externs" p;
578 c.cl_dynamic <- Some t;
603 if c.cl_dynamic <> None then typing_error "Cannot have several dynamics" p;
604 if not (has_class_flag c CExtern) then display_error ctx.com "In haxe 4, implements Dynamic is only supported on externs" p;
605 c.cl_dynamic <- Some (match t with None -> t_dynamic | Some t -> t);
579606 (fun () -> ())
580607 | _ ->
581 error "Should implement by using an interface" p
608 typing_error "Should implement by using an interface" p
582609 end
583610 in
584611 let fl = ExtList.List.filter_map (fun (is_extends,(ct,p)) ->
585612 try
586613 let t = try
587614 Typeload.load_instance ~allow_display:true ctx (ct,p) false
588 with DisplayException(DisplayFields Some({fkind = CRTypeHint} as r)) ->
615 with DisplayException(DisplayFields ({fkind = CRTypeHint} as r)) ->
589616 (* We don't allow `implements` on interfaces. Just raise fields completion with no fields. *)
590617 if not is_extends && (has_class_flag c CInterface) then raise_fields [] CRImplements r.fsubject;
591618 let l = List.filter (fun item -> match item.ci_kind with
599626 raise_fields l (if is_extends then CRExtends else CRImplements) r.fsubject
600627 in
601628 Some (check_herit t is_extends p)
602 with Error(Module_not_found(([],name)),p) when ctx.com.display.dms_kind <> DMNone ->
603 if Diagnostics.is_diagnostics_run ctx.com p then DisplayToplevel.handle_unresolved_identifier ctx name p true;
629 with Error(Module_not_found(([],name)),p,_) when ctx.com.display.dms_kind <> DMNone ->
630 if Diagnostics.error_in_diagnostics_run ctx.com p then DisplayToplevel.handle_unresolved_identifier ctx name p true;
604631 None
605632 ) herits in
606633 fl
608635
609636 let check_final_vars ctx e =
610637 let final_vars = Hashtbl.create 0 in
611 List.iter (fun cf -> match cf.cf_kind with
612 | Var _ when (has_class_field_flag cf CfFinal) && cf.cf_expr = None ->
613 Hashtbl.add final_vars cf.cf_name cf
638 let ordered_fields = DynArray.create () in
639 let rec loop c =
640 List.iter (fun cf -> match cf.cf_kind with
641 | Var _ when (has_class_field_flag cf CfFinal) && cf.cf_expr = None && not (Hashtbl.mem final_vars cf.cf_name) ->
642 Hashtbl.add final_vars cf.cf_name false;
643 DynArray.add ordered_fields (c,cf)
644 | _ ->
645 ()
646 ) c.cl_ordered_fields;
647 match c.cl_super with
648 | Some(c,_) when has_class_flag c CAbstract && not (has_constructor c) ->
649 loop c
614650 | _ ->
615651 ()
616 ) ctx.curclass.cl_ordered_fields;
652 in
653 loop ctx.curclass;
617654 if Hashtbl.length final_vars > 0 then begin
618655 let rec find_inits e = match e.eexpr with
619656 | TBinop(OpAssign,{eexpr = TField({eexpr = TConst TThis},fa)},e2) ->
623660 Type.iter find_inits e
624661 in
625662 find_inits e;
626 Hashtbl.iter (fun _ cf ->
627 display_error ctx ("final field " ^ cf.cf_name ^ " must be initialized immediately or in the constructor") cf.cf_pos;
628 ) final_vars
629 end
663 if Hashtbl.length final_vars > 0 then
664 display_error ctx.com "Some final fields are uninitialized in this class" ctx.curclass.cl_name_pos;
665 DynArray.iter (fun (c,cf) ->
666 if Hashtbl.mem final_vars cf.cf_name then
667 display_error ~depth:1 ctx.com "Uninitialized field" cf.cf_name_pos
668 ) ordered_fields
669 end
6565 is_inline : bool;
6666 is_final : bool;
6767 is_static : bool;
68 default : pos option;
6869 override : pos option;
6970 overload : pos option;
7071 is_extern : bool;
8182 (* If true, cf_expr = None makes a difference in the logic. We insert a dummy expression in
8283 display mode in order to address this. *)
8384 mutable expr_presence_matters : bool;
85 mutable had_error : bool;
8486 }
87
88 type method_kind =
89 | MKNormal
90 | MKGetter
91 | MKSetter
92
93 module FieldError = struct
94 let maybe_display_error com fctx s p =
95 if not fctx.had_error then begin
96 fctx.had_error <- true;
97 display_error com s p
98 end
99
100 let invalid_modifier_combination fctx com fctx a b p =
101 maybe_display_error com fctx (Printf.sprintf "Invalid modifier combination: %s + %s" a b) p
102
103 let invalid_modifier com fctx m c p =
104 maybe_display_error com fctx (Printf.sprintf "Invalid modifier: %s on %s" m c) p
105
106 let invalid_modifier_only com fctx m c p =
107 maybe_display_error com fctx (Printf.sprintf "Invalid modifier: %s is only supported %s" m c) p
108
109 let missing_expression com fctx reason p =
110 maybe_display_error com fctx (Printf.sprintf "%s" reason) p
111
112 let unexpected_expression com fctx reason p =
113 maybe_display_error com fctx (Printf.sprintf "%s" reason) p
114 end
115
116 open FieldError
85117
86118 let dump_class_context cctx =
87119 Printer.s_record_fields "" [
115147 "expr_presence_matters",string_of_bool fctx.expr_presence_matters;
116148 ]
117149
118
119150 let is_java_native_function ctx meta pos = try
120151 match Meta.get Meta.Native meta with
121152 | (Meta.Native,[],_) ->
122 ctx.com.warning "@:native metadata for jni functions is deprecated. Use @:java.native instead." pos;
153 warning ctx WDeprecated "@:native metadata for jni functions is deprecated. Use @:java.native instead." pos;
123154 true
124155 | _ -> false
125156 with | Not_found -> Meta.has Meta.NativeJni meta
174205 ast_fields
175206 in
176207 let super_args,super_expr,super_tl = get_struct_init_super_info ctx c p in
177 let params = List.map snd c.cl_params in
208 let params = extract_param_types c.cl_params in
178209 let ethis = mk (TConst TThis) (TInst(c,params)) p in
179210 let doc_buf = Buffer.create 0 in
180211 let args,el,tl = List.fold_left (fun (args,el,tl) cf -> match cf.cf_kind with
183214 let has_default_expr = field_has_default_expr cf.cf_name in
184215 let opt = has_default_expr || (Meta.has Meta.Optional cf.cf_meta) in
185216 let t = if opt then ctx.t.tnull cf.cf_type else cf.cf_type in
186 let v = alloc_var VGenerated cf.cf_name t p in
217 let v = alloc_var VGenerated cf.cf_name t cf.cf_name_pos in
187218 let ef = mk (TField(ethis,FInstance(c,params,cf))) cf.cf_type p in
188219 let ev = mk (TLocal v) v.v_type p in
189220 if opt && not (Meta.has Meta.Optional v.v_meta) then
239270 | FProp ((("get" | "never"),_),(("set" | "never"),_),_,_) when not stat ->
240271 f
241272 | FProp _ when not stat && not (Meta.has Meta.Enum f.cff_meta) ->
242 error "Member property accessors must be get/set or never" p;
273 typing_error "Member property accessors must be get/set or never" p;
243274 | FFun fu when fst f.cff_name = "new" && not stat ->
244 let init p = (EVars [mk_evar ~t:this_t ("this",null_pos)],p) in
275 let init p = (EVars [mk_evar ~t:this_t ~meta:([Meta.This,[],null_pos]) ("this",null_pos)],p) in
245276 let cast e = (ECast(e,None)),pos e in
246277 let ret p = (EReturn (Some (cast (EConst (Ident "this"),p))),p) in
247278 let meta = (Meta.NoCompletion,[],null_pos) :: f.cff_meta in
248279 if Meta.has Meta.MultiType a.a_meta then begin
249 if List.mem_assoc AInline f.cff_access then error "MultiType constructors cannot be inline" f.cff_pos;
250 if fu.f_expr <> None then error "MultiType constructors cannot have a body" f.cff_pos;
280 if List.mem_assoc AInline f.cff_access then typing_error "inline on MultiType constructor" f.cff_pos;
281 if fu.f_expr <> None then display_error com "MultiType constructors cannot have a body" f.cff_pos;
251282 f.cff_access <- (AExtern,null_pos) :: f.cff_access;
252283 end;
253284 (try
254285 let _, p = List.find (fun (acc, _) -> acc = AMacro) f.cff_access in
255 error "Macro abstract constructors are not supported" p
286 typing_error "Invalid modifier: macro on abstract constructor" p
256287 with Not_found -> ());
257288 (* We don't want the generated expression positions to shadow the real code. *)
258289 let p = { p with pmax = p.pmin } in
267298 } in
268299 { f with cff_name = "_new",pos f.cff_name; cff_kind = FFun fu; cff_meta = meta }
269300 | FFun fu when not stat ->
270 if Meta.has Meta.From f.cff_meta then error "@:from cast functions must be static" f.cff_pos;
301 if Meta.has Meta.From f.cff_meta then typing_error "@:from cast functions must be static" f.cff_pos;
271302 { f with cff_kind = FFun fu }
272303 | _ ->
273304 f
385416 | VUnknown ->
386417 ()
387418 | VPublic(access,p2) | VPrivate(access,p2) ->
388 display_error ctx (Printf.sprintf "Conflicting access modifier %s" (Ast.s_access access)) p1;
389 display_error ctx "Conflicts with this" p2;
419 display_error ctx.com (Printf.sprintf "Conflicting access modifier %s" (Ast.s_access access)) p1;
420 display_error ~depth:1 ctx.com "Conflicts with this" p2;
390421 in
391422 let rec loop visibility acc = match acc with
392423 | (AExtern,p) :: acc ->
393 display_error ctx "extern modifier is not allowed on enum abstract fields" p;
424 display_error ctx.com "Invalid modifier: extern on field of enum abstract" p;
394425 loop visibility acc
395426 | (APrivate,p) as access :: acc ->
396427 check_visibility_conflict visibility p;
408439 field.cff_meta <- (Meta.Enum,[],null_pos) :: field.cff_meta;
409440 let ct = match ct with
410441 | Some _ -> ct
411 | None -> Some (TExprToExpr.convert_type (TAbstract(a,List.map snd a.a_params)),null_pos)
442 | None -> Some (TExprToExpr.convert_type (TAbstract(a,extract_param_types a.a_params)),null_pos)
412443 in
413444 begin match eo with
414445 | None ->
416447 | EAString ->
417448 set_field field ct (EConst (String (fst field.cff_name,SDoubleQuotes)),null_pos)
418449 | EAInt i ->
419 set_field field ct (EConst (Int (string_of_int !i)),null_pos);
450 set_field field ct (EConst (Int (string_of_int !i, None)),null_pos);
420451 incr i;
421452 | EAOther ->
422 error "Value required" field.cff_pos
453 display_error ctx.com "Value required" field.cff_pos
423454 end else field.cff_kind <- FProp(("default",null_pos),("never",null_pos),ct,None)
424455 | Some e ->
425456 begin match mode,e with
426 | EAInt i,(EConst(Int s),_) ->
457 | EAInt i,(EConst(Int (s, None)),_) ->
427458 begin try
428459 let i' = int_of_string s in
429460 i := (i' + 1)
442473 let apply_macro ctx mode path el p =
443474 let cpath, meth = (match List.rev (ExtString.String.nsplit path ".") with
444475 | meth :: name :: pack -> (List.rev pack,name), meth
445 | _ -> error "Invalid macro path" p
476 | _ -> typing_error "Invalid macro path" p
446477 ) in
447478 ctx.g.do_macro ctx mode cpath meth el p
448479
452483 | Meta.Build,args,p when not is_typedef -> (fun () ->
453484 let epath, el = (match args with
454485 | [ECall (epath,el),p] -> epath, el
455 | _ -> error "Invalid build parameters" p
486 | _ -> typing_error "Invalid build parameters" p
456487 ) in
457 let s = try String.concat "." (List.rev (string_list_of_expr_path epath)) with Error (_,p) -> error "Build call parameter must be a class path" p in
458 if ctx.in_macro then error "You cannot use @:build inside a macro : make sure that your type is not used in macro" p;
488 let s = try String.concat "." (List.rev (string_list_of_expr_path epath)) with Error (_,p,depth) -> typing_error ~depth "Build call parameter must be a class path" p in
489 if ctx.com.is_macro_context then typing_error "You cannot use @:build inside a macro : make sure that your type is not used in macro" p;
459490 let old = ctx.get_build_infos in
460 ctx.get_build_infos <- (fun() -> Some (mt, List.map snd (t_infos mt).mt_params, fvars()));
491 ctx.get_build_infos <- (fun() -> Some (mt, extract_param_types (t_infos mt).mt_params, fvars()));
461492 context_init#run;
462493 let r = try apply_macro ctx MBuild s el p with e -> ctx.get_build_infos <- old; raise e in
463494 ctx.get_build_infos <- old;
464495 (match r with
465 | None -> error "Build failure" p
496 | None -> typing_error "Build failure" p
466497 | Some e -> fbuild e)
467498 ) :: f_build
468499 | Meta.Using,el,p -> (fun () ->
469500 List.iter (fun e ->
470501 try
471502 let path = List.rev (string_pos_list_of_expr_path_raise e) in
472 let types,filter_classes = handle_using ctx path (pos e) in
503 let types,filter_classes = ImportHandling.handle_using ctx path (pos e) in
473504 let ti =
474505 match mt with
475506 | TClassDecl { cl_kind = KAbstractImpl a } -> t_infos (TAbstractDecl a)
476507 | _ -> t_infos mt
477508 in
478 ti.mt_using <- (filter_classes types) @ ti.mt_using;
509 (* Delay for #10107, but use delay_late to make sure base classes run before their children do. *)
510 delay_late ctx PConnectField (fun () ->
511 ti.mt_using <- (filter_classes types) @ ti.mt_using
512 )
479513 with Exit ->
480 error "dot path expected" (pos e)
514 typing_error "dot path expected" (pos e)
481515 ) el;
482516 ) :: f_build
483517 | _ ->
485519 in
486520 (* let errors go through to prevent resume if build fails *)
487521 let f_build = List.fold_left loop [] meta in
488 (* Go for @:using in parents and interfaces *)
489522 let f_enum = match mt with
490523 | TClassDecl ({cl_kind = KAbstractImpl a} as c) when a.a_enum ->
491524 Some (fun () ->
492525 (* if p <> null_pos && not (Define.is_haxe3_compat ctx.com.defines) then
493 ctx.com.warning "`@:enum abstract` is deprecated in favor of `enum abstract`" p; *)
526 warning ctx WDeprecated "`@:enum abstract` is deprecated in favor of `enum abstract`" p; *)
494527 context_init#run;
495528 let e = build_enum_abstract ctx c a (fvars()) a.a_name_pos in
496529 fbuild e;
497530 )
498531 | TClassDecl { cl_super = csup; cl_implements = interfaces; cl_kind = kind } ->
532 (* Go for @:using in parents and interfaces *)
499533 let ti = t_infos mt in
500534 let inherit_using (c,_) =
501535 ti.mt_using <- ti.mt_using @ (t_infos (TClassDecl c)).mt_using
502536 in
503 Option.may inherit_using csup;
504 List.iter inherit_using interfaces;
537 delay_late ctx PConnectField (fun () ->
538 Option.may inherit_using csup;
539 List.iter inherit_using interfaces;
540 );
505541 None
506542 | _ ->
507543 None
509545 List.iter (fun f -> f()) (List.rev f_build);
510546 (match f_enum with None -> () | Some f -> f())
511547
512 let create_class_context ctx c context_init p =
513 locate_macro_error := true;
514 incr stats.s_classes_built;
548 let create_class_context c context_init p =
515549 let abstract = match c.cl_kind with
516550 | KAbstractImpl a -> Some a
517551 | _ -> None
518552 in
519 let ctx = {
520 ctx with
521 curclass = c;
522 type_params = c.cl_params;
523 pass = PBuildClass;
524 tthis = (match abstract with
525 | Some a ->
526 (match a.a_this with
527 | TMono r when r.tm_type = None -> TAbstract (a,List.map snd c.cl_params)
528 | t -> t)
529 | None -> TInst (c,List.map snd c.cl_params));
530 on_error = (fun ctx msg ep ->
531 ctx.com.error msg ep;
532 (* macros expressions might reference other code, let's recall which class we are actually compiling *)
533 let open TFunctions in
534 if not (ExtString.String.starts_with msg "...") && !locate_macro_error && (is_pos_outside_class c ep) && not (is_module_fields_class c) then ctx.com.error (compl_msg "Defined in this class") c.cl_pos
535 );
536 } in
537 (* a lib type will skip most checks *)
538553 let is_lib = Meta.has Meta.LibType c.cl_meta in
539 if is_lib && not (has_class_flag c CExtern) then ctx.com.error "@:libType can only be used in extern classes" c.cl_pos;
540554 (* a native type will skip one check: the static vs non-static field *)
541555 let is_native = Meta.has Meta.JavaNative c.cl_meta || Meta.has Meta.CsNative c.cl_meta in
542 if Meta.has Meta.Macro c.cl_meta then display_error ctx "Macro classes are no longer allowed in haxe 3" c.cl_pos;
543556 let rec extends_public c =
544557 Meta.has Meta.PublicFields c.cl_meta ||
545558 match c.cl_super with
560573 delayed_expr = [];
561574 has_display_field = false;
562575 } in
563 ctx,cctx
564
565 let create_field_context (ctx,cctx) c cff =
576 cctx
577
578 let create_typer_context_for_class ctx cctx p =
579 locate_macro_error := true;
580 incr stats.s_classes_built;
581 let c = cctx.tclass in
582 if cctx.is_lib && not (has_class_flag c CExtern) then ctx.com.error "@:libType can only be used in extern classes" c.cl_pos;
583 if Meta.has Meta.Macro c.cl_meta then display_error ctx.com "Macro classes are no longer allowed in haxe 3" c.cl_pos;
584 let ctx = {
585 ctx with
586 curclass = c;
587 type_params = c.cl_params;
588 pass = PBuildClass;
589 tthis = (match cctx.abstract with
590 | Some a ->
591 (match a.a_this with
592 | TMono r when r.tm_type = None -> TAbstract (a,extract_param_types c.cl_params)
593 | t -> t)
594 | None -> TInst (c,extract_param_types c.cl_params));
595 } in
596 ctx
597
598 let create_field_context cctx cff is_display_file display_modifier =
599 let is_static = List.mem_assoc AStatic cff.cff_access in
600 let is_static,is_abstract_member = if cctx.abstract <> None && not is_static then true,true else is_static,false in
601 let is_extern = ref (List.mem_assoc AExtern cff.cff_access) in
602 let is_abstract = List.mem_assoc AAbstract cff.cff_access in
603 let is_final = ref (List.mem_assoc AFinal cff.cff_access) in
604 List.iter (fun (m,_,p) ->
605 match m with
606 | Meta.Final ->
607 is_final := true;
608 (* if p <> null_pos && not (Define.is_haxe3_compat ctx.com.defines) then
609 warning ctx WDeprecated "`@:final` is deprecated in favor of `final`" p; *)
610 | Meta.Extern ->
611 (* if not (Define.is_haxe3_compat ctx.com.defines) then
612 warning ctx WDeprecated "`@:extern` on fields is deprecated in favor of `extern`" (pos cff.cff_name); *)
613 is_extern := true;
614 | _ ->
615 ()
616 ) cff.cff_meta;
617 let is_inline = List.mem_assoc AInline cff.cff_access in
618 let override = try Some (List.assoc AOverride cff.cff_access) with Not_found -> None in
619 let overload = try Some (List.assoc AOverload cff.cff_access) with Not_found -> None in
620 let is_macro = List.mem_assoc AMacro cff.cff_access in
621 let field_kind = match fst cff.cff_name with
622 | "new" -> FKConstructor
623 | "__init__" when is_static -> FKInit
624 | _ -> FKNormal
625 in
626 let default = try
627 let (_,_,p) = Meta.get Meta.JavaDefault cff.cff_meta in
628 Some p
629 with Not_found ->
630 None
631 in
632 let c = cctx.tclass in
633 let fctx = {
634 is_inline = is_inline;
635 is_static = is_static;
636 default = default;
637 override = override;
638 overload = overload;
639 is_macro = is_macro;
640 is_extern = !is_extern;
641 is_abstract = is_abstract;
642 is_final = !is_final;
643 is_display_field = is_display_file && DisplayPosition.display_position#enclosed_in cff.cff_pos;
644 is_field_debug = cctx.is_class_debug || Meta.has (Meta.Custom ":debug.typeload") cff.cff_meta;
645 display_modifier = display_modifier;
646 is_abstract_member = is_abstract_member;
647 is_generic = Meta.has Meta.Generic cff.cff_meta;
648 field_kind = field_kind;
649 do_bind = (((not ((has_class_flag c CExtern) || !is_extern) || is_inline) && not is_abstract && not (has_class_flag c CInterface)) || field_kind = FKInit);
650 do_add = true;
651 expr_presence_matters = false;
652 had_error = false;
653 } in
654 if fctx.is_display_field then cctx.has_display_field <- true;
655 fctx
656
657 let create_typer_context_for_field ctx cctx fctx cff =
566658 DeprecationCheck.check_is ctx.com (fst cff.cff_name) cff.cff_meta (snd cff.cff_name);
567659 let ctx = {
568660 ctx with
573665 perfunction = [];
574666 };
575667 } in
576 let display_modifier = Typeload.check_field_access ctx cff in
577 let is_static = List.mem_assoc AStatic cff.cff_access in
578 let is_static,is_abstract_member = if cctx.abstract <> None && not is_static then true,true else is_static,false in
579 let is_extern = ref (List.mem_assoc AExtern cff.cff_access) in
580 let is_abstract = List.mem_assoc AAbstract cff.cff_access in
581 let is_final = ref (List.mem_assoc AFinal cff.cff_access) in
582 List.iter (fun (m,_,p) ->
583 match m with
584 | Meta.Final ->
585 is_final := true;
586 (* if p <> null_pos && not (Define.is_haxe3_compat ctx.com.defines) then
587 ctx.com.warning "`@:final` is deprecated in favor of `final`" p; *)
588 | Meta.Extern ->
589 (* if not (Define.is_haxe3_compat ctx.com.defines) then
590 ctx.com.warning "`@:extern` on fields is deprecated in favor of `extern`" (pos cff.cff_name); *)
591 is_extern := true;
592 | _ ->
593 ()
594 ) cff.cff_meta;
595 let is_inline = List.mem_assoc AInline cff.cff_access in
596 if (is_abstract && not (has_meta Meta.LibType c.cl_meta)) then begin
597 if is_static then
598 display_error ctx "Static methods may not be abstract" (pos cff.cff_name)
599 else if !is_final then
600 display_error ctx "Abstract methods may not be final" (pos cff.cff_name)
601 else if is_inline then
602 display_error ctx "Abstract methods may not be inline" (pos cff.cff_name)
668 let c = cctx.tclass in
669 if (fctx.is_abstract && not (has_meta Meta.LibType c.cl_meta)) then begin
670 if fctx.is_static then
671 invalid_modifier_combination fctx ctx.com fctx "abstract" "static" (pos cff.cff_name)
672 else if fctx.is_final then
673 invalid_modifier_combination fctx ctx.com fctx "abstract" "final" (pos cff.cff_name)
674 else if fctx.is_inline then
675 invalid_modifier_combination fctx ctx.com fctx "abstract" "inline" (pos cff.cff_name)
603676 else if not (has_class_flag c CAbstract) then begin
604 display_error ctx "This class should be declared abstract because it has at least one abstract field" c.cl_name_pos;
605 display_error ctx "First abstract field was here" (pos cff.cff_name);
677 display_error ctx.com "This class should be declared abstract because it has at least one abstract field" c.cl_name_pos;
678 display_error ctx.com "First abstract field was here" (pos cff.cff_name);
606679 add_class_flag c CAbstract;
607680 end;
608681 end;
609 let override = try Some (List.assoc AOverride cff.cff_access) with Not_found -> None in
610 let overload = try Some (List.assoc AOverload cff.cff_access) with Not_found -> None in
611 let is_macro = List.mem_assoc AMacro cff.cff_access in
612 let field_kind = match fst cff.cff_name with
613 | "new" -> FKConstructor
614 | "__init__" when is_static -> FKInit
615 | _ -> FKNormal
616 in
617 let fctx = {
618 is_inline = is_inline;
619 is_static = is_static;
620 override = override;
621 overload = overload;
622 is_macro = is_macro;
623 is_extern = !is_extern;
624 is_abstract = is_abstract;
625 is_final = !is_final;
626 is_display_field = ctx.is_display_file && DisplayPosition.display_position#enclosed_in cff.cff_pos;
627 is_field_debug = cctx.is_class_debug || Meta.has (Meta.Custom ":debug.typeload") cff.cff_meta;
628 display_modifier = display_modifier;
629 is_abstract_member = is_abstract_member;
630 is_generic = Meta.has Meta.Generic cff.cff_meta;
631 field_kind = field_kind;
632 do_bind = (((not ((has_class_flag c CExtern) || !is_extern) || is_inline) && not is_abstract && not (has_class_flag c CInterface)) || field_kind = FKInit);
633 do_add = true;
634 expr_presence_matters = false;
635 } in
636 if fctx.is_display_field then cctx.has_display_field <- true;
637 ctx,fctx
682 ctx
638683
639684 let is_public (ctx,cctx) access parent =
640685 let c = cctx.tclass in
655700 with
656701 Not_found -> get_parent csup name
657702
703 let transform_abstract_field2 ctx a cff =
704 let a_t = TExprToExpr.convert_type' (TAbstract(a,extract_param_types a.a_params)) in
705 let this_t = TExprToExpr.convert_type' a.a_this in (* TODO: better pos? *)
706 transform_abstract_field ctx.com this_t a_t a cff
707
658708 let transform_field (ctx,cctx) c f fields p =
659709 let f = match cctx.abstract with
660710 | Some a ->
661 let a_t = TExprToExpr.convert_type' (TAbstract(a,List.map snd a.a_params)) in
662 let this_t = TExprToExpr.convert_type' a.a_this in (* TODO: better pos? *)
663 transform_abstract_field ctx.com this_t a_t a f
711 transform_abstract_field2 ctx a f
664712 | None ->
665713 f
666714 in
667715 if List.mem_assoc AMacro f.cff_access then
668716 (match ctx.g.macros with
669 | Some (_,mctx) when Hashtbl.mem mctx.g.types_module c.cl_path ->
717 | Some (_,mctx) when mctx.com.type_to_module#mem c.cl_path ->
670718 (* assume that if we had already a macro with the same name, it has not been changed during the @:build operation *)
671719 if not (List.exists (fun f2 -> f2.cff_name = f.cff_name && List.mem_assoc AMacro f2.cff_access) (!fields)) then
672 error "Class build macro cannot return a macro function when the class has already been compiled into the macro context" p
720 typing_error "Class build macro cannot return a macro function when the class has already been compiled into the macro context" p
673721 | _ -> ());
674722 f
675723
696744 | EVars [{ ev_type = Some (CTAnonymous f,p); ev_expr = None }] ->
697745 let f = List.map (fun f -> transform_field (ctx,cctx) c f fields p) f in
698746 fields := f
699 | _ -> error "Class build macro must return a single variable with anonymous fields" p
747 | _ -> typing_error "Class build macro must return a single variable with anonymous fields" p
700748 );
701749 c.cl_build <- (fun() -> Building [c]);
702750 List.iter (fun f -> f()) !pending;
739787 | TMono r -> (match r.tm_type with None -> false | Some t -> is_full_type t)
740788 | TAbstract _ | TInst _ | TEnum _ | TLazy _ | TDynamic _ | TAnon _ | TType _ -> true
741789 in
742 let force_macro () =
790 let force_macro display =
743791 (* force macro system loading of this class in order to get completion *)
744 delay ctx PTypeField (fun() -> try ignore(ctx.g.do_macro ctx MDisplay c.cl_path cf.cf_name [] p) with Exit | Error _ -> ())
792 delay ctx PTypeField (fun() ->
793 try
794 ignore(ctx.g.do_macro ctx MDisplay c.cl_path cf.cf_name [] p)
795 with
796 | Exit ->
797 ()
798 | Error _ when display ->
799 ()
800 )
745801 in
746802 let handle_display_field () =
747 if fctx.is_macro && not ctx.in_macro then
748 force_macro()
803 if fctx.is_macro && not ctx.com.is_macro_context then
804 force_macro true
749805 else begin
750806 cf.cf_type <- TLazy r;
751807 cctx.delayed_expr <- (ctx,Some r) :: cctx.delayed_expr;
752808 end
753809 in
754810 if ctx.com.display.dms_full_typing then begin
755 if fctx.is_macro && not ctx.in_macro then
756 force_macro ()
811 if fctx.is_macro && not ctx.com.is_macro_context then
812 force_macro false
757813 else begin
758814 cf.cf_type <- TLazy r;
759815 (* is_lib ? *)
760816 cctx.delayed_expr <- (ctx,Some r) :: cctx.delayed_expr;
761817 end
762 end else if ctx.com.display.dms_force_macro_typing && fctx.is_macro && not ctx.in_macro then
763 force_macro()
818 end else if ctx.com.display.dms_force_macro_typing && fctx.is_macro && not ctx.com.is_macro_context then
819 force_macro true
764820 else begin
765821 if fctx.is_display_field then begin
766822 handle_display_field()
797853 | Some (csup,_) ->
798854 (* this can happen on -net-lib generated classes if a combination of explicit interfaces and variables with the same name happens *)
799855 if not ((has_class_flag csup CInterface) && Meta.has Meta.CsNative c.cl_meta) then
800 error ("Redefinition of variable " ^ cf.cf_name ^ " in subclass is not allowed. Previously declared at " ^ (s_type_path csup.cl_path) ) cf.cf_name_pos
856 display_error ctx.com ("Redefinition of variable " ^ cf.cf_name ^ " in subclass is not allowed. Previously declared at " ^ (s_type_path csup.cl_path) ) cf.cf_name_pos
801857 end
802858
803859 let bind_var_expression ctx cctx fctx cf e =
804860 let c = cctx.tclass in
805861 let t = cf.cf_type in
806862 let p = cf.cf_pos in
807 if (has_class_flag c CInterface) then display_error ctx "Default values on interfaces are not allowed" (pos e);
863 if (has_class_flag c CInterface) then unexpected_expression ctx.com fctx "Initialization on field of interface" (pos e);
808864 cf.cf_meta <- ((Meta.Value,[e],null_pos) :: cf.cf_meta);
809865 let check_cast e =
810866 (* insert cast to keep explicit field type (issue #1901) *)
823879 if not !return_partial_type || (match fst e with EConst _ -> true | _ -> false) then begin
824880 r := lazy_processing (fun() -> t);
825881 cctx.context_init#run;
826 if ctx.com.verbose then Common.log ctx.com ("Typing " ^ (if ctx.in_macro then "macro " else "") ^ s_type_path c.cl_path ^ "." ^ cf.cf_name);
882 if ctx.com.verbose then Common.log ctx.com ("Typing " ^ (if ctx.com.is_macro_context then "macro " else "") ^ s_type_path c.cl_path ^ "." ^ cf.cf_name);
827883 let e = type_var_field ctx t e fctx.is_static fctx.is_display_field p in
828884 let maybe_run_analyzer e = match e.eexpr with
829885 | TConst _ | TLocal _ | TFunction _ -> e
830 | _ -> !analyzer_run_on_expr_ref ctx.com e
886 | _ -> !analyzer_run_on_expr_ref ctx.com (Printf.sprintf "%s.%s" (s_type_path cctx.tclass.cl_path) cf.cf_name) e
831887 in
832888 let require_constant_expression e msg =
833 if ctx.com.display.dms_kind <> DMNone && ctx.com.display.dms_error_policy <> EPCollect then
834 e
835 else match Optimizer.make_constant_expression ctx (maybe_run_analyzer e) with
889 match Optimizer.make_constant_expression ctx (maybe_run_analyzer e) with
836890 | Some e -> e
837 | None -> display_error ctx msg p; e
891 | None -> display_error ctx.com msg p; e
838892 in
839893 let e = (match cf.cf_kind with
840894 | Var v when (has_class_flag c CExtern) || fctx.is_extern ->
841895 if not fctx.is_static then begin
842 display_error ctx "Extern non-static variables may not be initialized" p;
896 unexpected_expression ctx.com fctx "on extern non-static variable" p;
843897 e
844898 end else if not fctx.is_inline then begin
845 display_error ctx "Extern non-inline variables may not be initialized" p;
899 unexpected_expression ctx.com fctx "on extern non-inline variable" p;
846900 e
847901 end else require_constant_expression e "Extern variable initialization must be a constant value"
848902 | Var v when not (is_physical_field cf) ->
849903 (* disallow initialization of non-physical fields (issue #1958) *)
850 display_error ctx "This field cannot be initialized because it is not a real variable" p; e
904 unexpected_expression ctx.com fctx "on field that is not a real variable" p; e
851905 | Var v when not fctx.is_static ->
852 let e = if ctx.com.display.dms_display && ctx.com.display.dms_error_policy <> EPCollect then
853 e
854 else begin
906 let e = begin
855907 let rec check_this e = match e.eexpr with
856908 | TConst TThis ->
857 display_error ctx "Cannot access this or other member field in variable initialization" e.epos;
909 display_error ctx.com "Cannot access this or other member field in variable initialization" e.epos;
858910 raise Exit
859911 | TLocal v when (match ctx.vthis with Some v2 -> v == v2 | None -> false) ->
860 display_error ctx "Cannot access this or other member field in variable initialization" e.epos;
912 display_error ctx.com "Cannot access this or other member field in variable initialization" e.epos;
861913 raise Exit
862914 | _ ->
863915 Type.iter check_this e
905957 r := lazy_processing (fun() -> t);
906958 cctx.context_init#run;
907959 incr stats.s_methods_typed;
908 if ctx.com.verbose then Common.log ctx.com ("Typing " ^ (if ctx.in_macro then "macro " else "") ^ s_type_path c.cl_path ^ "." ^ cf.cf_name);
960 if ctx.com.verbose then Common.log ctx.com ("Typing " ^ (if ctx.com.is_macro_context then "macro " else "") ^ s_type_path c.cl_path ^ "." ^ cf.cf_name);
909961 let fmode = (match cctx.abstract with
910962 | Some _ ->
911963 if fctx.is_abstract_member then FunMemberAbstract else FunStatic
915967 begin match ctx.com.platform with
916968 | Java when is_java_native_function ctx cf.cf_meta cf.cf_pos ->
917969 if e <> None then
918 ctx.com.warning "@:java.native function definitions shouldn't include an expression. This behaviour is deprecated." cf.cf_pos;
970 warning ctx WDeprecated "@:java.native function definitions shouldn't include an expression. This behaviour is deprecated." cf.cf_pos;
919971 cf.cf_expr <- None;
920972 cf.cf_type <- t
921973 | _ ->
927979 end;
928980 (* Disabled for now, see https://github.com/HaxeFoundation/haxe/issues/3033 *)
929981 (* List.iter (fun (v,_) ->
930 if v.v_name <> "_" && has_mono v.v_type then ctx.com.warning "Uninferred function argument, please add a type-hint" v.v_pos;
982 if v.v_name <> "_" && has_mono v.v_type then warning ctx WTemp "Uninferred function argument, please add a type-hint" v.v_pos;
931983 ) fargs; *)
932984 let tf = {
933985 tf_args = args#for_expr;
9511003 bind_type ctx cctx fctx cf r p
9521004 end
9531005
1006 let load_variable_type_hint ctx fctx eo p = function
1007 | None when eo = None ->
1008 missing_expression ctx.com fctx "Variable requires type-hint or initialization" p;
1009 t_dynamic
1010 | None ->
1011 mk_mono()
1012 | Some t ->
1013 lazy_display_type ctx (fun () -> load_type_hint ctx p (Some t))
1014
9541015 let create_variable (ctx,cctx,fctx) c f t eo p =
9551016 let is_abstract_enum_field = Meta.has Meta.Enum f.cff_meta in
956 if fctx.is_abstract_member && not is_abstract_enum_field then error (fst f.cff_name ^ ": Cannot declare member variable in abstract") p;
957 if fctx.is_inline && not fctx.is_static then error (fst f.cff_name ^ ": Inline variable must be static") p;
958 if fctx.is_inline && eo = None then error (fst f.cff_name ^ ": Inline variable must be initialized") p;
1017 if fctx.is_abstract_member && not is_abstract_enum_field then typing_error "Cannot declare member variable in abstract" p;
1018 if fctx.is_inline && not fctx.is_static then invalid_modifier ctx.com fctx "inline" "non-static variable" p;
1019 if fctx.is_inline && eo = None then missing_expression ctx.com fctx "Inline variable must be initialized" p;
9591020 let missing_initialization =
9601021 fctx.is_final
9611022 && not (fctx.is_extern || (has_class_flag c CExtern) || (has_class_flag c CInterface))
9621023 && eo = None
9631024 in
9641025 if missing_initialization && fctx.is_static && fctx.is_final then
965 error (fst f.cff_name ^ ": Static final variable must be initialized") p;
966 let t = (match t with
967 | None when eo = None ->
968 error ("Variable requires type-hint or initialization") (pos f.cff_name);
969 | None ->
970 mk_mono()
971 | Some t ->
972 lazy_display_type ctx (fun () -> load_type_hint ctx p (Some t))
973 ) in
1026 missing_expression ctx.com fctx "Static final variable must be initialized" p;
1027 let t = load_variable_type_hint ctx fctx eo (pos f.cff_name) t in
9741028 let kind = if fctx.is_inline then
9751029 { v_read = AccInline ; v_write = AccNever }
9761030 else if fctx.is_final then
10161070 let r = exc_protect ctx (fun r ->
10171071 r := lazy_processing (fun () -> t);
10181072 (* the return type of a from-function must be the abstract, not the underlying type *)
1019 if not fctx.is_macro then (try type_eq EqStrict ret ta with Unify_error l -> error (error_msg (Unify l)) p);
1073 if not fctx.is_macro then (try type_eq EqStrict ret ta with Unify_error l -> located_typing_error (error_msg p (Unify l)));
10201074 match t with
10211075 | TFun([_,_,t],_) -> t
1022 | _ -> error (cf.cf_name ^ ": @:from cast functions must accept exactly one argument") p
1076 | TFun([(_,_,t1);(_,true,t2)],_) when is_pos_infos t2 -> t1
1077 | _ -> typing_error ("@:from cast functions must accept exactly one argument") p
10231078 ) "@:from" in
10241079 a.a_from_field <- (TLazy r,cf) :: a.a_from_field;
10251080 | (Meta.To,_,_) :: _ ->
1026 if fctx.is_macro then error (cf.cf_name ^ ": Macro cast functions are not supported") p;
1081 if fctx.is_macro then invalid_modifier ctx.com fctx "macro" "cast function" p;
1082 let are_valid_args args =
1083 match args with
1084 | [_] -> true
1085 | [_; (_,true,t)] when is_pos_infos t -> true
1086 | _ -> false
1087 in
10271088 (match cf.cf_kind, cf.cf_type with
10281089 | Var _, _ ->
1029 error "@:to meta should be used on methods" p
1030 | Method _, TFun(args, _) when not fctx.is_abstract_member && List.length args <> 1 ->
1090 typing_error "Invalid metadata: @:to must be used on method of abstract" p
1091 | Method _, TFun(args, _) when not fctx.is_abstract_member && not (are_valid_args args) ->
10311092 if not (Meta.has Meta.MultiType a.a_meta) then (* TODO: get rid of this check once multitype is removed *)
1032 error ("static @:to method should have one argument") p
1033 | Method _, TFun(args, _) when fctx.is_abstract_member && List.length args <> 1 ->
1093 typing_error "static @:to method should have one argument" p
1094 | Method _, TFun(args, _) when fctx.is_abstract_member && not (are_valid_args args) ->
10341095 if not (Meta.has Meta.MultiType a.a_meta) then (* TODO: get rid of this check once multitype is removed *)
1035 error "@:to method should have no arguments" p
1096 typing_error "@:to method should have no arguments" p
10361097 | _ -> ()
10371098 );
10381099 (* TODO: this doesn't seem quite right... *)
10391100 if not (has_class_field_flag cf CfImpl) then add_class_field_flag cf CfImpl;
10401101 let resolve_m args =
1041 (try unify_raise ctx t (tfun (tthis :: args) m) cf.cf_pos with Error (Unify l,p) -> error (error_msg (Unify l)) p);
1102 (try unify_raise t (tfun (tthis :: args) m) cf.cf_pos with Error (Unify l,p,depth) -> located_typing_error ~depth (error_msg p (Unify l)));
10421103 match follow m with
10431104 | TMono _ when (match t with TFun(_,r) -> r == t_dynamic | _ -> false) -> t_dynamic
10441105 | m -> m
10521113 let ctor = try
10531114 PMap.find "_new" c.cl_statics
10541115 with Not_found ->
1055 error "Constructor of multi-type abstract must be defined before the individual @:to-functions are" cf.cf_pos
1116 typing_error "Constructor of multi-type abstract must be defined before the individual @:to-functions are" cf.cf_pos
10561117 in
10571118 (* delay ctx PFinal (fun () -> unify ctx m tthis f.cff_pos); *)
10581119 let args = match follow (monomorphs a.a_params ctor.cf_type) with
10611122 in
10621123 args
10631124 end else
1064 []
1125 match cf.cf_type with
1126 | TFun([_;(_,true,t)],_) when is_pos_infos t -> [t]
1127 | _ -> []
10651128 in
10661129 let t = resolve_m args in
10671130 t
10681131 ) "@:to" in
10691132 a.a_to_field <- (TLazy r, cf) :: a.a_to_field
10701133 | ((Meta.ArrayAccess,_,_) | (Meta.Op,[(EArrayDecl _),_],_)) :: _ ->
1071 if fctx.is_macro then error (cf.cf_name ^ ": Macro array-access functions are not supported") p;
1134 if fctx.is_macro then invalid_modifier ctx.com fctx "macro" "array-access function" p;
10721135 a.a_array <- cf :: a.a_array;
10731136 allow_no_expr();
10741137 | (Meta.Op,[EBinop(OpAssign,_,_),_],_) :: _ ->
1075 error (cf.cf_name ^ ": Assignment overloading is not supported") p;
1138 typing_error "Assignment overloading is not supported" p;
1139 | (Meta.Op,[EBinop(OpAssignOp OpNullCoal,_,_),_],_) :: _
1140 | (Meta.Op,[EBinop(OpNullCoal,_,_),_],_) :: _ ->
1141 typing_error "Null coalescing overloading is not supported" p;
10761142 | (Meta.Op,[ETernary(_,_,_),_],_) :: _ ->
1077 error (cf.cf_name ^ ": Ternary overloading is not supported") p;
1143 typing_error "Ternary overloading is not supported" p;
10781144 | (Meta.Op,[EBinop(op,_,_),_],_) :: _ ->
1079 if fctx.is_macro then error (cf.cf_name ^ ": Macro operator functions are not supported") p;
1145 if fctx.is_macro then invalid_modifier ctx.com fctx "macro" "operator function" p;
10801146 let targ = if fctx.is_abstract_member then tthis else ta in
1081 let left_eq,right_eq = match follow t with
1147 let left_eq,right_eq =
1148 match follow t with
10821149 | TFun([(_,_,t1);(_,_,t2)],_) ->
1150 type_iseq targ t1,type_iseq targ t2
1151 | TFun([(_,_,t1);(_,_,t2);(_,true,t3)],_) when is_pos_infos t3 ->
10831152 type_iseq targ t1,type_iseq targ t2
10841153 | _ ->
10851154 if fctx.is_abstract_member then
1086 error (cf.cf_name ^ ": Member @:op functions must accept exactly one argument") cf.cf_pos
1155 typing_error ("Member @:op functions must accept exactly one argument") cf.cf_pos
10871156 else
1088 error (cf.cf_name ^ ": Static @:op functions must accept exactly two arguments") cf.cf_pos
1157 typing_error ("Static @:op functions must accept exactly two arguments") cf.cf_pos
10891158 in
1090 if not (left_eq || right_eq) then error (cf.cf_name ^ ": The left or right argument type must be " ^ (s_type (print_context()) targ)) cf.cf_pos;
1091 if right_eq && Meta.has Meta.Commutative cf.cf_meta then error (cf.cf_name ^ ": @:commutative is only allowed if the right argument is not " ^ (s_type (print_context()) targ)) cf.cf_pos;
1159 if not (left_eq || right_eq) then typing_error ("The left or right argument type must be " ^ (s_type (print_context()) targ)) cf.cf_pos;
1160 if right_eq && Meta.has Meta.Commutative cf.cf_meta then typing_error ("Invalid metadata: @:commutative is only allowed if the right argument is not " ^ (s_type (print_context()) targ)) cf.cf_pos;
10921161 a.a_ops <- (op,cf) :: a.a_ops;
10931162 allow_no_expr();
10941163 | (Meta.Op,[EUnop(op,flag,_),_],_) :: _ ->
1095 if fctx.is_macro then error (cf.cf_name ^ ": Macro operator functions are not supported") p;
1164 if fctx.is_macro then invalid_modifier ctx.com fctx "macro" "operator function" p;
10961165 let targ = if fctx.is_abstract_member then tthis else ta in
1097 (try type_eq EqStrict t (tfun [targ] (mk_mono())) with Unify_error l -> raise (Error ((Unify l),cf.cf_pos)));
1166 (try type_eq EqStrict t (tfun [targ] (mk_mono())) with Unify_error l -> raise (Error ((Unify l),cf.cf_pos,0)));
10981167 a.a_unops <- (op,flag,cf) :: a.a_unops;
1168 allow_no_expr();
1169 | (Meta.Op,[ECall _,_],_) :: _ ->
1170 begin match a.a_call with
1171 | None ->
1172 a.a_call <- Some cf
1173 | Some cf' ->
1174 cf'.cf_overloads <- cf :: cf'.cf_overloads
1175 end;
10991176 allow_no_expr();
11001177 | ((Meta.Resolve,_,_) | (Meta.Op,[EField _,_],_)) :: _ ->
11011178 let targ = if fctx.is_abstract_member then tthis else ta in
11021179 let check_fun t1 t2 =
11031180 if not fctx.is_macro then begin
1104 if not (type_iseq targ t1) then error ("First argument type must be " ^ (s_type (print_context()) targ)) cf.cf_pos;
1105 if not (type_iseq ctx.t.tstring t2) then error ("Second argument type must be String") cf.cf_pos
1181 if not (type_iseq targ t1) then typing_error ("First argument type must be " ^ (s_type (print_context()) targ)) cf.cf_pos;
1182 if not (type_iseq ctx.t.tstring t2) then typing_error ("Second argument type must be String") cf.cf_pos
11061183 end
11071184 in
11081185 begin match follow t with
1109 | TFun([(_,_,t1);(_,_,t2)],_) ->
1110 if a.a_read <> None then error "Multiple resolve-read methods are not supported" cf.cf_pos;
1186 | TFun((_,_,t1) :: (_,_,t2) :: args,_) when is_empty_or_pos_infos args ->
1187 if a.a_read <> None then typing_error "Multiple resolve-read methods are not supported" cf.cf_pos;
11111188 check_fun t1 t2;
11121189 a.a_read <- Some cf;
1113 | TFun([(_,_,t1);(_,_,t2);(_,_,t3)],_) ->
1114 if a.a_write <> None then error "Multiple resolve-write methods are not supported" cf.cf_pos;
1190 | TFun((_,_,t1) :: (_,_,t2) :: (_,_,t3) :: args,_) when is_empty_or_pos_infos args ->
1191 if a.a_write <> None then typing_error "Multiple resolve-write methods are not supported" cf.cf_pos;
11151192 check_fun t1 t2;
11161193 a.a_write <- Some cf;
11171194 | _ ->
1118 error ("Field type of resolve must be " ^ (s_type (print_context()) targ) ^ " -> String -> T") cf.cf_pos
1195 typing_error ("Field type of resolve must be " ^ (s_type (print_context()) targ) ^ " -> String -> T") cf.cf_pos
11191196 end;
11201197 | _ -> ());
11211198 match ml with
11251202 loop cf.cf_meta;
11261203 if cf.cf_name = "_new" && Meta.has Meta.MultiType a.a_meta then fctx.do_bind <- false;
11271204 if fd.f_expr = None then begin
1128 if fctx.is_inline then error (cf.cf_name ^ ": Inline functions must have an expression") cf.cf_pos;
1129 if fd.f_type = None then error (cf.cf_name ^ ": Functions without expressions must have an explicit return type") cf.cf_pos;
1205 if fctx.is_inline then missing_expression ctx.com fctx "Inline functions must have an expression" cf.cf_pos;
1206 if fd.f_type = None then typing_error ("Functions without expressions must have an explicit return type") cf.cf_pos;
11301207 if !allows_no_expr then begin
11311208 cf.cf_meta <- (Meta.NoExpr,[],null_pos) :: cf.cf_meta;
11321209 fctx.do_bind <- false;
11361213 | _ ->
11371214 ()
11381215
1216 let type_opt (ctx,cctx,fctx) p t =
1217 let c = cctx.tclass in
1218 let is_truly_extern =
1219 (has_class_flag c CExtern || fctx.is_extern)
1220 && not fctx.is_inline (* if it's inline, we can infer the type from the expression *)
1221 in
1222 match t with
1223 | None when is_truly_extern || (has_class_flag c CInterface) ->
1224 display_error ctx.com "Type required for extern classes and interfaces" p;
1225 t_dynamic
1226 | None when cctx.is_core_api ->
1227 display_error ctx.com "Type required for core api classes" p;
1228 t_dynamic
1229 | None when fctx.is_abstract ->
1230 display_error ctx.com "Type required for abstract functions" p;
1231 t_dynamic
1232 | _ ->
1233 Typeload.load_type_hint ctx p t
1234
1235 let setup_args_ret ctx cctx fctx name fd p =
1236 let c = cctx.tclass in
1237 let mk = lazy (
1238 if String.length name < 4 then
1239 MKNormal
1240 else match String.sub name 0 4 with
1241 | "get_" ->
1242 begin match fd.f_args with
1243 | [] -> MKGetter
1244 | _ -> MKNormal
1245 end
1246 | "set_" ->
1247 begin match fd.f_args with
1248 | [_] -> MKSetter
1249 | _ -> MKNormal
1250 end
1251 | _ ->
1252 MKNormal
1253 ) in
1254 let try_find_property_type () =
1255 let name = String.sub name 4 (String.length name - 4) in
1256 let cf = if fctx.is_static then PMap.find name c.cl_statics else PMap.find name c.cl_fields (* TODO: inheritance? *) in
1257 match Lazy.force mk, cf.cf_kind with
1258 | MKGetter, Var({v_read = AccCall}) | MKSetter, Var({v_write = AccCall}) -> cf.cf_type
1259 | _ -> raise Not_found;
1260 in
1261 let maybe_use_property_type th check def =
1262 if th = None && check() then
1263 try
1264 try_find_property_type()
1265 with Not_found ->
1266 def()
1267 else
1268 def()
1269 in
1270 let ret = if fctx.field_kind = FKConstructor then
1271 ctx.t.tvoid
1272 else begin
1273 let def () =
1274 type_opt (ctx,cctx,fctx) p fd.f_type
1275 in
1276 maybe_use_property_type fd.f_type (fun () -> match Lazy.force mk with MKGetter | MKSetter -> true | _ -> false) def
1277 end in
1278 let abstract_this = match cctx.abstract with
1279 | Some a when fctx.is_abstract_member && name <> "_new" (* TODO: this sucks *) && not fctx.is_macro ->
1280 Some a.a_this
1281 | _ ->
1282 None
1283 in
1284 let is_extern = fctx.is_extern || has_class_flag ctx.curclass CExtern in
1285 let type_arg i opt cto p =
1286 let def () =
1287 type_opt (ctx,cctx,fctx) p cto
1288 in
1289 if i = 0 then maybe_use_property_type cto (fun () -> match Lazy.force mk with MKSetter -> true | _ -> false) def else def()
1290 in
1291 let args = new FunctionArguments.function_arguments ctx type_arg is_extern fctx.is_display_field abstract_this fd.f_args in
1292 args,ret
1293
11391294 let create_method (ctx,cctx,fctx) c f fd p =
1140 let params = TypeloadFunction.type_function_params ctx fd (fst f.cff_name) p in
1295 let name = fst f.cff_name in
1296 let params = TypeloadFunction.type_function_params ctx fd name p in
11411297 if fctx.is_generic then begin
1142 if params = [] then error (fst f.cff_name ^ ": Generic functions must have type parameters") p;
1298 if params = [] then typing_error "Generic functions must have type parameters" p;
11431299 end;
1144 let fd = if fctx.is_macro && not ctx.in_macro && not fctx.is_static then
1300 let fd = if fctx.is_macro && not ctx.com.is_macro_context && not fctx.is_static then
11451301 (* remove display of first argument which will contain the "this" expression *)
11461302 { fd with f_args = match fd.f_args with [] -> [] | _ :: l -> l }
11471303 else
11501306 let fd = if not fctx.is_macro then
11511307 fd
11521308 else begin
1153 if ctx.in_macro then begin
1309 if ctx.com.is_macro_context then begin
11541310 (* a class with a macro cannot be extern in macro context (issue #2015) *)
11551311 remove_class_flag c CExtern;
11561312 let texpr = CTPath (mk_type_path (["haxe";"macro"],"Expr")) in
11711327 let to_dyn p t = match t with
11721328 | { tpackage = ["haxe";"macro"]; tname = "Expr"; tsub = Some ("ExprOf"); tparams = [TPType t] } -> Some t
11731329 | { tpackage = []; tname = ("ExprOf"); tsub = None; tparams = [TPType t] } -> Some t
1174 | { tpackage = ["haxe"]; tname = ("PosInfos"); tsub = None; tparams = [] } -> error "haxe.PosInfos is not allowed on macro functions, use Context.currentPos() instead" p
1330 | { tpackage = ["haxe"]; tname = ("PosInfos"); tsub = None; tparams = [] } -> typing_error "haxe.PosInfos is not allowed on macro functions, use Context.currentPos() instead" p
11751331 | _ -> tdyn
11761332 in
11771333 {
11831339 end in
11841340 begin match (has_class_flag c CInterface),fctx.field_kind with
11851341 | true,FKConstructor ->
1186 error "An interface cannot have a constructor" p;
1342 typing_error "An interface cannot have a constructor" p;
11871343 | true,_ ->
1188 if not fctx.is_static && fd.f_expr <> None then error (fst f.cff_name ^ ": An interface method cannot have a body") p;
1189 if fctx.is_inline && (has_class_flag c CInterface) then error (fst f.cff_name ^ ": You can't declare inline methods in interfaces") p;
1344 if not fctx.is_static && fd.f_expr <> None then unexpected_expression ctx.com fctx ("An interface method cannot have a body") p;
1345 if fctx.is_inline && (has_class_flag c CInterface) then invalid_modifier ctx.com fctx "inline" "method of interface" p;
11901346 | false,FKConstructor ->
1191 if fctx.is_static then error "A constructor must not be static" p;
1347 if fctx.is_static then invalid_modifier ctx.com fctx "static" "constructor" p;
11921348 begin match fd.f_type with
11931349 | None -> ()
11941350 | Some (CTPath ({ tpackage = []; tname = "Void" } as tp),p) ->
11951351 if ctx.is_display_file && DisplayPosition.display_position#enclosed_in p then
11961352 ignore(load_instance ~allow_display:true ctx (tp,p) false);
1197 | _ -> error "A class constructor can't have a return value" p;
1353 | _ -> typing_error "A class constructor can't have a return type" p;
11981354 end
11991355 | false,_ ->
12001356 ()
12011357 end;
1202 let parent = (if not fctx.is_static then get_parent c (fst f.cff_name) else None) in
1358 let parent = (if not fctx.is_static then get_parent c name else None) in
12031359 let dynamic = List.mem_assoc ADynamic f.cff_access || (match parent with Some { cf_kind = Method MethDynamic } -> true | _ -> false) in
1204 if fctx.is_abstract && dynamic then display_error ctx "Abstract methods may not be dynamic" p;
1205 if fctx.is_inline && dynamic then error (fst f.cff_name ^ ": 'inline' is not allowed on 'dynamic' functions") p;
1360 if dynamic then begin
1361 if fctx.is_abstract then invalid_modifier_combination fctx ctx.com fctx "abstract" "dynamic" p;
1362 if fctx.is_inline then invalid_modifier_combination fctx ctx.com fctx "dynamic" "inline" p;
1363 if fctx.is_abstract_member then invalid_modifier ctx.com fctx "dynamic" "method of abstract" p;
1364 end;
12061365 let is_override = Option.is_some fctx.override in
1207 if (is_override && fctx.is_static) then error (fst f.cff_name ^ ": 'override' is not allowed on 'static' functions") p;
1366 if (is_override && fctx.is_static) then invalid_modifier_combination fctx ctx.com fctx "override" "static" p;
12081367
12091368 ctx.type_params <- if fctx.is_static && not fctx.is_abstract_member then params else params @ ctx.type_params;
12101369 (* TODO is_lib: avoid forcing the return type to be typed *)
1211 let ret = if fctx.field_kind = FKConstructor then ctx.t.tvoid else FunctionArguments.type_opt ctx cctx.is_core_api fctx.is_abstract p fd.f_type in
1212 let abstract_this = match cctx.abstract with
1213 | Some a when fctx.is_abstract_member && fst f.cff_name <> "_new" (* TODO: this sucks *) && not fctx.is_macro ->
1214 Some a.a_this
1215 | _ ->
1216 None
1217 in
1218 let is_extern = fctx.is_extern || has_class_flag ctx.curclass CExtern in
1219 let type_arg opt t p = FunctionArguments.type_opt ctx cctx.is_core_api fctx.is_abstract p t in
1220 let args = new FunctionArguments.function_arguments ctx type_arg is_extern fctx.is_display_field abstract_this fd.f_args in
1370 let args,ret = setup_args_ret ctx cctx fctx (fst f.cff_name) fd p in
12211371 let t = TFun (args#for_type,ret) in
12221372 let cf = {
1223 (mk_field (fst f.cff_name) ~public:(is_public (ctx,cctx) f.cff_access parent) t f.cff_pos (pos f.cff_name)) with
1373 (mk_field name ~public:(is_public (ctx,cctx) f.cff_access parent) t f.cff_pos (pos f.cff_name)) with
12241374 cf_doc = f.cff_doc;
12251375 cf_meta = f.cff_meta;
12261376 cf_kind = Method (if fctx.is_macro then MethMacro else if fctx.is_inline then MethInline else if dynamic then MethDynamic else MethNormal);
12281378 } in
12291379 if fctx.is_final then add_class_field_flag cf CfFinal;
12301380 if fctx.is_extern then add_class_field_flag cf CfExtern;
1231 if fctx.is_abstract then add_class_field_flag cf CfAbstract;
1381 if fctx.is_abstract then begin
1382 if fctx.field_kind = FKConstructor then begin
1383 let p =
1384 try List.assoc AAbstract f.cff_access
1385 with Not_found -> p
1386 in
1387 invalid_modifier ctx.com fctx "abstract" "constructor" p
1388 end;
1389 add_class_field_flag cf CfAbstract;
1390 end;
12321391 if fctx.is_abstract_member then add_class_field_flag cf CfImpl;
12331392 if fctx.is_generic then add_class_field_flag cf CfGeneric;
1393 begin match fctx.default with
1394 | Some p ->
1395 begin match ctx.com.platform with
1396 | Java ->
1397 if not (has_class_flag ctx.curclass CExtern) || not (has_class_flag c CInterface) then invalid_modifier_only ctx.com fctx "default" "on extern interfaces" p;
1398 add_class_field_flag cf CfDefault;
1399 | _ ->
1400 invalid_modifier_only ctx.com fctx "default" "on the Java target" p
1401 end;
1402 | None ->
1403 ()
1404 end;
12341405 begin match fctx.overload with
12351406 | Some p ->
12361407 if ctx.com.config.pf_overload then
12371408 add_class_field_flag cf CfOverload
12381409 else if fctx.field_kind = FKConstructor then
1239 display_error ctx "Constructors cannot be overloaded on this target" p
1410 invalid_modifier ctx.com fctx "overload" "constructor" p
12401411 else begin
12411412 add_class_field_flag cf CfOverload;
12421413 if not (has_class_flag c CExtern || fctx.is_extern) then
1243 display_error ctx "Only extern functions may be overloaded on this target" p
1414 invalid_modifier_only ctx.com fctx "overload" "on extern functions" p
12441415 end
12451416 | None ->
12461417 ()
12731444 end else
12741445 delay ctx PTypeField (fun () -> args#verify_extern);
12751446 if fd.f_expr <> None then begin
1276 if fctx.is_abstract then display_error ctx "Abstract methods may not have an expression" p
1277 else if not (fctx.is_inline || fctx.is_macro) then ctx.com.warning "Extern non-inline function may not have an expression" p;
1447 if fctx.is_abstract then unexpected_expression ctx.com fctx "Abstract methods may not have an expression" p
1448 else if not (fctx.is_inline || fctx.is_macro) then warning ctx WExternWithExpr "Extern non-inline function may not have an expression" p;
12781449 end;
12791450 end;
12801451 cf
12831454 let name = fst f.cff_name in
12841455 (* TODO is_lib: lazify load_complex_type *)
12851456 let ret = (match t, eo with
1286 | None, None -> error (name ^ ": Property requires type-hint or initialization") p;
1457 | None, None -> typing_error "Property requires type-hint or initialization" p;
12871458 | None, _ -> mk_mono()
12881459 | Some t, _ -> lazy_display_type ctx (fun () -> load_type_hint ctx p (Some t))
12891460 ) in
12901461 let t_get,t_set = match cctx.abstract with
12911462 | Some a when fctx.is_abstract_member ->
1292 if Meta.has Meta.IsVar f.cff_meta then error (name ^ ": Abstract properties cannot be real variables") f.cff_pos;
1293 let ta = apply_params a.a_params (List.map snd a.a_params) a.a_this in
1463 if Meta.has Meta.IsVar f.cff_meta then typing_error "Abstract properties cannot be real variables" f.cff_pos;
1464 let ta = apply_params a.a_params (extract_param_types a.a_params) a.a_this in
12941465 tfun [ta] ret, tfun [ta;ret] ret
12951466 | _ -> tfun [] ret, TFun(["value",false,ret],ret)
12961467 in
13081479 } in
13091480 if fctx.is_abstract_member then add_class_field_flag cf CfImpl;
13101481 let check_method m t is_getter =
1311 if ctx.com.display.dms_error_policy = EPIgnore then
1312 ()
1313 else try
1482 try
13141483 let overloads = find_accessor m in
13151484 let rec get_overload overl = match overl with
13161485 | [tf] ->
13351504 try
13361505 (match f2.cf_kind with
13371506 | Method MethMacro ->
1338 display_error ctx (f2.cf_name ^ ": Macro methods cannot be used as property accessor") p;
1339 display_error ctx (compl_msg (f2.cf_name ^ ": Accessor method is here")) f2.cf_pos;
1507 display_error ctx.com (f2.cf_name ^ ": Macro methods cannot be used as property accessor") p;
1508 display_error ~depth:1 ctx.com (compl_msg (f2.cf_name ^ ": Accessor method is here")) f2.cf_pos;
13401509 | _ -> ());
1341 unify_raise ctx t2 t f2.cf_pos;
1510 unify_raise t2 t f2.cf_pos;
13421511 if (fctx.is_abstract_member && not (has_class_field_flag f2 CfImpl)) || (has_class_field_flag f2 CfImpl && not (fctx.is_abstract_member)) then
1343 display_error ctx "Mixing abstract implementation and static properties/accessors is not allowed" f2.cf_pos;
1344 with Error (Unify l,p) ->
1345 raise (Error (Stack (Custom ("In method " ^ m ^ " required by property " ^ name),Unify l),p))
1512 display_error ctx.com "Mixing abstract implementation and static properties/accessors is not allowed" f2.cf_pos;
1513 with Error (Unify l,p,depth) ->
1514 raise (Error (Stack [(Custom ("In method " ^ m ^ " required by property " ^ name),p);(Unify l,p)],p,depth+1))
13461515 )
13471516 with
13481517 | Not_found ->
13561525 let cf = generate_field () in
13571526 c.cl_fields <- PMap.add cf.cf_name cf c.cl_fields;
13581527 c.cl_ordered_fields <- cf :: c.cl_ordered_fields;
1359 end else if Diagnostics.is_diagnostics_run ctx.com f.cff_pos then begin
1528 end else if Diagnostics.error_in_diagnostics_run ctx.com f.cff_pos then begin
13601529 let cf_accessor = generate_field() in
13611530 remove_class_field_flag cf_accessor CfPublic;
13621531 if fctx.is_static then add_class_field_flag cf_accessor CfStatic;
13701539 display.module_diagnostics <- MissingFields diag :: display.module_diagnostics
13711540 end else if not (has_class_flag c CExtern) then begin
13721541 try
1373 let _, _, f2 = (if not fctx.is_static then let f = PMap.find m c.cl_statics in None, f.cf_type, f else class_field c (List.map snd c.cl_params) m) in
1374 display_error ctx (Printf.sprintf "Method %s is no valid accessor for %s because it is %sstatic" m (name) (if fctx.is_static then "not " else "")) f2.cf_pos
1542 let _, _, f2 = (if not fctx.is_static then let f = PMap.find m c.cl_statics in None, f.cf_type, f else class_field c (extract_param_types c.cl_params) m) in
1543 display_error ctx.com (Printf.sprintf "Method %s is no valid accessor for %s because it is %sstatic" m (name) (if fctx.is_static then "not " else "")) f2.cf_pos
13751544 with Not_found ->
1376 display_error ctx ("Method " ^ m ^ " required by property " ^ name ^ " is missing") p
1545 display_error ctx.com ("Method " ^ m ^ " required by property " ^ name ^ " is missing") p
13771546 end
13781547 in
13791548 let display_accessor m p =
13951564 if not cctx.is_lib then delay_check (fun() -> check_method get t_get true);
13961565 AccCall
13971566 | _,pget ->
1398 display_error ctx (name ^ ": Custom property accessor is no longer supported, please use `get`") pget;
1567 display_error ctx.com (name ^ ": Custom property accessor is no longer supported, please use `get`") pget;
13991568 AccCall
14001569 ) in
14011570 let set = (match set with
14141583 if not cctx.is_lib then delay_check (fun() -> check_method set t_set false);
14151584 AccCall
14161585 | _,pset ->
1417 display_error ctx (name ^ ": Custom property accessor is no longer supported, please use `set`") pset;
1586 display_error ctx.com (name ^ ": Custom property accessor is no longer supported, please use `set`") pset;
14181587 AccCall
14191588 ) in
1420 if (set = AccNever && get = AccNever) then error (name ^ ": Unsupported property combination") p;
1589 if (set = AccNever && get = AccNever) then typing_error (name ^ ": Unsupported property combination") p;
14211590 cf.cf_kind <- Var { v_read = get; v_write = set };
14221591 if fctx.is_extern then add_class_field_flag cf CfExtern;
14231592 if Meta.has Meta.Enum cf.cf_meta then add_class_field_flag cf CfEnum;
14381607 try snd (List.find (fun (a,p) -> a = AStatic) f.cff_access)
14391608 with Not_found -> f.cff_pos
14401609 in
1441 ctx.com.error "Static method cannot be final" p
1610 invalid_modifier_combination fctx ctx.com fctx "final" "static" p
14421611
14431612 let init_field (ctx,cctx,fctx) f =
14441613 let c = cctx.tclass in
14501619 match (fst acc, f.cff_kind) with
14511620 | APublic, _ | APrivate, _ | AStatic, _ | AFinal, _ | AExtern, _ -> ()
14521621 | ADynamic, FFun _ | AOverride, FFun _ | AMacro, FFun _ | AInline, FFun _ | AInline, FVar _ | AAbstract, FFun _ | AOverload, FFun _ -> ()
1453 | _, FVar _ -> display_error ctx ("Invalid accessor '" ^ Ast.s_placed_access acc ^ "' for variable " ^ name) (snd acc)
1454 | _, FProp _ -> display_error ctx ("Invalid accessor '" ^ Ast.s_placed_access acc ^ "' for property " ^ name) (snd acc)
1622 | _, FVar _ -> display_error ctx.com ("Invalid accessor '" ^ Ast.s_placed_access acc ^ "' for variable " ^ name) (snd acc)
1623 | _, FProp _ -> display_error ctx.com ("Invalid accessor '" ^ Ast.s_placed_access acc ^ "' for property " ^ name) (snd acc)
14551624 ) f.cff_access;
14561625 begin match fctx.override with
14571626 | Some _ ->
14611630 try List.assoc AOverride f.cff_access
14621631 with Not_found -> p
14631632 in
1464 error ("Invalid override on field '" ^ name ^ "': class has no super class") p
1633 invalid_modifier ctx.com fctx "override" "field of class that has no parent" p
14651634 | _ -> ()
14661635 );
14671636 | None -> ()
14801649 | FProp (get,set,t,eo) ->
14811650 create_property (ctx,cctx,fctx) c f (get,set,t,eo) p
14821651 in
1483 (if (fctx.is_static || fctx.is_macro && ctx.in_macro) then add_class_field_flag cf CfStatic);
1652 (if (fctx.is_static || fctx.is_macro && ctx.com.is_macro_context) then add_class_field_flag cf CfStatic);
14841653 if Meta.has Meta.InheritDoc cf.cf_meta then
14851654 delay ctx PTypeField (fun() -> InheritDoc.build_class_field_doc ctx (Some c) cf);
14861655 cf
14931662 Overloads.same_overload_args f.cf_type f2.cf_type f f2
14941663 ) fs
14951664 in
1496 display_error ctx ("Another overloaded field of same signature was already declared : " ^ f.cf_name) f.cf_pos;
1497 display_error ctx (compl_msg "The second field is declared here") f2.cf_pos;
1665 display_error ctx.com ("Another overloaded field of same signature was already declared : " ^ f.cf_name) f.cf_pos;
1666 display_error ~depth:1 ctx.com (compl_msg "The second field is declared here") f2.cf_pos;
14981667 false
14991668 with Not_found -> try
15001669 (* OVERLOADTODO: generalize this and respect whether or not we actually generate the functions *)
15061675 Overloads.same_overload_args ~get_vmtype f.cf_type f2.cf_type f f2
15071676 ) fs
15081677 in
1509 display_error ctx (
1678 display_error ctx.com (
15101679 "Another overloaded field of similar signature was already declared : " ^
15111680 f.cf_name ^
15121681 "\nThe signatures are different in Haxe, but not in the target language"
15131682 ) f.cf_pos;
1514 display_error ctx (compl_msg "The second field is declared here") f2.cf_pos;
1683 display_error ~depth:1 ctx.com (compl_msg "The second field is declared here") f2.cf_pos;
15151684 false
15161685 with Not_found ->
15171686 true
15281697 List.iter check_field c.cl_ordered_statics;
15291698 Option.may check_field c.cl_constructor
15301699
1700 let finalize_class ctx cctx =
1701 (* push delays in reverse order so they will be run in correct order *)
1702 List.iter (fun (ctx,r) ->
1703 init_class_done ctx;
1704 (match r with
1705 | None -> ()
1706 | Some r -> delay ctx PTypeField (fun() -> ignore(lazy_type r)))
1707 ) cctx.delayed_expr
1708
1709 let check_functional_interface ctx c =
1710 let is_normal_field cf =
1711 (* TODO: more? *)
1712 not (has_class_field_flag cf CfDefault)
1713 in
1714 let rec loop o l = match l with
1715 | cf :: l ->
1716 if is_normal_field cf then begin
1717 if o = None then
1718 loop (Some cf) l
1719 else
1720 None
1721 end else
1722 loop o l
1723 | [] ->
1724 o
1725 in
1726 match loop None c.cl_ordered_fields with
1727 | None ->
1728 ()
1729 | Some cf ->
1730 add_class_flag c CFunctionalInterface;
1731 ctx.g.functional_interface_lut#add c.cl_path cf
1732
15311733 let init_class ctx c p context_init herits fields =
1532 let ctx,cctx = create_class_context ctx c context_init p in
1734 let cctx = create_class_context c context_init p in
1735 let ctx = create_typer_context_for_class ctx cctx p in
15331736 if cctx.is_class_debug then print_endline ("Created class context: " ^ dump_class_context cctx);
15341737 let fields = patch_class ctx c fields in
15351738 let fields = build_fields (ctx,cctx) c fields in
15571760 | e :: l ->
15581761 let sc = match fst e with
15591762 | EConst (Ident s) -> s
1560 | EBinop ((OpEq|OpNotEq|OpGt|OpGte|OpLt|OpLte) as op,(EConst (Ident s),_),(EConst ((Int _ | Float _ | String _) as c),_)) -> s ^ s_binop op ^ s_constant c
1763 | EBinop ((OpEq|OpNotEq|OpGt|OpGte|OpLt|OpLte) as op,(EConst (Ident s),_),(EConst ((Int (_,_) | Float (_,_) | String _) as c),_)) -> s ^ s_binop op ^ s_constant c
15611764 | _ -> ""
15621765 in
15631766 if not (ParserEntry.is_true (ParserEntry.eval ctx.com.defines e)) then
15711774 in
15721775 let rec check_if_feature = function
15731776 | [] -> []
1574 | (Meta.IfFeature,el,_) :: _ -> List.map (fun (e,p) -> match e with EConst (String(s,_)) -> s | _ -> error "String expected" p) el
1777 | (Meta.IfFeature,el,_) :: _ -> List.map (fun (e,p) -> match e with EConst (String(s,_)) -> s | _ -> typing_error "String expected" p) el
15751778 | _ :: l -> check_if_feature l
15761779 in
15771780 let cl_if_feature = check_if_feature c.cl_meta in
15801783 List.iter (fun f ->
15811784 let p = f.cff_pos in
15821785 try
1583 let ctx,fctx = create_field_context (ctx,cctx) c f in
1786 let display_modifier = Typeload.check_field_access ctx f in
1787 let fctx = create_field_context cctx f ctx.is_display_file display_modifier in
1788 let ctx = create_typer_context_for_field ctx cctx fctx f in
15841789 if fctx.is_field_debug then print_endline ("Created field context: " ^ dump_field_context fctx);
15851790 let cf = init_field (ctx,cctx,fctx) f in
15861791 if fctx.field_kind = FKInit then begin
15871792 if !has_init then
1588 display_error ctx ("Duplicate class field declaration : " ^ (s_type_path c.cl_path) ^ "." ^ cf.cf_name) cf.cf_name_pos
1793 display_error ctx.com ("Duplicate class field declaration : " ^ (s_type_path c.cl_path) ^ "." ^ cf.cf_name) cf.cf_name_pos
15891794 else
15901795 has_init := true
15911796 end;
15921797 if fctx.is_field_debug then print_endline ("Created field: " ^ Printer.s_tclass_field "" cf);
15931798 if fctx.is_static && (has_class_flag c CInterface) && fctx.field_kind <> FKInit && not cctx.is_lib && not ((has_class_flag c CExtern)) then
1594 error "You can only declare static fields in extern interfaces" p;
1799 typing_error "You can only declare static fields in extern interfaces" p;
15951800 let set_feature s =
15961801 ctx.m.curmod.m_extra.m_if_feature <- (s,(c,cf,fctx.is_static)) :: ctx.m.curmod.m_extra.m_if_feature
15971802 in
16161821 if has_class_field_flag cf CfOverload && has_class_field_flag ctor CfOverload then
16171822 ctor.cf_overloads <- cf :: ctor.cf_overloads
16181823 else
1619 display_error ctx ("If using overloaded constructors, all constructors must be declared with 'overload'") (if has_class_field_flag cf CfOverload then ctor.cf_pos else cf.cf_pos)
1824 display_error ctx.com ("If using overloaded constructors, all constructors must be declared with 'overload'") (if has_class_field_flag cf CfOverload then ctor.cf_pos else cf.cf_pos)
16201825 | Some ctor ->
1621 display_error ctx "Duplicate constructor" p
1826 display_error ctx.com "Duplicate constructor" p
16221827 end
16231828 | FKInit ->
16241829 ()
16251830 | FKNormal ->
16261831 let dup = if fctx.is_static then PMap.exists cf.cf_name c.cl_fields || has_field cf.cf_name c.cl_super else PMap.exists cf.cf_name c.cl_statics in
1627 if not cctx.is_native && not (has_class_flag c CExtern) && dup then error ("Same field name can't be used for both static and instance : " ^ cf.cf_name) p;
1832 if not cctx.is_native && not (has_class_flag c CExtern) && dup then typing_error ("Same field name can't be used for both static and instance : " ^ cf.cf_name) p;
16281833 if fctx.override <> None then
16291834 add_class_field_flag cf CfOverride;
1630 let is_var cf = match cf.cf_kind with | Var _ -> true | _ -> false in
1835 let is_var cf = match cf.cf_kind with
1836 | Var {v_read = AccRequire _; v_write = AccRequire _} -> false
1837 | Var _ -> true
1838 | _ -> false
1839 in
16311840 if PMap.mem cf.cf_name (if fctx.is_static then c.cl_statics else c.cl_fields) then
16321841 if has_class_field_flag cf CfOverload && not (is_var cf) then
16331842 let mainf = PMap.find cf.cf_name (if fctx.is_static then c.cl_statics else c.cl_fields) in
1634 if is_var mainf then display_error ctx "Cannot declare a variable with same name as a method" mainf.cf_pos;
1635 (if not (has_class_field_flag mainf CfOverload) then display_error ctx ("Overloaded methods must have 'overload' accessor") mainf.cf_pos);
1843 if is_var mainf then display_error ctx.com "Cannot declare a variable with same name as a method" mainf.cf_pos;
1844 (if not (has_class_field_flag mainf CfOverload) then display_error ctx.com ("Overloaded methods must have 'overload' accessor") mainf.cf_pos);
16361845 mainf.cf_overloads <- cf :: cf.cf_overloads @ mainf.cf_overloads
16371846 else
16381847 let type_kind,path = match c.cl_kind with
16401849 | KModuleFields m -> "module",m.m_path
16411850 | _ -> "class",c.cl_path
16421851 in
1643 display_error ctx ("Duplicate " ^ type_kind ^ " field declaration : " ^ s_type_path path ^ "." ^ cf.cf_name) cf.cf_name_pos
1852 display_error ctx.com ("Duplicate " ^ type_kind ^ " field declaration : " ^ s_type_path path ^ "." ^ cf.cf_name) cf.cf_name_pos
16441853 else
16451854 if fctx.do_add then TClass.add_field c cf
16461855 end
1647 with Error (Custom str,p2) when p = p2 ->
1648 display_error ctx str p
1856 with Error (Custom str,p2,depth) when p = p2 ->
1857 display_error ~depth ctx.com str p
16491858 ) fields;
1650 (match cctx.abstract with
1651 | Some a ->
1652 a.a_to_field <- List.rev a.a_to_field;
1653 a.a_from_field <- List.rev a.a_from_field;
1654 a.a_ops <- List.rev a.a_ops;
1655 a.a_unops <- List.rev a.a_unops;
1656 a.a_array <- List.rev a.a_array;
1657 | None -> ());
1859 begin match cctx.abstract with
1860 | Some a ->
1861 a.a_to_field <- List.rev a.a_to_field;
1862 a.a_from_field <- List.rev a.a_from_field;
1863 a.a_ops <- List.rev a.a_ops;
1864 a.a_unops <- List.rev a.a_unops;
1865 a.a_array <- List.rev a.a_array;
1866 | None ->
1867 if (has_class_flag c CInterface) && ctx.com.platform = Java then check_functional_interface ctx c;
1868 end;
16581869 c.cl_ordered_statics <- List.rev c.cl_ordered_statics;
16591870 c.cl_ordered_fields <- List.rev c.cl_ordered_fields;
16601871 (* if ctx.is_display_file && not cctx.has_display_field && Display.is_display_position c.cl_pos && ctx.com.display.dms_kind = DMToplevel then begin
16921903 in
16931904 if has_struct_init then
16941905 if (has_class_flag c CInterface) then
1695 display_error ctx "@:structInit is not allowed on interfaces" struct_init_pos
1696 else if (has_class_flag c CAbstract) then
1697 display_error ctx "@:structInit is not allowed on abstract classes" struct_init_pos
1906 display_error ctx.com "@:structInit is not allowed on interfaces" struct_init_pos
16981907 else
16991908 ensure_struct_init_constructor ctx c fields p;
17001909 begin match cctx.uninitialized_final with
1701 | cf :: cfl when c.cl_constructor = None ->
1702 if Diagnostics.is_diagnostics_run ctx.com cf.cf_name_pos then begin
1910 | cf :: cfl when c.cl_constructor = None && not (has_class_flag c CAbstract) ->
1911 if Diagnostics.error_in_diagnostics_run ctx.com cf.cf_name_pos then begin
17031912 let diag = {
17041913 mf_pos = c.cl_name_pos;
17051914 mf_on = TClassDecl c;
17091918 let display = ctx.com.display_information in
17101919 display.module_diagnostics <- MissingFields diag :: display.module_diagnostics
17111920 end else begin
1712 display_error ctx "This class has uninitialized final vars, which requires a constructor" p;
1713 display_error ctx "Example of an uninitialized final var" cf.cf_name_pos;
1921 display_error ctx.com "This class has uninitialized final vars, which requires a constructor" p;
1922 display_error ctx.com "Example of an uninitialized final var" cf.cf_name_pos;
17141923 end
17151924 | _ ->
17161925 ()
17181927 if not has_struct_init then
17191928 (* add_constructor does not deal with overloads correctly *)
17201929 if not ctx.com.config.pf_overload then TypeloadFunction.add_constructor ctx c cctx.force_constructor p;
1721 (* push delays in reverse order so they will be run in correct order *)
1722 List.iter (fun (ctx,r) ->
1723 init_class_done ctx;
1724 (match r with
1725 | None -> ()
1726 | Some r -> delay ctx PTypeField (fun() -> ignore(lazy_type r)))
1727 ) cctx.delayed_expr
1930 finalize_class ctx cctx
4646
4747 let type_function_params ctx fd fname p =
4848 let params = ref [] in
49 params := Typeload.type_type_params ctx ([],fname) (fun() -> !params) p fd.f_params;
49 params := Typeload.type_type_params ctx TPHMethod ([],fname) (fun() -> !params) p fd.f_params;
5050 !params
5151
5252 let type_function ctx (args : function_arguments) ret fmode e do_display p =
5858 args#bring_into_context;
5959 let e = match e with
6060 | None ->
61 if ctx.com.display.dms_error_policy = EPIgnore then
61 if ignore_error ctx.com then
6262 (* when we don't care because we're in display mode, just act like
6363 the function has an empty block body. this is fine even if function
6464 defines a return type, because returns aren't checked in this mode
6666 EBlock [],p
6767 else
6868 if fmode = FunMember && has_class_flag ctx.curclass CAbstract then
69 error "Function body or abstract modifier required" p
69 typing_error "Function body or abstract modifier required" p
7070 else
71 error "Function body required" p
71 typing_error "Function body required" p
7272 | Some e -> e
7373 in
7474 let is_position_debug = Meta.has (Meta.Custom ":debug.position") ctx.curfield.cf_meta in
103103 can _not_ use type_iseq to avoid the Void check above because that
104104 would turn Dynamic returns to Void returns. *)
105105 | TMono t when not (has_return e) -> ignore(link t ret ctx.t.tvoid)
106 | _ when ctx.com.display.dms_error_policy = EPIgnore -> ()
107106 | _ -> (try TypeloadCheck.return_flow ctx e with Exit -> ())
108107 end;
109108 let rec loop e =
136135 let e_super_call = mk (TCall(e_super,[])) ctx.t.tvoid e.epos in
137136 concat e_super_call e
138137 else begin
139 display_error ctx "Missing super constructor call" p;
138 display_error ctx.com "Missing super constructor call" p;
140139 e
141140 end
142141 with
182181
183182 let add_constructor ctx c force_constructor p =
184183 if c.cl_constructor <> None then () else
185 let constructor = try Some (Type.get_constructor_class c (List.map snd c.cl_params)) with Not_found -> None in
184 let constructor = try Some (Type.get_constructor_class c (extract_param_types c.cl_params)) with Not_found -> None in
186185 match constructor with
187186 | Some(cfsup,csup,cparams) when not (has_class_flag c CExtern) ->
188 let cf = {
189 cfsup with
190 cf_pos = p;
191 cf_meta = List.filter (fun (m,_,_) -> m = Meta.CompilerGenerated) cfsup.cf_meta;
192 cf_doc = None;
193 cf_expr = None;
194 } in
187 let cf = mk_field "new" cfsup.cf_type p null_pos in
188 cf.cf_kind <- cfsup.cf_kind;
189 cf.cf_params <- cfsup.cf_params;
190 cf.cf_meta <- List.filter (fun (m,_,_) -> m = Meta.CompilerGenerated) cfsup.cf_meta;
195191 let r = exc_protect ctx (fun r ->
196192 let t = mk_mono() in
197193 r := lazy_processing (fun() -> t);
2929 open Typeload
3030 open Error
3131
32 let get_policy ctx mpath =
32 let get_policy g mpath =
3333 let sl1 = full_dot_path2 mpath mpath in
34 List.fold_left (fun acc (sl2,policy,recursive) -> if match_path recursive sl1 sl2 then policy @ acc else acc) [] ctx.g.module_check_policies
35
36 let make_module ctx mpath file loadp =
37 let m = {
38 m_id = alloc_mid();
39 m_path = mpath;
40 m_types = [];
41 m_statics = None;
42 m_extra = module_extra (Path.get_full_path file) (Define.get_signature ctx.com.defines) (file_time file) (if ctx.in_macro then MMacro else MCode) (get_policy ctx mpath);
43 } in
44 m
45
46 let add_module ctx m p =
47 List.iter (TypeloadCheck.check_module_types ctx m p) m.m_types;
48 Hashtbl.add ctx.g.modules m.m_path m
49
50 module StrictMeta = struct
51 let get_native_repr md pos =
52 let path, meta = match md with
53 | TClassDecl cl -> cl.cl_path, cl.cl_meta
54 | TEnumDecl e -> e.e_path, e.e_meta
55 | TTypeDecl t -> t.t_path, t.t_meta
56 | TAbstractDecl a -> a.a_path, a.a_meta
57 in
58 let rec loop acc = function
59 | (Meta.JavaCanonical,[EConst(String(pack,_)),_; EConst(String(name,_)),_],_) :: _ ->
60 ExtString.String.nsplit pack ".", name
61 | (Meta.Native,[EConst(String(name,_)),_],_) :: meta ->
62 loop (Ast.parse_path name) meta
63 | _ :: meta ->
64 loop acc meta
34 List.fold_left (fun acc (sl2,policy,recursive) -> if match_path recursive sl1 sl2 then policy @ acc else acc) [] g.module_check_policies
35
36 let field_of_static_definition d p =
37 {
38 cff_name = d.d_name;
39 cff_doc = d.d_doc;
40 cff_pos = p;
41 cff_meta = d.d_meta;
42 cff_access = (AStatic,null_pos) :: d.d_flags;
43 cff_kind = d.d_data;
44 }
45
46 module ModuleLevel = struct
47 let make_module ctx mpath file loadp =
48 let m = {
49 m_id = alloc_mid();
50 m_path = mpath;
51 m_types = [];
52 m_statics = None;
53 m_extra = module_extra (Path.get_full_path file) (Define.get_signature ctx.com.defines) (file_time file) (if ctx.com.is_macro_context then MMacro else MCode) (get_policy ctx.g mpath);
54 } in
55 m
56
57 let add_module ctx m p =
58 List.iter (TypeloadCheck.check_module_types ctx m p) m.m_types;
59 ctx.com.module_lut#add m.m_path m
60
61 (*
62 Build module structure : should be atomic - no type loading is possible
63 *)
64 let create_module_types ctx m tdecls loadp =
65 let com = ctx.com in
66 let decls = ref [] in
67 let statics = ref [] in
68 let check_name name meta also_statics p =
69 DeprecationCheck.check_is com name meta p;
70 let error prev_pos =
71 display_error ctx.com ("Name " ^ name ^ " is already defined in this module") p;
72 typing_error ~depth:1 (compl_msg "Previous declaration here") prev_pos;
73 in
74 List.iter (fun (t2,(_,p2)) ->
75 if snd (t_path t2) = name then error (t_infos t2).mt_name_pos
76 ) !decls;
77 if also_statics then
78 List.iter (fun (d,_) ->
79 if fst d.d_name = name then error (snd d.d_name)
80 ) !statics
81 in
82 let make_path name priv meta p =
83 check_name name meta true p;
84 if priv then (fst m.m_path @ ["_" ^ snd m.m_path], name) else (fst m.m_path, name)
85 in
86 let has_declaration = ref false in
87 let rec make_decl acc decl =
88 let p = snd decl in
89 let check_type_name type_name meta =
90 let module_name = snd m.m_path in
91 if type_name <> module_name && not (Meta.has Meta.Native meta) then Typecore.check_uppercase_identifier_name ctx type_name "type" p;
92 in
93 let acc = (match fst decl with
94 | EImport _ | EUsing _ ->
95 if !has_declaration then typing_error "import and using may not appear after a declaration" p;
96 acc
97 | EStatic d ->
98 check_name (fst d.d_name) d.d_meta false (snd d.d_name);
99 has_declaration := true;
100 statics := (d,p) :: !statics;
101 acc;
102 | EClass d ->
103 let name = fst d.d_name in
104 has_declaration := true;
105 let priv = List.mem HPrivate d.d_flags in
106 let path = make_path name priv d.d_meta (snd d.d_name) in
107 let c = mk_class m path p (pos d.d_name) in
108 (* we shouldn't load any other type until we propertly set cl_build *)
109 c.cl_build <- (fun() -> typing_error (s_type_path c.cl_path ^ " is not ready to be accessed, separate your type declarations in several files") p);
110 c.cl_module <- m;
111 c.cl_private <- priv;
112 c.cl_doc <- d.d_doc;
113 c.cl_meta <- d.d_meta;
114 if List.mem HAbstract d.d_flags then add_class_flag c CAbstract;
115 List.iter (function
116 | HExtern -> add_class_flag c CExtern
117 | HInterface -> add_class_flag c CInterface
118 | HFinal -> add_class_flag c CFinal
119 | _ -> ()
120 ) d.d_flags;
121 if not (has_class_flag c CExtern) then check_type_name name d.d_meta;
122 if has_class_flag c CAbstract then begin
123 if has_class_flag c CInterface then display_error ctx.com "An interface may not be abstract" c.cl_name_pos;
124 if has_class_flag c CFinal then display_error ctx.com "An abstract class may not be final" c.cl_name_pos;
125 end;
126 decls := (TClassDecl c, decl) :: !decls;
127 acc
128 | EEnum d ->
129 let name = fst d.d_name in
130 has_declaration := true;
131 let priv = List.mem EPrivate d.d_flags in
132 let path = make_path name priv d.d_meta p in
133 if Meta.has (Meta.Custom ":fakeEnum") d.d_meta then typing_error "@:fakeEnum enums is no longer supported in Haxe 4, use extern enum abstract instead" p;
134 let e = {
135 e_path = path;
136 e_module = m;
137 e_pos = p;
138 e_name_pos = (pos d.d_name);
139 e_doc = d.d_doc;
140 e_meta = d.d_meta;
141 e_params = [];
142 e_using = [];
143 e_restore = (fun () -> ());
144 e_private = priv;
145 e_extern = List.mem EExtern d.d_flags;
146 e_constrs = PMap.empty;
147 e_names = [];
148 e_type = enum_module_type m path p;
149 } in
150 if not e.e_extern then check_type_name name d.d_meta;
151 decls := (TEnumDecl e, decl) :: !decls;
152 acc
153 | ETypedef d ->
154 let name = fst d.d_name in
155 check_type_name name d.d_meta;
156 has_declaration := true;
157 let priv = List.mem EPrivate d.d_flags in
158 let path = make_path name priv d.d_meta p in
159 let t = {(mk_typedef m path p (pos d.d_name) (mk_mono())) with
160 t_doc = d.d_doc;
161 t_private = priv;
162 t_meta = d.d_meta;
163 } in
164 (* failsafe in case the typedef is not initialized (see #3933) *)
165 delay ctx PBuildModule (fun () ->
166 match t.t_type with
167 | TMono r -> (match r.tm_type with None -> Monomorph.bind r com.basic.tvoid | _ -> ())
168 | _ -> ()
169 );
170 decls := (TTypeDecl t, decl) :: !decls;
171 acc
172 | EAbstract d ->
173 let name = fst d.d_name in
174 check_type_name name d.d_meta;
175 let priv = List.mem AbPrivate d.d_flags in
176 let path = make_path name priv d.d_meta p in
177 let a = {
178 a_path = path;
179 a_private = priv;
180 a_module = m;
181 a_pos = p;
182 a_name_pos = pos d.d_name;
183 a_doc = d.d_doc;
184 a_params = [];
185 a_using = [];
186 a_restore = (fun () -> ());
187 a_meta = d.d_meta;
188 a_from = [];
189 a_to = [];
190 a_from_field = [];
191 a_to_field = [];
192 a_ops = [];
193 a_unops = [];
194 a_impl = None;
195 a_array = [];
196 a_this = mk_mono();
197 a_read = None;
198 a_write = None;
199 a_call = None;
200 a_enum = List.mem AbEnum d.d_flags || Meta.has Meta.Enum d.d_meta;
201 } in
202 if a.a_enum && not (Meta.has Meta.Enum a.a_meta) then a.a_meta <- (Meta.Enum,[],null_pos) :: a.a_meta;
203 decls := (TAbstractDecl a, decl) :: !decls;
204 match d.d_data with
205 | [] when Meta.has Meta.CoreType a.a_meta ->
206 a.a_this <- t_dynamic;
207 acc
208 | fields ->
209 let a_t =
210 let params = List.map (fun t -> TPType (CTPath (mk_type_path ([],fst t.tp_name)),null_pos)) d.d_params in
211 CTPath (mk_type_path ~params ([],fst d.d_name)),null_pos
212 in
213 let rec loop = function
214 | [] -> a_t
215 | AbOver t :: _ -> t
216 | _ :: l -> loop l
217 in
218 let this_t = loop d.d_flags in
219 let fields = List.map (TypeloadFields.transform_abstract_field com this_t a_t a) fields in
220 let meta = ref [] in
221 if has_meta Meta.Dce a.a_meta then meta := (Meta.Dce,[],null_pos) :: !meta;
222 let acc = make_decl acc (EClass { d_name = (fst d.d_name) ^ "_Impl_",snd d.d_name; d_flags = [HPrivate]; d_data = fields; d_doc = None; d_params = []; d_meta = !meta },p) in
223 (match !decls with
224 | (TClassDecl c,_) :: _ ->
225 List.iter (fun m -> match m with
226 | ((Meta.Using | Meta.Build | Meta.CoreApi | Meta.Allow | Meta.Access | Meta.Enum | Meta.Dce | Meta.Native | Meta.HlNative | Meta.JsRequire | Meta.PythonImport | Meta.Expose | Meta.Deprecated | Meta.PhpGlobal | Meta.PublicFields),_,_) ->
227 c.cl_meta <- m :: c.cl_meta;
228 | _ ->
229 ()
230 ) a.a_meta;
231 a.a_impl <- Some c;
232 c.cl_kind <- KAbstractImpl a;
233 add_class_flag c CFinal;
234 | _ -> die "" __LOC__);
235 acc
236 ) in
237 decl :: acc
238 in
239 let tdecls = List.fold_left make_decl [] tdecls in
240 let tdecls =
241 match !statics with
65242 | [] ->
66 acc
67 in
68 let pack, name = loop path meta in
69 match pack with
70 | [] ->
71 (EConst(Ident(name)), pos)
72 | hd :: tl ->
73 let rec loop pack expr = match pack with
74 | hd :: tl ->
75 loop tl (EField(expr,hd),pos)
76 | [] ->
77 (EField(expr,name),pos)
78 in
79 loop tl (EConst(Ident(hd)),pos)
80
81 let rec process_meta_argument ?(toplevel=true) ctx expr = match expr.eexpr with
82 | TField(e,f) ->
83 (EField(process_meta_argument ~toplevel:false ctx e,field_name f),expr.epos)
84 | TConst(TInt i) ->
85 (EConst(Int (Int32.to_string i)), expr.epos)
86 | TConst(TFloat f) ->
87 (EConst(Float f), expr.epos)
88 | TConst(TString s) ->
89 (EConst(String(s,SDoubleQuotes)), expr.epos)
90 | TConst TNull ->
91 (EConst(Ident "null"), expr.epos)
92 | TConst(TBool b) ->
93 (EConst(Ident (string_of_bool b)), expr.epos)
94 | TCast(e,_) | TMeta(_,e) | TParenthesis(e) ->
95 process_meta_argument ~toplevel ctx e
96 | TTypeExpr md when toplevel ->
97 let p = expr.epos in
98 if ctx.com.platform = Cs then
99 (ECall( (EConst(Ident "typeof"), p), [get_native_repr md expr.epos] ), p)
100 else
101 (EField(get_native_repr md expr.epos, "class"), p)
102 | TTypeExpr md ->
103 get_native_repr md expr.epos
104 | _ ->
105 display_error ctx "This expression is too complex to be a strict metadata argument" expr.epos;
106 (EConst(Ident "null"), expr.epos)
107
108 let handle_fields ctx fields_to_check with_type_expr =
109 List.map (fun ((name,_,_),expr) ->
110 let pos = snd expr in
111 let field = (EField(with_type_expr,name), pos) in
112 let fieldexpr = (EConst(Ident name),pos) in
113 let left_side = match ctx.com.platform with
114 | Cs -> field
115 | Java -> (ECall(field,[]),pos)
116 | _ -> die "" __LOC__
117 in
118
119 let left = type_expr ctx left_side NoValue in
120 let right = type_expr ctx expr (WithType.with_type left.etype) in
121 unify ctx left.etype right.etype (snd expr);
122 (EBinop(Ast.OpAssign,fieldexpr,process_meta_argument ctx right), pos)
123 ) fields_to_check
124
125 let make_meta ctx texpr extra =
126 match texpr.eexpr with
127 | TNew(c,_,el) ->
128 ECall(get_native_repr (TClassDecl c) texpr.epos, (List.map (process_meta_argument ctx) el) @ extra), texpr.epos
129 | TTypeExpr(md) ->
130 ECall(get_native_repr md texpr.epos, extra), texpr.epos
131 | _ ->
132 display_error ctx "Unexpected expression" texpr.epos; die "" __LOC__
133
134 let get_strict_meta ctx meta params pos =
135 let pf = ctx.com.platform in
136 let changed_expr, fields_to_check, ctype = match params with
137 | [ECall(ef, el),p] ->
138 (* check last argument *)
139 let el, fields = match List.rev el with
140 | (EObjectDecl(decl),_) :: el ->
141 List.rev el, decl
142 | _ ->
143 el, []
144 in
145 let tpath = field_to_type_path ctx ef in
146 if pf = Cs then
147 (ENew((tpath,snd ef), el), p), fields, CTPath tpath
148 else
149 ef, fields, CTPath tpath
150 | [EConst(Ident i),p as expr] ->
151 let tpath = { tpackage=[]; tname=i; tparams=[]; tsub=None } in
152 if pf = Cs then
153 (ENew((tpath,p), []), p), [], CTPath tpath
154 else
155 expr, [], CTPath tpath
156 | [ (EField(_),p as field) ] ->
157 let tpath = field_to_type_path ctx field in
158 if pf = Cs then
159 (ENew((tpath,p), []), p), [], CTPath tpath
160 else
161 field, [], CTPath tpath
162 | _ ->
163 display_error ctx "A @:strict metadata must contain exactly one parameter. Please check the documentation for more information" pos;
164 raise Exit
165 in
166 let texpr = type_expr ctx changed_expr NoValue in
167 let with_type_expr = (ECheckType( (EConst (Ident "null"), pos), (ctype,null_pos) ), pos) in
168 let extra = handle_fields ctx fields_to_check with_type_expr in
169 meta, [make_meta ctx texpr extra], pos
170
171 let check_strict_meta ctx metas =
172 let pf = ctx.com.platform in
173 match pf with
174 | Cs | Java ->
175 let ret = ref [] in
176 List.iter (function
177 | Meta.AssemblyStrict,params,pos -> (try
178 ret := get_strict_meta ctx Meta.AssemblyMeta params pos :: !ret
179 with | Exit -> ())
180 | Meta.Strict,params,pos -> (try
181 ret := get_strict_meta ctx Meta.Meta params pos :: !ret
182 with | Exit -> ())
183 | _ -> ()
184 ) metas;
185 !ret
186 | _ -> []
187 end
188
189 (*
190 Build module structure : should be atomic - no type loading is possible
191 *)
192 let module_pass_1 ctx m tdecls loadp =
193 let com = ctx.com in
194 let decls = ref [] in
195 let statics = ref [] in
196 let check_name name meta also_statics p =
197 DeprecationCheck.check_is com name meta p;
198 let error prev_pos =
199 display_error ctx ("Name " ^ name ^ " is already defined in this module") p;
200 error (compl_msg "Previous declaration here") prev_pos;
201 in
202 List.iter (fun (t2,(_,p2)) ->
203 if snd (t_path t2) = name then error (t_infos t2).mt_name_pos
204 ) !decls;
205 if also_statics then
206 List.iter (fun (d,_) ->
207 if fst d.d_name = name then error (snd d.d_name)
208 ) !statics
209 in
210 let make_path name priv meta p =
211 check_name name meta true p;
212 if priv then (fst m.m_path @ ["_" ^ snd m.m_path], name) else (fst m.m_path, name)
213 in
214 let has_declaration = ref false in
215 let rec make_decl acc decl =
216 let p = snd decl in
217 let check_type_name type_name meta =
218 let module_name = snd m.m_path in
219 if type_name <> module_name && not (Meta.has Meta.Native meta) then Typecore.check_uppercase_identifier_name ctx type_name "type" p;
220 in
221 let acc = (match fst decl with
222 | EImport _ | EUsing _ ->
223 if !has_declaration then error "import and using may not appear after a declaration" p;
224 acc
225 | EStatic d ->
226 check_name (fst d.d_name) d.d_meta false (snd d.d_name);
227 has_declaration := true;
228 statics := (d,p) :: !statics;
229 acc;
230 | EClass d ->
231 let name = fst d.d_name in
232 has_declaration := true;
233 let priv = List.mem HPrivate d.d_flags in
234 let path = make_path name priv d.d_meta (snd d.d_name) in
235 let c = mk_class m path p (pos d.d_name) in
236 (* we shouldn't load any other type until we propertly set cl_build *)
237 c.cl_build <- (fun() -> error (s_type_path c.cl_path ^ " is not ready to be accessed, separate your type declarations in several files") p);
238 c.cl_module <- m;
239 c.cl_private <- priv;
240 c.cl_doc <- d.d_doc;
241 c.cl_meta <- d.d_meta;
242 if List.mem HAbstract d.d_flags then add_class_flag c CAbstract;
243 List.iter (function
244 | HExtern -> add_class_flag c CExtern
245 | HInterface -> add_class_flag c CInterface
246 | HFinal -> add_class_flag c CFinal
247 | _ -> ()
248 ) d.d_flags;
249 if not (has_class_flag c CExtern) then check_type_name name d.d_meta;
250 if has_class_flag c CAbstract then begin
251 if has_class_flag c CInterface then display_error ctx "An interface may not be abstract" c.cl_name_pos;
252 if has_class_flag c CFinal then display_error ctx "An abstract class may not be final" c.cl_name_pos;
253 end;
254 decls := (TClassDecl c, decl) :: !decls;
255 acc
256 | EEnum d ->
257 let name = fst d.d_name in
258 has_declaration := true;
259 let priv = List.mem EPrivate d.d_flags in
260 let path = make_path name priv d.d_meta p in
261 if Meta.has (Meta.Custom ":fakeEnum") d.d_meta then error "@:fakeEnum enums is no longer supported in Haxe 4, use extern enum abstract instead" p;
262 let e = {
263 e_path = path;
264 e_module = m;
265 e_pos = p;
266 e_name_pos = (pos d.d_name);
267 e_doc = d.d_doc;
268 e_meta = d.d_meta;
269 e_params = [];
270 e_using = [];
271 e_private = priv;
272 e_extern = List.mem EExtern d.d_flags;
273 e_constrs = PMap.empty;
274 e_names = [];
275 e_type = enum_module_type m path p;
276 } in
277 if not e.e_extern then check_type_name name d.d_meta;
278 decls := (TEnumDecl e, decl) :: !decls;
279 acc
280 | ETypedef d ->
281 let name = fst d.d_name in
282 check_type_name name d.d_meta;
283 has_declaration := true;
284 let priv = List.mem EPrivate d.d_flags in
285 let path = make_path name priv d.d_meta p in
286 let t = {
287 t_path = path;
288 t_module = m;
289 t_pos = p;
290 t_name_pos = pos d.d_name;
291 t_doc = d.d_doc;
292 t_private = priv;
293 t_params = [];
294 t_using = [];
295 t_type = mk_mono();
296 t_meta = d.d_meta;
297 } in
298 (* failsafe in case the typedef is not initialized (see #3933) *)
299 delay ctx PBuildModule (fun () ->
300 match t.t_type with
301 | TMono r -> (match r.tm_type with None -> Monomorph.bind r com.basic.tvoid | _ -> ())
302 | _ -> ()
303 );
304 decls := (TTypeDecl t, decl) :: !decls;
305 acc
306 | EAbstract d ->
307 let name = fst d.d_name in
308 check_type_name name d.d_meta;
309 let priv = List.mem AbPrivate d.d_flags in
310 let path = make_path name priv d.d_meta p in
311 let a = {
312 a_path = path;
313 a_private = priv;
314 a_module = m;
315 a_pos = p;
316 a_name_pos = pos d.d_name;
317 a_doc = d.d_doc;
318 a_params = [];
319 a_using = [];
320 a_meta = d.d_meta;
321 a_from = [];
322 a_to = [];
323 a_from_field = [];
324 a_to_field = [];
325 a_ops = [];
326 a_unops = [];
327 a_impl = None;
328 a_array = [];
329 a_this = mk_mono();
330 a_read = None;
331 a_write = None;
332 a_enum = List.mem AbEnum d.d_flags || Meta.has Meta.Enum d.d_meta;
333 } in
334 if a.a_enum && not (Meta.has Meta.Enum a.a_meta) then a.a_meta <- (Meta.Enum,[],null_pos) :: a.a_meta;
335 decls := (TAbstractDecl a, decl) :: !decls;
336 match d.d_data with
337 | [] when Meta.has Meta.CoreType a.a_meta ->
338 a.a_this <- t_dynamic;
339 acc
340 | fields ->
341 let a_t =
342 let params = List.map (fun t -> TPType (CTPath (mk_type_path ([],fst t.tp_name)),null_pos)) d.d_params in
343 CTPath (mk_type_path ~params ([],fst d.d_name)),null_pos
344 in
345 let rec loop = function
346 | [] -> a_t
347 | AbOver t :: _ -> t
348 | _ :: l -> loop l
349 in
350 let this_t = loop d.d_flags in
351 let fields = List.map (TypeloadFields.transform_abstract_field com this_t a_t a) fields in
352 let meta = ref [] in
353 if has_meta Meta.Dce a.a_meta then meta := (Meta.Dce,[],null_pos) :: !meta;
354 let acc = make_decl acc (EClass { d_name = (fst d.d_name) ^ "_Impl_",snd d.d_name; d_flags = [HPrivate]; d_data = fields; d_doc = None; d_params = []; d_meta = !meta },p) in
243 tdecls
244 | statics ->
245 let first_pos = ref null_pos in
246 let fields = List.map (fun (d,p) ->
247 first_pos := p;
248 field_of_static_definition d p;
249 ) statics in
250 let p = let p = !first_pos in { p with pmax = p.pmin } in
251 let c = EClass {
252 d_name = (snd m.m_path) ^ "_Fields_", null_pos;
253 d_flags = [HPrivate];
254 d_data = List.rev fields;
255 d_doc = None;
256 d_params = [];
257 d_meta = []
258 } in
259 let tdecls = make_decl tdecls (c,p) in
355260 (match !decls with
356261 | (TClassDecl c,_) :: _ ->
357 List.iter (fun m -> match m with
358 | ((Meta.Using | Meta.Build | Meta.CoreApi | Meta.Allow | Meta.Access | Meta.Enum | Meta.Dce | Meta.Native | Meta.HlNative | Meta.JsRequire | Meta.PythonImport | Meta.Expose | Meta.Deprecated | Meta.PhpGlobal),_,_) ->
359 c.cl_meta <- m :: c.cl_meta;
360 | _ ->
361 ()
362 ) a.a_meta;
363 a.a_impl <- Some c;
364 c.cl_kind <- KAbstractImpl a;
262 assert (m.m_statics = None);
263 m.m_statics <- Some c;
264 c.cl_kind <- KModuleFields m;
365265 add_class_flag c CFinal;
366 | _ -> die "" __LOC__);
367 acc
266 | _ -> assert false);
267 tdecls
268
269 in
270 let decls = List.rev !decls in
271 decls, List.rev tdecls
272
273 let handle_import_hx ctx m decls p =
274 let com = ctx.com in
275 let path_split = match List.rev (Path.get_path_parts (Path.UniqueKey.lazy_path m.m_extra.m_file)) with
276 | [] -> []
277 | _ :: l -> l
278 in
279 let join l = String.concat Path.path_sep (List.rev ("import.hx" :: l)) in
280 let rec loop path pack = match path,pack with
281 | _,[] -> [join path]
282 | (p :: path),(_ :: pack) -> (join (p :: path)) :: (loop path pack)
283 | _ -> []
284 in
285 let candidates = loop path_split (fst m.m_path) in
286 let make_import_module path r =
287 com.parser_cache#add path r;
288 (* We use the file path as module name to make it unique. This may or may not be a good idea... *)
289 let m_import = make_module ctx ([],path) path p in
290 m_import.m_extra.m_kind <- MImport;
291 add_module ctx m_import p;
292 m_import
293 in
294 List.fold_left (fun acc path ->
295 let decls = try
296 let r = com.parser_cache#find path in
297 let mimport = com.module_lut#find ([],path) in
298 if mimport.m_extra.m_kind <> MFake then add_dependency m mimport;
299 r
300 with Not_found ->
301 if Sys.file_exists path then begin
302 let _,r = match !TypeloadParse.parse_hook com path p with
303 | ParseSuccess(data,_,_) -> data
304 | ParseError(_,(msg,p),_) -> Parser.error msg p
305 in
306 List.iter (fun (d,p) -> match d with EImport _ | EUsing _ -> () | _ -> typing_error "Only import and using is allowed in import.hx files" p) r;
307 add_dependency m (make_import_module path r);
308 r
309 end else begin
310 let r = [] in
311 (* Add empty decls so we don't check the file system all the time. *)
312 (make_import_module path r).m_extra.m_kind <- MFake;
313 r
314 end
315 in
316 decls @ acc
317 ) decls candidates
318
319 let init_type_params ctx decls =
320 (* here is an additional PASS 1 phase, which define the type parameters for all module types.
321 Constraints are handled lazily (no other type is loaded) because they might be recursive anyway *)
322 List.iter (fun d ->
323 match d with
324 | (TClassDecl c, (EClass d, p)) ->
325 c.cl_params <- type_type_params ctx TPHType c.cl_path (fun() -> c.cl_params) p d.d_params;
326 if Meta.has Meta.Generic c.cl_meta && c.cl_params <> [] then c.cl_kind <- KGeneric;
327 if Meta.has Meta.GenericBuild c.cl_meta then begin
328 if ctx.com.is_macro_context then typing_error "@:genericBuild cannot be used in macros" c.cl_pos;
329 c.cl_kind <- KGenericBuild d.d_data;
330 end;
331 if c.cl_path = (["haxe";"macro"],"MacroType") then c.cl_kind <- KMacroType;
332 | (TEnumDecl e, (EEnum d, p)) ->
333 e.e_params <- type_type_params ctx TPHType e.e_path (fun() -> e.e_params) p d.d_params;
334 | (TTypeDecl t, (ETypedef d, p)) ->
335 t.t_params <- type_type_params ctx TPHType t.t_path (fun() -> t.t_params) p d.d_params;
336 | (TAbstractDecl a, (EAbstract d, p)) ->
337 a.a_params <- type_type_params ctx TPHType a.a_path (fun() -> a.a_params) p d.d_params;
338 | _ ->
339 die "" __LOC__
340 ) decls
341 end
342
343 module TypeLevel = struct
344 let load_enum_field ctx e et is_flat index c =
345 let p = c.ec_pos in
346 let params = ref [] in
347 params := type_type_params ctx TPHEnumConstructor ([],fst c.ec_name) (fun() -> !params) c.ec_pos c.ec_params;
348 let params = !params in
349 let ctx = { ctx with type_params = params @ ctx.type_params } in
350 let rt = (match c.ec_type with
351 | None -> et
352 | Some (t,pt) ->
353 let t = load_complex_type ctx true (t,pt) in
354 (match follow t with
355 | TEnum (te,_) when te == e ->
356 ()
357 | _ ->
358 typing_error "Explicit enum type must be of the same enum type" pt);
359 t
368360 ) in
369 decl :: acc
370 in
371 let tdecls = List.fold_left make_decl [] tdecls in
372 let tdecls =
373 match !statics with
374 | [] ->
375 tdecls
376 | statics ->
377 let first_pos = ref null_pos in
378 let fields = List.map (fun (d,p) ->
379 first_pos := p;
380 {
381 cff_name = d.d_name;
382 cff_doc = d.d_doc;
383 cff_pos = p;
384 cff_meta = d.d_meta;
385 cff_access = (AStatic,null_pos) :: d.d_flags;
386 cff_kind = d.d_data;
387 }
388 ) statics in
389 let p = let p = !first_pos in { p with pmax = p.pmin } in
390 let c = EClass {
391 d_name = (snd m.m_path) ^ "_Fields_", null_pos;
392 d_flags = [HPrivate];
393 d_data = List.rev fields;
394 d_doc = None;
395 d_params = [];
396 d_meta = []
397 } in
398 let tdecls = make_decl tdecls (c,p) in
399 (match !decls with
400 | (TClassDecl c,_) :: _ ->
401 assert (m.m_statics = None);
402 m.m_statics <- Some c;
403 c.cl_kind <- KModuleFields m;
404 add_class_flag c CFinal;
405 | _ -> assert false);
406 tdecls
407
408 in
409 let decls = List.rev !decls in
410 decls, List.rev tdecls
411
412 let load_enum_field ctx e et is_flat index c =
413 let p = c.ec_pos in
414 let params = ref [] in
415 params := type_type_params ~enum_constructor:true ctx ([],fst c.ec_name) (fun() -> !params) c.ec_pos c.ec_params;
416 let params = !params in
417 let ctx = { ctx with type_params = params @ ctx.type_params } in
418 let rt = (match c.ec_type with
419 | None -> et
420 | Some (t,pt) ->
421 let t = load_complex_type ctx true (t,pt) in
422 (match follow t with
423 | TEnum (te,_) when te == e ->
424 ()
425 | _ ->
426 error "Explicit enum type must be of the same enum type" pt);
427 t
428 ) in
429 let t = (match c.ec_args with
430 | [] -> rt
431 | l ->
432 is_flat := false;
433 let pnames = ref PMap.empty in
434 TFun (List.map (fun (s,opt,(t,tp)) ->
435 (match t with CTPath({tpackage=[];tname="Void"}) -> error "Arguments of type Void are not allowed in enum constructors" tp | _ -> ());
436 if PMap.mem s (!pnames) then error ("Duplicate argument `" ^ s ^ "` in enum constructor " ^ fst c.ec_name) p;
437 pnames := PMap.add s () (!pnames);
438 s, opt, load_type_hint ~opt ctx p (Some (t,tp))
439 ) l, rt)
440 ) in
441 let f = {
442 ef_name = fst c.ec_name;
443 ef_type = t;
444 ef_pos = p;
445 ef_name_pos = snd c.ec_name;
446 ef_doc = c.ec_doc;
447 ef_index = !index;
448 ef_params = params;
449 ef_meta = c.ec_meta;
450 } in
451 DeprecationCheck.check_is ctx.com f.ef_name f.ef_meta f.ef_name_pos;
452 let cf = {
453 (mk_field f.ef_name f.ef_type p f.ef_name_pos) with
454 cf_kind = (match follow f.ef_type with
455 | TFun _ -> Method MethNormal
456 | _ -> Var { v_read = AccNormal; v_write = AccNo }
457 );
458 cf_doc = f.ef_doc;
459 cf_params = f.ef_params;
460 } in
461 if ctx.is_display_file && DisplayPosition.display_position#enclosed_in f.ef_name_pos then
462 DisplayEmitter.display_enum_field ctx e f p;
463 f,cf
464
465 (*
466 In this pass, we can access load and access other modules types, but we cannot follow them or access their structure
467 since they have not been setup. We also build a context_init list that will be evaluated the first time we evaluate
468 an expression into the context
469 *)
470 let init_module_type ctx context_init (decl,p) =
471 let get_type name =
472 try List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types with Not_found -> die "" __LOC__
473 in
474 let commit_import path mode p =
475 ctx.m.module_imports <- (path,mode) :: ctx.m.module_imports;
476 if Filename.basename p.pfile <> "import.hx" then ImportHandling.add_import_position ctx p path;
477 in
478 let check_path_display path p =
479 if DisplayPosition.display_position#is_in_file (ctx.com.file_keys#get p.pfile) then DisplayPath.handle_path_display ctx path p
480 in
481 let init_import path mode =
482 check_path_display path p;
483 let rec loop acc = function
484 | x :: l when is_lower_ident (fst x) -> loop (x::acc) l
485 | rest -> List.rev acc, rest
486 in
487 let pack, rest = loop [] path in
488 (match rest with
489 | [] ->
490 (match mode with
491 | IAll ->
492 ctx.m.wildcard_packages <- (List.map fst pack,p) :: ctx.m.wildcard_packages
493 | _ ->
494 (match List.rev path with
495 (* p spans `import |` (to the display position), so we take the pmax here *)
496 | [] -> DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue true) CRImport (DisplayTypes.make_subject None {p with pmin = p.pmax})
497 | (_,p) :: _ -> error "Module name must start with an uppercase letter" p))
498 | (tname,p2) :: rest ->
499 let p1 = (match pack with [] -> p2 | (_,p1) :: _ -> p1) in
500 let p_type = punion p1 p2 in
501 let md = ctx.g.do_load_module ctx (List.map fst pack,tname) p_type in
502 let types = md.m_types in
503 let no_private (t,_) = not (t_infos t).mt_private in
504 let error_private p = error "Importing private declarations from a module is not allowed" p in
505 let chk_private t p = if ctx.m.curmod != (t_infos t).mt_module && (t_infos t).mt_private then error_private p in
506 let has_name name t = snd (t_infos t).mt_path = name in
507 let get_type tname =
508 let t = (try List.find (has_name tname) types with Not_found -> error (StringError.string_error tname (List.map (fun mt -> snd (t_infos mt).mt_path) types) ("Module " ^ s_type_path md.m_path ^ " does not define type " ^ tname)) p_type) in
509 chk_private t p_type;
510 t
511 in
512 let rebind t name p =
513 if not (name.[0] >= 'A' && name.[0] <= 'Z') then
514 error "Type aliases must start with an uppercase letter" p;
515 let _, _, f = ctx.g.do_build_instance ctx t p_type in
516 (* create a temp private typedef, does not register it in module *)
517 let mt = TTypeDecl {
518 t_path = (fst md.m_path @ ["_" ^ snd md.m_path],name);
519 t_module = ctx.m.curmod;
520 t_pos = p;
521 t_name_pos = p;
522 t_private = true;
523 t_doc = None;
524 t_meta = [];
525 t_params = (t_infos t).mt_params;
526 t_using = [];
527 t_type = f (List.map snd (t_infos t).mt_params);
528 } in
529 if ctx.is_display_file && DisplayPosition.display_position#enclosed_in p then
530 DisplayEmitter.display_module_type ctx mt p;
531 mt
532 in
533 let add_static_init t name s =
534 let name = (match name with None -> s | Some (n,_) -> n) in
535 match resolve_typedef t with
536 | TClassDecl c | TAbstractDecl {a_impl = Some c} ->
537 ignore(c.cl_build());
538 ignore(PMap.find s c.cl_statics);
539 ctx.m.module_globals <- PMap.add name (TClassDecl c,s,p) ctx.m.module_globals
540 | TEnumDecl e ->
541 ignore(PMap.find s e.e_constrs);
542 ctx.m.module_globals <- PMap.add name (TEnumDecl e,s,p) ctx.m.module_globals
543 | _ ->
544 raise Not_found
545 in
546 (match mode with
547 | INormal | IAsName _ ->
548 let name = (match mode with IAsName n -> Some n | _ -> None) in
549 (match rest with
550 | [] ->
551 (match name with
552 | None ->
553 ctx.m.module_types <- List.filter no_private (List.map (fun t -> t,p) types) @ ctx.m.module_types;
554 Option.may (fun c ->
555 context_init#add (fun () ->
556 ignore(c.cl_build());
557 List.iter (fun cf ->
558 if has_class_field_flag cf CfPublic then
559 ctx.m.module_globals <- PMap.add cf.cf_name (TClassDecl c,cf.cf_name,p) ctx.m.module_globals
560 ) c.cl_ordered_statics
561 );
562 ) md.m_statics
563 | Some(newname,pname) ->
564 ctx.m.module_types <- (rebind (get_type tname) newname pname,p) :: ctx.m.module_types);
565 | [tsub,p2] ->
566 let pu = punion p1 p2 in
567 (try
568 let tsub = List.find (has_name tsub) types in
569 chk_private tsub pu;
570 ctx.m.module_types <- ((match name with None -> tsub | Some(n,pname) -> rebind tsub n pname),p) :: ctx.m.module_types
571 with Not_found ->
572 (* this might be a static property, wait later to check *)
573 let find_main_type_static () =
574 let tmain = get_type tname in
575 try
576 add_static_init tmain name tsub
577 with Not_found ->
578 (* TODO: mention module-level declarations in the error message? *)
579 display_error ctx (s_type_path (t_infos tmain).mt_path ^ " has no field or subtype " ^ tsub) p
580 in
581 context_init#add (fun() ->
582 match md.m_statics with
583 | Some c ->
584 (try
585 ignore(c.cl_build());
586 let rec loop fl =
587 match fl with
588 | [] -> raise Not_found
589 | cf :: rest ->
590 if cf.cf_name = tsub then
591 if not (has_class_field_flag cf CfPublic) then
592 error_private p
593 else
594 let imported_name = match name with None -> tsub | Some (n,pname) -> n in
595 ctx.m.module_globals <- PMap.add imported_name (TClassDecl c,tsub,p) ctx.m.module_globals;
596 else
597 loop rest
598 in
599 loop c.cl_ordered_statics
600 with Not_found ->
601 find_main_type_static ())
602 | None ->
603 find_main_type_static ()
604 )
605 )
606 | (tsub,p2) :: (fname,p3) :: rest ->
607 (match rest with
608 | [] -> ()
609 | (n,p) :: _ -> error ("Unexpected " ^ n) p);
610 let tsub = get_type tsub in
611 context_init#add (fun() ->
612 try
613 add_static_init tsub name fname
614 with Not_found ->
615 display_error ctx (s_type_path (t_infos tsub).mt_path ^ " has no field " ^ fname) (punion p p3)
616 );
617 )
618 | IAll ->
619 let t = (match rest with
620 | [] -> get_type tname
621 | [tsub,_] -> get_type tsub
622 | _ :: (n,p) :: _ -> error ("Unexpected " ^ n) p
623 ) in
624 context_init#add (fun() ->
625 match resolve_typedef t with
626 | TClassDecl c
627 | TAbstractDecl {a_impl = Some c} ->
628 ignore(c.cl_build());
629 PMap.iter (fun _ cf -> if not (has_meta Meta.NoImportGlobal cf.cf_meta) then ctx.m.module_globals <- PMap.add cf.cf_name (TClassDecl c,cf.cf_name,p) ctx.m.module_globals) c.cl_statics
630 | TEnumDecl e ->
631 PMap.iter (fun _ c -> if not (has_meta Meta.NoImportGlobal c.ef_meta) then ctx.m.module_globals <- PMap.add c.ef_name (TEnumDecl e,c.ef_name,p) ctx.m.module_globals) e.e_constrs
632 | _ ->
633 error "No statics to import from this type" p
634 )
635 ))
636 in
637 match decl with
638 | EImport (path,mode) ->
639 begin try
640 init_import path mode;
641 commit_import path mode p;
642 with Error(err,p) ->
643 display_error ctx (Error.error_msg err) p
644 end
645 | EUsing path ->
646 check_path_display path p;
647 let types,filter_classes = handle_using ctx path p in
648 (* do the import first *)
649 ctx.m.module_types <- (List.map (fun t -> t,p) types) @ ctx.m.module_types;
650 context_init#add (fun() -> ctx.m.module_using <- filter_classes types @ ctx.m.module_using)
651 | EClass d ->
652 let c = (match get_type (fst d.d_name) with TClassDecl c -> c | _ -> die "" __LOC__) in
361 let t = (match c.ec_args with
362 | [] -> rt
363 | l ->
364 is_flat := false;
365 let pnames = ref PMap.empty in
366 TFun (List.map (fun (s,opt,(t,tp)) ->
367 (match t with CTPath({tpackage=[];tname="Void"}) -> typing_error "Arguments of type Void are not allowed in enum constructors" tp | _ -> ());
368 if PMap.mem s (!pnames) then typing_error ("Duplicate argument `" ^ s ^ "` in enum constructor " ^ fst c.ec_name) p;
369 pnames := PMap.add s () (!pnames);
370 s, opt, load_type_hint ~opt ctx p (Some (t,tp))
371 ) l, rt)
372 ) in
373 let f = {
374 ef_name = fst c.ec_name;
375 ef_type = t;
376 ef_pos = p;
377 ef_name_pos = snd c.ec_name;
378 ef_doc = c.ec_doc;
379 ef_index = !index;
380 ef_params = params;
381 ef_meta = c.ec_meta;
382 } in
383 DeprecationCheck.check_is ctx.com f.ef_name f.ef_meta f.ef_name_pos;
384 let cf = {
385 (mk_field f.ef_name f.ef_type p f.ef_name_pos) with
386 cf_kind = (match follow f.ef_type with
387 | TFun _ -> Method MethNormal
388 | _ -> Var { v_read = AccNormal; v_write = AccNo }
389 );
390 cf_doc = f.ef_doc;
391 cf_params = f.ef_params;
392 } in
393 if ctx.is_display_file && DisplayPosition.display_position#enclosed_in f.ef_name_pos then
394 DisplayEmitter.display_enum_field ctx e f p;
395 f,cf
396
397 let init_class ctx context_init c d p =
653398 if ctx.is_display_file && DisplayPosition.display_position#enclosed_in (pos d.d_name) then
654399 DisplayEmitter.display_module_type ctx (match c.cl_kind with KAbstractImpl a -> TAbstractDecl a | _ -> TClassDecl c) (pos d.d_name);
655400 TypeloadCheck.check_global_metadata ctx c.cl_meta (fun m -> c.cl_meta <- m :: c.cl_meta) c.cl_module.m_path c.cl_path None;
657402 List.iter (fun (m,_,p) ->
658403 if m = Meta.Final then begin
659404 add_class_flag c CFinal;
660 (* if p <> null_pos && not (Define.is_haxe3_compat ctx.com.defines) then
661 ctx.com.warning "`@:final class` is deprecated in favor of `final class`" p; *)
662405 end
663406 ) d.d_meta;
664407 let prev_build_count = ref (!build_count - 1) in
665408 let build() =
409 c.cl_build <- (fun()-> Building [c]);
666410 let fl = TypeloadCheck.Inheritance.set_heritance ctx c herits p in
667411 let rec build() =
668412 c.cl_build <- (fun()-> Building [c]);
671415 TypeloadFields.init_class ctx c p context_init d.d_flags d.d_data;
672416 c.cl_build <- (fun()-> Built);
673417 incr build_count;
674 List.iter (fun (_,t) -> ignore(follow t)) c.cl_params;
418 List.iter (fun tp -> ignore(follow tp.ttp_type)) c.cl_params;
675419 Built;
676420 with TypeloadCheck.Build_canceled state ->
677421 c.cl_build <- make_pass ctx build;
681425 (match state with
682426 | Built -> die "" __LOC__
683427 | Building cl ->
684 if !build_count = !prev_build_count then error ("Loop in class building prevent compiler termination (" ^ String.concat "," (List.map (fun c -> s_type_path c.cl_path) cl) ^ ")") c.cl_pos;
428 if !build_count = !prev_build_count then typing_error ("Loop in class building prevent compiler termination (" ^ String.concat "," (List.map (fun c -> s_type_path c.cl_path) cl) ^ ")") c.cl_pos;
685429 prev_build_count := !build_count;
686430 rebuild();
687431 Building (c :: cl)
716460 match c.cl_constructor with
717461 | Some f -> run_field f
718462 | _ -> ()
719 );
720 | EEnum d ->
721 let e = (match get_type (fst d.d_name) with TEnumDecl e -> e | _ -> die "" __LOC__) in
463 )
464
465 let init_enum ctx context_init e d p =
722466 if ctx.is_display_file && DisplayPosition.display_position#enclosed_in (pos d.d_name) then
723467 DisplayEmitter.display_module_type ctx (TEnumDecl e) (pos d.d_name);
724468 let ctx = { ctx with type_params = e.e_params } in
727471 (match h with
728472 | None -> ()
729473 | Some (h,hcl) ->
730 Hashtbl.iter (fun _ _ -> error "Field type patch not supported for enums" e.e_pos) h;
474 Hashtbl.iter (fun _ _ -> typing_error "Field type patch not supported for enums" e.e_pos) h;
731475 e.e_meta <- e.e_meta @ hcl.tp_meta);
732476 let constructs = ref d.d_data in
733477 let get_constructs() =
751495 let args, params, t = (match f.cff_kind with
752496 | FVar (t,None) -> [], [], t
753497 | FFun { f_params = pl; f_type = t; f_expr = (None|Some (EBlock [],_)); f_args = al } ->
754 let al = List.map (fun ((n,_),o,_,t,_) -> match t with None -> error "Missing function parameter type" f.cff_pos | Some t -> n,o,t) al in
498 let al = List.map (fun ((n,_),o,_,t,_) -> match t with None -> typing_error "Missing function parameter type" f.cff_pos | Some t -> n,o,t) al in
755499 al, pl, t
756500 | _ ->
757 error "Invalid enum constructor in @:build result" p
501 typing_error "Invalid enum constructor in @:build result" p
758502 ) in
759503 {
760504 ec_name = f.cff_name;
766510 ec_type = t;
767511 }
768512 ) fields
769 | _ -> error "Enum build macro must return a single variable with anonymous object fields" p
513 | _ -> typing_error "Enum build macro must return a single variable with anonymous object fields" p
770514 );
771 let et = TEnum (e,List.map snd e.e_params) in
515 let et = TEnum (e,extract_param_types e.e_params) in
772516 let names = ref [] in
773517 let index = ref 0 in
774518 let is_flat = ref true in
775519 let fields = ref PMap.empty in
776520 List.iter (fun c ->
777 if PMap.mem (fst c.ec_name) e.e_constrs then error ("Duplicate constructor " ^ fst c.ec_name) (pos c.ec_name);
521 if PMap.mem (fst c.ec_name) e.e_constrs then typing_error ("Duplicate constructor " ^ fst c.ec_name) (pos c.ec_name);
778522 let f,cf = load_enum_field ctx e et is_flat index c in
779523 e.e_constrs <- PMap.add f.ef_name f e.e_constrs;
780524 fields := PMap.add cf.cf_name cf !fields;
798542 let metas = StrictMeta.check_strict_meta ctx ef.ef_meta in
799543 if metas <> [] then ef.ef_meta <- metas @ ef.ef_meta
800544 ) e.e_constrs
801 );
802 | ETypedef d ->
803 let t = (match get_type (fst d.d_name) with TTypeDecl t -> t | _ -> die "" __LOC__) in
545 )
546
547 let init_typedef ctx context_init t d p =
804548 if ctx.is_display_file && DisplayPosition.display_position#enclosed_in (pos d.d_name) then
805549 DisplayEmitter.display_module_type ctx (TTypeDecl t) (pos d.d_name);
806550 TypeloadCheck.check_global_metadata ctx t.t_meta (fun m -> t.t_meta <- m :: t.t_meta) t.t_module.m_path t.t_path None;
810554 | CTExtend _ -> tt
811555 | CTPath { tpackage = ["haxe";"macro"]; tname = "MacroType" } ->
812556 (* we need to follow MacroType immediately since it might define other module types that we will load afterwards *)
813 if t.t_type == follow tt then error "Recursive typedef is not allowed" p;
557 if t.t_type == follow tt then typing_error "Recursive typedef is not allowed" p;
814558 tt
815559 | _ ->
816560 if (Meta.has Meta.Eager d.d_meta) then
817561 follow tt
818562 else begin
819563 let rec check_rec tt =
820 if tt == t.t_type then error "Recursive typedef is not allowed" p;
564 if tt == t.t_type then typing_error "Recursive typedef is not allowed" p;
821565 match tt with
822566 | TMono r ->
823567 (match r.tm_type with
826570 | TLazy f ->
827571 check_rec (lazy_type f);
828572 | TType (td,tl) ->
829 if td == t then error "Recursive typedef is not allowed" p;
830 check_rec (apply_params td.t_params tl td.t_type)
573 if td == t then typing_error "Recursive typedef is not allowed" p;
574 check_rec (apply_typedef td tl)
831575 | _ ->
832576 ()
833577 in
850594 delay ctx PTypeField (fun () ->
851595 let metas = StrictMeta.check_strict_meta ctx t.t_meta in
852596 if metas <> [] then t.t_meta <- metas @ t.t_meta;
853 );
854 | EAbstract d ->
855 let a = (match get_type (fst d.d_name) with TAbstractDecl a -> a | _ -> die "" __LOC__) in
597 )
598
599 let init_abstract ctx context_init a d p =
856600 if ctx.is_display_file && DisplayPosition.display_position#enclosed_in (pos d.d_name) then
857601 DisplayEmitter.display_module_type ctx (TAbstractDecl a) (pos d.d_name);
858602 TypeloadCheck.check_global_metadata ctx a.a_meta (fun m -> a.a_meta <- m :: a.a_meta) a.a_module.m_path a.a_path None;
865609 if !is_type then begin
866610 let r = exc_protect ctx (fun r ->
867611 r := lazy_processing (fun() -> t);
868 (try (if from then Type.unify t a.a_this else Type.unify a.a_this t) with Unify_error _ -> error "You can only declare from/to with compatible types" pos);
612 (try (if from then Type.unify t a.a_this else Type.unify a.a_this t) with Unify_error _ -> typing_error "You can only declare from/to with compatible types" pos);
869613 t
870614 ) "constraint" in
871615 TLazy r
872616 end else
873 error "Missing underlying type declaration or @:coreType declaration" p;
617 typing_error "Missing underlying type declaration or @:coreType declaration" p;
874618 end else begin
875619 if Meta.has Meta.Callable a.a_meta then
876 error "@:coreType abstracts cannot be @:callable" p;
620 typing_error "@:coreType abstracts cannot be @:callable" p;
877621 t
878622 end in
879623 t
882626 | AbFrom t -> a.a_from <- (load_type t true) :: a.a_from
883627 | AbTo t -> a.a_to <- (load_type t false) :: a.a_to
884628 | AbOver t ->
885 if a.a_impl = None then error "Abstracts with underlying type must have an implementation" a.a_pos;
886 if Meta.has Meta.CoreType a.a_meta then error "@:coreType abstracts cannot have an underlying type" p;
629 if a.a_impl = None then typing_error "Abstracts with underlying type must have an implementation" a.a_pos;
630 if Meta.has Meta.CoreType a.a_meta then typing_error "@:coreType abstracts cannot have an underlying type" p;
887631 let at = load_complex_type ctx true t in
888632 delay ctx PForce (fun () ->
889633 let rec loop stack t =
890634 match follow t with
891635 | TAbstract(a,_) when not (Meta.has Meta.CoreType a.a_meta) ->
892636 if List.memq a stack then
893 error "Abstract underlying type cannot be recursive" a.a_pos
637 typing_error "Abstract underlying type cannot be recursive" a.a_pos
894638 else
895639 loop (a :: stack) a.a_this
896640 | _ -> ()
907651 a.a_to <- List.rev a.a_to;
908652 if not !is_type then begin
909653 if Meta.has Meta.CoreType a.a_meta then
910 a.a_this <- TAbstract(a,List.map snd a.a_params)
654 a.a_this <- TAbstract(a,extract_param_types a.a_params)
911655 else
912 error "Abstract is missing underlying type declaration" a.a_pos
656 typing_error "Abstract is missing underlying type declaration" a.a_pos
913657 end;
914658 if Meta.has Meta.InheritDoc a.a_meta then
915 delay ctx PConnectField (fun() -> InheritDoc.build_abstract_doc ctx a);
916 | EStatic _ ->
917 (* nothing to do here as module fields are collected into a special EClass *)
918 ()
919
920 let module_pass_2 ctx m decls tdecls p =
921 (* here is an additional PASS 1 phase, which define the type parameters for all module types.
922 Constraints are handled lazily (no other type is loaded) because they might be recursive anyway *)
923 List.iter (fun d ->
924 match d with
925 | (TClassDecl c, (EClass d, p)) ->
926 c.cl_params <- type_type_params ctx c.cl_path (fun() -> c.cl_params) p d.d_params;
927 if Meta.has Meta.Generic c.cl_meta && c.cl_params <> [] then c.cl_kind <- KGeneric;
928 if Meta.has Meta.GenericBuild c.cl_meta then begin
929 if ctx.in_macro then error "@:genericBuild cannot be used in macros" c.cl_pos;
930 c.cl_kind <- KGenericBuild d.d_data;
931 end;
932 if c.cl_path = (["haxe";"macro"],"MacroType") then c.cl_kind <- KMacroType;
933 | (TEnumDecl e, (EEnum d, p)) ->
934 e.e_params <- type_type_params ctx e.e_path (fun() -> e.e_params) p d.d_params;
935 | (TTypeDecl t, (ETypedef d, p)) ->
936 t.t_params <- type_type_params ctx t.t_path (fun() -> t.t_params) p d.d_params;
937 | (TAbstractDecl a, (EAbstract d, p)) ->
938 a.a_params <- type_type_params ctx a.a_path (fun() -> a.a_params) p d.d_params;
939 | _ ->
940 die "" __LOC__
941 ) decls;
942 (* setup module types *)
943 let context_init = new TypeloadFields.context_init in
944 List.iter (init_module_type ctx context_init) tdecls;
945 (* Make sure that we actually init the context at some point (issue #9012) *)
946 delay ctx PConnectField (fun () -> context_init#run)
947
948 (*
949 Creates a module context for [m] and types [tdecls] using it.
950 *)
951 let type_types_into_module ctx m tdecls p =
952 let decls, tdecls = module_pass_1 ctx m tdecls p in
953 let types = List.map fst decls in
954 List.iter (TypeloadCheck.check_module_types ctx m p) types;
955 m.m_types <- m.m_types @ types;
956 (* define the per-module context for the next pass *)
957 let ctx = {
659 delay ctx PConnectField (fun() -> InheritDoc.build_abstract_doc ctx a)
660
661 (*
662 In this pass, we can access load and access other modules types, but we cannot follow them or access their structure
663 since they have not been setup. We also build a context_init list that will be evaluated the first time we evaluate
664 an expression into the context
665 *)
666 let init_module_type ctx context_init (decl,p) =
667 let get_type name =
668 try List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types with Not_found -> die "" __LOC__
669 in
670 let check_path_display path p =
671 if DisplayPosition.display_position#is_in_file (ctx.com.file_keys#get p.pfile) then DisplayPath.handle_path_display ctx path p
672 in
673 match decl with
674 | EImport (path,mode) ->
675 begin try
676 check_path_display path p;
677 ImportHandling.init_import ctx context_init path mode p;
678 ImportHandling.commit_import ctx path mode p;
679 with Error(err,p,depth) ->
680 located_display_error ~depth ctx.com (Error.error_msg p err)
681 end
682 | EUsing path ->
683 check_path_display path p;
684 ImportHandling.init_using ctx context_init path p
685 | EClass d ->
686 let c = (match get_type (fst d.d_name) with TClassDecl c -> c | _ -> die "" __LOC__) in
687 init_class ctx context_init c d p
688 | EEnum d ->
689 let e = (match get_type (fst d.d_name) with TEnumDecl e -> e | _ -> die "" __LOC__) in
690 init_enum ctx context_init e d p
691 | ETypedef d ->
692 let t = (match get_type (fst d.d_name) with TTypeDecl t -> t | _ -> die "" __LOC__) in
693 init_typedef ctx context_init t d p
694 | EAbstract d ->
695 let a = (match get_type (fst d.d_name) with TAbstractDecl a -> a | _ -> die "" __LOC__) in
696 init_abstract ctx context_init a d p
697 | EStatic _ ->
698 (* nothing to do here as module fields are collected into a special EClass *)
699 ()
700 end
701
702 let make_curmod ctx m = {
703 curmod = m;
704 module_imports = List.map (fun t -> t,null_pos) ctx.g.std.m_types;
705 module_using = [];
706 module_globals = PMap.empty;
707 wildcard_packages = [];
708 import_statements = [];
709 }
710
711 let create_typer_context_for_module ctx m = {
958712 com = ctx.com;
959713 g = ctx.g;
960 t = ctx.t;
961 m = {
962 curmod = m;
963 module_types = List.map (fun t -> t,null_pos) ctx.g.std.m_types;
964 module_using = [];
965 module_globals = PMap.empty;
966 wildcard_packages = [];
967 module_imports = [];
968 };
714 t = ctx.com.basic;
715 m = make_curmod ctx m;
969716 is_display_file = (ctx.com.display.dms_kind <> DMNone && DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key m.m_extra.m_file));
970717 bypass_accessor = 0;
971718 meta = [];
972 this_stack = [];
973719 with_type_stack = [];
974720 call_argument_stack = [];
975721 pass = PBuildModule;
976722 get_build_infos = (fun() -> None);
977 on_error = (fun ctx msg p -> ctx.com.error msg p);
978 macro_depth = ctx.macro_depth;
723 macro_depth = 0;
979724 curclass = null_class;
725 allow_inline = true;
726 allow_transform = true;
980727 curfield = null_field;
981 tthis = ctx.tthis;
982 ret = ctx.ret;
728 tthis = mk_mono();
729 ret = mk_mono();
983730 locals = PMap.empty;
984731 type_params = [];
985732 curfun = FunStatic;
986733 untyped = false;
987 in_macro = ctx.in_macro;
988734 in_display = false;
989735 in_function = false;
990736 in_loop = false;
997743 };
998744 vthis = None;
999745 memory_marker = Typecore.memory_marker;
1000 } in
746 }
747
748 (*
749 Creates a module context for [m] and types [tdecls] using it.
750 *)
751 let type_types_into_module ctx m tdecls p =
752 let ctx = create_typer_context_for_module ctx m in
753 let decls,tdecls = ModuleLevel.create_module_types ctx m tdecls p in
754 let types = List.map fst decls in
755 List.iter (TypeloadCheck.check_module_types ctx m p) types;
756 m.m_types <- m.m_types @ types;
757 (* define the per-module context for the next pass *)
1001758 if ctx.g.std != null_module then begin
1002759 add_dependency m ctx.g.std;
1003760 (* this will ensure both String and (indirectly) Array which are basic types which might be referenced *)
1004761 ignore(load_core_type ctx "String");
1005762 end;
1006 module_pass_2 ctx m decls tdecls p;
763 ModuleLevel.init_type_params ctx decls;
764 (* setup module types *)
765 let context_init = new TypeloadFields.context_init in
766 List.iter (TypeLevel.init_module_type ctx context_init) tdecls;
767 (* Make sure that we actually init the context at some point (issue #9012) *)
768 delay ctx PConnectField (fun () -> context_init#run);
1007769 ctx
1008
1009 let handle_import_hx ctx m decls p =
1010 let path_split = match List.rev (Path.get_path_parts (Path.UniqueKey.lazy_path m.m_extra.m_file)) with
1011 | [] -> []
1012 | _ :: l -> l
1013 in
1014 let join l = String.concat Path.path_sep (List.rev ("import.hx" :: l)) in
1015 let rec loop path pack = match path,pack with
1016 | _,[] -> [join path]
1017 | (p :: path),(_ :: pack) -> (join (p :: path)) :: (loop path pack)
1018 | _ -> []
1019 in
1020 let candidates = loop path_split (fst m.m_path) in
1021 let make_import_module path r =
1022 Hashtbl.replace ctx.com.parser_cache path r;
1023 (* We use the file path as module name to make it unique. This may or may not be a good idea... *)
1024 let m_import = make_module ctx ([],path) path p in
1025 m_import.m_extra.m_kind <- MImport;
1026 add_module ctx m_import p;
1027 m_import
1028 in
1029 List.fold_left (fun acc path ->
1030 let decls = try
1031 let r = Hashtbl.find ctx.com.parser_cache path in
1032 let mimport = Hashtbl.find ctx.g.modules ([],path) in
1033 if mimport.m_extra.m_kind <> MFake then add_dependency m mimport;
1034 r
1035 with Not_found ->
1036 if Sys.file_exists path then begin
1037 let _,r = match !TypeloadParse.parse_hook ctx.com path p with
1038 | ParseSuccess(data,_,_) -> data
1039 | ParseError(_,(msg,p),_) -> Parser.error msg p
1040 in
1041 List.iter (fun (d,p) -> match d with EImport _ | EUsing _ -> () | _ -> error "Only import and using is allowed in import.hx files" p) r;
1042 add_dependency m (make_import_module path r);
1043 r
1044 end else begin
1045 let r = [] in
1046 (* Add empty decls so we don't check the file system all the time. *)
1047 (make_import_module path r).m_extra.m_kind <- MFake;
1048 r
1049 end
1050 in
1051 decls @ acc
1052 ) decls candidates
1053770
1054771 (*
1055772 Creates a new module and types [tdecls] into it.
1056773 *)
1057774 let type_module ctx mpath file ?(dont_check_path=false) ?(is_extern=false) tdecls p =
1058 let m = make_module ctx mpath file p in
1059 Hashtbl.add ctx.g.modules m.m_path m;
1060 let tdecls = handle_import_hx ctx m tdecls p in
775 let m = ModuleLevel.make_module ctx mpath file p in
776 ctx.com.module_lut#add m.m_path m;
777 let tdecls = ModuleLevel.handle_import_hx ctx m tdecls p in
1061778 let ctx = type_types_into_module ctx m tdecls p in
1062779 if is_extern then m.m_extra.m_kind <- MExtern else if not dont_check_path then Typecore.check_module_path ctx m.m_path p;
1063 begin if ctx.is_display_file then match ctx.com.display.dms_kind with
1064 | DMResolve s ->
1065 DisplayPath.resolve_position_by_path ctx (mk_type_path ([],s)) p
1066 | _ ->
1067 ()
1068 end;
1069780 m
1070781
1071782 (* let type_module ctx mpath file ?(is_extern=false) tdecls p =
1074785
1075786 let type_module_hook = ref (fun _ _ _ -> None)
1076787
1077 let load_module ctx m p =
1078 let m2 = (try
1079 Hashtbl.find ctx.g.modules m
1080 with
1081 Not_found ->
1082 match !type_module_hook ctx m p with
1083 | Some m -> m
1084 | None ->
788 let load_module' ctx g m p =
789 try
790 (* Check current context *)
791 ctx.com.module_lut#find m
792 with Not_found ->
793 (* Check cache *)
794 match !type_module_hook ctx m p with
795 | Some m ->
796 m
797 | None ->
798 let raise_not_found () =
799 raise (Error (Module_not_found m,p,0))
800 in
801 if ctx.com.module_nonexistent_lut#mem m then raise_not_found();
802 if ctx.g.load_only_cached_modules then raise_not_found();
1085803 let is_extern = ref false in
1086 let file, decls = (try
804 let file, decls = try
805 (* Try parsing *)
1087806 TypeloadParse.parse_module ctx m p
1088807 with Not_found ->
808 (* Nothing to parse, try loading extern type *)
1089809 let rec loop = function
1090810 | [] ->
1091 raise (Error (Module_not_found m,p))
811 ctx.com.module_nonexistent_lut#add m true;
812 raise_not_found()
1092813 | (file,load) :: l ->
1093814 match load m p with
1094815 | None -> loop l
1096817 in
1097818 is_extern := true;
1098819 loop ctx.com.load_extern_type
1099 ) in
820 in
1100821 let is_extern = !is_extern in
1101822 try
1102823 type_module ctx m file ~is_extern decls p
1103824 with Forbid_package (inf,pl,pf) when p <> null_pos ->
1104825 raise (Forbid_package (inf,p::pl,pf))
1105 ) in
1106 add_dependency ctx.m.curmod m2;
826
827 let load_module ctx m p =
828 let m2 = load_module' ctx ctx.g m p in
829 add_dependency ~skip_postprocess:true ctx.m.curmod m2;
1107830 if ctx.pass = PTypeField then flush_pass ctx PConnectField "load_module";
1108831 m2
1109832
2121 open Globals
2222 open Ast
2323 open Parser
24 open DisplayTypes.DiagnosticsSeverity
2524 open DisplayTypes.DisplayMode
2625 open Common
2726 open Type
3938 with
4039 | Sedlexing.MalFormed ->
4140 t();
42 error "Malformed file. Source files must be encoded with UTF-8." {pfile = file; pmin = 0; pmax = 0}
41 typing_error "Malformed file. Source files must be encoded with UTF-8." {pfile = file; pmin = 0; pmax = 0}
4342 | e ->
4443 t();
4544 raise e
7675 in
7776 parse_file_from_string com file p s
7877 else
79 let ch = try open_in_bin file with _ -> error ("Could not open " ^ file) p in
78 let ch = try open_in_bin file with _ -> typing_error ("Could not open " ^ file) p in
8079 Std.finally (fun() -> close_in ch) (parse_file_from_lexbuf com file p) (Sedlexing.Utf8.from_channel ch)
8180
8281 let parse_hook = ref parse_file
138137
139138 let resolve_module_file com m remap p =
140139 try
141 Hashtbl.find com.module_to_file m
140 com.module_to_file#find m
142141 with Not_found ->
143142 let file = resolve_module_file com m remap p in
144 Hashtbl.add com.module_to_file m file;
143 com.module_to_file#add m file;
145144 file
146145
147146 (* let resolve_module_file com m remap p =
250249 raise DisplayInMacroBlock;
251250 begin match com.display.dms_kind with
252251 | DMHover ->
253 raise (DisplayException.DisplayException(DisplayHover None))
252 raise (DisplayException.DisplayException(DisplayNoResult))
254253 | _ ->
255254 ()
256255 end;
269268 let handle_parser_error msg p =
270269 let msg = Parser.error_msg msg in
271270 match com.display.dms_error_policy with
272 | EPShow -> error msg p
273 | EPIgnore -> ()
274 | EPCollect -> add_diagnostics_message com msg p DKParserError Error
271 | EPShow ->
272 if is_diagnostics com then add_diagnostics_message com (located msg p) DKParserError Error
273 else typing_error msg p
274 | EPIgnore ->
275 com.has_error <- true
275276 in
276277 match result with
277278 | ParseSuccess(data,is_display_file,pdi) ->
301302 if pack <> !remap then begin
302303 let spack m = if m = [] then "`package;`" else "`package " ^ (String.concat "." m) ^ ";`" in
303304 if p == null_pos then
304 display_error ctx ("Invalid commandline class : " ^ s_type_path m ^ " should be " ^ s_type_path (pack,snd m)) p
305 display_error ctx.com ("Invalid commandline class : " ^ s_type_path m ^ " should be " ^ s_type_path (pack,snd m)) p
305306 else
306 display_error ctx (spack pack ^ " in " ^ file ^ " should be " ^ spack (fst m)) {p with pmax = p.pmin}
307 display_error ctx.com (spack pack ^ " in " ^ file ^ " should be " ^ spack (fst m)) {p with pmax = p.pmin}
307308 end;
308309 file, if !remap <> fst m then
309310 (* build typedefs to redirect to real package *)
3535 (* ---------------------------------------------------------------------- *)
3636 (* TOOLS *)
3737
38 let mono_or_dynamic ctx with_type p = match with_type with
39 | WithType.NoValue ->
40 t_dynamic
41 | Value _ | WithType _ ->
42 spawn_monomorph ctx p
43
3844 let get_iterator_param t =
3945 match follow t with
4046 | TAnon a ->
7480 ) c.cl_ordered_statics in
7581 false,a.a_path,fields,TAbstractDecl a
7682 | TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
77 begin match get_abstract_froms a pl with
83 begin match get_abstract_froms ctx a pl with
7884 | [t2] ->
7985 if (List.exists (shallow_eq t) stack) then raise Exit;
8086 loop (t :: stack) t2
9096 let e = try
9197 f()
9298 with
93 | Error (Unknown_ident n,_) ->
99 | Error (Unknown_ident n,_,_) ->
94100 restore();
95101 raise_or_display_message ctx (StringError.string_error n fields ("Identifier '" ^ n ^ "' is not part of " ^ s_type_path path)) p;
96102 AKExpr (mk (TConst TNull) (mk_mono()) p)
116122 end
117123 with Exit ->
118124 f()
119
120 let check_error ctx err p = match err with
121 | Module_not_found ([],name) when Diagnostics.is_diagnostics_run ctx.com p ->
122 DisplayToplevel.handle_unresolved_identifier ctx name p true
123 | _ ->
124 display_error ctx (error_msg err) p
125125
126126 (* ---------------------------------------------------------------------- *)
127127 (* PASS 3 : type expression & check structure *)
242242 | UnifyMinOk t ->
243243 t
244244 | UnifyMinError(l,index) ->
245 raise_error (Unify l) (List.nth el index).epos
245 raise_typing_error (Unify l) (List.nth el index).epos
246246 end
247247
248248 let unify_min ctx el =
249249 try unify_min_raise ctx el
250 with Error (Unify l,p) ->
251 if not ctx.untyped then display_error ctx (error_msg (Unify l)) p;
250 with Error (Unify l,p,depth) ->
251 if not ctx.untyped then located_display_error ~depth ctx.com (error_msg p (Unify l));
252252 (List.hd el).etype
253253
254254 let unify_min_for_type_source ctx el src =
262262 let is_set = match mode with MSet _ -> true | _ -> false in
263263 match i with
264264 | "true" ->
265 let acc = AKExpr (mk (TConst (TBool true)) ctx.t.tbool p) in
265266 if mode = MGet then
266 AKExpr (mk (TConst (TBool true)) ctx.t.tbool p)
267 acc
267268 else
268 AKNo i
269 AKNo(acc,p)
269270 | "false" ->
271 let acc = AKExpr (mk (TConst (TBool false)) ctx.t.tbool p) in
270272 if mode = MGet then
271 AKExpr (mk (TConst (TBool false)) ctx.t.tbool p)
273 acc
272274 else
273 AKNo i
275 AKNo(acc,p)
274276 | "this" ->
275 if is_set then add_class_field_flag ctx.curfield CfModifiesThis;
276 (match mode, ctx.curclass.cl_kind with
277 | MSet _, KAbstractImpl _ ->
278 if not (assign_to_this_is_allowed ctx) then
279 error "Abstract 'this' value can only be modified inside an inline function" p;
280 AKExpr (get_this ctx p)
281 | (MCall _, KAbstractImpl _) | (MGet, _)-> AKExpr(get_this ctx p)
282 | _ -> AKNo i)
277 let acc = AKExpr(get_this ctx p) in
278 begin match mode with
279 | MSet _ ->
280 add_class_field_flag ctx.curfield CfModifiesThis;
281 begin match ctx.curclass.cl_kind with
282 | KAbstractImpl _ ->
283 if not (assign_to_this_is_allowed ctx) then
284 typing_error "Abstract 'this' value can only be modified inside an inline function" p;
285 acc
286 | _ ->
287 AKNo(acc,p)
288 end
289 | MCall _ ->
290 begin match ctx.curclass.cl_kind with
291 | KAbstractImpl _ ->
292 acc
293 | _ ->
294 AKNo(acc,p)
295 end
296 | MGet ->
297 acc
298 end;
299 | "abstract" ->
300 begin match mode, ctx.curclass.cl_kind with
301 | MSet _, KAbstractImpl ab -> typing_error "Property 'abstract' is read-only" p;
302 | (MGet, KAbstractImpl ab)
303 | (MCall _, KAbstractImpl ab) ->
304 let tl = extract_param_types ab.a_params in
305 let e = get_this ctx p in
306 let e = {e with etype = TAbstract (ab,tl)} in
307 AKExpr e
308 | _ ->
309 typing_error "Property 'abstract' is reserved and only available in abstracts" p
310 end
283311 | "super" ->
284312 let t = (match ctx.curclass.cl_super with
285 | None -> error "Current class does not have a superclass" p
313 | None -> typing_error "Current class does not have a superclass" p
286314 | Some (c,params) -> TInst(c,params)
287315 ) in
288316 (match ctx.curfun with
289317 | FunMember | FunConstructor -> ()
290 | FunMemberAbstract -> error "Cannot access super inside an abstract function" p
291 | FunStatic -> error "Cannot access super inside a static function" p;
292 | FunMemberClassLocal | FunMemberAbstractLocal -> error "Cannot access super inside a local function" p);
318 | FunMemberAbstract -> typing_error "Cannot access super inside an abstract function" p
319 | FunStatic -> typing_error "Cannot access super inside a static function" p;
320 | FunMemberClassLocal | FunMemberAbstractLocal -> typing_error "Cannot access super inside a local function" p);
293321 AKExpr (mk (TConst TSuper) t p)
294322 | "null" ->
295 if mode = MGet then
296 AKExpr (null (spawn_monomorph ctx p) p)
297 else
298 AKNo i
323 let acc =
324 (* Hack for #10787 *)
325 if ctx.com.platform = Cs then
326 AKExpr (null (spawn_monomorph ctx p) p)
327 else begin
328 let tnull () = ctx.t.tnull (spawn_monomorph ctx p) in
329 let t = match with_type with
330 | WithType.WithType(t,_) ->
331 begin match follow t with
332 | TMono r ->
333 (* If our expected type is a monomorph, bind it to Null<?>. *)
334 Monomorph.do_bind r (tnull())
335 | _ ->
336 (* Otherwise there's no need to create a monomorph, we can just type the null literal
337 the way we expect it. *)
338 ()
339 end;
340 t
341 | _ ->
342 tnull()
343 in
344 AKExpr (null t p)
345 end
346 in
347 if mode = MGet then acc else AKNo(acc,p)
299348 | _ ->
300349 try
301350 let v = PMap.find i ctx.locals in
306355 (match e with
307356 | Some ({ eexpr = TFunction f } as e) when ctx.com.display.dms_inline ->
308357 begin match mode with
309 | MSet _ -> error "Cannot set inline closure" p
310 | MGet -> error "Cannot create closure on inline closure" p
358 | MSet _ -> typing_error "Cannot set inline closure" p
359 | MGet -> typing_error "Cannot create closure on inline closure" p
311360 | MCall _ ->
312361 (* create a fake class with a fake field to emulate inlining *)
313362 let c = mk_class ctx.m.curmod (["local"],v.v_name) e.epos null_pos in
324373 with Not_found -> try
325374 (* member variable lookup *)
326375 if ctx.curfun = FunStatic then raise Not_found;
327 let c , t , f = class_field ctx ctx.curclass (List.map snd ctx.curclass.cl_params) i p in
376 let c , t , f = class_field ctx ctx.curclass (extract_param_types ctx.curclass.cl_params) i p in
328377 field_access ctx mode f (match c with None -> FHAnon | Some (c,tl) -> FHInstance (c,tl)) (get_this ctx p) p
329378 with Not_found -> try
330379 (* static variable lookup *)
332381 let is_impl = has_class_field_flag f CfImpl in
333382 let is_enum = has_class_field_flag f CfEnum in
334383 if is_impl && not (has_class_field_flag ctx.curfield CfImpl) && not is_enum then
335 error (Printf.sprintf "Cannot access non-static field %s from static method" f.cf_name) p;
384 typing_error (Printf.sprintf "Cannot access non-static field %s from static method" f.cf_name) p;
336385 let e,fa = match ctx.curclass.cl_kind with
337386 | KAbstractImpl a when is_impl && not is_enum ->
338 let tl = List.map snd a.a_params in
387 let tl = extract_param_types a.a_params in
339388 let e = get_this ctx p in
340389 let e = {e with etype = TAbstract(a,tl)} in
341390 e,FHAbstract(a,tl,ctx.curclass)
354403 field_access ctx mode f (FHStatic c) e p
355404 )
356405 with Not_found -> try
357 let wrap e = if is_set then
358 AKNo i
406 let wrap e =
407 let acc = AKExpr e in
408 if is_set then
409 AKNo(acc,p)
359410 else
360 AKExpr e
411 acc
361412 in
362413 (* lookup imported enums *)
363414 let rec loop l =
376427 | Var {v_read = AccInline} -> true
377428 | _ -> false
378429 in
379 let fa = FieldAccess.create et cf (FHAbstract(a,List.map snd a.a_params,c)) inline p in
430 let fa = FieldAccess.create et cf (FHAbstract(a,extract_param_types a.a_params,c)) inline p in
380431 ImportHandling.mark_import_position ctx pt;
381432 AKField fa
382433 end
399450 with
400451 Not_found -> loop l
401452 in
402 (try loop (List.rev_map (fun t -> t,null_pos) ctx.m.curmod.m_types) with Not_found -> loop ctx.m.module_types)
453 (try loop (List.rev_map (fun t -> t,null_pos) ctx.m.curmod.m_types) with Not_found -> loop ctx.m.module_imports)
403454 with Not_found ->
404455 (* lookup imported globals *)
405456 let t, name, pi = PMap.find i ctx.m.module_globals in
413464 with Not_found -> try
414465 (* lookup type *)
415466 if is_lower_ident i p then raise Not_found;
416 let e = (try type_type ctx ([],i) p with Error (Module_not_found ([],name),_) when name = i -> raise Not_found) in
467 let e = (try type_type ctx ([],i) p with Error (Module_not_found ([],name),_,_) when name = i -> raise Not_found) in
417468 AKExpr e
418469 with Not_found ->
419470 let resolved_to_type_parameter = ref false in
420471 try
421 let t = List.find (fun (i2,_) -> i2 = i) ctx.type_params in
472 let t = List.find (fun tp -> tp.ttp_name = i) ctx.type_params in
422473 resolved_to_type_parameter := true;
423 let c = match follow (snd t) with TInst(c,_) -> c | _ -> die "" __LOC__ in
474 let c = match follow (extract_param_type t) with TInst(c,_) -> c | _ -> die "" __LOC__ in
424475 if TypeloadCheck.is_generic_parameter ctx c && Meta.has Meta.Const c.cl_meta then begin
425476 let e = type_module_type ctx (TClassDecl c) None p in
426 AKExpr {e with etype = (snd t)}
477 AKExpr {e with etype = (extract_param_type t)}
427478 end else
428479 raise Not_found
429480 with Not_found ->
434485 let t = mk_mono() in
435486 AKExpr ((mk (TIdent i)) t p)
436487 end else begin
437 if ctx.curfun = FunStatic && PMap.mem i ctx.curclass.cl_fields then error ("Cannot access " ^ i ^ " in static function") p;
488 if ctx.curfun = FunStatic && PMap.mem i ctx.curclass.cl_fields then typing_error ("Cannot access " ^ i ^ " in static function") p;
438489 if !resolved_to_type_parameter then begin
439 display_error ctx ("Only @:const type parameters on @:generic classes can be used as value") p;
490 display_error ctx.com ("Only @:const type parameters on @:generic classes can be used as value") p;
440491 AKExpr (mk (TConst TNull) t_dynamic p)
441492 end else begin
442493 let err = Unknown_ident i in
443494 if ctx.in_display then begin
444 raise (Error (err,p))
495 raise (Error (err,p,0))
445496 end;
446 match ctx.com.display.dms_kind with
497 if Diagnostics.error_in_diagnostics_run ctx.com p then begin
498 DisplayToplevel.handle_unresolved_identifier ctx i p false;
499 DisplayFields.handle_missing_ident ctx i mode with_type p;
500 let t = mk_mono() in
501 AKExpr (mk (TIdent i) t p)
502 end else match ctx.com.display.dms_kind with
447503 | DMNone ->
448 raise (Error(err,p))
449 | DMDiagnostics _ ->
450 DisplayToplevel.handle_unresolved_identifier ctx i p false;
451 DisplayFields.handle_missing_ident ctx i mode with_type p;
452 let t = mk_mono() in
453 AKExpr (mk (TIdent i) t p)
504 raise (Error(err,p,0))
454505 | _ ->
455 display_error ctx (error_msg err) p;
506 located_display_error ctx.com (error_msg p err);
456507 let t = mk_mono() in
457508 (* Add a fake local for #8751. *)
458509 if !ServerConfig.legacy_completion then
465516 let open TyperDotPath in
466517
467518 let dot_path first pnext =
468 let name,_,p = first in
519 let {name = name; pos = p} = first in
469520 try
470521 (* first, try to resolve the first ident in the chain and access its fields.
471522 this doesn't support untyped identifiers yet, because we want to check fully-qualified
481532 try
482533 (* TODO: we don't really want to do full type_ident again, just the second part of it *)
483534 field_chain ctx pnext (type_ident ctx name p MGet WithType.value)
484 with Error (Unknown_ident _,p2) as e when p = p2 ->
535 with Error (Unknown_ident _,p2,_) as e when p = p2 ->
485536 try
486537 (* try raising a more sensible error if there was an uppercase-first (module name) part *)
487538 begin
488539 (* TODO: we should pass the actual resolution error from resolve_dot_path instead of Not_found *)
489540 let rec loop pack_acc first_uppercase path =
490541 match path with
491 | (name,PLowercase,_) :: rest ->
542 | {name = name; case = PLowercase} :: rest ->
492543 (match first_uppercase with
493544 | None -> loop (name :: pack_acc) None rest
494545 | Some (n,p) -> List.rev pack_acc, n, None, p)
495 | (name,PUppercase,p) :: rest ->
546 | {name = name; case = PUppercase; pos = p} :: rest ->
496547 (match first_uppercase with
497548 | None -> loop pack_acc (Some (name,p)) rest
498549 | Some (n,_) -> List.rev pack_acc, n, Some name, p)
503554 in
504555 let pack,name,sub,p = loop [] None path in
505556 let mpath = (pack,name) in
506 if Hashtbl.mem ctx.g.modules mpath then
557 if ctx.com.module_lut#mem mpath then
507558 let tname = Option.default name sub in
508 raise (Error (Type_not_found (mpath,tname,Not_defined),p))
559 raise (Error (Type_not_found (mpath,tname,Not_defined),p,0))
509560 else
510 raise (Error (Module_not_found mpath,p))
561 raise (Error (Module_not_found mpath,p,0))
511562 end
512563 with Not_found ->
513564 (* if there was no module name part, last guess is that we're trying to get package completion *)
514565 if ctx.in_display then begin
515 let sl = List.map (fun (n,_,_) -> n) path in
566 let sl = List.map (fun part -> part.name) path in
516567 if is_legacy_completion ctx.com then
517568 raise (Parser.TypePath (sl,None,false,p))
518569 else
522573 in
523574
524575 (* loop through the given EField expression to figure out whether it's a dot-path that we have to resolve,
525 or a simple field access chain *)
576 or a field access chain *)
526577 let rec loop dot_path_acc (e,p) =
527578 match e with
528 | EField (e,s) ->
579 | EField (e,s,EFNormal) ->
529580 (* field access - accumulate and check further *)
530581 loop ((mk_dot_path_part s p) :: dot_path_acc) e
531582 | EConst (Ident i) ->
532583 (* it's a dot-path, so it might be either fully-qualified access (pack.Class.field)
533584 or normal field access of a local/global/field identifier, proceed figuring this out *)
534 dot_path (mk_dot_path_part i p) dot_path_acc
585 dot_path (mk_dot_path_part i p) dot_path_acc mode with_type
586 | EField ((eobj,pobj),s,EFSafe) ->
587 (* safe navigation field access - definitely NOT a fully-qualified access,
588 create safe navigation chain from the object expression *)
589 let acc_obj = type_access ctx eobj pobj MGet WithType.value in
590 let eobj = acc_get ctx acc_obj in
591 let eobj, tempvar = match (Texpr.skip eobj).eexpr with
592 | TLocal _ | TTypeExpr _ | TConst _ ->
593 eobj, None
594 | _ ->
595 let v = alloc_var VGenerated "tmp" eobj.etype eobj.epos in
596 let temp_var = mk (TVar(v, Some eobj)) ctx.t.tvoid v.v_pos in
597 let eobj = mk (TLocal v) v.v_type v.v_pos in
598 eobj, Some temp_var
599 in
600 let access = field_chain ctx ((mk_dot_path_part s p) :: dot_path_acc) (AKExpr eobj) mode with_type in
601 AKSafeNav {
602 sn_pos = p;
603 sn_base = eobj;
604 sn_temp_var = tempvar;
605 sn_access = access;
606 }
535607 | _ ->
536608 (* non-ident expr occured: definitely NOT a fully-qualified access,
537609 resolve the field chain against this expression *)
538 let e = type_access ctx e p MGet WithType.value in
539 field_chain ctx dot_path_acc e
540 in
541 loop [] (e,p0) mode with_type
610 (match (type_access ctx e p MGet WithType.value) with
611 | AKSafeNav sn ->
612 (* further field access continues the safe navigation chain (after a non-field access inside the chain) *)
613 AKSafeNav { sn with sn_access = field_chain ctx dot_path_acc sn.sn_access mode with_type }
614 | e ->
615 field_chain ctx dot_path_acc e mode with_type)
616 in
617 loop [] (e,p0)
542618
543619 and type_access ctx e p mode with_type =
544620 match e with
545621 | EConst (Ident s) ->
546622 type_ident ctx s p mode with_type
547 | EField (e1,"new") ->
623 | EField (e1,"new",efk_todo) ->
548624 let e1 = type_expr ctx e1 WithType.value in
549625 begin match e1.eexpr with
550626 | TTypeExpr (TClassDecl c) ->
551627 begin match mode with
552 | MSet _ -> error "Cannot set constructor" p;
553 | MCall _ -> error ("Cannot call constructor like this, use 'new " ^ (s_type_path c.cl_path) ^ "()' instead") p;
628 | MSet _ -> typing_error "Cannot set constructor" p;
629 | MCall _ -> typing_error ("Cannot call constructor like this, use 'new " ^ (s_type_path c.cl_path) ^ "()' instead") p;
554630 | MGet -> ()
555631 end;
556632 let monos = Monomorph.spawn_constrained_monos (fun t -> t) (match c.cl_kind with KAbstractImpl a -> a.a_params | _ -> c.cl_params) in
579655 tf_type = t;
580656 tf_expr = mk (TReturn (Some ec)) t p;
581657 }) (TFun ((List.map (fun v -> v.v_name,false,v.v_type) vl),t)) p)
582 | _ -> error "Binding new is only allowed on class types" p
658 | _ -> typing_error "Binding new is only allowed on class types" p
583659 end;
584660 | EField _ ->
585661 handle_efield ctx e p mode with_type
586662 | EArray (e1,e2) ->
587663 type_array_access ctx e1 e2 p mode
664 | ECall (e, el) ->
665 type_call_access ctx e el mode with_type None p
588666 | EDisplay (e,dk) ->
589 AKExpr (TyperDisplay.handle_edisplay ctx e dk mode WithType.value)
667 AKExpr (TyperDisplay.handle_edisplay ctx e dk mode with_type)
590668 | _ ->
591 AKExpr (type_expr ~mode ctx (e,p) WithType.value)
669 AKExpr (type_expr ~mode ctx (e,p) with_type)
592670
593671 and type_array_access ctx e1 e2 p mode =
594 let e1 = type_expr ctx e1 WithType.value in
672 let e1, p1 = e1 in
673 let a1 = type_access ctx e1 p1 MGet WithType.value in
595674 let e2 = type_expr ctx e2 WithType.value in
596 Calls.array_access ctx e1 e2 mode p
675 match a1 with
676 | AKSafeNav sn ->
677 (* pack the array access inside the safe navigation chain *)
678 let e1 = acc_get ctx sn.sn_access in
679 AKSafeNav { sn with sn_access = Calls.array_access ctx e1 e2 mode p }
680 | _ ->
681 let e1 = acc_get ctx a1 in
682 Calls.array_access ctx e1 e2 mode p
597683
598684 and type_vars ctx vl p =
599685 let vl = List.map (fun ev ->
605691 let e = (match ev.ev_expr with
606692 | None -> None
607693 | Some e ->
608 let e = type_expr ctx e (WithType.with_type t) in
694 let old_in_loop = ctx.in_loop in
695 if ev.ev_static then ctx.in_loop <- false;
696 let e = Std.finally (fun () -> ctx.in_loop <- old_in_loop) (type_expr ctx e) (WithType.with_type t) in
609697 let e = AbstractCast.cast_or_unify ctx t e p in
610698 Some e
611699 ) in
612 let v = add_local_with_origin ctx TVOLocalVariable n t pv in
700 let v = if Meta.has Meta.This ev.ev_meta then
701 add_local ctx VAbstractThis n t pv
702 else
703 add_local_with_origin ctx TVOLocalVariable n t pv
704 in
613705 v.v_meta <- ev.ev_meta;
706 DisplayEmitter.check_display_metadata ctx v.v_meta;
614707 if ev.ev_final then add_var_flag v VFinal;
708 if ev.ev_static then add_var_flag v VStatic;
615709 if ctx.in_display && DisplayPosition.display_position#enclosed_in pv then
616710 DisplayEmitter.display_variable ctx v pv;
617711 v,e
618712 with
619 Error (e,p) ->
620 check_error ctx e p;
713 Error (e,p,depth) ->
714 check_error ctx e p depth;
621715 add_local ctx VGenerated n t_dynamic pv, None (* TODO: What to do with this... *)
622716 ) vl in
623 delay ctx PTypeField (fun() ->
624 List.iter
625 (fun (v,_) ->
626 if ExtType.is_void (follow v.v_type) then
627 error "Variables of type Void are not allowed" v.v_pos
628 )
629 vl
630 );
717 List.iter (fun (v,_) ->
718 delay_if_mono ctx PTypeField v.v_type (fun() ->
719 if ExtType.is_void (follow v.v_type) then
720 typing_error "Variables of type Void are not allowed" v.v_pos
721 )
722 ) vl;
631723 match vl with
632724 | [v,eo] ->
633725 mk (TVar (v,eo)) ctx.t.tvoid p
699791 if i = len then
700792 match groups with
701793 | [] -> die "" __LOC__
702 | g :: _ -> error ("Unclosed " ^ gname) { p with pmin = !pmin + g + 1; pmax = !pmin + g + 2 }
794 | g :: _ -> typing_error ("Unclosed " ^ gname) { p with pmin = !pmin + g + 1; pmax = !pmin + g + 2 }
703795 else
704796 let c = String.unsafe_get s i in
705797 if c = gopen then
718810 let e =
719811 let ep = { p with pmin = !pmin + pos + 2; pmax = !pmin + send + 1 } in
720812 let error msg pos =
721 if Lexer.string_is_whitespace scode then error "Expression cannot be empty" ep
722 else error msg pos
813 if Lexer.string_is_whitespace scode then typing_error "Expression cannot be empty" ep
814 else typing_error msg pos
723815 in
724816 match ParserEntry.parse_expr_string ctx.com.defines scode ep error true with
725817 | ParseSuccess(data,_,_) -> data
745837 let rec loop acc = function
746838 | [] -> List.rev acc
747839 | e :: l ->
748 let acc = try merge acc (type_expr ctx e (if l = [] then with_type else WithType.no_value)) with Error (e,p) -> check_error ctx e p; acc in
840 let acc = try merge acc (type_expr ctx e (if l = [] then with_type else WithType.no_value)) with Error (e,p,depth) -> check_error ctx e p depth; acc in
749841 loop acc l
750842 in
751843 let l = loop [] el in
766858 | TAbstract (a,pl) as t
767859 when not (Meta.has Meta.CoreType a.a_meta)
768860 && not (List.exists (fun t' -> shallow_eq t t') seen) ->
769 let froms = get_abstract_froms a pl
770 and fold = fun acc t' -> match loop (t :: seen) t' with ODKPlain -> acc | t -> t :: acc in
771 (match List.fold_left fold [] froms with
772 | [t] -> t
773 | _ -> ODKPlain)
774 | TDynamic t when (follow t != t_dynamic) ->
861 let froms = get_abstract_froms ctx a pl in
862 let fold = fun acc t' -> match loop (t :: seen) t' with ODKPlain -> acc | t -> t :: acc in
863 begin match List.fold_left fold [] froms with
864 | [] -> ODKPlain (* If the abstract has no casts in the first place, we can assume plain typing (issue #10730) *)
865 | [t] -> t
866 | _ -> ODKFailed
867 end
868 | TDynamic (Some t) ->
775869 dynamic_parameter := Some t;
776870 ODKWithStructure {
777871 a_status = ref Closed;
791885 let extra_fields = ref [] in
792886 let fl = List.map (fun ((n,pn,qs),e) ->
793887 let is_valid = Lexer.is_valid_identifier n in
794 if PMap.mem n !fields then error ("Duplicate field in object declaration : " ^ n) p;
888 if PMap.mem n !fields then typing_error ("Duplicate field in object declaration : " ^ n) pn;
795889 let is_final = ref false in
796890 let e = try
797891 let t = match !dynamic_parameter with
812906 type_expr ctx e WithType.value
813907 in
814908 if is_valid then begin
815 if starts_with n '$' then error "Field names starting with a dollar are not allowed" p;
909 if starts_with n '$' then typing_error "Field names starting with a dollar are not allowed" p;
816910 let cf = mk_field n e.etype (punion pn e.epos) pn in
817911 if !is_final then add_class_field_flag cf CfFinal;
818912 fields := PMap.add n cf !fields;
824918 (match PMap.foldi (fun n cf acc -> if not (Meta.has Meta.Optional cf.cf_meta) && not (PMap.mem n !fields) then n :: acc else acc) field_map [] with
825919 | [] -> ()
826920 | [n] -> raise_or_display ctx [Unify_custom ("Object requires field " ^ n)] p
827 | nl -> raise_or_display ctx [Unify_custom ("Object requires fields: " ^ (String.concat ", " nl))] p);
921 | depth -> raise_or_display ctx [Unify_custom ("Object requires fields: " ^ (String.concat ", " depth))] p);
828922 (match !extra_fields with
829923 | [] -> ()
830924 | _ -> raise_or_display ctx (List.map (fun n -> has_extra_field t n) !extra_fields) p);
834928 let type_plain_fields () =
835929 let rec loop (l,acc) ((f,pf,qs),e) =
836930 let is_valid = Lexer.is_valid_identifier f in
837 if PMap.mem f acc then error ("Duplicate field in object declaration : " ^ f) p;
931 if PMap.mem f acc then typing_error ("Duplicate field in object declaration : " ^ f) pf;
838932 let e = type_expr ctx e (WithType.named_structure_field f) in
839 (match follow e.etype with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed in structures" e.epos | _ -> ());
933 (match follow e.etype with TAbstract({a_path=[],"Void"},_) -> typing_error "Fields of type Void are not allowed in structures" e.epos | _ -> ());
840934 let cf = mk_field f e.etype (punion pf e.epos) pf in
841935 if ctx.in_display && DisplayPosition.display_position#enclosed_in pf then DisplayEmitter.display_field ctx Unknown CFSMember cf pf;
842936 (((f,pf,qs),e) :: l, if is_valid then begin
843 if starts_with f '$' then error "Field names starting with a dollar are not allowed" p;
937 if starts_with f '$' then typing_error "Field names starting with a dollar are not allowed" p;
844938 PMap.add f cf acc
845939 end else acc)
846940 in
850944 mk (TObjectDecl (List.rev fields)) (mk_anon ~fields:types x) p
851945 in
852946 (match a with
853 | ODKPlain -> type_plain_fields()
947 | ODKPlain | ODKFailed -> type_plain_fields()
854948 | ODKWithStructure a when PMap.is_empty a.a_fields && !dynamic_parameter = None -> type_plain_fields()
855949 | ODKWithStructure a ->
856950 let t, fl = type_fields a.a_fields in
859953 let fa = FieldAccess.get_constructor_access c tl p in
860954 let ctor = fa.fa_field in
861955 let args = match follow (FieldAccess.get_map_function fa ctor.cf_type) with
862 | TFun(args,_) -> args
956 | TFun(args,_) ->
957 begin match ctor.cf_expr with
958 | Some {eexpr = TFunction tf} ->
959 let rec loop acc args vl = match args,vl with
960 | arg :: args,(v,_) :: vl ->
961 loop ((arg,v.v_pos) :: acc) args vl
962 | [],_ ->
963 List.rev acc
964 | arg :: args,[] ->
965 loop ((arg,ctor.cf_name_pos) :: acc) args []
966 in
967 loop [] args tf.tf_args
968 | _ ->
969 List.map (fun args -> (args,ctor.cf_name_pos)) args
970 end
863971 | _ -> die "" __LOC__
864972 in
865 let fields = List.fold_left (fun acc (n,opt,t) ->
866 let f = mk_field n t ctor.cf_pos ctor.cf_name_pos in
867 if opt then f.cf_meta <- [(Meta.Optional,[],ctor.cf_pos)];
973 let fields = List.fold_left (fun acc ((n,opt,t),parg) ->
974 let f = mk_field n t parg parg in
975 if opt then f.cf_meta <- [(Meta.Optional,[],null_pos)];
868976 PMap.add n f acc
869977 ) PMap.empty args in
870978 let t,fl = type_fields fields in
882990 evars,(s,e) :: elocs,OptimizerTexpr.has_side_effect e
883991 end
884992 ) ([],[],false) (List.rev fl) in
885 let el = List.map (fun (n,_,t) ->
993 let el = List.map (fun ((n,_,t),parg) ->
886994 try Expr.field_assoc n fl
887995 with Not_found ->
888996 try
9281036 let fcc = unify_field_call ctx fa [] el p fa.fa_inline in
9291037 check_constructor_access ctx c fcc.fc_field p;
9301038 fcc
931 with Error (e,p) ->
932 error (error_msg e) p;
1039 with Error (e,p,depth) ->
1040 located_typing_error ~depth (error_msg p e);
1041 in
1042 let display_position_in_el () =
1043 List.exists (fun e -> DisplayPosition.display_position#enclosed_in (pos e)) el
9331044 in
9341045 let t = if (fst path).tparams <> [] then begin
9351046 try
9361047 Typeload.load_instance ctx path false
937 with Error _ as exc when ctx.com.display.dms_display ->
1048 with Error _ as exc when display_position_in_el() ->
9381049 (* If we fail for some reason, process the arguments in case we want to display them (#7650). *)
9391050 List.iter (fun e -> ignore(type_expr ctx e WithType.value)) el;
9401051 raise exc
9451056 ctx.call_argument_stack <- List.tl ctx.call_argument_stack;
9461057 (* Try to properly build @:generic classes here (issue #2016) *)
9471058 begin match t_follow with
948 | TInst({cl_kind = KGeneric } as c,tl) -> follow (Generic.build_generic ctx c p tl)
1059 | TInst({cl_kind = KGeneric } as c,tl) -> follow (Generic.build_generic_class ctx c p tl)
9491060 | _ -> t
9501061 end
9511062 with
9581069 no_abstract_constructor c p;
9591070 ignore (unify_constructor_call c fa);
9601071 begin try
961 Generic.build_generic ctx c p monos
1072 Generic.build_generic_class ctx c p monos
9621073 with Generic.Generic_Exception _ as exc ->
9631074 (* If we have an expected type, just use that (issue #3804) *)
9641075 begin match with_type with
9721083 end
9731084 end
9741085 | mt ->
975 error ((s_type_path (t_infos mt).mt_path) ^ " cannot be constructed") p
1086 typing_error ((s_type_path (t_infos mt).mt_path) ^ " cannot be constructed") p
9761087 end
977 | Error _ as exc when ctx.com.display.dms_display ->
1088 | Error _ as exc when display_position_in_el() ->
9781089 List.iter (fun e -> ignore(type_expr ctx e WithType.value)) el;
9791090 raise exc
9801091 in
9861097 let cf = fa.fa_field in
9871098 no_abstract_constructor c p;
9881099 begin match cf.cf_kind with
989 | Var { v_read = AccRequire (r,msg) } -> (match msg with Some msg -> error msg p | None -> error_require r p)
1100 | Var { v_read = AccRequire (r,msg) } -> (match msg with Some msg -> typing_error msg p | None -> error_require r p)
9901101 | _ -> ()
9911102 end;
9921103 unify_constructor_call c fa
9931104 in
9941105 try begin match Abstract.follow_with_forward_ctor t with
9951106 | TInst ({cl_kind = KTypeParameter tl} as c,params) ->
996 if not (TypeloadCheck.is_generic_parameter ctx c) then error "Only generic type parameters can be constructed" p;
1107 if not (TypeloadCheck.is_generic_parameter ctx c) then typing_error "Only generic type parameters can be constructed" p;
9971108 begin match get_constructible_constraint ctx tl p with
9981109 | None ->
999 raise_error (No_constructor (TClassDecl c)) p
1110 raise_typing_error (No_constructor (TClassDecl c)) p
10001111 | Some(tl,tr) ->
10011112 let el,_ = unify_call_args ctx el tl tr p false false false in
10021113 mk (TNew (c,params,el)) t p
10091120 let el = fcc.fc_args in
10101121 mk (TNew (c,params,el)) t p
10111122 | _ ->
1012 error (s_type (print_context()) t ^ " cannot be constructed") p
1013 end with Error(No_constructor _ as err,p) when ctx.com.display.dms_kind <> DMNone ->
1014 display_error ctx (error_msg err) p;
1123 typing_error (s_type (print_context()) t ^ " cannot be constructed") p
1124 end with Error(No_constructor _ as err,p,depth) when ctx.com.display.dms_kind <> DMNone ->
1125 located_display_error ~depth ctx.com (error_msg p err);
10151126 Diagnostics.secure_generated_code ctx (mk (TConst TNull) t p)
10161127
10171128 and type_try ctx e1 catches with_type p =
10191130 let rec check_unreachable cases t p = match cases with
10201131 | (v,e) :: cases ->
10211132 let unreachable () =
1022 display_error ctx "This block is unreachable" p;
1133 display_error ctx.com "This block is unreachable" p;
10231134 let st = s_type (print_context()) in
1024 display_error ctx (Printf.sprintf "%s can be caught to %s, which is handled here" (st t) (st v.v_type)) e.epos
1135 display_error ctx.com (Printf.sprintf "%s can be caught to %s, which is handled here" (st t) (st v.v_type)) e.epos
10251136 in
10261137 begin try
10271138 begin match follow t,follow v.v_type with
10441155 in
10451156 let check_catch_type_params params p =
10461157 List.iter (fun pt ->
1047 if Abstract.follow_with_abstracts pt != t_dynamic then error "Catch class parameter must be Dynamic" p;
1158 if Abstract.follow_with_abstracts pt != t_dynamic then typing_error "Catch class parameter must be Dynamic" p;
10481159 ) params
10491160 in
10501161 let catches,el = List.fold_left (fun (acc1,acc2) ((v,pv),t,e_ast,pc) ->
10521163 let t = Typeload.load_complex_type ctx true th in
10531164 let rec loop t = match follow t with
10541165 | TInst ({ cl_kind = KTypeParameter _} as c,_) when not (TypeloadCheck.is_generic_parameter ctx c) ->
1055 error "Cannot catch non-generic type parameter" p
1166 typing_error "Cannot catch non-generic type parameter" p
10561167 | TInst (_,params) | TEnum (_,params) ->
10571168 check_catch_type_params params (snd th);
10581169 t
10621173 | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) ->
10631174 loop (Abstract.get_underlying_type a tl)
10641175 | TDynamic _ -> t
1065 | _ -> error "Catch type must be a class, an enum or Dynamic" (pos e_ast)
1176 | _ -> typing_error "Catch type must be a class, an enum or Dynamic" (pos e_ast)
10661177 in
10671178 let t2 = loop t in
10681179 check_unreachable acc1 t2 (pos e_ast);
11091220 let check_key e_key =
11101221 try
11111222 let p = Hashtbl.find keys e_key.eexpr in
1112 display_error ctx "Duplicate key" e_key.epos;
1113 error (compl_msg "Previously defined here") p
1223 display_error ctx.com "Duplicate key" e_key.epos;
1224 typing_error ~depth:1 (compl_msg "Previously defined here") p
11141225 with Not_found ->
11151226 begin match e_key.eexpr with
11161227 | TConst _ -> Hashtbl.add keys e_key.eexpr e_key.epos;
11221233 | EBinop(OpArrow,e1,e2) -> e1,e2
11231234 | EDisplay _ ->
11241235 ignore(type_expr ctx e (WithType.with_type tkey));
1125 error "Expected a => b" (pos e)
1126 | _ -> error "Expected a => b" (pos e)
1236 typing_error "Expected a => b" (pos e)
1237 | _ -> typing_error "Expected a => b" (pos e)
11271238 ) el in
11281239 let el_k,el_v,tkey,tval = if has_type then begin
11291240 let el_k,el_v = List.fold_left (fun (el_k,el_v) (e1,e2) ->
11661277 let name,inline = match kind with FKNamed (name,inline) -> Some name,inline | _ -> None,false in
11671278 let params = TypeloadFunction.type_function_params ctx f (match name with None -> "localfun" | Some (n,_) -> n) p in
11681279 if params <> [] then begin
1169 if name = None then display_error ctx "Type parameters not supported in unnamed local functions" p;
1170 if with_type <> WithType.NoValue then error "Type parameters are not supported for rvalue functions" p
1280 if name = None then display_error ctx.com "Type parameters not supported in unnamed local functions" p;
1281 if with_type <> WithType.NoValue then typing_error "Type parameters are not supported for rvalue functions" p
11711282 end;
11721283 let v,pname = (match name with
11731284 | None -> None,p
11771288 ctx.type_params <- params @ ctx.type_params;
11781289 if not inline then ctx.in_loop <- false;
11791290 let rt = Typeload.load_type_hint ctx p f.f_type in
1180 let type_arg opt t p = Typeload.load_type_hint ~opt ctx p t in
1291 let type_arg _ opt t p = Typeload.load_type_hint ~opt ctx p t in
11811292 let args = new FunctionArguments.function_arguments ctx type_arg false ctx.in_display None f.f_args in
11821293 let targs = args#for_type in
1294 let maybe_unify_arg t1 t2 =
1295 match follow t1 with
1296 | TMono _ -> unify ctx t2 t1 p
1297 | _ -> ()
1298 in
1299 let maybe_unify_ret tr = match follow tr,follow rt with
1300 | TAbstract({a_path = [],"Void"},_),_ when kind <> FKArrow -> ()
1301 | _,TMono _ -> unify ctx rt tr p
1302 | _ -> ()
1303 in
1304 (* The idea here is: If we have multiple `from Function`, we can
1305 1. ignore any that have a different argument arity, and
1306 2. still top-down infer any argument or return type that is equal across all candidates.
1307 *)
1308 let handle_abstract_matrix l =
1309 let arity = List.length targs in
1310 let m = new unification_matrix (arity + 1) in
1311 let rec loop l = match l with
1312 | t :: l ->
1313 begin match follow t with
1314 | TFun(args,ret) when List.length args = arity ->
1315 List.iteri (fun i (_,_,t) ->
1316 (* We don't want to bind monomorphs because we want the widest type *)
1317 let t = dynamify_monos t in
1318 m#join t (i + 1);
1319 ) args;
1320 let ret = dynamify_monos ret in
1321 m#join ret 0;
1322 | t ->
1323 ()
1324 end;
1325 loop l
1326 | [] ->
1327 ()
1328 in
1329 loop l;
1330 List.iteri (fun i (_,_,t1) ->
1331 match m#get_type (i + 1) with
1332 | Some t2 ->
1333 maybe_unify_arg t1 t2
1334 | None ->
1335 ()
1336 ) targs;
1337 begin match m#get_type 0 with
1338 | Some tr ->
1339 maybe_unify_ret tr
1340 | None ->
1341 ()
1342 end
1343 in
11831344 (match with_type with
11841345 | WithType.WithType(t,_) ->
1185 let rec loop t =
1346 let rec loop stack t =
11861347 (match follow t with
11871348 | TFun (args2,tr) when List.length args2 = List.length targs ->
11881349 List.iter2 (fun (_,_,t1) (_,_,t2) ->
1189 match follow t1 with
1190 | TMono _ -> unify ctx t2 t1 p
1191 | _ -> ()
1350 maybe_unify_arg t1 t2
11921351 ) targs args2;
11931352 (* unify for top-down inference unless we are expecting Void *)
1194 begin
1195 match follow tr,follow rt with
1196 | TAbstract({a_path = [],"Void"},_),_ when kind <> FKArrow -> ()
1197 | _,TMono _ -> unify ctx rt tr p
1198 | _ -> ()
1353 maybe_unify_ret tr
1354 | TAbstract(a,tl) ->
1355 begin match get_abstract_froms ctx a tl with
1356 | [t2] ->
1357 if not (List.exists (shallow_eq t) stack) then loop (t :: stack) t2
1358 | l ->
1359 (* For cases like nested EitherType, we want a flat list of all possible candidates.
1360 This might be controversial because those could be considered transitive casts,
1361 but it's unclear if that's a bad thing for this kind of inference (issue #10982). *)
1362 let rec loop stack acc l = match l with
1363 | t :: l ->
1364 begin match follow t with
1365 | TAbstract(a,tl) as t when not (List.exists (shallow_eq t) stack) ->
1366 loop (t :: stack) acc (l @ get_abstract_froms ctx a tl)
1367 | _ ->
1368 loop stack (t :: acc) l
1369 end
1370 | [] ->
1371 List.rev acc
1372 in
1373 handle_abstract_matrix (loop [] [] l)
11991374 end
1200 | TAbstract(a,tl) ->
1201 loop (Abstract.get_underlying_type a tl)
12021375 | _ -> ())
12031376 in
1204 loop t
1377 loop [] t
12051378 | WithType.NoValue ->
1206 if name = None then display_error ctx "Unnamed lvalue functions are not supported" p
1379 if name = None then display_error ctx.com "Unnamed lvalue functions are not supported" p
12071380 | _ ->
12081381 ());
12091382 let ft = TFun (targs,rt) in
12491422 in
12501423 let exprs =
12511424 if is_rec then begin
1252 if inline then display_error ctx "Inline function cannot be recursive" e.epos;
1425 if inline then display_error ctx.com "Inline function cannot be recursive" e.epos;
12531426 (mk (TVar (v,Some (mk (TConst TNull) ft p))) ctx.t.tvoid p) ::
12541427 (mk (TBinop (OpAssign,mk (TLocal v) ft p,e)) ft p) ::
12551428 exprs
1256 end else if inline && not ctx.com.display.dms_display then
1429 end else if inline && not ctx.is_display_file then
12571430 (mk (TBlock []) ctx.t.tvoid p) :: exprs (* do not add variable since it will be inlined *)
12581431 else
12591432 (mk (TVar (v,Some e)) ctx.t.tvoid p) :: exprs
12891462 | Some t -> t :: acc
12901463 )
12911464 []
1292 (get_abstract_froms a pl)
1465 (get_abstract_froms ctx a pl)
12931466 in
12941467 (match types with
12951468 | [t] -> Some t
13111484 let el = List.map (fun e -> type_expr ctx e WithType.value) el in
13121485 let t = try
13131486 unify_min_raise ctx el
1314 with Error (Unify l,p) ->
1315 if !allow_array_dynamic || ctx.untyped || ctx.com.display.dms_error_policy = EPIgnore then
1487 with Error (Unify l,p,n) ->
1488 if !allow_array_dynamic || ctx.untyped || ignore_error ctx.com then
13161489 t_dynamic
13171490 else begin
1318 display_error ctx "Arrays of mixed types are only allowed if the type is forced to Array<Dynamic>" p;
1319 raise (Error (Unify l, p))
1491 display_error ctx.com "Arrays of mixed types are only allowed if the type is forced to Array<Dynamic>" p;
1492 raise (Error (Unify l, p,n))
13201493 end
13211494 in
13221495 mk (TArrayDecl el) (ctx.t.tarray t) p
13231496 | Some t ->
13241497 let el = List.map (fun e ->
13251498 let e = type_expr ctx e (WithType.with_type t) in
1326 AbstractCast.cast_or_unify ctx t e p;
1499 AbstractCast.cast_or_unify ctx t e e.epos;
13271500 ) el in
13281501 mk (TArrayDecl el) (ctx.t.tarray t) p)
13291502
13301503 and type_array_comprehension ctx e with_type p =
13311504 let v = gen_local ctx (spawn_monomorph ctx p) p in
1505 let ev = mk (TLocal v) v.v_type p in
1506 let e_ref = snd (store_typed_expr ctx.com ev p) in
13321507 let et = ref (EConst(Ident "null"),p) in
13331508 let comprehension_pos = p in
13341509 let rec map_compr (e,p) =
13461521 | EParenthesis e2 -> (EParenthesis (map_compr e2),p)
13471522 | EBinop(OpArrow,a,b) ->
13481523 et := (ENew(({tpackage=["haxe";"ds"];tname="Map";tparams=[];tsub=None},null_pos),[]),comprehension_pos);
1349 (ECall ((EField ((EConst (Ident v.v_name),p),"set"),p),[a;b]),p)
1524 (ECall ((efield (e_ref,"set"),p),[a;b]),p)
13501525 | _ ->
13511526 et := (EArrayDecl [],comprehension_pos);
1352 (ECall ((EField ((EConst (Ident v.v_name),p),"push"),p),[(e,p)]),p)
1527 (ECall ((efield (e_ref,"push"),p),[(e,p)]),p)
13531528 in
13541529 let e = map_compr e in
13551530 let ea = type_expr ctx !et with_type in
13581533 mk (TBlock [
13591534 mk (TVar (v,Some ea)) ctx.t.tvoid p;
13601535 efor;
1361 mk (TLocal v) v.v_type p;
1536 ev;
13621537 ]) v.v_type p
13631538
13641539 and type_return ?(implicit=false) ctx e with_type p =
13661541 match e with
13671542 | None when is_abstract_ctor ->
13681543 let e_cast = mk (TCast(get_this ctx p,None)) ctx.ret p in
1369 mk (TReturn (Some e_cast)) t_dynamic p
1544 mk (TReturn (Some e_cast)) (mono_or_dynamic ctx with_type p) p
13701545 | None ->
13711546 let v = ctx.t.tvoid in
13721547 unify ctx v ctx.ret p;
13751550 | WithType.Value (Some ImplicitReturn) -> true
13761551 | _ -> false
13771552 in
1378 mk (TReturn None) (if expect_void then v else t_dynamic) p
1553 mk (TReturn None) (if expect_void then v else (mono_or_dynamic ctx with_type p)) p
13791554 | Some e ->
13801555 if is_abstract_ctor then begin
13811556 match fst e with
13821557 | ECast((EConst(Ident "this"),_),None) -> ()
1383 | _ -> display_error ctx "Cannot return a value from constructor" p
1558 | _ -> display_error ctx.com "Cannot return a value from constructor" p
13841559 end;
13851560 try
13861561 let with_expected_type =
13971572 match follow e.etype with
13981573 | TAbstract({a_path=[],"Void"},_) ->
13991574 begin match (Texpr.skip e).eexpr with
1400 | TConst TNull -> error "Cannot return `null` from Void-function" p
1575 | TConst TNull -> typing_error "Cannot return `null` from Void-function" p
14011576 | _ -> ()
14021577 end;
14031578 (* if we get a Void expression (e.g. from inlining) we don't want to return it (issue #4323) *)
1579 let t = mono_or_dynamic ctx with_type p in
14041580 mk (TBlock [
14051581 e;
1406 mk (TReturn None) t_dynamic p
1407 ]) t_dynamic e.epos;
1582 mk (TReturn None) t p
1583 ]) t e.epos;
14081584 | _ ->
1409 mk (TReturn (Some e)) t_dynamic p
1410 with Error(err,p) ->
1411 check_error ctx err p;
1585 mk (TReturn (Some e)) (mono_or_dynamic ctx with_type p) p
1586 with Error(err,p,depth) ->
1587 check_error ctx err p depth;
14121588 (* If we have a bad return, let's generate a return null expression at least. This surpresses various
14131589 follow-up errors that come from the fact that the function no longer has a return expression (issue #6445). *)
14141590 let e_null = mk (TConst TNull) (mk_mono()) p in
1415 mk (TReturn (Some e_null)) t_dynamic p
1591 mk (TReturn (Some e_null)) (mono_or_dynamic ctx with_type p) p
14161592
14171593 and type_cast ctx e t p =
14181594 let tpos = pos t in
14201596 let check_param pt = match follow pt with
14211597 | TMono _ -> () (* This probably means that Dynamic wasn't bound (issue #4675). *)
14221598 | t when t == t_dynamic -> ()
1423 | _ -> error "Cast type parameters must be Dynamic" tpos
1599 | _ -> typing_error "Cast type parameters must be Dynamic" tpos
14241600 in
14251601 let rec loop t = match follow t with
14261602 | TInst (_,params) | TEnum (_,params) ->
14271603 List.iter check_param params;
14281604 (match follow t with
14291605 | TInst (c,_) ->
1430 (match c.cl_kind with KTypeParameter _ -> error "Can't cast to a type parameter" tpos | _ -> ());
1606 (match c.cl_kind with KTypeParameter _ -> typing_error "Can't cast to a type parameter" tpos | _ -> ());
14311607 TClassDecl c
14321608 | TEnum (e,_) -> TEnumDecl e
14331609 | _ -> die "" __LOC__);
14371613 | TAbstract (a,params) ->
14381614 loop (Abstract.get_underlying_type a params)
14391615 | _ ->
1440 error "Cast type must be a class or an enum" tpos
1616 typing_error "Cast type must be a class or an enum" tpos
14411617 in
14421618 let texpr = loop t in
14431619 mk (TCast (type_expr ctx e WithType.value,Some texpr)) t p
14441620
1445 and type_if ctx e e1 e2 with_type p =
1621 and make_if_then_else ctx e0 e1 e2 with_type p =
1622 let e1,e2,t = match with_type with
1623 | WithType.NoValue -> e1,e2,ctx.t.tvoid
1624 | WithType.Value _ -> e1,e2,unify_min ctx [e1; e2]
1625 | WithType.WithType(t,src) when (match follow t with TMono _ -> true | t -> ExtType.is_void t) ->
1626 e1,e2,unify_min_for_type_source ctx [e1; e2] src
1627 | WithType.WithType(t,_) ->
1628 let e1 = AbstractCast.cast_or_unify ctx t e1 e1.epos in
1629 let e2 = AbstractCast.cast_or_unify ctx t e2 e2.epos in
1630 e1,e2,t
1631 in
1632 mk (TIf (e0,e1,Some e2)) t p
1633
1634 and type_if ctx e e1 e2 with_type is_ternary p =
14461635 let e = type_expr ctx e WithType.value in
1636 if is_ternary then begin match e.eexpr with
1637 | TConst TNull -> typing_error "Cannot use null as ternary condition" e.epos
1638 | _ -> ()
1639 end;
14471640 let e = AbstractCast.cast_or_unify ctx ctx.t.tbool e p in
14481641 let e1 = type_expr ctx (Expr.ensure_block e1) with_type in
1449 (match e2 with
1642 match e2 with
14501643 | None ->
14511644 mk (TIf (e,e1,None)) ctx.t.tvoid p
14521645 | Some e2 ->
14531646 let e2 = type_expr ctx (Expr.ensure_block e2) with_type in
1454 let e1,e2,t = match with_type with
1455 | WithType.NoValue -> e1,e2,ctx.t.tvoid
1456 | WithType.Value _ -> e1,e2,unify_min ctx [e1; e2]
1457 | WithType.WithType(t,src) when (match follow t with TMono _ -> true | t -> ExtType.is_void t) ->
1458 e1,e2,unify_min_for_type_source ctx [e1; e2] src
1459 | WithType.WithType(t,_) ->
1460 let e1 = AbstractCast.cast_or_unify ctx t e1 e1.epos in
1461 let e2 = AbstractCast.cast_or_unify ctx t e2 e2.epos in
1462 e1,e2,t
1463 in
1464 mk (TIf (e,e1,Some e2)) t p)
1647 make_if_then_else ctx e e1 e2 with_type p
14651648
14661649 and type_meta ?(mode=MGet) ctx m e1 with_type p =
14671650 if ctx.is_display_file then DisplayEmitter.check_display_metadata ctx [m];
14751658 | TAbstract({a_impl = Some c},_) when PMap.mem "toString" c.cl_statics -> call_to_string ctx e
14761659 | _ -> e)
14771660 | (Meta.Markup,_,_) ->
1478 error "Markup literals must be processed by a macro" p
1479 | (Meta.This,_,_) ->
1480 let e = match ctx.this_stack with
1481 | [] -> error "Cannot type @:this this here" p
1482 | e :: _ -> e
1483 in
1484 let rec loop e = match e.eexpr with
1485 | TConst TThis -> get_this ctx e.epos
1486 | _ -> Type.map_expr loop e
1487 in
1488 loop e
1661 typing_error "Markup literals must be processed by a macro" p
14891662 | (Meta.Analyzer,_,_) ->
14901663 let e = e() in
14911664 {e with eexpr = TMeta(m,e)}
15111684 let old_counter = ctx.bypass_accessor in
15121685 ctx.bypass_accessor <- old_counter + 1;
15131686 let e = e () in
1514 (if ctx.bypass_accessor > old_counter then display_error ctx "Field access expression expected after @:bypassAccessor metadata" p);
1687 (if ctx.bypass_accessor > old_counter then display_error ctx.com "Field access expression expected after @:bypassAccessor metadata" p);
15151688 e
1516 | (Meta.Inline,_,_) ->
1689 | (Meta.Inline,_,pinline) ->
15171690 begin match fst e1 with
15181691 | ECall(e1,el) ->
1519 type_call ctx e1 el WithType.value true p
1692 acc_get ctx (type_call_access ctx e1 el MGet WithType.value (Some pinline) p)
15201693 | ENew (t,el) ->
15211694 let e = type_new ctx t el with_type true p in
15221695 {e with eexpr = TMeta((Meta.Inline,[],null_pos),e)}
15231696 | _ ->
1524 display_error ctx "Call or function expected after inline keyword" p;
1697 display_error ctx.com "Call or function expected after inline keyword" p;
15251698 e();
15261699 end
15271700 | (Meta.ImplicitReturn,_,_) ->
15291702 | (EReturn e, p) -> type_return ~implicit:true ctx e with_type p
15301703 | _ -> e()
15311704 end
1532 | _ -> e()
1705 | (Meta.Dollar s,_,p) ->
1706 display_error ctx.com (Printf.sprintf "Reification $%s is not allowed outside of `macro` expression" s) p;
1707 e()
1708 | _ ->
1709 if ctx.g.retain_meta then
1710 let e = e() in
1711 {e with eexpr = TMeta(m,e)}
1712 else
1713 e()
15331714 in
15341715 ctx.meta <- old;
15351716 e
15361717
1537 and type_call_target ctx e el with_type inline p =
1538 let e = maybe_type_against_enum ctx (fun () -> type_access ctx (fst e) (snd e) (MCall el) with_type) with_type true p in
1539 let check_inline cf =
1540 if (has_class_field_flag cf CfAbstract) then display_error ctx "Cannot force inline on abstract method" p
1541 in
1542 if not inline then
1718 and type_call_target ctx e el with_type p_inline =
1719 let p = (pos e) in
1720 let e = maybe_type_against_enum ctx (fun () -> type_access ctx (fst e) (snd e) (MCall el) WithType.value) with_type true p in
1721 let check_inline cf p =
1722 if (has_class_field_flag cf CfAbstract) then display_error ctx.com "Cannot force inline on abstract method" p
1723 in
1724 match p_inline with
1725 | None ->
15431726 e
1544 else match e with
1545 | AKField fa ->
1546 check_inline fa.fa_field;
1547 AKField({fa with fa_inline = true})
1548 | AKUsingField sea ->
1549 check_inline sea.se_access.fa_field;
1550 AKUsingField {sea with se_access = {sea.se_access with fa_inline = true}}
1551 | AKExpr {eexpr = TLocal _} ->
1552 display_error ctx "Cannot force inline on local functions" p;
1553 e
1554 | _ ->
1555 e
1556
1557 and type_call ?(mode=MGet) ctx e el (with_type:WithType.t) inline p =
1558 let def () =
1559 let e = type_call_target ctx e el with_type inline p in
1560 build_call ~mode ctx e el with_type p;
1561 in
1727 | Some pinline ->
1728 let rec loop e =
1729 match e with
1730 | AKSafeNav sn ->
1731 AKSafeNav { sn with sn_access = loop sn.sn_access }
1732 | AKField fa ->
1733 check_inline fa.fa_field pinline;
1734 AKField({fa with fa_inline = true})
1735 | AKUsingField sea ->
1736 check_inline sea.se_access.fa_field pinline;
1737 AKUsingField {sea with se_access = {sea.se_access with fa_inline = true}}
1738 | AKExpr {eexpr = TLocal _} ->
1739 display_error ctx.com "Cannot force inline on local functions" pinline;
1740 e
1741 | _ ->
1742 e
1743 in
1744 loop e
1745
1746 and type_call_access ctx e el mode with_type p_inline p =
1747 try
1748 let e = type_call_builtin ctx e el mode with_type p in
1749 AKExpr e
1750 with Exit ->
1751 let acc = type_call_target ctx e el with_type p_inline in
1752 build_call_access ctx acc el mode with_type p
1753
1754 and type_call_builtin ctx e el mode with_type p =
15621755 match e, el with
15631756 | (EConst (Ident "trace"),p) , e :: el ->
15641757 if Common.defined ctx.com Define.NoTraces then
15791772 let e_trace = mk (TIdent "`trace") t_dynamic p in
15801773 mk (TCall (e_trace,[e;infos])) ctx.t.tvoid p
15811774 else
1582 type_expr ctx (ECall ((EField ((EField ((EConst (Ident "haxe"),p),"Log"),p),"trace"),p),[mk_to_string_meta e;infos]),p) WithType.NoValue
1583 | (EField ((EConst (Ident "super"),_),_),_), _ ->
1584 (match def() with
1585 | { eexpr = TCall ({ eexpr = TField (_, FInstance(_, _, { cf_kind = Method MethDynamic; cf_name = name })); epos = p }, _) } as e ->
1586 ctx.com.error ("Cannot call super." ^ name ^ " since it's a dynamic method") p;
1587 e
1588 | e -> e
1589 )
1590 | (EField (e,"bind"),p), args ->
1775 type_expr ctx (ECall ((efield ((efield ((EConst (Ident "haxe"),p),"Log"),p),"trace"),p),[mk_to_string_meta e;infos]),p) WithType.NoValue
1776 | (EField ((EConst (Ident "super"),_),_,_),_), _ ->
1777 (* no builtins can be applied to super as it can't be a value *)
1778 raise Exit
1779 | (EField (e,"bind",efk_todo),p), args ->
15911780 let e = type_expr ctx e WithType.value in
15921781 (match follow e.etype with
15931782 | TFun signature -> type_bind ctx e signature args p
1594 | _ -> def ())
1783 | _ -> raise Exit)
15951784 | (EConst (Ident "$type"),_) , [e] ->
1596 let e = type_expr ctx e WithType.value in
1597 ctx.com.warning (s_type (print_context()) e.etype) e.epos;
1598 let e = Diagnostics.secure_generated_code ctx e in
1599 e
1600 | (EField(e,"match"),p), [epat] ->
1785 begin match fst e with
1786 | EConst (Ident "_") ->
1787 warning ctx WInfo (WithType.to_string with_type) p;
1788 mk (TConst TNull) t_dynamic p
1789 | _ ->
1790 let e = type_expr ctx e WithType.value in
1791 warning ctx WInfo (s_type (print_context()) e.etype) e.epos;
1792 let e = Diagnostics.secure_generated_code ctx e in
1793 e
1794 end
1795 | (EField(e,"match",efk_todo),p), [epat] ->
16011796 let et = type_expr ctx e WithType.value in
16021797 let rec has_enum_match t = match follow t with
16031798 | TEnum _ -> true
16101805 if has_enum_match et.etype then
16111806 Matcher.Match.match_expr ctx e [[epat],None,Some (EConst(Ident "true"),p),p] (Some (Some (EConst(Ident "false"),p),p)) (WithType.with_type ctx.t.tbool) true p
16121807 else
1613 def ()
1808 raise Exit
16141809 | (EConst (Ident "__unprotect__"),_) , [(EConst (String _),_) as e] ->
16151810 let e = type_expr ctx e WithType.value in
16161811 if Common.platform ctx.com Flash then
16221817 | (EDisplay((EConst (Ident "super"),_ as e1),dk),_),_ ->
16231818 TyperDisplay.handle_display ctx (ECall(e1,el),p) dk mode with_type
16241819 | (EConst (Ident "super"),sp) , el ->
1625 if ctx.curfun <> FunConstructor then error "Cannot call super constructor outside class constructor" p;
1820 if ctx.curfun <> FunConstructor then typing_error "Cannot call super constructor outside class constructor" p;
16261821 let el, t = (match ctx.curclass.cl_super with
1627 | None -> error "Current class does not have a super" p
1822 | None -> typing_error "Current class does not have a super" p
16281823 | Some (c,params) ->
16291824 let fa = FieldAccess.get_constructor_access c params p in
16301825 let cf = fa.fa_field in
16311826 let t = TInst (c,params) in
16321827 let e = mk (TConst TSuper) t sp in
1633 if (Meta.has Meta.CompilerGenerated cf.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p;
1828 if (Meta.has Meta.CompilerGenerated cf.cf_meta) then located_display_error ctx.com (error_msg p (No_constructor (TClassDecl c)));
16341829 let fa = FieldAccess.create e cf (FHInstance(c,params)) false p in
16351830 let fcc = unify_field_call ctx fa [] el p false in
16361831 let el = fcc.fc_args in
16381833 ) in
16391834 mk (TCall (mk (TConst TSuper) t sp,el)) ctx.t.tvoid p
16401835 | _ ->
1641 def ()
1836 raise Exit
16421837
16431838 and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
16441839 match e with
1645 | EField ((EConst (String(s,_)),ps),"code") ->
1646 if UTF8.length s <> 1 then error "String must be a single UTF8 char" ps;
1840 | EField ((EConst (String(s,_)),ps),"code",EFNormal) ->
1841 if UTF8.length s <> 1 then typing_error "String must be a single UTF8 char" ps;
16471842 mk (TConst (TInt (Int32.of_int (UCharExt.code (UTF8.get s 0))))) ctx.t.tint p
1648 | EField(_,n) when starts_with n '$' ->
1649 error "Field names starting with $ are not allowed" p
1843 | EField(_,n,_) when starts_with n '$' ->
1844 typing_error "Field names starting with $ are not allowed" p
16501845 | EConst (Ident s) ->
1651 if s = "super" && with_type <> WithType.NoValue && not ctx.in_display then error "Cannot use super as value" p;
1846 if s = "super" && with_type <> WithType.NoValue && not ctx.in_display then typing_error "Cannot use super as value" p;
16521847 let e = maybe_type_against_enum ctx (fun () -> type_ident ctx s p mode with_type) with_type false p in
1653 acc_get ctx e p
1848 acc_get ctx e
16541849 | EField _
1655 | EArray _ ->
1656 acc_get ctx (type_access ctx e p mode with_type) p
1850 | EArray _
1851 | ECall _ ->
1852 acc_get ctx (type_access ctx e p mode with_type)
16571853 | EConst (Regexp (r,opt)) ->
16581854 let str = mk (TConst (TString r)) ctx.t.tstring p in
16591855 let opt = mk (TConst (TString opt)) ctx.t.tstring p in
16611857 mk (TNew ((match t with TInst (c,[]) -> c | _ -> die "" __LOC__),[],[str;opt])) t p
16621858 | EConst (String(s,SSingleQuotes)) when s <> "" ->
16631859 type_expr ctx (format_string ctx s p) with_type
1860 | EConst (Int (s, Some suffix)) ->
1861 (match suffix with
1862 | "i32" ->
1863 (try mk (TConst (TInt (Int32.of_string s))) ctx.com.basic.tint p
1864 with _ -> typing_error ("Cannot represent " ^ s ^ " with a 32 bit integer") p)
1865 | "i64" ->
1866 if String.length s > 18 && String.sub s 0 2 = "0x" then typing_error "Invalid hexadecimal integer" p;
1867
1868 let i64 = Int64.of_string s in
1869 let high = Int64.to_int32 (Int64.shift_right i64 32) in
1870 let low = Int64.to_int32 i64 in
1871
1872 let ident = EConst (Ident "haxe"), p in
1873 let field = efield ((efield (ident, "Int64"), p), "make"), p in
1874
1875 let arg_high = EConst (Int (Int32.to_string high, None)), p in
1876 let arg_low = EConst (Int (Int32.to_string low, None)), p in
1877 let call = ECall (field, [ arg_high; arg_low ]), p in
1878 type_expr ctx call with_type
1879 | "u32" ->
1880 let check = ECheckType ((EConst (Int (s, None)), p), (CTPath (mk_type_path ([],"UInt")), p)), p in
1881 type_expr ctx check with_type
1882 | other -> typing_error (other ^ " is not a valid integer suffix") p)
1883 | EConst (Float (s, Some suffix) as c) ->
1884 (match suffix with
1885 | "f64" -> Texpr.type_constant ctx.com.basic c p
1886 | other -> typing_error (other ^ " is not a valid float suffix") p)
16641887 | EConst c ->
16651888 Texpr.type_constant ctx.com.basic c p
1889 | EBinop (OpNullCoal,e1,e2) ->
1890 let vr = new value_reference ctx in
1891 let e1 = type_expr ctx (Expr.ensure_block e1) with_type in
1892 let e2 = type_expr ctx (Expr.ensure_block e2) (WithType.with_type e1.etype) in
1893 let e1 = vr#as_var "tmp" {e1 with etype = ctx.t.tnull e1.etype} in
1894 let e_null = Builder.make_null e1.etype e1.epos in
1895 let e_cond = mk (TBinop(OpNotEq,e1,e_null)) ctx.t.tbool e1.epos in
1896
1897 let follow_null_once t =
1898 match t with
1899 | TAbstract({a_path = [],"Null"},[t]) -> t
1900 | _ -> t
1901 in
1902 let iftype = if DeadEnd.has_dead_end e2 then
1903 WithType.with_type (follow_null_once e1.etype)
1904 else
1905 WithType.WithType(e2.etype,None)
1906 in
1907 let e_if = make_if_then_else ctx e_cond e1 e2 iftype p in
1908 vr#to_texpr e_if
1909 | EBinop (OpAssignOp OpNullCoal,e1,e2) ->
1910 let e_cond = EBinop(OpNotEq,e1,(EConst(Ident "null"), p)) in
1911 let e_if = EIf ((e_cond, p),e1,Some e2) in
1912 type_assign ctx e1 (e_if, p) with_type p
16661913 | EBinop (op,e1,e2) ->
16671914 type_binop ctx op e1 e2 false with_type p
16681915 | EBlock [] when (match with_type with
17141961 | EFor (it,e2) ->
17151962 ForLoop.type_for_loop ctx TyperDisplay.handle_display it e2 p
17161963 | ETernary (e1,e2,e3) ->
1717 type_expr ctx (EIf (e1,e2,Some e3),p) with_type
1964 type_if ctx e1 e2 (Some e3) with_type true p
17181965 | EIf (e,e1,e2) ->
1719 type_if ctx e e1 e2 with_type p
1966 type_if ctx e e1 e2 with_type false p
17201967 | EWhile (cond,e,NormalWhile) ->
17211968 let old_loop = ctx.in_loop in
17221969 let cond = type_expr ctx cond WithType.value in
17391986 wrap e
17401987 | EReturn e ->
17411988 if not ctx.in_function then begin
1742 display_error ctx "Return outside function" p;
1989 display_error ctx.com "Return outside function" p;
17431990 match e with
17441991 | None ->
1745 Texpr.Builder.make_null t_dynamic p
1992 Texpr.Builder.make_null (mono_or_dynamic ctx with_type p) p
17461993 | Some e ->
17471994 (* type the return expression to see if there are more errors
17481995 as well as use its type as if there was no `return`, since
17511998 end else
17521999 type_return ctx e with_type p
17532000 | EBreak ->
1754 if not ctx.in_loop then display_error ctx "Break outside loop" p;
1755 mk TBreak t_dynamic p
2001 if not ctx.in_loop then display_error ctx.com "Break outside loop" p;
2002 mk TBreak (mono_or_dynamic ctx with_type p) p
17562003 | EContinue ->
1757 if not ctx.in_loop then display_error ctx "Continue outside loop" p;
1758 mk TContinue t_dynamic p
2004 if not ctx.in_loop then display_error ctx.com "Continue outside loop" p;
2005 mk TContinue (mono_or_dynamic ctx with_type p) p
17592006 | ETry (e1,[]) ->
17602007 type_expr ctx e1 with_type
17612008 | ETry (e1,catches) ->
17622009 type_try ctx e1 catches with_type p
17632010 | EThrow e ->
1764 let e = type_expr ctx e WithType.value in
1765 mk (TThrow e) (spawn_monomorph ctx p) p
1766 | ECall (e,el) ->
1767 type_call ~mode ctx e el with_type false p
2011 let e = try
2012 type_expr ctx e WithType.value
2013 with Error(e,p',depth) ->
2014 check_error ctx e p' depth;
2015 Texpr.Builder.make_null t_dynamic p
2016 in
2017 mk (TThrow e) (mono_or_dynamic ctx with_type p) p
17682018 | ENew (t,el) ->
17692019 type_new ctx t el with_type false p
17702020 | EUnop (op,flag,e) ->
17892039 type_cast ctx e t p
17902040 | EDisplay (e,dk) ->
17912041 TyperDisplay.handle_edisplay ctx e dk mode with_type
1792 | EDisplayNew t ->
1793 die "" __LOC__
17942042 | ECheckType (e,t) ->
17952043 let t = Typeload.load_complex_type ctx true t in
17962044 let e = type_expr ctx e (WithType.with_type t) in
18012049 | EIs (e,(t,p_t)) ->
18022050 match t with
18032051 | CTPath tp ->
1804 if tp.tparams <> [] then display_error ctx "Type parameters are not supported for the `is` operator" p_t;
2052 if tp.tparams <> [] then display_error ctx.com "Type parameters are not supported for the `is` operator" p_t;
18052053 let e = type_expr ctx e WithType.value in
18062054 let mt = Typeload.load_type_def ctx p_t tp in
18072055 if ctx.in_display && DisplayPosition.display_position#enclosed_in p_t then
18192067 in
18202068 mk (TCall (e_Std_isOfType, [e; e_t])) ctx.com.basic.tbool p
18212069 | _ ->
1822 display_error ctx "Unsupported type for `is` operator" p_t;
2070 display_error ctx.com "Unsupported type for `is` operator" p_t;
18232071 Texpr.Builder.make_bool ctx.com.basic false p
18242072
18252073 (* ---------------------------------------------------------------------- *)
18322080 g = {
18332081 core_api = None;
18342082 macros = None;
1835 modules = Hashtbl.create 0;
1836 types_module = Hashtbl.create 0;
18372083 type_patches = Hashtbl.create 0;
18382084 global_metadata = [];
18392085 module_check_policies = [];
18402086 delayed = [];
18412087 debug_delayed = [];
18422088 doinline = com.display.dms_inline && not (Common.defined com Define.NoInline);
1843 hook_generate = [];
2089 retain_meta = Common.defined com Define.RetainUntypedMeta;
18442090 std = null_module;
18452091 global_using = [];
18462092 complete = false;
18472093 type_hints = [];
2094 load_only_cached_modules = false;
2095 functional_interface_lut = new pmap_lookup;
18482096 do_inherit = MagicTypes.on_inherit;
18492097 do_create = create;
18502098 do_macro = MacroContext.type_macro;
18512099 do_load_macro = MacroContext.load_macro';
18522100 do_load_module = TypeloadModule.load_module;
18532101 do_load_type_def = Typeload.load_type_def;
1854 do_optimize = Optimizer.reduce_expression;
18552102 do_build_instance = InstanceBuilder.build_instance;
18562103 do_format_string = format_string;
1857 do_finalize = Finalization.finalize;
1858 do_generate = Finalization.generate;
18592104 do_load_core_class = Typeload.load_core_class;
18602105 };
18612106 m = {
18622107 curmod = null_module;
1863 module_types = [];
2108 module_imports = [];
18642109 module_using = [];
18652110 module_globals = PMap.empty;
18662111 wildcard_packages = [];
1867 module_imports = [];
2112 import_statements = [];
18682113 };
18692114 is_display_file = false;
18702115 bypass_accessor = 0;
18712116 meta = [];
1872 this_stack = [];
18732117 with_type_stack = [];
18742118 call_argument_stack = [];
18752119 pass = PBuildModule;
18792123 in_function = false;
18802124 in_loop = false;
18812125 in_display = false;
2126 allow_inline = true;
2127 allow_transform = true;
18822128 get_build_infos = (fun() -> None);
1883 in_macro = Common.defined com Define.Macro;
18842129 ret = mk_mono();
18852130 locals = PMap.empty;
18862131 type_params = [];
18952140 monomorphs = {
18962141 perfunction = [];
18972142 };
1898 on_error = (fun ctx msg p -> ctx.com.error msg p);
18992143 memory_marker = Typecore.memory_marker;
19002144 } in
19012145 ctx.g.std <- (try
19022146 TypeloadModule.load_module ctx ([],"StdTypes") null_pos
19032147 with
1904 Error (Module_not_found ([],"StdTypes"),_) ->
2148 Error (Module_not_found ([],"StdTypes"),_,_) ->
19052149 try
19062150 let std_path = Sys.getenv "HAXE_STD_PATH" in
1907 error ("Standard library not found. Please check your `HAXE_STD_PATH` environment variable (current value: \"" ^ std_path ^ "\")") null_pos
2151 typing_error ("Standard library not found. Please check your `HAXE_STD_PATH` environment variable (current value: \"" ^ std_path ^ "\")") null_pos
19082152 with Not_found ->
1909 error "Standard library not found. You may need to set your `HAXE_STD_PATH` environment variable" null_pos
2153 typing_error "Standard library not found. You may need to set your `HAXE_STD_PATH` environment variable" null_pos
19102154 );
19112155 (* We always want core types to be available so we add them as default imports (issue #1904 and #3131). *)
1912 ctx.m.module_types <- List.map (fun t -> t,null_pos) ctx.g.std.m_types;
2156 ctx.m.module_imports <- List.map (fun t -> t,null_pos) ctx.g.std.m_types;
19132157 List.iter (fun t ->
19142158 match t with
19152159 | TAbstractDecl a ->
19182162 | "Float" -> ctx.t.tfloat <- TAbstract (a,[]);
19192163 | "Int" -> ctx.t.tint <- TAbstract (a,[])
19202164 | "Bool" -> ctx.t.tbool <- TAbstract (a,[])
1921 | "Dynamic" -> t_dynamic_def := TAbstract(a,List.map snd a.a_params);
2165 | "Dynamic" -> t_dynamic_def := TAbstract(a,extract_param_types a.a_params);
19222166 | "Null" ->
19232167 let mk_null t =
19242168 try
19732217 make_call_ref := make_call;
19742218 type_call_target_ref := type_call_target;
19752219 type_access_ref := type_access;
1976 type_block_ref := type_block
2220 type_block_ref := type_block;
55
66 type access_kind =
77 (* Access is not possible or allowed. *)
8 | AKNo of string
8 | AKNo of access_kind * pos
99 (* Access on arbitrary expression. *)
1010 | AKExpr of texpr
11 (* Safe navigation access chain *)
12 | AKSafeNav of safe_nav_access
1113 (* Access on non-property field. *)
1214 | AKField of field_access
1315 (* Access on property field. The field is the property, not the accessor. *)
2224 (* Access on abstract via resolve method. *)
2325 | AKResolve of static_extension_access * string
2426
27 and safe_nav_access = {
28 (* position of the safe navigation chain start (the initial ?.field expression) *)
29 sn_pos : pos;
30 (* starting value to be checked for null *)
31 sn_base : texpr;
32 (* temp var declaration to store complex base expression *)
33 sn_temp_var : texpr option;
34 (* safe navigation access to be done if the base value is not null *)
35 sn_access : access_kind;
36 }
37
2538 type object_decl_kind =
2639 | ODKWithStructure of tanon
2740 | ODKWithClass of tclass * tparams
2841 | ODKPlain
29
30 let type_call_target_ref : (typer -> expr -> expr list -> WithType.t -> bool -> pos -> access_kind) ref = ref (fun _ _ _ _ _ -> die "" __LOC__)
42 | ODKFailed
43
44 module MetaConfig = struct
45
46 let as_bool e = match fst e with
47 | EConst (Ident "true") -> true
48 | EConst (Ident "false") -> false
49 | _ -> raise (Invalid_argument "bool")
50
51 let read_arg_config meta f l =
52 List.iter (fun (meta',el,_) ->
53 if meta' = meta then
54 List.iter (fun e -> match fst e with
55 | EConst (Ident s) ->
56 f (s,((EConst (Ident "true"),null_pos)))
57 | EBinop(OpAssign,(EConst (Ident s),_),e2) ->
58 f (s, e2)
59 | _ ->
60 ()
61 ) el
62 ) l
63 end
64
65 module AbstractFromConfig = struct
66 type t = {
67 mutable ignored_by_inference : bool;
68 }
69
70 let make () = {
71 ignored_by_inference = false;
72 }
73
74 let update_config_from_meta config ml =
75 MetaConfig.read_arg_config Meta.From (fun (s,e) -> match s with
76 | "ignoredByInference" ->
77 begin try
78 config.ignored_by_inference <- MetaConfig.as_bool e
79 with Invalid_argument _ ->
80 ()
81 end
82 | _ ->
83 ()
84 ) ml;
85 config
86 end
87
88 let type_call_target_ref : (typer -> expr -> expr list -> WithType.t -> pos option -> access_kind) ref = ref (fun _ _ _ _ -> die "" __LOC__)
3189 let type_access_ref : (typer -> expr_def -> pos -> access_mode -> WithType.t -> access_kind) ref = ref (fun _ _ _ _ _ -> assert false)
90
91 class value_reference (ctx : typer) =
92
93 object(self)
94 val vars = DynArray.create ()
95
96 method get_vars = DynArray.to_list vars
97
98 method as_var name e =
99 let v = alloc_var VGenerated name e.etype e.epos in
100 DynArray.add vars (v,e);
101 mk (TLocal v) v.v_type v.v_pos
102
103 method private get_expr_aux depth name e =
104 let rec loop depth name e = match (Texpr.skip e).eexpr with
105 | TLocal _ | TTypeExpr _ | TConst _ ->
106 e
107 | TField(ef,fa) when depth = 0 ->
108 let ef = loop (depth + 1) "fh" ef in
109 {e with eexpr = TField(ef,fa)}
110 | TArray(e1,e2) when depth = 0 ->
111 let e1 = loop (depth + 1) "base" e1 in
112 let e2 = loop (depth + 1) "index" e2 in
113 {e with eexpr = TArray(e1,e2)}
114 | _ ->
115 self#as_var name e
116 in
117 loop depth name e
118
119 method get_expr name e =
120 self#get_expr_aux 0 name e
121
122 method get_expr_part name e =
123 self#get_expr_aux 1 name e
124
125 method to_texpr e =
126 begin match self#get_vars with
127 | [] ->
128 e
129 | vl ->
130 let el = List.map (fun (v,e) ->
131 mk (TVar(v,Some e)) ctx.t.tvoid v.v_pos
132 ) vl in
133 let e = mk (TBlock (el @ [e])) e.etype e.epos in
134 {e with eexpr = TMeta((Meta.MergeBlock,[],null_pos),e)}
135 end
136
137 method to_texpr_el el e =
138 let vl = self#get_vars in
139 let el_vars = List.map (fun (v,e) ->
140 mk (TVar(v,Some e)) ctx.t.tvoid v.v_pos
141 ) vl in
142 let e = mk (TBlock (el_vars @ el @ [e])) e.etype e.epos in
143 {e with eexpr = TMeta((Meta.MergeBlock,[],null_pos),e)}
144 end
32145
33146 let is_lower_ident s p =
34147 try Ast.is_lower_ident s
35 with Invalid_argument msg -> error msg p
148 with Invalid_argument msg -> typing_error msg p
36149
37150 let get_this ctx p =
38151 match ctx.curfun with
39152 | FunStatic ->
40 error "Cannot access this from a static function" p
153 typing_error "Cannot access this from a static function" p
41154 | FunMemberClassLocal | FunMemberAbstractLocal ->
42155 let v = match ctx.vthis with
43156 | None ->
54167 in
55168 mk (TLocal v) ctx.tthis p
56169 | FunMemberAbstract ->
57 let v = (try PMap.find "this" ctx.locals with Not_found -> die "" __LOC__) in
170 let v = (try PMap.find "this" ctx.locals with Not_found -> typing_error "Cannot reference this abstract here" p) in
58171 mk (TLocal v) v.v_type p
59172 | FunConstructor | FunMember ->
60173 mk (TConst TThis) ctx.tthis p
78191 module_type_of_type t
79192 with Exit ->
80193 if follow t == t_dynamic then Typeload.load_type_def ctx p (mk_type_path ([],"Dynamic"))
81 else error "Invalid module type" p
194 else typing_error "Invalid module type" p
82195 in
83196 type_module_type ctx mt None p
84197 | TClassDecl c ->
88201 let types = (match tparams with None -> Monomorph.spawn_constrained_monos (fun t -> t) e.e_params | Some l -> l) in
89202 mk (TTypeExpr (TEnumDecl e)) (TType (e.e_type,types)) p
90203 | TTypeDecl s ->
91 let t = apply_params s.t_params (List.map (fun _ -> spawn_monomorph ctx p) s.t_params) s.t_type in
204 let t = apply_typedef s (List.map (fun _ -> spawn_monomorph ctx p) s.t_params) in
92205 DeprecationCheck.check_typedef ctx.com s p;
93206 (match follow t with
94207 | TEnum (e,params) ->
98211 | TAbstract (a,params) ->
99212 type_module_type ctx (TAbstractDecl a) (Some params) p
100213 | _ ->
101 error (s_type_path s.t_path ^ " is not a value") p)
214 typing_error (s_type_path s.t_path ^ " is not a value") p)
102215 | TAbstractDecl { a_impl = Some c } ->
103216 type_module_type ctx (TClassDecl c) tparams p
104217 | TAbstractDecl a ->
105 if not (Meta.has Meta.RuntimeValue a.a_meta) then error (s_type_path a.a_path ^ " is not a value") p;
218 if not (Meta.has Meta.RuntimeValue a.a_meta) then typing_error (s_type_path a.a_path ^ " is not a value") p;
106219 let t_tmp = abstract_module_type a [] in
107220 mk (TTypeExpr (TAbstractDecl a)) (TType (t_tmp,[])) p
108221
125238 "fa_on",se fa.fa_on;
126239 "fa_field",fa.fa_field.cf_name;
127240 "fa_host",sfa fa.fa_host;
128 "fa_inline",string_of_bool fa.fa_inline
241 "fa_inline",string_of_bool fa.fa_inline;
242 "fa_pos",(Printf.sprintf "%s(%i-%i)" fa.fa_pos.pfile fa.fa_pos.pmin fa.fa_pos.pmax);
129243 ]
130244
131245 let s_static_extension_access sea =
134248 "se_access",s_field_access "\t" sea.se_access
135249 ]
136250
137 let s_access_kind acc =
251 let rec s_access_kind acc =
138252 let st = s_type (print_context()) in
139253 let se = s_expr_pretty true "" false st in
140254 match acc with
141 | AKNo s -> "AKNo " ^ s
255 | AKNo(acc,_) -> "AKNo " ^ (s_access_kind acc)
142256 | AKExpr e -> "AKExpr " ^ (se e)
257 | AKSafeNav sn -> Printf.sprintf "AKSafeNav(%s)" (s_safe_nav_access sn)
143258 | AKField fa -> Printf.sprintf "AKField(%s)" (s_field_access "" fa)
144259 | AKAccessor fa -> Printf.sprintf "AKAccessor(%s)" (s_field_access "" fa)
145260 | AKUsingField sea -> Printf.sprintf "AKUsingField(%s)" (s_static_extension_access sea)
147262 | AKAccess(a,tl,c,e1,e2) -> Printf.sprintf "AKAccess(%s, [%s], %s, %s, %s)" (s_type_path a.a_path) (String.concat ", " (List.map st tl)) (s_type_path c.cl_path) (se e1) (se e2)
148263 | AKResolve(_) -> ""
149264
265 and s_safe_nav_access sn =
266 let st = s_type (print_context()) in
267 let se = s_expr_pretty true "" false st in
268 Printer.s_record_fields "" [
269 "sn_base",se sn.sn_base;
270 "sn_temp_var",Option.map_default (fun e -> "Some " ^ (se e)) "None" sn.sn_temp_var;
271 "sn_access",s_access_kind sn.sn_access
272 ]
273
274 let s_dot_path_part part =
275 Printer.s_record_fields "" [
276 "name",part.name;
277 "case",(match part.case with PUppercase -> "PUppercase" | PLowercase -> "PLowercase");
278 "pos",(Printf.sprintf "%s(%i-%i)" part.pos.pfile part.pos.pmin part.pos.pmax);
279 ]
280
150281 let get_constructible_constraint ctx tl p =
151282 let extract_function t = match follow t with
152283 | TFun(tl,tr) -> tl,tr
153 | _ -> error "Constructible type parameter should be function" p
284 | _ -> typing_error "Constructible type parameter should be function" p
154285 in
155286 let rec loop tl = match tl with
156287 | [] -> None
190321 e
191322 end
192323
193 let get_abstract_froms a pl =
324 let get_abstract_froms ctx a pl =
194325 let l = List.map (apply_params a.a_params pl) a.a_from in
195326 List.fold_left (fun acc (t,f) ->
196 match follow (Type.field_type f) with
327 (* We never want to use the @:from we're currently in because that's recursive (see #10604) *)
328 if f == ctx.curfield then
329 acc
330 else if (AbstractFromConfig.update_config_from_meta (AbstractFromConfig.make ()) f.cf_meta).ignored_by_inference then
331 acc
332 else match follow (Type.field_type f) with
197333 | TFun ([_,_,v],t) ->
198334 (try
199335 ignore(type_eq EqStrict t (TAbstract(a,List.map duplicate pl))); (* unify fields monomorphs *)
4747 let t = tpair e.etype in
4848 make_ci_expr e t
4949 in
50 let was_probably_literal_abstract v t = match follow t with
51 | TAbstract(a,tl) ->
52 type_iseq (Abstract.get_underlying_type a tl) v.v_type
53 | _ ->
54 false
55 in
5056 let rec loop e = match e.eexpr with
57 | TLocal ({v_kind = VAbstractThis} as v) when was_probably_literal_abstract v e.etype ->
58 (* `abstract` is typed as ((this : Underlying) : Abstract), so we detect it like that.
59 This could lead to false positives if somebody really tries, but even in that case
60 the displayed type is not wrong. *)
61 make_ci_literal "abstract" (tpair e.etype)
5162 | TLocal v | TVar(v,_) -> make_ci_local v (tpair ~values:(get_value_meta v.v_meta) v.v_type)
5263 | TField(e1,FStatic(c,cf)) ->
53 let te,c,cf = DisplayToplevel.maybe_resolve_macro_field ctx e.etype c cf in
64 let te,cf = DisplayToplevel.maybe_resolve_macro_field ctx e.etype c cf in
5465 Display.merge_core_doc ctx (TClassDecl c);
5566 let decl = decl_of_class c in
5667 let origin = match c.cl_kind,e1.eexpr with
6475 in
6576 of_field {e with etype = te} origin cf CFSStatic make_ci
6677 | TField(e1,(FInstance(c,_,cf) | FClosure(Some(c,_),cf))) ->
67 let te,c,cf = DisplayToplevel.maybe_resolve_macro_field ctx e.etype c cf in
78 let te,cf = DisplayToplevel.maybe_resolve_macro_field ctx e.etype c cf in
6879 Display.merge_core_doc ctx (TClassDecl c);
6980 let origin = match follow e1.etype with
7081 | TInst(c',_) when c != c' ->
8697 end
8798 | TTypeExpr (TClassDecl {cl_kind = KAbstractImpl a}) ->
8899 Display.merge_core_doc ctx (TAbstractDecl a);
89 let t = TType(abstract_module_type a (List.map snd a.a_params),[]) in
100 let t = TType(abstract_module_type a (extract_param_types a.a_params),[]) in
90101 let t = tpair t in
91102 make_ci_type (CompletionModuleType.of_module_type (TAbstractDecl a)) ImportStatus.Imported (Some t)
92103 | TTypeExpr mt ->
178189 | DMDefinition | DMTypeDefinition ->
179190 raise_positions []
180191 | _ ->
181 error "Unsupported method" p
192 typing_error "Unsupported method" p
182193 end
183194
184195 let rec handle_signature_display ctx e_ast with_type =
188199 let rec follow_with_callable (t,doc,values) = match follow t with
189200 | TAbstract(a,tl) when Meta.has Meta.Callable a.a_meta -> follow_with_callable (Abstract.get_underlying_type a tl,doc,values)
190201 | TFun(args,ret) -> ((args,ret),doc,values)
191 | _ -> error ("Not a callable type: " ^ (s_type (print_context()) t)) p
202 | _ -> typing_error ("Not a callable type: " ^ (s_type (print_context()) t)) p
192203 in
193204 let tl = List.map follow_with_callable tl in
194205 let rec loop i acc el = match el with
211222 let _ = unify_call_args ctx el args r p false false false in
212223 true
213224 with
214 | Error(Call_error (Not_enough_arguments _),_) -> true
225 | Error(Call_error (Not_enough_arguments _),_,_) -> true
215226 | _ -> false
216227 end
217228 in
223234 let overloads = List.map (fun (t,doc,values) -> (convert_function_signature ctx values t,doc)) overloads in
224235 raise_signatures overloads 0 (* ? *) display_arg SKCall
225236 in
237 let process_overloads stat co (map,cf,t) =
238 let is_wacky_overload = not (has_class_field_flag cf CfOverload) in
239 let can_access cf = match co with
240 | Some c -> can_access ctx c cf stat
241 | None -> true
242 in
243 let l = (t,cf) :: List.rev_map (fun cf -> map cf.cf_type,cf) cf.cf_overloads in
244 let l = List.filter (fun (_,cf) -> can_access cf) l in
245 let l = List.map (fun (t,cf') ->
246 (* Ghetto overloads have their documentation on the main field. *)
247 let doc = if is_wacky_overload then cf.cf_doc else cf'.cf_doc in
248 (t,doc,get_value_meta cf.cf_meta)
249 ) l in
250 l
251 in
226252 let find_constructor_types t = match follow t with
227253 | TInst ({cl_kind = KTypeParameter tl} as c,_) ->
228254 let rec loop tl = match tl with
229 | [] -> raise_error (No_constructor (TClassDecl c)) p
255 | [] -> raise_typing_error (No_constructor (TClassDecl c)) p
230256 | t :: tl -> match follow t with
231257 | TAbstract({a_path = ["haxe"],"Constructible"},[t]) -> t
232258 | _ -> loop tl
235261 | TInst (c,tl) | TAbstract({a_impl = Some c},tl) ->
236262 Display.merge_core_doc ctx (TClassDecl c);
237263 let fa = get_constructor_access c tl p in
238 let is_wacky_overload = not (has_class_field_flag fa.fa_field CfOverload) in
239264 let map = FieldAccess.get_map_function fa in
240 let map_cf cf =
241 (* Ghetto overloads have their documentation on the main field. *)
242 let doc = if is_wacky_overload then fa.fa_field.cf_doc else cf.cf_doc in
243 map cf.cf_type,doc,get_value_meta cf.cf_meta
244 in
245 List.map map_cf (fa.fa_field :: fa.fa_field.cf_overloads)
265 let cf = fa.fa_field in
266 process_overloads false (Some c) (map,cf,cf.cf_type)
246267 | _ ->
247268 []
248269 in
250271 | ECall(e1,el) ->
251272 let def () =
252273 try
253 acc_get ctx (!type_call_target_ref ctx e1 el with_type false (pos e1)) (pos e1)
274 acc_get ctx (!type_call_target_ref ctx e1 el with_type None)
254275 with
255 | Error (Unknown_ident "trace",_) ->
276 | Error (Unknown_ident "trace",_,_) ->
256277 let e = expr_of_type_path (["haxe";"Log"],"trace") p in
257278 type_expr ctx e WithType.value
258 | Error (Unknown_ident "$type",p) ->
279 | Error (Unknown_ident "$type",p,_) ->
259280 display_dollar_type ctx p (fun t -> t,(CompletionType.from_type (get_import_status ctx) t))
260281 in
261282 let e1 = match e1 with
262 | (EField (e,"bind"),p) ->
283 | (EField (e,"bind",_),p) ->
263284 let e = type_expr ctx e WithType.value in
264285 (match follow e.etype with
265286 | TFun signature -> e
268289 in
269290 let tl = match e1.eexpr with
270291 | TField(_,fa) ->
271 let f (t,_,cf) =
272 (t,cf.cf_doc,get_value_meta cf.cf_meta) :: List.rev_map (fun cf' -> cf'.cf_type,cf.cf_doc,get_value_meta cf'.cf_meta) cf.cf_overloads
273 in
274292 begin match fa with
275 | FStatic(c,cf) | FInstance(c,_,cf) -> f (DisplayToplevel.maybe_resolve_macro_field ctx e1.etype c cf)
276 | FAnon cf | FClosure(_,cf) -> f (e1.etype,null_class,cf)
277 | _ -> [e1.etype,None,PMap.empty]
293 | FStatic(c,cf) ->
294 let t,cf = DisplayToplevel.maybe_resolve_macro_field ctx e1.etype c cf in
295 process_overloads true (Some c) ((fun t -> t),cf,t)
296 | FInstance(c,tl,cf) | FClosure(Some(c,tl),cf) ->
297 let t,cf = DisplayToplevel.maybe_resolve_macro_field ctx e1.etype c cf in
298 process_overloads false (Some c) (TClass.get_map_function c tl,cf,t)
299 | FAnon cf | FClosure(None,cf) ->
300 process_overloads false None ((fun t -> t),cf,e1.etype)
301 | _ ->
302 [e1.etype,None,PMap.empty]
278303 end;
279304 | TConst TSuper ->
280305 find_constructor_types e1.etype
311336 | _ ->
312337 raise_signatures [] 0 0 SKArrayAccess
313338 end
314 | _ -> error "Call expected" p
339 | _ -> typing_error "Call expected" p
315340
316341 and display_expr ctx e_ast e dk mode with_type p =
317342 let get_super_constructor () = match ctx.curclass.cl_super with
318 | None -> error "Current class does not have a super" p
343 | None -> typing_error "Current class does not have a super" p
319344 | Some (c,params) ->
320345 let fa = get_constructor_access c params p in
321346 fa.fa_field,c
337362 | _ -> e
338363 in
339364 match ctx.com.display.dms_kind with
340 | DMResolve _ | DMPackage ->
365 | DMPackage ->
341366 die "" __LOC__
342367 | DMSignature ->
343368 handle_signature_display ctx e_ast with_type
351376 | TField(_,(FAnon cf | FClosure (None,cf))) ->
352377 Display.ReferencePosition.set (cf.cf_name,cf.cf_name_pos,SKField (cf,None));
353378 | TField(_,(FInstance (c,_,cf) | FStatic (c,cf) | FClosure (Some (c,_),cf))) ->
354 Display.ReferencePosition.set (cf.cf_name,cf.cf_name_pos,SKField (cf,Some c.cl_path));
379 Display.ReferencePosition.set (cf.cf_name,cf.cf_name_pos,SKField (cf,Some c));
355380 | TLocal v | TVar(v,_) ->
356381 Display.ReferencePosition.set (v.v_name,v.v_pos,SKVariable v);
357382 | TTypeExpr mt ->
368393 | TCall({eexpr = TConst TSuper},_) ->
369394 begin try
370395 let cf,c = get_super_constructor() in
371 Display.ReferencePosition.set (cf.cf_name,cf.cf_name_pos,SKField (cf,Some c.cl_path));
396 Display.ReferencePosition.set (cf.cf_name,cf.cf_name_pos,SKField (cf,Some c));
372397 with Not_found ->
373398 ()
374399 end
449474 raise_fields fields (CRField(item,e1.epos,None,None)) (make_subject so ~start_pos:(Some (pos e_ast)) {e.epos with pmin = e.epos.pmax - l;})
450475 in
451476 begin match fst e_ast,e.eexpr with
452 | EField(e1,s),TField(e2,_) ->
477 | EField(e1,s,_),TField(e2,_) ->
453478 display_fields e1 e2 (Some s)
454479 | EObjectDecl [(name,pn,_),(EConst (Ident "null"),pe)],_ when pe.pmin = -1 ->
455480 (* This is what the parser emits for #8651. Bit of a dodgy heuristic but should be fine. *)
464489 raise_toplevel ctx dk with_type (name,p)
465490 end
466491 end
467 | DMDefault | DMNone | DMModuleSymbols _ | DMDiagnostics _ | DMStatistics ->
492 | DMDefault | DMNone | DMModuleSymbols _ ->
468493 let fields = DisplayFields.collect ctx e_ast e dk with_type p in
469494 let item = completion_item_of_expr ctx e in
470495 let iterator = try
515540 | DMDefinition | DMTypeDefinition ->
516541 raise_positions []
517542 | _ ->
518 error "Unsupported method" p
543 typing_error "Unsupported method" p
519544 end
520545 | (EConst (Ident "_"),p),WithType.WithType(t,_) ->
521546 mk (TConst TNull) t p (* This is "probably" a bind skip, let's just use the expected type *)
522547 | (_,p),_ -> try
523548 type_expr ~mode ctx e_ast with_type
524 with Error (Unknown_ident n,_) when ctx.com.display.dms_kind = DMDefault ->
549 with Error (Unknown_ident n,_,_) when ctx.com.display.dms_kind = DMDefault ->
525550 if dk = DKDot && is_legacy_completion ctx.com then raise (Parser.TypePath ([n],None,false,p))
526551 else raise_toplevel ctx dk with_type (n,p)
527 | Error ((Type_not_found (path,_,_) | Module_not_found path),_) as err when ctx.com.display.dms_kind = DMDefault ->
552 | Error ((Type_not_found (path,_,_) | Module_not_found path),_,_) as err when ctx.com.display.dms_kind = DMDefault ->
528553 if is_legacy_completion ctx.com then begin try
529554 raise_fields (DisplayFields.get_submodule_fields ctx path) (CRField((make_ci_module path),p,None,None)) (make_subject None (pos e_ast))
530555 with Not_found ->
531556 raise err
532557 end else
533558 raise_toplevel ctx dk with_type (s_type_path path,p)
534 | DisplayException(DisplayFields Some({fkind = CRTypeHint} as r)) when (match fst e_ast with ENew _ -> true | _ -> false) ->
559 | DisplayException(DisplayFields ({fkind = CRTypeHint} as r)) when (match fst e_ast with ENew _ -> true | _ -> false) ->
535560 let timer = Timer.timer ["display";"toplevel";"filter ctors"] in
536561 ctx.pass <- PBuildClass;
537562 let l = List.filter (fun item ->
568593 let mt = ctx.g.do_load_type_def ctx null_pos {tpackage=mt.pack;tname=mt.module_name;tsub=Some mt.name;tparams=[]} in
569594 begin match resolve_typedef mt with
570595 | TClassDecl c -> has_constructor c
571 | TAbstractDecl a -> (match Abstract.follow_with_forward_ctor ~build:true (TAbstract(a,List.map snd a.a_params)) with
596 | TAbstractDecl a -> (match Abstract.follow_with_forward_ctor ~build:true (TAbstract(a,extract_param_types a.a_params)) with
572597 | TInst(c,_) -> has_constructor c
573598 | TAbstract({a_impl = Some c},_) -> PMap.mem "_new" c.cl_statics
574599 | _ -> false)
587612 in
588613 let e = match e_ast, e.eexpr with
589614 | _, TField(e1,FDynamic "bind") when (match follow e1.etype with TFun _ -> true | _ -> false) -> e1
590 | (EField(_,"new"),_), TFunction { tf_expr = { eexpr = TReturn (Some ({ eexpr = TNew _ } as e1))} } -> e1
615 | (EField(_,"new",_),_), TFunction { tf_expr = { eexpr = TReturn (Some ({ eexpr = TNew _ } as e1))} } -> e1
591616 | _ -> e
592617 in
593618 let is_display_debug = Meta.has (Meta.Custom ":debug.display") ctx.curfield.cf_meta in
600625 | WithType.WithType(t,_) ->
601626 (* We don't want to actually use the transformed expression which may have inserted implicit cast calls.
602627 It only matters that unification takes place. *)
603 (try ignore(AbstractCast.cast_or_unify_raise ctx t e e.epos) with Error (Unify l,p) -> ());
628 (try ignore(AbstractCast.cast_or_unify_raise ctx t e e.epos) with Error (Unify l,p,_) -> ());
604629 | _ ->
605630 ()
606631 end;
636661 let rec loop subj fl = match fl with
637662 | [] -> subj
638663 | ((n,p,_),e) :: fl ->
664 let wt () =
665 try
666 let cf = List.find (fun { cf_name = name } -> name = n) !fields in
667 WithType.with_type cf.cf_type
668 with Not_found -> WithType.value
669 in
639670 let subj = if DisplayPosition.display_position#enclosed_in p then
640671 Some(n,p)
641672 else begin
642 if DisplayPosition.display_position#enclosed_in ({ (pos e) with pmin = p.pmax + 1 }) then begin
643 let e = fst e, { (pos e) with pmin = p.pmax + 1 } in
644 let wt =
645 try
646 let cf = List.find (fun { cf_name = name } -> name = n) !fields in
647 WithType.with_type cf.cf_type
648 with Not_found -> WithType.value
649 in
650 ignore(handle_display ctx e DKMarked MGet wt)
673 if DisplayPosition.display_position#enclosed_in (pos e) then
674 ignore(handle_display ctx e DKMarked MGet (wt()))
675 else begin
676 (* If we are between the : and the expression, we don't want to use the actual expression as a filter string (issue #10414) *)
677 let p_between = { p with pmin = p.pmax + 1; pmax = (pos e).pmin - 1} in
678 if DisplayPosition.display_position#enclosed_in p_between then begin
679 let e = (EConst(Ident "null"),p_between) in
680 ignore(handle_display ctx e DKMarked MGet (wt()))
681 end;
651682 end;
652683 fields := List.filter (fun cf -> cf.cf_name <> n) !fields;
653684 subj
668699 let pinsert = DisplayPosition.display_position#with_pos (pos e) in
669700 raise_fields fields CRStructureField (make_subject None pinsert)
670701 | _ ->
671 error "Expected object expression" p
702 typing_error "Expected object expression" p
672703
673704 let handle_edisplay ctx e dk mode with_type =
674705 let handle_display ctx e dk with_type =
697728 | DKPattern outermost,DMDefault ->
698729 begin try
699730 handle_display ctx e dk with_type
700 with DisplayException(DisplayFields Some({fkind = CRToplevel _} as r)) ->
731 with DisplayException(DisplayFields ({fkind = CRToplevel _} as r)) ->
701732 raise_fields r.fitems (CRPattern ((get_expected_type ctx with_type),outermost)) r.fsubject
702733 end
703 | _ -> handle_display ctx e dk with_type
734 | _ -> handle_display ctx e dk with_type
2525 open TFunctions
2626 open Error
2727
28 type dot_path_part_case =
29 | PUppercase
30 | PLowercase
31
32 type dot_path_part = (string * dot_path_part_case * pos)
33
3428 let mk_dot_path_part s p : dot_path_part =
3529 let case = if is_lower_ident s p then PLowercase else PUppercase in
36 (s,case,p)
30 {
31 name = s;
32 case = case;
33 pos = p
34 }
3735
3836 let s_dot_path parts =
3937 String.concat "." (List.map (fun (s,_,_) -> s) parts)
4341 match path, m.m_statics with
4442 | [], _ | _, None ->
4543 raise Not_found
46 | (name,_,p) :: path_rest, Some c ->
44 | {name = name; pos = p} :: path_rest, Some c ->
4745 let f = PMap.find name c.cl_statics in (* raises Not_found *)
4846 let e = type_module_type ctx (TClassDecl c) None p in
4947 field_access ctx mode f (FHStatic c) e p, path_rest
6058 (* if there was no module fields, resolve *)
6159 let mname = snd m.m_path in
6260 match path with
63 | (sname,PUppercase,sp) :: path_rest ->
61 | {name = sname; case = PUppercase; pos = sp} :: path_rest ->
6462 begin
6563 try
6664 resolve_module_type ctx m sname sp, path_rest
7573 try
7674 let m = Typeload.load_module ctx (pack,name) p in
7775 resolve_in_module ctx m next_path p mode with_type
78 with Error (Module_not_found mpath,_) when mpath = (pack,name) ->
76 with Error (Module_not_found mpath,_,_) when mpath = (pack,name) ->
7977 (* might be an instance of https://github.com/HaxeFoundation/haxe/issues/9150
8078 so let's also check (pack,name) of a TYPE in the current module context ¯\_(ツ)_/¯ *)
8179 let t = Typeload.find_type_in_current_module_context ctx pack name in (* raises Not_found *)
9391 so we try resolving a field first and fall back to find_in_unqualified_modules
9492 *)
9593 match next_path with
96 | (field,_,pfield) :: next_path ->
94 | {name = field; pos = pfield} :: next_path ->
9795 let e = type_module_type ctx t None p in
9896 let access = type_field (TypeFieldConfig.create true) ctx e field pfield mode with_type in
9997 access, next_path
109107 let resolve_dot_path ctx (path_parts : dot_path_part list) mode with_type =
110108 let rec loop pack_acc path =
111109 match path with
112 | (_,PLowercase,_) as x :: path ->
110 | {case = PLowercase} as x :: path ->
113111 (* part starts with lowercase - it's a package part, add it the accumulator and proceed *)
114112 loop (x :: pack_acc) path
115113
116 | (name,PUppercase,p) :: path ->
114 | {name = name; case = PUppercase; pos = p} :: path ->
117115 (* If this is the last part we want to use the actual mode. *)
118116 let mode,with_type = match path with
119117 | [] | [_] -> mode,with_type
122120 (* part starts with uppercase - it's a module name - try resolving *)
123121 let accessor, path_rest =
124122 if pack_acc <> [] then
125 let pack = List.rev_map (fun (x,_,_) -> x) pack_acc in
123 let pack = List.rev_map (fun part -> part.name) pack_acc in
126124 resolve_qualified ctx pack name path p mode with_type
127125 else
128126 resolve_unqualified ctx name path p mode with_type
00 [
11 {
22 "name": "AbsolutePath",
3 "define": "absolute_path",
3 "define": "absolute-path",
44 "doc": "Print absolute file path in trace output."
55 },
66 {
1111 },
1212 {
1313 "name": "AnalyzerOptimize",
14 "define": "analyzer_optimize",
14 "define": "analyzer-optimize",
1515 "doc": "Perform advanced optimizations."
1616 },
1717 {
18 "name": "AnalyzerTimes",
19 "define": "analyzer-times",
20 "doc": "Record detailed timers for the analyzer",
21 "params": ["level: 0 | 1 | 2"]
22 },
23 {
1824 "name": "AnnotateSource",
19 "define": "annotate_source",
25 "define": "annotate-source",
2026 "doc": "Add additional comments to generated source code.",
2127 "platforms": ["cpp"]
2228 },
2329 {
2430 "name": "CheckXmlProxy",
25 "define": "check_xml_proxy",
31 "define": "check-xml-proxy",
2632 "doc": "Check the used fields of the XML proxy."
2733 },
2834 {
2935 "name": "CoreApi",
30 "define": "core_api",
36 "define": "core-api",
3137 "doc": "Defined in the core API context."
3238 },
3339 {
3440 "name": "CoreApiSerialize",
35 "define": "core_api_serialize",
41 "define": "core-api-serialize",
3642 "doc": "Mark some generated core API classes with the `Serializable` attribute on C#.",
3743 "platforms": ["cs"]
3844 },
4349 },
4450 {
4551 "name": "CsVer",
46 "define": "cs_ver",
52 "define": "cs-ver",
4753 "doc": "The C# version to target.",
4854 "platforms": ["cs"],
4955 "params": ["version"]
6268 },
6369 {
6470 "name": "DceDebug",
65 "define": "dce_debug",
71 "define": "dce-debug",
6672 "doc": "Show DCE log.",
6773 "links": ["https://haxe.org/manual/cr-dce.html"]
6874 },
7379 },
7480 {
7581 "name": "DisableUnicodeStrings",
76 "define": "disable_unicode_strings",
82 "define": "disable-unicode-strings",
7783 "doc": "Disable Unicode support in `String` type.",
7884 "platforms": ["cpp"]
7985 },
8591 },
8692 {
8793 "name": "DisplayStdin",
88 "define": "display_stdin",
94 "define": "display-stdin",
8995 "doc": "Read the contents of a file specified in `--display` from standard input."
9096 },
9197 {
9298 "name": "DllExport",
93 "define": "dll_export",
99 "define": "dll-export",
94100 "doc": "GenCPP experimental linking.",
95101 "platforms": ["cpp"]
96102 },
97103 {
98104 "name": "DllImport",
99 "define": "dll_import",
105 "define": "dll-import",
100106 "doc": "Handle Haxe-generated .NET DLL imports.",
101107 "platforms": ["cs"]
102108 },
103109 {
104110 "name": "DocGen",
105 "define": "doc_gen",
111 "define": "doc-gen",
106112 "doc": "Do not perform any removal/change in order to correctly generate documentation."
107113 },
108114 {
113119 },
114120 {
115121 "name": "DumpPath",
116 "define": "dump_path",
122 "define": "dump-path",
117123 "doc": "Path to generate dumps to (default: \"dump\").",
118124 "params": ["path"]
119125 },
120126 {
121127 "name": "DumpDependencies",
122 "define": "dump_dependencies",
128 "define": "dump-dependencies",
123129 "doc": "Dump the classes dependencies in a dump subdirectory."
124130 },
125131 {
126132 "name": "DumpIgnoreVarIds",
127 "define": "dump_ignore_var_ids",
133 "define": "dump-ignore-var-ids",
128134 "doc": "Remove variable IDs from non-pretty dumps (helps with diff)."
129135 },
130136 {
131137 "name": "DynamicInterfaceClosures",
132 "define": "dynamic_interface_closures",
138 "define": "dynamic-interface-closures",
133139 "doc": "Use slow path for interface closures to save space.",
134140 "platforms": ["cpp"]
135141 },
136142 {
137143 "name": "EraseGenerics",
138 "define": "erase_generics",
144 "define": "erase-generics",
139145 "doc": "Erase generic classes on C#.",
140146 "platforms": ["cs"]
141147 },
142148 {
143149 "name": "EvalCallStackDepth",
144 "define": "eval_call_stack_depth",
150 "define": "eval-call-stack-depth",
145151 "doc": "Set maximum call stack depth for eval. (default: 1000)",
146152 "platforms": ["eval"],
147153 "params": ["depth"]
148154 },
149155 {
150156 "name": "EvalDebugger",
151 "define": "eval_debugger",
152 "doc": "Support debugger in macro/interp mode. Allows `host:port` value to open a socket. Implies eval_stack.",
157 "define": "eval-debugger",
158 "doc": "Support debugger in macro/interp mode. Allows `host:port` value to open a socket. Implies eval-stack.",
153159 "platforms": ["eval"]
154160 },
155161 {
162 "name": "EvalPrintDepth",
163 "define": "eval-print-depth",
164 "doc": "Set maximum print depth (before replacing with '<...>') for eval. (default: 5)",
165 "platforms": ["eval"],
166 "params": ["depth"]
167 },
168 {
169 "name": "EvalPrettyPrint",
170 "define": "eval-pretty-print",
171 "doc": "Enable indented output for eval printing.",
172 "platforms": ["eval"]
173 },
174 {
156175 "name": "EvalStack",
157 "define": "eval_stack",
176 "define": "eval-stack",
158177 "doc": "Record stack information in macro/interp mode.",
159178 "platforms": ["eval"]
160179 },
161180 {
162181 "name": "EvalTimes",
163 "define": "eval_times",
164 "doc": "Record per-method execution times in macro/interp mode. Implies eval_stack.",
182 "define": "eval-times",
183 "doc": "Record per-method execution times in macro/interp mode. Implies eval-stack.",
165184 "platforms": ["eval"]
166185 },
167186 {
168187 "name": "FilterTimes",
169 "define": "filter_times",
188 "define": "filter-times",
170189 "doc": "Record per-filter execution times upon --times."
171190 },
172191 {
173192 "name": "FastCast",
174 "define": "fast_cast",
193 "define": "fast-cast",
175194 "doc": "Enables an experimental casts cleanup on C# and Java.",
176195 "platforms": ["cs", "java"]
177196 },
183202 },
184203 {
185204 "name": "FileExtension",
186 "define": "file_extension",
205 "define": "file-extension",
187206 "doc": "Output filename extension for cpp source code.",
188207 "platforms": ["cpp"]
189208 },
190209 {
191210 "name": "FlashStrict",
192 "define": "flash_strict",
211 "define": "flash-strict",
193212 "doc": "More strict typing for flash target.",
194213 "platforms": ["flash"]
195214 },
196215 {
197216 "name": "FlashUseStage",
198 "define": "flash_use_stage",
217 "define": "flash-use-stage",
199218 "doc": "Keep the SWF library initial stage.",
200219 "platforms": ["flash"]
201220 },
202221 {
203 "devcomment": "force_lib_check is only here as a debug facility - compiler checking allows errors to be found more easily",
222 "devcomment": "force-lib-check is only here as a debug facility - compiler checking allows errors to be found more easily",
204223 "name": "ForceLibCheck",
205 "define": "force_lib_check",
206 "doc": "Force the compiler to check `--net-lib` and `–-java-lib` added classes (internal).",
224 "define": "force-lib-check",
225 "doc": "Force the compiler to check `--net-lib` and `--java-lib` added classes (internal).",
207226 "platforms": ["cs", "java"]
208227 },
209228 {
210229 "name": "ForceNativeProperty",
211 "define": "force_native_property",
230 "define": "force-native-property",
212231 "doc": "Tag all properties with `:nativeProperty` metadata for 3.1 compatibility.",
213232 "platforms": ["cpp"]
214233 },
215234 {
216235 "name": "GencommonDebug",
217 "define": "gencommon_debug",
236 "define": "gencommon-debug",
218237 "doc": "GenCommon internal.",
219238 "platforms": ["cs", "java"]
220239 },
225244 },
226245 {
227246 "name": "HaxeBoot",
228 "define": "haxe_boot",
247 "define": "haxe-boot",
229248 "doc": "Give the name 'haxe' to the flash boot class instead of a generated name.",
230249 "platforms": ["flash"]
231250 },
232251 {
233252 "name": "HaxeVer",
234 "define": "haxe_ver",
253 "define": "haxe-ver",
235254 "doc": "The current Haxe version value as decimal number. E.g. 3.407 for 3.4.7.",
236255 "reserved": true
237256 },
242261 "reserved": true
243262 },
244263 {
264 "name": "HaxeNext",
265 "define": "haxe-next",
266 "doc": "Enable experimental features that are meant to be released on next Haxe version."
267 },
268 {
245269 "name": "HlVer",
246 "define": "hl_ver",
270 "define": "hl-ver",
247271 "doc": "The HashLink version to target. (default: 1.10.0)",
248272 "platforms": ["hl"],
249273 "params": ["version"]
250274 },
251275 {
252276 "name": "HxcppApiLevel",
253 "define": "hxcpp_api_level",
277 "define": "hxcpp-api-level",
254278 "doc": "Provided to allow compatibility between hxcpp versions.",
255279 "platforms": ["cpp"],
256280 "reserved": true
257281 },
258282 {
259283 "name": "HxcppGcGenerational",
260 "define": "HXCPP_GC_GENERATIONAL",
284 "define": "HXCPP-GC-GENERATIONAL",
261285 "doc": "Experimental Garbage Collector.",
262286 "platforms": ["cpp"]
263287 },
264288 {
265289 "name": "HxcppDebugger",
266 "define": "HXCPP_DEBUGGER",
267 "doc": "Include additional information for hxcpp_debugger.",
290 "define": "HXCPP-DEBUGGER",
291 "doc": "Include additional information for hxcpp-debugger.",
268292 "platforms": ["cpp"]
269293 },
270294 {
271295 "name": "HxcppSmartStings",
272 "define": "hxcpp_smart_strings",
273 "doc": "Use wide strings in hxcpp. (Turned on by default unless `-D disable_unicode_strings` is specified.)",
296 "define": "hxcpp-smart-strings",
297 "doc": "Use wide strings in hxcpp. (Turned on by default unless `-D disable-unicode-strings` is specified.)",
274298 "platforms": ["cpp"]
275299 },
276300 {
277301 "name": "IncludePrefix",
278 "define": "include_prefix",
302 "define": "include-prefix",
279303 "doc": "Prepend path to generated include files.",
280304 "platforms": ["cpp"]
281305 },
292316 },
293317 {
294318 "name": "JavaVer",
295 "define": "java_ver",
319 "define": "java-ver",
296320 "doc": "Sets the Java version to be targeted.",
297321 "platforms": ["java"],
298322 "params": ["version: 5-7"]
299323 },
300324 {
301325 "name": "JsClassic",
302 "define": "js_classic",
326 "define": "js-classic",
303327 "doc": "Don't use a function wrapper and strict mode in JS output.",
304328 "platforms": ["js"]
305329 },
306330 {
307331 "name": "JsEs",
308 "define": "js_es",
332 "define": "js-es",
309333 "doc": "Generate JS compliant with given ES standard version. (default: 5)",
310334 "platforms": ["js"],
311335 "params": ["version: 3 | 5 | 6"],
313337 },
314338 {
315339 "name": "JsEnumsAsArrays",
316 "define": "js_enums_as_arrays",
340 "define": "js-enums-as-arrays",
317341 "doc": "Generate enum representation as array instead of as object.",
318342 "platforms": ["js"]
319343 },
325349 },
326350 {
327351 "name": "JsUnflatten",
328 "define": "js_unflatten",
352 "define": "js-unflatten",
329353 "doc": "Generate nested objects for packages and types.",
330354 "platforms": ["js"]
331355 },
332356 {
333357 "name": "JsSourceMap",
334 "define": "js_source_map",
335 "doc": "Generate JavaScript source map even in non-debug mode. Deprecated in favor of `-D source_map`.",
358 "define": "js-source-map",
359 "doc": "Generate JavaScript source map even in non-debug mode. Deprecated in favor of `-D source-map`.",
336360 "platforms": ["js"]
337361 },
338362 {
339363 "name": "SourceMap",
340 "define": "source_map",
364 "define": "source-map",
341365 "doc": "Generate source map for compiled files.",
342366 "platforms": ["php", "js"]
343367 },
361385 },
362386 {
363387 "name": "KeepOldOutput",
364 "define": "keep_old_output",
388 "define": "keep-old-output",
365389 "doc": "Keep old source files in the output directory.",
366390 "platforms": ["cs", "java"]
367391 },
368392 {
369393 "name": "LoopUnrollMaxCost",
370 "define": "loop_unroll_max_cost",
394 "define": "loop-unroll-max-cost",
371395 "doc": "Maximum cost (number of expressions * iterations) before loop unrolling is canceled. (default: 250)",
372396 "params": ["cost"]
373397 },
374398 {
375399 "name": "LuaJit",
376 "define": "lua_jit",
400 "define": "lua-jit",
377401 "doc": "Enable the jit compiler for lua (version 5.2 only).",
378402 "platforms": ["lua"]
379403 },
380404 {
381405 "name": "LuaVanilla",
382 "define": "lua_vanilla",
406 "define": "lua-vanilla",
383407 "doc": "Generate code lacking compiled extern lib support (e.g. utf8).",
384408 "platforms": ["lua"]
385409 },
386410 {
387411 "name": "LuaVer",
388 "define": "lua_ver",
412 "define": "lua-ver",
389413 "doc": "The lua version to target.",
390414 "platforms": ["lua"],
391415 "params": ["version"]
399423 },
400424 {
401425 "name": "MacroTimes",
402 "define": "macro_times",
426 "define": "macro-times",
403427 "doc": "Display per-macro timing when used with `--times`."
404428 },
405429 {
406430 "name": "NetVer",
407 "define": "net_ver",
431 "define": "net-ver",
408432 "doc": "Sets the .NET version to be targeted.",
409433 "platforms": ["cs"],
410 "params": ["version: 20-45"]
434 "params": ["version: 20-50"]
411435 },
412436 {
413437 "name": "NetcoreVer",
414 "define": "netcore_ver",
438 "define": "netcore-ver",
415439 "doc": "Sets the .NET core version to be targeted",
416440 "platforms": ["cs"],
417441 "params": ["version: x.x.x"]
418442 },
419443 {
420444 "name": "NetTarget",
421 "define": "net_target",
445 "define": "net-target",
422446 "doc": "Sets the .NET target. `netcore` (.NET core), `xbox`, `micro` (Micro Framework), `compact` (Compact Framework) are some valid values. (default: `net`)",
423447 "platforms": ["cs"],
424448 "params": ["name"]
425449 },
426450 {
427451 "name": "NekoSource",
428 "define": "neko_source",
452 "define": "neko-source",
429453 "doc": "Output neko source instead of bytecode.",
430454 "platforms": ["neko"]
431455 },
432456 {
457 "name": "NekoNoHaxelibPaths",
458 "define": "neko-no-haxelib-paths",
459 "doc": "Disable hard-coded Haxelib ndll paths.",
460 "platforms": [
461 "neko"
462 ]
463 },
464 {
433465 "name": "NekoV1",
434 "define": "neko_v1",
466 "define": "neko-v1",
435467 "doc": "Keep Neko 1.x compatibility.",
436468 "platforms": ["neko"]
437469 },
449481 },
450482 {
451483 "name": "NoDebug",
452 "define": "no_debug",
484 "define": "no-debug",
453485 "doc": "Remove all debug macros from cpp output."
454486 },
455487 {
465497 },
466498 {
467499 "name": "NoOpt",
468 "define": "no_opt",
500 "define": "no-opt",
469501 "doc": "Disable optimizations."
470502 },
471503 {
472504 "name": "NoInline",
473 "define": "no_inline",
505 "define": "no-inline",
474506 "doc": "Disable inlining.",
475507 "links": ["https://haxe.org/manual/class-field-inline.html"]
476508 },
477509 {
478510 "name": "KeepInlinePositions",
479 "define": "keep_inline_positions",
511 "define": "keep-inline-positions",
480512 "doc": "Don't substitute positions of inlined expressions with the position of the place of inlining.",
481513 "links": ["https://haxe.org/manual/class-field-inline.html"]
482514 },
483515 {
484516 "name": "NoRoot",
485 "define": "no_root",
517 "define": "no-root",
486518 "doc": "Generate top-level types into the `haxe.root` namespace.",
487519 "platforms": ["cs"]
488520 },
489521 {
490522 "name": "NoMacroCache",
491 "define": "no_macro_cache",
523 "define": "no-macro-cache",
492524 "doc": "Disable macro context caching."
493525 },
494526 {
495527 "name": "NoSwfCompress",
496 "define": "no_swf_compress",
528 "define": "no-swf-compress",
497529 "doc": "Disable SWF output compression.",
498530 "platforms": ["flash"]
499531 },
500532 {
501533 "name": "NoTraces",
502 "define": "no_traces",
534 "define": "no-traces",
503535 "doc": "Disable all trace calls."
504536 },
505537 {
515547 },
516548 {
517549 "name": "PhpPrefix",
518 "define": "php_prefix",
550 "define": "php-prefix",
519551 "doc": "Root namespace for generated php classes. E.g. if compiled with`-D php-prefix=some.sub`, then all classes will be generated in `\\some\\sub` namespace.",
520552 "platforms": ["php"],
521553 "params": ["dot-separated namespace"]
522554 },
523555 {
524556 "name": "PhpLib",
525 "define": "php_lib",
557 "define": "php-lib",
526558 "doc": "Select the name for the php lib folder.",
527559 "platforms": ["php"],
528560 "params": ["folder name"]
529561 },
530562 {
531563 "name": "PhpFront",
532 "define": "php_front",
564 "define": "php-front",
533565 "doc": "Select the name for the php front file. (default: `index.php`)",
534566 "platforms": ["php"],
535567 "params": ["filename"]
536568 },
537569 {
538570 "name": "PythonVersion",
539 "define": "python_version",
571 "define": "python-version",
540572 "doc": "The python version to target. (default: 3.3)",
541573 "platforms": ["python"],
542574 "params": ["version"]
543575 },
544576 {
545577 "name": "RealPosition",
546 "define": "real_position",
578 "define": "real-position",
547579 "doc": "Disables Haxe source mapping when targetting C#, removes position comments in Java and Php output.",
548580 "platforms": ["cs", "java", "php"]
549581 },
550582 {
551583 "name": "ReplaceFiles",
552 "define": "replace_files",
584 "define": "replace-files",
553585 "doc": "GenCommon internal.",
554586 "platforms": ["cs", "java"]
587 },
588 {
589 "name": "RetainUntypedMeta",
590 "define": "retain-untyped-meta",
591 "doc": "Prevents arbitrary expression metadata from being discarded upon typing."
555592 },
556593 {
557594 "name": "Scriptable",
597634 },
598635 {
599636 "name": "SwfCompressLevel",
600 "define": "swf_compress_level",
637 "define": "swf-compress-level",
601638 "doc": "Set the amount of compression for the SWF output.",
602639 "platforms": ["flash"],
603640 "params": ["level: 1-9"]
604641 },
605642 {
606643 "name": "SwfDebugPassword",
607 "define": "swf_debug_password",
644 "define": "swf-debug-password",
608645 "doc": "Set a password for debugging.",
609646 "platforms": ["flash"],
610647 "params": ["password"]
611648 },
612649 {
613650 "name": "SwfDirectBlit",
614 "define": "swf_direct_blit",
651 "define": "swf-direct-blit",
615652 "doc": "Use hardware acceleration to blit graphics.",
616653 "platforms": ["flash"]
617654 },
618655 {
619656 "name": "SwfGpu",
620 "define": "swf_gpu",
657 "define": "swf-gpu",
621658 "doc": "Use GPU compositing features when drawing graphics.",
622659 "platforms": ["flash"]
623660 },
624661 {
662 "name": "SwfHeader",
663 "define": "swf-header",
664 "doc": "define SWF header (width:height:fps:color)",
665 "platforms": ["flash"]
666 },
667 {
625668 "name": "SwfMetadata",
626 "define": "swf_metadata",
669 "define": "swf-metadata",
627670 "doc": "Include contents of the given file as metadata in the SWF.",
628671 "platforms": ["flash"],
629672 "params": ["file"]
630673 },
631674 {
632675 "name": "SwfPreloaderFrame",
633 "define": "swf_preloader_frame",
676 "define": "swf-preloader-frame",
634677 "doc": "Insert empty first frame in SWF.",
635678 "platforms": ["flash"]
636679 },
637680 {
638681 "name": "SwfProtected",
639 "define": "swf_protected",
682 "define": "swf-protected",
640683 "doc": "Compile Haxe `private` as `protected` in the SWF instead of `public`.",
641684 "platforms": ["flash"]
642685 },
643686 {
644687 "name": "SwfScriptTimeout",
645 "define": "swf_script_timeout",
688 "define": "swf-script-timeout",
646689 "doc": "Maximum ActionScript processing time before script stuck dialog box displays.",
647690 "platforms": ["flash"],
648691 "params": ["time in seconds"]
649692 },
650693 {
651694 "name": "SwfUseDoAbc",
652 "define": "swf_use_doabc",
695 "define": "swf-use-doabc",
653696 "doc": "Use `DoAbc` SWF-tag instead of `DoAbcDefine`.",
654697 "platforms": ["flash"]
655698 },
667710 },
668711 {
669712 "name": "UseNekoc",
670 "define": "use_nekoc",
713 "define": "use-nekoc",
671714 "doc": "Use `nekoc` compiler instead of the internal one.",
672715 "platforms": ["neko"]
673716 },
685728 },
686729 {
687730 "name": "WarnVarShadowing",
688 "define": "warn_var_shadowing",
731 "define": "warn-var-shadowing",
689732 "doc": "Warn about shadowing variable declarations."
690733 },
691734 {
692735 "name": "NoTre",
693 "define": "no_tre",
736 "define": "no-tre",
694737 "doc": "Disable tail recursion elimination."
738 },
739 {
740 "name": "MessageReporting",
741 "define": "message-reporting",
742 "doc": "Select message reporting mode for compiler output. (default: classic)",
743 "params": ["mode: classic | pretty | indent"]
744 },
745 {
746 "name": "NoColor",
747 "define": "no-color",
748 "doc": "Disable ANSI color codes when using rich output."
749 },
750 {
751 "name": "MessagesLogFile",
752 "define": "messages-log-file",
753 "doc": "Path to a text file to write messages log to, in addition to regular output."
754 },
755 {
756 "name": "MessagesLogFormat",
757 "define": "messages-log-format",
758 "doc": "Select message reporting mode for messages log output. (default: indent)",
759 "params": ["format: classic | pretty | indent"]
695760 }
696761 ]
111111 {
112112 "name": "Build",
113113 "metadata": ":build",
114 "doc": "Builds a class or enum from a macro.",
114 "doc": "Builds a class, enum, or abstract from a macro.",
115115 "params": ["Build macro call"],
116 "targets": ["TClass", "TEnum"],
116 "targets": ["TClass", "TEnum", "TAbstract"],
117117 "links": ["https://haxe.org/manual/macro-type-building.html"]
118118 },
119119 {
517517 "targets": ["TClass", "TClassField"]
518518 },
519519 {
520 "name": "HxCompletion",
521 "metadata": ":hx.completion",
522 "doc": "Internally used for completion",
523 "internal": true
524 },
525 {
520526 "name": "HxGen",
521527 "metadata": ":hxGen",
522528 "doc": "Annotates that an extern class was generated by Haxe.",
610616 "platforms": ["java"],
611617 "params": ["Output type package", "Output type name"],
612618 "targets": ["TClass", "TEnum"]
619 },
620 {
621 "name": "JavaDefault",
622 "metadata": ":java.default",
623 "doc": "Equivalent to the default modifier of the Java language",
624 "platforms": ["java"],
625 "params": [],
626 "targets": ["TClassField"]
613627 },
614628 {
615629 "name": "JavaNative",
12721286 "internal": true
12731287 },
12741288 {
1289 "name": "HaxeWarning",
1290 "metadata": ":haxe.warning",
1291 "doc": "Modifies warning options, equivalent to the -w CLI argument",
1292 "targets": ["TClass","TClassField"]
1293 },
1294 {
12751295 "name": "Void",
12761296 "metadata": ":void",
12771297 "doc": "Use Cpp native `void` return type.",
12821302 "metadata": ":needsExceptionStack",
12831303 "doc": "Internally used for some of auto-generated `catch` vars",
12841304 "internal": true
1305 },
1306 {
1307 "name": "WrappedException",
1308 "metadata": ":wrappedException",
1309 "doc": "Internally used for exceptions wrapping in `throw` expressions.",
1310 "internal": true
1311 },
1312 {
1313 "name": "NativeArrayAccess",
1314 "metadata": ":nativeArrayAccess",
1315 "doc": "When used on an extern class which implements haxe.ArrayAccess native array access syntax will be generated",
1316 "platforms": ["cpp"]
12851317 }
12861318 ]
0 [
1 {
2 "name": "WAll",
3 "doc": "The mother of all warnings",
4 "generic": true
5 },
6 {
7 "name": "WInternal",
8 "doc": "Reserved for internal use",
9 "generic": true
10 },
11 {
12 "name": "WTemp",
13 "doc": "Reserved for internal use",
14 "generic": true
15 },
16 {
17 "name": "WInfo",
18 "doc": "Generic information like $type",
19 "generic": true
20 },
21 {
22 "name": "WUser",
23 "doc": "Custom user warnings, e.g. from Context.warning",
24 "generic": true
25 },
26 {
27 "name": "WCompiler",
28 "doc": "Warnings from the compiler frontend, e.g. argument parsing",
29 "generic": true
30 },
31 {
32 "name": "WParser",
33 "doc": "Warnings related to lexing and parsing",
34 "generic": true
35 },
36 {
37 "name": "WTyper",
38 "doc": "Warnings from the typer",
39 "generic": true
40 },
41 {
42 "name": "WMacro",
43 "doc": "Warning related to macros",
44 "generic": true
45 },
46 {
47 "name": "WOptimizer",
48 "doc": "Warnings related to optimization",
49 "generic": true
50 },
51 {
52 "name": "WGenerator",
53 "doc": "Warnings related to code generation",
54 "generic": true
55 },
56 {
57 "name": "WDeprecated",
58 "doc": "This is deprecated and should no longer be used"
59 },
60 {
61 "name": "WVarInit",
62 "doc": "A local variable might be used before being assigned a value",
63 "parent": "WTyper"
64 },
65 {
66 "name": "WVarShadow",
67 "doc": "A local variable hides another by using the same name",
68 "parent": "WTyper"
69 },
70 {
71 "name": "WExternWithExpr",
72 "doc": "A non-inline field marked as extern has an expression",
73 "parent": "WTyper"
74 },
75 {
76 "name": "WStaticInitOrder",
77 "doc": "The compiler could not determine a type order due to mutually dependent static initializations",
78 "parent": "WTyper"
79 },
80 {
81 "name": "WClosureCompare",
82 "doc": "Closures are being compared, which might be undefined",
83 "parent": "WTyper"
84 },
85 {
86 "name": "WReservedTypePath",
87 "doc": "A type path is being used that is supposed to be reserved on the current target",
88 "parent": "WTyper"
89 },
90 {
91 "name": "WPatternMatcher",
92 "doc": "Warnings related to the pattern matcher",
93 "parent": "WTyper"
94 },
95 {
96 "name": "WUnusedPattern",
97 "doc": "The pattern is not used because previous cases cover",
98 "parent": "WPatternMatcher"
99 },
100 {
101 "name": "WConstructorInliningCancelled",
102 "doc": "Constructor call could not be inlined because a field is uninitialized",
103 "parent": "WTyper"
104 }
105
106 ]
00 open Json
11
22 exception Prebuild_error of string
3
4 type parsed_warning = {
5 w_name : string;
6 w_doc : string;
7 w_parent : string option;
8 w_generic : bool;
9 }
310
411 let as_string = function
512 | JString s -> Some s
13 | _ -> None
14
15 let as_int = function
16 | JInt i -> Some i
617 | _ -> None
718
819 let as_params = function
6576 | Some v -> v
6677 with Not_found -> default
6778
79 let get_optional_field2 name map fields =
80 try
81 let field = List.find (fun (n, _) -> n = name) fields in
82 let value = map (snd field) in
83 match value with
84 | None -> raise (Prebuild_error ("field `" ^ name ^ "` has invalid data"))
85 | Some v -> Some v
86 with Not_found ->
87 None
88
6889 let get_field name map fields =
6990 let field = try List.find (fun (n, _) -> n = name) fields with Not_found -> raise (Prebuild_error ("no `" ^ name ^ "` field")) in
7091 let value = map (snd field) in
98119 (* internal *) get_optional_field "internal" as_bool false fields,
99120 (* links *) get_optional_field "links" as_links [] fields
100121
122 let parse_warning json =
123 let fields = match json with
124 | JObject fl -> fl
125 | _ -> raise (Prebuild_error "not an object")
126 in
127 {
128 w_name = get_field "name" as_string fields;
129 w_doc = get_field "doc" as_string fields;
130 w_parent = get_optional_field2 "parent" as_string fields;
131 w_generic = get_optional_field "generic" as_bool false fields;
132 }
133
101134 let parse_file_array path map =
102135 let file = open_in path in
103136 let data = Std.input_all file in
108141 | JArray s -> List.map map s
109142 | _ -> raise (Prebuild_error "not an array")
110143
144 let s_escape ?(hex=true) s =
145 let b = Buffer.create (String.length s) in
146 for i = 0 to (String.length s) - 1 do
147 match s.[i] with
148 | '\n' -> Buffer.add_string b "\\n"
149 | '\t' -> Buffer.add_string b "\\t"
150 | '\r' -> Buffer.add_string b "\\r"
151 | '"' -> Buffer.add_string b "\\\""
152 | '\\' -> Buffer.add_string b "\\\\"
153 | c when int_of_char c < 32 && hex -> Buffer.add_string b (Printf.sprintf "\\x%.2X" (int_of_char c))
154 | c -> Buffer.add_char b c
155 done;
156 Buffer.contents b
157
111158 let gen_platforms = function
112159 | [] -> []
113160 | platforms -> ["Platforms [" ^ (String.concat ";" platforms) ^ "]"]
125172 let platforms_str = gen_platforms platforms in
126173 let params_str = gen_params params in
127174 let links_str = gen_links links in
175 let define = String.concat "_" (ExtString.String.nsplit define "-") in
128176 "\t| " ^ name ^ " -> \"" ^ define ^ "\",(" ^ (Printf.sprintf "%S" doc) ^ ",[" ^ (String.concat "; " (platforms_str @ params_str @ links_str)) ^ "])"
129177 ) defines in
130178 String.concat "\n" define_str
155203 ) metas in
156204 String.concat "\n" meta_str
157205
206 let gen_warning_type warnings =
207 let warning_str = List.map (function
208 w ->
209 Printf.sprintf "\t| %s" w.w_name
210 ) warnings in
211 String.concat "\n" warning_str
212
213 let gen_warning_parse warnings =
214 let warning_str = List.map (function
215 w ->
216 Printf.sprintf "\t| \"%s\" -> %s" w.w_name w.w_name
217 ) warnings in
218 let warning_str = warning_str @ ["\t| _ -> raise Exit"] in
219 String.concat "\n" warning_str
220
221
222 let gen_warning_obj warnings =
223 let warning_str = List.map (fun w ->
224 let w_parent = match w.w_parent with
225 | None -> if w.w_name = "WAll" then "None" else "Some WAll"
226 | Some w -> Printf.sprintf "Some %s" w
227 in
228 Printf.sprintf "\t| %s -> {w_name = \"%s\"; w_doc = \"%s\"; w_generic = %b; w_parent = %s}" w.w_name w.w_name (s_escape w.w_doc) w.w_generic w_parent
229 ) warnings in
230 String.concat "\n" warning_str
231
158232 let autogen_header = "(* This file is auto-generated using prebuild from files in src-json *)
159233 (* Do not edit manually! *)
160234 "
184258 | TTypeParameter
185259 | TVariable
186260
261 let parse_meta_usage = function
262 | \"TClass\" -> TClass
263 | \"TClassField\" -> TClassField
264 | \"TAbstract\" -> TAbstract
265 | \"TAbstractField\" -> TAbstractField
266 | \"TEnum\" -> TEnum
267 | \"TTypedef\" -> TTypedef
268 | \"TAnyField\" -> TAnyField
269 | \"TExpr\" -> TExpr
270 | \"TTypeParameter\" -> TTypeParameter
271 | \"TVariable\" -> TVariable
272 | t -> raise (failwith (\"invalid metadata target \" ^ t))
273
187274 type meta_parameter =
188275 | HasParam of string
189276 | Platforms of platform list
201288 Printf.printf "%s" define_header;
202289 Printf.printf "type strict_defined =\n";
203290 Printf.printf "%s" (gen_define_type defines);
204 Printf.printf "\n\t| Last\n\n"; (* must be last *)
291 Printf.printf "\n\t| Last\n\t| Custom of string\n\n";
205292 Printf.printf "let infos = function\n";
206293 Printf.printf "%s" (gen_define_info defines);
207 Printf.printf "\n\t| Last -> die \"\" __LOC__\n"
294 Printf.printf "\n\t| Last -> die \"\" __LOC__\n\t| Custom s -> s,(\"\",[])\n"
208295 | [_; "meta"; meta_path]->
209296 let metas = parse_file_array meta_path parse_meta in
210297 Printf.printf "%s" meta_header;
214301 Printf.printf "let get_info = function\n";
215302 Printf.printf "%s" (gen_meta_info metas);
216303 Printf.printf "\n\t| Last -> die \"\" __LOC__\n\t| Dollar s -> \"$\" ^ s,(\"\",[])\n\t| Custom s -> s,(\"\",[])\n"
304 | [_; "warning"; warning_path]->
305 let warnings = parse_file_array warning_path parse_warning in
306 print_endline "type warning =";
307 print_endline (gen_warning_type warnings);
308 print_endline "";
309 print_endline "type warning_obj = {";
310 print_endline "\tw_name : string;";
311 print_endline "\tw_doc : string;";
312 print_endline "\tw_generic : bool;";
313 print_endline "\tw_parent : warning option;";
314 print_endline "}";
315 print_endline "";
316 print_endline "let warning_obj = function";
317 print_endline (gen_warning_obj warnings);
318 print_endline "";
319 print_endline "let from_string = function";
320 print_endline (gen_warning_parse warnings);
217321 | _ :: "libparams" :: params ->
218322 Printf.printf "(%s)" (String.concat " " (List.map (fun s -> Printf.sprintf "\"%s\"" s) params))
219323 | [_ ;"version";add_revision;branch;sha] ->
3131 to another type.
3232 **/
3333 @:forward.variance
34 abstract Any(Dynamic) {
34 abstract Any(Dynamic) from Dynamic {
3535 @:noCompletion @:to extern inline function __promote<T>():T
3636 return this;
37
38 @:noCompletion @:from extern inline static function __cast<T>(value:T):Any
39 return cast value;
4037
4138 @:noCompletion extern inline function toString():String
4239 return Std.string(this);
275275 static function isFinite(f:Float):Bool;
276276
277277 /**
278 Tells if `f` is not a valid number.
278 Tells if `f` is `Math.NaN`.
279279
280280 If `f` is `NaN`, the result is `true`, otherwise the result is `false`.
281 In particular, both `POSITIVE_INFINITY` and `NEGATIVE_INFINITY` are
281 In particular, `null`, `POSITIVE_INFINITY` and `NEGATIVE_INFINITY` are
282282 not considered `NaN`.
283283 **/
284284 static function isNaN(f:Float):Bool;
9696
9797 Leading whitespaces are ignored.
9898
99 If `x` starts with 0x or 0X, hexadecimal notation is recognized where the following digits may
100 contain 0-9 and A-F.
99 `x` may optionally start with a + or - to denote a postive or negative value respectively.
101100
102 Otherwise `x` is read as decimal number with 0-9 being allowed characters. `x` may also start with
103 a - to denote a negative value.
101 If the optional sign is followed 0x or 0X, hexadecimal notation is recognized where the following
102 digits may contain 0-9 and A-F. Both the prefix and digits are case insensitive.
104103
105 In decimal mode, parsing continues until an invalid character is detected, in which case the
106 result up to that point is returned. For hexadecimal notation, the effect of invalid characters
107 is unspecified.
104 Otherwise `x` is read as decimal number with 0-9 being allowed characters. Octal and binary
105 notations are not supported.
108106
109 Leading 0s that are not part of the 0x/0X hexadecimal notation are ignored, which means octal
110 notation is not supported.
107 Parsing continues until an invalid character is detected, in which case the result up to
108 that point is returned. Scientific notation is not supported. That is `Std.parseInt('10e2')` produces `10`.
111109
112 If `x` is null, the result is unspecified.
113 If `x` cannot be parsed as integer, the result is `null`.
110 If `x` is `null`, the result is `null`.
111 If `x` cannot be parsed as integer or is empty, the result is `null`.
112
113 If `x` starts with a hexadecimal prefix which is not followed by at least one valid hexadecimal
114 digit, the result is unspecified.
114115 **/
115116 static function parseInt(x:String):Null<Int>;
116117
118119 Converts a `String` to a `Float`.
119120
120121 The parsing rules for `parseInt` apply here as well, with the exception of invalid input
121 resulting in a `NaN` value instead of null.
122 resulting in a `NaN` value instead of `null`. Also, hexadecimal support is **not** specified.
122123
123124 Additionally, decimal notation may contain a single `.` to denote the start of the fractions.
125
126 It may also end with `e` or `E` followed by optional minus or plus sign and a sequence of
127 digits (defines exponent to base 10).
124128 **/
125129 static function parseFloat(x:String):Float;
126130
210210 public static inline function contains(s:String, value:String):Bool {
211211 #if (js && js_es >= 6)
212212 return (cast s).includes(value);
213 #else
213 #else
214214 return s.indexOf(value) != -1;
215215 #end
216216 }
233233 return python.NativeStringTools.startswith(s, start);
234234 #elseif (js && js_es >= 6)
235235 return (cast s).startsWith(start);
236 #elseif lua
237 return untyped __lua__("{0}:sub(1, #{1}) == {1}", s, start);
236238 #else
237239 return (s.length >= start.length && s.lastIndexOf(start, 0) == 0);
238240 #end
258260 return python.NativeStringTools.endswith(s, end);
259261 #elseif (js && js_es >= 6)
260262 return (cast s).endsWith(end);
263 #elseif lua
264 return end == "" || untyped __lua__("{0}:sub(-#{1}) == {1}", s, end);
261265 #else
262266 var elen = end.length;
263267 var slen = s.length;
5656 /**
5757 Sets the value of the given environment variable.
5858
59 If `v` is `null`, the environment variable is removed.
60
5961 (java) This functionality is not available on Java; calling this function will throw.
6062 **/
61 static function putEnv(s:String, v:String):Void;
63 static function putEnv(s:String, v:Null<String>):Void;
6264
6365 /**
64 Returns all environment variables.
66 Returns a map of the current environment variables and their values
67 as of the invocation of the function.
68
69 (python) On Windows, the variable names are always in upper case.
70
71 (cpp)(hl)(neko) On Windows, the variable names match the last capitalization used when modifying
72 the variable if the variable has been modified, otherwise they match their capitalization at
73 the start of the process.
74
75 On Windows on remaining targets, variable name capitalization matches however they were capitalized
76 at the start of the process or at the moment of their creation.
6577 **/
6678 static function environment():Map<String, String>;
6779
2525 import haxe.iterators.StringKeyValueIteratorUnicode;
2626
2727 /**
28 This abstract provides consistent cross-target unicode support.
29
30 @see https://haxe.org/manual/std-UnicodeString.html
28 This abstract provides consistent cross-target unicode support for characters of any width.
29
30 Due to differing internal representations of strings across targets, only the basic
31 multilingual plane (BMP) is supported consistently by `String` class.
32
33 This abstract provides API to consistently handle all characters even beyond BMP.
34
35 @see https://haxe.org/manual/std-String-unicode.html
3136 **/
3237 @:forward
3338 @:access(StringTools)
2121
2222 package cpp;
2323
24 @:coreType @:notNull @:runtimeValue abstract Int64 from Int to Int {
24 @:coreType @:notNull @:runtimeValue abstract Int64 from Int {
25
26 /**
27 Destructively cast to Int
28 **/
29 public inline function toInt():Int {
30 return cast this;
31 }
32
33 @:to
34 @:deprecated("Implicit cast from Int64 to Int (32 bits) is deprecated. Use .toInt() or explicitly cast instead.")
35 inline function implicitToInt(): Int {
36 return toInt();
37 }
38
2539 @:to
2640 #if !cppia inline #end function toInt64():haxe.Int64 {
2741 return cast this;
0 /*
1 * Copyright (C)2005-2019 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package cpp;
23
24 import haxe.Int64;
25
26 @:headerClassCode("
27 inline void set(cpp::Int64 key, ::null value) { __int64_hash_set(HX_MAP_THIS,key,value); }
28 inline void set(cpp::Int64 key, bool value) { __int64_hash_set(HX_MAP_THIS,key,value); }
29 inline void set(cpp::Int64 key, char value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
30 inline void set(cpp::Int64 key, unsigned char value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
31 inline void set(cpp::Int64 key, signed char value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
32 inline void set(cpp::Int64 key, short value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
33 inline void set(cpp::Int64 key, unsigned short value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
34 inline void set(cpp::Int64 key, int value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
35 inline void set(cpp::Int64 key, unsigned int value) { __int64_hash_set_int(HX_MAP_THIS,key,value); }
36 inline void set(cpp::Int64 key, float value) { __int64_hash_set_float(HX_MAP_THIS,key,value); }
37 inline void set(cpp::Int64 key, double value) { __int64_hash_set_float(HX_MAP_THIS,key,value); }
38 inline void set(cpp::Int64 key, ::String value) { __int64_hash_set_string(HX_MAP_THIS,key,value); }
39 inline void set(cpp::Int64 key, cpp::Int64 value) { __int64_hash_set_int64(HX_MAP_THIS,key,value); }
40
41 template<typename V, typename H>
42 inline void set(cpp::Int64 key, const ::cpp::Struct<V,H> &value) {__int64_hash_set(HX_MAP_THIS,key,value); }
43 template<typename F>
44 inline void set(cpp::Int64 key, const ::cpp::Function<F> &value) {__int64_hash_set(HX_MAP_THIS,key,value); }
45 template<typename V>
46 inline void set(cpp::Int64 key, const ::cpp::Pointer<V> &value) {__int64_hash_set(HX_MAP_THIS,key,(Dynamic)value ); }
47
48 template<typename VALUE>
49 inline void set(Dynamic &key, const VALUE &value) { set( (cpp::Int64)key, value ); }
50
51 inline bool get_bool(cpp::Int64 key) { return __int64_hash_get_bool(h,key); }
52 inline int get_int(cpp::Int64 key) { return __int64_hash_get_int(h,key); }
53 inline Float get_float(cpp::Int64 key) { return __int64_hash_get_float(h,key); }
54 inline String get_string(cpp::Int64 key) { return __int64_hash_get_string(h,key); }
55 inline cpp::Int64 get_int64(cpp::Int64 key) { return __int64_hash_get_int64(h,key); }
56 ")
57 @:coreApi class Int64Map<T> implements haxe.Constraints.IMap<Int64, T> {
58 @:ifFeature("cpp.Int64Map.*")
59 private var h:Dynamic;
60
61 public function new():Void {}
62
63 public function set(key:Int64, value:T):Void {
64 untyped __global__.__int64_hash_set(__cpp__("HX_MAP_THIS"), key, value);
65 }
66
67 public function get(key:Int64):Null<T> {
68 return untyped __global__.__int64_hash_get(h, key);
69 }
70
71 public function exists(key:Int64):Bool {
72 return untyped __global__.__int64_hash_exists(h, key);
73 }
74
75 public function remove(key:Int64):Bool {
76 return untyped __global__.__int64_hash_remove(h, key);
77 }
78
79 public function keys():Iterator<Int64> {
80 var a:Array<Int64> = untyped __global__.__int64_hash_keys(h);
81 return a.iterator();
82 }
83
84 public function iterator():Iterator<T> {
85 var a:Array<Dynamic> = untyped __global__.__int64_hash_values(h);
86 return a.iterator();
87 }
88
89 @:runtime public inline function keyValueIterator():KeyValueIterator<Int64, T> {
90 return new haxe.iterators.MapKeyValueIterator(this);
91 }
92
93 public function copy():Int64Map<T> {
94 var copied = new Int64Map();
95 for (key in keys())
96 copied.set(key, get(key));
97 return copied;
98 }
99
100 public function toString():String {
101 return untyped __global__.__int64_hash_to_string(h);
102 }
103
104 public function clear():Void {
105 #if (hxcpp_api_level >= 400)
106 return untyped __global__.__int64_hash_clear(h);
107 #else
108 h = null;
109 #end
110 }
111
112 #if (scriptable)
113 private function setString(key:Int64, val:String):Void {
114 untyped __int64_hash_set_string(__cpp__("HX_MAP_THIS"), key, val);
115 }
116
117 private function setInt(key:Int64, val:Int):Void {
118 untyped __int64_hash_set_int(__cpp__("HX_MAP_THIS"), key, val);
119 }
120
121 private function setBool(key:Int64, val:Bool):Void {
122 untyped __int64_hash_set_int(__cpp__("HX_MAP_THIS"), key, val);
123 }
124
125 private function setFloat(key:Int64, val:Float):Void {
126 untyped __int64_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
127 }
128
129 private function setInt64(key:Int64, val:Int64):Void {
130 untyped __int64_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
131 }
132
133 private function getString(key:Int64):String {
134 return untyped __int64_hash_get_string(h, key);
135 }
136
137 private function getInt(key:Int64):Int {
138 return untyped __int64_hash_get_int(h, key);
139 }
140
141 private function getBool(key:Int64):Bool {
142 return untyped __int64_hash_get_bool(h, key);
143 }
144
145 private function getFloat(key:Int64):Float {
146 return untyped __int64_hash_get_float(h, key);
147 }
148
149 private function getInt64(key:Int64):Int64 {
150 return untyped __int64_hash_get_int64(h, key);
151 }
152 #end
153 }
7878 }
7979
8080 @:noDebug @:native("HX_STACK_DO_RETHROW")
81 extern static function do_rethrow(inExp:Dynamic);
81 extern static function do_rethrow(inExp:Dynamic):Void;
8282
8383 @:noDebug #if (!cppia) inline #end
8484 public static function rethrow(inExp:Dynamic) {
4242 static function process_stdin_close(handle:Dynamic):Void;
4343
4444 @:native("_hx_std_process_exit")
45 static function process_exit(handle:Dynamic):Int;
45 static function process_exit(handle:Dynamic, block:Bool):Dynamic;
4646
4747 @:native("_hx_std_process_pid")
4848 static function process_pid(handle:Dynamic):Int;
3333 extern static function get_env(v:String):String;
3434
3535 @:native("_hx_std_put_env")
36 extern static function put_env(e:String, v:String):Void;
36 extern static function put_env(e:String, v:Null<String>):Void;
3737
3838 @:native("_hx_std_sys_sleep")
3939 extern static function sys_sleep(f:Float):Void;
220220 function new():Void {}
221221
222222 @:native("parse_xml")
223 extern static function parse_xml(str:String, state:NativeXmlState);
223 extern static function parse_xml(str:String, state:NativeXmlState):String;
224224
225225 public static function parse(str:String):Xml {
226226 var x = new Xml();
2121
2222 package cpp;
2323
24 @:coreType @:notNull @:runtimeValue abstract UInt64 from Int to Int {}
24 @:coreType @:notNull @:runtimeValue abstract UInt64 from Int {
25
26 /**
27 Destructively cast to Int
28 **/
29 public inline function toInt():Int {
30 return cast this;
31 }
32
33 @:to
34 @:deprecated("Implicit cast from UInt64 to Int (32 bits) is deprecated. Use .toInt() or explicitly cast instead.")
35 inline function implicitToInt(): Int {
36 return toInt();
37 }
38
39 }
6262 return v;
6363 }
6464
65 public static function putEnv(s:String, v:String):Void {
65 public static function putEnv(s:String, v:Null<String>):Void {
6666 NativeSys.put_env(s, v);
6767 }
6868
2121
2222 package haxe;
2323
24 import haxe.Int64Helper;
25
26 @:notNull
2724 @:include("cpp/Int64.h")
28 @:native("cpp::Int64Struct")
29 private extern class ___Int64 {
30
25 private extern class NativeInt64Helper {
3126 @:native("_hx_int64_make")
3227 static function make(high:Int32, low:Int32):__Int64;
3328
131126 static function low(a:__Int64):Int32;
132127 }
133128
134 private typedef __Int64 = ___Int64;
129 private typedef __Int64 = cpp.Int64;
135130
136131 @:coreApi
137132 @:transitive
138 abstract Int64(__Int64) from __Int64 to __Int64 {
133 @:notNull
134 abstract Int64(__Int64) from __Int64 from Int to __Int64 {
139135 public #if !cppia inline #end function copy():Int64
140136 return this;
141137
142138 public static #if !cppia inline #end function make(high:Int32, low:Int32):Int64 {
143 return __Int64.make(high, low);
144 }
145
146 @:from
139 return NativeInt64Helper.make(high, low);
140 }
141
147142 public static #if !cppia inline #end function ofInt(x:Int):Int64 {
148 return __Int64.ofInt(x);
143 return x;
149144 }
150145
151146 public static #if !cppia inline #end function toInt(x:Int64):Int {
157152
158153 @:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead')
159154 inline public static function is(val:Dynamic):Bool {
160 return isInt64(val);
155 return val is cpp.Int64;
161156 }
162157
163158 public static #if !cppia inline #end function isInt64(val:Dynamic):Bool
164 return __Int64.isInt64(val);
159 return val is cpp.Int64;
165160
166161 @:deprecated("Use high instead")
167162 public static #if !cppia inline #end function getHigh(x:Int64):Int32
172167 return x.low;
173168
174169 public static #if !cppia inline #end function isNeg(x:Int64):Bool
175 return __Int64.isNeg(x);
170 return NativeInt64Helper.isNeg(x);
176171
177172 public static #if !cppia inline #end function isZero(x:Int64):Bool
178 return __Int64.isZero(x);
173 return NativeInt64Helper.isZero(x);
179174
180175 public static #if !cppia inline #end function compare(a:Int64, b:Int64):Int
181 return __Int64.compare(a, b);
176 return NativeInt64Helper.compare(a, b);
182177
183178 public static #if !cppia inline #end function ucompare(a:Int64, b:Int64):Int
184 return __Int64.ucompare(a, b);
179 return NativeInt64Helper.ucompare(a, b);
185180
186181 public static #if !cppia inline #end function toStr(x:Int64):String
187 return x.toString();
182 return cast x.val;
188183
189184 private #if !cppia inline #end function toString():String
190 return __Int64.toString(this);
185 return cast this;
191186
192187 public static function parseString(sParam:String):Int64 {
193188 return Int64Helper.parseString(sParam);
200195 public static function divMod(dividend:Int64, divisor:Int64):{quotient:Int64, modulus:Int64} {
201196 var q = dividend / divisor;
202197
203 if (isZero(divisor))
198 if (divisor == 0)
204199 throw "divide by zero";
205200
206201 var m = dividend - q * divisor;
208203 return {quotient: q, modulus: m};
209204 }
210205
211 @:op(-A)
206 @:op(-A)
212207 public static #if !cppia inline #end function neg(x:Int64):Int64
213 return __Int64.neg(x);
208 return NativeInt64Helper.neg(x);
214209
215210 @:op(++A) private inline function preIncrement():Int64 {
216211 #if cppia
217212 this = this + make(0, 1);
218213 return this;
219214 #else
220 return __Int64.preIncrement(this);
215 return NativeInt64Helper.preIncrement(this);
221216 #end
222217 }
223218
227222 this = this + make(0, 1);
228223 return result;
229224 #else
230 return __Int64.postIncrement(this);
225 return NativeInt64Helper.postIncrement(this);
231226 #end
232227 }
233228
236231 untyped this = this - make(0, 1);
237232 return this;
238233 #else
239 return __Int64.preDecrement(this);
234 return NativeInt64Helper.preDecrement(this);
240235 #end
241236 }
242237
246241 this = this - make(0, 1);
247242 return result;
248243 #else
249 return __Int64.postDecrement(this);
244 return NativeInt64Helper.postDecrement(this);
250245 #end
251246 }
252247
253248 @:op(A + B)
254249 public static #if !cppia inline #end function add(a:Int64, b:Int64):Int64
255 return __Int64.add(a, b);
250 return NativeInt64Helper.add(a, b);
256251
257252 @:op(A + B)
258253 @:commutative
259254 private static #if !cppia inline #end function addInt(a:Int64, b:Int):Int64
260 return __Int64.addInt(a, b);
255 return NativeInt64Helper.addInt(a, b);
261256
262257 @:op(A - B)
263258 public static #if !cppia inline #end function sub(a:Int64, b:Int64):Int64 {
264 return __Int64.sub(a, b);
259 return NativeInt64Helper.sub(a, b);
265260 }
266261
267262 @:op(A - B)
268263 private static #if !cppia inline #end function subInt(a:Int64, b:Int):Int64
269 return __Int64.subInt(a, b);
264 return NativeInt64Helper.subInt(a, b);
270265
271266 @:op(A - B)
272267 private static #if !cppia inline #end function intSub(a:Int, b:Int64):Int64
273 return __Int64.intSub(a, b);
268 return NativeInt64Helper.intSub(a, b);
274269
275270 @:op(A * B)
276271 public static #if !cppia inline #end function mul(a:Int64, b:Int64):Int64
277 return __Int64.mul(a, b);
272 return NativeInt64Helper.mul(a, b);
278273
279274 @:op(A * B)
280275 @:commutative
283278
284279 @:op(A / B)
285280 public static #if !cppia inline #end function div(a:Int64, b:Int64):Int64 {
286 if (__Int64.isZero(b))
281 if (NativeInt64Helper.isZero(b))
287282 throw "divide by zero";
288 return __Int64.div(a, b);
283 return NativeInt64Helper.div(a, b);
289284 }
290285
291286 @:op(A / B)
298293
299294 @:op(A % B)
300295 public static #if !cppia inline #end function mod(a:Int64, b:Int64):Int64 {
301 if (__Int64.isZero(b))
296 if (NativeInt64Helper.isZero(b))
302297 throw "divide by zero";
303 return __Int64.mod(a, b);
298 return NativeInt64Helper.mod(a, b);
304299 }
305300
306301 @:op(A % B)
313308
314309 @:op(A == B)
315310 public static #if !cppia inline #end function eq(a:Int64, b:Int64):Bool
316 return __Int64.eq(a, b);
311 return NativeInt64Helper.eq(a, b);
317312
318313 @:op(A == B)
319314 @:commutative
320315 private static #if !cppia inline #end function eqInt(a:Int64, b:Int):Bool
321 return __Int64.eqInt(a, b);
316 return NativeInt64Helper.eqInt(a, b);
322317
323318 @:op(A != B)
324319 public static #if !cppia inline #end function neq(a:Int64, b:Int64):Bool
325 return __Int64.neq(a, b);
320 return NativeInt64Helper.neq(a, b);
326321
327322 @:op(A != B)
328323 @:commutative
379374
380375 @:op(~A)
381376 private static #if !cppia inline #end function complement(a:Int64):Int64
382 return __Int64.complement(a);
377 return NativeInt64Helper.complement(a);
383378
384379 @:op(A & B)
385380 public static #if !cppia inline #end function and(a:Int64, b:Int64):Int64
386 return __Int64.bitAnd(a, b);
381 return NativeInt64Helper.bitAnd(a, b);
387382
388383 @:op(A | B)
389384 public static #if !cppia inline #end function or(a:Int64, b:Int64):Int64
390 return __Int64.bitOr(a, b);
385 return NativeInt64Helper.bitOr(a, b);
391386
392387 @:op(A ^ B)
393388 public static #if !cppia inline #end function xor(a:Int64, b:Int64):Int64
394 return __Int64.bitXor(a, b);
389 return NativeInt64Helper.bitXor(a, b);
395390
396391 @:op(A << B)
397392 public static #if !cppia inline #end function shl(a:Int64, b:Int):Int64
398 return __Int64.shl(a, b);
393 return NativeInt64Helper.shl(a, b);
399394
400395 @:op(A >> B)
401396 public static #if !cppia inline #end function shr(a:Int64, b:Int):Int64
402 return __Int64.shr(a, b);
397 return NativeInt64Helper.shr(a, b);
403398
404399 @:op(A >>> B)
405400 public static #if !cppia inline #end function ushr(a:Int64, b:Int):Int64
406 return __Int64.ushr(a, b);
401 return NativeInt64Helper.ushr(a, b);
407402
408403 public var high(get, never):Int32;
409404
410405 private #if !cppia inline #end function get_high():Int32
411 return __Int64.high(this);
406 return NativeInt64Helper.high(this);
412407
413408 public var low(get, never):Int32;
414409
415410 private #if !cppia inline #end function get_low():Int32
416 return __Int64.low(this);
411 return NativeInt64Helper.low(this);
412
413 private var val(get, never):__Int64;
414
415 private #if !cppia inline #end function get_val():__Int64
416 return this;
417417 }
0 package haxe.atomic;
1
2 #if cppia
3 extern
4 #end
5 abstract AtomicInt(cpp.Pointer<Int>) {
6 public #if !(scriptable || cppia) inline #end function new(value:Int) {
7 this = cpp.Pointer.ofArray([value]);
8 }
9
10 public #if !(scriptable || cppia) inline #end function add(b:Int):Int {
11 return untyped __cpp__("_hx_atomic_add({0}, {1})", this, b);
12 }
13
14 public #if !(scriptable || cppia) inline #end function sub(b:Int):Int {
15 return untyped __cpp__("_hx_atomic_sub({0}, {1})", this, b);
16 }
17
18 public #if !(scriptable || cppia) inline #end function and(b:Int):Int {
19 return untyped __cpp__("_hx_atomic_and({0}, {1})", this, b);
20 }
21
22 public #if !(scriptable || cppia) inline #end function or(b:Int):Int {
23 return untyped __cpp__("_hx_atomic_or({0}, {1})", this, b);
24 }
25
26 public #if !(scriptable || cppia) inline #end function xor(b:Int):Int {
27 return untyped __cpp__("_hx_atomic_xor({0}, {1})", this, b);
28 }
29
30 public #if !(scriptable || cppia) inline #end function compareExchange(expected:Int, replacement:Int):Int {
31 return untyped __cpp__("_hx_atomic_compare_exchange({0}, {1}, {2})", this, expected, replacement);
32 }
33
34 public #if !(scriptable || cppia) inline #end function exchange(value:Int):Int {
35 return untyped __cpp__("_hx_atomic_exchange({0}, {1})", this, value);
36 }
37
38 public #if !(scriptable || cppia) inline #end function load():Int {
39 return untyped __cpp__("_hx_atomic_load({0})", this);
40 }
41
42 public #if !(scriptable || cppia) inline #end function store(value:Int):Int {
43 return untyped __cpp__("_hx_atomic_store({0}, {1})", this, value);
44 }
45 }
3434 inline void set(int key, float value) { __int_hash_set_float(HX_MAP_THIS,key,value); }
3535 inline void set(int key, double value) { __int_hash_set_float(HX_MAP_THIS,key,value); }
3636 inline void set(int key, ::String value) { __int_hash_set_string(HX_MAP_THIS,key,value); }
37 inline void set(int key, cpp::Int64 value) { __int_hash_set_int64(HX_MAP_THIS,key,value); }
3738
3839 template<typename V, typename H>
3940 inline void set(int key, const ::cpp::Struct<V,H> &value) {__int_hash_set(HX_MAP_THIS,key,value); }
4950 inline int get_int(int key) { return __int_hash_get_int(h,key); }
5051 inline Float get_float(int key) { return __int_hash_get_float(h,key); }
5152 inline String get_string(int key) { return __int_hash_get_string(h,key); }
53 inline cpp::Int64 get_int64(int key) { return __int_hash_get_int64(h,key); }
5254 ")
5355 @:coreApi class IntMap<T> implements haxe.Constraints.IMap<Int, T> {
5456 @:ifFeature("haxe.ds.IntMap.*")
122124 untyped __int_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
123125 }
124126
127 private function setInt64(key:Int, val:haxe.Int64):Void {
128 untyped __int_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
129 }
130
125131 private function getString(key:Int):String {
126132 return untyped __int_hash_get_string(h, key);
127133 }
137143 private function getFloat(key:Int):Float {
138144 return untyped __int_hash_get_float(h, key);
139145 }
146
147 private function getInt64(key:Int):haxe.Int64 {
148 return untyped __int_hash_get_int64(h, key);
149 }
140150 #end
141151 }
0 /*
1 * Copyright (C)2005-2019 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package haxe.ds;
23
24 import haxe.Int64;
25 import haxe.ds.StringMap;
26 import haxe.ds.IntMap;
27 import haxe.ds.HashMap;
28 import haxe.ds.ObjectMap;
29 import haxe.ds.WeakMap;
30 import haxe.ds.EnumValueMap;
31 import haxe.Constraints.IMap;
32 import cpp.Int64Map;
33
34 /**
35 Map allows key to value mapping for arbitrary value types, and many key
36 types.
37
38 This is a multi-type abstract, it is instantiated as one of its
39 specialization types depending on its type parameters.
40
41 A Map can be instantiated without explicit type parameters. Type inference
42 will then determine the type parameters from the usage.
43
44 Maps can also be created with `[key1 => value1, key2 => value2]` syntax.
45
46 Map is an abstract type, it is not available at runtime.
47
48 @see https://haxe.org/manual/std-Map.html
49 **/
50 @:transitive
51 @:multiType(@:followWithAbstracts K)
52 abstract Map<K, V>(IMap<K, V>) {
53 /**
54 Creates a new Map.
55
56 This becomes a constructor call to one of the specialization types in
57 the output. The rules for that are as follows:
58
59 1. if `K` is a `String`, `haxe.ds.StringMap` is used
60 2. if `K` is an `Int`, `haxe.ds.IntMap` is used
61 3. if `K` is an `EnumValue`, `haxe.ds.EnumValueMap` is used
62 4. if `K` is any other class or structure, `haxe.ds.ObjectMap` is used
63 5. if `K` is any other type, it causes a compile-time error
64
65 (Cpp) Map does not use weak keys on `ObjectMap` by default.
66 **/
67 public function new();
68
69 /**
70 Maps `key` to `value`.
71
72 If `key` already has a mapping, the previous value disappears.
73
74 If `key` is `null`, the result is unspecified.
75 **/
76 public inline function set(key:K, value:V)
77 this.set(key, value);
78
79 /**
80 Returns the current mapping of `key`.
81
82 If no such mapping exists, `null` is returned.
83
84 Note that a check like `map.get(key) == null` can hold for two reasons:
85
86 1. the map has no mapping for `key`
87 2. the map has a mapping with a value of `null`
88
89 If it is important to distinguish these cases, `exists()` should be
90 used.
91
92 If `key` is `null`, the result is unspecified.
93 **/
94 @:arrayAccess public inline function get(key:K)
95 return this.get(key);
96
97 /**
98 Returns true if `key` has a mapping, false otherwise.
99
100 If `key` is `null`, the result is unspecified.
101 **/
102 public inline function exists(key:K)
103 return this.exists(key);
104
105 /**
106 Removes the mapping of `key` and returns true if such a mapping existed,
107 false otherwise.
108
109 If `key` is `null`, the result is unspecified.
110 **/
111 public inline function remove(key:K)
112 return this.remove(key);
113
114 /**
115 Returns an Iterator over the keys of `this` Map.
116
117 The order of keys is undefined.
118 **/
119 public inline function keys():Iterator<K> {
120 return this.keys();
121 }
122
123 /**
124 Returns an Iterator over the values of `this` Map.
125
126 The order of values is undefined.
127 **/
128 public inline function iterator():Iterator<V> {
129 return this.iterator();
130 }
131
132 /**
133 Returns an Iterator over the keys and values of `this` Map.
134
135 The order of values is undefined.
136 **/
137 public inline function keyValueIterator():KeyValueIterator<K, V> {
138 return this.keyValueIterator();
139 }
140
141 /**
142 Returns a shallow copy of `this` map.
143
144 The order of values is undefined.
145 **/
146 public inline function copy():Map<K, V> {
147 return cast this.copy();
148 }
149
150 /**
151 Returns a String representation of `this` Map.
152
153 The exact representation depends on the platform and key-type.
154 **/
155 public inline function toString():String {
156 return this.toString();
157 }
158
159 /**
160 Removes all keys from `this` Map.
161 **/
162 public inline function clear():Void {
163 this.clear();
164 }
165
166 @:arrayAccess @:noCompletion public inline function arrayWrite(k:K, v:V):V {
167 this.set(k, v);
168 return v;
169 }
170
171 @:to static inline function toStringMap<K:String, V>(t:IMap<K, V>):StringMap<V> {
172 return new StringMap<V>();
173 }
174
175 @:to static inline function toIntMap<K:Int, V>(t:IMap<K, V>):IntMap<V> {
176 return new IntMap<V>();
177 }
178
179 @:noDoc
180 @:to static inline function toInt64Map<K:Int64, V>(t:IMap<K, V>):Int64Map<V> {
181 return new Int64Map<V>();
182 }
183
184 @:to static inline function toEnumValueMapMap<K:EnumValue, V>(t:IMap<K, V>):EnumValueMap<K, V> {
185 return new EnumValueMap<K, V>();
186 }
187
188 @:to static inline function toObjectMap<K:{}, V>(t:IMap<K, V>):ObjectMap<K, V> {
189 return new ObjectMap<K, V>();
190 }
191
192 @:from static inline function fromStringMap<V>(map:StringMap<V>):Map<String, V> {
193 return cast map;
194 }
195
196 @:from static inline function fromIntMap<V>(map:IntMap<V>):Map<Int, V> {
197 return cast map;
198 }
199
200 @:noDoc
201 @:from static inline function fromInt64Map<V>(map:Int64Map<V>):Map<Int64, V> {
202 return cast map;
203 }
204
205 @:from static inline function fromObjectMap<K:{}, V>(map:ObjectMap<K, V>):Map<K, V> {
206 return cast map;
207 }
208 }
3434 inline void set(Dynamic key, float value) { __object_hash_set_float(HX_MAP_THIS,key,value); }
3535 inline void set(Dynamic key, double value) { __object_hash_set_float(HX_MAP_THIS,key,value); }
3636 inline void set(Dynamic key, ::String value) { __object_hash_set_string(HX_MAP_THIS,key,value); }
37 inline void set(Dynamic key, cpp::Int64 value) { __object_hash_set_int64(HX_MAP_THIS,key,value); }
3738
3839
3940 template<typename V, typename H>
4748 inline int get_int(Dynamic key) { return __object_hash_get_int(h,key); }
4849 inline Float get_float(Dynamic key) { return __object_hash_get_float(h,key); }
4950 inline String get_string(Dynamic key) { return __object_hash_get_string(h,key); }
50
51 inline cpp::Int64 get_int64(Dynamic key) { return __object_hash_get_int64(h,key); }
5152 ")
5253 @:coreApi
5354 class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
122123 untyped __object_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
123124 }
124125
126 private function setInt64(key:Dynamic, val:haxe.Int64):Void {
127 untyped __object_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
128 }
129
125130 private function getString(key:Dynamic):String {
126131 return untyped __object_hash_get_string(h, key);
127132 }
137142 private function getFloat(key:Dynamic):Float {
138143 return untyped __object_hash_get_float(h, key);
139144 }
145
146 private function getInt64(key:Dynamic):haxe.Int64 {
147 return untyped __object_hash_get_int64(h, key);
148 }
140149 #end
141150 }
3434 inline void set(String key, float value) { __string_hash_set_float(HX_MAP_THIS,key,value); }
3535 inline void set(String key, double value) { __string_hash_set_float(HX_MAP_THIS,key,value); }
3636 inline void set(String key, ::String value) { __string_hash_set_string(HX_MAP_THIS,key,value); }
37 inline void set(String key, cpp::Int64 value) { __string_hash_set_int64(HX_MAP_THIS,key,value); }
3738
3839 template<typename V, typename H>
3940 inline void set(String key, const ::cpp::Struct<V,H> &value) {__string_hash_set(HX_MAP_THIS,key,value); }
4950 inline int get_int(String key) { return __string_hash_get_int(h,key); }
5051 inline Float get_float(String key) { return __string_hash_get_float(h,key); }
5152 inline String get_string(String key) { return __string_hash_get_string(h,key); }
53 inline cpp::Int64 get_int64(String key) { return __string_hash_get_int64(h,key); }
5254 ")
5355 @:coreApi class StringMap<T> implements haxe.Constraints.IMap<String, T> {
5456 @:ifFeature("haxe.ds.StringMap.*")
122124 untyped __string_hash_set_float(__cpp__("HX_MAP_THIS"), key, val);
123125 }
124126
127 private function setInt64(key:String, val:haxe.Int64):Void {
128 untyped __string_hash_set_int64(__cpp__("HX_MAP_THIS"), key, val);
129 }
130
125131 private function getString(key:String):String {
126132 return untyped __string_hash_get_string(h, key);
127133 }
137143 private function getFloat(key:String):Float {
138144 return untyped __string_hash_get_float(h, key);
139145 }
146
147 private function getInt64(key:String):haxe.Int64 {
148 return untyped __string_hash_get_int64(h, key);
149 }
140150 #end
141151 }
3434 inline void set(Dynamic key, float value) { __object_hash_set_float(HX_MAP_THIS,key,value,true); }
3535 inline void set(Dynamic key, double value) { __object_hash_set_float(HX_MAP_THIS,key,value,true); }
3636 inline void set(Dynamic key, ::String value) { __object_hash_set_string(HX_MAP_THIS,key,value,true); }
37 inline void set(Dynamic key, cpp::Int64 value) { __object_hash_set_int64(HX_MAP_THIS,key,value,true); }
3738
3839 template<typename V, typename H>
3940 inline void set(Dynamic key, const ::cpp::Struct<V,H> &value) {__object_hash_set(HX_MAP_THIS,key,value,true); }
104104 }
105105
106106 public function exitCode(block:Bool = true):Null<Int> {
107 if (block == false)
108 throw "Non blocking exitCode() not supported on this platform";
109 return NativeProcess.process_exit(p);
107 return NativeProcess.process_exit(p, block);
110108 }
111109
112110 public function close():Void {
0 package sys.thread;
1
2 @:coreApi
3 class Condition {
4 var c:Dynamic;
5 public function new():Void {
6 c = untyped __global__.__hxcpp_condition_create();
7 }
8
9 public function acquire():Void {
10 untyped __global__.__hxcpp_condition_acquire(c);
11 }
12
13 public function tryAcquire():Bool {
14 return untyped __global__.__hxcpp_condition_try_acquire(c);
15 }
16
17 public function release():Void {
18 untyped __global__.__hxcpp_condition_release(c);
19 }
20
21 public function wait():Void {
22 untyped __global__.__hxcpp_condition_wait(c);
23 }
24
25 public function signal():Void {
26 untyped __global__.__hxcpp_condition_signal(c);
27 }
28
29 public function broadcast():Void {
30 untyped __global__.__hxcpp_condition_broadcast(c);
31 }
32 }
0 package sys.thread;
1
2 @:coreApi
3 class Semaphore {
4 var m:Dynamic;
5
6 public function new(value:Int) {
7 m = untyped __global__.__hxcpp_semaphore_create(value);
8 }
9
10 public function acquire():Void {
11 untyped __global__.__hxcpp_semaphore_acquire(m);
12 }
13
14 public function tryAcquire(?timeout:Float):Bool {
15 return untyped __global__.__hxcpp_semaphore_try_acquire(m, timeout == null ? 0 : (timeout:Float));
16 }
17
18 public function release():Void {
19 untyped __global__.__hxcpp_semaphore_release(m);
20 }
21 }
4545 "sys.thread.Mutex",
4646 "sys.thread.Thread",
4747 "sys.thread.Tls",
48 "sys.thread.Semaphore",
49 "sys.thread.Condition",
4850 "cpp.vm.ExecutionTrace",
4951 "cpp.vm.Gc",
5052 "cpp.vm.Profiler",
5254 "cpp.vm.WeakRef",
5355 "cpp.Object",
5456 "cpp.Int64",
57 "cpp.Int64Map",
5558 "cpp.Finalizable",
5659 "Std",
5760 "StringBuf",
146149 "List",
147150 "Map",
148151 "String",
152 "haxe.atomic.AtomicInt"
149153 ];
150154
151155 static function parseClassInfo(externs:Map<String, Bool>, filename:String) {
2222 import cs.Boot;
2323 import cs.Lib;
2424
25 using StringTools;
26
2527 @:coreApi @:nativeGen class Std {
2628 @:deprecated('Std.is is deprecated. Use Std.isOfType instead.')
2729 public static inline function is(v:Dynamic, t:Dynamic):Bool {
7880 return cast x;
7981 }
8082
83 static inline function isSpaceChar(code:Int):Bool
84 return (code > 8 && code < 14) || code == 32;
85
86 static inline function isHexPrefix(cur:Int, next:Int):Bool
87 return cur == '0'.code && (next == 'x'.code || next == 'X'.code);
88
89 static inline function isDecimalDigit(code:Int):Bool
90 return '0'.code <= code && code <= '9'.code;
91
92 static inline function isHexadecimalDigit(code:Int):Bool
93 return isDecimalDigit(code) || ('a'.code <= code && code <= 'f'.code) || ('A'.code <= code && code <= 'F'.code);
94
8195 public static function parseInt(x:String):Null<Int> {
8296 if (x == null)
8397 return null;
8498
85 var base = 10;
86 var len = x.length;
87 var foundCount = 0;
88 var sign = 0;
89 var firstDigitIndex = 0;
90 var lastDigitIndex = -1;
91 var previous = 0;
92
93 for(i in 0...len) {
94 var c = StringTools.fastCodeAt(x, i);
95 switch c {
96 case _ if((c > 8 && c < 14) || c == 32):
97 if(foundCount > 0) {
98 return null;
99 }
100 continue;
101 case '-'.code if(foundCount == 0):
102 sign = -1;
103 case '+'.code if(foundCount == 0):
104 sign = 1;
105 case '0'.code if(foundCount == 0 || (foundCount == 1 && sign != 0)):
106 case 'x'.code | 'X'.code if(previous == '0'.code && ((foundCount == 1 && sign == 0) || (foundCount == 2 && sign != 0))):
107 base = 16;
108 case _ if('0'.code <= c && c <= '9'.code):
109 case _ if(base == 16 && (('a'.code <= c && c <= 'z'.code) || ('A'.code <= c && c <= 'Z'.code))):
110 case _:
111 break;
99 final len = x.length;
100 var index = 0;
101
102 inline function hasIndex(index:Int)
103 return index < len;
104
105 // skip whitespace
106 while (hasIndex(index)) {
107 if (!isSpaceChar(x.unsafeCodeAt(index)))
108 break;
109 ++index;
110 }
111
112 // handle sign
113 final isNegative = hasIndex(index) && {
114 final sign = x.unsafeCodeAt(index);
115 if (sign == '-'.code || sign == '+'.code) {
116 ++index;
112117 }
113 if((foundCount == 0 && sign == 0) || (foundCount == 1 && sign != 0)) {
114 firstDigitIndex = i;
118 sign == '-'.code;
119 }
120
121 // handle base
122 final isHexadecimal = hasIndex(index + 1) && isHexPrefix(x.unsafeCodeAt(index), x.unsafeCodeAt(index + 1));
123 if (isHexadecimal)
124 index += 2; // skip prefix
125
126 // handle digits
127 final firstInvalidIndex = {
128 var cur = index;
129 if (isHexadecimal) {
130 while (hasIndex(cur)) {
131 if (!isHexadecimalDigit(x.unsafeCodeAt(cur)))
132 break;
133 ++cur;
134 }
135 } else {
136 while (hasIndex(cur)) {
137 if (!isDecimalDigit(x.unsafeCodeAt(cur)))
138 break;
139 ++cur;
140 }
115141 }
116 foundCount++;
117 lastDigitIndex = i;
118 previous = c;
119 }
120 if(firstDigitIndex <= lastDigitIndex) {
121 var digits = x.substring(firstDigitIndex, lastDigitIndex + 1);
122 return try {
123 (sign == -1 ? -1 : 1) * cs.system.Convert.ToInt32(digits, base);
124 } catch(e:cs.system.FormatException) {
125 null;
126 }
127 }
128 return null;
142 cur;
143 }
144
145 // no valid digits
146 if (index == firstInvalidIndex)
147 return null;
148
149 final result = cs.system.Convert.ToInt32(x.substring(index, firstInvalidIndex), if (isHexadecimal) 16 else 10);
150 return if (isNegative) -result else result;
129151 }
130152
131153 public static function parseFloat(x:String):Float {
2525
2626 @:coreApi
2727 class Sys {
28 private static var _env:haxe.ds.StringMap<String>;
2928 private static var _args:Array<String>;
3029
3130 public static inline function print(v:Dynamic):Void {
4948 return Environment.GetEnvironmentVariable(s);
5049 }
5150
52 public static function putEnv(s:String, v:String):Void {
51 public static function putEnv(s:String, v:Null<String>):Void {
5352 Environment.SetEnvironmentVariable(s, v);
54 if (_env != null)
55 _env.set(s, v);
5653 }
5754
5855 public static function environment():Map<String, String> {
59 if (_env == null) {
60 var e = _env = new haxe.ds.StringMap();
61 var nenv = Environment.GetEnvironmentVariables().GetEnumerator();
62 while (nenv.MoveNext()) {
63 e.set(nenv.Key, nenv.Value);
64 }
56 final env = new haxe.ds.StringMap();
57 final nenv = Environment.GetEnvironmentVariables().GetEnumerator();
58 while (nenv.MoveNext()) {
59 env.set(nenv.Key, nenv.Value);
6560 }
66
67 return _env;
61 return env;
6862 }
6963
7064 public static inline function sleep(seconds:Float):Void {
7771 }
7872
7973 public static inline function getCwd():String {
80 return cs.system.io.Directory.GetCurrentDirectory();
74 return haxe.io.Path.addTrailingSlash(cs.system.io.Directory.GetCurrentDirectory());
8175 }
8276
8377 public static inline function setCwd(s:String):Void {
00 package haxe;
11
2 import cs.NativeArray;
3 import cs.system.Array as CsArray;
24 import haxe.iterators.RestIterator;
35 import haxe.iterators.RestKeyValueIterator;
4 import cs.NativeArray;
5 import cs.system.Array as CsArray;
66
77 private typedef NativeRest<T> = #if erase_generics NativeArray<Dynamic> #else NativeArray<T> #end;
88
99 @:coreApi
1010 abstract Rest<T>(NativeRest<T>) {
11 public var length(get,never):Int;
11 public var length(get, never):Int;
12
1213 inline function get_length():Int
1314 return this.Length;
1415
1516 @:from static public inline function of<T>(array:Array<T>):Rest<T>
17 #if erase_generics
18 // This is wrong but so is everything else in my life
1619 return new Rest(@:privateAccess array.__a);
20 #else
21 return new Rest(cs.Lib.nativeArray(array, false));
22 #end
1723
1824 inline function new(a:NativeRest<T>):Void
1925 this = a;
5056 public function toString():String {
5157 return toArray().toString();
5258 }
53 }
59 }
0 package haxe.atomic;
1
2 private class IntWrapper {
3 public var value:Int;
4
5 public function new(value:Int) {
6 this.value = value;
7 }
8 }
9
10 abstract AtomicInt(IntWrapper) {
11 public inline function new(value:Int) {
12 this = new IntWrapper(value);
13 }
14
15 private inline function cas_loop(value:Int, op:(a:Int, b:Int) -> Int):Int {
16 var oldValue;
17 var newValue;
18 do {
19 oldValue = load();
20 newValue = op(oldValue, value);
21 } while(compareExchange(oldValue, newValue) != oldValue);
22 return oldValue;
23 }
24
25 public inline function add(b:Int):Int {
26 return cas_loop(b, (a, b) -> a + b);
27 }
28
29 public inline function sub(b:Int):Int {
30 return cas_loop(b, (a, b) -> a - b);
31 }
32
33 public inline function and(b:Int):Int {
34 return cas_loop(b, (a, b) -> cast a & b);
35 }
36
37 public inline function or(b:Int):Int {
38 return cas_loop(b, (a, b) -> cast a | b);
39 }
40
41 public inline function xor(b:Int):Int {
42 return cas_loop(b, (a, b) -> cast a ^ b);
43 }
44
45 public inline function compareExchange(expected:Int, replacement:Int):Int {
46 return cs.Syntax.code("System.Threading.Interlocked.CompareExchange(ref ({0}).value, {1}, {2})", this, replacement, expected);
47 }
48
49 public inline function exchange(value:Int):Int {
50 return cs.Syntax.code("System.Threading.Interlocked.Exchange(ref ({0}).value, {1})", this, value);
51 }
52
53 public inline function load():Int {
54 return this.value; // according to the CLI spec reads and writes are atomic
55 }
56
57 public inline function store(value:Int):Int {
58 return this.value = value; // according to the CLI spec reads and writes are atomic
59 }
60 }
0 package haxe.atomic;
1
2 import cs.system.threading.Interlocked.*;
3
4 private class ObjectWrapper<T:{}> {
5 public var value:T;
6
7 public function new(value:T) {
8 this.value = value;
9 }
10 }
11
12 extern abstract AtomicObject<T:{}>(ObjectWrapper<T>) {
13 public inline function new(value:T) {
14 this = new ObjectWrapper(value);
15 }
16
17 public inline function compareExchange(expected:T, replacement:T):T {
18 return cs.Syntax.code("System.Threading.Interlocked.CompareExchange(ref ({0}).value, {1}, {2})", this, replacement, expected);
19 }
20
21 public inline function exchange(value:T):T {
22 return cs.Syntax.code("System.Threading.Interlocked.Exchange(ref ({0}).value, {1})", this, value);
23 }
24
25 public inline function load():T {
26 return this.value; // according to the CLI spec reads and writes are atomic
27 }
28
29 public inline function store(value:T):T {
30 return this.value = value; // according to the CLI spec reads and writes are atomic
31 }
32 }
363363
364364 public function toString():String {
365365 var s = new StringBuf();
366 s.add("{");
366 s.add("[");
367367 var it = keys();
368368 for (i in it) {
369369 s.add(i);
372372 if (it.hasNext())
373373 s.add(", ");
374374 }
375 s.add("}");
375 s.add("]");
376376 return s.toString();
377377 }
378378
377377
378378 public function toString():String {
379379 var s = new StringBuf();
380 s.add("{");
380 s.add("[");
381381 var it = keys();
382382 for (i in it) {
383383 s.add(Std.string(i));
386386 if (it.hasNext())
387387 s.add(", ");
388388 }
389 s.add("}");
389 s.add("]");
390390 return s.toString();
391391 }
392392
376376
377377 public function toString():String {
378378 var s = new StringBuf();
379 s.add("{");
379 s.add("[");
380380 var it = keys();
381381 for (i in it) {
382382 s.add(i);
385385 if (it.hasNext())
386386 s.add(", ");
387387 }
388 s.add("}");
388 s.add("]");
389389 return s.toString();
390390 }
391391
0 package sys.thread;
1
2 import cs.system.threading.Monitor;
3
4 @:coreApi
5 @:access(sys.thread.Mutex)
6 class Condition {
7 final object:cs.system.Object;
8
9 public function new():Void {
10 this.object = new cs.system.Object();
11 }
12
13 public function acquire():Void {
14 Monitor.Enter(object);
15 }
16
17 public function tryAcquire():Bool {
18 return Monitor.TryEnter(object);
19 }
20
21 public function release():Void {
22 Monitor.Exit(object);
23 }
24
25 public function wait():Void {
26 Monitor.Wait(object);
27 }
28
29 public function signal():Void {
30 Monitor.Pulse(object);
31 }
32
33 public function broadcast():Void {
34 Monitor.PulseAll(object);
35 }
36 }
0 package sys.thread;
1
2 @:coreApi
3 class Semaphore {
4 final native:cs.system.threading.Semaphore;
5
6 public function new(value:Int):Void {
7 this.native = new cs.system.threading.Semaphore(value, 0x7FFFFFFF);
8 }
9
10 public function acquire():Void {
11 native.WaitOne();
12 }
13
14 public function tryAcquire(?timeout:Float):Bool {
15 return native.WaitOne(timeout == null ? 0 : Std.int(timeout * 1000));
16 }
17
18 public function release():Void {
19 native.Release();
20 }
21 }
229229 if (ts != null)
230230 return ts();
231231 var ret = new StringBuf();
232 ret.add("{");
232 ret.add("[");
233233 var first = true;
234234 for (f in Reflect.fields(this)) {
235235 if (first)
243243 }
244244 if (!first)
245245 ret.add(" ");
246 ret.add("}");
246 ret.add("]");
247247 return ret.toString();
248248 }
249249 }
3232
3333 extern static public function getEnv(s:String):String;
3434
35 extern static public function putEnv(s:String, v:String):Void;
35 extern static public function putEnv(s:String, v:Null<String>):Void;
3636
3737 extern static public function environment():Map<String, String>;
3838
4242 this.ip = ip;
4343 }
4444
45 extern static public function localhost();
45 extern static public function localhost():String;
4646
47 extern static function hostReverse(ip:Int);
47 extern static function hostReverse(ip:Int):String;
4848
49 extern static function hostToString(ip:Int);
49 extern static function hostToString(ip:Int):String;
5050
51 extern static function resolve(name:String);
51 extern static function resolve(name:String):Int;
5252 }
0 package sys.thread;
1
2 @:coreApi class Condition {
3 final cond:eval.luv.Condition;
4 final mutex:eval.luv.Mutex;
5
6 public function new():Void {
7 cond = eval.luv.Condition.init().resolve();
8 mutex = eval.luv.Mutex.init(true).resolve();
9 eval.vm.Gc.finalise(destroy, this);
10 }
11
12 static function destroy(cond:Condition):Void {
13 cond.cond.destroy();
14 cond.mutex.destroy();
15 }
16
17 public function acquire():Void {
18 mutex.lock();
19 }
20
21 public function tryAcquire():Bool {
22 return mutex.tryLock().isOk();
23 }
24
25 public function release():Void {
26 mutex.unlock();
27 }
28
29 public function wait():Void {
30 cond.wait(mutex);
31 }
32
33 public function signal():Void {
34 cond.signal();
35 }
36
37 public function broadcast():Void {
38 cond.broadcast();
39 }
40 }
22 import eval.luv.Loop;
33 import eval.luv.Async;
44 import eval.luv.Timer as LuvTimer;
5
5 import haxe.MainLoop;
6
7 /**
8 When an event loop has an available event to execute.
9 **/
610 @:coreApi
711 enum NextEventTime {
12 /** There's already an event waiting to be executed */
813 Now;
14 /** No new events are expected. */
915 Never;
16 /**
17 An event is expected to arrive at any time.
18 If `time` is specified, then the event will be ready at that time for sure.
19 */
1020 AnyTime(time:Null<Float>);
21 /** An event is expected to be ready for execution at `time`. */
1122 At(time:Float);
1223 }
1324
2637 }
2738 }
2839
40 /**
41 An event loop implementation used for `sys.thread.Thread`
42 **/
2943 @:coreApi
3044 class EventLoop {
3145 @:allow(eval.luv.Loop)
3246 final handle:Loop;
3347
3448 final mutex = new Mutex();
35 final oneTimeEvents = new Array<Null<()->Void>>();
36 var oneTimeEventsIdx = 0;
3749 final wakeup:Async;
3850 var promisedEventsCount = 0;
3951 var pending:Array<()->Void> = [];
40 var looping = false;
52 var started:Bool = false;
53
54 var isMainThread:Bool;
55 static var CREATED : Bool;
4156
4257 public function new():Void {
58 isMainThread = !CREATED;
59 CREATED = true;
4360 handle = Loop.init().resolve();
4461 wakeup = Async.init(handle, consumePending).resolve();
4562 wakeup.unref();
4663 }
4764
65 /**
66 Schedule event for execution every `intervalMs` milliseconds in current loop.
67 **/
4868 public function repeat(event:()->Void, intervalMs:Int):EventHandler {
4969 var e = new RegularEvent(event);
5070 mutex.acquire();
51 pending.push(() -> {
52 e.timer = LuvTimer.init(handle).resolve();
53 e.timer.start(e.run, intervalMs, intervalMs < 1 ? 1 : intervalMs).resolve();
54 });
71 e.timer = LuvTimer.init(handle).resolve();
72 e.timer.start(e.run, intervalMs, intervalMs < 1 ? 1 : intervalMs).resolve();
5573 mutex.release();
5674 wakeup.send();
5775 return e;
5876 }
5977
78 /**
79 Prevent execution of a previously scheduled event in current loop.
80 **/
6081 public function cancel(eventHandler:EventHandler):Void {
6182 mutex.acquire();
6283 (eventHandler:RegularEvent).event = noop;
7091 }
7192 static final noop = function() {}
7293
94 /**
95 Notify this loop about an upcoming event.
96 This makes the thread stay alive and wait for as many events as the number of
97 times `.promise()` was called. These events should be added via `.runPromised()`.
98 **/
7399 public function promise():Void {
74100 mutex.acquire();
75101 ++promisedEventsCount;
78104 wakeup.send();
79105 }
80106
107 /**
108 Execute `event` as soon as possible.
109 **/
81110 public function run(event:()->Void):Void {
82111 mutex.acquire();
83112 pending.push(event);
85114 wakeup.send();
86115 }
87116
117 /**
118 Add previously promised `event` for execution.
119 **/
88120 public function runPromised(event:()->Void):Void {
89121 mutex.acquire();
90122 --promisedEventsCount;
95127 }
96128
97129 function refUnref():Void {
98 if(promisedEventsCount > 0) {
130 if (promisedEventsCount > 0 || (isMainThread && haxe.MainLoop.hasEvents())) {
99131 wakeup.ref();
100132 } else {
101133 wakeup.unref();
103135 }
104136
105137 public function progress():NextEventTime {
106 //TODO: throw if loop is already running
107 if((handle:Loop).run(NOWAIT)) {
138 if (started) throw "Event loop already started";
139
140 if (handle.run(NOWAIT)) {
108141 return AnyTime(null);
109142 } else {
110143 return Never;
111144 }
112145 }
113146
147 /**
148 Blocks until a new event is added or `timeout` (in seconds) to expires.
149
150 Depending on a target platform this method may also automatically execute arriving
151 events while waiting. However if any event is executed it will stop waiting.
152
153 Returns `true` if more events are expected.
154 Returns `false` if no more events expected.
155
156 Depending on a target platform this method may be non-reentrant. It must
157 not be called from event callbacks.
158 **/
114159 public function wait(?timeout:Float):Bool {
115 //TODO: throw if loop is already running
116 if(timeout == null) {
160 if (started) throw "Event loop already started";
161
162 if(timeout != null) {
117163 var timer = LuvTimer.init(handle).resolve();
118164 timer.start(() -> {
119165 timer.stop().resolve();
120166 timer.close(() -> {});
121167 }, Std.int(timeout * 1000));
122 return (handle:Loop).run(ONCE);
168 return handle.run(ONCE);
123169 } else {
124 return (handle:Loop).run(ONCE);
125 }
126 }
127
170 return handle.run(ONCE);
171 }
172 }
173
174 /**
175 Execute all pending events.
176 Wait and execute as many events as the number of times `promise()` was called.
177 Runs until all repeating events are cancelled and no more events are expected.
178
179 Depending on a target platform this method may be non-reentrant. It must
180 not be called from event callbacks.
181 **/
128182 public function loop():Void {
129 //TODO: throw if loop is already running
183 if (started) throw "Event loop already started";
184 started = true;
130185 consumePending();
131 (handle:Loop).run(DEFAULT);
186 handle.run(DEFAULT);
132187 }
133188
134189 function consumePending(?_:Async):Void {
190 mutex.acquire();
135191 var p = pending;
136192 pending = [];
193 mutex.release();
137194 for(fn in p) fn();
138 }
139 }
195
196 if (started && isMainThread) {
197 var next = @:privateAccess MainLoop.tick();
198 if (haxe.MainLoop.hasEvents()) {
199 wakeup.send();
200 } else {
201 refUnref();
202 }
203 }
204 }
205 }
0 package sys.thread;
1
2 @:coreApi class Semaphore {
3 final native:eval.luv.Semaphore;
4
5 public function new(value:Int):Void {
6 native = eval.luv.Semaphore.init(value).resolve();
7 eval.vm.Gc.finalise(destroy, this);
8 }
9
10 static function destroy(sem:Semaphore):Void {
11 sem.native.destroy();
12 }
13
14 public function acquire():Void {
15 native.wait();
16 }
17
18 public function tryAcquire(?timeout:Float):Bool {
19 if (timeout == null) {
20 return native.tryWait().isOk();
21 } else {
22 var t = Sys.time() + timeout;
23 while (Sys.time() < t) {
24 if (native.tryWait().isOk()) {
25 return true;
26 }
27 }
28 return false;
29 }
30 }
31
32 public function release():Void {
33 native.post();
34 }
35 }
1717
1818 /**
1919 Parse the given string value to an unsigned integer.
20 <<<<<<< HEAD
21
22 =======
23 >>>>>>> development
2420 Throws if the given string is not a valid representation of an unsigned
2521 integer.
2622 **/
5959 **/
6060 extern class DirSync {
6161 @:inheritDoc(eval.luv.Dir.open)
62 static public function open(loop:Loop, path:NativeString):Result<Dir>;
62 static public function open(path:NativeString):Result<Dir>;
6363
6464 @:inheritDoc(eval.luv.Dir.close)
65 static public function close(dir:Dir, loop:Loop):Result<Result.NoData>;
65 static public function close(dir:Dir):Result<Result.NoData>;
6666
6767 @:inheritDoc(eval.luv.Dir.read)
68 static public function read(dir:Dir, loop:Loop, ?numberOfEntries:Int):Result<Array<Dirent>>;
68 static public function read(dir:Dir, ?numberOfEntries:Int):Result<Array<Dirent>>;
6969
7070 @:inheritDoc(eval.luv.Dir.scan)
71 static public function scan(loop:Loop, path:NativeString):Result<DirectoryScan>;
71 static public function scan(path:NativeString):Result<DirectoryScan>;
7272 }
1616 static function setEnv(name:String, value:NativeString):Result<Result.NoData>;
1717
1818 /**
19 Deletes an environment variable.
20 **/
21 static function unsetEnv(name:String):Result<Result.NoData>;
22
23 /**
1924 Retrieves all environment variables.
2025 **/
2126 static function environ():Result<Map<String,NativeString>>;
6767 /**
6868 Evaluates to the resident set size for the current process.
6969 **/
70 static function residentSetMemory(pid:Int):Result<UInt64>;
70 static function residentSetMemory():Result<UInt64>;
7171
7272 /**
7373 Gets the resource usage measures for the current process.
161161 var UV_EFTYPE = 76;
162162 /** illegal byte sequence */
163163 var UV_EILSEQ = 77;
164 /** value too large for defined data type **/
165 var UV_EOVERFLOW = 78;
166 /** socket type not supported**/
167 var UV_ESOCKTNOSUPPORT = 79;
164168
165169 /**
166170 Converts a system error code to a libuv error.
9999 str = str.split("\\").join("\\\\");
100100 flash.external.ExternalInterface.call("console." + type, str);
101101 }
102
103 public static var parseInt(get, never):(string:String, ?radix:Int) -> Float;
104
105 extern static inline function get_parseInt():(string:String, ?radix:Int) -> Float {
106 return untyped __global__["parseInt"];
107 }
102108 }
4848 return untyped __int__(x);
4949 }
5050
51 public static function parseInt(x:String):Null<Int>
52 untyped {
53 var v = __global__["parseInt"](x);
54 if (__global__["isNaN"](v))
55 return null;
56 return v;
57 }
51 public static function parseInt(x:String):Null<Int> {
52 final v = flash.Lib.parseInt(x);
53 if (Math.isNaN(v))
54 return null;
55 return cast v;
56 }
5857
5958 public static function parseFloat(x:String):Float {
6059 return untyped __global__["parseFloat"](x);
6868
6969 public function toString():String {
7070 var s = new StringBuf();
71 s.add("{");
71 s.add("[");
7272 var it = keys();
7373 for (i in it) {
7474 s.add(i);
7777 if (it.hasNext())
7878 s.add(", ");
7979 }
80 s.add("}");
80 s.add("]");
8181 return s.toString();
8282 }
8383
6565 }
6666
6767 public function toString():String {
68 var s = "";
68 var s = "[";
6969 var it = keys();
7070 for (i in it) {
7171 s += (s == "" ? "" : ",") + Std.string(i);
7272 s += " => ";
7373 s += Std.string(get(i));
7474 }
75 return s + "}";
75 return s + "]";
7676 }
7777
7878 public function clear():Void {
106106
107107 public function toString():String {
108108 var s = new StringBuf();
109 s.add("{");
109 s.add("[");
110110 var it = keys();
111111 for (i in it) {
112112 s.add(i);
115115 if (it.hasNext())
116116 s.add(", ");
117117 }
118 s.add("}");
118 s.add("]");
119119 return s.toString();
120120 }
121121
7373
7474 public function toString():String {
7575 var s = new StringBuf();
76 s.add("{");
76 s.add("[");
7777 var it = keys();
7878 for (i in it) {
7979 s.add(i);
8282 if (it.hasNext())
8383 s.add(", ");
8484 }
85 s.add("}");
85 s.add("]");
8686 return s.toString();
8787 }
8888
6565 }
6666
6767 public function toString():String {
68 var s = "";
68 var s = "[";
6969 var it = keys();
7070 for (i in it) {
7171 s += (s == "" ? "" : ",") + Std.string(i);
7272 s += " => ";
7373 s += Std.string(get(i));
7474 }
75 return s + "}";
75 return s + "]";
7676 }
7777
7878 public function clear():Void {
77 function format(dateTime : Date) : String;
88 function formatUTC(dateTime : Date) : String;
99 function getDateStyle() : DateTimeStyle;
10 function getDateTimePattern() : DateTimeStyle;
10 function getDateTimePattern() : String;
1111 function getFirstWeekday() : Int;
1212 function getMonthNames(?nameStyle : DateTimeNameStyle, ?context : DateTimeNameContext) : flash.Vector<String>;
1313 function getTimeStyle() : DateTimeStyle;
149149 flash.Lib.current.stage.addEventListener(flash.events.Event.ENTER_FRAME, function(_) processEvents());
150150 #elseif (target.threaded && !cppia)
151151 //everything is delegated to sys.thread.EventLoop
152 #elseif lua
153 inline function luvRun(mode:String):Bool
154 return untyped __lua__('_hx_luv.run({0})', mode);
155 while (true) {
156 var nextTick = processEvents();
157 if(untyped __lua__('_hx_luv.loop_alive()')) {
158 if(nextTick < 0)
159 luvRun("once")
160 else
161 luvRun("nowait");
162 } else {
163 if (nextTick < 0)
164 break;
165 if (nextTick > 0)
166 sleepLock.wait(nextTick);
167 }
168 }
152169 #elseif sys
153170 while (true) {
154171 var nextTick = processEvents();
3939 this = i;
4040 }
4141
42 @:from static function from<T:EnumValue>(e:T) : EnumFlags<T> {
43 return new EnumFlags(1 << e.getIndex());
44 }
45
46 @:op(a|b) function or(f:haxe.EnumFlags<T>) : haxe.EnumFlags<T>;
47 @:op(a&b) function and(f:haxe.EnumFlags<T>) : haxe.EnumFlags<T>;
48 @:op(a^b) function xor(f:haxe.EnumFlags<T>) : haxe.EnumFlags<T>;
49
4250 /**
4351 Checks if the index of enum instance `v` is set.
4452
7684 }
7785
7886 /**
87 Depending on the value of `condition` sets (`condition=true`) or unsets (`condition=false`)
88 the index of enum instance `v`.
89
90 This method is optimized if `v` is an enum instance expression such as
91 `SomeEnum.SomeCtor`.
92
93 If `v` is `null`, the result is unspecified.
94 **/
95 public inline function setTo(v:T, condition:Bool):Void {
96 if(condition)
97 set(v)
98 else
99 unset(v);
100 }
101
102 /**
79103 Convert a integer bitflag into a typed one (this is a no-op, it does not
80104 have any impact on speed).
81105 **/
3636
3737 If `e` is inside a package, the package structure is returned dot-
3838 separated, with another dot separating the enum name:
39
39
4040 pack1.pack2.(...).packN.EnumName
4141
4242 If `e` is a sub-type of a Haxe module, that module is not part of the
109109 static inline function getConstructors<T>(e:Enum<T>):Array<String> {
110110 return Type.getEnumConstructs(e);
111111 }
112
113 #if (java && jvm)
114 @:noCompletion
115 extern static function values<T>(en:Enum<T>):java.NativeArray<java.lang.Enum<T>>;
116 #end
112117 }
113118
114119 /**
2424 /**
2525 Cross-platform JSON API: it will automatically use the optimized native API if available.
2626 Use `-D haxeJSON` to force usage of the Haxe implementation even if a native API is found:
27 This will provide extra encoding features such as enums (replaced by their index) and StringMaps.
27 This will provide extra encoding (but not decoding) features such as enums (replaced by their index) and StringMaps.
2828
2929 @see https://haxe.org/manual/std-Json.html
3030 **/
5959
6060 @:access(haxe.MainEvent)
6161 class MainLoop {
62 #if (target.threaded && !cppia)
63 static var eventLoopHandler:Null<EventHandler>;
64 static var mutex = new sys.thread.Mutex();
65 static var mainThread = Thread.current();
66 #end
6762
6863 static var pending:MainEvent;
6964
9388 /**
9489 Add a pending event to be run into the main loop.
9590 **/
96 public static function add(f:Void->Void, priority = 0):MainEvent@:privateAccess {
91 public static function add(f:Void->Void, priority = 0) : MainEvent {
9792 if (f == null)
9893 throw "Event function is null";
9994 var e = new MainEvent(f, priority);
10297 head.prev = e;
10398 e.next = head;
10499 pending = e;
105 injectIntoEventLoop(0);
106100 return e;
107 }
108
109 static function injectIntoEventLoop(waitMs:Int) {
110 #if (target.threaded && !cppia)
111 mutex.acquire();
112 if(eventLoopHandler != null)
113 mainThread.events.cancel(eventLoopHandler);
114 eventLoopHandler = mainThread.events.repeat(
115 () -> {
116 mainThread.events.cancel(eventLoopHandler);
117 var wait = tick();
118 if(hasEvents()) {
119 injectIntoEventLoop(Std.int(wait * 1000));
120 }
121 },
122 waitMs
123 );
124 mutex.release();
125 #end
126101 }
127102
128103 static function sortEvents() {
66
77 /**
88 A special type that represents a "rest" function argument.
9
9
1010 The special `...` syntax can be used for convenience and improved readability:
1111
1212 ```haxe
4444 **/
4545 public static function quoteWinArg(argument:String, escapeMetaCharacters:Bool):String {
4646 // If there is no space, tab, back-slash, or double-quotes, and it is not an empty string.
47 if (!~/^[^ \t\\"]+$/.match(argument)) {
47 if (!~/^(\/)?[^ \t\/\\"]+$/.match(argument)) {
4848 // Based on cpython's subprocess.list2cmdline().
4949 // https://hg.python.org/cpython/file/50741316dd3a/Lib/subprocess.py#l620
5050
5151 var result = new StringBuf();
52 var needquote = argument.indexOf(" ") != -1 || argument.indexOf("\t") != -1 || argument == "";
52 var needquote = argument.indexOf(" ") != -1 || argument.indexOf("\t") != -1 || argument == "" || argument.indexOf("/") > 0;
5353
5454 if (needquote)
5555 result.add('"');
3939
4040 It is also possible to extend this class and override its `run()` method in
4141 the child class.
42
43 Notice for threaded targets:
44 `Timer` instances require threads they were created in to run with Haxe's event loops.
45 Main thread of a Haxe program always contains an event loop. For other cases use
46 `sys.thread.Thread.createWithEventLoop` and `sys.thread.Thread.runWithEventLoop` methods.
4247 **/
4348 class Timer {
4449 #if (flash || js)
0 package haxe.atomic;
1
2 #if !(target.atomics || core_api)
3 #error "Atomic operations are not supported on this target!"
4 #end
5
6 /**
7 Atomic boolean.
8 (js) The Atomics and SharedArrayBuffer objects need to be available. Errors will be thrown if this is not the case.
9 **/
10 @:coreApi
11 abstract AtomicBool(AtomicInt) {
12 private inline function toInt(v:Bool):Int {
13 return v ? 1 : 0;
14 }
15
16 private inline function toBool(v:Int):Bool {
17 return v == 1;
18 }
19
20 public inline function new(value:Bool):Void {
21 this = new AtomicInt(toInt(value));
22 }
23
24 /**
25 Atomically compares the value of `a` with `expected` and replaces `a` with `replacement` if they are equal..
26 Returns the original value of `a`.
27 **/
28 public inline function compareExchange(expected:Bool, replacement:Bool):Bool {
29 return toBool(this.compareExchange(toInt(expected), toInt(replacement)));
30 }
31
32 /**
33 Atomically exchanges `a` with `value`.
34 Returns the original value of `a`.
35 **/
36 public inline function exchange(value:Bool):Bool {
37 return toBool(this.exchange(toInt(value)));
38 }
39
40 /**
41 Atomically fetches the value of `a`.
42 **/
43 public inline function load():Bool {
44 return toBool(this.load());
45 }
46
47 /**
48 Atomically stores `value` into `a`.
49 Returns the value that has been stored.
50 **/
51 public inline function store(value:Bool):Bool {
52 return toBool(this.store(toInt(value)));
53 }
54 }
0 package haxe.atomic;
1
2 #if !(target.atomics || core_api)
3 #error "This target does not support atomic operations."
4 #end
5
6 /**
7 Atomic integer.
8 (js) The Atomics and SharedArrayBuffer objects need to be available. Errors will be thrown if this is not the case.
9 **/
10 @:coreType
11 abstract AtomicInt {
12 public function new(value:Int):Void;
13
14 /**
15 Atomically adds `b` to `a`.
16 Returns the original value of `a`.
17 **/
18 public function add(b:Int):Int;
19
20 /**
21 Atomically substracts `b` from `a`.
22 Returns the original value of `a`.
23 **/
24 public function sub(b:Int):Int;
25
26 /**
27 Atomically computes the bitwise and of `a` and `b` and stores it in `a`.
28 Returns the original value of `a`.
29 **/
30 public function and(b:Int):Int;
31
32 /**
33 Atomically computes the bitwise or of `a` and `b` and stores it in `a`.
34 Returns the original value of `a`.
35 **/
36 public function or(b:Int):Int;
37
38 /**
39 Atomically computes the bitwise xor of `a` and `b` and stores it in `a`.
40 Returns the original value of `a`.
41 **/
42 public function xor(b:Int):Int;
43
44 /**
45 Atomically compares the value of `a` with `expected` and replaces `a` with `replacement` if they are equal..
46 Returns the original value of `a`.
47 **/
48 public function compareExchange(expected:Int, replacement:Int):Int;
49
50 /**
51 Atomically exchanges `a` with `value`.
52 Returns the original value of `a`.
53 **/
54 public function exchange(value:Int):Int;
55
56 /**
57 Atomically fetches the value of `a`.
58 **/
59 public function load():Int;
60
61 /**
62 Atomically stores `value` into `a`.
63 Returns the value that has been stored.
64 **/
65 public function store(value:Int):Int;
66 }
0 package haxe.atomic;
1
2 #if !(target.atomics || core_api)
3 #error "This target does not support atomic operations."
4 #end
5
6 #if (js || hxcpp)
7 #error "JavaScript and Hxcpp do not support AtomicObject"
8 #end
9
10 /**
11 Atomic object. Use with care, this does not magically make it thread-safe to mutate objects.
12 Not supported on JavaScript or C++.
13 **/
14 @:coreType
15 abstract AtomicObject<T:{}> {
16 public function new(value:T):Void;
17
18 /**
19 Atomically compares the value of `a` with `expected` and replaces `a` with `replacement` if they are equal..
20 Returns the original value of `a`.
21
22 Note that comparison is done by reference, and not by value.
23 While this is expected for most objects, this might give unexpected behaviour for strings.
24 **/
25 public function compareExchange(expected:T, replacement:T):T;
26
27 /**
28 Atomically exchanges `a` with `value`.
29 Returns the original value of `a`.
30 **/
31 public function exchange(value:T):T;
32
33 /**
34 Atomically fetches the value of `a`.
35 **/
36 public function load():T;
37
38 /**
39 Atomically stores `value` into `a`.
40 Returns the value that has been stored.
41 **/
42 public function store(value:T):T;
43 }
294294 var platforms:Array<Platform>;
295295 var targets:Array<MetadataTarget>;
296296 var internal:Bool;
297 var ?origin:String;
297298 var ?links:Array<String>;
298299 }
299300
162162 var OpInterval;
163163 var OpArrow;
164164 var OpIn;
165 var OpNullCoal;
165166 }
166167
167168 typedef JsonBinop<T> = {
4040 static inline var ModuleMemory = new HaxeRequestMethod<ModuleParams, Response<HaxeModuleMemoryResult>>("server/memory/module");
4141 static inline var Modules = new HaxeRequestMethod<ContextParams, Response<Array<String>>>("server/modules");
4242 static inline var Module = new HaxeRequestMethod<ModuleParams, Response<JsonModule>>("server/module");
43 static inline var Type = new HaxeRequestMethod<TypeParams, Response<JsonModuleType<Any>>>("server/type");
4344 static inline var Files = new HaxeRequestMethod<ContextParams, Response<Array<JsonServerFile>>>("server/files");
4445 static inline var ModuleCreated = new HaxeRequestMethod<FileParams, Response<NoData>>("server/moduleCreated");
4546 }
9697 final types:Array<JsonTypePath>;
9798 final file:String;
9899 final sign:String;
100 final dirty:Null<String>;
99101 final dependencies:Array<ModuleId>;
102 final dependents:Array<ModuleId>;
100103 }
101104
102105 typedef JsonServerFile = {
107110 }
108111
109112 /* Memory */
110
111113 typedef HaxeMemoryResult = {
112114 final contexts:Array<{
113115 final context:HaxeServerContext;
164166 typedef ModuleParams = ContextParams & {
165167 final path:String;
166168 }
169
170 typedef TypeParams = ContextParams & {
171 final modulePath:String;
172 final typeName:String;
173 }
226226 }
227227
228228 public function toString() {
229 return root == null ? '{}' : '{${root.toString()}}';
229 return root == null ? "[]" : '[${root.toString()}]';
230230 }
231231
232232 /**
263263 return this == null ? 0 : _height;
264264
265265 public function toString() {
266 return (left == null ? "" : left.toString() + ", ") + '$key=$value' + (right == null ? "" : ", " + right.toString());
266 return (left == null ? "" : left.toString() + ", ") + '$key => $value' + (right == null ? "" : ", " + right.toString());
267267 }
268268 }
3232 var d = k1.getIndex() - k2.getIndex();
3333 if (d != 0)
3434 return d;
35 #if hl
36 var a1 = @:privateAccess Type._enumParameters(k1);
37 var a2 = @:privateAccess Type._enumParameters(k2);
38 var ld = a1.length - a2.length;
39 if (ld != 0)
40 return ld;
41 for (i in 0...a1.length) {
42 var d = compareArg(a1[i], a2[i]);
43 if (d != 0)
44 return d;
45 }
46 return 0;
47 #else
3548 var p1 = k1.getParameters();
3649 var p2 = k2.getParameters();
3750 if (p1.length == 0 && p2.length == 0)
3851 return 0;
3952 return compareArgs(p1, p2);
53 #end
4054 }
4155
4256 function compareArgs(a1:Array<Dynamic>, a2:Array<Dynamic>):Int {
2323
2424 import haxe.ds.StringMap;
2525 import haxe.ds.IntMap;
26 import haxe.ds.HashMap;
2726 import haxe.ds.ObjectMap;
28 import haxe.ds.WeakMap;
2927 import haxe.ds.EnumValueMap;
3028 import haxe.Constraints.IMap;
3129
4040 eval.Vector<T>
4141 #else
4242 Array<T>
43 #end
43 #end;
4444
4545 /**
4646 A Vector is a storage of fixed size. It can be faster than Array on some
6060
6161 If `length` is less than or equal to 0, the result is unspecified.
6262 **/
63 public inline function new(length:Int) {
63 extern overload public inline function new(length:Int) {
6464 #if flash10
6565 this = new flash.Vector<T>(length, true);
6666 #elseif neko
7474 #elseif cpp
7575 this = NativeArray.create(length);
7676 #elseif python
77 this = python.Syntax.code("[{0}]*{1}", null, length);
77 this = python.Syntax.code("([{0}]*{1})", null, length);
7878 #elseif lua
7979 this = untyped __lua_table__({length: length});
8080 #elseif eval
8282 #else
8383 this = [];
8484 untyped this.length = length;
85 #end
86 }
87
88 /**
89 Creates a new Vector of length `length` filled with `defaultValue` elements.
90
91 Can be faster than `new Vector(length)` for iteration on some targets for non-nullable elements.
92
93 If `length` is less than or equal to 0, the result is unspecified.
94 **/
95 extern overload public inline function new(length:Int, defaultValue:T):Vector<T> {
96 #if js
97 this = [for (_ in 0...length) defaultValue];
98 #elseif python
99 this = python.Syntax.code("([{0}]*{1})", defaultValue, length);
100 #else
101
102 #if flash10
103 this = new flash.Vector<T>(length, true);
104 #elseif neko
105 this = untyped __dollar__amake(length);
106 #elseif cs
107 this = new cs.NativeArray(length);
108 #elseif java
109 this = new java.NativeArray(length);
110 #elseif cpp
111 this = NativeArray.create(length);
112 #elseif lua
113 this = untyped __lua_table__({length: length});
114 #elseif eval
115 this = new eval.Vector(length);
116 #else
117 this = [];
118 untyped this.length = length;
119 #end
120 fill(defaultValue);
121
85122 #end
86123 }
87124
139176 return untyped this.length;
140177 #end
141178 }
179
180 /**
181 Sets all `length` elements of `this` Vector to `value`.
182 **/
183 public inline function fill(value:T):Void
184 for (i in 0...length) this[i] = value;
142185
143186 /**
144187 Copies `length` of elements from `src` Vector, beginning at `srcPos` to
127127 } else
128128 classString(v);
129129 case TEnum(_):
130 var i:Dynamic = Type.enumIndex(v);
131 add(i);
130 var i = Type.enumIndex(v);
131 add(Std.string(i));
132132 case TBool:
133133 add(#if (php || jvm || hl) (v ? 'true' : 'false') #else v #end);
134134 case TNull:
2929 class HttpJs extends haxe.http.HttpBase {
3030 public var async:Bool;
3131 public var withCredentials:Bool;
32 public var responseHeaders:Map<String, String>;
3233
3334 var req:js.html.XMLHttpRequest;
3435
5253 public override function request(?post:Bool) {
5354 this.responseAsString = null;
5455 this.responseBytes = null;
56 this.responseHeaders = null;
5557 var r = req = js.Browser.createXMLHttpRequest();
5658 var onreadystatechange = function(_) {
5759 if (r.readyState != 4)
7274 onStatus(s);
7375 if (s != null && s >= 200 && s < 400) {
7476 req = null;
77
78 // split headers and remove the last \r\n\r\n
79 var headers = r.getAllResponseHeaders().split('\r\n');
80 headers = headers.filter(h -> h != '');
81
82 // store response headers
83 responseHeaders = new haxe.ds.StringMap();
84 for (hline in headers) {
85 var a = hline.split(": ");
86 var hname = a.shift();
87 var hval = if (a.length == 1) a[0] else a.join(": ");
88 hval = StringTools.ltrim(StringTools.rtrim(hval));
89 responseHeaders.set(hname, hval);
90 }
91
7592 success(Bytes.ofData(r.response));
7693 } else if (s == null || (s == 0 && r.response == null)) {
7794 req = null;
2626 import haxe.io.Bytes;
2727
2828 class HttpNodeJs extends haxe.http.HttpBase {
29 public var responseHeaders:Map<String, String>;
30
2931 var req:js.node.http.ClientRequest;
3032
3133 public function new(url:String) {
4648 public override function request(?post:Bool) {
4749 responseAsString = null;
4850 responseBytes = null;
51 responseHeaders = null;
4952 var parsedUrl = new js.node.url.URL(url);
5053 var secure = (parsedUrl.protocol == "https:");
5154 var host = parsedUrl.hostname;
9699 var buf = (data.length == 1 ? data[0] : Buffer.concat(data));
97100 responseBytes = Bytes.ofData(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
98101 req = null;
102
103 // store response headers
104 responseHeaders = new haxe.ds.StringMap();
105 for (field in Reflect.fields(res.headers))
106 {
107 responseHeaders.set(field, Reflect.field(res.headers, field));
108 }
109
99110 if (s != null && s >= 200 && s < 400) {
100111 success(responseBytes);
101112 } else {
317317 var ApplicationXCompress = 'application/x-compress';
318318 var MultipartXZip = 'multipart/x-zip';
319319 var TextXScriptZsh = 'text/x-script.zsh';
320 var ImageAvif = 'image/avif';
320321 }
2626 var current:Int = 0;
2727 var array:Array<T>;
2828
29 #if !hl inline #end
30 public function new(array:Array<T>) {
29 public inline function new(array:Array<T>) {
3130 this.array = array;
3231 }
3332
34 #if !hl inline #end
35 public function hasNext():Bool {
33 public inline function hasNext():Bool {
3634 return current < array.length;
3735 }
3836
39 #if !hl inline #end
40 public function next():{key:Int,value:T} {
37 public inline function next():{key:Int,value:T} {
4138 return {value:array[current], key:current++};
4239 }
4340 }
5151 of the current module file.
5252 **/
5353 var NoCheckShadowing = 3;
54 /**
55 Retype the module's contents if its file is invalidated. This is currently experimental.
56 **/
57 var Retype = 4;
5458 }
5559
5660 enum abstract ContextOptions(Int) {
2121
2222 package haxe.macro;
2323
24 import haxe.display.Display;
2425 import haxe.macro.Expr;
2526
2627 /**
6869 **/
6970 public static function define(flag:String, ?value:String) {
7071 #if (neko || eval)
72 Context.assertInitMacro();
7173 load("define", 2)(flag, value);
7274 #end
7375 }
135137 **/
136138 public static function addClassPath(path:String) {
137139 #if (neko || eval)
140 Context.assertInitMacro();
138141 load("add_class_path", 1)(path);
139142 #end
140143 }
162165 }
163166
164167 /**
168 Returns all the configuration settings applied to the compiler.
169
170 Usage of this function outside a macro context returns `null`.
171 **/
172 public static function getConfiguration():Null<CompilerConfiguration> {
173 #if (neko || eval)
174 return load("get_configuration", 0)();
175 #else
176 return null;
177 #end
178 }
179
180 /**
165181 Adds a native library depending on the platform (e.g. `-swf-lib` for Flash).
166182
167183 Usage of this function outside of initialization macros is deprecated and may cause compilation server issues.
168184 **/
169185 public static function addNativeLib(name:String) {
170186 #if (neko || eval)
187 Context.assertInitMacro();
171188 load("add_native_lib", 1)(name);
172189 #end
173190 }
200217 @param strict If true and given package wasn't found in any of class paths, fail with an error.
201218 **/
202219 public static function include(pack:String, ?rec = true, ?ignore:Array<String>, ?classPaths:Array<String>, strict = false) {
203 var ignoreWildcard:Array<String> = [];
204 var ignoreString:Array<String> = [];
205 if (ignore != null) {
206 for (ignoreRule in ignore) {
207 if (StringTools.endsWith(ignoreRule, "*")) {
208 ignoreWildcard.push(ignoreRule.substr(0, ignoreRule.length - 1));
209 } else {
210 ignoreString.push(ignoreRule);
211 }
212 }
220 function include(pack:String, ?rec = true, ?ignore:Array<String>, ?classPaths:Array<String>, strict = false) {
221 var ignoreWildcard:Array<String> = [];
222 var ignoreString:Array<String> = [];
223 if (ignore != null) {
224 for (ignoreRule in ignore) {
225 if (StringTools.endsWith(ignoreRule, "*")) {
226 ignoreWildcard.push(ignoreRule.substr(0, ignoreRule.length - 1));
227 } else {
228 ignoreString.push(ignoreRule);
229 }
230 }
231 }
232 var skip = if (ignore == null) {
233 function(c) return false;
234 } else {
235 function(c:String) {
236 if (Lambda.has(ignoreString, c))
237 return true;
238 for (ignoreRule in ignoreWildcard)
239 if (StringTools.startsWith(c, ignoreRule))
240 return true;
241 return false;
242 }
243 }
244 var displayValue = Context.definedValue("display");
245 if (classPaths == null) {
246 classPaths = Context.getClassPath();
247 // do not force inclusion when using completion
248 switch (displayValue) {
249 case null:
250 case "usage":
251 case _:
252 return;
253 }
254 // normalize class path
255 for (i in 0...classPaths.length) {
256 var cp = StringTools.replace(classPaths[i], "\\", "/");
257 if (StringTools.endsWith(cp, "/"))
258 cp = cp.substr(0, -1);
259 if (cp == "")
260 cp = ".";
261 classPaths[i] = cp;
262 }
263 }
264 var prefix = pack == '' ? '' : pack + '.';
265 var found = false;
266 for (cp in classPaths) {
267 var path = pack == '' ? cp : cp + "/" + pack.split(".").join("/");
268 if (!sys.FileSystem.exists(path) || !sys.FileSystem.isDirectory(path))
269 continue;
270 found = true;
271 for (file in sys.FileSystem.readDirectory(path)) {
272 if (StringTools.endsWith(file, ".hx") && file.substr(0, file.length - 3).indexOf(".") < 0) {
273 if( file == "import.hx" ) continue;
274 var cl = prefix + file.substr(0, file.length - 3);
275 if (skip(cl))
276 continue;
277 Context.getModule(cl);
278 } else if (rec && sys.FileSystem.isDirectory(path + "/" + file) && !skip(prefix + file))
279 include(prefix + file, true, ignore, classPaths);
280 }
281 }
282 if (strict && !found)
283 Context.error('Package "$pack" was not found in any of class paths', Context.currentPos());
213284 }
214 var skip = if (ignore == null) {
215 function(c) return false;
285
286 if (!Context.initMacrosDone()) {
287 Context.onAfterInitMacros(() -> include(pack, rec, ignore, classPaths, strict));
216288 } else {
217 function(c:String) {
218 if (Lambda.has(ignoreString, c))
219 return true;
220 for (ignoreRule in ignoreWildcard)
221 if (StringTools.startsWith(c, ignoreRule))
222 return true;
223 return false;
224 }
289 include(pack, rec, ignore, classPaths, strict);
225290 }
226 var displayValue = Context.definedValue("display");
227 if (classPaths == null) {
228 classPaths = Context.getClassPath();
229 // do not force inclusion when using completion
230 switch (displayValue) {
231 case null:
232 case "usage":
233 case _:
234 return;
235 }
236 // normalize class path
237 for (i in 0...classPaths.length) {
238 var cp = StringTools.replace(classPaths[i], "\\", "/");
239 if (StringTools.endsWith(cp, "/"))
240 cp = cp.substr(0, -1);
241 if (cp == "")
242 cp = ".";
243 classPaths[i] = cp;
244 }
245 }
246 var prefix = pack == '' ? '' : pack + '.';
247 var found = false;
248 for (cp in classPaths) {
249 var path = pack == '' ? cp : cp + "/" + pack.split(".").join("/");
250 if (!sys.FileSystem.exists(path) || !sys.FileSystem.isDirectory(path))
251 continue;
252 found = true;
253 for (file in sys.FileSystem.readDirectory(path)) {
254 if (StringTools.endsWith(file, ".hx") && file.substr(0, file.length - 3).indexOf(".") < 0) {
255 if( file == "import.hx" ) continue;
256 var cl = prefix + file.substr(0, file.length - 3);
257 if (skip(cl))
258 continue;
259 Context.getModule(cl);
260 } else if (rec && sys.FileSystem.isDirectory(path + "/" + file) && !skip(prefix + file))
261 include(prefix + file, true, ignore, classPaths);
262 }
263 }
264 if (strict && !found)
265 Context.error('Package "$pack" was not found in any of class paths', Context.currentPos());
266291 }
267292
268293 /**
450475 }
451476
452477 /**
478 Reference a json file describing user-defined metadata
479 See https://github.com/HaxeFoundation/haxe/blob/development/src-json/meta.json
480 **/
481 public static function registerMetadataDescriptionFile(path:String, ?source:String):Void {
482 var f = sys.io.File.getContent(path);
483 var content:Array<MetadataDescription> = haxe.Json.parse(f);
484 for (m in content) registerCustomMetadata(m, source);
485 }
486
487 /**
488 Reference a json file describing user-defined defines
489 See https://github.com/HaxeFoundation/haxe/blob/development/src-json/define.json
490 **/
491 public static function registerDefinesDescriptionFile(path:String, ?source:String):Void {
492 var f = sys.io.File.getContent(path);
493 var content:Array<DefineDescription> = haxe.Json.parse(f);
494 for (d in content) registerCustomDefine(d, source);
495 }
496
497 /**
498 Register a custom medatada for documentation and completion purposes
499 **/
500 public static function registerCustomMetadata(meta:MetadataDescription, ?source:String):Void {
501 #if (neko || eval)
502 load("register_metadata_impl", 2)(meta, source);
503 #end
504 }
505
506 /**
507 Register a custom define for documentation purposes
508 **/
509 public static function registerCustomDefine(define:DefineDescription, ?source:String):Void {
510 #if (neko || eval)
511 load("register_define_impl", 2)(define, source);
512 #end
513 }
514
515 /**
453516 Change the default JS output by using a custom generator callback
454517 **/
455518 public static function setCustomJSGenerator(callb:JSGenApi->Void) {
576639 **/
577640 var StrictThreaded;
578641 }
642
643 typedef MetadataDescription = {
644 final metadata:String;
645 final doc:String;
646
647 /**
648 External resources for more information about this metadata.
649 **/
650 @:optional final links:Array<String>;
651
652 /**
653 List (small description) of parameters that this metadata accepts.
654 **/
655 @:optional final params:Array<String>;
656
657 /**
658 Haxe target(s) for which this metadata is used.
659 **/
660 @:optional final platforms:Array<Platform>;
661
662 /**
663 Places where this metadata can be applied.
664 **/
665 @:optional final targets:Array<MetadataTarget>;
666 }
667
668 typedef DefineDescription = {
669 final define:String;
670 final doc:String;
671
672 /**
673 External resources for more information about this define.
674 **/
675 @:optional final links:Array<String>;
676
677 /**
678 List (small description) of parameters that this define accepts.
679 **/
680 @:optional final params:Array<String>;
681
682 /**
683 Haxe target(s) for which this define is used.
684 **/
685 @:optional final platforms:Array<Platform>;
686 }
687
688 typedef CompilerConfiguration = {
689 /**
690 The version integer of the current Haxe compiler build.
691 **/
692 final version:Int;
693
694 /**
695 Returns an array of the arguments passed to the compiler from either the `.hxml` file or the command line.
696 **/
697 final args:Array<String>;
698
699 /**
700 If `--debug` mode is enabled, this is `true`.
701 **/
702 final debug:Bool;
703
704 /**
705 If `--verbose` mode is enabled, this is `true`.
706 **/
707 final verbose:Bool;
708
709 /**
710 If `--no-opt` is enabled, this is `false`.
711 **/
712 final foptimize:Bool;
713
714 /**
715 The target platform.
716 **/
717 final platform:haxe.display.Display.Platform;
718
719 /**
720 The compilation configuration for the target platform.
721 **/
722 final platformConfig:PlatformConfig;
723
724 /**
725 A list of paths being used for the standard library.
726 **/
727 final stdPath:Array<String>;
728
729 /**
730 The path of the class passed using the `-main` argument.
731 **/
732 final mainClass:TypePath;
733
734 /**
735 Special access rules for packages depending on the compiler configuration.
736
737 For example, the "java" package is "Forbidden" when the target platform is Python.
738 **/
739 final packageRules:Map<String,PackageRule>;
740 }
741
742 enum PackageRule {
743 Forbidden;
744 Directory(path:String);
745 Remap(path:String);
746 }
3838 static public function toString(c:ComplexType):String
3939 return new Printer().printComplexType(c);
4040
41 #if (macro || display)
41 #if macro
4242 /**
4343 Returns a type corresponding to `c`.
4444
4646 Displays a compilation error `msg` at the given `Position` `pos`
4747 and aborts the current macro call.
4848 **/
49 public static function error(msg:String, pos:Position):Dynamic {
50 return load("error", 2)(msg, pos);
49 public static function error(msg:String, pos:Position, ?depth:Int = 0):Dynamic {
50 return load("error", 2)(msg, pos, depth);
5151 }
5252
5353 /**
5454 Displays a compilation error `msg` at the given `Position` `pos`
5555 and aborts the compilation.
5656 **/
57 public static function fatalError(msg:String, pos:Position):Dynamic {
58 return load("fatal_error", 2)(msg, pos);
57 public static function fatalError(msg:String, pos:Position, ?depth:Int = 0):Dynamic {
58 return load("fatal_error", 2)(msg, pos, depth);
59 }
60
61 /**
62 Displays a compilation error `msg` at the given `Position` `pos`
63 without aborting the current macro call.
64 **/
65 public static function reportError(msg:String, pos:Position, ?depth:Int = 0):Void {
66 load("report_error", 2)(msg, pos, depth);
5967 }
6068
6169 /**
6270 Displays a compilation warning `msg` at the given `Position` `pos`.
6371 **/
64 public static function warning(msg:String, pos:Position) {
65 load("warning", 2)(msg, pos);
72 public static function warning(msg:String, pos:Position, ?depth:Int = 0) {
73 load("warning", 2)(msg, pos, depth);
6674 }
6775
6876 /**
6977 Displays a compilation info `msg` at the given `Position` `pos`.
7078 **/
71 public static function info(msg:String, pos:Position) {
72 load("info", 2)(msg, pos);
79 public static function info(msg:String, pos:Position, ?depth:Int = 0) {
80 load("info", 2)(msg, pos, depth);
7381 }
7482
7583 /**
7684 Gets a list of all current compilation info/warning messages.
7785 **/
78 public static function getMessages() : Array<Message> {
79 return load("get_messages",0)();
86 public static function getMessages():Array<Message> {
87 return load("get_messages", 0)();
8088 }
8189
8290 /**
8391 Filters all current info/warning messages. Filtered out messages will
8492 not be displayed by the compiler.
8593 **/
86 public static function filterMessages( predicate : Message -> Bool ) {
87 load("filter_messages",1)(predicate);
94 public static function filterMessages(predicate:Message->Bool) {
95 load("filter_messages", 1)(predicate);
96 }
97
98 /**
99 Check if compiler is past initializations macros or not.
100 When it is, configuration phase is over and parsing/typing can start.
101 **/
102 public static function initMacrosDone():Bool {
103 return load("init_macros_done", 0)();
88104 }
89105
90106 /**
118134 return load("contains_display_position", 1)(pos);
119135 }
120136
137 public static function getDisplayMode():DisplayMode {
138 return load("get_display_mode", 0)();
139 }
140
121141 /**
122142 Returns the position at which the macro was called.
123143 **/
126146 }
127147
128148 /**
149 Get the call stack (excluding the call to `Context.getMacroStack()`
150 that led to current macro.
151 **/
152 public static function getMacroStack():Array<Position> {
153 return load("get_macro_stack", 0)();
154 }
155
156 /**
129157 Returns the type which is expected at the place the macro is called.
130158
131159 This affects usages such as `var x:Int = macroCall()`, where the
135163 macro is not an expression-macro.
136164 **/
137165 public static function getExpectedType():Null<Type> {
166 assertInitMacrosDone(false);
138167 return load("get_expected_type", 0)();
139168 }
140169
278307 declared class path has priority.
279308
280309 If no type can be found, an exception of type `String` is thrown.
310
311 Usage of this function from initialization macros is deprecated and may
312 cause compilation server issues. Use `Context.onAfterInitMacros` to
313 run your code once typer is ready to be used.
281314 **/
282315 public static function getType(name:String):Type {
316 assertInitMacrosDone();
283317 return load("get_type", 1)(name);
284318 }
285319
291325 declared class path has priority.
292326
293327 If no module can be found, an exception of type `String` is thrown.
328
329 Usage of this function from initialization macros is deprecated and may
330 cause compilation server issues. Use `Context.onAfterInitMacros` to
331 run your code once typer is ready to be used.
294332 **/
295333 public static function getModule(name:String):Array<Type> {
334 assertInitMacrosDone();
296335 return load("get_module", 1)(name);
336 }
337
338 /**
339 Returns the typed expression of the call to the main function.
340
341 This function will only work in the generation phase. Any calls
342 made outside a function passed to `haxe.macro.Context.onGenerate`
343 or `haxe.macro.Context.onAfterGenerate` will return `null`.
344 **/
345 public static function getMainExpr():Null<TypedExpr> {
346 return load("get_main_expr", 0)();
347 }
348
349 /**
350 Returns an array of module types to be generated in the output.
351
352 This list may change depending on the phase of compilation and
353 should not be treated as conclusive until the generation phase.
354
355 Modifying the returned array has no effect on the compilation.
356
357 Usage of this function from initialization macros is deprecated and may
358 cause compilation server issues. Use `Context.onAfterInitMacros` to
359 run your code once typer is ready to be used.
360 **/
361 public static function getAllModuleTypes():Array<haxe.macro.Type.ModuleType> {
362 assertInitMacrosDone();
363 return load("get_module_types", 0)();
297364 }
298365
299366 /**
333400 Returns a hashed MD5 signature of value `v`.
334401 **/
335402 public static function signature(v:Dynamic):String {
403 assertInitMacrosDone(false);
336404 return load("signature", 1)(v);
337405 }
338406
382450 }
383451
384452 /**
453 Adds a callback function `callback` which is invoked after the compiler
454 is done running initialization macros, when typing begins.
455
456 `onAfterInitMacros` should be used to delay typer-dependant code from
457 your initalization macros, to properly separate configuration phase and
458 actual typing.
459 **/
460 public static function onAfterInitMacros(callback:Void->Void):Void {
461 assertInitMacro();
462 load("on_after_init_macros", 1)(callback);
463 }
464
465 /**
385466 Adds a callback function `callback` which is invoked when a type name
386467 cannot be resolved.
387468
398479
399480 Typing the expression may result in a compiler error which can be
400481 caught using `try ... catch`.
482
483 Usage of this function from initialization macros is deprecated and may
484 cause compilation server issues. Use `Context.onAfterInitMacros` to
485 run your code once typer is ready to be used.
401486 **/
402487 public static function typeof(e:Expr):Type {
488 assertInitMacrosDone();
403489 return load("typeof", 1)(e);
404490 }
405491
407493 Types expression `e` and returns the corresponding `TypedExpr`.
408494
409495 Typing the expression may result in a compiler error which can be
410 caught using `try ... catch`.
496 caught using `try ... catch`. Note that not all compiler errors can
497 be caught this way because the compiler might delay various checks
498 to a later stage, at which point the exception handler is no longer
499 active.
500
501 Usage of this function from initialization macros is deprecated and may
502 cause compilation server issues. Use `Context.onAfterInitMacros` to
503 run your code once typer is ready to be used.
411504 **/
412505 public static function typeExpr(e:Expr):TypedExpr {
506 assertInitMacrosDone();
413507 return load("type_expr", 1)(e);
414508 }
415509
419513 Resolving the type may result in a compiler error which can be
420514 caught using `try ... catch`.
421515 Resolution is performed based on the current context in which the macro is called.
516
517 Usage of this function from initialization macros is deprecated and may
518 cause compilation server issues. Use `Context.onAfterInitMacros` to
519 run your code once typer is ready to be used.
422520 **/
423521 public static function resolveType(t:ComplexType, p:Position):Type {
522 assertInitMacrosDone();
424523 return load("resolve_type", 2)(t, p);
425524 }
426525
435534
436535 /**
437536 Tries to unify `t1` and `t2` and returns `true` if successful.
537
538 Usage of this function from initialization macros is deprecated and may
539 cause compilation server issues. Use `Context.onAfterInitMacros` to
540 run your code once typer is ready to be used.
438541 **/
439542 public static function unify(t1:Type, t2:Type):Bool {
543 assertInitMacrosDone();
440544 return load("unify", 2)(t1, t2);
441545 }
442546
444548 Follows a type.
445549
446550 See `haxe.macro.TypeTools.follow` for details.
551
552 Usage of this function from initialization macros is deprecated and may
553 cause compilation server issues. Use `Context.onAfterInitMacros` to
554 run your code once typer is ready to be used.
447555 **/
448556 public static function follow(t:Type, ?once:Bool):Type {
557 assertInitMacrosDone();
449558 return load("follow", 2)(t, once);
450559 }
451560
453562 Follows a type, including abstracts' underlying implementation
454563
455564 See `haxe.macro.TypeTools.followWithAbstracts` for details.
565
566 Usage of this function from initialization macros is deprecated and may
567 cause compilation server issues. Use `Context.onAfterInitMacros` to
568 run your code once typer is ready to be used.
456569 **/
457570 public static function followWithAbstracts(t:Type, once:Bool = false):Type {
571 assertInitMacrosDone();
458572 return load("follow_with_abstracts", 2)(t, once);
459573 }
460574
513627 If `moduleDependency` is given and is not `null`, it should contain
514628 a module path that will be used as a dependency for the newly defined module
515629 instead of the current module.
630
631 Usage of this function from initialization macros is deprecated and may
632 cause compilation server issues. Use `Context.onAfterInitMacros` to
633 run your code once typer is ready to be used.
516634 **/
517635 public static function defineType(t:TypeDefinition, ?moduleDependency:String):Void {
636 assertInitMacrosDone();
518637 load("define_type", 2)(t, moduleDependency);
638 }
639
640 /**
641 Creates and returns a new instance of monomorph (`TMono`) type.
642
643 Returned monomorph can be used with e.g. `Context.unify` to make the compiler
644 bind the monomorph to an actual type and let macro further process the resulting type.
645
646 Usage of this function from initialization macros is deprecated and may
647 cause compilation server issues. Use `Context.onAfterInitMacros` to
648 run your code once typer is ready to be used.
649 **/
650 public static function makeMonomorph():Type {
651 assertInitMacrosDone();
652 return load("make_monomorph", 0)();
519653 }
520654
521655 /**
525659 The individual `types` can reference each other and any identifier
526660 respects the `imports` and `usings` as usual, expect that imports are
527661 not allowed to have `.*` wildcards or `as s` shorthands.
662
663 Usage of this function from initialization macros is deprecated and may
664 cause compilation server issues. Use `Context.onAfterInitMacros` to
665 run your code once typer is ready to be used.
528666 **/
529667 public static function defineModule(modulePath:String, types:Array<TypeDefinition>, ?imports:Array<ImportExpr>, ?usings:Array<TypePath>):Void {
530668 if (imports == null)
531669 imports = [];
532670 if (usings == null)
533671 usings = [];
672 assertInitMacrosDone();
534673 load("define_module", 4)(modulePath, types, imports, usings);
535674 }
536675
538677 Returns a syntax-level expression corresponding to typed expression `t`.
539678
540679 This process may lose some information.
680
681 Usage of this function from initialization macros is deprecated and may
682 cause compilation server issues. Use `Context.onAfterInitMacros` to
683 run your code once typer is ready to be used.
541684 **/
542685 public static function getTypedExpr(t:Type.TypedExpr):Expr {
686 assertInitMacrosDone();
543687 return load("get_typed_expr", 1)(t);
544688 }
545689
554698 that is reset between compilations, so care should be taken when storing
555699 the expression returned by this method in a static variable and using the
556700 compilation server.
701
702 Usage of this function from initialization macros is deprecated and may
703 cause compilation server issues. Use `Context.onAfterInitMacros` to
704 run your code once typer is ready to be used.
557705 **/
558706 public static function storeTypedExpr(t:Type.TypedExpr):Expr {
707 assertInitMacrosDone();
559708 return load("store_typed_expr", 1)(t);
560709 }
561710
573722 that is reset between compilations, so care should be taken when storing
574723 the expression returned by this method in a static variable and using the
575724 compilation server.
725
726 Usage of this function from initialization macros is deprecated and may
727 cause compilation server issues. Use `Context.onAfterInitMacros` to
728 run your code once typer is ready to be used.
576729 **/
577730 public static function storeExpr(e:Expr):Expr {
731 assertInitMacrosDone();
578732 return load("store_expr", 1)(e);
733 }
734
735 /**
736 This function works like `storeExpr`, but also returns access to the expression's
737 type through the `type` field of the return value.
738
739 Usage of this function from initialization macros is deprecated and may
740 cause compilation server issues. Use `Context.onAfterInitMacros` to
741 run your code once typer is ready to be used.
742 **/
743 public static function typeAndStoreExpr(e:Expr):{final type:Type.Ref<Type>; final expr:Expr;} {
744 assertInitMacrosDone();
745 return load("type_and_store_expr", 1)(e);
579746 }
580747
581748 /**
586753 `externFile` has changed.
587754
588755 Has no effect if the compilation cache is not used.
756
757 Usage of this function from initialization macros is deprecated and may
758 cause compilation server issues. Use `Context.onAfterInitMacros` to
759 run your code once typer is ready to be used.
589760 **/
590761 public static function registerModuleDependency(modulePath:String, externFile:String) {
762 assertInitMacrosDone();
591763 load("register_module_dependency", 2)(modulePath, externFile);
592764 }
593765
605777 stopTimer();
606778 ```
607779 **/
608 public static function timer(id:String):()->Void {
780 public static function timer(id:String):() -> Void {
609781 return load("timer", 1)(id);
782 }
783
784 /**
785 Executes `code` in a context that has `imports` and `usings` added.
786
787 This is equivalent to temporarily having `import` and `using` statements in a file. These
788 are only active during the execution of `code` and do not affect anything afterwards. This
789 is true even if `code` throws an exception.
790
791 If any argument is `null`, the result is unspecified.
792
793 Usage of this function from initialization macros is deprecated and may
794 cause compilation server issues. Use `Context.onAfterInitMacros` to
795 run your code once typer is ready to be used.
796 **/
797 public static function withImports<X>(imports:Array<String>, usings:Array<String>, code:() -> X):X {
798 assertInitMacrosDone();
799 return load("with_imports", 3)(imports, usings, code);
800 }
801
802
803 /**
804 Executes `code` in a context that has some compiler options set, restore the compiler to its
805 default behavior afterwards.
806
807 `allowInlining`: enable or disable inlining during typing with `typeExpr`.
808
809 `allowTransform`: when disabled, the code typed with `typeExpr` will be almost exactly the same
810 as the input code. This will disable some abstract types transformations.
811
812 Usage of this function from initialization macros is deprecated and may
813 cause compilation server issues. Use `Context.onAfterInitMacros` to
814 run your code once typer is ready to be used.
815 **/
816 public static function withOptions<X>(options:{?allowInlining:Bool,?allowTransform:Bool}, code : () -> X) : X {
817 assertInitMacrosDone();
818 return load("with_options", 2)(options, code);
610819 }
611820
612821 @:deprecated
640849 private static function sExpr(e:TypedExpr, pretty:Bool):String {
641850 return haxe.macro.Context.load("s_expr", 2)(e, pretty);
642851 }
852
853 @:allow(haxe.macro.Compiler)
854 private static function assertInitMacro():Void {
855 if (initMacrosDone()) {
856 var stack = getMacroStack();
857
858 warning(
859 "This API should only be used from initialization macros.",
860 if (stack.length > 2) stack[2] else currentPos()
861 );
862 }
863 }
864
865 private static function assertInitMacrosDone(includeSuggestion = true):Void {
866 #if haxe_next
867 if (!initMacrosDone()) {
868 var stack = getMacroStack();
869 var suggestion = includeSuggestion
870 ? "\nUse `Context.onAfterInitMacros` to register a callback to run when context is ready."
871 : "";
872
873 warning(
874 "Cannot use this API from initialization macros." + suggestion,
875 if (stack.length > 2) stack[2] else currentPos()
876 );
877 }
878 #end
879 }
643880 #end
644881 }
0 package haxe.macro;
1
2 enum DisplayMode {
3 None;
4 Default;
5 Definition;
6 TypeDefinition;
7 Implementation;
8 Package;
9 Hover;
10 References(withDefinition:Bool, findDescendants:Bool, findBase:Bool);
11 ModuleSymbols;
12 WorkspaceSymbols(filter:String);
13 Signature;
14 }
230230 public function generate() {
231231 print("var $_, $hxClasses = $hxClasses || {}, $estr = function() { return js.Boot.__string_rec(this,''); }");
232232 newline();
233 print("function $bind(o,m) { var f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; return f; };");
233 print(
234 #if (js_es < 5)
235 "function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $global.$haxeUID++; 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; }"
236 #else
237 "function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $global.$haxeUID++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = m.bind(o); o.hx__closures__[m.__id__] = f; } return f; }"
238 #end
239 );
234240 newline();
235241 for (t in api.types)
236242 genType(t);
5959 /**
6060 Represents an integer literal.
6161 **/
62 CInt(v:String);
62 CInt(v:String, ?s:String);
6363
6464 /**
6565 Represents a float literal.
6666 **/
67 CFloat(f:String);
67 CFloat(f:String, ?s:String);
6868
6969 /**
7070 Represents a string literal.
213213 `in`
214214 **/
215215 OpIn;
216
217 /**
218 `??`
219 **/
220 OpNullCoal;
216221 }
217222
218223 /**
249254 `...`
250255 **/
251256 OpSpread;
257 }
258
259 enum EFieldKind {
260 Normal;
261 Safe;
252262 }
253263
254264 /**
321331 var ?isFinal:Bool;
322332
323333 /**
334 Whether or not the variable is static.
335 **/
336 var ?isStatic:Bool;
337
338 /**
324339 Metadata associatied with the variable, if available.
325340 **/
326341 var ?meta:Metadata;
423438
424439 /**
425440 Field access on `e.field`.
426 **/
427 EField(e:Expr, field:String);
441
442 If `kind` is null, it is equal to Normal.
443 **/
444 EField(e:Expr, field:String, ?kind:EFieldKind);
428445
429446 /**
430447 Parentheses `(e)`.
545562 EDisplay(e:Expr, displayKind:DisplayKind);
546563
547564 /**
548 Used internally to provide completion.
549 **/
550 EDisplayNew(t:TypePath);
551
552 /**
553565 A `(econd) ? eif : eelse` expression.
554566 **/
555567 ETernary(econd:Expr, eif:Expr, eelse:Expr);
681693 var ?constraints:Array<ComplexType>;
682694
683695 /**
696 The optional default type of the type parameter.
697 **/
698 var ?defaultType:Null<ComplexType>;
699
700 /**
684701 The optional parameters of the type parameter.
685702 **/
686703 var ?params:Array<TypeParamDecl>;
9921009 The position of the error.
9931010 **/
9941011 public var pos:Position;
1012
1013 /**
1014 Child error messages, if any.
1015 **/
1016 private var childErrors:Array<Error>;
9951017
9961018 /**
9971019 Instantiates an error with given message and position.
6969 **/
7070 static public function iter(e:Expr, f:Expr->Void):Void {
7171 switch (e.expr) {
72 case EConst(_), EContinue, EBreak, EDisplayNew(_):
72 case EConst(_), EContinue, EBreak:
7373 case EField(e, _), EParenthesis(e), EUntyped(e), EThrow(e), EDisplay(e, _), ECheckType(e, _), EUnop(_, _, e), ECast(e, _), EIs(e, _) | EMeta(_, e):
7474 f(e);
7575 case EArray(e1, e2), EWhile(e1, e2, _), EBinop(_, e1, e2), EFor(e1, e2):
175175 case EDisplay(e, dk): EDisplay(f(e), dk);
176176 case ETernary(econd, eif, eelse): ETernary(f(econd), f(eif), f(eelse));
177177 case ECheckType(e, t): ECheckType(f(e), t);
178 case EDisplayNew(_), EContinue, EBreak:
178 case EContinue, EBreak:
179179 e.expr;
180180 case ETry(e, catches):
181181 var ret = [];
3131 @:hlNative("macro")
3232 #end
3333 class MacroStringTools {
34 #if (macro || display)
34 #if macro
3535 /**
3636 Formats `String` `s` using the usual interpolation rules.
3737
0 package haxe.macro;
1
2 import haxe.macro.Expr;
3
4 /**
5 Represents the internal structure generated with options assigned based on
6 the target platform.
7
8 Warning: `PlatformConfig` and the typedefs unique to its fields correspond to
9 compiler-internal data structures and might change in minor Haxe releases in
10 order to adapt to internal changes.
11 **/
12 typedef PlatformConfig = {
13 /**
14 Has a static type system, with not-nullable basic types (Int/Float/Bool)
15 **/
16 final staticTypeSystem:Bool;
17
18 /**
19 Has access to the "sys" package
20 **/
21 final sys:Bool;
22
23 /**
24 Captured variables handling (see before)
25 **/
26 final capturePolicy:CapturePolicy;
27
28 /**
29 When calling a method with optional args, do we replace the missing args with "null" constants
30 **/
31 final padNulls:Bool;
32
33 /**
34 Add a final return to methods not having one already - prevent some compiler warnings
35 **/
36 final addFinalReturn:Bool;
37
38 /**
39 Does the platform natively support overloaded functions
40 **/
41 final overloadFunctions:Bool;
42
43 /**
44 Can the platform use default values for non-nullable arguments
45 **/
46 final canSkipNonNullableArgument:Bool;
47
48 /**
49 Type paths that are reserved on the platform
50 **/
51 final reservedTypePaths:Array<TypePath>;
52
53 /**
54 Supports function == function
55 **/
56 final supportsFunctionEquality:Bool;
57
58 /**
59 Uses utf16 encoding with ucs2 api
60 **/
61 final usesUtf16:Bool;
62
63 /**
64 Target supports accessing `this` before calling `super(...)`
65 **/
66 final thisBeforeSuper:Bool;
67
68 /**
69 Target supports threads
70 **/
71 final supportsThreads:Bool;
72
73 /**
74 Target supports Unicode
75 **/
76 final supportsUnicode:Bool;
77
78 /**
79 Target supports rest arguments
80 **/
81 final supportsRestArgs:Bool;
82
83 /**
84 Exceptions handling config
85 **/
86 final exceptions:ExceptionsConfig;
87
88 /**
89 The scoping of local variables
90 **/
91 final scoping:VarScopingConfig;
92
93 /**
94 Target supports atomic operations via haxe.Atomic
95 **/
96 final supportsAtomics:Bool;
97
98 }
99
100 enum CapturePolicy {
101 /**
102 Do nothing, let the platform handle it
103 **/
104 None;
105
106 /**
107 Wrap all captured variables into a single-element array to allow modifications
108 **/
109 WrapRef;
110
111 /**
112 Similar to wrap ref, but will only apply to the locals that are declared in loops
113 **/
114 LoopVars;
115 }
116
117 typedef VarScopingConfig = {
118 final scope:VarScope;
119 final flags:Array<VarScopingFlags>;
120 }
121
122 enum VarScope {
123 FunctionScope;
124 BlockScope;
125 }
126
127 enum VarScopingFlags {
128 /**
129 Variables are hoisted in their scope
130 **/
131 VarHoisting;
132
133 /**
134 It's not allowed to shadow existing variables in a scope.
135 **/
136 NoShadowing;
137
138 /**
139 It's not allowed to shadow a `catch` variable.
140 **/
141 NoCatchVarShadowing;
142
143 /**
144 Local vars cannot have the same name as the current top-level package or
145 (if in the root package) current class name
146 **/
147 ReserveCurrentTopLevelSymbol;
148
149 /**
150 Local vars cannot have a name used for any top-level symbol
151 (packages and classes in the root package)
152 **/
153 ReserveAllTopLevelSymbols;
154
155 /**
156 Reserve all type-paths converted to "flat path" with `Path.flat_path`
157 **/
158 ReserveAllTypesFlat;
159
160 /**
161 List of names cannot be taken by local vars
162 **/
163 ReserveNames(names:Array<String>);
164
165 /**
166 Cases in a `switch` won't have blocks, but will share the same outer scope.
167 **/
168 SwitchCasesNoBlocks;
169 }
170
171 typedef ExceptionsConfig = {
172 /**
173 Base types which may be thrown from Haxe code without wrapping.
174 **/
175 final nativeThrows:Array<TypePath>;
176
177 /**
178 Base types which may be caught from Haxe code without wrapping.
179 **/
180 final nativeCatches:Array<TypePath>;
181
182 /**
183 Hint exceptions filter to avoid wrapping for targets, which can throw/catch any type
184 Ignored on targets with a specific native base type for exceptions.
185 **/
186 final avoidWrapping:Bool;
187
188 /**
189 Path of a native class or interface, which can be used for wildcard catches.
190 **/
191 final wildcardCatch:TypePath;
192
193 /**
194 Path of a native base class or interface, which can be thrown.
195 This type is used to cast `haxe.Exception.thrown(v)` calls to.
196 For example `throw 123` is compiled to `throw (cast Exception.thrown(123):ec_base_throw)`
197 **/
198 final baseThrow:TypePath;
199
200 /**
201 Checks if throwing this expression is a special case for current target
202 and should not be modified.
203 **/
204 // final specialThrow:(TypedExpr)->Bool;
205 }
5959 #end
6060 }
6161
62 #if (macro || display)
62 #if macro
6363 /**
6464 Converts a `haxe.macro.Position` to a `haxe.display.Position.Location`.
6565
7474 case OpInterval: "...";
7575 case OpArrow: "=>";
7676 case OpIn: "in";
77 case OpNullCoal: "??";
7778 case OpAssignOp(op):
7879 printBinop(op) + "=";
7980 }
8081
8182 function escapeString(s:String, delim:String) {
8283 return delim
83 + s.replace("\n", "\\n")
84 + s.replace('\\', '\\\\')
85 .replace("\n", "\\n")
8486 .replace("\t", "\\t")
8587 .replace("\r", "\\r")
8688 .replace("'", "\\'")
99101 return switch (c) {
100102 case CString(s, SingleQuotes): printFormatString(s);
101103 case CString(s, _): printString(s);
102 case CIdent(s), CInt(s), CFloat(s):
104 case CIdent(s), CInt(s, null), CFloat(s, null):
103105 s;
106 case CInt(s, suffix), CFloat(s, suffix):
107 s + suffix;
104108 case CRegexp(s, opt): '~/$s/$opt';
105109 }
106110
191195 return (tpd.meta != null && tpd.meta.length > 0 ? tpd.meta.map(printMetadata).join(" ") + " " : "")
192196 + tpd.name
193197 + (tpd.params != null && tpd.params.length > 0 ? "<" + tpd.params.map(printTypeParamDecl).join(", ") + ">" : "")
194 + (tpd.constraints != null && tpd.constraints.length > 0 ? ":(" + tpd.constraints.map(printComplexType).join(", ") + ")" : "");
198 + (tpd.constraints != null && tpd.constraints.length > 0 ? ":(" + tpd.constraints.map(printComplexType).join(", ") + ")" : "")
199 + (tpd.defaultType != null ? "=" + printComplexType(tpd.defaultType) : "");
195200
196201 public function printFunctionArg(arg:FunctionArg)
197202 return (arg.opt ? "?" : "") + arg.name + opt(arg.type, printComplexType, ":") + opt(arg.value, printExpr, " = ");
234239 case EConst(c): printConstant(c);
235240 case EArray(e1, e2): '${printExpr(e1)}[${printExpr(e2)}]';
236241 case EBinop(op, e1, e2): '${printExpr(e1)} ${printBinop(op)} ${printExpr(e2)}';
237 case EField(e1, n): '${printExpr(e1)}.$n';
242 case EField(e1, n, kind): kind == Safe ? '${printExpr(e1)}?.$n' : '${printExpr(e1)}.$n';
238243 case EParenthesis(e1): '(${printExpr(e1)})';
239244 case EObjectDecl(fl):
240245 "{ " + fl.map(function(fld) return printObjectField(fld)).join(", ") + " }";
245250 case EUnop(op, false, e1): printUnop(op) + printExpr(e1);
246251 case EFunction(FNamed(no,inlined), func): (inlined ? 'inline ' : '') + 'function $no' + printFunction(func);
247252 case EFunction(kind, func): (kind != FArrow ? "function" : "") + printFunction(func, kind);
248 case EVars(vl): "var " + vl.map(printVar).join(", ");
253 case EVars([]): "var ";
254 case EVars(vl): ((vl[0].isStatic) ? "static " : "") + ((vl[0].isFinal) ? "final " : "var ") + vl.map(printVar).join(", ");
249255 case EBlock([]): '{ }';
250256 case EBlock(el):
251257 var old = tabs;
280286 case ECast(e1, _): "cast " + printExpr(e1);
281287 case EIs(e1, ct): '${printExpr(e1)} is ${printComplexType(ct)}';
282288 case EDisplay(e1, _): '#DISPLAY(${printExpr(e1)})';
283 case EDisplayNew(tp): '#DISPLAY(${printTypePath(tp)})';
284289 case ETernary(econd, eif, eelse): '${printExpr(econd)} ? ${printExpr(eif)} : ${printExpr(eelse)}';
285290 case ECheckType(e1, ct): '(${printExpr(e1)} : ${printComplexType(ct)})';
286291 case EMeta({ name:":implicitReturn" }, { expr:EReturn(e1) }): printExpr(e1);
542547 case EDisplay(e, displayKind):
543548 add("EDisplay");
544549 loopI(e);
545 case EDisplayNew(t):
546 add("EDisplayNew");
547550 case ETernary(econd, eif, eelse):
548551 add("ETernary");
549552 loopI(econd);
179179 `KTypeParameter` kind.
180180 **/
181181 var t:Type;
182
183 /**
184 The default type for this type parameter.
185 **/
186 var ?defaultType:Null<Type>;
182187 }
183188
184189 /**
8484 pos: cf.pos,
8585 meta: cf.meta.get(),
8686 } else {
87 throw "Invalid TAnonymous";
87 throw "Invalid TAnonymous";
8888 }
8989 }
9090
161161 }
162162 }
163163
164 #if (macro || display)
164 #if macro
165165 /**
166166 Follows all typedefs of `t` to reach the actual type.
167167
173173
174174 If `t` is null, an internal exception is thrown.
175175
176 Usage example:
176 Usage example with monomorphs:
177177 var t = Context.typeof(macro null); // TMono(<mono>)
178178 var ts = Context.typeof(macro "foo"); //TInst(String,[])
179179 Context.unify(t, ts);
180180 trace(t); // TMono(<mono>)
181 trace(t.follow()); //TInst(String,[])
182
183 Usage example with typedefs:
184 var t = Context.typeof(macro ("foo" :MyString)); // typedef MyString = String
185 trace(t); // TType(MyString,[])
181186 trace(t.follow()); //TInst(String,[])
182187 **/
183188 static public inline function follow(t:Type, ?once:Bool):Type
362367 return null;
363368 #end
364369 }
370
371 /**
372 Changes the name of the variable in the typed expression.
373 **/
374 static public function setVarName(t:TVar, name:String) {
375 Context.load("set_var_name", 2)(t, name);
376 }
377
378 /**
379 Converts type `t` to `haxe.macro.Type.ModuleType`.
380 **/
381 static public function toModuleType(t:Type):ModuleType {
382 #if (neko || eval)
383 return Context.load("type_to_module_type", 1)(t);
384 #else
385 return null;
386 #end
387 }
388
389 /**
390 Creates a type from the `haxe.macro.Type.ModuleType` argument.
391 **/
392 static public function fromModuleType(mt:ModuleType):Type {
393 #if (neko || eval)
394 return Context.load("module_type_to_type", 1)(mt);
395 #else
396 return null;
397 #end
398 }
365399 #end
366400
367401 /**
166166 }
167167 }
168168
169 #if (macro || display)
169 #if macro
170170 static public function toString(t:TypedExpr, ?pretty = false):String {
171171 return @:privateAccess haxe.macro.Context.sExpr(t, pretty);
172172 }
4242 @:hlNative("std", "ptr_compare") static function comparePointer(a:Dynamic, b:Dynamic):Int;
4343 #if (hl_ver >= version("1.12.0"))
4444 @:hlNative("std", "is_prim_loaded") static function isPrimLoaded(f:haxe.Constraints.Function):Bool;
45 @:hlNative("?std", "mem_compact") static function compact<T>( v : T, exclude : hl.NativeArray<Dynamic>, flags : Int, outCount : hl.Ref<Int> ) : T;
46 @:hlNative("?std", "sys_check_reload") static function checkReload( ?debugFile : hl.Bytes ) : Bool;
47 #end
48 #if (hl_ver >= version("1.13.0"))
49 @:hlNative("?std", "sys_has_debugger") static function hasDebugger() : Bool;
4550 #end
4651 }
0 package hl;
1
2 @:hlNative("std", "atomic_")
3 extern class Atomics {
4 static function add32(r:hl.Ref<Int>, a:Int):Int;
5 static function sub32(r:hl.Ref<Int>, a:Int):Int;
6 static function and32(r:hl.Ref<Int>, a:Int):Int;
7 static function or32(r:hl.Ref<Int>, a:Int):Int;
8 static function xor32(r:hl.Ref<Int>, a:Int):Int;
9 static function compareExchange32(r:hl.Ref<Int>, a:Int, b:Int):Int;
10 static function exchange32(r:hl.Ref<Int>, val:Int):Int;
11 static function load32(r:hl.Ref<Int>):Int;
12 static function store32(r:hl.Ref<Int>, val:Int):Int;
13
14 static function compareExchangePtr(r:hl.Ref<Dynamic>, a:Dynamic, b:Dynamic):Dynamic;
15 static function exchangePtr(r:hl.Ref<Dynamic>, val:Dynamic):Dynamic;
16 static function loadPtr(r:hl.Ref<Dynamic>):Dynamic;
17 static function storePtr(r:hl.Ref<Dynamic>, val:Dynamic):Dynamic;
18 }
0 package hl;
1
2 #if (hl_ver >= version("1.13.0"))
3 /**
4 CArray is a compact array where all objects are memory aligned and stored as a single GC block.
5 You must hold a reference to the CArray while any of the objects it contains is still referenced somewhere.
6 **/
7 abstract CArray<T>(Abstract<"hl_carray">) {
8
9 public var length(get,never) : Int;
10
11 inline function get_length() return getLen(cast this);
12
13 @:arrayAccess inline function get( index : Int ) : T return getIndex(cast this, index);
14
15 public static function alloc<T>( cl : Class<T>, size : Int ) : CArray<T> {
16 return cast alloc_carray( (cast cl:BaseType).__type__ , size );
17 }
18
19 @:hlNative("?std","carray_get")
20 static function getIndex( arr : CArray<Dynamic>, index : Int ) : Dynamic {
21 return null;
22 }
23
24 @:hlNative("?std","carray_length")
25 static function getLen( arr : CArray<Dynamic> ) : Int {
26 return 0;
27 }
28
29 @:hlNative("?std","alloc_carray")
30 static function alloc_carray( t : hl.Type, size : Int ) : CArray<Dynamic> {
31 return null;
32 }
33
34 }
35 #end
2121
2222 package hl;
2323
24 @:coreType @:notNull @:runtimeValue abstract I64 to Int from Int {}
24 @:coreType @:notNull @:runtimeValue abstract I64 from Int {
25
26 /**
27 Destructively cast to Int
28 **/
29 public inline function toInt():Int {
30 return cast this;
31 }
32
33 @:to
34 @:deprecated("Implicit cast from I64 to Int (32 bits) is deprecated. Use .toInt() or explicitly cast instead.")
35 inline function implicitToInt(): Int {
36 return toInt();
37 }
38
39 #if (hl_ver >= version("1.12.0") && !hl_legacy32)
40 @:op(a+b) function add(v:I64) : I64;
41 @:op(a-b) function sub(v:I64) : I64;
42 @:op(a*b) function mul(v:I64) : I64;
43 @:op(a/b) function div(v:I64) : I64;
44 @:op(a%b) function mod(v:I64) : I64;
45 @:op(a<<b) function shl(v:Int) : I64;
46 @:op(a>>b) function shr(v:Int) : I64;
47 @:op(a>>>b) function ushr(v:Int) : I64;
48 @:op(a|b) function or(v:I64) : I64;
49 @:op(a&b) function and(v:I64) : I64;
50 @:op(a^b) function xor(v:I64) : I64;
51
52 @:op(-a) function neg() : I64;
53 @:op(~a) inline function compl() : I64 { return (-1:I64) - this; }
54 @:op(++a) function incr() : I64;
55 @:op(--a) function decr() : I64;
56 @:op(a++) function pincr() : I64;
57 @:op(a--) function pdecr() : I64;
58
59 @:op(a==b) function eq(v:I64) : Bool;
60 @:op(a>=b) function gte(v:I64) : Bool;
61 @:op(a<=b) function lte(v:I64) : Bool;
62 @:op(a>b) function gt(v:I64) : Bool;
63 @:op(a<b) function lt(v:I64) : Bool;
64 #end
65
66 }
149149 }
150150
151151 public static function dialog(title:String, text:String, flags:haxe.EnumFlags<DialogFlags>) {
152 @:privateAccess _dialog(title.bytes, text.bytes, flags.toInt());
152 return @:privateAccess _dialog(title.bytes, text.bytes, flags.toInt()) != 0;
153153 }
154154
155155 @:hlNative("ui", "ui_loop")
8585 return makePath(v);
8686 }
8787
88 public static function putEnv(s:String, v:String):Void {
88 public static function putEnv(s:String, v:Null<String>):Void {
8989 if (!put_env(getPath(s), if (v == null) null else getPath(v)))
9090 throw "putEnv() failure";
9191 }
3737 static inline function get_allTypes():hl.types.BytesMap
3838 return untyped $allTypes();
3939
40 @:keep static function init():Void {
40 @:keep static function init():Bool {
41 if( allTypes != null )
42 return false;
4143 untyped $allTypes(new hl.types.BytesMap());
44 return true;
4245 }
4346
4447 @:keep static function initClass(ct:hl.Type, t:hl.Type, name:hl.Bytes):hl.BaseType.Class@:privateAccess {
45 var c:hl.BaseType.Class = ct.allocObject();
48 var c:hl.BaseType.Class = cast t.getGlobal();
49 if( c != null )
50 return c;
51 c = ct.allocObject();
4652 t.setGlobal(c);
4753 c.__type__ = t;
4854 c.__name__ = String.fromUCS2(name);
5157 }
5258
5359 @:keep static function initEnum(et:hl.Type, t:hl.Type):hl.BaseType.Enum@:privateAccess {
54 var e:hl.BaseType.Enum = et.allocObject();
60 var e:hl.BaseType.Enum = cast t.getGlobal();
61 if( e != null )
62 return e;
63 e = et.allocObject();
5564 e.__type__ = t;
5665 e.__evalues__ = t.getEnumValues();
5766 e.__ename__ = t.getTypeName();
245254 }
246255
247256 public static function enumParameters(e:EnumValue):Array<Dynamic> {
257 if( e == null ) (e:Dynamic)(); // trigger null access
248258 var arr = _enumParameters(e);
249259 return cast hl.types.ArrayObj.alloc(arr);
250260 }
88
99 @:noCompletion var __exceptionMessage:String;
1010 @:noCompletion var __exceptionStack:Null<CallStack>;
11 @:noCompletion var __nativeStack:hl.NativeArray<hl.Bytes>;
11 @:noCompletion var __nativeStack:hl.NativeArray<#if (hl_ver >= "1.12.0") haxe.NativeStackTrace.Symbol #else hl.Bytes #end>;
1212 @:noCompletion @:ifFeature("haxe.Exception.get_stack") var __skipStack:Int = 0;
1313 @:noCompletion var __nativeException:Any;
1414 @:noCompletion var __previousException:Null<Exception>;
0 /*
1 * Copyright (C)2005-2019 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package haxe;
23
24 using haxe.Int64;
25
26 #if (hl_ver >= version("1.12.0") && !hl_legacy32)
27
28 import haxe.Int64Helper;
29
30 private typedef __Int64 = hl.I64;
31
32 @:coreApi
33 @:transitive
34 abstract Int64(__Int64) from __Int64 to __Int64 {
35
36 static var MASK : hl.I64 = {
37 var v : hl.I64 = 0xFFFF;
38 v | (v << 16);
39 }
40
41 public static inline function make(high:Int32, low:Int32):Int64 {
42 var h : hl.I64 = high;
43 var l : hl.I64 = low;
44 return cast ((h << 32) | (l&MASK));
45 }
46
47 private inline function new(x:__Int64)
48 this = x;
49
50 private var val(get, set):__Int64;
51
52 inline function get_val():__Int64
53 return this;
54
55 inline function set_val(x:__Int64):__Int64
56 return this = x;
57
58 public var high(get, never):Int32;
59
60 inline function get_high():Int32
61 return cast(this >> 32);
62
63 public var low(get, never):Int32;
64
65 inline function get_low():Int32
66 return cast this;
67
68 public inline function copy():Int64
69 return new Int64(this);
70
71 @:from public static inline function ofInt(x:Int):Int64
72 return cast x;
73
74 @:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead')
75 inline public static function is(val:Dynamic):Bool
76 return isInt64(val);
77
78 inline public static function isInt64(val:Dynamic):Bool
79 return hl.Type.getDynamic(val).kind == HI64;
80
81 public static inline function toInt(x:Int64):Int {
82 if (x.val < 0x80000000 || x.val > 0x7FFFFFFF)
83 throw "Overflow";
84 return cast x.val;
85 }
86
87 public static inline function getHigh(x:Int64):Int32
88 return cast(x.val >> 32);
89
90 public static inline function getLow(x:Int64):Int32
91 return cast(x.val);
92
93 public static inline function isNeg(x:Int64):Bool
94 return x.val < 0;
95
96 public static inline function isZero(x:Int64):Bool
97 return x.val == 0;
98
99 public static inline function compare(a:Int64, b:Int64):Int {
100 if (a.val < b.val)
101 return -1;
102 if (a.val > b.val)
103 return 1;
104 return 0;
105 }
106
107 public static inline function ucompare(a:Int64, b:Int64):Int {
108 if (a.val < 0)
109 return (b.val < 0) ? compare(a, b) : 1;
110 return (b.val < 0) ? -1 : compare(a, b);
111 }
112
113 public static inline function toStr(x:Int64):String
114 return '${x.val}';
115
116 public static inline function divMod(dividend:Int64, divisor:Int64):{quotient:Int64, modulus:Int64}
117 return {quotient: dividend / divisor, modulus: dividend % divisor};
118
119 private inline function toString():String
120 return '$this';
121
122 public static function parseString(sParam:String):Int64 {
123 // can this be done?: return new Int64( java.lang.Long.LongClass.parseLong( sParam ) );
124 return Int64Helper.parseString(sParam);
125 }
126
127 public static function fromFloat(f:Float):Int64 {
128 return Int64Helper.fromFloat(f);
129 }
130
131 @:op(-A) public static function neg(x:Int64):Int64
132 return -x.val;
133
134 @:op(++A) private inline function preIncrement():Int64
135 return ++this;
136
137 @:op(A++) private inline function postIncrement():Int64
138 return this++;
139
140 @:op(--A) private inline function preDecrement():Int64
141 return --this;
142
143 @:op(A--) private inline function postDecrement():Int64
144 return this--;
145
146 @:op(A + B) public static inline function add(a:Int64, b:Int64):Int64
147 return a.val + b.val;
148
149 @:op(A + B) @:commutative private static inline function addInt(a:Int64, b:Int):Int64
150 return a.val + b;
151
152 @:op(A - B) public static inline function sub(a:Int64, b:Int64):Int64
153 return a.val - b.val;
154
155 @:op(A - B) private static inline function subInt(a:Int64, b:Int):Int64
156 return a.val - b;
157
158 @:op(A - B) private static inline function intSub(a:Int, b:Int64):Int64
159 return (a:hl.I64) - b.val;
160
161 @:op(A * B) public static inline function mul(a:Int64, b:Int64):Int64
162 return a.val * b.val;
163
164 @:op(A * B) @:commutative private static inline function mulInt(a:Int64, b:Int):Int64
165 return a.val * b;
166
167 @:op(A / B) public static inline function div(a:Int64, b:Int64):Int64
168 return a.val / b.val;
169
170 @:op(A / B) private static inline function divInt(a:Int64, b:Int):Int64
171 return a.val / b;
172
173 @:op(A / B) private static inline function intDiv(a:Int, b:Int64):Int64
174 return (a:hl.I64) / b.val;
175
176 @:op(A % B) public static inline function mod(a:Int64, b:Int64):Int64
177 return a.val % b.val;
178
179 @:op(A % B) private static inline function modInt(a:Int64, b:Int):Int64
180 return a.val % b;
181
182 @:op(A % B) private static inline function intMod(a:Int, b:Int64):Int64
183 return (a:hl.I64) % b.val;
184
185 @:op(A == B) public static inline function eq(a:Int64, b:Int64):Bool
186 return a.val == b.val;
187
188 @:op(A == B) @:commutative private static inline function eqInt(a:Int64, b:Int):Bool
189 return a.val == b;
190
191 @:op(A != B) public static inline function neq(a:Int64, b:Int64):Bool
192 return a.val != b.val;
193
194 @:op(A != B) @:commutative private static inline function neqInt(a:Int64, b:Int):Bool
195 return a.val != (b:hl.I64);
196
197 @:op(A < B) private static inline function lt(a:Int64, b:Int64):Bool
198 return a.val < b.val;
199
200 @:op(A < B) private static inline function ltInt(a:Int64, b:Int):Bool
201 return a.val < b;
202
203 @:op(A < B) private static inline function intLt(a:Int, b:Int64):Bool
204 return (a:hl.I64) < b.val;
205
206 @:op(A <= B) private static inline function lte(a:Int64, b:Int64):Bool
207 return a.val <= b.val;
208
209 @:op(A <= B) private static inline function lteInt(a:Int64, b:Int):Bool
210 return a.val <= b;
211
212 @:op(A <= B) private static inline function intLte(a:Int, b:Int64):Bool
213 return (a:hl.I64) <= b.val;
214
215 @:op(A > B) private static inline function gt(a:Int64, b:Int64):Bool
216 return a.val > b.val;
217
218 @:op(A > B) private static inline function gtInt(a:Int64, b:Int):Bool
219 return a.val > b;
220
221 @:op(A > B) private static inline function intGt(a:Int, b:Int64):Bool
222 return (a:hl.I64) > b.val;
223
224 @:op(A >= B) private static inline function gte(a:Int64, b:Int64):Bool
225 return a.val >= b.val;
226
227 @:op(A >= B) private static inline function gteInt(a:Int64, b:Int):Bool
228 return a.val >= b;
229
230 @:op(A >= B) private static inline function intGte(a:Int, b:Int64):Bool
231 return (a:hl.I64) >= b.val;
232
233 @:op(~A) private static inline function complement(x:Int64):Int64
234 return ~x.val;
235
236 @:op(A & B) public static inline function and(a:Int64, b:Int64):Int64
237 return a.val & b.val;
238
239 @:op(A | B) public static inline function or(a:Int64, b:Int64):Int64
240 return a.val | b.val;
241
242 @:op(A ^ B) public static inline function xor(a:Int64, b:Int64):Int64
243 return a.val ^ b.val;
244
245 @:op(A << B) public static inline function shl(a:Int64, b:Int):Int64
246 return a.val << b;
247
248 @:op(A >> B) public static inline function shr(a:Int64, b:Int):Int64
249 return a.val >> b;
250
251 @:op(A >>> B) public static inline function ushr(a:Int64, b:Int):Int64
252 return a.val >>> b;
253 }
254
255 #else
256
257 @:transitive
258 abstract Int64(__Int64) from __Int64 to __Int64 {
259 private inline function new(x:__Int64)
260 this = x;
261
262 public inline function copy():Int64
263 return make(high, low);
264
265 public static inline function make(high:Int32, low:Int32):Int64
266 return new Int64(new __Int64(high, low));
267
268 @:from public static inline function ofInt(x:Int):Int64
269 return make(x >> 31, x);
270
271 public static inline function toInt(x:Int64):Int {
272 if (x.high != x.low >> 31)
273 throw "Overflow";
274
275 return x.low;
276 }
277
278 @:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead')
279 inline public static function is(val:Dynamic):Bool {
280 return isInt64(val);
281 }
282
283 inline public static function isInt64(val:Dynamic):Bool
284 return Std.isOfType(val, __Int64);
285
286 @:deprecated("Use high instead")
287 public static inline function getHigh(x:Int64):Int32
288 return x.high;
289
290 @:deprecated("Use low instead")
291 public static inline function getLow(x:Int64):Int32
292 return x.low;
293
294 public static inline function isNeg(x:Int64):Bool
295 return x.high < 0;
296
297 public static inline function isZero(x:Int64):Bool
298 return x == 0;
299
300 public static inline function compare(a:Int64, b:Int64):Int {
301 var v = a.high - b.high;
302 v = if (v != 0) v else Int32.ucompare(a.low, b.low);
303 return a.high < 0 ? (b.high < 0 ? v : -1) : (b.high >= 0 ? v : 1);
304 }
305
306 public static inline function ucompare(a:Int64, b:Int64):Int {
307 var v = Int32.ucompare(a.high, b.high);
308 return if (v != 0) v else Int32.ucompare(a.low, b.low);
309 }
310
311 public static inline function toStr(x:Int64):String
312 return x.toString();
313
314 function toString():String {
315 var i:Int64 = cast this;
316 if (i == 0)
317 return "0";
318 var str = "";
319 var neg = false;
320 if (i.isNeg()) {
321 neg = true;
322 // i = -i; cannot negate here as --9223372036854775808 = -9223372036854775808
323 }
324 var ten:Int64 = 10;
325 while (i != 0) {
326 var r = i.divMod(ten);
327 if (r.modulus.isNeg()) {
328 str = Int64.neg(r.modulus).low + str;
329 i = Int64.neg(r.quotient);
330 } else {
331 str = r.modulus.low + str;
332 i = r.quotient;
333 }
334 }
335 if (neg)
336 str = "-" + str;
337 return str;
338 }
339
340 public static inline function parseString(sParam:String):Int64 {
341 return Int64Helper.parseString(sParam);
342 }
343
344 public static inline function fromFloat(f:Float):Int64 {
345 return Int64Helper.fromFloat(f);
346 }
347
348 public static function divMod(dividend:Int64, divisor:Int64):{quotient:Int64, modulus:Int64} {
349 // Handle special cases of 0 and 1
350 if (divisor.high == 0) {
351 switch (divisor.low) {
352 case 0:
353 throw "divide by zero";
354 case 1:
355 return {quotient: dividend.copy(), modulus: 0};
356 }
357 }
358
359 var divSign = dividend.isNeg() != divisor.isNeg();
360
361 var modulus = dividend.isNeg() ? -dividend : dividend.copy();
362 divisor = divisor.isNeg() ? -divisor : divisor;
363
364 var quotient:Int64 = 0;
365 var mask:Int64 = 1;
366
367 while (!divisor.isNeg()) {
368 var cmp = ucompare(divisor, modulus);
369 divisor <<= 1;
370 mask <<= 1;
371 if (cmp >= 0)
372 break;
373 }
374
375 while (mask != 0) {
376 if (ucompare(modulus, divisor) >= 0) {
377 quotient |= mask;
378 modulus -= divisor;
379 }
380 mask >>>= 1;
381 divisor >>>= 1;
382 }
383
384 if (divSign)
385 quotient = -quotient;
386 if (dividend.isNeg())
387 modulus = -modulus;
388
389 return {
390 quotient: quotient,
391 modulus: modulus
392 };
393 }
394
395 @:op(-A) public static inline function neg(x:Int64):Int64 {
396 var high = ~x.high;
397 var low = -x.low;
398 if (low == 0)
399 high++;
400 return make(high, low);
401 }
402
403 @:op(++A) private inline function preIncrement():Int64 {
404 this = copy();
405 this.low++;
406 if (this.low == 0)
407 this.high++;
408 return cast this;
409 }
410
411 @:op(A++) private inline function postIncrement():Int64 {
412 var ret = this;
413 preIncrement();
414 return ret;
415 }
416
417 @:op(--A) private inline function preDecrement():Int64 {
418 this = copy();
419 if (this.low == 0)
420 this.high--;
421 this.low--;
422 return cast this;
423 }
424
425 @:op(A--) private inline function postDecrement():Int64 {
426 var ret = this;
427 preDecrement();
428 return ret;
429 }
430
431 @:op(A + B) public static inline function add(a:Int64, b:Int64):Int64 {
432 var high = a.high + b.high;
433 var low = a.low + b.low;
434 if (Int32.ucompare(low, a.low) < 0)
435 high++;
436 return make(high, low);
437 }
438
439 @:op(A + B) @:commutative private static inline function addInt(a:Int64, b:Int):Int64
440 return add(a, b);
441
442 @:op(A - B) public static inline function sub(a:Int64, b:Int64):Int64 {
443 var high = a.high - b.high;
444 var low = a.low - b.low;
445 if (Int32.ucompare(a.low, b.low) < 0)
446 high--;
447 return make(high, low);
448 }
449
450 @:op(A - B) private static inline function subInt(a:Int64, b:Int):Int64
451 return sub(a, b);
452
453 @:op(A - B) private static inline function intSub(a:Int, b:Int64):Int64
454 return sub(a, b);
455
456 @:op(A * B)
457 public static #if !lua inline #end function mul(a:Int64, b:Int64):Int64 {
458 var mask = 0xFFFF;
459 var al = a.low & mask, ah = a.low >>> 16;
460 var bl = b.low & mask, bh = b.low >>> 16;
461 var p00 = al * bl;
462 var p10 = ah * bl;
463 var p01 = al * bh;
464 var p11 = ah * bh;
465 var low = p00;
466 var high = p11 + (p01 >>> 16) + (p10 >>> 16);
467 p01 <<= 16;
468 low += p01;
469 if (Int32.ucompare(low, p01) < 0)
470 high++;
471 p10 <<= 16;
472 low += p10;
473 if (Int32.ucompare(low, p10) < 0)
474 high++;
475 high += a.low * b.high + a.high * b.low;
476 return make(high, low);
477 }
478
479 @:op(A * B) @:commutative private static inline function mulInt(a:Int64, b:Int):Int64
480 return mul(a, b);
481
482 @:op(A / B) public static inline function div(a:Int64, b:Int64):Int64
483 return divMod(a, b).quotient;
484
485 @:op(A / B) private static inline function divInt(a:Int64, b:Int):Int64
486 return div(a, b);
487
488 @:op(A / B) private static inline function intDiv(a:Int, b:Int64):Int64
489 return div(a, b).toInt();
490
491 @:op(A % B) public static inline function mod(a:Int64, b:Int64):Int64
492 return divMod(a, b).modulus;
493
494 @:op(A % B) private static inline function modInt(a:Int64, b:Int):Int64
495 return mod(a, b).toInt();
496
497 @:op(A % B) private static inline function intMod(a:Int, b:Int64):Int64
498 return mod(a, b).toInt();
499
500 @:op(A == B) public static inline function eq(a:Int64, b:Int64):Bool
501 return a.high == b.high && a.low == b.low;
502
503 @:op(A == B) @:commutative private static inline function eqInt(a:Int64, b:Int):Bool
504 return eq(a, b);
505
506 @:op(A != B) public static inline function neq(a:Int64, b:Int64):Bool
507 return a.high != b.high || a.low != b.low;
508
509 @:op(A != B) @:commutative private static inline function neqInt(a:Int64, b:Int):Bool
510 return neq(a, b);
511
512 @:op(A < B) private static inline function lt(a:Int64, b:Int64):Bool
513 return compare(a, b) < 0;
514
515 @:op(A < B) private static inline function ltInt(a:Int64, b:Int):Bool
516 return lt(a, b);
517
518 @:op(A < B) private static inline function intLt(a:Int, b:Int64):Bool
519 return lt(a, b);
520
521 @:op(A <= B) private static inline function lte(a:Int64, b:Int64):Bool
522 return compare(a, b) <= 0;
523
524 @:op(A <= B) private static inline function lteInt(a:Int64, b:Int):Bool
525 return lte(a, b);
526
527 @:op(A <= B) private static inline function intLte(a:Int, b:Int64):Bool
528 return lte(a, b);
529
530 @:op(A > B) private static inline function gt(a:Int64, b:Int64):Bool
531 return compare(a, b) > 0;
532
533 @:op(A > B) private static inline function gtInt(a:Int64, b:Int):Bool
534 return gt(a, b);
535
536 @:op(A > B) private static inline function intGt(a:Int, b:Int64):Bool
537 return gt(a, b);
538
539 @:op(A >= B) private static inline function gte(a:Int64, b:Int64):Bool
540 return compare(a, b) >= 0;
541
542 @:op(A >= B) private static inline function gteInt(a:Int64, b:Int):Bool
543 return gte(a, b);
544
545 @:op(A >= B) private static inline function intGte(a:Int, b:Int64):Bool
546 return gte(a, b);
547
548 @:op(~A) private static inline function complement(a:Int64):Int64
549 return make(~a.high, ~a.low);
550
551 @:op(A & B) public static inline function and(a:Int64, b:Int64):Int64
552 return make(a.high & b.high, a.low & b.low);
553
554 @:op(A | B) public static inline function or(a:Int64, b:Int64):Int64
555 return make(a.high | b.high, a.low | b.low);
556
557 @:op(A ^ B) public static inline function xor(a:Int64, b:Int64):Int64
558 return make(a.high ^ b.high, a.low ^ b.low);
559
560 @:op(A << B) public static inline function shl(a:Int64, b:Int):Int64 {
561 b &= 63;
562 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);
563 }
564
565 @:op(A >> B) public static inline function shr(a:Int64, b:Int):Int64 {
566 b &= 63;
567 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));
568 }
569
570 @:op(A >>> B) public static inline function ushr(a:Int64, b:Int):Int64 {
571 b &= 63;
572 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));
573 }
574
575 public var high(get, never):Int32;
576
577 private inline function get_high()
578 return this.high;
579
580 private inline function set_high(x)
581 return this.high = x;
582
583 public var low(get, never):Int32;
584
585 private inline function get_low()
586 return this.low;
587
588 private inline function set_low(x)
589 return this.low = x;
590 }
591
592 private typedef __Int64 = ___Int64;
593
594 private class ___Int64 {
595 public var high:Int32;
596 public var low:Int32;
597
598 public inline function new(high, low) {
599 this.high = high;
600 this.low = low;
601 }
602
603 public function toString():String
604 return Int64.toStr(cast this);
605 }
606
607 #end
22 import hl.NativeArray;
33 import hl.Bytes;
44 import haxe.CallStack.StackItem;
5
6 typedef Symbol = #if (hl_ver >= version("1.12.0")) hl.Abstract<"hl_symbol"> #else hl.Bytes #end
57
68 /**
79 Do not use manually.
1214 @:ifFeature('haxe.NativeStackTrace.exceptionStack')
1315 static public inline function saveStack(exception:Any):Void {
1416 }
17
18 #if (hl_ver >= version("1.12.0") )
19
20 static public function exceptionStack():NativeArray<Symbol> {
21 var count = exceptionStackRaw(null);
22 var arr = new NativeArray(count);
23 exceptionStackRaw(arr);
24 return arr;
25 }
26
27 static public inline function callStack():NativeArray<Symbol> {
28 var count = callStackRaw(null);
29 var arr = new NativeArray(count);
30 callStackRaw(arr);
31 return arr;
32 }
33
34 @:hlNative("std", "exception_stack_raw")
35 static function exceptionStackRaw( arr : NativeArray<Symbol> ) : Int {
36 return 0;
37 }
38
39 @:hlNative("std", "call_stack_raw")
40 static function callStackRaw( arr : NativeArray<Symbol> ) : Int {
41 return 0;
42 }
43
44 @:hlNative("std","resolve_symbol")
45 static function resolveSymbol( sym : Symbol, buf : hl.Bytes, bufLen : hl.Ref<Int> ) : hl.Bytes {
46 return null;
47 }
48
49 #else
1550
1651 @:hlNative("std", "exception_stack")
1752 static public function exceptionStack():NativeArray<Bytes> {
3671 return skip < stack.length ? stack.sub(skip, stack.length - skip) : stack;
3772 }
3873
39 static public function toHaxe(native:NativeArray<Bytes>, skip:Int = 0):Array<StackItem> {
74 #end
75
76 static public function toHaxe(native:NativeArray<Symbol>, skip:Int=0 ):Array<StackItem> {
4077 var stack = [];
4178 var r = ~/^([A-Za-z0-9.$_]+)\.([~A-Za-z0-9_]+(\.[0-9]+)?)\((.+):([0-9]+)\)$/;
4279 var r_fun = ~/^fun\$([0-9]+)\((.+):([0-9]+)\)$/;
43 for (i in 0...native.length - 1) {
44 if(skip > i) {
45 continue;
46 }
47 var str = @:privateAccess String.fromUCS2(native[i]);
80 #if (hl_ver >= version("1.12.0"))
81 var maxLen = 1024;
82 var tmpBuf = @:privateAccess hl.Bytes.alloc(maxLen);
83 #end
84 for (i in 0...native.length-1) {
85 if( i < skip ) continue;
86 #if (hl_ver >= version("1.12.0"))
87 var len = maxLen;
88 var bytes = resolveSymbol(native[i],tmpBuf,len);
89 if( bytes == null ) continue;
90 #else
91 var bytes = native[i];
92 #end
93 var str = @:privateAccess String.fromUCS2(bytes);
4894 if (r.match(str))
4995 stack.push(FilePos(Method(r.matched(1), r.matched(2)), r.matched(4), Std.parseInt(r.matched(5))));
5096 else if (r_fun.match(str))
0 package haxe.atomic;
1
2 #if (hl_ver < version("1.13.0") && !doc_gen)
3 #error "Atomic operations require HL 1.13+"
4 #end
5 import hl.Atomics;
6
7 abstract AtomicInt(hl.NativeArray<Int>) {
8 public inline function new(value:Int):Void {
9 this = new hl.NativeArray(1);
10 this[0] = value;
11 }
12
13 public inline function add(b:Int):Int {
14 return Atomics.add32(this.getRef(), b);
15 }
16
17 public inline function sub(b:Int):Int {
18 return Atomics.sub32(this.getRef(), b);
19 }
20
21 public inline function and(b:Int):Int {
22 return Atomics.and32(this.getRef(), b);
23 }
24
25 public inline function or(b:Int):Int {
26 return Atomics.or32(this.getRef(), b);
27 }
28
29 public inline function xor(b:Int):Int {
30 return Atomics.xor32(this.getRef(), b);
31 }
32
33 public inline function compareExchange(expected:Int, replacement:Int):Int {
34 return Atomics.compareExchange32(this.getRef(), expected, replacement);
35 }
36
37 public inline function exchange(value:Int):Int {
38 return Atomics.exchange32(this.getRef(), value);
39 }
40
41 public inline function load():Int {
42 return Atomics.load32(this.getRef());
43 }
44
45 public inline function store(value:Int):Int {
46 return Atomics.store32(this.getRef(), value);
47 }
48 }
0 package haxe.atomic;
1
2 #if (hl_ver < version("1.13.0") && !doc_gen)
3 #error "Atomic operations require HL 1.13+"
4 #end
5 import hl.Atomics;
6
7 // use hl.NativeArray<Dynamic> instead of hl.NativeArray<T>
8 // so that the compiler doesn't get confused and emit hl.Ref.make(this.getRef())
9 abstract AtomicObject<T:{}>(hl.NativeArray<Dynamic>) {
10 public inline function new(value:T):Void {
11 this = new hl.NativeArray(1);
12 this[0] = value;
13 }
14
15 public inline function compareExchange(expected:T, replacement:T):T {
16 return Atomics.compareExchangePtr(this.getRef(), expected, replacement);
17 }
18
19 public inline function exchange(value:T):T {
20 return Atomics.exchangePtr(this.getRef(), value);
21 }
22
23 public inline function load():T {
24 return Atomics.loadPtr(this.getRef());
25 }
26
27 public inline function store(value:T):T {
28 return Atomics.storePtr(this.getRef(), value);
29 }
30 }
6868 var s = new StringBuf();
6969 var keys = h.keysArray();
7070 var values = h.valuesArray();
71 s.addChar('{'.code);
71 s.addChar("[".code);
7272 for (i in 0...keys.length) {
7373 if (i > 0)
7474 s.add(", ");
7676 s.add(" => ");
7777 s.add(values[i]);
7878 }
79 s.addChar('}'.code);
79 s.addChar("]".code);
8080 return s.toString();
8181 }
8282
6868 var s = new StringBuf();
6969 var keys = h.keysArray();
7070 var values = h.valuesArray();
71 s.addChar('{'.code);
71 s.addChar("[".code);
7272 for (i in 0...keys.length) {
7373 if (i > 0)
7474 s.add(", ");
7676 s.add(" => ");
7777 s.add(values[i]);
7878 }
79 s.addChar('}'.code);
79 s.addChar("]".code);
8080 return s.toString();
8181 }
8282
9595 var s = new StringBuf();
9696 var keys = h.keysArray();
9797 var values = h.valuesArray();
98 s.addChar('{'.code);
98 s.addChar("[".code);
9999 for (i in 0...keys.length) {
100100 if (i > 0)
101101 s.add(", ");
104104 s.add(" => ");
105105 s.add(values[i]);
106106 }
107 s.addChar('}'.code);
107 s.addChar("]".code);
108108 return s.toString();
109109 }
110110
2525
2626 @:coreApi
2727 abstract Vector<T>(VectorData<T>) {
28 public inline function new(length:Int) {
28 extern overload public inline function new(length:Int) {
2929 this = [];
3030 if (length > 0)
31 this[length - 1] = cast null;
31 this[length - 1] = @:nullSafety(Off) cast null;
32 }
33
34 extern overload public inline function new(length:Int, defaultValue:T):Vector<T> {
35 this = [
36 for (i in 0...length) defaultValue
37 ];
3238 }
3339
3440 @:op([]) public inline function get(index:Int):T {
4450 inline function get_length():Int {
4551 return this.length;
4652 }
53
54 public inline function fill(value:T):Void
55 for (i in 0...length) this[i] = value;
4756
4857 public static inline function blit<T>(src:Vector<T>, srcPos:Int, dest:Vector<T>, destPos:Int, len:Int):Void {
4958 (cast dest : hl.types.ArrayBase.ArrayAccess).blit(destPos, (cast src : hl.types.ArrayBase.ArrayAccess), srcPos, len);
4444
4545 public static function doubleToI64(v:Float):Int64 {
4646 helper.setF64(0, v);
47 #if (hl_ver >= version("1.12.0") && !hl_legacy32)
48 return Int64.make(helper.getI32(4),helper.getI32(0));
49 #else
4750 var i64 = i64tmp;
4851 @:privateAccess {
4952 i64.set_low(helper.getI32(0));
5053 i64.set_high(helper.getI32(4));
5154 }
5255 return i64;
56 #end
5357 }
5458 }
0 package sys.thread;
1
2 #if doc_gen
3 @:coreApi extern class Condition {
4 function new():Void;
5
6 public function acquire():Void;
7
8 public function tryAcquire():Bool;
9
10 public function release():Void;
11
12 public function wait():Void;
13
14 public function signal():Void;
15
16 public function broadcast():Void;
17 }
18 #else
19 abstract Condition(hl.Abstract<"hl_condition">) {
20 public function new():Void {
21 this = alloc();
22 }
23
24 @:hlNative("std", "condition_acquire")
25 public function acquire():Void {}
26
27 @:hlNative("std", "condition_try_acquire")
28 public function tryAcquire():Bool {
29 return false;
30 }
31
32 @:hlNative("std", "condition_release")
33 public function release():Void {}
34
35 @:hlNative("std", "condition_wait")
36 public function wait():Void {}
37
38 @:hlNative("std", "condition_signal")
39 public function signal():Void {}
40
41 @:hlNative("std", "condition_broadcast")
42 public function broadcast():Void {}
43
44 @:hlNative("std", "condition_alloc")
45 static function alloc():hl.Abstract<"hl_condition"> {
46 return null;
47 }
48 }
49 #end
0 package sys.thread;
1
2 #if doc_gen
3 @:coreApi extern class Semaphore {
4 function new(value:Int):Void;
5 function acquire():Void;
6 function tryAcquire(?timeout:Float):Bool;
7 function release():Void;
8 }
9 #else
10 abstract Semaphore(hl.Abstract<"hl_semaphore">) {
11 public function new(value:Int):Void {
12 this = alloc(value);
13 }
14
15 @:hlNative("std", "semaphore_acquire")
16 public function acquire():Void {}
17
18 @:hlNative("std", "semaphore_release")
19 public function release():Void {}
20
21 @:hlNative("std", "semaphore_try_acquire")
22 public function tryAcquire(?timeout:Float):Bool {
23 return false;
24 }
25
26 @:hlNative("std", "semaphore_alloc")
27 static function alloc(value:Int):hl.Abstract<"hl_semaphore"> {
28 return null;
29 }
30 }
31 #end
5050 return HaxeThread.current();
5151 }
5252
53
54 public function setName( name : String ) {
55 #if (hl_ver >= version("1.13.0"))
56 set_name(@:privateAccess this.handle, @:privateAccess name.toUtf8());
57 #end
58 }
59
60 public function getName() : Null<String> {
61 #if (hl_ver >= version("1.13.0"))
62 var name = get_name(@:privateAccess this.handle);
63 return name == null ? null : @:privateAccess String.fromUTF8(name);
64 #else
65 return null;
66 #end
67 }
68
69 #if (hl_ver >= version("1.13.0"))
70 @:hlNative("?std", "thread_set_name") static function set_name( t : ThreadHandle, name : hl.Bytes ) {}
71 @:hlNative("?std", "thread_get_name") static function get_name( t : ThreadHandle ) : hl.Bytes { return null; }
72 #end
73
5374 function get_events():EventLoop {
5475 if(this.events == null)
5576 throw new NoEventLoopException();
6586 private typedef ThreadHandle = hl.Abstract<"hl_thread">;
6687
6788 private class HaxeThread {
68 static var mainThreadHandle:ThreadHandle;
89
6990 static var mainThread:HaxeThread;
70 static var threads:Array<{thread:HaxeThread, handle:ThreadHandle}>;
91 static var threads:Array<HaxeThread>;
7192 static var threadsMutex:Mutex;
93 static var UID = 0;
7294
7395 static function __init__() {
74 mainThreadHandle = currentHandle();
7596 threadsMutex = new Mutex();
7697 threads = [];
77 mainThread = new HaxeThread();
98 mainThread = new HaxeThread(currentHandle());
7899 mainThread.events = new EventLoop();
79100 }
80101
102 var id = UID++;
81103 public var events(default,null):Null<EventLoop>;
104 var handle : ThreadHandle;
82105 final messages = new Deque();
83
84 static var ids = 0;
85 var id = ids++;
86106
87107 @:hlNative("std", "thread_create")
88108 static function createHandle(callb:Void->Void):ThreadHandle {
96116
97117 static public function current():HaxeThread {
98118 var handle = currentHandle();
99 if(handle == mainThreadHandle) {
119 if(handle == mainThread.handle) {
100120 return mainThread;
101121 }
102122 threadsMutex.acquire();
103123 var thread = null;
104124 for(item in threads) {
105125 if(item.handle == handle) {
106 thread = item.thread;
126 thread = item;
107127 break;
108128 }
109129 }
110130 if(thread == null) {
111 thread = new HaxeThread();
112 threads.push({thread:thread, handle:handle});
131 thread = new HaxeThread(handle);
132 threads.push(thread);
113133 }
114134 threadsMutex.release();
115135 return thread;
116136 }
117137
118138 public static function create(callb:()->Void, withEventLoop:Bool):Thread {
119 var item = {handle:null, thread:new HaxeThread()};
139 var item = new HaxeThread(null);
120140 threadsMutex.acquire();
121141 threads.push(item);
122142 threadsMutex.release();
123143 if(withEventLoop)
124 item.thread.events = new EventLoop();
144 item.events = new EventLoop();
125145 item.handle = createHandle(() -> {
126146 if(item.handle == null) {
127147 item.handle = currentHandle();
128148 }
129149 try {
150 hl.Api.setErrorHandler(function(_){});
130151 callb();
131152 if(withEventLoop)
132 item.thread.events.loop();
153 item.events.loop();
133154 } catch(e) {
155 hl.Api.setErrorHandler(null);
134156 dropThread(item);
135 throw e;
157 hl.Api.rethrow(e);
136158 }
137159 dropThread(item);
138160 });
139 return item.thread;
161 return item;
140162 }
141163
142164 public static function runWithEventLoop(job:()->Void):Void {
171193 return messages.pop(block);
172194 }
173195
174 public function new() {}
196 public function new(h) {
197 handle = h;
198 }
175199
176200 public function sendMessage(msg:Dynamic) {
177201 messages.add(msg);
0 1.10.0
0 1.12.0
4444 }
4545
4646 @:keep
47 @:generic
48 class BytesKeyValueIterator<T> extends ArrayKeyValueIterator<T> {
49 var a : ArrayBytes<T>;
50
51 public function new(a) {
52 super((null:Dynamic));
53 this.a = a;
54 }
55
56 override public function hasNext():Bool {
57 return current < a.length;
58 }
59
60 override public function next():{key:Int, value:T} {
61 var v = @:privateAccess a.bytes.get(current);
62 return {key:current++, value:v};
63 }
64 }
65
66 @:keep
6747 @:generic class ArrayBytes<T> extends ArrayBase {
6848 var bytes:hl.BytesAccess<T>;
6949 var size:Int;
9777 if (length == 0)
9878 return null;
9979 length--;
100 return bytes[length];
80 var v = bytes[length];
81 bytes[length] = cast 0;
82 return v;
10183 }
10284
10385 public function push(x:T):Int {
125107 var v = bytes[0];
126108 length--;
127109 (bytes : Bytes).blit(0, bytes, 1 << bytes.sizeBits, length << bytes.sizeBits);
110 bytes[length] = cast 0;
128111 return v;
129112 }
130113
190173 ret.size = ret.length = len;
191174 var end = pos + len;
192175 (bytes : Bytes).blit(pos << bytes.sizeBits, bytes, end << bytes.sizeBits, (length - end) << bytes.sizeBits);
176 (bytes : Bytes).fill((length - len) << bytes.sizeBits, (len) << bytes.sizeBits, 0);
193177 length -= len;
194178 return ret;
195179 }
284268 }
285269
286270 public function keyValueIterator() : ArrayKeyValueIterator<T> {
287 return new BytesKeyValueIterator<T>(this);
271 return new ArrayKeyValueIterator<T>(cast this);
288272 }
289273
290274 public function map<S>(f:T->S):ArrayDyn@:privateAccess {
4242 }
4343 }
4444
45 class ArrayDynKeyValueIterator extends ArrayKeyValueIterator<Dynamic> {
46 var a : ArrayBase;
47
48 public function new(a) {
49 super((null:Dynamic));
50 this.a = a;
51 }
52
53 override public function hasNext() {
54 return current < a.length;
55 }
56
57 override public function next() {
58 var v = a.getDyn(current);
59 return {key:current++, value:v};
60 }
61 }
62
6345 @:keep
6446 class ArrayDyn extends ArrayAccess {
6547 public var length(get, never):Int;
194176 }
195177
196178 public function keyValueIterator() : ArrayKeyValueIterator<Dynamic> {
197 return new ArrayDynKeyValueIterator(array);
179 return new ArrayKeyValueIterator(cast array);
198180 }
199181
200182 public function map(f:Dynamic->Dynamic):ArrayDyn {
4141 }
4242 }
4343
44 class ArrayObjKeyValueIterator<T> extends ArrayKeyValueIterator<T> {
45 var arr:ArrayObj<T>;
46
47 public inline function new(arr:ArrayObj<T>) {
48 super((null:Dynamic));
49 this.arr = arr;
50 }
51
52 override public function hasNext():Bool {
53 return current < arr.length;
54 }
55
56 override public function next():{key:Int, value:T} {
57 var v = @:privateAccess arr.array[current];
58 return {key:current++, value:v};
59 }
60 }
61
6244 @:keep
6345 class ArrayObj<T> extends ArrayBase {
6446 var array:hl.NativeArray<Dynamic>;
290272 }
291273
292274 public function keyValueIterator():ArrayKeyValueIterator<T> {
293 return new ArrayObjKeyValueIterator<T>(this);
275 return new ArrayKeyValueIterator<T>(cast this);
294276 }
295277
296278 public function map<S>(f:T->S):ArrayDyn {
316298 if (length < len) {
317299 __expand(len - 1);
318300 } else if (length > len) {
319 for (i in length...len) {
301 for (i in len...length) {
320302 array[i] = null;
321303 }
322304 this.length = len;
0 /*
1 * Copyright (C)2005-2019 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package hl.types;
23
24 #if (hl_ver >= version("1.13.0") && !hl_legacy32)
25
26 typedef Int64MapData = Abstract<"hl_int64_map">;
27
28 abstract Int64Map(Int64MapData) {
29 extern public inline function new() {
30 this = alloc();
31 }
32
33 @:hlNative("std", "hi64alloc") static function alloc():Int64MapData {
34 return null;
35 }
36
37 @:hlNative("std", "hi64set")
38 public function set(key:haxe.Int64, value:Dynamic) {}
39
40 @:hlNative("std", "hi64exists")
41 public function exists(key:haxe.Int64):Bool {
42 return false;
43 }
44
45 @:hlNative("std", "hi64get")
46 public function get(key:haxe.Int64):Dynamic {
47 return null;
48 }
49
50 @:hlNative("std", "hi64remove")
51 public function remove(key:haxe.Int64):Bool {
52 return false;
53 }
54
55 @:hlNative("std", "hi64keys")
56 public function keysArray():NativeArray<haxe.Int64> {
57 return null;
58 }
59
60 @:hlNative("std", "hi64values")
61 public function valuesArray():NativeArray<Dynamic> {
62 return null;
63 }
64
65 @:hlNative("std", "hi64clear")
66 public function clear():Void {}
67
68 extern public inline function iterator() {
69 return new NativeArray.NativeArrayIterator<Dynamic>(valuesArray());
70 }
71 }
72
73 #end
0 /*
1 * Copyright (C)2005-2019 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package hl.uv;
23
24 enum abstract Event(Int) {
25 var Rename = 1;
26 var Change = 2;
27 }
28
29 @:hlNative("uv")
30 class Fs extends Handle {
31 public function new(?loop : Loop, path : String, onContentChanged : Event -> Void) {
32 if(loop == null)
33 loop = Loop.getDefault();
34 super(fs_start_wrap(loop, (e) -> onContentChanged(cast(e, Event)), @:privateAccess path.toUtf8()));
35 }
36
37 public function stop() {
38 if(handle == null)
39 return;
40 fs_stop_wrap(handle);
41 }
42
43 static function fs_start_wrap(loop:Loop, cb : Int -> Void, path : hl.Bytes) : HandleData {
44 return null;
45 }
46
47 static function fs_stop_wrap(handle:HandleData) : Bool {
48 return false;
49 }
50 }
2121
2222 import java.Boot;
2323 import java.Lib;
24
25 using StringTools;
2426
2527 @:coreApi @:nativeGen class Std {
2628 @:deprecated('Std.is is deprecated. Use Std.isOfType instead.')
6264 return cast x;
6365 }
6466
67 static inline function isSpaceChar(code:Int):Bool
68 return (code > 8 && code < 14) || code == 32;
69
70 static inline function isHexPrefix(cur:Int, next:Int):Bool
71 return cur == '0'.code && (next == 'x'.code || next == 'X'.code);
72
73 static inline function isDecimalDigit(code:Int):Bool
74 return '0'.code <= code && code <= '9'.code;
75
76 static inline function isHexadecimalDigit(code:Int):Bool
77 return isDecimalDigit(code) || ('a'.code <= code && code <= 'f'.code) || ('A'.code <= code && code <= 'F'.code);
78
6579 public static function parseInt(x:String):Null<Int> {
6680 if (x == null)
6781 return null;
6882
69 var base = 10;
70 var len = x.length;
71 var foundCount = 0;
72 var sign = 0;
73 var firstDigitIndex = 0;
74 var lastDigitIndex = -1;
75 var previous = 0;
83 final len = x.length;
84 var index = 0;
7685
77 for(i in 0...len) {
78 var c = StringTools.fastCodeAt(x, i);
79 switch c {
80 case _ if((c > 8 && c < 14) || c == 32):
81 if(foundCount > 0) {
82 return null;
83 }
84 continue;
85 case '-'.code if(foundCount == 0):
86 sign = -1;
87 case '+'.code if(foundCount == 0):
88 sign = 1;
89 case '0'.code if(foundCount == 0 || (foundCount == 1 && sign != 0)):
90 case 'x'.code | 'X'.code if(previous == '0'.code && ((foundCount == 1 && sign == 0) || (foundCount == 2 && sign != 0))):
91 base = 16;
92 case _ if('0'.code <= c && c <= '9'.code):
93 case _ if(base == 16 && (('a'.code <= c && c <= 'z'.code) || ('A'.code <= c && c <= 'Z'.code))):
94 case _:
95 break;
86 inline function hasIndex(index:Int)
87 return index < len;
88
89 // skip whitespace
90 while (hasIndex(index)) {
91 if (!isSpaceChar(x.unsafeCodeAt(index)))
92 break;
93 ++index;
94 }
95
96 // handle sign
97 final isNegative = hasIndex(index) && {
98 final sign = x.unsafeCodeAt(index);
99 if (sign == '-'.code || sign == '+'.code) {
100 ++index;
96101 }
97 if((foundCount == 0 && sign == 0) || (foundCount == 1 && sign != 0)) {
98 firstDigitIndex = i;
102 sign == '-'.code;
103 }
104
105 // handle base
106 final isHexadecimal = hasIndex(index + 1) && isHexPrefix(x.unsafeCodeAt(index), x.unsafeCodeAt(index + 1));
107 if (isHexadecimal)
108 index += 2; // skip prefix
109
110 // handle digits
111 final firstInvalidIndex = {
112 var cur = index;
113 if (isHexadecimal) {
114 while (hasIndex(cur)) {
115 if (!isHexadecimalDigit(x.unsafeCodeAt(cur)))
116 break;
117 ++cur;
118 }
119 } else {
120 while (hasIndex(cur)) {
121 if (!isDecimalDigit(x.unsafeCodeAt(cur)))
122 break;
123 ++cur;
124 }
99125 }
100 foundCount++;
101 lastDigitIndex = i;
102 previous = c;
126 cur;
103127 }
104 if(firstDigitIndex <= lastDigitIndex) {
105 var digits = x.substring(firstDigitIndex + (base == 16 ? 2 : 0), lastDigitIndex + 1);
106 return try {
107 (sign == -1 ? -1 : 1) * java.lang.Integer.parseInt(digits, base);
108 } catch(e:java.lang.NumberFormatException) {
109 null;
110 }
111 }
112 return null;
128
129 // no valid digits
130 if (index == firstInvalidIndex)
131 return null;
132
133 final result = java.lang.Integer.parseInt(x.substring(index, firstInvalidIndex), if (isHexadecimal) 16 else 10);
134 return if (isNegative) -result else result;
113135 }
114136
115137 public static function parseFloat(x:String):Float {
2020 */
2121
2222 import java.lang.System;
23 import java.net.URI;
24 import java.nio.file.Paths;
2325 import sys.io.Process;
2426
2527 using haxe.Int64;
4749 return java.lang.System.getenv(s);
4850 }
4951
50 public static function putEnv(s:String, v:String):Void {
52 public static function putEnv(s:String, v:Null<String>):Void {
5153 // java offers no support for it (!)
5254 throw new haxe.exceptions.NotImplementedException("Not implemented in this platform");
5355 }
5456
5557 public static function environment():Map<String, String> {
56 if (_env != null)
57 return _env;
58 var _env = _env = new haxe.ds.StringMap();
59 for (mv in java.lang.System.getenv().entrySet()) {
60 _env.set(mv.getKey(), mv.getValue());
58 if (_env == null) {
59 _env = new haxe.ds.StringMap();
60 for (mv in java.lang.System.getenv().entrySet())
61 _env.set(mv.getKey(), mv.getValue());
6162 }
6263
63 return _env;
64 return _env.copy();
6465 }
6566
6667 public static function sleep(seconds:Float):Void {
140141 }
141142
142143 public static function programPath():String {
143 return java.Lib.toNativeType(Sys).getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
144 final uri:URI = java.Lib.toNativeType(Sys).getProtectionDomain().getCodeSource().getLocation().toURI();
145 return Std.string(Paths.get(uri));
144146 }
145147
146148 public static function getChar(echo:Bool):Int {
178178 }
179179
180180 // cache empty constructor arguments so we don't allocate it on each createEmptyInstance call
181 @:protected @:readOnly static var __createEmptyInstance_EMPTY_TYPES = java.NativeArray.make(java.Lib.toNativeEnum(java.internal.Runtime.EmptyObject));
182 @:protected @:readOnly static var __createEmptyInstance_EMPTY_ARGS = java.NativeArray.make(java.internal.Runtime.EmptyObject.EMPTY);
181 @:protected @:readOnly static var __createEmptyInstance_EMPTY_TYPES = java.Lib.toNativeEnum(java.internal.Runtime.EmptyObject);
182 @:protected @:readOnly static var __createEmptyInstance_EMPTY_ARGS = java.internal.Runtime.EmptyObject.EMPTY;
183183
184184 public static function createEmptyInstance<T>(cl:Class<T>):T {
185185 var t = java.Lib.toNativeType(cl);
22 import haxe.iterators.RestIterator;
33 import haxe.iterators.RestKeyValueIterator;
44 import java.NativeArray;
5 import java.StdTypes;
6 import java.lang.Object;
57 import java.lang.System;
6 import java.lang.Object;
78 import java.util.Arrays;
89
9 private typedef NativeRest<T> = NativeArray<Object>;
10 private typedef NativeRest<T> = NativeArray<T>;
1011
1112 @:coreApi
1213 abstract Rest<T>(NativeRest<T>) {
13 public var length(get,never):Int;
14 public var length(get, never):Int;
15
1416 inline function get_length():Int
1517 return this.length;
1618
17 @:from static public function of<T>(array:Array<T>):Rest<T> {
18 var native = @:privateAccess array.__a;
19 var result:NativeRest<T>;
20 #if jvm
21 result = (cast native:Object).clone();
22 #else
23 result = new NativeRest<T>(native.length);
24 for(i in 0...native.length)
25 result[i] = cast native[i];
26 #end
19 @:from extern inline static public function of<T>(array:Array<T>):Rest<T> {
20 var result = createNative(array.length);
21 var src:NativeArray<Object> = cast @:privateAccess array.__a;
22 for (i in 0...result.length)
23 result[i] = cast src[i];
2724 return new Rest(result);
25 }
26
27 @:noDoc
28 @:generic
29 static function ofNativePrimitive<TBoxed, TRest>(result:NativeRest<TBoxed>, collection:NativeArray<TRest>):Rest<TRest> {
30 for (i in 0...collection.length)
31 result[i] = cast collection[i];
32 return new Rest(cast result);
33 }
34
35 @:noDoc
36 @:from static function ofNativeInt(collection:NativeArray<Int>):Rest<Int>
37 return ofNativePrimitive(new NativeRest<java.lang.Integer>(collection.length), collection);
38
39 @:noDoc
40 @:from static function ofNativeFloat(collection:NativeArray<Float>):Rest<Float>
41 return ofNativePrimitive(new NativeRest<java.lang.Double>(collection.length), collection);
42
43 @:noDoc
44 @:from static function ofNativeBool(collection:NativeArray<Bool>):Rest<Bool>
45 return ofNativePrimitive(new NativeRest<java.lang.Boolean>(collection.length), collection);
46
47 @:noDoc
48 @:from static function ofNativeInt8(collection:NativeArray<Int8>):Rest<Int8>
49 return ofNativePrimitive(new NativeRest<java.lang.Byte>(collection.length), collection);
50
51 @:noDoc
52 @:from static function ofNativeInt16(collection:NativeArray<Int16>):Rest<Int16>
53 return ofNativePrimitive(new NativeRest<java.lang.Short>(collection.length), collection);
54
55 @:noDoc
56 @:from static function ofNativeChar16(collection:NativeArray<Char16>):Rest<Char16>
57 return ofNativePrimitive(new NativeRest<java.lang.Character>(collection.length), collection);
58
59 @:noDoc
60 @:from static function ofNativeHaxeInt64(collection:NativeArray<haxe.Int64>):Rest<haxe.Int64>
61 return ofNativePrimitive(new NativeRest<java.lang.Long>(collection.length), collection);
62
63 @:noDoc
64 @:from static function ofNativeInt64(collection:NativeArray<Int64>):Rest<Int64>
65 return ofNativePrimitive(new NativeRest<java.lang.Long>(collection.length), collection);
66
67 @:noDoc
68 @:from static function ofNative<T>(collection:NativeArray<T>):Rest<T> {
69 return new Rest(collection);
2870 }
2971
3072 inline function new(a:NativeRest<T>):Void
3173 this = a;
3274
75 /**
76 * Implemented in genjvm (to auto-box primitive types) and genjava
77 */
78 static function createNative<T>(length:Int):NativeRest<T>
79 return new NativeRest<T>(length);
80
3381 @:arrayAccess inline function get(index:Int):T
34 return cast this[index];
82 return this[index];
3583
3684 @:to public function toArray():Array<T> {
37 return [for(i in 0...this.length) cast this[i]];
85 return [for (i in 0...this.length) this[i]];
3886 }
3987
4088 public inline function iterator():RestIterator<T>
4391 public inline function keyValueIterator():RestKeyValueIterator<T>
4492 return new RestKeyValueIterator<T>(this);
4593
46 public function append(item:T):Rest<T> {
47 var result = new NativeRest<T>(this.length + 1);
94 extern inline public function append(item:T):Rest<T> {
95 return _append(createNative(this.length + 1), item);
96 }
97
98 function _append(result:NativeRest<T>, item:T):Rest<T> {
4899 System.arraycopy(this, 0, result, 0, this.length);
49100 result[this.length] = cast item;
50101 return new Rest(result);
51102 }
52103
53 public function prepend(item:T):Rest<T> {
54 var result = new NativeRest<T>(this.length + 1);
104 extern inline public function prepend(item:T):Rest<T> {
105 return _prepend(createNative(this.length + 1), item);
106 }
107
108 function _prepend(result:NativeRest<T>, item:T):Rest<T> {
55109 System.arraycopy(this, 0, result, 1, this.length);
56110 result[0] = cast item;
57111 return new Rest(result);
60114 public function toString():String {
61115 return toArray().toString();
62116 }
63 }
117 }
0 package haxe.atomic;
1
2 import java.util.concurrent.atomic.AtomicBoolean;
3
4 abstract AtomicBool(AtomicBoolean) {
5 public inline function new(value:Bool) {
6 this = new AtomicBoolean(value);
7 }
8
9 public inline function compareExchange(expected:Bool, replacement:Bool):Bool {
10 // Java's compareAndSet returns a boolean, so do a CAS loop to be able to return the original value without a potential race condition
11
12 var original;
13 var real_replacement;
14 do {
15 original = this.get();
16 real_replacement = original == expected ? replacement : original;
17 } while (!this.compareAndSet(original, real_replacement));
18 return original;
19 }
20
21 public inline function exchange(value:Bool):Bool {
22 return this.getAndSet(value);
23 }
24
25 public inline function load():Bool {
26 return this.get();
27 }
28
29 public inline function store(value:Bool):Bool {
30 this.set(value);
31 return value;
32 }
33 }
0 package haxe.atomic;
1
2 import java.util.concurrent.atomic.AtomicInteger;
3
4 abstract AtomicInt(AtomicInteger) {
5 public inline function new(value:Int) {
6 this = new AtomicInteger(value);
7 }
8
9 private inline function cas_loop(value:Int, op:(a:Int, b:Int) -> Int):Int {
10 var val;
11
12 do {
13 val = this.get();
14 } while (!this.compareAndSet(val, op(val, value)));
15
16 return val;
17 }
18
19 public inline function add(b:Int):Int {
20 return this.getAndAdd(b);
21 }
22
23 public inline function sub(b:Int):Int {
24 return this.getAndAdd(-b);
25 }
26
27 public inline function and(b:Int):Int {
28 return cas_loop(b, (a:Int, b:Int) -> a & b);
29 }
30
31 public inline function or(b:Int):Int {
32 return cas_loop(b, (a:Int, b:Int) -> a | b);
33 }
34
35 public inline function xor(b:Int):Int {
36 return cas_loop(b, (a:Int, b:Int) -> a ^ b);
37 }
38
39 public inline function compareExchange(expected:Int, replacement:Int):Int {
40 // Java's compareAndSet returns a boolean, so do a CAS loop to be able to return the original value without a potential race condition
41
42 var original;
43 var real_replacement;
44 do {
45 original = this.get();
46 real_replacement = original == expected ? replacement : original;
47 } while (!this.compareAndSet(original, real_replacement));
48 return original;
49 }
50
51 public inline function exchange(value:Int):Int {
52 return this.getAndSet(value);
53 }
54
55 public inline function load():Int {
56 return this.get();
57 }
58
59 public inline function store(value:Int):Int {
60 this.set(value);
61 return value;
62 }
63 }
0 package haxe.atomic;
1
2 import java.util.concurrent.atomic.AtomicReference;
3
4 abstract AtomicObject<T:{}>(AtomicReference<T>) {
5 public inline function new(value:T) {
6 this = new AtomicReference(value);
7 }
8
9 public inline function compareExchange(expected:T, replacement:T):T {
10 // Java's compareAndSet returns a boolean, so do a CAS loop to be able to return the original value without a potential race condition
11
12 var original;
13 var real_replacement;
14 do {
15 original = this.get();
16 real_replacement = original == expected ? replacement : original;
17 } while (!this.compareAndSet(original, real_replacement));
18 return original;
19 }
20
21 public inline function exchange(value:T):T {
22 return this.getAndSet(value);
23 }
24
25 public inline function load():T {
26 return this.get();
27 }
28
29 public inline function store(value:T):T {
30 this.set(value);
31 return value;
32 }
33 }
363363
364364 public function toString():String {
365365 var s = new StringBuf();
366 s.add("{");
366 s.add("[");
367367 var it = keys();
368368 for (i in it) {
369369 s.add(i);
372372 if (it.hasNext())
373373 s.add(", ");
374374 }
375 s.add("}");
375 s.add("]");
376376 return s.toString();
377377 }
378378
377377
378378 public function toString():String {
379379 var s = new StringBuf();
380 s.add("{");
380 s.add("[");
381381 var it = keys();
382382 for (i in it) {
383383 s.add(Std.string(i));
386386 if (it.hasNext())
387387 s.add(", ");
388388 }
389 s.add("}");
389 s.add("]");
390390 return s.toString();
391391 }
392392
376376
377377 public function toString():String {
378378 var s = new StringBuf();
379 s.add("{");
379 s.add("[");
380380 var it = keys();
381381 for (i in it) {
382382 s.add(i);
385385 if (it.hasNext())
386386 s.add(", ");
387387 }
388 s.add("}");
388 s.add("]");
389389 return s.toString();
390390 }
391391
403403
404404 public function toString():String {
405405 var s = new StringBuf();
406 s.add("{");
406 s.add("[");
407407 var it = keys();
408408 for (i in it) {
409409 s.add(Std.string(i));
412412 if (it.hasNext())
413413 s.add(", ");
414414 }
415 s.add("}");
415 s.add("]");
416416 return s.toString();
417417 }
418418
4040 var f = new File(path);
4141 if (!f.exists())
4242 throw "Path " + path + " doesn't exist";
43 return {
44 gid: 0, // java doesn't let you get this info
45 uid: 0, // same
46 atime: Date.now(), // same
47 mtime: Date.fromTime(cast(f.lastModified(), Float)),
48 ctime: Date.fromTime(cast(f.lastModified(), Float)), // same
49 size: cast(f.length(), Int), // TODO: maybe change to Int64 for Haxe 3?
50 dev: 0, // FIXME: not sure what that is
51 ino: 0, // FIXME: not sure what that is
52 nlink: 0, // FIXME: not sure what that is
53 rdev: 0, // FIXME: not sure what that is
54 mode: 0 // FIXME: not sure what that is
55 };
43
44 try {
45 final pathObject = java.nio.file.Paths.get(path);
46 final attributes = java.nio.file.Files.readAttributes(pathObject, "unix:*");
47
48 return {
49 atime: Date.fromTime(cast(attributes.get("lastAccessTime").toMillis(), Float)),
50 ctime: Date.fromTime(cast(attributes.get("creationTime").toMillis(), Float)),
51 dev: cast(attributes.get("dev"), Int),
52 gid: attributes.get("gid"),
53 ino: cast(attributes.get("ino"), Int),
54 mode: attributes.get("mode"),
55 mtime: Date.fromTime(cast(attributes.get("lastModifiedTime").toMillis(), Float)),
56 nlink: attributes.get("nlink"),
57 rdev: cast(attributes.get("rdev"), Int),
58 size: cast(attributes.get("size"), Int),
59 uid: attributes.get("uid"),
60 };
61 }
62
63 catch (e) {
64 return {
65 gid: 0, // java doesn't let you get this info
66 uid: 0, // same
67 atime: Date.now(), // same
68 mtime: Date.fromTime(cast(f.lastModified(), Float)),
69 ctime: Date.fromTime(cast(f.lastModified(), Float)), // same
70 size: cast(f.length(), Int), // TODO: maybe change to Int64 for Haxe 3?
71 dev: 0, // FIXME: not sure what that is
72 ino: 0, // FIXME: not sure what that is
73 nlink: 0, // FIXME: not sure what that is
74 rdev: 0, // FIXME: not sure what that is
75 mode: 0 // FIXME: not sure what that is
76 };
77 }
5678 }
5779
5880 public static function fullPath(relPath:String):String {
7474 }
7575 }
7676
77 return new java.lang.ProcessBuilder(pargs);
77 return new java.lang.ProcessBuilder(...pargs);
7878 }
7979
8080 public function new(cmd:String, ?args:Array<String>, ?detached:Bool):Void {
0 package sys.thread;
1
2 import java.util.concurrent.locks.ReentrantLock;
3 import java.util.concurrent.locks.Condition as NativeCondition;
4
5 @:access(sys.thread.Mutex)
6 @:coreApi
7 @:native('haxe.java.vm.Condition')
8 class Condition {
9 final lock:ReentrantLock;
10 final native:NativeCondition;
11
12 public function new():Void {
13 this.lock = new ReentrantLock();
14 this.native = lock.newCondition();
15 }
16
17 public function acquire():Void {
18 lock.lock();
19 }
20
21 public function tryAcquire():Bool {
22 return this.lock.tryLock();
23 }
24
25 public function release():Void {
26 lock.unlock();
27 }
28
29 // without the @:native, you get "java.lang.VerifyError: class sys.thread.Condition overrides final method java.lang.Object.wait()V" on jvm
30 // and "wait() in Condition cannot override wait() in Object" from javac
31
32 @:native("waitOn")
33 public function wait():Void {
34 native.await();
35 }
36
37 public function signal():Void {
38 native.signal();
39 }
40
41 public function broadcast():Void {
42 native.signalAll();
43 }
44 }
0 package sys.thread;
1
2 import java.util.concurrent.TimeUnit;
3
4 @:coreApi
5 @:native('haxe.java.vm.Semaphore')
6 class Semaphore {
7 final native:java.util.concurrent.Semaphore;
8
9 public function new(value:Int):Void {
10 this.native = new java.util.concurrent.Semaphore(value);
11 }
12
13 public function acquire():Void {
14 native.acquire();
15 }
16
17 public function tryAcquire(?timeout:Float):Bool {
18 return timeout == null ? native.tryAcquire() : native.tryAcquire(haxe.Int64.fromFloat(timeout * 1000000000),TimeUnit.NANOSECONDS);
19 }
20
21 public function release():Void {
22 native.release();
23 }
24 }
192192 if (ts != null)
193193 return ts();
194194 var ret = new StringBuf();
195 ret.add("{");
195 ret.add("[");
196196 var first = true;
197197 for (f in Reflect.fields(this)) {
198198 if (first)
206206 }
207207 if (!first)
208208 ret.add(" ");
209 ret.add("}");
209 ret.add("]");
210210 return ret.toString();
211211 }
212212 }
2828 Create or update a cookie.
2929 @param expireDelay In seconds. If null, the cookie expires at end of session.
3030 **/
31 public static function set(name:String, value:String, ?expireDelay:Int, ?path:String, ?domain:String) {
31 public static function set(name:String, value:String, ?expireDelay:Int, ?path:String, ?domain:String, ?secure:Bool, ?sameSite:String) {
3232 var s = name + "=" + StringTools.urlEncode(value);
3333 if (expireDelay != null) {
3434 var d = DateTools.delta(Date.now(), expireDelay * 1000);
3939 }
4040 if (domain != null) {
4141 s += ";domain=" + domain;
42 }
43 if (secure == true) {
44 s += ";secure";
45 }
46 if (sameSite != null) {
47 s += ";SameSite=" + sameSite;
4248 }
4349 Browser.document.cookie = s;
4450 }
3131 **/
3232 public static inline function debug() {
3333 js.Syntax.code("debugger");
34 }
35
36 /**
37 Inserts an `import` expression that loads JavaScript object from
38 a module or file specified in the `module` argument.
39 **/
40 public static inline function dynamicImport(module:String):js.lib.Promise<Dynamic> {
41 return js.Syntax.code("import({0})", module);
3442 }
3543
3644 /**
123131 }
124132
125133 /**
126 Re-throw last cathed exception, preserving original stack information.
134 Re-throw last caught exception, preserving original stack information.
127135
128136 Calling this is only possible inside a catch statement.
129137 **/
7878 return (a == b) ? 0 : (((cast a) > (cast b)) ? 1 : -1);
7979 }
8080
81 public static function compareMethods(f1:Dynamic, f2:Dynamic):Bool {
82 if (f1 == f2)
83 return true;
84 if (!isFunction(f1) || !isFunction(f2))
85 return false;
86 return f1.scope == f2.scope && f1.method == f2.method && f1.method != null;
81 public static inline function compareMethods(f1:Dynamic, f2:Dynamic):Bool {
82 return f1 == f2;
8783 }
8884
8985 @:access(js.Boot)
5353
5454 @:pure
5555 public static function parseInt(x:String):Null<Int> {
56 if(x != null) {
57 for(i in 0...x.length) {
58 var c = StringTools.fastCodeAt(x, i);
59 if(c <= 8 || (c >= 14 && c != ' '.code && c != '-'.code)) {
60 var nc = StringTools.fastCodeAt(x, i + 1);
61 var v = js.Lib.parseInt(x, (nc == "x".code || nc == "X".code) ? 16 : 10);
62 return Math.isNaN(v) ? null : cast v;
63 }
56 #if (js_es >= 5)
57 final v = js.Lib.parseInt(x);
58 #else
59 // before ES5, octal was supported in some implementations, so we need to explicitly use base 10 or 16
60 if (x == null)
61 return null;
62 var v:Float = Math.NaN;
63 for (i => c in StringTools.keyValueIterator(x)) {
64 if ((c <= 8 || c >= 14) && !(c == ' '.code || c == '-'.code || c == '+'.code)) {
65 final nc = js.Syntax.code("{0}[{1}]", x, i + 1);
66 v = js.Lib.parseInt(x, c == '0'.code && (nc == "x" || nc == "X") ? 16 : 10);
67 break;
6468 }
6569 }
66 return null;
70 #end
71 if (Math.isNaN(v))
72 return null;
73 return cast v;
6774 }
6875
6976 public static inline function parseFloat(x:String):Float {
7683
7784 static function __init__():Void
7885 untyped {
79 __feature__("js.Boot.getClass", String.prototype.__class__ = __feature__("Type.resolveClass", $hxClasses["String"] = String, String));
86 __feature__("js.Boot.getClass", Object.defineProperty(String.prototype, "__class__", {value: __feature__("Type.resolveClass", $hxClasses["String"] = String, String), enumerable: false, writable: true}));
8087 __feature__("js.Boot.isClass", String.__name__ = __feature__("Type.getClassName", "String", true));
8188 __feature__("Type.resolveClass", $hxClasses["Array"] = Array);
8289 __feature__("js.Boot.isClass", Array.__name__ = __feature__("Type.getClassName", "Array", true));
6161 for (i in 0...stack.length) {
6262 if(skip > i) continue;
6363 var line = stack[i];
64 var matched:Null<Array<String>> = Syntax.code('{0}.match(/^ at ([A-Za-z0-9_. ]+) \\(([^)]+):([0-9]+):([0-9]+)\\)$/)', line);
64 var matched:Null<Array<String>> = Syntax.code("{0}.match(/^ at ([$A-Za-z0-9_. ]+) \\(([^)]+):([0-9]+):([0-9]+)\\)$/)", line);
6565 if (matched != null) {
6666 var path = matched[1].split(".");
6767 if(path[0] == "$hxClasses") {
0 package haxe.atomic;
1
2 import js.lib.Atomics;
3
4 abstract AtomicInt(js.lib.Int32Array) {
5 public inline function new(value:Int) {
6 this = new js.lib.Int32Array(new js.lib.SharedArrayBuffer(js.lib.Int32Array.BYTES_PER_ELEMENT));
7 this[0] = value;
8 }
9
10 private function asArray():js.lib.Int32Array {
11 return this;
12 }
13
14 public inline function add(b:Int):Int {
15 return Atomics.add(asArray(), 0, b);
16 }
17
18 public inline function sub(b:Int):Int {
19 return Atomics.sub(asArray(), 0, b);
20 }
21
22 public inline function and(b:Int):Int {
23 return Atomics.and(asArray(), 0, b);
24 }
25
26 public inline function or(b:Int):Int {
27 return Atomics.or(asArray(), 0, b);
28 }
29
30 public inline function xor(b:Int):Int {
31 return Atomics.xor(asArray(), 0, b);
32 }
33
34 public inline function compareExchange(expected:Int, replacement:Int):Int {
35 return Atomics.compareExchange(asArray(), 0, expected, replacement);
36 }
37
38 public inline function exchange(value:Int):Int {
39 return Atomics.exchange(asArray(), 0, value);
40 }
41
42 public inline function load():Int {
43 return Atomics.load(asArray(), 0);
44 }
45
46 public inline function store(value:Int):Int {
47 return Atomics.store(asArray(), 0, value);
48 }
49 }
8080
8181 public function toString():String {
8282 var s = new StringBuf();
83 s.add("{");
83 s.add("[");
8484 var it = keys();
8585 for (i in it) {
8686 s.add(i);
8989 if (it.hasNext())
9090 s.add(", ");
9191 }
92 s.add("}");
92 s.add("]");
9393 return s.toString();
9494 }
9595
2626
2727 @:coreApi
2828 class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
29 static var count:Int;
30
31 // initialize count through __init__ magic, because these are generated
32 // before normal static initializations for which ObjectMap should be ready to use
33 // see https://github.com/HaxeFoundation/haxe/issues/6792
34 static inline function __init__():Void
35 count = 0;
3629
3730 static inline function assignId(obj:{}):Int {
3831 return Syntax.code('({0}.__id__ = {1})', obj, Lib.getNextHaxeUID());
112105
113106 public function toString():String {
114107 var s = new StringBuf();
115 s.add("{");
108 s.add("[");
116109 var it = keys();
117110 for (i in it) {
118111 s.add(Std.string(i));
121114 if (it.hasNext())
122115 s.add(", ");
123116 }
124 s.add("}");
117 s.add("]");
125118 return s.toString();
126119 }
127120
8686
8787 @:analyzer(no_optimize)
8888 static function stringify(h:Dynamic):String {
89 var s = "{", first = true;
89 var s = "[", first = true;
9090 js.Syntax.code("for (var key in {0}) {", h);
9191 js.Syntax.code("\tif ({0}) {0} = false; else {1} += ',';", first, s);
9292 js.Syntax.code("\t{0} += key + ' => ' + {1}({2}[key]);", s, Std.string, h);
9393 js.Syntax.code("}");
94 return s + "}";
94 return s + "]";
9595 }
9696 }
9797
285285
286286 public function toString():String {
287287 var s = new StringBuf();
288 s.add("{");
288 s.add("[");
289289 var keys = arrayKeys();
290290 for (i in 0...keys.length) {
291291 var k = keys[i];
295295 if (i < keys.length - 1)
296296 s.add(", ");
297297 }
298 s.add("}");
298 s.add("]");
299299 return s.toString();
300300 }
301301
0 package js.html;
1
2 import js.lib.Promise;
3
4 /**
5 The `BeforeInstallPromptEvent` is fired at the `Window.onbeforeinstallprompt` handler,
6 before a user is prompted to install a web site to a home screen.
7
8 @see https://developer.mozilla.org/en-US/docs/Web/API/BeforeInstallPromptEvent
9 **/
10 @:native("BeforeInstallPromptEvent")
11 extern class BeforeInstallPromptEvent extends Event {
12
13 /** The platforms on which this event was dispatched. **/
14 final platforms: Array<String>;
15
16 /** The user's choice to the install prompt. **/
17 final userChoice: Promise<BeforeInstallPromptUserChoice>;
18
19 /** Creates a new `BeforeInstallPromptEvent`. **/
20 function new();
21
22 /** Shows the install prompt. **/
23 function prompt(): Promise<Dynamic>;
24 }
25
26 typedef BeforeInstallPromptUserChoice = {
27 final outcome: BeforeInstallPromptUserChoiceOutcome;
28 }
29
30 enum abstract BeforeInstallPromptUserChoiceOutcome(String) {
31 var Accepted = "accepted";
32 var Dismissed = "dismissed";
33 }
503503 Asynchronously asks the browser to make the element full-screen.
504504 @throws DOMError
505505 **/
506 function requestFullscreen() : Void;
507
506 function requestFullscreen(?options: FullscreenOptions) : js.lib.Promise<Void>;
507
508508 /**
509509 Allows to asynchronously ask for the pointer to be locked on the given element.
510510 **/
0 /*
1 * Copyright (C)2005-2022 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package js.html;
23
24 /**
25 The `HTMLDialogElement` interface provides methods to manipulate `<dialog>` elements.
26 It inherits properties and methods from the `HTMLElement` interface.
27
28 @see <https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement>
29 **/
30 @:native("HTMLDialogElement")
31 extern class DialogElement extends Element {
32
33 /**
34 A `Boolean` reflecting the open HTML attribute, indicating whether the dialog is available for interaction.
35 **/
36 var open: Bool;
37
38 /**
39 A `DOMString` that sets or returns the return value for the dialog.
40 **/
41 var returnValue: String;
42
43 /**
44 Closes the dialog.
45 An optional `DOMString` may be passed as an argument, updating the `returnValue` of the the dialog.
46 **/
47 function close(?returnValue: String): Void;
48
49 /**
50 Displays the dialog modelessly, i.e. still allowing interaction with content outside of the dialog.
51 **/
52 function show(): Void;
53
54 /**
55 Displays the dialog as a modal, over the top of any other dialogs that might be present.
56 Interaction outside the dialog is blocked.
57 **/
58 function showModal(): Void;
59 }
509509 Releases the current mouse capture if it's on an element in this document.
510510 **/
511511 function releaseCapture() : Void;
512 function exitFullscreen() : Void;
513
512
513 /**
514 Requests that the element on this document which is currently being presented in fullscreen mode
515 be taken out of fullscreen mode, restoring the previous state of the screen.
516 **/
517 function exitFullscreen() : js.lib.Promise<Void>;
518
514519 /**
515520 Release the pointer lock.
516521 **/
0 /*
1 * Copyright (C)2005-2022 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package js.html;
23
24 /**
25 An object that controls the behavior of the transition to fullscreen mode.
26 **/
27 typedef FullscreenOptions = {
28
29 /**
30 Controls whether or not to show navigation UI while the element is in fullscreen mode.
31 **/
32 var ?navigationUI: FullscreenOptionsNavigationUI;
33 }
34
35 enum abstract FullscreenOptionsNavigationUI(String) {
36 var Auto = "auto";
37 var Hide = "hide";
38 var Show = "show";
39 }
191191 inline function createTableRowElement() : TableRowElement { return cast createElement("tr"); }
192192 /** Shorthand for creating an HTML `<html>` element. */
193193 inline function createHtmlElement() : HtmlElement { return cast createElement("html"); }
194
195 }
194 /** Shorthand for creating an HTML `<dialog>` element. */
195 inline function createDialoglElement() : DialogElement { return cast createElement("dialog"); }
196 }
1818 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1919 * DEALINGS IN THE SOFTWARE.
2020 */
21
22 // This file is generated from mozilla\Window.webidl. Do not edit!
2321
2422 package js.html;
2523
559557 function dump( str : String ) : Void;
560558
561559 /**
560 Creates a deep clone of a given value using the structured clone algorithm.
561 **/
562 function structuredClone<T>(value: T, ?options: {transfer: Array<Any>}): T;
563
564 /**
562565 Toggles a user's ability to resize a window.
563566 **/
564567 function setResizable( resizable : Bool ) : Void;
1818 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1919 * DEALINGS IN THE SOFTWARE.
2020 */
21
22 // This file is generated from mozilla\WorkerGlobalScope.webidl. Do not edit!
2321
2422 package js.html;
2523
8280 Allows you to write a message to stdout — i.e. in your terminal. This is the same as Firefox's `window.dump`, but for workers.
8381 **/
8482 function dump( ?str : String ) : Void;
83
84 /**
85 Creates a deep clone of a given value using the structured clone algorithm.
86 **/
87 function structuredClone<T>(value: T, ?options: {transfer: Array<Any>}): T;
88
8589 /** @throws DOMError */
8690 function btoa( btoa : String ) : String;
8791 /** @throws DOMError */
0 package js.lib;
1
2 private typedef E<A, B> = haxe.extern.EitherType<A, B>;
3 private typedef IntTypedArray = E<Int8Array, E<Uint8Array, E<Int16Array, E<Uint16Array, E<Int32Array, Uint32Array>>>>>;
4
5 /**
6 The Atomics object provides atomic operations as static methods. They are used with SharedArrayBuffer and ArrayBuffer objects.
7
8 Documentation [Atomics](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/contributors.txt), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
9 **/
10 @:native("Atomics")
11 extern class Atomics {
12 /**
13 Adds the provided value to the existing value at the specified index of the array.
14 Returns the old value at that index.
15 This atomic operation guarantees that no other write happens until the modified value is written back.
16 **/
17 static function add(typedArray:IntTypedArray, index:Int, value:Int):Int;
18
19 /**
20 Computes a bitwise AND on the value at the specified index of the array with the provided value.
21 Returns the old value at that index.
22 This atomic operation guarantees that no other write happens until the modified value is written back.
23 **/
24 static function and(typedArray:IntTypedArray, index:Int, value:Int):Int;
25
26 /**
27 Stores a value at the specified index of the array, if it equals a value.
28 Returns the old value.
29 This atomic operation guarantees that no other write happens until the modified value is written back.
30 **/
31 static function compareExchange(typedArray:IntTypedArray, index:Int, expectedValue:Int, replacementValue:Int):Int;
32
33 /**
34 Stores a value at the specified index of the array.
35 Returns the old value.
36 This atomic operation guarantees that no other write happens until the modified value is written back.
37 **/
38 static function exchange(typedArray:IntTypedArray, index:Int, value:Int):Int;
39
40 /**
41 An optimization primitive that can be used to determine whether to use locks or atomic operations.
42 Returns `true` if an atomic operation on arrays of the given element size will be implemented using a hardware atomic operation (as opposed to a lock). Experts only.
43 **/
44 static function isLockFree(size:Int):Bool;
45
46 /**
47 Returns the value at the specified index of the array.
48 This atomic operation guarantees that no other write happens until the modified value is written back.
49 **/
50 static function load(typedArray:IntTypedArray, index:Int):Int;
51
52 /**
53 Notifies agents that are waiting on the specified index of the array.
54 Returns the number of agents that were notified.
55 **/
56 static function notify(typedArray:IntTypedArray, index:Int, ?count:Int):Int;
57
58 /**
59 Computes a bitwise OR on the value at the specified index of the array with the provided value.
60 Returns the old value at that index.
61 This atomic operation guarantees that no other write happens until the modified value is written back.
62 **/
63 static function or(typedArray:IntTypedArray, index:Int, value:Int):Int;
64
65 /**
66 Stores a value at the specified index of the array.
67 Returns the value.
68 This atomic operation guarantees that no other write happens until the modified value is written back.
69 **/
70 static function store(typedArray:IntTypedArray, index:Int, value:Int):Int;
71
72 /**
73 Subtracts a value at the specified index of the array.
74 Returns the old value at that index.
75 This atomic operation guarantees that no other write happens until the modified value is written back.
76 **/
77 static function sub(typedArray:IntTypedArray, index:Int, value:Int):Int;
78
79 /**
80 Verifies that the specified index of the array still contains a value and sleeps awaiting or times out.
81 Returns either "ok", "not-equal", or "timed-out". If waiting is not allowed in the calling agent then it throws an Error exception.
82 Most browsers will not allow wait() on the browser's main thread.)
83 **/
84 static function wait(typedArray:Int32Array, index:Int, value:Int, ?timeout:Int):WaitValue;
85
86 /**
87 Computes a bitwise XOR on the value at the specified index of the array with the provided value.
88 Returns the old value at that index.
89 This atomic operation guarantees that no other write happens until the modified value is written back.
90 **/
91 static function xor(typedArray:IntTypedArray, index:Int, value:Int):Int;
92 }
93
94 enum abstract WaitValue(String) {
95 var OK = "ok";
96 var NotEqual = "not-equal";
97 var TimedOut = "timed-out";
98 }
3333
3434 @see <https://developer.mozilla.org/en-US/docs/Web/API/BufferSource>
3535 */
36 @:forward
37 abstract BufferSource(ArrayBuffer) to ArrayBuffer from ArrayBuffer {
38 @:from public static inline function fromBufferView(view:ArrayBufferView) {
39 return cast view.buffer;
36 abstract BufferSource(Dynamic) from ArrayBuffer from ArrayBufferView {
37
38 public var byteLength(get, never): Int;
39
40 @:pure
41 inline function get_byteLength(): Int {
42 return this.byteLength;
4043 }
44
4145 }
5858 the first promise in the iterable that rejected. This method can be
5959 useful for aggregating results of multiple promises.
6060 **/
61 static function all(iterable:Array<Dynamic>):Promise<Array<Dynamic>>;
61 @:overload(function(iterable:Array<Dynamic>):Promise<Array<Dynamic>> {})
62 static function all<T>(iterable:Array<Promise<T>>):Promise<Array<T>>;
6263
6364 /**
6465 Returns a promise that resolves after all of the given promises have either fulfilled or rejected,
7071 In comparison, the Promise returned by `Promise.all` may be more appropriate if the tasks are dependent
7172 on each other / if you'd like to immediately reject upon any of them rejecting.
7273 **/
73 static function allSettled(iterable:Array<Dynamic>):Promise<Array<PromiseSettleOutcome>>;
74 @:overload(function(iterable:Array<Dynamic>):Promise<Array<PromiseSettleOutcome<Dynamic>>> {})
75 static function allSettled<T>(iterable:Array<Promise<T>>):Promise<Array<PromiseSettleOutcome<T>>>;
7476
7577 /**
7678 Returns a promise that fulfills or rejects as soon as one of the
7779 promises in the iterable fulfills or rejects, with the value or reason
7880 from that promise.
7981 **/
80 static function race(iterable:Array<Dynamic>):Promise<Dynamic>;
82 @:overload(function(iterable:Array<Dynamic>):Promise<Dynamic> {})
83 static function race<T>(iterable:Array<Promise<T>>):Promise<T>;
8184
8285 /** @throws DOMError */
8386 function new(init:(resolve:(value:T) -> Void, reject:(reason:Dynamic) -> Void) -> Void):Void;
128131 function then<TOut>(onFulfilled:Null<PromiseHandler<T, TOut>>, ?onRejected:PromiseHandler<Dynamic, TOut>):Thenable<TOut>;
129132 }
130133
131 typedef PromiseSettleOutcome = {
134 typedef PromiseSettleOutcome<T> = {
132135 var status:PromiseSettleStatus;
133 var ?value:Dynamic;
136 var ?value:T;
134137 var ?reason:Dynamic;
135138 }
136139
0 package js.lib;
1
2 /**
3 The SharedArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer, similar to the ArrayBuffer object, but in a way that they can be used to create views on shared memory.
4 A SharedArrayBuffer is not a Transferable Object, unlike an ArrayBuffer which is transferable.
5
6 Documentation [SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer/contributors.txt), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
7 **/
8 @:native("SharedArrayBuffer")
9 extern class SharedArrayBuffer {
10 final byteLength:Int;
11
12 function new(?length:Int):Void;
13
14 function slice(?begin:Int, ?end:Int):ArrayBuffer;
15 }
0 package js.lib;
1 /*
2 * Copyright (C)2005-2019 Haxe Foundation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23 /**
24 The `WeakRef` object lets you hold a weak reference to another object, without preventing that object from getting garbage-collected.
25 Documentation [WeakRef](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
26 **/
27 @:native("WeakRef")
28 extern class WeakRef<T:{}> {
29 /**
30 Creates a new WeakRef object.
31 **/
32 @:pure function new(target:T);
33 /**
34 Returns the WeakRef object's target object, or null if the target object has been reclaimed.
35 **/
36 @:pure function deref():Null<T>;
37 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package js.lib.intl;
23
24 /**
25 The `Intl.DisplayNames` object enables the consistent translation of language,
26 region and script display names.
27 **/
28 @:native("Intl.DisplayNames")
29 extern class DisplayNames {
30
31 /**
32 Creates a new `Intl.DisplayNames` object.
33 **/
34 @:overload(function(?locales: Array<String>, ?options: DisplayNamesOptions): Void {})
35 function new(?locales: String, ?options: DisplayNamesOptions);
36
37 /**
38 Receives a code and returns a string based on the locale and options
39 provided when instantiating `Intl.DisplayNames`.
40 **/
41 function of(code: String): String;
42
43 /**
44 Returns a new object with properties reflecting the locale and formatting options
45 computed during initialization of the object.
46 **/
47 function resolvedOptions(): DisplayNamesResolvedOptions;
48
49 /**
50 Returns an array containing those of the provided locales that are supported
51 in display names without having to fall back to the runtime's default locale.
52 **/
53 @:overload(function(locales: Array<String>, ?options: DisplayNamesSupportedLocalesOfOptions): Array<String> {})
54 static function supportedLocalesOf(locales: String, ?options: DisplayNamesSupportedLocalesOfOptions): Array<String>;
55 }
56
57 enum abstract DisplayNamesFallback(String) {
58 var Code = "code";
59 var None = "none";
60 }
61
62 typedef DisplayNamesOptions = {
63 /**
64 The fallback to use.
65 The default is `Code`.
66 **/
67 var fallback: DisplayNamesFallback;
68
69 /**
70 The locale matching algorithm to use.
71 The default is `BestFit`.
72 **/
73 var ?localeMatcher: LocaleMatcher;
74
75 /**
76 The formatting style to use.
77 The default is `Long`.
78 **/
79 var ?style: DisplayNamesStyle;
80
81 /**
82 The type to use.
83 The default is `Language`.
84 **/
85 var ?type: DisplayNamesType;
86 }
87
88 typedef DisplayNamesResolvedOptions = {
89 /**
90 The value provided for this property in the `options` argument of the constructor
91 or the default value (`Code`).
92 **/
93 final fallback: DisplayNamesFallback;
94
95 /**
96 The BCP 47 language tag for the locale actually used.
97 **/
98 final locale: String;
99
100 /**
101 The value provided for this property in the `options` argument of the constructor
102 or the default value (`Long`).
103 **/
104 final style: DisplayNamesStyle;
105
106 /**
107 The value provided for this property in the `options` argument of the constructor
108 or the default value (`Language`).
109 **/
110 final type: DisplayNamesType;
111 }
112
113 enum abstract DisplayNamesStyle(String) {
114 var Long = "long";
115 var Narrow = "narrow";
116 var Short = "short";
117 }
118
119 typedef DisplayNamesSupportedLocalesOfOptions = {
120 /**
121 The locale matching algorithm to use.
122 The default is `BestFit`.
123 */
124 var ?localeMatcher: LocaleMatcher;
125 }
126
127 enum abstract DisplayNamesType(String) {
128 var Currency = "currency";
129 var Language = "language";
130 var Region = "region";
131 var Script = "script";
132 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package js.lib.intl;
23
24 /**
25 The `Intl.ListFormat` object enables language-sensitive list formatting.
26 **/
27 @:native("Intl.ListFormat")
28 extern class ListFormat {
29
30 /**
31 Creates a new `Intl.ListFormat` object.
32 **/
33 @:overload(function(?locales: Array<String>, ?options: ListFormatOptions): Void {})
34 function new(?locales: String, ?options: ListFormatOptions);
35
36 /**
37 Returns a language-specific formatted string representing the elements of the list.
38 **/
39 function format(?list: Array<String>): String;
40
41 /**
42 Returns an array of objects representing the different components
43 that can be used to format a list of values in a locale-aware fashion.
44 **/
45 function formatToParts(?list: Array<String>): Array<ListFormatPart>;
46
47 /**
48 Returns an array containing those of the provided locales that are supported
49 without having to fall back to the runtime's default locale.
50 **/
51 @:overload(function(locales: Array<String>, ?options: ListFormatSupportedLocalesOfOptions): Array<String> {})
52 static function supportedLocalesOf(locales: String, ?options: ListFormatSupportedLocalesOfOptions): Array<String>;
53 }
54
55 typedef ListFormatOptions = {
56 /**
57 The locale matching algorithm to use.
58 The default is `BestFit`.
59 **/
60 var ?localeMatcher: LocaleMatcher;
61
62 /**
63 The length of the formatted message.
64 The default is `Long`.
65 **/
66 var ?style: ListFormatStyle;
67
68 /**
69 The format of output message.
70 **/
71 var ?type: ListFormatType;
72 }
73
74 typedef ListFormatPart = {
75 final type: ListFormatPartType;
76 final value: String;
77 }
78
79 enum abstract ListFormatPartType(String) {
80 /**
81 A value from the list.
82 **/
83 var Element = "element";
84
85 /**
86 A linguistic construct.
87 **/
88 var Literal = "literal";
89 }
90
91 enum abstract ListFormatStyle(String) {
92 var Long = "long";
93 var Narrow = "narrow";
94 var Short = "short";
95 }
96
97 typedef ListFormatSupportedLocalesOfOptions = {
98 /**
99 The locale matching algorithm to use.
100 The default is `BestFit`.
101 */
102 var ?localeMatcher: LocaleMatcher;
103 }
104
105 enum abstract ListFormatType(String) {
106 /**
107 Stands for "and"-based lists.
108 **/
109 var Conjunction = "conjunction";
110
111 /**
112 Stands for "or"-based lists.
113 **/
114 var Disjunction = "disjunction";
115
116 /**
117 Stands for lists of values with units.
118 **/
119 var Unit = "unit";
120 }
4646 args;
4747 };
4848 try {
49 return method.invoke(context, args);
49 return method.invoke(context, ...args);
5050 } catch (e:java.lang.reflect.InvocationTargetException) {
5151 throw e.getCause();
5252 }
290290
291291 static public function readFieldClosure(obj:Dynamic, name:String, parameterTypes:NativeArray<java.lang.Class<Dynamic>>):Dynamic {
292292 var cl = (obj : java.lang.Object).getClass();
293 var method = cl.getMethod(name, parameterTypes);
293 var method = cl.getMethod(name, ...parameterTypes);
294294 if (method.isBridge()) {
295295 /* This is probably not what we want... go through all methods and see if we find one that
296296 isn't a bridge. This is pretty awkward, but I can't figure out how to use the Java reflection
2121
2222 import jvm.Jvm;
2323
24 using StringTools;
25
2426 @:coreApi
2527 class Std {
2628 @:deprecated('Std.is is deprecated. Use Std.isOfType instead.')
6264 return cast x;
6365 }
6466
67 static inline function isSpaceChar(code:Int):Bool
68 return (code > 8 && code < 14) || code == 32;
69
70 static inline function isHexPrefix(cur:Int, next:Int):Bool
71 return cur == '0'.code && (next == 'x'.code || next == 'X'.code);
72
73 static inline function isDecimalDigit(code:Int):Bool
74 return '0'.code <= code && code <= '9'.code;
75
76 static inline function isHexadecimalDigit(code:Int):Bool
77 return isDecimalDigit(code) || ('a'.code <= code && code <= 'f'.code) || ('A'.code <= code && code <= 'F'.code);
78
6579 public static function parseInt(x:String):Null<Int> {
66 if (x == null) {
80 if (x == null)
6781 return null;
68 }
69
70 var base = 10;
71 var len = x.length;
72 var foundCount = 0;
73 var sign = 0;
74 var firstDigitIndex = 0;
75 var lastDigitIndex = -1;
76 var previous = 0;
77
78 for (i in 0...len) {
79 var c = StringTools.fastCodeAt(x, i);
80 switch c {
81 case _ if ((c > 8 && c < 14) || c == 32):
82 if (foundCount > 0) {
83 return null;
84 }
85 continue;
86 case '-'.code if (foundCount == 0):
87 sign = -1;
88 case '+'.code if (foundCount == 0):
89 sign = 1;
90 case '0'.code if (foundCount == 0 || (foundCount == 1 && sign != 0)):
91 case 'x'.code | 'X'.code if (previous == '0'.code && ((foundCount == 1 && sign == 0) || (foundCount == 2 && sign != 0))):
92 base = 16;
93 case _ if ('0'.code <= c && c <= '9'.code):
94 case _ if (base == 16 && (('a'.code <= c && c <= 'z'.code) || ('A'.code <= c && c <= 'Z'.code))):
95 case _:
96 break;
82
83 final len = x.length;
84 var index = 0;
85
86 inline function hasIndex(index:Int)
87 return index < len;
88
89 // skip whitespace
90 while (hasIndex(index)) {
91 if (!isSpaceChar(x.unsafeCodeAt(index)))
92 break;
93 ++index;
94 }
95
96 // handle sign
97 final isNegative = hasIndex(index) && {
98 final sign = x.unsafeCodeAt(index);
99 if (sign == '-'.code || sign == '+'.code) {
100 ++index;
97101 }
98 if ((foundCount == 0 && sign == 0) || (foundCount == 1 && sign != 0)) {
99 firstDigitIndex = i;
102 sign == '-'.code;
103 }
104
105 // handle base
106 final isHexadecimal = hasIndex(index + 1) && isHexPrefix(x.unsafeCodeAt(index), x.unsafeCodeAt(index + 1));
107 if (isHexadecimal)
108 index += 2; // skip prefix
109
110 // handle digits
111 final firstInvalidIndex = {
112 var cur = index;
113 if (isHexadecimal) {
114 while (hasIndex(cur)) {
115 if (!isHexadecimalDigit(x.unsafeCodeAt(cur)))
116 break;
117 ++cur;
118 }
119 } else {
120 while (hasIndex(cur)) {
121 if (!isDecimalDigit(x.unsafeCodeAt(cur)))
122 break;
123 ++cur;
124 }
100125 }
101 foundCount++;
102 lastDigitIndex = i;
103 previous = c;
104 }
105 if (firstDigitIndex <= lastDigitIndex) {
106 var digits = x.substring(firstDigitIndex + (base == 16 ? 2 : 0), lastDigitIndex + 1);
107 return try {
108 (sign == -1 ? -1 : 1) * java.lang.Integer.parseInt(digits, base);
109 } catch (e:java.lang.NumberFormatException) {
110 null;
111 }
112 }
113 return null;
126 cur;
127 }
128
129 // no valid digits
130 if (index == firstInvalidIndex)
131 return null;
132
133 final result = java.lang.Integer.parseInt(x.substring(index, firstInvalidIndex), if (isHexadecimal) 16 else 10);
134 return if (isNegative) -result else result;
114135 }
115136
116137 public static function parseFloat(x:String):Float {
122122 }
123123 }
124124
125 static final emptyArg = {
126 var a = new java.NativeArray(1);
127 a[0] = (null : jvm.EmptyConstructor);
128 a;
129 }
130
131 static final emptyClass = {
132 var a = new java.NativeArray(1);
133 a[0] = jvm.EmptyConstructor.native();
134 a;
135 }
125 static final emptyArg = (null : jvm.EmptyConstructor);
126
127 static final emptyClass = jvm.EmptyConstructor.native();
136128
137129 public static function createInstance<T>(cl:Class<T>, args:Array<Dynamic>):T {
138130 var args = @:privateAccess args.getNative();
149141 switch (Jvm.unifyCallArguments(args, params, true)) {
150142 case Some(args):
151143 ctor.setAccessible(true);
152 return ctor.newInstance(args);
144 return ctor.newInstance(...args);
153145 case None:
154146 }
155147 }
165157 case Some(args):
166158 var obj = emptyCtor.newInstance(emptyArg);
167159 method.setAccessible(true);
168 method.invoke(obj, args);
160 method.invoke(obj, ...args);
169161 return obj;
170162 case None:
171163 }
177169 public static function createEmptyInstance<T>(cl:Class<T>):T {
178170 var annotation = (cl.native().getAnnotation((cast ClassReflectionInformation : java.lang.Class<ClassReflectionInformation>)));
179171 if (annotation != null) {
180 return cl.native().getConstructor(emptyClass).newInstance(emptyArg);
172 return cl.native().getConstructor(emptyClass)
173 .newInstance(emptyArg);
181174 } else {
182175 return cl.native().newInstance();
183176 }
240233 public static function getEnumConstructs(e:Enum<Dynamic>):Array<String> {
241234 var clInfo:java.lang.Class<EnumReflectionInformation> = cast EnumReflectionInformation;
242235 var annotation = e.native().getAnnotation(clInfo);
243 return @:privateAccess Array.ofNative(annotation.constructorNames());
236 if (annotation != null) {
237 return @:privateAccess Array.ofNative(annotation.constructorNames());
238 }
239 var vals = e.values();
240 var ret = [];
241 for (i in 0...vals.length) {
242 ret[i] = vals[i].name();
243 }
244 return ret;
244245 }
245246
246247 public static function typeof(v:Dynamic):ValueType {
302303 var ret = [];
303304 for (name in all) {
304305 var v = Jvm.readField(e, name);
305 if (Jvm.instanceof(v, jvm.Enum)) {
306 if (Jvm.instanceof(v, java.lang.Enum)) {
306307 ret.push(v);
307308 }
308309 }
0 package haxe;
1
2 import haxe.ds.Vector;
3 import haxe.iterators.RestIterator;
4 import haxe.iterators.RestKeyValueIterator;
5
6 private typedef NativeRest<T> = Vector<T>;
7
8 @:coreApi
9 abstract Rest<T>(NativeRest<T>) {
10 public var length(get, never):Int;
11
12 inline function get_length():Int
13 return this.length;
14
15 inline function new(a:NativeRest<T>) {
16 this = a;
17 }
18
19 @:arrayAccess inline function get(index:Int):T
20 return this[index];
21
22 @:from extern inline static public function of<T>(array:Array<T>):Rest<T> {
23 var result = new NativeRest(array.length);
24 for (i in 0...array.length)
25 result[i] = array[i];
26 return new Rest(result);
27 }
28
29 @:from extern inline static function fromNative<T>(a:java.NativeArray<T>):Rest<T> {
30 return new Rest(Vector.fromData(a));
31 }
32
33 extern inline public function append(item:T):Rest<T> {
34 var r = new NativeRest(length + 1);
35 Vector.blit(this, 0, r, 0, length);
36 r[length] = item;
37 return new Rest(r);
38 }
39
40 extern inline public function prepend(item:T):Rest<T> {
41 var r = new NativeRest(length + 1);
42 Vector.blit(this, 0, r, 1, length);
43 r[0] = item;
44 return new Rest(r);
45 }
46
47 public inline function iterator():RestIterator<T>
48 return new RestIterator<T>(this);
49
50 public inline function keyValueIterator():RestKeyValueIterator<T>
51 return new RestKeyValueIterator<T>(this);
52
53 @:to public inline function toArray():Array<T> {
54 return [for (i in 0...this.length) this[i]];
55 }
56
57 public inline function toString():String {
58 return toArray().toString();
59 }
60 }
7171
7272 public function toString():String {
7373 var s = new StringBuf();
74 s.add("{");
74 s.add("[");
7575 var it = keys();
7676 for (i in it) {
7777 s.add(i);
8080 if (it.hasNext())
8181 s.add(", ");
8282 }
83 s.add("}");
83 s.add("]");
8484 return s.toString();
8585 }
8686
2828 extern class FileHandle extends UserData {
2929 function flush():Void;
3030 function read(arg:Rest<EitherType<String, Int>>):String;
31 function lines():NativeIterator<String>;
3132 function close():Void;
3233
3334 function write(str:String):Void;
3232 end
3333
3434 function _hx_field_arr(obj)
35 res = {}
36 idx = 0
35 local res = {}
36 local idx = 0
3737 if obj.__fields__ ~= nil then
3838 obj = obj.__fields__
3939 end
0 -- require this for lua 5.1
1 pcall(require, 'bit')
2 if bit then
0 local hasBit32, bit32 = pcall(require, 'bit32')
1 if hasBit32 then --if we are on Lua 5.1, bit32 will be the default.
2 _hx_bit_raw = bit32
3 _hx_bit = setmetatable({}, { __index = _hx_bit_raw })
4 -- lua 5.2 weirdness
5 _hx_bit.bnot = function(...) return _hx_bit_clamp(_hx_bit_raw.bnot(...)) end
6 _hx_bit.bxor = function(...) return _hx_bit_clamp(_hx_bit_raw.bxor(...)) end
7 else
8 --If we do not have bit32, fallback to 'bit'
9 local hasBit, bit = pcall(require, 'bit')
10 if not hasBit then
11 error("Failed to load bit or bit32")
12 end
313 _hx_bit_raw = bit
4 _hx_bit = setmetatable({}, { __index = _hx_bit_raw });
5 else
6 _hx_bit_raw = _G.require('bit32')
7 _hx_bit = setmetatable({}, { __index = _hx_bit_raw });
8 -- lua 5.2 weirdness
9 _hx_bit.bnot = function(...) return _hx_bit_clamp(_hx_bit_raw.bnot(...)) end;
10 _hx_bit.bxor = function(...) return _hx_bit_clamp(_hx_bit_raw.bxor(...)) end;
14 _hx_bit = setmetatable({}, { __index = _hx_bit_raw })
1115 end
16
1217 -- see https://github.com/HaxeFoundation/haxe/issues/8849
13 _hx_bit.bor = function(...) return _hx_bit_clamp(_hx_bit_raw.bor(...)) end;
14 _hx_bit.band = function(...) return _hx_bit_clamp(_hx_bit_raw.band(...)) end;
15 _hx_bit.arshift = function(...) return _hx_bit_clamp(_hx_bit_raw.arshift(...)) end;
18 _hx_bit.bor = function(...) return _hx_bit_clamp(_hx_bit_raw.bor(...)) end
19 _hx_bit.band = function(...) return _hx_bit_clamp(_hx_bit_raw.band(...)) end
20 _hx_bit.arshift = function(...) return _hx_bit_clamp(_hx_bit_raw.arshift(...)) end
0 function _hx_handle_error(obj)
1 local message = tostring(obj)
2 if _G.debug and _G.debug.traceback then
3 -- level 2 to skip _hx_handle_error
4 message = _G.debug.traceback(message, 2)
5 end
6 return setmetatable({}, { __tostring = function() return message end })
7 end
0 if package.loaded.luv then
1 _hx_luv = _G.require("luv");
2 else
3 _hx_luv = {
4 run=function(mode) return false end,
5 loop_alive=function() return false end
6 }
7 end
9898 return ""
9999 end
100100 end
101
102 function _hx_error(obj)
103 if obj.value then
104 _G.print("runtime error:\n " .. _hx_tostring(obj.value));
105 else
106 _G.print("runtime error:\n " .. tostring(obj));
107 end
108
109 if _G.debug and _G.debug.traceback then
110 _G.print(debug.traceback());
111 end
112 end
113
5151 }
5252 }
5353
54 ropt |= FLAGS.UTF8; // always check validity of utf8 string
54 ropt |= FLAGS.UTF; // always check validity of utf8 string
5555 ropt |= FLAGS.UCP; // always enable utf8 character properties
5656
5757 if (global == null)
207207
208208 static function __init__():Void {
209209 if (Rex == null) {
210 throw "Rex is missing. Please install lrexlib-pcre.";
210 throw "Rex is missing. Please install lrexlib-pcre2.";
211211 }
212212 }
213213 }
2525
2626 @:coreApi class Reflect {
2727 public inline static function hasField(o:Dynamic, field:String):Bool {
28 if (Lua.type(o) == "string" && (untyped String.prototype[field] != null || field == "length")) {
29 return true;
28 return if (inline isFunction(o)) {
29 false;
30 } else if (Lua.type(o) == "string" && (untyped String.prototype[field] != null || field == "length")) {
31 true;
3032 } else
31 return untyped o.__fields__ != null ? o.__fields__[field] != null : o[field] != null;
33 untyped o.__fields__ != null ? o.__fields__[field] != null : o[field] != null;
3234 }
3335
3436 public static function field(o:Dynamic, field:String):Dynamic
115117 untyped {
116118 if (v == null)
117119 return false;
118 var t = __lua__("type(v)");
120 var t = lua.Lua.type(v);
119121 return (t == "string" || (t == "table" && v.__enum__ == null))
120122 || (t == "function" && (lua.Boot.isClass(v) || lua.Boot.isEnum(v)) != null);
121123 }
5757 public static function parseInt(x:String):Null<Int> {
5858 if (x == null)
5959 return null;
60 var hexMatch = NativeStringTools.match(x, "^[ \t\r\n]*([%-+]*0[xX][%da-fA-F]*)");
61 if (hexMatch != null) {
62 var sign = switch StringTools.fastCodeAt(hexMatch, 0) {
63 case '-'.code: -1;
64 case '+'.code: 1;
65 case _: 0;
66 }
67 return (sign == -1 ? -1 : 1) * lua.Lua.tonumber(hexMatch.substr(sign == 0 ? 2 : 3), 16);
68 } else {
69 var intMatch = NativeStringTools.match(x, "^ *[%-+]?%d*");
70 if (intMatch != null) {
71 return lua.Lua.tonumber(intMatch);
72 } else {
73 return null;
74 }
60 untyped {
61 __lua__("local sign, numString = {0}", NativeStringTools.match(x, "^%s*([%-+]?)0[xX]([%da-fA-F]*)"));
62 if (numString != null)
63 return switch sign {
64 case '-': -lua.Lua.tonumber(numString, 16);
65 case _: lua.Lua.tonumber(numString, 16);
66 }
7567 }
68 final intMatch = NativeStringTools.match(x, "^%s*[%-+]?%d*");
69 if (intMatch == null)
70 return null;
71 return lua.Lua.tonumber(intMatch);
7672 }
7773
7874 public static function parseFloat(x:String):Float {
7975 if (x == null || x == "")
8076 return Math.NaN;
81 var digitMatch = NativeStringTools.match(x, "^ *[%.%-+]?[0-9]%d*");
77 var digitMatch = NativeStringTools.match(x, "^%s*[%.%-+]?[0-9]%d*");
8278 if (digitMatch == null) {
8379 return Math.NaN;
8480 }
6161 public inline function toLowerCase():String
6262 return BaseString.lower(this);
6363
64 public inline function indexOf(str:String, ?startIndex:Int):Int {
64 public function indexOf(str:String, ?startIndex:Int):Int {
6565 if (startIndex == null)
6666 startIndex = 1;
6767 else
8585 return startIndex > length ? length : startIndex;
8686 }
8787
88 public inline function lastIndexOf(str:String, ?startIndex:Int):Int {
88 public function lastIndexOf(str:String, ?startIndex:Int):Int {
8989 var ret = -1;
9090 if (startIndex == null)
9191 startIndex = length;
9898 return ret;
9999 }
100100
101 public inline function split(delimiter:String):Array<String> {
102 var idx = 1;
101 public function split(delimiter:String):Array<String> {
102 var idx:Null<Int> = 1;
103103 var ret = [];
104104 while (idx != null) {
105 var newidx = 0;
105 var newidx:Null<Int> = 0;
106106 if (delimiter.length > 0) {
107107 newidx = BaseString.find(this, delimiter, idx, true).begin;
108108 } else if (idx >= this.length) {
127127 return this;
128128 }
129129
130 public inline function substring(startIndex:Int, ?endIndex:Int):String {
130 public function substring(startIndex:Int, ?endIndex:Int):String {
131131 if (endIndex == null)
132132 endIndex = this.length;
133133 if (endIndex < 0)
150150 return BaseString.byte(this, index + 1);
151151 }
152152
153 public inline function substr(pos:Int, ?len:Int):String {
153 public function substr(pos:Int, ?len:Int):String {
154154 if (len == null || len > pos + this.length)
155155 len = this.length;
156156 else if (len < 0)
8888 }
8989
9090 public inline static function getCwd():String
91 return Misc.cwd();
91 return haxe.io.Path.addTrailingSlash(Misc.cwd());
9292
9393 public inline static function setCwd(s:String):Void
9494 Misc.chdir(s);
9797 return Os.getenv(s);
9898 }
9999
100 public inline static function putEnv(s:String, v:String):Void {
100 public inline static function putEnv(s:String, v:Null<String>):Void {
101 if (v == null)
102 return Os.unsetenv(s);
101103 Os.setenv(s, v);
102104 }
103105
4848 return __nativeException;
4949 }
5050
51 @:keep // required for uncaught error handling
5152 public function toString():String {
5253 return message;
5354 }
9595
9696 public function toString():String {
9797 var s = new StringBuf();
98 s.add("{");
98 s.add("[");
9999 var it = keys();
100100 for (i in it) {
101101 s.add(i);
104104 if (it.hasNext())
105105 s.add(", ");
106106 }
107 s.add("}");
107 s.add("]");
108108 return s.toString();
109109 }
110110
9999
100100 public function toString():String {
101101 var s = new StringBuf();
102 s.add("{");
102 s.add("[");
103103 var it = keys();
104104 for (i in it) {
105105 s.add(i);
108108 if (it.hasNext())
109109 s.add(", ");
110110 }
111 s.add("}");
111 s.add("]");
112112 return s.toString();
113113 }
114114
4545 untyped {
4646 var ret = h[key];
4747 if (ret == tnull) {
48 ret = null;
48 return null;
4949 }
5050 return ret;
5151 }
9999
100100 public function toString():String {
101101 var s = new StringBuf();
102 s.add("{");
102 s.add("[");
103103 var it = keys();
104104 for (i in it) {
105105 s.add(i);
108108 if (it.hasNext())
109109 s.add(", ");
110110 }
111 s.add("}");
111 s.add("]");
112112 return s.toString();
113113 }
114114
4141 If `str` is null, the result is unspecified.
4242 **/
4343 static public inline function parse(str:String):Dynamic {
44 #if lua_vanilla
45 return new JsonParser(str).doParse();
46 #else
4447 return lua.lib.hxluasimdjson.Json.parse(str);
48 #end
4549 }
4650
4751 var str:String;
158158 var write_arr = res.write == null ? [] : Table.toArray(res.write).map(convert_socket);
159159 return {read: read_arr, write: write_arr, others: []};
160160 }
161 }
162
163 private class SocketInput extends haxe.io.Input {
164 var tcp:TcpClient;
165
166 public function new(tcp:TcpClient) {
167 this.tcp = tcp;
168 }
169
170 override public function readByte():Int {
171 var res = tcp.receive(1);
172 if (res.message == "closed"){
173 throw new haxe.io.Eof();
174 }
175 else if (res.message != null)
176 throw 'Error : ${res.message}';
177 return res.result.charCodeAt(0);
178 }
179
180 override public function readBytes(s:Bytes, pos:Int, len:Int):Int {
181 var leftToRead = len;
182 var b = s.getData();
183 if (pos < 0 || len < 0 || pos + len > s.length)
184 throw haxe.io.Error.OutsideBounds;
185 var readCount = 0;
186 try {
187 while (leftToRead > 0) {
188 b[pos] = cast readByte();
189 pos++;
190 readCount++;
191 leftToRead--;
192 }
193 } catch (e:haxe.io.Eof) {
194 if (readCount == 0) {
195 throw e;
196 }
197 }
198 return readCount;
199 }
200
201 }
202
203 private class SocketOutput extends haxe.io.Output {
204 var tcp:TcpClient;
205
206 public function new(tcp:TcpClient) {
207 this.tcp = tcp;
208 }
209
210 override public function writeByte(c:Int):Void {
211 var char = NativeStringTools.char(c);
212 var res = tcp.send(char);
213 if (res.message != null){
214 throw 'Error : Socket writeByte : ${res.message}';
215 }
216 }
217
218 override public function writeBytes(s:Bytes, pos:Int, len:Int):Int {
219 if (pos < 0 || len < 0 || pos + len > s.length)
220 throw Error.OutsideBounds;
221 var b = s.getData().slice(pos, pos +len).map(function(byte){
222 return lua.NativeStringTools.char(byte);
223 });
224 var encoded = Table.concat(cast b, 0);
225 var res = tcp.send(encoded);
226 if (res.message != null){
227 throw 'Error : Socket writeByte : ${res.message}';
228 }
229
230 return len;
231 }
232
233 }
161 }
0 /*
1 * Copyright (C)2005-2022 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package sys.net;
23
24 import lua.lib.luasocket.socket.TcpClient;
25 import lua.*;
26
27 import haxe.io.Bytes;
28 import haxe.io.Error;
29
30 class SocketInput extends haxe.io.Input {
31 var tcp:TcpClient;
32
33 public function new(tcp:TcpClient) {
34 this.tcp = tcp;
35 }
36
37 override public function readByte():Int {
38 var res = tcp.receive(1);
39 if (res.message == "closed"){
40 throw new haxe.io.Eof();
41 }
42 else if (res.message != null)
43 throw 'Error : ${res.message}';
44 return res.result.charCodeAt(0);
45 }
46
47 override public function readBytes(s:Bytes, pos:Int, len:Int):Int {
48 var leftToRead = len;
49 var b = s.getData();
50 if (pos < 0 || len < 0 || pos + len > s.length)
51 throw haxe.io.Error.OutsideBounds;
52 var readCount = 0;
53 try {
54 while (leftToRead > 0) {
55 b[pos] = cast readByte();
56 pos++;
57 readCount++;
58 leftToRead--;
59 }
60 } catch (e:haxe.io.Eof) {
61 if (readCount == 0) {
62 throw e;
63 }
64 }
65 return readCount;
66 }
67
68 }
0 /*
1 * Copyright (C)2005-2022 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package sys.net;
23
24 import lua.lib.luasocket.socket.TcpClient;
25 import lua.*;
26
27 import haxe.io.Bytes;
28 import haxe.io.Error;
29
30 class SocketOutput extends haxe.io.Output {
31 var tcp:TcpClient;
32
33 public function new(tcp:TcpClient) {
34 this.tcp = tcp;
35 }
36
37 override public function writeByte(c:Int):Void {
38 var char = NativeStringTools.char(c);
39 var res = tcp.send(char);
40 if (res.message != null){
41 throw 'Error : Socket writeByte : ${res.message}';
42 }
43 }
44
45 override public function writeBytes(s:Bytes, pos:Int, len:Int):Int {
46 if (pos < 0 || len < 0 || pos + len > s.length)
47 throw Error.OutsideBounds;
48 var b = s.getData().slice(pos, pos +len).map(function(byte){
49 return lua.NativeStringTools.char(byte);
50 });
51 var encoded = Table.concat(cast b, 0);
52 var res = tcp.send(encoded);
53 if (res.message != null){
54 throw 'Error : Socket writeByte : ${res.message}';
55 }
56
57 return len;
58 }
59
60 }
0 /*
1 * Copyright (C)2005-2022 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package sys.ssl;
23
24 import sys.net.Host;
25 import sys.net.SocketInput;
26 import sys.net.SocketOutput;
27
28 import lua.lib.luasocket.Socket as LuaSocket;
29 import lua.lib.luasec.Ssl as LuaSecSsl;
30 import lua.lib.luasec.SslTcpClient;
31
32 import haxe.io.Bytes;
33 import haxe.io.Error;
34
35 class Socket extends sys.net.Socket {
36 var _sslSocket:SslTcpClient;
37
38 private function wrap(sock:LuaSocket):SslTcpClient {
39 var res = LuaSecSsl.wrap(sock, {mode: Client, protocol: Any});
40 if (res.message != null) {
41 throw 'Socket Error : ${res.message}';
42 }
43 return res.result;
44 }
45
46 public function handshake():Void {
47 var res = this._sslSocket.dohandshake();
48 if (res.message != null) {
49 throw 'Handshake Error : ${res.message}';
50 }
51 }
52
53 public override function connect(host:Host, port:Int):Void {
54 var res = LuaSocket.connect(host.host, port);
55 if (res.message != null)
56 throw 'Socket Error : ${res.message}';
57 var sslSock = this.wrap(res.result);
58 input = new SocketInput(sslSock);
59 output = new SocketOutput(sslSock);
60 _sslSocket = sslSock;
61 _sslSocket.settimeout(timeout);
62 this.handshake();
63 }
64
65 public override function close():Void {
66 _sslSocket.close();
67 }
68 }
2323
2424 import haxe.extern.EitherType;
2525
26 @:luaRequire("rex_pcre")
26 @:luaRequire("rex_pcre2")
2727 extern class Rex {
2828 inline static function create(expr:String, flag:EitherType<Int, String>):Rex {
2929 return untyped Rex['new'](expr, flag);
0 /*
1 * Copyright (C)2005-2022 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package lua.lib.luasec;
23
24 import lua.lib.luasocket.Socket as LuaSocket;
25
26 @:luaRequire("ssl")
27 extern class Ssl {
28 static function wrap(sock:LuaSocket, params: SslParams):Result<SslTcpClient>;
29 }
30
31 typedef SslParams = {
32 mode: Mode,
33 protocol: Protocol,
34 }
35
36 enum abstract Mode(String) {
37 var Client = "client";
38 var Server = "server";
39 }
40
41 enum abstract Protocol(String) {
42 var Any = "any";
43 }
0 /*
1 * Copyright (C)2005-2022 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package lua.lib.luasec;
23
24 import lua.lib.luasocket.socket.TcpClient;
25
26 extern class SslTcpClient extends TcpClient {
27 function dohandshake():Result<Bool>;
28 }
2626 static function new_check():Check;
2727 @:native("new_check") function new():Void;
2828
29 function start(handle:Handle):Int;
29 function start(cb:()->Void):Int;
3030 function stop():Int;
3131 }
22 @:luaRequire("luv")
33 extern class Loop {
44 static function loop_close():Bool;
5 /**
6 Runs the event loop of libuv.
7
8 Haxe compiler automatically inserts a call to this function at the end of user's code if needed.
9 **/
510 static function run(?mode:String):Bool;
611 static function loop_alive():Bool;
712 static function stop():Void;
2626
2727 @:luaRequire("luv")
2828 extern class FileSystem {
29 static final constants:Table<String,Int>;
30
2931 @:native("fs_close")
3032 @:overload(function(file:FileDescriptor, cb:String->Bool->Void):Request {})
3133 static function close(file:FileDescriptor):Result<Bool>;
3234
3335 @:native("fs_open")
36 @:overload(function(path:String, flags:Int, mode:Int):Result<FileDescriptor> {})
37 @:overload(function(path:String, flags:Int, mode:Int, ?cb:String->FileDescriptor->Void):Request {})
3438 @:overload(function(path:String, flags:Open, mode:Int, ?cb:String->FileDescriptor->Void):Request {})
3539 static function open(path:String, flags:Open, mode:Int):Result<FileDescriptor>;
3640
3943 static function read(file:FileDescriptor, len:Int, offset:Int):Result<String>;
4044
4145 @:native("fs_unlink")
42 @:overload(function(file:FileDescriptor, ?cb:String->String->Void):Request {})
43 static function unlink(file:FileDescriptor, content:String):Result<String>;
46 @:overload(function(file:String, ?cb:String->Bool->Void):Request {})
47 static function unlink(file:String, content:String):Result<Bool>;
4448
4549 @:native("fs_write")
46 @:overload(function(file:FileDescriptor, content:String, offset:Int, ?cb:String->Bool->Void):Int {})
47 static function write(file:FileDescriptor, content:String, offset:Int):Result<Bool>;
50 @:overload(function(file:FileDescriptor, content:String, offset:Int, ?cb:String->Int->Void):Int {})
51 static function write(file:FileDescriptor, content:String, offset:Int):Result<Int>;
4852
4953 @:native("fs_mkdir")
5054 @:overload(function(path:String, mode:Int, cb:String->Bool->Void):Request {})
5155 static function mkdir(path:String, mode:Int):Result<Bool>;
5256
5357 @:native("fs_mkdtemp")
54 @:overload(function(data:String, cb:String->Bool->Void):Request {})
55 static function mkdtemp(data:String):Result<Bool>;
58 @:overload(function(template:String, cb:String->String->Void):Request {})
59 static function mkdtemp(template:String):Result<String>;
60
61 @:native("fs_mkstemp")
62 @:overload(function(template:String, cb:String->FileDescriptor->String->Void):Request {})
63 static function mkstemp(template:String):Result<FileDescriptor>;
5664
5765 @:native("fs_rmdir")
5866 @:overload(function(path:String, cb:String->Bool->Void):Request {})
145153 Not available on windows
146154 **/
147155 @:native("fs_lchown")
148 @:overload(function(descriptor:FileDescriptor, uid:Int, gid:Int, cb:String->Bool->Void):Request {})
149 static function lchown(descriptor:FileDescriptor, uid:Int, gid:Int):Bool;
156 @:overload(function(descriptor:String, uid:Int, gid:Int, cb:String->Bool->Void):Request {})
157 static function lchown(descriptor:String, uid:Int, gid:Int):Bool;
158
159 @:native("fs_copyfile")
160 @:overload(function(path:String, newPath:String, flags:Null<CopyFlags>, cb:String->Bool->Void):Request {})
161 static function copyfile(path:String, newPath:String, ?flags:CopyFlags):Bool;
150162
151163 @:native("fs_statfs")
152164 @:overload(function(path:String, cb:StatFs->Bool->Void):Request {})
153165 static function statfs(path:String):StatFs;
154166
155167 @:native("fs_opendir")
156 @:overload(function(path:String, cb:Handle->Bool->Void):Request {})
168 @:overload(function(path:String, cb:String->Handle->Void, ?entries:Int):Request {})
157169 static function opendir(path:String):Handle;
158170
159171 @:native("fs_readdir")
160 @:overload(function(dir:Handle, cb:Table<Int, NameType>->Bool->Void):Request {})
161 static function readdir(path:String):Table<Int, NameType>;
172 @:overload(function(dir:Handle, cb:String->Table<Int, NameType>->Void):Request {})
173 static function readdir(path:Handle):Table<Int, NameType>;
162174
163175 @:native("fs_closedir")
164 @:overload(function(dir:Handle, cb:Bool->Void):Request {})
176 @:overload(function(dir:Handle, cb:String->Bool->Void):Request {})
165177 static function closedir(dir:Handle):Bool;
166178 }
167179
212224 files:Int,
213225 ffree:Int
214226 }
227
228 typedef CopyFlags = {
229 ?excl:Bool,
230 ?ficlone:Bool,
231 ?ficlone_force:Bool
232 }
233
234 enum abstract AccessMode(Int) to Int {
235 // from libuv sources
236
237 /* Test for read permission. */
238 var R_OK = 4;
239 /* Test for write permission. */
240 var W_OK = 2;
241 /* Test for execute permission. */
242 var X_OK = 1;
243 /* Test for existence. */
244 var F_OK = 0;
245
246 @:op(A | B) function or(b:AccessMode):Int;
247 }
107107 }
108108 }
109109
110 private static function __tagserialize(o:Dynamic)
111 untyped {
112 var n = o.__enum__.__ename__;
113 var x = __dollar__amake(n.length + 1);
114 for (i in 0...n.length)
115 x[i] = n[i].__s;
116 x[n.length] = o.tag;
117 return x;
118 }
110 private static function __tagserialize(o:Dynamic) untyped {
111 var n = o.__enum__.__ename__;
112 var x = __dollar__amake(n.length + 1);
113 for (i in 0...n.length)
114 x[i] = n[i].__s;
115 x[n.length] = o.tag;
116 return x;
117 }
119118
120119 private static function __unserialize(v:Dynamic) {
121120 untyped {
124123 for (i in 0...__dollar__asize(v))
125124 if (__dollar__typeof(v[i]) != __dollar__tstring)
126125 throw "Invalid serialized class data";
127 var cl = neko.Boot.__classes;
126 var cl:Dynamic = neko.Boot.__classes;
128127 for (i in 0...__dollar__asize(v)) {
129128 cl = __dollar__objget(cl, __dollar__hash(v[i]));
130129 if (cl == null)
6868 return new String(v);
6969 }
7070
71 public static function putEnv( s : String, v : String ) : Void {
71 public static function putEnv( s : String, v : Null<String> ) : Void {
7272 untyped put_env(s.__s,if( v == null ) null else v.__s);
7373 }
7474
7373
7474 public function toString():String {
7575 var s = new StringBuf();
76 s.add("{");
76 s.add("[");
7777 var it = keys();
7878 for (i in it) {
7979 s.add(i);
8282 if (it.hasNext())
8383 s.add(", ");
8484 }
85 s.add("}");
85 s.add("]");
8686 return s.toString();
8787 }
8888
9393
9494 public function toString():String {
9595 var s = new StringBuf();
96 s.add("{");
96 s.add("[");
9797 var it = keys();
9898 for (i in it) {
9999 s.add(Std.string(i));
102102 if (it.hasNext())
103103 s.add(", ");
104104 }
105 s.add("}");
105 s.add("]");
106106 return s.toString();
107107 }
108108
7373
7474 public function toString():String {
7575 var s = new StringBuf();
76 s.add("{");
76 s.add("[");
7777 var it = keys();
7878 for (i in it) {
7979 s.add(i);
8282 if (it.hasNext())
8383 s.add(", ");
8484 }
85 s.add("}");
85 s.add("]");
8686 return s.toString();
8787 }
8888
558558 /**
559559 Create Haxe-compatible anonymous structure of `data` associative array
560560 **/
561 static public function createAnon(data:NativeArray):Dynamic {
562 var o = new HxAnon();
563 Syntax.foreach(data, (field:String, value:Any) -> Syntax.setField(o, field, value));
564 return o;
561 static public inline function createAnon(data:NativeArray):Dynamic {
562 return new HxAnon(data);
565563 }
566564
567565 /**
947945 @:keep
948946 @:dox(hide)
949947 private class HxAnon extends StdClass {
948 public function new(fields:NativeArray = null) {
949 super();
950 if (fields != null) {
951 Syntax.foreach(fields, function(name, value) Syntax.setField(this, name, value));
952 }
953 }
954
950955 @:phpMagic
951956 function __get(name:String) {
952957 return null;
618618 static final FILEINFO_PRESERVE_ATIME: Int;
619619 static final FILEINFO_RAW: Int;
620620 static final FILEINFO_SYMLINK: Int;
621
622 /**
623 @see http://php.net/manual/en/calendar.constants.php
624 **/
625 static final CAL_DOW_DAYNO: Int;
626 static final CAL_DOW_LONG: Int;
627 static final CAL_DOW_SHORT: Int;
628 static final CAL_EASTER_ALWAYS_GREGORIAN: Int;
629 static final CAL_EASTER_ALWAYS_JULIAN: Int;
630 static final CAL_EASTER_DEFAULT: Int;
631 static final CAL_EASTER_ROMAN: Int;
632 static final CAL_FRENCH: Int;
633 static final CAL_GREGORIAN: Int;
634 static final CAL_JEWISH: Int;
635 static final CAL_JEWISH_ADD_ALAFIM: Int;
636 static final CAL_JEWISH_ADD_ALAFIM_GERESH: Int;
637 static final CAL_JEWISH_ADD_GERESHAYIM: Int;
638 static final CAL_JULIAN: Int;
639 static final CAL_MONTH_FRENCH: Int;
640 static final CAL_MONTH_GREGORIAN_LONG: Int;
641 static final CAL_MONTH_GREGORIAN_SHORT: Int;
642 static final CAL_MONTH_JEWISH: Int;
643 static final CAL_MONTH_JULIAN_LONG: Int;
644 static final CAL_MONTH_JULIAN_SHORT: Int;
645 static final CAL_NUM_CALS: Int;
646
647 /**
648 @see http://php.net/manual/en/ftp.constants.php
649 **/
650 static final FTP_ASCII: Int;
651 static final FTP_AUTORESUME: Int;
652 static final FTP_AUTOSEEK: Int;
653 static final FTP_BINARY: Int;
654 static final FTP_FAILED: Int;
655 static final FTP_FINISHED: Int;
656 static final FTP_IMAGE: Int;
657 static final FTP_MOREDATA: Int;
658 static final FTP_TEXT: Int;
659 static final FTP_TIMEOUT_SEC: Int;
660 static final FTP_USEPASVADDRESS: Bool;
661
662 /**
663 @see http://php.net/manual/en/misc.constants.php
664 **/
665 static final CONNECTION_ABORTED: Int;
666 static final CONNECTION_NORMAL: Int;
667 static final CONNECTION_TIMEOUT: Int;
668
669 /**
670 @see http://php.net/manual/fr/filesystem.constants.php
671 **/
672 static final FILE_APPEND: Int;
673 static final FILE_BINARY: Int;
674 static final FILE_IGNORE_NEW_LINES: Int;
675 static final FILE_NO_DEFAULT_CONTEXT: Int;
676 static final FILE_SKIP_EMPTY_LINES: Int;
677 static final FILE_TEXT: Int;
678 static final FILE_USE_INCLUDE_PATH: Int;
621679 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 /**
25 The `DirectoryIterator` class provides a simple interface for viewing the contents of filesystem directories.
26 @see https://www.php.net/manual/en/class.directoryiterator.php
27 **/
28 @:native("DirectoryIterator")
29 extern class DirectoryIterator extends SplFileInfo implements SeekableIterator<Int, DirectoryIterator> {
30 function new(directory: String);
31
32 function current(): DirectoryIterator;
33 function isDot(): Bool;
34 function key(): Int;
35 function next(): Void;
36 function rewind(): Void;
37 function seek(offset: Int): Void;
38 function valid(): Bool;
39 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 import haxe.extern.EitherType;
25
26 /**
27 The Filesystem iterator.
28 @see https://www.php.net/manual/en/class.filesystemiterator.php
29 **/
30 @:native("FilesystemIterator")
31 extern class FilesystemIterator extends DirectoryIterator implements SeekableIterator<String, Dynamic> {
32 @:phpClassConst static final CURRENT_AS_FILEINFO: Int;
33 @:phpClassConst static final CURRENT_AS_PATHNAME: Int;
34 @:phpClassConst static final CURRENT_AS_SELF: Int;
35 @:phpClassConst static final CURRENT_MODE_MASK: Int;
36 @:phpClassConst static final FOLLOW_SYMLINKS: Int;
37 @:phpClassConst static final KEY_AS_FILENAME: Int;
38 @:phpClassConst static final KEY_AS_PATHNAME: Int;
39 @:phpClassConst static final KEY_MODE_MASK: Int;
40 @:phpClassConst static final NEW_CURRENT_AND_KEY: Int;
41 @:phpClassConst static final SKIP_DOTS: Int;
42 @:phpClassConst static final UNIX_PATHS: Int;
43
44 function new(directory: String, ?flags: Int);
45
46 function current(): EitherType<FilesystemIterator, EitherType<SplFileInfo, String>>;
47 function getFlags(): Int;
48 function key(): String;
49 function setFlags(flags: Int): Void;
50 }
99 @:phpGlobal
1010 extern class Global {
1111 /**
12 @see http://php.net/manual/en/function.get-browser.php
13 **/
14 static function get_browser(?user_agent:String, ?return_array:Bool = false):EitherType<Dynamic, EitherType<NativeArray, Bool>>;
15
16 /**
17 @see http://php.net/manual/en/function.get-defined-constants.php
18 **/
19 static function get_defined_constants(categorize:Bool = false):NativeArray;
20
21 /**
22 @see http://php.net/manual/en/function.finfo-file.php
23 **/
24 static function finfo_file(finfo:Finfo, filename:String, flags:Int = 0, ?context:Resource):EitherType<String, Bool>;
25
26 /**
27 @see http://php.net/manual/en/function.finfo-open.php
28 **/
29 static function finfo_open(flags:Int = 0, ?magic_database:String):EitherType<Finfo, Bool>;
30
31 /**
32 @see http://php.net/manual/en/function.finfo-close.php
33 **/
34 static function finfo_close(finfo:Finfo):Bool;
35
36 /**
37 @see http://php.net/manual/en/function.fastcgi-finish-request.php
38 **/
39 static function fastcgi_finish_request():Bool;
40
41 /**
1242 @see http://php.net/manual/en/function.exit.php
1343 **/
1444 static function exit(status:EitherType<String, Int>):Void;
370400 static function strpos(haystack:String, needle:String, offset:Int = 0):EitherType<Bool, Int>;
371401
372402 /**
403 @see http://php.net/manual/en/function.stripos.php
404 **/
405 static function stripos(haystack:String, needle:String, offset:Int = 0):EitherType<Bool, Int>;
406
407 /**
373408 @see http://php.net/manual/en/function.strrpos.php
374409 **/
375410 static function strrpos(haystack:String, needle:String, offset:Int = 0):EitherType<Bool, Int>;
388423 @see http://php.net/manual/en/function.strcmp.php
389424 **/
390425 static function strcmp(str1:String, str2:String):Int;
426
427 /**
428 @see https://www.php.net/manual/en/function.strspn.php
429 **/
430 static function strspn(string:String, characters:String, offset:Int = 0, ?length:Int):Int;
391431
392432 /**
393433 @see http://php.net/manual/en/function.strtr.php
405445 **/
406446 static function str_replace(search:EitherType<String, NativeArray>, replace:EitherType<String, NativeArray>, subject:EitherType<String, NativeArray>,
407447 ?count:Int):EitherType<String, NativeArray>;
448
449 /**
450 @see https://www.php.net/manual/en/function.str-starts-with.php
451 **/
452 static function str_starts_with(haystack:String, needle:String):Bool;
408453
409454 /**
410455 @see http://php.net/manual/en/function.explode.php
11961241 /**
11971242 @see http://php.net/manual/en/function.mb-strlen.php
11981243 **/
1199 static function mb_strlen(str:String, ?encoding:String):EitherType<Int, Bool>;
1244 static function mb_strlen(str:String, ?encoding:String):Int;
12001245
12011246 /**
12021247 @see http://php.net/manual/en/function.mb-substr.php
14521497 @see http://php.net/manual/en/function.base64-decode.php
14531498 **/
14541499 static function base64_decode(data:String, strict:Bool = false):EitherType<String, Bool>;
1500
1501 /**
1502 @see http://php.net/manual/en/function.gethostname.php
1503 **/
1504 static function gethostname():EitherType<String, Bool>;
14551505
14561506 /**
14571507 @see http://php.net/manual/en/function.gethostbyname.php
18671917 @see http://php.net/manual/en/function.empty.php
18681918 **/
18691919 static function empty(variable:Any):Bool;
1920
1921 /**
1922 @see http://php.net/manual/en/function.quoted-printable-decode.php
1923 **/
1924 static function quoted_printable_decode(string:String):String;
1925
1926 /**
1927 @see http://php.net/manual/en/function.quoted-printable-encode.php
1928 **/
1929 static function quoted_printable_encode(string:String):String;
1930
1931 /**
1932 @see http://php.net/manual/en/function.easter-date.php
1933 **/
1934 static function easter_date(?year:Int, ?mode:Int): Int;
1935
1936 /**
1937 @see http://php.net/manual/en/function.easter-days.php
1938 **/
1939 static function easter_days(?year:Int, ?mode:Int): Int;
1940
1941 /**
1942 @see http://php.net/manual/en/function.sys-get-temp-dir.php
1943 **/
1944 static function sys_get_temp_dir():String;
1945
1946 /**
1947 @see http://php.net/manual/en/function.tempnam.php
1948 **/
1949 static function tempnam(directory:String, prefix:String):EitherType<String, Bool>;
1950
1951 /**
1952 @see http://php.net/manual/en/function.tmpfile.php
1953 **/
1954 static function tmpfile():EitherType<Resource, Bool>;
1955
1956 /**
1957 @see http://php.net/manual/en/function.ftp-alloc.php
1958 **/
1959 static function ftp_alloc(ftp: Resource, size: Int, ?response: Ref<String>): Bool;
1960
1961 /**
1962 @see http://php.net/manual/en/function.ftp-append.php
1963 **/
1964 static function ftp_append(ftp: Resource, remote_filename: String, local_filename: String, ?mode: Int): Bool;
1965
1966 /**
1967 @see http://php.net/manual/en/function.ftp-cdup.php
1968 **/
1969 static function ftp_cdup(ftp: Resource): Bool;
1970
1971 /**
1972 @see http://php.net/manual/en/function.ftp-chdir.php
1973 **/
1974 static function ftp_chdir(ftp: Resource, directory: String): Bool;
1975
1976 /**
1977 @see http://php.net/manual/en/function.ftp-chmod.php
1978 **/
1979 static function ftp_chmod(ftp: Resource, permissions: Int, filename: String): EitherType<Int, Bool>;
1980
1981 /**
1982 @see http://php.net/manual/en/function.ftp-close.php
1983 **/
1984 static function ftp_close(ftp: Resource): Bool;
1985
1986 /**
1987 @see http://php.net/manual/en/function.ftp-connect.php
1988 **/
1989 static function ftp_connect(hostname: String, port: Int = 21, timeout: Int = 90): EitherType<Resource, Bool>;
1990
1991 /**
1992 @see http://php.net/manual/en/function.ftp-delete.php
1993 **/
1994 static function ftp_delete(ftp: Resource, filename: String): Bool;
1995
1996 /**
1997 @see http://php.net/manual/en/function.ftp-exec.php
1998 **/
1999 static function ftp_exec(ftp: Resource, command: String): Bool;
2000
2001 /**
2002 @see http://php.net/manual/en/function.ftp-fget.php
2003 **/
2004 static function ftp_fget(ftp: Resource, stream: Resource, remote_filename: String, ?mode: Int, offset: Int = 0): Bool;
2005
2006 /**
2007 @see http://php.net/manual/en/function.ftp-fput.php
2008 **/
2009 static function ftp_fput(ftp: Resource, remote_filename: String, stream: Resource, ?mode: Int, offset: Int = 0): Bool;
2010
2011 /**
2012 @see http://php.net/manual/en/function.ftp-get.php
2013 **/
2014 static function ftp_get(ftp: Resource, local_filename: String, remote_filename: String, offset: Int = 0): Bool;
2015
2016 /**
2017 @see http://php.net/manual/en/function.ftp-get-option.php
2018 **/
2019 static function ftp_get_option(ftp: Resource, option: Int): EitherType<Int, Bool>;
2020
2021 /**
2022 @see http://php.net/manual/en/function.ftp-login.php
2023 **/
2024 static function ftp_login(ftp: Resource, username: String, password: String): Bool;
2025
2026 /**
2027 @see http://php.net/manual/en/function.ftp-mdtm.php
2028 **/
2029 static function ftp_mdtm(ftp: Resource, filename: String): Int;
2030
2031 /**
2032 @see http://php.net/manual/en/function.ftp-mkdir.php
2033 **/
2034 static function ftp_mkdir(ftp: Resource, directory: String): EitherType<String, Bool>;
2035
2036 /**
2037 @see http://php.net/manual/en/function.ftp-mlsd.php
2038 **/
2039 static function ftp_mlsd(ftp: Resource, directory: String): EitherType<NativeIndexedArray<NativeAssocArray<String>>, Bool>;
2040
2041 /**
2042 @see http://php.net/manual/en/function.ftp-nb-continue.php
2043 **/
2044 static function ftp_nb_continue(ftp: Resource): Int;
2045
2046 /**
2047 @see http://php.net/manual/en/function.ftp-nb-fget.php
2048 **/
2049 static function ftp_nb_fget(ftp: Resource, stream: Resource, remote_filename: String, ?mode: Int, offset: Int = 0): Int;
2050
2051 /**
2052 @see http://php.net/manual/en/function.ftp-nb-fput.php
2053 **/
2054 static function ftp_nb_fput(ftp: Resource, remote_filename: String, stream: Resource, ?mode: Int, offset: Int = 0): Int;
2055
2056 /**
2057 @see http://php.net/manual/en/function.ftp-nb-get.php
2058 **/
2059 static function ftp_nb_get(ftp: Resource, local_filename: String, remote_filename: String, offset: Int = 0): Int;
2060
2061 /**
2062 @see http://php.net/manual/en/function.ftp-nb-put.php
2063 **/
2064 static function ftp_nb_put(ftp: Resource, remote_filename: String, local_filename: String, offset: Int = 0): EitherType<Int, Bool>;
2065
2066 /**
2067 @see http://php.net/manual/en/function.ftp-nlist.php
2068 **/
2069 static function ftp_nlist(ftp: Resource, directory: String): EitherType<NativeIndexedArray<String>, Bool>;
2070
2071 /**
2072 @see http://php.net/manual/en/function.ftp-pasv.php
2073 **/
2074 static function ftp_pasv(ftp: Resource, enable: Bool): Bool;
2075
2076 /**
2077 @see http://php.net/manual/en/function.ftp-put.php
2078 **/
2079 static function ftp_put(ftp: Resource, remote_filename: String, local_filename: String, offset: Int = 0): Bool;
2080
2081 /**
2082 @see http://php.net/manual/en/function.ftp-pwd.php
2083 **/
2084 static function ftp_pwd(ftp: Resource): EitherType<String, Bool>;
2085
2086 /**
2087 @see http://php.net/manual/en/function.ftp-raw.php
2088 **/
2089 static function ftp_raw(ftp: Resource, command: String): NativeIndexedArray<String>;
2090
2091 /**
2092 @see http://php.net/manual/en/function.ftp-rawlist.php
2093 **/
2094 static function ftp_rawlist(ftp: Resource, directory: String, recursive: Bool = false): EitherType<NativeIndexedArray<String>, Bool>;
2095
2096 /**
2097 @see http://php.net/manual/en/function.ftp-rename.php
2098 **/
2099 static function ftp_rename(ftp: Resource, from: String, to: String): Bool;
2100
2101 /**
2102 @see http://php.net/manual/en/function.ftp-rmdir.php
2103 **/
2104 static function ftp_rmdir(ftp: Resource, directory: String): Bool;
2105
2106 /**
2107 @see http://php.net/manual/en/function.ftp-set-option.php
2108 **/
2109 static function ftp_set_option(ftp: Resource, option: Int, value: EitherType<Int, Bool>): Bool;
2110
2111 /**
2112 @see http://php.net/manual/en/function.ftp-site.php
2113 **/
2114 static function ftp_site(ftp: Resource, command: String): Bool;
2115
2116 /**
2117 @see http://php.net/manual/en/function.ftp-size.php
2118 **/
2119 static function ftp_size(ftp: Resource, filename: String): Int;
2120
2121 /**
2122 @see http://php.net/manual/en/function.ftp-ssl-connect.php
2123 **/
2124 static function ftp_ssl_connect(hostname: String, port: Int = 21, timeout: Int = 90): EitherType<Resource, Bool>;
2125
2126 /**
2127 @see http://php.net/manual/en/function.ftp-systype.php
2128 **/
2129 static function ftp_systype(ftp: Resource): EitherType<String, Bool>;
2130
2131 /**
2132 @see http://php.net/manual/en/function.connection-aborted.php
2133 **/
2134 static function connection_aborted(): Int;
2135
2136 /**
2137 @see http://php.net/manual/en/function.connection-status.php
2138 **/
2139 static function connection_status(): Int;
2140
2141 /**
2142 @see http://php.net/manual/en/function.ignore-user-abort.php
2143 **/
2144 static function ignore_user_abort(enable: Null<Bool> = null): Int;
2145
2146 /**
2147 @see http://php.net/manual/en/function.highlight-file.php
2148 **/
2149 static function highlight_file(filename: String, returns: Bool = false): EitherType<String, Bool>;
2150
2151 /**
2152 @see http://php.net/manual/en/function.highlight-string.php
2153 **/
2154 static function highlight_string(string: String, returns: Bool = false): EitherType<String, Bool>;
2155
2156 /**
2157 @see http://php.net/manual/en/function.php-strip-whitespace.php
2158 **/
2159 static function php_strip_whitespace(filename: String): String;
18702160 }
9797 return @:privateAccess Array.wrap(a);
9898 }
9999
100 public static function hashOfAssociativeArray<T>(arr:NativeAssocArray<T>):Map<String, T> {
100 public static function hashOfAssociativeArray<T>(arr:NativeAssocArray<T>):StringMap<T> {
101101 var result = new StringMap();
102102 @:privateAccess result.data = arr;
103103 return result;
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 import haxe.extern.EitherType;
25
26 /**
27 The `Phar` class provides a high-level interface to accessing and creating PHAR archives.
28 @see https://www.php.net/manual/en/class.phar.php
29 **/
30 @:native("Phar")
31 extern class Phar extends RecursiveDirectoryIterator implements Countable implements php.ArrayAccess<String, PharFileInfo> {
32 @:phpClassConst static final BZ2: Int;
33 @:phpClassConst static final COMPRESSED: Int;
34 @:phpClassConst static final GZ: Int;
35 @:phpClassConst static final MD5: Int;
36 @:phpClassConst static final NONE: Int;
37 @:phpClassConst static final OPENSSL: Int;
38 @:phpClassConst static final PHAR: Int;
39 @:phpClassConst static final PHP: Int;
40 @:phpClassConst static final PHPS: Int;
41 @:phpClassConst static final SHA1: Int;
42 @:phpClassConst static final SHA256: Int;
43 @:phpClassConst static final SHA512: Int;
44 @:phpClassConst static final TAR: Int;
45 @:phpClassConst static final ZIP: Int;
46
47 final static function apiVersion(): String;
48 final static function canCompress(type: Int = 0): Bool;
49 final static function canWrite(): Bool;
50 final static function createDefaultStub(?index: String, ?webIndex: String): String;
51 final static function getSupportedCompression(): NativeIndexedArray<String>;
52 final static function getSupportedSignatures(): NativeIndexedArray<String>;
53 final static function isValidPharFilename(filename: String, executable: Bool = true): Bool;
54 final static function loadPhar(filename: String, ?alias: String): Bool;
55 final static function mapPhar(?alias: String, dataoffset: Int = 0): Bool;
56 final static function mount(pharpath: String, externalpath: String): Void;
57 final static function mungServer(munglist: NativeIndexedArray<String>): Void;
58 final static function running(retphar: Bool = true): String;
59 final static function unlinkArchive(archive: String): Bool;
60 final static function webPhar(?alias: String, index: String = "index.php", ?f404: String, ?mimetypes: NativeAssocArray<String>, ?callable: String -> EitherType<String, Bool>): Void;
61
62 function new(fname: String, ?flags: Int, ?alias: String);
63
64 function addEmptyDir(dirname: String): Void;
65 function addFile(file: String, ?localname: String): Void;
66 function addFromString(localname: String, contents: String): Void;
67 function buildFromDirectory(base_dir: String, ?regex: String): NativeAssocArray<String>;
68 function buildFromIterator(iter: EitherType<NativeIterator<String, String>, NativeIterator<Int, SplFileInfo>>, ?base_directory: String): NativeAssocArray<String>;
69 function compress(compression: Int, ?extension: String): Phar;
70 function compressFiles(compression: Int): Void;
71 function convertToData(?format: Int, ?compression: Int, ?extension: String): PharData;
72 function convertToExecutable(?format: Int, ?compression: Int, ?extension: String): Phar;
73 function copy(oldfile: String, newfile: String): Bool;
74 function count(): Int;
75 function decompress(?extension: String): PharData;
76 function decompressFiles(): Void;
77 function delete(entry: String): Bool;
78 function delMetadata(): Bool;
79 function extractTo(pathto: String, ?files: EitherType<String, NativeIndexedArray<String>>, overwrite: Bool = false): Bool;
80 function getAlias(): String;
81 function getMetadata(): Dynamic;
82 function getModified(): Bool;
83 function getPath(): String;
84 function getSignature(): NativeAssocArray<String>;
85 function getStub(): String;
86 function getVersion(): String;
87 function hasMetadata(): Bool;
88 function isBuffering(): Bool;
89 function isCompressed(): EitherType<Int, Bool>;
90 function isFileFormat(format: Int): Bool;
91 function isWritable(): Bool;
92 function offsetExists(offset: String): Bool;
93 function offsetGet(offset: String): PharFileInfo;
94 function offsetSet(offset: String, value: Dynamic): Void;
95 function offsetUnset(offset: String): Void;
96 function setAlias(alias: String): Bool;
97 function setDefaultStub(?index: String, ?webindex: String): Bool;
98 function setMetadata(metadata: Any): Void;
99 function setSignatureAlgorithm(sigtype: Int, ?privatekey: String): Void;
100 function setStub(stub: String, len: Int = -1): Bool;
101 function startBuffering(): Void;
102 function stopBuffering(): Void;
103 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 import haxe.extern.EitherType;
25
26 /**
27 The `PharData` class provides a high-level interface to accessing and creating non-executable TAR and ZIP archives.
28 @see https://www.php.net/manual/en/class.phardata.php
29 **/
30 @:native("PharData")
31 extern class PharData extends RecursiveDirectoryIterator implements Countable implements php.ArrayAccess<String, PharFileInfo> {
32 function new(fname: String, ?flags: Int, ?alias: String, ?format: Int);
33
34 function addEmptyDir(dirname: String): Void;
35 function addFile(file: String, ?localname: String): Void;
36 function addFromString(localname: String, contents: String): Void;
37 function buildFromDirectory(base_dir: String, ?regex: String): NativeAssocArray<String>;
38 function buildFromIterator(iter: EitherType<NativeIterator<String, String>, NativeIterator<Int, SplFileInfo>>, ?base_directory: String): NativeAssocArray<String>;
39 function compress(compression: Int, ?extension: String): PharData;
40 function compressFiles(compression: Int): Void;
41 function copy(oldfile: String, newfile: String): Bool;
42 function count(): Int;
43 function decompress(?extension: String): PharData;
44 function decompressFiles(): Void;
45 function delete(entry: String): Bool;
46 function delMetadata(): Bool;
47 function extractTo(pathto: String, ?files: EitherType<String, NativeIndexedArray<String>>, overwrite: Bool = false): Bool;
48 function isWritable(): Bool;
49 function offsetExists(offset: String): Bool;
50 function offsetGet(offset: String): PharFileInfo;
51 function offsetSet(offset: String, value: Dynamic): Void;
52 function offsetUnset(offset: String): Void;
53 function setAlias(alias: String): Bool;
54 function setDefaultStub(?index: String, ?webindex: String): Bool;
55 function setMetadata(metadata: Any): Void;
56 function setSignatureAlgorithm(sigtype: Int): Void;
57 function setStub(stub: String, len: Int = -1): Bool;
58 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 /**
25 The `PharException` class provides a phar-specific exception class for try/catch blocks.
26 @see https://www.php.net/manual/en/class.pharexception.php
27 **/
28 @:native("PharException")
29 extern class PharException extends Exception {}
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 /**
25 The `PharFileInfo` class provides a high-level interface to the contents and attributes of a single file within a PHAR archive.
26 @see https://www.php.net/manual/en/class.pharfileinfo
27 **/
28 @:native("PharFileInfo")
29 extern class PharFileInfo extends SplFileInfo {
30 function new(entry: String);
31
32 function chmod(permissions: Int): Void;
33 function compress(compression: Int): Bool;
34 function decompress(): Bool;
35 function delMetadata(): Bool;
36 function getCompressedSize(): Int;
37 function getContent(): String;
38 function getCRC32(): Int;
39 function getMetadata(): Dynamic;
40 function getPharFlags(): Int;
41 function hasMetadata(): Bool;
42 function isCompressed(?compression_type: Int): Bool;
43 function isCRCChecked(): Bool;
44 function setMetadata(metadata: Any): Void;
45 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 /**
25 The `RecursiveDirectoryIterator` provides an interface for iterating recursively over filesystem directories.
26 @see https://www.php.net/manual/en/class.recursivedirectoryiterator.php
27 **/
28 @:native("RecursiveDirectoryIterator")
29 extern class RecursiveDirectoryIterator extends FilesystemIterator implements RecursiveIterator<String, Dynamic> implements SeekableIterator<String, Dynamic> {
30 function new(directory: String, ?flags: Int);
31
32 function getChildren(): Null<RecursiveDirectoryIterator>;
33 function getSubPath(): String;
34 function getSubPathname(): String;
35
36 @:overload(function(allowLinks: Bool): Bool {})
37 function hasChildren(): Bool;
38 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 /**
25 Classes implementing `RecursiveIterator` can be used to iterate over iterators recursively.
26 @see https://www.php.net/manual/en/class.recursiveiterator.php
27 **/
28 @:native("RecursiveIterator")
29 extern interface RecursiveIterator<K, V> extends NativeIterator<K, V> {
30 function getChildren(): Null<RecursiveIterator<K, V>>;
31 function hasChildren(): Bool;
32 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 import haxe.extern.EitherType;
25
26 /**
27 The `ResourceBundle` class implements access to ICU resource data files.
28 @see https://www.php.net/manual/en/class.resourcebundle.php
29 **/
30 @:native("ResourceBundle")
31 extern class ResourceBundle {
32 function new(locale: Null<String>, bundle: Null<String>, fallback: Bool = true);
33
34 static function create(locale: Null<String>, bundle: Null<String>, fallback: Bool = true): Null<ResourceBundle>;
35 static function getLocales(bundle: String): EitherType<NativeIndexedArray<String>, Bool>;
36
37 function count(): Int;
38 function get(index: EitherType<Int, String>, fallback: Bool = true): Dynamic;
39 function getErrorCode(): Int;
40 function getErrorMessage(): String;
41 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 import haxe.extern.EitherType;
25
26 /**
27 The `SplFileInfo` class offers a high-level object-oriented interface to information for an individual file.
28 @see https://www.php.net/manual/en/class.splfileinfo.php
29 **/
30 @:native("SplFileInfo")
31 extern class SplFileInfo {
32 function new(filename: String);
33
34 function getATime(): EitherType<Int, Bool>;
35 function getBasename(suffix: String = ""): String;
36 function getCTime(): EitherType<Int, Bool>;
37 function getExtension(): String;
38 function getFileInfo(?className: String): SplFileInfo;
39 function getFilename(): String;
40 function getGroup(): EitherType<Int, Bool>;
41 function getInode(): EitherType<Int, Bool>;
42 function getLinkTarget(): EitherType<String, Bool>;
43 function getMTime(): EitherType<Int, Bool>;
44 function getOwner(): EitherType<Int, Bool>;
45 function getPath(): String;
46 function getPathInfo(?className: String): Null<SplFileInfo>;
47 function getPathname(): String;
48 function getPerms(): EitherType<Int, Bool>;
49 function getRealPath(): EitherType<String, Bool>;
50 function getSize(): EitherType<Int, Bool>;
51 function getType(): EitherType<SplFileInfoType, Bool>;
52 function isDir(): Bool;
53 function isExecutable(): Bool;
54 function isFile(): Bool;
55 function isLink(): Bool;
56 function isReadable(): Bool;
57 function isWritable(): Bool;
58 function openFile(mode: String = "r", useIncludePath: Bool = false, ?context: Resource): SplFileObject;
59 function setFileClass(?className: String): Void;
60 function setInfoClass(?className: String): Void;
61 }
62
63 enum abstract SplFileInfoType(String) to String {
64 var Block = "block";
65 var Char = "char";
66 var Dir = "dir";
67 var Fifo = "fifo";
68 var File = "file";
69 var Link = "link";
70 var Socket = "socket";
71 var Unknown = "unknown";
72 }
0 /*
1 * Copyright (C)2005-2021 Haxe Foundation
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 */
21
22 package php;
23
24 import haxe.extern.EitherType;
25 import haxe.extern.Rest;
26
27 /**
28 The `SplFileObject` class offers an object-oriented interface for a file.
29 @see https://www.php.net/manual/en/class.splfileobject.php
30 **/
31 @:native("SplFileObject")
32 extern class SplFileObject extends SplFileInfo implements RecursiveIterator<Int, Dynamic> implements SeekableIterator<Int, Dynamic> {
33 @:phpClassConst static final DROP_NEW_LINE: Int;
34 @:phpClassConst static final READ_AHEAD: Int;
35 @:phpClassConst static final READ_CSV: Int;
36 @:phpClassConst static final SKIP_EMPTY: Int;
37
38 function new(filename: String, mode: String = "r", useIncludePath: Bool = false, ?context: Resource);
39
40 function current(): EitherType<String, EitherType<NativeIndexedArray<String>, Bool>>;
41 function eof(): Bool;
42 function fflush(): Bool;
43 function fgetc(): EitherType<String, Bool>;
44 function fgetcsv(separator: String = ",", enclosure: String = "\"", escape: String = "\\"): EitherType<NativeIndexedArray<String>, Bool>;
45 function fgets(): String;
46 function fgetss(?allowable_tags: String): String;
47 function flock(operation: Int, ?wouldBlock: Ref<Int>): Bool;
48 function fpassthru(): Int;
49 function fputcsv(fields: NativeIndexedArray<String>, separator: String = ",", enclosure: String = "\"", escape: String = "\\"): EitherType<Int, Bool>;
50 function fread(length: Int): EitherType<String, Bool>;
51 function fscanf(format: String, vars: Rest<Ref<Dynamic>>): EitherType<Int, NativeIndexedArray<Dynamic>>;
52 function fseek(offset: Int, ?whence: Int): Int;
53 function fstat(): NativeArray;
54 function ftell(): EitherType<Int, Bool>;
55 function ftruncate(size: Int): Bool;
56 function fwrite(data: String, length: Int = 0): EitherType<Int, Bool>;
57 function getChildren(): Null<RecursiveIterator<Int, Dynamic>>;
58 function getCsvControl(): NativeIndexedArray<String>;
59 function getFlags(): Int;
60 function getMaxLineLen(): Int;
61 function hasChildren(): Bool;
62 function key(): Int;
63 function next(): Void;
64 function rewind(): Void;
65 function seek(line: Int): Void;
66 function setCsvControl(separator: String = ",", enclosure: String = "\"", escape: String = "\\"): Void;
67 function setFlags(flags: Int): Void;
68 function setMaxLineLen(maxLength: Int): Void;
69 function valid(): Bool;
70 }
5959 }
6060 }
6161
62 /**
63 * @see https://www.php.net/manual/en/function.str-starts-with.php
64 */
65 if (!function_exists('str_starts_with')) {
66 function str_starts_with($str, $start) {
67 return (@substr_compare($str, $start, 0, strlen($start))==0);
68 }
69 }
6270 }
214214 @:noCompletion @:keep
215215 @:php.attribute('\\ReturnTypeWillChange')
216216 function offsetGet(offset:Int):Ref<T> {
217 try {
218 return arr[offset];
219 } catch (e:Dynamic) {
220 return null;
221 }
217 if(offset < 0 || offset >= length) {
218 //This var is required in generated php code
219 //because only variables can be returned by reference.
220 final result = null;
221 Syntax.keepVar(result);
222 return result;
223 }
224 return arr[offset];
222225 }
223226
224227 @:noCompletion @:keep
5151 }
5252
5353 public static function parseInt(x:String):Null<Int> {
54 if (Global.is_numeric(x)) {
55 return Global.intval(x, 10);
56 } else {
57 x = Global.ltrim(x);
58 var firstCharIndex = (x.charAt(0) == '-' ? 1 : 0);
59 var firstCharCode = x.charCodeAt(firstCharIndex);
60 if (!isDigitCode(firstCharCode)) {
54 x = Global.ltrim(x, " \t\n\x0b\x0c\r");
55 final digitsOnly = Global.ltrim(x, "+-");
56 if (Global.str_starts_with(digitsOnly, '0x') || Global.str_starts_with(digitsOnly, '0X')) {
57 final val = Global.intval(x, 16); // hexadecimal
58 // if the value was 0, ensure there is only a maximum of one + or - sign
59 if (val == 0 && digitsOnly.length + 1 < x.length)
6160 return null;
62 }
63 var secondChar = x.charAt(firstCharIndex + 1);
64 if (secondChar == 'x' || secondChar == 'X') {
65 return Global.intval(x, 0);
66 } else {
67 return Global.intval(x, 10);
68 }
61 return val;
6962 }
63
64 switch Global.stripos(x, 'e') {
65 case false:
66 case ePos: x = Global.substr(x, 0, ePos);
67 }
68
69 final val = Global.intval(x, 10);
70 // if the value was 0, make sure it wasn't because the string had no valid digits
71 // last check ensures there is only a maximum of one + or - sign
72 if (val == 0 && (Global.strspn(digitsOnly, "0123456789", 0, 1) == 0 || digitsOnly.length + 1 < x.length))
73 return null;
74 return val;
7075 }
7176
7277 public static function parseFloat(x:String):Float {
2828 /** Environment variables set by `Sys.putEnv()` */
2929 static var customEnvVars = new NativeAssocArray<String>();
3030
31 // we need to keep track of capitalization for windows
32 static final isWindows = systemName() == "Windows";
33
34 static var envCapitalization(get, null):Map<String, String>;
35
36 static function get_envCapitalization():Map<String, String> {
37 if (envCapitalization == null)
38 return envCapitalization = [for (k => _ in SuperGlobal._SERVER) k.toUpperCase() => k];
39 return envCapitalization;
40 }
41
42 static inline function addCustom(name:String, value:String):Void {
43 customEnvVars[name] = value;
44 if (!isWindows)
45 return;
46 final upperCase = name.toUpperCase();
47 if (envCapitalization.exists(upperCase))
48 return;
49 envCapitalization[upperCase] = name;
50 }
51
52 static inline function removeCustom(name:String):Void {
53 Global.unset(customEnvVars[name]);
54 if (!isWindows)
55 return;
56 envCapitalization.remove(name.toUpperCase());
57 }
58
59 static inline function getCapitalization(name:String):String {
60 if (!isWindows)
61 return name;
62 final existing = envCapitalization[name.toUpperCase()];
63 if (existing != null)
64 return existing;
65 return name;
66 }
67
3168 public static inline function print(v:Dynamic):Void {
3269 Global.echo(Std.string(v));
3370 }
4986 return value == false ? null : value;
5087 }
5188
52 public static function putEnv(s:String, v:String):Void {
53 customEnvVars[s] = '$v'; // in case of `null` it should become `"null"`
54 Global.putenv('$s=$v');
89 public static function putEnv(s:String, v:Null<String>):Void {
90 if (v == null) {
91 removeCustom(s);
92 Global.putenv('$s');
93 } else {
94 addCustom(s, v);
95 Global.putenv('$s=$v');
96 }
5597 }
5698
5799 public static inline function sleep(seconds:Float):Void {
123165 public static function environment():Map<String, String> {
124166 var env = SuperGlobal._SERVER;
125167 Syntax.foreach(customEnvVars, function(name:String, value:String) {
126 env[name] = value;
168 final actualName = getCapitalization(name);
169 env[actualName] = value;
127170 });
128171 return php.Lib.hashOfAssociativeArray(env);
129172 }
1515 @:from
1616 static public inline function of<T>(array:Array<T>):Rest<T>
1717 return new Rest(@:privateAccess array.arr);
18
19 @:noDoc
20 @:from
21 static inline function ofNative<T>(array:NativeIndexedArray<T>):Rest<T>
22 return new Rest(array);
1823
1924 inline function new(a:NativeIndexedArray<T>):Void
2025 this = a;
4343
4444 public static inline function decode(str:String, complement = true):Bytes {
4545 if (!complement) {
46 switch (strlen(str) % 3) {
47 case 1:
46 switch (strlen(str) % 4) {
47 case 2:
4848 str += "==";
49 case 2:
49 case 3:
5050 str += "=";
5151 default:
5252 }
5353 }
54 return Bytes.ofString(base64_decode(str, true));
54 return switch base64_decode(str, true) {
55 case false: throw new Exception("Base64.decode : invalid encoded string");
56 case s: Bytes.ofString(s);
57 }
5558 }
5659
5760 public static inline function urlEncode(bytes:Bytes, complement = false):String {
6164
6265 public static inline function urlDecode(str:String, complement = false):Bytes {
6366 if (complement) {
64 switch (strlen(str) % 3) {
65 case 1:
67 switch (strlen(str) % 4) {
68 case 2:
6669 str += "==";
67 case 2:
70 case 3:
6871 str += "=";
6972 default:
7073 }
7174 }
72 return Bytes.ofString(base64_decode(str_replace(URL_62_63, NORMAL_62_63, str), true));
75 return switch base64_decode(str_replace(URL_62_63, NORMAL_62_63, str), true) {
76 case false: throw new Exception("Base64.urlDecode : invalid encoded string");
77 case s: Bytes.ofString(s);
78 }
7379 }
7480 }
7878 Global.array_push(parts, '$key => ' + Std.string(value));
7979 });
8080
81 return '{' + Global.implode(', ', parts) + '}';
81 return "[" + Global.implode(", ", parts) + "]";
8282 }
8383
8484 public inline function clear():Void {
7777 }
7878
7979 public function toString():String {
80 var s = "{";
80 var s = "[";
8181 var it = keys();
8282 for (i in it) {
8383 s += Std.string(i);
8686 if (it.hasNext())
8787 s += ", ";
8888 }
89 return s + "}";
89 return s + "]";
9090 }
9191
9292 public inline function clear():Void {
7979 Global.array_push(parts, '$key => ' + Std.string(value));
8080 });
8181
82 return '{' + Global.implode(', ', parts) + '}';
82 return "[" + Global.implode(", ", parts) + "]";
8383 }
8484
8585 public inline function clear():Void {
2727 public var length:Int;
2828 public var data:NativeIndexedArray<T>;
2929
30 public inline function new(length:Int) {
30 public inline function new(length:Int, data:NativeIndexedArray<T>) {
3131 this.length = length;
32 data = new NativeIndexedArray();
32 this.data = data;
3333 }
3434 }
3535
3636 private typedef VectorData<T> = PhpVectorData<T>;
3737
38 @:coreApi
3839 abstract Vector<T>(VectorData<T>) {
3940 public var length(get, never):Int;
4041
41 public inline function new(length:Int) {
42 this = new VectorData(length);
42 extern overload public inline function new(length:Int) {
43 this = new VectorData(length, new NativeIndexedArray());
44 }
45
46 extern overload public inline function new(length:Int, defaultValue:T):Vector<T> {
47 this = new VectorData(length, Global.array_fill(0, length, defaultValue));
4348 }
4449
4550 @:op([]) public inline function get(index:Int):T {
5358 inline function get_length():Int {
5459 return this.length;
5560 }
61
62 public inline function fill(value:T):Void
63 this.data = Global.array_fill(0, length, value);
5664
5765 public static function blit<T>(src:Vector<T>, srcPos:Int, dest:Vector<T>, destPos:Int, len:Int):Void {
5866 if (src == dest) {
98106 }
99107
100108 static public inline function fromArrayCopy<T>(array:Array<T>):Vector<T> {
101 var vectorData = new VectorData(array.length);
102 vectorData.data = @:privateAccess array.arr;
109 var vectorData = new VectorData(array.length, @:privateAccess array.arr);
103110 return cast vectorData;
104111 }
105112
126133 return result;
127134 }
128135
129 public inline function sort<T>(f:T->T->Int):Void {
136 public inline function sort(f:T->T->Int):Void {
130137 Global.usort(this.data, f);
131138 }
132139 }
9898 function errorInfo():NativeArray;
9999 function exec(statement:String):Int;
100100 function getAttribute(attribute:Int):Dynamic;
101 function getAvailableDrivers():NativeArray;
101 static function getAvailableDrivers():NativeIndexedArray<String>;
102102 function lastInsertId(?name:String):String;
103103 function prepare(statement:String, ?driver_options:NativeArray):PDOStatement;
104104 function query(statement:String, ?mode:Int):PDOStatement;
129129 }
130130 }
131131
132 static inline function isSpaceChar(char:String):Bool
133 return Syntax.isIn(char, " \n\r\t\x0b\x0c");
134
135 static inline function isHexPrefix(cur:String, next:String):Bool
136 return cur == '0' && (next == 'x' || next == 'X');
137
138 static inline function isDecimalDigit(char:String):Bool
139 return Syntax.isIn(char, "0123456789");
140
141 static inline function isHexadecimalDigit(char:String):Bool
142 return Syntax.isIn(char, "0123456789abcdefABCDEF");
143
132144 public static function parseInt(x:String):Null<Int> {
133145 if (x == null)
134146 return null;
135 try {
136 return UBuiltins.int(x);
137 } catch (e:Dynamic) {
138 var base = 10;
139 var len = x.length;
140 var foundCount = 0;
141 var sign = 0;
142 var firstDigitIndex = 0;
143 var lastDigitIndex = -1;
144 var previous = 0;
145
146 for(i in 0...len) {
147 var c = StringTools.fastCodeAt(x, i);
148 switch c {
149 case _ if((c > 8 && c < 14) || c == 32):
150 if(foundCount > 0) {
151 return null;
152 }
153 continue;
154 case '-'.code if(foundCount == 0):
155 sign = -1;
156 case '+'.code if(foundCount == 0):
157 sign = 1;
158 case '0'.code if(foundCount == 0 || (foundCount == 1 && sign != 0)):
159 case 'x'.code | 'X'.code if(previous == '0'.code && ((foundCount == 1 && sign == 0) || (foundCount == 2 && sign != 0))):
160 base = 16;
161 case _ if('0'.code <= c && c <= '9'.code):
162 case _ if(base == 16 && (('a'.code <= c && c <= 'z'.code) || ('A'.code <= c && c <= 'Z'.code))):
163 case _:
147
148 final len = x.length;
149 var index = 0;
150
151 inline function hasIndex(index:Int)
152 return index < len;
153
154 // skip whitespace
155 while (hasIndex(index)) {
156 if (!isSpaceChar(Syntax.arrayAccess(x, index)))
157 break;
158 ++index;
159 }
160
161 // handle sign
162 final isNegative = hasIndex(index) && {
163 final sign = Syntax.arrayAccess(x, index);
164 if (sign == '-' || sign == '+') {
165 ++index;
166 }
167 sign == '-';
168 }
169
170 // handle base
171 final isHexadecimal = hasIndex(index + 1) && isHexPrefix(Syntax.arrayAccess(x, index), Syntax.arrayAccess(x, index + 1));
172 if (isHexadecimal)
173 index += 2; // skip prefix
174
175 // handle digits
176 final firstInvalidIndex = {
177 var cur = index;
178 if (isHexadecimal) {
179 while (hasIndex(cur)) {
180 if (!isHexadecimalDigit(Syntax.arrayAccess(x, cur)))
164181 break;
182 ++cur;
165183 }
166 if((foundCount == 0 && sign == 0) || (foundCount == 1 && sign != 0)) {
167 firstDigitIndex = i;
184 } else {
185 while (hasIndex(cur)) {
186 if (!isDecimalDigit(Syntax.arrayAccess(x, cur)))
187 break;
188 ++cur;
168189 }
169 foundCount++;
170 lastDigitIndex = i;
171 previous = c;
172 }
173 if(firstDigitIndex <= lastDigitIndex) {
174 var digits = x.substring(firstDigitIndex, lastDigitIndex + 1);
175 return try {
176 (sign == -1 ? -1 : 1) * UBuiltins.int(digits, base);
177 } catch(e:Dynamic) {
178 null;
179 }
180 }
181 return null;
182 }
190 }
191 cur;
192 }
193
194 // no valid digits
195 if (index == firstInvalidIndex)
196 return null;
197
198 final result = python.internal.UBuiltins.int(x.substring(index, firstInvalidIndex), if (isHexadecimal) 16 else 10);
199 return if (isNegative) -result else result;
183200 }
184201
185202 static function shortenPossibleNumber(x:String):String {
2727
2828 @:coreApi
2929 class Sys {
30 static var environ(get,default):StringMap<String>;
31 static function get_environ():StringMap<String> {
32 return switch environ {
33 case null:
34 var environ = new StringMap();
35 var env = Os.environ;
36 for (key in env.keys()) {
37 environ.set(key, env.get(key, null));
38 }
39 Sys.environ = environ;
40 case env: env;
41 }
42 }
43
4430 public static inline function time():Float {
4531 return Time.time();
4632 }
6349 }
6450
6551 public static function getEnv(s:String):String {
66 return environ.get(s);
52 return Os.environ.get(s, null);
6753 }
6854
69 public static function putEnv(s:String, v:String):Void {
70 python.lib.Os.putenv(s, v);
71 environ.set(s, v);
55 public static function putEnv(s:String, v:Null<String>):Void {
56 if (v == null) {
57 try {
58 Os.environ.remove(s);
59 } catch(e:python.Exceptions.KeyError) {
60 // the variable didn't exist
61 }
62 return;
63 }
64 Os.environ.set(s, v);
7265 }
7366
7467 public static function environment():Map<String, String> {
68 final environ = new StringMap();
69 final env = Os.environ;
70 for (key in env.keys()) {
71 environ.set(key, env.get(key, null));
72 }
7573 return environ;
7674 }
7775
8482 }
8583
8684 public static function getCwd():String {
87 return python.lib.Os.getcwd();
85 return haxe.io.Path.addTrailingSlash(python.lib.Os.getcwd());
8886 }
8987
9088 public static function setCwd(s:String):Void {
7171
7272 public function toString():String {
7373 var s = new StringBuf();
74 s.add("{");
74 s.add("[");
7575 var it = keys();
7676 for (i in it) {
7777 s.add(i);
8080 if (it.hasNext())
8181 s.add(", ");
8282 }
83 s.add("}");
83 s.add("]");
8484 return s.toString();
8585 }
8686
7070
7171 public function toString():String {
7272 var s = new StringBuf();
73 s.add("{");
73 s.add("[");
7474 var it = keys();
7575 for (i in it) {
7676 s.add(Std.string(i));
7979 if (it.hasNext())
8080 s.add(", ");
8181 }
82 s.add("}");
82 s.add("]");
8383 return s.toString();
8484 }
8585
7272 public function toString():String {
7373 var s = new StringBuf();
7474
75 s.add("{");
75 s.add("[");
7676 var it = keys();
7777 for (i in it) {
7878 s.add(i);
8181 if (it.hasNext())
8282 s.add(", ");
8383 }
84 s.add("}");
84 s.add("]");
8585 return s.toString();
8686 }
8787
125125 __s = new PSocket();
126126 }
127127
128 function __rebuildIoStreams():Void {
129 input = new SocketInput(__s);
130 output = new SocketOutput(__s);
131 }
132
128133 public function close():Void {
129134 __s.close();
130135 }
0 package sys.thread;
1
2 @:coreApi
3 class Condition {
4 final cond:python.lib.threading.Condition;
5
6 public function new():Void {
7 this.cond = new python.lib.threading.Condition();
8 }
9
10 public function acquire():Void {
11 cond.acquire();
12 }
13
14 public function tryAcquire():Bool {
15 return cond.acquire(false);
16 }
17
18 public function release():Void {
19 cond.release();
20 }
21
22 public function wait():Void {
23 cond.wait();
24 }
25
26 public function signal():Void {
27 cond.notify();
28 }
29
30 public function broadcast():Void {
31 cond.notify_all();
32 }
33 }
2121
2222 package sys.thread;
2323
24 import python.lib.threading.Condition;
25
2426 using python.internal.UBuiltins;
2527
2628 class Deque<T> {
2729 var deque:NativeDeque<T>;
28 var lock:NativeCondition;
30 var lock:Condition;
2931
3032 public function new() {
3133 deque = new NativeDeque<T>();
32 lock = new NativeCondition();
34 lock = new Condition();
3335 }
3436
3537 public function add(i:T) {
6264
6365 @:pythonImport("collections", "deque")
6466 @:native("deque")
65 extern class NativeDeque<T> {
67 private extern class NativeDeque<T> {
6668 function new();
6769 function append(x:T):Void;
6870 function appendleft(x:T):Void;
6971 function popleft():T;
7072 }
71
72 @:pythonImport("threading", "Condition")
73 @:native("Condition")
74 private extern class NativeCondition {
75 function new(?lock:Dynamic);
76 function acquire(blocking:Bool = true, timeout:Float = -1):Bool;
77 function release():Void;
78 function wait(?timeout:Float):Bool;
79 function wait_for(predicate:()->Bool, ?timeout:Float):Bool;
80 function notify(n:Int = 1):Void;
81 function notify_all():Void;
82 }
2121
2222 package sys.thread;
2323
24 import python.lib.threading.Semaphore;
25
2426 @:coreApi
2527 class Lock {
26 final semaphore:NativeSemaphore;
28 final semaphore:Semaphore;
2729
2830 public inline function new() {
29 semaphore = new NativeSemaphore(0);
31 semaphore = new Semaphore(0);
3032 }
3133
3234 public inline function wait(?timeout:Float):Bool {
3739 semaphore.release();
3840 }
3941 }
40
41 @:pythonImport("threading", "Semaphore")
42 @:native("Lock")
43 private extern class NativeSemaphore {
44 function new(value:Int);
45 function acquire(blocking:Bool = true, ?timeout:Float):Bool;
46 function release():Void;
47 }
2121
2222 package sys.thread;
2323
24 import python.lib.threading.RLock;
25
2426 @:coreApi
2527 class Mutex {
26 final lock:NativeRLock;
28 final lock:RLock;
2729
2830 inline public function new():Void {
29 lock = new NativeRLock();
31 lock = new RLock();
3032 }
3133
3234 inline public function acquire():Void {
4143 lock.release();
4244 }
4345 }
44
45 @:pythonImport("threading", "RLock")
46 private extern class NativeRLock {
47 function new():Void;
48 function acquire(blocking:Bool):Bool;
49 function release():Void;
50 }
0 package sys.thread;
1
2 import python.lib.threading.Semaphore as NativeSemaphore;
3
4 @:coreApi
5 class Semaphore {
6 final semaphore:NativeSemaphore;
7
8 public function new(value:Int):Void {
9 this.semaphore = new NativeSemaphore(value);
10 }
11
12 public function acquire():Void {
13 semaphore.acquire();
14 }
15
16 public function tryAcquire(?timeout:Float):Bool {
17 return timeout == null ? semaphore.acquire(false) : semaphore.acquire(true, timeout);
18 }
19
20 public function release():Void {
21 semaphore.release();
22 }
23 }
2121
2222 package sys.thread;
2323
24 import python.lib.threading.Thread as NativeThread;
25 import python.lib.Threading;
26
2427 import haxe.ds.ObjectMap;
2528
2629 private typedef ThreadImpl = HxThread;
3235 return HxThread.current();
3336 }
3437
35 public static inline function create(callb:Void->Void):Thread {
36 return HxThread.create(callb, false);
38 public static inline function create(job:Void->Void):Thread {
39 return HxThread.create(job, false);
3740 }
3841
3942 public static inline function runWithEventLoop(job:()->Void):Void {
7780 static function __init__() {
7881 threads = new ObjectMap();
7982 threadsMutex = new Mutex();
80 mainThread = new HxThread(PyThreadingAPI.current_thread());
83 mainThread = new HxThread(Threading.current_thread());
8184 mainThread.events = new EventLoop();
8285 }
8386
9194
9295 public static function current():HxThread {
9396 threadsMutex.acquire();
94 var ct = PyThreadingAPI.current_thread();
95 if (ct == PyThreadingAPI.main_thread()) {
97 var ct = Threading.current_thread();
98 if (ct == Threading.main_thread()) {
9699 threadsMutex.release();
97100 return mainThread;
98101 }
120123 }
121124 dropThread(nt);
122125 }
123 nt = new NativeThread(null, wrappedCallB);
126 nt = new NativeThread({target:wrappedCallB});
124127 t = new HxThread(nt);
125128 if(withEventLoop)
126129 t.events = new EventLoop();
158161 return current().messages.pop(block);
159162 }
160163 }
161
162 @:pythonImport("threading", "Thread")
163 @:native("Thread")
164 private extern class NativeThread {
165 function new(group:Dynamic, target:Void->Void);
166 function start():Void;
167 }
168
169 @:pythonImport("threading")
170 @:native("threading")
171 private extern class PyThreadingAPI {
172 static function current_thread():NativeThread;
173 static function main_thread():NativeThread;
174 }
5656
5757 static function putenv(name:String, value:String):Void;
5858
59 /** Removes the value for the environment variable `name`.
60
61 When targeting python versions prior to 3.9, this function may not exist on some platforms.
62 **/
63 static function unsetenv(name:String):Void;
64
5965 static function chdir(path:String):Void;
6066
6167 static function unlink(path:String):Void;
2929 var wShowWindow:Int;
3030 }
3131
32 extern class CompletedProcess {
33 var args:EitherType<String, Array<String>>;
34 var returncode:Int;
35 var stdout:Null<EitherType<Bytes,String>>;
36 var stderr:Null<EitherType<Bytes,String>>;
37 function check_returncode():Void;
38 }
39
3240 @:pythonImport("subprocess")
3341 extern class Subprocess {
3442 static function STARTUPINFO():StartupInfo;
4856 static var STDOUT:Int;
4957
5058 static function call(args:EitherType<String, Array<String>>, ?kwArgs:python.KwArgs<Dynamic>):Int;
59 static function run(args:EitherType<String, Array<String>>, ?kwArgs:python.KwArgs<Dynamic>):CompletedProcess;
5160 }
8080 function getsockname():python.lib.socket.Address;
8181
8282 /**
83 Return the timeout for the socket or null if no timeout has been set.
84 **/
85 function gettimeout():Null<Float>;
86
87 /**
8388 Gives a timeout after which blocking socket operations (such as reading and writing) will abort and throw an exception.
8489 **/
8590 function settimeout(timeout:Float):Void;
9095 function waitForRead():Void;
9196
9297 /**
98 Return the current blocking mode of the socket.
99 **/
100 @:require(python_version >= 3.7)
101 function getblocking():Bool;
102
103 /**
93104 Change the blocking mode of the socket. A blocking socket is the default behavior. A non-blocking socket will abort blocking operations immediately by throwing a haxe.io.Error.Blocked value.
94105 **/
95106 function setblocking(b:Bool):Void;
96107
97108 /**
109 Return the current value of the sockopt as an Int or a Bytes buffer (if buflen is specified).
110 **/
111 function getsockopt(family:Int, option:Int):Int;
98112
113 /**
114 Change the value of the given socket option.
99115 **/
116 @:overload(function(family:Int, option:Int, value:Int):Void {})
100117 function setsockopt(family:Int, option:Int, value:Bool):Void;
101118
102119 function fileno():Int;
0 package python.lib.threading;
1
2 @:pythonImport("threading", "Condition")
3 extern class Condition {
4 function new(?lock:haxe.extern.EitherType<Lock, RLock>):Void;
5 function acquire(?blocking:Bool, ?timeout:Float):Bool;
6 function release():Void;
7 function wait(?timeout:Float):Bool;
8 function wait_for(predicate:()->Bool, ?timeout:Float):Bool;
9 function notify(n:Int = 1):Void;
10 function notify_all():Void;
11 }
0 package python.lib.threading;
1
2 @:noDoc
3 @:pythonImport("threading", "Semaphore")
4 extern class Semaphore {
5 function new(value:Int);
6 function acquire(blocking:Bool = true, ?timeout:Float):Bool;
7 function release(n:Int = 1):Void;
8 }
2424 import python.lib.Ssl;
2525 import python.lib.ssl.Purpose;
2626 import python.lib.socket.Socket as PSocket;
27 import python.lib.Socket in PSocketModule;
2728 import sys.net.Host;
2829
2930 class SslSocket extends sys.net.Socket {
30 var hostName:String;
31 var _timeout:Null<Float> = null;
32 var _blocking:Null<Bool> = null;
33 var _fastSend:Null<Bool> = null;
3134
32 override function __initSocket():Void {
35 function wrapSocketWithSslContext(hostName:String):Void {
3336 #if (python_version >= 3.4)
3437 var context = Ssl.create_default_context(Purpose.SERVER_AUTH);
3538 #else
4245 context.options |= Ssl.OP_NO_COMPRESSION;
4346 #end
4447 context.options |= Ssl.OP_NO_TLSv1 #if (python_version >= 3.4) | Ssl.OP_NO_TLSv1_1 #end; // python 3.4 | Ssl.OP_NO_TLSv1_1;
45 __s = new PSocket();
46 __s = context.wrap_socket(__s, false, true, true, this.hostName);
48 __s = context.wrap_socket(__s, false, true, true, hostName);
49 if (_timeout != null) {
50 super.setTimeout(_timeout);
51 }
52
53 if (_blocking != null) {
54 super.setBlocking(_blocking);
55 }
56
57 if (_fastSend != null) {
58 super.setFastSend(_fastSend);
59 }
60 __rebuildIoStreams();
4761 }
4862
4963 public override function connect(host:Host, port:Int):Void {
50 this.hostName = host.host;
64 wrapSocketWithSslContext(host.host);
5165 super.connect(host, port);
5266 }
5367
5468 public override function bind(host:Host, port:Int):Void {
5569 throw new haxe.exceptions.NotImplementedException();
5670 }
71
72 public override function setTimeout(timeout:Float):Void {
73 _timeout = timeout;
74 super.setTimeout(_timeout);
75 }
76
77 public override function setBlocking(b:Bool):Void {
78 _blocking = b;
79 super.setBlocking(_blocking);
80 }
81
82 public override function setFastSend(b:Bool):Void {
83 _fastSend = b;
84 super.setFastSend(_fastSend);
85 }
5786 }
3232 public var cnxTimeout:Float;
3333 public var responseHeaders:Map<String, String>;
3434
35 private var responseHeadersSameKey:Map<String, Array<String>>;
36
3537 var chunk_size:Null<Int>;
3638 var chunk_buf:haxe.io.Bytes;
3739 var file:{
103105 sock = new java.net.SslSocket();
104106 #elseif python
105107 sock = new python.net.SslSocket();
106 #elseif (!no_ssl && (hxssl || hl || cpp || (neko && !(macro || interp) || eval)))
108 #elseif (!no_ssl && (hxssl || hl || cpp || (neko && !(macro || interp) || eval) || (lua && !lua_vanilla)))
107109 sock = new sys.ssl.Socket();
108110 #elseif (neko || cpp)
109111 throw "Https is only supported with -lib hxssl";
251253 }
252254 }
253255
256 /**
257 Returns an array of values for a single response header or returns
258 null if no such header exists.
259 This method can be useful when you need to get a multiple headers with
260 the same name (e.g. `Set-Cookie`), that are unreachable via the
261 `responseHeaders` variable.
262 **/
263 public function getResponseHeaderValues(key:String):Null<Array<String>> {
264 var array = responseHeadersSameKey.get(key);
265 if (array == null) {
266 var singleValue = responseHeaders.get(key);
267 return (singleValue == null) ? null : [ singleValue ];
268 } else {
269 return array;
270 }
271 }
272
254273 function writeBody(body:Null<BytesOutput>, fileInput:Null<Input>, fileSize:Int, boundary:Null<String>, sock:Socket) {
255274 if (body != null) {
256275 var bytes = body.getBytes();
283302 var s = haxe.io.Bytes.alloc(4);
284303 sock.setTimeout(cnxTimeout);
285304 while (true) {
286 var p = sock.input.readBytes(s, 0, k);
287 while (p != k)
288 p += sock.input.readBytes(s, p, k - p);
305 var p = 0;
306 while (p != k) {
307 try {
308 p += sock.input.readBytes(s, p, k - p);
309 }
310 catch (e:haxe.io.Eof) { }
311 }
289312 b.addBytes(s, 0, k);
290313 switch (k) {
291314 case 1:
361384 var hname = a.shift();
362385 var hval = if (a.length == 1) a[0] else a.join(": ");
363386 hval = StringTools.ltrim(StringTools.rtrim(hval));
387
388 {
389 var previousValue = responseHeaders.get(hname);
390 if (previousValue != null) {
391 if (responseHeadersSameKey == null) {
392 responseHeadersSameKey = new haxe.ds.Map<String, Array<String>>();
393 }
394 var array = responseHeadersSameKey.get(hname);
395 if (array == null) {
396 array = new Array<String>();
397 array.push(previousValue);
398 responseHeadersSameKey.set(hname, array);
399 }
400 array.push(hval);
401 }
402 }
364403 responseHeaders.set(hname, hval);
365404 switch (hname.toLowerCase()) {
366405 case "content-length":
0 package sys.thread;
1
2 #if (!target.threaded)
3 #error "This class is not available on this target"
4 #end
5
6 /**
7 Creates a new condition variable.
8 Conditions variables can be used to block one or more threads at the same time,
9 until another thread modifies a shared variable (the condition)
10 and signals the condition variable.
11 **/
12 @:coreApi extern class Condition {
13 /**
14 Create a new condition variable.
15 A thread that waits on a newly created condition variable will block.
16 **/
17 function new():Void;
18
19 /**
20 Acquires the internal mutex.
21 **/
22 function acquire():Void;
23
24 /**
25 Tries to acquire the internal mutex.
26 @see `Mutex.tryAcquire`
27 **/
28 function tryAcquire():Bool;
29
30 /***
31 Releases the internal mutex.
32 **/
33 function release():Void;
34
35 /**
36 Atomically releases the mutex and blocks until the condition variable pointed is signaled by a call to
37 `signal` or to `broadcast`. When the calling thread becomes unblocked it
38 acquires the internal mutex.
39 The internal mutex should be locked before this function is called.
40 **/
41 function wait():Void;
42
43 /**
44 Unblocks one of the threads that are blocked on the
45 condition variable at the time of the call. If no threads are blocked
46 on the condition variable at the time of the call, the function does nothing.
47 **/
48 function signal():Void;
49
50 /**
51 Unblocks all of the threads that are blocked on the
52 condition variable at the time of the call. If no threads are blocked
53 on the condition variable at the time of the call, the function does
54 nothing.
55 **/
56 function broadcast():Void;
57 }
2727 final waitLock = new Lock();
2828 var promisedEventsCount = 0;
2929 var regularEvents:Null<RegularEvent>;
30
31 public function new():Void {}
30 var isMainThread:Bool;
31 static var CREATED : Bool;
32
33 public function new():Void {
34 isMainThread = !CREATED;
35 CREATED = true;
36 }
3237
3338 /**
3439 Schedule event for execution every `intervalMs` milliseconds in current loop.
9297 case null:
9398 case e: e.next = event.next;
9499 }
100 event.next = event.previous = null;
95101 mutex.release();
96102 }
97103
98104 /**
99105 Notify this loop about an upcoming event.
100 This makes the thread to stay alive and wait for as many events as many times
101 `.promise()` was called. These events should be added via `.runPromised()`
106 This makes the thread stay alive and wait for as many events as the number of
107 times `.promise()` was called. These events should be added via `.runPromised()`.
102108 **/
103109 public function promise():Void {
104110 mutex.acquire();
163169
164170 /**
165171 Execute all pending events.
166 Wait and execute as many events as many times `promiseEvent()` was called.
167 Runs until all repeating events are cancelled and no more events is expected.
172 Wait and execute as many events as the number of times `promise()` was called.
173 Runs until all repeating events are cancelled and no more events are expected.
168174
169175 Depending on a target platform this method may be non-reentrant. It must
170176 not be called from event callbacks.
220226
221227 // Run regular events
222228 for(i in 0...eventsToRunIdx) {
223 if(!regularsToRun[i].cancelled)
229 if(!regularsToRun[i].cancelled)
224230 regularsToRun[i].run();
225231 regularsToRun[i] = null;
226232 }
248254 oneTimersToRun[i] = null;
249255 }
250256
257 // run main events
258 if( isMainThread ) {
259 var next = @:privateAccess haxe.MainLoop.tick();
260 if( haxe.MainLoop.hasEvents() ) {
261 eventsToRunIdx++;
262 if( nextEventAt > next )
263 nextEventAt = next;
264 }
265 }
266
251267 // Some events were executed. They could add new events to run.
252268 if(eventsToRunIdx > 0) {
253269 nextEventAt = -2;
271287 this.nextRunTime = nextRunTime;
272288 this.interval = interval;
273289 }
274 }
290 }
0 package sys.thread;
1
2 #if (!target.threaded)
3 #error "This class is not available on this target"
4 #end
5 @:coreApi extern class Semaphore {
6 /**
7 Creates a new semaphore with an initial value.
8 **/
9 public function new(value:Int):Void;
10
11 /**
12 Locks the semaphore.
13 If the value of the semaphore is zero, then the thread will block until it is able to lock the semaphore.
14 If the value is non-zero, it is decreased by one.
15 **/
16 public function acquire():Void;
17
18 /**
19 Try to lock the semaphore.
20 If the value of the semaphore is zero, `false` is returned, else the value is increased.
21
22 If `timeout` is specified, this function will block until the thread is able to acquire the semaphore, or the timout expires.
23 `timeout` is in seconds.
24 **/
25 public function tryAcquire(?timeout:Float):Bool;
26
27 /**
28 Release the semaphore.
29 The value of the semaphore is increased by one.
30 **/
31 public function release():Void;
32 }
0 ; PHP.ini to use on Windows
1 extension=php_sqlite3.dll
2 extension=php_pdo_sqlite.dll
3 extension=php_sockets.dll
4 extension=php_mbstring.dll
33
44 "RunCi.hx" is the script used by our CIs to run all the test suites.
55
6 ### Local testing
6 ## Local testing
77
88 It is possible to run it in local machines too:
99
1010 1. Change to this directory.
11 2. Compile the script: `haxe RunCi.hxml`.
12 3. Define the test target by `export TEST=$TARGET` (or `set "TEST=$TARGET"` on Windows), where `$TARGET` should be a comma-seperated list of targets, e.g. `neko,macro`. Possible targets are `macro`, `neko`, `js`, `lua`, `php`, `cpp`, `flash9`, `java`, `cs`, `python`, and `third-party`. However, `flash9` and `third-party` are not likely to work on local machines (TODO).
13 4. Run it: `neko RunCi.n`.
11 2. Define the test target by `export TEST=$TARGET` (or `set "TEST=$TARGET"` on Windows), where `$TARGET` should be a comma-seperated list of targets, e.g. `neko,macro`. Possible targets are `macro`, `neko`, `js`, `lua`, `php`, `cpp`, `cppia`, `flash`, `java`, `jvm`, `cs`, `python`, and `hl`.
12 3. Run the script: `haxe RunCi.hxml`.
1413
1514 Note that the script will try to look for test dependencies and install them if they are not found. Look at the `getXXXDependencies` functions for the details.
1615
2626 changeDirectory(cwd);
2727 }
2828
29 final downloadPath = getDownloadPath();
30 if (!sys.FileSystem.exists(downloadPath))
31 sys.FileSystem.createDirectory(downloadPath);
32
2933 for (test in tests) {
3034 switch (systemName) {
3135 case "Windows":
3943 var echoServer = new sys.io.Process('nekotools', ['server', '-d', 'echoServer/www/', '-p', '20200']);
4044
4145 infoMsg('test $test');
42 var success = true;
4346 try {
4447 changeDirectory(unitDir);
45 haxelibInstallGit("haxe-utest", "utest", "master");
48 haxelibInstallGit("haxe-utest", "utest", "master", "--always");
4649
4750 var args = switch (ci) {
4851 case null:
7477 runci.targets.Jvm.run(args);
7578 case Cs:
7679 runci.targets.Cs.run(args);
77 case Flash9:
80 case Flash:
7881 runci.targets.Flash.run(args);
7982 case Hl:
8083 runci.targets.Hl.run(args);
8184 case t:
8285 throw new Exception("unknown target: " + t);
8386 }
84 } catch(f:Failure) {
85 success = false;
87 } catch(f:CommandFailure) {
88 failMsg('test ${test} failed');
89 Sys.exit(f.exitCode);
8690 }
8791
88 if (success) {
89 successMsg('test ${test} succeeded');
90 } else {
91 failMsg('test ${test} failed');
92 break;
93 }
92 successMsg('test ${test} succeeded');
9493
9594 echoServer.kill();
9695 echoServer.close();
9796 }
9897
99 if (success) {
100 deploy();
101 } else {
102 Sys.exit(1);
103 }
98 deploy();
10499 }
105100 }
00 // from vshaxe
1 import haxe.display.Position.Location;
12 import haxe.display.Position.Range;
3 import haxe.display.JsonModuleTypes;
24
35 enum abstract UnresolvedIdentifierSuggestion(Int) {
46 var UISImport;
57 var UISTypo;
68 }
79
10 enum abstract MissingFieldCauseKind<T>(String) {
11 final AbstractParent:MissingFieldCauseKind<{parent:JsonTypePathWithParams}>;
12 final ImplementedInterface:MissingFieldCauseKind<{parent:JsonTypePathWithParams}>;
13 final PropertyAccessor:MissingFieldCauseKind<{property:JsonClassField, isGetter:Bool}>;
14 final FieldAccess:MissingFieldCauseKind<{}>;
15 final FinalFields:MissingFieldCauseKind<{fields:Array<JsonClassField>}>;
16 }
17
18 typedef MissingFieldCause<T> = {
19 var kind:MissingFieldCauseKind<T>;
20 var args:T;
21 }
22
23 typedef MissingField = {
24 var field:JsonClassField;
25 var type:JsonType<Dynamic>;
26
27 /**
28 When implementing multiple interfaces, there can be field duplicates among them. This flag is only
29 true for the first such occurrence of a field, so that the "Implement all" code action doesn't end
30 up implementing the same field multiple times.
31 **/
32 var unique:Bool;
33 }
34
35 typedef MissingFieldDiagnostic = {
36 var fields:Array<MissingField>;
37 var cause:MissingFieldCause<Dynamic>;
38 }
39
40 typedef MissingFieldDiagnostics = {
41 var moduleType:JsonModuleType<Dynamic>;
42 var moduleFile:String;
43 var entries:Array<MissingFieldDiagnostic>;
44 }
45
846 enum abstract DiagnosticKind<T>(Int) from Int to Int {
9 var DKUnusedImport:DiagnosticKind<Void>;
10 var DKUnresolvedIdentifier:DiagnosticKind<Array<{kind:UnresolvedIdentifierSuggestion, name:String}>>;
11 var DKCompilerError:DiagnosticKind<String>;
12 var DKRemovableCode:DiagnosticKind<{description:String, range:Range}>;
13 var DKParserError:DiagnosticKind<String>;
47 final DKUnusedImport:DiagnosticKind<Void>;
48 final DKUnresolvedIdentifier:DiagnosticKind<Array<{kind:UnresolvedIdentifierSuggestion, name:String}>>;
49 final DKCompilerError:DiagnosticKind<String>;
50 final DKRemovableCode:DiagnosticKind<{description:String, range:Range}>;
51 final DKParserError:DiagnosticKind<String>;
52 final DeprecationWarning:DiagnosticKind<String>;
53 final InactiveBlock:DiagnosticKind<Void>;
54 final MissingFields:DiagnosticKind<MissingFieldDiagnostics>;
1455 }
1556
1657 enum abstract DiagnosticSeverity(Int) {
2566 var range:Range;
2667 var severity:DiagnosticSeverity;
2768 var args:T;
69 var relatedInformation:Array<DiagnosticRelatedInformation>;
2870 }
71
72 typedef DiagnosticRelatedInformation = {
73 var location:Location;
74 var message:String;
75 var depth:Int;
76 }
4343 eq(false, hasField(fields, "instanceField", "() -> Void"));
4444 eq(true, hasField(fields, "staticField", "() -> Void"));
4545 }
46
47 /**
48 abstract MyAbstract(String) {
49 public function new() this = "foo";
50
51 public function instanceField():Void {
52 {-1-}
53 }
54 static public function staticField():Void {
55 {-2-}
56 }
57 public function instanceField2():Void {
58 ab{-3-}stract;
59 }
60 }
61 abstract AbGeneric<T>(T) {
62 public function new(a:T) this = a;
63 public function foo() {
64 return ab{-4-}stract.bar();
65 }
66 public function bar() {
67 return th{-5-}is;
68 }
69 }
70 **/
71 function test3():Void {
72 final fields = toplevel(pos(1));
73 eq(true, hasToplevel(fields, "literal", "abstract"));
74 final fields = toplevel(pos(2));
75 eq(false, hasToplevel(fields, "literal", "abstract"));
76 // TODO: improve display hints
77 eq("cases.MyAbstract", type(pos(3)));
78 eq("cases.AbGeneric<cases.AbGeneric.T>", type(pos(4)));
79 eq("cases.AbGeneric.T", type(pos(5)));
80 }
4681 }
119119 function main() {}
120120 **/
121121 function testModuleLevelFields() {
122 checkDocumentSymbols([
123 {name: "main", kind: Method, containerName: null},
124 ], ctx.documentSymbols());
122 checkDocumentSymbols([{name: "main", kind: Method, containerName: null},], ctx.documentSymbols());
123 }
124
125 /*// Test
126 function main() {}
127 */
128 function testLeadingLineComment() {
129 checkDocumentSymbols([{name: "main", kind: Method, containerName: null},], ctx.documentSymbols());
125130 }
126131
127132 function checkDocumentSymbols(expected:Array<ModuleSymbolEntry>, actual:Array<ModuleSymbolEntry>, ?pos:haxe.PosInfos) {
0 package cases;
1
2 class Issue10004 extends DisplayTestCase {
3 /**
4 using Issue10004.Foo;
5
6 class Main {
7 static function main() {
8 0.{-1-}
9 }
10 }
11
12 class Foo {
13 public static overload extern inline function foo():Void {}
14
15 public static overload extern inline function foo(i:Int):Void {}
16 }
17 **/
18 function testGama() {
19 var fields = fields(pos(1));
20 eq(true, hasField(fields, "foo", "() -> Void"));
21 }
22
23 /**
24 using Issue10004.Tools;
25
26 class Tools {
27 public static extern inline overload function getOrZero<K>(map:Map<K,Int>, key:K):Int {
28 var value = map.get(key);
29 return if (value != null) value else 0;
30 }
31
32 public static extern inline overload function getOrZero<K>(map:Map<K,Float>, key:K):Float {
33 var value = map.get(key);
34 return if (value != null) value else 0.0;
35 }
36
37 }
38
39 function main() {
40 var m = ["a" => 1.1, "b" => 2.3];
41 m.{-1-}
42 }
43 **/
44 function testNotGama() {
45 var fields = fields(pos(1));
46 eq(true, hasField(fields, "getOrZero", "(key : String) -> Float"));
47 }
48 }
0 package cases;
1
2 class Issue10194 extends DisplayTestCase {
3 /**
4 function f(a:Int, b:Int) {}
5
6 function main() {
7 var v = 10; // reported as "unused variable"
8 f({-1-}""{-2-}, v);
9 }
10 **/
11 function test() {
12 arrayEq([
13 {
14 kind: DKCompilerError,
15 severity: Error,
16 range: diagnosticsRange(pos(1), pos(2)),
17 relatedInformation: [],
18 args: "String should be Int\nFor function argument 'a'"
19 }
20 ], diagnostics());
21 }
22 }
0 package cases;
1
2 class Issue10412 extends DisplayTestCase {
3 /**
4 class Main {
5 static function main() {
6 new Game();
7 }
8 }
9
10 class Scene {
11 public var scale:Float;
12 }
13
14 class Game extends Scene {
15
16 public function new():Void {}
17
18 function itWorks():Void {
19 // There is completion:
20 // Res.|.bar;
21 Res.foo.bar;
22 }
23
24 function itDoesNot():Void {
25 // There is not:
26 // Res.|.bar;
27 Res.{-1-}.bar;
28
29 // because of `final scale`
30 // changing `final scale` to other name fixes it
31 var strangeBust = 5 / 10;
32 final scale = 5 / 10;
33 // if you comment out `strangeBust` it will also work,
34 // but not if you change `final scale` to `var scale`
35 }
36 }
37
38 class Res {
39 public static var foo = {bar: "hello"};
40 }
41 **/
42 function testOriginal() {
43 var fields = fields(pos(1));
44 eq(true, hasField(fields, "foo", "{ bar : String }"));
45 }
46
47 /**
48 class Base {
49 final x:String;
50 }
51
52 class Child extends Base {
53 final x:String;
54 function test() {
55 "".{-1-};
56 }
57 }
58 **/
59 function testActualIssue() {
60 var fields = fields(pos(1));
61 eq(true, hasField(fields, "length", "Int"));
62 }
63
64 /**
65 class Test {
66 var a:Int;
67 function test() {
68 this.{-1-}.resume;
69
70 final x:String;
71 }
72 **/
73 function testFinalResume() {
74 var fields = fields(pos(1));
75 eq(true, hasField(fields, "x", "String"));
76 }
77 }
0 package cases;
1
2 class Issue10429 extends DisplayTestCase {
3 /**
4 import haxe.macro.Expr;
5
6 typedef ArgType = {
7 var f:String;
8 }
9
10 class Main {
11 public static function main() {
12 f{-1-}oo({-2-});
13 {-3-}
14 }
15
16 static macro function foo(s:String, e:ExprOf<String>, o:ArgType) {
17 return macro {};
18 }
19 }
20 **/
21 function test() {
22 var expectedType = "(s : String, e : String, o : cases.ArgType) -> haxe.macro.Expr";
23 var fields = toplevel(pos(1));
24 eq(true, hasToplevel(fields, "static", "foo", expectedType));
25 eq(expectedType, type(pos(1)));
26 sigEq(0, [["s:String", "e:String", "o:cases.ArgType"]], signature(pos(2)));
27 }
28 }
0 package cases;
1
2 class Issue10633 extends DisplayTestCase {
3 /**
4 enum Value {
5 Multiple(a:Array<String>);
6 }
7
8 class Main {
9 var values(get, set):Array<String>;
10
11 var whatever:Value;
12
13 function get_values() {
14 return switch (whatever) {
15 case Multiple(values): values;
16 default: [];
17 }
18 }
19
20 function set_values(a:Array<String>) {
21 return [];
22 }
23
24 static function main() {}
25 }
26 **/
27 function test() {
28 arrayEq([], diagnostics());
29 }
30 }
0 package cases;
1
2 class Issue10634 extends DisplayTestCase {
3 /**
4 function test(?x:String, ?e:haxe.macro.Expr.ExprDef) {}
5
6 function main() {
7 test(EBreak);
8 }
9 **/
10 // function test() {
11 // arrayEq([], diagnostics());
12 // }
13 }
0 package cases;
1
2 class Issue10691 extends DisplayTestCase {
3 /**
4 class Main {
5 static public function main() {
6 function hello() {}
7 function {-1-}
8 }
9 }
10 **/
11 function test1() {
12 eq(true, noCompletionPoint(toplevel.bind((pos(1)))));
13 }
14
15 /**
16 class Main {
17 static public function main() {
18 function hello() {}
19 function a{-1-}
20 }
21 }
22 **/
23 function test2() {
24 eq(true, noCompletionPoint(toplevel.bind((pos(1)))));
25 }
26
27 /**
28 class Main {
29 static public function main() {
30 function hello() {}
31 function a{-1-}b
32 }
33 }
34 **/
35 function test3() {
36 eq(true, noCompletionPoint(toplevel.bind((pos(1)))));
37 }
38
39 /**
40 class Main {
41 static public function main() {
42 function hello() {}
43 function a{-1-}b()
44 }
45 }
46 **/
47 function test4() {
48 eq(true, noCompletionPoint(toplevel.bind((pos(1)))));
49 }
50
51 /**
52 class Main {
53 static public function main() {
54 function hello() {}
55 function ab{-1-}()
56 }
57 }
58 **/
59 function test5() {
60 eq(true, noCompletionPoint(toplevel.bind((pos(1)))));
61 }
62 }
0 package cases;
1
2 class Issue10704 extends DisplayTestCase {
3 /**
4 import misc.issue10704.Statics.*;
5 class Main {
6 static function main() {
7 foo{-1-}
8 }
9 }
10 **/
11 function test() {
12 eq(true, hasToplevel(toplevel(pos(1)), "static", "fooPublic"));
13 eq(false, hasToplevel(toplevel(pos(1)), "static", "fooNoCompletion"));
14 eq(false, hasToplevel(toplevel(pos(1)), "static", "fooPrivate"));
15 }
16 }
0 package cases;
1
2 using Lambda;
3
4 class Issue10713 extends DisplayTestCase {
5 /**
6 class Main {
7 static function main() {
8 loadEverything(() -> {
9 {-1-}foo{-2-} = 1;
10 });
11 }
12
13 static function loadEverything(cb:() -> Void, ?what):Void {}
14 }
15 **/
16 function test() {
17 var d = diagnostics();
18 var range = diagnosticsRange(pos(1), pos(2));
19 utest.Assert.isTrue(d.exists(d -> d.kind == MissingFields && utest.Assert.same(d.range, range)));
20 }
21 }
0 package cases;
1
2 class Issue5172 extends DisplayTestCase {
3 /**
4 class Main {
5 static function main() {
6 for ({-3-}i{-1-} in 0...10) {
7 {-4-}i{-2-};
8 }
9 }
10 }
11 **/
12 function test() {
13 eq("Int", type(pos(1)));
14 eq("Int", type(pos(2)));
15 eq(range(3, 1), position(pos(1)));
16 arrayEq([range(4, 2)], usage(pos(1)));
17 }
18 }
+0
-19
tests/display/src/cases/Issue5172.hx.disabled less more
0 package cases;
1
2 class Issue5172 extends DisplayTestCase {
3 /**
4 class Main {
5 static function main() {
6 for ({-3-}i{-1-} in 0...10) {
7 {-4-}i{-2-};
8 }
9 }
10 }
11 **/
12 function test() {
13 eq("Int", type(pos(1)));
14 eq("Int", type(pos(2)));
15 eq(range(3, 1), position(pos(1)));
16 arrayEq([range(4, 2)], usage(pos(1)));
17 }
18 }
66 class Main {
77 static function main() {
88 var ib:Array<Int>;
9 ib[0] = 0; ib[1] = 1; {-7-}ib[2]{-8-}
9 ib[0] = 0; ib[1] = 1; ib[2]
1010 {-5-}trace{-6-}("test");
1111 }
1212 }
2020 // args: []
2121 // },
2222 {
23 kind: DKCompilerError,
24 range: diagnosticsRange(pos(3), pos(4)),
25 severity: Error,
26 args: "Type not found : InvalidType"
27 },
28 {
2923 kind: DKParserError,
3024 range: diagnosticsRange(pos(5), pos(6)),
3125 severity: Error,
26 relatedInformation: [],
3227 args: "Missing ;"
3328 },
3429 {
3530 kind: DKCompilerError,
36 range: diagnosticsRange(pos(7), pos(8)),
37 severity: Warning,
38 args: "This code has no effect"
31 range: diagnosticsRange(pos(3), pos(4)),
32 severity: Error,
33 relatedInformation: [],
34 args: "Type not found : InvalidType"
3935 }
4036 ];
4137 arrayEq(expected, diagnostics());
66 class Main {
77 public static function main() {
88 switch (null:ExprDef) {
9 case EConst(CInt({-1-}v)):
9 case EConst(CIdent({-1-}s)):
1010 case _:
1111 }
1212 }
1313 }
1414 **/
1515 function test() {
16 sigEq(0, [["v:String"]], signature(pos(1)));
16 sigEq(0, [["s:String"]], signature(pos(1)));
1717 }
1818 }
1818 kind: DKUnusedImport,
1919 severity: Warning,
2020 range: diagnosticsRange(pos(1), pos(2)),
21 relatedInformation: [],
2122 args: []
2223 }
2324 ], diagnostics());
1111 kind: DKParserError,
1212 range: diagnosticsRange(pos(1), pos(2)),
1313 severity: Error,
14 relatedInformation: [],
1415 args: "Expected type parameter"
1516 }
1617 ], diagnostics());
3939 kind: DKParserError,
4040 range: diagnosticsRange(pos(1), pos(2)),
4141 severity: Error,
42 relatedInformation: [],
4243 args: message
4344 }
4445 ], diagnostics());
1111 kind: DKParserError,
1212 range: diagnosticsRange(pos(1), pos(2)),
1313 severity: Error,
14 relatedInformation: [],
1415 args: "Unexpected fuction"
1516 }
1617 ], diagnostics());
99 kind: DKParserError,
1010 range: diagnosticsRange(pos(1), pos(2)),
1111 severity: Error,
12 relatedInformation: [],
1213 args: "Unexpected {"
1314 }
1415 ], diagnostics());
1313 kind: DKParserError,
1414 range: diagnosticsRange(pos(1), pos(1)),
1515 severity: Error,
16 relatedInformation: [],
1617 args: "Unterminated string"
1718 }
1819 ], diagnostics());
1313 kind: DKParserError,
1414 severity: Error,
1515 range: diagnosticsRange(pos(3), pos(4)),
16 relatedInformation: [],
1617 args: "Missing ;"
17 },
18 {
19 kind: DKCompilerError,
20 severity: Warning,
21 range: diagnosticsRange(pos(3), pos(4)),
22 args: "This code has no effect"
23 },
24 {
25 kind: DKCompilerError,
26 severity: Warning,
27 range: diagnosticsRange(pos(1), pos(2)),
28 args: "This code has no effect"
2918 }
3019 ], diagnostics());
3120 }
1313 kind: DKParserError,
1414 severity: Error,
1515 range: diagnosticsRange(pos(1), pos(2)),
16 relatedInformation: [],
1617 args: "Unexpected fun"
1718 }
1819 ], diagnostics());
99 kind: DKParserError,
1010 severity: Error,
1111 range: diagnosticsRange(pos(1), pos(2)),
12 relatedInformation: [],
1213 args: "Expected { or to or from"
1314 }
1415 ], diagnostics());
2324 kind: DKParserError,
2425 severity: Error,
2526 range: diagnosticsRange(pos(1), pos(2)),
27 relatedInformation: [],
2628 args: "Expected extends or implements or {"
2729 }
2830 ], diagnostics());
99 kind: DKParserError,
1010 severity: Error,
1111 range: diagnosticsRange(pos(1), pos(2)),
12 relatedInformation: [],
1213 args: "Unexpected open"
1314 }
1415 ], diagnostics());
2324 kind: DKParserError,
2425 severity: Error,
2526 range: diagnosticsRange(pos(1), pos(2)),
27 relatedInformation: [],
2628 args: "Unexpected clas"
2729 }
2830 ], diagnostics());
2121 kind: DKCompilerError,
2222 severity: Error,
2323 range: diagnosticsRange(pos(1), pos(2)),
24 relatedInformation: [],
2425 args: "Void should be Bool"
2526 }
2627 ], diagnostics());
4748 kind: DKCompilerError,
4849 severity: Error,
4950 range: diagnosticsRange(pos(1), pos(2)),
51 relatedInformation: [],
5052 args: "Bool should be Void"
5153 }
5254 ], diagnostics());
1313 kind: DKParserError,
1414 severity: Error,
1515 range: diagnosticsRange(pos(1), pos(2)),
16 args: "Unexpected class"
16 relatedInformation: [],
17 args: 'Unexpected keyword "class"'
1718 }
1819 ], diagnostics());
1920 }
3132 kind: DKParserError,
3233 severity: Error,
3334 range: diagnosticsRange(pos(1), pos(2)),
35 relatedInformation: [],
3436 args: "Unexpected }"
3537 }
3638 ], diagnostics());
108108 eq("Marks a class or class field as generic so each type parameter combination generates its own type/field.", metadataDoc(pos(2)));
109109 eq("Marks a class or class field as generic so each type parameter combination generates its own type/field.", metadataDoc(pos(3)));
110110 }
111
112 /**
113 #if !macro
114 @:build(cases.Metadata.Main.build())
115 #end
116 class Main {
117 #if !macro
118 @{-1-}
119 static var dummy = 123;
120
121 static function main() {}
122 #else
123 static function build() {
124 haxe.macro.Context.getBuildFields();
125 return null;
126 }
127 #end
128 }
129 **/
130 function test9853() {
131 eq(true, hasPath(fields(pos(1)), "@:generic"));
132 }
133
134 /**
135 @{-1-}
136 class Main {
137 static function main() {}
138 }
139 @{-2-}
140 class Test {}
141
142 **/
143 function test7864() {
144 eq(true, hasPath(fields(pos(1)), "@:generic"));
145 eq(true, hasPath(fields(pos(2)), "@:generic"));
146 }
147
148 /**
149 function main() {
150 var @{-1-}
151 }
152 **/
153 function test9639_1() {
154 eq(true, hasPath(fields(pos(1)), "@:generic"));
155 }
156
157 /**
158 function main() {
159 var @{-1-} local
160 }
161 **/
162 function test9639_2() {
163 eq(true, hasPath(fields(pos(1)), "@:generic"));
164 }
165
166 /**
167 function main() {
168 var @{-1-} local : Type
169 }
170 **/
171 function test9639_3() {
172 eq(true, hasPath(fields(pos(1)), "@:generic"));
173 }
174
175 /**
176 function main() {
177 var @{-1-} local =
178 }
179 **/
180 function test9639_4() {
181 eq(true, hasPath(fields(pos(1)), "@:generic"));
182 }
183
184 /**
185 function main() {
186 var @{-1-} local = 10
187 }
188 **/
189 function test9639_5() {
190 eq(true, hasPath(fields(pos(1)), "@:generic"));
191 }
111192 }
231231 sigEq(4, sig, signature(pos(14)));
232232 sigEq(4, sig, signature(pos(15)));
233233 }
234
235 /**
236 class NotMain {
237 overload public function new(s:String) {}
238 overload function new(i:Int) {}
239 }
240
241 class Main {
242 static function main() {
243 new NotMain({-1-}
244 }
245 }
246 **/
247 function testCtorVisibility() {
248 sigEq(0, [["s:String"]], signature(pos(1)));
249 }
250
251 /**
252 class NotMain {
253 overload public function new() {}
254
255 overload public function f(s:String) {}
256 overload function f(i:Int) {}
257 }
258
259 class Main {
260 static function main() {
261 new NotMain().f({-1-})
262 }
263 }
264 **/
265 function testMemberVisibility() {
266 sigEq(0, [["s:String"]], signature(pos(1)));
267 }
268
269 /**
270 class NotMain {
271 overload static public function f(s:String) {}
272 overload static function f(i:Int) {}
273 }
274
275 class Main {
276 static function main() {
277 NotMain.f({-1-})
278 }
279 }
280 **/
281 function testStaticVisibility() {
282 sigEq(0, [["s:String"]], signature(pos(1)));
283 }
234284 }
3131 test({{-1-}
3232 }
3333
34 static function test(o:{a:Float, b:String}) { }
34 public static function test(o:{a:Float, b:String}) { }
3535 }
3636 **/
3737 function testStructureCompletion4() {
4545 test(0, {{-1-}
4646 }
4747
48 static function test(x, o:{a:Float, b:String}) { }
48 public static function test(x, o:{a:Float, b:String}) { }
4949 }
5050 **/
5151 function testStructureCompletion5() {
167167 var field2:String;
168168 }
169169 class Main {
170 static function test1():Foo return { f{-1-}ie{-2-}
171 static function test2():Foo return { f{-3-}ie{-4-}:
172 static function test3():Foo return { f{-5-}ie{-6-} }
173 static function test4():Foo return { f{-7-}ie{-8-} : }
174 static function test5():Foo return { f{-9-}ie{-10-} : null }
175 static function test6():Foo return { f{-11-}ie{-12-} : null
170 public static function test1():Foo return { f{-1-}ie{-2-}
171 public static function test2():Foo return { f{-3-}ie{-4-}:
172 public static function test3():Foo return { f{-5-}ie{-6-} }
173 public static function test4():Foo return { f{-7-}ie{-8-} : }
174 public static function test5():Foo return { f{-9-}ie{-10-} : null }
175 public static function test6():Foo return { f{-11-}ie{-12-} : null
176176 **/
177177 function testStructureVsToplevel9() {
178178 for (i in 1...13) {
0 package misc.issue10704;
1
2 class Statics {
3 public static final fooPublic = 0;
4
5 @:noCompletion
6 public static final fooNoCompletion = 0;
7
8 static final fooPrivate = 0;
9 }
0 -lib dox
1 -lib hxtemplo
2 -lib hxparse
3 -lib hxargs
4 -lib markdown
5 -dce no
6 -main dox.Dox
7 -cpp cpp
00 <?xml version="1.0"?>
1 <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
1 <!DOCTYPE cross-domain-policy SYSTEM "https://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
22 <cross-domain-policy>
3 <site-control permitted-cross-domain-policies="master-only" />
4 <allow-access-from domain="*" to-ports="*" secure="false"/>
3 <site-control permitted-cross-domain-policies="master-only"/>
4 <allow-access-from domain="*" to-ports="*"/>
55 <allow-http-request-headers-from domain="*" headers="*"/>
6 </cross-domain-policy>
6 </cross-domain-policy>
00 -p src
1 #-D MISC_TEST_FILTER=9619
1 #-D MISC_TEST_FILTER=4270
22 -main Main
33 --interp
0 import sys.FileSystem;
1
2 function deleteDirectory(path:String) {
3 if (!FileSystem.isDirectory(path))
4 return FileSystem.deleteFile(path);
5
6 for (item in FileSystem.readDirectory(path))
7 deleteDirectory('$path/$item');
8
9 FileSystem.deleteDirectory(path);
10 }
11
12 function main() {
13 final definePairs = sys.io.File.getContent("out/Options.txt").split("\n");
14
15 for (definePair in definePairs)
16 for (index in 0...definePair.length) {
17 final char = definePair.charAt(index);
18 if (char == "=") break;
19 if (char == "-"){
20 deleteDirectory("out");
21 Sys.stderr().writeString("Generated `Options.txt` contains raw version of define flag: " + definePair + "\n");
22 Sys.exit(1);
23 }
24 }
25 deleteDirectory("out");
26 Sys.exit(0);
27 }
0 # test Options.txt defines
1 --main CheckOptionsTxt
2 --cpp out
3 -D no-compilation
4 --cmd haxe --run CheckOptionsTxt
0 -cp ../src
1 --run Main
4747 trace(String.fromCharCode("A".code + count++));
4848 if( count == 5 ) event.stop();
4949 });
50 #if sys
51 Sys.sleep(3);
52 #end
5350 });
5451 }
5552
56 }
53 }
0 --main Main
1 --dce full
2 -cpp cpp
0 Main.hx:18: BEFORE1
1 Main.hx:35: BEFORE2
2 Main.hx:26: T0
3 Main.hx:48: A
4 Main.hx:7: 0
5 Main.hx:48: B
6 Main.hx:7: 1
7 Main.hx:48: C
8 Main.hx:7: 2
9 Main.hx:48: D
10 Main.hx:7: 3
11 Main.hx:48: E
12 Main.hx:7: 4
13 Main.hx:7: 5
14 Main.hx:7: 6
15 Main.hx:7: 7
16 Main.hx:7: 8
17 Main.hx:7: 9
18 Main.hx:10: false
19 Main.hx:26: T1
20 Main.hx:26: T2
21 Main.hx:26: T3
22 Main.hx:26: T4
0 --main Main
1 --dce full
2 -hl eventLoop.hl
0 Main.hx:18: BEFORE1
1 Main.hx:35: BEFORE2
2 Main.hx:26: T0
3 Main.hx:48: A
4 Main.hx:7: 0
5 Main.hx:48: B
6 Main.hx:7: 1
7 Main.hx:48: C
8 Main.hx:7: 2
9 Main.hx:48: D
10 Main.hx:7: 3
11 Main.hx:48: E
12 Main.hx:7: 4
13 Main.hx:7: 5
14 Main.hx:7: 6
15 Main.hx:7: 7
16 Main.hx:7: 8
17 Main.hx:7: 9
18 Main.hx:10: false
19 Main.hx:26: T1
20 Main.hx:26: T2
21 Main.hx:26: T3
22 Main.hx:26: T4
0 import sys.FileSystem;
1
2 function deleteDirectory(path:String) {
3 if (!FileSystem.isDirectory(path))
4 return FileSystem.deleteFile(path);
5
6 for (item in FileSystem.readDirectory(path))
7 deleteDirectory('$path/$item');
8
9 FileSystem.deleteDirectory(path);
10 }
11
12 function main() {
13 final json = haxe.Json.parse(sys.io.File.getContent("out/hlc.json"));
14
15 final defines:haxe.DynamicAccess<String> = json.defines;
16
17 final success = Lambda.foreach(defines.keys(), function(define:String) {
18 if (!StringTools.contains(define, "-"))
19 return true;
20
21 Sys.stderr().writeString("Generated `hlc.json` contains raw version of define flag: " + define + "\n");
22 return false;
23 });
24
25 deleteDirectory("out");
26 Sys.exit(if (success) 0 else 1);
27 }
0 # test hlc.json defines
1 --main CheckJson
2 --hl out/main.c
3 -D no-compilation
4 --cmd haxe --run CheckJson
0 import sys.FileSystem;
1
2 final FILE = "out/main.c";
3
4 function deleteDirectory(path:String) {
5 if (!FileSystem.isDirectory(path))
6 return FileSystem.deleteFile(path);
7
8 for (item in FileSystem.readDirectory(path))
9 deleteDirectory('$path/$item');
10
11 FileSystem.deleteDirectory(path);
12 }
13
14 function main() {
15 final args = Sys.args();
16
17 final code =
18 try {
19 switch args {
20 case [""]:
21 checkForEmptySourceHeader(FILE);
22 case [expected]:
23 checkSourceHeader(FILE, expected);
24 case _:
25 throw "Incorrect number of arguments to script.";
26 }
27 0;
28 } catch (e){
29 Sys.stderr().writeString(e + "\n");
30 1;
31 }
32
33 deleteDirectory("out");
34 Sys.exit(code);
35 }
36
37 function checkForEmptySourceHeader(path:String) {
38 final content = getCSourceContent(path);
39
40 if (StringTools.startsWith(content, "// "))
41 throw "File has a source header when none was expected: " + content.split("\n")[0];
42 }
43
44 function checkSourceHeader(path:String, expected:String) {
45 final content = getCSourceContent(path);
46
47 if (!StringTools.startsWith(content, "// " + expected))
48 throw "File source header does not start with expected: // " + expected +
49 "\nSource header: " + content.split("\n")[0];
50 }
51
52 function getCSourceContent(path:String) {
53 // have to skip the BOM character
54 return sys.io.File.getContent(path).substr(1);
55 }
0 --main CheckSourceHeader
1 --hl out/main.c
2 -D no-compilation
3 -D source-header=custom
4 --cmd haxe --run CheckSourceHeader custom
0 --main CheckSourceHeader
1 --hl out/main.c
2 -D no-compilation
3
4 --cmd haxe --run CheckSourceHeader "Generated by HLC"
0 --main CheckSourceHeader
1 --hl out/main.c
2 -D no-compilation
3 -D source-header=
4 --cmd haxe --run CheckSourceHeader ""
0 -cp ../src
1 --run Main
tests/misc/java/projects/Issue10280/jvm.jar less more
Binary diff not shown
0 @:strict(jvm.annotation.ClassReflectionInformation(hasSuperClass = false))
1 class Main {
2 static function main() {
3
4 }
5 }
0 -main Main
1 --jvm whatever.jar
2 --no-output
0 Main.hx:1: characters 52-73 : Object declaration expected
0 interface MathOperation {
1 function perform(a:Int, b:Int):Int;
2 }
3
4 class Ops {
5 static public final add:MathOperation = (a, b) -> a + b;
6 static public final subtract:MathOperation = (a, b) -> a - b;
7
8 static public function performMathOperation(operation:MathOperation) {
9 return operation.perform(8, 4);
10 }
11 }
12
13 class Main {
14 static function main() {
15 var result = Ops.performMathOperation(Ops.add);
16 trace('Add: ${result}');
17
18 result = Ops.performMathOperation(Ops.subtract);
19 trace('Subtract: ${result}');
20
21 result = Ops.performMathOperation(multiply);
22 trace('Multiply: ${result}');
23
24 result = Ops.performMathOperation(function(a, b):Int {
25 return Std.int(a / b);
26 });
27 trace('Divide: ${result}');
28 }
29
30 static function multiply(a, b):Int {
31 return a * b;
32 }
33 }
0 --main Main
1 --jvm bin/run.jar
2 --cmd java -jar bin/run.jar
0 Main.hx:17: Add: 12
1 Main.hx:20: Subtract: 4
2 Main.hx:23: Multiply: 32
3 Main.hx:28: Divide: 2
0 import pack.ItemGroupEvents;
1
2 function test(m:ItemGroupEvents_ModifyEntries) {
3 m.modifyEntries(12);
4 }
5
6 function main() {
7 test(i -> trace(12));
8 }
0 function main() {
1 Sys.command("javac", ["pack/ItemGroupEvents.java", "-g"]);
2 Sys.command("jar", ["cf", "test.jar", "pack/ItemGroupEvents.class", "pack/ItemGroupEvents$ModifyEntries.class"]);
3 }
0 --main Setup
1 --interp
2
3 --next
4
5 --main Main
6 --java-lib test.jar
7 --jvm run.jar
8
9 --next
10
11 --cmd java -jar run.jar
0 package pack;
1
2 public final class ItemGroupEvents {
3 public interface ModifyEntries {
4 void modifyEntries(int entries);
5 }
6 }
0 final FILE = "main.js";
1
2 function main() {
3 final args = Sys.args();
4
5 switch args {
6 case [""]:
7 checkForEmptySourceHeader(FILE);
8 case [expected]:
9 checkSourceHeader(FILE, expected);
10 case _:
11 Tools.exitWithError("Incorrect number of arguments to script.");
12 }
13
14 Tools.exit(0);
15 }
16
17 function checkForEmptySourceHeader(path:String) {
18 final content = getJsSourceContent(path);
19
20 if (StringTools.startsWith(content, "// "))
21 Tools.exitWithError("File has a source header when none was expected: " + content.split("\n")[0]);
22 }
23
24 function checkSourceHeader(path:String, expected:String) {
25 final content = getJsSourceContent(path);
26
27 if (!StringTools.startsWith(content, "// " + expected))
28 Tools.exitWithError("File source header does not start with expected: // " + expected +
29 "\nSource header: " + content.split("\n")[0]);
30 }
31
32 function getJsSourceContent(path:String) {
33 return sys.io.File.getContent(path);
34 }
0 function main() {
1 js.Browser.console.log("Hello, World!");
2 }
0 import sys.FileSystem;
1
2 function exit(code:Int) {
3 FileSystem.deleteFile("main.js");
4 Sys.exit(code);
5 }
6
7 function exitWithError(msg:String, code:Int = 1) {
8 FileSystem.deleteFile("main.js");
9 Sys.stderr().writeString(msg + "\n");
10 Sys.exit(code);
11 }
0 --main Main
1 --js main.js
2 -D source-header=custom
3 --cmd haxe --run CheckSourceHeader custom
0 --main Main
1 --js main.js
2 -D source_header=custom
3 --cmd haxe --run CheckSourceHeader custom
0 # test source headers
1 --main Main
2 --js main.js
3 --cmd haxe --run CheckSourceHeader "Generated by Haxe"
0 --main Main
1 --js main.js
2 -D source-header=
3 --cmd haxe --run CheckSourceHeader ""
0 --main Main
1 --js main.js
2 -D source_header=
3 --cmd haxe --run CheckSourceHeader ""
0 -cp ../src
1 --run Main
0 class HaxeException {
1 static function main() {
2 throw "Exception thrown from Haxe";
3 }
4 }
0 class NativeError {
1 static function main() {
2 final object:Dynamic = null;
3 trace(object.value);
4 }
5 }
0 using StringTools;
1
2 function isLua5_1() {
3 final proc = new sys.io.Process("lua", ["-v"]);
4 final out = proc.stderr.readLine();
5 proc.close();
6 return out.startsWith("Lua 5.1.");
7 }
8
9 function matchesExpectedMessage(actual:String) {
10 // lua 5.1 doesn't print custom error objects
11 if (actual == "(error object is not a string)") {
12 return true;
13 }
14 return new EReg(Sys.args()[1], "").match(actual);
15 }
16
17 function main() {
18 final proc = new sys.io.Process("lua", [Sys.args()[0]]);
19
20 // ignore "lua: "
21 final exceptionMessage = proc.stderr.readLine().substr(5);
22
23 final hasExpectedMessage = matchesExpectedMessage(exceptionMessage);
24 // we don't want a bare error without a stack trace
25 final hasStackTrace = try {
26 proc.stderr.readLine().contains('stack traceback');
27 } catch (_:haxe.io.Eof) {
28 false;
29 };
30
31 Sys.println('Error code: ${proc.exitCode()}');
32 Sys.println('Has expected exception message: ${hasExpectedMessage}');
33 // 5.1 interpreter doesn't handle custom objects
34 Sys.println('Has call stack: ${hasStackTrace || isLua5_1()}');
35
36 proc.close();
37 }
0 --lua bin/native-error.lua
1 --main NativeError
2
3 --cmd lua runner.lua 'bin/native-error' '%./bin/native%-error%.lua:%d+: attempt to index .+'
0 Success: false
1 Has expected exception message: true
2 Has call stack: true
0 --lua bin/haxe-exception.lua
1 --main HaxeException
2
3 --cmd lua runner.lua 'bin/haxe-exception' 'Exception thrown from Haxe'
0 Success: false
1 Has expected exception message: true
2 Has call stack: true
0 -- error in loaded script should be caught here, instead of exiting everything
1 local success, err = pcall(require, arg[1])
2
3 local exception_message = string.match(tostring(err), '^[^\n]+')
4 local has_expected_message = string.match(exception_message, arg[2]) ~= nil
5 local has_stack_trace = string.match(tostring(err), 'stack traceback') ~= nil
6
7 print('Success: '..tostring(success))
8 print('Has expected exception message: '..tostring(has_expected_message))
9 print('Has call stack: '..tostring(has_stack_trace))
0 --lua bin/native-error.lua
1 --main NativeError
2
3 --next
4 --run RunScript
5 bin/native-error.lua
6 bin/native-error\.lua:\d+: attempt to index .*
0 Error code: 1
1 Has expected exception message: true
2 Has call stack: true
0 --lua bin/haxe-exception.lua
1 --main HaxeException
2
3 --next
4 --run RunScript
5 bin/haxe-exception.lua
6 Exception thrown from Haxe
0 Error code: 1
1 Has expected exception message: true
2 Has call stack: true
0 using StringTools;
1
2 @:nullSafety(Strict)
3 class Main {
4 static var f = "field";
5 static function main() {
6 final sclass = new String("foo");
7 final scl = sclass.toUpperCase();
8 trace(scl);
9 final f2 = f.toUpperCase();
10 trace(f2);
11 final str = "str".toUpperCase();
12 trace(str);
13 final isS = "sss".startsWith("s");
14 trace(isS);
15 // test internal static call
16 final i = "foo".indexOf("");
17 trace(i);
18 trace(("dyn" : Dynamic).toUpperCase());
19 }
20 }
0 -main Main
1 -lua bin/test.lua
2 --cmd lua bin/test.lua
3 -D no-inline
0 Main.hx:9: FOO
1 Main.hx:11: FIELD
2 Main.hx:13: STR
3 Main.hx:15: true
4 Main.hx:18: 0
5 Main.hx:19: DYN
0 import sys.io.Process;
1
2 using StringTools;
3
4 enum abstract Arch(String) {
5 final Arm64;
6 final Arm;
7 final X86;
8 final X86_64;
9
10 public function getNdllSuffix():String {
11 return switch abstract {
12 case Arm64: "Arm64";
13 case Arm: "Arm";
14 case X86_64: "64";
15 case X86: "";
16 };
17 }
18 }
19
20 function getArchWindows() {
21 return switch Sys.getEnv("PROCESSOR_ARCHITECTURE") {
22 case "x86": X86;
23 case "AMD64": X86_64;
24 case "ARM64": Arm64;
25 case other: throw 'Unknown CPU architecture: $other';
26 };
27 }
28
29 function getArchUnix() {
30 final uname = new Process("uname", ["-m"]);
31
32 final arch = try {
33 uname.stdout.readLine();
34 } catch (e:haxe.io.Eof) {
35 "";
36 };
37
38 uname.kill();
39 uname.close();
40
41 return switch arch {
42 case "x86_64" | "amd64": X86_64;
43 case "i386" | "x86": X86;
44 case "arm64" | "aarch64": Arm64;
45 case "arm": Arm;
46 case other: throw 'Unknown CPU architecture: "$other"';
47 };
48 }
49
50 function getArch() {
51 return switch Sys.systemName() {
52 case "Windows": getArchWindows();
53 default: getArchUnix();
54 };
55 }
56
57 function main() {
58 final arch = getArch();
59
60 final expectedNdllSubDir = Sys.systemName() + arch.getNdllSuffix() + "/";
61
62 final ndllPath = neko.vm.Loader.local().getPath()[0];
63
64 if (ndllPath.endsWith(expectedNdllSubDir)) {
65 Sys.println("Success");
66 } else {
67 Sys.println('Failure: Expected $ndllPath to end with $expectedNdllSubDir');
68 }
69 }
0 --cmd haxelib dev dummy_ndll dummy_ndll
0 --main Main
1 --neko bin/main.n
2 -lib dummy_ndll
3 --cmd neko bin/main.n
0 -cp ../src
1 --run Main
0 -cp src
1
2 --each
3
4 -D php-prefix=app1
5 -main App1
6 -php bin/app1
7
8 --next
9
10 -D php-prefix=app2
11 -main App2
12 -php bin/app2
13
14 --next
15
16 --cmd php bin/app1/index.php
17 --cmd php bin/app2/index.php
0 class App1 {
1 static function main() {
2 sys.io.File.saveContent('bin/serialized.data', php.Global.serialize({a:1}));
3 }
4 }
0 class App2 {
1 static function main() {
2 php.Global.unserialize(sys.io.File.getContent('bin/serialized.data'));
3 }
4 }
0 class PAckFoo extends pack.Foo {}
1
2 class Foo{
3 public var bar : PAckFoo;
4 public function new(){
5 bar = new PAckFoo();
6 }
7 }
0 class Main {
1 static var tmp:Any;
2
3 static function main() {
4 // pack.Foo.test();
5 tmp = new Foo().bar;
6 }
7 }
0 --main Main
1 --php bin
2
3 --cmd php bin/index.php
0 package pack;
1
2 class Foo {
3 public function new() {}
4 }
0 Main.hx:5: characters 16-24 : Only extern functions may be overloaded on this target
0 Main.hx:5: characters 16-24 : Invalid modifier: overload is only supported on extern functions
0 #if macro
1 class Foo {
2 public static function build(f:() -> Void)
3 return [];
4
5 public static function other():Void {}
6 }
7 #else
8 @:build(Foo.build(Foo.other))
9 class Main {}
10
11 class Foo {}
12 #end
0 Main.hx:9: characters 19-28 : haxe.macro.Expr should be () -> Void
1 Main.hx:9: characters 19-28 : ... For function argument 'f'
0 Main.hx:2: characters 41-43 : Type parameters of multi type abstracts must be known (for haxe.IMap<Unknown<0> : String, Int>)
0 Main.hx:2: characters 41-43 : Type parameters of multi type abstracts must be known (for haxe.IMap<Unknown<0>, Int>)
0 Main.hx:20: characters 3-37 : Cannot access field or identifier position for writing
0 Main.hx:20: characters 10-18 : This expression cannot be accessed for writing
0 @:using(Main)
1 typedef B = {
2 > A,
3 };
4
5 typedef A = {};
6 function main() {}
0 -cp src
1 -main Main
2 --interp
0 abstract class A {
1 final x:Int;
2 final y:Int;
3 }
4
5 class B extends A {
6 final z:Int;
7 public function new() {}
8 }
9
10 function main() {}
0 Main.hx:6: characters 7-8 : Some final fields are uninitialized in this class
1 Main.hx:7: characters 8-9 : Uninitialized field
2 Main.hx:2: characters 8-9 : Uninitialized field
3 Main.hx:3: characters 8-9 : Uninitialized field
0 typedef HasAString = {
1 text:String
2 }
3 typedef HasANullString = {
4 text:Null<String>
5 }
6
7 @:nullSafety(StrictThreaded)
8 class Main {
9 static function main() {
10 final has:HasAString = {text: null};
11
12 final tmp = {text: null};
13 final typed:HasAString = tmp;
14
15 final tmp = {text: null};
16 final typed:{text:String} = tmp;
17
18 final tmp = {text: null};
19 final arr:Array<String> = [tmp.text];
20
21 // should pass
22 final tmp = {text: null};
23 final typed:{text:Null<String>} = tmp;
24 final typed2:HasANullString = tmp;
25 final typed3:HasANullString = typed;
26 }
27 }
0 Main.hx:14: characters 3-32 : Null safety: Cannot unify { text : Null<String> } with HasAString
1 Main.hx:17: characters 3-35 : Null safety: Cannot unify { text : Null<String> } with { text : String }
2 Main.hx:20: characters 30-38 : Null safety: Cannot use nullable value of Null<String> as an item in Array<String>
0 class Main {
1 static function main () {
2 #if (foo != "bar")
3 trace("NOT EQUAL");
4 #else
5 trace("EQUAL");
6 #end
7 }
8 }
0 --main Main
1 -D foo=bar
2 --interp
0 function f():Int {
1 throw invalid;
2 }
3
4 function main() {
5
6 }
0 -cp src
1 -main Main
2 --interp
0 Main.hx:2: characters 8-15 : Unknown identifier : invalid
0 /**
1 I'm a library!
2 **/
3
4 /**
5 a random number generator (only works once)
6 **/
7 function randomNumber() {
8 return 7;
9 }
10
11 function main() {
12 randomNumber();
13 }
0 -cp src
1 -main Main
2 --interp
3 --display "Main.hx@150@signature"
0 {"signatures":[{"documentation":"\n\ta random number generator (only works once)\n","label":"():Int","parameters":[]}],"activeParameter":0,"activeSignature":0}
0 import haxe.macro.Context;
1
2 function main() {
3 // test that built in defines can be accessed by macros
4 // either with a dash or underscore
5
6 if (!Context.defined("haxe-ver"))
7 throw "`haxe-ver` flag is missing";
8
9 if (!Context.defined("haxe_ver"))
10 throw "`haxe_ver` flag is missing";
11 }
0 function main() {
1 // usage of a deprecated function to generate warning
2 Std.is("string", String);
3 }
0 import haxe.macro.Context;
1
2 function main() {
3 // set with dash
4 if (!Context.defined("f-dash"))
5 throw "`f-dash` flag is missing";
6 if (!Context.defined("f_dash"))
7 throw "`f_dash` flag is missing";
8
9 // set with underscore
10 if (!Context.defined("f-underscore"))
11 throw "`f-underscore` flag is missing";
12 if (!Context.defined("f_underscore"))
13 throw "`f_underscore` flag is missing";
14
15 // value set with dash
16 if (Context.definedValue("v-dash") != "value")
17 throw "`v-dash` flag has incorrect value: " + Context.definedValue("v-dash");
18 if (Context.definedValue("v_dash") != "value")
19 throw "`v_dash` flag has incorrect value" + Context.definedValue("v_dash");
20
21 // value set with underscore
22 if (Context.definedValue("v-underscore") != "value")
23 throw "`v-underscore` flag has incorrect value" + Context.definedValue("v-underscore");
24 if (Context.definedValue("v_underscore") != "value")
25 throw "`v_underscore` flag has incorrect value" + Context.definedValue("v-underscore");
26 }
0 function main() {
1 final defines = haxe.macro.Context.getDefines();
2
3 // -D f-dash
4 if (!defines.exists("f-dash"))
5 throw "`f-dash` flag is missing";
6 if (!defines.exists("f_dash"))
7 throw "`f_dash` flag is missing";
8
9 // -D f_underscore
10 if (!defines.exists("f-underscore"))
11 throw "`f-underscore` flag is missing";
12 if (!defines.exists("f_underscore"))
13 throw "`f_underscore` flag is missing";
14
15 // -D v-dash=value
16 if (defines["v-dash"] != "value")
17 throw "`v-dash` flag value is incorrect: " + defines["v-dash"];
18 if (defines["v_dash"] != "value")
19 throw "`v_dash` flag value is incorrect: " + defines["v_dash"];
20
21 // -D v_underscore=value
22 if (defines["v-underscore"] != "value")
23 throw "`v-underscore` flag value is incorrect: " + defines["v-underscore"];
24 if (defines["v_underscore"] != "value")
25 throw "`v_underscore` flag value is incorrect: " + defines["v_underscore"];
26 }
0 function throwInactive(flag:String) {
1 throw '`$flag` block is not active';
2 }
3
4 function throwInactiveValue(flag:String, expected:String, value:String) {
5 throw '`$flag` block is not active, as flag has value `$value` instead of `$expected`';
6 }
7
8 function main() {
9 #if !f_dash
10 throwInactive("f_dash");
11 #end
12
13 #if !f_underscore
14 throwInactive("f_underscore");
15 #end
16
17 #if (v_dash!="value")
18 throwInactiveValue("v_dash", "value", haxe.macro.Context.definedValue("v_dash"));
19 #end
20
21 #if (v_underscore!="value")
22 throwInactiveValue("v_underscore", "value", haxe.macro.Context.definedValue("v_underscore"));
23 #end
24 }
0 import haxe.macro.Context;
1
2 function main() {
3 // dash set then underscore
4 if (Context.definedValue("value-a") != "new value")
5 throw '`value-a` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value-a")}`';
6 if (Context.definedValue("value_a") != "new value")
7 throw '`value_a` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value_a")}`';
8
9 if (Context.definedValue("value-b") != "new value")
10 throw '`value-b` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value-b")}`';
11 if (Context.definedValue("value_b") != "new value")
12 throw '`value_b` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value_b")}`';
13
14 // underscore set then dash
15 if (Context.definedValue("value-c") != "new value")
16 throw '`value-c` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value-c")}`';
17 if (Context.definedValue("value_c") != "new value")
18 throw '`value_c` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value_c")}`';
19
20 if (Context.definedValue("value-d") != "new value")
21 throw '`value-c` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value-d")}`';
22 if (Context.definedValue("value_d") != "new value")
23 throw '`value_c` flag has incorrect value. Expected: `new value`, Got: `${Context.definedValue("value_d")}`';
24 }
0 # deprecation warnings should show
1 --run Deprecated
0 Deprecated.hx:3: characters 2-8 : Warning : (WDeprecated) Std.is is deprecated. Use Std.isOfType instead.
0 # test defines set via -D
1 -D f-dash
2 -D f_underscore
3 -D v-dash=value
4 -D v_underscore=value
5
6 --run Flags
0 # test that Context.getDefines works correctly
1
2 --main GetDefines
3 --interp
4
5 --each
6
7 -D f-dash
8 -D f_underscore
9 -D v-dash=value
10 -D v_underscore=value
11
12 --next
13
14 --macro define("f-dash")
15 --macro define("f_underscore")
16 --macro define("v-dash", "value")
17 --macro define("v_underscore", "value")
0 # test using if blocks
1
2 --main IfBlocks
3 --interp
4
5 --each
6
7 -D f-dash
8 -D f_underscore
9 -D v-dash=value
10 -D v_underscore=value
11
12 --next
13
14 --macro define("f-dash")
15 --macro define("f_underscore")
16 --macro define("v-dash", "value")
17 --macro define("v_underscore", "value")
0 # test defines set via define macro function
1 --macro define("f-dash")
2 --macro define("f_underscore")
3 --macro define("v-dash", "value")
4 --macro define("v_underscore", "value")
5
6 --run Flags
0 # should have no deprecation warnings
1 -D no_deprecation_warnings
2 --run Deprecated
0 # should have no deprecation warnings
1 -D no-deprecation-warnings
2 --run Deprecated
0 # test defining the same define twice sets it to the most recent value,
1 # regardless of if it uses a dash or underscore.
2
3 # dash first, then underscore
4 -D value-a=old value
5 -D value_a=new value
6
7 --macro define("value-b", "old value")
8 --macro define("value_b", "new value")
9
10 # underscore first, then dash
11 -D value_c=old value
12 -D value-c=new value
13
14 --macro define("value_d", "old value")
15 --macro define("value-d", "new value")
16
17 --run Repeated
0 abstract Main(Dynamic) {
1 static function main() {}
2 var bar(get, never):Int;
3 public function foo(?v = bar) {}
4 function get_bar() return 1;
5 }
0 Main.hx:4: characters 27-30 : Cannot reference this abstract here
0 enum E {
1 A;
2 B;
3 C(v:Int);
4 }
5
6 class Main {
7 static function main() {
8 var e = A;
9 switch (e) {
10 case A:
11 case B:
12 case C(0):
13 case C(x) if (x > 0):
14 }
15 }
16 }
0 Main.hx:14: characters 11-12 : Unmatched patterns: C(_)
0 class Main {
1 static function main()
2 var b:Int = fn(fn('s'));
3
4 static public function fn<T, R:T>(v:R):T
5 return null;
6 }
0 class Main2 {
1 static function main() {
2 var foo:Vector<Foo> = null;
3 var bar:Vector<Bar> = Vector.fromIterable(foo);
4 }
5 }
6
7 typedef Foo = {
8 final id:String;
9 final ?project:String;
10 }
11
12 typedef Bar = {
13 final id:String;
14 final createDate:Date;
15 }
16
17 abstract Vector<T>(Array<T>) {
18
19 inline function new(a)
20 this = a;
21
22 @:from static function fromVector<T, R:T>(v:Vector<R>):Vector<T>
23 return cast v;
24
25 static public function fromIterable<T, R:T>(v:Iterable<R>):Vector<T>
26 return null;
27
28 @:to public function toArray()
29 return this.copy();
30 }
0 function fn1<T1,R1:T1>(v:R1):T1
1 return null;
2
3 function fn2<T2,R2:T2>(v:R2):T2
4 return null;
5
6 function fn3<T3,R3:T3>(v:R3):T3
7 return null;
8
9 function main() {
10 var b:Array<Int> = fn1(fn2(fn3(['s'])));
11 }
0 Main.hx:3: characters 3-6 : Constraint check failure for fn.R
1 Main.hx:3: characters 3-6 : ... String should be Int
0 Main2.hx:4: characters 3-50 : error: { ?project : Null<String>, id : String } has no field createDate
1 Main2.hx:4: characters 3-50 : ... have: Vector<Foo>
2 Main2.hx:4: characters 3-50 : ... want: Vector<Bar>
0 Main3.hx:11: characters 2-42 : error: String should be Int
1 Main3.hx:11: characters 2-42 : ... have: Array<String>
2 Main3.hx:11: characters 2-42 : ... want: Array<Int>
+0
-8
tests/misc/projects/Issue10205/Main.hx less more
0 class Main {
1 static function main() {
2 test('hello');
3 }
4
5 overload extern static inline function test(s:String) {}
6 overload extern static inline function test(s:String, ...r:String) {}
7 }
+0
-1
tests/misc/projects/Issue10205/compile-fail.hxml less more
0 --main Main
+0
-3
tests/misc/projects/Issue10205/compile-fail.hxml.stderr less more
0 Main.hx:3: characters 3-16 : Ambiguous overload, candidates follow
1 Main.hx:6: characters 41-45 : ... (s : String) -> Void
2 Main.hx:7: characters 41-45 : ... (s : String, r : haxe.Rest<String>) -> Void
0 function main() {
1 var x:Int;
2 if (Math.random() < 0.5) {
3 x = 3;
4 } else {
5 var b = () -> 3;
6 }
7 trace(x);
8 }
0 Main.hx:8: characters 8-9 : Local variable x used without being initialized
0 typedef Foo = {
1 final id:String;
2 final ?project:String;
3 }
4
5 typedef Bar = {
6 final id:String;
7 final createDate:Date;
8 final ?project:String;
9 }
10
11 class Main {
12 static function constrained<T,R:T>(v:R):T
13 return null;
14
15 static function fn<T>(s:T):T {
16 return s;
17 }
18
19 static function main() {
20 var A:Int = fn('s'); // Error "String should be Int"
21 var B:Int = constrained('s'); //Error "Int should be String" instead of "String should be Int"
22 var C:Bar = constrained((null:Foo)); // compiles, but should error "Foo should be Bar; { ?project : Null<String>, id : String } has no field createDate"
23 }
24 }
0 Main.hx:21: characters 3-23 : String should be Int
1 Main.hx:22: characters 3-32 : Constraint check failure for constrained.R
2 Main.hx:22: characters 3-32 : ... String should be Int
3 Main.hx:23: characters 3-39 : Constraint check failure for constrained.R
4 Main.hx:23: characters 3-39 : ... Foo should be Bar
5 Main.hx:23: characters 3-39 : ... { ?project : Null<String>, id : String } has no field createDate
0 @:generic
1 class Foo<T> extends Foo<T> {}
0 --main Main
1 --interp
2 --macro addGlobalMetadata("", "@meta0", false)
3 --macro addGlobalMetadata("", "@meta1", true)
4 --macro addGlobalMetadata("Main", "@meta2", false)
5 --macro addGlobalMetadata("Main", "@meta3", true)
6 --macro addGlobalMetadata("Main.MainSub", "@meta4", false)
7 --macro addGlobalMetadata("Main.MainSub", "@meta5", true)
0 Main.hx:2: characters 22-28 : Recursive class
0 function main() {
1 var d:Dynamic = null;
2 var v:MacroFrom = d;
3 }
4
5 abstract MacroFrom(String) to String {
6 @:from
7 public static macro function fromExpr(e:haxe.macro.Expr)
8 return macro ($e:Main.MacroFrom);
9 }
0 Main.hx:9: characters 16-35 : Recursive implicit cast
0 import haxe.ds.Option;
1
2 class Main {
3 static function main() {
4 var o = Some({b: null});
5 switch (o) {
6 case Some({b: b}) if (b != null):
7 trace("Case 1: b=" + b);
8 case Some({b: null}):
9 trace("Case 2: b=null");
10 case None: // Change None to _ and it works
11 trace("Default");
12 }
13 }
14 }
0 Main.hx:9: characters 14-23 : Unmatched patterns: Some(_)
0 class Main {
1 static function main() {
2 var final;
3 }
4 }
0 class Main {
1 static function main() {
2 var not, final;
3 }
4 }
0 class Main {
1 static function main() {
2 var final = 0;
3 }
4 }
0 Main.hx:3: characters 7-12 : Keyword final cannot be used as variable name
0 Main2.hx:3: characters 12-17 : Keyword final cannot be used as variable name
0 Main3.hx:3: characters 7-12 : Keyword final cannot be used as variable name
0 class Main extends Abstr {
1 static function main() {}
2 }
3
4 abstract class Abstr {
5 abstract function new():Void;
6 }
0 Main.hx:6: characters 2-10 : Invalid modifier: abstract on constructor
0 class Main {
1 static function main() {
2 abstract;
3 abstract();
4 abstract + 1;
5 }
6 }
0 Main.hx:3: characters 3-11 : Property 'abstract' is reserved and only available in abstracts
1 Main.hx:4: characters 3-11 : Property 'abstract' is reserved and only available in abstracts
2 Main.hx:5: characters 3-11 : Property 'abstract' is reserved and only available in abstracts
0 class Main {
1 static function main() {
2 var v = { a : 1, foo : null };
3 $type(v);
4 parse1(v);
5 $type(v);
6 parse2(v);
7 }
8
9 extern static function parse1( v : { a : Int, ?b:Int } ):Void;
10 extern static function parse2( v : { a : Int, ?b:String } ):Void;
11 }
0 Main.hx:4: characters 9-10 : Warning : { foo : Null<Unknown<0>>, a : Int }
1 Main.hx:6: characters 9-10 : Warning : { foo : Null<Unknown<0>>, ?b : Null<Int>, a : Int }
2 Main.hx:7: characters 10-11 : error: Int should be String
3 Main.hx:7: characters 10-11 : ... have: { b: Int }
4 Main.hx:7: characters 10-11 : ... want: { b: String }
0 class Main {
1 static function main() {
2 new Bar(1, 2);
3 }
4 }
5
6 class Foo {
7 var x:Int;
8 var y:Int;
9
10 public function new(x:Int, y:Int) {
11 this.x = x;
12 this.y = y;
13 }
14 }
15
16 class Bar extends Foo {
17 public function new(x:Int, y:Int) {
18 super(x, y);
19 var foo = new Foo(super.x, super.y);
20 }
21 }
0 Main.hx:20: characters 27-28 : Normal variables cannot be accessed with 'super', use 'this' instead
1 Main.hx:20: characters 36-37 : Normal variables cannot be accessed with 'super', use 'this' instead
0 class Macro {
1 public static macro function foo(e:Expr) {}
2 }
0 import Macro;
1
2 class Main {
3 static function main() {
4 Macro.foo( 1 );
5 }
6 }
0 using Macro;
1
2 class Main {
3 static function main() {
4 1.foo();
5 }
6 }
0 Macro.hx:2: characters 37-41 : Type not found : Expr
0 Macro.hx:2: characters 37-41 : Type not found : Expr
0 import haxe.rtti.Meta;
1 using Lambda;
2
3
4 class MainSub {}
5
6 class Main {
7 static function main() {
8 function hf(t, s) {
9 Sys.stderr().writeString('$s: ${Reflect.hasField(t, s)}\n');
10 }
11
12 final numMetas = 6;
13
14 var check = [
15 { name: "Main", meta: Meta.getType(Main) },
16 { name: "MainSub", meta: Meta.getType(MainSub) }
17 ];
18
19 for (item in check) {
20 Sys.stderr().writeString(item.name + "\n");
21 for (i in 0...numMetas) {
22 hf(item.meta, 'meta$i');
23 }
24 }
25 }
26 }
0 --main Main
1 --interp
2 --macro addGlobalMetadata("", "@meta0", false)
3 --macro addGlobalMetadata("", "@meta1", true)
4 --macro addGlobalMetadata("Main", "@meta2", false)
5 --macro addGlobalMetadata("Main", "@meta3", true)
6 --macro addGlobalMetadata("Main.MainSub", "@meta4", false)
7 --macro addGlobalMetadata("Main.MainSub", "@meta5", true)
0 Main
1 meta0: true
2 meta1: true
3 meta2: true
4 meta3: true
5 meta4: false
6 meta5: false
7 MainSub
8 meta0: false
9 meta1: true
10 meta2: false
11 meta3: true
12 meta4: true
13 meta5: true
0 class Main {
1 static function main() {
2 var data = haxe.io.Bytes.alloc(2);
3 data.set(0, 0xFF);
4 data.toString().substr(0);
5 }
6 }
0 Uncaught exception Invalid string
1 Main.hx:5: characters 3-18 : Called from here
0 compile-fail.hxml
1 -D message-reporting=indent
0 Uncaught exception Invalid string
1 Main.hx:5: characters 3-18 : Called from here
0 compile-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] (unknown position)
1
2 | Uncaught exception Invalid string
3
4 -> Main.hx:5: characters 3-18
5
6 5 | data.toString().substr(0);
7 | ^^^^^^^^^^^^^^^
8 | Called from here
9
0 class Main {
1 var foo = new Foo();
2 var fooExtern = new Foo();
3 var fooAb = new FooExtern();
4 var vector = new haxe.ds.Vector(1);
5 var vector2 = new haxe.ds.Vector(1, 0);
6 static function main() {}
7 }
8
9 class Foo {
10 public var length = Std.random(1);
11 public inline function new() {}
12 }
13
14 class FooExtern {
15 public var length = Std.random(1);
16 extern public inline function new() {}
17 }
18
19 abstract FooAb({length:Int}) {
20 extern public inline function new() {
21 this = {length: Std.random(1)};
22 }
23 }
0 Main.hx:4: characters 14-29 : Extern constructor could not be inlined
0 class Main {
1 static function main() {
2 var x:X<String>;
3 }
4 }
0 --cmd haxelib dev lib1 lib1
1 --cmd haxelib dev lib2 lib2
2 --next
3 --main Main
4 -lib lib1
5 -lib lib2
6 --interp
0 interface IA {
1 public var a:String;
2 }
3
4 abstract class A implements IA {
5 public function new() {}
6 }
7
8 class B extends A {
9 public function new() {
10 super();
11 }
12 }
13
14 function main() {}
0 Main.hx:5: characters 16-17 : Field a needed by IA is missing
0 class Main {
1 static function main() {
2 getAnswer().next(v -> switch v {
3 case 42: 'Perfect!';
4 case 40, 41, 43, 44: 'Close enough!';
5 default: new NotError();
6 }).handle(o -> trace(Std.string(o)));
7 }
8
9 static function getAnswer():Promise<Int>
10 return 3 + 39;
11 }
12
13 class NotError {
14 public function new() {}
15 }
16
17 abstract Promise<T>((handler:(result:Outcome<T, NotError>) -> Void) -> Void) {
18 inline function new(f)
19 this = f;
20
21 public function next<X>(transform:Next<T, X>):Promise<X>
22 return new Promise(handler -> this(o -> switch o {
23 case Success(v): transform(v).handle(handler);
24 case Failure(e): handler(Failure(e));
25 }));
26
27 @:from static function ofOutcome<T>(o:Outcome<T, NotError>):Promise<T>
28 return new Promise<T>(h -> h(o));
29
30 @:from static function ofValue<T>(v:T):Promise<T>
31 return ofOutcome(Success(v));
32
33 @:from static function ofError<T>(e:NotError):Promise<T>
34 return ofOutcome(Failure(e));
35
36 public function handle(cb)
37 this(cb);
38 }
39
40 @:callable
41 abstract Next<In, Out>(In->Promise<Out>) from In->Promise<Out> {
42 @:from(ignoredByInference) static function ofSync<In, Out>(f:In->Out):Next<In, Out>
43 return v -> (f(v) : Promise<Out>);
44 }
45
46 enum Outcome<T, E> {
47 Success(data:T);
48 Failure(error:E);
49 }
0 -cp src
1 -main Main
2 --interp
0 Main.hx:7: Success(Perfect!)
0 import haxe.macro.Context;
1 import haxe.macro.Expr;
2
3 using haxe.macro.Tools;
4
5 abstract Foo(Dynamic) from Dynamic to Dynamic {
6 @:op(A.B) function get(prop:String) {
7 return Reflect.field(this, prop);
8 }
9
10 @:op(A.B) macro function set(obj:Expr, prop:Expr, val:Expr) {
11 var s = Context.getTypedExpr(Context.typeExpr(obj)).toString();
12 Sys.stderr().writeString(s);
13 return macro $val;
14 }
15 }
16
17 class Main {
18 static function main() {
19 var foo:Foo = {
20 n: 5
21 };
22 foo.n += 4;
23 }
24 }
0 --main Main
1 --interp
2 -D warn-var-shadowing
0 function main() {
1 new haxe.ds.Vector(-1);
2 }
0 function getMinusOne() {
1 return -1;
2 }
3
4 function main() {
5 new haxe.ds.Vector(getMinusOne());
6 }
0 Main.hx:2: characters 21-23 : Uncaught exception Vector size must be >= 0
0 Main2.hx:6: characters 21-34 : Uncaught exception Vector size must be >= 0
0 class Main {
1 static var a:Array<Int> = [1];
2
3 static function main() {
4 switch a { // <--- Warning : (WVarShadow) This variable shadows a previously declared variable
5 case [1]:
6 case _:
7 }
8 }
9 }
0 --main Main
1 --interp
2 -D warn-var-shadowing
0 class A {
1 public function new() {}
2
3 public final function run() {
4 trace("running");
5 }
6 }
7
8 class Main {
9 static function main() {
10 final a:A = null;
11 a.run();
12 }
13 }
0 Main.hx:12: characters 3-4 : Uncaught exception Null Access
0 import haxe.MainLoop;
1
2 class Main {
3 static function main() {
4 trace('main');
5 var event = null;
6 var done = false;
7 event = MainLoop.add(
8 () -> {
9 if(!done){
10 done = true;
11 trace('ok');
12 }
13 if(event !=null){
14 trace("stop");
15 event.stop();
16 }
17 }
18 );
19 }
20 }
0 Main.hx:5: main
1 Main.hx:12: ok
2 Main.hx:15: stop
0 --cmd haxelib dev dummy_doc_dep dummy_doc_dep
1 --cmd haxelib dev dummy_doc dummy_doc
0 dummy : <level: 10 | 11> On a scale from 0 to 10 (from dummy_doc_dep)
1 no-bullshit: Only very important stuff should be compiled (from dummy_doc)
0 -lib dummy_doc
1 --help-user-defines
0 dummy : <level: 10 | 11> On a scale from 0 to 10 (from dummy_doc_dep)
1 no-bullshit: Only very important stuff should be compiled (from dummy_doc)
0 @:bar : Some documentation for the TClass metadata '@:bar' (from dummy_doc)
1 @:baz : Some documentation for the @:baz metadata (from dummy_doc_dep)
2 @:foo : Some documentation for the @:foo metadata for cpp platform (cpp
3 only) (from dummy_doc)
4 @:foobar: Some documentation for @:foobar (cpp only) (from dummy_doc)
0 -lib dummy_doc
1 --help-user-metas
0 @:bar : Some documentation for the TClass metadata '@:bar' (from dummy_doc)
1 @:baz : Some documentation for the @:baz metadata (from dummy_doc_dep)
2 @:foo : Some documentation for the @:foo metadata for cpp platform (cpp
3 only) (from dummy_doc)
4 @:foobar: Some documentation for @:foobar (cpp only) (from dummy_doc)
0 [
1 {
2 "define": "fromjson",
3 "doc": "Custom user define from json"
4 }
5 ]
0 [
1 {
2 "define": "no-bullshit",
3 "doc": "Only very important stuff should be compiled"
4 }
5 ]
0 [
1 {
2 "metadata": ":foo",
3 "doc": "Some documentation for the @:foo metadata for cpp platform",
4 "platforms": ["cpp"]
5 },
6 {
7 "metadata": ":bar",
8 "doc": "Some documentation for the TClass metadata '@:bar'",
9 "targets": ["TClass"]
10 },
11 {
12 "metadata": ":foobar",
13 "doc": "Some documentation for @:foobar",
14 "platforms": ["cpp"]
15 }
16 ]
0 {
1 "name": "dummy_doc",
2 "url" : "http://example.org",
3 "license": "GPL",
4 "description": "This is a dummy lib for test purposes",
5 "version": "1.0.0",
6 "releasenote": "Initial release, everything is working correctly",
7 "documentation": {
8 "metadata": "doc/meta.json",
9 "defines": "doc/define.json"
10 },
11 "contributors": ["haxe"],
12 "dependencies": {
13 "dummy_doc_dep": "*"
14 }
15 }
0 [
1 {
2 "define": "dummy",
3 "doc": "On a scale from 0 to 10",
4 "params": ["level: 10 | 11"]
5 }
6 ]
0 [
1 {
2 "metadata": ":baz",
3 "doc": "Some documentation for the @:baz metadata"
4 }
5 ]
0 {
1 "name": "dummy_doc_dep",
2 "url" : "http://example.org",
3 "license": "GPL",
4 "description": "This is a dummy lib for test purposes",
5 "version": "1.0.0",
6 "releasenote": "Initial release, everything is working correctly",
7 "documentation": {
8 "metadata": "doc/meta.json",
9 "defines": "doc/define.json"
10 },
11 "contributors": ["haxe"]
12 }
0 [
1 {
2 "metadata": ":fromjson",
3 "doc": "Custom user metadata from json"
4 }
5 ]
0 --macro haxe.macro.Compiler.registerCustomDefine({dfine: 'zzz', doc: 'something'}, 'myapp')
1 --help-user-defines
0 (unknown) : Object requires field define
1 (unknown) : ... For function argument 'define'
0 --macro haxe.macro.Compiler.registerDefinesDescriptionFile('define.jsno', 'myapp')
1 --help-user-defines
0 (unknown) : Uncaught exception Could not read file define.jsno
1 $$normPath(::std::)/haxe/macro/Compiler.hx:493: characters 11-39 : Called from here
2 (unknown) : Called from here
0 -lib dummy_doc
1 --macro haxe.macro.Compiler.registerDefinesDescriptionFile('define.json', 'myapp')
2 --macro haxe.macro.Compiler.registerCustomDefine({define: 'custom', doc: 'Some user define'}, 'myapp')
3 --help-user-defines
0 custom : Some user define (from myapp)
1 dummy : <level: 10 | 11> On a scale from 0 to 10 (from dummy_doc_dep)
2 fromjson : Custom user define from json (from myapp)
3 no-bullshit: Only very important stuff should be compiled (from dummy_doc)
0 --macro haxe.macro.Compiler.registerCustomMetadata({metdata: ':zzz', doc: 'something'}, 'myapp')
1 --help-user-metas
0 (unknown) : Object requires field metadata
1 (unknown) : ... For function argument 'meta'
0 user-defined-meta-fail.hxml
1 -D message-reporting=indent
0 (unknown) : Object requires field metadata
1 (unknown) : For function argument 'meta'
0 --macro haxe.macro.Compiler.registerMetadataDescriptionFile('meta.jsno', 'myapp')
1 --help-user-metas
0 (unknown) : Uncaught exception Could not read file meta.jsno
1 $$normPath(::std::)/haxe/macro/Compiler.hx:483: characters 11-39 : Called from here
2 (unknown) : Called from here
0 user-defined-meta-json-fail.hxml
1 -D message-reporting=indent
0 (unknown) : Uncaught exception Could not read file meta.jsno
1 $$normPath(::std::)/haxe/macro/Compiler.hx:483: characters 11-39 : Called from here
2 (unknown) : Called from here
0 user-defined-meta-json-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
3
0 [ERROR] --macro haxe.macro.Compiler.registerMetadataDescriptionFile('meta.jsno', 'myapp')
1
2 | Uncaught exception Could not read file meta.jsno
3
4 -> $$normPath(::std::)/haxe/macro/Compiler.hx:483: characters 11-39
5
6 483 | var f = sys.io.File.getContent(path);
7 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 | Called from here
9
10 | Called from here
11
0 user-defined-meta-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
3
0 [ERROR] --macro haxe.macro.Compiler.registerCustomMetadata({metdata: ':zzz', doc: 'something'}, 'myapp')
1
2 | Object requires field metadata
3 | For function argument 'meta'
4
0 -lib dummy_doc
1 --macro haxe.macro.Compiler.registerMetadataDescriptionFile('meta.json', 'myapp')
2 --macro haxe.macro.Compiler.registerCustomMetadata({metadata: ':custom', doc: 'Some user meta'}, 'myapp')
3 --help-user-metas
0 @:bar : Some documentation for the TClass metadata '@:bar' (from
1 dummy_doc)
2 @:baz : Some documentation for the @:baz metadata (from dummy_doc_dep)
3 @:custom : Some user meta (from myapp)
4 @:foo : Some documentation for the @:foo metadata for cpp platform (cpp
5 only) (from dummy_doc)
6 @:foobar : Some documentation for @:foobar (cpp only) (from dummy_doc)
7 @:fromjson: Custom user metadata from json (from myapp)
0 abstract MyInt(Int) from Int to Int {
1 @:op(A += B)
2 public inline function addEq(x:Int):MyInt {
3 return this += x;
4 }
5
6 @:op(A++)
7 public inline function increment():MyInt {
8 return this++;
9 }
10 }
11
12 class MyClass {
13 final field:MyInt = 1;
14
15 function func():Void {
16 final local:MyInt = 1;
17
18 // --- overriden operators ---
19
20 field++; // Error: The field or identifier field is not accessible for writing
21 local++;
22
23 field += 1;
24 local += 1; // Error: Cannot assign to final
25
26 // --- raw operators ---
27
28 field--; // Error: The field or identifier field is not accessible for writing
29 local--; // Error: Cannot assign to final
30
31 field -= 1; // Error: Cannot access field or identifier field for writing
32 local -= 1; // Error: Cannot assign to final
33
34 // --- method calls ---
35
36 field.addEq(1);
37 local.addEq(1);
38
39 field.increment();
40 local.increment();
41 }
42 }
43
44 function main() {
45
46 }
0 Main.hx:21: characters 3-10 : Cannot modify abstract value of final field
1 Main.hx:22: characters 3-10 : Cannot modify abstract value of final local
2 Main.hx:24: characters 3-8 : Cannot modify abstract value of final field
3 Main.hx:25: characters 3-13 : Cannot modify abstract value of final local
4 Main.hx:29: characters 3-8 : This expression cannot be accessed for writing
5 Main.hx:30: characters 3-8 : Cannot assign to final
6 Main.hx:32: characters 3-8 : This expression cannot be accessed for writing
7 Main.hx:33: characters 3-8 : Cannot assign to final
8 Main.hx:37: characters 3-17 : Cannot modify abstract value of final field
9 Main.hx:38: characters 3-17 : Cannot modify abstract value of final local
10 Main.hx:40: characters 3-20 : Cannot modify abstract value of final field
11 Main.hx:41: characters 3-20 : Cannot modify abstract value of final local
0 import haxe.macro.Context;
1 import haxe.macro.Expr.Field;
2
3 class Macro {
4 public static macro function build():Array<Field> {
5 Context.typeof(macro(null : String));
6 return [];
7 }
8 }
0 interface Foo {
1 function foo():Void;
2 }
3
4 @:build(Macro.build())
5 class Main implements Foo {
6 public function foo():Void {}
7 }
8
9 function main() {}
0 Main.hx:6: characters 7-11 : Field foo needed by Foo is missing
0 import haxe.macro.Context;
1 import haxe.macro.Expr.Field;
2
3 class Macro {
4 public static macro function build():Array<Field> {
5 Context.typeof(macro(null : String));
6 return null;
7 }
8 }
0 interface Foo {
1 function foo():Void;
2 }
3
4 @:build(Macro.build())
5 class Main implements Foo {
6 public function foo():Void {}
7 }
8
9 function main() {}
0 class Main {
1 static function main() {
2 foo((o) ->);
3 }
4 static function foo(?f:Dynamic->Bool) {}
5 }
0 Main.hx:3: characters 19-20 : Expected expression
0 function main() {
1 foo();
2 }
3
4 macro function foo():Expr;
0 import haxe.macro.Context;
1 import haxe.macro.Expr;
2
3 macro function foo():Expr {
4 Context.warning("from macro", (macro 0).pos);
5 Context.warning("from non macro", Context.currentPos());
6 return macro null;
7 }
0 -main Main
1 -js js.js
2 -D message-reporting=pretty
3 -D no-color
4 --no-output
0 [WARNING] Main.macro.hx:5: characters 39-40
1
2 5 | Context.warning("from macro", (macro 0).pos);
3 | ^
4 | from macro
5
6 [WARNING] Main.js.hx:2: characters 2-7
7
8 2 | foo();
9 | ^^^^^
10 | from non macro
11
0 Any
1 -D messages-log-file=error.log
2 -D messages-log-format=awesome
0 Invalid message reporting mode: "awesome", expected classic | pretty | indent (for -D messages_log_format).
0 Any
1 -D message-reporting=awesome
0 Invalid message reporting mode: "awesome", expected classic | pretty | indent (for -D message_reporting).
0 class Main {
1 public static function main():Void
2 trace(foo());
3
4 public static function foo():Int {
5 true || throw 0;
6 0;
7 }
8 }
0 Main.hx:7: characters 3-4 : Missing return: Int
0 package;
1
2 #if macro
3 import haxe.macro.Compiler;
4 import haxe.macro.Compiler.PackageRule;
5 #end
6
7 function main() {
8 }
9
10 #if macro
11 class MacroClass {
12 public static function start() {
13 final config = Compiler.getConfiguration();
14
15 trace(config.args);
16 trace(config.debug);
17 trace(config.verbose);
18 trace(config.foptimize);
19 trace(config.platform);
20 trace(config.mainClass.pack);
21 trace(config.mainClass.name);
22
23 for(packageName => packageRule in config.packageRules) {
24 switch(packageRule) {
25 case Forbidden: trace(packageName + " is forbidden");
26 case _:
27 }
28 }
29 }
30 }
31 #end
0 package;
1
2 function main() {
3 haxe.macro.Compiler.getConfiguration();
4 }
0 MainFail.hx:4: characters 22-38 : Class<haxe.macro.Compiler> has no field getConfiguration
0 --main Main
1 --macro Main.MacroClass.start()
2 --interp
0 Main.hx:16: [--main,Main,--macro,Main.MacroClass.start(),--interp]
1 Main.hx:17: false
2 Main.hx:18: false
3 Main.hx:19: true
4 Main.hx:20: eval
5 Main.hx:21: []
6 Main.hx:22: Main
7 Main.hx:26: python is forbidden
8 Main.hx:26: php is forbidden
9 Main.hx:26: neko is forbidden
10 Main.hx:26: lua is forbidden
11 Main.hx:26: jvm is forbidden
12 Main.hx:26: js is forbidden
13 Main.hx:26: java is forbidden
14 Main.hx:26: hl is forbidden
15 Main.hx:26: flash is forbidden
16 Main.hx:26: cs is forbidden
17 Main.hx:26: cpp is forbidden
0 --main Main
1 --macro Main.MacroClass.start()
2 --js Output.js
3 --no-output
4 --debug
0 Main.hx:16: [--main,Main,--macro,Main.MacroClass.start(),--js,Output.js,--no-output,--debug]
1 Main.hx:17: true
2 Main.hx:18: false
3 Main.hx:19: true
4 Main.hx:20: js
5 Main.hx:21: []
6 Main.hx:22: Main
7 Main.hx:26: sys is forbidden
8 Main.hx:26: python is forbidden
9 Main.hx:26: php is forbidden
10 Main.hx:26: neko is forbidden
11 Main.hx:26: lua is forbidden
12 Main.hx:26: jvm is forbidden
13 Main.hx:26: java is forbidden
14 Main.hx:26: hl is forbidden
15 Main.hx:26: flash is forbidden
16 Main.hx:26: eval is forbidden
17 Main.hx:26: cs is forbidden
18 Main.hx:26: cpp is forbidden
0 --main Main
1 --macro Main.MacroClass.start()
2 --cpp bin
3 --no-output
4 --no-opt
0 Main.hx:16: [--main,Main,--macro,Main.MacroClass.start(),--cpp,bin,--no-output,--no-opt]
1 Main.hx:17: false
2 Main.hx:18: false
3 Main.hx:19: false
4 Main.hx:20: cpp
5 Main.hx:21: []
6 Main.hx:22: Main
7 Main.hx:26: python is forbidden
8 Main.hx:26: php is forbidden
9 Main.hx:26: neko is forbidden
10 Main.hx:26: lua is forbidden
11 Main.hx:26: jvm is forbidden
12 Main.hx:26: js is forbidden
13 Main.hx:26: java is forbidden
14 Main.hx:26: hl is forbidden
15 Main.hx:26: flash is forbidden
16 Main.hx:26: eval is forbidden
17 Main.hx:26: cs is forbidden
0 package;
1
2 #if macro
3 import haxe.macro.Context;
4 import haxe.macro.Type;
5 #end
6
7 function main() {
8 }
9
10 #if macro
11 class MacroClass {
12 public static function start() {
13 printTypedExpr(Context.getMainExpr());
14
15 Context.onAfterTyping(function(modules: Array<ModuleType>) {
16 printTypedExpr(Context.getMainExpr());
17 });
18
19 Context.onGenerate(function(types: Array<Type>) {
20 printTypedExpr(Context.getMainExpr());
21
22 if(Context.getAllModuleTypes().length == types.length) {
23 trace("Module type list length == types.length");
24 } else {
25 trace("Module types length != types.length");
26 }
27 });
28
29 Context.onAfterGenerate(function() {
30 printTypedExpr(Context.getMainExpr());
31 });
32 }
33
34 static function printTypedExpr(te: Null<TypedExpr>, ?pos:haxe.PosInfos) {
35 if(te == null) {
36 haxe.Log.trace("null", pos);
37 } else {
38 haxe.Log.trace(haxe.macro.TypedExprTools.toString(te, true), pos);
39 }
40 }
41 }
42 #end
0 --main Main
1 --macro Main.MacroClass.start()
2 --interp
0 Main.hx:14: null
1 Main.hx:17: null
2 Main.hx:21: _Main.Main_Fields_.main()
3 Main.hx:24: Module type list length == types.length
4 Main.hx:31: _Main.Main_Fields_.main()
0 package;
1
2 #if macro
3 import haxe.macro.Context;
4 import haxe.macro.TypeTools;
5 import haxe.macro.Type;
6 #end
7
8 function main() {
9 }
10
11 #if macro
12 class MacroClass {
13 public static function start() {
14 Context.onGenerate(function(types: Array<Type>) {
15 for(t in types) {
16 testTypeConversion(t);
17 }
18 });
19 }
20
21 static function testTypeConversion(t: Type) {
22 final moduleType = TypeTools.toModuleType(t);
23
24 switch(t) {
25 case TInst(t, params): {
26 switch(moduleType) {
27 case TClassDecl(t2): {
28 if(!compareClassTypes(t.get(), t2.get())) {
29 trace("Class types not equal");
30 }
31 }
32 case _: trace("Module wasn't class type");
33 }
34 }
35 case TEnum(e, params): {
36 switch(moduleType) {
37 case TEnumDecl(e2): {
38 if(!compareEnumTypes(e.get(), e2.get())) {
39 trace("Enum types not equal");
40 }
41 }
42 case _: trace("Module wasn't enum type");
43 }
44 }
45 case TType(d, params): {
46 switch(moduleType) {
47 case TTypeDecl(d2): {
48 if(!compareDefTypes(d.get(), d2.get())) {
49 trace("Def types not equal");
50 }
51 }
52 case _: trace("Module wasn't def type");
53 }
54 }
55 case TAbstract(a, params): {
56 switch(moduleType) {
57 case TAbstract(a2): {
58 if(!compareDefTypes(a.get(), a2.get())) {
59 trace("Abstract types not equal");
60 }
61 }
62 case _: trace("Module wasn't abstract type");
63 }
64 }
65 case _:
66 }
67 }
68
69 static function compareClassTypes(c1: ClassType, c2: ClassType): Bool {
70 return (
71 c1.name == c2.name &&
72 c1.module == c2.module &&
73 c1.pack.toString() == c2.pack.toString() &&
74 Std.string(c1.pos) == Std.string(c2.pos) &&
75 c1.isPrivate == c2.isPrivate &&
76 c1.isInterface == c2.isInterface &&
77 c1.isFinal == c2.isFinal &&
78 c1.isExtern == c2.isExtern &&
79 c1.isAbstract == c2.isAbstract
80 );
81 }
82
83 static function compareEnumTypes(e1: EnumType, e2: EnumType): Bool {
84 return (
85 e1.name == e2.name &&
86 e1.module == e2.module &&
87 e1.pack.toString() == e2.pack.toString() &&
88 e1.names.toString() == e2.names.toString() &&
89 Std.string(e1.pos) == Std.string(e2.pos) &&
90 e1.isPrivate == e2.isPrivate &&
91 e1.isExtern == e2.isExtern
92 );
93 }
94
95 static function compareDefTypes(d1: DefType, d2: DefType): Bool {
96 return (
97 d1.name == d2.name &&
98 d1.module == d2.module &&
99 d1.pack.toString() == d2.pack.toString() &&
100 Std.string(d1.pos) == Std.string(d2.pos) &&
101 d1.isPrivate == d2.isPrivate &&
102 d1.isExtern == d2.isExtern
103 );
104 }
105
106 static function compareAbstractTypes(a1: AbstractType, a2: AbstractType): Bool {
107 return (
108 a1.name == a2.name &&
109 a1.module == a2.module &&
110 a1.pack.toString() == a2.pack.toString() &&
111 Std.string(a1.pos) == Std.string(a2.pos) &&
112 a1.isPrivate == a2.isPrivate &&
113 a1.isExtern == a2.isExtern
114 );
115 }
116 }
117 #end
0 --main Main
1 --macro Main.MacroClass.start()
2 --interp
0 class Main {
1 static function main() {
2 trace(null());
3 }
4 }
0 Main.hx:3: characters 9-13 : This expression cannot be called
1 Main.hx:3: characters 9-13 : ... For function argument 'v'
0 abstract SerArray<S>(Array<S>) {
1 public dynamic function onChange():Void {};
2 }
3
4 class Main {
5 static function main() {}
6 }
0 Main.hx:2: characters 2-44 : Invalid modifier: dynamic on method of abstract
0 class Main {
1 static function main() {
2 var foo = {"a": 1, "b": 1, "c": 1};
3 test();
4 trace($i{"wtf"});
5 }
6
7 static macro function test() {
8 var options:Array<haxe.macro.Expr> = [
9 for (s in ["a", "b", "c"])
10 macro @:pos(pos) $p{["foo", s]}
11 ];
12 return macro $b{options};
13 }
14 }
0 Main.hx:5: characters 9-11 : Reification $i is not allowed outside of `macro` expression
1 Main.hx:5: characters 9-11 : Reification $i is not allowed outside of `macro` expression
0 extern class Main {
1 overload function test(b:Bool):Void;
2 @:require(false) overload function test(i:Int):Void;
3 @:require(false) overload function test(s:String):Void;
4 }
0 abstract AbstractFields(Dynamic) {
1 static function bar() {}
2 }
0 class ClassFields {
1 static function bar() {}
2 }
0 import AbstractFields.baz;
1
2 function main() {}
0 import ClassFields.baz;
1
2 function main() {}
0 import EnumFields.baz;
1
2 function main() {}
0 import ModuleFields.baz;
1
2 function main() {}
0 import Types.Baz;
1
2 function main() {}
0 ImportAbstractField.hx:1: characters 1-27 : Abstract<AbstractFields> has no field baz (Suggestion: bar)
0 ImportClassField.hx:1: characters 1-24 : Class<ClassFields> has no field baz (Suggestion: bar)
0 ImportEnumField.hx:1: characters 1-23 : Enum<EnumFields> has no field baz (Suggestion: bar)
0 ImportModuleField.hx:1: characters 1-25 : Module ModuleFields does not define field baz (Suggestion: bar)
0 ImportSubtype.hx:1: characters 1-18 : Module Types does not define type Baz (Suggestion: Bar)
0 class Main {
1 public var test:Int;
2 public function set_test(i:String) {
3 test = 42;
4 }
5 }
0 class Main {
1 static function main() {
2 final foo:Foo = {
3 a: 0,
4 b: 0,
5 c: 0,
6 a: 0,
7 }
8 final foo = {
9 a: 0,
10 b: 0,
11 c: 0,
12 a: 0,
13 }
14 final foo:CFoo = {
15 a: 0,
16 b: 0,
17 a: 0,
18 }
19 }
20 }
21
22 typedef Foo = {
23 a:Int,
24 b:Int,
25 c:Int,
26 }
27
28 typedef FooAdd = {
29 d:Int,
30 }
31
32 @:structInit
33 class CFoo {
34 var a:Int;
35 var b:Int;
36 }
0 Main.hx:7: characters 4-5 : Duplicate field in object declaration : a
1 Main.hx:13: characters 4-5 : Duplicate field in object declaration : a
2 Main.hx:18: characters 4-5 : Duplicate field in object declaration : a
0 import haxe.extern.EitherType as Or;
1
2 typedef Callback = Or<
3 Or<
4 () -> Void,
5 (a:Int) -> Void
6 >,
7 (a:Int, b:Int) -> Void
8 >;
9
10 class Main {
11 static function main() {
12 final foo:Callback = a -> {
13 $type(a); // Unknown<0> instead of Int
14 return;
15 }
16 }
17 }
0 -cp src
1 -main Main
2 --interp
0 Main.hx:14: characters 10-11 : Warning : Int
0 package;
1
2 #if macro
3 import haxe.macro.Context;
4 import haxe.macro.Expr;
5 import haxe.macro.Type;
6
7 using haxe.macro.ExprTools;
8 using haxe.macro.TypeTools;
9 #end
10
11 class Bar
12 {
13 public function new()
14 {
15 trace('New Bar');
16 }
17
18 public function nonmacro_func(val:String)
19 {
20 trace('Hello runtime: $val');
21 }
22
23 public macro function macro_func(this_expr:Expr) // :this (should refer to the Bar instance on the Foo)
24 {
25 var this_ident:String = get_this_ident(this_expr);
26 trace('${ this_expr.toString() } computed this_ident as: ${ this_ident }');
27
28 var code = '${ this_ident }.nonmacro_func("${ this_ident }")';
29 return Context.parse(code, Context.currentPos());
30 }
31
32 #if macro
33 static function get_this_ident(this_expr:Expr):String
34 {
35 // Read the ident from the source code
36 return switch (this_expr.expr) {
37 case EMeta(_, e):
38 var info = Context.getPosInfos(this_expr.pos);
39 var bytes = sys.io.File.getBytes(info.file);
40 bytes.getString(info.min, info.max-info.min);
41 default:
42 // Not in the above form? Hmm...
43 trace('Unexpected this resolution: ${ this_expr.toString() }');
44 this_expr.toString();
45 }
46 }
47 #end
48 }
0 class Foo
1 {
2 var _bar_private:Bar;
3
4 public function new()
5 {
6 trace('New foo');
7 _bar_private = new Bar();
8 }
9
10 public var bar(get,null):Bar;
11 public function get_bar():Bar return _bar_private;
12 }
0 class Main
1 {
2 public static function main()
3 {
4 var foo = new Foo();
5 foo.bar.macro_func();
6 }
7 }
0 Bar.hx:27: @:storedTypedExpr 3 computed this_ident as: foo.bar
0 #if !macro @:build(Main.error()) #end
1 class Main {
2 var field:Int = 0;
3 static function main() {}
4 }
5
6 #if macro
7 function error() {
8 var fields = haxe.macro.Context.getBuildFields();
9 haxe.macro.Context.info("Context.info", fields[0].pos);
10 haxe.macro.Context.warning("Context.warning", fields[0].pos);
11 haxe.macro.Context.error("Context.error", fields[0].pos);
12
13 return null;
14 }
15 #end
16
0 -cp src
1 -main Main
2 --interp
3 --display "Main.hx@0@diagnostics"
0 [{"file":"$$normPath(::cwd::/,true)Main.hx","diagnostics":[{"kind":2,"severity":3,"range":{"start":{"line":2,"character":1},"end":{"line":2,"character":19}},"args":"Context.info","relatedInformation":[]},{"kind":2,"severity":2,"range":{"start":{"line":2,"character":1},"end":{"line":2,"character":19}},"args":"Context.warning","relatedInformation":[]},{"kind":2,"severity":1,"range":{"start":{"line":2,"character":1},"end":{"line":2,"character":19}},"args":"Context.error","relatedInformation":[]},{"kind":2,"severity":1,"range":{"start":{"line":0,"character":11},"end":{"line":0,"character":18}},"args":"Build failure","relatedInformation":[]}]}]
0 macro function test() {
1 foo();
2 return macro null;
3 }
4
5 #if macro
6 function foo() {
7 throw "up";
8 }
9 #end
10
11 function main() {
12 test();
13 }
0 Main.hx:8: characters 2-7 : Uncaught exception up
1 Main.hx:2: characters 2-7 : Called from here
2 Main.hx:13: characters 2-8 : Called from here
0 compile-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] Main.hx:8: characters 2-7
1
2 8 | throw "up";
3 | ^^^^^
4 | Uncaught exception up
5
6 2 | foo();
7 | ^^^^^
8 | Called from here
9
10 13 | test();
11 | ^^^^^^
12 | Called from here
13
0 Main.hx:15: characters 4-15 : Warning : This case is unused
1 Main.hx:20: characters 4-14 : Warning : This case is unused
2 Main.hx:21: characters 4-15 : Warning : This case is unused
3 Main.hx:26: characters 6-11 : Warning : This pattern is unused
4 Main.hx:32: characters 7-18 : Warning : This pattern is unused
5 Main.hx:44: characters 4-32 : Warning : This case is unused
6 Main.hx:50: characters 4-19 : Warning : This case is unused
7 Main.hx:55: characters 4-15 : Warning : This case is unused
8 Main.hx:60: characters 4-16 : Warning : This case is unused
9 Main.hx:66: characters 9-15 : Warning : This pattern is unused
0 Main.hx:15: characters 4-15 : Warning : (WUnusedPattern) This case is unused
1 Main.hx:20: characters 4-14 : Warning : (WUnusedPattern) This case is unused
2 Main.hx:21: characters 4-15 : Warning : (WUnusedPattern) This case is unused
3 Main.hx:26: characters 6-11 : Warning : (WUnusedPattern) This pattern is unused
4 Main.hx:32: characters 7-18 : Warning : (WUnusedPattern) This pattern is unused
5 Main.hx:44: characters 4-32 : Warning : (WUnusedPattern) This case is unused
6 Main.hx:50: characters 4-19 : Warning : (WUnusedPattern) This case is unused
7 Main.hx:55: characters 4-15 : Warning : (WUnusedPattern) This case is unused
8 Main.hx:60: characters 4-16 : Warning : (WUnusedPattern) This case is unused
9 Main.hx:66: characters 9-15 : Warning : (WUnusedPattern) This pattern is unused
+0
-1
tests/misc/projects/Issue2996/A.hx less more
0 abstract A(String) {}
+0
-5
tests/misc/projects/Issue2996/Main.hx less more
0 import pack.B;
1
2 class Main {
3
4 }
+0
-1
tests/misc/projects/Issue2996/compile1.hxml less more
0 --display Main.hx@0@resolve@A
+0
-3
tests/misc/projects/Issue2996/compile1.hxml.stderr less more
0 <list>
1 <pos>$$normPath(::cwd::/A.hx):1: characters 1-22</pos>
2 </list>
+0
-1
tests/misc/projects/Issue2996/compile2.hxml less more
0 --display Main.hx@0@resolve@C
+0
-3
tests/misc/projects/Issue2996/compile2.hxml.stderr less more
0 <list>
1 <pos>$$normPath(::cwd::/pack/B.hx):3: characters 1-11</pos>
2 </list>
+0
-3
tests/misc/projects/Issue2996/pack/B.hx less more
0 package pack;
1
2 class C {}
0 Main.hx:8: characters 9-15 : Warning : Usage of this typedef is deprecated
1 Main.hx:9: characters 9-19 : Warning : Usage of this typedef is deprecated
2 Main.hx:10: characters 9-14 : Warning : Usage of this typedef is deprecated
3 Main.hx:18: characters 13-19 : Warning : This typedef is deprecated in favor of MyClass
4 Main.hx:19: characters 9-14 : Warning : Usage of this typedef is deprecated
5 Main.hx:20: characters 13-22 : Warning : This typedef is deprecated in favor of MyAbstract
6 Main.hx:32: characters 9-13 : Warning : Usage of this enum is deprecated
7 Main.hx:36: characters 9-14 : Warning : Usage of this enum field is deprecated
8 Main.hx:4: characters 9-16 : Warning : Usage of this class is deprecated
9 Main.hx:5: characters 9-20 : Warning : Usage of this class is deprecated
10 Main.hx:6: characters 9-15 : Warning : Usage of this enum is deprecated
11 Main.hx:15: characters 9-22 : Warning : Usage of this class is deprecated
12 Main.hx:16: characters 9-15 : Warning : Usage of this enum is deprecated
13 Main.hx:17: characters 9-29 : Warning : Usage of this class is deprecated
14 Main.hx:18: characters 9-21 : Warning : Usage of this class is deprecated
15 Main.hx:20: characters 9-28 : Warning : Usage of this class is deprecated
16 Main.hx:23: characters 9-24 : Warning : Usage of this field is deprecated
17 Main.hx:24: characters 9-23 : Warning : Usage of this field is deprecated
18 Main.hx:25: characters 9-27 : Warning : Usage of this field is deprecated
19 Main.hx:26: characters 17-35 : Warning : Usage of this field is deprecated
20 Main.hx:27: characters 9-25 : Warning : Usage of this field is deprecated
21 Main.hx:28: characters 17-33 : Warning : Usage of this field is deprecated
22 Main.hx:31: characters 11-15 : Warning : Usage of this enum is deprecated
23 Main.hx:35: characters 11-16 : Warning : Usage of this enum field is deprecated
0 Main.hx:8: characters 9-15 : Warning : (WDeprecated) Usage of this typedef is deprecated
1 Main.hx:9: characters 9-19 : Warning : (WDeprecated) Usage of this typedef is deprecated
2 Main.hx:10: characters 9-14 : Warning : (WDeprecated) Usage of this typedef is deprecated
3 Main.hx:18: characters 13-19 : Warning : (WDeprecated) This typedef is deprecated in favor of MyClass
4 Main.hx:19: characters 9-14 : Warning : (WDeprecated) Usage of this typedef is deprecated
5 Main.hx:20: characters 13-22 : Warning : (WDeprecated) This typedef is deprecated in favor of MyAbstract
6 Main.hx:32: characters 9-13 : Warning : (WDeprecated) Usage of this enum is deprecated
7 Main.hx:36: characters 9-14 : Warning : (WDeprecated) Usage of this enum field is deprecated
8 Main.hx:4: characters 9-16 : Warning : (WDeprecated) Usage of this class is deprecated
9 Main.hx:5: characters 9-20 : Warning : (WDeprecated) Usage of this class is deprecated
10 Main.hx:6: characters 9-15 : Warning : (WDeprecated) Usage of this enum is deprecated
11 Main.hx:15: characters 9-22 : Warning : (WDeprecated) Usage of this class is deprecated
12 Main.hx:16: characters 9-15 : Warning : (WDeprecated) Usage of this enum is deprecated
13 Main.hx:17: characters 9-29 : Warning : (WDeprecated) Usage of this class is deprecated
14 Main.hx:18: characters 9-21 : Warning : (WDeprecated) Usage of this class is deprecated
15 Main.hx:20: characters 9-28 : Warning : (WDeprecated) Usage of this class is deprecated
16 Main.hx:23: characters 9-24 : Warning : (WDeprecated) Usage of this field is deprecated
17 Main.hx:24: characters 9-23 : Warning : (WDeprecated) Usage of this field is deprecated
18 Main.hx:25: characters 9-27 : Warning : (WDeprecated) Usage of this field is deprecated
19 Main.hx:26: characters 17-35 : Warning : (WDeprecated) Usage of this field is deprecated
20 Main.hx:27: characters 9-25 : Warning : (WDeprecated) Usage of this field is deprecated
21 Main.hx:28: characters 17-33 : Warning : (WDeprecated) Usage of this field is deprecated
22 Main.hx:31: characters 11-15 : Warning : (WDeprecated) Usage of this enum is deprecated
23 Main.hx:35: characters 11-16 : Warning : (WDeprecated) Usage of this enum field is deprecated
0 extern inline overload function test(a:String) {}
1 extern inline overload function test(a:Int) {}
2
3 function main() {
4 test(function() {
5 var x:String = 1;
6 });
7 }
0 --main Main2
1 -js js.js
2 --no-output
0 Main2.hx:6: characters 3-20 : Int should be String
1 Main2.hx:6: characters 3-20 : ... For function argument 'a'
0 Main.hx:7: characters 18-23 : Pattern variables must be lower-case
0 Main.hx:7: characters 18-23 : Unknown identifier : VALUE, pattern variables must be lower-case or with `var ` prefix
0 User.hx:1: characters 20-47 : Type not found : ThisObviouslyDoesntExist
1 Main.hx:1: lines 1-5 : ... Defined in this class
0 User.hx:1: characters 20-47 : Type not found : ThisObviouslyDoesntExist
0 compile-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] User.hx:1: characters 20-47
1
2 1 | class User extends ThisObviouslyDoesntExist<T> {}
3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
4 | Type not found : ThisObviouslyDoesntExist
5
0 class NamedLocal {
1 static function main() {
2 // shouldn't be parsed as a call
3 function test(str) {
4 trace(str);
5 throw "This function shouldn't have been called!!";
6 }
7 ("hello");
8 }
9 }
0 class UnnamedLocal {
1 static function main() {
2 function(str) {
3 trace(str);
4 }
5 ("hello");
6 }
7 }
0 UnnamedLocal.hx:3: lines 3-5 : Unnamed lvalue functions are not supported
0 Main5.hx:4: characters 10-13 : Array<{ v : fromV.T }> should be fromV.T
1 Main5.hx:4: characters 3-13 : Recursive implicit cast
0 Main5.hx:4: characters 3-13 : Array<{ v : fromV.T }> should be Ref<fromV.T>
0 compile-fail.hxml
1 -D message-reporting=indent
0 Main.hx:11: characters 11-14 : Field a has different @:native value than in superclass
1 Main.hx:6: characters 18-19 : Base field is defined here
0 compile-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] Main.hx:11: characters 11-14
1
2 11 | @:native("z") override public function a() {}
3 | ^^^
4 | Field a has different @:native value than in superclass
5
6 6 | public function a() {}
7 | ^
8 | Base field is defined here
9
0 compile-fail.hxml
1 -D message-reporting=indent
0 Main.hx:8: characters 9-18 : Could not find a suitable overload, reasons follow
1 Main.hx:8: characters 9-18 : Overload resolution failed for () -> Void
2 Main.hx:8: characters 13-17 : Too many arguments
3 Main.hx:8: characters 9-18 : Overload resolution failed for (t : f.T) -> Void
4 Main.hx:8: characters 13-17 : Constraint check failure for f.T
5 Main.hx:8: characters 13-17 : String should be Int
6 Main.hx:8: characters 13-17 : For function argument 't'
7 Main.hx:9: characters 9-16 : Could not find a suitable overload, reasons follow
8 Main.hx:9: characters 9-16 : Overload resolution failed for () -> Void
9 Main.hx:9: characters 13-15 : Too many arguments
10 Main.hx:9: characters 9-16 : Overload resolution failed for (t : f.T) -> Void
11 Main.hx:9: characters 13-15 : Constraint check failure for f.T
12 Main.hx:9: characters 13-15 : { } should be Int
13 Main.hx:9: characters 13-15 : For function argument 't'
0 compile-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] Main.hx:8: characters 9-18
1
2 8 | C.f("hi");
3 | ^^^^^^^^^
4 | Could not find a suitable overload, reasons follow
5
6 | Overload resolution failed for () -> Void
7
8 8 | C.f("hi");
9 | ^^^^
10 | Too many arguments
11
12 | Overload resolution failed for (t : f.T) -> Void
13
14 8 | C.f("hi");
15 | ^^^^
16 | Constraint check failure for f.T
17 | String should be Int
18 | For function argument 't'
19
20 [ERROR] Main.hx:9: characters 9-16
21
22 9 | C.f({});
23 | ^^^^^^^
24 | Could not find a suitable overload, reasons follow
25
26 | Overload resolution failed for () -> Void
27
28 9 | C.f({});
29 | ^^
30 | Too many arguments
31
32 | Overload resolution failed for (t : f.T) -> Void
33
34 9 | C.f({});
35 | ^^
36 | Constraint check failure for f.T
37 | { } should be Int
38 | For function argument 't'
39
0 Main.hx:7: characters 3-4 : Warning : Usage of this field is deprecated
0 Main.hx:7: characters 3-4 : Warning : (WDeprecated) Usage of this field is deprecated
0 Main1.hx:2: characters 2-17 : v: Static final variable must be initialized
0 Main1.hx:2: characters 2-17 : Static final variable must be initialized
0 Main2.hx:5: characters 3-8 : Cannot access field or identifier v for writing
0 Main2.hx:5: characters 3-4 : This expression cannot be accessed for writing
0 Main3.hx:9: characters 3-8 : Cannot access field or identifier v for writing
0 Main3.hx:9: characters 3-4 : This expression cannot be accessed for writing
0 Main4.hx:2: characters 2-14 : final field y must be initialized immediately or in the constructor
0 Main4.hx:1: characters 7-11 : Some final fields are uninitialized in this class
1 Main4.hx:2: characters 8-9 : Uninitialized field
0 compile5-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] Main5.hx:1: lines 1-6
1
2 1 | class Main {
3 - | [...]
4 6 | }
5 |
6 | This class has uninitialized final vars, which requires a constructor
7
8 [ERROR] Main5.hx:2: characters 8-9
9
10 2 | final v:Int;
11 | ^
12 | Example of an uninitialized final var
13
0 compile-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] Mismatch.hx:6: characters 19-26
1
2 6 | p.then(x -> 10, e -> "");
3 | ^^^^^^^
4 | (e : Unknown<0>) -> String should be Null<js.lib.PromiseHandler<Dynamic, Int>>
5 | For optional function argument 'onRejected'
6
0 #if macro
1 import haxe.macro.Expr;
2 import haxe.macro.Context;
3 #end
4
5 class Main {
6 #if !macro
7 static function main()
8 test();
9 #end
10
11 static macro function test() {
12 try Context.typeof(macro foo)
13 catch (e) Context.warning("foo", (macro 0).pos);
14 return macro {};
15 }
16 }
0 --main Main
1 --display "Main.hx@0@diagnostics"
0 [{"file":"$$normPath(::cwd::/,true)Main.hx","diagnostics":[{"kind":2,"severity":2,"range":{"start":{"line":13,"character":42},"end":{"line":13,"character":43}},"args":"foo","relatedInformation":[]}]}]
0 compile-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] Main.hx:3: characters 21-25
1
2 3 | Sys.println(main["foo"]);
3 | ^^^^
4 | Array access is not allowed on () -> Unknown<0>
5 | For function argument 'v'
6
00 Fail.hx:7: characters 8-12 : error: Void should be haxe.NotVoid
11 Fail.hx:7: characters 8-12 : ... have: (...) -> Void
22 Fail.hx:7: characters 8-12 : ... want: (...) -> haxe.NotVoid
3 Fail.hx:7: characters 8-12 : ... For function argument 'f'
43 Fail.hx:8: characters 8-16 : error: FakeVoid should be haxe.NotVoid
54 Fail.hx:8: characters 8-16 : ... have: (...) -> FakeVoid
65 Fail.hx:8: characters 8-16 : ... want: (...) -> haxe.NotVoid
7 Fail.hx:8: characters 8-16 : ... For function argument 'f'
0 compile-fail.hxml
1 -D message-reporting=indent
0 Fail.hx:7: characters 8-12 : error: Void should be haxe.NotVoid
1 Fail.hx:7: characters 8-12 : have: (...) -> Void
2 Fail.hx:7: characters 8-12 : want: (...) -> haxe.NotVoid
3 Fail.hx:8: characters 8-16 : error: FakeVoid should be haxe.NotVoid
4 Fail.hx:8: characters 8-16 : have: (...) -> FakeVoid
5 Fail.hx:8: characters 8-16 : want: (...) -> haxe.NotVoid
0 -D messages-log-file=logfile-02-fail.hxml.stderr
1 compile-fail.hxml
0 -D messages-log-file=logfile-03-fail.hxml.stderr
1 -D messages-log-format=pretty
2 -D message-reporting=indent
3 compile-fail.hxml
0 -D messages-log-file=logfile-04-fail.hxml.stderr
1 -D messages-log-format=classic
2 -D message-reporting=pretty
3 compile-fail.hxml
0 compile-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] Fail.hx:7: characters 8-12
1
2 7 | test(void);
3 | ^^^^
4 | error: Void should be haxe.NotVoid
5 | have: (...) -> Void
6 | want: (...) -> haxe.NotVoid
7
8 [ERROR] Fail.hx:8: characters 8-16
9
10 8 | test(fakeVoid);
11 | ^^^^^^^^
12 | error: FakeVoid should be haxe.NotVoid
13 | have: (...) -> FakeVoid
14 | want: (...) -> haxe.NotVoid
15
0 Main.hx:6: lines 6-8 : opAssign: Assignment overloading is not supported
0 Main.hx:6: lines 6-8 : Assignment overloading is not supported
0 enum ScreenMode<T> {
1 AAA;
2 AAB;
3 }
4 enum abstract ScreenRatio(Int) {
5 var ZZA;
6 var ZZB;
7 }
8
9 class Main {
10 static final AAF = 0;
11 static final ZZF = 0;
12 static function main() {
13 var mode = ScreenMode.AAA;
14 switch(mode) {
15 case ScreenMoze.AAZ:
16 case _:
17 }
18 var mode2 = ScreenRatio.ZZA;
19 switch(mode2) {
20 case ScreenRazio.ZZZ:
21 case _:
22 }
23 }
24 }
0 Main1.hx:16: characters 9-23 : Warning : Potential typo detected (expected similar values are ScreenMode.AAA, ScreenMode.AAB)
1 Main1.hx:16: characters 9-23 : Only inline or read-only (default, never) fields can be used as a pattern
2 Main1.hx:21: characters 9-24 : Warning : Potential typo detected (expected similar values are ScreenRatio.ZZA, ScreenRatio.ZZB)
3 Main1.hx:21: characters 9-24 : Only inline or read-only (default, never) fields can be used as a pattern
0 Main.hx:5: characters 9-10 : Warning : Usage of this field is deprecated
0 Main.hx:5: characters 9-10 : Warning : (WDeprecated) Usage of this field is deprecated
77 abstract Abstr(Int) {
88 public inline function new() {
99 trace(() -> this);
10 this = 0;
1011 }
1112 }
0 Main.hx:4: characters 15-16 : Warning : Local variable v might be used before being initialized
1 Main.hx:10: characters 15-19 : Warning : this might be used before assigning a value to it
0 Main.hx:4: characters 15-16 : Warning : (WVarInit) Local variable v might be used before being initialized
1 Main.hx:10: characters 15-19 : Warning : (WVarInit) this might be used before assigning a value to it
00 Main.hx:13: characters 1-24 : Abstract chain detected: Test2 -> Test -> Test2
1 Main.hx:6: lines 6-10 : ... Defined in this class
21 Main.hx:6: lines 6-10 : Abstract underlying type cannot be recursive
0 Main.hx:13: characters 3-18 : Cannot call super.dynMethod since it's a dynamic method
0 Main.hx:13: characters 3-20 : Cannot call super.dynMethod since it's a dynamic method
0 class Main {
1 static function main() {
2 switch Std.random(0) {
3 case NumpadSubtract:
4 case NumpadDecimal:
5 }
6 switch Std.random(0) {
7 case 1, 2, NumpadSubtract:
8 case _:
9 }
10 }
11 }
0 Main.hx:4: characters 9-23 : Unknown identifier : NumpadSubtract, pattern variables must be lower-case or with `var ` prefix
1 Main.hx:5: characters 9-22 : Unknown identifier : NumpadDecimal, pattern variables must be lower-case or with `var ` prefix
2 Main.hx:5: characters 4-23 : Warning : (WUnusedPattern) This case is unused
3 Main.hx:8: characters 15-29 : Unknown identifier : NumpadSubtract, pattern variables must be lower-case or with `var ` prefix
4 Main.hx:8: characters 15-29 : Variable NumpadSubtract must appear exactly once in each sub-pattern
0 import haxe.macro.Compiler;
1 import haxe.macro.Context;
2
3 function init() {
4 var e = macro 42;
5 Context.typeof(e);
6 if (Context.defined("haxe")) Context.warning("ok", (macro 0).pos);
7 Compiler.define("foo", "foo");
8
9 Context.onAfterInitMacros(() -> {
10 Context.warning("after init 1", (macro 0).pos);
11 Compiler.define("bar", "bar");
12 Context.typeof(e);
13 });
14 Compiler.include("hax.ds", true, true);
15 Context.onAfterInitMacros(() -> {
16 Context.warning("after init 2", (macro 0).pos);
17 });
18 }
0 Macro.hx:7: characters 60-61 : Warning : ok
1 Macro.hx:11: characters 42-43 : Warning : after init 1
2 Macro.hx:12: characters 3-32 : Warning : This API should only be used from initialization macros.
3 Package "hax.ds" was not found in any of class paths
4 Macro.hx:17: characters 42-43 : Warning : after init 2
0 Macro.hx:6: characters 2-19 : Warning : Cannot use this API from initialization macros.
1 Macro.hx:6: characters 2-19 : ... Use `Context.onAfterInitMacros` to register a callback to run when context is ready.
2 Macro.hx:7: characters 60-61 : Warning : ok
3 Macro.hx:11: characters 42-43 : Warning : after init 1
4 Macro.hx:12: characters 3-32 : Warning : This API should only be used from initialization macros.
5 Package "hax.ds" was not found in any of class paths
6 Macro.hx:17: characters 42-43 : Warning : after init 2
0 Main3.hx:4: characters 2-3 : Unexpected }
0 Main3.hx:4: characters 2-3 : Expected , or )
0 compile-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] Foo.hx:2: characters 1-18
1
2 2 | typedef A = Float;
3 | ^^^^^^^^^^^^^^^^^
4 | Name A is already defined in this module
5
6 1 | typedef A = Int;
7 | ^
8 | Previous declaration here
9
0 Main.hx:2: characters 2-7 : Static method cannot be final
0 Main.hx:2: characters 2-7 : Invalid modifier combination: final + static
11 Main.hx:9: lines 9-11 : Cannot override final constructor
0 compile-fail.hxml
1 -D message-reporting=indent
0 Uncaught exception Stack overflow
1 Main.hx:1: character 1 : Called from here
2 Main.hx:8: characters 4-9 : Called from here
3 Main.hx:8: characters 4-9 : Called from here
4 Main.hx:8: characters 4-9 : Called from here
5 Main.hx:8: characters 4-9 : Called from here
6 Main.hx:8: characters 4-9 : Called from here
7 Main.hx:8: characters 4-9 : Called from here
8 Main.hx:8: characters 4-9 : Called from here
9 Main.hx:8: characters 4-9 : Called from here
10 Main.hx:8: characters 4-9 : Called from here
11 Main.hx:8: characters 4-9 : Called from here
12 Main.hx:8: characters 4-9 : Called from here
13 Main.hx:8: characters 4-9 : Called from here
14 Main.hx:8: characters 4-9 : Called from here
15 Main.hx:8: characters 4-9 : Called from here
16 Main.hx:8: characters 4-9 : Called from here
17 Main.hx:8: characters 4-9 : Called from here
18 Main.hx:8: characters 4-9 : Called from here
19 Main.hx:10: characters 3-8 : Called from here
20 Main.hx:3: characters 3-9 : Called from here
0 compile-fail.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [ERROR] (unknown position)
1
2 | Uncaught exception Stack overflow
3
4 -> Main.hx:1: character 1
5
6 1 | class Main {
7 | ^
8 | Called from here
9
10 8 | log();
11 | ^^^^^
12 | Called from here
13
14 | Called from here
15
16 | Called from here
17
18 | Called from here
19
20 | Called from here
21
22 | Called from here
23
24 | Called from here
25
26 | Called from here
27
28 | Called from here
29
30 | Called from here
31
32 | Called from here
33
34 | Called from here
35
36 | Called from here
37
38 | Called from here
39
40 | Called from here
41
42 | Called from here
43
44 | Called from here
45
46 10 | log();
47 | ^^^^^
48 | Called from here
49
50 3 | test();
51 | ^^^^^^
52 | Called from here
53
0 compile2.hxml
1 -D message-reporting=pretty
2 -D no-color
0 [WARNING] Macro2.hx:12: characters 25-39
1
2 12 | Context.warning(("1" :DeprecatedType), Context.currentPos());
3 | ^^^^^^^^^^^^^^
4 | (WDeprecated) This typedef is deprecated in favor of String
5
6 [WARNING] (unknown position)
7
8 | 1
9
10 [WARNING] (unknown position)
11
12 | 2
13
14 [WARNING] (unknown position)
15
16 | 3
17
18 [WARNING] (unknown position)
19
20 | i123|i123
21
0 Macro2.hx:12: characters 25-39 : Warning : This typedef is deprecated in favor of String
0 Macro2.hx:12: characters 25-39 : Warning : (WDeprecated) This typedef is deprecated in favor of String
11 Warning : 1
22 Warning : 2
33 Warning : 3
00 Macro.hx:3: characters 60-69 : Invalid assign
1 Fail.hx:1: lines 1-7 : ... Defined in this class
21 Fail.hx:4: characters 3-12 : Invalid assign
32 Fail.hx:5: characters 3-12 : Invalid assign
0 Main.hx:6: characters 2-7 : Macro abstract constructors are not supported
0 Main.hx:6: characters 2-7 : Invalid modifier: macro on abstract constructor
0 class Main {
1 static function main() {
2 var s:Null<String> = null;
3 trace(s = null ? "null" : "not null");
4 }
5 }
0 Main.hx:4: characters 13-17 : Cannot use null as ternary condition
0 Main1.hx:2: characters 2-8 : extern modifier is not allowed on enum abstract fields
0 Main1.hx:2: characters 2-8 : Invalid modifier: extern on field of enum abstract
0 Main.hx:3: characters 2-40 : foo: 'override' is not allowed on 'static' functions
1 Main.hx:4: characters 2-39 : bar: 'inline' is not allowed on 'dynamic' functions
0 Main.hx:3: characters 2-40 : Invalid modifier combination: override + static
1 Main.hx:4: characters 2-39 : Invalid modifier combination: dynamic + inline
00 Main.hx:8: characters 1-13 : @:structInit is not allowed on interfaces
1 Main.hx:9: lines 9-11 : ... Defined in this class
21 Main.hx:3: characters 15-26 : Foo does not have a constructor
0 class Main {
1 static function main() {
2 var foo = '5';
3 var bar = '5';
4 var isEqual = switch (bar) {
5 case 'foo$ foo': true;
6 case '\\ foo': true;
7 case '$foo': true;
8 default: false;
9 }
10 }
11 }
0 Main.hx:8: characters 10-14 : String interpolation is not allowed in case patterns
0 class C {
1 final x:Int;
2
3 function new() {
4 x = nonsense;
5 }
6 }
7
8 function main() {
9
10 }
0 -cp src
1 -main Main
2 --interp
0 Main.hx:5: characters 7-15 : Unknown identifier : nonsense
0 Main.hx:3: characters 3-4 : Warning : Usage of this class is deprecated
0 Main.hx:3: characters 3-4 : Warning : (WDeprecated) Usage of this class is deprecated
0 Main.hx:7: characters 9-13 : Warning : Usage of this field is deprecated
0 Main.hx:7: characters 9-13 : Warning : (WDeprecated) Usage of this field is deprecated
0 Main.hx:10: characters 3-17 : Cannot access field or identifier x for writing
0 Main.hx:10: characters 11-12 : This expression cannot be accessed for writing
0 @:autoBuild(FinalDisplayBuilder.build())
1 interface FinalDisplay {}
0 import haxe.macro.Context;
1
2 class FinalDisplayBuilder {
3 #if macro
4 public static function build() {
5 var cls = Context.getLocalClass().get();
6 if (!cls.isFinal) {
7 Context.fatalError('class needs to be final', cls.pos);
8 } else {
9 Sys.stderr().writeString(cls.name + " is very final\n");
10 }
11 return null;
12 }
13 #end
14 }
0 final class FinalDisplayTest implements FinalDisplay {} // here it works fine
1 final class FinalDisplayTestFailed implements FinalDisplay {} // seconds class shows: class needs to be final diagnostics(2)
2
3 function main() {}
0 FinalDisplayTestFailed is very final
1 FinalDisplayTest is very final
0 Main.hx:8: characters 9-20 : Foo is missing @:genericBuild meta. Was it removed by a macro?
0 Main.hx:9: characters 9-17 : Foo is missing @:genericBuild meta. Was it removed by a macro?
0 Main.hx:10: characters 3-14 : Warning : Usage of this field is deprecated
0 Main.hx:10: characters 3-14 : Warning : (WDeprecated) Usage of this field is deprecated
0 class Main {
1 static function main() {
2 final foo:Array<{x:Int, y:Int}> = [
3 {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1},
4 {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1}, {x: 0, y: 1}, {x: 0,}
5 ];
6 }
7 }
0 Main.hx:5: characters 74-81 : Object requires field y
1 Main.hx:5: characters 74-81 : { x : Int } should be { y : Int, x : Int }
2 Main.hx:5: characters 74-81 : ... { x : Int } has no field y
0 Main.hx:2: characters 2-52 : Abstract methods may not be dynamic
0 Main.hx:2: characters 2-52 : Invalid modifier combination: abstract + dynamic
0 Main.hx:8: characters 3-30 : Cannot force inline on abstract method
0 Main.hx:8: characters 3-9 : Cannot force inline on abstract method
0 Main.hx:2: characters 26-42 : Abstract methods may not be final
0 Main.hx:2: characters 26-42 : Invalid modifier combination: abstract + final
0 Main.hx:2: characters 34-50 : Abstract methods may not be inline
0 Main.hx:2: characters 34-50 : Invalid modifier combination: abstract + inline
0 Main.hx:2: characters 27-43 : Static methods may not be abstract
0 Main.hx:2: characters 27-43 : Invalid modifier combination: abstract + static
+0
-9
tests/misc/projects/Issue9619/abstract-structInit/Main.hx less more
0 @:structInit abstract class Abstract {
1
2 }
3
4 class Main extends Abstract {
5 static function main() {
6
7 }
8 }
+0
-2
tests/misc/projects/Issue9619/abstract-structInit/compile-fail.hxml less more
0 --main Main
1 --interp
+0
-2
tests/misc/projects/Issue9619/abstract-structInit/compile-fail.hxml.stderr less more
0 Main.hx:1: characters 1-13 : @:structInit is not allowed on abstract classes
1 Main.hx:1: lines 1-3 : ... Defined in this class
11 Main.hx:8: characters 3-36 : Constraint check failure for new.B
22 Main.hx:8: characters 3-36 : ... Foo should be BarLike
33 Main.hx:8: characters 3-36 : ... Foo has no field bar
4 Main.hx:10: characters 9-13 : Warning : Mono<Unknown<0>>
4 Main.hx:10: characters 9-13 : Warning : Mono<Unknown<0>>
0 function main() {
1 final var value:String;
2 }
0 class MainField {
1 static final var value = "1";
2
3 static function main() {}
4 }
0 function main() {
1 macro final var value:String;
2 }
0 MainField.hx:2: characters 9-18 : `final var` is not supported, use `final` instead
0 --main MainField
1 --display "MainField.hx@0@diagnostics"
0 [{"file":"$$normPath(::cwd::/,true)MainField.hx","diagnostics":[{"kind":4,"severity":1,"range":{"start":{"line":1,"character":8},"end":{"line":1,"character":17}},"args":"`final var` is not supported, use `final` instead","relatedInformation":[]}]}]
0 MainExpr.hx:2: characters 2-11 : `final var` is not supported, use `final` instead
0 --main MainExpr
1 --display "MainExpr.hx@0@diagnostics"
0 [{"file":"$$normPath(::cwd::/,true)MainExpr.hx","diagnostics":[{"kind":4,"severity":1,"range":{"start":{"line":1,"character":1},"end":{"line":1,"character":10}},"args":"`final var` is not supported, use `final` instead","relatedInformation":[]}]}]
0 MainMacro.hx:2: characters 8-17 : `final var` is not supported, use `final` instead
0 --main MainMacro
1 --display "MainMacro.hx@0@diagnostics"
0 [{"file":"$$normPath(::cwd::/,true)MainMacro.hx","diagnostics":[{"kind":4,"severity":1,"range":{"start":{"line":1,"character":7},"end":{"line":1,"character":16}},"args":"`final var` is not supported, use `final` instead","relatedInformation":[]}]}]
0 Main.hx:2: characters 2-19 : x: Cannot declare member variable in abstract
0 Main.hx:2: characters 2-19 : Cannot declare member variable in abstract
0 function main() {
1 var foo:Void->Void;
2 foo = function() {
3 trace("Hello");
4 haxe.Timer.delay(foo, 1);
5 };
6 }
0 -cp src
1 -main Main
2 --interp
0 class C {
1 function new<T=String>(){}
2 }
0 function method<T=String>() {}
0 Ctor.hx:2: characters 17-23 : Default type parameters are only supported on types
0 EnumCtor.hx:2: characters 6-12 : Default type parameters are only supported on types
0 Method.hx:1: characters 19-25 : Default type parameters are only supported on types
0 class Main {
1
2 static function main() {
3 var event : haxe.MainLoop.MainEvent = null;
4 var count = 0;
5 event = haxe.MainLoop.add(function() {
6 trace(count++);
7 if( count == 10 ) {
8 event.stop();
9 trace(haxe.MainLoop.hasEvents());
10 }
11 });
12
13 #if sys
14 // if we don't use native timer, this should execute before
15 var t = new haxe.Timer(100);
16 t.run = function() {
17 trace("BEFORE1");
18 t.stop();
19 };
20 #end
21
22 var t = new haxe.Timer(200);
23 var count = 0;
24 t.run = function() {
25 trace("T" + count++);
26 if( count == 5 )
27 t.stop();
28 };
29
30 #if sys
31 // if we don't use native timer, this should execute before
32 var t = new haxe.Timer(100);
33 t.run = function() {
34 trace("BEFORE2");
35 t.stop();
36 };
37 #end
38
39 #if sys
40 Sys.sleep(0.3);
41 #end
42
43 haxe.MainLoop.addThread(function() {
44 var event : haxe.MainLoop.MainEvent = null;
45 var count = 0;
46 event = haxe.MainLoop.add(function() {
47 trace(String.fromCharCode("A".code + count++));
48 if( count == 5 ) event.stop();
49 });
50 });
51 }
52
53 }
0 --main Main
1 --dce full
2 --interp
0 Main.hx:18: BEFORE1
1 Main.hx:35: BEFORE2
2 Main.hx:26: T0
3 Main.hx:48: A
4 Main.hx:7: 0
5 Main.hx:48: B
6 Main.hx:7: 1
7 Main.hx:48: C
8 Main.hx:7: 2
9 Main.hx:48: D
10 Main.hx:7: 3
11 Main.hx:48: E
12 Main.hx:7: 4
13 Main.hx:7: 5
14 Main.hx:7: 6
15 Main.hx:7: 7
16 Main.hx:7: 8
17 Main.hx:7: 9
18 Main.hx:10: false
19 Main.hx:26: T1
20 Main.hx:26: T2
21 Main.hx:26: T3
22 Main.hx:26: T4
0 Main.hx:2: characters 2-10 : Only extern functions may be overloaded on this target
0 Main.hx:2: characters 2-10 : Invalid modifier: overload is only supported on extern functions
0 Main.hx:2: characters 2-10 : Constructors cannot be overloaded on this target
0 Main.hx:2: characters 2-10 : Invalid modifier: overload on constructor
00 Main.hx:1: characters 1-8 : "0" is not a valid field name.
1 Main.hx:2: lines 2-4 : ... Defined in this class
2 Main.hx:1: characters 1-8 : "this" is not a valid field name.
3 Main.hx:2: lines 2-4 : ... Defined in this class
1 Main.hx:1: characters 1-8 : "this" is not a valid field name.
0 "0_variable" is not a valid variable name.
1 Main2.hx:6: characters 3-32 : ... Called from macro here
2 "var" is not a valid variable name.
3 Main2.hx:7: characters 3-25 : ... Called from macro here
4 "new" is not a valid variable name.
5 Main2.hx:8: characters 3-25 : ... Called from macro here
6 "foo \"\t\n" is not a valid variable name.
7 Main2.hx:9: characters 3-32 : ... Called from macro here
8 "0_catchVariable" is not a valid catch variable name.
9 Main2.hx:10: characters 3-25 : ... Called from macro here
10 "0_function" is not a valid function name.
11 Main2.hx:11: characters 3-24 : ... Called from macro here
12 "0_argument" is not a valid function argument name.
13 Main2.hx:12: characters 3-32 : ... Called from macro here
14 Main2.hx:13: characters 3-27 : Pattern variables must be lower-case
0 Main2.hx:6: characters 3-32 : "0_variable" is not a valid variable name.
1 Main2.hx:7: characters 3-25 : "var" is not a valid variable name.
2 Main2.hx:8: characters 3-25 : "new" is not a valid variable name.
3 Main2.hx:9: characters 3-32 : "foo \"\t\n" is not a valid variable name.
4 Main2.hx:10: characters 3-25 : "0_catchVariable" is not a valid catch variable name.
5 Main2.hx:11: characters 3-24 : "0_function" is not a valid function name.
6 Main2.hx:12: characters 3-32 : "0_argument" is not a valid function argument name.
7 Main2.hx:13: characters 3-27 : Unknown identifier : 0_patternVariable, pattern variables must be lower-case or with `var ` prefix
158 Main2.hx:14: characters 3-23 : "0_forVariable" is not a valid for variable name.
169 Main2.hx:15: characters 3-31 : "0_forVariableKey" is not a valid for variable name.
17 Main2.hx:15: characters 3-31 : "0_forVariableValue" is not a valid for variable name.
10 Main2.hx:15: characters 3-31 : "0_forVariableValue" is not a valid for variable name.
00 Main4.hx:3: characters 7-9 : Variable names starting with a dollar are not allowed: "$i"
11 Main4.hx:5: characters 17-19 : Catch variable names starting with a dollar are not allowed: "$i"
22 Main4.hx:7: characters 8-10 : For variable names starting with a dollar are not allowed: "$i"
3 Main4.hx:10: characters 9-11 : Pattern variables must be lower-case
3 Main4.hx:10: characters 9-11 : Unknown identifier : $i, pattern variables must be lower-case or with `var ` prefix
0 class Main {
1 static function main() {
2 while(Math.random() > 0.5) {
3 static var x = break;
4 }
5 }
6 }
0 Main.hx:4: characters 19-24 : Break outside loop
0 class Main {
1 static function main() {
2 while(Math.random() > 0.5) {
3 static var x = continue;
4 }
5 }
6 }
0 Main.hx:4: characters 19-27 : Continue outside loop
0 class Main {
1 static function main() {
2 function x() {}
3 static var y = x;
4 }
5 }
0 Main.hx:4: characters 18-19 : Accessing local variables in static initialization is not allowed
0 class Main {
1 static function main() {
2 var x = 1;
3 static var y = x;
4 }
5 }
0 Main.hx:4: characters 18-19 : Accessing local variables in static initialization is not allowed
0 class Main {
1 static function main() {
2 static var x = 1;
3 static var x = 2;
4 }
5 }
0 Main.hx:4: characters 14-15 : The expanded name of this local (main_x) conflicts with another static field
1 Main.hx:3: characters 14-15 : Conflicting field was found here
0 class Main {
1 static var main_x = 1;
2 static function main() {
3 static var x = 2;
4 }
5 }
0 Main.hx:4: characters 14-15 : The expanded name of this local (main_x) conflicts with another static field
1 Main.hx:2: characters 13-19 : Conflicting field was found here
0 class Main {
1 static function main() {
2 static var x = return;
3 }
4 }
0 Main.hx:3: characters 18-24 : This kind of control flow in static initialization is not allowed
0 class Main {
1 static function main() {
2
3 }
4
5 var x = 1;
6
7 function test() {
8 static var y = x;
9 }
10 }
0 Main.hx:9: characters 18-19 : Accessing `this` in static initialization is not allowed
0 #if macro
1 import haxe.macro.Context;
2
3 function init() {
4 var here = (macro here).pos;
5
6 Context.onAfterInitMacros(() -> {
7 Context.warning("1", here);
8 Context.onAfterInitMacros(() -> {
9 Context.warning("2", here);
10 });
11 });
12
13 Context.onGenerate((_) -> {
14 Context.warning("3", here);
15 Context.onGenerate((_) -> {
16 Context.warning("4", here);
17 });
18 });
19
20 Context.onAfterGenerate(() -> {
21 Context.warning("5", here);
22 Context.onAfterGenerate(() -> {
23 Context.warning("6", here);
24 });
25 });
26 }
27 #end
28
29 function main() {}
0 Main.hx:5: characters 20-24 : Warning : 1
1 Main.hx:9: lines 9-11 : Warning : This API should only be used from initialization macros.
2 Main.hx:5: characters 20-24 : Warning : 2
3 Main.hx:5: characters 20-24 : Warning : 3
4 Main.hx:5: characters 20-24 : Warning : 4
5 Main.hx:5: characters 20-24 : Warning : 5
6 Main.hx:5: characters 20-24 : Warning : 6
0 class SysExit0 {
1 static function main() {
2 Sys.stderr().writeString("Exiting with 0\n");
3 Sys.exit(0);
4 }
5 }
0 class SysExit1 {
1 static function main() {
2 Sys.stderr().writeString("Exiting with 1\n");
3 Sys.exit(1);
4 }
5 }
0 --main SysExit0
1 --interp
2
3 --next
4
5 --main SysExit0
6 --interp
0 Exiting with 0
1 Exiting with 0
0 --main SysExit0
1 --interp
2
3 --next
4
5 --main SysExit1
6 --interp
0 --main SysExit1
1 --interp
2
3 --next
4
5 --main SysExit0
6 --interp
0 --main SysExit1
1 --interp
2
3 --next
4
5 --main SysExit1
6 --interp
0 class Main {
1 static function f(t:Type.ValueType, t2:Type.ValueType,) {}
2 public static function main():Void {
3 f(TNull,TNull,);
4 foobar(
5 1,
6 2,
7 );
8 function blah(
9 a:Int,
10 b:Int,
11 ):Void {}
12 var a = (
13 a:Int,
14 b:Int,
15 ) -> 0;
16 var a:(
17 a:Int,
18 b:Int,
19 )->Int = null;
20 a = (a, b,) -> a + b;
21 trace(a(2, 3,) + moduleFoobar(5, 5,));
22 }
23
24 static function foobar(
25 a:Int,
26 b:Int,
27 ):Void {}
28 }
29
30 enum Foo {
31 Bar(
32 a:Int,
33 b:Int,
34 );
35 }
36
37 function moduleFoobar(
38 a:Int,
39 b:Int,
40 ):Int {
41 return a + b;
42 }
0 class Main2 {
1 static function f(t:Type.ValueType, t2:Type.ValueType,,) {}
2 public static function main():Void {
3 f(TNull,TNull,);
4 }
5 }
0 class Main3 {
1 public static function main():Void {
2 f(,);
3 }
4 static function f():Void {}
5 }
0 Main2.hx:2: characters 56-57 : Unexpected ,
0 Main3.hx:3: characters 5-6 : Expected expression or )
0 function main() {
1 trace(new haxe.ds.Vector(1)[0]);
2 }
0 -python bin/main.py
1 --main Main
2 -cmd python3 bin/main.py
0 import haxe.io.Bytes;
01 import haxe.macro.Compiler;
12 import sys.FileSystem;
23 import sys.io.File;
4344 Sys.setCwd(dirPath);
4445 Sys.println('Running haxe $path');
4546 var expectFailure = file.endsWith("-fail.hxml");
47 var expectStdout = if (FileSystem.exists('$file.stdout')) prepareExpectedOutput(File.getContent('$file.stdout')) else null;
4648 var expectStderr = if (FileSystem.exists('$file.stderr')) prepareExpectedOutput(File.getContent('$file.stderr')) else null;
47 var result = runCommand("haxe", [file], expectFailure, expectStderr);
49 var result = runCommand("haxe", [file], expectFailure, expectStdout, expectStderr);
4850 ++count;
4951 if (!result.success) {
5052 failures++;
6668 s = s.replace("\r\n", "\n"); // get rid of windows newlines
6769
6870 var cwd = Path.removeTrailingSlashes(FileSystem.fullPath(Sys.getCwd()));
71 var std = Path.removeTrailingSlashes(getStd());
6972
70 var context = {cwd: cwd};
73 var context = {cwd: cwd, std: std};
7174 var macros = {normPath: normPath};
7275
7376 return new haxe.Template(s).execute(context, macros);
7477 }
7578
76 static function normPath(_, p:String):String {
79 static function normPath(_, p:String, escape:String = "false"):String {
80 var escape = escape != "false";
81
7782 if (Sys.systemName() == "Windows") {
7883 // on windows, haxe returns lowercase paths with backslashes, drive letter uppercased
7984 p = p.substr(0, 1).toUpperCase() + p.substr(1);
8085 p = p.replace("/", "\\");
86 if (escape) p = p.replace("\\", "\\\\");
8187 }
8288 return p;
8389 }
8490
85 static function runCommand(command:String, args:Array<String>, expectFailure:Bool, expectStderr:String):{success:Bool, summary:String} {
91 static function runCommand(command:String, args:Array<String>, expectFailure:Bool, expectStdout:String, expectStderr:String):{success:Bool, summary:String} {
8692 var summary = [];
8793 function println(msg:String) {
8894 summary.push(msg);
120126 false;
121127 }
122128
123 if (stdout.length > 0) {
129 if (result && expectStdout != null) {
130 result = checkOutput(println, "stdout", stdout.toString(), expectStdout);
131 } else if (stdout.length > 0) {
124132 println(stdout.toString());
125133 }
126134
127135 if (result && expectStderr != null) {
128 var stderr = proc.stderr.readAll().toString().replace("\r\n", "\n").trim();
129 var expected = expectStderr.trim();
130 if (stderr != expected) {
131 // "Picked up JAVA_TOOL_OPTIONS: <...>" is printed by JVM sometimes.
132 // @see https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars002.html
133 stderr = stderr.split('\n')
134 .filter(s -> 0 != s.indexOf('Picked up JAVA_TOOL_OPTIONS:'))
135 .join('\n');
136 if(stderr != expected) {
137 println("Actual stderr output doesn't match the expected one");
138 println('Expected:\n"$expectStderr"');
139 println('Actual:\n"$stderr"');
140 result = false;
141 }
142 }
136 result = checkOutput(println, "stderr", proc.stderr.readAll().toString(), expectStderr);
143137 }
138
144139 proc.close();
145140 return {success:result, summary:summary.join('\n')};
146141 }
142
143 static function checkOutput(println:String->Void, name:String, content:String, expected:String):Bool {
144 var content = content.replace("\r\n", "\n").trim();
145 var expected = expected.trim();
146 if (content != expected) {
147 // "Picked up JAVA_TOOL_OPTIONS: <...>" is printed by JVM sometimes.
148 // @see https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars002.html
149 content = content.split('\n')
150 .filter(s -> 0 != s.indexOf('Picked up JAVA_TOOL_OPTIONS:'))
151 .join('\n');
152
153 if (content != expected) {
154 final a = new diff.FileData(Bytes.ofString(expected), "expected", Date.now());
155 final b = new diff.FileData(Bytes.ofString(content), "actual", Date.now());
156 var ctx:diff.Context = {
157 file1: a,
158 file2: b,
159 context: 10
160 }
161 final script = diff.Analyze.diff2Files(ctx);
162 var diff = diff.Printer.printUnidiff(ctx, script);
163 diff = diff.split("\n").slice(3).join("\n");
164 println(diff);
165 return false;
166 }
167 }
168
169 return true;
170 }
171
172 static macro function getStd() {
173 var std = Compiler.getConfiguration().stdPath;
174 return macro $v{std.shift()};
175 }
147176 }
0 package diff;
1
2 import haxe.ds.Vector;
3 import diff.Diffseq;
4
5 class Analyze {
6 static function discardConfusingLines(file1:FileData, file2:FileData) {}
7
8 static function analyzeHunk(ctx:Context, script:Array<Change>) {
9 var showFrom = 0;
10 var showTo = 0;
11
12 final first0 = script[0].line0;
13 final first1 = script[0].line1;
14
15 var l0 = 0;
16 var l1 = 0;
17 for (next in script) {
18 l0 = next.line0 + next.deleted - 1;
19 l1 = next.line1 + next.inserted - 1;
20 showFrom += next.deleted;
21 showTo += next.inserted;
22 }
23
24 return {
25 first0: first0,
26 first1: first1,
27 last0: l0,
28 last1: l1,
29 showFrom: showFrom > 0,
30 showTo: showTo > 0
31 }
32 }
33
34 static function buildScript(ctx:Context) {
35 var currentChange = null;
36 var firstChange = null;
37 function addChange(line0:Int, line1:Int, deleted:Int, inserted:Int) {
38 var change:Change = {
39 line0: line0,
40 line1: line1,
41 deleted: deleted,
42 inserted: inserted
43 };
44 if (currentChange == null) {
45 currentChange = change;
46 firstChange = change;
47 } else {
48 currentChange.next = change;
49 currentChange = change;
50 }
51 };
52 final changed0 = ctx.file1.changed;
53 final changed1 = ctx.file2.changed;
54 final len0 = ctx.file1.lines.length;
55 final len1 = ctx.file2.lines.length;
56 var i0 = 0;
57 var i1 = 0;
58 while (i0 < len0 || i1 < len1) {
59 if (changed0[i0] | changed1[i1] != 0) {
60 final line0 = i0;
61 final line1 = i1;
62 while (changed0[i0] != 0) {
63 ++i0;
64 }
65 while (changed1[i1] != 0) {
66 ++i1;
67 }
68 addChange(line0, line1, i0 - line0, i1 - line1);
69 }
70 i0++;
71 i1++;
72 }
73 return firstChange;
74 }
75
76 static function printNormalHunk(ctx:Context, script:Array<Change>) {
77 // final changes = analyzeHunk(ctx, script);
78 var buf = new StringBuf();
79 for (change in script) {
80 if (change.deleted > 0) {
81 for (i in change.line0...change.line0 + change.deleted) {
82 final line = ctx.file1.lines[i];
83 buf.add("< ");
84 buf.add(ctx.file1.data.sub(line.pos, line.length));
85 buf.addChar("\n".code);
86 }
87 }
88 buf.add("---\n");
89 if (change.inserted > 0) {
90 for (i in change.line1...change.line1 + change.inserted) {
91 final line = ctx.file2.lines[i];
92 buf.add("> ");
93 buf.add(ctx.file2.data.sub(line.pos, line.length).toString());
94 buf.addChar("\n".code);
95 }
96 }
97 }
98 return buf.toString();
99 }
100
101 static public function diff2Files(ctx:Context) {
102 Io.readFiles(ctx);
103 final flagSpace = new Vector(ctx.file1.lines.length + ctx.file2.lines.length + 4);
104 for (i in 0...flagSpace.length) {
105 flagSpace[i] = 0;
106 }
107 ctx.file1.changed = new IndexVector(flagSpace, 1);
108 ctx.file2.changed = new IndexVector(flagSpace, ctx.file1.lines.length + 3);
109 // TODO: discardConfusingLines
110 final diags = ctx.file1.equivs.length + ctx.file2.equivs.length + 3;
111 var fdiag = new IndexVector(new Vector(diags * 2), 0);
112 var bdiag = fdiag + diags;
113 fdiag += ctx.file2.equivs.length + 1;
114 bdiag += ctx.file2.equivs.length + 1;
115 var dCtx:DiffseqContext = {
116 xvec: ctx.file1.equivs,
117 yvec: ctx.file2.equivs,
118 fdiag: fdiag,
119 bdiag: bdiag,
120 NOTE_INSERT: (d) -> {
121 ctx.file2.markChange(d);
122 },
123 NOTE_DELETE: (d) -> {
124 ctx.file1.markChange(d);
125 }
126 }
127 Diffseq.compareseq(0, ctx.file1.equivs.length, 0, ctx.file2.equivs.length, dCtx);
128 // TODO: shiftBoundaries
129 return buildScript(ctx);
130 }
131 }
0 package diff;
1
2 @:structInit
3 class Change {
4 @:optional
5 public var next:Null<Change>;
6 public var inserted:Int;
7 public var deleted:Int;
8 public var line0:Int;
9 public var line1:Int;
10
11 public function toString() {
12 return '[CHANGE inserted: $inserted, deleted: $deleted, line0: $line0, line1: $line1]';
13 }
14 }
0 package diff;
1
2 @:structInit
3 class Context {
4 public final file1:FileData;
5 public final file2:FileData;
6 public var context:Int;
7 }
0 package diff;
1
2 import haxe.ds.Vector;
3
4 @:structInit
5 private class Parition {
6 public var xmid:Int;
7 public var ymid:Int;
8
9 function toString() {
10 return '[Partition xmid: $xmid, ymid: $ymid]';
11 }
12 }
13
14 final OFFSET_MAX = 1 << 30;
15
16 @:structInit
17 class DiffseqContext {
18 public final xvec:Vector<Int>;
19 public final yvec:Vector<Int>;
20 public final fdiag:IndexVector;
21 public final bdiag:IndexVector;
22 public final NOTE_DELETE:(Int) -> Void;
23 public final NOTE_INSERT:(Int) -> Void;
24 }
25
26 class Diffseq {
27 static public function diag(xoff:Int, xlim:Int, yoff:Int, ylim:Int, ctxt:DiffseqContext):Parition {
28 var fd = ctxt.fdiag;
29 var bd = ctxt.bdiag;
30 var xv = ctxt.xvec;
31 var yv = ctxt.yvec;
32 inline function XREF_YREF_EQUAL(x, y) {
33 return xv[x] == yv[y];
34 }
35 final dmin = xoff - ylim;
36 final dmax = xlim - yoff;
37 final fmid = xoff - yoff;
38 final bmid = xlim - ylim;
39 var fmin = fmid;
40 var fmax = fmid;
41 var bmin = bmid;
42 var bmax = bmid;
43 var odd = ((fmid - bmid) & 1) != 0;
44 fd[fmid] = xoff;
45 bd[bmid] = xlim;
46 while (true) {
47 var d;
48 if (fmin > dmin) {
49 fd[--fmin - 1] = -1;
50 } else {
51 ++fmin;
52 }
53 if (fmax < dmax) {
54 fd[++fmax + 1] = -1;
55 } else {
56 --fmax;
57 }
58 d = fmax;
59 while (d >= fmin) {
60 var tlo = fd[d - 1];
61 var thi = fd[d + 1];
62 var x0 = tlo < thi ? thi : tlo + 1;
63 var x = x0;
64 var y = x0 - d;
65 while (x < xlim && y < ylim && XREF_YREF_EQUAL(x, y)) {
66 x++;
67 y++;
68 }
69 fd[d] = x;
70 if (odd && bmin <= d && d <= bmax && bd[d] <= x) {
71 return {
72 xmid: x,
73 ymid: y
74 }
75 }
76 d -= 2;
77 }
78
79 if (bmin > dmin) {
80 bd[--bmin - 1] = OFFSET_MAX;
81 } else {
82 ++bmin;
83 }
84 if (bmax < dmax) {
85 bd[++bmax + 1] = OFFSET_MAX;
86 } else {
87 --bmax;
88 }
89 d = bmax;
90 while (d >= bmin) {
91 var tlo = bd[d - 1];
92 var thi = bd[d + 1];
93 var x0 = tlo < thi ? tlo : thi - 1;
94 var x = x0;
95 var y = x0 - d;
96 while (xoff < x && yoff < y && XREF_YREF_EQUAL(x - 1, y - 1)) {
97 x--;
98 y--;
99 }
100 bd[d] = x;
101 if (!odd && fmin <= d && d <= fmax && x <= fd[d]) {
102 return {
103 xmid: x,
104 ymid: y
105 }
106 }
107 d -= 2;
108 }
109 }
110 }
111
112 static public function compareseq(xoff:Int, xlim:Int, yoff:Int, ylim:Int, ctxt:DiffseqContext) {
113 final xv = ctxt.xvec;
114 final yv = ctxt.yvec;
115 inline function XREF_YREF_EQUAL(x, y) {
116 return xv[x] == yv[y];
117 }
118 while (true) {
119 while (xoff < xlim && yoff < ylim && XREF_YREF_EQUAL(xoff, yoff)) {
120 xoff++;
121 yoff++;
122 }
123
124 while (xoff < xlim && yoff < ylim && XREF_YREF_EQUAL(xlim - 1, ylim - 1)) {
125 xlim--;
126 ylim--;
127 }
128
129 if (xoff == xlim) {
130 while (yoff < ylim) {
131 ctxt.NOTE_INSERT(yoff);
132 yoff++;
133 }
134 break;
135 }
136 if (yoff == ylim) {
137 while (xoff < xlim) {
138 ctxt.NOTE_DELETE(xoff);
139 xoff++;
140 }
141 break;
142 }
143
144 var part = diag(xoff, xlim, yoff, ylim, ctxt);
145
146 var xoff1, xlim1, yoff1, ylim1, xoff2, xlim2, yoff2, ylim2;
147 if ((xlim + ylim) - (part.xmid + part.ymid) < (part.xmid + part.ymid) - (xoff + yoff)) {
148 xoff1 = part.xmid;
149 xlim1 = xlim;
150 yoff1 = part.ymid;
151 ylim1 = ylim;
152 xoff2 = xoff;
153 xlim2 = part.xmid;
154 yoff2 = yoff;
155 ylim2 = part.ymid;
156 } else {
157 xoff1 = xoff;
158 xlim1 = part.xmid;
159 yoff1 = yoff;
160 ylim1 = part.ymid;
161 xoff2 = part.xmid;
162 xlim2 = xlim;
163 yoff2 = part.ymid;
164 ylim2 = ylim;
165 }
166 compareseq(xoff1, xlim1, yoff1, ylim1, ctxt);
167
168 xoff = xoff2;
169 xlim = xlim2;
170 yoff = yoff2;
171 ylim = ylim2;
172 }
173 return false;
174 }
175 }
0 package diff;
1
2 import haxe.io.Bytes;
3 import haxe.ds.Vector;
4
5 @:structInit
6 private class Line {
7 public final pos:Int;
8 public final length:Int;
9 }
10
11 class FileData {
12 public final data:Bytes;
13 public final label:String;
14 public final mtime:Date;
15 public var prefixEnd:Int;
16 public var prefixNewlines:Int;
17 public var suffixBegin:Int;
18 public var equivs:Vector<Int>;
19 public final equivCount:Array<Null<Int>>;
20 public final lines:Array<Line>;
21
22 public var changed:IndexVector;
23
24 public function new(data:Bytes, label:String, mtime:Date) {
25 this.label = label;
26 this.mtime = mtime;
27 this.data = data;
28 prefixEnd = 0;
29 suffixBegin = data.length;
30 equivCount = [];
31 lines = [];
32 }
33
34 #if sys
35 static public function loadFile(path:String) {
36 final stat = sys.FileSystem.stat(path);
37 return new FileData(sys.io.File.getBytes(path), path, stat.mtime);
38 }
39 #end
40
41 public function addLine(pos:Int, length:Int) {
42 lines.push({pos: pos, length: length});
43 }
44
45 public function markChange(line:Int) {
46 changed[line] = 1;
47 }
48
49 public function finishLineProcessing(equivs:Array<Int>) {
50 this.equivs = Vector.fromArrayCopy(equivs);
51 }
52
53 public function increaseEquivCount(index:Int) {
54 if (equivCount[index] == null) {
55 equivCount[index] = 1;
56 } else {
57 equivCount[index]++;
58 }
59 }
60
61 public function dump() {
62 var buf = new StringBuf();
63 inline function add(s:String) {
64 buf.add(s);
65 }
66 add(' prefixEnd: ${prefixEnd}\n');
67 add('suffixBegin: ${suffixBegin}\n');
68 add(' equivs: ${equivs}\n');
69 add(' equivCount: ${equivCount}\n');
70 return buf.toString();
71 }
72 }
0 package diff;
1
2 import haxe.ds.Vector;
3
4 @:structInit
5 private class IV {
6 public final v:Vector<Int>;
7 public var index:Int;
8 }
9
10 abstract IndexVector(IV) {
11 public inline function new(v:Vector<Int>, index:Int) {
12 this = {
13 v: v,
14 index: index
15 }
16 }
17
18 @:op(A += B)
19 inline function addAssign(rhs:Int) {
20 this.index += rhs;
21 }
22
23 @:op(A + B)
24 inline function add(delta:Int) {
25 return new IndexVector(this.v, this.index + delta);
26 }
27
28 @:op([])
29 inline function read(delta:Int) {
30 return this.v[this.index + delta];
31 }
32
33 @:op([])
34 inline function write(delta:Int, v:Int) {
35 return this.v[this.index + delta] = v;
36 }
37
38 public inline function toString() {
39 return '[IV +${this.index}]';
40 }
41 }
0 package diff;
1
2 import haxe.io.Bytes;
3 import haxe.ds.IntMap;
4 import haxe.ds.Vector;
5
6 using diff.Io.BytesTools;
7
8 private typedef Hash = Int;
9
10 class BytesTools {
11 static public function compareSub(bytes1:Bytes, pos1:Int, bytes2:Bytes, pos2:Int, length:Int) {
12 for (i in 0...length) {
13 if (bytes1.get(pos1 + i) != bytes2.get(pos2 + i)) {
14 return false;
15 }
16 }
17 return true;
18 }
19 }
20
21 @:structInit
22 private class Equivclass {
23 public final hash:Hash;
24 public final bytes:Bytes; // This is the complete bytes, not the sub-range
25 public final pos:Int;
26 public final length:Int;
27 }
28
29 private class IoContext {
30 final equivLut:IntMap<Array<Int>>;
31 final equivs:Array<Equivclass>;
32
33 public function new() {
34 equivLut = new IntMap();
35 equivs = [];
36 }
37
38 public function addEquiv(equiv:Equivclass) {
39 return equivs.push(equiv) - 1;
40 }
41
42 public function getEquiv(i:Int) {
43 return equivs[i];
44 }
45
46 public function lookup(hash:Hash) {
47 var a = equivLut.get(hash);
48 if (a == null) {
49 a = [];
50 equivLut.set(hash, a);
51 }
52 return a;
53 }
54 }
55
56 class Io {
57 static inline function ROL(v, n)
58 return ((v) << (n) | (v) >> (32 - (n)));
59
60 static inline function HASH(h, c)
61 return ((c) + ROL(h, 7));
62
63 static public function findIdenticalEnds(ctx:Context) {
64 var w1 = 0;
65 final file1 = ctx.file1;
66 final file2 = ctx.file2;
67 final len1 = file1.data.length;
68 final len2 = file2.data.length;
69 final min = len1 < len2 ? len1 : len2;
70 var newlineCount = 0;
71 final ringMod = ctx.context + 1;
72 final newlineRing = new Vector(ringMod);
73 var c;
74 while (w1 < min && (c = file1.data.get(w1)) == file2.data.get(w1)) {
75 if (c == '\n'.code) {
76 newlineRing[newlineCount++ % ringMod] = w1;
77 }
78 ++w1;
79 }
80 if (newlineCount < ringMod) {
81 file1.prefixEnd = 0;
82 file2.prefixEnd = 0;
83 newlineCount = 0;
84 } else {
85 file1.prefixEnd = newlineRing[newlineCount % ringMod] + 1;
86 file2.prefixEnd = file1.prefixEnd;
87 newlineCount -= ringMod - 1;
88 }
89 file1.prefixNewlines = file2.prefixNewlines = newlineCount;
90
91 w1 = len1 - 1;
92 var w2 = len2 - 1;
93 newlineCount = 0;
94 while (w1 > file1.prefixEnd && w2 > file2.prefixEnd && (c = file1.data.get(w1)) == file2.data.get(w2)) {
95 if (c == '\n'.code) {
96 newlineRing[newlineCount++ % ringMod] = w1;
97 }
98 w1--;
99 w2--;
100 }
101 if (newlineCount < ringMod) {
102 file1.suffixBegin = len1 - 1;
103 file2.suffixBegin = len2 - 1;
104 } else {
105 file1.suffixBegin = newlineRing[newlineCount % ringMod] + 1;
106 file2.suffixBegin = file1.suffixBegin + (len2 - len1);
107 }
108 }
109
110 static public function findAndHashEachLine(ctx:IoContext, file:FileData) {
111 var p = file.prefixEnd;
112 var c = 0;
113 final cureqs = [];
114 while (p < file.suffixBegin) {
115 final ip = p;
116 var h = 0;
117 // TODO: This has a big switch in io.c that depends on the whitespace policy
118 while ((c = file.data.get(p++)) != '\n'.code) {
119 h = HASH(h, c);
120 if (p == file.data.length) {
121 p++;
122 break;
123 }
124 }
125 final length = p - ip - 1;
126 final a = ctx.lookup(h);
127 var equivIndex = -1;
128 for (i in a) {
129 final equiv = ctx.getEquiv(i);
130 if (equiv.hash == h && equiv.length == length && file.data.compareSub(ip, equiv.bytes, equiv.pos, length)) {
131 equivIndex = i;
132 break;
133 }
134 }
135 if (equivIndex < 0) {
136 final equiv:Equivclass = {
137 hash: h,
138 bytes: file.data,
139 pos: ip,
140 length: length
141 }
142 equivIndex = ctx.addEquiv(equiv);
143 a.push(equivIndex);
144 }
145 cureqs.push(equivIndex);
146 file.increaseEquivCount(equivIndex);
147 file.addLine(ip, length);
148 }
149 file.finishLineProcessing(cureqs);
150 }
151
152 static public function readFiles(ctx:Context) {
153 findIdenticalEnds(ctx);
154 var ioctx = new IoContext();
155 findAndHashEachLine(ioctx, ctx.file1);
156 findAndHashEachLine(ioctx, ctx.file2);
157 }
158 }
0 package diff;
1
2 class Printer {
3 static function printContextLabel(mark:String, file:FileData) {
4 var buf = new StringBuf();
5 buf.add(mark);
6 buf.add(" ");
7 buf.add(file.label);
8 buf.add("\t");
9 buf.add(file.mtime.toString());
10 buf.add("\n");
11 return buf.toString();
12 }
13
14 static function printContextHeader(ctx:Context) {
15 var buf = new StringBuf();
16 buf.add(printContextLabel("---", ctx.file1));
17 buf.add(printContextLabel("+++", ctx.file2));
18 return buf.toString();
19 }
20
21 static function translateLineNumber(file:FileData, a:Int) {
22 return file.prefixNewlines + a + 1;
23 }
24
25 static function printUnidiffNumberRange(file:FileData, a:Int, b:Int) {
26 var transA = translateLineNumber(file, a - 1) + 1;
27 var transB = translateLineNumber(file, b + 1) - 1;
28
29 if (transB == transA) {
30 return '$transB,0';
31 } else if (transB - transA == 1) {
32 return '1';
33 } else {
34 return '$transA,${transB - transA}';
35 }
36 }
37
38 static function printUnidiffHunk(ctx:Context, change:Change) {
39 var buf = new StringBuf();
40 var from0 = change.line0 - ctx.context;
41 if (from0 < 0) {
42 from0 = 0;
43 }
44 var from1 = change.line1 - ctx.context;
45 if (from1 < 0) {
46 from1 = 0;
47 }
48 final last = {
49 var next = change;
50 while (next.next != null) {
51 next = next.next;
52 }
53 next;
54 }
55 var to0 = last.line0 + last.deleted + ctx.context;
56 if (to0 >= ctx.file1.lines.length) {
57 to0 = ctx.file1.lines.length;
58 }
59 var to1 = last.line1 + last.inserted + ctx.context;
60 if (to1 >= ctx.file2.lines.length) {
61 to1 = ctx.file2.lines.length;
62 }
63 buf.add("@@ -");
64 buf.add(printUnidiffNumberRange(ctx.file1, from0, to0));
65 buf.add(" +");
66 buf.add(printUnidiffNumberRange(ctx.file2, from1, to1));
67 buf.add(" @@\n");
68
69 function printLine(file:FileData, prefix:String, i:Int) {
70 final line = file.lines[i];
71 buf.add(prefix);
72 buf.add(file.data.sub(line.pos, line.length).toString());
73 buf.addChar("\n".code);
74 }
75 var i = from0;
76 var j = from1;
77 while (i < to0 || j < to1) {
78 if (change == null || i < change.line0) {
79 printLine(ctx.file1, " ", i);
80 ++i;
81 ++j;
82 } else {
83 for (_ in 0...change.deleted) {
84 printLine(ctx.file1, "-", i++);
85 }
86 for (_ in 0...change.inserted) {
87 printLine(ctx.file2, "+", j++);
88 }
89 change = change.next;
90 }
91 }
92 return buf.toString();
93 }
94
95 static public function findHunk(ctx:Context, change:Change) {
96 final threshold = ctx.context * 2 + 1;
97 var previousChange = change;
98 while ((change = change.next) != null) {
99 if (change.line0 - (previousChange.line0 + previousChange.deleted) < threshold) {
100 previousChange = change;
101 continue;
102 }
103 break;
104 }
105 return previousChange;
106 }
107
108 static public function printUnidiff(ctx:Context, change:Change) {
109 var buf = new StringBuf();
110 buf.add(printContextHeader(ctx));
111 var next = change;
112 while (next != null) {
113 var end = findHunk(ctx, next);
114 final cur = next;
115 next = end.next;
116 end.next = null;
117 buf.add(printUnidiffHunk(ctx, cur));
118 }
119 return buf.toString();
120 }
121 }
133133 function get_str() {
134134 shouldFail(return (null:Null<String>));
135135 }
136 function set_str(v) {
137 shouldFail(return (v:Null<String>));
136 function set_str(v:Null<String>) {
137 shouldFail(return v);
138138 }
139139
140140 /**
995995 else a = 'hello';
996996 var s:String = a;
997997 }
998
999 /**
1000 * @see https://github.com/HaxeFoundation/haxe/pull/10428#issuecomment-951574457
1001 */
1002 static function issue10428() {
1003 final arr:Array<Int> = [
1004 {
1005 var tmp = (1 : Null<Int>);
1006 if (tmp != null) tmp else 2;
1007 }
1008 ];
1009 }
1010
1011 static function issue9588_DynamicIsNullable_AnyIsNotNullable(?a:String) {
1012 function dyn(v:Dynamic):Dynamic
1013 return v;
1014 var d:Dynamic = dyn(a);
1015 // TODO: decide if 'dynamic to non-nullable' should fail since we allow 'nullable to dynamic now'.
1016 //shouldFail(var s:String = d);
1017
1018 function any(v:Any):Any
1019 return v;
1020 shouldFail(any(a));
1021 var s:String = any('');
1022 }
1023
1024 static function issue10272_nullableConcatString_shouldPass(msg:Null<Dynamic>) {
1025 trace("Message: " + msg);
1026 }
9981027 }
9991028
10001029 private class FinalNullableFields {
1919 --macro Macro.register('Test')
2020 --macro Macro.register('TestJs')
2121 --macro Macro.register('TestLocalDce')
22 --macro Macro.register('TestNadako')
2223 --macro Macro.register('TestTreGeneration')
2324 --macro Macro.register('TestInlineConstructors')
2425 --macro Macro.register('issues')
2525
2626 @:analyzer(no_user_var_fusion)
2727 class TestJs {
28 static var notFalse = true;
29
2830 //@:js('var x = 10;"" + x;var x1 = 10;"" + x1;var x2 = 10.0;"" + x2;var x3 = "10";x3;var x4 = true;"" + x4;')
2931 //static function testStdString() {
3032 //var x = 10;
273275
274276 @:js('
275277 var x = TestJs.getInt();
276 var tmp = [x,"foo"];
277 x = TestJs.getInt();
278 TestJs.call(tmp,TestJs.getInt());
279 ')
280 static function testMightBeAffected2() {
278 TestJs.getInt();
279 TestJs.call([x,"foo"],TestJs.getInt());
280 ')
281 static function testMightActuallyNotBeAffected() {
281282 var x = getInt();
282283 call([x, "foo"], {
283284 x = getInt();
286287 }
287288
288289 @:js('
290 TestJs.getInt();
291 var tmp = TestJs.getImpureArray();
292 TestJs.getInt();
293 TestJs.call(tmp,TestJs.getInt());
294 ')
295 static function testMightBeAffected2() {
296 var x = getInt();
297 call(getImpureArray(), {
298 x = getInt();
299 getInt();
300 });
301 }
302
303 @:js('
289304 var x = TestJs.getInt();
290 TestJs.call(x++,TestJs.getInt());
305 TestJs.call(x,TestJs.getInt());
291306 ')
292307 static function testMightBeAffected3() {
293308 var x = getInt();
323338 }
324339
325340 @:js('
341 var a = Std.random(100);
342 var b = Std.random(100);
343 var c = Std.random(100);
344 var d = Std.random(100);
345 Std.random(100);
346 a = b + c;
347 b -= d;
348 TestJs.use(a + b);
349 ')
350 static function testIssue10972() {
351 var a = Std.random(100);
352 var b = Std.random(100);
353 var c = Std.random(100);
354 var d = Std.random(100);
355 var e = Std.random(100);
356 a = b + c;
357 b = b - d;
358 c = c + d;
359 e = b + c;
360 use(a + b);
361 }
362
363 @:js('
326364 var a = TestJs.getInt();
327365 TestJs.use(a);
328366 ')
335373 @:js('
336374 var a = TestJs.getInt();
337375 var b = a;
338 a = TestJs.getInt();
376 TestJs.getInt();
339377 TestJs.use(b);
340378 ')
341379 static function testCopyPropagation2() {
483521 @:pure(false)
484522 static function getInt(?d:Dynamic) { return 1; }
485523 static function getArray() { return [0, 1]; }
524
525 @:pure(false)
526 static function getImpureArray() { return [0, 1]; }
527
486528 @:pure(false)
487529 static function call(d1:Dynamic, d2:Dynamic) { return d1; }
488530 @:pure(false)
489531 static public function use<T>(t:T) { return t; }
532 @:pure(false)
533 static function run(f:()->Void) {}
490534
491535 static var intField = 12;
492536 static var stringField(default, never) = "foo";
646690 var f = Issue9227.new.bind(1);
647691 f(3);
648692 }
693
694 @:js('
695 var c = new Issue10737();
696 var _g = c;
697 var value = 42;
698 TestJs.run(function() {_g.process(value);});
699 ')
700 static function testIssue10737_avoidInstanceMethodClosure() {
701 var c = new Issue10737();
702 run(c.process.bind(42));
703 c = null;
704 }
705
706 @:js('
707 var _g = new Issue10737();
708 var value = 42;
709 TestJs.run(function() {_g.process(value);});
710 ')
711 static function testIssue10737_avoidInstanceMethodClosure2() {
712 run(new Issue10737().process.bind(42));
713 }
714
715 @:js('
716 var tmp = Issue10740.inst;
717 if(tmp != null) {
718 Issue10740.use(tmp.value);
719 }
720 ')
721 static function testIssue10740_forceInlineInSafeNav() {
722 inline Issue10740.inst?.f();
723 }
724
725 @:js('
726 var offset = 0;
727 do {
728 TestJs.use(offset);
729 if(offset >= 3) {
730 break;
731 }
732 offset = 3;
733 } while(TestJs.notFalse);
734 ')
735 static function testDoWhile() {
736 var offset = 0;
737 do {
738 use(offset);
739 if (offset >= 3)
740 break;
741 offset = 3;
742 } while (notFalse);
743 }
649744 }
650745
651746 class Issue9227 {
664759 inline public function toInt():Int {
665760 return this;
666761 }
762 }
763
764 class Issue10737 {
765 public function new() {}
766 public function process(value:Int) {}
767 }
768
769 class Issue10740 {
770 public static var inst:Issue10740;
771
772 public final value:Int;
773 public function new() {
774 value = 42;
775 }
776 public function f() {
777 use(value);
778 }
779 @:pure(false)
780 static function use(v:Int) {}
667781 }
0 import TestJs.use;
1
2 class TestNadako {
3 @:js('var r = [];
4 var _g_current = 0;
5 while(_g_current < _requirements.length) {
6 var _g_value = _requirements[_g_current];
7 TestJs.use(_g_value);
8 r[_g_current++] = _g_value;
9 }')
10 static function testNadako1(_requirements:Array<{}>) {
11 var r = [];
12 for (i => resourceData in _requirements) {
13 use(resourceData);
14 r[i] = resourceData;
15 }
16 }
17 }
0 package issues;
1
2 enum abstract Value(Int) to Int {
3 final V1 = 1;
4 final V2 = 2;
5
6 public inline function toString():String {
7 return switch (cast this:Value) {
8 case V1: 'V1';
9 case V2: 'V2';
10 }
11 }
12 }
13
14 @:enum abstract ActorStateType(Int) from Int to Int {
15 var GoingLeft = 0;
16 var GoingRight = 1;
17 }
18
19 class Issue10188 {
20 @:js('
21 var _g = [];
22 if(issues_Issue10188.has(1)) {
23 _g.push("V1");
24 }
25 issues_Issue10188.use(_g);
26 ')
27 static function testKevin() {
28 use([for(v in [V1]) if(has(v)) v.toString()]);
29 }
30
31
32 static function has(v:Value) {
33 return true;
34 }
35
36 @:js('
37 var state = 0;
38 if(Math.random() > 0.5) {
39 state = 0;
40 issues_Issue10188.use("left");
41 }
42 issues_Issue10188.use(state);
43 ')
44 static function testNotKevin() {
45 var state = GoingLeft;
46 inline function set(s) {
47 state = s;
48 use(getAnim(s));
49 }
50 if(Math.random() > 0.5) set(GoingLeft);
51 use(state);
52 }
53
54 static inline function getAnim(state:ActorStateType):String {
55 return switch(state) {
56 case GoingLeft: 'left';
57 case GoingRight: 'right';
58 }
59 }
60
61 @:pure(false)
62 static public function use<T>(t:T) { return t; }
63 }
0 package issues;
1
2 @:forward
3 private abstract ComplexArray(js.lib.DataView) {
4 public inline function new(length: Int) {
5 final buffer = new js.lib.ArrayBuffer(length * 2 * 4);
6 this = new js.lib.DataView(buffer, 0, buffer.byteLength);
7 }
8
9 @:arrayAccess
10 public static inline function get(impl: ComplexArray, index: Int): Complex {
11 return new Complex(impl.getFloat32(index * 2 * 4), impl.getFloat32((index * 2 + 1) * 4));
12 }
13
14 @:arrayAccess
15 public static inline function set(impl: ComplexArray, index: Int, value: Complex): Complex {
16 impl.setFloat32(index * 2 * 4, value.real);
17 impl.setFloat32((index * 2 + 1) * 4, value.imag);
18 return value;
19 }
20 }
21
22 private class Complex {
23 public var real: Float;
24 public var imag: Float;
25
26 public inline function new(real: Float, imag: Float) {
27 this.real = real;
28 this.imag = imag;
29 }
30
31 public inline function add(other: Complex): Complex {
32 return new Complex(this.real + other.real, this.imag + other.imag);
33 }
34 }
35
36 class Issue10765 {
37 @:js('
38 var buffer = new ArrayBuffer(80);
39 var array = new DataView(buffer,0,buffer.byteLength);
40 var real = array.getFloat32(0);
41 var imag = array.getFloat32(4);
42 array.setFloat32(0,real + real);
43 array.setFloat32(4,imag + imag);
44 ')
45 static function test() {
46 final array = new ComplexArray(10);
47
48 final tmp = array[0];
49 array[0] = tmp.add(tmp);
50 }
51 }
0 package issues;
1
2 class Issue7237 {
3
4 @:js('
5 var f = function(a) {
6 var b = a;
7 return b;
8 };
9 var f2 = function(a) {
10 var b = a;
11 return b;
12 };
13 ')
14 @:analyzer(ignore)
15 static function main() {
16 var f = function(a) {
17 var b = a;
18 return b;
19 }
20 var f2 = function(a) {
21 var b = a;
22 return b;
23 }
24 }
25 }
0 package issues;
1
2 class Issue7765 {
3 @:pure(false) function add(m:Issue7765)
4 return this;
5
6 function new(i:Int) {}
7
8 static inline function pipe(m:Issue7765)
9 return m;
10
11 @:js('
12 new issues_Issue7765(0).add(new issues_Issue7765(1)).add(new issues_Issue7765(2));
13 ')
14 static function test() {
15 new Issue7765(0).add(pipe(new Issue7765(1))).add(pipe(new Issue7765(2)));
16 }
17
18 @:js('
19 var tmp = new issues_Issue7765(0);
20 var m = new issues_Issue7765(1);
21 var tmp1 = tmp.add(m);
22 var m = new issues_Issue7765(2);
23 tmp1.add(m);
24 ')
25 @:analyzer(no_fusion)
26 static function testNoFusion() {
27 new Issue7765(0).add(pipe(new Issue7765(1))).add(pipe(new Issue7765(2)));
28 }
29
30 @:js('
31 new issues_Issue7765(0).add(new issues_Issue7765(1));
32 ')
33 static function test2() {
34 new Issue7765(0).add({var m = new Issue7765(1); m; });
35 }
36
37 @:js('
38 var tmp = new issues_Issue7765(0);
39 var m = new issues_Issue7765(1);
40 tmp.add(m);
41 ')
42 @:analyzer(no_fusion)
43 static function test2NoFusion() {
44 new Issue7765(0).add({var m = new Issue7765(1); m; });
45 }
46 }
0 package issues;
1
2 private extern class Element {
3 static function get():Element;
4 var offset(default,null) : Int;
5 var style(default,null) : CSSStyleDeclaration;
6 }
7 @:pure
8 private extern class PureElement {
9 static function get():PureElement;
10 var offset(default,null) : Int;
11 var style(default,null) : CSSStyleDeclaration;
12 }
13 private extern class CSSStyleDeclaration {
14 var verticalAlign : Int;
15 }
16
17 class Issue9943 {
18 static final foo = Std.random(0);
19
20 @:js('
21 var el = issues._Issue9943.Element.get();
22 var a = el.offset + issues_Issue9943.foo;
23 el.style.verticalAlign = 1;
24 var b = el.offset + issues_Issue9943.foo;
25 el.style.verticalAlign = 2;
26 var c = el.offset + issues_Issue9943.foo;
27 issues_Issue9943.values(a,b,c);
28 ')
29 static function test() {
30 final el = Element.get();
31 final a = (el.offset + foo);
32 el.style.verticalAlign = 1;
33 final b = (el.offset + foo);
34 el.style.verticalAlign = 2;
35 final c = (el.offset + foo);
36 values(a, b, c);
37 }
38 @:js('
39 var el = issues._Issue9943.PureElement.get();
40 el.style.verticalAlign = 1;
41 el.style.verticalAlign = 2;
42 issues_Issue9943.values(el.offset + issues_Issue9943.foo,el.offset + issues_Issue9943.foo,el.offset + issues_Issue9943.foo);
43 ')
44 static function test2() {
45 final el = PureElement.get();
46 final a = (el.offset + foo);
47 el.style.verticalAlign = 1;
48 final b = (el.offset + foo);
49 el.style.verticalAlign = 2;
50 final c = (el.offset + foo);
51 values(a, b, c);
52 }
53 static function values(a, b, c) trace(a, b, c);
54 }
00 package runci;
11
22 import sys.FileSystem;
3 import haxe.io.Path;
34
45 enum Ci {
56 GithubActions;
910 static public final systemName = Sys.systemName();
1011 static public final cwd = Sys.getCwd();
1112 static public final repoDir = FileSystem.fullPath("..") + "/";
12 static public final unitDir = cwd + "unit/";
13 static public final sysDir = cwd + "sys/";
13 static public final unitDir = Path.join([cwd, "unit"]);
14 static public final sysDir = Path.join([cwd, "sys"]);
1415 static public final optDir = cwd + "optimization/";
15 static public final miscDir = cwd + "misc/";
16 static public final displayDir = cwd + "display/";
17 static public final serverDir = cwd + "server/";
18 static public final sourcemapsDir = cwd + "sourcemaps/";
19 static public final nullSafetyDir = cwd + "nullsafety/";
20 static public final threadsDir = cwd + "threads/";
16 static public final displayDir = Path.join([cwd, "display"]);
17 static public final serverDir = Path.join([cwd, "server"]);
18 static public final sourcemapsDir = Path.join([cwd, "sourcemaps"]);
19 static public final nullSafetyDir = Path.join([cwd, "nullsafety"]);
20 static public final threadsDir = Path.join([cwd, "threads"]);
21 // this stands for third-party, but I've always wanted a party directory
22 static public final partyDir = Path.join([cwd, "party"]);
23
24 static public function getMiscSubDir(...subDir:String)
25 return Path.join([cwd, "misc"].concat(subDir.toArray()));
2126
2227 static public final ci:Null<Ci> =
23 if (Sys.getEnv("GITHUB_WORKSPACE") != null)
28 if (Sys.getEnv("GITHUB_ACTIONS") == "true")
2429 GithubActions;
2530 else
2631 null;
2732
28 static public function isCi():Bool {
29 return ci != null;
33 static public macro function isCi() {
34 return macro $v{ci != null};
3035 }
3136
3237 static public final colorSupported = switch [ci, systemName] {
11
22 import runci.System.*;
33
4 using StringTools;
5
46 class Linux {
7 static public var arch(get, null):Arch;
8
9 static function get_arch() {
10 if(arch == null)
11 arch = switch commandResult('arch', []).stdout.replace('\n', '') {
12 case 'arm64' | 'aarch64': Arm64;
13 case _: Amd64;
14 }
15 return arch;
16 }
17
518 static public function isAptPackageInstalled(aptPackage:String):Bool {
619 return commandSucceed("dpkg-query", ["-W", "-f='${Status}'", aptPackage]);
720 }
821
22 static inline function hasAptGet() {
23 // CI always runs on ubuntu, otherwise check for apt-get
24 return Config.isCi() || commandSucceed("type", ["apt-get"]);
25 }
26
927 static public function requireAptPackages(packages:Array<String>):Void {
28 if (!hasAptGet()){
29 infoMsg("System does not have apt-get installed.");
30 return;
31 }
1032 var notYetInstalled = [for (p in packages) if (!isAptPackageInstalled(p)) p];
1133 if (notYetInstalled.length > 0) {
1234 var aptCacheDir = Sys.getEnv("APT_CACHE_DIR");
1537 } else {
1638 ["apt-get", "install", "-qqy"];
1739 };
18 runCommand("sudo", baseCommand.concat(notYetInstalled), true);
40 runNetworkCommand("sudo", baseCommand.concat(notYetInstalled));
1941 }
2042 }
21 }
43 }
44
45 enum abstract Arch(Int) {
46 final Arm64;
47 final Amd64;
48 }
55
66 using StringTools;
77
8 enum Failure {
9 Fail;
8 class CommandFailure extends haxe.Exception {
9 public final exitCode:Int;
10 public function new(exitCode:Int = 1) {
11 super("Command failed: " + Std.string(exitCode));
12 this.exitCode = exitCode;
13 }
1014 }
1115
1216 class System {
13 static public var success(default, null) = true;
14
15
1617 static public function successMsg(msg:String):Void {
1718 Sys.println(colorSupported ? '\x1b[32m' + msg + '\x1b[0m' : msg);
1819 }
2526
2627 static public function commandSucceed(cmd:String, args:Array<String>):Bool {
2728 return try {
28 var p = new Process(cmd, args);
29 var succeed = p.exitCode() == 0;
29 final p = new Process(cmd, args);
30 final succeed = p.exitCode() == 0;
3031 p.close();
3132 succeed;
3233 } catch(e:Dynamic) false;
3738 stderr:String,
3839 exitCode:Int
3940 } {
40 var p = new Process(cmd, args);
41 var out = {
41 final p = new Process(cmd, args);
42 final out = {
4243 stdout: p.stdout.readAll().toString(),
4344 stderr: p.stderr.readAll().toString(),
4445 exitCode: p.exitCode()
4748 return out;
4849 }
4950
51 static inline function getDisplayCmd(cmd:String, ?args:Array<String>) {
52 return cmd + (args == null ? '' : ' $args');
53 }
54
5055 /**
5156 Run a command using `Sys.command()`.
52 If the command exits with non-zero code, exit the whole script with the same code.
53
54 If `useRetry` is `true`, the command will be re-run if it exits with non-zero code (3 trials).
55 It is useful for running network-dependent commands.
57 If the command exits with non-zero code, throws `CommandFailure` with the same code.
5658 */
57 static public function runCommand(cmd:String, ?args:Array<String>, useRetry:Bool = false, allowFailure:Bool = false):Void {
58 var trials = useRetry ? 3 : 1;
59 var exitCode:Int = 1;
60 var cmdStr = cmd + (args == null ? '' : ' $args');
61
62 while (trials-->0) {
63 infoMsg('Command: $cmdStr');
64
65 var t = Timer.stamp();
66 exitCode = Sys.command(cmd, args);
67 var dt = Math.round(Timer.stamp() - t);
68
69 if (exitCode == 0) {
70 successMsg('Command exited with $exitCode in ${dt}s: $cmdStr');
59 static public function runCommand(cmd:String, ?args:Array<String>):Void {
60 final exitCode = showAndRunCommand(cmd, args);
61
62 if (exitCode != 0)
63 throw new CommandFailure(exitCode);
64 }
65
66 /** Runs command using `Sys.command()` but ignores failures. **/
67 static public function attemptCommand(cmd:String, ?args:Array<String>) {
68 showAndRunCommand(cmd, args);
69 }
70
71 static function showAndRunCommand(cmd:String, args:Null<Array<String>>, ?displayed:String):Int {
72 if (displayed == null)
73 displayed = getDisplayCmd(cmd, args);
74
75 infoMsg('Command: $displayed');
76
77 final t = Timer.stamp();
78 final exitCode = Sys.command(cmd, args);
79 final dt = Math.round(Timer.stamp() - t);
80
81 final msg = 'Command exited with $exitCode in ${dt}s: $displayed';
82 if (exitCode != 0)
83 failMsg(msg);
84 else
85 successMsg(msg);
86
87 return exitCode;
88 }
89
90
91 static final TRIALS = 3;
92 /**
93 Run a command using `Sys.command()` with up to three attempts. Useful for running network-dependent commands.
94
95 If all three attempts fail, throws a `CommandFailure` with the exit code of the last run.
96 **/
97 static public function runNetworkCommand(cmd:String, ?args:Array<String>) {
98 final cmdStr = getDisplayCmd(cmd, args);
99
100 for (trial in 1...TRIALS+1){
101 final exitCode = showAndRunCommand(cmd, args, cmdStr);
102 if (exitCode == 0)
71103 return;
72 }
73 else
74 failMsg('Command exited with $exitCode in ${dt}s: $cmdStr');
75
76 if (trials > 0) {
77 infoMsg('Command will be re-run...');
78 }
79 }
80
81 if (!allowFailure)
82 fail();
104
105 if (trial == TRIALS)
106 throw new CommandFailure(exitCode);
107
108 infoMsg('Command will be re-run...');
109 }
83110 }
84111
85112 /**
95122 }
96123 }
97124
98 static public function fail():Void {
99 success = false;
100 throw Fail;
101 }
102
103125 static public function addToPATH(path:String):Void {
104126 infoMsg('Prepending $path to PATH.');
105127 switch (systemName) {
110132 }
111133 }
112134
135 static function isLibraryInstalled(library:String):Bool {
136 return new Process("haxelib", ["path", library]).exitCode() == 0;
137 }
138
113139 static public function haxelibInstallGit(account:String, repository:String, ?branch:String, ?srcPath:String, useRetry:Bool = false, ?altName:String):Void {
114 var name:String = (altName == null) ? repository : altName;
115 try {
116 getHaxelibPath(name);
117 infoMsg('$name has already been installed.');
118 } catch (e:Dynamic) {
119 var args:Array<String> = ["git", name, 'https://github.com/$account/$repository'];
120 if (branch != null) {
121 args.push(branch);
122 }
123 if (srcPath != null) {
124 args.push(srcPath);
125 }
126
127 runCommand("haxelib", args, useRetry);
128 }
140 final name = (altName == null) ? repository : altName;
141 // It could only be installed already if we're on a local machine
142 if (!isCi() && isLibraryInstalled(name))
143 return infoMsg('$name has already been installed.');
144
145 final args = ["git", name, 'https://github.com/$account/$repository'];
146 if (branch != null)
147 args.push(branch);
148 if (srcPath != null)
149 args.push(srcPath);
150
151 if (useRetry)
152 runNetworkCommand("haxelib", args);
153 else
154 runCommand("haxelib", args);
129155 }
130156
131157 static public function haxelibInstall(library:String):Void {
132 try {
133 getHaxelibPath(library);
134 infoMsg('$library has already been installed.');
135 } catch (e:Dynamic) {
136 runCommand("haxelib", ["install", library]);
137 }
158 // It could only be installed already if we're on a local machine
159 if (!isCi() && isLibraryInstalled(library))
160 return infoMsg('$library has already been installed.');
161 runCommand("haxelib", ["install", library]);
162 }
163
164 static public function haxelibDev(library:String, path:String):Void {
165 // It could only be installed already if we're on a local machine
166 if (!isCi() && isLibraryInstalled(library))
167 return infoMsg('$library has already been installed.');
168 runCommand("haxelib", ["dev", library, path]);
138169 }
139170
140171 static public function haxelibRun(args:Array<String>, useRetry:Bool = false):Void {
141 runCommand("haxelib", ["run"].concat(args), useRetry);
172 final allArgs = ["run"].concat(args);
173 if (useRetry)
174 runNetworkCommand("haxelib", allArgs);
175 else
176 runCommand("haxelib", allArgs);
142177 }
143178
144179 static public function getHaxelibPath(libName:String) {
145 var proc = new Process("haxelib", ["path", libName]);
180 final proc = new Process("haxelib", ["path", libName]);
181 final code = proc.exitCode();
146182 var result;
147 var code = proc.exitCode();
148183 do {
149184 result = proc.stdout.readLine();
150185 if (!result.startsWith("-L")) {
162197 Sys.println('Changing directory to $path');
163198 Sys.setCwd(path);
164199 }
165 }
200
201 static function mergeArgs(cmd:String, args:Array<String>) {
202 return switch (Sys.systemName()) {
203 case "Windows":
204 [StringTools.replace(cmd, "/", "\\")].concat(args).map(haxe.SysTools.quoteWinArg.bind(_, true)).join(" ");
205 case _:
206 [cmd].concat(args).map(haxe.SysTools.quoteUnixArg).join(" ");
207 }
208 }
209
210 /* command for setting the environment variable to set before sys tests */
211 static final setCommand = if (Sys.systemName() == "Windows") "set"; else "export";
212 static final nameAndValue = "EXISTS=1";
213
214 /** Prepares environment for system tests and runs `cmd` with `args` **/
215 static public function runSysTest(cmd:String, ?args:Array<String>) {
216 final toDisplay = getDisplayCmd(setCommand, [nameAndValue]) + ' && ' + getDisplayCmd(cmd, args);
217
218 if (args != null)
219 cmd = mergeArgs(cmd, args);
220
221 final fullCmd = '$setCommand $nameAndValue && $cmd';
222
223 final exitCode = showAndRunCommand(fullCmd, null, toDisplay);
224
225 if (exitCode != 0)
226 throw new CommandFailure(exitCode);
227 }
228
229 static final installPath = if (systemName == "Windows")
230 Sys.getEnv("USERPROFILE") + "/haxe-ci";
231 else
232 Sys.getEnv("HOME") + "/haxe-ci";
233
234 /** Returns path where packages should be installed. **/
235 public static inline function getInstallPath():String {
236 return installPath;
237 }
238
239 /** Returns path where downloads should be placed. **/
240 public static inline function getDownloadPath():String {
241 return installPath + "/downloads";
242 }
243
244 }
55 var Js = "js";
66 var Lua = "lua";
77 var Php = "php";
8 var Php7 = "php7";
98 var Cpp = "cpp";
109 var Cppia = "cppia";
11 var Flash9 = "flash9";
10 var Flash = "flash";
1211 var Java = "java";
1312 var Jvm = "jvm";
1413 var Cs = "cs";
55
66 class Cpp {
77 static public var gotCppDependencies = false;
8 static final miscCppDir = getMiscSubDir('cpp');
89
910 static public function getCppDependencies() {
1011 if (gotCppDependencies) return;
1213 //hxcpp dependencies
1314 switch (systemName) {
1415 case "Linux":
15 Linux.requireAptPackages(["gcc-multilib", "g++-multilib"]);
16 Linux.requireAptPackages(["gcc-multilib", switch Linux.arch {
17 case Arm64: "g++-multilib-arm-linux-gnueabi";
18 case Amd64: "g++-multilib";
19 }]);
1620 case "Mac":
1721 //pass
1822 }
2024
2125 //install and build hxcpp
2226 try {
23 var path = getHaxelibPath("hxcpp");
27 final path = getHaxelibPath("hxcpp");
2428 infoMsg('hxcpp has already been installed in $path.');
2529 } catch(e:Dynamic) {
2630 haxelibInstallGit("HaxeFoundation", "hxcpp", true);
27 var oldDir = Sys.getCwd();
31 final oldDir = Sys.getCwd();
2832 changeDirectory(getHaxelibPath("hxcpp") + "tools/hxcpp/");
2933 runCommand("haxe", ["-D", "source-header=''", "compile.hxml"]);
3034 changeDirectory(oldDir);
4246 static public function run(args:Array<String>, testCompiled:Bool, testCppia:Bool) {
4347 getCppDependencies();
4448
45 var archFlag = if (systemName == "Windows") "HXCPP_M32" else "HXCPP_M64";
49 final isLinuxArm64 = systemName == 'Linux' && Linux.arch == Arm64;
50
51 final archFlag = switch systemName {
52 case 'Windows':
53 'HXCPP_M32';
54 case 'Linux' if(Linux.arch == Arm64):
55 'HXCPP_LINUX_ARM64';
56 case _:
57 'HXCPP_M64';
58 }
59
4660 if (testCompiled) {
4761 runCommand("rm", ["-rf", "cpp"]);
4862 runCommand("haxe", ["compile-cpp.hxml", "-D", archFlag].concat(args));
5064 }
5165
5266 if (testCppia) {
53 runCommand("haxe", ["compile-cppia-host.hxml"].concat(args));
67 runCommand("haxe", ["compile-cppia-host.hxml", "-D", archFlag].concat(args));
5468 runCommand("haxe", ["compile-cppia.hxml"].concat(args));
5569 runCpp("bin/cppia/Host-debug", ["bin/unit.cppia"]);
56 runCpp("bin/cppia/Host-debug", ["bin/unit.cppia", "-jit"]);
70
71 if (!isLinuxArm64) // FIXME
72 runCpp("bin/cppia/Host-debug", ["bin/unit.cppia", "-jit"]);
5773 }
5874
5975 changeDirectory(sysDir);
60 runCommand("haxe", ["compile-cpp.hxml"].concat(args));
61 runCpp("bin/cpp/Main-debug", []);
76 runCommand("haxe", ["-D", archFlag, "--each", "compile-cpp.hxml"].concat(args));
77 runSysTest(FileSystem.fullPath("bin/cpp/Main-debug"));
6278
63 changeDirectory(threadsDir);
64 runCommand("haxe", ["build.hxml", "-cpp", "export/cpp"]);
65 runCpp("export/cpp/Main");
79 if (!isLinuxArm64) { // FIXME
80 changeDirectory(threadsDir);
81 runCommand("haxe", ["-D", archFlag, "build.hxml", "-cpp", "export/cpp"]);
82 runCpp("export/cpp/Main");
83 }
84
85 changeDirectory(getMiscSubDir("eventLoop"));
86 runCommand("haxe", ["build-cpp.hxml"]);
87 // TODO: check output like misc tests do
88 runCpp("cpp/Main");
6689
6790 // if (Sys.systemName() == "Mac")
6891 // {
69 // changeDirectory(miscDir + "cppObjc");
92 // changeDirectory(getMiscSubDir("cppObjc"));
7093 // runCommand("haxe", ["build.hxml"]);
7194 // runCpp("bin/TestObjc-debug");
7295 // }
96
97 changeDirectory(miscCppDir);
98 runCommand("haxe", ["run.hxml"]);
7399 }
74100 }
44 import runci.Config.*;
55
66 class Cs {
7 static var miscCsDir(get,never):String;
8 static inline function get_miscCsDir() return miscDir + 'cs/';
7 static final miscCsDir = getMiscSubDir('cs');
98
109 static public function getCsDependencies() {
1110 switch (systemName) {
1918 if (commandSucceed("mono", ["--version"]))
2019 infoMsg('mono has already been installed.');
2120 else
22 runCommand("brew", ["install", "mono"], true);
21 runNetworkCommand("brew", ["install", "mono"]);
2322 runCommand("mono", ["--version"]);
2423 case "Windows":
2524 //pass
3231 if (args == null) args = [];
3332 exe = FileSystem.fullPath(exe);
3433 switch (systemName) {
35 case "Linux", "Mac":
34 case "Linux" | "Mac":
3635 runCommand("mono", [exe].concat(args));
3736 case "Windows":
3837 runCommand(exe, args);
4645 for (noroot in [[], ["-D", "no_root"]])
4746 for (erasegenerics in [[], ["-D", "erase_generics"]])
4847 {
49 var extras = fastcast.concat(erasegenerics).concat(noroot);
48 final extras = fastcast.concat(erasegenerics).concat(noroot);
5049 runCommand("haxe", ['compile-cs.hxml'].concat(extras).concat(args));
5150 runCs("bin/cs/bin/TestMain-Debug.exe");
5251
5958
6059 changeDirectory(sysDir);
6160 runCommand("haxe", ["compile-cs.hxml",'-D','fast_cast'].concat(args));
62 runCs("bin/cs/bin/Main-Debug.exe", []);
61 final exe = FileSystem.fullPath("bin/cs/bin/Main-Debug.exe");
62 switch (systemName) {
63 case "Windows":
64 runSysTest(exe);
65 case _:
66 runSysTest("mono", [exe]);
67 }
6368
6469 changeDirectory(threadsDir);
6570 runCommand("haxe", ["build.hxml", "-cs", "export/cs"]);
6873 changeDirectory(miscCsDir);
6974 runCommand("haxe", ["run.hxml"]);
7075
71 changeDirectory(miscCsDir + "csTwoLibs");
76 changeDirectory(getMiscSubDir("cs", "csTwoLibs"));
7277 for (i in 1...5)
7378 {
7479 runCommand("haxe", ['compile-$i.hxml','-D','fast_cast']);
7580 runCs("bin/main/bin/Main.exe");
7681 }
7782 }
78 }
83 }
00 package runci.targets;
11
2 import sys.FileSystem;
23 import sys.io.File;
3 import sys.FileSystem;
4 import sys.io.Process;
5 import haxe.Json;
6 import haxe.Http;
47 import haxe.io.Path;
5 import haxe.Json;
6 import sys.io.Process;
7 import haxe.Http;
88
99 import runci.System.*;
10 import runci.System.CommandFailure;
1011 import runci.Config.*;
1112
13 using StringTools;
14
1215 class Flash {
13 static var miscFlashDir(get,never):String;
14 static inline function get_miscFlashDir() return miscDir + 'flash/';
15
16 static public function getLatestFPVersion():Array<Int> {
17 var appcast = Xml.parse(haxe.Http.requestUrl("http://fpdownload2.macromedia.com/get/flashplayer/update/current/xml/version_en_mac_pep.xml"));
18 var versionStr = new haxe.xml.Access(appcast).node.XML.node.update.att.version;
19 return versionStr.split(",").map(Std.parseInt);
20 }
21
22 static public function setupFlexSdk():Void {
16 static final miscFlashDir = getMiscSubDir('flash');
17 static var playerLocation:String;
18
19 static final DEFAULT_APACHE_MIRROR = "https://downloads.apache.org/";
20
21 static function getPreferredApacheMirror() {
22 return try {
23 Json.parse(Http.requestUrl("https://www.apache.org/dyn/closer.lua?as_json=1")).preferred;
24 } catch (e) {
25 failMsg('Unable to determine preferred Apache mirror. Defaulting to $DEFAULT_APACHE_MIRROR');
26 DEFAULT_APACHE_MIRROR;
27 };
28 }
29
30 static function downloadAndExtractFlexSdk(version:String, sdkPath:String):Void {
31 final apacheMirror = getPreferredApacheMirror();
32 final archiveExtension = if (systemName == "Windows") "zip" else "tar.gz";
33 final archiveName = 'apache-flex-sdk-${version}-bin.$archiveExtension';
34 runNetworkCommand("wget", ["-nv", '${apacheMirror}/flex/${version}/binaries/$archiveName', "-O", getDownloadPath() + '/$archiveName']);
35
36 if (systemName == "Windows") {
37 runCommand("7z", ["x", getDownloadPath() + '/$archiveName', "-o" + sdkPath, "-y"]);
38 } else {
39 runCommand("tar", ["-xf", getDownloadPath() + '/$archiveName', "-C", getInstallPath()]);
40 }
41 }
42
43 static function setupFlexSdk():Void {
2344 if (commandSucceed("mxmlc", ["--version"])) {
2445 infoMsg('mxmlc has already been installed.');
25 } else {
26 var apacheMirror = Json.parse(Http.requestUrl("http://www.apache.org/dyn/closer.lua?as_json=1")).preferred;
27 var flexVersion = "4.16.0";
28 runCommand("wget", ["-nv", '${apacheMirror}/flex/${flexVersion}/binaries/apache-flex-sdk-${flexVersion}-bin.tar.gz'], true);
29 runCommand("tar", ["-xf", 'apache-flex-sdk-${flexVersion}-bin.tar.gz', "-C", Sys.getEnv("HOME")]);
30 var flexsdkPath = Sys.getEnv("HOME") + '/apache-flex-sdk-${flexVersion}-bin';
31 addToPATH(flexsdkPath + "/bin");
32 var playerglobalswcFolder = flexsdkPath + "/player";
33 FileSystem.createDirectory(playerglobalswcFolder + "/11.1");
34 var flashVersion = runci.targets.Flash.getLatestFPVersion();
35 runCommand("wget", ["-nv", 'http://download.macromedia.com/get/flashplayer/updaters/${flashVersion[0]}/playerglobal${flashVersion[0]}_${flashVersion[1]}.swc', "-O", playerglobalswcFolder + "/11.1/playerglobal.swc"], true);
36 File.saveContent(flexsdkPath + "/env.properties", 'env.PLAYERGLOBAL_HOME=$playerglobalswcFolder');
37 runCommand("mxmlc", ["--version"]);
38 }
39 }
40
41 static public var playerCmd:String;
42
43 static public function setupFlashPlayerDebugger():Void {
44 var mmcfgPath = switch (systemName) {
46 return;
47 }
48 // download flex sdk
49 final flexVersion = "4.16.1";
50 final flexSdkPath = Path.normalize(getInstallPath() + '/apache-flex-sdk-${flexVersion}-bin');
51
52 if (FileSystem.exists(flexSdkPath)) {
53 infoMsg('Flex SDK found at $flexSdkPath');
54 } else {
55 downloadAndExtractFlexSdk(flexVersion, flexSdkPath);
56 }
57 addToPATH(flexSdkPath + "/bin");
58
59 // download playerglobal.swc
60 final playerGlobalSwcFolder = flexSdkPath + "/player";
61 final playerGlobalSwcSubFolder = playerGlobalSwcFolder + "/27.0";
62 FileSystem.createDirectory(playerGlobalSwcSubFolder);
63
64 final playerGlobalSwcPath = '$playerGlobalSwcSubFolder/playerglobal.swc';
65
66 if (FileSystem.exists(playerGlobalSwcPath)) {
67 infoMsg('playerglobal.swc found at $playerGlobalSwcPath');
68 } else {
69 final flashVersion = getLatestFPVersion();
70 runNetworkCommand("wget", [
71 "-nv",
72 'https://fpdownload.macromedia.com/get/flashplayer/updaters/${flashVersion[0]}/playerglobal${flashVersion[0]}_${flashVersion[1]}.swc',
73 "-O",
74 playerGlobalSwcPath
75 ]);
76 }
77 // set playerglobal.swc
78 File.saveContent(flexSdkPath + "/env.properties", 'env.PLAYERGLOBAL_HOME=$playerGlobalSwcFolder');
79
80 // ensure flex sdk is working
81 runCommand("mxmlc", ["--version"]);
82 }
83
84 static function getLatestFPVersion():Array<Int> {
85 final appcast = Xml.parse(haxe.Http.requestUrl("http://fpdownload.macromedia.com/get/flashplayer/update/current/xml/version_en_mac_pep.xml"));
86 final versionStr = new haxe.xml.Access(appcast).node.XML.node.update.att.version;
87 return versionStr.split(",").map(Std.parseInt);
88 }
89
90 static function downloadPlayer(version:Int, fileName:String, outputPath:String) {
91 runNetworkCommand("wget", [
92 "-nv",
93 'https://fpdownload.macromedia.com/pub/flashplayer/updaters/$version/$fileName',
94 "-O",
95 '$outputPath/$fileName'
96 ]);
97 }
98
99 static function setupFlashPlayerMac():Void {
100 playerLocation = getInstallPath() + "/Flash Player.app";
101
102 if (FileSystem.exists(playerLocation))
103 infoMsg('Flash player found at $playerLocation');
104 else {
105 final majorVersion = getLatestFPVersion()[0];
106 final packageName = 'flashplayer_${majorVersion}_sa_debug.dmg';
107 downloadPlayer(majorVersion, packageName, getDownloadPath());
108 runCommand("hdiutil", ["attach", getDownloadPath() + '/$packageName']);
109
110 runCommand("cp", ["-R", "/Volumes/Flash Player/Flash Player.app", getInstallPath()]);
111 runCommand("hdiutil", ["detach", "/Volumes/Flash Player"]);
112
113 // Disable the "application downloaded from Internet" warning
114 runCommand("xattr", ["-d", "-r", "com.apple.quarantine", playerLocation]);
115 }
116
117 runCommand("open", ["-a", playerLocation, "-v"]);
118 }
119
120 static function setupFlashPlayerLinux():Void {
121 final playerName = "flashplayerdebugger";
122 playerLocation = Path.join([getInstallPath(), playerName]);
123 if (Sys.command("type", [playerName]) == 0) {
124 playerLocation = playerName;
125 infoMsg('Using $playerName from PATH');
126 } else if(FileSystem.exists(playerLocation)) {
127 infoMsg('Flash player found at $playerLocation');
128 } else {
129 Linux.requireAptPackages(["libglib2.0-0", "libfreetype6"]);
130 final tarFileName = 'flash_player_sa_linux_debug.x86_64.tar.gz';
131 downloadPlayer(getLatestFPVersion()[0], tarFileName, getDownloadPath());
132 runCommand("tar", ["-xf", getDownloadPath() + '/$tarFileName', "-C", getInstallPath()]);
133 }
134
135 // ensure the debugger works
136 switch (ci) {
137 case GithubActions:
138 runCommand("xvfb-run", ["-a", playerLocation, "-v"]);
139 case _:
140 runCommand(playerLocation, ["-v"]);
141 }
142 }
143
144 static function setupFlashPlayerWindows():Void {
145 final majorVersion = getLatestFPVersion()[0];
146 final exeName = 'flashplayer_${majorVersion}_sa_debug.exe';
147 playerLocation = Path.join([getInstallPath(), exeName]);
148
149 if (FileSystem.exists(playerLocation))
150 infoMsg('Flash player found at $playerLocation');
151 else
152 downloadPlayer(majorVersion, exeName, getInstallPath());
153 }
154
155 static function setupFlashPlayer():Void {
156 switch (systemName) {
45157 case "Linux":
46 Sys.getEnv("HOME") + "/mm.cfg";
158 setupFlashPlayerLinux();
47159 case "Mac":
48 "/Library/Application Support/Macromedia/mm.cfg";
160 setupFlashPlayerMac();
161 case "Windows":
162 setupFlashPlayerWindows();
49163 case _:
50164 throw "unsupported system";
51165 }
52
53 switch (systemName) {
54 case "Linux":
55 playerCmd = "flashplayerdebugger";
56 if(Sys.command("type", [playerCmd]) != 0) {
57 Linux.requireAptPackages([
58 "libglib2.0", "libfreetype6"
59 ]);
60 var majorVersion = getLatestFPVersion()[0];
61 runCommand("wget", ["-nv", 'http://fpdownload.macromedia.com/pub/flashplayer/updaters/${majorVersion}/flash_player_sa_linux_debug.x86_64.tar.gz'], true);
62 runCommand("tar", ["-xf", "flash_player_sa_linux_debug.x86_64.tar.gz", "-C", Sys.getEnv("HOME")]);
63 playerCmd = Path.join([Sys.getEnv("HOME"), "flashplayerdebugger"]);
64 }
65 if (!FileSystem.exists(mmcfgPath)) {
66 File.saveContent(mmcfgPath, "ErrorReportingEnable=1\nTraceOutputFileEnable=1");
67 }
68 switch (ci) {
69 case GithubActions:
70 runCommand("xvfb-run", ["-a", playerCmd, "-v"]);
71 case _:
72 runCommand(playerCmd, ["-v"]);
73 }
74 case "Mac":
75 if (commandResult("brew", ["cask", "list", "flash-player-debugger"]).exitCode == 0) {
166 }
167
168 static function readUntil(stdout:haxe.io.Input, expected:String, ?unexpectedStrings:Map<String, ()->Void>) {
169 final possibleStrings = unexpectedStrings?.copy() ?? [];
170 possibleStrings[expected] = function() {};
171 var output = "";
172 while (true) {
173 final char = try {
174 String.fromCharCode(stdout.readByte());
175 } catch (e:haxe.io.Eof) {
176 failMsg('Expected to find "$expected" in stdout');
177 throw new CommandFailure();
178 };
179 Sys.print(char);
180 output += char;
181 for (string => onMatch in possibleStrings) {
182 if (output.endsWith(string)) {
183 onMatch();
76184 return;
77185 }
78 runCommand("brew", ["uninstall", "openssl@1.0.2t"], false, true);
79 runCommand("brew", ["uninstall", "python@2.7.17"], false, true);
80 runCommand("brew", ["untap", "local/openssl"], false, true);
81 runCommand("brew", ["untap", "local/python2"], false, true);
82 runCommand("brew", ["update"]);
83 runCommand("brew", ["install", "--cask", "flash-player-debugger"]);
84
85 // Disable the "application downloaded from Internet" warning
86 runCommand("xattr", ["-d", "-r", "com.apple.quarantine", "/Applications/Flash Player Debugger.app"]);
87
88 var dir = Path.directory(mmcfgPath);
89 if (!FileSystem.exists(dir)) {
90 runCommand("sudo", ["mkdir", "-p", dir]);
91 runCommand("sudo", ["chmod", "a+w", dir]);
92 }
93 if (!FileSystem.exists(mmcfgPath)) {
94 File.saveContent(mmcfgPath, "ErrorReportingEnable=1\nTraceOutputFileEnable=1");
95 }
186 }
96187 }
97188 }
98189
99190 /**
100191 Run a Flash swf file.
101 Return whether the test is successful or not.
102 It detemines the test result by reading the flashlog.txt, looking for "SUCCESS: true".
192 Throws `CommandFailure` if unsuccessful.
103193 */
104 static public function runFlash(swf:String):Bool {
194 static function runFlash(swf:String):Void {
105195 swf = FileSystem.fullPath(swf);
106 Sys.println('going to run $swf');
107 switch (systemName) {
108 case "Linux":
109 switch (ci) {
110 case GithubActions:
111 new Process("xvfb-run", ["-a", playerCmd, swf]);
112 case _:
113 new Process(playerCmd, [swf]);
114 }
196 infoMsg('Running .swf file: $swf');
197
198 final debuggerProcess = new Process("fdb");
199
200 final FDB_PROMPT = "(fdb) ";
201 // waits for the fdb prompt and runs a command
202 function runDebuggerCommand(command:String) {
203 readUntil(debuggerProcess.stdout, FDB_PROMPT);
204 Sys.println(command);
205 debuggerProcess.stdin.writeString('$command\n');
206 }
207
208 runDebuggerCommand("run");
209
210 function onUnexpectedPrompt() {
211 Sys.println("quit");
212 debuggerProcess.stdin.writeString("quit\n");
213 throw new CommandFailure();
214 }
215
216 readUntil(debuggerProcess.stdout, "Waiting for Player to connect", [FDB_PROMPT => onUnexpectedPrompt]);
217 final playerProcess = switch (systemName) {
218 case "Linux" if (ci == GithubActions):
219 new Process("xvfb-run", ["-a", playerLocation, swf]);
115220 case "Mac":
116 Sys.command("open", ["-a", "/Applications/Flash Player Debugger.app", swf]);
117 }
118
119 //wait a little until flashlog.txt is created
120 var flashlogPath = switch (systemName) {
121 case "Linux":
122 Sys.getEnv("HOME") + "/.macromedia/Flash_Player/Logs/flashlog.txt";
123 case "Mac":
124 Sys.getEnv("HOME") + "/Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt";
125 case _:
126 throw "unsupported system";
127 }
128
129 for (t in 0...5) {
130 runCommand("sleep", ["2"]);
131 if (FileSystem.exists(flashlogPath))
132 break;
133 }
134 if (!FileSystem.exists(flashlogPath)) {
135 failMsg('$flashlogPath not found.');
136 return false;
137 }
138
139 //read flashlog.txt continously
140 var traceProcess = new Process("tail", ["-f", flashlogPath]);
141 var success = false;
142 while (true) {
143 try {
144 var line = traceProcess.stdout.readLine();
145 if (line.indexOf("success: ") >= 0) {
146 success = line.indexOf("success: true") >= 0;
147 break;
148 }
149 } catch (e:haxe.io.Eof) {
150 break;
151 }
152 }
153 traceProcess.kill();
154 traceProcess.close();
155 Sys.command("cat", [flashlogPath]);
156 return success;
221 new Process("open", ["-a", playerLocation, swf]);
222 default:
223 new Process(playerLocation, [swf]);
224 };
225
226 readUntil(debuggerProcess.stdout, "Player connected; session starting.", [FDB_PROMPT => onUnexpectedPrompt]);
227 runDebuggerCommand("continue");
228
229 var success = true;
230 readUntil(debuggerProcess.stdout, "(success: true)", [
231 FDB_PROMPT => onUnexpectedPrompt,
232 "(success: false)" => () -> { success = false; }
233 ]);
234
235 runDebuggerCommand("quit");
236
237 debuggerProcess.kill();
238 debuggerProcess.close();
239 playerProcess.kill();
240 playerProcess.close();
241
242 if (!success)
243 throw new CommandFailure();
157244 }
158245
159246 static public function run(args:Array<String>) {
160 setupFlashPlayerDebugger();
247 setupFlashPlayer();
161248 setupFlexSdk();
162 var success = true;
163 for (argsVariant in [[], ["--swf-version", "32"]]) {
164 runCommand("haxe", ["compile-flash9.hxml", "-D", "fdb", "-D", "dump", "-D", "dump_ignore_var_ids"].concat(args).concat(argsVariant));
165 var runSuccess = runFlash("bin/unit9.swf");
166 if (!runSuccess) {
167 success = false;
168 }
249 for (flashVersion in ["11", "32"]) {
250 runCommand("haxe", ["compile-flash.hxml", "-D", "fdb", "-D", "dump", "-D", "dump_ignore_var_ids", "--swf-version", flashVersion].concat(args));
251 runFlash("bin/unit.swf");
169252 }
170253
171254 changeDirectory(miscFlashDir);
172255 runCommand("haxe", ["run.hxml"]);
173
174 if (!success)
175 fail();
176 }
177
256 }
178257
179258 }
44 import runci.System.*;
55 import runci.Config.*;
66
7 using StringTools;
8
79 class Hl {
8 static var hlSrc = switch [ci, systemName] {
9 case [GithubActions, "Windows"]: "C:\\hashlink";
10 case _: Path.join([Sys.getEnv("HOME"), "hashlink"]);
11 };
12 static var hlBuild = switch [ci, systemName] {
13 case [GithubActions, "Windows"]: "C:\\hashlink_build";
14 case _: Path.join([Sys.getEnv("HOME"), "hashlink_build"]);
15 };
16 static var hlBinDir = switch [ci, systemName] {
17 case [GithubActions, "Windows"]: "C:\\hashlink_build\\bin";
18 case _: Path.join([Sys.getEnv("HOME"), "hashlink_build", "bin"]);
19 };
20 static var hlBinary = switch [ci, systemName] {
21 case [GithubActions, "Windows"]: "C:\\hashlink_build\\bin\\hl.exe";
22 case _: Path.join([Sys.getEnv("HOME"), "hashlink_build", "bin", "hl"]);
23 };
10 static final hlSrc = Path.join([getDownloadPath(), "hashlink"]);
2411
25 static public function getHlDependencies() {
26 if (commandSucceed("hl", ["--version"])) {
27 infoMsg('hl has already been installed.');
28 return;
29 }
30 if (!FileSystem.exists(hlSrc)) {
31 runCommand("git", ["clone", "https://github.com/HaxeFoundation/hashlink.git", hlSrc]);
32 } else infoMsg("Reusing hashlink repository");
12 static final hlBuild = Path.join([getInstallPath(), "hashlink_build"]);
3313
34 switch (systemName) {
35 case "Linux":
36 Linux.requireAptPackages(["libpng-dev", "libjpeg-turbo8-dev", "libturbojpeg", "zlib1g-dev", "libvorbis-dev"]);
37 case "Mac":
38 runCommand("brew", ["update", '--preinstall'], true);
39 runCommand("brew", ["bundle", '--file=${hlSrc}/Brewfile'], true);
40 case "Windows":
41 //pass
42 }
14 static final hlBuildBinDir = Path.join([getInstallPath(), "hashlink_build", "bin"]);
4315
44 FileSystem.createDirectory(hlBuild);
45 var generator = systemName == "Windows" ? ["-DCMAKE_SYSTEM_VERSION=10.0.19041.0"] : ["-GNinja"];
46 runCommand("cmake", generator.concat([
47 "-DBUILD_TESTING=OFF",
48 "-DWITH_BULLET=OFF",
49 "-DWITH_DIRECTX=OFF",
50 "-DWITH_FMT=ON",
51 "-DWITH_OPENAL=OFF",
52 "-DWITH_SDL=OFF",
53 "-DWITH_SQLITE=OFF",
54 "-DWITH_SSL=OFF",
55 "-DWITH_UI=OFF",
56 "-DWITH_UV=OFF",
57 "-DWITH_VIDEO=OFF",
58 "-B" + hlBuild,
59 "-H" + hlSrc
60 ]));
61 runCommand("cmake", [
62 "--build", hlBuild
63 ]);
16 static final hlBinary =
17 if (isCi() || !commandSucceed("hl", ["--version"])){
18 Path.join([hlBuildBinDir, "hl"]) + ((systemName == "Windows") ? ".exe" : "");
19 } else {
20 commandResult(if(systemName == "Windows") "where" else "which", ["hl"]).stdout.trim();
21 };
6422
65 runCommand(hlBinary, ["--version"]);
66 addToPATH(hlBinDir);
67 }
23 static final miscHlDir = getMiscSubDir('hl');
6824
69 static public function run(args:Array<String>) {
70 getHlDependencies();
71 runCommand("haxe", ["compile-hl.hxml"].concat(args));
72 runCommand(hlBinary, ["bin/unit.hl"]);
25 static public function getHlDependencies() {
26 if (!isCi() && FileSystem.exists(hlBinary)) {
27 infoMsg('hl has already been installed at $hlBinary.');
28 return;
29 }
30 if (!FileSystem.exists(hlSrc))
31 runCommand("git", ["clone", "https://github.com/HaxeFoundation/hashlink.git", hlSrc]);
32 else
33 infoMsg("Reusing hashlink repository");
7334
74 changeDirectory(threadsDir);
75 runCommand("haxe", ["build.hxml", "-hl", "export/threads.hl"]);
76 runCommand("hl", ["export/threads.hl"]);
35 switch (systemName) {
36 case "Linux":
37 Linux.requireAptPackages(["libpng-dev", "libjpeg-turbo8-dev", "libturbojpeg", "zlib1g-dev", "libvorbis-dev", "libsqlite3-dev"]);
38 case "Mac":
39 runNetworkCommand("brew", ["update", '--preinstall']);
40 runNetworkCommand("brew", ["bundle", '--file=${hlSrc}/Brewfile']);
41 case "Windows":
42 //pass
43 }
7744
78 changeDirectory(sysDir);
79 runCommand("haxe", ["compile-hl.hxml"].concat(args));
80 runCommand(hlBinary, ["bin/hl/sys.hl"]);
81 }
45 FileSystem.createDirectory(hlBuild);
46 final generator = systemName == "Windows" ? ["-DCMAKE_SYSTEM_VERSION=10.0.19041.0"] : ["-GNinja"];
47 runCommand("cmake", generator.concat([
48 "-DBUILD_TESTING=OFF",
49 "-DWITH_DIRECTX=OFF",
50 "-DWITH_FMT=ON",
51 "-DWITH_OPENAL=OFF",
52 "-DWITH_SDL=OFF",
53 "-DWITH_SQLITE=ON",
54 "-DWITH_SSL=OFF",
55 "-DWITH_UI=OFF",
56 "-DWITH_UV=OFF",
57 "-DWITH_VIDEO=OFF",
58 "-B" + hlBuild,
59 "-H" + hlSrc
60 ]));
61 runCommand("cmake", [
62 "--build", hlBuild
63 ]);
64
65 runCommand(hlBinary, ["--version"]);
66 addToPATH(hlBuildBinDir);
67
68 haxelibDev("hashlink", '$hlSrc/other/haxelib/');
69 }
70
71 static public function run(args:Array<String>) {
72 getHlDependencies();
73
74 switch (systemName) {
75 case "Windows":
76 runCommand("haxe", ["compile-hl.hxml"].concat(args));
77 case _:
78 runCommand("haxe", [
79 "compile-hl.hxml",
80 "-D", "no_http", // hl's ssl.hdll is only built on Windows
81 ].concat(args));
82 }
83 runCommand(hlBinary, ["bin/unit.hl"]);
84
85 changeDirectory(threadsDir);
86 runCommand("haxe", ["build.hxml", "-hl", "export/threads.hl"]);
87 runCommand(hlBinary, ["export/threads.hl"]);
88
89 changeDirectory(sysDir);
90 runCommand("haxe", ["compile-hl.hxml"].concat(args));
91 runSysTest(hlBinary, ["bin/hl/sys.hl"]);
92
93 changeDirectory(getMiscSubDir("eventLoop"));
94 runCommand("haxe", ["build-hl.hxml"]);
95 // TODO: check output like misc tests do
96 runCommand(hlBinary, ["eventLoop.hl"]);
97
98 changeDirectory(miscHlDir);
99 runCommand("haxe", ["run.hxml"]);
100 }
82101 }
00 package runci.targets;
11
22 import sys.FileSystem;
3 import haxe.io.Path;
34 import runci.System.*;
45 import runci.Config.*;
56 using StringTools;
67
78 class Java {
8 static var miscJavaDir(get,never):String;
9 static inline function get_miscJavaDir() return miscDir + 'java/';
9 static final miscJavaDir = getMiscSubDir('java');
1010
1111 static public function getJavaDependencies() {
1212 haxelibInstallGit("HaxeFoundation", "hxjava", true);
2828
2929 changeDirectory(sysDir);
3030 runCommand("haxe", ["compile-java.hxml"].concat(args));
31 runCommand("java", ["-jar", "bin/java/Main-Debug.jar"]);
31 runSysTest("java", ["-jar", "bin/java/Main-Debug.jar"]);
3232
3333 changeDirectory(threadsDir);
3434 runCommand("haxe", ["build.hxml", "-java", "export/java"].concat(args));
3535 runCommand("java", ["-jar", "export/java/Main.jar"]);
3636
3737 infoMsg("Testing java-lib extras");
38 changeDirectory('$unitDir/bin');
39 if (!FileSystem.exists('java-lib-tests')) {
40 runCommand("git", ["clone", "https://github.com/waneck/java-lib-tests.git", "--depth", "1"], true);
41 }
42 for (dir in FileSystem.readDirectory('java-lib-tests'))
43 {
44 var path = 'java-lib-tests/$dir';
45 if (FileSystem.isDirectory(path)) for (file in FileSystem.readDirectory(path))
46 {
47 if (file.endsWith('.hxml'))
48 {
49 runCommand("haxe", ["--cwd",'java-lib-tests/$dir',file]);
50 }
51 }
38 changeDirectory(Path.join([unitDir, 'bin']));
39 final libTestDir = 'java-lib-tests';
40 if (!FileSystem.exists(libTestDir))
41 runNetworkCommand("git", ["clone", "https://github.com/waneck/java-lib-tests.git", "--depth", "1"]);
42
43 for (dir in FileSystem.readDirectory(libTestDir)) {
44 final path = Path.join([libTestDir, dir]);
45 if (FileSystem.isDirectory(path))
46 for (file in FileSystem.readDirectory(path))
47 if (file.endsWith('.hxml'))
48 runCommand("haxe", ["--cwd", path, file]);
5249 }
5350 }
54 }
51 }
88 using StringTools;
99
1010 class Js {
11 static final miscJsDir = getMiscSubDir('js');
12
1113 static public function getJSDependencies() {
1214 switch [ci, systemName] {
1315 case [_, "Linux"]:
2325 runCommand("node", ["-v"]);
2426 }
2527
28 static function installNpmPackages(packages:Array<String>) {
29 final required = if (isCi()) {
30 packages;
31 } else {
32 final filtered = packages.filter( (lib) -> {
33 final isInstalled = commandSucceed("npm", ["list", lib]);
34 if (isInstalled)
35 infoMsg('npm package `$lib` has already been installed.');
36 return !isInstalled;
37 });
38 if (filtered.length == 0)
39 return;
40 filtered;
41 };
42 runNetworkCommand("npm", ["install"].concat(required));
43 }
44
2645 static public function run(args:Array<String>) {
2746 getJSDependencies();
2847
29 var jsOutputs = [
48 final jsOutputs = [
3049 for (es_ver in [[], ["-D", "js-es=3"], ["-D", "js-es=6"]])
3150 for (unflatten in [[], ["-D", "js-unflatten"]])
3251 for (classic in [[], ["-D", "js-classic"]])
3352 for (enums_as_objects in [[], ["-D", "js-enums-as-arrays"]])
3453 {
35 var extras = args.concat(es_ver).concat(unflatten).concat(classic).concat(enums_as_objects);
54 final extras = args.concat(es_ver).concat(unflatten).concat(classic).concat(enums_as_objects);
3655
3756 runCommand("haxe", ["compile-js.hxml"].concat(extras));
3857
39 var output = if (extras.length > 0) {
58 final output = if (extras.length > 0) {
4059 "bin/js/" + extras.join("") + "/unit.js";
4160 } else {
4261 "bin/js/default/unit.js";
4362 }
44 var outputDir = Path.directory(output);
45 if (!FileSystem.exists(outputDir)) {
63 final outputDir = Path.directory(output);
64 if (!FileSystem.exists(outputDir))
4665 FileSystem.createDirectory(outputDir);
47 }
66
4867 FileSystem.rename("bin/unit.js", output);
4968 FileSystem.rename("bin/unit.js.map", output + ".map");
5069 runCommand("node", ["-e", "require('./" + output + "').unit.TestMain.main();"]);
5372 ];
5473
5574 infoMsg("Test ES6:");
56 changeDirectory(miscDir + "es6");
75 changeDirectory(getMiscSubDir("es6"));
5776 runCommand("haxe", ["run.hxml"]);
5877
5978 haxelibInstallGit("HaxeFoundation", "hxnodejs");
60 var env = Sys.environment();
79 final env = Sys.environment();
6180 if (
6281 env.exists("SAUCE") &&
6382 env.exists("SAUCE_USERNAME") &&
6483 env.exists("SAUCE_ACCESS_KEY")
6584 ) {
66 var sc = switch (ci) {
85 final sc = switch (ci) {
6786 // TODO: figure out SauceConnect for GitHub Actions
6887 // case AzurePipelines:
6988 // var scVersion = "sc-4.5.3-linux";
86105 }
87106
88107 changeDirectory(unitDir);
89 runCommand("npm", ["install", "wd", "q"], true);
108 installNpmPackages(["wd", "q"]);
90109 runCommand("haxe", ["compile-saucelabs-runner.hxml"]);
91 var server = new Process("nekotools", ["server"]);
110 final server = new Process("nekotools", ["server"]);
92111 runCommand("node", ["bin/RunSauceLabs.js"].concat([for (js in jsOutputs) "unit-js.html?js=" + js.urlEncode()]));
93112
94113 server.close();
106125 changeDirectory(serverDir);
107126 runCommand("haxe", ["build.hxml"]);
108127 runCommand("node", ["test.js"]);
128
129 changeDirectory(sysDir);
130 installNpmPackages(["deasync"]);
131 runCommand("haxe", ["compile-js.hxml"].concat(args));
132 runSysTest("node", ["bin/js/sys.js"]);
133
134 changeDirectory(miscJsDir);
135 runCommand("haxe", ["run.hxml"]);
109136 }
110 }
137 }
44
55 class Jvm {
66 static public function run(args:Array<String>) {
7 deleteDirectoryRecursively("bin/jvm");
8 Java.getJavaDependencies();
9
710 for (level in 0...3) {
8 var args = args.concat(["-D", "jvm.dynamic-level=" + level]);
11 final args = args.concat(["-D", "jvm.dynamic-level=" + level]);
912 runCommand("haxe", ["compile-jvm.hxml"].concat(args));
1013 runCommand("java", ["-jar", "bin/unit.jar"]);
1114
1518
1619 changeDirectory(sysDir);
1720 runCommand("haxe", ["compile-jvm.hxml"].concat(args));
18 runCommand("java", ["-jar", "bin/jvm/sys.jar"]);
21 runSysTest("java", ["-jar", "bin/jvm/sys.jar"]);
1922
2023 changeDirectory(threadsDir);
2124 runCommand("haxe", ["build.hxml", "--jvm", "export/threads.jar"].concat(args));
2225 runCommand("java", ["-jar", "export/threads.jar"]);
2326 }
24 }
27 }
00 package runci.targets;
11
2 import sys.FileSystem;
32 import runci.System.*;
43 import runci.Config.*;
54 import haxe.io.*;
65 using StringTools;
76
87 class Lua {
9 static var miscLuaDir(get,never):String;
10 static inline function get_miscLuaDir() return miscDir + 'lua/';
8 static final miscLuaDir = getMiscSubDir('lua');
119
1210 static public function getLuaDependencies(){
1311 switch (systemName){
1412 case "Linux":
15 Linux.requireAptPackages(["libpcre3-dev", "libssl-dev", "libreadline-dev"]);
13 Linux.requireAptPackages(["libpcre2-dev", "libssl-dev", "libreadline-dev"]);
1614 runCommand("pip", ["install", "--user", "hererocks"]);
17 var pyUserBase = commandResult("python", ["-m", "site", "--user-base"]).stdout.trim();
15 final pyUserBase = commandResult("python", ["-m", "site", "--user-base"]).stdout.trim();
1816 addToPATH(Path.join([pyUserBase, "bin"]));
1917 case "Mac": {
2018 if (commandSucceed("python3", ["-V"]))
2119 infoMsg('python3 has already been installed.');
2220 else
23 runCommand("brew", ["install", "python3"], true);
21 runNetworkCommand("brew", ["install", "python3"]);
2422
25 runCommand("brew", ["install", "pcre"], false, true);
23 attemptCommand("brew", ["install", "pcre2"]);
2624 runCommand("pip3", ["install", "hererocks"]);
25 runCommand("brew", ["install", "openssl"]);
2726 }
2827 }
2928 }
3029
3130 static function installLib(lib : String, version : String, ?server :String){
3231 if (!commandSucceed("luarocks", ["show", lib, version])) {
33 var args = ["install", lib, version];
32 final args = ["install", lib, version];
33 if (systemName == "Mac") {
34 args.push('OPENSSL_DIR=/usr/local/opt/openssl@3');
35 }
3436 if (server != null){
35 var server_arg = '--server=$server';
37 final server_arg = '--server=$server';
3638 args.push(server_arg);
3739 }
3840 runCommand("luarocks", args);
4547
4648 getLuaDependencies();
4749
48 for (lv in ["-l5.1", "-l5.2", "-l5.3", "-j2.0", "-j2.1" ]){
49
50 var envpath = Sys.getEnv("HOME") + '/lua_env$lv';
50 for (lv in ["-l5.1", "-l5.2", "-l5.3"].concat(systemName == 'Linux' && Linux.arch == Arm64 ? [] : ["-j2.0", "-j2.1"])) {
51 final envpath = getInstallPath() + '/lua_env/lua$lv';
5152 addToPATH(envpath + '/bin');
5253
5354 if (systemName == "Mac" && lv.startsWith("-j")) continue;
6667 runCommand("luarocks", ["config", "--rock-trees"]);
6768
6869 // Note: don't use a user config
69 // runCommand("luarocks", ["config", "--user-config"], false, true);
70 // attemptCommand("luarocks", ["config", "--user-config"]);
7071
71 installLib("haxe-deps", "0.0.1-6");
72 installLib("luasec", "1.0.2-1");
73
74 installLib("lrexlib-pcre2", "2.9.1-1");
75 installLib("luv", "1.36.0-0");
76 installLib("luasocket", "3.0rc1-2");
77 installLib("luautf8", "0.1.1-1");
78
79 //Install bit32 for lua 5.1
80 if(lv == "-l5.1"){
81 installLib("bit32", "5.2.2-1");
82 }
83
84 installLib("hx-lua-simdjson", "0.0.1-1");
7285
7386 changeDirectory(unitDir);
7487 runCommand("haxe", ["compile-lua.hxml"].concat(args));
7689
7790 changeDirectory(sysDir);
7891 runCommand("haxe", ["compile-lua.hxml"].concat(args));
79 runCommand("lua", ["bin/lua/sys.lua"]);
92 runSysTest("lua", ["bin/lua/sys.lua"]);
8093
81 changeDirectory(miscDir + "luaDeadCode/stringReflection");
94 changeDirectory(getMiscSubDir("luaDeadCode", "stringReflection"));
8295 runCommand("haxe", ["compile.hxml"]);
8396
8497 changeDirectory(miscLuaDir);
00 package runci.targets;
11
2 import sys.FileSystem;
32 import runci.System.*;
43 import runci.Config.*;
54
2019 infoMsg("Js-es6 null safety:");
2120 runCommand("haxe", ["test-js-es6.hxml"]);
2221
23 changeDirectory(miscDir);
22 changeDirectory(getMiscSubDir());
2423 runCommand("haxe", ["compile.hxml"]);
2524
26 changeDirectory(miscDir + "resolution");
25 changeDirectory(getMiscSubDir("resolution"));
2726 runCommand("haxe", ["run.hxml"]);
2827
2928 changeDirectory(sysDir);
30 runCommand("haxe", ["compile-macro.hxml"].concat(args));
29 runSysTest("haxe", ["compile-macro.hxml"].concat(args));
3130
3231 switch Sys.systemName() {
3332 case 'Linux':
34 changeDirectory(miscDir + 'compiler_loops');
33 changeDirectory(getMiscSubDir('compiler_loops'));
3534 runCommand("haxe", ["run.hxml"]);
3635 case _: // TODO
3736 }
3837
3938 changeDirectory(threadsDir);
4039 runCommand("haxe", ["build.hxml", "--interp"]);
40
41 deleteDirectoryRecursively(partyDir);
42 runCommand("mkdir", [partyDir]);
43 changeDirectory(partyDir);
44 party();
4145 }
42 }
46
47 static function party() {
48 runCommand("git", ["clone", "https://github.com/haxetink/tink_core", "tink_core"]);
49 changeDirectory("tink_core");
50 runCommand("haxelib", ["newrepo"]);
51 runCommand("haxelib", ["install", "tests.hxml", "--always"]);
52 runCommand("haxelib", ["dev", "tink_core", "."]);
53 runCommand("haxe", ["tests.hxml", "-w", "-WDeprecated", "--interp", "--macro", "addMetadata('@:exclude','Futures','testDelay')"]);
54 }
55 }
00 package runci.targets;
11
2 import sys.FileSystem;
32 import runci.System.*;
43 import runci.Config.*;
54
87 runCommand("haxe", ["compile-neko.hxml", "-D", "dump", "-D", "dump_ignore_var_ids"].concat(args));
98 runCommand("neko", ["bin/unit.n"]);
109
10 changeDirectory(getMiscSubDir('neko'));
11 runCommand("haxe", ["run.hxml"].concat(args));
12
1113 changeDirectory(sysDir);
1214 runCommand("haxe", ["compile-neko.hxml"].concat(args));
13 runCommand("neko", ["bin/neko/sys.n"]);
15 runSysTest("neko", ["bin/neko/sys.n"]);
1416
1517 changeDirectory(threadsDir);
1618 runCommand("haxe", ["build.hxml", "--neko", "export/threads.n"]);
1719 runCommand("neko", ["export/threads.n"]);
1820 }
19 }
21 }
00 package runci.targets;
11
2 import sys.FileSystem;
32 import runci.System.*;
43 import runci.Config.*;
54
5 using haxe.io.Path;
6
67 class Php {
7 static var miscPhpDir(get,never):String;
8 static inline function get_miscPhpDir() return miscDir + 'php/';
8 static final miscPhpDir = getMiscSubDir('php');
9
10 static final windowsPhpIni = cwd + 'PHP.ini';
11
12 static var windowsPhpExtPath(get, null) = null;
13 static function get_windowsPhpExtPath() {
14 if (windowsPhpExtPath != null)
15 return windowsPhpExtPath;
16
17 final phpPath = commandResult("where", ["php"]).stdout;
18 return windowsPhpExtPath = Path.join([phpPath.directory(), "ext"]);
19 }
20
21
22 static function generateArgs(file:String) {
23 if (systemName != "Windows")
24 return [file];
25 return [
26 "-c",
27 windowsPhpIni,
28 "-d",
29 'extension_dir=$windowsPhpExtPath',
30 file
31 ];
32 }
933
1034 static public function getPhpDependencies() {
11 var phpCmd = commandResult("php", ["-v"]);
12 var phpVerReg = ~/PHP ([0-9]+\.[0-9]+)/i;
13 var phpVer = if (phpVerReg.match(phpCmd.stdout))
35 final phpCmd = commandResult("php", ["-v"]);
36 final phpVerReg = ~/PHP ([0-9]+\.[0-9]+)/i;
37 final phpVer = if (phpVerReg.match(phpCmd.stdout))
1438 Std.parseFloat(phpVerReg.matched(1));
1539 else
1640 null;
1842 if (phpCmd.exitCode == 0 && phpVer != null && phpVer >= 7.0) {
1943 switch systemName {
2044 case "Linux":
21 var phpInfo = commandResult("php", ["-i"]);
22 if(phpInfo.stdout.indexOf("mbstring => enabled") < 0) {
45 var phpInfo = commandResult("php", ["-i"]).stdout;
46 if(phpInfo.indexOf("mbstring => enabled") < 0) {
2347 Linux.requireAptPackages(["php-mbstring"]);
2448 }
2549 case _:
2650 }
27 infoMsg('php ${phpVer} has already been installed.');
51 infoMsg('php $phpVer has already been installed.');
2852 return;
2953 }
3054 switch systemName {
3155 case "Linux":
32 Linux.requireAptPackages(["php-cli", "php-mbstring"]);
56 Linux.requireAptPackages(["php-cli", "php-mbstring", "php-sqlite3"]);
3357 case "Mac":
34 runCommand("brew", ["install", "php"], true);
58 runNetworkCommand("brew", ["install", "php"]);
3559 case "Windows":
36 runCommand("cinst", ["php", "-version", "7.1.8", "-y"], true);
60 runNetworkCommand("cinst", ["php", "-version", "7.1.8", "-y"]);
3761 case _:
3862 throw 'unknown system: $systemName';
3963 }
4670 changeDirectory(miscPhpDir);
4771 runCommand("haxe", ["run.hxml"]);
4872
49 var binDir = "bin/php";
73 final binDir = "bin/php";
5074
51 var prefixes = [[]];
75 final prefixes = [[]];
5276 if(isCi()) {
5377 prefixes.push(['-D', 'php-prefix=haxe']);
5478 prefixes.push(['-D', 'php-prefix=my.pack']);
5680
5781 for(prefix in prefixes) {
5882 changeDirectory(unitDir);
59 if(isCi()) {
83 if(isCi())
6084 deleteDirectoryRecursively(binDir);
61 }
6285
6386 runCommand("haxe", ["compile-php.hxml"].concat(prefix).concat(args));
64 runThroughPhpVersions(runCommand.bind(_, [binDir + "/index.php"]));
87 runCommand("php", generateArgs(binDir + "/index.php"));
6588
6689 changeDirectory(sysDir);
67 if(isCi()) {
90 if(isCi())
6891 deleteDirectoryRecursively(binDir);
69 }
92
7093 runCommand("haxe", ["compile-php.hxml"].concat(prefix).concat(args));
71 runThroughPhpVersions(runCommand.bind(_, ["bin/php/Main/index.php"]));
94 runSysTest("php", generateArgs(binDir + "/Main/index.php"));
7295 }
7396 }
74
75 static function runThroughPhpVersions(fn:(phpCmd:String)->Void) {
76 switch [ci, systemName] {
77 case [GithubActions, "Linux"]:
78 for(version in ['7.1', '7.2', '7.3', '7.4']) {
79 fn('php$version');
80 }
81 case _:
82 fn('php');
83 }
84 }
85 }
97 }
44 import runci.Config.*;
55
66 class Python {
7 static var miscPythonDir(get,never):String;
8 static inline function get_miscPythonDir() return miscDir + 'python/';
9
107 static public function getPythonDependencies():Array<String> {
118 switch (systemName) {
129 case "Linux":
2017 if (commandSucceed(pypy, ["-V"])) {
2118 infoMsg('pypy3 has already been installed.');
2219 } else {
23 var pypyVersion = "pypy3.6-v7.3.1-linux64";
24 var file = '${pypyVersion}.tar.bz2';
20 final pypyVersion = "pypy3.8-v7.3.7-" + (switch Linux.arch {
21 case Arm64: "aarch64";
22 case Amd64: "linux64";
23 });
24 final file = '${pypyVersion}.tar.bz2';
2525 if(!FileSystem.exists(file)) {
26 runCommand("wget", ["-nv", 'https://downloads.python.org/pypy/$file'], true);
26 runNetworkCommand("wget", ["-nv", 'https://downloads.python.org/pypy/$file']);
2727 }
2828 runCommand("tar", ["-xf", file]);
2929 pypy = FileSystem.fullPath('${pypyVersion}/bin/pypy3');
3535 if (commandSucceed("python3", ["-V"]))
3636 infoMsg('python3 has already been installed.');
3737 else
38 runCommand("brew", ["install", "python3"], true);
38 runNetworkCommand("brew", ["install", "python3"]);
3939 runCommand("python3", ["-V"]);
4040
4141 if (commandSucceed("pypy3", ["-V"]))
4242 infoMsg('pypy3 has already been installed.');
4343 else
44 runCommand("brew", ["install", "pypy3"], true);
44 runNetworkCommand("brew", ["install", "pypy3"]);
4545 runCommand("pypy3", ["-V"]);
4646
4747 return ["python3", "pypy3"];
5858 }
5959
6060 static public function run(args:Array<String>) {
61 var pys = getPythonDependencies();
61 final pys = getPythonDependencies();
6262 runCommand("haxe", ["compile-python.hxml"].concat(args));
6363 for (py in pys) {
6464 runCommand(py, ["bin/unit.py"]);
65 // Additional test for python-version >= 3.4
66 runCommand(py, ["bin/unit34.py"]);
6567 }
6668
6769 changeDirectory(sysDir);
6870 runCommand("haxe", ["compile-python.hxml"].concat(args));
6971 for (py in pys) {
70 runCommand(py, ["bin/python/sys.py"]);
72 runSysTest(py, ["bin/python/sys.py"]);
7173 }
7274
73 changeDirectory(miscPythonDir);
75 changeDirectory(getMiscSubDir("python"));
7476 runCommand("haxe", ["run.hxml"]);
7577
76 changeDirectory(miscPythonDir + "pythonImport");
78 changeDirectory(getMiscSubDir('python', "pythonImport"));
7779 runCommand("haxe", ["compile.hxml"]);
7880 for (py in pys) {
7981 runCommand(py, ["test.py"]);
8587 runCommand(py, ["export/threads.py"]);
8688 }
8789 }
88 }
90 }
00 {
11 "haxe.diagnosticsPathFilter": "${workspaceRoot}/src",
2 // "editor.formatOnSave": true,
2 "editor.formatOnSave": true,
33 "haxeTestExplorer.testCommand": [
44 "${haxe}",
55 "build.hxml",
77 "test-adapter",
88 "-cmd",
99 "node test.js"
10 ]
10 ],
11 "haxe.enableCompilationServer": false
1112 }
22 "tasks": [
33 {
44 "type": "hxml",
5 "file": "build.hxml",
5 "file": "run.hxml",
66 "group": {
77 "kind": "build",
88 "isDefault": true
99 # or set UTEST_PATTERN environment variable
1010
1111 #Temporary. To find out what's wrong with random CI failures
12 --macro addMetadata('@:build(utils.macro.DebugFailures.patchAssert())', 'utest.Assert')
12 #--macro addMetadata('@:build(utils.macro.DebugFailures.patchAssert())', 'utest.Assert')
0
1 enum SkipReason {
2 DependencyDirty(path:String);
3 Tainted(cause:String);
4 FileChanged(file:String);
5 Shadowed(file:String);
6 LibraryChanged;
7 }
0 import SkipReason;
01 import haxe.PosInfos;
12 import haxe.Exception;
23 import haxe.display.Position;
1617
1718 @:autoBuild(utils.macro.BuildHub.build())
1819 class TestCase implements ITest {
19 static public var debugLastResult:{hasError:Bool, stdout:String, stderr:String, prints:Array<String>};
20 static public var debugLastResult:{
21 hasError:Bool,
22 stdout:String,
23 stderr:String,
24 prints:Array<String>
25 };
2026
2127 var server:HaxeServerAsync;
2228 var vfs:Vfs;
2935
3036 public function new() {}
3137
32 public function setup() {
38 static public function printSkipReason(ddr:SkipReason) {
39 return switch (ddr) {
40 case DependencyDirty(path): 'DependencyDirty $path';
41 case Tainted(cause): 'Tainted $cause';
42 case FileChanged(file): 'FileChanged $file';
43 case Shadowed(file): 'Shadowed $file';
44 case LibraryChanged: 'LibraryChanged';
45 }
46 }
47
48 public function setup(async:utest.Async) {
3349 testDir = "test/cases/" + i++;
3450 vfs = new Vfs(testDir);
35 server = new HaxeServerAsync(() -> new HaxeServerProcessNode("haxe", ["-v", "--cwd", testDir]));
51 server = new HaxeServerAsync(() -> new HaxeServerProcessNode("haxe", ["-v", "--cwd", testDir], {}, () -> async.done()));
3652 }
3753
3854 public function teardown() {
3955 server.stop();
4056 }
4157
42 function runHaxe(args:Array<String>, done:()->Void) {
58 function runHaxe(args:Array<String>, done:() -> Void) {
4359 messages = [];
4460 errorMessages = [];
4561 server.rawRequest(args, null, function(result) {
6278 }, sendErrorMessage);
6379 }
6480
65 function runHaxeJson<TParams, TResponse>(args:Array<String>, method:HaxeRequestMethod<TParams, TResponse>, methodArgs:TParams, done:()->Void) {
81 function runHaxeJson<TParams, TResponse>(args:Array<String>, method:HaxeRequestMethod<TParams, TResponse>, methodArgs:TParams, done:() -> Void) {
6682 var methodArgs = {method: method, id: 1, params: methodArgs};
6783 args = args.concat(['--display', Json.stringify(methodArgs)]);
6884 runHaxe(args, done);
85 }
86
87 function runHaxeJsonCb<TParams, TResponse>(args:Array<String>, method:HaxeRequestMethod<TParams, Response<TResponse>>, methodArgs:TParams,
88 callback:TResponse->Void, done:() -> Void) {
89 var methodArgs = {method: method, id: 1, params: methodArgs};
90 args = args.concat(['--display', Json.stringify(methodArgs)]);
91 server.rawRequest(args, null, function(result) {
92 callback(Json.parse(result.stderr).result.result);
93 done();
94 }, function(msg) {
95 sendErrorMessage(msg);
96 done();
97 });
6998 }
7099
71100 function sendErrorMessage(msg:String) {
149178 }
150179
151180 function assertSuccess(?p:haxe.PosInfos) {
152 Assert.isTrue(0 == errorMessages.length, p);
181 return Assert.isTrue(0 == errorMessages.length, p);
153182 }
154183
155184 function assertErrorMessage(message:String, ?p:haxe.PosInfos) {
156 Assert.isTrue(hasErrorMessage(message), p);
185 return Assert.isTrue(hasErrorMessage(message), p);
157186 }
158187
159188 function assertHasPrint(line:String, ?p:haxe.PosInfos) {
160 Assert.isTrue(hasMessage("Haxe print: " + line), null, p);
189 return Assert.isTrue(hasMessage("Haxe print: " + line), null, p);
161190 }
162191
163192 function assertReuse(module:String, ?p:haxe.PosInfos) {
164 Assert.isTrue(hasMessage('reusing $module'), null, p);
165 }
166
167 function assertSkipping(module:String, ?dependency:String, ?p:haxe.PosInfos) {
168 var msg = 'skipping $module';
169 if (dependency != null) {
170 msg += '($dependency)';
171 }
172 Assert.isTrue(hasMessage(msg), null, p);
193 return Assert.isTrue(hasMessage('reusing $module'), null, p);
194 }
195
196 function assertSkipping(module:String, reason:SkipReason, ?p:haxe.PosInfos) {
197 var msg = 'skipping $module (${printSkipReason(reason))})';
198 return Assert.isTrue(hasMessage(msg), null, p);
173199 }
174200
175201 function assertNotCacheModified(module:String, ?p:haxe.PosInfos) {
176 Assert.isTrue(hasMessage('$module not cached (modified)'), null, p);
202 return Assert.isTrue(hasMessage('$module not cached (modified)'), null, p);
177203 }
178204
179205 function assertHasType(typePackage:String, typeName:String, ?p:haxe.PosInfos) {
180 Assert.isTrue(getStoredType(typePackage, typeName) != null, null, p);
206 return Assert.isTrue(getStoredType(typePackage, typeName) != null, null, p);
181207 }
182208
183209 function assertHasField(typePackage:String, typeName:String, fieldName:String, isStatic:Bool, ?p:haxe.PosInfos) {
195221 }
196222 }
197223
198 function assertClassField(completion:CompletionResult, name:String, ?callback:(field:JsonClassField)->Void, ?pos:PosInfos) {
224 function assertClassField(completion:CompletionResult, name:String, ?callback:(field:JsonClassField) -> Void, ?pos:PosInfos) {
199225 for (item in completion.result.items) {
200226 switch item.kind {
201 case ClassField if(item.args.field.name == name):
227 case ClassField if (item.args.field.name == name):
202228 switch callback {
203229 case null: Assert.pass(pos);
204230 case fn: fn(item.args.field);
0 package cases;
1
2 import haxe.display.FsPath;
3 import haxe.display.Server;
4 import utest.Assert;
5
6 using StringTools;
7 using Lambda;
8
9 class RetyperTests extends TestCase {
10 static function getBaseArgs(moduleName:String) {
11 return [
12 moduleName + ".hx",
13 "--no-output",
14 "-js",
15 "no.js",
16 "--macro",
17 "haxe.macro.CompilationServer.setModuleCheckPolicy(['" + moduleName + "'], [Retype], false)"
18 ];
19 }
20
21 function testNonSignature() {
22 vfs.putContent("WithDependency.hx", getTemplate("WithDependency.hx"));
23 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
24 var args = getBaseArgs("WithDependency");
25 runHaxe(args);
26 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
27 runHaxe(args);
28 Assert.isTrue(hasMessage('retyped WithDependency'));
29 }
30
31 function testSignature() {
32 vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependency.hx"));
33 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
34 var args = getBaseArgs("WithSignatureDependency");
35 runHaxe(args);
36 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
37 runHaxe(args);
38 Assert.isTrue(hasMessage('failed retyping WithSignatureDependency'));
39 Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]'));
40 }
41
42 function testSignatureInferredArg() {
43 vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyInferredArg.hx"));
44 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
45 var args = getBaseArgs("WithSignatureDependency");
46 runHaxe(args);
47 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
48 runHaxe(args);
49 Assert.isTrue(hasMessage('failed retyping WithSignatureDependency'));
50 Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]'));
51 }
52
53 function testSignatureInferredRet() {
54 vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyInferredRet.hx"));
55 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
56 var args = getBaseArgs("WithSignatureDependency");
57 runHaxe(args);
58 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
59 runHaxe(args);
60 Assert.isTrue(hasMessage('failed retyping WithSignatureDependency'));
61 Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]'));
62 }
63
64 function testSignatureVariable() {
65 vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyVariable.hx"));
66 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
67 var args = getBaseArgs("WithSignatureDependency");
68 runHaxe(args);
69 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
70 runHaxe(args);
71 Assert.isTrue(hasMessage('failed retyping WithSignatureDependency'));
72 Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]'));
73 }
74
75 function testSignatureInferredVariable() {
76 vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyInferredVariable.hx"));
77 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
78 var args = getBaseArgs("WithSignatureDependency");
79 runHaxe(args);
80 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
81 runHaxe(args);
82 Assert.isTrue(hasMessage('failed retyping WithSignatureDependency'));
83 Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]'));
84 }
85
86 function testSignatureProperty() {
87 vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyProperty.hx"));
88 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
89 var args = getBaseArgs("WithSignatureDependency");
90 runHaxe(args);
91 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
92 runHaxe(args);
93 Assert.isTrue(hasMessage('failed retyping WithSignatureDependency'));
94 Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]'));
95 }
96
97 function testSignatureInferredProperty() {
98 vfs.putContent("WithSignatureDependency.hx", getTemplate("retyper/WithSignatureDependencyInferredProperty.hx"));
99 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
100 var args = getBaseArgs("WithSignatureDependency");
101 runHaxe(args);
102 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
103 runHaxe(args);
104 Assert.isTrue(hasMessage('failed retyping WithSignatureDependency'));
105 Assert.isTrue(hasMessage('[Module WithSignatureDependency] [Class WithSignatureDependency] [Field test]: Could not load [Module Dependency]'));
106 }
107
108 function testMutual() {
109 vfs.putContent("WithMutualDependency.hx", getTemplate("retyper/WithMutualDependency.hx"));
110 vfs.putContent("MutualDependency.hx", getTemplate("retyper/MutualDependency.hx"));
111 var args = getBaseArgs("WithMutualDependency");
112 runHaxe(args);
113 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MutualDependency.hx")});
114 runHaxe(args);
115 Assert.isTrue(hasMessage('retyped WithMutualDependency'));
116 }
117
118 function testParent() {
119 vfs.putContent("WithParentDependency.hx", getTemplate("retyper/WithParentDependency.hx"));
120 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
121 var args = getBaseArgs("WithParentDependency");
122 runHaxe(args);
123 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
124 runHaxe(args);
125 Assert.isTrue(hasMessage('failed retyping WithParentDependency'));
126 Assert.isTrue(hasMessage('[Module WithParentDependency] [Class WithParentDependency] [Relations]: Could not load [Module Dependency]'));
127 }
128
129 function testInterface() {
130 vfs.putContent("WithInterfaceDependency.hx", getTemplate("retyper/WithInterfaceDependency.hx"));
131 vfs.putContent("InterfaceDependency.hx", getTemplate("retyper/InterfaceDependency.hx"));
132 var args = getBaseArgs("WithInterfaceDependency");
133 runHaxe(args);
134 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("InterfaceDependency.hx")});
135 runHaxe(args);
136 Assert.isTrue(hasMessage('failed retyping WithInterfaceDependency'));
137 Assert.isTrue(hasMessage('[Module WithInterfaceDependency] [Class WithInterfaceDependency] [Relations]: Could not load [Module InterfaceDependency]'));
138 }
139
140 function testIndependentEnum() {
141 vfs.putContent("IndependentEnum.hx", getTemplate("retyper/IndependentEnum.hx"));
142 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
143 var args = getBaseArgs("IndependentEnum");
144 runHaxe(args);
145 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
146 runHaxe(args);
147 Assert.isTrue(hasMessage('retyped IndependentEnum'));
148 }
149
150 function testDependentEnum() {
151 vfs.putContent("DependentEnum.hx", getTemplate("retyper/DependentEnum.hx"));
152 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
153 var args = getBaseArgs("DependentEnum");
154 runHaxe(args);
155 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
156 runHaxe(args);
157 Assert.isTrue(hasMessage('failed retyping DependentEnum'));
158 Assert.isTrue(hasMessage('[Module DependentEnum] [Enum DependentEnum] [Field Constructor]: Could not load [Module Dependency]'));
159 }
160
161 function testIndependentTypedef() {
162 vfs.putContent("IndependentTypedef.hx", getTemplate("retyper/IndependentTypedef.hx"));
163 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
164 var args = getBaseArgs("IndependentTypedef");
165 runHaxe(args);
166 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
167 runHaxe(args);
168 Assert.isTrue(hasMessage('retyped IndependentTypedef'));
169 }
170
171 function testDependentTypedef() {
172 vfs.putContent("DependentTypedef.hx", getTemplate("retyper/DependentTypedef.hx"));
173 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
174 var args = getBaseArgs("DependentTypedef");
175 runHaxe(args);
176 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
177 runHaxe(args);
178 Assert.isTrue(hasMessage('failed retyping DependentTypedef'));
179 Assert.isTrue(hasMessage('[Module DependentTypedef] [Typedef DependentTypedef]: Could not load [Module Dependency]'));
180 }
181
182 function testAbstractNonSignature() {
183 vfs.putContent("AbstractWithDependency.hx", getTemplate("retyper/AbstractWithDependency.hx"));
184 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
185 var args = getBaseArgs("AbstractWithDependency");
186 runHaxe(args);
187 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
188 runHaxe(args);
189 Assert.isTrue(hasMessage('retyped AbstractWithDependency'));
190 }
191
192 function testAbstractSignature() {
193 vfs.putContent("AbstractWithSignatureDependency.hx", getTemplate("retyper/AbstractWithSignatureDependency.hx"));
194 vfs.putContent("Dependency.hx", getTemplate("Dependency.hx"));
195 var args = getBaseArgs("AbstractWithSignatureDependency");
196 runHaxe(args);
197 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
198 runHaxe(args);
199 Assert.isTrue(hasMessage('failed retyping AbstractWithSignatureDependency'));
200 Assert.isTrue(hasMessage('[Module AbstractWithSignatureDependency] [Abstract AbstractWithSignatureDependency] [Field test]: Could not load [Module Dependency]'));
201 }
202 }
2424 runHaxe(args);
2525 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")});
2626 runHaxe(args);
27 assertSkipping("HelloWorld");
27 assertSkipping("HelloWorld", Tainted("server/invalidate"));
2828 // assertNotCacheModified("HelloWorld");
2929 }
3030
3535 runHaxe(args);
3636 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")});
3737 runHaxe(args);
38 assertSkipping("WithDependency", "Dependency");
38 assertSkipping("WithDependency", DependencyDirty("Dependency - Tainted server/invalidate"));
3939 // assertNotCacheModified("Dependency");
4040 runHaxe(args);
4141 assertReuse("Dependency");
7777 var args = ["-main", "BuiltClass.hx", "--interp"];
7878 runHaxe(args);
7979 runHaxe(args);
80 assertReuse("BuiltClass");
80 /* This often fails on our CI because the reported stdout is empty. I don't know why this is the case,
81 but it's probably some obscure timing issue related to pipes which has nothing to do with that we
82 actually want to test here. */
83 // trace(lastResult);
84 // assertReuse("BuiltClass");
8185 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("BuildMacro.hx")});
8286 runHaxe(args);
8387 // assertNotCacheModified("BuildMacro");
84 assertSkipping("BuiltClass", "BuildMacro");
85 assertSkipping("BuildMacro");
88 assertSkipping("BuiltClass", DependencyDirty("BuildMacro - Tainted server/invalidate"));
89 assertSkipping("BuildMacro", Tainted("server/invalidate"));
8690 }
8791
8892 function testBrokenSyntaxDiagnostics() {
104108 assertSuccess();
105109 }
106110
107 #if false // @see https://github.com/HaxeFoundation/haxe/issues/8596#issuecomment-518815594
108111 function testDisplayModuleRecache() {
109112 vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
110113 var args = ["--main", "HelloWorld", "--interp"];
123126 runHaxe(args2);
124127
125128 runHaxe(args);
126 assertSkipping("HelloWorld");
127 }
128 #end
129
130 #if false // @see https://github.com/HaxeFoundation/haxe/issues/8596#issuecomment-518815594
129 assertSkipping("HelloWorld", Tainted("check_display_file"));
130 }
131
131132 function testMutuallyDependent() {
132133 vfs.putContent("MutuallyDependent1.hx", getTemplate("MutuallyDependent1.hx"));
133134 vfs.putContent("MutuallyDependent2.hx", getTemplate("MutuallyDependent2.hx"));
139140 runHaxe(args);
140141 assertSuccess();
141142 }
142 #end
143
144 function testDiagnosticsRecache() {
145 vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
146 var args = ["--main", "HelloWorld", "--interp"];
147 runHaxe(args);
148 runHaxe(args);
149 assertReuse("HelloWorld");
150 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")});
151 runHaxe(args);
152 assertSkipping("HelloWorld", Tainted("server/invalidate"));
153 runHaxe(args.concat(["--display", "HelloWorld.hx@0@diagnostics"]));
154 runHaxe(args);
155 assertReuse("HelloWorld");
156 }
157
158 function testDiagnosticsRecache2() {
159 vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
160 var args = ["--main", "HelloWorld", "--interp"];
161 runHaxe(args.concat(["--display", "HelloWorld.hx@0@diagnostics"]));
162 runHaxe(args);
163 assertReuse("HelloWorld");
164 }
165
166 function testDiagnosticsRecache3() {
167 vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
168 var args = ["--main", "HelloWorld", "--interp"];
169 runHaxe(args);
170 runHaxe(args);
171 assertReuse("HelloWorld");
172 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")});
173 runHaxe(args.concat(["--display", "HelloWorld.hx@0@diagnostics"]));
174 runHaxe(args.concat(["--display", "HelloWorld.hx@0@hover"]));
175 assertReuse("HelloWorld");
176 }
143177
144178 function testSyntaxCache() {
145179 vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
198232 return ~/[\r\n\t]/g.replace(s, "");
199233 }
200234 utest.Assert.equals("function() {_Vector.Vector_Impl_.toIntVector(null);}", moreHack(type.args.statics[0].expr.testHack)); // lmao
235 }
236
237 function test10986() {
238 vfs.putContent("Main.hx", getTemplate("issues/Issue10986/Main.hx"));
239 vfs.putContent("haxe/ds/Vector.hx", getTemplate("issues/Issue10986/Vector.hx"));
240 var args = ["-main", "Main", "--jvm", "Main.jar"];
241 runHaxe(args);
242 vfs.touchFile("haxe/ds/Vector.hx");
243 runHaxe(args);
244 assertSuccess();
245
201246 }
202247
203248 // See https://github.com/HaxeFoundation/haxe/issues/8368#issuecomment-525379060
213258 assertSuccess();
214259 }
215260 #end
261
262 function testXRedefinedFromX_2() {
263 vfs.putContent("Main.hx", getTemplate("issues/Issue8368/Main2.hx"));
264 var transform = Marker.extractMarkers(getTemplate("issues/Issue8368/MyMacro2.macro.hx"));
265 var args = ["-main", "Main", "--macro", "define('whatever')"];
266
267 vfs.putContent(
268 "MyMacro.macro.hx",
269 transform.source.substr(0, transform.markers[1])
270 + transform.source.substr(transform.markers[2], transform.source.length)
271 );
272
273 runHaxe(args);
274 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MyMacro.macro.hx")});
275
276 var completionRequest = {file: new FsPath("MyMacro.macro.hx"), contents: transform.source, offset: transform.markers[2], wasAutoTriggered: false};
277 runHaxeJson(args, DisplayMethods.Completion, completionRequest);
278 Assert.isTrue(parseCompletion().result.items.length == 23);
279 runHaxeJson(args, DisplayMethods.Completion, completionRequest);
280 Assert.isTrue(parseCompletion().result.items.length == 23);
281 runHaxeJson(args, DisplayMethods.Completion, completionRequest);
282 Assert.isTrue(parseCompletion().result.items.length == 23);
283
284 runHaxe(args);
285 assertSuccess();
286 }
287
288 @:async function testStackOverflow(async:utest.Async) {
289 vfs.putContent("Empty.hx", getTemplate("Empty.hx"));
290 var args = ["-main", "Empty.hx", "--macro", "allowPackage('sys')", "--interp", "--no-output"];
291 var runs = 0;
292
293 function runLoop() {
294 runHaxe(args.concat(["--display", "Empty.hx@0@diagnostics"]), () -> {
295 runHaxe(args.concat(["-D", "compile-only-define"]), () -> {
296 if (assertSuccess() && ++runs < 20) runLoop();
297 else async.done();
298 });
299 });
300 }
301
302 async.setTimeout(20000);
303 runLoop();
304 }
216305
217306 function testMacroStaticsReset() {
218307 vfs.putContent("Main.hx", getTemplate("issues/Issue8631/Main.hx"));
225314 utest.Assert.equals('2', counter);
226315 }
227316
228 // function testIssue8616() {
229 // vfs.putContent("Main.hx", getTemplate("issues/Issue8616/Main.hx"));
230 // vfs.putContent("A.hx", getTemplate("issues/Issue8616/A.hx"));
231 // var args = ["-main", "Main", "-js", "out.js"];
232 // runHaxe(args);
233 // runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
234 // runHaxe(args);
235 // var content = sys.io.File.getContent(haxe.io.Path.join([testDir, "out.js"]));
236 // Assert.isTrue(content.indexOf("this1.use(v1)") != -1);
237 // }
317 function testIssue8616() {
318 vfs.putContent("Main.hx", getTemplate("issues/Issue8616/Main.hx"));
319 vfs.putContent("A.hx", getTemplate("issues/Issue8616/A.hx"));
320 var args = ["-main", "Main", "-js", "out.js"];
321 runHaxe(args);
322 var originalContent = sys.io.File.getContent(haxe.io.Path.join([testDir, "out.js"]));
323 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
324 runHaxe(args);
325 var content = sys.io.File.getContent(haxe.io.Path.join([testDir, "out.js"]));
326 Assert.isTrue(content == originalContent);
327 }
238328
239329 function test9918() {
240330 vfs.putContent("Issue9918.hx", getTemplate("Issue9918.hx"));
2020 offset: offset(1),
2121 wasAutoTriggered: true
2222 });
23 assertHasCompletion(parseCompletion(), item -> item.args.name == 'a');
23 final completion = parseCompletion();
24 assertHasCompletion(completion, item -> item.args.name == 'a');
25 Assert.equals("", completion.result.filterString);
26 }
27
28 /**
29 class Main {
30 static function main() {
31 var abc = 1;
32 var obj:{
33 foo:Int,
34 bar:Bool
35 } = {
36 foo:{-1-}a{-2-}b{-3-}
37 bar: true
38 }
39 }
40 }
41 **/
42 function test2(_) {
43 runHaxeJson([], DisplayMethods.Completion, {
44 file: file,
45 offset: offset(1),
46 wasAutoTriggered: true
47 });
48 final completion = parseCompletion();
49 assertHasCompletion(completion, item -> item.args.name == 'abc');
50 Assert.equals("ab", completion.result.filterString);
51
52 runHaxeJson([], DisplayMethods.Completion, {
53 file: file,
54 offset: offset(2),
55 wasAutoTriggered: true
56 });
57 final completion = parseCompletion();
58 assertHasCompletion(completion, item -> item.args.name == 'abc');
59 Assert.equals("a", completion.result.filterString);
60
61 runHaxeJson([], DisplayMethods.Completion, {
62 file: file,
63 offset: offset(3),
64 wasAutoTriggered: true
65 });
66 final completion = parseCompletion();
67 assertHasCompletion(completion, item -> item.args.name == 'abc');
68 Assert.equals("ab", completion.result.filterString);
69 }
70
71 /**
72 class Container {
73 public function new() {};
74 }
75 class Main {
76 static function main() {
77 final rockC = addContainer();
78 addSprite({
79 container: {-1-}
80 frame: ""
81 });
82 }
83 static function addContainer():Container return new Container();
84 static function addSprite(obj:{
85 container:Container,
86 frame:String
87 }):Void {}
88 }
89 **/
90 function test3(_) {
91 runHaxeJson([], DisplayMethods.Completion, {
92 file: file,
93 offset: offset(1),
94 wasAutoTriggered: true
95 });
96 final completion = parseCompletion();
97 assertHasCompletion(completion, item -> item.args.name == 'rockC');
98 Assert.equals("", completion.result.filterString);
99 }
100
101 /**
102 class Container {
103 public function new() {};
104 }
105 class Main {
106 static function main() {
107 final rockC = addContainer();
108 addSprite({
109 container: {-1-},
110 frame: ""
111 });
112 }
113 static function addContainer():Container return new Container();
114 static function addSprite(obj:{
115 container:Container,
116 frame:String
117 }):Void {}
118 }
119 **/
120 function test4(_) {
121 runHaxeJson([], DisplayMethods.Completion, {
122 file: file,
123 offset: offset(1),
124 wasAutoTriggered: true
125 });
126 final completion = parseCompletion();
127 assertHasCompletion(completion, item -> item.args.name == 'rockC');
128 Assert.equals("", completion.result.filterString);
129 }
130
131 /**
132 class Container {
133 public function new() {};
134 }
135 class Main {
136 static function main() {
137 final rockC = addContainer();
138 addSprite({
139 container: rockC,
140 container: {-1-}
141 frame: ""
142 });
143 }
144 static function addContainer():Container return new Container();
145 static function addSprite(obj:{
146 container:Container,
147 frame:String
148 }):Void {}
149 }
150 **/
151 function test5(_) {
152 runHaxeJson([], DisplayMethods.Completion, {
153 file: file,
154 offset: offset(1),
155 wasAutoTriggered: true
156 });
157 final completion = parseCompletion();
158 assertHasCompletion(completion, item -> item.args.name == 'rockC');
159 Assert.equals("", completion.result.filterString);
24160 }
25161 }
0 package cases.display.issues;
1
2 import haxe.display.JsonModuleTypes;
3 import haxe.Json;
4
5 class Issue10635 extends DisplayTestCase {
6 /**
7 class C {
8 public function new() {}
9 }
10
11 function main() {
12 Something.append([new C()], [new C()]);
13 }
14 **/
15 function test(_) {
16 var args = ["-main", "Main", "--display", "Main.hx@0@diagnostics"];
17 vfs.putContent("Something.hx", getTemplate("issues/Issue10635/Something.hx"));
18 runHaxe(args);
19 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
20 runHaxe(args);
21 Assert.isTrue(lastResult.stderr.length == 2); // dumb, but we don't have a proper diagnostics structure in these tests
22 }
23
24 /**
25 class C {
26 public function new() {}
27 }
28
29 function main() {
30 Something.append([new C()], [new C()]);
31 }
32 **/
33 function testGenericClassPerMethod(_) {
34 var args = ["-main", "Main", "--display", "Main.hx@0@diagnostics"];
35 vfs.putContent("Something.hx", "@:genericClassPerMethod " + getTemplate("issues/Issue10635/Something.hx"));
36 runHaxe(args);
37 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
38 runHaxe(args);
39 Assert.isTrue(lastResult.stderr.length == 2); // dumb, but we don't have a proper diagnostics structure in these tests
40 }
41
42 function testGenericAddition(_) {
43 var args = ["-main", "Main"];
44 vfs.putContent("GenericMethod.hx", getTemplate("GenericMethod.hx"));
45 vfs.putContent("Main.hx", getTemplate("issues/Issue10635/MainBefore.hx"));
46 runHaxe(args);
47 vfs.putContent("Main.hx", getTemplate("issues/Issue10635/MainAfter.hx"));
48 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
49 // Note: We only have to run this once to reproduce because ServerMethods.Type will call cl_restore anyway
50 runHaxe(args);
51 runHaxeJson(args, ServerMethods.Contexts, null);
52 var contexts:Array<HaxeServerContext> = Json.parse(lastResult.stderr).result.result;
53 utest.Assert.equals(1, contexts.length);
54 var sig = contexts[0].signature;
55 runHaxeJson(args, ServerMethods.Type, {signature: sig, modulePath: "GenericMethod", typeName: "GenericMethod"});
56 var type:JsonModuleType<JsonClass> = Json.parse(lastResult.stderr).result.result;
57 var statics = type.args.statics;
58 Assert.isTrue(statics.exists(cf -> cf.name == "f"));
59 Assert.isTrue(statics.exists(cf -> cf.name == "f_Class<Main>"));
60 }
61
62 function testGenericInstanceAddition(_) {
63 var args = ["-main", "Main"];
64 vfs.putContent("GenericInstanceMethod.hx", getTemplate("GenericInstanceMethod.hx"));
65 vfs.putContent("Main.hx", getTemplate("issues/Issue10635/MainInstanceBefore.hx"));
66 runHaxe(args);
67 vfs.putContent("Main.hx", getTemplate("issues/Issue10635/MainInstanceAfter.hx"));
68 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
69 // Note: We only have to run this once to reproduce because ServerMethods.Type will call cl_restore anyway
70 runHaxe(args);
71 var contexts = null;
72 runHaxeJsonCb(args, ServerMethods.Contexts, null, r -> contexts = r);
73 Assert.notNull(contexts);
74 utest.Assert.equals(1, contexts.length);
75 var sig = contexts[0].signature;
76 var type:JsonModuleType<JsonClass> = null;
77 runHaxeJsonCb(args, ServerMethods.Type, {signature: sig, modulePath: "GenericInstanceMethod", typeName: "GenericInstanceMethod"}, r -> type = r);
78 var fields = type.args.fields;
79 Assert.isTrue(fields.exists(cf -> cf.name == "f"));
80 Assert.isTrue(fields.exists(cf -> cf.name == "f_Class<Main>"));
81 }
82 }
0 package cases.display.issues;
1
2 class Issue10638 extends DisplayTestCase {
3 /**
4 var x = {-1-}"f{-2-}oo"{-3-};
5
6 class Main {
7 static function main() {}
8 }
9 **/
10 function test(_) {
11 runHaxe(["--main", "Main"]);
12 runHaxeJson([], DisplayMethods.Hover, {
13 file: file,
14 offset: offset(2)
15 });
16 var result = parseHover();
17 Assert.same(range(1, 3), result.result.range);
18 }
19
20 }
0 package cases.display.issues;
1
2 import haxe.Json;
3
4 class Issue10678 extends DisplayTestCase {
5 function test(_) {
6 vfs.putContent("Macro.hx", getTemplate("issues/Issue10678/Macro.hx"));
7 vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
8 var args = ["--main HelloWorld", "--js", "js.js", "--macro", "Macro.init()"];
9 // This is very facepalm
10 runHaxeJson(args, DisplayMethods.FindReferences, {file: new FsPath("HelloWorld.hx"), offset: 0});
11 var results:Array<String> = Json.parse(lastResult.stderr).result.result;
12 for (i => result in results) {
13 Assert.notContains(result, results.slice(i + 1));
14 }
15 }
16 }
0 package cases.display.issues;
1
2 class Issue10781 extends DisplayTestCase {
3 /**
4 interface Canvas {
5 var g2(get, null):Graphics;
6 }
7
8 class Graphics {
9 public function begin() {}
10 }
11
12 class Main {
13 static function main() {
14 onRender(null);
15 }
16
17 static function onRender(canvas:Canvas) {
18 final {-1-}g = canvas.g2;
19 g.begin();
20 }
21 }
22 **/
23 function test(_) {
24 runHaxeJson([], DisplayMethods.Hover, {
25 file: file,
26 offset: offset(1)
27 });
28 runHaxeJson([], ServerMethods.Invalidate, {file: file});
29 runHaxeJson([], DisplayMethods.Hover, {
30 file: file,
31 offset: offset(1)
32 });
33 var result = parseHover();
34 Assert.same({
35 kind: "TInst",
36 args: {
37 path: {
38 moduleName: "Main",
39 importStatus: 0,
40 pack: [],
41 typeName: "Graphics"
42 },
43 params: []
44 }
45 }, result.result.item.type);
46 }
47 }
0 package cases.display.issues;
1
2 class Issue9140 extends DisplayTestCase {
3 /**
4 class Main {
5 static function main() {
6 var c = new C();
7 var f {-1-}= c.field{-2-};
8 {-3-} c.field{-4-} = f;
9 }
10 }
11
12 class C implements I {
13 public var field(g{-5-}et,s{-6-}et):Int;
14 public function new() {}
15
16 function get{-7-}_field() return 10;
17 function set_f{-8-}ield(value:Int) return value;
18 }
19
20 interface I {
21 var field(get,set):Int;
22 }
23 **/
24 function test(_) {
25 // TODO: The starting positions are off by 4. This comes from patch_string_pos in
26 // statistics.ml subtracting the length of get_/set_, while the syntax has the plain
27 // field. This is not a new issue though.
28 runHaxeJson([], DisplayMethods.FindReferences, {
29 file: file,
30 kind: WithBaseAndDescendants,
31 offset: offset(5)
32 });
33 var result = parseGotoDefinitionLocations();
34 Assert.same([range(1, 2)], result.map(l -> l.range));
35
36 runHaxeJson([], DisplayMethods.FindReferences, {
37 file: file,
38 kind: WithBaseAndDescendants,
39 offset: offset(7)
40 });
41 var result = parseGotoDefinitionLocations();
42 Assert.same([range(1, 2)], result.map(l -> l.range));
43
44 runHaxeJson([], DisplayMethods.FindReferences, {
45 file: file,
46 kind: WithBaseAndDescendants,
47 offset: offset(6)
48 });
49 var result = parseGotoDefinitionLocations();
50 Assert.same([range(3, 4)], result.map(l -> l.range));
51
52 runHaxeJson([], DisplayMethods.FindReferences, {
53 file: file,
54 kind: WithBaseAndDescendants,
55 offset: offset(8)
56 });
57 var result = parseGotoDefinitionLocations();
58 Assert.same([range(3, 4)], result.map(l -> l.range));
59 }
60 }
0 package cases.display.issues;
1
2 class Issue9318 extends DisplayTestCase {
3 /**
4 typedef T = {
5 var {-1-}field{-2-}:Int;
6 }
7
8 @:structInit
9 class C {
10 public function new({-3-}field{-4-}:Int) {}
11 }
12
13 @:structInit
14 class D {
15 var {-5-}field{-6-}:Int;
16 }
17
18 class Main {
19 static function main() {
20 var t:T = {fie{-7-}ld: 1}; // clicking on `field` takes to the field position: ideal
21 var c:C = {fie{-8-}ld: 1}; // clicking on `field` takes to the contstructor position: not bad, but ideally should take to the argument position (not sure if possible)
22 var d:D = {fiel{-9-}d: 1}; // clicking on `field` doesn't work :()
23 }
24 }
25 **/
26 function test(_) {
27 var args = ["Main", "-js", "main.js"];
28 function parseGotoDefintion():GotoDefinitionResult {
29 return haxe.Json.parse(lastResult.stderr).result.result.map(result -> result.range);
30 }
31 runHaxeJson(args, DisplayMethods.GotoDefinition, {file: file, offset: offset(7), contents: source});
32 Assert.same([range(1, 2)], parseGotoDefintion());
33 // runHaxeJson(args, DisplayMethods.GotoDefinition, {file: file, offset: offset(8), contents: source});
34 // Assert.same([range(3, 4)], parseGotoDefintion());
35 runHaxeJson(args, DisplayMethods.GotoDefinition, {file: file, offset: offset(9), contents: source});
36 Assert.same([range(5, 6)], parseGotoDefintion());
37 }
38 }
00 package cases.display.issues;
11
22 import haxe.display.Protocol;
3 using Lambda;
34
45 class Issue9423 extends DisplayTestCase {
56 /**
1213 function test(_) {
1314 vfs.putContent("Mod9423.hx", getTemplate("issues/Issue9423/Mod9423.hx"));
1415 vfs.putContent("Mod9423.whatever.hx", getTemplate("issues/Issue9423/Mod9423.whatever.hx"));
15 runHaxeJson([], DisplayMethods.Completion, {
16 runHaxeJson(["-cp", "."], DisplayMethods.Completion, {
1617 file: file,
1718 offset: offset(1),
1819 wasAutoTriggered: false
1920 });
2021 var result = parseCompletion().result;
21 // TODO: this test does not pass, but the same setup works fine in vscode
22 // TODO: Another test which does not work here, but works in vshaxe: #9423.
23 // Assert.equals(1, result.items.length);
24 Assert.pass();
22 final l = result.items.filter(di -> switch [di.kind, di.args] {
23 case [Type, args]: args.path.typeName == "Mod9423";
24 case _: false;
25 });
26 Assert.equals(1, l.length);
2527 }
2628 }
0 package cases.issues;
1
2 class Issue10646 extends TestCase {
3 function test(_) {
4 vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx"));
5 var args = ["-main", "HelloWorld", "--neko", "test.n"];
6 runHaxe(args);
7 var nekoCtx = null;
8 runHaxeJsonCb([], ServerMethods.Contexts, null, function(ctxs) {
9 for (ctx in ctxs) {
10 if (ctx.desc == "after_init_macros") {
11 nekoCtx = ctx;
12 }
13 }
14 });
15 Assert.notNull(nekoCtx);
16 runHaxeJsonCb([], ServerMethods.ContextMemory, {signature: nekoCtx.signature}, function(mem) {
17 Assert.isNull(mem.leaks);
18 });
19 }
20 }
0 package cases.issues;
1
2 class Issue10653 extends TestCase {
3 function test(_) {
4 vfs.putContent("Test.hx", getTemplate("issues/Issue10653/Test.hx"));
5 vfs.putContent("Main.hx", getTemplate("issues/Issue10653/MainBefore.hx"));
6 var args = ["-main", "Main", "--js", "no.js", "--no-output"];
7 runHaxe(args);
8 vfs.putContent("Main.hx", getTemplate("issues/Issue10653/MainAfter.hx"));
9 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
10 runHaxe(args.concat(["--display", "Main.hx@0@diagnostics"]));
11 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
12 runHaxe(args.concat(["--display", "Main.hx@0@diagnostics"]));
13 Assert.isTrue(lastResult.stderr.length == 2);
14 }
15 }
0 package cases.issues;
1
2 class Issue10677 extends TestCase {
3 function test(_) {
4 vfs.putContent("Main.hx", getTemplate("issues/Issue10677/Main.hx"));
5 vfs.putContent("Polygon.hx", getTemplate("issues/Issue10677/Polygon.hx"));
6 vfs.putContent("Polygons.hx", getTemplate("issues/Issue10677/Polygons.hx"));
7 vfs.putContent("PolygonCollider.hx", getTemplate("issues/Issue10677/PolygonCollider.hx"));
8 var args = ["--main", "Main.hx", "--no-output"];
9 runHaxe(args);
10 runHaxeJson(args, ServerMethods.Invalidate, {file: new FsPath("Main.hx")});
11 runHaxe(args);
12 Assert.isFalse(lastResult.hasError);
13 }
14 }
1818 runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("res/dep.dep")});
1919 runHaxeJson(args, DisplayMethods.Hover, {file: new FsPath("WithDependency.hx"), offset: 65});
2020 // check messages manually because module file contains awkward absolute path
21 var r = ~/skipping Dependency\(.*dep.dep\)/;
22 Assert.isTrue(messages.exists(message -> r.match(message)));
21 // var r = ~/skipping Dependency \(.*dep.dep\)/;
22 // Assert.isTrue(messages.exists(message -> r.match(message)));
2323 }
24 }
24 }
0 package cases.issues;
1
2 class Issue9636 extends TestCase {
3 function test(_) {
4 vfs.putContent('Main.hx', getTemplate('issues/Issue9636/Main.hx'));
5 var args = ['--main', 'Main', '--macro', 'include("pack")', '--js', 'test.js'];
6 runHaxe(args);
7 assertSuccess();
8 vfs.putContent('pack/Foo.hx', getTemplate('issues/Issue9636/Foo.hx'));
9 runHaxe(args);
10 assertSuccess();
11 runHaxe(['--cmd', 'node test.js']);
12 Assert.isTrue(lastResult.stderr.contains('Exception from Foo'));
13 }
14 }
1111 continue;
1212 }
1313 switch (field.kind) {
14 case FFun(f) if (field.meta.exists(m -> m.name == ":async")):
15 // Async is already manually handled, nothing to do
16
1417 case FFun(f):
1518 var asyncName = switch f.args {
1619 case []:
2124 });
2225 name;
2326 case [arg]:
24 if(arg.name == "_") {
27 if (arg.name == "_") {
2528 arg.name = "async";
2629 arg.type = macro:utest.Async;
2730 }
6265 var e = transformHaxeCalls(asyncName, el);
6366 args.push(macro() -> ${failOnException(asyncName, e)});
6467 macro runHaxeJson($a{args});
68 case macro runHaxeJsonCb($a{args}):
69 var e = transformHaxeCalls(asyncName, el);
70 args.push(macro() -> ${failOnException(asyncName, e)});
71 macro runHaxeJsonCb($a{args});
6572 case macro complete($a{args}):
6673 var e = transformHaxeCalls(asyncName, el);
6774 args.push(macro function(response, markers) ${failOnException(asyncName, e)});
7582 }
7683
7784 static function failOnException(asyncName:String, e:Expr):Expr {
78 return macro @:pos(e.pos) try {
79 $e;
80 } catch(e) {
81 Assert.fail(e.details());
82 $i{asyncName}.done();
83 return;
84 }
85 return macro
86 @:pos(e.pos) try {
87 $e;
88 } catch (e) {
89 Assert.fail(e.details());
90 $i{asyncName}.done();
91 return;
92 }
8593 }
8694 }
11 static public function get() {
22 return "Hello World";
33 }
4
5 public function new() {}
46 }
0 class GenericInstanceMethod {
1 public function new() {}
2
3 @:generic public function f<T>(t:T) {}
4 }
0 class GenericMethod {
1 @:generic static public function f<T>(t:T) {}
2 }
0 class Main {
1 static function main() {
2 GenericMethod;
3 GenericMethod.f(Main);
4 }
5 }
0 class Main {
1 static function main() {
2 GenericMethod;
3 }
4 }
0 class Main {
1 static function main() {
2 var c = new GenericInstanceMethod();
3 c.f(Main);
4 }
5 }
0 class Main {
1 static function main() {
2 var c = new GenericInstanceMethod();
3 }
4 }
0 class Something {
1 @:generic
2 static public function append<T>(a:Array<T>, b:Array<T>) {
3 for (e in b) {
4 a.push(e);
5 }
6 return a;
7 }
8 }
0 class Main {
1 static function main() {
2 var x = Test.test();
3 x = new Main();
4 }
5
6 function new() {}
7 }
0 class Main {
1 static function main() {
2 var x = Test.test();
3 }
4
5 function new() {}
6 }
0 class Test {
1 static public function test() {
2 return null;
3 }
4 }
0 class Main {
1 static function main() {
2 trace(Polygons);
3 Polygon.x = Main;
4 }
5 }
0 class Polygon {
1 static public var x:Class<Main>;
2 }
0 class PolygonCollider {
1 static public var p:Polygons;
2 }
0 class Polygons {
1 static public var c:PolygonCollider;
2 static public var p:Polygon;
3 }
0 import haxe.macro.Context;
1
2 var lookups = [];
3
4 function init() {
5 Context.onTypeNotFound(path -> {
6 lookups.push(path);
7 return null;
8 });
9 Context.onAfterTyping(_ -> {
10 var json = haxe.Json.stringify(lookups);
11 @:privateAccess Context.load("send_json", 1)(json);
12 });
13 }
0 import haxe.ds.Vector;
1
2 class Main {
3 static public function main() {
4 final v = new Vector(2, 5);
5 }
6 }
0 package haxe.ds;
1
2 private typedef VectorData<T> = java.NativeArray<T>
3
4 abstract Vector<T>(VectorData<T>) {
5 public var length(get, never):Int;
6
7 inline function get_length():Int {
8 return this.length;
9 }
10
11 extern overload public inline function new(length:Int) {
12 this = new java.NativeArray(length);
13 }
14
15 extern overload public inline function new(length:Int, defaultValue:T) {
16 this = new java.NativeArray(length);
17 // uncomment and rebuild to break compilation server
18 // server restart will fix errors until the next change in this file
19
20 // trace("uncomment me");
21 }
22
23 @:op([]) public inline function get(index:Int):T {
24 return this[index];
25 }
26
27 @:op([]) public inline function set(index:Int, val:T):T {
28 return this[index] = val;
29 }
30
31 public static function blit<T>(src:Vector<T>, srcPos:Int, dest:Vector<T>, destPos:Int, len:Int):Void {}
32
33 static public function fromData<T>(data:VectorData<T>):Vector<T>
34 return cast data;
35
36 public function copy<T>():Vector<T> {
37 return cast this;
38 }
39
40 public function toData():VectorData<T>
41 return cast this;
42 }
0 --main Main
1 --jvm Main.jar
2 # --cmd java -jar bin/Main.jar
0 class Main {
1 public static function main() {
2 buildSimplest();
3 }
4
5 macro static function buildSimplest() {
6 var cb = new MyMacro(null);
7 cb.build();
8 return macro {}
9 }
10 }
0 class MyMacro {
1 var data:FunctionData;
2
3 public function new(data:FunctionData) {
4 this.data = data;
5 }
6
7 public function build():Void {
8 {-1-}data.args.{-2-}
9 }
10
11 }
12
13 @:structInit class FunctionData {
14 public final args:Array<String>;
15 }
0 package pack;
1
2 class Foo {
3 static function __init__() throw "Exception from Foo";
4 public static function bar() {}
5 }
0
1 class Main {
2 static public function main() {
3 trace("hello world");
4 }
5 }
0 abstract AbstractWithDependency(String) {
1 public static function notMain() {
2 trace(Dependency.get());
3 }
4 }
0 abstract AbstractWithSignatureDependency(String) {
1 public static function test(d:Dependency) {}
2 }
0 enum DependentEnum {
1 Constructor(s:Dependency);
2 }
0 typedef DependentTypedef = Dependency;
0 enum IndependentEnum {
1 Constructor(s:String);
2 }
3
4 class MakeDependency {
5 static function f() {
6 Dependency.get();
7 }
8 }
0 typedef IndependentTypedef = String;
1
2 class MakeDependency {
3 static function f() {
4 Dependency.get();
5 }
6 }
0 class MutualDependency {
1 static public function get() {
2 return WithMutualDependency.value;
3 }
4 }
0 class WithInterfaceDependency implements InterfaceDependency {}
0 class WithMutualDependency {
1 static public var value = "Hello World";
2
3 public static function main() {
4 trace(MutualDependency.get());
5 }
6 }
0 class WithParentDependency extends Dependency {}
0 class WithSignatureDependency {
1 public static function test(d:Dependency) {}
2 }
0 class WithSignatureDependency {
1 public static function test(d) {
2 d = new Dependency();
3 }
4 }
0 class WithSignatureDependency {
1 public static var test(default, null) = new Dependency();
2 }
0 class WithSignatureDependency {
1 public static function test() {
2 return new Dependency();
3 }
4 }
0 class WithSignatureDependency {
1 public static var test = new Dependency();
2 }
0 class WithSignatureDependency {
1 public static var test(default, null):Dependency;
2 }
0 class WithSignatureDependency {
1 public static var test:Dependency;
2 }
0 compile-each.hxml
1 --main Main
2 -js bin/js/sys.js
3 -lib hxnodejs
4
5 --next
6 compile-each.hxml
7 --main TestArguments
8 -js bin/js/TestArguments.js
9 -lib hxnodejs
10
11 --next
12 compile-each.hxml
13 --main ExitCode
14 -js bin/js/ExitCode.js
15 -lib hxnodejs
16
17 --next
18 compile-each.hxml
19 --main UtilityProcess
20 -js bin/js/UtilityProcess.js
21 -lib hxnodejs
77 --next compile-java.hxml
88 --next compile-php.hxml
99 --next compile-hl.hxml
10 --next compile-js.hxml
11 --next compile-lua.hxml
+0
-98
tests/sys/genTestRes.py less more
0 #!/usr/bin/env python3
1
2 # Generates files and directories in test-res used for Unicode sys tests.
3 # The test vector printf'ed into data.bin, as well as the names in filenames()
4 # should correspond exactly to the sequences in UnicodeSequences.valid.
5
6 # Run with:
7 # python3 genTestRes.py
8 # Or:
9 # python3 genTestRes.py TEST_INVALID_UNICODE_FS
10 # The latter will attempt to create filenames which contain invalid Unicode
11 # codepoints; this does not work on some filesystems, e.g. APFS.
12
13 import os
14 import shutil
15 import sys
16
17 MODE = " ".join(sys.argv[1:])
18
19 TESTDIR = "test-res"
20
21 # delete previous, if any
22 if os.path.isdir(TESTDIR):
23 shutil.rmtree(TESTDIR)
24
25 os.mkdir(TESTDIR)
26
27 # Unicode test vectors
28 allUnicode = [
29 [0x01], # will not work on NTFS
30 [0x7F],
31 [0xC2, 0x80],
32 [0xDF, 0xBF],
33 [0xE0, 0xA0, 0x80],
34 [0xED, 0x9F, 0xBF], # will not work on APFS
35 [0xEE, 0x80, 0x80],
36 [0xEF, 0xBF, 0xBD],
37 [0xF0, 0x90, 0x80, 0x80],
38 [0xF0, 0x9F, 0xBF, 0xBF], # will not work on APFS
39 [0xF3, 0xBF, 0xBF, 0xBF], # will not work on APFS
40 [0xF4, 0x80, 0x80, 0x80],
41 [0xF4, 0x8F, 0xBF, 0xBF], # will not work on APFS
42 [0xF0, 0x9F, 0x98, 0x82, 0xF0, 0x9F, 0x98, 0x84, 0xF0, 0x9F, 0x98, 0x99],
43 [0xC8, 0xA7],
44 [0xE4, 0xB8, 0xAD, 0xE6, 0x96, 0x87, 0xEF, 0xBC, 0x8C, 0xE3, 0x81, 0xAB, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0x94]
45 ]
46
47 allStrings = [ bytes(data).decode("utf-8") for data in allUnicode ]
48
49 allFilenames = allStrings[:]
50 # Windows does not allow codepoints in the U+0000 - U+001F range
51 # see https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file
52 if os.name == "nt":
53 allFilenames.remove(bytes([0x01]).decode("utf-8"))
54
55 # on APFS (macOS 10.13+), filenames must consist of valid Unicode codepoints
56 if MODE != "TEST_INVALID_UNICODE_FS":
57 allFilenames.remove(bytes([0xED, 0x9F, 0xBF]).decode("utf-8"))
58 allFilenames.remove(bytes([0xF0, 0x9F, 0xBF, 0xBF]).decode("utf-8"))
59 allFilenames.remove(bytes([0xF3, 0xBF, 0xBF, 0xBF]).decode("utf-8"))
60 allFilenames.remove(bytes([0xF4, 0x8F, 0xBF, 0xBF]).decode("utf-8"))
61
62 allBinary = b""
63 for data in allUnicode:
64 allBinary += bytes(data) + b"\n"
65
66 # generate a file with Unicode data
67 with open(os.path.join(TESTDIR, "data.bin"), "wb") as f:
68 f.write(allBinary)
69
70 # generate sub-directories with symlinks
71 os.mkdir(os.path.join(TESTDIR, "a"))
72 for data in allFilenames:
73 os.mkdir(os.path.join(TESTDIR, data))
74 os.mkdir(os.path.join(TESTDIR, "a", data))
75 if os.name != "nt":
76 for target, name in [
77 ("../../bin/cpp/UtilityProcess-debug", "bin-cpp-debug"),
78 ("../../bin/cpp/UtilityProcess", "bin-cpp"),
79 ("../../bin/cs/bin/UtilityProcess-Debug.exe", "bin-cs-debug"),
80 ("../../bin/cs/bin/UtilityProcess.exe", "bin-cs"),
81 ("../../bin/hl/UtilityProcess.hl", "bin-hl"),
82 ("../../bin/lua/UtilityProcess.lua", "bin-lua"),
83 ("../../bin/java/UtilityProcess-Debug.jar", "bin-java-debug"),
84 ("../../bin/java/UtilityProcess.jar", "bin-java"),
85 ("../../bin/jvm/UtilityProcess.jar", "bin-jvm"),
86 ("../../bin/neko/UtilityProcess.n", "bin-neko"),
87 ("../../bin/php/UtilityProcess/index.php", "bin-php"),
88 ("../../bin/python/UtilityProcess.py", "bin-py"),
89 ("../../src/UtilityProcess.hx", "bin-eval")
90 ]:
91 os.symlink(target, os.path.join(TESTDIR, data, name), target_is_directory = False)
92
93 # files
94 os.mkdir(os.path.join(TESTDIR, "b"))
95 for data in allFilenames:
96 with open(os.path.join(TESTDIR, "b", data), "wb") as f:
97 f.write(allBinary)
0 #!/usr/bin/env python3
1
2 # Generates files and directories in test-res used for Unicode sys tests.
3 # The test vector printf'ed into data.bin, as well as the names in filenames()
4 # should correspond exactly to the sequences in UnicodeSequences.valid.
5
6 # Run with:
7 # python3 gen_test_res.py
8 # Or:
9 # python3 gen_test_res.py TEST_INVALID_UNICODE_FS
10 # The latter will attempt to create filenames which contain invalid Unicode
11 # codepoints; this does not work on some filesystems, e.g. APFS.
12
13 import os
14 import shutil
15 import sys
16
17 MODE = " ".join(sys.argv[1:])
18
19 TESTDIR = "test-res"
20
21 # delete previous, if any
22 if os.path.isdir(TESTDIR):
23 shutil.rmtree(TESTDIR)
24
25 os.mkdir(TESTDIR)
26
27 # Unicode test vectors
28 all_unicode = [
29 [0x01], # will not work on NTFS
30 [0x7F],
31 [0xC2, 0x80],
32 [0xDF, 0xBF],
33 [0xE0, 0xA0, 0x80],
34 [0xED, 0x9F, 0xBF], # will not work on APFS
35 [0xEE, 0x80, 0x80],
36 [0xEF, 0xBF, 0xBD],
37 [0xF0, 0x90, 0x80, 0x80],
38 [0xF0, 0x9F, 0xBF, 0xBF], # will not work on APFS
39 [0xF3, 0xBF, 0xBF, 0xBF], # will not work on APFS
40 [0xF4, 0x80, 0x80, 0x80],
41 [0xF4, 0x8F, 0xBF, 0xBF], # will not work on APFS
42 [0xF0, 0x9F, 0x98, 0x82, 0xF0, 0x9F, 0x98, 0x84, 0xF0, 0x9F, 0x98, 0x99],
43 [0xC8, 0xA7],
44 [0xE4, 0xB8, 0xAD, 0xE6, 0x96, 0x87, 0xEF, 0xBC, 0x8C, 0xE3, 0x81, 0xAB,
45 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0x94]
46 ]
47
48 all_strings = [bytes(data).decode("utf-8") for data in all_unicode]
49
50 all_filenames = all_strings[:]
51 # Windows does not allow codepoints in the U+0000 - U+001F range
52 # see https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file
53 if os.name == "nt":
54 all_filenames.remove(bytes([0x01]).decode("utf-8"))
55
56 # on APFS (macOS 10.13+), filenames must consist of valid Unicode codepoints
57 if MODE != "TEST_INVALID_UNICODE_FS":
58 all_filenames.remove(bytes([0xED, 0x9F, 0xBF]).decode("utf-8"))
59 all_filenames.remove(bytes([0xF0, 0x9F, 0xBF, 0xBF]).decode("utf-8"))
60 all_filenames.remove(bytes([0xF3, 0xBF, 0xBF, 0xBF]).decode("utf-8"))
61 all_filenames.remove(bytes([0xF4, 0x8F, 0xBF, 0xBF]).decode("utf-8"))
62
63 all_binary = b""
64 for data in all_unicode:
65 all_binary += bytes(data) + b"\n"
66
67 # generate a file with Unicode data
68 with open(os.path.join(TESTDIR, "data.bin"), "wb") as f:
69 f.write(all_binary)
70
71 # generate sub-directories with symlinks
72 os.mkdir(os.path.join(TESTDIR, "a"))
73 for data in all_filenames:
74 os.mkdir(os.path.join(TESTDIR, data))
75 os.mkdir(os.path.join(TESTDIR, "a", data))
76 if os.name == "nt":
77 continue
78 for target, name in [
79 ("../../bin/cpp/UtilityProcess-debug", "bin-cpp-debug"),
80 ("../../bin/cpp/UtilityProcess", "bin-cpp"),
81 ("../../bin/cs/bin/UtilityProcess-Debug.exe", "bin-cs-debug"),
82 ("../../bin/cs/bin/UtilityProcess.exe", "bin-cs"),
83 ("../../bin/hl/UtilityProcess.hl", "bin-hl"),
84 ("../../bin/lua/UtilityProcess.lua", "bin-lua"),
85 ("../../bin/java/UtilityProcess-Debug.jar", "bin-java-debug"),
86 ("../../bin/java/UtilityProcess.jar", "bin-java"),
87 ("../../bin/jvm/UtilityProcess.jar", "bin-jvm"),
88 ("../../bin/neko/UtilityProcess.n", "bin-neko"),
89 ("../../bin/php/UtilityProcess/index.php", "bin-php"),
90 ("../../bin/python/UtilityProcess.py", "bin-py"),
91 ("../../src/UtilityProcess.hx", "bin-eval"),
92 ("../../bin/js/UtilityProcess.js", "bin-js")
93 ]:
94 os.symlink(target, os.path.join(TESTDIR, data, name), target_is_directory=False)
95
96 # files
97 os.mkdir(os.path.join(TESTDIR, "b"))
98 for data in all_filenames:
99 with open(os.path.join(TESTDIR, "b", data), "wb") as f:
100 f.write(all_binary)
22 # Compile everything first.
33 compile.hxml
44
5 # Install Dependencies
6 # --next
7 # --cmd luarocks install haxe-deps 0.0.1-6
8 # --cmd npm install deasync
9
510 # Mac/Linux
611 --next
7 -cmd echo Neko && neko bin/neko/sys.n
8 -cmd echo Python && python3 bin/python/sys.py
9 -cmd echo Cpp && bin/cpp/Main-debug
10 -cmd echo CS && mono bin/cs/bin/Main-Debug.exe
11 -cmd echo Java && java -jar bin/java/Main-Debug.jar
12 -cmd echo Php && php bin/php/Main/index.php
12 --cmd echo Neko && export EXISTS=1 && neko bin/neko/sys.n
13 --cmd echo Python && export EXISTS=1 && python3 bin/python/sys.py
14 --cmd echo Cpp && export EXISTS=1 && bin/cpp/Main-debug
15 --cmd echo CS && export EXISTS=1 && mono bin/cs/bin/Main-Debug.exe
16 --cmd echo Java && export EXISTS=1 && java -jar bin/java/Main-Debug.jar
17 --cmd echo Php && export EXISTS=1 && php bin/php/Main/index.php
18 --cmd echo Hl && export EXISTS=1 && hl bin/hl/sys.hl
19 --cmd echo Js && export EXISTS=1 && node bin/js/sys.js
20 --cmd echo Lua && export EXISTS=1 && lua bin/sys.lua
21 --cmd echo Macro && export EXISTS=1 && haxe compile-macro.hxml
1322
1423 # Windows
1524 # --next
16 # -cmd echo Neko && neko bin\neko\sys.n
17 # -cmd echo Python && python3 bin\python\sys.py
18 # -cmd echo Cpp && bin\cpp\Main-debug.exe
19 # -cmd echo CS && bin\cs\bin\Main-Debug.exe
20 # -cmd echo Java && java -jar bin\java\Main-Debug.jar
21 # -cmd echo Php && php bin\php\Main\index.php
22
23 # Macro has to be placed at the end since it would exit the compilation process.
24 --next
25 -cmd echo Macro
26 --next
27 compile-macro.hxml
25 # --cmd echo Neko && set EXISTS=1 && neko bin\neko\sys.n
26 # --cmd echo Python && set EXISTS=1 && python3 bin\python\sys.py
27 # --cmd echo Cpp && set EXISTS=1 && bin\cpp\Main-debug.exe
28 # --cmd echo CS && set EXISTS=1 && bin\cs\bin\Main-Debug.exe
29 # --cmd echo Java && set EXISTS=1 && java -jar bin\java\Main-Debug.jar
30 # --cmd echo Php && set EXISTS=1 && php -c ..\PHP.ini bin\php\Main\index.php
31 # --cmd echo Hl && set EXISTS=1 && hl bin/hl/sys.hl
32 # --cmd echo Js && set EXISTS=1 && node bin/js/sys.js
33 # --cmd echo Lua && set EXISTS=1 && lua bin/lua/sys.lua
34 # --cmd echo Macro && set EXISTS=1 && haxe compile-macro.hxml
3838 "bin/php/ExitCode/index.php";
3939 #elseif lua
4040 "bin/lua/ExitCode.lua";
41 #elseif js
42 "bin/js/ExitCode.js";
4143 #else
4244 null;
4345 #end
99 runner.addCase(new TestFileSystem());
1010 runner.addCase(new io.TestFile());
1111 runner.addCase(new io.TestFileInput());
12 #if !js
1213 runner.addCase(new io.TestProcess());
13 #if !(java || cs || lua || python || eval) // Sqlite is not implemented for these targets
14 #if !hl // Idk how to resolve "FATAL ERROR : Failed to load library sqlite.hdll"
15 var testSqlite = #if php Sys.systemName() != 'Windows' #else true #end; //our CI doesn't have sqlite php module
16 if(testSqlite) {
17 runner.addCase(new db.TestSqliteConnection());
18 runner.addCase(new db.TestSqliteResultSet());
19 }
2014 #end
15 #if !(java || cs || lua || python || eval || js) // Sqlite is not implemented for these targets
16 runner.addCase(new db.TestSqliteConnection());
17 runner.addCase(new db.TestSqliteResultSet());
2118 #end
22 #if php
23 switch (Sys.systemName()) {
24 case "Windows":
25 // pass
26 case _:
27 runner.addCase(new net.TestSocket());
28 }
29 #else
30 runner.addCase(new net.TestSocket());
31 #end
19 runner.addCase(new net.TestSocket());
3220 var report = Report.create(runner);
3321 report.displayHeader = AlwaysShowHeader;
3422 report.displaySuccessResults = NeverShowSuccessResults;
9898 "bin/php/TestArguments/index.php";
9999 #elseif lua
100100 "bin/lua/TestArguments.lua";
101 #elseif js
102 "bin/js/TestArguments.js";
101103 #else
102104 null;
103105 #end
4141 run(php.Global.defined('PHP_BINARY') ? php.Const.PHP_BINARY : 'php', [bin].concat(args));
4242 #elseif lua
4343 run("lua", [bin].concat(args));
44 #elseif js
45 run("node", [bin].concat(args));
4446 #else
4547 -1;
4648 #end
132134 run(php.Global.defined('PHP_BINARY') ? php.Const.PHP_BINARY : 'php', [bin].concat(args));
133135 #elseif lua
134136 run("lua", [bin].concat(args));
137 #elseif js
138 run("node", [bin].concat(args));
135139 #else
136140 -1;
137141 #end
140140 }
141141
142142 static function normPath(p:String, properCase = false):String {
143 if (Sys.systemName() == "Windows")
144 {
143 if (Sys.systemName() == "Windows") {
145144 // on windows, haxe returns lowercase paths with backslashes, drive letter uppercased
146145 p = p.substr(0, 1).toUpperCase() + p.substr(1);
147146 p = p.replace("/", "\\");
148147 }
149148 return p;
150149 }
151 }
150 }
44 return Sys.command(cmd, args);
55 }
66
7 function testEnv() {
8 #if !(java)
9 Sys.putEnv("foo", "value");
10 Assert.equals("value", Sys.getEnv("foo"));
7 function testEnvironment() {
8 var env = Sys.environment();
9 // EXISTS should be set manually via the command line
10 Assert.notNull(env.get("EXISTS"));
11 Assert.isNull(env.get("doesn't exist"));
12
13 final nonExistent = "NON_EXISTENT";
14 env.set(nonExistent, "1");
15 // new copies should not be affected
16 Assert.isNull(Sys.environment()[nonExistent]);
17
18 #if !java
19 // env should not update when environment updates
20 final toUpdate = "TO_UPDATE";
21
22 Sys.putEnv(toUpdate, "1");
23 Assert.isNull(env.get(toUpdate));
24
25 // new copy should have the variable
26 Assert.equals("1", Sys.environment()[toUpdate]);
27
28 // environment should not update if env updates
29 env.set(toUpdate, "2");
30 Assert.equals("1", Sys.getEnv(toUpdate));
31
32 // variables set via target specific api should exist
33 #if (cs || python)
34 final toSetNatively = "SET_NATIVELY";
35 #if cs
36 cs.system.Environment.SetEnvironmentVariable(toSetNatively, "1");
37 #elseif python
38 python.lib.Os.environ.set(toSetNatively, "1");
1139 #end
12 Assert.equals(null, Sys.getEnv("doesn't exist"));
13
14 #if !(java)
15 var env = Sys.environment();
16 Assert.equals("value", env.get("foo"));
40 Assert.equals("1", Sys.environment()[toSetNatively]);
41 #end
1742 #end
1843 }
44
45 function existsInSubProcess(variable:String, value:String) {
46 #if js
47 return UtilityProcess.runUtilityAsCommand(["checkEnv", variable, value]) == 0;
48 #else
49 return UtilityProcess.runUtility(["checkEnv", variable, value]).exitCode == 0;
50 #end
51 }
52
53 function testGetEnv() {
54 // EXISTS should be set manually via the command line
55 Assert.notNull(Sys.getEnv("EXISTS"));
56
57 // on windows, Sys.getEnv should be case insensitive
58 if (Sys.systemName() == "Windows")
59 Assert.notNull(Sys.getEnv("exists"));
60
61 Assert.isNull(Sys.getEnv("doesn't exist"));
62 }
63
64 #if !java
65 function testPutEnv() {
66 Sys.putEnv("FOO", "value");
67 Assert.equals("value", Sys.getEnv("FOO"));
68
69 Assert.equals("value", Sys.environment().get("FOO"));
70
71 Assert.isTrue(existsInSubProcess("FOO", "value"));
72
73 #if python
74 // the variable should also be visible through python's api
75 Assert.equals("value", python.lib.Os.environ.get("FOO"));
76 #end
77
78 // null
79 Sys.putEnv("FOO", null);
80 Assert.isNull(Sys.getEnv("FOO"));
81
82 Assert.isFalse(Sys.environment().exists("FOO"));
83
84 Assert.isFalse(existsInSubProcess("FOO", "value"));
85
86 #if python
87 // the variable should also be gone when checking through python's api
88 Assert.isFalse(python.lib.Os.environ.hasKey("FOO"));
89 #end
90
91 Assert.isTrue(try {
92 Sys.putEnv("NON_EXISTENT", null);
93 true;
94 } catch (e) {
95 trace(e);
96 false;
97 });
98 }
99 #end
19100
20101 function testProgramPath() {
21102 var p = Sys.programPath();
49130 #end
50131 }
51132
133 function testGetCwd() {
134 final current = Sys.getCwd();
135 // ensure it has a trailing slash
136 Assert.notEquals(current, haxe.io.Path.removeTrailingSlashes(current));
137 }
138
52139 #if !java
53 function testCwd() {
140 function testSetCwd() {
54141 var cur = Sys.getCwd();
55142 Sys.setCwd("../");
56143 var newCwd = haxe.io.Path.join([cur, "../"]);
4141 "bin-py";
4242 #elseif eval
4343 "bin-eval";
44 #elseif js
45 "bin-js";
4446 #else
4547 null;
4648 #end
128130 function setupClass() {
129131 FileSystem.createDirectory("temp-unicode");
130132 #if TEST_INVALID_UNICODE_FS
131 Sys.command("python3", ["genTestRes.py", "TEST_INVALID_UNICODE_FS"]);
133 Sys.command("python3", ["gen_test_res.py", "TEST_INVALID_UNICODE_FS"]);
132134 #else
133 Sys.command("python3", ["genTestRes.py"]);
135 Sys.command("python3", ["gen_test_res.py"]);
134136 #end
135137 }
136138
145147
146148 #if target.unicode
147149 function testFilesystem() {
148 #if !java
149 #if !(cpp || cs) // C++ disabled temporarily (#8400), C# disabled temporarily (#8247)
150 #if !java // java does not have this functionality
151 #if !cs // C# disabled temporarily (#8247)
150152 // setCwd + getCwd
151153 Sys.setCwd("test-res");
152154 function enterLeave(dir:String, ?alt:String):Void {
182184 );
183185 }, "test-res");
184186
185 #if !java
186 #if !(cpp || cs) // C++ disabled temporarily (#8400), C# disabled temporarily (#8247)
187 #if !java // java does not have this functionality
188 #if !cs // C# disabled temporarily (#8247)
187189 assertNormalEither(path -> {
188190 if (!FileSystem.exists(path)) return false; // NFC/NFD differences
189191 Sys.setCwd(path);
206208 #end
207209
208210 // exists
209 #if !cpp // C++ disabled temporarily (#8400)
210211 assertNormalEither(FileSystem.exists, 'test-res/a', 'expected exists == true');
211212 assertNormalEither(FileSystem.exists, 'test-res/b', 'expected exists == false');
212 #end
213213
214214 // fullPath
215215 #if !lua // Lua disabled temporarily (#8215)
256256 });
257257
258258 // rename
259 #if !cpp // C++ disabled temporarily (#8400)
260259 File.copy("test-res/data.bin", "temp-unicode/rename-me");
261260 pathBoth(str -> {
262261 FileSystem.rename('temp-unicode/rename-me', 'temp-unicode/$str');
264263 Assert.isTrue(FileSystem.exists('temp-unicode/$str'));
265264 FileSystem.rename('temp-unicode/$str', 'temp-unicode/rename-me');
266265 });
267 #end
268
269 #if !cpp // C++ disabled temporarily (#8400)
266
270267 pathBoth(str -> {
271268 // copy
272269 File.copy("test-res/data.bin", 'temp-unicode/$str');
286283 FileSystem.deleteDirectory('temp-unicode/$str');
287284 Assert.isFalse(FileSystem.exists('temp-unicode/$str'));
288285 });
289 #end
290286 }
291287
292288 // Temporary disabled for local run because of https://github.com/HaxeFoundation/haxe/issues/8380
322318 // trace
323319 assertUEnds(runUtility(["trace", '$i', mode]).stdout, str + endLine);
324320 #if !java
325 #if (hl || cpp) if (Sys.systemName() != "Windows") { #end // HL and C++ temporarily disabled (#8379)
326321 // putEnv + getEnv
327322 assertUEquals(runUtility(["putEnv", "HAXE_TEST", '$i', mode, "getEnv", "HAXE_TEST"]).stdout, str + endLine);
328323 // putEnv + environment
329324 assertUEquals(runUtility(["putEnv", "HAXE_TEST", '$i', mode, "environment", "HAXE_TEST"]).stdout, str + endLine);
330 #if (hl || cpp) } #end // HL and C++ temporarily disabled (#8379)
331325 #end
332326 });
333327
334328 // args
335329 #if !cs // C# behaves like Windows here
336 if (#if (java || eval || hl || cpp) Sys.systemName() != "Windows" #else true #end) {
330 if (#if (java || eval || cpp) Sys.systemName() != "Windows" #else true #end) {
337331 // https://stackoverflow.com/questions/7660651/passing-command-line-unicode-argument-to-java-code
338332 UnicodeSequences.normalBoth(str -> {
339333 assertUEquals(runUtility(["args", str]).stdout, str + endLine);
388382 assertBytesEqual(File.getBytes("temp-unicode/out.bin"), UnicodeSequences.validBytes);
389383
390384 // append
391 var out = File.append("temp-unicode/out.bin");
392 out.writeString(UnicodeSequences.validString);
393 out.close();
394 var repeated = Bytes.alloc(UnicodeSequences.validBytes.length * 2);
395 repeated.blit(0, UnicodeSequences.validBytes, 0, UnicodeSequences.validBytes.length);
396 repeated.blit(UnicodeSequences.validBytes.length, UnicodeSequences.validBytes, 0, UnicodeSequences.validBytes.length);
397 assertBytesEqual(File.getBytes("temp-unicode/out.bin"), repeated);
385 #if js
386 if (Sys.systemName() != "Mac") // File.append() here is broken on mac
387 #end
388 {
389 var out = File.append("temp-unicode/out.bin");
390 out.writeString(UnicodeSequences.validString);
391 out.close();
392 var repeated = Bytes.alloc(UnicodeSequences.validBytes.length * 2);
393 repeated.blit(0, UnicodeSequences.validBytes, 0, UnicodeSequences.validBytes.length);
394 repeated.blit(UnicodeSequences.validBytes.length, UnicodeSequences.validBytes, 0, UnicodeSequences.validBytes.length);
395 assertBytesEqual(File.getBytes("temp-unicode/out.bin"), repeated);
396 }
398397
399398 // readLine
400399 var data = File.read("test-res/data.bin");
00 /**
1 Used by TestUnicode.
1 Used by TestUnicode and TestSys.
22 Runs a given simple program based on the first argument.
33 */
44
2727 Path.join(["bin", "python"]);
2828 #elseif eval
2929 Path.join(["src"]);
30 #elseif js
31 Path.join(["bin", "js"]);
3032 #else
3133 null;
3234 #end
6365 "UtilityProcess.py";
6466 #elseif eval
6567 "UtilityProcess.hx";
68 #elseif js
69 "UtilityProcess.js";
6670 #else
6771 null;
6872 #end
117121 stderr: stderr
118122 };
119123 }
120
124
125 /** Runs the utility program via Sys.command rather than as a separate process,
126 for compatiblity with hxnodejs.
127
128 Returns the exit code of the command.
129 **/
130 public static function runUtilityAsCommand(args:Array<String>, ?options:{?stdin:String, ?execPath:String, ?execName:String}):Int {
131 if (options == null) options = {};
132 if (options.execPath == null) options.execPath = BIN_PATH;
133 if (options.execName == null) options.execName = BIN_NAME;
134 final execFull = Path.join([options.execPath, options.execName]);
135 final exitCode =
136 #if (macro || interp)
137 Sys.command("haxe", ["compile-each.hxml", "-p", options.execPath, "--run", options.execName].concat(args));
138 #elseif cpp
139 Sys.command(execFull, args);
140 #elseif cs
141 (switch (Sys.systemName()) {
142 case "Windows":
143 Sys.command(execFull, args);
144 case _:
145 Sys.command("mono", [execFull].concat(args));
146 });
147 #elseif java
148 Sys.command(Path.join([java.lang.System.getProperty("java.home"), "bin", "java"]), ["-jar", execFull].concat(args));
149 #elseif python
150 Sys.command(python.lib.Sys.executable, [execFull].concat(args));
151 #elseif neko
152 Sys.command("neko", [execFull].concat(args));
153 #elseif hl
154 Sys.command("hl", [execFull].concat(args));
155 #elseif php
156 Sys.command(php.Global.defined('PHP_BINARY') ? php.Const.PHP_BINARY : 'php', [execFull].concat(args));
157 #elseif lua
158 Sys.command("lua", [execFull].concat(args));
159 #elseif js
160 Sys.command("node", [execFull].concat(args));
161 #else
162 1;
163 #end
164
165 return exitCode;
166 }
167
121168 public static function main():Void {
122169 var args = Sys.args();
123 function sequenceIndex(d:String, mode:String):String return (switch (UnicodeSequences.valid[Std.parseInt(d)]) {
170 function sequenceIndex(d:String, mode:String):String
171 return switch UnicodeSequences.valid[Std.parseInt(d)] {
124172 case Only(ref): UnicodeSequences.codepointsToString(ref);
125173 case Normal(nfc, nfd): UnicodeSequences.codepointsToString(mode == "nfc" ? nfc : nfd);
126 });
174 };
127175 switch (args) {
128176 case _.slice(0, 1) => ["putEnv"]:
129 // ["putEnv", var name, index, nfc mode, next args...]
130 Sys.putEnv(args[1], sequenceIndex(args[2], args[3]));
131 var out = runUtility(args.slice(4));
132 Sys.print(out.stdout);
133 Sys.exit(out.exitCode);
177 // ["putEnv", var name, index, nfc mode, next args...]
178 Sys.putEnv(args[1], sequenceIndex(args[2], args[3]));
179 var out = runUtility(args.slice(4));
180 Sys.print(out.stdout);
181 Sys.exit(out.exitCode);
134182 case ["getCwd"]: Sys.println(Sys.getCwd());
135183 case ["getEnv", name]: Sys.println(Sys.getEnv(name));
184 case ["checkEnv", name, value]:
185 Sys.exit(value == Sys.getEnv(name) ? 0 : 1);
136186 case ["environment", name]: Sys.println(Sys.environment().get(name));
137187 case ["exitCode", Std.parseInt(_) => code]: Sys.exit(code);
138188 case ["args", data]: Sys.println(data);
143193 case ["stdin.readString", Std.parseInt(_) => len]: Sys.println(Sys.stdin().readString(len, UTF8));
144194 case ["stdin.readUntil", Std.parseInt(_) => end]: Sys.println(Sys.stdin().readUntil(end));
145195 case ["stderr.writeString", d, mode]:
146 var stream = Sys.stderr(); stream.writeString(sequenceIndex(d, mode)); stream.flush();
196 var stream = Sys.stderr(); stream.writeString(sequenceIndex(d, mode)); stream.flush();
147197 case ["stdout.writeString", d, mode]:
148 var stream = Sys.stdout(); stream.writeString(sequenceIndex(d, mode)); stream.flush();
198 var stream = Sys.stdout(); stream.writeString(sequenceIndex(d, mode)); stream.flush();
149199 case ["programPath"]: Sys.println(Sys.programPath());
150200 case _: // no-op
151201 }
1818 registeredSockets = [];
1919 }
2020
21 #if !js // bind is not implemented on nodejs
2122 public function testBind() {
2223 var socket = register(new Socket());
2324 socket.bind(new Host('localhost'), 34567);
2425 Assert.pass();
2526 }
26 }
27 #end
28 }
11 --main Main
22 --library utest
33 --dce full
4 -D analyzer-optimize
4 -D analyzer-optimize
5 -D UTEST_PRINT_TESTS
6 -D hl-ver=1.13.0
0 package cases;
1
2
3 #if target.atomics
4 import haxe.atomic.AtomicInt;
5 #end
6
7 @:timeout(2000)
8 class TestAtomics extends utest.Test {
9 #if target.atomics
10 function test(async:Async) {
11 var a = new AtomicInt(5);
12 final thread = Thread.create(() -> {
13 while(a.compareExchange(0, 2) != 0) {}
14 });
15 isTrue(a.compareExchange(5, 0) == 5);
16
17 while (a.compareExchange(2, 2) != 2) {}
18
19 async.done();
20 }
21 #end
22 }
0 package cases;
1
2 #if !neko
3 import sys.thread.Condition;
4 import sys.thread.Thread;
5 #end
6
7 class TestCondition extends utest.Test {
8 #if !neko
9 function test() {
10 final cond = new Condition();
11 cond.acquire();
12 Thread.create(() -> {
13 cond.acquire();
14 cond.signal();
15 cond.release();
16 });
17 cond.wait();
18 cond.release();
19 utest.Assert.pass();
20 }
21 #end
22 }
1313 events.cancel(e1);
1414 events.cancel(e2);
1515 events.cancel(e3);
16 }, 2);
17 e1 = events.repeat(() -> checks.push(1), 1);
18 e3 = events.repeat(() -> checks.push(3), 3);
16 }, 20);
17 e1 = events.repeat(() -> checks.push(1), 10);
18 e3 = events.repeat(() -> checks.push(3), 30);
1919 Sys.sleep(0.1);
2020
2121 var checker = null;
0 package cases;
1
2 #if !neko
3 import sys.thread.Semaphore;
4 #end
5
6 class TestSemaphore extends utest.Test {
7 #if !neko
8 function test() {
9 var m = new Semaphore(3);
10 m.acquire();
11 m.acquire();
12 isTrue(m.tryAcquire());
13 isFalse(m.tryAcquire());
14 isFalse(m.tryAcquire(0.1));
15 m.release();
16 m.release();
17 m.release();
18 }
19 #end
20 }
33 {"label": "JavaScript", "args": ["compile-js.hxml", "-cmd", "node -e \"require('./bin/unit.js').unit.TestMain.main()\""]},
44 {"label": "JVM", "args": ["compile-jvm-only.hxml", "-cmd", "java -jar bin/unit.jar"]},
55 {"label": "Interp", "args": ["compile-macro.hxml"]},
6 {"label": "Lua", "args": ["compile-lua.hxml", "-cmd", "lua bin/unit.lua"]},
67 ],
78 "[haxe]": {
89 "editor.formatOnSave": true,
1516 "arguments": ["-v"]
1617 },
1718 "haxe.enableCompilationServer": false
18 }
19 }
0 -D source-header=''
0 -D source-header=
11 --debug
22 -p src
33 # -cp "C:\Program Files\The Haxe Effect\src/dev/null"
66 --resource serializedValues.txt
77 --macro Macro.init()
88 --dce full
9 -lib utest:git:https://github.com/haxe-utest/utest#559b24c9a36533281ba7a2eed8aab83ed6b872b4
9 -lib utest
1010 -D analyzer-optimize
1111 -D analyzer-user-var-fusion
12 -D message-reporting=pretty
0 -cmd compc -output native_swf/lib.swc -include-sources native_swf/
1
2 --next
3
4 compile-each.hxml
5 --main unit.TestMain
6 -swf bin/unit.swf
7 -swf-lib native_swf/lib.swc
8 -D network-sandbox
+0
-10
tests/unit/compile-flash9.hxml less more
0 -cmd compc -output native_swf/lib.swc -include-sources native_swf/
1
2 --next
3
4 compile-each.hxml
5 --main unit.TestMain
6 --swf-version 11
7 -swf bin/unit9.swf
8 -swf-lib native_swf/lib.swc
9 -D network-sandbox
22 -hl bin/unit.hl
33 #-D interp
44 -D hl-check
5 -D hl-ver=1.11.0
5 -D hl-ver=1.13.0
00 compile-each.hxml
1
2 --each
3
14 --main unit.TestMain
2 -python bin/unit.py
5 -python bin/unit.py
6
7 --next
8
9 -D python-version=3.4
10 --main unit.TestMain
11 -python bin/unit34.py
1010
1111 # targets
1212
13 --next compile-flash9.hxml
13 --next compile-flash.hxml
1414 --next compile-js.hxml
1515 --next compile-hl.hxml
1616 --next compile-lua.hxml
2020 --next compile-java.hxml
2121 --next compile-cs.hxml
2222 --next compile-python.hxml
23 --next compile-cs-unsafe.hxml
2324 --next compile-macro.hxml
24 --next compile-cs-unsafe.hxml
2121 C haxe.UpperCasePackage.SomeClass
2222 M haxe.UpperCasePackage.lowercase
2323 C haxe.UpperCasePackage.lowercase
24 M haxe.test.MyDefaultInterface
25 C haxe.test.MyDefaultInterface
26 M haxe.test.MyDefaultSubInterface
27 C haxe.test.MyDefaultSubInterface
2428 end modules
0 package haxe.test;
1 import java.lang.annotation.*;
2
3 public interface MyDefaultInterface
4 {
5 default public String test(String a)
6 {
7 return a.toUpperCase();
8 }
9 }
10
11 class MyDefaultClass implements MyDefaultInterface {}
0 package haxe.test;
1 import java.lang.annotation.*;
2
3 public interface MyDefaultSubInterface extends MyDefaultInterface
4 {
5
6 }
4747 return { pos: currentPos(), expr: haxe.macro.Expr.ExprDef.EConst(haxe.macro.Expr.Constant.CIdent(result)) };
4848 }
4949
50 @:access(haxe.macro.Error.childErrors)
5051 static public macro function typeErrorText(e:haxe.macro.Expr) {
5152 var result = try {
5253 typeof(e);
5354 null;
54 } catch (e:haxe.macro.Expr.Error) e.message;
55 } catch (e:haxe.macro.Expr.Error) {
56 var msg = e.message;
57 if (e.childErrors != null) for (c in e.childErrors) msg += "\n" + c.message;
58 msg;
59 }
5560 return {
5661 pos: currentPos(),
5762 expr: if (result == null)
8686 f3_1 = (?a:Int, b:String) -> a + b.length;
8787 f3_2 = (a:Int, ?b:Int) -> a + b;
8888
89 #if !(flash || hl) // Cannot skip not nullable argument
89 #if !flash // Cannot skip not nullable argument
9090 f3_1 = function (a=1, b:String) return a + b.length;
9191 eq(f3_1("--"),3);
9292
273273 i[x++] += 4;
274274 eq(x, 2);
275275 eq(i[1], 4);
276
277 eq(new Map<Int, Int>().toString(), "[]");
278 eq(new Map<String, Int>().toString(), "[]");
279 eq(new Map<MyEnum, Int>().toString(), "[]");
280 eq(new Map<{}, Int>().toString(), "[]");
281
282 eq([1 => 1].toString(), "[1 => 1]");
283 eq(["foo" => 1].toString(), "[foo => 1]");
284 eq([MyEnum.C(0, "foo") => 1].toString(), "[C(0,foo) => 1]");
285 final objMapString = [{foo: 1} => 1].toString();
286 eq(objMapString.charCodeAt(0), "[".code);
287 eq(objMapString.charCodeAt(objMapString.length - 1), "]".code);
276288 }
277289
278290 function testObjectKeyword() {
0 package unit;
1
2 import utest.Assert;
3
4 using StringTools;
5
6 private class DefaultTPClass_y<T=String> {}
7 private class DefaultTPClass_yn<S=String, T> {}
8 private class DefaultTPClass_ny<S, T=String> {}
9 private class DefaultTPClass_yy<S=Int, T=String> {}
10
11 class TestDefaultTypeParameters extends Test {
12 function test() {
13 t(HelperMacros.typeString((null : DefaultTPClass_y)).endsWith("DefaultTPClass_y<String>"));
14 t(HelperMacros.typeString((null : DefaultTPClass_y<Int>)).endsWith("DefaultTPClass_y<Int>"));
15 t(HelperMacros.typeString((null : DefaultTPClass_yn<Int, String>)).endsWith("DefaultTPClass_yn<Int, String>"));
16 t(HelperMacros.typeString((null : DefaultTPClass_ny<Int>)).endsWith("DefaultTPClass_ny<Int, String>"));
17 t(HelperMacros.typeString((null : DefaultTPClass_ny<Int, Int>)).endsWith("DefaultTPClass_ny<Int, Int>"));
18 t(HelperMacros.typeString((null : DefaultTPClass_yy)).endsWith("DefaultTPClass_yy<Int, String>"));
19 t(HelperMacros.typeString((null : DefaultTPClass_yy<String>)).endsWith("DefaultTPClass_yy<String, String>"));
20 t(HelperMacros.typeString((null : DefaultTPClass_yy<Int, Int>)).endsWith("DefaultTPClass_yy<Int, Int>"));
21 }
22
23 macro static function printThings() {
24 var pr = new haxe.macro.Printer();
25 var tds = [
26 macro class DefaultTPClass_y<T=String> {},
27 macro class DefaultTPClass_yn<S=String, T> {},
28 macro class DefaultTPClass_ny<S, T=String > {},
29 macro class DefaultTPClass_yy<S=Int, T=String> {},
30 ];
31 return macro $v{[for (td in tds) pr.printTypeDefinition(td).replace("\r", "").replace("\n", "")]};
32 }
33
34 function testPrinting() {
35 var expected = [
36 "class DefaultTPClass_y<T=String> {}",
37 "class DefaultTPClass_yn<S=String, T> {}",
38 "class DefaultTPClass_ny<S, T=String> {}",
39 "class DefaultTPClass_yy<S=Int, T=String> {}"
40 ];
41 Assert.same(expected, printThings());
42 }
43 }
241241 var expected = null;
242242 var lineShift = 0;
243243 for(s in stacks) {
244 // TODO: fix hl vs other targets difference with callstacks
245 // See https://github.com/HaxeFoundation/haxe/issues/10926
246 #if hl @:privateAccess s.asArray().shift(); #end
247
244248 if(expected == null) {
245249 expected = stackItemData(s[0]);
246250 } else {
55 CFloat(s:String):Constant<Float>;
66 }
77
8 enum Binop<S,T> {
9 OpAdd:Binop<Float,Float>;
10 OpEq:Binop<S,Bool>;
8 enum Binop<S, T> {
9 OpAdd:Binop<Float, Float>;
10 OpEq:Binop<S, Bool>;
1111 }
1212
1313 enum Expr<T> {
1414 EConst(c:Constant<T>):Expr<T>;
15 EBinop<C>(op:Binop<C,T>, e1:Expr<C>, e2:Expr<C>):Expr<T>;
15 EBinop<C>
16 (op : Binop<C, T>, e1 : Expr<C>, e2 : Expr<C>) : Expr<T>;
1617 }
1718
1819 class TestGADT extends Test {
19
2020 function testBasic() {
2121 var ti = 1.22;
2222 var tb = false;
2525 var e2 = EConst(CFloat("8"));
2626 var e3 = EConst(CFloat("12"));
2727
28 var eadd = EBinop(OpAdd,e1,e2);
28 var eadd = EBinop(OpAdd, e1, e2);
2929 var s = eval(eadd);
3030 HelperMacros.typedAs(s, ti);
31 eq(s,20);
31 eq(s, 20);
3232
33 var eeq = EBinop(OpEq,e1,e2);
33 var eeq = EBinop(OpEq, e1, e2);
3434 var s = eval(eeq);
3535 HelperMacros.typedAs(s, tb);
36 eq(s,false);
36 eq(s, false);
3737
38 var eeq = EBinop(OpEq,e1,e3);
38 var eeq = EBinop(OpEq, e1, e3);
3939 var s = eval(eeq);
4040 HelperMacros.typedAs(s, tb);
41 eq(s,true);
41 eq(s, true);
4242 }
4343
44 @:haxe.warning("-WGenerator")
4445 static function evalConst<T>(c:Constant<T>):T {
4546 return switch (c) {
4647 case CString(s): s;
4950 }
5051 }
5152
52 static function evalBinop<T,C>(op:Binop<C,T>, e1:Expr<C>, e2:Expr<C>):T {
53 return switch(op) {
53 @:haxe.warning("-WGenerator")
54 static function evalBinop<T, C>(op:Binop<C, T>, e1:Expr<C>, e2:Expr<C>):T {
55 return switch (op) {
5456 case OpAdd: eval(e1) + eval(e2);
5557 case OpEq: eval(e1) == eval(e2);
5658 }
5759 }
5860
5961 static function eval<T>(e:Expr<T>):T {
60 return switch(e) {
62 return switch (e) {
6163 case EConst(c): evalConst(c);
62 case EBinop(_op,_e1,_e2): evalBinop(_op,_e1,_e2); // TODO: this generates some unused variable warnings in macro context (issue #1675?)
64 case EBinop(_op, _e1, _e2): evalBinop(_op, _e1, _e2); // TODO: this generates some unused variable warnings in macro context (issue #1675?)
6365 }
6466 }
65 }
67 }
77 @:generic
88 class MyGeneric<T> {
99 public var t:T;
10
1011 public function new(t:T) {
1112 this.t = t;
1213 }
1415
1516 class MyRandomClass {
1617 public var s:String;
18
1719 public function new(s:String) {
1820 this.s = s;
1921 }
2022 }
2123
22 class MyRandomEmptyClass { }
24 class MyRandomEmptyClass {}
2325
2426 @:generic class RBNode<T:RBNode<T>> {
25 public var rbLeft : T;
26 public var rbRight : T;
27 public var rbLeft:T;
28 public var rbRight:T;
2729 }
2830
2931 @:generic class RBTree<T:RBNode<T>> {
30 public var root : T;
31 public function new() { }
32 public var root:T;
33
34 public function new() {}
3235 }
3336
3437 class MyData extends RBNode<MyData> {
35 var id : Int;
38 var id:Int;
39
3640 public function new(id:Int) {
3741 this.id = id;
3842 }
4549 t((mg.t is Int));
4650
4751 var mg = new MyGeneric<String>("12");
48 eq(mg.t,"12");
52 eq(mg.t, "12");
4953 t((mg.t is String));
5054 }
5155
6367 eq(a.t.b, null);
6468 }
6569
70 @:haxe.warning("-WGenerator")
6671 function testGenericFn() {
6772 var a = new MyGeneric<Int->Int>(function(i:Int):Int return i * i);
6873 eq(4, a.t(2));
2626 return;
2727 }
2828 test();
29 #elseif (github && (hl || java || (flash && (Linux || Mac)) || (cs && Windows)))
29 #elseif (github && (hl || java || (flash && (Linux || Mac || Windows)) || (cs && Windows)))
3030 noAssert();
3131 async.done();
3232 return;
00 package unit;
11
2 import haxe.Int64.*;
3
24 using haxe.Int64;
3 import haxe.Int64.*;
45
56 class TestInt64 extends Test {
67
1011 // Test creation and fields
1112 a = Int64.make(10,0xFFFFFFFF);
1213 eq( a.high, 10 );
14 eq( a.low, 0xFFFFFFFF );
15
16 a = 47244640255i64;
17 eq( a.high, 10 );
18 eq( a.low, 0xFFFFFFFF );
19
20 a = 0x7FFFFFFFFFFFFFFFi64;
21 eq( a.high, 0x7FFFFFFF );
1322 eq( a.low, 0xFFFFFFFF );
1423
1524 // Int casts
5261
5362 // This fails because the first division fails:
5463 var ten = haxe.Int64.make(0, 10);
55 var modulus = haxe.Int64.divMod( z, ten ).modulus.low;
56 eq( modulus, 0 );
64 var modulus = haxe.Int64.divMod(z, ten).modulus.low;
65 eq(modulus, 0);
5766
5867 // The first division failed because of negate:
59 eq( (-z).low, -2147483648 );
60 eq( (-z).high, 2147483647 );
68 eq((-z).low, -2147483648);
69 eq((-z).high, 2147483647);
6170 }
6271
6372 // Some tests of how it generates Int64 when used as Null<Int64> or as type parameters
64 function testGen()
65 {
73 function testGen() {
6674 var arr:Array<Int64> = [];
6775 arr.push(1);
68 arr.push(Int64.make(0xFFFFFFFF,0x80000000));
76 arr.push(Int64.make(0xFFFFFFFF, 0x80000000));
6977 eq(arr[0].high, 0);
7078 eq(arr[0].low, 1);
7179 eq(arr[1].high, 0xFFFFFFFF);
8088 eq(n.low, 0xefefefef);
8189 }
8290
83 function tryOverflow( a : Int64 )
84 {
91 function tryOverflow(a:Int64) {
8592 a.toInt();
8693 }
8794
8895 public function testIncrement() {
89 var a : Int64, b : Int64, c : Int64;
96 var a:Int64, b:Int64, c:Int64;
9097
9198 // Int64 should act as a value type and be immutable.
9299 // Increment ops should swap `this` to a new Int64 object.
93 a = 0; b = a;
100 a = 0;
101 b = a;
94102 a++;
95103 f(a == b);
96104
97 a = 0; b = a;
105 a = 0;
106 b = a;
98107 ++a;
99108 f(a == b);
100109
101 a = 0; b = a;
110 a = 0;
111 b = a;
102112 a--;
103113 f(a == b);
104114
105 a = 0; b = a;
115 a = 0;
116 b = a;
106117 --a;
107118 f(a == b);
108119
109 a = Int64.make(0,0xFFFFFFFF);
120 a = Int64.make(0, 0xFFFFFFFF);
110121 b = a;
111 c = Int64.make(1,0);
112 int64eq( a++, b );
113 int64eq( a--, c );
114 int64eq( ++a, c );
115 int64eq( --a, b );
122 c = Int64.make(1, 0);
123 int64eq(a++, b);
124 int64eq(a--, c);
125 int64eq(++a, c);
126 int64eq(--a, b);
116127 }
117128
118129 public function testToString() {
119 var a : Int64;
130 var a:Int64;
120131
121132 // Issue #903
122133 a = 0;
123 eq( Std.string( a ), "0" );
134 eq(Std.string(a), "0");
124135
125136 a = 156;
126 eq( '$a', "156" );
137 eq('$a', "156");
127138
128139 a = -1;
129 eq( '$a', "-1" );
130
131 a = Int64.make(0xFFFFFFFE,0);
132 eq( a.toStr(), "-8589934592" );
133
134 a = Int64.make(1,1);
135 eq( a.toStr(), "4294967297" );
140 eq('$a', "-1");
141
142 a = Int64.make(0xFFFFFFFE, 0);
143 eq(a.toStr(), "-8589934592");
144
145 a = Int64.make(1, 1);
146 eq(a.toStr(), "4294967297");
136147
137148 // set a to 2^63 (overflows to the smallest negative number)
138149 a = Int64.ofInt(2);
140151 a = Int64.mul(a, 2);
141152 }
142153
143 eq( Int64.add(a, -1).toStr(), "9223372036854775807" ); // largest positive
144 eq( Int64.add(a, 1).toStr(), "-9223372036854775807" ); // smallest negative - 1
145 eq( a.toStr(), "-9223372036854775808" ); // smallest negative
154 eq(Int64.add(a, -1).toStr(), "9223372036854775807"); // largest positive
155 eq(Int64.add(a, 1).toStr(), "-9223372036854775807"); // smallest negative - 1
156 eq(a.toStr(), "-9223372036854775808"); // smallest negative
146157 }
147158
148159 public function testComparison() {
149 var a : Int64, b : Int64;
150 a = 1; b = 1;
151 t( a == b ); f( a != b );
152 t( a <= b ); f( a < b );
153 t( a >= b ); f( a > b );
154 eq( a.compare(b), 0 );
155 eq( a.ucompare(b), 0 );
160 var a:Int64, b:Int64;
161 a = 1;
162 b = 1;
163 t(a == b);
164 f(a != b);
165 t(a <= b);
166 f(a < b);
167 t(a >= b);
168 f(a > b);
169 eq(a.compare(b), 0);
170 eq(a.ucompare(b), 0);
156171
157172 a = -10;
158173 b = -15;
159 f( a == b ); t( a != b );
160 f( a <= b ); f( a < b );
161 t( a >= b ); t( a > b );
162 t( a.compare(b) > 0 );
163 t( a.ucompare(b) > 0 );
164
165 a = Int64.make(0,0);
166 b = Int64.make(1,0);
167 f( a == b ); t( a != b );
168 t( a <= b ); t( a < b );
169 f( a >= b ); f( a > b );
170 t( a.compare(b) < 0 );
171 t( a.ucompare(b) < 0 );
172
173 a = Int64.make(0x0FFFFFFF,0xFFFFFFFF);
174 b = Int64.make(0x80000000,0x80000000);
175 f( a == b ); t( a != b );
176 f( a <= b ); f( a < b );
177 t( a >= b ); t( a > b );
178 t( a.compare(b) > 0 );
179 t( a.ucompare(b) < 0 );
174 f(a == b);
175 t(a != b);
176 f(a <= b);
177 f(a < b);
178 t(a >= b);
179 t(a > b);
180 t(a.compare(b) > 0);
181 t(a.ucompare(b) > 0);
182
183 a = Int64.make(0, 0);
184 b = Int64.make(1, 0);
185 f(a == b);
186 t(a != b);
187 t(a <= b);
188 t(a < b);
189 f(a >= b);
190 f(a > b);
191 t(a.compare(b) < 0);
192 t(a.ucompare(b) < 0);
193
194 a = Int64.make(0x0FFFFFFF, 0xFFFFFFFF);
195 b = Int64.make(0x80000000, 0x80000000);
196 f(a == b);
197 t(a != b);
198 f(a <= b);
199 f(a < b);
200 t(a >= b);
201 t(a > b);
202 t(a.compare(b) > 0);
203 t(a.ucompare(b) < 0);
180204
181205 // Issue #2317
182206 a = Int64.make(0xA, 0x828D97A8);
183207 b = 0;
184 t( a.compare(b) > 0 );
185 t( a.ucompare(b) > 0 );
208 t(a.compare(b) > 0);
209 t(a.ucompare(b) > 0);
186210
187211 // Issue #2090
188212 a = 0;
189213 b = Int64.make(320, -2138504556);
190 t( a.compare(b) < 0 );
191 t( a.ucompare(b) < 0 );
192
193
214 t(a.compare(b) < 0);
215 t(a.ucompare(b) < 0);
194216 }
195217
196218 public function testAddition() {
197 var a : Int64, b : Int64;
198
199 a = Int64.make(0,0x9E370301);
200 b = Int64.make(0,0xB0590000);
201 int64eq( a+b, Int64.make(0x1,0x4E900301) );
219 var a:Int64, b:Int64;
220
221 a = Int64.make(0, 0x9E370301);
222 b = Int64.make(0, 0xB0590000);
223 int64eq(a + b, Int64.make(0x1, 0x4E900301));
202224
203225 // negation
204226 b = -a;
205 int64eq( a+b, 0 );
227 int64eq(a + b, 0);
206228
207229 // Int64+Int
208 int64eq( a+12345678, Int64.make(0,0x9EF3644F) );
230 int64eq(a + 12345678, Int64.make(0, 0x9EF3644F));
209231
210232 // Int+Int64
211 int64eq( 0xF0002222+a, Int64.make(0,0x8E372523) );
233 int64eq(0xF0002222 + a, Int64.make(0, 0x8E372523));
212234 }
213235
214236 public function testSubtraction() {
215 var a : Int64, b : Int64;
216
217 a = Int64.make(1,0);
218 b = Int64.make(0,1);
219 int64eq( a-b, Int64.make(0,0xFFFFFFFF) );
237 var a:Int64, b:Int64;
238
239 a = Int64.make(1, 0);
240 b = Int64.make(0, 1);
241 int64eq(a - b, Int64.make(0, 0xFFFFFFFF));
220242
221243 b = a;
222 int64eq( a-b, 0 );
223
224 b = Int64.make(0xFFFFFFFE,1);
225 int64eq( a-b, Int64.make(2,0xFFFFFFFF) );
244 int64eq(a - b, 0);
245
246 b = Int64.make(0xFFFFFFFE, 1);
247 int64eq(a - b, Int64.make(2, 0xFFFFFFFF));
226248
227249 // Int64-Int
228 int64eq( a-12345678, Int64.make(0,0xFF439EB2) );
250 int64eq(a - 12345678, Int64.make(0, 0xFF439EB2));
229251
230252 // Int-Int64
231 int64eq( 12345678-a, Int64.make(0xFFFFFFFF,0x00BC614E) );
253 int64eq(12345678 - a, Int64.make(0xFFFFFFFF, 0x00BC614E));
232254 }
233255
234256 public function testMultiplication() {
235 var a : Int64, b : Int64;
257 var a:Int64, b:Int64;
236258
237259 a = Int64.make(0, 0x239B0E13);
238260 b = Int64.make(0, 0x39193D1B);
239 int64eq( a*b, Int64.make(0x07F108C6,0x4E900301) );
261 int64eq(a * b, Int64.make(0x07F108C6, 0x4E900301));
240262
241263 a = Int64.make(0, 0xD3F9C9F4);
242264 b = Int64.make(0, 0xC865C765);
243 int64eq( a*b, Int64.make(0xA5EF6C6E,0x1ACD5944) );
265 int64eq(a * b, Int64.make(0xA5EF6C6E, 0x1ACD5944));
244266
245267 var a = Int64.make(0xFFF21CDA, 0x972E8BA3);
246268 var b = Int64.make(0x0098C29B, 0x81000001);
247 int64eq( a*b, Int64.make(0xDDE8A2E8, 0xBA2E8BA3) );
269 int64eq(a * b, Int64.make(0xDDE8A2E8, 0xBA2E8BA3));
248270
249271 var a = Int64.make(0x81230000, 0x81230000);
250272 var b = Int64.make(0x90909090, 0x90909090);
251 int64eq( a*b, Int64.make(0xF04C9C9C,0x53B00000) );
273 int64eq(a * b, Int64.make(0xF04C9C9C, 0x53B00000));
252274
253275 var a = Int64.make(0x00001000, 0x0020020E);
254276 var b = Int64.make(0xBEDBEDED, 0xDEBDEBDE);
255 int64eq( a*b, Int64.make(0xC45C967D,0x25FAA224) );
277 int64eq(a * b, Int64.make(0xC45C967D, 0x25FAA224));
256278
257279 // Issue #1532
258280 a = Int64.make(0xFFF21CDA, 0x972E8BA3);
259281 b = Int64.make(0x0098C29B, 0x81000001);
260 int64eq( a*b, Int64.make(0xDDE8A2E8, 0xBA2E8BA3) );
282 int64eq(a * b, Int64.make(0xDDE8A2E8, 0xBA2E8BA3));
261283
262284 // Int64*Int
263285 a = Int64.make(0x01000000, 0x11131111);
264 int64eq( a*7, Int64.make(0x07000000,0x77857777) );
286 int64eq(a * 7, Int64.make(0x07000000, 0x77857777));
265287
266288 // Int*Int64
267289 a = Int64.make(0x91111111, 0x11111111);
268 int64eq( 2*a, Int64.make(0x22222222,0x22222222) );
290 int64eq(2 * a, Int64.make(0x22222222, 0x22222222));
269291 }
270292
271293 public function testDivision() {
272 var a : Int64, b : Int64;
294 var a:Int64, b:Int64;
273295
274296 a = Int64.make(0x00002342, 0xDDEF3421);
275297 b = Int64.make(0x00000001, 0x00002000);
276 int64eq( a/b, 9026 );
277 int64eq( a%b, Int64.make(0,0xD986F421) );
298 int64eq(a / b, 9026);
299 int64eq(a % b, Int64.make(0, 0xD986F421));
278300 var result = a.divMod(b);
279 int64eq( a/b, result.quotient );
280 int64eq( a%b, result.modulus );
301 int64eq(a / b, result.quotient);
302 int64eq(a % b, result.modulus);
281303
282304 a = Int64.make(0xF0120AAA, 0xAAAAAAA0);
283305 b = Int64.make(0x00020001, 0x0FF02000);
284 int64eq( a/b, -2038 );
285 int64eq( a%b, Int64.make(0xFFFE131F,0x8C496AA0) );
306 int64eq(a / b, -2038);
307 int64eq(a % b, Int64.make(0xFFFE131F, 0x8C496AA0));
286308 result = a.divMod(b);
287 int64eq( a/b, result.quotient );
288 int64eq( a%b, result.modulus );
309 int64eq(a / b, result.quotient);
310 int64eq(a % b, result.modulus);
289311
290312 a = Int64.make(0, 2);
291313 b = Int64.make(0xFFFFFFFF, 0xFAFAFAFA);
292 int64eq( a/b, 0 );
293 int64eq( a%b, 2 );
314 int64eq(a / b, 0);
315 int64eq(a % b, 2);
294316 result = a.divMod(b);
295 int64eq( a/b, result.quotient );
296 int64eq( a%b, result.modulus );
317 int64eq(a / b, result.quotient);
318 int64eq(a % b, result.modulus);
297319
298320 a = Int64.make(0x7ABADDAD, 0xDEADBEEF);
299321 b = Int64.make(0xFFFFFFF1, 0x1FFFFFFF);
300 int64eq( a/b, Int64.make(0xFFFFFFFF,0xF7BFCEAE) );
301 int64eq( a%b, Int64.make(0x0000000A,0x166D8D9D) );
322 int64eq(a / b, Int64.make(0xFFFFFFFF, 0xF7BFCEAE));
323 int64eq(a % b, Int64.make(0x0000000A, 0x166D8D9D));
302324 result = a.divMod(b);
303 int64eq( a/b, result.quotient );
304 int64eq( a%b, result.modulus );
325 int64eq(a / b, result.quotient);
326 int64eq(a % b, result.modulus);
305327
306328 a = Int64.make(0x81234567, 0xFDECBA98);
307329 b = Int64.make(0xFFFFFEFF, 0xEEEEEEEE);
308 int64eq( a/b, 0x007ED446 );
309 int64eq( a%b, Int64.make(0xFFFFFFF5,0x31964D84) );
330 int64eq(a / b, 0x007ED446);
331 int64eq(a % b, Int64.make(0xFFFFFFF5, 0x31964D84));
310332 result = a.divMod(b);
311 int64eq( a/b, result.quotient );
312 int64eq( a%b, result.modulus );
333 int64eq(a / b, result.quotient);
334 int64eq(a % b, result.modulus);
313335
314336 // Int64/Int
315 int64eq( a/2, Int64.make(0xC091A2B3,0xFEF65D4C) );
316 int64eq( a%100, -68 );
337 int64eq(a / 2, Int64.make(0xC091A2B3, 0xFEF65D4C));
338 int64eq(a % 100, -68);
317339
318340 // Int/Int64
319 int64eq( 10001/a, 0 );
320 int64eq( 515151%a, 515151 );
341 int64eq(10001 / a, 0);
342 int64eq(515151 % a, 515151);
321343 }
322344
323345 public function testBinaryOps() {
324 var a : Int64, b : Int64;
346 var a:Int64, b:Int64;
325347
326348 a = haxe.Int64.make(0x0FFFFFFF, 0x00000001);
327349 b = haxe.Int64.make(0, 0x8FFFFFFF);
328 int64eq( a&b, 1 );
329 int64eq( a|b, Int64.make(0x0FFFFFFF, 0x8FFFFFFF) );
330 int64eq( a^b, Int64.make(0x0FFFFFFF, 0x8FFFFFFE) );
331 int64eq( ~a, Int64.make(0xF0000000, 0xFFFFFFFE) );
350 int64eq(a & b, 1);
351 int64eq(a | b, Int64.make(0x0FFFFFFF, 0x8FFFFFFF));
352 int64eq(a ^ b, Int64.make(0x0FFFFFFF, 0x8FFFFFFE));
353 int64eq(~a, Int64.make(0xF0000000, 0xFFFFFFFE));
332354 }
333355
334356 public function testShifts() {
335 var a : Int64;
357 var a:Int64;
336358
337359 a = 1 << 20;
338 int64eq( a, 0x100000 );
360 int64eq(a, 0x100000);
339361
340362 a <<= 20;
341 int64eq( a, Int64.make(0x100,0x00000000) );
363 int64eq(a, Int64.make(0x100, 0x00000000));
342364
343365 a = -1;
344366 a >>= 4;
345 int64eq( a, -1 );
367 int64eq(a, -1);
346368 a >>>= 4;
347 int64eq( a, Int64.make(0x0FFFFFFF,0xFFFFFFFF) );
369 int64eq(a, Int64.make(0x0FFFFFFF, 0xFFFFFFFF));
348370
349371 // Ensure proper overflow behavior for shift operand
350 a = Int64.make(1,1);
351 int64eq( a << 0, a );
352 int64eq( a >> 0, a );
353 int64eq( a >>> 0, a );
354 int64eq( a << 64, a );
355 int64eq( a >> 64, a );
356 int64eq( a >>> 64, a );
372 a = Int64.make(1, 1);
373 int64eq(a << 0, a);
374 int64eq(a >> 0, a);
375 int64eq(a >>> 0, a);
376 int64eq(a << 64, a);
377 int64eq(a >> 64, a);
378 int64eq(a >>> 64, a);
357379 }
358380
359381 /** Tests that we have all of the classic Int64 interface. */
360382 public function testBackwardsCompat() {
361 var a : Int64 = 32.ofInt();
362 var b : Int64 = (-4).ofInt();
363
364 f( a.eq(b) );
365 t( a.neq(b) );
366 int64eq( a.add(b), 28 );
367 int64eq( a.sub(b), 36 );
368 int64eq( a.div(b), -8 );
369 int64eq( a.mod(b), 0 );
370 int64eq( b.shl(1), -8 );
371 int64eq( b.shr(1), -2 );
372 int64eq( b.ushr(1), Int64.make(0x7FFFFFFF,0xFFFFFFFE) );
373 int64eq( a.and(b), 32 );
374 int64eq( a.or(b), -4 );
375 int64eq( a.xor(b), -36 );
376 int64eq( a.neg(), -32 );
377 f( a.isNeg() ); t( b.isNeg() );
378 f( a.isZero() ); f( b.isZero() );
379 t( a.compare(b) > 0 );
380 t( a.ucompare(b) < 0 );
381 int64eq( a.toInt(), 32 );
382 int64eq( b.toInt(), -4 );
383 }
384
385 public function testCapture()
386 {
387 var a = Int64.make(0xFF00FF00,0xF0F0F0F0),
388 b = Int64.make(0xFF00FF00,0xF0F0F0F0);
383 var a:Int64 = 32.ofInt();
384 var b:Int64 = (-4).ofInt();
385
386 f(a.eq(b));
387 t(a.neq(b));
388 int64eq(a.add(b), 28);
389 int64eq(a.sub(b), 36);
390 int64eq(a.div(b), -8);
391 int64eq(a.mod(b), 0);
392 int64eq(b.shl(1), -8);
393 int64eq(b.shr(1), -2);
394 int64eq(b.ushr(1), Int64.make(0x7FFFFFFF, 0xFFFFFFFE));
395 int64eq(a.and(b), 32);
396 int64eq(a.or(b), -4);
397 int64eq(a.xor(b), -36);
398 int64eq(a.neg(), -32);
399 f(a.isNeg());
400 t(b.isNeg());
401 f(a.isZero());
402 f(b.isZero());
403 t(a.compare(b) > 0);
404 t(a.ucompare(b) < 0);
405 int64eq(a.toInt(), 32);
406 int64eq(b.toInt(), -4);
407 }
408
409 public function testCapture() {
410 var a = Int64.make(0xFF00FF00, 0xF0F0F0F0),
411 b = Int64.make(0xFF00FF00, 0xF0F0F0F0);
389412 eq(a.compare(b), 0);
390413 eq(a.high, 0xFF00FF00);
391 function test() return Int64.compare(a,Int64.make(0xFF00FF00,0xF0F0F0F0));
392 eq(test(),0);
393 function testSet(v:Int64) b = v;
394 testSet( make(0xFF00FF00, 0xFF0) );
395 eq(b.compare(make(0xFF00FF00,0xFF0)),0);
414 function test()
415 return Int64.compare(a, Int64.make(0xFF00FF00, 0xF0F0F0F0));
416 eq(test(), 0);
417 function testSet(v:Int64)
418 b = v;
419 testSet(make(0xFF00FF00, 0xFF0));
420 eq(b.compare(make(0xFF00FF00, 0xFF0)), 0);
396421 eq(b.high, 0xFF00FF00);
397422 }
398423
400425 var a = Int64.make(0, 0x239B0E13);
401426 var b = Int64.make(0, 0x39193D1B);
402427 var c = Int64.mul(a, b);
403 eq( c.toStr(), "572248275467371265" );
428 eq(c.toStr(), "572248275467371265");
404429 eq(Int64.toStr(c), "572248275467371265");
405430
406431 var a = Int64.make(0, 0xD3F9C9F4);
407432 var b = Int64.make(0, 0xC865C765);
408433 var c = Int64.mul(a, b);
409 eq( c.toStr(), "-6489849317865727676" );
434 eq(c.toStr(), "-6489849317865727676");
410435
411436 var a = Int64.make(0, 0x9E370301);
412437 var b = Int64.make(0, 0xB0590000);
413438 var c = Int64.add(a, b);
414 eq( Int64.toStr(c), "5613028097" );
439 eq(Int64.toStr(c), "5613028097");
415440
416441 var a = Int64.make(0xFFF21CDA, 0x972E8BA3);
417442 var b = Int64.make(0x0098C29B, 0x81000001);
418443 var c = Int64.mul(a, b);
419444 var expected = Int64.make(0xDDE8A2E8, 0xBA2E8BA3);
420 eq( expected.compare(c), 0 );
445 eq(expected.compare(c), 0);
421446 }
422447
423448 public function testCompare() {
424 var a = ofInt(2),
425 b = ofInt(3);
449 var a = ofInt(2), b = ofInt(3);
426450 t(a == a);
427451 t(b == b);
428452 eq(a.compare(a), 0);
431455 }
432456
433457 public function testBits() {
434 var x = make(0xfedcba98,0x76543210);
458 var x = make(0xfedcba98, 0x76543210);
435459 var y = x.and((ofInt(0xffff))),
436460 z = x.or((ofInt(0xffff))),
437 w = x.xor((make(0xffffffff,0xffffffff)));
461 w = x.xor((make(0xffffffff, 0xffffffff)));
438462 eq(y.toStr(), '12816');
439463 eq(z.toStr(), '-81985529216434177');
440464 eq(w.toStr(), '81985529216486895');
441465 eq(x.and(ofInt(0xffff)).toStr(), '12816');
442466 eq((x.or(ofInt(0xffff))).toStr(), '-81985529216434177');
443467 eq((x.xor(ofInt(0xffff))).toStr(), '-81985529216446993');
444 eq((x.and(make(0x1,0xffffffff))).toStr(), '1985229328');
445 eq((x.or(make(0x1,0xffffffff))).toStr(), '-81985522611781633');
468 eq((x.and(make(0x1, 0xffffffff))).toStr(), '1985229328');
469 eq((x.or(make(0x1, 0xffffffff))).toStr(), '-81985522611781633');
446470 eq((x.xor(make(0x1, 0xffffffff))).toStr(), '-81985524597010961');
447 var a = ofInt(7),
448 b = a.shl(1);
471 var a = ofInt(7), b = a.shl(1);
449472 eq(b.toStr(), '14');
450473 }
451474
452475 public function testAdd() {
453 var a = ofInt(3),
454 b = ofInt(2),
455 c = make(0xffffffff,0xfffffffe);
456 eq( (a.add(b)).compare(ofInt(5)), 0 );
457 eq( (a.add(ofInt(4))).compare(ofInt(7)), 0 );
458 eq( (c.add(ofInt(3))).compare(ofInt(1)), 0 );
476 var a = ofInt(3), b = ofInt(2), c = make(0xffffffff, 0xfffffffe);
477 eq((a.add(b)).compare(ofInt(5)), 0);
478 eq((a.add(ofInt(4))).compare(ofInt(7)), 0);
479 eq((c.add(ofInt(3))).compare(ofInt(1)), 0);
459480 // numbers larger than int32
460 eq( a.add(make(0x1, 0)).toStr(), '4294967299');
481 eq(a.add(make(0x1, 0)).toStr(), '4294967299');
461482 }
462483
463484 public function testNeg() {
464 eq(Std.string(ofInt(-1)),Std.string(neg(ofInt(1))));
465 eq(Std.string(ofInt(-100)),Std.string(neg(ofInt(100))));
485 eq(Std.string(ofInt(-1)), Std.string(neg(ofInt(1))));
486 eq(Std.string(ofInt(-100)), Std.string(neg(ofInt(100))));
466487 eq(Std.string(make(-2147483648, 1)), Std.string(neg(make(2147483647, -1)))); // -9223372036854775807 == neg(9223372036854775807)
467488 }
468489
469 function int64eq( v : Int64, v2 : Int64, ?pos ) {
490 function int64eq(v:Int64, v2:Int64, ?pos) {
470491 t(v == v2);
471492 }
472493
473 public function testParseString()
474 {
494 public function testParseString() {
475495 for (v in ["0", "1", "-1", "9223372036854775807", "-9223372036854775807"]) {
476496 eq(Std.string(parseString(v)), v);
477497 }
479499 // trims the string:
480500 eq("-23", Std.string(parseString(" -23 ")));
481501
482
483502 // overflow and underflow raise exceptions:
484 try
485 {
503 try {
486504 parseString("9223372036854775808");
487505 f(true);
488 }
489 catch (e:Dynamic)
490 {
491 // fine
492 }
493
494 try
495 {
506 } catch (e:Dynamic) {
507 // fine
508 }
509
510 try {
496511 parseString("-9223372036854775809");
497512 f(true);
498 }
499 catch (e:Dynamic)
500 {
501 // fine
502 }
503
504 try
505 {
513 } catch (e:Dynamic) {
514 // fine
515 }
516
517 try {
506518 parseString("--1");
507519 f(true);
508 }
509 catch (e:Dynamic)
510 {
511 // fine
512 }
513
514 try
515 {
520 } catch (e:Dynamic) {
521 // fine
522 }
523
524 try {
516525 parseString("asd1");
517526 f(true);
518 }
519 catch (e:Dynamic)
520 {
521 // fine
522 }
523
524 try
525 {
527 } catch (e:Dynamic) {
528 // fine
529 }
530
531 try {
526532 parseString("1asdf");
527533 f(true);
528 }
529 catch (e:Dynamic)
530 {
531 // fine
532 }
533 }
534
535 public function testFromFloat()
536 {
534 } catch (e:Dynamic) {
535 // fine
536 }
537 }
538
539 public function testFromFloat() {
537540 for (v in [0.0, 1.0, -1.0, 9007199254740991, -9007199254740991]) {
538541 eq(Std.parseFloat(Std.string(fromFloat(v))), v);
539542 }
540543
541 try
542 {
544 try {
543545 fromFloat(9007199254740992);
544546 f(true);
545 }
546 catch (e:Dynamic)
547 {
548 // fine
549 }
550
551 try
552 {
547 } catch (e:Dynamic) {
548 // fine
549 }
550
551 try {
553552 fromFloat(-9007199254740992);
554553 f(true);
555 }
556 catch (e:Dynamic)
557 {
554 } catch (e:Dynamic) {
558555 // fine
559556 }
560557
561558 var nan = Math.NaN;
562 try
563 {
559 try {
564560 fromFloat(nan);
565561 f(true);
566 }
567 catch (e:Dynamic)
568 {
569 // fine
570 }
571 }
572 }
562 } catch (e:Dynamic) {
563 // fine
564 }
565 }
566
567 static function toHex(v:haxe.Int64) {
568 return "0x" + (v.high == 0 ? StringTools.hex(v.low) : StringTools.hex(v.high) + StringTools.hex(v.low, 8));
569 }
570
571 function testNicolas() {
572 inline function check(a:haxe.Int64, str:String) {
573 eq(toHex(a), str);
574 }
575
576 check(33, "0x21");
577 check(-8, "0xFFFFFFFFFFFFFFF8");
578 var x = haxe.Int64.make(0x87654321, 0xABCDEF99);
579 check(x, "0x87654321ABCDEF99");
580 var y = haxe.Int64.make(0xABCDEF99, 0x87654321);
581 var small = haxe.Int64.make(0x3, 0x87654321);
582 check(x + x, "0xECA8643579BDF32");
583 check(x * x, "0xF6889F3201490971");
584 check(x + y, "0x333332BB333332BA");
585 check(x - y, "0xDB9753882468AC78");
586 check(x / small, "0xFFFFFFFFDDD2DC89");
587 check(x % small, "0xFFFFFFFFA2DAA6F0");
588 check(-x, "0x789ABCDE54321067");
589 check(small / 255, "0x38AF033");
590 check(small % 255, "0x54");
591 check(x << 1, "0xECA8643579BDF32");
592 check(x << 33, "0x579BDF3200000000");
593 check(x >> 8, "0xFF87654321ABCDEF");
594 check(x >> 40, "0xFFFFFFFFFF876543");
595 check(x >>> 40, "0x876543");
596 check(x & y, "0x8345430183454301");
597 check(x | y, "0xAFEDEFB9AFEDEFB9");
598 check(x ^ y, "0x2CA8ACB82CA8ACB8");
599 x++;
600 check(x, "0x87654321ABCDEF9A");
601 x--;
602 check(x, "0x87654321ABCDEF99");
603 check(~x, "0x789ABCDE54321066");
604 t(x == x);
605 f(x == y);
606
607 t(y >= x);
608 f(x >= y);
609 t(x >= x);
610 t(x + 1 >= x);
611 f(x - 1 >= x);
612 t(y > x);
613 f(x > y);
614 t(x + 1 > x);
615 f(x - 1 > x);
616 f(x > x);
617
618 f(y <= x);
619 t(x <= y);
620 t(x <= x);
621 f(x + 1 <= x);
622 t(x - 1 <= x);
623 f(y < x);
624 t(x < y);
625 f(x + 1 < x);
626 t(x - 1 < x);
627 f(x < x);
628 }
629 }
00 package unit;
1
12 import haxe.io.Bytes;
2 import haxe.test.Base;
3 import haxe.test.MyClass;
43 import haxe.test.Base.Base_InnerClass;
54 import haxe.test.Base.Base___InnerClass3__;
65 import haxe.test.Base.Base___InnerClass3___InnerClass4__;
6 import haxe.test.Base;
7 import haxe.test.LowerCaseClass;
8 import haxe.test.MyClass;
9 import haxe.test.MyDefaultInterface;
10 import haxe.test.MyDefaultSubInterface;
711 import haxe.test.TEnum;
8 import haxe.test.LowerCaseClass;
912 import java.util.EnumSet;
1013 import java.vm.*;
1114
1215 #if java
13 @:strict(haxe.test.MyClass.MyClass_MyAnnotation({ author:"John Doe", someEnum: TB }))
16 @:strict(haxe.test.MyClass.MyClass_MyAnnotation({author: "John Doe", someEnum: TB}))
1417 @:strict(MyClass_ParameterLessAnnotation)
15 class TestJava extends Test
16 {
17 function testException()
18 {
19 var native = new NativeClass();
20 var hx:NativeClass = new HxClass();
21
22 exc(function() try native.excTest() catch (e:Dynamic) throw e);
23 var dyn:Dynamic = native;
24 exc(dyn.excTest);
25
26 try
27 hx.excTest()
28 catch(e:Dynamic) throw e; //shouldn't throw any exception
29 }
30
31 public function testIssue2964()
32 {
18 class TestJava extends Test {
19 function testException() {
20 var native = new NativeClass();
21 var hx:NativeClass = new HxClass();
22
23 exc(function() try
24 native.excTest()
25 catch (e:Dynamic)
26 throw e);
27 var dyn:Dynamic = native;
28 exc(dyn.excTest);
29
30 try
31 hx.excTest()
32 catch (e:Dynamic)
33 throw e; // shouldn't throw any exception
34 }
35
36 public function testIssue2964() {
3337 var cl = new MyClass();
3438 var bbool:java.lang.Boolean = null;
3539 eq(cl.boolTest1(bbool), 100);
4549
4650 var i:java.lang.Integer = null;
4751 eq(cl.intTest1(i), 100);
48 eq(cl.intTest1(cast(-1, java.lang.Integer)),-1);
49 eq(cl.intTest1(cast(1000, java.lang.Integer)),1000);
52 eq(cl.intTest1(cast(-1, java.lang.Integer)), -1);
53 eq(cl.intTest1(cast(1000, java.lang.Integer)), 1000);
5054 i = -1;
5155 eq(cl.intTest1(i), -1);
5256 i = null;
5357 eq(cl.intTest2(i), 100);
54 eq(cl.intTest2(-1),-1);
55 eq(cl.intTest2(1000),1000);
58 eq(cl.intTest2(-1), -1);
59 eq(cl.intTest2(1000), 1000);
5660 i = -1;
5761 eq(cl.intTest2(i), -1);
5862
5963 var i:java.lang.Long = null;
6064 eq(cl.longTest(i), 100);
61 eq(cl.longTest(haxe.Int64.ofInt(-1)),-1);
62 eq(cl.longTest(haxe.Int64.ofInt(1000)),1000);
65 eq(cl.longTest(haxe.Int64.ofInt(-1)), -1);
66 eq(cl.longTest(haxe.Int64.ofInt(1000)), 1000);
6367 i = 10;
6468 eq(cl.longTest(i), 10);
6569 }
6670
67 public function testVarClash()
68 {
71 public function testVarClash() {
6972 var ic = new Base_InnerClass2();
7073 eq(ic.varNameClash2(), 1);
71 eq(ic.varNameClash2(2),2.2);
74 eq(ic.varNameClash2(2), 2.2);
7275 var iface:Base_VarNameClash = ic;
7376 eq(iface.varNameClash2(), 1);
74 eq(iface.varNameClash2(2),2.2);
77 eq(iface.varNameClash2(2), 2.2);
7578 var base:Base = ic;
76 eq(base.varNameClash2,0);
79 eq(base.varNameClash2, 0);
7780 base.varNameClash2 = 2;
78 eq(base.varNameClash2,2);
79 }
80
81 @:strict(MyClass_MyAnnotation({ author:"author", currentRevision: 2 }))
82 public function testAnnotations()
83 {
81 eq(base.varNameClash2, 2);
82 }
83
84 @:strict(MyClass_MyAnnotation({author: "author", currentRevision: 2}))
85 public function testAnnotations() {
8486 var cl = java.Lib.toNativeType(TestJava);
8587 var a = cl.getAnnotation(java.Lib.toNativeType(MyClass_MyAnnotation));
8688 t(a != null);
8890 eq(a.someEnum(), TB);
8991 eq(a.currentRevision(), 1);
9092 t(cl.getAnnotation(java.Lib.toNativeType(MyClass_ParameterLessAnnotation)) != null);
91 var m = cl.getMethod("testAnnotations", new java.NativeArray(0));
93 var m = cl.getMethod("testAnnotations");
9294 a = m.getAnnotation(java.Lib.toNativeType(MyClass_MyAnnotation));
9395 t(a != null);
9496 eq(a.author(), "author");
9698 eq(a.currentRevision(), 2);
9799 }
98100
99 function testLowerCase()
100 {
101 function testLowerCase() {
101102 var l = new LowerCaseClass();
102103 t(l.works);
103104 }
104105
105 function testNameCase()
106 {
106 function testNameCase() {
107107 t(haxe.uppercasepackage.SomeClass.SomeClassFound);
108108 t(haxe.uppercasepackage.Lowercase.lowercaseFound);
109109 }
110110
111 function testEnumSet()
112 {
111 function testEnumSet() {
113112 var es1:EnumSet<TEnum> = EnumSet.noneOf(java.Lib.toNativeEnum(TEnum));
114113 f(es1.contains(TA));
115114 es1.add(TA);
120119 // f(es2.contains(HC));
121120 }
122121
123 function testHaxeKeywords()
124 {
122 function testHaxeKeywords() {
125123 eq(Base._inline, 42);
126124 eq(Base.callback, 43);
127125 eq(Base._cast, 44);
131129 eq(Base._in, 40);
132130 }
133131
134 function testTypes()
135 {
132 function testTypes() {
136133 eq(Base.charTest(cast 10), cast 10);
137134 eq(Base.byteTest(cast 10), cast 10);
138135 }
139136
140
141 function testInnerClass()
142 {
137 function testInnerClass() {
143138 //-java-lib should be able to detect inner classes on import
144139 var i = new Base_InnerClass();
145140 eq(i.nameClash(), 10);
157152 eq("$$Inner$$Name8", haxe.test.MyClass.MyClass___Inner__Name7_____Inner__Name8.test());
158153 }
159154
160 function testGenerics()
161 {
155 function testGenerics() {
162156 var jcl:java.lang.Class<Base_InnerClass_InnerInnerClass> = cast Base_InnerClass_InnerInnerClass;
163157 t(haxe.test.GenericHelper.staticTypedGeneric(jcl) != null);
164158
165159 var helper = new haxe.test.GenericHelper();
166 //TODO use typedAs
160 // TODO use typedAs
167161 eq(helper.getUntypedGeneric(), null);
168162 eq(helper.typedGeneric, null);
169163
171165 var val3 = new Base___InnerClass3__();
172166 var g1 = new haxe.test.Generic1(val);
173167 g1.complexTypeParameterOfTypeParameter(new Base_InnerClass_InnerInnerClass());
174 //if no compile-time error, we're fine!
168 // if no compile-time error, we're fine!
175169 t(true);
176170 }
177171
178 function testNameClash()
179 {
172 function testNameClash() {
180173 eq(Base.nameClash(null), -1);
181174 eq(new Base().nameClash(), 1);
182175 eq(new Base().varNameClash(1), 1);
183176 eq(Base.varNameClash(10.4), 10.4);
184
185 }
186
187 function testOverloadOverride()
188 {
177 }
178
179 function testOverloadOverride() {
189180 var c = new TestMyClass();
190181 c.normalOverload(true);
191182 t(c.boolCalled);
213204 t(c.dynamicCalled);
214205 }
215206
216 function testThrows1()
217 {
207 function testThrows1() {
218208 // test 1: no @:throws / no catch
219209 var b = new Base();
220210 eq(Base.throwsTest(), 5);
223213 eq(b.throwsMemberTest(true), 10);
224214 }
225215
226 function testThrows2()
227 {
216 function testThrows2() {
228217 // test 2: catching only the IOException
229 try
230 {
218 try {
231219 var b = new Base();
232220 eq(Base.throwsTest(), 5);
233221 eq(Base.throwsTest(42), 42);
234222 eq(b.throwsMemberTest(), 6);
235223 eq(b.throwsMemberTest(true), 10);
236 }
237 catch(e:java.io.IOException)
238 {
239 }
240 }
241
242 function testThrows3()
243 {
224 } catch (e:java.io.IOException) {}
225 }
226
227 function testThrows3() {
244228 // test 3: catching all exceptions
245 try
246 {
229 try {
247230 var b = new Base();
248231 eq(Base.throwsTest(), 5);
249232 eq(Base.throwsTest(42), 42);
250233 eq(b.throwsMemberTest(), 6);
251234 eq(b.throwsMemberTest(true), 10);
252 }
253 catch(e:java.lang.Throwable)
254 {
255 }
235 } catch (e:java.lang.Throwable) {}
256236 }
257237
258238 // test 4: @:throws IOException and only use IOException
259 @:throws('java.io.IOException') function testThrows4()
260 {
239 @:throws('java.io.IOException') function testThrows4() {
261240 var b = new Base();
262241 eq(Base.throwsTest(), 5);
263242 eq(b.throwsMemberTest(true), 10);
264243 }
265244
266245 // test 5: @:throws IOException and use any
267 @:throws('java.io.IOException') function testThrows5()
268 {
246 @:throws('java.io.IOException') function testThrows5() {
269247 var b = new Base();
270248 eq(Base.throwsTest(), 5);
271249 eq(Base.throwsTest(42), 42);
273251 eq(b.throwsMemberTest(true), 10);
274252 }
275253
276 function testJavaLibEnum()
277 {
254 function testJavaLibEnum() {
278255 var e = TEnum.TA;
279 switch(e)
280 {
256 switch (e) {
281257 case TA:
282258 t(true);
283259 case _:
284260 t(false);
285261 }
286 eq("TA",Type.enumConstructor(e));
287 }
288
289 function testMiscJavaLib()
290 {
291 //setting inline should be an error
262 eq("TA", Type.enumConstructor(e));
263 }
264
265 function testMiscJavaLib() {
266 // setting inline should be an error
292267 t(HelperMacros.typeError(Base.inlineNumber = 4));
293268 }
294269
295 //TODO:
296 //overload with functions + variable types
297
298 }
299
300 private class TestMyClass extends haxe.test.MyClass
301 {
302 @:overload public function new()
303 {
270 // TODO:
271 // overload with functions + variable types
272
273 function testDefaultInterface() {
274 var c = new MyDefaultInterfaceClass();
275 eq("FOO", c.test("foo"));
276 }
277
278 function testDefaultSubInterface() {
279 var c = new MyDefaultSubInterfaceClass();
280 eq("FOO", c.test("foo"));
281 }
282 }
283
284 private class TestMyClass extends haxe.test.MyClass {
285 @:overload public function new() {
304286 super();
305287 }
306288
307 @:overload public function new(str:String)
308 {
289 @:overload public function new(str:String) {
309290 super();
310291 alternativeCtorCalled = true;
311292 }
317298 public var stringCalled:Bool;
318299 public var dynamicCalled:Bool;
319300
320 @:overload override public function normalOverload(b:Bool):Void
321 {
301 @:overload override public function normalOverload(b:Bool):Void {
322302 this.boolCalled = true;
323303 }
324304
325 @:overload override public function normalOverload(i:Int):Void
326 {
305 @:overload override public function normalOverload(i:Int):Void {
327306 this.intCalled = true;
328307 }
329308
330 @:overload override public function normalOverload(i64:haxe.Int64):Void
331 {
309 @:overload override public function normalOverload(i64:haxe.Int64):Void {
332310 this.int64Called = true;
333311 }
334312
335 @:overload override public function normalOverload(str:String):Void
336 {
313 @:overload override public function normalOverload(str:String):Void {
337314 this.stringCalled = true;
338315 }
339316
340 @:overload override public function normalOverload(dyn:Dynamic):Void
341 {
317 @:overload override public function normalOverload(dyn:Dynamic):Void {
342318 this.dynamicCalled = true;
343319 }
344320 }
345321
346 @:nativeGen private class NativeClass
347 {
348 public function new()
349 {
350
351 }
352
353 @:throws("java.lang.Throwable")
354 public function excTest():Void
355 {
356 throw new java.lang.Throwable("test", null);
357 }
358 }
359
360 private class HxClass extends NativeClass
361 {
362
363 @:throws("java.lang.Throwable")
364 override public function excTest():Void
365 {
366
367 }
322 @:nativeGen private class NativeClass {
323 public function new() {}
324
325 @:throws("java.lang.Throwable")
326 public function excTest():Void {
327 throw new java.lang.Throwable("test", null);
328 }
329 }
330
331 private class HxClass extends NativeClass {
332 @:throws("java.lang.Throwable")
333 override public function excTest():Void {}
368334 }
369335
370336 enum HaxeEnum {
373339 HC;
374340 }
375341
342 class MyDefaultInterfaceClass implements MyDefaultInterface {
343 public function new() {}
344 }
345
346 class MyDefaultSubInterfaceClass implements MyDefaultSubInterface {
347 public function new() {}
348 }
376349 #end
0 package unit;
1
2 class TestLocalStatic extends Test {
3 function basic() {
4 static var x = 1;
5 static final y = "final";
6 x++;
7 return {x: x, y: y};
8 }
9
10 function testBasic() {
11 var obj = basic();
12 eq(2, obj.x);
13 eq("final", obj.y);
14
15 obj = basic();
16 eq(3, obj.x);
17 eq("final", obj.y);
18 }
19 }
6969 parseAndPrint('(a, b) -> c');
7070 parseAndPrint('function(a) return b');
7171 parseAndPrint('function named(a) return b');
72 parseAndPrint('function named() {\n\tstatic final @Test a = 1, b = 2;\n\tstatic var c, d;\n\tfinal e = 2;\n\tvar f;\n}');
7273
7374 var p = new haxe.macro.Printer();
7475 // special handling of single arguments (don't add parentheses)
00 package unit;
11
2 import haxe.ds.List;
3 import unit.Test.*;
4 import utest.Runner;
25 import utest.ui.Report;
3 import utest.Runner;
4 import unit.Test.*;
5 import haxe.ds.List;
66
77 final asyncWaits = new Array<haxe.PosInfos>();
88 final asyncCache = new Array<() -> Void>();
2424 }
2525 #end
2626
27 var verbose = #if ( cpp || neko || php ) Sys.args().indexOf("-v") >= 0 #else false #end;
27 var verbose = #if (cpp || neko || php) Sys.args().indexOf("-v") >= 0 #else false #end;
2828
29 #if cs //"Turkey Test" - Issue #996
29 #if cs // "Turkey Test" - Issue #996
3030 cs.system.threading.Thread.CurrentThread.CurrentCulture = new cs.system.globalization.CultureInfo('tr-TR');
3131 cs.Lib.applyCultureChanges();
3232 #end
3333 #if neko
34 if( neko.Web.isModNeko )
35 neko.Web.setHeader("Content-Type","text/plain");
34 if (neko.Web.isModNeko)
35 neko.Web.setHeader("Content-Type", "text/plain");
3636 #elseif php
37 if( php.Web.isModNeko )
38 php.Web.setHeader("Content-Type","text/plain");
37 if (php.Web.isModNeko)
38 php.Web.setHeader("Content-Type", "text/plain");
3939 #end
4040 #if !macro
4141 trace("Generated at: " + HelperMacros.getCompilationDate());
4242 #end
4343 trace("START");
4444 #if flash
45 var tf : flash.text.TextField = untyped flash.Boot.getTrace();
45 var tf:flash.text.TextField = untyped flash.Boot.getTrace();
4646 tf.selectable = true;
4747 tf.mouseEnabled = true;
4848 #end
4949 var classes = [
5050 new TestOps(),
5151 new TestBasetypes(),
52 new TestNumericSuffixes(),
53 new TestNumericSeparator(),
5254 new TestExceptions(),
5355 new TestBytes(),
5456 new TestIO(),
5557 new TestLocals(),
58 new TestLocalStatic(),
5659 new TestEReg(),
5760 new TestXML(),
5861 new TestMisc(),
7477 new TestNumericCasts(),
7578 new TestHashMap(),
7679 new TestRest(),
77 #if (!no_http && (!github || !(php && Windows)))
78 new TestHttp(),
80 #if !no_http new TestHttp(),
7981 #end
8082 #if !no_pattern_matching
8183 new TestMatch(),
104106 new TestOverloadsForEveryone(),
105107 new TestInterface(),
106108 new TestNaN(),
107 #if ((dce == "full") && !interp)
108 new TestDCE(),
109 #if ((dce == "full") && !interp) new TestDCE(),
109110 #end
110111 new TestMapComprehension(),
111112 new TestMacro(),
112113 new TestKeyValueIterator(),
113114 new TestFieldVariance(),
114 new TestConstrainedMonomorphs()
115 //new TestUnspecified(),
115 new TestConstrainedMonomorphs(),
116 new TestDefaultTypeParameters(),
117 // new TestUnspecified(),
116118 ];
117119
118120 for (specClass in unit.UnitBuilder.generateSpec("src/unitstd")) {
130132 report.displaySuccessResults = NeverShowSuccessResults;
131133 var success = true;
132134 runner.onProgress.add(function(e) {
133 for(a in e.result.assertations) {
135 for (a in e.result.assertations) {
134136 switch a {
135137 case Success(pos):
136138 case Warning(msg):
137139 case Ignore(reason):
138 case _: success = false;
140 case _:
141 success = false;
139142 }
140143 }
141144 #if js
151154 });
152155 #end
153156 runner.run();
157
158 #if (flash && fdb)
159 flash.Lib.fscommand("quit");
160 #end
154161 }
135135 eq("foo", switchNormal(macro null.foo));
136136 eq("22", switchNormal(macro null[22]));
137137 eq("22.5", switchNormal(macro null[22.5]));
138 eq("EConst(CInt(0))", switchNormal(macro 1 in 0));
138 eq("EConst(CInt(0,null))", switchNormal(macro 1 in 0));
139139 eq("not_found", switchNormal(macro null["22"]));
140140
141141 t(null != switchCapture(macro "foobar"));
145145
146146 eq("[]", switchArray(macro []));
147147 eq("_", switchArray(macro 2));
148 eq("[EConst(CInt(22))]", switchArray(macro [22]));
149 eq("[EConst(CInt(22)),EConst(CString(foo,DoubleQuotes))]", switchArray(macro [22,"foo"]));
148 eq("[EConst(CInt(22,null))]", switchArray(macro [22]));
149 eq("[EConst(CInt(22,null)),EConst(CString(foo,DoubleQuotes))]", switchArray(macro [22,"foo"]));
150150 eq("_", switchArray(macro [22, "foo", "bar"]));
151151
152152 eq("0", switchArray2(["a", "b"]));
327327 eq("Héllow", haxe.crypto.Base64.decode("SMOpbGxvdw", false).toString());
328328 eq("Héllo", haxe.crypto.Base64.decode("SMOpbGxv").toString());
329329 eq("Héll", haxe.crypto.Base64.decode("SMOpbGw=").toString());
330 exc(() -> haxe.crypto.Base64.decode("invalid string"));
330331
331332 // alternative base64
332333 var b = new haxe.crypto.BaseCode(haxe.io.Bytes.ofString("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"));
0 package unit;
1
2 @:nullSafety(StrictThreaded)
3 class TestNullCoalescing extends Test {
4 final nullInt:Null<Int> = null;
5 final nullBool:Null<Bool> = null;
6 final nullString:Null<String> = null;
7
8 var count = 0;
9 function call() {
10 count++;
11 return "_";
12 }
13
14 function test() {
15 var a = call() ?? "default";
16 eq(count, 1);
17
18 eq(nullInt ?? nullInt, null);
19 eq(nullBool ?? nullBool, null);
20
21 final a:Dynamic = Std.random(0) + 1;
22 final b = Std.random(0) + 2;
23 eq(1 + a + 1 ?? 1 + b + 1, 3);
24
25 final nullableBool:Null<Bool> = false;
26 final testBool = nullBool ?? true;
27 final testNullBool = nullBool ?? nullableBool;
28 final s:Int = nullInt == null ? 2 : nullInt;
29 final s:Int = if (nullInt == null) 2; else nullInt;
30 final s = nullInt ?? 2;
31
32 // $type(testBool); // Bool
33 // $type(testNullBool); // Null<Bool>
34 // $type(s); // Int
35 final shouldBeBool:Bool = testBool;
36 if (testNullBool == null) {}
37 final shouldBeInt:Int = s;
38
39 eq(testBool, true);
40 eq(testNullBool, false);
41 eq(s, 2);
42
43 eq(nullInt == null ? 2 : nullInt, 2);
44 eq(nullInt ?? 2, 2);
45 eq(nullInt ?? (2 : Null<Int>) ?? 3 + 100, 2);
46 eq(nullInt ?? nullInt ?? 3, 3);
47
48 final i:Null<Int> = 1;
49 final arr:Array<Int> = [i ?? 2];
50 arr.push(i ?? 2);
51 arr.push((1 : Null<Int>) ?? 2);
52 eq(arr[0], 1);
53 eq(arr[1], 1);
54 eq(arr[2], 1);
55
56 final arr = [
57 nullInt ?? 2,
58 2
59 ];
60 eq(arr[0], arr[1]);
61
62 var a = [0 => nullInt ?? 0 + 100];
63 eq(a[0], 100);
64
65 final di:Null<Dynamic> = null;
66 final di2:Null<Dynamic> = null;
67 final di3:Null<Dynamic> = 2;
68 eq(di ?? di2 ?? di3, 2);
69
70 var a:Null<Int> = null;
71 a ??= 5;
72 eq(a, 5);
73 var a:Null<Int> = null;
74 eq(a ??= 5, 5);
75 eq(a, 5);
76 var a = "default";
77 eq(a ??= "5", "default");
78
79 count = 0;
80 var a = call();
81 eq(count, 1);
82 a ??= call();
83 eq(count, 1);
84
85 var a:Null<String> = null;
86 final b = a ??= call();
87 final c = a ??= call();
88 eq(count, 2);
89 eq(a, "_");
90 eq(b, "_");
91 eq(c, "_");
92
93 final a:Null<Int> = ({} : Dynamic).x;
94 eq(a ?? 2, 2);
95
96 final a = nullInt;
97 eq(a ?? 2, 2);
98
99 final a = nullString;
100 eq(a ?? "2", "2");
101
102 eq(1 ?? 2, 1);
103 eq("1" ?? "2", "1");
104
105 final arr = [];
106 function item(n) {
107 arr.push(n);
108 return n;
109 }
110 eq(item(1) ?? item(2) ?? item(3), 1);
111 eq(arr.length, 1);
112 for (i => v in [1]) eq(arr[i], v);
113
114 final arr = [];
115 function item(n) {
116 arr.push(n);
117 return null;
118 }
119 eq(item(1) ?? item(2) ?? item(3), null);
120 eq(arr.length, 3);
121 for (i => v in [1, 2, 3]) eq(arr[i], v);
122 }
123 }
0 package unit;
1
2 class TestNumericSeparator extends Test {
3 public function test() {
4 // normal int
5 eq(12_0, 120);
6 eq(1_2_0, 120);
7
8 // hex int
9 eq(0x12_0, 0x120);
10 eq(0x1_2_0, 0x120);
11
12 // normal float
13 feq(12.3_4, 12.34);
14 feq(1_2.34, 12.34);
15 feq(1_2.3_4, 12.34);
16
17 // dot float
18 feq(.3_4, .34);
19 feq(.3_4_5, .345);
20
21 // science float
22 feq(1_2e3_4, 12e34);
23 feq(1_2.3e4_5, 12.3e45);
24
25 // int but actually float
26 feq(1_2f64, 12f64);
27 }
28
29 public function testWithSuffix() {
30 // normal int
31 eq(12_0i32, 120i32);
32 eq(1_2_0i32, 120i32);
33
34 // hex int
35 eq(0x12_0i32, 0x120i32);
36 eq(0x1_2_0i32, 0x120i32);
37
38 // normal float
39 feq(12.3_4f64, 12.34f64);
40 feq(1_2.34f64, 12.34f64);
41 feq(1_2.3_4f64, 12.34f64);
42
43 // dot float
44 feq(.3_4f64, .34f64);
45 feq(.3_4_5f64, .345f64);
46
47 // science float
48 feq(1_2e3_4f64, 12e34f64);
49 feq(1_2.3e4_5f64, 12.3e45f64);
50 }
51
52 public function testJustBeforeSuffix() {
53 // normal int
54 eq(12_0_i32, 120i32);
55 eq(1_2_0_i32, 120i32);
56
57 // hex int
58 eq(0x12_0_i32, 0x120i32);
59 eq(0x1_2_0_i32, 0x120i32);
60
61 // normal float
62 feq(12.3_4_f64, 12.34f64);
63 feq(1_2.34_f64, 12.34f64);
64 feq(1_2.3_4_f64, 12.34f64);
65
66 // dot float
67 feq(.3_4_f64, .34f64);
68 feq(.3_4_5_f64, .345f64);
69
70 // science float
71 feq(1_2e3_4_f64, 12e34f64);
72 feq(1_2.3e4_5_f64, 12.3e45f64);
73 }
74 }
0 package unit;
1
2 class TestNumericSuffixes extends Test {
3
4 public function testIntSuffixes() {
5 eq(7i32, 7);
6 eq(-7i32, -7);
7 eq(-1u32, (-1 : UInt));
8 eq(3000000000000i64 + "", "3000000000000");
9 eq(9223372036854775807i64 + "", "9223372036854775807");
10 }
11
12 public function testFloatSuffixes() {
13 eq(7.0f64, 7.0);
14 eq(-7.0f64, -7.0);
15 eq(1f64 is Float, true);
16 eq(.0f64, 0.0);
17 eq(7e+0f64, 7e+0);
18 eq(7.0e+0f64, 7.0e+0);
19 }
20
21 public function testHexSuffixes() {
22 eq(0xFFFFFFFFi32, -1);
23 eq(0xFFFFFFFFu32, (0xFFFFFFFF : UInt));
24 eq(0xFFFFFFFFi64 + "", "4294967295");
25 eq(0xFFFFFFFFFFFFFFFFi64 + "", "-1");
26 eq(0x7FFFFFFFFFFFFFFFi64 + "", "9223372036854775807");
27 }
28 }
1919 function testToArray() {
2020 function rest(...r:Int):Array<Int> {
2121 var a = r.toArray();
22 a[0] = 999; //make sure array modification doesn't affect rest arguments object
22 a[0] = 999; // make sure array modification doesn't affect rest arguments object
2323 return r.toArray();
2424 }
2525 aeq([1, 2, 3, 4], rest(1, 2, 3, 4));
3535
3636 function testIterator() {
3737 function rest(...r:Int):Array<Int> {
38 return [for(i in r) i];
38 return [for (i in r) i];
3939 }
4040 aeq([3, 2, 1], rest(3, 2, 1));
4141 }
4444 function rest(...r:Int):{keys:Array<Int>, values:Array<Int>} {
4545 var keys = [];
4646 var values = [];
47 for(k => v in r) {
47 for (k => v in r) {
4848 keys.push(k);
4949 values.push(v);
5050 }
51 return {keys:keys, values:values}
51 return {keys: keys, values: values}
5252 }
5353 var r = rest(3, 2, 1, 0);
5454 aeq([0, 1, 2, 3], r.keys);
5656 }
5757
5858 @:depends(testToArray)
59 @:haxe.warning("-WGenerator")
5960 function testAppend() {
6061 function rest(...r:Int) {
6162 var appended = r.append(9);
62 return {initial:r.toArray(), appended:appended.toArray()}
63 return {initial: r.toArray(), appended: appended.toArray()}
6364 }
6465 var result = rest(1, 2);
6566 aeq([1, 2], result.initial);
6667 aeq([1, 2, 9], result.appended);
68 }
69
70 @:depends(testToArray)
71 function testPrepend() {
72 function rest(...r:Int) {
73 var prepended = r.prepend(9);
74 return {initial: r.toArray(), prepended: prepended.toArray()}
75 }
76 var result = rest(1, 2);
77 aeq([1, 2], result.initial);
78 aeq([9, 1, 2], result.prepended);
6779 }
6880
6981 @:depends(testToArray)
7991 aeq([1, 2, 3], new Parent(...[1, 2, 3]).ctorArgs.toArray());
8092 }
8193
82 @:depends(testToArray, testRestReturn)
94 @:depends(testToArray, testRestReturn, testAppend)
8395 function testInheritance() {
8496 var p = new Parent(1, 2, 3);
8597 var c = new Child(4, 5, 6);
100112
101113 @:depends(testToArray)
102114 function testClosure() {
103 var fn:(...r:Int)->Array<Int>;
115 var fn:(...r:Int) -> Array<Int>;
104116 fn = staticRest;
105117 aeq([1, 2, 3], fn(1, 2, 3));
106118 aeq([1, 2, 3], fn(...[1, 2, 3]));
108120 aeq([3, 2, 1], fn(3, 2, 1));
109121 aeq([3, 2, 1], fn(...[3, 2, 1]));
110122 }
123
111124 function instanceRest(...r:Int):Array<Int> {
112125 return r.toArray();
113126 }
127
114128 static function staticRest(...r:Int):Array<Int> {
115129 return r.toArray();
116130 }
128142 function rest(...r:{f:Int}) {
129143 return r.toArray();
130144 }
131 aeq([{f:2}, {f:1}], rest({f:2}, {f:1}));
145 aeq([{f: 2}, {f: 1}], rest({f: 2}, {f: 1}));
132146 }
133147
134148 function testInferred() {
135149 function rest(...r) {
136150 (r[0] : Int);
137151 }
138 HelperMacros.typedAs(rest, (null : (r : Rest<Int>)->Void));
152 HelperMacros.typedAs(rest, (null : (r:Rest<Int>) -> Void));
139153 }
140154
141155 function testToString() {
166180 override public function methodWithRest(rest:Rest<Int>):Rest<Int> {
167181 return super.methodWithRest(...rest.append(999));
168182 }
169 }
183 }
2424 import haxe.macro.Context;
2525 import haxe.macro.Expr;
2626 import haxe.macro.Type;
27
2728 using StringTools;
2829
2930 class UnitBuilder {
30
3131 static public macro function generateSpec(basePath:String) {
3232 var ret = [];
3333 var numFiles = 0;
4545 params: [],
4646 expr: read(filePath)
4747 }
48 var p = Context.makePosition( { min:0, max:0, file:filePath + file } );
48 var p = Context.makePosition({min: 0, max: 0, file: filePath + file});
4949 var field = {
5050 name: "test",
5151 kind: FFun(func),
5252 pos: p,
5353 access: [APublic],
5454 doc: null,
55 meta: []
55 meta: file.endsWith("Utf8.unit.hx") ? [{name: ":haxe.warning", params: [macro "-WDeprecated"], pos: p}] : []
5656 };
5757 var pack = ["unit", "spec"].concat(pack);
5858 var typeName = "Test" + file.substr(0, file.indexOf("."));
59 Context.defineModule(pack.join(".") + "." + typeName, [{
60 pack: pack,
61 name: typeName,
62 pos: p,
63 kind: TDClass({
64 pack: ["unit"],
65 name: "Test"
66 }),
67 fields: [field]
68 }], [{
69 path: [{pos: p, name: "unit"}, {pos: p, name: "spec"}, {pos: p, name: "TestSpecification"}],
70 mode: INormal
71 }, {
72 // TODO: import.hx doesn't work for this?
73 path: [{pos: p, name: "haxe"}, {pos: p, name: "macro"}, {pos: p, name: "Expr"}],
74 mode: INormal
75 }]);
59 Context.defineModule(pack.join(".") + "." + typeName, [
60 {
61 pack: pack,
62 name: typeName,
63 pos: p,
64 kind: TDClass({
65 pack: ["unit"],
66 name: "Test"
67 }),
68 fields: [field]
69 }
70 ], [
71 {
72 path: [
73 {pos: p, name: "unit"},
74 {pos: p, name: "spec"},
75 {pos: p, name: "TestSpecification"}
76 ],
77 mode: INormal
78 },
79 {
80 // TODO: import.hx doesn't work for this?
81 path: [{pos: p, name: "haxe"}, {pos: p, name: "macro"}, {pos: p, name: "Expr"}],
82 mode: INormal
83 }
84 ]);
7685 var tp:TypePath = {
7786 pack: pack,
7887 name: typeName
8089 ret.push(macro new $tp());
8190 } else if (sys.FileSystem.isDirectory(filePath)) {
8291 readDir(filePath, pack.concat([file]));
83 } else if(filePath.endsWith('.hx')) {
92 } else if (filePath.endsWith('.hx')) {
8493 Context.error('$filePath: specification tests filenames should end with ".unit.hx"', Context.currentPos());
8594 }
8695 }
92101
93102 #if macro
94103 static function collapseToOrExpr(el:Array<Expr>) {
95 return switch(el) {
104 return switch (el) {
96105 case []: throw "";
97106 case [e]: e;
98 case _:
99 var e = el.pop();
100 { expr: EBinop(OpBoolOr, e, collapseToOrExpr(el)), pos: e.pos }
107 case _:
108 var e = el.pop();
109 {expr: EBinop(OpBoolOr, e, collapseToOrExpr(el)), pos: e.pos}
101110 }
102111 }
103112
104113 static function mkEq(e1, e2, p:Position) {
105114 function isFloat(e) {
106 try return switch(Context.follow(Context.typeof(e))) {
107 case TAbstract(tr, _):
108 tr.get().name == "Float";
109 case _:
110 false;
111 } catch (e:Dynamic) {
115 try
116 return switch (Context.follow(Context.typeof(e))) {
117 case TAbstract(tr, _):
118 tr.get().name == "Float";
119 case _:
120 false;
121 } catch (e:Dynamic) {
112122 return false;
113123 }
114124 }
115125 var e = switch [isFloat(e1) || isFloat(e2), e2.expr] {
116 case [_, EField( { expr:EConst(CIdent("Math" | "math")) }, "POSITIVE_INFINITY" | "NEGATIVE_INFINITY")] if (Context.defined("cpp") || Context.defined("php")):
126 case [
127 _,
128 EField({expr: EConst(CIdent("Math" | "math"))}, "POSITIVE_INFINITY" | "NEGATIVE_INFINITY")
129 ] if (Context.defined("cpp") || Context.defined("php")):
117130 macro t($e1 == $e2);
118131 case [true, _]:
119132 macro feq($e1, $e2);
125138 pos: p
126139 }
127140 }
141
128142 static public function read(path:String) {
129 var p = Context.makePosition( { min:0, max:0, file:path } );
143 var p = Context.makePosition({min: 0, max: 0, file: path});
130144 var file = sys.io.File.getContent(path);
131145 var code = Context.parseInlineString("{" + file + "\n}", p);
132146 function mkBlock(e:Expr) {
133 return switch(e.expr) {
147 return switch (e.expr) {
134148 case EBlock(b): b;
135149 case _: [e];
136150 }
138152 function bl(block:Array<Expr>):Array<Expr> {
139153 var ret = [];
140154 for (e in block) {
141 var e = switch(e.expr) {
142 case EBinop(OpEq, e1, { expr: EConst(CIdent("false")) } )
143 | EBinop(OpEq, { expr: EConst(CIdent("false")) }, e1):
155 var e = switch (e.expr) {
156 case EBinop(OpEq, e1, {expr: EConst(CIdent("false"))}) | EBinop(OpEq, {expr: EConst(CIdent("false"))}, e1):
144157 {
145158 expr: (macro f($e1)).expr,
146159 pos: e.pos
147160 }
148 case EBinop(OpEq, e1, { expr: EConst(CIdent("true")) } )
149 | EBinop(OpEq, { expr: EConst(CIdent("true")) }, e1):
161 case EBinop(OpEq, e1, {expr: EConst(CIdent("true"))}) | EBinop(OpEq, {expr: EConst(CIdent("true"))}, e1):
150162 {
151163 expr: (macro t($e1)).expr,
152164 pos: e.pos
153165 }
154 case EBinop(OpEq, e1, { expr: EArrayDecl(el) } )
155 | EBinop(OpEq, { expr: EArrayDecl(el) }, e1 ):
166 case EBinop(OpEq, e1, {expr: EArrayDecl(el)}) | EBinop(OpEq, {expr: EArrayDecl(el)}, e1):
156167 var el2 = [];
157168 for (i in 0...el.length) {
158169 var e2 = el[i];
159170 el2.push(mkEq((macro $e1[$v{i}]), e2, e.pos));
160171 }
161 if (el2.length == 0)
162 mkEq((macro @:pos(e1.pos) $e1.length), (macro 0), e.pos);
163 else
164 macro { $a{el2}; };
172 if (el2.length == 0) mkEq((macro @:pos(e1.pos) $e1.length), (macro 0), e.pos); else macro {$a{el2};};
165173 case EBinop(OpEq, e1, e2):
166174 mkEq(e1, e2, e.pos);
167175 case EBinop(OpNotEq, e1, e2):
173181 }
174182 case EThrow(e):
175183 macro exc(function() $e);
176 case EBinop(OpIn, e1, {expr:EArrayDecl(el) }):
184 case EBinop(OpIn, e1, {expr: EArrayDecl(el)}):
177185 var el2 = [];
178186 for (e in el)
179187 el2.push(macro $e1 == $e);
180 macro @:pos(e.pos) t(${ collapseToOrExpr(el2) } );
188 macro @:pos(e.pos) t(${collapseToOrExpr(el2)});
181189 case EVars(vl):
182190 for (v in vl)
183191 if (v.name == "t" || v.name == "f" || v.name == "eq" || v.name == "neq")
184192 Context.error('${v.name} is reserved for unit testing', e.pos);
185 e;
193 e;
186194 case EFor(it, {expr: EBlock(el), pos: p}):
187 { expr: EFor(it, {expr:EBlock(bl(el)), pos: p}), pos: e.pos };
195 {expr: EFor(it, {expr: EBlock(bl(el)), pos: p}), pos: e.pos};
188196 case _:
189197 e;
190198 }
196204 return macro $b{bl(block)};
197205 }
198206 #end
199 }
207 }
0 package unit.issues;
1
2 private abstract Foo(Array<String>) from Array<String> {
3 @:op(_ += _) inline function add(string:String)
4 this.push(string);
5 }
6
7 class Issue10066 extends unit.Test {
8 function testExpr() {
9 var a = [];
10 var foo:Foo = a;
11 foo += (1 == 2 ? 'two' : 'three');
12 eq("three", a[0]);
13 }
14
15 static var staticFoo:Foo;
16
17 function testField() {
18 var a = [];
19 staticFoo = a;
20 staticFoo += (1 == 2 ? 'two' : 'three');
21 eq("three", a[0]);
22 }
23 }
00 package unit.issues;
11
22 private abstract Foo(Array<Int>) from Array<Int> {
3 @:op([])
4 function get(index: Int): Int;
3 @:op([])
4 function get(index:Int):Int;
55
6 @:op([])
7 function set(index: Int, value: Int): Void;
6 @:op([])
7 function set(index:Int, value:Int):Void;
88 }
99
1010 #if eval
1111 abstract Bar(Int) from Int {
12 @:op(_ + _)
13 extern function add(other: Int): Int;
12 @:op(_ + _)
13 extern function add(other:Int):Int;
1414
15 @:op([])
16 extern function get(index: Int): Int;
15 @:op([])
16 extern function get(index:Int):Int;
1717
18 @:native('add')
19 function doAdd(other: Int): Int
20 return 39;
18 @:native('add')
19 function doAdd(other:Int):Int
20 return 39;
2121
22 @:native('get')
23 function doGet(index: Int)
24 return (this + index) * 2;
22 @:native('get')
23 function doGet(index:Int)
24 return (this + index) * 2;
2525 }
2626 #end
2727
28 @:haxe.warning("-WGenerator")
2829 class Issue10073 extends Test {
29 function test() {
30 var foo: Foo = [];
31 foo[0] = 3;
32 eq(3, foo[0]);
30 function test() {
31 var foo:Foo = [];
32 foo[0] = 3;
33 eq(3, foo[0]);
3334
34 #if eval
35 var bar: Bar = 71;
36 eq(39, bar + 1);
37 eq(144, bar[1]);
38 #end
39 }
35 #if eval
36 var bar:Bar = 71;
37 eq(39, bar + 1);
38 eq(144, bar[1]);
39 #end
40 }
4041 }
44 using unit.issues.Issue10124.Util;
55
66 private class Util {
7 public static inline function add<T>(arr:Array<T>,...values:T) {
7 public static inline function add<T>(arr:Array<T>, ...values:T) {
88 for (v in values)
99 arr.push(v);
1010 }
1111
12 public static inline function addFloat<T>(arr:Array<Any>,...values:Float) {
12 public static inline function addFloat<T>(arr:Array<Any>, ...values:Float) {
1313 for (v in values)
1414 arr.push(v);
1515 }
0 package unit.issues;
1
2 @:allow(unit.issues.Issue10127)
3 class Issue10127 extends Test {
4 static final privateField = true;
5
6 function test() {
7 accessible();
8 noAssert();
9 }
10 }
11
12 function accessible() {
13 Issue10127.privateField;
14 }
0 package unit.issues;
1
2 class Issue10135 extends Test {
3 function doEncode() {
4 var w = 0;
5
6 var i = 0;
7 while (Math.random() > 0.5) {
8 while (i < 80) {
9 w = 1;
10 }
11 }
12 }
13
14 function test() {
15 utest.Assert.pass();
16 }
17 }
0 package unit.issues;
1
2 import utest.Assert;
3
4 private abstract class A { // This class has uninitialized final vars, which requires a constructor
5 public final x:Int; // Example of an uninitialized final var
6 }
7
8 private class B extends A {
9 public function new() {
10 x = 10; // Cannot access field or identifier x for writing
11 }
12 }
13
14 class Issue10139 extends Test {
15 function test() {
16 eq(10, new B().x);
17 }
18 }
0 package unit.issues;
1
2 private enum FooBar {
3 Foo;
4 Bar(value: Any);
5 }
6
7 class Issue10148 extends Test {
8 function test() {
9 var bar: FooBar = Bar(0);
10 var matched = switch (bar) {
11 case Bar(0): true;
12 case _: false;
13 }
14 eq(true, matched);
15 }
16 }
0 package unit.issues;
1
2 class Issue10205 extends unit.Test {
3 function test() {
4 eq("no rest foo", over("foo"));
5 eq("rest foo bar", over("foo", "bar"));
6 }
7
8 overload extern static inline function over(s:String) {
9 return "no rest " + s;
10 }
11
12 overload extern static inline function over(s:String, ...r:String) {
13 return "rest " + s + " " + r.toArray().join(" ");
14 }
15 }
0 package unit.issues;
1
2 class Issue10209 extends Test {
3 function test() {
4 var s:AStr = 'hello';
5 s += ', world';
6 eq('hello, world', s);
7 }
8 }
9
10 private abstract AStr(String) from String to String {
11 @:op(A += B) @:commutative static function assignAdd(a:AStr, b:String):AStr;
12 }
0 package unit.issues;
1
2 import haxe.ds.Option;
3
4 class Issue10291 extends Test {
5 function test() {
6 eq("Case 2: b=null", match());
7 }
8
9 function match() {
10 var ret = "";
11 var o = Some({b: null});
12 switch (o) {
13 case Some({b: b}) if (b != null):
14 ret = "Case 1: b=" + b;
15 case Some({b: null}):
16 ret = "Case 2: b=null";
17 case Some(_):
18 ret = "Case 3: Some(_)";
19 case None:
20 ret = ("Default");
21 }
22 return ret;
23 }
24 }
0 package unit.issues;
1
2 import utest.Assert;
3
4 private class PairIter<T> {
5 var data:Array<T>;
6 var x = 0;
7 var prev:T;
8 var cur:T;
9
10 public inline function new(data:Array<T>) {
11 this.data = data;
12 }
13
14 public inline function hasNext() {
15 return x < data.length;
16 }
17
18 public inline function next() {
19 prev = cur;
20 cur = data[x++];
21 return {prev: prev, cur: cur};
22 }
23 }
24
25 class Issue10304 extends Test {
26 @:haxe.warning("-WConstructorInliningCancelled")
27 function test() {
28 var buf = new StringBuf();
29 for (p in new PairIter(["1", "2", "3"])) {
30 buf.add('${p.prev} ${p.cur} ');
31 }
32 eq("null 1 1 2 2 3 ", buf.toString());
33 }
34 }
0 package unit.issues;
1
2 private abstract JurajFunc<T>(T->Unit) {
3 @:from
4 public static function fromFuncReturningSameType<T>(f:T->T):JurajFunc<T> {
5 throw 'irrelevant';
6 }
7 }
8
9 private abstract KevinFunc<T>(T->Unit) from T->Unit to T->Unit {
10 @:from
11 public static function fromFuncReturningSameType<T>(f:T->T):KevinFunc<T> {
12 throw 'irrelevant';
13 }
14 }
15
16 private class Unit {}
17
18 private abstract Callback<T>(T->Void) from(T -> Void) {
19 @:from static function ofSingle<A>(cb:A->Void):Callback<A>
20 return null;
21
22 @:from static function fromMany<A>(callbacks:Array<Callback<A>>):Callback<A>
23 throw 0;
24 }
25
26 private abstract Foo(Dynamic) {
27 public var value(get, never):Int;
28
29 inline function get_value()
30 return 1;
31 }
32
33 class Issue10336 extends Test {
34 function testJuraj() {
35 var value = 'foo';
36 exc(() -> {
37 var f:JurajFunc<String> = function(v:String) return value = v;
38 });
39 }
40
41 function testKevin() {
42 var value = 'foo';
43 exc(() -> {
44 var f:KevinFunc<String> = function(v:String) return value = v;
45 });
46 }
47
48 function testJurajReloaded() {
49 var cb:Callback<String> = foo -> trace(foo.length);
50 var cb:Callback<Foo> = foo -> trace(foo.value);
51 utest.Assert.pass();
52 }
53 }
0 package unit.issues;
1
2 class Issue10383 extends Test {
3 function test() {
4 exec();
5 utest.Assert.pass();
6 }
7
8 static inline function exec():{a:Int, ?b:String, ?c:String} {
9 if (Math.random() > 0.5) {
10 return {a: 0, b: ""};
11 }
12 return {a: 0, c: ""};
13 }
14 }
0 package unit.issues;
1
2 import utest.Assert.*;
3
4 #if jvm
5 @:meta(java.lang.annotation.Documented())
6 private class NotMain {
7 static public function gather() {
8 final main = new NotMain();
9
10 final cls = java.Lib.getNativeType(main);
11
12 final classAnnotations = [];
13 final methods = new Map();
14 final fieldAnnotations = [];
15
16 for (an in cls.getAnnotations())
17 classAnnotations.push(an.toString());
18
19 for (f in cls.getMethods()) {
20 final methodAnnotations = [];
21 final methodArgAnnotations = new Map();
22 for (an in f.getAnnotations())
23 methodAnnotations.push(an.toString());
24
25 for (arg in f.getParameters()) {
26 var annots = [];
27 for (an in arg.getAnnotations()) {
28 annots.push(an.toString());
29 }
30 methodArgAnnotations[arg.getName()] = annots;
31 }
32 methods[f.getName()] = {methodAnnotations: methodAnnotations, methodArgAnnotations: methodArgAnnotations};
33 }
34
35 for (f in cls.getConstructors()) {
36 final methodAnnotations = [];
37 final methodArgAnnotations = new Map();
38 for (an in f.getAnnotations())
39 methodAnnotations.push(an.toString());
40
41 for (arg in f.getParameters()) {
42 var annots = [];
43 for (an in arg.getAnnotations()) {
44 annots.push(an.toString());
45 }
46 methodArgAnnotations[arg.getName()] = annots;
47 }
48 methods[f.toString()] = {methodAnnotations: methodAnnotations, methodArgAnnotations: methodArgAnnotations};
49 }
50
51 for (f in cls.getFields())
52 if (f.getName() == 'member') {
53 for (an in f.getAnnotations())
54 fieldAnnotations.push(an.toString());
55 }
56
57 return {
58 classAnnotations: classAnnotations,
59 methods: methods,
60 fieldAnnotations: fieldAnnotations
61 }
62 }
63
64 @:meta(java.lang.annotation.Documented())
65 @:keep
66 public overload function new(@:meta(java.lang.annotation.Documented()) arg0:String, @:meta(java.lang.annotation.Documented()) arg1:String) {}
67
68 overload function new() {}
69
70 @:meta(java.lang.annotation.Documented())
71 @:keep var member:String;
72
73 @:meta(java.lang.annotation.Documented())
74 @:keep
75 public function on0(@:meta(java.lang.annotation.Documented()) arg0:String):String {
76 return 'foo';
77 }
78
79 @:keep
80 public function on1(arg0:String, @:meta(java.lang.annotation.Documented()) arg1:String):String {
81 return 'foo';
82 }
83
84 @:meta(java.lang.annotation.Documented())
85 @:keep
86 public function onBoth(@:meta(java.lang.annotation.Documented()) arg0:String, @:meta(java.lang.annotation.Documented()) arg1:String):String {
87 return 'foo';
88 }
89
90 @:meta(java.lang.annotation.Documented())
91 @:keep
92 public function on0Static(@:meta(java.lang.annotation.Documented()) arg0:String):String {
93 return 'foo';
94 }
95
96 @:keep
97 public function on1Static(arg0:String, @:meta(java.lang.annotation.Documented()) arg1:String):String {
98 return 'foo';
99 }
100
101 @:meta(java.lang.annotation.Documented())
102 @:keep
103 public function onBothStatic(@:meta(java.lang.annotation.Documented()) arg0:String, @:meta(java.lang.annotation.Documented()) arg1:String):String {
104 return 'foo';
105 }
106 }
107 #end
108
109 class Issue10397 extends unit.Test {
110 #if jvm
111 function test() {
112 var annots = NotMain.gather();
113 same([
114 "@java.lang.annotation.Documented()",
115 "@haxe.jvm.annotation.ClassReflectionInformation(hasSuperClass=false)"
116 ], annots.classAnnotations);
117 same({
118 methodAnnotations: ["@java.lang.annotation.Documented()"],
119 methodArgAnnotations: ["arg0" => ["@java.lang.annotation.Documented()"]],
120 }, annots.methods["on0"]);
121 same({
122 methodAnnotations: [],
123 methodArgAnnotations: ["arg0" => [], "arg1" => ["@java.lang.annotation.Documented()"]],
124 }, annots.methods["on1"]);
125 same({
126 methodAnnotations: ["@java.lang.annotation.Documented()"],
127 methodArgAnnotations: [
128 "arg0" => ["@java.lang.annotation.Documented()"],
129 "arg1" => ["@java.lang.annotation.Documented()"]
130 ],
131 }, annots.methods["onBoth"]);
132 same({
133 methodAnnotations: ["@java.lang.annotation.Documented()"],
134 methodArgAnnotations: ["arg0" => ["@java.lang.annotation.Documented()"]],
135 }, annots.methods["on0Static"]);
136 same({
137 methodAnnotations: [],
138 methodArgAnnotations: ["arg0" => [], "arg1" => ["@java.lang.annotation.Documented()"]],
139 }, annots.methods["on1Static"]);
140 same({
141 methodAnnotations: ["@java.lang.annotation.Documented()"],
142 methodArgAnnotations: [
143 "arg0" => ["@java.lang.annotation.Documented()"],
144 "arg1" => ["@java.lang.annotation.Documented()"]
145 ],
146 }, annots.methods["onBothStatic"]);
147 same({
148 methodAnnotations: ["@java.lang.annotation.Documented()"],
149 methodArgAnnotations: [
150 "arg0" => ["@java.lang.annotation.Documented()"],
151 "arg1" => ["@java.lang.annotation.Documented()"]
152 ],
153 },
154 annots.methods["public unit.issues.Issue10397$NotMain(java.lang.String,java.lang.String)"]);
155 same(["@java.lang.annotation.Documented()"], annots.fieldAnnotations);
156 }
157 #end
158 }
0 package unit.issues;
1
2 class Issue10410 extends Test {
3 #if js
4 function test() {
5 var n = cast("5", String); // including this to add the code due to DCE, otherwise remove this if no DCE
6 var fields = [];
7 js.Syntax.code("for (var s in {0}) {1}.push(s)", n, fields);
8 f(fields.contains('__class__'));
9 }
10 #end
11 }
0 package unit.issues;
1
2 class Issue10455 extends Test {
3 function test() {
4 var a = [0 => true ? 1 : 0];
5 eq(1, a[0]);
6 }
7 }
0 package unit.issues;
1
2 import haxe.SysTools;
3
4 class Issue10468 extends Test {
5 function test() {
6 eq('"some/path"', SysTools.quoteWinArg('some/path', false));
7 eq('/S', SysTools.quoteWinArg('/S', false));
8 }
9 }
0 package unit.issues;
1
2 class Issue10482 extends Test {
3 function test() {
4 final ab = new MyAbstract(1);
5 final arr = ab.foo();
6 eq('plus 2', arr[0]);
7 eq("call", arr[1]);
8 eq("hi", arr[2]);
9
10 eq(1, ab.arr()[0].arr()[0].value());
11 eq("plus 3", ab + 3);
12 eq("call", ab());
13 eq("hi", ab.arr()[0].hi());
14
15 final ab = new MyInlineAbstract(1);
16 final arr = ab.foo();
17 eq('plus 2', arr[0]);
18 eq("call", arr[1]);
19 eq("hi", arr[2]);
20
21 eq(1, ab.arr()[0].arr()[0].value());
22 eq("plus 3", ab + 3);
23 eq("call", ab());
24 eq("hi", ab.arr()[0].hi());
25
26 final ab = new AbGeneric(1.5);
27 eq(1.5, ab.foo());
28 }
29 }
30
31 abstract MyAbstract(Int) {
32 public function new(a):Void this = a;
33
34 public function foo():Array<String> {
35 return [
36 abstract + 2,
37 abstract(),
38 abstract.hi()
39 ];
40 }
41
42 public function hi() return "hi";
43
44 public function arr() return [abstract];
45
46 @:op(a()) function call() return "call";
47
48 @:op(a + b) function plus(b) return 'plus $b';
49
50 public function value():Int return this;
51 }
52
53 abstract MyInlineAbstract(Int) {
54 public inline function new(a):Void this = a;
55
56 public inline function foo():Array<String> {
57 return [
58 abstract + 2,
59 abstract(),
60 abstract.hi()
61 ];
62 }
63
64 public function hi() return "hi";
65
66 public function arr() return [abstract];
67
68 @:op(a()) function call() return "call";
69
70 @:op(a + b) function plus(b) return 'plus $b';
71
72 public function value():Int return this;
73 }
74
75 abstract AbGeneric<T>(T) {
76 public function new(a:T):Void {
77 this = a;
78 }
79 public function foo() {
80 return abstract.bar();
81 }
82 public function bar() {
83 return this;
84 }
85 }
0 package unit.issues;
1
2 class Issue10508 extends Test {
3 #if java
4 function test() {
5 t(java.math.RoundingMode.getConstructors().length > 0);
6 t(java.math.RoundingMode.createAll().length > 0);
7 }
8 #end
9 }
0 package unit.issues;
1
2 class Issue10535 extends Test {
3 #if hl
4 function foo<T>(a:Array<T>) {}
5
6 function test() {
7 var x:hl.F32 = 10.0;
8 foo([x]);
9 utest.Assert.pass();
10 }
11 #end
12 }
0 package unit.issues;
1
2 import haxe.macro.Context;
3
4 class Issue10537 extends Test {
5 macro static function m() {
6 var imports = [
7 "haxe.ds.StringMap",
8 "StringTools.endsWith",
9 "StringTools.*",
10 "StringTools.startsWith as sw"
11 ];
12 var usings = ["StringTools"];
13 Context.withImports(imports, usings, () -> {
14 Context.typeExpr(macro {
15 StringMap;
16 endsWith("foo", "o");
17 startsWith("foo", "o");
18 sw("foo", "f");
19 "foo".endsWith("o");
20 });
21 });
22
23 // nested
24 Context.withImports(["haxe.ds.StringMap"], [], () -> {
25 Context.withImports(["StringTools.endsWith"], [], () -> {
26 Context.typeExpr(macro {
27 StringMap;
28 endsWith("foo", "o");
29 });
30 });
31 });
32 return macro null;
33 }
34
35 function test() {
36 m();
37 utest.Assert.pass();
38 }
39 }
0 package unit.issues;
1
2 @:publicFields
3 private abstract Foo(Int) from Int {
4 static function make(f:Float) {
5 return Std.int(f);
6 }
7 }
8
9 class Issue10541 extends Test {
10 function test() {
11 eq(1, Foo.make(1.2));
12 }
13 }
0 package unit.issues;
1
2 @:structInit @:publicFields
3 private class Tuple2<T, U> {
4 final _1:T;
5 final _2:U;
6
7 inline function new(_1:T, _2:U) {
8 this._1 = _1;
9 this._2 = _2;
10 }
11 }
12
13 @:generic
14 @:structInit @:publicFields
15 private class Tuple2Generic<T, U> {
16 final _1:T;
17 final _2:U;
18
19 inline function new(_1:T, _2:U) {
20 this._1 = _1;
21 this._2 = _2;
22 }
23 }
24
25 class Issue10550 extends Test {
26 function test() {
27 final foo:Tuple2<Int, String> = {_1: 1, _2: "abc"}; // works
28 final bar:Tuple2Generic<Int, String> = {_1: 1, _2: "abc"}; // doesn't work
29 utest.Assert.pass();
30 }
31 }
0 package unit.issues;
1
2 class Issue10561 extends Test {
3 function test() {
4 eq(null, getNull() ?.length);
5 }
6
7 function getNull():String {
8 return null;
9 }
10 }
0 package unit.issues;
1
2 private abstract MapProxy<K, V>(Dynamic) {
3 @:from static function fromMap<K, V>(map:Map<K, V>):MapProxy<K, V> {
4 return null;
5 }
6 }
7
8 private class Foo {}
9 private abstract ReactTypeOf<T:{}>(Foo) to Foo {}
10
11 @:forward
12 private abstract ReactContext<T>(IReactContext<T>) from IReactContext<T> to IReactContext<T> {
13 public function new() {
14 this = new Context();
15 }
16
17 @:to
18 public function toReactType<T1:{children:T->String}>():ReactTypeOf<T1> {
19 return cast this;
20 }
21 }
22
23 private interface IReactContext<T> {
24 var Consumer:ReactContext<T>;
25 }
26
27 private class Context<T> implements IReactContext<T> {
28 public var Consumer = null;
29
30 public function new() {}
31 }
32
33 private typedef Bar = {
34 children:{foo:String}->String
35 }
36
37 class Issue10565 extends Test {
38 function test() {
39 var m:MapProxy<String, Int> = new Map();
40 utest.Assert.pass();
41 }
42
43 public static var Consumer:ReactTypeOf<Bar>;
44
45 function testReactMess() {
46 var context = createContext();
47 Consumer = context.Consumer;
48 utest.Assert.pass();
49 }
50
51 public static function createContext<TContext>():ReactContext<TContext> {
52 return new ReactContext();
53 }
54 }
0 package unit.issues;
1
2 private abstract A(String) {
3 var selected(get, set):Dynamic;
4
5 public function get_selected() {
6 return null;
7 }
8
9 public function set_selected(v) {
10 return null;
11 }
12
13 public function new() {
14 this = "";
15 }
16 }
17
18 private class C {
19 var selected(get, set):Dynamic;
20
21 public function get_selected() {
22 return null;
23 }
24
25 public function set_selected(v) {
26 return null;
27 }
28
29 public function new() {}
30 }
31
32 class Issue10568 extends Test {
33 static var selected(get, set):Dynamic;
34
35 static public function get_selected() {
36 return null;
37 }
38
39 static public function set_selected(v) {
40 return null;
41 }
42
43 function test() {
44 HelperMacros.typedAs(get_selected, (null : () -> Dynamic));
45 HelperMacros.typedAs(set_selected, (null : (v:Dynamic) -> Dynamic));
46
47 var c = new C();
48 HelperMacros.typedAs(c.get_selected, (null : () -> Dynamic));
49 HelperMacros.typedAs(c.set_selected, (null : (v:Dynamic) -> Dynamic));
50
51 var a = new A();
52 HelperMacros.typedAs(a.get_selected, (null : () -> Dynamic));
53 HelperMacros.typedAs(a.set_selected, (null : (v:Dynamic) -> Dynamic));
54 }
55 }
0 package unit.issues;
1
2 class Issue10571 extends Test {
3 #if java
4 function test() {
5 eq("test()", foo());
6 eq("test(I)", foo(1));
7 }
8
9 overload static function foo() {
10 function x() {
11 return "test()";
12 }
13 return x();
14 }
15
16 overload static function foo(i:Int) {
17 function x() {
18 return "test(I)";
19 }
20 return x();
21 }
22 #end
23 }
0 package unit.issues;
1
2 class Issue10600 extends Test {
3 function test() {
4 var x = {
5 "checkstyle.checks.Checker": ["CheckBase", "UnusedImportCheck"]
6 };
7 var a = Reflect.field(x, "checkstyle.checks.Checker");
8 eq("CheckBase", a[0]);
9 eq("UnusedImportCheck", a[1]);
10 }
11 }
0 package unit.issues;
1
2 private abstract Promise<T>(Dynamic) {
3 @:from static inline function ofData<T>(d:T):Promise<T>
4 throw 0;
5 }
6
7 @:callable
8 private abstract Next<In, Out>(In->Promise<Out>) from In->Promise<Out> to In->Promise<Out> {
9 @:from static function ofSafeSync<In, Out>(f:In->Out):Next<In, Out>
10 return x -> f(x); // error: Recursive implicit cast
11 }
12
13 class Issue10604 extends Test {
14 function test() {
15 utest.Assert.pass();
16 }
17 }
0 package unit.issues;
1
2 #if java
3 @:keep
4 private class NotMain implements java.util.Iterator<String> {
5 static function main() {}
6
7 public function hasNext():Bool
8 throw 0;
9
10 public function next():String
11 throw 0;
12 }
13 #end
14
15 class Issue10618 extends unit.Test {
16 public function test() {
17 utest.Assert.pass();
18 }
19 }
0 package unit.issues;
1
2 class Issue10624 extends unit.Test {
3 static final RANDOM:Int = 33;
4
5 public function test() {
6 var v = switch (33) {
7 case 1:
8 "no";
9 case RANDOM:
10 "yes";
11 default:
12 "noooo";
13 }
14 eq("yes", v);
15 }
16 }
0 package unit.issues;
1
2 macro function foo() {
3 var s = try {
4 haxe.macro.Context.typeExpr(macro var x:Void);
5 "no exception";
6 } catch (e) {
7 "an exception";
8 }
9 return macro $v{s};
10 }
11
12 class Issue10626 extends unit.Test {
13 function test() {
14 eq("an exception", foo());
15 }
16 }
0 package unit.issues;
1
2 private abstract A(Int) from Int {
3 @:op(A++)
4 function preInc():Void;
5
6 @:op(++A)
7 function postInc():Void;
8 }
9
10 macro function check() {
11 #if macro
12 final type = haxe.macro.ComplexTypeTools.toType(TPath({
13 pack: ["unit", "issues"],
14 name: "Issue10641",
15 sub: "A"
16 }));
17 var acc = [];
18 function add(s:String) {
19 acc.push(s);
20 }
21 switch type {
22 case TAbstract(_.get() => t, params):
23 final unop = t.unops[0];
24 for (unop in t.unops) {
25 add("" + unop.op);
26 add("" + unop.postFix);
27 add(unop.field.name);
28 }
29 case _:
30 }
31 return macro $v{acc.join(" ")};
32 #end
33 }
34
35 class Issue10641 extends unit.Test {
36 public function test() {
37 eq("OpIncrement true preInc OpIncrement false postInc", check());
38 }
39 }
0 package unit.issues;
1
2 class Issue10684 extends unit.Test {
3 function test() {
4 eq("1", makeMapF()([1 => "1", 2 => "2"]));
5 }
6
7 function makeMapF(?f:Map<Int, String>->String) {
8 return f ?? v -> v[1];
9 }
10 }
0 package unit.issues;
1
2 @:structInit
3 private abstract class A {
4 public final x:Int;
5 }
6
7 @:structInit
8 private class B extends A {
9 public var y:Int;
10 }
11
12 class Issue10685 extends Test {
13 function test() {
14 var b:B = {x: 1, y: 2};
15 eq(1, b.x);
16 eq(2, b.y);
17 }
18 }
0 package unit.issues;
1
2 class Issue10709 extends unit.Test {
3 function test() {
4 eq("null", Std.string(foo()));
5 }
6
7 static function foo():Null<Map<String, String>> {
8 return null;
9 }
10 }
0 package unit.issues;
1
2 import haxe.extern.EitherType;
3
4 private typedef PrepareRenameResult = EitherType<Range, EitherType<RangePlaceholder, DefaultBehaviour>>;
5
6 private typedef Range = {
7 var start:Position;
8 var end:Position;
9 }
10
11 private typedef RangePlaceholder = {
12 var range:Range;
13 var placeholder:String;
14 }
15
16 private typedef DefaultBehaviour = {
17 var defaultBehavior:Bool;
18 }
19
20 private typedef Position = {
21 var line:Int;
22 var character:Int;
23 }
24
25 class Issue10712 extends unit.Test {
26 function test() {
27 var pos:Position = {line: 1, character: 10};
28 var range:Range = {start: pos, end: pos};
29
30 var result:PrepareRenameResult = {range: range, placeholder: "Haxe"};
31 result = range;
32 result = {defaultBehavior: true};
33
34 test2({range: range, placeholder: "Haxe"});
35 test2(range);
36 test2({defaultBehavior: true});
37
38 test2(cast {range: range, placeholder: "Haxe"});
39 test2(range);
40 test2(cast {defaultBehavior: true});
41
42 utest.Assert.pass();
43 }
44
45 static function test2(param:PrepareRenameResult) {}
46 }
0 package unit.issues;
1
2 using unit.issues.Issue10716.Extension;
3
4 private class Extension {
5 macro public static function test(x:ExprOf<Int>)
6 return macro $x + $v{1};
7 }
8
9 class Issue10716 extends unit.Test {
10 function test() {
11 #if !macro
12 eq(11, 10.test());
13 #end
14
15 utest.Assert.pass();
16 }
17 }
18
19 function test()
20 return 1;
0 package unit.issues;
1
2 class Issue10720 extends unit.Test {
3 function test() {
4 eq(1, switcheroo("😀 😀"));
5 eq(2, switcheroo("名 字"));
6 }
7
8 function switcheroo(x:String) {
9 return switch (x) {
10 case '😀 😀':
11 1;
12 case '名 字':
13 2;
14 case _:
15 0;
16 }
17 }
18 }
0 package unit.issues;
1
2 class Issue10728 extends Test {
3 function test(){
4 eq("String", m());
5 }
6
7 static macro function m() {
8 var mono = haxe.macro.Context.makeMonomorph();
9 var td = switch (haxe.macro.Context.getType("B")) {
10 case TType(td, _): td;
11 case _: throw "assert";
12 };
13 haxe.macro.Context.unify(haxe.macro.Context.getType("A"), TType(td, [mono]));
14 return macro $v{haxe.macro.TypeTools.toString(mono)};
15 }
16 }
17
18 private abstract A(Int) to B<String> {}
19
20 private typedef B<T> = Int;
0 package unit.issues;
1
2 import haxe.extern.EitherType;
3
4 private abstract A(String) {}
5 private typedef ET = EitherType<DocumentFilter, A>;
6
7 private typedef DocumentFilter = {
8 final ?language:String;
9 final ?scheme:String;
10 }
11
12 class Issue10730 extends Test {
13 function testSimn() {
14 final et:ET = {language: "haxe"};
15 utest.Assert.pass();
16 }
17 }
0 package unit.issues;
1
2 @:generic
3 private abstract class A<T> {
4 var i:T;
5
6 public function new(i:T) {
7 this.i = i;
8 }
9
10 abstract function foo():T;
11 }
12
13 private class B extends A<Int> {
14 public function foo() {
15 return i;
16 }
17 }
18
19 class Issue10735 extends Test {
20 function test() {
21 eq(12, new B(12).foo());
22 }
23 }
0 package unit.issues;
1
2 class Issue10738 extends Test {
3 function test() {
4 var c = new C();
5 func = c.process.bind(42);
6 c = null;
7 eq(42, func());
8 }
9
10 var func:()->Int;
11 }
12
13 private class C {
14 public function new() {}
15 public function process(value:Int):Int {
16 return value;
17 }
18 }
0 package unit.issues;
1
2 import unit.HelperMacros.typeString;
3
4 class Issue10740 extends Test {
5 // not local vars to prevent optimizations
6 var o:Null<S> = null;
7 var o2:Null<S & {sideEffectCount:() -> Int}> = {
8 var sideEffectCount = 0;
9 {
10 field1: 42,
11 field2: "hallo",
12 field3: {field4: true},
13 field5: function() {
14 sideEffectCount++;
15 return [{field6: 28}];
16 },
17 sideEffectCount: () -> sideEffectCount
18 };
19 };
20
21 function testTyping() {
22 // simple field access
23 eq("Null<Int>", typeString(o?.field1));
24 eq("Null<String>", typeString(o?.field2));
25
26 // field chain
27 eq("Null<Bool>", typeString(o?.field3.field4));
28
29 // complex chain
30 eq("Null<Int>", typeString(o?.field5()[0].field6));
31
32 // nested chain
33 eq("Null<Int>", typeString(o?.field5()[0]?.field6));
34 }
35
36 function testNull() {
37 // simple field access
38 eq(null, o?.field1);
39 eq(null, o?.field2);
40
41 // field chain
42 eq(null, o?.field3.field4);
43
44 // complex chain
45 eq(null, o?.field5()[0].field6);
46
47 // nested chain
48 eq(null, o?.field5()[0]?.field6);
49 }
50
51 function testNonNull() {
52 // simple field access
53 eq(42, o2?.field1);
54 eq("hallo", o2?.field2);
55
56 // field chain
57 eq(true, o2?.field3.field4);
58
59 // complex chain
60 eq(28, o2?.field5()[0].field6);
61 eq(1, o2.sideEffectCount());
62
63 // nested chain
64 eq(28, o2?.field5()[0]?.field6);
65 eq(2, o2.sideEffectCount());
66 eq(null, o2?.field5()[1]?.field6);
67 eq(3, o2.sideEffectCount());
68 }
69 }
70
71 private typedef S = {
72 var field1:Int;
73 var field2:String;
74 var field3:{field4:Bool};
75 var field5:() -> Array<{field6:Null<Int>}>;
76 }
0 package unit.issues;
1
2 @:keep
3 private class C {
4 var o = () -> {
5 return 28;
6 };
7 }
8
9 class Issue10743 extends Test {
10 function test() {
11 utest.Assert.pass();
12 }
13 }
0 package unit.issues;
1
2 import unit.HelperMacros.typeString;
3
4 class Issue10744 extends Test {
5 function test() {
6 var v:Null<Int> = 10;
7 eq("Int", typeString(v ?? return));
8 eq("Int", typeString(v ?? throw true));
9 for (i in 0...1) {
10 eq("Int", typeString(v ?? break));
11 eq("Int", typeString(v ?? continue));
12 }
13 eq("Int", typeString(v ?? {
14 (throw "nope");
15 }));
16 eq("Null<Int>", typeString(v ?? {
17 if (Std.random(0) == 0)
18 return;
19 else
20 v;
21 }));
22 eq("Null<Int>", typeString(v ?? {
23 function foo()
24 return;
25 v;
26 }));
27 eq("Int", typeString(v ?? {
28 if (Std.random(0) == 0)
29 return;
30 else
31 throw "nope";
32 }));
33 eq("Int", typeString(v ?? {
34 Std.parseInt(return);
35 }));
36 eq("Int", typeString(v ?? {
37 (return)();
38 }));
39 eq("Int", typeString(v ?? {
40 v + return;
41 v;
42 }));
43 eq("Null<Int>", typeString(v ?? {
44 false && return ;
45 v;
46 }));
47 eq("Int", typeString(v ?? {
48 true && return ;
49 v;
50 }));
51 eq("Int", typeString(v ?? {
52 false || return ;
53 v;
54 }));
55 eq("Int", typeString(v ?? {
56 final a = return;
57 v;
58 }));
59 eq("Int", typeString(v ?? {
60 [0, return, 2];
61 v;
62 }));
63 eq("Null<Int>", typeString(v ?? {
64 for (i in 0...Std.random(1)) {
65 return;
66 }
67 v;
68 }));
69 eq("Int", typeString(v ?? {
70 for (i in [0, return, 2]) {
71 break;
72 }
73 v;
74 }));
75 eq("Int", typeString(v ?? {
76 switch (null) {
77 case _: return;
78 }
79 v;
80 }));
81 eq("Int", typeString(v ?? {
82 switch (return) {
83 case _: null;
84 }
85 v;
86 }));
87 eq("Int", typeString(v ?? {
88 final arr = [];
89 arr[return];
90 v;
91 }));
92 eq("Int", typeString(v ?? {
93 new EReg("", return);
94 v;
95 }));
96 eq("Null<Int>", typeString(v ?? {
97 do {
98 break;
99 return;
100 } while (true);
101 v;
102 }));
103 eq("Int", typeString(v ?? {
104 do {
105 break; // die
106 return;
107 } while (true); // resurrect
108 return; // die again
109 v;
110 }));
111 eq("Null<Int>", typeString(v ?? {
112 try {
113 throw null;
114 } catch (e) {}
115 v;
116 }));
117 eq("Int", typeString(v ?? {
118 try {
119 throw null;
120 } catch (e) {
121 return;
122 }
123 v;
124 }));
125 eq("Null<Int>", typeString(v ?? {
126 try {
127 throw null;
128 } catch (e:String) {
129 // fall through
130 } catch (e) {
131 return;
132 }
133 v;
134 }));
135 eq("Null<Int>", typeString(v ?? {
136 try {
137 return;
138 } catch (e:String) {
139 // fall through
140 } catch (e) {
141 return;
142 }
143 v;
144 }));
145 eq("Int", typeString(v ?? {
146 try {
147 return;
148 } catch (e:String) {
149 return;
150 } catch (e) {
151 return;
152 }
153 v;
154 }));
155 eq("Null<Int>", typeString(v ?? {
156 try {
157 // something here COULD throw and end up in the fall through case
158 } catch (e:String) {
159 // fall through
160 } catch (e) {
161 return;
162 }
163 v;
164 }));
165 eq("Int", typeString(v ?? {
166 try {
167 return;
168 }
169 v;
170 }));
171 eq("Null<Int>", typeString(v ?? {
172 try {
173 // fall through
174 }
175 v;
176 }));
177 }
178 }
0 package unit.issues;
1
2 class Issue10746 extends Test {
3 #if js
4 @:keep var _ = @:privateAccess js.Boot.getClass;
5
6 function test() {
7 js.Syntax.code("String.prototype.__class__ = String");
8 t(true);
9 }
10 #end
11 }
12
0 package unit.issues;
1
2 private interface I<T> {
3 function foo(v:T):Void;
4 }
5
6 private abstract class Base implements I<Int> {
7 public function new() {}
8 }
9
10 private class Real extends Base {
11 public function foo(v:Int) {}
12 }
13
14 class Issue10748 extends Test {
15 function test() {
16 var r = new Real();
17 r.foo(33);
18 utest.Assert.pass();
19 }
20 }
0 package unit.issues;
1
2 class Issue10752 extends Test {
3 function shl(x, y)
4 return x << y;
5
6 #if (!php && !python && !lua)
7 function test() {
8 eq(2, shl(1, 33));
9 eq(2, 1 << 33);
10
11 eq(1 >> 1, 1 >> 33);
12 eq(1 >>> 1, 1 >>> 33);
13 }
14 #end
15 }
0 package unit.issues;
1
2 class Issue10754 extends Test {
3 function test() {
4 var a = [0, 1, 2];
5 var boundPush = a.push.bind();
6 eq(boundPush(3), 4);
7 }
8 }
0 package unit.issues;
1
2 import haxe.Rest;
3
4 class Issue10761 extends Test {
5 function rest(args:Rest<Int>) {
6 return args;
7 }
8
9 #if !erase_generics
10 function test() {
11 aeq([0, 1], rest(0, 1)); // works
12 aeq([0, 1], rest(...[0, 1])); // works
13 aeq([0, 1], rest(...[for (i in 0...2) i])); // errors
14 }
15 #end
16 }
0 package unit.issues;
1
2 import utest.Assert;
3
4 @:forward
5 private abstract DialogConfig(DialogConfigData) from DialogConfigData {
6 @:from static function fromRenderResult(r:RenderResult):DialogConfig
7 return {priority: 0, ui: r};
8 }
9
10 private typedef DialogConfigData = {
11 final priority:Int;
12 final ui:DialogUi;
13 }
14
15 @:callable
16 private abstract DialogUi((close:() -> Void)->RenderResult) from (close:() -> Void)->RenderResult {
17 inline function new(f)
18 this = f;
19
20 @:from static function fromRenderResult(r:RenderResult)
21 return new DialogUi(_ -> r);
22 }
23
24 private abstract RenderResult(String) to String from String {}
25
26 class Issue10776 extends Test {
27 function test() {
28 var cfg:DialogConfig = {
29 priority: 0,
30 ui: (null : RenderResult),
31 };
32 Assert.pass();
33 }
34 }
0 package unit.issues;
1
2 class Issue10799 extends Test {
3 #if lua
4 var myField:(Int) -> Int;
5
6 private static function foo(x:Int):Int
7 return x * 3;
8
9 private dynamic function bar(x:Int):Int {
10 eq("table", untyped __lua__("_G.type(self)"));
11 eq("number", untyped __lua__("_G.type(x)"));
12 return x * 4;
13 }
14
15 private dynamic function baz(x:Int):Int {
16 throw "not implemented";
17 }
18
19 private function returnsField():(Int) -> Int {
20 return this.myField;
21 }
22
23 private function returnsMethod():(Int) -> Int {
24 return this.bar;
25 }
26
27 private function returnsClosure():(Int) -> Int {
28 final obj = lua.Lua.assert({num: 7});
29 final fn:(Int) -> Int = x -> x * obj.num;
30 lua.Lua.assert(fn);
31 return fn;
32 }
33
34 public function test() {
35 this.myField = x -> x * 2;
36 eq(6, untyped __lua__("self.myField(3)"));
37 this.myField = Issue10799.foo;
38 eq(9, untyped __lua__("self.myField(3)"));
39 eq(9, untyped __lua__("__unit_issues_Issue10799.foo(3)"));
40 this.myField = this.bar;
41 eq(12, untyped __lua__("self.myField(3)"));
42 exc(() -> untyped __lua__("self.bar(3)"));
43 this.myField = x -> x * 2;
44 this.bar = this.myField;
45 eq(6, untyped __lua__("self:bar(3)"));
46 this.baz = this.bar;
47 eq(6, untyped __lua__("self:baz(3)"));
48
49 var localVar = this.myField;
50 lua.Lua.assert(localVar);
51 eq(6, untyped __lua__("localVar(3)"));
52
53 localVar = this.bar;
54 lua.Lua.assert(localVar);
55 eq(6, untyped __lua__("localVar(3)"));
56
57 final field = this.returnsField();
58 eq(6, untyped __lua__("field(3)"));
59 final method = this.returnsMethod();
60 eq(6, untyped __lua__("method(3)"));
61 final closure = this.returnsClosure();
62 eq(21, untyped __lua__("closure(3)"));
63
64 final anon = lua.Lua.assert({
65 fromField: this.myField,
66 fromStatic: Issue10799.foo,
67 fromMethod: this.bar,
68 });
69
70 exc(() -> untyped __lua__("anon.fromField(3)"));
71 eq(6, untyped __lua__("anon:fromField(3)"));
72 exc(() -> untyped __lua__("anon.fromStatic(3)"));
73 eq(9, untyped __lua__("anon:fromStatic(3)"));
74 exc(() -> untyped __lua__("anon.fromMethod(3)"));
75 eq(6, untyped __lua__("anon:fromMethod(3)"));
76 }
77 #end
78 }
0 package unit.issues;
1
2 class Issue10821 extends Test {
3 function test() {
4 eq('foo', Std.string(new Dummy()));
5 }
6 }
7
8 private class Dummy {
9 var toString:()->String;
10
11 public function new() {
12 toString = () -> 'foo';
13 }
14 }
0 package unit.issues;
1
2 import utest.Assert;
3
4 #if (cpp && !cppia)
5
6 @:native('customnamespace::MyExternEnum')
7 extern enum MyExternEnum {
8 First;
9 Second(v : String);
10 }
11
12 @:headerCode('
13 HX_DECLARE_CLASS1(customnamespace, MyExternEnum)
14
15 namespace customnamespace {
16 class MyExternEnum_obj : public hx::EnumBase_obj {
17 public:
18 typedef MyExternEnum_obj OBJ_;
19
20 enum Type {
21 TFirst,
22 TSecond
23 };
24
25 MyExternEnum_obj() = default;
26
27 HX_DO_ENUM_RTTI;
28
29 static bool __GetStatic(const String&, Dynamic&, hx::PropertyAccess);
30
31 String GetEnumName() const { return HX_CSTRING("MyExternEnum"); }
32 String __ToString() const { return HX_CSTRING("MyExternEnum.") + _hx_tag; }
33
34 static MyExternEnum First();
35 static Dynamic First_dyn();
36
37 static MyExternEnum Second(String);
38 static Dynamic Second_dyn();
39 };
40 }
41 ')
42 @:cppFileCode('
43 namespace customnamespace {
44 MyExternEnum MyExternEnum_obj::First() {
45 return hx::CreateEnum<MyExternEnum_obj>(HX_CSTRING("First"), Type::TFirst, 0);
46 }
47
48 MyExternEnum MyExternEnum_obj::Second(String v) {
49 return hx::CreateEnum<MyExternEnum_obj>(HX_CSTRING("Second"), Type::TSecond, 1)->_hx_init(0, v);
50 }
51
52 bool MyExternEnum_obj::__GetStatic(const String& _inName, Dynamic& _outValue, hx::PropertyAccess _propAccess) {
53 if (_inName == HX_CSTRING("First")) { _outValue = MyExternEnum_obj::First_dyn(); return true; }
54 if (_inName == HX_CSTRING("Second")) { _outValue = MyExternEnum_obj::Second_dyn(); return true; }
55 return hx::EnumBase_obj::__GetStatic(_inName, _outValue, _propAccess);
56 }
57
58 hx::Val MyExternEnum_obj::__Field(const String& _inName, hx::PropertyAccess _propAccess) {
59 if (_inName == HX_CSTRING("First")) { return MyExternEnum_obj::First_dyn(); }
60 if (_inName == HX_CSTRING("Second")) { return MyExternEnum_obj::Second_dyn(); }
61 return hx::EnumBase_obj::__Field(_inName, _propAccess);
62 }
63
64 int MyExternEnum_obj::__FindIndex(String _inName) {
65 if (_inName == HX_CSTRING("First")) { return Type::TFirst; }
66 if (_inName == HX_CSTRING("Second")) { return Type::TSecond; }
67 return hx::EnumBase_obj::__FindIndex(_inName);
68 }
69
70 int MyExternEnum_obj::__FindArgCount(String _inName) {
71 if (_inName == HX_CSTRING("First")) { return 0; }
72 if (_inName == HX_CSTRING("Second")) { return 1; }
73 return hx::EnumBase_obj::__FindArgCount(_inName);
74 }
75
76 HX_DEFINE_CREATE_ENUM(MyExternEnum_obj)
77
78 STATIC_HX_DEFINE_DYNAMIC_FUNC0(MyExternEnum_obj, First, return)
79
80 STATIC_HX_DEFINE_DYNAMIC_FUNC1(MyExternEnum_obj, Second, return)
81
82 hx::Class MyExternEnum_obj::__mClass;
83 }
84 ')
85 #end
86 class Issue10830 extends Test {
87
88 #if (cpp && !cppia)
89 function test() {
90 switch create() {
91 case First:
92 Assert.fail();
93 case Second(v):
94 Assert.equals('Hello, World!', v);
95 }
96 }
97
98 function create() : MyExternEnum {
99 return untyped __cpp__('::customnamespace::MyExternEnum_obj::Second(HX_CSTRING("Hello, World!"))');
100 }
101 #end
102 }
0 package unit.issues;
1
2 import utest.Assert;
3
4 #if cpp
5 private enum MyEnum {
6 EnumTest(p:cpp.Pointer<Int>);
7 }
8 #end
9
10 class Issue10831 extends Test {
11 #if cpp
12 function test() {
13 switch (get()) {
14 case EnumTest(p):
15 trace(p);
16 }
17 Assert.pass();
18 }
19
20 function get() {
21 return EnumTest(null);
22 }
23 #end
24 }
0 package unit.issues;
1
2 class Issue10834 extends Test {
3 var tmp:Any;
4 var a:Dynamic = [];
5
6 function test() {
7 tmp = a[0];
8 eq(0, a.length);
9 eq(#if (js || flash) '' #else '[]' #end, a.toString());
10 }
11 }
0 package unit.issues;
1
2 class Issue10836 extends Test {
3 function test() {
4 var foo = new Foo();
5 foo.bar = () -> 'Foo::new bar';
6 eq('Foo::bar', foo.run());
7 }
8 }
9
10 private class Foo {
11 public var run:Void->String;
12
13 public function new() {
14 run = bar;
15 }
16
17 public dynamic function bar() {
18 return 'Foo::bar';
19 }
20 }
0 package unit.issues;
1
2 import utest.Assert;
3
4 private var count = 0;
5
6 private abstract MyInt(Int) from Int to Int {
7 @:op(A += B)
8 public inline function addEq(x:Int):MyInt {
9 count++;
10 return this;
11 }
12
13 @:op(A++)
14 public inline function increment():MyInt {
15 count++;
16 return this;
17 }
18 }
19
20 class Issue10845 extends Test {
21 final field:MyInt = 1;
22
23 function test():Void {
24 final local:MyInt = 1;
25
26 field++;
27 eq(1, count);
28 local++;
29 eq(2, count);
30
31 field += 1;
32 eq(3, count);
33 local += 1;
34 eq(4, count);
35
36 field.addEq(1);
37 eq(5, count);
38 local.addEq(1);
39 eq(6, count);
40
41 field.increment();
42 eq(7, count);
43 local.increment();
44 eq(8, count);
45 }
46 }
0 package unit.issues;
1
2 class Issue10867 extends Test {
3 function test() {
4 var r = ~/\/\*(((?!\*\/).)*)$/s;
5 var a = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
6
7 var test = "/*";
8 var res = new StringBuf();
9 for (i in 0...10) {
10 test += a;
11 res.add('iter $i: ${r.match(test)} ');
12 }
13
14 res.add("Finished");
15 eq("iter 0: true iter 1: true iter 2: true iter 3: true iter 4: true iter 5: true iter 6: true iter 7: true iter 8: true iter 9: true Finished",
16 res.toString());
17 }
18 }
0 package unit.issues;
1
2 import utest.Assert;
3
4 #if (cpp && !cppia)
5 @:native('MY_DEFINE')
6 extern class MyDefine {}
7
8 @:unreflective
9 @:structAccess
10 @:native('my_extern')
11 extern class MyExtern<T> {
12 function new();
13
14 function create() : T;
15 }
16
17 @:headerCode('
18
19 typedef int MY_DEFINE;
20
21 template<class T>
22 class my_extern {
23 public:
24 T create() {
25 return T();
26 }
27 };
28
29 ')
30 #end
31 class Issue10876 extends Test {
32 #if (cpp && !cppia)
33 function test() {
34 final vec = cpp.Pointer.fromStar(new MyExtern<MyDefine>());
35 final num = vec.ptr.create();
36
37 Assert.equals(0, num);
38 }
39 #end
40 }
0 package unit.issues;
1
2 import haxe.Rest;
3 import utest.Assert;
4
5 class Issue10906 extends Test {
6 #if !erase_generics
7 function test() {
8 var a:Array<Any> = new Array<Any>();
9 a.push(1);
10 a.push(2);
11 a.push(3);
12 Assert.same([1, 2, 3], a);
13 eq(3, a.length);
14 var r = Rest.of(a);
15 eq(1, r[0]);
16 eq(3, r.length);
17 }
18 #end
19 }
0 package unit.issues;
1
2 class Issue10960 extends Test {
3 function test() {
4 final obj:Dynamic = 0;
5 eq("", mm(obj));
6 }
7
8 static macro function mm(any:Any) {
9 return macro "";
10 }
11 }
0 package unit.issues;
1
2 class Issue10965 extends Test {
3 #if jvm
4 function testNeg() {
5 var a:Single = 1;
6 var c = -a;
7 eq((-1 : Single), c);
8 }
9
10 function testIncPre() {
11 var a:Single = 1;
12 var c = ++a;
13 eq((2 : Single), a);
14 eq((2 : Single), c);
15 }
16
17 function testIncPost() {
18 var a:Single = 1;
19 var c = a++;
20 eq((2 : Single), a);
21 eq((1 : Single), c);
22 }
23
24 function testDecPre() {
25 var a:Single = 1;
26 var c = --a;
27 eq((0 : Single), a);
28 eq((0 : Single), c);
29 }
30
31 function testDecPost() {
32 var a:Single = 1;
33 var c = a--;
34 eq((0 : Single), a);
35 eq((1 : Single), c);
36 }
37 #end
38 }
0 package unit.issues;
1
2 enum Issue10993_TestEnum {
3 FOO;
4 }
5
6 class Issue10993 extends Test {
7 function testHasFieldWithEnum() {
8 final foo = Issue10993_TestEnum.FOO;
9 eq(false, Reflect.hasField(foo, "bar"));
10 }
11
12 function testHasFieldWithFunction() {
13 final foo = () -> null;
14 eq(false, Reflect.hasField(foo, "bar"));
15 }
16 }
0 package unit.issues;
1
2 class Issue11007 extends Test {
3 function test() {
4 var a:Dynamic<Dynamic> = {day: "numeric"};
5 eq("numeric", a.day);
6 }
7 }
0 package unit.issues;
1
2 class Issue11040 extends Test {
3 function run() {
4 var tagName = "Array";
5 var text:String = "<Array<haxe.Json>>";
6 var startTag = '<$tagName';
7 var endTag = '</$tagName>';
8
9 var depth = 0;
10 var index = 0;
11 var buf = new StringBuf();
12 function append(s:String) {
13 buf.add(s);
14 buf.add("\n");
15 }
16 append("enter loop");
17 while (true) {
18 append("looping");
19 var indexStartTag = text.indexOf(startTag, index);
20 var indexEndTag = text.indexOf(endTag, index);
21 if ((indexStartTag == -1) && (indexEndTag == -1)) {
22 append(">>> should exit here >>>");
23 return buf.toString();
24 }
25 index++;
26 switch (text.charAt(index)) {
27 case " " | "/" | ">":
28 default:
29 append("default -> continue loop");
30 continue;
31 }
32 if (depth <= 0) {
33 break;
34 }
35 }
36 text = text.substr(0, index);
37 append("exit loop");
38 return buf.toString();
39 }
40
41 function test() {
42 eq("enter loop
43 looping
44 default -> continue loop
45 looping
46 >>> should exit here >>>
47 ", run());
48 }
49 }
00 package unit.issues;
1
12 import unit.Test;
23
34 class Issue2776 extends Test {
45 function test() {
56 var type = null;
6 switch(type) {
7 switch (type) {
78 case String:
89 case Int:
910 }
1011 unit.HelperMacros.typedAs(type, getClassT());
1112
1213 var type = null;
13 switch(type) {
14 switch (type) {
1415 case haxe.macro.Expr.ExprDef:
1516 case haxe.macro.Expr.Constant:
1617 }
1718 unit.HelperMacros.typedAs(type, getEnumT());
1819
1920 var type = null;
20 t(unit.HelperMacros.typeError(switch(type) {
21 t(unit.HelperMacros.typeError(switch (type) {
2122 case String:
2223 case haxe.macro.Expr.ExprDef:
2324 }));
2425 }
2526
26 static function getClassT<T>():Class<T> {
27 static function getClassT<T>():#if cs Class<T> #else Null<Class<T>> #end {
2728 return (null : Class<T>);
2829 }
2930
30 static function getEnumT<T>():Enum<T> {
31 static function getEnumT<T>():#if cs Enum<T> #else Null<Enum<T>> #end {
3132 return (null : Enum<T>);
3233 }
33 }
34 }
55 }
66
77 class Issue2778 extends Test {
8
98 function test() {
109 eq(true, sameType(BoolLit(true), BoolLit(true)));
1110 eq(false, sameType(BoolLit(false), BoolLit(true)));
1615 t(unit.HelperMacros.typeError(sameType(BoolLit(true), IntLit(1))));
1716 }
1817
18 @:haxe.warning("-WGenerator")
1919 static function sameType<S>(o1:E<S>, o2:E<S>):S {
2020 return switch [o1, o2] {
2121 case [BoolLit(b1), BoolLit(b2)]: b1 && b2;
2222 case [IntLit(i1), IntLit(i2)]: i1 + i2;
2323 }
2424 }
25 }
25 }
77 Reflect.makeVarArgs(f);
88 Reflect.makeVarArgs(f2);
99 var s:String = f([]);
10 unit.HelperMacros.typedAs(r, (r:String));
11 unit.HelperMacros.typedAs(f2([]), (null:Void));
10 #if cs
11 unit.HelperMacros.typedAs(r, (r : String));
12 #else
13 unit.HelperMacros.typedAs(r, (r : Null<String>));
14 #end
15 unit.HelperMacros.typedAs(f2([]), (null : Void));
1216 }
13 }
17 }
00 package unit.issues;
11
22 class Issue3861 extends unit.Test {
3 @:haxe.warning("-WVarInit")
34 function test() {
45 var a;
56 var b = function() return a;
67 a = 2;
78 eq(2, b());
89 }
9 }
10 }
22 @:callable
33 abstract Example(()->String) {
44 public function new() {
5 this = null;
56 this = fun;
67 }
78
00 package unit.issues;
11
22 private class TList {}
3 private class TCons<U,V:TList> extends TList {}
3 private class TCons<U, V:TList> extends TList {}
44 private class TNil extends TList {}
55
66 private enum Stack<L:TList> {
7 Nil: Stack<TNil>;
8 Cons<X,L:TList>(x: X, xs: Stack<L>): Stack<TCons<X,L>>;
7 Nil:Stack<TNil>;
8 Cons<X, L:TList>
9 (x : X, xs : Stack<L>) : Stack<TCons<X, L>>;
910 }
1011
11 private interface Instr<L1:TList,L2:TList> {
12 function denote(s: Stack<L1>): Stack<L2>;
12 private interface Instr<L1:TList, L2:TList> {
13 function denote(s:Stack<L1>):Stack<L2>;
1314 }
1415
15 private class IUnOp<X,Y,S:TList> implements Instr<TCons<X,S>,TCons<Y,S>> {
16 var f: X->Y;
16 private class IUnOp<X, Y, S:TList> implements Instr<TCons<X, S>, TCons<Y, S>> {
17 var f:X->Y;
1718
1819 public function new(f) {
1920 this.f = f;
2021 }
2122
22 public function denote(s: Stack<TCons<X,S>>): Stack<TCons<Y,S>> {
23 return switch(s) {
23 public function denote(s:Stack<TCons<X, S>>):Stack<TCons<Y, S>> {
24 return switch (s) {
2425 case Cons(x, s):
2526 Cons(f(x), s);
2627 }
2728 }
2829 }
2930
31 @:haxe.warning("-WGenerator")
3032 class Issue4578 extends Test {
3133 function test() {
3234 var i = new IUnOp(function(x) return x * 2);
3436 eq(20, getHead(v));
3537 }
3638
37 static function getHead<S, T:TList>(s:Stack<TCons<S,T>>):S {
39 static function getHead<S, T:TList>(s:Stack<TCons<S, T>>):S {
3840 return switch (s) {
3941 case Cons(x, _): x;
4042 }
4143 }
42 }
44 }
00 package unit.issues;
11
22 class Issue5078 extends Test {
3 #if !(js || php || lua)
3 #if !(js || lua)
44 static function getToLower() return "ABC".toLowerCase;
55 #end
66
77 function test() {
8 #if !(js || php || lua)
8 #if !(js || lua)
99 eq(getToLower()(), "abc");
1010 #else
1111 noAssert();
0 package unit.issues;
1
2 class Issue5890 extends unit.Test {
3 function test() {
4 new ReporterImplSuc2();
5 noAssert();
6 }
7 }
8
9 interface Reporter<TDef> {
10 public function shoot<T:TDef>(ctx:T):Void;
11 }
12
13 class ReporterImpl<A, TDef> implements Reporter<TDef> {
14 public function shoot<T:TDef>(ctx:T):Void {}
15 }
16
17 class Impl2 implements Reporter<Int> {
18 public function shoot<T:Int>(a:T) {}
19 }
20
21 class ReporterImplSuc<TDef, A> extends ReporterImpl<A, TDef> implements Reporter<TDef> {}
22
23 class ReporterImplSuc2 extends ReporterImpl<Int, String> implements Reporter<String> {
24 public function new() {}
25 }
26
27 class HierarchyImpl implements ISuc<Float> {
28 public function shoot<A:Float>(a:A) {
29 trace(a + 5);
30 }
31 }
32
33 class HierarchyImpl2<T> implements ISuc<T> {
34 public function shoot<A:T>(a:A) {}
35 }
36
37 interface IBase2<T> {
38 function shoot<A:T>(a:A):Void;
39 }
40
41 interface OtherBase {}
42 interface ISuc<T> extends IBase2<T> extends OtherBase {}
43 class StatBase<T:{}> {}
44 class ShotContext<TDef:{}, T:StatBase<TDef>> {}
45
46 interface WeaponReporter<TDef:{}> {
47 public function shoot<T:StatBase<TDef>>(ctx:ShotContext<TDef, T>):Void;
48 }
49
50 class StatWeaponReporterImpl<TDef:{}> implements WeaponReporter<TDef> {
51 public function shoot<T:StatBase<TDef>>(ctx:ShotContext<TDef, T>):Void {}
52 }
0 package unit.issues;
1
2 import utest.Assert;
3 import haxe.PosInfos;
4
5 class Issue6017 extends Test {
6 function checkPos(i:Any, ?p:PosInfos) {
7 Assert.same(p, Abstr.p);
8 }
9
10 function test() {
11 checkPos((123:Abstr));
12 var i:Abstr = 123;
13 checkPos(i + 100);
14 checkPos((i:String));
15 checkPos(i[0]);
16 checkPos(i[0] = 1);
17 checkPos(i());
18 checkPos(i.hello);
19 checkPos(i.hello = 'world');
20 }
21 }
22
23 private abstract Abstr(Int) {
24 static public var p:PosInfos;
25
26 @:from static public function fromInt(i:Int, ?p:PosInfos) {
27 Abstr.p = p;
28 return new Abstr(i);
29 }
30
31 @:to public function toString(?p:PosInfos):String {
32 Abstr.p = p;
33 return 'Abstr $this';
34 }
35
36 @:op(A + B) public function addInt(i:Int, ?p:PosInfos) {
37 Abstr.p = p;
38 return new Abstr(i + this);
39 }
40
41 @:op([]) public function arrayGet(i:Int, ?p:PosInfos) {
42 Abstr.p = p;
43 return i;
44 }
45
46 @:op([]) public function arraySet(i:Int, v:Int, ?p:PosInfos) {
47 Abstr.p = p;
48 return v;
49 }
50
51 @:op(a()) public function call(?p:PosInfos) {
52 Abstr.p = p;
53 return Std.random(10);
54 }
55
56 @:op(a.b) public function resolveGet(f:String, ?p:PosInfos) {
57 Abstr.p = p;
58 return f;
59 }
60
61 @:op(a.b) public function resolveSet(f:String, v:String, ?p:PosInfos) {
62 Abstr.p = p;
63 return v;
64 }
65
66 function new(i:Int) {
67 this = i;
68 }
69 }
0 package unit.issues;
1
2 import haxe.macro.Context;
3 import haxe.macro.Expr;
4 import unit.HelperMacros.*;
5
6 class Issue6063 extends Test {
7 macro static function convert(e:Expr) {
8 var t = Context.typeof(e);
9 var ct = Context.toComplexType(t);
10 return macro @:pos(e.pos) (null : $ct);
11 }
12
13 function testFinal() {
14 #if !macro
15 var x:{final s:String;} = null;
16 var y = convert(x);
17 x = y;
18 t(typeError(y.s = "foo"));
19 #end
20 }
21
22 function testAccess() {
23 var o:{var x(default, null):Int;} = null;
24 var o2 = convert(o);
25 o = o2;
26 t(typeError(o2.x = 12));
27 }
28
29 function testFunction() {
30 var f:(?a:String) -> Void = null;
31 var e = convert(f);
32 eq("(?a : String) -> Void", typeString(e));
33 }
34 }
1111 var vals = [ for (k in m) k];
1212 eq(vals.length, 1);
1313 eq(vals[0], 10);
14 #if !cpp
15 eq(m.toString(), '{0 => 10}');
16 #end
14 eq(m.toString(), '[0 => 10]');
1715
1816 var m = new Map();
1917 m.set("c", 1);
2624 var vals = [ for (k in m) k];
2725 eq(vals.length, 1);
2826 eq(vals[0], 10);
29 #if !cpp
30 eq(m.toString(), '{z => 10}');
31 #end
27 eq(m.toString(), '[z => 10]');
3228 }
3329 }
33 NotLog(msg:String):Log<String>;
44 }
55
6
76 class Issue6561 extends unit.Test {
87 function test() {
98 eq("hello", apply(NotLog("hello")));
109 }
1110
12 static function apply<A>(f:Log<A>):A {
11 @:haxe.warning("-WGenerator")
12 static function apply<A>(f:Log<A>):A {
1313 return switch f {
1414 case NotLog(msg):
15 msg;
15 msg;
1616 }
17 }
18 }
17 }
18 }
0 package unit.issues;
1
2 class Issue7736 extends Test {
3 #if !cs
4 @:nullSafety
5 function test() {
6 var found = null;
7 for (i in 0...10) {
8 if (i == 5) {
9 found = i;
10 break;
11 }
12 }
13 unit.HelperMacros.typedAs(found, (null : Null<Int>));
14 if (found != null) {
15 var x:Int = found;
16 eq(5, x);
17 }
18 }
19 #end
20 }
2525 test.eq(f(), "hello");
2626 test.eq(call(f), "hello");
2727
28 // super. protected access
29 test.eq(super.x, 50);
30 super.x = 55;
31 test.eq(super.x, 55);
32
33 test.eq(super.i, 10);
34 super.i = 15;
35 test.eq(super.i, 15);
36
37 test.eq(super.f(), "hello");
38
3928 // static protected access
4029 test.eq(Lib.sx, 42);
4130 Lib.sx = 50;
0 package unit.issues;
1
2 class Issue8401 extends unit.Test {
3 #if python
4 function testNew() {
5 var sock = new python.net.SslSocket();
6 // With Issue8401, construction fails immediately; if we get this far, it's a pass
7 utest.Assert.pass();
8 }
9
10 @:access(python.net.SslSocket.__s)
11 @:access(python.net.SslSocket.wrapSocketWithSslContext)
12 function testTimeout() {
13 var sock = new python.net.SslSocket();
14 eq(null, sock.__s.gettimeout());
15 sock.setTimeout(500);
16 feq(500, sock.__s.gettimeout());
17 // This will change __s. Make sure we set the timeout properly.
18 sock.wrapSocketWithSslContext("127.0.0.1");
19 feq(500, sock.__s.gettimeout());
20 }
21
22 #if (python_verion >= 3.7)
23 @:access(python.net.SslSocket.__s)
24 @:access(python.net.SslSocket.wrapSocketWithSslContext)
25 function testBlocking() {
26 var sock = new python.net.SslSocket();
27 t(sock.__s.getblocking());
28 sock.setBlocking(false);
29 f(sock.__s.getblocking());
30 // This will change __s. Make sure we set the blocking flag properly.
31 sock.wrapSocketWithSslContext("127.0.0.1");
32 f(sock.__s.getblocking());
33 }
34 #end
35
36 @:access(python.net.SslSocket.__s)
37 @:access(python.net.SslSocket.wrapSocketWithSslContext)
38 function testFastSend() {
39 var sock = new python.net.SslSocket();
40 eq(0, sock.__s.getsockopt(python.lib.Socket.SOL_TCP, python.lib.Socket.TCP_NODELAY));
41 sock.setFastSend(true);
42 // NOTE: this number can vary per platform; non-zero means true/enabled
43 utest.Assert.notEquals(0, sock.__s.getsockopt(python.lib.Socket.SOL_TCP, python.lib.Socket.TCP_NODELAY));
44 // This will change __s. Make sure we set the sock opt properly.
45 sock.wrapSocketWithSslContext("127.0.0.1");
46 utest.Assert.notEquals(0, sock.__s.getsockopt(python.lib.Socket.SOL_TCP, python.lib.Socket.TCP_NODELAY));
47 }
48 #end
49 }
44 noAssert();
55 }
66
7 function checkIntersectionConstraintInParentheses<T:(haxe.Constraints.Constructible<()->Void> & Dummy)>(cl:Class<T>) {}
7 function checkIntersectionConstraintInParentheses<T:(haxe.Constraints.Constructible<() -> Void> & Dummy)>(cl:Class<T>) {}
8
9 function checkFunctionTypeConstraint<T:(Int) -> Void>() {}
810 }
911
1012 private class Dummy {
1113 public function new() {}
12 }
14 }
44 class Issue9034 extends Test{
55 #if java
66 function test() {
7 bar(java.nio.file.Paths.get('build.hxml', new java.NativeArray(0)));
7 bar(java.nio.file.Paths.get('build.hxml'));
88 utest.Assert.pass();
99 }
1010
0 package unit.issues;
1
2 import unit.Test;
3
4 class Issue9198 extends Test {
5 public function test() {
6 eq(null, Std.parseInt("axolotl"));
7 }
8 }
0 package unit.issues;
1
2 private abstract A(String) {
3 public inline function new(s:String) {
4 this = s;
5 }
6
7 public function f(index:Int) {
8 return StringTools.fastCodeAt(this, index);
9 }
10
11 public inline function g(index:Int) {
12 return StringTools.fastCodeAt(this, index);
13 }
14 }
15
16 class Issue9543 extends unit.Test {
17 #if (cpp && !cppia)
18 function testVar() {
19 var foo:Int = 0;
20 var bar:cpp.Reference<Int> = foo;
21 foo += 1;
22 eq(1, foo);
23 eq(1, bar);
24 }
25
26 function testAssign() {
27 var foo:Int = 0;
28 var bar:cpp.Reference<Int>;
29 bar = foo;
30 foo += 1;
31 eq(1, foo);
32 eq(1, bar);
33 }
34 #end
35 }
0 package unit.issues;
1
2 import unit.Test;
3 import utest.Assert;
4
5 enum abstract Noise(Null<Dynamic>) {
6 final Noise = null;
7 }
8
9 class Issue9563 extends Test {
10 function test() {
11 switch Noise { // Unmatched patterns: _
12 case Noise:
13 }
14 Assert.pass();
15 }
16 }
8686 ~/a/g.replace("bab", "z") == "bzb";
8787 ~/a/g.replace("baba", "z") == "bzbz";
8888
89 #if !(hl && interp) // not allowed in local interpreter, still allowed in hl runtime
89 #if !(interp) // not allowed in local interpreter, still allowed in hl runtime
9090 // replace + $
9191 ~/href="(.*?)"/.replace('lead href="foo" trail',"$1") == "lead foo trail";
9292 //~/href="(.*?)"/.replace('lead href="foo" trail',"$2") == "lead $2 trail";
7070 Std.int(0.2) == 0;
7171
7272 // parseInt
73
74 // general
7375 Std.parseInt("0") == 0;
7476 Std.parseInt("-1") == -1;
75 Std.parseInt(" 5") == 5;
77 // preceeding zeroes
7678 Std.parseInt("0001") == 1;
7779 Std.parseInt("0010") == 10;
78 Std.parseInt("100") == 100;
79 Std.parseInt("-100") == -100;
80 // trailing text
8081 Std.parseInt("100x123") == 100;
8182 Std.parseInt("12foo13") == 12;
82 Std.parseInt("") == null;
83 Std.parseInt("abcd") == null;
84 Std.parseInt("a10") == null;
85 Std.parseInt(null) == null;
86 Std.parseInt("0xFF") == 255;
83 Std.parseInt("23e2") == 23;
84 Std.parseInt("0x10z") == 16;
85 Std.parseInt("0x10x123") == 16;
86 Std.parseInt("0xff\n") == 255;
87 // hexadecimals
88 Std.parseInt("0xff") == 255;
8789 Std.parseInt("0x123") == 291;
8890 Std.parseInt("0XFF") == 255;
8991 Std.parseInt("0X123") == 291;
9092 Std.parseInt("0X01") == 1;
9193 Std.parseInt("0x01") == 1;
92 #if !neko //sorry, neko
93 #if !hl //see https://github.com/HaxeFoundation/hashlink/issues/330
94 #if !cpp //see https://github.com/HaxeFoundation/hxcpp/issues/869
94 // signs
95 Std.parseInt("123") == 123;
96 Std.parseInt("+123") == 123;
97 Std.parseInt("-123") == -123;
98 Std.parseInt("0xa0") == 160;
99 Std.parseInt("+0xa0") == 160;
100 Std.parseInt("-0xa0") == -160;
101 // whitespace: space, horizontal tab, newline, vertical tab, form feed, and carriage return
102 Std.parseInt(" 5") == 5;
103 Std.parseInt(" \t\n\x0b\x0c\r16") == 16;
104 Std.parseInt(" \t\n\x0b\x0c\r0xa") == 10;
105 // whitespace and signs
106 Std.parseInt(' 16') == 16;
107 Std.parseInt(' -16') == -16;
108 Std.parseInt(' +16') == 16;
109 Std.parseInt(' 0x10') == 16;
95110 Std.parseInt(' -0x10') == -16;
96 #end
97 #end
98 #end
111 Std.parseInt(' +0x10') == 16;
112 // binary and octal unsupported
113 Std.parseInt("010") == 10;
114 Std.parseInt("0b10") == 0;
115 // null
116 Std.parseInt(null) == null;
117 // no number
118 Std.parseInt("") == null;
119 Std.parseInt("abcd") == null;
120 Std.parseInt("a10") == null;
121 // invalid use of signs
122 Std.parseInt("++123") == null;
123 Std.parseInt("+-123") == null;
124 Std.parseInt("-+123") == null;
125 Std.parseInt("--123") == null;
126 Std.parseInt("+ 123") == null;
127 Std.parseInt("- 123") == null;
128 Std.parseInt("++0x123") == null;
129 Std.parseInt("+-0x123") == null;
130 Std.parseInt("-+0x123") == null;
131 Std.parseInt("--0x123") == null;
132 Std.parseInt("+ 0x123") == null;
133 Std.parseInt("- 0x123") == null;
134 // hexadecimal prefix with no number
135 unspec(Std.parseInt.bind("0x"));
136 unspec(Std.parseInt.bind("0x C"));
137 unspec(Std.parseInt.bind("0x+A"));
99138
100139 // parseFloat
140
141 // general
101142 Std.parseFloat("0") == 0.;
102 Std.parseFloat(" 5.3") == 5.3;
143 Std.parseFloat("0.0") == 0.;
144 // preceeding zeroes
103145 Std.parseFloat("0001") == 1.;
104 Std.parseFloat("100.45") == 100.45;
105 Std.parseFloat("-100.01") == -100.01;
146 Std.parseFloat("0010") == 10.;
147 // trailing text
106148 Std.parseFloat("100x123") == 100.;
107 Math.isNaN(Std.parseFloat("")) == true;
108 Math.isNaN(Std.parseFloat("abcd")) == true;
109 Math.isNaN(Std.parseFloat("a10")) == true;
110 Math.isNaN(Std.parseFloat(null)) == true;
149 Std.parseFloat("12foo13") == 12.;
111150 Std.parseFloat("5.3 ") == 5.3;
112 Std.parseFloat("0.0") == 0.;
113151 Std.parseFloat("5.3 1") == 5.3;
152 // signs
153 Std.parseFloat("123.45") == 123.45;
154 Std.parseFloat("+123.45") == 123.45;
155 Std.parseFloat("-123.45") == -123.45;
156 // whitespace: space, horizontal tab, newline, vertical tab, form feed, and carriage return
157 Std.parseFloat(" 5.2") == 5.2;
158 Std.parseFloat(" \t\n\x0b\x0c\r1.6") == 1.6;
159 // whitespace and signs
160 Std.parseFloat(' 1.6') == 1.6;
161 Std.parseFloat(' -1.6') == -1.6;
162 Std.parseFloat(' +1.6') == 1.6;
163 // exponent
164 Std.parseFloat("2.426670815e12") == 2.426670815e12;
165 Std.parseFloat("2.426670815E12") == 2.426670815e12;
114166 Std.parseFloat("2.426670815e+12") == 2.426670815e+12;
115167 Std.parseFloat("2.426670815E+12") == 2.426670815e+12;
116168 Std.parseFloat("2.426670815e-12") == 2.426670815e-12;
117169 Std.parseFloat("2.426670815E-12") == 2.426670815e-12;
118 // Std.parseInt("0x C") == 0;
119 // Std.parseInt("0x+A") == 0;
170 #if !interp
171 Std.parseFloat("6e") == 6;
172 Std.parseFloat("6E") == 6;
173 #end
174 // null
175 Math.isNaN(Std.parseFloat(null)) == true;
176 // no number
177 Math.isNaN(Std.parseFloat("")) == true;
178 Math.isNaN(Std.parseFloat("abcd")) == true;
179 Math.isNaN(Std.parseFloat("a10")) == true;
180 // invalid use of signs
181 Math.isNaN(Std.parseFloat("++12.3")) == true;
182 Math.isNaN(Std.parseFloat("+-12.3")) == true;
183 Math.isNaN(Std.parseFloat("-+12.3")) == true;
184 Math.isNaN(Std.parseFloat("--12.3")) == true;
185 Math.isNaN(Std.parseFloat("+ 12.3")) == true;
186 Math.isNaN(Std.parseFloat("- 12.3")) == true;
120187
121188 // random
122189 var x = Std.random(2);
4141 flags.has(EB) == true;
4242 flags.has(EC) == false;
4343
44
4445 // Big Enum (32)
4546 var bigFlags = new haxe.EnumFlags(1<<31);
4647 bigFlags.has( EF_31 ) == true;
4849 bigFlags.has( EF_31 ) == false;
4950 bigFlags.set( EF_31 );
5051 bigFlags.has( EF_31 ) == true;
52
53 // setTo
54 var flags = new haxe.EnumFlags();
55 flags.setTo(EB, true);
56 flags.has(EB) == true;
57 flags.setTo(EB, false);
58 flags.has(EB) == false;
59 flags.setTo(EB, true);
60 flags.has(EB) == true;
0 #if (target.atomics)
1 var a = new haxe.atomic.AtomicBool(true);
2
3 a.load() == true;
4 a.store(false) == false;
5 a.load() == false;
6
7 a.compareExchange(false, true) == false;
8 a.load() == true;
9
10 a.compareExchange(false, false) == true;
11 a.load() == true;
12
13 a.exchange(true) == true;
14 a.load() == true;
15 #else
16 0 == 0; // prevent "no assertions" warning
17 #end
0 #if target.atomics
1 var a = new haxe.atomic.AtomicInt(0);
2
3 a.load() == 0;
4
5 a.store(5) == 5;
6 a.load() == 5;
7
8 a.add(5) == 5;
9 a.load() == 10;
10
11 a.sub(5) == 10;
12 a.load() == 5;
13
14 a.and(20) == 5;
15 a.load() == 4;
16
17 a.or(3) == 4;
18 a.load() == 7;
19
20 a.xor(2) == 7;
21 a.load() == 5;
22
23 a.compareExchange(0, 0) == 5;
24 a.load() == 5;
25 a.compareExchange(5, 0) == 5;
26 a.load() == 0;
27
28 a.exchange(10) == 0;
29 a.load() == 10;
30 #else
31 0 == 0; // prevent "no assertions" warning
32 #end
0 #if (target.atomics && !(js || cpp))
1 var a = new haxe.atomic.AtomicObject("Hey World!");
2
3 a.load() == "Hey World!";
4 a.store("Hello World!") == "Hello World!";
5 a.load() == "Hello World!";
6
7 a.compareExchange("Hello World!", "Goodbye World!") == "Hello World!";
8 a.load() == "Goodbye World!";
9
10 a.exchange("Hello World!") == "Goodbye World!";
11 a.load() == "Hello World!";
12 #else
13 0 == 0; // prevent "no assertions" warning
14 #end
0 haxe.crypto.Base64.encode(haxe.io.Bytes.ofString("The quick brown fox jumps over the lazy dog"), true) == "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==";
1 haxe.crypto.Base64.encode(haxe.io.Bytes.ofString("The quick brown fox jumps over the lazy dog"), false) == "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw";
2 haxe.crypto.Base64.urlEncode(haxe.io.Bytes.ofString("The quick brown fox jumps over the lazy dog"), true) == "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==";
3 haxe.crypto.Base64.urlEncode(haxe.io.Bytes.ofString("The quick brown fox jumps over the lazy dog"), false) == "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw";
4
5 haxe.crypto.Base64.decode("VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==", true).toString() == "The quick brown fox jumps over the lazy dog";
6 haxe.crypto.Base64.decode("VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw", false).toString() == "The quick brown fox jumps over the lazy dog";
7 haxe.crypto.Base64.urlDecode("VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==", true).toString() == "The quick brown fox jumps over the lazy dog";
8 haxe.crypto.Base64.urlDecode("VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw", false).toString() == "The quick brown fox jumps over the lazy dog";
9
10 haxe.crypto.Base64.encode(haxe.io.Bytes.ofString("a"), true) == "YQ==";
11 haxe.crypto.Base64.encode(haxe.io.Bytes.ofString("ab"), true) == "YWI=";
12 haxe.crypto.Base64.encode(haxe.io.Bytes.ofString("ab?"), true) == "YWI/";
13 haxe.crypto.Base64.encode(haxe.io.Bytes.ofString("ab~c"), true) == "YWJ+Yw==";
14 haxe.crypto.Base64.encode(haxe.io.Bytes.ofString("a"), false) == "YQ";
15 haxe.crypto.Base64.encode(haxe.io.Bytes.ofString("ab"), false) == "YWI";
16 haxe.crypto.Base64.encode(haxe.io.Bytes.ofString("ab?"), false) == "YWI/";
17 haxe.crypto.Base64.encode(haxe.io.Bytes.ofString("ab~c"), false) == "YWJ+Yw";
18
19 haxe.crypto.Base64.urlEncode(haxe.io.Bytes.ofString("a"), true) == "YQ==";
20 haxe.crypto.Base64.urlEncode(haxe.io.Bytes.ofString("ab"), true) == "YWI=";
21 haxe.crypto.Base64.urlEncode(haxe.io.Bytes.ofString("ab?"), true) == "YWI_";
22 haxe.crypto.Base64.urlEncode(haxe.io.Bytes.ofString("ab~c"), true) == "YWJ-Yw==";
23 haxe.crypto.Base64.urlEncode(haxe.io.Bytes.ofString("a"), false) == "YQ";
24 haxe.crypto.Base64.urlEncode(haxe.io.Bytes.ofString("ab"), false) == "YWI";
25 haxe.crypto.Base64.urlEncode(haxe.io.Bytes.ofString("ab?"), false) == "YWI_";
26 haxe.crypto.Base64.urlEncode(haxe.io.Bytes.ofString("ab~c"), false) == "YWJ-Yw";
27
28 haxe.crypto.Base64.decode("YQ==", true).toString() == "a";
29 haxe.crypto.Base64.decode("YWI=", true).toString() == "ab";
30 haxe.crypto.Base64.decode("YWI/", true).toString() == "ab?";
31 haxe.crypto.Base64.decode("YWJ+Yw==", true).toString() == "ab~c";
32 haxe.crypto.Base64.decode("YQ", false).toString() == "a";
33 haxe.crypto.Base64.decode("YWI", false).toString() == "ab";
34 haxe.crypto.Base64.decode("YWI/", false).toString() == "ab?";
35 haxe.crypto.Base64.decode("YWJ+Yw", false).toString() == "ab~c";
36
37 haxe.crypto.Base64.urlDecode("YQ==", true).toString() == "a";
38 haxe.crypto.Base64.urlDecode("YWI=", true).toString() == "ab";
39 haxe.crypto.Base64.urlDecode("YWI_", true).toString() == "ab?";
40 haxe.crypto.Base64.urlDecode("YWJ-Yw==", true).toString() == "ab~c";
41 haxe.crypto.Base64.urlDecode("YQ", false).toString() == "a";
42 haxe.crypto.Base64.urlDecode("YWI", false).toString() == "ab";
43 haxe.crypto.Base64.urlDecode("YWI_", false).toString() == "ab?";
44 haxe.crypto.Base64.urlDecode("YWJ-Yw", false).toString() == "ab~c";
9292 vec3[5] == 5;
9393 vec3[6] == 6;
9494
95 var vec5 = new haxe.ds.Vector(3, 5);
96 vec5[0] == 5;
97 vec5[1] == 5;
98 vec5[2] == 5;
99 vec5.fill(1);
100 vec5[0] == 1;
101 vec5[1] == 1;
102 vec5[2] == 1;
103
104 var vec5 = new haxe.ds.Vector(3, true);
105 vec5[0] == true;
106 vec5[1] == true;
107 vec5[2] == true;
108
95109 var vec5 = haxe.ds.Vector.fromArrayCopy([0,1,2,3,4]);
96110 haxe.ds.Vector.blit(vec5, 0, vec5, 1, 4);
97111 vec5[0] == 0;
7171 iter(econtinue, fail);
7272 iter(ebreak, fail);
7373 iter(efield, seq.bind("EConst(CString(foo,DoubleQuotes))"));
74 iter(eparenthesis, seq.bind("EConst(CInt(1))"));
75 iter(euntyped, seq.bind("EConst(CInt(1))"));
76 iter(ethrow, seq.bind("EConst(CInt(1))"));
77 iter(eunop, seq.bind("EConst(CInt(1))"));
78 iter(ecast, seq.bind("EConst(CInt(1))"));
79 iter(emeta, seq.bind("EConst(CInt(1))"));
80 check(earray, ["EConst(CInt(1))", "EConst(CInt(0))"]);
81 check(ewhile1, ["EConst(CInt(1))", "EConst(CString(foo,DoubleQuotes))"]);
82 check(ewhile2, ["EConst(CInt(1))", "EConst(CString(foo,DoubleQuotes))"]);
83 check(ebinop, ["EConst(CInt(1))", "EConst(CInt(1))"]);
84 check(efor, ["EConst(CInt(1))", "EConst(CString(foo,DoubleQuotes))"]);
85 check(ein, ["EConst(CIdent(i))", "EConst(CInt(1))"]);
86 check(evars, ["EConst(CInt(1))", "EConst(CInt(2))"]);
87 check(etry, ["EConst(CInt(1))", "EConst(CString(foo,DoubleQuotes))", "EConst(CString(bar,DoubleQuotes))"]);
88 check(eternary, ["EConst(CInt(1))", "EConst(CInt(2))", "EConst(CInt(3))"]);
89 check(earraydecl, ["EConst(CInt(1))", "EConst(CInt(2))"]);
90 check(enew, ["EConst(CInt(1))", "EConst(CInt(2))"]);
91 check(eblock, ["EConst(CInt(1))", "EConst(CInt(2))"]);
92 check(eobjectdecl, ["EConst(CInt(1))", "EConst(CInt(2))"]);
93 check(ecall, ["EConst(CIdent(foo))", "EConst(CInt(1))", "EConst(CInt(2))"]);
94 check(ereturn, ["EConst(CInt(1))"]);
95 check(efunction, ["EConst(CInt(1))", "EConst(CInt(2))", "EConst(CInt(3))"]);
96 check(eswitch, ["EConst(CInt(1))", "EConst(CInt(2))", "EConst(CInt(3))", "EConst(CInt(4))", "EConst(CInt(5))", "EConst(CInt(6))"]);
74 iter(eparenthesis, seq.bind("EConst(CInt(1,null))"));
75 iter(euntyped, seq.bind("EConst(CInt(1,null))"));
76 iter(ethrow, seq.bind("EConst(CInt(1,null))"));
77 iter(eunop, seq.bind("EConst(CInt(1,null))"));
78 iter(ecast, seq.bind("EConst(CInt(1,null))"));
79 iter(emeta, seq.bind("EConst(CInt(1,null))"));
80 check(earray, ["EConst(CInt(1,null))", "EConst(CInt(0,null))"]);
81 check(ewhile1, ["EConst(CInt(1,null))", "EConst(CString(foo,DoubleQuotes))"]);
82 check(ewhile2, ["EConst(CInt(1,null))", "EConst(CString(foo,DoubleQuotes))"]);
83 check(ebinop, ["EConst(CInt(1,null))", "EConst(CInt(1,null))"]);
84 check(efor, ["EConst(CInt(1,null))", "EConst(CString(foo,DoubleQuotes))"]);
85 check(ein, ["EConst(CIdent(i))", "EConst(CInt(1,null))"]);
86 check(evars, ["EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
87 check(etry, ["EConst(CInt(1,null))", "EConst(CString(foo,DoubleQuotes))", "EConst(CString(bar,DoubleQuotes))"]);
88 check(eternary, ["EConst(CInt(1,null))", "EConst(CInt(2,null))", "EConst(CInt(3,null))"]);
89 check(earraydecl, ["EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
90 check(enew, ["EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
91 check(eblock, ["EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
92 check(eobjectdecl, ["EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
93 check(ecall, ["EConst(CIdent(foo))", "EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
94 check(ereturn, ["EConst(CInt(1,null))"]);
95 check(efunction, ["EConst(CInt(1,null))", "EConst(CInt(2,null))", "EConst(CInt(3,null))"]);
96 check(eswitch, ["EConst(CInt(1,null))", "EConst(CInt(2,null))", "EConst(CInt(3,null))", "EConst(CInt(4,null))", "EConst(CInt(5,null))", "EConst(CInt(6,null))"]);
9797
9898 // map
9999 function wrap(e) return macro ($e);
00 #if sys
1
2 #if !(php && Windows)
31
42 // bind & listen
53 var s = new sys.net.Socket();
6058 c.close();
6159 s.close();
6260
63 #else //!(php && Windows)
64 1 == 1;
65 #end
66
6761 #else
6862 1 == 1;
6963 #end
5555 <div id="php_container" class="cont"><iframe src="bin/php/index.php"></iframe></div>
5656 </div>
5757 <div class="window">
58 <div class="label">Flash 9</div>
58 <div class="label">Flash</div>
5959 <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
6060 width="400"
6161 height="300"
62 id="haxeFlash9"
62 id="haxeFlash"
6363 align="middle">
64 <param name="movie" value="bin/unit9.swf"/>
64 <param name="movie" value="bin/unit.swf"/>
6565 <param name="allowScriptAccess" value="always" />
6666 <param name="quality" value="high" />
6767 <param name="scale" value="noscale" />
6868 <param name="salign" value="lt" />
6969 <param name="bgcolor" value="#ffffff"/>
70 <embed src="bin/unit9.swf"
70 <embed src="bin/unit.swf"
7171 bgcolor="#ffffff"
7272 width="400"
7373 height="300"
74 name="haxeFlash9"
74 name="haxeFlash"
7575 quality="high"
7676 align="middle"
7777 allowScriptAccess="always"