From 23e38a0f1235019b0c1cc7fede7ecd786ff16cbf Mon Sep 17 00:00:00 2001 From: hector Date: Sun, 10 Jun 2012 23:41:58 +0200 Subject: [PATCH] moved back to old acc --- .gitignore | 32 + CMakeLists.txt | 180 ++ HISTORY | 15 + LICENSE | 26 + README | 7 + TODO | 4 + emscripten/Makefile | 19 + emscripten/console.html | 78 + emscripten/make.vx | 125 ++ etc/makefile | 34 + etc/min | Bin 0 -> 70357 bytes etc/minimal.cpp | 153 ++ etc/minimal.o | Bin 0 -> 65040 bytes etc/out.vx | 1 + etc/test.vx | 17 + etc/tmp/all.cpp | 30 + etc/tmp/custom_alloc.cpp | 0 examples/99_bottles_of_beer.vx | 14 + examples/ackermann.vx | 30 + examples/array.vx | 24 + examples/bin2c.vx | 151 ++ examples/class.vx | 49 + examples/classattributes.vx | 42 + examples/compiletpl.vx | 10 + examples/config/sample.cfg | 9 + examples/config/test.vx | 17 + examples/coroutines.vx | 24 + examples/debug.vx | 67 + examples/delegation.vx | 54 + examples/doors.vx | 17 + examples/dow.vx | 31 + examples/fibonacci.vx | 23 + examples/flow.vx | 33 + examples/generators.vx | 42 + examples/hello.vx | 3 + examples/hello_extended.vx | 64 + examples/inheritance.vx | 60 + examples/interactive.vx | 114 ++ examples/lint.vx | 31 + examples/list.vx | 40 + examples/loops.vx | 32 + examples/matrix.vx | 70 + examples/metamethods.vx | 123 ++ examples/methcall.vx | 75 + examples/no_commas.vx | 0 examples/prototypes.vx | 24 + examples/readfile_extended.vx | 12 + examples/regex.vx | 17 + examples/spellnumber.vx | 84 + examples/substr.vx | 10 + examples/syntax-abuse.vx | 26 + examples/tailstate.vx | 26 + examples/walk.vx | 29 + examples/ycombinator.vx | 25 + include/vox.h | 1485 ++++++++++++++++ modules/core/cgi.vx | 760 +++++++++ modules/core/config.vx | 254 +++ modules/core/debug.vx | 12 + modules/core/repr.vx | 150 ++ modules/core/sandbox.vx | 41 + modules/core/serialize.vx | 9 + modules/core/simpledb.vx | 50 + modules/core/strict.vx | 23 + modules/core/warning.vx | 7 + src/core/CMakeLists.txt | 59 + src/core/array.cpp | 177 ++ src/core/baselib.cpp | 293 ++++ src/core/baselib.hpp | 27 + src/core/baselib_array.cpp | 508 ++++++ src/core/baselib_class.cpp | 91 + src/core/baselib_closure.cpp | 125 ++ src/core/baselib_generator.cpp | 35 + src/core/baselib_hashlib.cpp | 117 ++ src/core/baselib_io.cpp | 496 ++++++ src/core/baselib_math.cpp | 191 +++ src/core/baselib_string.cpp | 757 +++++++++ src/core/baselib_system.cpp | 432 +++++ src/core/baselib_table.cpp | 94 ++ src/core/baselib_thread.cpp | 143 ++ src/core/class.cpp | 415 +++++ src/core/class.hpp | 23 + src/core/closure.cpp | 72 + src/core/closure.hpp | 247 +++ src/core/compiler.cpp | 2205 ++++++++++++++++++++++++ src/core/compiler.hpp | 82 + src/core/debug.cpp | 108 ++ src/core/debug.hpp | 33 + src/core/errors.hpp | 0 src/core/funcproto.cpp | 238 +++ src/core/funcproto.hpp | 190 +++ src/core/funcstate.cpp | 754 +++++++++ src/core/funcstate.hpp | 92 + src/core/h_impl.cpp | 663 ++++++++ src/core/hash.hpp | 177 ++ src/core/lexer.cpp | 727 ++++++++ src/core/lexer.hpp | 42 + src/core/mem.cpp | 34 + src/core/mem.hpp | 20 + src/core/names.hpp | 35 + src/core/object.cpp | 911 ++++++++++ src/core/object.hpp | 195 +++ src/core/opcodes.cpp | 586 +++++++ src/core/opcodes.hpp | 231 +++ src/core/pcheader.hpp | 51 + src/core/repr.cpp | 122 ++ src/core/state.cpp | 692 ++++++++ src/core/state.hpp | 136 ++ src/core/string.cpp | 38 + src/core/string.hpp | 24 + src/core/table.cpp | 409 +++++ src/core/table.hpp | 32 + src/core/userdata.hpp | 39 + src/core/utils.cpp | 62 + src/core/utils.hpp | 48 + src/core/vm.cpp | 3629 ++++++++++++++++++++++++++++++++++++++++ src/core/vm.hpp | 62 + src/frontend/CMakeLists.txt | 26 + src/frontend/frontend.cpp | 537 ++++++ src/frontend/optget.cpp | 293 ++++ src/frontend/optget.h | 113 ++ src/stdlib/CMakeLists.txt | 43 + src/stdlib/helper.hpp | 39 + src/stdlib/importlib.cpp | 315 ++++ src/stdlib/loadlib.cpp | 90 + src/stdlib/oslib.cpp | 522 ++++++ src/stdlib/regexp.cpp | 251 +++ src/stdlib/sharedlib.c | 172 ++ src/stdlib/sharedlib.h | 60 + src/stdlib/vxlibrary.hpp | 155 ++ test/syntax/classattr.vx | 39 + test/syntax/classdef.vx | 28 + test/syntax/dowhile.vx | 9 + test/syntax/for.vx | 0 test/syntax/foreach.vx | 0 test/syntax/funcdef.vx | 24 + test/syntax/if.vx | 0 test/syntax/literals.vx | 12 + test/syntax/trycatch.vx | 9 + test/syntax/variables.vx | 32 + test/syntax/while.vx | 6 + 140 files changed, 24758 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 HISTORY create mode 100644 LICENSE create mode 100644 README create mode 100644 TODO create mode 100644 emscripten/Makefile create mode 100644 emscripten/console.html create mode 100644 emscripten/make.vx create mode 100644 etc/makefile create mode 100755 etc/min create mode 100644 etc/minimal.cpp create mode 100644 etc/minimal.o create mode 100644 etc/out.vx create mode 100644 etc/test.vx create mode 100644 etc/tmp/all.cpp create mode 100644 etc/tmp/custom_alloc.cpp create mode 100644 examples/99_bottles_of_beer.vx create mode 100644 examples/ackermann.vx create mode 100644 examples/array.vx create mode 100644 examples/bin2c.vx create mode 100644 examples/class.vx create mode 100644 examples/classattributes.vx create mode 100644 examples/compiletpl.vx create mode 100644 examples/config/sample.cfg create mode 100644 examples/config/test.vx create mode 100644 examples/coroutines.vx create mode 100644 examples/debug.vx create mode 100644 examples/delegation.vx create mode 100644 examples/doors.vx create mode 100644 examples/dow.vx create mode 100644 examples/fibonacci.vx create mode 100644 examples/flow.vx create mode 100644 examples/generators.vx create mode 100644 examples/hello.vx create mode 100644 examples/hello_extended.vx create mode 100644 examples/inheritance.vx create mode 100644 examples/interactive.vx create mode 100644 examples/lint.vx create mode 100644 examples/list.vx create mode 100644 examples/loops.vx create mode 100644 examples/matrix.vx create mode 100644 examples/metamethods.vx create mode 100644 examples/methcall.vx create mode 100644 examples/no_commas.vx create mode 100644 examples/prototypes.vx create mode 100644 examples/readfile_extended.vx create mode 100644 examples/regex.vx create mode 100644 examples/spellnumber.vx create mode 100644 examples/substr.vx create mode 100644 examples/syntax-abuse.vx create mode 100644 examples/tailstate.vx create mode 100644 examples/walk.vx create mode 100644 examples/ycombinator.vx create mode 100644 include/vox.h create mode 100644 modules/core/cgi.vx create mode 100644 modules/core/config.vx create mode 100644 modules/core/debug.vx create mode 100644 modules/core/repr.vx create mode 100644 modules/core/sandbox.vx create mode 100644 modules/core/serialize.vx create mode 100644 modules/core/simpledb.vx create mode 100644 modules/core/strict.vx create mode 100644 modules/core/warning.vx create mode 100644 src/core/CMakeLists.txt create mode 100644 src/core/array.cpp create mode 100644 src/core/baselib.cpp create mode 100644 src/core/baselib.hpp create mode 100644 src/core/baselib_array.cpp create mode 100644 src/core/baselib_class.cpp create mode 100644 src/core/baselib_closure.cpp create mode 100644 src/core/baselib_generator.cpp create mode 100644 src/core/baselib_hashlib.cpp create mode 100644 src/core/baselib_io.cpp create mode 100644 src/core/baselib_math.cpp create mode 100644 src/core/baselib_string.cpp create mode 100644 src/core/baselib_system.cpp create mode 100644 src/core/baselib_table.cpp create mode 100644 src/core/baselib_thread.cpp create mode 100644 src/core/class.cpp create mode 100644 src/core/class.hpp create mode 100644 src/core/closure.cpp create mode 100644 src/core/closure.hpp create mode 100644 src/core/compiler.cpp create mode 100644 src/core/compiler.hpp create mode 100644 src/core/debug.cpp create mode 100644 src/core/debug.hpp create mode 100644 src/core/errors.hpp create mode 100644 src/core/funcproto.cpp create mode 100644 src/core/funcproto.hpp create mode 100644 src/core/funcstate.cpp create mode 100644 src/core/funcstate.hpp create mode 100644 src/core/h_impl.cpp create mode 100644 src/core/hash.hpp create mode 100644 src/core/lexer.cpp create mode 100644 src/core/lexer.hpp create mode 100644 src/core/mem.cpp create mode 100644 src/core/mem.hpp create mode 100644 src/core/names.hpp create mode 100644 src/core/object.cpp create mode 100644 src/core/object.hpp create mode 100644 src/core/opcodes.cpp create mode 100644 src/core/opcodes.hpp create mode 100644 src/core/pcheader.hpp create mode 100644 src/core/repr.cpp create mode 100644 src/core/state.cpp create mode 100644 src/core/state.hpp create mode 100644 src/core/string.cpp create mode 100644 src/core/string.hpp create mode 100644 src/core/table.cpp create mode 100644 src/core/table.hpp create mode 100644 src/core/userdata.hpp create mode 100644 src/core/utils.cpp create mode 100644 src/core/utils.hpp create mode 100644 src/core/vm.cpp create mode 100644 src/core/vm.hpp create mode 100644 src/frontend/CMakeLists.txt create mode 100644 src/frontend/frontend.cpp create mode 100644 src/frontend/optget.cpp create mode 100644 src/frontend/optget.h create mode 100644 src/stdlib/CMakeLists.txt create mode 100644 src/stdlib/helper.hpp create mode 100644 src/stdlib/importlib.cpp create mode 100644 src/stdlib/loadlib.cpp create mode 100644 src/stdlib/oslib.cpp create mode 100644 src/stdlib/regexp.cpp create mode 100644 src/stdlib/sharedlib.c create mode 100644 src/stdlib/sharedlib.h create mode 100644 src/stdlib/vxlibrary.hpp create mode 100644 test/syntax/classattr.vx create mode 100644 test/syntax/classdef.vx create mode 100644 test/syntax/dowhile.vx create mode 100644 test/syntax/for.vx create mode 100644 test/syntax/foreach.vx create mode 100644 test/syntax/funcdef.vx create mode 100644 test/syntax/if.vx create mode 100644 test/syntax/literals.vx create mode 100644 test/syntax/trycatch.vx create mode 100644 test/syntax/variables.vx create mode 100644 test/syntax/while.vx diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1bac21e --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +## build root (BSD or Linux) +build* +build*/ +build*/* +build_* +build_*/ +build_*/** + +## build root (Windows) +wbuild* +wbuild*/ +wbuild*/* +wbuild_* +wbuild_*/ +wbuild_*/** + +## temporary folders +temp* +temp*/ +temp*/* + + +## archive generators and generated archives +mkarch.sh +*.tar.bz2 +*.tar.gz + +## kate rubbish +**.kate-swp + +## precompiled headers +**.gch diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c6d7366 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,180 @@ + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(VoxLang CXX C) +INCLUDE (CheckIncludeFiles) + +MACRO(VXOPTION varname description defaultvalue) + OPTION(${varname} ${description} ${defaultvalue}) +ENDMACRO(VXOPTION) + +MACRO(VXOPTION_A varname description defaultvalue) + VXOPTION(${varname} ${description} ${defaultvalue}) + MARK_AS_ADVANCED(${varname}) +ENDMACRO(VXOPTION_A) + +MACRO(VXCMINCLUDE file) + CMAKE_POLICY(SET CMP0011 NEW) + INCLUDE("${CMAKE_CURRENT_SOURCE_DIR}/cmake/${file}") + CMAKE_POLICY(SET CMP0011 OLD) +ENDMACRO(VXCMINCLUDE) + +MACRO(SET_32BIT_ENV) + SET(CMAKE_C_FLAGS -m32) + SET(CMAKE_CXX_FLAGS -m32) + SET(CMAKE_SHARED_LINKER_FLAGS "-m32") +ENDMACRO(SET_32BIT_ENV) + + +############## +CHECK_INCLUDE_FILES("malloc.h" HAVE_MALLOC_H) +#### + +# don't actually uncomment this unless you +# _do_ want to screw over the build +#set(CMAKE_BUILD_TYPE "Release") +SET(CMAKE_BUILD_TYPE "Debug") +#SET(CMAKE_CXX_FLAGS "-g3 -ggdb") + + +## add the path to $srcdir/modules/ and +## $installdir/modules +ADD_DEFINITIONS( + "-DVOX_MODULEPATH_SRCDIR=\"${CMAKE_CURRENT_SOURCE_DIR}/modules/\"" + "-DVOX_MODULEPATH_INSTALLDIR=\"${CMAKE_INSTALL_PREFIX}/modules/\"" +) + +## various options (usable from cmake-gui, for example) +VXOPTION(BUILD_STDLIB + "OFF to skip building the vox standard library" ON) +VXOPTION(BUILD_SHAREDLIBS + "ON to build libraries as shared libraries" ON) +VXOPTION(WITHOUT_COMPILER + "ON to skip the compiler (bytecode-only)" OFF) +VXOPTION(TRACE_API_CALLS + "ON to trace Vox API calls to stderr (warning: might slow vox down!)" OFF) +VXOPTION(STRIP_FILES + "ON to strip libraries/binaries (currently only used for CPack)" OFF) +VXOPTION(BUILD_32BIT + "ON to build vox as 32bit library and binary/binaries. Currently only supported for GCC!" + OFF) + +# the core library +SET(vox_corelib "vox_target_corelib") +SET(vox_corelib_name "vox") + +# the stdlib +SET(vox_stdlib "vox_target_stdlib") +SET(vox_stdlib_name "vox_stdlib") + + +# the frontend interpreter +SET(vox_exe "vox_target_exe") +SET(vox_exe_name "vox") + + + + +## paths to be inserted into the runtime paths +SET(vox_rpath_paths + "${CMAKE_INSTALL_PREFIX}" + "${CMAKE_INSTALL_PREFIX}/lib" + "${CMAKE_CURRENT_BINARY_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}/lib" +) +## the path to the headers +SET(vox_incpath "${CMAKE_CURRENT_SOURCE_DIR}/include") + + + +# make cmake put all binaries/libraries in the root of the builddir +# note that this is set likely only temporary, as vox isn't quite +# ready yet to be installed, even though installing is supported +SET(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}") +SET(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}") + + +## list of all headers (may be extended, if necessary) +SET(vox_includes "${vox_incpath}") + +## find boost +set(Boost_DEBUG OFF) +#set(Boost_USE_STATIC_RUNTIME ON) +FIND_PACKAGE(Boost COMPONENTS system filesystem regex) +MESSAGE(STATUS "\${Boost_INCLUDE_DIRS}: ${Boost_INCLUDE_DIRS}") +#set(Boost_FOUND OFF) + + +## core libraries, taking care of dependencies +## to dlfcn, LoadLibrary, and such +SET(vox_coredeps) +IF(WIN32) + SET(vox_coredeps + "kernel32" + "user32") +ELSEIF(UNIX) + IF(CMAKE_SYSTEM_NAME MATCHES "(.+)BSD") + ## apparently, *BSD provides dlfcn via libc, + ## so nothing to do here + ELSE() + SET(vox_coredeps ${vox_coredeps} "dl") + ENDIF() + SET(vox_coredeps ${vox_coredeps} "m") +ENDIF(WIN32) + +IF(Boost_FOUND) + MESSAGE(STATUS "Will link against libboost*") + ADD_DEFINITIONS("-DVOX_HAVEBOOST") + INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) + SET(VOX_HAVEBOOST 1) + SET(vox_coredeps ${vox_coredeps} ${Boost_LIBRARIES}) +ENDIF(Boost_FOUND) + + +## add include paths to compiler flags (-I$path) +INCLUDE_DIRECTORIES(${vox_includes}) + +## build actual projects +IF(BUILD_32BIT) + MESSAGE(STATUS "Vox will be built as 32Bit binaries!") + SET_32BIT_ENV() +ENDIF(BUILD_32BIT) +IF(TRACE_API_CALLS) + ADD_DEFINITIONS("-DVOX_TRACE_API_CALLS=1") +ENDIF(TRACE_API_CALLS) +IF(WITHOUT_COMPILER) + ADD_DEFINITIONS("-DVOX_NO_COMPILER=1") +ENDIF(WITHOUT_COMPILER) +ADD_SUBDIRECTORY("${CMAKE_CURRENT_SOURCE_DIR}/src/core") +IF(BUILD_STDLIB) + ADD_DEFINITIONS("-DVOX_STDLIB_AVAILABLE=1") + ADD_SUBDIRECTORY("${CMAKE_CURRENT_SOURCE_DIR}/src/stdlib") +ENDIF(BUILD_STDLIB) +ADD_SUBDIRECTORY("${CMAKE_CURRENT_SOURCE_DIR}/src/frontend") + + +## installation of headerfiles +INSTALL( + DIRECTORY "${vox_incpath}/vox" + DESTINATION include +) + +#SET(CPACK_GENERATOR "DEB;TGZ;RPM") +SET(CPACK_GENERATOR "DEB") +SET(CPACK_PACKAGE_NAME "vox1") +SET(CPACK_PACKAGE_VERSION "1.0.1") +SET(CPACK_PACKAGE_VERSION_MAJOR "1") +SET(CPACK_PACKAGE_VERSION_MINOR "0") +SET(CPACK_PACKAGE_VERSION_PATCH "1") +SET(CPACK_PACKAGE_FILE_NAME "vox1") +SET(CPACK_PACKAGE_VENDOR "Beelzebub Software") +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Embeddable, extensible programming language") +SET(CPACK_PACKAGE_INSTALL_DIRECTORY "vox${CPACK_PACKAGE_VERSION_MAJOR}") +SET(CPACK_PACKAGE_INSTALL_REGISTRY_KEY + "VoxPL-${CPACK_PACKAGE_VERSION_MAJOR}") +SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") +SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") +#SET(CPACK_RESOURCE_FILE_WELCOME "${CMAKE_CURRENT_SOURCE_DIR}/pkg/welcome.txt") +SET(CPACK_NSIS_DISPLAY_NAME "Vox${CPACK_PACKAGE_VERSION_MAJOR} SDK") +SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "maintainer@email.address") +INCLUDE(CPack) + diff --git a/HISTORY b/HISTORY new file mode 100644 index 0000000..f81dd7f --- /dev/null +++ b/HISTORY @@ -0,0 +1,15 @@ + +Version 1.8.0: + + introduced hashlib as part of the core (currently supporting MD5 and SHA1) + + core/sandbox is now a class, that enforces a specific environment + + lexer now understands '\e' + +Version: 1.05 (26 01 12): + + moved from Mars to Boost + + cleanup of the lexer, new slot operator ('<-' became ':=') + + stdlib rewritten from scratch + + no more external stringlib, instead it became part of the core as stringtype methods + +Version: 0.1 (14 12 2011): + + First public release + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..33d0387 --- /dev/null +++ b/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2011-2012 Beelzebub Software +Copyright (c) 2003-2011 Alberto Demichelis + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README b/README new file mode 100644 index 0000000..4937c7d --- /dev/null +++ b/README @@ -0,0 +1,7 @@ +The VOX programming language is a new, experimental multipurpose Programming language +based on a heavily modified version of the core vm of Squirrel (3.0). + +Vox is still in testing, but already contains just about everything needed to +use it, embed it, and extend it. + +To get started, read the minimal example application at etc/minimal.cpp. \ No newline at end of file diff --git a/TODO b/TODO new file mode 100644 index 0000000..0d493f6 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ + ++ write actual documentation (document vox.h) ++ implement socketlib (very unlikely for now; boost.asio is a possible candidate) ++ free cgi.vx from non-voxist code diff --git a/emscripten/Makefile b/emscripten/Makefile new file mode 100644 index 0000000..5e95a20 --- /dev/null +++ b/emscripten/Makefile @@ -0,0 +1,19 @@ + +## you might want to change this path, if your vox binary isn't in $PATH +VOX = vox + +# do not touch below or dragons will trample your house +BSCRIPT = make.vx +SBUILD = $(VOX) $(BSCRIPT) + +all: + @$(SBUILD) + +rebuild: + @$(SBUILD) rebuild + +clean: + @$(SBUILD) clean + +dist-clean: clean + @$(SBUILD) dist-clean \ No newline at end of file diff --git a/emscripten/console.html b/emscripten/console.html new file mode 100644 index 0000000..76c4ea0 --- /dev/null +++ b/emscripten/console.html @@ -0,0 +1,78 @@ + + + + + + Emscripten-Generated Code + + + +
+
Downloading...
+ +
+
+
+ +
+ + + + diff --git a/emscripten/make.vx b/emscripten/make.vx new file mode 100644 index 0000000..716d72d --- /dev/null +++ b/emscripten/make.vx @@ -0,0 +1,125 @@ + +### base config for emscriptens clang wrapper +### note that the include flags are added later! +emxx = "em++" +ccflags = ["-Wall", "-Wextra", "-O2"] +outfile = "vox.js" + + +### core config +### don't touch, here be dragons +rootdir = ".." +thisdir = os.getenv("PWD") +srcdir = os.joinpath(rootdir, "src") +objdir = os.joinpath(thisdir, "objects") +dirs = [os.joinpath(srcdir, "core"), os.joinpath(srcdir, "frontend")] +exts = [".cpp"] +files = [] +objects = [] + +## populate ccflags with include flags +ccflags.extend([ + "-I"+os.joinpath(rootdir, "include"), + "-I"+os.joinpath(srcdir, "frontend") +]) + +### populate files array +dirs.map(function(dir) os.listdir(dir).map(function(file) +{ + exts.map(function(ext) + { + if(file.endswith(ext)) + files.append(file) + }) +})) + +# a really silly function that behaves like execve(), by +# escaping arguments using .quote() +function shellcmd(exe, arguments, just_print=false) +{ + assert(typeof exe == "string") + local scmd = exe + arguments.map(function(arg) scmd += " " + arg.quote()) + if(just_print) + { + println(scmd) + return + } + local status = os.system(scmd) + if(status == -1) + { + throw ("executing command '%s' failed with status %d".fmt(exe, status)) + } +} + + + +function rmfiles(files) +{ + println("+ [EMS:STEP] removing ...") + files.map(function(path) + { + println("- [RM] %s".fmt(path)) + os.remove(path) + }) +} + +function build_object(sourcepath, outpath, basename, rebuild) +{ + local args = clone ccflags + args.extend([sourcepath, "-o", outpath]) + print("- [EMS:BUILD] %s ... ".fmt(basename)); io.stdout.flush() + if(os.exists(outpath) && !rebuild) + { + print("skipped (exists)") + } + else + { + shellcmd(emxx, args) + } + println() +} + +function main() +{ + local rebuild = system.argv.find("rebuild") + local clean = system.argv.find("clean") + local distclean = system.argv.find("dist-clean") + + if(clean || distclean) + { + local allfiles = [] + os.listdir(objdir).map(function(file) allfiles.append(file)) + if(distclean) + { + os.exists(outfile) && allfiles.append(outfile) + } + rmfiles(allfiles) + return + } + + ## create object directory + !os.isdir(objdir) && os.mkdir(objdir, 0775) + + ## now build the objects! + println("+ [EMS:STEP] building objects ... ") + foreach(file in files) + { + local relpath = os.joinpath(objdir, os.basename(file) + ".bc") + local basename = os.basename(relpath) + build_object(file, relpath, basename, rebuild) + } + + ## and now, build vox.js + println("+ [EMS:STEP] building javascript library ... ") + if(os.exists(outfile) && !rebuild) + { + println("- outfile ('%s') already exists, skipping!".fmt(outfile)) + return + } + args = ["-o", outfile] + args.extend(os.listdir(objdir)) + shellcmd(emxx, args) +} + +main() \ No newline at end of file diff --git a/etc/makefile b/etc/makefile new file mode 100644 index 0000000..38520cf --- /dev/null +++ b/etc/makefile @@ -0,0 +1,34 @@ + +VOX_HOME = .. +EXE = min +OBJ = minimal.o + +## +CXX = clang++ -g3 -ggdb +CC = gcc +RM = rm +CFLAGS = -I$(VOX_HOME)/include +LFLAGS = -L$(VOX_HOME)/build -lvox -Wl,-rpath=$(VOX_HOME)/build + +all: $(EXE) + +$(EXE): $(OBJ) + $(CXX) $? -o $@ $(LFLAGS) + +$(OBJ): $(SRC) + +clean: + $(RM) -f $(OBJ) + +dist-clean: clean + $(RM) -f $(EXE) + +rebuild: dist-clean all + +%.o: %.cpp + $(CXX) -c $(CFLAGS) $? + +%.o: %.c + $(CXX) -c $(CFLAGS) $? + + diff --git a/etc/min b/etc/min new file mode 100755 index 0000000000000000000000000000000000000000..019b78ddb09165828ceea615bf9eac2cd86ddd9a GIT binary patch literal 70357 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 LvpI-aG(i3@p5s*= literal 0 HcwPel00001 diff --git a/etc/minimal.cpp b/etc/minimal.cpp new file mode 100644 index 0000000..41af44a --- /dev/null +++ b/etc/minimal.cpp @@ -0,0 +1,153 @@ + +/** +* This is the most minimal version of a standalone interpreter +* of Vox. +* This interpreter will not use the stdlib, so linking +* against libvox_stdlib is not necessary. +* Thus, the only element in the 'std' namespace will be 'system' and 'io', +* which contains implementation defined VM controlling routines. +* +* TODO: Write some actual documentation +*/ + +#include +#include +#include + + +/* here is a simple function callback, iterating through the arguments */ +VXInteger sandbox_func(VXState* v) +{ + VXInteger pos; + VXObject ob; + for(pos=2; pos!=v->GetTop()+1; pos++) + { + ob = v->StackGet(pos); + printf("Stack #%d = (%p) '%s'\n", pos, &ob, ob.TypeString()); + } + v->Push(v->NewString("hello from the 'hello' function!")); + return 1; +} + +/** +* Here is a simple class definition. +* +*/ + +struct SimpleClass +{ + bool havename; + std::string name; +}; + +// this is the release function for the class, called upon +// destruction of the VM +VXInteger scfn_releasehook(VXUserPointer p, VXInteger size) +{ + SimpleClass* self = (SimpleClass*)p; + printf("deleting SimpleClass!\n"); + delete self; + return 1; +} + +// this is the constructor for the class, where you might want to check for +// arguments passed to it. as with all native callbacks, the arguments stack +// begins at index 2. +VXInteger scfn_constructor(VXState* v) +{ + SimpleClass* self = new SimpleClass; + self->havename = false; + if(VX_SUCCEEDED(v->GetString(2, &(self->name)))) + { + self->havename = true; + } + v->SetInstanceUp(1, (VXUserPointer*)&self); + v->SetReleaseHook(1, scfn_releasehook); + // important: the return value of a class constructor is ignored! + return 0; +} + +VXInteger scfn_setname(VXState* v) +{ + std::string name; + SimpleClass* self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + if(VX_FAILED(v->GetString(2, &name))) + { + return v->ThrowError("[string] expected!"); + } + self->name = name; + self->havename = true; + return 0; +} + +VXInteger scfn_getname(VXState* v) +{ + std::string name; + SimpleClass* self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + if(self->havename) + { + v->Push(v->NewString(self->name.c_str(), self->name.length())); + return 1; + } + return v->ThrowError("name not set!"); +} + +static VXRegFunction scfn_funcs[]= +{ + {"constructor", scfn_constructor, -1, ".ss"}, + {"setname", scfn_setname, 2, ".s"}, + {"getname", scfn_getname, -1, NULL}, + {0, 0, 0, 0}, +}; + +/** +* +*/ + +bool getfile(int argc, char** argv, const char** filename) +{ + if(argc > 1) + { + (*filename) = argv[1]; + return true; + } + return false; +} + +void populate_argv(VXState* v, int argc, char** argv, VXInteger start) +{ + VXInteger i; + for(i=start; iGetSysArgv()->Append(v->NewString(argv[i])); + } +} + + +int main(int argc, char* argv[]) +{ + const char* filename; + const char* err_message; + VXState* vm = VXState::Create(1024); + if(getfile(argc, argv, &filename)) + { + /* DefineGlobal is just a shortened version of: + vm->GetRootTable()->NewSlot(vm->NewString("hello"), vm->NewClosure(sandbox_func)); + */ + vm->DefineGlobal("hello", vm->NewClosure(sandbox_func)); + vm->DefineGlobal("SimpleClass", vm->RegClass(scfn_funcs)); + populate_argv(vm, argc, argv, 1); + if(VX_FAILED(vm->DoFile(filename, false, true))) + { + printf("Eval('%s') failed: %s\n", filename, vm->LastError()); + } + } + else + { + printf("Usage: %s \n", argv[0]); + } + VXState::Destroy(vm); +} + diff --git a/etc/minimal.o b/etc/minimal.o new file mode 100644 index 0000000000000000000000000000000000000000..0aa10773bc27239cc6345fc127ec343543cdb5c8 GIT binary patch literal 65040 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 literal 0 HcwPel00001 diff --git a/etc/out.vx b/etc/out.vx new file mode 100644 index 0000000..43abcef --- /dev/null +++ b/etc/out.vx @@ -0,0 +1 @@ +[1, 2, 3, 4, "hello with \"subquotes and more \\\"subquotes!\\\"!\"", null, , , 5] diff --git a/etc/test.vx b/etc/test.vx new file mode 100644 index 0000000..e7853cf --- /dev/null +++ b/etc/test.vx @@ -0,0 +1,17 @@ + +/* +system.atexit(function() +{ + println("goodbye") +}) + +local t = [1, 2, 3, 4, "hello", null, function(){}, class {}, 5] +println(t.repr()) + +println("----------------") +*/ + +mc = SimpleClass() +mc.setname("John Doe") +assert(mc.getname() == "John Doe") +println("name = ", mc.getname()) \ No newline at end of file diff --git a/etc/tmp/all.cpp b/etc/tmp/all.cpp new file mode 100644 index 0000000..5a76794 --- /dev/null +++ b/etc/tmp/all.cpp @@ -0,0 +1,30 @@ +#include + +#include "../src/core/api.cpp" +#include "../src/core/array.cpp" +#include "../src/core/baselib_array.cpp" +#include "../src/core/baselib_class.cpp" +#include "../src/core/baselib_closure.cpp" +#include "../src/core/baselib.cpp" +#include "../src/core/baselib_generator.cpp" +#include "../src/core/baselib_hashlib.cpp" +#include "../src/core/baselib_io.cpp" +#include "../src/core/baselib_math.cpp" +#include "../src/core/baselib_string.cpp" +#include "../src/core/baselib_system.cpp" +#include "../src/core/baselib_table.cpp" +#include "../src/core/baselib_thread.cpp" +#include "../src/core/class.cpp" +#include "../src/core/compiler.cpp" +#include "../src/core/debug.cpp" +#include "../src/core/funcstate.cpp" +#include "../src/core/h_impl.cpp" +#include "../src/core/lexer.cpp" +#include "../src/core/mem.cpp" +#include "../src/core/object.cpp" +#include "../src/core/opcodes.cpp" +#include "../src/core/state.cpp" +#include "../src/core/string.cpp" +#include "../src/core/table.cpp" +#include "../src/core/vm.cpp" +#include "minimal.cpp" diff --git a/etc/tmp/custom_alloc.cpp b/etc/tmp/custom_alloc.cpp new file mode 100644 index 0000000..e69de29 diff --git a/examples/99_bottles_of_beer.vx b/examples/99_bottles_of_beer.vx new file mode 100644 index 0000000..efdacb3 --- /dev/null +++ b/examples/99_bottles_of_beer.vx @@ -0,0 +1,14 @@ + +// translated from + +local beer; +while((beer = typeof beer == "null" ? 99 : beer) > 0) + println( + beer + " bottle" + + (beer != 1 ? "s" : "") + + " of beer on the wall\n" + beer + " bottle" + + (beer != 1 ? "s" : "") + + " of beer\nTake one down, pass it around\n" + + (--beer) + " bottle" + + (beer != 1 ? "s" : "") + " of beer on the wall\n" + ); diff --git a/examples/ackermann.vx b/examples/ackermann.vx new file mode 100644 index 0000000..d6468fd --- /dev/null +++ b/examples/ackermann.vx @@ -0,0 +1,30 @@ + +function Ack(M, N) +{ + if(M == 0) + return N + 1 + if(N == 0) + return Ack(M - 1, 1) + return Ack(M - 1, Ack(M, (N - 1))) +} + + +local m = 3, n = 1 +if(system.argv.len() > 2) +{ + try + { + m = system.argv[1].tointeger(); + n = system.argv[2].tointeger() + if(n < 1) + n = 1; + } + catch(err) + { + io.stderr.write("Error = %s".fmt(err)) + } +} + +// first write the definition to stdout, then the result +print("Ack(M=%d, N=%d) = ".fmt(m, n)); io.stdout.flush(); println(Ack(m, n)) + diff --git a/examples/array.vx b/examples/array.vx new file mode 100644 index 0000000..b8ac6e9 --- /dev/null +++ b/examples/array.vx @@ -0,0 +1,24 @@ +/* +* +* Original Javascript version by David Hedbor(http://www.bagley.org/~doug/shootout/) +* +*/ + +n = (system.argv.len() > 1) ? system.argv[1].tointeger() : 1 +if(n < 1) n = 1 +x = [] +y = [] +for (i = 0; i < n; i+=1) +{ + x[i] = i + 1; + y[i] = 0; +} +for (k = 0 ; k < n; k+=1) +{ + for (i = n-1; i >= 0; i-=1) + { + y[i] = y[i]+ x[i]; + } +} +println(y[0].tostring() + " " + y[n-1]); + diff --git a/examples/bin2c.vx b/examples/bin2c.vx new file mode 100644 index 0000000..0839951 --- /dev/null +++ b/examples/bin2c.vx @@ -0,0 +1,151 @@ + + +class BinaryToRepr +{ + fieldname = "" + result = [] + space = " " + norawchars = false + + function isPrintable(char) + { + return false + } + + function mkPrintable(char) + { + local tmpresult + if(this.norawchars) + { + return "%04s".format("0x%04x".format(char.tointeger())) + } + else + { + tmpresult = char + if(this.isPrintable(char)) + { + return "'%s'".format(char) + } + else + { + tmpresult = "0x%.2x".format(char.tointeger()) + } + return "%04s".format(tmpresult) + } + } + + function processFile(filename) + { + this.processHandle(io.open(filename, "r"), true) + } + + function processHandle(handle, do_close=false) + { + local c + local rawdata = [] + while((c = handle.readchar()) != null) + { + rawdata.push(c) + } + if(do_close) handle.close() + this.processData(rawdata) + } + + function processData(rawdata) + { + local templine = [] + local idx = 0 + local strlen = 0 + local strlen = rawdata.len() + this.result.push( + "const char %s[%d] = {\n%s".format(this.fieldname, + strlen+1, + this.space)) + foreach(char in rawdata) + { + char = this.mkPrintable(char) + if(idx > 0) + { + if ((idx % 10) == 0) + { + this.result.push("\n%s".format(this.space)) + } + } + this.result.push("%s".format(char)) + if ((idx + 1) < strlen) + { + this.result.push(", ") + } + idx += 1 + } + this.result.push(", "); + this.result.push(this.mkPrintable('\0')); + this.result.push("\n};") + } + + function rawData() + { + local data = "" + foreach(itm in this.result) + { + data += itm + } + return data + } + + function setSpace(instr) + { + this.space = instr + } + + function setFieldName(instr) + { + this.fieldname = instr + } + + function constructor() + { + this.fieldname = "rawdata" + } +} + + +function main() +{ + bin2c = BinaryToRepr() + if(system.argv.len() > 1) + { + fieldname = system.argv[1] + filename = system.argv[2] + bin2c.setFieldName(fieldname) + if(filename == "-" || filename == "/dev/stdin") + { + io.stderr.write("** reading from stdin **\n") + bin2c.processHandle(io.stdin) + } + else + { + bin2c.processFile(filename) + } + if(vargv.len() > 3) + { + outfile := ARGV[3] + handle := io.open(outfile, "w") + handle.write(bin2c.rawData()) + handle.close() + } + else + { + print(bin2c.rawData()) + } + return 0 + } + else + { + println("Usage: bin2c.vx []") + return 1 + } +} + +main() + diff --git a/examples/class.vx b/examples/class.vx new file mode 100644 index 0000000..42beab8 --- /dev/null +++ b/examples/class.vx @@ -0,0 +1,49 @@ +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +class BaseVector { + constructor(...) + { + if(vargv.len() >= 3) { + x = vargv[0]; + y = vargv[1]; + z = vargv[2]; + } + } + + + x = 0; + y = 0; + z = 0; +} + +class Vector3 extends BaseVector { + function __add__(other) + { + if(other instanceof this.getclass()) + return ::Vector3(x+other.x,y+other.y,z+other.z); + else + throw "wrong parameter"; + } + function Print() + { + ::print(x+","+y+","+z+"\n"); + } +} + +local v0 = Vector3(1,2,3) +local v1 = Vector3(11,12,13) +local v2 = v0 + v1; +v2.Print(); + +FakeNamespace := { + Utils = {} +} + +class FakeNamespace.Utils.SuperClass { + constructor() + { + ::print("FakeNamespace.Utils.SuperClass") + } +} + +local testy = FakeNamespace.Utils.SuperClass(); diff --git a/examples/classattributes.vx b/examples/classattributes.vx new file mode 100644 index 0000000..758f99f --- /dev/null +++ b/examples/classattributes.vx @@ -0,0 +1,42 @@ + +class Foo +{ + //constructor + constructor(a) + { + testy = ["stuff",1,2,3]; + } + //attributes of PrintTesty + + function PrintTesty() + { + foreach(i,val in testy) + { + println("idx = ", i, " = ", val); + } + } + + //attributes of testy + + testy = null; + +} + +foreach(member,val in Foo) +{ + println(member); + local attr + if((attr = Foo.getattributes(member)) != null) + { + foreach(i, v in attr) + { + println("\t%s = <%s> %s".fmt(i.tostring(), typeof v, v.repr())) + } + } + else + { + println("\t") + } +} \ No newline at end of file diff --git a/examples/compiletpl.vx b/examples/compiletpl.vx new file mode 100644 index 0000000..811b5c8 --- /dev/null +++ b/examples/compiletpl.vx @@ -0,0 +1,10 @@ + +local template = import("core/template") +if(system.argv.len() > 1) +{ + println(template.compile_string(io.readfile(system.argv[1]))) +} +else +{ + println("Usage: %s ".fmt(system.argv[0])) +} \ No newline at end of file diff --git a/examples/config/sample.cfg b/examples/config/sample.cfg new file mode 100644 index 0000000..da21dca --- /dev/null +++ b/examples/config/sample.cfg @@ -0,0 +1,9 @@ + +[main] + introfile = $SYSPATH/files/static/intro.shl + +[plugins] + paths = $SYSPATH/plugins/extra, $SYSPATH/plugins/contrib, $SYSPATH/plugins/contrib + +[domains] +case_sensitive_domains = *imgur.com, *youtube.com, ebay.com diff --git a/examples/config/test.vx b/examples/config/test.vx new file mode 100644 index 0000000..acbd276 --- /dev/null +++ b/examples/config/test.vx @@ -0,0 +1,17 @@ + +local SimpleDB = import("core/simpledb") +local ConfigParser = import("core/config") + +cfg := ConfigParser() +cfg.parselists = true +cfg.parsevars = true +cfg.add_vars({ + SYSPATH = "/opt/some_company/some_product/system" +}) +cfg.parse_file("sample.cfg") + +println(cfg.tree().repr()) +println("-----------") +println(cfg.dump()) + + diff --git a/examples/coroutines.vx b/examples/coroutines.vx new file mode 100644 index 0000000..24d065a --- /dev/null +++ b/examples/coroutines.vx @@ -0,0 +1,24 @@ +function coroutine_test(a, b) +{ + println(a, " ", b); + local ret = system.suspend("suspend 1"); + println("the coroutine says ", ret); + ret = system.suspend("suspend 2"); + println("the coroutine says: ", ret); + ret = system.suspend("suspend 3"); + println("the coroutine says ", ret); + return "I'm done" +} + +local coro = system.newthread(coroutine_test); +local susparam = coro.call("test","coroutine"); //starts the coroutine + +local i = 1; +do +{ + println("suspend passed [", susparam, "]") + susparam = coro.wakeup("ciao "+i); + ++i; +}while(coro.getstatus()=="suspended") + +println("return passed [", susparam, "]") \ No newline at end of file diff --git a/examples/debug.vx b/examples/debug.vx new file mode 100644 index 0000000..511546d --- /dev/null +++ b/examples/debug.vx @@ -0,0 +1,67 @@ + +local sandbox = import("core/sandbox") + +local function begin_debug() +{ + system.enabledebuginfo(false) + system.setdebughook(function(type=null, src=null, line=null, funcname=null) + { + local action = "unknown" + local msg, pre, premsg, isposix = (system.platform_group() == "posix") + local mkc = function(light, code) + if(isposix) + return "\e[%d;%dm".fmt(light, code) + else + return "" + local colors = + { + red = mkc(0, 31) + blue = mkc(0, 34) + yellow = mkc(0, 33) + end = isposix ? "\e[0m" : "" + } + switch(type) + { + case 'r': + action = "returned from function %s".fmt(funcname.quote()); + break + case 'c': + action = "call to function %s".fmt(funcname.quote()) + break + case 'l': + action = "entering new line" + break + } + #if(type != '-') + #{ + pre = colors.red + "**debug**" + colors.end + premsg = pre + " in %s<%s:%d>%s: ".fmt(colors.blue, src, line, colors.end) + msg = premsg + colors.yellow + action + colors.end + "\n" + io.stderr.write(msg) + io.stderr.flush() + system.gc_collect() + #} + }) +} + +if(system.argv.len() > 1) +{ + begin_debug() + local new_argv = system.argv + local path = system.argv[1] + local sb, env = {} + new_argv.remove(1) + foreach(k, v in this) + { + env[k] := v + } + if(!env.get("system")) + env.system = {} + env.system.argv := new_argv + sb = sandbox(env) + sb.callfile(path) +} +else +{ + println("Usage: %s [args]".fmt(system.argv[0])) +} diff --git a/examples/delegation.vx b/examples/delegation.vx new file mode 100644 index 0000000..f275d0a --- /dev/null +++ b/examples/delegation.vx @@ -0,0 +1,54 @@ + +PEntity := { + name="noname" + pos={x=0,y=0,z=0} + type="entity" + //methamethod + _typeof=function() + { + return type; + } +} + +function PEntity::PrintPos() +{ + ::print("x="+pos.x+" y="+pos.y+" z="+pos.z+"\n"); +} + +function PEntity::new(name,pos) +{ + local newentity=clone ::PEntity; + if(name) + newentity.name=name; + if(pos) + newentity.pos=pos; + return newentity; +} + +PPlayer := { + model="warrior.mdl" + weapon="fist" + health=100 + armor=0 + //overrides the parent type + type="player" +} + +function PPlayer::new(name,pos) +{ + local p = clone ::PPlayer; + local newplayer = ::PEntity.new(name,pos); + newplayer.setdelegate(p); + return newplayer; +} + +local player=PPlayer.new("godzilla",{x=10,y=20,z=30}); + +::print("PLAYER NAME"+player.name+"\n"); +::print("ENTITY TYPE"+typeof player+"\n"); + +player.PrintPos(); + +player.pos.x=123; + +player.PrintPos(); \ No newline at end of file diff --git a/examples/doors.vx b/examples/doors.vx new file mode 100644 index 0000000..8b40aeb --- /dev/null +++ b/examples/doors.vx @@ -0,0 +1,17 @@ + +// Translation of the 100 Doors for Lua + +is_open := [] +is_open.resize(100) +for(door:=1; door!=100; door++) + is_open[door] = false +for(pass:=1;pass!=100;pass++) + for(door=pass; door<100; door+=pass) + is_open[door] = !is_open[door] +foreach(i, v in is_open) +{ + if(v) + println("Door #%d is open".fmt(i)) + else + println("Door #%d is closed".fmt(i)) +} diff --git a/examples/dow.vx b/examples/dow.vx new file mode 100644 index 0000000..4ffdf6b --- /dev/null +++ b/examples/dow.vx @@ -0,0 +1,31 @@ + +function datetoday(day, month, year) +{ + local z, dayofweek + if (month < 3) z = y-1 + else z = year + dayofweek = (23 * month / 9 + day + 4 + year + z / 4 - z / 100 + z / 400) + if(month >= 3) dayofweek -= 2 + dayofweek = dayofweek % 7 + return dayofweek +} + +local values, day, month, year, dow, months, days +months = [ + "january", "february", "march", + "april", "may", "june", "july", + "august", "september", "october", + "november", "december"] + +days = [ + "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday", "Sunday"] + + +print("Enter the date as 'dd mm yyyy' (without quotes): ") +values = io.stdin.readline().split(" ") +day = values[0].tointeger() +month = values[1].tointeger() +year = values[2].tointeger() +dow = days[datetoday(day, month, year) - 1] +println("The %d' of %s, %d is a %s".fmt(day, months[month-1], year, dow)) diff --git a/examples/fibonacci.vx b/examples/fibonacci.vx new file mode 100644 index 0000000..31c48d3 --- /dev/null +++ b/examples/fibonacci.vx @@ -0,0 +1,23 @@ + + + + +local n = system.argv.len() > 1 ? system.argv[1].tointeger() : 4 + +println("fib(%d) = %d".fmt(n, function(value) +{ + local last_value = 0; + local this_value = 1; + local new_value, count; + if (value < 2) + { + return value; + } + for (count=1; county?x:y; + +if(min(100,200)>max(50,20)) + print("I'm useless statement just to show up the if/else\n"); +else + print("squirrel!!\n"); + +print("\n") + +function typy(obj) +{ + switch(typeof obj) + { + case "integer": + case "float": + return "is a number"; + case "table": + case "array": + return "is a container"; + default: + return "is other stuff" + } +} + +local a=1,b={},c=function(a,b){return a+b;} + +print("a "+typy(a)+"\n"); +print("b "+typy(b)+"\n"); +print("c "+typy(c)+"\n"); \ No newline at end of file diff --git a/examples/generators.vx b/examples/generators.vx new file mode 100644 index 0000000..acacfad --- /dev/null +++ b/examples/generators.vx @@ -0,0 +1,42 @@ +/* +*Random number function from The Great Computer Language shootout +*converted to a generator func +*/ + +function gen_random(max) { + local last=42 + local IM = 139968; + local IA = 3877; + local IC = 29573; + for(;;){ //loops forever + yield (max * (last = (last * IA + IC) % IM) / IM); + } +} + +local randtor=gen_random(100); + +print("RAND NUMBERS \n") + +for(local i=0;i<10;i+=1) + print(">"+resume randtor+"\n"); + +print("FIBONACCI \n") +function fiboz(n) +{ + local prev=0; + local curr=1; + yield 1; + + for(local i=0;i"+val+"\n"); +} \ No newline at end of file diff --git a/examples/hello.vx b/examples/hello.vx new file mode 100644 index 0000000..209154e --- /dev/null +++ b/examples/hello.vx @@ -0,0 +1,3 @@ + +println("Hello World!") + diff --git a/examples/hello_extended.vx b/examples/hello_extended.vx new file mode 100644 index 0000000..2eda207 --- /dev/null +++ b/examples/hello_extended.vx @@ -0,0 +1,64 @@ + +/* inspired by */ + +local amount = 220 +local answer = 42 + +local chartable = [ + 2, 6, 2, 2, 10, 2, 2, 10, + 2, 10, 10, -1, 2, 6, 2, 2, + 2, 10, 2, 10, 2, 10, 2, 6, + 2, -1, 2, 6, 2, 2, 2, 10, 2, + 10, 2, 10, 2, 6, 2, -1, 10, + 2, 10, 2, 2, 10, 2, 10, 2, 6, + 2, -1, 2, 6, 2, 2, 2, 10, 2, + 10, 2, 10, 2, 6, 2, -1, 2, 6, + 2, 2, 2, 10, 2, 10, 2, 10, 2, + 6, 2, -1, 2, 6, 2, 2, 10, 2, + 10, 2, 10, 2, 10, -1, 0, -1, + 2, 3, 2, 5, 2, 2, 2, 2, 10, 2, + 10, 2, 2, 10, 2, 1, 4, -1, 0, + 1, 2, 3, 2, 3, 2, 2, 2, 3, 2, 6, + 2, 2, 2, 6, 2, 2, 2, 10, 2, 5, + 2, -1, 0, 2, 2, 3, 2, 1, 2, 2, 2, + 4, 2, 6, 2, 2, 2, 6, 2, 2, 2, 10, + 2, 5, 2, -1, 0, 3, 2, 3, 2, 3, 2, + 5, 2, 6, 2, 2, 2, 2, 2, 6, 2, 10, + 2, 5, 2, -1, 0, 4, 2, 1, 4, 1, 2, + 6, 2, 6, 2, 2, 2, 4, 2, 4, 2, 10, + 2, 5, 2, -1, 0, 5, 2, 4, 2, 7, 10, + 2, 2, 6, 2, 2, 10, 2, 9, -1 +] + +function emit_char(c) +{ + print(c.tochar()) +} + +function emit_newline() +{ + emit_char('\n') +} + +function say_hello_world() +{ + local i + local j + for(i=0; i 0 && buffer[i-1] == '\\') + { + buffer[i-1] = '\n'.tochar(); + } + else if(blocks == 0) + { + break; + } + else + { + print(".. ") + } + buffer[i++] = '\n'.tochar(); + } + else if (c == '}') + { + blocks--; + buffer[i++] = c.tochar(); + #print(".. ") + } + else if(c == '{' && !isstring) + { + blocks++; + buffer[i++] = c.tochar(); + #print(".. ") + } + else if(c == '"' || c == '\'') + { + isstring = !isstring; + buffer[i++] = c.tochar(); + } + else if (i >= (maxinput-1)) + { + io.stderr.write(" input line too long\n"); + os.exit(-1); + break; + } + else + { + buffer[i++] = c.tochar(); + } + } + } + evalbuf = "return (%s)".format(buffer.join("")) + try + { + system.loadstring(evalbuf) + retval = true + } + catch(err) + { + retval = false + evalbuf = buffer.join("") + } + if(i > 0) + { + local returned = function() + { + try + { + return system.dostring(evalbuf) + } + catch(err) + { + system.errorhandler(err) + } + }() + if(retval && returned != null) + { + println(system.serialize(returned)) + } + io.stdout.flush() + evalbuf = null + buffer = [] + retval = false + } + } +} + +enter_interactive() + diff --git a/examples/lint.vx b/examples/lint.vx new file mode 100644 index 0000000..c9f7f90 --- /dev/null +++ b/examples/lint.vx @@ -0,0 +1,31 @@ + +sandbox := import("core/sandbox") + +if(system.argv.len() > 1) +{ + local file = system.argv[1] + local nargv = system.argv + nargv.remove(1) + local env = + { + "println": println, + "print": print, + "io": io, + "math": math, + "system": {"argv": nargv}, + } + try + { + local fn = system.loadfile(file) + local sb = sandbox(env) + sb.call(fn) + } + catch(err) + { + println("Cannot evaluate %s: %s".fmt(file.quote(), err)) + } +} +else +{ + println("usage: %s [, ...]".fmt(system.argv[0])) +} \ No newline at end of file diff --git a/examples/list.vx b/examples/list.vx new file mode 100644 index 0000000..df6e02e --- /dev/null +++ b/examples/list.vx @@ -0,0 +1,40 @@ +/*translation of the list test from The Great Computer Language Shootout +*/ + +function compare_arr(a1,a2) +{ + foreach(i,val in a1) + if(val!=a2[i])return null; + return 1; +} + +function test() +{ + local size=10000 + local l1=[]; l1.resize(size); + for(local i=0;i0) + l3.append(l2.pop()); + while(l3.len()>0) + l2.append(l3.pop()); + l1.reverse(); + + if(compare_arr(l1,l2)) + return l1.len(); + return null; +} + +local n = vargv.len()!=0?vargv[0].tointeger():1 +for(local i=0;i"); +else + println(""); diff --git a/examples/methcall.vx b/examples/methcall.vx new file mode 100644 index 0000000..0939cb5 --- /dev/null +++ b/examples/methcall.vx @@ -0,0 +1,75 @@ +/*translation of the methcall test from The Great Computer Language Shootout +*/ + +class Toggle +{ + bool=null + + function constructor(startstate) + { + bool = startstate + } + + function value() + { + return bool; + } + + function activate() + { + bool = !bool; + return this; + } +} + + +class NthToggle extends Toggle +{ + count_max=null + count=0 + + function constructor(start_state,max_counter) + { + base.constructor(start_state); + count_max = max_counter + } + + function activate () + { + count++; + if (count >= count_max ) + { + base.activate() + count = 0 + } + return this; + } +} + + + + +function main() +{ + local n = system.argv.len() > 1 ? system.argv[1].tointeger() : 1 + local val = 1; + local toggle = Toggle(val); + local i = n; + while(i--) + { + val = toggle.activate().value(); + } + println(toggle.value() ? "true" : "false"); + val = 1; + local ntoggle = NthToggle(val, 3); + i = n; + while(i--) + { + val = ntoggle.activate().value(); + } + println(ntoggle.value() ? "true" : "false"); + +} +local start=os.clock(); +main(); +println("TIME = %f".fmt(os.clock()-start)); diff --git a/examples/no_commas.vx b/examples/no_commas.vx new file mode 100644 index 0000000..e69de29 diff --git a/examples/prototypes.vx b/examples/prototypes.vx new file mode 100644 index 0000000..ddb647c --- /dev/null +++ b/examples/prototypes.vx @@ -0,0 +1,24 @@ + +class Foo +{ + name = null + constructor(_name) + { + this.name = _name + } +} + +Foo.print_name := function() +{ + println("this.name = ", this.name) +} + +Foo.set_name := function(newname) +{ + this.name = newname +} + +f := Foo("world") +f.print_name() +f.set_name("Buddha") +f.print_name() diff --git a/examples/readfile_extended.vx b/examples/readfile_extended.vx new file mode 100644 index 0000000..3600231 --- /dev/null +++ b/examples/readfile_extended.vx @@ -0,0 +1,12 @@ + + +handle := io.open("/etc/passwd", "r") +buf := "" +while((c := handle.readchar()) != null) +{ + buf += c.tochar(); +} +handle.close() +println(buf) + + diff --git a/examples/regex.vx b/examples/regex.vx new file mode 100644 index 0000000..654d4e8 --- /dev/null +++ b/examples/regex.vx @@ -0,0 +1,17 @@ + +local str = "some-file-with-dashes-in-it.tar.gz" +local rex = regexp.compile(@"^(?P.+?)\.(?P.*?)$") + +println("match: ", rex.match(str).repr()) +println("filename: ", rex.group(str, "filename")) +println("extension: ", rex.group(str, "extension")) + +foreach(i, pair in rex.findall(str)) +{ + mt := pair.string; + println("Matched string: ", mt) + foreach(i, substr in pair.submatches) + { + println(" [", i, "] = ", substr) + } +} diff --git a/examples/spellnumber.vx b/examples/spellnumber.vx new file mode 100644 index 0000000..792c55f --- /dev/null +++ b/examples/spellnumber.vx @@ -0,0 +1,84 @@ + + + +local function spellnumber(n) +{ + local smallnumbers = [ + "zero", "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "ten", + "eleven", "twelve", "thirteen", "fourteen", "fifteen", + "sixteen", "seventeen", "eighteen", "nineteen" + ] + local thousandpowers = [ + " billion", " million", " thousand", "" + ] + local decades = [ + "", "", "twenty", "thirty", "forty", + "fifty", "sixty", "seventy", "eighty", "ninety" + ] + local res = ""; + local pScaleName = thousandpowers; + local scaleFactor = 1000000000; // 1 billion + local count = 0; + local function spellhundreds(n) + { + local res = ""; + if (n > 99) + { + res = smallnumbers[n/100]; + res += " hundred"; + n %= 100; + if(n) + { + res += " and "; + } + } + if (n >= 20) + { + res += decades[n/10]; + n %= 10; + if(n) + { + res += "-"; + } + } + if (n < 20 && n > 0) + { + res += smallnumbers[n]; + } + return res; + } + if (n < 20) + { + return smallnumbers[n]; + } + while (scaleFactor > 0) + { + if (n >= scaleFactor) + { + local h = n / scaleFactor; + res += spellhundreds(h) + (pScaleName[count]); + n %= scaleFactor; + if(n) + { + res += ", "; + } + } + scaleFactor /= 1000; + count++; + } + return res; +} + +/* example output: +spellnumber(691677947) = six hundred and ninety-one million, six hundred and seventy-seven thousand, nine hundred and forty-seven +*/ +if(system.argv.len() > 1) +{ + val = system.argv[1].tointeger() + println("spellnumber(%d) = %s".fmt(val, spellnumber(val))) +} +else +{ + println("Usage: %s ".fmt(system.argv[0])) +} diff --git a/examples/substr.vx b/examples/substr.vx new file mode 100644 index 0000000..1ad6771 --- /dev/null +++ b/examples/substr.vx @@ -0,0 +1,10 @@ + +local str, str2, str3, result +local pos +str = "We think in generalities, but we live in details." +str2 = str.substr(12, 12) +pos = str.indexof("live") +str3 = str.substr(pos) +result = str2 + " " + str3 +println("result: ", result) +assert(result == "generalities live in details.") diff --git a/examples/syntax-abuse.vx b/examples/syntax-abuse.vx new file mode 100644 index 0000000..3990f31 --- /dev/null +++ b/examples/syntax-abuse.vx @@ -0,0 +1,26 @@ + +/* + Just showing off the madness that is technically possible in Vox. + Please don't actually write programs that way though, please :-) +*/ + +foreach(i, line in + function(path, mode) + { + h = (class extends io.open + { + constructor(path, mode) + { + base.constructor(path, mode) + } + })(path, mode) + while((line = h.readline())) + { + yield line + } + }(system.argv.len() > 1 ? + system.argv[1] : + println("usage: %s ".fmt(system.argv[0])), "r") && os.exit()) +{ + println("#%03d: %s".fmt(i, line)) +} diff --git a/examples/tailstate.vx b/examples/tailstate.vx new file mode 100644 index 0000000..b888305 --- /dev/null +++ b/examples/tailstate.vx @@ -0,0 +1,26 @@ +function state1() +{ + system.suspend("state1"); + return state2(); +} + +function state2() +{ + system.suspend("state2"); + return state3(); +} + +function state3() +{ + system.suspend("state3"); + return state1(); +} + +local statethread = system.newthread(state1) + +println(statethread.call()); + +for(local i = 0; i < 10; i++) +{ + println(statethread.wakeup()); +} \ No newline at end of file diff --git a/examples/walk.vx b/examples/walk.vx new file mode 100644 index 0000000..9dc973a --- /dev/null +++ b/examples/walk.vx @@ -0,0 +1,29 @@ + +function walk(dir, cb) +{ + try + { + local files = os.listdir(dir) + foreach(path in files) + { + local fullpath = dir + "/" + path + local st = os.stat(fullpath) + cb(st.is_dir ? fullpath : dir, path, fullpath, st.is_dir, st) + if(st.is_dir) + { + walk(fullpath, cb) + } + } + } + catch(err) + {} +} + +walk(".", function(dir, path, fullpath, isdir, stat) +{ + if(isdir) + { + println("dir %s:".fmt(dir.quote())) + } + println(" ", path) +}) diff --git a/examples/ycombinator.vx b/examples/ycombinator.vx new file mode 100644 index 0000000..6853619 --- /dev/null +++ b/examples/ycombinator.vx @@ -0,0 +1,25 @@ + +/* code 'borrowed' from the spidermonkey distribution (thanks!) */ + +function factorial(proc) +{ + return function (n) + { + return (n <= 1) ? 1 : n * proc(n-1); + } +} + +function Y(outer) +{ + function inner(proc) + { + function apply(arg) + { + return proc(proc)(arg); + } + return outer(apply); + } + return inner(inner); +} + +println("5! is " + Y(factorial)(5)); diff --git a/include/vox.h b/include/vox.h new file mode 100644 index 0000000..020249a --- /dev/null +++ b/include/vox.h @@ -0,0 +1,1485 @@ +/* +Copyright (c) 2003-2011 Alberto Demichelis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef _VOX_H_ +#define _VOX_H_ + +#include +#include +#include + + +/* version and signature information */ +#define VOX_VERSION "Vox 1.8.0 experimental" +#define VOX_VERSION_NUMBER 180 +#define VOX_COPYRIGHT "Copyright (C) 2003-2011 Beelzebub Software" +#define VOX_AUTHOR "Beelzebub Software" + +/* platform information */ +#if defined(__x86_64__) || defined(__ppc64__) || defined(_WIN64) +# define VOX_PLATFORM_BITS 64 +# define VOX_PLATFORM_BITS_NAME "64" +#else +# define VOX_PLATFORM_BITS 32 +# define VOX_PLATFORM_BITS_NAME "32" +#endif + +/* first the rough check (namely posix) ... */ + +#if defined(__unix__) +# include +#endif + +/* now check for details ... */ +#if defined(WIN32) || defined(_WIN32) || defined(_WIN64) +# define VOX_PLATFORM_MSWINDOWS +# define VOX_PLATFORM_UNTESTED 0 +# define VOX_PLATFORM_NAME "win" VOX_PLATFORM_BITS_NAME +# define VOX_PLATFORM_GROUP_NAME "nt" +#elif defined(linux) || defined(__linux__) +# define VOX_PLATFORM_UNIX +# define VOX_PLATFORM_LINUX 1 +# define VOX_PLATFORM_UNTESTED 0 +# define VOX_PLATFORM_NAME "linux" VOX_PLATFORM_BITS_NAME +#elif defined(unix) || defined(__unix__) +/* TODO: differentiate between *BSD, MacOSX, etc */ +# define VOX_PLATFORM_UNIX +# define VOX_PLATFORM_UNTESTED 1 +# define VOX_PLATFORM_NAME "unix" VOX_PLATFORM_BITS_NAME +#else +# ifdef VOX_IGNORE_UNKNOWN_PLATFORM +# define VOX_PLATFORM_UNKNOWN +# define VOX_PLATFORM_UNTESTED 1 +# define VOX_PLATFORM_NAME "unknown" VOX_PLATFORM_BITS_NAME +# define VOX_PLATFORM_GROUP_NAME "unknown" +# else +# if !defined(SWIG) +# error "Unknown platform! Define 'VOX_IGNORE_UNKNOWN_PLATFORM' to compile anyway" +# endif +# endif +#endif + +/* we deliberately skipped defining VOX_PLATFORM_GROUP_NAME on + platforms that may define '_POSIX_VERSION'. + The idea is to overwrite the platform_group for platforms + that support posix, as defined by the posix standard. */ +#if defined(_POSIX_VERSION) +# if defined(VOX_PLATFORM_GROUP_NAME) +# undef VOX_PLATFORM_GROUP_NAME +# endif +# define VOX_PLATFORM_GROUP_NAME "posix" +#endif + +/* if at this point VOX_PLATFORM_GROUP_NAME is still + undefined, just give it a default value */ +#if !defined(VOX_PLATFORM_GROUP_NAME) +# define VOX_PLATFORM_GROUP_NAME "unknown" +#endif + +/* stdlib partly depends on boost */ +#if defined(VOX_STDLIB_AVAILABLE) +# undef VOX_STDLIB_AVAILABLE +#endif +#ifdef VOX_HAVEBOOST +# define VOX_STDLIB_AVAILABLE 1 +#endif + + + +#define vox_assert(expr) \ + do \ + { \ + if(bool(expr) == 0) \ + { \ + vox_aux_asserthandler(\ + #expr, \ + __FUNCTION__, \ + __FILE__, \ + __LINE__); \ + } \ + } while(0); + +#define VX_MALLOC(__size) \ + vox_mem_malloc((__size)); + +#define VX_FREE(__ptr,__size) \ + vox_mem_free((__ptr), (__size)); + +#define VX_REALLOC(__ptr,__oldsize,__size) \ + vox_mem_realloc((__ptr),(__oldsize),(__size)); + +/* sanity macros to check errorcodes (see return codes for native closures) */ +#define VX_FAILED(res) ((res) == VX_ERROR) +#define VX_SUCCEEDED(res) (!VX_FAILED(res)) + +/* return codes for native closures */ +#define VX_OK (0) +#define VX_ERROR (-1) + +/* declaration for extern definitions */ +#define VOX_API extern + +typedef long VXLongInteger; +typedef int VXInteger; +typedef int VXInt32; +typedef unsigned int VXUnsignedInteger32; +typedef unsigned int VXUnsignedInteger; +typedef unsigned int VXHash; +typedef float VXFloat; +typedef int VXChar; +typedef long VXRawValue; +typedef void* VXUserPointer; + + +void* vox_mem_malloc(VXUnsignedInteger size); +void* vox_mem_realloc(void* p, VXUnsignedInteger oldsize,VXUnsignedInteger size); +void vox_mem_free(void *p,VXUnsignedInteger size); + +struct VXState; +struct VXInstruction; +struct VXWeakRefObj; +struct VXClassObj; +struct VXTableObj; +struct VXArrayObj; +struct VXStringObj; +struct VXForeignClosureObj; +struct VXGeneratorObj; +struct VXNativeClosureObj; +struct VXUserDataObj; +struct VXFuncProtoObj; +struct VXRefCountedObj; +struct VXClassObj; +struct VXInstanceObj; +struct VXDelegableObj; +struct VXOuterObj; +struct VXObject; +struct VXSharedState; + + +typedef VXInteger (*VXFunction)(VXState*); + +typedef VXInteger (*VXReleaseHook)(VXUserPointer,VXInteger size); + +typedef void (*VXCompileError)(VXState* /* v */, + const char* /* desc */, + const char* /* source */, + VXInteger /* line */, + VXInteger /* column */); + +typedef void (*VXPrintFunction)(VXState*, + const char * ,...); + + + +typedef VXInteger (*VXWriteFunc)(VXUserPointer, + VXUserPointer, + VXInteger); + +typedef VXInteger(*VXReadFunc)(VXUserPointer, + VXUserPointer, + VXInteger); + +typedef VXInteger(*VXPrintFunc)( + VXState* v, + bool isend, + const char* str, + VXInteger len); + +typedef VXInteger(*VXLexReadFunc)(VXUserPointer); + +struct VXRegFunction +{ + const char *name; + VXFunction func; + VXInteger nparamscheck; + const char *typemask; +}; + +struct VXFunctionInfo +{ + VXUserPointer funcid; + const char *name; + const char *source; +}; + +/* vxobject type masks */ +enum +{ + VX_RT_MASK = 0x00FFFFFF, + VX_RT_NULL = 0x00000001, + VX_RT_INTEGER = 0x00000002, + VX_RT_FLOAT = 0x00000004, + VX_RT_BOOL = 0x00000008, + VX_RT_STRING = 0x00000010, + VX_RT_TABLE = 0x00000020, + VX_RT_ARRAY = 0x00000040, + VX_RT_USERDATA = 0x00000080, + VX_RT_CLOSURE = 0x00000100, + VX_RT_NATIVECLOSURE = 0x00000200, + VX_RT_GENERATOR = 0x00000400, + VX_RT_USERPOINTER = 0x00000800, + VX_RT_THREAD = 0x00001000, + VX_RT_FUNCPROTO = 0x00002000, + VX_RT_CLASS = 0x00004000, + VX_RT_INSTANCE = 0x00008000, + VX_RT_WEAKREF = 0x00010000, + VX_RT_OUTER = 0x00020000 +}; + +/* object type constants */ +enum +{ + VXOBJECT_REF_COUNTED = 0x08000000, + VXOBJECT_NUMERIC = 0x04000000, + VXOBJECT_DELEGABLE = 0x02000000, + VXOBJECT_CANBEFALSE = 0x01000000 +}; + +enum VXMetaMethod +{ + VX_MT_ADD = 0, + VX_MT_SUB = 1, + VX_MT_MUL = 2, + VX_MT_DIV = 3, + VX_MT_UNM = 4, + VX_MT_MODULO = 5, + VX_MT_SET = 6, + VX_MT_GET = 7, + VX_MT_TYPEOF = 8, + VX_MT_NEXTI = 9, + VX_MT_CMP = 10, + VX_MT_CALL = 11, + VX_MT_CLONED = 12, + VX_MT_NEWSLOT = 13, + VX_MT_DELSLOT = 14, + VX_MT_TOSTRING = 15, + VX_MT_NEWMEMBER = 16, + VX_MT_INHERITED = 17, + VX_MT_LAST = 18 +}; + +enum VXOType +{ + VX_OT_NULL = + (VX_RT_NULL | VXOBJECT_CANBEFALSE), + VX_OT_INTEGER = + (VX_RT_INTEGER | VXOBJECT_NUMERIC | VXOBJECT_CANBEFALSE), + VX_OT_FLOAT = + (VX_RT_FLOAT | VXOBJECT_NUMERIC | VXOBJECT_CANBEFALSE), + VX_OT_BOOL = + (VX_RT_BOOL | VXOBJECT_CANBEFALSE), + VX_OT_STRING = + (VX_RT_STRING | VXOBJECT_REF_COUNTED), + VX_OT_TABLE = + (VX_RT_TABLE | VXOBJECT_REF_COUNTED | VXOBJECT_DELEGABLE), + VX_OT_ARRAY = + (VX_RT_ARRAY | VXOBJECT_REF_COUNTED), + VX_OT_USERDATA = + (VX_RT_USERDATA | VXOBJECT_REF_COUNTED | VXOBJECT_DELEGABLE), + VX_OT_CLOSURE = + (VX_RT_CLOSURE | VXOBJECT_REF_COUNTED), + VX_OT_NATIVECLOSURE = + (VX_RT_NATIVECLOSURE | VXOBJECT_REF_COUNTED), + VX_OT_GENERATOR = + (VX_RT_GENERATOR | VXOBJECT_REF_COUNTED), + VX_OT_USERPOINTER = + (VX_RT_USERPOINTER), + VX_OT_THREAD = + (VX_RT_THREAD | VXOBJECT_REF_COUNTED), + VX_OT_FUNCPROTO = + (VX_RT_FUNCPROTO | VXOBJECT_REF_COUNTED), + VX_OT_CLASS = + (VX_RT_CLASS | VXOBJECT_REF_COUNTED), + VX_OT_INSTANCE = + (VX_RT_INSTANCE | VXOBJECT_REF_COUNTED | VXOBJECT_DELEGABLE), + VX_OT_WEAKREF = + (VX_RT_WEAKREF | VXOBJECT_REF_COUNTED), + VX_OT_OUTER = + (VX_RT_OUTER | VXOBJECT_REF_COUNTED) +}; + +template class VXVector +{ + private: // variables + VXUnsignedInteger _size; + VXUnsignedInteger _allocated; + Type* _vals; + + private: // functions + void _do_realloc(VXUnsignedInteger newsize) + { + newsize = (newsize > 0) ? newsize : 4; + _vals = (Type*)VX_REALLOC(_vals, + _allocated * sizeof(Type), + newsize * sizeof(Type)); + _allocated = newsize; + } + + + public: // functions + VXVector() + { + _vals = NULL; + _size = 0; + _allocated = 0; + } + + VXVector(const VXVector& v) + { + copy(v); + } + + ~VXVector() + { + if(_allocated) + { + for(VXUnsignedInteger i = 0; i < _size; i++) + { + _vals[i].~Type(); + } + VX_FREE(_vals, (_allocated * sizeof(Type))); + } + } + + void copy(const VXVector& v) + { + if(_size) + { + //destroys all previous stuff + resize(0); + } + if(v._size > _allocated) + { + this->_do_realloc(v._size); + } + for(VXUnsignedInteger i = 0; i < v._size; i++) + { + new ((void *)&_vals[i]) Type(v._vals[i]); + } + _size = v._size; + } + + void clear() + { + resize(0); + } + + void reserve(VXUnsignedInteger newsize) + { + this->_do_realloc(newsize); + } + + void resize(VXUnsignedInteger newsize, const Type& fill = Type()) + { + if(newsize > _allocated) + { + this->_do_realloc(newsize); + } + if(newsize > _size) + { + while(_size < newsize) + { + new ((void *)&_vals[_size]) Type(fill); + _size++; + } + } + else + { + for(VXUnsignedInteger i = newsize; i < _size; i++) + { + _vals[i].~Type(); + } + _size = newsize; + } + } + + void shrinktofit() + { + if(_size > 4) + { + this->_do_realloc(_size); + } + } + + Type& top() const + { + return _vals[_size - 1]; + } + + inline VXUnsignedInteger size() const + { + return _size; + } + + bool empty() const + { + return (_size <= 0); + } + + inline Type &push_back(const Type& val = Type()) + { + if(_allocated <= _size) + { + this->_do_realloc(_size * 2); + } + return *(new ((void *)&_vals[_size++]) Type(val)); + } + + inline void pop_back() + { + _size--; _vals[_size].~Type(); + } + + void insert(VXUnsignedInteger idx, const Type& val) + { + resize(_size + 1); + for(VXUnsignedInteger i = _size - 1; i > idx; i--) + { + _vals[i] = _vals[i - 1]; + } + _vals[idx] = val; + } + + void remove(VXUnsignedInteger idx) + { + _vals[idx].~Type(); + if(idx < (_size - 1)) + { + memcpy(&_vals[idx], &_vals[idx+1], sizeof(Type) * (_size - idx - 1)); + } + _size--; + } + + VXUnsignedInteger capacity() + { + return _allocated; + } + + inline Type &back() const + { + return _vals[_size - 1]; + } + + inline Type& operator[](VXUnsignedInteger pos) const + { + return _vals[pos]; + } + + inline Type& at(VXUnsignedInteger pos) const + { + return _vals[pos]; + } + + inline Type* values() + { + return this->_vals; + } +}; + + +struct VXExceptionTrap +{ + VXExceptionTrap() + { + } + + VXExceptionTrap(VXInteger ss, VXInteger stackbase,VXInstruction *ip, VXInteger ex_target) + { + _stacksize = ss; + _stackbase = stackbase; + _ip = ip; + _extarget = ex_target; + } + + VXExceptionTrap(const VXExceptionTrap &et) + { + (*this) = et; + } + + VXInteger _stackbase; + VXInteger _stacksize; + VXInstruction *_ip; + VXInteger _extarget; +}; + + +typedef VXVector ExceptionsTraps; + + +struct VXRawObj +{ + union Value + { + VXTableObj* pTable; + VXArrayObj* pArray; + VXForeignClosureObj *pClosure; + VXNativeClosureObj *pNativeClosure; + VXStringObj *pString; + VXWeakRefObj *pWeakRef; + VXClassObj *pClass; + + VXFuncProtoObj *pFunctionProto; + VXUserDataObj *pUserData; + VXRefCountedObj *pRefCounted; + VXDelegableObj *pDelegable; + VXState *pThread; + VXInstanceObj *pInstance; + VXOuterObj *pOuter; + VXGeneratorObj *pGenerator; + VXRawValue raw; + VXInteger nInteger; + VXFloat fFloat; + VXUserPointer pUserPointer; + }; + + inline VXOType Type() const + { + return _type; + } + + VXOType _type; + Value _unVal; +}; + +struct VXObject: public VXRawObj +{ + VXObject(); + VXObject(const VXObject &o); + VXObject(const VXRawObj &o); + VXObject(VXTableObj * x); + VXObject(VXClassObj * x); + VXObject(VXInstanceObj * x); + VXObject(VXArrayObj * x); + VXObject(VXForeignClosureObj * x); + VXObject(VXNativeClosureObj * x); + VXObject(VXOuterObj * x); + VXObject(VXGeneratorObj * x); + VXObject(VXStringObj * x); + VXObject(VXUserDataObj * x); + VXObject(VXWeakRefObj * x); + VXObject(VXState * x); + VXObject(VXFuncProtoObj * x); + VXObject(VXInteger x); + VXObject(VXFloat x); + VXObject(VXUserPointer x); + VXObject(bool bBool); + ~VXObject(); + + VXObject& operator=(VXTableObj *x); + VXObject& operator=(VXClassObj *x); + VXObject& operator=(VXInstanceObj *x); + VXObject& operator=(VXArrayObj *x); + VXObject& operator=(VXForeignClosureObj *x); + VXObject& operator=(VXNativeClosureObj *x); + VXObject& operator=(VXOuterObj *x); + VXObject& operator=(VXGeneratorObj *x); + VXObject& operator=(VXStringObj *x); + VXObject& operator=(VXUserDataObj *x); + VXObject& operator=(VXWeakRefObj *x); + VXObject& operator=(VXState *x); + VXObject& operator=(VXFuncProtoObj *x); + VXObject& operator=(VXUserPointer x); + VXObject& operator=(VXInteger x); + VXObject& operator=(VXFloat x); + VXObject& operator=(bool b); + VXObject& operator=(const VXObject& obj); + VXObject& operator=(const VXRawObj& obj); + + bool Is(VXOType tp) const; + bool IsNull() const; + bool IsNumeric() const; + bool IsTable() const; + bool IsArray() const; + bool IsFunction() const; + bool IsClosure() const; + bool IsNativeClosure() const; + bool IsGenerator() const; + bool IsString() const; + bool IsInteger() const; + bool IsFloat() const; + bool IsUserPointer() const; + bool IsUserData() const; + bool IsThread() const; + bool IsClass() const; + bool IsInstance() const; + bool IsBool() const; + bool IsWeakRef() const; + + bool Boolean() { return Integer(); }; + bool Boolean() const { return Integer(); }; + VXInteger Integer(); + VXInteger Integer() const; + VXFloat Float(); + VXFloat Float() const; + VXStringObj* String(); + VXStringObj* String() const; + void String(const char** dest, VXInteger* len_dest=NULL) const; + VXTableObj* Table(); + VXTableObj* Table() const; + VXArrayObj* Array(); + VXArrayObj* Array() const; + VXGeneratorObj* Generator(); + VXGeneratorObj* Generator() const; + VXForeignClosureObj* Closure(); + VXForeignClosureObj* Closure() const; + VXNativeClosureObj* NativeClosure(); + VXNativeClosureObj* NativeClosure() const; + VXUserDataObj* UserData(); + VXUserDataObj* UserData() const; + VXUserPointer UserPointer(); + VXUserPointer UserPointer() const; + VXState* Thread(); + VXState* Thread() const; + VXFuncProtoObj* FuncProto(); + VXFuncProtoObj* FuncProto() const; + VXClassObj* Class(); + VXClassObj* Class() const; + VXInstanceObj* Instance(); + VXInstanceObj* Instance() const; + VXDelegableObj* Delegable(); + VXDelegableObj* Delegable() const; + VXWeakRefObj* WeakRef(); + VXWeakRefObj* WeakRef() const; + VXOuterObj* Outer(); + VXOuterObj* Outer() const; + VXRefCountedObj* RefCounted(); + VXRefCountedObj* RefCounted() const; + VXRawValue Raw(); + VXRawValue Raw() const; + + template Type As(); + + VXOType Type() const; + const char* TypeString() const; + + void Null(); + + private: + VXObject(const char *); +}; + +typedef VXVector VXObjectVec; + +struct VXRefCountedObj +{ + VXUnsignedInteger _uiRef; + struct VXWeakRefObj *_weakref; + VXRefCountedObj() + { + _uiRef = 0; + _weakref = NULL; + } + virtual ~VXRefCountedObj(); + VXWeakRefObj *GetWeakRef(VXOType type); + virtual void Release()=0; + +}; + +struct VXWeakRefObj : VXRefCountedObj +{ + void Release(); + VXRawObj _obj; +}; + + + +struct VXCollectable : public VXRefCountedObj +{ + VXCollectable *_next; + VXCollectable *_prev; + VXSharedState *_sharedstate; + virtual VXOType GetType()=0; + virtual void Release()=0; + virtual void Mark(VXCollectable **chain)=0; + void UnMark(); + virtual void Finalize()=0; + static void AddToChain(VXCollectable **chain,VXCollectable *c); + static void RemoveFromChain(VXCollectable **chain,VXCollectable *c); +}; + +struct VXDelegableObj: public VXCollectable +{ + bool SetDelegate(VXTableObj *m); + virtual bool GetMetaMethod(VXState *v,VXMetaMethod mm,VXObject &res); + VXTableObj *_delegate; +}; + +struct VXStringObj : public VXRefCountedObj +{ + VXStringObj() + { + } + + ~VXStringObj() + { + } + + public: + static VXStringObj* Create(VXSharedState* ss, const char* str); + + static VXStringObj* Create(VXSharedState* ss, const char* str, VXInteger len); + + VXInteger Next(const VXObject &refpos, VXObject &outkey, VXObject &outval); + + void Release(); + + void Get(const char** dest_str, VXInteger* dest_len); + + inline const char* Value() const + { + return this->_val; + } + + inline VXInteger Length() const + { + return this->_len; + } + + template + void Get(StrClass* dest) + { + const char* dest_str; + VXInteger dest_len; + Get(&dest_str, &dest_len); + dest->append(dest_str, dest_len); + } + + VXSharedState *_sharedstate; + + VXStringObj *_next; + + VXInteger _len; + + VXHash _hash; + + char _val[1]; +}; + +struct VXArrayObj : public VXCollectable +{ + private: + VXArrayObj(VXSharedState *ss,VXInteger nsize); + + ~VXArrayObj(); + + public: + static VXArrayObj* Create(VXSharedState *ss,VXInteger nInitialSize); + void Mark(VXCollectable **chain); + + VXOType GetType(); + + void Finalize(); + + bool Get(const VXInteger nidx,VXObject &val); + + bool Set(const VXInteger nidx,const VXObject &val); + + VXInteger Next(const VXObject &refpos, + VXObject &outkey, + VXObject &outval); + + VXArrayObj *Clone(); + + VXInteger Size() const; + + void Resize(VXInteger size); + + void Resize(VXInteger size,VXObject &fill); + + void Reserve(VXInteger size); + + void Append(const VXObject &o); + + void Extend(const VXArrayObj *a); + + VXObject &Top(); + + void Pop(); + + bool Insert(VXInteger idx,const VXRawObj &val); + + void ShrinkIfNeeded(); + + bool Remove(VXInteger idx); + + void Release(); + + VXObjectVec _values; +}; + +struct VXTableObj : public VXDelegableObj +{ + private: + struct _HashNode + { + _HashNode() { next = NULL; } + VXObject val; + VXObject key; + _HashNode *next; + }; + + _HashNode *_firstfree; + _HashNode *_nodes; + VXInteger _numofnodes; + VXInteger _usednodes; + + /////////////////////////// + void AllocNodes(VXInteger nSize); + void Rehash(bool force); + VXTableObj(VXSharedState *ss, VXInteger nInitialSize); + void _ClearNodes(); + + public: + static VXTableObj* Create(VXSharedState *ss,VXInteger nInitialSize); + void Finalize(); + + VXTableObj *Clone(); + + ~VXTableObj(); + + void Mark(VXCollectable **chain); + + VXOType GetType(); + + _HashNode* _Get(const VXObject &key,VXHash hash); + + bool Get(const VXObject &key,VXObject &val); + + void Remove(const VXObject &key); + + bool Set(const VXObject &key, const VXObject &val); + + //returns true if a new slot has been created false if it was already present + bool NewSlot(const VXObject &key,const VXObject &val); + + VXInteger Next(bool getweakrefs, + const VXObject &refpos, + VXObject &outkey, + VXObject &outval); + + VXInteger CountUsed(); + + VXInteger Size() const; + + void Clear(); + + void Release(); + + VXInteger GetBoolValue(const VXObject& keyname, bool* destination); + + VXInteger GetStringValue(const VXObject& keyname, VXStringObj** dest); + + VXInteger GetStringValue(const VXObject& keyname, const char** dest_str, VXInteger* dest_len); + + VXInteger GetIntegerValue(const VXObject& keyname, VXInteger* dest); + + VXInteger GetFloatValue(const VXObject& keyname, VXFloat* dest); + + VXInteger GetArrayValue(const VXObject& keyname, VXArrayObj** dest); + + VXInteger GetTableValue(const VXObject& keyname, VXTableObj** dest); + +}; + +struct VXInstanceObj: public VXDelegableObj +{ + void Init(VXSharedState *ss); + VXInstanceObj(VXSharedState *ss, VXClassObj *c, VXInteger memsize); + VXInstanceObj(VXSharedState *ss, VXInstanceObj *c, VXInteger memsize); + + public: + static VXInstanceObj* Create(VXSharedState *ss, VXClassObj *theclass); + + VXInstanceObj *Clone(VXSharedState *ss); + + ~VXInstanceObj(); + + bool Get(const VXObject &key,VXObject &val); + + bool Set(const VXObject &key,const VXObject &val); + + void Release(); + + void Finalize(); + + void Mark(VXCollectable**); + + VXOType GetType(); + + bool InstanceOf(VXClassObj* trg); + + bool GetMetaMethod(VXState *v,VXMetaMethod mm,VXObject &res); + + bool _hasbase; + VXObject _base; + VXUserPointer _base_userpointer; + VXClassObj *_class; + VXUserPointer _userpointer; + VXReleaseHook _hook; + VXInteger _memsize; + VXObject _values[1]; +}; + +struct VXClassObj: public VXCollectable +{ + struct Member + { + VXObject val; + VXObject attrs; + }; + + typedef VXVector ClassMemberVec; + + VXClassObj(VXSharedState *ss, VXClassObj *base); + + public: + static VXClassObj* Create(VXSharedState *ss, VXClassObj *base); + + ~VXClassObj(); + + bool NewSlot(VXSharedState *ss, const VXObject &key, const VXObject &val, bool bstatic); + + bool Get(const VXObject &key,VXObject &val); + + bool GetConstructor(VXObject &ctor); + + bool SetAttributes(const VXObject &key,const VXObject &val); + + bool GetAttributes(const VXObject &key,VXObject &outval); + + void Lock(); + + void Release(); + + void Finalize(); + + void Mark(VXCollectable ** ); + + VXOType GetType(); + + VXInteger Next(const VXObject &refpos, VXObject &outkey, VXObject &outval); + + VXInstanceObj *CreateInstance(); + + public: + VXSharedState* _ss; + + VXTableObj *_members; + + VXClassObj *_base; + + ClassMemberVec _defaultvalues; + + ClassMemberVec _methods; + + VXObject _metamethods[VX_MT_LAST]; + + VXObject _attributes; + + VXUserPointer _typetag; + + VXReleaseHook _hook; + + bool _locked; + + VXInteger _constructoridx; + + VXInteger _udsize; + + const char* _name; +}; + + +typedef void (*VXDebugHook)(VXState* /* v */, + VXInteger /* type */, + const char* /* sourcename */, + VXInteger /* line */, + const char* /*funcname*/); + +struct VXMemberHandle +{ + bool _static; + VXInteger _index; +}; + +struct VXStackInfos +{ + const char* funcname; + const char* source; + VXInteger line; + VXInteger column; + bool native; +}; + + +struct VXState: public VXCollectable +{ + enum ExecutionType + { + ET_CALL, + ET_RESUME_GENERATOR, + ET_RESUME_VM, + ET_RESUME_THROW_VM + }; + + struct CallInfo + { + VXInstruction *_ip; + VXObject *_literals; + VXObject _closure; + VXGeneratorObj *_generator; + VXInt32 _etraps; + VXInt32 _prevstkbase; + VXInt32 _prevtop; + VXInt32 _target; + VXInt32 _ncalls; + bool _root; + }; + + typedef VXVector CallInfoVec; + + VXState(VXSharedState *ss); + + ~VXState(); + + static VXState* Create(VXInteger stacksize); + + static void Destroy(VXState* vm); + + VXInteger GetState(); + VXInteger WakeUp(bool wakeupret,bool retval,bool raiseerror,bool throwerror); + + void DebugHookProxy(VXInteger type, + const char* sourcename, + VXInteger line, + const char* funcname); + + static void _DebugHookProxy(VXState* v, + VXInteger type, + const char* sourcename, + VXInteger line, + const char* funcname); + + bool Init(VXState *friendvm, + VXInteger stacksize); + + bool Execute(VXObject &func, + VXInteger nargs, + VXInteger stackbase, + VXObject &outres, + bool raiseerror, + ExecutionType et = ET_CALL); + + //starts a native call return when the NATIVE closure returns + bool CallNative(VXNativeClosureObj* nclosure, + VXInteger nargs, + VXInteger newbase, + VXObject &retval, + bool &suspend); + + //starts a VOX_ call in the same "Execution loop" + bool StartCall(VXForeignClosureObj* closure, + VXInteger target, + VXInteger nargs, + VXInteger stackbase, + bool tailcall); + + bool CreateClassInstance(VXClassObj* theclass, + VXObject& inst, + VXObject& constructor); + + //call a generic closure pure VOX_ or NATIVE + bool Call(VXObject &closure, + VXInteger nparams, + VXInteger stackbase, + VXObject &outres, + bool raiseerror); + + VXInteger CallSimple(VXObject& closure, VXInteger params,bool retval,bool raiseerror); + VXInteger CallStack(VXInteger params,bool retval,bool raiseerror); + VXInteger CallStack(VXInteger idx, VXInteger params,bool retval,bool raiseerror); + + VXInteger Suspend(); + + void CallDebugHook(VXInteger type, + VXInteger forcedline=0); + + void CallErrorHandler(VXObject &e); + + bool Get(const VXObject &self, + const VXObject &key, + VXObject &dest, + bool raw, + VXInteger selfidx); + + const char* GetLocal(VXUnsignedInteger level,VXUnsignedInteger idx, VXObject& dest); + + VXInteger FallBackGet(const VXObject &self, + const VXObject &key, + VXObject &dest); + + bool InvokeDefaultDelegate(const VXObject &self, + const VXObject &key, + VXObject &dest); + + bool Set(const VXObject &self, + const VXObject &key, + const VXObject &val, + VXInteger selfidx); + + VXInteger FallBackSet(const VXObject &self, + const VXObject &key, + const VXObject &val); + + bool NewSlot(const VXObject &self, + const VXObject &key, + const VXObject &val, + bool bstatic); + + bool DeleteSlot(const VXObject &self, const VXObject &key, VXObject &res); + + bool Clone(const VXObject &self, VXObject &target); + + bool ObjCmp(const VXObject &o1, const VXObject &o2,VXInteger &res); + + bool StringCat(const VXObject &str, const VXObject &obj, VXObject &dest); + + static bool IsEqual(const VXObject &o1,const VXObject &o2,bool &res); + + bool ToString(const VXObject &o,VXObject &res); + + VXStringObj* PrintObjVal(const VXObject &o); + + VXInteger ThrowError(const char *s, ...); + + VXInteger ThrowError(const VXObject &desc); + + VXInteger Irrecoverable_Error(const char* s, ...); + + VXInteger Raise_IdxError(const VXObject &o, + const VXObject& origin, + bool is_index=false); + + VXInteger Raise_CompareError(const VXObject& o1, const VXObject& o2); + + VXInteger Raise_ParamTypeError(VXInteger nparam,VXInteger typemask,VXInteger type); + + bool TypeOf(const VXObject &obj1, VXObject &dest); + + void Mark(VXCollectable **chain); + + VXOType GetType(); + + void Finalize(); + + void GrowCallStack(); + + bool EnterFrame(VXInteger newbase, VXInteger newtop, bool tailcall); + + void LeaveFrame(); + + void Release(); + //////////////////////////////////////////////////////////////////////////// + //stack functions for the api + void Remove(VXInteger n); + + static bool IsFalse(VXObject &o); + + void Pop(); + + void Pop(VXInteger n); + + void Push(const VXObject &o); + + void PushString(const char* str, VXInteger len=-1); + + void PushInteger(VXInteger itm); + + void PushFloat(VXFloat itm); + + VXTableObj* RegisterLib(const char* libname, + const VXRegFunction* funcs, + bool reg_global, + VXTableObj* tb=NULL); + + VXClassObj* RegClass(const VXVector& funcs, + VXClassObj* base=NULL, + VXUserPointer typetag=0); + + VXClassObj* RegClass(const VXRegFunction* funcs, + VXClassObj* base=NULL, + VXUserPointer typetag=0); + + VXClassObj* NewClass(VXClassObj* baseclass=NULL); + + VXInteger SetParamsCheck(VXObject& o, VXInteger nparams, const char *typemask); + + void PushNull(); + + VXObject &Top(); + + void SetTop(VXInteger newtop); + + VXInteger GetTop(); + + VXObject& PopGet(); + + VXObject& GetUp(VXInteger n); + + VXObject& GetAt(VXInteger n); + + VXInteger Repush(VXInteger idx); + + VXInteger StackCall(VXInteger params, bool retval, bool raiseerror); + + //// extras + VXInteger SetDelegate(VXObject& self, const VXObject& mt); + + VXInteger BindEnv(VXObject& o, const VXObject& env, VXObject& ret); + + char* ScratchPad(VXInteger size); + + void AtExit(const VXObject& ob); + + static void Move(VXState* destination, VXState* source, const VXObject& o); + + static void MoveIndex(VXState* destination, VXState* source, VXInteger idx); + + VXInteger ToStringAt(VXInteger idx, VXObject& dest); + + void SetReleaseHook(VXInteger idx, VXReleaseHook hook); + + VXInteger SetTypeTag(VXObject& o, VXUserPointer typetag); + + VXInteger SetInstanceUp(VXInteger idx, VXUserPointer* p); + + VXInteger GetInstanceUp(VXInteger idx, VXUserPointer *p,VXUserPointer typetag, bool previously_checked_base=false); + + VXInteger RawSetStack(VXInteger idx); + + VXInteger RawGetStack(VXInteger idx); + + VXInteger Raise_InvalidType(VXOType type); + + VXInteger GetSize(const VXObject& o); + + VXInteger GetSizeAt(VXInteger idx); + + VXInteger ClearAt(VXInteger idx); + + VXInteger Clear(VXObject& o); + + void PushLastError(); + + VXInteger StackInfos(VXInteger level, VXStackInfos* si); + + void SetPrintFunc(VXPrintFunction printfunc,VXPrintFunction errfunc); + + VXInteger WriteClosure(VXWriteFunc w, VXUserPointer up); + + VXInteger WriteClosureToFile(const char *filename); + + void SetCompilerErrorHandler(VXCompileError f); + + void SetDebugHook(const VXObject& o); + + void SetErrorHandler(const VXObject& o); + + void SetErrorHandlers(); + + VXPrintFunction GetErrorFunc(); + + void EnableDebugInfo(bool enable); + + VXNativeClosureObj* NewClosure(VXFunction func, VXUnsignedInteger nfreevars=0); + + VXStringObj* NewString(const char* str, VXInteger len=-1); + + VXArrayObj* NewArray(VXInteger initial_size=0); + + VXTableObj* NewTable(); + + VXState* NewThread(VXState* friendvm, VXInteger initialstacksize); + + + VXArrayObj* GetSysArgv(); + + VXTableObj* GetRegistryTable(); + + VXTableObj* GetRootTable(); + + void PushRoot(); + + void PopRoot(); + + VXSharedState* Shared(); + + VXObject& StackGet(VXInteger idx); + + VXInteger ReadClosure(VXReadFunc r, VXUserPointer up, VXObject* dest=NULL); + + VXInteger CompileBuffer(const char* source, VXInteger size, const char* sourcename, bool raiseerror); + + VXInteger LoadFile(const char* filename, + bool printerror, + bool* failed_to_open=NULL, + VXObject* dest=NULL); + + VXInteger DoString(const char* source, + VXInteger len, + const char* bufname, + bool retval, + bool printerror); + + + VXInteger DoStringFmt(bool globaltable, bool returns, + bool raise_error, const char* str_format, ...); + + VXInteger DoFile(const char* path, + bool retval, + bool printerror, bool* failed_to_open=NULL); + + void DefineGlobal(const char* name, const VXObject& sym); + + const char* LastError(); + + VXInteger GetTypedArg(VXInteger idx, VXOType, VXObject& dest); + + VXInteger GetUserPointer(VXInteger idx, VXUserPointer *p); + + VXInteger GetClosure(VXInteger idx, VXFuncProtoObj** fnproto); + + VXInteger GetFloat(VXInteger idx, VXFloat *f); + + VXInteger GetBool(VXInteger idx,bool *b); + + VXInteger GetInteger(VXInteger idx, VXInteger* dest); + + VXInteger GetString(VXInteger idx, const char** src_dest, VXInteger* len_dest); + + template VXInteger GetString(VXInteger idx, Type* dest) + { + const char* src; + VXInteger len; + if(VX_SUCCEEDED(this->GetString(idx, &src, &len))) + { + dest->append(src, len); + return VX_OK; + } + return VX_ERROR; + } + + bool CollectGarbage(); + + bool ResurrectUnreachable(); + + // vars + VXArrayObj* _system_argv; + VXObjectVec _stack; + + VXInteger _top; + VXInteger _stackbase; + VXOuterObj *_openouters; + VXObject _roottable; + VXObject _lasterror; + VXObject _errorhandler; + + bool _debughook; + VXDebugHook _debughook_native; + VXObject _debughook_closure; + + VXObject temp_reg; + + CallInfo* _callsstack; + VXInteger _callsstacksize; + VXInteger _alloccallsstacksize; + VXVector _callstackdata; + + ExceptionsTraps _etraps; + CallInfo *ci; + void *_foreignptr; + //VMs sharing the same state + VXSharedState *_sharedstate; + VXInteger _nnativecalls; + VXInteger _nmetamethodscall; + //suspend infos + bool _suspended; + bool _suspended_root; + VXInteger _suspended_target; + VXInteger _suspended_traps; + + // atexit stuff + VXVector _atexit_functions; +}; + +struct VXRepr +{ + VXState* v; + VXObject root_ob; + VXInteger returns; + std::stringstream strm; + + VXRepr(VXState* _v, const VXObject& ob); + + void do_serialize(const VXObject& o); + + void emit_string(const VXObject& o); + + void emit_table(const VXObject& o); + + void emit_array(const VXObject& o); + + void emit_othertype(const VXObject& o); + + std::string str(); + + VXInteger status(); +}; + +VOX_API void* vox_malloc(VXUnsignedInteger size); +VOX_API void* vox_realloc(void* p,VXUnsignedInteger oldsize,VXUnsignedInteger newsize); +VOX_API void vox_free(void* p,VXUnsignedInteger size); + +VXInteger vox_aux_invalidtype(VXState* v,VXOType type); +VOX_API void vox_aux_seterrorhandlers(VXState* v); +VOX_API void vox_aux_printcallstack(VXState* v); +VOX_API void vox_aux_asserthandler(const char* expr, + const char* funct, + const char* file, + int line); + +VOX_API void vox_defaultprintfunc(VXState* v,const char *s,...); +VOX_API void vox_defaulterrorfunc(VXState* v,const char *s,...); + +/* stdlib functions */ +/* system, mathlib, iolib and hashlib are part of the core */ +VOX_API VXInteger voxstd_register_system(VXState* v); +VOX_API VXInteger voxstd_register_mathlib(VXState* v); +VOX_API VXInteger voxstd_register_iolib(VXState* v); +VOX_API VXInteger voxstd_register_hashlib(VXState* v); +#ifdef VOX_STDLIB_AVAILABLE + VOX_API VXInteger voxstd_register_importlib(VXState* v); + VOX_API VXInteger voxstd_register_oslib(VXState* v); + VOX_API VXInteger voxstd_register_regexlib(VXState* v); +#endif /* VOX_STDLIB_AVAILABLE */ + + +#endif /*_VOX_H_*/ diff --git a/modules/core/cgi.vx b/modules/core/cgi.vx new file mode 100644 index 0000000..8419426 --- /dev/null +++ b/modules/core/cgi.vx @@ -0,0 +1,760 @@ + +/** +* This file is part of the Vox project +* +* #################### +* @synopsis@ +* cgi.vx - provides a CGI Interface, influenced by LunarCGI +* +* @examples@ +* Most basic example: +* --- +* CGI := import("core/cgi") +* app:= CGI.Application() +* app.sendHeaders(200, {type="text/html"}) +* // you can add as many headers as you please until +* // the first call to CGI::Interface::write() +* app.putHeader("X-Server", "VoxCGI") +* app.write("Hello world!") +* --- +* +* @notes@ +* cgi.vx is not yet finished +* +* @license@ +* Copyright (c) 2011-2012 Beelzebub Software +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +local template = import("core/template") +local CGI = {} + +CGI.parse_query := function(query) +{ + + local vars = query.split("&") + local pairs = {} + for(local i=0; i", ">"], + ] + foreach(pair in escape_me) + { + text = text.replace(pair[0], pair[1]) + } + return text +} + +CGI.urldecode := function(src) +{ + local ret = "" + for(local i=0; i 0) + { + if(kname == "query") + { + kvalue = CGI.parse_query(kvalue) + } + newvars[kname] := kvalue; + } + } + return newvars; +} + +class CGI.Interface +{ + m_buffer = [] + m_headers = [] + m_cookies = {} + m_headersent = false + m_haveheaders = false + m_trimtext = false + m_autoflush = false + m_cachedata = false + m_do_not_send_headers = false + m_status = 200 + m_lend = "\r\n" + m_query_post_cache = null + m_query_get_cache = null + m_iostream = null + + constructor(_autoflush=true, _trimtext=false, _cachedata=true) + { + this.m_trimtext = _trimtext + this.m_autoflush = _autoflush + this.m_cachedata = _cachedata + this.m_iostream = io.stdout + } + + function writeraw(str, doflush=false) + { + if(str != null) + { + ::print(str.tostring()) + } + if(doflush) + { + //io.stdout.flush() + } + } + + function write(...) + { + local str = "" + foreach(s in vargv) + { + str += s.tostring() + } + str = this.m_trimtext ? str.trim() : str + this.m_buffer.push(str) + if(this.m_autoflush == true) + { + local sendheader = true + if(this.m_headersent == true) + { + sendheader = false + } + if(this.m_do_not_send_headers == true) + { + sendheader = false + } + this.flush(sendheader) + } + if(m_cachedata == false) + { + flush(false) + } + return this + } + + function haveheaders() + { + return this.m_haveheaders + } + + function putheader(key, value) + { + local values = [] + switch(key.tostring().tolower()) + { + case "type": + key = "Content-Type" + break; + case "location": + key = "Location" + break + } + values.push(key) + values.push(value) + this.m_headers.push(values) + this.m_haveheaders = true + return this + } + + function setstatus(_status) + { + this.m_status = _status + return this + } + + function sendheader(_status, key=null, value=null) + { + if(key == null && value == null) + { + this.setstatus(_status) + } + else + { + if(typeof _status == "string" && + typeof key == "string" && value == null) + { + this.putheader(_status, key) + } + else + { + this.setstatus(_status) + this.putheader(key, value) + } + } + if(m_cachedata == false) flush() + return this + } + + function sendheaders(_status, allpairs=null) + { + this.setstatus(_status) + if(allpairs != null) + { + foreach(key, value in allpairs) + { + this.putheader(key, value) + } + } + if(m_cachedata == false) flush() + return this + } + + function redirect(url) + { + if(this.m_headersent == false) + { + this.sendheader(302, "Content-Type", "text/html") + } + this.sendHeader("Location", url) + this.write("Location has moved: %s".fmt(url, url)) + } + + function sendcookie(key, value) + { + if(key in this.m_cookies) + this.m_cookies[key] = value + else + this.m_cookies[key] := value + } + + function clearCache() + { + this.m_buffer = [] + } + + function flush(sendheader=true) + { + if(sendheader) + { + foreach(key, value in this.m_cookies) + { + key = key.tostring() + value = value.tostring() + local fmt = "%s=%s;".fmt(key, value) + local cookiestr = fmt + this.putheader("Set-Cookie", cookiestr) + } + if(this.m_headersent == false) + { + this.putheader("Status", this.m_status) + foreach(i, vpair in this.m_headers) + { + local key = vpair[0].tostring() + local value = vpair[1].tostring() + this.writeraw("%s: %s%s".fmt(key, value, this.m_lend)) + } + this.writeraw(this.m_lend) + this.m_headersent = true + } + else + { + throw "Header already sent!" + } + } + foreach(i, item in this.m_buffer) + { + this.writeraw(item.tostring()) + } + this.writeraw(null, true) + this.m_buffer = [] + } + + function queriesGET() + { + local vars = {} + local data = os.getenv("QUERY_STRING") + if(data) + { + vars = CGI.parse_query(data) + this.m_query_get_cache = data + } + return vars + } + + function queriesPOST() + { + local vars = {} + local multipart + local length_str = os.getenv("CONTENT_LENGTH") + if(length_str) + { + local length = length_str.tointeger() + local data = io.stdin.read(length) + if(data) + { + vars = CGI.parse_query(data) + this.m_query_post_cache = data + } + else + { + if(this.m_query_post_cache) + { + vars = CGI.parse_query(this.m_query_post_cache) + } + } + io.stdin.flush() + } + return vars + } + + function param_proxy(key, fn) + { + local vars = fn() + if(key in vars) + { + return vars[key] + } + return null + } + + function paramMULTIPART(key) + { + return this.param_proxy(key, this.queriesMULTIPART) + } + + function paramPOST(key) + { + return this.param_proxy(key, this.queriesPOST) + } + + function paramGET(key) + { + return this.param_proxy(key, this.queriesGET) + } + + function param(key) + { + local post_val = this.paramPOST(key) + local get_val = this.paramGET(key) + // first check POST, since one could easily do something like this: + // someurl.cgi?someVar=1 + // where "someVar" is also defined in a formular. so checking + // POST first prevents this override. + if(post_val) + { + return post_val + } + else if(get_val) + { + return get_val + } + return null + } +} + +class CGI.Application extends CGI.Interface +{ + _template_path = "." + _default_env = {} + + constructor() + { + local _self = this + base() + } + + function set_defaultenv(env) + { + _default_env = env + } + + function set_template_path(newpath) + { + this._template_path = newpath + } + + function eval_tplfile(name, env={}) + { + local realenv = env + local realpath = this._template_path + "/" + name + foreach(key, value in _default_env) + { + realenv[key] := value + } + try + { + template.eval_file(this, realpath, realenv) + } + catch(error) + { + throw "Compiling %s failed: %s".fmt(realpath.quote(), error) + } + } + + function eval_tplstring(source, env={}, env_use_subtable=true) + { + local realenv = env + foreach(key, value in _default_env) + { + realenv[key] := value + } + try + { + template.eval_string(this, source, realenv, env_use_subtable) + } + catch(error) + { + throw "Compiling failed: %s".fmt(error) + } + } +} + +// _raw_path = os.getenv("PATH_INFO") + +class CGI.RoutedApp extends CGI.Application +{ + + _allroutes = [] + _handle_notfound = null + + constructor() + { + base() + } + + function raw_pathinfo() + { + return os.getenv("PATH_INFO") || "" + } + + function parsed_pathinfo() + { + local parts = raw_pathinfo().split("/") + if((parts.len() > 0) && (t[0].len() == 0)) + { + parts.remove(0) + } + return parts + } + + function isroute(expr, useregex=true) + { + local rawpi = raw_pathinfo() + if(expr == "/" && rawpi.len() == 0) + { + rawpi = "/" + } + if(useregex) + { + local rex = regexp.compile(expr) + local matches = rex.match(rawpi) + return matches + } + else + { + if(expr == rawpi) + { + return true + } + } + return null + } + + function on_notfound(func) + { + this._handle_notfound = func + } + + function on_route(slug, func) + { + _allroutes.push({pattern=slug, func=func, ispattern=false}) + } + + function on_pattern(pattern, func) + { + _allroutes.push({pattern=pattern, func=func, ispattern=true}) + } + + function exec() + { + local found_cb = false + foreach(route in _allroutes) + { + local rawpi = raw_pathinfo() + if(route.pattern == "/" && rawpi.len() == 0) + rawpi = "/" + if(route.ispattern) + { + local re = regexp.compile(route.pattern) + local captures + if((captures = re.match(rawpi))) + { + route.func(captures) + found_cb = true + } + } + else + { + if(route.pattern == rawpi) + { + route.func() + found_cb = true + } + } + } + if(found_cb == false) + { + if(_handle_notfound != null) + { + _handle_notfound() + } + } + } +} + + +return CGI + diff --git a/modules/core/config.vx b/modules/core/config.vx new file mode 100644 index 0000000..3900b2c --- /dev/null +++ b/modules/core/config.vx @@ -0,0 +1,254 @@ + + +return class +{ + parselists = false + parsevars = false + _values = {} + _vars = {} + _comment_rex = regexp.compile(@"(;|#).*$") + + constructor(filepath=null, parselists=false, parsevars=false) + { + this.parselists = parselists + this.parsevars = parsevars + if(filepath) + { + this.parse_file(filepath) + } + } + + function _notnull(val) + { + if(val == null) + { + return false + } + if(typeof val == "string" && val.len() == 0) + { + return false + } + return true + } + + function _findandreplacevars(val) + { + local pat = @"$%s" + local nval = val + foreach(var_key, var_val in this._vars) + { + local findme = pat.fmt(var_key) + if(typeof nval == "string") + { + nval = nval.replace(findme, var_val) + } + else + { + foreach(i, item in nval) + { + nval[i] = item.replace(findme, var_val) + } + } + } + return nval + } + + function _insert(section, key, value) + { + if(_notnull(key) && _notnull(value)) + { + key = key.trim() + if(parsevars) + { + value = _findandreplacevars(value) + } + if(section in this._values) + { + this._values[section][key] := value + } + else + { + this._values[section] := {} + this._insert(section, key, value) + } + } + } + + function _parsepair(line) + { + local key, value = "" + local parts = line.split("=") + if(parts.len() == 0) + { + return null + } + key = parts[0] + parts = parts.slice(1, parts.len()) + foreach(i, val in parts) + { + value += val + (i+1 == parts.len() ? "" : "=") + } + return {key=key, value=value} + } + + function _iscomment(line) + { + if(this._comment_rex.match(line.trim())) + { + return true + } + return false + } + + function _stripcomments(line) + { + local newline = regexp.replace(line, @"(;|;;|#).*$", "") + return newline + } + + function _issection(line) + { + line = line.trim() + if(line.startswith("[") && line.endswith("]")) + { + local section_tmp = line.slice(1, line.len()) + local section = section_tmp.slice(0, section_tmp.len() - 1) + return section + } + return null + } + + function _parselist(str) + { + if(parselists) + { + local list = [] + local splitup = str.split(",") + foreach(val in splitup) + { + list.push(val.trim()) + } + return list + } + else + { + return str + } + } + + function add_vars(tbl) + { + if(typeof tbl != "table") + throw "expected table!" + this._vars = tbl + } + + function preprocess(src) + { + return src + } + + function parse_file(path,) + { + local strdata = io.readfile(path) + return this.parse_string(strdata, path) + } + + function dump() + { + local str = "" + foreach(section, pairs in this._values) + { + str += "[%s]\n".format(section) + foreach(key, value in pairs) + { + local strvalue = "" + if(typeof value == "array") + { + foreach(i, val in value) + { + strvalue += val + if(i+1 != value.len()) + strvalue += "," + } + } + else + { + strvalue = value + } + str += "%s = %s\n".format(key.tostring(), strvalue.tostring()) + } + str += "\n" + } + return str + } + + function tree() + { + return this._values + } + + function write(filename) + { + local hnd = io.open(filename, "w") + hnd.write(this.dump()) + hnd.close() + } + + function add(section, key=null, val=null) + { + if(typeof key == "string") + { + this._insert(section, key, val) + } + else if(typeof key == "table" && val == null) + { + local vartable = key + foreach(key, val in vartable) + { + this._insert(section, key, val) + } + } + else + { + throw "expected (, , ) or (, )" + } + } + + function parse_string(_src, filename="") + { + local i, issection, pair + local section = "main" + local src = this.preprocess(_src) + local lines = src.split("\n") + // using for() instead of foreach() to keep track of + // the locations in the (potential) file + for(i=0; i") + fn_body_replacement = (infos.native ? "" : "") + this.dumped_value += "function %s() { %s }".fmt(fn_name, fn_body_replacement) + } + + function emit_array(ar, include_brackets=true, quote_values=true) + { + if(include_brackets) dumped_value += "[" + foreach(i, val in ar) + { + if(quote_values) + { + do_serialize(val, this.check_original, this.json_only) + } + else + { + dumped_value += val + } + if((i+1) != ar.len()) + { + dumped_value += ", " + } + } + if(include_brackets) dumped_value += "]" + } + + function emit_table(tb) + { + local i = 0 + dumped_value += "{" + foreach(key, value in tb) + { + do_serialize(key, this.check_original, this.json_only) + dumped_value += ": " + do_serialize(value, this.check_original, this.json_only) + if(i+1 != tb.len()) + { + dumped_value += ",\n" + } + i++ + } + dumped_value += "}" + } + + function emit_string(st) + { + local real_val = st + if(this.json_only) + { + real_val = st.replace("\n", @"\n") + } + dumped_value += real_val.quote() + } + + function tostring() + { + return this.dumped_value.tostring() + } + + function __tostring__() + { + return this.tostring() + } +} diff --git a/modules/core/sandbox.vx b/modules/core/sandbox.vx new file mode 100644 index 0000000..0226979 --- /dev/null +++ b/modules/core/sandbox.vx @@ -0,0 +1,41 @@ + +return class +{ + environ = {} + system = ::system + + constructor(newenv) + { + this.environ = newenv + assert(typeof this.environ == "table", "environment needs to be a table") + } + + function call(func) + { + local ret = null + local oldroot = this.system.getroottable() + this.system.setroottable(this.environ) + try + { + ret = func.call(this.environ, false) + } + catch(err) + { + this.system.setroottable(oldroot) + throw ("sandbox: " + err) + } + this.system.setroottable(oldroot) + return ret + } + + function callfile(path) + { + return this.call(this.system.loadfile(path)) + } + + function callstring(str) + { + return this.call(this.system.loadstring(str)) + } +} + diff --git a/modules/core/serialize.vx b/modules/core/serialize.vx new file mode 100644 index 0000000..27606ff --- /dev/null +++ b/modules/core/serialize.vx @@ -0,0 +1,9 @@ + +/** +** Starting with the introduction of #Object.repr(), serialize.vx doesn't really +** serve any purpose anymore. +*/ + + +throw "serialize.vx is deprecated! Please use #Object.repr() instead, please. If you must, import core/repr instead, which is a reimplementation of the repr algorithm in vox" + diff --git a/modules/core/simpledb.vx b/modules/core/simpledb.vx new file mode 100644 index 0000000..62c7067 --- /dev/null +++ b/modules/core/simpledb.vx @@ -0,0 +1,50 @@ + +return class +{ + m_filepath = null + m_data = {} + + constructor(path, overwrite=false) + { + this.m_filepath = path + if(os.exists(this.m_filepath) == true) + { + if(overwrite == false) + { + if(os.filesize(this.m_filepath) > 0) + { + this.m_data = system.dofile(this.m_filepath) + } + } + } + } + + function push_key(key, value) + { + assert(typeof key == "string", "key must be a string") + this.m_data[key] := value + } + + function commit() + { + local buf = "return " + this.m_data.repr() + "\n" + local compiled = system.loadstring(buf) + system.writeclosuretofile(this.m_filepath, compiled) + } + + function data() + { + return this.m_data + } + + function serialized_data() + { + return _serialize(this.data()) + } + + function path() + { + return this.m_filepath + } +} + diff --git a/modules/core/strict.vx b/modules/core/strict.vx new file mode 100644 index 0000000..2f37933 --- /dev/null +++ b/modules/core/strict.vx @@ -0,0 +1,23 @@ + + +println("this = ", this) + +/* +this.setdelegate( +{ + constructor() + { + println("constructor") + } + + __get__ = function(key) + { + println("__get__()") + } + + __set__ = function(key, value) + { + println("__set__()") + } +}) +*/ \ No newline at end of file diff --git a/modules/core/warning.vx b/modules/core/warning.vx new file mode 100644 index 0000000..8457ce1 --- /dev/null +++ b/modules/core/warning.vx @@ -0,0 +1,7 @@ + +return function(...) +{ + local str = "" + vargv.map(function(arg) { str += arg.tostring() }) + ::io.stderr.write("Runtime Warning: %s\n".fmt(str)) +} diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt new file mode 100644 index 0000000..ee5d6b2 --- /dev/null +++ b/src/core/CMakeLists.txt @@ -0,0 +1,59 @@ + + +SET(vox_corelib_sourcefiles + "vm.cpp" + "utils.cpp" + "class.cpp" + "compiler.cpp" + "debug.cpp" + "funcstate.cpp" + "funcproto.cpp" + "lexer.cpp" + "mem.cpp" + "object.cpp" + "state.cpp" + "array.cpp" + "table.cpp" + "string.cpp" + "closure.cpp" + "opcodes.cpp" + "repr.cpp" + "h_impl.cpp" + "baselib.cpp" + "baselib_io.cpp" + "baselib_array.cpp" + "baselib_class.cpp" + "baselib_string.cpp" + "baselib_table.cpp" + "baselib_system.cpp" + "baselib_math.cpp" + "baselib_closure.cpp" + "baselib_thread.cpp" + "baselib_generator.cpp" + "baselib_hashlib.cpp" +) + +IF(BUILD_SHAREDLIBS) + ADD_LIBRARY(${vox_corelib} SHARED ${vox_corelib_sourcefiles}) + SET_TARGET_PROPERTIES(${vox_corelib} + PROPERTIES + BUILD_WITH_INSTALL_RPATH TRUE + INSTALL_RPATH_USE_LINK_PATH TRUE + INSTALL_RPATH "${vox_rpath_paths}" + ) + IF(WIN32) + SET_TARGET_PROPERTIES(${vox_corelib} + PROPERTIES + PREFIX "" + ) + ENDIF(WIN32) + TARGET_LINK_LIBRARIES(${vox_corelib} ${vox_coredeps}) +ELSE(BUILD_SHAREDLIBS) + ADD_LIBRARY(${vox_corelib} STATIC ${vox_corelib_sourcefiles}) +ENDIF(BUILD_SHAREDLIBS) +SET_TARGET_PROPERTIES(${vox_corelib} + PROPERTIES + OUTPUT_NAME "${vox_corelib_name}" +) +INSTALL(TARGETS ${vox_corelib} DESTINATION lib) + diff --git a/src/core/array.cpp b/src/core/array.cpp new file mode 100644 index 0000000..35ebce5 --- /dev/null +++ b/src/core/array.cpp @@ -0,0 +1,177 @@ + +#include "pcheader.hpp" +#include "utils.hpp" +#include "object.hpp" +#include "vm.hpp" +#include "state.hpp" + +VXArrayObj::VXArrayObj(VXSharedState *ss,VXInteger nsize) +{ + _values.resize(nsize); + INIT_CHAIN(); + ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); +} + +VXArrayObj::~VXArrayObj() +{ + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); +} + +VXArrayObj* VXArrayObj::Create(VXSharedState *ss,VXInteger nInitialSize) +{ + VXArrayObj *newarray = (VXArrayObj*)VX_MALLOC(sizeof(VXArrayObj)); + new (newarray) VXArrayObj(ss,nInitialSize); + return newarray; +} + +void VXArrayObj::Mark(VXCollectable **chain) +{ + START_MARK() + VXInteger len = _values.size(); + for(VXInteger i = 0;i < len; i++) + { + VXSharedState::MarkObject(_values[i], chain); + } + END_MARK() +} + +VXOType VXArrayObj::GetType() +{ + return VX_OT_ARRAY; +} + +void VXArrayObj::Finalize() +{ + _values.resize(0); +} +bool VXArrayObj::Get(const VXInteger nidx,VXObject &val) +{ + if(nidx>=0 && nidx<(VXInteger)_values.size()) + { + VXObject &o = _values[nidx]; + val = VX_REALVAL(o); + return true; + } + return false; +} + +bool VXArrayObj::Set(const VXInteger nidx,const VXObject &val) +{ + if(nidx>=0 && nidx < (VXInteger)_values.size()) + { + _values[nidx] = val; + return true; + } + else + { + VXObject fill; + Resize(nidx + 1, fill); + return Set(nidx, val); + } + return false; +} + +VXInteger VXArrayObj::Next(const VXObject &refpos, VXObject &outkey, VXObject &outval) +{ + VXUnsignedInteger idx=TranslateIndex(refpos); + while(idx < _values.size()) + { + //first found + outkey=(VXInteger)idx; + VXObject &o = _values[idx]; + outval = VX_REALVAL(o); + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; +} + +VXArrayObj* VXArrayObj::Clone() +{ + VXArrayObj *anew=Create(_opt_ss(this),0); + anew->_values.copy(_values); + return anew; +} + +VXInteger VXArrayObj::Size() const +{ + return _values.size(); +} + +void VXArrayObj::Resize(VXInteger size) +{ + VXObject _null; + Resize(size,_null); +} + +void VXArrayObj::Resize(VXInteger size,VXObject &fill) +{ + _values.resize(size,fill); + ShrinkIfNeeded(); +} + +void VXArrayObj::Reserve(VXInteger size) +{ + _values.reserve(size); +} + +void VXArrayObj::Append(const VXObject &o) +{ + _values.push_back(o); +} + +void VXArrayObj::Extend(const VXArrayObj *a) +{ + VXInteger xlen; + if((xlen=a->Size())) + for(VXInteger i=0;i_values[i]); +} + + +VXObject& VXArrayObj::Top() +{ + return _values.top(); +} + +void VXArrayObj::Pop() +{ + _values.pop_back(); + ShrinkIfNeeded(); +} + +bool VXArrayObj::Insert(VXInteger idx,const VXRawObj &val) +{ + if(idx < 0 || idx > (VXInteger)_values.size()) + { + return false; + } + _values.insert(idx,val); + return true; +} + +void VXArrayObj::ShrinkIfNeeded() +{ + //shrink the array + if(_values.size() <= _values.capacity()>>2) + { + _values.shrinktofit(); + } +} + +bool VXArrayObj::Remove(VXInteger idx) +{ + if(idx < 0 || idx >= (VXInteger)_values.size()) + { + return false; + } + _values.remove(idx); + ShrinkIfNeeded(); + return true; +} + +void VXArrayObj::Release() +{ + vox_delete(this,VXArrayObj); +} diff --git a/src/core/baselib.cpp b/src/core/baselib.cpp new file mode 100644 index 0000000..e056689 --- /dev/null +++ b/src/core/baselib.cpp @@ -0,0 +1,293 @@ + +#include +#include "baselib.hpp" +#include "names.hpp" +#include "debug.hpp" + +bool str2num(const char *s,VXObject &res) +{ + char *end; + if(strstr(s, ".")) + { + VXFloat r = VXFloat(strtod(s, &end)); + if(s == end) + { + return false; + } + res = r; + return true; + } + else + { + /* + VXInteger r = VXInteger(strtol(s,&end,10)); + if(s == end) + { + return false; + } + */ + VXInteger r = VXInteger(atol(s)); + res = r; + return true; + } +} + +template +std::string num2hex(Type ivalue, bool prefix, VXInteger width, char fill) +{ + std::stringstream stream; + if(prefix) + { + stream << "0x"; + } + stream << std::setfill(fill) << std::setw(width) << std::hex << ivalue; + return stream.str(); +} + +VXInteger __getcallstackinfos(VXState* v,VXInteger level) +{ + VXTableObj* main_tb; + VXTableObj* sub_tb; + VXStackInfos si; + VXInteger seq = 0; + const char* name; + const char* fn; + const char* src; + if (VX_SUCCEEDED(v->StackInfos(level, &si))) + { + VXObject value; + fn = get_funcname(si); + src = get_sourcename(si); + main_tb = v->NewTable(); + sub_tb = v->NewTable(); + main_tb->NewSlot(v->NewString("func"), v->NewString(fn)); + main_tb->NewSlot(v->NewString("src"), v->NewString(src)); + main_tb->NewSlot(v->NewString("line"), si.line); + while((name = v->GetLocal(level, seq, value))) + { + sub_tb->NewSlot(v->NewString(name), value); + seq++; + } + main_tb->NewSlot(v->NewString("locals"), sub_tb); + v->Push(main_tb); + + return 1; + } + + return 0; +} + +VXInteger default_delegate_repr(VXState* v) +{ + VXInteger status; + VXObject& o = v->StackGet(1); + VXRepr ser(v, o); + if(VX_FAILED(status = ser.status())) + { + return status; + } + const std::string& str = ser.str(); + v->Push(v->NewString(str.c_str(), str.length())); + return 1; +} + +VXInteger default_delegate_tostring(VXState* v) +{ + bool do_serialize; + VXInteger status; + VXObject res; + if(VX_FAILED(v->GetBool(2, &do_serialize))) + { + do_serialize = false; + } + if(VX_SUCCEEDED(status = v->ToStringAt(1, res))) + { + v->Push(res); + } + return status; +} + +VXInteger obj_delegate_weakref(VXState* v) +{ + VXRawObj &o = v->StackGet(1); + if(ISREFCOUNTED(type(o))) + { + v->Push(_refcounted(o)->GetWeakRef(type(o))); + } + else + { + v->Push(o); + } + return 1; +} + +VXInteger obj_clear(VXState* v) +{ + return v->ClearAt(-1); +} + +VXInteger get_slice_params(VXState* v,VXInteger &sidx,VXInteger &eidx,VXObject &o) +{ + VXInteger top = v->GetTop(); + sidx=0; + eidx=0; + o= v->StackGet(1); + VXObject &start = v->StackGet(2); + if(type(start) != VX_OT_NULL && start.IsNumeric()) + { + sidx = start.Integer(); + } + if(top>2) + { + VXObject &end = v->StackGet(3); + if(end.IsNumeric()) + { + eidx=end.Integer(); + } + } + else + { + eidx = v->GetSizeAt(1); + } + return 1; +} + + +VXInteger default_delegate_len(VXState* v) +{ + v->Push(VXInteger(v->GetSize(v->StackGet(1)))); + return 1; +} + +VXInteger default_delegate_tofloat(VXState* v) +{ + VXObject& o = v->StackGet(1); + switch(type(o)) + { + case VX_OT_STRING: + { + VXObject res; + if(str2num(_stringval(o),res)) + { + v->Push(VXObject(tofloat(res))); + break; + } + } + return v->ThrowError("cannot convert the string to float"); + break; + case VX_OT_INTEGER: + case VX_OT_FLOAT: + v->Push(VXObject(tofloat(o))); + break; + case VX_OT_BOOL: + v->Push(VXObject((VXFloat)(_integer(o)?1:0))); + break; + default: + v->PushNull(); + break; + } + return 1; +} + +VXInteger default_delegate_tointeger(VXState* v) +{ + VXObject& o = v->StackGet(1); + switch(type(o)) + { + case VX_OT_STRING: + { + VXObject res; + if(str2num(_stringval(o),res)) + { + v->Push(VXObject(tointeger(res))); + break; + } + } + return v->ThrowError("cannot convert the string to integer"); + break; + case VX_OT_INTEGER: + case VX_OT_FLOAT: + v->Push(VXObject(tointeger(o))); + break; + case VX_OT_BOOL: + v->Push(VXObject(_integer(o)?(VXInteger)1:(VXInteger)0)); + break; + default: + v->PushNull(); + break; + } + return 1; +} + + +VXInteger container_rawset(VXState* v) +{ + return v->RawSetStack(-3); +} + +VXInteger container_rawget(VXState* v) +{ + return v->RawGetStack(-2); +} + + +VXInteger number_delegate_tochar(VXState* v) +{ + VXRawObj &o=stack_get(v,1); + char c = (char)tointeger(o); + v->Push(v->NewString((const char*)&c, 1)); + return 1; +} + +VXInteger number_delegate_tohex(VXState* v) +{ + VXInteger i; + VXInteger width; + bool prefix; + std::string val; + v->GetInteger(1, &i); + if(VX_FAILED(v->GetBool(2, &prefix))) + { + prefix = false; + } + if(VX_FAILED(v->GetInteger(3, &width))) + { + width = 0; + } + val = num2hex(i, prefix, width, '0'); + v->PushString(val.c_str(), val.length()); + return 1; +} + +/* +VXInteger weakref_ref(VXState* v) +{ + if(VX_FAILED(vox_getweakrefval(v,1))) + { + return VX_ERROR; + } + return 1; +} +*/ + +VXRegFunction VXSharedState::_number_default_delegate_funcz[]= +{ + {"tointeger", default_delegate_tointeger, 1, "n|b"}, + {"tofloat", default_delegate_tofloat, 1, "n|b"}, + {"tostring", default_delegate_tostring, -1, ".b"}, + {"tohex", number_delegate_tohex, -1, ".bn"}, + {"tochar", number_delegate_tochar, 1, "n|b"}, + {"weakref", obj_delegate_weakref, 1, NULL}, + {"repr", default_delegate_repr, 1, "."}, + {0, 0, 0, 0} +}; + + +VXRegFunction VXSharedState::_weakref_default_delegate_funcz[] = +{ + /*{"ref", weakref_ref, 1, "r"},*/ + {"weakref", obj_delegate_weakref, 1, NULL }, + {"tostring", default_delegate_tostring, -1, ".b"}, + {"repr", default_delegate_repr, 1, "."}, + {0, 0, 0, 0} +}; diff --git a/src/core/baselib.hpp b/src/core/baselib.hpp new file mode 100644 index 0000000..049ca56 --- /dev/null +++ b/src/core/baselib.hpp @@ -0,0 +1,27 @@ + +#include "pcheader.hpp" +#include "vm.hpp" +#include "string.hpp" +#include "table.hpp" +#include "funcproto.hpp" +#include "closure.hpp" +#include "class.hpp" + +#include +#include +#include + +bool str2num(const char *s,VXObject &res); +VXInteger __getcallstackinfos(VXState* v,VXInteger level); +VXInteger default_delegate_tostring(VXState* v); +VXInteger obj_delegate_weakref(VXState* v); +VXInteger obj_clear(VXState* v); +VXInteger get_slice_params(VXState* v,VXInteger &sidx,VXInteger &eidx,VXObject &o); +VXInteger default_delegate_len(VXState* v); +VXInteger default_delegate_tofloat(VXState* v); +VXInteger default_delegate_tointeger(VXState* v); +VXInteger default_delegate_repr(VXState* v); +VXInteger container_rawset(VXState* v); +VXInteger container_rawget(VXState* v); + + diff --git a/src/core/baselib_array.cpp b/src/core/baselib_array.cpp new file mode 100644 index 0000000..a2f89f4 --- /dev/null +++ b/src/core/baselib_array.cpp @@ -0,0 +1,508 @@ + +#include +#include "baselib.hpp" + +//ARRAY DEFAULT DELEGATE/////////////////////////////////////// + +VXInteger array_append(VXState* v) +{ + VXObject arr = v->StackGet(1); + arr.Array()->Append(v->StackGet(2)); + return VX_OK; +} + +VXInteger array_extend(VXState* v) +{ + VXArrayObj* self = v->StackGet(1).Array(); + self->Extend(v->StackGet(2).Array()); + v->Push(self); + return 1; +} + +VXInteger array_reverse(VXState* v) +{ + VXInteger i; + VXInteger n; + VXInteger size; + VXArrayObj* arr = v->StackGet(1).Array(); + VXArrayObj* narr = arr->Clone(); + if(arr->Size() > 0) + { + VXObject t; + size = arr->Size(); + n = (size >> 1); + size -= 1; + for(i=0; i < n; i++) + { + t = arr->_values[i]; + narr->_values[i] = arr->_values[size-i]; + narr->_values[size-i] = t; + } + } + v->Push(narr); + return 1; +} + +VXInteger array_pop(VXState* v) +{ + VXArrayObj* arr = v->StackGet(1).Array(); + if(arr->Size() > 0) + { + v->Push(arr->Top()); + arr->Pop(); + return 1; + } + return v->ThrowError("pop() on an empty array"); +} + +VXInteger array_top(VXState* v) +{ + VXArrayObj* arr = v->StackGet(1).Array(); + if(arr->Size() > 0) + { + v->Push(arr->Top()); + return 1; + } + return v->ThrowError("top() on a empty array"); +} + +VXInteger array_insert(VXState* v) +{ + VXArrayObj* arr = v->StackGet(1).Array(); + VXObject& idx = v->StackGet(2); + VXObject& val = v->StackGet(3); + if(!arr->Insert(idx.Integer(), val)) + { + return v->ThrowError("insert() failed: index out of range"); + } + return 0; +} + +VXInteger array_remove(VXState* v) +{ + VXObject val; + VXObject& o = v->StackGet(1); + VXObject& idx = v->StackGet(2); + if(!idx.IsNumeric()) + { + return v->ThrowError("wrong type"); + } + if(o.Array()->Get(idx.Integer(), val)) + { + o.Array()->Remove(idx.Integer()); + v->Push(val); + return 1; + } + return v->ThrowError("index out of range"); +} + +VXInteger array_resize(VXState* v) +{ + VXObject &o = v->StackGet(1); + VXObject &nsize = v->StackGet(2); + VXObject fill; + if(nsize.IsNumeric()) + { + if(v->GetTop() > 2) + { + fill = v->StackGet(3); + } + o.Array()->Resize(nsize.Integer(), fill); + return 0; + } + return v->ThrowError("size must be a number"); +} + +VXInteger __map_array(VXState* v, VXArrayObj *dest,VXArrayObj *src) +{ + VXInteger n; + VXInteger size; + VXObject temp; + size = src->Size(); + for(n=0; nGet(n,temp); + v->Push(src); + v->Push(temp); + if(VX_FAILED(v->StackCall(2, true, false))) + { + return VX_ERROR; + } + dest->Set(n, v->GetUp(-1)); + v->Pop(); + } + return 0; +} + + +VXInteger array_map(VXState* v) +{ + VXObject& o = v->StackGet(1); + VXInteger size = o.Array()->Size(); + VXObject ret = v->NewArray(size); + if(VX_FAILED(__map_array(v, ret.Array(), o.Array()))) + return VX_ERROR; + v->Push(ret); + return 1; +} + + +VXInteger array_apply(VXState* v) +{ + VXObject& o = v->StackGet(1); + if(VX_FAILED(__map_array(v, o.Array(), o.Array()))) + { + return VX_ERROR; + } + return 0; +} + +VXInteger array_reduce(VXState* v) +{ + VXObject& o = stack_get(v,1); + VXArrayObj *a = o.Array(); + VXInteger size = a->Size(); + if(size == 0) + { + return 0; + } + VXObject res; + a->Get(0,res); + if(size > 1) + { + VXObject other; + for(VXInteger n = 1; n < size; n++) + { + a->Get(n,other); + v->Push(o); + v->Push(res); + v->Push(other); + if(VX_FAILED(v->StackCall(3,true,false))) + { + return VX_ERROR; + } + res = v->GetUp(-1); + v->Pop(); + } + } + v->Push(res); + return 1; +} + +VXInteger array_filter(VXState* v) +{ + VXObject& o = v->StackGet(1); + VXArrayObj* a = o.Array(); + VXObject ret = v->NewArray(); + VXInteger size = a->Size(); + VXObject val; + for(VXInteger n = 0; n < size; n++) + { + a->Get(n,val); + v->Push(o); + v->Push(n); + v->Push(val); + if(VX_FAILED(v->StackCall(3, true, false))) + { + return VX_ERROR; + } + if(!VXState::IsFalse(v->GetUp(-1))) + { + ret.Array()->Append(val); + } + v->Pop(); + } + v->Push(ret); + return 1; +} + +VXInteger array_find(VXState* v) +{ + bool res; + VXObject temp; + VXInteger found_elements; + VXInteger n; + VXObject& o = v->StackGet(1); + VXObject& val = v->StackGet(2); + VXArrayObj* a = o.Array(); + VXInteger size = a->Size(); + found_elements = 0; + res = false; + for(n=0; nGet(n, temp); + if(VXState::IsEqual(temp, val, res) && res) + { + found_elements++; + } + } + v->Push(found_elements); + return 1; +} + +//QSORT ala Sedgewick +bool _qsort_compare(VXState* v,VXObject &arr,VXObject &a,VXObject &b,VXInteger func,VXInteger &ret) +{ + (void)arr; + if(func < 0) + { + if(!v->ObjCmp(a,b,ret)) + { + return false; + } + } + else + { + VXInteger top = v->GetTop(); + v->Repush(func); + v->Push(v->GetRootTable()); + v->Push(a); + v->Push(b); + if(VX_FAILED(v->CallStack(3, true, false))) + { + if(!v->_lasterror.IsString()) + { + v->ThrowError("compare func failed"); + } + return false; + } + v->GetInteger(-1, &ret); + v->SetTop(top); + return true; + } + return true; +} + +//QSORT ala Sedgewick +bool _qsort(VXState* v,VXObject &arr, VXInteger l, VXInteger r,VXInteger func) +{ + VXInteger i; + VXInteger j; + VXArrayObj *a= arr.Array(); + VXObject pivot,t; + if( l < r ) + { + pivot = a->_values[l]; + i = l; + j = r + 1; + while(1) + { + VXInteger ret; + do + { + ++i; + if(i > r) + { + break; + } + if(!_qsort_compare(v,arr,a->_values[i],pivot,func,ret)) + { + return false; + } + } while( ret <= 0); + do + { + --j; + if (j < 0) + { + v->ThrowError("Invalid qsort, probably compare function defect"); + return false; + } + if(!_qsort_compare(v,arr,a->_values[j],pivot,func,ret)) + { + return false; + } + } + while(ret > 0); + if(i >= j) + { + break; + } + t = a->_values[i]; + a->_values[i] = a->_values[j]; + a->_values[j] = t; + } + t = a->_values[l]; + a->_values[l] = a->_values[j]; + a->_values[j] = t; + if(!_qsort( v, arr, l, j-1,func)) + { + return false; + } + if(!_qsort( v, arr, j+1, r,func)) + { + return false; + } + } + v->Push(arr); + return true; +} + +VXInteger array_sort(VXState* v) +{ + VXInteger func = -1; + VXObject &o = v->StackGet(1); + if(_array(o)->Size() > 1) + { + VXObject clone = o.Array()->Clone(); + if(v->GetTop() == 2) + { + func = 2; + } + if(!_qsort(v, clone, 0, clone.Array()->Size()-1, func)) + { + return VX_ERROR; + } + } + return 1; +} + +VXInteger array_slice(VXState* v) +{ + VXInteger sidx; + VXInteger eidx; + VXObject o; + if(get_slice_params(v, sidx, eidx, o) == -1) + { + return -1; + } + VXInteger alen = o.Array()->Size(); + if(sidx < 0) + { + sidx = alen + sidx; + } + if(eidx < 0) + { + eidx = alen + eidx; + } + if(eidx < sidx) + { + return v->ThrowError("wrong indexes"); + } + if(eidx > alen) + { + return v->ThrowError("slice out of range"); + } + VXArrayObj* arr = v->NewArray(eidx - sidx); + VXObject t; + VXInteger count=0; + for(VXInteger i=sidx;iGet(i,t); + arr->Set(count++,t); + } + v->Push(arr); + return 1; + +} + +VXInteger array_join(VXState* v) +{ + std::string delim; + std::stringstream strm; + VXObject& o = v->StackGet(1); + VXArrayObj *a = o.Array(); + VXInteger size = a->Size(); + VXInteger n; + VXObject temp; + v->GetString(2, &delim); + for(n=0; nGet(n, temp)) + { + VXObject res; + if(v->ToString(temp, res)) + { + res.String()->Get(&stringval, &stringlen); + } + else + { + goto cannot_convert; + } + strm.write(stringval, stringlen); + if((n+1) < size) + { + strm << delim; + } + } + } + v->Push(v->NewString(strm.str().c_str(), strm.str().length())); + return 1; + +cannot_convert: + return v->ThrowError("join(): cannot convert element to string"); +} + +VXInteger array_isset(VXState* v) +{ + bool status; + VXInteger index; + VXObject val; + VXObject& o = v->StackGet(1); + VXArrayObj *a = o.Array(); + v->GetInteger(2, &index); + if(a->Get(index, val)) + { + status = true; + } + else + { + status = false; + } + v->Push(status); + return 1; +} + +VXInteger array_first(VXState* v) +{ + VXObject val; + VXObject& o = v->StackGet(1); + VXArrayObj* a = o.Array(); + a->Get(0, val); + v->Push(val); + return 1; +} + +VXInteger array_last(VXState* v) +{ + VXObject val; + VXObject& o = v->StackGet(1); + VXArrayObj* a = o.Array(); + a->Get(a->Size()-1, val); + v->Push(val); + return 1; +} + +VXRegFunction VXSharedState::_array_default_delegate_funcz[]= +{ + {"weakref", obj_delegate_weakref, 1, NULL}, + {"tostring", default_delegate_tostring, -1, ".b"}, + {"len", default_delegate_len, 1, "a"}, + {"clear", obj_clear, 1, "."}, + {"first", array_first, 1, "a"}, + {"last", array_last, 1, "a"}, + {"append", array_append, 2, "a"}, + {"push", array_append, 2, "a"}, + {"extend", array_extend, 2, "aa"}, + {"pop", array_pop, 1, "a"}, + {"top", array_top, 1, "a"}, + {"insert", array_insert, 3, "an"}, + {"remove", array_remove, 2, "an"}, + {"resize", array_resize, -2, "an"}, + {"reverse", array_reverse, 1, "a"}, + {"sort", array_sort, -1, "ac"}, + {"slice", array_slice, -1, "ann"}, + {"map", array_map, 2, "ac"}, + {"apply", array_apply, 2, "ac"}, + {"reduce", array_reduce, 2, "ac"}, + {"filter", array_filter, 2, "ac"}, + {"find", array_find, 2, "a."}, + {"join", array_join, 2, "as"}, + {"isset", array_isset, 2, "an"}, + {"repr", default_delegate_repr, 1, "."}, + {0, 0, 0, 0} +}; + + diff --git a/src/core/baselib_class.cpp b/src/core/baselib_class.cpp new file mode 100644 index 0000000..85f93bb --- /dev/null +++ b/src/core/baselib_class.cpp @@ -0,0 +1,91 @@ + +#include "baselib.hpp" + +VXInteger class_getattributes(VXState* v) +{ + VXObject& o = v->StackGet(1); + VXObject &key = v->StackGet(2); + VXObject attrs; + if(o.Class()->GetAttributes(key,attrs)) + { + v->Push(attrs); + return 1; + } + return v->ThrowError("wrong index"); +} + + +VXInteger class_setattributes(VXState* v) +{ + VXObject& o = v->StackGet(1); + VXObject& key = v->StackGet(2); + VXObject& val = v->StackGet(3); + VXObject attrs; + if(key.Type() == VX_OT_NULL) + { + attrs = o.Class()->_attributes; + o.Class()->_attributes = val; + v->Push(attrs); + return 1; + } + else if(o.Class()->GetAttributes(key,attrs)) + { + o.Class()->SetAttributes(key, val); + v->Push(attrs); + return 1; + } + return v->ThrowError("wrong index"); +} + +VXInteger class_instance(VXState* v) +{ + VXObject& o = v->StackGet(1); + v->Push(o.Class()->CreateInstance()); + return 1; +} + +VXInteger class_getbase(VXState* v) +{ + VXObject& o = v->StackGet(1); + if(o.Class()->_base) + { + v->Push(o.Class()->_base); + return 1; + } + return 0; +} + +VXInteger instance_getclass(VXState* v) +{ + VXObject& o = v->StackGet(1); + v->Push(o.Instance()->_class); + return 1; +} + + +VXRegFunction VXSharedState::_class_default_delegate_funcz[] = +{ + {"weakref", obj_delegate_weakref, 1, NULL }, + {"tostring", default_delegate_tostring, -1, ".b"}, + {"rawget", container_rawget, 2, "y"}, + {"rawset", container_rawset, 3, "y"}, + {"instance", class_instance, 1, "y"}, + {"getbase", class_getbase, 1, "y"}, + {"getattributes", class_getattributes, 2, "y."}, + {"setattributes", class_setattributes, 3, "y.."}, + {"repr", default_delegate_repr, 1, "."}, + {0, 0, 0, 0} +}; + + +VXRegFunction VXSharedState::_instance_default_delegate_funcz[] = +{ + {"weakref", obj_delegate_weakref, 1, NULL }, + {"tostring", default_delegate_tostring, -1, ".b"}, + {"rawget", container_rawget, 2, "x"}, + {"rawset", container_rawset, 3, "x"}, + {"getclass", instance_getclass, 1, "x"}, + {"repr", default_delegate_repr, 1, "."}, + {0, 0, 0, 0} +}; + diff --git a/src/core/baselib_closure.cpp b/src/core/baselib_closure.cpp new file mode 100644 index 0000000..1fc4f57 --- /dev/null +++ b/src/core/baselib_closure.cpp @@ -0,0 +1,125 @@ + +#include "baselib.hpp" + + +VXInteger closure_pcall(VXState* v) +{ + //return VX_SUCCEEDED(vox_call(v,vox_gettop(v)-1,true,false))?1:VX_ERROR; + return v->CallStack(v->GetTop()-1, true, false); +} + +VXInteger closure_call(VXState* v) +{ + bool raise; + if(VX_FAILED(v->GetBool(3, &raise))) + { + raise = true; + } + if(VX_FAILED(v->CallStack(v->GetTop()-1, true, raise))) + { + return VX_ERROR; + } + return 1; +} + +VXInteger _closure_acall(VXState* v,bool raiseerror) +{ + VXInteger i; + VXArrayObj *aparams = v->StackGet(2).Array(); + VXInteger nparams = aparams->Size(); + v->Push(v->StackGet(1)); + for(i=0; iPush(aparams->_values[i]); + } + return v->CallStack(nparams, true, raiseerror); +} + +VXInteger closure_acall(VXState* v) +{ + return _closure_acall(v,true); +} + +VXInteger closure_pacall(VXState* v) +{ + return _closure_acall(v,false); +} + +VXInteger closure_bindenv(VXState* v) +{ + VXObject res; + if(VX_FAILED(v->BindEnv(v->StackGet(1), v->StackGet(2), res))) + { + return VX_ERROR; + } + v->Push(res); + return 1; +} + +VXInteger closure_getinfos(VXState* v) +{ + VXInteger n; + bool native; + VXObject filename; + VXObject funcname; + VXObject sourcename; + VXRawObj o = v->StackGet(1); + VXTableObj* res = v->NewTable(); + if(type(o) == VX_OT_CLOSURE) + { + VXFuncProtoObj* f = _closure(o)->_function; + VXInteger nparams = f->_nparameters + (f->_varparams?1:0); + VXObject params = v->NewArray(nparams); + for(n=0; n<(f->_nparameters); n++) + { + _array(params)->Set(n, f->_parameters[n]); + } + if(f->_varparams) + { + _array(params)->Set(nparams-1, v->NewString("...")); + } + native = false; + funcname = f->_name; + filename = f->_sourcename; + res->NewSlot(v->NewString("parameters"), params); + res->NewSlot(v->NewString("varargs"), f->_varparams); + } + else //VX_OT_NATIVECLOSURE + { + VXNativeClosureObj *nc = _nativeclosure(o); + native = true; + funcname = nc->_name.String(); + filename = v->NewString("[native]"); + res->NewSlot(v->NewString("paramscheck"), nc->_nparamscheck); + VXObject typecheck; + if(nc->_typecheck.size() > 0) + { + typecheck = v->NewArray(nc->_typecheck.size()); + for(VXUnsignedInteger n = 0; n_typecheck.size(); n++) + { + _array(typecheck)->Set((VXInteger)n, nc->_typecheck[n]); + } + } + res->NewSlot(v->NewString("typecheck"), typecheck); + } + res->NewSlot(v->NewString("native"), native); + res->NewSlot(v->NewString("name"), funcname); + res->NewSlot(v->NewString("src"), filename); + v->Push(res); + return 1; +} + +VXRegFunction VXSharedState::_closure_default_delegate_funcz[]= +{ + {"call", closure_call, -1, "c"}, + {"pcall", closure_pcall, -1, "c"}, + {"acall", closure_acall, 2, "ca"}, + {"pacall", closure_pacall, 2, "ca"}, + {"weakref", obj_delegate_weakref, 1, NULL }, + {"tostring", default_delegate_tostring, -1, ".b"}, + {"bindenv", closure_bindenv, 2, "c x|y|t"}, + {"getinfos", closure_getinfos, 1, "c"}, + {0, 0, 0, 0} +}; + + diff --git a/src/core/baselib_generator.cpp b/src/core/baselib_generator.cpp new file mode 100644 index 0000000..3d4bd86 --- /dev/null +++ b/src/core/baselib_generator.cpp @@ -0,0 +1,35 @@ + +#include "baselib.hpp" +#include "names.hpp" + +VXInteger generator_getstatus(VXState* v) +{ + VXRawObj &o=stack_get(v,1); + switch(_generator(o)->_state) + { + case VXGeneratorObj::eSuspended: + v->Push(VXStringObj::Create(_ss(v), GENERATOR_STATUS_SUSPENDED)); + break; + case VXGeneratorObj::eRunning: + v->Push(VXStringObj::Create(_ss(v), GENERATOR_STATUS_RUNNING)); + break; + case VXGeneratorObj::eDead: + v->Push(VXStringObj::Create(_ss(v), GENERATOR_STATUS_DEAD)); + break; + } + return 1; +} + +VXRegFunction VXSharedState::_generator_default_delegate_funcz[]= +{ + {"getstatus", generator_getstatus, 1, "g"}, + {"weakref", obj_delegate_weakref, 1, NULL }, + {"tostring", default_delegate_tostring, -1, ".b"}, + {"repr", default_delegate_repr, 1, "."}, + {0, 0, 0, 0} +}; + + + + + diff --git a/src/core/baselib_hashlib.cpp b/src/core/baselib_hashlib.cpp new file mode 100644 index 0000000..d2477ce --- /dev/null +++ b/src/core/baselib_hashlib.cpp @@ -0,0 +1,117 @@ + +#include "baselib.hpp" +#include "hash.hpp" + +template struct VXHashProxy +{ + Type* instance; + + VXHashProxy() + { + this->instance = new Type; + } + + ~VXHashProxy() + { + delete this->instance; + } +}; + + +template VXInteger hashclass_releasehook(VXUserPointer p, VXInteger) +{ + VXHashProxy* self = (VXHashProxy*)p; + delete self; + return 1; +} + +template VXInteger hashclass_constructor(VXState* v) +{ + VXHashProxy* self; + self = new VXHashProxy; + v->SetInstanceUp(1, (VXUserPointer*)&self); + v->SetReleaseHook(1, hashclass_releasehook); + return 1; +} + +VXInteger hashclass_update(VXState* v) +{ + VXHashProxy* self; + std::string value; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + v->GetString(2, &value); + self->instance->update(value); + return VX_OK; +} + +VXInteger hashclass_update_char(VXState* v) +{ + VXHashProxy* self; + VXInteger value; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + v->GetInteger(2, &value); + self->instance->update(value); + return VX_OK; +} + +VXInteger hashclass_update_file(VXState* v) +{ + VXHashProxy* self; + std::string path; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + v->GetString(2, &path); + self->instance->updateFromFile(path); + return VX_OK; +} + +VXInteger hashclass_finalize(VXState* v) +{ + VXHashProxy* self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + self->instance->finalize(); + return VX_OK; +} + +VXInteger hashclass_hexdigest(VXState* v) +{ + VXHashProxy* self; + std::string hd; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + try + { + hd = self->instance->hexDigest(); + v->Push(v->NewString(hd.c_str(), hd.length())); + return 1; + } + catch(Hash::Error& err) + { + return v->ThrowError(err.what()); + } + return VX_ERROR; +} + +template VXRegFunction* hashfuncs() +{ + static VXRegFunction funcs[] = + { + {"constructor", hashclass_constructor, 0, "x"}, + {"update", hashclass_update, 2, ".s"}, + {"update_char", hashclass_update_char, 2, ".n"}, + {"update_file", hashclass_update_file, 2, ".s"}, + {"finalize", hashclass_finalize, 0, "x"}, + {"hexdigest", hashclass_hexdigest, 0, "x"}, + {0, 0, 0, 0}, + }; + return funcs; +} + +VXInteger voxstd_register_hashlib(VXState* v) +{ + VXTableObj* tb; + tb = v->NewTable(); + tb->NewSlot(v->NewString("SHA1"), v->RegClass(hashfuncs())); + tb->NewSlot(v->NewString("MD5"), v->RegClass(hashfuncs())); + v->GetRootTable()->NewSlot(v->NewString("hashlib"), tb); + return VX_OK; +} + diff --git a/src/core/baselib_io.cpp b/src/core/baselib_io.cpp new file mode 100644 index 0000000..c6f9b7a --- /dev/null +++ b/src/core/baselib_io.cpp @@ -0,0 +1,496 @@ + +/* here be dragons + you have been warned */ + +#include +#include +#include +#include +#include +#include +#include "baselib.hpp" + +#define IOLIB_STDOUT_PTRNAME "__HSTDOUT" +#define IOLIB_STDERR_PTRNAME "__HSTDERR" +#define IOLIB_STDIN_PTRNAME "__HSTDIN" +#define IOLIB_PTRCLASS_NAME "__ioclass_fileptr" + +#define VXIO_CHECKVALID(v, self) \ + if((self)->isvalid == false) \ + { \ + return ioclass_fn_invalidhandle(v, self); \ + } + +#define IOTYPETAG (('I' << 24) | ('O' << 16) | ('S' << 8) | 'C') + +#define SETUP(v, self) \ + vox_assert(VX_SUCCEEDED(v->GetInstanceUp(1, (VXUserPointer*)&self, 0))); \ + /*if(self == NULL) { return v->ThrowError("GetInstanceUp() returned NULL?"); }*/ \ + vox_assert(self != NULL && "GetInstanceUp() returned NULL"); + +struct VXIOStream +{ + FILE* stream; + bool isvalid; + bool isclosed; + const char* name; + + VXIOStream() + { + this->stream = NULL; + this->isvalid = false; + this->isclosed = false; + } + + bool open(const char* path, const char* mode) + { + this->name = path; + if((this->stream = fopen(path, mode)) == NULL) + { + return false; + } + this->isvalid = true; + return true; + } + + bool open(FILE* strm) + { + this->stream = strm; + this->isclosed = true; + this->isvalid = true; + return true; + } + + const char* error() + { + return strerror(errno); + } + + bool close() + { + if(this->isclosed == false) + { + fclose(this->stream); + this->isclosed = true; + } + return true; + } + + size_t readbuf(char* buffer, size_t howmuch, size_t nmemb=1) + { + size_t haveread; + haveread = fread(buffer, nmemb, howmuch, this->stream); + return haveread; + } + + void readline(std::vector& buffer) + { + VXInteger cur; + while((cur = this->readchar()) != EOF) + { + if(cur == '\n') + { + break; + } + buffer.push_back(cur); + } + } + + bool eof() + { + return feof(this->stream) != 0; + } + + template + bool write(const CharT* data, size_t length, VXInteger* written) + { + size_t actually_written; + *written = 0; + actually_written = fwrite(data, sizeof(CharT), length, this->stream); + if(actually_written < length) + { + return false; + } + *written = actually_written; + return true; + } + + bool flushstream() + { + if(fflush(this->stream) == EOF) + { + return false; + } + return true; + } + + int readchar() + { + return fgetc(this->stream); + } +}; + +void decl_fileptr(VXState* v, const char* name, const char* ptrname) +{ + v->DoStringFmt(true, false, false, "::io.%s := ::io.%s(::io.%s);", + name, IOLIB_PTRCLASS_NAME, ptrname); +} + +void del_member(VXState* v, const char* name) +{ + v->DoStringFmt(true, false, false, "delete ::io.%s;", name); +} + +VXInteger iolib_readfile(VXState* v) +{ + VXInteger c; + VXIOStream stream; + std::vector buffer; + const char* filename; + v->GetString(2, &filename, NULL); + if(!stream.open(filename, "rb")) + { + return v->ThrowError(stream.error()); + } + while((c = stream.readchar()) != EOF) + { + buffer.push_back(c); + } + stream.close(); + v->PushString(&buffer[0], buffer.size()); + return 1; +} + +VXInteger iolib_writefile(VXState* v) +{ + VXIOStream stream; + VXInteger written; + VXInteger len; + bool append; + const char* filename; + const char* data; + std::vector buffer; + v->GetString(2, &filename, NULL); + v->GetString(3, &data, &len); + if(VX_FAILED(v->GetBool(4, &append))) + { + append = false; + } + if(!stream.open(filename, append ? "a" : "w")) + { + return v->ThrowError(stream.error()); + } + if(stream.write(data, len, &written) == false) + { + return v->ThrowError(stream.error()); + } + stream.close(); + v->Push(written); + return 1; +} + + + +VXInteger iolib_read(VXState* v) +{ + VXInteger actual; + VXInteger howmuch; + VXIOStream stream; + char* buf; + stream.open(stdin); + if(!VX_FAILED(v->GetInteger(2, &howmuch))) + { + howmuch = 1024; + } + buf = new char[howmuch+1]; + actual = stream.readbuf(buf, howmuch); + v->Push(v->NewString(buf, actual)); + delete[] buf; + return 1; +} + +VXInteger iolib_readline(VXState* v) +{ + std::vector buffer; + VXIOStream stream; + stream.open(stdin); + stream.readline(buffer); + if(buffer.size() == 0) + { + return 0; + } + v->Push(v->NewString(&buffer[0], buffer.size())); + return 1; +} + +VXInteger iolib_readchar(VXState* v) +{ + char ch; + VXIOStream hnd; + hnd.open(stdin); + ch = hnd.readchar(); + if(ch == EOF) + { + v->PushNull(); + } + else + { + v->Push(VXInteger(ch)); + } + return 1; +} + +VXInteger ioclass_fn_invalidhandle(VXState* v, VXIOStream* self) +{ + (void)self; + return v->ThrowError("invalid i/o handle (%f)"); +} + +VXInteger ioclass_fn_releasehook(VXUserPointer p, VXInteger size) +{ + (void)size; + VXIOStream* self = (VXIOStream*)p; + if(self->isclosed == false) + { + self->close(); + } + delete self; + return 1; +} + +VXInteger ioclass_fn_read(VXState* v) +{ + char* buffer; + VXInteger howmuch; + VXInteger haveread; + VXIOStream* self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + VXIO_CHECKVALID(v, self) + if(VX_FAILED(v->GetInteger(2, &howmuch))) + { + howmuch = 1024; + } + buffer = new char[howmuch+1]; + haveread = self->readbuf(buffer, howmuch); + if(haveread > 0) + { + buffer[haveread] = 0; + v->PushString(buffer, haveread); + } + else + { + v->PushNull(); + } + delete[] buffer; + return 1; +} + +VXInteger ioclass_fn_flush(VXState* v) +{ + VXIOStream* self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + VXIO_CHECKVALID(v, self) + v->Push(self->flushstream()); + return 1; +} + +VXInteger ioclass_fn_name(VXState* v) +{ + VXIOStream* self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + VXIO_CHECKVALID(v, self) + v->PushString(self->name); + return 1; +} + +VXInteger ioclass_fn_readline(VXState* v) +{ + VXIOStream* self; + std::vector buffer; + SETUP(v, self) + VXIO_CHECKVALID(v, self) + if(self->eof()) + { + return 0; + } + self->readline(buffer); + v->Push(v->NewString(&buffer[0], buffer.size())); + return 1; +} + +VXInteger ioclass_fn_readchar(VXState* v) +{ + VXIOStream* self; + VXInteger c; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + VXIO_CHECKVALID(v, self) + c = self->readchar(); + /* make use of the fact that vox has a nulltype/nullvalue, + and push null when EOF is reached*/ + if(c == EOF) + { + v->PushNull(); + } + else + { + v->Push(c); + } + return 1; +} + + +VXInteger ioclass_fn_close(VXState* v) +{ + VXIOStream* self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + VXIO_CHECKVALID(v, self) + v->Push(self->close()); + return 1; +} + +VXInteger ioclass_fn_write(VXState* v) +{ + const char* data; + VXInteger len; + VXInteger written; + VXIOStream* self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + VXIO_CHECKVALID(v, self) + v->GetString(2, &data, &len); + if(self->write(data, len, &written) == true) + { + v->Push(written); + return 0; + } + /* when the file got opened in readonly mode, write() + will fail, so don't just ignore it, but handle it */ + return v->ThrowError(self->error()); +} + +VXInteger ioclass_fn_eof(VXState* v) +{ + VXIOStream* self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + VXIO_CHECKVALID(v, self) + v->Push(bool(self->eof())); + return 1; +} + +VXInteger ioclass_fn_constructor(VXState* v) +{ + const char* path; + const char* mode; + VXIOStream* self; + self = new VXIOStream; + v->GetString(2, &path, NULL); + if(VX_FAILED(v->GetString(3, &mode, NULL))) + { + mode = "r"; + } + if(!self->open(path, mode)) + { + return v->ThrowError("%s: %s", self->error(), path); + } + v->SetInstanceUp(1, (VXUserPointer*)&self); + v->SetReleaseHook(1, ioclass_fn_releasehook); + return 0; +} + +VXInteger ioclass_fn_constructor_ptr(VXState* v) +{ + VXIOStream* self; + self = new VXIOStream; + v->GetUserPointer(2, (VXUserPointer*)&(self->stream)); + if(self->stream == NULL) + { + return v->ThrowError("invalid i/o pointer"); + } + self->isvalid = true; + v->SetInstanceUp(1, (VXUserPointer*)&self); + v->SetReleaseHook(1, ioclass_fn_releasehook); + return 0; +} + +VXInteger ioclass_fn_typeof(VXState* v) +{ + v->PushString("file"); + return 1; +} + +VXInteger ioclass_fn_cloned(VXState* v) +{ + return v->ThrowError("cannot clone a file descriptor"); +} + +VXRegFunction mkreg(const char* name, VXFunction func, + VXInteger nparamscheck, const char* typemask) +{ + VXRegFunction fn; + fn.name = name; + fn.func = func; + fn.nparamscheck = nparamscheck; + fn.typemask = typemask; + return fn; +} + +VXVector get_funcs(bool isptrclass) +{ + VXVector funcs; + VXFunction ctor = ioclass_fn_constructor; + VXInteger ctor_args = -1; + const char* ctor_tm = ".ss"; + if(isptrclass) + { + ctor_args = 2; + ctor = ioclass_fn_constructor_ptr; + ctor_tm = NULL; + } + funcs.push_back(mkreg("constructor", ctor, ctor_args, ctor_tm)); + funcs.push_back(mkreg("name", ioclass_fn_name, -1, ".n")); + funcs.push_back(mkreg("readchar", ioclass_fn_readchar, 1, NULL)); + funcs.push_back(mkreg("readline", ioclass_fn_readline, -1, NULL)); + funcs.push_back(mkreg("write", ioclass_fn_write, 2, ".s")); + funcs.push_back(mkreg("close", ioclass_fn_close, 1, NULL)); + funcs.push_back(mkreg("flush", ioclass_fn_flush, 1, "x")); + funcs.push_back(mkreg("eof", ioclass_fn_eof, 1, "x")); + funcs.push_back(mkreg("__typeof__", ioclass_fn_typeof, 1, "x")); + funcs.push_back(mkreg("__cloned__", ioclass_fn_cloned, -1, NULL)); + return funcs; +} + +static VXRegFunction iolib_funcs[]= +{ + {"readfile", iolib_readfile, 2, ".s"}, + {"writefile", iolib_writefile, -1, ".ssb"}, + {"read", iolib_read, -1, NULL}, + {"readline", iolib_readline, -1, NULL}, + {"readchar", iolib_readchar, -1, NULL}, + {0, 0, 0, 0}, +}; + + +VXInteger voxstd_register_iolib(VXState* v) +{ + VXTableObj* tb; + tb = v->NewTable(); + tb->NewSlot(v->NewString("open"), v->RegClass(get_funcs(false))); + tb->NewSlot(v->NewString(IOLIB_PTRCLASS_NAME), v->RegClass(get_funcs(true))); + tb->NewSlot(v->NewString(IOLIB_STDOUT_PTRNAME), VXUserPointer(stdout)); + tb->NewSlot(v->NewString(IOLIB_STDERR_PTRNAME), VXUserPointer(stderr)); + tb->NewSlot(v->NewString(IOLIB_STDIN_PTRNAME), VXUserPointer(stdin)); + v->RegisterLib("io", iolib_funcs, true, tb); + + // declare filehandle members + decl_fileptr(v, "stdout", IOLIB_STDOUT_PTRNAME); + decl_fileptr(v, "stderr", IOLIB_STDERR_PTRNAME); + decl_fileptr(v, "stdin", IOLIB_STDIN_PTRNAME); + + // cleanup the ungodly mess we created + del_member(v, IOLIB_STDOUT_PTRNAME); + del_member(v, IOLIB_STDERR_PTRNAME); + del_member(v, IOLIB_STDIN_PTRNAME); + del_member(v, IOLIB_PTRCLASS_NAME); + return 1; +} + + diff --git a/src/core/baselib_math.cpp b/src/core/baselib_math.cpp new file mode 100644 index 0000000..504af0f --- /dev/null +++ b/src/core/baselib_math.cpp @@ -0,0 +1,191 @@ + +#include "baselib.hpp" +#include +#include + + +#ifndef M_PI +# define M_PI (3.14159265358979323846) +#endif + + +#define single_arg_func(InType, OutType, v, fn_cb) \ + do \ + { \ + InType arg; \ + VXObject& ob = v->StackGet(2); \ + arg = ob.As(); \ + v->Push((OutType)(fn_cb(arg))); \ + } while(0); + +#define float_func(v, fn_cb) \ + single_arg_func(VXFloat, VXFloat, v, fn_cb) + +#define int_func(v, fn_cb) \ + single_arg_func(VXInteger, VXInteger, v, fn_cb) + +VXInteger math_srand(VXState* v) +{ + VXInteger seed; + if(VX_FAILED(v->GetInteger(2, &seed))) + { + seed = time(NULL); + } + srand((unsigned int)seed); + return 0; +} + +VXInteger math_rand(VXState* v) +{ + v->Push(VXInteger(rand())); + return 1; +} + +VXInteger math_abs(VXState* v) +{ + int_func(v, cos); + return 1; +} + +VXInteger math_sqrt(VXState* v) +{ + float_func(v, sqrt); + return 1; +} + +VXInteger math_fabs(VXState* v) +{ + float_func(v, fabs); + return 1; +} + +VXInteger math_sin(VXState* v) +{ + float_func(v, sin); + return 1; +} + +VXInteger math_cos(VXState* v) +{ + float_func(v, cos); + return 1; +} + + +VXInteger math_asin(VXState* v) +{ + float_func(v, asin); + return 1; +} + + +VXInteger math_acos(VXState* v) +{ + float_func(v, acos) + return 1; +} + + +VXInteger math_log(VXState* v) +{ + float_func(v, log) + return 1; +} + + +VXInteger math_log10(VXState* v) +{ + float_func(v, log10) + return 1; +} + + +VXInteger math_tan(VXState* v) +{ + float_func(v, tan) + return 1; +} + + +VXInteger math_atan(VXState* v) +{ + float_func(v, atan) + return 1; +} + + +VXInteger math_floor(VXState* v) +{ + float_func(v, floor) + return 1; +} + + +VXInteger math_ceil(VXState* v) +{ + float_func(v, ceil) + return 1; +} + + +VXInteger math_exp(VXState* v) +{ + float_func(v, ceil) + return 1; +} + + +VXInteger math_atan2(VXState* v) +{ + VXFloat p1; + VXFloat p2; + v->GetFloat(2, &p1); + v->GetFloat(3, &p2); + v->Push(VXFloat(atan2(p1, p2))); + return 1; +} + + +VXInteger math_pow(VXState* v) +{ + VXFloat p1, p2; + v->GetFloat(2, &p1); + v->GetFloat(3, &p2); + v->Push(VXFloat(pow(p1, p2))); + return 1; +} + + +static VXRegFunction vox_mathlib_funcs[] = +{ + + {"sqrt", math_sqrt, 2, ".n"}, + {"sin", math_sin, 2, ".n"}, + {"cos", math_cos, 2, ".n"}, + {"asin", math_asin, 2, ".n"}, + {"acos", math_acos, 2, ".n"}, + {"log", math_log, 2, ".n"}, + {"log10", math_log10, 2, ".n"}, + {"tan", math_tan, 2, ".n"}, + {"atan", math_atan, 2, ".n"}, + {"atan2", math_atan2, 3, ".nn"}, + {"pow", math_pow, 3, ".nn"}, + {"floor", math_floor, 2, ".n"}, + {"ceil", math_ceil, 2, ".n"}, + {"exp", math_exp, 2, ".n"}, + {"srand", math_srand, -1, ".n"}, + {"rand", math_rand, 1, NULL}, + {"fabs", math_fabs, 2, ".n"}, + {"abs", math_abs, 2, ".n"}, + {0, 0, 0, 0}, +}; + +VXInteger voxstd_register_mathlib(VXState* v) +{ + VXTableObj* tb = v->RegisterLib("math", vox_mathlib_funcs, true); + tb->NewSlot(v->NewString("PI"), VXFloat(M_PI)); + v->Push(tb); + return 1; +} + + diff --git a/src/core/baselib_string.cpp b/src/core/baselib_string.cpp new file mode 100644 index 0000000..4e065fe --- /dev/null +++ b/src/core/baselib_string.cpp @@ -0,0 +1,757 @@ + +#include "baselib.hpp" +#include "string.hpp" +#include +#include +#include +#include + +#define MAX_FORMAT_LEN 20 +#define MAX_WFORMAT_LEN 3 +#define ADDITIONAL_FORMAT_SPACE (100*sizeof(char)) +#define SOUNDEX_TABLE "01230120022455012623010202" +#define SOUNDEX_NULBIT "0000" + +int strhelp_find(const std::string& subject, const std::string& findme) +{ + int n = 0; + std::string ::size_type pos = 0; + while((pos = subject.find(findme, pos)) != std::string::npos) + { + n++; + pos += findme.size(); + } + return n; +} + + +std::string strhelp_soundex(const std::string& subject) +{ + int count; + char* instr; + char* outptr; + std::string result; + std::string istring; + std::vector buffer; + buffer.reserve(16); + istring = subject; + instr = (char*)(istring.c_str()); + outptr = &buffer[0]; + count = 0; + while(!isalpha(instr[0]) && instr[0]) + { + ++instr; + } + if(toupper(instr[0]) == 'P' && toupper(instr[1]) == 'H') + { + instr[0] = 'F'; + instr[1] = 'A'; + } + *outptr++ = toupper(*instr++); + while(*instr && count < 5) + { + if(isalpha(*instr) && *instr != *(instr-1)) + { + *outptr = SOUNDEX_TABLE[toupper(instr[0]) - 'A']; + if(*outptr != '0') + { + ++outptr; + ++count; + } + } + ++instr; + } + /* the following line is practically pointless, + but kept for "historical purpose" */ + *outptr = '\0'; + result.append((std::string(&buffer[0]) + SOUNDEX_NULBIT).substr(0, 4)); + return result; +} + +std::string strhelp_replace(const std::string& str, + const std::string& from, + const std::string& to) +{ + std::string tmp = str; + size_t start_pos = 0; + while((start_pos = tmp.find(from, start_pos)) != std::string::npos) + { + tmp.replace(start_pos, from.length(), to); + // In case $to contains $from, like replacing 'x' with 'yx' + start_pos += to.length(); + } + return tmp; +} + +std::string strhelp_quote(const std::string& str, bool escape_only) +{ + int ch; + int quote = 34; + std::string res; + std::string::const_iterator iter; + if(!escape_only) res.push_back(quote); + for(iter=str.begin(); iter!=str.end(); iter++) + { + ch = *iter; + switch(ch) + { + case '\\': + res.push_back('\\'); + res.push_back(ch); + break; + case '"': + res.append("\\\""); + break; + default: + if(ch == 0 || iscntrl(ch) || ch > SCHAR_MAX) + { + int fmtres; + int maxlen = 30; + char cbuf[maxlen+1]; + fmtres = snprintf(cbuf, maxlen, "\\x%02X", ch); + res.append(cbuf, fmtres); + } + else + { + res.push_back(ch); + } + break; + } + } + if(!escape_only) res.push_back(quote); + return res; +} + + + +void strhelp_trim_l(const char *str,const char **start) +{ + const char *t = str; + while(((*t) != '\0') && isspace(*t)) + { + t++; + } + *start = t; +} + +void strhelp_trim_r(const char *str,VXInteger len,const char **end) +{ + const char* t; + if(len == 0) + { + *end = str; + return; + } + t = &str[len-1]; + while(t != str && isspace(*t)) + { + t--; + } + *end = t+1; +} + +bool strhelp_startswith(const char* subject, VXInteger subject_len, + const char* search, VXInteger search_len) +{ + if(subject_len < search_len) + { + return false; + } + return strncmp(subject, search, search_len) == 0; +} + + +bool strhelp_endswith(const char* subject, VXInteger subject_len, + const char* search, VXInteger search_len) +{ + if(subject_len < search_len) + { + return false; + } + return strncmp(subject + subject_len - search_len, search, search_len) == 0; +} +std::vector strhelp_split(const std::string& s, + const std::string& delim, + const bool keep_empty = true) +{ + // have to use std::vector, because split depends on + // iterator magic + std::vector result; + if (delim.empty()) + { + result.push_back(s); + return result; + } + std::string::const_iterator substart = s.begin(), subend; + while(true) + { + subend = std::search(substart, s.end(), delim.begin(), delim.end()); + std::string temp(substart, subend); + if (keep_empty || !temp.empty()) + { + result.push_back(temp); + } + if (subend == s.end()) + { + break; + } + substart = subend + delim.size(); + } + return result; +} + +VXInteger stringdeleg_quote(VXState* v) +{ + std::string subject; + std::string result; + v->GetString(1, &subject); + result = strhelp_quote(subject, false); + v->Push(v->NewString(result.c_str(), result.length())); + return 1; +} + +VXInteger stringdeleg_escape(VXState* v) +{ + std::string subject; + std::string result; + v->GetString(1, &subject); + result = strhelp_quote(subject, true); + v->Push(v->NewString(result.c_str(), result.length())); + return 1; +} + +VXInteger stringdeleg_replace(VXState* v) +{ + std::string subject; + std::string search; + std::string repl; + std::string result; + v->GetString(1, &subject); + v->GetString(2, &search); + v->GetString(3, &repl); + result = strhelp_replace(subject, search, repl); + v->Push(v->NewString(result.c_str(), result.length())); + return 1; +} + +VXInteger stringdeleg_soundex(VXState* v) +{ + std::string subject; + std::string result; + v->GetString(1, &subject); + result = strhelp_soundex(subject); + v->Push(v->NewString(result.c_str(), result.length())); + return 1; +} + +VXInteger stringdeleg_reverse(VXState* v) +{ + VXInteger subj_len; + VXInteger count; + VXInteger index; + const char* subject; + char* buf; + v->GetString(1, &subject, &subj_len); + buf = new char[subj_len + 1]; + for(index=subj_len-1,count=0;index>=0;index--,count++) + { + buf[count] = subject[index]; + } + buf[count] = '\0'; + v->Push(v->NewString(buf, count)); + delete[] buf; + return 1; +} + +VXInteger stringdeleg_startswith(VXState* v) +{ + VXInteger subject_len; + VXInteger search_len; + const char* subject; + const char* search; + v->GetString(1, &subject, &subject_len); + v->GetString(2, &search, &search_len); + v->Push(strhelp_startswith(subject, subject_len, search, search_len)); + return 1; +} + +VXInteger stringdeleg_endswith(VXState* v) +{ + VXInteger subject_len; + VXInteger search_len; + const char* subject; + const char* search; + v->GetString(1, &subject, &subject_len); + v->GetString(2, &search, &search_len); + v->Push(strhelp_endswith(subject, subject_len, search, search_len)); + return 1; +} + +VXInteger stringdeleg_trim(VXState* v) +{ + VXInteger len; + const char* str; + const char* start; + const char* end; + v->GetString(1, &str, &len); + strhelp_trim_l(str, &start); + strhelp_trim_r(str, len, &end); + v->Push(v->NewString(start, end - start)); + return 1; +} + +VXInteger stringdeleg_ltrim(VXState* v) +{ + const char* str; + const char* start; + v->GetString(1, &str, NULL); + strhelp_trim_l(str, &start); + v->Push(v->NewString(start)); + return 1; +} + +VXInteger stringdeleg_rtrim(VXState* v) +{ + VXInteger len; + const char* str; + const char* end; + v->GetString(1, &str, &len); + strhelp_trim_r(str, len, &end); + v->Push(v->NewString(str, end - str)); + return 1; +} + + +VXInteger stringdeleg_split(VXState* v) +{ + bool keep_empty; + std::string str; + std::string delim; + std::vector values; + std::vector::iterator iter; + v->GetString(1, &str); + v->GetString(2, &delim); + if(VX_FAILED(v->GetBool(3, &keep_empty))) + { + keep_empty = true; + } + values = strhelp_split(str, delim, keep_empty); + VXArrayObj* arr = v->NewArray(); + for(iter=values.begin(); iter!=values.end(); iter++) + { + std::string item = *iter; + arr->Append(v->NewString(item.c_str(), item.length())); + } + v->Push(arr); + return 1; +} + +VXInteger stringdeleg_slice(VXState* v) +{ + VXInteger sidx; + VXInteger eidx; + VXInteger slen; + VXObject o; + if(VX_FAILED(get_slice_params(v,sidx,eidx,o))) + { + return -1; + } + slen = o.String()->_len; + if(sidx < 0) + { + sidx = slen + sidx; + } + if(eidx < 0) + { + eidx = slen + eidx; + } + if(eidx < sidx) + { + return v->ThrowError("wrong indexes"); + } + if(eidx > slen) + { + return v->ThrowError("slice out of range"); + } + v->Push(v->NewString(&_stringval(o)[sidx], eidx-sidx)); + return 1; +} + + +VXInteger stringdeleg_substr(VXState* v) +{ + std::string newstr; + std::string str; + std::string::size_type offset; + std::string::size_type count; + v->GetString(1, &str); + v->GetInteger(2, (VXInteger*)&offset); + if(VX_FAILED(v->GetInteger(3, (VXInteger*)&count))) + { + count = std::string::npos; + } + if(offset > str.length()) + { + return v->ThrowError("offset is out of range"); + } + newstr = str.substr(offset, count); + v->Push(v->NewString(newstr.c_str(), newstr.length())); + return 1; +} + +VXInteger stringdeleg_indexof(VXState* v) +{ + std::string str; + std::string findme; + std::string::size_type found; + v->GetString(1, &str); + v->GetString(2, &findme); + found = str.find(findme); + if(found == std::string::npos) + { + return 0; + } + v->Push(VXInteger(found)); + return 1; +} + +VXInteger stringdeleg_findall(VXState* v) +{ + std::string str; + std::string findme; + std::string::size_type found; + v->GetString(1, &str); + v->GetString(2, &findme); + found = str.find(findme); + if(found == std::string::npos) + { + return 0; + } + VXArrayObj* arr = v->NewArray(); + std::string::size_type pos = 0; + while((pos = str.find(findme, pos)) != std::string::npos) + { + arr->Append(VXInteger(pos)); + pos += findme.size(); + } + v->Push(arr); + return 1; +} + +VXInteger stringdeleg_count(VXState* v) +{ + std::string str; + std::string findme; + std::string::size_type found; + v->GetString(1, &str); + v->GetString(2, &findme); + found = strhelp_find(str, findme); + v->Push(VXInteger(found)); + return 1; +} + +VXInteger validate_format(VXState* v, + char *fmt, + const char *src, + VXInteger n, + VXInteger& width) +{ + char swidth[MAX_WFORMAT_LEN]; + VXInteger wc = 0; + VXInteger start = n; + fmt[0] = '%'; + while (strchr("-+ #0", src[n])) + { + n++; + } + while (isdigit(src[n])) + { + swidth[wc] = src[n]; + n++; + wc++; + if(wc >= MAX_WFORMAT_LEN) + { + return v->ThrowError("width format too long"); + } + } + swidth[wc] = '\0'; + if(wc > 0) + { + width = atoi(swidth); + } + else + { + width = 0; + } + if (src[n] == '.') + { + n++; + wc = 0; + while (isdigit(src[n])) + { + swidth[wc] = src[n]; + n++; + wc++; + if(wc>=MAX_WFORMAT_LEN) + { + return v->ThrowError("precision format too long"); + } + } + swidth[wc] = '\0'; + if(wc > 0) + { + width += atoi(swidth); + } + } + if ((n-start) > MAX_FORMAT_LEN ) + { + return v->ThrowError("format too long"); + } + memcpy(&fmt[1], &src[start], ((n-start)+1)*sizeof(char)); + fmt[(n-start)+2] = '\0'; + return n; +} + +VXInteger voxstd_format(VXState* v, + VXInteger nformatstringidx, + VXInteger* outlen, + char** output) +{ + VXInteger addlen = 0; + VXInteger valtype = 0; + VXInteger ti; + VXInteger fmt_length; + VXInteger ts_length; + VXFloat tf; + const char *format; + const char *ts; + char* dest; + char fmt[MAX_FORMAT_LEN]; + v->GetString(nformatstringidx, &format, &fmt_length); + VXInteger allocated = (fmt_length+2)*sizeof(char); + dest = v->ScratchPad(allocated); + VXInteger n = 0; + VXInteger i = 0; + VXInteger w = 0; + VXInteger nparam = nformatstringidx+1; + while(format[n] != '\0') + { + if(format[n] != '%') + { + vox_assert(i < allocated); + dest[i++] = format[n]; + n++; + } + else if(format[n+1] == '%') //handles %% + { + dest[i++] = '%'; + n += 2; + } + else + { + n++; + if(nparam > v->GetTop()) + { + return v->ThrowError("not enough paramters for given format"); + } + n = validate_format(v,fmt,format,n,w); + if(n < 0) + { + return -1; + } + + switch(format[n]) + { + case 's': + if(VX_FAILED(v->GetString(nparam, &ts, &ts_length))) + { + return v->ThrowError("string expected"); + } + addlen = (ts_length * sizeof(char))+((w+1)*sizeof(char)); + valtype = 's'; + break; + case 'i': + case 'd': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + if(VX_FAILED(v->GetInteger(nparam,&ti))) + { + return v->ThrowError("integer expected"); + } + addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(char)); + valtype = 'i'; + break; + case 'f': + case 'g': + case 'G': + case 'e': + case 'E': + if(VX_FAILED(v->GetFloat(nparam,&tf))) + { + return v->ThrowError("float expected"); + } + addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(char)); + valtype = 'f'; + break; + default: + return v->ThrowError("invalid format"); + } + n++; + allocated += addlen + sizeof(char); + dest = v->ScratchPad(allocated); + switch(valtype) + { + case 's': + i += sprintf(&dest[i], fmt, ts); + break; + case 'i': + i += sprintf(&dest[i], fmt, ti); + break; + case 'f': + i += sprintf(&dest[i], fmt, tf); + break; + }; + nparam ++; + } + } + *outlen = i; + dest[i] = '\0'; + *output = dest; + return VX_OK; +} + +VXInteger stringdeleg_format(VXState* v) +{ + char *dest = NULL; + VXInteger length = 0; + if(VX_FAILED(voxstd_format(v, 1, &length, &dest))) + { + return -1; + } + v->Push(v->NewString(dest,length)); + return 1; +} + +VXInteger stringdeleg_hashval(VXState*) +{ + //const char* data_str; + //VXInteger data_len; + //v->Push(vox_gethashval(v, 1)); + //return 1; + return 0; +} + +VXInteger stringdeleg_hextoint(VXState* v) +{ + std::string subject; + VXInteger val; + v->GetString(1, &subject); + if(sscanf(subject.c_str(), "%x", &val) < 1) + { + return v->ThrowError("cannot parse string as hexadecimal number"); + } + v->Push(val); + return 1; +} + +VXInteger stringdeleg_preplace(VXState* v) +{ + std::string subject; + std::string replacement; + VXInteger from; + VXInteger to; + v->GetString(1, &subject); + v->GetInteger(2, &from); + v->GetInteger(3, &to); + v->GetString(4, &replacement); + subject.replace(std::string::size_type(from), std::string::size_type(to), replacement); + v->Push(v->NewString(subject.c_str(), subject.length())); + return 1; +} + +VXInteger stringdeleg_stripset(VXState* v) +{ + std::string self; + std::string nstr; + VXInteger i; + VXArrayObj* arr; + VXObject arr_ob; + v->GetString(1, &self); + v->GetTypedArg(2, VX_OT_ARRAY, arr_ob); + arr = arr_ob.Array(); + for(i=0; iSize(); i++) + { + VXObject ob; + arr->Get(i, ob); + switch(ob.Type()) + { + case VX_OT_INTEGER: + fprintf(stderr, "it's a number?\n"); + break; + default: + return v->ThrowError("cannot use type '%s' in string::stripset", + ob.TypeString()); + } + } + v->Push(v->NewString(nstr.c_str(), nstr.length())); + return 1; +} + +/* --------- end matching ------------- */ + +#define STRING_TOFUNCZ(func) \ + VXInteger stringdeleg_##func(VXState* v) \ + { \ + VXObject& str = v->StackGet(1); \ + VXInteger len = str.String()->_len; \ + const char *sThis = _stringval(str); \ + char *sNew=(v->ScratchPad(len)); \ + for(VXInteger i=0;iPush(v->NewString(sNew, len)); \ + return 1; \ + } + +STRING_TOFUNCZ(tolower) +STRING_TOFUNCZ(toupper) + +VXRegFunction VXSharedState::_string_default_delegate_funcz[]= +{ + {"weakref", obj_delegate_weakref, 1, NULL}, + {"len", default_delegate_len, 1, "s"}, + {"tointeger", default_delegate_tointeger, 1, "s"}, + {"tofloat", default_delegate_tofloat, 1, "s"}, + {"tostring", default_delegate_tostring, -1, ".b"}, + {"slice", stringdeleg_slice, -1, " s n n"}, + {"substr", stringdeleg_substr, -1, " s n n"}, + {"count", stringdeleg_count, -2, "s s n "}, + {"findall", stringdeleg_findall, 2, ".s"}, + {"indexof", stringdeleg_indexof, 2, ".s"}, + {"tolower", stringdeleg_tolower, 1, "s"}, + {"toupper", stringdeleg_toupper, 1, "s"}, + {"format", stringdeleg_format, -2, NULL}, + {"fmt", stringdeleg_format, -2, NULL}, + {"hashval", stringdeleg_hashval, 1, "s"}, + {"trim", stringdeleg_trim, 1, "s"}, + {"ltrim", stringdeleg_ltrim, 1, ".s"}, + {"rtrim", stringdeleg_rtrim, 1, ".s"}, + {"split", stringdeleg_split, -2, ".sb"}, + {"startswith", stringdeleg_startswith, 2, ".s"}, + {"endswith", stringdeleg_endswith, 2, ".s"}, + {"reverse", stringdeleg_reverse, 1, NULL}, + {"soundex", stringdeleg_soundex, 1, NULL}, + {"preplace", stringdeleg_preplace, 4, ".nns"}, + {"replace", stringdeleg_replace, 3, ".ss"}, + {"hextoint", stringdeleg_hextoint, 1, ".s"}, + {"quote", stringdeleg_quote, 1, NULL}, + {"escape", stringdeleg_escape, 1, NULL}, + {"stripset", stringdeleg_stripset, 2, ".a"}, + {"repr", default_delegate_repr, 1, "."}, + {0, 0, 0, 0} +}; + diff --git a/src/core/baselib_system.cpp b/src/core/baselib_system.cpp new file mode 100644 index 0000000..9ca6182 --- /dev/null +++ b/src/core/baselib_system.cpp @@ -0,0 +1,432 @@ + +#include "baselib.hpp" +#include "string.hpp" + +VXInteger vox_printfunc_callback(VXState* v, VXInteger start, VXPrintFunc vpf) +{ + const char* data_str; + VXInteger data_len; + VXInteger top; + VXInteger i; + if(vpf) + { + top = v->GetTop(); + for(i=start; i<=top; i++) + { + VXObject res; + v->ToString(v->StackGet(i), res); + res.String(&data_str, &data_len); + if(VX_FAILED(vpf(v, false, data_str, data_len))) + { + goto _printfunc_failed; + } + } + if(VX_FAILED(vpf(v, true, data_str, data_len))) + { + goto _printfunc_failed; + } + } + return 0; + +_printfunc_failed: + return v->ThrowError("Internal error: call to printfunc failed"); +} + + +VXInteger _println_callback(VXState* v, bool isend, const char* str, VXInteger len) +{ + if(v->Shared()->_printfunc) + { + if(isend) + { + v->Shared()->_printfunc(v, "\n"); + } + else + { + v->Shared()->_printfunc(v, "%.*s", len, str); + } + return VX_OK; + } + return VX_ERROR; +} + +VXInteger _print_callback(VXState* v, bool isend, const char* str, VXInteger len) +{ + if(_ss(v)->_printfunc) + { + if(!isend) + { + _ss(v)->_printfunc(v, "%.*s", len, str); + } + return VX_OK; + } + return VX_ERROR; +} + +VXInteger system_repr(VXState* v) +{ + VXInteger status; + VXRepr ser(v, v->StackGet(2)); + status = ser.status(); + if(status == VX_OK) + { + const std::string& data = ser.str(); + v->Push(v->NewString(data.c_str(), data.length())); + return 1; + } + return status; +} + +VXInteger system_dummy(VXState*) +{ + return 0; +} + +VXInteger system_gc_collect(VXState* v) +{ + v->Push(v->CollectGarbage()); + return 1; +} + +VXInteger system_gc_resurrect(VXState* v) +{ + v->ResurrectUnreachable(); + return 1; +} + +VXInteger system_gc_release(VXState* v) +{ + VXObject& ob = v->StackGet(2); + ob.Null(); + return 0; +} + +VXInteger system_getroottable(VXState* v) +{ + v->Push(v->_roottable); + return 1; +} + +VXInteger system_getconsttable(VXState* v) +{ + v->Push(v->Shared()->_consts); + return 1; +} + +VXInteger system_setroottable(VXState* v) +{ + VXObject oldroot = v->_roottable; + VXObject newroot = v->StackGet(2); + if(newroot.Type() == VX_OT_TABLE || newroot.Type() == VX_OT_NULL) + { + v->_roottable = newroot; + v->Push(oldroot); + return 1; + } + return v->ThrowError("wrong type (expected 'table' or 'null')"); +} + +VXInteger system_setconsttable(VXState* v) +{ + VXObject oldtable = v->Shared()->_consts; + VXObject newtable = v->StackGet(2); + if(newtable.Type() == VX_OT_TABLE) + { + v->Shared()->_consts = newtable; + v->Push(oldtable); + return 1; + } + return VX_ERROR;; +} + +VXInteger system_seterrorhandler(VXState* v) +{ + v->SetErrorHandler(v->StackGet(2)); + return 0; +} + +VXInteger system_setdebughook(VXState* v) +{ + v->SetDebugHook(v->StackGet(2)); + return 0; +} + +VXInteger system_enabledebuginfo(VXState* v) +{ + bool val; + v->GetBool(2, &val); + v->EnableDebugInfo(val); + return 0; +} + + +VXInteger system_getstackinfos(VXState* v) +{ + VXInteger level; + v->GetInteger(-1, &level); + return __getcallstackinfos(v,level); +} + +VXInteger system_assert(VXState* v) +{ + const char* message; + if(VXState::IsFalse(v->StackGet(2))) + { + if(VX_FAILED(v->GetString(3, &message, NULL))) + { + return v->ThrowError("assertion failed"); + } + else + { + return v->ThrowError("assertion failed: %s", message); + } + } + return 0; +} + + + +VXInteger system_print(VXState* v) +{ + return vox_printfunc_callback(v, 2, _print_callback); +} + +VXInteger system_println(VXState* v) +{ + return vox_printfunc_callback(v, 2, _println_callback); +} + + +VXInteger system_compilestring(VXState* v) +{ + const char* src; + const char* name; + VXInteger size; + v->GetString(2, &src, &size); + if(VX_FAILED(v->GetString(3, &name, NULL))) + { + name = "unnamedbuffer"; + } + if(VX_SUCCEEDED(v->CompileBuffer(src,size,name,false))) + { + return 1; + } + return VX_ERROR; +} + +VXInteger system_newthread(VXState* v) +{ + VXObject &func = v->StackGet(2); + VXInteger stksize = (func.Closure()->_function->_stacksize << 1) +2; + VXState* newv = v->NewThread(v, (stksize < MIN_STACK_OVERHEAD + 2)? + MIN_STACK_OVERHEAD + 2 : stksize); + VXState::MoveIndex(newv, v, -2); + return 1; +} + +VXInteger system_suspend(VXState* v) +{ + return v->Suspend(); +} + +VXInteger system_type(VXState* v) +{ + VXObject &o = v->StackGet(2); + v->PushString(o.TypeString()); + return 1; +} + +VXInteger system_callee(VXState* v) +{ + if(v->_callsstacksize > 1) + { + v->Push(v->_callsstack[v->_callsstacksize - 2]._closure); + return 1; + } + return v->ThrowError("no closure in the calls stack"); +} + +VXInteger system_loadfile(VXState* v) +{ + const char *filename; + bool printerror = false; + v->GetString(2, &filename, NULL); + if(VX_FAILED(v->GetBool(3, &printerror))) + { + printerror = false; + } + if(VX_SUCCEEDED(v->LoadFile(filename,printerror))) + { + return 1; + } + return v->ThrowError("loadfile('%s'): %s", filename, v->LastError()); +} + + + +VXInteger system_writeclosuretofile(VXState* v) +{ + const char *filename; + v->GetString(2, &filename, NULL); + if(VX_SUCCEEDED(v->WriteClosureToFile(filename))) + { + return 1; + } + return VX_ERROR; +} + +VXInteger system_dofile(VXState* v) +{ + const char *filename; + bool printerror; + v->GetString(2, &filename, NULL); + if(VX_FAILED(v->GetBool(3, &printerror))) + { + /* by default, do not print the yielded error */ + printerror = false; + } + v->Push(v->GetRootTable()); + if(VX_SUCCEEDED(v->DoFile(filename, true, printerror))) + { + return 1; + } + return v->ThrowError("dofile('%s'): %s", filename, v->LastError()); +} + + + +VXInteger system_dostring(VXState* v) +{ + VXInteger ret; + std::string source; + const char* buffername; + bool printerror; + v->GetString(2, &source); + if(VX_FAILED(v->GetBool(3, &printerror))) + { + /* by default, do not print the yielded error */ + printerror = false; + } + if(VX_FAILED(v->GetString(4, &buffername, NULL))) + { + buffername = NULL; + } + v->Push(v->GetRootTable()); + ret = v->DoString( + source.c_str(), + source.length(), + buffername, true, printerror); + if(VX_SUCCEEDED(ret)) + { + return 1; + } + /* only throw custom errormessage if buffername is not NULL. + reason: if system.errorhandler() is called from vox, + the buffername is not reachable, so we'll just act as if + it got called natively */ + if(buffername != NULL) + { + return v->ThrowError("dostring(%s): %s", buffername , v->LastError()); + } + return VX_ERROR; +} + +VXInteger system_platform_group(VXState* v) +{ + v->Push(v->NewString(VOX_PLATFORM_GROUP_NAME)); + return 1; +} + +VXInteger system_platform(VXState* v) +{ + v->Push(v->NewString(VOX_PLATFORM_NAME)); + return 1; +} + +VXInteger system_atexit(VXState* v) +{ + VXObject& o = v->StackGet(2); + if(type(o) == VX_OT_CLOSURE) + { + VXFuncProtoObj* f = o.Closure()->_function; + v->AtExit(f); + return VX_OK; + } + if(type(o) == VX_OT_NATIVECLOSURE) + { + return v->ThrowError("atexit() cannot handle native closures at the moment"); + } + return VX_ERROR; +} + +VXInteger system_errorhandler(VXState* v) +{ + v->CallErrorHandler(v->StackGet(2)); + return VX_OK; +} + +VXRegFunction system_funcs[]= +{ + {"platform", system_platform, 1, NULL}, + {"platform_group", system_platform_group, 1, NULL}, + {"seterrorhandler", system_seterrorhandler, 2, NULL}, + {"debughook", system_setdebughook, 2, NULL}, + {"enabledebug", system_enabledebuginfo, 2, NULL}, + {"stackinfos", system_getstackinfos, 2, ".n"}, + {"getroot", system_getroottable, 1, NULL}, + {"setroot", system_setroottable, 2, NULL}, + {"getconsttable", system_getconsttable, 1, NULL}, + {"setconsttable", system_setconsttable, 2, NULL}, + {"compilestring", system_compilestring, -2, ".ss"}, + {"newthread", system_newthread, 2, ".c"}, + {"suspend", system_suspend, -1, NULL}, + {"type", system_type, 2, NULL}, + {"callee", system_callee, 0, NULL}, + {"dummy", system_dummy, 0, NULL}, + {"loadfile", system_loadfile, -2, ".sb"}, + {"loadstring", system_compilestring, -2, ".ss"}, + {"dofile", system_dofile, -2, ".sb"}, + {"dostring", system_dostring, -2, ".sbs"}, + {"writeclosuretofile", system_writeclosuretofile, 3, ".sc"}, + {"atexit", system_atexit, 2, ".c"}, + {"repr", system_repr, 2, NULL}, + {"errorhandler", system_errorhandler, 2, NULL}, + {"gc_collect", system_gc_collect, 0, NULL}, + {"gc_resurrect", system_gc_resurrect, 0, NULL}, + {"gc_release", system_gc_release, 2, "."}, + + /** NOTE: these declarations are going to be deprecated in some + future release. remember to remove them at some point... + Main reason(s) for removal are usually: + + overly verbose function name (writeclosuretofile is way too long) + + ambigious/idiotic function name (gc_collect vs gccollect) + */ + {"getstackinfos", system_getstackinfos, 2, ".n"}, + {"setdebughook", system_setdebughook, 2, NULL}, + {"enabledebuginfo", system_enabledebuginfo, 2, NULL}, + {"seterrorhandler", system_seterrorhandler, 2, NULL}, + {"getroottable", system_getroottable, 1, NULL}, + {"setroottable", system_setroottable, 2, NULL}, + {"getconsttable", system_getconsttable, 1, NULL}, + {"setconsttable", system_setconsttable, 2, NULL}, + {0, 0, 0, 0} +}; + +VXRegFunction system_globalfuncs[] = +{ + {"assert", system_assert, -2, ".bs"}, + {"print", system_print, -1, NULL}, + {"println", system_println, -1, NULL}, + {0, 0, 0, 0} +}; + + +VXInteger voxstd_register_system(VXState* v) +{ + VXTableObj* systb = v->NewTable(); + systb->NewSlot(v->NewString("argv"), v->GetSysArgv()); + v->RegisterLib("system", system_funcs, true, systb); + v->RegisterLib(NULL, system_globalfuncs, true); + return VX_OK; +} + diff --git a/src/core/baselib_table.cpp b/src/core/baselib_table.cpp new file mode 100644 index 0000000..4a6fc47 --- /dev/null +++ b/src/core/baselib_table.cpp @@ -0,0 +1,94 @@ + +#include "baselib.hpp" + +///////////////////////////////////////////////////////////////// +//TABLE DEFAULT DELEGATE + +VXInteger table_rawdelete(VXState* v) +{ + //if(VX_FAILED(vox_rawdeleteslot(v,1,true))) + //{ + // return VX_ERROR; + //} + //return 1; + (void)v; + return 0; +} + +VXInteger table_setdelegate(VXState* v) +{ + VXObject& self = v->StackGet(1); + VXObject& mt = v->StackGet(2); + if(VX_SUCCEEDED(v->SetDelegate(self, mt))) + { + v->Push(self); + return 1; + } + return VX_ERROR; +} + +VXInteger table_getdelegate(VXState* v) +{ + //return VX_SUCCEEDED(vox_getdelegate(v,-1))?1:VX_ERROR; + (void)v; + return 0; +} + +VXInteger table_get(VXState* v) +{ + VXObject dest; + VXObject key; + VXObject self = v->StackGet(1); + VXTableObj* tb = self.Table(); + key = v->StackGet(2); + if(tb->Get(key, dest)) + { + v->Push(dest); + return 1; + } + //return VX_ERROR; + return v->Raise_IdxError(key, tb); +} + +VXInteger table_each(VXState* v) +{ + VXTableObj* self = v->StackGet(1).Table(); + VXObject& closure = v->StackGet(2); + VXInteger ridx; + VXObject key; + VXObject val; + while((ridx = self->Next(true, ridx, key, val)) != -1) + { + v->PushRoot(); + v->Push(key); + v->Push(val); + + + //v->Push(closure); + //v->Repush(-2); + //if(VX_FAILED(v->CallSimple(3, false, true))) + if(VX_FAILED(v->CallSimple(closure, 3, false, true))) + { + return VX_ERROR; + } + } + return VX_OK; +} + +VXRegFunction VXSharedState::_table_default_delegate_funcz[]= +{ + {"len", default_delegate_len, 1, "t"}, + {"tostring", default_delegate_tostring, -1, ".b"}, + {"weakref", obj_delegate_weakref, 1, NULL}, + {"clear", obj_clear, 1, "."}, + {"rawget", container_rawget, 2, "t"}, + {"rawset", container_rawset, 3, "t"}, + {"rawdelete", table_rawdelete, 2, "t"}, + {"each", table_each, 2, ".c"}, + {"get", table_get, 2, NULL}, + {"setdelegate", table_setdelegate, 2, ".t|o"}, + {"getdelegate", table_getdelegate, 1, "."}, + {"repr", default_delegate_repr, 1, "."}, + {0, 0, 0, 0} +}; + diff --git a/src/core/baselib_thread.cpp b/src/core/baselib_thread.cpp new file mode 100644 index 0000000..483ecbf --- /dev/null +++ b/src/core/baselib_thread.cpp @@ -0,0 +1,143 @@ + +#include "baselib.hpp" + +VXInteger thread_call(VXState* v) +{ + VXInteger i; + VXObject o = v->StackGet(1); + if(o.Type() == VX_OT_THREAD) + { + VXInteger nparams = v->GetTop(); + _thread(o)->Push(o.Thread()->_roottable); + for(i = 2; i<(nparams+1); i++) + { + VXState::Move(o.Thread(), v, i); + } + if(VX_SUCCEEDED(o.Thread()->CallStack(nparams, true, false))) + { + VXState::Move(v,_thread(o),-1); + o.Thread()->Pop(1); + return 1; + } + v->_lasterror = o.Thread()->_lasterror; + return VX_ERROR; + } + return v->ThrowError("wrong parameter"); +} + +VXInteger thread_wakeup(VXState* v) +{ + VXObject o = v->StackGet(1); + if(o.Type() == VX_OT_THREAD) + { + VXState *thread = o.Thread(); + VXInteger state = thread->GetState(); + if(state != VX_VMSTATE_SUSPENDED) + { + switch(state) + { + case VX_VMSTATE_IDLE: + return v->ThrowError("cannot wakeup a idle thread"); + break; + case VX_VMSTATE_RUNNING: + return v->ThrowError("cannot wakeup a running thread"); + break; + } + } + + VXInteger wakeupret = v->GetTop() > 1 ? 1 : 0; + if(wakeupret) + { + VXState::Move(thread, v, 2); + } + if(VX_SUCCEEDED(thread->WakeUp(wakeupret,true,true,false))) + { + VXState::Move(v, thread, -1); + thread->Pop(1); //pop retval + if(thread->GetState() == VX_VMSTATE_IDLE) + { + //pop roottable + thread->SetTop(1); + } + return 1; + } + thread->SetTop(1); + v->_lasterror = thread->_lasterror; + return VX_ERROR; + } + return v->ThrowError("wrong parameter"); +} + +VXInteger thread_getstatus(VXState* v) +{ + VXObject& o = v->StackGet(1); + //switch(vox_getvmstate(_thread(o))) + VXInteger status = o.Thread()->GetState(); + switch(status) + { + case VX_VMSTATE_IDLE: + v->PushString("idle"); + break; + case VX_VMSTATE_RUNNING: + v->PushString("running"); + break; + case VX_VMSTATE_SUSPENDED: + v->PushString("suspended"); + break; + default: + return v->ThrowError("internal VM error: unknown status (%d)!", status); + } + return 1; +} + +VXInteger thread_getstackinfos(VXState* v) +{ + VXObject o = v->StackGet(1); + if(o.Type() == VX_OT_THREAD) + { + VXState *thread = o.Thread(); + VXInteger threadtop = thread->GetTop(); + VXInteger level; + //vox_getinteger(v,-1,&level); + v->GetInteger(-1, &level); + VXInteger res = __getcallstackinfos(thread,level); + if(VX_FAILED(res)) + { + //vox_settop(thread,threadtop); + thread->SetTop(threadtop); + if(thread->_lasterror.Type() == VX_OT_STRING) + { + v->ThrowError(thread->_lasterror.String()->Value()); + } + else + { + v->ThrowError("unknown error"); + } + } + if(res > 0) + { + //some result + VXState::Move(v,thread,-1); + thread->SetTop(threadtop); + return 1; + } + //no result + thread->SetTop(threadtop); + return 0; + + } + return v->ThrowError("wrong parameter"); +} + +VXRegFunction VXSharedState::_thread_default_delegate_funcz[] = +{ + {"call", thread_call, -1, "v"}, + {"wakeup", thread_wakeup, -1, "v"}, + {"getstatus", thread_getstatus, 1, "v"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {"getstackinfos",thread_getstackinfos,2, "vn"}, + {"tostring",default_delegate_tostring,1, "."}, + {0, 0, 0, 0}, +}; + + diff --git a/src/core/class.cpp b/src/core/class.cpp new file mode 100644 index 0000000..786de1c --- /dev/null +++ b/src/core/class.cpp @@ -0,0 +1,415 @@ + +#include "pcheader.hpp" +#include "vm.hpp" +#include "table.hpp" +#include "class.hpp" +#include "funcproto.hpp" +#include "closure.hpp" + +VXClassObj* VXClassObj::Create(VXSharedState *ss, VXClassObj *base) +{ + VXClassObj *newclass = (VXClassObj *)VX_MALLOC(sizeof(VXClassObj)); + new (newclass) VXClassObj(ss, base); + return newclass; +} + +bool VXClassObj::Get(const VXObject &key,VXObject &val) +{ + if(_members->Get(key,val)) + { + if(_isfield(val)) + { + VXObject &o = _defaultvalues[_member_idx(val)].val; + val = VX_REALVAL(o); + } + else + { + val = _methods[_member_idx(val)].val; + } + return true; + } + return false; +} + +bool VXClassObj::GetConstructor(VXObject &dest) +{ + if(_constructoridx != -1) + { + dest = _methods[_constructoridx].val; + return true; + } + return false; +} + + +void VXClassObj::Lock() +{ + _locked = true; + if(_base) + { + _base->Lock(); + } +} + +void VXClassObj::Release() +{ + if (_hook) + { + _hook(_typetag,0); + } + vox_delete(this, VXClassObj); +} + + +VXOType VXClassObj::GetType() +{ + return VX_OT_CLASS; +} + + +VXClassObj::VXClassObj(VXSharedState *ss,VXClassObj *base) +{ + _base = base; + _typetag = 0; + _hook = NULL; + _udsize = 0; + _locked = false; + _constructoridx = -1; + _ss = ss; + _name = NULL; + if(_base) + { + _constructoridx = _base->_constructoridx; + _udsize = _base->_udsize; + _defaultvalues.copy(base->_defaultvalues); + _methods.copy(base->_methods); + VX_COPY_VECTOR(_metamethods,base->_metamethods,VX_MT_LAST); + __ObjAddRef(_base); + } + _members = base?base->_members->Clone() : VXTableObj::Create(ss,0); + __ObjAddRef(_members); + + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +void VXClassObj::Finalize() +{ + _attributes.Null(); + _defaultvalues.resize(0); + _methods.resize(0); + _NULL_VXOBJECT_VECTOR(_metamethods,VX_MT_LAST); + __ObjRelease(_members); + if(_base) + { + __ObjRelease(_base); + } +} + +VXClassObj::~VXClassObj() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + Finalize(); +} + +bool VXClassObj::NewSlot(VXSharedState *ss, const VXObject &key, const VXObject &val, bool bstatic) +{ + VXObject temp; + bool belongs_to_static_table = ( + type(val) == VX_OT_CLOSURE || type(val) == VX_OT_NATIVECLOSURE || bstatic); + if(_locked && !belongs_to_static_table) + { + return false; //the class already has an instance so cannot be modified + //overrides the default value + } + if(_members->Get(key,temp) && _isfield(temp)) + { + _defaultvalues[_member_idx(temp)].val = val; + return true; + } + if(belongs_to_static_table) + { + VXInteger mmidx; + if((type(val) == VX_OT_CLOSURE || type(val) == VX_OT_NATIVECLOSURE) && + (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) + { + _metamethods[mmidx] = val; + } + else + { + VXObject theval = val; + if(_base && type(val) == VX_OT_CLOSURE) + { + theval = _closure(val)->Clone(); + _closure(theval)->_base = _base; + __ObjAddRef(_base); //ref for the closure + } + if(type(temp) == VX_OT_NULL) + { + bool isconstructor; + VXState::IsEqual(ss->_constructoridx, key, isconstructor); + if(isconstructor) + { + _constructoridx = (VXInteger)_methods.size(); + } + VXClassObj::Member m; + m.val = theval; + _members->NewSlot(key,VXObject(_make_method_idx(_methods.size()))); + _methods.push_back(m); + } + else + { + _methods[_member_idx(temp)].val = theval; + } + } + return true; + } + VXClassObj::Member m; + m.val = val; + _members->NewSlot(key,VXObject(_make_field_idx(_defaultvalues.size()))); + _defaultvalues.push_back(m); + return true; +} + +VXInstanceObj* VXClassObj::CreateInstance() +{ + if(!_locked) + { + Lock(); + } + return VXInstanceObj::Create(_opt_ss(this),this); +} + +VXInteger VXClassObj::Next(const VXObject &refpos, VXObject &outkey, VXObject &outval) +{ + VXObject oval; + VXInteger idx = _members->Next(false,refpos,outkey,oval); + if(idx != -1) + { + if(_ismethod(oval)) + { + outval = _methods[_member_idx(oval)].val; + } + else + { + VXObject &o = _defaultvalues[_member_idx(oval)].val; + outval = VX_REALVAL(o); + } + } + return idx; +} + +bool VXClassObj::SetAttributes(const VXObject &key,const VXObject &val) +{ + VXObject idx; + if(_members->Get(key,idx)) + { + if(_isfield(idx)) + _defaultvalues[_member_idx(idx)].attrs = val; + else + _methods[_member_idx(idx)].attrs = val; + return true; + } + return false; +} + +bool VXClassObj::GetAttributes(const VXObject &key,VXObject &outval) +{ + VXObject idx; + if(_members->Get(key,idx)) + { + //outval = (_isfield(idx)?_defaultvalues[_member_idx(idx)].attrs:_methods[_member_idx(idx)].attrs); + if(_isfield(idx)) + { + outval = _defaultvalues[_member_idx(idx)].attrs; + } + else + { + outval = _methods[_member_idx(idx)].attrs; + } + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////// + +VXInstanceObj* VXInstanceObj::Create(VXSharedState *ss,VXClassObj *theclass) +{ + + VXInteger size = calcinstancesize(theclass); + VXInstanceObj *newinst = (VXInstanceObj *)VX_MALLOC(size); + new (newinst) VXInstanceObj(ss, theclass,size); + if(theclass->_udsize) + { + newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize); + } + return newinst; +} + +VXInstanceObj* VXInstanceObj::Clone(VXSharedState *ss) +{ + VXInteger size = calcinstancesize(_class); + VXInstanceObj *newinst = (VXInstanceObj *)VX_MALLOC(size); + new (newinst) VXInstanceObj(ss, this,size); + if(_class->_udsize) + { + newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize); + } + return newinst; +} + + +bool VXInstanceObj::Get(const VXObject &key,VXObject &val) +{ + if(_class->_members->Get(key,val)) + { + if(_isfield(val)) + { + VXObject &o = _values[_member_idx(val)]; + val = VX_REALVAL(o); + } + else + { + val = _class->_methods[_member_idx(val)].val; + } + return true; + } + return false; +} + +bool VXInstanceObj::Set(const VXObject &key,const VXObject &val) +{ + VXObject idx; + if(_class->_members->Get(key,idx) && _isfield(idx)) + { + _values[_member_idx(idx)] = val; + return true; + } + return false; +} + +void VXInstanceObj::Release() +{ + _uiRef++; + if (_hook) + { + _hook(_userpointer, 0); + } + _uiRef--; + if(_uiRef > 0) + { + return; + } + VXInteger size = _memsize; + this->~VXInstanceObj(); + VX_FREE(this, size); +} + +VXOType VXInstanceObj::GetType() +{ + return VX_OT_INSTANCE; +} + +void VXInstanceObj::Init(VXSharedState *ss) +{ + _userpointer = NULL; + _hook = NULL; + __ObjAddRef(_class); + _delegate = _class->_members; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +VXInstanceObj::VXInstanceObj(VXSharedState *ss, VXClassObj *c, VXInteger memsize) +{ + _memsize = memsize; + _class = c; + VXUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(VXUnsignedInteger n = 0; n < nvalues; n++) + { + new (&_values[n]) VXObject(_class->_defaultvalues[n].val); + } + Init(ss); +} + +VXInstanceObj::VXInstanceObj(VXSharedState *ss, VXInstanceObj *i, VXInteger memsize) +{ + _memsize = memsize; + _class = i->_class; + VXUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(VXUnsignedInteger n = 0; n < nvalues; n++) + { + new (&_values[n]) VXObject(i->_values[n]); + } + Init(ss); +} + +void VXInstanceObj::Finalize() +{ + VXUnsignedInteger nvalues = _class->_defaultvalues.size(); + __ObjRelease(_class); + _NULL_VXOBJECT_VECTOR(_values,nvalues); +} + +VXInstanceObj::~VXInstanceObj() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + if(_class) //if _class is null it was already finalized by the GC + { + Finalize(); + } +} + +bool VXInstanceObj::GetMetaMethod(VXState *v,VXMetaMethod mm,VXObject &res) +{ + (void)v; + if(type(_class->_metamethods[mm]) != VX_OT_NULL) + { + res = _class->_metamethods[mm]; + return true; + } + return false; +} + +bool VXInstanceObj::InstanceOf(VXClassObj *trg) +{ + VXClassObj *parent = _class; + while(parent != NULL) + { + if(parent == trg) + { + return true; + } + parent = parent->_base; + } + return false; +} + + + +void VXClassObj::Mark(VXCollectable **chain) +{ + START_MARK() + _members->Mark(chain); + if(_base) + { + _base->Mark(chain); + } + VXSharedState::MarkObject(_attributes, chain); + for(VXUnsignedInteger i =0; i< _defaultvalues.size(); i++) + { + VXSharedState::MarkObject(_defaultvalues[i].val, chain); + VXSharedState::MarkObject(_defaultvalues[i].attrs, chain); + } + for(VXUnsignedInteger j =0; j< _methods.size(); j++) + { + VXSharedState::MarkObject(_methods[j].val, chain); + VXSharedState::MarkObject(_methods[j].attrs, chain); + } + for(VXUnsignedInteger k =0; k< VX_MT_LAST; k++) + { + VXSharedState::MarkObject(_metamethods[k], chain); + } + END_MARK() +} diff --git a/src/core/class.hpp b/src/core/class.hpp new file mode 100644 index 0000000..1a30338 --- /dev/null +++ b/src/core/class.hpp @@ -0,0 +1,23 @@ + +#ifndef _VXCLASS_H_ +#define _VXCLASS_H_ + + +#define MEMBER_TYPE_METHOD 0x01000000 +#define MEMBER_TYPE_FIELD 0x02000000 + +#define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD) +#define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD) +#define _make_method_idx(i) ((VXInteger)(MEMBER_TYPE_METHOD|i)) +#define _make_field_idx(i) ((VXInteger)(MEMBER_TYPE_FIELD|i)) +#define _member_type(o) (_integer(o)&0xFF000000) +#define _member_idx(o) (_integer(o)&0x00FFFFFF) + +#define calcinstancesize(_theclass_) \ + (_theclass_->_udsize + vox_aligning(sizeof(VXInstanceObj) +\ + (sizeof(VXObject) * \ + (_theclass_->_defaultvalues.size()>0?_theclass_->_defaultvalues.size()-1:0)))) + + + +#endif //_VXCLASS_H_ diff --git a/src/core/closure.cpp b/src/core/closure.cpp new file mode 100644 index 0000000..d8777d9 --- /dev/null +++ b/src/core/closure.cpp @@ -0,0 +1,72 @@ + +#include "object.hpp" +#include "closure.hpp" + +void VXNativeClosureObj::Mark(VXCollectable **chain) +{ + START_MARK() + for(VXUnsignedInteger i = 0; i < _noutervalues; i++) + { + VXSharedState::MarkObject(_outervalues[i], chain); + } + END_MARK() +} + +void VXForeignClosureObj::Mark(VXCollectable **chain) +{ + START_MARK() + if(_base) + { + _base->Mark(chain); + } + VXFuncProtoObj *fp = _function; + fp->Mark(chain); + for(VXInteger i = 0; i < fp->_noutervalues; i++) + { + VXSharedState::MarkObject(_outervalues[i], chain); + } + for(VXInteger k = 0; k < fp->_ndefaultparams; k++) + { + VXSharedState::MarkObject(_defaultparams[k], chain); + } + END_MARK() +} + +bool VXForeignClosureObj::Save(VXState *v,VXUserPointer up,VXWriteFunc write) +{ + _CHECK_IO(WriteTag(v,write,up,VX_CLOSURESTREAM_HEAD)); + _CHECK_IO(WriteTag(v,write,up,sizeof(char))); + _CHECK_IO(WriteTag(v,write,up,sizeof(VXInteger))); + _CHECK_IO(WriteTag(v,write,up,sizeof(VXFloat))); + _CHECK_IO(_function->Save(v,up,write)); + _CHECK_IO(WriteTag(v,write,up,VX_CLOSURESTREAM_TAIL)); + return true; +} + +bool VXForeignClosureObj::Load(VXState *v,VXUserPointer up,VXReadFunc read,VXObject &ret) +{ + VXObject func; + if(!CheckTag(v,read,up,VX_CLOSURESTREAM_HEAD)) + { + // FIXME: technically speaking, this should be + // handled by vox_readclosure + v->Irrecoverable_Error("Invalid Bytecode signature!"); + return false; + } + _CHECK_IO(CheckTag(v,read,up,sizeof(char))); + _CHECK_IO(CheckTag(v,read,up,sizeof(VXInteger))); + _CHECK_IO(CheckTag(v,read,up,sizeof(VXFloat))); + _CHECK_IO(VXFuncProtoObj::Load(v,up,read,func)); + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_TAIL)); + ret = VXForeignClosureObj::Create(_ss(v),_funcproto(func)); + return true; +} + + +VXForeignClosureObj::~VXForeignClosureObj() +{ + __ObjRelease(_env); + __ObjRelease(_base); + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); +} + diff --git a/src/core/closure.hpp b/src/core/closure.hpp new file mode 100644 index 0000000..ed70f49 --- /dev/null +++ b/src/core/closure.hpp @@ -0,0 +1,247 @@ + +#ifndef _VXCLOSURE_H_ +#define _VXCLOSURE_H_ + +#include "pcheader.hpp" +#include "funcproto.hpp" +#include "object.hpp" +#include "state.hpp" + +#define _CALC_CLOSURE_SIZE(func) \ + (sizeof(VXForeignClosureObj) + (func->_noutervalues*sizeof(VXObject)) + (func->_ndefaultparams*sizeof(VXObject))) + +//struct VXFuncProtoObj; +//struct VXClassObj; + +struct VXForeignClosureObj : public VXCollectable +{ + private: + VXForeignClosureObj(VXSharedState *ss,VXFuncProtoObj *func) + { + _function = func; + __ObjAddRef(_function); + _base = NULL; + INIT_CHAIN(); + ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); + _env = NULL; + } + + public: + static VXForeignClosureObj* Create(VXSharedState *ss,VXFuncProtoObj *func) + { + VXInteger size = _CALC_CLOSURE_SIZE(func); + VXForeignClosureObj *nc=(VXForeignClosureObj*)VX_MALLOC(size); + new (nc) VXForeignClosureObj(ss,func); + nc->_outervalues = (VXObject *)(nc + 1); + nc->_defaultparams = &nc->_outervalues[func->_noutervalues]; + VX_CONSTRUCT_VECTOR(VXObject,func->_noutervalues,nc->_outervalues); + VX_CONSTRUCT_VECTOR(VXObject,func->_ndefaultparams,nc->_defaultparams); + return nc; + } + void Release() + { + VXFuncProtoObj *f = _function; + VXInteger size = _CALC_CLOSURE_SIZE(f); + VX_DESTRUCT_VECTOR(VXObject,f->_noutervalues,_outervalues); + VX_DESTRUCT_VECTOR(VXObject,f->_ndefaultparams,_defaultparams); + __ObjRelease(_function); + this->~VXForeignClosureObj(); + vox_mem_free(this,size); + } + + VXForeignClosureObj *Clone() + { + VXFuncProtoObj *f = _function; + VXForeignClosureObj * ret = VXForeignClosureObj::Create(_opt_ss(this),f); + ret->_env = _env; + if(ret->_env) __ObjAddRef(ret->_env); + VX_COPY_VECTOR(ret->_outervalues,_outervalues,f->_noutervalues); + VX_COPY_VECTOR(ret->_defaultparams,_defaultparams,f->_ndefaultparams); + return ret; + } + ~VXForeignClosureObj(); + + bool Save(VXState *v,VXUserPointer up,VXWriteFunc write); + static bool Load(VXState *v,VXUserPointer up,VXReadFunc read,VXObject &ret); + #ifndef NO_GARBAGE_COLLECTOR + void Mark(VXCollectable **chain); + void Finalize() + { + VXFuncProtoObj *f = _function; + _NULL_VXOBJECT_VECTOR(_outervalues,f->_noutervalues); + _NULL_VXOBJECT_VECTOR(_defaultparams,f->_ndefaultparams); + } + VXOType GetType() {return VX_OT_CLOSURE;} + #endif + VXWeakRefObj *_env; + VXClassObj *_base; + VXFuncProtoObj *_function; + VXObject *_outervalues; + VXObject *_defaultparams; +}; + +////////////////////////////////////////////// +struct VXOuterObj : public CHAINABLE_OBJ +{ + + private: + VXOuterObj(VXSharedState *ss, VXObject *outer){_valptr = outer; _next = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } + + public: + static VXOuterObj *Create(VXSharedState *ss, VXObject *outer) + { + VXOuterObj *nc = (VXOuterObj*)VX_MALLOC(sizeof(VXOuterObj)); + new (nc) VXOuterObj(ss, outer); + return nc; + } + ~VXOuterObj() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } + + void Release() + { + this->~VXOuterObj(); + vox_mem_free(this,sizeof(VXOuterObj)); + } + + #ifndef NO_GARBAGE_COLLECTOR + void Mark(VXCollectable **chain); + void Finalize() { _value.Null(); } + VXOType GetType() {return VX_OT_OUTER;} + #endif + + VXObject *_valptr; /* pointer to value on stack, or _value below */ + VXInteger _idx; /* idx in stack array, for relocation */ + VXObject _value; /* value of outer after stack frame is closed */ + VXOuterObj *_next; /* pointer to next outer when frame is open */ +}; + +////////////////////////////////////////////// +struct VXGeneratorObj : public CHAINABLE_OBJ +{ + enum VXGeneratorObjState + { + eRunning, + eSuspended, + eDead + }; + + private: + VXGeneratorObj(VXSharedState *ss,VXForeignClosureObj *closure) + { + _closure = closure; + _state = eRunning; + _ci._generator = NULL; + INIT_CHAIN(); + ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); + } + + public: + static VXGeneratorObj *Create(VXSharedState *ss,VXForeignClosureObj *closure) + { + VXGeneratorObj *nc=(VXGeneratorObj*)VX_MALLOC(sizeof(VXGeneratorObj)); + new (nc) VXGeneratorObj(ss,closure); + return nc; + } + + ~VXGeneratorObj() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + + void Kill() + { + _state=eDead; + _stack.resize(0); + _closure.Null(); + } + + void Release() + { + vox_delete(this,VXGeneratorObj); + } + + bool Yield(VXState *v,VXInteger target); + + bool Resume(VXState *v,VXObject &dest); + + void Mark(VXCollectable **chain); + + void Finalize() + { + _stack.resize(0); + _closure.Null(); + } + + VXOType GetType() + { + return VX_OT_GENERATOR; + } + + VXObject _closure; + VXObjectVec _stack; + VXState::CallInfo _ci; + ExceptionsTraps _etraps; + VXGeneratorObjState _state; +}; + +#define _CALC_NATVIVECLOSURE_SIZE(noutervalues) (sizeof(VXNativeClosureObj) + (noutervalues*sizeof(VXObject))) + +struct VXNativeClosureObj : public CHAINABLE_OBJ +{ + private: + VXNativeClosureObj(VXSharedState *ss,VXFunction func) + { + _function=func; + INIT_CHAIN(); + ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); + _env = NULL; + } + + public: + static VXNativeClosureObj *Create(VXSharedState *ss,VXFunction func,VXInteger nouters) + { + VXInteger size = _CALC_NATVIVECLOSURE_SIZE(nouters); + VXNativeClosureObj *nc=(VXNativeClosureObj*)VX_MALLOC(size); + new (nc) VXNativeClosureObj(ss,func); + nc->_outervalues = (VXObject *)(nc + 1); + nc->_noutervalues = nouters; + VX_CONSTRUCT_VECTOR(VXObject,nc->_noutervalues,nc->_outervalues); + return nc; + } + VXNativeClosureObj *Clone() + { + VXNativeClosureObj * ret = VXNativeClosureObj::Create(_opt_ss(this),_function,_noutervalues); + ret->_env = _env; + if(ret->_env) __ObjAddRef(ret->_env); + ret->_name = _name; + VX_COPY_VECTOR(ret->_outervalues,_outervalues,_noutervalues); + ret->_typecheck.copy(_typecheck); + ret->_nparamscheck = _nparamscheck; + return ret; + } + ~VXNativeClosureObj() + { + __ObjRelease(_env); + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + void Release() + { + VXInteger size = _CALC_NATVIVECLOSURE_SIZE(_noutervalues); + VX_DESTRUCT_VECTOR(VXObject,_noutervalues,_outervalues); + this->~VXNativeClosureObj(); + vox_free(this,size); + } + + #ifndef NO_GARBAGE_COLLECTOR + void Mark(VXCollectable **chain); + void Finalize() { _NULL_VXOBJECT_VECTOR(_outervalues,_noutervalues); } + VXOType GetType() {return VX_OT_NATIVECLOSURE;} + #endif + VXInteger _nparamscheck; + VXIntVec _typecheck; + VXObject *_outervalues; + VXUnsignedInteger _noutervalues; + VXWeakRefObj *_env; + VXFunction _function; + VXObject _name; +}; +#endif //_VXCLOSURE_H_ diff --git a/src/core/compiler.cpp b/src/core/compiler.cpp new file mode 100644 index 0000000..305a4c5 --- /dev/null +++ b/src/core/compiler.cpp @@ -0,0 +1,2205 @@ + +// continue: line 720 + + +#ifndef VOX_NO_COMPILER +#include +#include + +#include "opcodes.hpp" +#include "string.hpp" +#include "funcproto.hpp" +#include "compiler.hpp" +#include "funcstate.hpp" +#include "lexer.hpp" +#include "vm.hpp" +#include "table.hpp" +#include "names.hpp" + +#define EXPR 1 +#define OBJECT 2 +#define BASE 3 +#define LOCAL 4 +#define OUTER 5 + +struct VXExpState { + VXInteger etype; /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */ + VXInteger epos; /* expr. location on stack; -1 for OBJECT and BASE */ + bool donot_get; /* signal not to deref the next value */ +}; + +struct VXScope { + VXInteger outers; + VXInteger stacksize; +}; + +#define BEGIN_VXCOPE() \ + VXScope __oldscope__ = _scope; \ + _scope.outers = _fs->_outers; \ + _scope.stacksize = _fs->GetStackSize(); + +#define RESOLVE_OUTERS() \ + if(_fs->GetStackSize() != _scope.stacksize) \ + { \ + if(_fs->CountOuters(_scope.stacksize)) \ + { \ + _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \ + } \ + } + +#define END_VXCOPE_NO_CLOSE() \ + { \ + if(_fs->GetStackSize() != _scope.stacksize) \ + { \ + _fs->SetStackSize(_scope.stacksize); \ + } \ + _scope = __oldscope__; \ + } + +#define END_VXCOPE() \ + { \ + VXInteger oldouters = _fs->_outers; \ + if(_fs->GetStackSize() != _scope.stacksize) \ + { \ + _fs->SetStackSize(_scope.stacksize); \ + if(oldouters != _fs->_outers) \ + { \ + _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \ + } \ + } \ + _scope = __oldscope__; \ + } + +#define BEGIN_BREAKBLE_BLOCK() \ + VXInteger __nbreaks__ = _fs->_unresolvedbreaks.size(); \ + VXInteger __ncontinues__ = _fs->_unresolvedcontinues.size(); \ + _fs->_breaktargets.push_back(0); \ + _fs->_continuetargets.push_back(0); + +#define END_BREAKBLE_BLOCK(continue_target) \ + { \ + __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; \ + __ncontinues__ = _fs->_unresolvedcontinues.size() - __ncontinues__; \ + if(__ncontinues__>0)\ + { \ + ResolveContinues(_fs,__ncontinues__,continue_target); \ + } \ + if(__nbreaks__>0) \ + { \ + ResolveBreaks(_fs,__nbreaks__); \ + } \ + _fs->_breaktargets.pop_back(); \ + _fs->_continuetargets.pop_back(); \ + } + +class VXCompiler +{ + public: + VXCompiler(VXState *v, + VXLexReadFunc rg, + VXUserPointer up, + const char* sourcename, + bool raiseerror, + bool lineinfo) + { + _vm = v; + _lex.Init(_ss(v), rg, up, HandleError,this); + _sourcename = VXStringObj::Create(_ss(v), sourcename); + _lineinfo = lineinfo;_raiseerror = raiseerror; + _scope.outers = 0; + _scope.stacksize = 0; + compilererror = NULL; + } + + static void HandleError(void *ud, const char *s) + { + VXCompiler *c = (VXCompiler *)ud; + c->Error(s); + } + + void Error(const char *s, ...) + { + static char temp[256]; + va_list vl; + va_start(vl, s); + vsprintf(temp, s, vl); + va_end(vl); + compilererror = temp; + longjmp(_errorjmp,1); + } + + void Lex() + { + _token = _lex.Lex(); + } + + VXRawObj Expect(VXInteger tok) + { + if(_token != tok) + { + if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) + { + //do nothing + } + else + { + const char *etypename; + if(tok > 255) + { + switch(tok) + { + case TK_IDENTIFIER: + etypename = "IDENTIFIER"; + break; + case TK_STRING_LITERAL: + etypename = "STRING_LITERAL"; + break; + case TK_INTEGER: + etypename = "INTEGER"; + break; + case TK_FLOAT: + etypename = "FLOAT"; + break; + default: + etypename = _lex.Tok2Str(tok); + } + Error("expected '%s'", etypename); + } + Error("expected '%c'", tok); + } + } + VXObject ret; + switch(tok) + { + case TK_IDENTIFIER: + ret = _fs->CreateString(_lex._svalue); + break; + case TK_STRING_LITERAL: + ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); + break; + case TK_INTEGER: + ret = VXObject(_lex._nvalue); + break; + case TK_FLOAT: + ret = VXObject(_lex._fvalue); + break; + } + Lex(); + return ret; + } + bool IsEndOfStatement() + { + return ( + (_lex._prevtoken == '\n') || + (_token == VOX_EOB) || + (_token == '}') || + (_token == ';') + ); + } + void OptionalSemicolon() + { + if(_token == ';') + { + Lex(); + return; + } + if(!IsEndOfStatement()) + { + Error("end of statement expected (';' or EOL)"); + } + } + void MoveIfCurrentTargetIsLocal() + { + VXInteger trg = _fs->TopTarget(); + if(_fs->IsLocal(trg)) + { + trg = _fs->PopTarget(); //no pops the target and move it + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg); + } + } + bool Compile(VXObject &o) + { + _debugline = 1; + _debugop = 0; + + VXFuncState funcstate(_ss(_vm), NULL, HandleError,this); + funcstate._name = VXStringObj::Create(_ss(_vm), NAMES_MAINFUNC); + _fs = &funcstate; + _fs->AddParameter(_fs->CreateString(NAMES_TK_THISVAR)); + _fs->AddParameter(_fs->CreateString(NAMES_VARGV)); + _fs->_varparams = true; + _fs->_sourcename = _sourcename; + VXInteger stacksize = _fs->GetStackSize(); + if(setjmp(_errorjmp) == 0) + { + Lex(); + while(_token > 0) + { + Statement(); + if(_lex._prevtoken != '}' && _lex._prevtoken != ';') + { + OptionalSemicolon(); + } + } + _fs->SetStackSize(stacksize); + _fs->AddLineInfos(_lex._currentline, _lineinfo, true); + _fs->AddInstruction(_OP_RETURN, 0xFF); + _fs->SetStackSize(0); + o =_fs->BuildProto(); +#ifdef _DEBUG_DUMP + _fs->Dump(_funcproto(o)); +#endif + } + else + { + if(_raiseerror && _ss(_vm)->_compilererrorhandler) + { + _ss(_vm)->_compilererrorhandler( + _vm, + compilererror, + type(_sourcename)==VX_OT_STRING?_stringval(_sourcename):"unknown", + _lex._currentline, + _lex._currentcolumn); + } + _vm->_lasterror = VXStringObj::Create(_ss(_vm), compilererror, -1); + return false; + } + return true; + } + + void Statements() + { + while(_token != '}' && _token != TK_DEFAULT && _token != TK_CASE) + { + Statement(); + if(_lex._prevtoken != '}' && _lex._prevtoken != ';') + { + OptionalSemicolon(); + } + } + } + + void Statement(bool closeframe = true) + { + _fs->AddLineInfos(_lex._currentline, _lineinfo); + switch(_token) + { + case ';': + Lex(); + break; + + case TK_IF: + IfStatement(); + break; + + case TK_WHILE: + WhileStatement(); + break; + + case TK_DO: + DoWhileStatement(); + break; + + case TK_FOR: + ForStatement(); + break; + + case TK_FOREACH: + ForEachStatement(); + break; + + case TK_SWITCH: + SwitchStatement(); + break; + + case TK_LOCAL: + LocalDeclStatement(); + break; + + case TK_RETURN: + case TK_YIELD: + { + VXOpcode op; + if(_token == TK_RETURN) + { + op = _OP_RETURN; + } + else + { + op = _OP_YIELD; + _fs->_bgenerator = true; + } + Lex(); + if(!IsEndOfStatement()) + { + VXInteger retexp = _fs->GetCurrentPos()+1; + CommaExpr(); + if(op == _OP_RETURN && _fs->_traps > 0) + { + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0); + } + _fs->_returnexp = retexp; + _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize()); + } + else + { + if(op == _OP_RETURN && _fs->_traps > 0) + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0); + _fs->_returnexp = -1; + _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize()); + } + break; + } + + case TK_BREAK: + if(_fs->_breaktargets.size() <= 0) + { + Error("'break' has to be in a loop block"); + } + if(_fs->_breaktargets.top() > 0) + { + _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0); + } + RESOLVE_OUTERS(); + _fs->AddInstruction(_OP_JMP, 0, -1234); + _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos()); + Lex(); + break; + + case TK_CONTINUE: + if(_fs->_continuetargets.size() <= 0) + { + Error("'continue' has to be in a loop block"); + } + if(_fs->_continuetargets.top() > 0) + { + _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0); + } + RESOLVE_OUTERS(); + _fs->AddInstruction(_OP_JMP, 0, -1234); + _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos()); + Lex(); + break; + + case TK_FUNCTION: + FunctionStatement(); + break; + + case TK_CLASS: + ClassStatement(); + break; + + case TK_ENUM: + EnumStatement(); + break; + + case '{': + { + BEGIN_VXCOPE(); + Lex(); + Statements(); + Expect('}'); + if(closeframe) + { + END_VXCOPE(); + } + else + { + END_VXCOPE_NO_CLOSE(); + } + } + break; + + case TK_TRY: + TryCatchStatement(); + break; + + case TK_THROW: + Lex(); + CommaExpr(); + _fs->AddInstruction(_OP_THROW, _fs->PopTarget()); + break; + + case TK_CONST: + { + Lex(); + VXRawObj id = Expect(TK_IDENTIFIER); + Expect('='); + VXRawObj val = ExpectScalar(); + OptionalSemicolon(); + VXTableObj *enums = _table(_ss(_vm)->_consts); + VXObject strongid = id; + enums->NewSlot(strongid,VXObject(val)); + strongid.Null(); + } + break; + + default: + CommaExpr(); + _fs->DiscardTarget(); + //_fs->PopTarget(); + break; + } + _fs->SnoozeOpt(); + } + + void EmitDerefOp(VXOpcode op) + { + VXInteger val = _fs->PopTarget(); + VXInteger key = _fs->PopTarget(); + VXInteger src = _fs->PopTarget(); + _fs->AddInstruction(op,_fs->PushTarget(),src,key,val); + } + + void Emit2ArgsOP(VXOpcode op, VXInteger p3 = 0) + { + VXInteger p2 = _fs->PopTarget(); //src in OP_GET + VXInteger p1 = _fs->PopTarget(); //key in OP_GET + _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3); + } + + void EmitCompoundArith(VXInteger tok, VXInteger etype, VXInteger pos) + { + /* Generate code depending on the expression type */ + switch(etype) + { + case LOCAL: + { + VXInteger p2 = _fs->PopTarget(); //src in OP_GET + VXInteger p1 = _fs->PopTarget(); //key in OP_GET + _fs->PushTarget(p1); + //EmitCompArithLocal(tok, p1, p1, p2); + _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0); + } + break; + case OBJECT: + case BASE: + { + VXInteger val = _fs->PopTarget(); + VXInteger key = _fs->PopTarget(); + VXInteger src = _fs->PopTarget(); + /* _OP_COMPARITH mixes dest obj and source val in the arg1 */ + _fs->AddInstruction( + _OP_COMPARITH, + _fs->PushTarget(), + (src<<16)|val, + key, + ChooseCompArithCharByToken(tok)); + } + break; + case OUTER: + { + VXInteger val = _fs->TopTarget(); + VXInteger tmp = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, tmp, pos); + _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0); + _fs->AddInstruction(_OP_SETOUTER, tmp, pos, tmp); + } + break; + } + } + + void CommaExpr() + { + for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr()); + } + + void Expression() + { + VXExpState es = _es; + _es.etype = EXPR; + _es.epos = -1; + _es.donot_get = false; + LogicalOrExp(); + switch(_token) + { + case '=': + case TK_NEWSLOT: + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ: + { + VXInteger op = _token; + VXInteger ds = _es.etype; + VXInteger pos = _es.epos; + if(ds == EXPR) + { + Error("can't assign expression"); + } + Lex(); + Expression(); + switch(op) + { + case TK_NEWSLOT: + if(ds == OBJECT || ds == BASE) + { + EmitDerefOp(_OP_NEWSLOT); + } + //if _derefstate != DEREF_NO_DEREF && + // DEREF_FIELD so is the index of a local + else + { + //Error("can't \"create\" a local slot"); + Error("can't use variable as slot that was previously declared local"); + } + break; + case '=': //ASSIGN + switch(ds) + { + case LOCAL: + { + VXInteger src = _fs->PopTarget(); + VXInteger dst = _fs->TopTarget(); + _fs->AddInstruction(_OP_MOVE, dst, src); + } + break; + case OBJECT: + case BASE: + EmitDerefOp(_OP_SET); + break; + case OUTER: + { + VXInteger src = _fs->PopTarget(); + VXInteger dst = _fs->PushTarget(); + _fs->AddInstruction(_OP_SETOUTER, dst, pos, src); + } + } + break; + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ: + EmitCompoundArith(op, ds, pos); + break; + } + } + break; + case '?': + { + Lex(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + VXInteger jzpos = _fs->GetCurrentPos(); + VXInteger trg = _fs->PushTarget(); + Expression(); + VXInteger first_exp = _fs->PopTarget(); + if(trg != first_exp) + { + _fs->AddInstruction(_OP_MOVE, trg, first_exp); + } + VXInteger endfirstexp = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_JMP, 0, 0); + Expect(':'); + VXInteger jmppos = _fs->GetCurrentPos(); + Expression(); + VXInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) + { + _fs->AddInstruction(_OP_MOVE, trg, second_exp); + } + _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); + _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1); + _fs->SnoozeOpt(); + } + break; + } + _es = es; + } + + template void BIN_EXP(VXOpcode op, T f,VXInteger op3 = 0) + { + Lex(); + (this->*f)(); + VXInteger op1 = _fs->PopTarget(); + VXInteger op2 = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3); + } + + void LogicalOrExp() + { + LogicalAndExp(); + for(;;) + { + if(_token == TK_OR) + { + VXInteger first_exp = _fs->PopTarget(); + VXInteger trg = _fs->PushTarget(); + _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0); + VXInteger jpos = _fs->GetCurrentPos(); + if(trg != first_exp) + { + _fs->AddInstruction(_OP_MOVE, trg, first_exp); + } + Lex(); + LogicalOrExp(); + _fs->SnoozeOpt(); + VXInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) + { + _fs->AddInstruction(_OP_MOVE, trg, second_exp); + } + _fs->SnoozeOpt(); + _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); + break; + } + else + { + return; + } + } + } + void LogicalAndExp() + { + BitwiseOrExp(); + for(;;) + { + switch(_token) + { + case TK_AND: + { + VXInteger first_exp = _fs->PopTarget(); + VXInteger trg = _fs->PushTarget(); + _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0); + VXInteger jpos = _fs->GetCurrentPos(); + if(trg != first_exp) + { + _fs->AddInstruction(_OP_MOVE, trg, first_exp); + } + Lex(); + LogicalAndExp(); + _fs->SnoozeOpt(); + VXInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) + { + _fs->AddInstruction(_OP_MOVE, trg, second_exp); + } + _fs->SnoozeOpt(); + _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); + break; + } + case TK_IN: + BIN_EXP(_OP_EXISTS, &VXCompiler::BitwiseOrExp); + break; + case TK_INSTANCEOF: + BIN_EXP(_OP_INSTANCEOF, &VXCompiler::BitwiseOrExp); + break; + default: + return; + } + } + } + void BitwiseOrExp() + { + BitwiseXorExp(); + for(;;) + { + if(_token == '|') + { + BIN_EXP(_OP_BITW, &VXCompiler::BitwiseXorExp,BW_OR); + } + else + { + return; + } + } + } + void BitwiseXorExp() + { + BitwiseAndExp(); + for(;;) + { + if(_token == '^') + { + BIN_EXP(_OP_BITW, &VXCompiler::BitwiseAndExp,BW_XOR); + } + else + { + return; + } + } + } + void BitwiseAndExp() + { + EqExp(); + for(;;) + { + if(_token == '&') + { + BIN_EXP(_OP_BITW, &VXCompiler::EqExp,BW_AND); + } + else + { + return; + } + } + } + void EqExp() + { + CompExp(); + for(;;) + { + switch(_token) + { + case TK_EQ: + BIN_EXP(_OP_EQ, &VXCompiler::CompExp); + break; + case TK_NE: + BIN_EXP(_OP_NE, &VXCompiler::CompExp); + break; + case TK_3WAYSCMP: + BIN_EXP(_OP_CMP, &VXCompiler::CompExp,CMP_3W); + break; + default: + return; + } + } + } + void CompExp() + { + ShiftExp(); + for(;;) + { + switch(_token) + { + case '>': + BIN_EXP(_OP_CMP, &VXCompiler::ShiftExp,CMP_G); + break; + case '<': + BIN_EXP(_OP_CMP, &VXCompiler::ShiftExp,CMP_L); + break; + case TK_GE: + BIN_EXP(_OP_CMP, &VXCompiler::ShiftExp,CMP_GE); + break; + case TK_LE: + BIN_EXP(_OP_CMP, &VXCompiler::ShiftExp,CMP_LE); + break; + default: + return; + } + } + } + + void ShiftExp() + { + PlusExp(); + for(;;) + { + switch(_token) + { + case TK_USHIFTR: + BIN_EXP(_OP_BITW, &VXCompiler::PlusExp,BW_USHIFTR); + break; + case TK_SHIFTL: + BIN_EXP(_OP_BITW, &VXCompiler::PlusExp,BW_SHIFTL); + break; + case TK_SHIFTR: + BIN_EXP(_OP_BITW, &VXCompiler::PlusExp,BW_SHIFTR); + break; + default: return; + } + } + } + + VXOpcode ChooseArithOpByToken(VXInteger tok) + { + switch(tok) + { + case TK_PLUSEQ: + case '+': + return _OP_ADD; + case TK_MINUSEQ: + case '-': + return _OP_SUB; + case TK_MULEQ: + case '*': + return _OP_MUL; + case TK_DIVEQ: + case '/': + return _OP_DIV; + case TK_MODEQ: + case '%': + return _OP_MOD; + default: + vox_assert(0); + } + return _OP_ADD; + } + + VXInteger ChooseCompArithCharByToken(VXInteger tok) + { + VXInteger oper; + switch(tok) + { + case TK_MINUSEQ: + oper = '-'; + break; + case TK_PLUSEQ: + oper = '+'; break; + case TK_MULEQ: + oper = '*'; break; + case TK_DIVEQ: + oper = '/'; break; + case TK_MODEQ: + oper = '%'; break; + default: + oper = 0; //shut up compiler + vox_assert(0); + break; + }; + return oper; + } + + void PlusExp() + { + MultExp(); + for(;;) + { + switch(_token) + { + case '+': + case '-': + BIN_EXP(ChooseArithOpByToken(_token), &VXCompiler::MultExp); + break; + default: + return; + } + } + } + + void MultExp() + { + PrefixedExpr(); + for(;;) + { + switch(_token) + { + case '*': + case '/': + case '%': + BIN_EXP(ChooseArithOpByToken(_token), &VXCompiler::PrefixedExpr); + break; + default: + return; + } + } + } + + //if 'pos' != -1 the previous variable is a local variable + void PrefixedExpr() + { + VXInteger pos = Factor(); + for(;;) + { + switch(_token) + { + case '.': + pos = -1; + Lex(); + _fs->AddInstruction( + _OP_LOAD, + _fs->PushTarget(), + _fs->GetConstant(Expect(TK_IDENTIFIER))); + if(_es.etype==BASE) + { + Emit2ArgsOP(_OP_GET); + pos = _fs->TopTarget(); + _es.etype = EXPR; + _es.epos = pos; + } + else + { + if(NeedGet()) + { + Emit2ArgsOP(_OP_GET); + } + _es.etype = OBJECT; + } + break; + case '[': + if(_lex._prevtoken == '\n') + { + Error("cannot brake deref/or comma needed after [exp]=exp slot declaration"); + } + Lex(); + Expression(); + Expect(']'); + pos = -1; + if(_es.etype==BASE) + { + Emit2ArgsOP(_OP_GET); + pos = _fs->TopTarget(); + _es.etype = EXPR; + _es.epos = pos; + } + else + { + if(NeedGet()) + { + Emit2ArgsOP(_OP_GET); + } + _es.etype = OBJECT; + } + break; + case TK_MINUSMINUS: + case TK_PLUSPLUS: + { + if(IsEndOfStatement()) + return; + VXInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1; + Lex(); + switch(_es.etype) + { + case EXPR: + Error("can't '++' or '--' an expression"); + break; + case OBJECT: + case BASE: + Emit2ArgsOP(_OP_PINC, diff); + break; + case LOCAL: + { + VXInteger src = _fs->PopTarget(); + _fs->AddInstruction( + _OP_PINCL, + _fs->PushTarget(), + src, 0, diff); + } + break; + case OUTER: + { + VXInteger tmp1 = _fs->PushTarget(); + VXInteger tmp2 = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, + tmp2, _es.epos); + _fs->AddInstruction(_OP_PINCL, + tmp1, tmp2, 0, diff); + _fs->AddInstruction(_OP_SETOUTER, + tmp2, _es.epos, tmp2); + _fs->PopTarget(); + } + } + } + return; + break; + case '(': + switch(_es.etype) + { + case OBJECT: + { + /* location of the key */ + VXInteger key = _fs->PopTarget(); + /* location of the object */ + VXInteger table = _fs->PopTarget(); + /* location for the closure */ + VXInteger closure = _fs->PushTarget(); + /* location for 'this' pointer */ + VXInteger ttarget = _fs->PushTarget(); + _fs->AddInstruction(_OP_PREPCALL, + closure, key, table, ttarget); + } + break; + case BASE: + //Emit2ArgsOP(_OP_GET); + _fs->AddInstruction(_OP_MOVE, + _fs->PushTarget(), 0); + break; + case OUTER: + _fs->AddInstruction(_OP_GETOUTER, + _fs->PushTarget(), _es.epos); + _fs->AddInstruction(_OP_MOVE, + _fs->PushTarget(), 0); + break; + default: + _fs->AddInstruction(_OP_MOVE, + _fs->PushTarget(), 0); + } + _es.etype = EXPR; + Lex(); + FunctionCallArgs(); + break; + default: + return; + } + } + } + VXInteger Factor() + { + _es.etype = EXPR; + switch(_token) + { + case '{': + _fs->AddInstruction(_OP_NEWOBJ, + _fs->PushTarget(), + 0, NVX_OT_TABLE); + Lex(); + ParseTableOrClass(',', '}'); + break; + case '[': + { + _fs->AddInstruction(_OP_NEWOBJ, + _fs->PushTarget(),0,0, + NVX_OT_ARRAY); + VXInteger apos = _fs->GetCurrentPos(); + VXInteger key = 0; + Lex(); + while(_token != ']') + { + Expression(); + if(_token == ',') + { + Lex(); + } + VXInteger val = _fs->PopTarget(); + VXInteger array = _fs->TopTarget(); + _fs->AddInstruction(_OP_APPENDARRAY, + array, + val, + AAT_STACK); + key++; + } + _fs->SetIntructionParam(apos, 1, key); + Lex(); + } + break; + case TK_FUNCTION: + FunctionExp(_token); + break; + case '@': + FunctionExp(_token,true); + break; + case TK_CLASS: + Lex(); + ClassExp(); + break; + case '-': + Lex(); + switch(_token) + { + case TK_INTEGER: + EmitLoadConstInt(-_lex._nvalue,-1); + Lex(); + break; + case TK_FLOAT: + EmitLoadConstFloat(-_lex._fvalue,-1); + Lex(); + break; + default: + UnaryOP(_OP_NEG); + } + break; + case '!': + Lex(); + UnaryOP(_OP_NOT); + break; + case '~': + Lex(); + if(_token == TK_INTEGER) + { + EmitLoadConstInt(~_lex._nvalue,-1); + Lex(); + break; + } + UnaryOP(_OP_BWNOT); + break; + case TK_STRING_LITERAL: + _fs->AddInstruction(_OP_LOAD, + _fs->PushTarget(), + _fs->GetConstant( + _fs->CreateString(_lex._svalue, + _lex._longstr.size()-1))); + Lex(); + break; + case TK_BASE: + Lex(); + _fs->AddInstruction(_OP_GETBASE, + _fs->PushTarget()); + _es.etype = BASE; + _es.epos = _fs->TopTarget(); + return (_es.epos); + break; + case TK_IDENTIFIER: + case TK_CONSTRUCTOR: + case TK_THIS: + { + VXRawObj id; + VXRawObj constant; + + switch(_token) + { + case TK_IDENTIFIER: + id = _fs->CreateString(_lex._svalue); + break; + case TK_THIS: + id = _fs->CreateString(NAMES_TK_THISVAR); + break; + case TK_CONSTRUCTOR: + id = _fs->CreateString(NAMES_TK_CTOR); + break; + } + + VXInteger pos = -1; + Lex(); + if((pos = _fs->GetLocalVariable(id)) != -1) + { + /* Handle a local variable (includes 'this') */ + _fs->PushTarget(pos); + _es.etype = LOCAL; + _es.epos = pos; + } + + else if((pos = _fs->GetOuterVariable(id)) != -1) + { + /* Handle a free var */ + if(NeedGet()) + { + _es.epos = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos); + /* _es.etype = EXPR; already default value */ + } + else + { + _es.etype = OUTER; + _es.epos = pos; + } + } + + else if(_fs->IsConstant(id, constant)) + { + /* Handle named constant */ + VXObject constval; + VXRawObj constid; + if(type(constant) == VX_OT_TABLE) + { + Expect('.'); + constid = Expect(TK_IDENTIFIER); + if(!_table(constant)->Get(constid, constval)) + { + constval.Null(); + Error("invalid constant [%s.%s]", + _stringval(id), + _stringval(constid)); + } + } + else + { + constval = constant; + } + _es.epos = _fs->PushTarget(); + + /* generate direct or literal function depending on size */ + VXOType ctype = type(constval); + switch(ctype) + { + case VX_OT_INTEGER: + EmitLoadConstInt(_integer(constval), + _es.epos); + break; + case VX_OT_FLOAT: + EmitLoadConstFloat(_float(constval), + _es.epos); + break; + default: + _fs->AddInstruction( + _OP_LOAD, + _es.epos, + _fs->GetConstant(constval)); + break; + } + _es.etype = EXPR; + } + else + { + /* + * Handle a non-local variable, aka a field. + * Push the 'this' pointer on + * the virtual stack (always found in offset 0, so + * no instruction needs to + * be generated), and push the key next. Generate an + * _OP_LOAD instruction + * for the latter. If we are not using the variable as + * a dref expr, generate + * the _OP_GET instruction. + */ + _fs->PushTarget(0); + _fs->AddInstruction( + _OP_LOAD, + _fs->PushTarget(), + _fs->GetConstant(id)); + if(NeedGet()) + { + Emit2ArgsOP(_OP_GET); + } + _es.etype = OBJECT; + } + return _es.epos; + } + break; + case TK_DOUBLE_COLON: // "::" + _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget()); + _es.etype = OBJECT; + _token = '.'; /* hack: drop into PrefixExpr, case '.'*/ + _es.epos = -1; + return _es.epos; + break; + case TK_NULL: + _fs->AddInstruction(_OP_LOADNULLS, + _fs->PushTarget(),1); + Lex(); + break; + case TK_INTEGER: + EmitLoadConstInt(_lex._nvalue,-1); + Lex(); + break; + case TK_FLOAT: + EmitLoadConstFloat(_lex._fvalue,-1); + Lex(); + break; + case TK_TRUE: + case TK_FALSE: + _fs->AddInstruction( + _OP_LOADBOOL, + _fs->PushTarget(), + _token == TK_TRUE ? 1 : 0); + Lex(); + break; + case TK_TYPEOF: + Lex(); + UnaryOP(_OP_TYPEOF); + break; + case TK_RESUME: + Lex(); + UnaryOP(_OP_RESUME); + break; + case TK_CLONE: + Lex(); + UnaryOP(_OP_CLONE); + break; + case TK_MINUSMINUS: + case TK_PLUSPLUS: + PrefixIncDec(_token); + break; + case TK_DELETE: + DeleteExpr(); + break; + case '(': + Lex(); + CommaExpr(); + Expect(')'); + break; + default: + Error("expression expected"); + } + return -1; + } + + void EmitLoadConstInt(VXInteger value,VXInteger target) + { + if(target < 0) + { + target = _fs->PushTarget(); + } + //does it fit in 32 bits? + if((value & (~((VXInteger)0xFFFFFFFF))) == 0) + { + _fs->AddInstruction(_OP_LOADINT, target,value); + } + else + { + _fs->AddInstruction(_OP_LOAD, + target, + _fs->GetNumericConstant(value)); + } + } + void EmitLoadConstFloat(VXFloat value,VXInteger target) + { + if(target < 0) + { + target = _fs->PushTarget(); + } + if(sizeof(VXFloat) == sizeof(VXInt32)) + { + _fs->AddInstruction(_OP_LOADFLOAT, target,*((VXInt32 *)&value)); + } + else + { + _fs->AddInstruction(_OP_LOAD, + target, + _fs->GetNumericConstant(value)); + } + } + + void UnaryOP(VXOpcode op) + { + PrefixedExpr(); + VXInteger src = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), src); + } + + bool NeedGet() + { + switch(_token) + { + case '=': + case '(': + case TK_NEWSLOT: + case TK_MODEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_PLUSPLUS: + case TK_MINUSMINUS: + return false; + } + return (!_es.donot_get || + (_es.donot_get && + (_token == '.' || _token == '['))); + } + void FunctionCallArgs() + { + VXInteger nargs = 1;//this + while(_token != ')') + { + Expression(); + MoveIfCurrentTargetIsLocal(); + nargs++; + if(_token == ',') + { + Lex(); + if(_token == ')') + { + Error("expression expected, found ')'"); + } + } + } + Lex(); + for(VXInteger i = 0; i < (nargs - 1); i++) + { + _fs->PopTarget(); + } + VXInteger stackbase = _fs->PopTarget(); + VXInteger closure = _fs->PopTarget(); + _fs->AddInstruction(_OP_CALL, + _fs->PushTarget(), closure, + stackbase, nargs); + } + + void ParseTableOrClass(VXInteger separator,VXInteger terminator) + { + VXInteger tpos = _fs->GetCurrentPos(); + VXInteger nkeys = 0; + while(_token != terminator) + { + bool hasattrs = false; + bool isstatic = false; + //check if is an attribute + if(separator == ';') + { + if(_token == TK_ATTR_OPEN) + { + _fs->AddInstruction(_OP_NEWOBJ, + _fs->PushTarget(),0, + NVX_OT_TABLE); + Lex(); + ParseTableOrClass(',', TK_ATTR_CLOSE); + hasattrs = true; + } + if(_token == TK_STATIC) + { + isstatic = true; + Lex(); + } + } + switch(_token) + { + case TK_FUNCTION: + case TK_CONSTRUCTOR: + { + VXInteger tk = _token; + Lex(); + VXRawObj id = (tk == TK_FUNCTION ? + Expect(TK_IDENTIFIER) : + _fs->CreateString("constructor")); + Expect('('); + _fs->AddInstruction(_OP_LOAD, + _fs->PushTarget(), + _fs->GetConstant(id)); + CreateFunction(id); + _fs->AddInstruction(_OP_CLOSURE, + _fs->PushTarget(), + _fs->_functions.size() - 1, 0); + } + break; + case '[': + Lex(); + CommaExpr(); + Expect(']'); + Expect('='); + Expression(); + break; + //case TK_IDENTIFIER: + case TK_STRING_LITERAL: //JSON + //only works for tables + if(separator == ',') + { + _fs->AddInstruction( + _OP_LOAD, + _fs->PushTarget(), + _fs->GetConstant(Expect(TK_STRING_LITERAL))); + Expect(':'); + Expression(); + break; + } + default: + _fs->AddInstruction( + _OP_LOAD, + _fs->PushTarget(), + _fs->GetConstant(Expect(TK_IDENTIFIER))); + Expect('='); + Expression(); + } + if(_token == separator) + { + Lex();//optional comma/semicolon + } + nkeys++; + VXInteger val = _fs->PopTarget(); + VXInteger key = _fs->PopTarget(); + VXInteger attrs = hasattrs ? _fs->PopTarget():-1; + vox_assert((hasattrs && (attrs == key-1)) || !hasattrs); + unsigned char flags = ( + (hasattrs ? NEW_SLVX_OT_ATTRIBUTES_FLAG : 0) | + (isstatic ? NEW_SLVX_OT_STATIC_FLAG : 0)); + // vvv BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE + VXInteger table = _fs->TopTarget(); + //hack recognizes a table from the separator + if(separator == ',') + { + _fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val); + } + else + { + //this for classes only as it invokes _newmember + _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); + } + } + if(separator == ',') //hack recognizes a table from the separator + { + _fs->SetIntructionParam(tpos, 1, nkeys); + } + Lex(); + } + void LocalDeclStatement() + { + VXRawObj varname; + Lex(); + if( _token == TK_FUNCTION) + { + Lex(); + varname = Expect(TK_IDENTIFIER); + Expect('('); + CreateFunction(varname, false); + _fs->AddInstruction(_OP_CLOSURE, + _fs->PushTarget(), + _fs->_functions.size() - 1, 0); + _fs->PopTarget(); + _fs->PushLocalVariable(varname); + return; + } + do + { + varname = Expect(TK_IDENTIFIER); + if(_token == '=') + { + Lex(); + Expression(); + VXInteger src = _fs->PopTarget(); + VXInteger dest = _fs->PushTarget(); + if(dest != src) + { + _fs->AddInstruction(_OP_MOVE, dest, src); + } + } + else + { + _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); + } + _fs->PopTarget(); + _fs->PushLocalVariable(varname); + if(_token == ',') + { + Lex(); + } + else + { + break; + } + } while(1); + } + + void IfStatement() + { + VXInteger jmppos; + bool haselse = false; + Lex(); + Expect('('); + CommaExpr(); + Expect(')'); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + VXInteger jnepos = _fs->GetCurrentPos(); + BEGIN_VXCOPE(); + Statement(); + // + if(_token != '}' && _token != TK_ELSE) + { + OptionalSemicolon(); + } + END_VXCOPE(); + VXInteger endifblock = _fs->GetCurrentPos(); + if(_token == TK_ELSE) + { + haselse = true; + BEGIN_VXCOPE(); + _fs->AddInstruction(_OP_JMP); + jmppos = _fs->GetCurrentPos(); + Lex(); + Statement(); + OptionalSemicolon(); + END_VXCOPE(); + _fs->SetIntructionParam(jmppos, 1, + _fs->GetCurrentPos() - jmppos); + } + _fs->SetIntructionParam(jnepos, 1, + endifblock - jnepos + (haselse?1:0)); + } + + void WhileStatement() + { + VXInteger jzpos, jmppos; + jmppos = _fs->GetCurrentPos(); + Lex(); + Expect('('); + CommaExpr(); + Expect(')'); + BEGIN_BREAKBLE_BLOCK(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + jzpos = _fs->GetCurrentPos(); + BEGIN_VXCOPE(); + Statement(); + END_VXCOPE(); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + END_BREAKBLE_BLOCK(jmppos); + } + + void DoWhileStatement() + { + Lex(); + VXInteger jmptrg = _fs->GetCurrentPos(); + BEGIN_BREAKBLE_BLOCK() + BEGIN_VXCOPE(); + Statement(); + END_VXCOPE(); + Expect(TK_WHILE); + VXInteger continuetrg = _fs->GetCurrentPos(); + Expect('('); + CommaExpr(); + Expect(')'); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1); + _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1); + END_BREAKBLE_BLOCK(continuetrg); + } + + void ForStatement() + { + Lex(); + BEGIN_VXCOPE(); + Expect('('); + if(_token == TK_LOCAL) + { + LocalDeclStatement(); + } + else if(_token != ';') + { + CommaExpr(); + _fs->PopTarget(); + } + Expect(';'); + _fs->SnoozeOpt(); + VXInteger jmppos = _fs->GetCurrentPos(); + VXInteger jzpos = -1; + if(_token != ';') + { + CommaExpr(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + jzpos = _fs->GetCurrentPos(); + } + Expect(';'); + _fs->SnoozeOpt(); + VXInteger expstart = _fs->GetCurrentPos() + 1; + if(_token != ')') + { + CommaExpr(); + _fs->PopTarget(); + } + Expect(')'); + _fs->SnoozeOpt(); + VXInteger expend = _fs->GetCurrentPos(); + VXInteger expsize = (expend - expstart) + 1; + VXInstructionVec exp; + if(expsize > 0) + { + for(VXInteger i = 0; i < expsize; i++) + { + exp.push_back(_fs->GetInstruction(expstart + i)); + } + _fs->PopInstructions(expsize); + } + BEGIN_BREAKBLE_BLOCK() + Statement(); + VXInteger continuetrg = _fs->GetCurrentPos(); + if(expsize > 0) + { + for(VXInteger i = 0; i < expsize; i++) + { + _fs->AddInstruction(exp[i]); + } + } + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0); + if(jzpos> 0) + { + _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + } + END_VXCOPE(); + END_BREAKBLE_BLOCK(continuetrg); + } + + void ForEachStatement() + { + VXRawObj idxname, valname; + Lex(); + Expect('('); + valname = Expect(TK_IDENTIFIER); + if(_token == ',') + { + idxname = valname; + Lex(); + valname = Expect(TK_IDENTIFIER); + } + else + { + idxname = _fs->CreateString("@INDEX@"); + } + Expect(TK_IN); + + //save the stack size + BEGIN_VXCOPE(); + //put the table in the stack(evaluate the table expression) + Expression(); + Expect(')'); + VXInteger container = _fs->TopTarget(); + //push the index local var + VXInteger indexpos = _fs->PushLocalVariable(idxname); + _fs->AddInstruction(_OP_LOADNULLS, indexpos,1); + //push the value local var + VXInteger valuepos = _fs->PushLocalVariable(valname); + _fs->AddInstruction(_OP_LOADNULLS, valuepos,1); + //push reference index + //use invalid id to make it inaccessible + VXInteger itrpos = _fs->PushLocalVariable(_fs->CreateString("@ITERATOR@")); + _fs->AddInstruction(_OP_LOADNULLS, itrpos,1); + VXInteger jmppos = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos); + VXInteger foreachpos = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos); + //generate the statement code + BEGIN_BREAKBLE_BLOCK() + Statement(); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos); + _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos); + END_BREAKBLE_BLOCK(foreachpos - 1); + //restore the local variable stack(remove index,val and ref idx) + END_VXCOPE(); + } + + void SwitchStatement() + { + Lex(); + Expect('('); + CommaExpr(); + Expect(')'); + Expect('{'); + VXInteger expr = _fs->TopTarget(); + bool bfirst = true; + VXInteger tonextcondjmp = -1; + VXInteger skipcondjmp = -1; + VXInteger __nbreaks__ = _fs->_unresolvedbreaks.size(); + _fs->_breaktargets.push_back(0); + while(_token == TK_CASE) + { + if(!bfirst) + { + _fs->AddInstruction(_OP_JMP, 0, 0); + skipcondjmp = _fs->GetCurrentPos(); + _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); + } + //condition + Lex(); + Expression(); + Expect(':'); + VXInteger trg = _fs->PopTarget(); + _fs->AddInstruction(_OP_EQ, trg, trg, expr); + _fs->AddInstruction(_OP_JZ, trg, 0); + //end condition + if(skipcondjmp != -1) + { + _fs->SetIntructionParam(skipcondjmp, 1, + (_fs->GetCurrentPos()-skipcondjmp)); + } + tonextcondjmp = _fs->GetCurrentPos(); + BEGIN_VXCOPE(); + Statements(); + END_VXCOPE(); + bfirst = false; + } + if(tonextcondjmp != -1) + { + _fs->SetIntructionParam(tonextcondjmp, 1, + _fs->GetCurrentPos()-tonextcondjmp); + } + if(_token == TK_DEFAULT) + { + Lex(); + Expect(':'); + BEGIN_VXCOPE(); + Statements(); + END_VXCOPE(); + } + Expect('}'); + _fs->PopTarget(); + __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; + if(__nbreaks__ > 0) + { + ResolveBreaks(_fs, __nbreaks__); + } + _fs->_breaktargets.pop_back(); + } + + void FunctionStatement() + { + VXRawObj id; + Lex(); id = Expect(TK_IDENTIFIER); + _fs->PushTarget(0); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(_token == TK_DOUBLE_COLON) + { + Emit2ArgsOP(_OP_GET); + } + while(_token == TK_DOUBLE_COLON) + { + Lex(); + id = Expect(TK_IDENTIFIER); + _fs->AddInstruction(_OP_LOAD, + _fs->PushTarget(), + _fs->GetConstant(id)); + if(_token == TK_DOUBLE_COLON) + { + Emit2ArgsOP(_OP_GET); + } + } + Expect('('); + CreateFunction(id); + _fs->AddInstruction(_OP_CLOSURE, + _fs->PushTarget(), + _fs->_functions.size() - 1, 0); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + + void ClassStatement() + { + VXExpState es; + Lex(); + es = _es; + _es.donot_get = true; + PrefixedExpr(); + if(_es.etype == EXPR) + { + Error("invalid class name"); + } + else if(_es.etype == OBJECT || _es.etype == BASE) + { + ClassExp(); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + else + { + Error("cannot create a class in a local with the syntax(class )"); + } + _es = es; + } + + VXRawObj ExpectScalar() + { + VXRawObj val; + val._type = VX_OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x + switch(_token) + { + case TK_INTEGER: + val._type = VX_OT_INTEGER; + val._unVal.nInteger = _lex._nvalue; + break; + case TK_FLOAT: + val._type = VX_OT_FLOAT; + val._unVal.fFloat = _lex._fvalue; + break; + case TK_STRING_LITERAL: + val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); + break; + case '-': + Lex(); + switch(_token) + { + case TK_INTEGER: + val._type = VX_OT_INTEGER; + val._unVal.nInteger = -_lex._nvalue; + break; + case TK_FLOAT: + val._type = VX_OT_FLOAT; + val._unVal.fFloat = -_lex._fvalue; + break; + default: + Error("scalar expected: integer, float"); + } + break; + default: + Error("scalar expected: integer, float or string"); + } + Lex(); + return val; + } + void EnumStatement() + { + Lex(); + VXRawObj id = Expect(TK_IDENTIFIER); + Expect('{'); + VXRawObj table = _fs->CreateTable(); + VXInteger nval = 0; + while(_token != '}') + { + VXRawObj key = Expect(TK_IDENTIFIER); + VXRawObj val; + if(_token == '=') + { + Lex(); + val = ExpectScalar(); + } + else + { + val._type = VX_OT_INTEGER; + val._unVal.nInteger = nval++; + } + _table(table)->NewSlot(VXObject(key),VXObject(val)); + if(_token == ',') + { + Lex(); + } + } + VXTableObj *enums = _table(_ss(_vm)->_consts); + VXObject strongid = id; + enums->NewSlot(VXObject(strongid),VXObject(table)); + strongid.Null(); + Lex(); + } + + void TryCatchStatement() + { + VXRawObj exid; + Lex(); + _fs->AddInstruction(_OP_PUSHTRAP,0,0); + _fs->_traps++; + if(_fs->_breaktargets.size()) + { + _fs->_breaktargets.top()++; + } + + if(_fs->_continuetargets.size()) + { + _fs->_continuetargets.top()++; + } + + VXInteger trappos = _fs->GetCurrentPos(); + { + BEGIN_VXCOPE(); + Statement(); + END_VXCOPE(); + } + _fs->_traps--; + _fs->AddInstruction(_OP_POPTRAP, 1, 0); + if(_fs->_breaktargets.size()) + { + _fs->_breaktargets.top()--; + } + if(_fs->_continuetargets.size()) + { + _fs->_continuetargets.top()--; + } + _fs->AddInstruction(_OP_JMP, 0, 0); + VXInteger jmppos = _fs->GetCurrentPos(); + _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos)); + Expect(TK_CATCH); + Expect('('); + exid = Expect(TK_IDENTIFIER); + Expect(')'); + { + BEGIN_VXCOPE(); + VXInteger ex_target = _fs->PushLocalVariable(exid); + _fs->SetIntructionParam(trappos, 0, ex_target); + Statement(); + _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0); + END_VXCOPE(); + } + } + + void FunctionExp(VXInteger ftype,bool lambda = false) + { + Lex(); + Expect('('); + VXObject dummy; + CreateFunction(dummy,lambda); + _fs->AddInstruction(_OP_CLOSURE, + _fs->PushTarget(), + _fs->_functions.size() - 1, + ftype == TK_FUNCTION?0:1); + } + + void ClassExp() + { + VXInteger base = -1; + VXInteger attrs = -1; + if(_token == TK_EXTENDS) + { + Lex(); Expression(); + base = _fs->TopTarget(); + } + + if(_token == TK_ATTR_OPEN) + { + Lex(); + _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NVX_OT_TABLE); + ParseTableOrClass(',',TK_ATTR_CLOSE); + attrs = _fs->TopTarget(); + } + Expect('{'); + if(attrs != -1) + { + _fs->PopTarget(); + } + if(base != -1) + { + _fs->PopTarget(); + } + _fs->AddInstruction(_OP_NEWOBJ, + _fs->PushTarget(), + base, attrs, NVX_OT_CLASS); + ParseTableOrClass(';', '}'); + } + + void DeleteExpr() + { + VXExpState es; + Lex(); + es = _es; + _es.donot_get = true; + PrefixedExpr(); + if(_es.etype==EXPR) + { + Error("can't delete an expression"); + } + if(_es.etype==OBJECT || _es.etype==BASE) + { + Emit2ArgsOP(_OP_DELETE); + } + else + { + Error("cannot delete an (outer) local"); + } + _es = es; + } + + void PrefixIncDec(VXInteger token) + { + VXExpState es; + VXInteger diff = (token==TK_MINUSMINUS) ? -1 : 1; + Lex(); + es = _es; + _es.donot_get = true; + PrefixedExpr(); + if(_es.etype==EXPR) + { + Error("can't '++' or '--' an expression"); + } + else if(_es.etype==OBJECT || _es.etype==BASE) + { + Emit2ArgsOP(_OP_INC, diff); + } + else if(_es.etype==LOCAL) + { + VXInteger src = _fs->TopTarget(); + _fs->AddInstruction(_OP_INCL, src, src, 0, diff); + } + else if(_es.etype==OUTER) + { + VXInteger tmp = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos); + _fs->AddInstruction(_OP_INCL, tmp, tmp, 0, diff); + _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp); + } + _es = es; + } + + void CreateFunction(VXRawObj &name,bool lambda = false) + { + VXFuncState *funcstate = _fs->PushChildState(_ss(_vm)); + funcstate->_name = name; + VXRawObj paramname; + funcstate->AddParameter(_fs->CreateString(NAMES_TK_THISVAR)); + funcstate->_sourcename = _sourcename; + VXInteger defparams = 0; + while(_token!=')') + { + if(_token == TK_VARPARAMS) + { + if(defparams > 0) + { + Error("function with default parameters cannot" + " have variable number of parameters"); + } + funcstate->AddParameter(_fs->CreateString(NAMES_VARGV)); + funcstate->_varparams = true; + Lex(); + if(_token != ')') + { + Error("expected ')'"); + } + break; + } + else + { + paramname = Expect(TK_IDENTIFIER); + funcstate->AddParameter(paramname); + if(_token == '=') + { + Lex(); + Expression(); + funcstate->AddDefaultParam(_fs->TopTarget()); + defparams++; + } + else + { + if(defparams > 0) + { + Error("expected '='"); + } + } + if(_token == ',') + { + Lex(); + } + else if(_token != ')') + { + Error("expected ')' or ','"); + } + } + } + Expect(')'); + for(VXInteger n = 0; n < defparams; n++) + { + _fs->PopTarget(); + } + + VXFuncState *currchunk = _fs; + _fs = funcstate; + if(lambda) + { + Expression(); + _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget()); + } + else + { + Statement(false); + } + funcstate->AddLineInfos( + (_lex._prevtoken == '\n') ? + _lex._lasttokenline : _lex._currentline, + _lineinfo, true); + funcstate->AddInstruction(_OP_RETURN, -1); + funcstate->SetStackSize(0); + + VXFuncProtoObj *func = funcstate->BuildProto(); + #ifdef _DEBUG_DUMP + funcstate->Dump(func); + #endif + _fs = currchunk; + _fs->_functions.push_back(func); + _fs->PopChildState(); + } + + void ResolveBreaks(VXFuncState *funcstate, VXInteger ntoresolve) + { + while(ntoresolve > 0) + { + VXInteger pos = funcstate->_unresolvedbreaks.back(); + funcstate->_unresolvedbreaks.pop_back(); + //set the jmp instruction + funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0); + ntoresolve--; + } + } + + void ResolveContinues(VXFuncState *funcstate, + VXInteger ntoresolve, + VXInteger targetpos) + { + while(ntoresolve > 0) + { + VXInteger pos = funcstate->_unresolvedcontinues.back(); + funcstate->_unresolvedcontinues.pop_back(); + //set the jmp instruction + funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0); + ntoresolve--; + } + } + + private: + VXInteger _token; + VXFuncState *_fs; + VXObject _sourcename; + VXLexer _lex; + bool _lineinfo; + bool _raiseerror; + VXInteger _debugline; + VXInteger _debugop; + VXExpState _es; + VXScope _scope; + char *compilererror; + jmp_buf _errorjmp; + VXState *_vm; +}; + +bool Compile(VXState *vm,VXLexReadFunc rg, + VXUserPointer up, + const char *sourcename, + VXObject &out, + bool raiseerror, + bool lineinfo) +{ + VXCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo); + return p.Compile(out); +} + +#endif diff --git a/src/core/compiler.hpp b/src/core/compiler.hpp new file mode 100644 index 0000000..28fe078 --- /dev/null +++ b/src/core/compiler.hpp @@ -0,0 +1,82 @@ + +#ifndef _VXCOMPILER_H_ +#define _VXCOMPILER_H_ + +#include "pcheader.hpp" +#include "object.hpp" +#include "state.hpp" + +struct VXState; + +#define TK_IDENTIFIER 258 +#define TK_STRING_LITERAL 259 +#define TK_INTEGER 260 +#define TK_FLOAT 261 +#define TK_BASE 262 +#define TK_DELETE 263 +#define TK_EQ 264 +#define TK_NE 265 +#define TK_LE 266 +#define TK_GE 267 +#define TK_SWITCH 268 +#define TK_ARROW 269 +#define TK_AND 270 +#define TK_OR 271 +#define TK_IF 272 +#define TK_ELSE 273 +#define TK_WHILE 274 +#define TK_BREAK 275 +#define TK_FOR 276 +#define TK_DO 277 +#define TK_NULL 278 +#define TK_FOREACH 279 +#define TK_IN 280 +#define TK_NEWSLOT 281 +#define TK_MODULO 282 +#define TK_LOCAL 283 +#define TK_CLONE 284 +#define TK_FUNCTION 285 +#define TK_RETURN 286 +#define TK_TYPEOF 287 +#define TK_UMINUS 288 +#define TK_PLUSEQ 289 +#define TK_MINUSEQ 290 +#define TK_CONTINUE 291 +#define TK_YIELD 292 +#define TK_TRY 293 +#define TK_CATCH 294 +#define TK_THROW 295 +#define TK_SHIFTL 296 +#define TK_SHIFTR 297 +#define TK_RESUME 298 +#define TK_DOUBLE_COLON 299 +#define TK_CASE 300 +#define TK_DEFAULT 301 +#define TK_THIS 302 +#define TK_PLUSPLUS 303 +#define TK_MINUSMINUS 304 +#define TK_3WAYSCMP 305 +#define TK_USHIFTR 306 +#define TK_CLASS 307 +#define TK_EXTENDS 308 +#define TK_CONSTRUCTOR 310 +#define TK_INSTANCEOF 311 +#define TK_VARPARAMS 312 +//#define TK_VARGC 313 +//#define TK_VARGV 314 +#define TK_TRUE 315 +#define TK_FALSE 316 +#define TK_MULEQ 317 +#define TK_DIVEQ 318 +#define TK_MODEQ 319 +#define TK_ATTR_OPEN 320 +#define TK_ATTR_CLOSE 321 +#define TK_STATIC 322 +#define TK_ENUM 323 +#define TK_CONST 324 +#define TK_IMPORT 325 + + +typedef void(*CompilerErrorFunc)(void *ud, const char *s); +bool Compile(VXState *vm, VXLexReadFunc rg, VXUserPointer up, const char *sourcename, VXObject &out, bool raiseerror, bool lineinfo); +#endif //_VXCOMPILER_H_ diff --git a/src/core/debug.cpp b/src/core/debug.cpp new file mode 100644 index 0000000..ce29f89 --- /dev/null +++ b/src/core/debug.cpp @@ -0,0 +1,108 @@ + +#include +#include +#include "pcheader.hpp" +#include "vm.hpp" +#include "string.hpp" +#include "table.hpp" +#include "funcproto.hpp" +#include "closure.hpp" +#include "userdata.hpp" +#include "compiler.hpp" +#include "funcstate.hpp" +#include "class.hpp" +#include "debug.hpp" + +VXInteger vox_aux_invalidtype(VXState* v,VXOType type) +{ + return v->ThrowError("unexpected type '%s'", IdType2Name(type)); +} + + + + +void vox_aux_printcallstack(VXState* v) +{ + const char* fn; + const char* src; + VXPrintFunction pf = v->GetErrorFunc(); + if(pf) + { + VXStackInfos si; + //1 is to skip this function that is level 0 + VXInteger level=1; + while(VX_SUCCEEDED(v->StackInfos(level, &si))) + { + fn = get_funcname(si); + src = get_sourcename(si); + pf(v, " At '%s' in [%s:%d]\n", fn, src, si.line, si.column); + level++; + } + } +} + +VXInteger vox_aux_printerror(VXState* v) +{ + VXPrintFunction pf = v->GetErrorFunc(); + const char *sErr; + if(pf) + { + if(v->GetTop() >= 1) + { + if(VX_FAILED(v->GetString(2, &sErr, NULL))) + { + sErr = "[unknown error]"; + } + pf(v, "\nRuntime Error: %s\n", sErr); + vox_aux_printcallstack(v); + } + } + return 0; +} + +void vox_aux_compiler_error(VXState* v, + const char *sErr, + const char *sSource, + VXInteger line, + VXInteger column) +{ + VXPrintFunction pf = v->GetErrorFunc(); + if(pf) + { + pf(v, + "Syntax Error: in %s, line %d, column %d: %s\n", + sSource, line, column, sErr); + } +} + +void vox_aux_asserthandler(const char* expr, + const char* funct, + const char* file, + int line) +{ + fprintf(stderr, "vox_assert(%s) failed:\n At %s:%d, function '%s'\n", + expr, file, line, funct); + abort(); +} + + + +VXInteger vox_getfunctioninfo(VXState* v,VXInteger level,VXFunctionInfo *fi) +{ + VXInteger cssize = v->_callsstacksize; + if (cssize > level) + { + VXState::CallInfo &ci = v->_callsstack[cssize-level-1]; + if(ci._closure.IsClosure()) + { + VXForeignClosureObj *c = _closure(ci._closure); + VXFuncProtoObj *proto = c->_function; + fi->funcid = proto; + fi->name = type(proto->_name) == VX_OT_STRING?_stringval(proto->_name):"unknown"; + fi->source = type(proto->_name) == VX_OT_STRING?_stringval(proto->_sourcename):"unknown"; + return VX_OK; + } + } + return v->ThrowError("the object is not a closure"); +} + diff --git a/src/core/debug.hpp b/src/core/debug.hpp new file mode 100644 index 0000000..a134436 --- /dev/null +++ b/src/core/debug.hpp @@ -0,0 +1,33 @@ + +#ifndef __vox_debug_hpp__ +#define __vox_debug_hpp__ + +#include "names.hpp" + +template const char* get_funcname(Type& si) +{ + if(si.funcname) + { + return si.funcname; + } + return NAMES_ANONFUNC; +} + +template const char* get_sourcename(Type& si) +{ + if(si.source) + { + return si.source; + } + return NAMES_ANONFILE; +} + + +void vox_aux_compiler_error(VXState* v, + const char *sErr, + const char *sSource, + VXInteger line, + VXInteger column); + +VXInteger vox_aux_printerror(VXState* v); +#endif /* __vox_debug_hpp__ */ diff --git a/src/core/errors.hpp b/src/core/errors.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/funcproto.cpp b/src/core/funcproto.cpp new file mode 100644 index 0000000..f82aaba --- /dev/null +++ b/src/core/funcproto.cpp @@ -0,0 +1,238 @@ + +#include "funcproto.hpp" + +void VXFuncProtoObj::Mark(VXCollectable **chain) +{ + START_MARK() + for(VXInteger i = 0; i < _nliterals; i++) VXSharedState::MarkObject(_literals[i], chain); + for(VXInteger k = 0; k < _nfunctions; k++) VXSharedState::MarkObject(_functions[k], chain); + END_MARK() +} + +const char* VXFuncProtoObj::GetLocal( + VXState *vm, + VXUnsignedInteger stackbase, + VXUnsignedInteger nseq, + VXUnsignedInteger nop, + VXObject& valuedest) +{ + VXUnsignedInteger nvars=_nlocalvarinfos; + const char *res=NULL; + if(nvars>=nseq) + { + for(VXUnsignedInteger i=0;i=nop) + { + if(nseq==0) + { + //vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]); + valuedest = vm->_stack[stackbase+_localvarinfos[i]._pos]; + res=_stringval(_localvarinfos[i]._name); + break; + } + nseq--; + } + } + } + return res; +} + +VXInteger VXFuncProtoObj::GetLine(VXInstruction *curr) +{ + VXInteger op = (VXInteger)(curr-_instructions); + VXInteger line=_lineinfos[0]._line; + VXInteger low = 0; + VXInteger high = _nlineinfos - 1; + VXInteger mid = 0; + while(low <= high) + { + mid = low + ((high - low) >> 1); + VXInteger curop = _lineinfos[mid]._op; + if(curop > op) + { + high = mid - 1; + } + else if(curop < op) + { + if((mid < (_nlineinfos - 1)) && (_lineinfos[mid + 1]._op >= op)) + { + break; + } + low = mid + 1; + } + else //equal + { + break; + } + } + line = _lineinfos[mid]._line; + return line; +} + + +VXFuncProtoObj::VXFuncProtoObj(VXSharedState *ss) +{ + _stacksize=0; + _bgenerator=false; + INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); +} + +VXFuncProtoObj::~VXFuncProtoObj() +{ + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); +} + +bool VXFuncProtoObj::Save(VXState *v,VXUserPointer up,VXWriteFunc write) +{ + VXInteger i,nliterals = _nliterals,nparameters = _nparameters; + VXInteger noutervalues = _noutervalues,nlocalvarinfos = _nlocalvarinfos; + VXInteger nlineinfos=_nlineinfos,ninstructions = _ninstructions,nfunctions=_nfunctions; + VXInteger ndefaultparams = _ndefaultparams; + _CHECK_IO(WriteTag(v,write,up,VX_CLOSURESTREAM_PART)); + _CHECK_IO(WriteObject(v,up,write,_sourcename)); + _CHECK_IO(WriteObject(v,up,write,_name)); + _CHECK_IO(WriteTag(v,write,up,VX_CLOSURESTREAM_PART)); + _CHECK_IO(SafeWrite(v,write,up,&nliterals,sizeof(nliterals))); + _CHECK_IO(SafeWrite(v,write,up,&nparameters,sizeof(nparameters))); + _CHECK_IO(SafeWrite(v,write,up,&noutervalues,sizeof(noutervalues))); + _CHECK_IO(SafeWrite(v,write,up,&nlocalvarinfos,sizeof(nlocalvarinfos))); + _CHECK_IO(SafeWrite(v,write,up,&nlineinfos,sizeof(nlineinfos))); + _CHECK_IO(SafeWrite(v,write,up,&ndefaultparams,sizeof(ndefaultparams))); + _CHECK_IO(SafeWrite(v,write,up,&ninstructions,sizeof(ninstructions))); + _CHECK_IO(SafeWrite(v,write,up,&nfunctions,sizeof(nfunctions))); + _CHECK_IO(WriteTag(v,write,up,VX_CLOSURESTREAM_PART)); + for(i=0;iSave(v,up,write)); + } + _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize))); + _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator))); + _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams))); + return true; +} + +bool VXFuncProtoObj::Load(VXState *v,VXUserPointer up,VXReadFunc read,VXObject &ret) +{ + VXInteger i, nliterals,nparameters; + VXInteger noutervalues ,nlocalvarinfos ; + VXInteger nlineinfos,ninstructions ,nfunctions,ndefaultparams ; + VXObject sourcename, name; + VXObject o; + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_PART)); + _CHECK_IO(ReadObject(v, up, read, sourcename)); + _CHECK_IO(ReadObject(v, up, read, name)); + + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nliterals, sizeof(nliterals))); + _CHECK_IO(SafeRead(v,read,up, &nparameters, sizeof(nparameters))); + _CHECK_IO(SafeRead(v,read,up, &noutervalues, sizeof(noutervalues))); + _CHECK_IO(SafeRead(v,read,up, &nlocalvarinfos, sizeof(nlocalvarinfos))); + _CHECK_IO(SafeRead(v,read,up, &nlineinfos, sizeof(nlineinfos))); + _CHECK_IO(SafeRead(v,read,up, &ndefaultparams, sizeof(ndefaultparams))); + _CHECK_IO(SafeRead(v,read,up, &ninstructions, sizeof(ninstructions))); + _CHECK_IO(SafeRead(v,read,up, &nfunctions, sizeof(nfunctions))); + + VXFuncProtoObj *f = VXFuncProtoObj::Create(_opt_ss(v),ninstructions,nliterals,nparameters, + nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams); + VXObject proto = f; //gets a ref in case of failure + f->_sourcename = sourcename; + f->_name = name; + + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_PART)); + + for(i = 0;i < nliterals; i++) + { + _CHECK_IO(ReadObject(v, up, read, o)); + f->_literals[i] = o; + } + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_PART)); + + for(i = 0; i < nparameters; i++) + { + _CHECK_IO(ReadObject(v, up, read, o)); + f->_parameters[i] = o; + } + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_PART)); + + for(i = 0; i < noutervalues; i++) + { + VXUnsignedInteger type; + VXObject name; + _CHECK_IO(SafeRead(v,read,up, &type, sizeof(VXUnsignedInteger))); + _CHECK_IO(ReadObject(v, up, read, o)); + _CHECK_IO(ReadObject(v, up, read, name)); + f->_outervalues[i] = VXOuterObjVar(name,o, (VXOuterObjType)type); + } + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_PART)); + + for(i = 0; i < nlocalvarinfos; i++) + { + VXLocalVarInfo lvi; + _CHECK_IO(ReadObject(v, up, read, lvi._name)); + _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(VXUnsignedInteger))); + _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(VXUnsignedInteger))); + _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(VXUnsignedInteger))); + f->_localvarinfos[i] = lvi; + } + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_lineinfos, sizeof(VXLineInfo)*nlineinfos)); + + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_defaultparams, sizeof(VXInteger)*ndefaultparams)); + + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_instructions, sizeof(VXInstruction)*ninstructions)); + + _CHECK_IO(CheckTag(v,read,up,VX_CLOSURESTREAM_PART)); + for(i = 0; i < nfunctions; i++) + { + _CHECK_IO(_funcproto(o)->Load(v, up, read, o)); + f->_functions[i] = o; + } + _CHECK_IO(SafeRead(v,read,up, &f->_stacksize, sizeof(f->_stacksize))); + _CHECK_IO(SafeRead(v,read,up, &f->_bgenerator, sizeof(f->_bgenerator))); + _CHECK_IO(SafeRead(v,read,up, &f->_varparams, sizeof(f->_varparams))); + + ret = f; + return true; +} diff --git a/src/core/funcproto.hpp b/src/core/funcproto.hpp new file mode 100644 index 0000000..95387b9 --- /dev/null +++ b/src/core/funcproto.hpp @@ -0,0 +1,190 @@ + +#ifndef _VXFunction_H_ +#define _VXFunction_H_ + +#include "opcodes.hpp" +#include "object.hpp" +#include "string.hpp" +#include "mem.hpp" + +enum VXOuterObjType +{ + otLOCAL = 0, + otOUTER = 1 +}; + +struct VXOuterObjVar +{ + + VXOuterObjVar(){} + VXOuterObjVar(const VXObject &name,const VXObject &src,VXOuterObjType t) + { + _name = name; + _src=src; + _type=t; + } + VXOuterObjVar(const VXOuterObjVar &ov) + { + _type=ov._type; + _src=ov._src; + _name=ov._name; + } + VXOuterObjType _type; + VXObject _name; + VXObject _src; +}; + +struct VXLocalVarInfo +{ + VXLocalVarInfo():_start_op(0),_end_op(0),_pos(0){} + VXLocalVarInfo(const VXLocalVarInfo &lvi) + { + _name=lvi._name; + _start_op=lvi._start_op; + _end_op=lvi._end_op; + _pos=lvi._pos; + } + VXObject _name; + VXUnsignedInteger _start_op; + VXUnsignedInteger _end_op; + VXUnsignedInteger _pos; +}; + +struct VXLineInfo { VXInteger _line;VXInteger _op; }; + +typedef VXVector VXOuterObjVarVec; +typedef VXVector VXLocalVarInfoVec; +typedef VXVector VXLineInfoVec; + +#define _FUNC_SIZE(ni,nl,nparams,nfuncs,nouters,nlineinf,localinf,defparams) (sizeof(VXFuncProtoObj) \ + +((ni-1)*sizeof(VXInstruction))+(nl*sizeof(VXObject)) \ + +(nparams*sizeof(VXObject))+(nfuncs*sizeof(VXObject)) \ + +(nouters*sizeof(VXOuterObjVar))+(nlineinf*sizeof(VXLineInfo)) \ + +(localinf*sizeof(VXLocalVarInfo))+(defparams*sizeof(VXInteger))) + +struct VXFuncProtoObj : public CHAINABLE_OBJ +{ + private: + VXFuncProtoObj(VXSharedState *ss); + + ~VXFuncProtoObj(); + + public: + static VXFuncProtoObj *Create( + VXSharedState *ss, + VXInteger ninstructions, + VXInteger nliterals, + VXInteger nparameters, + VXInteger nfunctions, + VXInteger noutervalues, + VXInteger nlineinfos, + VXInteger nlocalvarinfos, + VXInteger ndefaultparams) + { + VXFuncProtoObj *f; + //I compact the whole class and members in a single memory allocation + f = (VXFuncProtoObj *)vox_mem_malloc(_FUNC_SIZE( + ninstructions, + nliterals, + nparameters, + nfunctions, + noutervalues, + nlineinfos, + nlocalvarinfos, + ndefaultparams)); + new (f) VXFuncProtoObj(ss); + f->_ninstructions = ninstructions; + f->_literals = (VXObject*)&f->_instructions[ninstructions]; + f->_nliterals = nliterals; + f->_parameters = (VXObject*)&f->_literals[nliterals]; + f->_nparameters = nparameters; + f->_functions = (VXObject*)&f->_parameters[nparameters]; + f->_nfunctions = nfunctions; + f->_outervalues = (VXOuterObjVar*)&f->_functions[nfunctions]; + f->_noutervalues = noutervalues; + f->_lineinfos = (VXLineInfo *)&f->_outervalues[noutervalues]; + f->_nlineinfos = nlineinfos; + f->_localvarinfos = (VXLocalVarInfo *)&f->_lineinfos[nlineinfos]; + f->_nlocalvarinfos = nlocalvarinfos; + f->_defaultparams = (VXInteger *)&f->_localvarinfos[nlocalvarinfos]; + f->_ndefaultparams = ndefaultparams; + + VX_CONSTRUCT_VECTOR(VXObject,f->_nliterals,f->_literals); + VX_CONSTRUCT_VECTOR(VXObject,f->_nparameters,f->_parameters); + VX_CONSTRUCT_VECTOR(VXObject,f->_nfunctions,f->_functions); + VX_CONSTRUCT_VECTOR(VXOuterObjVar,f->_noutervalues,f->_outervalues); + VX_CONSTRUCT_VECTOR(VXLocalVarInfo,f->_nlocalvarinfos,f->_localvarinfos); + return f; + } + + void Release() + { + VX_DESTRUCT_VECTOR(VXObject,_nliterals,_literals); + VX_DESTRUCT_VECTOR(VXObject,_nparameters,_parameters); + VX_DESTRUCT_VECTOR(VXObject,_nfunctions,_functions); + VX_DESTRUCT_VECTOR(VXOuterObjVar,_noutervalues,_outervalues); + VX_DESTRUCT_VECTOR(VXLocalVarInfo,_nlocalvarinfos,_localvarinfos); + VXInteger size = _FUNC_SIZE( + _ninstructions, + _nliterals, + _nparameters, + _nfunctions, + _noutervalues, + _nlineinfos, + _nlocalvarinfos, + _ndefaultparams); + this->~VXFuncProtoObj(); + vox_mem_free(this,size); + } + + const char* GetLocal(VXState *v, + VXUnsignedInteger stackbase, + VXUnsignedInteger nseq, + VXUnsignedInteger nop, + VXObject& dest); + + VXInteger GetLine(VXInstruction *curr); + + bool Save(VXState *v,VXUserPointer up,VXWriteFunc write); + + static bool Load(VXState *v,VXUserPointer up,VXReadFunc read,VXObject &ret); + + #ifndef NO_GARBAGE_COLLECTOR + void Mark(VXCollectable **chain); + + void Finalize(){ _NULL_VXOBJECT_VECTOR(_literals,_nliterals); } + + VXOType GetType() {return VX_OT_FUNCPROTO;} + #endif + + VXObject _sourcename; + VXObject _name; + VXInteger _stacksize; + bool _bgenerator; + VXInteger _varparams; + + VXInteger _nlocalvarinfos; + VXLocalVarInfo *_localvarinfos; + + VXInteger _nlineinfos; + VXLineInfo *_lineinfos; + + VXInteger _nliterals; + VXObject *_literals; + + VXInteger _nparameters; + VXObject *_parameters; + + VXInteger _nfunctions; + VXObject *_functions; + + VXInteger _noutervalues; + VXOuterObjVar *_outervalues; + + VXInteger _ndefaultparams; + VXInteger *_defaultparams; + + VXInteger _ninstructions; + VXInstruction _instructions[1]; +}; +#endif //_VXFunction_H_ diff --git a/src/core/funcstate.cpp b/src/core/funcstate.cpp new file mode 100644 index 0000000..f8d6e6b --- /dev/null +++ b/src/core/funcstate.cpp @@ -0,0 +1,754 @@ + +#include "pcheader.hpp" +#ifndef VOX_NO_COMPILER +#include "compiler.hpp" +#include "string.hpp" +#include "funcproto.hpp" +#include "table.hpp" +#include "opcodes.hpp" +#include "funcstate.hpp" + +#ifdef _DEBUG_DUMP +VXInstructionDesc g_InstrDesc[]= +{ + {"_OP_LINE"}, + {"_OP_LOAD"}, + {"_OP_LOADINT"}, + {"_OP_LOADFLOAT"}, + {"_OP_DLOAD"}, + {"_OP_TAILCALL"}, + {"_OP_CALL"}, + {"_OP_PREPCALL"}, + {"_OP_PREPCALLK"}, + {"_OP_GETK"}, + {"_OP_MOVE"}, + {"_OP_NEWSLOT"}, + {"_OP_DELETE"}, + {"_OP_SET"}, + {"_OP_GET"}, + {"_OP_EQ"}, + {"_OP_NE"}, + {"_OP_ADD"}, + {"_OP_SUB"}, + {"_OP_MUL"}, + {"_OP_DIV"}, + {"_OP_MOD"}, + {"_OP_BITW"}, + {"_OP_RETURN"}, + {"_OP_LOADNULLS"}, + {"_OP_LOADROOT"}, + {"_OP_LOADBOOL"}, + {"_OP_DMOVE"}, + {"_OP_JMP"}, + {"_OP_JCMP"}, + {"_OP_JZ"}, + {"_OP_SETOUTER"}, + {"_OP_GETOUTER"}, + {"_OP_NEWOBJ"}, + {"_OP_APPENDARRAY"}, + {"_OP_COMPARITH"}, + {"_OP_INC"}, + {"_OP_INCL"}, + {"_OP_PINC"}, + {"_OP_PINCL"}, + {"_OP_CMP"}, + {"_OP_EXISTS"}, + {"_OP_INSTANCEOF"}, + {"_OP_AND"}, + {"_OP_OR"}, + {"_OP_NEG"}, + {"_OP_NOT"}, + {"_OP_BWNOT"}, + {"_OP_CLOSURE"}, + {"_OP_YIELD"}, + {"_OP_RESUME"}, + {"_OP_FOREACH"}, + {"_OP_POSTFOREACH"}, + {"_OP_CLONE"}, + {"_OP_TYPEOF"}, + {"_OP_PUSHTRAP"}, + {"_OP_POPTRAP"}, + {"_OP_THROW"}, + {"_OP_NEWSLOTA"}, + {"_OP_GETBASE"}, + {"_OP_CLOSE"}, + {"_OP_JCMP"} +}; +#endif +void DumpLiteral(VXObject &o) +{ + switch(type(o)) + { + case VX_OT_STRING: + printf("\"%s\"", _stringval(o)); + break; + case VX_OT_FLOAT: + printf("{%f}", _float(o)); + break; + case VX_OT_INTEGER: + printf("{" _PRINT_INT_FMT "}", _integer(o)); + break; + case VX_OT_BOOL: + printf("%s", _integer(o) ? "true" : "false"); + break; + default: + printf("(%s %p)", GetTypeName(o), &_rawval(o)); + break; + break; //shut up compiler + } +} + +VXFuncState::VXFuncState(VXSharedState *ss,VXFuncState *parent,CompilerErrorFunc efunc,void *ed) +{ + _nliterals = 0; + _literals = VXTableObj::Create(ss,0); + _strings = VXTableObj::Create(ss,0); + _sharedstate = ss; + _lastline = 0; + _optimization = true; + _parent = parent; + _stacksize = 0; + _traps = 0; + _returnexp = 0; + _varparams = false; + _errfunc = efunc; + _errtarget = ed; + _bgenerator = false; + _outers = 0; + _ss = ss; + +} + +void VXFuncState::Error(const char *err) +{ + _errfunc(_errtarget,err); +} + +#ifdef _DEBUG_DUMP +void VXFuncState::Dump(VXFuncProtoObj *func) +{ + VXUnsignedInteger n=0,i; + VXInteger si; + printf("VXInstruction sizeof %d\n",sizeof(VXInstruction)); + printf("VXRawObj sizeof %d\n",sizeof(VXRawObj)); + printf("-----------------------------------------------------\n"); + printf("*****FUNCTION [%s]\n", + type(func->_name)==VX_OT_STRING ? _stringval(func->_name):"unknown"); + printf("-----LITERALS\n"); + VXObject refidx,key,val; + VXInteger idx; + VXObjectVec templiterals; + templiterals.resize(_nliterals); + while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) + { + refidx=idx; + templiterals[_integer(val)]=key; + } + for(i=0;i>\n"); + n=0; + for(i=0;i<_parameters.size();i++) + { + printf("[%d] ",n); + DumpLiteral(_parameters[i]); + printf("\n"); + n++; + } + printf("-----LOCALS\n"); + for(si=0;si_nlocalvarinfos;si++) + { + VXLocalVarInfo lvi=func->_localvarinfos[si]; + printf("[%d] %s \t%d %d\n", + lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op); + n++; + } + printf("-----LINE INFO\n"); + for(i=0;i<_lineinfos.size();i++) + { + VXLineInfo li=_lineinfos[i]; + printf("op [%d] line [%d] \n",li._op,li._line); + n++; + } + printf("-----dump\n"); + n=0; + for(i=0;i<_instructions.size();i++) + { + VXInstruction &inst=_instructions[i]; + if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ) + { + + VXInteger lidx = inst._arg1; + printf("[%03d] %15s %d ",n,g_InstrDesc[inst.op].name,inst._arg0); + if(lidx >= 0xFFFFFFFF) + printf("null"); + else + { + VXInteger refidx; + VXObject val,key,refo; + while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) + { + refo = refidx; + } + DumpLiteral(key); + } + if(inst.op != _OP_DLOAD) + { + printf(" %d %d \n",inst._arg2,inst._arg3); + } + else + { + printf(" %d ",inst._arg2); + lidx = inst._arg3; + if(lidx >= 0xFFFFFFFF) + printf("null"); + else + { + VXInteger refidx; + VXObject val,key,refo; + while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) + { + refo = refidx; + } + DumpLiteral(key); + printf("\n"); + } + } + } + else if(inst.op==_OP_LOADFLOAT) + { + printf("[%03d] %15s %d %f %d %d\n", + n,g_InstrDesc[inst.op].name, + inst._arg0, + *((VXFloat*)&inst._arg1), + inst._arg2, + inst._arg3); + } + /* else if(inst.op==_OP_ARITH){ + printf("[%03d] %15s %d %d %d %c\n", + n,g_InstrDesc[inst.op].name, + inst._arg0, + inst._arg1, + inst._arg2, + inst._arg3); + }*/ + else + { + printf("[%03d] %15s %d %d %d %d\n", + n,g_InstrDesc[inst.op].name, + inst._arg0, + inst._arg1, + inst._arg2, + inst._arg3); + } + n++; + } + printf("-----\n"); + printf("stack size[%d]\n",func->_stacksize); + printf("---------------------------------------------------\n\n"); +} +#endif + +VXInteger VXFuncState::GetNumericConstant(const VXInteger cons) +{ + return GetConstant(VXObject(cons)); +} + +VXInteger VXFuncState::GetNumericConstant(const VXFloat cons) +{ + return GetConstant(VXObject(cons)); +} + +VXInteger VXFuncState::GetConstant(const VXRawObj &cons) +{ + VXObject val; + if(!_table(_literals)->Get(cons,val)) + { + val = _nliterals; + _table(_literals)->NewSlot(cons,val); + _nliterals++; + if(_nliterals > MAX_LITERALS) + { + val.Null(); + Error("internal compiler error: too many literals"); + } + } + return _integer(val); +} + +void VXFuncState::SetIntructionParams(VXInteger pos,VXInteger arg0,VXInteger arg1,VXInteger arg2,VXInteger arg3) +{ + _instructions[pos]._arg0=(unsigned char)*((VXUnsignedInteger *)&arg0); + _instructions[pos]._arg1=(VXInt32)*((VXUnsignedInteger *)&arg1); + _instructions[pos]._arg2=(unsigned char)*((VXUnsignedInteger *)&arg2); + _instructions[pos]._arg3=(unsigned char)*((VXUnsignedInteger *)&arg3); +} + +void VXFuncState::SetIntructionParam(VXInteger pos,VXInteger arg,VXInteger val) +{ + switch(arg) + { + case 0:_instructions[pos]._arg0=(unsigned char)*((VXUnsignedInteger *)&val);break; + case 1:case 4:_instructions[pos]._arg1=(VXInt32)*((VXUnsignedInteger *)&val);break; + case 2:_instructions[pos]._arg2=(unsigned char)*((VXUnsignedInteger *)&val);break; + case 3:_instructions[pos]._arg3=(unsigned char)*((VXUnsignedInteger *)&val);break; + }; +} + +VXInteger VXFuncState::AllocStackPos() +{ + VXInteger npos=_vlocals.size(); + _vlocals.push_back(VXLocalVarInfo()); + if(_vlocals.size()>((VXUnsignedInteger)_stacksize)) + { + if(_stacksize>MAX_FUNC_STACKSIZE) + { + Error("internal compiler error: too many locals"); + } + _stacksize=_vlocals.size(); + } + return npos; +} + +VXInteger VXFuncState::PushTarget(VXInteger n) +{ + if(n!=-1) + { + _targetstack.push_back(n); + return n; + } + n=AllocStackPos(); + _targetstack.push_back(n); + return n; +} + +VXInteger VXFuncState::GetUpTarget(VXInteger n) +{ + return _targetstack[((_targetstack.size()-1)-n)]; +} + +VXInteger VXFuncState::TopTarget() +{ + return _targetstack.back(); +} + +VXInteger VXFuncState::PopTarget() +{ + VXInteger npos=_targetstack.back(); + VXLocalVarInfo &t=_vlocals[_targetstack.back()]; + if(type(t._name)==VX_OT_NULL) + { + _vlocals.pop_back(); + } + _targetstack.pop_back(); + return npos; +} + +VXInteger VXFuncState::GetStackSize() +{ + return _vlocals.size(); +} + +VXInteger VXFuncState::CountOuters(VXInteger stacksize) +{ + VXInteger outers = 0; + VXInteger k = _vlocals.size() - 1; + while(k >= stacksize) + { + VXLocalVarInfo &lvi = _vlocals[k]; + k--; + //this means is an outer + if(lvi._end_op == UINT_MINUS_ONE) + { + outers++; + } + } + return outers; +} + +void VXFuncState::SetStackSize(VXInteger n) +{ + VXInteger size=_vlocals.size(); + while(size>n) + { + size--; + VXLocalVarInfo lvi = _vlocals.back(); + if(type(lvi._name)!=VX_OT_NULL) + { + //this means is an outer + if(lvi._end_op == UINT_MINUS_ONE) + { + _outers--; + } + lvi._end_op = GetCurrentPos(); + _localvarinfos.push_back(lvi); + } + _vlocals.pop_back(); + } +} + +bool VXFuncState::IsConstant(const VXRawObj &name,VXRawObj &e) +{ + VXObject val; + if(_table(_sharedstate->_consts)->Get(name,val)) + { + e = val; + return true; + } + return false; +} + +bool VXFuncState::IsLocal(VXUnsignedInteger stkpos) +{ + if(stkpos>=_vlocals.size())return false; + else if(type(_vlocals[stkpos]._name)!=VX_OT_NULL)return true; + return false; +} + +VXInteger VXFuncState::PushLocalVariable(const VXRawObj &name) +{ + VXInteger pos=_vlocals.size(); + VXLocalVarInfo lvi; + lvi._name=name; + lvi._start_op=GetCurrentPos()+1; + lvi._pos=_vlocals.size(); + _vlocals.push_back(lvi); + if(_vlocals.size()>((VXUnsignedInteger)_stacksize))_stacksize=_vlocals.size(); + return pos; +} + +VXInteger VXFuncState::GetLocalVariable(const VXRawObj &name) +{ + VXInteger locals=_vlocals.size(); + while(locals>=1) + { + VXLocalVarInfo &lvi = _vlocals[locals-1]; + if(type(lvi._name)==VX_OT_STRING && _string(lvi._name)==_string(name)) + { + return locals-1; + } + locals--; + } + return -1; +} + +void VXFuncState::MarkLocalAsOuter(VXInteger pos) +{ + VXLocalVarInfo &lvi = _vlocals[pos]; + lvi._end_op = UINT_MINUS_ONE; + _outers++; +} + +VXInteger VXFuncState::GetOuterVariable(const VXRawObj &name) +{ + VXInteger outers = _outervalues.size(); + for(VXInteger i = 0; iGetLocalVariable(name); + if(pos == -1) + { + pos = _parent->GetOuterVariable(name); + if(pos != -1) + { + //local + _outervalues.push_back(VXOuterObjVar(name,VXObject(VXInteger(pos)),otOUTER)); + return _outervalues.size() - 1; + } + } + else + { + _parent->MarkLocalAsOuter(pos); + //local + _outervalues.push_back(VXOuterObjVar(name,VXObject(VXInteger(pos)),otLOCAL)); + return _outervalues.size() - 1; + + } + } + return -1; +} + +void VXFuncState::AddParameter(const VXRawObj &name) +{ + PushLocalVariable(name); + _parameters.push_back(name); +} + +void VXFuncState::AddLineInfos(VXInteger line,bool lineop,bool force) +{ + if(_lastline!=line || force) + { + VXLineInfo li; + li._line=line;li._op=(GetCurrentPos()+1); + if(lineop)AddInstruction(_OP_LINE,0,line); + if(_lastline!=line) + { + _lineinfos.push_back(li); + } + _lastline=line; + } +} + +void VXFuncState::DiscardTarget() +{ + VXInteger discardedtarget = PopTarget(); + VXInteger size = _instructions.size(); + if(size > 0 && _optimization) + { + //previous instruction + VXInstruction &pi = _instructions[size-1]; + switch(pi.op) + { + case _OP_SET:case _OP_NEWSLOT:case _OP_SETOUTER:case _OP_CALL: + if(pi._arg0 == discardedtarget) + { + pi._arg0 = 0xFF; + } + } + } +} + +void VXFuncState::AddInstruction(VXInstruction &i) +{ + VXInteger size = _instructions.size(); + if(size > 0 && _optimization)//simple optimizer + { + //previous instruction + VXInstruction &pi = _instructions[size-1]; + switch(i.op) + { + case _OP_JZ: + if( pi.op == _OP_CMP && pi._arg1 < 0xFF) + { + pi.op = _OP_JCMP; + pi._arg0 = (unsigned char)pi._arg1; + pi._arg1 = i._arg1; + return; + } + case _OP_SET: + case _OP_NEWSLOT: + if(i._arg0 == i._arg3) + { + i._arg0 = 0xFF; + } + break; + case _OP_SETOUTER: + if(i._arg0 == i._arg2) + { + i._arg0 = 0xFF; + } + break; + case _OP_RETURN: + if(_parent && + (i._arg0 != MAX_FUNC_STACKSIZE) && + (pi.op == _OP_CALL) && + (_returnexp < (size-1))) + { + pi.op = _OP_TAILCALL; + } + else if(pi.op == _OP_CLOSE) + { + pi = i; + return; + } + break; + case _OP_GET: + if(pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))) + { + pi._arg1 = pi._arg1; + pi._arg2 = (unsigned char)i._arg1; + pi.op = _OP_GETK; + pi._arg0 = i._arg0; + return; + } + break; + case _OP_PREPCALL: + if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))) + { + pi.op = _OP_PREPCALLK; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = i._arg2; + pi._arg3 = i._arg3; + return; + } + break; + case _OP_APPENDARRAY: + { + VXInteger aat = -1; + switch(pi.op) + { + case _OP_LOAD: aat = AAT_LITERAL; break; + case _OP_LOADINT: aat = AAT_INT; break; + case _OP_LOADBOOL: aat = AAT_BOOL; break; + case _OP_LOADFLOAT: aat = AAT_FLOAT; break; + default: break; + } + if(aat != -1 && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))) + { + pi.op = _OP_APPENDARRAY; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = (unsigned char)aat; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + } + break; + case _OP_MOVE: + switch(pi.op) + { + case _OP_GET: + case _OP_ADD: + case _OP_SUB: + case _OP_MUL: + case _OP_DIV: + case _OP_MOD: + case _OP_BITW: + case _OP_LOADINT: + case _OP_LOADFLOAT: + case _OP_LOADBOOL: + case _OP_LOAD: + if(pi._arg0 == i._arg1) + { + pi._arg0 = i._arg0; + _optimization = false; + //_result_elimination = false; + return; + } + } + + if(pi.op == _OP_MOVE) + { + pi.op = _OP_DMOVE; + pi._arg2 = i._arg0; + pi._arg3 = (unsigned char)i._arg1; + return; + } + break; + case _OP_LOAD: + if(pi.op == _OP_LOAD && i._arg1 < 256) + { + pi.op = _OP_DLOAD; + pi._arg2 = i._arg0; + pi._arg3 = (unsigned char)i._arg1; + return; + } + break; + case _OP_EQ: + case _OP_NE: + if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))) + { + pi.op = i.op; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = i._arg2; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + break; + case _OP_LOADNULLS: + if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) + { + pi._arg1 = pi._arg1 + 1; + pi.op = _OP_LOADNULLS; + return; + } + break; + case _OP_LINE: + if(pi.op == _OP_LINE) + { + _instructions.pop_back(); + _lineinfos.pop_back(); + } + break; + } + } + _optimization = true; + _instructions.push_back(i); +} + +VXRawObj VXFuncState::CreateString(const char *s,VXInteger len) +{ + VXObject ns(VXStringObj::Create(_sharedstate,s,len)); + _table(_strings)->NewSlot(ns,(VXInteger)1); + return ns; +} + +VXRawObj VXFuncState::CreateTable() +{ + VXObject nt(VXTableObj::Create(_sharedstate,0)); + _table(_strings)->NewSlot(nt,(VXInteger)1); + return nt; +} + +VXFuncProtoObj *VXFuncState::BuildProto() +{ + + VXFuncProtoObj *f=VXFuncProtoObj::Create(_ss,_instructions.size(), + _nliterals,_parameters.size(),_functions.size(),_outervalues.size(), + _lineinfos.size(),_localvarinfos.size(),_defaultparams.size()); + + VXObject refidx,key,val; + VXInteger idx; + + f->_stacksize = _stacksize; + f->_sourcename = _sourcename; + f->_bgenerator = _bgenerator; + f->_name = _name; + + while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) + { + f->_literals[_integer(val)]=key; + refidx=idx; + } + + for(VXUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf]; + for(VXUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np]; + for(VXUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no]; + for(VXUnsignedInteger nl = 0; nl < _localvarinfos.size(); nl++) f->_localvarinfos[nl] = _localvarinfos[nl]; + for(VXUnsignedInteger ni = 0; ni < _lineinfos.size(); ni++) f->_lineinfos[ni] = _lineinfos[ni]; + for(VXUnsignedInteger nd = 0; nd < _defaultparams.size(); nd++) f->_defaultparams[nd] = _defaultparams[nd]; + + memcpy(f->_instructions,&_instructions[0],_instructions.size()*sizeof(VXInstruction)); + + f->_varparams = _varparams; + + return f; +} + +VXFuncState *VXFuncState::PushChildState(VXSharedState *ss) +{ + VXFuncState *child = (VXFuncState *)vox_malloc(sizeof(VXFuncState)); + new (child) VXFuncState(ss,this,_errfunc,_errtarget); + _childstates.push_back(child); + return child; +} + +void VXFuncState::PopChildState() +{ + VXFuncState *child = _childstates.back(); + vox_delete(child,VXFuncState); + _childstates.pop_back(); +} + +VXFuncState::~VXFuncState() +{ + while(_childstates.size() > 0) + { + PopChildState(); + } +} +#endif diff --git a/src/core/funcstate.hpp b/src/core/funcstate.hpp new file mode 100644 index 0000000..4717430 --- /dev/null +++ b/src/core/funcstate.hpp @@ -0,0 +1,92 @@ + +#ifndef _VXFUNCSTATE_H_ +#define _VXFUNCSTATE_H_ + +#include "utils.hpp" + +struct VXFuncState +{ + VXFuncState(VXSharedState *ss,VXFuncState *parent,CompilerErrorFunc efunc,void *ed); + ~VXFuncState(); + #ifdef _DEBUG_DUMP + void Dump(VXFuncProtoObj *func); + #endif + void Error(const char *err); + VXFuncState *PushChildState(VXSharedState *ss); + void PopChildState(); + void AddInstruction(VXOpcode _op,VXInteger arg0=0,VXInteger arg1=0,VXInteger arg2=0,VXInteger arg3=0) + { + VXInstruction i(_op,arg0,arg1,arg2,arg3); + AddInstruction(i); + } + void AddInstruction(VXInstruction &i); + void SetIntructionParams(VXInteger pos,VXInteger arg0,VXInteger arg1,VXInteger arg2=0,VXInteger arg3=0); + void SetIntructionParam(VXInteger pos,VXInteger arg,VXInteger val); + VXInstruction &GetInstruction(VXInteger pos){return _instructions[pos];} + void PopInstructions(VXInteger size){for(VXInteger i=0;i _childstates; + VXInteger GetConstant(const VXRawObj &cons); + private: + CompilerErrorFunc _errfunc; + void *_errtarget; + VXSharedState *_ss; +}; +#endif //_VXFUNCSTATE_H_ diff --git a/src/core/h_impl.cpp b/src/core/h_impl.cpp new file mode 100644 index 0000000..fd75160 --- /dev/null +++ b/src/core/h_impl.cpp @@ -0,0 +1,663 @@ + +#include "hash.hpp" +#include +#include +#include +#include +#include + +// Constants for MD5Transform routine. +enum +{ + __MD5_S11 = 7, + __MD5_S12 = 12, + __MD5_S13 = 17, + __MD5_S14 = 22, + __MD5_S21 = 5, + __MD5_S22 = 9, + __MD5_S23 = 14, + __MD5_S24 = 20, + __MD5_S31 = 4, + __MD5_S32 = 11, + __MD5_S33 = 16, + __MD5_S34 = 23, + __MD5_S41 = 6, + __MD5_S42 = 10, + __MD5_S43 = 15, + __MD5_S44 = 21 +}; + +namespace Hash +{ + +void Object::updateFromFile(const std::string& path) +{ + int c; + std::ifstream ifs; + ifs.open(path.c_str(), std::ios_base::in | std::ios_base::binary); + while(ifs.good()) + { + c = ifs.get(); + if(ifs.good()) + { + this->update(c); + } + } + ifs.close(); +} + +/* +* SHA1 Impl +*/ + + +std::string SHA1::GenSHA1(const std::string& data, unsigned int length) +{ + SHA1 sh; + length = (length == 0) ? data.length() : length; + sh.update(data.c_str(), length); + sh.finalize(); + return sh.hexDigest(); +} + + +SHA1::SHA1() +{ + reset(); +} + +SHA1::~SHA1() +{ + delete[] Words; + delete[] Message_Block; +} + +unsigned int SHA1::CircularShift(int bits, unsigned word) +{ + return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits)); +} + +std::string SHA1::hexDigest() +{ + std::vector outbuffer; + std::vector digest; + std::string format = "%08x%08x%08x%08x%08x"; + if(finalized == true) + { + digest.resize(6); + outbuffer.resize(60); + result(&digest[0]); + sprintf(&outbuffer[0], + format.c_str(), + digest.at(0), + digest.at(1), + digest.at(2), + digest.at(3), + digest.at(4)); + return (&outbuffer[0]); + } + throw Error( + "SHA1::finalize needs to be called before SHA1::hexDigest"); + return std::string(); // never reached +} + +void SHA1::PadMessage() +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second block. + */ + if (Message_Block_Index > 55) + { + Message_Block[Message_Block_Index++] = 0x80; + while(Message_Block_Index < 64) + { + Message_Block[Message_Block_Index++] = 0; + } + ProcessMessageBlock(); + while(Message_Block_Index < 56) + { + Message_Block[Message_Block_Index++] = 0; + } + } + else + { + Message_Block[Message_Block_Index++] = 0x80; + while(Message_Block_Index < 56) + { + Message_Block[Message_Block_Index++] = 0; + } + } + /* + * Store the message length as the last 8 octets + */ + Message_Block[56] = (Length_High >> 24) & 0xFF; + Message_Block[57] = (Length_High >> 16) & 0xFF; + Message_Block[58] = (Length_High >> 8) & 0xFF; + Message_Block[59] = (Length_High) & 0xFF; + Message_Block[60] = (Length_Low >> 24) & 0xFF; + Message_Block[61] = (Length_Low >> 16) & 0xFF; + Message_Block[62] = (Length_Low >> 8) & 0xFF; + Message_Block[63] = (Length_Low) & 0xFF; + ProcessMessageBlock(); +} + +void SHA1::ProcessMessageBlock() +{ + int t; + unsigned int temp; + unsigned int A; + unsigned int B; + unsigned int C; + unsigned int D; + unsigned int E; + + // Constants defined for SHA-1 + const unsigned int K[] = {0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6}; + + /* + * Initialize the first 16 words in the array W + */ + for(t=0; t<16; t++) + { + Words[t] = ((unsigned int)Message_Block[t * 4]) << 24; + Words[t] |= ((unsigned int)Message_Block[t * 4 + 1]) << 16; + Words[t] |= ((unsigned int)Message_Block[t * 4 + 2]) << 8; + Words[t] |= ((unsigned int)Message_Block[t * 4 + 3]); + } + for(t=16; t<80; t++) + { + Words[t] = CircularShift(1, Words[t-3] ^ Words[t-8] ^ Words[t-14] ^ Words[t-16]); + } + A = H.at(0); + B = H.at(1); + C = H.at(2); + D = H.at(3); + E = H.at(4); + for(t=0; t<20; t++) + { + temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + Words[t] + K[0]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = CircularShift(30,B); + B = A; + A = temp; + } + for(t = 20; t < 40; t++) + { + temp = CircularShift(5,A) + (B ^ C ^ D) + E + Words[t] + K[1]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = CircularShift(30,B); + B = A; + A = temp; + } + for(t = 40; t<60; t++) + { + temp = CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + Words[t] + K[2]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = CircularShift(30,B); + B = A; + A = temp; + } + for(t=60; t<80; t++) + { + temp = CircularShift(5,A) + (B ^ C ^ D) + E + Words[t] + K[3]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = CircularShift(30,B); + B = A; + A = temp; + } + H[0] = (H[0] + A) & 0xFFFFFFFF; + H[1] = (H[1] + B) & 0xFFFFFFFF; + H[2] = (H[2] + C) & 0xFFFFFFFF; + H[3] = (H[3] + D) & 0xFFFFFFFF; + H[4] = (H[4] + E) & 0xFFFFFFFF; + Message_Block_Index = 0; +} + + +void SHA1::reset() +{ + Message_Block = new unsigned int[64]; + Words = new unsigned int[80]; + H.reserve(5); + H.push_back(0x67452301); + H.push_back(0xEFCDAB89); + H.push_back(0x98BADCFE); + H.push_back(0x10325476); + H.push_back(0xC3D2E1F0); + Length_Low = 0; + Length_High = 0; + Message_Block_Index = 0; + Computed = false; + Corrupted = false; + finalized = false; +} + +bool SHA1::result(int* message_digest_array) +{ + int i; + if (Corrupted) + { + return false; + } + if (!Computed) + { + PadMessage(); + Computed = true; + } + for(i=0; i<5; i++) + { + message_digest_array[i] = H.at(i); + } + return true; +} + +void SHA1::update(const char *message_array, unsigned int length) +{ + if (!length) + { + return; + } + if (Computed || Corrupted) + { + Corrupted = true; + return; + } + while((length--) && !Corrupted) + { + Message_Block[Message_Block_Index++] = (*message_array & 0xFF); + Length_Low += 8; + Length_Low &= 0xFFFFFFFF; // Force it to 32 bits + if (Length_Low == 0) + { + Length_High++; + Length_High &= 0xFFFFFFFF; // Force it to 32 bits + if (Length_High == 0) + { + Corrupted = true; // Message is too long + } + } + if(Message_Block_Index == 64) + { + ProcessMessageBlock(); + } + message_array++; + } +} + + +void SHA1::update(const std::string& data) +{ + update(data.c_str(), data.length()); +} + +void SHA1::update(char message_element) +{ + update(&message_element, 1); +} + +void SHA1::finalize() +{ + finalized = true; +} + + + + + +/* +* MD5 Impl +*/ + +std::string MD5::GenMD5(const std::string& str, unsigned int length) +{ + MD5 hs_ctx; + length = (length == 0) ? str.length() : length; + hs_ctx.update(str.c_str(), length); + hs_ctx.finalize(); + return hs_ctx.hexDigest(); +} + +MD5::MD5() +{ + presetup(); + init(); +} + +MD5::~MD5() +{ + cleanup(); +} + +void MD5::presetup() +{ + cleanedup = false; + finalized = false; + buffer = new uint1[blocksize+1]; + count = new uint4[2+1]; + state = new uint4[4+1]; + digest = new uint1[16+1]; + digest_buffer = new char[33+1]; +} + + +void MD5::cleanup() +{ + if(cleanedup == false) + { + delete[] buffer; + delete[] count; + delete[] state; + delete[] digest; + delete[] digest_buffer; + cleanedup = true; + } +} + +void MD5::decode(uint4 output[], const uint1 input[], size_type len) +{ + for (unsigned int i = 0, j = 0; j < len; i++, j += 4) + { + output[i] = + ( + ((uint4)input[j]) | + (((uint4)input[j + 1]) << 8) | + (((uint4)input[j + 2]) << 16) | + (((uint4)input[j + 3]) << 24) + ); + } +} + +void MD5::encode(uint1 output[], const uint4 input[], size_type len) +{ + size_type i; + size_type j; + for (i=0, j=0; j> 8) & 0xff; + output[j+2] = (input[i] >> 16) & 0xff; + output[j+3] = (input[i] >> 24) & 0xff; + } +} + +void MD5::finalize() +{ + size_type index; + size_type padLen; + unsigned char bits[8]; + static unsigned char padding[64] = + { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (!finalized) + { + /* Save number of bits */ + encode(bits, count, 8); + + /* pad out to 56 mod 64. */ + index = count[0] / 8 % 64; + padLen = (index < 56) ? (56 - index) : (120 - index); + update(padding, padLen); + + /* Append length (before padding) */ + update(bits, 8); + + /* Store state in digest */ + encode(digest, state, 16); + + /* Zeroize sensitive information. */ + //memset(buffer, 0, sizeof(buffer)); + memset(buffer, 0, blocksize); + //memset(count, 0, sizeof(count)); + memset(buffer, 0, 2); + finalized = true; + } +} + +std::string MD5::hexDigest() +{ + const char* format = "%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x"; + if(finalized == true) + { + sprintf(digest_buffer, format, + digest[0], digest[1], digest[2], + digest[3], digest[4], digest[5], + digest[6], digest[7], digest[8], + digest[9], digest[10], digest[11], + digest[12], digest[13], digest[14], + digest[15], digest[16]); + return std::string(digest_buffer); + } + throw Error( + "MD5::finalize needs to be called before MD5::hexDigest"); + return std::string(); //never reached +} + +void MD5::init() +{ + finalized=false; + + count[0] = 0; + count[1] = 0; + + // load magic initialization constants. + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; +} + +MD5::uint4 MD5::rotate_left(uint4 x, int n) +{ + return (((x << n) | (x >> (32 - n)))); +} + +MD5::uint4 MD5::logic_F(uint4 x, uint4 y, uint4 z) +{ + return (((x & y) | (~x & z))); +} + +MD5::uint4 MD5::logic_G(uint4 x, uint4 y, uint4 z) +{ + return (((x & z) | (y & ~z))); +} + +MD5::uint4 MD5::logic_H(uint4 x, uint4 y, uint4 z) +{ + return ((x ^ y ^ z)); +} + +MD5::uint4 MD5::logic_I(uint4 x, uint4 y, uint4 z) +{ + return ((y ^ (x | ~z))); +} + +void MD5::rot_round1(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) +{ + a = rotate_left(a + logic_F(b, c, d) + x + ac, s) + b; +} + +void MD5::rot_round2(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) +{ + a = rotate_left(a + logic_G(b, c, d) + x + ac, s) + b; +} + +void MD5::rot_round3(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) +{ + a = rotate_left(a + logic_H(b, c, d) + x + ac, s) + b; +} + +void MD5::rot_round4(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) +{ + a = rotate_left(a + logic_I(b,c,d) + x + ac, s) + b; +} + + +void MD5::transform(const uint1 block[blocksize]) +{ + uint4 a = state[0]; + uint4 b = state[1]; + uint4 c = state[2]; + uint4 d = state[3]; + uint4 x[16]; + decode(x, block, blocksize); + + /* Round 1 */ + rot_round1(a, b, c, d, x[ 0], __MD5_S11, 0xd76aa478); /* 1 */ + rot_round1(d, a, b, c, x[ 1], __MD5_S12, 0xe8c7b756); /* 2 */ + rot_round1(c, d, a, b, x[ 2], __MD5_S13, 0x242070db); /* 3 */ + rot_round1(b, c, d, a, x[ 3], __MD5_S14, 0xc1bdceee); /* 4 */ + rot_round1(a, b, c, d, x[ 4], __MD5_S11, 0xf57c0faf); /* 5 */ + rot_round1(d, a, b, c, x[ 5], __MD5_S12, 0x4787c62a); /* 6 */ + rot_round1(c, d, a, b, x[ 6], __MD5_S13, 0xa8304613); /* 7 */ + rot_round1(b, c, d, a, x[ 7], __MD5_S14, 0xfd469501); /* 8 */ + rot_round1(a, b, c, d, x[ 8], __MD5_S11, 0x698098d8); /* 9 */ + rot_round1(d, a, b, c, x[ 9], __MD5_S12, 0x8b44f7af); /* 10 */ + rot_round1(c, d, a, b, x[10], __MD5_S13, 0xffff5bb1); /* 11 */ + rot_round1(b, c, d, a, x[11], __MD5_S14, 0x895cd7be); /* 12 */ + rot_round1(a, b, c, d, x[12], __MD5_S11, 0x6b901122); /* 13 */ + rot_round1(d, a, b, c, x[13], __MD5_S12, 0xfd987193); /* 14 */ + rot_round1(c, d, a, b, x[14], __MD5_S13, 0xa679438e); /* 15 */ + rot_round1(b, c, d, a, x[15], __MD5_S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + rot_round2(a, b, c, d, x[ 1], __MD5_S21, 0xf61e2562); /* 17 */ + rot_round2(d, a, b, c, x[ 6], __MD5_S22, 0xc040b340); /* 18 */ + rot_round2(c, d, a, b, x[11], __MD5_S23, 0x265e5a51); /* 19 */ + rot_round2(b, c, d, a, x[ 0], __MD5_S24, 0xe9b6c7aa); /* 20 */ + rot_round2(a, b, c, d, x[ 5], __MD5_S21, 0xd62f105d); /* 21 */ + rot_round2(d, a, b, c, x[10], __MD5_S22, 0x2441453); /* 22 */ + rot_round2(c, d, a, b, x[15], __MD5_S23, 0xd8a1e681); /* 23 */ + rot_round2(b, c, d, a, x[ 4], __MD5_S24, 0xe7d3fbc8); /* 24 */ + rot_round2(a, b, c, d, x[ 9], __MD5_S21, 0x21e1cde6); /* 25 */ + rot_round2(d, a, b, c, x[14], __MD5_S22, 0xc33707d6); /* 26 */ + rot_round2(c, d, a, b, x[ 3], __MD5_S23, 0xf4d50d87); /* 27 */ + rot_round2(b, c, d, a, x[ 8], __MD5_S24, 0x455a14ed); /* 28 */ + rot_round2(a, b, c, d, x[13], __MD5_S21, 0xa9e3e905); /* 29 */ + rot_round2(d, a, b, c, x[ 2], __MD5_S22, 0xfcefa3f8); /* 30 */ + rot_round2(c, d, a, b, x[ 7], __MD5_S23, 0x676f02d9); /* 31 */ + rot_round2(b, c, d, a, x[12], __MD5_S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + rot_round3(a, b, c, d, x[ 5], __MD5_S31, 0xfffa3942); /* 33 */ + rot_round3(d, a, b, c, x[ 8], __MD5_S32, 0x8771f681); /* 34 */ + rot_round3(c, d, a, b, x[11], __MD5_S33, 0x6d9d6122); /* 35 */ + rot_round3(b, c, d, a, x[14], __MD5_S34, 0xfde5380c); /* 36 */ + rot_round3(a, b, c, d, x[ 1], __MD5_S31, 0xa4beea44); /* 37 */ + rot_round3(d, a, b, c, x[ 4], __MD5_S32, 0x4bdecfa9); /* 38 */ + rot_round3(c, d, a, b, x[ 7], __MD5_S33, 0xf6bb4b60); /* 39 */ + rot_round3(b, c, d, a, x[10], __MD5_S34, 0xbebfbc70); /* 40 */ + rot_round3(a, b, c, d, x[13], __MD5_S31, 0x289b7ec6); /* 41 */ + rot_round3(d, a, b, c, x[ 0], __MD5_S32, 0xeaa127fa); /* 42 */ + rot_round3(c, d, a, b, x[ 3], __MD5_S33, 0xd4ef3085); /* 43 */ + rot_round3(b, c, d, a, x[ 6], __MD5_S34, 0x4881d05); /* 44 */ + rot_round3(a, b, c, d, x[ 9], __MD5_S31, 0xd9d4d039); /* 45 */ + rot_round3(d, a, b, c, x[12], __MD5_S32, 0xe6db99e5); /* 46 */ + rot_round3(c, d, a, b, x[15], __MD5_S33, 0x1fa27cf8); /* 47 */ + rot_round3(b, c, d, a, x[ 2], __MD5_S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + rot_round4(a, b, c, d, x[ 0], __MD5_S41, 0xf4292244); /* 49 */ + rot_round4(d, a, b, c, x[ 7], __MD5_S42, 0x432aff97); /* 50 */ + rot_round4(c, d, a, b, x[14], __MD5_S43, 0xab9423a7); /* 51 */ + rot_round4(b, c, d, a, x[ 5], __MD5_S44, 0xfc93a039); /* 52 */ + rot_round4(a, b, c, d, x[12], __MD5_S41, 0x655b59c3); /* 53 */ + rot_round4(d, a, b, c, x[ 3], __MD5_S42, 0x8f0ccc92); /* 54 */ + rot_round4(c, d, a, b, x[10], __MD5_S43, 0xffeff47d); /* 55 */ + rot_round4(b, c, d, a, x[ 1], __MD5_S44, 0x85845dd1); /* 56 */ + rot_round4(a, b, c, d, x[ 8], __MD5_S41, 0x6fa87e4f); /* 57 */ + rot_round4(d, a, b, c, x[15], __MD5_S42, 0xfe2ce6e0); /* 58 */ + rot_round4(c, d, a, b, x[ 6], __MD5_S43, 0xa3014314); /* 59 */ + rot_round4(b, c, d, a, x[13], __MD5_S44, 0x4e0811a1); /* 60 */ + rot_round4(a, b, c, d, x[ 4], __MD5_S41, 0xf7537e82); /* 61 */ + rot_round4(d, a, b, c, x[11], __MD5_S42, 0xbd3af235); /* 62 */ + rot_round4(c, d, a, b, x[ 2], __MD5_S43, 0x2ad7d2bb); /* 63 */ + rot_round4(b, c, d, a, x[ 9], __MD5_S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + // Zeroize sensitive information. + //memset(x, 0, sizeof(x)); +} + +void MD5::update(const unsigned char input[], size_type length) +{ + MD5::size_type index; + MD5::size_type i; + MD5::size_type firstpart; + // compute number of bytes mod 64 + index = count[0] / 8 % blocksize; + + // Update number of bits + if ((count[0] += (length << 3)) < (length << 3)) + { + count[1]++; + } + count[1] += (length >> 29); + + // number of bytes we need to fill in buffer + firstpart = 64 - index; + + // transform as many times as possible. + if (length >= firstpart) + { + // fill buffer first, transform + memcpy(&buffer[index], input, firstpart); + transform(buffer); + + // transform chunks of blocksize (64 bytes) + for (i = firstpart; i + blocksize <= length; i += blocksize) + { + transform(&input[i]); + } + index = 0; + } + else + { + i = 0; + } + // buffer remaining input + memcpy(&buffer[index], &input[i], length-i); +} + + +void MD5::update(const char* input, size_type length) +{ + update((const unsigned char*)input, length); +} + +void MD5::update(const std::string& input) +{ + update(input.c_str(), input.length()); +} + +void MD5::update(char input) +{ + update(&input, 1); +} + +} // namespace Hash + diff --git a/src/core/hash.hpp b/src/core/hash.hpp new file mode 100644 index 0000000..db23259 --- /dev/null +++ b/src/core/hash.hpp @@ -0,0 +1,177 @@ + +#ifndef __standalone_hashpp_header_defined__ +#define __standalone_hashpp_header_defined__ + +#include +#include +#include +#include + +namespace Hash +{ + +class Error: public std::runtime_error +{ + public: + Error(const std::string& msg): std::runtime_error(msg) + { + } + + virtual ~Error() throw() + { + } +}; + + +/** +* The HashObject "superclass". +* For maximum portability, rely -only- on functions provided in HashObject. +*/ +class Object +{ + public: + typedef unsigned int size_type; + + public: + virtual ~Object() + {} + + virtual void update(const std::string& input) = 0; + virtual void update(const char* input, size_type length) = 0; + virtual void update(char input) = 0; + virtual void updateFromFile(const std::string& path); + virtual void finalize() = 0; + virtual std::string hexDigest() = 0; + +}; + + +class MD5: public Object +{ + public: // types + typedef unsigned char uint1; // 8bit + typedef unsigned int uint4; // 32bit + + public: // static + static std::string GenMD5(const std::string& str, unsigned int length=0); + + private: // enums + enum + { + blocksize = 64 + }; + + private: // variables + bool finalized; + bool cleanedup; + char* digest_buffer; + MD5::uint1* buffer; + MD5::uint4* count; + MD5::uint4* state; + MD5::uint1* digest; + + private: + void presetup(); + + void init(); + + // apply MD5 algo on a block + void transform(const uint1 block[blocksize]); + + // decodes input (unsigned char) into output (uint4). + // Assumes len is a multiple of 4. + void decode(uint4 output[], const uint1 input[], size_type len); + + + // encodes input (uint4) into output (unsigned char). Assumes len is + // a multiple of 4. + void encode(uint1 output[], const uint4 input[], size_type len); + + // low level logic operations + uint4 logic_F(uint4 x, uint4 y, uint4 z); + + uint4 logic_G(uint4 x, uint4 y, uint4 z); + + uint4 logic_H(uint4 x, uint4 y, uint4 z); + + uint4 logic_I(uint4 x, uint4 y, uint4 z); + + uint4 rotate_left(uint4 x, int n); + + void rot_round1(uint4 &a, uint4 b, uint4 c, uint4 d, + uint4 x, uint4 s, uint4 ac); + + void rot_round2(uint4 &a, uint4 b, uint4 c, uint4 d, + uint4 x, uint4 s, uint4 ac); + + void rot_round3(uint4 &a, uint4 b, uint4 c, uint4 d, + uint4 x, uint4 s, uint4 ac); + + void rot_round4(uint4 &a, uint4 b, uint4 c, uint4 d, + uint4 x, uint4 s, uint4 ac); + + public: // functions + MD5(); + virtual ~MD5(); + void update(const std::string& input); + void update(const unsigned char* input, size_type length); + void update(const char* input, size_type length); + void update(char input); + void finalize(); + void cleanup(); + std::string hexDigest(); +}; + +class SHA1: public Object +{ + public: + static std::string GenSHA1(const std::string& data, unsigned int length=0); + + private: // vars + // Message digest buffers + std::vector H; + + // 512-bit message blocks + unsigned int* Message_Block; + + // words block + unsigned int* Words; + + // Message length in bits + unsigned int Length_Low; + + // Message length in bits + unsigned int Length_High; + + // Index into message block array + int Message_Block_Index; + + // Is the digest computed? + bool Computed; + + // Is the message digest corruped? + bool Corrupted; + + // is the digest finalized? + bool finalized; + + private: + void ProcessMessageBlock(); + void PadMessage(); + unsigned int CircularShift(int bits, unsigned int word); + + public: + SHA1(); + virtual ~SHA1(); + void reset(); + void update(const std::string& data); + void update(const char* message_array, unsigned int length); + void update(char message_element); + bool result(int* message_digest_array); + void finalize(); + std::string hexDigest(); +}; + +} // namespace Hash + +#endif /* __standalone_hashpp_header_defined__ */ diff --git a/src/core/lexer.cpp b/src/core/lexer.cpp new file mode 100644 index 0000000..3dd9595 --- /dev/null +++ b/src/core/lexer.cpp @@ -0,0 +1,727 @@ + +#include +#include + +#include "pcheader.hpp" +#include "table.hpp" +#include "string.hpp" +#include "compiler.hpp" +#include "lexer.hpp" +#include "names.hpp" + +#define CUR_CHAR (_currdata) + +#define RETURN_TOKEN(t) \ + { \ + _prevtoken = _curtoken; \ + _curtoken = t; \ + return t; \ + } + +#define IS_EOB() \ + (CUR_CHAR <= VOX_EOB) + +#define NEXT() \ + { \ + Next(); \ + _currentcolumn++; \ + } + +#define INIT_TEMP_STRING() \ + { \ + _longstr.resize(0); \ + } + +#define APPEND_CHAR(c) \ + { \ + _longstr.push_back(c); \ + } + +#define TERMINATE_BUFFER() \ + { \ + _longstr.push_back('\0'); \ + } + +#define ADD_KEYWORD(key, id) \ + _keywords->NewSlot(VXStringObj::Create(ss, key), VXInteger(id)) + +VXLexer::VXLexer(){} +VXLexer::~VXLexer() +{ + _keywords->Release(); +} + +void VXLexer::Init(VXSharedState *ss, VXLexReadFunc rg, VXUserPointer up,CompilerErrorFunc efunc,void *ed) +{ + _errfunc = efunc; + _errtarget = ed; + _sharedstate = ss; + _keywords = VXTableObj::Create(ss, 27); + ADD_KEYWORD(NAMES_TK_THISVAR, TK_THIS); + ADD_KEYWORD(NAMES_TK_CTOR, TK_CONSTRUCTOR); + ADD_KEYWORD("while", TK_WHILE); + ADD_KEYWORD("do", TK_DO); + ADD_KEYWORD("if", TK_IF); + ADD_KEYWORD("else", TK_ELSE); + ADD_KEYWORD("break", TK_BREAK); + ADD_KEYWORD("continue", TK_CONTINUE); + ADD_KEYWORD("return", TK_RETURN); + ADD_KEYWORD("null", TK_NULL); + ADD_KEYWORD("function", TK_FUNCTION); + ADD_KEYWORD("local", TK_LOCAL); + ADD_KEYWORD("for", TK_FOR); + ADD_KEYWORD("foreach", TK_FOREACH); + ADD_KEYWORD("in", TK_IN); + ADD_KEYWORD("typeof", TK_TYPEOF); + ADD_KEYWORD("base", TK_BASE); + ADD_KEYWORD("delete", TK_DELETE); + ADD_KEYWORD("try", TK_TRY); + ADD_KEYWORD("catch", TK_CATCH); + ADD_KEYWORD("throw", TK_THROW); + ADD_KEYWORD("clone", TK_CLONE); + ADD_KEYWORD("yield", TK_YIELD); + ADD_KEYWORD("resume", TK_RESUME); + ADD_KEYWORD("switch", TK_SWITCH); + ADD_KEYWORD("case", TK_CASE); + ADD_KEYWORD("default", TK_DEFAULT); + ADD_KEYWORD("class", TK_CLASS); + ADD_KEYWORD("extends", TK_EXTENDS); + ADD_KEYWORD("instanceof", TK_INSTANCEOF); + ADD_KEYWORD("true", TK_TRUE); + ADD_KEYWORD("false", TK_FALSE); + ADD_KEYWORD("static", TK_STATIC); + ADD_KEYWORD("enum", TK_ENUM); + ADD_KEYWORD("const", TK_CONST); + //ADD_KEYWORD("import", TK_IMPORT); + + _readf = rg; + _up = up; + _lasttokenline = _currentline = 1; + _currentcolumn = 0; + _prevtoken = -1; + _reached_eof = false; + Next(); +} + +void VXLexer::Error(const char *err) +{ + _errfunc(_errtarget,err); +} + +void VXLexer::Next() +{ + VXInteger t = _readf(_up); + if(t > VOX_MAX_CHAR) + { + Error("Invalid character"); + } + if(t != 0) + { + _currdata = (LexChar)t; + return; + } + _currdata = VOX_EOB; + _reached_eof = true; +} + +const char *VXLexer::Tok2Str(VXInteger tok) +{ + VXObject itr, key, val; + VXInteger nitr; + while((nitr = _keywords->Next(false,itr, key, val)) != -1) + { + itr = (VXInteger)nitr; + if(((VXInteger)_integer(val)) == tok) + { + return _stringval(key); + } + } + return NULL; +} + +void VXLexer::LexBlockComment() +{ + bool done = false; + while(!done) + { + switch(CUR_CHAR) + { + case '*': + { + NEXT(); + if(CUR_CHAR == '/') + { + done = true; + NEXT(); + } + }; + continue; + case '\n': + _currentline++; + NEXT(); + continue; + case + VOX_EOB: Error("missing \"*/\" in comment"); + default: + NEXT(); + } + } +} + +void VXLexer::LexLineComment() +{ + do + { + NEXT(); + } while (CUR_CHAR != '\n' && (!IS_EOB())); +} + +VXInteger VXLexer::Lex() +{ + _lasttokenline = _currentline; + while(CUR_CHAR != VOX_EOB) + { + switch(CUR_CHAR) + { + case '\t': + case '\r': + case ' ': + NEXT(); + continue; + case '\n': + _currentline++; + _prevtoken=_curtoken; + _curtoken='\n'; + NEXT(); + _currentcolumn=1; + continue; + case '#': + LexLineComment(); + continue; + case '/': + NEXT(); + switch(CUR_CHAR) + { + case '*': + NEXT(); + LexBlockComment(); + continue; + case '/': + LexLineComment(); + continue; + case '=': + NEXT(); + RETURN_TOKEN(TK_DIVEQ); + continue; + case '>': + NEXT(); + RETURN_TOKEN(TK_ATTR_CLOSE); + continue; + default: + RETURN_TOKEN('/'); + } + case '=': + NEXT(); + if (CUR_CHAR != '=') + { + RETURN_TOKEN('=') + } + else + { + NEXT(); + RETURN_TOKEN(TK_EQ); + } + case '<': + NEXT(); + switch(CUR_CHAR) + { + case '=': + NEXT(); + if(CUR_CHAR == '>') + { + NEXT(); + RETURN_TOKEN(TK_3WAYSCMP); + } + RETURN_TOKEN(TK_LE) + break; + /** + * this is the old slot parsing part, which had to be removed + * because it causes ambigious syntax. + * consider: 5<-6 + * Usually, that would translate to: + * expression of (five less than (minus six)) + * but with this slot operator, it translates to: + * expression of (assign (minus six) to five) + * which is invalid and ambigious. one "workaround" was + * to write '5< -6' (note the space) instead, which is awful. + */ + /* + case '-': + NEXT(); + RETURN_TOKEN(TK_NEWSLOT); + Error("The old slot operator '<-' is deprecated; Use ':=' instead"); + break; + */ + case '<': + NEXT(); + RETURN_TOKEN(TK_SHIFTL); + break; + case '/': + NEXT(); + RETURN_TOKEN(TK_ATTR_OPEN); + break; + } + RETURN_TOKEN('<'); + + case '>': + NEXT(); + if (CUR_CHAR == '=') + { + NEXT(); + RETURN_TOKEN(TK_GE); + } + else if(CUR_CHAR == '>') + { + NEXT(); + if(CUR_CHAR == '>') + { + NEXT(); + RETURN_TOKEN(TK_USHIFTR); + } + RETURN_TOKEN(TK_SHIFTR); + } + else + { + RETURN_TOKEN('>') + } + case '!': + NEXT(); + if (CUR_CHAR != '=') + { + RETURN_TOKEN('!') + } + else + { + NEXT(); + RETURN_TOKEN(TK_NE); + } + case '@': + { + VXInteger stype; + VXInteger until = '"'; + NEXT(); + if(CUR_CHAR != '"') + { + Error("Expected '\"'"); + } + if((stype=ReadString(until, true)) != -1) + { + RETURN_TOKEN(stype); + } + Error("error parsing the string literal (missing quote?)"); + } + case '"': + case '\'': + { + VXInteger stype; + if((stype=ReadString(CUR_CHAR,false))!=-1) + { + RETURN_TOKEN(stype); + } + Error("error parsing the string literal"); + } + case '{': + case '}': + case '(': + case ')': + case '[': + case ']': + case ';': + case ',': + case '?': + case '^': + case '~': + { + VXInteger ret = CUR_CHAR; + NEXT(); + RETURN_TOKEN(ret); + } + case '.': + NEXT(); + if (CUR_CHAR != '.') + { + RETURN_TOKEN('.') + } + NEXT(); + if(CUR_CHAR != '.') + { + Error("invalid token '..'"); + } + NEXT(); + RETURN_TOKEN(TK_VARPARAMS); + case '&': + NEXT(); + if (CUR_CHAR != '&') + { + RETURN_TOKEN('&') + } + else { NEXT(); RETURN_TOKEN(TK_AND); } + case '|': + NEXT(); + if (CUR_CHAR != '|'){ RETURN_TOKEN('|') } + else { NEXT(); RETURN_TOKEN(TK_OR); } + case ':': + NEXT(); + if(CUR_CHAR == '=') + { + NEXT(); + RETURN_TOKEN(TK_NEWSLOT); + //break; + } + if (CUR_CHAR != ':') + { + RETURN_TOKEN(':') + } + else + { + NEXT(); + RETURN_TOKEN(TK_DOUBLE_COLON); + } + case '*': + NEXT(); + if (CUR_CHAR == '=') + { + NEXT(); + RETURN_TOKEN(TK_MULEQ); + } + else + { + RETURN_TOKEN('*'); + } + case '%': + NEXT(); + if(CUR_CHAR == '=') + { + NEXT(); RETURN_TOKEN(TK_MODEQ); + } + else + { + RETURN_TOKEN('%'); + } + case '-': + NEXT(); + if (CUR_CHAR == '=') + { + NEXT(); + RETURN_TOKEN(TK_MINUSEQ); + } + else if(CUR_CHAR == '-') + { + NEXT(); + RETURN_TOKEN(TK_MINUSMINUS); + } + else + { + RETURN_TOKEN('-'); + } + case '+': + NEXT(); + if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);} + else if (CUR_CHAR == '+'){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);} + else RETURN_TOKEN('+'); + case VOX_EOB: + return 0; + default: + { + if (isdigit(CUR_CHAR)) + { + VXInteger ret = ReadNumber(); + RETURN_TOKEN(ret); + } + else if (isalpha(CUR_CHAR) || CUR_CHAR == '_') + { + VXInteger t = ReadID(); + RETURN_TOKEN(t); + } + else + { + VXInteger c = CUR_CHAR; + if (iscntrl((int)c)) Error("unexpected character (ctrl)"); + NEXT(); + RETURN_TOKEN(c); + } + RETURN_TOKEN(0); + } + } + } + return 0; +} + +VXInteger VXLexer::GetIDType(char *s) +{ + VXObject t; + if(_keywords->Get(VXStringObj::Create(_sharedstate, s), t)) + { + return VXInteger(_integer(t)); + } + return TK_IDENTIFIER; +} + +#define ADD_ESCAPE(find_this, add_this) \ + case find_this: \ + APPEND_CHAR(add_this); \ + NEXT(); \ + break; + +VXInteger VXLexer::ReadString(VXInteger ndelim, bool verbatim) +{ + INIT_TEMP_STRING(); + NEXT(); + if(IS_EOB()) + { + return -1; + } + for(;;) + { + while(CUR_CHAR != ndelim) + { + switch(CUR_CHAR) + { + case VOX_EOB: + Error("unfinished string"); + return -1; + case '\n': + APPEND_CHAR(CUR_CHAR); NEXT(); + _currentline++; + break; + case '\\': + if(verbatim == false) + { + NEXT(); + switch(CUR_CHAR) + { + case 'x': + { + VXInteger n = 0; + const VXInteger maxdigits = 4; + char* sTemp; + char temp[maxdigits+1]; + NEXT(); + if(!isxdigit(CUR_CHAR)) + { + Error("hexadecimal number expected"); + } + while(isxdigit(CUR_CHAR) && n < maxdigits) + { + temp[n] = CUR_CHAR; + n++; + NEXT(); + } + temp[n] = 0; + APPEND_CHAR((char)strtoul(temp,&sTemp,16)); + } + break; + ADD_ESCAPE('t', '\t') + ADD_ESCAPE('a', '\a') + ADD_ESCAPE('b', '\b') + ADD_ESCAPE('n', '\n') + ADD_ESCAPE('r', '\r') + ADD_ESCAPE('v', '\v') + ADD_ESCAPE('e', 033) + ADD_ESCAPE('0', '\0') + ADD_ESCAPE('\\', '\\') + ADD_ESCAPE('"', '\"') + ADD_ESCAPE('\'', '\'') + default: + Error("unrecognised escape char"); + break; + } + } + else + { + APPEND_CHAR('\\'); + NEXT(); + } + break; + default: + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + } + NEXT(); + //double quotation + if(verbatim && CUR_CHAR == '"') + { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + else + { + break; + } + } + TERMINATE_BUFFER(); + VXInteger len = _longstr.size()-1; + if(ndelim == '\'') + { + if(len == 0) Error("empty constant"); + if(len > 1) Error("constant too long"); + _nvalue = _longstr[0]; + return TK_INTEGER; + } + _svalue = &_longstr[0]; + return TK_STRING_LITERAL; +} + +void LexHexadecimal(const char *s,VXInteger *res) +{ + *res = 0; + while(*s != 0) + { + if(isdigit(*s)) + { + *res = (*res)*16+((*s++)-'0'); + } + else if(isxdigit(*s)) + { + *res = (*res)*16+(toupper(*s++)-'A'+10); + } + else + { + vox_assert(0); + } + } +} + +void LexInteger(const char *s, VXInteger* res) +{ + (*res) = atol(s); +} + +VXInteger scisodigit(VXInteger c) +{ + return c >= '0' && c <= '7'; +} + +void LexOctal(const char *s,VXInteger *res) +{ + *res = 0; + while(*s != 0) + { + if(scisodigit(*s)) + { + *res = (*res)*8+((*s++)-'0'); + } + else + { + vox_assert(0); + } + } +} + +VXInteger isexponent(VXInteger c) +{ + return c == 'e' || c=='E'; +} + +#define MAX_HEX_DIGITS (sizeof(VXInteger)*2) +VXInteger VXLexer::ReadNumber() +{ + #define TINT 1 + #define TFLOAT 2 + #define THEX 3 + #define TSCIENTIFIC 4 + #define TOCTAL 5 + VXInteger type = TINT; + VXInteger firstchar = CUR_CHAR; + char *sTemp; + INIT_TEMP_STRING(); + NEXT(); + if(firstchar == '0' && (toupper(CUR_CHAR) == 'X' || scisodigit(CUR_CHAR))) + { + if(scisodigit(CUR_CHAR)) + { + type = TOCTAL; + while(scisodigit(CUR_CHAR)) + { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(isdigit(CUR_CHAR)) + { + Error("invalid octal number"); + } + } + else + { + NEXT(); + type = THEX; + while(isxdigit(CUR_CHAR)) + { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(_longstr.size() > MAX_HEX_DIGITS) Error("too many digits for an Hex number"); + } + } + else + { + APPEND_CHAR((int)firstchar); + while (CUR_CHAR == '.' || isdigit(CUR_CHAR) || isexponent(CUR_CHAR)) + { + if(CUR_CHAR == '.') type = TFLOAT; + if(isexponent(CUR_CHAR)) + { + if(type != TFLOAT) Error("invalid numeric format"); + type = TSCIENTIFIC; + APPEND_CHAR(CUR_CHAR); + NEXT(); + if(CUR_CHAR == '+' || CUR_CHAR == '-') + { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(!isdigit(CUR_CHAR)) Error("exponent expected"); + } + + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + } + TERMINATE_BUFFER(); + switch(type) + { + case TSCIENTIFIC: + case TFLOAT: + _fvalue = (VXFloat)strtod(&_longstr[0],&sTemp); + return TK_FLOAT; + case TINT: + LexInteger(&_longstr[0], (VXInteger*)&_nvalue); + return TK_INTEGER; + case THEX: + LexHexadecimal(&_longstr[0], (VXInteger*)&_nvalue); + return TK_INTEGER; + case TOCTAL: + LexOctal(&_longstr[0], (VXInteger*)&_nvalue); + return TK_INTEGER; + } + return 0; +} + +VXInteger VXLexer::ReadID() +{ + VXInteger res; + INIT_TEMP_STRING(); + do + { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } while(isalnum(CUR_CHAR) || CUR_CHAR == '_'); + TERMINATE_BUFFER(); + res = GetIDType(&_longstr[0]); + if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) + { + _svalue = &_longstr[0]; + } + return res; +} diff --git a/src/core/lexer.hpp b/src/core/lexer.hpp new file mode 100644 index 0000000..c9492dc --- /dev/null +++ b/src/core/lexer.hpp @@ -0,0 +1,42 @@ + +#ifndef _VXLEXER_H_ +#define _VXLEXER_H_ + +typedef unsigned char LexChar; +struct VXLexer +{ + VXLexer(); + ~VXLexer(); + void Init(VXSharedState *ss,VXLexReadFunc rg,VXUserPointer up,CompilerErrorFunc efunc,void *ed); + void Error(const char *err); + VXInteger Lex(); + const char *Tok2Str(VXInteger tok); + private: + VXInteger GetIDType(char *s); + void Parse_Escapes(bool); + VXInteger ReadString(VXInteger ndelim,bool verbatim); + VXInteger ReadNumber(); + void LexBlockComment(); + void LexLineComment(); + VXInteger ReadID(); + void Next(); + VXInteger _curtoken; + VXTableObj *_keywords; + bool _reached_eof; + public: + VXInteger _prevtoken; + VXInteger _currentline; + VXInteger _lasttokenline; + VXInteger _currentcolumn; + const char *_svalue; + VXInteger _nvalue; + VXFloat _fvalue; + VXLexReadFunc _readf; + VXUserPointer _up; + LexChar _currdata; + VXSharedState *_sharedstate; + VXVector _longstr; + CompilerErrorFunc _errfunc; + void *_errtarget; +}; +#endif diff --git a/src/core/mem.cpp b/src/core/mem.cpp new file mode 100644 index 0000000..e67766d --- /dev/null +++ b/src/core/mem.cpp @@ -0,0 +1,34 @@ + +#include "pcheader.hpp" + +void* vox_mem_malloc(VXUnsignedInteger size) +{ + return malloc(size); +} + +void* vox_mem_realloc(void *p, VXUnsignedInteger oldsize, VXUnsignedInteger size) +{ + (void)oldsize; + return realloc(p, size); +} + +void vox_mem_free(void *p, VXUnsignedInteger size) +{ + (void)size; + free(p); +} + +void *vox_malloc(VXUnsignedInteger size) +{ + return VX_MALLOC(size); +} + +void *vox_realloc(void* p,VXUnsignedInteger oldsize,VXUnsignedInteger newsize) +{ + return VX_REALLOC(p,oldsize,newsize); +} + +void vox_free(void *p,VXUnsignedInteger size) +{ + VX_FREE(p,size); +} diff --git a/src/core/mem.hpp b/src/core/mem.hpp new file mode 100644 index 0000000..9a1f7e1 --- /dev/null +++ b/src/core/mem.hpp @@ -0,0 +1,20 @@ +#define vox_new(__ptr, __type) \ + { \ + __ptr = (__type *)vox_mem_malloc(sizeof(__type)); \ + new(__ptr) __type; \ + } + +#define vox_delete(__ptr,__type) \ + { \ + __ptr->~__type(); \ + vox_mem_free(__ptr, sizeof(__type)); \ + } + +#define VX_MALLOC(__size) \ + vox_mem_malloc((__size)); + +#define VX_FREE(__ptr,__size) \ + vox_mem_free((__ptr), (__size)); + +#define VX_REALLOC(__ptr,__oldsize,__size) \ + vox_mem_realloc((__ptr),(__oldsize),(__size)); diff --git a/src/core/names.hpp b/src/core/names.hpp new file mode 100644 index 0000000..21321b8 --- /dev/null +++ b/src/core/names.hpp @@ -0,0 +1,35 @@ + +#ifndef __vox_names_hpp__ +#define __vox_names_hpp__ + +// names +#define NAMES_MAINFUNC "__main__" +#define NAMES_VARGV "vargv" +#define NAMES_ANONFUNC "" +#define NAMES_ANONFILE "" + + +// token names +#define NAMES_TK_THISVAR "this" +#define NAMES_TK_CTOR "constructor" + +// generator statuses +#define GENERATOR_STATUS_SUSPENDED "suspended" +#define GENERATOR_STATUS_RUNNING "running" +#define GENERATOR_STATUS_DEAD "dead" + +// types names and other yadda yadda +#define S_TYPE_NULL "null" +#define S_TYPE_STRING "string" +#define S_TYPE_INTEGER "integer" +#define S_TYPE_FLOAT "float" +#define S_TYPE_USERPOINTER "userpointer" +#define S_TYPE_TABLE "table" +#define S_TYPE_ARRAY "array" +#define S_TYPE_CLOSURE "closure" +#define S_TYPE_ARRAY "array" +#define S_TYPE_ARRAY "array" +#define S_TYPE_ARRAY "array" + + +#endif /* __vox_names_hpp__ */ diff --git a/src/core/object.cpp b/src/core/object.cpp new file mode 100644 index 0000000..c1297dc --- /dev/null +++ b/src/core/object.cpp @@ -0,0 +1,911 @@ + +#include "pcheader.hpp" +#include "vm.hpp" +#include "string.hpp" +#include "table.hpp" +#include "userdata.hpp" +#include "funcproto.hpp" +#include "class.hpp" +#include "closure.hpp" + + + + +VXWeakRefObj *VXRefCountedObj::GetWeakRef(VXOType type) +{ + if(!_weakref) + { + vox_new(_weakref,VXWeakRefObj); + _weakref->_obj._type = type; + _weakref->_obj._unVal.pRefCounted = this; + } + return _weakref; +} + +VXRefCountedObj::~VXRefCountedObj() +{ + if(_weakref) + { + _weakref->_obj._type = VX_OT_NULL; + _weakref->_obj._unVal.pRefCounted = NULL; + } +} + +void VXWeakRefObj::Release() +{ + if(ISREFCOUNTED(_obj._type)) + { + _obj._unVal.pRefCounted->_weakref = NULL; + } + vox_delete(this,VXWeakRefObj); +} + +bool VXDelegableObj::GetMetaMethod(VXState *v,VXMetaMethod mm,VXObject &res) +{ + if(_delegate) + { + return _delegate->Get((*_ss(v)->_metamethods)[mm],res); + } + return false; +} + +bool VXDelegableObj::SetDelegate(VXTableObj *mt) +{ + VXTableObj *temp = mt; + if(temp == this) return false; + while (temp) + { + //cycle detected + if (temp->_delegate == this) return false; + temp = temp->_delegate; + } + if (mt) __ObjAddRef(mt); + __ObjRelease(_delegate); + _delegate = mt; + return true; +} + +bool VXGeneratorObj::Yield(VXState *v,VXInteger target) +{ + if(_state==eSuspended) + { + v->ThrowError("internal vm error, yielding dead generator"); + return false; + } + if(_state==eDead) + { + v->ThrowError("internal vm error, yielding a dead generator"); + return false; + } + VXInteger size = ((v->_top) - (v->_stackbase)); + _stack.resize(size); + VXRawObj _this = v->_stack[v->_stackbase]; + _stack.values()[0] = ( + ISREFCOUNTED(type(_this)) ? + VXObject(_refcounted(_this)->GetWeakRef(type(_this))) : + _this); + for(VXInteger n =1; n_stack[v->_stackbase+n]; + } + for(VXInteger j =0; j < size; j++) + { + v->_stack[v->_stackbase+j].Null(); + } + + _ci = *v->ci; + _ci._generator=NULL; + for(VXInteger i=0;i<_ci._etraps;i++) + { + _etraps.push_back(v->_etraps.top()); + v->_etraps.pop_back(); + } + _state=eSuspended; + return true; +} + +bool VXGeneratorObj::Resume(VXState *v,VXObject &dest) +{ + if(_state==eDead) + { + v->ThrowError("resuming dead generator"); + return false; + } + if(_state==eRunning) + { + v->ThrowError("resuming active generator"); + return false; + } + VXInteger size = _stack.size(); + VXInteger target = &dest - &(v->_stack.values()[v->_stackbase]); + vox_assert(target>=0 && target<=255); + if(!v->EnterFrame(v->_top, v->_top + size, false)) + { + return false; + } + v->ci->_generator = this; + v->ci->_target = (VXInt32)target; + v->ci->_closure = _ci._closure; + v->ci->_ip = _ci._ip; + v->ci->_literals = _ci._literals; + v->ci->_ncalls = _ci._ncalls; + v->ci->_etraps = _ci._etraps; + v->ci->_root = _ci._root; + for(VXInteger i=0;i<_ci._etraps;i++) + { + v->_etraps.push_back(_etraps.top()); + _etraps.pop_back(); + } + VXRawObj _this = _stack.values()[0]; + v->_stack[v->_stackbase] = type(_this) == VX_OT_WEAKREF ? _weakref(_this)->_obj : _this; + + for(VXInteger n = 1; n_stack[v->_stackbase+n] = _stack.values()[n]; + _stack.values()[n].Null(); + } + + _state=eRunning; + if (v->_debughook) + { + v->CallDebugHook('c'); + } + return true; +} + + +void VXInstanceObj::Mark(VXCollectable **chain) +{ + START_MARK() + _class->Mark(chain); + VXUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(VXUnsignedInteger i =0; i< nvalues; i++) + { + VXSharedState::MarkObject(_values[i], chain); + } + END_MARK() +} + +void VXGeneratorObj::Mark(VXCollectable **chain) +{ + START_MARK() + for(VXUnsignedInteger i = 0; i < _stack.size(); i++) + { + VXSharedState::MarkObject(_stack[i], chain); + } + VXSharedState::MarkObject(_closure, chain); + END_MARK() +} + + + +void VXOuterObj::Mark(VXCollectable **chain) +{ + START_MARK() + /* If the valptr points to a closed value, that value is alive */ + if(_valptr == &_value) + { + VXSharedState::MarkObject(_value, chain); + } + END_MARK() +} + +void VXUserDataObj::Mark(VXCollectable **chain) +{ + START_MARK() + if(_delegate) + { + _delegate->Mark(chain); + } + END_MARK() +} + +void VXCollectable::UnMark() +{ + _uiRef&=~MARK_FLAG; +} + + + +void VXObject::Null() +{ + __Release(_type ,_unVal); + _type = VX_OT_NULL; + _unVal.raw = (VXRawValue)NULL; +} + +bool VXObject::IsNull() const +{ + return (_unVal.raw == (VXRawValue)NULL); +} + +bool VXObject::IsNumeric() const +{ + return (Type() & VXOBJECT_NUMERIC); +} + + +/** +* Object instance access methods +*/ + +VXInteger VXObject::Integer() +{ + return _unVal.nInteger; +} + +VXInteger VXObject::Integer() const +{ + return _unVal.nInteger; +} + +VXFloat VXObject::Float() +{ + return _unVal.fFloat; +} + +VXFloat VXObject::Float() const +{ + return _unVal.fFloat; +} + +VXStringObj* VXObject::String() +{ + return _unVal.pString; +} + + +VXStringObj* VXObject::String() const +{ + return _unVal.pString; +} + +void VXObject::String(const char** dest, VXInteger* len_dest) const +{ + VXStringObj* ob = this->String(); + (*dest) = ob->_val; + if(len_dest != NULL) + { + (*len_dest) = ob->_len; + } +} + +VXTableObj* VXObject::Table() +{ + return _unVal.pTable; +} + +VXTableObj* VXObject::Table() const +{ + return _unVal.pTable; +} + +VXArrayObj* VXObject::Array() +{ + return _unVal.pArray; +} + +VXArrayObj* VXObject::Array() const +{ + return _unVal.pArray; +} +VXForeignClosureObj* VXObject::Closure() +{ + return _unVal.pClosure; +} + +VXGeneratorObj* VXObject::Generator() +{ + return _unVal.pGenerator; +} + +VXNativeClosureObj* VXObject::NativeClosure() +{ + return _unVal.pNativeClosure; +} + +VXUserDataObj* VXObject::UserData() +{ + return _unVal.pUserData; +} + +VXUserPointer VXObject::UserPointer() +{ + return _unVal.pUserPointer; +} + +VXState* VXObject::Thread() +{ + return _unVal.pThread; +} + +VXFuncProtoObj* VXObject::FuncProto() +{ + return _unVal.pFunctionProto; +} + +VXClassObj* VXObject::Class() +{ + return _unVal.pClass; +} + +VXInstanceObj* VXObject::Instance() +{ + return _unVal.pInstance; +} + +VXDelegableObj* VXObject::Delegable() +{ + return (VXDelegableObj*)(_unVal.pDelegable); +} + +VXWeakRefObj* VXObject::WeakRef() +{ + return _unVal.pWeakRef; +} + +VXOuterObj* VXObject::Outer() +{ + return _unVal.pOuter; +} + +VXRefCountedObj* VXObject::RefCounted() +{ + return _unVal.pRefCounted; +} + +VXRefCountedObj* VXObject::RefCounted() const +{ + return _unVal.pRefCounted; +} + +VXRawValue VXObject::Raw() +{ + return _unVal.raw; +} + + +template<> VXFloat VXObject::As() +{ + return Float(); +} + +template<> VXInteger VXObject::As() +{ + return Integer(); +} + +/** +* Type Information +*/ + +VXOType VXObject::Type() const +{ + return _type; +} + +const char* VXObject::TypeString() const +{ + return IdType2Name(this->Type()); +} + +bool VXObject::Is(VXOType tp) const +{ + return Type() == tp; +} + +bool VXObject::IsTable() const +{ + return Is(VX_OT_TABLE); +} + +bool VXObject::IsArray() const +{ + return Is(VX_OT_ARRAY); +} + +bool VXObject::IsFunction() const +{ + return Is(VX_OT_FUNCPROTO); +} +bool VXObject::IsClosure() const +{ + return Is(VX_OT_CLOSURE); +} + +bool VXObject::IsNativeClosure() const +{ + return Is(VX_OT_NATIVECLOSURE); +} + +bool VXObject::IsGenerator() const +{ + return Is(VX_OT_GENERATOR); +} + +bool VXObject::IsString() const +{ + return Is(VX_OT_STRING); +} + +bool VXObject::IsInteger() const +{ + return Is(VX_OT_INTEGER); +} + +bool VXObject::IsFloat() const +{ + return Is(VX_OT_FLOAT); +} + +bool VXObject::IsUserPointer() const +{ + return Is(VX_OT_USERPOINTER); +} + +bool VXObject::IsUserData() const +{ + return Is(VX_OT_USERDATA); +} + +bool VXObject::IsThread() const +{ + return Is(VX_OT_THREAD); +} + +bool VXObject::IsClass() const +{ + return Is(VX_OT_CLASS); +} + +bool VXObject::IsInstance() const +{ + return Is(VX_OT_INSTANCE); +} + +bool VXObject::IsBool() const +{ + return Is(VX_OT_BOOL); +} + +bool VXObject::IsWeakRef() const +{ + return Is(VX_OT_WEAKREF); +} + +/** +* Constructors +*/ + +VXObject::~VXObject() +{ + __Release(_type,_unVal); +} + +VXObject::VXObject() +{ + VX_OBJECT_RAWINIT(this) + _type=VX_OT_NULL; + _unVal.pUserPointer=NULL; +} +VXObject::VXObject(const VXObject &o) +{ + _type=o._type; + _unVal=o._unVal; + VX_ADDREF(_type,_unVal); +} + +VXObject::VXObject(const VXRawObj &o) +{ + _type=o._type; + _unVal=o._unVal; + VX_ADDREF(_type,_unVal); +} + + +VXObject::VXObject(bool bBool) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_BOOL; + _unVal.nInteger = bBool?1:0; +} + +VXObject::VXObject (VXTableObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_TABLE; + _unVal.pTable = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + +VXObject::VXObject (VXClassObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_CLASS; + _unVal.pClass = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + +VXObject & VXObject::operator= (VXClassObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_CLASS; + VX_REFOBJECT_INIT (this) + _unVal.pClass = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject::VXObject (VXInstanceObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_INSTANCE; + _unVal.pInstance = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + +VXObject::VXObject(VXArrayObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_ARRAY; + _unVal.pArray = x; + vox_assert(_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + + + +VXObject::VXObject (VXForeignClosureObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_CLOSURE; + _unVal.pClosure = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + + + +VXObject::VXObject (VXNativeClosureObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_NATIVECLOSURE; + _unVal.pNativeClosure = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + + + +VXObject::VXObject (VXOuterObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_OUTER; + _unVal.pOuter = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + + +VXObject::VXObject (VXGeneratorObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_GENERATOR; + _unVal.pGenerator = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + +VXObject::VXObject (VXStringObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_STRING; + _unVal.pString = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + +VXObject::VXObject (VXUserDataObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_USERDATA; + _unVal.pUserData = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + + +VXObject::VXObject (VXWeakRefObj * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_WEAKREF; + _unVal.pWeakRef = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + + +VXObject::VXObject (VXState * x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_THREAD; + _unVal.pThread = x; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + + +VXObject::VXObject (VXFuncProtoObj * x) +{ + VX_OBJECT_RAWINIT(this) + _unVal.pFunctionProto = x; + _type = VX_OT_FUNCPROTO; + vox_assert (_unVal.pTable); + _unVal.pRefCounted->_uiRef++; +} + +VXObject::VXObject(VXInteger x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_INTEGER; + _unVal.nInteger = x; +} + +VXObject::VXObject (VXFloat x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_FLOAT; + _unVal.fFloat = x; +} + +VXObject::VXObject (VXUserPointer x) +{ + VX_OBJECT_RAWINIT(this) + _type = VX_OT_USERPOINTER; + _unVal.pUserPointer = x; +} + +/** +* operator=() methods +*/ + +VXObject & VXObject::operator= (VXGeneratorObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_GENERATOR; + VX_REFOBJECT_INIT (this) + _unVal.pGenerator = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject & VXObject::operator= (VXOuterObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_OUTER; + VX_REFOBJECT_INIT (this) + _unVal.pOuter = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + + +VXObject & VXObject::operator= (VXNativeClosureObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_NATIVECLOSURE; + VX_REFOBJECT_INIT (this) + _unVal.pNativeClosure = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject & VXObject::operator= (VXForeignClosureObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_CLOSURE; + VX_REFOBJECT_INIT (this) + _unVal.pClosure = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject & VXObject::operator= (VXArrayObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_ARRAY; + VX_REFOBJECT_INIT(this) + _unVal.pArray = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject & VXObject::operator= (VXInstanceObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_INSTANCE; + VX_REFOBJECT_INIT (this) + _unVal.pInstance = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject & VXObject::operator= (VXTableObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_TABLE; + VX_REFOBJECT_INIT(this) + _unVal.pTable = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject& VXObject::operator=(const VXObject& obj) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType=_type; + unOldVal=_unVal; + _unVal = obj._unVal; + _type = obj._type; + VX_ADDREF(_type,_unVal); + __Release(tOldType,unOldVal); + return *this; +} + +VXObject& VXObject::operator=(const VXRawObj& obj) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType=_type; + unOldVal=_unVal; + _unVal = obj._unVal; + _type = obj._type; + VX_ADDREF(_type,_unVal); + __Release(tOldType,unOldVal); + return *this; +} + +VXObject& VXObject::operator=(bool b) +{ + __Release(_type,_unVal); + VX_OBJECT_RAWINIT(this) + _type = VX_OT_BOOL; + _unVal.nInteger = b?1:0; + return *this; +} + +VXObject & VXObject::operator= (VXStringObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_STRING; + VX_REFOBJECT_INIT (this) + _unVal.pString = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject & VXObject::operator= (VXUserDataObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_USERDATA; + VX_REFOBJECT_INIT (this) + _unVal.pUserData = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject & VXObject::operator= (VXWeakRefObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_WEAKREF; + VX_REFOBJECT_INIT (this) + _unVal.pWeakRef = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject & VXObject::operator= (VXState * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_THREAD; + VX_REFOBJECT_INIT (this) + _unVal.pThread = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + +VXObject & VXObject::operator= (VXFuncProtoObj * x) +{ + VXOType tOldType; + VXRawObj::Value unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = VX_OT_FUNCPROTO; + VX_REFOBJECT_INIT (this) + _unVal.pFunctionProto = x; + _unVal.pRefCounted->_uiRef++; + __Release (tOldType, unOldVal); + return *this; +} + + +VXObject & VXObject::operator= (VXFloat x) +{ + __Release (_type, _unVal); + _type = VX_OT_FLOAT; + VX_OBJECT_RAWINIT(this) + _unVal.fFloat = x; + return *this; +} + +VXObject & VXObject::operator= (VXInteger x) +{ + __Release (_type, _unVal); + _type = VX_OT_INTEGER; + VX_OBJECT_RAWINIT(this) + _unVal.nInteger = x; + return *this; +} + +VXObject & VXObject::operator= (VXUserPointer x) +{ + __Release (_type, _unVal); + _type = VX_OT_USERPOINTER; + VX_OBJECT_RAWINIT(this) + _unVal.pUserPointer = x; + return *this; +} + + diff --git a/src/core/object.hpp b/src/core/object.hpp new file mode 100644 index 0000000..4f8f597 --- /dev/null +++ b/src/core/object.hpp @@ -0,0 +1,195 @@ + +#ifndef _VXOBJECT_H_ +#define _VXOBJECT_H_ + +#include "utils.hpp" + +#define UINT_MINUS_ONE (0xFFFFFFFF) + +#define VX_OBJECT_RAWINIT(selfptr) { selfptr->_unVal.raw = 0; } +#define VX_REFOBJECT_INIT(selfptr) VX_OBJECT_RAWINIT(selfptr) + +/* +#define VX_CLOSURESTREAM_HEAD (('L' << 24) | ('X' << 16) | ('O' << 8) | 'V') +#define VX_CLOSURESTREAM_PART (('P' << 24) | ('A' << 16) |('R' << 8) | 'T') +#define VX_CLOSURESTREAM_TAIL (('T' << 24) | ('A' << 16) |('I' << 8) | 'L') +*/ + +#define VX_CLOSURESTREAM_HEAD \ + (('!' << 24) | ('X' << 16) | ('O' << 8) | 'V') + +#define VX_CLOSURESTREAM_PART \ + (('T' << 24) | (10 << 16) | ('P' << 8) | 100) + +#define VX_CLOSURESTREAM_TAIL \ + (('L' << 24) | (10 << 16) | ('T' << 8) | 200) + +#define _CHECK_IO(exp) { if(!exp)return false; } + +#define VX_MM_ADD "__add__" +#define VX_MM_SUB "__sub__" +#define VX_MM_MUL "__mul__" +#define VX_MM_DIV "__div__" +#define VX_MM_UNM "__unm__" +#define VX_MM_MODULO "__modulo__" +#define VX_MM_SET "__set__" +#define VX_MM_GET "__get__" +#define VX_MM_TYPEOF "__typeof__" +#define VX_MM_NEXTI "__nexti__" +#define VX_MM_CMP "__cmp__" +#define VX_MM_CALL "__call__" +#define VX_MM_CLONED "__cloned__" +#define VX_MM_NEWSLOT "__newslot__" +#define VX_MM_DELSLOT "__delslot__" +#define VX_MM_TOSTRING "__tostring__" +#define VX_MM_NEWMEMBER "__newmember__" +#define VX_MM_INHERITED "__inherited__" + + +#define VX_CONSTRUCT_VECTOR(type,size,ptr) \ +{ \ + for(VXInteger n = 0; n < ((VXInteger)size); n++) { \ + new (&ptr[n]) type(); \ + } \ +} + +#define VX_DESTRUCT_VECTOR(type,size,ptr) { \ + for(VXInteger nl = 0; nl < ((VXInteger)size); nl++) { \ + ptr[nl].~type(); \ + } \ +} + +#define VX_COPY_VECTOR(dest,src,size) { \ + for(VXInteger _n_ = 0; _n_ < ((VXInteger)size); _n_++) { \ + dest[_n_] = src[_n_]; \ + } \ +} + + + + + + + + +#define VX_REALVAL(o) (type((o)) != VX_OT_WEAKREF?(VXRawObj)o:_weakref(o)->_obj) + + +#define VX_ADDREF(type,unval) if(ISREFCOUNTED(type)) \ + { \ + unval.pRefCounted->_uiRef++; \ + } + +#define __Release(type,unval) \ + if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)==0)) \ + { \ + unval.pRefCounted->Release(); \ + } + +#define __ObjRelease(obj) { \ + if((obj)) { \ + (obj)->_uiRef--; \ + if((obj)->_uiRef == 0) \ + (obj)->Release(); \ + (obj) = NULL; \ + } \ +} + +#define __ObjAddRef(obj) { \ + (obj)->_uiRef++; \ +} + +#define type(obj) ((obj)._type) +#define is_delegable(t) (t.Type() & VXOBJECT_DELEGABLE) + +#define _integer(obj) ((obj)._unVal.nInteger) +#define _float(obj) ((obj)._unVal.fFloat) +#define _string(obj) ((obj)._unVal.pString) +#define _table(obj) ((obj)._unVal.pTable) +#define _array(obj) ((obj)._unVal.pArray) +#define _closure(obj) ((obj)._unVal.pClosure) +#define _generator(obj) ((obj)._unVal.pGenerator) +#define _nativeclosure(obj) ((obj)._unVal.pNativeClosure) +#define _userdata(obj) ((obj)._unVal.pUserData) +#define _userpointerval(obj) ((obj)._unVal.pUserPointer) +#define _thread(obj) ((obj)._unVal.pThread) +#define _funcproto(obj) ((obj)._unVal.pFunctionProto) +#define _class(obj) ((obj)._unVal.pClass) +#define _instance(obj) ((obj)._unVal.pInstance) +#define _delegable(obj) ((VXDelegableObj *)(obj)._unVal.pDelegable) +#define _weakref(obj) ((obj)._unVal.pWeakRef) +#define _outer(obj) ((obj)._unVal.pOuter) +#define _refcounted(obj) ((obj)._unVal.pRefCounted) +#define _rawval(obj) ((obj)._unVal.raw) + +#define _stringval(obj) (((obj)._unVal).pString->Value()) +#define _stringlen(obj) (((obj)._unVal).pString->Length()) +#define _userdataval(obj) ((VXUserPointer)vox_aligning((obj)._unVal.pUserData + 1)) + +#define tofloat(num) ((type(num)==VX_OT_INTEGER)?(VXFloat)_integer(num):_float(num)) +#define tointeger(num) ((type(num)==VX_OT_FLOAT)?(VXInteger)_float(num):_integer(num)) + +#define MINPOWER2 4 + +#define START_MARK() \ + if(!(_uiRef & MARK_FLAG))\ + { \ + _uiRef |= MARK_FLAG; + +#define END_MARK() \ + this->RemoveFromChain(&_sharedstate->_gc_chain, this); \ + this->AddToChain(chain, this); \ + } + + +#define MARK_FLAG 0x80000000 +#define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj) +#define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG)) this->RemoveFromChain(chain,obj);} +#define CHAINABLE_OBJ VXCollectable +#define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;} + + + +struct VXSharedState; +struct VXObject; +typedef VXVector VXIntVec; + +inline void _Swap(VXRawObj &a,VXRawObj &b) +{ + VXOType tOldType = a._type; + VXRawObj::Value unOldVal = a._unVal; + a._type = b._type; + a._unVal = b._unVal; + b._type = tOldType; + b._unVal = unOldVal; +} + +template void _NULL_VXOBJECT_VECTOR(Type& vec, VXInteger size) +{ + VXInteger n; + for(n= 0; n< size; n++) + { + vec[n].Null(); + } +} + + +VXUnsignedInteger TranslateIndex(const VXObject &idx); + + +const char *GetTypeName(const VXObject &obj1); +const char *IdType2Name(VXOType type); + +bool SafeWrite(VXState* v, + VXWriteFunc write, + VXUserPointer up, + VXUserPointer dest, + VXInteger size); +bool SafeRead(VXState* v,VXWriteFunc read,VXUserPointer up,VXUserPointer dest,VXInteger size); +bool WriteTag(VXState* v,VXWriteFunc write,VXUserPointer up,VXUnsignedInteger32 tag); +bool CheckTag(VXState* v,VXWriteFunc read,VXUserPointer up,VXUnsignedInteger32 tag); +bool WriteObject(VXState* v,VXUserPointer up,VXWriteFunc write,VXObject &o); +bool ReadObject(VXState* v,VXUserPointer up,VXReadFunc read,VXObject &o); + + +#endif //_VXOBJECT_H_ diff --git a/src/core/opcodes.cpp b/src/core/opcodes.cpp new file mode 100644 index 0000000..bdb3055 --- /dev/null +++ b/src/core/opcodes.cpp @@ -0,0 +1,586 @@ + + +#include +#include "opcodes.hpp" +#include "vm.hpp" + +void FindOuter(VXState* v, VXObject &target, VXObject *stackindex) +{ + VXOuterObj **pp = &v->_openouters; + VXOuterObj *p; + VXOuterObj *otr; + while ((p = *pp) != NULL && p->_valptr >= stackindex) + { + if (p->_valptr == stackindex) + { + target = VXObject(p); + return; + } + pp = &p->_next; + } + otr = VXOuterObj::Create(_ss(v), stackindex); + otr->_next = *pp; + otr->_idx = (stackindex - v->_stack.values()); + __ObjAddRef(otr); + *pp = otr; + target = VXObject(otr); +} + +void RelocateOuters(VXState* v) +{ + VXOuterObj *p = v->_openouters; + while (p) + { + p->_valptr = v->_stack.values() + p->_idx; + p = p->_next; + } +} + +void CloseOuters(VXState* v, VXObject *stackindex) +{ + VXOuterObj *p; + while ((p = v->_openouters) != NULL && p->_valptr >= stackindex) + { + p->_value = *(p->_valptr); + p->_valptr = &p->_value; + v->_openouters = p->_next; + __ObjRelease(p); + } +} + + +bool CallMetaMethod(VXState* v, VXObject &closure, + VXMetaMethod mm, + VXInteger nparams, + VXObject &outres) +{ + (void)mm; + v->_nmetamethodscall++; + if(v->Call(closure, nparams, v->_top - nparams, outres, false)) + { + v->_nmetamethodscall--; + v->Pop(nparams); + return true; + } + v->_nmetamethodscall--; + v->Pop(nparams); + return false; +} + + + +bool ArithMetaMethod(VXState* v, + VXInteger op, + const VXObject &o1, + const VXObject &o2, + VXObject &dest) +{ + VXMetaMethod mm; + switch(op) + { + case '+': + mm=VX_MT_ADD; + break; + case '-': + mm=VX_MT_SUB; + break; + case '/': + mm=VX_MT_DIV; + break; + case '*': + mm=VX_MT_MUL; + break; + case '%': + mm=VX_MT_MODULO; + break; + default: + mm = VX_MT_ADD; + vox_assert(0); + break; //shutup compiler + } + if(is_delegable(o1) && _delegable(o1)->_delegate) + { + VXObject closure; + if(_delegable(o1)->GetMetaMethod(v, mm, closure)) + { + v->Push(o1); + v->Push(o2); + bool b; + b = CallMetaMethod(v, closure,mm,2,dest); + return b; + } + } + v->ThrowError("arith op %c on between '%s' and '%s'",op, GetTypeName(o1), GetTypeName(o2)); + return false; +} + +bool NEG_OP(VXState* v, VXObject &trg, const VXObject &o) +{ + + switch(type(o)) + { + case VX_OT_INTEGER: + trg = -_integer(o); + return true; + case VX_OT_FLOAT: + trg = -_float(o); + return true; + case VX_OT_TABLE: + case VX_OT_USERDATA: + case VX_OT_INSTANCE: + if(_delegable(o)->_delegate) + { + VXObject closure; + if(_delegable(o)->GetMetaMethod(v, VX_MT_UNM, closure)) + { + v->Push(o); + if(!CallMetaMethod(v, closure, VX_MT_UNM, 1, v->temp_reg)) + { + return false; + } + _Swap(trg, v->temp_reg); + return true; + + } + } + default: + break; //shutup compiler + } + v->ThrowError("attempt to negate a %s", GetTypeName(o)); + return false; +} + +bool PLOCAL_INC(VXState* v, VXInteger op, + VXObject &target, + VXObject &a, + VXObject &incr) +{ + VXObject trg; + _RET_ON_FAIL(ARITH_OP(v, op , trg, a, incr)); + target = a; + a = trg; + return true; +} + +bool CMP_OP(VXState* v, + VXInteger op, + const VXObject &o1, + const VXObject &o2, + VXObject &res) +{ + VXInteger r; + if(v->ObjCmp(o1, o2, r)) + { + switch(op) + { + case CMP_G: + res = (r > 0); + return true; + case CMP_GE: + res = (r >= 0); + return true; + case CMP_L: + res = (r < 0); + return true; + case CMP_LE: + res = (r <= 0); + return true; + case CMP_3W: + res = r; + return true; + } + vox_assert(0); + } + return false; +} + + +bool Return(VXState* v, VXInteger _arg0, + VXInteger _arg1, + VXObject &retval) +{ + VXObject *dest; + bool _isroot = v->ci->_root; + VXInteger callerbase = v->_stackbase - v->ci->_prevstkbase; + if (v->_debughook) + { + for(VXInteger i=0; ici->_ncalls; i++) + { + v->CallDebugHook('r'); + } + } + if (_isroot) + { + dest = &(retval); + } + else if (v->ci->_target == -1) + { + dest = NULL; + } + else + { + dest = &v->_stack.values()[callerbase + v->ci->_target]; + } + if (dest) + { + if(_arg0 != 0xFF) + { + *dest = v->_stack.values()[v->_stackbase+_arg1]; + } + else + { + dest->Null(); + } + } + v->LeaveFrame(); + return _isroot ? true : false; +} + +bool ARITH_OP(VXState* v, VXUnsignedInteger op, + VXObject &trg, + const VXObject &o1, + const VXObject &o2) +{ + VXInteger tmask = type(o1) | type(o2); + + if(tmask & VX_RT_STRING) + { + if(op == '+') + { + if(!v->StringCat(o1, o2, trg)) + { + return false; + } + return true; + } + } + switch(tmask) + { + case VX_OT_INTEGER: + { + VXInteger res; + VXInteger i1 = _integer(o1); + VXInteger i2 = _integer(o2); + switch(op) + { + case '+': + res = i1 + i2; + break; + case '-': + res = i1 - i2; + break; + case '/': + if(i2 == 0) + { + v->ThrowError("division by zero"); + return false; + } + res = i1 / i2; + break; + case '*': + res = i1 * i2; + break; + case '%': + if(i2 == 0) + { + v->ThrowError("modulo by zero"); + return false; + } + res = i1 % i2; + break; + default: + res = 0xDEADBEEF; + } + trg = res; + } + break; + case (VX_OT_FLOAT|VX_OT_INTEGER): + case (VX_OT_FLOAT): + { + VXFloat res; + VXFloat f1 = tofloat(o1); + VXFloat f2 = tofloat(o2); + switch(op) + { + case '+': + res = f1 + f2; + break; + case '-': + res = f1 - f2; + break; + case '/': + res = f1 / f2; + break; + case '*': + res = f1 * f2; + break; + case '%': + res = VXFloat(fmod((double)f1,(double)f2)); + break; + default: + res = 0x0f; + } + trg = res; + } + break; + default: + if(!ArithMetaMethod(v, op,o1,o2,trg)) + { + return false; + } + } + return true; +} + +bool BW_OP(VXState* v, + VXUnsignedInteger op, + VXObject& trg, + const VXObject& o1, + const VXObject& o2) +{ + VXInteger res; + if((type(o1) | type(o2)) == VX_OT_INTEGER) + { + VXInteger i1 = _integer(o1); + VXInteger i2 = _integer(o2); + switch(op) + { + case BW_AND: + res = i1 & i2; + break; + case BW_OR: + res = i1 | i2; + break; + case BW_XOR: + res = i1 ^ i2; + break; + case BW_SHIFTL: + res = i1 << i2; + break; + case BW_SHIFTR: + res = i1 >> i2; + break; + case BW_USHIFTR: + res = (VXInteger)(*((VXUnsignedInteger*)&i1) >> i2); + break; + default: + { + v->ThrowError("internal vm error: bitwise op failed"); + return false; + } + } + } + else + { + v->ThrowError("bitwise op between '%s' and '%s'",GetTypeName(o1),GetTypeName(o2)); + return false; + } + trg = res; + return true; +} + +#define __VSTK(_vm_, a) (_vm_->_stack.values()[_vm_->_stackbase+(a)]) +#define VSTK(vm, a) (((vm->_stack).values())[(vm->_stackbase)+(a)]) + + +bool CLOSURE_OP(VXState* v, VXObject &target, + VXFuncProtoObj *func) +{ + VXInteger nouters; + VXForeignClosureObj *closure = VXForeignClosureObj::Create(_ss(v), func); + if((nouters = func->_noutervalues)) + { + for(VXInteger i = 0; i_outervalues[i]; + switch(outer._type) + { + case otLOCAL: + + FindOuter(v, + closure->_outervalues[i], + &VSTK(v, _integer(outer._src)) + ); + break; + case otOUTER: + closure->_outervalues[i] = + _closure(v->ci->_closure)->_outervalues[_integer(outer._src)]; + break; + } + } + } + VXInteger ndefparams; + if((ndefparams = func->_ndefaultparams)) + { + for(VXInteger i = 0; i < ndefparams; i++) + { + VXInteger spos = func->_defaultparams[i]; + closure->_defaultparams[i] = v->_stack.values()[v->_stackbase + spos]; + } + } + target = closure; + return true; +} + +bool CLASS_OP(VXState* v, + VXObject &target, + VXInteger baseclass, + VXInteger attributes) +{ + VXClassObj *base = NULL; + VXObject attrs; + if(baseclass != -1) + { + if(type(v->_stack.values()[v->_stackbase+baseclass]) != VX_OT_CLASS) + { + v->ThrowError("cannot inherit from builtin type %s", + GetTypeName(v->_stack.values()[v->_stackbase+baseclass])); + return false; + } + base = _class(v->_stack.values()[v->_stackbase + baseclass]); + } + if(attributes != MAX_FUNC_STACKSIZE) + { + attrs = v->_stack.values()[v->_stackbase+attributes]; + } + target = VXClassObj::Create(_ss(v), base); + if(type(_class(target)->_metamethods[VX_MT_INHERITED]) != VX_OT_NULL) + { + int nparams = 2; + VXObject ret; + v->Push(target); + v->Push(attrs); + v->Call(_class(target)->_metamethods[VX_MT_INHERITED], + nparams, (v->_top - nparams), ret, false); + v->Pop(nparams); + } + _class(target)->_attributes = attrs; + return true; +} + +bool FOREACH_OP(VXState* v, VXObject &o1, + VXObject &o2, + VXObject &o3, + VXObject &o4, + VXInteger arg_2, + int exitpos, + int &jump) +{ + VXInteger nrefidx; + (void)arg_2; + switch(type(o1)) + { + case VX_OT_TABLE: + if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) + { + _FINISH(exitpos); + } + o4 = (VXInteger)nrefidx; + _FINISH(1); + case VX_OT_ARRAY: + if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) + { + _FINISH(exitpos); + } + o4 = (VXInteger) nrefidx; _FINISH(1); + case VX_OT_STRING: + if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1) + { + _FINISH(exitpos); + } + o4 = (VXInteger)nrefidx; + _FINISH(1); + case VX_OT_CLASS: + if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1) + { + _FINISH(exitpos); + } + o4 = (VXInteger)nrefidx; + _FINISH(1); + case VX_OT_USERDATA: + case VX_OT_INSTANCE: + if(_delegable(o1)->_delegate) + { + VXObject itr; + VXObject closure; + if(_delegable(o1)->GetMetaMethod(v, VX_MT_NEXTI, closure)) + { + v->Push(o1); + v->Push(o4); + if(CallMetaMethod(v, closure, VX_MT_NEXTI, 2, itr)) + { + o4 = o2 = itr; + if(type(itr) == VX_OT_NULL) + { + _FINISH(exitpos); + } + if(!v->Get(o1, itr, o3, false, DONT_FALL_BACK)) + { + // could be changed + v->ThrowError("__nexti__ returned an invalid index"); + return false; + } + _FINISH(1); + } + else + { + return false; + } + } + v->ThrowError("__nexti__ failed"); + return false; + } + break; + case VX_OT_GENERATOR: + if(_generator(o1)->_state == VXGeneratorObj::eDead) + { + _FINISH(exitpos); + } + if(_generator(o1)->_state == VXGeneratorObj::eSuspended) + { + VXInteger idx = 0; + if(type(o4) == VX_OT_INTEGER) + { + idx = _integer(o4) + 1; + } + o2 = idx; + o4 = idx; + _generator(o1)->Resume(v, o3); + _FINISH(0); + } + default: + v->ThrowError("cannot iterate %s", GetTypeName(o1)); + } + return false; //cannot be hit(just to avoid warnings) +} + +bool DerefInc(VXState* v, VXInteger op, + VXObject &target, + VXObject &self, + VXObject &key, + VXObject &incr, + bool postfix, + VXInteger selfidx) +{ + VXObject tmp; + VXObject tself = self; + VXObject tkey = key; + if(!v->Get(tself, tkey, tmp, false, selfidx)) + { + return false; + } + if(!ARITH_OP(v, op , target, tmp, incr)) + { + return false; + } + if(!v->Set(tself, tkey, target,selfidx)) + { + return false; + } + if(postfix) + { + target = tmp; + } + return true; +} + diff --git a/src/core/opcodes.hpp b/src/core/opcodes.hpp new file mode 100644 index 0000000..8e0b893 --- /dev/null +++ b/src/core/opcodes.hpp @@ -0,0 +1,231 @@ + +#ifndef _VXOPCODES_H_ +#define _VXOPCODES_H_ + +#include "pcheader.hpp" + +#define MAX_FUNC_STACKSIZE 0xFF +#define MAX_LITERALS ((VXInteger)0x7FFFFFFF) +#define NEW_SLVX_OT_ATTRIBUTES_FLAG 0x01 +#define NEW_SLVX_OT_STATIC_FLAG 0x02 + +#define _FINISH(howmuchtojump) \ + {\ + jump = howmuchtojump; \ + return true; \ + } + +#define _RET_ON_FAIL(exp) { if(!exp) return false; } + + + +enum BitWiseOP +{ + BW_AND = 0, + BW_OR = 2, + BW_XOR = 3, + BW_SHIFTL = 4, + BW_SHIFTR = 5, + BW_USHIFTR = 6 +}; + +enum CmpOP +{ + CMP_G = 0, + CMP_GE = 2, + CMP_L = 3, + CMP_LE = 4, + CMP_3W = 5 +}; + +enum NewObjectType +{ + NVX_OT_TABLE = 0, + NVX_OT_ARRAY = 1, + NVX_OT_CLASS = 2 +}; + +enum AppendArrayType +{ + AAT_STACK = 0, + AAT_LITERAL = 1, + AAT_INT = 2, + AAT_FLOAT = 3, + AAT_BOOL = 4 +}; + +enum VXOpcode +{ + _OP_LINE= 0x00, + _OP_LOAD= 0x01, + _OP_LOADINT= 0x02, + _OP_LOADFLOAT= 0x03, + _OP_DLOAD= 0x04, + _OP_TAILCALL= 0x05, + _OP_CALL= 0x06, + _OP_PREPCALL= 0x07, + _OP_PREPCALLK= 0x08, + _OP_GETK= 0x09, + _OP_MOVE= 0x0A, + _OP_NEWSLOT= 0x0B, + _OP_DELETE= 0x0C, + _OP_SET= 0x0D, + _OP_GET= 0x0E, + _OP_EQ= 0x0F, + _OP_NE= 0x10, + _OP_ADD= 0x11, + _OP_SUB= 0x12, + _OP_MUL= 0x13, + _OP_DIV= 0x14, + _OP_MOD= 0x15, + _OP_BITW= 0x16, + _OP_RETURN= 0x17, + _OP_LOADNULLS= 0x18, + _OP_LOADROOT= 0x19, + _OP_LOADBOOL= 0x1A, + _OP_DMOVE= 0x1B, + _OP_JMP= 0x1C, + _OP_JCMP= 0x1D, + _OP_JZ= 0x1E, + _OP_SETOUTER= 0x1F, + _OP_GETOUTER= 0x20, + _OP_NEWOBJ= 0x21, + _OP_APPENDARRAY= 0x22, + _OP_COMPARITH= 0x23, + _OP_INC= 0x24, + _OP_INCL= 0x25, + _OP_PINC= 0x26, + _OP_PINCL= 0x27, + _OP_CMP= 0x28, + _OP_EXISTS= 0x29, + _OP_INSTANCEOF= 0x2A, + _OP_AND= 0x2B, + _OP_OR= 0x2C, + _OP_NEG= 0x2D, + _OP_NOT= 0x2E, + _OP_BWNOT= 0x2F, + _OP_CLOSURE= 0x30, + _OP_YIELD= 0x31, + _OP_RESUME= 0x32, + _OP_FOREACH= 0x33, + _OP_POSTFOREACH= 0x34, + _OP_CLONE= 0x35, + _OP_TYPEOF= 0x36, + _OP_PUSHTRAP= 0x37, + _OP_POPTRAP= 0x38, + _OP_THROW= 0x39, + _OP_NEWSLOTA= 0x3A, + _OP_GETBASE= 0x3B, + _OP_CLOSE= 0x3C +}; + +struct VXInstructionDesc +{ + const char *name; +}; + +struct VXInstruction +{ + VXInstruction() + { + }; + + VXInstruction(VXOpcode _op,VXInteger a0=0,VXInteger a1=0,VXInteger a2=0,VXInteger a3=0) + { + op = _op; + _arg0 = (unsigned char)a0; + _arg1 = (VXInteger)a1; + _arg2 = (unsigned char)a2; + _arg3 = (unsigned char)a3; + } + + VXInteger _arg1; + unsigned char op; + unsigned char _arg0; + unsigned char _arg2; + unsigned char _arg3; +}; + +typedef VXVector VXInstructionVec; + + +void FindOuter(VXState* v, VXObject &target, VXObject *stackindex); +void RelocateOuters(VXState* v); +void CloseOuters(VXState* v, VXObject *stackindex); + +bool CallMetaMethod(VXState* v, + VXObject &closure, + VXMetaMethod mm, + VXInteger nparams, + VXObject &outres); + +bool ArithMetaMethod(VXState* v, + VXInteger op, + const VXObject &o1, + const VXObject &o2, + VXObject &dest); + +bool Return(VXState* v, + VXInteger _arg0, + VXInteger _arg1, + VXObject &retval); +//new stuff +bool ARITH_OP(VXState* v, + VXUnsignedInteger op, + VXObject &trg, + const VXObject &o1, + const VXObject &o2); + +bool BW_OP(VXState* v, + VXUnsignedInteger op, + VXObject &trg, + const VXObject &o1, + const VXObject &o2); + +bool NEG_OP(VXState* v, + VXObject &trg, + const VXObject &o1); + +bool CMP_OP(VXState* v, + VXInteger op, + const VXObject &o1, + const VXObject &o2, + VXObject &res); + +bool CLOSURE_OP(VXState* v, + VXObject &target, + VXFuncProtoObj *func); + +bool CLASS_OP(VXState* v, + VXObject &target, + VXInteger base, + VXInteger attrs); +//return true if the loop is finished + +bool FOREACH_OP(VXState* v, + VXObject &o1, + VXObject &o2, + VXObject &o3, + VXObject &o4, + VXInteger arg_2, + int exitpos, + int &jump); + +bool PLOCAL_INC(VXState* v, + VXInteger op, + VXObject &target, + VXObject &a, + VXObject &incr); + +bool DerefInc(VXState* v, + VXInteger op, + VXObject &target, + VXObject &self, + VXObject &key, + VXObject &incr, + bool postfix, + VXInteger arg0); + + + +#endif // _VXOPCODES_H_ diff --git a/src/core/pcheader.hpp b/src/core/pcheader.hpp new file mode 100644 index 0000000..2495cbc --- /dev/null +++ b/src/core/pcheader.hpp @@ -0,0 +1,51 @@ + +#ifndef _VXPCHEADER_H_ +#define _VXPCHEADER_H_ + +#include +#include +#include +#include +#include +#include +#include "errors.hpp" +#include "vox.h" + +#define VX_VMSTATE_IDLE 0 +#define VX_VMSTATE_RUNNING 1 +#define VX_VMSTATE_SUSPENDED 2 + +#define VOX_EOB 0 + +#define VX_MATCHTYPEMASKSTRING (-99999) +#define VX_RAW_TYPE(type) ((type) & VX_RT_MASK) + +#define ISREFCOUNTED(t) (t & VXOBJECT_REF_COUNTED) + +#define _PRINT_INT_FMT "%d" + +#define VOX_MAX_CHAR 0xFF + +// VX_ALIGNMENT shall be less than or equal to VX_MALLOC alignments, and +// its value shall be power of 2. +#define VX_ALIGNMENT 4 + +#define VX_BYTECODE_STREAM_TAG 0xFAFA + +#define DOSTRING_DEFAULTBUFFERNAME "" + +#define vox_new(__ptr, __type) \ + { \ + __ptr = (__type *)vox_mem_malloc(sizeof(__type)); \ + new(__ptr) __type; \ + } + +#define vox_delete(__ptr,__type) \ + { \ + __ptr->~__type(); \ + vox_mem_free(__ptr, sizeof(__type)); \ + } + +#define vox_aligning(v) (((size_t)(v) + (VX_ALIGNMENT-1)) & (~(VX_ALIGNMENT-1))) + +#endif //_VXPCHEADER_H_ diff --git a/src/core/repr.cpp b/src/core/repr.cpp new file mode 100644 index 0000000..87364f4 --- /dev/null +++ b/src/core/repr.cpp @@ -0,0 +1,122 @@ + +#include "baselib.hpp" +#include "string.hpp" +#include + +#define Err(...) \ + { \ + this->returns = v->ThrowError(__VA_ARGS__); \ + return; \ + } + +VXRepr::VXRepr(VXState* _v, const VXObject& ob): v(_v), root_ob(ob) +{ + returns = VX_OK; + do_serialize(root_ob); +} + +void VXRepr::do_serialize(const VXObject& o) +{ + switch(o.Type()) + { + case VX_OT_NULL: + strm << "null"; + break; + case VX_OT_CLOSURE: + case VX_OT_NATIVECLOSURE: + /* TODO: this is where the function proto should be emitted */ + case VX_OT_INSTANCE: + case VX_OT_CLASS: + case VX_OT_WEAKREF: + emit_othertype(o); + break; + case VX_OT_STRING: + emit_string(o); + break; + case VX_OT_ARRAY: + emit_array(o); + break; + case VX_OT_TABLE: + emit_table(o); + break; + case VX_OT_INTEGER: + strm << o.Integer(); + break; + case VX_OT_FLOAT: + strm << o.Float(); + break; + default: + Err("cannot serialize type '%s'", o.TypeString()); + break; + } +} + +void VXRepr::emit_othertype(const VXObject& o) +{ + const VXUserPointer o_addr = VXUserPointer(&o); + strm << "<" << o.TypeString() << " at " << o_addr << ">"; +} + +void VXRepr::emit_string(const VXObject& o) +{ + std::string tmp; + const char* str_p; + VXInteger len_p; + o.String(&str_p, &len_p); + tmp.append(str_p, len_p); + strm << strhelp_quote(tmp); +} + +void VXRepr::emit_table(const VXObject& o) +{ + VXInteger size; + VXInteger count = 0; + VXInteger ridx = 0; // start at first index + VXObject outkey; + VXObject outval; + VXTableObj* tb = o.Table(); + size = tb->Size(); + strm << "{"; + while((ridx = tb->Next(false, ridx, outkey, outval)) != -1) + { + do_serialize(outkey); + strm << ": "; + do_serialize(outval); + if((count+1) != size) + { + strm << ", "; + } + count++; + } + strm << "}"; +} + +void VXRepr::emit_array(const VXObject& o) +{ + VXInteger size; + VXInteger ridx = 0; // start at first index + VXObject outkey; + VXObject outval; + VXArrayObj* arr = o.Array(); + size = arr->Size(); + strm << "["; + while((ridx = arr->Next(ridx, outkey, outval)) != -1) + { + do_serialize(outval); + if(ridx != size) + { + strm << ", "; + } + } + strm << "]"; +} + +std::string VXRepr::str() +{ + return this->strm.str(); +} + +VXInteger VXRepr::status() +{ + return returns; +} diff --git a/src/core/state.cpp b/src/core/state.cpp new file mode 100644 index 0000000..d79b9c6 --- /dev/null +++ b/src/core/state.cpp @@ -0,0 +1,692 @@ + +#include "pcheader.hpp" +#include "opcodes.hpp" +#include "vm.hpp" +#include "funcproto.hpp" +#include "closure.hpp" +#include "string.hpp" +#include "table.hpp" +#include "userdata.hpp" +#include "class.hpp" + +//VXObject _null_; +//VXObject _true_(true); +//VXObject _false_(false); +//VXObject _one_((VXInteger)1); +//VXObject _minusone_((VXInteger)-1); + +VXSharedState::VXSharedState() +{ + _compilererrorhandler = NULL; + _printfunc = NULL; + _errorfunc = NULL; + _debuginfo = false; + _notifyallexceptions = false; +} + +#define newsysstring(s) { \ + _systemstrings->push_back(VXStringObj::Create(this,s)); \ + } + +#define newmetamethod(s) { \ + _metamethods->push_back(VXStringObj::Create(this,s)); \ + _table(_metamethodsmap)->NewSlot(_metamethods->back(),(VXInteger)(_metamethods->size()-1)); \ + } + +bool CompileTypemask(VXIntVec &res,const char *typemask) +{ + VXInteger i = 0; + + VXInteger mask = 0; + while(typemask[i] != 0) + { + + switch(typemask[i]) + { + case 'o': mask |= VX_RT_NULL; break; + case 'i': mask |= VX_RT_INTEGER; break; + case 'f': mask |= VX_RT_FLOAT; break; + case 'n': mask |= (VX_RT_FLOAT | VX_RT_INTEGER); break; + case 's': mask |= VX_RT_STRING; break; + case 't': mask |= VX_RT_TABLE; break; + case 'a': mask |= VX_RT_ARRAY; break; + case 'u': mask |= VX_RT_USERDATA; break; + case 'c': mask |= (VX_RT_CLOSURE | VX_RT_NATIVECLOSURE); break; + case 'b': mask |= VX_RT_BOOL; break; + case 'g': mask |= VX_RT_GENERATOR; break; + case 'p': mask |= VX_RT_USERPOINTER; break; + case 'v': mask |= VX_RT_THREAD; break; + case 'x': mask |= VX_RT_INSTANCE; break; + case 'y': mask |= VX_RT_CLASS; break; + case 'r': mask |= VX_RT_WEAKREF; break; + case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue; + //ignores spaces + case ' ': i++; continue; + default: + return false; + } + i++; + if(typemask[i] == '|') + { + i++; + if(typemask[i] == 0) + return false; + continue; + } + res.push_back(mask); + mask = 0; + + } + return true; +} + +VXTableObj *CreateDefaultDelegate(VXSharedState *ss,VXRegFunction *funcz, bool isdeleg=true) +{ + VXInteger i=0; + (void)isdeleg; + VXTableObj* t =VXTableObj::Create(ss,0); + while(funcz[i].name != 0) + { + VXNativeClosureObj *nc = VXNativeClosureObj::Create(ss,funcz[i].func,0); + nc->_nparamscheck = funcz[i].nparamscheck; + nc->_name = VXStringObj::Create(ss,funcz[i].name); + if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask)) + { + return NULL; + } + t->NewSlot(VXStringObj::Create(ss,funcz[i].name),nc); + i++; + } + return t; +} + +void VXSharedState::Init() +{ + _scratchpad=NULL; + _scratchpadsize=0; + #ifndef NO_GARBAGE_COLLECTOR + _gc_chain=NULL; + #endif + _stringtable = (VXStringObjTable*)VX_MALLOC(sizeof(VXStringObjTable)); + new (_stringtable) VXStringObjTable(this); + vox_new(_metamethods,VXObjectVec); + vox_new(_systemstrings,VXObjectVec); + vox_new(_types,VXObjectVec); + _metamethodsmap = VXTableObj::Create(this,VX_MT_LAST-1); + //adding type strings to avoid memory trashing + //types names + newsysstring("null"); + newsysstring("table"); + newsysstring("array"); + newsysstring("closure"); + newsysstring("string"); + newsysstring("userdata"); + newsysstring("integer"); + newsysstring("float"); + newsysstring("userpointer"); + newsysstring("function"); + newsysstring("generator"); + newsysstring("thread"); + newsysstring("class"); + newsysstring("instance"); + newsysstring("bool"); + //meta methods + newmetamethod(VX_MM_ADD); + newmetamethod(VX_MM_SUB); + newmetamethod(VX_MM_MUL); + newmetamethod(VX_MM_DIV); + newmetamethod(VX_MM_UNM); + newmetamethod(VX_MM_MODULO); + newmetamethod(VX_MM_SET); + newmetamethod(VX_MM_GET); + newmetamethod(VX_MM_TYPEOF); + newmetamethod(VX_MM_NEXTI); + newmetamethod(VX_MM_CMP); + newmetamethod(VX_MM_CALL); + newmetamethod(VX_MM_CLONED); + newmetamethod(VX_MM_NEWSLOT); + newmetamethod(VX_MM_DELSLOT); + newmetamethod(VX_MM_TOSTRING); + newmetamethod(VX_MM_NEWMEMBER); + newmetamethod(VX_MM_INHERITED); + + _constructoridx = VXStringObj::Create(this,"constructor"); + _registry = VXTableObj::Create(this,0); + _consts = VXTableObj::Create(this,0); + _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz); + _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz); + _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz); + _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz); + _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz); + _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz); + _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz); + _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz); + _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz); + _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz); + +} + +VXSharedState::~VXSharedState() +{ + // and now the rest + _constructoridx.Null(); + _table(_registry)->Finalize(); + _table(_consts)->Finalize(); + _table(_metamethodsmap)->Finalize(); + _registry.Null(); + _consts.Null(); + _metamethodsmap.Null(); + while(!_systemstrings->empty()) + { + _systemstrings->back().Null(); + _systemstrings->pop_back(); + } + _thread(_root_vm)->Finalize(); + _root_vm.Null(); + _table_default_delegate.Null(); + _array_default_delegate.Null(); + _string_default_delegate.Null(); + _number_default_delegate.Null(); + _closure_default_delegate.Null(); + _generator_default_delegate.Null(); + _thread_default_delegate.Null(); + _class_default_delegate.Null(); + _instance_default_delegate.Null(); + _weakref_default_delegate.Null(); + _refs_table.Finalize(); + #ifndef NO_GARBAGE_COLLECTOR + VXCollectable *t = _gc_chain; + VXCollectable *nx = NULL; + while(t) + { + t->_uiRef++; + t->Finalize(); + nx = t->_next; + if(--t->_uiRef == 0) + t->Release(); + t=nx; + } + vox_assert(_gc_chain==NULL); //just to prove a theory + while(_gc_chain) + { + _gc_chain->_uiRef++; + _gc_chain->Release(); + } + #endif + + vox_delete(_types,VXObjectVec); + vox_delete(_systemstrings,VXObjectVec); + vox_delete(_metamethods,VXObjectVec); + vox_delete(_stringtable,VXStringObjTable); + if(_scratchpad)VX_FREE(_scratchpad,_scratchpadsize); +} + +VXInteger VXSharedState::GetMetaMethodIdxByName(const VXObject &name) +{ + if(type(name) != VX_OT_STRING) + return -1; + VXObject ret; + if(_table(_metamethodsmap)->Get(name,ret)) + { + return _integer(ret); + } + return -1; +} + +#ifndef NO_GARBAGE_COLLECTOR + +void VXSharedState::MarkObject(VXObject &o,VXCollectable **chain) +{ + switch(type(o)) + { + case VX_OT_TABLE:_table(o)->Mark(chain);break; + case VX_OT_ARRAY:_array(o)->Mark(chain);break; + case VX_OT_USERDATA:_userdata(o)->Mark(chain);break; + case VX_OT_CLOSURE:_closure(o)->Mark(chain);break; + case VX_OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; + case VX_OT_GENERATOR:_generator(o)->Mark(chain);break; + case VX_OT_THREAD:_thread(o)->Mark(chain);break; + case VX_OT_CLASS:_class(o)->Mark(chain);break; + case VX_OT_INSTANCE:_instance(o)->Mark(chain);break; + case VX_OT_OUTER:_outer(o)->Mark(chain);break; + case VX_OT_FUNCPROTO:_funcproto(o)->Mark(chain);break; + default: break; //shutup compiler + } +} + +void VXSharedState::RunMark(VXState *vm,VXCollectable **tchain) +{ + (void)vm; + VXState *vms = _thread(_root_vm); + vms->Mark(tchain); + _refs_table.Mark(tchain); + MarkObject(_registry,tchain); + MarkObject(_consts,tchain); + MarkObject(_metamethodsmap,tchain); + MarkObject(_table_default_delegate,tchain); + MarkObject(_array_default_delegate,tchain); + MarkObject(_string_default_delegate,tchain); + MarkObject(_number_default_delegate,tchain); + MarkObject(_generator_default_delegate,tchain); + MarkObject(_thread_default_delegate,tchain); + MarkObject(_closure_default_delegate,tchain); + MarkObject(_class_default_delegate,tchain); + MarkObject(_instance_default_delegate,tchain); + MarkObject(_weakref_default_delegate,tchain); + +} + +VXInteger VXSharedState::ResurrectUnreachable(VXState *vm) +{ + VXInteger n=0; + VXCollectable *tchain=NULL; + + RunMark(vm,&tchain); + + VXCollectable *resurrected = _gc_chain; + VXCollectable *t = resurrected; + //VXCollectable *nx = NULL; + + _gc_chain = tchain; + + VXArrayObj *ret = NULL; + if(resurrected) + { + ret = VXArrayObj::Create(this,0); + VXCollectable *rlast = NULL; + while(t) + { + rlast = t; + VXOType type = t->GetType(); + if(type != VX_OT_FUNCPROTO && type != VX_OT_OUTER) + { + VXRawObj sqo; + sqo._type = type; + sqo._unVal.pRefCounted = t; + ret->Append(sqo); + } + t = t->_next; + n++; + } + + vox_assert(rlast->_next == NULL); + rlast->_next = _gc_chain; + if(_gc_chain) + { + _gc_chain->_prev = rlast; + } + _gc_chain = resurrected; + } + + t = _gc_chain; + while(t) + { + t->UnMark(); + t = t->_next; + } + + if(ret) + { + VXObject temp = ret; + vm->Push(temp); + } + else + { + vm->PushNull(); + } + return n; +} + +VXInteger VXSharedState::CollectGarbage(VXState *vm) +{ + VXInteger n=0; + VXCollectable *tchain=NULL; + + RunMark(vm,&tchain); + + VXCollectable *t = _gc_chain; + VXCollectable *nx = NULL; + while(t) + { + t->_uiRef++; + t->Finalize(); + nx = t->_next; + if(--t->_uiRef == 0) + t->Release(); + t = nx; + n++; + } + + t = tchain; + while(t) + { + t->UnMark(); + t = t->_next; + } + _gc_chain = tchain; + + return n; +} +#endif + +#ifndef NO_GARBAGE_COLLECTOR +void VXCollectable::AddToChain(VXCollectable **chain,VXCollectable *c) +{ + c->_prev = NULL; + c->_next = *chain; + if(*chain) (*chain)->_prev = c; + *chain = c; +} + +void VXCollectable::RemoveFromChain(VXCollectable **chain,VXCollectable *c) +{ + if(c->_prev) c->_prev->_next = c->_next; + else *chain = c->_next; + if(c->_next) + c->_next->_prev = c->_prev; + c->_next = NULL; + c->_prev = NULL; +} +#endif + +char* VXSharedState::GetScratchPad(VXInteger size) +{ + VXInteger newsize; + if(size>0) + { + if(_scratchpadsize < size) + { + newsize = size + (size>>1); + _scratchpad = (char *)VX_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize = newsize; + + } + else if(_scratchpadsize >= (size<<5)) + { + newsize = _scratchpadsize >> 1; + _scratchpad = (char *)VX_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize = newsize; + } + } + return _scratchpad; +} + +RefTable::RefTable() +{ + AllocNodes(4); +} + +void RefTable::Finalize() +{ + RefNode *nodes = _nodes; + for(VXUnsignedInteger n = 0; n < _numofslots; n++) + { + nodes->obj.Null(); + nodes++; + } +} + +RefTable::~RefTable() +{ + VX_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode))); +} + +#ifndef NO_GARBAGE_COLLECTOR +void RefTable::Mark(VXCollectable **chain) +{ + RefNode *nodes = (RefNode *)_nodes; + for(VXUnsignedInteger n = 0; n < _numofslots; n++) + { + if(type(nodes->obj) != VX_OT_NULL) + { + VXSharedState::MarkObject(nodes->obj,chain); + } + nodes++; + } +} +#endif + +void RefTable::AddRef(VXRawObj &obj) +{ + VXHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,true); + ref->refs++; +} + +VXUnsignedInteger RefTable::GetRefCount(VXRawObj &obj) +{ + VXHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,true); + return ref->refs; +} + +bool RefTable::Release(VXRawObj &obj) +{ + VXHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,false); + if(ref) + { + if(--ref->refs == 0) + { + VXObject o = ref->obj; + if(prev) + { + prev->next = ref->next; + } + else + { + _buckets[mainpos] = ref->next; + } + ref->next = _freelist; + _freelist = ref; + _slotused--; + ref->obj.Null(); + //<>test for shrink? + return true; + } + } + else + { + vox_assert(0); + } + return false; +} + +void RefTable::Resize(VXUnsignedInteger size) +{ + RefNode **oldbucks = _buckets; + RefNode *t = _nodes; + VXUnsignedInteger oldnumofslots = _numofslots; + AllocNodes(size); + //rehash + VXUnsignedInteger nfound = 0; + for(VXUnsignedInteger n = 0; n < oldnumofslots; n++) + { + if(type(t->obj) != VX_OT_NULL) + { + //add back; + vox_assert(t->refs != 0); + RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj); + nn->refs = t->refs; + t->obj.Null(); + nfound++; + } + t++; + } + vox_assert(nfound == oldnumofslots); + VX_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode))); +} + +RefTable::RefNode *RefTable::Add(VXHash mainpos,VXRawObj &obj) +{ + RefNode *t = _buckets[mainpos]; + RefNode *newnode = _freelist; + newnode->obj = obj; + _buckets[mainpos] = newnode; + _freelist = _freelist->next; + newnode->next = t; + vox_assert(newnode->refs == 0); + _slotused++; + return newnode; +} + +RefTable::RefNode *RefTable::Get(VXRawObj &obj,VXHash &mainpos,RefNode **prev,bool add) +{ + RefNode *ref; + mainpos = ::HashObj(obj)&(_numofslots-1); + *prev = NULL; + for (ref = _buckets[mainpos]; ref; ) + { + if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj)) + break; + *prev = ref; + ref = ref->next; + } + if(ref == NULL && add) + { + if(_numofslots == _slotused) + { + vox_assert(_freelist == 0); + Resize(_numofslots*2); + mainpos = ::HashObj(obj)&(_numofslots-1); + } + ref = Add(mainpos,obj); + } + return ref; +} + +void RefTable::AllocNodes(VXUnsignedInteger size) +{ + RefNode **bucks; + RefNode *nodes; + bucks = (RefNode **)VX_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode))); + nodes = (RefNode *)&bucks[size]; + RefNode *temp = nodes; + VXUnsignedInteger n; + for(n = 0; n < size - 1; n++) + { + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) VXObject; + temp->next = temp+1; + temp++; + } + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) VXObject; + temp->next = NULL; + _freelist = nodes; + _nodes = nodes; + _buckets = bucks; + _slotused = 0; + _numofslots = size; +} + +////////////////////////////////////////////////////////////////////////// +//VXStringObjTable +/* + * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) + * http://www.lua.org/copyright.html#4 + * http://www.lua.org/source/4.0.1/src_lstring.c.html + */ + +VXStringObjTable::VXStringObjTable(VXSharedState *ss) +{ + _sharedstate = ss; + AllocNodes(4); + _slotused = 0; +} + +VXStringObjTable::~VXStringObjTable() +{ + VX_FREE(_strings,sizeof(VXStringObj*)*_numofslots); + _strings = NULL; +} + +void VXStringObjTable::AllocNodes(VXInteger size) +{ + _numofslots = size; + _strings = (VXStringObj**)VX_MALLOC(sizeof(VXStringObj*)*_numofslots); + memset(_strings,0,sizeof(VXStringObj*)*_numofslots); +} + +VXStringObj *VXStringObjTable::Add(const char *news,VXInteger len) +{ + if(len<0) + { + len = (VXInteger)strlen(news); + } + VXHash h = ::_hashstr(news,len)&(_numofslots-1); + VXStringObj *s; + for (s = _strings[h]; s; s = s->_next) + { + if(s->_len == len && (!memcmp(news,s->_val, len))) + { + return s; //found + } + } + VXStringObj *t = (VXStringObj*)VX_MALLOC(len + sizeof(VXStringObj)); + new (t) VXStringObj; + t->_sharedstate = _sharedstate; + memcpy(t->_val, news, len); + t->_val[len] = '\0'; + t->_len = len; + t->_hash = ::_hashstr(news,len); + t->_next = _strings[h]; + _strings[h] = t; + _slotused++; + if (_slotused > _numofslots) /* too crowded? */ + { + Resize(_numofslots*2); + } + return t; +} + +void VXStringObjTable::Resize(VXInteger size) +{ + VXInteger oldsize=_numofslots; + VXStringObj **oldtable=_strings; + AllocNodes(size); + for (VXInteger i=0; i_next; + VXHash h = p->_hash&(_numofslots-1); + p->_next = _strings[h]; + _strings[h] = p; + p = next; + } + } + VX_FREE(oldtable,oldsize*sizeof(VXStringObj*)); +} + +void VXStringObjTable::Remove(VXStringObj *bs) +{ + VXStringObj *s; + VXStringObj *prev=NULL; + VXHash h = bs->_hash&(_numofslots - 1); + + for (s = _strings[h]; s; ) + { + if(s == bs) + { + if(prev) + prev->_next = s->_next; + else + _strings[h] = s->_next; + _slotused--; + VXInteger slen = s->_len; + s->~VXStringObj(); + VX_FREE(s,sizeof(VXStringObj) + slen); + return; + } + prev = s; + s = s->_next; + } + vox_assert(0); //if this fails then something is wrong +} diff --git a/src/core/state.hpp b/src/core/state.hpp new file mode 100644 index 0000000..a9d0be3 --- /dev/null +++ b/src/core/state.hpp @@ -0,0 +1,136 @@ + +#ifndef _VXSTATE_H_ +#define _VXSTATE_H_ + +#include "utils.hpp" +#include "object.hpp" + +struct VXStringObj; +struct VXTableObj; +//max number of character for a printed number +#define NUMBER_MAX_CHAR 50 + +struct VXStringObjTable +{ + VXStringObjTable(VXSharedState*ss); + ~VXStringObjTable(); + VXStringObj *Add(const char *,VXInteger len); + void Remove(VXStringObj *); + private: + void Resize(VXInteger size); + void AllocNodes(VXInteger size); + VXStringObj **_strings; + VXUnsignedInteger _numofslots; + VXUnsignedInteger _slotused; + VXSharedState *_sharedstate; +}; + +struct RefTable +{ + struct RefNode + { + VXObject obj; + VXUnsignedInteger refs; + struct RefNode *next; + }; + RefTable(); + ~RefTable(); + void AddRef(VXRawObj &obj); + bool Release(VXRawObj &obj); + VXUnsignedInteger GetRefCount(VXRawObj &obj); + #ifndef NO_GARBAGE_COLLECTOR + void Mark(VXCollectable **chain); + #endif + void Finalize(); + private: + RefNode *Get(VXRawObj &obj,VXHash &mainpos,RefNode **prev,bool add); + RefNode *Add(VXHash mainpos,VXRawObj &obj); + void Resize(VXUnsignedInteger size); + void AllocNodes(VXUnsignedInteger size); + VXUnsignedInteger _numofslots; + VXUnsignedInteger _slotused; + RefNode *_nodes; + RefNode *_freelist; + RefNode **_buckets; +}; + +#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len) +#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr) + +struct VXObject; + +struct VXSharedState +{ + VXSharedState(); + ~VXSharedState(); + void Init(); + public: + char* GetScratchPad(VXInteger size); + VXInteger GetMetaMethodIdxByName(const VXObject &name); + #ifndef NO_GARBAGE_COLLECTOR + VXInteger CollectGarbage(VXState *vm); + void RunMark(VXState *vm,VXCollectable **tchain); + VXInteger ResurrectUnreachable(VXState *vm); + static void MarkObject(VXObject &o,VXCollectable **chain); + #endif + VXObjectVec *_metamethods; + VXObject _metamethodsmap; + VXObjectVec *_systemstrings; + VXObjectVec *_types; + VXStringObjTable *_stringtable; + RefTable _refs_table; + VXObject _registry; + VXObject _consts; + VXObject _constructoridx; + #ifndef NO_GARBAGE_COLLECTOR + VXCollectable *_gc_chain; + #endif + VXObject _root_vm; + VXObject _table_default_delegate; + static VXRegFunction _table_default_delegate_funcz[]; + VXObject _array_default_delegate; + static VXRegFunction _array_default_delegate_funcz[]; + VXObject _string_default_delegate; + static VXRegFunction _string_default_delegate_funcz[]; + VXObject _number_default_delegate; + static VXRegFunction _number_default_delegate_funcz[]; + VXObject _generator_default_delegate; + static VXRegFunction _generator_default_delegate_funcz[]; + VXObject _closure_default_delegate; + static VXRegFunction _closure_default_delegate_funcz[]; + VXObject _thread_default_delegate; + static VXRegFunction _thread_default_delegate_funcz[]; + VXObject _class_default_delegate; + static VXRegFunction _class_default_delegate_funcz[]; + VXObject _instance_default_delegate; + static VXRegFunction _instance_default_delegate_funcz[]; + VXObject _weakref_default_delegate; + static VXRegFunction _weakref_default_delegate_funcz[]; + + VXCompileError _compilererrorhandler; + VXPrintFunction _printfunc; + VXPrintFunction _errorfunc; + bool _debuginfo; + bool _notifyallexceptions; + private: + char *_scratchpad; + VXInteger _scratchpadsize; +}; + +#define _table_ddel _table(_sharedstate->_table_default_delegate) +#define _array_ddel _table(_sharedstate->_array_default_delegate) +#define _string_ddel _table(_sharedstate->_string_default_delegate) +#define _number_ddel _table(_sharedstate->_number_default_delegate) +#define _generator_ddel _table(_sharedstate->_generator_default_delegate) +#define _closure_ddel _table(_sharedstate->_closure_default_delegate) +#define _thread_ddel _table(_sharedstate->_thread_default_delegate) +#define _class_ddel _table(_sharedstate->_class_default_delegate) +#define _instance_ddel _table(_sharedstate->_instance_default_delegate) +#define _weakref_ddel _table(_sharedstate->_weakref_default_delegate) + +#define rsl(l) (l) + +//extern VXObject _null_; + +bool CompileTypemask(VXIntVec &res,const char *typemask); +#endif //_VXSTATE_H_ diff --git a/src/core/string.cpp b/src/core/string.cpp new file mode 100644 index 0000000..0415008 --- /dev/null +++ b/src/core/string.cpp @@ -0,0 +1,38 @@ + +#include "string.hpp" + +VXStringObj* VXStringObj::Create(VXSharedState* ss, const char* str) +{ + return VXStringObj::Create(ss, str, -1); +} + +VXStringObj *VXStringObj::Create(VXSharedState *ss,const char *s,VXInteger len) +{ + VXStringObj *str= ADD_STRING(ss,s,len); + return str; +} + +void VXStringObj::Release() +{ + REMOVE_STRING(_sharedstate,this); +} + +VXInteger VXStringObj::Next(const VXObject &refpos, VXObject &outkey, VXObject &outval) +{ + VXInteger idx = (VXInteger)TranslateIndex(refpos); + while(idx < _len) + { + outkey = (VXInteger)idx; + outval = VXInteger(_val[idx]); + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; +} + +void VXStringObj::Get(const char** dest_str, VXInteger* dest_len) +{ + (*dest_str) = _val; + (*dest_len) = _len; +} diff --git a/src/core/string.hpp b/src/core/string.hpp new file mode 100644 index 0000000..096225d --- /dev/null +++ b/src/core/string.hpp @@ -0,0 +1,24 @@ + +#ifndef _VXSTRING_H_ +#define _VXSTRING_H_ + +#include "pcheader.hpp" +#include "object.hpp" +#include "state.hpp" +#include + +std::string strhelp_quote(const std::string& str, bool escape_only=false); + +inline VXHash _hashstr(const char* s, size_t l) +{ + VXHash h = (VXHash)l; /* seed */ + size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ + for (; l>=step; l-=step) + { + h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++)); + } + return h; +} + + +#endif //_VXSTRING_H_ diff --git a/src/core/table.cpp b/src/core/table.cpp new file mode 100644 index 0000000..a2e1722 --- /dev/null +++ b/src/core/table.cpp @@ -0,0 +1,409 @@ + +#include "pcheader.hpp" +#include "vm.hpp" +#include "table.hpp" +#include "funcproto.hpp" +#include "closure.hpp" + +VXTableObj::VXTableObj(VXSharedState *ss,VXInteger nInitialSize) +{ + VXInteger pow2size = MINPOWER2; + while(nInitialSize > pow2size) + { + pow2size = pow2size << 1; + } + AllocNodes(pow2size); + _usednodes = 0; + _delegate = NULL; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain,this); +} + +void VXTableObj::Remove(const VXObject &key) +{ + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); + if (n) + { + n->val.Null(); + n->key.Null(); + _usednodes--; + Rehash(false); + } +} + +void VXTableObj::AllocNodes(VXInteger nSize) +{ + _HashNode *nodes=(_HashNode *)VX_MALLOC(sizeof(_HashNode)*nSize); + for(VXInteger i=0;i= oldsize-oldsize/4) + { + AllocNodes(oldsize*2); + } + + /* less than 1/4? */ + else if (nelems <= oldsize/4 && oldsize > MINPOWER2) + { + AllocNodes(oldsize/2); + } + + else if(force) + AllocNodes(oldsize); + else + return; + _usednodes = 0; + for (VXInteger i=0; ikey) != VX_OT_NULL) + NewSlot(old->key,old->val); + } + for(VXInteger k=0;k_nodes; + _HashNode *src = _nodes; + _HashNode *dst = nt->_nodes; + VXInteger n = 0; + for(n = 0; n < _numofnodes; n++) + { + dst->key = src->key; + dst->val = src->val; + if(src->next) + { + vox_assert(src->next > basesrc); + dst->next = basedst + (src->next - basesrc); + vox_assert(dst != dst->next); + } + dst++; + src++; + } + vox_assert(_firstfree > basesrc); + vox_assert(_firstfree != NULL); + nt->_firstfree = basedst + (_firstfree - basesrc); + #else + VXInteger ridx=0; + VXObject key,val; + while((ridx=Next(true,ridx,key,val))!=-1) + { + nt->NewSlot(key,val); + } + #endif + nt->SetDelegate(_delegate); + return nt; +} + +bool VXTableObj::Get(const VXObject &key,VXObject &val) +{ + if(type(key) == VX_OT_NULL) + return false; + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); + if (n) + { + val = VX_REALVAL(n->val); + return true; + } + return false; +} + +bool VXTableObj::NewSlot(const VXObject &key,const VXObject &val) +{ + vox_assert(type(key) != VX_OT_NULL); + VXHash h = HashObj(key) & (_numofnodes - 1); + _HashNode *n = _Get(key, h); + if (n) + { + n->val = val; + return false; + } + _HashNode *mp = &_nodes[h]; + n = mp; + //key not found I'll insert it + //main pos is not free + if(type(mp->key) != VX_OT_NULL) + { + /* get a free place */ + n = _firstfree; + VXHash mph = HashObj(mp->key) & (_numofnodes - 1); + /* main position of colliding node */ + _HashNode *othern; + if (mp > n && (othern = &_nodes[mph]) != mp) + { + /* yes; move colliding node into free position */ + while (othern->next != mp) + { + vox_assert(othern->next != NULL); + /* find previous */ + othern = othern->next; + } + /* redo the chain with `n' in place of `mp' */ + othern->next = n; + n->key = mp->key; + /* copy colliding node into free pos. (mp->next also goes) */ + n->val = mp->val; + n->next = mp->next; + mp->key.Null(); + mp->val.Null(); + /* now `mp' is free */ + mp->next = NULL; + } + else + { + /* new node will go into free position */ + /* chain new position */ + n->next = mp->next; + mp->next = n; + mp = n; + } + } + mp->key = key; + /* correct `firstfree' */ + for (;;) + { + if (type(_firstfree->key) == VX_OT_NULL && _firstfree->next == NULL) + { + mp->val = val; + _usednodes++; + /* OK; table still has a free place */ + return true; + } + else if(_firstfree == _nodes) + { + /* cannot decrement from here */ + break; + } + else + { + (_firstfree)--; + } + } + Rehash(true); + return NewSlot(key, val); +} + +VXInteger VXTableObj::Next(bool getweakrefs, + const VXObject &refpos, + VXObject &outkey, + VXObject &outval) +{ + VXInteger idx = (VXInteger)TranslateIndex(refpos); + while(idx < _numofnodes) + { + _HashNode &n = _nodes[idx]; + if(type(n.key) != VX_OT_NULL) + { + //first found + outkey = n.key; + outval = getweakrefs?(VXRawObj)n.val:VX_REALVAL(n.val); + //return idx for the next iteration + return ++idx; + } + + ++idx; + } + //nothing to iterate anymore + return -1; +} + +bool VXTableObj::Set(const VXObject &key, const VXObject &val) +{ + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); + if(n) + { + n->val = val; + return true; + } +# define TABLE_SLOT_OVERRIDE + else + { + return NewSlot(key, val); + } + return false; +} + +void VXTableObj::_ClearNodes() +{ + for(VXInteger i = 0;i < _numofnodes; i++) + { + _HashNode &n = _nodes[i]; + n.key.Null(); + n.val.Null(); + } +} + +void VXTableObj::Finalize() +{ + _ClearNodes(); + SetDelegate(NULL); +} + +VXInteger VXTableObj::Size() const +{ + return _usednodes; + +} + +void VXTableObj::Clear() +{ + _ClearNodes(); + _usednodes = 0; + Rehash(true); +} + + +VXTableObj* VXTableObj::Create(VXSharedState *ss,VXInteger nInitialSize) +{ + VXTableObj *newtable = (VXTableObj*)VX_MALLOC(sizeof(VXTableObj)); + new (newtable) VXTableObj(ss, nInitialSize); + newtable->_delegate = NULL; + return newtable; +} + +VXTableObj::~VXTableObj() +{ + SetDelegate(NULL); + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + for(VXInteger i = 0; i < _numofnodes; i++) + { + _nodes[i].~_HashNode(); + } + VX_FREE(_nodes, _numofnodes * sizeof(_HashNode)); +} + + +VXOType VXTableObj::GetType() +{ + return VX_OT_TABLE; +} + +VXTableObj::_HashNode* VXTableObj::_Get(const VXObject &key,VXHash hash) +{ + VXTableObj::_HashNode* n = &_nodes[hash]; + do + { + if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)) + { + return n; + } + } while((n = n->next)); + return NULL; +} + + +VXInteger VXTableObj::CountUsed() +{ + return _usednodes; +} + +void VXTableObj::Release() +{ + vox_delete(this, VXTableObj); +} + +void VXTableObj::Mark(VXCollectable **chain) +{ + START_MARK() + if(_delegate) + { + _delegate->Mark(chain); + } + VXInteger len = _numofnodes; + for(VXInteger i = 0; i < len; i++) + { + VXSharedState::MarkObject(_nodes[i].key, chain); + VXSharedState::MarkObject(_nodes[i].val, chain); + } + END_MARK() +} + + +#define get_object(keyvar, destvar, expected_type) \ + if(this->Get(keyvar, destvar) == false) \ + { \ + return VX_ERROR; \ + } \ + if(destvar.Type() != expected_type) \ + { \ + return VX_ERROR; \ + } \ + +VXInteger VXTableObj::GetBoolValue(const VXObject& keyname, bool* destination) +{ + VXObject ob; + get_object(keyname, ob, VX_OT_BOOL) + (*destination) = ob.Boolean(); + return VX_OK; +} + +VXInteger VXTableObj::GetStringValue(const VXObject& keyname, VXStringObj** dest) +{ + VXObject ob; + get_object(keyname, ob, VX_OT_STRING) + (*dest) = ob.String(); + return VX_OK; +} + +VXInteger VXTableObj::GetStringValue(const VXObject& keyname, const char** dest_str, VXInteger* dest_len) +{ + VXObject ob; + get_object(keyname, ob, VX_OT_STRING) + ob.String()->Get(dest_str, dest_len); + return VX_OK; +} + +VXInteger VXTableObj::GetIntegerValue(const VXObject& keyname, VXInteger* dest) +{ + VXObject ob; + get_object(keyname, ob, VX_OT_INTEGER) + (*dest) = ob.Integer(); + return VX_OK; +} + +VXInteger VXTableObj::GetFloatValue(const VXObject& keyname, VXFloat* dest) +{ + VXObject ob; + get_object(keyname, ob, VX_OT_FLOAT) + (*dest) = ob.Float(); + return VX_OK; +} + +VXInteger VXTableObj::GetArrayValue(const VXObject& keyname, VXArrayObj** dest) +{ + VXObject ob; + get_object(keyname, ob, VX_OT_ARRAY) + (*dest) = ob.Array(); + return VX_OK; +} + +VXInteger VXTableObj::GetTableValue(const VXObject& keyname, VXTableObj** dest) +{ + VXObject ob; + get_object(keyname, ob, VX_OT_TABLE) + (*dest) = ob.Table(); + return VX_OK; +} diff --git a/src/core/table.hpp b/src/core/table.hpp new file mode 100644 index 0000000..0e0eb9a --- /dev/null +++ b/src/core/table.hpp @@ -0,0 +1,32 @@ + +#ifndef _VXTABLE_H_ +#define _VXTABLE_H_ +/* + * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) + * http://www.lua.org/copyright.html#4 + * http://www.lua.org/source/4.0.1/src_ltable.c.html + */ + +#include "string.hpp" + +//#define hashptr(p) ((VXHash)(((VXInteger)p) >> 3)) +#define hashptr(p) (((*reinterpret_cast(p)) >> 3)) + +inline VXHash HashObj(const VXObject &key) +{ + switch(type(key)) + { + case VX_OT_STRING: + return _string(key)->_hash; + case VX_OT_FLOAT: + return (VXHash)((VXInteger)_float(key)); + case VX_OT_BOOL: + case VX_OT_INTEGER: + return (VXHash)((VXInteger)_integer(key)); + default: + return hashptr(key._unVal.pRefCounted); + } +} + + +#endif //_VXTABLE_H_ diff --git a/src/core/userdata.hpp b/src/core/userdata.hpp new file mode 100644 index 0000000..6f6f830 --- /dev/null +++ b/src/core/userdata.hpp @@ -0,0 +1,39 @@ + +#ifndef _VXUSERDATA_H_ +#define _VXUSERDATA_H_ + +struct VXUserDataObj : VXDelegableObj +{ + VXUserDataObj(VXSharedState *ss){ _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); } + ~VXUserDataObj() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this); + SetDelegate(NULL); + } + static VXUserDataObj* Create(VXSharedState *ss, VXInteger size) + { + VXUserDataObj* ud = (VXUserDataObj*)VX_MALLOC(vox_aligning(sizeof(VXUserDataObj))+size); + new (ud) VXUserDataObj(ss); + ud->_size = size; + ud->_typetag = 0; + return ud; + } + #ifndef NO_GARBAGE_COLLECTOR + void Mark(VXCollectable **chain); + void Finalize(){SetDelegate(NULL);} + VXOType GetType(){ return VX_OT_USERDATA;} + #endif + void Release() + { + if (_hook) _hook((VXUserPointer)vox_aligning(this + 1),_size); + VXInteger tsize = _size; + this->~VXUserDataObj(); + VX_FREE(this, vox_aligning(sizeof(VXUserDataObj)) + tsize); + } + + VXInteger _size; + VXReleaseHook _hook; + VXUserPointer _typetag; + //char _val[1]; +}; +#endif //_VXUSERDATA_H_ diff --git a/src/core/utils.cpp b/src/core/utils.cpp new file mode 100644 index 0000000..774a36b --- /dev/null +++ b/src/core/utils.cpp @@ -0,0 +1,62 @@ + + +#include "utils.hpp" + +VXInteger buf_lexfeed(VXUserPointer file) +{ + BufState *buf=(BufState*)file; + if(buf->size<(buf->ptr+1)) + return 0; + return buf->buf[buf->ptr++]; +} + +VXInteger file_read(VXUserPointer file,VXUserPointer buf,VXInteger size) +{ + VXInteger ret; + if((ret = fread(buf, 1, size, (FILE*)file)) != 0) + { + return ret; + } + return -1; +} + +VXInteger file_write(VXUserPointer file, VXUserPointer p, VXInteger size) +{ + return fwrite(p, 1, size,(FILE*)file); +} + +VXInteger _io_file_lexfeed_PLAIN(VXUserPointer file) +{ + VXInteger ret; + char c; + if((ret = fread(&c, sizeof(c), 1, (FILE*)file) > 0)) + { + return c; + } + return 0; +} + +VXInteger _io_file_lexfeed_UCS2_LE(VXUserPointer file) +{ + VXInteger ret; + wchar_t c; + if((ret = fread(&c, sizeof(c), 1, (FILE *)file) > 0)) + { + return (char)c; + } + return 0; +} + +VXInteger _io_file_lexfeed_UCS2_BE(VXUserPointer file) +{ + VXInteger ret; + unsigned short c; + if((ret = fread(&c, sizeof(c), 1, (FILE*)file) > 0)) + { + c = ((c >> 8) & 0x00FF) | ((c << 8) & 0xFF00); + return (char)c; + } + return 0; +} + + diff --git a/src/core/utils.hpp b/src/core/utils.hpp new file mode 100644 index 0000000..301ad16 --- /dev/null +++ b/src/core/utils.hpp @@ -0,0 +1,48 @@ + +#ifndef _VXUTILS_H_ +#define _VXUTILS_H_ + +#include +#include "pcheader.hpp" +#include "mem.hpp" + +#define _ss(_vm_) (_vm_)->_sharedstate + +#ifndef NO_GARBAGE_COLLECTOR +# define _opt_ss(_vm_) (_vm_)->_sharedstate +#else +# define _opt_ss(_vm_) NULL +#endif + +#define _GETSAFE_OBJ(v,idx,type,o) \ + { \ + if(!vox_aux_gettypedarg(v,idx,type,&o)) \ + { \ + return VX_ERROR; \ + } \ + } + +#define vox_aux_paramscheck(v,count) \ + { \ + if(vox_gettop(v) < count) \ + { \ + v->ThrowError("not enough params in the stack"); \ + return VX_ERROR; \ + } \ + } + +struct BufState +{ + const char *buf; + VXInteger ptr; + VXInteger size; +}; + +VXInteger buf_lexfeed(VXUserPointer file); +VXInteger file_read(VXUserPointer file,VXUserPointer buf,VXInteger size); +VXInteger file_write(VXUserPointer file, VXUserPointer p, VXInteger size); +VXInteger _io_file_lexfeed_PLAIN(VXUserPointer file); +VXInteger _io_file_lexfeed_UCS2_LE(VXUserPointer file); +VXInteger _io_file_lexfeed_UCS2_BE(VXUserPointer file); + +#endif //_VXUTILS_H_ diff --git a/src/core/vm.cpp b/src/core/vm.cpp new file mode 100644 index 0000000..cdaf4e1 --- /dev/null +++ b/src/core/vm.cpp @@ -0,0 +1,3629 @@ + +#include +#include + +#include "pcheader.hpp" +#include "opcodes.hpp" +#include "vm.hpp" +#include "funcproto.hpp" +#include "closure.hpp" +#include "string.hpp" +#include "table.hpp" +#include "userdata.hpp" +#include "class.hpp" +#include "names.hpp" +#include "compiler.hpp" +#include "debug.hpp" + +#define TOP() (_stack.values()[_top-1]) + +#define arg0 (_i_._arg0) +#define sarg0 ((VXInteger)*((signed char *)&_i_._arg0)) +#define arg1 (_i_._arg1) +#define sarg1 (*((VXInteger*)&_i_._arg1)) +#define arg2 (_i_._arg2) +#define arg3 (_i_._arg3) +#define sarg3 ((VXInteger)*((signed char *)&_i_._arg3)) + +#define _ARITH_(op,trg,o1,o2) \ +{ \ + VXInteger tmask = type(o1)|type(o2); \ + switch(tmask) \ + { \ + case VX_OT_INTEGER: trg = _integer(o1) op _integer(o2);break; \ + case (VX_OT_FLOAT|VX_OT_INTEGER): \ + case (VX_OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\ + default: _GUARD(ARITH_OP(this, (#op)[0],trg,o1,o2)); break;\ + } \ +} + +#define _ARITH_NOZERO(op,trg,o1,o2,err) \ +{ \ + VXInteger tmask = type(o1)|type(o2); \ + switch(tmask) { \ + case VX_OT_INTEGER: \ + { \ + VXInteger i2 = _integer(o2); \ + if(i2 == 0) \ + { \ + ThrowError(err); \ + VX_THROW(); \ + } \ + trg = _integer(o1) op i2; \ + } \ + break;\ + case (VX_OT_FLOAT|VX_OT_INTEGER): \ + case (VX_OT_FLOAT): \ + trg = tofloat(o1) op tofloat(o2); \ + break;\ + default: \ + _GUARD(ARITH_OP(this, (#op)[0],trg,o1,o2)); \ + break;\ + } \ +} + +#define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1)) + +#define VX_THROW() { goto exception_trap; } + +#define _GUARD(exp) { if(!exp) { VX_THROW();} } + +#define _RET_SUCCEED(exp) { result = (exp); return true; } + +#define FALLBACK_OK 0 +#define FALLBACK_NO_MATCH 1 +#define FALLBACK_ERROR 2 + + + +#undef _GETSAFE_OBJ + +#define _GETSAFE_OBJ(v,idx,type,o) \ + { \ + if(VX_FAILED(v->GetTypedArg(v,idx,type,&o))) \ + { \ + return VX_ERROR; \ + } \ + } + + +#define _GETSAFE_OBJ_REF(v, idx, type, o) \ + { \ + if(VX_FAILED(v->GetTypedArg(idx, type, o))) \ + { \ + return VX_ERROR; \ + } \ + } + +void vox_defaultprintfunc(VXState* v,const char *s,...) +{ + (void)v; + va_list vl; + va_start(vl, s); + vfprintf(stdout, s, vl); + va_end(vl); +} + +void vox_defaulterrorfunc(VXState* v,const char *s,...) +{ + (void)v; + va_list vl; + va_start(vl, s); + vfprintf(stderr, s, vl); + va_end(vl); +} + + + +template +Type WrongNumberOfArguments(VXState* vm, + Type retval, + bool isnative, + ClosureType func) +{ + const char* funcname = _stringval(func->_name); + const char* prefix = isnative ? " native" : ""; + if(func->_name.IsNull()) + { + funcname = NAMES_ANONFUNC; + } + vm->ThrowError("wrong number of parameters to%s function '%s'", prefix, funcname); + return retval; +} + +VXUnsignedInteger TranslateIndex(const VXObject &idx) +{ + switch(type(idx)) + { + case VX_OT_NULL: + return 0; + case VX_OT_INTEGER: + return (VXUnsignedInteger)_integer(idx); + default: vox_assert(0); break; + } + return 0; +} + +const char *IdType2Name(VXOType type) +{ + switch(VX_RAW_TYPE(type)) + { + case VX_RT_NULL: return "null"; + case VX_RT_INTEGER: return "integer"; + case VX_RT_FLOAT: return "float"; + case VX_RT_BOOL: return "bool"; + case VX_RT_STRING: return "string"; + case VX_RT_TABLE: return "table"; + case VX_RT_ARRAY: return "array"; + case VX_RT_GENERATOR: return "generator"; + case VX_RT_CLOSURE: + case VX_RT_NATIVECLOSURE: return "function"; + case VX_RT_USERDATA: + case VX_RT_USERPOINTER: return "userdata"; + case VX_RT_THREAD: return "thread"; + case VX_RT_FUNCPROTO: return "function"; + case VX_RT_CLASS: return "class"; + case VX_RT_INSTANCE: return "instance"; + case VX_RT_WEAKREF: return "weakref"; + case VX_RT_OUTER: return "outer"; + default: + return ""; + } +} + +const char *GetTypeName(const VXObject &obj1) +{ + return IdType2Name(type(obj1)); +} + + +VXInteger VXState::GetState() +{ + if(this->_suspended) + { + return VX_VMSTATE_SUSPENDED; + } + if(this->_callsstacksize != 0) + { + return VX_VMSTATE_RUNNING; + } + return VX_VMSTATE_IDLE; +} + +VXInteger VXState::WakeUp(bool wakeupret,bool retval,bool raiseerror,bool throwerror) +{ + VXObject ret; + if(!this->_suspended) + { + return this->ThrowError("cannot resume a vm that is not running any code"); + } + VXInteger target = this->_suspended_target; + if(wakeupret) + { + if(target != -1) + { + //retval + this->GetAt(this->_stackbase + this->_suspended_target) = this->GetUp(-1); + } + this->Pop(); + } + else if(target != -1) + { + this->GetAt(this->_stackbase + this->_suspended_target).Null(); + } + VXObject dummy; + VXState::ExecutionType extype; + extype = throwerror ? VXState::ET_RESUME_THROW_VM : VXState::ET_RESUME_VM; + if(!this->Execute(dummy, -1, -1, ret, raiseerror, extype)) + { + return VX_ERROR; + } + if(retval) + { + this->Push(ret); + } + return VX_OK; +} + +VXInteger VXState::SetDelegate(VXObject& self, const VXObject& mt) +{ + VXOType type = self.Type(); + switch(type) + { + case VX_OT_TABLE: + if(mt.Type() == VX_OT_TABLE) + { + if(!self.Table()->SetDelegate(_table(mt))) + { + return ThrowError("delegate cycle"); + } + } + else if(mt.Type() == VX_OT_NULL) + { + self.Table()->SetDelegate(NULL); + } + else + { + return vox_aux_invalidtype(this, type); + } + break; + case VX_OT_USERDATA: + if(mt.Type() == VX_OT_TABLE) + { + _userdata(self)->SetDelegate(_table(mt)); + } + else if(type(mt)==VX_OT_NULL) + { + _userdata(self)->SetDelegate(NULL); + } + else return vox_aux_invalidtype(this, type); + break; + default: + return vox_aux_invalidtype(this, type); + break; + } + return VX_OK; +} + +bool SafeWrite(VXState* v, + VXWriteFunc write, + VXUserPointer up, + VXUserPointer dest, + VXInteger size) +{ + if(write(up,dest,size) != size) + { + v->ThrowError("io error (write function failure)"); + return false; + } + return true; +} + +bool SafeRead(VXState* v,VXWriteFunc read,VXUserPointer up,VXUserPointer dest,VXInteger size) +{ + if(size && read(up,dest,size) != size) + { + v->ThrowError("io error, read function failure, the origin stream could be corrupted/trucated"); + return false; + } + return true; +} + +bool WriteTag(VXState* v,VXWriteFunc write,VXUserPointer up,VXUnsignedInteger32 tag) +{ + return SafeWrite(v,write,up,&tag,sizeof(tag)); +} + +bool CheckTag(VXState* v,VXWriteFunc read,VXUserPointer up,VXUnsignedInteger32 tag) +{ + VXUnsignedInteger32 t; + _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t))); + if(t != tag) + { + v->ThrowError("invalid or corrupted closure stream"); + return false; + } + return true; +} + +bool WriteObject(VXState* v,VXUserPointer up,VXWriteFunc write,VXObject &o) +{ + VXUnsignedInteger32 _type = (VXUnsignedInteger32)type(o); + _CHECK_IO(SafeWrite(v, write, up, &_type,sizeof(_type))); + switch(type(o)) + { + case VX_OT_STRING: + _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(VXInteger))); + _CHECK_IO(SafeWrite(v, + write, up, + VXUserPointer(o.String()->Value()), o.String()->Length())); + break; + case VX_OT_INTEGER: + _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(VXInteger)));break; + case VX_OT_FLOAT: + _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(VXFloat)));break; + case VX_OT_NULL: + break; + default: + v->ThrowError("cannot serialize a %s",GetTypeName(o)); + return false; + } + return true; +} + +bool ReadObject(VXState* v,VXUserPointer up,VXReadFunc read,VXObject &o) +{ + VXUnsignedInteger32 _type; + _CHECK_IO(SafeRead(v,read,up,&_type,sizeof(_type))); + VXOType t = (VXOType)_type; + switch(t) + { + case VX_OT_STRING: + { + VXInteger len; + _CHECK_IO(SafeRead(v,read,up,&len,sizeof(VXInteger))); + _CHECK_IO(SafeRead(v,read,up,v->ScratchPad(len),len)); + o = v->NewString(v->ScratchPad(-1), len); + } + break; + case VX_OT_INTEGER: + { + VXInteger i; + _CHECK_IO(SafeRead(v,read,up,&i,sizeof(VXInteger))); o = i; break; + } + case VX_OT_FLOAT: + { + VXFloat f; + _CHECK_IO(SafeRead(v,read,up,&f,sizeof(VXFloat))); o = f; break; + } + case VX_OT_NULL: + o.Null(); + break; + default: + v->ThrowError("cannot serialize a %s",IdType2Name(t)); + return false; + } + return true; +} + + + +char* VXState::ScratchPad(VXInteger size) +{ + return Shared()->GetScratchPad(size); +} + +void VXState::SetReleaseHook(VXInteger idx, VXReleaseHook hook) +{ + if(GetTop() >= 1) + { + VXObject& ud = StackGet(idx); + switch(type(ud)) + { + case VX_OT_USERDATA: + _userdata(ud)->_hook = hook; + break; + case VX_OT_INSTANCE: + _instance(ud)->_hook = hook; + break; + case VX_OT_CLASS: + _class(ud)->_hook = hook; + break; + default: + break; + } + } +} + +VXInteger VXState::SetTypeTag(VXObject& o, VXUserPointer typetag) +{ + switch(o.Type()) + { + case VX_OT_USERDATA: + _userdata(o)->_typetag = typetag; + break; + case VX_OT_CLASS: + _class(o)->_typetag = typetag; + break; + default: + return ThrowError("invalid object type"); + } + return VX_OK; +} + +VXInteger VXState::GetInstanceUp(VXInteger idx, VXUserPointer *p, + VXUserPointer typetag, + bool previously_checked_base) +{ + (void)previously_checked_base; + VXObject& o = StackGet(idx); + if(o.Type() != VX_OT_INSTANCE) + { + return ThrowError("the object is not a class instance"); + } + (*p) = _instance(o)->_userpointer; + if(typetag != 0) + { + VXClassObj *cl = _instance(o)->_class; + do + { + if(cl->_typetag == typetag) + { + return VX_OK; + } + cl = cl->_base; + } while(cl != NULL); + return this->ThrowError("invalid type tag"); + } + return VX_OK; +} + + +VXInteger VXState::SetInstanceUp(VXInteger idx, VXUserPointer* p) +{ + VXObject& o = StackGet(idx); + if(type(o) != VX_OT_INSTANCE) + { + return ThrowError("the object is not a class instance"); + } + _instance(o)->_userpointer = (*p); + Push(o); + return VX_OK; +} + + +void VXState::PushString(const char* str, VXInteger len) +{ + this->Push(this->NewString(str, len)); +} + +void VXState::PushInteger(VXInteger itm) +{ + this->Push(VXObject(itm)); +} + +void VXState::PushFloat(VXFloat itm) +{ + this->Push(VXObject(itm)); +} + +void VXState::SetTop(VXInteger newtop) +{ + VXInteger top = this->GetTop(); + if(top > newtop) + { + this->Pop(top - newtop); + } + else + { + while(top++ < newtop) + { + this->PushNull(); + } + } +} + +VXInteger VXState::GetTop() +{ + return ((this->_top) - (this->_stackbase)); +} + +VXInteger VXState::WriteClosure(VXWriteFunc w, VXUserPointer up) +{ + VXObject o; + _GETSAFE_OBJ_REF(this, -1, VX_OT_CLOSURE,o); + unsigned short tag = VX_BYTECODE_STREAM_TAG; + if(w(up, &tag, 2) != 2) + { + return this->ThrowError("io error"); + } + if(!_closure(o)->Save(this, up, w)) + { + return VX_ERROR; + } + return VX_OK; +} + + +VXInteger VXState::WriteClosureToFile(const char *filename) +{ + FILE* file = fopen(filename, "wb+"); + if(!file) + { + return ThrowError("Cannot open '%s' for writing: %s", filename, strerror(errno)); + } + else + { + if(VX_SUCCEEDED(this->WriteClosure(file_write, file))) + { + fclose(file); + return VX_OK; + } + fclose(file); + } + return VX_ERROR; //forward the error +} + +VXInteger VXState::BindEnv(VXObject& o, const VXObject& env, VXObject& ret) +{ + VXWeakRefObj* weak; + VXForeignClosureObj* fclos; + VXNativeClosureObj* nclos; + if(!o.IsNativeClosure() && !o.IsClosure()) + { + return this->ThrowError("the target is not a closure"); + } + if(!env.IsTable() && !env.IsClass() && !env.IsInstance()) + { + return this->ThrowError("invalid environment"); + } + weak = env.RefCounted()->GetWeakRef(env.Type()); + if(o.IsClosure()) + { + fclos = o.Closure()->Clone(); + __ObjRelease(fclos->_env); + fclos->_env = weak; + __ObjAddRef(fclos->_env); + if(_closure(o)->_base) + { + fclos->_base = o.Closure()->_base; + __ObjAddRef(fclos->_base); + } + ret = fclos; + } + else //then must be a native closure + { + nclos = o.NativeClosure()->Clone(); + __ObjRelease(nclos->_env); + nclos->_env = weak; + __ObjAddRef(nclos->_env); + ret = nclos; + } + return VX_OK; +} + +void VXState::SetCompilerErrorHandler(VXCompileError f) +{ + Shared()->_compilererrorhandler = f; +} + +void VXState::SetDebugHook(const VXObject& o) +{ + if(o.IsClosure() || o.IsNativeClosure() || o.IsNull()) + { + this->_debughook_closure = o; + this->_debughook_native = NULL; + this->_debughook = !o.IsNull(); + } +} + +void VXState::SetErrorHandler(const VXObject& o) +{ + if(o.IsClosure() || o.IsNativeClosure() || o.IsNull()) + { + this->_errorhandler = o; + } +} + + +void VXState::SetErrorHandlers() +{ + this->SetCompilerErrorHandler(vox_aux_compiler_error); + VXObject fn = VXNativeClosureObj::Create(this->Shared(), vox_aux_printerror, 0); + if(fn.IsClosure() || fn.IsNativeClosure() || fn.IsNull()) + { + this->_errorhandler = fn; + } +} + +void VXState::EnableDebugInfo(bool enable) +{ + _ss(this)->_debuginfo = enable; +} + +void VXState::PushRoot() +{ + this->Push(this->_roottable); +} + +void VXState::PopRoot() +{ + this->Pop(1); +} + +VXInteger VXState::GetUserPointer(VXInteger idx, VXUserPointer *p) +{ + VXObject o; + _GETSAFE_OBJ_REF(this, idx, VX_OT_USERPOINTER, o); + (*p) = _userpointerval(o); + return VX_OK; +} + +VXInteger VXState::GetString(VXInteger idx, const char** destination, VXInteger* len_dest) +{ + VXObject objptr; + _GETSAFE_OBJ_REF(this, idx, VX_OT_STRING, objptr); + *destination = _stringval(objptr); + if(len_dest != NULL) + { + *len_dest = _stringlen(objptr); + } + return VX_OK; +} + +VXInteger VXState::GetInteger(VXInteger idx, VXInteger* dest) +{ + VXObject& o = this->StackGet(idx); + if(o.IsNumeric()) + { + *dest = o.Integer(); + return VX_OK; + } + return VX_ERROR; +} + + +VXInteger VXState::GetFloat(VXInteger idx, VXFloat* dest) +{ + VXObject& o = this->StackGet(idx); + if(o.IsNumeric()) + { + *dest = o.Float(); + return VX_OK; + } + return VX_ERROR; +} + +VXInteger VXState::GetBool(VXInteger idx, bool* dest) +{ + VXObject& o = this->StackGet(idx); + if(o.IsBool()) + { + *dest = o.Integer(); + return VX_OK; + } + return VX_ERROR; +} + +VXInteger VXState::GetClosure(VXInteger idx, VXFuncProtoObj** fnproto) +{ + VXRawObj o = this->StackGet(idx); + if(type(o) == VX_OT_CLOSURE) + { + (*fnproto) = _closure(o)->_function; + return VX_OK; + } + return VX_ERROR; +} + +VXInteger VXState::GetTypedArg(VXInteger idx, VXOType expected_type, VXObject& dest) +{ + dest = this->StackGet(idx); + if(type(dest) != expected_type) + { + VXObject oval = this->PrintObjVal(dest); + this->ThrowError( + "wrong argument type, expected '%s' got '%.50s'", + IdType2Name(expected_type), + _stringval(oval)); + return VX_ERROR; + } + return VX_OK; +} + +bool VXState::CollectGarbage() +{ + return this->Shared()->CollectGarbage(this); +} + +bool VXState::ResurrectUnreachable() +{ + return this->Shared()->ResurrectUnreachable(this); +} + +void VXState::AtExit(const VXObject& ob)//(VXFuncProtoObj* fn) +{ + //VXForeignClosureObj* clos = VXForeignClosureObj::Create(Shared(), fn); + //VXObject pt(clos); + //this->_atexit_functions.push_back(pt); + //VXObject pt; + //VXInteger type = ob.Type(); + //if(type == VX_RT_NATIVECLOSURE) + //{ + // pt = VXNativeClosureObj::Create(Shared(), ob.NativeClosure()); + //} + //pt = ob; + this->_atexit_functions.push_back(ob); +} + +void VXState::Move(VXState* destination, VXState* source, const VXObject& o) +{ + (void)source; + destination->Push(o); +} + +void VXState::MoveIndex(VXState* destination, VXState* source, VXInteger idx) +{ + VXState::Move(destination, source, source->StackGet(idx)); +} + +VXInteger DoCompile(VXState* v, VXLexReadFunc read, + VXUserPointer p, const char *sourcename, + bool raiseerror, VXObject* dest=NULL) +{ + VXObject o; + #ifndef VOX_NO_COMPILER + if(Compile(v, read, p, sourcename, o, raiseerror, _ss(v)->_debuginfo)) + { + VXForeignClosureObj* closure = VXForeignClosureObj::Create(_ss(v), _funcproto(o)); + if(dest != NULL) + { + (*dest) = closure; + } + else + { + v->Push(closure); + } + return VX_OK; + } + return VX_ERROR; + #else + return v->ThrowError("this is a no compiler build"); + #endif +} + + +VXInteger VXState::CompileBuffer(const char* source, VXInteger size, + const char* sourcename, bool raiseerror) +{ + BufState buf; + buf.buf = source; + buf.size = size; + buf.ptr = 0; + return DoCompile(this, buf_lexfeed, &buf, sourcename, raiseerror); +} + +VXInteger VXState::DoStringFmt(bool globaltable, bool returns, + bool raise_error, const char* str_format, ...) +{ + VXInteger retvalue; + va_list arguments; + va_start(arguments, str_format); + char* buffptr; + size_t realsize; + size_t needed = 0; + size_t initial_bufsize = 1; + buffptr = new char[initial_bufsize+1]; + needed = 1 + vsnprintf(buffptr, initial_bufsize, str_format, arguments); + va_end(arguments); + if(needed > initial_bufsize) + { + delete[] buffptr; + buffptr = new char[needed+1]; + va_start(arguments, str_format); + realsize = vsnprintf(buffptr, needed, str_format, arguments); + va_end(arguments); + } + else + { + realsize = needed; + } + buffptr[realsize] = 0; + if(globaltable) + { + this->PushRoot(); + } + retvalue = this->DoString(buffptr, realsize, "", returns, raise_error); + if(globaltable) + { + this->Pop(1); + } + delete[] buffptr; + return retvalue; +} + + +VXInteger VXState::DoString(const char* str, VXInteger len, + const char* bufname, bool retval, bool printerror) +{ + len = (len == -1) ? strlen(str) : len; + if(bufname == NULL) + { + bufname = "";//DOSTRING_DEFAULTBUFFERNAME; + } + if(VX_FAILED(this->CompileBuffer(str, len, bufname, printerror))) + { + return VX_ERROR; + } + else + { + Repush(-2); + if(VX_FAILED(StackCall(1, retval, printerror))) + { + return VX_ERROR; + } + return VX_OK; + } + return ThrowError("call failed"); +} + +VXInteger VXState::ReadClosure(VXReadFunc r, VXUserPointer up, VXObject* dest) +{ + VXObject closure; + unsigned short tag; + if(r(up, &tag, 2) != 2) + { + return ThrowError("io error"); + } + if(tag != VX_BYTECODE_STREAM_TAG) + { + return ThrowError("invalid stream"); + } + if(!VXForeignClosureObj::Load(this, up, r, closure)) + { + return VX_ERROR; + } + if(dest) + { + (*dest) = closure; + } + else + { + this->Push(closure); + } + return VX_OK; +} + +VXInteger VXState::LoadFile(const char* filename, bool printerror, + bool* failed_to_open, VXObject* dest) +{ + + FILE* file = fopen(filename, "rb"); + VXInteger ret; + unsigned short us; + unsigned char uc; + VXLexReadFunc func = _io_file_lexfeed_PLAIN; + if(file) + { + if(failed_to_open != NULL) + { + (*failed_to_open) = false; + } + ret = fread(&us,1,2,file); + if(ret != 2) + { + //probably an empty file + us = 0; + } + //BYTECODE + if(us == VX_BYTECODE_STREAM_TAG) + { + VXInteger st; + fseek(file, 0, SEEK_SET); + if(VX_SUCCEEDED((st = this->ReadClosure(file_read, file, dest)))) + { + fclose(file); + return st; + } + return st; + } + else //SCRIPT + { + switch(us) + { + //gotta swap the next 2 lines on BIG endian machines + //UTF-16 little endian + case 0xFFFE: + func = _io_file_lexfeed_UCS2_BE; + break; + + // UTF-16 big endian + case 0xFEFF: + func = _io_file_lexfeed_UCS2_LE; + break; + + // UTF-8 + case 0xBBEF: + if(fread(&uc, 1, sizeof(uc), file) == 0) + { + fclose(file); + return ThrowError("io error"); + } + if(uc != 0xBF) + { + fclose(file); + return ThrowError("Unrecognozed encoding"); + } + func = _io_file_lexfeed_PLAIN; + break; + + // ascii + default: + fseek(file, 0, SEEK_SET); + break; + } + if(VX_SUCCEEDED(DoCompile(this, func,file,filename,printerror, dest))) + { + fclose(file); + return VX_OK; + } + } + fclose(file); + return VX_ERROR; + } + if(failed_to_open != NULL) + { + (*failed_to_open) = true; + } + return ThrowError("Cannot open '%s' for reading: %s", filename, strerror(errno)); +} + +VXInteger VXState::CallStack(VXInteger idx, VXInteger params,bool retval,bool raiseerror) +{ + return this->CallSimple(this->GetUp(idx), params, retval, raiseerror); +} + +VXInteger VXState::CallStack(VXInteger params,bool retval,bool raiseerror) +{ + return this->CallStack(-(params+1), params, retval, raiseerror); +} + +VXInteger VXState::CallSimple(VXObject& closure, VXInteger params,bool retval,bool raiseerror) +{ + VXObject res; + if(this->Call(closure, params, this->_top-params, res, raiseerror)) + { + if(!this->_suspended) + { + //pop closure and args + this->Pop(params); + } + if(retval) + { + this->Push(res); + return VX_OK; + } + return VX_OK; + } + else + { + this->Pop(params); + return VX_ERROR; + } + if(!this->_suspended) + { + this->Pop(params); + } + return this->ThrowError("call failed"); +} + + +VXInteger VXState::Repush(VXInteger idx) +{ + this->Push(this->StackGet(idx)); + return VX_OK; +} + +VXInteger VXState::StackCall(VXInteger params, bool retval, bool raiseerror) +{ + VXObject res; + if(this->Call(this->GetUp(-(params+1)), params, this->_top - params, res, raiseerror)) + { + if(!this->_suspended) + { + //pop closure and args + this->Pop(params); + } + if(retval) + { + this->Push(res); + return VX_OK; + } + return VX_OK; + } + else + { + this->Pop(params); + return VX_ERROR; + } + if(!this->_suspended) + { + this->Pop(params); + } + return ThrowError("call failed"); +} + +VXInteger VXState::DoFile(const char* filename, bool retval, bool printerror, bool* failed_to_open) +{ + if(VX_SUCCEEDED(this->LoadFile(filename, printerror, failed_to_open))) + { + this->Repush(-2); + if(VX_SUCCEEDED(this->StackCall(1, retval, printerror))) + { + this->Remove(retval ? -2 : -1); + return VX_OK; + } + this->Pop(1); + return VX_ERROR; + } + return VX_ERROR; +} + + + +const char* VXState::GetLocal(VXUnsignedInteger level,VXUnsignedInteger idx, VXObject& dest) +{ + VXUnsignedInteger cstksize = this->_callsstacksize; + VXUnsignedInteger lvl = (cstksize-level)-1; + VXInteger stackbase = this->_stackbase; + if(lvl < cstksize) + { + for(VXUnsignedInteger i=0; i_callsstack[(cstksize-i)-1]; + stackbase -= ci._prevstkbase; + } + VXState::CallInfo &ci = this->_callsstack[lvl]; + if(type(ci._closure) != VX_OT_CLOSURE) + return NULL; + VXForeignClosureObj *c = _closure(ci._closure); + VXFuncProtoObj *func = c->_function; + if(func->_noutervalues > (VXInteger)idx) + { + //v->Push(*_outer(c->_outervalues[idx])->_valptr); + dest = *_outer(c->_outervalues[idx])->_valptr; + return _stringval(func->_outervalues[idx]._name); + } + idx -= func->_noutervalues; + return func->GetLocal(this, + stackbase, idx, + (VXInteger)(ci._ip-func->_instructions)-1, dest); + } + return NULL; +} + + + +void VXState::DefineGlobal(const char* name, const VXObject& sym) +{ + GetRootTable()->NewSlot(NewString(name), sym); +} + +void VXState::SetPrintFunc(VXPrintFunction printfunc,VXPrintFunction errfunc) +{ + this->Shared()->_printfunc = printfunc; + this->Shared()->_errorfunc = errfunc; +} + + + +void VXState::PushLastError() +{ + this->Push(this->_lasterror); +} + + +const char* VXState::LastError() +{ + const char* result; + this->PushLastError(); + if(VX_FAILED(this->GetString(-1, &result, NULL))) + { + result = ""; + } + return result; +} + +void VXState::Mark(VXCollectable **chain) +{ + START_MARK() + VXSharedState::MarkObject(_lasterror,chain); + VXSharedState::MarkObject(_errorhandler,chain); + VXSharedState::MarkObject(_debughook_closure,chain); + VXSharedState::MarkObject(_roottable, chain); + VXSharedState::MarkObject(temp_reg, chain); + for(VXUnsignedInteger i = 0; i < _stack.size(); i++) + { + VXSharedState::MarkObject(_stack[i], chain); + } + for(VXInteger k = 0; k < _callsstacksize; k++) + { + VXSharedState::MarkObject(_callsstack[k]._closure, chain); + } + END_MARK() +} + +void VXState::Release() +{ + vox_delete(this,VXState); +} + +VXOType VXState::GetType() +{ + return VX_OT_THREAD; +} + +void VXState::GrowCallStack() +{ + VXInteger newsize = _alloccallsstacksize*2; + _callstackdata.resize(newsize); + _callsstack = &_callstackdata[0]; + _alloccallsstacksize = newsize; +} + +VXObject& VXState::StackGet(VXInteger idx) +{ + //return ((idx>=0) ? (this->GetAt(idx + ((this->_stackbase)-1))) : (this->GetUp(idx))); + if(idx >= 0) + { + return this->GetAt(idx + ((this->_stackbase)-1)); + } + return this->GetUp(idx); +} + +VXInteger VXState::SetParamsCheck(VXObject& o, VXInteger nparams, const char *typemask) +{ + //VXObject o = stack_get(v, -1); + if(!o.IsNativeClosure()) + { + return ThrowError("native closure expected"); + } + VXNativeClosureObj *nc = _nativeclosure(o); + nc->_nparamscheck = nparams; + if(typemask) + { + VXIntVec res; + if(!CompileTypemask(res, typemask)) + { + return ThrowError("invalid typemask"); + } + nc->_typecheck.copy(res); + } + else + { + nc->_typecheck.resize(0); + } + if(nparams == VX_MATCHTYPEMASKSTRING) + { + nc->_nparamscheck = nc->_typecheck.size(); + } + return VX_OK; +} + + +void RegisterLib_IterReg(VXState* self, const VXRegFunction* funcs, VXTableObj* dest) +{ + VXInteger i; + for(i=0; funcs[i].name; i++) + { + VXRegFunction reg = funcs[i]; + VXObject name = self->NewString(reg.name); + VXObject fn = self->NewClosure(reg.func); + self->SetParamsCheck(fn, reg.nparamscheck, reg.typemask); + dest->NewSlot(name, fn); + } +} + +VXTableObj* VXState::RegisterLib(const char* libname, const VXRegFunction* funcs, + bool reg_global, VXTableObj* tb) +{ + + if(reg_global && (libname == NULL)) + { + // in this case, each function of $funcs is supposed to be + // a separate item in the root table + RegisterLib_IterReg(this, funcs, GetRootTable()); + } + else + { + // otherwise, a separate table with each function of $funcs will be + // created and newslot'd to the root table + if(tb == NULL) + { + tb = this->NewTable(); + } + RegisterLib_IterReg(this, funcs, tb); + if(reg_global) + { + vox_assert(libname != NULL); + GetRootTable()->NewSlot(NewString(libname), tb); + } + } + return tb; +} + +VXClassObj* VXState::RegClass(const VXVector& funcs, + VXClassObj* base, + VXUserPointer typetag) +{ + VXUnsignedInteger i; + VXClassObj* cl; + cl = this->NewClass(base); + for(i=0; iNewClosure(f.func); + VXObject name = this->NewString(f.name); + this->SetParamsCheck(fn, f.nparamscheck, f.typemask); + cl->NewSlot(this->Shared(), name, fn, false); + } + if(typetag != 0) + { + cl->_typetag = typetag; + } + return cl; + +} + +VXClassObj* VXState::RegClass(const VXRegFunction* funcs, + VXClassObj* base, + VXUserPointer typetag) +{ + VXInteger i; + VXVector vecfuncs; + for(i=0; funcs[i].name; i++) + { + vecfuncs.push_back(funcs[i]); + } + return this->RegClass(vecfuncs, base, typetag); +} + + +VXClassObj* VXState::NewClass(VXClassObj* baseclass) +{ + VXClassObj* ret; + ret = VXClassObj::Create(this->Shared(), baseclass); + return ret; +} + +VXNativeClosureObj* VXState::NewClosure(VXFunction func, VXUnsignedInteger nfreevars) +{ + VXNativeClosureObj *nc = VXNativeClosureObj::Create(this->Shared(), func,nfreevars); + nc->_nparamscheck = 0; + for(VXUnsignedInteger i=0; i_outervalues[i] = this->Top(); + this->Pop(); + } + return nc; +} + +VXStringObj* VXState::NewString(const char* str, VXInteger len) +{ + return VXStringObj::Create(_sharedstate, str, len); +} + +VXArrayObj* VXState::NewArray(VXInteger initial_size) +{ + return VXArrayObj::Create(_sharedstate, initial_size); +} + +VXTableObj* VXState::NewTable() +{ + return VXTableObj::Create(_sharedstate, 0); +} + + +VXState* VXState::NewThread(VXState* friendvm, VXInteger initialstacksize) +{ + VXSharedState *ss; + VXState *v; + ss = _ss(friendvm); + v = (VXState *)VX_MALLOC(sizeof(VXState)); + new (v) VXState(ss); + + if(v->Init(friendvm, initialstacksize)) + { + friendvm->Push(v); + return v; + } + else + { + vox_delete(v, VXState); + return NULL; + } +} + +VXArrayObj* VXState::GetSysArgv() +{ + return _system_argv; +} + +VXTableObj* VXState::GetRegistryTable() +{ + return Shared()->_registry.Table(); +} + +VXTableObj* VXState::GetRootTable() +{ + return _roottable.Table(); +} + + +VXInteger VXState::ThrowError(const char *s, ...) +{ + va_list vl; + va_start(vl, s); + vsprintf(ScratchPad((VXInteger)strlen(s)+(NUMBER_MAX_CHAR*2)), s, vl); + va_end(vl); + this->_lasterror = VXStringObj::Create(_ss(this),ScratchPad(-1),-1); + return VX_ERROR; +} + +VXInteger VXState::Irrecoverable_Error(const char* s, ...) +{ + va_list vl; + va_start(vl, s); + vsprintf(ScratchPad((VXInteger)strlen(s)+(NUMBER_MAX_CHAR*2)), s, vl); + va_end(vl); + fprintf(stderr, "Irrecoverable Error: %s\n", ScratchPad(-1)); + exit(-1); + return VX_ERROR; // never reached +} + + +VXStringObj* VXState::PrintObjVal(const VXObject &o) +{ + switch(type(o)) + { + case VX_OT_STRING: + return _string(o); + case VX_OT_INTEGER: + sprintf(ScratchPad(NUMBER_MAX_CHAR+1), _PRINT_INT_FMT, _integer(o)); + return VXStringObj::Create(_ss(this), ScratchPad(-1)); + break; + case VX_OT_FLOAT: + sprintf(ScratchPad(NUMBER_MAX_CHAR+1), "%.14g", _float(o)); + return VXStringObj::Create(_ss(this), ScratchPad(-1)); + break; + default: + return VXStringObj::Create(_ss(this), GetTypeName(o)); + } +} + +VXInteger VXState::Raise_IdxError(const VXObject &o, + const VXObject& origin, + bool is_index) +{ + VXInteger len; + VXObject idx = PrintObjVal(o); + if(origin.Type() == VX_OT_TABLE) + { + return ThrowError("table key '%.50s' does not exist", _stringval(idx)); + } + if(((origin.Type() == VX_OT_CLASS || origin.Type() == VX_OT_INSTANCE) || + (origin.Type() & VX_OT_INSTANCE)) && !is_index) + { + return ThrowError("class member '%.50s' does not exist", _stringval(idx)); + } + if(origin.Type() == VX_OT_STRING || origin.Type() == VX_OT_ARRAY) + { + switch(origin.Type()) + { + case VX_OT_STRING: + len = origin.String()->_len; + break; + case VX_OT_ARRAY: + len = origin.Array()->Size(); + break; + default: + len = -1; + } + return ThrowError("%s index '%.50s' out of range (%s size: %d)", + origin.TypeString(), _stringval(idx), origin.TypeString(), len); + } + return ThrowError("%s index '%.50s' does not exist", + origin.TypeString(), _stringval(idx)); +} + +VXInteger VXState::ThrowError(const VXObject &desc) +{ + _lasterror = desc; + return VX_ERROR; +} + + +VXInteger VXState::Raise_CompareError(const VXObject &o1, const VXObject &o2) +{ + VXObject oval1 = PrintObjVal(o1); + VXObject oval2 = PrintObjVal(o2); + ThrowError("comparison between '%s' and '%s'", o1.TypeString(), o2.TypeString()); + return VX_ERROR; +} + +VXInteger VXState::Raise_ParamTypeError(VXInteger nparam,VXInteger typemask,VXInteger type) +{ + VXObject exptypes = VXStringObj::Create(_ss(this), "", -1); + VXInteger found = 0; + for(VXInteger i=0; i<16; i++) + { + VXInteger mask = 0x00000001 << i; + if(typemask & (mask)) + { + if(found > 0) + { + StringCat(exptypes,VXStringObj::Create(_ss(this), "|", -1), exptypes); + } + found++; + StringCat(exptypes,VXStringObj::Create(_ss(this), + IdType2Name((VXOType)mask), -1), exptypes); + } + } + return ThrowError("parameter %d has an invalid type '%s' ; expected: '%s'", + nparam, + IdType2Name((VXOType)type), + _stringval(exptypes) + ); +} + + +VXSharedState* VXState::Shared() +{ + return _sharedstate; +} + +VXState* VXState::Create(VXInteger stacksize) +{ + VXSharedState *ss; + VXState *v; + vox_new(ss, VXSharedState); + ss->Init(); + v = (VXState *)VX_MALLOC(sizeof(VXState)); + new (v) VXState(ss); + ss->_root_vm = v; + if(v->Init(NULL, stacksize) == true) + { + v->_system_argv = v->NewArray(); + voxstd_register_system(v); + voxstd_register_mathlib(v); + voxstd_register_iolib(v); + v->SetPrintFunc(vox_defaultprintfunc, vox_defaulterrorfunc); + return v; + } + else + { + vox_delete(v, VXState); + return NULL; + } + return NULL; +} + +void VXState::Destroy(VXState* vm) +{ + VXUnsignedInteger i; + VXSharedState* ss = _ss(vm); + for(i=0; i<(vm->_atexit_functions.size()); i++) + { + VXObject res; + if(!vm->Call(vm->_atexit_functions[i], 1, vm->GetTop()-1, res, false)) + { + //fprintf(stderr, "Call() failed?\n"); + } + } + _thread(ss->_root_vm)->Finalize(); + vox_delete(ss, VXSharedState); +} + + +VXState::VXState(VXSharedState *ss) +{ + _sharedstate=ss; + _suspended = false; + _suspended_target = -1; + _suspended_root = false; + _suspended_traps = -1; + _foreignptr = NULL; + _nnativecalls = 0; + _nmetamethodscall = 0; + _lasterror.Null(); + _errorhandler.Null(); + _debughook = false; + _debughook_native = NULL; + _debughook_closure.Null(); + _openouters = NULL; + ci = NULL; + INIT_CHAIN(); + ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); +} + +void VXState::Finalize() +{ + if(_openouters) + { + CloseOuters(this, &_stack.values()[0]); + } + _roottable.Null(); + _lasterror.Null(); + _errorhandler.Null(); + _debughook = false; + _debughook_native = NULL; + _debughook_closure.Null(); + temp_reg.Null(); + _callstackdata.resize(0); + VXInteger size=_stack.size(); + for(VXInteger i=0;i_gc_chain,this); +} + + + + +bool VXState::ObjCmp(const VXObject &o1, + const VXObject &o2, + VXInteger &result) +{ + VXObject res; + VXOType t1 = type(o1); + VXOType t2 = type(o2); + if(t1 == t2) + { + if(_rawval(o1) == _rawval(o2)) + { + _RET_SUCCEED(0); + } + switch(t1) + { + case VX_OT_STRING: + _RET_SUCCEED(strcmp(_stringval(o1), _stringval(o2))); + case VX_OT_INTEGER: + _RET_SUCCEED(_integer(o1)-_integer(o2)); + case VX_OT_FLOAT: + _RET_SUCCEED((_float(o1)<_float(o2))?-1:1); + case VX_OT_TABLE: + case VX_OT_USERDATA: + case VX_OT_INSTANCE: + if(_delegable(o1)->_delegate) + { + VXObject closure; + if(_delegable(o1)->GetMetaMethod(this, VX_MT_CMP, closure)) + { + Push(o1);Push(o2); + if(!CallMetaMethod(this, closure,VX_MT_CMP,2,res)) + { + return false; + } + } + break; + } + //continues through (no break needed) + default: + _RET_SUCCEED( _userpointerval(o1) < _userpointerval(o2)?-1:1 ); + } + if(type(res)!=VX_OT_INTEGER) + { + Raise_CompareError(o1,o2); + return false; + } + _RET_SUCCEED(_integer(res)); + + } + else + { + if(o1.IsNumeric() && o2.IsNumeric()) + { + if((t1==VX_OT_INTEGER) && (t2==VX_OT_FLOAT)) + { + if(_integer(o1) == _float(o2) ) + { + _RET_SUCCEED(0); + } + else if(_integer(o1)<_float(o2)) + { + _RET_SUCCEED(-1); + } + _RET_SUCCEED(1); + } + else + { + if(_float(o1)==_integer(o2)) + { + _RET_SUCCEED(0); + } + else if(_float(o1) < _integer(o2)) + { + _RET_SUCCEED(-1); + } + _RET_SUCCEED(1); + } + } + else if(t1==VX_OT_NULL) + { + _RET_SUCCEED(-1); + } + else if(t2==VX_OT_NULL) + { + _RET_SUCCEED(1); + } + else + { + Raise_CompareError(o1,o2); + return false; + } + } + vox_assert(0); + _RET_SUCCEED(0); //cannot happen +} + + +bool VXState::ToString(const VXObject &o, VXObject &res) +{ + switch(type(o)) + { + case VX_OT_STRING: + res = o; + return true; + case VX_OT_FLOAT: + sprintf(ScratchPad(NUMBER_MAX_CHAR+1),"%g",_float(o)); + break; + case VX_OT_INTEGER: + sprintf(ScratchPad(NUMBER_MAX_CHAR+1),_PRINT_INT_FMT,_integer(o)); + break; + case VX_OT_BOOL: + sprintf(ScratchPad(6),_integer(o)?"true":"false"); + break; + case VX_OT_TABLE: + case VX_OT_USERDATA: + case VX_OT_INSTANCE: + if(_delegable(o)->_delegate) + { + VXObject closure; + if(_delegable(o)->GetMetaMethod(this, VX_MT_TOSTRING, closure)) + { + Push(o); + if(CallMetaMethod(this, closure,VX_MT_TOSTRING,1,res)) + { + if(type(res) == VX_OT_STRING) + { + return true; + } + } + else + { + return false; + } + } + } + default: + if(type(o) != VX_OT_NULL) + { + sprintf(ScratchPad(sizeof(void*)+60), + "<%s at %p>", + GetTypeName(o),(void*)_rawval(o)); + } + else + { + sprintf(ScratchPad(8), ""); + } + } + //res = VXStringObj::Create(_ss(this), ScratchPad(-1)); + res = NewString(ScratchPad(-1)); + return true; +} + + +bool VXState::StringCat(const VXObject &str, + const VXObject &obj, + VXObject &dest) +{ + VXObject a, b; + if(!ToString(str, a)) + { + return false; + } + if(!ToString(obj, b)) + { + return false; + } + VXInteger l = _string(a)->_len , ol = _string(b)->_len; + char *s = ScratchPad(l + ol + 1); + memcpy(s, _stringval(a), l); + memcpy(s + l, _stringval(b), ol); + dest = VXStringObj::Create(_ss(this), ScratchPad(-1), l + ol); + return true; +} + +bool VXState::TypeOf(const VXObject &obj1, + VXObject &dest) +{ + if(is_delegable(obj1) && _delegable(obj1)->_delegate) + { + VXObject closure; + if(_delegable(obj1)->GetMetaMethod(this, VX_MT_TYPEOF, closure)) + { + Push(obj1); + return CallMetaMethod(this, closure,VX_MT_TYPEOF,1,dest); + } + } + dest = VXStringObj::Create(_ss(this),GetTypeName(obj1)); + return true; +} + +bool VXState::Init(VXState *friendvm, VXInteger stacksize) +{ + _stack.resize(stacksize); + _alloccallsstacksize = 4; + _callstackdata.resize(_alloccallsstacksize); + _callsstacksize = 0; + _callsstack = &_callstackdata[0]; + _stackbase = 0; + _top = 0; + if(!friendvm) + { + _roottable = NewTable(); + } + else + { + _roottable = friendvm->_roottable; + _errorhandler = friendvm->_errorhandler; + _debughook = friendvm->_debughook; + _debughook_native = friendvm->_debughook_native; + _debughook_closure = friendvm->_debughook_closure; + } + return true; + +} + + +bool VXState::StartCall(VXForeignClosureObj *closure, + VXInteger target, + VXInteger args, + VXInteger stackbase, + bool tailcall) +{ + VXFuncProtoObj *func = closure->_function; + + VXInteger paramssize = func->_nparameters; + const VXInteger newtop = stackbase + func->_stacksize; + VXInteger nargs = args; + const char* funcname = _stringval(func->_name); + if(func->_name.IsNull()) + { + funcname = NAMES_ANONFUNC; + } + if(func->_varparams) + { + paramssize--; + if(nargs < paramssize) + { + return WrongNumberOfArguments(this, false, false, func); + } + VXInteger nvargs = nargs - paramssize; + VXArrayObj *arr = VXArrayObj::Create(_ss(this),nvargs); + VXInteger pbase = stackbase+paramssize; + for(VXInteger n = 0; n < nvargs; n++) + { + arr->_values[n] = _stack.values()[pbase]; + _stack.values()[pbase].Null(); + pbase++; + } + _stack.values()[stackbase+paramssize] = arr; + } + else if (paramssize != nargs) + { + VXInteger ndef = func->_ndefaultparams; + VXInteger diff; + if(ndef && (nargs < paramssize) && (diff = (paramssize - nargs)) <= ndef) + { + for(VXInteger n = ndef - diff; n < ndef; n++) + { + _stack.values()[stackbase + (nargs++)] = closure->_defaultparams[n]; + } + } + else + { + return WrongNumberOfArguments(this, false, false, func); + } + } + if(closure->_env) + { + _stack.values()[stackbase] = closure->_env->_obj; + } + if(!EnterFrame(stackbase, newtop, tailcall)) + { + return false; + } + ci->_closure = closure; + ci->_literals = func->_literals; + ci->_ip = func->_instructions; + ci->_target = (VXInt32)target; + if (_debughook) + { + CallDebugHook('c'); + } + if (closure->_function->_bgenerator) + { + VXFuncProtoObj *f = closure->_function; + VXGeneratorObj *gen = VXGeneratorObj::Create(_ss(this), closure); + if(!gen->Yield(this,f->_stacksize)) + return false; + VXObject temp; + Return(this, 1, target, temp); + STK(target) = gen; + } + return true; +} + + + +VXInteger VXState::RawGetStack(VXInteger idx) +{ + VXObject& self = StackGet(idx); + switch(type(self)) + { + case VX_OT_TABLE: + if(_table(self)->Get(GetUp(-1), GetUp(-1))) + return VX_OK; + break; + case VX_OT_CLASS: + if(_class(self)->Get(GetUp(-1), GetUp(-1))) + return VX_OK; + break; + case VX_OT_INSTANCE: + if(_instance(self)->Get(GetUp(-1), GetUp(-1))) + return VX_OK; + break; + case VX_OT_ARRAY: + { + VXObject& key = GetUp(-1); + if(key.IsNumeric()) + { + if(_array(self)->Get(tointeger(key), GetUp(-1))) + { + return VX_OK; + } + } + else + { + Pop(); + return ThrowError("invalid index type for an array"); + } + } + break; + default: + Pop(); + return ThrowError("rawget works only on array/table/instance and class"); + } + Pop(); + return ThrowError("the index doesn't exist"); +} + +VXInteger VXState::RawSetStack(VXInteger idx) +{ + VXObject &self = this->StackGet(idx); + if(type(this->GetUp(-2)) == VX_OT_NULL) + { + return this->ThrowError("null key"); + } + switch(type(self)) + { + case VX_OT_TABLE: + _table(self)->NewSlot(GetUp(-2), GetUp(-1)); + Pop(2); + return VX_OK; + break; + case VX_OT_CLASS: + _class(self)->NewSlot(Shared(), GetUp(-2), GetUp(-1),false); + Pop(2); + return VX_OK; + break; + case VX_OT_INSTANCE: + if(_instance(self)->Set(GetUp(-2), GetUp(-1))) + { + Pop(2); + return VX_OK; + } + break; + case VX_OT_ARRAY: + if(Set(self, GetUp(-2), GetUp(-1),false)) + { + Pop(2); + return VX_OK; + } + break; + default: + Pop(2); + return ThrowError("rawset works only on array/table/class and instance"); + } + return Raise_IdxError(GetUp(-2), self); +} + +VXInteger VXState::ToStringAt(VXInteger idx, VXObject& dest) +{ + VXObject &o = this->StackGet(idx); + return this->ToString(o, dest); +} + +VXInteger VXState::Raise_InvalidType(VXOType type) +{ + return ThrowError("unexpected type %s", IdType2Name(type)); +} + + +VXInteger VXState::GetSize(const VXObject& o) +{ + VXOType type = type(o); + switch(type) + { + case VX_OT_STRING: + return _string(o)->_len; + case VX_OT_TABLE: + return _table(o)->CountUsed(); + case VX_OT_ARRAY: + return _array(o)->Size(); + case VX_OT_USERDATA: + return _userdata(o)->_size; + case VX_OT_INSTANCE: + return _instance(o)->_class->_udsize; + case VX_OT_CLASS: + return _class(o)->_udsize; + default: + return this->Raise_InvalidType(type); + } +} + +VXInteger VXState::GetSizeAt(VXInteger idx) +{ + VXObject &o = StackGet(idx); + return this->GetSize(o); +} + +VXInteger VXState::Clear(VXObject& o) +{ + switch(type(o)) + { + case VX_OT_TABLE: + _table(o)->Clear(); + break; + case VX_OT_ARRAY: + _array(o)->Resize(0); + break; + default: + return this->ThrowError("clear only works on table and array"); + break; + } + return VX_OK; +} + + +VXInteger VXState::ClearAt(VXInteger idx) +{ + return this->Clear(this->StackGet(idx)); +} + + +VXInteger VXState::StackInfos(VXInteger level, VXStackInfos* si) +{ + VXInteger cssize = this->_callsstacksize; + if (cssize > level) + { + memset(si, 0, sizeof(VXStackInfos)); + VXState::CallInfo &ci = this->_callsstack[cssize-level-1]; + switch(type(ci._closure)) + { + case VX_OT_CLOSURE: + { + VXFuncProtoObj *func = _closure(ci._closure)->_function; + si->native = false; + if (type(func->_name) == VX_OT_STRING) + { + si->funcname = _stringval(func->_name); + } + if (type(func->_sourcename) == VX_OT_STRING) + { + si->source = _stringval(func->_sourcename); + } + si->line = func->GetLine(ci._ip); + } + break; + case VX_OT_NATIVECLOSURE: + { + si->native = true; + si->source = ""; + si->funcname = ""; + if(type(_nativeclosure(ci._closure)->_name) == VX_OT_STRING) + { + si->funcname = _stringval(_nativeclosure(ci._closure)->_name); + } + si->line = -1; + } + break; + default: + break; + } + return VX_OK; + } + return VX_ERROR; +} + +VXPrintFunction VXState::GetErrorFunc() +{ + return Shared()->_errorfunc; +} + +VXInteger VXState::Suspend() +{ + if (_suspended) + { + return this->ThrowError("cannot suspend an already suspended vm"); + } + if (_nnativecalls!=2) + { + return this->ThrowError("cannot suspend through native calls/metamethods"); + } + return VX_SUSPEND_FLAG; +} + + + + + +bool VXState::IsEqual(const VXObject &o1, + const VXObject &o2, + bool &res) +{ + if(type(o1) == type(o2)) + { + res = (_rawval(o1) == _rawval(o2)); + } + else + { + if(o1.IsNumeric() && o2.IsNumeric()) + { + res = (tofloat(o1) == tofloat(o2)); + } + else + { + res = false; + } + } + return true; +} + +bool VXState::IsFalse(VXObject &o) +{ + if(((type(o) & VXOBJECT_CANBEFALSE) + && ( ((type(o) == VX_OT_FLOAT) && (_float(o) == VXFloat(0.0))) )) + || (_integer(o) == 0) ) //VX_OT_NULL|OT_INTEGER|OT_BOOL + { + return true; + } + return false; +} + +bool VXState::Execute(VXObject &closure, + VXInteger nargs, + VXInteger stackbase, + VXObject &outres, + bool raiseerror, + ExecutionType et) +{ + if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) + { + ThrowError("native stack overflow"); + return false; + } + _nnativecalls++; + AutoDec ad(&_nnativecalls); + VXInteger traps = 0; + CallInfo *prevci = ci; + switch(et) + { + case ET_CALL: + { + temp_reg = closure; + if(!StartCall(_closure(temp_reg), + _top - nargs, + nargs, stackbase, false)) + { + // call the handler if there are no calls in the + // stack, if not relies on the previous node + if(ci == NULL) + { + CallErrorHandler(_lasterror); + } + return false; + } + if(ci == prevci) + { + outres = STK(_top-nargs); + return true; + } + ci->_root = true; + } + break; + case ET_RESUME_GENERATOR: + _generator(closure)->Resume(this, outres); + ci->_root = true; + traps += ci->_etraps; + break; + case ET_RESUME_VM: + case ET_RESUME_THROW_VM: + traps = _suspended_traps; + ci->_root = _suspended_root; + _suspended = false; + if(et == ET_RESUME_THROW_VM) + { + VX_THROW(); + } + break; + } + +exception_restore: + // + { + for(;;) + { + const VXInstruction &_i_ = *ci->_ip++; + switch(_i_.op) + { + case _OP_LINE: + if (_debughook) + { + CallDebugHook('l',arg1); + } + continue; + + case _OP_LOAD: + TARGET = ci->_literals[arg1]; + continue; + + case _OP_LOADINT: + TARGET = (VXInteger)arg1; + continue; + + case _OP_LOADFLOAT: + TARGET = *((VXFloat *)&arg1); + continue; + + case _OP_DLOAD: + TARGET = ci->_literals[arg1]; + STK(arg2) = ci->_literals[arg3]; + continue; + + case _OP_TAILCALL: + { + VXInteger i; + VXObject &t = STK(arg1); + if (type(t) == VX_OT_CLOSURE + && (!_closure(t)->_function->_bgenerator)) + { + VXObject clo = t; + if(_openouters) + { + CloseOuters(this, &(_stack.values()[_stackbase])); + } + for(i=0; i_target, arg3, _stackbase, true)); + continue; + } + } + + case _OP_CALL: + { + VXObject clo = STK(arg1); + switch (type(clo)) + { + case VX_OT_CLOSURE: + _GUARD(StartCall(_closure(clo), + sarg0, arg3, + _stackbase+arg2, false)); + continue; + case VX_OT_NATIVECLOSURE: + { + bool suspend; + _GUARD(CallNative( + _nativeclosure(clo), + arg3, _stackbase+arg2, + clo,suspend)); + if(suspend) + { + _suspended = true; + _suspended_target = sarg0; + _suspended_root = ci->_root; + _suspended_traps = traps; + outres = clo; + return true; + } + if(sarg0 != -1) + { + STK(arg0) = clo; + } + } + continue; + case VX_OT_CLASS: + { + VXInteger stkbase; + VXObject inst; + _GUARD(CreateClassInstance( + _class(clo),inst,clo)); + if(sarg0 != -1) + { + STK(arg0) = inst; + } + switch(type(clo)) + { + case VX_OT_CLOSURE: + stkbase = _stackbase+arg2; + _stack.values()[stkbase] = inst; + _GUARD(StartCall( + _closure(clo), -1, arg3, + stkbase, false)); + break; + case VX_OT_NATIVECLOSURE: + bool suspend; + stkbase = _stackbase+arg2; + _stack.values()[stkbase] = inst; + + _GUARD(CallNative( + _nativeclosure(clo), arg3, + stkbase, clo, suspend)); + + + break; + default: + break; //shutup GCC 4.x + } + + + + } + break; + case VX_OT_TABLE: + case VX_OT_USERDATA: + case VX_OT_INSTANCE: + { + VXObject closure; + if(_delegable(clo)->_delegate && + _delegable(clo)->GetMetaMethod(this,VX_MT_CALL,closure)) + { + Push(clo); + for (VXInteger i=0; i_literals)[arg1] : STK(arg1); + VXObject &o = STK(arg2); + if (!Get(o, key, temp_reg,false,arg2)) + { + VX_THROW(); + } + STK(arg3) = o; + _Swap(TARGET,temp_reg);//TARGET = temp_reg; + } + continue; + + case _OP_GETK: + if (!Get(STK(arg2), ci->_literals[arg1], + temp_reg, false,arg2)) + { + VX_THROW(); + } + _Swap(TARGET,temp_reg);//TARGET = temp_reg; + continue; + + case _OP_MOVE: + TARGET = STK(arg1); + continue; + + case _OP_NEWSLOT: + _GUARD(NewSlot(STK(arg1), STK(arg2), + STK(arg3),false)); + if(arg0 != 0xFF) + { + TARGET = STK(arg3); + } + continue; + + case _OP_DELETE: + _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); + continue; + + case _OP_SET: + if (!Set(STK(arg1), STK(arg2), STK(arg3),arg1)) + { + VX_THROW(); + } + if (arg0 != 0xFF) + { + TARGET = STK(arg3); + } + continue; + + case _OP_GET: + if (!Get(STK(arg1), STK(arg2), temp_reg, false,arg1)) + { + VX_THROW(); + } + _Swap(TARGET,temp_reg);//TARGET = temp_reg; + continue; + + case _OP_EQ: + { + bool res; + if(!IsEqual(STK(arg2),COND_LITERAL,res)) + { + VX_THROW(); + } + TARGET = res ? true : false; + } + continue; + + case _OP_NE: + { + bool res; + if(!IsEqual(STK(arg2),COND_LITERAL,res)) + { + VX_THROW(); + } + TARGET = (!res) ? true : false; + } + continue; + + case _OP_ADD: + _ARITH_(+,TARGET,STK(arg2),STK(arg1)); + continue; + + case _OP_SUB: + _ARITH_(-,TARGET,STK(arg2),STK(arg1)); + continue; + + case _OP_MUL: + _ARITH_(*,TARGET,STK(arg2),STK(arg1)); + continue; + + case _OP_DIV: + _ARITH_NOZERO(/,TARGET,STK(arg2), + STK(arg1), "division by zero"); + continue; + + case _OP_MOD: + ARITH_OP(this, '%',TARGET,STK(arg2),STK(arg1)); + continue; + + case _OP_BITW: + _GUARD(BW_OP(this, arg3,TARGET,STK(arg2),STK(arg1))); + continue; + + case _OP_RETURN: + if((ci)->_generator) + { + (ci)->_generator->Kill(); + } + if(Return(this, arg0, arg1, temp_reg)) + { + vox_assert(traps == 0); + //outres = temp_reg; + _Swap(outres,temp_reg); + return true; + } + continue; + + case _OP_LOADNULLS: + { + for(VXInt32 n=0; n < arg1; n++) + { + STK(arg0+n).Null(); + } + } + continue; + + case _OP_LOADROOT: + TARGET = _roottable; + continue; + + case _OP_LOADBOOL: + TARGET = arg1?true:false; + continue; + + case _OP_DMOVE: + STK(arg0) = STK(arg1); + STK(arg2) = STK(arg3); + continue; + + case _OP_JMP: + ci->_ip += (sarg1); + continue; + + case _OP_JCMP: + _GUARD(CMP_OP(this, (CmpOP)arg3,STK(arg2), + STK(arg0),temp_reg)); + if(IsFalse(temp_reg)) + { + ci->_ip+=(sarg1); + } + continue; + + case _OP_JZ: + if(IsFalse(STK(arg0))) + { + ci->_ip+=(sarg1); + } + continue; + + case _OP_GETOUTER: + { + VXForeignClosureObj *cur_cls = _closure(ci->_closure); + VXOuterObj *otr = _outer(cur_cls->_outervalues[arg1]); + TARGET = *(otr->_valptr); + } + continue; + + case _OP_SETOUTER: + { + VXForeignClosureObj *cur_cls = _closure(ci->_closure); + VXOuterObj *otr = _outer(cur_cls->_outervalues[arg1]); + *(otr->_valptr) = STK(arg2); + if(arg0 != 0xFF) + { + TARGET = STK(arg2); + } + } + continue; + + case _OP_NEWOBJ: + switch(arg3) + { + case NVX_OT_TABLE: + TARGET = VXTableObj::Create(_ss(this), arg1); + continue; + case NVX_OT_ARRAY: + TARGET = VXArrayObj::Create(_ss(this), 0); + _array(TARGET)->Reserve(arg1); + continue; + + case NVX_OT_CLASS: + _GUARD(CLASS_OP(this, TARGET,arg1,arg2)); + continue; + + default: + vox_assert(0); + continue; + } + case _OP_APPENDARRAY: + { + VXRawObj val; + val._unVal.raw = 0; + switch(arg2) + { + case AAT_STACK: + val = STK(arg1); + break; + case AAT_LITERAL: + val = ci->_literals[arg1]; + break; + case AAT_INT: + val._type = VX_OT_INTEGER; + val._unVal.nInteger = (VXInteger)arg1; + break; + case AAT_FLOAT: + val._type = VX_OT_FLOAT; + val._unVal.fFloat = *((VXFloat *)&arg1); + break; + case AAT_BOOL: + val._type = VX_OT_BOOL; + val._unVal.nInteger = arg1; + break; + default: + vox_assert(0); + break; + + } + _array(STK(arg0))->Append(val); + continue; + } + + case _OP_COMPARITH: + { + VXInteger selfidx = + (((VXUnsignedInteger)arg1&0xFFFF0000)>>16); + _GUARD(DerefInc(this, arg3, TARGET, + STK(selfidx), STK(arg2), + STK(arg1&0x0000FFFF), false, selfidx)); + } + continue; + + case _OP_INC: + { + VXObject o(sarg3); + _GUARD(DerefInc(this, '+',TARGET, STK(arg1), + STK(arg2), o, false, arg1)); + } + continue; + + case _OP_INCL: + { + VXObject &a = STK(arg1); + if(type(a) == VX_OT_INTEGER) + { + a._unVal.nInteger = _integer(a) + sarg3; + } + else + { + VXObject o(sarg3); + _ARITH_(+,a,a,o); + } + } + continue; + + case _OP_PINC: + { + VXObject o(sarg3); + _GUARD(DerefInc(this, '+',TARGET, + STK(arg1), STK(arg2), o, true, arg1)); + } + continue; + + case _OP_PINCL: + { + VXObject &a = STK(arg1); + if(type(a) == VX_OT_INTEGER) + { + TARGET = a; + a._unVal.nInteger = _integer(a) + sarg3; + } + else + { + VXObject o(sarg3); + _GUARD(PLOCAL_INC(this, '+',TARGET, STK(arg1), o)); + } + } + continue; + + case _OP_CMP: + _GUARD(CMP_OP(this, (CmpOP)arg3, + STK(arg2),STK(arg1),TARGET)); + continue; + + case _OP_EXISTS: + TARGET = + Get(STK(arg1), STK(arg2), + temp_reg, true, DONT_FALL_BACK) + ? true : false; + continue; + + case _OP_INSTANCEOF: + if(type(STK(arg1)) != VX_OT_CLASS) + { + ThrowError( + "cannot apply instanceof between a %s and a %s", + GetTypeName(STK(arg1)), + GetTypeName(STK(arg2))); + VX_THROW(); + } + TARGET = + (type(STK(arg2)) == VX_OT_INSTANCE) ? + (_instance(STK(arg2))->InstanceOf(_class(STK(arg1))) + ? true : false) : false; + continue; + + case _OP_AND: + if(IsFalse(STK(arg2))) + { + TARGET = STK(arg2); + ci->_ip += (sarg1); + } + continue; + + case _OP_OR: + if(!IsFalse(STK(arg2))) + { + TARGET = STK(arg2); + ci->_ip += (sarg1); + } + continue; + + case _OP_NEG: + _GUARD(NEG_OP(this, TARGET,STK(arg1))); + continue; + + case _OP_NOT: + TARGET = IsFalse(STK(arg1)); + continue; + + case _OP_BWNOT: + if(type(STK(arg1)) == VX_OT_INTEGER) + { + VXInteger t = _integer(STK(arg1)); + TARGET = VXInteger(~t); + continue; + } + ThrowError( + "attempt to perform a bitwise op on a %s", + GetTypeName(STK(arg1))); + VX_THROW(); + + case _OP_CLOSURE: + { + VXForeignClosureObj *c = ci->_closure._unVal.pClosure; + VXFuncProtoObj *fp = c->_function; + if(!CLOSURE_OP(this, TARGET, + fp->_functions[arg1]._unVal.pFunctionProto)) + { + VX_THROW(); + } + continue; + } + case _OP_YIELD: + { + if(ci->_generator) + { + if(sarg1 != MAX_FUNC_STACKSIZE) + temp_reg = STK(arg1); + _GUARD(ci->_generator->Yield(this,arg2)); + traps -= ci->_etraps; + if(sarg1 != MAX_FUNC_STACKSIZE) + _Swap(STK(arg1),temp_reg); + } + else + { + ThrowError( + "trying to yield a '%s'," + "only genenerator can be yielded", + GetTypeName(ci->_generator)); + VX_THROW(); + } + if(Return(this, arg0, arg1, temp_reg)) + { + vox_assert(traps == 0); + outres = temp_reg; + return true; + } + + } + continue; + + case _OP_RESUME: + if(type(STK(arg1)) != VX_OT_GENERATOR) + { + ThrowError( + "trying to resume a '%s'," + " only a genenerator can be resumed", + GetTypeName(STK(arg1))); + VX_THROW(); + } + _GUARD(_generator(STK(arg1))->Resume(this, TARGET)); + traps += ci->_etraps; + continue; + + case _OP_FOREACH: + { + int tojump; + _GUARD(FOREACH_OP(this, STK(arg0),STK(arg2), + STK(arg2+1),STK(arg2+2),arg2, + sarg1,tojump)); + ci->_ip += tojump; + } + continue; + + case _OP_POSTFOREACH: + vox_assert(type(STK(arg0)) == VX_OT_GENERATOR); + if(_generator(STK(arg0))->_state == VXGeneratorObj::eDead) + ci->_ip += (sarg1 - 1); + continue; + + case _OP_CLONE: + _GUARD(Clone(STK(arg1), TARGET)); + continue; + + case _OP_TYPEOF: + _GUARD(TypeOf(STK(arg1), TARGET)); + continue; + + case _OP_PUSHTRAP: + { + VXInstruction *_iv = + _closure(ci->_closure)->_function->_instructions; + _etraps.push_back(VXExceptionTrap( + _top,_stackbase, + &_iv[(ci->_ip-_iv)+arg1], arg0)); + traps++; + ci->_etraps++; + } + continue; + + case _OP_POPTRAP: + { + for(VXInteger i=0; i_etraps--; + } + } + continue; + + case _OP_THROW: + ThrowError(TARGET); + VX_THROW(); + continue; + + case _OP_NEWSLOTA: + { + bool bstatic = + (arg0&NEW_SLVX_OT_STATIC_FLAG)?true:false; + if(type(STK(arg1)) == VX_OT_CLASS) + { + if(type(_class(STK(arg1))-> + _metamethods[VX_MT_NEWMEMBER]) != VX_OT_NULL) + { + Push(STK(arg1)); + Push(STK(arg2)); + Push(STK(arg3)); + Push((arg0&NEW_SLVX_OT_ATTRIBUTES_FLAG)? + STK(arg2-1) : VXObject()); + Push(bstatic); + int nparams = 5; + if(Call(_class(STK(arg1))-> + _metamethods[VX_MT_NEWMEMBER], + nparams, _top - nparams, + temp_reg,false)) + { + Pop(nparams); + continue; + } + else + { + VX_THROW(); + } + } + } + _GUARD(NewSlot(STK(arg1), STK(arg2), + STK(arg3),bstatic)); + if((arg0&NEW_SLVX_OT_ATTRIBUTES_FLAG)) + { + _class(STK(arg1))->SetAttributes( + STK(arg2), STK(arg2-1)); + } + } + continue; + + case _OP_GETBASE: + { + VXForeignClosureObj *clo = _closure(ci->_closure); + if(clo->_base) + { + TARGET = clo->_base; + } + else + { + TARGET.Null(); + } + continue; + } + + case _OP_CLOSE: + if(_openouters) + { + CloseOuters(this, &(STK(arg1))); + } + continue; + } + } + } + +exception_trap: + { + VXObject currerror = _lasterror; + VXInteger last_top = _top; + if(_ss(this)->_notifyallexceptions || (!traps && raiseerror)) + { + CallErrorHandler(currerror); + } + while(ci) + { + if(ci->_etraps > 0) + { + VXExceptionTrap &et = _etraps.top(); + ci->_ip = et._ip; + _top = et._stacksize; + _stackbase = et._stackbase; + _stack.values()[_stackbase + et._extarget] = currerror; + _etraps.pop_back(); traps--; ci->_etraps--; + while(last_top >= _top) + { + _stack.values()[last_top--].Null(); + } + goto exception_restore; + } + else if (_debughook) + { + //notify debugger of a "return" + //even if it really an exception unwinding the stack + for(VXInteger i=0; i<(ci->_ncalls); i++) + { + CallDebugHook('r'); + } + } + if(ci->_generator) + { + ci->_generator->Kill(); + } + bool mustbreak = ci && ci->_root; + LeaveFrame(); + if(mustbreak) + { + break; + } + } + _lasterror = currerror; + return false; + } + vox_assert(0); +} + +bool VXState::CreateClassInstance(VXClassObj *theclass, + VXObject &inst, + VXObject &constructor) +{ + inst = theclass->CreateInstance(); + if(!theclass->GetConstructor(constructor)) + { + constructor.Null(); + } + return true; +} + +void VXState::CallErrorHandler(VXObject &error) +{ + if(type(_errorhandler) != VX_OT_NULL) + { + VXObject out; + if(_errorhandler.Type() == VX_OT_NATIVECLOSURE) + { + _errorhandler.NativeClosure()->_nparamscheck = 2; + } + Push(_roottable); + Push(error); + if(!Call(_errorhandler, 2, _top-2, out, false)) + { + // the irony is killing me! + Irrecoverable_Error("failed to call errorhandler!"); + } + Pop(2); + } +} + + +void VXState::CallDebugHook(VXInteger type, + VXInteger forcedline) +{ + VXFuncProtoObj* func; + VXInteger line; + const char* src; + const char* fname; + _debughook = false; + func =_closure(ci->_closure)->_function; + if(_debughook_native) + { + src = type(func->_sourcename) == VX_OT_STRING ? + _stringval(func->_sourcename) : NULL; + fname = type(func->_name) == VX_OT_STRING ? + _stringval(func->_name) : NULL; + line = forcedline ? forcedline : func->GetLine(ci->_ip); + _debughook_native(this,type,src,line,fname); + } + else + { + VXObject temp_reg; + VXInteger nparams=5; + Push(_roottable); + Push(VXInteger(type)); + Push(func->_sourcename); + Push(VXInteger(forcedline?forcedline:func->GetLine(ci->_ip))); + Push(func->_name); + Call(_debughook_closure,nparams,_top-nparams,temp_reg,false); + Pop(nparams); + } + _debughook = true; +} + +bool VXState::CallNative(VXNativeClosureObj *nclosure, + VXInteger nargs, + VXInteger newbase, + VXObject &retval, + bool &suspend) +{ + VXInteger nparamscheck = nclosure->_nparamscheck; + VXInteger newtop = newbase + nargs + nclosure->_noutervalues; + if(_nnativecalls + 1 > MAX_NATIVE_CALLS) + { + ThrowError("native stack overflow"); + return false; + } + if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) || + ((nparamscheck < 0) && (nargs < (-nparamscheck))))) + { + return WrongNumberOfArguments(this, false, true, nclosure); + } + VXInteger tcs; + VXIntVec &tc = nclosure->_typecheck; + if((tcs = tc.size())) + { + for(VXInteger i = 0; i < nargs && i < tcs; i++) + { + if((tc.values()[i] != -1) && !(type(_stack.values()[newbase+i]) & tc.values()[i])) + { + Raise_ParamTypeError(i,tc.values()[i],type(_stack.values()[newbase+i])); + return false; + } + } + } + if(!EnterFrame(newbase, newtop, false)) + { + return false; + } + ci->_closure = nclosure; + VXInteger outers = nclosure->_noutervalues; + for (VXInteger i = 0; i < outers; i++) + { + _stack.values()[newbase+nargs+i] = nclosure->_outervalues[i]; + } + if(nclosure->_env) + { + _stack.values()[newbase] = nclosure->_env->_obj; + } + _nnativecalls++; + VXInteger ret = (nclosure->_function)(this); + _nnativecalls--; + suspend = false; + if (ret == VX_SUSPEND_FLAG) + { + suspend = true; + } + else if (ret < 0) + { + LeaveFrame(); + ThrowError(_lasterror); + return false; + } + if(ret) + { + retval = _stack.values()[_top-1]; + } + else + { + retval.Null(); + } + //retval = ret ? _stack.values()[_top-1] : _null_; + LeaveFrame(); + return true; +} + + + +bool VXState::Get(const VXObject &self, + const VXObject &key, + VXObject &dest, + bool raw, + VXInteger selfidx) +{ + switch(type(self)) + { + case VX_OT_TABLE: + if(_table(self)->Get(key,dest)) + { + return true; + } + break; + case VX_OT_ARRAY: + if(key.IsNumeric()) + { + if(_array(self)->Get(tointeger(key),dest)) + { + return true; + } + Raise_IdxError(key, self, true); + return false; + } + break; + case VX_OT_INSTANCE: + if(_instance(self)->Get(key,dest)) + { + return true; + } + break; + case VX_OT_CLASS: + if(_class(self)->Get(key,dest)) + { + return true; + } + break; + case VX_OT_STRING: + if(key.IsNumeric()) + { + VXInteger n = tointeger(key); + if(abs((int)n) < _string(self)->_len) + { + if(n < 0) + { + n = ((_string(self)->_len) - n); + } + dest = VXInteger(_stringval(self)[n]); + return true; + } + Raise_IdxError(key, self, true); + return false; + } + break; + default: + break; //shut up compiler + } + if(!raw) + { + switch(FallBackGet(self,key,dest)) + { + case FALLBACK_OK: + return true; //okie + case FALLBACK_NO_MATCH: + break; //keep falling back + case FALLBACK_ERROR: + return false; // the metamethod failed + } + if(InvokeDefaultDelegate(self,key,dest)) + { + return true; + } + } + if(selfidx == 0) + { + if(_table(_roottable)->Get(key,dest)) + { + return true; + } + } + Raise_IdxError(key, self); + return false; +} + +bool VXState::InvokeDefaultDelegate(const VXObject &self, + const VXObject &key, + VXObject &dest) +{ + VXTableObj *ddel = NULL; + switch(type(self)) + { + case VX_OT_CLASS: + ddel = _class_ddel; + break; + case VX_OT_TABLE: + ddel = _table_ddel; + break; + case VX_OT_ARRAY: + ddel = _array_ddel; + break; + case VX_OT_STRING: + ddel = _string_ddel; + break; + case VX_OT_INSTANCE: + ddel = _instance_ddel; + break; + case VX_OT_INTEGER: + case VX_OT_FLOAT: + case VX_OT_BOOL: + ddel = _number_ddel; + break; + case VX_OT_GENERATOR: + ddel = _generator_ddel; + break; + case VX_OT_CLOSURE: + case VX_OT_NATIVECLOSURE: + ddel = _closure_ddel; + break; + case VX_OT_THREAD: + ddel = _thread_ddel; + break; + case VX_OT_WEAKREF: + ddel = _weakref_ddel; + break; + default: + return false; + } + return ddel->Get(key,dest); +} + + +VXInteger VXState::FallBackGet(const VXObject &self, + const VXObject &key, + VXObject &dest) +{ + switch(type(self)) + { + case VX_OT_TABLE: + case VX_OT_USERDATA: + //delegation + if(_delegable(self)->_delegate) + { + if(Get(VXObject(_delegable(self)->_delegate), + key,dest,false,DONT_FALL_BACK)) + { + return FALLBACK_OK; + } + } + else + { + return FALLBACK_NO_MATCH; + } + //go through + case VX_OT_INSTANCE: + { + VXObject closure; + if(_delegable(self)->GetMetaMethod(this, VX_MT_GET, closure)) + { + Push(self); + Push(key); + _nmetamethodscall++; + AutoDec ad(&_nmetamethodscall); + if(Call(closure, 2, _top - 2, dest, false)) + { + Pop(2); + return FALLBACK_OK; + } + else + { + //NULL means "clean failure" (not found) + if(type(_lasterror) != VX_OT_NULL) + { + //error + Pop(2); + return FALLBACK_ERROR; + } + } + } + } + break; + default: + break;//shutup GCC 4.x + } + // no metamethod or no fallback type + return FALLBACK_NO_MATCH; +} + +bool VXState::Set(const VXObject &self, + const VXObject &key, + const VXObject &val, + VXInteger selfidx) +{ + switch(type(self)) + { + case VX_OT_TABLE: + if(_table(self)->Set(key,val)) + { + return true; + } + break; + case VX_OT_INSTANCE: + if(_instance(self)->Set(key,val)) + { + return true; + } + break; + case VX_OT_ARRAY: + if(!key.IsNumeric()) + { + ThrowError("cannot index %s with type %s", + GetTypeName(self), GetTypeName(key)); + return false; + } + if(!_array(self)->Set(tointeger(key), val)) + { + Raise_IdxError(key, self); + return false; + } + return true; + default: + ThrowError("type '%s' does not support index assignment", GetTypeName(self)); + return false; + } + switch(FallBackSet(self,key,val)) + { + case FALLBACK_OK: + return true; //okie + case FALLBACK_NO_MATCH: + break; //keep falling back + case FALLBACK_ERROR: + return false; // the metamethod failed + } + if(selfidx == 0) + { + if(_table(_roottable)->Set(key,val)) + { + return true; + } + } + Raise_IdxError(key, self); + return false; +} + +VXInteger VXState::FallBackSet(const VXObject &self, + const VXObject &key, + const VXObject &val) +{ + switch(type(self)) + { + case VX_OT_TABLE: + if(_table(self)->_delegate) + { + if(Set(_table(self)->_delegate,key,val,DONT_FALL_BACK)) + { + return FALLBACK_OK; + } + } + //keps on going + case VX_OT_INSTANCE: + case VX_OT_USERDATA: + { + VXObject closure; + VXObject t; + if(_delegable(self)->GetMetaMethod(this, VX_MT_SET, closure)) + { + Push(self); + Push(key); + Push(val); + _nmetamethodscall++; + AutoDec ad(&_nmetamethodscall); + if(Call(closure, 3, _top - 3, t, false)) + { + Pop(3); + return FALLBACK_OK; + } + else + { + //NULL means "clean failure" (not found) + if(type(_lasterror) != VX_OT_NULL) + { + //error + Pop(3); + return FALLBACK_ERROR; + } + } + } + } + break; + default: + break;//shutup GCC 4.x + } + // no metamethod or no fallback type + return FALLBACK_NO_MATCH; +} + +bool VXState::Clone(const VXObject& self, + VXObject &target) +{ + VXObject temp_reg; + VXObject newobj; + switch(type(self)) + { + case VX_OT_TABLE: + newobj = _table(self)->Clone(); + goto cloned_mt; + case VX_OT_INSTANCE: + { + newobj = _instance(self)->Clone(_ss(this)); +cloned_mt: + VXObject closure; + if(_delegable(newobj)->_delegate && + _delegable(newobj)->GetMetaMethod(this,VX_MT_CLONED,closure)) + { + Push(newobj); + Push(self); + if(!CallMetaMethod(this, closure,VX_MT_CLONED,2,temp_reg)) + { + return false; + } + } + } + target = newobj; + return true; + case VX_OT_ARRAY: + target = _array(self)->Clone(); + return true; + default: + ThrowError("cannot clone a '%s'", GetTypeName(self)); + return false; + } +} + +bool VXState::NewSlot(const VXObject &self, + const VXObject &key, + const VXObject &val, + bool bstatic) +{ + if(type(key) == VX_OT_NULL) + { + ThrowError("null cannot be used as index"); + return false; + } + switch(type(self)) + { + case VX_OT_TABLE: + { + bool rawcall = true; + if(_table(self)->_delegate) + { + VXObject res; + if(!_table(self)->Get(key,res)) + { + VXObject closure; + if(_delegable(self)->_delegate && + _delegable(self)->GetMetaMethod(this,VX_MT_NEWSLOT,closure)) + { + Push(self); + Push(key); + Push(val); + if(!CallMetaMethod(this, closure,VX_MT_NEWSLOT,3,res)) + { + return false; + } + rawcall = false; + } + else + { + rawcall = true; + } + } + } + if(rawcall) + { + _table(self)->NewSlot(key,val); //cannot fail + } + break; + } + case VX_OT_INSTANCE: + { + VXObject res; + VXObject closure; + if(_delegable(self)->_delegate && + _delegable(self)->GetMetaMethod(this, VX_MT_NEWSLOT, closure)) + { + Push(self); + Push(key); + Push(val); + if(!CallMetaMethod(this, closure, VX_MT_NEWSLOT, 3,res)) + { + return false; + } + break; + } + //ThrowError("class instances do not support the new slot operator"); + ThrowError("cannot create slots in class instances; use 'local' instead!"); + return false; + break; + } + case VX_OT_CLASS: + if(!_class(self)->NewSlot(Shared(), key, val, bstatic)) + { + if(_class(self)->_locked) + { + ThrowError("trying to modify a class that has already been instantiated"); + return false; + } + else + { + VXObject oval = PrintObjVal(key); + ThrowError("property '%s' already exists",_stringval(oval)); + return false; + } + } + break; + default: + ThrowError("indexing %s with %s", GetTypeName(self),GetTypeName(key)); + return false; + break; + } + return true; +} + + + +bool VXState::DeleteSlot(const VXObject &self, + const VXObject &key, + VXObject &res) +{ + switch(type(self)) + { + case VX_OT_TABLE: + case VX_OT_INSTANCE: + case VX_OT_USERDATA: + { + VXObject t; + //bool handled = false; + VXObject closure; + if(_delegable(self)->_delegate && + _delegable(self)->GetMetaMethod(this,VX_MT_DELSLOT,closure)) + { + Push(self); + Push(key); + return CallMetaMethod(this, closure,VX_MT_DELSLOT,2,res); + } + else + { + if(type(self) == VX_OT_TABLE) + { + if(_table(self)->Get(key,t)) + { + _table(self)->Remove(key); + } + else + { + Raise_IdxError((VXRawObj &)key, self); + return false; + } + } + else + { + ThrowError("cannot delete a slot from %s",GetTypeName(self)); + return false; + } + } + res = t; + } + break; + default: + ThrowError("attempt to delete a slot from a %s",GetTypeName(self)); + return false; + } + return true; +} + +bool VXState::Call(VXObject &closure, + VXInteger nparams, + VXInteger stackbase, + VXObject &outres, + bool raiseerror) +{ + switch(type(closure)) + { + case VX_OT_CLOSURE: + return Execute(closure, nparams, stackbase, outres, raiseerror); + break; + case VX_OT_NATIVECLOSURE: + { + bool suspend; + return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend); + } + break; + case VX_OT_CLASS: + { + VXObject constr; + VXObject temp; + CreateClassInstance(_class(closure),outres,constr); + if(type(constr) != VX_OT_NULL) + { + _stack[stackbase] = outres; + return Call(constr,nparams,stackbase,temp,raiseerror); + } + return true; + } + break; + default: + // populate LastError() with a meaningful message + ThrowError("Call(): not a closure (type: %s)", closure.TypeString()); + return false; + } + return true; +} + + +bool VXState::EnterFrame(VXInteger newbase, VXInteger newtop, bool tailcall) +{ + if( !tailcall ) + { + if( _callsstacksize == _alloccallsstacksize ) + { + GrowCallStack(); + } + ci = &_callsstack[_callsstacksize++]; + ci->_prevstkbase = (VXInt32)(newbase - _stackbase); + ci->_prevtop = (VXInt32)(_top - _stackbase); + ci->_etraps = 0; + ci->_ncalls = 1; + ci->_generator = NULL; + ci->_root = false; + } + else + { + ci->_ncalls++; + } + _stackbase = newbase; + _top = newtop; + if(newtop + MIN_STACK_OVERHEAD > (VXInteger)_stack.size()) + { + if(_nmetamethodscall) + { + ThrowError("stack overflow, cannot resize stack while in a metamethod"); + return false; + } + _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD << 2)); + RelocateOuters(this); + } + return true; +} + +void VXState::LeaveFrame() +{ + VXInteger last_top = _top; + VXInteger last_stackbase = _stackbase; + VXInteger css = --_callsstacksize; + /* First clean out the call stack frame */ + ci->_closure.Null(); + _stackbase -= ci->_prevstkbase; + _top = _stackbase + ci->_prevtop; + ci = (css) ? &_callsstack[css-1] : NULL; + if(_openouters) + { + CloseOuters(this, &(_stack.values()[last_stackbase])); + } + while (last_top >= _top) + { + _stack.values()[last_top--].Null(); + } +} + +void VXState::Remove(VXInteger n) +{ + n = (n >= 0)?n + _stackbase - 1:_top + n; + for(VXInteger i = n; i < _top; i++) + { + _stack[i] = _stack[i+1]; + } + _stack[_top].Null(); + _top--; +} + +void VXState::Pop() +{ + _stack[--_top].Null(); +} + +void VXState::Pop(VXInteger n) +{ + for(VXInteger i = 0; i < n; i++) + { + _stack[--_top].Null(); + } +} + +void VXState::PushNull() +{ + _stack[_top++].Null(); +} + +void VXState::Push(const VXObject &o) +{ + _stack[_top++] = o; +} + +VXObject& VXState::Top() +{ + return _stack[_top-1]; +} + +VXObject& VXState::PopGet() +{ + return _stack[--_top]; +} + +VXObject& VXState::GetUp(VXInteger n) +{ + return _stack[_top+n]; +} + +VXObject& VXState::GetAt(VXInteger n) +{ + return _stack[n]; +} diff --git a/src/core/vm.hpp b/src/core/vm.hpp new file mode 100644 index 0000000..abbcb0e --- /dev/null +++ b/src/core/vm.hpp @@ -0,0 +1,62 @@ + +#ifndef _VXState_H_ +#define _VXState_H_ + +#include "opcodes.hpp" +#include "closure.hpp" +#include "funcproto.hpp" +#include "object.hpp" + +#define MAX_NATIVE_CALLS 100 +#define MIN_STACK_OVERHEAD 15 + +#define VX_SUSPEND_FLAG -666 +#define DONT_FALL_BACK 666 + +#define _INLINE + +#define STK(a) _stack.values()[_stackbase+(a)] +#define TARGET _stack.values()[_stackbase+arg0] + + + +#define PUSH_CALLINFO(v,nci) \ + { \ + VXInteger css = v->_callsstacksize; \ + if(css == v->_alloccallsstacksize) \ + { \ + v->GrowCallStack(); \ + } \ + v->ci = &v->_callsstack[css]; \ + *(v->ci) = nci; \ + v->_callsstacksize++; \ + } + +#define POP_CALLINFO(v) \ + { \ + VXInteger css = --v->_callsstacksize; \ + v->ci->_closure.Null(); \ + v->ci = css?&v->_callsstack[css-1]:NULL; \ + } + +struct AutoDec +{ + VXInteger *_n; + AutoDec(VXInteger *n) + { + _n = n; + } + ~AutoDec() + { + (*_n)--; + } +}; + + +inline VXObject &stack_get(VXState* v,VXInteger idx) +{ + return v->StackGet(idx); +} + + +#endif //_VXState_H_ diff --git a/src/frontend/CMakeLists.txt b/src/frontend/CMakeLists.txt new file mode 100644 index 0000000..bf6d902 --- /dev/null +++ b/src/frontend/CMakeLists.txt @@ -0,0 +1,26 @@ + +SET(vox_exelibs + ${vox_corelib} +) + +SET(vox_exe_sourcefiles + "frontend.cpp" + "optget.cpp" +) + +IF(BUILD_STDLIB) + SET(vox_exelibs + ${vox_exelibs} + ${vox_stdlib}) +ENDIF(BUILD_STDLIB) + +ADD_EXECUTABLE(${vox_exe} ${vox_exe_sourcefiles}) +SET_TARGET_PROPERTIES(${vox_exe} + PROPERTIES + BUILD_WITH_INSTALL_RPATH TRUE + INSTALL_RPATH_USE_LINK_PATH TRUE + INSTALL_RPATH "${vox_rpath_paths}" + OUTPUT_NAME "${vox_exe_name}" +) +TARGET_LINK_LIBRARIES(${vox_exe} ${vox_exelibs} ${vox_coredeps}) +INSTALL(TARGETS ${vox_exe} DESTINATION bin) diff --git a/src/frontend/frontend.cpp b/src/frontend/frontend.cpp new file mode 100644 index 0000000..1b2fccb --- /dev/null +++ b/src/frontend/frontend.cpp @@ -0,0 +1,537 @@ + +#include +#include +#include +#include +#include +#include +#include +#include "optget.h" +#include "vox.h" + +#define MAXINPUT 1024 + + +#define USERCFG_FILE "voxrc.vx" +#define USERCFG_ENV_OVERRIDE "VOXRCPATH" +#if defined(VOX_PLATFORM_MSWINDOWS) +# define USERCFG_ENV_USERHOME "APPDATA" +# define DELIM '\\' +#else +# define USERCFG_ENV_USERHOME "HOME" +# define DELIM '/' +#endif + + +enum { + ST_OK = 0, + ST_ERR = 1 +}; + +static const char* vxf_def_inputprefix = ">> "; +static const char* vxf_def_compiledoutput = "out.vxc"; +static int vxf_def_stacksize = 1024; + + + +bool get_usercfg_path(std::string& dest) +{ + const char* env_value; + std::stringstream fullpath; + /* first, check whether the override var is defined ... */ + if((env_value = getenv(USERCFG_ENV_OVERRIDE)) != NULL) + { + dest = env_value; + return true; + } + /* technically unlikely to happen, but let's check anyway ... */ + if((env_value = getenv(USERCFG_ENV_USERHOME)) == NULL) + { + return false; + } + fullpath << env_value << DELIM; +#if !defined(VOX_PLATFORM_MSWINDOWS) && defined(VOX_PLATFORM_UNIX) + /*note: on Linux and UNIX, go with the freedesktop.org standard of + putting configuration files into $HOME/.config/ */ + fullpath << ".config" << DELIM; +#endif + fullpath << USERCFG_FILE; + dest = fullpath.str(); + return true; +} + +bool check_file(const std::string& path) +{ + /* just check whether the file exists (using stat), nothing more */ + struct stat sbuf; + return stat(path.c_str(), &sbuf) == 0; +} + +void load_stdlib(VXState* v) +{ +#if VOX_STDLIB_AVAILABLE + voxstd_register_oslib(v); + voxstd_register_regexlib(v); + voxstd_register_importlib(v); + voxstd_register_hashlib(v); +#else + (void)v; +#endif +} + +class VXFrontend { + private: + // our VM + VXState* vm; + + // status code to be returned in main() + int exitstatus; + + // arguments passed to this program + VXVector args; + + // argument count + int argc; + + // argument vector + char** argv; + + // name of this program + const char* program; + + // path to the script passed to this program + std::string scriptfile; + + // contains the script supplied by '-e' + std::string scriptline; + + // optget instance + optget_t opt; + + // is true when we have at least one positional argument + bool havefile; + + // is true when '-e' is being used + bool is_scriptline; + + // is set to true by the '-c' flag + bool opt_compileonly; + + // is set to true by the '-d' flag + bool opt_debuginfo; + + // is set to true by the '-n' flag + bool opt_ignoreuserconf; + + // is modified by the '-s' flag + int opt_stacksize; + + // is modified by the '-o' flag + std::string opt_compiledoutput; + + public: + VXFrontend(int _argc, char** _argv): + argc(_argc), argv(_argv) + { + int i; + exitstatus = ST_OK; + program = argv[0]; + havefile = false; + is_scriptline = false; + opt_compiledoutput = vxf_def_compiledoutput; + opt_compileonly = false; + opt_debuginfo = false; + opt_ignoreuserconf = false; + opt_stacksize = vxf_def_stacksize; + optget_init(&opt, argc, argv, NULL); + parse_args(); + if(opt.ind < argc) + { + scriptfile = argv[opt.ind]; + havefile = true; + for(i=opt.ind; iLastError(); + } + + void populate_argv() + { + size_t i; + std::string arg; + for(i=0; iGetSysArgv()->Append(vm->NewString(arg.c_str(), arg.length())); + } + } + + void exec_userconf() + { + std::string usercfg_path; + if(get_usercfg_path(usercfg_path)) + { + if(check_file(usercfg_path)) + { + vm->DoFile(usercfg_path.c_str(), true, true); + } + } + } + + bool check_stacksize() + { + if(opt_stacksize < 1) + { + return false; + } + return true; + } + + void check_vm() + { + if(vm == NULL) + { + fprintf(stderr, "Failed to create the virtualmachine!\n"); + exit(ST_ERR); + } + } + + void start_vm() + { + if(!check_stacksize()) + { + fprintf(stderr, "Stacksize too small to start the VM!\n"); + exitstatus = ST_ERR; + exit(exitstatus); + } + vm = VXState::Create(opt_stacksize); + check_vm(); + if(opt_debuginfo) + { + vm->EnableDebugInfo(true); + } + vm->SetErrorHandlers(); + vm->PushRoot(); + load_stdlib(vm); + populate_argv(); + } + + void stop_vm() + { + vm->PopRoot(); + VXState::Destroy(vm); + } + + void run_file() + { + const char* err; + bool failed_to_open; + if(VX_FAILED(vm->DoFile(scriptfile.c_str(), false, true, &failed_to_open))) + { + get_err(&err); + exitstatus = ST_ERR; + if(failed_to_open) + { + fprintf(stderr, "Could not open '%s': %s\n", scriptfile.c_str(), err); + } + } + } + + void run_string() + { + const char* err; + if(VX_FAILED(vm->DoString(scriptline.c_str(), + scriptline.length(), + NULL, false, true))) + { + get_err(&err); + exitstatus = ST_ERR; + } + } + + void compile_file() + { + const char* err; + if(VX_SUCCEEDED(vm->LoadFile(scriptfile.c_str(), true))) + { + if(VX_FAILED(vm->WriteClosureToFile(opt_compiledoutput.c_str()))) + { + get_err(&err); + exitstatus = ST_ERR; + fprintf(stderr, "Compiling failed: %s\n", err); + } + } + } + + void handle_rest() + { + start_vm(); + if(!opt_ignoreuserconf) + { + exec_userconf(); + } + if(is_scriptline) + { + run_string(); + } + else if(havefile) + { + if(opt_compileonly) + { + compile_file(); + } + else + { + run_file(); + } + } + else + { + enter_interactive(); + } + stop_vm(); + } + + void interactive_showbanner() + { + //VXInt32 bits = sizeof(VXInteger)*8; + fprintf(stdout, "%s %s (%s)\n", + VOX_VERSION, VOX_COPYRIGHT, VOX_PLATFORM_NAME); + fprintf(stdout, "To view the license, type 'license()'\n"); + fprintf(stdout, "To exit, type CTRL+C or CTRL+D\n\n"); + fflush(stdout); + } + + void enter_interactive() + { + char buffer[MAXINPUT]; + char* tmpbuf = NULL; + bool retval = false; + VXInteger blocks = 0; + VXInteger isstring = 0; + VXInteger done = 0; + VXInteger cstatus; + interactive_showbanner(); + while (!done) + { + VXInteger i = 0; + printf("%s", vxf_def_inputprefix); + fflush(stdout); + while(true) + { + int c; + if(done) + { + return; + } + c = getchar(); + if(c == EOF) + { + fprintf(stderr, "\nBye\n"); + return; + } + else + { + if (c == '\n') + { + if (i>0 && buffer[i-1] == '\\') + { + buffer[i-1] = '\n'; + } + else if(blocks == 0) + { + break; + } + buffer[i++] = '\n'; + } + else if (c == '}') + { + blocks--; + buffer[i++] = (char)c; + } + else if(c == '{' && !isstring) + { + blocks++; + buffer[i++] = (char)c; + } + else if(c == '"' || c == '\'') + { + isstring = !isstring; + buffer[i++] = (char)c; + } + else if (i >= (MAXINPUT-1)) + { + fprintf(stderr, " input line too long\n"); + exit(-1); + break; + } + else + { + buffer[i++] = (char)c; + } + } + } + buffer[i] = '\0'; + /* allocate tmpbuf, and copy the contents of the buffer chunk, so + we can restore it later, if return() failed to compile */ + tmpbuf = new char[MAXINPUT]; + memset(tmpbuf, 0, MAXINPUT); + memcpy(tmpbuf, buffer, strlen(buffer)); + /* create a code chunk that returns the expression - assuming + that the expression can be returned in the first place. + that is, the chunk '1 + 1' becomes 'return (1 + 1)', etc. + If it fails, the original chunk gets restored */ + sprintf(vm->ScratchPad(MAXINPUT), "return (%s)", &buffer[0]); + memcpy(buffer, vm->ScratchPad(-1), strlen(vm->ScratchPad(-1)) + 1); + /* here's where the previously defined chunk gets compiled, to + see whether it's valid syntax */ + if(VX_SUCCEEDED(vm->CompileBuffer(buffer, strlen(buffer), "", false))) + { + retval = true; + i = strlen(buffer); + vm->Pop(); + } + else + { + /* at this point, returning the value did not work, + due to syntax errors (it didn't even compile, so no reason + to investigate any further). + so restore the old buffer, by copying from tmpbuf */ + memcpy(buffer, tmpbuf, strlen(tmpbuf) + 1); + i = strlen(tmpbuf); + } + delete[] tmpbuf; + if(i > 0) + { + VXInteger oldtop = vm->GetTop(); + cstatus = vm->CompileBuffer(buffer, i, "", true); + if(VX_SUCCEEDED(cstatus)) + { + vm->PushRoot(); + if(VX_SUCCEEDED(vm->CallStack(1, true, true)) && retval) + { +#if defined(VOX_INTER_NO_SERIALIZE) + /* without serialization, simply ToString()'ify the + value, and print to stdout. */ + VXObject val; + vm->ToString(vm->StackGet(-1), val); + VXInteger str_len; + const char* str_val; + val.String()->Get(&str_val, &str_len); + fprintf(stdout, "%.*s\n", str_len, str_val); +#else + /* using serialization, the data becomes more readable, but + might also be a little slower (not tragically, though!) */ + VXRepr ser(vm, vm->StackGet(-1)); + const std::string& data = ser.str(); + fprintf(stdout, "%.*s\n", VXInt32(data.length()), data.c_str()); +#endif + fflush(stdout); + retval = false; + } + } + vm->SetTop(oldtop); + } + } + } + + void print_version() + { + printf("%s\n", VOX_VERSION); + exit(ST_OK); + } + + void print_help() + { + printf( + "Usage: %s [] [ []]\n" + "Available options:\n" + " -c compiles the file to bytecode (default output: '%s')\n" + " -o specifies output file for the -c option to \n" + " -d enable debug information\n" + " -s sets initial stacksize to (default: %d)\n" + " -e evaluates \n" + " -v displays version\n" + " -n ignore user configuration, even if $VOXRCPATH is defined\n" + " -h prints help\n", + program, vxf_def_compiledoutput, vxf_def_stacksize); + exit(ST_OK); + } + + void parse_args() + { + int c; + while ((c = optget_short(&opt, "hvndco:s:e:")) != -1) + { + switch (c) + { + case 'h': + print_help(); + return; + case 'v': + print_version(); + return; + case 'd': + opt_debuginfo = true; + break; + case 'c': + opt_compileonly = true; + break; + case 'n': + opt_ignoreuserconf = true; + break; + case 'o': + opt_compiledoutput = opt.arg; + break; + case 's': + opt_stacksize = atoi(opt.arg); + break; + case 'e': + is_scriptline = true; + scriptline = opt.arg; + break; + case '?': + if(opt.opt == 'o' || opt.opt == 's' || opt.opt == 'e') + { + fprintf(stderr, + "%s: option -%c requires an argument\n", + argv[0], opt.opt); + } + else if(isprint(opt.opt)) + { + fprintf(stderr, + "%s: unknown option `-%c'\n", + argv[0], opt.opt); + } + else + { + fprintf(stderr, + "%s: unknown option character `\\x%x'\n", + argv[0], opt.opt); + } + exit(1); + default: + abort(); + } + } + } + + int exit_status() + { + return exitstatus; + } +}; + +int main(int argc, char* argv[]) +{ + VXFrontend vxf(argc, argv); + return vxf.exit_status(); +} + diff --git a/src/frontend/optget.cpp b/src/frontend/optget.cpp new file mode 100644 index 0000000..027cb8a --- /dev/null +++ b/src/frontend/optget.cpp @@ -0,0 +1,293 @@ + +#include +#include +#include "optget.h" + +int optget_reset; + +static char optget_emsg[] = ""; + +const char* optget_strchr(const char* dataptr, int search) +{ + char found; + if(search == 0) + { + while(*dataptr++); + return (dataptr - 1); + } + while((found = *dataptr++)) + { + if(found == search) + { + return (dataptr - 1); + } + } + return 0; +} + +void optget_tell(int err, char** nargv, char opt, const char* str) +{ + (void)opt; + if(err) + { + fputs(nargv[0], stderr); + fputs(str, stderr); + fputc('\n', stderr); + } +} + +void optget_init(optget_t* gto, + int nargc, + char** nargv, + optget_errfunc_t errfunc) +{ + gto->err = 1; + gto->ind = 1; + gto->arg = NULL; + gto->nargc = nargc; + gto->nargv = nargv; + gto->errfunc = (errfunc ? errfunc : optget_tell); +} + +int optget_short(optget_t* gto, const char* ostr) +{ + const char* oli; + static char* place = optget_emsg; + if (!*place) + { + if((gto->ind >= gto->nargc) || + (*(place = gto->nargv[gto->ind]) != '-') || + (!*++place)) + { + return EOF; + } + /* found "--" */ + if (*place == '-') + { + (gto->ind)++; + return EOF; + } + } + /* option letter okay? */ + if (((gto->opt = *place++) == ':') || + ((oli = optget_strchr(ostr, gto->opt)) == NULL)) + { + if (!*place) + { + gto->ind++; + } + gto->errfunc(gto->err, gto->nargv, gto->opt, ": illegal option -- "); + goto __optget_Bad; + } + /* don't need argument */ + if (*++oli != ':') + { + gto->arg = NULL; + if (!*place) + { + (gto->ind)++; + } + } + /* need an argument */ + else + { + if (*place) + { + /* no white space */ + gto->arg = place; + } + else + { + if (gto->nargc <= ++(gto->ind)) + { + place = optget_emsg; + gto->errfunc(gto->err, gto->nargv, gto->opt, + ": option requires an argument -- "); + goto __optget_Bad; + } + else + { + /* white space */ + gto->arg = gto->nargv[gto->ind]; + } + } + place = optget_emsg; + (gto->ind)++; + } + /* dump back option letter */ + return gto->opt; + + __optget_Bad: + return OPTGET_BADCH; +} + + + + +int optget_long(optget_t* opt, + const char* optstring, + optget_option_t* longopts, + int* longindex) + +{ + static char* place = optget_emsg; + char* oli; + unsigned int namelen; + int i; + if (optget_reset || !*place) + { + optget_reset = 0; + if (opt->ind >= opt->nargc) + { + place = optget_emsg; + return -1; + } + place = opt->nargv[opt->ind]; + if (place[0] != '-') + { + place = optget_emsg; + return -1; + } + place++; + if (place[0] && place[0] == '-' && place[1] == '\0') + { + ++(opt->ind); + place = optget_emsg; + return -1; + } + if (place[0] && place[0] == '-' && place[1]) + { + /* long option */ + place++; + namelen = strcspn(place, "="); + for (i = 0; longopts[i].name != NULL; i++) + { + if (strlen(longopts[i].name) == namelen + && strncmp(place, longopts[i].name, namelen) == 0) + { + if (longopts[i].has_arg) + { + if (place[namelen] == '=') + { + opt->arg = place + namelen + 1; + } + else if (opt->ind < (opt->nargc - 1)) + { + opt->ind++; + opt->arg = opt->nargv[opt->ind]; + } + else + { + if (optstring[0] == ':') + { + return OPTGET_BADARG; + } + if (opt->err) + { + char errbuf[50]; + sprintf(errbuf, + ": option '--%s' required an argument", + place); + opt->errfunc(opt->err, opt->nargv, opt->opt, errbuf); + } + place = optget_emsg; + opt->ind++; + return OPTGET_BADCH; + } + } + else + { + opt->arg = NULL; + if (place[namelen] != 0) + { + /* XXX error? */ + } + } + opt->ind++; + if (longindex) + { + *longindex = i; + } + place = optget_emsg; + if (longopts[i].flag == NULL) + { + return longopts[i].val; + } + else + { + *longopts[i].flag = longopts[i].val; + return 0; + } + } + } + if (opt->err && optstring[0] != ':') + { + char errbuf[50]; + sprintf(errbuf, ": illegal option '%s'", place); + opt->errfunc(opt->err, opt->nargv, opt->opt, errbuf); + } + place = optget_emsg; + opt->ind++; + return OPTGET_BADCH; + } + } + /* short option */ + opt->opt = (int)*place++; + oli = strchr((char*)optstring, opt->opt); + if (!oli) + { + if (!*place) + { + ++opt->ind; + } + if (opt->err && *optstring != ':') + { + char errbuf[50]; + sprintf(errbuf, ": illegal option -- %c", opt->opt); + opt->errfunc(opt->err, opt->nargv, opt->opt, errbuf); + } + return OPTGET_BADCH; + } + + if (oli[1] != ':') + { + opt->arg = NULL; + if (!*place) + { + ++opt->ind; + } + } + else + { + if (*place) + { + opt->arg = place; + } + else if (opt->nargc <= (++opt->ind)) + { + place = optget_emsg; + if (*optstring == ':') + { + return OPTGET_BADARG; + } + if (opt->err) + { + char errbuf[50]; + sprintf(errbuf, ": option '-%c' requires an argument", + opt->opt); + opt->errfunc(opt->err, opt->nargv, opt->opt, errbuf); + } + return OPTGET_BADCH; + } + else + { + opt->arg = opt->nargv[opt->ind]; + } + place = optget_emsg; + ++opt->ind; + } + return opt->opt; +} + + +static const int i=0; diff --git a/src/frontend/optget.h b/src/frontend/optget.h new file mode 100644 index 0000000..a14db52 --- /dev/null +++ b/src/frontend/optget.h @@ -0,0 +1,113 @@ + +/* +* optget.h & optget.c +* +* a commandline parser based on the public domain getopt.c file +* (original: ftp://ftp.es.ele.tue.nl/pub/users/jos/poster/getopt.c) +* --------- +* +* The usage of optget differs from getopt in a few ways; +* However, these differences serve the portability, and +* code-cleanliness, so previous users of getopt should +* feel right at home with the API. +* +* Minimalistic Example: + + int main(int argc, char** argv) + { + optget_t opt; + const char* outfile; + int verbose; + int c; + optget_init(&opt, argc, argv, NULL); + while((c = optget_main(&opt, "vc:")) != -1) + { + case 'v': + verbose = 1; + break; + case 'o': + outfile = opt.arg; + break; + case '?': + if (opt.opt == 'o') + { + fprintf(stderr, "Option -%c requires an argument.\n", opt.opt); + } + else if (isprint(opt.opt)) + { + fprintf(stderr, "Unknown option `-%c'.\n", opt.opt); + } + return 1; + } + } + +* +*/ + +#ifndef __PD_OPTGET_PUBLIC_HEADER_H__ +#define __PD_OPTGET_PUBLIC_HEADER_H__ + +#define OPTGET_BADCH '?' +#define OPTGET_BADARG ':' +#define OPTGET_EMSG "" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef void(*optget_errfunc_t)(int,char**,char,const char*); + +typedef struct __optget_t { + /* undocumented error-suppressor */ + int err; + + /* index into argv vector */ + int ind; + + /* char checked for validity */ + int opt; + + /* arg associated with option */ + char* arg; + + /* argc */ + int nargc; + + /* argv*/ + char** nargv; + + /* errfunc */ + optget_errfunc_t errfunc; + +} optget_t; + + +/* {"add", 1, 0, 0}, */ +typedef struct optget_option_t +{ + const char *name; + int has_arg; + int* flag; + int val; +} optget_option_t; + + +void optget_init(optget_t* gto, + int nargc, + char** nargv, + optget_errfunc_t errfunc); + +int optget_short(optget_t* gto, + const char* ostr); + + +int optget_long(optget_t* opt, + const char* optstring, + optget_option_t* longopts, + int* longindex); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* __PD_OPTGET_PUBLIC_HEADER_H__ */ diff --git a/src/stdlib/CMakeLists.txt b/src/stdlib/CMakeLists.txt new file mode 100644 index 0000000..032e183 --- /dev/null +++ b/src/stdlib/CMakeLists.txt @@ -0,0 +1,43 @@ + +SET(vox_stdlib_sourcefiles + "loadlib.cpp" + ## 3rdparty yatta yatta + "sharedlib.c" + +) + +IF(Boost_FOUND) + MESSAGE(STATUS "Found boost, 'std.os', 'std.re' and 'import' will be supported!") + SET(vox_stdlib_sourcefiles + ${vox_stdlib_sourcefiles} + "oslib.cpp" + "regexp.cpp" + "importlib.cpp" + ) +ENDIF() + +INCLUDE_DIRECTORIES("extra-include") + +IF(BUILD_SHAREDLIBS) + ADD_LIBRARY(${vox_stdlib} SHARED ${vox_stdlib_sourcefiles}) + TARGET_LINK_LIBRARIES(${vox_stdlib} ${vox_corelib}) + SET_TARGET_PROPERTIES(${vox_stdlib} + PROPERTIES + BUILD_WITH_INSTALL_RPATH TRUE + INSTALL_RPATH_USE_LINK_PATH TRUE + INSTALL_RPATH "${vox_rpath_paths}" + ) + IF(WIN32) + SET_TARGET_PROPERTIES(${vox_stdlib} + PROPERTIES + PREFIX "" + ) + ENDIF(WIN32) +ELSE(BUILD_SHAREDLIBS) + ADD_LIBRARY(${vox_stdlib} STATIC ${vox_stdlib_sourcefiles}) +ENDIF(BUILD_SHAREDLIBS) +SET_TARGET_PROPERTIES(${vox_stdlib} + PROPERTIES + OUTPUT_NAME "${vox_stdlib_name}" +) +INSTALL(TARGETS ${vox_stdlib} DESTINATION lib) diff --git a/src/stdlib/helper.hpp b/src/stdlib/helper.hpp new file mode 100644 index 0000000..de4fff6 --- /dev/null +++ b/src/stdlib/helper.hpp @@ -0,0 +1,39 @@ + +#ifndef __vox_stdlib_helper_hpp +#define __vox_stdlib_helper_hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vox.h" + +#if defined(VOX_PLATFORM_UNIX) +# include +# include +#endif + +#if defined(VOX_PLATFORM_MSWINDOWS) +# include +# include +#endif + +template +ReturnT forcecast(InputT what) +{ + return *((ReturnT*)&what); +} + +void oslib_register_libload(VXState* v, VXTableObj* top); + +#endif /* __vox_stdlib_helper_hpp */ + diff --git a/src/stdlib/importlib.cpp b/src/stdlib/importlib.cpp new file mode 100644 index 0000000..a4009e3 --- /dev/null +++ b/src/stdlib/importlib.cpp @@ -0,0 +1,315 @@ + +#include +#include +#include +#include +#include "helper.hpp" +#include "vxlibrary.hpp" + +#define IMPORTHOOK_NAME "importhook" + + +#define IMPORT_GET_SELF(__vm__, __var__) \ + VXObject o; \ + if(!__vm__->GetRegistryTable()->Get(v->NewString(IMPORTHOOK_NAME), o)) \ + { \ + return v->ThrowError("importhook wasn't installed correctly!"); \ + } \ + __var__ = (VXImportHook*)o.UserPointer(); + +namespace fslib = boost::filesystem; +typedef fslib::filesystem_error fslib_error; + + +//DSO_EXT = kernel.getproperty("DSO_EXT") +//const char* DSO_EXT = "." VOX_PLATFORM_NAME ".vxd"; +const char* DSO_EXT = ".vxd"; +//VOX_EXT = kernel.getproperty("VOX_EXT") +const char* VOX_EXT = ".vx"; + +const char* VOX_PLUGIN_FUNCTION_OPEN = "vox_module_open"; + +void get_err(VXState* v, const char** err) +{ + /* + vox_pushlasterror(v); + if(VX_FAILED(vox_getstring(v, -1, err, NULL))) + { + *err = ""; + } + */ + (*err) = v->LastError(); +} + + +struct VXImportError +{ + std::string path; + std::string message; + bool is_dll; + bool dll_failed_to_load; +}; + +struct VXLibWrap +{ + VXSharedLibrary handle; +}; + +struct VXImportHook +{ + VXState* v; + VXVector searchpaths; + VXVector errvalues; + bool foundmodule; + VXInteger status; + + void fill_searchpaths() + { + const char* env = getenv("VOX_PATH"); + if(env != NULL) + { + searchpaths.push_back(env); + } + searchpaths.push_back("./"); + // add installdir before srcdir, so it has higher priority +#if defined(VOX_MODULEPATH_INSTALLDIR) + searchpaths.push_back(VOX_MODULEPATH_INSTALLDIR); +#endif +#if defined(VOX_MODULEPATH_SRCDIR) + searchpaths.push_back(VOX_MODULEPATH_SRCDIR); +#endif + } + + VXImportHook(VXState* _v): v(_v) + { + fill_searchpaths(); + } + + void pusherror(const std::string& path, + const std::string& message, + bool is_dll = false, + bool dll_failed_to_load = false) + { + VXImportError err; + err.path = path; + err.message = message; + err.is_dll = is_dll; + err.dll_failed_to_load = dll_failed_to_load; + errvalues.push_back(err); + } + + void do_import(const std::string& expr) + { + int i; + char dir_sep = '/'; + char dot = '.'; + std::string relpath; + std::string abspath; + std::string searchpath; + VXImportError pair; + this->status = 1; + this->foundmodule = false; + for(i=0; icheckmodule(abspath); + if(foundmodule == true) + { + return; + } + } + if(foundmodule == false) + { + // create a little errormessage, explaining what went wrong, + // and what files we have searched + // yes, the errormessage is inspired by Lua + std::string msg; + msg = "import: Module '"+expr+"' not found:\n"; + for(i=0; iThrowError(msg.c_str()); + } + } + + + void checkmodule(const std::string& abspath) + { + std::string dso_path; + std::string vox_path; + std::string err; + dso_path = abspath + DSO_EXT; + vox_path = abspath + VOX_EXT; + this->check_voxfile(vox_path); + // only continue searching DSO files when + // no voxfile could be found, to + // prevent race conditions + if(!foundmodule) + { + this->check_dsofile(dso_path); + } + } + + void check_voxfile(const std::string& path) + { + bool retval = true; + bool ofail; + const char* err; + std::string ret_err; + VXObject closure; + if(VX_SUCCEEDED(v->LoadFile(path.c_str(), true, &ofail, &closure))) + { + v->PushRoot(); + if(VX_SUCCEEDED(v->CallSimple(closure, 1, retval, true))) + { + foundmodule = true; + return; + } + else + { + get_err(v, &err); + ret_err = err; + pusherror(path, ret_err); + v->Pop(1); + return; + } + } + else + { + get_err(v, &err); + ret_err = err; + pusherror(path, ret_err); + return; + } + } + + void check_dsofile(const std::string& path) + { + VXFunction func; + VXLibWrap lib; + try + { + lib.handle.open(path); + func = lib.handle.resolve(VOX_PLUGIN_FUNCTION_OPEN); + func(v); + foundmodule = true; + return; + } + catch(VXSharedLibrary::LoadError& err) + { + lib.handle.close(); + pusherror(path, err.what(), true, true); + } + catch(std::runtime_error& err) + { + lib.handle.destroy(); + pusherror(path, err.what(), true, true); + } + } + + VXInteger finalize() + { + this->errvalues.clear(); + return this->status; + } +}; + + + +VXInteger importreg_release(VXState* v) +{ + VXImportHook* self; + IMPORT_GET_SELF(v, self) + delete self; + return 1; +} + + +VXInteger importlib_import(VXState* v) +{ + std::string expr; + VXImportHook* self; + IMPORT_GET_SELF(v, self) + v->GetString(2, &expr); + self->do_import(expr); + return self->finalize(); +} + +VXInteger package_searchpaths(VXState* v) +{ + std::string path; + VXInteger i; + VXImportHook* self; + IMPORT_GET_SELF(v, self) + VXArrayObj* arr = v->NewArray(); + for(i=0; isearchpaths.size(); i++) + { + path = self->searchpaths.at(i); + arr->Append(v->NewString(path.c_str(), path.length())); + } + v->Push(arr); + return 1; +} + +VXInteger package_addpath(VXState* v) +{ + std::string path; + VXImportHook* self; + IMPORT_GET_SELF(v, self) + v->GetString(2, &path); + self->searchpaths.push_back(path); + return VX_OK; +} + +static VXRegFunction package_funcs[] = +{ + {"searchpaths", package_searchpaths, 1, NULL}, + {"addpath", package_addpath, 2, ".s"}, + {0, 0, 0, 0}, +}; + +static VXRegFunction importlib_funcs[]= +{ + {"import", importlib_import, 2, ".s"}, + {0, 0, 0, 0} +}; + + +VXInteger voxstd_register_importlib(VXState* v) +{ + VXImportHook* self = new VXImportHook(v); + v->GetRegistryTable()->NewSlot(v->NewString(IMPORTHOOK_NAME), (VXUserPointer)self); + //vox_pushatexitfunc_native(v, importreg_release); + v->AtExit(v->NewClosure(importreg_release, 0)); + //vox_registerlib(v, "package", package_funcs, true, true); + v->RegisterLib("package", package_funcs, true); + //vox_registerlib(v, NULL, importlib_funcs, true, true); + v->RegisterLib(NULL, importlib_funcs, true); + return 0; +} diff --git a/src/stdlib/loadlib.cpp b/src/stdlib/loadlib.cpp new file mode 100644 index 0000000..b26a4c5 --- /dev/null +++ b/src/stdlib/loadlib.cpp @@ -0,0 +1,90 @@ + +#include "helper.hpp" + +#ifndef VX_NO_LOADLIB +#include "vxlibrary.hpp" + +VXInteger oslib_loadlib_releasehook(VXUserPointer p, VXInteger size) +{ + (void)size; + VXSharedLibrary* self = (VXSharedLibrary*)p; + delete self; + return 1; +} + +VXInteger oslib_loadlib_constructor(VXState* v) +{ + VXInteger ret = 0; + const char* path; + VXSharedLibrary* self = NULL; + v->GetString(2, &path, NULL); + try + { + self = new VXSharedLibrary(path); + } + catch(VXSharedLibrary::LoadError& err) + { + ret = v->ThrowError(err.what()); + } + v->SetInstanceUp(1, (VXUserPointer*)&self); + v->SetReleaseHook(1, oslib_loadlib_releasehook); + return ret; +} + +VXInteger oslib_loadlib_resolve(VXState* v) +{ + const char* symname; + char* errbuf; + VXFunction func; + VXSharedLibrary* self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + v->GetString(2, &symname, NULL); + try + { + func = self->resolve(symname); + v->Push(v->NewClosure(func, 0)); + return 1; + } + catch(VXSharedLibrary::SymbolError& err) + { + return v->ThrowError("Could not resolve symbol '%s'", symname); + } + return 0; +} + +VXInteger oslib_loadlib_close(VXState* v) +{ + VXSharedLibrary *self; + v->GetInstanceUp(1, (VXUserPointer*)&self, 0); + if(self == NULL) + { + return v->ThrowError("attempt to close an invalid LoadLib object"); + } + self->close(); + return 0; +} + +static VXInteger oslib_loadlib_typeof(VXState* v) +{ + v->PushString("os.loadlib", -1); + return 1; +} + +static VXRegFunction oslib_libload_funcs[]= +{ + {"constructor", oslib_loadlib_constructor, 2, ".s"}, + {"resolve", oslib_loadlib_resolve, 2, ".s"}, + {"close", oslib_loadlib_close, 1, NULL}, + {"_typeof", oslib_loadlib_typeof, 1, "x"}, + {0, 0, 0, 0} +}; + +void oslib_register_libload(VXState* v, VXTableObj* tb) +{ + //vox_regclass(v, "loadlib", oslib_libload_funcs); + //vox_rawset(v, top); + tb->NewSlot(v->NewString("loadlib"), v->RegClass(oslib_libload_funcs)); +} + +#endif + diff --git a/src/stdlib/oslib.cpp b/src/stdlib/oslib.cpp new file mode 100644 index 0000000..9b63a3d --- /dev/null +++ b/src/stdlib/oslib.cpp @@ -0,0 +1,522 @@ + + +#include +#include "helper.hpp" + +namespace fslib = boost::filesystem; +typedef fslib::filesystem_error fslib_error; + +const char* oshelper_strerror(int errval) +{ +#if defined(VOX_PLATFORM_MSWINDOWS) + std::string res; + std::string strng_end; + LPCSTR tempmessage; + ::FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errval, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), + (LPTSTR)& tempmessage,0,NULL); + return (const char*)tempmessage; +#else + return strerror(errval); +#endif +} + +int oshelper_errno() +{ +#if defined(VOX_PLATFORM_MSWINDOWS) + return ::GetLastError(); +#else + return errno; +#endif +} + +const char* oshelper_lasterror() +{ + return oshelper_strerror(oshelper_errno()); +} + + + +bool oshelper_killpid(int pid, int sign) +{ + bool failed; +#if defined(VOX_PLATFORM_UNIX) + failed = (kill(pid, sign) == -1); +#elif defined(VOX_PLATFORM_MSWINDOWS) + int retv; + HANDLE hnd = OpenProcess(1, 0, pid); + failed = (0 != TerminateProcess(hnd, 0)); +#endif + return failed; +} + +int oshelper_sleep(VXFloat milisec) +{ +#ifdef VOX_PLATFORM_MSWINDOWS + ::Sleep(milisec); +#else + timespec req = {0, 0}; + time_t sec; + if (milisec == 0) + { + return -1; + } + sec = (milisec/1000); + milisec = milisec - (sec * 1000); + req.tv_sec = sec; + req.tv_nsec = milisec*1000000L; + while(nanosleep(&req, &req) == -1) + { + continue; + } +#endif + return -1; +} + +bool oshelper_chdir(const std::string& path) +{ + int status; +#if defined(VOX_PLATFORM_MSWINDOWS) + status = _chdir(path.c_str()); +#elif defined(VOX_PLATFORM_UNIX) + status = chdir(path.c_str()); +#endif + return status; +} + +bool oshelper_chmod(const std::string& path, unsigned int octal) +{ + int status; +#if defined(VOX_PLATFORM_MSWINDOWS) + status = _chmod(path.c_str(), octal); +#elif defined(VOX_PLATFORM_UNIX) + status = chmod(path.c_str(), octal); +#endif + return (status == 0); +} + +bool oshelper_mkdir(const std::string& path, int octal) +{ + int status; +#if defined(VOX_PLATFORM_MSWINDOWS) + (void)octal; + status = _mkdir(path.c_str()); +#elif defined(VOX_PLATFORM_UNIX) + status = mkdir(path.c_str(), octal); +#endif + return (status == -1); +} + +template const char* oshelper_exception_message(Type& err) +{ + return err.code().message().c_str(); +} + +VXInteger oslib_getenv(VXState* v) +{ + const char* env_name; + const char* env_value; + v->GetString(2, &env_name, NULL); + env_value = getenv(env_name); + if(env_value != NULL) + { + v->Push(v->NewString(env_value)); + return 1; + } + return 0; +} + +VXInteger oslib_system(VXState* v) +{ + const char* shellcmd; + if(system(NULL) == 0) + { + return v->ThrowError("system() is not available"); + } + v->GetString(2, &shellcmd, NULL); + v->Push(VXInteger(system(shellcmd))); + return 1; +} + + +VXInteger oslib_clock(VXState* v) +{ + v->Push(VXFloat(clock()) / VXFloat(CLOCKS_PER_SEC)); + return 1; +} + +VXInteger oslib_time(VXState* v) +{ + time_t t; + time(&t); + v->Push(VXInteger(t)); + return 1; +} + +VXInteger oslib_remove(VXState* v) +{ + const char* path; + v->GetString(2, &path, NULL); + try + { + fslib::remove(path); + } + catch(fslib_error& err) + { + return v->ThrowError(err.what()); + } + return 0; +} + +VXInteger oslib_remove_all(VXState* v) +{ + const char* path; + v->GetString(2, &path, NULL); + try + { + fslib::remove_all(path); + } + catch(fslib_error& err) + { + return v->ThrowError(oshelper_exception_message(err)); + } + return 0; +} + +VXInteger oslib_exit(VXState* v) +{ + VXInteger status; + if(VX_FAILED(v->GetInteger(2, &status))) + { + status = -1; + } + exit(status); + return 0; +} + + +VXInteger oslib_rename(VXState* v) +{ + const char* oldpath; + const char* newpath; + v->GetString(2, &oldpath, NULL); + v->GetString(3, &newpath, NULL); + try + { + fslib::rename(oldpath, newpath); + } + catch(fslib_error& err) + { + return v->ThrowError(oshelper_exception_message(err)); + } + return 0; +} + +VXInteger oslib_date(VXState* v) +{ + time_t t; + VXInteger it; + VXInteger top; + VXInteger format = 'l'; + if(v->GetTop() > 1) + { + v->GetInteger(2,&it); + t = it; + if(v->GetTop() > 2) + { + v->GetInteger(3, (VXInteger*)&format); + } + } + else + { + time(&t); + } + tm *date; + if(format == 'u') + { + date = gmtime(&t); + } + else + { + date = localtime(&t); + } + if(!date) + { + return v->ThrowError("crt api failure"); + } + VXTableObj* tb = v->NewTable(); + tb->NewSlot(v->NewString("sec"), VXInteger(date->tm_sec)); + tb->NewSlot(v->NewString("min"), VXInteger(date->tm_min)); + tb->NewSlot(v->NewString("hour"), VXInteger(date->tm_hour)); + tb->NewSlot(v->NewString("day"), VXInteger(date->tm_mday)); + tb->NewSlot(v->NewString("month"), VXInteger(date->tm_mon)); + tb->NewSlot(v->NewString("year"), VXInteger(date->tm_year)); + tb->NewSlot(v->NewString("wday"), VXInteger(date->tm_wday)); + tb->NewSlot(v->NewString("yday"), VXInteger(date->tm_yday)); + v->Push(tb); + return 1; +} + +VXInteger oslib_listdir(VXState* v) +{ + const char* path; + std::string s_itm; + v->GetString(2, &path, NULL); + fslib::directory_iterator end; + fslib::directory_iterator iter(path); + VXArrayObj* arr = v->NewArray(); + for(; iter!=end; iter++) + { + s_itm = (*iter).path().string(); + arr->Append(v->NewString(s_itm.c_str(), s_itm.length())); + } + v->Push(arr); + return 1; +} + +VXInteger oslib_kill(VXState* v) +{ + VXInteger pid; + VXInteger sign; + v->GetInteger(2, &pid); + if(VX_FAILED(v->GetInteger(3, &sign))) + { + sign = SIGINT; + } + v->PushInteger(oshelper_killpid(pid, sign)); + return 1; +} + +VXInteger oslib_mkdir(VXState* v) +{ + const char* path; + VXInteger permissions; + v->GetString(2, &path, NULL); + if(VX_FAILED(v->GetInteger(3, &permissions))) + { + permissions = 0755; + } + if(oshelper_mkdir(path, permissions) == false) + { + return v->ThrowError(oshelper_lasterror()); + } + return 0; +} + +VXInteger oslib_chmod(VXState* v) +{ + const char* path; + VXInteger permissions; + v->GetString(2, &path, NULL); + v->GetInteger(3, &permissions); + if(oshelper_chmod(path, permissions) == false) + { + return v->ThrowError(oshelper_lasterror()); + } + return 0; +} + +VXInteger oslib_basename(VXState* v) +{ + const char* path; + std::string newpath; + v->GetString(2, &path, NULL); + newpath = fslib::path(path).filename().string(); + v->Push(v->NewString(newpath.c_str(), newpath.length())); + return 1; +} + +VXInteger oslib_dirname(VXState* v) +{ + const char* path; + std::string newpath; + v->GetString(2, &path, NULL); + fslib::path _tmp(path); + newpath = fslib::path(path).parent_path().string(); + v->Push(v->NewString(newpath.c_str(), newpath.length())); + return 1; +} + +VXInteger oslib_usleep(VXState* v) +{ + VXFloat howlong; + v->GetFloat(2, &howlong); + oshelper_sleep(howlong); + return 0; +} + +VXInteger oslib_sleep(VXState* v) +{ + VXInteger howlong; + v->GetInteger(2, &howlong); + oshelper_sleep(howlong * 1000); + return 0; +} + +VXInteger oslib_filesize(VXState* v) +{ + const char* path; + v->GetString(2, &path, NULL); + try + { + v->Push(VXInteger(fslib::file_size(path))); + } + catch(fslib_error& err) + { + return v->ThrowError(oshelper_exception_message(err)); + } + return 1; +} + +VXInteger oslib_exists(VXState* v) +{ + const char* path; + v->GetString(2, &path, NULL); + v->Push(bool(fslib::exists(path))); + return 1; +} + +VXInteger oslib_isfile(VXState* v) +{ + const char* path; + v->GetString(2, &path, NULL); + v->Push(bool(fslib::is_regular_file(path))); + return 1; +} + +VXInteger oslib_isdir(VXState* v) +{ + const char* path; + v->GetString(2, &path, NULL); + v->Push(bool(fslib::is_directory(path))); + return 1; +} + +VXInteger oslib_stat(VXState* v) +{ + const char* path; + struct stat buf; + v->GetString(2, &path, NULL); + if(stat(path, &buf) == 0) + { + VXTableObj* tb = v->NewTable(); + + v->Push(tb); + return 1; + } + return v->ThrowError(oshelper_lasterror()); +} + +VXInteger oslib_uname(VXState* v) +{ +#if defined(VOX_PLATFORM_UNIX) + struct utsname buf; + if(uname(&buf) == 0) + { + VXTableObj* tb = v->NewTable(); + tb->NewSlot(v->NewString("sysname"), v->NewString(buf.sysname)); + tb->NewSlot(v->NewString("nodename"), v->NewString(buf.nodename)); + tb->NewSlot(v->NewString("release"), v->NewString(buf.release)); + tb->NewSlot(v->NewString("version"), v->NewString(buf.version)); + tb->NewSlot(v->NewString("machine"), v->NewString(buf.machine)); + v->Push(tb); + return 1; + } + return v->ThrowError(oshelper_lasterror()); +#else + return v->ThrowError("uname() is not available on this platform"); +#endif +} + + + +VXInteger oslib_tempname(VXState* v) +{ + char* result; // char*, because it needs to be free()'d + const char* path; + const char* tpl; + if(VX_FAILED(v->GetString(2, &path, NULL))) + path = NULL; + if(VX_FAILED(v->GetString(3, &tpl, NULL))) + tpl = NULL; + result = tempnam(path, tpl); + v->Push(v->NewString(result)); + free(result); + return 1; +} + +VXInteger oslib_joinpath(VXState* v) +{ + VXInteger i; + VXObject strval; + VXObject ob; + std::string fullpath; + fslib::path p; + for(i=2; i!=(v->GetTop()+1); i++) + { + std::string str; + ob = v->StackGet(i); + v->ToString(ob, strval); + strval.String()->Get(&str); + p /= str; + ob.Null(); + } + fullpath = p.string(); + v->Push(v->NewString(fullpath.c_str(), fullpath.length())); + return 1; +} + +VXInteger oslib_abspath(VXState* v) +{ + std::string subject; + std::string fullpath; + v->GetString(2, &subject); + fslib::path p(subject); + fullpath = p.string(); + v->Push(v->NewString(fullpath.c_str(), fullpath.length())); + return 1; +} + +VXRegFunction oslib_funcs[]= +{ + {"getenv", oslib_getenv, 2, ".s"}, + {"system", oslib_system, 2, ".s"}, + {"date", oslib_date, -1, ".nn"}, + {"remove", oslib_remove, 2, ".s"}, + {"remove_all", oslib_remove_all, 2, ".s"}, + {"listdir", oslib_listdir, 2, ".s"}, + {"rename", oslib_rename, 3, ".ss"}, + {"clock", oslib_clock, 0, NULL}, + {"time", oslib_time, 1, NULL}, + {"exit", oslib_exit, -1, ".n"}, + {"kill", oslib_kill, -1, ".nn"}, + {"chmod", oslib_chmod, 3, ".sn"}, + {"mkdir", oslib_mkdir, 3, ".s|.n"}, + {"basename", oslib_basename, 2, ".s"}, + {"dirname", oslib_dirname, 2, ".s"}, + {"usleep", oslib_usleep, 2, ".n"}, + {"sleep", oslib_sleep, 2, ".n"}, + {"exists", oslib_exists, 2, ".s"}, + {"isdir", oslib_isdir, 2, ".s"}, + {"isfile", oslib_isfile, 2, ".s"}, + {"abspath", oslib_abspath, 2, ".s"}, + {"joinpath", oslib_joinpath, -1, "."}, + {"filesize", oslib_filesize, 2, ".s"}, + {"uname", oslib_uname, 1, NULL}, + {"tempname", oslib_tempname, -1, ".ss"}, + {0, 0, 0, 0} +}; + +VXInteger voxstd_register_oslib(VXState* v) +{ + VXTableObj* tb = v->NewTable(); + v->RegisterLib("os", oslib_funcs, true, tb); +#ifndef VX_NO_LOADLIB + oslib_register_libload(v, tb); +#endif + return 1; +} + diff --git a/src/stdlib/regexp.cpp b/src/stdlib/regexp.cpp new file mode 100644 index 0000000..5a3a6cc --- /dev/null +++ b/src/stdlib/regexp.cpp @@ -0,0 +1,251 @@ + +/* important: don't move boost.xpressive include + instruction to helper.hpp, otherwise compilation + speed goes down the drain */ +#include +#include "vox.h" + +#define SETUP_REX(vm, selfname) \ + RexObj* selfname = NULL; \ + if(VX_FAILED(vm->GetInstanceUp(1, (VXUserPointer *)&selfname,0))) \ + { \ + vm->ThrowError("regex: GetInstanceUp failed!"); \ + } + +struct RexObj +{ + boost::xpressive::sregex rex; +}; + +VXInteger rexhelp_compile(VXState* v, RexObj* self, const std::string& pattern) +{ + try + { + self->rex = boost::xpressive::sregex::compile(pattern); + } + catch(boost::xpressive::regex_error& err) + { + return v->ThrowError(err.what()); + } + return VX_OK; +} + +template +VXArrayObj* rexhelp_array_from_match(VXState* v, Type& what) +{ + VXInteger artop; + size_t i; + VXArrayObj* arr = v->NewArray(); + for(i=0; i 0) + { + arr->Append(v->NewString(submatch.c_str(), submatch.length())); + } + } + return arr; +} + +VXArrayObj* rexhelp_findall(VXState* v, RexObj* self, const std::string& subject) +{ + VXArrayObj* arr = v->NewArray(); + std::string::const_iterator begin = subject.begin(); + std::string::const_iterator end = subject.end(); + boost::xpressive::match_results what; + while(boost::xpressive::regex_search(begin, end, what, self->rex)) + { + VXInteger newtop; + std::string str; + str = what.str(); + VXTableObj* tb = v->NewTable(); + + /* the primary matched string */ + tb->NewSlot(v->NewString("string"), v->NewString(str.c_str(), str.length())); + + + /* matched substrings (eg, from groups) */ + tb->NewSlot(v->NewString("submatches"), rexhelp_array_from_match(v, what)); + + + /* where the matched string starts */ + tb->NewSlot(v->NewString("position"), VXInteger(what.position())); + + /* absolute length of the matched string */ + tb->NewSlot(v->NewString("length"), VXInteger(what.length())); + + arr->Append(tb); + begin = what[0].second; + } + return arr; +} + + +VXInteger rexfunc_replace(VXState* v) +{ + std::string pat; + std::string sub; + std::string rep; + std::string result; + VXInteger status; + RexObj* self = new RexObj; + v->GetString(2, &sub); + v->GetString(3, &pat); + v->GetString(4, &rep); + if((status = rexhelp_compile(v, self, pat)) != VX_OK) + { + delete self; + return status; + } + else + { + try + { + result = boost::xpressive::regex_replace( + sub, + self->rex, + rep, + boost::xpressive::regex_constants::format_all); + v->Push(v->NewString(result.c_str(), result.length())); + delete self; + return 1; + } + catch(boost::xpressive::regex_error& err) + { + delete self; + return v->ThrowError(err.what()); + } + } + return 0; +} + + +VXInteger rexfunc_match(VXState* v) +{ + std::string sub; + std::string pat; + VXInteger status; + RexObj* self = new RexObj; + v->GetString(2, &pat); + v->GetString(3, &sub); + if((status = rexhelp_compile(v, self, pat)) != VX_OK) + { + delete self; + return status; + } + else + { + boost::xpressive::match_results what; + if(boost::xpressive::regex_match(sub, what, self->rex)) + { + v->Push(rexhelp_array_from_match(v, what)); + delete self; + return 1; + } + return 0; + } + return 0; +} + +static VXInteger rexclass_typeof(VXState* v) +{ + v->Push(v->NewString("regexp")); + return 1; +} + +static VXInteger rexclass_release(VXUserPointer p, VXInteger size) +{ + (void)size; + RexObj* rex = (RexObj*)p; + delete rex; + return 1; +} + +VXInteger rexclass_match(VXState* v) +{ + SETUP_REX(v, self) + std::string subject; + boost::xpressive::match_results what; + v->GetString(2, &subject); + if(boost::xpressive::regex_match(subject, what, self->rex)) + { + v->Push(rexhelp_array_from_match(v, what)); + return 1; + } + return 0; +} + +VXInteger rexclass_group(VXState* v) +{ + SETUP_REX(v, self) + std::string subject; + std::string groupname; + v->GetString(2, &subject); + v->GetString(3, &groupname); + boost::xpressive::smatch what; + if(regex_search(subject, what, self->rex)) + { + try + { + std::string matched = what[groupname]; + v->Push(v->NewString(matched.c_str(), matched.length())); + } + catch(boost::xpressive::regex_error& err) + { + return v->ThrowError(err.what()); + } + return 1; + } + return 0; +} + +VXInteger rexclass_findall(VXState* v) +{ + SETUP_REX(v, self) + std::string opt; + v->GetString(2, &opt); + v->Push(rexhelp_findall(v, self, opt)); + return 1; +} + +static VXInteger rexclass_constructor(VXState* v) +{ + RexObj* self = new RexObj; + std::string pat; + VXInteger status; + v->GetString(2, &pat); + if((status = rexhelp_compile(v, self, pat)) != VX_OK) + { + return status; + } + v->SetInstanceUp(1, (VXUserPointer*)&self); + v->SetReleaseHook(1, rexclass_release); + return 0; +} + +VXRegFunction rexclass_funcs[] = +{ + {"constructor", rexclass_constructor, 2, ".s"}, + {"findall", rexclass_findall, 2, ".s"}, + {"match", rexclass_match, 2, ".s"}, + {"group", rexclass_group, 3, ".ss"}, + {"__typeof__", rexclass_typeof, 1, "x"}, + {0, 0, 0, 0}, +}; + + +static VXRegFunction regexlib_funcs[]= +{ + {"match", rexfunc_match, 3, ".ss"}, + {"replace", rexfunc_replace, 4, ".sss"}, + {0, 0, 0, 0} +}; + + +VXInteger voxstd_register_regexlib(VXState* v) +{ + VXTableObj* tb = v->NewTable(); + tb->NewSlot(v->NewString("compile"), v->RegClass(rexclass_funcs)); + v->RegisterLib("regexp", regexlib_funcs, true, tb); + return 1; +} diff --git a/src/stdlib/sharedlib.c b/src/stdlib/sharedlib.c new file mode 100644 index 0000000..84974e4 --- /dev/null +++ b/src/stdlib/sharedlib.c @@ -0,0 +1,172 @@ + +#include +#include +#include +#include "sharedlib.h" + +#if defined(SHAREDLIB_ISWINNT) +# include +#elif defined(SHAREDLIB_ISUNIX) +# include +# include +# include +#endif + +struct shl_handle_t { +#ifdef SHAREDLIB_ISWINNT + /* technically, HANDLE is just typedef'd to 'const void*' anyway */ + HANDLE libhandle; +#elif defined(SHAREDLIB_ISUNIX) + void* libhandle; +#endif + /* currently not really used */ + int isloaded; +}; + +shl_handle_t* shl_new() +{ + shl_handle_t* ret; + ret = (shl_handle_t*)malloc(sizeof(shl_handle_t)); + ret->libhandle = NULL; + ret->isloaded = 0; + return ret; +} + +shl_handle_t* shl_openlib(const char* path) +{ + shl_handle_t* ret; + ret = shl_new(); +#if defined(SHAREDLIB_ISWINNT) + ret->libhandle = LoadLibrary(path); +#elif defined(SHAREDLIB_ISUNIX) + ret->libhandle = dlopen(path, RTLD_LAZY); +#endif + if(ret->libhandle == NULL) + { + shl_destroy(ret); + return NULL; + } + return ret; +} + +shl_handle_t* shl_openself() +{ + shl_handle_t* ret; + ret = shl_new(); +#if defined(SHAREDLIB_ISWINNT) + HANDLE this_process; + /* GetModuleHandleEx(0,0, &this_process); */ + this_process = GetModuleHandle(0); + ret->libhandle = this_process; +#elif defined(SHAREDLIB_ISUNIX) + ret->libhandle = dlopen(NULL, 0); +#endif + return ret; +} + + +void shl_destroy(shl_handle_t* shl) +{ + if(shl != NULL) + { + free(shl); + shl = NULL; + } +} + +void shl_closelib(shl_handle_t* shl) +{ + if(shl != NULL) + { +#if defined(SHAREDLIB_ISWINNT) + FreeLibrary(shl->libhandle); +#elif defined(SHAREDLIB_ISUNIX) + dlclose(shl->libhandle); +#endif + } + shl_destroy(shl); +} + +int shl_havesym(shl_handle_t* shl, const char* sym) +{ + if(shl_resolve(shl, sym) == NULL) + { + return 0; + } + return 1; +} + +void* shl_resolve(shl_handle_t* shl, const char* sym) +{ + void* symaddr; +#if defined(SHAREDLIB_ISWINNT) + symaddr = (void*)GetProcAddress(shl->libhandle, sym); +#elif defined(SHAREDLIB_ISUNIX) + symaddr = (void*)dlsym(shl->libhandle, sym); +#endif + return symaddr; +} + +void* shl_loadsym(shl_handle_t* shl, const char* sym) +{ + if(shl_havesym(shl, sym) == 0) + { + return NULL; + } + return shl_resolve(shl, sym); +} + +int shl_geterrcode(shl_handle_t* shl) +{ + (void)shl; +#if defined(SHAREDLIB_ISWINNT) + /* the interface for loading/unloading shared objects on + windows uses the global errorcode system */ + return GetLastError(); +#elif defined(SHAREDLIB_ISUNIX) + return errno; +#endif +} + +const char* shl_geterrstr(shl_handle_t* shl) +{ +#if defined(SHAREDLIB_ISWINNT) + int errval = shl_geterrcode(shl); + /* + sometimes, in localized versions of Windows XP (and newer), + the output returned by FormatMessage() contains "\r\n" ... + so far I have not found a 'sane' way to fix this. + also, it's not like i'm the one who should fix this in the first place. + YES MICROSOFT I AM TALKING ABOUT YOU FIX YOUR SHIT FOR FUCKS SAKE + */ + LPCSTR tempmessage; + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errval, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), + (LPTSTR)& tempmessage, 0,NULL); + return tempmessage; +#elif defined(SHAREDLIB_ISUNIX) + const char* errstr; + /* sometimes dlerror() returns NULL, and in that case, + we just use strerror() instead */ + if((errstr = dlerror()) == NULL) + { + errstr = strerror(shl_geterrcode(shl)); + } + return errstr; +#endif +} + +int shl_preload(const char* path) +{ + shl_handle_t* handle; + if((handle = shl_openlib(path)) == NULL) + { + return 0; + } + shl_closelib(handle); + return 1; + +} diff --git a/src/stdlib/sharedlib.h b/src/stdlib/sharedlib.h new file mode 100644 index 0000000..ad9c5ed --- /dev/null +++ b/src/stdlib/sharedlib.h @@ -0,0 +1,60 @@ + +/* +* Copyright (C) 2008-2011 Beelzebub Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef __sharedlib_header_h__ +#define __sharedlib_header_h__ + +#if defined(_WIN32) || defined(_WIN32) +# define SHAREDLIB_ISWINNT 1 +#elif defined(__unix__) || defined(__linux__) +# define SHAREDLIB_ISUNIX +#else +# error "Unknown or unsupported Operating system?" +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct shl_handle_t shl_handle_t; + +shl_handle_t* shl_new(); +shl_handle_t* shl_openlib(const char* path); +shl_handle_t* shl_openself(); +void shl_destroy(shl_handle_t* shl); +void shl_closelib(shl_handle_t* shl); +int shl_havesym(shl_handle_t* shl, const char* sym); +void* shl_resolve(shl_handle_t* shl, const char* sym); +void* shl_loadsym(shl_handle_t* shl, const char* sym); +int shl_geterrcode(shl_handle_t* shl); +const char* shl_geterrstr(shl_handle_t* shl); +int shl_preload(const char* path); + +#ifdef __cplusplus +} +#endif /*__cplusplus */ + +#endif /* __sharedlib_header_h__ */ diff --git a/src/stdlib/vxlibrary.hpp b/src/stdlib/vxlibrary.hpp new file mode 100644 index 0000000..eff522f --- /dev/null +++ b/src/stdlib/vxlibrary.hpp @@ -0,0 +1,155 @@ + +#include "helper.hpp" +#include "sharedlib.h" + + +class VXSharedLibrary { + public: + class Error: public std::runtime_error { + public: + Error(): + std::runtime_error("VXSharedLibrary::Error") + {} + + Error(const std::string& msg): + std::runtime_error(msg) + {} + + virtual ~Error() throw() + {} + }; + + class LoadError: public VXSharedLibrary::Error { + public: + LoadError(const std::string& msg): + VXSharedLibrary::Error(msg.c_str()) + { + } + }; + + class SymbolError: public VXSharedLibrary::Error { + public: + SymbolError(const std::string& msg): + VXSharedLibrary::Error(msg.c_str()) + { + } + }; + + class CloseError: public VXSharedLibrary::Error { + public: + CloseError(const std::string& msg): + VXSharedLibrary::Error(msg.c_str()) + { + } + }; + + class NotOpenError: public VXSharedLibrary::Error { + public: + NotOpenError(const std::string& msg): + VXSharedLibrary::Error(msg.c_str()) + { + } + }; + + public: + static VXSharedLibrary openSelf() + { + VXSharedLibrary lib(shl_openself()); + return lib; + } + + + private: + shl_handle_t* m_handle; + std::string errormessage; + std::string message; + bool m_isclosed; + + private: + std::string lasterr() + { + const char* err = shl_geterrstr(m_handle); + if(err == NULL) + { + return strerror(errno); + } + return err; + } + + void setup() + { + m_isclosed = false; + } + + public: + VXSharedLibrary() + { + } + + VXSharedLibrary(shl_handle_t* ctx) + { + this->setup(); + this->m_handle = ctx; + } + + VXSharedLibrary(const std::string& path) + { + this->setup(); + this->open(path); + } + + ~VXSharedLibrary() + {} + + void open(const std::string& path) + { + this->setup(); + this->m_handle = shl_openlib(path.c_str()); + if(this->m_handle == NULL) + { + this->destroy(); + throw VXSharedLibrary::LoadError(this->lasterr()); + } + } + + void* resolve(const std::string& funcname) + { + void* ptr; + ptr = shl_resolve(this->m_handle, funcname.c_str()); + if(ptr == NULL) + { + throw VXSharedLibrary::SymbolError(this->lasterr()); + } + return ptr; + } + + template func_t resolve(const std::string& name) + { + return forcecast(this->resolve(name)); + } + + void destroy() + { + shl_destroy(this->m_handle); + } + + void close() + { + if(this->m_handle != NULL) + { + if(!m_isclosed) + { + shl_closelib(this->m_handle); + m_isclosed = true; + } + else + { + shl_destroy(this->m_handle); + } + } + else + { + shl_destroy(this->m_handle); + } + } +}; diff --git a/test/syntax/classattr.vx b/test/syntax/classattr.vx new file mode 100644 index 0000000..37045e2 --- /dev/null +++ b/test/syntax/classattr.vx @@ -0,0 +1,39 @@ + + +class Foo { + /* this would be a good place to place root information */ + + constructor(); + + + function setSomeValue(newValue); + +} + +/* attributes can be iterated through by first + iterating through the members of a class + (as explained in classattr.vx, classes are 'special' tables), + and then, calling .getattributes(), which + will yield null if there are no attributes, or a table containing + key->value pairs.*/ +foreach(member, val in Foo) +{ + println("Member: %s (%s)".format(member.tostring(), val.tostring())) + Foo.getattributes(member).each(function(k, v) + println(" %s = %s".format(k.tostring(), v.tostring()))) +} \ No newline at end of file diff --git a/test/syntax/classdef.vx b/test/syntax/classdef.vx new file mode 100644 index 0000000..c433e35 --- /dev/null +++ b/test/syntax/classdef.vx @@ -0,0 +1,28 @@ + +class NameOfClass { + /* the constructor can be defined both with and without the + 'function' keyword. both do exactly the same, and both are + perfectly valid. + */ + constructor() + { + println("Goodbye!") + } + + /* any redeclared function silently overwrites any previous + function decl with the same name, thus the previous + constructor will never get called */ + + function constructor() + { + println("Hello!") + } +} + +NameOfClass() + +/* classes can also be declared local, or as slots: */ + +local MyHiddenClass = class {} + +MySlotClass := class {} \ No newline at end of file diff --git a/test/syntax/dowhile.vx b/test/syntax/dowhile.vx new file mode 100644 index 0000000..06679ba --- /dev/null +++ b/test/syntax/dowhile.vx @@ -0,0 +1,9 @@ + + +/* do { ... } while(...) behaves just like it does in C and C++ */ + +i := 10 +do +{ + println("i = ", i) +} while(i--) \ No newline at end of file diff --git a/test/syntax/for.vx b/test/syntax/for.vx new file mode 100644 index 0000000..e69de29 diff --git a/test/syntax/foreach.vx b/test/syntax/foreach.vx new file mode 100644 index 0000000..e69de29 diff --git a/test/syntax/funcdef.vx b/test/syntax/funcdef.vx new file mode 100644 index 0000000..afbf394 --- /dev/null +++ b/test/syntax/funcdef.vx @@ -0,0 +1,24 @@ + +# "regular" function definition: + +function mul(a, b) +{ + return a*b +} +println(mul(5, 5)) + +# functions don't need braces, as long as the next statements +# form an expression: +function hi(val) + if(typeof val == "string") + println("Hi ", val, "!") + else + println("Hi value ", val.tostring().quote(), "!") +hi("World") +hi(mul(4, 2)) + +# anonymous functions (lambdas): +stuff := function(whoosh) +{ + return whoosh +} \ No newline at end of file diff --git a/test/syntax/if.vx b/test/syntax/if.vx new file mode 100644 index 0000000..e69de29 diff --git a/test/syntax/literals.vx b/test/syntax/literals.vx new file mode 100644 index 0000000..b74d979 --- /dev/null +++ b/test/syntax/literals.vx @@ -0,0 +1,12 @@ + +/* literals in Vox are _real_ objects (like in Smalltalk, Python, Ruby, ...) */ + +/* iterating through an array literal*/ +["red", "green", "blue"].map(function(val) +{ + println("val = " + val) +}) + +/* string formatting on string literals: */ +s := "Hello, %s!".format("World") +println(s) diff --git a/test/syntax/trycatch.vx b/test/syntax/trycatch.vx new file mode 100644 index 0000000..db526ee --- /dev/null +++ b/test/syntax/trycatch.vx @@ -0,0 +1,9 @@ + +/* if you have ever worked with try-catch in Javascript, + then you already know how it's done in vox. */ + +/* trycatch doesn't even require curly braces */ +try + 5/0 +catch(e) + println("err = ", e) diff --git a/test/syntax/variables.vx b/test/syntax/variables.vx new file mode 100644 index 0000000..cbddb0c --- /dev/null +++ b/test/syntax/variables.vx @@ -0,0 +1,32 @@ + +/* to explicitly define a variable, use the keyword 'local', which, + as the name suggests, creates a local value. + in classes, using local is the only way to define a new variable, + as namespacing in classes does not support new slots. + + to implicitly define a variable, use the slot operator, ':='. + for example: +*/ + +a := 10 +println("a = ", a) + +/* the variable 'a' has been created in a new slot, using the slot operator, + containing the value 'a'. + + since the root namespace is, infact, just a table, this suggests that + the slot operator is in reality a table operator. let's see: +*/ + +b := {} +b.foo := "Bar" + +/* the key 'foo' has been created with the slot operator. + in tables, this is the only way to insert a new value. + notice, however, that the slot operator is ONLY needed to + create values; not to modify them: +*/ +b.foo = "Quux" + +/* modifications can be done using the assignment operator. */ +println("b.foo = ", b.foo) diff --git a/test/syntax/while.vx b/test/syntax/while.vx new file mode 100644 index 0000000..3b979c5 --- /dev/null +++ b/test/syntax/while.vx @@ -0,0 +1,6 @@ + +/* while(...) ... works just like in C and C++ */ + +i := 0 +while(i++ != 10) + println(i) \ No newline at end of file -- 2.11.4.GIT