Comparar commits
29 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| e8141ac49d | |||
| 4cf537888b | |||
| 2752b5bbb1 | |||
| cc6cbf3852 | |||
| 1a4fac8a25 | |||
| ae6443500e | |||
| e42452e4f2 | |||
| 1dd7e6165e | |||
| 01ef59346e | |||
| 9380a44469 | |||
| 3f859af167 | |||
| 55ecfbdbb6 | |||
| f951cb8d88 | |||
| 2a3225ecd0 | |||
| 65cfdabb76 | |||
| 25a26c6bd7 | |||
| 3effbfe5d1 | |||
| 3a708166b8 | |||
| 3c17422435 | |||
| d3f23f393f | |||
| 3fa32fab6e | |||
| 075cb79c9f | |||
| a1f2c80031 | |||
| 4e791cc4b6 | |||
| e62e500a84 | |||
| bab7343e83 | |||
| ef3d8e9fc5 | |||
| 9401291363 | |||
| f0665f2e92 |
+12
-2
@@ -32,8 +32,18 @@ hphp.log
|
||||
/hphp/hhvm/gen
|
||||
/hphp/hhvm/hhvm
|
||||
|
||||
*.ext_hhvm.cpp
|
||||
*.ext_hhvm.h
|
||||
/hphp/runtime/ext/*.ext_hhvm.cpp
|
||||
/hphp/runtime/ext/*.ext_hhvm.h
|
||||
/hphp/runtime/ext/*/*.ext_hhvm.cpp
|
||||
/hphp/runtime/ext/*/*.ext_hhvm.h
|
||||
/hphp/runtime/ext/*/*/*.ext_hhvm.h
|
||||
/hphp/runtime/ext/*/*/*.ext_hhvm.cpp
|
||||
/hphp/runtime/ext_zend_compat/*/*.ext_hhvm.cpp
|
||||
/hphp/runtime/ext_zend_compat/*/*.ext_hhvm.h
|
||||
/hphp/runtime/ext_zend_compat/*/*/*.ext_hhvm.cpp
|
||||
/hphp/runtime/ext_zend_compat/*/*/*.ext_hhvm.h
|
||||
/hphp/runtime/base/builtin-functions.cpp.ext_hhvm.cpp
|
||||
/hphp/runtime/base/builtin-functions.cpp.ext_hhvm.h
|
||||
/hphp/runtime/ext_hhvm/ext_hhvm_infotabs.cpp
|
||||
/hphp/runtime/ext_hhvm/ext_hhvm_infotabs.h
|
||||
|
||||
|
||||
+8
-19
@@ -4,34 +4,23 @@ compiler:
|
||||
- gcc
|
||||
|
||||
before_script:
|
||||
- time TRAVIS=1 ./configure_ubuntu_12.04.sh
|
||||
- TRAVIS=1 ./configure_ubuntu_12.04.sh
|
||||
# for some tests
|
||||
- time sudo locale-gen de_DE && sudo locale-gen zh_CN.utf8 && sudo locale-gen fr_FR
|
||||
- time HPHP_HOME=`pwd` make -j 6
|
||||
# mysql configuration for unit-tests
|
||||
- mysql -e 'CREATE DATABASE IF NOT EXISTS hhvm;'
|
||||
- export PDO_MYSQL_TEST_DSN="mysql:host=127.0.0.1;dbname=hhvm"
|
||||
- export PDO_MYSQL_TEST_USER="travis"
|
||||
- export PDO_MYSQL_TEST_PASS=""
|
||||
- sudo locale-gen de_DE && sudo locale-gen zh_CN.utf8 && sudo locale-gen fr_FR
|
||||
- HPHP_HOME=`pwd` make -j 6
|
||||
|
||||
# Test suites take longer to run in RepoAuthoritative mode (-r) than normal so
|
||||
# split out the -r from normal runs and further split the -r runs by suite to
|
||||
# avoid the possibility of slower machines exceeding the 50 minute test timeout
|
||||
env:
|
||||
- TEST_RUN_MODE="-m jit quick"
|
||||
- TEST_RUN_MODE="-m jit slow"
|
||||
- TEST_RUN_MODE="-m jit zend"
|
||||
- TEST_RUN_MODE="-m jit -r quick"
|
||||
- TEST_RUN_MODE="-m jit -r slow"
|
||||
- TEST_RUN_MODE="-m jit all"
|
||||
- TEST_RUN_MODE="-m interp all"
|
||||
- TEST_RUN_MODE="-m jit -r quick slow"
|
||||
- TEST_RUN_MODE="-m interp -r quick slow"
|
||||
- TEST_RUN_MODE="-m jit -r zend"
|
||||
- TEST_RUN_MODE="-m interp quick"
|
||||
- TEST_RUN_MODE="-m interp slow"
|
||||
- TEST_RUN_MODE="-m interp zend"
|
||||
- TEST_RUN_MODE="-m interp -r quick"
|
||||
- TEST_RUN_MODE="-m interp -r slow"
|
||||
- TEST_RUN_MODE="-m interp -r zend"
|
||||
|
||||
script: time hphp/hhvm/hhvm hphp/test/run $TEST_RUN_MODE
|
||||
script: hphp/hhvm/hhvm hphp/test/run $TEST_RUN_MODE
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
option(ENABLE_ZEND_COMPAT "Enable Zend source compatibility (beta)" OFF)
|
||||
|
||||
set(ZEND_COMPAT_PROJECTS)
|
||||
set(ZEND_COMPAT_BUILD_DIRS)
|
||||
set(ZEND_COMPAT_EXCLUDE_IDLS)
|
||||
set(ZEND_COMPAT_LINK_LIBRARIES)
|
||||
|
||||
# Look for projects
|
||||
set(EZC_DIR "${HPHP_HOME}/hphp/runtime/ext_zend_compat/")
|
||||
file(GLOB ezc_projects RELATIVE ${EZC_DIR} "${EZC_DIR}/*")
|
||||
foreach(ezc_project ${ezc_projects})
|
||||
get_filename_component(ezc_name ${ezc_project} NAME)
|
||||
if ((NOT ${ezc_name} STREQUAL "php-src") AND (IS_DIRECTORY "${EZC_DIR}/${ezc_name}"))
|
||||
list(APPEND ZEND_COMPAT_PROJECTS ${ezc_name})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (ENABLE_ZEND_COMPAT)
|
||||
foreach(ezc_project ${ZEND_COMPAT_PROJECTS})
|
||||
if (${ezc_project} STREQUAL "yaml")
|
||||
find_package(LibYaml)
|
||||
if (LibYaml_INCLUDE_DIRS)
|
||||
list(APPEND ZEND_COMPAT_BUILD_DIRS "${EZC_DIR}/yaml")
|
||||
include_directories(${LibYaml_INCLUDE_DIRS})
|
||||
list(APPEND ZEND_COMPAT_LINK_LIBRARIES ${LibYaml_LIBRARIES})
|
||||
else()
|
||||
list(APPEND ZEND_COMPAT_EXCLUDE_IDLS "yaml.idl.json")
|
||||
endif()
|
||||
elseif (${ezc_project} STREQUAL "mongo")
|
||||
include_directories("${EZC_DIR}/mongo/mcon")
|
||||
list(APPEND ZEND_COMPAT_BUILD_DIRS "${EZC_DIR}/mongo")
|
||||
else()
|
||||
list(APPEND ZEND_COMPAT_BUILD_DIRS "${EZC_DIR}/${ezc_project}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (ZEND_COMPAT_BUILD_DIRS)
|
||||
list(APPEND ZEND_COMPAT_BUILD_DIRS "${EZC_DIR}/php-src")
|
||||
include_directories("${EZC_DIR}/php-src")
|
||||
include_directories("${EZC_DIR}/php-src/main")
|
||||
include_directories("${EZC_DIR}/php-src/Zend")
|
||||
include_directories("${EZC_DIR}/php-src/TSRM")
|
||||
endif()
|
||||
else()
|
||||
foreach(ezc_project ${ZEND_COMPAT_PROJECTS})
|
||||
list(APPEND ZEND_COMPAT_EXCLUDE_IDLS "${ezc_project}.idl.json")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# This is really ugly, but cmake's list(FIND)
|
||||
# doesn't entirely work the way it should
|
||||
macro(ZEND_COMPAT_STRIP_IDLS IDLS)
|
||||
foreach(idl ${${IDLS}})
|
||||
get_filename_component(idl_name ${idl} NAME)
|
||||
foreach(f ${ARGV})
|
||||
if (${idl_name} STREQUAL ${f})
|
||||
list(REMOVE_ITEM ${IDLS} ${idl})
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endmacro()
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_FREETYPE QUIET freetype2)
|
||||
|
||||
find_path(FREETYPE_INCLUDE_DIRS NAMES freetype/config/ftheader.h
|
||||
HINTS ${PC_FREETYPE_INCLUDEDIR} ${PC_FREETYPE_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES freetype2)
|
||||
|
||||
find_library(FREETYPE_LIBRARIES NAMES freetype)
|
||||
|
||||
include (FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Freetype DEFAULT_MSG
|
||||
FREETYPE_LIBRARIES
|
||||
FREETYPE_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(FREETYPE_INCLUDE_DIRS FREETYPE_LIBRARIES)
|
||||
@@ -0,0 +1,121 @@
|
||||
# - Find GD
|
||||
# Find the native GD includes and library
|
||||
# This module defines
|
||||
# GD_INCLUDE_DIR, where to find gd.h, etc.
|
||||
# GD_LIBRARIES, the libraries needed to use GD.
|
||||
# GD_FOUND, If false, do not try to use GD.
|
||||
# also defined, but not for general use are
|
||||
# GD_LIBRARY, where to find the GD library.
|
||||
# GD_SUPPORTS_PNG, GD_SUPPORTS_JPEG, GD_SUPPORTS_GIF, test
|
||||
# support for image formats in GD.
|
||||
|
||||
FIND_PATH(GD_INCLUDE_DIR gd.h
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
if(WIN32 AND NOT CYGWIN)
|
||||
SET(GD_NAMES ${GD_NAMES} bgd)
|
||||
else(WIN32)
|
||||
SET(GD_NAMES ${GD_NAMES} gd)
|
||||
endif(WIN32 AND NOT CYGWIN)
|
||||
|
||||
FIND_LIBRARY(GD_LIBRARY
|
||||
NAMES ${GD_NAMES}
|
||||
PATHS /usr/lib64 /usr/lib /usr/local/lib
|
||||
)
|
||||
|
||||
IF (GD_LIBRARY AND GD_INCLUDE_DIR)
|
||||
SET(GD_LIBRARIES ${GD_LIBRARY})
|
||||
SET(GD_FOUND "YES")
|
||||
ELSE (GD_LIBRARY AND GD_INCLUDE_DIR)
|
||||
SET(GD_FOUND "NO")
|
||||
ENDIF (GD_LIBRARY AND GD_INCLUDE_DIR)
|
||||
|
||||
IF (GD_FOUND)
|
||||
IF (WIN32 AND NOT CYGWIN)
|
||||
SET(GD_SUPPORTS_PNG ON)
|
||||
SET(GD_SUPPORTS_JPEG ON)
|
||||
SET(GD_SUPPORTS_GIF ON)
|
||||
get_filename_component(GD_LIBRARY_DIR ${GD_LIBRARY} PATH)
|
||||
ELSE (WIN32 AND NOT CYGWIN)
|
||||
INCLUDE(CheckLibraryExists)
|
||||
GET_FILENAME_COMPONENT(GD_LIB_PATH ${GD_LIBRARY} PATH)
|
||||
GET_FILENAME_COMPONENT(GD_LIB ${GD_LIBRARY} NAME)
|
||||
|
||||
CHECK_LIBRARY_EXISTS("${GD_LIBRARY}" "gdImagePng" "${GD_LIB_PATH}" GD_SUPPORTS_PNG)
|
||||
IF (GD_SUPPORTS_PNG)
|
||||
find_package(PNG)
|
||||
IF (PNG_FOUND)
|
||||
SET(GD_LIBRARIES ${GD_LIBRARIES} ${PNG_LIBRARIES})
|
||||
SET(GD_INCLUDE_DIR ${GD_INCLUDE_DIR} ${PNG_INCLUDE_DIR})
|
||||
ELSE (PNG_FOUND)
|
||||
SET(GD_SUPPORTS_PNG "NO")
|
||||
ENDIF (PNG_FOUND)
|
||||
ENDIF (GD_SUPPORTS_PNG)
|
||||
|
||||
CHECK_LIBRARY_EXISTS("${GD_LIBRARY}" "gdImageJpeg" "${GD_LIB_PATH}" GD_SUPPORTS_JPEG)
|
||||
IF (GD_SUPPORTS_JPEG)
|
||||
find_package(JPEG)
|
||||
IF (JPEG_FOUND)
|
||||
SET(GD_LIBRARIES ${GD_LIBRARIES} ${JPEG_LIBRARIES})
|
||||
SET(GD_INCLUDE_DIR ${GD_INCLUDE_DIR} ${JPEG_INCLUDE_DIR})
|
||||
ELSE (JPEG_FOUND)
|
||||
SET(GD_SUPPORTS_JPEG "NO")
|
||||
ENDIF (JPEG_FOUND)
|
||||
ENDIF (GD_SUPPORTS_JPEG)
|
||||
|
||||
CHECK_LIBRARY_EXISTS("${GD_LIBRARY}" "gdImageGif" "${GD_LIB_PATH}" GD_SUPPORTS_GIF)
|
||||
|
||||
# Trim the list of include directories
|
||||
SET(GDINCTRIM)
|
||||
FOREACH(GD_DIR ${GD_INCLUDE_DIR})
|
||||
SET(GD_TMP_FOUND OFF)
|
||||
FOREACH(GD_TRIMMED ${GDINCTRIM})
|
||||
IF ("${GD_DIR}" STREQUAL "${GD_TRIMMED}")
|
||||
SET(GD_TMP_FOUND ON)
|
||||
ENDIF ("${GD_DIR}" STREQUAL "${GD_TRIMMED}")
|
||||
ENDFOREACH(GD_TRIMMED ${GDINCTRIM})
|
||||
IF (NOT GD_TMP_FOUND)
|
||||
SET(GDINCTRIM "${GDINCTRIM}" "${GD_DIR}")
|
||||
ENDIF (NOT GD_TMP_FOUND)
|
||||
ENDFOREACH(GD_DIR ${GD_INCLUDE_DIR})
|
||||
SET(GD_INCLUDE_DIR ${GDINCTRIM})
|
||||
|
||||
SET(GD_LIBRARY_DIR)
|
||||
|
||||
# Generate trimmed list of library directories and list of libraries
|
||||
FOREACH(GD_LIB ${GD_LIBRARIES})
|
||||
GET_FILENAME_COMPONENT(GD_NEXTLIBDIR ${GD_LIB} PATH)
|
||||
SET(GD_TMP_FOUND OFF)
|
||||
FOREACH(GD_LIBDIR ${GD_LIBRARY_DIR})
|
||||
IF ("${GD_NEXTLIBDIR}" STREQUAL "${GD_LIBDIR}")
|
||||
SET(GD_TMP_FOUND ON)
|
||||
ENDIF ("${GD_NEXTLIBDIR}" STREQUAL "${GD_LIBDIR}")
|
||||
ENDFOREACH(GD_LIBDIR ${GD_LIBRARIES})
|
||||
IF (NOT GD_TMP_FOUND)
|
||||
SET(GD_LIBRARY_DIR "${GD_LIBRARY_DIR}" "${GD_NEXTLIBDIR}")
|
||||
ENDIF (NOT GD_TMP_FOUND)
|
||||
ENDFOREACH(GD_LIB ${GD_LIBRARIES})
|
||||
ENDIF (WIN32 AND NOT CYGWIN)
|
||||
ENDIF (GD_FOUND)
|
||||
|
||||
IF (GD_FOUND)
|
||||
IF (NOT GD_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found GD: ${GD_LIBRARY}")
|
||||
ENDIF (NOT GD_FIND_QUIETLY)
|
||||
ELSE (GD_FOUND)
|
||||
IF (GD_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find GD library")
|
||||
ENDIF (GD_FIND_REQUIRED)
|
||||
ENDIF (GD_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
GD_LIBRARY
|
||||
GD_LIBRARIES
|
||||
GD_INCLUDE_DIR
|
||||
GD_LIBRARY_DIR
|
||||
GD_SUPPORTS_PNG
|
||||
GD_SUPPORTS_JPEG
|
||||
GD_SUPPORTS_GIF
|
||||
)
|
||||
@@ -18,7 +18,7 @@ endif (LIBDWARF_LIBRARIES AND LIBDWARF_INCLUDE_DIRS)
|
||||
|
||||
find_path (DWARF_INCLUDE_DIR
|
||||
NAMES
|
||||
libdwarf.h dwarf.h
|
||||
dwarf.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/include/libdwarf
|
||||
@@ -50,13 +50,5 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibDwarf DEFAULT_MSG
|
||||
LIBDWARF_LIBRARIES
|
||||
LIBDWARF_INCLUDE_DIRS)
|
||||
|
||||
if (LIBDWARF_LIBRARIES AND LIBDWARF_INCLUDE_DIRS)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${LIBDWARF_INCLUDE_DIRS})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${LIBDWARF_LIBRARIES})
|
||||
include(CheckSymbolExists)
|
||||
CHECK_SYMBOL_EXISTS(dwarf_encode_leb128 "libdwarf.h" LIBDWARF_HAVE_ENCODE_LEB128)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(LIBDW_INCLUDE_DIR DWARF_INCLUDE_DIR)
|
||||
mark_as_advanced(LIBDWARF_INCLUDE_DIRS LIBDWARF_LIBRARIES)
|
||||
mark_as_advanced(LIBDWARF_HAVE_ENCODE_LEB128)
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
if (LIBJPEG_LIBRARIES AND LIBJPEG_INCLUDE_DIRS)
|
||||
set (LibJpeg_FIND_QUIETLY TRUE)
|
||||
endif (LIBJPEG_LIBRARIES AND LIBJPEG_INCLUDE_DIRS)
|
||||
|
||||
find_path(LIBJPEG_INCLUDE_DIRS NAMES jpeglib.h)
|
||||
find_library(LIBJPEG_LIBRARIES NAMES jpeg)
|
||||
|
||||
include (FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibJpeg DEFAULT_MSG
|
||||
LIBJPEG_LIBRARIES
|
||||
LIBJPEG_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(LIBJPEG_INCLUDE_DIRS LIBJPEG_LIBRARIES)
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
if (LIBPNG_LIBRARIES AND LIBPNG_INCLUDE_DIRS)
|
||||
set (LibPng_FIND_QUIETLY TRUE)
|
||||
endif (LIBPNG_LIBRARIES AND LIBPNG_INCLUDE_DIRS)
|
||||
|
||||
find_path(LIBPNG_INCLUDE_DIRS NAMES png.h)
|
||||
find_library(LIBPNG_LIBRARIES NAMES png)
|
||||
|
||||
include (FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibPng DEFAULT_MSG
|
||||
LIBPNG_LIBRARIES
|
||||
LIBPNG_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(LIBPNG_INCLUDE_DIRS LIBPNG_LIBRARIES)
|
||||
@@ -1,12 +0,0 @@
|
||||
if (LIBODBC_LIBRARIES AND LIBODBC_INCLUDE_DIRS)
|
||||
set (LibUODBC_FIND_QUIETLY TRUE)
|
||||
endif (LIBODBC_LIBRARIES AND LIBODBC_INCLUDE_DIRS)
|
||||
|
||||
find_path (LIBODBC_INCLUDE_DIRS NAMES sqlext.h)
|
||||
find_library (LIBODBC_LIBRARIES NAMES odbc)
|
||||
include (FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUODBC DEFAULT_MSG
|
||||
LIBODBC_LIBRARIES
|
||||
LIBODBC_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(LIBODBC_INCLUDE_DIRS LIBODBC_LIBRARIES)
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
if (LIBVPX_LIBRARIES AND LIBVPX_INCLUDE_DIRS)
|
||||
set (LibVpx_FIND_QUIETLY TRUE)
|
||||
endif (LIBVPX_LIBRARIES AND LIBVPX_INCLUDE_DIRS)
|
||||
|
||||
find_path(LIBVPX_INCLUDE_DIRS NAMES vpx_codec.h)
|
||||
find_library(LIBVPX_LIBRARIES NAMES vpx)
|
||||
|
||||
include (FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibVpx DEFAULT_MSG
|
||||
LIBVPX_LIBRARIES
|
||||
LIBVPX_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(LIBVPX_INCLUDE_DIRS LIBVPX_LIBRARIES)
|
||||
@@ -1,13 +0,0 @@
|
||||
if (LibYaml_LIBRARIES AND LibYaml_INCLUDE_DIRS)
|
||||
set (LibYaml_FIND_QUIETLY TRUE)
|
||||
endif (LibYaml_LIBRARIES AND LibYaml_INCLUDE_DIRS)
|
||||
|
||||
find_path (LibYaml_INCLUDE_DIRS NAMES yaml.h)
|
||||
find_library (LibYaml_LIBRARIES NAMES yaml)
|
||||
|
||||
include (FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibYaml DEFAULT_MSG
|
||||
LibYaml_LIBRARIES
|
||||
LibYaml_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(LibYaml_INCLUDE_DIRS LibYaml_LIBRARIES)
|
||||
@@ -13,8 +13,11 @@ if (FOLLY_IFUNC)
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES rt)
|
||||
include(CheckFunctionExists)
|
||||
CHECK_FUNCTION_EXISTS("clock_gettime" HAVE_CLOCK_GETTIME)
|
||||
CHECK_CXX_SOURCE_COMPILES("#include <time.h>
|
||||
int main() {
|
||||
clock_gettime((clockid_t)0, NULL);
|
||||
return 0;
|
||||
}" HAVE_CLOCK_GETTIME)
|
||||
|
||||
if (HAVE_CLOCK_GETTIME)
|
||||
add_definitions("-DFOLLY_HAVE_CLOCK_GETTIME=1")
|
||||
|
||||
@@ -39,11 +39,7 @@ else()
|
||||
set(GNUCC_48_OPT "-Wno-unused-local-typedefs -fno-canonical-system-headers -Wno-deprecated-declarations")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "-w")
|
||||
set(CMAKE_CXX_FLAGS "-fno-gcse -fno-omit-frame-pointer -ftemplate-depth-180 -Wall -Woverloaded-virtual -Wno-deprecated -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names -Wno-error=array-bounds -Wno-error=switch -std=gnu++11 -Werror=format-security -Wno-unused-result -Wno-sign-compare -Wno-attributes -Wno-maybe-uninitialized -mcrc32 ${GNUCC_48_OPT}")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_CXX_COMPILER} MATCHES ".*clang.*")
|
||||
set(CMAKE_CXX_FLAGS "-fno-gcse -fno-omit-frame-pointer -ftemplate-depth-180 -Wall -Woverloaded-virtual -Wno-deprecated -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names -Wno-error=array-bounds -Wno-error=switch -std=gnu++11 -Werror=format-security -Wno-unused-result -Wno-sign-compare -Wno-attributes -Wno-maybe-uninitialized -Wno-mismatched-tags -Wno-unknown-warning-option -Wno-return-type-c-linkage -Qunused-arguments")
|
||||
set(CMAKE_CXX_FLAGS "-fno-gcse -fno-omit-frame-pointer -ftemplate-depth-180 -Wall -Woverloaded-virtual -Wno-deprecated -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names -Wno-error=array-bounds -Wno-error=switch -std=gnu++11 -Werror=format-security -Wno-unused-result -Wno-sign-compare -Wno-attributes -Wno-maybe-uninitialized ${GNUCC_48_OPT}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
|
||||
@@ -96,40 +96,13 @@ if(HAVE_CUSTOM_LIBEVENT)
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_LIBRARIES)
|
||||
|
||||
find_package(LibUODBC)
|
||||
if (LIBUODBC_INCLUDE_DIRS)
|
||||
include_directories(${LIBUODBC_INCLUDE_DIRS})
|
||||
add_definitions("-DHAVE_UODBC")
|
||||
endif ()
|
||||
|
||||
# GD checks
|
||||
add_definitions(-DPNG_SKIP_SETJMP_CHECK)
|
||||
find_package(LibVpx)
|
||||
if (LIBVPX_INCLUDE_DIRS)
|
||||
include_directories(${LIBVPX_INCLUDE_DIRS})
|
||||
add_definitions("-DHAVE_GD_WEBP")
|
||||
endif()
|
||||
find_package(LibJpeg)
|
||||
if (LIBJPEG_INCLUDE_DIRS)
|
||||
include_directories(${LIBJPEG_INCLUDE_DIRS})
|
||||
add_definitions("-DHAVE_GD_JPG")
|
||||
endif()
|
||||
find_package(LibPng)
|
||||
if (LIBPNG_INCLUDE_DIRS)
|
||||
include_directories(${LIBPNG_INCLUDE_DIRS})
|
||||
add_definitions("-DHAVE_GD_PNG")
|
||||
endif()
|
||||
find_package(Freetype)
|
||||
if (FREETYPE_INCLUDE_DIRS)
|
||||
include_directories(${FREETYPE_INCLUDE_DIRS})
|
||||
add_definitions("-DHAVE_LIBFREETYPE -DHAVE_GD_FREETYPE -DENABLE_GD_TTF")
|
||||
endif()
|
||||
find_package(GD REQUIRED)
|
||||
|
||||
# libXed
|
||||
find_package(LibXed)
|
||||
if (LibXed_INCLUDE_DIR AND LibXed_LIBRARY)
|
||||
include_directories(${LibXed_INCLUDE_DIR})
|
||||
add_definitions("-DHAVE_LIBXED")
|
||||
add_definitions(-DHAVE_LIBXED)
|
||||
endif()
|
||||
|
||||
# CURL checks
|
||||
@@ -319,9 +292,6 @@ include_directories(${CCLIENT_INCLUDE_PATH})
|
||||
|
||||
find_package(LibDwarf REQUIRED)
|
||||
include_directories(${LIBDWARF_INCLUDE_DIRS})
|
||||
if (LIBDWARF_HAVE_ENCODE_LEB128)
|
||||
add_definitions("-DHAVE_LIBDWARF_20130729")
|
||||
endif()
|
||||
|
||||
find_package(LibElf REQUIRED)
|
||||
include_directories(${LIBELF_INCLUDE_DIRS})
|
||||
@@ -335,26 +305,15 @@ if (NOT RECENT_CCLIENT)
|
||||
message(FATAL_ERROR "Your version of c-client is too old, you need 2007")
|
||||
endif()
|
||||
|
||||
|
||||
if (EXISTS "${CCLIENT_INCLUDE_PATH}/linkage.c")
|
||||
CONTAINS_STRING("${CCLIENT_INCLUDE_PATH}/linkage.c" auth_gss CCLIENT_HAS_GSS)
|
||||
elseif (EXISTS "${CCLIENT_INCLUDE_PATH}/linkage.h")
|
||||
CONTAINS_STRING("${CCLIENT_INCLUDE_PATH}/linkage.h" auth_gss CCLIENT_HAS_GSS)
|
||||
endif()
|
||||
|
||||
find_package(Libpam)
|
||||
if (PAM_INCLUDE_PATH)
|
||||
include_directories(${PAM_INCLUDE_PATH})
|
||||
endif()
|
||||
|
||||
if (NOT CCLIENT_HAS_GSS)
|
||||
else()
|
||||
add_definitions(-DSKIP_IMAP_GSS=1)
|
||||
endif()
|
||||
|
||||
if (EXISTS "${CCLIENT_INCLUDE_PATH}/linkage.c")
|
||||
CONTAINS_STRING("${CCLIENT_INCLUDE_PATH}/linkage.c" ssl_onceonlyinit CCLIENT_HAS_SSL)
|
||||
elseif (EXISTS "${CCLIENT_INCLUDE_PATH}/linkage.h")
|
||||
CONTAINS_STRING("${CCLIENT_INCLUDE_PATH}/linkage.h" ssl_onceonlyinit CCLIENT_HAS_SSL)
|
||||
endif()
|
||||
|
||||
if (NOT CCLIENT_HAS_SSL)
|
||||
@@ -488,21 +447,7 @@ endif()
|
||||
target_link_libraries(${target} ${ONIGURUMA_LIBRARIES})
|
||||
target_link_libraries(${target} ${Mcrypt_LIB})
|
||||
target_link_libraries(${target} ${GD_LIBRARY})
|
||||
if (FREETYPE_LIBRARIES)
|
||||
target_link_libraries(${target} ${FREETYPE_LIBRARIES})
|
||||
endif()
|
||||
if (LIBJPEG_LIBRARIES)
|
||||
target_link_libraries(${target} ${LIBJPEG_LIBRARIES})
|
||||
endif()
|
||||
if (LIBPNG_LIBRARIES)
|
||||
target_link_libraries(${target} ${LIBPNG_LIBRARIES})
|
||||
endif()
|
||||
if (LIBVPX_LIBRARIES)
|
||||
target_link_libraries(${target} ${LIBVPX_LIBRARIES})
|
||||
endif()
|
||||
if (LIBUODBC_LIBRARIES)
|
||||
target_link_libraries(${target} ${LIBUODBC_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${target} ${LDAP_LIBRARIES})
|
||||
target_link_libraries(${target} ${LBER_LIBRARIES})
|
||||
|
||||
|
||||
@@ -38,27 +38,6 @@ function(auto_sources RETURN_VALUE PATTERN SOURCE_SUBDIRS)
|
||||
set(${RETURN_VALUE} ${${RETURN_VALUE}} PARENT_SCOPE)
|
||||
endfunction(auto_sources)
|
||||
|
||||
macro(HHVM_SELECT_SOURCES DIR)
|
||||
auto_sources(files "*.cpp" "RECURSE" "${DIR}")
|
||||
foreach(f ${files})
|
||||
if (NOT (${f} MATCHES "(ext_hhvm|/(old-)?tests?/)"))
|
||||
list(APPEND CXX_SOURCES ${f})
|
||||
endif()
|
||||
endforeach()
|
||||
auto_sources(files "*.c" "RECURSE" "${DIR}")
|
||||
foreach(f ${files})
|
||||
if (NOT (${f} MATCHES "(ext_hhvm|/(old-)?tests?/)"))
|
||||
list(APPEND C_SOURCES ${f})
|
||||
endif()
|
||||
endforeach()
|
||||
auto_sources(files "*.S" "RECURSE" "${DIR}")
|
||||
foreach(f ${files})
|
||||
if (NOT (${f} MATCHES "(ext_hhvm|/(old-)?tests?/)"))
|
||||
list(APPEND ASM_SOURCES ${f})
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro(HHVM_SELECT_SOURCES)
|
||||
|
||||
function(CONTAINS_STRING FILE SEARCH RETURN_VALUE)
|
||||
file(STRINGS ${FILE} FILE_CONTENTS REGEX ".*${SEARCH}.*")
|
||||
if (FILE_CONTENTS)
|
||||
|
||||
@@ -62,7 +62,8 @@ include(HPHPCompiler)
|
||||
include(HPHPFunctions)
|
||||
include(HPHPFindLibs)
|
||||
|
||||
add_definitions(-D_REENTRANT=1 -D_PTHREADS=1 -D__STDC_FORMAT_MACROS -DFOLLY_HAVE_WEAK_SYMBOLS=1)
|
||||
add_definitions(-D_REENTRANT=1 -D_PTHREADS=1 -D__STDC_FORMAT_MACROS)
|
||||
add_definitions(-DHHVM_LIB_PATH_DEFAULT="${HPHP_HOME}/bin")
|
||||
|
||||
if (LINUX)
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
@@ -123,10 +124,6 @@ if(ENABLE_FASTCGI)
|
||||
add_definitions(-DENABLE_FASTCGI=1)
|
||||
endif ()
|
||||
|
||||
if(DISABLE_HARDWARE_COUNTERS)
|
||||
add_definitions(-DNO_HARDWARE_COUNTERS=1)
|
||||
endif ()
|
||||
|
||||
# enable the OSS options if we have any
|
||||
add_definitions(-DHPHP_OSS=1)
|
||||
|
||||
|
||||
@@ -13,6 +13,3 @@ option(USE_JEMALLOC "Use jemalloc" ON)
|
||||
option(USE_TCMALLOC "Use tcmalloc (if jemalloc is not used)" ON)
|
||||
option(USE_GOOGLE_HEAP_PROFILER "Use Google heap profiler" OFF)
|
||||
option(USE_GOOGLE_CPU_PROFILER "Use Google cpu profiler" OFF)
|
||||
|
||||
option(DISABLE_HARDWARE_COUNTERS "Disable hardware counters (for XenU systems)" OFF)
|
||||
|
||||
|
||||
+21
-11
@@ -1,18 +1,18 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5 FATAL_ERROR)
|
||||
PROJECT(hphp C CXX ASM)
|
||||
|
||||
IF(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
message(FATAL_ERROR "HHVM requires a 64bit OS")
|
||||
IF("$ENV{HPHP_HOME}" STREQUAL "")
|
||||
message(FATAL_ERROR "You should set the HPHP_HOME environmental")
|
||||
ENDIF()
|
||||
|
||||
set(HPHP_HOME "$ENV{HPHP_HOME}")
|
||||
if (NOT HPHP_HOME)
|
||||
set(HPHP_HOME "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
endif()
|
||||
message("Using HPHP_HOME == ${HPHP_HOME}")
|
||||
file(TO_CMAKE_PATH "$ENV{HPHP_HOME}" HPHP_HOME)
|
||||
|
||||
IF(NOT EXISTS "${HPHP_HOME}/CMake/HPHPSetup.cmake")
|
||||
message(FATAL_ERROR "Invalid HPHP_HOME. Set it to the root of your hhvm tree, or run `cmake .` from there.")
|
||||
IF(NOT IS_DIRECTORY ${HPHP_HOME})
|
||||
message(FATAL_ERROR "The value of HPHP_HOME does not exist")
|
||||
ENDIF()
|
||||
|
||||
IF(NOT EXISTS "${HPHP_HOME}/LICENSE.PHP")
|
||||
message(FATAL_ERROR "The value of HPHP_HOME in incorrect")
|
||||
ENDIF()
|
||||
|
||||
SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
|
||||
@@ -20,5 +20,15 @@ SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/HPHPFunctions.cmake")
|
||||
include(CheckFunctionExists)
|
||||
|
||||
add_subdirectory(hphp)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/hphp)
|
||||
|
||||
IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
message(FATAL_ERROR "32-bit support is currently unsupported, check back with a later version of HipHop")
|
||||
ENDIF()
|
||||
|
||||
if ("$ENV{USE_HHVM}" STREQUAL "1")
|
||||
message("Building for HHVM")
|
||||
endif()
|
||||
if ("$ENV{USE_HPHPC}" STREQUAL "1")
|
||||
message(FATAL_ERROR "Building HPHPc is no longer supported")
|
||||
endif()
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# HHVM [](https://travis-ci.org/facebook/hhvm)
|
||||
|
||||
HHVM (aka the HipHop Virtual Machine) is a new open-source virtual machine designed for executing programs written in PHP. HHVM uses a just-in-time compilation approach to achieve superior performance while maintaining the flexibility that PHP developers are accustomed to. To date, HHVM (and its predecessor HPHPc before it) has realized over a 9x increase in web request throughput and over a 5x reduction in memory consumption for Facebook compared with the Zend PHP 5.2 engine + APC.
|
||||
HHVM (aka the HipHop Virtual Machine) is a new open-source virtual machine designed for executing programs written in PHP. HHVM uses a just-in-time compilation approach to achieve superior performance while maintaining the flexibility that PHP developers are accustomed to. To date, HHVM (and its precedessor HPHPc before it) has realized over a 9x increase in web request throughput and over a 5x reduction in memory consumption for Facebook compared with the Zend PHP 5.2 engine + APC.
|
||||
|
||||
HHVM can be run as a standalone webserver (i.e. without the Apache webserver and the "modphp" extension). HHVM can also be used together with a FastCGI-based webserver, and work is in progress to make HHVM work smoothly with Apache.
|
||||
|
||||
|
||||
externo
+1
-1
@@ -3,7 +3,7 @@
|
||||
if [ "$1" = '--help' ] || [ "$1" = '-h' ]; then
|
||||
echo 'usage: ./configure -Dvariable=argument ...\n'
|
||||
echo 'Variables: '
|
||||
echo ' CMAKE_BUILD_TYPE=Debug|Release Sets build type (default Release).'
|
||||
echo ' CMAKE_BUILD_TYPE=Debug|Release Sets build type (default Relase).'
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#########################################
|
||||
#
|
||||
# Install all the dependencies for HipHop
|
||||
# Install all the dependancies for HipHop
|
||||
#
|
||||
#########################################
|
||||
|
||||
@@ -20,12 +20,13 @@ if [ "x${TRAVIS}" != "x" ]; then
|
||||
fi
|
||||
|
||||
export CMAKE_PREFIX_PATH=`/bin/pwd`/..
|
||||
export HPHP_HOME=`/bin/pwd`
|
||||
|
||||
# install python-software-properties before trying to add a PPA
|
||||
# install python-software-properties before trying to add a PPA
|
||||
sudo apt-get -y update
|
||||
sudo apt-get install -y python-software-properties
|
||||
|
||||
# install apt-fast to speed up later dependency installation
|
||||
# install apt-fast to speedup later dependency installation
|
||||
sudo add-apt-repository -y ppa:apt-fast/stable
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install apt-fast
|
||||
@@ -123,4 +124,4 @@ cmake .
|
||||
|
||||
echo "-------------------------------------------------------------------------"
|
||||
echo "Done. Now run:"
|
||||
echo " CMAKE_PREFIX_PATH=\`pwd\`/.. make"
|
||||
echo " CMAKE_PREFIX_PATH=\`pwd\`/.. HPHP_HOME=\`pwd\` make"
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
|
||||
include(HPHPSetup)
|
||||
include(FollySetup)
|
||||
include(ExtZendCompat)
|
||||
|
||||
add_definitions("-DHHVM")
|
||||
# HHVM Build
|
||||
SET(USE_HHVM TRUE)
|
||||
SET(ENV{HHVM} 1)
|
||||
ADD_DEFINITIONS("-DHHVM -DHHVM_BINARY=1 -DHHVM_PATH=\\\"${HPHP_HOME}/hphp/hhvm/hhvm\\\"")
|
||||
|
||||
add_subdirectory(tools/bootstrap)
|
||||
|
||||
|
||||
+5
-99
@@ -1,104 +1,10 @@
|
||||
Next release
|
||||
- FrozenMap collection
|
||||
- Deprecated Vector|Set|Map::put() method removed
|
||||
- == between Frozen{Vector|Set|Map} and {Vector|Set|Map} now can return true
|
||||
- Map collections learned the in-place retain() and retainWithKey()
|
||||
- 'num' scalar typehint that accepts both ints and floats
|
||||
|
||||
"Beastie Boys" 6-Jan-2014
|
||||
- Support lex-time binary constants (eg. 0b10111)
|
||||
- StreamWrappers now support rmdir, mkdir, rename and unlink
|
||||
- Miscellaneous Zend PHP compatibility fixes
|
||||
- Default StatCache to off
|
||||
- Miscellaneous FastCGI fixes
|
||||
- Miscellaneous region compiler fixes
|
||||
- Map and StableMap collections use the same underlying implementation
|
||||
- Trait requirements enforced
|
||||
- hhprof performance improvements
|
||||
- Add array to string conversion notice
|
||||
- Add RaiseNotice IR opcode
|
||||
- Fix VirtualHost.<name>.Pattern matching
|
||||
- Fix various memory leaks (pdo_parse_params, Gen*WaitHandle)
|
||||
- Import a lot more Zend tests that used to crash or hang
|
||||
- Clean up base.h
|
||||
- XLS register allocation cleanup
|
||||
- Enable region compiler by default for JIT functions in ahot
|
||||
- Fatal on eval() in RepoAuthoritative mode
|
||||
- Enable LTO for HHVM
|
||||
- Fix a few SPL compatibility issues
|
||||
|
||||
"Appleseed" 23-Dec-2013
|
||||
- Fix issues with DOCUMENT_ROOT in fastcgi
|
||||
- Better type inference for collections and builtins in repo mode
|
||||
- Shorter syntax for lambda expressions w/ automatic captures
|
||||
- Parser support for trait require clauses
|
||||
- Move FrozenVector and Set to the HH namespace
|
||||
- Fix resource to array conversion
|
||||
- Fix a request local memory leak in foreach of apc arrays
|
||||
- Initial php_odbc API implementation
|
||||
- Implement PHP's hash_copy() function
|
||||
- Experimental tool: Memoization Opportunity Profiler
|
||||
- Various small parity/behavior fixes (in phar, proc_open, filter_var)
|
||||
- A Eval.DumpHhas=1 option to dump hhas for a php file
|
||||
- Better warnings in Set::toArray
|
||||
- Fix the behavior of foreach loops in finally blocks
|
||||
- chmod -x runtime/vm/jit/*.{cpp,h}
|
||||
- Changes to make hhvm build clean with clang-3.4
|
||||
- Fix array_product to not be bug-compatible with PHP 5.2
|
||||
- Change the Map datastructure---preserves order and does faster foreach
|
||||
- FrozenSet collection
|
||||
- Generate pid.map when we unmap text section, for the perf tool
|
||||
- Implemented GlobIterator
|
||||
- Implemented Reflection::export and Reflection::getModifierNames
|
||||
|
||||
"Tom Yum" 9-Dec-2013
|
||||
- support date.timezone in ini files
|
||||
- implement fileinfo
|
||||
- special comparisons for DateTime
|
||||
- delete unimplemented functions
|
||||
- support for the finally clause in try blocks
|
||||
|
||||
"Huarache" 26-Nov-2013
|
||||
- Linker re-ordering of hot functions
|
||||
- Huge pages for hot functions
|
||||
- Implement ZipArchive
|
||||
- preg_replace /e support
|
||||
- get_mem_usage() no longer can be negative
|
||||
- Userland file system support
|
||||
- Implement fileinfo extension
|
||||
- wordwrap() fixes
|
||||
- PDO::sqliteCreateFunction()
|
||||
- Implement NumberFormatter
|
||||
- Implement Locale
|
||||
- Implement DatePeriod
|
||||
- Many reflection fixes
|
||||
- Stub out PharData
|
||||
- A ton of performance fixes
|
||||
- A ton of open source framework fixes
|
||||
- FastCGI Server Support
|
||||
|
||||
"Garlic Alfredo" 11-Nov-2013
|
||||
- teach implode() about collections
|
||||
- fix ini parsing leak
|
||||
- Make array not an instanceof Traversable
|
||||
|
||||
"Burrito" 28-Oct-2013
|
||||
- Initial support for using FastCGI
|
||||
- Initial support for php.ini configuration files
|
||||
- Log when a nullable (e.g. ?int) is incorrect
|
||||
- Add support for collections to array_diff, array_diff_key, array_intersect,
|
||||
array_intersect_key
|
||||
- tc-print improvements and fixes
|
||||
- Several debugger fixes
|
||||
- More improvements to the experimental PHP extension compat layer
|
||||
- Fixed how parse errors are handled by eval()
|
||||
- Support custom reason for status header
|
||||
- Emit better error message when hhvm's systemlib doesn't load properly
|
||||
- Fixes / clarifications added to the bytecode specification
|
||||
- Lots of other bug fixes, clean up, PHP compat fixes, and JIT improvements
|
||||
|
||||
"Sausage" 14-Oct-2013
|
||||
- Direct invocation of callable arrays: $f = [$cls_or_obj, 'method']; $f()
|
||||
- Direct invocation of callable arrays: $f = [$cls_or_instance, 'method']; $f()
|
||||
- ASAN clean
|
||||
- Support dynamically loadable extensions
|
||||
- Support loading mini-systemlibs from extensions
|
||||
@@ -120,7 +26,7 @@ Next release
|
||||
- Support arbitrary expressions inside empty()
|
||||
|
||||
"Bobotie" 16-Sep-2013
|
||||
- HNI (HipHop Native Interface) for calling C++ functions from PHP
|
||||
- HNI (HipHop Native Interface) for calling C++ functions from Php
|
||||
- Fix PropertyAccessorMap::isset
|
||||
- Expose more POSIX constants
|
||||
- Fixed behavior of stream_get_contents when default args are used.
|
||||
@@ -134,14 +40,14 @@ Next release
|
||||
- Import ftp extension
|
||||
|
||||
"Kimchi" 2-Sep-2013
|
||||
- Fix order of custom attributes and visibility in ctor arg promotion
|
||||
- Fix order of custom attributes and visibility in ctor arg promotion
|
||||
- Implement CachingIterator
|
||||
- Implement RecursiveCachingIterator
|
||||
- Generalized heuristic for choosing when to inline in the jit
|
||||
- Introduced a Zend compatibility layer to compile extensions
|
||||
- Imported calendar extension
|
||||
- Use gcc-4.8.1 by default
|
||||
- Improve hhvm command line parsing logic
|
||||
- Improve hhvm commandline parsing logic
|
||||
- Fix register_shutdown in session_set_save_handler to match PHP 5.4
|
||||
- Add "native" functions for use in Systemlib
|
||||
- PHP extension source-compatitblility layer
|
||||
@@ -199,7 +105,7 @@ Next release
|
||||
"Wasabi Peas" 08-Jul-2013
|
||||
- always_assert when we run out of TC space
|
||||
- Initial changes to get HHVM compiling on OSX
|
||||
- Consolidate ObjectData and Instance
|
||||
- Consolodate ObjectData and Instance
|
||||
- Prototype heap tracing framework & Heap profiler
|
||||
- Better JIT code generation for Mod and Div
|
||||
- Fixes to enable compilation with clang
|
||||
|
||||
@@ -1927,7 +1927,6 @@ StatementPtr AliasManager::canonicalizeRecur(StatementPtr s, int &ret) {
|
||||
|
||||
switch (stype) {
|
||||
case Statement::KindOfUseTraitStatement:
|
||||
case Statement::KindOfTraitRequireStatement:
|
||||
case Statement::KindOfTraitPrecStatement:
|
||||
case Statement::KindOfTraitAliasStatement:
|
||||
return StatementPtr();
|
||||
@@ -1969,7 +1968,7 @@ StatementPtr AliasManager::canonicalizeRecur(StatementPtr s, int &ret) {
|
||||
}
|
||||
|
||||
case Statement::KindOfIfBranchStatement:
|
||||
always_assert(false);
|
||||
always_assert(0);
|
||||
break;
|
||||
|
||||
case Statement::KindOfForStatement: {
|
||||
@@ -3304,12 +3303,6 @@ private:
|
||||
static bool isNewResult(ExpressionPtr e) {
|
||||
if (!e) return false;
|
||||
if (e->is(Expression::KindOfNewObjectExpression)) return true;
|
||||
if (e->is(Expression::KindOfBinaryOpExpression)) {
|
||||
auto b = spc(BinaryOpExpression, e);
|
||||
if (b->getOp() == T_COLLECTION) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (e->is(Expression::KindOfAssignmentExpression)) {
|
||||
return isNewResult(spc(AssignmentExpression, e)->getValue());
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "hphp/compiler/statement/loop_statement.h"
|
||||
#include "hphp/compiler/statement/class_variable.h"
|
||||
#include "hphp/compiler/statement/use_trait_statement.h"
|
||||
#include "hphp/compiler/statement/trait_require_statement.h"
|
||||
#include "hphp/compiler/analysis/symbol_table.h"
|
||||
#include "hphp/compiler/package.h"
|
||||
#include "hphp/compiler/parser/parser.h"
|
||||
@@ -489,7 +488,8 @@ void AnalysisResult::link(FileScopePtr user, FileScopePtr provider) {
|
||||
|
||||
bool AnalysisResult::addClassDependency(FileScopePtr usingFile,
|
||||
const std::string &className) {
|
||||
if (m_systemClasses.find(className) != m_systemClasses.end())
|
||||
if (BuiltinSymbols::s_classes.find(className) !=
|
||||
BuiltinSymbols::s_classes.end())
|
||||
return true;
|
||||
|
||||
StringToClassScopePtrVecMap::const_iterator iter =
|
||||
@@ -507,7 +507,8 @@ bool AnalysisResult::addClassDependency(FileScopePtr usingFile,
|
||||
|
||||
bool AnalysisResult::addFunctionDependency(FileScopePtr usingFile,
|
||||
const std::string &functionName) {
|
||||
if (m_functions.find(functionName) != m_functions.end())
|
||||
if (BuiltinSymbols::s_functions.find(functionName) !=
|
||||
BuiltinSymbols::s_functions.end())
|
||||
return true;
|
||||
StringToFunctionScopePtrMap::const_iterator iter =
|
||||
m_functionDecs.find(functionName);
|
||||
@@ -569,16 +570,12 @@ bool AnalysisResult::isSystemConstant(const std::string &constName) const {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Program
|
||||
|
||||
void AnalysisResult::addSystemFunction(FunctionScopeRawPtr fs) {
|
||||
FunctionScopePtr& entry = m_functions[fs->getName()];
|
||||
assert(!entry);
|
||||
entry = fs;
|
||||
}
|
||||
|
||||
void AnalysisResult::addSystemClass(ClassScopeRawPtr cs) {
|
||||
ClassScopePtr& entry = m_systemClasses[cs->getName()];
|
||||
assert(!entry);
|
||||
entry = cs;
|
||||
void AnalysisResult::loadBuiltins() {
|
||||
AnalysisResultPtr ar = shared_from_this();
|
||||
BuiltinSymbols::LoadFunctions(ar, m_functions);
|
||||
BuiltinSymbols::LoadClasses(ar, m_systemClasses);
|
||||
BuiltinSymbols::LoadVariables(ar, m_variables);
|
||||
BuiltinSymbols::LoadConstants(ar, m_constants);
|
||||
}
|
||||
|
||||
void AnalysisResult::checkClassDerivations() {
|
||||
@@ -590,11 +587,7 @@ void AnalysisResult::checkClassDerivations() {
|
||||
hphp_string_iset seen;
|
||||
cls->checkDerivation(ar, seen);
|
||||
if (Option::WholeProgram) {
|
||||
try {
|
||||
cls->importUsedTraits(ar);
|
||||
} catch (const AnalysisTimeFatalException& e) {
|
||||
cls->setFatal(e);
|
||||
}
|
||||
cls->importUsedTraits(ar);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -612,26 +605,22 @@ void AnalysisResult::resolveNSFallbackFuncs() {
|
||||
}
|
||||
|
||||
void AnalysisResult::collectFunctionsAndClasses(FileScopePtr fs) {
|
||||
for (const auto& iter : fs->getFunctions()) {
|
||||
FunctionScopePtr func = iter.second;
|
||||
const StringToFunctionScopePtrMap &funcs = fs->getFunctions();
|
||||
|
||||
for (StringToFunctionScopePtrMap::const_iterator iter = funcs.begin();
|
||||
iter != funcs.end(); ++iter) {
|
||||
FunctionScopePtr func = iter->second;
|
||||
if (!func->inPseudoMain()) {
|
||||
FunctionScopePtr &funcDec = m_functionDecs[iter.first];
|
||||
FunctionScopePtr &funcDec = m_functionDecs[iter->first];
|
||||
if (funcDec) {
|
||||
if (funcDec->isSystem()) {
|
||||
assert(funcDec->allowOverride());
|
||||
funcDec = func;
|
||||
} else if (func->isSystem()) {
|
||||
assert(func->allowOverride());
|
||||
} else {
|
||||
FunctionScopePtrVec &funcVec = m_functionReDecs[iter.first];
|
||||
int sz = funcVec.size();
|
||||
if (!sz) {
|
||||
funcDec->setRedeclaring(sz++);
|
||||
funcVec.push_back(funcDec);
|
||||
}
|
||||
func->setRedeclaring(sz++);
|
||||
funcVec.push_back(func);
|
||||
FunctionScopePtrVec &funcVec = m_functionReDecs[iter->first];
|
||||
int sz = funcVec.size();
|
||||
if (!sz) {
|
||||
funcDec->setRedeclaring(sz++);
|
||||
funcVec.push_back(funcDec);
|
||||
}
|
||||
func->setRedeclaring(sz++);
|
||||
funcVec.push_back(func);
|
||||
} else {
|
||||
funcDec = func;
|
||||
}
|
||||
@@ -639,12 +628,13 @@ void AnalysisResult::collectFunctionsAndClasses(FileScopePtr fs) {
|
||||
}
|
||||
|
||||
if (const StringToFunctionScopePtrVecMap *redec = fs->getRedecFunctions()) {
|
||||
for (const auto &iter : *redec) {
|
||||
FunctionScopePtrVec::const_iterator i = iter.second.begin();
|
||||
FunctionScopePtrVec::const_iterator e = iter.second.end();
|
||||
FunctionScopePtr &funcDec = m_functionDecs[iter.first];
|
||||
for (StringToFunctionScopePtrVecMap::const_iterator iter = redec->begin();
|
||||
iter != redec->end(); ++iter) {
|
||||
FunctionScopePtrVec::const_iterator i = iter->second.begin();
|
||||
FunctionScopePtrVec::const_iterator e = iter->second.end();
|
||||
FunctionScopePtr &funcDec = m_functionDecs[iter->first];
|
||||
assert(funcDec); // because the first one was in funcs above
|
||||
FunctionScopePtrVec &funcVec = m_functionReDecs[iter.first];
|
||||
FunctionScopePtrVec &funcVec = m_functionReDecs[iter->first];
|
||||
int sz = funcVec.size();
|
||||
if (!sz) {
|
||||
funcDec->setRedeclaring(sz++);
|
||||
@@ -657,9 +647,11 @@ void AnalysisResult::collectFunctionsAndClasses(FileScopePtr fs) {
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& iter : fs->getClasses()) {
|
||||
ClassScopePtrVec &clsVec = m_classDecs[iter.first];
|
||||
clsVec.insert(clsVec.end(), iter.second.begin(), iter.second.end());
|
||||
const StringToClassScopePtrVecMap &classes = fs->getClasses();
|
||||
for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin();
|
||||
iter != classes.end(); ++iter) {
|
||||
ClassScopePtrVec &clsVec = m_classDecs[iter->first];
|
||||
clsVec.insert(clsVec.end(), iter->second.begin(), iter->second.end());
|
||||
}
|
||||
|
||||
m_classAliases.insert(fs->getClassAliases().begin(),
|
||||
@@ -1616,10 +1608,12 @@ void AnalysisResult::inferTypes() {
|
||||
BlockScopeRawPtrQueue scopes;
|
||||
getScopesSet(scopes);
|
||||
|
||||
for (auto scope : scopes) {
|
||||
scope->setInTypeInference(true);
|
||||
scope->clearUpdated();
|
||||
assert(scope->getNumDepsToWaitFor() == 0);
|
||||
for (BlockScopeRawPtrQueue::iterator
|
||||
it = scopes.begin(), end = scopes.end();
|
||||
it != end; ++it) {
|
||||
(*it)->setInTypeInference(true);
|
||||
(*it)->clearUpdated();
|
||||
assert((*it)->getNumDepsToWaitFor() == 0);
|
||||
}
|
||||
|
||||
#ifdef HPHP_INSTRUMENT_TYPE_INF
|
||||
@@ -1630,11 +1624,13 @@ void AnalysisResult::inferTypes() {
|
||||
|
||||
processScopesParallel<InferTypes>("InferTypes");
|
||||
|
||||
for (auto scope : scopes) {
|
||||
scope->setInTypeInference(false);
|
||||
scope->clearUpdated();
|
||||
assert(scope->getMark() == BlockScope::MarkProcessed);
|
||||
assert(scope->getNumDepsToWaitFor() == 0);
|
||||
for (BlockScopeRawPtrQueue::iterator
|
||||
it = scopes.begin(), end = scopes.end();
|
||||
it != end; ++it) {
|
||||
(*it)->setInTypeInference(false);
|
||||
(*it)->clearUpdated();
|
||||
assert((*it)->getMark() == BlockScope::MarkProcessed);
|
||||
assert((*it)->getNumDepsToWaitFor() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "hphp/compiler/analysis/symbol_table.h"
|
||||
#include "hphp/compiler/analysis/function_container.h"
|
||||
#include "hphp/compiler/package.h"
|
||||
#include "hphp/compiler/hphp.h"
|
||||
|
||||
#include "hphp/util/string-bag.h"
|
||||
#include "hphp/util/thread-local.h"
|
||||
@@ -37,7 +36,7 @@ namespace HPHP {
|
||||
|
||||
|
||||
DECLARE_BOOST_TYPES(ClassScope);
|
||||
DECLARE_EXTENDED_BOOST_TYPES(FileScope);
|
||||
DECLARE_BOOST_TYPES(FileScope);
|
||||
DECLARE_BOOST_TYPES(FunctionScope);
|
||||
DECLARE_BOOST_TYPES(Location);
|
||||
DECLARE_BOOST_TYPES(AnalysisResult);
|
||||
@@ -151,8 +150,7 @@ public:
|
||||
|
||||
void addNSFallbackFunc(ConstructPtr c, FileScopePtr fs);
|
||||
|
||||
void addSystemFunction(FunctionScopeRawPtr fs);
|
||||
void addSystemClass(ClassScopeRawPtr cs);
|
||||
void loadBuiltins();
|
||||
void analyzeProgram(bool system = false);
|
||||
void analyzeIncludes();
|
||||
void analyzeProgramFinal();
|
||||
|
||||
@@ -155,7 +155,9 @@ bool BlockScope::hasUser(BlockScopeRawPtr user, int useKinds) const {
|
||||
}
|
||||
|
||||
void BlockScope::addUse(BlockScopeRawPtr user, int useKinds) {
|
||||
if ((is(ClassScope) || is(FunctionScope)) && getStmt()) {
|
||||
if (is(ClassScope) ? static_cast<HPHP::ClassScope*>(this)->isUserClass() :
|
||||
is(FunctionScope) &&
|
||||
static_cast<HPHP::FunctionScope*>(this)->isUserFunction()) {
|
||||
|
||||
if (user.get() == this) {
|
||||
m_selfUser |= useKinds;
|
||||
|
||||
@@ -1,391 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/compiler/analysis/capture_extractor.h"
|
||||
#include "hphp/compiler/expression/join_clause.h"
|
||||
#include "hphp/compiler/expression/scalar_expression.h"
|
||||
#include "hphp/parser/hphp.tab.hpp"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Rewrites the construct rooted in cp so that it is in a form
|
||||
* that a query processor can evaluate while referencing only
|
||||
* state that is contained in the query processor or supplied
|
||||
* to the query processor in the form of arguments to the query.
|
||||
* For instance, a reference to a local variable in the scope
|
||||
* containing the query expression will be rewritten into a
|
||||
* reference to a (synthetic) parameter of the query expression.
|
||||
* This is similar to the way lambda expressions capture variables
|
||||
* from their enclosing environment.
|
||||
* Note that rewriting implies allocating new objects.
|
||||
* The original construct is not mutated in any way.
|
||||
* If the original construct is already in the right form, it is
|
||||
* returned as is.
|
||||
*/
|
||||
ExpressionPtr CaptureExtractor::rewrite(ExpressionPtr ep) {
|
||||
assert(ep != nullptr);
|
||||
switch (ep->getKindOf()) {
|
||||
case Expression::KindOfQueryExpression: {
|
||||
return rewriteQuery(static_pointer_cast<QueryExpression>(ep));
|
||||
}
|
||||
case Expression::KindOfSelectClause: {
|
||||
// leave select clauses alone, another visitor deals with them.
|
||||
return ep;
|
||||
}
|
||||
case Expression::KindOfFromClause:
|
||||
case Expression::KindOfLetClause:
|
||||
case Expression::KindOfIntoClause:
|
||||
case Expression::KindOfWhereClause: {
|
||||
return rewriteSimpleClause(static_pointer_cast<SimpleQueryClause>(ep));
|
||||
}
|
||||
case Expression::KindOfGroupClause:
|
||||
case Expression::KindOfJoinClause:
|
||||
case Expression::KindOfOrderbyClause:
|
||||
case Expression::KindOfOrdering: {
|
||||
// leave these alone. they are query specific and not parameterizable.
|
||||
return ep;
|
||||
}
|
||||
case Expression::KindOfObjectPropertyExpression: {
|
||||
return rewriteObjectProperty(
|
||||
static_pointer_cast<ObjectPropertyExpression>(ep));
|
||||
}
|
||||
case Expression::KindOfSimpleFunctionCall: {
|
||||
return rewriteCall(static_pointer_cast<SimpleFunctionCall>(ep));
|
||||
}
|
||||
case Expression::KindOfScalarExpression: {
|
||||
// Leave scalars alone. If the query processor can't handle them
|
||||
// rewriting won't help.
|
||||
return ep;
|
||||
}
|
||||
case Expression::KindOfUnaryOpExpression: {
|
||||
return rewriteUnary(static_pointer_cast<UnaryOpExpression>(ep));
|
||||
}
|
||||
case Expression::KindOfBinaryOpExpression: {
|
||||
return rewriteBinary(static_pointer_cast<BinaryOpExpression>(ep));
|
||||
}
|
||||
case Expression::KindOfSimpleVariable: {
|
||||
return rewriteSimpleVariable(static_pointer_cast<SimpleVariable>(ep));
|
||||
}
|
||||
case Expression::KindOfExpressionList: {
|
||||
return rewriteExpressionList(static_pointer_cast<ExpressionList>(ep));
|
||||
}
|
||||
default: {
|
||||
// If we get here, the expression is not a candidate for evaluation
|
||||
// by the query processor, so just turn it into a query parameter.
|
||||
return newQueryParamRef(ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given expression to end of the m_capturedExpressions list
|
||||
* and creates a new expression with the same scope and source location
|
||||
* that represents a reference to a query parameter. Query parameters do
|
||||
* not have a source code equivalent, but inform the query processor that
|
||||
* this expression represents the ith argument value, where i is zero based
|
||||
* and forms the last character of the special string @query_param_i.
|
||||
*/
|
||||
SimpleVariablePtr CaptureExtractor::newQueryParamRef(ExpressionPtr ae) {
|
||||
assert(ae != nullptr);
|
||||
char count = '0' + m_capturedExpressions.size();
|
||||
std::string pname = "@query_param_";
|
||||
pname.push_back(count);
|
||||
SimpleVariablePtr param(
|
||||
new SimpleVariable(ae->getScope(), ae->getLocation(), pname)
|
||||
);
|
||||
m_capturedExpressions.push_back(ae);
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
* If one or more of the arguments of the function call depend on query only
|
||||
* state (query local but not a query parameter reference), then rewrite
|
||||
* all of the arguments to be query local and return the rewritten
|
||||
* function call (the query processor has to either figure out a way to call
|
||||
* the function or must cause a runtime error when faced with the call).
|
||||
* Otherwise, rewrite the call as a query parameter reference.
|
||||
*/
|
||||
ExpressionPtr CaptureExtractor::rewriteCall(SimpleFunctionCallPtr sfc) {
|
||||
assert(sfc != nullptr);
|
||||
if (sfc->hadBackslash() ||
|
||||
(sfc->getClass() != nullptr && !sfc->getClassName().empty())) {
|
||||
return newQueryParamRef(sfc);
|
||||
}
|
||||
auto args = sfc->getParams();
|
||||
auto pc = args == nullptr ? 0 : args->getCount();
|
||||
bool isQueryCall = false;
|
||||
for (int i = 0; i < pc; i++) {
|
||||
auto arg = (*args)[i];
|
||||
assert(arg != nullptr);
|
||||
isQueryCall |= this->dependsOnQueryOnlyState(arg);
|
||||
}
|
||||
if (!isQueryCall) return newQueryParamRef(sfc);
|
||||
ExpressionListPtr newArgs(
|
||||
new ExpressionList(args->getScope(), args->getLocation())
|
||||
);
|
||||
bool noRewrites = true;
|
||||
for (int i = 0; i < pc; i++) {
|
||||
auto arg = (*args)[i];
|
||||
auto newArg = rewrite(arg);
|
||||
if (arg != newArg) noRewrites = false;
|
||||
newArgs->addElement(newArg);
|
||||
}
|
||||
if (noRewrites) return sfc;
|
||||
SimpleFunctionCallPtr result(
|
||||
new SimpleFunctionCall(sfc->getScope(), sfc->getLocation(),
|
||||
sfc->getName(), false, newArgs, ExpressionPtr())
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the expression tree rooted at e and returns true if
|
||||
* any node in the tree is a simple variable that references a
|
||||
* name in m_boundVars.
|
||||
*/
|
||||
bool CaptureExtractor::dependsOnQueryOnlyState(ExpressionPtr e) {
|
||||
assert(e != nullptr);
|
||||
if (e->getKindOf() == Expression::KindOfSimpleVariable) {
|
||||
auto sv = static_pointer_cast<SimpleVariable>(e);
|
||||
auto varName = sv->getName();
|
||||
for (auto &boundVar : m_boundVars) {
|
||||
if (varName == boundVar) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
auto numKids = e->getKidCount();
|
||||
for (int i = 0; i < numKids; i++) {
|
||||
auto ei = e->getNthExpr(i);
|
||||
if (ei == nullptr) return false; //Default param
|
||||
if (dependsOnQueryOnlyState(ei)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a simple variable refers to a name bound inside the query
|
||||
* then leave it alone. If not, rewrite it to be reference to
|
||||
* a query parameter.
|
||||
*/
|
||||
SimpleVariablePtr CaptureExtractor::rewriteSimpleVariable(
|
||||
SimpleVariablePtr sv) {
|
||||
assert(sv != nullptr);
|
||||
auto varName = sv->getName();
|
||||
for (auto &boundVar : m_boundVars) {
|
||||
if (varName == boundVar) return sv;
|
||||
}
|
||||
return newQueryParamRef(sv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query expressions introduce a local scope with names introduced
|
||||
* by some of the clauses of the query expression. This needs
|
||||
* special handling so that we can track variables local to the query.
|
||||
*/
|
||||
QueryExpressionPtr CaptureExtractor::rewriteQuery(QueryExpressionPtr qe) {
|
||||
assert(qe != nullptr);
|
||||
auto clauses = qe->getClauses();
|
||||
auto newClauses = rewriteExpressionList(clauses);
|
||||
if (clauses == newClauses) return qe;
|
||||
QueryExpressionPtr result(
|
||||
new QueryExpression(qe->getScope(), qe->getLocation(), newClauses)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites any expression query clauses in this list of clauses, taking care
|
||||
* to track variables local to the query.
|
||||
*/
|
||||
ExpressionListPtr CaptureExtractor::rewriteExpressionList(ExpressionListPtr l) {
|
||||
int np = 0;
|
||||
int nc = l->getCount();
|
||||
ExpressionListPtr newList(
|
||||
new ExpressionList(l->getScope(), l->getLocation())
|
||||
);
|
||||
bool noRewrites = true;
|
||||
for (int i = 0; i < nc; i++) {
|
||||
auto e = (*l)[i];
|
||||
assert(e != nullptr);
|
||||
auto kind = e->getKindOf();
|
||||
switch (kind) {
|
||||
case Expression::KindOfIntoClause: {
|
||||
// The into expression is in the scope of the into clause
|
||||
SimpleQueryClausePtr qcp(static_pointer_cast<SimpleQueryClause>(e));
|
||||
m_boundVars.push_back(qcp->getIdentifier());
|
||||
np++;
|
||||
break;
|
||||
}
|
||||
case Expression::KindOfJoinClause: {
|
||||
JoinClausePtr jcp(static_pointer_cast<JoinClause>(e));
|
||||
m_boundVars.push_back(jcp->getVar());
|
||||
np++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
auto ne = rewrite(e);
|
||||
if (ne != e) noRewrites = false;
|
||||
newList->addElement(ne);
|
||||
// deal with clauses that introduce names for subsequent clauses
|
||||
switch (kind) {
|
||||
case Expression::KindOfFromClause:
|
||||
case Expression::KindOfLetClause: {
|
||||
SimpleQueryClausePtr qcp(static_pointer_cast<SimpleQueryClause>(e));
|
||||
m_boundVars.push_back(qcp->getIdentifier());
|
||||
np++;
|
||||
break;
|
||||
}
|
||||
case Expression::KindOfJoinClause: {
|
||||
JoinClausePtr jcp(static_pointer_cast<JoinClause>(e));
|
||||
auto groupId = jcp->getGroup();
|
||||
if (!groupId.empty()) {
|
||||
m_boundVars.push_back(groupId);
|
||||
np++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (np-- > 0) m_boundVars.pop_back();
|
||||
if (noRewrites) return l;
|
||||
return newList;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the expression of a simple query clause is query local, then
|
||||
* return the clause as is. Otherwise return a clone of the clause
|
||||
* with the expression rewritten to reference a query parameter.
|
||||
*/
|
||||
SimpleQueryClausePtr CaptureExtractor::rewriteSimpleClause(
|
||||
SimpleQueryClausePtr sc) {
|
||||
assert (sc != nullptr);
|
||||
auto expr = sc->getExpression();
|
||||
auto newExpr = rewrite(expr);
|
||||
if (expr == newExpr) return sc;
|
||||
auto rsc = static_pointer_cast<SimpleQueryClause>(sc->clone());
|
||||
rsc->setExpression(newExpr);
|
||||
return rsc;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the object expression is query local, that is, if it is a simple variable
|
||||
* referring to a name declared in a query clause, or itself a query local
|
||||
* object expression, then if keep this expression as is. If not, then
|
||||
* rewrite this expression into a query parameter reference.
|
||||
*/
|
||||
ExpressionPtr CaptureExtractor::rewriteObjectProperty(
|
||||
ObjectPropertyExpressionPtr ope) {
|
||||
assert(ope != nullptr);
|
||||
auto obj = ope->getObject();
|
||||
if (this->dependsOnQueryOnlyState(obj)) {
|
||||
auto prop = ope->getProperty();
|
||||
if (prop->getKindOf() == Expression::KindOfScalarExpression) {
|
||||
auto scalar = static_pointer_cast<ScalarExpression>(prop);
|
||||
const string &propName = scalar->getLiteralString();
|
||||
if (!propName.empty()) {
|
||||
return ope;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newQueryParamRef(ope);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the unary operation is not PHP specific, but something a query
|
||||
* processor can handle (+ - ! ~), then rewrite the operand to something
|
||||
* the query processor can evaluate (such as a query parameter reference)
|
||||
* and rewrite the entire expression to use the rewritten operand.
|
||||
* If the rewritten operand is the same as the original operand, just
|
||||
* return the expression as is.
|
||||
*/
|
||||
ExpressionPtr CaptureExtractor::rewriteUnary(UnaryOpExpressionPtr ue) {
|
||||
assert (ue != nullptr);
|
||||
if (!ue->getFront()) return nullptr;
|
||||
switch (ue->getOp()) {
|
||||
case '+':
|
||||
case '-':
|
||||
case '!':
|
||||
case '~':
|
||||
break; // Could be something the query processor can handle
|
||||
default:
|
||||
return newQueryParamRef(ue);
|
||||
}
|
||||
auto expr = ue->getExpression();
|
||||
auto newExpr = rewrite(expr);
|
||||
if (expr == newExpr) return ue;
|
||||
UnaryOpExpressionPtr result(
|
||||
new UnaryOpExpression(ue->getScope(), ue->getLocation(),
|
||||
newExpr, ue->getOp(), true)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the binary operation is not PHP specific, but something a query
|
||||
* processor can handle (+ - * and so on), then rewrite the operands to
|
||||
* something the query processor can evaluate (such as a query parameter
|
||||
* references) and rewrite the entire expression to use the rewritten operands.
|
||||
* If the rewritten operands are the same as the original operands, just
|
||||
* return the expression as is.
|
||||
*/
|
||||
ExpressionPtr CaptureExtractor::rewriteBinary(BinaryOpExpressionPtr be) {
|
||||
assert(be != nullptr);
|
||||
switch (be->getOp()) {
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
case '%':
|
||||
case '&':
|
||||
case '|':
|
||||
case '^':
|
||||
case T_IS_IDENTICAL:
|
||||
case T_IS_EQUAL:
|
||||
case '>':
|
||||
case '<':
|
||||
case T_IS_GREATER_OR_EQUAL:
|
||||
case T_IS_SMALLER_OR_EQUAL:
|
||||
case T_IS_NOT_IDENTICAL:
|
||||
case T_IS_NOT_EQUAL:
|
||||
case T_BOOLEAN_OR:
|
||||
case T_BOOLEAN_AND:
|
||||
case T_LOGICAL_OR:
|
||||
case T_LOGICAL_AND:
|
||||
case '.':
|
||||
break; // Could be something the query processor can handle
|
||||
|
||||
default:
|
||||
return newQueryParamRef(be);
|
||||
}
|
||||
auto expr1 = be->getExp1();
|
||||
auto expr2 = be->getExp2();
|
||||
auto newExpr1 = rewrite(expr1);
|
||||
auto newExpr2 = rewrite(expr2);
|
||||
if (expr1 == newExpr1 && expr2 == newExpr2) return be;
|
||||
BinaryOpExpressionPtr result(
|
||||
new BinaryOpExpression(be->getScope(), be->getLocation(),
|
||||
newExpr1, newExpr2, be->getOp())
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef incl_HPHP_CAPTURE_EXTRACTOR_H_
|
||||
#define incl_HPHP_CAPTURE_EXTRACTOR_H_
|
||||
|
||||
#include "hphp/compiler/expression/binary_op_expression.h"
|
||||
#include "hphp/compiler/expression/expression.h"
|
||||
#include "hphp/compiler/expression/object_property_expression.h"
|
||||
#include "hphp/compiler/expression/query_expression.h"
|
||||
#include "hphp/compiler/expression/simple_function_call.h"
|
||||
#include "hphp/compiler/expression/simple_query_clause.h"
|
||||
#include "hphp/compiler/expression/simple_variable.h"
|
||||
#include "hphp/compiler/expression/unary_op_expression.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** A rewriter for query expressions that capture variables that lie
|
||||
* outside of the scope of the query expression. Subexpressions that
|
||||
* contain such references are turned into references to query parameter
|
||||
* variables. The original expressions are collected into the list
|
||||
* returned by getCapturedEpressions. Their runtime values are obtained
|
||||
* before the query is evaluated and are passed as arguments to the query
|
||||
* processor.
|
||||
*/
|
||||
class CaptureExtractor {
|
||||
public:
|
||||
|
||||
ExpressionPtr rewrite(ExpressionPtr ep);
|
||||
|
||||
std::vector<ExpressionPtr> getCapturedExpressions() {
|
||||
return m_capturedExpressions;
|
||||
}
|
||||
|
||||
private:
|
||||
bool dependsOnQueryOnlyState(ExpressionPtr e);
|
||||
SimpleVariablePtr newQueryParamRef(ExpressionPtr ae);
|
||||
ExpressionPtr rewriteBinary(BinaryOpExpressionPtr be);
|
||||
ExpressionPtr rewriteCall(SimpleFunctionCallPtr sfc);
|
||||
ExpressionListPtr rewriteExpressionList(ExpressionListPtr l);
|
||||
ExpressionPtr rewriteObjectProperty(ObjectPropertyExpressionPtr ope);
|
||||
QueryExpressionPtr rewriteQuery(QueryExpressionPtr qe);
|
||||
SimpleQueryClausePtr rewriteSimpleClause(SimpleQueryClausePtr sc);
|
||||
SimpleVariablePtr rewriteSimpleVariable(SimpleVariablePtr sv);
|
||||
ExpressionPtr rewriteUnary(UnaryOpExpressionPtr ue);
|
||||
|
||||
std::vector<ExpressionPtr> m_capturedExpressions;
|
||||
std::vector<std::string> m_boundVars;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // incl_HPHP_CAPTURE_EXTRACTOR_H_
|
||||
@@ -39,7 +39,6 @@
|
||||
#include "hphp/compiler/statement/class_variable.h"
|
||||
#include "hphp/compiler/statement/class_constant.h"
|
||||
#include "hphp/compiler/statement/use_trait_statement.h"
|
||||
#include "hphp/compiler/statement/trait_require_statement.h"
|
||||
#include "hphp/compiler/statement/trait_prec_statement.h"
|
||||
#include "hphp/compiler/statement/trait_alias_statement.h"
|
||||
#include "hphp/runtime/base/zend-string.h"
|
||||
@@ -474,17 +473,6 @@ void ClassScope::addImportTraitMethod(const TraitMethod &traitMethod,
|
||||
m_importMethToTraitMap[methName].push_back(traitMethod);
|
||||
}
|
||||
|
||||
void ClassScope::addTraitRequirement(const string &requiredName,
|
||||
bool isExtends) {
|
||||
assert(isTrait());
|
||||
|
||||
if (isExtends) {
|
||||
m_traitRequiredExtends.insert(requiredName);
|
||||
} else {
|
||||
m_traitRequiredImplements.insert(requiredName);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClassScope::setImportTraitMethodModifiers(const string &methName,
|
||||
ClassScopePtr traitCls,
|
||||
@@ -545,7 +533,6 @@ ClassScope::findTraitMethod(AnalysisResultPtr ar,
|
||||
|
||||
void ClassScope::findTraitMethodsToImport(AnalysisResultPtr ar,
|
||||
ClassScopePtr trait) {
|
||||
assert(Option::WholeProgram);
|
||||
ClassStatementPtr tStmt =
|
||||
dynamic_pointer_cast<ClassStatement>(trait->getStmt());
|
||||
StatementListPtr tStmts = tStmt->getStmts();
|
||||
@@ -562,45 +549,7 @@ void ClassScope::findTraitMethodsToImport(AnalysisResultPtr ar,
|
||||
}
|
||||
}
|
||||
|
||||
void ClassScope::importTraitRequirements(AnalysisResultPtr ar,
|
||||
ClassScopePtr trait) {
|
||||
if (isTrait()) {
|
||||
for (auto const& req : trait->getTraitRequiredExtends()) {
|
||||
addTraitRequirement(req, true);
|
||||
}
|
||||
for (auto const& req : trait->getTraitRequiredImplements()) {
|
||||
addTraitRequirement(req, false);
|
||||
}
|
||||
} else {
|
||||
for (auto const& req : trait->getTraitRequiredExtends()) {
|
||||
if (!derivesFrom(ar, req, true, false)) {
|
||||
getStmt()->analysisTimeFatal(
|
||||
Compiler::InvalidDerivation,
|
||||
Strings::TRAIT_REQ_EXTENDS,
|
||||
m_originalName.c_str(),
|
||||
req.c_str(),
|
||||
trait->getOriginalName().c_str(),
|
||||
"use"
|
||||
);
|
||||
}
|
||||
}
|
||||
for (auto const& req : trait->getTraitRequiredImplements()) {
|
||||
if (!derivesFrom(ar, req, true, false)) {
|
||||
getStmt()->analysisTimeFatal(
|
||||
Compiler::InvalidDerivation,
|
||||
Strings::TRAIT_REQ_IMPLEMENTS,
|
||||
m_originalName.c_str(),
|
||||
req.c_str(),
|
||||
trait->getOriginalName().c_str(),
|
||||
"use"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClassScope::applyTraitPrecRule(TraitPrecStatementPtr stmt) {
|
||||
assert(Option::WholeProgram);
|
||||
const string methodName = Util::toLower(stmt->getMethodName());
|
||||
const string selectedTraitName = Util::toLower(stmt->getTraitName());
|
||||
std::set<string> otherTraitNames;
|
||||
@@ -631,20 +580,12 @@ void ClassScope::applyTraitPrecRule(TraitPrecStatementPtr stmt) {
|
||||
|
||||
// Report error if didn't find the selected trait
|
||||
if (!foundSelectedTrait) {
|
||||
stmt->analysisTimeFatal(
|
||||
Compiler::UnknownTrait,
|
||||
Strings::TRAITS_UNKNOWN_TRAIT,
|
||||
selectedTraitName.c_str()
|
||||
);
|
||||
Compiler::Error(Compiler::UnknownTrait, stmt);
|
||||
}
|
||||
|
||||
// Sanity checking: otherTraitNames should be empty now
|
||||
if (otherTraitNames.size()) {
|
||||
stmt->analysisTimeFatal(
|
||||
Compiler::UnknownTrait,
|
||||
Strings::TRAITS_UNKNOWN_TRAIT,
|
||||
selectedTraitName.c_str()
|
||||
);
|
||||
Compiler::Error(Compiler::UnknownTrait, stmt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +596,6 @@ bool ClassScope::hasMethod(const string &methodName) const {
|
||||
ClassScopePtr
|
||||
ClassScope::findSingleTraitWithMethod(AnalysisResultPtr ar,
|
||||
const string &methodName) const {
|
||||
assert(Option::WholeProgram);
|
||||
ClassScopePtr trait = ClassScopePtr();
|
||||
|
||||
for (unsigned i = 0; i < m_usedTraitNames.size(); i++) {
|
||||
@@ -673,7 +613,6 @@ ClassScope::findSingleTraitWithMethod(AnalysisResultPtr ar,
|
||||
}
|
||||
|
||||
void ClassScope::addTraitAlias(TraitAliasStatementPtr aliasStmt) {
|
||||
assert(Option::WholeProgram);
|
||||
const string &traitName = aliasStmt->getTraitName();
|
||||
const string &origMethName = aliasStmt->getMethodName();
|
||||
const string &newMethName = aliasStmt->getNewMethodName();
|
||||
@@ -684,7 +623,6 @@ void ClassScope::addTraitAlias(TraitAliasStatementPtr aliasStmt) {
|
||||
|
||||
void ClassScope::applyTraitAliasRule(AnalysisResultPtr ar,
|
||||
TraitAliasStatementPtr stmt) {
|
||||
assert(Option::WholeProgram);
|
||||
const string traitName = Util::toLower(stmt->getTraitName());
|
||||
const string origMethName = Util::toLower(stmt->getMethodName());
|
||||
const string newMethName = Util::toLower(stmt->getNewMethodName());
|
||||
@@ -697,11 +635,8 @@ void ClassScope::applyTraitAliasRule(AnalysisResultPtr ar,
|
||||
traitCls = ar->findClass(traitName);
|
||||
}
|
||||
if (!traitCls || !(traitCls->isTrait())) {
|
||||
stmt->analysisTimeFatal(
|
||||
Compiler::UnknownTrait,
|
||||
Strings::TRAITS_UNKNOWN_TRAIT,
|
||||
traitName.empty() ? origMethName.c_str() : traitName.c_str()
|
||||
);
|
||||
Compiler::Error(Compiler::UnknownTrait, stmt);
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep record of alias rule
|
||||
@@ -712,10 +647,8 @@ void ClassScope::applyTraitAliasRule(AnalysisResultPtr ar,
|
||||
MethodStatementPtr methStmt = findTraitMethod(ar, traitCls, origMethName,
|
||||
visitedTraits);
|
||||
if (!methStmt) {
|
||||
stmt->analysisTimeFatal(
|
||||
Compiler::UnknownTraitMethod,
|
||||
Strings::TRAITS_UNKNOWN_TRAIT_METHOD, origMethName.c_str()
|
||||
);
|
||||
Compiler::Error(Compiler::UnknownTraitMethod, stmt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (origMethName == newMethName) {
|
||||
@@ -730,7 +663,6 @@ void ClassScope::applyTraitAliasRule(AnalysisResultPtr ar,
|
||||
}
|
||||
|
||||
void ClassScope::applyTraitRules(AnalysisResultPtr ar) {
|
||||
assert(Option::WholeProgram);
|
||||
ClassStatementPtr classStmt = dynamic_pointer_cast<ClassStatement>(getStmt());
|
||||
assert(classStmt);
|
||||
StatementListPtr stmts = classStmt->getStmts();
|
||||
@@ -763,7 +695,6 @@ void ClassScope::applyTraitRules(AnalysisResultPtr ar) {
|
||||
// 1) implemented by other traits
|
||||
// 2) duplicate
|
||||
void ClassScope::removeSpareTraitAbstractMethods(AnalysisResultPtr ar) {
|
||||
assert(Option::WholeProgram);
|
||||
for (MethodToTraitListMap::iterator iter = m_importMethToTraitMap.begin();
|
||||
iter != m_importMethToTraitMap.end(); iter++) {
|
||||
|
||||
@@ -801,17 +732,9 @@ void ClassScope::removeSpareTraitAbstractMethods(AnalysisResultPtr ar) {
|
||||
}
|
||||
|
||||
void ClassScope::importUsedTraits(AnalysisResultPtr ar) {
|
||||
// Trait flattening is supposed to happen only when we have awareness of
|
||||
// the whole program.
|
||||
assert(Option::WholeProgram);
|
||||
|
||||
if (m_traitStatus == FLATTENED) return;
|
||||
if (m_traitStatus == BEING_FLATTENED) {
|
||||
getStmt()->analysisTimeFatal(
|
||||
Compiler::CyclicDependentTraits,
|
||||
"Cyclic dependency between traits involving %s",
|
||||
getOriginalName().c_str()
|
||||
);
|
||||
Compiler::Error(Compiler::CyclicDependentTraits, getStmt());
|
||||
return;
|
||||
}
|
||||
if (m_usedTraitNames.size() == 0) {
|
||||
@@ -828,53 +751,18 @@ void ClassScope::importUsedTraits(AnalysisResultPtr ar) {
|
||||
}
|
||||
}
|
||||
|
||||
if (isTrait()) {
|
||||
for (auto const& req : getTraitRequiredExtends()) {
|
||||
ClassScopePtr rCls = ar->findClass(req);
|
||||
if (!rCls || rCls->isFinal() || rCls->isInterface()) {
|
||||
getStmt()->analysisTimeFatal(
|
||||
Compiler::InvalidDerivation,
|
||||
Strings::TRAIT_BAD_REQ_EXTENDS,
|
||||
m_originalName.c_str(),
|
||||
req.c_str(),
|
||||
req.c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
for (auto const& req : getTraitRequiredImplements()) {
|
||||
ClassScopePtr rCls = ar->findClass(req);
|
||||
if (!rCls || !(rCls->isInterface())) {
|
||||
getStmt()->analysisTimeFatal(
|
||||
Compiler::InvalidDerivation,
|
||||
Strings::TRAIT_BAD_REQ_IMPLEMENTS,
|
||||
m_originalName.c_str(),
|
||||
req.c_str(),
|
||||
req.c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find trait methods to be imported
|
||||
for (unsigned i = 0; i < m_usedTraitNames.size(); i++) {
|
||||
ClassScopePtr tCls = ar->findClass(m_usedTraitNames[i]);
|
||||
if (!tCls || !(tCls->isTrait())) {
|
||||
setAttribute(UsesUnknownTrait); // XXX: is this useful ... for anything?
|
||||
getStmt()->analysisTimeFatal(
|
||||
Compiler::UnknownTrait,
|
||||
Strings::TRAITS_UNKNOWN_TRAIT,
|
||||
m_usedTraitNames[i].c_str()
|
||||
);
|
||||
setAttribute(UsesUnknownTrait);
|
||||
Compiler::Error(Compiler::UnknownTrait, getStmt());
|
||||
continue;
|
||||
}
|
||||
// First, make sure the used trait is flattened
|
||||
tCls->importUsedTraits(ar);
|
||||
|
||||
findTraitMethodsToImport(ar, tCls);
|
||||
|
||||
// Import any interfaces implemented
|
||||
tCls->getInterfaces(ar, m_bases, false);
|
||||
|
||||
importTraitRequirements(ar, tCls);
|
||||
}
|
||||
|
||||
// Apply rules
|
||||
@@ -894,7 +782,7 @@ void ClassScope::importUsedTraits(AnalysisResultPtr ar) {
|
||||
}
|
||||
|
||||
std::map<string, MethodStatementPtr> importedTraitMethods;
|
||||
std::vector<std::pair<string,const TraitMethod*>> importedTraitsWithOrigName;
|
||||
std::vector<std::pair<string,const TraitMethod*> > importedTraitsWithOrigName;
|
||||
|
||||
// Actually import the methods
|
||||
for (MethodToTraitListMap::const_iterator
|
||||
@@ -908,11 +796,7 @@ void ClassScope::importUsedTraits(AnalysisResultPtr ar) {
|
||||
}
|
||||
// Consistency checking: each name must only refer to one imported method
|
||||
if (iter->second.size() > 1) {
|
||||
getStmt()->analysisTimeFatal(
|
||||
Compiler::MethodInMultipleTraits,
|
||||
Strings::METHOD_IN_MULTIPLE_TRAITS,
|
||||
iter->first.c_str()
|
||||
);
|
||||
Compiler::Error(Compiler::MethodInMultipleTraits, getStmt());
|
||||
} else {
|
||||
TraitMethodList::const_iterator traitMethIter = iter->second.begin();
|
||||
if ((traitMethIter->m_modifiers ? traitMethIter->m_modifiers :
|
||||
@@ -923,6 +807,13 @@ void ClassScope::importUsedTraits(AnalysisResultPtr ar) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (traitMethIter->m_modifiers &&
|
||||
traitMethIter->m_modifiers->isStatic()) {
|
||||
Compiler::Error(Compiler::InvalidAccessModifier,
|
||||
traitMethIter->m_modifiers);
|
||||
continue;
|
||||
}
|
||||
|
||||
string sourceName = traitMethIter->m_ruleStmt ?
|
||||
Util::toLower(((TraitAliasStatement*)traitMethIter->m_ruleStmt.get())->
|
||||
getMethodName()) : iter->first;
|
||||
@@ -1243,7 +1134,8 @@ void ClassScope::getInterfaces(AnalysisResultConstPtr ar,
|
||||
if (cls && cls->isRedeclaring()) {
|
||||
cls = self->findExactClass(cls);
|
||||
}
|
||||
names.push_back(cls ? cls->getDocName() : *it);
|
||||
if (cls) names.push_back(cls->getDocName());
|
||||
else names.push_back(*it);
|
||||
if (cls && recursive) {
|
||||
cls->getInterfaces(ar, names, true);
|
||||
}
|
||||
|
||||
@@ -24,9 +24,8 @@
|
||||
#include "hphp/compiler/statement/trait_prec_statement.h"
|
||||
#include "hphp/compiler/statement/trait_alias_statement.h"
|
||||
#include "hphp/compiler/expression/user_attribute.h"
|
||||
#include "hphp/compiler/json.h"
|
||||
#include "hphp/util/functional.h"
|
||||
#include "hphp/util/hash-map-typedefs.h"
|
||||
#include "hphp/util/json.h"
|
||||
#include "hphp/util/case-insensitive.h"
|
||||
#include "hphp/compiler/option.h"
|
||||
|
||||
namespace HPHP {
|
||||
@@ -174,7 +173,6 @@ public:
|
||||
* Get/set attributes.
|
||||
*/
|
||||
void setSystem();
|
||||
bool isSystem() const { return m_attribute & System; }
|
||||
void setAttribute(Attribute attr) { m_attribute |= attr;}
|
||||
void clearAttribute(Attribute attr) { m_attribute &= ~attr;}
|
||||
bool getAttribute(Attribute attr) const {
|
||||
@@ -303,29 +301,17 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
const boost::container::flat_set<std::string>& getTraitRequiredExtends()
|
||||
const {
|
||||
return m_traitRequiredExtends;
|
||||
}
|
||||
|
||||
const boost::container::flat_set<std::string>& getTraitRequiredImplements()
|
||||
const {
|
||||
return m_traitRequiredImplements;
|
||||
}
|
||||
|
||||
const std::vector<std::string> &getUsedTraitNames() const {
|
||||
return m_usedTraitNames;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::string, std::string>>& getTraitAliases()
|
||||
const std::vector<std::pair<std::string, std::string> > &getTraitAliases()
|
||||
const {
|
||||
return m_traitAliases;
|
||||
}
|
||||
|
||||
void addTraitAlias(TraitAliasStatementPtr aliasStmt);
|
||||
|
||||
void addTraitRequirement(const std::string &requiredName, bool isExtends);
|
||||
|
||||
void importUsedTraits(AnalysisResultPtr ar);
|
||||
|
||||
/**
|
||||
@@ -383,16 +369,6 @@ public:
|
||||
bool canSkipCreateMethod(AnalysisResultConstPtr ar) const;
|
||||
bool checkHasPropTable(AnalysisResultConstPtr ar);
|
||||
|
||||
const StringData* getFatalMessage() const {
|
||||
return m_fatal_error_msg;
|
||||
}
|
||||
|
||||
void setFatal(const AnalysisTimeFatalException& fatal) {
|
||||
assert(m_fatal_error_msg == nullptr);
|
||||
m_fatal_error_msg = makeStaticString(fatal.getMessage());
|
||||
assert(m_fatal_error_msg != nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
// need to maintain declaration order for ClassInfo map
|
||||
FunctionScopePtrVec m_functionsVec;
|
||||
@@ -402,8 +378,6 @@ private:
|
||||
UserAttributeMap m_userAttributes;
|
||||
|
||||
std::vector<std::string> m_usedTraitNames;
|
||||
boost::container::flat_set<std::string> m_traitRequiredExtends;
|
||||
boost::container::flat_set<std::string> m_traitRequiredImplements;
|
||||
// m_traitAliases is used to support ReflectionClass::getTraitAliases
|
||||
std::vector<std::pair<std::string, std::string> > m_traitAliases;
|
||||
|
||||
@@ -453,9 +427,6 @@ private:
|
||||
// bases 32 through n are all known.
|
||||
unsigned m_knownBases;
|
||||
|
||||
// holds the fact that accessing this class declaration is a fatal error
|
||||
const StringData* m_fatal_error_msg = nullptr;
|
||||
|
||||
void addImportTraitMethod(const TraitMethod &traitMethod,
|
||||
const std::string &methName);
|
||||
void informClosuresAboutScopeClone(ConstructPtr root,
|
||||
@@ -476,8 +447,6 @@ private:
|
||||
|
||||
void findTraitMethodsToImport(AnalysisResultPtr ar, ClassScopePtr trait);
|
||||
|
||||
void importTraitRequirements(AnalysisResultPtr ar, ClassScopePtr trait);
|
||||
|
||||
MethodStatementPtr findTraitMethod(AnalysisResultPtr ar,
|
||||
ClassScopePtr trait,
|
||||
const std::string &methodName,
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#define incl_HPHP_COMPILER_ERROR_H_
|
||||
|
||||
#include "hphp/compiler/analysis/type.h"
|
||||
#include "hphp/compiler/json.h"
|
||||
#include "hphp/util/json.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -245,7 +245,6 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
|
||||
Statement::KindOf stype = s->getKindOf();
|
||||
switch (stype) {
|
||||
case Statement::KindOfUseTraitStatement:
|
||||
case Statement::KindOfTraitRequireStatement:
|
||||
case Statement::KindOfTraitPrecStatement:
|
||||
case Statement::KindOfTraitAliasStatement:
|
||||
not_reached();
|
||||
|
||||
@@ -37,6 +37,7 @@ CODE_ERROR_ENTRY(InvalidAttribute)
|
||||
CODE_ERROR_ENTRY(UnknownTrait)
|
||||
CODE_ERROR_ENTRY(MethodInMultipleTraits)
|
||||
CODE_ERROR_ENTRY(UnknownTraitMethod)
|
||||
CODE_ERROR_ENTRY(InvalidAccessModifier)
|
||||
CODE_ERROR_ENTRY(CyclicDependentTraits)
|
||||
CODE_ERROR_ENTRY(InvalidTraitStatement)
|
||||
CODE_ERROR_ENTRY(RedeclaredTrait)
|
||||
@@ -44,4 +45,3 @@ CODE_ERROR_ENTRY(InvalidInstantiation)
|
||||
CODE_ERROR_ENTRY(InvalidYield)
|
||||
CODE_ERROR_ENTRY(InvalidAwait)
|
||||
CODE_ERROR_ENTRY(BadDefaultValueType)
|
||||
CODE_ERROR_ENTRY(InvalidMethodDefinition)
|
||||
|
||||
+1090
-990
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+206
-161
@@ -20,7 +20,6 @@
|
||||
#include "hphp/compiler/expression/expression.h"
|
||||
#include "hphp/compiler/statement/statement.h"
|
||||
#include "hphp/compiler/statement/use_trait_statement.h"
|
||||
#include "hphp/compiler/statement/trait_require_statement.h"
|
||||
#include "hphp/compiler/statement/trait_prec_statement.h"
|
||||
#include "hphp/compiler/statement/trait_alias_statement.h"
|
||||
#include "hphp/compiler/statement/typedef_statement.h"
|
||||
@@ -111,7 +110,7 @@ public:
|
||||
typ1 a1, typ2 a2, typ3 a3
|
||||
#define FOUR(typ1, typ2, typ3, typ4) \
|
||||
typ1 a1, typ2 a2, typ3 a3, typ4 a4
|
||||
#define MA std::vector<unsigned char>
|
||||
#define MA std::vector<uchar>
|
||||
#define BLA std::vector<Label*>&
|
||||
#define SLA std::vector<StrOff>&
|
||||
#define ILA std::vector<IterPair>&
|
||||
@@ -123,7 +122,7 @@ public:
|
||||
#define SA const StringData*
|
||||
#define AA ArrayData*
|
||||
#define BA Label&
|
||||
#define OA(type) type
|
||||
#define OA unsigned char
|
||||
#define VSA std::vector<std::string>&
|
||||
OPCODES
|
||||
#undef O
|
||||
@@ -330,130 +329,240 @@ public:
|
||||
Label m_entry;
|
||||
};
|
||||
|
||||
DECLARE_BOOST_TYPES(ControlTarget);
|
||||
/*
|
||||
* The structure represents a code path that potentially requires
|
||||
* running finally blocks. A code path has an assigned state ID that
|
||||
* is used inside switch statements emitted at the end of finally
|
||||
* blocks. It also has an optional label (the destination to jump
|
||||
* to after all the required finally blocks are run).
|
||||
*/
|
||||
struct ControlTarget {
|
||||
static const int k_unsetState;
|
||||
explicit ControlTarget(EmitterVisitor* router);
|
||||
~ControlTarget();
|
||||
// Manage state ID reuse.
|
||||
bool isRegistered();
|
||||
EmitterVisitor* m_visitor;
|
||||
// The target to jump to once all the necessary finally blocks are run.
|
||||
Label m_label;
|
||||
// The state ID that identifies this control target inside finally
|
||||
// epilogues. This ID assigned to the "state" unnamed local variable.
|
||||
int m_state;
|
||||
};
|
||||
|
||||
struct ControlTargetInfo {
|
||||
ControlTargetInfo() : used(false) {}
|
||||
ControlTargetInfo(ControlTargetPtr t, bool b) : target(t), used(b) {}
|
||||
ControlTargetPtr target;
|
||||
bool used;
|
||||
};
|
||||
class FinallyRouter;
|
||||
|
||||
DECLARE_BOOST_TYPES(Region);
|
||||
DECLARE_BOOST_TYPES(FinallyRouterEntry);
|
||||
/*
|
||||
* Region represents a single level of the unified stack
|
||||
* FinallyRouterEntry represents a single level of the unified stack
|
||||
* of constructs that are meaningful from the point of view of finally
|
||||
* implementation. The levels are used to keep track of the information
|
||||
* such as the control targets that can be taken inside a block.
|
||||
* such as the actions that can be taken inside a block.
|
||||
*/
|
||||
class Region {
|
||||
class FinallyRouterEntry {
|
||||
public:
|
||||
enum Kind {
|
||||
enum EntryKind {
|
||||
// Top-level (global) context.
|
||||
Global,
|
||||
GlobalEntry,
|
||||
// Function body / method body entry.
|
||||
FuncBody,
|
||||
FuncBodyEntry,
|
||||
// Entry for finally fault funclets emitted after the body of
|
||||
// a function
|
||||
FaultFunclet,
|
||||
// Region by a finally clause
|
||||
TryFinally,
|
||||
FuncFaultEntry,
|
||||
// Try block entry (begins with try ends after catches).
|
||||
TryFinallyEntry,
|
||||
// Finally block entry (begins after catches ends after finally)
|
||||
Finally,
|
||||
// Loop or switch statement.
|
||||
LoopOrSwitch,
|
||||
FinallyEntry,
|
||||
// Loop OR a break statement.
|
||||
LoopEntry,
|
||||
};
|
||||
|
||||
typedef Emitter::IterPair IterPair;
|
||||
typedef std::vector<IterPair> IterVec;
|
||||
|
||||
Region(Region::Kind kind, RegionPtr parent);
|
||||
DECLARE_BOOST_TYPES(Action);
|
||||
/*
|
||||
* The structure represents a code path that potentially requires
|
||||
* running finally blocks. A code path has an assigned state ID that
|
||||
* is used inside switch statements emitted at the end of finally
|
||||
* blocks. It also has an optional label (the destination to jump
|
||||
* to after all the required finally blocks are run).
|
||||
*/
|
||||
struct Action {
|
||||
static const int k_unsetState;
|
||||
|
||||
explicit Action(FinallyRouter* router);
|
||||
~Action();
|
||||
|
||||
// Manage state ID reuse.
|
||||
bool isAllocated();
|
||||
void allocate();
|
||||
void release();
|
||||
|
||||
FinallyRouter* m_router;
|
||||
// The target to jump to once all the necessary finally blocks
|
||||
// are run.
|
||||
Label m_label;
|
||||
// The state ID that identifies this action inside finally switch
|
||||
// statements. This is the id assigned to the "state" unnamed
|
||||
// local variable.
|
||||
int m_state;
|
||||
};
|
||||
|
||||
FinallyRouterEntry(FinallyRouter* router,
|
||||
EntryKind kind,
|
||||
FinallyRouterEntryPtr parent);
|
||||
~FinallyRouterEntry();
|
||||
|
||||
// Helpers used for freeing iterators when appropriate actions
|
||||
// require that.
|
||||
void emitIterBreak(Emitter& e,
|
||||
IterVec& iters,
|
||||
Label& target);
|
||||
void emitIterFree(Emitter& e, IterVec& iters);
|
||||
void emitIterFree(Emitter& e);
|
||||
|
||||
// Emission of code snippets commencing actions. Method
|
||||
// emitXYZ(e, ...) should be used instead of e.XYZ(...) in
|
||||
// EmitterVisitor.
|
||||
void emitReturn(Emitter& e, char sym);
|
||||
void emitReturnImpl(Emitter& e,
|
||||
char sym,
|
||||
IterVec& iters);
|
||||
void emitGoto(Emitter& e, StringData* name);
|
||||
void emitGotoImpl(Emitter& e,
|
||||
StringData* name,
|
||||
IterVec& iters);
|
||||
void emitBreak(Emitter& e, int depth);
|
||||
void emitBreakImpl(Emitter& e,
|
||||
int depth,
|
||||
IterVec& iters);
|
||||
void emitContinue(Emitter& e, int depth);
|
||||
void emitContinueImpl(Emitter& e,
|
||||
int depth,
|
||||
IterVec& iters);
|
||||
|
||||
// Emit the switch statement in the finally epilogue. Optimizes
|
||||
// cases where there is either just a fall-through case, or where
|
||||
// there is a single case other than fall-through.
|
||||
void emitFinallySwitch(Emitter& e);
|
||||
|
||||
// Helper for emitting beginning of single case from the finally
|
||||
// epilogue.
|
||||
void emitCase(Emitter& e, std::vector<Label*>& cases, ActionPtr action);
|
||||
void emitReturnCase(Emitter& e, std::vector<Label*>& cases, char sym);
|
||||
void emitReturnCaseImpl(Emitter& e, char sym, IterVec& iters);
|
||||
void emitBreakCase(Emitter& e, std::vector<Label*>& cases, int depth);
|
||||
void emitBreakCaseImpl(Emitter& e, int depth, IterVec& iters);
|
||||
void emitContinueCase(Emitter& e, std::vector<Label*>& cases, int depth);
|
||||
void emitContinueCaseImpl(Emitter& e, int depth, IterVec& iters);
|
||||
|
||||
// Helper for establishing the maximal depth of break / continue
|
||||
// control targets that are allocated.
|
||||
// actions that are allocated.
|
||||
int getBreakContinueDepth();
|
||||
|
||||
// Returns the maximal break / continue depth admissable (aka the
|
||||
// number of nested loops).
|
||||
int getMaxBreakContinueDepth();
|
||||
|
||||
int getMaxState();
|
||||
// Methods used for emitting different cases for the finally
|
||||
// epilogue switch.
|
||||
void emitGotoCase(Emitter& e, std::vector<Label*>& cases, StringData* name);
|
||||
void emitGotoCaseImpl(Emitter& e, StringData* name, IterVec& iters);
|
||||
void emitReturnCases(Emitter& e, std::vector<Label*>& cases);
|
||||
void emitGotoCases(Emitter& e, std::vector<Label*>& cases);
|
||||
void emitBreakContinueCases(Emitter& e, std::vector<Label*>& cases);
|
||||
void emitAllCases(Emitter& e, std::vector<Label*>& cases);
|
||||
|
||||
// Methods used for collecting labels corresponding to the cases
|
||||
// from the finally epilogue. All the labels are accumulated
|
||||
// inside the cases array. The array is eventually passed to
|
||||
// e.Switch as the immediate argument.
|
||||
void collectReturnCases(std::vector<Label*>& cases);
|
||||
void collectGotoCases(std::vector<Label*>& cases);
|
||||
void collectBreakContinueCases(std::vector<Label*>& cases);
|
||||
void collectCase(std::vector<Label*>& cases,
|
||||
ActionPtr action);
|
||||
void collectAllCases(std::vector<Label*>& cases);
|
||||
|
||||
// The number of cases to be emitted. This is a helper used in
|
||||
// establishing whether one of the optimized cases can be used.
|
||||
int getCaseCount();
|
||||
|
||||
bool isForeach() { return m_iterId != -1; }
|
||||
bool isTryFinally() { return m_kind == Region::Kind::TryFinally; }
|
||||
bool isFinally() { return m_kind == Region::Kind::Finally; }
|
||||
// Methods used for allocating new finally-aware code-paths.
|
||||
// When alloc is set to false, the action is merely allocated in
|
||||
// memory and shared among different entries. When alloc is set to
|
||||
// true, the action is additionally assigned a state ID.
|
||||
ActionPtr registerReturn(StatementPtr s, char sym);
|
||||
ActionPtr registerGoto(StatementPtr s, StringData* name, bool alloc);
|
||||
ActionPtr registerBreak(StatementPtr s, int depth, bool alloc);
|
||||
ActionPtr registerContinue(StatementPtr s, int depth, bool alloc);
|
||||
// Used to indicate that a particular label is present inside
|
||||
// an entry. Labels don't have corresponding actions, however
|
||||
// they need to be tracked in order to handle gotos appropriately.
|
||||
void registerLabel(StatementPtr s, StringData* name);
|
||||
// Yield / await is not supported inside a finally block for now.
|
||||
// This method throws a parse time fatal whenever appropriate.
|
||||
void registerYieldAwait(ExpressionPtr e);
|
||||
|
||||
bool isBreakUsed(int i) {
|
||||
auto it = m_breakTargets.find(i);
|
||||
if (it == m_breakTargets.end()) return false;
|
||||
return it->second.used;
|
||||
}
|
||||
|
||||
bool isContinueUsed(int i) {
|
||||
auto it = m_continueTargets.find(i);
|
||||
if (it == m_continueTargets.end()) return false;
|
||||
return it->second.used;
|
||||
}
|
||||
|
||||
Region::Kind m_kind;
|
||||
FinallyRouter* m_router;
|
||||
EntryKind m_kind;
|
||||
// Only used for loop / break kind of entries.
|
||||
Id m_iterId;
|
||||
IterKind m_iterKind;
|
||||
bool m_iterRef;
|
||||
// Because of a bug in code emission, functions sometimes have
|
||||
// inconsistent return flavors. Therefore instead of a single
|
||||
// return control target, there need to be one return control
|
||||
// target per flavor used. Once the bug is removed, this code
|
||||
// can be simplified.
|
||||
std::map<char, ControlTargetInfo> m_returnTargets;
|
||||
// Break and continue control targets identified by their depth.
|
||||
std::map<int, ControlTargetInfo> m_breakTargets;
|
||||
std::map<int, ControlTargetInfo> m_continueTargets;
|
||||
// Goto control targets. Each goto control target is identified
|
||||
// by the name of the destination label.
|
||||
std::map<StringData*, ControlTargetInfo, string_data_lt> m_gotoTargets;
|
||||
// A set of goto labels occurrning inside the statement represented
|
||||
// inconsistent return flavours. Therefore instead of a single
|
||||
// return action, there need to be one return action per flavor
|
||||
// used. Once the bug is removed, this code can be simplified.
|
||||
std::map<char, ActionPtr> m_returnActions;
|
||||
// A map of goto actions. Each goto action is identified by the
|
||||
// name of the destination label.
|
||||
std::map<StringData*, ActionPtr, string_data_lt> m_gotoActions;
|
||||
// A map of goto labels occurrning inside the statement represented
|
||||
// by this entry. This value is used for establishing whether
|
||||
// a finally block needs to be executed when performing gotos.
|
||||
std::set<StringData*, string_data_lt> m_gotoLabels;
|
||||
// Continue actions identified by their depth.
|
||||
std::map<int, ActionPtr> m_continueActions;
|
||||
// Break actions identified by their depth.
|
||||
std::map<int, ActionPtr> m_breakActions;
|
||||
// The label denoting the beginning of a finally block inside the
|
||||
// current try. Only used when the entry kind is a try statement.
|
||||
Label m_finallyLabel;
|
||||
// The cases that need to be included in the switch statement. Only
|
||||
// used when kind is set to try statement.
|
||||
// These are the actions that are invoked inside the protected region
|
||||
// protected by the try represented by this entry.
|
||||
std::set<ActionPtr> m_finallyCases;
|
||||
// The parent entry.
|
||||
RegionPtr m_parent;
|
||||
FinallyRouterEntryPtr m_parent;
|
||||
};
|
||||
|
||||
class FinallyRouter {
|
||||
public:
|
||||
typedef FinallyRouterEntry::EntryKind EntryKind;
|
||||
|
||||
FinallyRouter();
|
||||
~FinallyRouter();
|
||||
|
||||
// The top entry on the unified stack.
|
||||
FinallyRouterEntryPtr top();
|
||||
// Create an entry corresponding to the passed in statement s.
|
||||
// If the statement is insignificant (e.g. is an if statement),
|
||||
// nullptr is returned.
|
||||
FinallyRouterEntryPtr createForStatement(StatementPtr s);
|
||||
// Create a global (top-level) entry.
|
||||
FinallyRouterEntryPtr createGlobal(StatementPtr s);
|
||||
// Create an entry for a functiob body.
|
||||
FinallyRouterEntryPtr createFuncBody(StatementPtr s);
|
||||
// Create an entry for a fault funclet inside a function body
|
||||
FinallyRouterEntryPtr createFuncFault(StatementPtr s);
|
||||
// Helper function for creating entries.
|
||||
FinallyRouterEntryPtr create(StatementPtr s, EntryKind kind);
|
||||
// Enter/leave the passed in entry. Note that entries sometimes need be
|
||||
// to be constructed before they are entered, or need to be accessed
|
||||
// after they are left. This especially applies to constructs such
|
||||
// as loops and try blocks.
|
||||
void enter(FinallyRouterEntryPtr);
|
||||
void leave(FinallyRouterEntryPtr);
|
||||
|
||||
// Functions used for handling state IDs allocation.
|
||||
// FIXME (#3275259): This should be moved into global / func
|
||||
// body / fault funclet entries in order to optimize state
|
||||
// allocation. See the task description for more details.
|
||||
int allocateState();
|
||||
void releaseState(int state);
|
||||
|
||||
// The stack of all the entered entries.
|
||||
std::vector<FinallyRouterEntryPtr> m_entries;
|
||||
// The state IDs currently allocated. See FIXME above.
|
||||
std::set<int> m_states;
|
||||
};
|
||||
|
||||
class EmitterVisitor {
|
||||
friend class UnsetUnnamedLocalThunklet;
|
||||
friend class FuncFinisher;
|
||||
public:
|
||||
typedef std::vector<int> IndexChain;
|
||||
typedef Emitter::IterPair IterPair;
|
||||
typedef std::vector<IterPair> IterVec;
|
||||
|
||||
explicit EmitterVisitor(UnitEmitter& ue);
|
||||
~EmitterVisitor();
|
||||
|
||||
@@ -465,7 +574,7 @@ public:
|
||||
void assignFinallyVariableIds();
|
||||
void fixReturnType(Emitter& e, FunctionCallPtr fn,
|
||||
Func* builtinFunc = nullptr);
|
||||
|
||||
typedef std::vector<int> IndexChain;
|
||||
void visitListAssignmentLHS(Emitter& e, ExpressionPtr exp,
|
||||
IndexChain& indexChain,
|
||||
std::vector<IndexChain*>& chainList);
|
||||
@@ -501,13 +610,13 @@ public:
|
||||
|| isJumpTarget(m_ue.bcPos())
|
||||
|| (instrFlags(getPrevOpcode()) & TF) == 0);
|
||||
}
|
||||
FuncEmitter* getFuncEmitter() { return m_curFunc; }
|
||||
FinallyRouter& getFinallyRouter() { return m_finallyRouter; }
|
||||
Id getStateLocal() {
|
||||
assert(m_stateLocal >= 0);
|
||||
DCHECK(m_stateLocal >= 0);
|
||||
return m_stateLocal;
|
||||
}
|
||||
Id getRetLocal() {
|
||||
assert(m_retLocal >= 0);
|
||||
DCHECK(m_retLocal >= 0);
|
||||
return m_retLocal;
|
||||
}
|
||||
|
||||
@@ -579,11 +688,11 @@ private:
|
||||
FuncEmitter* m_fe;
|
||||
};
|
||||
|
||||
class CatchRegion {
|
||||
class ExnHandlerRegion {
|
||||
public:
|
||||
CatchRegion(Offset start, Offset end) : m_start(start),
|
||||
ExnHandlerRegion(Offset start, Offset end) : m_start(start),
|
||||
m_end(end) {}
|
||||
~CatchRegion() {
|
||||
~ExnHandlerRegion() {
|
||||
for (std::vector<std::pair<StringData*, Label*> >::const_iterator it =
|
||||
m_catchLabels.begin(); it != m_catchLabels.end(); it++) {
|
||||
delete it->second;
|
||||
@@ -662,31 +771,24 @@ private:
|
||||
static EmittedClosures s_emittedClosures;
|
||||
std::deque<Funclet*> m_funclets;
|
||||
std::map<StatementPtr, Funclet*> m_memoizedFunclets;
|
||||
std::deque<CatchRegion*> m_catchRegions;
|
||||
std::deque<ExnHandlerRegion*> m_exnHandlers;
|
||||
std::deque<FaultRegion*> m_faultRegions;
|
||||
std::deque<FPIRegion*> m_fpiRegions;
|
||||
std::vector<Array> m_staticArrays;
|
||||
std::set<std::string,stdltistr> m_hoistables;
|
||||
LocationPtr m_tempLoc;
|
||||
std::vector<Label> m_yieldLabels;
|
||||
|
||||
// The stack of all Regions that this EmitterVisitor is currently inside
|
||||
std::vector<RegionPtr> m_regions;
|
||||
// The state IDs currently allocated for the "finally router" logic.
|
||||
// See FIXME above the registerControlTarget() method.
|
||||
std::set<int> m_states;
|
||||
// Unnamed local variables used by the "finally router" logic
|
||||
FinallyRouter m_finallyRouter;
|
||||
Id m_stateLocal;
|
||||
Id m_retLocal;
|
||||
|
||||
MetaInfoBuilder m_metaInfo;
|
||||
|
||||
public:
|
||||
bool checkIfStackEmpty(const char* forInstruction) const;
|
||||
void unexpectedStackSym(char sym, const char* where) const;
|
||||
|
||||
int scanStackForLocation(int iLast);
|
||||
void buildVectorImm(std::vector<unsigned char>& vectorImm,
|
||||
void buildVectorImm(std::vector<uchar>& vectorImm,
|
||||
int iFirst, int iLast, bool allowW,
|
||||
Emitter& e);
|
||||
enum class PassByRefKind {
|
||||
@@ -709,7 +811,7 @@ public:
|
||||
void emitSet(Emitter& e);
|
||||
void emitSetOp(Emitter& e, int op);
|
||||
void emitBind(Emitter& e);
|
||||
void emitIncDec(Emitter& e, IncDecOp cop);
|
||||
void emitIncDec(Emitter& e, unsigned char cop);
|
||||
void emitPop(Emitter& e);
|
||||
void emitConvertToCell(Emitter& e);
|
||||
void emitConvertToCellIfVar(Emitter& e);
|
||||
@@ -809,44 +911,14 @@ public:
|
||||
void emitForeachListAssignment(Emitter& e,
|
||||
ListAssignmentPtr la,
|
||||
int vLocalId);
|
||||
void emitForeach(Emitter& e, ForEachStatementPtr fe);
|
||||
void emitForeach(Emitter& e,
|
||||
ForEachStatementPtr fe,
|
||||
FinallyRouterEntryPtr entry);
|
||||
void emitRestoreErrorReporting(Emitter& e, Id oldLevelLoc);
|
||||
void emitMakeUnitFatal(Emitter& e,
|
||||
const char* msg,
|
||||
FatalOp k = FatalOp::Runtime);
|
||||
|
||||
// Emits a Jmp or IterBreak instruction to the specified target, freeing
|
||||
// the specified iterator variables. emitJump() cannot be used to leave a
|
||||
// try region, except if it jumps to the m_finallyLabel of the try region.
|
||||
void emitJump(Emitter& e, IterVec& iters, Label& target);
|
||||
|
||||
// These methods handle the return, break, continue, and goto operations.
|
||||
// These methods are aware of try/finally blocks and foreach blocks and
|
||||
// will free iterators and jump to finally epilogues as appropriate.
|
||||
void emitReturn(Emitter& e, char sym, StatementPtr s);
|
||||
void emitBreak(Emitter& e, int depth, StatementPtr s);
|
||||
void emitContinue(Emitter& e, int depth, StatementPtr s);
|
||||
void emitGoto(Emitter& e, StringData* name, StatementPtr s);
|
||||
|
||||
// Helper methods for emitting IterFree instructions
|
||||
void emitIterFree(Emitter& e, IterVec& iters);
|
||||
void emitIterFreeForReturn(Emitter& e);
|
||||
|
||||
// A "finally epilogue" is a blob of bytecode that comes after an inline
|
||||
// copy of a "finally" clause body. Finally epilogues are used to ensure
|
||||
// that that the bodies of finally clauses are executed whenever a return,
|
||||
// break, continue, or goto operation jumps out of their corresponding
|
||||
// "try" blocks.
|
||||
void emitFinallyEpilogue(Emitter& e, Region* entry);
|
||||
void emitReturnTrampoline(Emitter& e, Region* entry,
|
||||
std::vector<Label*>& cases, char sym);
|
||||
void emitBreakTrampoline(Emitter& e, Region* entry,
|
||||
std::vector<Label*>& cases, int depth);
|
||||
void emitContinueTrampoline(Emitter& e, Region* entry,
|
||||
std::vector<Label*>& cases, int depth);
|
||||
void emitGotoTrampoline(Emitter& e, Region* entry,
|
||||
std::vector<Label*>& cases, StringData* name);
|
||||
|
||||
Funclet* addFunclet(Thunklet* body);
|
||||
Funclet* addFunclet(StatementPtr stmt,
|
||||
Thunklet* body);
|
||||
@@ -867,20 +939,18 @@ public:
|
||||
Offset end,
|
||||
Label* entry,
|
||||
FaultIterInfo = FaultIterInfo { -1, KindOfIter });
|
||||
void
|
||||
newFaultRegionAndFunclet(Offset start,
|
||||
void newFuncletAndRegion(Offset start,
|
||||
Offset end,
|
||||
Thunklet* t,
|
||||
FaultIterInfo = FaultIterInfo { -1, KindOfIter });
|
||||
void
|
||||
newFaultRegionAndFunclet(StatementPtr stmt,
|
||||
void newFuncletAndRegion(StatementPtr stmt,
|
||||
Offset start,
|
||||
Offset end,
|
||||
Thunklet* t,
|
||||
FaultIterInfo = FaultIterInfo { -1, KindOfIter });
|
||||
|
||||
void newFPIRegion(Offset start, Offset end, Offset fpOff);
|
||||
void copyOverCatchAndFaultRegions(FuncEmitter* fe);
|
||||
void copyOverExnHandlers(FuncEmitter* fe);
|
||||
void copyOverFPIRegions(FuncEmitter* fe);
|
||||
void saveMaxStackCells(FuncEmitter* fe);
|
||||
void finishFunc(Emitter& e, FuncEmitter* fe);
|
||||
@@ -892,31 +962,6 @@ public:
|
||||
void emitClassTraitAliasRule(PreClassEmitter* pce,
|
||||
TraitAliasStatementPtr rule);
|
||||
void emitClassUseTrait(PreClassEmitter* pce, UseTraitStatementPtr useStmt);
|
||||
|
||||
// Helper function for creating entries.
|
||||
RegionPtr createRegion(StatementPtr s, Region::Kind kind);
|
||||
// Enter/leave the passed in entry. Note that entries sometimes need be
|
||||
// to be constructed before they are entered, or need to be accessed
|
||||
// after they are left. This especially applies to constructs such
|
||||
// as loops and try blocks.
|
||||
void enterRegion(RegionPtr);
|
||||
void leaveRegion(RegionPtr);
|
||||
|
||||
// Functions used for handling state IDs allocation.
|
||||
// FIXME (#3275259): This should be moved into global / func
|
||||
// body / fault funclet entries in order to optimize state
|
||||
// allocation. See the task description for more details.
|
||||
void registerControlTarget(ControlTarget* t);
|
||||
void unregisterControlTarget(ControlTarget* t);
|
||||
|
||||
void registerReturn(StatementPtr s, Region* entry, char sym);
|
||||
void registerYieldAwait(ExpressionPtr e);
|
||||
ControlTargetPtr registerBreak(StatementPtr s, Region* entry, int depth,
|
||||
bool alloc);
|
||||
ControlTargetPtr registerContinue(StatementPtr s, Region* entry, int depth,
|
||||
bool alloc);
|
||||
ControlTargetPtr registerGoto(StatementPtr s, Region* entry,
|
||||
StringData* name, bool alloc);
|
||||
};
|
||||
|
||||
void emitAllHHBC(AnalysisResultPtr ar);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "folly/ScopeGuard.h"
|
||||
|
||||
#include "hphp/compiler/analysis/code_error.h"
|
||||
#include "hphp/compiler/analysis/lambda_names.h"
|
||||
#include "hphp/compiler/analysis/analysis_result.h"
|
||||
#include "hphp/compiler/analysis/class_scope.h"
|
||||
#include "hphp/compiler/statement/statement_list.h"
|
||||
@@ -30,7 +29,7 @@
|
||||
#include "hphp/compiler/parser/parser.h"
|
||||
#include "hphp/util/logger.h"
|
||||
#include "hphp/util/util.h"
|
||||
#include "hphp/util/deprecated/base.h"
|
||||
#include "hphp/util/base.h"
|
||||
#include "hphp/compiler/expression/expression_list.h"
|
||||
#include "hphp/compiler/statement/function_statement.h"
|
||||
#include "hphp/compiler/analysis/variable_table.h"
|
||||
@@ -39,14 +38,15 @@
|
||||
#include "hphp/compiler/expression/user_attribute.h"
|
||||
#include "hphp/runtime/base/complex-types.h"
|
||||
|
||||
namespace HPHP {
|
||||
using namespace HPHP;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FileScope::FileScope(const string &fileName, int fileSize, const MD5 &md5)
|
||||
: BlockScope("", "", StatementPtr(), BlockScope::FileScope),
|
||||
m_size(fileSize), m_md5(md5), m_includeState(0), m_system(false),
|
||||
m_fileName(fileName), m_redeclaredFunctions(0) {
|
||||
m_size(fileSize), m_md5(md5), m_module(false), m_privateInclude(false),
|
||||
m_externInclude(false),
|
||||
m_includeState(0), m_fileName(fileName), m_redeclaredFunctions(0) {
|
||||
pushAttribute(); // for global scope
|
||||
}
|
||||
|
||||
@@ -68,11 +68,6 @@ void FileScope::setFileLevel(StatementListPtr stmtList) {
|
||||
}
|
||||
}
|
||||
|
||||
void FileScope::setSystem() {
|
||||
m_fileName = "/:" + m_fileName;
|
||||
m_system = true;
|
||||
}
|
||||
|
||||
FunctionScopePtr FileScope::setTree(AnalysisResultConstPtr ar,
|
||||
StatementListPtr tree) {
|
||||
m_tree = tree;
|
||||
@@ -262,10 +257,9 @@ void FileScope::addConstantDependency(AnalysisResultPtr ar,
|
||||
}
|
||||
|
||||
void FileScope::analyzeProgram(AnalysisResultPtr ar) {
|
||||
if (!m_pseudoMain) return;
|
||||
m_pseudoMain->getStmt()->analyzeProgram(ar);
|
||||
|
||||
resolve_lambda_names(ar, shared_from_this());
|
||||
if (m_pseudoMain) {
|
||||
m_pseudoMain->getStmt()->analyzeProgram(ar);
|
||||
}
|
||||
}
|
||||
|
||||
ClassScopeRawPtr FileScope::resolveClass(ClassScopeRawPtr cls) {
|
||||
@@ -379,6 +373,11 @@ void FileScope::analyzeIncludesHelper(AnalysisResultPtr ar) {
|
||||
static_pointer_cast<IncludeExpression>(exp)->getIncludedFile(ar));
|
||||
if (fs && fs->m_includeState != 1) {
|
||||
if (!fs->m_includeState) {
|
||||
if (m_module && fs->m_privateInclude) {
|
||||
BOOST_FOREACH(BlockScopeRawPtr bs, m_providedDefs) {
|
||||
fs->m_providedDefs.insert(bs);
|
||||
}
|
||||
}
|
||||
fs->analyzeIncludesHelper(ar);
|
||||
}
|
||||
BOOST_FOREACH(BlockScopeRawPtr bs, fs->m_providedDefs) {
|
||||
@@ -396,7 +395,7 @@ void FileScope::analyzeIncludesHelper(AnalysisResultPtr ar) {
|
||||
}
|
||||
|
||||
void FileScope::analyzeIncludes(AnalysisResultPtr ar) {
|
||||
if (!m_includeState) {
|
||||
if (!m_privateInclude && !m_includeState) {
|
||||
analyzeIncludesHelper(ar);
|
||||
}
|
||||
}
|
||||
@@ -458,18 +457,24 @@ string FileScope::outputFilebase() const {
|
||||
|
||||
static void getFuncScopesSet(BlockScopeRawPtrQueue &v,
|
||||
const StringToFunctionScopePtrMap &funcMap) {
|
||||
for (const auto& iter : funcMap) {
|
||||
FunctionScopePtr f = iter.second;
|
||||
if (f->getStmt()) {
|
||||
for (StringToFunctionScopePtrMap::const_iterator
|
||||
iter = funcMap.begin(), end = funcMap.end();
|
||||
iter != end; ++iter) {
|
||||
FunctionScopePtr f = iter->second;
|
||||
if (f->isUserFunction()) {
|
||||
v.push_back(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileScope::getScopesSet(BlockScopeRawPtrQueue &v) {
|
||||
for (const auto& clsVec : getClasses()) {
|
||||
for (const auto cls : clsVec.second) {
|
||||
if (cls->getStmt()) {
|
||||
const StringToClassScopePtrVecMap &classes = getClasses();
|
||||
for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin(),
|
||||
end = classes.end(); iter != end; ++iter) {
|
||||
for (ClassScopePtrVec::const_iterator it = iter->second.begin(),
|
||||
e = iter->second.end(); it != e; ++it) {
|
||||
ClassScopePtr cls = *it;
|
||||
if (cls->isUserClass()) {
|
||||
v.push_back(cls);
|
||||
getFuncScopesSet(v, cls->getFunctions());
|
||||
}
|
||||
@@ -477,17 +482,20 @@ void FileScope::getScopesSet(BlockScopeRawPtrQueue &v) {
|
||||
}
|
||||
|
||||
getFuncScopesSet(v, getFunctions());
|
||||
if (const auto redec = m_redeclaredFunctions) {
|
||||
for (const auto& funcVec : *redec) {
|
||||
auto i = funcVec.second.begin(), e = funcVec.second.end();
|
||||
if (const StringToFunctionScopePtrVecMap *redec = m_redeclaredFunctions) {
|
||||
for (StringToFunctionScopePtrVecMap::const_iterator iter = redec->begin(),
|
||||
end = redec->end(); iter != end; ++iter) {
|
||||
FunctionScopePtrVec::const_iterator i = iter->second.begin(),
|
||||
e = iter->second.end();
|
||||
v.insert(v.end(), ++i, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileScope::getClassesFlattened(ClassScopePtrVec &classes) const {
|
||||
for (const auto& clsVec : m_classes) {
|
||||
for (auto cls : clsVec.second) {
|
||||
for (StringToClassScopePtrVecMap::const_iterator it = m_classes.begin();
|
||||
it != m_classes.end(); ++it) {
|
||||
BOOST_FOREACH(ClassScopePtr cls, it->second) {
|
||||
classes.push_back(cls);
|
||||
}
|
||||
}
|
||||
@@ -510,4 +518,3 @@ void FileScope::serialize(JSON::DocTarget::OutputStream &out) const {
|
||||
ms.done();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,16 +17,14 @@
|
||||
#ifndef incl_HPHP_FILE_SCOPE_H_
|
||||
#define incl_HPHP_FILE_SCOPE_H_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "hphp/compiler/analysis/block_scope.h"
|
||||
#include "hphp/compiler/analysis/function_container.h"
|
||||
#include "hphp/compiler/analysis/code_error.h"
|
||||
#include "hphp/compiler/code_generator.h"
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include "hphp/compiler/json.h"
|
||||
#include "hphp/util/json.h"
|
||||
#include "hphp/util/md5.h"
|
||||
|
||||
namespace HPHP {
|
||||
@@ -80,7 +78,6 @@ public:
|
||||
|
||||
const std::string &getName() const { return m_fileName;}
|
||||
const MD5& getMd5() const { return m_md5; }
|
||||
void setMd5(const MD5& md5) { m_md5 = md5; }
|
||||
StatementListPtr getStmt() const { return m_tree;}
|
||||
const StringToClassScopePtrVecMap &getClasses() const {
|
||||
return m_classes;
|
||||
@@ -145,12 +142,8 @@ public:
|
||||
const std::string &decname);
|
||||
|
||||
void addClassAlias(const std::string& target, const std::string& alias) {
|
||||
m_classAliasMap.insert(
|
||||
std::make_pair(
|
||||
boost::to_lower_copy(target),
|
||||
boost::to_lower_copy(alias)
|
||||
)
|
||||
);
|
||||
m_classAliasMap.insert(std::make_pair(Util::toLower(target),
|
||||
Util::toLower(alias)));
|
||||
}
|
||||
|
||||
std::multimap<std::string,std::string> const& getClassAliases() const {
|
||||
@@ -158,7 +151,7 @@ public:
|
||||
}
|
||||
|
||||
void addTypeAliasName(const std::string& name) {
|
||||
m_typeAliasNames.insert(boost::to_lower_copy(name));
|
||||
m_typeAliasNames.insert(Util::toLower(name));
|
||||
}
|
||||
|
||||
std::set<std::string> const& getTypeAliasNames() const {
|
||||
@@ -173,8 +166,10 @@ public:
|
||||
m_vertex = vertex;
|
||||
}
|
||||
|
||||
void setSystem();
|
||||
bool isSystem() const { return m_system; }
|
||||
void setModule() { m_module = true; }
|
||||
void setPrivateInclude() { m_privateInclude = true; }
|
||||
bool isPrivateInclude() const { return m_privateInclude && !m_externInclude; }
|
||||
void setExternInclude() { m_externInclude = true; }
|
||||
|
||||
void analyzeProgram(AnalysisResultPtr ar);
|
||||
void analyzeIncludes(AnalysisResultPtr ar);
|
||||
@@ -204,8 +199,10 @@ public:
|
||||
private:
|
||||
int m_size;
|
||||
MD5 m_md5;
|
||||
unsigned m_module : 1;
|
||||
unsigned m_privateInclude : 1;
|
||||
unsigned m_externInclude : 1;
|
||||
unsigned m_includeState : 2;
|
||||
unsigned m_system : 1;
|
||||
|
||||
std::vector<int> m_attributes;
|
||||
std::string m_fileName;
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace HPHP {
|
||||
|
||||
class CodeGenerator;
|
||||
DECLARE_BOOST_TYPES(AnalysisResult);
|
||||
DECLARE_EXTENDED_BOOST_TYPES(FunctionScope);
|
||||
DECLARE_BOOST_TYPES(FunctionScope);
|
||||
DECLARE_BOOST_TYPES(ClassScope);
|
||||
DECLARE_BOOST_TYPES(FunctionContainer);
|
||||
|
||||
|
||||
@@ -292,8 +292,7 @@ bool FunctionScope::hasUserAttr(const char *attr) const {
|
||||
}
|
||||
|
||||
bool FunctionScope::isZendParamMode() const {
|
||||
return m_attributeClassInfo &
|
||||
(ClassInfo::ZendParamModeNull | ClassInfo::ZendParamModeFalse);
|
||||
return m_attributeClassInfo & ClassInfo::ZendParamMode;
|
||||
}
|
||||
|
||||
bool FunctionScope::isPublic() const {
|
||||
@@ -848,14 +847,11 @@ bool FunctionScope::popReturnType() {
|
||||
m_prevReturn.reset();
|
||||
return false;
|
||||
}
|
||||
Logger::Verbose("Corrected %s's return type %s -> %s",
|
||||
getFullName().c_str(),
|
||||
m_prevReturn->toString().c_str(),
|
||||
m_returnType->toString().c_str());
|
||||
} else {
|
||||
Logger::Verbose("Set %s's return type %s",
|
||||
getFullName().c_str(),
|
||||
m_returnType->toString().c_str());
|
||||
if (!isFirstPass()) {
|
||||
Logger::Verbose("Corrected function return type %s -> %s",
|
||||
m_prevReturn->toString().c_str(),
|
||||
m_returnType->toString().c_str());
|
||||
}
|
||||
}
|
||||
} else if (!m_prevReturn) {
|
||||
return false;
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
#include "hphp/compiler/expression/user_attribute.h"
|
||||
#include "hphp/compiler/analysis/block_scope.h"
|
||||
#include "hphp/compiler/option.h"
|
||||
#include "hphp/compiler/json.h"
|
||||
|
||||
#include "hphp/util/hash-map-typedefs.h"
|
||||
#include "hphp/util/json.h"
|
||||
#include "hphp/parser/parser.h"
|
||||
|
||||
namespace HPHP {
|
||||
@@ -96,7 +95,6 @@ public:
|
||||
* What kind of function this is.
|
||||
*/
|
||||
bool isUserFunction() const { return !m_system && !isNative(); }
|
||||
bool isSystem() const { return m_system; }
|
||||
bool isDynamic() const { return m_dynamic; }
|
||||
bool isPublic() const;
|
||||
bool isProtected() const;
|
||||
@@ -389,7 +387,7 @@ public:
|
||||
|
||||
ReadWriteMutex &getInlineMutex() { return m_inlineMutex; }
|
||||
|
||||
DECLARE_EXTENDED_BOOST_TYPES(FunctionInfo);
|
||||
DECLARE_BOOST_TYPES(FunctionInfo);
|
||||
|
||||
static void RecordFunctionInfo(std::string fname, FunctionScopePtr func);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#define incl_HPHP_LABEL_SCOPE_H_
|
||||
|
||||
#include "hphp/compiler/hphp.h"
|
||||
#include "hphp/util/deprecated/base.h"
|
||||
#include "hphp/util/base.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
#include "hphp/compiler/analysis/lambda_names.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "folly/ScopeGuard.h"
|
||||
|
||||
#include "hphp/compiler/analysis/variable_table.h"
|
||||
#include "hphp/compiler/analysis/function_scope.h"
|
||||
#include "hphp/compiler/statement/method_statement.h"
|
||||
#include "hphp/compiler/statement/function_statement.h"
|
||||
#include "hphp/compiler/expression/closure_expression.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace {
|
||||
|
||||
struct NameScope {
|
||||
NameScope* const prev;
|
||||
VariableTablePtr const vars;
|
||||
};
|
||||
|
||||
struct Walker {
|
||||
explicit Walker(AnalysisResultPtr ar)
|
||||
: m_curScope{nullptr}
|
||||
, m_ar{ar}
|
||||
{}
|
||||
|
||||
void walk_functions(const FunctionContainer& funcCont) {
|
||||
for (auto& kv : funcCont.getFunctions()) {
|
||||
walk_function(kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void visit_closure(ClosureExpressionPtr ce) {
|
||||
auto const cfunc = ce->getClosureFunction();
|
||||
|
||||
with_scope(
|
||||
cfunc->getScope()->getVariables(),
|
||||
[&] {
|
||||
walk_ast(cfunc->getStmts());
|
||||
}
|
||||
);
|
||||
|
||||
if (ce->type() != ClosureType::Short) return;
|
||||
if (ce->captureState() == ClosureExpression::CaptureState::Known) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto const paramNames = ce->collectParamNames();
|
||||
std::set<std::string> mentioned;
|
||||
cfunc->getScope()->getVariables()->getNames(mentioned);
|
||||
|
||||
std::set<std::string> toCapture;
|
||||
|
||||
for (auto& m : mentioned) {
|
||||
if (paramNames.count(m)) continue;
|
||||
if (m == "this") {
|
||||
toCapture.insert("this");
|
||||
continue;
|
||||
}
|
||||
for (auto scope = m_curScope; scope; scope = scope->prev) {
|
||||
if (scope->vars->getSymbol(m)) {
|
||||
toCapture.insert(m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cfunc->getFunctionScope()->containsThis()) {
|
||||
toCapture.insert("this");
|
||||
}
|
||||
|
||||
ce->setCaptureList(m_ar, toCapture);
|
||||
}
|
||||
|
||||
void walk_ast(ConstructPtr node) {
|
||||
if (!node) return;
|
||||
|
||||
if (dynamic_pointer_cast<MethodStatement>(node)) {
|
||||
// Don't descend into nested non-closure functions, or functions
|
||||
// in the psuedo-main.
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto ce = dynamic_pointer_cast<ClosureExpression>(node)) {
|
||||
visit_closure(ce);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < node->getKidCount(); ++i) {
|
||||
walk_ast(node->getNthKid(i));
|
||||
}
|
||||
}
|
||||
|
||||
void walk_function(const FunctionScopePtr& fscope) {
|
||||
if (fscope->isClosure()) return;
|
||||
auto ms = dynamic_pointer_cast<MethodStatement>(fscope->getStmt());
|
||||
|
||||
ConstructPtr node(ms->getStmts());
|
||||
with_scope(
|
||||
fscope->getVariables(),
|
||||
[&] {
|
||||
walk_ast(node);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
template<class Func>
|
||||
void with_scope(const VariableTablePtr& scopeVars, Func func) {
|
||||
auto newScope = NameScope { m_curScope, scopeVars };
|
||||
m_curScope = &newScope;
|
||||
SCOPE_EXIT { m_curScope = m_curScope->prev; };
|
||||
func();
|
||||
}
|
||||
|
||||
private:
|
||||
NameScope* m_curScope;
|
||||
AnalysisResultPtr m_ar;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void resolve_lambda_names(AnalysisResultPtr ar, const FileScopePtr& fscope) {
|
||||
Walker walker(ar);
|
||||
|
||||
ClassScopePtrVec classScopes;
|
||||
fscope->getClassesFlattened(classScopes);
|
||||
for (auto& cls : classScopes) {
|
||||
walker.walk_functions(*cls);
|
||||
}
|
||||
walker.walk_functions(*fscope);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef incl_HPHP_COMPILER_ANALYSIS_LAMBDA_NAMES_H_
|
||||
#define incl_HPHP_COMPILER_ANALYSIS_LAMBDA_NAMES_H_
|
||||
|
||||
#include "hphp/compiler/statement/statement_list.h"
|
||||
#include "hphp/compiler/analysis/file_scope.h"
|
||||
#include "hphp/compiler/analysis/analysis_result.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* After the first analysis pass over a file, this pass must run to
|
||||
* resolve names for lambda expressions and determine their automatic
|
||||
* capture lists.
|
||||
*/
|
||||
void resolve_lambda_names(AnalysisResultPtr ar, const FileScopePtr&);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -24,7 +24,7 @@ namespace HPHP { namespace Compiler {
|
||||
static void collapseJmp(Offset* offsetPtr, Op* instr, Op* start) {
|
||||
if (offsetPtr) {
|
||||
Op* dest = instr + *offsetPtr;
|
||||
while (isUnconditionalJmp(*dest) && dest != instr) {
|
||||
while (*dest == OpJmp && dest != instr) {
|
||||
dest = start + instrJumpTarget(start, dest - start);
|
||||
}
|
||||
*offsetPtr = dest - instr;
|
||||
@@ -91,10 +91,10 @@ Peephole::Peephole(UnitEmitter &ue, MetaInfoBuilder& metaInfo)
|
||||
// fallthrough
|
||||
|
||||
incDecOp:
|
||||
if (static_cast<IncDecOp>(imm->u_OA) == IncDecOp::PostInc) {
|
||||
imm->u_OA = static_cast<unsigned char>(IncDecOp::PreInc);
|
||||
} else if (static_cast<IncDecOp>(imm->u_OA) == IncDecOp::PostDec) {
|
||||
imm->u_OA = static_cast<unsigned char>(IncDecOp::PreDec);
|
||||
if (imm->u_OA == PostInc) {
|
||||
imm->u_OA = PreInc;
|
||||
} else if (imm->u_OA == PostDec) {
|
||||
imm->u_OA = PreDec;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
#define incl_HPHP_SYMBOL_TABLE_H_
|
||||
|
||||
#include "hphp/compiler/hphp.h"
|
||||
#include "hphp/compiler/json.h"
|
||||
#include "hphp/util/json.h"
|
||||
#include "hphp/util/util.h"
|
||||
#include "hphp/util/lock.h"
|
||||
#include "hphp/util/hash-map-typedefs.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -30,7 +29,7 @@ class BlockScope;
|
||||
class CodeGenerator;
|
||||
class Variant;
|
||||
DECLARE_BOOST_TYPES(Construct);
|
||||
DECLARE_EXTENDED_BOOST_TYPES(Type);
|
||||
DECLARE_BOOST_TYPES(Type);
|
||||
DECLARE_BOOST_TYPES(AnalysisResult);
|
||||
DECLARE_BOOST_TYPES(SymbolTable);
|
||||
DECLARE_BOOST_TYPES(FunctionScope);
|
||||
|
||||
@@ -71,8 +71,6 @@ void Type::InitTypeHintMap() {
|
||||
s_HHTypeHintTypes["double"] = Type::Double;
|
||||
s_HHTypeHintTypes["float"] = Type::Double;
|
||||
s_HHTypeHintTypes["string"] = Type::String;
|
||||
// Type::Numeric doesn't include numeric strings; this is intentional
|
||||
s_HHTypeHintTypes["num"] = Type::Numeric;
|
||||
s_HHTypeHintTypes["resource"] = Type::Resource;
|
||||
s_HHTypeHintTypes["callable"] = Type::Variant;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#define incl_HPHP_TYPE_H_
|
||||
|
||||
#include "hphp/compiler/hphp.h"
|
||||
#include "hphp/compiler/json.h"
|
||||
#include "hphp/util/functional.h"
|
||||
#include "hphp/util/json.h"
|
||||
#include "hphp/util/case-insensitive.h"
|
||||
#include "hphp/runtime/base/types.h"
|
||||
|
||||
|
||||
|
||||
@@ -428,9 +428,7 @@ TypePtr VariableTable::add(Symbol *sym, TypePtr type,
|
||||
type = setType(ar, sym, type, true);
|
||||
if (sym->isParameter()) {
|
||||
auto p = dynamic_pointer_cast<ParameterExpression>(construct);
|
||||
if (p) {
|
||||
sym->setDeclaration(construct);
|
||||
}
|
||||
if (p) sym->setDeclaration(construct);
|
||||
} else {
|
||||
sym->setDeclaration(construct);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "hphp/compiler/analysis/symbol_table.h"
|
||||
#include "hphp/compiler/statement/statement.h"
|
||||
#include "hphp/compiler/analysis/class_scope.h"
|
||||
#include "hphp/util/hash-map-typedefs.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -297,7 +296,7 @@ public:
|
||||
* GlobalVariables class to make ThreadLocal<GlobalVaribles> work.
|
||||
* This data structure is only needed by global scope.
|
||||
*/
|
||||
DECLARE_EXTENDED_BOOST_TYPES(StaticGlobalInfo);
|
||||
DECLARE_BOOST_TYPES(StaticGlobalInfo);
|
||||
struct StaticGlobalInfo {
|
||||
Symbol *sym;
|
||||
VariableTable *variables; // where this variable was from
|
||||
|
||||
@@ -50,7 +50,8 @@ using namespace HPHP;
|
||||
|
||||
bool BuiltinSymbols::Loaded = false;
|
||||
StringBag BuiltinSymbols::s_strings;
|
||||
AnalysisResultPtr BuiltinSymbols::s_systemAr;
|
||||
|
||||
StringToFunctionScopePtrMap BuiltinSymbols::s_functions;
|
||||
|
||||
const char *const BuiltinSymbols::GlobalNames[] = {
|
||||
"HTTP_RAW_POST_DATA",
|
||||
@@ -85,7 +86,12 @@ const char *BuiltinSymbols::SystemClasses[] = {
|
||||
nullptr
|
||||
};
|
||||
|
||||
StringToClassScopePtrMap BuiltinSymbols::s_classes;
|
||||
VariableTablePtr BuiltinSymbols::s_variables;
|
||||
ConstantTablePtr BuiltinSymbols::s_constants;
|
||||
StringToTypePtrMap BuiltinSymbols::s_superGlobals;
|
||||
AnalysisResultPtr BuiltinSymbols::s_systemAr;
|
||||
void *BuiltinSymbols::s_handle_main = nullptr;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -212,6 +218,7 @@ FunctionScopePtr BuiltinSymbols::ImportFunctionScopePtr(AnalysisResultPtr ar,
|
||||
}
|
||||
|
||||
void BuiltinSymbols::ImportExtFunctions(AnalysisResultPtr ar,
|
||||
StringToFunctionScopePtrMap &map,
|
||||
ClassInfo *cls) {
|
||||
const ClassInfo::MethodVec &methods = cls->getMethodsVec();
|
||||
for (auto it = methods.begin(); it != methods.end(); ++it) {
|
||||
@@ -221,13 +228,14 @@ void BuiltinSymbols::ImportExtFunctions(AnalysisResultPtr ar,
|
||||
}
|
||||
|
||||
FunctionScopePtr f = ImportFunctionScopePtr(ar, cls, *it);
|
||||
ar->addSystemFunction(f);
|
||||
assert(!map[f->getName()]);
|
||||
map[f->getName()] = f;
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinSymbols::ImportExtMethods(AnalysisResultPtr ar,
|
||||
FunctionScopePtrVec &vec,
|
||||
ClassInfo *cls) {
|
||||
void BuiltinSymbols::ImportExtFunctions(AnalysisResultPtr ar,
|
||||
FunctionScopePtrVec &vec,
|
||||
ClassInfo *cls) {
|
||||
const ClassInfo::MethodVec &methods = cls->getMethodsVec();
|
||||
for (auto it = methods.begin(); it != methods.end(); ++it) {
|
||||
FunctionScopePtr f = ImportFunctionScopePtr(ar, cls, *it);
|
||||
@@ -279,7 +287,7 @@ void BuiltinSymbols::ImportExtConstants(AnalysisResultPtr ar,
|
||||
ClassScopePtr BuiltinSymbols::ImportClassScopePtr(AnalysisResultPtr ar,
|
||||
ClassInfo *cls) {
|
||||
FunctionScopePtrVec methods;
|
||||
ImportExtMethods(ar, methods, cls);
|
||||
ImportExtFunctions(ar, methods, cls);
|
||||
|
||||
ClassInfo::InterfaceVec ifaces = cls->getInterfacesVec();
|
||||
String parent = cls->getParentClass();
|
||||
@@ -317,7 +325,8 @@ void BuiltinSymbols::ImportExtClasses(AnalysisResultPtr ar) {
|
||||
}
|
||||
|
||||
ClassScopePtr cl = ImportClassScopePtr(ar, it->second);
|
||||
ar->addSystemClass(cl);
|
||||
assert(!s_classes[cl->getName()]);
|
||||
s_classes[cl->getName()] = cl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,11 +338,13 @@ bool BuiltinSymbols::Load(AnalysisResultPtr ar) {
|
||||
ClassInfo::Load();
|
||||
|
||||
// load extension functions first, so system/php may call them
|
||||
ImportExtFunctions(ar, ClassInfo::GetSystem());
|
||||
ImportExtFunctions(ar, s_functions, ClassInfo::GetSystem());
|
||||
AnalysisResultPtr ar2 = AnalysisResultPtr(new AnalysisResult());
|
||||
s_variables = VariableTablePtr(new VariableTable(*ar2.get()));
|
||||
s_constants = ConstantTablePtr(new ConstantTable(*ar2.get()));
|
||||
|
||||
ConstantTablePtr cns = ar->getConstants();
|
||||
// load extension constants, classes and dynamics
|
||||
ImportExtConstants(ar, cns, ClassInfo::GetSystem());
|
||||
ImportExtConstants(ar, s_constants, ClassInfo::GetSystem());
|
||||
ImportExtClasses(ar);
|
||||
|
||||
Array constants = ClassInfo::GetSystemConstants();
|
||||
@@ -342,11 +353,11 @@ bool BuiltinSymbols::Load(AnalysisResultPtr ar) {
|
||||
CVarRef key = it.first();
|
||||
if (!key.isString()) continue;
|
||||
std::string name = key.toCStrRef().data();
|
||||
if (cns->getSymbol(name)) continue;
|
||||
if (s_constants->getSymbol(name)) continue;
|
||||
if (name == "true" || name == "false" || name == "null") continue;
|
||||
CVarRef value = it.secondRef();
|
||||
if (!value.isInitialized() || value.isObject()) continue;
|
||||
ExpressionPtr e = Expression::MakeScalarExpression(ar, ar, loc, value);
|
||||
ExpressionPtr e = Expression::MakeScalarExpression(ar2, ar2, loc, value);
|
||||
TypePtr t =
|
||||
value.isNull() ? Type::Null :
|
||||
value.isBoolean() ? Type::Boolean :
|
||||
@@ -354,47 +365,122 @@ bool BuiltinSymbols::Load(AnalysisResultPtr ar) {
|
||||
value.isDouble() ? Type::Double :
|
||||
value.isArray() ? Type::Array : Type::Variant;
|
||||
|
||||
cns->add(key.toCStrRef().data(), t, e, ar, e);
|
||||
s_constants->add(key.toCStrRef().data(), t, e, ar2, e);
|
||||
}
|
||||
s_variables = ar2->getVariables();
|
||||
for (int i = 0, n = NumGlobalNames(); i < n; ++i) {
|
||||
ar->getVariables()->add(GlobalNames[i], Type::Variant, false, ar,
|
||||
ConstructPtr(), ModifierExpressionPtr());
|
||||
s_variables->add(GlobalNames[i], Type::Variant, false, ar,
|
||||
ConstructPtr(), ModifierExpressionPtr());
|
||||
}
|
||||
|
||||
cns->setDynamic(ar, "PHP_BINARY", true);
|
||||
cns->setDynamic(ar, "PHP_BINDIR", true);
|
||||
cns->setDynamic(ar, "PHP_OS", true);
|
||||
cns->setDynamic(ar, "PHP_SAPI", true);
|
||||
cns->setDynamic(ar, "SID", true);
|
||||
s_constants->setDynamic(ar, "PHP_BINARY", true);
|
||||
s_constants->setDynamic(ar, "PHP_BINDIR", true);
|
||||
s_constants->setDynamic(ar, "PHP_OS", true);
|
||||
s_constants->setDynamic(ar, "PHP_SAPI", true);
|
||||
s_constants->setDynamic(ar, "SID", true);
|
||||
|
||||
// Systemlib files were all parsed by hphp_process_init
|
||||
// parse all PHP files under system/php
|
||||
s_systemAr = ar = AnalysisResultPtr(new AnalysisResult());
|
||||
ar->loadBuiltins();
|
||||
string slib = get_systemlib();
|
||||
|
||||
Scanner scanner(slib.c_str(), slib.size(),
|
||||
Option::GetScannerType(), "systemlib.php");
|
||||
Compiler::Parser parser(scanner, "systemlib.php", ar);
|
||||
if (!parser.parse()) {
|
||||
Logger::Error("Unable to parse systemlib.php: %s",
|
||||
parser.getMessage().c_str());
|
||||
assert(false);
|
||||
}
|
||||
|
||||
ar->analyzeProgram(true);
|
||||
ar->inferTypes();
|
||||
const StringToFileScopePtrMap &files = ar->getAllFiles();
|
||||
for (const auto& file : files) {
|
||||
file.second->setSystem();
|
||||
|
||||
const auto& classes = file.second->getClasses();
|
||||
for (const auto& clsVec : classes) {
|
||||
assert(clsVec.second.size() == 1);
|
||||
auto cls = clsVec.second[0];
|
||||
cls->setSystem();
|
||||
ar->addSystemClass(cls);
|
||||
for (const auto& func : cls->getFunctions()) {
|
||||
FunctionScope::RecordFunctionInfo(func.first, func.second);
|
||||
}
|
||||
for (StringToFileScopePtrMap::const_iterator iterFile = files.begin();
|
||||
iterFile != files.end(); iterFile++) {
|
||||
const StringToClassScopePtrVecMap &classes =
|
||||
iterFile->second->getClasses();
|
||||
for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin();
|
||||
iter != classes.end(); ++iter) {
|
||||
assert(iter->second.size() == 1);
|
||||
iter->second[0]->setSystem();
|
||||
assert(!s_classes[iter->first]);
|
||||
s_classes[iter->first] = iter->second[0];
|
||||
}
|
||||
|
||||
const auto& functions = file.second->getFunctions();
|
||||
for (const auto& func : functions) {
|
||||
func.second->setSystem();
|
||||
ar->addSystemFunction(func.second);
|
||||
FunctionScope::RecordFunctionInfo(func.first, func.second);
|
||||
const StringToFunctionScopePtrMap &functions =
|
||||
iterFile->second->getFunctions();
|
||||
for (StringToFunctionScopePtrMap::const_iterator iter = functions.begin();
|
||||
iter != functions.end(); ++iter) {
|
||||
iter->second->setSystem();
|
||||
s_functions[iter->first] = iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AnalysisResultPtr BuiltinSymbols::LoadGlobalSymbols(const char *fileName) {
|
||||
AnalysisResultPtr ar(new AnalysisResult());
|
||||
string phpBaseName = "/system/globals/";
|
||||
phpBaseName += fileName;
|
||||
string phpFileName = Option::GetSystemRoot() + phpBaseName;
|
||||
const char *baseName = s_strings.add(phpBaseName.c_str());
|
||||
fileName = s_strings.add(phpFileName.c_str());
|
||||
|
||||
try {
|
||||
Scanner scanner(fileName, Option::GetScannerType());
|
||||
Compiler::Parser parser(scanner, baseName, ar);
|
||||
if (!parser.parse()) {
|
||||
assert(false);
|
||||
Logger::Error("Unable to parse file %s: %s", fileName,
|
||||
parser.getMessage().c_str());
|
||||
}
|
||||
} catch (FileOpenException &e) {
|
||||
Logger::Error("%s", e.getMessage().c_str());
|
||||
}
|
||||
ar->analyzeProgram(true);
|
||||
ar->inferTypes();
|
||||
return ar;
|
||||
}
|
||||
|
||||
void BuiltinSymbols::LoadFunctions(AnalysisResultPtr ar,
|
||||
StringToFunctionScopePtrMap &functions) {
|
||||
assert(Loaded);
|
||||
functions.insert(s_functions.begin(), s_functions.end());
|
||||
}
|
||||
|
||||
void BuiltinSymbols::LoadClasses(AnalysisResultPtr ar,
|
||||
StringToClassScopePtrMap &classes) {
|
||||
assert(Loaded);
|
||||
classes.insert(s_classes.begin(), s_classes.end());
|
||||
}
|
||||
|
||||
void BuiltinSymbols::LoadVariables(AnalysisResultPtr ar,
|
||||
VariableTablePtr variables) {
|
||||
assert(Loaded);
|
||||
if (s_variables) {
|
||||
variables->import(s_variables);
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinSymbols::LoadConstants(AnalysisResultPtr ar,
|
||||
ConstantTablePtr constants) {
|
||||
assert(Loaded);
|
||||
if (s_constants) {
|
||||
constants->import(s_constants);
|
||||
}
|
||||
}
|
||||
|
||||
ConstantTablePtr BuiltinSymbols::LoadSystemConstants() {
|
||||
AnalysisResultPtr ar = LoadGlobalSymbols("constants.php");
|
||||
const auto &fileScopes = ar->getAllFilesVector();
|
||||
if (!fileScopes.empty()) {
|
||||
return fileScopes[0]->getConstants();
|
||||
}
|
||||
throw std::runtime_error("LoadSystemConstants failed");
|
||||
}
|
||||
|
||||
void BuiltinSymbols::LoadSuperGlobals() {
|
||||
if (s_superGlobals.empty()) {
|
||||
s_superGlobals["_SERVER"] = Type::Variant;
|
||||
|
||||
@@ -24,17 +24,16 @@
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DECLARE_EXTENDED_BOOST_TYPES(Type);
|
||||
DECLARE_BOOST_TYPES(Type);
|
||||
DECLARE_BOOST_TYPES(AnalysisResult);
|
||||
DECLARE_EXTENDED_BOOST_TYPES(FunctionScope);
|
||||
DECLARE_EXTENDED_BOOST_TYPES(ClassScope);
|
||||
DECLARE_BOOST_TYPES(FunctionScope);
|
||||
DECLARE_BOOST_TYPES(ClassScope);
|
||||
DECLARE_BOOST_TYPES(VariableTable);
|
||||
DECLARE_BOOST_TYPES(ConstantTable);
|
||||
|
||||
class BuiltinSymbols {
|
||||
public:
|
||||
static bool Loaded;
|
||||
static AnalysisResultPtr s_systemAr;
|
||||
|
||||
static bool Load(AnalysisResultPtr ar);
|
||||
|
||||
@@ -47,6 +46,11 @@ public:
|
||||
static void LoadConstants(AnalysisResultPtr ar,
|
||||
ConstantTablePtr constants);
|
||||
|
||||
/*
|
||||
* Load system/globals/constants.php.
|
||||
*/
|
||||
static ConstantTablePtr LoadSystemConstants();
|
||||
|
||||
/**
|
||||
* Testing whether a variable is a PHP superglobal.
|
||||
*/
|
||||
@@ -56,24 +60,35 @@ public:
|
||||
static bool IsDeclaredDynamic(const std::string& name);
|
||||
static void LoadSuperGlobals();
|
||||
|
||||
static StringToFunctionScopePtrMap s_functions;
|
||||
static StringToClassScopePtrMap s_classes;
|
||||
static VariableTablePtr s_variables;
|
||||
static ConstantTablePtr s_constants;
|
||||
static AnalysisResultPtr s_systemAr;
|
||||
|
||||
static const char *const GlobalNames[];
|
||||
static int NumGlobalNames();
|
||||
private:
|
||||
static StringBag s_strings;
|
||||
static const char *SystemClasses[];
|
||||
|
||||
static AnalysisResultPtr LoadGlobalSymbols(const char *fileName);
|
||||
|
||||
static StringToTypePtrMap s_superGlobals;
|
||||
|
||||
static std::set<std::string> s_declaredDynamic;
|
||||
|
||||
static void *s_handle_main;
|
||||
|
||||
static FunctionScopePtr ImportFunctionScopePtr(AnalysisResultPtr ar,
|
||||
ClassInfo *cls,
|
||||
ClassInfo::MethodInfo *method);
|
||||
static void ImportExtFunctions(AnalysisResultPtr ar,
|
||||
StringToFunctionScopePtrMap &map,
|
||||
ClassInfo *cls);
|
||||
static void ImportExtFunctions(AnalysisResultPtr ar,
|
||||
FunctionScopePtrVec &vec,
|
||||
ClassInfo *cls);
|
||||
static void ImportExtMethods(AnalysisResultPtr ar,
|
||||
FunctionScopePtrVec &vec,
|
||||
ClassInfo *cls);
|
||||
static void ImportExtProperties(AnalysisResultPtr ar,
|
||||
VariableTablePtr dest,
|
||||
ClassInfo *cls);
|
||||
|
||||
@@ -451,14 +451,6 @@ void CodeGenerator::printPropertyHeader(const std::string propertyName) {
|
||||
printf("%s\";", propertyName.c_str());
|
||||
}
|
||||
|
||||
void CodeGenerator::printNull() {
|
||||
printf("N;");
|
||||
}
|
||||
|
||||
void CodeGenerator::printBool(bool value) {
|
||||
printf("b:%d;", value ? 1 : 0);
|
||||
}
|
||||
|
||||
void CodeGenerator::printValue(double v) {
|
||||
*m_out << "d:";
|
||||
if (std::isnan(v)) {
|
||||
@@ -481,7 +473,7 @@ void CodeGenerator::printValue(int32_t value) {
|
||||
}
|
||||
|
||||
void CodeGenerator::printValue(int64_t value) {
|
||||
printf("i:%" PRId64 ";", value);
|
||||
printf("i:%ld;", value);
|
||||
}
|
||||
|
||||
void CodeGenerator::printValue(std::string value) {
|
||||
@@ -491,7 +483,7 @@ void CodeGenerator::printValue(std::string value) {
|
||||
}
|
||||
|
||||
void CodeGenerator::printModifierVector(std::string value) {
|
||||
printf("V:9:\"HH\\Vector\":1:{");
|
||||
printf("V:6:\"Vector\":1:{");
|
||||
printObjectHeader("Modifier", 1);
|
||||
printPropertyHeader("name");
|
||||
printValue(value);
|
||||
@@ -508,12 +500,12 @@ void CodeGenerator::printTypeExpression(std::string value) {
|
||||
|
||||
void CodeGenerator::printExpression(ExpressionPtr expression, bool isRef) {
|
||||
if (isRef) {
|
||||
printObjectHeader("UnaryOpExpression", 3);
|
||||
printObjectHeader("UnaryOpExpression", 4);
|
||||
printPropertyHeader("expression");
|
||||
expression->outputCodeModel(*this);
|
||||
printPropertyHeader("operation");
|
||||
printValue(PHP_REFERENCE_OP);
|
||||
printPropertyHeader("sourceLocation");
|
||||
printPropertyHeader("location");
|
||||
printLocation(expression->getLocation());
|
||||
printObjectFooter();
|
||||
} else {
|
||||
@@ -522,62 +514,47 @@ void CodeGenerator::printExpression(ExpressionPtr expression, bool isRef) {
|
||||
}
|
||||
|
||||
void CodeGenerator::printExpressionVector(ExpressionListPtr el) {
|
||||
auto count = el == nullptr ? 0 : el->getCount();
|
||||
printf("V:9:\"HH\\Vector\":%d:{", count);
|
||||
if (count > 0) {
|
||||
printf("V:6:\"Vector\":%d:{", el->getCount());
|
||||
if (el->getCount() > 0) {
|
||||
el->outputCodeModel(*this);
|
||||
}
|
||||
printf("}");
|
||||
}
|
||||
|
||||
void CodeGenerator::printExpressionVector(ExpressionPtr e) {
|
||||
if (e->is(Expression::KindOfExpressionList)) {
|
||||
auto sl = static_pointer_cast<ExpressionList>(e);
|
||||
printExpressionVector(sl);
|
||||
} else {
|
||||
printf("V:9:\"HH\\Vector\":1:{");
|
||||
e->outputCodeModel(*this);
|
||||
printf("}");
|
||||
}
|
||||
printf("V:6:\"Vector\":1:{");
|
||||
e->outputCodeModel(*this);
|
||||
printf("}");
|
||||
}
|
||||
|
||||
void CodeGenerator::printAsBlock(StatementPtr s) {
|
||||
if (s != nullptr && s->is(Statement::KindOfBlockStatement)) {
|
||||
if (s->is(Statement::KindOfBlockStatement)) {
|
||||
s->outputCodeModel(*this);
|
||||
} else {
|
||||
auto numProps = s == nullptr ? 1 : 2;
|
||||
printObjectHeader("BlockStatement", numProps);
|
||||
printObjectHeader("BlockStatement", 2);
|
||||
printPropertyHeader("statements");
|
||||
printStatementVector(s);
|
||||
if (s != nullptr) {
|
||||
printPropertyHeader("sourceLocation");
|
||||
printLocation(s->getLocation());
|
||||
if (s->is(Statement::KindOfStatementList)) {
|
||||
auto sl = static_pointer_cast<StatementList>(s);
|
||||
printStatementVector(sl);
|
||||
} else {
|
||||
printf("V:6:\"Vector\":1:{");
|
||||
s->outputCodeModel(*this);
|
||||
printf("}");
|
||||
}
|
||||
printPropertyHeader("location");
|
||||
printLocation(s->getLocation());
|
||||
printObjectFooter();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::printStatementVector(StatementListPtr sl) {
|
||||
printf("V:9:\"HH\\Vector\":%d:{", sl->getCount());
|
||||
printf("V:6:\"Vector\":%d:{", sl->getCount());
|
||||
if (sl->getCount() > 0) {
|
||||
sl->outputCodeModel(*this);
|
||||
}
|
||||
printf("}");
|
||||
}
|
||||
|
||||
void CodeGenerator::printStatementVector(StatementPtr s) {
|
||||
if (s == nullptr) {
|
||||
printf("V:9:\"HH\\Vector\":0:{}");
|
||||
} else if (s->is(Statement::KindOfStatementList)) {
|
||||
auto sl = static_pointer_cast<StatementList>(s);
|
||||
printStatementVector(sl);
|
||||
} else {
|
||||
printf("V:9:\"HH\\Vector\":1:{");
|
||||
s->outputCodeModel(*this);
|
||||
printf("}");
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::printLocation(LocationPtr location) {
|
||||
if (location == nullptr) return;
|
||||
printObjectHeader("SourceLocation", 4);
|
||||
|
||||
@@ -27,7 +27,7 @@ DECLARE_BOOST_TYPES(Statement);
|
||||
DECLARE_BOOST_TYPES(StatementList);
|
||||
DECLARE_BOOST_TYPES(Construct);
|
||||
DECLARE_BOOST_TYPES(BlockScope);
|
||||
DECLARE_EXTENDED_BOOST_TYPES(ClassScope);
|
||||
DECLARE_BOOST_TYPES(ClassScope);
|
||||
DECLARE_BOOST_TYPES(FunctionScope);
|
||||
DECLARE_BOOST_TYPES(FileScope);
|
||||
DECLARE_BOOST_TYPES(LoopStatement);
|
||||
@@ -277,8 +277,6 @@ public:
|
||||
void printObjectHeader(const std::string className, int numProperties);
|
||||
void printPropertyHeader(const std::string propertyName);
|
||||
void printObjectFooter();
|
||||
void printNull();
|
||||
void printBool(bool value);
|
||||
void printValue(double value);
|
||||
void printValue(int32_t value);
|
||||
void printValue(int64_t value);
|
||||
@@ -290,7 +288,6 @@ public:
|
||||
void printExpressionVector(ExpressionPtr e);
|
||||
void printAsBlock(StatementPtr s);
|
||||
void printStatementVector(StatementListPtr sl);
|
||||
void printStatementVector(StatementPtr s);
|
||||
void printLocation(LocationPtr location);
|
||||
void setAstClassPrefix(const std::string &prefix) { m_astPrefix = prefix; }
|
||||
private:
|
||||
|
||||
@@ -85,18 +85,11 @@ namespace HPHP {
|
||||
PHP_POST_INCREMENT_OP = 18,
|
||||
PHP_PRE_DECREMENT_OP = 19,
|
||||
PHP_PRE_INCREMENT_OP = 20,
|
||||
PHP_PRINT_OP = 21,
|
||||
PHP_REFERENCE_OP = 22,
|
||||
PHP_REQUIRE_OP = 23,
|
||||
PHP_REQUIRE_ONCE_OP = 24,
|
||||
PHP_STRING_CAST_OP = 25,
|
||||
PHP_UNSET_CAST_OP = 26,
|
||||
};
|
||||
|
||||
/** Enumerates the kinds of trait require statements. */
|
||||
enum CodeModelRequireKind {
|
||||
PHP_EXTENDS = 1,
|
||||
PHP_IMPLEMENTS = 2,
|
||||
PHP_REFERENCE_OP = 21,
|
||||
PHP_REQUIRE_OP = 22,
|
||||
PHP_REQUIRE_ONCE_OP = 23,
|
||||
PHP_STRING_CAST_OP = 24,
|
||||
PHP_UNSET_CAST_OP = 25,
|
||||
};
|
||||
|
||||
/** Enumerates the kinds of type declaration statements. */
|
||||
@@ -106,12 +99,5 @@ namespace HPHP {
|
||||
PHP_TRAIT = 3,
|
||||
};
|
||||
|
||||
/** The sort order to use when grouping query results */
|
||||
enum CodeModelOrder {
|
||||
PHP_NOT_SPECIFIED = 1,
|
||||
PHP_ASCENDING = 2,
|
||||
PHP_DESCENDING = 3,
|
||||
};
|
||||
|
||||
}
|
||||
#endif // incl_HPHP_CODE_MODEL_ENUMS_H_
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "hphp/compiler/option.h"
|
||||
#include "hphp/compiler/parser/parser.h"
|
||||
#include "hphp/compiler/builtin_symbols.h"
|
||||
#include "hphp/compiler/json.h"
|
||||
#include "hphp/util/json.h"
|
||||
#include "hphp/util/logger.h"
|
||||
#include "hphp/util/db-conn.h"
|
||||
#include "hphp/util/exception.h"
|
||||
@@ -484,8 +484,6 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
|
||||
Option::ParseTimeOpts = false;
|
||||
}
|
||||
|
||||
initialize_hhbbc_options();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -542,12 +540,6 @@ int process(const CompilerOptions &po) {
|
||||
|
||||
bool isPickledPHP = (po.target == "php" && po.format == "pickled");
|
||||
if (!isPickledPHP) {
|
||||
bool wp = Option::WholeProgram;
|
||||
Option::WholeProgram = false;
|
||||
BuiltinSymbols::s_systemAr = ar;
|
||||
hphp_process_init();
|
||||
BuiltinSymbols::s_systemAr.reset();
|
||||
Option::WholeProgram = wp;
|
||||
if (po.target == "hhbc" && !Option::WholeProgram) {
|
||||
// We're trying to produce the same bytecode as runtime parsing.
|
||||
// There's nothing to do.
|
||||
@@ -555,7 +547,9 @@ int process(const CompilerOptions &po) {
|
||||
if (!BuiltinSymbols::Load(ar)) {
|
||||
return false;
|
||||
}
|
||||
ar->loadBuiltins();
|
||||
}
|
||||
hphp_process_init();
|
||||
}
|
||||
|
||||
{
|
||||
@@ -807,7 +801,6 @@ void hhbcTargetInit(const CompilerOptions &po, AnalysisResultPtr ar) {
|
||||
if (po.format.find("exe") != string::npos) {
|
||||
RuntimeOption::RepoCentralPath += ".hhbc";
|
||||
}
|
||||
unlink(RuntimeOption::RepoCentralPath.c_str());
|
||||
RuntimeOption::RepoLocalMode = "--";
|
||||
RuntimeOption::RepoDebugInfo = Option::RepoDebugInfo;
|
||||
RuntimeOption::RepoJournal = "memory";
|
||||
@@ -923,8 +916,6 @@ int runTarget(const CompilerOptions &po) {
|
||||
|
||||
cmd += buf;
|
||||
cmd += " -vRepo.Authoritative=true";
|
||||
if (getenv("HPHP_DUMP_BYTECODE")) cmd += " -vEval.DumpBytecode=1";
|
||||
if (getenv("HPHP_INTERP")) cmd += " -vEval.Jit=0";
|
||||
cmd += " -vRepo.Local.Mode=r- -vRepo.Local.Path=";
|
||||
}
|
||||
cmd += po.outputDir + '/' + po.program;
|
||||
|
||||
@@ -469,23 +469,9 @@ void Construct::parseTimeFatal(Compiler::ErrorType err, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
string msg;
|
||||
string_vsnprintf(msg, fmt, ap);
|
||||
Util::string_vsnprintf(msg, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (err != Compiler::NoError) Compiler::Error(err, shared_from_this());
|
||||
throw ParseTimeFatalException(m_loc->file, m_loc->line0, "%s", msg.c_str());
|
||||
}
|
||||
|
||||
void Construct::analysisTimeFatal(Compiler::ErrorType err,
|
||||
const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
string msg;
|
||||
string_vsnprintf(msg, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
assert(err != Compiler::NoError);
|
||||
Compiler::Error(err, shared_from_this());
|
||||
throw AnalysisTimeFatalException(m_loc->file, m_loc->line0,
|
||||
"%s [analysis]", msg.c_str());
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef incl_HPHP_CONSTRUCT_H_
|
||||
#define incl_HPHP_CONSTRUCT_H_
|
||||
|
||||
#include "hphp/compiler/json.h"
|
||||
#include "hphp/util/json.h"
|
||||
#include "hphp/compiler/code_generator.h"
|
||||
#include "hphp/compiler/analysis/code_error.h"
|
||||
#include "hphp/compiler/analysis/block_scope.h"
|
||||
@@ -180,8 +180,6 @@ public:
|
||||
void resetScope(BlockScopeRawPtr scope, bool resetOrigScope=false);
|
||||
void parseTimeFatal(Compiler::ErrorType error, const char *fmt, ...)
|
||||
ATTRIBUTE_PRINTF(3,4);
|
||||
void analysisTimeFatal(Compiler::ErrorType error, const char *fmt, ...)
|
||||
ATTRIBUTE_PRINTF(3,4);
|
||||
virtual int getLocalEffects() const { return UnknownEffect;}
|
||||
int getChildrenEffects() const;
|
||||
int getContainedEffects() const;
|
||||
|
||||
@@ -399,7 +399,7 @@ void ArrayElementExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("SimpleVariableExpression", 2);
|
||||
cg.printPropertyHeader("name");
|
||||
cg.printValue(m_globalName);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
} else if (m_offset) {
|
||||
@@ -410,16 +410,16 @@ void ArrayElementExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printExpression(m_offset, false);
|
||||
cg.printPropertyHeader("operation");
|
||||
cg.printValue(PHP_ARRAY_ELEMENT);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
} else {
|
||||
cg.printObjectHeader("UnaryOpExpression", 3);
|
||||
cg.printObjectHeader("UnaryOpExpression", 4);
|
||||
cg.printPropertyHeader("expression");
|
||||
m_variable->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("operation");
|
||||
cg.printValue(PHP_ARRAY_APPEND_POINT_OP);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ void ArrayPairExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printExpression(m_value, m_ref);
|
||||
cg.printPropertyHeader("operation");
|
||||
cg.printValue(PHP_ARRAY_PAIR);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
} else {
|
||||
|
||||
@@ -317,7 +317,7 @@ void AssignmentExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printExpression(m_value, m_ref);
|
||||
cg.printPropertyHeader("operation");
|
||||
cg.printValue(PHP_ASSIGNMENT);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -86,12 +86,12 @@ TypePtr AwaitExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AwaitExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("UnaryOpExpression", 3);
|
||||
cg.printObjectHeader("UnaryOpExpression", 2);
|
||||
cg.printPropertyHeader("expression");
|
||||
m_exp->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("operation");
|
||||
cg.printValue(PHP_AWAIT_OP);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ BinaryOpExpression::BinaryOpExpression
|
||||
break;
|
||||
case T_COLLECTION: {
|
||||
std::string s = m_exp1->getLiteralString();
|
||||
Collection::Type cType = Collection::InvalidType;
|
||||
int cType = 0;
|
||||
if (strcasecmp(s.c_str(), "vector") == 0) {
|
||||
cType = Collection::VectorType;
|
||||
} else if (strcasecmp(s.c_str(), "map") == 0) {
|
||||
@@ -78,12 +78,6 @@ BinaryOpExpression::BinaryOpExpression
|
||||
cType = Collection::SetType;
|
||||
} else if (strcasecmp(s.c_str(), "pair") == 0) {
|
||||
cType = Collection::PairType;
|
||||
} else if (strcasecmp(s.c_str(), "frozenvector") == 0) {
|
||||
cType = Collection::FrozenVectorType;
|
||||
} else if (strcasecmp(s.c_str(), "frozenmap") == 0) {
|
||||
cType = Collection::FrozenMapType;
|
||||
} else if (strcasecmp(s.c_str(), "frozenset") == 0) {
|
||||
cType = Collection::FrozenSetType;
|
||||
}
|
||||
ExpressionListPtr el = static_pointer_cast<ExpressionList>(m_exp2);
|
||||
el->setCollectionType(cType);
|
||||
@@ -484,9 +478,6 @@ ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
|
||||
ExpressionPtr aExp = m_exp1;
|
||||
ExpressionPtr bExp = binOpExp->m_exp1;
|
||||
ExpressionPtr cExp = binOpExp->m_exp2;
|
||||
if (aExp->isArray() || bExp->isArray() || cExp->isArray()) {
|
||||
break;
|
||||
}
|
||||
m_exp1 = binOpExp = Clone(binOpExp);
|
||||
m_exp2 = cExp;
|
||||
binOpExp->m_exp1 = aExp;
|
||||
@@ -547,9 +538,6 @@ ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
|
||||
*result.asCell() = cellBitXor(*v1.asCell(), *v2.asCell());
|
||||
break;
|
||||
case '.':
|
||||
if (v1.isArray() || v2.isArray()) {
|
||||
return ExpressionPtr();
|
||||
}
|
||||
result = concat(v1.toString(), v2.toString());
|
||||
break;
|
||||
case T_IS_IDENTICAL:
|
||||
@@ -816,7 +804,7 @@ TypePtr BinaryOpExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
case T_COLLECTION:
|
||||
et1 = Type::Any;
|
||||
et2 = Type::Any;
|
||||
rt = Type::CreateObjectType(m_exp1->getLiteralString());
|
||||
rt = Type::Object;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
@@ -934,7 +922,7 @@ void BinaryOpExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
m_exp1->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("arguments");
|
||||
cg.printExpressionVector(static_pointer_cast<ExpressionList>(m_exp2));
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
return;
|
||||
@@ -990,7 +978,7 @@ void BinaryOpExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
}
|
||||
|
||||
cg.printValue(op);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
@@ -1075,3 +1063,4 @@ bool BinaryOpExpression::isOpEqual() {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -224,12 +224,12 @@ bool ClassConstantExpression::canonCompare(ExpressionPtr e) const {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ClassConstantExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("ClassPropertyExpression", 3);
|
||||
cg.printObjectHeader("ClassPropertyExpression", 2);
|
||||
cg.printPropertyHeader("className");
|
||||
StaticClassName::outputCodeModel(cg);
|
||||
cg.printPropertyHeader("propertyName");
|
||||
cg.printValue(m_varName);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ public:
|
||||
bool isValid() const { return m_valid; }
|
||||
bool isDynamic() const;
|
||||
bool hasClass() const { return m_defScope != 0; }
|
||||
bool isColonColonClass() const { return m_varName == "class"; }
|
||||
private:
|
||||
std::string m_varName;
|
||||
BlockScope *m_defScope;
|
||||
|
||||
@@ -13,11 +13,8 @@
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/compiler/expression/closure_expression.h"
|
||||
|
||||
#include <boost/make_shared.hpp>
|
||||
#include "folly/ScopeGuard.h"
|
||||
|
||||
#include "hphp/compiler/expression/parameter_expression.h"
|
||||
#include "hphp/compiler/expression/expression_list.h"
|
||||
#include "hphp/compiler/expression/simple_variable.h"
|
||||
@@ -27,79 +24,68 @@
|
||||
#include "hphp/compiler/analysis/function_scope.h"
|
||||
#include "hphp/compiler/analysis/file_scope.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
using namespace HPHP;
|
||||
|
||||
TypePtr ClosureExpression::s_ClosureType =
|
||||
Type::CreateObjectType("closure"); // needs lower case
|
||||
|
||||
ClosureExpression::ClosureExpression(
|
||||
EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ClosureType type,
|
||||
FunctionStatementPtr func,
|
||||
ExpressionListPtr vars)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClosureExpression))
|
||||
, m_type(type)
|
||||
, m_func(func)
|
||||
, m_captureState(m_type == ClosureType::Short ? CaptureState::Unknown
|
||||
: CaptureState::Known)
|
||||
{
|
||||
switch (m_type) {
|
||||
case ClosureType::Short:
|
||||
break;
|
||||
case ClosureType::Long:
|
||||
if (vars) initializeFromUseList(vars);
|
||||
break;
|
||||
}
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// constructors/destructors
|
||||
|
||||
void ClosureExpression::initializeFromUseList(ExpressionListPtr vars) {
|
||||
m_vars = ExpressionListPtr(
|
||||
new ExpressionList(vars->getScope(), vars->getLocation()));
|
||||
ClosureExpression::ClosureExpression
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func,
|
||||
ExpressionListPtr vars)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClosureExpression)),
|
||||
m_func(func) {
|
||||
|
||||
// Because PHP is insane you can have a use variable with the same
|
||||
// name as a param name.
|
||||
// In that case, params win (which is different than zend but much easier)
|
||||
auto seenBefore = collectParamNames();
|
||||
if (vars) {
|
||||
m_vars = ExpressionListPtr
|
||||
(new ExpressionList(vars->getScope(), vars->getLocation()));
|
||||
// push the vars in reverse order, not retaining duplicates
|
||||
std::set<string> seenBefore;
|
||||
|
||||
for (int i = vars->getCount() - 1; i >= 0; i--) {
|
||||
ParameterExpressionPtr param(
|
||||
dynamic_pointer_cast<ParameterExpression>((*vars)[i]));
|
||||
assert(param);
|
||||
if (param->getName() == "this") {
|
||||
// "this" is automatically included.
|
||||
// Once we get rid of all the callsites, make this an error
|
||||
continue;
|
||||
// Because PHP is insane you can have a use variable with the same
|
||||
// name as a param name.
|
||||
// In that case, params win (which is different than zend but much easier)
|
||||
ExpressionListPtr bodyParams = m_func->getParams();
|
||||
if (bodyParams) {
|
||||
int nParams = bodyParams->getCount();
|
||||
for (int i = 0; i < nParams; i++) {
|
||||
ParameterExpressionPtr par(
|
||||
static_pointer_cast<ParameterExpression>((*bodyParams)[i]));
|
||||
seenBefore.insert(par->getName());
|
||||
}
|
||||
}
|
||||
if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) {
|
||||
seenBefore.insert(param->getName().c_str());
|
||||
m_vars->insertElement(param);
|
||||
|
||||
for (int i = vars->getCount() - 1; i >= 0; i--) {
|
||||
ParameterExpressionPtr param(
|
||||
dynamic_pointer_cast<ParameterExpression>((*vars)[i]));
|
||||
assert(param);
|
||||
if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) {
|
||||
seenBefore.insert(param->getName().c_str());
|
||||
m_vars->insertElement(param);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_vars) {
|
||||
m_values = ExpressionListPtr
|
||||
(new ExpressionList(m_vars->getScope(), m_vars->getLocation()));
|
||||
for (int i = 0; i < m_vars->getCount(); i++) {
|
||||
ParameterExpressionPtr param =
|
||||
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
|
||||
const string &name = param->getName();
|
||||
|
||||
SimpleVariablePtr var(new SimpleVariable(param->getScope(),
|
||||
param->getLocation(),
|
||||
name));
|
||||
if (param->isRef()) {
|
||||
var->setContext(RefValue);
|
||||
}
|
||||
m_values->addElement(var);
|
||||
}
|
||||
assert(m_vars->getCount() == m_values->getCount());
|
||||
}
|
||||
}
|
||||
|
||||
initializeValuesFromVars();
|
||||
}
|
||||
|
||||
void ClosureExpression::initializeValuesFromVars() {
|
||||
if (!m_vars) return;
|
||||
|
||||
m_values = ExpressionListPtr
|
||||
(new ExpressionList(m_vars->getScope(), m_vars->getLocation()));
|
||||
for (int i = 0; i < m_vars->getCount(); i++) {
|
||||
ParameterExpressionPtr param =
|
||||
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
|
||||
const string &name = param->getName();
|
||||
|
||||
SimpleVariablePtr var(new SimpleVariable(param->getScope(),
|
||||
param->getLocation(),
|
||||
name));
|
||||
if (param->isRef()) {
|
||||
var->setContext(RefValue);
|
||||
}
|
||||
m_values->addElement(var);
|
||||
}
|
||||
assert(m_vars->getCount() == m_values->getCount());
|
||||
}
|
||||
|
||||
ExpressionPtr ClosureExpression::clone() {
|
||||
@@ -146,65 +132,62 @@ void ClosureExpression::setNthKid(int n, ConstructPtr cp) {
|
||||
|
||||
void ClosureExpression::analyzeProgram(AnalysisResultPtr ar) {
|
||||
m_func->analyzeProgram(ar);
|
||||
if (m_vars) {
|
||||
m_values->analyzeProgram(ar);
|
||||
|
||||
if (m_vars) analyzeVars(ar);
|
||||
if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
|
||||
getFunctionScope()->addUse(m_func->getFunctionScope(),
|
||||
BlockScope::UseKindClosure);
|
||||
m_func->getFunctionScope()->setClosureVars(m_vars);
|
||||
|
||||
FunctionScopeRawPtr container =
|
||||
// closure function's variable table (not containing function's)
|
||||
VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
|
||||
VariableTablePtr containing = getFunctionScope()->getVariables();
|
||||
for (int i = 0; i < m_vars->getCount(); i++) {
|
||||
ParameterExpressionPtr param =
|
||||
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
|
||||
const string &name = param->getName();
|
||||
{
|
||||
Symbol *containingSym = containing->addDeclaredSymbol(name, param);
|
||||
containingSym->setPassClosureVar();
|
||||
|
||||
Symbol *sym = variables->addDeclaredSymbol(name, param);
|
||||
sym->setClosureVar();
|
||||
sym->setDeclaration(ConstructPtr());
|
||||
if (param->isRef()) {
|
||||
sym->setRefClosureVar();
|
||||
sym->setUsed();
|
||||
} else {
|
||||
sym->clearRefClosureVar();
|
||||
sym->clearUsed();
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
|
||||
// closure function's variable table (not containing function's)
|
||||
VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
|
||||
for (int i = 0; i < m_vars->getCount(); i++) {
|
||||
ParameterExpressionPtr param =
|
||||
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
|
||||
const string &name = param->getName();
|
||||
|
||||
// so we can assign values to them, instead of seeing CVarRef
|
||||
Symbol *sym = variables->getSymbol(name);
|
||||
if (sym && sym->isParameter()) {
|
||||
sym->setLvalParam();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FunctionScopeRawPtr container =
|
||||
getFunctionScope()->getContainingNonClosureFunction();
|
||||
if (container && container->isStatic()) {
|
||||
m_func->getModifiers()->add(T_STATIC);
|
||||
}
|
||||
}
|
||||
|
||||
void ClosureExpression::analyzeVars(AnalysisResultPtr ar) {
|
||||
m_values->analyzeProgram(ar);
|
||||
|
||||
if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
|
||||
getFunctionScope()->addUse(m_func->getFunctionScope(),
|
||||
BlockScope::UseKindClosure);
|
||||
m_func->getFunctionScope()->setClosureVars(m_vars);
|
||||
|
||||
// closure function's variable table (not containing function's)
|
||||
VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
|
||||
VariableTablePtr containing = getFunctionScope()->getVariables();
|
||||
for (int i = 0; i < m_vars->getCount(); i++) {
|
||||
ParameterExpressionPtr param =
|
||||
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
|
||||
const string &name = param->getName();
|
||||
{
|
||||
Symbol *containingSym = containing->addDeclaredSymbol(name, param);
|
||||
containingSym->setPassClosureVar();
|
||||
|
||||
Symbol *sym = variables->addDeclaredSymbol(name, param);
|
||||
sym->setClosureVar();
|
||||
sym->setDeclaration(ConstructPtr());
|
||||
if (param->isRef()) {
|
||||
sym->setRefClosureVar();
|
||||
sym->setUsed();
|
||||
} else {
|
||||
sym->clearRefClosureVar();
|
||||
sym->clearUsed();
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
|
||||
// closure function's variable table (not containing function's)
|
||||
VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
|
||||
for (int i = 0; i < m_vars->getCount(); i++) {
|
||||
ParameterExpressionPtr param =
|
||||
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
|
||||
const string &name = param->getName();
|
||||
|
||||
// so we can assign values to them, instead of seeing CVarRef
|
||||
Symbol *sym = variables->getSymbol(name);
|
||||
if (sym && sym->isParameter()) {
|
||||
sym->setLvalParam();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TypePtr ClosureExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
@@ -268,72 +251,6 @@ TypePtr ClosureExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
return s_ClosureType;
|
||||
}
|
||||
|
||||
void ClosureExpression::setCaptureList(
|
||||
AnalysisResultPtr ar,
|
||||
const std::set<std::string>& captureNames) {
|
||||
assert(m_captureState == CaptureState::Unknown);
|
||||
m_captureState = CaptureState::Known;
|
||||
|
||||
bool usedThis = false;
|
||||
SCOPE_EXIT {
|
||||
/*
|
||||
* TODO: closures in a non-class scope should be neither static
|
||||
* nor non-static, but right now we don't really have this idea.
|
||||
*
|
||||
* This would allow not having to check for a $this or late bound
|
||||
* class in the closure object or on the ActRec when returning
|
||||
* from those closures.
|
||||
*
|
||||
* (We could also mark closures that don't use late static binding
|
||||
* with this flag to avoid checks on closures in member functions
|
||||
* when they use neither $this nor static::)
|
||||
*/
|
||||
if (!usedThis) m_func->getModifiers()->add(T_STATIC);
|
||||
};
|
||||
|
||||
if (captureNames.empty()) return;
|
||||
|
||||
m_vars = ExpressionListPtr(
|
||||
new ExpressionList(getOriginalScope(), getLocation()));
|
||||
|
||||
for (auto const& name : captureNames) {
|
||||
if (name == "this") {
|
||||
usedThis = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto expr = ParameterExpressionPtr(new ParameterExpression(
|
||||
BlockScopePtr(getOriginalScope()),
|
||||
getLocation(),
|
||||
TypeAnnotationPtr(),
|
||||
true /* hhType */,
|
||||
name,
|
||||
false /* ref */,
|
||||
0 /* token modifier thing */,
|
||||
ExpressionPtr(),
|
||||
ExpressionPtr()
|
||||
));
|
||||
m_vars->insertElement(expr);
|
||||
}
|
||||
|
||||
initializeValuesFromVars();
|
||||
analyzeVars(ar);
|
||||
}
|
||||
|
||||
std::set<std::string> ClosureExpression::collectParamNames() const {
|
||||
std::set<std::string> ret;
|
||||
|
||||
auto bodyParams = m_func->getParams();
|
||||
if (!bodyParams) return ret;
|
||||
|
||||
int nParams = bodyParams->getCount();
|
||||
for (int i = 0; i < nParams; i++) {
|
||||
auto par = static_pointer_cast<ParameterExpression>((*bodyParams)[i]);
|
||||
ret.insert(par->getName());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ClosureExpression::hasStaticLocals() {
|
||||
ConstructPtr cons(m_func);
|
||||
return hasStaticLocalsImpl(cons);
|
||||
@@ -365,15 +282,12 @@ bool ClosureExpression::hasStaticLocalsImpl(ConstructPtr root) {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ClosureExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
auto numProps = m_vars != nullptr && m_vars->getCount() > 0 ? 3 : 2;
|
||||
cg.printObjectHeader("ClosureExpression", numProps);
|
||||
cg.printPropertyHeader("ffunction");
|
||||
cg.printObjectHeader("ClosureExpression", 3);
|
||||
cg.printPropertyHeader("function");
|
||||
m_func->outputCodeModel(cg);
|
||||
if (m_vars != nullptr && m_vars->getCount() > 0) {
|
||||
cg.printPropertyHeader("capturedVariables");
|
||||
cg.printExpressionVector(m_vars);
|
||||
}
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("capturedVariables");
|
||||
cg.printExpressionVector(m_vars);
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
@@ -390,5 +304,3 @@ void ClosureExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
}
|
||||
m_func->outputPHPBody(cg, ar);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#define incl_HPHP_CLOSURE_EXPRESSION_H_
|
||||
|
||||
#include "hphp/compiler/expression/expression.h"
|
||||
#include "hphp/parser/parser.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -30,20 +29,10 @@ DECLARE_BOOST_TYPES(ExpressionList);
|
||||
class ClosureExpression : public Expression {
|
||||
public:
|
||||
ClosureExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ClosureType type,
|
||||
FunctionStatementPtr func,
|
||||
ExpressionListPtr vars);
|
||||
FunctionStatementPtr func, ExpressionListPtr vars);
|
||||
|
||||
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
|
||||
// Flag for whether we have already determined the capture list for
|
||||
// this lambda.
|
||||
enum class CaptureState {
|
||||
Unknown,
|
||||
Known,
|
||||
};
|
||||
CaptureState captureState() const { return m_captureState; }
|
||||
|
||||
virtual ConstructPtr getNthKid(int n) const;
|
||||
virtual void setNthKid(int n, ConstructPtr cp);
|
||||
virtual int getKidCount() const;
|
||||
@@ -54,35 +43,17 @@ public:
|
||||
StringData* getClosureClassName() { return m_closureClassName; }
|
||||
void setClosureClassName(StringData* value) { m_closureClassName = value; }
|
||||
bool hasStaticLocals();
|
||||
ClosureType type() const { return m_type; }
|
||||
std::set<std::string> collectParamNames() const;
|
||||
|
||||
/*
|
||||
* Initialize the capture list for a closure that uses automatic
|
||||
* captures.
|
||||
*
|
||||
* Pre: captureState() == CaptureState::Unknown.
|
||||
*/
|
||||
void setCaptureList(AnalysisResultPtr ar,
|
||||
const std::set<std::string>&);
|
||||
|
||||
private:
|
||||
static TypePtr s_ClosureType;
|
||||
|
||||
private:
|
||||
void initializeFromUseList(ExpressionListPtr vars);
|
||||
void initializeValuesFromVars();
|
||||
void analyzeVars(AnalysisResultPtr);
|
||||
bool hasStaticLocalsImpl(ConstructPtr root);
|
||||
|
||||
private:
|
||||
ClosureType m_type;
|
||||
FunctionStatementPtr m_func;
|
||||
ExpressionListPtr m_vars;
|
||||
ExpressionListPtr m_values;
|
||||
StringData* m_closureClassName;
|
||||
std::set<std::string> m_unboundNames;
|
||||
CaptureState m_captureState;
|
||||
|
||||
static TypePtr s_ClosureType;
|
||||
|
||||
bool hasStaticLocalsImpl(ConstructPtr root);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -277,9 +277,9 @@ TypePtr ConstantExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
|
||||
void ConstantExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("SimpleVariableExpression", 2);
|
||||
cg.printPropertyHeader("variableName");
|
||||
cg.printValue(m_origName);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("name");
|
||||
cg.printValue(getNonNSOriginalName());
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ void DynamicFunctionCall::outputCodeModel(CodeGenerator &cg) {
|
||||
m_nameExp->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("arguments");
|
||||
cg.printExpressionVector(m_params);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(m_nameExp->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ void DynamicVariable::outputCodeModel(CodeGenerator &cg) {
|
||||
m_exp->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("operation");
|
||||
cg.printValue(PHP_DYNAMIC_VARIABLE_OP) ;
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -122,12 +122,14 @@ bool EncapsListExpression::canonCompare(ExpressionPtr e) const {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EncapsListExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("EncapsListExpression", 3);
|
||||
cg.printObjectHeader("EncapsListExpression", 2);
|
||||
cg.printPropertyHeader("delimiter");
|
||||
cg.printValue(m_type);
|
||||
cg.printPropertyHeader("expressions");
|
||||
cg.printExpressionVector(m_exps);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
if (m_exps) {
|
||||
cg.printPropertyHeader("expressions");
|
||||
cg.printExpressionVector(m_exps);
|
||||
}
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -17,12 +17,9 @@
|
||||
#ifndef incl_HPHP_EXPRESSION_H_
|
||||
#define incl_HPHP_EXPRESSION_H_
|
||||
|
||||
#include "hphp/util/deprecated/declare-boost-types.h"
|
||||
#include "hphp/util/hash-map-typedefs.h"
|
||||
#include "hphp/compiler/construct.h"
|
||||
#include "hphp/compiler/analysis/type.h"
|
||||
#include "hphp/compiler/analysis/analysis_result.h"
|
||||
#include "hphp/util/hash-map-typedefs.h"
|
||||
|
||||
#define EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS \
|
||||
BlockScopePtr scope, LocationPtr loc, Expression::KindOf kindOf
|
||||
@@ -51,7 +48,7 @@ namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DECLARE_BOOST_TYPES(Statement);
|
||||
DECLARE_EXTENDED_BOOST_TYPES(Expression);
|
||||
DECLARE_BOOST_TYPES(Expression);
|
||||
class Variant;
|
||||
|
||||
#define DECLARE_EXPRESSION_TYPES(x) \
|
||||
@@ -81,17 +78,7 @@ class Variant;
|
||||
x(ClosureExpression, None), \
|
||||
x(YieldExpression, None), \
|
||||
x(AwaitExpression, None), \
|
||||
x(UserAttribute, None), \
|
||||
x(QueryExpression, None), \
|
||||
x(FromClause, None), \
|
||||
x(LetClause, None), \
|
||||
x(WhereClause, None), \
|
||||
x(SelectClause, None), \
|
||||
x(IntoClause, None), \
|
||||
x(JoinClause, None), \
|
||||
x(GroupClause, None), \
|
||||
x(OrderbyClause, None), \
|
||||
x(Ordering, None)
|
||||
x(UserAttribute, None)
|
||||
|
||||
class Expression : public Construct {
|
||||
public:
|
||||
|
||||
@@ -239,11 +239,9 @@ void ExpressionList::stripConcat() {
|
||||
BinaryOpExpressionPtr b
|
||||
(static_pointer_cast<BinaryOpExpression>(e));
|
||||
if (b->getOp() == '.') {
|
||||
if(!b->getExp1()->isArray() && !b->getExp2()->isArray()) {
|
||||
e = b->getExp1();
|
||||
el.insertElement(b->getExp2(), i + 1);
|
||||
continue;
|
||||
}
|
||||
e = b->getExp1();
|
||||
el.insertElement(b->getExp2(), i + 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
@@ -274,7 +272,7 @@ void ExpressionList::markParams(bool noRefWrapper) {
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionList::setCollectionType(Collection::Type cType) {
|
||||
void ExpressionList::setCollectionType(int cType) {
|
||||
m_arrayElements = true;
|
||||
m_collectionType = cType;
|
||||
}
|
||||
@@ -471,11 +469,7 @@ bool ExpressionList::canonCompare(ExpressionPtr e) const {
|
||||
void ExpressionList::outputCodeModel(CodeGenerator &cg) {
|
||||
for (unsigned int i = 0; i < m_exps.size(); i++) {
|
||||
ExpressionPtr exp = m_exps[i];
|
||||
if (exp) {
|
||||
cg.printExpression(exp, exp->hasContext(RefParameter));
|
||||
} else {
|
||||
cg.printNull();
|
||||
}
|
||||
cg.printExpression(exp, exp?exp->hasContext(RefParameter):false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,3 +508,4 @@ unsigned int ExpressionList::checkLitstrKeys() const {
|
||||
}
|
||||
return keys.size();
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
void markParam(int p, bool noRefWrapper);
|
||||
void markParams(bool noRefWrapper);
|
||||
|
||||
void setCollectionType(Collection::Type cType);
|
||||
void setCollectionType(int cType);
|
||||
|
||||
virtual bool canonCompare(ExpressionPtr e) const;
|
||||
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/compiler/expression/group_clause.h"
|
||||
#include "hphp/compiler/analysis/code_error.h"
|
||||
#include "hphp/runtime/base/complex-types.h"
|
||||
|
||||
using namespace HPHP;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// constructors/destructors
|
||||
|
||||
GroupClause::GroupClause
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr coll, ExpressionPtr key)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(GroupClause)),
|
||||
m_coll(coll), m_key(key) {
|
||||
}
|
||||
|
||||
ExpressionPtr GroupClause::clone() {
|
||||
GroupClausePtr exp(new GroupClause(*this));
|
||||
Expression::deepCopy(exp);
|
||||
exp->m_coll = Clone(m_coll);
|
||||
exp->m_key = Clone(m_key);
|
||||
return exp;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// parser functions
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// static analysis functions
|
||||
|
||||
void GroupClause::analyzeProgram(AnalysisResultPtr ar) {
|
||||
m_coll->analyzeProgram(ar);
|
||||
m_key->analyzeProgram(ar);
|
||||
}
|
||||
|
||||
ConstructPtr GroupClause::getNthKid(int n) const {
|
||||
switch (n) {
|
||||
case 0:
|
||||
return m_coll;
|
||||
case 1:
|
||||
return m_key;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return ConstructPtr();
|
||||
}
|
||||
|
||||
int GroupClause::getKidCount() const {
|
||||
return 2;
|
||||
}
|
||||
|
||||
void GroupClause::setNthKid(int n, ConstructPtr cp) {
|
||||
switch (n) {
|
||||
case 0:
|
||||
m_coll = dynamic_pointer_cast<Expression>(cp);
|
||||
break;
|
||||
case 1:
|
||||
m_key = dynamic_pointer_cast<Expression>(cp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TypePtr GroupClause::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
bool coerce) {
|
||||
m_coll->inferAndCheck(ar, Type::Some, false);
|
||||
m_key->inferAndCheck(ar, Type::Some, false);
|
||||
return Type::Object;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GroupClause::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("GroupClause", 3);
|
||||
cg.printPropertyHeader("collection");
|
||||
m_coll->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("key");
|
||||
m_key->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// code generation functions
|
||||
|
||||
void GroupClause::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
cg_printf("group ");
|
||||
m_coll->outputPHP(cg, ar);
|
||||
cg_printf(" by ");
|
||||
m_key->outputPHP(cg, ar);
|
||||
}
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/compiler/expression/join_clause.h"
|
||||
#include "hphp/compiler/analysis/code_error.h"
|
||||
#include "hphp/runtime/base/complex-types.h"
|
||||
|
||||
using namespace HPHP;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// constructors/destructors
|
||||
|
||||
JoinClause::JoinClause
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const std::string &var, ExpressionPtr coll, ExpressionPtr left,
|
||||
ExpressionPtr right, const std::string &group)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(JoinClause)),
|
||||
m_var(var), m_coll(coll), m_left(left),
|
||||
m_right(right), m_group(group) {
|
||||
}
|
||||
|
||||
ExpressionPtr JoinClause::clone() {
|
||||
JoinClausePtr exp(new JoinClause(*this));
|
||||
Expression::deepCopy(exp);
|
||||
exp->m_var = m_var;
|
||||
exp->m_coll = Clone(m_coll);
|
||||
exp->m_left = Clone(m_left);
|
||||
exp->m_right = Clone(m_right);
|
||||
exp->m_group = m_group;
|
||||
return exp;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// parser functions
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// static analysis functions
|
||||
|
||||
void JoinClause::analyzeProgram(AnalysisResultPtr ar) {
|
||||
m_coll->analyzeProgram(ar);
|
||||
m_left->analyzeProgram(ar);
|
||||
m_right->analyzeProgram(ar);
|
||||
}
|
||||
|
||||
ConstructPtr JoinClause::getNthKid(int n) const {
|
||||
switch (n) {
|
||||
case 0:
|
||||
return m_coll;
|
||||
case 1:
|
||||
return m_left;
|
||||
case 2:
|
||||
return m_right;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return ConstructPtr();
|
||||
}
|
||||
|
||||
int JoinClause::getKidCount() const {
|
||||
return 3;
|
||||
}
|
||||
|
||||
void JoinClause::setNthKid(int n, ConstructPtr cp) {
|
||||
switch (n) {
|
||||
case 0:
|
||||
m_coll = dynamic_pointer_cast<Expression>(cp);
|
||||
break;
|
||||
case 1:
|
||||
m_left = dynamic_pointer_cast<Expression>(cp);
|
||||
break;
|
||||
case 2:
|
||||
m_right = dynamic_pointer_cast<Expression>(cp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TypePtr JoinClause::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
bool coerce) {
|
||||
m_coll->inferAndCheck(ar, Type::Some, false);
|
||||
m_left->inferAndCheck(ar, Type::Some, false);
|
||||
m_right->inferAndCheck(ar, Type::Some, false);
|
||||
return Type::Object;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void JoinClause::outputCodeModel(CodeGenerator &cg) {
|
||||
auto numProps = 5;
|
||||
if (!m_group.empty()) numProps++;
|
||||
cg.printObjectHeader("JoinClause", numProps);
|
||||
cg.printPropertyHeader("variable");
|
||||
cg.printValue(m_var);
|
||||
cg.printPropertyHeader("collection");
|
||||
m_coll->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("left");
|
||||
m_left->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("right");
|
||||
m_right->outputCodeModel(cg);
|
||||
if (!m_group.empty()) {
|
||||
cg.printPropertyHeader("group");
|
||||
cg.printValue(m_group);
|
||||
}
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// code generation functions
|
||||
|
||||
void JoinClause::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
cg_printf("join %s in ", m_var.c_str());
|
||||
m_coll->outputPHP(cg, ar);
|
||||
cg_printf(" on ");
|
||||
m_left->outputPHP(cg, ar);
|
||||
cg_printf(" equals ");
|
||||
m_right->outputPHP(cg, ar);
|
||||
if (!m_group.empty()) {
|
||||
cg_printf(" into %s", m_group.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef incl_HPHP_JOIN_CLAUSE_H_
|
||||
#define incl_HPHP_JOIN_CLAUSE_H_
|
||||
|
||||
#include "hphp/compiler/expression/expression.h"
|
||||
#include "hphp/compiler/expression/expression_list.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DECLARE_BOOST_TYPES(JoinClause);
|
||||
|
||||
class JoinClause : public Expression {
|
||||
public:
|
||||
JoinClause(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const std::string &var, ExpressionPtr coll, ExpressionPtr left,
|
||||
ExpressionPtr right, const std::string &group);
|
||||
|
||||
DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
|
||||
std::string getVar() const { return m_var; }
|
||||
ExpressionPtr getColl() { return m_coll; }
|
||||
ExpressionPtr getLeft() { return m_left; }
|
||||
ExpressionPtr getRight() { return m_right; }
|
||||
std::string getGroup() { return m_group; }
|
||||
private:
|
||||
std::string m_var;
|
||||
ExpressionPtr m_coll;
|
||||
ExpressionPtr m_left;
|
||||
ExpressionPtr m_right;
|
||||
std::string m_group;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
#endif // incl_HPHP_JOIN_CLAUSE_H_
|
||||
@@ -31,7 +31,7 @@ using namespace HPHP;
|
||||
// constructors/destructors
|
||||
|
||||
/*
|
||||
Determine whether the rhs behaves normally, or abnormally.
|
||||
Determine whether the rhs behaves normall, or abnormally.
|
||||
|
||||
1) If the expression is the silence operator, recurse on the inner expression.
|
||||
2) If the expression is a list assignment expression, recurse on the
|
||||
@@ -77,7 +77,6 @@ static ListAssignment::RHSKind GetRHSKind(ExpressionPtr rhs) {
|
||||
case Expression::KindOfIncludeExpression:
|
||||
case Expression::KindOfYieldExpression:
|
||||
case Expression::KindOfAwaitExpression:
|
||||
case Expression::KindOfQueryExpression:
|
||||
return ListAssignment::Regular;
|
||||
|
||||
case Expression::KindOfListAssignment:
|
||||
@@ -119,15 +118,6 @@ static ListAssignment::RHSKind GetRHSKind(ExpressionPtr rhs) {
|
||||
case Expression::KindOfParameterExpression:
|
||||
case Expression::KindOfModifierExpression:
|
||||
case Expression::KindOfUserAttribute:
|
||||
case Expression::KindOfFromClause:
|
||||
case Expression::KindOfLetClause:
|
||||
case Expression::KindOfWhereClause:
|
||||
case Expression::KindOfSelectClause:
|
||||
case Expression::KindOfIntoClause:
|
||||
case Expression::KindOfJoinClause:
|
||||
case Expression::KindOfGroupClause:
|
||||
case Expression::KindOfOrderbyClause:
|
||||
case Expression::KindOfOrdering:
|
||||
always_assert(false);
|
||||
|
||||
// non-arrays
|
||||
@@ -286,15 +276,12 @@ TypePtr ListAssignment::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ListAssignment::outputCodeModel(CodeGenerator &cg) {
|
||||
auto numProps = m_array != nullptr ? 3 : 2;
|
||||
cg.printObjectHeader("ListAssignmentExpression", numProps);
|
||||
cg.printObjectHeader("ListAssignmentExpression", 3);
|
||||
cg.printPropertyHeader("variables");
|
||||
cg.printExpressionVector(m_variables);
|
||||
if (m_array != nullptr) {
|
||||
cg.printPropertyHeader("expression");
|
||||
m_array->outputCodeModel(cg);
|
||||
}
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("expression");
|
||||
m_array->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -118,20 +118,6 @@ bool ModifierExpression::validForClosure() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* In the context of a trait alias rule, only method access and visibility
|
||||
* modifiers are allowed
|
||||
*/
|
||||
bool ModifierExpression::validForTraitAliasRule() const {
|
||||
for (auto const& mod: m_modifiers) {
|
||||
if (mod != T_PUBLIC && mod != T_PRIVATE && mod != T_PROTECTED
|
||||
&& mod != T_FINAL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// static analysis functions
|
||||
|
||||
@@ -148,7 +134,7 @@ TypePtr ModifierExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ModifierExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printf("V:9:\"HH\\Vector\":%d:{", (int)m_modifiers.size());
|
||||
cg.printf("V:6:\"Vector\":%d:{", (int)m_modifiers.size());
|
||||
for (unsigned int i = 0; i < m_modifiers.size(); i++) {
|
||||
cg.printObjectHeader("Modifier", 1);
|
||||
cg.printPropertyHeader("name");
|
||||
|
||||
@@ -56,7 +56,6 @@ public:
|
||||
|
||||
bool validForFunction() const;
|
||||
bool validForClosure() const;
|
||||
bool validForTraitAliasRule() const;
|
||||
|
||||
void setHasPrivacy(bool f) { m_hasPrivacy = f; }
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ void NewObjectExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printPropertyHeader("arguments");
|
||||
cg.printExpressionVector(m_params);
|
||||
}
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ TypePtr ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar,
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ObjectMethodExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("ObjectMethodCallExpression",
|
||||
cg.printObjectHeader("ObjectMethodCallExpression(",
|
||||
m_params == nullptr ? 3 : 4);
|
||||
cg.printPropertyHeader("object");
|
||||
m_object->outputCodeModel(cg);
|
||||
@@ -294,7 +294,7 @@ void ObjectMethodExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printPropertyHeader("arguments");
|
||||
cg.printExpressionVector(m_params);
|
||||
}
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ ObjectPropertyExpression::postOptimize(AnalysisResultConstPtr ar) {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ObjectPropertyExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("ObjectPropertyExpression", 3);
|
||||
cg.printObjectHeader("ObjectPropertyExpression(", 3);
|
||||
cg.printPropertyHeader("object");
|
||||
m_object->outputCodeModel(cg);
|
||||
if (m_property->is(Expression::KindOfScalarExpression)) {
|
||||
@@ -344,7 +344,7 @@ void ObjectPropertyExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printPropertyHeader("propertyExpression");
|
||||
}
|
||||
m_property->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/compiler/expression/ordering.h"
|
||||
#include "hphp/compiler/analysis/code_error.h"
|
||||
#include "hphp/runtime/base/complex-types.h"
|
||||
|
||||
using namespace HPHP;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// constructors/destructors
|
||||
|
||||
Ordering::Ordering
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr key, TokenID direction)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(Ordering)),
|
||||
m_key(key), m_direction(direction){
|
||||
}
|
||||
|
||||
ExpressionPtr Ordering::clone() {
|
||||
OrderingPtr exp(new Ordering(*this));
|
||||
Expression::deepCopy(exp);
|
||||
exp->m_key = Clone(m_key);
|
||||
exp->m_direction = m_direction;
|
||||
return exp;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// parser functions
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// static analysis functions
|
||||
|
||||
void Ordering::analyzeProgram(AnalysisResultPtr ar) {
|
||||
m_key->analyzeProgram(ar);
|
||||
}
|
||||
|
||||
ConstructPtr Ordering::getNthKid(int n) const {
|
||||
switch (n) {
|
||||
case 0:
|
||||
return m_key;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return ConstructPtr();
|
||||
}
|
||||
|
||||
int Ordering::getKidCount() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Ordering::setNthKid(int n, ConstructPtr cp) {
|
||||
switch (n) {
|
||||
case 0:
|
||||
m_key = dynamic_pointer_cast<Expression>(cp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TypePtr Ordering::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
bool coerce) {
|
||||
m_key->inferAndCheck(ar, Type::Some, false);
|
||||
return Type::Object;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Ordering::outputCodeModel(CodeGenerator &cg) {
|
||||
int direction;
|
||||
switch (m_direction) {
|
||||
case T_ASCENDING:
|
||||
direction = 1;
|
||||
break;
|
||||
case T_DESCENDING:
|
||||
direction = 2;
|
||||
break;
|
||||
default:
|
||||
direction = 3;
|
||||
break;
|
||||
}
|
||||
auto propCount = direction > 0 ? 3 : 2;
|
||||
cg.printObjectHeader("Ordering", propCount);
|
||||
cg.printPropertyHeader("key");
|
||||
m_key->outputCodeModel(cg);
|
||||
if (propCount == 3) {
|
||||
cg.printPropertyHeader("direction");
|
||||
cg.printValue(direction);
|
||||
}
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// code generation functions
|
||||
|
||||
void Ordering::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
m_key->outputPHP(cg, ar);
|
||||
switch (m_direction) {
|
||||
case T_ASCENDING:
|
||||
cg_printf(" ascending");
|
||||
break;
|
||||
case T_DESCENDING:
|
||||
cg_printf(" decending");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,14 +308,14 @@ void ParameterExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
if (m_modifier != 0) propCount++;
|
||||
if (m_ref) propCount++;
|
||||
if (m_defaultValue != nullptr) propCount++;
|
||||
cg.printObjectHeader("ParameterDeclaration", propCount);
|
||||
cg.printObjectHeader("ParameterDeclaration(", propCount);
|
||||
if (m_attributeList) {
|
||||
cg.printPropertyHeader("isPassedByReference");
|
||||
cg.printExpressionVector(m_attributeList);
|
||||
}
|
||||
if (m_modifier != 0) {
|
||||
cg.printPropertyHeader("modifiers");
|
||||
printf("V:9:\"HH\\Vector\":1:{");
|
||||
printf("V:6:\"Vector\":1:{");
|
||||
switch (m_modifier) {
|
||||
case T_PUBLIC: cg.printValue("public"); break;
|
||||
case T_PROTECTED: cg.printValue("protected"); break;
|
||||
@@ -334,7 +334,7 @@ void ParameterExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printPropertyHeader("expression");
|
||||
m_defaultValue->outputCodeModel(cg);
|
||||
}
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "hphp/compiler/expression/expression.h"
|
||||
#include "hphp/compiler/expression/constant_expression.h"
|
||||
#include "hphp/compiler/json.h"
|
||||
#include "hphp/util/json.h"
|
||||
#include "hphp/parser/scanner.h"
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
@@ -172,7 +172,7 @@ void QOpExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
m_condition->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("valueIfNull");
|
||||
} else {
|
||||
cg.printObjectHeader("ConditionalExpression", 4);
|
||||
cg.printObjectHeader("ConditionalExpression(", 4);
|
||||
cg.printPropertyHeader("condition");
|
||||
m_condition->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("valueIfTrue");
|
||||
@@ -180,7 +180,7 @@ void QOpExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printPropertyHeader("valueIfFalse");
|
||||
}
|
||||
m_expNo->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/compiler/expression/query_expression.h"
|
||||
#include "hphp/compiler/expression/simple_query_clause.h"
|
||||
#include "hphp/compiler/analysis/capture_extractor.h"
|
||||
#include "hphp/compiler/analysis/code_error.h"
|
||||
#include "hphp/runtime/base/complex-types.h"
|
||||
|
||||
using namespace HPHP;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// constructors/destructors
|
||||
|
||||
QueryOrderby::QueryOrderby(EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_BASE_PARAMETER_VALUES) {
|
||||
m_expressions = nullptr;
|
||||
}
|
||||
|
||||
ExpressionPtr QueryOrderby::clone() {
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QueryExpression::QueryExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr head, ExpressionPtr body)
|
||||
: QueryOrderby(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(QueryExpression)) {
|
||||
m_queryargs = ExpressionListPtr(
|
||||
new ExpressionList(getScope(), getLocation())
|
||||
);
|
||||
m_expressions = ExpressionListPtr(
|
||||
new ExpressionList(getScope(), getLocation())
|
||||
);
|
||||
m_expressions->addElement(head);
|
||||
|
||||
assert(body != nullptr && body->is(Expression::KindOfExpressionList));
|
||||
ExpressionListPtr el(static_pointer_cast<ExpressionList>(body));
|
||||
for (unsigned int i = 0; i < el->getCount(); i++) {
|
||||
if ((*el)[i]) m_expressions->addElement((*el)[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QueryExpression::QueryExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionListPtr clauses)
|
||||
: QueryOrderby(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(QueryExpression)) {
|
||||
m_queryargs = ExpressionListPtr(
|
||||
new ExpressionList(getScope(), getLocation())
|
||||
);
|
||||
m_expressions = clauses;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// parser functions
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// static analysis functions
|
||||
|
||||
ExpressionListPtr QueryExpression::getQueryArguments() {
|
||||
if (m_queryargs->getCount() == 0) serializeQueryExpression();
|
||||
return m_queryargs;
|
||||
}
|
||||
|
||||
StringData* QueryExpression::getQueryString() {
|
||||
if (m_querystr == nullptr) serializeQueryExpression();
|
||||
return m_querystr;
|
||||
}
|
||||
|
||||
void QueryExpression::serializeQueryExpression() {
|
||||
CaptureExtractor ce;
|
||||
auto qe = ce.rewrite(static_pointer_cast<Expression>(shared_from_this()));
|
||||
m_queryargs->clearElements();
|
||||
for (auto e : ce.getCapturedExpressions()) {
|
||||
m_queryargs->addElement(e);
|
||||
}
|
||||
assert(m_queryargs->getCount() > 0); //syntax requires an initial from clause
|
||||
|
||||
std::ostringstream serialized;
|
||||
CodeGenerator cg(&serialized, CodeGenerator::Output::CodeModel);
|
||||
cg.setAstClassPrefix("Code"); //TODO: create option for this
|
||||
qe->outputCodeModel(cg);
|
||||
std::string s(serialized.str().c_str(), serialized.str().length());
|
||||
m_querystr = makeStaticString(s);
|
||||
}
|
||||
|
||||
void QueryOrderby::analyzeProgram(AnalysisResultPtr ar) {
|
||||
for (unsigned int i = 0; i < m_expressions->getCount(); i++) {
|
||||
(*m_expressions)[i]->analyzeProgram(ar);
|
||||
}
|
||||
}
|
||||
|
||||
ConstructPtr QueryOrderby::getNthKid(int n) const {
|
||||
if (n < (int)m_expressions->getCount()) {
|
||||
return (*m_expressions)[n];
|
||||
}
|
||||
return ConstructPtr();
|
||||
}
|
||||
|
||||
int QueryOrderby::getKidCount() const {
|
||||
return m_expressions->getCount();
|
||||
}
|
||||
|
||||
void QueryOrderby::setNthKid(int n, ConstructPtr cp) {
|
||||
int m = m_expressions->getCount();
|
||||
if (n >= m) {
|
||||
assert(false);
|
||||
} else {
|
||||
(*m_expressions)[n] = dynamic_pointer_cast<Expression>(cp);
|
||||
}
|
||||
}
|
||||
|
||||
TypePtr QueryOrderby::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
bool coerce) {
|
||||
for (unsigned int i = 0; i < m_expressions->getCount(); i++) {
|
||||
if (ExpressionPtr e = (*m_expressions)[i]) {
|
||||
e->inferAndCheck(ar, Type::Some, false);
|
||||
}
|
||||
}
|
||||
return Type::Object;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void QueryOrderby::outputCodeModel(CodeGenerator &cg) {
|
||||
if (this->getKindOf() == Expression::KindOfOrderbyClause) {
|
||||
cg.printObjectHeader("OrderbyClause", 2);
|
||||
} else {
|
||||
cg.printObjectHeader("QueryExpression", 2);
|
||||
}
|
||||
cg.printPropertyHeader("clauses");
|
||||
m_expressions->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// code generation functions
|
||||
|
||||
void QueryOrderby::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
if (this->getKindOf() == Expression::KindOfOrderbyClause) {
|
||||
cg_printf("orderby ");
|
||||
}
|
||||
for (unsigned int i = 0; i < m_expressions->getCount(); i++) {
|
||||
if (ExpressionPtr e = (*m_expressions)[i]) {
|
||||
e->outputPHP(cg, ar);
|
||||
if (i > 0) cg_printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef incl_HPHP_QUERY_EXPRESSION_H_
|
||||
#define incl_HPHP_QUERY_EXPRESSION_H_
|
||||
|
||||
#include "hphp/compiler/expression/expression.h"
|
||||
#include "hphp/compiler/expression/expression_list.h"
|
||||
#include "hphp/runtime/base/static-string-table.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DECLARE_BOOST_TYPES(QueryOrderby);
|
||||
|
||||
class QueryOrderby : public Expression {
|
||||
public:
|
||||
DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
|
||||
protected:
|
||||
explicit QueryOrderby(EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS);
|
||||
|
||||
ExpressionListPtr m_expressions;
|
||||
};
|
||||
|
||||
DECLARE_BOOST_TYPES(QueryExpression);
|
||||
|
||||
class QueryExpression : public QueryOrderby {
|
||||
public:
|
||||
QueryExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr head, ExpressionPtr body);
|
||||
QueryExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionListPtr clauses);
|
||||
|
||||
virtual ExpressionPtr clone() {
|
||||
QueryExpressionPtr exp(new QueryExpression(*this));
|
||||
Expression::deepCopy(exp);
|
||||
exp->m_expressions = Clone(m_expressions);
|
||||
exp->m_queryargs = Clone(m_queryargs);
|
||||
exp->m_querystr = m_querystr;
|
||||
return exp;
|
||||
}
|
||||
|
||||
ExpressionListPtr getClauses() const { return m_expressions; }
|
||||
ExpressionListPtr getQueryArguments();
|
||||
StringData* getQueryString();
|
||||
private:
|
||||
void serializeQueryExpression();
|
||||
|
||||
ExpressionListPtr m_queryargs;
|
||||
StringData* m_querystr;
|
||||
};
|
||||
|
||||
DECLARE_BOOST_TYPES(OrderbyClause);
|
||||
|
||||
class OrderbyClause : public QueryOrderby {
|
||||
public:
|
||||
OrderbyClause(EXPRESSION_CONSTRUCTOR_PARAMETERS, ExpressionPtr orderings)
|
||||
: QueryOrderby(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(OrderbyClause)) {
|
||||
assert(orderings && orderings->is(Expression::KindOfExpressionList));
|
||||
m_expressions = static_pointer_cast<ExpressionList>(orderings);
|
||||
}
|
||||
|
||||
virtual ExpressionPtr clone() {
|
||||
OrderbyClausePtr exp(new OrderbyClause(*this));
|
||||
Expression::deepCopy(exp);
|
||||
exp->m_expressions = Clone(m_expressions);
|
||||
return exp;
|
||||
}
|
||||
|
||||
ExpressionListPtr getOrderings() const { return m_expressions; }
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
#endif // incl_HPHP_QUERY_EXPRESSION_H_
|
||||
@@ -387,39 +387,36 @@ std::string ScalarExpression::getIdentifier() const {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ScalarExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
switch (m_type) {
|
||||
case T_NS_C:
|
||||
case T_LINE:
|
||||
case T_TRAIT_C:
|
||||
case T_CLASS_C:
|
||||
case T_METHOD_C:
|
||||
case T_FUNC_C: {
|
||||
cg.printObjectHeader("SimpleVariableExpression", 2);
|
||||
std::string varName;
|
||||
switch (m_type) {
|
||||
case T_NS_C: varName = "__NAMESPACE__"; break;
|
||||
case T_LINE: varName = "__LINE__"; break;
|
||||
case T_TRAIT_C: varName = "__TRAIT__"; break;
|
||||
case T_CLASS_C: varName = "__CLASS__"; break;
|
||||
case T_METHOD_C: varName = "__METHOD__"; break;
|
||||
case T_FUNC_C: varName = "__FUNCTION__"; break;
|
||||
default: break;
|
||||
}
|
||||
cg.printPropertyHeader("variableName");
|
||||
cg.printValue(varName);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cg.printObjectHeader("ScalarExpression", 2);
|
||||
cg.printPropertyHeader("value");
|
||||
cg.printValue(m_originalValue);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
switch (m_type) {
|
||||
case T_CONSTANT_ENCAPSED_STRING:
|
||||
case T_ENCAPSED_AND_WHITESPACE:
|
||||
case T_STRING:
|
||||
case T_NUM_STRING:
|
||||
cg.printValue(m_value);
|
||||
break;
|
||||
case T_LNUMBER:
|
||||
case T_COMPILER_HALT_OFFSET:
|
||||
cg.printValue((int64_t)strtoll(m_value.c_str(), nullptr, 0));
|
||||
break;
|
||||
case T_LINE:
|
||||
cg.printValue(String(m_translated).toInt64());
|
||||
break;
|
||||
case T_TRAIT_C:
|
||||
case T_CLASS_C:
|
||||
case T_NS_C:
|
||||
case T_METHOD_C:
|
||||
case T_FUNC_C:
|
||||
cg.printValue(m_translated);
|
||||
break;
|
||||
case T_DNUMBER:
|
||||
cg.printValue(String(m_value).toDouble());
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
@@ -501,7 +498,7 @@ Variant ScalarExpression::getVariant() const {
|
||||
return String(m_value);
|
||||
case T_LNUMBER:
|
||||
case T_COMPILER_HALT_OFFSET:
|
||||
return getIntValue();
|
||||
return strtoll(m_value.c_str(), nullptr, 0);
|
||||
case T_LINE:
|
||||
return String(m_translated).toInt64();
|
||||
case T_TRAIT_C:
|
||||
@@ -540,7 +537,7 @@ bool ScalarExpression::getString(const std::string *&s) const {
|
||||
|
||||
bool ScalarExpression::getInt(int64_t &i) const {
|
||||
if (m_type == T_LNUMBER || m_type == T_COMPILER_HALT_OFFSET) {
|
||||
i = getIntValue();
|
||||
i = strtoll(m_value.c_str(), nullptr, 0);
|
||||
return true;
|
||||
} else if (m_type == T_LINE) {
|
||||
i = getLocation() ? getLocation()->line1 : 0;
|
||||
@@ -566,12 +563,3 @@ void ScalarExpression::setCompilerHaltOffset(int64_t ofs) {
|
||||
m_value = ss.str();
|
||||
m_originalValue = ss.str();
|
||||
}
|
||||
|
||||
int64_t ScalarExpression::getIntValue() const {
|
||||
// binary number syntax "0b" is not supported by strtoll
|
||||
if (m_value.compare(0, 2, "0b") == 0) {
|
||||
return strtoll(m_value.c_str() + 2, nullptr, 2);
|
||||
}
|
||||
|
||||
return strtoll(m_value.c_str(), nullptr, 0);
|
||||
}
|
||||
|
||||
@@ -87,8 +87,6 @@ private:
|
||||
std::string m_translated;
|
||||
bool m_quoted;
|
||||
std::string m_comment; // for inlined constant name
|
||||
|
||||
int64_t getIntValue() const;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -545,9 +545,7 @@ void SimpleFunctionCall::analyzeProgram(AnalysisResultPtr ar) {
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
if (m_classScope || !Unit::lookupFunc(String(m_name).get())) {
|
||||
Compiler::Error(Compiler::UnknownFunction, shared_from_this());
|
||||
}
|
||||
Compiler::Error(Compiler::UnknownFunction, shared_from_this());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1287,11 +1285,11 @@ void SimpleFunctionCall::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("SimpleFunctionCallExpression", 3);
|
||||
cg.printPropertyHeader("functionName");
|
||||
}
|
||||
cg.printValue(m_origName);
|
||||
m_nameExp->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("arguments");
|
||||
cg.printExpressionVector(m_params);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(m_nameExp->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -1634,3 +1632,4 @@ ExpressionPtr hphp_opt_is_callable(CodeGenerator *cg,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "hphp/compiler/expression/simple_query_clause.h"
|
||||
#include "hphp/compiler/analysis/code_error.h"
|
||||
#include "hphp/runtime/base/complex-types.h"
|
||||
|
||||
using namespace HPHP;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// constructors/destructors
|
||||
|
||||
SimpleQueryClause::SimpleQueryClause
|
||||
(EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS,
|
||||
const std::string &identifier, ExpressionPtr expression)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_BASE_PARAMETER_VALUES) {
|
||||
m_identifier = identifier;
|
||||
m_expression = expression;
|
||||
}
|
||||
|
||||
ExpressionPtr SimpleQueryClause::clone() {
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// parser functions
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// static analysis functions
|
||||
|
||||
void SimpleQueryClause::analyzeProgram(AnalysisResultPtr ar) {
|
||||
m_expression->analyzeProgram(ar);
|
||||
}
|
||||
|
||||
ConstructPtr SimpleQueryClause::getNthKid(int n) const {
|
||||
switch (n) {
|
||||
case 0:
|
||||
return m_expression;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return ConstructPtr();
|
||||
}
|
||||
|
||||
int SimpleQueryClause::getKidCount() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SimpleQueryClause::setNthKid(int n, ConstructPtr cp) {
|
||||
switch (n) {
|
||||
case 0:
|
||||
m_expression = dynamic_pointer_cast<Expression>(cp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TypePtr SimpleQueryClause::inferTypes(AnalysisResultPtr ar,
|
||||
TypePtr type, bool coerce) {
|
||||
m_expression->inferAndCheck(ar, Type::Some, false);
|
||||
return Type::Object;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SimpleQueryClause::outputCodeModel(CodeGenerator &cg) {
|
||||
switch (this->getKindOf()) {
|
||||
case Expression::KindOfFromClause:
|
||||
cg.printObjectHeader("FromClause", 3);
|
||||
cg.printPropertyHeader("identifier");
|
||||
cg.printValue(m_identifier);
|
||||
cg.printPropertyHeader("collection");
|
||||
break;
|
||||
case Expression::KindOfLetClause:
|
||||
cg.printObjectHeader("LetClause", 3);
|
||||
cg.printPropertyHeader("identifier");
|
||||
cg.printValue(m_identifier);
|
||||
cg.printPropertyHeader("expression");
|
||||
break;
|
||||
case Expression::KindOfIntoClause:
|
||||
cg.printObjectHeader("IntoClause", 3);
|
||||
cg.printPropertyHeader("identifier");
|
||||
cg.printValue(m_identifier);
|
||||
cg.printPropertyHeader("query");
|
||||
break;
|
||||
case Expression::KindOfWhereClause:
|
||||
cg.printObjectHeader("WhereClause", 2);
|
||||
cg.printPropertyHeader("condition");
|
||||
break;
|
||||
case Expression::KindOfSelectClause:
|
||||
cg.printObjectHeader("SelectClause", 2);
|
||||
cg.printPropertyHeader("expression");
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
m_expression->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// code generation functions
|
||||
|
||||
void SimpleQueryClause::outputPHP(
|
||||
CodeGenerator &cg, AnalysisResultPtr ar) {
|
||||
switch (this->getKindOf()) {
|
||||
case Expression::KindOfFromClause:
|
||||
cg_printf("from %s in ", m_identifier.c_str());
|
||||
break;
|
||||
case Expression::KindOfLetClause:
|
||||
cg_printf("let %s in ", m_identifier.c_str());
|
||||
break;
|
||||
case Expression::KindOfIntoClause:
|
||||
cg_printf("into %s ", m_identifier.c_str());
|
||||
break;
|
||||
case Expression::KindOfWhereClause:
|
||||
cg_printf("where ");
|
||||
break;
|
||||
case Expression::KindOfSelectClause:
|
||||
cg_printf("select ");
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
m_expression->outputPHP(cg, ar);
|
||||
}
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef incl_HPHP_SIMPLE_QUERY_CLAUSE_H_
|
||||
#define incl_HPHP_SIMPLE_QUERY_CLAUSE_H_
|
||||
|
||||
#include "hphp/compiler/expression/expression.h"
|
||||
#include "hphp/compiler/expression/expression_list.h"
|
||||
|
||||
namespace HPHP {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DECLARE_BOOST_TYPES(SimpleQueryClause);
|
||||
|
||||
class SimpleQueryClause : public Expression {
|
||||
public:
|
||||
DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
|
||||
std::string getIdentifier() const { return m_identifier; }
|
||||
ExpressionPtr getExpression() { return m_expression; }
|
||||
void setExpression(ExpressionPtr value) { m_expression = value; }
|
||||
protected:
|
||||
SimpleQueryClause(EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS,
|
||||
const std::string &identifier, ExpressionPtr collection);
|
||||
|
||||
std::string m_identifier;
|
||||
ExpressionPtr m_expression;
|
||||
};
|
||||
|
||||
DECLARE_BOOST_TYPES(FromClause);
|
||||
|
||||
class FromClause : public SimpleQueryClause {
|
||||
public:
|
||||
FromClause(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const std::string &identifier, ExpressionPtr collection)
|
||||
: SimpleQueryClause(
|
||||
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(FromClause),
|
||||
identifier, collection) {
|
||||
}
|
||||
|
||||
virtual ExpressionPtr clone() {
|
||||
FromClausePtr exp(new FromClause(*this));
|
||||
Expression::deepCopy(exp);
|
||||
exp->m_identifier = m_identifier;
|
||||
exp->m_expression = Clone(m_expression);
|
||||
return exp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOOST_TYPES(LetClause);
|
||||
|
||||
class LetClause : public SimpleQueryClause {
|
||||
public:
|
||||
LetClause(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const std::string &identifier, ExpressionPtr expression)
|
||||
: SimpleQueryClause(
|
||||
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(LetClause),
|
||||
identifier, expression) {
|
||||
}
|
||||
|
||||
virtual ExpressionPtr clone() {
|
||||
LetClausePtr exp(new LetClause(*this));
|
||||
Expression::deepCopy(exp);
|
||||
exp->m_identifier = m_identifier;
|
||||
exp->m_expression = Clone(m_expression);
|
||||
return exp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOOST_TYPES(WhereClause);
|
||||
|
||||
class WhereClause : public SimpleQueryClause {
|
||||
public:
|
||||
WhereClause(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr condition)
|
||||
: SimpleQueryClause(
|
||||
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(WhereClause),
|
||||
"", condition) {
|
||||
}
|
||||
|
||||
virtual ExpressionPtr clone() {
|
||||
WhereClausePtr exp(new WhereClause(*this));
|
||||
Expression::deepCopy(exp);
|
||||
exp->m_identifier = m_identifier;
|
||||
exp->m_expression = Clone(m_expression);
|
||||
return exp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOOST_TYPES(SelectClause);
|
||||
|
||||
class SelectClause : public SimpleQueryClause {
|
||||
public:
|
||||
SelectClause(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr expression)
|
||||
: SimpleQueryClause(
|
||||
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(SelectClause),
|
||||
"", expression) {
|
||||
}
|
||||
|
||||
virtual ExpressionPtr clone() {
|
||||
SelectClausePtr exp(new SelectClause(*this));
|
||||
Expression::deepCopy(exp);
|
||||
exp->m_identifier = m_identifier;
|
||||
exp->m_expression = Clone(m_expression);
|
||||
return exp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOOST_TYPES(IntoClause);
|
||||
|
||||
class IntoClause : public SimpleQueryClause {
|
||||
public:
|
||||
IntoClause(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const std::string &identifier, ExpressionPtr query)
|
||||
: SimpleQueryClause(
|
||||
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(IntoClause),
|
||||
identifier, query) {
|
||||
}
|
||||
|
||||
virtual ExpressionPtr clone() {
|
||||
IntoClausePtr exp(new IntoClause(*this));
|
||||
Expression::deepCopy(exp);
|
||||
exp->m_identifier = m_identifier;
|
||||
exp->m_expression = Clone(m_expression);
|
||||
return exp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
#endif // incl_HPHP_SIMPLE_QUERY_CLAUSE_H_
|
||||
@@ -313,7 +313,7 @@ void SimpleVariable::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("SimpleVariableExpression", 2);
|
||||
cg.printPropertyHeader("variableName");
|
||||
cg.printValue(m_name);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -169,13 +169,13 @@ bool StaticClassName::checkPresent() {
|
||||
|
||||
void StaticClassName::outputCodeModel(CodeGenerator &cg) {
|
||||
if (isSelf()) {
|
||||
cg.printValue("self");
|
||||
cg.printf("self");
|
||||
} else if (isParent()) {
|
||||
cg.printValue("parent");
|
||||
cg.printf("parent");
|
||||
} else if (isStatic()) {
|
||||
cg.printValue("static");
|
||||
cg.printf("static");
|
||||
} else {
|
||||
cg.printValue(m_origClassName);
|
||||
cg.printf("%s", m_origClassName.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ bool StaticMemberExpression::canonCompare(ExpressionPtr e) const {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void StaticMemberExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("ClassPropertyExpression", 3);
|
||||
cg.printObjectHeader("ClassPropertyExpression", 2);
|
||||
cg.printPropertyHeader("className");
|
||||
StaticClassName::outputCodeModel(cg);
|
||||
if (m_exp->is(Expression::KindOfScalarExpression)) {
|
||||
@@ -349,7 +349,7 @@ void StaticMemberExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printPropertyHeader("propertyExpression");
|
||||
}
|
||||
m_exp->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -571,7 +571,6 @@ ExpressionPtr UnaryOpExpression::unneededHelper() {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UnaryOpExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
auto numProps = m_exp == nullptr ? 2 : 3;
|
||||
switch (m_op) {
|
||||
case T_UNSET:
|
||||
case T_EXIT:
|
||||
@@ -579,7 +578,7 @@ void UnaryOpExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
case T_ISSET:
|
||||
case T_EMPTY:
|
||||
case T_EVAL: {
|
||||
cg.printObjectHeader("SimpleFunctionCallExpression", numProps);
|
||||
cg.printObjectHeader("SimpleFunctionCallExpression", 3);
|
||||
std::string funcName;
|
||||
switch (m_op) {
|
||||
case T_UNSET: funcName = "unset"; break;
|
||||
@@ -592,11 +591,11 @@ void UnaryOpExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
}
|
||||
cg.printPropertyHeader("functionName");
|
||||
cg.printValue(funcName);
|
||||
if (m_exp != nullptr) {
|
||||
cg.printPropertyHeader("arguments");
|
||||
cg.printExpressionVector(m_exp);
|
||||
}
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("arguments");
|
||||
printf("V:6:\"Vector\":1:{");
|
||||
m_exp->outputCodeModel(cg);
|
||||
printf("}");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
return;
|
||||
@@ -605,38 +604,9 @@ void UnaryOpExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (m_op) {
|
||||
case T_FILE:
|
||||
case T_DIR:
|
||||
case T_CLASS:
|
||||
case T_FUNCTION: {
|
||||
cg.printObjectHeader("SimpleVariableExpression", 2);
|
||||
std::string varName;
|
||||
switch (m_op) {
|
||||
case T_FILE: varName = "__FILE__"; break;
|
||||
case T_DIR: varName = "__DIR__"; break;
|
||||
//case T_CLASS: varName = "class"; break;
|
||||
//case T_FUNCTION: varName = "function"; break;
|
||||
default:
|
||||
assert(false); //fishing expedition. Are these cases dead?
|
||||
break;
|
||||
}
|
||||
cg.printPropertyHeader("variableName");
|
||||
cg.printValue(varName);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cg.printObjectHeader("UnaryOpExpression", numProps);
|
||||
if (m_exp != nullptr) {
|
||||
cg.printPropertyHeader("expression");
|
||||
m_exp->outputCodeModel(cg);
|
||||
}
|
||||
cg.printObjectHeader("UnaryOpExpression", 3);
|
||||
cg.printPropertyHeader("expression");
|
||||
m_exp->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("operation");
|
||||
int op = 0;
|
||||
switch (m_op) {
|
||||
@@ -659,7 +629,6 @@ void UnaryOpExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
case T_BOOL_CAST: op = PHP_BOOL_CAST_OP; break;
|
||||
case T_UNSET_CAST: op = PHP_UNSET_CAST_OP; break;
|
||||
case '@': op = PHP_ERROR_CONTROL_OP; break;
|
||||
case T_PRINT: op = PHP_PRINT_OP; break;
|
||||
case T_INCLUDE: op = PHP_INCLUDE_OP; break;
|
||||
case T_INCLUDE_ONCE: op = PHP_INCLUDE_ONCE_OP; break;
|
||||
case T_REQUIRE: op = PHP_REQUIRE_OP; break;
|
||||
@@ -668,7 +637,7 @@ void UnaryOpExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
assert(false);
|
||||
}
|
||||
cg.printValue(op);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -61,31 +61,25 @@ TypePtr UserAttribute::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UserAttribute::outputCodeModel(CodeGenerator &cg) {
|
||||
cg.printObjectHeader("Attribute", m_exp != nullptr ? 3 : 2);
|
||||
cg.printObjectHeader("CodeAttribute", m_exp != nullptr ? 3 : 2);
|
||||
cg.printPropertyHeader("attributeName");
|
||||
cg.printValue(m_name);
|
||||
if (m_exp != nullptr && m_exp->is(Expression::KindOfUnaryOpExpression)) {
|
||||
UnaryOpExpressionPtr u(static_pointer_cast<UnaryOpExpression>(m_exp));
|
||||
if (u->getOp() == T_ARRAY) {
|
||||
ExpressionPtr ex = u->getExpression();
|
||||
if (ex != nullptr) {
|
||||
if (ex->is(Expression::KindOfExpressionList)) {
|
||||
ExpressionListPtr el(static_pointer_cast<ExpressionList>(ex));
|
||||
cg.printPropertyHeader("expressions");
|
||||
cg.printExpressionVector(el);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
} else {
|
||||
ExpressionListPtr el;
|
||||
if (ex->is(Expression::KindOfExpressionList)) {
|
||||
ExpressionListPtr el(static_pointer_cast<ExpressionList>(ex));
|
||||
cg.printPropertyHeader("expressions");
|
||||
cg.printExpressionVector(el);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ void YieldExpression::outputCodeModel(CodeGenerator &cg) {
|
||||
}
|
||||
cg.printPropertyHeader("value");
|
||||
m_valExp->outputCodeModel(cg);
|
||||
cg.printPropertyHeader("sourceLocation");
|
||||
cg.printPropertyHeader("location");
|
||||
cg.printLocation(this->getLocation());
|
||||
cg.printObjectFooter();
|
||||
}
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário