neko-2.0.0/0000755000175000017500000000000012112157473013154 5ustar ncannassencannasseneko-2.0.0/CHANGES0000644000175000017500000003351712112157473014160 0ustar ncannassencannasse2013-02-23 : 2.0.0 all : changed license to MIT mod_neko+mod_tora : fixed issue with get_client_ip in 64 bits mode /gcc mysql : added support for timestamp to date conversion std : added merge_sort native implementation std : added mem_local_size regexp : fix in regexp_match, ^ no longer match if pos > 0 tools : don't abort server on invalid http request std : fixed sys_command error code (was <<8 on Linux/OSX) nekoc : added -version which adds Loop opcode and ensure correct $array evaluation order vm : support for bytecode version and new Loop/MakeArray2 opcodes mod_neko/tora : only mix POST with GET params if content-type contains 'urlencoded' mysql5 : added charset support check for escape() nekoc : fixed bug with switch tables where max >= 256 neko : int32 is now a first class value std : md5 and hashing now takes the int32 value into account neko : max array/string size is now 256MB instead of 512MB std : date_new("YYYY-MM-DD") now uses localtime instead of UTC (same as Y-M-D H:M:S) neko : fixed missing stack for array write in interp mode with invalid index neko : added "-version" to print version and exit 2011-09-10 : 1.8.2 vm : use 15 digits (instead of 10) for float display std : allow up to 512MB array/string size in serialize (instead of 1MB) std : bugfix in utf8 (with 4 bytes codes) vm : finalizers bugfix on Windows std : added sys_thread_cpu_time() vm : use VEXTERN for neko_kind_module and neko_id_module std : hide process console in process_run nekoml : added Math core module std : fixed timeout error for sockets on Windows mod_tora : added PROXY_MODE configuration std : fixed timeout error for sockets on Linux vm : fixed $int and $float - return null on invalid strings mysql : added result_get_fields_names gc : prevent issues with AV softs / GoogleDesktop which inject threads vm : use sse2 for fp calculus on gcc (double precision, same as msvc/flash) removed in updated build (some CPU are not compatible) mysql : added support for BINARY(size) type vm : keep stack infos for object/array ops (interp) std : added thread_stack vm : added $fasthash mysql5 : fixed 5.5 protocol change std : fixed sha1 for 64-bits (also fix mysql5 auth) std : added make_sha1 mysql : added set_conv_funs for string + bytes wrapping support 2009-07-26 : 1.8.1 nekoc : small fix in evaluation of using jump tables for switch on integers regexp : use a recursion limit to prevent stack overflows in pcre mysql5 : completely rewrote mysql client mod_tora : complete rearchitecture with abstract protocol std : added socket_set_fast_send mod_tora : use socket fast send to optimize timing mod_tora : fixed bug when .n file does not exists mod_tora : fix for Apache 2.x - does not set the content-type if declined mod_tora : added port range configuration (for random tora server) std, mod_tora : propagate jit mode to created threads nekoc : optimization for debug infos : precompute file table at compile-time threads : added neko_gc_register_thread (but buggy, so not used) mysql5 : added 5 hours network timeout while waiting for an answer mysql5 : fixed some additional errors handling mysql5 : allow big requests (more than 16MB) vm : optimize object table - one word and one memory block saved per object jit : one more crash fix for the + operation and unexisting overloaded operator nekoml : added Sys.is_directory, Sys.read_directory and Regexp.split nekoml : don't allow empty match vm : create pthreads in detached mode (prevent leak on osx/linux) std : added math_fceil,math_ffloor,math_fround,math_int,process_kill nekoc : forbidden usage of 'var' outside blocks 2008-09-23 : 1.8.0 added mod_tora (neko application server) changed mod_neko get_host_name : return the http host instead of the server IP bugfix in nekoml : fixed usage of nekoml.std + added -nostd std : added EINTR handling in send/recv socket operations and fread/fwrite gc : upgraded windows version to 7.1 vm : fixed comparison of bool vm : moved threads stuff into threads.c nekoml : fixed lexing engine, allow escape sequences in char groups mysql : link with thread_safe version on linux std : fixed threads issues with host_resolve and host_reverse libs : compile with -pthread on linux/osx to ensure thread safety main : turned ON jit by default for bootable executables std : added set_trusted primitive gc : use alloc_ignore_off_page for large blocks gc : use finalizers with no_order (prevent cycles) mysql : prevent hashing the fields that looks like inner requests vm : optimized global fields cache std : string_split doesn't copy the string anymore if the pattern is not found vm : added neko_vm_dump_stack std : use per-thread locale on POSIX systems std : url_encode does not encode anymore - and . chars std : fixed sleep() for unix (more accurate and deal with signals) std : added module_read_string and module_set_name std : fixed some file descriptor issues with processes and threads jit : fixed crash whith unsupported OO overloading vm : added $getkind and $iskind builtins std : added same_closure for closure comparison 2008-07-28 : 1.7.1 nekotools : fixed set_return_code in web server std : display windowed application in process_run mod_neko : allowed to uncache module with set_main(null) mod_neko : use strmcpi for set_header("Content-Type") nekoc : one last fix for big arrays (first element was not compiled) mod_neko : added get_http_method nekoml : minor fixes in lexer nekoml : added -pack and -use, auto build nekoml.std include nekoml as part of standard distribution vm/security : $smake now fills the string with 0 std/int32 : fixed need_32_bits macro (negative values) bugfix : >> and >>> were reversed in JIT bugfix : date functions are now MT-safe removed context.h and context.c added lock and tls multithread API to neko.h std : added date_get_tz() mod_neko : added log_message regexp : fix for unmatched optional groups, return null instead of empty string threads : for windows, use critical_section instead of mutex for locks threads : for posix, use a recursive mutex which match windows behavior std : added mutex and deque api (threads) 2008-03-16 : 1.7.0 nekoc : allow binary ast format with -p, don't allow inline nxml std : allow int32_new float parameter vm : reduce debug infos memory size by 16 vm : fixed $int in case of overflow regexp : upgraded windows ndll to use pcre 7.3 with utf8 support fixed : math_round(0.5) is now 1 fixed : date_set_hour and date_set_day crash with invalid dates fixed : bug in vm/callback.c when stack address is >2GB sockets : added support for socket_poll for Windows sockets : added socket_poll_prepare and socket_poll_events thread : added tls_create, tls_set, tls_get vm : threaded interpreter (gcc only) vm : always use COMPACT_TABLE for objects mod_neko : log some errors into apache log neko+vm : added perf statistics hooks (-stats) mod_neko : scriptable configuration and statistics regexp : allow more than 10 matches std : added process_close vm : added $aconcat nekoc : fixed big arrays declarations std : added sys_is64 2007-07-25 : 1.6.0 display error message when uncaught exception in neko thread fix bug in long run JIT programs : no C functions callable anymore use a smarter way to prevent C stack overflow nekoc : stack align error message set max-stack-per-function to 128 and default-stack-size to 256 jit now check stack overflow on function entry and not on every push mod_neko2 set MOD_NEKO=2 env var (for version detection) mod_neko2 : remove Apache 2.0 error message, use 302 http code for redirect fixed fallback of interp operator overloading fix for 64-bit CPU minor optimization for [0] jit array access gnuk/freebsd support fixed thread messages on Windows (do not use system queue) thread_current returns unique value remove kind_import, kind_export, added kind_share added ui library added libs/std/process api functions new binary ast format (faster than nxml) 2007-01-28 : 1.5.3 minor fixes in mod_neko multipart and POST data handling fixed $objremove result (was always true) fixed one-last-bug when using more-than-five-arguments method call return value fixed bug in dev webserver when accessing a directory added xcross support fixed bug with $setresolver in bytecode interpreter changed bootable vm implementation (easier, allow compressed bin) added .mode in sys_stat change in $version format 2006-11-22 : 1.5.2 fixed std math_pow float minor thread cleanup added MySQL5.ndll for Windows fields hash cache is now global (instead of per-thread) socket_select retry on EINTR fixed under-second lock timeout for Linux/OSX added socket_poll for Linux/OSX (emulate with select() on Windows) fixed compilation bug when accessing 'this' in arguments and more than 5 args fixed string_split with empty string (was causing infinite loop) fixes in more-than-five-arguments-calls added $varargs 2006-10-29 : 1.5 neko web server : get_client_header is now case-insensitive std : new thread and lock api neko : when run from commandline, SEGV on Linux are turned into exceptions + added mod_neko2 error if used with Apache 2.0.x 2006-10-09 : 1.4.5 sqlite : added BOOL handling jit : added mmap support (for execution protection) jit : fixed bug when unsupported operation exception vm : fixed bug in debug infos reading when nfiles > 255 vm : fixed bug in interp -> jit call vm : default NEKOPATH is now the same on OSX/Linux vm : optimized debug infos runtime memory size std : added misc.c (float & double bytes manipulations + gc/vm functions) std : fixed buf in sys_read_dir on windows (directory not closed correctly) std : added sys_getch, sys_get_pid std : fixed socket_host (was returning the same as socket_peer) std : improved performances of serialize/unserialize allowed break & continues in try/catch if they don't break outside nekoml : fixed bug in lexer allocating too bug memory when small reads nekotools : bugfixes in server, added static file streaming nekotools : fixed boot for universal binaries mod_neko : minor updates for better memory handling mod_neko : use soft timeout for Apache 1.3 2006-08-02 : 1.4 std : added a SO_REUSEADDR before socket_bind (except windows) nekoc/nekovm : allowed more than 127 filenames in debug infos nekotools server : added -rewrite for mod_rewrite'style urls added zlib wrapper mod_neko for apache 2.0 added sqlite wrapper std : fixed socket_set_timeout (changed unit from millisec to seconds) std : fixed math_pow (integer overflow) , fixed readdir (missing closedir on Linux) added PPC registers neko.h : added NEKO_* OS/CPU flags added JIT for x86 vm : (int mod 0) is now an exception (and not NaN) neko.h : added kind_import and kind_export to share abstracts between libraries std : handle signals in socket send and recv allowed OSX universal build added $setresolver for unknown object field handling 2006-05-11 : 1.3 neko : fixed endianness bug needed to boot, exported neko_is_big_endian neko : fixed bug on Linux x86 gcc with object operators (eax get overwritten) neko : fixed bug : error when __string or __compare does not exist neko : allowed runtime printer redirection (+ added std@print_redirect) neko : defined a default NEKOPATH when not specified (less configuration) neko : fixed int32 calculus bug (need_32_bits macro) neko : fixed calls with a lot of arguments (some cases were failing) neko : fixed preservation of 'this' through tailcall, if changed inside the call neko : added unary operator minus parsing neko : fixed error reporting of unclosed parenthesis nekoml : added Net core module for sockets nekoml : when catching Neko errors, wrap them using Neko_error constructor std : supported serialization of C primitives and __serialize/__unserialize overrides added nekotools (merged nekoboot and neko webserver) std : fixed math_round, fixed math docs std : fixed bug in utf8_resize, utf8_get and utf8_iter. regexp : added regexp_new_options for matching options and regexp_replace_fun regexp : fixed invalid matched length when not index 0 added some benchmarks in src/benchs neko : fixed $ablit and $sblit (when used with same array/string) neko : fixed multithread win32 support mod_neko : changed Content-Type handling for POST data std : added blocking sockets support std : changed sys_time to sys_cpu_time, added sys_time (local time). std : fixed put_env on Linux (GC issue) cleanup of some stuff needed by experimental JIT std : added memory module 2006-01-09 : 1.2 nekoc: added linker : provide linked versions of neko & nekoml compilers added tail calls optimization nekoml: little improved nekoml->neko patterns generator libs: added md5 digest , utf8 api and base_encode/base_decode in std some changes in mod_neko api mysql api now threat tinyint(1) as booleans improved xml parser : support for doctype some fixes for OSX and C++ compilation neko: renamed 'nekovm' to 'neko' experimental jit support object prototypes moved args from builtin ($args) to loader ($loader.args) makeboot can create standalone binaries runtime errors on : - calls with invalid number of arguments - field accesses of not-an-object - binary operations on invalid types - array accesses on not-an-array and not-an-object license change : from GPL to LGPL 2005-11-10 : 1.1 vm : ports PPC (big endian) and AMD64 added stack conservation check at bytecode loadtime : faster VM runtime some more opcodes for better speed added exception and call stack traces added debug informations for bytecode added dispatch tables (for integer switchs) tuned GC usage reorganized VM apis neko: added labels in the language specification added $goto and $apply added switchs added documentation generator nekoml: added NekoML bootstrapped the language (no more need for ocaml) libs: rewrote and completed standard library added generated documentation 2005-08-17 : 1.0 compiler in ocaml virtual machine mod_neko some small libraries neko-2.0.0/neko.sln0000644000175000017500000000631312112157473014631 0ustar ncannassencannasseMicrosoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nekovm", "vm\nekovm.vcproj", "{C9796A2F-49BA-4EE2-A28A-2707C5151D0E}" ProjectSection(ProjectDependencies) = postProject {FEBA0CA8-4D9C-49C3-B3CC-1A7CFF9BB8B3} = {FEBA0CA8-4D9C-49C3-B3CC-1A7CFF9BB8B3} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nekovm_dll", "vm\nekovm_dll.vcproj", "{FEBA0CA8-4D9C-49C3-B3CC-1A7CFF9BB8B3}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "neko", "src\neko.vcproj", "{4C13C941-4D12-4904-BDA2-A2DF8AF4F31A}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nekoml", "src\nekoml.vcproj", "{4662A8A2-AE65-465A-B97B-7F1269433BD5}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release ReleaseCrt60 = ReleaseCrt60 EndGlobalSection GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {C9796A2F-49BA-4EE2-A28A-2707C5151D0E}.Debug.ActiveCfg = Debug|Win32 {C9796A2F-49BA-4EE2-A28A-2707C5151D0E}.Debug.Build.0 = Debug|Win32 {C9796A2F-49BA-4EE2-A28A-2707C5151D0E}.Release.ActiveCfg = Release|Win32 {C9796A2F-49BA-4EE2-A28A-2707C5151D0E}.Release.Build.0 = Release|Win32 {C9796A2F-49BA-4EE2-A28A-2707C5151D0E}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {C9796A2F-49BA-4EE2-A28A-2707C5151D0E}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {FEBA0CA8-4D9C-49C3-B3CC-1A7CFF9BB8B3}.Debug.ActiveCfg = Debug|Win32 {FEBA0CA8-4D9C-49C3-B3CC-1A7CFF9BB8B3}.Debug.Build.0 = Debug|Win32 {FEBA0CA8-4D9C-49C3-B3CC-1A7CFF9BB8B3}.Release.ActiveCfg = Release|Win32 {FEBA0CA8-4D9C-49C3-B3CC-1A7CFF9BB8B3}.Release.Build.0 = Release|Win32 {FEBA0CA8-4D9C-49C3-B3CC-1A7CFF9BB8B3}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {FEBA0CA8-4D9C-49C3-B3CC-1A7CFF9BB8B3}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {4C13C941-4D12-4904-BDA2-A2DF8AF4F31A}.Debug.ActiveCfg = Debug|Win32 {4C13C941-4D12-4904-BDA2-A2DF8AF4F31A}.Debug.Build.0 = Debug|Win32 {4C13C941-4D12-4904-BDA2-A2DF8AF4F31A}.Release.ActiveCfg = Release|Win32 {4C13C941-4D12-4904-BDA2-A2DF8AF4F31A}.Release.Build.0 = Release|Win32 {4C13C941-4D12-4904-BDA2-A2DF8AF4F31A}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {4C13C941-4D12-4904-BDA2-A2DF8AF4F31A}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {4662A8A2-AE65-465A-B97B-7F1269433BD5}.Debug.ActiveCfg = Debug|Win32 {4662A8A2-AE65-465A-B97B-7F1269433BD5}.Debug.Build.0 = Debug|Win32 {4662A8A2-AE65-465A-B97B-7F1269433BD5}.Release.ActiveCfg = Release|Win32 {4662A8A2-AE65-465A-B97B-7F1269433BD5}.Release.Build.0 = Release|Win32 {4662A8A2-AE65-465A-B97B-7F1269433BD5}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {4662A8A2-AE65-465A-B97B-7F1269433BD5}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal neko-2.0.0/libs/0000755000175000017500000000000012112157473014105 5ustar ncannassencannasseneko-2.0.0/libs/mod_tora/0000755000175000017500000000000012112157473015711 5ustar ncannassencannasseneko-2.0.0/libs/mod_tora/protocol.h0000644000175000017500000000523212112157473017725 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef PROTOCOL_H #define PROTOCOL_H #include "osdef.h" typedef void (*pf_callback)( void *custom ); typedef int (*pf_print)( void *custom, const char *buffer, int size ); typedef void (*pf_set_header)( void *custom, const char *key, const char *value, bool add ); typedef void (*pf_set_code)( void *custom, int code ); typedef void (*pf_log)( void *custom, const char *message, bool inner_log ); typedef int (*pf_stream_data)( void *custom, char *buffer, int size ); typedef struct { const char *script; const char *uri; const char *hostname; const char *client_ip; const char *http_method; const char *get_data; const char *post_data; const char *content_type; int post_data_size; pf_callback do_get_headers; pf_callback do_get_params; pf_print do_print; pf_callback do_flush; pf_set_header do_set_header; pf_set_code do_set_return_code; pf_stream_data do_stream_data; pf_log do_log; void *custom; } protocol_infos; struct _protocol; typedef struct _protocol proto; proto *protocol_init( protocol_infos *inf ); bool protocol_connect( proto *p, const char *host, int port ); bool protocol_send_request( proto *p ); void protocol_send_header( proto *p, const char *header, const char *value ); void protocol_send_param( proto *p, const char *param, int param_size, const char *value, int value_size ); void protocol_send_raw_params( proto *p, const char *data ); bool protocol_read_answer( proto *p ); const char *protocol_get_error( proto *p ); void protocol_free( proto *p ); #endif /* ************************************************************************ */ neko-2.0.0/libs/mod_tora/mod_tora2.vcxproj0000644000175000017500000002011312112157473021211 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {0242BA00-FECF-4D6B-80FA-2A9389E9060C} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug2\ Debug2\ true Release2\ Release2\ false Release\ Release\ false Disabled ../../vm;../common;..\include\apache2;..\include\apache2\apr;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_TORA2_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ../include/apache2/libhttpd.lib;../include/apache2/libapr-1.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/mod_tora2.ndll true $(OutDir)mod_tora2.pdb Windows $(OutDir)mod_tora2.lib MachineX86 ../../vm;../common;..\include\apache2;..\include\apache2\apr;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_TORA2_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../include/apache2/libhttpd.lib;../include/apache2/libapr-1.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/mod_tora2.ndll %(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)mod_tora2.lib MachineX86 ../../vm;../common;..\include\apache2;..\include\apache2\apr;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_TORA2_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../include/apache2/libhttpd.lib;../include/apache2/libapr-1.lib;ws2_32.lib;../include/msvcrt/extra.lib;%(AdditionalDependencies) ../../bin/mod_tora2.ndll MSVCRT;%(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)mod_tora2.lib MachineX86 neko-2.0.0/libs/mod_tora/mod_tora.vcxproj0000644000175000017500000001763312112157473021144 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {4F7BD088-CAFB-4263-98DA-D9BABE82EAC6} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ true Release\ Release\ false Release\ Release\ false Disabled ../../vm;../common;..\include\apache;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_TORA_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ws2_32.lib;..\include\apache/ApacheCore.lib;%(AdditionalDependencies) ../../bin/mod_tora.ndll true $(OutDir)mod_tora.pdb Windows $(OutDir)mod_tora.lib MachineX86 ../../vm;../common;..\include\apache;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_TORA_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ws2_32.lib;..\include\apache/ApacheCore.lib;%(AdditionalDependencies) ../../bin/mod_tora.ndll %(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)mod_tora.lib MachineX86 ../../vm;../common;..\include\apache;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_TORA_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ws2_32.lib;..\include\apache/ApacheCore.lib;../include/msvcrt/extra.lib;%(AdditionalDependencies) ../../bin/mod_tora.ndll MSVCRT;%(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)mod_tora.lib MachineX86 neko-2.0.0/libs/mod_tora/mod_tora.vcproj0000644000175000017500000001207112112157473020743 0ustar ncannassencannasse neko-2.0.0/libs/mod_tora/protocol.c0000644000175000017500000002747712112157473017737 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include "protocol.h" #include "socket.h" struct _protocol { PSOCK s; bool error; char *error_msg; protocol_infos inf; }; typedef enum { CODE_FILE = 1, CODE_URI, CODE_CLIENT_IP, CODE_GET_PARAMS, CODE_POST_DATA, CODE_HEADER_KEY, CODE_HEADER_VALUE, CODE_HEADER_ADD_VALUE, CODE_PARAM_KEY, CODE_PARAM_VALUE, CODE_HOST_NAME, CODE_HTTP_METHOD, CODE_EXECUTE, CODE_ERROR, CODE_PRINT, CODE_LOG, CODE_FLUSH, CODE_REDIRECT, CODE_RETURNCODE, CODE_QUERY_MULTIPART, CODE_PART_FILENAME, CODE_PART_KEY, CODE_PART_DATA, CODE_PART_DONE, CODE_TEST_CONNECT, CODE_LISTEN, } proto_code; #define PARSE_HEADER(start,cursor) \ cursor = start; \ if( *cursor == '"' ) { \ start++; \ cursor++; \ while( *cursor != '"' && *cursor != 0 ) \ cursor++; \ } else { \ while( *cursor != 0 && *cursor != '\r' && *cursor != '\n' && *cursor != '\t' ) \ cursor++; \ } static bool proto_error( proto *p, const char *error ) { free(p->error_msg); p->error_msg = strdup(error); p->error = true; return false; } proto *protocol_init( protocol_infos *inf ) { proto *p = (proto*)malloc(sizeof(struct _protocol)); p->s = INVALID_SOCKET; p->inf = *inf; p->error = false; p->error_msg = NULL; psock_init(); return p; } bool protocol_connect( proto *p, const char *host, int port ) { PHOST h = phost_resolve(host); if( h == UNRESOLVED_HOST ) return proto_error(p,"Failed to resolve host"); p->s = psock_create(); if( p->s == INVALID_SOCKET ) return proto_error(p,"Failed to create socket"); if( psock_connect(p->s,h,port) != PS_OK ) return proto_error(p,"Failed to connect to TORA host"); return true; } const char *protocol_get_error( proto *p ) { return p->error_msg ? p->error_msg : "NO ERROR"; } void protocol_free( proto *p ) { psock_close(p->s); free(p->error_msg); free(p); } static void proto_write( proto *p, const char *str, int len ) { while( len ) { int b = psock_send(p->s,str,len); if( b <= 0 ) { p->error = true; return; } len -= b; str += b; } } static bool proto_read( proto *p, char *str, int len ) { while( len ) { int b = psock_recv(p->s,str,len); if( b <= 0 ) { p->error = true; return false; } len -= b; str += b; } return true; } static void proto_send_size( proto *p, proto_code code, const char *str, int len ) { unsigned char h[4]; h[0] = (unsigned char)code; h[1] = (unsigned char)len; h[2] = (unsigned char)(len >> 8); h[3] = (unsigned char)(len >> 16); proto_write(p,(char*)h,4); proto_write(p,str,len); } static void proto_send( proto *p, proto_code code, const char *str ) { proto_send_size(p,code,str,(int)strlen(str)); } void protocol_send_header( proto *p, const char *key, const char *val ) { proto_send(p,CODE_HEADER_KEY,key); proto_send(p,CODE_HEADER_VALUE,val); } static int url_decode( const char *bin, int len, char *bout ) { int pin = 0; int pout = 0; while( len-- > 0 ) { char c = bin[pin++]; if( c == '+' ) c = ' '; else if( c == '%' ) { int p1, p2; if( len < 2 ) break; p1 = bin[pin++]; p2 = bin[pin++]; len -= 2; if( p1 >= '0' && p1 <= '9' ) p1 -= '0'; else if( p1 >= 'a' && p1 <= 'f' ) p1 -= 'a' - 10; else if( p1 >= 'A' && p1 <= 'F' ) p1 -= 'A' - 10; else continue; if( p2 >= '0' && p2 <= '9' ) p2 -= '0'; else if( p2 >= 'a' && p2 <= 'f' ) p2 -= 'a' - 10; else if( p2 >= 'A' && p2 <= 'F' ) p2 -= 'A' - 10; else continue; c = (char)((unsigned char)((p1 << 4) + p2)); } bout[pout++] = c; } bout[pout] = 0; return pout; } #define DEFAULT_SIZE 256 static void proto_send_decode( proto *p, proto_code code, const char *str, int len ) { char tmp[DEFAULT_SIZE]; char *buf = NULL; int size; if( len >= DEFAULT_SIZE ) buf = malloc(len+1); size = url_decode(str,len,buf?buf:tmp); proto_send_size(p,code,buf?buf:tmp,size); if( buf ) free(buf); } void protocol_send_param( proto *p, const char *param, int param_size, const char *value, int value_size ) { proto_send_size(p,CODE_PARAM_KEY,param,param_size); proto_send_size(p,CODE_PARAM_VALUE,value,value_size); } void protocol_send_raw_params( proto *p, const char *args ) { char *aand, *aeq, *asep; while( true ) { aand = strchr(args,'&'); if( aand == NULL ) { asep = strchr(args,';'); aand = asep; } else { asep = strchr(args,';'); if( asep != NULL && asep < aand ) aand = asep; } if( aand != NULL ) *aand = 0; aeq = strchr(args,'='); if( aeq != NULL ) { *aeq = 0; proto_send_decode(p,CODE_PARAM_KEY,args,(int)(aeq-args)); proto_send_decode(p,CODE_PARAM_VALUE,aeq+1,(int)strlen(aeq+1)); *aeq = '='; } if( aand == NULL ) break; *aand = (aand == asep)?';':'&'; args = aand+1; } } static char *memfind( char *mem, int mlen, const char *v ) { char *found; int len = (int)strlen(v); if( len == 0 ) return mem; while( (found = memchr(mem,*v,mlen)) != NULL ) { if( (int)(found - mem) + len > mlen ) break; if( memcmp(found,v,len) == 0 ) return found; mlen -= (int)(found - mem + 1); mem = found + 1; } return NULL; } bool protocol_send_request( proto *p ) { proto_send(p,CODE_FILE,p->inf.script); proto_send(p,CODE_URI,p->inf.uri); proto_send(p,CODE_HOST_NAME,p->inf.hostname); proto_send(p,CODE_CLIENT_IP,p->inf.client_ip); if( p->inf.do_get_headers ) p->inf.do_get_headers(p->inf.custom); if( p->inf.get_data ) proto_send(p,CODE_GET_PARAMS,p->inf.get_data); if( p->inf.post_data ) proto_send_size(p,CODE_POST_DATA,p->inf.post_data,p->inf.post_data_size); if( p->inf.do_get_params ) p->inf.do_get_params(p->inf.custom); proto_send(p,CODE_HTTP_METHOD,p->inf.http_method); psock_set_fastsend(p->s,1); proto_send_size(p,CODE_EXECUTE,NULL,0); psock_set_fastsend(p->s,0); return !p->error; } static int fill_buffer( proto *p, char *buf, int bufsize, int pos ) { while( pos < bufsize ) { int k = p->inf.do_stream_data(p->inf.custom,buf+pos,bufsize-pos); if( k <= 0 ) break; pos += k; } return pos; } static bool send_multipart_data( proto *p, char *buf, int bufsize ) { int len = 0; char *boundstr = NULL; int boundstr_len; if( p->inf.content_type == NULL || p->inf.do_stream_data == NULL ) return true; // extract boundary value { const char *boundary, *bend; if( (boundary = strstr(p->inf.content_type,"boundary=")) == NULL ) return false; boundary += 9; PARSE_HEADER(boundary,bend); len = (int)(bend - boundary); boundstr_len = len + 2; if( boundstr_len > bufsize / 2 ) return false; boundstr = (char*)malloc(boundstr_len + 1); boundstr[0] = '-'; boundstr[1] = '-'; boundstr[boundstr_len] = 0; memcpy(boundstr+2,boundary,len); } len = 0; // permit the server to start download if needed if( p->inf.do_stream_data(p->inf.custom,NULL,0) != 0 ) { free(boundstr); return false; } while( true ) { char *name, *end_name, *filename, *end_file_name, *data; int pos; // refill buffer // we assume here that the the whole multipart header can fit in the buffer len = fill_buffer(p,buf,bufsize,len); // is boundary at the beginning of buffer ? if( len < boundstr_len || memcmp(buf,boundstr,boundstr_len) != 0 ) { free(boundstr); return false; } name = memfind(buf,len,"Content-Disposition:"); if( name == NULL ) break; name = memfind(name,len - (int)(name - buf),"name="); if( name == NULL ) { free(boundstr); return false; } name += 5; PARSE_HEADER(name,end_name); data = memfind(end_name,len - (int)(end_name - buf),"\r\n\r\n"); if( data == NULL ) { free(boundstr); return false; } filename = memfind(name,(int)(data - name),"filename="); if( filename != NULL ) { filename += 9; PARSE_HEADER(filename,end_file_name); } data += 4; pos = (int)(data - buf); // send part name if( filename ) proto_send_size(p,CODE_PART_FILENAME,filename,(int)(end_file_name - filename)); proto_send_size(p,CODE_PART_KEY,name,(int)(end_name - name)); // read data while( true ) { const char *boundary; // recall buffer memcpy(buf,buf+pos,len - pos); len -= pos; pos = 0; len = fill_buffer(p,buf,bufsize,len); // lookup bounds boundary = memfind(buf,len,boundstr); if( boundary == NULL ) { if( len == 0 ) { free(boundstr); return false; } // send as much buffer as possible to client if( len < bufsize ) pos = len; else pos = len - boundstr_len + 1; proto_send_size(p,CODE_PART_DATA,buf,pos); } else { // send remaining data pos = (int)(boundary - buf); proto_send_size(p,CODE_PART_DATA,buf,pos - 2); // recall memcpy(buf,buf+pos,len - pos); len -= pos; break; } } proto_send_size(p,CODE_PART_DONE,"",0); } free(boundstr); return true; } #define BUFSIZE (1 << 16) // 64 KB #define ABORT(msg) { proto_error(p,msg); goto exit; } bool protocol_read_answer( proto *p ) { unsigned char header[4]; int len; char *buf = (char*)malloc(BUFSIZE), *key = NULL; int buflen = BUFSIZE; int listening = 0; while( true ) { if( !proto_read(p,header,4) ) ABORT("Connection Closed"); len = header[1] | (header[2] << 8) | (header[3] << 16); if( buflen <= len ) { while( buflen < len ) buflen <<= 1; free(buf); buf = (char*)malloc(buflen); } if( !proto_read(p,buf,len) ) ABORT("Connection Closed"); buf[len] = 0; switch( *header ) { case CODE_HEADER_KEY: key = strdup(buf); break; case CODE_HEADER_VALUE: if( !key ) ABORT("Missing key"); p->inf.do_set_header(p->inf.custom,key,buf,false); free(key); key = NULL; break; case CODE_HEADER_ADD_VALUE: if( !key ) ABORT("Missing key"); p->inf.do_set_header(p->inf.custom,key,buf,true); free(key); key = NULL; break; case CODE_EXECUTE: goto exit; case CODE_ERROR: p->inf.do_log(p->inf.custom,buf,true); goto exit; case CODE_PRINT: if( !p->inf.do_print(p->inf.custom,buf,len) && listening ) goto exit; if( listening ) p->inf.do_flush(p->inf.custom); break; case CODE_LOG: p->inf.do_log(p->inf.custom,buf,false); break; case CODE_FLUSH: p->inf.do_flush(p->inf.custom); break; case CODE_REDIRECT: p->inf.do_set_header(p->inf.custom,"Location",buf,false); p->inf.do_set_return_code(p->inf.custom,302); break; case CODE_RETURNCODE: p->inf.do_set_return_code(p->inf.custom,atoi(buf)); break; case CODE_QUERY_MULTIPART: { int tmpsize = atoi(buf); char *tmp = (char*)malloc(tmpsize + 1); tmp[tmpsize] = 0; if( !send_multipart_data(p,tmp,tmpsize) ) { free(tmp); ABORT("Failed to send multipart data"); } free(tmp); proto_send(p,CODE_EXECUTE,""); } break; case CODE_LISTEN: listening = 1; p->inf.do_flush(p->inf.custom); break; default: ABORT("Unexpected code"); } } exit: free(key); free(buf); return !p->error; } /* ************************************************************************ */ neko-2.0.0/libs/mod_tora/mod_tora2.vcproj0000644000175000017500000001235112112157473021026 0ustar ncannassencannasse neko-2.0.0/libs/mod_tora/mod_tora.c0000644000175000017500000002426312112157473017670 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include "protocol.h" #ifndef OS_WINDOWS # include # define strcmpi strcasecmp #endif #define send_headers(c) \ if( !c->headers_sent ) { \ ap_send_http_header(c->r); \ c->headers_sent = 1; \ } #ifdef STANDARD20_MODULE_STUFF # define APACHE_2_X # define ap_send_http_header(x) # define ap_soft_timeout(msg,r) # define ap_kill_timeout(r) # define ap_table_get apr_table_get # define ap_table_set apr_table_set # define ap_table_add apr_table_add # define ap_table_do apr_table_do # define ap_palloc apr_palloc # define LOG_SUCCESS APR_SUCCESS, # define REDIRECT HTTP_MOVED_TEMPORARILY # define REMOTE_ADDR(c) c->remote_addr->sa.sin.sin_addr #else # define LOG_SUCCESS # define REMOTE_ADDR(c) c->remote_addr.sin_addr #endif #define DEFAULT_HOST "127.0.0.1" #define DEFAULT_PORT 6666 #define DEFAULT_MAX_POST_DATA (1 << 18) // 256 K typedef struct { char *host; int port_min; int port_max; int max_post_size; int hits; bool proxy_mode; } mconfig; typedef struct { request_rec *r; proto *p; char *post_data; char *xff; char *client_ip; int post_data_size; bool headers_sent; bool is_multipart; bool is_form_post; bool need_discard; } mcontext; static mconfig config; static bool init_done = false; static int get_client_header( void *_c, const char *key, const char *val ) { mcontext *c = (mcontext*)_c; if( key == NULL || val == NULL ) return 1; if( config.proxy_mode && strcmpi(key,"X-Forwarded-For") == 0 ) protocol_send_header(c->p,key,c->xff); else protocol_send_header(c->p,key,val); return 1; } static void do_get_headers( void *_c ) { mcontext *c = (mcontext*)_c; ap_table_do(get_client_header,c,c->r->headers_in,NULL); } static void do_get_params( void *_c ) { mcontext *c = (mcontext*)_c; if( c->r->args ) protocol_send_raw_params(c->p,c->r->args); if( c->post_data && c->is_form_post ) protocol_send_raw_params(c->p,c->post_data); } static int do_print( void *_c, const char *buf, int len ) { mcontext *c = (mcontext*)_c; ap_soft_timeout("Client Timeout",c->r); send_headers(c); ap_rwrite(buf,len,c->r); ap_kill_timeout(c->r); return c->r->connection->aborted == 0; } static void do_flush( void *_c ) { mcontext *c = (mcontext*)_c; ap_rflush(c->r); } static void do_set_header( void *_c, const char *key, const char *value, bool add ) { mcontext *c = (mcontext*)_c; if( add ) ap_table_add(c->r->headers_out,key,value); else if( strcmpi(key,"Content-Type") == 0 ) { int len = (int)strlen(value); char *ct = (char*)ap_palloc(c->r->pool,len+1); memcpy(ct,value,len+1); c->r->content_type = ct; } else ap_table_set(c->r->headers_out,key,value); } static void do_set_return_code( void *_c, int code ) { mcontext *c = (mcontext*)_c; c->r->status = code; } static void do_log( void *_c, const char *msg, bool user_log ) { mcontext *c = (mcontext*)_c; if( user_log ) { c->r->content_type = "text/plain"; do_print(c,"Error : ",8); do_print(c,msg,(int)strlen(msg)); } else ap_log_rerror(__FILE__, __LINE__, APLOG_WARNING, LOG_SUCCESS c->r, "[mod_tora] %s", msg); } static void log_error( mcontext *c, const char *msg ) { do_log(c,msg,false); // add to apache log do_log(c,msg,true); // display to user } static int do_stream_data( void *_c, char *buf, int size ) { mcontext *c = (mcontext*)_c; // startup if( size == 0 ) { if( !ap_should_client_block(c->r) ) return -1; c->need_discard = true; return 0; } return ap_get_client_block(c->r,buf,size); } static void discard_body( mcontext *c ) { char buf[1024]; while( ap_get_client_block(c->r,buf,1024) > 0 ) { } } static int tora_handler( request_rec *r ) { mcontext ctx, *c = &ctx; if( strcmp(r->handler,"tora-handler") != 0) return DECLINED; // init context c->need_discard = false; c->is_multipart = false; c->headers_sent = false; c->is_form_post = false; c->r = r; c->post_data = NULL; c->xff = NULL; c->client_ip = NULL; c->p = NULL; c->r->content_type = "text/html"; config.hits++; // read post data { const char *ctype = ap_table_get(r->headers_in,"Content-Type"); ap_setup_client_block(r,REQUEST_CHUNKED_ERROR); if( ctype && strstr(ctype,"multipart/form-data") ) c->is_multipart = true; else if( ap_should_client_block(r) ) { int tlen = 0; c->post_data = (char*)malloc(config.max_post_size); while( true ) { int len = ap_get_client_block(r,c->post_data + tlen,config.max_post_size - tlen); if( len <= 0 ) break; tlen += len; } if( tlen >= config.max_post_size ) { discard_body(c); free(c->post_data); log_error(c,"Maximum POST data exceeded. Try using multipart encoding"); return OK; } c->post_data[tlen] = 0; c->post_data_size = tlen; c->is_form_post = ctype == NULL || (strstr(ctype,"urlencoded") != NULL); } } // init protocol { protocol_infos infos; request_rec *first = r; while( first->prev != NULL ) first = first->prev; infos.custom = c; infos.script = r->filename; infos.uri = first->uri; infos.hostname = r->hostname ? r->hostname : ""; if( config.proxy_mode ) { const char *xff = ap_table_get(r->headers_in,"X-Forwarded-For"); if( xff == NULL ) infos.client_ip = r->connection->remote_ip; else { char tmp; char *xend = (char*)xff + strlen(xff) - 1; while( xend > xff && *xend != ' ' && *xend != ',' ) xend--; c->client_ip = strdup(xend); infos.client_ip = c->client_ip; if( xend > xff && *xend == ' ' && xend[-1] == ',' ) xend--; tmp = *xend; *xend = 0; c->xff = strdup(xff); *xend = tmp; } } else infos.client_ip = inet_ntoa(REMOTE_ADDR(r->connection)); infos.http_method = r->method; infos.get_data = r->args; infos.post_data = c->post_data; infos.post_data_size = c->post_data_size; infos.content_type = ap_table_get(r->headers_in,"Content-Type"); infos.do_get_headers = do_get_headers; infos.do_get_params = do_get_params; infos.do_set_header = do_set_header; infos.do_set_return_code = do_set_return_code; infos.do_print = do_print; infos.do_flush = do_flush; infos.do_log = do_log; infos.do_stream_data = c->is_multipart ? do_stream_data : NULL; c->p = protocol_init(&infos); } // run protocol { int port = config.port_min + (config.hits % (1 + config.port_max - config.port_min)); if( !protocol_connect(c->p,config.host,port) || !protocol_send_request(c->p) || !protocol_read_answer(c->p) ) log_error(c,protocol_get_error(c->p)); } // cleanup protocol_free(c->p); free(c->xff); free(c->client_ip); free(c->post_data); send_headers(c); // in case... if( c->need_discard ) discard_body(c); return OK; } static void mod_tora_do_init() { int tmp = 0; if( init_done ) return; init_done = true; memset(&config,0,sizeof(config)); config.host = DEFAULT_HOST; config.port_min = DEFAULT_PORT; config.port_max = DEFAULT_PORT; config.max_post_size = DEFAULT_MAX_POST_DATA; } #ifdef APACHE_2_X # define MCONFIG void* #else # define MCONFIG char* #endif static const char *mod_tora_config( cmd_parms *cmd, MCONFIG mconfig, const char *fargs ) { char *code = strdup(fargs); char *args = code; int value; while( true ) { char c = *args; if( c == 0 || c == ' ' || c == '\t' ) break; args++; } while( *args == ' ' || *args == '\t' ) *args++ = 0; value = atoi(args); mod_tora_do_init(); if( strcmp(code,"HOST") == 0 ) config.host = strdup(args); else if( strcmp(code,"PORT") == 0 ) { config.port_min = value; config.port_max = value; } else if( strcmp(code,"PORT_MAX") == 0 ) config.port_max = value; else if( strcmp(code,"POST_SIZE") == 0 ) config.max_post_size = value; else if( strcmp(code,"PROXY_MODE") == 0 ) config.proxy_mode = value; else ap_log_error(__FILE__,__LINE__,APLOG_WARNING,LOG_SUCCESS cmd->server,"Unknown ModTora configuration command '%s'",code); free(code); return NULL; } #ifdef APACHE_2_X static int tora_init( apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s ) { mod_tora_do_init(); return OK; } #else static void tora_init(server_rec *s, pool *p) { mod_tora_do_init(); } #endif static command_rec tora_module_cmds[] = { # ifdef APACHE_2_X AP_INIT_RAW_ARGS( "ModTora", mod_tora_config , NULL, RSRC_CONF, NULL ), # else { "ModTora", mod_tora_config, NULL, RSRC_CONF, RAW_ARGS, NULL }, # endif { NULL } }; #ifdef APACHE_2_X static void tora_register_hooks( apr_pool_t *p ) { ap_hook_post_config( tora_init, NULL, NULL, APR_HOOK_MIDDLE ); ap_hook_handler( tora_handler, NULL, NULL, APR_HOOK_LAST ); }; module AP_MODULE_DECLARE_DATA tora_module = { STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, tora_module_cmds, tora_register_hooks }; #else /* APACHE 1.3 */ static const handler_rec tora_handlers[] = { {"tora-handler", tora_handler}, {NULL} }; module MODULE_VAR_EXPORT tora_module = { STANDARD_MODULE_STUFF, tora_init, NULL, NULL, NULL, NULL, tora_module_cmds, tora_handlers, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #endif /* ************************************************************************ */ neko-2.0.0/libs/std/0000755000175000017500000000000012112157473014677 5ustar ncannassencannasseneko-2.0.0/libs/std/utf8.c0000644000175000017500000002442212112157473015735 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include /**

UTF8

Operations on UTF8 strings. Most of the operations are optimized for speed so they might still succeed on some malformed UTF8 string. The only function that completely check the UTF8 format is [utf8_validate]. Other functions might raise some exception or not depending on the malformed data.

**/ typedef struct { value buf; int pos; int nesc; } ubuf; DEFINE_KIND(k_ubuf); /** utf8_buf_alloc : size:int -> 'ubuf Create a new buffer with an initial size in bytes **/ static value utf8_buf_alloc( value size ) { ubuf *b; val_check(size,int); if( val_int(size) < 0 ) neko_error(); b = (ubuf*)alloc(sizeof(ubuf)); b->buf = alloc_empty_string(val_int(size)); b->nesc = 0; b->pos = 0; return alloc_abstract(k_ubuf,b); } static void utf8_buf_resize( ubuf *b ) { value s; int len = val_strlen(b->buf); // allocate a number of bytes depending on previously // escaped caracters, with a minimum of 10 int nbytes = (b->nesc + b->pos * 2 - 1) / (b->pos?b->pos:1); if( nbytes < 10 ) nbytes = 10; s = alloc_empty_string(len+nbytes); memcpy(val_string(s),val_string(b->buf),len); b->buf = s; } /** utf8_buf_add : 'buf -> int -> void Add a valid UTF8 char (0 - 0x10FFFF) to the buffer **/ static value utf8_buf_add( value buf, value uchar ) { ubuf *b; unsigned char *s; unsigned int c; val_check_kind(buf,k_ubuf); val_check(uchar,int); b = (ubuf*)val_data(buf); c = (unsigned)val_int(uchar); if( c <= 0x7F ) { if( b->pos >= val_strlen(b->buf) ) utf8_buf_resize(b); val_string(b->buf)[b->pos++] = (char)c; return val_true; } if( b->pos + 4 > val_strlen(b->buf) ) utf8_buf_resize(b); s = (unsigned char*)val_string(b->buf); if( c <= 0x7FF ) { b->nesc += 1; s[b->pos++] = 0xC0 | (c >> 6); s[b->pos++] = 0x80 | (c & 63); } else if( c <= 0xFFFF ) { b->nesc += 2; s[b->pos++] = 0xE0 | (c >> 12); s[b->pos++] = 0x80 | ((c >> 6) & 63); s[b->pos++] = 0x80 | (c & 63); } else if( c <= 0x10FFFF ) { b->nesc += 3; s[b->pos++] = 0xF0 | (c >> 18); s[b->pos++] = 0x80 | ((c >> 12) & 63); s[b->pos++] = 0x80 | ((c >> 6) & 63); s[b->pos++] = 0x80 | (c & 63); } else neko_error(); return val_true; } /** utf8_buf_content : 'buf -> string Return the current content of the buffer. This is not a copy of the buffer but the shared content. Retreiving content and then continuing to add chars is possible but not very efficient. **/ static value utf8_buf_content( value buf ) { ubuf *b; val_check_kind(buf,k_ubuf); b = (ubuf*)val_data(buf); val_set_length(b->buf,b->pos); return b->buf; } /** utf8_buf_length : 'buf -> int Return the number of UTF8 chars stored in the buffer **/ static value utf8_buf_length( value buf ) { ubuf *b; val_check_kind(buf,k_ubuf); b = (ubuf*)val_data(buf); return alloc_int(b->pos - b->nesc); } /** utf8_buf_size : 'buf -> int Return the current size in bytes of the buffer **/ static value utf8_buf_size( value buf ) { ubuf *b; val_check_kind(buf,k_ubuf); b = (ubuf*)val_data(buf); return alloc_int(b->pos); } /** utf8_validate : string -> bool Validate if a string is encoded using the UTF8 format **/ static value utf8_validate( value str ) { int l; unsigned char *s; val_check(str,string); l = val_strlen(str); s = (unsigned char*)val_string(str); while( l-- ) { unsigned char c = *s++; if( c < 0x7F ) continue; else if( c < 0xC0 ) return val_false; else if( c < 0xE0 ) { if( (*s++ & 0x80) != 0x80 ) return val_false; l--; } else if( c < 0xF0 ) { if( (*s++ & 0x80) != 0x80 ) return val_false; if( (*s++ & 0x80) != 0x80 ) return val_false; l-=2; } else { if( (*s++ & 0x80) != 0x80 ) return val_false; if( (*s++ & 0x80) != 0x80 ) return val_false; if( (*s++ & 0x80) != 0x80 ) return val_false; l-=3; } } return val_true; } /** utf8_length : string -> int Returns the number of UTF8 chars in the string. **/ static value utf8_length( value str ) { int l; int count = 0; unsigned char *s; val_check(str,string); l = val_strlen(str); s = (unsigned char*)val_string(str); while( l > 0 ) { unsigned char c = *s; count++; if( c < 0x7F ) { l--; s++; } else if( c < 0xC0 ) neko_error(); else if( c < 0xE0 ) { l-=2; s+=2; } else if( c < 0xF0 ) { l-=3; s+=3; } else { l-=4; s+=4; } } if( l < 0 ) neko_error(); return alloc_int(count); } /** utf8_sub : string -> pos:int -> len:int -> string Returns a part of an UTF8 string. **/ static value utf8_sub( value str, value pos, value len ) { int l; int count; unsigned char *s, *save; val_check(str,string); val_check(pos,int); val_check(len,int); l = val_strlen(str); count = val_int(pos); if( count < 0 ) neko_error(); s = (unsigned char*)val_string(str); while( count-- && l > 0 ) { unsigned char c = *s; if( c < 0x7F ) { l--; s++; } else if( c < 0xC0 ) neko_error(); else if( c < 0xE0 ) { l-=2; s+=2; } else if( c < 0xF0 ) { l-=3; s+=3; } else { l-=4; s+=4; } } if( l < 0 ) neko_error(); save = s; count = val_int(len); if( count < 0 ) neko_error(); while( count-- && l > 0 ) { unsigned char c = *s; if( c < 0x7F ) { l--; s++; } else if( c < 0xC0 ) neko_error(); else if( c < 0xE0 ) { l-=2; s+=2; } else if( c < 0xF0 ) { l-=3; s+=3; } else { l-=4; s+=4; } } if( l < 0 ) neko_error(); l = (int)(s - save); str = alloc_empty_string(l); memcpy(val_string(str),save,l); return str; } /** utf8_get : string -> n:int -> int Returns the [n]th char in an UTF8 string. This might be inefficient if [n] is big. **/ static value utf8_get( value str, value pos ) { int l; int p; unsigned char *s; val_check(pos,int); val_check(str,string); l = val_strlen(str); p = val_int(pos); if( p < 0 ) neko_error(); s = (unsigned char*)val_string(str); while( l-- ) { unsigned char c = *s++; if( c < 0x7F ) { if( p-- == 0 ) return alloc_int(c); } else if( c < 0xC0 ) neko_error(); else if( c < 0xE0 ) { l--; if( l < 0 ) neko_error(); if( p-- == 0 ) return alloc_int(((c & 0x3F) << 6) | ((*s) & 0x7F)); s++; } else if( c < 0xF0 ) { l -= 2; if( l < 0 ) neko_error(); if( p-- == 0 ) return alloc_int(((c & 0x1F) << 12) | (((*s) & 0x7F) << 6) | (s[1] & 0x7F)); s += 2; } else { l -= 3; if( l < 0 ) neko_error(); if( p-- == 0 ) return alloc_int(((c & 0x0F) << 18) | (((*s) & 0x7F) << 12) | ((s[1] & 0x7F) << 6) | (s[2] & 0x7F)); s += 3; } } neko_error(); return val_true; } /** utf8_iter : string -> f:(int -> void) -> void Call [f] with each of UTF8 char of the string. **/ static value utf8_iter( value str, value f ) { int l; unsigned char *s; val_check(str,string); val_check_function(f,1); l = val_strlen(str); s = (unsigned char*)val_string(str); while( l-- ) { unsigned char c = *s++; if( c < 0x7F ) val_call1(f,alloc_int(c)); else if( c < 0xC0 ) neko_error(); else if( c < 0xE0 ) { l--; if( l < 0 ) neko_error(); val_call1(f,alloc_int(((c & 0x3F) << 6) | ((*s) & 0x7F))); s++; } else if( c < 0xF0 ) { l -= 2; if( l < 0 ) neko_error(); val_call1(f,alloc_int(((c & 0x1F) << 12) | (((*s) & 0x7F) << 6) | (s[1] & 0x7F))); s += 2; } else { l -= 3; if( l < 0 ) neko_error(); val_call1(f,alloc_int(((c & 0x0F) << 18) | (((*s) & 0x7F) << 12) | ((s[1] & 0x7F) << 6) | (s[2] & 0x7F))); s += 3; } } return val_true; } /** utf8_compare : s1:string -> s2:string -> int Compare two UTF8 strings according to UTF8 char codes. **/ static value utf8_compare( value str1, value str2 ) { int l1, l2, l; unsigned char *s1, *s2; val_check(str1,string); val_check(str2,string); l1 = val_strlen(str1); l2 = val_strlen(str2); s1 = (unsigned char*)val_string(str1); s2 = (unsigned char*)val_string(str2); l = (l1 < l2)?l1:l2; while( l-- ) { unsigned char c1 = *s1++; unsigned char c2 = *s1++; if( c1 != c2 ) return alloc_int((c1 > c2)?-1:1); if( c1 < 0x7F ) continue; else if( c1 < 0xC0 ) neko_error(); else if( c1 < 0xE0 ) { l--; if( l < 0 ) neko_error(); if( *s1++ != *s2++ ) return alloc_int((s1[-1] > s2[-1])?-1:1); } else if( c1 < 0xF0 ) { l-=2; if( l < 0 ) neko_error(); if( *s1++ != *s2++ ) return alloc_int((s1[-1] > s2[-1])?-1:1); if( *s1++ != *s2++ ) return alloc_int((s1[-1] > s2[-1])?-1:1); } else { l -= 3; if( l < 0 ) neko_error(); if( *s1++ != *s2++ ) return alloc_int((s1[-1] > s2[-1])?-1:1); if( *s1++ != *s2++ ) return alloc_int((s1[-1] > s2[-1])?-1:1); if( *s1++ != *s2++ ) return alloc_int((s1[-1] > s2[-1])?-1:1); } } if( l1 != l2 ) return alloc_int((l1 > l2)?1:-1); return alloc_int(0); } DEFINE_PRIM(utf8_buf_alloc,1); DEFINE_PRIM(utf8_buf_add,2); DEFINE_PRIM(utf8_buf_content,1); DEFINE_PRIM(utf8_buf_length,1); DEFINE_PRIM(utf8_buf_size,1); DEFINE_PRIM(utf8_get,2); DEFINE_PRIM(utf8_validate,1); DEFINE_PRIM(utf8_iter,2); DEFINE_PRIM(utf8_length,1); DEFINE_PRIM(utf8_compare,2); DEFINE_PRIM(utf8_sub,3); /* ************************************************************************ */ neko-2.0.0/libs/std/random.c0000644000175000017500000001034412112157473016325 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #ifdef NEKO_WINDOWS # include # include #else # include # include # include #endif /**

Random

A seeded pseudo-random generator

**/ DEFINE_KIND(k_random); #define val_rnd(o) ((rnd*)val_data(o)) #define NSEEDS 25 #define MAX 7 typedef struct _rnd rnd; struct _rnd { unsigned long seeds[NSEEDS]; unsigned long cur; }; static unsigned long mag01[2]={ 0x0, 0x8ebfd028 // magic, don't change }; static const unsigned long init_seeds[] = { 0x95f24dab, 0x0b685215, 0xe76ccae7, 0xaf3ec239, 0x715fad23, 0x24a590ad, 0x69e4b5ef, 0xbf456141, 0x96bc1b7b, 0xa7bdf825, 0xc1de75b7, 0x8858a9c9, 0x2da87693, 0xb657f9dd, 0xffdc8a9f, 0x8121da71, 0x8b823ecb, 0x885d05f5, 0x4e20cd47, 0x5a9ad5d9, 0x512c0c03, 0xea857ccd, 0x4cc1d30f, 0x8891a8a1, 0xa6b7aadb }; static int rnd_size() { return sizeof(rnd); } static void rnd_set_seed( rnd *r, int s ) { int i; r->cur = 0; memcpy(r->seeds,init_seeds,sizeof(init_seeds)); for(i=0;iseeds[i] ^= s; } static rnd *rnd_init( void *data ) { rnd *r = (rnd*)data; int pid = getpid(); unsigned int time; #ifdef NEKO_WINDOWS time = GetTickCount(); #else struct timeval t; gettimeofday(&t,NULL); time = t.tv_sec * 1000000 + t.tv_usec; #endif rnd_set_seed(r,time ^ (pid | (pid << 16))); return r; } static unsigned int rnd_int( rnd *r ) { unsigned int y; int pos = r->cur++; if( pos >= NSEEDS ) { int kk; for(kk=0;kkseeds[kk] = r->seeds[kk+MAX] ^ (r->seeds[kk] >> 1) ^ mag01[r->seeds[kk] % 2]; for(;kkseeds[kk] = r->seeds[kk+(MAX-NSEEDS)] ^ (r->seeds[kk] >> 1) ^ mag01[r->seeds[kk] % 2]; r->cur = 1; pos = 0; } y = r->seeds[pos]; y ^= (y << 7) & 0x2b5b2500; y ^= (y << 15) & 0xdb8b0000; y ^= (y >> 16); return y; } static double rnd_float( rnd *r ) { double big = 4294967296.0; return ((rnd_int(r) / big + rnd_int(r)) / big + rnd_int(r)) / big; } /** random_new : void -> 'random Create a new random with random seed **/ static value random_new() { return alloc_abstract( k_random, rnd_init(alloc_private(rnd_size())) ); } /** random_set_seed : 'random -> int -> void Set the generator seed **/ static value random_set_seed( value o, value v ) { val_check_kind(o,k_random); val_check(v,any_int); rnd_set_seed(val_rnd(o),val_any_int(v)); return val_true; } /** random_int : 'random -> max:int -> int Return a random integer modulo [max] **/ static value random_int( value o, value max ) { val_check_kind(o,k_random); val_check(max,int); if( val_int(max) <= 0 ) return alloc_int(0); return alloc_int( (rnd_int(val_rnd(o)) & 0x3FFFFFFF) % val_int(max) ); } /** random_float : 'random -> float Return a random float **/ static value random_float( value o ) { val_check_kind(o,k_random); return alloc_float( rnd_float(val_rnd(o)) ); } DEFINE_PRIM(random_new,0); DEFINE_PRIM(random_set_seed,2); DEFINE_PRIM(random_int,2); DEFINE_PRIM(random_float,1); /* ************************************************************************ */ neko-2.0.0/libs/std/socket.c0000644000175000017500000005436412112157473016347 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #ifdef NEKO_WINDOWS # include # define FDSIZE(n) (sizeof(u_int) + (n) * sizeof(SOCKET)) # define SHUT_WR SD_SEND # define SHUT_RD SD_RECEIVE # define SHUT_RDWR SD_BOTH static bool init_done = false; static WSADATA init_data; #else # include # include # include # include # include # include # include # include # include # include # include # include typedef int SOCKET; # define closesocket close # define SOCKET_ERROR (-1) # define INVALID_SOCKET (-1) #endif #if defined(NEKO_WINDOWS) || defined(NEKO_MAC) # define MSG_NOSIGNAL 0 #endif #define NRETRYS 20 typedef struct { SOCKET sock; char *buf; int size; int ret; } sock_tmp; typedef struct { int max; # ifdef NEKO_WINDOWS struct fd_set *fdr; struct fd_set *fdw; struct fd_set *outr; struct fd_set *outw; # else struct pollfd *fds; int rcount; int wcount; # endif value ridx; value widx; } polldata; DEFINE_KIND(k_socket); DEFINE_KIND(k_poll); #define val_sock(o) ((SOCKET)(int_val)val_data(o)) #define val_poll(o) ((polldata*)val_data(o)) /**

Socket

TCP and UDP sockets

**/ static value block_error() { #ifdef NEKO_WINDOWS int err = WSAGetLastError(); if( err == WSAEWOULDBLOCK || err == WSAEALREADY || err == WSAETIMEDOUT ) #else if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY ) #endif val_throw(alloc_string("Blocking")); neko_error(); return val_true; } /** socket_init : void -> void Initialize the socket API. Must be called at least once per process before using any socket or host function. **/ static value socket_init() { #ifdef NEKO_WINDOWS if( !init_done ) { WSAStartup(MAKEWORD(2,0),&init_data); init_done = true; } #endif return val_true; } /** socket_new : udp:bool -> 'socket Create a new socket, TCP or UDP **/ static value socket_new( value udp ) { SOCKET s; val_check(udp,bool); if( val_bool(udp) ) s = socket(AF_INET,SOCK_DGRAM,0); else s = socket(AF_INET,SOCK_STREAM,0); if( s == INVALID_SOCKET ) neko_error(); # ifdef NEKO_MAC setsockopt(s,SOL_SOCKET,SO_NOSIGPIPE,NULL,0); # endif # ifdef NEKO_POSIX // we don't want sockets to be inherited in case of exec { int old = fcntl(s,F_GETFD,0); if( old >= 0 ) fcntl(s,F_SETFD,old|FD_CLOEXEC); } # endif return alloc_abstract(k_socket,(value)(int_val)s); } /** socket_close : 'socket -> void Close a socket. Any subsequent operation on this socket will fail **/ static value socket_close( value o ) { val_check_kind(o,k_socket); POSIX_LABEL(close_again); if( closesocket(val_sock(o)) ) { HANDLE_EINTR(close_again); } val_kind(o) = NULL; return val_true; } /** socket_send_char : 'socket -> int -> void Send a character over a connected socket. Must be in the range 0..255 **/ static value socket_send_char( value o, value v ) { int c; unsigned char cc; val_check_kind(o,k_socket); val_check(v,int); c = val_int(v); if( c < 0 || c > 255 ) neko_error(); cc = (unsigned char)c; POSIX_LABEL(send_char_again); if( send(val_sock(o),&cc,1,MSG_NOSIGNAL) == SOCKET_ERROR ) { HANDLE_EINTR(send_char_again); return block_error(); } return val_true; } /** socket_send : 'socket -> buf:string -> pos:int -> len:int -> int Send up to [len] bytes from [buf] starting at [pos] over a connected socket. Return the number of bytes sent. **/ static value socket_send( value o, value data, value pos, value len ) { int p,l,dlen; val_check_kind(o,k_socket); val_check(data,string); val_check(pos,int); val_check(len,int); p = val_int(pos); l = val_int(len); dlen = val_strlen(data); if( p < 0 || l < 0 || p > dlen || p + l > dlen ) neko_error(); POSIX_LABEL(send_again); dlen = send(val_sock(o), val_string(data) + p , l, MSG_NOSIGNAL); if( dlen == SOCKET_ERROR ) { HANDLE_EINTR(send_again); return block_error(); } return alloc_int(dlen); } static void tmp_recv( void *_t ) { sock_tmp *t = (sock_tmp*)_t; t->ret = recv(t->sock,t->buf,t->size,MSG_NOSIGNAL); } /** socket_recv : 'socket -> buf:string -> pos:int -> len:int -> int Read up to [len] bytes from [buf] starting at [pos] from a connected socket. Return the number of bytes readed. **/ static value socket_recv( value o, value data, value pos, value len ) { int p,l,dlen,ret; int retry = 0; val_check_kind(o,k_socket); val_check(data,string); val_check(pos,int); val_check(len,int); p = val_int(pos); l = val_int(len); dlen = val_strlen(data); if( p < 0 || l < 0 || p > dlen || p + l > dlen ) neko_error(); POSIX_LABEL(recv_again); if( retry++ > NRETRYS ) { sock_tmp t; t.sock = val_sock(o); t.buf = val_string(data) + p; t.size = l; neko_thread_blocking(tmp_recv,&t); ret = t.ret; } else ret = recv(val_sock(o), val_string(data) + p , l, MSG_NOSIGNAL); if( ret == SOCKET_ERROR ) { HANDLE_EINTR(recv_again); return block_error(); } return alloc_int(ret); } /** socket_recv_char : 'socket -> int Read a single char from a connected socket. **/ static value socket_recv_char( value o ) { int ret; int retry = 0; unsigned char cc; val_check_kind(o,k_socket); POSIX_LABEL(recv_char_again); if( retry++ > NRETRYS ) { sock_tmp t; t.sock = val_sock(o); t.buf = (char*)&cc; t.size = 1; neko_thread_blocking(tmp_recv,&t); ret = t.ret; } else ret = recv(val_sock(o),&cc,1,MSG_NOSIGNAL); if( ret == SOCKET_ERROR ) { HANDLE_EINTR(recv_char_again); return block_error(); } if( ret == 0 ) neko_error(); return alloc_int(cc); } /** socket_write : 'socket -> string -> void Send the whole content of a string over a connected socket. **/ static value socket_write( value o, value data ) { const char *cdata; int datalen, slen; val_check_kind(o,k_socket); val_check(data,string); cdata = val_string(data); datalen = val_strlen(data); while( datalen > 0 ) { POSIX_LABEL(write_again); slen = send(val_sock(o),cdata,datalen,MSG_NOSIGNAL); if( slen == SOCKET_ERROR ) { HANDLE_EINTR(write_again); return block_error(); } cdata += slen; datalen -= slen; } return val_true; } /** socket_read : 'socket -> string Read the whole content of a the data available from a socket until the connection close. If the socket hasn't been close by the other side, the function might block. **/ static value socket_read( value o ) { buffer b; char buf[256]; int len; val_check_kind(o,k_socket); b = alloc_buffer(NULL); while( true ) { POSIX_LABEL(read_again); len = recv(val_sock(o),buf,256,MSG_NOSIGNAL); if( len == SOCKET_ERROR ) { HANDLE_EINTR(read_again); return block_error(); } if( len == 0 ) break; buffer_append_sub(b,buf,len); } return buffer_to_string(b); } /** host_resolve : string -> 'int32 Resolve the given host string into an IP address. **/ static value host_resolve( value host ) { unsigned int ip; val_check(host,string); ip = inet_addr(val_string(host)); if( ip == INADDR_NONE ) { struct hostent *h; # if defined(NEKO_WINDOWS) || defined(NEKO_MAC) h = gethostbyname(val_string(host)); # else struct hostent hbase; char buf[1024]; int errcode; gethostbyname_r(val_string(host),&hbase,buf,1024,&h,&errcode); # endif if( h == NULL ) neko_error(); ip = *((unsigned int*)h->h_addr); } return alloc_int32(ip); } /** host_to_string : 'int32 -> string Return a string representation of the IP address. **/ static value host_to_string( value ip ) { struct in_addr i; val_check(ip,int32); *(int*)&i = val_int32(ip); return alloc_string( inet_ntoa(i) ); } /** host_reverse : 'int32 -> string Reverse the DNS of the given IP address. **/ static value host_reverse( value host ) { struct hostent *h; unsigned int ip; val_check(host,int32); ip = val_int32(host); # if defined(NEKO_WINDOWS) || defined(NEKO_MAC) h = gethostbyaddr((char *)&ip,4,AF_INET); # else struct hostent htmp; int errcode; char buf[1024]; gethostbyaddr_r((char *)&ip,4,AF_INET,&htmp,buf,1024,&h,&errcode); # endif if( h == NULL ) neko_error(); return alloc_string( h->h_name ); } /** host_local : void -> string Return the local host name. **/ static value host_local() { char buf[256]; if( gethostname(buf,256) == SOCKET_ERROR ) neko_error(); return alloc_string(buf); } /** socket_connect : 'socket -> host:'int32 -> port:int -> void Connect the socket the given [host] and [port] **/ static value socket_connect( value o, value host, value port ) { struct sockaddr_in addr; val_check_kind(o,k_socket); val_check(host,int32); val_check(port,int); memset(&addr,0,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(val_int(port)); *(int*)&addr.sin_addr.s_addr = val_int32(host); if( connect(val_sock(o),(struct sockaddr*)&addr,sizeof(addr)) != 0 ) return block_error(); return val_true; } /** socket_listen : 'socket -> int -> void Listen for a number of connections **/ static value socket_listen( value o, value n ) { val_check_kind(o,k_socket); val_check(n,int); if( listen(val_sock(o),val_int(n)) == SOCKET_ERROR ) neko_error(); return val_true; } static fd_set INVALID; static fd_set *make_socket_array( value a, fd_set *tmp, SOCKET *n ) { int i, len; SOCKET sock; if( val_is_null(a) ) return NULL; if( !val_is_array(a) ) return &INVALID; len = val_array_size(a); if( len > FD_SETSIZE ) val_throw(alloc_string("Too many sockets in select")); FD_ZERO(tmp); for(i=0;i *n ) *n = sock; FD_SET(sock,tmp); } return tmp; } static value make_array_result( value a, fd_set *tmp ) { value r; int i, len; int pos = 0; if( tmp == NULL ) return val_null; len = val_array_size(a); r = alloc_array(len); for(i=0;itv_usec = (int)((f - (int)f) * 1000000); t->tv_sec = (int)f; } /** socket_select : read : 'socket array -> write : 'socket array -> others : 'socket array -> timeout:number? -> 'socket array array Perform the [select] operation. Timeout is in seconds or [null] if infinite **/ static value socket_select( value rs, value ws, value es, value timeout ) { struct timeval tval; struct timeval *tt; SOCKET n = 0; fd_set rx, wx, ex; fd_set *ra, *wa, *ea; value r; POSIX_LABEL(select_again); ra = make_socket_array(rs,&rx,&n); wa = make_socket_array(ws,&wx,&n); ea = make_socket_array(es,&ex,&n); if( ra == &INVALID || wa == &INVALID || ea == &INVALID ) neko_error(); if( val_is_null(timeout) ) tt = NULL; else { val_check(timeout,number); tt = &tval; init_timeval(val_number(timeout),tt); } if( select((int)(n+1),ra,wa,ea,tt) == SOCKET_ERROR ) { HANDLE_EINTR(select_again); neko_error(); } r = alloc_array(3); val_array_ptr(r)[0] = make_array_result(rs,ra); val_array_ptr(r)[1] = make_array_result(ws,wa); val_array_ptr(r)[2] = make_array_result(es,ea); return r; } /** socket_bind : 'socket -> host : 'int32 -> port:int -> void Bind the socket for server usage on the given host and port **/ static value socket_bind( value o, value host, value port ) { int opt = 1; struct sockaddr_in addr; val_check_kind(o,k_socket); val_check(host,int32); val_check(port,int); memset(&addr,0,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(val_int(port)); *(int*)&addr.sin_addr.s_addr = val_int32(host); #ifndef NEKO_WINDOWS setsockopt(val_sock(o),SOL_SOCKET,SO_REUSEADDR,(char*)&opt,sizeof(opt)); #endif if( bind(val_sock(o),(struct sockaddr*)&addr,sizeof(addr)) == SOCKET_ERROR ) neko_error(); return val_true; } /** socket_accept : 'socket -> 'socket Accept an incoming connection request **/ static value socket_accept( value o ) { struct sockaddr_in addr; unsigned int addrlen = sizeof(addr); SOCKET s; val_check_kind(o,k_socket); POSIX_LABEL(accept_again); s = accept(val_sock(o),(struct sockaddr*)&addr,&addrlen); if( s == INVALID_SOCKET ) { HANDLE_EINTR(accept_again); return block_error(); } return alloc_abstract(k_socket,(value)(int_val)s); } /** socket_peer : 'socket -> #address Return the socket connected peer address composed of an (host,port) array **/ static value socket_peer( value o ) { struct sockaddr_in addr; unsigned int addrlen = sizeof(addr); value ret; val_check_kind(o,k_socket); if( getpeername(val_sock(o),(struct sockaddr*)&addr,&addrlen) == SOCKET_ERROR ) neko_error(); ret = alloc_array(2); val_array_ptr(ret)[0] = alloc_int32(*(int*)&addr.sin_addr); val_array_ptr(ret)[1] = alloc_int(ntohs(addr.sin_port)); return ret; } /** socket_host : 'socket -> #address Return the socket local address composed of an (host,port) array **/ static value socket_host( value o ) { struct sockaddr_in addr; unsigned int addrlen = sizeof(addr); value ret; val_check_kind(o,k_socket); if( getsockname(val_sock(o),(struct sockaddr*)&addr,&addrlen) == SOCKET_ERROR ) neko_error(); ret = alloc_array(2); val_array_ptr(ret)[0] = alloc_int32(*(int*)&addr.sin_addr); val_array_ptr(ret)[1] = alloc_int(ntohs(addr.sin_port)); return ret; } /** socket_set_timeout : 'socket -> timout:number? -> void Set the socket send and recv timeout in seconds to the given value (or null for blocking) **/ static value socket_set_timeout( value o, value t ) { #ifdef NEKO_WINDOWS int time; val_check_kind(o,k_socket); if( val_is_null(t) ) time = 0; else { val_check(t,number); time = (int)(val_number(t) * 1000); } #else struct timeval time; val_check_kind(o,k_socket); if( val_is_null(t) ) { time.tv_usec = 0; time.tv_sec = 0; } else { val_check(t,number); init_timeval(val_number(t),&time); } #endif if( setsockopt(val_sock(o),SOL_SOCKET,SO_SNDTIMEO,(char*)&time,sizeof(time)) != 0 ) neko_error(); if( setsockopt(val_sock(o),SOL_SOCKET,SO_RCVTIMEO,(char*)&time,sizeof(time)) != 0 ) neko_error(); return val_true; } /** socket_shutdown : 'socket -> read:bool -> write:bool -> void Prevent the socket from further reading or writing or both. **/ static value socket_shutdown( value o, value r, value w ) { val_check_kind(o,k_socket); val_check(r,bool); val_check(w,bool); if( !val_bool(r) && !val_bool(w) ) return val_true; if( shutdown(val_sock(o),val_bool(r)?(val_bool(w)?SHUT_RDWR:SHUT_RD):SHUT_WR) ) neko_error(); return val_true; } /** socket_set_blocking : 'socket -> bool -> void Turn on/off the socket blocking mode. **/ static value socket_set_blocking( value o, value b ) { val_check_kind(o,k_socket); val_check(b,bool); #ifdef NEKO_WINDOWS { unsigned long arg = val_bool(b)?0:1; if( ioctlsocket(val_sock(o),FIONBIO,&arg) != 0 ) neko_error(); } #else { int rights = fcntl(val_sock(o),F_GETFL); if( rights == -1 ) neko_error(); if( val_bool(b) ) rights &= ~O_NONBLOCK; else rights |= O_NONBLOCK; if( fcntl(val_sock(o),F_SETFL,rights) == -1 ) neko_error(); } #endif return val_true; } /** socket_poll_alloc : int -> 'poll Allocate memory to perform polling on a given number of sockets **/ static value socket_poll_alloc( value nsocks ) { polldata *p; int i; val_check(nsocks,int); p = (polldata*)alloc(sizeof(polldata)); p->max = val_int(nsocks); if( p->max < 0 || p->max > 1000000 ) neko_error(); # ifdef NEKO_WINDOWS { p->fdr = (fd_set*)alloc_private(FDSIZE(p->max)); p->fdw = (fd_set*)alloc_private(FDSIZE(p->max)); p->outr = (fd_set*)alloc_private(FDSIZE(p->max)); p->outw = (fd_set*)alloc_private(FDSIZE(p->max)); p->fdr->fd_count = 0; p->fdw->fd_count = 0; } # else p->fds = (struct pollfd*)alloc_private(sizeof(struct pollfd) * p->max); p->rcount = 0; p->wcount = 0; # endif p->ridx = alloc_array(p->max+1); p->widx = alloc_array(p->max+1); for(i=0;i<=p->max;i++) { val_array_ptr(p->ridx)[i] = alloc_int(-1); val_array_ptr(p->widx)[i] = alloc_int(-1); } return alloc_abstract(k_poll, p); } /** socket_poll_prepare : 'poll -> read:'socket array -> write:'socket array -> int array array Prepare a poll for scanning events on sets of sockets. **/ static value socket_poll_prepare( value pdata, value rsocks, value wsocks ) { polldata *p; int i,len; val_check(rsocks,array); val_check(wsocks,array); val_check_kind(pdata,k_poll); p = val_poll(pdata); len = val_array_size(rsocks); if( len + val_array_size(wsocks) > p->max ) val_throw(alloc_string("Too many sockets in poll")); # ifdef NEKO_WINDOWS for(i=0;ifdr->fd_array[i] = val_sock(s); } p->fdr->fd_count = len; len = val_array_size(wsocks); for(i=0;ifdw->fd_array[i] = val_sock(s); } p->fdw->fd_count = len; # else for(i=0;ifds[i].fd = val_sock(s); p->fds[i].events = POLLIN; p->fds[i].revents = 0; } p->rcount = len; len = val_array_size(wsocks); for(i=0;ircount; value s = val_array_ptr(wsocks)[i]; val_check_kind(s,k_socket); p->fds[k].fd = val_sock(s); p->fds[k].events = POLLOUT; p->fds[k].revents = 0; } p->wcount = len; # endif { value a = alloc_array(2); val_array_ptr(a)[0] = p->ridx; val_array_ptr(a)[1] = p->widx; return a; } } /** socket_poll_events : 'poll -> timeout:float -> void Update the read/write flags arrays that were created with [socket_poll_prepare]. **/ static value socket_poll_events( value pdata, value timeout ) { polldata *p; # ifdef NEKO_WINDOWS unsigned int i; int k = 0; struct timeval t; val_check_kind(pdata,k_poll); p = val_poll(pdata); memcpy(p->outr,p->fdr,FDSIZE(p->fdr->fd_count)); memcpy(p->outw,p->fdw,FDSIZE(p->fdw->fd_count)); val_check(timeout,number); init_timeval(val_number(timeout),&t); if( p->fdr->fd_count + p->fdw->fd_count != 0 && select(0,p->outr,p->outw,NULL,&t) == SOCKET_ERROR ) neko_error(); k = 0; for(i=0;ifdr->fd_count;i++) if( FD_ISSET(p->fdr->fd_array[i],p->outr) ) val_array_ptr(p->ridx)[k++] = alloc_int(i); val_array_ptr(p->ridx)[k] = alloc_int(-1); k = 0; for(i=0;ifdw->fd_count;i++) if( FD_ISSET(p->fdw->fd_array[i],p->outw) ) val_array_ptr(p->widx)[k++] = alloc_int(i); val_array_ptr(p->widx)[k] = alloc_int(-1); #else int i,k; int tot; val_check_kind(pdata,k_poll); val_check(timeout,number); p = val_poll(pdata); tot = p->rcount + p->wcount; POSIX_LABEL(poll_events_again); if( poll(p->fds,tot,(int)(val_number(timeout) * 1000)) < 0 ) { HANDLE_EINTR(poll_events_again); neko_error(); } k = 0; for(i=0;ircount;i++) if( p->fds[i].revents & (POLLIN|POLLHUP) ) val_array_ptr(p->ridx)[k++] = alloc_int(i); val_array_ptr(p->ridx)[k] = alloc_int(-1); k = 0; for(;ifds[i].revents & (POLLOUT|POLLHUP) ) val_array_ptr(p->widx)[k++] = alloc_int(i - p->rcount); val_array_ptr(p->widx)[k] = alloc_int(-1); #endif return val_null; } /** socket_poll : 'socket array -> 'poll -> timeout:float -> 'socket array Perform a polling for data available over a given set of sockets. This is similar to [socket_select] except that [socket_select] is limited to a given number of simultaneous sockets to check. **/ static value socket_poll( value socks, value pdata, value timeout ) { polldata *p; value a; int i, rcount = 0; if( socket_poll_prepare(pdata,socks,alloc_array(0)) == NULL ) neko_error(); if( socket_poll_events(pdata,timeout) == NULL ) neko_error(); p = val_poll(pdata); while( val_array_ptr(p->ridx)[rcount] != alloc_int(-1) ) rcount++; a = alloc_array(rcount); for(i=0;iridx)[i])]; return a; } /** socket_set_fast_send : 'socket -> bool -> void Disable or enable to TCP_NODELAY flag for the socket **/ static value socket_set_fast_send( value s, value f ) { int fast; val_check_kind(s,k_socket); val_check(f,bool); fast = val_bool(f); if( setsockopt(val_sock(s),IPPROTO_TCP,TCP_NODELAY,(char*)&fast,sizeof(fast)) ) neko_error(); return val_null; } DEFINE_PRIM(socket_init,0); DEFINE_PRIM(socket_new,1); DEFINE_PRIM(socket_send,4); DEFINE_PRIM(socket_send_char,2); DEFINE_PRIM(socket_recv,4); DEFINE_PRIM(socket_recv_char,1); DEFINE_PRIM(socket_write,2); DEFINE_PRIM(socket_read,1); DEFINE_PRIM(socket_close,1); DEFINE_PRIM(socket_connect,3); DEFINE_PRIM(socket_listen,2); DEFINE_PRIM(socket_select,4); DEFINE_PRIM(socket_bind,3); DEFINE_PRIM(socket_accept,1); DEFINE_PRIM(socket_peer,1); DEFINE_PRIM(socket_host,1); DEFINE_PRIM(socket_set_timeout,2); DEFINE_PRIM(socket_shutdown,3); DEFINE_PRIM(socket_set_blocking,2); DEFINE_PRIM(socket_set_fast_send,2); DEFINE_PRIM(socket_poll_alloc,1); DEFINE_PRIM(socket_poll,3); DEFINE_PRIM(socket_poll_prepare,3); DEFINE_PRIM(socket_poll_events,2); DEFINE_PRIM(host_local,0); DEFINE_PRIM(host_resolve,1); DEFINE_PRIM(host_to_string,1); DEFINE_PRIM(host_reverse,1); /* ************************************************************************ */ neko-2.0.0/libs/std/math.c0000644000175000017500000001313512112157473015777 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include /**

Math

Mathematical functions

**/ #define MATH_PRIM(f) \ value math_##f( value n ) { \ val_check(n,number); \ return alloc_float( f( val_number(n) ) ); \ } \ DEFINE_PRIM(math_##f,1) /** math_atan2 : number -> number -> float Return atan2 calculus **/ static value math_atan2( value a, value b ) { val_check(a,number); val_check(b,number); return alloc_float( atan2(val_number(a),val_number(b)) ); } /** math_pow : number -> number -> float Return power calculus **/ static value math_pow( value a, value b ) { tfloat r; val_check(a,number); val_check(b,number); r = (tfloat)pow(val_number(a),val_number(b)); if( (int)r == r && fabs(r) < (1 << 31) ) return alloc_best_int((int)r); return alloc_float(r); } /** math_abs : number -> number Return absolute value of a number **/ static value math_abs( value n ) { switch( val_type(n) ) { case VAL_INT: return alloc_int( abs(val_int(n)) ); case VAL_INT32: return alloc_int32( abs(val_int32(n)) ); case VAL_FLOAT: return alloc_float( fabs(val_float(n)) ); default: neko_error(); } } /** math_ceil : number -> int Return rounded-up integer **/ static value math_ceil( value n ) { switch( val_type(n) ) { case VAL_INT: case VAL_INT32: return n; case VAL_FLOAT: return alloc_best_int( (int)ceil(val_float(n)) ); default: neko_error(); } } /** math_floor : number -> int Return rounded-down integer **/ static value math_floor( value n ) { switch( val_type(n) ) { case VAL_INT: case VAL_INT32: return n; case VAL_FLOAT: return alloc_best_int( (int)floor(val_float(n)) ); default: neko_error(); } } /** math_round : number -> int Return nearest integer **/ static value math_round( value n ) { switch( val_type(n) ) { case VAL_INT: case VAL_INT32: return n; case VAL_FLOAT: return alloc_best_int( (int)floor(val_float(n) + 0.5) ); default: neko_error(); } } /** math_fceil : number -> number Return rounded-up float without integer overflow **/ static value math_fceil( value n ) { switch( val_type(n) ) { case VAL_INT: case VAL_INT32: return n; case VAL_FLOAT: return alloc_float( ceil(val_float(n)) ); default: neko_error(); } } /** math_ffloor : number -> number Return rounded-down float without integer overflow **/ static value math_ffloor( value n ) { switch( val_type(n) ) { case VAL_INT: case VAL_INT32: return n; case VAL_FLOAT: return alloc_float( floor(val_float(n)) ); default: neko_error(); } } /** math_fround : number -> number Return rounded float without integer overflow **/ static value math_fround( value n ) { switch( val_type(n) ) { case VAL_INT: case VAL_INT32: return n; case VAL_FLOAT: return alloc_float( floor(val_float(n) + 0.5) ); default: neko_error(); } } /** math_int : number -> int Return integer rounded down towards 0 **/ static value math_int( value n ) { switch( val_type(n) ) { case VAL_INT: case VAL_INT32: return n; case VAL_FLOAT: { tfloat v = val_float(n); return alloc_best_int( (int)((n < 0) ? ceil(v) : floor(v)) ); } default: neko_error(); } } #define PI 3.1415926535897932384626433832795 /** math_pi : void -> float Return the value of PI **/ static value math_pi() { return alloc_float(PI); } /** math_sqrt : number -> float Return the square-root **/ MATH_PRIM(sqrt); /** math_atan : number -> float Return the arc-tangent **/ MATH_PRIM(atan); /** math_cos : number -> float Return the cosinus **/ MATH_PRIM(cos); /** math_sin : number -> float Return the sinus **/ MATH_PRIM(sin); /** math_tan : number -> float Return the tangent **/ MATH_PRIM(tan); /** math_log : number -> float Return the logarithm **/ MATH_PRIM(log); /** math_exp : number -> float Return the exponant **/ MATH_PRIM(exp); /** math_acos : number -> float Return the arc-cosinus **/ MATH_PRIM(acos); /** math_asin : number -> float Return the arc-sinus **/ MATH_PRIM(asin); DEFINE_PRIM(math_pi,0); DEFINE_PRIM(math_atan2,2); DEFINE_PRIM(math_pow,2); DEFINE_PRIM(math_abs,1); DEFINE_PRIM(math_ceil,1); DEFINE_PRIM(math_floor,1); DEFINE_PRIM(math_round,1); DEFINE_PRIM(math_fceil,1); DEFINE_PRIM(math_ffloor,1); DEFINE_PRIM(math_fround,1); DEFINE_PRIM(math_int,1); /* ************************************************************************ */ neko-2.0.0/libs/std/md5.c0000644000175000017500000002526112112157473015536 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include "sha1.h" /**

MD5

MD5 digest functions

**/ #ifndef uint8 #define uint8 unsigned char #endif #ifndef uint32 #define uint32 unsigned long int #endif typedef struct { uint32 total[2]; uint32 state[4]; uint8 buffer[64]; } md5_context; #define GET_UINT32(n,b,i) \ { \ (n) = ( (uint32) (b)[(i) ] ) \ | ( (uint32) (b)[(i) + 1] << 8 ) \ | ( (uint32) (b)[(i) + 2] << 16 ) \ | ( (uint32) (b)[(i) + 3] << 24 ); \ } #define PUT_UINT32(n,b,i) \ { \ (b)[(i) ] = (uint8) ( (n) ); \ (b)[(i) + 1] = (uint8) ( (n) >> 8 ); \ (b)[(i) + 2] = (uint8) ( (n) >> 16 ); \ (b)[(i) + 3] = (uint8) ( (n) >> 24 ); \ } static void md5_starts( md5_context *ctx ) { ctx->total[0] = 0; ctx->total[1] = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xEFCDAB89; ctx->state[2] = 0x98BADCFE; ctx->state[3] = 0x10325476; } static void md5_process( md5_context *ctx, uint8 data[64] ) { uint32 X[16], A, B, C, D; GET_UINT32( X[0], data, 0 ); GET_UINT32( X[1], data, 4 ); GET_UINT32( X[2], data, 8 ); GET_UINT32( X[3], data, 12 ); GET_UINT32( X[4], data, 16 ); GET_UINT32( X[5], data, 20 ); GET_UINT32( X[6], data, 24 ); GET_UINT32( X[7], data, 28 ); GET_UINT32( X[8], data, 32 ); GET_UINT32( X[9], data, 36 ); GET_UINT32( X[10], data, 40 ); GET_UINT32( X[11], data, 44 ); GET_UINT32( X[12], data, 48 ); GET_UINT32( X[13], data, 52 ); GET_UINT32( X[14], data, 56 ); GET_UINT32( X[15], data, 60 ); #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) #define P(a,b,c,d,k,s,t) \ { \ a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ } A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; #define F(x,y,z) (z ^ (x & (y ^ z))) P( A, B, C, D, 0, 7, 0xD76AA478 ); P( D, A, B, C, 1, 12, 0xE8C7B756 ); P( C, D, A, B, 2, 17, 0x242070DB ); P( B, C, D, A, 3, 22, 0xC1BDCEEE ); P( A, B, C, D, 4, 7, 0xF57C0FAF ); P( D, A, B, C, 5, 12, 0x4787C62A ); P( C, D, A, B, 6, 17, 0xA8304613 ); P( B, C, D, A, 7, 22, 0xFD469501 ); P( A, B, C, D, 8, 7, 0x698098D8 ); P( D, A, B, C, 9, 12, 0x8B44F7AF ); P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); P( B, C, D, A, 11, 22, 0x895CD7BE ); P( A, B, C, D, 12, 7, 0x6B901122 ); P( D, A, B, C, 13, 12, 0xFD987193 ); P( C, D, A, B, 14, 17, 0xA679438E ); P( B, C, D, A, 15, 22, 0x49B40821 ); #undef F #define F(x,y,z) (y ^ (z & (x ^ y))) P( A, B, C, D, 1, 5, 0xF61E2562 ); P( D, A, B, C, 6, 9, 0xC040B340 ); P( C, D, A, B, 11, 14, 0x265E5A51 ); P( B, C, D, A, 0, 20, 0xE9B6C7AA ); P( A, B, C, D, 5, 5, 0xD62F105D ); P( D, A, B, C, 10, 9, 0x02441453 ); P( C, D, A, B, 15, 14, 0xD8A1E681 ); P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); P( A, B, C, D, 9, 5, 0x21E1CDE6 ); P( D, A, B, C, 14, 9, 0xC33707D6 ); P( C, D, A, B, 3, 14, 0xF4D50D87 ); P( B, C, D, A, 8, 20, 0x455A14ED ); P( A, B, C, D, 13, 5, 0xA9E3E905 ); P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); P( C, D, A, B, 7, 14, 0x676F02D9 ); P( B, C, D, A, 12, 20, 0x8D2A4C8A ); #undef F #define F(x,y,z) (x ^ y ^ z) P( A, B, C, D, 5, 4, 0xFFFA3942 ); P( D, A, B, C, 8, 11, 0x8771F681 ); P( C, D, A, B, 11, 16, 0x6D9D6122 ); P( B, C, D, A, 14, 23, 0xFDE5380C ); P( A, B, C, D, 1, 4, 0xA4BEEA44 ); P( D, A, B, C, 4, 11, 0x4BDECFA9 ); P( C, D, A, B, 7, 16, 0xF6BB4B60 ); P( B, C, D, A, 10, 23, 0xBEBFBC70 ); P( A, B, C, D, 13, 4, 0x289B7EC6 ); P( D, A, B, C, 0, 11, 0xEAA127FA ); P( C, D, A, B, 3, 16, 0xD4EF3085 ); P( B, C, D, A, 6, 23, 0x04881D05 ); P( A, B, C, D, 9, 4, 0xD9D4D039 ); P( D, A, B, C, 12, 11, 0xE6DB99E5 ); P( C, D, A, B, 15, 16, 0x1FA27CF8 ); P( B, C, D, A, 2, 23, 0xC4AC5665 ); #undef F #define F(x,y,z) (y ^ (x | ~z)) P( A, B, C, D, 0, 6, 0xF4292244 ); P( D, A, B, C, 7, 10, 0x432AFF97 ); P( C, D, A, B, 14, 15, 0xAB9423A7 ); P( B, C, D, A, 5, 21, 0xFC93A039 ); P( A, B, C, D, 12, 6, 0x655B59C3 ); P( D, A, B, C, 3, 10, 0x8F0CCC92 ); P( C, D, A, B, 10, 15, 0xFFEFF47D ); P( B, C, D, A, 1, 21, 0x85845DD1 ); P( A, B, C, D, 8, 6, 0x6FA87E4F ); P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); P( C, D, A, B, 6, 15, 0xA3014314 ); P( B, C, D, A, 13, 21, 0x4E0811A1 ); P( A, B, C, D, 4, 6, 0xF7537E82 ); P( D, A, B, C, 11, 10, 0xBD3AF235 ); P( C, D, A, B, 2, 15, 0x2AD7D2BB ); P( B, C, D, A, 9, 21, 0xEB86D391 ); #undef F ctx->state[0] += A; ctx->state[1] += B; ctx->state[2] += C; ctx->state[3] += D; } static void md5_update( md5_context *ctx, uint8 *input, uint32 length ) { uint32 left, fill; if( !length ) return; left = ctx->total[0] & 0x3F; fill = 64 - left; ctx->total[0] += length; ctx->total[0] &= 0xFFFFFFFF; if( ctx->total[0] < length ) ctx->total[1]++; if( left && length >= fill ) { memcpy( (void *) (ctx->buffer + left), (void *) input, fill ); md5_process( ctx, ctx->buffer ); length -= fill; input += fill; left = 0; } while( length >= 64 ) { md5_process( ctx, input ); length -= 64; input += 64; } if( length ) { memcpy( (void *) (ctx->buffer + left), (void *) input, length ); } } static uint8 md5_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 }; static void md5_finish( md5_context *ctx, uint8 digest[16] ) { uint32 last, padn; uint32 high, low; uint8 msglen[8]; high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); PUT_UINT32( low, msglen, 0 ); PUT_UINT32( high, msglen, 4 ); last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); md5_update( ctx, md5_padding, padn ); md5_update( ctx, msglen, 8 ); PUT_UINT32( ctx->state[0], digest, 0 ); PUT_UINT32( ctx->state[1], digest, 4 ); PUT_UINT32( ctx->state[2], digest, 8 ); PUT_UINT32( ctx->state[3], digest, 12 ); } static void md5_uint( md5_context *m, uint32 i ) { md5_update(m,(unsigned char*)&i,4); } typedef struct stack { uint32 pos; value v; md5_context *m; struct stack *next; } stack; // build some integers that are not neko ones (last bit at 0) // this reduce the possible collisions. // bit 0 = 0 // bit 1-2 = // 00 : const (null, true, false, abstract) // 01 : ref // 10 : fun // 11 : array // // md5-similar objects can still be forged, in particular // due to the fact that no special flag is added to the string // digest in order to keep compatibility with standard md5 // implementation. // // For example md5(null) == md5("\000\000\000\000") static void make_md5_fields( value v, field f, void * ); static void make_md5_rec( md5_context *m, value v, stack *cur ) { switch( val_type(v) ) { case VAL_NULL: md5_uint(m,0); break; case VAL_INT: md5_uint(m,(uint32)(int_val)v); break; case VAL_INT32: md5_uint(m,(uint32)val_int32(v)); break; case VAL_BOOL: md5_uint(m,val_bool(v)?8:16); break; case VAL_FLOAT: { tfloat f = val_float(v); md5_update(m,(unsigned char *)&f,sizeof(tfloat)); } break; case VAL_STRING: md5_update(m,(uint8*)val_string(v),(uint32)val_strlen(v)); break; case VAL_OBJECT: case VAL_ARRAY: { stack loc; stack *s = cur; while( s != NULL ) { if( s->v == v ) { md5_uint(m,(s->pos << 3) | 2); return; } s = s->next; } loc.v = v; loc.pos = cur?(cur->pos+1):0; loc.next = cur; loc.m = m; if( val_is_object(v) ) { val_iter_fields(v,make_md5_fields,&loc); v = (value)((vobject*)v)->proto; if( v != NULL ) make_md5_rec(m,v,&loc); } else { int len = val_array_size(v); md5_uint(m,(len << 3) | 6); while( len-- > 0 ) make_md5_rec(m,val_array_ptr(v)[len],&loc); } } break; case VAL_FUNCTION: md5_uint(m,(val_fun_nargs(v) << 3) | 4); break; case VAL_ABSTRACT: md5_uint(m,24); break; } } static void make_md5_fields( value v, field f, void *c ) { stack *s = (stack*)c; md5_uint(s->m,f); make_md5_rec(s->m,v,s); } /** make_md5 : any -> string Build a MD5 digest (16 bytes binary string) from any value. **/ static value make_md5( value v ) { value out = alloc_empty_string(16); md5_context m; md5_starts(&m); make_md5_rec(&m,v,NULL); md5_finish(&m,(uint8 *)val_string(out)); return out; } /** make_sha1 : string -> pos:int -> len:int -> string Build a SHA1 digest for the given substring **/ static value make_sha1( value s, value p, value l ) { SHA1_CTX ctx; SHA1_DIGEST result; int pp , ll; val_check(s,string); val_check(p,int); val_check(l,int); pp = val_int(p); ll = val_int(l); if( pp < 0 || ll < 0 || pp + ll < 0 || pp + ll > val_strlen(s) ) neko_error(); sha1_init(&ctx); sha1_update(&ctx,(unsigned char*)val_string(l)+pp,ll); sha1_final(&ctx,result); return copy_string( (char*)result, sizeof(SHA1_DIGEST) ); } DEFINE_PRIM(make_md5,1); DEFINE_PRIM(make_sha1,3); /* ************************************************************************ */ neko-2.0.0/libs/std/file.c0000644000175000017500000001717612112157473015776 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #ifdef NEKO_WINDOWS # include #endif /**

File

The file api can be used for different kind of file I/O.

**/ typedef struct { value name; FILE *io; } fio; #define val_file(o) ((fio*)val_data(o)) DEFINE_KIND(k_file); static void file_error( const char *msg, fio *f ) { value a = alloc_array(2); val_array_ptr(a)[0] = alloc_string(msg); val_array_ptr(a)[1] = alloc_string(val_string(f->name)); val_throw(a); } /** file_open : f:string -> r:string -> 'file Call the C function [fopen] with the file path and access rights. Return the opened file or throw an exception if the file couldn't be open. **/ static value file_open( value name, value r ) { fio *f; val_check(name,string); val_check(r,string); f = (fio*)alloc(sizeof(fio)); f->name = alloc_string(val_string(name)); f->io = fopen(val_string(name),val_string(r)); if( f->io == NULL ) file_error("file_open",f); return alloc_abstract(k_file,f); } /** file_close : 'file -> void Close an file. Any other operations on this file will fail **/ static value file_close( value o ) { fio *f; val_check_kind(o,k_file); f = val_file(o); fclose(f->io); val_kind(o) = NULL; return val_null; } /** file_name : 'file -> string Return the name of the file which was opened **/ static value file_name( value o ) { val_check_kind(o,k_file); return alloc_string(val_string(val_file(o)->name)); } /** file_write : 'file -> s:string -> p:int -> l:int -> int Write up to [l] chars of string [s] starting at position [p]. Returns the number of chars written which is >= 0. **/ static value file_write( value o, value s, value pp, value n ) { int p, len; fio *f; val_check_kind(o,k_file); val_check(s,string); val_check(pp,int); val_check(n,int); f = val_file(o); p = val_int(pp); len = val_int(n); if( p < 0 || len < 0 || p > val_strlen(s) || p + len > val_strlen(s) ) neko_error(); while( len > 0 ) { int d; POSIX_LABEL(file_write_again); d = (int)fwrite(val_string(s)+p,1,len,f->io); if( d <= 0 ) { HANDLE_FINTR(f->io,file_write_again); file_error("file_write",f); } p += d; len -= d; } return n; } /** file_read : 'file -> s:string -> p:int -> l:int -> int Read up to [l] chars into the string [s] starting at position [p]. Returns the number of chars readed which is > 0 (or 0 if l == 0). **/ static value file_read( value o, value s, value pp, value n ) { fio *f; int p; int len; val_check_kind(o,k_file); val_check(s,string); val_check(pp,int); val_check(n,int); f = val_file(o); p = val_int(pp); len = val_int(n); if( p < 0 || len < 0 || p > val_strlen(s) || p + len > val_strlen(s) ) neko_error(); while( len > 0 ) { int d; POSIX_LABEL(file_read_again); d = (int)fread((char*)val_string(s)+p,1,len,f->io); if( d <= 0 ) { int size = val_int(n) - len; HANDLE_FINTR(f->io,file_read_again); if( size == 0 ) file_error("file_read",f); return alloc_int(size); } p += d; len -= d; } return n; } /** file_write_char : 'file -> c:int -> void Write the char [c]. Error if [c] outside of the range 0..255 **/ static value file_write_char( value o, value c ) { unsigned char cc; fio *f; val_check(c,int); val_check_kind(o,k_file); if( val_int(c) < 0 || val_int(c) > 255 ) neko_error(); cc = (char)val_int(c); f = val_file(o); POSIX_LABEL(write_char_again); if( fwrite(&cc,1,1,f->io) != 1 ) { HANDLE_FINTR(f->io,write_char_again); file_error("file_write_char",f); } return val_null; } /** file_read_char : 'file -> int Read a char from the file. Exception on error **/ static value file_read_char( value o ) { unsigned char cc; fio *f; val_check_kind(o,k_file); f = val_file(o); POSIX_LABEL(read_char_again); if( fread(&cc,1,1,f->io) != 1 ) { HANDLE_FINTR(f->io,read_char_again); file_error("file_read_char",f); } return alloc_int(cc); } /** file_seek : 'file -> pos:int -> mode:int -> void Use [fseek] to move the file pointer. **/ static value file_seek( value o, value pos, value kind ) { fio *f; val_check_kind(o,k_file); val_check(pos,int); val_check(kind,int); f = val_file(o); if( fseek(f->io,val_int(pos),val_int(kind)) != 0 ) file_error("file_seek",f); return val_null; } /** file_tell : 'file -> int Return the current position in the file **/ static value file_tell( value o ) { int p; fio *f; val_check_kind(o,k_file); f = val_file(o); p = ftell(f->io); if( p == -1 ) file_error("file_tell",f); return alloc_int(p); } /** file_eof : 'file -> bool Tell if we have reached the end of the file **/ static value file_eof( value o ) { val_check_kind(o,k_file); return alloc_bool( feof(val_file(o)->io) ); } /** file_flush : 'file -> void Flush the file buffer **/ static value file_flush( value o ) { fio *f; val_check_kind(o,k_file); f = val_file(o); if( fflush( f->io ) != 0 ) file_error("file_flush",f); return val_true; } /** file_contents : f:string -> string Read the content of the file [f] and return it. **/ static value file_contents( value name ) { value s; fio f; int len; int p; val_check(name,string); f.name = name; f.io = fopen(val_string(name),"rb"); if( f.io == NULL ) file_error("file_contents",&f); fseek(f.io,0,SEEK_END); len = ftell(f.io); fseek(f.io,0,SEEK_SET); s = alloc_empty_string(len); p = 0; while( len > 0 ) { int d; POSIX_LABEL(file_contents); d = (int)fread((char*)val_string(s)+p,1,len,f.io); if( d <= 0 ) { HANDLE_FINTR(f.io,file_contents); fclose(f.io); file_error("file_contents",&f); } p += d; len -= d; } fclose(f.io); return s; } #define MAKE_STDIO(k) \ static value file_##k() { \ fio *f; \ f = (fio*)alloc(sizeof(fio)); \ f->name = alloc_string(#k); \ f->io = k; \ return alloc_abstract(k_file,f); \ } \ DEFINE_PRIM(file_##k,0); /** file_stdin : void -> 'file The standard input **/ MAKE_STDIO(stdin); /** file_stdout : void -> 'file The standard output **/ MAKE_STDIO(stdout); /** file_stderr : void -> 'file The standard error output **/ MAKE_STDIO(stderr); DEFINE_PRIM(file_open,2); DEFINE_PRIM(file_close,1); DEFINE_PRIM(file_name,1); DEFINE_PRIM(file_write,4); DEFINE_PRIM(file_read,4); DEFINE_PRIM(file_write_char,2); DEFINE_PRIM(file_read_char,1); DEFINE_PRIM(file_seek,3); DEFINE_PRIM(file_tell,1); DEFINE_PRIM(file_eof,1); DEFINE_PRIM(file_flush,1); DEFINE_PRIM(file_contents,1); /* ************************************************************************ */ neko-2.0.0/libs/std/std.vcxproj0000644000175000017500000002047712112157473017120 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ true Release\ Release\ false Release\ Release\ false Disabled ../../vm;../include;../common;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;STD_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ../../bin/neko.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/std.ndll true $(OutDir)std.pdb Windows $(OutDir)std.lib MachineX86 ../../vm;../include;../common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;STD_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../../bin/neko.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/std.ndll %(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)std.lib MachineX86 ../../vm;../include;../common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;STD_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../../bin/neko.lib;ws2_32.lib;../include/msvcrt/extra.lib;%(AdditionalDependencies) ../../bin/std.ndll MSVCRT;%(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)std.lib MachineX86 neko-2.0.0/libs/std/int32.c0000644000175000017500000001230512112157473016003 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include /**

Int32

Int32 api is deprecated as of Neko 2.0, which have native support for Int32.

**/ /** int32_new : (#int32 | float) -> 'int32 Allocate an int32 from any number **/ static value int32_new( value v ) { val_check(v,number); return alloc_int32((int)val_number(v)); } /** int32_to_int : #int32 -> int Return the int value if it can be represented using 31 bits. Error either **/ static value int32_to_int( value v ) { int i; val_check(v,any_int); i = val_any_int(v); if( need_32_bits(i) ) neko_error(); return alloc_int(i); } /** int32_to_float : #int32 -> float Return the float value of the integer. **/ static value int32_to_float( value v ) { val_check(v,any_int); return alloc_float(val_any_int(v)); } /** int32_compare : #int32 -> #int32 -> int Compare two integers **/ static value int32_compare( value v1, value v2 ) { int i1, i2; val_check(v1,any_int); val_check(v2,any_int); i1 = val_any_int(v1); i2 = val_any_int(v2); if( i1 == i2 ) return alloc_int(0); else if( i1 > i2 ) return alloc_int(1); else return alloc_int(-1); } #define INT32_OP(op_name,op) \ static value int32_##op_name( value v1, value v2 ) { \ int r; \ val_check(v1,any_int); \ val_check(v2,any_int); \ r = val_any_int(v1) op val_any_int(v2); \ return alloc_best_int(r); \ } \ DEFINE_PRIM(int32_##op_name,2) #define INT32_UNOP(op_name,op) \ static value int32_##op_name( value v ) { \ int r; \ val_check(v,any_int); \ r = op val_any_int(v); \ return alloc_best_int(r); \ } \ DEFINE_PRIM(int32_##op_name,1) #define INT32_OP_ZERO(op_name,op) \ static value int32_##op_name( value v1, value v2 ) { \ int d; \ int r; \ val_check(v1,any_int); \ val_check(v2,any_int); \ d = val_any_int(v2); \ if( d == 0 ) \ neko_error(); \ r = val_any_int(v1) op d; \ return alloc_best_int(r); \ } \ DEFINE_PRIM(int32_##op_name,2) /** int32_ushr : #int32 -> #int32 -> #int32 Perform unsigned right bits-shifting **/ static value int32_ushr( value v1, value v2 ) { int r; val_check(v1,any_int); val_check(v2,any_int); r = ((unsigned int)val_any_int(v1)) >> val_any_int(v2); return alloc_best_int(r); } /** int32_add : #int32 -> #int32 -> #int32 Add two integers **/ INT32_OP(add,+); /** int32_sub : #int32 -> #int32 -> #int32 Subtract two integers **/ INT32_OP(sub,-); /** int32_mul : #int32 -> #int32 -> #int32 Multiply two integers **/ INT32_OP(mul,*); /** int32_div : #int32 -> #int32 -> #int32 Divide two integers. Error on division by 0 **/ INT32_OP_ZERO(div,/); /** int32_shl : #int32 -> #int32 -> #int32 Perform left bit-shifting **/ INT32_OP(shl,<<); /** int32_shr : #int32 -> #int32 -> #int32 Perform right bit-shifting **/ INT32_OP(shr,>>); /** int32_mod : #int32 -> #int32 -> #int32 Return the modulo of one integer by the other. Error on modulo by 0 **/ INT32_OP_ZERO(mod,%); /** int32_neg : #int32 -> #int32 Return the negative value of an integer **/ INT32_UNOP(neg,-); /** int32_complement : #int32 -> #int32 Return the one-complement bitwised integer **/ INT32_UNOP(complement,~); /** int32_or : #int32 -> #int32 -> #int32 Return the bitwise or of two integers **/ INT32_OP(or,|); /** int32_and : #int32 -> #int32 -> #int32 Return the bitwise and of two integers **/ INT32_OP(and,&); /** int32_xor : #int32 -> #int32 -> #int32 Return the bitwise xor of two integers **/ INT32_OP(xor,^); /** int32_address : any -> #int32 Return the address of the value. The address should not be considered constant. It is not unique either unless you are sure you are running on a 32-bit platform. **/ static value int32_address( value v ) { return alloc_best_int((int)(int_val)v); } DEFINE_PRIM(int32_new,1); DEFINE_PRIM(int32_to_int,1); DEFINE_PRIM(int32_to_float,1); DEFINE_PRIM(int32_compare,2); DEFINE_PRIM(int32_ushr,2); DEFINE_PRIM(int32_address,1); /* ************************************************************************ */ neko-2.0.0/libs/std/date.c0000644000175000017500000001504112112157473015761 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include /**

Date

Date are using standard C functions in order to manipulate a 32 bit integer. Dates are then represented as the number of seconds elapsed since 1st January 1970.

**/ extern field id_h; extern field id_m; extern field id_s; extern field id_y; extern field id_d; #ifdef NEKO_WINDOWS static struct tm *localtime_r( time_t *t, struct tm *r ) { struct tm *r2 = localtime(t); if( r2 == NULL ) return NULL; *r = *r2; return r; } static struct tm *gmtime_r( time_t *t, struct tm *r ) { struct tm *r2 = gmtime(t); if( r2 == NULL ) return NULL; *r = *r2; return r; } #endif /** date_now : void -> 'int32 Return current date and time **/ static value date_now() { int t = (int)time(NULL); return alloc_int32(t); } /** date_new : string? -> 'int32 Parse a date format. The following formats are accepted :
  • [null] : return current date and time
  • [YYYY-MM-DD HH:MM:SS] : full date and time
  • [YYYY-MM-DD] : date only (time will be set to midnight)
  • [HH:MM:SS] : this represent an elapsed time. It will be corrected with timezone so you can subtract it from a date.
**/ static value date_new( value s ) { int o = 0; if( val_is_null(s) ) o = (int)time(NULL); else { struct tm t; bool recal = true; val_check(s,string); memset(&t,0,sizeof(struct tm)); switch( val_strlen(s) ) { case 19: sscanf(val_string(s),"%4d-%2d-%2d %2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec); t.tm_isdst = -1; break; case 8: sscanf(val_string(s),"%2d:%2d:%2d",&t.tm_hour,&t.tm_min,&t.tm_sec); o = t.tm_sec + t.tm_min * 60 + t.tm_hour * 60 * 60; recal = false; break; case 10: sscanf(val_string(s),"%4d-%2d-%2d",&t.tm_year,&t.tm_mon,&t.tm_mday); t.tm_isdst = -1; break; default: { buffer b = alloc_buffer("Invalid date format : "); val_buffer(b,s); bfailure(b); } } if( recal ) { t.tm_year -= 1900; t.tm_mon--; o = (int)mktime(&t); } } return alloc_int32(o); } /** date_format : #int32 -> fmt:string? -> string Format a date using [strftime]. If [fmt] is [null] then default format is used **/ static value date_format( value o, value fmt ) { char buf[128]; struct tm t; time_t d; val_check(o,any_int); if( val_is_null(fmt) ) fmt = alloc_string("%Y-%m-%d %H:%M:%S"); val_check(fmt,string); d = val_any_int(o); if( localtime_r(&d,&t) == NULL ) neko_error(); strftime(buf,127,val_string(fmt),&t); return alloc_string(buf); } /** date_set_hour : #int32 -> h:int -> m:int -> s:int -> 'int32 Change the time of a date. Return the modified date **/ static value date_set_hour( value o, value h, value m, value s ) { struct tm t; time_t d; val_check(o,any_int); val_check(h,int); val_check(m,int); val_check(s,int); d = val_any_int(o); if( localtime_r(&d,&t) == NULL ) neko_error(); t.tm_hour = val_int(h); t.tm_min = val_int(m); t.tm_sec = val_int(s); d = mktime(&t); if( d == -1 ) neko_error(); return alloc_int32((int)d); } /** date_set_day : #int32 -> y:int -> m:int -> d:int -> 'int32 Change the day of a date. Return the modified date **/ static value date_set_day( value o, value y, value m, value d ) { struct tm t; time_t date; val_check(o,any_int); val_check(y,int); val_check(m,int); val_check(d,int); date = val_any_int(o); if( localtime_r(&date,&t) == NULL ) neko_error(); t.tm_year = val_int(y) - 1900; t.tm_mon = val_int(m) - 1; t.tm_mday = val_int(d); date = mktime(&t); if( date == -1 ) neko_error(); return alloc_int32((int)date); } /** date_get_day : #int32 -> { y => int, m => int, d => int } Return the year month and day of a date **/ static value date_get_day( value o ) { value r; struct tm t; time_t d; val_check(o,any_int); d = val_any_int(o); if( localtime_r(&d,&t) == NULL ) neko_error(); r = alloc_object(NULL); alloc_field(r,id_y,alloc_int(t.tm_year + 1900)); alloc_field(r,id_m,alloc_int(t.tm_mon + 1)); alloc_field(r,id_d,alloc_int(t.tm_mday)); return r; } /** date_get_hour : #int32 -> { h => int, m => int, s => int } Return the hour minutes and seconds of a date **/ static value date_get_hour( value o ) { value r; struct tm t; time_t d; val_check(o,any_int); d = val_any_int(o); if( localtime_r(&d,&t) == NULL ) neko_error(); r = alloc_object(NULL); alloc_field(r,id_h,alloc_int(t.tm_hour)); alloc_field(r,id_m,alloc_int(t.tm_min)); alloc_field(r,id_s,alloc_int(t.tm_sec)); return r; } /** date_get_tz : void -> int Return the local Timezone (in seconds) **/ static value date_get_tz() { struct tm local; struct tm gmt; int diff; time_t raw = time(NULL); if( localtime_r(&raw, &local) == NULL || gmtime_r(&raw, &gmt) == NULL ) neko_error(); diff = (local.tm_hour - gmt.tm_hour) * 3600 + (local.tm_min - gmt.tm_min) * 60; // adjust for different days/years if( gmt.tm_year > local.tm_year || gmt.tm_yday > local.tm_yday ) diff -= 24 * 3600; else if( gmt.tm_year < local.tm_year || gmt.tm_yday < local.tm_yday ) diff += 24 * 3600; return alloc_int(diff); } DEFINE_PRIM(date_now,0); DEFINE_PRIM(date_new,1); DEFINE_PRIM(date_format,2); DEFINE_PRIM(date_set_hour,4); DEFINE_PRIM(date_set_day,4); DEFINE_PRIM(date_get_hour,1); DEFINE_PRIM(date_get_day,1); DEFINE_PRIM(date_get_tz,0); /* ************************************************************************ */ neko-2.0.0/libs/std/process.c0000644000175000017500000002345212112157473016527 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #ifdef NEKO_WINDOWS # include #else # include # include # include # ifndef NEKO_MAC # include # endif #endif #include #include typedef struct { #ifdef NEKO_WINDOWS HANDLE oread; HANDLE eread; HANDLE iwrite; PROCESS_INFORMATION pinf; #else int oread; int eread; int iwrite; int pid; #endif } vprocess; DEFINE_KIND(k_process); #define val_process(v) ((vprocess*)val_data(v)) /**

Process

An API for starting and communication with sub processes.

**/ #ifndef NEKO_WINDOWS static int do_close( int fd ) { POSIX_LABEL(close_again); if( close(fd) != 0 ) { HANDLE_EINTR(close_again); return 1; } return 0; } #endif static void free_process( value vp ) { vprocess *p = val_process(vp); # ifdef NEKO_WINDOWS CloseHandle(p->eread); CloseHandle(p->oread); CloseHandle(p->iwrite); CloseHandle(p->pinf.hProcess); CloseHandle(p->pinf.hThread); # else do_close(p->eread); do_close(p->oread); do_close(p->iwrite); # endif } /** process_run : cmd:string -> args:string array -> 'process Start a process using a command and the specified arguments. **/ static value process_run( value cmd, value vargs ) { int i; vprocess *p; val_check(cmd,string); val_check(vargs,array); # ifdef NEKO_WINDOWS { SECURITY_ATTRIBUTES sattr; STARTUPINFO sinf; HANDLE proc = GetCurrentProcess(); HANDLE oread,eread,iwrite; // creates commandline buffer b = alloc_buffer(NULL); value sargs; buffer_append_char(b,'"'); val_buffer(b,cmd); buffer_append_char(b,'"'); for(i=0;ioread,0,FALSE,DUPLICATE_SAME_ACCESS); DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS); DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS); CloseHandle(oread); CloseHandle(eread); CloseHandle(iwrite); if( !CreateProcess(NULL,val_string(sargs),NULL,NULL,TRUE,0,NULL,NULL,&sinf,&p->pinf) ) neko_error(); // close unused pipes CloseHandle(sinf.hStdOutput); CloseHandle(sinf.hStdError); CloseHandle(sinf.hStdInput); } # else char **argv = (char**)alloc_private(sizeof(char*)*(val_array_size(vargs)+2)); argv[0] = val_string(cmd); for(i=0;ipid = fork(); if( p->pid == -1 ) { do_close(input[0]); do_close(input[1]); do_close(output[0]); do_close(output[1]); do_close(error[0]); do_close(error[1]); neko_error(); } // child if( p->pid == 0 ) { close(input[1]); close(output[0]); close(error[0]); dup2(input[0],0); dup2(output[1],1); dup2(error[1],2); execvp(val_string(cmd),argv); fprintf(stderr,"Command not found : %s\n",val_string(cmd)); exit(1); } // parent do_close(input[0]); do_close(output[1]); do_close(error[1]); p->iwrite = input[1]; p->oread = output[0]; p->eread = error[0]; # endif { value vp = alloc_abstract(k_process,p); val_gc(vp,free_process); return vp; } } #define CHECK_ARGS() \ vprocess *p; \ val_check_kind(vp,k_process); \ val_check(str,string); \ val_check(pos,int); \ val_check(len,int); \ if( val_int(pos) < 0 || val_int(len) < 0 || val_int(pos) + val_int(len) > val_strlen(str) ) \ neko_error(); \ p = val_process(vp); \ /** process_stdout_read : 'process -> buf:string -> pos:int -> len:int -> int Read up to [len] bytes in [buf] starting at [pos] from the process stdout. Returns the number of bytes readed this way. Raise an exception if this process stdout is closed and no more data is available for reading. **/ static value process_stdout_read( value vp, value str, value pos, value len ) { CHECK_ARGS(); # ifdef NEKO_WINDOWS { DWORD nbytes; if( !ReadFile(p->oread,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) ) neko_error(); return alloc_int(nbytes); } # else int nbytes; POSIX_LABEL(stdout_read_again); nbytes = read(p->oread,val_string(str)+val_int(pos),val_int(len)); if( nbytes < 0 ) { HANDLE_EINTR(stdout_read_again); neko_error(); } if( nbytes == 0 ) neko_error(); return alloc_int(nbytes); # endif } /** process_stderr_read : 'process -> buf:string -> pos:int -> len:int -> int Read up to [len] bytes in [buf] starting at [pos] from the process stderr. Returns the number of bytes readed this way. Raise an exception if this process stderr is closed and no more data is available for reading. **/ static value process_stderr_read( value vp, value str, value pos, value len ) { CHECK_ARGS(); # ifdef NEKO_WINDOWS { DWORD nbytes; if( !ReadFile(p->eread,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) ) neko_error(); return alloc_int(nbytes); } # else int nbytes; POSIX_LABEL(stderr_read_again); nbytes = read(p->eread,val_string(str)+val_int(pos),val_int(len)); if( nbytes < 0 ) { HANDLE_EINTR(stderr_read_again); neko_error(); } if( nbytes == 0 ) neko_error(); return alloc_int(nbytes); # endif } /** process_stdin_write : 'process -> buf:string -> pos:int -> len:int -> int Write up to [len] bytes from [buf] starting at [pos] to the process stdin. Returns the number of bytes writen this way. Raise an exception if this process stdin is closed. **/ static value process_stdin_write( value vp, value str, value pos, value len ) { CHECK_ARGS(); # ifdef NEKO_WINDOWS { DWORD nbytes; if( !WriteFile(p->iwrite,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) ) neko_error(); return alloc_int(nbytes); } # else int nbytes; POSIX_LABEL(stdin_write_again); nbytes = write(p->iwrite,val_string(str)+val_int(pos),val_int(len)); if( nbytes == -1 ) { HANDLE_EINTR(stdin_write_again); neko_error(); } return alloc_int(nbytes); # endif } /** process_stdin_close : 'process -> void Close the process standard input. **/ static value process_stdin_close( value vp ) { vprocess *p; val_check_kind(vp,k_process); p = val_process(vp); # ifdef NEKO_WINDOWS if( !CloseHandle(p->iwrite) ) neko_error(); # else if( do_close(p->iwrite) ) neko_error(); p->iwrite = -1; # endif return val_null; } /** process_exit : 'process -> int Wait until the process terminate, then returns its exit code. **/ static value process_exit( value vp ) { vprocess *p; val_check_kind(vp,k_process); p = val_process(vp); # ifdef NEKO_WINDOWS { DWORD rval; WaitForSingleObject(p->pinf.hProcess,INFINITE); if( !GetExitCodeProcess(p->pinf.hProcess,&rval) ) neko_error(); return alloc_int(rval); } # else int rval; while( waitpid(p->pid,&rval,0) != p->pid ) { if( errno == EINTR ) continue; neko_error(); } if( !WIFEXITED(rval) ) neko_error(); return alloc_int(WEXITSTATUS(rval)); # endif } /** process_pid : 'process -> int Returns the process id. **/ static value process_pid( value vp ) { vprocess *p; val_check_kind(vp,k_process); p = val_process(vp); # ifdef NEKO_WINDOWS return alloc_int(p->pinf.dwProcessId); # else return alloc_int(p->pid); # endif } /** process_close : 'process -> void Close the process I/O. **/ static value process_close( value vp ) { val_check_kind(vp,k_process); free_process(vp); val_kind(vp) = NULL; val_gc(vp,NULL); return val_null; } /** process_kill : 'process -> void Terminates a running process. **/ static value process_kill( value vp ) { val_check_kind(vp,k_process); # ifdef NEKO_WINDOWS TerminateProcess(val_process(vp)->pinf.hProcess,-1); # else kill(val_process(vp)->pid,9); # endif return val_null; } DEFINE_PRIM(process_run,2); DEFINE_PRIM(process_stdout_read,4); DEFINE_PRIM(process_stderr_read,4); DEFINE_PRIM(process_stdin_close,1); DEFINE_PRIM(process_stdin_write,4); DEFINE_PRIM(process_exit,1); DEFINE_PRIM(process_pid,1); DEFINE_PRIM(process_close,1); DEFINE_PRIM(process_kill,1); /* ************************************************************************ */ neko-2.0.0/libs/std/string.c0000644000175000017500000002347512112157473016364 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include /**

String Functions

Some useful functions dealing with string manipulation.

**/ /** string_split : s:string -> sep:string -> string list split the string [s] using separator [sep] **/ static value string_split( value o, value s ) { value l, first; int ilen; int slen; int start = 0; int pos; val_check(s,string); val_check(o,string); ilen = val_strlen(o); slen = val_strlen(s); l = NULL; first = NULL; for(pos=slen?0:1;pos<=ilen-slen;pos++) if( memcmp(val_string(o)+pos,val_string(s),slen) == 0 ) { value ss = copy_string(val_string(o)+start,pos-start); value l2 = alloc_array(2); val_array_ptr(l2)[0] = ss; val_array_ptr(l2)[1] = val_null; if( first == NULL ) first = l2; else val_array_ptr(l)[1] = l2; l = l2; start = pos + slen; if( slen ) pos = start - 1; } if( ilen > 0 && slen ) { value ss = start ? copy_string(val_string(o)+start,ilen-start) : o; value l2 = alloc_array(2); val_array_ptr(l2)[0] = ss; val_array_ptr(l2)[1] = val_null; if( first == NULL ) first = l2; else val_array_ptr(l)[1] = l2; } return (first == NULL)?val_null:first; } #define HEX 1 #define HEX_SMALL 2 /** sprintf : fmt:string -> params:(any | array) -> string Format a string. If only one parameter is needed then it can be directly passed, either the parameters need to be stored in an array. The following formats are accepted (with corresponding types) :
  • [%s] : string
  • [%d] [%x] [%X] : int
  • [%c] : int in the 0..255 range
  • [%b] : bool
  • [%f] : float
**/ static value neko_sprintf( value fmt, value params ) { char *last, *cur, *end; int count = 0; buffer b; val_check(fmt,string); b = alloc_buffer(NULL); last = val_string(fmt); cur = last; end = cur + val_strlen(fmt); while( cur != end ) { if( *cur == '%' ) { int width = 0, prec = 0, flags = 0; buffer_append_sub(b,last,cur - last); cur++; while( *cur >= '0' && *cur <= '9' ) { width = width * 10 + (*cur - '0'); cur++; } if( *cur == '.' ) { cur++; while( *cur >= '0' && *cur <= '9' ) { prec = prec * 10 + (*cur - '0'); cur++; } } if( *cur == '%' ) { buffer_append_sub(b,"%",1); cur++; } else { value param; if( count == 0 && !val_is_array(params) ) { // first ? param = params; count++; } else if( !val_is_array(params) || val_array_size(params) <= count ) neko_error(); else param = val_array_ptr(params)[count++]; switch( *cur ) { case 'c': { int c; char cc; val_check(param,int); c = val_int(param); if( c < 0 || c > 255 ) neko_error(); cc = (char)c; buffer_append_sub(b,&cc,1); } break; case 'x': flags |= HEX_SMALL; case 'X': flags |= HEX; case 'd': { char tmp[10]; int sign = 0; int size = 0; int tsize; int n; val_check(param,int); n = val_int(param); if( !(flags & HEX) && n < 0 ) { sign++; prec--; n = -n; } else if( n == 0 ) tmp[9-size++] = '0'; if( flags & HEX ) { unsigned int nn = (unsigned int)n; while( nn > 0 ) { int k = nn&15; if( k < 10 ) tmp[9-size++] = k + '0'; else tmp[9-size++] = (k - 10) + ((flags & HEX_SMALL)?'a':'A'); nn = nn >> 4; } } else { while( n > 0 ) { tmp[9-size++] = (n % 10) + '0'; n = n / 10; } } tsize = (size > prec)?size:prec + sign; while( width > tsize ) { width--; buffer_append_sub(b," ",1); } if( sign ) buffer_append_sub(b,"-",1); while( prec > size ) { prec--; buffer_append_sub(b,"0",1); } buffer_append_sub(b,tmp+10-size,size); } break; case 'f': { val_check(param,float); val_buffer(b,param); } break; case 's': { int size; int tsize; val_check(param,string); size = val_strlen(param); tsize = (size > prec)?size:prec; while( width > tsize ) { width--; buffer_append_sub(b," ",1); } while( prec > size ) { prec--; buffer_append_sub(b," ",1); } buffer_append_sub(b,val_string(param),size); } break; case 'b': { val_check(param,bool); buffer_append_sub(b,val_bool(param)?"true":"false",val_bool(param)?4:5); } break; default: neko_error(); break; } } cur++; last = cur; } else cur++; } buffer_append_sub(b,last,cur - last); return buffer_to_string(b); } /** url_decode : string -> string Decode an url using escaped format **/ static value url_decode( value v ) { val_check(v,string); { int pin = 0; int pout = 0; const char *in = val_string(v); int len = val_strlen(v); value v2 = alloc_empty_string(len); char *out = (char*)val_string(v2); while( len-- > 0 ) { char c = in[pin++]; if( c == '+' ) c = ' '; else if( c == '%' ) { int p1, p2; if( len < 2 ) break; p1 = in[pin++]; p2 = in[pin++]; len -= 2; if( p1 >= '0' && p1 <= '9' ) p1 -= '0'; else if( p1 >= 'a' && p1 <= 'f' ) p1 -= 'a' - 10; else if( p1 >= 'A' && p1 <= 'F' ) p1 -= 'A' - 10; else continue; if( p2 >= '0' && p2 <= '9' ) p2 -= '0'; else if( p2 >= 'a' && p2 <= 'f' ) p2 -= 'a' - 10; else if( p2 >= 'A' && p2 <= 'F' ) p2 -= 'A' - 10; else continue; c = (char)((unsigned char)((p1 << 4) + p2)); } out[pout++] = c; } out[pout] = 0; val_set_size(v2,pout); return v2; } } /** url_encode : string -> string Encode an url using escaped format **/ static value url_encode( value v ) { val_check(v,string); { int pin = 0; int pout = 0; const unsigned char *in = (const unsigned char*)val_string(v); static const char *hex = "0123456789ABCDEF"; int len = val_strlen(v); value v2 = alloc_empty_string(len * 3); unsigned char *out = (unsigned char*)val_string(v2); while( len-- > 0 ) { unsigned char c = in[pin++]; if( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '.' ) out[pout++] = c; else { out[pout++] = '%'; out[pout++] = hex[c >> 4]; out[pout++] = hex[c & 0xF]; } } out[pout] = 0; val_set_size(v2,pout); return v2; } } /** base_encode : s:string -> base:string -> string Encode a string using the specified base. The base length must be a power of two. **/ static value base_encode( value s, value base ) { int nbits; int len; int size; int mask; unsigned int buf; int curbits; value out; unsigned char *cin, *cout, *chars; val_check(s,string); val_check(base,string); len = val_strlen(base); cin = (unsigned char *)val_string(s); chars = (unsigned char *)val_string(base); nbits = 1; while( len > 1 << nbits ) nbits++; if( nbits > 8 || len != 1 << nbits ) neko_error(); size = (val_strlen(s) * 8 + nbits - 1) / nbits; out = alloc_empty_string(size); cout = (unsigned char *)val_string(out); buf = 0; curbits = 0; mask = ((1 << nbits) - 1); while( size-- > 0 ) { while( curbits < nbits ) { curbits += 8; buf <<= 8; buf |= *cin++; } curbits -= nbits; *cout++ = chars[(buf >> curbits) & mask]; } return out; } /** base_decode : s:string -> base:string -> string Decode a string encode in the specified base. The base length must be a power of two. **/ static value base_decode( value s, value base ) { int nbits; int len; int size; unsigned int buf; int curbits; value out; int i; int tbl[256]; unsigned char *cin, *cout, *chars; val_check(s,string); val_check(base,string); len = val_strlen(base); cin = (unsigned char *)val_string(s); chars = (unsigned char *)val_string(base); nbits = 1; while( len > 1 << nbits ) nbits++; if( nbits > 8 || len != 1 << nbits ) neko_error(); for(i=0;i<256;i++) tbl[i] = -1; for(i=0;i 0 ) { while( curbits < 8 ) { curbits += nbits; buf <<= nbits; i = tbl[*cin++]; if( i == -1 ) neko_error(); buf |= i; } curbits -= 8; *cout++ = (buf >> curbits) & 0xFF; } return out; } #define neko_sprintf__2 sprintf__2 DEFINE_PRIM(neko_sprintf,2); DEFINE_PRIM(string_split,2); DEFINE_PRIM(url_decode,1); DEFINE_PRIM(url_encode,1); DEFINE_PRIM(base_encode,2); DEFINE_PRIM(base_decode,2); /* ************************************************************************ */ neko-2.0.0/libs/std/module.c0000644000175000017500000001515612112157473016340 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #define READ_BUFSIZE 64 /**

Module

An API for reflexion of Neko bytecode modules.

**/ static int read_proxy( readp p, void *buf, int size ) { value fread = val_array_ptr(p)[0]; value vbuf = val_array_ptr(p)[1]; value ret; int len; if( size < 0 ) return -1; if( size > READ_BUFSIZE ) vbuf = alloc_empty_string(size); ret = val_call3(fread,vbuf,alloc_int(0),alloc_int(size)); if( !val_is_int(ret) ) return -1; len = val_int(ret); if( len < 0 || len > size ) return -1; memcpy(buf,val_string(vbuf),len); return len; } /** module_read : fread:(buf:string -> pos:int -> len:int -> int) -> loader:object -> 'module Read a module using the specified read function and the specified loader. **/ static value module_read( value fread, value loader ) { value p; neko_module *m; val_check_function(fread,3); val_check(loader,object); p = alloc_array(2); val_array_ptr(p)[0] = fread; val_array_ptr(p)[1] = alloc_empty_string(READ_BUFSIZE); m = neko_read_module(read_proxy,p,loader); if( m == NULL ) neko_error(); m->name = alloc_string(""); return alloc_abstract(neko_kind_module,m); } /** module_read_string : string -> loader:object -> 'module Read a module using the specified string datas. **/ static value module_read_string( value str, value loader ) { neko_module *m; string_pos p; val_check(str,string); val_check(loader,object); p.p = val_string(str); p.len = val_strlen(str); m = neko_read_module(neko_string_reader,&p,loader); if( m == NULL ) neko_error(); m->name = alloc_string(""); return alloc_abstract(neko_kind_module,m); } /** module_read_path : string list -> name:string -> loader:object -> 'module Read a module using the specified search path. **/ static value module_read_path( value path, value name, value loader ) { FILE *f; value fname; char *mname, *ext; neko_module *m; val_check(name,string); val_check(loader,object); mname = val_string(name); ext = strrchr(mname,'.'); if( ext && ext[1] == 'n' && ext[2] == 0 ) fname = neko_select_file(path,mname,""); else fname = neko_select_file(path,mname,".n"); f = fopen(val_string(fname),"rb"); if( f == NULL ) { buffer b = alloc_buffer("Module not found : "); buffer_append(b,mname); bfailure(b); } m = neko_read_module(neko_file_reader,f,loader); fclose(f); if( m == NULL ) { buffer b = alloc_buffer("Invalid module : "); val_buffer(b,name); bfailure(b); } m->name = alloc_string(val_string(name)); return alloc_abstract(neko_kind_module,m); } /** module_exec : 'module -> any Execute the module, return the calculated value **/ static value module_exec( value mv ) { neko_module *m; val_check_kind(mv,neko_kind_module); m = (neko_module*)val_data(mv); return neko_vm_execute(neko_vm_current(),m); } /** module_name : 'module -> string Return the module name **/ static value module_name( value mv ) { neko_module *m; val_check_kind(mv,neko_kind_module); m = (neko_module*)val_data(mv); return m->name; } /** module_set_name : 'module -> string -> void Set the module name **/ static value module_set_name( value mv, value str ) { neko_module *m; val_check_kind(mv,neko_kind_module); val_check(str,string); m = (neko_module*)val_data(mv); m->name = str; return val_null; } /** module_exports : 'module -> object Return the module export table **/ static value module_exports( value mv ) { neko_module *m; val_check_kind(mv,neko_kind_module); m = (neko_module*)val_data(mv); return m->exports; } /** module_loader : 'module -> object Return the module loader **/ static value module_loader( value mv ) { neko_module *m; val_check_kind(mv,neko_kind_module); m = (neko_module*)val_data(mv); return m->loader; } /** module_nglobals : 'module -> int Return the number of globals for this module **/ static value module_nglobals( value mv ) { neko_module *m; val_check_kind(mv,neko_kind_module); m = (neko_module*)val_data(mv); return alloc_int(m->nglobals); } /** module_global_get : 'module -> n:int -> any Get the [n]th global **/ static value module_global_get( value mv, value p ) { neko_module *m; unsigned int pp; val_check_kind(mv,neko_kind_module); m = (neko_module*)val_data(mv); val_check(p,int); pp = (unsigned)val_int(p); if( pp >= m->nglobals ) neko_error(); return m->globals[pp]; } /** module_global_set : 'module -> n:int -> any -> void Set the [n]th global **/ static value module_global_set( value mv, value p, value v ) { neko_module *m; unsigned int pp; val_check_kind(mv,neko_kind_module); m = (neko_module*)val_data(mv); val_check(p,int); pp = (unsigned)val_int(p); if( pp >= m->nglobals ) neko_error(); m->globals[pp] = v; return v; } /** module_code_size : 'module -> int return the codesize of the module **/ static value module_code_size( value mv ) { val_check_kind(mv,neko_kind_module); return alloc_int( ((neko_module*)val_data(mv))->codesize ); } DEFINE_PRIM(module_read,2); DEFINE_PRIM(module_read_string,2); DEFINE_PRIM(module_read_path,3); DEFINE_PRIM(module_exec,1); DEFINE_PRIM(module_name,1); DEFINE_PRIM(module_exports,1); DEFINE_PRIM(module_loader,1); DEFINE_PRIM(module_nglobals,1); DEFINE_PRIM(module_global_get,2); DEFINE_PRIM(module_global_set,3); DEFINE_PRIM(module_code_size,1); DEFINE_PRIM(module_set_name,2); /* ************************************************************************ */ neko-2.0.0/libs/std/buffer.c0000644000175000017500000000662112112157473016321 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include /**

Buffer

A buffer can store any value as a string and will only allocate the total needed space when requested. It makes a copy of each value when stored so modifying them after is not a problem.

**/ DEFINE_KIND(k_buffer); /** buffer_new : void -> 'buffer Allocate a new empty buffer **/ static value buffer_new() { buffer b = alloc_buffer(NULL); return alloc_abstract(k_buffer,b); } /** buffer_add : 'buffer -> any -> void Add a value to a buffer **/ static value buffer_add( value b, value v ) { val_check_kind(b,k_buffer); val_buffer( (buffer)val_data(b), v ); return val_true; } /** buffer_add_char : 'buffer -> c:int -> void Add a single char to a buffer. Error if [c] is not in the 0..255 range **/ static value buffer_add_char( value b, value c ) { val_check_kind(b,k_buffer); val_check(c,int); if( val_int(c) < 0 || val_int(c) > 255 ) neko_error(); buffer_append_char( (buffer)val_data(b), (char)(unsigned char)val_int(c) ); return val_true; } /** buffer_add_sub : 'buffer -> s:string -> p:int -> l:int -> void Add [l] characters of the string [s] starting at position [p]. An error occurs if out of string bounds. **/ static value buffer_add_sub( value b, value v, value p, value l ) { val_check_kind(b,k_buffer); val_check(v,string); val_check(p,int); val_check(l,int); if( val_int(p) < 0 || val_int(l) < 0 ) neko_error(); if( val_strlen(v) < val_int(p) || val_strlen(v) < val_int(p) + val_int(l) ) neko_error(); buffer_append_sub( (buffer)val_data(b), val_string(v) + val_int(p) , val_int(l) ); return val_true; } /** buffer_string : 'buffer -> string Build and return the string built with the buffer **/ static value buffer_string( value b ) { val_check_kind(b,k_buffer); return buffer_to_string( (buffer)val_data(b) ); } /** buffer_reset : 'buffer -> void Make the buffer empty **/ static value buffer_reset( value b ) { val_check_kind(b,k_buffer); val_data(b) = alloc_buffer(NULL); return val_true; } DEFINE_PRIM(buffer_new,0); DEFINE_PRIM(buffer_add,2); DEFINE_PRIM(buffer_add_char,2); DEFINE_PRIM(buffer_add_sub,4); DEFINE_PRIM(buffer_string,1); DEFINE_PRIM(buffer_reset,1); /* ************************************************************************ */ neko-2.0.0/libs/std/std.vcproj0000644000175000017500000001323212112157473016717 0ustar ncannassencannasse neko-2.0.0/libs/std/misc.c0000644000175000017500000002275612112157473016012 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include /**

Misc

Misc. functions for different usages.

**/ /** float_bytes : number -> bigendian:bool -> string Returns the 4 bytes representation of the number as an IEEE 32-bit float **/ static value float_bytes( value n, value be ) { float f; val_check(n,number); val_check(be,bool); f = (float)val_number(n); if( neko_is_big_endian() != val_bool(be) ) { char *c = (char*)&f; char tmp; tmp = c[0]; c[0] = c[3]; c[3] = tmp; tmp = c[1]; c[1] = c[2]; c[2] = tmp; } return copy_string((char *)&f,4); } /** double_bytes : number -> bigendian:bool -> string Returns the 8 bytes representation of the number as an IEEE 64-bit float **/ static value double_bytes( value n, value be ) { double f; val_check(n,number); val_check(be,bool); f = (double)val_number(n); if( neko_is_big_endian() != val_bool(be) ) { char *c = (char*)&f; char tmp; tmp = c[0]; c[0] = c[7]; c[7] = tmp; tmp = c[1]; c[1] = c[6]; c[6] = tmp; tmp = c[2]; c[2] = c[5]; c[5] = tmp; tmp = c[3]; c[3] = c[4]; c[4] = tmp; } return copy_string((char*)&f,8); } /** float_of_bytes : string -> bigendian:bool -> float Returns a float from a 4 bytes IEEE 32-bit representation **/ static value float_of_bytes( value s, value be ) { float f; val_check(s,string); val_check(be,bool); if( val_strlen(s) != 4 ) neko_error(); f = *(float*)val_string(s); if( neko_is_big_endian() != val_bool(be) ) { char *c = (char*)&f; char tmp; tmp = c[0]; c[0] = c[3]; c[3] = tmp; tmp = c[1]; c[1] = c[2]; c[2] = tmp; } return alloc_float(f); } /** double_of_bytes : string -> bigendian:bool -> float Returns a float from a 8 bytes IEEE 64-bit representation **/ static value double_of_bytes( value s, value be ) { double f; val_check(s,string); val_check(be,bool); if( val_strlen(s) != 8 ) neko_error(); f = *(double*)val_string(s); if( neko_is_big_endian() != val_bool(be) ) { char *c = (char*)&f; char tmp; tmp = c[0]; c[0] = c[7]; c[7] = tmp; tmp = c[1]; c[1] = c[6]; c[6] = tmp; tmp = c[2]; c[2] = c[5]; c[5] = tmp; tmp = c[3]; c[3] = c[4]; c[4] = tmp; } return alloc_float(f); } /** run_gc : major:bool -> void Run the Neko garbage collector **/ static value run_gc( value b ) { val_check(b,bool); if( val_bool(b) ) neko_gc_major(); else neko_gc_loop(); return val_null; } /** gc_stats : void -> { heap => int, free => int } Return the size of the GC heap and the among of free space, in bytes **/ static value gc_stats() { int heap, free; value o; neko_gc_stats(&heap,&free); o = alloc_object(NULL); alloc_field(o,val_id("heap"),alloc_int(heap)); alloc_field(o,val_id("free"),alloc_int(free)); return o; } /** enable_jit : ?bool -> ?bool Enable or disable the JIT. Calling enable_jit(null) tells if JIT is enabled or not **/ static value enable_jit( value b ) { if( val_is_null(b) ) return alloc_bool(neko_vm_jit(neko_vm_current(),-1)); val_check(b,bool); neko_vm_jit(neko_vm_current(),val_bool(b)); return val_null; } /** test : void -> void The test function, to check that library is reachable and correctly linked **/ static value test() { val_print(alloc_string("Calling a function inside std library...\n")); return val_null; } /** print_redirect : function:1? -> void Set a redirection function for all printed values. Setting it to null will cancel the redirection and restore previous printer. **/ static void print_callback( const char *s, int size, void *f ) { val_call1(f,copy_string(s,size)); } static value print_redirect( value f ) { neko_vm *vm = neko_vm_current(); if( val_is_null(f) ) { neko_vm_redirect(vm,NULL,NULL); return val_null; } val_check_function(f,1); neko_vm_redirect(vm,print_callback,f); return val_null; } /** set_trusted : bool -> void Change the trusted mode of the VM. This can optimize some operations such as module loading by turning off some checks. **/ static value set_trusted( value b ) { val_check(b,bool); neko_vm_trusted(neko_vm_current(),val_bool(b)); return val_null; } /** same_closure : any -> any -> bool Compare two functions by checking that they refer to the same implementation and that their environments contains physically equal values. **/ static value same_closure( value _f1, value _f2 ) { vfunction *f1 = (vfunction*)_f1; vfunction *f2 = (vfunction*)_f2; int i; if( !val_is_function(f1) || !val_is_function(f2) ) return val_false; if( f1 == f2 ) return val_true; if( f1->nargs != f2->nargs || f1->addr != f2->addr || f1->module != f2->module || val_array_size(f1->env) != val_array_size(f2->env) ) return val_false; for(i=0;ienv);i++) if( val_array_ptr(f1->env)[i] != val_array_ptr(f2->env)[i] ) return val_false; return val_true; } // ------------- MERGE SORT HELPERS ----------------------------- typedef struct { value *arr; value cmp; } m_sort; static int ms_compare( m_sort *m, int a, int b ) { value v = val_call2(m->cmp,m->arr[a],m->arr[b]); if( !val_is_int(v) ) return -1; return val_int(v); } static void ms_swap( m_sort *m, int a, int b ) { value tmp = m->arr[a]; m->arr[a] = m->arr[b]; m->arr[b] = tmp; } static int ms_lower( m_sort *m, int from, int to, int val ) { int len = to - from, half, mid; while( len > 0 ) { half = len>>1; mid = from + half; if( ms_compare(m, mid, val) < 0 ) { from = mid+1; len = len - half -1; } else len = half; } return from; } static int ms_upper( m_sort *m, int from, int to, int val ) { int len = to - from, half, mid; while( len > 0 ) { half = len>>1; mid = from + half; if( ms_compare(m, val, mid) < 0 ) len = half; else { from = mid+1; len = len - half -1; } } return from; } static int ms_gcd( int m, int n ) { while( n != 0 ) { int t = m % n; m=n; n=t; } return m; } static void ms_rotate( m_sort *m, int from, int mid, int to ) { int n; if( from==mid || mid==to ) return; n = ms_gcd(to - from, mid - from); while (n-- != 0) { value val = m->arr[from+n]; int shift = mid - from; int p1 = from+n, p2=from+n+shift; while (p2 != from + n) { m->arr[p1] = m->arr[p2]; p1=p2; if( to - p2 > shift) p2 += shift; else p2=from + (shift - (to - p2)); } m->arr[p1] = val; } } static void ms_do_merge( m_sort *m, int from, int pivot, int to, int len1, int len2 ) { int first_cut, second_cut, len11, len22, new_mid; if( len1 == 0 || len2==0 ) return; if( len1+len2 == 2 ) { if( ms_compare(m, pivot, from) < 0 ) ms_swap(m, pivot, from); return; } if (len1 > len2) { len11=len1>>1; first_cut = from + len11; second_cut = ms_lower(m, pivot, to, first_cut); len22 = second_cut - pivot; } else { len22 = len2>>1; second_cut = pivot + len22; first_cut = ms_upper(m, from, pivot, second_cut); len11=first_cut - from; } ms_rotate(m, first_cut, pivot, second_cut); new_mid=first_cut+len22; ms_do_merge(m, from, first_cut, new_mid, len11, len22); ms_do_merge(m, new_mid, second_cut, to, len1 - len11, len2 - len22); } static void merge_sort_rec( m_sort *m, int from, int to ) { int middle; if( to - from < 12 ) { // insert sort int i; if( to <= from ) return; for(i=from+1;i from ) { if( ms_compare(m,j,j-1) < 0 ) ms_swap(m,j-1,j); else break; j--; } } return; } middle = (from + to)>>1; merge_sort_rec(m, from, middle); merge_sort_rec(m, middle, to); ms_do_merge(m, from, middle, to, middle-from, to - middle); } /** merge_sort : array -> length:int -> cmp:function:2 -> void Sort the array using stable in-place merge sort and the [cmp] compare function. **/ static value merge_sort( value arr, value len, value cmp ) { m_sort m; val_check(arr,array); val_check(len,int); val_check_function(cmp,2); m.arr = val_array_ptr(arr); m.cmp = cmp; merge_sort_rec(&m,0,val_int(len)); return val_null; } DEFINE_PRIM(float_bytes,2); DEFINE_PRIM(double_bytes,2); DEFINE_PRIM(float_of_bytes,2); DEFINE_PRIM(double_of_bytes,2); DEFINE_PRIM(run_gc,1); DEFINE_PRIM(gc_stats,0); DEFINE_PRIM(enable_jit,1); DEFINE_PRIM(test,0); DEFINE_PRIM(print_redirect,1); DEFINE_PRIM(set_trusted,1); DEFINE_PRIM(same_closure,2); DEFINE_PRIM(merge_sort,3); /* ************************************************************************ */ neko-2.0.0/libs/std/thread.c0000644000175000017500000003503712112157473016322 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #undef free_lock #undef lock_release #include #include #include #ifdef NEKO_WINDOWS # include typedef HANDLE vlock; #else # include # include typedef struct _vlock { pthread_mutex_t lock; pthread_cond_t cond; int counter; } *vlock; #endif typedef struct _tqueue { value msg; struct _tqueue *next; } tqueue; typedef struct { tqueue *first; tqueue *last; # ifdef NEKO_WINDOWS CRITICAL_SECTION lock; HANDLE wait; # else pthread_mutex_t lock; pthread_cond_t wait; # endif } vdeque; typedef struct { # ifdef NEKO_WINDOWS DWORD tid; # else pthread_t phandle; # endif value v; vdeque q; neko_vm *vm; } vthread; DECLARE_KIND(k_thread); #define val_thread(t) ((vthread*)val_data(t)) #ifdef NEKO_WINDOWS # define LOCK(l) EnterCriticalSection(&(l)) # define UNLOCK(l) LeaveCriticalSection(&(l)) # define SIGNAL(l) ReleaseSemaphore(l,1,NULL) #else # define LOCK(l) pthread_mutex_lock(&(l)) # define UNLOCK(l) pthread_mutex_unlock(&(l)) # define SIGNAL(l) pthread_cond_signal(&(l)) #endif /* deque raw API */ static void _deque_init( vdeque *q ) { # ifdef NEKO_WINDOWS q->wait = CreateSemaphore(NULL,0,(1 << 30),NULL); InitializeCriticalSection(&q->lock); # else pthread_mutex_init(&q->lock,NULL); pthread_cond_init(&q->wait,NULL); # endif } static void _deque_destroy( vdeque *q ) { #ifdef NEKO_WINDOWS DeleteCriticalSection(&q->lock); CloseHandle(q->wait); #else pthread_mutex_destroy(&q->lock); pthread_cond_destroy(&q->wait); #endif } static void _deque_add( vdeque *q, value msg ) { tqueue *t; t = (tqueue*)alloc(sizeof(tqueue)); t->msg = msg; t->next = NULL; LOCK(q->lock); if( q->last == NULL ) q->first = t; else q->last->next = t; q->last = t; SIGNAL(q->wait); UNLOCK(q->lock); } static void _deque_push( vdeque *q, value msg ) { tqueue *t; t = (tqueue*)alloc(sizeof(tqueue)); t->msg = msg; LOCK(q->lock); t->next = q->first; q->first = t; if( q->last == NULL ) q->last = t; SIGNAL(q->wait); UNLOCK(q->lock); } static value _deque_pop( vdeque *q, int block ) { value msg; LOCK(q->lock); while( q->first == NULL ) if( block ) { # ifdef NEKO_WINDOWS UNLOCK(q->lock); WaitForSingleObject(q->wait,INFINITE); LOCK(q->lock); # else pthread_cond_wait(&q->wait,&q->lock); # endif } else { UNLOCK(q->lock); return val_null; } msg = q->first->msg; q->first = q->first->next; if( q->first == NULL ) q->last = NULL; else SIGNAL(q->wait); UNLOCK(q->lock); return msg; } /**

Thread

An API to create and manager system threads and locks.

**/ #define val_lock(l) ((vlock)val_data(l)) #define val_tls(l) ((vtls*)val_data(l)) #define val_mutex(l) ((mt_lock*)val_data(l)) #define val_deque(l) ((vdeque*)val_data(l)) typedef struct { # ifdef NEKO_WINDOWS DWORD tls; # else pthread_key_t key; # endif } vtls; DEFINE_KIND(k_thread); DEFINE_KIND(k_lock); DEFINE_KIND(k_tls); DEFINE_KIND(k_mutex); DEFINE_KIND(k_deque); typedef struct { value callb; value callparam; vthread *t; void *handle; int jit; } tparams; static vthread *neko_thread_current() { return (vthread*)neko_vm_custom(neko_vm_current(),k_thread); } static void free_thread( value v ) { vthread *t = val_thread(v); _deque_destroy(&t->q); } static vthread *alloc_thread( neko_vm *vm ) { vthread *t = (vthread*)alloc(sizeof(vthread)); memset(t,0,sizeof(vthread)); #ifdef NEKO_WINDOWS t->tid = GetCurrentThreadId(); #else t->phandle = pthread_self(); #endif t->v = alloc_abstract(k_thread,t); t->vm = vm; _deque_init(&t->q); val_gc(t->v,free_thread); return t; } static void thread_init( void *_p ) { tparams *p = (tparams*)_p; neko_vm *vm; // init the VM and set current thread vm = neko_vm_alloc(NULL); p->t = alloc_thread(vm); neko_vm_jit(vm,p->jit); neko_vm_select(vm); neko_vm_set_custom(vm,k_thread,p->t); } static void thread_loop( void *_p ) { tparams *p = (tparams*)_p; value exc = NULL; val_callEx(val_null,p->callb,&p->callparam,1,&exc); // display exception if( exc != NULL ) { buffer b = alloc_buffer(NULL); fprintf(stderr,"An exception occured in a neko Thread :\n"); val_buffer(b,exc); fprintf(stderr,"%s\n",val_string(buffer_to_string(b))); } // cleanup neko_vm_select(NULL); p->t->v = val_null; p->t->vm = NULL; } /** thread_create : f:function:1 -> p:any -> 'thread Creates a thread that will be running the function [f(p)] **/ static value thread_create( value f, value param ) { tparams *p; val_check_function(f,1); p = (tparams*)alloc(sizeof(tparams)); p->callb = f; p->callparam = param; p->jit = neko_vm_jit(neko_vm_current(),-1); if( !neko_thread_create(thread_init,thread_loop,p,&p->handle) ) neko_error(); return p->t->v; } /** thread_current : void -> 'thread Returns the current thread **/ static value thread_current() { vthread *t = neko_thread_current(); // should only occur for main thread ! if( t == NULL ) { neko_vm *vm = neko_vm_current(); t = alloc_thread(vm); neko_vm_set_custom(vm,k_thread,t); } return t->v; } /** thread_send : 'thread -> msg:any -> void Send a message into the target thread message queue **/ static value thread_send( value vt, value msg ) { vthread *t; val_check_kind(vt,k_thread); t = val_thread(vt); _deque_add(&t->q,msg); return val_null; } /** thread_read_message : block:bool -> any Reads a message from the message queue. If [block] is true, the function only returns when a message is available. If [block] is false and no message is available in the queue, the function will return immediatly [null]. **/ static value thread_read_message( value block ) { value v = thread_current(); vthread *t; if( v == NULL ) neko_error(); t = val_thread(v); val_check(block,bool); return _deque_pop( &t->q, val_bool(block) ); } /** thread_stack : 'thread -> array Get the thread current call stack. Might crash if the thread currently manipulate the stack, so mostly used to debug infinite loops. **/ static value thread_stack( value vt ) { vthread *t; val_check_kind(vt,k_thread); t = val_thread(vt); if( t->vm == NULL ) neko_error(); return neko_call_stack(t->vm); } static void free_lock( value l ) { # ifdef NEKO_WINDOWS CloseHandle( val_lock(l) ); # else pthread_cond_destroy( &val_lock(l)->cond ); pthread_mutex_destroy( &val_lock(l)->lock ); # endif } /** lock_create : void -> 'lock Creates a lock which is initially locked **/ static value lock_create() { value vl; vlock l; # ifdef NEKO_WINDOWS l = CreateSemaphore(NULL,0,(1 << 30),NULL); if( l == NULL ) neko_error(); # else l = (vlock)alloc_private(sizeof(struct _vlock)); l->counter = 0; if( pthread_mutex_init(&l->lock,NULL) != 0 || pthread_cond_init(&l->cond,NULL) != 0 ) neko_error(); # endif vl = alloc_abstract(k_lock,l); val_gc(vl,free_lock); return vl; } /** lock_release : 'lock -> void Release a lock. The thread does not need to own the lock to be able to release it. If a lock is released several times, it can be acquired as many times **/ static value lock_release( value lock ) { vlock l; val_check_kind(lock,k_lock); l = val_lock(lock); # ifdef NEKO_WINDOWS if( !ReleaseSemaphore(l,1,NULL) ) neko_error(); # else pthread_mutex_lock(&l->lock); l->counter++; pthread_cond_signal(&l->cond); pthread_mutex_unlock(&l->lock); # endif return val_true; } /** lock_wait : 'lock -> timeout:number? -> bool Waits for a lock to be released and acquire it. If [timeout] (in seconds) is not null and expires then the returned value is false **/ static value lock_wait( value lock, value timeout ) { int has_timeout = !val_is_null(timeout); val_check_kind(lock,k_lock); if( has_timeout ) val_check(timeout,number); # ifdef NEKO_WINDOWS switch( WaitForSingleObject(val_lock(lock),has_timeout?(DWORD)(val_number(timeout) * 1000.0):INFINITE) ) { case WAIT_ABANDONED: case WAIT_OBJECT_0: return val_true; case WAIT_TIMEOUT: return val_false; default: neko_error(); } # else { vlock l = val_lock(lock); pthread_mutex_lock(&l->lock); while( l->counter == 0 ) { if( has_timeout ) { struct timeval tv; struct timespec t; double delta = val_number(timeout); int idelta = (int)delta, idelta2; delta -= idelta; delta *= 1.0e9; gettimeofday(&tv,NULL); delta += tv.tv_usec * 1000.0; idelta2 = (int)(delta / 1e9); delta -= idelta2 * 1e9; t.tv_sec = tv.tv_sec + idelta + idelta2; t.tv_nsec = (long)delta; if( pthread_cond_timedwait(&l->cond,&l->lock,&t) != 0 ) { pthread_mutex_unlock(&l->lock); return val_false; } } else pthread_cond_wait(&l->cond,&l->lock); } l->counter--; if( l->counter > 0 ) pthread_cond_signal(&l->cond); pthread_mutex_unlock(&l->lock); return val_true; } # endif } static void free_tls( value v ) { vtls *t = val_tls(v); # ifdef NEKO_WINDOWS TlsFree(t->tls); # else pthread_key_delete(t->key); # endif free(t); } /** tls_create : void -> 'tls Creates thread local storage. This is placeholder that can store a value that will be different depending on the local thread. You must set the tls value to [null] before exiting the thread or the memory will never be collected. **/ static value tls_create() { value v; vtls *t = (vtls*)malloc(sizeof(vtls)); # ifdef NEKO_WINDOWS t->tls = TlsAlloc(); TlsSetValue(t->tls,NULL); # else pthread_key_create(&t->key,NULL); # endif v = alloc_abstract(k_tls,t); val_gc(v,free_tls); return v; } /** tls_get : 'tls -> any Returns the value set by [tls_set] for the local thread. **/ static value tls_get( value v ) { vtls *t; value *r; val_check_kind(v,k_tls); t = val_tls(v); # ifdef NEKO_WINDOWS r = (value*)TlsGetValue(t->tls); # else r = (value*)pthread_getspecific(t->key); # endif if( r == NULL ) return val_null; return *r; } /** tls_set : 'tls -> any -> void Set the value of the TLS for the local thread. **/ static value tls_set( value v, value content ) { vtls *t; value *r; val_check_kind(v,k_tls); t = val_tls(v); # ifdef NEKO_WINDOWS r = (value*)TlsGetValue(t->tls); # else r = (value*)pthread_getspecific(t->key); # endif if( r == NULL ) { if( val_is_null(content) ) return val_null; r = alloc_root(1); # ifdef NEKO_WINDOWS TlsSetValue(t->tls,r); # else pthread_setspecific(t->key,r); # endif } else if( val_is_null(content) ) { free_root(r); # ifdef NEKO_WINDOWS TlsSetValue(t->tls,NULL); # else pthread_setspecific(t->key,NULL); # endif return val_null; } *r = content; return val_null; } static void free_mutex( value v ) { neko_free_lock( val_mutex(v) ); } /** mutex_create : void -> 'mutex Creates a mutex, which can be used to acquire a temporary lock to access some ressource. The main difference with a lock is that a mutex must always be released by the owner thread. **/ static value mutex_create() { mt_lock *m = neko_alloc_lock(); value v = alloc_abstract(k_mutex,m); val_gc(v,free_mutex); return v; } /** mutex_acquire : 'mutex -> void The current thread acquire the mutex or wait if not available. The same thread can acquire several times the same mutex but must release it as many times it has been acquired. **/ static value mutex_acquire( value m ) { val_check_kind(m,k_mutex); neko_lock_acquire( val_mutex(m) ); return val_null; } /** mutex_try : 'mutex -> bool Try to acquire the mutex, returns true if acquire or false if it's already locked by another thread. **/ static value mutex_try( value m ) { val_check_kind(m,k_mutex); return alloc_bool( neko_lock_try(val_mutex(m)) ); } /** mutex_release : 'mutex -> void Release a mutex that has been acquired by the current thread. The behavior is undefined if the current thread does not own the mutex. **/ static value mutex_release( value m ) { val_check_kind(m,k_mutex); neko_lock_release(val_mutex(m)); return val_null; } static void free_deque( value v ) { _deque_destroy(val_deque(v)); } /** deque_create : void -> 'deque create a message queue for multithread access **/ static value deque_create() { vdeque *q = (vdeque*)alloc(sizeof(vdeque)); value v = alloc_abstract(k_deque,q); val_gc(v,free_deque); _deque_init(q); return v; } /** deque_add : 'deque -> any -> void add a message at the end of the queue **/ static value deque_add( value v, value i ) { val_check_kind(v,k_deque); _deque_add(val_deque(v),i); return val_null; } /** deque_push : 'deque -> any -> void add a message at the head of the queue **/ static value deque_push( value v, value i ) { val_check_kind(v,k_deque); _deque_push(val_deque(v),i); return val_null; } /** deque_pop : 'deque -> bool -> any? pop a message from the queue head. Either block until a message is available or return immedialtly with null. **/ static value deque_pop( value v, value block ) { val_check_kind(v,k_deque); val_check(block,bool); return _deque_pop(val_deque(v),val_bool(block)); } DEFINE_PRIM(thread_create,2); DEFINE_PRIM(thread_current,0); DEFINE_PRIM(thread_send,2); DEFINE_PRIM(thread_read_message,1); DEFINE_PRIM(thread_stack,1); DEFINE_PRIM(lock_create,0); DEFINE_PRIM(lock_wait,2); DEFINE_PRIM(lock_release,1); DEFINE_PRIM(tls_create,0); DEFINE_PRIM(tls_set,2); DEFINE_PRIM(tls_get,1); DEFINE_PRIM(mutex_create,0); DEFINE_PRIM(mutex_acquire,1); DEFINE_PRIM(mutex_try,1); DEFINE_PRIM(mutex_release,1); DEFINE_PRIM(deque_create,0); DEFINE_PRIM(deque_add,2); DEFINE_PRIM(deque_push,2); DEFINE_PRIM(deque_pop,2); neko-2.0.0/libs/std/sys.c0000644000175000017500000003734612112157473015676 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #ifdef NEKO_WINDOWS # include # include # include #else # include # include # include # include # include # include # include # include # include #endif #ifdef NEKO_MAC # include # include # include #endif #ifndef CLK_TCK # define CLK_TCK 100 #endif /**

System

Interactions with the operating system.

**/ /** get_env : string -> string? Get some environment variable if exists **/ static value get_env( value v ) { char *s; val_check(v,string); s = getenv(val_string(v)); if( s == NULL ) return val_null; return alloc_string(s); } /** put_env : var:string -> val:string -> void Set some environment variable value **/ static value put_env( value e, value v ) { #ifdef NEKO_WINDOWS buffer b; val_check(e,string); val_check(v,string); b = alloc_buffer(NULL); val_buffer(b,e); buffer_append_sub(b,"=",1); val_buffer(b,v); if( putenv(val_string(buffer_to_string(b))) != 0 ) neko_error(); #else val_check(e,string); val_check(v,string); if( setenv(val_string(e),val_string(v),1) != 0 ) neko_error(); #endif return val_true; } /** sys_sleep : number -> void Sleep a given number of seconds **/ static value sys_sleep( value f ) { val_check(f,number); #ifdef NEKO_WINDOWS Sleep((DWORD)(val_number(f) * 1000)); #else { struct timespec t; struct timespec tmp; t.tv_sec = (int)val_number(f); t.tv_nsec = (int)((val_number(f) - t.tv_sec) * 1e9); while( nanosleep(&t,&tmp) == -1 ) { if( errno != EINTR ) neko_error(); t = tmp; } } #endif return val_true; } /** set_time_locale : string -> bool Set the locale for LC_TIME, returns true on success **/ static value set_time_locale( value l ) { #ifdef NEKO_POSIX locale_t lc, old; val_check(l,string); lc = newlocale(LC_TIME_MASK,val_string(l),NULL); if( lc == NULL ) return val_false; old = uselocale(lc); if( old == NULL ) { freelocale(lc); return val_false; } if( old != LC_GLOBAL_LOCALE ) freelocale(old); return val_true; #else val_check(l,string); return alloc_bool(setlocale(LC_TIME,val_string(l)) != NULL); #endif } /** get_cwd : void -> string Return current working directory **/ static value get_cwd() { char buf[256]; int l; if( getcwd(buf,256) == NULL ) neko_error(); l = (int)strlen(buf); if( buf[l-1] != '/' && buf[l-1] != '\\' ) { buf[l] = '/'; buf[l+1] = 0; } return alloc_string(buf); } /** set_cwd : string -> void Set current working directory **/ static value set_cwd( value d ) { val_check(d,string); if( chdir(val_string(d)) ) neko_error(); return val_true; } /** sys_string : void -> string Return the local system string. The current value are possible :
  • [Windows]
  • [Linux]
  • [BSD]
  • [Mac]
**/ static value sys_string() { #if defined(NEKO_WINDOWS) return alloc_string("Windows"); #elif defined(NEKO_GNUKBSD) return alloc_string("GNU/kFreeBSD"); #elif defined(NEKO_LINUX) return alloc_string("Linux"); #elif defined(NEKO_BSD) return alloc_string("BSD"); #elif defined(NEKO_MAC) return alloc_string("Mac"); #else #error Unknow system string #endif } /** sys_is64 : void -> bool Returns true if we are on a 64-bit system **/ static value sys_is64() { #ifdef NEKO_64BITS return val_true; #else return val_false; #endif } /** sys_command : string -> int Run the shell command and return exit code **/ static value sys_command( value cmd ) { val_check(cmd,string); if( val_strlen(cmd) == 0 ) return alloc_int(-1); #ifdef NEKO_WINDOWS return alloc_int( system(val_string(cmd)) ); #else int status = system(val_string(cmd)); return alloc_int( WEXITSTATUS(status) | (WTERMSIG(status) << 8) ); #endif } /** sys_exit : int -> void Exit with the given errorcode. Never returns. **/ static value sys_exit( value ecode ) { val_check(ecode,int); exit(val_int(ecode)); return val_true; } /** sys_exists : string -> bool Returns true if the file or directory exists. **/ static value sys_exists( value path ) { struct stat st; val_check(path,string); return alloc_bool(stat(val_string(path),&st) == 0); } /** file_exists : string -> bool Deprecated : use sys_exists instead. **/ static value file_exists( value path ) { return sys_exists(path); } /** file_delete : string -> void Delete the file. Exception on error. **/ static value file_delete( value path ) { val_check(path,string); if( unlink(val_string(path)) != 0 ) neko_error(); return val_true; } /** sys_rename : from:string -> to:string -> void Rename the file or directory. Exception on error. **/ static value sys_rename( value path, value newname ) { val_check(path,string); val_check(newname,string); if( rename(val_string(path),val_string(newname)) != 0 ) neko_error(); return val_true; } #define STATF(f) alloc_field(o,val_id(#f),alloc_int(s.st_##f)) #define STATF32(f) alloc_field(o,val_id(#f),alloc_int32((int)s.st_##f)) /** sys_stat : string -> { gid => int, uid => int, atime => 'int32, mtime => 'int32, ctime => 'int32, dev => int, ino => int, nlink => int, rdev => int, mode => int, size => int } Run the [stat] command on the given file or directory. **/ static value sys_stat( value path ) { struct stat s; value o; val_check(path,string); if( stat(val_string(path),&s) != 0 ) neko_error(); o = alloc_object(NULL); STATF(gid); STATF(uid); STATF32(atime); STATF32(mtime); STATF32(ctime); STATF(dev); STATF(ino); STATF(mode); STATF(nlink); STATF(rdev); STATF(size); STATF(mode); return o; } /** sys_file_type : string -> string Return the type of the file. The current values are possible :
  • [file]
  • [dir]
  • [symlink]
  • [sock]
  • [char]
  • [block]
  • [fifo]
**/ static value sys_file_type( value path ) { struct stat s; val_check(path,string); if( stat(val_string(path),&s) != 0 ) neko_error(); if( s.st_mode & S_IFREG ) return alloc_string("file"); if( s.st_mode & S_IFDIR ) return alloc_string("dir"); if( s.st_mode & S_IFCHR ) return alloc_string("char"); #ifndef NEKO_WINDOWS if( s.st_mode & S_IFLNK ) return alloc_string("symlink"); if( s.st_mode & S_IFBLK ) return alloc_string("block"); if( s.st_mode & S_IFIFO ) return alloc_string("fifo"); if( s.st_mode & S_IFSOCK ) return alloc_string("sock"); #endif neko_error(); } /** sys_create_dir : string -> mode:int -> void Create a directory with the specified rights **/ static value sys_create_dir( value path, value mode ) { val_check(path,string); val_check(mode,int); #ifdef NEKO_WINDOWS if( mkdir(val_string(path)) != 0 ) #else if( mkdir(val_string(path),val_int(mode)) != 0 ) #endif neko_error(); return val_true; } /** sys_remove_dir : string -> void Remove a directory. Exception on error **/ static value sys_remove_dir( value path ) { val_check(path,string); if( rmdir(val_string(path)) != 0 ) neko_error(); return val_true; } /** sys_time : void -> float Return an accurate local time stamp in seconds since Jan 1 1970 **/ static value sys_time() { #ifdef NEKO_WINDOWS #define EPOCH_DIFF (134774*24*60*60.0) SYSTEMTIME t; FILETIME ft; ULARGE_INTEGER ui; GetSystemTime(&t); if( !SystemTimeToFileTime(&t,&ft) ) neko_error(); ui.LowPart = ft.dwLowDateTime; ui.HighPart = ft.dwHighDateTime; return alloc_float( ((tfloat)ui.QuadPart) / 10000000.0 - EPOCH_DIFF ); #else struct timeval tv; if( gettimeofday(&tv,NULL) != 0 ) neko_error(); return alloc_float( tv.tv_sec + ((tfloat)tv.tv_usec) / 1000000.0 ); #endif } /** sys_cpu_time : void -> float Return the most accurate CPU time spent since the process started (in seconds) **/ static value sys_cpu_time() { #ifdef NEKO_WINDOWS FILETIME unused; FILETIME stime; FILETIME utime; if( !GetProcessTimes(GetCurrentProcess(),&unused,&unused,&stime,&utime) ) neko_error(); return alloc_float( ((tfloat)(utime.dwHighDateTime+stime.dwHighDateTime)) * 65.536 * 6.5536 + (((tfloat)utime.dwLowDateTime + (tfloat)stime.dwLowDateTime) / 10000000) ); #else struct tms t; times(&t); return alloc_float( ((tfloat)(t.tms_utime + t.tms_stime)) / CLK_TCK ); #endif } /** sys_thread_cpu_time : void -> float Return the most accurate CPU time spent in user mode in the current thread (in seconds) **/ static value sys_thread_cpu_time() { #if defined(NEKO_WINDOWS) FILETIME unused; FILETIME utime; if( !GetThreadTimes(GetCurrentThread(),&unused,&unused,&unused,&utime) ) neko_error(); return alloc_float( ((tfloat)utime.dwHighDateTime) * 65.536 * 6.5536 + (((tfloat)utime.dwLowDateTime) / 10000000) ); #elif defined(NEKO_MAC) val_throw(alloc_string("sys_thread_cpu_time not implmented on OSX")); return val_null; #else struct timespec t; if( clock_gettime(CLOCK_THREAD_CPUTIME_ID,&t) ) neko_error(); return alloc_float( t.tv_sec + t.tv_nsec * 1e-9 ); #endif } /** sys_read_dir : string -> string list Return the content of a directory **/ static value sys_read_dir( value path ) { value h = val_null; value cur = NULL, tmp; #ifdef NEKO_WINDOWS WIN32_FIND_DATA d; HANDLE handle; buffer b; int len; val_check(path,string); len = val_strlen(path); b = alloc_buffer(NULL); val_buffer(b,path); if( len && val_string(path)[len-1] != '/' && val_string(path)[len-1] != '\\' ) buffer_append(b,"/*.*"); else buffer_append(b,"*.*"); path = buffer_to_string(b); handle = FindFirstFile(val_string(path),&d); if( handle == INVALID_HANDLE_VALUE ) neko_error(); while( true ) { // skip magic dirs if( d.cFileName[0] != '.' || (d.cFileName[1] != 0 && (d.cFileName[1] != '.' || d.cFileName[2] != 0)) ) { tmp = alloc_array(2); val_array_ptr(tmp)[0] = alloc_string(d.cFileName); val_array_ptr(tmp)[1] = val_null; if( cur ) val_array_ptr(cur)[1] = tmp; else h = tmp; cur = tmp; } if( !FindNextFile(handle,&d) ) break; } FindClose(handle); #else DIR *d; struct dirent *e; val_check(path,string); d = opendir(val_string(path)); if( d == NULL ) neko_error(); while( true ) { e = readdir(d); if( e == NULL ) break; // skip magic dirs if( e->d_name[0] == '.' && (e->d_name[1] == 0 || (e->d_name[1] == '.' && e->d_name[2] == 0)) ) continue; tmp = alloc_array(2); val_array_ptr(tmp)[0] = alloc_string(e->d_name); val_array_ptr(tmp)[1] = val_null; if( cur ) val_array_ptr(cur)[1] = tmp; else h = tmp; cur = tmp; } closedir(d); #endif return h; } /** file_full_path : string -> string Return an absolute path from a relative one. The file or directory must exists **/ static value file_full_path( value path ) { #ifdef NEKO_WINDOWS char buf[MAX_PATH+1]; val_check(path,string); if( GetFullPathName(val_string(path),MAX_PATH+1,buf,NULL) == 0 ) neko_error(); return alloc_string(buf); #else char buf[PATH_MAX]; val_check(path,string); if( realpath(val_string(path),buf) == NULL ) neko_error(); return alloc_string(buf); #endif } /** sys_exe_path : void -> string Return the path of the executable **/ static value sys_exe_path() { #if defined(NEKO_WINDOWS) char path[MAX_PATH]; if( GetModuleFileName(NULL,path,MAX_PATH) == 0 ) neko_error(); return alloc_string(path); #elif defined(NEKO_MAC) char path[PATH_MAX+1]; uint32_t path_len = PATH_MAX; if( _NSGetExecutablePath(path, &path_len) ) neko_error(); return alloc_string(path); #else const char *p = getenv("_"); if( p != NULL ) return alloc_string(p); { char path[PATH_MAX]; int length = readlink("/proc/self/exe", path, sizeof(path)); if( length < 0 ) neko_error(); path[length] = '\0'; return alloc_string(path); } #endif } #ifdef NEKO_MAC # define environ (*_NSGetEnviron()) #endif #ifndef NEKO_WINDOWS extern char **environ; #endif /** sys_env : void -> #list Return all the (key,value) pairs in the environment as a chained list **/ static value sys_env() { value h = val_null; value cur = NULL, tmp, key; char **e = environ; while( *e ) { char *x = strchr(*e,'='); if( x == NULL ) { e++; continue; } tmp = alloc_array(3); key = alloc_empty_string((int)(x - *e)); memcpy(val_string(key),*e,(int)(x - *e)); val_array_ptr(tmp)[0] = key; val_array_ptr(tmp)[1] = alloc_string(x+1); val_array_ptr(tmp)[2] = val_null; if( cur ) val_array_ptr(cur)[2] = tmp; else h = tmp; cur = tmp; e++; } return h; } /** sys_getch : bool -> int Read a character from stdin with or without echo **/ static value sys_getch( value b ) { # ifdef NEKO_WINDOWS val_check(b,bool); return alloc_int( val_bool(b)?getche():getch() ); # else // took some time to figure out how to do that // without relying on ncurses, which clear the // terminal on initscr() int c; struct termios term, old; val_check(b,bool); tcgetattr(fileno(stdin), &old); term = old; cfmakeraw(&term); tcsetattr(fileno(stdin), 0, &term); c = getchar(); tcsetattr(fileno(stdin), 0, &old); if( val_bool(b) ) fputc(c,stdout); return alloc_int(c); # endif } /** sys_get_pid : void -> int Returns the current process identifier **/ static value sys_get_pid() { # ifdef NEKO_WINDOWS return alloc_int(GetCurrentProcessId()); # else return alloc_int(getpid()); # endif } /** win_env_changed : void -> void Tell that the windows envionment variables were changed in the registry **/ static value win_env_changed() { # ifdef NEKO_WINDOWS DWORD unused; SendMessageTimeout(HWND_BROADCAST,WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, &unused ); # endif return val_null; } DEFINE_PRIM(get_env,1); DEFINE_PRIM(put_env,2); DEFINE_PRIM(set_time_locale,1); DEFINE_PRIM(get_cwd,0); DEFINE_PRIM(set_cwd,1); DEFINE_PRIM(sys_sleep,1); DEFINE_PRIM(sys_command,1); DEFINE_PRIM(sys_exit,1); DEFINE_PRIM(sys_string,0); DEFINE_PRIM(sys_is64,0); DEFINE_PRIM(sys_stat,1); DEFINE_PRIM(sys_time,0); DEFINE_PRIM(sys_cpu_time,0); DEFINE_PRIM(sys_env,0); DEFINE_PRIM(sys_create_dir,2); DEFINE_PRIM(sys_remove_dir,1); DEFINE_PRIM(sys_read_dir,1); DEFINE_PRIM(file_full_path,1); DEFINE_PRIM(file_exists,1); DEFINE_PRIM(sys_exists,1); DEFINE_PRIM(file_delete,1); DEFINE_PRIM(sys_rename,2); DEFINE_PRIM(sys_exe_path,0); DEFINE_PRIM(sys_file_type,1); DEFINE_PRIM(sys_getch,1); DEFINE_PRIM(sys_get_pid,0); DEFINE_PRIM(sys_thread_cpu_time,0); DEFINE_PRIM(win_env_changed,0); /* ************************************************************************ */ neko-2.0.0/libs/std/xml.c0000644000175000017500000002165312112157473015652 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #ifndef NEKO_WINDOWS # include # undef strcmpi # define strcmpi(a,b) strcasecmp(a,b) #else # include #endif #define ERROR(msg) xml_error(xml,p,line,msg); // -------------- parsing -------------------------- typedef enum { IGNORE_SPACES, BEGIN, BEGIN_NODE, TAG_NAME, BODY, ATTRIB_NAME, EQUALS, ATTVAL_BEGIN, ATTRIB_VAL, CHILDS, CLOSE, WAIT_END, WAIT_END_RET, PCDATA, HEADER, COMMENT, DOCTYPE, CDATA, } STATE; extern field id_pcdata; extern field id_xml; extern field id_done; extern field id_comment; extern field id_cdata; extern field id_doctype; static void xml_error( const char *xml, const char *p, int *line, const char *msg ) { buffer b = alloc_buffer("Xml parse error : "); int l = (int)strlen(p); int nchars = 30; buffer_append(b,msg); buffer_append(b," at line "); val_buffer(b,alloc_int(*line)); buffer_append(b," : "); if( p != xml ) buffer_append(b,"..."); buffer_append_sub(b,p,(l < nchars)?l:nchars); if( l > nchars ) buffer_append(b,"..."); if( l == 0 ) buffer_append(b,""); bfailure(b); } static bool is_valid_char( int c ) { return ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= '0' && c <= '9' ) || c == ':' || c == '.' || c == '_' || c == '-'; } static void do_parse_xml( const char *xml, const char **lp, int *line, value callb, const char *parentname ) { STATE state = BEGIN; STATE next = BEGIN; field aname = (field)0; value attribs = NULL; value nodename = NULL; const char *start = NULL; const char *p = *lp; char c = *p; int nsubs = 0, nbrackets = 0; while( c ) { switch( state ) { case IGNORE_SPACES: switch( c ) { case '\n': case '\r': case '\t': case ' ': break; default: state = next; continue; } break; case BEGIN: switch( c ) { case '<': state = IGNORE_SPACES; next = BEGIN_NODE; break; default: start = p; state = PCDATA; continue; } break; case PCDATA: if( c == '<' ) { val_ocall1(callb,id_pcdata,copy_string(start,p-start)); nsubs++; state = IGNORE_SPACES; next = BEGIN_NODE; } break; case CDATA: if( c == ']' && p[1] == ']' && p[2] == '>' ) { val_ocall1(callb,id_cdata,copy_string(start,p-start)); nsubs++; p += 2; state = BEGIN; } break; case BEGIN_NODE: switch( c ) { case '!': if( p[1] == '[' ) { p += 2; if( (p[0] != 'C' && p[0] != 'c') || (p[1] != 'D' && p[1] != 'd') || (p[2] != 'A' && p[2] != 'a') || (p[3] != 'T' && p[3] != 't') || (p[4] != 'A' && p[4] != 'a') || (p[5] != '[') ) ERROR("Expected ': state = CHILDS; nsubs++; val_ocall2(callb,id_xml,nodename,attribs); break; default: state = ATTRIB_NAME; start = p; continue; } break; case ATTRIB_NAME: if( !is_valid_char(c) ) { value tmp; if( start == p ) ERROR("Expected attribute name"); tmp = copy_string(start,p-start); aname = val_id(val_string(tmp)); if( !val_is_null(val_field(attribs,aname)) ) ERROR("Duplicate attribute"); state = IGNORE_SPACES; next = EQUALS; continue; } break; case EQUALS: switch( c ) { case '=': state = IGNORE_SPACES; next = ATTVAL_BEGIN; break; default: ERROR("Expected ="); } break; case ATTVAL_BEGIN: switch( c ) { case '"': case '\'': state = ATTRIB_VAL; start = p; break; default: ERROR("Expected \""); } break; case ATTRIB_VAL: if( c == *start ) { value aval = copy_string(start+1,p-start-1); alloc_field(attribs,aname,aval); state = IGNORE_SPACES; next = BODY; } break; case CHILDS: *lp = p; do_parse_xml(xml,lp,line,callb,val_string(nodename)); p = *lp; start = p; state = BEGIN; break; case WAIT_END: switch( c ) { case '>': val_ocall0(callb,id_done); state = BEGIN; break; default : ERROR("Expected >"); } break; case WAIT_END_RET: switch( c ) { case '>': if( nsubs == 0 ) val_ocall1(callb,id_pcdata,alloc_string("")); val_ocall0(callb,id_done); *lp = p; return; default : ERROR("Expected >"); } break; case CLOSE: if( !is_valid_char(c) ) { if( start == p ) ERROR("Expected node name"); { value v = copy_string(start,p - start); if( strcmpi(parentname,val_string(v)) != 0 ) { buffer b = alloc_buffer("Expected "); ERROR(val_string(buffer_to_string(b))); } } state = IGNORE_SPACES; next = WAIT_END_RET; continue; } break; case COMMENT: if( c == '-' && p[1] == '-' && p[2] == '>' ) { val_ocall1(callb,id_comment,copy_string(start,p-start)); p += 2; state = BEGIN; } break; case DOCTYPE: if( c == '[' ) nbrackets++; else if( c == ']' ) nbrackets--; else if( c == '>' && nbrackets == 0 ) { val_ocall1(callb,id_doctype,copy_string(start,p-start)); state = BEGIN; } break; case HEADER: if( c == '?' && p[1] == '>' ) { p++; val_ocall1(callb,id_comment,copy_string(start,p-start)); state = BEGIN; } break; } c = *++p; if( c == '\n' ) (*line)++; } if( state == BEGIN ) { start = p; state = PCDATA; } if( parentname == NULL && state == PCDATA ) { if( p != start || nsubs == 0 ) val_ocall1(callb,id_pcdata,copy_string(start,p-start)); return; } ERROR("Unexpected end"); } // ---------------------------------------------- /**

Xml

The standard event-driven XML parser.

**/ /** parse_xml : xml:string -> events:object -> void The [parse_xml] parse a string and for each parsed element call the corresponding object method in [events] :
  • [void xml( name : string, attribs : object)] when an XML node is found
  • [void done()] when an XML node is closed
  • [void pcdata(string)] when PCData chars found
  • [void cdata(string)] when a CData session is found
  • [void comment(string)] when some comment or special header is found
You can then implement the events so they build the appropriate XML data structure needed by your language.
**/ static value parse_xml( value str, value callb ) { const char *p; int line = 0; val_check(str,string); val_check(callb,object); p = val_string(str); // skip BOM if( p[0] == (char)0xEF && p[1] == (char)0xBB && p[2] == (char)0xBF ) p += 3; do_parse_xml(p,&p,&line,callb,NULL); return val_true; } DEFINE_PRIM(parse_xml,2); /* ************************************************************************ */ neko-2.0.0/libs/std/memory.c0000644000175000017500000001244012112157473016354 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include /**

Memory

An API for memory manipulation and statistics.

**/ typedef struct _vtree { int_val v; struct _vtree *left; struct _vtree *right; } vtree; typedef struct { vtree **t; int s; } vparams; static int mem_cache( void *v, vtree **t ) { vtree *p = *t; vtree *prev = NULL; while( p != NULL ) { if( p->v == (int_val)v ) return 1; prev = p; if( p->v > (int_val)v ) p = p->left; else p = p->right; } p = (vtree*)alloc(sizeof(vtree)); p->v = (int_val)v; p->left = NULL; p->right = NULL; if( prev == NULL ) *t = p; else { if( prev->v > p->v ) prev->left = p; else prev->right = p; } return 0; } static void mem_obj_field( value v, field f, void *_p ); static int mem_module( neko_module *m, vtree **l ); static int mem_size_rec( value v, vtree **l ) { switch( val_type(v) ) { case VAL_INT: case VAL_BOOL: case VAL_NULL: return 0; case VAL_FLOAT: if( mem_cache(v,l) ) return 0; return sizeof(vfloat); case VAL_INT32: if( mem_cache(v,l) ) return 0; return sizeof(vint32); case VAL_STRING: if( mem_cache(v,l) ) return 0; return sizeof(value) + val_strlen(v); case VAL_OBJECT: if( mem_cache(v,l) ) return 0; { vparams p; p.t = l; p.s = sizeof(vobject); val_iter_fields(v,mem_obj_field,&p); if( ((vobject*)v)->proto != NULL ) p.s += mem_size_rec((value)((vobject*)v)->proto,l); return p.s; } case VAL_ARRAY: if( mem_cache(v,l) ) return 0; { int t = sizeof(value); int size = val_array_size(v); int i; t += size * sizeof(value); for(i=0;ienv,l); if( val_tag(v) == VAL_PRIMITIVE ) t += mem_size_rec((value)((vfunction*)v)->module,l); else t += mem_module(((vfunction*)v)->module,l); return t; } case VAL_ABSTRACT: { int t; if( mem_cache(v,l) ) return 0; t = sizeof(vabstract); if( val_kind(v) == neko_kind_module ) t += mem_module((neko_module*)val_data(v),l); else if( val_kind(v) == k_hash ) { vhash *h = (vhash*)val_data(v); int i; t += sizeof(vhash); t += sizeof(hcell*) * h->ncells; for(i=0;incells;i++) { hcell *c = h->cells[i]; while( c != NULL ) { t += sizeof(hcell); t += mem_size_rec(c->key,l); t += mem_size_rec(c->val,l); c = c->next; } } } return t; } default: val_throw(alloc_string("mem_size : Unexpected value")); break; } return 0; } static void mem_obj_field( value v, field f, void *_p ) { vparams *p = (vparams*)_p; p->s += sizeof(objcell); p->s += mem_size_rec(v,p->t); } static int mem_module( neko_module *m, vtree **l ) { int t = 0; unsigned int i; if( mem_cache(m,l) ) return 0; t += sizeof(neko_module); t += m->codesize * sizeof(int_val); t += m->nglobals * sizeof(int_val); for(i=0;inglobals;i++) t += mem_size_rec(m->globals[i],l); t += m->nfields * sizeof(value*); for(i=0;infields;i++) t += mem_size_rec(m->fields[i],l); t += mem_size_rec(m->loader,l); t += mem_size_rec(m->exports,l); t += mem_size_rec(m->dbgtbl,l); if( m->dbgidxs ) t += sizeof(neko_debug) * (m->codesize >> 5); t += mem_size_rec(m->name,l); return t; } /** mem_size : any -> int Calculate the quite precise amount of VM memory reachable from this value **/ static value mem_size( value v ) { vtree *t = NULL; return alloc_int(mem_size_rec(v,&t)); } /** mem_local_size : any -> any array -> int Calculate the quite precise amount of VM memory reachable from this value, without scanning the values contained in the array. **/ static value mem_local_size( value v, value a ) { vtree *t = NULL; int i; val_check(a,array); for(i=0;i #include #define BUF_SIZE 4096 #define ERROR() val_throw(alloc_string("Invalid serialized data")) typedef struct strlist { unsigned char *str; int slen; struct strlist *next; } strlist; typedef struct odatalist { int k; value data; struct odatalist *left; struct odatalist *right; } odatalist; typedef struct { odatalist *refs; int nrefs; value *trefs; int tsize; strlist *olds; unsigned char *cur; int size; int pos; int totlen; int nrec; } sbuffer; extern field id_module; extern field id_loadmodule; extern field id_loadprim; extern field id_serialize; extern field id_unserialize; static void buffer_alloc( sbuffer *b, int size ) { strlist *str = (strlist*)alloc(sizeof(strlist)); str->str = b->cur; str->slen = b->pos; str->next = b->olds; b->olds = str; b->totlen += b->pos; b->pos = 0; b->size = size; b->cur = (unsigned char*)alloc_private(size); } static void write_char( sbuffer *b, char c ) { if( b->pos == b->size ) buffer_alloc(b,BUF_SIZE); b->cur[b->pos++] = c; } static int read_char( sbuffer *b ) { if( b->pos >= b->size ) return -1; return b->cur[b->pos++]; } static void write_str( sbuffer *b, int len, const void *s ) { int left = b->size - b->pos; if( left == 0 ) { buffer_alloc(b,BUF_SIZE); left = b->size - b->pos; } if( left >= len ) { memcpy(b->cur + b->pos,s,len); b->pos += len; } else { memcpy(b->cur + b->pos,s,left); b->pos += left; write_str(b,len - left, (char*)s + left); } } static void read_str( sbuffer *b, int len, void *s ) { if( b->pos + len > b->size ) ERROR(); memcpy(s,b->cur + b->pos, len); b->pos += len; } static void write_int( sbuffer *b, int n ) { write_str(b,4,&n); } static int read_int( sbuffer *b ) { int n; if( b->pos + 4 > b->size ) ERROR(); memcpy(&n,b->cur + b->pos,4); b->pos += 4; return n; } static void lookup_serialize_field( value data, field id, void *v ) { if( id == id_serialize ) *(value*)v = data; } static bool write_ref( sbuffer *b, value o, value *serialize ) { odatalist *d = b->refs, *prev = NULL; while( d != NULL ) { if( d->data < o ) { prev = d; d = d->left; } else if( d->data == o ) { write_char(b,'r'); write_int(b,b->nrefs - 1 - d->k); return true; } else { prev = d; d = d->right; } } if( serialize != NULL ) { *serialize = NULL; val_iter_fields(o,lookup_serialize_field,serialize); if( *serialize != NULL ) return false; } d = (odatalist*)alloc(sizeof(odatalist)); d->data = o; d->k = b->nrefs++; d->left = NULL; d->right = NULL; if( prev == NULL ) b->refs = d; else if( prev->data < o ) prev->left = d; else prev->right = d; return false; } static void add_ref( sbuffer *b, value v ) { if( b->nrefs == b->tsize ) { int nsize = b->tsize?(b->tsize*2):16; value *ntrefs = (value*)alloc(sizeof(value) * nsize); memcpy(ntrefs,b->trefs,b->tsize * sizeof(value)); b->trefs = ntrefs; b->tsize = nsize; } b->trefs[b->nrefs++] = v; } static void serialize_fields_rec( value data, field id, void *b ); void serialize_rec( sbuffer *b, value o ) { b->nrec++; if( b->nrec > 350 ) failure("Serialization stack overflow"); switch( val_type(o) ) { case VAL_NULL: write_char(b,'N'); break; case VAL_BOOL: if( val_bool(o) ) write_char(b,'T'); else write_char(b,'F'); break; case VAL_INT: write_char(b,'i'); write_int(b,val_int(o)); break; case VAL_FLOAT: write_char(b,'f'); write_str(b,sizeof(tfloat),&val_float(o)); break; case VAL_STRING: if( !write_ref(b,o,NULL) ) { write_char(b,'s'); write_int(b,val_strlen(o)); write_str(b,val_strlen(o),val_string(o)); } break; case VAL_OBJECT: { value s; if( !write_ref(b,o,&s) ) { if( s != NULL ) { // reference was not written if( !val_is_function(s) || (val_fun_nargs(s) != 0 && val_fun_nargs(s) != VAR_ARGS) ) failure("Invalid __serialize method"); write_char(b,'x'); serialize_rec(b,((neko_module*)((vfunction*)s)->module)->name); serialize_rec(b,val_ocall0(o,id_serialize)); // put reference back write_ref(b,o,NULL); break; } write_char(b,'o'); val_iter_fields(o,serialize_fields_rec,b); write_int(b,0); o = (value)((vobject*)o)->proto; if( o == NULL ) write_char(b,'z'); else { write_char(b,'p'); serialize_rec(b,o); } } } break; case VAL_ARRAY: if( !write_ref(b,o,NULL) ) { int i; int n = val_array_size(o); write_char(b,'a'); write_int(b,n); for(i=0;ienv != alloc_array(0) ) failure("Cannot Serialize Primitive with environment"); write_char(b,'p'); write_int(b,((vfunction*)o)->nargs); serialize_rec(b,((vfunction*)o)->module); break; } if( val_tag(o) == VAL_JITFUN ) failure("Cannot Serialize JIT method"); write_char(b,'L'); m = (neko_module*)((vfunction*)o)->module; serialize_rec(b,m->name); write_int(b,(int)((int_val*)((vfunction*)o)->addr - m->code)); write_int(b,((vfunction*)o)->nargs); serialize_rec(b,((vfunction*)o)->env); } break; case VAL_INT32: write_char(b,'I'); write_int(b,val_int32(o)); break; case VAL_ABSTRACT: if( val_is_kind(o,k_hash) ) { int i; vhash *h = val_hdata(o); write_char(b,'h'); write_int(b,h->ncells); write_int(b,h->nitems); for(i=0;incells;i++) { hcell *c = h->cells[i]; while( c != NULL ) { write_int(b,c->hkey); serialize_rec(b,c->key); serialize_rec(b,c->val); c = c->next; } } break; } default: failure("Cannot Serialize Abstract"); break; } b->nrec--; } static void serialize_fields_rec( value data, field id, void *b ) { write_int(b,(int)id); serialize_rec(b,data); } /**

Serialize

Serialization can be used in order to store permanantly some runtime value. Serialization of all values is possible, except Abstracts, with the special cases of ['int32] and ['hash] which are handled as specific cases.

Serialization of bytecode function is possible, but will result in a runtime exception when deserializing if the function offset in the bytecode has changed.

You can define the __serialize method of an object. When this method is found when serializing the object, it is called with no arguments and its return value will be serialized. The name of the module the method is declared in will also be serialized. When unserializing, the module is loaded and its __unserialize exported function is called with the value that was returned by __serialize.

**/ /** serialize : any -> string Serialize any value recursively **/ static value serialize( value o ) { sbuffer b; value v; char *s; strlist *l; b.olds = NULL; b.refs = NULL; b.nrefs = 0; b.cur = (unsigned char*)alloc_private(BUF_SIZE); b.size = BUF_SIZE; b.pos = 0; b.totlen = 0; b.nrec = 0; serialize_rec(&b,o); v = alloc_empty_string(b.pos + b.totlen); s = (char*)val_string(v); s += b.totlen; l = b.olds; memcpy(s,b.cur,b.pos); while( l != NULL ) { s -= l->slen; memcpy(s,l->str,l->slen); l = l->next; } return v; } static value unserialize_rec( sbuffer *b, value loader ) { switch( read_char(b) ) { case 'N': return val_null; case 'T': return val_true; case 'F': return val_false; case 'i': return alloc_int(read_int(b)); case 'I': return alloc_int32(read_int(b)); case 'f': { tfloat d; read_str(b,sizeof(tfloat),&d); return alloc_float(d); } case 's': { int l = read_int(b); value v; if( l < 0 || l > max_string_size ) ERROR(); v = alloc_empty_string(l); add_ref(b,v); read_str(b,l,(char*)val_string(v)); return v; } case 'o': { int f; value o = alloc_object(NULL); add_ref(b,o); while( (f = read_int(b)) != 0 ) { value fval = unserialize_rec(b,loader); alloc_field(o,(field)f,fval); } switch( read_char(b) ) { case 'p': { value v = unserialize_rec(b,loader); if( !val_is_object(v) ) ERROR(); ((vobject*)o)->proto = (vobject*)v; } break; case 'z': break; default: ERROR(); } return o; } case 'r': { int n = read_int(b); if( n < 0 || n >= b->nrefs ) ERROR(); return b->trefs[b->nrefs - n - 1]; } case 'a': { int i; int n = read_int(b); value o; value *t; if( n < 0 || n > max_array_size ) ERROR(); o = alloc_array(n); t = val_array_ptr(o); add_ref(b,o); for(i=0;it = f2->t; f->addr = f2->addr; f->module = f2->module; return (value)f; } case 'L': { vfunction *f = (vfunction*)alloc_function((void*)1,0,NULL); value mname; int pos; int nargs; value env; add_ref(b,(value)f); mname = unserialize_rec(b,loader); pos = read_int(b); nargs = read_int(b); env = unserialize_rec(b,loader); if( !val_is_array(env) ) ERROR(); { value exp = val_ocall2(loader,id_loadmodule,mname,loader); value mval; unsigned int i; int_val *mpos; neko_module *m; if( !val_is_object(exp) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," is not an object"); bfailure(b); } mval = val_field(exp,id_module); if( !val_is_kind(mval,neko_kind_module) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has invalid type"); bfailure(b); } m = (neko_module*)val_data(mval); mpos = m->code + pos; for(i=0;inglobals;i++) { vfunction *g = (vfunction*)m->globals[i]; if( val_is_function(g) && g->addr == mpos && g->module == m && g->nargs == nargs ) { f->t = VAL_FUNCTION; f->env = env; f->addr = mpos; f->nargs = nargs; f->module = m; return (value)f; } } { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has been modified"); bfailure(b); } } return val_null; } case 'x': { value mname = unserialize_rec(b,loader); value data = unserialize_rec(b,loader); value exports = val_ocall2(loader,id_loadmodule,mname,loader); value s; if( !val_is_object(exports) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," is not an object"); bfailure(b); } s = val_field(exports,id_unserialize); if( !val_is_function(s) || (val_fun_nargs(s) != 1 && val_fun_nargs(s) != VAR_ARGS) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has invalid __unserialize function"); } s = val_call1(s,data); add_ref(b,s); return s; } case 'h': { int i; vhash *h = (vhash*)alloc(sizeof(vhash)); h->ncells = read_int(b); h->nitems = read_int(b); h->cells = (hcell**)alloc(sizeof(hcell*)*h->ncells); for(i=0;incells;i++) h->cells[i] = NULL; for(i=0;initems;i++) { hcell **p; hcell *c = (hcell*)alloc(sizeof(hcell)); c->hkey = read_int(b); c->key = unserialize_rec(b,loader); c->val = unserialize_rec(b,loader); c->next = NULL; p = &h->cells[c->hkey % h->ncells]; while( *p != NULL ) p = &(*p)->next; *p = c; } return alloc_abstract(k_hash,h); } default: ERROR(); return val_null; } } /** unserialize : string -> #loader -> any Unserialize a stored value. Need a loader to look for modules if some bytecode functions have been serialized. **/ static value unserialize( value s, value loader ) { sbuffer b; val_check(s,string); b.cur = (unsigned char*)val_string(s); b.pos = 0; b.olds = NULL; b.trefs = NULL; b.tsize = 0; b.nrefs = 0; b.size = val_strlen(s); b.totlen = 0; return unserialize_rec(&b,loader); } DEFINE_PRIM(serialize,1); DEFINE_PRIM(unserialize,2); /* ************************************************************************ */ neko-2.0.0/libs/std/init.c0000644000175000017500000000425712112157473016016 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include field id_h; field id_m; field id_s; field id_y; field id_d; field id_module; field id_loadmodule; field id_loadprim; field id_done; field id_comment; field id_xml; field id_pcdata; field id_cdata; field id_doctype; field id_serialize; field id_unserialize; DEFINE_ENTRY_POINT(std_main); extern vkind k_file; extern vkind k_socket; extern vkind k_buffer; extern vkind k_thread; void std_main() { id_h = val_id("h"); id_m = val_id("m"); id_s = val_id("s"); id_y = val_id("y"); id_d = val_id("d"); id_loadmodule = val_id("loadmodule"); id_loadprim = val_id("loadprim"); id_module = val_id("__module"); id_done = val_id("done"); id_comment = val_id("comment"); id_xml = val_id("xml"); id_pcdata = val_id("pcdata"); id_cdata = val_id("cdata"); id_doctype = val_id("doctype"); id_serialize = val_id("__serialize"); id_unserialize = val_id("__unserialize"); kind_share(&k_file,"file"); kind_share(&k_socket,"socket"); kind_share(&k_buffer,"buffer"); kind_share(&k_thread,"thread"); } /* ************************************************************************ */ neko-2.0.0/libs/sqlite/0000755000175000017500000000000012112157473015406 5ustar ncannassencannasseneko-2.0.0/libs/sqlite/sqlite.vcproj0000644000175000017500000001136212112157473020137 0ustar ncannassencannasse neko-2.0.0/libs/sqlite/sqlite.c0000644000175000017500000002133312112157473017055 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include /**

SQLite

Sqlite is a small embeddable SQL database that store all its data into a single file. See http://sqlite.org for more details.

**/ DEFINE_KIND(k_db); DEFINE_KIND(k_result); #define val_db(v) ((database*)val_data(v)) #define val_result(v) ((result*)val_data(v)) typedef struct _database { sqlite3 *db; value last; } database; typedef struct _result { database *db; int ncols; int count; field *names; int *bools; int done; int first; sqlite3_stmt *r; } result; static void sqlite_error( sqlite3 *db ) { buffer b = alloc_buffer("Sqlite error : "); buffer_append(b,sqlite3_errmsg(db)); val_throw(buffer_to_string(b)); } static void finalize_result( result *r, int exc ) { r->first = 0; r->done = 1; if( r->ncols == 0 ) r->count = sqlite3_changes(r->db->db); if( sqlite3_finalize(r->r) != SQLITE_OK && exc ) val_throw(alloc_string("Could not finalize request")); r->r = NULL; r->db->last = NULL; r->db = NULL; } static void free_db( value v ) { database *db = val_db(v); if( db->last != NULL ) finalize_result(val_result(db->last),0); if( sqlite3_close(db->db) != SQLITE_OK ) { // No exception : we shouldn't alloc memory in a finalizer anyway } } /** connect : filename:string -> 'db Open or create the database stored in the specified file. **/ static value connect( value filename ) { int err; database *db = (database*)alloc(sizeof(database)); value v; val_check(filename,string); db->last = NULL; if( (err = sqlite3_open(val_string(filename),&db->db)) != SQLITE_OK ) { buffer b = alloc_buffer("Sqlite error : "); buffer_append(b,sqlite3_errmsg(db->db)); sqlite3_close(db->db); val_throw(buffer_to_string(b)); } v = alloc_abstract(k_db,db); val_gc(v,free_db); return v; } /** close : 'db -> void Closes the database. **/ static value close( value v ) { val_check_kind(v,k_db); free_db(v); val_gc(v,NULL); val_kind(v) = NULL; return val_null; } /** last_insert_id : 'db -> int Returns the last inserted auto_increment id. **/ static value last_insert_id( value db ) { val_check_kind(db,k_db); return alloc_int(sqlite3_last_insert_rowid(val_db(db)->db)); } /** request : 'db -> sql:string -> 'result Executes the SQL request and returns its result **/ static value request( value v, value sql ) { database *db; result *r; const char *tl; int i,j; val_check_kind(v,k_db); val_check(sql,string); db = val_db(v); r = (result*)alloc(sizeof(result)); r->db = db; if( sqlite3_prepare(db->db,val_string(sql),val_strlen(sql),&r->r,&tl) != SQLITE_OK ) { buffer b = alloc_buffer("Sqlite error in "); val_buffer(b,sql); buffer_append(b," : "); buffer_append(b,sqlite3_errmsg(db->db)); val_throw(buffer_to_string(b)); } if( *tl ) { sqlite3_finalize(r->r); val_throw(alloc_string("Cannot execute several SQL requests at the same time")); } r->ncols = sqlite3_column_count(r->r); r->names = (field*)alloc_private(sizeof(field)*r->ncols); r->bools = (int*)alloc_private(sizeof(int)*r->ncols); r->first = 1; r->done = 0; for(i=0;incols;i++) { field id = val_id(sqlite3_column_name(r->r,i)); const char *dtype = sqlite3_column_decltype(r->r,i); for(j=0;jnames[j] == id ) { if( strcmp(sqlite3_column_name(r->r,i),sqlite3_column_name(r->r,j)) == 0 ) { buffer b = alloc_buffer("Error, same field is two times in the request "); val_buffer(b,sql); sqlite3_finalize(r->r); val_throw(buffer_to_string(b)); } else { buffer b = alloc_buffer("Error, same field ids for : "); buffer_append(b,sqlite3_column_name(r->r,i)); buffer_append(b," and "); buffer_append(b,sqlite3_column_name(r->r,j)); buffer_append_char(b,'.'); sqlite3_finalize(r->r); val_throw(buffer_to_string(b)); } } r->names[i] = id; r->bools[i] = dtype?(strcmp(dtype,"BOOL") == 0):0; } // changes in an update/delete if( db->last != NULL ) finalize_result(val_result(db->last),0); db->last = alloc_abstract(k_result,r); return db->last; } /** result_get_length : 'result -> int Returns the number of rows in the result or the number of rows changed by the request. **/ static value result_get_length( value v ) { result *r; val_check_kind(v,k_result); r = val_result(v); if( r->ncols != 0 ) neko_error(); // ??? return alloc_int(r->count); } /** result_get_nfields : 'result -> int Returns the number of fields in the result. **/ static value result_get_nfields( value r ) { val_check_kind(r,k_result); return alloc_int(val_result(r)->ncols); } /** result_next : 'result -> object? Returns the next row in the result or [null] if no more result. **/ static value result_next( value v ) { int i; result *r; val_check_kind(v,k_result); r = val_result(v); if( r->done ) return val_null; switch( sqlite3_step(r->r) ) { case SQLITE_ROW: r->first = 0; v = alloc_object(NULL); for(i=0;incols;i++) { value f; switch( sqlite3_column_type(r->r,i) ) { case SQLITE_NULL: f = val_null; break; case SQLITE_INTEGER: if( r->bools[i] ) f = alloc_bool(sqlite3_column_int(r->r,i)); else f = alloc_int(sqlite3_column_int(r->r,i)); break; case SQLITE_FLOAT: f = alloc_float(sqlite3_column_double(r->r,i)); break; case SQLITE_TEXT: f = alloc_string((char*)sqlite3_column_text(r->r,i)); break; case SQLITE_BLOB: { int size = sqlite3_column_bytes(r->r,i); f = alloc_empty_string(size); memcpy(val_string(f),sqlite3_column_blob(r->r,i),size); break; } default: { buffer b = alloc_buffer("Unknown Sqlite type #"); val_buffer(b,alloc_int(sqlite3_column_type(r->r,i))); val_throw(buffer_to_string(b)); } } alloc_field(v,r->names[i],f); } return v; case SQLITE_DONE: finalize_result(r,1); return val_null; case SQLITE_BUSY: val_throw(alloc_string("Database is busy")); case SQLITE_ERROR: sqlite_error(r->db->db); default: neko_error(); } return val_null; } /** result_get : 'result -> n:int -> string Return the [n]th field of the current result row. **/ static value result_get( value v, value n ) { result *r; val_check_kind(v,k_result); r = val_result(v); if( val_int(n) < 0 || val_int(n) >= r->ncols ) neko_error(); if( r->first ) result_next(v); if( r->done ) neko_error(); return alloc_string((char*)sqlite3_column_text(r->r,val_int(n))); } /** result_get_int : 'result -> n:int -> int Return the [n]th field of the current result row as an integer. **/ static value result_get_int( value v, value n ) { result *r; val_check_kind(v,k_result); r = val_result(v); if( val_int(n) < 0 || val_int(n) >= r->ncols ) neko_error(); if( r->first ) result_next(v); if( r->done ) neko_error(); return alloc_int(sqlite3_column_int(r->r,val_int(n))); } /** result_get_float : 'result -> n:int -> float Return the [n]th field of the current result row as a float. **/ static value result_get_float( value v, value n ) { result *r; val_check_kind(v,k_result); r = val_result(v); if( val_int(n) < 0 || val_int(n) >= r->ncols ) neko_error(); if( r->first ) result_next(v); if( r->done ) neko_error(); return alloc_float(sqlite3_column_double(r->r,val_int(n))); } DEFINE_PRIM(connect,1); DEFINE_PRIM(close,1); DEFINE_PRIM(request,2); DEFINE_PRIM(last_insert_id,1); DEFINE_PRIM(result_get_length,1); DEFINE_PRIM(result_get_nfields,1); DEFINE_PRIM(result_next,1); DEFINE_PRIM(result_get,2); DEFINE_PRIM(result_get_int,2); DEFINE_PRIM(result_get_float,2); /* ************************************************************************ */ neko-2.0.0/libs/sqlite/sqlite.vcxproj0000644000175000017500000001726312112157473020335 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {EDFCD8E6-CFB1-4288-82F5-D069A25C3947} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ true Release\ Release\ false Release\ Release\ false Disabled ..\..\vm;..\include\sqlite;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ..\include\sqlite\sqlite3.lib;..\..\bin\neko.lib;%(AdditionalDependencies) ../../bin/sqlite.ndll LIBCMT;%(IgnoreSpecificDefaultLibraries) true $(OutDir)sqlite.pdb Windows $(OutDir)sqlite.lib MachineX86 ..\..\vm;..\include\sqlite;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) MultiThreaded false Level3 ProgramDatabase ..\include\sqlite\sqlite3.lib;..\..\bin\neko.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/sqlite.ndll %(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)sqlite.lib MachineX86 ..\..\vm;..\include\sqlite;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ..\include\sqlite\sqlite3.lib;..\..\bin\neko.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/sqlite.ndll LIBCMT;%(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)sqlite.lib MachineX86 neko-2.0.0/libs/common/0000755000175000017500000000000012112157473015375 5ustar ncannassencannasseneko-2.0.0/libs/common/osdef.h0000644000175000017500000000413212112157473016646 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef OS_H #define OS_H #if defined(_WIN32) # define OS_WINDOWS #endif #if defined(__APPLE__) || defined(__MACH__) || defined(macintosh) # define OS_MAC #endif #if defined(linux) || defined(__linux__) # define OS_LINUX #endif #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) # define OS_BSD #endif #if defined(NEKO_LINUX) || defined(NEKO_MAC) || defined(NEKO_BSD) || defined(NEKO_GNUKBSD) # define OS_POSIX #endif #if defined(OS_WINDOWS) # define LITTLE_ENDIAN 1 # define BIG_ENDIAN 2 # define BYTE_ORDER LITTLE_ENDIAN #elif defined(OS_MAC) || defined(OS_BSD) # include #else # include #endif #ifndef BYTE_ORDER # warning BYTE_ORDER unknown, assuming BIG_ENDIAN # define BYTE_ORDER BIG_ENDIAN #endif #if BYTE_ORDER == BIG_ENDIAN # define IS_BIG_ENDIAN #else # define IS_LITTLE_ENDIAN #endif #ifndef true # define true 1 # define false 0 typedef int bool; #endif #endif /* ************************************************************************ */ neko-2.0.0/libs/common/socket.c0000644000175000017500000001211412112157473017030 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "socket.h" #include #ifdef OS_WINDOWS static int init_done = 0; static WSADATA init_data; # define POSIX_LABEL(x) # define HANDLE_EINTR(x) #else # include # include # include # include # include # include # include # include # include # include # include # include # define closesocket close # define SOCKET_ERROR (-1) # define POSIX_LABEL(x) x: # define HANDLE_EINTR(x) if( errno == EINTR ) goto x #endif #if defined(OS_WINDOWS) || defined(OS_MAC) # define MSG_NOSIGNAL 0 #endif static int block_error() { #ifdef OS_WINDOWS int err = WSAGetLastError(); if( err == WSAEWOULDBLOCK || err == WSAEALREADY ) #else if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY ) #endif return PS_BLOCK; return PS_ERROR; } void psock_init() { #ifdef OS_WINDOWS if( !init_done ) { WSAStartup(MAKEWORD(2,0),&init_data); init_done = 1; } #endif } PSOCK psock_create() { PSOCK s = socket(AF_INET,SOCK_STREAM,0); # if defined(OS_MAC) || defined(OS_BSD) if( s != INVALID_SOCKET ) setsockopt(s,SOL_SOCKET,SO_NOSIGPIPE,NULL,0); # endif # ifdef OS_POSIX // we don't want sockets to be inherited in case of exec { int old = fcntl(s,F_GETFD,0); if( old >= 0 ) fcntl(s,F_SETFD,old|FD_CLOEXEC); } # endif return s; } void psock_close( PSOCK s ) { POSIX_LABEL(close_again); if( closesocket(s) ) { HANDLE_EINTR(close_again); } } int psock_send( PSOCK s, const char *buf, int size ) { int ret; POSIX_LABEL(send_again); ret = send(s,buf,size,MSG_NOSIGNAL); if( ret == SOCKET_ERROR ) { HANDLE_EINTR(send_again); return block_error(); } return ret; } int psock_recv( PSOCK s, char *buf, int size ) { int ret; POSIX_LABEL(recv_again); ret = recv(s,buf,size,MSG_NOSIGNAL); if( ret == SOCKET_ERROR ) { HANDLE_EINTR(recv_again); return block_error(); } return ret; } PHOST phost_resolve( const char *host ) { PHOST ip = inet_addr(host); if( ip == INADDR_NONE ) { struct hostent *h; # if defined(OS_WINDOWS) || defined(OS_MAC) h = gethostbyname(host); # else struct hostent hbase; char buf[1024]; int errcode; gethostbyname_r(host,&hbase,buf,1024,&h,&errcode); # endif if( h == NULL ) return UNRESOLVED_HOST; ip = *((unsigned int*)h->h_addr); } return ip; } SERR psock_connect( PSOCK s, PHOST host, int port ) { struct sockaddr_in addr; memset(&addr,0,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); *(int*)&addr.sin_addr.s_addr = host; if( connect(s,(struct sockaddr*)&addr,sizeof(addr)) != 0 ) return block_error(); return PS_OK; } SERR psock_set_timeout( PSOCK s, double t ) { #ifdef OS_WINDOWS int time = (int)(t * 1000); #else struct timeval time; time.tv_usec = (int)((t - (int)t)*1000000); time.tv_sec = (int)t; #endif if( setsockopt(s,SOL_SOCKET,SO_SNDTIMEO,(char*)&time,sizeof(time)) != 0 ) return PS_ERROR; if( setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char*)&time,sizeof(time)) != 0 ) return PS_ERROR; return PS_OK; } SERR psock_set_blocking( PSOCK s, int block ) { #ifdef OS_WINDOWS { unsigned long arg = !block; if( ioctlsocket(s,FIONBIO,&arg) != 0 ) return PS_ERROR; } #else { int rights = fcntl(s,F_GETFL); if( rights == -1 ) return PS_ERROR; if( block ) rights &= ~O_NONBLOCK; else rights |= O_NONBLOCK; if( fcntl(s,F_SETFL,rights) == -1 ) return PS_ERROR; } #endif return PS_OK; } SERR psock_set_fastsend( PSOCK s, int fast ) { if( setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char*)&fast,sizeof(fast)) ) return block_error(); return PS_OK; } void psock_wait( PSOCK s ) { # ifdef OS_WINDOWS fd_set set; FD_ZERO(&set); FD_SET(s,&set); select((int)s+1,&set,NULL,NULL,NULL); # else struct pollfd fds; POSIX_LABEL(poll_again); fds.fd = s; fds.events = POLLIN; fds.revents = 0; if( poll(&fds,1,-1) < 0 ) { HANDLE_EINTR(poll_again); } # endif } /* ************************************************************************ */ neko-2.0.0/libs/common/sha1.h0000644000175000017500000000305112112157473016401 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef SHA1_H #define SHA1_H #define SHA1_SIZE 20 typedef unsigned char SHA1_DIGEST[SHA1_SIZE]; typedef struct { unsigned int state[5]; unsigned int count[2]; unsigned char buffer[64]; } SHA1_CTX; void sha1_init( SHA1_CTX *c ); void sha1_update( SHA1_CTX *c, const unsigned char *data, unsigned int len ); void sha1_final( SHA1_CTX *c, SHA1_DIGEST digest ); #endif /* ************************************************************************ */ neko-2.0.0/libs/common/sha1.c0000644000175000017500000001250212112157473016375 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "osdef.h" #include "sha1.h" #include #include // original code by Steve Reid #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) #ifdef IS_BIG_ENDIAN # define blk0(i) block[i] #else # define blk0(i) (block[i] = (rol(block[i],24)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #endif #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); static void sha1_transform( unsigned int state[5], unsigned char buffer[64] ) { unsigned int a, b, c, d, e; unsigned int block[16]; memcpy(block, buffer, 64); /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; } void sha1_init( SHA1_CTX *context ) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } void sha1_update( SHA1_CTX *context, const unsigned char *data, unsigned int len ) { unsigned int i, j; j = (context->count[0] >> 3) & 63; if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; context->count[1] += (len >> 29); if ((j + len) > 63) { memcpy(&context->buffer[j], data, (i = 64-j)); sha1_transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64 ) sha1_transform(context->state, (unsigned char *)&data[i]); j = 0; } else i = 0; memcpy(&context->buffer[j], &data[i], len - i); } void sha1_final( SHA1_CTX *context, unsigned char digest[SHA1_SIZE] ) { unsigned int i; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } sha1_update(context, (unsigned char *)"\200", 1); while ((context->count[0] & 504) != 448) { sha1_update(context, (unsigned char *)"\0", 1); } sha1_update(context, finalcount, 8); for (i = 0; i < SHA1_SIZE; i++) { digest[i] = (unsigned char) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } sha1_transform(context->state, context->buffer); } neko-2.0.0/libs/common/socket.h0000644000175000017500000000362412112157473017043 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef SOCKET_H #define SOCKET_H #include "osdef.h" #ifdef OS_WINDOWS # include typedef SOCKET PSOCK; #else typedef int PSOCK; # define INVALID_SOCKET (-1) #endif typedef unsigned int PHOST; #define UNRESOLVED_HOST ((PHOST)-1) typedef enum { PS_OK = 0, PS_ERROR = -1, PS_BLOCK = -2, } SERR; void psock_init(); PSOCK psock_create(); void psock_close( PSOCK s ); SERR psock_connect( PSOCK s, PHOST h, int port ); SERR psock_set_timeout( PSOCK s, double timeout ); SERR psock_set_blocking( PSOCK s, int block ); SERR psock_set_fastsend( PSOCK s, int fast ); int psock_send( PSOCK s, const char *buf, int size ); int psock_recv( PSOCK s, char *buf, int size ); PHOST phost_resolve( const char *hostname ); #endif /* ************************************************************************ */ neko-2.0.0/libs/regexp/0000755000175000017500000000000012112157473015377 5ustar ncannassencannasseneko-2.0.0/libs/regexp/regexp.vcxproj0000644000175000017500000002207612112157473020315 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ true Release\ Release\ false Release\ Release\ false Disabled ../include/pcre;../../vm;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;REGEXP_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ../../bin/neko.lib;%(AdditionalDependencies) ../../bin/regexp.ndll true $(OutDir)regexp.pdb Windows $(OutDir)regexp.lib MachineX86 ../include/pcre;../../vm;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;REGEXP_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../../bin/neko.lib;%(AdditionalDependencies) ../../bin/regexp.ndll %(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)regexp.lib MachineX86 ../include/pcre;../../vm;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;REGEXP_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../../bin/neko.lib;../include/msvcrt/extra.lib;%(AdditionalDependencies) ../../bin/regexp.ndll MSVCRT;%(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)regexp.lib MachineX86 neko-2.0.0/libs/regexp/regexp.c0000644000175000017500000001733612112157473017047 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #define PCRE_STATIC #include #define PCRE(o) ((pcredata*)val_data(o)) typedef struct { value str; pcre *r; int nmatchs; int *matchs; } pcredata; DEFINE_KIND(k_regexp); static field id_pos; static field id_len; static pcre_extra limit; /**

Regexp

Regular expressions using PCRE engine.

**/ static void free_regexp( value p ) { pcre_free( PCRE(p)->r ); } static int do_exec( pcredata *d, const char *str, int len, int pos ) { int res = pcre_exec(d->r,&limit,str,len,pos,0,d->matchs,d->nmatchs * 3); if( res >= 0 ) return 1; if( res != PCRE_ERROR_NOMATCH ) val_throw(alloc_string("An error occured while running pcre_exec")); return 0; } /** regexp_new_options : reg:string -> options:string -> 'regexp Build a new regexpr with the following options :
  • i : case insensitive matching
  • s : . match anything including newlines
  • m : treat the input as a multiline string
  • u : run in utf8 mode
  • g : turn off greedy behavior
**/ static value regexp_new_options( value s, value opt ) { val_check(s,string); val_check(opt,string); { value v; const char *error; int err_offset; pcre *p; pcredata *pdata; char *o = val_string(opt); int options = 0; while( *o ) { switch( *o++ ) { case 'i': options |= PCRE_CASELESS; break; case 's': options |= PCRE_DOTALL; break; case 'm': options |= PCRE_MULTILINE; break; case 'u': options |= PCRE_UTF8; break; case 'g': options |= PCRE_UNGREEDY; break; default: neko_error(); break; } } p = pcre_compile(val_string(s),options,&error,&err_offset,NULL); if( p == NULL ) { buffer b = alloc_buffer("Regexp compilation error : "); buffer_append(b,error); buffer_append(b," in "); val_buffer(b,s); bfailure(b); } v = alloc_abstract(k_regexp,alloc(sizeof(pcredata))); pdata = PCRE(v); pdata->r = p; pdata->str = val_null; pdata->nmatchs = 0; pcre_fullinfo(p,NULL,PCRE_INFO_CAPTURECOUNT,&pdata->nmatchs); pdata->nmatchs++; pdata->matchs = (int*)alloc_private(sizeof(int) * 3 * pdata->nmatchs); val_gc(v,free_regexp); return v; } } /** regexp_new : string -> 'regexp Build a new regexp **/ static value regexp_new( value s ) { return regexp_new_options(s,alloc_string("")); } /** regexp_match : 'regexp -> string -> pos:int -> len:int -> bool Match [len] chars of a string starting at [pos] using the regexp. Return true if match found **/ static value regexp_match( value o, value s, value p, value len ) { pcredata *d; int pp,ll; val_check_kind(o,k_regexp); val_check(s,string); val_check(p,int); val_check(len,int); pp = val_int(p); ll = val_int(len); if( pp < 0 || ll < 0 || pp > val_strlen(s) || pp + ll > val_strlen(s) ) neko_error(); d = PCRE(o); if( do_exec(d,val_string(s),ll+pp,pp) ) { d->str = s; return val_true; } else { d->str = val_null; return val_false; } } static value do_replace( value o, value s, value s2, bool all ) { val_check_kind(o,k_regexp); val_check(s,string); val_check(s2,string); { pcredata *d = PCRE(o); buffer b = alloc_buffer(NULL); int pos = 0; int len = val_strlen(s); const char *str = val_string(s); const char *str2 = val_string(s2); int len2 = val_strlen(s2); while( do_exec(d,str,len,pos) ) { buffer_append_sub(b,str+pos,d->matchs[0] - pos); buffer_append_sub(b,str2,len2); pos = d->matchs[1]; if( !all ) break; } d->str = val_null; buffer_append_sub(b,str+pos,len-pos); return buffer_to_string(b); } } /** regexp_replace : 'regexp -> from:string -> by:string -> string Perform a replacement using a regexp **/ static value regexp_replace( value o, value s, value s2 ) { return do_replace(o,s,s2,false); } /** regexp_replace_all : 'regexp -> from:string -> by:string -> string Perform a replacement of all matched substrings using a regexp **/ static value regexp_replace_all( value o, value s, value s2 ) { return do_replace(o,s,s2,true); } /** regexp_replace_fun : 'regexp -> from:string -> f:('regexp -> any) -> string Perform a replacement of all matched substrings by calling [f] for every match **/ static value regexp_replace_fun( value o, value s, value f ) { val_check_kind(o,k_regexp); val_check(s,string); val_check_function(f,1); { pcredata *d = PCRE(o); buffer b = alloc_buffer(NULL); int pos = 0; int len = val_strlen(s); const char *str = val_string(s); d->str = s; while( do_exec(d,str,len,pos) ) { buffer_append_sub(b,str+pos,d->matchs[0] - pos); val_buffer(b,val_call1(f,o)); pos = d->matchs[1]; } d->str = val_null; buffer_append_sub(b,str+pos,len-pos); return buffer_to_string(b); } } /** regexp_matched : 'regexp -> n:int -> string? Return the [n]th matched block by the regexp. If [n] is 0 then return the whole matched substring. If the [n]th matched block was optional and not matched, returns null **/ static value regexp_matched( value o, value n ) { pcredata *d; int m; val_check_kind(o,k_regexp); d = PCRE(o); val_check(n,int); m = val_int(n); if( m < 0 || m >= d->nmatchs || val_is_null(d->str) ) neko_error(); { int start = d->matchs[m*2]; int len = d->matchs[m*2+1] - start; value str; if( start == -1 ) return val_null; str = alloc_empty_string(len); memcpy((char*)val_string(str),val_string(d->str)+start,len); return str; } } /** regexp_matched_pos : 'regexp -> n:int -> { pos => int, len => int } Return the [n]th matched block position by the regexp. If [n] is 0 then return the whole matched substring position **/ static value regexp_matched_pos( value o, value n ) { pcredata *d; int m; val_check_kind(o,k_regexp); d = PCRE(o); val_check(n,int); m = val_int(n); if( m < 0 || m >= d->nmatchs || val_is_null(d->str) ) neko_error(); { int start = d->matchs[m*2]; int len = d->matchs[m*2+1] - start; value o = alloc_object(NULL); alloc_field(o,id_pos,alloc_int(start)); alloc_field(o,id_len,alloc_int(len)); return o; } } void regexp_main() { id_pos = val_id("pos"); id_len = val_id("len"); limit.flags = PCRE_EXTRA_MATCH_LIMIT_RECURSION; limit.match_limit_recursion = 3500; // adapted based on Windows 1MB stack size } DEFINE_PRIM(regexp_new,1); DEFINE_PRIM(regexp_new_options,2); DEFINE_PRIM(regexp_match,4); DEFINE_PRIM(regexp_replace,3); DEFINE_PRIM(regexp_replace_all,3); DEFINE_PRIM(regexp_replace_fun,3); DEFINE_PRIM(regexp_matched,2); DEFINE_PRIM(regexp_matched_pos,2); DEFINE_ENTRY_POINT(regexp_main); /* ************************************************************************ */ neko-2.0.0/libs/regexp/regexp.vcproj0000644000175000017500000001527012112157473020123 0ustar ncannassencannasse neko-2.0.0/libs/zlib/0000755000175000017500000000000012112157473015045 5ustar ncannassencannasseneko-2.0.0/libs/zlib/zlib.vcproj0000644000175000017500000001136012112157473017233 0ustar ncannassencannasse neko-2.0.0/libs/zlib/zlib.c0000644000175000017500000002056712112157473016163 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include /**

ZLib

Give access to the popular ZLib compression library, used in several file formats such as ZIP and PNG.

**/ DEFINE_KIND(k_stream_def); DEFINE_KIND(k_stream_inf); #define val_stream(v) ((z_stream *)val_data(v)) #define val_flush(s) *((int*)(((char*)s)+sizeof(z_stream))) static field id_read, id_write, id_done; DEFINE_ENTRY_POINT(zlib_main); void zlib_main() { id_read = val_id("read"); id_write = val_id("write"); id_done = val_id("done"); } static void free_stream_def( value v ) { z_stream *s = val_stream(v); deflateEnd(s); // no error free(s); val_kind(v) = NULL; val_gc(v,NULL); } static void free_stream_inf( value v ) { z_stream *s = val_stream(v); inflateEnd(s); // no error free(s); val_kind(v) = NULL; val_gc(v,NULL); } static void zlib_error( z_stream *z, int err ) { buffer b = alloc_buffer("ZLib Error : "); if( z && z->msg ) { buffer_append(b,z->msg); buffer_append(b," ("); } val_buffer(b,alloc_int(err)); if( z && z->msg ) buffer_append_char(b,')'); val_throw(buffer_to_string(b)); } /** deflate_init : level:int -> 'dstream Open a compression stream with the given level of compression **/ static value deflate_init( value level ) { z_stream *z; value s; int err; val_check(level,int); z = (z_stream*)malloc(sizeof(z_stream) + sizeof(int)); memset(z,0,sizeof(z_stream)); val_flush(z) = Z_NO_FLUSH; if( (err = deflateInit(z,val_int(level))) != Z_OK ) { free(z); zlib_error(NULL,err); } s = alloc_abstract(k_stream_def,z); val_gc(s,free_stream_def); return s; } /** deflate_buffer : 'dstream -> src:string -> srcpos:int -> dst:string -> dstpos:int -> { done => bool, read => int, write => int } **/ static value deflate_buffer( value s, value src, value srcpos, value dst, value dstpos ) { z_stream *z; int slen, dlen, err; value o; val_check_kind(s,k_stream_def); val_check(src,string); val_check(srcpos,int); val_check(dst,string); val_check(dstpos,int); z = val_stream(s); if( val_int(srcpos) < 0 || val_int(dstpos) < 0 ) neko_error(); slen = val_strlen(src) - val_int(srcpos); dlen = val_strlen(dst) - val_int(dstpos); if( slen < 0 || dlen < 0 ) neko_error(); z->next_in = (Bytef*)(val_string(src) + val_int(srcpos)); z->next_out = (Bytef*)(val_string(dst) + val_int(dstpos)); z->avail_in = slen; z->avail_out = dlen; if( (err = deflate(z,val_flush(z))) < 0 ) zlib_error(z,err); z->next_in = NULL; z->next_out = NULL; o = alloc_object(NULL); alloc_field(o,id_done,alloc_bool(err == Z_STREAM_END)); alloc_field(o,id_read,alloc_int(slen - z->avail_in)); alloc_field(o,id_write,alloc_int(dlen - z->avail_out)); return o; } /** deflate_end : 'dstream -> void Close a compression stream **/ static value deflate_end( value s ) { val_check_kind(s,k_stream_def); free_stream_def(s); return val_null; } /** inflate_init : window_size:int? -> 'istream Open a decompression stream **/ static value inflate_init( value wsize ) { z_stream *z; value s; int err; int wbits; if( val_is_null(wsize) ) wbits = MAX_WBITS; else { val_check(wsize,int); wbits = val_int(wsize); } z = (z_stream*)malloc(sizeof(z_stream) + sizeof(int)); memset(z,0,sizeof(z_stream)); val_flush(z) = Z_NO_FLUSH; if( (err = inflateInit2(z,wbits)) != Z_OK ) { free(z); zlib_error(NULL,err); } s = alloc_abstract(k_stream_inf,z); val_gc(s,free_stream_inf); return s; } /** inflate_buffer : 'istream -> src:string -> srcpos:int -> dst:string -> dstpos:int -> { done => bool, read => int, write => int } **/ static value inflate_buffer( value s, value src, value srcpos, value dst, value dstpos ) { z_stream *z; int slen, dlen, err; value o; val_check_kind(s,k_stream_inf); val_check(src,string); val_check(srcpos,int); val_check(dst,string); val_check(dstpos,int); z = val_stream(s); if( val_int(srcpos) < 0 || val_int(dstpos) < 0 ) neko_error(); slen = val_strlen(src) - val_int(srcpos); dlen = val_strlen(dst) - val_int(dstpos); if( slen < 0 || dlen < 0 ) neko_error(); z->next_in = (Bytef*)(val_string(src) + val_int(srcpos)); z->next_out = (Bytef*)(val_string(dst) + val_int(dstpos)); z->avail_in = slen; z->avail_out = dlen; if( (err = inflate(z,val_flush(z))) < 0 ) zlib_error(z,err); z->next_in = NULL; z->next_out = NULL; o = alloc_object(NULL); alloc_field(o,id_done,alloc_bool(err == Z_STREAM_END)); alloc_field(o,id_read,alloc_int(slen - z->avail_in)); alloc_field(o,id_write,alloc_int(dlen - z->avail_out)); return o; } /** inflate_end : 'istream -> void Close a decompression stream **/ static value inflate_end( value s ) { val_check_kind(s,k_stream_inf); free_stream_inf(s); return val_null; } /** set_flush_mode : 'stream -> string -> void Change the flush mode ("NO","SYNC","FULL","FINISH","BLOCK") **/ static value set_flush_mode( value s, value flush ) { int f; if( !val_is_kind(s,k_stream_inf) ) val_check_kind(s,k_stream_def); val_check(flush,string); if( strcmp(val_string(flush),"NO") == 0 ) f = Z_NO_FLUSH; else if( strcmp(val_string(flush),"SYNC") == 0 ) f = Z_SYNC_FLUSH; else if( strcmp(val_string(flush),"FULL") == 0 ) f = Z_FULL_FLUSH; else if( strcmp(val_string(flush),"FINISH") == 0 ) f = Z_FINISH; else if( strcmp(val_string(flush),"BLOCK") == 0 ) f = Z_BLOCK; else neko_error(); val_flush(val_stream(s)) = f; return val_null; } /** get_adler32 : 'stream -> 'int32 Returns the adler32 value of the stream **/ static value get_adler32( value s ) { if( !val_is_kind(s,k_stream_inf) ) val_check_kind(s,k_stream_def); return alloc_int32(val_stream(s)->adler); } /** update_adler32 : adler:'int32 -> string -> pos:int -> len:int -> 'int32 Update an adler32 value with a substring **/ static value update_adler32( value adler, value s, value pos, value len ) { val_check(adler,int32); val_check(s,string); val_check(pos,int); val_check(len,int); if( val_int(pos) < 0 || val_int(len) < 0 || val_int(pos) + val_int(len) > val_strlen(s) ) neko_error(); return alloc_int32(adler32(val_int32(adler),(Bytef*)(val_string(s)+val_int(pos)),val_int(len))); } /** update_crc32 : crc:'int32 -> string -> pos:int -> len:int -> 'int32 Update a CRC32 value with a substring **/ static value update_crc32( value crc, value s, value pos, value len ) { val_check(crc,int32); val_check(s,string); val_check(pos,int); val_check(len,int); if( val_int(pos) < 0 || val_int(len) < 0 || val_int(pos) + val_int(len) > val_strlen(s) ) neko_error(); return alloc_int32(crc32(val_int32(crc),(Bytef*)(val_string(s)+val_int(pos)),val_int(len))); } /** deflate_bound : 'dstream -> n:int -> int Return the maximum buffer size needed to write [n] bytes **/ static value deflate_bound( value s, value size ) { val_check_kind(s,k_stream_def); val_check(size,int); return alloc_int(deflateBound(val_stream(s),val_int(size))); } DEFINE_PRIM(deflate_init,1); DEFINE_PRIM(deflate_buffer,5); DEFINE_PRIM(deflate_end,1); DEFINE_PRIM(inflate_init,1); DEFINE_PRIM(inflate_buffer,5); DEFINE_PRIM(inflate_end,1); DEFINE_PRIM(set_flush_mode,2); DEFINE_PRIM(deflate_bound,2); DEFINE_PRIM(get_adler32,1); DEFINE_PRIM(update_adler32,4); DEFINE_PRIM(update_crc32,4); /* ************************************************************************ */ neko-2.0.0/libs/zlib/zlib.vcxproj0000644000175000017500000001727612112157473017437 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ true Release\ Release\ false Release\ Release\ false Disabled ../include/zlib;../../vm;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;ZLIB_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ../../bin/neko.lib;../include/zlib/zlib.lib;%(AdditionalDependencies) ../../bin/zlib.ndll MSVCRT;%(IgnoreSpecificDefaultLibraries) true $(OutDir)zlib.pdb Windows $(OutDir)zlib.lib MachineX86 ../include/zlib;../../vm;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;ZLIB_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../../bin/neko.lib;../include/zlib/zlib.lib;%(AdditionalDependencies) ../../bin/zlib.ndll %(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)zlib.lib MachineX86 ../include/zlib;../../vm;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;ZLIB_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../../bin/neko.lib;../include/zlib/zlib.lib;../include/msvcrt/extra.lib;%(AdditionalDependencies) ../../bin/zlib.ndll MSVCRT;%(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)zlib.lib MachineX86 neko-2.0.0/libs/mysql/0000755000175000017500000000000012112157473015252 5ustar ncannassencannasseneko-2.0.0/libs/mysql/mysql.vcproj0000644000175000017500000001151012112157473017642 0ustar ncannassencannasse neko-2.0.0/libs/mysql/mysql.vcxproj0000644000175000017500000001741112112157473020040 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {159607BD-674F-44DA-9290-CF923B2703CC} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ true Release\ Release\ false Release\ Release\ false Disabled ..\..\vm;..\include\mysql;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ..\include\mysql\mysqlclient.lib;ws2_32.lib;..\..\bin\neko.lib;%(AdditionalDependencies) ../../bin/mysql.ndll LIBCMT;%(IgnoreSpecificDefaultLibraries) true $(OutDir)mysql.pdb Windows $(OutDir)mysql.lib MachineX86 ..\..\vm;..\include\mysql;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions) MultiThreaded false Level3 ProgramDatabase ..\include\mysql\mysqlclient.lib;..\..\bin\neko.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/mysql.ndll %(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)mysql.lib MachineX86 ..\..\vm;..\include\mysql;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ..\include\mysql\mysqlclient.lib;..\..\bin\neko.lib;ws2_32.lib;../include/msvcrt/extra.lib;%(AdditionalDependencies) ../../bin/mysql.ndll MSVCRT;LIBCMT;%(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)mysql.lib MachineX86 neko-2.0.0/libs/mysql/mysql5.vcproj0000644000175000017500000001241512112157473017734 0ustar ncannassencannasse neko-2.0.0/libs/mysql/mysql5.vcxproj0000644000175000017500000001776712112157473020143 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {DB4D82FF-EE9A-4456-9163-48CCC64FEB09} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug5\ Debug5\ true Release5\ Release5\ false Release\ Release\ false Disabled ..\..\vm;my_proto;..\common;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug Level3 EditAndContinue ..\..\bin\neko.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/mysql5.ndll LIBCMT;%(IgnoreSpecificDefaultLibraries) true $(OutDir)mysql5.pdb Windows $(OutDir)mysql5.lib MachineX86 ..\..\vm;my_proto;..\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ..\..\bin\neko.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/mysql5.ndll %(IgnoreSpecificDefaultLibraries) Windows true true $(OutDir)mysql5.lib MachineX86 ..\..\vm;my_proto;..\common;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ..\..\bin\neko.lib;ws2_32.lib;../include/msvcrt/extra.lib;%(AdditionalDependencies) ../../bin/mysql5.ndll MSVCRT;%(IgnoreSpecificDefaultLibraries) Windows true true $(OutDir)mysql5.lib MachineX86 neko-2.0.0/libs/mysql/my_proto/0000755000175000017500000000000012112157473017122 5ustar ncannassencannasseneko-2.0.0/libs/mysql/my_proto/my_api.c0000644000175000017500000003217012112157473020547 0ustar ncannassencannasse/* ************************************************************************ */ /* */ /* MYSQL 5.0 Protocol Implementation */ /* Copyright (c)2008 Nicolas Cannasse */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /* ************************************************************************ */ #include #include #include #include "my_proto.h" static void error( MYSQL *m, const char *err, const char *param ) { if( param ) { unsigned int max = MAX_ERR_SIZE - (strlen(err) + 3); if( strlen(param) > max ) { char *p2 = (char*)malloc(max + 1); memcpy(p2,param,max-3); p2[max - 3] = '.'; p2[max - 2] = '.'; p2[max - 1] = '.'; p2[max] = 0; sprintf(m->last_error,err,param); free(p2); return; } } sprintf(m->last_error,err,param); m->errcode = -1; } static void save_error( MYSQL *m, MYSQL_PACKET *p ) { int ecode; p->pos = 0; // seems like we sometimes get some FFFFFF sequences before // the actual error... do { if( myp_read_byte(p) != 0xFF ) { m->errcode = -1; error(m,"Failed to decode error",NULL); return; } ecode = myp_read_ui16(p); } while( ecode == 0xFFFF ); if( m->is41 && p->buf[p->pos] == '#' ) p->pos += 6; // skip sqlstate marker error(m,"%s",myp_read_string(p)); m->errcode = ecode; } static int myp_ok( MYSQL *m, int allow_others ) { int code; MYSQL_PACKET *p = &m->packet; if( !myp_read_packet(m,p) ) { error(m,"Failed to read packet",NULL); return 0; } code = myp_read_byte(p); if( code == 0x00 ) return 1; if( code == 0xFF ) save_error(m,p); else if( allow_others ) return 1; else error(m,"Invalid packet error",NULL); return 0; } static void myp_close( MYSQL *m ) { psock_close(m->s); m->s = INVALID_SOCKET; } MYSQL *mysql_init( void *unused ) { MYSQL *m = (MYSQL*)malloc(sizeof(struct _MYSQL)); psock_init(); memset(m,0,sizeof(struct _MYSQL)); m->s = INVALID_SOCKET; error(m,"NO ERROR",NULL); m->errcode = 0; m->last_field_count = -1; m->last_insert_id = -1; m->affected_rows = -1; return m; } MYSQL *mysql_real_connect( MYSQL *m, const char *host, const char *user, const char *pass, void *unused, int port, const char *socket, int options ) { PHOST h; char scramble_buf[21]; MYSQL_PACKET *p = &m->packet; int pcount = 1; if( socket && *socket ) { error(m,"Unix Socket connections are not supported",NULL); return NULL; } h = phost_resolve(host); if( h == UNRESOLVED_HOST ) { error(m,"Failed to resolve host '%s'",host); return NULL; } m->s = psock_create(); if( m->s == INVALID_SOCKET ) { error(m,"Failed to create socket",NULL); return NULL; } psock_set_fastsend(m->s,1); psock_set_timeout(m->s,50); // 50 seconds if( psock_connect(m->s,h,port) != PS_OK ) { myp_close(m); error(m,"Failed to connect on host '%s'",host); return NULL; } if( !myp_read_packet(m,p) ) { myp_close(m); error(m,"Failed to read handshake packet",NULL); return NULL; } // process handshake packet { char filler[13]; unsigned int len; m->infos.proto_version = myp_read_byte(p); // this seems like an error packet if( m->infos.proto_version == 0xFF ) { myp_close(m); save_error(m,p); return NULL; } m->infos.server_version = strdup(myp_read_string(p)); m->infos.thread_id = myp_read_int(p); myp_read(p,scramble_buf,8); myp_read_byte(p); // should be 0 m->infos.server_flags = myp_read_ui16(p); m->infos.server_charset = myp_read_byte(p); m->infos.server_status = myp_read_ui16(p); m->infos.server_flags |= myp_read_ui16(p) << 16; len = myp_read_byte(p); myp_read(p,filler,10); // try to disable 41 m->is41 = (m->infos.server_flags & FL_PROTOCOL_41) != 0; if( !p->error && m->is41 ) myp_read(p,scramble_buf + 8,13); if( p->pos != p->size ) myp_read_string(p); // 5.5+ if( p->error ) { myp_close(m); error(m,"Failed to decode server handshake",NULL); return NULL; } // fill answer packet { unsigned int flags = m->infos.server_flags; int max_packet_size = 0x01000000; SHA1_DIGEST hpass; char filler[23]; flags &= (FL_PROTOCOL_41 | FL_TRANSACTIONS | FL_SECURE_CONNECTION); myp_begin_packet(p,128); if( m->is41 ) { myp_write_int(p,flags); myp_write_int(p,max_packet_size); myp_write_byte(p,m->infos.server_charset); memset(filler,0,23); myp_write(p,filler,23); myp_write_string(p,user); if( *pass ) { myp_encrypt_password(pass,scramble_buf,hpass); myp_write_bin(p,SHA1_SIZE); myp_write(p,hpass,SHA1_SIZE); myp_write_byte(p,0); } else myp_write_bin(p,0); } else { myp_write_ui16(p,flags); // max_packet_size myp_write_byte(p,0xFF); myp_write_byte(p,0xFF); myp_write_byte(p,0xFF); myp_write_string(p,user); if( *pass ) { char hpass[SEED_LENGTH_323 + 1]; myp_encrypt_pass_323(pass,scramble_buf,hpass); hpass[SEED_LENGTH_323] = 0; myp_write(p,hpass,SEED_LENGTH_323 + 1); } else myp_write_bin(p,0); } } } // send connection packet send_cnx_packet: if( !myp_send_packet(m,p,&pcount) ) { myp_close(m); error(m,"Failed to send connection packet",NULL); return NULL; } // read answer packet if( !myp_read_packet(m,p) ) { myp_close(m); error(m,"Failed to read packet",NULL); return NULL; } // increase packet counter (because we read one packet) pcount++; // process answer { int code = myp_read_byte(p); switch( code ) { case 0: // OK packet break; case 0xFF: // ERROR myp_close(m); save_error(m,p); return NULL; case 0xFE: // EOF // we are asked to send old password authentification if( p->size == 1 ) { char hpass[SEED_LENGTH_323 + 1]; myp_encrypt_pass_323(pass,scramble_buf,hpass); hpass[SEED_LENGTH_323] = 0; myp_begin_packet(p,0); myp_write(p,hpass,SEED_LENGTH_323 + 1); goto send_cnx_packet; } // fallthrough default: myp_close(m); error(m,"Invalid packet error",NULL); return NULL; } } // we are connected, setup a longer timeout psock_set_timeout(m->s,18000); return m; } int mysql_select_db( MYSQL *m, const char *dbname ) { MYSQL_PACKET *p = &m->packet; int pcount = 0; myp_begin_packet(p,0); myp_write_byte(p,COM_INIT_DB); myp_write_string(p,dbname); if( !myp_send_packet(m,p,&pcount) ) { error(m,"Failed to send packet",NULL); return -1; } return myp_ok(m,0) ? 0 : -1; } int mysql_real_query( MYSQL *m, const char *query, int qlength ) { MYSQL_PACKET *p = &m->packet; int pcount = 0; myp_begin_packet(p,0); myp_write_byte(p,COM_QUERY); myp_write(p,query,qlength); m->last_field_count = -1; m->affected_rows = -1; m->last_insert_id = -1; if( !myp_send_packet(m,p,&pcount) ) { error(m,"Failed to send packet",NULL); return -1; } if( !myp_ok(m,1) ) return -1; p->id = IS_QUERY; return 0; } static int do_store( MYSQL *m, MYSQL_RES *r ) { int i; MYSQL_PACKET *p = &m->packet; p->pos = 0; r->nfields = myp_read_bin(p); if( p->error ) return 0; r->fields = (MYSQL_FIELD*)malloc(sizeof(MYSQL_FIELD) * r->nfields); memset(r->fields,0,sizeof(MYSQL_FIELD) * r->nfields); for(i=0;infields;i++) { if( !myp_read_packet(m,p) ) return 0; { MYSQL_FIELD *f = r->fields + i; f->catalog = m->is41 ? myp_read_bin_str(p) : NULL; f->db = m->is41 ? myp_read_bin_str(p) : NULL; f->table = myp_read_bin_str(p); f->org_table = m->is41 ? myp_read_bin_str(p) : NULL; f->name = myp_read_bin_str(p); f->org_name = m->is41 ? myp_read_bin_str(p) : NULL; if( m->is41 ) myp_read_byte(p); f->charset = m->is41 ? myp_read_ui16(p) : 0x08; f->length = m->is41 ? myp_read_int(p) : myp_read_bin(p); f->type = m->is41 ? myp_read_byte(p) : myp_read_bin(p); f->flags = m->is41 ? myp_read_ui16(p) : myp_read_bin(p); f->decimals = myp_read_byte(p); if( m->is41 ) myp_read_byte(p); // should be 0 if( m->is41 ) myp_read_byte(p); // should be 0 if( p->error ) return 0; } } // first EOF packet if( !myp_read_packet(m,p) ) return 0; if( myp_read_byte(p) != 0xFE || p->size >= 9 ) return 0; // reset packet buffer (to prevent to store large buffer in row data) free(p->buf); p->buf = NULL; p->mem = 0; // datas while( 1 ) { if( !myp_read_packet(m,p) ) return 0; // EOF : end of datas if( (unsigned char)p->buf[0] == 0xFE && p->size < 9 ) break; // ERROR ? if( (unsigned char)p->buf[0] == 0xFF ) { save_error(m,p); return 0; } // allocate one more row if( r->row_count == r->memory_rows ) { MYSQL_ROW_DATA *rows; r->memory_rows = r->memory_rows ? (r->memory_rows << 1) : 1; rows = (MYSQL_ROW_DATA*)malloc(r->memory_rows * sizeof(MYSQL_ROW_DATA)); memcpy(rows,r->rows,r->row_count * sizeof(MYSQL_ROW_DATA)); free(r->rows); r->rows = rows; } // read row fields { MYSQL_ROW_DATA *current = r->rows + r->row_count++; int prev = 0; current->raw = p->buf; current->lengths = (unsigned long*)malloc(sizeof(unsigned long) * r->nfields); current->datas = (char**)malloc(sizeof(char*) * r->nfields); for(i=0;infields;i++) { int l = myp_read_bin(p); if( !p->error ) p->buf[prev] = 0; if( l == -1 ) { current->lengths[i] = 0; current->datas[i] = NULL; } else { current->lengths[i] = l; current->datas[i] = p->buf + p->pos; p->pos += l; } prev = p->pos; } if( !p->error ) p->buf[prev] = 0; } // the packet buffer as been stored, don't reuse it p->buf = NULL; p->mem = 0; if( p->error ) return 0; } return 1; } MYSQL_RES *mysql_store_result( MYSQL *m ) { MYSQL_RES *r; MYSQL_PACKET *p = &m->packet; if( p->id != IS_QUERY ) return NULL; // OK without result if( p->buf[0] == 0 ) { p->pos = 0; m->last_field_count = myp_read_byte(p); // 0 m->affected_rows = myp_read_bin(p); m->last_insert_id = myp_read_bin(p); return NULL; } r = (MYSQL_RES*)malloc(sizeof(struct _MYSQL_RES)); memset(r,0,sizeof(struct _MYSQL_RES)); m->errcode = 0; if( !do_store(m,r) ) { mysql_free_result(r); if( !m->errcode ) error(m,"Failure while storing result",NULL); return NULL; } m->last_field_count = r->nfields; return r; } int mysql_field_count( MYSQL *m ) { return m->last_field_count; } int mysql_affected_rows( MYSQL *m ) { return m->affected_rows; } int mysql_escape_string( MYSQL *m, char *sout, const char *sin, int length ) { return myp_escape_string(m->infos.server_charset,sout,sin,length); } const char *mysql_character_set_name( MYSQL *m ) { const char *name = myp_charset_name(m->infos.server_charset); if( name == NULL ) { static char tmp[512]; sprintf(tmp,"#%d",m->infos.server_charset); return tmp; } return name; } int mysql_real_escape_string( MYSQL *m, char *sout, const char *sin, int length ) { if( !myp_supported_charset(m->infos.server_charset) ) return -1; if( m->infos.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES ) return myp_escape_quotes(m->infos.server_charset,sout,sin,length); return myp_escape_string(m->infos.server_charset,sout,sin,length); } void mysql_close( MYSQL *m ) { myp_close(m); free(m->packet.buf); free(m->infos.server_version); free(m); } const char *mysql_error( MYSQL *m ) { return m->last_error; } // RESULTS API unsigned int mysql_num_rows( MYSQL_RES *r ) { return r->row_count; } int mysql_num_fields( MYSQL_RES *r ) { return r->nfields; } MYSQL_FIELD *mysql_fetch_fields( MYSQL_RES *r ) { return r->fields; } unsigned long *mysql_fetch_lengths( MYSQL_RES *r ) { return r->current ? r->current->lengths : NULL; } MYSQL_ROW mysql_fetch_row( MYSQL_RES * r ) { MYSQL_ROW_DATA *cur = r->current; if( cur == NULL ) cur = r->rows; else { // free the previous result, since we're done with it free(cur->datas); free(cur->lengths); free(cur->raw); cur->datas = NULL; cur->lengths = NULL; cur->raw = NULL; // next cur++; } if( cur >= r->rows + r->row_count ) { free(r->rows); r->rows = NULL; r->memory_rows = 0; cur = NULL; } r->current = cur; return cur ? cur->datas : NULL; } void mysql_free_result( MYSQL_RES *r ) { if( r->fields ) { int i; for(i=0;infields;i++) { MYSQL_FIELD *f = r->fields + i; free(f->catalog); free(f->db); free(f->table); free(f->org_table); free(f->name); free(f->org_name); } free(r->fields); } if( r->rows ) { int i; for(i=0;irow_count;i++) { MYSQL_ROW_DATA *row = r->rows + i; free(row->datas); free(row->lengths); free(row->raw); } free(r->rows); } free(r); } /* ************************************************************************ */ neko-2.0.0/libs/mysql/my_proto/my_proto.h0000644000175000017500000001206012112157473021142 0ustar ncannassencannasse/* ************************************************************************ */ /* */ /* MYSQL 5.0 Protocol Implementation */ /* Copyright (c)2008 Nicolas Cannasse */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /* ************************************************************************ */ #ifndef MY_PROTO_H #define MY_PROTO_H #include "mysql.h" #include "socket.h" #include "sha1.h" typedef enum { FL_LONG_PASSWORD = 1, FL_FOUND_ROWS = 2, FL_LONG_FLAG = 4, FL_CONNECT_WITH_DB = 8, FL_NO_SCHEMA = 16, FL_COMPRESS = 32, FL_ODBC = 64, FL_LOCAL_FILES = 128, FL_IGNORE_SPACE = 256, FL_PROTOCOL_41 = 512, FL_INTERACTIVE = 1024, FL_SSL = 2048, FL_IGNORE_SIGPIPE = 4096, FL_TRANSACTIONS = 8192, FL_RESERVED = 16384, FL_SECURE_CONNECTION = 32768, FL_MULTI_STATEMENTS = 65536, FL_MULTI_RESULTS = 131072, } MYSQL_FLAG; typedef enum { COM_SLEEP = 0x00, COM_QUIT = 0x01, COM_INIT_DB = 0x02, COM_QUERY = 0x03, COM_FIELD_LIST = 0x04, //COM_CREATE_DB = 0x05, //COM_DROP_DB = 0x06 COM_REFRESH = 0x07, COM_SHUTDOWN = 0x08, COM_STATISTICS = 0x09, COM_PROCESS_INFO = 0x0A, //COM_CONNECT = 0x0B, COM_PROCESS_KILL = 0x0C, COM_DEBUG = 0x0D, COM_PING = 0x0E, //COM_TIME = 0x0F, //COM_DELAYED_INSERT = 0x10, COM_CHANGE_USER = 0x11, COM_BINLOG_DUMP = 0x12, COM_TABLE_DUMP = 0x13, COM_CONNECT_OUT = 0x14, COM_REGISTER_SLAVE = 0x15, COM_STMT_PREPARE = 0x16, COM_STMT_EXECUTE = 0x17, COM_STMT_SEND_LONG_DATA = 0x18, COM_STMT_CLOSE = 0x19, COM_STMT_RESET = 0x1A, COM_SET_OPTION = 0x1B, COM_STMT_FETCH = 0x1C, } MYSQL_COMMAND; typedef enum { SERVER_STATUS_IN_TRANS = 1, SERVER_STATUS_AUTOCOMMIT = 2, SERVER_MORE_RESULTS_EXISTS = 8, SERVER_QUERY_NO_GOOD_INDEX_USED = 16, SERVER_QUERY_NO_INDEX_USED = 32, SERVER_STATUS_CURSOR_EXISTS = 64, SERVER_STATUS_LAST_ROW_SENT = 128, SERVER_STATUS_DB_DROPPED = 256, SERVER_STATUS_NO_BACKSLASH_ESCAPES = 512, } MYSQL_SERVER_STATUS; typedef struct { unsigned char proto_version; char *server_version; unsigned int thread_id; unsigned int server_flags; unsigned char server_charset; unsigned short server_status; } MYSQL_INFOS; typedef struct { int id; int error; int size; int pos; int mem; char *buf; } MYSQL_PACKET; #define MAX_ERR_SIZE 1024 #define IS_QUERY -123456 struct _MYSQL { PSOCK s; MYSQL_INFOS infos; MYSQL_PACKET packet; int is41; int errcode; int last_field_count; int affected_rows; int last_insert_id; char last_error[MAX_ERR_SIZE]; }; typedef struct { char *raw; unsigned long *lengths; char **datas; } MYSQL_ROW_DATA; struct _MYSQL_RES { int nfields; MYSQL_FIELD *fields; MYSQL_ROW_DATA *rows; MYSQL_ROW_DATA *current; int row_count; int memory_rows; }; // network int myp_recv( MYSQL *m, void *buf, int size ); int myp_send( MYSQL *m, void *buf, int size ); int myp_read_packet( MYSQL *m, MYSQL_PACKET *p ); int myp_send_packet( MYSQL *m, MYSQL_PACKET *p, int *packet_counter ); // packet read int myp_read( MYSQL_PACKET *p, void *buf, int size ); unsigned char myp_read_byte( MYSQL_PACKET *p ); unsigned short myp_read_ui16( MYSQL_PACKET *p ); int myp_read_int( MYSQL_PACKET *p ); const char *myp_read_string( MYSQL_PACKET *p ); int myp_read_bin( MYSQL_PACKET *p ); char *myp_read_bin_str( MYSQL_PACKET *p ); // packet write void myp_begin_packet( MYSQL_PACKET *p, int minsize ); void myp_write( MYSQL_PACKET *p, const void *data, int size ); void myp_write_byte( MYSQL_PACKET *p, int b ); void myp_write_ui16( MYSQL_PACKET *p, int b ); void myp_write_int( MYSQL_PACKET *p, int b ); void myp_write_string( MYSQL_PACKET *p, const char *str ); void myp_write_bin( MYSQL_PACKET *p, int size ); // passwords #define SEED_LENGTH_323 8 void myp_crypt( unsigned char *out, const unsigned char *s1, const unsigned char *s2, unsigned int len ); void myp_encrypt_password( const char *pass, const char *seed, SHA1_DIGEST out ); void myp_encrypt_pass_323( const char *pass, const char seed[SEED_LENGTH_323], char out[SEED_LENGTH_323] ); // escaping int myp_supported_charset( int charset ); const char *myp_charset_name( int charset ); int myp_escape_string( int charset, char *sout, const char *sin, int length ); int myp_escape_quotes( int charset, char *sout, const char *sin, int length ); #endif /* ************************************************************************ */ neko-2.0.0/libs/mysql/my_proto/mysql.h0000644000175000017500000001036012112157473020440 0ustar ncannassencannasse/* ************************************************************************ */ /* */ /* MYSQL 5.0 Protocol Implementation */ /* Copyright (c)2008 Nicolas Cannasse */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /* ************************************************************************ */ #ifndef MYSQL_H #define MYSQL_H struct _MYSQL; struct _MYSQL_RES; typedef struct _MYSQL MYSQL; typedef struct _MYSQL_RES MYSQL_RES; typedef char **MYSQL_ROW; typedef enum enum_field_types { FIELD_TYPE_DECIMAL = 0x00, FIELD_TYPE_TINY = 0x01, FIELD_TYPE_SHORT = 0x02, FIELD_TYPE_LONG = 0x03, FIELD_TYPE_FLOAT = 0x04, FIELD_TYPE_DOUBLE = 0x05, FIELD_TYPE_NULL = 0x06, FIELD_TYPE_TIMESTAMP = 0x07, FIELD_TYPE_LONGLONG = 0x08, FIELD_TYPE_INT24 = 0x09, FIELD_TYPE_DATE = 0x0A, FIELD_TYPE_TIME = 0x0B, FIELD_TYPE_DATETIME = 0x0C, FIELD_TYPE_YEAR = 0x0D, FIELD_TYPE_NEWDATE = 0x0E, FIELD_TYPE_VARCHAR = 0x0F, FIELD_TYPE_BIT = 0x10, FIELD_TYPE_NEWDECIMAL = 0xF6, FIELD_TYPE_ENUM = 0xF7, FIELD_TYPE_SET = 0xF8, FIELD_TYPE_TINY_BLOB = 0xF9, FIELD_TYPE_MEDIUM_BLOB = 0xFA, FIELD_TYPE_LONG_BLOB = 0xFB, FIELD_TYPE_BLOB = 0xFC, FIELD_TYPE_VAR_STRING = 0xFD, FIELD_TYPE_STRING = 0xFE, FIELD_TYPE_GEOMETRY = 0xFF } FIELD_TYPE; typedef enum { NOT_NULL_FLAG = 1, PRI_KEY_FLAG = 2, UNIQUE_KEY_FLAG = 4, MULTIPLE_KEY_FLAG = 8, BLOB_FLAG = 16, UNSIGNED_FLAG = 32, ZEROFILL_FLAG = 64, BINARY_FLAG = 128, ENUM_FLAG = 256, AUTO_INCREMENT_FLAG = 512, TIMESTAMP_FLAG = 1024, SET_FLAG = 2048, NUM_FLAG = 32768, } __FIELD_FLAG; typedef struct { char *catalog; char *db; char *table; char *org_table; char *name; char *org_name; int charset; int length; int flags; int decimals; FIELD_TYPE type; } MYSQL_FIELD; #define mysql_init mp_init #define mysql_real_connect mp_real_connect #define mysql_select_db mp_select_db #define mysql_real_query mp_real_query #define mysql_store_result mp_store_result #define mysql_field_count mp_field_count #define mysql_affected_rows mp_affected_rows #define mysql_escape_string mp_escape_string #define mysql_real_escape_string mp_real_escape_string #define mysql_close mp_close #define mysql_error mp_error #define mysql_num_rows mp_num_rows #define mysql_num_fields mp_num_fields #define mysql_fetch_fields mp_fetch_fields #define mysql_fetch_lengths mp_fetch_lengths #define mysql_fetch_row mp_fetch_row #define mysql_free_result mp_free_result MYSQL *mysql_init( void * ); MYSQL *mysql_real_connect( MYSQL *m, const char *host, const char *user, const char *pass, void *unused, int port, const char *socket, int options ); int mysql_select_db( MYSQL *m, const char *dbname ); int mysql_real_query( MYSQL *m, const char *query, int qlength ); MYSQL_RES *mysql_store_result( MYSQL *m ); int mysql_field_count( MYSQL *m ); int mysql_affected_rows( MYSQL *m ); int mysql_escape_string( MYSQL *m, char *sout, const char *sin, int length ); int mysql_real_escape_string( MYSQL *m, char *sout, const char *sin, int length ); void mysql_close( MYSQL *m ); const char *mysql_error( MYSQL *m ); const char *mysql_character_set_name( MYSQL *m ); unsigned int mysql_num_rows( MYSQL_RES *r ); int mysql_num_fields( MYSQL_RES *r ); MYSQL_FIELD *mysql_fetch_fields( MYSQL_RES *r ); unsigned long *mysql_fetch_lengths( MYSQL_RES *r ); MYSQL_ROW mysql_fetch_row( MYSQL_RES * r ); void mysql_free_result( MYSQL_RES *r ); #endif /* ************************************************************************ */ neko-2.0.0/libs/mysql/my_proto/my_proto.c0000644000175000017500000002303712112157473021143 0ustar ncannassencannasse/* ************************************************************************ */ /* */ /* MYSQL 5.0 Protocol Implementation */ /* Copyright (c)2008 Nicolas Cannasse */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /* ************************************************************************ */ #include #include #include #include "my_proto.h" #define MAX_PACKET_LENGTH 0xFFFFFF int myp_recv( MYSQL *m, void *buf, int size ) { while( size ) { int len = psock_recv(m->s,(char*)buf,size); if( len <= 0 ) return size == 0 ? 1 : 0; buf = ((char*)buf) + len; size -= len; } return 1; } int myp_send( MYSQL *m, void *buf, int size ) { while( size ) { int len = psock_send(m->s,(char*)buf,size); if( len <= 0 ) return size == 0 ? 1 : 0; buf = ((char*)buf) + len; size -= len; } return 1; } int myp_read( MYSQL_PACKET *p, void *buf, int size ) { if( p->size - p->pos < size ) { p->error = 1; return 0; } memcpy(buf,p->buf + p->pos,size); p->pos += size; return 1; } unsigned char myp_read_byte( MYSQL_PACKET *p ) { unsigned char c; if( !myp_read(p,&c,1) ) return 0; return c; } unsigned short myp_read_ui16( MYSQL_PACKET *p ) { unsigned short i; if( !myp_read(p,&i,2) ) return 0; return i; } int myp_read_int( MYSQL_PACKET *p ) { int i; if( !myp_read(p,&i,4) ) return 0; return i; } int myp_read_bin( MYSQL_PACKET *p ) { int c = myp_read_byte(p); if( c <= 250 ) return c; if( c == 251 ) return -1; // NULL if( c == 252 ) return myp_read_ui16(p); if( c == 253 ) { c = 0; myp_read(p,&c,3); return c; } if( c == 254 ) return myp_read_int(p); p->error = 1; return 0; } const char *myp_read_string( MYSQL_PACKET *p ) { char *str; if( p->pos >= p->size ) { p->error = 1; return ""; } str = p->buf + p->pos; p->pos += strlen(str) + 1; return str; } char *myp_read_bin_str( MYSQL_PACKET *p ) { int size = myp_read_bin(p); char *str; if( size == -1 ) return NULL; if( p->error || p->pos + size > p->size ) { p->error = 1; return NULL; } str = (char*)malloc(size + 1); memcpy(str,p->buf + p->pos, size); str[size] = 0; p->pos += size; return str; } int myp_read_packet( MYSQL *m, MYSQL_PACKET *p ) { unsigned int psize; p->pos = 0; p->error = 0; if( !myp_recv(m,&psize,4) ) { p->error = 1; p->size = 0; return 0; } //p->id = (psize >> 24); psize &= 0xFFFFFF; p->size = psize; if( p->mem < (int)psize ) { free(p->buf); p->buf = (char*)malloc(psize + 1); p->mem = psize; } p->buf[psize] = 0; if( psize == 0 || !myp_recv(m,p->buf,psize) ) { p->error = 1; p->size = 0; p->buf[0] = 0; return 0; } return 1; } int myp_send_packet( MYSQL *m, MYSQL_PACKET *p, int *packet_counter ) { unsigned int header; char *buf = p->buf; int size = p->size; int next = 1; while( next ) { int psize; if( size >= MAX_PACKET_LENGTH ) psize = MAX_PACKET_LENGTH; else { psize = size; next = 0; } header = psize | (((*packet_counter)++) << 24); if( !myp_send(m,&header,4) || !myp_send(m,buf,psize) ) { p->error = 1; return 0; } buf += psize; size -= psize; } return 1; } void myp_begin_packet( MYSQL_PACKET *p, int minsize ) { if( p->mem < minsize ) { free(p->buf); p->buf = (char*)malloc(minsize + 1); p->mem = minsize; } p->error = 0; p->size = 0; } void myp_write( MYSQL_PACKET *p, const void *data, int size ) { if( p->size + size > p->mem ) { char *buf2; if( p->mem == 0 ) p->mem = 32; do { p->mem <<= 1; } while( p->size + size > p->mem ); buf2 = (char*)malloc(p->mem + 1); memcpy(buf2,p->buf,p->size); free(p->buf); p->buf = buf2; } memcpy( p->buf + p->size , data, size ); p->size += size; } void myp_write_byte( MYSQL_PACKET *p, int i ) { unsigned char c = (unsigned char)i; myp_write(p,&c,1); } void myp_write_ui16( MYSQL_PACKET *p, int i ) { unsigned short c = (unsigned char)i; myp_write(p,&c,2); } void myp_write_int( MYSQL_PACKET *p, int i ) { myp_write(p,&i,4); } void myp_write_string( MYSQL_PACKET *p, const char *str ) { myp_write(p,str,strlen(str) + 1); } void myp_write_bin( MYSQL_PACKET *p, int size ) { if( size <= 250 ) { unsigned char l = (unsigned char)size; myp_write(p,&l,1); } else if( size < 0x10000 ) { unsigned char c = 252; unsigned short l = (unsigned short)size; myp_write(p,&c,1); myp_write(p,&l,2); } else if( size < 0x1000000 ) { unsigned char c = 253; unsigned int l = (unsigned short)size; myp_write(p,&c,1); myp_write(p,&l,3); } else { unsigned char c = 254; myp_write(p,&c,1); myp_write(p,&size,4); } } void myp_crypt( unsigned char *out, const unsigned char *s1, const unsigned char *s2, unsigned int len ) { unsigned int i; for(i=0;imax_value = 0x3FFFFFFFL; r->max_value_dbl = (double)r->max_value; r->seed1 = seed1 % r->max_value ; r->seed2 = seed2 % r->max_value; } static double myp_rnd( rand_ctx *r ) { r->seed1 = (r->seed1 * 3 + r->seed2) % r->max_value; r->seed2 = (r->seed1 + r->seed2 + 33) % r->max_value; return (((double) r->seed1)/r->max_value_dbl); } static void hash_password( unsigned long *result, const char *password, int password_len ) { register unsigned long nr = 1345345333L, add = 7, nr2 = 0x12345671L; unsigned long tmp; const char *password_end = password + password_len; for(; password < password_end; password++) { if( *password == ' ' || *password == '\t' ) continue; tmp = (unsigned long)(unsigned char)*password; nr ^= (((nr & 63)+add)*tmp)+(nr << 8); nr2 += (nr2 << 8) ^ nr; add += tmp; } result[0] = nr & (((unsigned long) 1L << 31) -1L); result[1] = nr2 & (((unsigned long) 1L << 31) -1L); } void myp_encrypt_pass_323( const char *password, const char seed[SEED_LENGTH_323], char to[SEED_LENGTH_323] ) { rand_ctx r; unsigned long hash_pass[2], hash_seed[2]; char extra, *to_start = to; const char *seed_end = seed + SEED_LENGTH_323; hash_password(hash_pass,password,(unsigned int)strlen(password)); hash_password(hash_seed,seed,SEED_LENGTH_323); random_init(&r,hash_pass[0] ^ hash_seed[0],hash_pass[1] ^ hash_seed[1]); while( seed < seed_end ) { *to++ = (char)(floor(myp_rnd(&r)*31)+64); seed++; } extra= (char)(floor(myp_rnd(&r)*31)); while( to_start != to ) *(to_start++) ^= extra; } // defined in mysql/strings/ctype-*.c const char *myp_charset_name( int charset ) { switch( charset ) { case 8: case 31: case 47: return "latin1"; case 63: return "binary"; // 101+ : utf16 // 160+ : utf32 case 33: case 83: case 223: case 254: return "utf8"; case 45: case 46: return "utf8mb4"; // superset of utf8 with up to 4 bytes per-char default: if( charset >= 192 && charset <= 211 ) return "utf8"; if( charset >= 224 && charset <= 243 ) return "utf8mb4"; } return NULL; } int myp_supported_charset( int charset ) { return myp_charset_name(charset) != NULL; } int myp_escape_string( int charset, char *sout, const char *sin, int length ) { // this is safe for UTF8 as well since mysql protects against invalid UTF8 char injection const char *send = sin + length; char *sbegin = sout; while( sin != send ) { char c = *sin++; switch( c ) { case 0: *sout++ = '\\'; *sout++ = '0'; break; case '\n': *sout++ = '\\'; *sout++ = 'n'; break; case '\r': *sout++ = '\\'; *sout++ = 'r'; break; case '\\': *sout++ = '\\'; *sout++ = '\\'; break; case '\'': *sout++ = '\\'; *sout++ = '\''; break; case '"': *sout++ = '\\'; *sout++ = '"'; break; case '\032': *sout++ = '\\'; *sout++ = 'Z'; break; default: *sout++ = c; } } *sout = 0; return sout - sbegin; } int myp_escape_quotes( int charset, char *sout, const char *sin, int length ) { const char *send = sin + length; char *sbegin = sout; while( sin != send ) { char c = *sin++; *sout++ = c; if( c == '\'' ) *sout++ = c; } *sout = 0; return sout - sbegin; } /* ************************************************************************ */ neko-2.0.0/libs/mysql/mysql.c0000644000175000017500000003331712112157473016572 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include typedef int SOCKET; #include #include /**

MySQL

API to connect and use MySQL database

**/ #define CNX(o) ((connection*)val_data(o)) #define RESULT(o) ((result*)val_data(o)) typedef struct { MYSQL *m; value conv_date; value conv_bytes; value conv_string; } connection; DEFINE_KIND(k_connection); DEFINE_KIND(k_result); static void error( MYSQL *m, const char *msg ) { buffer b = alloc_buffer(msg); buffer_append(b," "); buffer_append(b,mysql_error(m)); bfailure(b); } // --------------------------------------------------------------- // Result /**

Result

**/ #undef CONV_FLOAT typedef enum { CONV_INT, CONV_STRING, CONV_FLOAT, CONV_BINARY, CONV_DATE, CONV_DATETIME, CONV_BOOL } CONV; typedef struct { MYSQL_RES *r; int nfields; CONV *fields_convs; field *fields_ids; MYSQL_ROW current; value conv_date; value conv_string; value conv_bytes; } result; static void free_result( value o ) { result *r = RESULT(o); mysql_free_result(r->r); } /** result_set_conv_date : 'result -> function:1 -> void Set the function that will convert a Date or DateTime string to the corresponding value. **/ static value result_set_conv_date( value o, value c ) { val_check_function(c,1); if( val_is_int(o) ) return val_true; val_check_kind(o,k_result); RESULT(o)->conv_date = c; return val_true; } /** result_get_length : 'result -> int Return the number of rows returned or affected **/ static value result_get_length( value o ) { if( val_is_int(o) ) return o; val_check_kind(o,k_result); return alloc_int( (int)mysql_num_rows(RESULT(o)->r) ); } /** result_get_nfields : 'result -> int Return the number of fields in a result row **/ static value result_get_nfields( value o ) { val_check_kind(o,k_result); return alloc_int(RESULT(o)->nfields); } /** result_get_fields_names : 'result -> string array Return the fields names corresponding results columns **/ static value result_get_fields_names( value o ) { result *r; value a; int k; MYSQL_FIELD *fields; val_check_kind(o,k_result); r = RESULT(o); fields = mysql_fetch_fields(r->r); a = alloc_array(r->nfields); for(k=0;knfields;k++) val_array_ptr(a)[k] = alloc_string(fields[k].name); return a; } /** result_next : 'result -> object? Return the next row if available. A row is represented as an object, which fields have been converted to the corresponding Neko value (int, float or string). For Date and DateTime you can specify your own conversion function using [result_set_conv_date]. By default they're returned as plain strings. Additionally, the TINYINT(1) will be converted to either true or false if equal to 0. **/ static value result_next( value o ) { result *r; unsigned long *lengths = NULL; MYSQL_ROW row; val_check_kind(o,k_result); r = RESULT(o); row = mysql_fetch_row(r->r); if( row == NULL ) return val_null; { int i; value cur = alloc_object(NULL); r->current = row; for(i=0;infields;i++) if( row[i] != NULL ) { value v; switch( r->fields_convs[i] ) { case CONV_INT: v = alloc_int(atoi(row[i])); break; case CONV_STRING: v = alloc_string(row[i]); if( r->conv_string != NULL ) v = val_call1(r->conv_string,v); break; case CONV_BOOL: v = alloc_bool( *row[i] != '0' ); break; case CONV_FLOAT: v = alloc_float(atof(row[i])); break; case CONV_BINARY: if( lengths == NULL ) { lengths = mysql_fetch_lengths(r->r); if( lengths == NULL ) val_throw(alloc_string("mysql_fetch_lengths")); } v = copy_string(row[i],lengths[i]); if( r->conv_bytes != NULL ) v = val_call1(r->conv_bytes,v); break; case CONV_DATE: if( r->conv_date == NULL ) v = alloc_string(row[i]); else { struct tm t; sscanf(row[i],"%4d-%2d-%2d",&t.tm_year,&t.tm_mon,&t.tm_mday); t.tm_hour = 0; t.tm_min = 0; t.tm_sec = 0; t.tm_isdst = -1; t.tm_year -= 1900; t.tm_mon--; v = val_call1(r->conv_date,alloc_int32((int)mktime(&t))); } break; case CONV_DATETIME: if( r->conv_date == NULL ) v = alloc_string(row[i]); else { struct tm t; sscanf(row[i],"%4d-%2d-%2d %2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec); t.tm_isdst = -1; t.tm_year -= 1900; t.tm_mon--; v = val_call1(r->conv_date,alloc_int32((int)mktime(&t))); } break; default: v = val_null; break; } alloc_field(cur,r->fields_ids[i],v); } return cur; } } /** result_get : 'result -> n:int -> string Return the [n]th field of the current row **/ static value result_get( value o, value n ) { result *r; const char *s; val_check_kind(o,k_result); val_check(n,int); r = RESULT(o); if( val_int(n) < 0 || val_int(n) >= r->nfields ) neko_error(); if( !r->current ) { result_next(o); if( !r->current ) neko_error(); } s = r->current[val_int(n)]; return alloc_string( s?s:"" ); } /** result_get_int : 'result -> n:int -> int Return the [n]th field of the current row as an integer (or 0) **/ static value result_get_int( value o, value n ) { result *r; const char *s; val_check_kind(o,k_result); val_check(n,int); r = RESULT(o); if( val_int(n) < 0 || val_int(n) >= r->nfields ) neko_error(); if( !r->current ) { result_next(o); if( !r->current ) neko_error(); } s = r->current[val_int(n)]; return alloc_int( s?atoi(s):0 ); } /** result_get_float : 'result -> n:int -> float Return the [n]th field of the current row as a float (or 0) **/ static value result_get_float( value o, value n ) { result *r; const char *s; val_check_kind(o,k_result); val_check(n,int); r = RESULT(o); if( val_int(n) < 0 || val_int(n) >= r->nfields ) neko_error(); if( !r->current ) { result_next(o); if( !r->current ) neko_error(); } s = r->current[val_int(n)]; return alloc_float( s?atof(s):0 ); } static CONV convert_type( enum enum_field_types t, int flags, unsigned int length ) { // FIELD_TYPE_TIME // FIELD_TYPE_YEAR // FIELD_TYPE_NEWDATE // FIELD_TYPE_NEWDATE + 2: // 5.0 MYSQL_TYPE_BIT switch( t ) { case FIELD_TYPE_TINY: if( length == 1 ) return CONV_BOOL; case FIELD_TYPE_SHORT: case FIELD_TYPE_LONG: case FIELD_TYPE_INT24: return CONV_INT; case FIELD_TYPE_LONGLONG: case FIELD_TYPE_DECIMAL: case FIELD_TYPE_FLOAT: case FIELD_TYPE_DOUBLE: case 246: // 5.0 MYSQL_NEW_DECIMAL return CONV_FLOAT; case FIELD_TYPE_BLOB: case FIELD_TYPE_TINY_BLOB: case FIELD_TYPE_MEDIUM_BLOB: case FIELD_TYPE_LONG_BLOB: if( (flags & BINARY_FLAG) != 0 ) return CONV_BINARY; return CONV_STRING; case FIELD_TYPE_DATETIME: case FIELD_TYPE_TIMESTAMP: return CONV_DATETIME; case FIELD_TYPE_DATE: return CONV_DATE; case FIELD_TYPE_NULL: case FIELD_TYPE_ENUM: case FIELD_TYPE_SET: //case FIELD_TYPE_VAR_STRING: //case FIELD_TYPE_GEOMETRY: // 5.0 MYSQL_TYPE_VARCHAR default: if( (flags & BINARY_FLAG) != 0 ) return CONV_BINARY; return CONV_STRING; } } static value alloc_result( connection *c, MYSQL_RES *r ) { result *res = (result*)alloc(sizeof(result)); value o = alloc_abstract(k_result,res); int num_fields = mysql_num_fields(r); int i,j; MYSQL_FIELD *fields = mysql_fetch_fields(r); res->r = r; res->conv_date = c->conv_date; res->conv_bytes = c->conv_bytes; res->conv_string = c->conv_string; res->current = NULL; res->nfields = num_fields; res->fields_ids = (field*)alloc_private(sizeof(field)*num_fields); res->fields_convs = (CONV*)alloc_private(sizeof(CONV)*num_fields); for(i=0;ifields_ids[j] == id ) { buffer b = alloc_buffer("Error, same field ids for : "); buffer_append(b,fields[i].name); buffer_append(b,":"); val_buffer(b,alloc_int(i)); buffer_append(b," and "); buffer_append(b,fields[j].name); buffer_append(b,":"); val_buffer(b,alloc_int(j)); buffer_append(b,"."); bfailure(b); } } res->fields_ids[i] = id; res->fields_convs[i] = convert_type(fields[i].type,fields[i].flags,fields[i].length); } val_gc(o,free_result); return o; } // --------------------------------------------------------------- // Connection /**

Connection

**/ /** close : 'connection -> void Close the connection. Any subsequent operation will fail on it **/ static value close( value o ) { val_check_kind(o,k_connection); mysql_close(CNX(o)->m); val_data(o) = NULL; val_kind(o) = NULL; val_gc(o,NULL); return val_true; } /** select_db : 'connection -> string -> void Select the database **/ static value select_db( value o, value db ) { val_check_kind(o,k_connection); val_check(db,string); if( mysql_select_db(CNX(o)->m,val_string(db)) != 0 ) error(CNX(o)->m,"Failed to select database :"); return val_true; } /** request : 'connection -> string -> 'result Execute an SQL request. Exception on error **/ static value request( value o, value r ) { MYSQL_RES *res; connection *c; val_check_kind(o,k_connection); val_check(r,string); c = CNX(o); if( mysql_real_query(c->m,val_string(r),val_strlen(r)) != 0 ) error(c->m,val_string(r)); res = mysql_store_result(c->m); if( res == NULL ) { if( mysql_field_count(c->m) == 0 ) return alloc_int( (int)mysql_affected_rows(c->m) ); else error(c->m,val_string(r)); } return alloc_result(c,res); } /** escape : 'connection -> string -> string Escape the string for inserting into a SQL request **/ static value escape( value o, value s ) { int len; value sout; val_check_kind(o,k_connection); val_check(s,string); len = val_strlen(s) * 2; sout = alloc_empty_string(len); len = mysql_real_escape_string(CNX(o)->m,val_string(sout),val_string(s),val_strlen(s)); if( len < 0 ) { buffer b = alloc_buffer("Unsupported charset : "); buffer_append(b,mysql_character_set_name(CNX(o)->m)); bfailure(b); } val_set_length(sout,len); return sout; } /** set_conv_funs : 'connection -> function:1 -> function:1 -> function:1 -> void Set three wrapper methods to be be called when creating a string, a date, and binary data in results **/ static value set_conv_funs( value o, value fstring, value fdate, value fbytes ) { val_check_kind(o,k_connection); val_check_function(fstring,1); val_check_function(fdate,1); val_check_function(fbytes,1); CNX(o)->conv_string = fstring; CNX(o)->conv_date = fdate; CNX(o)->conv_bytes = fbytes; return val_null; } // --------------------------------------------------------------- // Sql static void free_connection( value o ) { mysql_close(CNX(o)->m); } /** connect : { host => string, port => int, user => string, pass => string, socket => string? } -> 'connection Connect to a database using the connection informations **/ static value connect( value params ) { value host, port, user, pass, socket; val_check(params,object); host = val_field(params,val_id("host")); port = val_field(params,val_id("port")); user = val_field(params,val_id("user")); pass = val_field(params,val_id("pass")); socket = val_field(params,val_id("socket")); val_check(host,string); val_check(port,int); val_check(user,string); val_check(pass,string); if( !val_is_string(socket) && !val_is_null(socket) ) neko_error(); { connection *c = (connection*)alloc(sizeof(connection)); value v; c->m = mysql_init(NULL); c->conv_string = NULL; c->conv_date = NULL; c->conv_bytes = NULL; if( mysql_real_connect(c->m,val_string(host),val_string(user),val_string(pass),NULL,val_int(port),val_is_null(socket)?NULL:val_string(socket),0) == NULL ) { buffer b = alloc_buffer("Failed to connect to mysql server : "); buffer_append(b,mysql_error(c->m)); mysql_close(c->m); bfailure(b); } v = alloc_abstract(k_connection,c); val_gc(v,free_connection); return v; } } // --------------------------------------------------------------- // Registers DEFINE_PRIM(connect,1); DEFINE_PRIM(close,1); DEFINE_PRIM(request,2); DEFINE_PRIM(select_db,2); DEFINE_PRIM(escape,2); DEFINE_PRIM(result_get_length,1); DEFINE_PRIM(result_get_nfields,1); DEFINE_PRIM(result_get_fields_names,1); DEFINE_PRIM(result_next,1); DEFINE_PRIM(result_get,2); DEFINE_PRIM(result_get_int,2); DEFINE_PRIM(result_get_float,2); DEFINE_PRIM(result_set_conv_date,2); DEFINE_PRIM(set_conv_funs,4); /* ************************************************************************ */ neko-2.0.0/libs/libs_vc10.sln0000644000175000017500000001456112112157473016414 0ustar ncannassencannasseMicrosoft Visual Studio Solution File, Format Version 11.00 # Visual C++ Express 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_neko", "mod_neko\mod_neko.vcxproj", "{BC400EC9-8F65-4E34-85DC-687D5272B049}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql", "mysql\mysql.vcxproj", "{159607BD-674F-44DA-9290-CF923B2703CC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regexp", "regexp\regexp.vcxproj", "{145AAFB0-C897-4F74-A330-314F5727C5D4}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "std", "std\std.vcxproj", "{32AA6F03-939E-469B-8E85-A0CCE55464AD}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcxproj", "{55ECFCE6-00FB-44F0-B477-E8507423930D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_neko2", "mod_neko\mod_neko2.vcxproj", "{311DC43B-AABB-4796-883C-F2482165F8C4}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqlite", "sqlite\sqlite.vcxproj", "{EDFCD8E6-CFB1-4288-82F5-D069A25C3947}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql5", "mysql\mysql5.vcxproj", "{DB4D82FF-EE9A-4456-9163-48CCC64FEB09}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ui", "ui\ui.vcxproj", "{9A36DC8A-8070-4F5D-A401-6889DD652288}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_tora", "mod_tora\mod_tora.vcxproj", "{4F7BD088-CAFB-4263-98DA-D9BABE82EAC6}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_tora2", "mod_tora\mod_tora2.vcxproj", "{0242BA00-FECF-4D6B-80FA-2A9389E9060C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 ReleaseCrt60|Win32 = ReleaseCrt60|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {BC400EC9-8F65-4E34-85DC-687D5272B049}.Debug|Win32.ActiveCfg = Debug|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.Debug|Win32.Build.0 = Debug|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.Release|Win32.ActiveCfg = Release|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.Release|Win32.Build.0 = Release|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.ReleaseCrt60|Win32.Build.0 = ReleaseCrt60|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Debug|Win32.ActiveCfg = Debug|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Debug|Win32.Build.0 = Debug|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Release|Win32.ActiveCfg = Release|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Release|Win32.Build.0 = Release|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.ReleaseCrt60|Win32.Build.0 = ReleaseCrt60|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.Debug|Win32.ActiveCfg = Debug|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.Debug|Win32.Build.0 = Debug|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.Release|Win32.ActiveCfg = Release|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.Release|Win32.Build.0 = Release|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.ReleaseCrt60|Win32.Build.0 = ReleaseCrt60|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.Debug|Win32.ActiveCfg = Debug|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.Debug|Win32.Build.0 = Debug|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.Release|Win32.ActiveCfg = Release|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.Release|Win32.Build.0 = Release|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.ReleaseCrt60|Win32.Build.0 = ReleaseCrt60|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.Debug|Win32.ActiveCfg = Debug|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.Debug|Win32.Build.0 = Debug|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.Release|Win32.ActiveCfg = Release|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.Release|Win32.Build.0 = Release|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.ReleaseCrt60|Win32.Build.0 = ReleaseCrt60|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Debug|Win32.ActiveCfg = Debug|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Debug|Win32.Build.0 = Debug|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Release|Win32.ActiveCfg = Release|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Release|Win32.Build.0 = Release|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.ReleaseCrt60|Win32.Build.0 = ReleaseCrt60|Win32 {EDFCD8E6-CFB1-4288-82F5-D069A25C3947}.Debug|Win32.ActiveCfg = Debug|Win32 {EDFCD8E6-CFB1-4288-82F5-D069A25C3947}.Release|Win32.ActiveCfg = Release|Win32 {EDFCD8E6-CFB1-4288-82F5-D069A25C3947}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 {DB4D82FF-EE9A-4456-9163-48CCC64FEB09}.Debug|Win32.ActiveCfg = Debug|Win32 {DB4D82FF-EE9A-4456-9163-48CCC64FEB09}.Release|Win32.ActiveCfg = Release|Win32 {DB4D82FF-EE9A-4456-9163-48CCC64FEB09}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.Debug|Win32.ActiveCfg = Debug|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.Debug|Win32.Build.0 = Debug|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.Release|Win32.ActiveCfg = Release|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.Release|Win32.Build.0 = Release|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.ReleaseCrt60|Win32.Build.0 = ReleaseCrt60|Win32 {4F7BD088-CAFB-4263-98DA-D9BABE82EAC6}.Debug|Win32.ActiveCfg = Debug|Win32 {4F7BD088-CAFB-4263-98DA-D9BABE82EAC6}.Release|Win32.ActiveCfg = Release|Win32 {4F7BD088-CAFB-4263-98DA-D9BABE82EAC6}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 {0242BA00-FECF-4D6B-80FA-2A9389E9060C}.Debug|Win32.ActiveCfg = Debug|Win32 {0242BA00-FECF-4D6B-80FA-2A9389E9060C}.Release|Win32.ActiveCfg = Release|Win32 {0242BA00-FECF-4D6B-80FA-2A9389E9060C}.ReleaseCrt60|Win32.ActiveCfg = ReleaseCrt60|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal neko-2.0.0/libs/mod_neko/0000755000175000017500000000000012112157473015700 5ustar ncannassencannasseneko-2.0.0/libs/mod_neko/mod_neko.h0000644000175000017500000000412212112157473017643 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef MODNEKO_H #define MODNEKO_H #include #include #include #include #include #include #undef NOERROR #undef INLINE #include #ifndef NEKO_WINDOWS # include #endif typedef struct { request_rec *r; value main; value post_data; value content_type; bool headers_sent; } mcontext; typedef struct { int hits; int use_jit; int use_stats; int use_prim_stats; int use_cache; int exceptions; int gc_period; int max_post_size; } mconfig; #define CONTEXT() ((mcontext*)neko_vm_custom(neko_vm_current(),k_mod_neko)) DECLARE_KIND(k_mod_neko) #ifdef STANDARD20_MODULE_STUFF # define APACHE_2_X # define REMOTE_ADDR(c) c->remote_addr->sa.sin.sin_addr #else # define REMOTE_ADDR(c) c->remote_addr.sin_addr #endif extern mconfig *mod_neko_get_config(); extern void mod_neko_set_config( mconfig *cfg ); #endif /* ************************************************************************ */ neko-2.0.0/libs/mod_neko/mod_neko2.vcxproj0000644000175000017500000002000312112157473021165 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {311DC43B-AABB-4796-883C-F2482165F8C4} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug2\ Debug2\ true Release2\ Release2\ false Release\ Release\ false Disabled ../../vm;..\include\apache2;..\include\apache2\apr;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_NEKO2_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ../include/apache2/libhttpd.lib;../include/apache2/libapr-1.lib;../../bin/neko.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/mod_neko2.ndll true $(OutDir)mod_neko2.pdb Windows $(OutDir)mod_neko2.lib MachineX86 ../../vm;..\include\apache2;..\include\apache2\apr;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_NEKO2_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../include/apache2/libhttpd.lib;../include/apache2/libapr-1.lib;../../bin/neko.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/mod_neko2.ndll %(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)mod_neko2.lib MachineX86 ../../vm;..\include\apache2;..\include\apache2\apr;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_NEKO2_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../include/apache2/libhttpd.lib;../include/apache2/libapr-1.lib;../../bin/neko.lib;ws2_32.lib;../include/msvcrt/extra.lib;%(AdditionalDependencies) ../../bin/mod_neko2.ndll MSVCRT;%(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)mod_neko2.lib MachineX86 neko-2.0.0/libs/mod_neko/mod_neko.c0000644000175000017500000003176612112157473017654 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "mod_neko.h" #include #include #include #ifndef MOD_NEKO_POST_SIZE # define MOD_NEKO_POST_SIZE (1 << 18) // 256 K #endif #ifdef APACHE_2_X # define FTIME(r) r->finfo.mtime # define ap_send_http_header(x) # define ap_soft_timeout(msg,r) # define ap_kill_timeout(r) # define ap_table_get apr_table_get # define LOG_SUCCESS APR_SUCCESS, typedef apr_time_t aptime; #else # define FTIME(r) r->finfo.st_mtime # define LOG_SUCCESS typedef time_t aptime; #endif #define apache_error(level,request,message) \ ap_rprintf(request,"Error : %s",message); \ ap_log_rerror(__FILE__, __LINE__, level, LOG_SUCCESS request, "[mod_neko error] %s", message) typedef struct cache { value file; value main; int hits; aptime time; struct cache *next; } cache; static mconfig config; static int init_done = 0; static mt_local *cache_root = NULL; extern void neko_stats_measure( neko_vm *vm, const char *kind, int start ); extern value neko_stats_build( neko_vm *vm ); value cgi_command( value v ) { val_check(v,string); if( strcmp(val_string(v),"stats") == 0 ) return neko_stats_build(neko_vm_current()); if( strcmp(val_string(v),"cache") == 0 ) { cache *c = (cache*)local_get(cache_root); value l = val_null; while( c != NULL ) { value a = alloc_array(4); val_array_ptr(a)[0] = c->file; val_array_ptr(a)[1] = c->main; val_array_ptr(a)[2] = alloc_int(c->hits); val_array_ptr(a)[3] = l; l = a; c = c->next; } return l; } neko_error(); } mconfig *mod_neko_get_config() { return &config; } void mod_neko_set_config( mconfig *c ) { config = *c; } static void gc_major() { if( config.gc_period <= 0 || config.hits % config.gc_period != 0 ) return; if( config.use_stats ) neko_stats_measure(NULL,"gc",1); neko_gc_major(); if( config.use_stats ) neko_stats_measure(NULL,"gc",0); } static void send_headers( mcontext *c ) { if( !c->headers_sent ) { ap_send_http_header(c->r); c->headers_sent = true; } } static void request_print( const char *data, int size, void *_c ) { mcontext *c = (mcontext *)_c; if( c == NULL ) c = CONTEXT(); if( size == -1 ) size = (int)strlen(data); ap_soft_timeout("Client Timeout",c->r); send_headers(c); ap_rwrite(data,size,c->r); ap_kill_timeout(c->r); } static void null_print( const char *data, int size, void *_c ) { } static value cache_find( request_rec *r ) { cache *c = (cache*)local_get(cache_root); cache *prev = NULL; value fname = alloc_string(r->filename); while( c != NULL ) { if( val_compare(fname,c->file) == 0 ) { if( config.use_cache && FTIME(r) == c->time ) { c->hits++; return c->main; } if( prev == NULL ) local_set(cache_root,c->next); else prev->next = c->next; free_root((value*)c); // try to lower memory partitioning // when a module is updated c = NULL; gc_major(); break; } prev = c; c = c->next; } return NULL; } static char *request_base_uri( request_rec *r ) { while( r->prev != NULL ) r = r->prev; return r->unparsed_uri; } static void cache_module( const char *filename, aptime time, value main ) { cache *c = (cache*)local_get(cache_root), *prev = NULL; value fname = alloc_string(filename); while( c != NULL ) { if( val_compare(fname,c->file) == 0 ) { if( main == NULL ) { if( prev == NULL ) local_set(cache_root,c->next); else prev->next = c->next; free_root((value*)c); } else { c->main = main; c->time = time; } return; } prev = c; c = c->next; } c = (cache*)alloc_root(sizeof(struct cache) / sizeof(value)); c->file = fname; c->main = main; c->time = time; c->hits = 0; c->next = (cache*)local_get(cache_root); local_set(cache_root,c); } static int neko_handler_rec( request_rec *r ) { mcontext ctx; neko_vm *vm; const char *ctype; value exc = NULL; /* Seems to crash on Windows. And on Linux, we rarely have libGC 7.x installed anyway # if defined(APACHE_2_X) || defined(NEKO_WINDOWS) // we are using threads, so let's make sure that the current thread is registered neko_thread_register(true); # endif */ config.hits++; ctx.r = r; ctx.main = cache_find(r); ctx.post_data = val_null; ctx.headers_sent = false; ctx.content_type = alloc_string("text/html"); r->content_type = val_string(ctx.content_type); if( ap_setup_client_block(r,REQUEST_CHUNKED_ERROR) != 0 ) { send_headers(&ctx); apache_error(APLOG_WARNING,r,"ap_setup_client_block failed"); return OK; } ctype = ap_table_get(r->headers_in,"Content-Type"); if( (!ctype || strstr(ctype,"multipart/form-data") == NULL) && ap_should_client_block(r) ) { # define MAXLEN 1024 char buf[MAXLEN]; int len; int tlen = 0; buffer b = alloc_buffer(NULL); while( (len = ap_get_client_block(r,buf,MAXLEN)) > 0 ) { if( tlen < config.max_post_size ) buffer_append_sub(b,buf,len); tlen += len; } if( tlen >= config.max_post_size ) { send_headers(&ctx); apache_error(APLOG_WARNING,r,"Maximum POST data exceeded. Try using multipart encoding"); return OK; } ctx.post_data = buffer_to_string(b); } vm = neko_vm_alloc(NULL); if( config.use_stats ) neko_vm_set_stats(vm,neko_stats_measure,config.use_prim_stats?neko_stats_measure:NULL); neko_vm_set_custom(vm,k_mod_neko,&ctx); if( config.use_jit && !neko_vm_jit(vm,1) ) { send_headers(&ctx); apache_error(APLOG_WARNING,r,"JIT required by env. var but not enabled in NekoVM"); return OK; } neko_vm_redirect(vm,request_print,&ctx); neko_vm_select(vm); if( ctx.main != NULL ) { value old = ctx.main; if( config.use_stats ) neko_stats_measure(vm,r->filename,1); val_callEx(val_null,old,NULL,0,&exc); if( config.use_stats ) neko_stats_measure(vm,r->filename,0); if( old != ctx.main ) cache_module(r->filename,FTIME(r),ctx.main); } else { char *base_uri = request_base_uri(r); value mload = neko_default_loader(&base_uri,1); value args[] = { alloc_string(r->filename), mload }; char *p = strrchr(val_string(args[0]),'.'); if( p != NULL ) *p = 0; val_callEx(mload,val_field(mload,val_id("loadmodule")),args,2,&exc); if( ctx.main != NULL && config.use_cache ) cache_module(r->filename,FTIME(r),ctx.main); } if( exc != NULL ) { buffer b = alloc_buffer(NULL); value v; int i; const char *p, *start; value st = neko_exc_stack(vm); val_buffer(b,exc); config.exceptions++; ap_soft_timeout("Client Timeout",r); send_headers(&ctx); v = buffer_to_string(b); p = val_string(v); start = p; ap_rprintf(r,"Uncaught exception - "); while( *p ) { if( *p == '<' || *p == '>' ) { ap_rwrite(start,(int)(p - start),r); ap_rwrite((*p == '<')?"<":">",4, r); start = p + 1; } p++; } ap_rwrite(start,(int)(p - start),r); ap_rprintf(r,"

"); for(i=0;i"); else if( val_is_string(s) ) { ap_rprintf(r,"Called from %s (no debug available)
",val_string(s)); } else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) ) ap_rprintf(r,"Called from %s line %d
",val_string(val_array_ptr(s)[0]),val_int(val_array_ptr(s)[1])); else { b = alloc_buffer(NULL); val_buffer(b,s); ap_rprintf(r,"Called from %s
",val_string(buffer_to_string(b))); } } ap_kill_timeout(r); return OK; } send_headers(&ctx); return OK; } static int neko_handler( request_rec *r ) { int ret; if( strcmp(r->handler,"neko-handler") != 0) return DECLINED; if( config.use_stats ) neko_stats_measure(NULL,r->hostname,1); ret = neko_handler_rec(r); neko_vm_select(NULL); if( config.use_stats ) neko_stats_measure(NULL,r->hostname,0); gc_major(); return ret; } static void mod_neko_do_init() { int tmp = 0; if( init_done ) return; init_done = 1; memset(&config,0,sizeof(config)); config.use_cache = 1; config.gc_period = 1; config.max_post_size = MOD_NEKO_POST_SIZE; # ifdef APACHE_2_X putenv(strdup("MOD_NEKO=2")); # else putenv(strdup("MOD_NEKO=1")); # endif neko_global_init(); cache_root = alloc_local(); } static value init_module() { neko_vm *vm = neko_vm_current(); mcontext *ctx = CONTEXT(); value env = vm->env; ctx->main = NULL; val_call1(val_array_ptr(env)[0],val_array_ptr(env)[1]); cache_module(ctx->r->filename,FTIME(ctx->r),ctx->main); return val_null; } static void preload_module( const char *name, server_rec *serv ) { value exc = NULL; neko_vm *vm = neko_vm_alloc(NULL); value mload = neko_default_loader(NULL,0); value m, read_path, exec; time_t time = 0; neko_vm_select(vm); if( config.use_jit ) neko_vm_jit(vm,1); if( !exc ) { value args[] = { alloc_string("std@module_read_path"), alloc_int(3) }; read_path = val_callEx(mload,val_field(mload,val_id("loadprim")),args,2,&exc); } if( !exc ) { value args[] = { alloc_string("std@module_exec"), alloc_int(1) }; exec = val_callEx(mload,val_field(mload,val_id("loadprim")),args,2,&exc); } if( !exc ) { value args[] = { val_null, alloc_string(name), mload }; char *p = strrchr(val_string(args[1]),'.'); if( p != NULL ) *p = 0; m = val_callEx(mload,read_path,args,3,&exc); } if( !exc ) { struct stat t; if( stat(name,&t) ) exc = alloc_string("failed to stat()"); else time = t.st_mtime; } if( !exc ) { value f = alloc_function(init_module,0,"init_module"); value env = alloc_array(2); val_array_ptr(env)[0] = exec; val_array_ptr(env)[1] = m; ((vfunction*)f)->env = env; cache_module(name,time,f); } if( exc ) { buffer b = alloc_buffer(NULL); val_buffer(b,exc); ap_log_error(__FILE__,__LINE__,APLOG_WARNING,LOG_SUCCESS serv,"Failed to preload module '%s' : %s",name,val_string(buffer_to_string(b))); } neko_vm_select(NULL); } #ifdef APACHE_2_X # define MCONFIG void* #else # define MCONFIG char* #endif static const char *mod_neko_config( cmd_parms *cmd, MCONFIG mconfig, const char *fargs ) { char *code = strdup(fargs); char *args = code; int value; while( true ) { char c = *args; if( c == 0 || c == ' ' || c == '\t' ) break; args++; } while( *args == ' ' || *args == '\t' ) *args++ = 0; value = atoi(args); mod_neko_do_init(); if( strcmp(code,"JIT") == 0 ) config.use_jit = value; else if( strcmp(code,"CACHE") == 0 ) config.use_cache = value; else if( strcmp(code,"GC_PERIOD") == 0 ) config.gc_period = value; else if( strcmp(code,"POST_SIZE") == 0 ) config.max_post_size = value; else if( strcmp(code,"STATS") == 0 ) config.use_stats = value; else if( strcmp(code,"PRIM_STATS") == 0 ) config.use_prim_stats = value; else if( strcmp(code,"PRELOAD") == 0 ) preload_module(args,cmd->server); else ap_log_error(__FILE__,__LINE__,APLOG_WARNING,LOG_SUCCESS cmd->server,"Unknown ModNeko configuration command '%s'",code); free(code); return NULL; } #ifdef APACHE_2_X static int neko_init( apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s ) { mod_neko_do_init(); return OK; } #else static void neko_init(server_rec *s, pool *p) { mod_neko_do_init(); } #endif static command_rec neko_module_cmds[] = { # ifdef APACHE_2_X AP_INIT_RAW_ARGS( "ModNeko", mod_neko_config , NULL, RSRC_CONF, NULL ), # else { "ModNeko", mod_neko_config, NULL, RSRC_CONF, RAW_ARGS, NULL }, # endif { NULL } }; #ifdef APACHE_2_X static void neko_register_hooks( apr_pool_t *p ) { ap_hook_post_config( neko_init, NULL, NULL, APR_HOOK_MIDDLE ); ap_hook_handler( neko_handler, NULL, NULL, APR_HOOK_LAST ); }; module AP_MODULE_DECLARE_DATA neko_module = { STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, neko_module_cmds, neko_register_hooks }; #else /* APACHE 1.3 */ static const handler_rec neko_handlers[] = { {"neko-handler", neko_handler}, {NULL} }; module MODULE_VAR_EXPORT neko_module = { STANDARD_MODULE_STUFF, neko_init, NULL, NULL, NULL, NULL, neko_module_cmds, neko_handlers, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #endif /* ************************************************************************ */ neko-2.0.0/libs/mod_neko/mod_neko2.vcproj0000644000175000017500000001221212112157473021000 0ustar ncannassencannasse neko-2.0.0/libs/mod_neko/mod_neko.vcproj0000644000175000017500000001172712112157473020730 0ustar ncannassencannasse neko-2.0.0/libs/mod_neko/mod_neko.vcxproj0000644000175000017500000001752012112157473021115 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ true Release\ Release\ false Release\ Release\ false Disabled ../../vm;..\include\apache;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_NEKO_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ../../bin/neko.lib;..\include\apache/ApacheCore.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/mod_neko.ndll true $(OutDir)mod_neko.pdb Windows $(OutDir)mod_neko.lib MachineX86 ../../vm;..\include\apache;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_NEKO_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../../bin/neko.lib;..\include\apache/ApacheCore.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/mod_neko.ndll %(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)mod_neko.lib MachineX86 ../../vm;..\include\apache;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_NEKO_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../../bin/neko.lib;..\include\apache/ApacheCore.lib;../include/msvcrt/extra.lib;ws2_32.lib;%(AdditionalDependencies) ../../bin/mod_neko.ndll MSVCRT;%(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)mod_neko.lib MachineX86 neko-2.0.0/libs/mod_neko/cgi.c0000644000175000017500000003560712112157473016621 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include "mod_neko.h" DEFINE_KIND(k_mod_neko); #ifndef NEKO_WINDOWS # define strcmpi strcasecmp #endif #ifdef APACHE_2_X # define ap_table_get apr_table_get # define ap_table_set apr_table_set # define ap_table_add apr_table_add # define ap_table_do apr_table_do # define REDIRECT HTTP_MOVED_TEMPORARILY #endif #define PARSE_HEADER(start,cursor) \ cursor = start; \ if( *cursor == '"' ) { \ start++; \ cursor++; \ while( *cursor != '"' && *cursor != 0 ) \ cursor++; \ } else { \ while( *cursor != 0 && *cursor != '\r' && *cursor != '\n' && *cursor != '\t' ) \ cursor++; \ } #define HEADERS_NOT_SENT(msg) \ if( c->headers_sent ) { \ buffer b = alloc_buffer("Cannot set "); \ buffer_append(b,msg); \ buffer_append(b," : Headers already sent"); \ bfailure(b); \ } /**

Mod_neko

Apache access when running inside mod_neko.

**/ /** get_cookies : void -> #list Return a cookie list as a (name,value) chained list **/ static value get_cookies() { const char *k = ap_table_get(CONTEXT()->r->headers_in,"Cookie"); char *start, *end; value p = val_null, tmp; if( k == NULL ) return p; while( (start = strchr(k,'=')) != NULL ) { start++; end = start; while( *end != 0 && *end != '\r' && *end != '\n' && *end != ';' ) end++; tmp = alloc_array(3); val_array_ptr(tmp)[0] = copy_string(k,(int)(start-k-1)); val_array_ptr(tmp)[1] = copy_string(start,(int)(end-start)); val_array_ptr(tmp)[2] = p; p = tmp; if( *end != ';' || end[1] != ' ' ) break; k = end + 2; } return p; } /** set_cookie : name:string -> val:string -> void Set a cookie **/ static value set_cookie( value name, value v ) { mcontext *c = CONTEXT(); buffer b; value str; val_check(name,string); val_check(v,string); HEADERS_NOT_SENT("Cookie"); b = alloc_buffer(NULL); val_buffer(b,name); buffer_append(b,"="); val_buffer(b,v); buffer_append(b,";"); str = buffer_to_string(b); ap_table_add(c->r->headers_out,"Set-Cookie",val_string(str)); return val_true; } /** get_host_name : void -> string Get the local host IP **/ static value get_host_name() { mcontext *c = CONTEXT(); return alloc_string( c->r->hostname ); } /** get_client_ip : void -> string Get the connected client IP **/ static value get_client_ip() { return alloc_string( inet_ntoa(REMOTE_ADDR(CONTEXT()->r->connection)) ); } /** get_uri : void -> string Get the original URI requested by the client (before any internal redirection) **/ static value get_uri() { request_rec *r = CONTEXT()->r; while( r->prev != NULL ) r = r->prev; return alloc_string( r->uri ); } /** redirect : string -> void Redirect the client to another page (Location header) **/ static value redirect( value s ) { mcontext *c = CONTEXT(); val_check(s,string); HEADERS_NOT_SENT("Redirection"); ap_table_set(c->r->headers_out,"Location",val_string(s)); c->r->status = REDIRECT; return val_true; } /** set_return_code : int -> void Set the HTTP return code **/ static value set_return_code( value i ) { mcontext *c = CONTEXT(); val_check(i,int); HEADERS_NOT_SENT("Return code"); c->r->status = val_int(i); return val_true; } /** set_header : name:string -> val:string -> void Set a HTTP header value **/ static value set_header( value s, value k ) { mcontext *c = CONTEXT(); val_check(s,string); val_check(k,string); HEADERS_NOT_SENT("Header"); if( strcmpi(val_string(s),"Content-Type") == 0 ) { c->content_type = alloc_string(val_string(k)); c->r->content_type = val_string(c->content_type); } else ap_table_set(c->r->headers_out,val_string(s),val_string(k)); return val_true; } /** get_client_header : name:string -> string? Get a HTTP header sent by the client **/ static value get_client_header( value s ) { mcontext *c = CONTEXT(); val_check(s,string); return alloc_string( ap_table_get(c->r->headers_in,val_string(s)) ); } static int store_table( void *r, const char *key, const char *val ) { value a; if( key == NULL || val == NULL ) return 1; a = alloc_array(2); a = alloc_array(3); val_array_ptr(a)[0] = alloc_string(key); val_array_ptr(a)[1] = alloc_string(val); val_array_ptr(a)[2] = *(value*)r; *((value*)r) = a; return 1; } /** get_client_headers : void -> string list Get all the HTTP client headers **/ static value get_client_headers() { value r = val_null; ap_table_do(store_table,&r,CONTEXT()->r->headers_in,NULL); return r; } /** get_params_string : void -> string Return the whole parameters string **/ static value get_params_string() { return alloc_string(CONTEXT()->r->args); } /** get_post_data : void -> string Return the whole unparsed POST string **/ static value get_post_data() { return CONTEXT()->post_data; } static char *memfind( char *mem, int mlen, const char *v ) { char *found; int len = (int)strlen(v); if( len == 0 ) return mem; while( (found = memchr(mem,*v,mlen)) != NULL ) { if( (int)(found - mem) + len > mlen ) break; if( memcmp(found,v,len) == 0 ) return found; mlen -= (int)(found - mem + 1); mem = found + 1; } return NULL; } #define BUFSIZE 1024 static void fill_buffer( mcontext *c, value buf, int *len ) { int pos = *len; while( pos < BUFSIZE ) { int k = ap_get_client_block(c->r,val_string(buf)+pos,BUFSIZE-pos); if( k == 0 ) break; pos += k; } *len = pos; } static value discard_body( mcontext *c ) { char buf[256]; while( ap_get_client_block(c->r,buf,256) > 0 ) { } neko_error(); } /** parse_multipart_data : onpart:function:2 -> ondata:function:3 -> void Incrementally parse the multipart data. call [onpart(name,filename)] for each part found and [ondata(buf,pos,len)] when some data is available **/ static value parse_multipart_data( value onpart, value ondata ) { value buf; int len = 0; mcontext *c = CONTEXT(); const char *ctype = ap_table_get(c->r->headers_in,"Content-Type"); value boundstr; val_check_function(onpart,2); val_check_function(ondata,3); buf = alloc_empty_string(BUFSIZE); if( !ctype || strstr(ctype,"multipart/form-data") == NULL ) return val_null; // extract boundary value { const char *boundary, *bend; if( (boundary = strstr(ctype,"boundary=")) == NULL ) neko_error(); boundary += 9; PARSE_HEADER(boundary,bend); len = (int)(bend - boundary); boundstr = alloc_empty_string(len+2); if( val_strlen(boundstr) > BUFSIZE / 2 ) neko_error(); val_string(boundstr)[0] = '-'; val_string(boundstr)[1] = '-'; memcpy(val_string(boundstr)+2,boundary,len); } len = 0; if( !ap_should_client_block(c->r) ) neko_error(); while( true ) { char *name, *end_name, *filename, *end_file_name, *data; int pos; // refill buffer // we assume here that the the whole multipart header can fit in the buffer fill_buffer(c,buf,&len); // is boundary at the beginning of buffer ? if( len < val_strlen(boundstr) || memcmp(val_string(buf),val_string(boundstr),val_strlen(boundstr)) != 0 ) return discard_body(c); name = memfind(val_string(buf),len,"Content-Disposition:"); if( name == NULL ) break; name = memfind(name,len - (int)(name - val_string(buf)),"name="); if( name == NULL ) return discard_body(c); name += 5; PARSE_HEADER(name,end_name); data = memfind(end_name,len - (int)(end_name - val_string(buf)),"\r\n\r\n"); if( data == NULL ) return discard_body(c); filename = memfind(name,(int)(data - name),"filename="); if( filename != NULL ) { filename += 9; PARSE_HEADER(filename,end_file_name); } data += 4; pos = (int)(data - val_string(buf)); // send part name val_call2(onpart,copy_string(name,(int)(end_name - name)),filename?copy_string(filename,(int)(end_file_name - filename)):val_null); // read data while( true ) { const char *boundary; // recall buffer memcpy(val_string(buf),val_string(buf)+pos,len - pos); len -= pos; pos = 0; fill_buffer(c,buf,&len); // lookup bounds boundary = memfind(val_string(buf),len,val_string(boundstr)); if( boundary == NULL ) { if( len == 0 ) return discard_body(c); // send as much buffer as possible to client if( len < BUFSIZE ) pos = len; else pos = len - val_strlen(boundstr) + 1; val_call3(ondata,buf,alloc_int(0),alloc_int(pos)); } else { // send remaining data pos = (int)(boundary - val_string(buf)); val_call3(ondata,buf,alloc_int(0),alloc_int(pos-2)); // recall memcpy(val_string(buf),val_string(buf)+pos,len - pos); len -= pos; break; } } } return val_null; } static value url_decode( const char *in, int len ) { int pin = 0; int pout = 0; value v = alloc_empty_string(len); char *out = (char*)val_string(v); while( len-- > 0 ) { char c = in[pin++]; if( c == '+' ) c = ' '; else if( c == '%' ) { int p1, p2; if( len < 2 ) break; p1 = in[pin++]; p2 = in[pin++]; len -= 2; if( p1 >= '0' && p1 <= '9' ) p1 -= '0'; else if( p1 >= 'a' && p1 <= 'f' ) p1 -= 'a' - 10; else if( p1 >= 'A' && p1 <= 'F' ) p1 -= 'A' - 10; else continue; if( p2 >= '0' && p2 <= '9' ) p2 -= '0'; else if( p2 >= 'a' && p2 <= 'f' ) p2 -= 'a' - 10; else if( p2 >= 'A' && p2 <= 'F' ) p2 -= 'A' - 10; else continue; c = (char)((unsigned char)((p1 << 4) + p2)); } out[pout++] = c; } out[pout] = 0; val_set_size(v,pout); return v; } static void parse_get( value *p, const char *args ) { char *aand, *aeq, *asep; value tmp; while( true ) { aand = strchr(args,'&'); if( aand == NULL ) { asep = strchr(args,';'); aand = asep; } else { asep = strchr(args,';'); if( asep != NULL && asep < aand ) aand = asep; } if( aand != NULL ) *aand = 0; aeq = strchr(args,'='); if( aeq != NULL ) { *aeq = 0; tmp = alloc_array(3); val_array_ptr(tmp)[0] = url_decode(args,(int)(aeq-args)); val_array_ptr(tmp)[1] = url_decode(aeq+1,(int)strlen(aeq+1)); val_array_ptr(tmp)[2] = *p; *p = tmp; *aeq = '='; } if( aand == NULL ) break; *aand = (aand == asep)?';':'&'; args = aand+1; } } /** get_params : void -> #list parse all GET and POST params and return them into a chained list **/ static value get_params() { mcontext *c = CONTEXT(); const char *args = c->r->args; value p = val_null; // PARSE "GET" PARAMS if( args != NULL ) parse_get(&p,args); // PARSE "POST" PARAMS if( c->post_data != NULL ) { const char *ctype = ap_table_get(c->r->headers_in,"Content-Type"); if( ctype == NULL || strstr(ctype,"urlencoded") != NULL ) parse_get(&p,val_string(c->post_data)); } return p; } /** cgi_get_cwd : void -> string Return current bytecode file working directory **/ static value cgi_get_cwd() { mcontext *c = CONTEXT(); char *s = strrchr(c->r->filename,'/'); value v; char old; if( s != NULL ) { old = s[1]; s[1] = 0; } v = alloc_string(c->r->filename); if( s != NULL ) s[1] = old; return v; } /** cgi_set_main : function:0? -> void Set or disable the main entry point function **/ static value cgi_set_main( value f ) { if( val_is_null(f) ) { CONTEXT()->main = NULL; return val_true; } val_check_function(f,0); CONTEXT()->main = f; return val_true; } /** cgi_flush : void -> void Flush the data written so it's immediatly sent to the client **/ static value cgi_flush() { ap_rflush(CONTEXT()->r); return val_null; } /** cgi_get_config : void -> object Return the current configuration **/ #define FSET(name,t) alloc_field(v,val_id(#name),alloc_##t(c-> name)) static value cgi_get_config() { value v = alloc_object(NULL); mconfig *c = mod_neko_get_config(); FSET(hits,int); FSET(use_jit,bool); FSET(use_stats,bool); FSET(use_prim_stats,bool); FSET(use_cache,bool); FSET(exceptions,int); FSET(gc_period,int); FSET(max_post_size,int); return v; } /** cgi_set_config : object -> void Set the current configuration **/ #define FGET(name,t) f = val_field(v,val_id(#name)); val_check(f,t); c. name = val_##t(f) static value cgi_set_config( value v ) { mconfig c; value f; val_check(v,object); FGET(hits,int); FGET(use_jit,bool); FGET(use_stats,bool); FGET(use_prim_stats,bool); FGET(use_cache,bool); FGET(exceptions,int); FGET(gc_period,int); FGET(max_post_size,int); mod_neko_set_config(&c); return val_null; } /** cgi_command : any -> any Perform a configuration-specific command :
  • stats : returns the statistics
  • cache : returns the current cache
**/ extern value cgi_command( value v ); /** get_http_method : void -> string Returns the http method (GET,POST...) used by the client **/ static value get_http_method() { return alloc_string(CONTEXT()->r->method); } /** log_message : string -> void Write the message into the apache log **/ static value log_message( value message ) { mcontext *c = CONTEXT(); val_check(message, string); #ifdef APACHE_2_X ap_log_rerror(__FILE__, __LINE__, APLOG_NOTICE, APR_SUCCESS, c->r, "[mod_neko] %s", val_string(message)); #else ap_log_rerror(__FILE__, __LINE__, APLOG_NOTICE, c->r, "[mod_neko] %s", val_string(message)); #endif return val_null; } DEFINE_PRIM(cgi_get_cwd,0); DEFINE_PRIM(cgi_set_main,1); DEFINE_PRIM(get_cookies,0); DEFINE_PRIM(set_cookie,2); DEFINE_PRIM(get_host_name,0); DEFINE_PRIM(get_client_ip,0); DEFINE_PRIM(get_uri,0); DEFINE_PRIM(redirect,1); DEFINE_PRIM(get_params,0); DEFINE_PRIM(get_params_string,0); DEFINE_PRIM(get_post_data,0); DEFINE_PRIM(set_header,2); DEFINE_PRIM(set_return_code,1); DEFINE_PRIM(get_client_header,1); DEFINE_PRIM(get_client_headers,0); DEFINE_PRIM(parse_multipart_data,2); DEFINE_PRIM(cgi_flush,0); DEFINE_PRIM(cgi_get_config,0); DEFINE_PRIM(cgi_set_config,1); DEFINE_PRIM(cgi_command,1); DEFINE_PRIM(get_http_method,0); DEFINE_PRIM(log_message,1); /* ************************************************************************ */ neko-2.0.0/libs/ui/0000755000175000017500000000000012112157473014522 5ustar ncannassencannasseneko-2.0.0/libs/ui/ui.c0000644000175000017500000001506612112157473015313 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #define HEADER_IMPORTS #include #include #if defined(NEKO_WINDOWS) # include # define CLASS_NAME "Neko_UI_wnd_class" # define WM_SYNC_CALL (WM_USER + 101) #elif defined(NEKO_MAC) # include # include # define UIEvent 0xFFFFAA00 # define eCall 0x0 enum { pFunc = 'func' }; #elif defined(NEKO_LINUX) # include # include # include # include #endif /**

UI

Core native User Interface support. This API uses native WIN32 API on Windows, Carbon API on OSX, and GTK2 on Linux.

**/ typedef struct { int init_done; #if defined(NEKO_WINDOWS) DWORD tid; HWND wnd; #elif defined(NEKO_MAC) pthread_t tid; #elif defined(NEKO_LINUX) pthread_t tid; pthread_mutex_t lock; #endif } ui_data; static ui_data data = { 0 }; #if defined(NEKO_WINDOWS) static LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { switch( msg ) { case WM_SYNC_CALL: { value *r = (value*)lparam; value f = *r; free_root(r); // There are some GC issues here when having a lot of threads // It seems that somehow the function is not called, it might // also trigger some crashes. val_call0(f); return 0; }} return DefWindowProc(hwnd,msg,wparam,lparam); } #elif defined(NEKO_MAC) static OSStatus nothing() { return 0; } static OSStatus handleEvents( EventHandlerCallRef ref, EventRef e, void *data ) { switch( GetEventKind(e) ) { case eCall: { value *r; value f; GetEventParameter(e,pFunc,typeVoidPtr,0,sizeof(void*),0,&r); f = *r; free_root(r); val_call0(f); break; }} return 0; } #elif defined(NEKO_LINUX) static gint onSyncCall( gpointer data ) { value *r = (value*)data; value f = *r; free_root(r); val_call0(f); return FALSE; } #endif DEFINE_ENTRY_POINT(ui_main); void ui_main() { if( data.init_done ) return; data.init_done = 1; # if defined(NEKO_WINDOWS) { WNDCLASSEX wcl; HINSTANCE hinst = GetModuleHandle(NULL); memset(&wcl,0,sizeof(wcl)); wcl.cbSize = sizeof(WNDCLASSEX); wcl.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wcl.lpfnWndProc = WindowProc; wcl.cbClsExtra = 0; wcl.cbWndExtra = 0; wcl.hInstance = hinst; wcl.hIcon = NULL; wcl.hCursor = LoadCursor(NULL, IDC_ARROW); wcl.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); wcl.lpszMenuName = ""; wcl.lpszClassName = CLASS_NAME; wcl.hIconSm = 0; RegisterClassEx(&wcl); } data.tid = GetCurrentThreadId(); data.wnd = CreateWindow(CLASS_NAME,"",0,0,0,0,0,NULL,NULL,NULL,NULL); # elif defined(NEKO_MAC) MPCreateTask(nothing,NULL,0,0,0,0,0,NULL); // creates a MPTask that will enable Carbon MT data.tid = pthread_self(); EventTypeSpec ets = { UIEvent, eCall }; InstallEventHandler(GetApplicationEventTarget(),NewEventHandlerUPP(handleEvents),1,&ets,0,0); # elif defined(NEKO_LINUX) g_thread_init(NULL); gdk_threads_init(); gtk_init(NULL,NULL); setlocale(LC_NUMERIC,"POSIX"); // prevent broking atof() data.tid = pthread_self(); pthread_mutex_init(&data.lock,NULL); # endif } /** ui_is_main : void -> bool Tells if the current thread is the main loop thread or not. The main loop thread is the one in which the first "ui" library primitive has been loaded. **/ static value ui_is_main() { # ifdef NEKO_WINDOWS return alloc_bool(data.tid == GetCurrentThreadId()); # else return alloc_bool(pthread_equal(data.tid,pthread_self())); # endif } /** ui_loop : void -> void Starts the native UI event loop. This method can only be called from the main thread. **/ static value ui_loop() { if( !val_bool(ui_is_main()) ) neko_error(); # if defined(NEKO_WINDOWS) { MSG msg; while( GetMessage(&msg,NULL,0,0) ) { TranslateMessage(&msg); DispatchMessage(&msg); if( msg.message == WM_QUIT ) break; } } # elif defined(NEKO_MAC) RunApplicationEventLoop(); # else gtk_main(); # endif return val_null; } /** ui_stop_loop : void -> void Stop the native UI event loop. This method can only be called from the main thread. **/ static value ui_stop_loop() { if( !val_bool(ui_is_main()) ) neko_error(); # if defined(NEKO_WINDOWS) while( !PostMessage(data.wnd,WM_QUIT,0,0) ) Sleep(100); # elif defined(NEKO_MAC) QuitApplicationEventLoop(); # else gtk_main_quit(); # endif return val_null; } /** ui_sync : callb:(void -> void) -> void Queue a method call [callb] to be executed by the main thread while running the UI event loop. This can be used to perform UI updates in the UI thread using results processed by another thread. **/ static value ui_sync( value f ) { value *r; val_check_function(f,0); r = alloc_root(1); *r = f; # if defined(NEKO_WINDOWS) while( !PostMessage(data.wnd,WM_SYNC_CALL,0,(LPARAM)r) ) Sleep(100); # elif defined(NEKO_MAC) EventRef e; CreateEvent(NULL,UIEvent,eCall,GetCurrentEventTime(),kEventAttributeUserEvent,&e); SetEventParameter(e,pFunc,typeVoidPtr,sizeof(void*),&r); PostEventToQueue(GetMainEventQueue(),e,kEventPriorityStandard); ReleaseEvent(e); # elif defined(NEKO_LINUX) // the lock should not be needed because GTK is MT-safe // however the GTK lock mechanism is a LOT slower than // using a pthread_mutex pthread_mutex_lock(&data.lock); gtk_timeout_add( 0, onSyncCall, (gpointer)r ); pthread_mutex_unlock(&data.lock); # endif return val_null; } DEFINE_PRIM(ui_loop,0); DEFINE_PRIM(ui_stop_loop,0); DEFINE_PRIM(ui_is_main,0); DEFINE_PRIM(ui_sync,1); /* ************************************************************************ */ neko-2.0.0/libs/ui/ui.vcxproj0000644000175000017500000001746212112157473016566 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ true Release\ Release\ false Release\ Release\ false Disabled ../../vm;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;UI_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug Level3 EditAndContinue ../../bin/neko.lib;../std/Debug/std.lib;%(AdditionalDependencies) ../../bin/ui.ndll true $(OutDir)ui.pdb Windows $(OutDir)ui.lib MachineX86 ../../vm;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;UI_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../../bin/neko.lib;../std/Release/std.lib;%(AdditionalDependencies) ../../bin/ui.ndll false %(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)ui.lib MachineX86 ../../vm;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;UI_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../../bin/neko.lib;../std/Release/std.lib;../include/msvcrt/extra.lib;%(AdditionalDependencies) ../../bin/ui.ndll false MSVCRT;%(IgnoreSpecificDefaultLibraries) true Windows true true $(OutDir)ui.lib MachineX86 {32aa6f03-939e-469b-8e85-a0cce55464ad} neko-2.0.0/libs/ui/ui.vcproj0000644000175000017500000001146512112157473016373 0ustar ncannassencannasse neko-2.0.0/libs/libs.sln0000644000175000017500000001735512112157473015567 0ustar ncannassencannasseMicrosoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_neko", "mod_neko\mod_neko.vcproj", "{BC400EC9-8F65-4E34-85DC-687D5272B049}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql", "mysql\mysql.vcproj", "{159607BD-674F-44DA-9290-CF923B2703CC}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regexp", "regexp\regexp.vcproj", "{145AAFB0-C897-4F74-A330-314F5727C5D4}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "std", "std\std.vcproj", "{32AA6F03-939E-469B-8E85-A0CCE55464AD}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcproj", "{55ECFCE6-00FB-44F0-B477-E8507423930D}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_neko2", "mod_neko\mod_neko2.vcproj", "{311DC43B-AABB-4796-883C-F2482165F8C4}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqlite", "sqlite\sqlite.vcproj", "{159607BD-674F-44DA-9290-CF923B2703CC}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql5", "mysql\mysql5.vcproj", "{159607BD-674F-44DA-9290-CF923B2703CC}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ui", "ui\ui.vcproj", "{9A36DC8A-8070-4F5D-A401-6889DD652288}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_tora", "mod_tora\mod_tora.vcproj", "{BC400EC9-8F65-4E34-85DC-687D5272B049}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_tora2", "mod_tora\mod_tora2.vcproj", "{311DC43B-AABB-4796-883C-F2482165F8C4}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release ReleaseCrt60 = ReleaseCrt60 EndGlobalSection GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {BC400EC9-8F65-4E34-85DC-687D5272B049}.Debug.ActiveCfg = Debug|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.Debug.Build.0 = Debug|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.Release.ActiveCfg = Release|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.Release.Build.0 = Release|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Debug.ActiveCfg = Debug|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Debug.Build.0 = Debug|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Release.ActiveCfg = Release|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Release.Build.0 = Release|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.Debug.ActiveCfg = Debug|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.Debug.Build.0 = Debug|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.Release.ActiveCfg = Release|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.Release.Build.0 = Release|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {145AAFB0-C897-4F74-A330-314F5727C5D4}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.Debug.ActiveCfg = Debug|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.Debug.Build.0 = Debug|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.Release.ActiveCfg = Release|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.Release.Build.0 = Release|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {32AA6F03-939E-469B-8E85-A0CCE55464AD}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.Debug.ActiveCfg = Debug|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.Debug.Build.0 = Debug|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.Release.ActiveCfg = Release|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.Release.Build.0 = Release|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {55ECFCE6-00FB-44F0-B477-E8507423930D}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Debug.ActiveCfg = Debug|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Debug.Build.0 = Debug|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Release.ActiveCfg = Release|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Release.Build.0 = Release|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Debug.ActiveCfg = Debug|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Debug.Build.0 = Debug|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Release.ActiveCfg = Release|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Release.Build.0 = Release|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Debug.ActiveCfg = Debug|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Debug.Build.0 = Debug|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Release.ActiveCfg = Release|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.Release.Build.0 = Release|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {159607BD-674F-44DA-9290-CF923B2703CC}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.Debug.ActiveCfg = Debug|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.Debug.Build.0 = Debug|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.Release.ActiveCfg = Release|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.Release.Build.0 = Release|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {9A36DC8A-8070-4F5D-A401-6889DD652288}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.Debug.ActiveCfg = Debug|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.Debug.Build.0 = Debug|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.Release.ActiveCfg = Release|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.Release.Build.0 = Release|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {BC400EC9-8F65-4E34-85DC-687D5272B049}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Debug.ActiveCfg = Debug|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Debug.Build.0 = Debug|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Release.ActiveCfg = Release|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.Release.Build.0 = Release|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.ReleaseCrt60.ActiveCfg = ReleaseCrt60|Win32 {311DC43B-AABB-4796-883C-F2482165F8C4}.ReleaseCrt60.Build.0 = ReleaseCrt60|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal neko-2.0.0/Makefile0000644000175000017500000000751712112157473014626 0ustar ncannassencannasse# This Makefile works by default for Linux # You can active other OS support by compiling with the following options # # For OSX # make os=osx # # For MingW/MSys # make os=mingw # ## CONFIG INSTALL_PREFIX = /usr/local CFLAGS = -Wall -O3 -fPIC -fomit-frame-pointer -I vm -D_GNU_SOURCE -I libs/common EXTFLAGS = -pthread MAKESO = $(CC) -shared -Wl,-Bsymbolic LIBNEKO_NAME = libneko.so LIBNEKO_LIBS = -ldl -lgc -lm NEKOVM_FLAGS = -Lbin -lneko STD_NDLL_FLAGS = ${NEKOVM_FLAGS} -lrt INSTALL_FLAGS = NEKO_EXEC = LD_LIBRARY_PATH=../bin:${LD_LIBRARY_PATH} NEKOPATH=../boot:../bin ../bin/neko # For profiling VM # # CFLAGS += -DNEKO_PROF # For lower memory usage (takes more CPU !) # # CFLAGS += -DLOW_MEM ## MINGW SPECIFIC ifeq (${os}, mingw) CFLAGS = -g -Wall -O3 -momit-leaf-frame-pointer -I vm -I /usr/local/include -I libs/common EXTFLAGS = MAKESO = $(CC) -O -shared LIBNEKO_NAME = neko.dll LIBNEKO_LIBS = -Lbin -lgc STD_NDLL_FLAGS = ${NEKOVM_FLAGS} -lws2_32 endif ### OSX SPECIFIC ifeq (${os}, osx) export MACOSX_DEPLOYMENT_TARGET=10.4 EXTFLAGS = MAKESO = ${CC} LIBNEKO_NAME = libneko.dylib LIBNEKO_INSTALL = -install_name @executable_path/${LIBNEKO_NAME} LIBNEKO_LIBS = -ldl /opt/local/lib/libgc.a -lm -dynamiclib -single_module ${LIBNEKO_INSTALL} NEKOVM_FLAGS = -L${CURDIR}/bin -lneko STD_NDLL_FLAGS = -bundle -undefined dynamic_lookup ${NEKOVM_FLAGS} CFLAGS += -L/usr/local/lib -L/opt/local/lib -I/opt/local/include INSTALL_FLAGS = -static endif ### MAKE VM_OBJECTS = vm/stats.o vm/main.o STD_OBJECTS = libs/std/buffer.o libs/std/date.o libs/std/file.o libs/std/init.o libs/std/int32.o libs/std/math.o libs/std/string.o libs/std/random.o libs/std/serialize.o libs/std/socket.o libs/std/sys.o libs/std/xml.o libs/std/module.o libs/common/sha1.o libs/std/md5.o libs/std/utf8.o libs/std/memory.o libs/std/misc.o libs/std/thread.o libs/std/process.o LIBNEKO_OBJECTS = vm/alloc.o vm/builtins.o vm/callback.o vm/interp.o vm/load.o vm/objtable.o vm/others.o vm/hash.o vm/module.o vm/jit_x86.o vm/threads.o all: createbin libneko neko std compiler libs createbin: -mkdir bin 2>/dev/null libneko: bin/${LIBNEKO_NAME} libs: (cd src; ${NEKO_EXEC} nekoc tools/install.neko) (cd src; ${NEKO_EXEC} tools/install ${INSTALL_FLAGS}) tools: (cd src; ${NEKO_EXEC} nekoc tools/install.neko) (cd src; ${NEKO_EXEC} tools/install -nolibs) doc: (cd src; ${NEKO_EXEC} nekoc tools/makedoc.neko) (cd src; ${NEKO_EXEC} tools/makedoc) test: (cd src; ${NEKO_EXEC} nekoc tools/test.neko) (cd src; ${NEKO_EXEC} tools/test) neko: bin/neko std: bin/std.ndll compiler: (cd src; ${NEKO_EXEC} nekoml -nostd neko/Main.nml nekoml/Main.nml) (cd src; ${NEKO_EXEC} nekoc -link ../boot/nekoc.n neko/Main) (cd src; ${NEKO_EXEC} nekoc -link ../boot/nekoml.n nekoml/Main) bin/${LIBNEKO_NAME}: ${LIBNEKO_OBJECTS} ${MAKESO} ${EXTFLAGS} -o $@ ${LIBNEKO_OBJECTS} ${LIBNEKO_LIBS} bin/neko: $(VM_OBJECTS) ${CC} ${CFLAGS} ${EXTFLAGS} -o $@ ${VM_OBJECTS} ${NEKOVM_FLAGS} strip bin/neko bin/std.ndll: ${STD_OBJECTS} ${MAKESO} -o $@ ${STD_OBJECTS} ${STD_NDLL_FLAGS} clean: rm -rf bin/${LIBNEKO_NAME} ${LIBNEKO_OBJECTS} ${VM_OBJECTS} rm -rf bin/neko bin/nekoc bin/nekoml bin/nekotools rm -rf bin/std bin/*.ndll bin/*.n libs/*/*.o rm -rf src/*.n src/neko/*.n src/nekoml/*.n src/tools/*.n rm -rf bin/mtypes bin/tools install: cp bin/${LIBNEKO_NAME} ${INSTALL_PREFIX}/lib cp bin/neko bin/nekoc bin/nekotools bin/nekoml bin/nekoml.std ${INSTALL_PREFIX}/bin -mkdir ${INSTALL_PREFIX}/lib/neko cp bin/*.ndll ${INSTALL_PREFIX}/lib/neko -mkdir ${INSTALL_PREFIX}/include cp vm/neko*.h ${INSTALL_PREFIX}/include uninstall: rm -rf ${INSTALL_PREFIX}/lib/${LIBNEKO_NAME} rm -rf ${INSTALL_PREFIX}/bin/neko ${INSTALL_PREFIX}/bin/nekoc ${INSTALL_PREFIX}/bin/nekotools rm -rf ${INSTALL_PREFIX}/lib/neko .SUFFIXES : .c .o .c.o : ${CC} ${CFLAGS} ${EXTFLAGS} -o $@ -c $< .PHONY: all libneko libs neko std compiler clean doc test neko-2.0.0/LICENSE0000644000175000017500000000204612112157473014163 0ustar ncannassencannasseCopyright (C)2005-2013 Haxe Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.neko-2.0.0/src/0000755000175000017500000000000012112157473013743 5ustar ncannassencannasseneko-2.0.0/src/neko.vcxproj0000644000175000017500000001305612112157473016321 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {4C13C941-4D12-4904-BDA2-A2DF8AF4F31A} MakeFileProj Makefile Makefile Makefile <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ make neko make clean neko make clean Release\ Release\ make neko make clean neko make clean $(Configuration)\ $(Configuration)\ make neko make clean neko make clean neko-2.0.0/src/core/0000755000175000017500000000000012112157473014673 5ustar ncannassencannasseneko-2.0.0/src/core/Hashtbl.nml0000644000175000017500000000352412112157473016774 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type ('a,'b) t; function hash(x:'a) : int { neko("$hkey(x)") } function create() : ('a,'b) t { neko("$hnew(0)") } function length(h : ('a,'b) t) : int { neko("$hcount(h)") } function find(h : ('a,'b) t,k : 'a) : 'b { var v = neko("$hget(h,k,@Core.@compare)"); if neko("v == null") then throw Not_found; v } function exists(h : ('a,'b) t,k : 'a) : bool { neko("$hmem(h,k,@Core.@compare)"); } function add(h : ('a,'b) t, k : 'a, v : 'b) : void { neko("$hadd(h,k,v)"); } function remove(h : ('a,'b) t,k : 'a) : void { neko("$hremove(h,k,@Core.@compare)"); } function replace(h : ('a,'b) t,k : 'a,v : 'b) : void { neko("$hset(h,k,v,@Core.@compare)"); } function iter(f : 'a -> 'b -> void,h : ('a,'b) t) : void { neko("$hiter(h,f)"); } neko-2.0.0/src/core/IO.nml0000644000175000017500000001745012112157473015721 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type file type input { mutable in_read : void -> char; mutable in_input : string -> int -> int -> int; mutable in_close : void -> void; } type output { mutable out_write : char -> void; mutable out_output : string -> int -> int -> int; mutable out_close : void -> void; mutable out_flush : void -> void; } exception Overflow : string; exception Eof; exception Closed; exception Blocked; /* ---------------------------- RAW FILE API ------------------------------- */ neko(" @load = function(name,nargs) { return $loader.loadprim('std@'+name,nargs); } "); var file_open : string -> string -> file = neko("@load('file_open',2)"); var file_contents : string -> string = neko("@load('file_contents',1)"); var file_close : file -> void = neko("@load('file_close',1)"); var file_read : file -> string -> int -> int -> int = neko("@load('file_read',4)"); var file_read_char : file -> char = neko("@load('file_read_char',1)"); var file_write : file -> string -> int -> int -> int = neko("@load('file_write',4)"); var file_write_char : file -> char -> void = neko("@load('file_write_char',2)"); var file_flush : file -> void = neko("@load('file_flush',1)"); function file_input(f) { { in_read = function() { try file_read_char(f) catch { _ -> throw Eof } }; in_input = function(s,p,l) { try file_read f s p l catch { _ -> throw Eof } }; in_close = function() { file_close(f) }; } } function read_file(path,bin) { var f = file_open(path,if bin then "rb" else "r"); file_input f } function read_string(str) { var p = &0; var len = String.length str; { in_read = function() { if *p == len then throw Eof; var c = String.get str (*p); p := *p + 1; c }; in_input = function(s,pp,l) { if *p == len then throw Eof; var l = min l (len - *p); String.blit s pp str (*p) l; p := *p + l; l }; in_close = function() { } } } function file_output(f) { { out_write = file_write_char f; out_output = file_write f; out_close = function() { file_close(f) }; out_flush = function() { file_flush(f) }; } } function write_file(path,bin) { var f = file_open(path,if bin then "wb" else "w"); file_output f } function write_string() { var b = Buffer.create(); var o = { out_write = Buffer.add_char b; out_output = function(s,pp,l) { Buffer.add_sub b s pp l; l }; out_close = function() { }; out_flush = function() { }; }; (o , function() { Buffer.string b }) } var file_stdin : file = neko("@load('file_stdin',0)()"); var file_stdout : file = neko("@load('file_stdout',0)()"); var file_stderr : file = neko("@load('file_stderr',0)()"); var stdin : input = file_input file_stdin; var stdout : output = file_output file_stdout; var stderr : output = file_output file_stderr; /* ---------------------------- INPUT API ------------------------------- */ function create_in(read,input,close) { { in_read = read; in_input = input; in_close = close; } } function read_char(i) { i.in_read() } function read_byte(i) { ord i.in_read() } function input(i,s,p,n) { var len = String.length s; if p < 0 || n < 0 || p > len || p + n > len then invalid_arg(); i.in_input s p n } function read(i,n) { if n < 0 then invalid_arg(); if n == 0 then "" else { var s = String.create n; var p = &0; var len = &n; while *len > 0 { var n = i.in_input s (*p) (*len); if n == 0 then throw Blocked; p := *p + n; len := *len - n; }; s } } function read_buf(i,n) { if n < 0 then invalid_arg(); if n == 0 then "" else { var s = String.create n; var p = &0; var len = &n; try { while *len > 0 { var n = i.in_input s (*p) (*len); if n == 0 then throw (if *p == 0 then Blocked else Eof); p := *p + n; len := *len - n; }; s } catch { Eof -> if *p == 0 then throw Eof; String.sub s 0 (*p) } } } function read_all(i : input) : string { var b = Buffer.create(); var maxlen = 4096; try { while true { Buffer.add b (read_buf i maxlen); } magic(); } catch { Eof -> Buffer.string b } } function read_line(i : input) : string { var buf = Buffer.create(); try { while true { var ch = i.in_read(); if ch == '\n' then throw Exit; Buffer.add_char buf ch; } assert() } catch { Exit -> Buffer.string buf } } function read_i32(i) : int { var ch1 = read_byte i; var ch2 = read_byte i; var ch3 = read_byte i; var ch4 = read_byte i; ch1 or (ch2 << 8) or (ch3 << 16) or (ch4 << 24) } function read_ui16(i) { var ch1 = read_byte i; var ch2 = read_byte i; ch1 or (ch2 << 8) } function read_ui24(i) { var ch1 = read_byte i; var ch2 = read_byte i; var ch3 = read_byte i; ch1 or (ch2 << 8) or (ch3 << 16) } function read_i16(i) { var ch1 = read_byte i; var ch2 = read_byte i; var n = ch1 or (ch2 << 8); if ch2 and 128 != 0 then n - 65536 else n } function close_in(i) { i.in_close(); i.in_read := function() { throw Closed }; i.in_input := function(s,p,l) { throw Closed }; i.in_close := function() { throw Closed }; } /* ---------------------------- OUTPUT API ------------------------------- */ function create_out(write,output,flush,close) { { out_write = write; out_output = output; out_flush = flush; out_close = close; } } function write_char(o : output, x : char) : void { o.out_write x } function write_byte(o : output, x : int) : void { o.out_write (chr (x and 255)) } function write_i8(o : output, x : int) : void { if x < 127 || x > 128 then invalid_arg(); write_byte o (x and 0xFF) } function output(o,s,p,n) { var len = String.length s; if p < 0 || n < 0 || p > len || p + n > len then invalid_arg(); o.out_output s p n } function write(o : output,x : string) : void { var p = &0; var len = &(String.length x); while *len > 0 { var n = o.out_output x (*p) (*len); if n == 0 then throw Blocked; p := *p + n; len := *len - n; } } function write_i32(o : output, x : int) : void { write_byte o x; write_byte o (x >> 8); write_byte o (x >> 16); write_byte o (x >>> 24) } function write_ui16(o : output, x : int) : void { if x < 0 || x > 0xFFFF then invalid_arg(); write_byte o x; write_byte o (x >> 8) } function write_i16(o : output, x : int) : void { if x < -0x7FFF || x > 0x7FFF then invalid_arg(); if x < 0 then write_ui16 o (65536 + x) else write_ui16 o x } function write_ui24(o : output, x : int) : void { if x < 0 || x > 0xFFFFFF then invalid_arg(); write_byte o x; write_byte o (x >> 8); write_byte o (x >> 16); } function flush(o) { o.out_flush(); } function close_out(o) { o.out_close(); o.out_flush := function() { throw Closed }; o.out_write := function(_) { throw Closed }; o.out_output := function(_,_,_) { throw Closed }; o.out_close := function() { throw Closed }; } function printf(o : output, fmt : 'a format, p : 'a ) : void { write o (sprintf fmt p) } neko-2.0.0/src/core/Reflect.nml0000644000175000017500000000775412112157473017004 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type neko_object; type neko_abstract; type neko_function; type neko_array; type neko_loader; type module; type value { VNull; VInt : int; VFloat : float; VBool : bool; VString : string; VObject : neko_object; VAbstract : neko_abstract; VFunction : neko_function; VArray : neko_array; } neko(" @module_read = $loader.loadprim('std@module_read',2); @module_name = $loader.loadprim('std@module_name',1); @module_exports = $loader.loadprim('std@module_exports',1); @module_loader = $loader.loadprim('std@module_loader',1); @module_exec = $loader.loadprim('std@module_exec',1); @module_nglobals = $loader.loadprim('std@module_nglobals',1); @module_global_get = $loader.loadprim('std@module_global_get',2); @module_global_set = $loader.loadprim('std@module_global_set',3); @module_code_size = $loader.loadprim('std@module_code_size',1); @module_read_path = $loader.loadprim('std@module_read_path',3); "); function value( n : neko_value ) : value { var i = function() { invalid_arg() }; neko(" switch $typeof(n) { $tnull => VNull $tint => VInt(n) $tfloat => VFloat(n) $tbool => VBool(n) $tstring => VString(n) $tobject => VObject(n) $tabstract => VAbstract(n) $tfunction => VFunction(n) $tarray => VArray(n) default => i() } "); } function neko_value(v) : neko_value { match v { | VNull -> neko("null") | VInt i -> magic i | VFloat f -> magic f | VBool b -> magic b | VString s -> magic s | VObject o -> magic o | VAbstract a -> magic a | VFunction f -> magic f | VArray a -> magic a } } function asize(a : neko_array) : int { neko("$asize(a)"); } function aget(a : neko_array, p : int) : value { value(neko("a[p]")); } function aset(a : neko_array, p : int, v : value) : void { var v = neko_value v; neko("a[p] = v"); } function module_read( fread : string -> int -> int -> int ) : module { neko("@module_read(fread,$loader)"); } var __list_dep = List.map function loader_path() : string list { neko("@List.@make($loader.path)"); } function module_read_path( path : string array, name : string, loader : neko_loader ) : module { neko(" var h; var n = path[2]; path = path[0]; while( n > 0 ) { n -= 1; h = $array(path[n],h); } @module_read_path(h,name,loader); "); } function module_name( m : module ) : string { neko("@module_name(m)"); } function module_execute( m : module ) { value neko("@module_exec(m)"); } function module_exports( m : module ) { value neko("@module_exports(m)") } function module_loader( m : module ) { value neko("@module_loader(m)") } function module_globals_count( m : module ) : int { neko("@module_nglobals(m)"); } function module_get_global( m : module, n : int ) { value neko("@module_global_get(m,n)"); } function module_set_global( m : module, n : int, v : value ) : void { var v = neko_value v; neko("@module_global_set(m,n,v)"); } function module_code_size( m : module ) : int { neko("@module_code_size(m)"); } neko-2.0.0/src/core/Zip.nml0000644000175000017500000000642312112157473016152 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type in; type out; type flush { NO; SYNC; FULL; FINISH; BLOCK; } type result { done : bool; read : int; write : int; } function init() { neko(" @set_flush_mode = $loader.loadprim('zlib@set_flush_mode',2); @inflate_init = $loader.loadprim('zlib@inflate_init',1); @deflate_buffer = $loader.loadprim('zlib@deflate_buffer',5); @inflate_buffer = $loader.loadprim('zlib@inflate_buffer',5); @deflate_init = $loader.loadprim('zlib@deflate_init',1); @deflate_bound = $loader.loadprim('zlib@deflate_bound',2); @deflate_end = $loader.loadprim('zlib@deflate_end',1); @inflate_end = $loader.loadprim('zlib@inflate_end',1); "); } function __result(x) { { done = neko "x.done"; read = neko "x.read"; write = neko "x.write" } } function output(v:int) : out { neko("@deflate_init")(v); } function output_bound(o:out,size:int) : int { neko("@deflate_bound")(o,size); } function output_end(o:out) : void { neko("@deflate_end")(o); } function output_buffer(o:out,in:string,ipos:int,out:string,opos:int) { __result(neko "@deflate_buffer(o,in,ipos,out,opos)"); } function input( n : int option ) : in { neko("@inflate_init")(match n { None -> neko "null" | Some i -> i }) } function input_buffer(i:in,in:string,ipos:int,out:string,opos:int) { __result(neko "@inflate_buffer(i,in,ipos,out,opos)"); } function input_end(i:in) : void { neko("@inflate_end")(i); } function output_set_flush_mode(o:out,f:flush) : void { neko("@set_flush_mode")(o,string f); } function input_set_flush_mode(i:in,f:flush) : void { neko("@set_flush_mode")(i,string f); } function compress(str,level) { var c = output level; output_set_flush_mode c FINISH; var out = String.create (output_bound c (String.length str)); var r = output_buffer c str 0 out 0; output_end c; if !r.done || r.read != String.length str then throw Error("Compression failed"); String.sub out 0 r.write; } function uncompress(str) { var u = input None; var tmp = String.create (1 << 16); // 64K var b = Buffer.create(); input_set_flush_mode u SYNC; function rec loop(pos) { var r = input_buffer u str pos tmp 0; Buffer.add_sub b tmp 0 r.write; if !r.done then loop(pos + r.read); } loop(0); input_end u; Buffer.string b; } neko-2.0.0/src/core/Regexp.nml0000644000175000017500000000356012112157473016641 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type t neko(" regexp_matched_pos = $loader.loadprim('regexp@regexp_matched_pos',2); "); var build : string -> t = neko("$loader.loadprim('regexp@regexp_new',1)"); var find : t -> string -> int -> int -> bool = neko("$loader.loadprim('regexp@regexp_match',4)"); var matched : t -> int -> string = neko("$loader.loadprim('regexp@regexp_matched',2)"); function matched_pos( r : t, n : int ) : (int , int) { neko(" var s = regexp_matched_pos(r,n); $array(s.pos,s.len); "); } function split( r, str ) { function rec loop(pos,len) { if !find r str pos len then [String.sub str pos len] else { var ppos, plen = matched_pos r 0; var tot = ppos - pos + plen; String.sub str pos (ppos - pos) :: loop (pos + tot) (len - tot) } } loop 0 String.length(str) }neko-2.0.0/src/core/Math.nml0000644000175000017500000000442512112157473016301 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ function _load(name,nargs) : 'a { neko("return $loader.loadprim('std@math_'+name,nargs)"); } function _lload(name,nargs) : 'a { neko("return try $loader.loadprim('std@math_'+name,nargs) catch e function(_) $throw(e)"); } var atan2 : float -> float -> float = _load("atan2",2); var pow : float -> float -> float = _load("pow",2); var abs : float -> float = _load("abs",1); var iabs : int -> int = _load("abs",1); var ceil : float -> int = _load("ceil",1); var floor : float -> int = _load("floor",1); var round : float -> int = _load("round",1); var fceil : float -> float = _lload("fceil",1); var ffloor : float -> float = _lload("ffloor",1); var fround : float -> float = _lload("fround",1); var fint : float -> int = _lload("int",1); var pi : float = neko "$loader.loadprim('std@math_pi',0)()"; var sqrt : float -> float = _load("sqrt",1); var atan : float -> float = _load("atan",1); var cos : float -> float = _load("cos",1); var sin : float -> float = _load("sin",1); var tan : float -> float = _load("tan",1); var log : float -> float = _load("log",1); var exp : float -> float = _load("exp",1); var acos : float -> float = _load("acos",1); var asin : float -> float = _load("asin",1); neko-2.0.0/src/core/Xml.nml0000644000175000017500000000742112112157473016147 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type t { Node : (string, (string, string) list , t list); PCData : string; CData : string; Document : t list; } exception Error : string; var __list = List.hd; neko(" @parser = function() { return { stack => null, doc => null, cdata => function(s) { this.doc = $array(CData(s),this.doc); }, pcdata => function(s) { this.doc = $array(PCData(s),this.doc); }, xml => function(name,att) { var fields = $objfields(att); var nf = $asize(fields); var fl = null; var i = 0; while( i < nf ) { var f = fields[i]; fl = $array($array($field(f),$objget(att,f)),fl); i = i + 1; } this.stack = $array(name,fl,this.doc,this.stack); this.doc = null; }, done => function() { var s = this.stack; var d = this.doc; this.doc = $array(Node(s[0],@List.@rmake(s[1]),@List.@rmake(d)),s[2]); this.stack = s[3]; } } } @parse = $loader.loadprim('std@parse_xml',2); "); function parse( s : string ) : t { neko(" var p = @parser(); try { @parse(s,p); return Document(@List.@rmake(p.doc)); } catch e { if( $typeof(e) == $tstring ) $rethrow(Error(e)); $rethrow(e); } "); } function is_node(x) { match x { | Node _ -> true | _ -> false } } function is_pcdata(x) { match x { | PCData _ -> true | _ -> false } } function is_cdata(x) { match x { | CData _ -> true | _ -> false } } function firstNode(x) { match x { | Node (_,_,l) | Document l -> List.find is_node l | CData _ | PCData _ -> invalid_arg() } } function nodes(x) { match x { | Node (_,_,l) | Document l -> List.filter is_node l | CData _ | PCData _ -> invalid_arg() } } function node_name(x) { match x { | Node (name,_,_) -> name | _ -> invalid_arg() } } function node_text(x) { match x { | Node (_,_,childs) -> var b = Buffer.create(); List.iter (function(x) { match x { | CData t | PCData t -> Buffer.add b t | _ -> invalid_arg() } }) childs; Buffer.string b | _ -> invalid_arg() } } function attrib(x,n) { var n = String.lowercase n; match x { | Node (_,att,_) -> snd (List.find (function((n2,_)) { String.lowercase n2 == n }) att) | _ -> invalid_arg() } } function rec write(ch,x) { match x { | Document l -> List.iter write(ch) l | CData c -> IO.write ch ""; | PCData c -> IO.write ch c; | Node (name,att,childs) -> IO.printf ch "<%s%s" (name,String.concat "" (List.map (function((a,v)) { " "+a+"=\""+String.escape v+"\"" }) att)); match childs { | [] -> IO.write ch "/>" | l -> IO.write ch ">"; List.iter write(ch) l; IO.printf ch "" name } } } function to_string(x) { var ch , str = IO.write_string(); write ch x; str() } neko-2.0.0/src/core/String.nml0000644000175000017500000001167012112157473016656 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ neko(" @string_split = $loader.loadprim('std@string_split',2); "); function make(size : int, c : char) : string { neko(" var s = $smake(size); var i = 0; while( i < size ) { $sset(s,i,c); i = i + 1; } s "); } var create : int -> string = neko("$smake"); var length : string -> int = neko("$ssize"); function get(s : string,n : int) : char { var c = neko("$sget(s,n)"); if c == neko("null") then invalid_arg(); c } function set(s : string, n : int, c : char) : void { if neko("$sset(s,n,c) == null") then invalid_arg(); } function blit(dst : string, p : int, src : string, p2 : int, l : int ) : void { if neko("try { $sblit(dst,p,src,p2,l); false; } catch e true") then invalid_arg(); } function sub(s : string, p : int, l : int ) : string { var s = neko("$ssub(s,p,l)"); if s == neko("null") then invalid_arg(); s } function find( s : string, p : int, pat : string ) : int { var pos = neko "$sfind(s,p,pat)"; if pos == neko "null" then throw Not_found; pos } var list_depency = List.iter function split( s : string, sub : string ) : string list { neko(" var l = @string_split(s,sub); return @List.@make(l); "); } function concat( sep : string, s : string list ) : string { var b = Buffer.create(); function rec loop(l) { match l { | [] -> () | [x] -> Buffer.add b x | x :: l -> Buffer.add b x; Buffer.add b sep; loop l } }; loop(s); Buffer.string b } function is_printable(c) { c >= '\032' && c <= '\126' } function escape_char(c) { match c { | '\n' -> "\\n" | '\t' -> "\\t" | '\r' -> "\\r" | '\\' -> "\\\\" | '"' -> "\\\"" | c when !is_printable c -> sprintf "\\%.3d" (ord c) | c -> String.make 1 c } } function escape(s) { var b = Buffer.create(); function rec loop(i) { if i == String.length s then Buffer.string b else { match String.get s i { | '\n' -> Buffer.add b "\\n" | '\t' -> Buffer.add b "\\t" | '\r' -> Buffer.add b "\\r" | '\\' -> Buffer.add b "\\\\" | '"' -> Buffer.add b "\\\"" | c when !is_printable c -> Buffer.add b (sprintf "\\%.3d" (ord c)) | c -> Buffer.add_char b c }; loop (i+1) } }; loop(0); } function unescape(s) { var l = length s; var s2 = create l; var i = &0; var p = &0; while *i < l { match neko("$sget")(s,*i) { | '\\' -> i := *i + 1; if *i == l then invalid_arg(); var c = neko("$sget")(s,*i); match c { | 'n' -> neko("$sset")(s2,*p,'\n'); | 't' -> neko("$sset")(s2,*p,'\t'); | 'r' -> neko("$sset")(s2,*p,'\r'); | '"' -> neko("$sset")(s2,*p,'"'); | '\\' -> neko("$sset")(s2,*p,'\\'); | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' -> if *i + 2 >= l then invalid_arg(); var c2 = neko("$sget")(s,*i + 1); var c3 = neko("$sget")(s,*i + 2); i := *i + 2; if c2 < '0' || c2 > '9' || c3 < '0' || c3 > '9' then invalid_arg(); var o0 = ord '0'; var n = (ord c - o0) * 100 + (ord c2 - o0) * 10 + (ord c3 - o0); if n > 255 then invalid_arg(); neko("$sset")(s2,*p,chr n); | _ -> invalid_arg() } | c -> neko("$sset")(s2,*p,c); } p := *p + 1; i := *i + 1; } sub s2 0 (*p) } function lowercase(s) { var l = length s; var s2 = sub s 0 l; var i = &0; var delta = ord 'a' - ord 'A'; while *i < l { var c = neko("$sget")(s,*i); if c >= 'A' && c <= 'Z' then neko("$sset")(s2,*i,chr(ord c + delta)); i := *i + 1; } s2 } function uppercase(s) { var l = length s; var s2 = sub s 0 l; var i = &0; var delta = ord 'A' - ord 'a'; while *i < l { var c = neko("$sget")(s,*i); if c >= 'a' && c <= 'z' then neko("$sset")(s2,*i,chr(ord c + delta)); i := *i + 1; } s2 } neko(" @serialize = $loader.loadprim('std@serialize',1); @unserialize = $loader.loadprim('std@unserialize',2); "); function serialize( x : 'a ) : string { neko "@serialize(x)"; } function unserialize( x : string ) : 'a { neko "@unserialize(x,$loader)"; } neko-2.0.0/src/core/Sys.nml0000644000175000017500000000545712112157473016174 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ neko(" @sys_exit = $loader.loadprim('std@sys_exit',1); @get_env = $loader.loadprim('std@get_env',1); @get_cwd = $loader.loadprim('std@get_cwd',0); @exe_path = $loader.loadprim('std@sys_exe_path',0); @sys_file_type = $loader.loadprim('std@sys_file_type',1); @sys_read_dir = $loader.loadprim('std@sys_read_dir',1); "); type version { maj : int; min : int; build : int; } function without_extension(s) { match List.rev (String.split s ".") { | [] -> "" | [x] -> x | ext :: l -> String.concat "." (List.rev l) } } function extension(s) { match List.rev (String.split s ".") { | [] | [_] -> "" | ext :: _ -> ext } } function without_dir(s) { var s = String.concat "/" (String.split s "\\"); match List.rev (String.split s "/") { | [] -> assert() | file :: _ -> file } } var array_dependency = Array.make function args() : string array { neko(" @Array.@make($loader.args) "); } function exit(code : int) : 'a { neko(" @sys_exit(code); "); } var exists : string -> bool = neko "$loader.loadprim('std@sys_exists',1)" var version = { var v : int = neko "$version()"; { maj = v / 100; min = (v / 10) % 10; build = v % 10; } } function get_env( s : string ) : string option { var s = neko "@get_env(s)"; if s == neko "null" then None else Some s; } var put_env : string -> string -> void = neko "$loader.loadprim('std@put_env',2)" function get_cwd() : string { neko "@get_cwd()" } var set_cwd : string -> void = neko "$loader.loadprim('std@set_cwd',1)" function executable_path() : string { neko "@exe_path()" } function is_directory(str:string) : bool { neko "@sys_file_type(str) == 'dir'"; } function read_directory(str:string) : string list { neko "@List.@make(@sys_read_dir(str))" } neko-2.0.0/src/core/Array.nml0000644000175000017500000000744612112157473016474 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ function string( a : 'a array ) : string { neko(" var s = '['; var items = a[0]; var l = a[2]; var i = 0; while i < l { s = s + @Core.string(items[i]); i = i + 1; if i < l s = s + ', '; } s = s + ']'; s "); }; neko(" @make = function(a) { $array(a,string,$asize(a)); }; @merge_sort = $loader.loadprim('std@merge_sort',3); $exports.@make = @make; "); function length( a : 'a array ) : int { neko("a[2]"); } function create() : 'a array { neko("$array($array(),string,0)"); } function add( a : 'a array, x : 'a ) : void { neko(" var k = a[0]; var n = a[2]; if( $asize(k) == n ) { k = $amake(n*2+1); $ablit(k,0,a[0],0,n); a[0] = k; } k[n] = x; a[2] = n + 1; "); } function get( a : 'a array, p : int ) : 'a { a.[p] } function set( a : 'a array, p : int, x : 'a ) : void { a.[p] := x; } function make( size : int, x : 'a ) : 'a array { neko(" var a = $amake(size); var i = 0; while( i < size ) { a[i] = x; i = i + 1; } $array(a,string,size) "); } function init( size : int, f : int -> 'a ) : 'a array { neko(" var a = $amake(size); var i = 0; while( i < size ) { a[i] = $apply(f,i); i = i + 1; } $array(a,string,size) "); } function iter( f : 'a -> void, a : 'a array ) : void { neko(" var l = a[2]; var i = 0; a = a[0]; while (i < l) { f(a[i]); i = i + 1; } "); } function iteri( f : int -> 'a -> void, a : 'a array ) : void { neko(" var l = a[2]; var i = 0; a = a[0]; while (i < l) { f(i,a[i]); i = i + 1; } "); } function map( f : 'a -> 'b, a : 'a array ) : 'b array { neko(" var l = a[2]; var i = 0; var a2 = $amake(l); a = a[0]; while i < l { a2[i] = $apply(f,a[i]); i = i + 1; } $array(a2,string,l); "); } function sort( f : 'a -> 'a -> int, a : 'a array ) : void { neko(" @merge_sort(a[0],a[2],f) "); } function list( a : 'a array ) : 'a list { neko(" var i = a[2]; var l = @Core.@empty; a = a[0]; while i > 0 { i = i - 1; l = @Core.@cons(a[i],l); } l "); } function append( src : 'a array, dst : 'a array ) : void { neko(" var l = src[2]; var i = 0; src = src[0]; while i < l { add(dst,src[i]); i = i + 1; } "); } function sub( a : 'a array, p : int, l : int ) : 'a array { neko(" var al = a[2]; if( p + l > al ) $throw('$asub'); $array($asub(a[0],p,l),string,l) "); } function blit( dst : 'a array, pdst : int, src : 'a array, psrc : int, len : int ) { neko(" $ablit(dst[0],pdst,src[0],psrc,len) "); } function index( a : 'a array, it : 'a ) : int { neko(" var al = a[2]; a = a[0]; var i = 0; while( i < al ) { if( @Core.@compare(a[i],it) == 0 ) return i; i = i + 1; } "); throw Not_found } neko-2.0.0/src/core/Args.nml0000644000175000017500000000451212112157473016301 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type argtype { Void : void -> void; String : string -> void; Int : int -> void; } exception Invalid; function help(head,decl) { print head; print "\n Options :\n"; List.iter (function((name,_,help)) { printf " %s %s\n" (name,help); }) decl; Sys.exit(1) } function parse_args(args,head,decl,def) { var i = &0; var l = Array.length args; var h = Hashtbl.create(); var hdecl = Void (function() { help head decl }); Hashtbl.add h "-help" hdecl; Hashtbl.add h "--help" hdecl; List.iter (function((name,decl,_)) { Hashtbl.add h name decl; }) decl; try { while *i < l { var arg = args.[*i]; i := *i + 1; var d = try { Hashtbl.find h arg; } catch { Not_found -> Void (function() { def arg }) }; match d { | Void f -> f() | String f -> if *i == l then throw Invalid; var param = args.[*i]; i := *i + 1; f param | Int f -> if *i == l then throw Invalid; var param = args.[*i]; i := *i + 1; var pval = try { int param } catch { _ -> throw Invalid }; f pval } } } catch { Invalid -> var arg = args.[*i - 1]; print "Invalid argument : "; print arg; print "\n"; help head decl } } function parse(head,decl,def) { parse_args(Sys.args(),head,decl,def); } neko-2.0.0/src/core/Stack.nml0000644000175000017500000000367612112157473016464 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type stack_item { CFunction; Module : string; Pos : (string,int); } type stack = stack_item array; neko(" @make_stack = function(a) { var a = $acopy(a); var i = 0; var l = $asize(a); while( i < l ) { var k = a[i]; a[i] = if( k == null ) CFunction else if( $typeof(k) == $tstring ) Module(k) else Pos(k[0],k[1]); i = i + 1; } return @Array.@make(a); } ") function call() : stack { neko("@make_stack($callstack())"); } function exc() : stack { neko("@make_stack($excstack())"); } function dump(ch,stack) { Array.iter (function(s) { match s { | CFunction -> IO.write ch "Called from a C function\n" | Module m -> IO.printf ch "Called from %s (no debug available)\n" m | Pos (file,line) -> IO.printf ch "Called from %s line %d\n" (file,line) } }) stack } function print() { dump(IO.stdout,call()); } neko-2.0.0/src/core/Buffer.nml0000644000175000017500000000350012112157473016612 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type t; neko(" @buffer_new = $loader.loadprim('std@buffer_new',0); @buffer_add = $loader.loadprim('std@buffer_add',2); @buffer_add_sub = $loader.loadprim('std@buffer_add_sub',4); @buffer_add_char = $loader.loadprim('std@buffer_add_char',2); @buffer_string = $loader.loadprim('std@buffer_string',1); @buffer_reset = $loader.loadprim('std@buffer_reset',1); "); function create() : t { neko("@buffer_new()"); } function add(b:t,x : 'a) : void { neko("@buffer_add(b,x)"); } function reset(b:t) : void { neko("@buffer_reset(b)"); } var string : t -> string = neko("@buffer_string"); var add_sub : t -> string -> int -> int -> void = neko("@buffer_add_sub"); var add_char : t -> char -> void = neko("@buffer_add_char"); neko-2.0.0/src/core/Set.nml0000644000175000017500000001361412112157473016143 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* This is very similar to PMap except that it does only store one value */ type 'a set { Empty; Node : ('a set, 'a ,'a set, int); } type 'a t { cmp : 'a -> 'a -> int; set : 'a set; } /* -------- tools ----------- */ function height(s) { match s { | Empty -> 0 | Node(_, _, _, h) -> h } } function make(l,v,r) { Node(l, v, r, max (height l) (height r) + 1) } function bal(l,v,r) { var hl = height l; var hr = height r; if hl > hr + 2 then match l { | Node (ll,lv,lr,_) -> if height ll >= height lr then make ll lv (make lr v r) else match lr { | Node (lrl,lrv,lrr,_) -> make (make ll lv lrl) lrv (make lrr v r) | Empty -> assert() } | Empty -> assert() } else if hr > hl + 2 then match r { | Node (rl,rv,rr,_) -> if height rr >= height rl then make (make l v rl) rv rr else match rl { | Node (rll, rlv, rlr, _) -> make (make l v rll) rlv (make rlr rv rr) | Empty -> assert() } | Empty -> assert() } else Node l v r (max hl hr + 1) } function rec remove_min_elt(s) { match s { | Empty -> assert() | Node(Empty, v, r, _) -> r | Node(l, v, r, _) -> bal (remove_min_elt l) v r } } function rec min_elt(s) { match s { | Empty -> throw Not_found | Node(Empty, v, r, _) -> v | Node(l, v, r, _) -> min_elt l } } function merge(t1,t2) { match (t1, t2) { | (Empty, t) -> t | (t, Empty) -> t | _ -> bal t1 (min_elt t2) (remove_min_elt t2) } } function rec add_loop(cmp,x,s) { match s { | Empty -> Node(Empty,x,Empty,1) | Node(l, v, r, _) -> var c = cmp x v; if c == 0 then s else if c < 0 then bal (add_loop cmp x l) v r else bal l v (add_loop cmp x r) } } function rec join(cmp,l,v,r) { match (l, r) { | (Empty, _) -> add_loop cmp v r | (_, Empty) -> add_loop cmp v l | (Node(ll, lv, lr, lh), Node(rl, rv, rr, rh)) -> if lh > rh + 2 then bal ll lv (join cmp lr v r) else if rh > lh + 2 then bal (join cmp l v rl) rv rr else make l v r | _ -> assert() } } function concat(cmp,t1,t2) { match (t1, t2) { | (Empty, t) -> t | (t, Empty) -> t | _ -> join cmp t1 (min_elt t2) (remove_min_elt t2) } } function rec split(cmp,x,s) { match s { | Empty -> (Empty, false, Empty) | Node(l, v, r, _) -> var c = cmp x v; if c == 0 then (l, true, r) else if c < 0 then { var ll, pres, rl = split cmp x l; (ll, pres, join cmp rl v r) } else { var lr, pres, rr = split cmp x r; (join cmp l v lr, pres, rr) } } } /* ---------- api ----------- */ function rec add(set : 'a t, x : 'a) { { cmp = set.cmp; set = add_loop set.cmp x set.set; } } function create(cmp) { { cmp = cmp; set = Empty; } } function empty() { { cmp = compare; set = Empty; } } function is_empty(s) { match s.set { | Empty -> true | _ -> false } } function exists(set,x) { function rec loop(s) { match s { | Empty -> false | Node(l, v, r, _) -> var c = set.cmp x v; c == 0 || loop (if c < 0 then l else r) } } loop set.set } function remove(set,x) { function rec loop(s) { match s { | Empty -> Empty | Node(l, v, r, _) -> var c = set.cmp x v; if c == 0 then merge l r else if c < 0 then bal (loop l) v r else bal l v (loop r) } } { cmp = set.cmp; set = loop set.set; } } function union(set1,set2) { var cmp = set1.cmp; function rec loop(s1,s2) { match (s1, s2) { | (Empty, t2) -> t2 | (t1, Empty) -> t1 | (Node(l1, v1, r1, h1), Node(l2, v2, r2, h2)) -> if h1 >= h2 then if h2 == 1 then add_loop cmp v2 s1 else { var l2, _, r2 = split cmp v1 s2; join cmp (loop l1 l2) v1 (loop r1 r2) } else if h1 == 1 then add_loop cmp v1 s2 else { var l1, _, r1 = split cmp v2 s1; join cmp (loop l1 l2) v2 (loop r1 r2) } | _ -> assert() } } { cmp = cmp; set = loop set1.set set2.set; } } function inter(set1,set2) { var cmp = set1.cmp; function rec loop(s1,s2) { match (s1, s2) { | (Empty, t2) -> Empty | (t1, Empty) -> Empty | (Node(l1, v1, r1, _), t2) -> match split cmp v1 t2 { | (l2, false, r2) -> concat cmp (loop l1 l2) (loop r1 r2) | (l2, true, r2) -> join cmp (loop l1 l2) v1 (loop r1 r2) | _ -> assert() } | _ -> assert() } } { cmp = cmp; set = loop set1.set set2.set; } } function diff(set1,set2) { var cmp = set1.cmp; function rec loop(s1,s2) { match (s1, s2) { | (Empty, t2) -> Empty | (t1, Empty) -> t1 | (Node(l1, v1, r1, _), t2) -> match split cmp v1 t2 { | (l2, false, r2) -> join cmp (loop l1 l2) v1 (loop r1 r2) | (l2, true, r2) -> concat cmp (loop l1 l2) (loop r1 r2) | _ -> assert() } | _ -> assert() } } { cmp = cmp; set = loop set1.set set2.set; } } function iter(f,set) { function rec loop(s) { match s { | Empty -> () | Node(l, v, r, _) -> loop l; f v; loop r } } loop set.set } neko-2.0.0/src/core/Map.nml0000644000175000017500000001070712112157473016125 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* This code is translated from OCaml ExtLib PMap Copyright (C) 1996-2003 Xavier Leroy, Nicolas Cannasse, Markus Mottl */ type ('k, 'v) map { Empty; Node : (('k, 'v) map , 'k , 'v , ('k, 'v) map , int); } type ('k, 'v) t { cmp : 'k -> 'k -> int; map : ('k, 'v) map; } function height(m) { match m { | Node (_, _, _, _, h) -> h | Empty -> 0 } } function make(l,k,v,r) { Node(l, k, v, r, max (height l) (height r) + 1) } function bal(l,k,v,r) { var hl = height l; var hr = height r; if hl > hr + 2 then match l { | Node (ll,lk,lv,lr,_) -> if height ll >= height lr then make ll lk lv (make lr k v r) else match lr { | Node (lrl,lrk,lrv,lrr,_) -> make (make ll lk lv lrl) lrk lrv (make lrr k v r) | Empty -> assert() } | Empty -> assert() } else if hr > hl + 2 then match r { | Node (rl,rk,rv,rr,_) -> if height rr >= height rl then make (make l k v rl) rk rv rr else match rl { | Node (rll, rlk, rlv, rlr, _) -> make (make l k v rll) rlk rlv (make rlr rk rv rr) | Empty -> assert() } | Empty -> assert() } else Node(l, k, v, r, max hl hr + 1) } function rec min_binding(m) { match m { | Node (Empty, k, v, _, _) -> (k, v) | Node (l, _, _, _, _) -> min_binding l | Empty -> throw Not_found } } function rec remove_min_binding(m) { match m { | Node (Empty, _, _, r, _) -> r | Node (l, k, v, r, _) -> bal (remove_min_binding l) k v r | Empty -> invalid_arg() } } function merge(t1,t2) { match (t1, t2) { | (Empty, _) -> t2 | (_, Empty) -> t1 | _ -> var k, v = min_binding t2; bal t1 k v (remove_min_binding t2) } } function create(cmp) { { cmp = cmp; map = Empty; } } function empty() { { cmp = compare; map = Empty; } } function is_empty(m) { m.map == Empty } function add(m,x,d) { var cmp = m.cmp; function rec loop(m) { match m { | Node (l, k, v, r, h) -> var c = cmp x k; if c == 0 then Node(l, x, d, r, h) else if c < 0 then { var nl = loop l; bal nl k v r; } else { var nr = loop r; bal l k v nr } | Empty -> Node(Empty, x, d, Empty, 1) } }; { cmp = cmp; map = loop m.map; } } function find(m,x) { var cmp = m.cmp; function rec loop(m) { match m { | Node (l, k, v, r, _) -> var c = cmp x k; if c < 0 then loop l else if c > 0 then loop r else v | Empty -> throw Not_found } }; loop m.map } function remove(m,x) { var cmp = m.cmp; function rec loop(m) { match m { | Node(l, k, v, r, _) -> var c = cmp x k; if c == 0 then merge l r else if c < 0 then bal (loop l) k v r else bal l k v (loop r) | Empty -> Empty } }; { cmp = cmp; map = loop m.map; } } function exists(m,x) { var cmp = m.cmp; function rec loop(m) { match m { | Node (l, k, v, r, _) -> var c = cmp x k; c == 0 || loop (if c < 0 then l else r) | Empty -> false } }; loop m.map } function iter(f,m) { function rec loop(m) { match m { | Empty -> () | Node (l, k, v, r, _) -> loop l; f k v; loop r } }; loop m.map } function map(f,m) { function rec loop(m) { match m { | Empty -> Empty | Node (l, k, v, r, h) -> var l = loop l; var r = loop r; Node(l, k, f v, r, h) } }; { cmp = m.cmp; map = loop m.map; } } function fold(f,m,acc) { function rec loop(acc,m) { match m { | Empty -> acc | Node (l, k, v, r, _) -> loop (f (loop acc l) v) r } }; loop acc m.map } neko-2.0.0/src/core/Net.nml0000644000175000017500000001076112112157473016136 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type socket; type ip = int32; // init neko "$loader.loadprim('std@socket_init',0)()"; var socket_new : bool -> socket = neko "$loader.loadprim('std@socket_new',1)"; var socket_close : socket -> void = neko "$loader.loadprim('std@socket_close',1)"; var socket_send_char : socket -> char -> void = neko "$loader.loadprim('std@socket_send_char',2)"; var socket_send : socket -> string -> int -> int -> int = neko "$loader.loadprim('std@socket_send',4)"; var socket_recv : socket -> string -> int -> int -> int = neko "$loader.loadprim('std@socket_recv',4)"; var socket_recv_char : socket -> char = neko "$loader.loadprim('std@socket_recv_char',1)"; var socket_write : socket -> string -> void = neko "$loader.loadprim('std@socket_write',2)"; var socket_read : socket -> string = neko "$loader.loadprim('std@socket_read',1)"; var socket_connect : socket -> ip -> int -> void = neko "$loader.loadprim('std@socket_connect',3)"; var socket_listen : socket -> int -> void = neko "$loader.loadprim('std@socket_listen',2)"; var socket_bind : socket -> ip -> int -> void = neko "$loader.loadprim('std@socket_bind',3)"; var socket_accept : socket -> socket = neko "$loader.loadprim('std@socket_accept',1)"; var socket_peer : socket -> (ip,int) = neko "$loader.loadprim('std@socket_peer',1)"; var socket_host : socket -> (ip,int) = neko "$loader.loadprim('std@socket_host',1)"; var socket_set_timeout : socket -> int -> void = neko "$loader.loadprim('std@socket_set_timeout',2)"; var host_resolve : string -> ip = neko "$loader.loadprim('std@host_resolve',1)"; var host_to_string : ip -> string = neko "$loader.loadprim('std@host_to_string',1)"; neko "@host_local = $loader.loadprim('std@host_local',0)"; function host_local() : string { neko "@host_local()" }; var url_encode : string -> string = neko "$loader.loadprim('std@url_encode',1)"; var url_decode : string -> string = neko "$loader.loadprim('std@url_decode',1)"; neko "@socket_select = $loader.loadprim('std@socket_select',4)" var _array_dep = Array.make; function socket_select( read : socket array, write : socket array, others : socket array, timeout : float option ) : (socket array, socket array, socket array) { var t = match timeout { None -> neko "null" | Some t -> t }; neko " var r = @socket_select($asub(read[0],0,read[2]),$asub(write[0],0,write[2]),$asub(others[0],0,others[2]),t); r[0] = @Array.@make(r[0]); r[1] = @Array.@make(r[1]); r[2] = @Array.@make(r[2]); r " } function socket_io(s) { (IO.create_in (function() { try socket_recv_char s catch { e -> throw IO.Eof } }) (function(b,p,l) { try { var n = socket_recv s b p l; if n == 0 then throw IO.Eof; n } catch { e -> throw IO.Eof } }) (function() { socket_close s }) ,IO.create_out (socket_send_char s) (socket_send s) (function() { }) (function() { socket_close s }) ) } function start_server( ip, port, on_connect, on_data ) { var sock = socket_new false; socket_bind sock ip port; socket_listen sock 10; var clients = &[]; var empty = Array.create(); while true { var r, _ , _ = socket_select List.array(sock :: List.map fst (*clients)) empty empty None; Array.iter (function(s) { if s == sock then { var s2 = socket_accept sock; clients := (s2,on_connect s2) :: *clients; } else { var cldata = List.assoc s (*clients); if !(on_data cldata) then clients := List.filter (function((s2,_)) { s != s2 }) (*clients); } }) r; } () } neko-2.0.0/src/core/List.nml0000644000175000017500000001001712112157473016315 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ neko(" @make = function(s) { if( s == null ) return @Core.@empty; return @Core.@cons(s[0],@make(s[1])); } @rmake = function(s,x) { if( s == null ) return x; return @rmake(s[1],@Core.@cons(s[0],x)); } $exports.@rmake = function(s) { @rmake(s,@Core.@empty) }; $exports.@make = @make; "); function rec length(l) { match l { | [] -> 0 | _ :: l -> 1 + length l } } function hd(l) { match l { | [] -> invalid_arg() | x :: _ -> x } } function tl(l) { match l { | [] -> invalid_arg() | _ :: l -> l } } function rec map(f,l) { match l { | [] -> [] | x :: l -> f(x) :: map f l } } function rec iter(f,l) { match l { | [] -> () | x :: l -> f x; iter f l } } function rec iter2(f,l1,l2) { match l1 { | [] -> match l2 { | [] -> () | _ -> invalid_arg() } | x1 :: l1 -> match l2 { | [] -> invalid_arg() | x2 :: l2 -> f x1 x2; iter2 f l1 l2 } } } function rec split(l) { match l { | [] -> ([] , []) | (a,b) :: l -> var la , lb = split l; (a :: la, b :: lb) } } function rec exists(f,l) { match l { | [] -> false | x :: l -> if f x then true else exists f l } } function rec mem(v,l) { match l { | [] -> false | x :: l -> if x == v then true else mem v l } } function rec assoc(k,l) { match l { | [] -> throw Not_found | (k2,v) :: l -> if k == k2 then v else assoc k l } } function rec phys(k,l) { match l { | [] -> throw Not_found | (k2,v) :: l -> if k === k2 then v else phys k l } } function rec find(f,l) { match l { | [] -> throw Not_found | k :: l -> if f k then k else find f l } } function rec rev_rec(l,acc) { match l { | [] -> acc | x :: l -> rev_rec l (x :: acc) } } function rev(l) { rev_rec l [] } function rec fold(f,acc,l) { match l { | [] -> acc | x :: l -> fold f (f acc x) l } } function rec append(l1,l2) { match l1 { | [] -> l2 | x :: l1 -> x :: append l1 l2 } } function rec concat(ll) { function rec loop(ll,acc) { match ll { | [] -> acc | l :: ll -> loop ll (append acc l) } }; loop ll [] } function rec chop(n,l) { if n == 0 then l else match l { | [] -> invalid_arg() | _ :: l -> chop (n -1) l } } function rec all(f,l) { match l { | [] -> true | x :: l -> if f x then all(f,l) else false } } function rec none(f,l) { match l { | [] -> true | x :: l -> if f x then false else none(f,l) } } function nth(l,n) { function rec loop(l,n) { match l { | [] -> invalid_arg() | x :: l -> if n == 0 then x else loop l (n-1) } } if n < 0 then invalid_arg(); loop l n } function rec filter(f,l) { match l { | [] -> [] | x :: l -> if f x then x :: filter f l else filter f l } } function array(l) { match l { | [] -> Array.create() | x :: l -> var a = Array.make (1+ List.length l) x; function rec loop(p,l) { match l { | [] -> () | x :: l -> a.[p] := x; loop (p + 1) l } }; loop 1 l; a } } function sort(cmp,l) { var a = array l; Array.sort cmp a; Array.list a } neko-2.0.0/src/core/Lexer.nml0000644000175000017500000001207712112157473016471 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type pos { psource : string; pline : int; pmin : int; pmax : int; } type 'a t { mutable data : 'a; mutable current : string; mutable buffer : string; mutable bsize : int; mutable bin : int; mutable bpos : int; mutable cin : int; mutable cpos : int; mutable input : IO.input; mutable source : string; mutable line : int; mutable pos : int; mutable carriage : bool; } type ('a,'b) tables { engine : LexEngine.tables; cases : ('b t -> 'a) array; def : 'b t -> 'a; } exception Invalid_rule : string var null_pos = { pmin = 0; pmax = 0; pline = 0; psource = "" }; function source(p) { p.psource } function line(p) { p.pline } function punion(p,p2) { { psource = p.psource; pline = p.pline; pmin = min p.pmin p2.pmin; pmax = max p.pmax p2.pmax; } } function create(data) { var bufsize = 4096; { data = data; carriage = false; current = ""; buffer = String.create bufsize; bsize = bufsize; bin = 0; cin = 0; bpos = bufsize; cpos = bufsize; input = IO.read_string ""; source = ""; line = 0; pos = 0; } } function data(l) { l.data; } function set(l,data) { l.data := data; } function input(l,source,input,line,pos) { l.bin := 0; l.cin := 0; l.bpos := l.bsize; l.cpos := l.bsize; l.input := input; l.source := source; l.line := line; l.pos := pos; } function curpos(l) { { psource = l.source; pline = l.line; pmin = l.pos - String.length l.current; pmax = l.pos; } } function current(l) : string { l.current } function read(l) : char { if l.bin == 0 then { if l.bpos == l.bsize then { var buf = String.create (l.bsize * 2); String.blit buf l.bsize l.buffer 0 l.bsize; l.cpos := l.cpos + l.bsize; l.bpos := l.bpos + l.bsize; l.buffer := buf; l.bsize := l.bsize * 2; } var delta = l.bpos - l.cpos; String.blit l.buffer 0 l.buffer l.cpos delta; l.bpos := delta; l.cpos := 0; var k = IO.input l.input l.buffer delta (l.bsize - delta); l.bin := l.bin + k; l.cin := l.cin + k; }; var c = String.get l.buffer l.bpos; l.bpos := l.bpos + 1; l.bin := l.bin - 1; c } function inc_line(l,c) { if c == '\r' then l.carriage := true else if c == '\n' || l.carriage then { l.carriage := false; l.line := l.line + 1; }; } function char(l) : char option { try { var c = read l; l.bpos := l.bpos - 1; l.bin := l.bin + 1; inc_line l c; Some c } catch { IO.Eof -> None } } type cur { mutable cur_n : int; mutable cur_res : int; } function token(l,t) : 'a { var tbl = fst t.engine; var exits = snd t.engine; var cur = { cur_n = 0; cur_res = -1 }; var last = { cur_n = 0; cur_res = -1 }; function rec loop(n,k) { var res = neko("tbl[0][k][0][read(l)]"); var e = exits.[k]; cur.cur_n := n; cur.cur_res := res; if e != -1 then { last.cur_n := n; last.cur_res := e; } if res == -1 then throw Exit; neko("loop[0](n+1,res)"); }; function process(eof) { var n = last.cur_n; var k = last.cur_res; if k == -1 then { l.current := ""; if !eof then { l.bpos := l.bpos - (cur.cur_n + 1); l.bin := l.bin + (cur.cur_n + 1); } -1; } else { l.cin := l.cin - n; l.bin := l.cin; l.current := String.sub l.buffer l.cpos n; l.cpos := l.cpos + n; l.bpos := l.cpos; l.pos := l.pos + n; var i = &0; while *i < n { inc_line l (String.get l.current (*i)); i := *i + 1; } k } }; var k = try { loop 0 0; assert(); } catch { | IO.Eof -> if cur.cur_res != -1 then { last.cur_n := cur.cur_n + 1; last.cur_res := exits.[cur.cur_res]; } process true; | Exit -> process false } if k == -1 then t.def(l) else t.cases.[k](l) } function build(rules,def) { var nfa = List.map (function((r,_)) { try LexEngine.parse r catch { _ -> throw Invalid_rule(r) } }) rules; var cases = List.array (List.map snd rules); { engine = LexEngine.make_tables (LexEngine.determinize (List.array nfa)); cases = cases; def = def; } } function empty() { function empty_table(_) { invalid_arg() }; build [] empty_table; } neko-2.0.0/src/core/LexEngine.nml0000644000175000017500000002017312112157473017264 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* most of this code is taken from the ULex lexer by Alain Frish, originaly written as an OCaml library. */ type charset = (int , int) list type node { mutable id : int; mutable trans : (charset , node) list; mutable epsilon : node list; } type state = node list type tables = (int array array , int array) type t { Empty; Match : charset; Star : t; Plus : t; Next : (t , t); Choice : (t , t); } /* ------- charset ------ */ var max_code = 255; var cempty = []; var call = [(0,max_code)]; function is_empty(c) { c == [] } function rec cunion(c1,c2) { match (c1 , c2) { | ([] , _) -> c2 | (_ , []) -> c1 | (((i1,j1) as s1)::r1, (i2,j2)::r2) -> if i1 <= i2 then if j1 + 1 < i2 then s1::(cunion r1 c2) else if (j1 < j2) then cunion r1 ((i1,j2)::r2) else cunion c1 r2 else cunion c2 c1 | _ -> assert() } } function ccomplement(c) { function rec loop(start,l) { match l { | [] -> if start <= max_code then [(start,max_code)] else [] | (i,j) :: l -> (start,i-1) :: (loop (j + 1) l) } }; match c { | (-1,j) :: l -> loop (j + 1) l | l -> loop (-1) l } } function cinter(c1,c2) { ccomplement (cunion (ccomplement c1) (ccomplement c2)) } function cdiff(c1,c2) { ccomplement (cunion (ccomplement c1) c2) } /* ------- nodes -------- */ function node(g) { { id = g(); trans = []; epsilon = []; } } function rec add_node(state,node) { if List.exists (function(k) { k === node }) state then state else add_nodes (node::state) node.epsilon } function rec add_nodes(state,nodes) { List.fold add_node state nodes } function nodes(nfa) { var g = &0; var gen = function() { g := *g + 1; *g }; function rec loop(n,final) { match n { | Empty -> final | Match c -> var n = node gen; n.trans := [(c,final)]; n | Star a -> var n = node gen; var an = loop a n; n.epsilon := [an; final]; n | Plus a -> var n = node gen; var an = loop a n; n.epsilon := [an; final]; an | Next (a,b) -> loop a (loop b final) | Choice (a,b) -> var n = node gen; n.epsilon := [loop a final; loop b final]; n } }; Array.map (function(n) { var f = node gen; (loop n f,f) }) nfa } /* ------- NFA -> DFA -------- */ function transitions(state : state) { // Merge transition with the same target function rec norm(l) { match l { | (t1,n1) :: (((t2,n2) :: q) as l) -> if n1 === n2 then norm ((cunion t1 t2,n1) :: q) else (t1,n1) :: (norm l) | _ -> l } }; var t = List.concat (List.map (function(n) { n.trans }) state); var t = norm (List.sort (function((t1,n1),(t2,n2)) { n1.id - n2.id }) t); // Split char sets so as to make them disjoint function rec split((all,t),(c0,n0)) { var t = (cdiff c0 all, [n0]) :: List.append (List.map (function((c,ns)) { (cinter c c0, n0::ns) }) t) (List.map (function((c,ns)) { (cdiff c c0, ns) }) t); (cunion all c0, List.filter (function((c,ns)) { !is_empty c }) t) }; var _ , t = List.fold split (cempty,[]) t; // Epsilon closure of targets var t = List.map (function((t,ns)) { (t,add_nodes [] ns) }) t; // Canonical ordering var t = List.array t; Array.sort (function((c1,ns1),(c2,ns2)) { compare c1 c2 }) t; (Array.map fst t, Array.map snd t) } function determinize(nfa : t array) { var nfa = nodes nfa; var h = Hashtbl.create(); var parts = Hashtbl.create(); var state_counter = &0; var part_counter = &0; var lparts = &[]; var states = &[]; function get_part(p) { try Hashtbl.find parts p catch { Not_found -> var pid = *part_counter; part_counter := *part_counter + 1; Hashtbl.add parts p pid; lparts := p :: *lparts; pid } }; function rec loop(state) { var sid = List.map (function(s) { s.id }) state; try Hashtbl.find h sid catch { Not_found -> var id = *state_counter; state_counter := *state_counter + 1; Hashtbl.add h sid id; var part, targets = transitions state; var part = get_part part; var targets = Array.map loop targets; var finals = Array.map (function((_,f)) { List.mem f state }) nfa; states := (id, (part,targets,finals)) :: *states; id } }; var init : node list ref = &[]; Array.iter (function((i,_)) { init := add_node (*init) i }) nfa; ignore(loop (*init)); var dfa = Array.init (*state_counter) (function(id) { List.assoc id (*states) }); function loop(part) { var seg = &[]; Array.iteri (function(i,c) { List.iter (function((a,b)) { seg := (a,b,i) :: *seg }) c }) part; List.sort (function((a1,_,_),(a2,_,_)) { compare a1 a2 }) (*seg); }; var trans = List.array (List.map loop (List.rev (*lparts))); (dfa , trans) } /* ---- DFA -> Tables ---- */ // this expands memory but is better since all accesses are O(1) function make_trans(trans,tbl) { var a = Array.make 256 (-1); List.iter (function((min,max,n)) { var i = &min; while *i <= max { a.[*i] := tbl.[n]; i := *i + 1; } }) trans; a } function make_tables((dfa,trans)) { function rec first(p,a) { if p == Array.length a then -1 else if a.[p] then p else first (p + 1) a }; var exits = Array.map (function((_,_,states)) { first 0 states }) dfa; var tbls = Array.map (function((tid,tbl,_)) { make_trans trans.[tid] tbl }) dfa; (tbls , exits) } /* ---- Regexp Parsing ---- */ exception InvalidRegexp : string function single(c) { var n = ord c; [(n,n)] } function group(chars) { var chars = List.map (function((c1,c2)) { [(ord c1,ord c2)] }) chars; List.fold cunion cempty chars } function invalid(s) { throw InvalidRegexp(s) } function escaped(s,i) { var c = String.get s (*i); i := *i + 1; match c { | '\\' | '+' | '*' | '?' | '[' | ']' | '-' -> c | _ -> invalid s } } function rec plus(r) { match r { | Next (r1,r2) -> Next(r1,plus r2) | _ -> Plus r } } function rec star(r) { match r { | Next (r1,r2) -> Next(r1,star r2) | _ -> Star r } } function rec opt(r) { match r { | Next(r1,r2) -> Next(r1,opt r2) | _ -> Choice(r,Empty) } } function next(r,r2) { match r { | Empty -> r2 | _ -> Next r r2 } } function parse( s : string ) : t { var i = &0; var r = &Empty; var l = String.length s; while *i < l { var c = String.get s (*i); i := *i + 1; match c { | '+' -> r := plus (*r) | '*' -> r := star (*r) | '?' -> r := opt (*r) | '[' -> var range = &None; function rec loop(acc) { var c = String.get s (*i); i := *i + 1; if c == ']' then { if *range != None then invalid s; acc } else if c == '-' then { if *range != None then invalid s; match acc { | [] -> loop ((c,c) :: acc) | (x1,x2) :: l -> if x1 != x2 then invalid s; range := Some x1; loop l } } else { var c = (if c == '\\' then escaped s i else c); match *range { | None -> loop ((c,c) :: acc) | Some c2 -> range := None; loop ((c2,c) :: acc) } } }; var c = String.get s (*i); var g = if c == '^' then { i := *i + 1; cdiff call (group (loop [])) } else group (loop []); r := next (*r) Match(g) | '\\' -> r := next (*r) Match(single (escaped s i)) | _ -> r := next (*r) Match(single c) } }; *r } neko-2.0.0/src/core/Core.nml0000644000175000017500000001415612112157473016302 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type void; type int; type int32; type float; type char; type string; type error; type 'a array; type 'a ref; type 'a format; type 'a stream; type 'a option { None; Some : 'a; } type neko_value; exception Neko_error : neko_value; exception Invalid_argument : string; exception Assert_failure : (string,int); exception Error : string; exception Stream_error; exception Not_found; exception Exit; /* ----- theses are defined directly in the compiler because they need additional magic. type bool { true; false; } type 'a list { []; :: : ('a , 'a list); } val neko : string -> 'a ----- */ neko(" @sprintf = $loader.loadprim('std@sprintf',2); @string = function(x) { // tuples if( $typeof(x) == $tarray ) { // constructor var printer = x[1]; if( $typeof(printer) == $tfunction && $nargs(printer) == 1 ) return printer(x); var s = '('; var l = $asize(x); var i = 0; while i < l { s = s + @string(x[i]); i = i + 1; if i < l s = s + ', '; } s = s + ')'; return s; } // others return $string(x); } $exports.@print_record = function() { var o = $objfields(this); var s = '{ '; var i = 0; var l = $asize(o) - 1; while i < l { var f = o[i]; var fname = $field(f); if fname == '__string' l = l + 1; else s = s + fname + ' = ' + @string($objget(this,f))+'; '; i = i + 1; } s = s + '}'; s } $exports.@print_union = function(s,a) { var l = $asize(a); if l == 2 return s; var i = 2; s = s + '('; while i < l { s = s + @string(a[i]); i = i + 1; if i < l s = s + ', '; } s = s + ')'; return s; } @compare = function(a,b,history) { if( $pcompare(a,b) == 0 ) return 0; if( $typeof(a) == $tarray ) { var l1 = $asize(a); var l2 = $asize(b); if( l1 != l2 ) return $compare(l1,l2); var h = history; while h != null { if( h[0] == a && h[1] == b ) return $pcompare(a,b); h = h[2]; } var i = 0; while i < l1 { var k = @compare(a[i],b[i],$array(a,b,history)); if( k != 0 ) return k; i = i + 1; } return 0; } if( $typeof(a) == $tobject ) { var h = history; while h != null { if( h[0] == a && h[1] == b ) return $pcompare(a,b); h = h[2]; } var o = $objfields(a); var i = 0; var l = $asize(o); while i < l { var v = $objget(b,o[i]); var k = @compare($objget(a,o[i]),v,$array(a,b,history)); if( k != 0 ) return k; i = i + 1; } return 0; } return $compare(a,b); } $exports.@compare = function(a,b) { @compare(a,b,null) }; $exports.@aget = function(a,i) { if( i < 0 || i >= a[2] ) $exports.invalid_arg('Array.get'); a[0][i] } $exports.@aset = function(a,i,v) { if( i < 0 || i >= a[2] ) $exports.invalid_arg('Array.set'); a[0][i] = v; } @empty = $array(0,function(_){ '[]' }); @pcons = function(c) { @string(c[2]) + ' :: ' + @string(c[3]) }; @cons = function(x,l) { $array(1,@pcons,x,l) } $exports.@pcons = @pcons; $exports.@cons = @cons; $exports.@empty = @empty; "); function magic(x) { neko("x"); } function throw(x : error) : 'a { neko("$throw(x)"); } function assert(file,line) { throw Assert_failure(file,line) } function invalid_arg(fun) : 'a { throw Invalid_argument(fun); } function error(x : string) { throw Error(x) } function ignore(x) { } function fst((a,_)) { a } function snd((_,a)) { a } function int(x:string) : int { var i = neko("$int(x)"); if i == neko("null") then invalid_arg(); i } function float(x:string) : float { var i = neko("$float(x)"); if i == neko("null") then invalid_arg(); i } function ord(x:char) : int { neko("x"); } function chr(x:int) : char { if x < 0 || x > 255 then invalid_arg(); neko("x"); } function string(x : 'a) : string { neko("@string(x)"); } function nstring(x : 'a) : string { neko("$string(x)"); } function print(x) : void { neko("$print(string(x))"); } function nprint(x) : void { neko("$print(x)"); } function compare(x : 'a, y : 'a) : int { neko("$exports.@compare(x,y)"); } function min(x,y) { if x < y then x else y } function max(x,y) { if x < y then y else x } function sprintf(fmt : 'a format, p : 'a ) : string { neko("@sprintf(fmt,p)") } function printf(fmt : 'a format, p : 'a ) : void { print (sprintf fmt p) } function stream(f : void -> 'a ) : 'a stream { neko("{ get => f, pos => 0, cache => $array() }"); } function stream_token( s : 'a stream, x : int ) : 'a { if x < 0 then invalid_arg(); neko(" var tmp = s.cache[x]; if( tmp != null ) return tmp; var n = $asize(s.cache); var c = $amake(x + 1); $ablit(c,0,s.cache,0,n); while n <= x { c[n] = s.get(null); n = n + 1; } s.cache = c; return c[x]; "); } function stream_junk( s : 'a stream, x : int ) : void { if x < 0 then invalid_arg(); neko(" var c = $asize(s.cache); s.pos = s.pos + x; if( c >= x ) s.cache = $asub(s.cache,x,c - x); else { s.cache = $array(); x = x - c; while x > 0 { s.get(null); x = x - 1; } } "); } function stream_pos( s : 'a stream ) : int { neko("s.pos"); } neko-2.0.0/src/nekoml.vcxproj0000644000175000017500000001142212112157473016645 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {4662A8A2-AE65-465A-B97B-7F1269433BD5} MakeFileProj Makefile Makefile Makefile <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ make nekoml make clean nekoml make clean Release\ Release\ make nekoml make clean nekoml make clean $(Configuration)\ $(Configuration)\ make nekoml make clean nekoml make clean neko-2.0.0/src/nekoml/0000755000175000017500000000000012112157473015230 5ustar ncannassencannasseneko-2.0.0/src/nekoml/Type.nml0000644000175000017500000002014212112157473016660 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type pos = Lexer.pos type mutflag { Mutable; Immutable; } type t; type type_expr { TAbstract; TMono : int; TPoly; TRecord : (string , mutflag , t) list; TUnion : (int , (string , t) list); TTuple : t list; TLink : t; TFun : (t list , t); TNamed : (string list , t list , t); } type t { mutable tid : int; mutable texpr : type_expr; } type tconstant { TVoid; TInt : int; TBool : bool; TFloat : string; TString : string; TChar : char; TIdent : string; TConstr : string; TModule : (string list, tconstant); } type texpr; type match_op { MRoot; MFailure; MHandle : (match_op, match_op); MExecute : (texpr, bool); MConstants : (match_op, (tconstant, match_op) list); MField : (match_op, int); MTuple : (match_op, int); MToken : (match_op, int); MRecordField : (match_op, string, t); MJunk : (match_op, int, match_op); MSwitch : (match_op, (tconstant, match_op) list); MBind : (string, match_op, match_op); MWhen : (texpr, match_op); MNext : (match_op, match_op); } type texpr_decl { TConst : tconstant; TBlock : texpr list; TParenthesis : texpr; TCall : (texpr, texpr list); TField : (texpr, string); TArray : (texpr, texpr); TVar : (string list, texpr); TIf : (texpr, texpr, texpr option); TFunction : (bool, string, (string, t) list, texpr); TBinop : (string, texpr, texpr); TTupleDecl : texpr list; TTypeDecl : t; TMut : texpr ref; TRecordDecl : (string, texpr) list; TListDecl : texpr list; TUnop : (string, texpr); TMatch : (texpr, match_op, bool); TTry : (texpr, match_op); TTupleGet : (texpr, int); TErrorDecl : (string, t); TWhile : (texpr, texpr); } type texpr { edecl : texpr_decl; etype : t; epos : pos; } type id_gen = int ref function pos(e) { e.epos } function rec tlinks(name,t) { match t.texpr { | TLink t -> tlinks name t | TNamed (_,_,t) when !name -> tlinks name t | _ -> t.texpr } } function etype(name,e) { tlinks name e.etype } function genid(i) { i := *i + 1; *i } function generator() { &0 } function mk(e,t,p) { { edecl = e; etype = t; epos = p; } } var t_abstract = { tid = -1; texpr = TAbstract } function abstract(s) { tid = -1; texpr = TNamed [s] [] t_abstract; } // theses are not really unique since they're declared // also in Core, so it's not possible to use physeq var t_void = abstract "void"; var t_int = abstract "int"; var t_float = abstract "float"; var t_char = abstract "char"; var t_error = abstract "error"; var t_string = abstract "string" var t_bool = { tid = -1; texpr = TNamed ["bool"] [] ({ tid = -1; texpr = TUnion 2 [ ("true",t_abstract); ("false",t_abstract) ]; }); } function rec is_int(t) { match t.texpr { | TNamed(["int"],_,_) -> true | TLink t -> is_int t | _ -> false } } function t_mono(g) { { tid = -2; texpr = TMono (genid g); } } function t_polymorph(g) { { tid = genid g; texpr = TPoly; } } function t_poly(g,name) { var param = t_mono g; ({ tid = genid g; texpr = TNamed [name] [param] ({ tid = -1; texpr = TAbstract }); } , param) } function mk_fun(g,params,ret) { { tid = if List.exists (function(t) { t.tid != -1 }) (ret :: params) then genid g else -1; texpr = TFun params ret; } } function mk_tup(g,l) { { tid = if List.exists (function(t) { t.tid != -1 }) l then genid g else -1; texpr = TTuple l; } } function mk_record(g,fl) { { tid = if List.exists (function((_,_,t)) { t.tid != -1 }) fl then genid g else -1; texpr = TRecord fl; } } function mk_union(g,fl) { { tid = if List.exists (function((_,t)) { t.tid != -1 }) fl then genid g else -1; texpr = TUnion List.length(fl) fl; } } function rec file_name(m : string list,ext) { match m { | [] -> invalid_arg() | [x] -> x + ext | p :: l -> var c = String.get p 0; var p = if c < 'A' || c > 'Z' then p else { var p = String.sub p 0 (String.length p); String.set p 0 chr(ord c - ord 'A' + ord 'a'); p } p + "/" + file_name l ext } } type print_infos { mutable pi_mcount : int; mutable pi_pcount : int; mutable pi_ml : (t, int) list; mutable pi_ph : (int, int) Hashtbl.t; } function s_context() { { pi_mcount = 0; pi_pcount = 0; pi_ml = []; pi_ph = Hashtbl.create(); } } function poly_id(n) { if n < 26 then String.make 1 chr(ord 'a' + n) else string (n - 25) } function s_mutable(m) { match m { | Mutable -> "mutable " | Immutable -> "" } } function rec s_type(ext,h,t) { match t.texpr { | TAbstract -> "" | TMono _ -> sprintf "'_%s" poly_id(try if t.tid != -2 then assert(); List.phys t h.pi_ml; catch { Not_found -> var k = h.pi_mcount; h.pi_mcount := h.pi_mcount + 1; h.pi_ml := (t,k) :: h.pi_ml; k }) | TPoly -> sprintf "'%s" poly_id(try if t.tid == -1 then assert(); Hashtbl.find h.pi_ph t.tid catch { Not_found -> var k = h.pi_pcount; h.pi_pcount := h.pi_pcount + 1; Hashtbl.add h.pi_ph t.tid k; k }) | TRecord fl -> sprintf "{ %s }" (String.concat "; " (List.map (function((f,m,t)) { s_mutable m + f + " : " + s_type false h t }) fl)) | TUnion (_,fl) -> sprintf "{ %s }" (String.concat "; " (List.map (function((f,t)) { f + " : " + s_type false h t }) fl)) | TTuple l -> sprintf "(%s)" (String.concat ", " (List.map (s_type false h) l)) | TLink t -> s_type ext h t | TFun (tl,r) -> var l = String.concat " -> " (List.map (s_fun false h) tl) + " -> "; l + s_type false h r | TNamed (name,params,t) -> var s = match params { | [] -> "" | [p] -> s_type false h p + " " | l -> "(" + String.concat ", " (List.map (s_type false h) l) + ") " }; var name = String.concat "." name; if ext then s + name + " = " + s_type false h t else s + name } } function rec s_fun(ext,h,t) { match t.texpr { | TLink t -> s_fun ext h t | TFun _ -> "(" + s_type ext h t + ")" | _ -> s_type ext h t } } function rec duplicate(g,h,t) { if t.tid < 0 then t else try Hashtbl.find h t.tid catch { Not_found -> var t2 = { tid = genid g; texpr = TAbstract; }; Hashtbl.add h t.tid t2; t2.texpr := match t.texpr { | TAbstract -> TAbstract | TMono _ -> assert() | TPoly -> t2.tid := -2; TMono (genid g) | TRecord tl -> TRecord (List.map (function((n,m,t)) { (n , m, duplicate g h t) }) tl) | TUnion (n,tl) -> TUnion n (List.map (function((n,t)) { (n , duplicate g h t) }) tl) | TTuple tl -> TTuple (List.map (duplicate g h) tl) | TLink t -> TLink (duplicate g h t) | TFun (tl,t) -> TFun (List.map (duplicate g h) tl) (duplicate g h t) | TNamed (n,p,t) -> TNamed n (List.map (duplicate g h) p) (duplicate g h t) }; t2 } } function rec polymorphize(g,mink,t) { if t.tid == -1 then () else match t.texpr { | TAbstract -> () | TMono k -> if k > mink then { t.texpr := TPoly; t.tid := genid g } | TPoly -> () | TRecord fl -> List.iter (function((_,_,t)) { polymorphize g mink t }) fl | TUnion (_,fl) -> List.iter (function((_,t)) { polymorphize g mink t }) fl | TTuple tl -> List.iter (polymorphize g mink) tl | TLink t -> polymorphize g mink t | TFun (tl,t) -> List.iter (polymorphize g mink) tl; polymorphize g mink t | TNamed (_,tl,t) -> List.iter (polymorphize g mink) tl } } neko-2.0.0/src/nekoml/Typer.nml0000644000175000017500000007755312112157473017064 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Nekoml.Ast; open Nekoml.Type; type module_context { mutable file : string; path : string list; types : (string,t) Hashtbl.t; constrs : (string, (t, t)) Hashtbl.t; records : (string, (t, t, mutflag)) Hashtbl.t; deps : (string list, module_context) Hashtbl.t; mutable done : bool; mutable idents : (string,t) Map.t; } type context { gen : id_gen; mutable mink : int; mutable functions : (bool, string, texpr ref, t, (string, t) list, expr, t, pos) list; mutable opens : module_context list; mutable curfunction : string; filecache : (string, string) Hashtbl.t; tmptypes : (string, (t, t list, (string,t) Hashtbl.t)) Hashtbl.t; current : module_context; modules : (string list, module_context) Hashtbl.t; classpath : string list; callback : context -> module_context -> texpr -> void; } type error_msg { Cannot_unify : (t, t); Have_no_field : (t, string); Stack : (error_msg, error_msg); Unknown_field : string; Module_not_loaded : module_context; Custom : string; } exception Error : (error_msg , pos); function rec error_msg_loop(h,m) { match m { | Cannot_unify (t1,t2) -> "Cannot unify " + s_type false h t1 + " and " + s_type false h t2 | Have_no_field (t,f) -> s_type false h t + " have no field " + f | Stack (m1,m2) -> error_msg_loop h m1 + "\n " + error_msg_loop h m2 | Unknown_field s -> "Unknown field " + s | Module_not_loaded m -> "Module " + String.concat "." m.path + " require an interface" | Custom s -> s } } function error_msg(m) { error_msg_loop s_context() m } function s_ttype(t) { s_type false s_context() t } function error(m,p) { throw Error(m,p) } Nekoml.Match.error_ref := (function(msg,p) error Custom(msg) p); var verbose = &false; var load_module_ref = &(function(_,_,_) { assert() }); function add_local(ctx,v,t) { if v != "_" then ctx.current.idents := Map.add ctx.current.idents v t } function save_locals(ctx) { ctx.current.idents } function restore_locals(ctx,l) { ctx.current.idents := l } function module(ctx,path) { Hashtbl.find ctx.modules path } function union(m,c) { fst (Hashtbl.find m.constrs c) } function get_module(ctx,path,p) { match path { | [] -> ctx.current | _ -> var m = try Hashtbl.find ctx.modules path catch { Not_found -> (*load_module_ref) ctx path p }; if m != ctx.current then { if !m.done then error (Module_not_loaded m) p; Hashtbl.replace ctx.current.deps m.path m; }; m } } function get_type(ctx,path,name,p) { function rec loop(l) { match l { | [] -> error Custom("Unknown type " + s_path path name) p | m :: l -> try { Hashtbl.find m.types name } catch { Not_found -> loop l } } } match path { | [] -> loop (ctx.current :: ctx.opens); | _ -> loop [get_module ctx path p] } } function get_constr(ctx,path,name,p) { function rec loop(l) { match l { | [] -> error Custom("Unknown constructor " + s_path path name) p | m :: l -> try { var t1, t2 = Hashtbl.find m.constrs name; (if m == ctx.current then [] else m.path , t1, t2) } catch { Not_found -> loop l } } }; match path { | [] -> loop (ctx.current :: ctx.opens) | _ -> loop [get_module ctx path p] } } function get_ident(ctx,path,name,p) { function rec loop(l) { match l { | [] -> error Custom("Unknown identifier " + s_path path name) p | m :: l -> try (if m == ctx.current then [] else m.path , Map.find m.idents name) catch { Not_found -> loop l } } } match path { | [] -> loop (ctx.current :: ctx.opens) | _ -> loop [get_module ctx path p] } } function get_record(ctx,f,p) { function rec loop(l) { match l { | [] -> error (Unknown_field f) p | m :: l -> try Hashtbl.find m.records f catch { Not_found -> loop l } } } var rt , ft , mut = loop (ctx.current :: ctx.opens); var h = Hashtbl.create(); (duplicate ctx.gen h rt, duplicate ctx.gen h ft, mut) } function rec is_tuple(t) { match t.texpr { | TLink t -> is_tuple t | TTuple _ -> true | TNamed(_,_,t) -> is_tuple t | _ -> false } } function rec is_recursive(t1,t2) { if t1 === t2 then true else match t2.texpr { | TAbstract | TMono _ | TPoly -> false | TRecord _ | TUnion _ -> assert() | TTuple tl -> List.exists (is_recursive t1) tl | TLink t -> is_recursive t1 t | TFun (tl,t) -> List.exists (is_recursive t1) tl || is_recursive t1 t | TNamed (_,p,t) -> List.exists (is_recursive t1) p } } function link(ctx,t1,t2,p) { if is_recursive t1 t2 then error Cannot_unify(t1,t2) p; t1.texpr := TLink t2; if t1.tid < 0 then { if t2.tid == -1 then t1.tid := -1 else t1.tid := genid ctx.gen; } else if t2.tid == -1 then t1.tid := -1 } function unify_stack(t1,t2,e) { match e { | Error ((Cannot_unify _) as e, p) -> error (Stack e Cannot_unify(t1,t2)) p | e -> throw e } } function is_alias(t) { match t { | TAbstract | TRecord _ | TUnion _ -> false | TMono _ | TPoly | TTuple _ | TLink _ | TFun _ | TNamed _ -> true } } function rec propagate(k,t) { match t.texpr { | TAbstract | TPoly -> () | TUnion _ | TRecord _ -> assert() | TMono k2 -> if k < k2 then t.texpr := TMono k | TTuple tl -> List.iter (propagate k) tl | TLink t -> propagate k t | TFun (tl,t) -> propagate k t; List.iter (propagate k) tl | TNamed (_,tl,_) -> List.iter (propagate k) tl } } function rec unify(ctx,t1,t2,p) { if t1 == t2 then () else match (t1.texpr , t2.texpr) { | (TLink t , _) -> unify ctx t t2 p | (_ , TLink t) -> unify ctx t1 t p | (TPoly , _) -> link ctx t1 t2 p | (_ , TPoly) -> link ctx t2 t1 p | (TMono k , _) -> link ctx t1 t2 p; propagate k t2 | (_ , TMono k) -> link ctx t2 t1 p; propagate k t1 | (TNamed (n1,p1,_) , TNamed (n2,p2,_)) when n1 == n2 -> try List.iter2 (function(p1,p2) { unify ctx p1 p2 p }) p1 p2 catch { e -> unify_stack t1 t2 e } | (TNamed (_,_,t1) , _) when is_alias t1.texpr -> try unify ctx t1 t2 p catch { e -> unify_stack t1 t2 e } | (_ , TNamed (_,_,t2)) when is_alias t2.texpr -> try unify ctx t1 t2 p catch { e -> unify_stack t1 t2 e } | (TFun (tl1,r1) , TFun (tl2,r2)) when List.length tl1 == List.length tl2 -> try List.iter2 (function(t1,t2) { unify ctx t1 t2 p }) tl1 tl2; unify ctx r1 r2 p; catch { e -> unify_stack t1 t2 e } | (TTuple tl1 , TTuple tl2) when List.length tl1 == List.length tl2 -> try List.iter2 (function(t1,t2) { unify ctx t1 t2 p }) tl1 tl2 catch { e -> unify_stack t1 t2 e } | _ -> error Cannot_unify(t1,t2) p } } function rec type_type(allow,h,ctx,t,p) { match t { | ETuple [] -> assert() | ETuple [t] -> type_type allow h ctx t p | ETuple el -> mk_tup ctx.gen (List.map (function(t) { type_type allow h ctx t p }) el) | EPoly s -> try Hashtbl.find h s catch { Not_found -> if !allow then error Custom("Unbound type variable '" + s) p; var t = t_mono ctx.gen; Hashtbl.add h s t; t } | EType (param,path,name) -> var param = match param { None -> None | Some t -> Some (type_type allow h ctx t p) }; var t = get_type ctx path name p; match t.texpr { | TNamed (_,params,t2) -> var tl = match (params, param) { | ([] , None) -> [] | ([x] , Some t) -> [t] | (l , Some { texpr = TTuple tl }) when List.length tl == List.length l -> tl | _ -> error Custom("Invalid number of type parameters for " + s_path path name) p }; var h = Hashtbl.create(); var t = duplicate ctx.gen h t; var params = List.map (duplicate ctx.gen h) params; List.iter2 (function(pa,t) { unify ctx pa t p }) params tl; t | _ -> assert() } | EArrow _ -> function rec loop(params,t) { match t { | EArrow (ta,tb) -> var ta = type_type allow h ctx ta p; loop (ta :: params) tb | _ -> var t = type_type allow h ctx t p; mk_fun ctx.gen (List.rev params) t } }; loop [] t } } function rec type_constant(ctx,path,c,p) { match c { | Int i -> mk TConst(TInt i) t_int p | Float s -> mk TConst(TFloat s) t_float p | Bool b -> mk TConst(TBool b) t_bool p | String s -> mk TConst(TString s) t_string p | Char c -> mk TConst(TChar c) t_char p | Ident s -> var path , t = get_ident ctx path s p; var t = duplicate ctx.gen Hashtbl.create() t; mk TConst(TModule path TIdent(s)) t p | Constr s -> var path , ut , t = get_constr ctx path s p; var t = duplicate ctx.gen Hashtbl.create() (match t.texpr { | TAbstract -> ut | TTuple tl -> mk_fun ctx.gen tl ut | _ -> mk_fun ctx.gen [t] ut }); mk TConst(TModule path TConstr(s)) t p | Module (path,c) -> type_constant ctx path c p } } type addable { NInt; NFloat; NString; NNan; } function addable(str,e) { match etype true e { | TNamed (["int"],_,_) -> NInt | TNamed (["float"],_,_) -> NFloat | TNamed (["string"],_,_) when str -> NString | _ -> NNan } } function type_binop(ctx,op,e1,e2,p) { function emk(t) { mk TBinop(op,e1,e2) t p }; match op { | "%" | "+" | "-" | "/" | "*" -> var str = (op == "+"); match (addable str e1, addable str e2) { | (NInt , NInt) -> emk t_int | (NFloat , NFloat) | (NInt , NFloat) | (NFloat , NInt) -> emk t_float | (NInt , NString) | (NFloat , NString) | (NString , NInt) | (NString , NFloat) | (NString , NString) -> emk t_string | (NInt , NNan) | (NFloat , NNan) | (NString , NNan) -> unify ctx e2.etype e1.etype (pos e2); emk e1.etype | (NNan , NInt) | (NNan , NFloat) | (NNan , NString) -> unify ctx e1.etype e2.etype (pos e1); emk e2.etype | (NNan , NNan) -> unify ctx e1.etype t_int (pos e1); unify ctx e2.etype t_int (pos e2); emk t_int } | ">>" | ">>>" | "<<" | "and" | "or" | "xor" -> unify ctx e1.etype t_int (pos e1); unify ctx e2.etype t_int (pos e2); emk t_int | "&&" | "||" -> unify ctx e1.etype t_bool (pos e1); unify ctx e2.etype t_bool (pos e2); emk t_bool | "<" | "<=" | ">" | ">=" | "==" | "!=" | "===" | "!==" -> unify ctx e2.etype e1.etype (pos e2); emk t_bool | ":=" -> match e1.edecl { | TArray _ -> unify ctx e2.etype e1.etype (pos e2); emk t_void | TField (e,f) -> match tlinks false e.etype { | TRecord fl -> var _ , mut , _ = try List.find (function((f2,_,_)) { f2 == f }) fl catch { Not_found -> assert() }; if mut == Immutable then error Custom("Field " + f + " is not mutable") pos(e1); unify ctx e2.etype e1.etype (pos e2); emk t_void | _ -> assert(); } | _ -> var t , pt = t_poly ctx.gen "ref"; unify ctx e2.etype pt (pos e2); unify ctx e1.etype t (pos e1); emk t_void } | "::" -> var t , pt = t_poly ctx.gen "list"; unify ctx e1.etype pt (pos e1); unify ctx e2.etype t (pos e2); var c = mk TConst(TConstr "::") t_mono(ctx.gen) p; mk (TCall c [e1;e2]) t p | _ -> error Custom("Invalid operation " + op) p } } function type_unop(ctx,op,e,p) { function emk(t) { mk TUnop(op,e) t p }; match op { | "&" -> var p , pt = t_poly ctx.gen "ref"; unify ctx e.etype pt (pos e); emk p | "*" -> var p , pt = t_poly ctx.gen "ref"; unify ctx e.etype p (pos e); emk pt | "!" -> unify ctx e.etype t_bool (pos e); emk t_bool | "-" -> match addable false e { | NInt -> emk t_int | NFloat -> emk t_float | _ -> unify ctx e.etype t_int (pos e); emk t_int } | _ -> assert() } } function rec type_arg(ctx,h,binds,p,a) { match a { | ATyped (a,t) -> var n , ta = type_arg ctx h binds p a; unify ctx ta (type_type true h ctx t p) p; (n , ta) | ANamed s -> (s , t_mono ctx.gen) | ATuple al -> var aname = "@t" + string (genid ctx.gen); var nl , tl = List.split (List.map (type_arg ctx h binds p) al); var k = &0; List.iter (function(n) { if n != "_" then binds := (aname,*k,n) :: *binds; k := *k + 1; }) nl; (aname , mk_tup ctx.gen tl) } } function register_function(ctx,isrec,name,pl,e,rt,p) { if ctx.functions == [] then ctx.mink := *ctx.gen; var pl = match pl { | [] -> [ATyped (ANamed "_") EType(None,[],"void")] | _ -> pl }; var expr = &(mk (TConst TVoid) t_void p); var h = Hashtbl.create(); var binds = &[]; var el = List.map (type_arg ctx h binds p) pl; var name = match name { None -> "_" | Some n -> n }; var e = match List.rev (*binds) { | [] -> e | l -> var b = List.fold (function(acc,(v,n,v2)) { var tget = ETupleGet (EConst Ident(v),p) n; (EVar [(v2,None)] (tget,p) , p) :: acc }) [e] l; (EBlock b , p) }; var rt = match rt { | None -> t_mono ctx.gen | Some rt -> type_type true h ctx rt p }; var ft = mk_fun ctx.gen (List.map snd el) rt; ctx.functions := (isrec,name,expr,ft,el,e,rt,p) :: ctx.functions; if isrec then add_local ctx name ft; mk (TMut expr) (if name == "_" then ft else t_void) p } function type_format(ctx,s,p) { var types = &[]; var percent = &false; var i = &0; var l = String.length s; while *i < l { var c = String.get s (*i); if *percent then { percent := false; match c { | '%' -> () | 'x' | 'X' | 'd' -> types := t_int :: *types | 'f' -> types := t_float :: *types | 's' -> types := t_string :: *types | 'b' -> types := t_bool :: *types | 'c' -> types := t_char :: *types | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '.' -> percent := true | _ -> error (Custom "Invalid % sequence") p } } else match c { | '%' -> percent := true | _ -> () } i := *i + 1; }; if *percent then error (Custom "Invalid % sequence") p; match *types { | [] -> t_void | [x] -> x | l -> mk_tup ctx.gen (List.rev l) } } function rec type_functions(ctx) { var l = ctx.functions; if l != [] then { var mink = ctx.mink; ctx.functions := []; var l = List.map (function((isrec,name,expr,ft,el,e,rt,p)) { var locals = save_locals ctx; var func = ctx.curfunction; if name != "_" then { var fname = s_path ctx.current.path name; if *verbose then print ("Typing "+fname+"\n"); ctx.curfunction := fname; } List.iter (function((p,pt)) { add_local ctx p pt }) el; var e = type_expr ctx e; restore_locals ctx locals; ctx.curfunction := func; var ft2 = mk_fun ctx.gen (List.map snd el) e.etype; unify ctx ft ft2 p; expr := mk TFunction(isrec,name,el,e) ft2 p; if !isrec then add_local ctx name ft; (name == "_" , ft2) }) (List.rev l); List.iter (function((anon,t)) { if !anon then polymorphize ctx.gen mink t }) l } } function rec type_expr(ctx,(e,p)) { match e { | EConst c -> type_constant ctx [] c p | EBlock [] -> mk TConst(TVoid) t_void p | EBlock (e :: l) -> var locals = save_locals ctx; var e = type_block ctx e; var el , t = List.fold (function((l,t),e) { unify ctx t t_void (List.hd l).epos; var e = type_block ctx e; (e :: l , e.etype) }) ([e] , e.etype) l; type_functions ctx; restore_locals ctx locals; mk TBlock(List.rev el) t p | EApply (e,el) -> type_expr ctx (ECall e el,p) | ECall ((EConst (Ident "open"),_),[(EConst (Module (m,Constr modname)),p)]) -> ctx.opens := get_module ctx (List.append m [modname]) p :: ctx.opens; mk (TConst TVoid) t_void p | ECall ((EConst (Ident "open"),_),[(EConst (Constr modname),p)]) -> ctx.opens := get_module ctx [modname] p :: ctx.opens; mk (TConst TVoid) t_void p | ECall ((EConst (Ident "assert"),_) as a,[]) -> type_expr ctx (ECall a [(EConst (String p.psource),p);(EConst (Int p.pline),p)], p) | ECall ((EConst (Ident "invalid_arg"),_) as a,[]) -> type_expr ctx (ECall a [(EConst (String ctx.curfunction),p)], p) | ECall ((EConst (Constr "TYPE"),_),[e]) -> var e = type_expr ctx e; printf "%s:(%d): type : %s\n" (p.psource,p.pline,s_type true s_context() e.etype); mk (TParenthesis e) t_void p | ECall (e,el) -> var e = type_expr ctx e; var el = match el { [] -> [(ETupleDecl [],p)] | _ -> el }; var el = List.map (type_expr ctx) el; match etype false e { | TFun (args,r) -> function rec loop(acc,expr,l,tl,r) { match (l , tl) { | (e :: l , t :: tl) -> match tlinks true t { | TNamed (["format"],[param],_) -> match e.edecl { | TConst (TString s) -> var tfmt = type_format ctx s e.epos; unify ctx param tfmt e.epos; | _ -> match tlinks true e.etype { | TNamed (["format"],[param2],_) -> unify ctx param2 param e.epos | _ -> error Custom("Constant string required for format") e.epos } } | _ -> unify ctx e.etype t (pos e) } loop (e :: acc) expr l tl r | ([] , []) -> mk TCall(expr,List.rev acc) r p | ([] , tl) -> mk TCall(expr,List.rev acc) (mk_fun ctx.gen tl r) p | (el , []) -> match tlinks false r { | TFun (args,r2) -> loop [] (mk TCall(expr,List.rev acc) r p) el args r2 | _ -> error Custom("Too many arguments") p } | _ -> assert() } } loop [] e el args r | _ -> var r = t_mono ctx.gen; var f = mk_fun ctx.gen (List.map (function(e) { e.etype }) el) r; unify ctx e.etype f p; mk TCall(e,el) r p } | EField (e,s) -> var e = type_expr ctx e; var t = match etype false e { | TRecord fl -> try { var _ , _ , t = List.find (function((s2,_,_)) { s == s2 }) fl; t } catch { Not_found -> error Have_no_field(e.etype,s) p } | _ -> var r , t , _ = get_record ctx s p; unify ctx e.etype r (pos e); t }; mk TField(e,s) t p | EArray (e,ei) -> var e = type_expr ctx e; var ei = type_expr ctx ei; unify ctx ei.etype t_int (pos ei); var t , pt = t_poly ctx.gen "array"; unify ctx e.etype t (pos e); mk TArray(e,ei) pt p | EVar _ -> error Custom("Variable declaration not allowed outside a block") p | EIf (e,e1,None) -> var e = type_expr ctx e; unify ctx e.etype t_bool (pos e); var e1 = type_expr ctx e1; unify ctx e1.etype t_void (pos e1); mk TIf(e,e1,None) t_void p | EIf (e,e1,Some e2) -> var e = type_expr ctx e; unify ctx e.etype t_bool (pos e); var e1 = type_expr ctx e1; var e2 = type_expr ctx e2; unify ctx e2.etype e1.etype (pos e2); mk TIf(e,e1,Some e2) e1.etype p | EWhile (e1,e2) -> var e1 = type_expr ctx e1; unify ctx e1.etype t_bool (pos e1); var e2 = type_expr ctx e2; unify ctx e2.etype t_void (pos e2); mk TWhile(e1,e2) t_void p | EFunction (isrec,name,pl,e,rt) -> var r = register_function ctx isrec name pl e rt p; type_functions ctx; r | EBinop (op,e1,e2) -> type_binop ctx op (type_expr ctx e1) (type_expr ctx e2) p | ETypeAnnot (e,t) -> var e = type_expr ctx e; var t = type_type true Hashtbl.create() ctx t p; unify ctx e.etype t (pos e); mk e.edecl t p | ETupleDecl [] -> mk TConst(TVoid) t_void p | ETupleDecl [e] -> var e = type_expr ctx e; mk TParenthesis(e) e.etype (pos e) | ETupleDecl el -> var el = List.map (type_expr ctx) el; mk TTupleDecl(el) (mk_tup ctx.gen (List.map (function(e) { e.etype }) el)) p | ETypeDecl (params,tname,decl) -> var fullname = match ctx.current.path { ["Core"] -> [tname] | p -> List.append p [tname]}; var t , tl , h = try { var t , tl , h = Hashtbl.find ctx.tmptypes tname; if decl != EAbstract then Hashtbl.remove ctx.tmptypes tname; if List.length tl != List.length params then error Custom("Invalid number of parameters for type " + tname) p; (t , tl , h) } catch { Not_found -> if Hashtbl.exists ctx.current.types tname then error Custom("Invalid type redefinition of type " + tname) p; var h = Hashtbl.create(); var tl = List.map (function(p) { var t = t_mono ctx.gen; Hashtbl.add h p t; t }) params; var t = { tid = -1; texpr = TNamed fullname tl t_abstract; }; Hashtbl.add ctx.current.types tname t; if decl == EAbstract then Hashtbl.add ctx.tmptypes tname (t,tl,h); (t , tl , h) }; var t2 = match decl { | EAbstract -> t_abstract | EAlias t -> type_type false h ctx t p | ERecord fields -> var fields = List.map (function((f,m,ft)) { var ft = type_type false h ctx ft p; var m = (if m then Mutable else Immutable); Hashtbl.add ctx.current.records f (t,ft,m); (f , m , ft) }) fields; mk_record ctx.gen fields | EUnion constr -> var constr = List.map (function((c,ft)) { var ft = match ft { | None -> t_abstract | Some ft -> type_type false h ctx ft p }; Hashtbl.add ctx.current.constrs c (t,ft); (c , ft) }) constr; mk_union ctx.gen constr }; t.tid := if t2.tid == -1 && params == [] then -1 else genid ctx.gen; t.texpr := TNamed fullname tl t2; polymorphize ctx.gen 0 t; mk TTypeDecl(t) t_void p | ERecordDecl fl -> var s , _ = try List.hd fl catch { _ -> assert() }; var r , _ , _ = get_record ctx s p; var fll = match tlinks false r { | TRecord fl -> fl | _ -> assert() }; var fl2 = &fll; function rec loop(f,l) { match l { | [] -> if List.exists (function((f2,_,_)) { f == f2 }) fll then error Custom("Duplicate declaration for field " + f) p else error Have_no_field(r,f) p | (f2,_,ft) :: l when f == f2 -> (ft , l) | x :: l -> var t , l = loop f l; (t , x :: l) } } var el = List.map (function((f,e)) { var ft , fl2b = loop f (*fl2); fl2 := fl2b; var e = type_expr ctx e; unify ctx e.etype ft (pos e); (f , e) }) fl; List.iter (function((f,_,_)) { error Custom("Missing field " + f + " in record declaration") p; }) (*fl2); mk (TRecordDecl el) r p | EErrorDecl (name,t) -> var t = match t { None -> t_abstract | Some t -> type_type false Hashtbl.create() ctx t p }; Hashtbl.add ctx.current.constrs name (t_error,t); mk TErrorDecl(name,t) t_void p | EUnop (op,e) -> type_unop ctx op (type_expr ctx e) p | EMatch (e,cl) -> var e = type_expr ctx e; var is_stream = match cl { [] -> false | _ -> List.all (function((l,_,_)) { List.all (function((p,_)) { match p { PStream _ -> true | _ -> false }}) l}) cl }; var partial , m , t = type_match ctx e.etype cl p; if !is_stream && partial then error Custom("This matching is not complete") p; mk TMatch(e,m,is_stream) t p | ETry (e,cl) -> var e = type_expr ctx e; var _ , m , t = type_match ctx t_error cl p; unify ctx t e.etype p; mk TTry(e,m) t p | ETupleGet (e,n) -> var e = type_expr ctx e; function try_unify(et) { var t = Array.init (n + 1) (function(_) { t_mono ctx.gen }); unify ctx et (mk_tup ctx.gen (Array.list t)) p; t.[n] } function rec loop(et) { match et.texpr { | TLink et -> loop et | TTuple l -> try List.nth l n catch { _ -> try_unify et } | _ -> try_unify et } } mk TTupleGet(e,n) (loop e.etype) p } } function rec type_block(ctx,x) { var e , p = x; match e { | EVar (vl,e) -> type_functions ctx; var e = type_expr ctx e; function make(v,t) { var t = match t { | None -> t_mono ctx.gen | Some t -> type_type true Hashtbl.create() ctx t p } add_local ctx v t; t } var t = match vl { | [] -> assert() | [(v,t)] -> make v t | _ -> mk_tup ctx.gen (List.map (function((v,t)) { make v t }) vl) } unify ctx t e.etype (pos e); mk TVar(List.map fst vl,e) t_void p | EFunction (true,name,pl,e,rt) -> register_function ctx true name pl e rt p | _ -> type_functions ctx; type_expr ctx x } } function rec type_pattern(ctx,h,h2,set,add,(pat,p)) { function pvar(add,s) { if Set.exists (*set) s then error Custom("This variable is several time in the pattern") p; set := Set.add (*set) s; try Hashtbl.find h s catch { Not_found -> var t = t_mono ctx.gen; Hashtbl.add h s t; if add then add_local ctx s t; t } } var pt , pat = match pat { | PConst c -> (match c { | Int n -> t_int | Float s -> t_float | String s -> t_string | Char c -> t_char | Bool b -> t_bool | Ident _ | Constr _ | Module _ -> assert() } , pat) | PTuple [p] -> var pt , pat = type_pattern ctx h h2 set add p; (pt , fst pat) | PTuple pl -> var pl , patl = List.split (List.map (type_pattern ctx h h2 set add) pl); (mk_tup ctx.gen pl , PTuple patl) | PRecord (fl,_) -> var s = try fst (List.hd fl) catch { _ -> assert() }; var r , _ , _ = get_record ctx s p; var fl = match tlinks false r { | TRecord rl -> List.map (function((f,pat)) { var pt , pat = type_pattern ctx h h2 set add pat; var t = try { var _ , _ , t = List.find (function((f2,_,_)) { f == f2 }) rl; t } catch { Not_found -> error Have_no_field(r,f) p }; unify ctx pt t (snd pat); (f , pat) }) fl | _ -> assert() }; (r , PRecord fl magic(r)) | PIdent s -> (if s == "_" then t_mono ctx.gen else pvar add s , pat) | PConstr (path,s,param) -> var tparam , param = match param { | None -> (None , None ) | Some ((_,p) as param) -> var t , pat = type_pattern ctx h h2 set add param; (Some (p,t) , Some pat) } var path , ut , t = get_constr ctx path s p; match (t.texpr , tparam) { | (TAbstract , None) -> (duplicate ctx.gen Hashtbl.create() ut , PConstr path s param) | (TAbstract , Some _) -> error Custom("Constructor does not take parameters") p | (_ , None) -> error Custom("Constructor require parameters") p | (_ , Some (p,pt)) -> var h = Hashtbl.create(); var ut = duplicate ctx.gen h ut; var t = duplicate ctx.gen h t; var param , pt = match param { | Some (PTuple l,p) when !is_tuple t -> (Some (PTuple [(PTuple l,p)],p) , mk_fun ctx.gen [pt] ut) | Some (PIdent "_",p) -> (param , pt) | _ -> (param , match pt.texpr { TTuple l -> mk_fun ctx.gen l ut | _ -> mk_fun ctx.gen [pt] ut }) } var t = match t.texpr { TTuple l -> mk_fun ctx.gen l ut | _ -> mk_fun ctx.gen [t] ut }; unify ctx t pt p; (ut , PConstr path s param) } | PAlias (s,pat) -> var pt , pat = type_pattern ctx h h2 set false pat; var t = pvar false s; unify ctx pt t (snd pat); (t , PAlias s pat) | PTyped (pat,t) -> var pt , pat = type_pattern ctx h h2 set add pat; unify ctx pt (type_type true h2 ctx t p) p; (pt , PTyped pat t) | PStream (l,k) -> var t , polyt = t_poly ctx.gen "stream"; var locals = save_locals ctx; var l = List.map (function(s) { match s { | SPattern pat -> var t , p = type_pattern ctx h h2 set true pat; unify ctx t polyt (snd p); SPattern p | SExpr ([v],e) -> var e = type_expr ctx e; var t = pvar true v; unify ctx t e.etype e.epos; SMagicExpr (PIdent v,e.epos) magic(e) | SExpr (vl,e) -> var e = type_expr ctx e; var tl = List.map (pvar true) vl; unify ctx (mk_tup ctx.gen tl) e.etype e.epos; var tup = PTuple (List.map (function(v) { (PIdent v, e.epos) }) vl); SMagicExpr (tup,e.epos) magic(e) | SMagicExpr _ -> assert() } }) l; restore_locals ctx locals; (t , PStream l k) } (pt , (pat,p)) } function rec type_match(ctx,t,cl,p) { var ret = t_mono ctx.gen; var cl = List.map (function((pl,wh,pe)) { var first = &true; var h = Hashtbl.create(); var mainset = &Set.empty(); var pl = List.map (function(pat) { var set = &Set.empty(); var pt , pat = type_pattern ctx h Hashtbl.create() set false pat; if *first then { first := false; mainset := *set; } else { var s1 = Set.diff (*set) (*mainset); var s2 = Set.diff (*mainset) (*set); Set.iter (function(s) { error Custom("Variable " + s + " must occur in all patterns") p }) (Set.union s1 s2); } unify ctx pt t p; pat }) pl; var locals = save_locals ctx; Hashtbl.iter (function(v,t) { add_local ctx v t }) h; var wh = match wh { | None -> None | Some e -> var e = type_expr ctx e; unify ctx e.etype t_bool e.epos; Some e } var pe = type_expr ctx pe; unify ctx pe.etype ret (pos pe); restore_locals ctx locals; (pl , wh , pe) }) cl; Nekoml.Match.fully_matched_ref := (function(cl) { match cl { | (TModule(path,TConstr c)) :: l -> var path , ut , t = get_constr ctx path c Lexer.null_pos; if ut == t_error then false else match tlinks false ut { | TUnion (n,_) -> n == List.length cl | _ -> assert() } | TVoid :: _ -> true | _ -> false } }); var partial , m = Nekoml.Match.make cl p; (partial , m , ret) } function module_infos(m) { var h = Hashtbl.create(); var deps = &(if m.path == ["Core"] || Hashtbl.exists m.deps ["Core"] then [] else [["Core"]]); var idents = &[]; Hashtbl.iter (function(_,m) { deps := m.path :: *deps }) m.deps; Map.iter (function(i,t) { idents := i :: *idents }) m.idents; (m.path,*deps,*idents) } function open_file(ctx,m,p) { var file = file_name m ".nml"; function rec loop(l) { match l { | [] -> try { (file, IO.read_string (Hashtbl.find ctx.filecache (String.concat "." m))) } catch { Not_found -> error Custom("File not found " + file) p } | pp :: l -> try { var f = pp + file; (f , IO.read_file f true) } catch { _ -> loop l } } } loop ctx.classpath } function load_module(ctx,m,p) { try Hashtbl.find ctx.modules m catch { Not_found -> var file , ch = open_file ctx m p; var is_core , core = try (false , Hashtbl.find ctx.modules ["Core"]) catch { Not_found -> ctx.current.file := file; (true , ctx.current) } var ctx = { mink = ctx.mink; gen = ctx.gen; modules = ctx.modules; classpath = ctx.classpath; callback = ctx.callback; filecache = ctx.filecache; curfunction = "anonymous"; tmptypes = Hashtbl.create(); functions = []; opens = [core]; current = if is_core then ctx.current else { file = file; path = m; constrs = Hashtbl.create(); records = Hashtbl.create(); types = Hashtbl.create(); done = false; idents = Map.empty(); deps = Hashtbl.create(); } }; Hashtbl.add ctx.modules m ctx.current; var lex = Lexer.create Buffer.create(); Lexer.input lex file ch 1 0; var ast = Nekoml.Parser.parse lex; if *verbose then printf "Parsed %s\n" file; var e = match ast { | (EBlock (e :: l) , p) -> var e = type_block ctx e; var el , t = List.fold (function((l,t),e) { var e = type_block ctx e; (e :: l , e.etype) }) ([e] , e.etype) l; type_functions ctx; mk TBlock(List.rev el) t p | _ -> type_expr ctx ast } if *verbose then printf "Typing done with %s\n" file; ctx.current.done := true; ctx.callback ctx ctx.current e; ctx.current } } function context(cpath,filecache,callb) { var ctx = { gen = generator(); tmptypes = Hashtbl.create(); modules = Hashtbl.create(); filecache = filecache; functions = []; opens = []; mink = 0; classpath = cpath; curfunction = "anonymous"; callback = callb; current = { file = ""; path = ["Core"]; done = false; idents = Map.empty(); constrs = Hashtbl.create(); types = Hashtbl.create(); deps = Hashtbl.create(); records = Hashtbl.create(); }; }; function add_type(args,name,t) { ignore(type_expr ctx (ETypeDecl args name t, Lexer.null_pos)); } function add_variable(name,t) { ctx.current.idents := Map.add ctx.current.idents name t } add_type [] "bool" EUnion([("true",None);("false",None)]); add_type ["a"] "list" (EUnion [("[]",None);("::",Some (ETuple [ EPoly "a"; EType Some(EPoly "a") [] "list"; ]))]); add_variable "neko" (mk_fun ctx.gen [t_polymorph ctx.gen] (t_polymorph ctx.gen)); var core = load_module ctx ["Core"] Lexer.null_pos; ctx } load_module_ref := load_module neko-2.0.0/src/nekoml/Parser.nml0000644000175000017500000003515012112157473017200 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Nekoml.Ast type error_msg { Unexpected : token; Unclosed : string; } exception Error : (error_msg , pos) function error_msg(msg) { match msg { | Unexpected t -> "Unexpected " + s_token t | Unclosed s -> "Unclosed " + s } } var punion = Lexer.punion; function error(m,p) { throw Error(m,p) } function priority(op) { match op { | "+=" | "-=" | "*=" | "/=" | "|=" | "&=" | "^=" | ":=" -> -3 | "&&" | "||" -> -2 | "==" | "!=" | ">" | "<" | "<=" | ">=" | "===" | "!==" | "<>" | "=" -> -1 | "+" | "-" -> 0 | "*" | "/" -> 1 | "or" | "and" | "xor" -> 2 | "<<" | ">>" | "%" | ">>>" -> 3 | _ -> 4 } } function can_swap(_op,op) { var p1 = priority _op; var p2 = priority op; if p1 < p2 then true else if p1 == p2 then op != "::" else false } function rec make_binop(op,e,e2) { var v , p2 = e2; match v { | EBinop (_op,_e,_e2) when can_swap _op op -> var _e = make_binop op e _e; (EBinop _op _e _e2 , punion (pos _e) (pos _e2)) | _ -> (EBinop op e e2 , punion (pos e) (pos e2)) } } function rec make_unop(op,e,p1) { var v , p2 = e; match v { | EBinop (bop,e,e2) -> ( EBinop bop (make_unop op e p1) e2 , punion p1 p2) | _ -> (EUnop op e, punion p1 p2) } } function rec make_list_pat(p,l) { match l { | [] -> (PConstr [] "[]" None , p) | x :: l -> var p = snd x; var params = (PTuple [x;make_list_pat p l] , p); (PConstr [] "::" Some(params) , p) } } function rec make_list(p,l) { match l { | [] -> (EConst Constr("[]") , p) | x :: l -> var p = snd x; (ECall (EConst Constr("::"), p) [x;make_list p l] , p) } } function is_unop(op) { match op { | "-" | "*" | "!" | "&" -> true | _ -> false } } function unclosed(s,p) { error (Unclosed s) p } function mk(e,p) { (e,p) } function rec program(s) { match s { | [< e = expr s; p = program s >] -> e :: p | [< (Semicolon,_); p = program s >] -> p | [< (Eof,_) >] -> [] } } function rec expr(s) { match s { | [< (BraceOpen,p1); e = block1 s >] -> match s { | [< (BraceClose,p2) >] -> mk e punion(p1,p2) | [< (Eof,_) >] -> unclosed "{" p1 } | [< (Keyword Var,p1); (Const (Ident name),_); t = type_opt s; l = vars s; e = expr s >] -> mk EVar((name,t) :: l,e) punion(p1,pos e) | [< (Keyword If,p1); cond = expr s; (Keyword Then,_); e = expr s >] -> match s { | [< (Keyword Else,_); e2 = expr s >] -> mk EIf(cond,e,Some e2) punion(p1,pos e2) | [< >] -> mk EIf(cond,e,None) punion(p1,pos e) } | [< (Keyword Function,p1); r = function_rec s; n = ident_opt s; (ParentOpen _,po); p = parameters_decl s; t = type_opt s; e = expr s >] -> mk EFunction(r,n,p,e,t) punion(p1,pos e) | [< (Keyword Type,p1); pl = type_decl_parameters s; (Const (Ident tname),p2); d , p3 = type_declaration p2 s >] -> mk ETypeDecl(pl,tname,d) punion(p1,p3) | [< (Keyword Exception,p1); (Const (Constr ename),p2); t = type_opt s >] -> mk EErrorDecl(ename,t) punion(p1,p2) | [< (Keyword Match,p1); e = expr s; (BraceOpen,po); pl = patterns_begin s >] -> match s { | [< (BraceClose,pe) >] -> mk EMatch(e,pl) punion(p1,pe) | [< (Eof,_) >] -> unclosed "{" po } | [< (Keyword Try,p1); b = block s; (Keyword Catch,p2); (BraceOpen,po); pl = patterns_begin s >] -> match s { | [< (BraceClose,pe); >] -> mk ETry((EBlock b,punion p1 p2),pl) punion(p1,pe) | [< (Eof,_) >] -> unclosed "{" po } | [< (Keyword While,p1); e = expr s; (BraceOpen,po); b = block s >] -> match s { | [< (BraceClose,pe) >] -> mk EWhile(e,(EBlock b,punion po pe)) punion(po,pe) | [< (Eof,_) >] -> unclosed "{" po } | [< e = expr_short s >] -> e } } function rec expr_short(s) { match s { | [< (ParentOpen _,p1); pl = parameters s >] -> match s { | [< (ParentClose,p2) >] -> expr_next (ETupleDecl pl,punion p1 p2) s | [< (Eof,_) >] -> unclosed "(" p1 } | [< (Binop op,p) >] -> if ! is_unop op then throw Stream_error; match s { | [< e = expr s >] -> expr_next (make_unop op e p) s } | [< (Const (Constr n),p); e = expr_constr n p s >] -> expr_next e s | [< (Const c,p) >] -> expr_next (EConst c,p) s | [< (BracketOpen,p1); b = block s; (BracketClose,p2) >] -> expr_next (make_list (punion p1 p2) b) s } } function rec expr_next(e,s) { match s { | [< (Binop ":",_); t , p = type_path s >] -> expr_next (ETypeAnnot e t,punion (pos e) p) s | [< (ParentOpen false,po); pl = parameters s >] -> match s { | [< (ParentClose,p) >] -> expr_next (ECall e pl,punion (pos e) p) s | [< (Eof,_) >] -> unclosed "(" po } | [< (Dot,_) >] -> match s { | [< (Const (Ident name),p) >] -> expr_next (EField e name,punion (pos e) p) s | [< (BracketOpen,po); e2 = expr s >] -> match s { | [< (BracketClose,p) >] -> expr_next (EArray e e2,punion (pos e) p) s | [< (Eof,_) >] -> unclosed "[" po } } | [< (Binop op,_); e2 = expr s >] -> make_binop op e e2 | [< ep = expr_short s >] -> function rec loop(ep) { var p = pos ep; match fst ep { | EApply (e2,l) -> mk EApply(e,e2 :: l) punion(pos e,p) | EBinop (op,e1,e2) -> mk EBinop(op,loop e1,e2) punion(pos e,p) | _ -> mk EApply(e,[ep]) punion(pos e,pos ep) } } loop ep | [< >] -> e } } function rec expr_constr(n,p,s) { match s { | [< (Dot,_); e , p2 = expr_constr2 s >] -> match e { | EConst ((Ident _) as c) | EConst ((Constr _) as c) -> mk EConst(Module [n] c) punion(p,p2) | EConst (Module (l,c)) -> mk EConst(Module (n :: l) c) punion(p,p2) | _ -> assert() } | [< >] -> mk EConst(Constr n) p } } function rec expr_constr2(s) { match s { | [< (Const (Ident n),p) >] -> mk EConst(Ident n) p | [< (Const (Constr n),p); e = expr_constr n p s >] -> e } } function rec block1(s) { match s { | [< (Const (Ident name),p) >] -> match s { | [< (Binop "=",_); e = expr s; l = record_fields s >] -> ERecordDecl ((name,e) :: l) | [< e = expr_next (EConst (Ident name),p) s; b = block s >] -> EBlock (e :: b) } | [< b = block s >] -> EBlock b } } function rec record_fields(s) { match s { | [< (Const (Ident name),_); (Binop "=",_); e = expr s; l = record_fields s >] -> (name,e) :: l | [< (Semicolon,_); l = record_fields s >] -> l | [< >] -> [] } } function rec vars(s) { match s { | [< (Binop "=",_) >] -> [] | [< (Comma,_); (Const (Ident name),_); t = type_opt s; l = vars s >] -> (name,t) :: l } } function rec block(s) { match s { | [< e = expr s; b = block s >] -> e :: b | [< (Semicolon,_); b = block s >] -> b | [< >] -> [] } } function rec parameters_decl(s) { match s { | [< (Const (Ident name),_) >] -> parameters_decl_next (ANamed name) s | [< (ParentOpen _,_); l = parameters_decl s >] -> parameters_decl_next (ATuple l) s | [< (ParentClose,_) >] -> [] } } function rec parameters_decl_next(acc,s) { match s { | [< (Comma,_); p = parameters_decl s >] -> acc :: p | [< (Binop ":",_); t , _ = type_path s >] -> parameters_decl_next ATyped(acc,t) s | [< (ParentClose,_) >] -> [acc] } } function rec type_opt(s) { match s { | [< (Binop ":",_); t , _ = type_path s >] -> Some t | [< >] -> None } } function rec function_rec(s) { match s { | [< (Const (Ident "rec"),_) >] -> true | [< >] -> false } } function rec ident_opt(s) { match s { | [< (Const (Ident name),_) >] -> Some name | [< >] -> None } } function rec parameters(s) { match s { | [< e = expr s; p = parameters_next s >] -> e :: p | [< >] -> [] } } function rec parameters_next(s) { match s { | [< (Comma,_); p = parameters s >] -> p | [< >] -> [] } } function rec type_path(s) { match s { | [< (Const (Ident tname),p) >] -> type_path_next EType(None,[],tname) p s | [< (Const (Constr m),p); (Dot,_); l = type_path_mod s; (Const (Ident tname),_) >] -> type_path_next EType(None,m :: l,tname) p s | [< (Quote,_); (Const (Ident a),p) >] -> type_path_next (EPoly a) p s | [< (ParentOpen _,_); t , p = type_path s; l , p2 = type_path_list_next p s; (ParentClose,_) >] -> type_path_next (ETuple (t :: l)) p2 s } } function rec type_path_list(p,s) { match s { | [< t , p = type_path s; l , p2 = type_path_list_next p s >] -> mk (t :: l) p2 } } function rec type_path_list_next(p,s) { match s { | [< (Comma,_); t = type_path_list p s >] -> t | [< >] -> ([] , p) } } function rec type_path_next(t,p,s) { match s { | [< (Arrow,_); t2 , p = type_path s >] -> mk EArrow(t,t2) p | [< (Const (Ident tname),p) >] -> type_path_next EType(Some t,[],tname) p s | [< (Const (Constr m),p); (Dot,_); l = type_path_mod s; (Const (Ident tname),_) >] -> type_path_next EType(Some t,m :: l,tname) p s | [< >] -> (t , p) } } function rec type_path_mod(s) { match s { | [< (Const (Constr m),_); (Dot,_); l = type_path_mod s >] -> m :: l | [< >] -> [] } } function rec type_decl_parameters(s) { match s { | [< (Quote,_); (Const (Ident a),_); >] -> [a] | [< (ParentOpen _,_); l = type_decl_plist s; (ParentClose,_); >] -> l | [< >] -> [] } } function rec type_decl_plist(s) { match s { | [< (Quote,_); (Const (Ident a),_); l = type_decl_plist_next s >] -> a :: l } } function rec type_decl_plist_next(s) { match s { | [< (Comma,_); l = type_decl_plist s >] -> l | [< >] -> [] } } function rec type_declaration(p,s) { match s { | [< (BraceOpen,_) >] -> match s { | [< el , p = record_declaration false s >] -> mk ERecord(el) p | [< el , p = union_declaration s >] -> mk EUnion(el) p } | [< (Binop "=",_); t , p = type_path s >] -> mk EAlias(t) p | [< >] -> mk EAbstract p } } function rec record_declaration(mut,s) { match s { | [< (BraceClose,p) >] -> mk [] p | [< (Const (Ident "mutable"),_); l = record_declaration true s >] -> l | [< (Semicolon,_); l = record_declaration false s >] -> l | [< (Const (Ident name),_); (Binop ":",_); t , _ = type_path s; l , p = record_declaration false s >] -> mk ((name,mut,t) :: l) p } } function rec union_declaration(s) { match s { | [< (BraceClose,p) >] -> mk [] p | [< (Semicolon,_); l = union_declaration s >] -> l | [< (Const (Constr name),_); t = type_opt s; l , p = union_declaration s >] -> mk ((name,t) :: l) p } } function rec patterns_begin(s) { match s { | [< (Vertical,_); l = patterns s >] -> l | [< l = patterns s >] -> l } } function rec patterns(s) { match s { | [< p = pattern s; pl = pattern_next s; w = when_clause s; (Arrow,pa); b = block s; l = patterns_begin s >] -> var pat = (p :: pl,w,match b { [e] -> e | _ -> mk EBlock(b) pa }); pat :: l | [< >] -> [] } } function rec pattern_next(s) { match s { | [< (Vertical,_); p = pattern s; l = pattern_next s >] -> p :: l | [< >] -> [] } } function rec pattern(s) { match s { | [< d , p = pattern_decl s >] -> match s { | [< (Const (Ident "as"),_); (Const (Ident v),p2) >] -> mk PAlias(v,(d,p)) punion(p,p2) | [< (Binop "::",_); d2 , p2 = pattern s >] -> mk PConstr([],"::",Some (PTuple [(d,p);(d2,p2)] , punion p p2)) punion(p,p2) | [< t = type_opt s >] -> match t { | None -> mk d p | Some t -> mk PTyped((d,p),t) p } } } } function rec pattern_decl(s) { match s { | [< (ParentOpen _,p1); pl = pattern_tuple s; (ParentClose,p2) >] -> mk PTuple(pl) punion(p1,p2) | [< (BraceOpen,p1); (Const (Ident name),_); (Binop "=",_); p = pattern s; pl = pattern_record s; (BraceClose,p2) >] -> mk PRecord((name,p) :: pl,0) punion(p1,p2) | [< (Const (Constr name),p1); l, name2, p2 = pattern_mod_path name p1 s; p , p3 = pattern_opt p2 s >] -> mk PConstr(l,name2,p) punion(p1,p3) | [< (Const (Ident i),p); >] -> mk PIdent(i) p | [< (Const c,p); >] -> mk PConst(c) p | [< (Binop "-",p1); (Const (Int i),p2) >] -> mk PConst(Int (-i)) punion(p1,p2) | [< (BracketOpen,p1); l = pattern_list s; (BracketClose,p2) >] -> make_list_pat (punion p1 p2) l | [< (StreamOpen,p1); l = stream_list s; (StreamClose,p2) >] -> mk PStream(l,0) punion(p1,p2) } } function rec pattern_mod_path(name,p,s) { match s { | [< (Dot,_); (Const (Constr n),p); l, n2, p2 = pattern_mod_path n p s >] -> (name :: l , n2 , p2) | [< >] -> ([], name, p) } } function rec stream_list(s) { match s { | [< (Const (Ident v),p1) >] -> match s { | [< l = stream_ident_list s; e = expr s >] -> SExpr(v :: l,e) :: stream_next s | [< >] -> SPattern (PIdent v,p1) :: stream_next s } | [< p = pattern s; l = stream_next s >] -> SPattern p :: l | [< >] -> [] } } function rec stream_ident_list(s) { match s { | [< (Comma,_); (Const (Ident v),_); l = stream_ident_list s >] -> v :: l | [< (Binop "=",_) >] -> [] } } function rec stream_next(s) { match s { | [< (Semicolon,_); l = stream_list s >] -> l | [< >] -> [] } } function rec pattern_list(s) { match s { | [< p = pattern s; l = pattern_list_next s >] -> p :: l | [< >] -> [] } } function rec pattern_list_next(s) { match s { | [< (Semicolon,_); l = pattern_list s >] -> l | [< >] -> [] } } function rec pattern_tuple(s) { match s { | [< p = pattern s; l = pattern_tuple_next s >] -> p :: l | [< >] -> [] } } function rec pattern_tuple_next(s) { match s { | [< (Comma,_); l = pattern_tuple s >] -> l | [< >] -> [] } } function rec pattern_record(s) { match s { | [< (Const (Ident name),_); (Binop "=",_); p = pattern s; l = pattern_record s >] -> (name,p) :: l | [< (Semicolon,_); l = pattern_record s >] -> l | [< >] -> [] } } function rec pattern_opt(p,s) { match s { | [< p = pattern s >] -> (Some p , snd p) | [< >] -> (None , p) } } function rec when_clause(s) { match s { | [< (Keyword When,_); e = expr s >] -> Some e | [< >] -> None } } function parse(lex) { var last = &(Eof,Lexer.null_pos); function rec next_token() { var t = Lexer.token lex (*Nekoml.Lexer.token); match fst t { | Comment s | CommentLine s -> next_token() | _ -> last := t; t } }; try { var p = program (stream next_token); mk EBlock(p) Lexer.null_pos } catch { Stream_error -> error Unexpected(fst (*last)) snd(*last) } } neko-2.0.0/src/nekoml/Neko.nml0000644000175000017500000004201012112157473016631 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Lexer; open Neko.Ast; open Nekoml.Type; type comparison { Native; Structural; } type context { typectx : Nekoml.Typer.context; current : string list; module_name : string; imports : (string list,string) Hashtbl.t; mutable counter : int; mutable refvars : string Set.t; } function gen_label(ctx) { var c = ctx.counter; ctx.counter := ctx.counter + 1; "l" + string c } function gen_variable(ctx) { var c = ctx.counter; ctx.counter := ctx.counter + 1; "v" + string c } function module_name(m) { "@" + String.concat "_" m } function builtin(name) { (EConst (Builtin name) , null_pos) } function ident(name) { (EConst (Ident name) , null_pos) } function int(n) { (EConst (Int n) , null_pos) } var enull = (EConst Null , null_pos) var core = ["Core"]; function record_index(f,t) { match tlinks false t { | TRecord fl -> function rec loop(i,l) { match l { | [] -> assert() | (ff,_,_) :: l -> if f == ff then i else loop (i+1) l } } loop 0 fl | _ -> assert() } } function construct_id(ctx,m,c) { var m = if m == [] then ctx.current else m; var mod = try Nekoml.Typer.module ctx.typectx m catch { Not_found -> assert() }; var r = try Nekoml.Typer.union mod c catch { Not_found -> assert() }; if r == t_error then Hashtbl.hash (c :: m) else match tlinks false r { | TUnion (_,fl) -> function rec loop(i,l) { match l { | [] -> assert() | (cc,_) :: l -> if c == cc then i else loop (i+1) l } } loop 0 fl | _ -> assert() } } function rec is_fun(t) { match t.texpr { | TNamed (_,_,t) | TLink t -> is_fun t | TPoly | TMono _ | TFun _ -> true | _ -> false } } function call(ret,f,args,p) { if is_fun ret then (ECall (EConst (Builtin "apply"),p) (f :: args) , p) else (ECall f args , p) } function array(args,p) { (ECall (EConst (Builtin "array"),p) args , p) } function block(e) { match fst e { | EBlock _ -> e | _ -> (EBlock [e] , snd e) } } function rec arity(t) { match t.texpr { | TAbstract -> 0 | TTuple tl -> List.length tl | TLink t -> arity t | _ -> 1 } } function comparison(t) { match tlinks true t { | TNamed (["int"],[],_) | TNamed (["char"],[],_) | TNamed (["float"],[],_) | TNamed (["string"],[],_) -> Native | _ -> Structural } } function import(ctx,m,i,p) { if m == ctx.current then (EField ident(ctx.module_name) i,p) else { var key = i :: m; (EConst Ident(try { Hashtbl.find ctx.imports key } catch { Not_found -> var i = "@" + String.concat "_" m + "_" + i; Hashtbl.add ctx.imports key i; i }),p) } } function rec gen_constant(ctx,c,p) { (match c { | TVoid -> EConst Null | TInt n when n < 0 -> EBinop "-" int(0) int(-n) | TInt n -> EConst (Int n) | TFloat s -> EConst (Float s) | TChar c -> EConst Int(ord c) | TString s -> EConst (String s) | TIdent s -> if Set.exists ctx.refvars s then EArray ident(s) int(0) else EConst (Ident s) | TBool b -> EConst (if b then True else False) | TConstr "[]" | TModule (["Core"],TConstr "[]") -> fst (import ctx core "@empty" p) | TConstr "::" | TModule (["Core"],TConstr "::") -> fst (import ctx core "@cons" p) | TConstr s -> EConst (Ident s) | TModule ([],c) -> fst (gen_constant ctx c p) | TModule (m,c) -> fst (import ctx m (match c { TConstr x -> x | TIdent s -> s | _ -> assert() }) p) } , p) } type match_context { ctx : context; out : string; pos : pos; mutable cache : (match_op , string) list; mutable next : string; mutable first : bool; } var no_label = "" function rec gen_match_rec(mctx,fail,next,m) { try ident (List.phys m mctx.cache) catch { Not_found -> var p = mctx.pos; var ctx = mctx.ctx; var gen_rec = gen_match_rec mctx; match m { | MFailure -> var label = if mctx.first && mctx.next != no_label then mctx.next else fail; if label == no_label then (EBlock [] , p) else call t_void (builtin "goto") [ident label] p | MHandle (m1,m2) -> var label = gen_label ctx; var m1 = gen_rec label true m1; var m2 = gen_rec fail next m2; (EBlock [m1; (ELabel label, p); m2] , p) | MRoot -> assert() | MExecute (e,b) -> if !b then { var ematch = (EBinop "==" ident("@exc") (import ctx core "Stream_error" p) , p); var stream_pos = (ECall (import ctx core "stream_pos" p) [gen_rec fail true MRoot] , p); var test = (EBinop "==" ident("@pos") stream_pos , p); var reraise = (EIf (EBinop "&&" ematch test,p) gen_rec(fail,true,MFailure) Some((ECall (builtin "rethrow") [ident "@exc"],p)) , p); mctx.first := false; match e.edecl { | TConst _ -> gen_expr ctx e | _ -> (ETry gen_expr(ctx,e) "@exc" reraise , p) } } else { mctx.first := true; if !next then gen_expr ctx e else { var out = call t_void (builtin "goto") [ident mctx.out] p; (EBlock [gen_expr ctx e;out] , p) } } | MConstants (m,[(TIdent v,m1)]) -> var m = gen_rec fail true m; (EBlock [ (EVars [(v, Some m)] , p); gen_rec fail next m1 ] , p) | MConstants (m,cl) -> var e = gen_rec fail true m; var cases = List.map (function((c,m)) { (gen_constant ctx c p, gen_rec fail next m) }) cl; (ESwitch e cases Some(gen_rec fail next MFailure), p) | MRecordField (m,f,t) -> (EArray gen_rec(fail,true,m) int(record_index f t) , p) | MTuple (m,n) -> (EArray gen_rec(fail,true,m) int(n) , p) | MField (m,n) -> (EArray gen_rec(fail,true,m) int(n + 2) , p) | MNext (m1,m2) -> var old = mctx.next; var label = gen_label ctx; mctx.next := label; var m1 = gen_rec fail true m1; mctx.next := old; var m2 = gen_rec fail next m2; (EBlock [m1; (ELabel label, p); m2] , p) | MSwitch (m,cl) -> var e = (EArray (gen_rec fail true m) int(0) , p); var cases = List.map (function((c,m)) { var path , c = match c { | TModule (path,TConstr c) -> (path , c) | TConstr c -> (ctx.current,c) | _ -> assert() } (int(construct_id ctx path c), gen_rec fail next m) }) cl; (ESwitch e cases Some(gen_rec fail next MFailure), p) | MBind (v,m1,m2) -> var e1 = gen_rec fail true m1; var old = mctx.cache; mctx.cache := (m1,v) :: mctx.cache; var e2 = gen_rec fail next m2; mctx.cache := old; (EBlock [(EVars [(v, Some e1)] , p); e2] , p) | MWhen (e,m) -> var e = gen_expr ctx e; var m = gen_rec fail next m; var fail = gen_rec fail next MFailure; (EIf e m Some(fail), p) | MToken (m,n) -> call t_void (import ctx core "stream_token" p) [gen_rec fail true m; int n] p | MJunk (m,n,m2) -> var m = gen_rec fail true m; mctx.first := false; (EBlock [ call t_void (import ctx core "stream_junk" p) [m; int n] p; gen_rec fail next m2 ] , p) } } } function rec gen_matching(ctx,v,m,p,stream,next,out) { var mctx = { ctx = ctx; cache = [(MRoot,v)]; pos = p; out = out; first = stream; next = no_label; }; var label = (if stream then gen_label ctx else no_label); var e = gen_match_rec mctx label next m; if stream then { var vpos = "@pos"; var stream_pos = (ECall (import ctx core "stream_pos" p) [ident v] , p); var exc = (ECall builtin("throw") [import ctx core "Stream_error" p] , p); (EBlock [(EVars [(vpos , Some stream_pos)] , p); e; (ELabel label , p); exc] , p) } else e } function rec gen_match(ctx,e,m,stream,p) { var out = gen_label ctx; var v = gen_variable ctx; var m = gen_matching ctx v m p stream stream out; var m = (ENext (EVars [(v,Some e)],p) m, p); (EBlock [m; (ELabel out , p)] , p) } function rec gen_constructor(ctx,tname,c,id,t,p) { var field = ident c; var printer = (EConst Ident(tname + "__string"), p); function val_type(t) { match arity t { | 0 -> var make = array [int id;printer] p; (EBinop "=" field make , p) | n -> var args = Array.list (Array.init n (function(n) { "p" + string n })); var build = array (int id :: printer :: List.map (function(a) { (EConst (Ident a) , p) }) args) p; var func = (EFunction args (EBlock [(EReturn (Some build),p)] , p) , p); (EBinop "=" field func , p) } } var export = (EBinop "=" (EField ident(ctx.module_name) c,p) field , p); (ENext val_type(t) export , p) } function rec gen_type_printer(ctx,c,t,p) { var printer = mk TConst(TModule ["Core"] TIdent("@print_union")) t_void p; var e = mk (TCall printer [ mk TConst(TString c) t_string p; mk TConst(TIdent "v") t_void p ]) t_string p; e } function rec gen_type(ctx,name,t,p) { match t.texpr { | TAbstract | TMono _ | TPoly | TRecord _ | TTuple _ | TFun _ | TNamed (_,_,{ texpr = TNamed _ }) -> (EBlock [] , p) | TLink t -> gen_type ctx name t p | TNamed (name,_,t) -> function rec loop(l) { match l { | [] -> assert() | [x] -> x | _ :: l -> loop l } } gen_type ctx (loop name) t p | TUnion (_,constrs) -> var cmatch = gen_match ctx (ident "v") (MSwitch MRoot (List.map (function((c,t)) { var e = gen_type_printer ctx c t p; (TConstr c , MExecute e true) }) constrs)) false p; var printer = (EFunction ["v"] cmatch , p); var i = &(-1); var regs = List.map (function((c,t)) { i := *i + 1; gen_constructor ctx name c (*i) t p }) constrs; (EBlock ((EVars [(name + "__string",Some printer)],p) :: regs) , p) } } function rec gen_binop(ctx,op,e1,e2,p) { function compare(op) { var cmp = (ECall (import ctx core "@compare" p) [gen_expr ctx e1; gen_expr ctx e2] , p); (EBinop op cmp int(0) , p) } function make(op) { (EBinop op gen_expr(ctx,e1) gen_expr(ctx,e2) , p) } function builtin2(op) { (ECall (builtin op) [gen_expr ctx e1; gen_expr ctx e2] , p) } match op { | "and" -> make "&" | "or" -> make "|" | "xor" -> make "+" | "==" | "!=" | ">" | "<" | ">=" | "<=" -> match comparison e1.etype { | Structural -> compare op | Native -> make op } | "===" -> (EBinop "==" builtin2("pcompare") int(0) , p) | "!==" -> (EBinop "!=" builtin2("pcompare") int(0) , p) | ":=" -> match e1.edecl { | TField _ -> make "=" | TArray (a,i) -> (ECall (import ctx core "@aset" p) [gen_expr ctx a; gen_expr ctx i; gen_expr ctx e2] , p) | _ -> (EBinop "=" (EArray gen_expr(ctx,e1) int(0),e1.epos) gen_expr(ctx,e2) , p) } | "/" when is_int e1.etype && is_int e2.etype -> builtin2 "idiv" | _ -> make op } } function rec gen_call(ctx,rt,e,el,p) { match e.edecl { | TConst (TIdent "neko") | TConst (TModule ([],TIdent "neko")) | TConst (TModule (["Core"],TIdent "neko")) -> match el { | [{ edecl = TConst (TString s) }] -> var ch = IO.read_string (String.concat "\"" (String.split s "'")); var lex = Lexer.create Buffer.create(); Lexer.input lex p.psource ch p.pline p.pmin; fst (Neko.Parser.parse lex) | _ -> assert() } | TConst (TConstr "::") | TConst (TModule ([],TConstr "::")) | TConst (TModule (["Core"],TConstr "::")) -> match el { | [e1;e2] -> ECall (EConst (Builtin "array"),p) [int 1;import ctx core "@pcons" p;gen_expr ctx e1;gen_expr ctx e2] | _ -> assert() } | _ -> fst (call rt (gen_expr ctx e) (List.map (gen_expr ctx) el) p) } } function rec gen_expr(ctx,e) { var p = e.epos; var e = match e.edecl { | TConst c -> fst (gen_constant ctx c p) | TBlock el -> EBlock (gen_block ctx el p) | TParenthesis e -> EParenthesis (gen_expr ctx e) | TCall (f,el) -> gen_call ctx e.etype f el p | TField (e,s) -> EArray gen_expr(ctx,e) int(record_index s e.etype) | TArray (e1,e2) -> ECall (import ctx core "@aget" p) [gen_expr ctx e1;gen_expr ctx e2] | TVar ([v],e) -> ctx.refvars := Set.remove ctx.refvars v; EVars [(v , Some (gen_expr ctx e))] | TVar (vl,e) -> var n = &(-1); EVars (("@tmp" , Some (gen_expr ctx e)) :: List.map (function(v) { ctx.refvars := Set.remove ctx.refvars v; n := *n + 1; (v , Some (EArray ident("@tmp") int(*n),p)) }) vl) | TIf (e,e1,e2) -> EIf (gen_expr ctx e) (gen_expr ctx e1) (match e2 { None -> None | Some e2 -> Some (gen_expr ctx e2) }) | TWhile (e1,e2) -> EWhile (gen_expr ctx e1) (gen_expr ctx e2) NormalWhile | TFunction (rflag,name,params,code) -> if name == "_" then EFunction (List.map fst params) block(gen_expr ctx code) else if !rflag then EVars [(name , Some (EFunction (List.map fst params) block(gen_expr ctx code), p))] else EBlock [gen_functions ctx [e] p] | TBinop (op,e1,e2) -> fst (gen_binop ctx op e1 e2 p) | TTupleDecl tl -> fst (array (List.map (gen_expr ctx) tl) p) | TTypeDecl t -> fst (gen_type ctx "" t p) | TMut e -> fst (gen_expr ctx (*e)) | TRecordDecl fl -> var fl = List.sort (function((f1,_),(f2,_)) { compare (record_index f1 e.etype) (record_index f2 e.etype)}) fl; fst(array (List.map (function((_,e)) { gen_expr ctx e }) fl) p) | TListDecl el -> fst (match el { | [] -> array [] p | x :: l -> array [gen_expr ctx x; gen_expr ctx (mk TListDecl(l) e.etype p)] p }) | TUnop (op,e) -> match op { | "-" -> EBinop "-" int(0) gen_expr(ctx,e) | "*" -> EArray gen_expr(ctx,e) int(0) | "!" -> fst (call t_void (builtin "not") [gen_expr ctx e] p) | "&" -> fst (array [gen_expr ctx e] p) | _ -> assert() } | TMatch (e,m,stream) -> fst (gen_match ctx (gen_expr ctx e) m stream p) | TTupleGet (e,n) -> EArray (gen_expr ctx e) int(n) | TErrorDecl (e,t) -> var printer = gen_expr ctx (gen_type_printer ctx e t p); var printer = (EFunction ["v"] (EBlock [printer],p) , p); var printer = (EVars [(e + "__string",Some printer)] , p); ENext printer (gen_constructor ctx e e (Hashtbl.hash (e :: ctx.current)) t p) | TTry (e,m) -> var out = gen_label ctx; var not_exc = (EBinop "!=" (call t_void (builtin "typeof") [ident "@exc"] p) builtin("tarray"),p); var type_check = (EIf not_exc (EBinop "=" ident("@exc") (call t_void (import ctx core "Neko_error" p) [ident "@exc"] p),p) None,p); var matching = gen_matching ctx "@exc" m p false true out; var reraise = call t_void (builtin "rethrow") [ident "@exc"] p; var handle = (EBlock [type_check; matching; reraise;(ELabel out , p)] , p); ETry (gen_expr ctx e) "@exc" handle }; (e,p) } function rec gen_functions(ctx,fl,p) { var ell = &(EVars (List.map (function(e) { match e.edecl { | TFunction (_,"_",params,e) -> ("_" , Some (EFunction (List.map fst params) block(gen_expr ctx e),p)) | TFunction (_,name,_,_) -> ctx.refvars := Set.add ctx.refvars name; (name , Some (array [enull] p)) | _ -> assert() } }) fl) , p); List.iter (function(e) { var p = e.epos; match e.edecl { | TFunction (_,name,params,e) -> if name != "_" then { var e = gen_expr ctx e; var e = (EFunction (List.map fst params) block(e) , p); var e = (EBinop "=" (EArray ident(name) int(0),p) e, p); var e = (EBlock [e; (EBinop "=" ident(name) (EArray ident(name) int(0),p) , p)] , p); ell := (ENext (*ell) e , p); ctx.refvars := Set.remove ctx.refvars name; } | _ -> assert() } }) fl; *ell } function rec gen_block(ctx,el,p) { var old = ctx.refvars; var ell = &[]; function rec loop(fl,l) { match l { | [] -> if fl != [] then ell := gen_functions ctx (List.rev fl) p :: *ell | ({ edecl = TFunction (true,name,p,f) } as e) :: l -> loop (e :: fl) l | { edecl = TMut r } :: l -> loop fl ((*r) :: l) | x :: l -> if fl != [] then ell := gen_functions ctx (List.rev fl) p :: *ell; ell := gen_expr ctx x :: *ell; loop [] l } } loop [] el; ctx.refvars := old; List.rev (*ell) } function generate(tctx,e,deps,idents,mod) { var m = module_name mod; var ctx = { typectx = tctx; current = mod; module_name = m; counter = 0; imports = Hashtbl.create(); refvars = Set.empty(); }; var p = e.epos; var init = (EBinop "=" ident(m) builtin("exports") , p); var deps = List.map (function(m) { var file = file_name m ""; var load = (ECall (EField builtin("loader") "loadmodule",p) [gen_constant ctx (TString file) p;builtin "loader"] , p); (EBinop "=" ident(module_name m) load , p) }) deps; var exports = List.map (function(i) { (EBinop "=" (EField builtin("exports") i,p) ident(i) , p) }) idents; var el = match gen_expr ctx e { | (EBlock el, _) -> el | e -> [e] } var imports = &[]; Hashtbl.iter (function(key,id) { var e = match key { | [] -> assert() | i :: m -> (EBinop "=" ident(id) (EField ident(module_name m) i , p) , p) } imports := e :: *imports; }) ctx.imports; (EBlock (List.append (init :: List.append deps (*imports)) (List.append el exports)) , e.epos) } neko-2.0.0/src/nekoml/Ast.nml0000644000175000017500000001062212112157473016470 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type pos = Lexer.pos type constant { Int : int; Char : char; Bool : bool; Float : string; String : string; Ident : string; Constr : string; Module : (string list , constant); } type keyword { Var; If; Else; Function; Try; Catch; Type; Match; Then; When; While; Exception; } type token { Eof; Semicolon; Dot; Comma; Quote; BraceOpen; BraceClose; ParentOpen : bool; ParentClose; BracketOpen; BracketClose; Arrow; Vertical; StreamOpen; StreamClose; Const : constant; Keyword : keyword; Binop : string; Comment : string; CommentLine : string; } type type_path { EType : (type_path option , string list , string); EPoly : string; ETuple : type_path list; EArrow : (type_path , type_path); } type type_decl { EAbstract; EAlias : type_path; ERecord : (string , bool , type_path) list; EUnion : (string , type_path option) list; } type arg { ATyped : (arg , type_path); ANamed : string; ATuple : arg list; } type pattern; type expr; type stream_item; type pattern_decl { PIdent : string; PConst : constant; PTuple : pattern list; PRecord : ((string , pattern) list, int); PConstr : (string list , string , pattern option); PAlias : (string , pattern); PTyped : (pattern , type_path); PStream : (stream_item list , int); } type stream_item { SPattern : pattern; SExpr : (string list , expr); SMagicExpr : (pattern , int); } type expr_decl { EConst : constant; EBlock : expr list; EField : (expr , string); ECall : (expr , expr list); EArray : (expr , expr); EVar : ((string , type_path option) list , expr); EIf : (expr , expr , expr option); EFunction : (bool , string option , arg list , expr , type_path option); EBinop : (string , expr , expr); EUnop : (string , expr); ETypeAnnot : (expr , type_path); ETupleDecl : expr list; ETypeDecl : (string list , string , type_decl); EErrorDecl : (string , type_path option); ERecordDecl : (string , expr) list; EMatch : (expr , (pattern list , expr option , expr) list); ETry : (expr , (pattern list , expr option , expr) list); ETupleGet : (expr , int); EApply : (expr , expr list); EWhile : (expr , expr); } type pattern = (pattern_decl , pos) type expr = (expr_decl , pos) var pos = snd; function rec s_constant(c) { match c { | Int i -> string i | Float s -> s | Bool b -> if b then "true" else "false" | Char c -> "\"" + String.escape_char c + "\"" | String s -> "\"" + String.escape s + "\"" | Ident s -> s | Constr s -> s | Module (l,c) -> String.concat "." l + "." + s_constant c } } function s_path(path,n) { match path { | [] -> n | _ -> String.concat "." path + "." + n } } function s_keyword(k) { match k { | Var -> "var" | If -> "if" | Else -> "else" | Function -> "function" | Try -> "try" | Catch -> "catch" | Type -> "type" | Match -> "match" | Then -> "then" | When -> "when" | While -> "while" | Exception -> "exception" } } function s_token(t) { match t { | Eof -> "" | Semicolon -> ";" | Dot -> "." | Comma -> "," | Quote -> "'" | BraceOpen -> "{" | BraceClose -> "}" | ParentOpen _ -> "(" | ParentClose -> ")" | BracketOpen -> "[" | BracketClose -> "]" | StreamOpen -> "[<" | StreamClose -> ">]" | Arrow -> "->" | Vertical -> "|" | Const c -> s_constant c | Keyword k -> s_keyword k | Binop s -> s | Comment s -> "/*" + s + "*--" | CommentLine s -> "//" + s } } neko-2.0.0/src/nekoml/Lexer.nml0000644000175000017500000001210512112157473017016 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Nekoml.Ast type error_msg { Invalid_character : char; Unterminated_string; Unclosed_comment; Invalid_escaped_character : int; Invalid_escape; } exception Error : (error_msg , pos) function error_msg(msg) { match msg { | Invalid_character c -> sprintf "Invalid character '%s'" (String.escape_char c) | Unterminated_string -> "Unterminated string" | Unclosed_comment -> "Unclosed comment" | Invalid_escaped_character n -> sprintf "Invalid escaped character %d" n | Invalid_escape -> "Invalid escape sequence" } } function error(l,msg) { throw Error(msg,Lexer.curpos l) } var keywords = { var h = Hashtbl.create(); List.iter (function(k) { Hashtbl.add h (s_keyword k) k }) [Var;If;Else;Function;Try;Catch;Type;Match;Then;When;While;Exception]; h } function mk(l,t) { (t,Lexer.curpos l) } function mk_ident(l) { var s = Lexer.current l; mk l (try Keyword (Hashtbl.find keywords s) catch { Not_found -> Const (Ident s) }) } function mk_int(l) { mk l (Const (Int (int (Lexer.current l)))) } function mk_float(l) { mk l (Const (Float (Lexer.current l))) } function mk_binop(l) { mk l (Binop (Lexer.current l)); } var ident = "[a-z_][a-zA-Z0-9_]*"; var modident = "[A-Z][a-zA-Z0-9_]*"; var binop = "[-!=*/<>&|%+:]"; var number = "[0-9]"; var numbers = number + "+"; var spaces = "[ \r\n\t]+"; var token = &Lexer.empty(); function comment(l) { Lexer.token l (*Neko.Lexer.ecomment) } function str(l) { Lexer.token l (*Neko.Lexer.estring) } token := Lexer.build [ (";", function(l) { mk l Semicolon }); (".", function(l) { mk l Dot }); (",", function(l) { mk l Comma }); ("{", function(l) { mk l BraceOpen }); ("}", function(l) { mk l BraceClose }); (spaces + "(", function(l) { mk l (ParentOpen true) }); ("(", function(l) { mk l (ParentOpen false) }); (")", function(l) { mk l ParentClose }); ("\\[", function(l) { mk l BracketOpen }); ("]", function(l) { mk l BracketClose }); ("'", function(l) { mk l Quote }); ("|", function(l) { mk l Vertical }); (spaces, function(l) { Lexer.token l (*token) }); ( "0x[0-9a-fA-F]+", mk_int ); ( numbers, mk_int ); ( numbers + "." + number + "*", mk_float); ( "." + numbers, mk_float ); ("true", function(l) { mk l (Const (Bool true)) }); ("false", function(l) { mk l (Const (Bool false))}); ("\"", function(l) { var p1 = Lexer.curpos l; var buf = Lexer.data l; Buffer.reset buf; try str l catch { Exit -> throw Error(Unterminated_string,p1) }; var p2 = Lexer.curpos l; (Const String(Buffer.string buf) , Lexer.punion p1 p2) }); ("/\\*", function(l) { var p1 = Lexer.curpos l; var buf = Lexer.data l; Buffer.reset buf; try comment l catch { Exit -> throw Error(Unclosed_comment,p1) }; var p2 = Lexer.curpos l; (Comment(Buffer.string buf) , Lexer.punion p1 p2) }); ("'\\\\n'", function(l) { mk l Const(Char '\n') }); ("'\\\\t'", function(l) { mk l Const(Char '\t') }); ("'\\\\r'", function(l) { mk l Const(Char '\r') }); ("'\\\\''", function(l) { mk l Const(Char '\'') }); ("'\\\\\\\\'", function(l) { mk l Const(Char '\\') }); ("'\\\\\"'", function(l) { mk l Const(Char '"') }); ("'[^\\\\]'", function(l) { mk l Const(Char (String.get Lexer.current(l) 1)) }); ("'\\\\[0-9][0-9][0-9]'", function(l) { var s = String.sub (Lexer.current l) 2 3; var n = int s; if n > 255 then error l Invalid_escaped_character(n); mk l (Const (Char (chr n))) }); ("//[^\r\n]*\n?", function(l) { var s = Lexer.current l; var len = String.length s; var n = (if String.get s (len - 1) == '\r' then 3 else 2); mk l CommentLine(String.sub s 0 (len - n)) }); ("\\[<", function(l) { mk l StreamOpen }); (">]", function(l) { mk l StreamClose }); ("->", function(l) { mk l Arrow }); (binop + binop + "?", mk_binop); (">>>" , mk_binop); ("===" , mk_binop); ("!==" , mk_binop); ("or" , mk_binop); ("and" , mk_binop); ("xor" , mk_binop); (ident , mk_ident); (modident , function(l) { mk l Const(Constr (Lexer.current l)) }); ] (function(l) { match Lexer.char l { | None -> mk l Eof | Some c -> error l (Invalid_character c) } }); neko-2.0.0/src/nekoml/Match.nml0000644000175000017500000002443012112157473016777 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* ----- We're using the same algorithm and source code as described in chapter 5.2.4 of "The Zinc experiment" by X. Leroy ( http://citeseer.ist.psu.edu/leroy90zinc.html ) also described in "The Implementation of Functional Programming Languages" by Simon Peyton Jones, in the Chapter 5 by Philip Wadler ( http://research.microsoft.com/Users/simonpj/Papers/slpj-book-1987/ ) */ open Nekoml.Ast; open Nekoml.Type; type complete { Total; Partial; Dubious; } type lambda = match_op type matching = ((pattern list , lambda) list , lambda list) var fully_matched_ref = &(function(cl) { false }) var error_ref = &(function(msg : string,p : pos) { assert() }) function error(msg,p) { (*error_ref) msg p; } var failure = MFailure function handle(l1,l2) { if l2 == MFailure then l1 else if l1 == MFailure then l2 else MHandle l1 l2 } function exec(e) { MExecute e true } function cond(path,lambdas) { MConstants path lambdas } function rec mswitch(path,lambdas) { match lambdas { | (TVoid,m1) :: [] -> m1 | (TVoid,m1) :: l -> MNext m1 (mswitch path l) | _ -> MSwitch path lambdas } } function ewhen(e,e2) { MWhen e e2 } function rec bind(v,p,m) { match m { | MBind (v2,p2,m) -> MBind v2 p2 (bind v p m) | act -> if v == "_" then act else MBind v p act } } function rec junk(p,k,m) { match m { | MBind (v,m,m2) -> MBind v m (junk p k m2) | act -> if k == 0 then act else MJunk p k act } } function rec stream_pattern((p,pos)) { (match p { | PIdent i -> PConst (Ident i) | PConst c -> PConst c | PTuple pl -> PTuple (List.map stream_pattern pl) | PRecord (pr,t) -> PRecord (List.map (function((s,p)) { (s , stream_pattern p) }) pr) t | PConstr (path,name,param) -> PConstr path name (match param { None -> None | Some p -> Some (stream_pattern p) }) | PAlias (s,p) -> PAlias s (stream_pattern p) | PTyped (p,t) -> PTyped (stream_pattern p) t | PStream (s,k) -> PStream s k } , pos) } function rec have_when(m) { match m { | MWhen _ -> true | MBind (_,_,e) -> have_when e | _ -> false } } function t_const(c) { match c { | Int i -> TInt i | String s -> TString s | Float f -> TFloat f | Char c -> TChar c | Ident i -> TIdent i | Bool b -> TBool b | _ -> assert() } } function total(p1,p2) { match (p1 , p2) { | (Total , Total) -> Total | (Partial , _) -> Partial | (_ , Partial) -> Partial | _ -> Dubious } } function partial(p1,p2) { match (p1 , p2) { | (Total , _) -> p2 | (_ , Total) -> Total | _ -> Dubious } } function rec start_by_a_variable((p,_)) { match p { | PAlias (_,p) -> start_by_a_variable p | PIdent _ -> true | _ -> false } } function add_to_match((casel,pathl),cas) { (cas :: casel , pathl) } function make_constant_match(path,cas) { match path { | [] -> assert() | _ :: pathl -> ([cas] , pathl) } } function make_token_match(path,cas) { ([cas] , path) } function make_construct_match(tuple,nargs,pathl,cas) { match pathl { | [] -> assert() | path :: pathl -> function rec make_path(i) { if i >= nargs then pathl else { var k = if tuple then MTuple path i else MField path i; k :: make_path (i + 1) } } ([cas] , make_path 0) } } function make_record_match(args,pathl,t,cas) { match pathl { | [] -> assert() | path :: pathl -> var l = List.fold (function(acc,(f,_)) { MRecordField(path,f,t) :: acc }) pathl (List.rev args); ([cas] , l) } } function add_to_division(make_match,divlist,key,cas) { try { var matchref = List.assoc key divlist; matchref := add_to_match (*matchref) cas; divlist } catch { Not_found -> (key , &(make_match cas)) :: divlist } } function always_add(make_match,divlist,cas) { (TVoid , &(make_match cas)) :: divlist } var lines_of_matching = fst function fully_matched(cl) { (*fully_matched_ref) cl } function flatten(a) { match a { | None -> [] | Some p -> match p { | (PTuple l,_) -> l | _ -> [p] } } } function split_matching(m) { match m { | (_ , []) -> assert() | (casel, (curpath :: endpathl) as pathl) -> function rec split_rec(l) { match l { | ((PTyped (p,_),_) :: l , act) :: rest -> split_rec ((p :: l, act) :: rest) | ((PAlias (v,p),_) :: l , act) :: rest -> split_rec ((p :: l, bind v curpath act) :: rest) | ((PIdent v,_) :: l , act) :: rest -> var vars , others = split_rec rest; (add_to_match vars (l, bind v curpath act) , others) | casel -> (([] , endpathl) , (casel , pathl)) } } split_rec casel } } function divide_matching(m) { match m { | (_ , []) -> assert() | (casel , (curpath :: tailpathl) as pathl) -> function rec divide_rec(l) { match l { | [] -> ([] , [] , ([] , pathl)) | ([],_) :: _ -> assert() | ((PTyped (p,_),_) :: l , act) :: rest -> divide_rec ((p :: l , act) :: rest) | ((PAlias (v,p),_) :: l, act) :: rest -> divide_rec ((p :: l , bind v curpath act) :: rest) | ((PConst c,_) :: l, act) :: rest -> var constant , constrs, others = divide_rec rest; (add_to_division (make_constant_match pathl) constant (t_const c) (l, act), constrs , others) | ((PConstr (path,c,arg),_) :: l,act) :: rest -> var constants , constrs, others = divide_rec rest; var args = flatten arg; (constants , add_to_division (make_construct_match false (List.length args) pathl) constrs (TModule path TConstr(c)) (List.append args l,act) , others) | ((PTuple [],_) :: l,act) :: rest -> var constants , constrs, others = divide_rec rest; (constants , add_to_division (make_constant_match pathl) constrs TVoid (l, act), others) | ((PTuple args,_) :: l,act) :: rest -> var constants , constrs, others = divide_rec rest; (constants , add_to_division (make_construct_match true (List.length args) pathl) constrs TVoid (List.append args l,act) , others) | ((PRecord (args,t),_) :: l,act) :: rest -> var constants , constrs, others = divide_rec rest; (constants , add_to_division (make_record_match args pathl magic(t)) constrs TVoid (List.append (List.map snd args) l,act) , others) | ((PStream ((SPattern p) :: sl,k),pp) :: l,act) :: rest -> var constants , constrs, others = divide_rec rest; (constants , always_add (make_token_match ((MToken curpath k) :: pathl)) constrs (stream_pattern p :: (PStream sl (k+1),pp) :: l, act) , others) | ((PStream ((SMagicExpr ((PTuple _,_) as p,e)) :: sl,k),pp) :: l,act) :: rest -> var constants , constrs, others = divide_rec rest; var ebind = MExecute (mk TConst(TIdent "@tmp") t_void pp) false; (constants , always_add (make_token_match (junk curpath k (MExecute magic(e) false) :: ebind :: pathl)) constrs ((PConst (Ident "@tmp"),pp) :: stream_pattern p :: (PStream sl 0,pp) :: l, act) , others) | ((PStream ((SMagicExpr (p,e)) :: sl,k),pp) :: l,act) :: rest -> var constants , constrs, others = divide_rec rest; (constants , always_add (make_token_match (junk curpath k (MExecute magic(e) false) :: pathl)) constrs (stream_pattern p :: (PStream sl 0,pp) :: l, act) , others) | ((PStream ([],k),pp) :: l,act) :: rest -> var constants , constrs, others = divide_rec rest; (constants , always_add (make_constant_match pathl) constrs (l, junk curpath k act) , others) | casel -> ([] , [] , (casel,pathl)) } } divide_rec casel } } function rec conquer_divided_matching(m) { match m { | [] -> ([], Total, []) | (key, matchref) :: rest -> var l1, p1, u1 = conquer_matching (*matchref); var l2, p2, u2 = conquer_divided_matching rest; ((key , l1) :: l2 , total p1 p2 , List.append u1 u2) } } function rec conquer_matching(m) { match m { | ([] , _) -> (failure , Partial , []) | (([],action) :: rest , k) -> if have_when action then { var a , p , r = conquer_matching (rest,k); (handle action a , p , r) } else (action , Total, rest) | (_ , []) -> assert() | ((p :: _,_) :: _ , _ :: _) when start_by_a_variable p -> var vars , rest = split_matching m; var l1, p1, u1 = conquer_matching vars; var l2, p2, u2 = conquer_matching rest; if p1 == Total then (l1 , Total, List.append u1 lines_of_matching(rest)) else (handle l1 l2 , (if p2 == Total then Total else Dubious) , List.append u1 u2) | (_ , path :: _) -> match divide_matching m { | ([] , [] , vars) -> conquer_matching vars | (consts , [] , vars) -> var l1, _ , u1 = conquer_divided_matching consts; var l2, p2, u2 = conquer_matching vars; (handle (cond path l1) l2 , p2 , List.append u1 u2) | ([] , constrs , vars) -> var l1, p1, u1 = conquer_divided_matching constrs; var l2, p2, u2 = conquer_matching vars; if fully_matched (List.map fst constrs) && p1 == Total then (mswitch path l1 , Total , List.append u1 lines_of_matching(vars)) else (handle (mswitch path l1) l2 , partial p1 p2 , List.append u1 u2) | _ -> assert() } | _ -> assert() } } function make(cases : (pattern list, texpr option, texpr) list,p) { var cases = List.concat (List.map (function((pl,wcond,e)) { var e = exec e; var e = match wcond { None -> e | Some e2 -> ewhen e2 e }; List.map (function(p) { ([p] , e) }) pl }) cases); var m = (cases , [MRoot]); var lambda, partial, unused = conquer_matching m; match unused { | [] -> () | ([] , _ ) :: _ -> error "Some pattern are never matched" p | ((_,p) :: _ , _) :: _ -> error "This pattern is never matched" p}; (partial != Total , lambda) } neko-2.0.0/src/nekoml/Main.nml0000644000175000017500000001241312112157473016625 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Nekoml.Typer; function complete(s) { var l = String.length s; if l > 0 && String.get s (l - 1) != '\\' && String.get s (l-1) != '/' then s + "/" else s } function report(msg,p) { if p == Lexer.null_pos then { Stack.dump IO.stderr Stack.exc(); IO.printf IO.stderr "Exception : %s\n" msg } else IO.printf IO.stderr "%s(%d): %s\n" (Lexer.source p,Lexer.line p,msg); Sys.exit(-1); } function gen_neko(ctx,m,e) { var path , deps, idents = module_infos m; var file = Nekoml.Type.file_name path ".neko"; if *verbose then printf "Generating %s\n" file; var e = Nekoml.Neko.generate ctx e deps idents path; var ch = IO.write_file file false; var ctx = Neko.Printer.create ch; Neko.Printer.print ctx e; IO.close_out ch } function compile(ctx,m,e) { var path, deps, idents = module_infos m; var file = Nekoml.Type.file_name path ".n"; if *verbose then printf "Compiling %s\n" file; /* don't use version 1+ since this will use left-to-right evaluation for $array, leading to too much stack used with big chained lists */ var code = Neko.Compile.compile 0 (Nekoml.Neko.generate ctx e deps idents path); var ch = IO.write_file file true; Neko.Bytecode.write ch code; IO.close_out ch } function capitalize(p) { var c = String.get p 0; if c < 'a' || c > 'z' then p else { var p = String.sub p 0 (String.length p); String.set p 0 chr(ord c - ord 'a' + ord 'A'); p } } exception FileNotFound : string; try { var v = Sys.version; var head = "NekoML Compiler v" + v.maj + "." + v.min + "." + v.build + " - (c)2005-2013 Haxe Foundation\n Usage : nekoml [options] files..."; var path = &[""]; var files = &[]; var neko = &false; var std = &Some("nekoml.std"); var pack = &None; var packs = Hashtbl.create(); function use_pack(file) { var data = try IO.file_contents file catch { _ -> throw FileNotFound(file) }; Zip.init(); var h = String.unserialize (Zip.uncompress data); Hashtbl.iter (function(key,m) { if *verbose then printf "Cached %s [%d bytes]\n" (key,String.length m); Hashtbl.add packs key m }) h; } var decl = [ ("-p", Args.String (function(p) { path := complete p :: *path }) , " : additional file search path"); ("-v", Args.Void (function() { verbose := true }) , ": verbose mode"); ("-n", Args.Void (function() { neko := true }) , ": generate intermediate .neko files"); ("-pack", Args.String (function(p) { pack := Some p })," : build module packages"); ("-use", Args.String use_pack," : use this module package"); ("-nostd", Args.Void (function() { path := List.append (*path) ["core/"]; std := None; }),": disable std lib"); ]; var std_path = List.append (*path) Reflect.loader_path(); function rec loop(std,l) { match l { | [] -> if *verbose then printf "%s not found in %s\n" (std,String.concat ":" std_path) | path :: l -> try use_pack (path+std) catch { FileNotFound _ -> loop std l } } } Args.parse head decl (function(f) { files := f :: *files }); match *std { | None -> () | Some std -> loop std std_path } var ctx = context (*path) packs (function(ctx,m,e) { if *neko then gen_neko ctx m e else compile ctx m e }); List.iter (function(file) { if *verbose then printf "Compiling %s\n" file; var modname = String.split (Sys.without_extension file) "/"; var modname = match List.map capitalize modname { | "Core" :: m -> m | m -> m }; ignore(load_module ctx modname Lexer.null_pos); }) (List.rev (*files)); match *pack { | None -> () | Some file -> var h = Hashtbl.create(); Hashtbl.iter (function(key,m) { Hashtbl.add h (String.concat "." key) (IO.file_contents m.file) }) ctx.modules; Zip.init(); var ch = IO.write_file file true; IO.write ch (Zip.compress (String.serialize h) 9); IO.close_out ch; } } catch { | Neko.Lexer.Error (msg,p) -> report Neko.Lexer.error_msg(msg) p | Neko.Parser.Error (msg,p) -> report Neko.Parser.error_msg(msg) p | Neko.Compile.Error (msg,p) -> report Neko.Compile.error_msg(msg) p | Nekoml.Lexer.Error (msg,p) -> report Nekoml.Lexer.error_msg(msg) p | Nekoml.Parser.Error (msg,p) -> report Nekoml.Parser.error_msg(msg) p | Nekoml.Typer.Error (msg,p) -> report Nekoml.Typer.error_msg(msg) p | e -> report string(e) Lexer.null_pos } neko-2.0.0/src/Makefile.boot0000644000175000017500000000412312112157473016345 0ustar ncannassencannasse# # Bootstrap errors : # # pass1 = the compiler have a type error or the boot is broken # try to go around the problem that cause the error (the boot cannot be fixed now) # # pass2 = the compiler makes a runtime error OR the boot is producing invalid code # try to fix the compiler # or try to go around the broken boot codegen # # pass3 = the compiler is broken or the VM is broken # fix it # NEKOVM = neko NEKOVM1 = NEKOPATH='../boot' c:/neko/neko1 NEKOVM2 = NEKOPATH='' c:/neko/neko1 TIME = @c:/progra~1/cygwin/bin/times -f %e make all: clean pass1 pass2 pass3 source: clean ${NEKOVM1} nekoml -nostd -n neko/Main.nml nekoml/Main.nml link: ${NEKOVM} neko/Main -link nekoc.n neko/Main ${NEKOVM} neko/Main -link nekoml.n nekoml/Main ${NEKOVM} tools/nekoboot nekoc.n ${NEKOVM} tools/nekoboot nekoml.n ${NEKOVM} tools/nekoboot nekotools.n tools: ${NEKOVM} neko/Main tools/test.neko ${NEKOVM} neko/Main tools/nekoboot.neko ${NEKOVM} nekoml/Main -nostd -p tools Tools.nml ${NEKOVM} neko/Main -link nekotools.n Tools pass1: ${TIME} tpass1 spass1: ${NEKOVM1} nekoml -nostd -v -n neko/Main.nml nekoml/Main.nml ${NEKOVM1} nekoc -v *.neko neko/*.neko nekoml/*.neko tpass1: ${NEKOVM1} nekoml -nostd neko/Main.nml nekoml/Main.nml pass2: ${TIME} tpass2 spass2: ${NEKOVM2} nekoml/Main -nostd -v -n neko/Main.nml nekoml/Main.nml ${NEKOVM2} neko/Main -v *.neko neko/*.neko nekoml/*.neko tpass2: ${NEKOVM2} nekoml/Main -nostd neko/Main.nml nekoml/Main.nml pass3: ${TIME} tpass3 spass3: ${NEKOVM} nekoml/Main -nostd -v -n neko/Main.nml nekoml/Main.nml ${NEKOVM} neko/Main -v *.neko neko/*.neko nekoml/*.neko tpass3: ${NEKOVM} nekoml/Main -nostd neko/Main.nml nekoml/Main.nml core/*.nml -pack ../bin/nekoml.std install: tools link -cp nekoc.n nekoml.n ../boot -cp nekoc.exe nekoml.exe nekotools.exe tools/test.n ../bin clean: rm -rf *.n rm -rf neko/*.n rm -rf nekoml/*.n rm -rf tools/*.n rm -rf benchs/*.n rm -rf nekoc.exe nekoml.exe nekotools.exe cleanall: clean rm -rf *.neko rm -rf neko/*.neko rm -rf nekoml/*.neko .PHONY: all pass1 tpass1 pass2 tpass2 pass3 tpass3 install clean link tools neko-2.0.0/src/neko/0000755000175000017500000000000012112157473014677 5ustar ncannassencannasseneko-2.0.0/src/neko/Compile.nml0000644000175000017500000006521412112157473017007 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Lexer; open Neko.Ast; open Neko.Bytecode; type access { XEnv : int; XStack : int; XGlobal : int; XField : string; XIndex : int; XArray; XThis; } type label { lname : string; ltraps : int list; lstack : int; mutable lpos : int option; mutable lwait : (void -> void) list; } type globals { globals : (global,int) Hashtbl.t; gobjects : (string list,int) Hashtbl.t; mutable functions : (opcode array, (int,int) array, int , int) list; mutable gtable : global array; labels : (string,label) Hashtbl.t; hfiles : (string,int) Hashtbl.t; files : string array; } type context { g : globals; version : int; mutable ops : opcode array; mutable locals : (string,int) Map.t; mutable env : (string,int) Map.t; mutable nenv : int; mutable stack : int; mutable loop_limit : int; mutable limit : int; mutable traps : int list; mutable breaks : (void -> void, pos) list; mutable continues : (void -> void, pos) list; mutable pos : (int,int) array; mutable curpos : (int, int); mutable curfile : string; } type error_msg = string exception Error : (error_msg , pos) function error(e,p) { throw Error(e,p) } function error_msg(s) { s } function stack_delta(o) { match o { | AccNull | AccTrue | AccFalse | AccThis | AccInt _ | AccStack _ | AccGlobal _ | AccEnv _ | AccField _ | AccBuiltin _ | AccIndex _ | JumpIf _ | JumpIfNot _ | Jump _ | JumpTable _ | Ret _ | SetGlobal _ | SetStack _ | SetEnv _ | SetThis | Bool | IsNull | IsNotNull | Not | Hash | TypeOf | New | AccStack0 | AccStack1 | AccIndex0 | AccIndex1 | Loop -> 0 | Add | Sub | Mult | Div | Mod | Shl | Shr | UShr | Or | And | Xor | Eq | Neq | Gt | Gte | Lt | Lte | PhysCompare -> -1 | AccArray -> -1 | SetField _ | SetIndex _ | Compare -> -1 | SetArray -> -2 | Push -> 1 | Pop x -> -x | Apply nargs | Call nargs | TailCall (nargs,_) -> -nargs | ObjCall nargs -> -(nargs + 1) | MakeEnv size | MakeArray size -> -size | Trap _ -> trap_stack_delta | EndTrap -> -trap_stack_delta } } function check_stack(ctx,stack,p) { if ctx.stack != stack then error "Stack alignment failure" p; } function pos(ctx) { Array.length ctx.ops } function set_pos(ctx,p) { if p.psource == ctx.curfile then { if p.pline != snd ctx.curpos then ctx.curpos := (fst ctx.curpos, p.pline); } else if p == Lexer.null_pos then { // nothing } else { var fid = try Hashtbl.find ctx.g.hfiles p.psource catch { Not_found -> var fid = Array.length ctx.g.files; Array.add ctx.g.files p.psource; Hashtbl.add ctx.g.hfiles p.psource fid; fid; } ctx.curfile := p.psource; ctx.curpos := (fid,p.pline); } } function write(ctx,op) { ctx.stack := ctx.stack + stack_delta op; Array.add ctx.pos ctx.curpos; if op_param op then Array.add ctx.pos ctx.curpos; Array.add ctx.ops op; } function jmp(ctx) { var p = pos ctx; write ctx (Jump 0); function() { Array.set ctx.ops p Jump(pos ctx - p) } } function cjmp(cond,ctx) { var p = pos ctx; write ctx (Jump 0); function() { Array.set ctx.ops p (if cond then JumpIf else JumpIfNot)(pos ctx - p) } } function trap(ctx) { var p = pos ctx; write ctx (Trap 0); function() { Array.set ctx.ops p Trap(pos ctx - p) } } function goto(ctx,p) { write ctx Jump(p - pos ctx) } function global(ctx,g) { var ginf = ctx.g; try Hashtbl.find ginf.globals g catch { Not_found -> var gid = Array.length ginf.gtable; Hashtbl.add ginf.globals g gid; Array.add ginf.gtable g; gid } } function save_breaks(ctx) { var oldc = ctx.continues; var oldb = ctx.breaks; var oldl = ctx.loop_limit; ctx.loop_limit := ctx.stack; ctx.breaks := []; ctx.continues := []; (ctx , oldc, oldb , oldl) } function process_continues((ctx,oldc,_,_)) { List.iter (function((f,_)) { f() }) ctx.continues; ctx.continues := oldc } function process_breaks((ctx,_,oldb,oldl)) { List.iter (function((f,_)) { f() }) ctx.breaks; ctx.loop_limit := oldl; ctx.breaks := oldb } function check_breaks(ctx) { List.iter (function((_,p)) { error "Break outside a loop" p }) ctx.breaks; List.iter (function((_,p)) { error "Continue outside a loop" p }) ctx.continues } function make_array(p,el) { (ECall (EConst (Builtin "array"),p) el , p) } function get_cases_ints(cases) { var max = &(-1); var l = List.map (function((e,e2)) { match e { | (EConst (Int n),_) when n >= 0 -> if n > *max then max := n; (n,e2) | _ -> throw Exit } }) cases; // only create jump table if small or >10% cases matched var nmatches = List.length l; if nmatches < 3 then throw Exit; if *max >= 16 && (nmatches * 100) / (*max + 1) < 10 then throw Exit; if *max > 512 then throw Exit; (l,*max + 1) } function rec scan_labels(ctx,supported,in_block,e) { match fst e { | EFunction (args,e) -> var nargs = List.length args; var traps = ctx.traps; ctx.traps := []; ctx.stack := ctx.stack + nargs; scan_labels ctx supported false e; ctx.stack := ctx.stack - nargs; ctx.traps := traps | EBlock _ -> var old = ctx.stack; Neko.Ast.iter (scan_labels ctx supported true) e; ctx.stack := old | EVars l -> if !in_block then error "Variable declaration must be done inside a block" (snd e); List.iter (function((_,e)) { match e { | None -> () | Some e -> scan_labels ctx supported false e }; ctx.stack := ctx.stack + 1 }) l | ELabel l when !supported -> error "Label is not supported in this part of the program" (snd e); | ELabel l when Hashtbl.exists ctx.g.labels l -> error ("Duplicate label " + l) (snd e) | ELabel l -> var label = { lname = l; ltraps = List.rev ctx.traps; lstack = ctx.stack; lpos = None; lwait = []; }; Hashtbl.add ctx.g.labels l label | ETry (e,_,e2) -> ctx.stack := ctx.stack + trap_stack_delta; ctx.traps := ctx.stack :: ctx.traps; scan_labels ctx supported false e; ctx.stack := ctx.stack - trap_stack_delta; ctx.traps := match ctx.traps { [] -> assert() | _ :: l -> l }; ctx.stack := ctx.stack + 1; scan_labels ctx supported false e2; ctx.stack := ctx.stack - 1; | EBinop ("=",e1,e2) -> function rec is_extended((e,_)) { match e { | EParenthesis e -> is_extended e | EArray _ | EField _ -> true | _ -> false } }; var ext = is_extended e1; if ext then ctx.stack := ctx.stack + 1; scan_labels ctx supported false e2; ctx.stack := ctx.stack + 1; scan_labels ctx supported false e1; ctx.stack := ctx.stack - (if ext then 2 else 1); | ECall ((EConst (Builtin "array"),_),e :: el) -> if ctx.version >= 2 then { scan_labels ctx supported false e; List.iter (function(e) { ctx.stack := ctx.stack + 1; scan_labels ctx supported false e; }) el; ctx.stack := ctx.stack - List.length el } else { List.iter (function(e) { scan_labels ctx supported false e; ctx.stack := ctx.stack + 1; }) el; scan_labels ctx supported false e; ctx.stack := ctx.stack - List.length el } | ECall ((EConst (Builtin x),_),el) when x != "apply" -> Neko.Ast.iter (scan_labels ctx false false) e | ECall ((EConst (Builtin "apply"),_),e :: el) | ECall(e,el) -> List.iter (function(e) { scan_labels ctx supported false e; ctx.stack := ctx.stack + 1; }) el; scan_labels ctx supported false e; ctx.stack := ctx.stack - List.length el | EObject fl -> ctx.stack := ctx.stack + 2; List.iter (function((s,e)) { scan_labels ctx supported false e }) fl; ctx.stack := ctx.stack - 2; | ESwitch (ee,[(econd,exec)],eo) -> var p = snd e; scan_labels ctx supported false (EIf (EBinop "==" ee econd,p) exec eo,p) | ESwitch (e,cases,eo) -> scan_labels ctx supported false e; var delta = try { ignore(get_cases_ints cases); 0 } catch { Exit -> 1 }; ctx.stack := ctx.stack + delta; List.iter (function((e1,e2)) { ctx.stack := ctx.stack + delta; scan_labels ctx supported false e1; ctx.stack := ctx.stack - delta; scan_labels ctx supported false e2; }) cases; match eo { | None -> () | Some e -> scan_labels ctx supported false e } ctx.stack := ctx.stack - delta; | ENext (e1,e2) -> scan_labels ctx supported in_block e1; scan_labels ctx supported in_block e2; | EConst _ | EContinue | EBreak _ | EReturn _ | EIf _ | EWhile _ | EParenthesis _ -> Neko.Ast.iter (scan_labels ctx supported false) e | EBinop (_,_,_) | EArray _ | EField _ -> Neko.Ast.iter (scan_labels ctx false false) e } } function compile_constant(ctx,c,p) { match c { | True -> write ctx AccTrue | False -> write ctx AccFalse | Null -> write ctx AccNull | This -> write ctx AccThis | Int n -> write ctx (AccInt n) | Float f -> write ctx (AccGlobal (global ctx (GlobalFloat f))) | String s -> write ctx (AccGlobal (global ctx (GlobalString s))) | Builtin s -> match s { | "tnull" -> write ctx (AccInt 0) | "tint" -> write ctx (AccInt 1) | "tfloat" -> write ctx (AccInt 2) | "tbool" -> write ctx (AccInt 3) | "tstring" -> write ctx (AccInt 4) | "tobject" -> write ctx (AccInt 5) | "tarray" -> write ctx (AccInt 6) | "tfunction" -> write ctx (AccInt 7) | "tabstract" -> write ctx (AccInt 8) | s -> write ctx (AccBuiltin s) } | Ident s -> try { var l = Map.find ctx.locals s; if l <= ctx.limit then { var e = try { Map.find ctx.env s } catch { Not_found -> var e = ctx.nenv; ctx.nenv := ctx.nenv + 1; ctx.env := Map.add ctx.env s e; e }; write ctx (AccEnv e); } else { var p = ctx.stack - l; write ctx (if p == 0 then AccStack0 else if p == 1 then AccStack1 else AccStack p); } } catch { Not_found -> var g = global ctx (GlobalVar s); write ctx (AccGlobal g) } } } function rec compile_access(ctx,e) { match fst e { | EConst (Ident s) -> try { var l = Map.find ctx.locals s; if l <= ctx.limit then { var e = try { Map.find ctx.env s } catch { Not_found -> var e = ctx.nenv; ctx.nenv := ctx.nenv + 1; ctx.env := Map.add ctx.env s e; e }; XEnv e } else XStack l } catch { Not_found -> var g = global ctx (GlobalVar s); XGlobal g } | EField (e,f) -> compile ctx false e; write ctx Push; XField f | EArray (e1,(EConst (Int n),_)) -> compile ctx false e1; write ctx Push; XIndex n | EArray (ea,ei) -> compile ctx false ei; write ctx Push; compile ctx false ea; write ctx Push; XArray | EConst This -> XThis | _ -> error "Invalid access" (snd e) } } function rec compile_access_set(ctx,a) { match a { | XEnv n -> write ctx (SetEnv n) | XStack l -> write ctx (SetStack (ctx.stack - l)) | XGlobal g -> write ctx (SetGlobal g) | XField f -> write ctx (SetField f) | XIndex i -> write ctx (SetIndex i) | XThis -> write ctx SetThis | XArray -> write ctx SetArray } } function rec compile_access_get(ctx,a) { match a { | XEnv n -> write ctx (AccEnv n) | XStack l -> write ctx (AccStack (ctx.stack - l)) | XGlobal g -> write ctx (AccGlobal g) | XField f -> write ctx (AccField f) | XIndex i -> write ctx (AccIndex i) | XThis -> write ctx AccThis | XArray -> write ctx Push; write ctx (AccStack 2); write ctx AccArray } } function rec write_op(ctx,op,p) { match op { | "+" -> write ctx Add | "-" -> write ctx Sub | "/" -> write ctx Div | "*" -> write ctx Mult | "%" -> write ctx Mod | "<<" -> write ctx Shl | ">>" -> write ctx Shr | ">>>" -> write ctx UShr | "|" -> write ctx Or | "&" -> write ctx And | "^" -> write ctx Xor | "==" -> write ctx Eq | "!=" -> write ctx Neq | ">" -> write ctx Gt | ">=" -> write ctx Gte | "<" -> write ctx Lt | "<=" -> write ctx Lte | _ -> error "Unknown operation" p } } function rec compile_binop(ctx,tail,op,e1,e2,p) { match op { | "=" -> var a = compile_access ctx e1; compile ctx false e2; compile_access_set ctx a | "&&" -> compile ctx false e1; var jnext = cjmp false ctx; compile ctx tail e2; jnext() | "||" -> compile ctx false e1; var jnext = cjmp true ctx; compile ctx tail e2; jnext() | "++=" | "--=" -> write ctx Push; var base = ctx.stack; var a = compile_access ctx e1; compile_access_get ctx a; write ctx SetStack(ctx.stack - base); write ctx Push; compile ctx false e2; write_op ctx (String.sub op 0 (String.length op - 2)) p; compile_access_set ctx a; write ctx (AccStack 0); write ctx (Pop 1); | "+=" | "-=" | "/=" | "*=" | "%=" | "<<=" | ">>=" | ">>>=" | "|=" | "&=" | "^=" -> var a = compile_access ctx e1; compile_access_get ctx a; write ctx Push; compile ctx false e2; write_op ctx (String.sub op 0 (String.length op - 1)) p; compile_access_set ctx a | _ -> match (op , e1 , e2) { | ("==" , _ , (EConst Null,_)) -> compile ctx false e1; write ctx IsNull | ("!=" , _ , (EConst Null,_)) -> compile ctx false e1; write ctx IsNotNull | ("==" , (EConst Null,_) , _) -> compile ctx false e2; write ctx IsNull | ("!=" , (EConst Null,_) , _) -> compile ctx false e2; write ctx IsNotNull | ("-", (EConst (Int 0),_) , (EConst (Int i),_)) -> compile ctx tail (EConst (Int (-i)),p) | _ -> compile ctx false e1; write ctx Push; compile ctx false e2; write_op ctx op p } } } function rec compile_function(main,params,e) { var ctx = { g = main.g; // reset ops = Array.create(); pos = Array.create(); breaks = []; continues = []; env = Map.empty(); nenv = 0; traps = []; limit = main.stack; // dup version = main.version; stack = main.stack; locals = main.locals; loop_limit = main.loop_limit; curpos = main.curpos; curfile = main.curfile; }; List.iter (function(v) { ctx.stack := ctx.stack + 1; ctx.locals := Map.add ctx.locals v ctx.stack; }) params; var s = ctx.stack; compile ctx true e; write ctx (Ret (ctx.stack - ctx.limit)); check_stack ctx s (snd e); check_breaks ctx; // add function var gid = Array.length ctx.g.gtable; ctx.g.functions := (ctx.ops,ctx.pos,gid,List.length params) :: ctx.g.functions; Array.add ctx.g.gtable GlobalFunction(gid,-1); // environment if ctx.nenv > 0 then { var a = Array.make ctx.nenv ""; Map.iter (function(v,i){ a.[i] := v }) ctx.env; Array.iter (function(v){ compile_constant main (Ident v) snd(e); write main Push; }) a; write main (AccGlobal gid); write main (MakeEnv ctx.nenv); } else write main (AccGlobal gid); } function rec compile_builtin(ctx,tail,b,el,p) { match (b , el) { | ("istrue" , [e]) -> compile ctx false e; write ctx Bool | ("not" , [e]) -> compile ctx false e; write ctx Not | ("typeof" , [e]) -> compile ctx false e; write ctx TypeOf | ("hash" , [e]) -> compile ctx false e; write ctx Hash | ("new" , [e]) -> compile ctx false e; write ctx New | ("compare" , [e1;e2]) -> compile ctx false e1; write ctx Push; compile ctx false e2; write ctx Compare | ("pcompare" , [e1;e2]) -> compile ctx false e1; write ctx Push; compile ctx false e2; write ctx PhysCompare | ("goto" , [(EConst (Ident l) , _)] ) -> var l = try Hashtbl.find ctx.g.labels l catch { Not_found -> error ("Unknown label " + l) p }; var os = ctx.stack; function rec loop(l1,l2) { match (l1,l2) { | (x :: l1 , y :: l2) when x == y -> loop l1 l2 | _ -> (l1,l2) } } var straps , dtraps = loop List.rev(ctx.traps) l.ltraps; List.iter (function(l) { if ctx.stack != l then write ctx Pop(ctx.stack - l); write ctx EndTrap; }) List.rev(straps); var dtraps = List.map (function(l) { var l = l - trap_stack_delta; if l < ctx.stack then write ctx Pop(ctx.stack - l); while ctx.stack < l { write ctx Push; } trap ctx }) dtraps; if l.lstack < ctx.stack then write ctx Pop(ctx.stack - l.lstack); while l.lstack > ctx.stack { write ctx Push }; ctx.stack := os; match l.lpos { | None -> l.lwait := jmp ctx :: l.lwait | Some p -> write ctx (Jump p) }; List.iter (function(t) { t(); write ctx Push; compile_constant ctx (Builtin "throw") p; write ctx (Call 1); // insert an infinite loop in order to // comply with bytecode checker ignore(jmp ctx) }) dtraps; | ("goto" , _) -> error "Invalid $goto statement" p | ("array",e :: el) -> var count = List.length el; // a single function can't have >128 stack if count > 120 - ctx.stack && count > 8 then { // split in 8 and recurse var part = count >> 3; function rec loop(el,acc,count) { match el { | [] -> [List.rev acc] | e :: l -> if count == part then List.rev(acc) :: loop el [] 0 else loop l (e :: acc) (count + 1) } } var arr = make_array p (List.map make_array(p) (loop (e :: el) [] 0)); compile_builtin ctx tail "aconcat" [arr] p; } else if ctx.version >= 2 then { compile ctx false e; List.iter (function(e) { write ctx Push; compile ctx false e; }) el; write ctx (MakeArray count); } else { List.iter (function(e) { compile ctx false e; write ctx Push; }) el; compile ctx false e; write ctx (MakeArray count); } | ("apply",e :: el) -> List.iter (function(e) { compile ctx false e; write ctx Push; }) el; compile ctx false e; var nargs = List.length el; if nargs > 0 then write ctx (Apply nargs); | _ -> List.iter (function(e) { compile ctx false e; write ctx Push; }) el; compile_constant ctx (Builtin b) p; if tail then write ctx TailCall(List.length el,ctx.stack - ctx.limit) else write ctx Call(List.length el) } } function rec compile(ctx,tail,(e,p)) { set_pos ctx p; match e { | EConst c -> compile_constant ctx c p | EBlock [] -> write ctx AccNull | EBlock el -> var locals = ctx.locals; var stack = ctx.stack; function rec loop(el) { match el { | [] -> assert() | [e] -> compile ctx tail e | [e; (ELabel _,_) as f] -> compile ctx tail e; compile ctx tail f | e :: el -> compile ctx false e; loop el } } loop el; if stack < ctx.stack then write ctx (Pop (ctx.stack - stack)); check_stack ctx stack p; ctx.locals := locals | EParenthesis e -> compile ctx tail e | EField (e,f) -> compile ctx false e; write ctx (AccField f) | ECall (e,a :: b :: c :: d :: x1 :: x2 :: l) when match e { (EConst (Builtin "array"),_) -> false | _ -> true } -> var call = (EConst (Builtin "call"),p); var args = (ECall (EConst (Builtin "array"),p) (a :: b :: c :: d :: x1 :: x2 :: l),p); match e { | (EField (e,name) , p2) -> var locals = ctx.locals; var etmp = (EConst (Ident "$tmp"),p2); compile ctx false (EVars [("$tmp",Some e)],p2); compile ctx tail (ECall call [(EField etmp name,p2);etmp;args], p); write ctx (Pop 1); ctx.locals := locals | _ -> compile ctx tail (ECall call [e; (EConst This,p); args],p); } | ECall ((EConst (Builtin b),_),el) -> compile_builtin ctx tail b el p | ECall ((EField (e,f),_),el) -> List.iter (function(e) { compile ctx false e; write ctx Push; }) el; compile ctx false e; write ctx Push; write ctx (AccField f); write ctx ObjCall(List.length el) | ECall (e,el) -> List.iter (function(e) { compile ctx false e; write ctx Push; }) el; compile ctx false e; if tail then write ctx TailCall(List.length el,ctx.stack - ctx.limit) else write ctx Call(List.length el) | EArray (e1,(EConst (Int n),_)) -> compile ctx false e1; write ctx (if n == 0 then AccIndex0 else if n == 1 then AccIndex1 else AccIndex n) | EArray (e1,e2) -> compile ctx false e1; write ctx Push; compile ctx false e2; write ctx AccArray | EVars vl -> List.iter (function((v,o)) { match o { | None -> write ctx AccNull | Some e -> compile ctx false e }; write ctx Push; ctx.locals := Map.add ctx.locals v ctx.stack; }) vl | EWhile (econd,e,NormalWhile) -> var start = pos ctx; if ctx.version >= 2 then write ctx Loop; compile ctx false econd; var jend = cjmp false ctx; var save = save_breaks ctx; compile ctx false e; process_continues save; goto ctx start; process_breaks save; jend(); | EWhile (econd,e,DoWhile) -> var start = pos ctx; if ctx.version >= 2 then write ctx Loop; var save = save_breaks ctx; compile ctx false e; process_continues save; compile ctx false econd; write ctx (JumpIf (start - pos ctx)); process_breaks save | EIf (e,e1,e2) -> var stack = ctx.stack; compile ctx false e; var jelse = cjmp false ctx; compile ctx tail e1; check_stack ctx stack p; match e2 { | None -> jelse() | Some e2 -> var jend = jmp ctx; jelse(); compile ctx tail e2; check_stack ctx stack p; jend() }; | ETry (e,v,ecatch) -> var trap = trap ctx; var breaks = ctx.breaks; var continues = ctx.continues; ctx.breaks := []; ctx.continues := []; ctx.traps := ctx.stack :: ctx.traps; compile ctx false e; if ctx.breaks != [] then error "Break in try...catch is not allowed" p; if ctx.continues != [] then error "Continue in try...catch is not allowed" p; ctx.breaks := breaks; ctx.continues := continues; write ctx EndTrap; ctx.traps := match ctx.traps { [] -> assert() | _ :: l -> l }; var jend = jmp ctx; trap(); write ctx Push; var locals = ctx.locals; ctx.locals := Map.add ctx.locals v ctx.stack; compile ctx tail ecatch; write ctx (Pop 1); ctx.locals := locals; jend() | EBinop (op,e1,e2) -> compile_binop ctx tail op e1 e2 p | EReturn e -> match e { None -> write ctx AccNull | Some e -> compile ctx (ctx.traps == []) e }; var i = &0; var stack = ctx.stack; List.iter (function(t) { if ctx.stack > t then write ctx Pop(ctx.stack - t); write ctx EndTrap; }) ctx.traps; write ctx (Ret (ctx.stack - ctx.limit)); ctx.stack := stack | EBreak e -> match e { | None -> () | Some e -> compile ctx false e }; if ctx.loop_limit != ctx.stack then { var s = ctx.stack; write ctx Pop(ctx.stack - ctx.loop_limit); ctx.stack := s; } ctx.breaks := (jmp ctx , p) :: ctx.breaks | EContinue -> if ctx.loop_limit != ctx.stack then { var s = ctx.stack; write ctx Pop(ctx.stack - ctx.loop_limit); ctx.stack := s; } ctx.continues := (jmp ctx , p) :: ctx.continues | EFunction (params,e) -> compile_function ctx params e | ENext (e1,e2) -> compile ctx false e1; compile ctx tail e2 | EObject [] -> write ctx AccNull; write ctx New | EObject fl -> var fields = List.sort compare (List.map fst fl); var id = try Hashtbl.find ctx.g.gobjects fields catch { Not_found -> var id = global ctx (GlobalVar ("o:" + Hashtbl.length ctx.g.gobjects)); Hashtbl.add ctx.g.gobjects fields id; id }; write ctx (AccGlobal id); write ctx New; write ctx Push; List.iter (function((f,e)) { write ctx Push; compile ctx false e; write ctx (SetField f); write ctx AccStack0; }) fl; write ctx (Pop 1) | ELabel l -> var l = try Hashtbl.find ctx.g.labels l catch { Not_found -> assert() }; if ctx.stack != l.lstack || List.rev(ctx.traps) != l.ltraps then error (sprintf "Label failure %d %d %s %s" (ctx.stack,l.lstack,string List.rev(ctx.traps),string l.ltraps)) p; List.iter (function(f) { f() }) l.lwait; l.lwait := []; l.lpos := Some (pos ctx) | ESwitch (e,[(econd,exec)],eo) -> compile ctx tail (EIf (EBinop "==" e econd,p) exec eo,p) | ESwitch (e,cases,eo) -> try { var ints , size = get_cases_ints cases; compile ctx false e; write ctx (JumpTable size); var tbl = Array.make size None; List.iter (function((i,e)) { tbl.[i] := Some e; }) ints; var tbl = Array.map (function(e) { (jmp ctx,e) }) tbl; Array.iter (function((j,e)) { if e == None then j() }) tbl; match eo { | None -> write ctx AccNull | Some e -> compile ctx tail e } var jump_end = jmp ctx; var tbl = Array.map (function((j,e)) { match e { | Some e -> j(); compile ctx tail e; jmp ctx | None -> function() { } } }) tbl; jump_end(); Array.iter (function(j) { j() }) tbl } catch { Exit -> compile ctx false e; write ctx Push; var jumps = List.map (function((e1,e2)) { write ctx AccStack0; write ctx Push; compile ctx false e1; write ctx Eq; (cjmp true ctx , e2) }) cases; match eo { | None -> write ctx AccNull | Some e -> compile ctx tail (EBlock [e],p) } var jump_end = jmp ctx; var jumps = List.map (function((j,e)) { j(); compile ctx tail (EBlock [e],p); jmp ctx; }) jumps; jump_end(); List.iter (function(j) { j() }) jumps; write ctx (Pop 1) } } } function compile(version,ast) { var g = { globals = Hashtbl.create(); gobjects = Hashtbl.create(); gtable = Array.create(); functions = []; labels = Hashtbl.create(); hfiles = Hashtbl.create(); files = Array.create(); }; var ctx = { g = g; version = version; stack = 0; loop_limit = 0; limit = -1; locals = Map.empty(); ops = Array.create(); breaks = []; continues = []; env = Map.empty(); nenv = 0; traps = []; pos = Array.create(); curpos = (0,0); curfile = "_"; }; if version >= 2 then Array.add g.gtable (GlobalVersion version); scan_labels ctx true true ast; compile ctx false ast; check_breaks ctx; if g.functions != [] || Hashtbl.length g.gobjects != 0 then { var ctxops = ctx.ops; var ctxpos = ctx.pos; var ops = Array.create(); var pos = Array.create(); ctx.pos := pos; ctx.ops := ops; write ctx (Jump 0); List.iter (function((fops,fpos,gid,nargs)) { Array.set g.gtable gid GlobalFunction(Array.length ops,nargs); Array.append fops ops; Array.append fpos pos; }) (List.rev g.functions); Array.set ops 0 (Jump (Array.length ops)); var objects = Array.create(); Hashtbl.iter (function(fl,g) Array.add objects (fl,g)) g.gobjects; Array.sort (function((_,g1),(_,g2)) g1 - g2) objects; Array.iter (function((fl,g)) { write ctx AccNull; write ctx New; write ctx (SetGlobal g); List.iter (function(f) { write ctx (AccGlobal g); write ctx Push; write ctx (SetField f); }) fl }) objects; Array.append ctxpos pos; Array.append ctxops ops; }; Array.add g.gtable (GlobalDebug ctx.g.files ctx.pos); (g.gtable, ctx.ops) } neko-2.0.0/src/neko/Printer.nml0000644000175000017500000001275612112157473017045 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Neko.Ast type ctx { ch : IO.output; mutable level : int; mutable tabs : bool; } function create(ch) { { ch = ch; level = 0; tabs = true; } } function newline(ctx) { IO.write_char ctx.ch '\n'; ctx.tabs := false; } function level(ctx,b) { ctx.level := ctx.level + (if b then 1 else -1); newline ctx } function printf(ctx) { if !ctx.tabs then { IO.write ctx.ch (String.make (ctx.level * 4) ' '); ctx.tabs := true; }; IO.printf ctx.ch } function rec print_list(ctx,sep,f,x) { match x { | [] -> () | x :: [] -> f x | x :: l -> f x; printf ctx "%s" sep; print_list ctx sep f l } } function print(ctx,n) { printf ctx "%s" n } function rec print_ast(ctx,binop,(e,p)) { var print_rec = print_ast ctx false; match e { | EConst c -> printf ctx "%s" (s_constant c) | EBlock el -> print ctx "{"; level ctx true; List.iter (function(e) { print_rec e; if ctx.tabs then { print ctx ";"; newline ctx; } }) el; ctx.level := ctx.level - 1; print ctx "}"; newline ctx; | EParenthesis e when !ctx.tabs -> print ctx "{ "; print_rec e; print ctx " }"; | EParenthesis e -> print ctx "( "; print_rec e; print ctx " )"; | EField (e,s) -> print_rec e; printf ctx ".%s" s; | ECall (e,el) -> print_rec e; print ctx "("; print_list ctx "," print_rec el; print ctx ")"; | EArray (e1,e2) -> print_rec e1; print ctx "["; print_rec e2; print ctx "]" | EVars vl -> print ctx "var "; print_list ctx ", " (function((n,v)) { printf ctx "%s" n; match v { | None -> () | Some e -> print ctx " = "; print_rec e } }) vl; print ctx ";"; newline ctx | EWhile(cond,e,NormalWhile) -> print ctx "while "; print_rec cond; level_expr ctx e false; | EWhile (cond,e,DoWhile) -> print ctx "do "; level_expr ctx e false; print ctx "while "; print_rec cond; newline ctx | EIf (cond,e,e2) -> print ctx "if "; print_rec cond; level_expr ctx e (e2 == None); match e2 { | None -> () | Some e -> print ctx "else"; level_expr ctx e false } | ETry (e,id,e2) -> print ctx "try"; level_expr ctx e false; printf ctx "catch %s" id; level_expr ctx e2 false; | EFunction (params,e) -> print ctx "function("; print_list ctx "," (printf ctx "%s") params; print ctx ")"; level_expr ctx e false; | EBinop (op,e1,e2) -> var tabs = ctx.tabs; if binop then (if tabs then print ctx "(" else print ctx "{"); print_ast ctx true e1; printf ctx " %s " op; print_ast ctx true e2; if binop then (if tabs then print ctx ")" else print ctx "}"); | EReturn None -> print ctx "return;"; | EReturn (Some e) -> print ctx "return "; print_rec e; | EBreak None -> print ctx "break;"; | EBreak (Some e) -> print ctx "break "; print_rec e; | EContinue -> print ctx "continue" | ENext (e1,e2) -> print_rec e1; print ctx ";"; newline ctx; print_rec e2 | EObject [] -> print ctx "$new(null)" | EObject fl -> print ctx "{"; level ctx true; function rec loop(x) { match x { | [] -> assert() | [(f,e)] -> printf ctx "%s => " f; print_rec e; newline ctx; | (f,e) :: l -> printf ctx "%s => " f; print_rec e; print ctx ", "; newline ctx; loop l } }; loop fl; level ctx false; print ctx "}" | ELabel s -> printf ctx "%s:" s | ESwitch (e,cases,eo) -> print ctx "switch "; print_rec e; print ctx "{"; newline ctx; List.iter (function((e1,e2)) { print_rec e1; print ctx " => "; level ctx true; print_rec e2; level ctx false; }) cases; match eo { | None -> () | Some e -> print ctx "default => "; level ctx true; print_rec e; level ctx false } print ctx "}"; newline ctx } } function rec level_expr(ctx,(e,p),closed) { match e { | EBlock _ -> if ctx.tabs then print ctx " "; print_ast ctx false (e,p) | EParenthesis e -> if ctx.tabs then print ctx " "; print ctx "{"; level ctx true; print_ast ctx false e; level ctx false; print ctx "}"; | _ -> level ctx true; print_ast ctx false (e,p); if closed then print ctx ";"; level ctx false } } function print(ctx,ast) { match fst ast { | EBlock el -> List.iter (function(e) { print_ast ctx false e; if ctx.tabs then { print ctx ";"; newline ctx; } }) el; | _ -> print_ast ctx false ast } } function to_string(ast) { var ch , str = IO.write_string(); var ctx = create ch; print ctx ast; IO.close_out ch; str() } neko-2.0.0/src/neko/Xml.nml0000644000175000017500000001647312112157473016162 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Lexer; open Neko.Ast; open Xml; exception Error : string; var parse_string : (string -> pos -> expr) ref = &(function(_,_) { assert() }); function parse_pos(p,x) { try { var a = attrib x "p"; var f, l = match String.split a ":" { | [] -> assert() | [line] -> (p.psource, int line) | l -> match List.rev l { | [] -> assert() | line :: l -> (String.concat ":" (List.rev l),int line) } }; { psource = f; pmin = p.pmin; pmax = p.pmax; pline = l; } } catch { Not_found -> p } } function rec parse_xml(p,x) { function error() { invalid_arg(); } var p = parse_pos p x; function binop(f) { match nodes x { | [a;b] -> (f (parse_xml p a) (parse_xml p b),p) | _ -> error() } } match node_name x { | "i" -> var v = int (attrib x "v"); (EConst Int(v),p) | "f" -> var v = attrib x "v"; (EConst Float(v),p) | "s" -> var v = attrib x "v"; (EConst String(String.unescape v),p) | "v" -> var v = attrib x "v"; if String.get v 0 == '$' then (EConst Builtin(String.sub v 1 (String.length v - 1)),p) else match v { | "true" -> (EConst True,p) | "false" -> (EConst False,p) | "null" -> (EConst Null,p) | "this" -> (EConst This,p) | _ -> (EConst Ident(v),p) } | "b" -> (EBlock (List.map (parse_xml p) (nodes x)),p) | "p" -> (EParenthesis (parse_xml p (firstNode x)),p) | "g" -> var v = attrib x "v"; (EField (parse_xml p (firstNode x)) v,p) | "c" -> match nodes x { | [] -> error() | x :: l -> (ECall (parse_xml p x) (List.map (parse_xml p) l),p) } | "a" -> binop EArray | "var" -> (EVars (List.map (function(x) { var e = try Some (firstNode x) catch { _ -> None }; (attrib x "v", match e { None -> None | Some x -> Some (parse_xml p x) }) }) nodes(x)),p) | "while" -> binop (function(a,b) { EWhile a b NormalWhile }) | "do" -> binop (function(a,b) { EWhile b a DoWhile }) | "if" -> match nodes x { | [cond;e] -> (EIf (parse_xml p cond) (parse_xml p e) None,p) | [cond;e1;e2] -> (EIf (parse_xml p cond) (parse_xml p e1) Some(parse_xml p e2),p) | _ -> error() } | "o" -> var v = attrib x "v"; binop (EBinop v) | "try" -> var v = attrib x "v"; binop (function(a,b) { ETry a v b }) | "function" -> var args = String.split (attrib x "v") ":"; (EFunction args (parse_xml p (firstNode x)),p) | "return" -> var x = try Some (firstNode x) catch { _ -> None }; (EReturn (match x { None -> None | Some x -> Some (parse_xml p x) }),p) | "break" -> var x = try Some (firstNode x) catch { _ -> None }; (EBreak (match x { None -> None | Some x -> Some (parse_xml p x) }),p) | "continue" -> (EContinue,p) | "next" -> binop ENext | "object" -> (EObject (List.map (function(x) { (attrib x "v", parse_xml p (firstNode x)) }) nodes(x)),p) | "label" -> var v = attrib x "v"; (ELabel v,p) | "switch" -> var cases = &[]; var def = &None; var e = &None; List.iter (function(x) { match node_name x { | "case" -> var c = match nodes x { | [a;b] -> (parse_xml p a, parse_xml p b) | _ -> error() }; cases := c :: *cases; | "default" -> if *def != None then error(); def := Some (parse_xml p firstNode(x)); | _ -> if *e != None then error(); e := Some (parse_xml p x); } }) nodes(x); match *e { | None -> error() | Some e -> (ESwitch e (List.rev (*cases)) (*def),p) } | "neko" -> var e , _ = (*parse_string) (node_text x) p; (e,p) | n -> throw Error("Unknown node name : "+n); } } function parse(s,p) { var x = parse s; match nodes x { | [(Node _) as x] -> parse_xml p x | _ -> invalid_arg() } } function rec to_xml_rec(p2,ast) { var e , p = ast; var name = &""; var val = &None; var childs = &[]; match e { | EConst c -> match c { | True | False | Null | This | Builtin _ | Ident _ -> name := "v"; val := Some (s_constant c) | Int i -> name := "i"; val := Some (string i); | Float s -> name := "f"; val := Some s; | String s -> name := "s"; val := Some s; } | EBlock el -> name := "b"; childs := List.map (to_xml_rec p) el; | EParenthesis e -> name := "p"; childs := [to_xml_rec p e]; | EField (e,f) -> name := "g"; val := Some f; childs := [to_xml_rec p e]; | ECall (e,el) -> name := "c"; childs := to_xml_rec p e :: List.map (to_xml_rec p) el; | EArray (a,b) -> name := "a"; childs := [to_xml_rec p a; to_xml_rec p b]; | EVars vl -> name := "var"; childs := List.map (function((v,e)) { Node "v" [("v",v)] (match e { None -> [] | Some e -> [to_xml_rec p e] }) }) vl; | EWhile (econd,e,NormalWhile) -> name := "while"; childs := [to_xml_rec p econd; to_xml_rec p e]; | EWhile (econd,e,DoWhile) -> name := "do"; childs := [to_xml_rec p e; to_xml_rec p econd]; | EIf (cond,e,eelse) -> name := "if"; childs := to_xml_rec p cond :: to_xml_rec p e :: (match eelse { None -> [] | Some e -> [to_xml_rec p e] }) | ETry (e1,v,e2) -> name := "try"; val := Some v; childs := [to_xml_rec p e1; to_xml_rec p e2]; | EFunction (args,e) -> name := "function"; val := Some (String.concat ":" args); childs := [to_xml_rec p e]; | EBinop (op,e1,e2) -> name := "o"; val := Some op; childs := [to_xml_rec p e1; to_xml_rec p e2]; | EReturn e -> name := "return"; childs := match e { None -> [] | Some e -> [to_xml_rec p e]}; | EBreak e -> name := "break"; childs := match e { None -> [] | Some e -> [to_xml_rec p e]}; | EContinue -> name := "continue"; | ENext (e1,e2) -> name := "next"; childs := [to_xml_rec p e1; to_xml_rec p e2]; | EObject fl -> name := "object"; childs := List.map (function((v,e)) { Node "v" [("v",v)] [to_xml_rec p e] }) fl; | ELabel v -> name := "label"; val := Some v; | ESwitch (e,cases,def) -> name := "switch"; var cases = List.map (function((e1,e2)) { Node "case" [] [to_xml_rec p e1; to_xml_rec p e2] }) cases; childs := to_xml_rec p e :: (match def { None -> cases | Some e -> Node "default" [] [to_xml_rec p e] :: cases }); } var pos = (if p.psource != p2.psource then [("p",p.psource + ":" + p.pline)] else if p.pline != p2.pline then [("p",string p.pline)] else []); var val = match *val { None -> [] | Some v -> [("v",v)] }; Node (*name) (List.append pos val) (*childs) } function to_xml(ast) { to_xml_rec null_pos ast } neko-2.0.0/src/neko/Parser.nml0000644000175000017500000001661712112157473016656 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Lexer; open Neko.Ast; type error_msg { Unexpected : token; Unclosed : string; Invalid_nxml : error; } exception Error : (error_msg , pos) function error_msg(m) { match m { | Unexpected t -> "Unexpected " + s_token t | Unclosed s -> "Unclosed " + s | Invalid_nxml e -> "Invalid nxml (" + string e + ")" } } function error(m,p) { throw Error(m,p) } function priority(x) { match x { | "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | ">>>=" | "|=" | "&=" | "^=" -> -4 | "++=" | "--=" -> -3 | "&&" | "||" -> -2 | "==" | "!=" | ">" | "<" | "<=" | ">=" -> -1 | "+" | "-" -> 0 | "*" | "/" -> 1 | "|" | "&" | "^" -> 2 | "<<" | ">>" | "%" | ">>>" -> 3 | _ -> 4 } } function mk(t,p) { (t,p) } function rec make_binop(op,e,e2) { var v , p2 = e2; match v { | EBinop (_op,_e,_e2) when priority _op <= priority op -> var _e = make_binop op e _e; mk EBinop(_op,_e,_e2) punion(pos _e,pos _e2) | _ -> mk EBinop(op,e,e2) punion(pos e,pos e2) } } function rec program(s) { match s { | [< e = expr s; p = program s >] -> e :: p | [< (Semicolon,_); p = program s >] -> p | [< (Eof,_) >] -> [] } } function rec expr(s) { match s { | [< (Const ((Ident k) as i),p) >] -> match s { | [< (Binop ":",p2) >] -> mk ELabel(k) punion(p,p2) | [< >] -> expr_next (EConst i,p) s } | [< (Const c,p) >] -> expr_next (EConst c,p) s | [< (BraceOpen,p1); e = block1 s >] -> match s { | [< (BraceClose,p2) >] -> expr_next (e,punion p1 p2) s | [< (Eof,_) >] -> error (Unclosed "{") p1 } | [< (ParentOpen,p1); e = expr s >] -> match s { | [< (ParentClose,p2) >] -> expr_next (EParenthesis e,punion p1 p2) s | [< (Eof,_) >] -> error (Unclosed "(") p1 } | [< (Keyword Var,p1); v , p2 = variables p1 s >] -> expr_next (EVars v,punion p1 p2) s | [< (Keyword While,p1); cond = expr s; e = expr s >] -> expr_next (EWhile cond e NormalWhile, punion p1 (pos e)) s | [< (Keyword Do,p1); e = expr s; (Keyword While,_); cond = expr s >] -> expr_next (EWhile cond e DoWhile, punion p1 (pos cond)) s | [< (Keyword Switch,p1); v = expr s; (BraceOpen,_); l , def = switch_cases s; (BraceClose,p2) >] -> expr_next (ESwitch v l def,punion p1 p2) s; | [< (Keyword If,p1); cond = expr s; e = expr s >] -> function rec loop() { match s { | [< (Keyword Else,_); e2 = expr s >] -> expr_next (EIf cond e Some(e2),punion p1 (pos e2)) s | [< (Semicolon,_) >] -> loop() | [< >] -> expr_next (EIf cond e None,punion p1 (pos e)) s } }; loop() | [< (Keyword Function,p1); (ParentOpen,po); p = parameter_names s >] -> match s { | [< (ParentClose,_); e = expr s >] -> expr_next (EFunction p e,punion p1 (pos e)) s | [< (Eof,_) >] -> error (Unclosed "(") po } | [< (Keyword Return,p1) >] -> match s { | [< e = expr s >] -> expr_next (EReturn (Some e), punion p1 (pos e)) s | [< (Semicolon,_) >] -> expr_next (EReturn None,p1) s } | [< (Keyword Break,p1) >] -> match s { | [< e = expr s >] -> expr_next (EBreak (Some e), punion p1 (pos e)) s | [< (Semicolon,_) >] -> expr_next (EBreak None,p1) s } | [< (Keyword Continue,p1) >] -> expr_next (EContinue,p1) s | [< (Keyword Try,p1); e = expr s; (Keyword Catch,_); (Const (Ident name),_); e2 = expr s >] -> expr_next (ETry e name e2,punion p1 (pos e2)) s | [< (Binop "-",p1); e2 = expr s >] -> (EParenthesis (make_binop "-" (EConst (Int 0),p1) e2), punion p1 (pos e2)) } } function rec expr_next(e,s) { match s { | [< (Dot,_); (Const (Ident name),p) >] -> expr_next (EField e name,punion (pos e) p) s | [< (ParentOpen,po); pl = parameters s >] -> match s { | [< (ParentClose,p) >] -> expr_next (ECall e pl,punion (pos e) p) s | [< (Eof,_) >] -> error (Unclosed "(") po } | [< (BracketOpen,po); e2 = expr s >] -> match s { | [< (BracketClose,p) >] -> expr_next (EArray e e2,punion (pos e) p) s | [< (Eof,_) >] -> error (Unclosed "[") po } | [< (Binop op,_); e2 = expr s >] -> make_binop op e e2 | [< >] -> e } } function rec block1(s) { match s { | [< (Const (Ident name),p) >] -> match s { | [< (Arrow,_); e = expr s; l = object_fields s >] -> EObject ((name,e) :: l) | [< (Binop ":",p2); b = block s >] -> EBlock ( (ELabel name, punion p p2) :: b ) | [< e = expr_next (EConst (Ident name),p) s; b = block s >] -> EBlock (e :: b) } | [< b = block s >] -> EBlock b } } function rec block(s) { match s { | [< e = expr s; b = block s >] -> e :: b | [< (Semicolon,_); b = block s >] -> b | [< >] -> [] } } function rec object_fields(s) { match s { | [< (Const (Ident name),_); (Arrow,_); e = expr s; l = object_fields s >] -> (name,e) :: l | [< (Comma,_); l = object_fields s >] -> l | [< >] -> [] } } function rec switch_cases(s) { match s { | [< e1 = expr s; (Arrow,p); e2 = expr s; l , def = switch_cases s >] -> ((e1,e2) :: l , def) | [< (Keyword Default,pp); (Arrow,p); e = expr s; l, def = switch_cases s >] -> match def { | None -> (l, Some e) | Some _ -> error (Unexpected (Keyword Default)) pp } | [< >] -> ([] , None) } } function rec parameter_names(s) { match s { | [< (Const (Ident name),_); p = parameter_names s >] -> name :: p | [< (Comma,_); p = parameter_names s >] -> p | [< >] -> [] } } function rec parameters(s) { match s { | [< e = expr s; p = parameters_next s >] -> e :: p | [< >] -> [] } } function rec parameters_next(s) { match s { | [< (Comma,_); p = parameters s >] -> p | [< >] -> [] } } function rec variables(sp,s) { match s { | [< (Const (Ident name),p) >] -> match s { | [< (Binop "=",_); e = expr s; v , p = variables_next (pos e) s >] -> ((name, Some e) :: v , p) | [< v , p = variables_next p s >] -> ((name, None) :: v , p) } } } function rec variables_next(sp,s) { match s { | [< (Comma,p); v = variables p s >] -> v | [< >] -> ([] , sp) } } function parse(lexer) { var last = &(Eof,null_pos); function rec next_token() { var t = Lexer.token lexer (*Neko.Lexer.expr); match fst t { | Comment s | CommentLine s -> next_token() | _ -> last := t; t } } try { var p = program (stream next_token); (EBlock p,null_pos) } catch { Stream_error -> error Unexpected(fst(*last)) snd(*last) } } function parse_string(str,p) { var ch = IO.read_string str; var lex = Lexer.create Buffer.create(); Lexer.input lex p.psource ch p.pline p.pmin; parse lex } Neko.Xml.parse_string := parse_string; Neko.Binast.parse_from_string := parse_string; neko-2.0.0/src/neko/Linker.nml0000644000175000017500000001354012112157473016636 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Neko.Bytecode; type context { globals : global array; opcodes : opcode array; debug : (int, int) array; debug_files : string array; loaded : (string, int option) Hashtbl.t; mutable version : int option; mutable have_debug : bool; } var neko_path : string list = neko "@List.@make($loader.path)"; function file_open(file) { function rec loop(l) { match l { | [] -> throw Error("File not found : " + file) | p :: l -> try IO.read_file (p + file) true; catch { _ -> loop l } } } loop ("" :: neko_path) } function rec do_link(ctx,module) { print (module + "\n"); var ch = file_open (module + ".n"); var globals, opcodes = Neko.Bytecode.read ch; IO.close_in ch; var debug = &None; var funcs = &[]; var version = &0; var gtbl = Array.map (function(g) { match g { | GlobalVar _ -> var k = Array.length ctx.globals; Array.add ctx.globals g; k | GlobalFunction (p,nargs) -> var k = Array.length ctx.globals; Array.add ctx.globals g; funcs := (p,nargs,k) :: *funcs; k | GlobalString _ | GlobalFloat _ -> try Array.index ctx.globals g catch { Not_found -> var k = Array.length ctx.globals; Array.add ctx.globals g; k } | GlobalDebug(files,inf) -> ctx.have_debug := true; debug := Some (files,inf); -1 | GlobalVersion v -> if ctx.version == None then { ctx.version := Some v; Array.add ctx.globals GlobalVersion(v); } version := v; -1 } }) globals; match ctx.version { | None -> ctx.version := Some (*version); | Some v2 -> if v2 != (*version) then throw Error("Linking modules with different version"); } var mid = Array.length ctx.globals; var module_fid = Array.length ctx.debug_files; Array.add ctx.debug_files module; Array.add ctx.globals (GlobalVar module); List.iter (Array.add ctx.opcodes) [AccNull; Push; AccBuiltin "new"; Call 1; SetGlobal mid]; Array.append (Array.make 8 (module_fid,0)) ctx.debug; Hashtbl.add ctx.loaded module None; var nops = Array.length opcodes; var opmap = Array.make nops (-1); var debug = match *debug { | None -> Array.make (nops*2) (module_fid,0) | Some(files,inf) -> var fmap = Array.map (function(f) { var p = Array.length ctx.debug_files; Array.add ctx.debug_files f; p }) files; Array.map (function((f,p)) { (fmap.[f],p) }) inf }; var debug_pos = &0; var jumps = &[]; function op(o) { Array.add ctx.opcodes o; Array.add ctx.debug (Array.get debug (*debug_pos)); debug_pos := *debug_pos + 1; if Neko.Bytecode.op_param o then { Array.add ctx.debug (Array.get debug (*debug_pos)); debug_pos := *debug_pos + 1; } } function jump(mkop,p,i) { var k = Array.length ctx.opcodes; op (Jump 0); jumps := (mkop,k,p,i) :: *jumps } function rec loop((p,l)) { match l { | [] -> assert() // $loader.loadmodule("name",$loader) | (AccGlobal str) :: Push :: (AccBuiltin "loader") :: Push :: (AccBuiltin "loader") :: Push :: (AccField "loadmodule") :: (ObjCall 2) :: l -> match Array.get globals str { | GlobalString s -> var mid = try Hashtbl.find ctx.loaded s catch { Not_found -> Some (do_link ctx s) }; match mid { | None -> throw Error("Recursive loading " + module + " => " + s) | Some i -> op (AccGlobal i); debug_pos := *debug_pos + 11; (p + 8, l) } | _ -> throw Error("Cannot link not constant file") } | o :: l -> Array.set opmap p (Array.length ctx.opcodes); match o { | AccBuiltin "exports" -> op (AccGlobal mid) | AccGlobal g -> op (AccGlobal (Array.get gtbl g)); | SetGlobal g -> op (SetGlobal (Array.get gtbl g)); | Jump i -> jump Jump p i | JumpIf i -> jump JumpIf p i | JumpIfNot i -> jump JumpIfNot p i | Trap i -> jump Trap p i | _ -> op o } (p+1 , l) } } var l = &(0,Array.list opcodes); while snd (*l) != [] { l := loop (*l) } List.iter (function((op,k,p,i)) { var ik = Array.get opmap (p + i) - Array.get opmap p; Array.set ctx.opcodes k op(ik) }) (*jumps); List.iter (function((p,nargs,k)) { Array.set ctx.globals k (GlobalFunction (Array.get opmap p) nargs) }) (*funcs); Hashtbl.replace ctx.loaded module (Some mid); Array.add ctx.opcodes (AccGlobal mid); Array.add ctx.debug (module_fid,0); Array.add ctx.debug (module_fid,0); mid } function link(output,modules) { var ctx = { globals = Array.create(); opcodes = Array.create(); debug = Array.create(); debug_files = Array.create(); loaded = Hashtbl.create(); have_debug = false; version = None; }; List.iter (function(m) { ignore(do_link ctx m) }) modules; if ctx.have_debug then Array.add ctx.globals (GlobalDebug ctx.debug_files ctx.debug); var ch = IO.write_file output true; Neko.Bytecode.write ch (ctx.globals,ctx.opcodes); IO.close_out ch } neko-2.0.0/src/neko/Doc.nml0000644000175000017500000002210712112157473016116 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type doc_type { TBase : string; TAbstract : string; TCustom : string; TFun : (doc_type, doc_type); TOpt : doc_type; TStar : doc_type; TMult : doc_type list; TObj : (string , doc_type) list; TNamed : (string , doc_type); TPoly : (string, doc_type); TFunction : int; } type doc_item { Function : (string , doc_type, Xml.t option); Document : Xml.t; } type doc = doc_item list type token { Eof; Begin; End; Star; Question; Arrow; DoubleDot; POpen; PClose; BrOpen; BrClose; Comma; Field; Or; Quote; Sharp; Int : int; Doc : Xml.t; Ident : string; } type status { mutable doc : bool; buf : Buffer.t; } type error_msg { Unexpected : token; Invalid_char : char; Unknown_type : string; Unclosed_doc; Invalid_doc; } exception Error : (error_msg,Lexer.pos); function error(msg,p) { throw Error(msg,p) } function s_token(t) { match t { | Eof -> "" | Begin -> "/**" | End -> "**/" | DoubleDot -> ":" | Arrow -> "->" | Star -> "*" | POpen -> "(" | PClose -> ")" | BrOpen -> "{" | BrClose -> "}" | Comma -> "," | Field -> "=>" | Or -> "|" | Quote -> "'" | Sharp -> "#" | Question -> "?" | Int i -> string i | Ident i -> i | Doc d -> ""+Xml.to_string d+"" } } function error_msg(msg) { match msg { | Unexpected t -> "Unexpected " + s_token t | Invalid_char c -> "Invalid character " + String.escape_char c | Unknown_type s -> "Unknown type " + s | Unclosed_doc -> "Unclosed doc tag" | Invalid_doc -> "Documentation is not XHTML valid" } } function mk_tok(l,t) { (t,Lexer.curpos l) } function status() { { buf = Buffer.create(); doc = false; } } var doc_token = &Lexer.empty(); var doc_content = &Lexer.empty(); var doc_doc = &Lexer.empty(); doc_token := Lexer.build [ ("/\\*\\*" , function(l) { (Lexer.data l).doc := true; mk_tok l Begin }); ("/" , function(l) { Lexer.token l (*doc_token) }); ("[^/]+", function(l) { Lexer.token l (*doc_token) }); ] (function(l) { mk_tok l Eof }); doc_content := Lexer.build [ ("\\*\\*/", function(l) { (Lexer.data l).doc := false; mk_tok l End }); (":", function(l) { mk_tok l DoubleDot }); ("(", function(l) { mk_tok l POpen }); (")", function(l) { mk_tok l PClose }); ("{", function(l) { mk_tok l BrOpen }); ("}", function(l) { mk_tok l BrClose }); (",", function(l) { mk_tok l Comma }); ("=>", function(l) { mk_tok l Field }); ("|", function(l) { mk_tok l Or }); ("->", function(l) { mk_tok l Arrow }); ("\\*", function(l) { mk_tok l Star }); ("\\?", function(l) { mk_tok l Question }); ("'", function(l) { mk_tok l Quote }); ("#", function(l) { mk_tok l Sharp }); ("", function(l) { var p1 = Lexer.curpos l; var buf = (Lexer.data l).buf; Buffer.reset buf; try Lexer.token l (*doc_doc) catch { Exit -> error Unclosed_doc p1 }; var p2 = Lexer.curpos l; var x = try Xml.parse (Buffer.string buf) catch { _ -> error Invalid_doc p1 }; (Doc x, Lexer.punion p1 p2) }); ("[ \t\r\n]+", function(l) { Lexer.token l (*doc_content) }); ("[0-9]+", function(l) { mk_tok l Int(int (Lexer.current l)) }); ("$?[a-zA-Z_@][a-zA-Z0-9_@]*", function(l) { mk_tok l Ident(Lexer.current l) }); ] (function(l) { match Lexer.char l { | None -> mk_tok l Eof | Some c -> error Invalid_char(c) Lexer.curpos(l) } }); doc_doc := Lexer.build [ ("", function(l) { }); ("<", function(l) { Buffer.add_char (Lexer.data l).buf '<'; Lexer.token l (*doc_doc) }); ("[^<]+", function(l) { Buffer.add (Lexer.data l).buf Lexer.current(l); Lexer.token l (*doc_doc) }); ] (function(l) { throw Exit }); function rec documentation(s) { match s { | [< (Eof,_) >] -> [] | [< (Begin,_); d = document s; (End,_); l = documentation s >] -> d :: l } } function rec document(s) { match s { | [< (Ident i,_); (DoubleDot,_); t = doc_type s; d = doc_option s >] -> Function i t d | [< (Doc d,_) >] -> Document d } } function rec doc_option(s) { match s { | [< (Doc d,_) >] -> Some d | [< >] -> None } } function rec doc_type(s) { match s { | [< t = doc_type_base s >] -> doc_type_next t s } } function rec doc_type_base(s) { match s { | [< (Quote,_); (Ident i,_); >] -> TAbstract i | [< (Sharp,_); (Ident i,_); >] -> TCustom i | [< (Ident i,p) >] -> match i { | "null" | "int" | "float" | "string" | "array" | "bool" | "any" | "void" | "number" | "object" -> TBase i | "function" -> match s { | [< (DoubleDot,_); (Int n,_) >] -> TFunction n | [< >] -> TBase i } | _ -> match s { | [< (DoubleDot,_); t = doc_type_base s >] -> TNamed i t | [< >] -> error Unknown_type(i) p } } | [< (POpen,_); t = doc_type s; l = doc_type_list s; (PClose,_) >] -> TMult (t :: l) | [< (BrOpen,_); f = doc_type_fields s; (BrClose,_) >] -> TObj f } } function rec doc_type_next(t,s) { match s { | [< (Arrow,_); t2 = doc_type s >] -> doc_type_next (TFun t t2) s | [< (Star,_) >] -> doc_type_next (TStar t) s | [< (Question,_) >] -> doc_type_next (TOpt t) s | [< (Ident "array",_) >] -> doc_type_next TPoly("array",t) s | [< (Ident "list",_) >] -> doc_type_next TPoly("list",t) s | [< >] -> t } } function rec doc_type_list(s) { match s { | [< (Or,_); t = doc_type s; l = doc_type_list s >] -> t :: l | [< >] -> [] } } function rec doc_type_fields(s) { match s { | [< (Ident i,_); (Field,_); t = doc_type s >] -> (i,t) :: doc_type_fields s | [< (Comma,_) >] -> doc_type_fields s | [< >] -> [] } } function parse(lex) : doc { var last = &(Eof,Lexer.null_pos); function rec next_token() { var t = Lexer.token lex (if (Lexer.data lex).doc then (*doc_content) else (*doc_token)); last := t; t } try { documentation (stream next_token) } catch { Stream_error -> error Unexpected(fst(*last)) snd(*last) } } function rec type_write(ch,t) { match t { | TBase b -> IO.write ch b | TAbstract a -> IO.printf ch "'%s" a | TCustom s -> IO.printf ch "#%s" s | TFun (t1,t2) -> type_write_par ch t1; IO.write ch " -> "; type_write ch t2 | TOpt t -> type_write_par ch t; IO.write ch "?" | TStar t -> type_write_par ch t; IO.write ch "*" | TMult l -> IO.write ch "("; function rec loop(l) { match l { | [] -> () | [t] -> type_write_par ch t | t :: l -> type_write_par ch t; IO.write ch " | "; loop l } } loop l; IO.write ch ")" | TObj l -> IO.write ch "{ "; function rec loop(l) { match l { | [] -> () | [(n,t)] -> IO.write ch n; IO.write ch " => "; type_write ch t; | (n,t) :: l -> IO.write ch n; IO.write ch " => "; type_write ch t; IO.write ch ", "; loop l } } loop l; IO.write ch "}"; | TNamed (s,t) -> IO.printf ch "%s : " s; type_write_par ch t | TPoly (s,t) -> type_write_par ch t; IO.printf ch " %s" s | TFunction n -> IO.printf ch "function:%d" n } } function rec type_write_par(ch,t) { match t { | TFun _ -> IO.write ch "("; type_write ch t; IO.write ch ")"; | _ -> type_write ch t; } } function format_xml(s) { var s = String.concat "" (String.split s "["); var s = String.concat "" (String.split s "]"); s } function to_html(ch,doc) { List.iter (function(d) { match d { | Document x -> IO.write ch (format_xml Xml.to_string(x)); IO.write ch "\n" | Function (f,t,doc) -> IO.write ch "\n"; function rec loop(t) { match t { | TFun (p,r) -> var args , r = loop r; (p :: args, r) | _ -> ([],t) } } var args , r = loop t; match args { | [] -> IO.printf ch " %s : " f; type_write ch r; | _ -> IO.write ch " "; type_write_par ch r; IO.printf ch " %s(" f; function rec loop(l) { match l { | [] -> () | [t] -> type_write ch t | t :: l -> type_write ch t; IO.write ch ", "; loop l } } match args { | [TBase "void"] -> () | _ -> loop args } IO.write ch ")"; } IO.write ch " "; match doc { | None -> () | Some x -> IO.write ch (format_xml Xml.to_string(x)) } IO.write ch "\n\n"; } }) doc; }neko-2.0.0/src/neko/Ast.nml0000644000175000017500000001263312112157473016143 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type pos = Lexer.pos type constant { True; False; Null; This; Int : int; Float : string; String : string; Builtin : string; Ident : string; } type keyword { Var; While; Do; If; Else; Function; Return; Break; Continue; Default; Try; Catch; Switch; } type token { Eof; Semicolon; Dot; Comma; Arrow; BraceOpen; BraceClose; ParentOpen; ParentClose; BracketOpen; BracketClose; Const : constant; Keyword : keyword; Binop : string; Comment : string; CommentLine : string; } type while_flag { NormalWhile; DoWhile; } type expr; type expr_decl { EConst : constant; EBlock : expr list; EParenthesis : expr; EField : (expr , string); ECall : (expr , expr list); EArray : (expr , expr); EVars : (string , expr option) list; EWhile : (expr , expr , while_flag); EIf : (expr , expr , expr option); ETry : (expr , string , expr); EFunction : (string list , expr); EBinop : (string , expr , expr); EReturn : expr option; EBreak : expr option; EContinue; ENext : (expr , expr); EObject : (string , expr) list; ELabel : string; ESwitch : (expr, (expr, expr) list, expr option); } type expr = (expr_decl , pos) function pos((_,x)) { x } var var_args = -1; function mk_call(v,args,p) { (ECall v args , p) } function mk_call0(v,p) { (ECall v [], p) } function mk_call1(v,a,p) { (ECall v [a], p) } function mk_ident(i,p) { (EConst (Ident i), p) } function mk_builtin(b,p) { (EConst (Builtin b), p) } function mk_int(i,p) { (EConst (Int i), p) } function mk_string(s,p) { (EConst (String s), p) } function mk_binop(op,e1,e2,p) { (EBinop op e1 e2, p) } function map(f,(e,p)) { (match e { | EBlock el -> EBlock (List.map f el) | EParenthesis e -> EParenthesis f(e) | EField (e,s) -> EField f(e) s | ECall (e,el) -> ECall f(e) (List.map f el) | EArray (e1,e2) -> EArray f(e1) f(e2) | EVars vl -> EVars(List.map(function((v,e)) { (v , match e { | None -> None | Some e -> Some (f e) }) },vl)) | EWhile (e1,e2,flag) -> EWhile f(e1) f(e2) flag | EIf (e,e1,e2) -> EIf f(e) f(e1) (match e2 { None -> None | Some e -> Some f(e)}) | ETry (e,ident,e2) -> ETry f(e) ident f(e2) | EFunction (params,e) -> EFunction params f(e) | EBinop (op,e1,e2) -> EBinop op f(e1) f(e2) | EReturn (Some e) -> EReturn Some(f e) | EBreak (Some e) -> EBreak Some(f e) | ENext (e1,e2) -> ENext f(e1) f(e2) | EObject fl -> EObject (List.map (function((s,e)) { (s , f e) }) fl) | ESwitch (e,cases,eo) -> ESwitch f(e) (List.map (function((e1,e2)) { (f e1, f e2) }) cases) (match eo { None -> None | Some e -> Some f(e) }) | EReturn None | EBreak None | EContinue | ELabel _ | EConst _ -> e }, p) } function iter(f,(e,p)) { match e { | EBlock el -> List.iter f el | EParenthesis e -> f e | EField (e,s) -> f e | ECall (e,el) -> f e; List.iter f el | EArray (e1,e2) -> f e1; f e2 | EVars vl -> List.iter (function((_,e)) { match e { None -> () | Some e -> f e } }) vl | EWhile (e1,e2,_) -> f e1; f e2 | EIf (e,e1,e2) -> f e; f e1; (match e2 { None -> () | Some e -> f e }) | ETry (e1,_,e2) -> f e1; f e2 | EFunction (_,e) -> f e | EBinop (_,e1,e2) -> f e1; f e2 | EReturn (Some e) -> f e | EBreak (Some e) -> f e | ENext (e1,e2) -> f e1; f e2 | EObject fl -> List.iter (function((_,e)) { f e }) fl | ESwitch (e,cases,eo) -> f e; List.iter (function((e1,e2)) { f e1; f e2 }) cases; match eo { None -> () | Some e -> f e }; | EReturn None | EBreak None | EContinue | ELabel _ | EConst _ -> () } } function s_constant(x) { match x { | True -> "true" | False -> "false" | Null -> "null" | This -> "this" | Int i -> string i | Float s -> s | String s -> "\"" + String.escape s + "\"" | Builtin s -> "$" + s | Ident s -> s } } function s_keyword(x) { match x { | Var -> "var" | While -> "while" | Do -> "do" | If -> "if" | Else -> "else" | Function -> "function" | Return -> "return" | Break -> "break" | Continue -> "continue" | Default -> "default" | Try -> "try" | Catch -> "catch" | Switch -> "switch" } } function s_token(x) { match x { | Eof -> "" | Semicolon -> ";" | Dot -> "." | Comma -> "," | Arrow -> "=>" | BraceOpen -> "{" | BraceClose -> "}" | ParentOpen -> "(" | ParentClose -> ")" | BracketOpen -> "[" | BracketClose -> "]" | Const c -> s_constant c | Keyword k -> s_keyword k | Binop s -> s | Comment s -> "/*" + s + "*/" | CommentLine s -> "//" + s } } neko-2.0.0/src/neko/Console.nml0000644000175000017500000000674512112157473017025 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ function read() { var buf = Buffer.create(); function rec loop() { var l = IO.read_line IO.stdin; var len = String.length l; if len > 0 && String.get l (len - 1) == '!' then Buffer.add buf (String.sub l 0 (len - 1)) else { Buffer.add buf l; Buffer.add_char buf '\n'; loop(); } } loop(); Buffer.string buf } function report(msg,p) { IO.printf IO.stderr "%s(%d): %s\n" (Lexer.source p,Lexer.line p,msg); } function run(version) { var ctx = Hashtbl.create(); function loop() { // read input print "> "; var code = read(); var bytecode , module = if String.length code > 6 && String.sub code 0 6 == "#load " then { // load bytecode var file = String.sub code 6 (String.length code - 6); var input = IO.read_file file true; var bytecode = Neko.Bytecode.read input; IO.close_in input; var input = IO.read_file file true; var str = IO.read_all input; IO.close_in input; (bytecode, str) } else { // parse and compile var input = IO.read_string code; var lex = Lexer.create Buffer.create(); Lexer.input lex "@console" input 1 0; var ast = Neko.Parser.parse lex; var bytecode = Neko.Compile.compile version ast; var output , str = IO.write_string(); Neko.Bytecode.write output bytecode; (bytecode , str()) } // read compiled module var m = Reflect.module_read (IO.input (IO.read_string module)); // set module environement var globals = fst bytecode; Array.iteri (function(i,g) { match g { | Neko.Bytecode.GlobalVar v -> try { var v = Hashtbl.find ctx v; Reflect.module_set_global m i v } catch { Not_found -> () } | _ -> () } }) globals; // execute try { nprint Reflect.neko_value(Reflect.module_execute m); nprint "\n"; } catch { e -> var st = Stack.exc(); Stack.dump IO.stdout st; print "Exception : "; match e { | Neko_error e -> nprint e | _ -> print e } print "\n"; } // save environment Array.iteri (function(i,g) { match g { | Neko.Bytecode.GlobalVar v -> Hashtbl.replace ctx v (Reflect.module_get_global m i) | _ -> () } }) globals; } while true { try { loop() } catch { | Neko.Lexer.Error(msg,pos) -> report Neko.Lexer.error_msg(msg) pos | Neko.Parser.Error(msg,pos) -> report Neko.Parser.error_msg(msg) pos | Neko.Compile.Error(msg,pos) -> report Neko.Compile.error_msg(msg) pos } } }neko-2.0.0/src/neko/Binast.nml0000644000175000017500000001266112112157473016635 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Lexer; open Neko.Ast; type context { ch : IO.input; strings : string array; mutable pos : Lexer.pos; } var parse_from_string : (string -> pos -> expr) ref = &(function(_,_) { assert() }); var header = "NBA\001"; function parse_string(ctx) { var index = IO.read_byte ctx.ch; if index == 0 then { var size = IO.read_ui16 ctx.ch; var str = IO.read ctx.ch size; Array.add ctx.strings str; str } else Array.get ctx.strings (Array.length ctx.strings - index) } function rec parse_list(ctx,f,n) { if n == 0 then [] else { var x = f ctx; x :: parse_list ctx f (n - 1); } } function parse_constant(ctx) { match IO.read_byte ctx.ch { | 0 -> True | 1 -> False | 2 -> Null | 3 -> This | 4 -> Int (IO.read_byte ctx.ch) | 5 -> Int (IO.read_i32 ctx.ch) | 6 -> Float (parse_string ctx) | 7 -> String (parse_string ctx) | 8 -> Builtin (parse_string ctx) | 9 -> Ident (parse_string ctx) | n -> error ("Invalid const tag : " + n) } } function parse_op(ctx) { match IO.read_byte ctx.ch { | 0 -> "+" | 1 -> "-" | 2 -> "/" | 3 -> "*" | 4 -> "%" | 5 -> "<<" | 6 -> ">>" | 7 -> ">>>" | 8 -> "|" | 9 -> "&" | 10 -> "^" | 11 -> "==" | 12 -> "!=" | 13 -> ">" | 14 -> ">=" | 15 -> "<" | 16 -> "<=" | 17 -> "=" | 18 -> "&&" | 19 -> "||" | 20 -> "++=" | 21 -> "--=" | 22 -> "+=" | 23 -> "-=" | 24 -> "/=" | 25 -> "*=" | 26 -> "%=" | 27 -> "<<=" | 28 -> ">>=" | 29 -> ">>>=" | 30 -> "|=" | 31 -> "&=" | 32 -> "^=" | n -> error ("Invalid op tag "+n) } } function rec parse_field(ctx) { var name = parse_string ctx; (name,parse_expr ctx) } function rec parse_switch(ctx,n) { var e = parse_expr ctx; var l = parse_list ctx (function(ctx) { var e1 = parse_expr ctx; var e2 = parse_expr ctx; (e1,e2) }) n; var eo = parse_expr_opt ctx; ESwitch e l eo } function rec parse_expr_opt(ctx) { if IO.read_byte ctx.ch == 0 then None else Some (parse_expr ctx) } function rec parse_expr(ctx) { var n = IO.read_byte ctx.ch; if n < 2 then { var file = if n == 1 then ctx.pos.psource else parse_string ctx; var line = IO.read_ui24 ctx.ch; ctx.pos := { psource = file; pline = line; pmin = 0; pmax = 0; }; parse_expr(ctx); } else { var pos = ctx.pos; (match n { | 2 -> EConst (parse_constant ctx) | 3 -> EBlock (parse_list ctx parse_expr (IO.read_byte ctx.ch)) | 4 -> EBlock (parse_list ctx parse_expr (IO.read_ui24 ctx.ch)) | 5 -> EParenthesis (parse_expr ctx) | 6 -> var e = parse_expr ctx; EField e (parse_string ctx) | 7 -> var e = parse_expr ctx; ECall e (parse_list ctx parse_expr (IO.read_byte ctx.ch)) | 8 -> var e = parse_expr ctx; EArray e (parse_expr ctx) | 9 -> function parse_var(_) { var v = parse_string ctx; var e = parse_expr_opt ctx; (v,e); } EVars (parse_list ctx parse_var (IO.read_byte ctx.ch)) | 10 -> var e1 = parse_expr ctx; var e2 = parse_expr ctx; EWhile e1 e2 NormalWhile | 11 -> var e1 = parse_expr ctx; var e2 = parse_expr ctx; EWhile e1 e2 DoWhile | 12 -> var e1 = parse_expr ctx; var e2 = parse_expr ctx; EIf e1 e2 (parse_expr_opt ctx) | 13 -> var e1 = parse_expr ctx; var str = parse_string ctx; ETry e1 str (parse_expr ctx) | 14 -> var vars = parse_list ctx parse_string (IO.read_byte ctx.ch); EFunction vars (parse_expr ctx) | 15 -> var op = parse_op ctx; var e1 = parse_expr ctx; var e2 = parse_expr ctx; EBinop op e1 e2 | 16 -> EReturn None | 17 -> EReturn Some(parse_expr ctx) | 18 -> EBreak None | 19 -> EBreak Some(parse_expr ctx) | 20 -> EContinue | 21 -> var e1 = parse_expr ctx; var e2 = parse_expr ctx; ENext e1 e2 | 22 -> EObject (parse_list ctx parse_field (IO.read_byte ctx.ch)) | 23 -> EObject (parse_list ctx parse_field (IO.read_ui24 ctx.ch)) | 24 -> ELabel (parse_string ctx) | 25 -> parse_switch ctx (IO.read_byte ctx.ch) | 26 -> parse_switch ctx (IO.read_ui24 ctx.ch) | 27 -> var str = IO.read ctx.ch (IO.read_ui24 ctx.ch); fst (*parse_from_string)(str,pos) | 28 -> var e = parse_expr ctx; ECall e (parse_list ctx parse_expr (IO.read_ui24 ctx.ch)) | n -> error ("Invalid expr tag : " + n) },pos) } } function parse(ch,pos) { var ctx = { ch = ch; strings = Array.create(); pos = pos; }; if IO.read ctx.ch 4 != header then error "Invalid binast header"; parse_expr(ctx); } neko-2.0.0/src/neko/Bytecode.nml0000644000175000017500000003737512112157473017164 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type opcode { // getters AccNull; AccTrue; AccFalse; AccThis; AccInt : int; AccStack : int; AccGlobal : int; AccEnv : int; AccField : string; AccArray; AccIndex : int; AccBuiltin : string; // setters SetStack : int; SetGlobal : int; SetEnv : int; SetField : string; SetArray; SetIndex : int; SetThis; // stack ops Push; Pop : int; Call : int; ObjCall : int; Jump : int; JumpIf : int; JumpIfNot : int; Trap : int; EndTrap; Ret : int; MakeEnv : int; MakeArray : int; // value ops Bool; IsNull; IsNotNull; Add; Sub; Mult; Div; Mod; Shl; Shr; UShr; Or; And; Xor; Eq; Neq; Gt; Gte; Lt; Lte; Not; // extra ops TypeOf; Compare; Hash; New; JumpTable : int; Apply : int; AccStack0; AccStack1; AccIndex0; AccIndex1; PhysCompare; TailCall : (int, int); Loop; }; type global { GlobalVar : string; GlobalFunction : (int , int); GlobalString : string; GlobalFloat : string; GlobalDebug : (string array, (int, int) array); GlobalVersion : int; } exception Invalid_file; var trap_stack_delta = 6 var inull : int = neko("null") function hash_field(s : string) : int { neko("$hash(s)") } function op_param(x) { match x { | AccInt _ | AccStack _ | AccGlobal _ | AccEnv _ | AccField _ | AccBuiltin _ | SetStack _ | SetGlobal _ | SetEnv _ | SetField _ | Pop _ | Call _ | ObjCall _ | Jump _ | JumpIf _ | JumpIfNot _ | JumpTable _ | Trap _ | MakeEnv _ | MakeArray _ | Ret _ | AccIndex _ | SetIndex _ | Apply _ | TailCall _ -> true | AccNull | AccTrue | AccFalse | AccThis | AccArray | SetArray | SetThis | Push | EndTrap | Bool | Add | Sub | Mult | Div | Mod | Shl | Shr | UShr | Or | And | Xor | Eq | Neq | Gt | Gte | Lt | Lte | IsNull | IsNotNull | Not | TypeOf | Compare | Hash | New | AccStack0 | AccStack1 | AccIndex0 | AccIndex1 | PhysCompare | Loop -> false } } function code_tables(ops) { var ids = Hashtbl.create(); var fids = Array.create(); Array.iter (function(x) { match x { | AccField s | SetField s | AccBuiltin s -> var id = hash_field s; try var f = Hashtbl.find ids id; if f != s then error("Field hashing conflict " + s + " and " + f); catch { Not_found -> Hashtbl.add ids id s; Array.add fids s } | _ -> () } }) ops; var p = &0; var pos = Array.make (Array.length(ops) + 1) 0; Array.iteri (function(i,op) { pos.[i] := *p; p := *p + (if op_param op then 2 else 1); }) ops; pos.[Array.length ops] := *p; (fids , pos , *p) } function write_debug_infos(ch,files,inf) { var nfiles = Array.length files; // the encoding of nfiles was set to keep // backward compatibility with 1.3 which // only allowed up to 127 filenames var lot_of_files = &false; if nfiles < 0x80 then IO.write_byte ch nfiles else if nfiles < 0x8000 then { lot_of_files := true; IO.write_byte ch ((nfiles >> 8) or 0x80); IO.write_byte ch (nfiles and 0xFF); } else invalid_arg(); Array.iter (function(s) { IO.write ch s; IO.write_char ch '\000' }) files; IO.write_i32 ch (Array.length inf); var curfile = &0; var curpos = &0; var rcount = &0; function rec flush_repeat(p) { if *rcount > 0 then { if *rcount > 15 then { IO.write_byte ch ((15 << 2) or 2); rcount := *rcount - 15; flush_repeat(p) } else { var delta = p - *curpos; var delta = (if delta > 0 && delta < 4 then delta else 0); IO.write_byte ch ((delta << 6) or (*rcount << 2) or 2); rcount := 0; curpos := *curpos + delta; } } } Array.iter (function((f,p)) { if f != *curfile then { flush_repeat(p); curfile := f; if *lot_of_files then { IO.write_byte ch ((f >> 7) or 1); IO.write_byte ch (f and 0xFF); } else IO.write_byte ch ((f << 1) or 1); } if p != *curpos then flush_repeat(p); if p == *curpos then rcount := *rcount + 1 else { var delta = p - *curpos; if delta > 0 && delta < 32 then { IO.write_byte ch ((delta << 3) or 4) } else { IO.write_byte ch (p << 3); IO.write_byte ch (p >> 5); IO.write_byte ch (p >> 13); } curpos := p; } }) inf; flush_repeat(*curpos) } function write(ch,(globals,ops)) { IO.write ch "NEKO"; var ids , pos , csize = code_tables ops; IO.write_i32 ch (Array.length globals); IO.write_i32 ch (Array.length ids); IO.write_i32 ch csize; Array.iter (function(x) { match x { | GlobalVar s -> IO.write_byte ch 1; IO.write ch s; IO.write_char ch '\000'; | GlobalFunction (p,nargs) -> IO.write_byte ch 2; IO.write_i32 ch (pos.[p] or (nargs << 24)) | GlobalString s -> IO.write_byte ch 3; IO.write_ui16 ch (String.length s); IO.write ch s | GlobalFloat s -> IO.write_byte ch 4; IO.write ch s; IO.write_char ch '\000' | GlobalDebug (files,inf) -> IO.write_byte ch 5; write_debug_infos ch files inf; | GlobalVersion v -> IO.write_byte ch 6; IO.write_byte ch v } }) globals; Array.iter (function(s) { IO.write ch s; IO.write_char ch '\000'; }) ids; Array.iteri (function(i,op) { var pop = &inull; var opid = (match op { | AccNull -> 0 | AccTrue -> 1 | AccFalse -> 2 | AccThis -> 3 | AccInt n -> pop := n; 4 | AccStack n -> pop := (n - 2); 5 | AccGlobal n -> pop := n; 6 | AccEnv n -> pop := n; 7 | AccField s -> pop := (hash_field s); 8 | AccArray -> 9 | AccIndex n -> pop := (n - 2); 10 | AccBuiltin s -> pop := (hash_field s); 11 | SetStack n -> pop := n; 12 | SetGlobal n -> pop := n; 13 | SetEnv n -> pop := n; 14 | SetField s -> pop := (hash_field s); 15 | SetArray -> 16 | SetIndex n -> pop := n; 17 | SetThis -> 18 | Push -> 19 | Pop n -> pop := n; 20 | Call n -> pop := n; 21 | ObjCall n -> pop := n; 22 | Jump n -> pop := (pos.[i+n] - pos.[i]); 23 | JumpIf n -> pop := (pos.[i+n] - pos.[i]); 24 | JumpIfNot n -> pop := (pos.[i+n] - pos.[i]); 25 | Trap n -> pop := (pos.[i+n] - pos.[i]); 26 | EndTrap -> 27 | Ret n -> pop := n; 28 | MakeEnv n -> pop := n; 29 | MakeArray n -> pop := n; 30 | Bool -> 31 | IsNull -> 32 | IsNotNull -> 33 | Add -> 34 | Sub -> 35 | Mult -> 36 | Div -> 37 | Mod -> 38 | Shl -> 39 | Shr -> 40 | UShr -> 41 | Or -> 42 | And -> 43 | Xor -> 44 | Eq -> 45 | Neq -> 46 | Gt -> 47 | Gte -> 48 | Lt -> 49 | Lte -> 50 | Not -> 51 | TypeOf -> 52 | Compare -> 53 | Hash -> 54 | New -> 55 | JumpTable n -> pop := n; 56 | Apply n -> pop := n; 57 | AccStack0 -> 58 | AccStack1 -> 59 | AccIndex0 -> 60 | AccIndex1 -> 61 | PhysCompare -> 62 | TailCall (args,st) -> pop := (args or (st << 3)); 63 | Loop -> pop := 64; 0 }); var n = *pop; if n == inull then IO.write_byte ch (opid << 2) else if opid < 32 && (n == 0 || n == 1) then IO.write_byte ch ((opid << 3) or (n << 2) or 1) else if n >= 0 && n <= 0xFF then { IO.write_byte ch ((opid << 2) or 2); IO.write_byte ch n; } else { IO.write_byte ch ((opid << 2) or 3); IO.write_i32 ch n; } }) ops } function read_string(ch) { var b = Buffer.create(); function rec loop() { var c = IO.read_char ch; if c == '\000' then Buffer.string b else { Buffer.add_char b c; loop() } }; loop() } function read_debug_infos(ch) { var nfiles = IO.read_byte ch; // see comments in read_debug_infos var lot_of_files = &false; var nfiles = if nfiles < 0x80 then nfiles else { lot_of_files := true; var b = IO.read_byte ch; ((nfiles and 0x7F) << 8) or b }; if nfiles == 0 then invalid_arg(); var files = Array.init nfiles (function(_) { read_string ch }); var npos = IO.read_i32 ch; var curfile = &0; var curpos = &0; var pos = Array.make npos (0,0); function rec loop(i) { if i == npos then () else { var b = IO.read_byte ch; if b and 1 != 0 then { var file = if *lot_of_files then { var b2 = IO.read_byte ch; ((b >> 1) << 8) or b2 } else b >> 1; if file >= Array.length files then invalid_arg(); curfile := file; loop(i) } else if b and 2 != 0 then { var delta = b >> 6; var count = (b >> 2) and 15; var p = &0; while *p < count { pos.[i + *p] := (*curfile,*curpos); p := *p + 1; } curpos := *curpos + delta; loop (i + count) } else if b and 4 != 0 then { curpos := *curpos + (b >> 3); pos.[i] := (*curfile,*curpos); loop (i + 1) } else { var b2 = IO.read_byte ch; var b3 = IO.read_byte ch; curpos := (b >> 3) or (b2 << 5) or (b3 << 13); pos.[i] := (*curfile,*curpos); loop (i + 1) } } } loop 0; (files, pos) } function read(ch) { try { var head = IO.read ch 4; if head != "NEKO" then throw Invalid_file; var nglobals = IO.read_i32 ch; var nids = IO.read_i32 ch; var csize = IO.read_i32 ch; if nglobals < 0 || nglobals > 0xFFFF || nids < 0 || nids > 0xFFFF || csize < 0 || csize > 0xFFFFFF then throw Invalid_file; var globals = Array.init nglobals (function(_) { match IO.read_byte ch { | 1 -> GlobalVar(read_string ch) | 2 -> var v = IO.read_i32 ch; GlobalFunction(v and 0xFFFFFF, v >> 24) | 3 -> var len = IO.read_ui16 ch; GlobalString(IO.read ch len) | 4 -> GlobalFloat(read_string ch) | 5 -> var files, inf = read_debug_infos ch; GlobalDebug files inf | 6 -> GlobalVersion(IO.read_byte ch) | _ -> throw Invalid_file } }); var ids = Hashtbl.create(); function rec loop(n) { if n == 0 then () else { var s = read_string ch; var id = hash_field s; try var s2 = Hashtbl.find ids id; if s != s2 then throw Invalid_file; catch { Not_found -> Hashtbl.add ids id s; loop (n-1) } } }; loop nids; var pos = Array.make (csize+1) (-1); var cpos = &0; var jumps = &[]; var ops = Array.create(); while *cpos < csize { var code = IO.read_byte ch; var op , p = match code and 3 { | 0 -> (code >> 2 , inull) | 1 -> (code >> 3 , ((code >> 2) and 1)) | 2 -> if code == 2 then (IO.read_byte ch, inull) else (code >> 2 , IO.read_byte ch) | 3 -> (code >> 2 , IO.read_i32 ch) | _ -> assert() }; var op = match op { | 0 -> AccNull | 1 -> AccTrue | 2 -> AccFalse | 3 -> AccThis | 4 -> AccInt p | 5 -> AccStack (p + 2) | 6 -> AccGlobal p | 7 -> AccEnv p | 8 -> AccField (try Hashtbl.find ids p catch { Not_found -> throw Invalid_file }) | 9 -> AccArray | 10 -> AccIndex (p + 2) | 11 -> AccBuiltin (try Hashtbl.find ids p catch { Not_found -> throw Invalid_file }) | 12 -> SetStack p | 13 -> SetGlobal p | 14 -> SetEnv p | 15 -> SetField (try Hashtbl.find ids p catch { Not_found -> throw Invalid_file }) | 16 -> SetArray | 17 -> SetIndex p | 18 -> SetThis | 19 -> Push | 20 -> Pop p | 21 -> Call p | 22 -> ObjCall p | 23 -> jumps := (*cpos , Array.length ops) :: *jumps; Jump p | 24 -> jumps := (*cpos , Array.length ops) :: *jumps; JumpIf p | 25 -> jumps := (*cpos , Array.length ops) :: *jumps; JumpIfNot p | 26 -> jumps := (*cpos , Array.length ops) :: *jumps; Trap p | 27 -> EndTrap | 28 -> Ret p | 29 -> MakeEnv p | 30 -> MakeArray p | 31 -> Bool | 32 -> IsNull | 33 -> IsNotNull | 34 -> Add | 35 -> Sub | 36 -> Mult | 37 -> Div | 38 -> Mod | 39 -> Shl | 40 -> Shr | 41 -> UShr | 42 -> Or | 43 -> And | 44 -> Xor | 45 -> Eq | 46 -> Neq | 47 -> Gt | 48 -> Gte | 49 -> Lt | 50 -> Lte | 51 -> Not | 52 -> TypeOf | 53 -> Compare | 54 -> Hash | 55 -> New | 56 -> JumpTable p | 57 -> Apply p | 58 -> AccStack0 | 59 -> AccStack1 | 60 -> AccIndex0 | 61 -> AccIndex1 | 62 -> PhysCompare | 63 -> TailCall (p and 7) (p >> 3) | 64 -> Loop | _ -> throw Invalid_file }; pos.[*cpos] := Array.length ops; cpos := *cpos + (if op_param op then 2 else 1); Array.add ops op; }; if *cpos != csize then throw Invalid_file; pos.[*cpos] := Array.length ops; function pos_index(i,sadr) { var idx = pos.[sadr]; if idx == -1 then throw Invalid_file; idx - i }; List.iter (function((a,i)) { Array.set ops i (match Array.get ops i { | Jump p -> Jump (pos_index i (a+p)) | JumpIf p -> JumpIf (pos_index i (a+p)) | JumpIfNot p -> JumpIfNot (pos_index i (a+p)) | Trap p -> Trap (pos_index i (a+p)) | _ -> assert() }); }) (*jumps); Array.iteri (function(i,g) { match g { | GlobalFunction(f,n) -> globals.[i] := GlobalFunction(pos_index 0 f,n) | _ -> () } }) globals; (globals , ops) } catch { | IO.Eof | IO.Overflow _ -> throw Invalid_file } } function dump(ch,(globals,ops)) { var ids, pos , csize = code_tables ops; IO.printf ch "nglobals : %d\n" (Array.length globals); IO.printf ch "nfields : %d\n" (Array.length ids); IO.printf ch "codesize : %d ops , %d total\n" (Array.length ops,csize); IO.printf ch "GLOBALS =\n" (); var marks = Array.make csize false; Array.iteri (function(i,g) { IO.printf ch " global %d : %s\n" (i, match g { | GlobalVar s -> "var " + String.escape s | GlobalFunction (p,n) -> if p >= 0 && p < csize then marks.[p] := true; "function " + string p + " nargs " + string n | GlobalString s -> "string \"" + String.escape s + "\"" | GlobalFloat s -> "float " + String.escape s | GlobalDebug (files,inf) -> var ch, buf = IO.write_string(); write_debug_infos ch files inf; sprintf "debug %d ops %d bytes" (Array.length inf,String.length buf()) | GlobalVersion v -> "version " + string v }) }) globals; IO.printf ch "FIELDS =\n" (); Array.iter (function(f) { IO.printf ch " %s%s%.8X\n" (f , if String.length(f) >= 24 then " " else String.make (24 - String.length f) ' ', hash_field f); }) ids; IO.printf ch "CODE =\n" (); function str(s,i) { s + " " + string i }; var bpos = &0; Array.iteri (function(pos,op) { if marks.[pos] then IO.write_char ch '\n'; IO.printf ch "%.6X %6d %s\n" (*bpos , pos , match op { | AccInt i -> str "AccInt" i | AccStack i -> str "AccStack" i | AccGlobal i -> str "AccGlobal" i | AccEnv i -> str "AccEnv" i | AccField s -> "AccField " + s | AccIndex i -> str "AccIndex" i | AccBuiltin s -> "AccBuiltin " + s | SetStack i -> str "SetStack" i | SetGlobal i -> str "SetGlobal" i | SetEnv i -> str "SetEnv" i | SetField f -> "SetField " + f | SetIndex i -> str "SetIndex" i | Pop i -> str "Pop" i | Call i -> str "Call" i | ObjCall i -> str "ObjCall" i | Jump i -> str "Jump" (pos + i) | JumpIf i -> str "JumpIf" (pos + i) | JumpIfNot i -> str "JumpIfNot" (pos + i) | Trap i -> str "Trap" (pos + i) | Ret i -> str "Ret" i | MakeEnv i -> str "MakeEnv" i | MakeArray i -> str "MakeArray" i | JumpTable i -> str "JumpTable" i | Apply i -> str "Apply" i | _ -> string op }); bpos := *bpos + if op_param op then 2 else 1; }) ops; IO.printf ch "END\n" (); } neko-2.0.0/src/neko/Lexer.nml0000644000175000017500000001362612112157473016476 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ open Neko.Ast; type error_msg { Invalid_character : char; Unterminated_string; Unclosed_comment; Unclosed_nxml; Invalid_escaped_character : int; Invalid_escape; } exception Error : (error_msg , Lexer.pos) function error_msg(msg) { match msg { | Invalid_character c when ord c > 32 && ord c < 128 -> sprintf "Invalid character '%c'" c | Invalid_character c -> sprintf "Invalid character 0x%.2X" (ord c) | Unterminated_string -> "Unterminated string" | Unclosed_comment -> "Unclosed comment" | Unclosed_nxml -> "Unclosed nxml" | Invalid_escaped_character n -> sprintf "Invalid escaped character %d" n | Invalid_escape -> "Invalid escape sequence" } } function error(l,msg) { throw Error(msg,Lexer.curpos l) } var keywords = { var h = Hashtbl.create(); List.iter (function(k) { Hashtbl.add h (s_keyword k) k }) [Var;While;Do;If;Else;Function;Return;Break;Continue;Try;Catch;Switch;Default]; h } function mk(l,t) { (t,Lexer.curpos l) } function mk_int(l) { mk l Const(Int(int (Lexer.current l))) } function mk_float(l) { mk l Const(Float(Lexer.current l)) } function mk_ident(l) { var s = Lexer.current l; mk l (try Keyword (Hashtbl.find keywords s) catch { Not_found -> Const (Ident s) }) } var ident = "[a-zA-Z_@][a-zA-Z0-9_@]*"; var binop = "[-!=\\*/<>&|^%\\+:]"; var expr = &Lexer.empty(); var estring = &Lexer.empty(); var ecomment = &Lexer.empty(); var enxml = &Lexer.empty(); function comment(l) { Lexer.token l (*ecomment) } function str(l) { Lexer.token l (*estring) }; function nxml(l) { Lexer.token l (*enxml) } exception Continue : bool; expr := Lexer.build [ (";", function(l) { mk l Semicolon }); (".", function(l) { mk l Dot }); (",", function(l) { mk l Comma }); ("{", function(l) { mk l BraceOpen }); ("}", function(l) { mk l BraceClose }); ("(", function(l) { mk l ParentOpen }); (")", function(l) { mk l ParentClose }); ("\\[", function(l) { mk l BracketOpen }); ("]", function(l) { mk l BracketClose }); ("=>", function(l) { mk l Arrow }); ("[ \r\t\n]+", function(l) { Lexer.token l (*expr) }); ("0x[0-9a-fA-F]+", mk_int); ("[0-9]+", mk_int); ("[0-9]+.[0-9]*", mk_float); (".[0-9]+", mk_float); ("$"+ident, function(l) { var s = Lexer.current l; var s = String.sub s 1 (String.length s - 1); mk l Const(Builtin s) }); ("true", function(l) { mk l (Const True) }); ("false", function(l) { mk l (Const False) }); ("null", function(l) { mk l (Const Null) }); ("this", function(l) { mk l (Const This) }); (ident , function(l) { mk_ident l }); ("\"", function(l) { var p1 = Lexer.curpos l; var buf = Lexer.data l; Buffer.reset buf; try str l catch { Exit -> throw Error(Unterminated_string,p1) }; var p2 = Lexer.curpos l; (Const String(Buffer.string buf) , Lexer.punion p1 p2) }); ("/\\*", function(l) { var p1 = Lexer.curpos l; var buf = Lexer.data l; Buffer.reset buf; try comment l catch { Exit -> throw Error(Unclosed_comment,p1) }; var p2 = Lexer.curpos l; (Comment(Buffer.string buf) , Lexer.punion p1 p2) }); ("//[^\r\n]*\n?", function(l) { var s = Lexer.current l; var len = String.length s; var n = (if String.get s (len - 1) == '\r' then 3 else 2); mk l CommentLine(String.sub s 0 (len - n)) }); (binop + binop + "?",function(l) { mk l (Binop (Lexer.current l)) }); (binop + binop + "=",function(l) { mk l (Binop (Lexer.current l)) }); (">>>",function(l) { mk l (Binop ">>>") }); (">>>=",function(l) { mk l (Binop ">>>=") }); ] (function(l) { match Lexer.char l { | None -> mk l Eof | Some c -> error l (Invalid_character c) } }); ; ecomment := Lexer.build [ ("\\*/", function(l) { }); ("\\*", function(l) { Buffer.add (Lexer.data l) (Lexer.current l); comment l }); ("[^*]+", function(l) { Buffer.add (Lexer.data l) (Lexer.current l); comment l }); ] (function(l) { throw Exit }); estring := Lexer.build [ ("\\\\\"", function(l) { Buffer.add_char (Lexer.data l) '"'; str l }); ("\\\\\\\\", function(l) { Buffer.add_char (Lexer.data l) '\\'; str l }); ("\\\\n", function(l) { Buffer.add_char (Lexer.data l) '\n'; str l }); ("\\\\t", function(l) { Buffer.add_char (Lexer.data l) '\t'; str l }); ("\\\\r", function(l) { Buffer.add_char (Lexer.data l) '\r'; str l }); ("\\\\[0-9][0-9][0-9]", function(l) { var k = int (String.sub (Lexer.current l) 1 3); if k > 255 then error l (Invalid_escaped_character k); Buffer.add_char (Lexer.data l) (chr k); str l }); ("\\\\" , function(l) { error l Invalid_escape }); ("\"" , function(l) { }); ("[^\\\\\"]+", function(l) { Buffer.add (Lexer.data l) (Lexer.current l); str l }); ] (function(l) { throw Exit }); enxml := Lexer.build [ ("", function(l) { throw Continue(false) }); ("<",function(l) { Buffer.add_char (Lexer.data l) '<'; throw Continue(true) }); ("[^<]+", function(l) { Buffer.add (Lexer.data l) (Lexer.current l); nxml l }); ] (function(l) { throw Exit }); neko-2.0.0/src/neko/Main.nml0000644000175000017500000001274712112157473016306 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ var dir = &None; var verbose = &false; function out(file,ext) { var file = Sys.without_extension file + ext; match *dir { | None -> file | Some dir -> dir + Sys.without_dir file } } function is_nxml(str) { var len = String.length str; if len <= 10 || String.sub str 0 6 != "" then None else if String.sub str (len - 7) 7 == "" then Some (String.sub str 6 (len - 13)) else if String.sub str (len - 8) 8 == "\n" then Some (String.sub str 6 (len - 14)) else if String.sub str (len - 9) 9 == "\r\n" then Some (String.sub str 6 (len - 15)) else None } function parse_multiformat(file) { var str = IO.file_contents file; match is_nxml str { | Some nxml -> Neko.Xml.parse nxml Lexer.null_pos | None when String.length str > 4 && String.sub str 0 4 == Neko.Binast.header -> Neko.Binast.parse (IO.read_string str) Lexer.null_pos | None -> var i = IO.read_string str; var lex = Lexer.create Buffer.create(); Lexer.input lex file i 1 0; Neko.Parser.parse lex; } } function compile(version,file) { if *verbose then printf "Compiling %s\n" file; var ast = parse_multiformat file; var code = Neko.Compile.compile version ast; var o = IO.write_file out(file,".n") true; Neko.Bytecode.write o code; IO.close_out o } function dump(file) { if *verbose then printf "Dumping %s\n" file; var i = IO.read_file file true; var code = Neko.Bytecode.read i; IO.close_in i; var o = IO.write_file out(file,".dump") false; Neko.Bytecode.dump o code; IO.close_out o } function print_ast(file) { if *verbose then printf "Printing %s\n" file; var ast = parse_multiformat file; var o = IO.write_file out(file,"2.neko") false; Neko.Printer.print Neko.Printer.create(o) ast; IO.close_out o } function release(file) { if *verbose then printf "Releasing %s\n" file; var i = IO.read_file file true; var globals, code = Neko.Bytecode.read i; IO.close_in i; var globals = Array.map (function(g) { match g { | Neko.Bytecode.GlobalVar _ | Neko.Bytecode.GlobalDebug _ -> Neko.Bytecode.GlobalVar "" | _ -> g } }) globals; var o = IO.write_file out(file,".n") true; Neko.Bytecode.write o (globals,code); IO.close_out o } function documentation(file) { if *verbose then printf "Building documentation for %s\n" file; var i = IO.read_file file false; var lex = Lexer.create Neko.Doc.status(); Lexer.input lex file i 1 0; var doc = Neko.Doc.parse lex; IO.close_in i; var o = IO.write_file out(file,".html") false; Neko.Doc.to_html o doc; IO.close_out o } function report(msg,p) { if p == Lexer.null_pos then { Stack.dump IO.stderr Stack.exc(); IO.printf IO.stderr "Exception : %s\n" msg } else IO.printf IO.stderr "%s(%d): %s\n" (Lexer.source p,Lexer.line p,msg); Sys.exit(-1); } function complete(dir) { var l = String.length dir; if l > 0 && String.get dir (l - 1) != '/' && String.get dir (l - 1) != '\\' then dir + "/" else dir } try { var v = Sys.version; var head = "Neko Compiler v" + v.maj + "." + v.min + "." + v.build + " - (c)2005-2013 Haxe Foundation\n Usage : neko [options] files..."; var link = &None; var links = &[]; var version = &0; var decl = [ ("-d", Args.String (function(f) { dump f }) , " : dump bytecode"); ("-z", Args.String (function(f) { release f }), " : make bytecode release"); ("-p", Args.String (function(f) { print_ast f }), " : parse and print neko source"); ("-doc", Args.String (function(f) { documentation f }) , " : make documentation"); ("-o", Args.String (function(f) { dir := Some (complete f) })," : set output directory"); ("-console", Args.Void (function() { Neko.Console.run(*version) }),": run the console"); ("-link", Args.String (function(f) { link := Some f })," : link bytecodes files"); ("-v", Args.Void (function() { verbose := true }) , ": verbose mode"); ("-version", Args.Int (function(v) version := v), ": set the bytecode version"); ]; Args.parse head decl (function(f) { match *link { | None -> compile (*version) f | Some _ -> links := f :: *links } }); match *link { None -> () | Some f -> Neko.Linker.link f List.rev(*links) }; } catch { | Neko.Lexer.Error(msg,pos) -> report Neko.Lexer.error_msg(msg) pos | Neko.Parser.Error(msg,pos) -> report Neko.Parser.error_msg(msg) pos | Neko.Compile.Error(msg,pos) -> report Neko.Compile.error_msg(msg) pos | Neko.Doc.Error(msg,pos) -> report Neko.Doc.error_msg(msg) pos | e -> report string(e) Lexer.null_pos } neko-2.0.0/src/benchs/0000755000175000017500000000000012112157473015205 5ustar ncannassencannasseneko-2.0.0/src/benchs/test_ops.neko0000644000175000017500000000225312112157473017725 0ustar ncannassencannasse eq = function(a,b) { if( a != b ) $print(a," should be ",b,"\n") else $print(".") } eq($string(1),"1"); eq($string(0xFFFFFFFF),"-1"); o = $new(null); o.__add = function(x) return x + 66; o.__radd = function(x) return x + 77; o.__sub = function(x) return x - 66; o.__rsub = function(x) return x - 77; var small = 0x7FFF; var med = 0x7FFF0000; var less = 0x80000000; var spe1 = 0xC0000000; eq($string(small),"32767"); eq($string(med),"2147418112"); eq($string(less),"-2147483648"); eq($string(spe1),"-1073741824"); $print("\n"); eq(small<<16,med); eq(small<<17,-131072); eq(med+0x10000,less); var low = 0xC000; eq(low<<16,spe1); var low = 0xA000; eq(low<<16,0xA0000000); eq(small*small,1073676289); eq(small*small*small,1073840127); eq(small*small*small*med,65536); eq(med+med,-131072); eq(o + 1, 67); eq(1 + o, 78); eq(o + "x", "x66"); eq("x" + o, "x77"); eq( med + 1.1, 2147418113.1 ); eq( 1.1 + med, 2147418113.1 ); eq( 1 - 1.25, -0.25 ); eq( 1.25 - 1, 0.25 ); eq( med - 1, 2147418111 ); eq( 1 - med, -2147418111 ); eq( med - 1.25, 2147418110.75 ); eq( 1.25 - med, -2147418110.75 ); eq( o - 1, -65 ); eq( 1 - o, -76 ); neko-2.0.0/src/benchs/fannkuch.neko0000644000175000017500000000225012112157473017657 0ustar ncannassencannasse/* The Computer Language Shootout http://shootout.alioth.debian.org/ contributed by Nicolas Cannasse */ var n = $int($loader.args[0]); if( n == null ) n = 7; check = 0; perm = $amake(n); perm1 = $amake(n); count = $amake(n); maxPerm = $amake(n); maxflips = 0; m = n - 1; r = n; i = 0; while( i < n ) { perm1[i] = i; i += 1 }; while (true) { if( check < 30 ) { i = 0; while( i < n ) { $print(perm1[i]+1); i += 1; }; $print("\n"); check += 1; } while( r != 1 ) { count[r-1] = r; r -= 1; }; if( perm1[0] != 0 && perm1[m] != m ) { i = 0; while( i < n ) { perm[i] = perm1[i]; i += 1; }; flips = 0; k = perm[0]; do { i = 1; j = k - 1; while( i < j ) { tmp = perm[i]; perm[i] = perm[j]; perm[j] = tmp; i += 1; j -= 1; } flips += 1; j = perm[k]; perm[k] = k; k = j; } while( k != 0 ); if( flips > maxflips ) maxflips = flips; } while (true) { if( r == n ) { $print("Pfannkuchen(",n,") = ",maxflips,"\n"); $goto(exit); } perm0 = perm1[0]; i = 0; while( i < r ) { j = i + 1; perm1[i] = perm1[j]; i = j; } perm1[r] = perm0; count[r] -= 1; if( count[r] > 0 ) break; r += 1; } } exit: neko-2.0.0/src/benchs/module.neko0000644000175000017500000000030012112157473017341 0ustar ncannassencannassevar arg = $int($loader.args[0]); if( arg == null ) arg = 100; $loader.args = $array(); while( arg > 0 ) { $loader.cache = $new(null); $loader.loadmodule("boot/nekoc.n",$loader); arg -= 1; }neko-2.0.0/src/benchs/fib.neko0000644000175000017500000000026312112157473016624 0ustar ncannassencannassefib = function(n) { if( n <= 1 ) return 1; return fib(n-1) + fib(n-2); }; var arg = $int($loader.args[0]); if( arg == null ) arg = 30; $print("fib(",arg,") = ",fib(arg),"\n"); neko-2.0.0/src/benchs/binary-trees.neko0000644000175000017500000000207312112157473020471 0ustar ncannassencannasse/* The Computer Language Shootout http://shootout.alioth.debian.org/ contributed by Nicolas Cannasse */ make = function(i,d) { if( d == 0 ) return $array(i,null,null); var i2 = 2 * i; d -= 1; $array(i,make(i2-1,d),make(i2,d)); }; check = function(n) { if( n[1] == null ) return n[0]; return n[0] + check(n[1]) - check(n[2]); } var arg = $int($loader.args[0]); if( arg == null ) arg = 10; var min_depth = 4; var max_depth = if( min_depth + 2 < arg ) arg else min_depth + 2; var stretch_depth = max_depth + 1 var c = check(make(0,stretch_depth)); $print("stretch tree of depth ",stretch_depth,"\t check: ",c,"\n"); var long_lived_tree = make(0,max_depth); loop_depths = function(d) { if( d <= max_depth ) { var niter = 1 << (max_depth - d + min_depth); var c = 0; var i = 0; while( i < niter ) { i += 1; c += check(make(i,d))+check(make(0-i,d)); } $print(2*niter,"\t trees of depth ",d,"\t check: ",c,"\n"); loop_depths(d + 2); } } loop_depths(min_depth); $print("long lived tree of depth ",max_depth,"\t check: ",check(long_lived_tree),"\n"); neko-2.0.0/src/benchs/nbodies.neko0000644000175000017500000000707712112157473017521 0ustar ncannassencannasse/* The Computer Language Shootout http://shootout.alioth.debian.org/ contributed by Nicolas Cannasse */ pi = 3.141592653589793; solar_mass = (4 * pi * pi); days_per_year = 365.24; sqrt = $loader.loadprim("std@math_sqrt",1); round = $loader.loadprim("std@math_round",1); advance = function(nbodies,bodies,dt) { var i = 0,j; while( i < nbodies ) { var b = bodies[i]; i += 1; j = i; while( j < nbodies ) { var b2 = bodies[j]; var dx = b.x - b2.x; var dy = b.y - b2.y; var dz = b.z - b2.z; var dist = sqrt(dx*dx+dy*dy+dz*dz); var mag = dt / (dist * dist * dist); var bm = b.mass * mag; var b2m = b2.mass * mag; b.vx -= dx * b2m; b.vy -= dy * b2m; b.vz -= dz * b2m; b2.vx += dx * bm; b2.vy += dy * bm; b2.vz += dz * bm; j += 1; } } i = 0; while( i < nbodies ) { var b = bodies[i]; b.x += dt * b.vx; b.y += dt * b.vy; b.z += dt * b.vz; i += 1; } } energy = function(nbodies,bodies) { var e = 0, i = 0, j; while( i < nbodies ) { var b = bodies[i]; e += 0.5 * b.mass * (b.vx * b.vx + b.vy * b.vy + b.vz * b.vz); i += 1; j = i; while( j < nbodies ) { var b2 = bodies[j]; var dx = b.x - b2.x; var dy = b.y - b2.y; var dz = b.z - b2.z; var dist = sqrt(dx*dx+dy*dy+dz*dz); e -= (b.mass * b2.mass) / dist; j += 1; } } return e; }; offset_momentum = function(nbodies,bodies) { var px = 0, py = 0, pz = 0; var i = 0; while( i < nbodies ) { var b = bodies[i]; px += b.vx * b.mass; py += b.vy * b.mass; pz += b.vz * b.mass; i += 1; } var b = bodies[0]; b.vx = 0 - px / solar_mass; b.vy = 0 - py / solar_mass; b.vz = 0 - pz / solar_mass; } ; var bodies = $array( // sun { x => 0, y => 0, z => 0, vx => 0, vy => 0, vz => 0, mass => solar_mass }, // jupiter { x => $float("4.84143144246472090e+00"), y => $float("-1.16032004402742839e+00"), z => $float("-1.03622044471123109e-01"), vx => $float("1.66007664274403694e-03") * days_per_year, vy => $float("7.69901118419740425e-03") * days_per_year, vz => $float("-6.90460016972063023e-05") * days_per_year, mass => $float("9.54791938424326609e-04") * solar_mass }, // saturn { x => $float("8.34336671824457987e+00"), y => $float("4.12479856412430479e+00"), z => $float("-4.03523417114321381e-01"), vx => $float("-2.76742510726862411e-03") * days_per_year, vy => $float("4.99852801234917238e-03") * days_per_year, vz => $float("2.30417297573763929e-05") * days_per_year, mass => $float("2.85885980666130812e-04") * solar_mass }, // uranus { x => $float("1.28943695621391310e+01"), y => $float("-1.51111514016986312e+01"), z => $float("-2.23307578892655734e-01"), vx => $float("2.96460137564761618e-03") * days_per_year, vy => $float("2.37847173959480950e-03") * days_per_year, vz => $float("-2.96589568540237556e-05") * days_per_year, mass => $float("4.36624404335156298e-05") * solar_mass }, // neptune { x => $float("1.53796971148509165e+01"), y => $float("-2.59193146099879641e+01"), z => $float("1.79258772950371181e-01"), vx => $float("2.68067772490389322e-03") * days_per_year, vy => $float("1.62824170038242295e-03") * days_per_year, vz => $float("-9.51592254519715870e-05") * days_per_year, mass => $float("5.15138902046611451e-05") * solar_mass } ); var nbodies = $asize(bodies); display = function() { var prec = $float("1e+09"); var e = energy(nbodies,bodies) * prec; $print(round(e)/prec,"\n"); } var n = $int($loader.args[0]); if( n == null ) n = 1000; offset_momentum(nbodies, bodies); display(); var i = 0; while( i < n ) { advance(nbodies,bodies,0.01); i += 1; }; display(); neko-2.0.0/src/benchs/nsieve.neko0000644000175000017500000000114112112157473017351 0ustar ncannassencannasse/* The Computer Language Shootout http://shootout.alioth.debian.org/ contributed by Nicolas Cannasse */ fmt = function(i) { var s = $string(i); while( $ssize(s) < 8 ) s = " "+s; return s; } nsieve = function(m) { var a = $amake(m); var count = 0; var i = 2; while( i < m ) { if $not(a[i]) { count += 1; var j = (i << 1); while( j < m ) { if( $not(a[j]) ) a[j] = true; j += i; } } i += 1; } $print("Primes up to ",fmt(m)," ",fmt(count),"\n"); } var n = $int($loader.args[0]); if( n == null ) n = 2; var i = 0; while( i < 3 ) { nsieve(10000 << (n - i)); i += 1; } neko-2.0.0/src/benchs/fp.neko0000644000175000017500000000023012112157473016463 0ustar ncannassencannassevar x = 1.0; var y = 1.0; var i = $float($loader.args[0]); while( i > 0.0 ) { x *= 1.000000001; y /= 1.000000001; i -= 1.0; } $print(x,"\n",y,"\n"); neko-2.0.0/src/benchs/recursive.neko0000644000175000017500000000167112112157473020077 0ustar ncannassencannasse/* The Computer Language Shootout http://shootout.alioth.debian.org/ contributed by Nicolas Cannasse */ ack = function(x,y) { if( x == 0 ) return y + 1; if( y == 0 ) return ack(x - 1,1); return ack(x - 1,ack(x,y - 1)); } fib = function(n) { if( n < 2 ) return 1; return fib(n-2) + fib(n-1); } fib_fp = function(n) { if( n < 2.0 ) return 1.0; return fib_fp(n - 2.0) + fib_fp(n - 1.0); } tak = function(x,y,z) { if( y >= x ) return z; return tak(tak(x-1,y,z),tak(y-1,z,x),tak(z-1,x,y)); } tak_fp = function(x,y,z) { if( y >= x ) return z; return tak_fp(tak_fp(x-1.0,y,z),tak_fp(y-1.0,z,x),tak_fp(z-1.0,x,y)); } var n = $int($loader.args[0]); if( n == null ) n = 4; n -= 1; $print("Ack(3,",n + 1,"): ",ack(3,n + 1),"\n"); $print("Fib(",n + 28.0,".0): ",fib_fp(n + 28.0),".0\n"); $print("Tak(",3*n,",",2*n,",",n,"): ",tak(3*n,2*n,n),"\n"); $print("Fib(",3,"): ",fib(3),"\n"); $print("Tak(3.0,2.0,1.0): ",tak_fp(3.0,2.0,1.0),".0\n"); neko-2.0.0/src/benchs/ackerman.neko0000644000175000017500000000045312112157473017646 0ustar ncannassencannasseack = function(x,y) { if( x == 0 ) return y + 1; if( y == 0 ) return ack(x-1,1); return ack(x-1,ack(x,y-1)); }; var arg1 = $int($loader.args[1]); var arg2 = $int($loader.args[0]); if( arg1 == null ) arg1 = 3; if( arg2 == null ) arg2 = 4; $print("Ack(",arg1,",",arg2,"): ",ack(arg1,arg2),"\n"); neko-2.0.0/src/benchs/startup.neko0000644000175000017500000000021012112157473017556 0ustar ncannassencannasse/* The Computer Language Shootout http://shootout.alioth.debian.org/ contributed by Nicolas Cannasse */ $print("hello world\n"); neko-2.0.0/src/nekoml.vcproj0000644000175000017500000000344112112157473016457 0ustar ncannassencannasse neko-2.0.0/src/tools/0000755000175000017500000000000012112157473015103 5ustar ncannassencannasseneko-2.0.0/src/tools/install.neko0000644000175000017500000002402712112157473017434 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ // PRIMITIVES system = $loader.loadprim("std@sys_string",0)(); is64 = $loader.loadprim("std@sys_is64",0)(); chdir = $loader.loadprim("std@set_cwd",1); readdir = $loader.loadprim("std@sys_read_dir",1); stdin = $loader.loadprim("std@file_stdin",0)(); read_char = $loader.loadprim("std@file_read_char",1); ftype = $loader.loadprim("std@sys_file_type",1); command = $loader.loadprim("std@sys_command",1); exists = $loader.loadprim("std@sys_exists",1); split = $loader.loadprim("std@string_split",2); mkdir = $loader.loadprim("std@sys_create_dir",2); delete = $loader.loadprim("std@file_delete",1); getenv = $loader.loadprim("std@get_env",1); buffer_new = $loader.loadprim("std@buffer_new",0); buffer_add_char = $loader.loadprim("std@buffer_add_char",2); buffer_string = $loader.loadprim("std@buffer_string",1); // LIBS DATAS libs = { mod_neko => { src => $array("../../vm/stats","mod_neko","cgi"), inc => "httpd.h", incname => "Apache 1.3.x" }, mod_neko2 => { src => $array("../../vm/stats","mod_neko","cgi"), inc => $array("httpd.h","apr.h"), incname => "Apache 2.2.x", cflags => "-D_LARGEFILE64_SOURCE", realdir => "mod_neko", apache2 => true, }, mysql => { src => $array("mysql"), inc => "mysql.h", incname => "MySQL 4.+" lib => "libmysqlclient_r.a", lparams => "-lz -lssl" }, mysql5 => { src => $array("../common/sha1","../common/socket","my_proto/my_proto","my_proto/my_api","mysql"), inc => $array(), realdir => "mysql", cflags => "-Imy_proto -I../common", }, regexp => { src => $array("regexp"), inc => "pcre.h", incname => "PCRE", lparams => "-lpcre", }, zlib => { src => $array("zlib"), inc => "zlib.h", incname => "LibZ", lparams => "-lz", }, sqlite => { src => $array("sqlite"), inc => "sqlite3.h", incname => "Sqlite 3", lparams => "-lsqlite3", }, ui => { src => $array("ui"), inc => switch system { "Mac" => "Carbon.h" default => "gtk/gtk.h" }, incname => switch system { "Mac" => "Carbon" default => "GTK+2.0" }, cflags => switch system { "Mac" => "" default => "`pkg-config --cflags gtk+-2.0`" }, lparams => switch system { "Mac" => "-framework Carbon" default => "`pkg-config --libs gtk+-2.0` -lgthread-2.0" }, }, mod_tora => { src => $array("../common/socket","protocol","mod_tora"), inc => "httpd.h", incname => "Apache 1.3.x", cflags => "-I../common", }, mod_tora2 => { src => $array("../common/socket","protocol","mod_tora"), inc => $array("httpd.h","apr.h"), incname => "Apache 2.2.x", cflags => "-D_LARGEFILE64_SOURCE -I../common", realdir => "mod_tora", apache2 => true, }, } if( $loader.args[0] == "-static" ) { libs.regexp.lparams = null; libs.regexp.lib = "libpcre.a"; libs.zlib.lparams = null; libs.zlib.lib = "libz.a"; } if( $loader.args[0] == "-nolibs" ) libs = $new(null); // PLATFORM cflags = "-O3 -fPIC"; if( system == "Linux" ) cflags += " -pthread"; cc = getenv("CC"); if( cc == null ) cc = "gcc"; linkcmd = switch system { "BSD" => "ld" default => cc }; linkneko = "-lneko"; linkoptions = switch system { "Mac" => "-bundle -undefined dynamic_lookup -L../../bin" default => "-shared -L../../bin -pthread" }; nekovm = switch system { "Windows" => "..\\bin\\neko" default => "../bin/neko" }; // COMMANDS includes = $array( "../../vm", ); search_includes = function(isap2) { var inc1 = $array( "/usr/include", "/usr/local/include/mysql", "/usr/include/mysql", "/usr/local/include", "/usr/include/gtk-2.0", "/opt/local/include", "/opt/local/include/mysql", "/opt/local/include/mysql5/mysql", "/Developer/Headers/FlatCarbon", ); var inc2; if( isap2 ) inc2 = $array( "/usr/local/apache2/include", "/usr/include/apache2", "/opt/local/apache2/include", "/usr/include/apr-1", "/usr/include/apr-1.0", "/usr/include/apr-0", "/usr/local/include/apr-1", "/usr/local/include/apr-1.0", "/usr/local/include/apr-0", "/opt/local/include/apr-1", "/opt/local/include/apr-1.0", "/opt/local/include/apr-0" ); else inc2 = $array( "/usr/apache/include", "/usr/include/apache-1.3", "/usr/include/httpd", "/opt/local/include/apache", "/opt/local/include/httpd", "/usr/local/apache/include" ); return $aconcat($array(inc1,inc2)); } var cwd = $loader.loadprim("std@get_cwd",0)(); cwd = $ssub(cwd,0,$ssize(cwd)-1); libraries = $array( cwd, "/usr/lib", "/usr/lib/mysql", "/usr/local/lib", "/usr/local/lib/mysql", "/opt/local/lib", "/opt/local/lib/mysql", "/opt/local/lib/mysql5/mysql", ); exec = function(cmd) { $print(cmd,"\n"); var ecode = command(cmd); if( ecode != 0 ) $throw("Error "+ecode+" : aborted"); } make = function(sep,arr) { var i = 0; var s = ""; while( i < $asize(arr) ) { s = s + sep+arr[i]+" "; i = i + 1; } return s; } append = function(arr,s) { var n = $asize(arr); var arr2 = $amake(n+1); $ablit(arr2,0,arr,0,n); arr2[n] = s; return arr2; } readline = function() { $print("> "); var b = buffer_new(); do { var c = read_char(stdin); if( c == 10 ) break; buffer_add_char(b,c); } while(true); return buffer_string(b); } request_include = function(incl) { var s = readline(); if( s == "s" ) return null; return append(incl,s); } request_lib = function() { var s = readline(); if( s == "s" ) return false; libraries = append(libraries,s); return true; } find_file = function(f,arr) { var i = 0; while( i < $asize(arr) ) { if( exists(arr[i]+"/"+f) ) return arr[i]; i = i + 1; } return null; } map = function(a,f) { var i = 0; var l = $asize(a); var a2 = $amake(l); while( i < l ) { a2[i] = f(a[i]); i = i + 1; } return a2; } copy = function(file,path) { switch system { "Windows" => { slashes = function(f) { var c = split(f,"/"); var b = ""; while( c != null ) { b = b + c[0]; if( c[1] != null ) b = b + "\\"; c = c[1]; } return b; } exec("copy "+slashes(file)+" "+slashes(path)+" >NUL"); } default => exec("cp "+file+" "+path) }; } compile = function(file,eflags,incl) { exec(cc+" "+cflags+" "+eflags+" -c "+make("-I",includes)+make("-I",incl)+file+".c"); } nekoboot = function(file) { exec(nekovm+" tools/nekoboot "+file); delete(file); } link = function(files,target,params1,params2) { files = make("",map(files,function(f) { var dir = split(f,"/"); while( dir[1] != null ) dir = dir[1]; dir[0] + ".o" })); var opt = linkoptions; if( target != "mod_tora" && target != "mod_tora2" ) opt += " "+linkneko; var cmd = linkcmd+" "+make("-L",libraries); var out = " -o ../../bin/"+target+".ndll "; exec(cmd+out+files+params1+params2+" "+opt); } // COMPILATION loop_include = function(data,i,incl) { var dir; while( (dir = find_file(data.inc[i],incl)) == null ) { $print("The file "+data.inc[i]+" provided when installing "+data.incname+" was not found\n"); $print("Please enter a valid include path to look for it\n"); $print("Or 's' to skip this library\n"); incl = request_include(incl); if( incl == null ) return null; } return dir; } compile_lib = function(name,data) { $print("Compiling ",name,"...\n"); var incl = search_includes(data.apache2); var dirs = $array(); if( $typeof(data.inc) == $tstring ) data.inc = $array(data.inc); var i = 0; while( i < $asize(data.inc) ) { var dir = loop_include(data,i,incl); if( dir == null ) return; dirs = append(dirs,dir); i += 1; } var linklib = data.lib; var dir = ""; if( linklib == null ) linklib = ""; else { while( (dir = find_file(linklib,libraries)) == null ) { $print("The file "+linklib+" provided when installing "+data.incname+" was not found\n"); $print("Please enter a valid include path to look for it\n"); $print("Or 's' to skip this library\n"); if( $not(request_lib()) ) return; } linklib = dir + "/" + linklib; } var i = 0; var dir = data.realdir; if( dir == null ) dir = name; chdir(dir); while( i < $asize(data.src) ) { compile(data.src[i],if( data.cflags != null ) data.cflags else "", dirs); i = i + 1; } link(data.src,name,if( data.lparams != null ) { data.lparams+" " } else ""," "+linklib); chdir(".."); data.built = true; } // MAIN LOOP rights = 493; // octal 755 base = "../bin"; try { mkdir(base,rights); } catch e { }; copy("../boot/nekoc.n",base); copy("../boot/nekoml.n",base); // compile some neko sources exec(nekovm+" nekoc tools/test.neko"); copy("tools/test.n",base); exec(nekovm+" nekoc tools/nekoboot.neko"); exec(nekovm+" nekoml -nostd -p tools Tools.nml"); exec(nekovm+" nekoc -link tools/nekotools.n Tools"); copy("tools/nekotools.n",base); nekoboot(base+"/nekoc.n"); nekoboot(base+"/nekoml.n"); nekoboot(base+"/nekotools.n"); // compile libs chdir("../libs"); var liblist = $objfields(libs); var i = 0; while( i < $asize(liblist) ) { var l = liblist[i]; compile_lib($field(l),$objget(libs,l)); i += 1; } // rebuild nekoml.std (needs zlib) chdir("../src"); if( libs.zlib != null && libs.zlib.built ) exec(nekovm+" nekoml -nostd neko/Main.nml nekoml/Main.nml core/*.nml -pack ../bin/nekoml.std"); // END $print("Install done, all files are available in /bin directory\n"); neko-2.0.0/src/tools/WebServer.nml0000644000175000017500000004005312112157473017521 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ type main_function; type client { sock : Net.socket; in : IO.input; out : IO.output; mutable headers : (string, string) list; mutable headers_sent : bool; mutable return_code : (int, string); mutable main : main_function option; } var mime = [ ("gif" , "image/gif"); ("jpeg", "image/jpeg"); ("jpg", "image/jpeg"); ("png", "image/png"); ("css", "text/css"); ("html", "text/html"); ("htm", "text/html"); ("txt", "text/plain"); ("js", "application/javascript"); ("pdf", "application/pdf"); // do we really want that ?? ("xml", "text/xml"); ("wav", "audio/x-wav") ]; var cur_path = &Sys.get_cwd(); var file_log = &None; var module_cache = Hashtbl.create(); var mod_rewrite = &false; function sys_is_file(file) { neko "$loader.loadprim('std@sys_file_type',1)(file)" == "file" } function page_404(url) { " 404 Not Found

Not Found

The requested URL "+url+" was not found on this server.


Neko Web DevServer
" } function page_config() { var path = String.concat " - " neko("@List.@make($loader.path)"); " Neko WebServer Config

Neko WebServer Configuration

Visit website" } type http_method { MethodGet; MethodPost; MethodCustom : string; } type http_request { method : http_method; res : string; url : (string, string); version : string; ctype : string option; headers : (string,string) list; mutable params : (string, string) list; mutable post_data : string option; } exception Invalid_char; function invalid_char(l) { throw Invalid_char }; function part(lex,p,l) { var s = Lexer.current lex; String.sub s p (String.length s - (p+l)) } function parse_get_params(str) { var params = String.split str ";"; var params = List.concat (List.map (function(s) { String.split s "&" }) params); List.map (function(p) { match String.split p "=" { | [] -> ("","") | [p] -> (Net.url_decode p,"") | p :: val -> (Net.url_decode p , Net.url_decode (String.concat "=" val)) } }) params; } var http_request_method = Lexer.build [ ("GET", function(l) { MethodGet }); ("POST", function(l) { MethodPost }); ("PUT", function(l) { MethodCustom "PUT" }); ("HEAD", function(l) { MethodCustom "HEAD" }); ("DELETE", function(l) { MethodCustom "DELETE" }); ("TRACE",function(l) { MethodCustom "TRACE" }); ("CONNECT",function(l) { MethodCustom "CONNECT" }); ("OPTIONS",function(l) { MethodCustom "OPTIONS" }); ] invalid_char; var http_request_url = Lexer.build [ (" [^ ]+ ", function(l) { var url = part l 1 1; try { var p = String.find url 0 "?"; var base = String.sub url 0 p; var params = String.sub url (p + 1) (String.length url - (p+1)); (base, params) } catch { Not_found -> (url,"") } }) ] invalid_char; var http_request_version = Lexer.build [ ("HTTP/[0-9.]+\r\n", function(l) { part l 5 2 }); ] invalid_char; var http_header_value = Lexer.build [ ("[^\r]+\r\n", function(l) { part l 0 2 }) ] invalid_char; var http_headers = &Lexer.empty(); http_headers := Lexer.build [ ("\r", function(l) { if Lexer.read l != '\n' then throw Invalid_char; [] }); ("[-A-Za-z0-9_]+: ", function(l) { var s = part l 0 2; var v = Lexer.token l http_header_value; (s,v) :: Lexer.token l (*http_headers) }); ] invalid_char; function header(name,headers) { try { Some snd(List.find (function((n,_)) { String.lowercase n == String.lowercase name }) headers) } catch { Not_found -> None } } function parse_http_request(c) { var l = Lexer.create(); Lexer.input l "http-stream" c.in 1 0; var meth = Lexer.token l http_request_method; var url = Lexer.token l http_request_url; var version = Lexer.token l http_request_version; var headers = Lexer.token l (*http_headers); var params = parse_get_params snd(url); var ctype = header "Content-Type" headers; var post_data, params = if meth == MethodPost && ctype != Some "multipart/form-data" then { var len = match header "Content-Length" headers { None -> 0 | Some len -> int len }; if len >= (1 << 18) then { IO.write c.out "HTTP/1.1 200 OK\r\n"; IO.write c.out "\n\n"; IO.write c.out "Max post data exceeded"; printf "Max post data exceeded (%d bytes)\n" len; throw IO.Eof; } var b = Buffer.create(); var i = &0; while *i < len { Buffer.add_char b (Lexer.read l); i := *i + 1; } var data = Buffer.string b; (Some data , List.append (parse_get_params data) params); } else (None , params); { method = meth; res = Net.url_decode fst(url); url = url; params = params; version = version; headers = headers; post_data = post_data; ctype = ctype; } } function flog(s) { match *file_log { | None -> () | Some f -> IO.write f s; IO.flush f; } } function log( fmt : 'a format, args : 'a ) { var s = sprintf fmt args + "\n"; print s; flog s; } function init_client(s) { var read, write = Net.socket_io s; var ip , port = Net.socket_peer s; { sock = s; in = read; out = write; headers = [("Content-Type","text/html")]; headers_sent = false; return_code = (200,"OK"); main = None; } } function rec find_url_file(url,recursive) { var len = String.length url; if len > 0 && String.get url (len - 1) == '/' then { function rec loop(l) { match l { | [] -> if *mod_rewrite then find_url_file (String.sub url 0 (len - 1)) true else None | f :: l -> match find_url_file(url + f) false { | None -> loop l | x -> x } } } loop ["index.html"; "index.htm"; "index.n"]; } else { var path = if len > 0 && String.get url 0 == '/' then String.sub url 1 (len - 1) else url; var path = *cur_path + path; if Sys.exists path && sys_is_file path then Some path else if recursive && *mod_rewrite then // if path like /path/to/file then lookup /path/to/file.n match find_url_file (url + ".n") false { | Some url -> Some url | None -> // lookup in subdirectory match List.rev String.split(url,"/") { | [] | [_] -> None | _ :: dir -> find_url_file (String.concat "/" List.rev(dir) + "/") true } } else None } } function log_exception(e) { Stack.dump IO.stderr Stack.exc(); IO.printf IO.stderr "Exception : %s\n" string(e); } function print_exception(e) { var stack = Stack.exc(); function format(s) { var s = String.concat "<" (String.split s "<"); var s = String.concat ">" (String.split s ">"); s }; Array.iter (function(s) { match s { | Stack.CFunction -> print "Called from a C function
" | Stack.Module m -> printf "Called from %s (no debug available)
" format(m) | Stack.Pos (file,line) -> printf "Called from %s line %d
" (format file,line) } }) stack var s = string(e); printf "Exception : %s" format(s); } function send_headers(c) { if !c.headers_sent then { c.headers_sent := true; IO.write c.out (sprintf "HTTP/1.1 %d %s\r\n" c.return_code); List.iter (function((name,v)) { IO.write c.out (sprintf "%s: %s\r\n" (name,v)); }) (List.rev c.headers); IO.write c.out "\r\n"; } } function headers_not_sent(c,s) { // should we send an object like mod_neko failure does ? if c.headers_sent then (neko "$throw")("Cannot set "+s+" : Headers already sent"); } function set_header(c,n,v) { headers_not_sent c n; c.headers := (n,v) :: List.filter (function((n2,_)) { n != n2 }) c.headers; } var cur_client : client option ref = &None; var cur_request : http_request option ref = &None; function client() { match *cur_client { | None -> assert() | Some c -> c } } function request() { match *cur_request { | None -> assert() | Some r -> r } } function do_print(v) { var c = client(); try { send_headers(c); var s = string(v); IO.write c.out s; } catch { Neko_error e when magic e == "std@socket_send" -> () } } function init_mod_neko() { // simulate a mod_neko environment var hmethods = Hashtbl.create(); function rec flatten(l) { match l { | [] -> neko "null" | (x,y) :: l -> var l = flatten l; neko "$array(x,y,l)" } } Sys.put_env "MOD_NEKO" "1"; var jit = Sys.get_env "MOD_NEKO_JIT" != None; neko "$loader.loadprim('std@enable_jit',1)(jit)"; function def(name : string,f) { Hashtbl.replace hmethods name magic(f); } function no_param(name,f) { def name neko("function() { f(null) }"); } no_param "get_cookies" (function() { flatten ( match header "Cookie" request().headers { | None -> [] | Some k -> var l = String.split k "; "; List.map (function(k) { match String.split k "=" { | [] | [_] -> (k,"") | k :: l -> (k,String.concat "=" l) } }) l } ) }); def "set_cookie" (function(name,val) { var c = client(); headers_not_sent c "Cookie"; c.headers := ("Set-Cookie",name+"="+val+";") :: c.headers; }); no_param "get_host_name" (function() { Net.host_to_string fst(Net.socket_host client().sock); }); no_param "get_client_ip" (function() { Net.host_to_string fst(Net.socket_peer client().sock); }); no_param "get_uri" (function() { var r = request(); fst r.url }); def "redirect" (function(url) { var c = client(); headers_not_sent c "Redirection"; set_header c "Location" url; c.return_code := (302, "Found"); }); def "set_return_code" (function(i) { var c = client(); headers_not_sent c "Return code"; c.return_code := (i, "OK"); }); def "set_header" (function(name,val) { var c = client(); headers_not_sent c name; set_header c name val; }); def "get_client_header" (function(name) { match header name request().headers { | None -> neko "null" | Some h -> h } }); no_param "get_client_headers" (function() { flatten request().headers }); no_param "get_params_string" (function() { snd request().url }); no_param "get_post_data" (function() { match request().post_data { | None -> neko "null" | Some d -> d } }); no_param "get_params" (function() { flatten request().params }); no_param "cgi_get_cwd" (function() { *cur_path }); def "cgi_set_main" (function(f) { client().main := (if f == neko "null" then None else Some f); }); no_param "cgi_flush" (function() { IO.flush client().out; }); def "parse_multipart_data" (function(part,data) { if request().ctype == Some "multipart/form-data" then (neko "$throw")("parse_multipart_data not implemented"); }); no_param "get_http_method" (function() { match request().method { | MethodGet -> "GET" | MethodPost -> "POST" | MethodCustom r -> r } }); def "log_message" (function (s) { IO.printf IO.stderr "[log] %s\n" s; }); function resolve_method(f:string) { try { Hashtbl.find hmethods f } catch { Not_found -> neko "null" } } var loader = neko "{ args => $array(), path => $loader.path, cache => $loader.cache, loadmodule => function(name,l) { $loader.cache = this.cache; $loader.loadmodule(name,l); }, loadprim => function(prim,nargs) { var l = $ssize(prim); if l > 9 && $ssub(prim,0,9) == 'mod_neko@' { prim = $ssub(prim,9,l-9); var f = resolve_method(prim); if( f == null ) $throw('Unknown mod_neko primitive : '+prim); if( $nargs(f) != nargs ) $throw('Invalid number of arguments for '+prim); return f; } return $loader.loadprim(prim,nargs); } }"; var redirect = neko "$loader.loadprim('std@print_redirect',1)"; var old_cache = neko "$new($loader.cache)"; function(c,r,file) { cur_client := Some c; cur_request := Some r; var main_fun = try { var f = Hashtbl.find module_cache file; c.main := Some f; f } catch { Not_found -> neko "null" }; try { redirect(do_print); if main_fun == neko "null" then neko "loader.loadmodule(file,loader)" else neko "main_fun()"; redirect(neko "null"); } catch { e -> log_exception(e); // stderr try { print_exception(e) } catch { e -> () }; // on screen redirect(neko "null"); } if !c.headers_sent then do_print " "; match c.main { | None -> neko " $loader.cache = $new(old_cache); loader.cache = $loader.cache; "; | Some f -> Hashtbl.add module_cache file f; } } } var mod_neko = init_mod_neko(); function config(c,r) { try { var dir = List.assoc "path" r.params; var old = Sys.get_cwd(); try { Sys.set_cwd dir; cur_path := Sys.get_cwd(); Sys.set_cwd old; } catch { e -> log_exception e } } catch { Not_found -> () } do_print page_config() } function client_msg(c) { var r = parse_http_request c; cur_client := Some c; if r.res == "/server:config" then config(c,r) else match find_url_file r.res true { | None -> c.return_code := (404,"Not Found"); do_print page_404(r.res); | Some file -> var ext = String.lowercase (Sys.extension file); if ext == "n" then { log "Request %s [%s]" (r.res, match r.params { | [] -> "" | l -> "\n " + (String.concat "\n " (List.map (function((p,v)) { p + " => "+ v }) l)) + "\n" }); mod_neko c r file } else { // directly send the file content IO.write c.out "HTTP/1.1 200 OK\r\n"; var ctype = try { List.assoc ext mime } catch { Not_found -> "unknown/unknown" }; var file_size : int = neko "$loader.loadprim('std@sys_stat',1)(file).size"; IO.write c.out ("Content-Type: " + ctype + "\r\n"); IO.write c.out ("Content-Length: " + file_size + "\r\n"); IO.write c.out "\r\n"; var fin = IO.read_file file true; var bufsize = 100000; var n = &(file_size / bufsize); try { while *n > 0 { IO.write c.out IO.read(fin,bufsize); n := *n - 1; } IO.write c.out IO.read(fin,file_size % bufsize); } catch { e -> IO.close_in fin; throw e } IO.close_in fin } } } function client_msg_safe(c) { try { client_msg(c); } catch { | Invalid_char -> printf "Invalid char reveived\n" (); | IO.Eof -> printf "Connection aborted\n" (); | Neko_error e when Reflect.value e == Reflect.VString "std@socket_send" -> printf "Sending file aborted\n" (); } Net.socket_close c.sock; neko "$loader.loadprim('std@run_gc',1)(true)"; false } function init() { var head = "Neko Web Server v1.0 - (c)2006-2013 Haxe Foundation"; var port = &2000; var host = &"localhost"; var decl = [ ("-p", Args.Int (function(n) { port := n }) , " : change server port"); ("-h", Args.String (function(h) { host := h }) , " : change server host"); ("-d", Args.String (function(d) { var old = Sys.get_cwd(); Sys.set_cwd d; cur_path := Sys.get_cwd(); Sys.set_cwd old; }), " : change the server base directory"); ("-log", Args.String (function(s) { file_log := Some (IO.write_file s true) }), " : set log file"); ("-rewrite", Args.Void (function() { mod_rewrite := true }), ": activate pseudo mod-rewrite for smart urls"); ]; Args.parse head decl (function(f) { throw Args.Invalid }); log "Starting Neko Server on %s:%d" (*host,*port); Net.start_server Net.host_resolve(*host) (*port) init_client client_msg_safe; } neko-2.0.0/src/tools/nekoboot.neko0000644000175000017500000000621712112157473017607 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ // primitives file_contents = $loader.loadprim("std@file_contents",1); file_open = $loader.loadprim("std@file_open",2); file_write = $loader.loadprim("std@file_write",4); file_write_char = $loader.loadprim("std@file_write_char",2); file_close = $loader.loadprim("std@file_close",1); command = $loader.loadprim("std@sys_command",1); system = $loader.loadprim("std@sys_string",0)(); // find a substring from then end find = function(str,sub,pos) { var l1 = $ssize(str); var l2 = $ssize(sub); var i = l1 - pos; while( i >= 0 ) { if( $ssub(str,i,l2) == sub ) return i; i -= 1; } return null; } // find a file in a path find_exe_in_path = function(path,file) { while( path != null ) { try { var s = file_contents(path[0]+file); if( $sget(s,0) == 35 ) // '#' $throw("Is a script"); return s; } catch e { path = path[1]; } } $throw("The bootable executable file was not found : "+file); } // bytecode = first argument var args = $loader.args; var exe_ext = switch system { "Windows" => ".exe" default => "" }; var boot_exe = "neko" + exe_ext; if( args[0] == "-b" ) { boot_exe = args[1]; args = $asub(args,2,$asize(args)-2); } if( $asize(args) != 1 ) $throw("Need bytecode argument"); var file = args[0]; var bytecode = file_contents(file); // load boot binary var boot = find_exe_in_path($loader.path,boot_exe); var boot_size = $ssize(boot); var dot_pos = find(file,".",1); if( dot_pos != null ) file = $ssub(file,0,dot_pos); // create executable file : // this is the content of boot.bin where is appended // the neko bytecode followed by 'NEKO' and the original exe size var out_name = file+exe_ext; var out = file_open(out_name,"wb"); file_write(out,boot,0,boot_size); file_write(out,bytecode,0,$ssize(bytecode)); file_write(out,"NEKO",0,4); file_write_char(out,boot_size & 0xFF); file_write_char(out,(boot_size >> 8) & 0xFF); file_write_char(out,(boot_size >> 16) & 0xFF); file_write_char(out,boot_size >>> 24); file_close(out); // set execution rights switch system { "Windows" => null default => command("chmod 755 "+out_name) } neko-2.0.0/src/tools/Tools.nml0000644000175000017500000000356612112157473016725 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ exception Done; function erase_argument() { neko "$loader.args = $asub($loader.args,1,$asize($loader.args)-1)" } function invalid_arg(f) { throw Args.Invalid } try { var head = "Neko Tools v1.0 - (c)2006-2013 Haxe Foundation\nUsage : nekotools [options]"; var decl = [ ("server", Args.Void (function() { erase_argument(); WebServer.init(); throw Done }) , " : start a neko web server"); ("boot", Args.String (function(_) { erase_argument(); neko "$loader.loadmodule('tools/nekoboot',$loader)"; throw Done; }) , " : build an standalone executable"); ]; Args.parse head decl invalid_arg; } catch { | e -> if e == Done then Sys.exit(0); Stack.dump IO.stderr Stack.exc(); IO.printf IO.stderr "Exception : %s\n" string(e); Sys.exit (-1); }neko-2.0.0/src/tools/test.neko0000644000175000017500000000017112112157473016737 0ustar ncannassencannasse$print("The virtual machine is working !\n"); test = $loader.loadprim("std@test",0); test(); $print("Test successful\n");neko-2.0.0/src/tools/makedoc.neko0000644000175000017500000000351312112157473017366 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ readdir = $loader.loadprim("std@sys_read_dir",1); command = $loader.loadprim("std@sys_command",1); exec = function(cmd) { $print(cmd,"\n"); var ecode = command(cmd); if( ecode != 0 ) $throw("Error "+ecode+" : aborted"); } makedoc = function(file) { exec("nekoc -o ../www/libs -doc ../"+file); } files = $array( "vm/builtins.c", ); var i = 0; var l = $asize(files); while i < l { makedoc(files[i]); i = i + 1; } var libs = readdir("../libs"); while( libs != null ) { var l = libs[0]; var k = try readdir("../libs/"+l) catch _ { null }; if( l == "mod_tora" ) k = null; while( k != null ) { var f = k[0]; var len = $ssize(f); if( $ssub(f,len-2,2) == ".c" ) makedoc("libs/"+l+"/"+f); k = k[1]; } libs = libs[1]; } neko-2.0.0/src/tools/mod_neko_config.neko0000644000175000017500000000644512112157473021112 0ustar ncannassencannassebegin = " Mod_Neko Configuration

Mod_neko Configuration

"; end = "

Home

"; var params = $loader.loadprim("mod_neko@get_params",0)(); var get_config = $loader.loadprim("mod_neko@cgi_get_config",0); var memory = $loader.loadprim("std@mem_size",1); var execCommand = $loader.loadprim("mod_neko@cgi_command",1); var setHeader = $loader.loadprim("mod_neko@set_header",2); getParam = function(name) { var p = params; while( p != null ) { if( p[0] == name ) return p[1]; p = p[2]; } return null; } error = function(e) { $throw(e); } message = function(msg) { $print(begin); $print("

",msg,"

"); $print(end); } displayObject = function(obj,edit) { var fl = $objfields(obj); var i = 0; $print("
    "); while( i < $asize(fl) ) { var name = $field(fl[i]); var data = $objget(obj,fl[i]); $print("
  • ",name," "); if( edit && $typeof(data) == $tbool ) $print(""); else $print(": ",data); $print("
  • "); i += 1; } $print("
"); } displayVars = function() { var gc = $loader.loadprim("std@gc_stats",0)(); var now = $loader.loadprim("std@date_now",0)(); displayObject({ date => $loader.loadprim("std@date_format",2)(now,null), pid => $loader.loadprim("std@sys_get_pid",0)(), gc_heap => gc.heap, gc_free => gc.free, gc_free_size => $int(gc.free * 100.0 / gc.heap) + "%", },false); } displayConfig = function(cfg) { $print("
"); displayObject(cfg,true); $print(""); $print(""); } displayCache = function(cache) { $print("
Loader path : "+path+"
Server directory :
 
"); $print(""); while( cache != null ) { $print(""); cache = cache[3]; } $print("
FileMemHits
",cache[0],"",memory(cache[1]),"",cache[2],"
"); } displayMenu = function() { $print(begin); $print("

Vars

"); displayVars(); $print("

Config

"); displayConfig(get_config()); $print("

Cache

"); displayCache(execCommand("cache")); $print("

Command

"); $print(""); $print(end); } displayStatistics = function(stats) { $print(begin); $print("

Statistics

"); $print(""); $print(""); while( stats != null ) { $print(""); stats = stats[5]; } $print("
NameTotal TimeInner TimeHitsErrors
",stats[0],"",stats[1],"",stats[2],"",stats[3],"",stats[4],"
"); $print(end); } setConfig = function() { var cfg = get_config(); var fl = $objfields(cfg); var i = 0; while( i < $asize(fl) ) { var name = $field(fl[i]); var data = $objget(cfg,fl[i]); var value = getParam(name); if( $typeof(data) == $tbool ) $objset(cfg,fl[i],value != null); i += 1; } $loader.loadprim("mod_neko@cgi_set_config",1)(cfg); message("Configuration Updated"); } var cmd = getParam("command"); switch( cmd ) { "stats" => displayStatistics(execCommand("stats")) "setconfig" => setConfig() default => { if( cmd != null && cmd != "" ) error("Unknown command "+cmd); displayMenu() } } neko-2.0.0/src/neko.vcproj0000644000175000017500000000617212112157473016132 0ustar ncannassencannasse neko-2.0.0/vm/0000755000175000017500000000000012112157473013576 5ustar ncannassencannasseneko-2.0.0/vm/objtable.c0000644000175000017500000000554612112157473015536 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include "objtable.h" int otable_remove( objtable *t, field id ) { int min = 0; int max = t->count; int mid; field cid; objcell *c = t->cells; if( !max ) return 0; while( min < max ) { mid = (min + max) >> 1; cid = c[mid].id; if( cid < id ) min = mid + 1; else if( cid > id ) max = mid; else { t->count--; while( mid < t->count ) { c[mid] = c[mid+1]; mid++; } c[mid].v = val_null; return 1; } } return 0; } void otable_optimize( objtable *t ) { int max = t->count; int i; int cur = 0; objcell *c = t->cells; for(i=0;icount = cur; } void otable_replace( objtable *t, field id, value data ) { int min = 0; int max = t->count; int mid; field cid; objcell *c = t->cells; while( min < max ) { mid = (min + max) >> 1; cid = c[mid].id; if( cid < id ) min = mid + 1; else if( cid > id ) max = mid; else { c[mid].v = data; return; } } mid = (min + max) >> 1; c = (objcell*)alloc(sizeof(objcell)*(t->count + 1)); min = 0; while( min < mid ) { c[min] = t->cells[min]; min++; } c[mid].id = id; c[mid].v = data; while( min < t->count ) { c[min+1] = t->cells[min]; min++; } t->cells = c; t->count++; } void otable_copy( objtable *t, objtable *target ) { target->count = t->count; target->cells = (objcell*)alloc(sizeof(objcell)*t->count); memcpy(target->cells,t->cells,sizeof(objcell)*t->count); } void otable_iter(objtable *t, void f( value data, field id, void *), void *p ) { int i; int n = t->count; objcell *c = t->cells; for(i=0;icount = 0; t->cells = NULL; } static INLINE value *otable_find(objtable *t,field id) { int min; int max; int mid; objcell *c; field cid; min = 0; max = t->count; c = t->cells; while( min < max ) { mid = (min + max) >> 1; cid = c[mid].id; if( cid < id ) min = mid + 1; else if( cid > id ) max = mid; else return &c[mid].v; } return NULL; } static INLINE value otable_get(objtable *t,field id) { int min; int max; int mid; objcell *c; field cid; min = 0; max = t->count; c = t->cells; while( min < max ) { mid = (min + max) >> 1; cid = c[mid].id; if( cid < id ) min = mid + 1; else if( cid > id ) max = mid; else return c[mid].v; } return val_null; } void otable_replace(objtable *t, field id, value data); int otable_remove(objtable *t, field id); void otable_optimize(objtable *t); #define otable_count(t) (t)->count void otable_copy(objtable *t, objtable *target); void otable_iter(objtable *t, void f( value data, field id, void *), void *p ); #endif /* ************************************************************************ */ neko-2.0.0/vm/stats.c0000644000175000017500000001255112112157473015104 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include "neko_vm.h" #ifdef NEKO_WINDOWS # include #else # include #endif typedef struct _statinfos { const char *kind; int ksize; int ncalls; int nerrors; int subtime; int totaltime; int starttime; struct _statinfos *stack; struct _statinfos *next; } statinfos; static statinfos *list = NULL; static statinfos *stack = NULL; static int init_done = 0; static int precise_timer() { # ifdef NEKO_WINDOWS LARGE_INTEGER t; static LARGE_INTEGER freq; if( !init_done ) { DWORD procs, sm, procid = 1; // ensure that we always use the same processor // or else, performance counter might vary depending // on the current CPU GetProcessAffinityMask(GetCurrentProcess(),&procs,&sm); while( !(procs & procid) ) procid <<= 1; SetProcessAffinityMask(GetCurrentProcess(),procid); init_done = 1; QueryPerformanceFrequency(&freq); } QueryPerformanceCounter(&t); return (int)( t.QuadPart * 1000000 / freq.QuadPart ); # else static int base_sec; struct timeval tv; gettimeofday(&tv,NULL); if( !init_done ) { init_done = 1; base_sec = tv.tv_sec; } return (tv.tv_sec - base_sec) * 1000000 + tv.tv_usec; # endif } void neko_stats_measure( neko_vm *vm, const char *kind, int start ) { int ksize = (int)strlen(kind); statinfos *s; if( start ) { int time = precise_timer(); // lookup in list s = list; while( s ) { if( ksize == s->ksize && s->starttime == 0 && memcmp(kind,s->kind,ksize) == 0 ) break; s = s->next; } // init if( s == NULL ) { s = (statinfos*)malloc(sizeof(statinfos)); s->kind = strdup(kind); s->ksize = ksize; s->ncalls = 0; s->nerrors = 0; s->totaltime = 0; s->subtime = 0; s->next = list; list = s; } // add to stack s->ncalls++; s->stack = stack; stack = s; s->starttime = time; } else { // lookup on stack s = stack; while( s ) { statinfos *next; if( ksize == s->ksize && memcmp(kind,s->kind,ksize) == 0 ) break; next = s->stack; s->nerrors++; // stop was not done (exception) s->starttime = 0; s = next; } // pop from stack if( s ) { int delta = precise_timer() - s->starttime; s->totaltime += delta; stack = s->stack; if( stack ) stack->subtime += delta; s->starttime = 0; } else stack = NULL; } } // merged-sort for linked list static int cmp( statinfos *a, statinfos *b ) { int delta = a->totaltime - b->totaltime; if( delta == 0 ) return b->ncalls - a->ncalls; return delta; } static statinfos *sort( statinfos *list ) { statinfos *p, *q, *e, *tail; int insize, nmerges, psize, qsize, i; insize = 1; while( list ) { p = list; list = NULL; tail = NULL; nmerges = 0; while( p ) { nmerges++; q = p; psize = 0; for(i=0;inext; if (!q) break; } qsize = insize; while (psize > 0 || (qsize > 0 && q)) { if( psize == 0 ) { e = q; q = q->next; qsize--; } else if( qsize == 0 || !q ) { e = p; p = p->next; psize--; } else if( cmp(p,q) <= 0 ) { e = p; p = p->next; psize--; } else { e = q; q = q->next; qsize--; } if( tail ) tail->next = e; else list = e; tail = e; } p = q; } tail->next = NULL; if( nmerges <= 1 ) return list; insize *= 2; } return NULL; } value neko_stats_build( neko_vm *vm ) { value v = val_null; statinfos *s = list; // merge duplicates while( s ) { statinfos *s2 = s->next, *prev = s; while( s2 ) { if( s2->ksize == s->ksize && memcmp(s->kind,s2->kind,s->ksize) == 0 ) { s->nerrors += s2->nerrors; s->ncalls += s2->ncalls; s->totaltime += s2->totaltime; s->subtime += s2->subtime; prev->next = s2->next; free(s2); s2 = prev->next; } else { prev = s2; s2 = s2->next; } } s = s->next; } list = sort(list); s = list; while( s ) { value tmp = alloc_array(6); val_array_ptr(tmp)[0] = alloc_string(s->kind); val_array_ptr(tmp)[1] = alloc_int(s->totaltime); val_array_ptr(tmp)[2] = alloc_int(s->totaltime - s->subtime); val_array_ptr(tmp)[3] = alloc_int(s->ncalls); val_array_ptr(tmp)[4] = alloc_int(s->nerrors); val_array_ptr(tmp)[5] = v; v = tmp; s = s->next; } return v; } neko-2.0.0/vm/main.c0000644000175000017500000001761212112157473014675 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include "neko_vm.h" #ifdef NEKO_WINDOWS # include #else # include #endif #ifdef NEKO_MAC # include # include #endif #ifdef NEKO_POSIX # include #endif #ifdef NEKO_STANDALONE extern void neko_standalone_init(); extern void neko_standalone_error( const char *str ); extern value neko_standalone_loader( char **arv, int argc ); # define default_loader neko_standalone_loader #else # define default_loader neko_default_loader #endif static FILE *self; extern void neko_stats_measure( neko_vm *vm, const char *kind, int start ); extern value neko_stats_build( neko_vm *vm ); static char *executable_path() { #if defined(NEKO_WINDOWS) static char path[MAX_PATH]; if( GetModuleFileName(NULL,path,MAX_PATH) == 0 ) return NULL; return path; #elif defined(NEKO_MAC) static char path[MAXPATHLEN+1]; uint32_t path_len = MAXPATHLEN; if ( _NSGetExecutablePath(path, &path_len) ) return NULL; return path; #else static char path[200]; int length = readlink("/proc/self/exe", path, sizeof(path)); if( length < 0 || length >= 200 ) { char *p = getenv(" "); // for upx if( p == NULL ) p = getenv("_"); return p; } path[length] = '\0'; return path; #endif } int neko_has_embedded_module( neko_vm *vm ) { char *exe = executable_path(); unsigned char id[8]; int pos; if( exe == NULL ) return 0; self = fopen(exe,"rb"); if( self == NULL ) return 0; fseek(self,-8,SEEK_END); if( fread(id,1,8,self) != 8 || id[0] != 'N' || id[1] != 'E' || id[2] != 'K' || id[3] != 'O' ) { fclose(self); return 0; } pos = id[4] | id[5] << 8 | id[6] << 16; fseek(self,pos,SEEK_SET); // flags if( (id[7] & 1) == 0 ) neko_vm_jit(vm,1); return 1; } static void report( neko_vm *vm, value exc, int isexc ) { int i; buffer b = alloc_buffer(NULL); value st = neko_exc_stack(vm); for(i=0;i #else # define _CrtSetDbgFlag(x) #endif #ifdef NEKO_POSIX static void handle_signal( int signal ) { val_throw(alloc_string("Segmentation fault")); } #endif int main( int argc, char *argv[] ) { neko_vm *vm; value mload; int r; _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); neko_global_init(); vm = neko_vm_alloc(NULL); neko_vm_select(vm); # ifdef NEKO_STANDALONE neko_standalone_init(); # endif if( !neko_has_embedded_module(vm) ) { int jit = 1; int stats = 0; while( argc > 1 ) { if( strcmp(argv[1],"-interp") == 0 ) { argc--; argv++; jit = 0; continue; } if( strcmp(argv[1],"-stats") == 0 ) { argc--; argv++; stats = 1; neko_vm_set_stats(vm,neko_stats_measure,neko_stats_measure); neko_stats_measure(vm,"total",1); continue; } if( strcmp(argv[1],"-version") == 0 ) { argc--; argv++; printf("%d.%d.%d",NEKO_VERSION/100,(NEKO_VERSION/10)%10,NEKO_VERSION%10); return 0; } break; } # ifdef NEKO_POSIX if( jit ) { struct sigaction act; act.sa_sigaction = NULL; act.sa_handler = handle_signal; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGSEGV,&act,NULL); } # endif neko_vm_jit(vm,jit); if( argc == 1 ) { # ifdef NEKO_STANDALONE report(vm,alloc_string("No embedded module in this executable"),0); # else printf("NekoVM %d.%d.%d (c)2005-2013 Haxe Foundation\n Usage : neko \n",NEKO_VERSION/100,(NEKO_VERSION/10)%10,NEKO_VERSION%10); # endif mload = NULL; r = 1; } else { mload = default_loader(argv+2,argc-2); r = execute_file(vm,argv[1],mload); } if( stats ) { value v; neko_stats_measure(vm,"total",0); v = neko_stats_build(vm); val_print(alloc_string("TOT\tTIME\tCOUNT\tNAME\n")); while( v != val_null ) { char buf[256]; value *s = val_array_ptr(v); int errors = val_int(s[4]); sprintf(buf,"%d\t%d\t%d\t%s%c", val_int(s[1]), val_int(s[2]), val_int(s[3]), val_string(s[0]), errors?' ':'\n'); if( errors ) sprintf(buf+strlen(buf),"ERRORS=%d\n",errors); val_print(alloc_string(buf)); v = s[5]; } } } else { mload = default_loader(argv+1,argc-1); r = neko_execute_self(vm,mload); } if( mload != NULL && val_field(mload,val_id("dump_prof")) != val_null ) val_ocall0(mload,val_id("dump_prof")); vm = NULL; mload = NULL; neko_vm_select(NULL); neko_global_free(); return r; } /* ************************************************************************ */ neko-2.0.0/vm/hash.c0000644000175000017500000000544712112157473014677 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "neko.h" typedef struct vlist { value v; struct vlist *next; } vlist; typedef struct vparam { int *h; vlist l; } vparam; #define HBIG(x) *h = *h * 65599 + (x) #define HSMALL(x) *h = *h * 19 + (x) static void hash_obj_rec( value v, field f, void *_p ); static void hash_rec( value v, int *h, vlist *l ) { val_type t = val_type(v); switch( t ) { case VAL_INT: HBIG(val_int(v)); break; case VAL_INT32: HBIG(val_int32(v)); break; case VAL_NULL: HSMALL(0); break; case VAL_FLOAT: { int k = sizeof(tfloat); while( k ) HSMALL(val_string(v)[--k]); } break; case VAL_BOOL: HSMALL(val_bool(v)); break; case VAL_STRING: { int k = val_strlen(v); while( k ) HSMALL(val_string(v)[--k]); } break; case VAL_OBJECT: case VAL_ARRAY: { vlist *tmp = l; int k = 0; while( tmp != NULL ) { if( tmp->v == v ) { HSMALL(k); return; } k = k + 1; tmp = tmp->next; } } if( t == VAL_OBJECT ) { vparam p; p.h = h; p.l.v = v; p.l.next = l; val_iter_fields(v,hash_obj_rec,&p); v = (value)((vobject*)v)->proto; if( v != NULL ) hash_rec(v,h,&p.l); } else { vlist cur; int k = val_array_size(v); cur.v = v; cur.next = l; while( k ) hash_rec(val_array_ptr(v)[--k],h,&cur); } break; default: // ignore since we want hashes to be stable wrt memory break; } } static void hash_obj_rec( value v, field f, void *_p ) { vparam *p = (vparam*)_p; int *h = p->h; HBIG((int)f); hash_rec(v,h,&p->l); } EXTERN int val_hash( value v ) { int h = 0; hash_rec(v,&h,NULL); return (((unsigned int)h) & 0x3FFFFFFF); } /* ************************************************************************ */ neko-2.0.0/vm/opcodes.h0000644000175000017500000001027112112157473015404 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef _NEKO_OPCODES_H #define _NEKO_OPCODES_H #ifndef OP # define OP(x) x # define OPBEGIN enum OPCODE { # define OPEND }; #endif OPBEGIN OP(AccNull), OP(AccTrue), OP(AccFalse), OP(AccThis), OP(AccInt), OP(AccStack), OP(AccGlobal), OP(AccEnv), OP(AccField), OP(AccArray), OP(AccIndex), OP(AccBuiltin), OP(SetStack), OP(SetGlobal), OP(SetEnv), OP(SetField), OP(SetArray), OP(SetIndex), OP(SetThis), OP(Push), OP(Pop), OP(Call), OP(ObjCall), OP(Jump), OP(JumpIf), OP(JumpIfNot), OP(Trap), OP(EndTrap), OP(Ret), OP(MakeEnv), OP(MakeArray), OP(Bool), OP(IsNull), OP(IsNotNull), OP(Add), OP(Sub), OP(Mult), OP(Div), OP(Mod), OP(Shl), OP(Shr), OP(UShr), OP(Or), OP(And), OP(Xor), OP(Eq), OP(Neq), OP(Gt), OP(Gte), OP(Lt), OP(Lte), OP(Not), OP(TypeOf), OP(Compare), OP(Hash), OP(New), OP(JumpTable), OP(Apply), OP(AccStack0), OP(AccStack1), OP(AccIndex0), OP(AccIndex1), OP(PhysCompare), OP(TailCall), OP(Loop), OP(MakeArray2), OP(AccInt32), OP(Last), OPEND #ifdef PARAMETER_TABLE static int parameter_table[] = { 0, // AccNull 0, // AccTrue 0, // AccFalse 0, // AccThis 1, // AccInt 1, // AccStack 1, // AccGlobal 1, // AccEnv 1, // AccField 0, // AccArray 1, // AccIndex 1, // AccBuiltin 1, // SetStack 1, // SetGlobal 1, // SetEnv 1, // SetField 0, // SetArray 1, // SetIndex 0, // SetThis 0, // Push 1, // Pop 1, // Call 1, // ObjCall 1, // Jump 1, // JumpIf 1, // JumpIfNot 1, // Trap 0, // EndTrap 1, // Ret 1, // MakeEnv 1, // MakeArray 0, // Bool 0, // IsNull 0, // IsNotNull 0, // Add 0, // Sub 0, // Mult 0, // Div 0, // Mod 0, // Shl 0, // Shr 0, // UShr 0, // Or 0, // And 0, // Xor 0, // Eq 0, // Neq 0, // Gt 0, // Gte 0, // Lt 0, // Lte 0, // Not 0, // TypeOf 0, // Compare 0, // Hash 0, // New 1, // JumpTable 1, // Apply 0, // AccStack0 0, // AccStack1 0, // AccIndex0 0, // AccIndex1 0, // PhysCompare 1, // TailCall 0, // Loop 1, // MakeArray2 1, // AccInt32 }; #endif #ifdef STACK_TABLE #define P 0xFF static int stack_table[] = { 0, // AccNull 0, // AccTrue 0, // AccFalse 0, // AccThis 0, // AccInt 0, // AccStack 0, // AccGlobal 0, // AccEnv 0, // AccField -1, // AccArray 0, // AccIndex 0, // AccBuiltin 0, // SetStack 0, // SetGlobal 0, // SetEnv -1, // SetField -2, // SetArray -1, // SetIndex 0, // SetThis 1, // Push -P, // Pop -P, // Call -P, // ObjCall 0, // Jump 0, // JumpIf 0, // JumpIfNot 6, // Trap -6, // EndTrap 0, // Ret -P, // MakeEnv -P, // MakeArray 0, // Bool 0, // IsNull 0, // IsNotNull -1, // Add -1, // Sub -1, // Mult -1, // Div -1, // Mod -1, // Shl -1, // Shr -1, // UShr -1, // Or -1, // And -1, // Xor -1, // Eq -1, // Neq -1, // Gt -1, // Gte -1, // Lt -1, // Lte 0, // Not 0, // TypeOf -1, // Compare 0, // Hash 0, // New 0, // JumpTable -P, // Apply 0, // AccStack0 0, // AccStack1 0, // AccIndex0 0, // AccIndex1 -1, // PhysCompare 0, // TailCall 0, // Loop -P, // MakeArray2 0, // AccInt32 0, // Last }; #endif #endif /* ************************************************************************ */ neko-2.0.0/vm/nekovm.vcxproj0000644000175000017500000001703112112157473016514 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {C9796A2F-49BA-4EE2-A28A-2707C5151D0E} Win32Proj Application MultiByte Application MultiByte Application MultiByte <_ProjectFileVersion>10.0.30319.1 ..\bin\ Debug\ true Release\ Release\ false Release\ Release\ false neko Disabled WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug Level3 EditAndContinue ..\bin\neko.lib;%(AdditionalDependencies) $(OutDir)neko.exe true $(OutDir)nekovm.pdb Console MachineX86 WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ..\bin\neko.lib;%(AdditionalDependencies) $(OutDir)neko.exe %(IgnoreSpecificDefaultLibraries) true Console true true MachineX86 copy Release\neko.exe ..\bin WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ..\bin\neko.lib;../libs/include/msvcrt/extra.lib;%(AdditionalDependencies) $(OutDir)neko.exe MSVCRT;%(IgnoreSpecificDefaultLibraries) true Console true true MachineX86 copy Release\neko.exe ..\bin {feba0ca8-4d9c-49c3-b3cc-1a7cff9bb8b3} false neko-2.0.0/vm/callback.c0000644000175000017500000001277612112157473015513 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include "neko.h" #include "objtable.h" #include "vm.h" #include "neko_mod.h" #define MAXCALLS 350 typedef value (*c_prim0)(); typedef value (*c_prim1)(value); typedef value (*c_prim2)(value,value); typedef value (*c_prim3)(value,value,value); typedef value (*c_prim4)(value,value,value,value); typedef value (*c_prim5)(value,value,value,value,value); typedef value (*c_primN)(value*,int); typedef value (*jit_prim)( neko_vm *, void *, value, neko_module * ); extern void neko_setup_trap( neko_vm *vm ); extern void neko_process_trap( neko_vm *vm ); extern int neko_stack_expand( int_val *sp, int_val *csp, neko_vm *vm ); extern char *jit_boot_seq; EXTERN value val_callEx( value vthis, value f, value *args, int nargs, value *exc ) { neko_vm *vm = NEKO_VM(); value old_this = vm->vthis; value old_env = vm->env; value ret = val_null; jmp_buf oldjmp; if( vthis != NULL ) vm->vthis = vthis; if( exc ) { memcpy(&oldjmp,&vm->start,sizeof(jmp_buf)); if( setjmp(vm->start) ) { *exc = vm->vthis; neko_process_trap(vm); vm->vthis = old_this; vm->env = old_env; memcpy(&vm->start,&oldjmp,sizeof(jmp_buf)); return val_null; } neko_setup_trap(vm); } if( (uintptr_t)&vm < (uintptr_t)vm->c_stack_max ) val_throw(alloc_string("C Stack Overflow")); if( val_is_int(f) ) val_throw(alloc_string("Invalid call")); if( val_tag(f) == VAL_PRIMITIVE ) { vm->env = ((vfunction *)f)->env; if( nargs == ((vfunction*)f)->nargs ) { if( nargs > CALL_MAX_ARGS ) failure("Too many arguments for a call"); switch( nargs ) { case 0: ret = ((c_prim0)((vfunction*)f)->addr)(); break; case 1: ret = ((c_prim1)((vfunction*)f)->addr)(args[0]); break; case 2: ret = ((c_prim2)((vfunction*)f)->addr)(args[0],args[1]); break; case 3: ret = ((c_prim3)((vfunction*)f)->addr)(args[0],args[1],args[2]); break; case 4: ret = ((c_prim4)((vfunction*)f)->addr)(args[0],args[1],args[2],args[3]); break; case 5: ret = ((c_prim5)((vfunction*)f)->addr)(args[0],args[1],args[2],args[3],args[4]); break; } } else if( ((vfunction*)f)->nargs == -1 ) ret = (value)((c_primN)((vfunction*)f)->addr)(args,nargs); else val_throw(alloc_string("Invalid call")); if( ret == NULL ) val_throw( (value)((vfunction*)f)->module ); } else if( val_short_tag(f) == VAL_FUNCTION ) { if( nargs == ((vfunction*)f)->nargs ) { int n; if( vm->csp + 4 >= vm->sp - nargs && !neko_stack_expand(vm->sp,vm->csp,vm) ) { if( exc ) { neko_process_trap(vm); memcpy(&vm->start,&oldjmp,sizeof(jmp_buf)); } failure("Stack Overflow"); } else { for(n=0;nsp = (int_val)args[n]; vm->env = ((vfunction*)f)->env; if( val_tag(f) == VAL_FUNCTION ) { *++vm->csp = (int_val)callback_return; *++vm->csp = 0; *++vm->csp = 0; *++vm->csp = 0; ret = neko_interp(vm,((vfunction*)f)->module,(int_val)val_null,(int_val*)((vfunction*)f)->addr); } else { neko_module *m = (neko_module*)((vfunction*)f)->module; ret = ((jit_prim)jit_boot_seq)(vm,((vfunction*)f)->addr,val_null,m); } } } else val_throw(alloc_string("Invalid call")); } else val_throw(alloc_string("Invalid call")); if( exc ) { neko_process_trap(vm); memcpy(&vm->start,&oldjmp,sizeof(jmp_buf)); } vm->vthis = old_this; vm->env = old_env; return ret; } EXTERN value val_callN( value f, value *args, int nargs ) { return val_callEx(NULL,f,args,nargs,NULL); } EXTERN value val_ocallN( value o, field f, value *args, int nargs ) { return val_callEx(o,val_field(o,f),args,nargs,NULL); } EXTERN value val_call0( value f ) { return val_callN(f,NULL,0); } EXTERN value val_call1( value f, value v ) { return val_callN(f,&v,1); } EXTERN value val_call2( value f, value v1, value v2 ) { value args[2] = { v1, v2 }; return val_callN(f,args,2); } EXTERN value val_call3( value f, value arg1, value arg2, value arg3 ) { value args[3] = { arg1, arg2, arg3 }; return val_callN(f,args,3); } EXTERN value val_ocall0( value o, field f ) { return val_ocallN(o,f,NULL,0); } EXTERN value val_ocall1( value o, field f, value arg ) { return val_ocallN(o,f,&arg,1); } EXTERN value val_ocall2( value o, field f, value arg1, value arg2 ) { value args[2] = { arg1, arg2 }; return val_ocallN(o,f,args,2); } EXTERN value val_this() { return (value)NEKO_VM()->vthis; } /* ************************************************************************ */ neko-2.0.0/vm/neko_vm.h0000644000175000017500000000526112112157473015411 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef _NEKO_VM_H #define _NEKO_VM_H #include "neko.h" typedef void (*neko_printer)( const char *data, int size, void *param ); typedef void (*thread_main_func)( void *param ); typedef struct _neko_vm neko_vm; typedef void (*neko_stat_func)( neko_vm *vm, const char *kind, int start ); C_FUNCTION_BEGIN EXTERN void neko_global_init(); EXTERN void neko_global_free(); EXTERN void neko_gc_major(); EXTERN void neko_gc_loop(); EXTERN void neko_gc_stats( int *heap, int *free ); EXTERN int neko_thread_create( thread_main_func init, thread_main_func main, void *param, void **handle ); EXTERN void neko_thread_blocking( thread_main_func f, void *p ); EXTERN bool neko_thread_register( bool t ); EXTERN neko_vm *neko_vm_alloc( void *unused ); EXTERN neko_vm *neko_vm_current(); EXTERN value neko_exc_stack( neko_vm *vm ); EXTERN value neko_call_stack( neko_vm *vm ); EXTERN void *neko_vm_custom( neko_vm *vm, vkind k ); EXTERN void neko_vm_set_custom( neko_vm *vm, vkind k, void *v ); EXTERN value neko_vm_execute( neko_vm *vm, void *module ); EXTERN void neko_vm_select( neko_vm *vm ); EXTERN int neko_vm_jit( neko_vm *vm, int enable_jit ); EXTERN int neko_vm_trusted( neko_vm *vm, int trusted ); EXTERN value neko_default_loader( char **argv, int argc ); EXTERN void neko_vm_redirect( neko_vm *vm, neko_printer print, void *param ); EXTERN void neko_vm_set_stats( neko_vm *vm, neko_stat_func fstats, neko_stat_func pstats ); EXTERN void neko_vm_dump_stack( neko_vm *vm ); EXTERN int neko_is_big_endian(); C_FUNCTION_END #endif /* ************************************************************************ */ neko-2.0.0/vm/builtins.c0000644000175000017500000007370412112157473015606 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include "neko.h" #include "objtable.h" #include "vm.h" #ifdef NEKO_MINGW # undef setjmp # define setjmp _setjmp #endif extern value *neko_builtins; DEFINE_KIND(neko_k_kind); DEFINE_KIND(k_old_int32); /**

Builtins

Builtins are basic operations that can be optimized by the Neko compiler.

**/ /**

Array Builtins

**/ /** $array : any* -> array Create an array from a list of values **/ static value builtin_array( value *args, int nargs ) { value a = alloc_array(nargs); int i; for(i=0;i array Create an array of size [n] **/ static value builtin_amake( value size ) { value a; int i,s; val_check(size,int); s = val_int(size); a = alloc_array(s); for(i=0;i array Make a copy of an array **/ static value builtin_acopy( value a ) { int i; value a2; val_check(a,array); a2 = alloc_array(val_array_size(a)); for(i=0;i int Return the size of an array **/ static value builtin_asize( value a ) { val_check(a,array); return alloc_int( val_array_size(a) ); } /** $asub : array -> p:int -> l:int -> array Return [l] elements starting at position [p] of an array. An error occurs if out of array bounds. **/ static value builtin_asub( value a, value p, value l ) { value a2; int i; int pp, ll; val_check(a,array); val_check(p,int); val_check(l,int); pp = val_int(p); ll = val_int(l); if( pp < 0 || ll < 0 || pp+ll < 0 || pp+ll > val_array_size(a) ) neko_error(); a2 = alloc_array(ll); for(i=0;i dst_pos:int -> src:array -> src_pos:int -> len:int -> void Copy [len] elements from [src_pos] of [src] to [dst_pos] of [dst]. An error occurs if out of arrays bounds. **/ static value builtin_ablit( value dst, value dp, value src, value sp, value l ) { int dpp, spp, ll; val_check(dst,array); val_check(dp,int); val_check(src,array); val_check(sp,int); val_check(l,int); dpp = val_int(dp); spp = val_int(sp); ll = val_int(l); if( dpp < 0 || spp < 0 || ll < 0 || dpp + ll < 0 || spp + ll < 0 || dpp + ll > val_array_size(dst) || spp + ll > val_array_size(src) ) neko_error(); memmove(val_array_ptr(dst)+dpp,val_array_ptr(src)+spp,ll * sizeof(value)); return val_null; } /** $aconcat : array array -> array Build a single array from several ones. **/ static value builtin_aconcat( value arrs ) { int tot = 0; int len; int i; value all; val_check(arrs,array); len = val_array_size(arrs); for(i=0;i

String Builtins

**/ /** $string : any -> string Convert any value to a string. This will make a copy of string. **/ static value builtin_string( value v ) { buffer b = alloc_buffer(NULL); val_buffer(b,v); return buffer_to_string(b); } /** $smake : n:int -> string Return an uninitialized string of size [n] **/ static value builtin_smake( value l ) { value v; val_check(l,int); v = alloc_empty_string( val_int(l) ); memset(val_string(v),0,val_int(l)); return v; } /** $ssize : string -> int Return the size of a string **/ static value builtin_ssize( value s ) { val_check(s,string); return alloc_int(val_strlen(s)); } /** $scopy : string -> string Make a copy of a string **/ static value builtin_scopy( value s ) { val_check(s,string); return copy_string( val_string(s), val_strlen(s) ); } /** $ssub : string -> p:int -> l:int -> string Return [l] chars starting at position [p] of a string. An error occurs if out of string bounds. **/ static value builtin_ssub( value s, value p, value l ) { int pp , ll; val_check(s,string); val_check(p,int); val_check(l,int); pp = val_int(p); ll = val_int(l); if( pp < 0 || ll < 0 || pp + ll < 0 || pp + ll > val_strlen(s) ) neko_error(); return copy_string( val_string(s) + pp , ll ); } /** $sget : string -> n:int -> int? Return the [n]th char of a string or [null] if out of bounds **/ static value builtin_sget( value s, value p ) { int pp; val_check(s,string); val_check(p,int); pp = val_int(p); if( pp < 0 || pp >= val_strlen(s) ) return val_null; return alloc_int( (unsigned char)(val_string(s)[pp]) ); } /** $sset : string -> n:int -> c:int -> int? Set the [n]th char of a string to ([c] & 255). Returns the char set or [null] if out of bounds. **/ static value builtin_sset( value s, value p, value c ) { int pp; unsigned char cc; val_check(s,string); val_check(p,int); val_check(c,int); pp = val_int(p); if( pp < 0 || pp >= val_strlen(s) ) return val_null; cc = (unsigned char)val_int(c); val_string(s)[pp] = (char)cc; return alloc_int(cc); } /** $sblit : dst:string -> dst_pos:int -> src:string -> src_pos:int -> len:int -> void Copy [len] chars from [src_pos] of [src] to [dst_pos] of [dst]. An error occurs if out of strings bounds. **/ static value builtin_sblit( value dst, value dp, value src, value sp, value l ) { int dpp, spp, ll; val_check(dst,string); val_check(dp,int); val_check(src,string); val_check(sp,int); val_check(l,int); dpp = val_int(dp); spp = val_int(sp); ll = val_int(l); if( dpp < 0 || spp < 0 || ll < 0 || dpp + ll < 0 || spp + ll < 0 || dpp + ll > val_strlen(dst) || spp + ll > val_strlen(src) ) neko_error(); memmove(val_string(dst)+dpp,val_string(src)+spp,ll); return val_null; } /** $sfind : src:string -> pos:int -> pat:string -> int? Return the first position starting at [pos] in [src] where [pat] was found. Return null if not found. Error if [pos] is outside [src] bounds. **/ static value builtin_sfind( value src, value pos, value pat ) { int p, l, l2; const char *ptr; val_check(src,string); val_check(pos,int); val_check(pat,string); p = val_int(pos); l = val_strlen(src); l2 = val_strlen(pat); if( p < 0 || p >= l ) neko_error(); ptr = val_string(src) + p; while( l - p >= l2 ) { if( memcmp(ptr,val_string(pat),l2) == 0 ) return alloc_int(p); p++; ptr++; } return val_null; } /**

Object Builtins

**/ /** $new : object? -> object Return a copy of the object or a new object if [null] **/ static value builtin_new( value o ) { if( !val_is_null(o) && !val_is_object(o) ) neko_error(); return alloc_object(o); } /** $objget : o:any -> f:int -> any Return the field [f] of [o] or [null] if doesn't exists or [o] is not an object **/ static value builtin_objget( value o, value f ) { if( !val_is_object(o) ) return val_null; // keep dot-access semantics val_check(f,int); return val_field(o,val_int(f)); } /** $objset : o:any -> f:int -> v:any -> any Set the field [f] of [o] to [v] and return [v] if [o] is an object or [null] if not **/ static value builtin_objset( value o, value f, value v ) { if( !val_is_object(o) ) return val_null; // keep dot-access semantics val_check(f,int); alloc_field(o,val_int(f),v); return v; } /** $objcall : o:any -> f:int -> args:array -> any Call the field [f] of [o] with [args] and return the value or [null] is [o] is not an object **/ static value builtin_objcall( value o, value f, value args ) { if( !val_is_object(o) ) return val_null; // keep dot-access semantics val_check(f,int); val_check(args,array); return val_ocallN(o,val_int(f),val_array_ptr(args),val_array_size(args)); } /** $objfield : o:any -> f:int -> bool Return true if [o] is an object which have field [f] **/ static value builtin_objfield( value o, value f ) { val_check(f,int); return alloc_bool( val_is_object(o) && otable_find(&((vobject*)o)->table, val_int(f)) != NULL ); } /** $objremove : o:object -> f:int -> bool Remove the field [f] from object [o]. Return [true] on success **/ static value builtin_objremove( value o, value f ) { val_check(o,object); val_check(f,int); return alloc_bool( otable_remove(&((vobject*)o)->table,val_int(f)) ); } static void builtin_objfields_rec( value d, field id, void *a ) { *((*(value**)a)++) = alloc_int((int)id); } /** $objfields : o:object -> int array Return all fields of the object **/ static value builtin_objfields( value o ) { value a; value *aptr; objtable *t; val_check(o,object); t = &((vobject*)o)->table; a = alloc_array(otable_count(t)); aptr = val_array_ptr(a); otable_iter(t,builtin_objfields_rec,&aptr); return a; } /** $hash : string -> int Return the hashed value of a field name **/ static value builtin_hash( value f ) { val_check(f,string); return alloc_int( (int)val_id(val_string(f)) ); } /** $fasthash : string -> int Return the hashed value of a field name, without accessing the cache **/ static value builtin_fasthash( value f ) { value acc = alloc_int(0); unsigned char *name; val_check(f,string); name = (unsigned char *)val_string(f); while( *name ) { acc = alloc_int(223 * val_int(acc) + *name); name++; } return acc; } /** $field : int -> string Reverse the hashed value of a field name. Return [null] on failure **/ static value builtin_field( value f ) { val_check(f,int); return val_field_name(val_int(f)); } /** $objsetproto : o:object -> proto:object? -> void Set the prototype of the object **/ static value builtin_objsetproto( value o, value p ) { val_check(o,object); if( val_is_null(p) ) ((vobject*)o)->proto = NULL; else { val_check(p,object); ((vobject*)o)->proto = (vobject*)p; } return val_null; } /** $objgetproto : o:object -> object? Get the prototype of the object **/ static value builtin_objgetproto( value o ) { val_check(o,object); o = (value)((vobject*)o)->proto; if( o == NULL ) return val_null; return o; } /**

Function Builtins

**/ /** $nargs : function -> int Return the number of arguments of a function. If the function have a variable number of arguments, it returns -1 **/ static value builtin_nargs( value f ) { val_check(f,function); return alloc_int( val_fun_nargs(f) ); } /** $call : f:function -> this:any -> args:array -> any Call [f] with [this] context and [args] arguments **/ static value builtin_call( value f, value ctx, value args ) { value old; value ret; neko_vm *vm; val_check(args,array); vm = NEKO_VM(); old = vm->vthis; vm->vthis = ctx; ret = val_callN(f,val_array_ptr(args),val_array_size(args)); vm->vthis = old; return ret; } static value closure_callback( value *args, int nargs ) { value env = NEKO_VM()->env; int cargs = val_array_size(env) - 2; value *a = val_array_ptr(env); value f = a[0]; value o = a[1]; int fargs = val_fun_nargs(f); int i; if( fargs != cargs + nargs && fargs != VAR_ARGS ) return val_null; if( nargs == 0 ) a = val_array_ptr(env) + 2; else if( cargs == 0 ) a = args; else { a = (value*)alloc(sizeof(value)*(nargs+cargs)); for(i=0;i object -> any* -> function Build a closure by applying a given number of arguments to a function **/ static value builtin_closure( value *args, int nargs ) { value f; value env; int fargs; if( nargs <= 1 ) failure("Invalid closure arguments number"); f = args[0]; if( !val_is_function(f) ) neko_error(); fargs = val_fun_nargs(f); if( fargs != VAR_ARGS && fargs < nargs-2 ) failure("Invalid closure arguments number"); env = alloc_array(nargs); memcpy(val_array_ptr(env),args,nargs * sizeof(f)); f = alloc_function( closure_callback, VAR_ARGS, "closure_callback" ); ((vfunction*)f)->env = env; return f; } /** $apply : function -> any* -> any Apply the function to several arguments. Return a function asking for more arguments or the function result if more args needed. **/ static value builtin_apply( value *args, int nargs ) { value f, env; int fargs; int i; nargs--; args++; if( nargs < 0 ) neko_error(); f = args[-1]; if( !val_is_function(f) ) neko_error(); if( nargs == 0 ) return f; fargs = val_fun_nargs(f); if( fargs == nargs || fargs == VAR_ARGS ) return val_callN(f,args,nargs); if( nargs > fargs ) neko_error(); env = alloc_array(fargs + 1); val_array_ptr(env)[0] = f; for(i=0;ienv; value a = alloc_array(nargs); int i; for(i=0;i function Return a variable argument function that, when called, will callback [f] with the array of arguments. **/ static value builtin_varargs( value f ) { value fvar; val_check_function(f,1); fvar = alloc_function(varargs_callback,VAR_ARGS,"varargs"); ((vfunction*)fvar)->env = f; return fvar; } /**

Number Builtins

**/ /** $iadd : any -> any -> int Add two integers **/ static value builtin_iadd( value a, value b ) { return alloc_best_int( val_any_int(a) + val_any_int(b) ); } /** $isub : any -> any -> int Subtract two integers **/ static value builtin_isub( value a, value b ) { return alloc_best_int( val_any_int(a) - val_any_int(b) ); } /** $imult : any -> any -> int Multiply two integers **/ static value builtin_imult( value a, value b ) { return alloc_best_int( val_any_int(a) * val_any_int(b) ); } /** $idiv : any -> any -> int Divide two integers. An error occurs if division by 0 **/ static value builtin_idiv( value a, value b ) { if( val_any_int(b) == 0 ) neko_error(); return alloc_best_int( val_any_int(a) / val_any_int(b) ); } typedef union { double d; struct { unsigned int l; unsigned int h; } i; } qw; /** $isnan : any -> bool Return if a value is the float NaN **/ static value builtin_isnan( value f ) { qw q; unsigned int h, l; if( !val_is_float(f) ) return val_false; q.d = val_float(f); h = q.i.h; l = q.i.l; l = l | (h & 0xFFFFF); h = h & 0x7FF00000; return alloc_bool( h == 0x7FF00000 && l != 0 ); } /** $isinfinite : any -> bool Return if a value is the float +Infinite **/ static value builtin_isinfinite( value f ) { qw q; unsigned int h, l; if( !val_is_float(f) ) return val_false; q.d = val_float(f); h = q.i.h; l = q.i.l; l = l | (h & 0xFFFFF); h = h & 0x7FF00000; return alloc_bool( h == 0x7FF00000 && l == 0 ); } /** $int : any -> int? Convert the value to the corresponding integer or return [null] **/ static value builtin_int( value f ) { switch( val_type(f) ) { case VAL_FLOAT: #ifdef NEKO_WINDOWS return alloc_best_int((int)val_float(f)); #else // in case of overflow, the result is unspecified by ISO // so we have to make a module 2^32 before casting to int return alloc_int((unsigned int)fmod(val_float(f),4294967296.0)); #endif case VAL_STRING: { char *c = val_string(f), *end; int h; if( val_strlen(f) >= 2 && c[0] == '0' && (c[1] == 'x' || c[1] == 'X') ) { h = 0; c += 2; while( *c ) { char k = *c++; if( k >= '0' && k <= '9' ) h = (h << 4) | (k - '0'); else if( k >= 'A' && k <= 'F' ) h = (h << 4) | ((k - 'A') + 10); else if( k >= 'a' && k <= 'f' ) h = (h << 4) | ((k - 'a') + 10); else return val_null; } return alloc_best_int(h); } h = strtol(c,&end,10); return ( c == end ) ? val_null : alloc_best_int(h); } case VAL_INT: case VAL_INT32: return f; } return val_null; } /** $float : any -> float? Convert the value to the corresponding float or return [null] **/ static value builtin_float( value f ) { if( val_is_string(f) ) { char *c = val_string(f), *end; tfloat f = (tfloat)strtod(c,&end); return (c == end) ? val_null : alloc_float(f); } if( val_is_number(f) ) return alloc_float( val_number(f) ); return val_null; } /**

Abstract Builtins

**/ /** $getkind : 'abstract -> 'kind Returns the kind value of the abstract **/ static value builtin_getkind( value v ) { if( val_is_int32(v) ) return alloc_abstract(neko_k_kind,k_old_int32); val_check(v,abstract); return alloc_abstract(neko_k_kind,val_kind(v)); } /** $iskind : any -> 'kind -> bool Tells if a value is of the given kind **/ static value builtin_iskind( value v, value k ) { val_check_kind(k,neko_k_kind); return val_is_abstract(v) ? alloc_bool(val_kind(v) == (vkind)val_data(k)) : (val_data(k) == k_old_int32 ? alloc_bool(val_is_int32(v)) : val_false); } /**

Hashtable Builtins

**/ /** $hkey : any -> int Return the hash of any value **/ static value builtin_hkey( value v ) { return alloc_int(val_hash(v)); } #define HASH_DEF_SIZE 7 /** $hnew : s:int -> 'hash Create an hashtable with [s] slots **/ static value builtin_hnew( value size ) { vhash *h; int i; val_check(size,int); h = (vhash*)alloc(sizeof(vhash)); h->nitems = 0; h->ncells = val_int(size); if( h->ncells <= 0 ) h->ncells = HASH_DEF_SIZE; h->cells = (hcell**)alloc(sizeof(hcell*)*h->ncells); for(i=0;incells;i++) h->cells[i] = NULL; return alloc_abstract(k_hash,h); } static void add_rec( hcell **cc, int size, hcell *c ) { int k; if( c == NULL ) return; add_rec(cc,size,c->next); k = c->hkey % size; c->next = cc[k]; cc[k] = c; } /** $hresize : 'hash -> int -> void Resize an hashtable **/ static value builtin_hresize( value vh, value size ) { vhash *h; hcell **cc; int nsize; int i; val_check_kind(vh,k_hash); val_check(size,int); h = val_hdata(vh); nsize = val_int(size); if( nsize <= 0 ) nsize = HASH_DEF_SIZE; cc = (hcell**)alloc(sizeof(hcell*)*nsize); memset(cc,0,sizeof(hcell*)*nsize); for(i=0;incells;i++) add_rec(cc,nsize,h->cells[i]); h->cells = cc; h->ncells = nsize; return val_null; } /** $hget : 'hash -> k:any -> cmp:function:2? -> any Look for the value bound to the key [k] in the hashtable. Use the comparison function [cmp] or [$compare] if [null]. Return [null] if no value is found. **/ static value builtin_hget( value vh, value key, value cmp ) { vhash *h; hcell *c; if( !val_is_null(cmp) ) val_check_function(cmp,2); val_check_kind(vh,k_hash); h = val_hdata(vh); c = h->cells[val_hash(key) % h->ncells]; if( val_is_null(cmp) ) { while( c != NULL ) { if( val_compare(key,c->key) == 0 ) return c->val; c = c->next; } } else { while( c != NULL ) { if( val_call2(cmp,key,c->key) == alloc_int(0) ) return c->val; c = c->next; } } return val_null; } /** $hmem : 'hash -> k:any -> cmp:function:2? -> bool Look for the value bound to the key [k] in the hashtable. Use the comparison function [cmp] or [$compare] if [null]. Return true if such value exists, false either. **/ static value builtin_hmem( value vh, value key, value cmp ) { vhash *h; hcell *c; if( !val_is_null(cmp) ) val_check_function(cmp,2); val_check_kind(vh,k_hash); h = val_hdata(vh); c = h->cells[val_hash(key) % h->ncells]; if( val_is_null(cmp) ) { while( c != NULL ) { if( val_compare(key,c->key) == 0 ) return val_true; c = c->next; } } else { while( c != NULL ) { if( val_call2(cmp,key,c->key) == alloc_int(0) ) return val_true; c = c->next; } } return val_false; } /** $hremove : 'hash -> k:any -> cmp:function:2? -> bool Look for the value bound to the key [k] in the hashtable. Use the comparison function [cmp] or [$compare] if [null]. Return true if such value exists and remove it from the hash, false either. **/ static value builtin_hremove( value vh, value key, value cmp ) { vhash *h; hcell *c, *prev = NULL; int hkey; if( !val_is_null(cmp) ) val_check_function(cmp,2); val_check_kind(vh,k_hash); h = val_hdata(vh); hkey = val_hash(key) % h->ncells; c = h->cells[hkey]; if( val_is_null(cmp) ) { while( c != NULL ) { if( val_compare(key,c->key) == 0 ) { if( prev == NULL ) h->cells[hkey] = c->next; else prev->next = c->next; h->nitems--; return val_true; } prev = c; c = c->next; } } else { while( c != NULL ) { if( val_call2(cmp,key,c->key) == alloc_int(0) ) { if( prev == NULL ) h->cells[hkey] = c->next; else prev->next = c->next; h->nitems--; return val_true; } prev = c; c = c->next; } } return val_false; } /** $hset : 'hash -> k:any -> v:any -> cmp:function:2? -> bool Set the value bound to key [k] to [v] or add it to the hashtable if not found. Return true if the value was added to the hashtable. **/ static value builtin_hset( value vh, value key, value val, value cmp ) { vhash *h; hcell *c; int hkey; if( !val_is_null(cmp) ) val_check_function(cmp,2); val_check_kind(vh,k_hash); h = val_hdata(vh); hkey = val_hash(key); c = h->cells[hkey % h->ncells]; if( val_is_null(cmp) ) { while( c != NULL ) { if( val_compare(key,c->key) == 0 ) { c->val = val; return val_false; } c = c->next; } } else { while( c != NULL ) { if( val_call2(cmp,key,c->key) == alloc_int(0) ) { c->val = val; return val_false; } c = c->next; } } if( h->nitems >= (h->ncells << 1) ) builtin_hresize(vh,alloc_int(h->ncells << 1)); c = (hcell*)alloc(sizeof(hcell)); c->hkey = hkey; c->key = key; c->val = val; hkey %= h->ncells; c->next = h->cells[hkey]; h->cells[hkey] = c; h->nitems++; return val_true; } /** $hadd : 'hash -> k:any -> v:any -> void Add the value [v] with key [k] to the hashtable. Previous binding is masked but not removed. **/ static value builtin_hadd( value vh, value key, value val ) { vhash *h; hcell *c; int hkey; val_check_kind(vh,k_hash); h = val_hdata(vh); hkey = val_hash(key); if( hkey < 0 ) neko_error(); if( h->nitems >= (h->ncells << 1) ) builtin_hresize(vh,alloc_int(h->ncells << 1)); c = (hcell*)alloc(sizeof(hcell)); c->hkey = hkey; c->key = key; c->val = val; hkey %= h->ncells; c->next = h->cells[hkey]; h->cells[hkey] = c; h->nitems++; return val_null; } /** $hiter : 'hash -> f:function:2 -> void Call the function [f] with every key and value in the hashtable **/ static value builtin_hiter( value vh, value f ) { int i; hcell *c; vhash *h; val_check_function(f,2); val_check_kind(vh,k_hash); h = val_hdata(vh); for(i=0;incells;i++) { c = h->cells[i]; while( c != NULL ) { val_call2(f,c->key,c->val); c = c->next; } } return val_null; } /** $hcount : 'hash -> int Return the number of elements in the hashtable **/ static value builtin_hcount( value vh ) { val_check_kind(vh,k_hash); return alloc_int( val_hdata(vh)->nitems ); } /** $hsize : 'hash -> int Return the size of the hashtable **/ static value builtin_hsize( value vh ) { val_check_kind(vh,k_hash); return alloc_int( val_hdata(vh)->ncells ); } /**

Other Builtins

**/ /** $print : any* -> void Can print any value **/ static value builtin_print( value *args, int nargs ) { buffer b; int i; if( nargs == 1 && val_is_string(*args) ) { val_print(*args); return neko_builtins[1]; } b = alloc_buffer(NULL); for(i=0;i any Throw any value as an exception. Never returns **/ static value builtin_throw( value v ) { val_throw(v); return val_null; } /** $rethrow : any -> any Throw any value as an exception while keeping previous exception stack. Never returns **/ static value builtin_rethrow( value v ) { val_rethrow(v); return val_null; } /** $istrue : v:any -> bool Return true if [v] is not [false], not [null] and not 0 **/ static value builtin_istrue( value f ) { return alloc_bool(f != val_false && f != val_null && f != alloc_int(0) && (val_is_int(f) || val_tag(f) != VAL_INT32 || val_int32(f) != 0)); } /** $not : any -> bool Return true if [v] is [false] or [null] or [0] **/ static value builtin_not( value f ) { return alloc_bool(f == val_false || f == val_null || f == alloc_int(0) || (!val_is_int(f) && val_tag(f) == VAL_INT32 && val_int32(f) == 0)); } /** $typeof : any -> int Return the type of a value. The following builtins are defined :
  • [$tnull] = 0
  • [$tint] = 1
  • [$tfloat] = 2
  • [$tbool] = 3
  • [$tstring] = 4
  • [$tobject] = 5
  • [$tarray] = 6
  • [$tfunction] = 7
  • [$tabstract] = 8
**/ static value builtin_typeof( value v ) { switch( val_type(v) ) { case VAL_INT: case VAL_INT32: return alloc_int(1); case VAL_NULL: return alloc_int(0); case VAL_FLOAT: return alloc_int(2); case VAL_BOOL: return alloc_int(3); case VAL_STRING: return alloc_int(4); case VAL_OBJECT: return alloc_int(5); case VAL_ARRAY: return alloc_int(6); case VAL_FUNCTION: return alloc_int(7); case VAL_ABSTRACT: return alloc_int(8); default: neko_error(); } } /** $compare : any -> any -> int? Compare two values and return 1, -1 or 0. Return [null] if comparison is not possible **/ static value builtin_compare( value a, value b ) { int r = val_compare(a,b); return (r == invalid_comparison)?val_null:alloc_int(r); } /** $pcompare : any -> any -> int Physically compare two values. Same as [$compare] for integers. **/ static value builtin_pcompare( value a, value b ) { int_val ia = (int_val)a; int_val ib = (int_val)b; if( ia > ib ) return alloc_int(1); else if( ia < ib ) return alloc_int(-1); else return alloc_int(0); } /** $excstack : void -> array Return the stack between the place the last exception was raised and the place it was catched. The stack is composed of the following items :
  • [null] when it's a C function
  • a string when it's a module without debug informations
  • an array of two elements (usually file and line) if debug informations where available
**/ static value builtin_excstack() { return NEKO_VM()->exc_stack; } /** $callstack : void -> array Return the current callstack. Same format as [$excstack] **/ static value builtin_callstack() { return neko_call_stack(NEKO_VM()); } /** $version : void -> int Return the version of Neko : 135 means 1.3.5 **/ static value builtin_version() { return alloc_int(NEKO_VERSION); } /** $setresolver : function:2? -> void Set a function to callback with object and field id when an object field is not found. **/ static value builtin_setresolver( value f ) { neko_vm *vm = NEKO_VM(); if( val_is_null(f) ) vm->resolver = NULL; else { val_check_function(f,2); vm->resolver = f; } return val_null; } #define BUILTIN(name,nargs) \ alloc_field(neko_builtins[0],val_id(#name),alloc_function(builtin_##name,nargs,"$" #name)); void neko_init_builtins() { neko_builtins = alloc_root(2); neko_builtins[0] = alloc_object(NULL); neko_builtins[1] = alloc_function(builtin_print,VAR_ARGS,"$print"); BUILTIN(print,VAR_ARGS); BUILTIN(array,VAR_ARGS); BUILTIN(amake,1); BUILTIN(acopy,1); BUILTIN(asize,1); BUILTIN(asub,3); BUILTIN(ablit,5); BUILTIN(aconcat,1); BUILTIN(smake,1); BUILTIN(ssize,1); BUILTIN(scopy,1); BUILTIN(ssub,3); BUILTIN(sget,2); BUILTIN(sset,3); BUILTIN(sblit,5); BUILTIN(sfind,3); BUILTIN(new,1); BUILTIN(objget,2); BUILTIN(objset,3); BUILTIN(objcall,3); BUILTIN(objfield,2); BUILTIN(objremove,2); BUILTIN(objfields,1); BUILTIN(hash,1); BUILTIN(fasthash,1); BUILTIN(field,1); BUILTIN(objsetproto,2); BUILTIN(objgetproto,1); BUILTIN(int,1); BUILTIN(float,1); BUILTIN(string,1); BUILTIN(typeof,1); BUILTIN(closure,VAR_ARGS); BUILTIN(apply,VAR_ARGS); BUILTIN(varargs,1); BUILTIN(compare,2); BUILTIN(pcompare,2); BUILTIN(not,1); BUILTIN(throw,1); BUILTIN(rethrow,1); BUILTIN(nargs,1); BUILTIN(call,3); BUILTIN(isnan,1); BUILTIN(isinfinite,1); BUILTIN(istrue,1); BUILTIN(getkind,1); BUILTIN(iskind,2); BUILTIN(hnew,1); BUILTIN(hget,3); BUILTIN(hmem,3); BUILTIN(hset,4); BUILTIN(hadd,3); BUILTIN(hremove,3); BUILTIN(hresize,2); BUILTIN(hkey,1); BUILTIN(hcount,1); BUILTIN(hsize,1); BUILTIN(hiter,2); BUILTIN(iadd,2); BUILTIN(isub,2); BUILTIN(imult,2); BUILTIN(idiv,2); BUILTIN(excstack,0); BUILTIN(callstack,0); BUILTIN(version,0); BUILTIN(setresolver,1); } /* ************************************************************************ */ neko-2.0.0/vm/module.c0000644000175000017500000003524312112157473015236 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include "neko_mod.h" #include "vm.h" #define PARAMETER_TABLE #define STACK_TABLE #include "opcodes.h" DEFINE_KIND(neko_kind_module); /* Endianness macros. */ #ifdef NEKO_BSD # include #endif #ifndef LITTLE_ENDIAN # define LITTLE_ENDIAN 1 #endif #ifndef BIG_ENDIAN # define BIG_ENDIAN 2 #endif #ifdef NEKO_WINDOWS # define BYTE_ORDER LITTLE_ENDIAN #endif #ifndef BYTE_ORDER # warning BYTE_ORDER unknown, assuming BIG_ENDIAN # define BYTE_ORDER BIG_ENDIAN #endif /* *_TO_LE(X) converts (X) to little endian. */ #if BYTE_ORDER == LITTLE_ENDIAN # define LONG_TO_LE(X) (X) # define SHORT_TO_LE(X) (X) #else # define LONG_TO_LE(X) ((((X) >> 24) & 0xff) | \ (((X) >> 8) & 0xff00) | (((X) & 0xff00) << 8) | \ (((X) & 0xff) << 24)) # define SHORT_TO_LE(X) ((((X) >> 8) & 0xff) | (((X) & 0xff) << 8)) #endif #define MAXSIZE 0x100 #define ERROR() { free(tmp); return NULL; } #define READ(buf,len) if( r(p,buf,len) == -1 ) ERROR() #ifdef NEKO_64BITS static void read_long( reader r, readp p, unsigned int *i ) { unsigned char c[4]; int n; r(p,c,4); n = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); *i = LONG_TO_LE(n); } static void read_short( reader r, readp p, unsigned short *i ) { unsigned char c[2]; int n; r(p,c,2); n = c[0] | (c[1] << 8); *i = SHORT_TO_LE(n); } # define READ_LONG(var) read_long(r,p,&(var)) # define READ_SHORT(var) read_short(r,p,&(var)) #else # define READ_LONG(var) READ(&(var), 4); var = LONG_TO_LE(var) # define READ_SHORT(var) READ(&(var), 2); var = SHORT_TO_LE(var) #endif extern field id_loader; extern field id_exports; extern value *neko_builtins; extern value neko_alloc_module_function( void *m, int_val pos, int nargs ); extern void neko_module_jit( neko_module *m ); EXTERN int neko_is_big_endian() { #if BYTE_ORDER == LITTLE_ENDIAN return 0; #else return 1; #endif } static int read_string( reader r, readp p, char *buf ) { int i = 0; char c; while( i < MAXSIZE ) { if( r(p,&c,1) == -1 ) return -1; buf[i++] = c; if( c == 0 ) return i; } return -1; } static value get_builtin( neko_module *m, field id ) { value f = val_field(*neko_builtins,id); if( val_is_null(f) ) { unsigned int i; for(i=0;infields;i++) if( val_id(val_string(m->fields[i])) == id ) { buffer b = alloc_buffer("Builtin not found : "); val_buffer(b,m->fields[i]); bfailure(b); } failure("Builtin not found"); } return f; } #define UNKNOWN ((unsigned char)-1) static int neko_check_stack( neko_module *m, unsigned char *tmp, unsigned int i, int stack, int istack ) { unsigned int itmp; while( true ) { int c = (int)m->code[i]; int s = stack_table[c]; if( tmp[i] == UNKNOWN ) tmp[i] = stack; else if( tmp[i] != stack ) return 0; else return 1; if( s == P ) stack += (int)m->code[i+1]; else if( s == -P ) stack -= (int)m->code[i+1]; else stack += s; // 4 because it's the size of a push-infos needed in case of subcall if( stack < istack || stack >= MAX_STACK_PER_FUNCTION - 4 ) return 0; switch( c ) { case Jump: case JumpIf: case JumpIfNot: case Trap: itmp = (int)(((int_val*)m->code[i+1]) - m->code); if( tmp[itmp] == UNKNOWN ) { if( c == Trap ) stack -= s; if( !neko_check_stack(m,tmp,itmp,stack,istack) ) return 0; if( c == Trap ) stack += s; } else if( tmp[itmp] != stack ) return 0; if( c == Jump ) return 1; break; case JumpTable: itmp = (int)m->code[i+1]; i += itmp; while( itmp > 0 ) { itmp -= 2; if( m->code[i - itmp] != Jump ) return 0; if( !neko_check_stack(m,tmp,i - itmp,stack,istack) ) return 0; } break; case AccStack: case SetStack: if( m->code[i+1] >= stack ) return 0; break; case AccStack0: if( 0 >= stack ) return 0; break; case AccStack1: if( 1 >= stack ) return 0; break; case Last: if( stack != 0 ) return 0; return 1; case Ret: if( m->code[i+1] != stack ) return 0; return 1; case ObjCall: stack--; if( stack < istack ) return 0; break; case TailCall: if( stack - (m->code[i+1] & 7) < istack || (m->code[i+1]>>3) != stack ) return 0; return 1; } i += parameter_table[c]?2:1; } return 1; } static void append_array( value *arr, int pos, value v ) { int len = val_array_size(*arr); if( pos >= len ) { value a2 = alloc_array((len * 3) / 2); memcpy(val_array_ptr(a2),val_array_ptr(*arr),len * sizeof(value)); *arr = a2; } val_array_ptr(*arr)[pos] = v; } #define SETBIT(b) { \ if( (i & 31) == 0 ) { \ bits++; \ bits->base = pos_index; \ bits->bits = 0; \ } else \ bits->bits |= b << (31 - (i & 31)); \ i++; \ } static void *read_debug_infos( reader r, readp p, char *tmp, neko_module *m ) { unsigned int i; int curline = 0; value curfile; unsigned int npos; unsigned int nfiles; unsigned char c,c2; value files; value positions, pp; neko_debug *bits; int pos_index = -1; int lot_of_files = 0; READ(&c,1); if( c >= 0x80 ) { READ(&c2,1); nfiles = ((c & 0x7F) << 8) | c2; lot_of_files = 1; } else nfiles = c; if( nfiles == 0 ) ERROR(); files = alloc_array(nfiles); for(i=0;icodesize ) ERROR(); curfile = val_array_ptr(files)[0]; positions = alloc_array(2 + (npos / 20)); bits = (neko_debug *)alloc_private(sizeof(neko_debug) * ((npos + 31) >> 5)); m->dbgidxs = bits; bits--; i = 0; pp = NULL; while( i < npos ) { READ(&c,1); if( c & 1 ) { c >>= 1; if( lot_of_files ) { READ(&c2,1); nfiles = (c << 8) | c2; } else nfiles = c; if( nfiles >= (unsigned int)val_array_size(files) ) ERROR(); curfile = val_array_ptr(files)[nfiles]; pp = NULL; } else if( c & 2 ) { int delta = c >> 6; int count = (c >> 2) & 15; if( i + count > npos ) ERROR(); if( pp == NULL ) { pp = alloc_array(2); val_array_ptr(pp)[0] = curfile; val_array_ptr(pp)[1] = alloc_int(curline); append_array(&positions,++pos_index,pp); SETBIT(1); count--; } while( count-- ) SETBIT(0); if( delta ) { curline += delta; pp = NULL; } } else if( c & 4 ) { curline += c >> 3; pp = alloc_array(2); val_array_ptr(pp)[0] = curfile; val_array_ptr(pp)[1] = alloc_int(curline); append_array(&positions,++pos_index,pp); SETBIT(1); } else { unsigned char b2; unsigned char b3; READ(&b2,1); READ(&b3,1); curline = (c >> 3) | (b2 << 5) | (b3 << 13); pp = alloc_array(2); val_array_ptr(pp)[0] = curfile; val_array_ptr(pp)[1] = alloc_int(curline); append_array(&positions,++pos_index,pp); SETBIT(1); } } // table copy pos_index++; m->dbgtbl = alloc_array(pos_index); memcpy(val_array_ptr(m->dbgtbl),val_array_ptr(positions),pos_index * sizeof(value)); return m; } neko_module *neko_read_module( reader r, readp p, value loader ) { register unsigned int i; unsigned int itmp; unsigned char t; unsigned short stmp; register char *tmp = NULL; unsigned char version = 1; register neko_module *m = (neko_module*)alloc(sizeof(neko_module)); neko_vm *vm = NEKO_VM(); READ_LONG(itmp); if( itmp != 0x4F4B454E ) ERROR(); READ_LONG(m->nglobals); READ_LONG(m->nfields); READ_LONG(m->codesize); if( m->nglobals < 0 || m->nglobals > 0xFFFF || m->nfields < 0 || m->nfields > 0xFFFF || m->codesize < 0 || m->codesize > 0xFFFFF ) ERROR(); tmp = (char*)malloc(sizeof(char)*(((m->codesize+1)>MAXSIZE)?(m->codesize+1):MAXSIZE)); m->jit = NULL; m->jit_gc = NULL; m->dbgtbl = val_null; m->dbgidxs = NULL; m->globals = (value*)alloc(m->nglobals * sizeof(value)); m->fields = (value*)alloc(sizeof(value*)*m->nfields); m->loader = loader; m->exports = alloc_object(NULL); if( vm->fstats ) vm->fstats(vm,"neko_read_module_data",1); alloc_field(m->exports,neko_id_module,alloc_abstract(neko_kind_module,m)); // Init global table for(i=0;inglobals;i++) { READ(&t,1); switch( t ) { case 1: if( read_string(r,p,tmp) == -1 ) ERROR(); m->globals[i] = val_null; break; case 2: READ_LONG(itmp); if( (itmp & 0xFFFFFF) >= m->codesize ) ERROR(); m->globals[i] = neko_alloc_module_function(m,(itmp&0xFFFFFF),(itmp >> 24)); break; case 3: READ_SHORT(stmp); m->globals[i] = alloc_empty_string(stmp); READ(val_string(m->globals[i]),stmp); break; case 4: if( read_string(r,p,tmp) == -1 ) ERROR(); m->globals[i] = alloc_float( atof(tmp) ); break; case 5: if( !read_debug_infos(r,p,tmp,m) ) { tmp = NULL; // already free in read_debug_infos ERROR(); } m->globals[i] = val_null; break; case 6: READ(&version,1); m->globals[i] = val_null; break; default: ERROR(); break; } } for(i=0;infields;i++) { if( read_string(r,p,tmp) == -1 ) ERROR(); m->fields[i] = alloc_string(tmp); } if( vm->fstats ) { vm->fstats(vm,"neko_read_module_data",0); vm->fstats(vm,"neko_read_module_code",1); } #ifdef NEKO_PROF if( m->codesize >= PROF_SIZE ) ERROR(); m->code = (int_val*)alloc_private(sizeof(int_val)*(m->codesize+PROF_SIZE)); memset(m->code+PROF_SIZE,0,m->codesize*sizeof(int_val)); #else m->code = (int_val*)alloc_private(sizeof(int_val)*(m->codesize+1)); #endif i = 0; // Unpack opcodes while( i < m->codesize ) { READ(&t,1); tmp[i] = 1; switch( t & 3 ) { case 0: m->code[i++] = (t >> 2); break; case 1: m->code[i++] = (t >> 3); tmp[i] = 0; m->code[i++] = (t >> 2) & 1; break; case 2: m->code[i++] = (t >> 2); if( t == 2 ) { // extra opcodes READ(&t,1); m->code[i-1] = t; } else { READ(&t,1); tmp[i] = 0; m->code[i++] = t; } break; case 3: m->code[i++] = (t >> 2); READ_LONG(itmp); tmp[i] = 0; m->code[i++] = (int)itmp; break; } } tmp[i] = 1; m->code[i] = Last; if( vm->fstats ) { vm->fstats(vm,"neko_read_module_code",0); vm->fstats(vm,"neko_read_module_check",1); } // Check bytecode for(i=0;icodesize;i++) { register int c = (int)m->code[i]; itmp = (unsigned int)m->code[i+1]; if( c >= Last || tmp[i+1] == parameter_table[c] ) ERROR(); // Additional checks and optimizations switch( m->code[i] ) { case AccGlobal: case SetGlobal: if( itmp >= m->nglobals ) ERROR(); m->code[i+1] = (int_val)(m->globals + itmp); break; case Jump: case JumpIf: case JumpIfNot: case Trap: itmp += i; if( itmp > m->codesize || !tmp[itmp] ) ERROR(); m->code[i+1] = (int_val)(m->code + itmp); break; case AccInt: if( need_32_bits((int)itmp) ) m->code[i] = AccInt32; else m->code[i+1] = (int_val)alloc_int((int)itmp); break; case AccIndex: m->code[i+1] += 2; break; case AccStack: m->code[i+1] += 2; itmp = (unsigned int)m->code[i+1]; case SetStack: if( ((int)itmp) < 0 ) ERROR(); break; case Ret: case Pop: case AccEnv: case SetEnv: if( ((int)itmp) < 0 ) ERROR(); break; case AccBuiltin: { field f = (field)(int_val)itmp; if( f == id_loader ) m->code[i+1] = (int_val)loader; else if( f == id_exports ) m->code[i+1] = (int_val)m->exports; else m->code[i+1] = (int_val)get_builtin(m,f); } break; case Call: case ObjCall: if( itmp > CALL_MAX_ARGS ) ERROR(); break; case TailCall: if( (itmp&7) > CALL_MAX_ARGS ) ERROR(); break; case Apply: if( itmp == 0 || itmp >= CALL_MAX_ARGS ) ERROR(); break; case MakeEnv: if( itmp > 0xFF ) failure("Too much big environment"); break; case MakeArray: if( itmp > 0x10000 ) failure("Too much big array"); if( version >= 2 ) m->code[i] = MakeArray2; break; case JumpTable: if( itmp > 512 || i + 1 + itmp * 2 >= m->codesize ) ERROR(); m->code[i+1] <<= 1; break; } if( !tmp[i+1] ) i++; } // Check stack preservation { unsigned char *stmp = (unsigned char*)malloc(m->codesize+1); unsigned int prev = 0; memset(stmp,UNKNOWN,m->codesize+1); if( !vm->trusted_code && !neko_check_stack(m,stmp,0,0,0) ) { free(stmp); ERROR(); } for(i=0;inglobals;i++) { vfunction *f = (vfunction*)m->globals[i]; if( val_type(f) == VAL_FUNCTION ) { itmp = (unsigned int)(int_val)f->addr; if( itmp >= m->codesize || !tmp[itmp] || itmp < prev ) { free(stmp); ERROR(); } if( !vm->trusted_code && !neko_check_stack(m,stmp,itmp,f->nargs,f->nargs) ) { free(stmp); ERROR(); } f->addr = m->code + itmp; prev = itmp; } } free(stmp); } free(tmp); if( vm->fstats ) vm->fstats(vm,"neko_read_module_check",0); // jit ? if( vm->run_jit ) { if( vm->fstats ) vm->fstats(vm,"neko_read_module_jit",1); neko_module_jit(m); if( vm->fstats ) vm->fstats(vm,"neko_read_module_jit",0); } # ifdef NEKO_DIRECT_THREADED { int_val *jtbl = neko_get_ttable(); if( vm->fstats ) vm->fstats(vm,"neko_read_module_thread",1); for(i=0;i<=m->codesize;i++) { int_val c = m->code[i]; m->code[i] = jtbl[c]; i += parameter_table[c]; } if( vm->fstats ) vm->fstats(vm,"neko_read_module_thread",0); } # endif return m; } int neko_file_reader( readp p, void *buf, int size ) { int len = 0; while( size > 0 ) { int l; POSIX_LABEL(fread_again); l = (int)fread(buf,1,size,(FILE*)p); if( l <= 0 ) { HANDLE_FINTR((FILE*)p,fread_again); return len; } size -= l; len += l; buf = (char*)buf+l; } return len; } int neko_string_reader( readp p, void *buf, int size ) { string_pos *sp = (string_pos*)p; int delta = (sp->len >= size)?size:sp->len; memcpy(buf,sp->p,delta); sp->p += delta; sp->len -= delta; return delta; } /* ************************************************************************ */ neko-2.0.0/vm/load.c0000644000175000017500000002650412112157473014670 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include "vm.h" #include "neko_mod.h" #ifndef NEKO_WINDOWS # include #endif extern field id_cache; extern field id_path; extern field id_loader_libs; DEFINE_KIND(k_loader_libs); #ifdef NEKO_PROF typedef void (*callb)( const char *name, neko_module *m, int *tot ); typedef struct { callb callb; int tot; } dump_param; static void profile_total( const char *name, neko_module *m, int *tot ) { unsigned int i; unsigned int n = 0; for(i=0;icodesize;i++) n += (int)m->code[PROF_SIZE+i]; *tot += n; } static void profile_summary( const char *name, neko_module *m, int *ptr ) { unsigned int i; unsigned int tot = 0; for(i=0;icodesize;i++) tot += (int)m->code[PROF_SIZE+i]; printf("%10d %-4.1f%% %s\n",tot,(tot * 100.0f) / (*ptr),name); } static void profile_details( const char *name, neko_module *m, int *tot ) { unsigned int i; value *dbg = val_is_null(m->debuginf)?NULL:val_array_ptr(m->debuginf); printf("Details for : %s[%d]\n",name,m->codesize); for(i=0;icodesize;i++) { int c = (int)m->code[PROF_SIZE+i]; if( c > 0 ) { if( dbg ) val_print(dbg[i]); printf(" %-4X %d\n",i,c); } } printf("\n"); } static void profile_functions( const char *name, neko_module *m, int *tot ) { unsigned int i; value *dbg = val_is_null(m->debuginf)?NULL:val_array_ptr(m->debuginf); for(i=0;inglobals;i++) { value v = m->globals[i]; if( val_is_function(v) && val_type(v) == VAL_FUNCTION && ((vfunction*)v)->module == m ) { int pos = (int)(((int_val)((vfunction*)v)->addr - (int_val)m->code) / sizeof(int_val)); if( m->code[PROF_SIZE+pos] > 0 ) { printf("%-8d %-4d %-20s %X ",m->code[PROF_SIZE+pos],i,name,pos); if( dbg ) val_print(dbg[pos]); printf("\n"); } } } } static void dump_module( value v, field f, void *p ) { value vname; const char *name; if( !val_is_kind(v,neko_kind_module) ) return; vname = val_field_name(f); name = val_is_null(vname)?"???":val_string(vname); ((dump_param*)p)->callb( name, (neko_module*)val_data(v), &((dump_param*)p)->tot ); } static value dump_prof() { dump_param p; value o = val_this(); value cache; val_check(o,object); cache = val_field(o,id_cache); val_check(cache,object); p.tot = 0; p.callb = profile_total; val_iter_fields(cache,dump_module,&p); printf("Summary :\n"); p.callb = profile_summary; val_iter_fields(cache,dump_module,&p); printf("%10d\n\n",p.tot); printf("Functions :\n"); p.callb = profile_functions; val_iter_fields(cache,dump_module,&p); printf("\n"); p.callb = profile_details; val_iter_fields(cache,dump_module,&p); return val_true; } #endif #ifdef NEKO_WINDOWS # undef ERROR # include # define dlopen(l,p) (void*)LoadLibrary(l) # define dlsym(h,n) GetProcAddress((HANDLE)h,n) #endif EXTERN value neko_select_file( value path, const char *file, const char *ext ) { struct stat s; value ff; buffer b = alloc_buffer(file); buffer_append(b,ext); ff = buffer_to_string(b); if( stat(val_string(ff),&s) == 0 ) { char *p = strchr(file,'/'); if( p == NULL ) p = strchr(file,'\\'); if( p != NULL ) return ff; b = alloc_buffer("./"); buffer_append(b,file); buffer_append(b,ext); return buffer_to_string(b); } while( val_is_array(path) && val_array_size(path) == 2 ) { value p = val_array_ptr(path)[0]; buffer b = alloc_buffer(NULL); path = val_array_ptr(path)[1]; val_buffer(b,p); val_buffer(b,ff); p = buffer_to_string(b); if( stat(val_string(p),&s) == 0 ) return p; } return ff; } static void open_module( value path, const char *mname, reader *r, readp *p ) { FILE *f; value fname; char *ext = strrchr(mname,'.'); if( ext && ext[1] == 'n' && ext[2] == 0 ) fname = neko_select_file(path,mname,""); else fname = neko_select_file(path,mname,".n"); f = fopen(val_string(fname),"rb"); if( f == NULL ) { buffer b = alloc_buffer("Module not found : "); buffer_append(b,mname); bfailure(b); } *r = neko_file_reader; *p = f; } static void close_module( readp p ) { fclose(p); } typedef struct _liblist { char *name; void *handle; struct _liblist *next; } liblist; typedef value (*PRIM0)(); static void *load_primitive( const char *prim, int nargs, value path, liblist **libs ) { char *pos = strchr(prim,'@'); int len; liblist *l; PRIM0 ptr; if( pos == NULL ) return NULL; l = *libs; *pos = 0; len = (int)strlen(prim) + 1; # ifndef NEKO_STANDALONE while( l != NULL ) { if( memcmp(l->name,prim,len) == 0 ) break; l = l->next; } # endif if( l == NULL ) { void *h; value pname = pname = neko_select_file(path,prim,".ndll"); #ifdef NEKO_STANDALONE # ifdef NEKO_WINDOWS h = (void*)GetModuleHandle(NULL); # else h = dlopen(NULL,RTLD_LAZY); # endif #else h = dlopen(val_string(pname),RTLD_LAZY); #endif if( h == NULL ) { buffer b = alloc_buffer("Failed to load library : "); val_buffer(b,pname); #ifndef NEKO_WINDOWS buffer_append(b," ("); buffer_append(b,dlerror()); buffer_append(b,")"); #endif *pos = '@'; bfailure(b); } l = (liblist*)alloc(sizeof(liblist)); l->handle = h; l->name = alloc_private(len); memcpy(l->name,prim,len); l->next = *libs; *libs = l; ptr = (PRIM0)dlsym(l->handle,"__neko_entry_point"); if( ptr != NULL ) ((PRIM0)ptr())(); } *pos++ = '@'; { char buf[100]; if( strlen(pos) > 90 ) return NULL; if( nargs == VAR_ARGS ) sprintf(buf,"%s__MULT",pos); else sprintf(buf,"%s__%d",pos,nargs); ptr = (PRIM0)dlsym(l->handle,buf); if( ptr == NULL ) return NULL; return ptr(); } } static value init_path( const char *path ) { value l = val_null, tmp; char *p, *p2; char *allocated = NULL; #ifdef NEKO_WINDOWS char exe_path[MAX_PATH]; if( path == NULL ) { # ifdef NEKO_STANDALONE # define SELF_DLL NULL # else # define SELF_DLL "neko.dll" # endif if( GetModuleFileName(GetModuleHandle(SELF_DLL),exe_path,MAX_PATH) == 0 ) return val_null; p = strrchr(exe_path,'\\'); if( p == NULL ) return val_null; *p = 0; path = exe_path; } #else if( path == NULL ) { allocated = strdup("/usr/local/lib/neko:/usr/lib/neko:/usr/local/bin:/usr/bin"); path = allocated; } #endif while( true ) { // windows drive letter (same behavior expected on all os) if( *path && path[1] == ':' ) { p = strchr(path+2,':'); p2 = strchr(path+2,';'); } else { p = strchr(path,':'); p2 = strchr(path,';'); } if( p == NULL || (p2 != NULL && p2 < p) ) p = p2; if( p != NULL ) *p = 0; tmp = alloc_array(2); if( (p && p[-1] != '/' && p[-1] != '\\') || (!p && path[strlen(path)-1] != '/' && path[strlen(path)-1] != '\\') ) { buffer b = alloc_buffer(path); char c = '/'; buffer_append_sub(b,&c,1); val_array_ptr(tmp)[0] = buffer_to_string(b); } else val_array_ptr(tmp)[0] = alloc_string(path); val_array_ptr(tmp)[1] = l; l = tmp; if( p != NULL ) *p = (p == p2)?';':':'; else break; path = p+1; } if( allocated != NULL ) free(allocated); return l; } typedef value (*stats_callback)( value, value, value, value, value, value ); static value stats_proxy( value p1, value p2, value p3, value p4, value p5, value p6 ) { neko_vm *vm = NEKO_VM(); value env = vm->env; value ret; if( vm->pstats ) vm->pstats(vm,val_string(val_array_ptr(env)[0]),1); ret = ((stats_callback)((int_val)val_array_ptr(vm->env)[1]&~1))(p1,p2,p3,p4,p5,p6); if( vm->pstats ) vm->pstats(vm,val_string(val_array_ptr(env)[0]),0); return ret; } static value loader_loadprim( value prim, value nargs ) { value o = val_this(); value libs; val_check(o,object); val_check(prim,string); val_check(nargs,int); libs = val_field(o,id_loader_libs); val_check_kind(libs,k_loader_libs); if( val_int(nargs) >= 10 || val_int(nargs) < -1 ) neko_error(); { neko_vm *vm = NEKO_VM(); void *ptr = load_primitive(val_string(prim),val_int(nargs),val_field(o,id_path),(liblist**)(void*)&val_data(libs)); vfunction *f; if( ptr == NULL ) { buffer b = alloc_buffer("Primitive not found : "); val_buffer(b,prim); buffer_append(b,"("); val_buffer(b,nargs); buffer_append(b,")"); bfailure(b); } f = (vfunction*)alloc_function(ptr,val_int(nargs),val_string(copy_string(val_string(prim),val_strlen(prim)))); if( vm->pstats && val_int(nargs) <= 6 ) { value env = alloc_array(2); val_array_ptr(env)[0] = f->module; val_array_ptr(env)[1] = (value)(((int_val)f->addr) | 1); f->addr = stats_proxy; f->env = env; } return (value)f; } } static value loader_loadmodule( value mname, value vthis ) { value o = val_this(); value cache; val_check(o,object); val_check(mname,string); val_check(vthis,object); cache = val_field(o,id_cache); val_check(cache,object); { reader r; readp p; neko_module *m; neko_vm *vm = NEKO_VM(); field mid = val_id(val_string(mname)); value mv = val_field(cache,mid); if( val_is_kind(mv,neko_kind_module) ) { m = (neko_module*)val_data(mv); return m->exports; } open_module(val_field(o,id_path),val_string(mname),&r,&p); if( vm->fstats ) vm->fstats(vm,"neko_read_module",1); m = neko_read_module(r,p,vthis); if( vm->fstats ) vm->fstats(vm,"neko_read_module",0); close_module(p); if( m == NULL ) { buffer b = alloc_buffer("Invalid module : "); val_buffer(b,mname); bfailure(b); } m->name = alloc_string(val_string(mname)); mv = alloc_abstract(neko_kind_module,m); alloc_field(cache,mid,mv); if( vm->fstats ) vm->fstats(vm,val_string(mname),1); neko_vm_execute(neko_vm_current(),m); if( vm->fstats ) vm->fstats(vm,val_string(mname),0); return m->exports; } } EXTERN value neko_default_loader( char **argv, int argc ) { value o = alloc_object(NULL); value args = alloc_array(argc); int i; for(i=0;i #include #include "neko.h" #include "objtable.h" #include "vm.h" #define C(x,y) ((x << 8) | y) #define FLOAT_FMT "%.15g" DEFINE_KIND(k_hash); extern mt_lock *neko_fields_lock; extern objtable *neko_fields; extern field id_compare; extern field id_string; extern char *jit_handle_trap; typedef void (*jit_handle)( neko_vm * ); static INLINE int icmp( int a, int b ) { return (a == b)?0:((a < b)?-1:1); } static INLINE int fcmp( tfloat a, tfloat b ) { return (a == b)?0:((a < b)?-1:1); } static INLINE int scmp( const char *s1, int l1, const char *s2, int l2 ) { int r = memcmp(s1,s2,(l1 < l2)?l1:l2); return r?r:icmp(l1,l2); } EXTERN int val_compare( value a, value b ) { char tmp_buf[32]; switch( C(val_type(a),val_type(b)) ) { case C(VAL_INT,VAL_INT): return icmp(val_int(a),val_int(b)); case C(VAL_INT32,VAL_INT): return icmp(val_int32(a),val_int(b)); case C(VAL_INT,VAL_INT32): return icmp(val_int(a),val_int32(b)); case C(VAL_INT32,VAL_INT32): return icmp(val_int32(a),val_int32(b)); case C(VAL_INT,VAL_FLOAT): return fcmp(val_int(a),val_float(b)); case C(VAL_INT32,VAL_FLOAT): return fcmp(val_int32(a),val_float(b)); case C(VAL_INT,VAL_STRING): return scmp(tmp_buf,sprintf(tmp_buf,"%d",val_int(a)),val_string(b),val_strlen(b)); case C(VAL_INT32,VAL_STRING): return scmp(tmp_buf,sprintf(tmp_buf,"%d",val_int32(a)),val_string(b),val_strlen(b)); case C(VAL_FLOAT,VAL_INT): return fcmp(val_float(a),val_int(b)); case C(VAL_FLOAT,VAL_INT32): return fcmp(val_float(a),val_int32(b)); case C(VAL_FLOAT,VAL_FLOAT): return fcmp(val_float(a),val_float(b)); case C(VAL_FLOAT,VAL_STRING): return scmp(tmp_buf,sprintf(tmp_buf,FLOAT_FMT,val_float(a)),val_string(b),val_strlen(b)); case C(VAL_STRING,VAL_INT): return scmp(val_string(a),val_strlen(a),tmp_buf,sprintf(tmp_buf,"%d",val_int(b))); case C(VAL_STRING,VAL_INT32): return scmp(val_string(a),val_strlen(a),tmp_buf,sprintf(tmp_buf,"%d",val_int32(b))); case C(VAL_STRING,VAL_FLOAT): return scmp(val_string(a),val_strlen(a),tmp_buf,sprintf(tmp_buf,FLOAT_FMT,val_float(b))); case C(VAL_STRING,VAL_BOOL): return scmp(val_string(a),val_strlen(a),val_bool(b)?"true":"false",val_bool(b)?4:5); case C(VAL_BOOL,VAL_STRING): return scmp(val_bool(a)?"true":"false",val_bool(a)?4:5,val_string(b),val_strlen(b)); case C(VAL_STRING,VAL_STRING): return scmp(val_string(a),val_strlen(a),val_string(b),val_strlen(b)); case C(VAL_BOOL,VAL_BOOL): return (a == b) ? 0 : (val_bool(a) ? 1 : -1); case C(VAL_OBJECT,VAL_OBJECT): if( a == b ) return 0; { value tmp = val_field(a,id_compare); if( tmp == val_null ) return invalid_comparison; a = val_callEx(a,tmp,&b,1,NULL); } if( val_is_int(a) ) return val_int(a); return invalid_comparison; default: if( a == b ) return 0; return invalid_comparison; } } typedef struct _stringitem { char *str; int size; int len; struct _stringitem *next; } * stringitem; struct _buffer { int totlen; int blen; stringitem data; }; EXTERN buffer alloc_buffer( const char *init ) { buffer b = (buffer)alloc(sizeof(struct _buffer)); b->totlen = 0; b->blen = 16; b->data = NULL; if( init ) buffer_append(b,init); return b; } static void buffer_append_new( buffer b, const char *s, int len ) { int size; stringitem it; while( b->totlen >= (b->blen << 2) ) b->blen <<= 1; size = (len < b->blen)?b->blen:len; it = (stringitem)alloc(sizeof(struct _stringitem)); it->str = alloc_private(size); memcpy(it->str,s,len); it->size = size; it->len = len; it->next = b->data; b->data = it; } EXTERN void buffer_append_sub( buffer b, const char *s, int_val _len ) { stringitem it; int len = (int)_len; if( s == NULL || len <= 0 ) return; b->totlen += len; it = b->data; if( it ) { int free = it->size - it->len; if( free >= len ) { memcpy(it->str + it->len,s,len); it->len += len; return; } else { memcpy(it->str + it->len,s,free); it->len += free; s += free; len -= free; } } buffer_append_new(b,s,len); } EXTERN void buffer_append( buffer b, const char *s ) { if( s == NULL ) return; buffer_append_sub(b,s,strlen(s)); } EXTERN void buffer_append_char( buffer b, char c ) { stringitem it; b->totlen++; it = b->data; if( it && it->len != it->size ) { it->str[it->len++] = c; return; } buffer_append_new(b,&c,1); } EXTERN value buffer_to_string( buffer b ) { value v = alloc_empty_string(b->totlen); stringitem it = b->data; char *s = (char*)val_string(v) + b->totlen; while( it != NULL ) { stringitem tmp; s -= it->len; memcpy(s,it->str,it->len); tmp = it->next; it = tmp; } return v; } typedef struct vlist { value v; struct vlist *next; } vlist; typedef struct vlist2 { value v; struct vlist *next; buffer b; int prev; } vlist2; static void val_buffer_rec( buffer b, value v, vlist *stack ); static void val_buffer_fields( value v, field f, void *_l ) { vlist2 *l = (vlist2*)_l; if( l->prev ) buffer_append_sub(l->b,", ",2); else { buffer_append_sub(l->b," ",1); l->prev = 1; } val_buffer(l->b,val_field_name(f)); buffer_append_sub(l->b," => ",4); val_buffer_rec(l->b,v,(vlist*)l); } static void val_buffer_rec( buffer b, value v, vlist *stack ) { char buf[32]; int i, l; vlist *vtmp = stack; while( vtmp != NULL ) { if( vtmp->v == v ) { buffer_append_sub(b,"...",3); return; } vtmp = vtmp->next; } switch( val_type(v) ) { case VAL_INT: buffer_append_sub(b,buf,sprintf(buf,"%d",val_int(v))); break; case VAL_STRING: buffer_append_sub(b,val_string(v),val_strlen(v)); break; case VAL_FLOAT: buffer_append_sub(b,buf,sprintf(buf,FLOAT_FMT,val_float(v))); break; case VAL_NULL: buffer_append_sub(b,"null",4); break; case VAL_BOOL: if( val_bool(v) ) buffer_append_sub(b,"true",4); else buffer_append_sub(b,"false",5); break; case VAL_FUNCTION: buffer_append_sub(b,buf,sprintf(buf,"#function:%d",val_fun_nargs(v))); break; case VAL_OBJECT: { value s = val_field(v,id_string); if( s != val_null ) s = val_callEx(v,s,NULL,0,NULL); if( val_is_string(s) ) buffer_append_sub(b,val_string(s),val_strlen(s)); else { vlist2 vtmp; vtmp.v = v; vtmp.next = stack; vtmp.b = b; vtmp.prev = 0; buffer_append_sub(b,"{",1); val_iter_fields(v,val_buffer_fields,&vtmp); if( vtmp.prev ) buffer_append_sub(b," }",2); else buffer_append_sub(b,"}",1); } break; } case VAL_ARRAY: buffer_append_sub(b,"[",1); l = val_array_size(v); { vlist vtmp; vtmp.v = v; vtmp.next = stack; for(i=0;itmp,"%d",x); v = alloc_empty_string(len+len2); if( way ) { memcpy((char*)val_string(v),val_string(str),len); memcpy((char*)val_string(v)+len,vm->tmp,len2+1); } else { memcpy((char*)val_string(v),vm->tmp,len2); memcpy((char*)val_string(v)+len2,val_string(str),len+1); } return v; } value neko_append_strings( value s1, value s2 ) { int len1 = val_strlen(s1); int len2 = val_strlen(s2); value v = alloc_empty_string(len1+len2); memcpy((char*)val_string(v),val_string(s1),len1); memcpy((char*)val_string(v)+len1,val_string(s2),len2+1); return v; } int neko_stack_expand( int_val *sp, int_val *csp, neko_vm *vm ) { int i; int size = (int)((((int_val)vm->spmax - (int_val)vm->spmin) / sizeof(int_val)) << 1); int_val *nsp; if( size > MAX_STACK_SIZE ) { vm->sp = sp; vm->csp = csp; return 0; } nsp = (int_val*)alloc(size * sizeof(int_val)); // csp size i = (int)(((int_val)(csp + 1) - (int_val)vm->spmin) / sizeof(int_val)); memcpy(nsp,vm->spmin,sizeof(int_val) * i); vm->csp = nsp + i - 1; // sp size i = (int)(((int_val)vm->spmax - (int_val)sp) / sizeof(int_val)); memcpy(nsp+size-i,sp,sizeof(int_val) * i); vm->sp = nsp + size - i; vm->spmin = nsp; vm->spmax = nsp + size; return 1; } EXTERN field val_id( const char *name ) { objtable *t; value fdata; field f; value acc = alloc_int(0); const char *oname = name; while( *name ) { acc = alloc_int(223 * val_int(acc) + *((unsigned char*)name)); name++; } f = val_int(acc); t = &neko_fields[f&NEKO_FIELDS_MASK]; fdata = otable_get(t,f); if( fdata == val_null ) { // insert in the table, but by using a larger table that grows faster // since we don't want to resize the table for each insert int min; int max; int mid; field cid; objcell *c; lock_acquire(neko_fields_lock); min = 0; max = t->count; c = t->cells; while( min < max ) { mid = (min + max) >> 1; cid = c[mid].id; if( cid < f ) min = mid + 1; else if( cid > f ) max = mid; else { fdata = c[mid].v; break; } } // in case we found it, it means that it's been inserted by another thread if( fdata == val_null ) { objcell *c2 = (objcell*)alloc(sizeof(objcell)*(t->count+1)); // copy the whole table mid = (min + max) >> 1; min = 0; while( min < mid ) { c2[min] = c[min]; min++; } c2[min].id = f; c2[min].v = copy_string(oname,name - oname); max = t->count; while( min < max ) { c2[min+1] = c[min]; min++; } // update t->cells = c2; t->count++; } lock_release(neko_fields_lock); } if( fdata != val_null && scmp(val_string(fdata),val_strlen(fdata),oname,(int)(name - oname)) != 0 ) { buffer b = alloc_buffer("Field conflict between "); val_buffer(b,fdata); buffer_append(b," and "); buffer_append(b,oname); bfailure(b); } return f; } EXTERN value val_field_name( field id ) { return otable_get(&neko_fields[id&NEKO_FIELDS_MASK],id); } EXTERN value val_field( value _o, field id ) { value *f; // WARNING : we can't change the value on the stack // since it will be reused by the JIT (when compiled with GCC) vobject *o = (vobject*)_o; do { f = otable_find(&o->table,id); if( f != NULL ) return *f; o = o->proto; } while( o ); return val_null; } EXTERN void val_iter_fields( value o, void f( value , field, void * ) , void *p ) { otable_iter( &((vobject*)o)->table, f, p ); } EXTERN void val_print( value v ) { neko_vm *vm; if( !val_is_string(v) ) { buffer b = alloc_buffer(NULL); val_buffer(b,v); v = buffer_to_string(b); } vm = NEKO_VM(); vm->print( val_string(v), val_strlen(v), vm->print_param ); } EXTERN void val_throw( value v ) { neko_vm *vm = NEKO_VM(); vm->exc_stack = alloc_array(0); vm->vthis = v; if( *(char**)vm->start == jit_handle_trap ) ((jit_handle)jit_handle_trap)(vm); else longjmp(vm->start,1); } EXTERN void val_rethrow( value v ) { neko_vm *vm = NEKO_VM(); vm->vthis = v; if( *(char**)vm->start == jit_handle_trap ) ((jit_handle)jit_handle_trap)(vm); else longjmp(vm->start,1); } static value failure_to_string() { value o = val_this(); buffer b = alloc_buffer(NULL); val_check(o,object); val_buffer(b,val_field(o,val_id("file"))); buffer_append(b,"("); val_buffer(b,val_field(o,val_id("line"))); buffer_append(b,") : "); val_buffer(b,val_field(o,val_id("msg"))); return buffer_to_string(b); } EXTERN void _neko_failure( value msg, const char *file, int line ) { char *fname = strrchr(file,'/'); char *fname2 = strrchr(file,'\\'); value o = alloc_object(NULL); if( fname2 > fname ) fname = fname2; alloc_field(o,val_id("msg"),msg); alloc_field(o,val_id("file"),alloc_string(fname?(fname+1):file)); alloc_field(o,val_id("line"),alloc_int(line)); alloc_field(o,id_string,alloc_function(failure_to_string,0,"failure_to_string")); val_throw(o); } /* ************************************************************************ */ neko-2.0.0/vm/neko.h0000644000175000017500000003160312112157473014706 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef _NEKO_H #define _NEKO_H // OS FLAGS #if defined(_WIN32) # define NEKO_WINDOWS #endif #if defined(__APPLE__) || defined(__MACH__) || defined(macintosh) # define NEKO_MAC #endif #if defined(linux) || defined(__linux__) # define NEKO_LINUX #endif #if defined(__FreeBSD_kernel__) # define NEKO_GNUKBSD #endif #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) # define NEKO_BSD #endif // COMPILER/PROCESSOR FLAGS #if defined(__GNUC__) # define NEKO_GCC #endif #if defined(_MSC_VER) # define NEKO_VCC // remove deprecated C API usage warnings # pragma warning( disable : 4996 ) #endif #if defined(__MINGW32__) # define NEKO_MINGW #endif #if defined(__i386__) || defined(_WIN32) # define NEKO_X86 #endif #if defined(__ppc__) # define NEKO_PPC #endif #if defined(_64BITS) || defined(__x86_64__) # define NEKO_64BITS #endif #if defined(NEKO_LINUX) || defined(NEKO_MAC) || defined(NEKO_BSD) || defined(NEKO_GNUKBSD) # define NEKO_POSIX #endif #if defined(NEKO_GCC) # define NEKO_THREADED # define NEKO_DIRECT_THREADED #endif #ifndef NEKO_NO_THREADS # define NEKO_THREADS #endif #include #ifndef NEKO_VCC # include #endif #define NEKO_VERSION 200 typedef intptr_t int_val; typedef enum { VAL_INT = 0xFF, VAL_NULL = 0, VAL_FLOAT = 1, VAL_BOOL = 2, VAL_STRING = 3, VAL_OBJECT = 4, VAL_ARRAY = 5, VAL_FUNCTION = 6, VAL_ABSTRACT = 7, VAL_INT32 = 8, VAL_PRIMITIVE = 6 | 16, VAL_JITFUN = 6 | 32, VAL_32_BITS = 0xFFFFFFFF } val_type; struct _value { val_type t; }; struct _buffer; typedef int field; typedef struct { int __zero; } *vkind; typedef struct _value *value; typedef struct { field id; value v; } objcell; typedef struct _objtable { int count; objcell *cells; } objtable; typedef struct _buffer *buffer; typedef double tfloat; typedef void (*finalizer)(value v); #pragma pack(4) typedef struct { val_type t; tfloat f; } vfloat; typedef struct { val_type t; int i; } vint32; #pragma pack() typedef struct _vobject { val_type t; objtable table; struct _vobject *proto; } vobject; typedef struct { val_type t; int nargs; void *addr; value env; void *module; } vfunction; typedef struct { val_type t; char c; } vstring; typedef struct { val_type t; value ptr; } varray; typedef struct { val_type t; vkind kind; void *data; } vabstract; typedef struct hcell { int hkey; value key; value val; struct hcell *next; } hcell; typedef struct { hcell **cells; int ncells; int nitems; } vhash; struct _mt_local; struct _mt_lock; typedef struct _mt_local mt_local; typedef struct _mt_lock mt_lock; #define TAG_BITS 4 #define val_tag(v) (*(val_type*)(v)) #define val_short_tag(v) (val_tag(v)&((1<data #define val_kind(v) ((vabstract*)(v))->kind #define val_type(v) (val_is_int(v) ? VAL_INT : val_short_tag(v)) #define val_int(v) (((int)(int_val)(v)) >> 1) #define val_float(v) (CONV_FLOAT ((vfloat*)(v))->f) #define val_int32(v) (((vint32*)(v))->i) #define val_any_int(v) (val_is_int(v)?val_int(v):val_int32(v)) #define val_bool(v) ((v) == val_true) #define val_number(v) (val_is_int(v)?val_int(v):((val_tag(v)==VAL_FLOAT)?val_float(v):val_int32(v))) #define val_hdata(v) ((vhash*)val_data(v)) #define val_string(v) (&((vstring*)(v))->c) #define val_strlen(v) (val_tag(v) >> TAG_BITS) #define val_set_length(v,l) val_tag(v) = val_short_tag(v) | ((l) << TAG_BITS) #define val_set_size val_set_length #define val_array_size(v) (val_tag(v) >> TAG_BITS) #define val_array_ptr(v) (&((varray*)(v))->ptr) #define val_fun_nargs(v) ((vfunction*)(v))->nargs #define alloc_int(v) ((value)(int_val)((((int)(v)) << 1) | 1)) #define alloc_bool(b) ((b)?val_true:val_false) #define max_array_size ((1 << (32 - TAG_BITS)) - 1) #define max_string_size ((1 << (32 - TAG_BITS)) - 1) #define invalid_comparison 0xFE #undef EXTERN #undef EXPORT #undef IMPORT #if defined(NEKO_VCC) || defined(NEKO_MINGW) # define INLINE __inline # define EXPORT __declspec( dllexport ) # define IMPORT __declspec( dllimport ) #else # define INLINE inline # define EXPORT # define IMPORT #endif #if defined(NEKO_SOURCES) || defined(NEKO_STANDALONE) # define EXTERN EXPORT #else # define EXTERN IMPORT #endif #define VEXTERN extern EXTERN #ifdef __cplusplus # define C_FUNCTION_BEGIN extern "C" { # define C_FUNCTION_END }; #else # define C_FUNCTION_BEGIN # define C_FUNCTION_END # ifndef true # define true 1 # define false 0 typedef int bool; # endif #endif // the two upper bits must be either 00 or 11 #define need_32_bits(i) ( (((unsigned int)(i)) + 0x40000000) & 0x80000000 ) #define alloc_best_int(i) (need_32_bits(i) ? alloc_int32(i) : alloc_int(i)) #define neko_error() return NULL #define failure(msg) _neko_failure(alloc_string(msg),__FILE__,__LINE__) #define bfailure(buf) _neko_failure(buffer_to_string(buf),__FILE__,__LINE__) #ifndef CONV_FLOAT # define CONV_FLOAT #endif #ifdef NEKO_POSIX # include # define POSIX_LABEL(name) name: # define HANDLE_EINTR(label) if( errno == EINTR ) goto label # define HANDLE_FINTR(f,label) if( ferror(f) && errno == EINTR ) goto label #else # define POSIX_LABEL(name) # define HANDLE_EINTR(label) # define HANDLE_FINTR(f,label) #endif #define VAR_ARGS (-1) #define DEFINE_PRIM_MULT(func) C_FUNCTION_BEGIN EXPORT void *func##__MULT() { return (void*)(&func); } C_FUNCTION_END #define DEFINE_PRIM(func,nargs) C_FUNCTION_BEGIN EXPORT void *func##__##nargs() { return (void*)(&func); } C_FUNCTION_END #define DEFINE_KIND(name) int_val __kind_##name = 0; vkind name = (vkind)&__kind_##name; #ifdef NEKO_STANDALONE # define DEFINE_ENTRY_POINT(name) #else # define DEFINE_ENTRY_POINT(name) C_FUNCTION_BEGIN void name(); EXPORT void *__neko_entry_point() { return &name; } C_FUNCTION_END #endif #ifdef HEADER_IMPORTS # define H_EXTERN IMPORT #else # define H_EXTERN EXPORT #endif #define DECLARE_PRIM(func,nargs) C_FUNCTION_BEGIN H_EXTERN void *func##__##nargs(); C_FUNCTION_END #define DECLARE_KIND(name) C_FUNCTION_BEGIN H_EXTERN extern vkind name; C_FUNCTION_END #define alloc_int32 neko_alloc_int32 #define alloc_float neko_alloc_float #define alloc_string neko_alloc_string #define alloc_empty_string neko_alloc_empty_string #define copy_string neko_copy_string #define val_this neko_val_this #define val_id neko_val_id #define val_field neko_val_field #define alloc_object neko_alloc_object #define alloc_field neko_alloc_field #define alloc_array neko_alloc_array #define val_call0 neko_val_call0 #define val_call1 neko_val_call1 #define val_call2 neko_val_call2 #define val_call3 neko_val_call3 #define val_callN neko_val_callN #define val_ocall0 neko_val_ocall0 #define val_ocall1 neko_val_ocall1 #define val_ocall2 neko_val_ocall2 #define val_ocallN neko_val_ocallN #define val_callEx neko_val_callEx #define alloc_root neko_alloc_root #define free_root neko_free_root #define alloc neko_alloc #define alloc_private neko_alloc_private #define alloc_abstract neko_alloc_abstract #define alloc_function neko_alloc_function #define alloc_buffer neko_alloc_buffer #define buffer_append neko_buffer_append #define buffer_append_sub neko_buffer_append_sub #define buffer_append_char neko_buffer_append_char #define buffer_to_string neko_buffer_to_string #define val_buffer neko_val_buffer #define val_compare neko_val_compare #define val_print neko_val_print #define val_gc neko_val_gc #define val_throw neko_val_throw #define val_rethrow neko_val_rethrow #define val_iter_fields neko_val_iter_fields #define val_field_name neko_val_field_name #define val_hash neko_val_hash #define k_hash neko_k_hash #define kind_share neko_kind_share #define alloc_local neko_alloc_local #define local_get neko_local_get #define local_set neko_local_set #define free_local neko_free_local #define alloc_lock neko_alloc_lock #define lock_acquire neko_lock_acquire #define lock_try neko_lock_try #define lock_release neko_lock_release #define free_lock neko_free_lock C_FUNCTION_BEGIN VEXTERN vkind k_hash; VEXTERN value val_null; VEXTERN value val_true; VEXTERN value val_false; EXTERN value alloc_float( tfloat t ); EXTERN value alloc_int32( int i ); EXTERN value alloc_string( const char *str ); EXTERN value alloc_empty_string( unsigned int size ); EXTERN value copy_string( const char *str, int_val size ); EXTERN value val_this(); EXTERN field val_id( const char *str ); EXTERN value val_field( value o, field f ); EXTERN value alloc_object( value o ); EXTERN void alloc_field( value obj, field f, value v ); EXTERN void val_iter_fields( value obj, void f( value v, field f, void * ), void *p ); EXTERN value val_field_name( field f ); EXTERN value alloc_array( unsigned int n ); EXTERN value alloc_abstract( vkind k, void *data ); EXTERN value val_call0( value f ); EXTERN value val_call1( value f, value arg ); EXTERN value val_call2( value f, value arg1, value arg2 ); EXTERN value val_call3( value f, value arg1, value arg2, value arg3 ); EXTERN value val_callN( value f, value *args, int nargs ); EXTERN value val_ocall0( value o, field f ); EXTERN value val_ocall1( value o, field f, value arg ); EXTERN value val_ocall2( value o, field f, value arg1, value arg2 ); EXTERN value val_ocallN( value o, field f, value *args, int nargs ); EXTERN value val_callEx( value vthis, value f, value *args, int nargs, value *exc ); EXTERN value *alloc_root( unsigned int nvals ); EXTERN void free_root( value *r ); EXTERN char *alloc( unsigned int nbytes ); EXTERN char *alloc_private( unsigned int nbytes ); EXTERN value alloc_function( void *c_prim, unsigned int nargs, const char *name ); EXTERN buffer alloc_buffer( const char *init ); EXTERN void buffer_append( buffer b, const char *s ); EXTERN void buffer_append_sub( buffer b, const char *s, int_val len ); EXTERN void buffer_append_char( buffer b, char c ); EXTERN value buffer_to_string( buffer b ); EXTERN void val_buffer( buffer b, value v ); EXTERN int val_compare( value a, value b ); EXTERN void val_print( value s ); EXTERN void val_gc( value v, finalizer f ); EXTERN void val_throw( value v ); EXTERN void val_rethrow( value v ); EXTERN int val_hash( value v ); EXTERN void kind_share( vkind *k, const char *name ); EXTERN void _neko_failure( value msg, const char *file, int line ); // MULTITHREADING API EXTERN mt_local *alloc_local(); EXTERN void *local_get( mt_local *l ); EXTERN void local_set( mt_local *l, void *v ); EXTERN void free_local( mt_local *l ); EXTERN mt_lock *alloc_lock(); EXTERN void lock_acquire( mt_lock *l ); EXTERN int lock_try( mt_lock *l ); EXTERN void lock_release( mt_lock *l ); EXTERN void free_lock( mt_lock *l ); C_FUNCTION_END #endif /* ************************************************************************ */ neko-2.0.0/vm/threads.c0000644000175000017500000002061312112157473015376 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifdef __APPLE__ // prevent later redefinition of bool # include #endif #include "vm.h" #include #if !defined(NEKO_THREADS) #include struct _mt_local { void *value; }; #else #ifdef NEKO_WINDOWS // necessary for TryEnterCriticalSection // which is only available on 2000 PRO and XP # define _WIN32_WINNT 0x0400 # define GC_NOT_DLL # define GC_WIN32_THREADS #endif #define GC_THREADS #include #if GC_VERSION_MAJOR < 7 # define GC_SUCCESS 0 # define GC_DUPLICATE 1 #endif #ifdef NEKO_WINDOWS struct _mt_lock { CRITICAL_SECTION cs; }; #else #include #include struct _mt_local { pthread_key_t key; }; struct _mt_lock { pthread_mutex_t lock; }; // should be enough to store any GC_stack_base // implementation typedef char __stack_base[64]; #endif #endif // !NEKO_THREADS typedef struct { thread_main_func init; thread_main_func main; void *param; #ifdef NEKO_THREADS # ifdef NEKO_WINDOWS HANDLE lock; # else pthread_mutex_t lock; # endif #endif } tparams; #ifdef NEKO_THREADS #ifdef NEKO_WINDOWS # define THREAD_FUN DWORD WINAPI #else # define THREAD_FUN void * #endif typedef int (*rec)( int, void * ); static int clean_c_stack( int n, void *f ) { char buf[256]; memset(buf,n,sizeof(buf)); if( n == 0 ) return *buf; return ((rec)f)(n-1,f) ? 1 : 0; // prevent tail-rec } static THREAD_FUN ThreadMain( void *_p ) { tparams *lp = (tparams*)_p; tparams p = *lp; p.init(p.param); // we have the 'param' value on this thread C stack // so it's safe to give back control to main thread # ifdef NEKO_WINDOWS ReleaseSemaphore(p.lock,1,NULL); # else pthread_mutex_unlock(&lp->lock); # endif clean_c_stack(40,clean_c_stack); p.main(p.param); return 0; } #endif EXTERN int neko_thread_create( thread_main_func init, thread_main_func main, void *param, void **handle ) { tparams p; p.init = init; p.main = main; p.param = param; # if !defined(NEKO_THREADS) return 0; # elif defined(NEKO_WINDOWS) { HANDLE h; p.lock = CreateSemaphore(NULL,0,1,NULL); h = GC_CreateThread(NULL,0,ThreadMain,&p,0,(void*)handle); if( h == NULL ) { CloseHandle(p.lock); return 0; } WaitForSingleObject(p.lock,INFINITE); CloseHandle(p.lock); CloseHandle(h); return 1; } # else pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); pthread_mutex_init(&p.lock,NULL); pthread_mutex_lock(&p.lock); // force the use of a the GC method to capture created threads // this function should be defined in gc/gc.h if( GC_pthread_create((pthread_t*)handle,&attr,&ThreadMain,&p) != 0 ) { pthread_attr_destroy(&attr); pthread_mutex_destroy(&p.lock); return 0; } pthread_mutex_lock(&p.lock); pthread_attr_destroy(&attr); pthread_mutex_destroy(&p.lock); return 1; # endif } #if defined(NEKO_POSIX) && defined(NEKO_THREADS) # include typedef void (*callb_func)( thread_main_func, void * ); typedef int (*std_func)(); typedef int (*gc_stack_ptr)( __stack_base * ); static int do_nothing( __stack_base *sb ) { return -1; } #endif EXTERN void neko_thread_blocking( thread_main_func f, void *p ) { # if !defined(NEKO_THREADS) f(p); // nothing # elif defined(NEKO_WINDOWS) f(p); // we don't have pthreads issues # else // we have different APIs depending on the GC version, make sure we load // the good one at runtime static callb_func do_blocking = NULL; static std_func start = NULL, end = NULL; if( do_blocking ) do_blocking(f,p); else if( start ) { start(); f(p); end(); } else { void *self = dlopen(NULL,0); do_blocking = (callb_func)dlsym(self,"GC_do_blocking"); if( !do_blocking ) { start = (std_func)dlsym(self,"GC_start_blocking"); end = (std_func)dlsym(self,"GC_end_blocking"); if( !start || !end ) val_throw(alloc_string("Could not init GC blocking API")); } neko_thread_blocking(f,p); } # endif } EXTERN bool neko_thread_register( bool t ) { # if !defined(NEKO_THREADS) return 0; # elif defined(NEKO_WINDOWS) struct GC_stack_base sb; int r; if( !t ) return GC_unregister_my_thread() == GC_SUCCESS; if( GC_get_stack_base(&sb) != GC_SUCCESS ) return 0; r = GC_register_my_thread(&sb); return( r == GC_SUCCESS || r == GC_DUPLICATE ); # else // since the API is only available on GC 7.0, // we will do our best to locate it dynamically static gc_stack_ptr get_sb = NULL, my_thread = NULL; static std_func unreg_my_thread = NULL; if( !t && unreg_my_thread != NULL ) { return unreg_my_thread() == GC_SUCCESS; } else if( my_thread != NULL ) { __stack_base sb; int r; if( get_sb(&sb) != GC_SUCCESS ) return 0; r = my_thread(&sb); return( r == GC_SUCCESS || r == GC_DUPLICATE ); } else { void *self = dlopen(NULL,0); my_thread = (gc_stack_ptr)dlsym(self,"GC_register_my_thread"); get_sb = (gc_stack_ptr)dlsym(self,"GC_get_stack_base"); unreg_my_thread = (std_func)dlsym(self,"GC_unregister_my_thread"); if( my_thread == NULL ) my_thread = do_nothing; if( get_sb == NULL ) get_sb = do_nothing; if( unreg_my_thread == NULL ) unreg_my_thread = (std_func)do_nothing; return neko_thread_register(t); } # endif } EXTERN mt_local *alloc_local() { # if !defined(NEKO_THREADS) mt_local *l = malloc(sizeof(mt_local)); l->value = NULL; return l; # elif defined(NEKO_WINDOWS) DWORD t = TlsAlloc(); TlsSetValue(t,NULL); return (mt_local*)(int_val)t; # else mt_local *l = malloc(sizeof(mt_local)); pthread_key_create(&l->key,NULL); return l; # endif } EXTERN void free_local( mt_local *l ) { # if !defined(NEKO_THREADS) free(l); # elif defined(NEKO_WINDOWS) TlsFree((DWORD)(int_val)l); # else pthread_key_delete(l->key); free(l); # endif } EXTERN void local_set( mt_local *l, void *v ) { # if !defined(NEKO_THREADS) l->value = v; # elif defined(NEKO_WINDOWS) TlsSetValue((DWORD)(int_val)l,v); # else pthread_setspecific(l->key,v); # endif } EXTERN void *local_get( mt_local *l ) { if( l == NULL ) return NULL; # if !defined(NEKO_THREADS) return l->value; # elif defined(NEKO_WINDOWS) return (void*)TlsGetValue((DWORD)(int_val)l); # else return pthread_getspecific(l->key); # endif } EXTERN mt_lock *alloc_lock() { # if !defined(NEKO_THREADS) return (mt_lock*)1; # elif defined(NEKO_WINDOWS) mt_lock *l = (mt_lock*)malloc(sizeof(mt_lock)); InitializeCriticalSection(&l->cs); return l; # else mt_lock *l = (mt_lock*)malloc(sizeof(mt_lock)); pthread_mutexattr_t a; pthread_mutexattr_init(&a); pthread_mutexattr_settype(&a,PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&l->lock,&a); pthread_mutexattr_destroy(&a); return l; # endif } EXTERN void lock_acquire( mt_lock *l ) { # if !defined(NEKO_THREADS) # elif defined(NEKO_WINDOWS) EnterCriticalSection(&l->cs); # else pthread_mutex_lock(&l->lock); # endif } EXTERN int lock_try( mt_lock *l ) { #if !defined(NEKO_THREADS) return 1; # elif defined(NEKO_WINDOWS) return TryEnterCriticalSection(&l->cs); # else return pthread_mutex_trylock(&l->lock) == 0; # endif } EXTERN void lock_release( mt_lock *l ) { # if !defined(NEKO_THREADS) # elif defined(NEKO_WINDOWS) LeaveCriticalSection(&l->cs); # else pthread_mutex_unlock(&l->lock); # endif } EXTERN void free_lock( mt_lock *l ) { # if !defined(NEKO_THREADS) # elif defined(NEKO_WINDOWS) DeleteCriticalSection(&l->cs); free(l); # else pthread_mutex_destroy(&l->lock); free(l); # endif } /* ************************************************************************ */ neko-2.0.0/vm/vm.h0000644000175000017500000000431512112157473014374 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef _NEKO_VMCONTEXT_H #define _NEKO_VMCONTEXT_H #include #include "neko_vm.h" #define INIT_STACK_SIZE (1 << 8) #define MAX_STACK_SIZE (1 << 18) #define MAX_STACK_PER_FUNCTION 128 #define PROF_SIZE (1 << 20) #define CALL_MAX_ARGS 5 #define NEKO_FIELDS_MASK 63 typedef struct _custom_list { vkind tag; void *custom; struct _custom_list *next; } custom_list; struct _neko_vm { int_val *sp; int_val *csp; value env; value vthis; int_val *spmin; int_val *spmax; int_val trap; void *jit_val; jmp_buf start; void *c_stack_max; int run_jit; value exc_stack; neko_printer print; void *print_param; custom_list *clist; value resolver; char tmp[100]; int trusted_code; neko_stat_func fstats; neko_stat_func pstats; }; extern int_val *callback_return; extern mt_local *neko_vm_context; #define NEKO_VM() ((neko_vm*)local_get(neko_vm_context)) extern value neko_alloc_apply( int nargs, value env ); extern value neko_interp( neko_vm *vm, void *m, int_val acc, int_val *pc ); extern int_val *neko_get_ttable(); #endif /* ************************************************************************ */ neko-2.0.0/vm/nekovm.vcproj0000644000175000017500000001071612112157473016327 0ustar ncannassencannasse neko-2.0.0/vm/nekovm_dll.vcproj0000644000175000017500000001354712112157473017167 0ustar ncannassencannasse neko-2.0.0/vm/jit_x86.c0000644000175000017500000016756212112157473015256 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "vm.h" #include "neko_mod.h" #include "objtable.h" #include #include #include #include #ifdef NEKO_POSIX # include # include # define USE_MMAP #endif #define tmp_alloc(size) malloc(size) #define tmp_free(ptr) free(ptr) #if defined(NEKO_X86) && !defined(NEKO_MAC) #define JIT_ENABLE #endif #ifdef NEKO_MAC #define STACK_ALIGN #endif #if defined(NEKO_WINDOWS) && defined(_DEBUG_XX) #define STACK_ALIGN #define STACK_ALIGN_DEBUG #endif #define TAG_MASK ((1<pos); tmp_free(ctx->baseptr); failure("JIT error"); } #define CONST(v) ((int)(int_val)(v)) #define PATCH_JUMP(local) if( local != NULL ) { \ int delta = (int)((int_val)buf.p - ((int_val)local + 1)); \ if( sizeof(*local) == sizeof(int) ) \ *local = delta - 3; \ else { \ if( delta > 127 || delta < -127 ) \ ERROR; \ *local = (char)delta; \ } \ } \ #define FIELD(n) ((n) * 4) #define VMFIELD(f) ((int)(int_val)&((neko_vm*)0)->f) #define FUNFIELD(f) ((int)(int_val)&((vfunction*)0)->f) #define POS() ((int)((int_val)ctx->buf.p - (int_val)ctx->baseptr)) #define GET_PC() CONST(ctx->module->code + ctx->curpc) #define INIT_BUFFER register jit_buffer buf = ctx->buf #define END_BUFFER ctx->buf = buf #define MOD_RM(mod,reg,rm) B((mod << 6) | (reg << 3) | rm) #define SIB MOD_RM #define IS_SBYTE(c) ( (c) >= -128 && (c) < 128 ) #define OP_RM(op,mod,reg,rm) { B(op); MOD_RM(mod,reg,rm); } #define OP_ADDR(op,addr,reg,rm) { B(op); \ MOD_RM(((addr) == 0 && reg != Ebp)?0:(IS_SBYTE(addr)?1:2),rm,reg); \ if( reg == Esp ) B(0x24); \ if( (addr) == 0 && reg != Ebp ) {} \ else if IS_SBYTE(addr) B(addr); \ else W(addr); } // OPCODES : // _r : register // _c : constant // _b : 8-bit constant // _a : [constant] // _i : [reg] // _p : [reg + constant:idx] // _x : [reg + reg:idx * mult] #define XRet() B(0xC3) #define XMov_rr(dst,src) OP_RM(0x8B,3,dst,src) #define XMov_rc(dst,cst) B(0xB8+(dst)); W(cst) #define XMov_rp(dst,reg,idx) OP_ADDR(0x8B,idx,reg,dst) #define XMov_ra(dst,addr) OP_RM(0x8B,0,dst,5); W(addr) #define XMov_rx(dst,r,idx,mult) OP_RM(0x8B,0,dst,4); SIB(Mult##mult,idx,r) #define XMov_pr(dst,idx,src) OP_ADDR(0x89,idx,dst,src) #define XMov_pc(dst,idx,c) OP_ADDR(0xC7,idx,dst,0); W(c) #define XMov_ar(addr,reg) B(0x3E); if( reg == Eax ) { B(0xA3); } else { OP_RM(0x89,0,reg,5); }; W(addr) #define XMov_xr(r,idx,mult,src) OP_RM(0x89,0,src,4); SIB(Mult##mult,idx,r) #define XCall_r(r) OP_RM(0xFF,3,2,r) #define XCall_m_debug(v) { \ int *l; \ XMov_rr(TMP,Ebp); \ XSub_rr(TMP,Esp); \ XAnd_rc(TMP,15); \ XCmp_rc(TMP,0); \ XJump(JEq,l); \ XShr_rc(TMP,2); \ XPush_r(TMP); \ XPush_c(CONST(__LINE__)); \ XMov_rc(TMP,CONST(debug_method_call)); \ XCall_r(TMP); \ PATCH_JUMP(l); \ XMov_rc(TMP,CONST(v)); \ XCall_r(TMP); \ } #define XCall_m_real(v) XMov_rc(TMP,CONST(v)); XCall_r(TMP); #ifdef STACK_ALIGN_DEBUG # define XCall_m XCall_m_debug #else # define XCall_m XCall_m_real #endif #define XCall_d(delta) B(0xE8); W(delta) #define XPush_r(r) B(0x50+(r)) #define XPush_c(cst) B(0x68); W(cst) #define XPush_p(reg,idx) OP_ADDR(0xFF,idx,reg,6) #define XAdd_rc(reg,cst) if IS_SBYTE(cst) { OP_RM(0x83,3,0,reg); B(cst); } else { OP_RM(0x81,3,0,reg); W(cst); } #define XAdd_rr(dst,src) OP_RM(0x03,3,dst,src) #define XSub_rc(reg,cst) if IS_SBYTE(cst) { OP_RM(0x83,3,5,reg); B(cst); } else { OP_RM(0x81,3,5,reg); W(cst); } #define XSub_rr(dst,src) OP_RM(0x2B,3,dst,src) #define XCmp_rr(r1,r2) OP_RM(0x3B,3,r1,r2) #define XCmp_rc(reg,cst) if( reg == Eax ) { B(0x3D); } else { OP_RM(0x81,3,7,reg); }; W(cst) #define XCmp_rb(reg,byte) OP_RM(0x83,3,7,reg); B(byte) #define XJump(how,local) if( (how) == JAlways ) { B(0xE9); } else { B(0x0F); B(how); }; local = buf.i; W(0) #define XJump_near(local) B(0xEB); local = buf.c; B(0) #define XJump_r(reg) OP_RM(0xFF,3,4,reg) #define XPop_r(reg) B(0x58 + (reg)) #define XTest_rc(r,cst) if( r == Eax ) { B(0xA9); W(cst); } else { B(0xF7); MOD_RM(3,0,r); W(cst); } #define XTest_rr(r,src) B(0x85); MOD_RM(3,r,src) #define XAnd_rc(r,cst) if( r == Eax ) { B(0x25); W(cst); } else { B(0x81); MOD_RM(3,4,r); W(cst); } #define XAnd_rr(r,src) B(0x23); MOD_RM(3,r,src) #define XOr_rc(r,cst) if( r == Eax ) { B(0x0D); W(cst); } else { B(0x81); MOD_RM(3,1,r); W(cst); } #define XOr_rr(r,src) B(0x0B); MOD_RM(3,r,src) #define XXor_rc(r,cst) if( r == Eax ) { B(0x35); W(cst); } else { B(0x81); MOD_RM(3,6,r); W(cst); } #define XXor_rr(r,src) B(0x33); MOD_RM(3,r,src) #define shift_r(r,spec) B(0xD3); MOD_RM(3,spec,r); #define shift_c(r,n,spec) if( (n) == 1 ) { B(0xD1); MOD_RM(3,spec,r); } else { B(0xC1); MOD_RM(3,spec,r); B(n); } #define XShl_rr(r,src) if( src != Ecx ) ERROR; shift_r(r,4) #define XShl_rc(r,n) shift_c(r,n,4) #define XShr_rr(r,src) if( src != Ecx ) ERROR; shift_r(r,7) #define XShr_rc(r,n) shift_c(r,n,7) #define XUShr_rr(r,src) if( src != Ecx ) ERROR; shift_r(r,5) #define XUShr_rc(r,n) shift_c(r,n,5) #define XIMul_rr(dst,src) B(0x0F); B(0xAF); MOD_RM(3,dst,src) #define XIDiv_r(r) B(0xF7); MOD_RM(3,7,r) #define XCdq() B(0x99); // FPU #define XFAddp() B(0xDE); B(0xC1) #define XFSubp() B(0xDE); B(0xE9) #define XFMulp() B(0xDE); B(0xC9) #define XFDivp() B(0xDE); B(0xF9) #define XFStp_i(r) B(0xDD); MOD_RM(0,3,r); if( r == Esp ) B(0x24) #define XFLd_i(r) B(0xDD); MOD_RM(0,0,r); if( r == Esp ) B(0x24) #define XFILd_i(r) B(0xDB); MOD_RM(0,0,r); if( r == Esp ) B(0x24) #define is_int(r,flag,local) { XTest_rc(r,1); XJump((flag)?JNeq:JEq,local); } #ifdef STACK_ALIGN # define stack_pad(n) stack_push(Esp,n) # define stack_pop_pad(n,n2) stack_pop(Esp,((n) + (n2))) #else # define stack_pad(n) # define stack_pop_pad(n,n2) stack_pop(Esp,(n)) #endif #define stack_push(r,n) \ if( (n) != 0 ) { \ if( (r) == CSP ) { \ XAdd_rc(r,(n) * 4); \ } else { \ XSub_rc(r,(n) * 4); \ } \ } #define stack_pop(r,n) \ if( (n) != 0 ) { \ if( (r) == CSP ) { \ XSub_rc(r,(n) * 4); \ } else { \ XAdd_rc(r,(n) * 4); \ } \ } #define begin_call() { XMov_pr(VM,VMFIELD(sp),SP); XMov_pr(VM,VMFIELD(csp),CSP); } #define end_call() { XMov_rp(SP,VM,VMFIELD(sp)); XMov_rp(CSP,VM,VMFIELD(csp)); } #define label(code) { XMov_rc(TMP2,CONST(code)); XCall_r(TMP2); } #define todo(str) { int *loop; XMov_rc(TMP2,CONST(str)); XJump(JAlways,loop); *loop = -5; } #define pop(n) if( (n) != 0 ) { \ int i = (n); \ while( i-- > 0 ) { \ XMov_pc(SP,FIELD(i),0); \ } \ stack_pop(SP,n); \ } #define pop_loop(n) { \ char *start; \ int *loop; \ XMov_rc(TMP,n); \ start = buf.c; \ XMov_pc(SP,FIELD(0),0); \ stack_pop(SP,1); \ XSub_rc(TMP,1); \ XCmp_rc(TMP,0); \ XJump(JNeq,loop); \ *loop = (int)(start - buf.c); \ } #ifdef STACK_ALIGN # define PAD_OPT(x) (x) #else # define PAD_OPT(x) 0 #endif #define runtime_error(msg_id,in_label) { \ if( in_label ) { stack_pad(2); } else { stack_pad(1); } \ XPush_c(CONST(strings[msg_id])); \ if( in_label ) { \ XMov_rp(TMP2,Esp,FIELD(2+PAD_OPT(2))); \ XPush_r(TMP2); \ } else { \ XPush_c(GET_PC()); \ } \ label(code->runtime_error); \ } #define get_var_r(reg,v) { \ switch( v ) { \ case VThis: \ XMov_rp(reg,VM,VMFIELD(vthis)); \ break; \ case VEnv: \ XMov_rp(reg,VM,VMFIELD(env)); \ break; \ case VModule: \ XMov_rp(reg,VM,VMFIELD(jit_val)); \ break; \ case VVm: \ XMov_rr(reg,VM); \ break; \ case VSpMax: \ XMov_rp(reg,VM,VMFIELD(spmax)); \ break; \ case VTrap: \ XMov_rp(reg,VM,VMFIELD(trap)); \ break; \ default: \ ERROR; \ break; \ } \ } #define get_var_p(reg,idx,v) { \ switch( v ) { \ case VThis: \ XMov_rp(TMP,VM,VMFIELD(vthis)); \ XMov_pr(reg,idx,TMP); \ break; \ case VEnv: \ XMov_rp(TMP,VM,VMFIELD(env)); \ XMov_pr(reg,idx,TMP); \ break; \ case VModule: \ XMov_rp(TMP,VM,VMFIELD(jit_val)); \ XMov_pr(reg,idx,TMP); \ break; \ case VVm: \ XMov_pr(reg,idx,VM); \ break; \ case VSpMax: \ XMov_rp(TMP,VM,VMFIELD(spmax)); \ XMov_pr(reg,idx,TMP); \ break; \ case VTrap: \ XMov_rp(TMP,VM,VMFIELD(trap)); \ XMov_pr(reg,idx,TMP); \ break; \ default: \ ERROR; \ break; \ } \ } #define set_var_r(v,reg) { \ switch( v ) { \ case VThis: \ XMov_pr(VM,VMFIELD(vthis),reg); \ break; \ case VEnv: \ XMov_pr(VM,VMFIELD(env),reg); \ break; \ case VTrap: \ XMov_pr(VM,VMFIELD(trap),reg); \ break; \ case VModule: \ XMov_pr(VM,VMFIELD(jit_val),reg); \ break; \ default: \ ERROR; \ break; \ } \ } #define set_var_p(v,reg,idx) { \ switch( v ) { \ case VThis: \ XMov_rp(TMP,reg,idx); \ XMov_pr(VM,VMFIELD(vthis),TMP); \ break; \ case VEnv: \ XMov_rp(TMP,reg,idx); \ XMov_pr(VM,VMFIELD(env),TMP); \ break; \ case VTrap: \ XMov_rp(TMP,reg,idx); \ XMov_pr(VM,VMFIELD(trap),TMP); \ break; \ case VModule: \ XMov_rp(TMP,reg,idx); \ XMov_pr(VM,VMFIELD(jit_val),TMP); \ break; \ default: \ ERROR; \ break; \ } \ } #define jump(how,targ) { \ jlist *j = (jlist*)alloc(sizeof(jlist)); \ void *jcode; \ j->target = (int)((int_val*)(int_val)(targ) - ctx->module->code); \ j->next = ctx->jumps; \ ctx->jumps = j; \ XJump(how,jcode); \ j->pos = (int)((int_val)jcode - (int_val)ctx->baseptr); \ } #define setup_before_call(mode,is_callb) { \ push_infos(is_callb?CALLBACK:PC_ARG); \ if( !is_callb ) { XPush_r(ACC); } \ if( mode == THIS_CALL ) { \ set_var_p(VThis,SP,FIELD(0)); \ pop(1); \ } \ set_var_p(VEnv,ACC,FUNFIELD(env)); \ } #define restore_after_call(nargs,pad) { \ int *jok; \ XCmp_rc(ACC,0); \ XJump(JNeq,jok); \ XMov_rp(ACC,Esp,FIELD(nargs+PAD_OPT(pad))); \ XMov_rp(ACC,ACC,FUNFIELD(module)); \ stack_pad(-1); \ XPush_r(ACC); \ XCall_m(val_throw); \ PATCH_JUMP(jok); \ stack_pop_pad(1+nargs,pad); \ pop_infos(); \ } #define NARGS (CALL_MAX_ARGS + 1) #define MAX_ENV 8 typedef struct { char *boot; char *stack_expand; char *runtime_error; char *call_normal_jit[NARGS]; char *call_this_jit[NARGS]; char *call_tail_jit[NARGS]; char *call_normal_prim[NARGS]; char *call_this_prim[NARGS]; char *call_tail_prim[NARGS]; char *call_normal_fun[NARGS]; char *call_this_fun[NARGS]; char *call_tail_fun[NARGS]; char *make_env[MAX_ENV]; char *make_env_n; char *oo_get; char *oo_set; char *handle_trap; char *invalid_access; } jit_code; char *jit_boot_seq = NULL; char *jit_handle_trap = NULL; static jit_code *code; static value *strings; static const char *cstrings[] = { "Stack overflow", // 0 "Reading Outside Env", // 1 "Writing Outside Env", // 2 "Invalid call", // 3 "Invalid array access", // 4 "Invalid field access", // 5 "Invalid environment", // 6 "Invalid operation (%)", // 7 "$apply", // 8 "Invalid End Trap", // 9 "$hash", // 10 }; #define DEFINE_PROC(p,arg) ctx->buf = buf; jit_##p(ctx,arg); buf = ctx->buf #define push_infos(arg) DEFINE_PROC(push_infos,arg) #define test(arg) DEFINE_PROC(test,arg) #define call(mode,nargs) ctx->buf = buf; jit_call(ctx,mode,nargs); buf = ctx->buf #define number_op(arg) DEFINE_PROC(number_op,arg) #define array_access(p) DEFINE_PROC(array_access,p) #define int_op(arg) DEFINE_PROC(int_op,arg) #define best_int() DEFINE_PROC(best_int,0) #ifdef STACK_ALIGN_DEBUG #include static void debug_method_call( int line, int stack ) { printf("Stack align error line %d (%d)\n" , line ,stack); exit(-1); } #endif #ifdef JIT_DEBUG static void val_print_2( value v ) { val_print(alloc_string(" ")); val_print(v); } static void val_print_3( value v ) { val_print_2(v); val_print(alloc_string("\n")); } #endif static jit_ctx *jit_init_context( void *ptr, int size ) { jit_ctx *c = (jit_ctx*)alloc(sizeof(jit_ctx)); c->size = size; c->baseptr = ptr; c->buf.p = ptr; c->pos = NULL; c->curpc = 0; c->debug_wait = 0; c->jumps = NULL; c->traps = NULL; return c; } static void jit_finalize_context( jit_ctx *ctx ) { jlist *l; int nbytes = POS(); if( nbytes == 0 || nbytes > ctx->size ) *(int*)0xAABBCC = 0; l = ctx->jumps; while( l != NULL ) { *(int*)((char*)ctx->baseptr + l->pos) = ctx->pos[l->target] - (l->pos + 4); l = l->next; } l = ctx->traps; while( l != NULL ) { *(int*)((char*)ctx->baseptr + l->pos) = ctx->pos[l->target] + (int)(int_val)ctx->baseptr; l = l->next; } } static void jit_push_infos( jit_ctx *ctx, enum PushInfosMode callb ) { INIT_BUFFER; stack_push(CSP,4); if( callb == CALLBACK ) { XMov_pc(CSP,FIELD(-3),CONST(callback_return)); get_var_p(CSP,FIELD(-2),VEnv); get_var_p(CSP,FIELD(-1),VThis); XMov_pc(CSP,FIELD(0),0); } else { if( callb == PC_CUR ) { XMov_pc(CSP,FIELD(-3),GET_PC()); } else { // PC_ARG : on the stack XMov_rp(TMP2,Esp,FIELD(1)); XMov_pr(CSP,FIELD(-3),TMP2); } get_var_p(CSP,FIELD(-2),VEnv); get_var_p(CSP,FIELD(-1),VThis); get_var_p(CSP,FIELD(0),VModule) } END_BUFFER; } static void jit_best_int( jit_ctx *ctx, int _ ) { int *wrap; char *jend; INIT_BUFFER; XMov_rr(TMP,ACC); XShl_rc(ACC,1); XJump(JOverflow,wrap); XOr_rc(ACC,1); XJump_near(jend); PATCH_JUMP(wrap); XPush_r(TMP); XCall_m(alloc_int32); stack_pop(Esp,1); PATCH_JUMP(jend); END_BUFFER; } #define pop_infos() { \ set_var_p(VModule,CSP,FIELD(0)); \ set_var_p(VThis,CSP,FIELD(-1)); \ set_var_p(VEnv,CSP,FIELD(-2)); \ XMov_pc(CSP,FIELD(0),0); \ XMov_pc(CSP,FIELD(-1),0); \ XMov_pc(CSP,FIELD(-2),0); \ XMov_pc(CSP,FIELD(-3),0); \ stack_pop(CSP,4); \ } static void jit_boot( jit_ctx *ctx, void *_ ) { INIT_BUFFER; XPush_r(Ebp); XPush_r(Ebx); XPush_r(Esi); # ifdef STACK_ALIGN_DEBUG XMov_rr(Ebp,Esp); // ALIGNED STACK # endif XPush_r(Edi); XMov_rp(VM,Esp,FIELD(5)); get_var_r(TMP,VModule); XPush_r(TMP); set_var_p(VModule,Esp,FIELD(9)); XMov_rp(TMP,Esp,FIELD(7)); XMov_rp(ACC,Esp,FIELD(8)); end_call(); XCall_r(TMP); begin_call(); XPop_r(TMP); set_var_r(VModule,TMP); XPop_r(Edi); XPop_r(Esi); XPop_r(Ebx); XPop_r(Ebp); XRet(); END_BUFFER; } static void jit_trap( jit_ctx *ctx, int n ) { INIT_BUFFER; XMov_rp(VM,Esp,FIELD(1)); get_var_r(Ebp,VThis); // restore vm stack_pad(3); XPush_r(VM); XCall_m(neko_process_trap); stack_pop_pad(1,3); // restore registers end_call(); XMov_rr(ACC,Ebp); XMov_rp(Ebp,VM,VMFIELD(start)+FIELD(1)); XMov_rp(Esp,VM,VMFIELD(start)+FIELD(2)); XMov_rp(TMP2,VM,VMFIELD(start)+FIELD(3)); // restore vm jmp_buf XPop_r(TMP); XMov_pr(VM,VMFIELD(start)+FIELD(3),TMP); XPop_r(TMP); XMov_pr(VM,VMFIELD(start)+FIELD(2),TMP); XPop_r(TMP); XMov_pr(VM,VMFIELD(start)+FIELD(1),TMP); XPop_r(TMP); XMov_pr(VM,VMFIELD(start),TMP); XPush_r(TMP2); XRet(); END_BUFFER; } static void jit_stack_expand( jit_ctx *ctx, int _ ) { int *jresize, *jdone; int max = MAX_STACK_PER_FUNCTION; INIT_BUFFER; stack_push(CSP,max); XCmp_rr(SP,CSP); XJump(JLt,jresize); stack_pop(CSP,max); XRet(); PATCH_JUMP(jresize); stack_pop(CSP,max); XPush_r(ACC); XPush_r(VM); XPush_r(CSP); XPush_r(SP); XCall_m(neko_stack_expand); XCmp_rb(ACC,0); XJump(JNeq,jdone); stack_pad(-1); XPush_c(CONST(strings[0])); // Stack overflow XCall_m(val_throw); PATCH_JUMP(jdone); XMov_rp(ACC,Esp,FIELD(3)); end_call(); stack_pop(Esp,4); XRet(); END_BUFFER; } static void jit_runtime_error( jit_ctx *ctx, void *unused ) { INIT_BUFFER; push_infos(PC_ARG); // pc begin_call(); XMov_rp(TMP,Esp,FIELD(2)); // msg on stack XPush_r(TMP); XCall_m(val_throw); END_BUFFER; } static void jit_invalid_access( jit_ctx *ctx, int _ ) { INIT_BUFFER; int *jnext; // if( val_field_name(f) == val_null ) RuntimeError("Invalid field access") stack_pad(1); XMov_rp(TMP,Esp,FIELD(2)); // field XPush_r(TMP); XCall_m(val_field_name); stack_pop_pad(1,1); XCmp_rc(ACC,CONST(val_null)); XJump(JNeq,jnext); runtime_error(5,true); // else { // b = alloc_buffer("Invalid field access : "); PATCH_JUMP(jnext); XPush_r(ACC); XPush_c(CONST("Invalid field access : ")); XCall_m(alloc_buffer); stack_pop(Esp,1); // val_buffer(b,v); XPush_r(ACC); XCall_m(val_buffer); // buffer_to_string(b); XCall_m(buffer_to_string); stack_pop(Esp,2); push_infos(PC_ARG); // pc begin_call(); XPush_r(ACC); XCall_m(val_throw); END_BUFFER; } static void jit_test( jit_ctx *ctx, int how ) { INIT_BUFFER; int *jnot1, *jnot2; char *jend; // call val_compare(sp[0],acc) XPush_r(ACC); XMov_rp(TMP,SP,FIELD(0)); XPush_r(TMP); begin_call(); XCall_m(val_compare); end_call(); stack_pop(Esp,2); pop(1); // test ok and != invalid_comparison XCmp_rc(ACC,0); XJump(how,jnot1); XCmp_rc(ACC,invalid_comparison); XJump(JEq,jnot2); XMov_rc(ACC,CONST(val_true)); XJump_near(jend); PATCH_JUMP(jnot1); PATCH_JUMP(jnot2); XMov_rc(ACC,CONST(val_false)); PATCH_JUMP(jend); END_BUFFER; } static void jit_call( jit_ctx *ctx, int mode, int nargs ) { INIT_BUFFER; int *jerr, *jother, *jerr2; char *jend1, *jend2, *jend3; // if( is_int ) : error is_int(ACC,1,jerr); // if( type == jit ) XMov_rp(TMP,ACC,FUNFIELD(t)); XCmp_rb(TMP,VAL_JITFUN); XJump(JNeq,jother); XPush_c(GET_PC()); switch( mode ) { case NORMAL: label(code->call_normal_jit[nargs]); break; case THIS_CALL: label(code->call_this_jit[nargs]); break; case TAIL_CALL: label(code->call_tail_jit[nargs]); break; } if( mode == TAIL_CALL ) jend1 = NULL; else { XJump_near(jend1); } // else if( type == prim ) PATCH_JUMP(jother); XCmp_rb(TMP,VAL_PRIMITIVE); XJump(JNeq,jother); XPush_c(GET_PC()); switch( mode ) { case NORMAL: label(code->call_normal_prim[nargs]); break; case THIS_CALL: label(code->call_this_prim[nargs]); break; case TAIL_CALL: label(code->call_tail_prim[nargs]); break; } XJump_near(jend2); // else if( type == function ) PATCH_JUMP(jother); XCmp_rb(TMP,VAL_FUNCTION); XJump(JNeq,jerr2); XPush_c(GET_PC()); switch( mode ) { case NORMAL: label(code->call_normal_fun[nargs]); break; case THIS_CALL: label(code->call_this_fun[nargs]); break; case TAIL_CALL: label(code->call_tail_fun[nargs]); break; } XJump_near(jend3); // else error PATCH_JUMP(jerr); PATCH_JUMP(jerr2); runtime_error(3,false); // Invalid call // end PATCH_JUMP(jend1); PATCH_JUMP(jend2); PATCH_JUMP(jend3); stack_pop(Esp,1); // pushed pc END_BUFFER; } static void jit_call_jit( jit_ctx *ctx, int nargs, int mode ) { INIT_BUFFER; int *jerr; // check arg count XMov_rp(TMP,ACC,FUNFIELD(nargs)); XCmp_rb(TMP,nargs); XJump(JNeq,jerr); if( mode == TAIL_CALL ) { // pop PC and EIP from the stack stack_pop(Esp,2); set_var_p(VModule,ACC,FUNFIELD(module)); set_var_p(VEnv,ACC,FUNFIELD(env)); XMov_rp(TMP,ACC,FUNFIELD(addr)); XJump_r(TMP); } else { push_infos(PC_ARG); set_var_p(VModule,ACC,FUNFIELD(module)); set_var_p(VEnv,ACC,FUNFIELD(env)); if( mode == THIS_CALL ) { set_var_p(VThis,SP,FIELD(0)); pop(1); } XMov_rp(TMP,ACC,FUNFIELD(addr)); stack_pad(1); XCall_r(TMP); stack_pad(-1); pop_infos(); XRet(); } PATCH_JUMP(jerr); runtime_error(3,true); // Invalid call END_BUFFER; } static void jit_call_prim( jit_ctx *ctx, int nargs, int mode ) { INIT_BUFFER; int *jvararg, *jerr; int i; # ifdef STACK_ALIGN int pad_size = 4 - ((2+nargs)%4); # endif // check arg count XMov_rp(TMP,ACC,FUNFIELD(nargs)); XCmp_rb(TMP,nargs); XJump(JNeq,jvararg); // push args from VMSP to PROCSP setup_before_call(mode,false); stack_pad(pad_size); for(i=0;isp,vm->csp,vm) ) val_throw(alloc_string("Stack Overflow")) #define ERASE 0 #define ACC_BACKUP #define ACC_RESTORE #define PushInfos() \ if( vm->csp + 4 >= vm->sp ) STACK_EXPAND; \ *++vm->csp = (int_val)pc; \ *++vm->csp = (int_val)vm->env; \ *++vm->csp = (int_val)vm->vthis; \ *++vm->csp = (int_val)vm->jit_val; #define PopInfos(restpc) \ vm->jit_val = (void*)*vm->csp; \ *vm->csp-- = ERASE; \ vm->vthis = (value)*vm->csp; \ *vm->csp-- = ERASE; \ vm->env = (value)*vm->csp; \ *vm->csp-- = ERASE; \ if( restpc ) pc = (int)*vm->csp; \ *vm->csp-- = ERASE; #define BeginCall() #define EndCall() #define RuntimeError(err) { PushInfos(); BeginCall(); val_throw(alloc_string(err)); } #define ObjectOpGen(obj,param,id,err) { \ value _o = (value)obj; \ value _arg = (value)param; \ value _f = val_field(_o,id); \ if( _f == val_null ) { \ err; \ } else { \ PushInfos(); \ BeginCall(); \ acc = (int_val)val_callEx(_o,_f,&_arg,1,NULL); \ EndCall(); \ PopInfos(false); \ } \ } #define ObjectOp(obj,param,id) ObjectOpGen(obj,param,id,RuntimeError("Unsupported operation")) #define OpError(op) RuntimeError("Invalid operation (" op ")") static int_val generic_add( neko_vm *vm, int_val acc, int_val sp, int pc ) { if( acc & 1 ) { if( val_tag(sp) == VAL_FLOAT ) acc = (int_val)alloc_float(val_float(sp) + val_int(acc)); else if( val_tag(sp) == VAL_INT32 ) acc = (int_val)alloc_best_int(val_int32(sp) + val_int(acc)); else if( val_short_tag(sp) == VAL_STRING ) acc = (int_val)neko_append_int(vm,(value)sp,val_int(acc),true); else if( val_tag(sp) == VAL_OBJECT ) ObjectOp(sp,acc,id_add) else OpError("+"); } else if( sp & 1 ) { if( val_tag(acc) == VAL_FLOAT ) acc = (int_val)alloc_float(val_int(sp) + val_float(acc)); else if( val_tag(acc) == VAL_INT32 ) acc = (int_val)alloc_best_int(val_int(sp) + val_int32(acc)); else if( val_short_tag(acc) == VAL_STRING ) acc = (int_val)neko_append_int(vm,(value)acc,val_int(sp),false); else if( val_tag(acc) == VAL_OBJECT ) ObjectOp(acc,sp,id_radd) else OpError("+"); } else if( val_tag(acc) == VAL_FLOAT ) { if( val_tag(sp) == VAL_FLOAT ) acc = (int_val)alloc_float(val_float(sp) + val_float(acc)); else if( val_tag(sp) == VAL_INT32 ) acc = (int_val)alloc_float(val_int32(sp) + val_float(acc)); else goto add_next; } else if( val_tag(acc) == VAL_INT32 ) { if( val_tag(sp) == VAL_INT32 ) acc = (int_val)alloc_best_int(val_int32(sp) + val_int32(acc)); else if( val_tag(sp) == VAL_FLOAT ) acc = (int_val)alloc_float(val_float(sp) + val_int32(acc)); else goto add_next; } else { add_next: if( val_tag(sp) == VAL_OBJECT ) ObjectOpGen(sp,acc,id_add,goto add_2) else { add_2: if( val_tag(acc) == VAL_OBJECT ) ObjectOpGen(acc,sp,id_radd,goto add_3) else { add_3: if( val_short_tag(acc) == VAL_STRING || val_short_tag(sp) == VAL_STRING ) { ACC_BACKUP buffer b = alloc_buffer(NULL); BeginCall(); val_buffer(b,(value)sp); ACC_RESTORE; val_buffer(b,(value)acc); EndCall(); acc = (int_val)buffer_to_string(b); } else OpError("+"); } } } return acc; } #define NumberOp(op,fop,id_op,id_rop) \ if( acc & 1 ) { \ if( val_tag(sp) == VAL_FLOAT ) \ acc = (int_val)alloc_float(fop(val_float(sp),val_int(acc))); \ else if( val_tag(sp) == VAL_INT32 ) \ acc = (int_val)alloc_best_int(val_int32(sp) op val_int(acc)); \ else if( val_tag(sp) == VAL_OBJECT ) \ ObjectOp(sp,acc,id_op) \ else \ OpError(#op); \ } else if( sp & 1 ) { \ if( val_tag(acc) == VAL_FLOAT ) \ acc = (int_val)alloc_float(fop(val_int(sp),val_float(acc))); \ else if( val_tag(acc) == VAL_INT32 ) \ acc = (int_val)alloc_best_int(val_int(sp) op val_int32(acc)); \ else if( val_tag(acc) == VAL_OBJECT ) \ ObjectOp(acc,sp,id_rop) \ else \ OpError(#op); \ } else if( val_tag(acc) == VAL_FLOAT ) { \ if( val_tag(sp) == VAL_FLOAT ) \ acc = (int_val)alloc_float(fop(val_float(sp),val_float(acc))); \ else if( val_tag(sp) == VAL_INT32 ) \ acc = (int_val)alloc_float(fop(val_int32(sp),val_float(acc))); \ else \ goto id_op##_next; \ } else if( val_tag(acc) == VAL_INT32 ) {\ if( val_tag(sp) == VAL_INT32 ) \ acc = (int_val)alloc_best_int(val_int32(sp) op val_int32(acc)); \ else if( val_tag(sp) == VAL_FLOAT ) \ acc = (int_val)alloc_float(fop(val_float(sp),val_int32(acc))); \ else \ goto id_op##_next; \ } else { \ id_op##_next: \ if( val_tag(sp) == VAL_OBJECT ) \ ObjectOpGen(sp,acc,id_op,goto id_op##_next2) \ else { \ id_op##_next2: \ if( val_tag(acc) == VAL_OBJECT ) \ ObjectOp(acc,sp,id_rop) \ else \ OpError(#op); \ } \ } #define SUB(x,y) ((x) - (y)) #define MULT(x,y) ((x) * (y)) #define DIV(x,y) ((x) / (y)) #define GENERIC_OP(id,op,fop) \ static int_val generic_##id( neko_vm *vm, int_val acc, int_val sp, int pc ) { \ NumberOp(op,fop,id_##id,id_r##id); \ return acc; \ } GENERIC_OP(sub,-,SUB); GENERIC_OP(mult,*,MULT); static int_val generic_div( neko_vm *vm, int_val acc, int_val sp, int pc ) { if( val_is_number(acc) && val_is_number(sp) ) acc = (int_val)alloc_float( ((tfloat)val_number(sp)) / val_number(acc) ); else if( val_is_object(sp) ) ObjectOpGen(sp,acc,id_div,goto div_next) else { div_next: if( val_is_object(acc) ) ObjectOp(acc,sp,id_rdiv) else OpError("/"); } return acc; } static int_val generic_mod( neko_vm *vm, int_val acc, int_val sp, int pc ) { if( (acc == 1 || (val_is_int32(acc) && val_int32(acc)==0)) && val_is_any_int(sp) ) OpError("%"); NumberOp(%,fmod,id_mod,id_rmod); return acc; } #define GENERIC_IOP(id,op) \ static int_val generic_##id( neko_vm *vm, int_val acc, int_val sp, int pc ) { \ if( val_is_any_int(acc) && val_is_any_int(sp) ) \ acc = (int_val)alloc_best_int(val_any_int(sp) op val_any_int(acc)); \ else \ OpError(#op); \ return acc; \ } GENERIC_IOP(shl,<<); GENERIC_IOP(shr,>>); GENERIC_IOP(or,|); GENERIC_IOP(and,&); GENERIC_IOP(xor,^); static int_val generic_ushr( neko_vm *vm, int_val acc, int_val sp, int pc ) { if( val_is_any_int(acc) && val_is_any_int(sp) ) acc = (int_val)alloc_best_int( ((unsigned int)val_any_int(sp)) >> val_any_int(acc)); else OpError(">>>"); return acc; } // -------------------------------------------- // we only inline operations for (int,int) and (float,float) // other cases are handled by a single generic_op primitive // through a small jit_generic_* wrapper static void jit_number_op( jit_ctx *ctx, enum Operation op ) { INIT_BUFFER; int *jnot_int, *jnot_int2, *jint, *jnot_float1, *jnot_float2, *jmod0; char *jend, *jend2, *jdiv = NULL; // tmp = acc XMov_rr(TMP,ACC); // acc = *sp XMov_rp(ACC,SP,FIELD(0)); // is_int(acc) && is_int(sp) is_int(ACC,false,jnot_int); is_int(TMP,false,jnot_int2); XShr_rc(ACC,1); XShr_rc(TMP,1); switch( op ) { case OP_ADD: XAdd_rr(ACC,TMP); break; case OP_SUB: XSub_rr(ACC,TMP); break; case OP_MUL: XIMul_rr(ACC,TMP); break; case OP_MOD: XCmp_rc(TMP,0); XJump(JNeq,jmod0); runtime_error(7,false); PATCH_JUMP(jmod0); XCdq(); XIDiv_r(TMP); XMov_rr(ACC,Edx); break; case OP_DIV: XPush_r(ACC); XFILd_i(Esp); XPush_r(TMP); XFILd_i(Esp); stack_pop(Esp,2); XJump_near(jdiv); break; default: ERROR; break; } best_int(); XJump_near(jend); // is_float(acc) && is_float(sp) PATCH_JUMP(jnot_int); XMov_rp(TMP2,ACC,FIELD(0)); XCmp_rb(TMP2,VAL_FLOAT); XJump(JNeq,jnot_float1); is_int(TMP,true,jint); XMov_rp(TMP2,TMP,FIELD(0)); XCmp_rb(TMP2,VAL_FLOAT); XJump(JNeq,jnot_float2); // load floats XAdd_rc(ACC,4); XFLd_i(ACC); XAdd_rc(TMP,4); XFLd_i(TMP); switch( op ) { case OP_ADD: XFAddp(); break; case OP_SUB: XFSubp(); break; case OP_DIV: PATCH_JUMP(jdiv); XFDivp(); break; case OP_MUL: XFMulp(); break; case OP_MOD: stack_push(Esp,2); XFStp_i(Esp); stack_push(Esp,2); XFStp_i(Esp); XCall_m(fmod); stack_pop(Esp,2); break; default: ERROR; break; } if( op != OP_MOD ) { stack_push(Esp,2); } XFStp_i(Esp); XCall_m(alloc_float); stack_pop(Esp,2); XJump_near(jend2); // else... PATCH_JUMP(jint); PATCH_JUMP(jnot_float1); PATCH_JUMP(jnot_float2); PATCH_JUMP(jnot_int2); begin_call(); XPush_c(GET_PC()); XPush_r(ACC); XPush_r(TMP); XPush_r(VM); switch( op ) { case OP_ADD: XCall_m(generic_add); break; case OP_SUB: XCall_m(generic_sub); break; case OP_DIV: XCall_m(generic_div); break; case OP_MUL: XCall_m(generic_mult); break; case OP_MOD: XCall_m(generic_mod); break; case OP_GET: case OP_SET: case OP_LAST: // not used here break; } stack_pop(Esp,4); end_call(); PATCH_JUMP(jend); PATCH_JUMP(jend2); pop(1); END_BUFFER; } static void jit_int_op( jit_ctx *ctx, enum IOperation op ) { INIT_BUFFER; int *jerr1, *jerr2; char *jend; XMov_rr(TMP,ACC); XMov_rp(ACC,SP,FIELD(0)); is_int(ACC,false,jerr1); is_int(TMP,false,jerr2); XShr_rc(TMP,1); XShr_rc(ACC,1); switch( op ) { case IOP_SHL: XShl_rr(ACC,TMP); break; case IOP_SHR: XShr_rr(ACC,TMP); break; case IOP_USHR: XUShr_rr(ACC,TMP); break; case IOP_AND: XAnd_rr(ACC,TMP); break; case IOP_OR: XOr_rr(ACC,TMP); break; case IOP_XOR: XXor_rr(ACC,TMP); break; default: ERROR; } best_int(); XJump_near(jend); PATCH_JUMP(jerr1); PATCH_JUMP(jerr2); begin_call(); XPush_c(GET_PC()); XPush_r(ACC); // acc and tmp are reversed in jit_number_op XPush_r(TMP); // XPush_r(VM); switch( op ) { case IOP_SHL: XCall_m(generic_shl); break; case IOP_SHR: XCall_m(generic_shr); break; case IOP_USHR: XCall_m(generic_ushr); break; case IOP_AND: XCall_m(generic_and); break; case IOP_OR: XCall_m(generic_or); break; case IOP_XOR: XCall_m(generic_xor); break; case IOP_LAST: // nothing break; } stack_pop(Esp,4); end_call(); PATCH_JUMP(jend); pop(1); END_BUFFER; } static void jit_array_access( jit_ctx *ctx, int n ) { INIT_BUFFER; int *jerr1, *jerr2; char *jend1, *jend2 = NULL, *jend3; int *jnot_array, *jbounds = NULL; is_int(ACC,true,jerr1); XMov_rp(TMP,ACC,0); XMov_rr(TMP2,TMP); XAnd_rc(TMP2,TAG_MASK); XCmp_rb(TMP2,VAL_ARRAY); XJump(JNeq,jnot_array); if( n > 0 ) { XUShr_rc(TMP,TAG_BITS); XCmp_rc(TMP,n); XJump(JLte,jbounds); } XMov_rp(ACC,ACC,FIELD(n + 1)); XJump_near(jend1); if( n > 0 ) { PATCH_JUMP(jbounds); XMov_rc(ACC,CONST(val_null)); XJump_near(jend2); } PATCH_JUMP(jnot_array); XCmp_rb(TMP2,VAL_OBJECT); XJump(JNeq,jerr2); XPush_c(GET_PC()); XMov_rr(TMP,ACC); XMov_rc(ACC,CONST(alloc_int(n))); label(code->oo_get); stack_pop(Esp,1); XJump_near(jend3); PATCH_JUMP(jerr1); PATCH_JUMP(jerr2); runtime_error(4,false); PATCH_JUMP(jend1); PATCH_JUMP(jend2); PATCH_JUMP(jend3); END_BUFFER; } static void jit_make_env( jit_ctx *ctx, int esize ) { INIT_BUFFER; int *jerr1, *jerr2, *jok; int i; if( esize == -1 ) { XMov_rr(TMP2,TMP); // store esize } // check type t_function or t_jit is_int(ACC,true,jerr1); XMov_rp(TMP,ACC,FUNFIELD(t)); XCmp_rb(TMP,VAL_JITFUN); XJump(JEq,jok); XCmp_rb(TMP,VAL_FUNCTION); XJump(JNeq,jerr2); PATCH_JUMP(jok); // prepare args for alloc_module_function XPush_r(TMP); // acc->type stack_push(Esp,1); // empty cell stack_pad(2); XMov_rp(TMP,ACC,FUNFIELD(nargs)); XPush_r(TMP); XMov_rp(TMP,ACC,FUNFIELD(addr)); XPush_r(TMP); XMov_rp(TMP,ACC,FUNFIELD(module)); XPush_r(TMP); // call alloc_array(n) stack_pad(3); if( esize == -1 ) { XPush_r(TMP2); } else { XPush_c(esize); } XCall_m(alloc_array); if( esize == -1 ) { char *start; int *loop; XPop_r(TMP2); stack_pad(-3); // fill array start = buf.c; XMov_rp(TMP,SP,FIELD(0)); XMov_xr(ACC,TMP2,4,TMP); XMov_pc(SP,FIELD(0),0); stack_pop(SP,1); XSub_rc(TMP2,1); XCmp_rc(TMP2,0); XJump(JNeq,loop); *loop = (int)(start - buf.c); } else { stack_pop_pad(1,3); // fill array for(i=0;ioo_get); stack_pop(Esp,1); XJump_near(jend3); // check int32 index (with array) PATCH_JUMP(jerr2); XMov_rp(TMP2,ACC,FIELD(0)); XCmp_rb(TMP2,VAL_INT32); XJump(JNeq,jerr4); XMov_rc(ACC,CONST(val_null)); XJump_near(jend4); PATCH_JUMP(jerr1); PATCH_JUMP(jerr3); PATCH_JUMP(jerr4); runtime_error(4,false); // Invalid array access PATCH_JUMP(jend1); PATCH_JUMP(jend2); PATCH_JUMP(jend3); PATCH_JUMP(jend4); break; } case AccIndex: array_access(p); break; case AccIndex0: array_access(0); break; case AccIndex1: array_access(1); break; case AccField: { int *jerr1, *jerr2, *jend1, *loop, *no_resolver; char *jend2, *jend3, *start; is_int(ACC,true,jerr1); XMov_rp(TMP,ACC,FIELD(0)); XCmp_rb(TMP,VAL_OBJECT); XJump(JNeq,jerr2); XPush_r(ACC); XPush_r(VM); stack_pad(1); XMov_rr(VM,ACC); XPush_c(p); start = buf.c; XMov_rr(TMP,VM); XAdd_rc(TMP,FIELD(1)); XPush_r(TMP); XCall_m(otable_find); XCmp_rc(ACC,0); XJump(JNeq,jend1); stack_pop(Esp,1); XMov_rp(VM,VM,FIELD(3)); // acc = acc->proto XCmp_rc(VM,0); XJump(JNeq,loop); *loop = (int)(start - buf.c); stack_pop_pad(1,1); XPop_r(VM); XPop_r(ACC); XMov_rp(TMP,VM,VMFIELD(resolver)); XCmp_rc(TMP,0); XJump(JEq,no_resolver); XPush_c(CONST(alloc_int(p))); XPush_r(ACC); XPush_r(TMP); begin_call(); XCall_m(val_call2); end_call(); stack_pop(Esp,3); XJump_near(jend3); PATCH_JUMP(no_resolver); XMov_rc(ACC,CONST(val_null)); XJump_near(jend2); PATCH_JUMP(jerr1); PATCH_JUMP(jerr2); XPush_c(p); XPush_c(GET_PC()); label(code->invalid_access); PATCH_JUMP(jend1); stack_pop_pad(2,2); XPop_r(VM); stack_pop(Esp,1); XMov_rp(ACC,ACC,FIELD(0)); PATCH_JUMP(jend2); PATCH_JUMP(jend3); break; } case SetStack: XMov_pr(SP,FIELD(p),ACC); break; case SetGlobal: XMov_ar(CONST(p),ACC); break; case SetEnv: get_var_r(TMP,VEnv); XMov_rp(TMP2,TMP,FIELD(0)); XCmp_rc(TMP2,(p << TAG_BITS) | VAL_ARRAY); XJump(JGt,jok); runtime_error(2,false); // Writing Outside Env PATCH_JUMP(jok); XMov_pr(TMP,FIELD(p+1),ACC); // val_array_ptr(env)[p] = acc break; case SetThis: set_var_r(VThis,ACC); break; case SetField: { int *jerr1, *jerr2; char *jend; XMov_rp(TMP,SP,FIELD(0)); is_int(TMP,true,jerr1); XMov_rp(TMP2,TMP,FIELD(0)); XCmp_rb(TMP2,VAL_OBJECT); XJump(JNeq,jerr2); // call otable_replace(table,field,acc) stack_pad(2); XPush_r(ACC); XPush_c(p); XAdd_rc(TMP,FIELD(1)); XPush_r(TMP); XCall_m(otable_replace); stack_pop(Esp,3); XMov_rp(ACC,Esp,FIELD(-1)); stack_pad(-2); XJump_near(jend); PATCH_JUMP(jerr1); PATCH_JUMP(jerr2); runtime_error(5,false); PATCH_JUMP(jend); pop(1); break; } case SetArray: { int *jerr1, *jerr2, *jerr3, *jnot_array, *jend1, *jend4; char *jend2, *jend3; XMov_rp(TMP,SP,FIELD(0)); // sp[0] : array/object is_int(TMP,true,jerr1); XMov_rp(TMP2,TMP,FIELD(0)); XAnd_rc(TMP2,TAG_MASK); XCmp_rb(TMP2,VAL_ARRAY); XJump(JNeq,jnot_array); XMov_rp(TMP2,SP,FIELD(1)); // sp[1] : index is_int(TMP2,false,jerr2); XMov_rp(TMP,TMP,FIELD(0)); // tmp = tmp->type XShr_rc(TMP2,1); XUShr_rc(TMP,TAG_BITS); XCmp_rr(TMP2,TMP); XJump(JGte,jend1); XMov_rp(TMP,SP,FIELD(0)); XAdd_rc(TMP2,1); XMov_xr(TMP,TMP2,4,ACC); XJump_near(jend2); PATCH_JUMP(jnot_array); XCmp_rb(TMP2,VAL_OBJECT); XJump(JNeq,jerr3); XMov_rp(TMP2,SP,FIELD(1)); // index XPush_r(TMP2); XPush_c(GET_PC()); label(code->oo_set); stack_pop(Esp,2); XJump_near(jend3); // check int32 index (with array) PATCH_JUMP(jerr2); XMov_rp(TMP2,TMP2,FIELD(0)); XCmp_rb(TMP2,VAL_INT32); XJump(JEq,jend4); PATCH_JUMP(jerr1); PATCH_JUMP(jerr3); runtime_error(4,false); PATCH_JUMP(jend1); PATCH_JUMP(jend2); PATCH_JUMP(jend3); PATCH_JUMP(jend4); pop(2); break; } case SetIndex: { int *jerr1, *jerr2, *jnot_array, *jend1; char *jend2, *jend3; XMov_rp(TMP,SP,FIELD(0)); // sp[0] : array / object pop(1); is_int(TMP,true,jerr1); XMov_rp(TMP2,TMP,FIELD(0)); XAnd_rc(TMP2,TAG_MASK); XCmp_rb(TMP2,VAL_ARRAY); XJump(JNeq,jnot_array); XMov_rp(TMP2,TMP,FIELD(0)); XCmp_rc(TMP2,(p << TAG_BITS) | VAL_ARRAY); // fake header XJump(JLte,jend1); XMov_pr(TMP,FIELD(p + 1),ACC); XJump_near(jend2); PATCH_JUMP(jnot_array); XCmp_rb(TMP2,VAL_OBJECT); XJump(JNeq,jerr2); XPush_c(CONST(alloc_int(p))); XPush_c(GET_PC()); label(code->oo_set); stack_pop(Esp,2); XJump_near(jend3); PATCH_JUMP(jerr1); PATCH_JUMP(jerr2); runtime_error(4,false); PATCH_JUMP(jend1); PATCH_JUMP(jend2); PATCH_JUMP(jend3); break; } case Push: stack_push(SP,1); XMov_pr(SP,FIELD(0),ACC); break; case Pop: if( p > 10 ) { pop_loop(p); } else { pop(p); } break; case Jump: jump(JAlways,p); break; case JumpIf: XCmp_rc(ACC,CONST(val_true)); jump(JEq,p); break; case JumpIfNot: XCmp_rc(ACC,CONST(val_true)); jump(JNeq,p); break; case Neq: { int *jnot1, *jnot2; char *jend; // call val_compare(sp[0],acc) XPush_r(ACC); XMov_rp(TMP,SP,FIELD(0)); XPush_r(TMP); begin_call(); XCall_m(val_compare); end_call(); stack_pop(Esp,2); pop(1); // test if ok and != invalid_comparison XCmp_rc(ACC,0); XJump(JNeq,jnot1); XCmp_rc(ACC,invalid_comparison); XJump(JEq,jnot2); XMov_rc(ACC,CONST(val_false)); XJump_near(jend); PATCH_JUMP(jnot1); PATCH_JUMP(jnot2); XMov_rc(ACC,CONST(val_true)); PATCH_JUMP(jend); break; } case Eq: test(JNeq); break; case Gt: test(JSignLte); break; case Gte: test(JSignLt); break; case Lt: test(JSignGte); break; case Lte: test(JSignGt); break; case Bool: case Not: { int *jfalse1, *jfalse2, *jfalse3; char *jend; XCmp_rc(ACC,CONST(val_false)); XJump(JEq,jfalse1); XCmp_rc(ACC,CONST(val_null)); XJump(JEq,jfalse2); XCmp_rc(ACC,CONST(alloc_int(0))); XJump(JEq,jfalse3); XMov_rc(ACC,CONST((op == Bool)?val_true:val_false)); XJump_near(jend); PATCH_JUMP(jfalse1); PATCH_JUMP(jfalse2); PATCH_JUMP(jfalse3); XMov_rc(ACC,CONST((op == Bool)?val_false:val_true)); PATCH_JUMP(jend); break; } case IsNull: { int *jnext; char *jend; XCmp_rc(ACC,CONST(val_null)); XJump(JNeq,jnext); XMov_rc(ACC,CONST(val_true)); XJump_near(jend); PATCH_JUMP(jnext); XMov_rc(ACC,CONST(val_false)); PATCH_JUMP(jend); break; } case IsNotNull: { int *jnext; char *jend; XCmp_rc(ACC,CONST(val_null)); XJump(JNeq,jnext); XMov_rc(ACC,CONST(val_false)); XJump_near(jend); PATCH_JUMP(jnext); XMov_rc(ACC,CONST(val_true)); PATCH_JUMP(jend); break; } case Call: call(NORMAL,p); break; case ObjCall: call(THIS_CALL,p); break; case TailCall: { int stack = (p >> 3); int nargs = (p & 7); int i = nargs; while( i > 0 ) { i--; XMov_rp(TMP,SP,FIELD(i)); XMov_pr(SP,FIELD(stack - nargs + i),TMP); } if( stack - nargs > 10 ) { pop_loop(stack - nargs); } else { pop(stack - nargs); } call(TAIL_CALL,nargs); // in case we return from a Primitive XRet(); } break; case Ret: if( p > 10 ) { pop_loop(p); } else { pop(p); } XRet(); break; case Add: number_op(OP_ADD); break; case Sub: number_op(OP_SUB); break; case Div: number_op(OP_DIV); break; case Mult: number_op(OP_MUL); break; case Mod: number_op(OP_MOD); break; case Shl: int_op(IOP_SHL); break; case Shr: int_op(IOP_SHR); break; case UShr: int_op(IOP_USHR); break; case And: int_op(IOP_AND); break; case Or: int_op(IOP_OR); break; case Xor: int_op(IOP_XOR); break; case New: XPush_r(ACC); XCall_m(alloc_object); stack_pop(Esp,1); break; case MakeArray: stack_pad(3); XPush_r(ACC); XPush_c(p + 1); XCall_m(alloc_array); XMov_rp(TMP,Esp,FIELD(1)); // tmp = saved acc XMov_pr(ACC,FIELD(1),TMP); // val_array_ptr(acc)[0] = tmp stack_pop_pad(2,3); if( p < 6 ) { i = 0; while( p > 0 ) { p--; i++; XMov_rp(TMP,SP,FIELD(p)); XMov_pr(ACC,FIELD(i + 1),TMP); XMov_pc(SP,FIELD(p),0); } stack_pop(SP,i); } else { char *start; int *loop; XMov_rc(TMP2,(p+1)); start = buf.c; XMov_rp(TMP,SP,FIELD(0)); XMov_pc(SP,FIELD(0),0); XMov_xr(ACC,TMP2,4,TMP); stack_pop(SP,1); XSub_rc(TMP2,1); XCmp_rc(TMP2,1); XJump(JNeq,loop); *loop = (int)(start - buf.c); } break; case MakeArray2: stack_pad(3); XPush_r(ACC); XPush_c(p + 1); XCall_m(alloc_array); XMov_rp(TMP,Esp,FIELD(1)); // tmp = saved acc XMov_pr(ACC,FIELD(p+1),TMP); // val_array_ptr(acc)[p] = tmp stack_pop_pad(2,3); if( p < 6 ) { i = 0; while( p > 0 ) { p--; i++; XMov_rp(TMP,SP,FIELD(p)); XMov_pr(ACC,FIELD(i),TMP); XMov_pc(SP,FIELD(p),0); } stack_pop(SP,i); } else { char *start; int *loop; XMov_rc(TMP2,p); start = buf.c; XMov_rp(TMP,SP,FIELD(0)); XMov_pc(SP,FIELD(0),0); XMov_xr(ACC,TMP2,4,TMP); stack_pop(SP,1); XSub_rc(TMP2,1); XCmp_rc(TMP2,0); XJump(JNeq,loop); *loop = (int)(start - buf.c); } break; case MakeEnv: XPush_c(GET_PC()); if( p >= MAX_ENV ) { XMov_rc(TMP,p); label(code->make_env_n); } else { label(code->make_env[p]); } stack_pop(Esp,1); break; case Last: XRet(); break; case Apply: { int *jerr1, *jerr2, *jnext, *jcall1, *jcall2, *jdone; char *jend, *start; is_int(ACC,true,jerr1); XMov_rp(TMP,ACC,FIELD(0)); XAnd_rc(TMP,TAG_MASK); XCmp_rb(TMP,VAL_FUNCTION); XJump(JNeq,jerr2); XMov_rp(TMP,ACC,FUNFIELD(nargs)); // what do we do depending of the number of args ? XCmp_rb(TMP,p); XJump(JSignGt,jnext); XJump(JEq,jcall1); XCmp_rb(TMP,VAR_ARGS); XJump(JEq,jcall2); PATCH_JUMP(jerr1); PATCH_JUMP(jerr2); runtime_error(8,false); // $apply // build the apply PATCH_JUMP(jnext); XPush_r(ACC); XPush_r(TMP); XAdd_rc(TMP,1); XPush_r(TMP); XCall_m(alloc_array); stack_pop(Esp,1); XPop_r(TMP); XPop_r(TMP2); // fill the env array XMov_pr(ACC,FIELD(1),TMP2); // env[0] = f i = p; while( i-- > 0 ) { // env[*pc-i] = sp[i] XMov_rp(TMP2,SP,FIELD(i)); XMov_pr(ACC,FIELD(1+p-i),TMP2); } pop(p); // fargs = fargs - *pc XSub_rc(TMP,p); // prepare stack for alloc_apply XPush_r(ACC); XPush_r(TMP); // fill the env array with null's XAdd_rc(ACC,(2+p) * 4 ); start = buf.c; XCmp_rb(TMP,0); XJump(JEq,jdone); XMov_pc(ACC,FIELD(0),CONST(val_null)); XAdd_rc(ACC,4); XSub_rc(TMP,1); // jump back to "start" { char *back; XJump_near(back); *back = (char)(start - (back + 1)); } // call alloc_apply PATCH_JUMP(jdone); XCall_m(neko_alloc_apply); stack_pop(Esp,2); XJump_near(jend); // direct call PATCH_JUMP(jcall1); PATCH_JUMP(jcall2); call(NORMAL,p); PATCH_JUMP(jend); break; } case Trap: { // save some vm->start on the stack XMov_rp(TMP,VM,VMFIELD(start)); XPush_r(TMP); XMov_rp(TMP,VM,VMFIELD(start)+FIELD(1)); XPush_r(TMP); XMov_rp(TMP,VM,VMFIELD(start)+FIELD(2)); XPush_r(TMP); XMov_rp(TMP,VM,VMFIELD(start)+FIELD(3)); XPush_r(TMP); // save magic, ebp , esp and ret_pc XMov_pc(VM,VMFIELD(start),CONST(jit_handle_trap)); XMov_pr(VM,VMFIELD(start)+FIELD(1),Ebp); XMov_pr(VM,VMFIELD(start)+FIELD(2),Esp); XMov_pc(VM,VMFIELD(start)+FIELD(3),-1); { jlist *t = (jlist*)alloc(sizeof(jlist)); ctx->buf = buf; t->pos = POS() - 4; t->target = (int)((int_val*)(int_val)p - ctx->module->code); t->next = ctx->traps; ctx->traps = t; } // neko_setup_trap(vm) XPush_r(ACC); stack_pad(3); XPush_r(VM); begin_call(); XCall_m(neko_setup_trap); end_call(); stack_pop(Esp,1); stack_pad(-3); XPop_r(ACC); break; } case EndTrap: { // check spmax - trap = sp get_var_r(TMP,VSpMax); get_var_r(TMP2,VTrap); XShl_rc(TMP2,2); XSub_rr(TMP,TMP2); XCmp_rr(TMP,SP); XJump(JEq,jok); runtime_error(9,false); // Invalid End Trap PATCH_JUMP(jok); // restore VM jmp_buf XPop_r(TMP); XMov_pr(VM,VMFIELD(start)+FIELD(3),TMP); XPop_r(TMP); XMov_pr(VM,VMFIELD(start)+FIELD(2),TMP); XPop_r(TMP); XMov_pr(VM,VMFIELD(start)+FIELD(1),TMP); XPop_r(TMP); XMov_pr(VM,VMFIELD(start),TMP); // trap = val_int(sp[5]) XMov_rp(TMP,SP,FIELD(5)); XShr_rc(TMP,1); set_var_r(VTrap,TMP); pop(6); break; } case TypeOf: { int *jnot_int; char *jend; is_int(ACC,false,jnot_int); XMov_rc(ACC,CONST(alloc_int(1))); // t_int != VAL_INT XJump_near(jend); PATCH_JUMP(jnot_int); XMov_rp(TMP,ACC,FIELD(0)); XAnd_rc(TMP,TAG_MASK); XMov_rc(TMP2,CONST(NEKO_TYPEOF)); XMov_rx(ACC,TMP2,TMP,4); PATCH_JUMP(jend); break; } case Compare: { int *jint; char *jend; // val_compare(sp[0],acc) XPush_r(ACC); XMov_rp(TMP,SP,FIELD(0)); XPush_r(TMP); begin_call(); XCall_m(val_compare); end_call(); stack_pop(Esp,2); XCmp_rc(ACC,invalid_comparison); XJump(JNeq,jint); XMov_rc(ACC,CONST(val_null)); XJump_near(jend); PATCH_JUMP(jint); XShl_rc(ACC,1); XOr_rc(ACC,1); PATCH_JUMP(jend); pop(1); break; } case PhysCompare: { int *jeq, *jlow; char *jend1, *jend2; XMov_rp(TMP,SP,FIELD(0)); pop(1); XCmp_rr(ACC,TMP); XJump(JEq,jeq); XJump(JSignLt,jlow); XMov_rc(ACC,CONST(alloc_int(-1))); XJump_near(jend1); PATCH_JUMP(jlow); XMov_rc(ACC,CONST(alloc_int(1))); XJump_near(jend2); PATCH_JUMP(jeq); XMov_rc(ACC,CONST(alloc_int(0))); PATCH_JUMP(jend1); PATCH_JUMP(jend2); break; } case Hash: { int *jerr1, *jerr2; char *jend; is_int(ACC,true,jerr1); XMov_rp(TMP,ACC,FIELD(0)); XAnd_rc(TMP,TAG_MASK); XCmp_rb(TMP,VAL_STRING); XJump(JNeq,jerr2); begin_call(); XAdd_rc(ACC,4); // val_string(acc) XPush_r(ACC); XCall_m(val_id); stack_pop(Esp,1); XShl_rc(ACC,1); XOr_rc(ACC,1); XJump_near(jend); PATCH_JUMP(jerr1); PATCH_JUMP(jerr2); runtime_error(10,false); // $hash PATCH_JUMP(jend); break; } case JumpTable: { int njumps = p / 2; int *jok1, *jok2; char *jnext1, *jnext2; is_int(ACC,true,jok1); XMov_rc(TMP2,njumps); XJump_near(jnext1); PATCH_JUMP(jok1); XCmp_rc(ACC,p); XJump(JLt,jok2); XMov_rc(TMP2,njumps); XJump_near(jnext2); PATCH_JUMP(jok2); XMov_rr(TMP2,ACC); XShr_rc(TMP2,1); PATCH_JUMP(jnext1); PATCH_JUMP(jnext2); get_var_r(TMP,VModule); // tmp = jit + tmp2 * 5 XMov_rp(TMP,TMP,FIELD(0)); // m->jit XAdd_rr(TMP,TMP2); XShl_rc(TMP2,2); XAdd_rr(TMP,TMP2); ctx->debug_wait = njumps; ctx->buf = buf; { int add_size = 6; int small_add_size = 3; int jump_rsize = 2; int delta = POS() + add_size + jump_rsize; if( IS_SBYTE(delta) ) delta += small_add_size - add_size; XAdd_rc(TMP,delta); XJump_r(TMP); } break; } case Loop: // nothing break; default: ERROR; } END_BUFFER; } #if defined(STACK_ALIGN_DEBUG) || defined(JIT_DEBUG) # define MAX_OP_SIZE 1000 # define MAX_BUF_SIZE 1000 #else # define MAX_OP_SIZE 298 // Apply(4) + label(stack_expand) # define MAX_BUF_SIZE 500 #endif #define FILL_BUFFER(f,param,ptr) \ { \ jit_ctx *ctx; \ char *buf = alloc_private(MAX_BUF_SIZE); \ int size; \ ctx = jit_init_context(buf,MAX_BUF_SIZE); \ f(ctx,param); \ size = POS(); \ buf = alloc_jit_mem(size); \ code->ptr = buf; \ memcpy(buf,ctx->baseptr,size); \ ctx->buf.p = buf + size; \ ctx->baseptr = buf; \ jit_finalize_context(ctx); \ } #ifdef USE_MMAP static void free_jit_mem( void *_p ) { int *p = (int*)_p - 1; munmap(p,*p); } static void free_jit_abstract( value v ) { free_jit_mem(val_data(v)); } static char *alloc_jit_mem( int size ) { int *p; // add space for size size += sizeof(int); // round to next page size += (4096 - size%4096); p = (int*)mmap(NULL,size,PROT_READ|PROT_WRITE|PROT_EXEC,(MAP_PRIVATE|MAP_ANON),-1,0); if( p == (int*)-1 ) { buffer b = alloc_buffer("Failed to allocate JIT memory "); val_buffer(b,alloc_int(size>>10)); val_buffer(b,alloc_string("KB")); val_throw(buffer_to_string(b)); } *p = size; return (char*)(p + 1); } #else # define alloc_jit_mem alloc_private #endif void neko_init_jit() { int nstrings = sizeof(cstrings) / sizeof(const char *); int i; strings = alloc_root(nstrings); for(i=0;iboot; jit_handle_trap = code->handle_trap; } void neko_free_jit() { # ifdef USE_MMAP int i; for(i=0;inglobals && !val_is_function(m->globals[k]) ) k++; if( k == m->nglobals ) { *faddr = -1; return 0; } *faddr = (int_val*)((vfunction*)m->globals[k])->addr - m->code; return k; } void neko_module_jit( neko_module *m ) { unsigned int i = 0; int_val faddr; unsigned int fcursor = next_function(m,0,&faddr); jit_ctx *ctx = jit_init_context(NULL,0); ctx->pos = (int*)tmp_alloc(sizeof(int)*(m->codesize + 1)); ctx->module = m; while( i <= m->codesize ) { enum OPCODE op = m->code[i]; int curpos = POS(); ctx->pos[i] = curpos; ctx->curpc = i + 2; // resize buffer if( curpos + MAX_OP_SIZE > ctx->size ) { int nsize = ctx->size ? (ctx->size * 4) / 3 : ((m->codesize + 1) * 20); char *buf2; if( nsize - curpos < MAX_OP_SIZE ) nsize = curpos + MAX_OP_SIZE; buf2 = tmp_alloc(nsize); memcpy(buf2,ctx->baseptr,curpos); tmp_free(ctx->baseptr); ctx->baseptr = buf2; ctx->buf.p = buf2 + curpos; ctx->size = nsize; } // begin of function : check stack overflow if( faddr == i ) { INIT_BUFFER; label(code->stack_expand); END_BUFFER; fcursor = next_function(m,fcursor+1,&faddr); } // --------- debug --------- # ifdef JIT_DEBUG if( ctx->debug_wait ) ctx->debug_wait--; else { INIT_BUFFER; XPush_r(ACC); // val_print(acc) XPush_r(ACC); XCall_m_real(val_print); stack_pop(Esp,1); // val_print(pc_pos) XPush_c(CONST(alloc_int(i))); XCall_m_real(val_print_2); stack_pop(Esp,1); // val_print(alloc_int(spmax - sp)) get_var_r(TMP,VSpMax); XSub_rr(TMP,SP); XShr_rc(TMP,1); XOr_rc(TMP,1); XPush_r(TMP); XCall_m_real(val_print_2); stack_pop(Esp,1); // val_print(alloc_int(csp - spmin)) XMov_rp(TMP2,VM,VMFIELD(spmin)); XMov_rr(TMP,CSP); XSub_rr(TMP,TMP2); XShr_rc(TMP,1); XOr_rc(TMP,1); XPush_r(TMP); XCall_m_real(val_print_3); stack_pop(Esp,1); XPop_r(ACC); END_BUFFER; } # endif i++; jit_opcode(ctx,op,(int)m->code[i]); # ifdef _DEBUG { int bytes = POS() - curpos; if( bytes > MAX_OP_SIZE ) ERROR; } # endif i += parameter_table[op]; } // FINALIZE { int csize = POS(); char *rbuf = alloc_jit_mem(csize); memcpy(rbuf,ctx->baseptr,csize); tmp_free(ctx->baseptr); ctx->baseptr = rbuf; ctx->buf.p = rbuf + csize; ctx->size = csize; # ifdef USE_MMAP m->jit_gc = alloc_abstract(NULL,rbuf); val_gc(m->jit_gc,free_jit_abstract); # endif # ifdef JIT_DEBUG printf("Jit size = %d ( x%.1f )\n",csize,csize * 1.0 / ((m->codesize + 1) * 4)); # endif jit_finalize_context(ctx); } // UPDATE GLOBALS { for(i=0;inglobals;i++) { vfunction *f = (vfunction*)m->globals[i]; if( !val_is_int(f) && val_tag(f) == VAL_FUNCTION && f->module == m ) { int pc = (int)((int_val*)f->addr - m->code); f->t = VAL_JITFUN; f->addr = (char*)ctx->baseptr + ctx->pos[pc]; } } } m->jit = ctx->baseptr; tmp_free(ctx->pos); } #else // JIT_ENABLE char *jit_boot_seq = NULL; char *jit_handle_trap = (char*)&jit_boot_seq; void neko_init_jit() { } void neko_free_jit() { } int neko_can_jit() { return 0; } void neko_module_jit( neko_module *m ) { } #endif /* ************************************************************************ */ neko-2.0.0/vm/nekovm_dll.vcxproj0000644000175000017500000002046712112157473017356 0ustar ncannassencannasse Debug Win32 ReleaseCrt60 Win32 Release Win32 {FEBA0CA8-4D9C-49C3-B3CC-1A7CFF9BB8B3} Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 ..\bin\ Debug\ true Release\ Release\ false Release\ Release\ false neko Disabled ../libs/include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;NEKOVM_DLL_EXPORTS;NEKO_SOURCES;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ../libs/include/gc/gc.lib;%(AdditionalDependencies) $(OutDir)$(TargetName).dll true $(OutDir)nekovm_dll.pdb Windows ../bin/neko.lib MachineX86 ../libs/include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;NEKOVM_DLL_EXPORTS;NEKO_SOURCES;COMPACT_TABLE;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../libs/include/gc/gc.lib;%(AdditionalDependencies) ..\bin\neko.dll %(IgnoreSpecificDefaultLibraries) true Windows true true ../bin/neko.lib MachineX86 ../libs/include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;NEKOVM_DLL_EXPORTS;NEKO_SOURCES;COMPACT_TABLE;%(PreprocessorDefinitions) MultiThreadedDLL false Level3 ProgramDatabase ../libs/include/gc/gc.lib;../libs/include/msvcrt/extra.lib;%(AdditionalDependencies) ../bin/neko.dll MSVCRT;%(IgnoreSpecificDefaultLibraries) true Windows true true ../bin/neko.lib MachineX86 neko-2.0.0/vm/alloc.c0000644000175000017500000002616312112157473015044 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include "neko.h" #include "objtable.h" #include "opcodes.h" #include "vm.h" #include "neko_mod.h" #include "neko_vm.h" #ifdef NEKO_POSIX # include #endif #ifdef NEKO_WINDOWS #ifdef NEKO_STANDALONE # define GC_NOT_DLL #else # define GC_DLL #endif # define GC_WIN32_THREADS #endif #define GC_THREADS #include "gc/gc.h" #ifndef GC_MALLOC # error Looks like libgc was not installed, please install it before compiling #else // activate to get debug informations about the GC // #define GC_LOG #define gc_alloc GC_MALLOC #define gc_alloc_private GC_MALLOC_ATOMIC #define gc_alloc_big(n) (((n) > 256) ? GC_MALLOC_IGNORE_OFF_PAGE(n) : GC_MALLOC(n)) #define gc_alloc_private_big(n) (((n) > 256) ? GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(n) : GC_MALLOC_ATOMIC(n)) #define gc_alloc_root GC_MALLOC_UNCOLLECTABLE #define gc_free_root GC_FREE typedef struct _klist { const char *name; vkind k; struct _klist *next; } kind_list; static int_val op_last = Last; static value *apply_string = NULL; int_val *callback_return = &op_last; value *neko_builtins = NULL; objtable *neko_fields = NULL; mt_lock *neko_fields_lock = NULL; mt_local *neko_vm_context = NULL; static val_type t_null = VAL_NULL; static val_type t_true = VAL_BOOL; static val_type t_false = VAL_BOOL; EXTERN value val_null = (value)&t_null; EXTERN value val_true = (value)&t_true; EXTERN value val_false = (value)&t_false; static varray empty_array = { VAL_ARRAY, NULL }; static vstring empty_string = { VAL_STRING, 0 }; static kind_list **kind_names = NULL; field id_compare; field id_string; field id_loader; field id_exports; field id_cache; field id_path; field id_loader_libs; field id_get, id_set; field id_add, id_radd, id_sub, id_rsub, id_mult, id_rmult, id_div, id_rdiv, id_mod, id_rmod; EXTERN field neko_id_module; #if defined (GC_LOG) && defined(NEKO_POSIX) static void handle_signal( int signal ) { // reset to default handler struct sigaction act; act.sa_sigaction = NULL; act.sa_handler = SIG_DFL; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGSEGV,&act,NULL); // print signal VM stack printf("**** SIGNAL %d CAUGHT ****\n",signal); neko_vm_dump_stack(neko_vm_current()); // signal again raise(signal); } #endif static void null_warn_proc( char *msg, int arg ) { # ifdef GC_LOG printf(msg,arg); if( strstr(msg,"very large block") ) neko_vm_dump_stack(neko_vm_current()); # endif } void neko_gc_init() { GC_set_warn_proc((GC_warn_proc)(void*)null_warn_proc); # ifndef NEKO_WINDOWS // we can't set this on windows with old GC since // it's already initialized through its own DllMain GC_all_interior_pointers = 0; # endif #if (GC_VERSION_MAJOR >= 7) && defined(NEKO_WINDOWS) GC_all_interior_pointers = 0; # ifndef NEKO_STANDALONE GC_use_DllMain(); // needed to auto-detect threads created by Apache # endif #endif GC_java_finalization = 1; GC_init(); GC_no_dls = 1; #ifdef LOW_MEM GC_dont_expand = 1; #endif GC_clear_roots(); #if defined(GC_LOG) && defined(NEKO_POSIX) { struct sigaction act; act.sa_sigaction = NULL; act.sa_handler = handle_signal; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGSEGV,&act,NULL); } #endif } EXTERN void neko_gc_loop() { GC_collect_a_little(); } EXTERN void neko_gc_major() { GC_gcollect(); } EXTERN void neko_gc_stats( int *heap, int *free ) { *heap = (int)GC_get_heap_size(); *free = (int)GC_get_free_bytes(); } EXTERN char *alloc( unsigned int nbytes ) { return (char*)gc_alloc_big(nbytes); } EXTERN char *alloc_private( unsigned int nbytes ) { return (char*)gc_alloc_private_big(nbytes); } EXTERN value alloc_empty_string( unsigned int size ) { vstring *s; if( size == 0 ) return (value)&empty_string; if( size > max_string_size ) failure("max_string_size reached"); s = (vstring*)gc_alloc_private_big(size+sizeof(vstring)); s->t = VAL_STRING | (size << TAG_BITS); (&s->c)[size] = 0; return (value)s; } EXTERN value alloc_string( const char *str ) { if( str == NULL ) return val_null; return copy_string(str,strlen(str)); } EXTERN value alloc_float( tfloat f ) { vfloat *v = (vfloat*)gc_alloc_private(sizeof(vfloat)); v->t = VAL_FLOAT; v->f = f; return (value)v; } EXTERN value alloc_int32( int i ) { vint32 *v = (vint32*)gc_alloc_private(sizeof(vint32)); v->t = VAL_INT32; v->i = i; return (value)v; } EXTERN value alloc_array( unsigned int n ) { value v; if( n == 0 ) return (value)(void*)&empty_array; if( n > max_array_size ) failure("max_array_size reached"); v = (value)gc_alloc_big(sizeof(varray)+(n - 1)*sizeof(value)); v->t = VAL_ARRAY | (n << TAG_BITS); return v; } EXTERN value alloc_abstract( vkind k, void *data ) { vabstract *v = (vabstract*)gc_alloc(sizeof(vabstract)); v->t = VAL_ABSTRACT; v->kind = k; v->data = data; return (value)v; } EXTERN value alloc_function( void *c_prim, unsigned int nargs, const char *name ) { vfunction *v; if( c_prim == NULL || (nargs < 0 && nargs != VAR_ARGS) ) failure("alloc_function"); v = (vfunction*)gc_alloc(sizeof(vfunction)); v->t = VAL_PRIMITIVE; v->addr = c_prim; v->nargs = nargs; v->env = alloc_array(0); v->module = alloc_string(name); return (value)v; } value neko_alloc_module_function( void *m, int_val pos, int nargs ) { vfunction *v; if( nargs < 0 && nargs != VAR_ARGS ) failure("alloc_module_function"); v = (vfunction*)gc_alloc(sizeof(vfunction)); v->t = VAL_FUNCTION; v->addr = (void*)pos; v->nargs = nargs; v->env = alloc_array(0); v->module = m; return (value)v; } static value apply1( value p1 ) { value env = NEKO_VM()->env; value *a = val_array_ptr(env) + 1; int n = val_array_size(env) - 1; a[n-1] = p1; return val_callN(a[-1],a,n); } static value apply2( value p1, value p2 ) { value env = NEKO_VM()->env; value *a = val_array_ptr(env) + 1; int n = val_array_size(env) - 1; a[n-2] = p1; a[n-1] = p2; return val_callN(a[-1],a,n); } static value apply3( value p1, value p2, value p3 ) { value env = NEKO_VM()->env; value *a = val_array_ptr(env) + 1; int n = val_array_size(env) - 1; a[n-3] = p1; a[n-2] = p2; a[n-1] = p3; return val_callN(a[-1],a,n); } static value apply4( value p1, value p2, value p3, value p4 ) { value env = NEKO_VM()->env; value *a = val_array_ptr(env) + 1; int n = val_array_size(env) - 1; a[n-4] = p1; a[n-3] = p2; a[n-2] = p3; a[n-1] = p4; return val_callN(a[-1],a,n); } static value apply5( value p1, value p2, value p3, value p4, value p5 ) { value env = NEKO_VM()->env; value *a = val_array_ptr(env) + 1; int n = val_array_size(env) - 1; a[n-4] = p1; a[n-3] = p2; a[n-2] = p3; a[n-1] = p4; a[n-1] = p5; return val_callN(a[-1],a,n); } value neko_alloc_apply( int nargs, value env ) { vfunction *v = (vfunction*)gc_alloc(sizeof(vfunction)); v->t = VAL_PRIMITIVE; switch( nargs ) { case 1: v->addr = apply1; break; case 2: v->addr = apply2; break; case 3: v->addr = apply3; break; case 4: v->addr = apply4; break; case 5: v->addr = apply5; break; default: failure("Too many apply arguments"); break; } v->nargs = nargs; v->env = env; v->module = *apply_string; return (value)v; } EXTERN value alloc_object( value cpy ) { vobject *v; if( cpy != NULL && !val_is_null(cpy) && !val_is_object(cpy) ) val_throw(alloc_string("$new")); // 'new' opcode simulate $new v = (vobject*)gc_alloc(sizeof(vobject)); v->t = VAL_OBJECT; if( cpy == NULL || val_is_null(cpy) ) { v->proto = NULL; otable_init(&v->table); } else { v->proto = ((vobject*)cpy)->proto; otable_copy(&((vobject*)cpy)->table,&v->table); } return (value)v; } EXTERN value copy_string( const char *str, int_val strlen ) { value v = alloc_empty_string((unsigned int)strlen); char *c = (char*)val_string(v); memcpy(c,str,strlen); return v; } EXTERN void alloc_field( value obj, field f, value v ) { otable_replace(&((vobject*)obj)->table,f,v); } static void __on_finalize( value v, void *f ) { ((finalizer)f)(v); } EXTERN void val_gc(value v, finalizer f ) { if( !val_is_abstract(v) ) failure("val_gc"); if( f ) GC_REGISTER_FINALIZER_NO_ORDER(v,(GC_finalization_proc)__on_finalize,f,0,0); else GC_REGISTER_FINALIZER_NO_ORDER(v,NULL,NULL,0,0); } EXTERN value *alloc_root( unsigned int nvals ) { return (value*)gc_alloc_root(nvals*sizeof(value)); } EXTERN void free_root(value *v) { gc_free_root(v); } extern void neko_init_builtins(); extern void neko_init_fields(); extern void neko_init_jit(); extern void neko_free_jit(); #define INIT_ID(x) id_##x = val_id("__" #x) EXTERN void neko_global_init() { # ifdef NEKO_DIRECT_THREADED op_last = neko_get_ttable()[Last]; # endif empty_array.ptr = val_null; neko_gc_init(); neko_vm_context = alloc_local(); neko_fields_lock = alloc_lock(); neko_fields = (objtable*)alloc_root((NEKO_FIELDS_MASK+1) * sizeof(struct _objtable) / sizeof(value)); { int i; for(i=0;i<=NEKO_FIELDS_MASK;i++) otable_init(&neko_fields[i]); } neko_init_builtins(); kind_names = (kind_list**)alloc_root(1); *kind_names = NULL; id_loader = val_id("loader"); id_exports = val_id("exports"); id_cache = val_id("cache"); id_path = val_id("path"); id_loader_libs = val_id("__libs"); neko_id_module = val_id("__module"); INIT_ID(compare); INIT_ID(string); INIT_ID(add); INIT_ID(radd); INIT_ID(sub); INIT_ID(rsub); INIT_ID(mult); INIT_ID(rmult); INIT_ID(div); INIT_ID(rdiv); INIT_ID(mod); INIT_ID(rmod); INIT_ID(get); INIT_ID(set); apply_string = alloc_root(1); *apply_string = alloc_string("apply"); neko_init_jit(); } EXTERN void neko_global_free() { neko_free_jit(); free_root((value*)kind_names); free_root(apply_string); free_root(neko_builtins); free_root((value*)neko_fields); apply_string = NULL; free_local(neko_vm_context); free_lock(neko_fields_lock); neko_gc_major(); } EXTERN void neko_set_stack_base( void *s ) { // deprecated } EXTERN void kind_share( vkind *k, const char *name ) { kind_list *l = *kind_names; while( l != NULL ) { if( strcmp(l->name,name) == 0 ) { *k = l->k; return; } l = l->next; } l = (kind_list*)alloc(sizeof(kind_list)); l->k = *k; l->name = name; l->next = *kind_names; *kind_names = l; } #endif /* ************************************************************************ */ neko-2.0.0/vm/interp.c0000644000175000017500000007532312112157473015255 0ustar ncannassencannasse/* * Copyright (C)2005-2012 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include "opcodes.h" #include "vm.h" #include "neko_mod.h" #include "objtable.h" #ifndef NEKO_WINDOWS # include #endif #if defined(NEKO_GCC) && defined(NEKO_X86) && (__GNUC__ == 3) # define ACC_BACKUP int_val __acc = acc; # define ACC_RESTORE acc = __acc; # define ACC_REG asm("%eax") # define PC_REG asm("%esi") # define SP_REG asm("%edi") # define CSP_REG # define VM_ARG vm #elif defined(NEKO_GCC) && defined(NEKO_PPC) # define ACC_BACKUP # define ACC_RESTORE # define ACC_REG asm("26") # define PC_REG asm("27") # define SP_REG asm("28") # define CSP_REG asm("29") # define VM_REG asm("30") # define VM_ARG _vm #else # define ACC_BACKUP # define ACC_RESTORE # define ACC_REG # define PC_REG # define SP_REG # define CSP_REG # define VM_ARG vm #endif #define ERASE 0 #define address_int(a) (((int_val)(a)) | 1) #define int_address(a) (int_val*)(a & ~1) extern field id_add, id_radd, id_sub, id_rsub, id_mult, id_rmult, id_div, id_rdiv, id_mod, id_rmod; extern field id_get, id_set; extern value neko_alloc_module_function( void *m, int_val pos, int nargs ); extern char *jit_boot_seq; extern char *jit_handle_trap; typedef void (*jit_handle)( neko_vm * ); extern int neko_can_jit(); value NEKO_TYPEOF[] = { alloc_int(0), alloc_int(2), alloc_int(3), alloc_int(4), alloc_int(5), alloc_int(6), alloc_int(7), alloc_int(8), alloc_int(1), }; static void default_printer( const char *s, int len, void *out ) { while( len > 0 ) { int p = (int)fwrite(s,1,len,(FILE*)out); if( p <= 0 ) { fputs("[ABORTED]",(FILE*)out); break; } len -= p; s += p; } fflush((FILE*)out); } EXTERN neko_vm *neko_vm_alloc( void *custom ) { neko_vm *vm = (neko_vm*)alloc(sizeof(neko_vm)); # ifdef NEKO_WINDOWS int stack_size = 0x100000; // 1MB default # else struct rlimit st; int stack_size; if( getrlimit(RLIMIT_STACK,&st) != 0 || st.rlim_cur == RLIM_INFINITY ) stack_size = 8192 << 10; else stack_size = st.rlim_cur; # endif vm->spmin = (int_val*)alloc(INIT_STACK_SIZE*sizeof(int_val)); vm->print = default_printer; vm->print_param = stdout; vm->clist = NULL; // the maximum stack position for a C call is estimated // - stack grows bottom // - neko_vm_alloc should be near the beginning of the stack // - we keep 64KB for the C call work space and error margin vm->c_stack_max = (void*)(((int_val)&vm) - (stack_size - 0x10000)); vm->exc_stack = alloc_array(0); vm->spmax = vm->spmin + INIT_STACK_SIZE; vm->sp = vm->spmax; vm->csp = vm->spmin - 1; vm->vthis = val_null; vm->env = alloc_array(0); vm->jit_val = NULL; vm->run_jit = 0; vm->resolver = NULL; vm->trusted_code = 0; vm->fstats = NULL; vm->pstats = NULL; return vm; } EXTERN int neko_vm_jit( neko_vm *vm, int enable_jit ) { if( enable_jit < 0 ) return vm->run_jit; if( enable_jit ) vm->run_jit = neko_can_jit(); else vm->run_jit = 0; return vm->run_jit; } EXTERN int neko_vm_trusted( neko_vm *vm, int t ) { int old = vm->trusted_code; vm->trusted_code = t; return old; } EXTERN void neko_vm_set_stats( neko_vm *vm, neko_stat_func fstats, neko_stat_func pstats ) { vm->fstats = fstats; vm->pstats = pstats; } EXTERN void neko_vm_select( neko_vm *vm ) { local_set(neko_vm_context,vm); } EXTERN neko_vm *neko_vm_current() { return NEKO_VM(); } EXTERN void *neko_vm_custom( neko_vm *vm, vkind k ) { custom_list *c = vm->clist; while( c != NULL ) { if( c->tag == k ) return c->custom; c = c->next; } return NULL; } EXTERN void neko_vm_set_custom( neko_vm *vm, vkind k, void *v ) { custom_list *c = vm->clist, *prev = NULL; while( c != NULL ) { if( c->tag == k ) { if( v ) { c->custom = v; return; } if( prev == NULL ) vm->clist = c->next; else prev->next = c->next; return; } prev = c; c = c->next; } c = (custom_list*)alloc(sizeof(custom_list)); c->tag = k; c->custom = v; c->next = vm->clist; vm->clist = c; } typedef struct { neko_printer prev; void *prev_param; neko_printer cur; void *cur_param; } redirect_param; static void redirected_print( const char *s, int size, void *_p ) { redirect_param *p = (redirect_param*)_p; p->cur(s,size,p->cur_param); } EXTERN void neko_vm_redirect( neko_vm *vm, neko_printer print, void *param ) { redirect_param *p; if( print == NULL ) { if( vm->print != redirected_print ) return; p = (redirect_param*)vm->print_param; vm->print = p->prev; vm->print_param = p->prev_param; return; } p = (redirect_param*)alloc(sizeof(redirect_param)); p->prev = vm->print; p->prev_param = vm->print_param; p->cur = print; p->cur_param = param; vm->print = redirected_print; vm->print_param = p; } EXTERN value neko_vm_execute( neko_vm *vm, void *_m ) { unsigned int i; neko_module *m = (neko_module*)_m; value old_env = vm->env, ret; value old_this = vm->vthis; neko_vm_select(vm); for(i=0;infields;i++) val_id(val_string(m->fields[i])); vm->env = alloc_array(0); vm->vthis = val_null; ret = neko_interp(vm,m,(int_val)val_null,m->code); vm->env = old_env; vm->vthis = old_this; return ret; } EXTERN value neko_exc_stack( neko_vm *vm ) { return vm->exc_stack; } static value neko_flush_stack( int_val *cspup, int_val *csp, value old ); EXTERN value neko_call_stack( neko_vm *vm ) { return neko_flush_stack(vm->csp,vm->spmin - 1,NULL); } typedef int_val (*c_prim0)(); typedef int_val (*c_prim1)(int_val); typedef int_val (*c_prim2)(int_val,int_val); typedef int_val (*c_prim3)(int_val,int_val,int_val); typedef int_val (*c_prim4)(int_val,int_val,int_val,int_val); typedef int_val (*c_prim5)(int_val,int_val,int_val,int_val,int_val); typedef int_val (*c_primN)(value*,int); typedef int_val (*jit_prim)( neko_vm *, void *, value , neko_module *m ); static int_val jit_run( neko_vm *vm, vfunction *acc ) { neko_module *m = (neko_module*)acc->module; return ((jit_prim)jit_boot_seq)(vm,acc->addr,(value)acc,m); } #define RuntimeError(err,param) { if( param ) pc++; PushInfos(); BeginCall(); val_throw(alloc_string(err)); } #define CallFailure() RuntimeError("Invalid call",false) #define InvalidFieldAccess() { \ value v = val_field_name((field)*pc); \ buffer b; \ if( val_is_null(v) ) RuntimeError("Invalid field access",true); \ b = alloc_buffer("Invalid field access : "); \ val_buffer(b,v); \ pc++; PushInfos(); BeginCall(); \ val_throw(buffer_to_string(b)); \ } #ifdef NEKO_THREADED # define Instr(x) Label##x: # ifdef NEKO_DIRECT_THREADED # define Next goto **pc++; # else # define Next goto **(instructions + *pc++); # endif #else # define Instr(x) case x: # define Next break; #endif #define PopMacro(n) { \ int tmp = (int)n; \ while( tmp-- > 0 ) \ *sp++ = ERASE; \ } #define BeginCall() \ vm->sp = sp; \ vm->csp = csp; #define EndCall() \ sp = vm->sp; \ csp = vm->csp #define PushInfos() \ if( csp + 4 >= sp ) STACK_EXPAND; \ *++csp = (int_val)pc; \ *++csp = (int_val)vm->env; \ *++csp = (int_val)vm->vthis; \ *++csp = (int_val)m; #define PopInfos(restpc) \ m = (neko_module*)*csp; \ *csp-- = ERASE; \ vm->vthis = (value)*csp; \ *csp-- = ERASE; \ vm->env = (value)*csp; \ *csp-- = ERASE; \ if( restpc ) pc = (int_val*)*csp; \ *csp-- = ERASE; #define SetupBeforeCall(this_arg) \ vfunction *f = (vfunction*)acc; \ PushInfos(); \ vm->vthis = this_arg; \ vm->env = ((vfunction*)acc)->env; \ BeginCall(); #define RestoreAfterCall() \ if( acc == (int_val)NULL ) val_throw( (value)f->module ); \ EndCall(); \ PopInfos(false); #define DoCall(this_arg,pc_args) \ if( acc & 1 ) \ CallFailure() \ else if( val_tag(acc) == VAL_FUNCTION && pc_args == ((vfunction*)acc)->nargs ) { \ PushInfos(); \ m = (neko_module*)((vfunction*)acc)->module; \ pc = (int_val*)((vfunction*)acc)->addr; \ vm->vthis = this_arg; \ vm->env = ((vfunction*)acc)->env; \ } else if( val_tag(acc) == VAL_PRIMITIVE ) { \ if( pc_args == ((vfunction*)acc)->nargs ) { \ SetupBeforeCall(this_arg); \ switch( pc_args ) { \ case 0: \ acc = ((c_prim0)((vfunction*)acc)->addr)(); \ break; \ case 1: \ acc = ((c_prim1)((vfunction*)acc)->addr)(sp[0]); \ break; \ case 2: \ acc = ((c_prim2)((vfunction*)acc)->addr)(sp[1],sp[0]); \ break; \ case 3: \ acc = ((c_prim3)((vfunction*)acc)->addr)(sp[2],sp[1],sp[0]); \ break; \ case 4: \ acc = ((c_prim4)((vfunction*)acc)->addr)(sp[3],sp[2],sp[1],sp[0]); \ break; \ case 5: \ acc = ((c_prim5)((vfunction*)acc)->addr)(sp[4],sp[3],sp[2],sp[1],sp[0]); \ break; \ } \ RestoreAfterCall(); \ } \ else if( ((vfunction*)acc)->nargs == VAR_ARGS ) { \ int_val args[CALL_MAX_ARGS]; \ int_val tmp; \ SetupBeforeCall(this_arg); \ sp += pc_args; \ for(tmp=0;tmpaddr)((value*)(void*)args,(int)pc_args); \ RestoreAfterCall(); \ } else \ CallFailure(); \ PopMacro(pc_args); \ } else if( val_tag(acc) == VAL_JITFUN ) { \ if( pc_args == ((vfunction*)acc)->nargs ) { \ SetupBeforeCall(this_arg); \ acc = jit_run(vm,(vfunction*)acc); \ RestoreAfterCall(); \ } else \ CallFailure(); \ } else \ CallFailure(); #define OpError(op) RuntimeError("Invalid operation (" op ")", false) #define IntOp(op) \ if( (acc & 1) && (*sp & 1) ) \ acc = (int_val)alloc_best_int(val_int(*sp) op val_int(acc)); \ else if( val_is_any_int(acc) && val_is_any_int(*sp) ) \ acc = (int_val)alloc_best_int(val_any_int(*sp) op val_any_int(acc)); \ else \ OpError(#op); \ *sp++ = ERASE; \ Next #define Test(test) \ BeginCall(); \ acc = (int_val)val_compare((value)*sp,(value)acc); \ EndCall(); \ *sp++ = ERASE; \ acc = (int_val)((acc test 0 && acc != invalid_comparison)?val_true:val_false); \ Next #define SUB(x,y) ((x) - (y)) #define MULT(x,y) ((x) * (y)) #define DIV(x,y) ((x) / (y)) #define ObjectOpGen(obj,param,id,err) { \ ACC_BACKUP \ value _o = (value)obj; \ value _arg = (value)param; \ value _f = val_field(_o,id); \ if( _f == val_null ) { \ ACC_RESTORE \ err; \ } else { \ PushInfos(); \ BeginCall(); \ acc = (int_val)val_callEx(_o,_f,&_arg,1,NULL); \ EndCall(); \ PopInfos(false); \ } \ } #define ObjectOp(obj,param,id) ObjectOpGen(obj,param,id,RuntimeError("Unsupported operation",false)) #define NumberOp(op,fop,id_op,id_rop) \ if( (acc & 1) && (*sp & 1) ) \ acc = (int_val)alloc_best_int(val_int(*sp) op val_int(acc)); \ else if( acc & 1 ) { \ if( val_tag(*sp) == VAL_FLOAT ) \ acc = (int_val)alloc_float(fop(val_float(*sp),val_int(acc))); \ else if( val_tag(*sp) == VAL_INT32 ) \ acc = (int_val)alloc_best_int(val_int32(*sp) op val_int(acc)); \ else if( val_tag(*sp) == VAL_OBJECT ) \ ObjectOp(*sp,acc,id_op) \ else \ OpError(#op); \ } else if( *sp & 1 ) { \ if( val_tag(acc) == VAL_FLOAT ) \ acc = (int_val)alloc_float(fop(val_int(*sp),val_float(acc))); \ else if( val_tag(acc) == VAL_INT32 ) \ acc = (int_val)alloc_best_int(val_int(*sp) op val_int32(acc)); \ else if( val_tag(acc) == VAL_OBJECT ) \ ObjectOp(acc,*sp,id_rop) \ else \ OpError(#op); \ } else if( val_tag(acc) == VAL_FLOAT ) { \ if( val_tag(*sp) == VAL_FLOAT ) \ acc = (int_val)alloc_float(fop(val_float(*sp),val_float(acc))); \ else if( val_tag(*sp) == VAL_INT32 ) \ acc = (int_val)alloc_float(fop(val_int32(*sp),val_float(acc))); \ else \ goto id_op##_next; \ } else if( val_tag(acc) == VAL_INT32 ) {\ if( val_tag(*sp) == VAL_INT32 ) \ acc = (int_val)alloc_best_int(val_int32(*sp) op val_int32(acc)); \ else if( val_tag(*sp) == VAL_FLOAT ) \ acc = (int_val)alloc_float(fop(val_float(*sp),val_int32(acc))); \ else \ goto id_op##_next; \ } else { \ id_op##_next: \ if( val_tag(*sp) == VAL_OBJECT ) \ ObjectOpGen(*sp,acc,id_op,goto id_op##_next2) \ else { \ id_op##_next2: \ if( val_tag(acc) == VAL_OBJECT ) \ ObjectOp(acc,*sp,id_rop) \ else \ OpError(#op); \ } \ } \ *sp++ = ERASE; \ Next; extern int neko_stack_expand( int_val *sp, int_val *csp, neko_vm *vm ); extern value neko_append_int( neko_vm *vm, value str, int x, bool way ); extern value neko_append_strings( value s1, value s2 ); #define STACK_EXPAND { \ ACC_BACKUP; \ if( neko_stack_expand(sp,csp,vm) ) { \ sp = vm->sp; \ csp = vm->csp; \ } else \ val_throw(alloc_string("Stack Overflow")); \ ACC_RESTORE; \ } // optimized for sparse bits static int bitcount( unsigned int k ) { int b = 0; while( k ) { b++; k &= (k - 1); } return b; } static value neko_flush_stack( int_val *cspup, int_val *csp, value old ) { int ncalls = (int)((cspup - csp) / 4); value stack_trace = alloc_array(ncalls + ((old == NULL)?0:val_array_size(old))); value *st = val_array_ptr(stack_trace); neko_module *m; while( csp != cspup ) { m = (neko_module*)csp[4]; if( m ) { if( m->dbgidxs ) { unsigned int ppc = (unsigned int)((((int_val**)csp)[1]-2) - m->code); if( ppc < m->codesize ) { int idx =m->dbgidxs[ppc>>5].base + bitcount(m->dbgidxs[ppc>>5].bits >> (31 - (ppc & 31))); *st = val_array_ptr(m->dbgtbl)[idx]; } else *st = m->name; } else *st = m->name; } else *st = val_null; st++; if( old ) { *++csp = ERASE; *++csp = ERASE; *++csp = ERASE; *++csp = ERASE; } else csp += 4; } if( old ) { value *oldst = val_array_ptr(old); ncalls = val_array_size(old); while( ncalls-- ) *st++ = *oldst++; } return stack_trace; } EXTERN void neko_vm_dump_stack( neko_vm *vm ) { // we can't do any GC allocation here since we might hold the lock int_val *cspup = vm->csp; int_val *csp = vm->spmin - 1; while( csp != cspup ) { neko_module *m = (neko_module*)csp[4]; printf("Called from "); if( m ) { printf("%s ",val_string(m->name)); if( m->dbgidxs ) { int ppc = (int)((((int_val**)csp)[1]-2) - m->code); int idx = m->dbgidxs[ppc>>5].base + bitcount(m->dbgidxs[ppc>>5].bits >> (31 - (ppc & 31))); value s = val_array_ptr(m->dbgtbl)[idx]; if( val_is_string(s) ) printf("%s",val_string(s)); else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) ) printf("file %s line %d",val_string(val_array_ptr(s)[0]),val_int(val_array_ptr(s)[1])); else printf("???"); } } else printf("a C function"); csp += 4; printf("\n"); } fflush(stdout); } void neko_setup_trap( neko_vm *vm ) { vm->sp -= 6; if( vm->sp <= vm->csp && !neko_stack_expand(vm->sp,vm->csp,vm) ) val_throw(alloc_string("Stack Overflow")); vm->sp[0] = (int_val)alloc_int((int_val)(vm->csp - vm->spmin)); vm->sp[1] = (int_val)vm->vthis; vm->sp[2] = (int_val)vm->env; vm->sp[3] = address_int(vm->jit_val); vm->sp[4] = (int_val)val_null; vm->sp[5] = (int_val)alloc_int((int_val)vm->trap); vm->trap = vm->spmax - vm->sp; } void neko_process_trap( neko_vm *vm ) { // pop csp int_val *sp; int_val *trap; if( vm->trap == 0 ) return; trap = vm->spmax - vm->trap; sp = vm->spmin + val_int(trap[0]); vm->exc_stack = neko_flush_stack(vm->csp,sp,vm->exc_stack); vm->csp = sp; // restore state vm->vthis = (value)trap[1]; vm->env = (value)trap[2]; vm->jit_val = int_address(trap[3]); // pop sp sp = trap + 6; vm->trap = val_int(trap[5]); while( vm->sp < sp ) *vm->sp++ = ERASE; } int_val neko_interp_loop( neko_vm *VM_ARG, neko_module *m, int_val _acc, int_val *_pc ) { register int_val acc ACC_REG = _acc; register int_val *pc PC_REG = _pc; # ifdef VM_REG register neko_vm *vm VM_REG = VM_ARG; # endif # ifdef NEKO_THREADED static void *instructions[] = { # undef _NEKO_OPCODES_H # undef OPBEGIN # undef OPEND # undef OP # define OPBEGIN # define OPEND # define OP(x) &&Label##x # include "opcodes.h" }; if( m == NULL ) return (int_val)instructions; # endif register int_val *sp SP_REG = vm->sp; register int_val *csp CSP_REG = vm->csp; #ifdef NEKO_THREADED Next; {{ #else while( true ) { # ifdef NEKO_PROF if( *pc != Last ) pc[PROF_SIZE]++; # endif switch( *pc++ ) { #endif Instr(AccNull) acc = (int_val)val_null; Next; Instr(AccTrue) acc = (int_val)val_true; Next; Instr(AccFalse) acc = (int_val)val_false; Next; Instr(AccThis) acc = (int_val)vm->vthis; Next; Instr(AccInt) acc = *pc++; Next; Instr(AccInt32) acc = (int_val)alloc_int32((int)*pc++); Next; Instr(AccStack0) acc = *sp; Next; Instr(AccStack1) acc = sp[1]; Next; Instr(AccStack) acc = sp[*pc++]; Next; Instr(AccGlobal) acc = *(int_val*)(*pc++); Next; Instr(AccEnv) if( *pc >= val_array_size(vm->env) ) RuntimeError("Reading Outside Env",true); acc = (int_val)val_array_ptr(vm->env)[*pc++]; Next; Instr(AccField) if( val_is_object(acc) ) { value *f; value old = (value)acc, tacc = (value)acc; do { f = otable_find(&((vobject*)acc)->table,(field)*pc); if( f ) break; acc = (int_val)((vobject*)tacc)->proto; tacc = (value)acc; } while( acc ); if( f ) acc = (int_val)*f; else if( vm->resolver ) { BeginCall(); acc = (int_val)val_call2(vm->resolver,old,alloc_int(*pc)); EndCall(); } else acc = (int_val)val_null; } else InvalidFieldAccess(); pc++; Next; Instr(AccArray) if( val_is_int(acc) && val_is_array(*sp) ) { int k = val_int(acc); if( k < 0 || k >= val_array_size(*sp) ) acc = (int_val)val_null; else acc = (int_val)val_array_ptr(*sp)[k]; } else if( val_is_object(*sp) ) ObjectOp(*sp,acc,id_get) else if( val_is_int32(acc) && val_is_array(*sp) ) acc = (int_val)val_null; else RuntimeError("Invalid array access",false); *sp++ = ERASE; Next; Instr(AccIndex0) if( val_is_array(acc) ) { if( val_array_size(acc) ) acc = (int_val)*val_array_ptr(acc); else acc = (int_val)val_null; } else if( val_is_object(acc) ) ObjectOp(acc,alloc_int(0),id_get) else RuntimeError("Invalid array access",false); Next; Instr(AccIndex1) if( val_is_array(acc) ) { if( val_array_size(acc) > 1 ) acc = (int_val)val_array_ptr(acc)[1]; else acc = (int_val)val_null; } else if( val_is_object(acc) ) ObjectOp(acc,alloc_int(1),id_get) else RuntimeError("Invalid array access",false); Next; Instr(AccIndex) if( val_is_array(acc) ) { if( *pc < 0 || *pc >= val_array_size(acc) ) acc = (int_val)val_null; else acc = (int_val)val_array_ptr(acc)[*pc]; pc++; } else if( val_is_object(acc) ) ObjectOp(acc,alloc_int(*pc++),id_get) else RuntimeError("Invalid array access",true); Next; Instr(AccBuiltin) acc = *pc++; Next; Instr(SetStack) sp[*pc++] = acc; Next; Instr(SetGlobal) *(int_val*)(*pc++) = acc; Next; Instr(SetEnv) if( *pc >= val_array_size(vm->env) ) RuntimeError("Writing Outside Env",true); val_array_ptr(vm->env)[*pc++] = (value)acc; Next; Instr(SetField) if( val_is_object(*sp) ) { ACC_BACKUP; otable_replace(&((vobject*)*sp)->table,(field)*pc,(value)acc); ACC_RESTORE; } else InvalidFieldAccess(); *sp++ = ERASE; pc++; Next; Instr(SetArray) if( val_is_array(*sp) && val_is_int(sp[1]) ) { int k = val_int(sp[1]); if( k >= 0 && k < val_array_size(*sp) ) val_array_ptr(*sp)[k] = (value)acc; } else if( val_is_object(*sp) ) { value args[] = { (value)sp[1], (value)acc }; value f = val_field((value)*sp,id_set); if( f == val_null ) RuntimeError("Unsupported operation",false); PushInfos(); BeginCall(); val_callEx((value)*sp,f,args,2,NULL); EndCall(); PopInfos(false); acc = (int_val)args[1]; } else if( val_is_int32(sp[1]) && val_is_array(*sp) ) { // out range } else RuntimeError("Invalid array access",false); *sp++ = ERASE; *sp++ = ERASE; Next; Instr(SetIndex) if( val_is_array(*sp) ) { if( *pc >= 0 && *pc < val_array_size(*sp) ) val_array_ptr(*sp)[*pc] = (value)acc; } else if( val_is_object(*sp) ) { value args[] = { (value)alloc_int(*pc), (value)acc }; value f = val_field((value)*sp,id_set); if( f == val_null ) RuntimeError("Unsupported operation",true); PushInfos(); BeginCall(); val_callEx((value)*sp,f,args,2,NULL); EndCall(); PopInfos(false); acc = (int_val)args[1]; } else RuntimeError("Invalid array access",true); pc++; *sp++ = ERASE; Next; Instr(SetThis) vm->vthis = (value)acc; Next; Instr(Push) --sp; if( sp <= csp ) STACK_EXPAND; *sp = acc; Next; Instr(Pop) PopMacro(*pc++) Next; Instr(Apply) if( !val_is_function(acc) ) RuntimeError("$apply",true); { int fargs = val_fun_nargs(acc); if( fargs == *pc || fargs == VAR_ARGS ) goto do_call; if( *pc > fargs ) RuntimeError("$apply",true); { int i = fargs; ACC_BACKUP value env = alloc_array(fargs + 1); ACC_RESTORE; val_array_ptr(env)[0] = (value)acc; while( i > *pc ) val_array_ptr(env)[i--] = val_null; while( i ) { val_array_ptr(env)[i--] = (value)*sp; *sp++ = ERASE; } acc = (int_val)neko_alloc_apply((int)(fargs - *pc++),env); } } Next; Instr(TailCall) { int stack = (int)((*pc) >> 3); int nargs = (int)((*pc) & 7); int i = nargs; value cur_this = vm->vthis; stack -= nargs; sp += nargs; while( i > 0 ) { sp--; sp[stack] = *sp; i--; } while( stack-- > 0 ) *sp++ = ERASE; // preserve 'this' through the call PopInfos(true); DoCall(cur_this,nargs); } Next; Instr(Call) do_call: pc++; DoCall(vm->vthis,pc[-1]); Next; Instr(ObjCall) { value vtmp = (value)*sp; *sp++ = ERASE; pc++; DoCall(vtmp,pc[-1]); } Next; Instr(Jump) pc = (int_val*)*pc; Next; Instr(JumpIf) if( acc == (int_val)val_true ) pc = (int_val*)*pc; else pc++; Next; Instr(JumpIfNot) if( acc != (int_val)val_true ) pc = (int_val*)*pc; else pc++; Next; Instr(Trap) sp -= 6; if( sp <= csp ) STACK_EXPAND; sp[0] = (int_val)alloc_int((int_val)(csp - vm->spmin)); sp[1] = (int_val)vm->vthis; sp[2] = (int_val)vm->env; sp[3] = address_int(*pc); sp[4] = address_int(m); sp[5] = (int_val)alloc_int(vm->trap); vm->trap = vm->spmax - sp; pc++; Next; Instr(EndTrap) if( vm->spmax - vm->trap != sp ) RuntimeError("Invalid End Trap",false); vm->trap = val_int(sp[5]); PopMacro(6); Next; Instr(Ret) PopMacro( *pc++ ); PopInfos(true); Next; Instr(MakeEnv) { int n = (int)(*pc++); ACC_BACKUP int_val tmp = (int_val)alloc_array(n); ACC_RESTORE; while( n-- ) { val_array_ptr(tmp)[n] = (value)*sp; *sp++ = ERASE; } if( val_is_int(acc) || val_tag(acc) != VAL_FUNCTION ) RuntimeError("Invalid environment",false); acc = (int_val)neko_alloc_module_function(((vfunction*)acc)->module,(int_val)((vfunction*)acc)->addr,((vfunction*)acc)->nargs); ((vfunction*)acc)->env = (value)tmp; } Next; Instr(MakeArray) { int n = (int)*pc++; ACC_BACKUP value arr = alloc_array(n+1); ACC_RESTORE; while( n ) { val_array_ptr(arr)[n] = (value)*sp; *sp++ = ERASE; n--; } val_array_ptr(arr)[0] = (value)acc; acc = (int_val)arr; } Next; Instr(MakeArray2) { // similar to MakeArray but will keep a correct evaluation order int n = (int)*pc++; ACC_BACKUP value arr = alloc_array(n+1); ACC_RESTORE; if( n == 2 ) { n += 0; } val_array_ptr(arr)[n] = (value)acc; while( n ) { val_array_ptr(arr)[--n] = (value)*sp; *sp++ = ERASE; } acc = (int_val)arr; } Next; Instr(Bool) acc = (acc == (int_val)val_false || acc == (int_val)val_null || acc == 1)?(int_val)val_false:(int_val)val_true; Next; Instr(Not) acc = (acc == (int_val)val_false || acc == (int_val)val_null || acc == 1)?(int_val)val_true:(int_val)val_false; Next; Instr(IsNull) acc = (int_val)((acc == (int_val)val_null)?val_true:val_false); Next; Instr(IsNotNull) acc = (int_val)((acc == (int_val)val_null)?val_false:val_true); Next; Instr(Add) if( (acc & 1) && (*sp & 1) ) acc = (int_val)alloc_best_int(val_int(*sp) + val_int(acc)); else if( acc & 1 ) { if( val_tag(*sp) == VAL_FLOAT ) acc = (int_val)alloc_float(val_float(*sp) + val_int(acc)); else if( val_tag(*sp) == VAL_INT32 ) acc = (int_val)alloc_best_int(val_int32(*sp) + val_int(acc)); else if( val_short_tag(*sp) == VAL_STRING ) acc = (int_val)neko_append_int(vm,(value)*sp,val_int(acc),true); else if( val_tag(*sp) == VAL_OBJECT ) ObjectOp(*sp,acc,id_add) else OpError("+"); } else if( *sp & 1 ) { if( val_tag(acc) == VAL_FLOAT ) acc = (int_val)alloc_float(val_int(*sp) + val_float(acc)); else if( val_tag(acc) == VAL_INT32 ) acc = (int_val)alloc_best_int(val_int(*sp) + val_int32(acc)); else if( val_short_tag(acc) == VAL_STRING ) acc = (int_val)neko_append_int(vm,(value)acc,val_int(*sp),false); else if( val_tag(acc) == VAL_OBJECT ) ObjectOp(acc,*sp,id_radd) else OpError("+"); } else if( val_tag(acc) == VAL_FLOAT ) { if( val_tag(*sp) == VAL_FLOAT ) acc = (int_val)alloc_float(val_float(*sp) + val_float(acc)); else if( val_tag(*sp) == VAL_INT32 ) acc = (int_val)alloc_float(val_int32(*sp) + val_float(acc)); else goto add_next; } else if( val_tag(acc) == VAL_INT32 ) { if( val_tag(*sp) == VAL_INT32 ) acc = (int_val)alloc_best_int(val_int32(*sp) + val_int32(acc)); else if( val_tag(*sp) == VAL_FLOAT ) acc = (int_val)alloc_float(val_float(*sp) + val_int32(acc)); else goto add_next; } else { add_next: if( val_tag(*sp) == VAL_OBJECT ) ObjectOpGen(*sp,acc,id_add,goto add_2) else { add_2: if( val_tag(acc) == VAL_OBJECT ) ObjectOpGen(acc,*sp,id_radd,goto add_3) else { add_3: if( val_short_tag(acc) == VAL_STRING || val_short_tag(*sp) == VAL_STRING ) { ACC_BACKUP buffer b = alloc_buffer(NULL); BeginCall(); val_buffer(b,(value)*sp); ACC_RESTORE; val_buffer(b,(value)acc); EndCall(); acc = (int_val)buffer_to_string(b); } else OpError("+"); } } } *sp++ = ERASE; Next; Instr(Sub) NumberOp(-,SUB,id_sub,id_rsub) Instr(Mult) NumberOp(*,MULT,id_mult,id_rmult) Instr(Div) if( val_is_number(acc) && val_is_number(*sp) ) acc = (int_val)alloc_float( ((tfloat)val_number(*sp)) / val_number(acc) ); else if( val_is_object(*sp) ) ObjectOpGen(*sp,acc,id_div,goto div_next) else { div_next: if( val_is_object(acc) ) ObjectOp(acc,*sp,id_rdiv) else OpError("/"); } *sp++ = ERASE; Next; Instr(Mod) if( (acc == 1 || (val_is_int32(acc) && val_int32(acc)==0)) && val_is_any_int(*sp) ) OpError("%"); NumberOp(%,fmod,id_mod,id_rmod); Instr(Shl) IntOp(<<); Instr(Shr) IntOp(>>); Instr(UShr) if( (acc & 1) && (*sp & 1) ) acc = (int_val)alloc_best_int(((unsigned int)val_int(*sp)) >> val_int(acc)); else if( val_is_any_int(acc) && val_is_any_int(*sp) ) acc = (int_val)alloc_best_int(((unsigned int)val_any_int(*sp)) >> val_any_int(acc)); else OpError(">>>"); *sp++ = ERASE; Next; Instr(Or) IntOp(|); Instr(And) IntOp(&); Instr(Xor) IntOp(^); Instr(Eq) Test(==) Instr(Neq) BeginCall(); acc = (int_val)((val_compare((value)*sp,(value)acc) == 0)?val_false:val_true); EndCall(); *sp++ = ERASE; Next; Instr(Lt) Test(<) Instr(Lte) Test(<=) Instr(Gt) Test(>) Instr(Gte) Test(>=) Instr(TypeOf) acc = (int_val)(val_is_int(acc) ? alloc_int(1) : NEKO_TYPEOF[val_short_tag(acc)]); Next; Instr(Compare) BeginCall(); acc = (int_val)val_compare((value)*sp,(value)acc); EndCall(); acc = (int_val)((acc == invalid_comparison)?val_null:alloc_int(acc)); *sp++ = ERASE; Next; Instr(PhysCompare) acc = (int_val)(( *sp > acc )?alloc_int(1):(( *sp < acc )?alloc_int(-1):alloc_int(0))); *sp++ = ERASE; Next; Instr(Hash) if( val_is_string(acc) ) { BeginCall(); acc = (int_val)alloc_int( val_id(val_string(acc)) ); } else RuntimeError("$hash",false); Next; Instr(New) BeginCall(); acc = (int_val)alloc_object((value)acc); Next; Instr(JumpTable) if( val_is_int(acc) && ((unsigned)acc) < ((unsigned)*pc) ) pc += acc; else pc += *pc + 1; Next; Instr(Loop) // space for GC/Debug Next; Instr(Last) goto end; #ifdef NEKO_VCC default: __assume(0); #endif }} end: vm->sp = sp; vm->csp = csp; return acc; } int_val *neko_get_ttable() { # ifdef NEKO_THREADED return (int_val*)neko_interp_loop(NULL,NULL,0,NULL); # else return NULL; # endif } value neko_interp( neko_vm *vm, void *_m, int_val acc, int_val *pc ) { int_val *sp, *csp, *trap; int_val init_sp = vm->spmax - vm->sp; neko_module *m = (neko_module*)_m; jmp_buf old; memcpy(&old,&vm->start,sizeof(jmp_buf)); if( setjmp(vm->start) ) { acc = (int_val)vm->vthis; // if uncaught or outside init stack, reraise if( vm->trap == 0 || vm->trap <= init_sp ) { char **tmp; memcpy(&vm->start,&old,sizeof(jmp_buf)); tmp = (char**)vm->start; if( *tmp == jit_handle_trap ) ((jit_handle)jit_handle_trap)(vm); else longjmp(vm->start,1); } trap = vm->spmax - vm->trap; if( trap < vm->sp ) { // trap outside stack vm->trap = 0; val_throw(alloc_string("Invalid Trap")); } // pop csp csp = vm->spmin + val_int(trap[0]); vm->exc_stack = neko_flush_stack(vm->csp,csp,vm->exc_stack); vm->csp = csp; // restore state vm->vthis = (value)trap[1]; vm->env = (value)trap[2]; pc = int_address(trap[3]); m = (neko_module*)int_address(trap[4]); // pop sp sp = trap + 6; vm->trap = val_int(trap[5]); while( vm->sp < sp ) *vm->sp++ = ERASE; // jit return ? if( val_is_kind(m,neko_kind_module) ) { m = (neko_module*)val_data(m); pc = (int_val*)((((int_val)pc)>>1) + (int_val)m->jit); acc = ((jit_prim)jit_boot_seq)(vm,pc,(value)acc,m); return (value)acc; } } if( m->jit != NULL && m->code == pc ) acc = ((jit_prim)jit_boot_seq)(vm,m->jit,(value)acc,m); else acc = neko_interp_loop(vm,m,acc,pc); memcpy(&vm->start,&old,sizeof(jmp_buf)); return (value)acc; } /* ************************************************************************ */ neko-2.0.0/boot/0000755000175000017500000000000012112157473014117 5ustar ncannassencannasseneko-2.0.0/boot/nekoml.n0000644000175000017500000103232412112157473015570 0ustar ncannassencannasseNEKOGʎ@Nekoml_Main@IOIO@Neko_Printer neko/Printer@HashtblHashtbl@ListList@Nekoml_Type nekoml/Type@Neko_Compile neko/Compile@LexerLexer@StringString@ReflectReflect@Nekoml_Neko nekoml/Neko@Neko_Lexer neko/Lexer@Nekoml_Typer nekoml/Typer@SysSys@Nekoml_Lexer nekoml/Lexer@ZipZip@Neko_Parser neko/Parser@StackStack@Nekoml_Parser nekoml/Parser@ArgsArgs@Neko_Bytecode neko/Bytecode@CoreCore@Sys_exit@List_iter@String_split@Stack_dump@Neko_Printer_create@String_concat@List_rev@Neko_Bytecode_write@Nekoml_Neko_generate@Core_@compare@String_length@IO_close_out@IO_stderr@Neko_Compile_compile@Core_chr@Core_printf@Nekoml_Lexer_error_msg@Args_String@Core_ignore@String_unserialize@Zip_uncompress@Core_@pcons@Neko_Printer_print@Core_Neko_error@Core_throw@IO_write_file@Core_@empty@Nekoml_Typer_load_module@Nekoml_Typer_module_infos@Sys_version@Zip_init@Hashtbl_iter@List_append@IO_file_contents@Core_@print_union@Core_None@Lexer_line@Nekoml_Type_file_name@String_sub@Neko_Parser_error_msg@Args_Void@Neko_Lexer_error_msg@String_serialize@Stack_exc@Nekoml_Parser_error_msg@String_get@Nekoml_Typer_context@IO_printf@String_set@Core_Some@Zip_compress@Hashtbl_add@IO_write@Lexer_null_pos@Core_ord@Reflect_loader_path@Lexer_source@Neko_Compile_error_msg@Nekoml_Typer_error_msg@Core_string@Nekoml_Typer_verbose@Sys_without_extension@Hashtbl_create@Args_parse@List_map/ Exception : %s  %s(%d): %s H.nekoGenerating %s .n Compiling %s a FileNotFoundFileNotFoundNekoML Compiler v.B - (c)2005-2013 Haxe Foundation Usage : nekoml [options] files... nekoml.stdCached %s [%d bytes] S$ : additional file search path-pm: verbose mode-vu#: generate intermediate .neko files-n} : build module packages-pack : use this module package-usecore/: disable std lib-nostd%s not found in %s :8Mpnekoml/Main@IO@String@BufferBuffer@Core@Core_@print_union@String_blit@Buffer_add_char@String_create@String_sub@Core_assert@Core_ord@Core_Exit@Buffer_add_sub@Core_Neko_error@Buffer_string@Core_sprintf@Core_throw@String_length@String_get@Buffer_add@Buffer_create@Core_magic@Core_chr@Core_min@Core_invalid_argOverflowOverflowEofEofClosed&ClosedBlocked1Blocked@loadstd@< file_open file_contents file_close file_readfile_read_char file_writefile_write_char file_flushPrbrCFswbw  file_stdin file_stdout file_stderrCMUIO.inputbIO.read IO.read_buf core/IO.nml=) W ` i r     IO.write_i8  IO.output  o  IO.write_ui16  IO.write_i16  IO.write_ui24 4 = F O X a  IO@String@List@Buffer@Core@List_iter@Buffer_string@Core_sprintf@Buffer_add_char@Core_throw@Buffer_add@Buffer_create@Core_chr@Core_invalid_arg@Core_Not_found@Core_ord@string_splitstd@string_split  String.get  String.set  String.blit  String.sub* J j    \n\t\r\\\"\%.3d*  String.unescape<@serialize std@serialize@unserializestd@unserialize8@String@List@ArrayArray@Core@Core_@pcons@Array_make@Core_@aset@Array_list@Core_@compare@Array_create@Core_throw@Core_@empty@Array_sort@Core_invalid_arg@Core_Not_found@makeY@rmakeyList.hdList.tl6 List.iter2QHA[ List.chop~ List.loopIList.nth f  List@Array@Core@Core_@aset@Core_throw@Core_@aget@Core_Not_found[, ] @makeF!@merge_sortstd@merge_sortV![!i!!!!":"d""""#$asubE#v##Array@CoreNoneSome#NoneSome$ Neko_error"$Neko_error0$Invalid_argument=$Invalid_argumentK$Assert_failureX$Assert_failuref$Errorw$Error$ Stream_error$Stream_error Not_found$Not_foundExit$Exit@sprintf std@sprintf@string()${ __string = ; }8%%@compare &E' Array.getQ' Array.setr'@empty[]'@pcons :: '@cons''''''''(Core.int ( Core.float"(;(Core.chr>(V(^(f(s({(((((o:0(Core.stream_token(Core.stream_junk`))nekoCore@Buffer@Core@buffer_newstd@buffer_new@buffer_addstd@buffer_add@buffer_add_substd@buffer_add_sub@buffer_add_charstd@buffer_add_char@buffer_stringstd@buffer_string@buffer_resetstd@buffer_reset///Buffer@Neko_Printer@IO@List@String@Neko_Astneko/Ast@Core@IO_write_char@List_iter@IO_write_string@String_make@Core_@compare@Core_None@IO_close_out@IO_write@Neko_Ast_s_constant@Core_assert@IO_printf@Core_fstr5}555%s5E6{;U6 }(  ).%s,var t6while do if elsetrycatch %s function( %s return;return break;break continue $new(null)neko/Printer.nml%s => 6%s:switch  => k7 default => 7 Z=(>M>>neko/Printer@Neko_Ast@List@Lexer@String@Core@Core_@pcons@Core_Some@Core_@print_union@List_iter@Core_None@String_escape@Core_@empty@Core_string@List_mapTrueFalseNullThisIntFloatBuiltinIdent>TrueFalseNullThisIntd?Floatq?String~?Builtin?Ident?VarWhileDoIfElseFunctionReturnBreakContinueDefaultTryCatchSwitch?VarWhileDoIfElseFunctionReturnBreakContinueDefaultTryCatchSwitch SemicolonDotCommaArrow BraceOpen BraceClose ParentOpen ParentClose BracketOpen BracketCloseConstKeywordBinopComment CommentLineh@EofSemicolonDotCommaArrowBraceOpenBraceCloseParentOpenParentCloseBracketOpenBracketCloseConstUAKeywordbABinopoAComment|ACommentLineA NormalWhileDoWhileANormalWhileDoWhileEConstEBlock EParenthesisEFieldECallEArrayEVarsEWhileEIfETry EFunctionEBinopEReturnEBreak EContinueENextEObjectELabelESwitchAEConstBEBlockBEParenthesisBEFieldCECallCEArray*CEVars;CEWhileHCEIf\CETrypCEFunctionCEBinopCEReturnCEBreakCEContinueENextCEObjectCELabelCESwitchCD DD*DEDWDiD{DDDDD EH6HCHYHtruefalsenullthis"$JvarwhiledoiffunctionreturnbreakdefaultcatchswitchK=>/**///sKneko/Ast@Lexer@IO@List@String@LexEngine LexEngine@Core@Core_Some@List_array@Core_@print_union@String_blit@IO_input@String_create@Core_None@LexEngine_make_tables@String_sub@Core_assert@Core_fst@Core_@aget@Core_max@Core_Exit@Core_Neko_error@LexEngine_determinize@IO_read_string@Core_snd@String_length@String_get@Core_throw@LexEngine_parse@Core_@empty@Core_min@Core_invalid_arg@List_map Invalid_rule!LInvalid_rule,L9L=LALiLLLLLM MM+NNNcore/Lexer.nmlOPPLexer.empty_table#Q,QLexer@LexEngine@List@Hashtbl@Array@String@Core@List_array@Array_make@Core_@print_union@List_iter@Array_map@Hashtbl_find@Core_None@Core_assert@Array_sort@List_mem@List_filter@Core_fst@List_rev@Core_compare@Array_iteri@Core_@aset@Core_@compare@Array_iter@String_get@String_length@List_exists@Array_init@Core_Some@List_fold@Core_ignore@Hashtbl_add@Core_@aget@Core_ord@List_assoc@Core_@pcons@List_concat@Core_Neko_error@List_sort@Core_snd@Array_length@Core_throw@Core_@empty@List_map@List_append@Hashtbl_createEmptyMatchStarPlusNextChoiceVQEmptyMatchQStarQPlusQNextQChoiceQRcore/LexEngine.nmlRRuSSSTTTJTYTjTUUUtVxVVVVV\WtWW1XXXXdY{YYYYYYZZ[0[A[\[ InvalidRegexp[InvalidRegexp[[[[\#\\\&]_]~]^LexEngine@Hashtbl@Core@Core_throw@Core_Not_found?`G`P`X`v`````Hashtbl@Nekoml_Type@List@Hashtbl@Lexer@String@Core@String_set@Core_@print_union@List_iter@String_make@Hashtbl_find@String_sub@Core_assert@Hashtbl_add@String_concat@Core_ord@Core_@pcons@Core_sprintf@Core_Neko_error@String_get@String_length@Core_@empty@Core_chr@Core_string@Core_invalid_arg@List_exists@List_length@Hashtbl_create@List_phys@List_mapMutable ImmutablekMutableImmutable TAbstractTMonoTPolyTRecordTUnionTTupleTLinkTFunTNamedkTAbstractTMonoQlTPolyTRecord^lTUnionklTTuple|lTLinklTFunlTNamedlTVoidTIntTBoolTFloatTStringTCharTIdentTConstrTModulelTVoidTIntFmTBoolSmTFloat`mTStringmmTCharzmTIdentmTConstrmTModulemMRootMFailureMHandleMExecute MConstantsMFieldMTupleMToken MRecordFieldMJunkMSwitchMBindMWhenMNextmMRootMFailureMHandlenMExecutenMConstantsnMFieldnMTuplenMTokennMRecordFieldnMJunknMSwitchoMBind"oMWhen6oMNextGoTConstTBlock TParenthesisTCallTFieldTArrayTVarTIf TFunctionTBinop TTupleDecl TTypeDeclTMut TRecordDecl TListDeclTUnopTMatchTTry TTupleGet TErrorDeclTWhileXoTConstpTBlockpTParenthesispTCallpTFieldpTArraypTVarpTIfpTFunction qTBinop!qTTupleDecl5qTTypeDeclBqTMutOqTRecordDecl\qTListDecliqTUnopvqTMatchqTTryqTTupleGetqTErrorDeclqTWhileqqq=rHrVr\rfrvoidintfloatcharerrorstringboolrrssRsZsssssssNekoml.Type.file_nametttmutable u '_%snekoml/Type.nml'%s{ %s } : =uhu(%s) -> ) u>xxxxzzznekoml/Type@Neko_Compile@Hashtbl@List@Lexer@Array@MapMap@String@Neko_Ast@Neko_Bytecode@Core@Neko_Bytecode_op_param@Neko_Ast_Builtin@Neko_Bytecode_SetIndex@Neko_Bytecode_trap_stack_delta@Neko_Bytecode_GlobalFloat@List_rev@Neko_Bytecode_Mod@Neko_Bytecode_Bool@Neko_Bytecode_Apply@Neko_Bytecode_MakeEnv@String_length@Array_iter@Neko_Bytecode_SetGlobal@Neko_Bytecode_Lte@Neko_Bytecode_Neq@Neko_Bytecode_AccIndex0@Array_set@Neko_Bytecode_AccIndex1@Neko_Bytecode_Or@Hashtbl_length@Core_Neko_error@Neko_Ast_EField@Core_snd@Neko_Bytecode_Not@Neko_Bytecode_GlobalString@Neko_Bytecode_AccEnv@Neko_Bytecode_SetThis@Core_@empty@Neko_Bytecode_ObjCall@Neko_Bytecode_Jump@List_length@Array_make@Core_@print_union@Neko_Bytecode_AccInt@Core_assert@String_sub@Array_sort@Neko_Bytecode_New@Neko_Bytecode_Pop@Neko_Bytecode_JumpTable@Neko_Ast_Ident@Array_add@Neko_Bytecode_PhysCompare@Neko_Bytecode_AccGlobal@Neko_Bytecode_Div@Neko_Bytecode_Ret@Hashtbl_add@Neko_Bytecode_Xor@Core_Exit@Neko_Bytecode_GlobalVersion@Neko_Bytecode_TypeOf@Array_length@Neko_Bytecode_SetField@Neko_Bytecode_Lt@Array_append@Neko_Bytecode_JumpIf@Neko_Bytecode_AccThis@Map_iter@Hashtbl_create@Neko_Bytecode_JumpIfNot@List_iter@Neko_Bytecode_SetEnv@Map_find@Map_add@Neko_Bytecode_Hash@Array_map@Neko_Bytecode_EndTrap@Neko_Ast_EConst@Neko_Bytecode_AccStack@Hashtbl_exists@Neko_Bytecode_Shl@Core_@aset@Core_compare@Neko_Ast_EBlock@Neko_Bytecode_GlobalDebug@Core_@compare@Neko_Bytecode_SetArray@Neko_Ast_EVars@Neko_Ast_EBinop@Neko_Bytecode_Eq@Neko_Ast_EIf@Neko_Bytecode_AccTrue@Core_ignore@Neko_Bytecode_Gte@Neko_Ast_Int@Neko_Bytecode_Sub@Core_@pcons@Neko_Bytecode_TailCall@Core_sprintf@List_sort@Core_throw@Neko_Ast_ECall@Neko_Bytecode_Mult@Map_empty@Neko_Bytecode_AccField@Neko_Bytecode_AccIndex@Hashtbl_iter@Neko_Bytecode_Shr@Hashtbl_find@Core_None@Array_create@Neko_Bytecode_UShr@Neko_Bytecode_IsNotNull@Core_fst@Neko_Bytecode_AccFalse@Neko_Bytecode_AccNull@Neko_Bytecode_Push@Neko_Bytecode_SetStack@Neko_Ast_iter@Neko_Bytecode_MakeArray@Neko_Bytecode_AccArray@Neko_Bytecode_Compare@Neko_Bytecode_AccBuiltin@Neko_Bytecode_Call@Core_Some@Neko_Bytecode_IsNull@Neko_Ast_This@Lexer_null_pos@Neko_Bytecode_And@Neko_Bytecode_GlobalVar@Neko_Bytecode_AccStack0@Neko_Bytecode_Add@Neko_Bytecode_AccStack1@Neko_Bytecode_Loop@Neko_Bytecode_GlobalFunction@Core_string@Neko_Bytecode_Trap@List_map@Neko_Bytecode_GtXEnvXStackXGlobalXFieldXIndexXArrayXThisXEnvXStackXGlobalXFieldXIndexXArrayXThisʂErrorՂStack alignment failure҄2YÆۆ>sBreak outside a loop͇Continue outside a loop݇array.apply<[0Variable declaration must be done inside a blockzneko/Compile.nml=É2Label is not supported in this part of the programDuplicate label ==^tnulltinttfloattbooltstringtobjecttarray tfunction tabstract;Invalid access+-*%<<>>>>>|&^!=>>=<<=Unknown operationq&&||++=--=+=-=/=*=%=<<=>>=>>>=|=&=^=:_mistruenottypeofhashnewcomparepcomparegotoUnknown label ޢKuthrowInvalid $goto statementaconcat{Ƥߤcall$tmp#Break in try...catch is not allowed&Continue in try...catch is not allowedyo:Label failure %d %d %s %sܬ ),w~_])neko/Compile@Map@Core@Core_compare@Core_@print_union@Core_@compare@Core_throw@Core_assert@Core_Not_found@Core_invalid_arg@Core_maxNodeݾEmptyNode+T core/Map.nmlMap.remove_min_binding]/V|Map@Neko_Bytecode@Hashtbl@IO@List@Array@String@Buffer@Core@Array_make@IO_read_byte@Core_@print_union@List_iter@Array_create@Hashtbl_find@String_make@IO_write_i32@Core_assert@IO_read_ui16@IO_read_i32@Array_iteri@Core_@aset@IO_read@IO_write_ui16@IO_write_string@Array_iter@String_length@Buffer_create@Core_invalid_arg@Array_get@IO_printf@IO_read_char@Array_init@Array_add@IO_write_char@Buffer_add_char@Array_set@IO_write_byte@Hashtbl_add@IO_write@Core_@aget@Core_@pcons@Core_Neko_error@Buffer_string@Core_sprintf@String_escape@Array_length@Core_throw@Core_@empty@Core_string@Core_error@Hashtbl_createAccNullAccTrueAccFalseAccThisAccIntAccStack AccGlobalAccEnvAccFieldAccArrayAccIndex AccBuiltinSetStack SetGlobalSetEnvSetFieldSetArraySetIndexSetThisPushPopCallObjCallJumpJumpIf JumpIfNotTrapEndTrapRetMakeEnv MakeArrayBoolIsNull IsNotNullAddSubMultDivModShlShrUShrOrAndXorEqNeqGtGteLtLteNotTypeOfCompareHashNew JumpTableApply AccStack0 AccStack1 AccIndex0 AccIndex1 PhysCompareTailCallLoop}AccNullAccTrueAccFalseAccThisAccIntAccStack%AccGlobal2AccEnv?AccFieldLAccArrayAccIndexYAccBuiltinfSetStacksSetGlobalSetEnvSetFieldSetArraySetIndexSetThisPushPopCallObjCallJumpJumpIfJumpIfNotTrapEndTrapRetMakeEnvMakeArray)BoolIsNullIsNotNullAddSubMultDivModShlShrUShrOrAndXorEqNeqGtGteLtLteNotTypeOfCompareHashNewJumpTable6ApplyCAccStack0AccStack1AccIndex0AccIndex1PhysCompareTailCallPLoop GlobalVarGlobalFunction GlobalString GlobalFloat GlobalDebug GlobalVersionaGlobalVarGlobalFunctionGlobalStringGlobalFloatGlobalDebugGlobalVersion  Invalid_fileInvalid_file#'Field hashing conflict  and yHNeko.Bytecode.write_debug_infosR%NEKOoNeko.Bytecode.read_debug_infosNeko.Bytecode.loop(neko/Bytecode.nmlEnglobals : %d  nfields : %d codesize : %d ops , %d total  GLOBALS =  global %d : %s  function  nargs string "float debug %d ops %d bytesversion ? FIELDS =  %s%s%.8X :CODE = x%.6X %6d %s  AccField  AccBuiltin  SetField END Tneko/Bytecode@Reflect@List@Core@Core_@print_union@Core_magic@Core_invalid_arg@List_mapVNullVIntVFloatVBoolVStringVObject VAbstract VFunctionVArray]VNullVIntVFloatVBoolVStringVObjectVAbstract)VFunction6VArrayC@module_readstd@module_read@module_namestd@module_name@module_exportsstd@module_exports@module_loaderstd@module_loader@module_execstd@module_exec@module_nglobalsstd@module_nglobals@module_global_getstd@module_global_get@module_global_setstd@module_global_set@module_code_sizestd@module_code_size@module_read_pathstd@module_read_path Reflect.valuePY"/7F^Reflect@Nekoml_Neko@Nekoml_Typer@Hashtbl@List@IO@Nekoml_Type@Lexer@Array@Neko_Parser@SetSet@String@Neko_Ast@Buffer@Core@Nekoml_Typer_module@Array_list@Set_add@List_iter@Nekoml_Type_TIdent@String_split@String_concat@Neko_Ast_Builtin@Neko_Ast_EConst@Neko_Ast_True@Neko_Ast_String@Neko_Ast_ESwitch@Nekoml_Type_t_string@List_rev@Neko_Ast_EBlock@Core_compare@Core_@compare@IO_read_string@Neko_Ast_EVars@Lexer_input@Neko_Ast_EBinop@Nekoml_Type_mk@Neko_Ast_EIf@Lexer_create@Neko_Ast_EWhile@Neko_Ast_Int@Neko_Ast_Float@Nekoml_Type_t_error@Neko_Ast_Null@Core_@pcons@Core_Neko_error@Neko_Ast_EField@Nekoml_Typer_union@Core_snd@List_sort@Neko_Ast_ECall@Core_@empty@Nekoml_Type_MRoot@Nekoml_Type_TModule@List_length@List_phys@Hashtbl_iter@List_append@Core_@print_union@Nekoml_Type_tlinks@Neko_Ast_ETry@Neko_Parser_parse@Hashtbl_find@Core_None@Core_assert@Nekoml_Type_file_name@Core_fst@Set_remove@Neko_Ast_EFunction@Nekoml_Type_TListDecl@Neko_Ast_NormalWhile@Nekoml_Type_MFailure@Neko_Ast_EReturn@Nekoml_Type_TString@Buffer_create@Neko_Ast_ELabel@Neko_Ast_Ident@Hashtbl_hash@Neko_Ast_ENext@Core_Some@Array_init@Neko_Ast_EArray@Neko_Ast_False@Nekoml_Type_TConstr@Hashtbl_add@Nekoml_Type_MExecute@Neko_Ast_EParenthesis@Lexer_null_pos@Core_ord@Set_empty@Nekoml_Type_TConst@Nekoml_Type_MSwitch@Nekoml_Type_TCall@Nekoml_Type_is_int@Core_string@Set_exists@Nekoml_Type_t_void@List_map@Hashtbl_createNative StructuralNativeStructurallv@"4nekoml/Neko.nmlF9D0zu::@empty@cons@exc stream_pos@posrethrow stream_token stream_junk_|  p ' 9   @print_union Bv@compareSandorxor===!==:=@asetidivneko'@pcons@aget@tmp8^!o""# $`%exportsloader loadmodule%&J&&nekoml/Neko@Nekoml_Typer@Hashtbl@List@IO@Nekoml_Type@Nekoml_Ast nekoml/Ast@Nekoml_Match nekoml/Match@Array@Lexer@Map@String@Set@Nekoml_Parser@Buffer@Core@Array_list@Nekoml_Type_polymorphize@String_concat@Nekoml_Type_TLink@Nekoml_Ast_EType@Nekoml_Type_TWhile@List_rev@Nekoml_Type_t_string@Nekoml_Type_TErrorDecl@Nekoml_Type_duplicate@String_length@Core_print@Nekoml_Ast_PRecord@Core_magic@Lexer_input@Nekoml_Ast_ETypeDecl@Nekoml_Type_TField@Nekoml_Ast_ATyped@Core_printf@Nekoml_Ast_EBlock@Lexer_create@List_iter2@Nekoml_Type_generator@Nekoml_Type_TTypeDecl@Core_@aget@Nekoml_Ast_Int@Core_Neko_error@Nekoml_Type_TFunction@Core_snd@Core_@empty@Nekoml_Ast_PConstr@Nekoml_Type_TModule@Nekoml_Type_TVoid@Nekoml_Type_TMut@List_length@List_append@Nekoml_Type_TIf@Nekoml_Type_TTry@Nekoml_Ast_SMagicExpr@Core_@print_union@Nekoml_Type_tlinks@Nekoml_Type_TNamed@Nekoml_Ast_Ident@Nekoml_Type_TInt@Nekoml_Match_make@Core_assert@Nekoml_Type_mk_record@Nekoml_Type_file_name@Nekoml_Type_TArray@Nekoml_Type_t_abstract@Set_union@Nekoml_Match_error_ref@Hashtbl_remove@String_get@Buffer_create@List_fold@Nekoml_Type_TRecordDecl@Hashtbl_add@Nekoml_Ast_PStream@Set_empty@IO_read_file@Nekoml_Type_genid@Nekoml_Type_t_bool@Nekoml_Type_t_char@Nekoml_Ast_EAbstract@Nekoml_Type_TConst@Nekoml_Type_TBlock@Nekoml_Ast_SPattern@Hashtbl_create@Nekoml_Type_t_float@Nekoml_Type_t_void@Map_iter@Nekoml_Ast_ETuple@Nekoml_Type_t_polymorph@Nekoml_Type_TChar@Set_add@Nekoml_Type_s_context@List_iter@Map_add@Map_find@Nekoml_Type_TIdent@Nekoml_Type_TBinop@Nekoml_Type_s_type@List_find@Nekoml_Ast_EConst@Nekoml_Ast_PTyped@Nekoml_Ast_EUnion@Hashtbl_exists@Nekoml_Type_TTupleDecl@List_all@Core_@compare@IO_read_string@Nekoml_Type_mk@Nekoml_Type_TParenthesis@List_exists@Nekoml_Ast_ECall@Nekoml_Ast_String@Core_ignore@Nekoml_Ast_ETupleDecl@Nekoml_Type_TFloat@Nekoml_Match_fully_matched_ref@Nekoml_Type_t_error@Nekoml_Type_mk_union@Core_@pcons@List_hd@Core_throw@Nekoml_Type_TMono@Nekoml_Ast_ETupleGet@List_nth@Nekoml_Ast_ANamed@Nekoml_Ast_PTuple@Map_empty@Hashtbl_iter@Nekoml_Type_Immutable@Nekoml_Type_Mutable@Hashtbl_find@Core_None@Nekoml_Type_t_int@Nekoml_Type_TTupleGet@Core_fst@Hashtbl_replace@Nekoml_Parser_parse@Nekoml_Type_TVar@Nekoml_Type_t_mono@Nekoml_Type_mk_fun@Nekoml_Type_TUnop@Nekoml_Ast_PIdent@Nekoml_Type_TString@Set_diff@Nekoml_Type_TMatch@Set_iter@Core_Some@Array_init@Nekoml_Type_t_poly@Nekoml_Ast_EVar@Nekoml_Ast_s_path@Nekoml_Type_TConstr@Lexer_null_pos@Nekoml_Ast_EPoly@Nekoml_Type_TBool@Nekoml_Ast_PAlias@Nekoml_Type_mk_tup@Nekoml_Type_TCall@Nekoml_Type_etype@Core_string@List_split@Set_exists@Nekoml_Type_pos@List_map Cannot_unify Have_no_field Unknown_fieldModule_not_loadedCustom'Cannot_unify6(Have_no_fieldG(StackX(Unknown_fieldi(Module_not_loadedv(Custom((Error( Cannot unify  have no field  Unknown field Module  require an interface(q))))nekoml/Typer.nml)))))) * Unknown type *'+Unknown constructor +>,Unknown identifier ,L--2.../ 0\00W1j1}11&Invalid number of type parameters for `5Unbound type variable 'r5568NIntNFloatNStringNNan:NIntNFloatNStringNNan ;;;Field  is not mutablereflistInvalid operation ;JJ@tKLL>MInvalid % sequenceNTyping  QQRSkSSopenassert invalid_argTYPE%s:(%d): type : %s format#Constant string required for formatToo many argumentsSvV0Variable declaration not allowed outside a blockzV&Invalid number of parameters for type "Invalid type redefinition of type ~VVVKW Duplicate declaration for field WWXMissing field  in record declarationZXwXXThis matching is not completeXXXaY'h|hh,This variable is several time in the patternijj$Constructor does not take parametersConstructor require parametersstream4kCkl Variable  must occur in all patternssssstkuuuu.nmlFile not found vKw anonymous Parsed %s wTyping done with %s wyyaznekoml/Typer@Nekoml_Ast@Lexer@String@Core@Core_@print_union@Core_snd@String_escape@Core_string@String_concat@String_escape_charCharConstrModule{Int|Char#|Bool0|Float=|StringJ|IdentW|Constrd|Moduleq|TypeThenWhen Exception|VarIfElseFunctionTryCatchTypeMatchThenWhenWhileExceptionQuoteVertical StreamOpen StreamClose7}EofSemicolonDotCommaQuoteBraceOpenBraceCloseParentOpen\~ParentCloseBracketOpenBracketCloseArrowVerticalStreamOpenStreamCloseConsti~Keywordv~Binop~Comment~CommentLine~ETypeEPolyETupleEArrow~EType~EPolyETupleEArrow EAbstractEAliasERecordEUnion.EAbstractEAliassERecordEUnionATypedANamedATupleATypedANamedATupleSPatternSExpr SMagicExprSPattern3SExpr@SMagicExprQPIdentPConstPTuplePRecordPConstrPAliasPTypedPStreambPIdent߀PConstPTuplePRecordPConstrPAlias+PTyped<PStreamM^EVarEUnop ETypeAnnot ETupleDecl ETypeDecl EErrorDecl ERecordDeclEMatch ETupleGetEApplyāEConstEBlockEFieldECallEArray%EVar6EIfGEFunction[EBinopuEUnopETypeAnnotETupleDeclETypeDeclEErrorDecl̃ERecordDecl݃EMatchETryETupleGet EApplyEWhile.?typematchthenwhen exception->[<>]*--cnekoml/Ast@Nekoml_Match@List@Nekoml_Type@Nekoml_Ast@Core@Nekoml_Type_TChar@Core_@print_union@Nekoml_Ast_Ident@Core_None@Nekoml_Type_TIdent@Nekoml_Type_MRecordField@Nekoml_Ast_PConst@Nekoml_Type_TInt@Core_assert@Nekoml_Ast_PTyped@Nekoml_Type_MField@Core_fst@List_rev@Nekoml_Type_MFailure@Core_@compare@Nekoml_Type_MHandle@Nekoml_Ast_PRecord@Nekoml_Type_TString@Nekoml_Type_MTuple@Core_magic@Nekoml_Type_mk@Core_Some@List_fold@Nekoml_Type_TConstr@Nekoml_Type_MExecute@Nekoml_Ast_PStream@Nekoml_Type_TFloat@Nekoml_Type_MToken@Nekoml_Type_MJunk@Nekoml_Type_MBind@Nekoml_Type_TBool@List_assoc@Core_@pcons@List_concat@Nekoml_Ast_PAlias@Core_Neko_error@Nekoml_Type_MSwitch@Core_snd@Nekoml_Type_TConst@Nekoml_Type_MConstants@Nekoml_Type_MWhen@Nekoml_Ast_PConstr@Core_@empty@Nekoml_Type_MRoot@Nekoml_Type_MNext@Nekoml_Ast_PTuple@Nekoml_Type_TVoid@Nekoml_Type_TModule@List_map@List_length@List_append@Nekoml_Type_t_voidTotalPartialDubious֋TotalPartialDubious nekoml/Match.nml'U_iьی9Ҏ !`|А|b|ג2 ! 4Some pattern are never matchedThis pattern is never matchednekoml/Match@Set@Core@Core_compare@Core_@print_union@Core_throw@Core_assert@Core_Not_found@Core_maxEmptyNodeE\ core/Set.nmlX?Gdy!׬&]eڰ$Set@Nekoml_Parser@Nekoml_Lexer@Nekoml_Ast@Lexer@Core@Nekoml_Ast_EMatch@Nekoml_Ast_ETypeAnnot@Lexer_punion@Nekoml_Ast_EConst@Nekoml_Ast_EUnion@Nekoml_Ast_PTyped@Nekoml_Ast_EUnop@Nekoml_Ast_EType@Core_Stream_error@Nekoml_Ast_EArrow@Nekoml_Ast_EBinop@Nekoml_Ast_ETypeDecl@Nekoml_Ast_PRecord@Nekoml_Ast_ECall@Nekoml_Ast_EApply@Nekoml_Ast_ATyped@Nekoml_Ast_EBlock@Nekoml_Ast_EWhile@Nekoml_Ast_s_token@Nekoml_Ast_EFunction@Nekoml_Ast_EErrorDecl@Nekoml_Ast_ETupleDecl@Nekoml_Ast_SExpr@Core_@pcons@Nekoml_Ast_EField@Nekoml_Ast_Int@Nekoml_Ast_Module@Nekoml_Ast_ERecordDecl@Core_Neko_error@Core_snd@Nekoml_Ast_Constr@Nekoml_Ast_EAlias@Core_throw@Nekoml_Ast_PConstr@Core_@empty@Nekoml_Ast_PTuple@Nekoml_Ast_ANamed@Nekoml_Ast_EIf@Core_@print_union@Core_stream_junk@Core_None@Nekoml_Ast_Ident@Core_stream@Nekoml_Ast_PConst@Core_assert@Core_fst@Nekoml_Lexer_token@Nekoml_Ast_ATuple@Nekoml_Ast_ETry@Core_stream_pos@Nekoml_Ast_PIdent@Core_stream_token@Nekoml_Ast_ERecord@Core_Some@Nekoml_Ast_EArray@Nekoml_Ast_EVar@Nekoml_Ast_pos@Nekoml_Ast_PStream@Nekoml_Ast_EPoly@Lexer_null_pos@Nekoml_Ast_EAbstract@Nekoml_Ast_PAlias@Nekoml_Ast_SPattern@Nekoml_Ast_Eof@Lexer_token@Nekoml_Ast_ETuple UnexpectedUnclosed%UnexpectedYUnclosedfsError~ Unexpected  Unclosed ʳ<>ٳ|GV^nekoml/Parser.nmlGoFrecfrHxDmutableQ=asKk{ nekoml/Parser@Nekoml_Lexer@Hashtbl@List@Nekoml_Ast@Lexer@String@Neko_Lexer@Buffer@Core@List_iter@Nekoml_Ast_Var@Lexer_punion@Lexer_char@Nekoml_Ast_Float@Nekoml_Ast_Quote@Nekoml_Ast_Keyword@Nekoml_Ast_Char@Nekoml_Ast_Then@Lexer_current@String_length@Core_chr@Nekoml_Ast_String@Nekoml_Ast_Binop@Neko_Lexer_ecomment@Nekoml_Ast_Vertical@Nekoml_Ast_Try@Nekoml_Ast_ParentOpen@Nekoml_Ast_BracketClose@Nekoml_Ast_Match@Nekoml_Ast_Arrow@String_escape_char@Buffer_reset@Nekoml_Ast_StreamOpen@Core_@pcons@Nekoml_Ast_Int@Core_int@Neko_Lexer_estring@Core_sprintf@Core_Neko_error@Lexer_build@Nekoml_Ast_Constr@Core_throw@Nekoml_Ast_Bool@Nekoml_Ast_Catch@Core_@empty@Nekoml_Ast_CommentLine@Core_@print_union@Nekoml_Ast_Ident@Hashtbl_find@Nekoml_Ast_Semicolon@String_sub@Nekoml_Ast_Const@Nekoml_Ast_BraceClose@Nekoml_Ast_Function@Nekoml_Ast_Dot@Nekoml_Ast_Comma@String_get@Nekoml_Ast_BraceOpen@Nekoml_Ast_BracketOpen@Nekoml_Ast_Else@Nekoml_Ast_Exception@Hashtbl_add@Lexer_empty@Nekoml_Ast_ParentClose@Nekoml_Ast_If@Lexer_data@Buffer_string@Nekoml_Ast_StreamClose@Nekoml_Ast_Type@Nekoml_Ast_When@Nekoml_Ast_Comment@Lexer_token@Nekoml_Ast_Eof@Lexer_curpos@Hashtbl_create@Nekoml_Ast_s_keyword@Nekoml_Ast_WhileInvalid_characterUnterminated_stringUnclosed_commentInvalid_escaped_characterInvalid_escapeInvalid_characterUnterminated_stringUnclosed_commentInvalid_escaped_characterInvalid_escapeError Invalid character '%s'Unterminated stringUnclosed commentInvalid escaped character %dInvalid escape sequencedy'[a-z_][a-zA-Z0-9_]*[A-Z][a-zA-Z0-9_]*[-!=*/<>&|%+:][0-9][ ]+;GS^it\[0x[0-9a-fA-F]+/\* '\\n''\\t'4'\\r'I'\\''^'\\\\'s'\\"''[^\\]''\\[0-9][0-9][0-9]' //[^ ]* ?<\[<GR?]vnekoml/Lexer@Neko_Lexer@Hashtbl@List@Lexer@String@Neko_Ast@Buffer@Core@List_iter@Neko_Ast_Default@Neko_Ast_Keyword@Neko_Ast_Semicolon@Neko_Ast_BraceOpen@Neko_Ast_Function@Neko_Ast_ParentOpen@Neko_Ast_BracketClose@Neko_Ast_Builtin@Lexer_punion@Neko_Ast_True@Lexer_char@Neko_Ast_String@Neko_Ast_Return@Neko_Ast_Continue@Neko_Ast_While@Lexer_current@String_length@Neko_Ast_BracketOpen@Core_chr@Neko_Ast_Try@Neko_Ast_Int@Neko_Ast_Float@Neko_Ast_BraceClose@Neko_Ast_ParentClose@Neko_Ast_Null@Buffer_reset@Core_@pcons@Core_int@Core_sprintf@Core_Neko_error@Neko_Ast_Switch@Lexer_build@Core_throw@Neko_Ast_Do@Core_@empty@Neko_Ast_Binop@Neko_Ast_s_keyword@Core_@print_union@Hashtbl_find@Neko_Ast_Dot@Neko_Ast_Arrow@String_sub@Neko_Ast_If@Neko_Ast_Else@Neko_Ast_Catch@String_get@Buffer_add@Neko_Ast_Ident@Buffer_add_char@Neko_Ast_Break@Neko_Ast_Const@Neko_Ast_False@Neko_Ast_This@Hashtbl_add@Lexer_empty@Neko_Ast_Comma@Core_ord@Neko_Ast_Comment@Core_Exit@Lexer_data@Neko_Ast_Eof@Buffer_string@Neko_Ast_Var@Neko_Ast_CommentLine@Lexer_token@Lexer_curpos@Hashtbl_create Unclosed_nxmlInvalid_character<Unterminated_stringUnclosed_commentUnclosed_nxmlInvalid_escaped_characterIInvalid_escapeVErroraInvalid character '%c'Invalid character 0x%.2X Unclosed nxmlr  ' E ^ [a-zA-Z_@][a-zA-Z0-9_@]*[-!=\*/<>&|^%\+:]    Continue      ) 4 ? J U ` [ ]+[0-9]+ [0-9]+.[0-9]*.[0-9]+l       f  ( < P ` p  \*/ \* [^*]+  \\" \\\\ \\n5 \\tK \\ra \\[0-9][0-9][0-9]   [^\\"]+   [^<]+neko/Lexer@Neko_Parser@IO@Neko_Binast neko/Binast@Lexer@Neko_Xmlneko/Xml@Neko_Ast@Neko_Lexer@Buffer@Core@Core_@print_union@Core_stream_junk@Neko_Ast_ETry@Core_None@Neko_Ast_Keyword@Neko_Ast_Default@Core_stream@Neko_Xml_parse_string@Lexer_punion@Neko_Ast_EConst@Core_fst@Neko_Ast_ESwitch@Neko_Ast_EFunction@Neko_Ast_NormalWhile@Neko_Ast_DoWhile@Neko_Ast_EBlock@Core_Stream_error@Core_stream_pos@Neko_Ast_EObject@IO_read_string@Neko_Ast_s_token@Neko_Ast_EVars@Neko_Ast_EReturn@Buffer_create@Lexer_input@Neko_Ast_EBinop@Core_stream_token@Neko_Ast_ELabel@Neko_Ast_pos@Neko_Ast_EContinue@Neko_Ast_Ident@Core_Some@Neko_Ast_EWhile@Neko_Ast_EIf@Neko_Ast_EArray@Lexer_create@Neko_Ast_Int@Neko_Ast_EParenthesis@Lexer_null_pos@Neko_Binast_parse_from_string@Core_@pcons@Neko_Ast_Eof@Neko_Ast_EField@Core_Neko_error@Core_snd@Core_throw@Neko_Ast_ECall@Neko_Lexer_expr@Core_string@Core_@empty@Neko_Ast_EBreak@Lexer_token Invalid_nxml,Unexpected-Unclosed$-Invalid_nxml1->-ErrorI-Invalid nxml (Z---//b012@CwFlGHK LL0MNlOOSPneko/Parser@Neko_Binast@IO@Lexer@Array@Neko_Ast@Core@IO_read_byte@Neko_Ast_ETry@Core_None@Array_create@Core_assert@Neko_Ast_Builtin@IO_read_ui16@Neko_Ast_True@Neko_Ast_EConst@Core_fst@IO_read_i32@Neko_Ast_String@Neko_Ast_ESwitch@Neko_Ast_EFunction@IO_read@Neko_Ast_EBlock@Neko_Ast_NormalWhile@Neko_Ast_DoWhile@Neko_Ast_EObject@IO_read_ui24@Neko_Ast_EVars@Neko_Ast_EReturn@Array_get@Neko_Ast_EBinop@Neko_Ast_ELabel@Neko_Ast_Ident@Neko_Ast_EContinue@Neko_Ast_ENext@Core_Some@Array_add@Neko_Ast_EArray@Neko_Ast_EWhile@Neko_Ast_EIf@Neko_Ast_False@Neko_Ast_Int@Neko_Ast_This@Neko_Ast_Float@Neko_Ast_EParenthesis@Neko_Ast_Null@Core_@pcons@Neko_Ast_EField@Array_length@Neko_Ast_ECall@Core_@empty@Neko_Ast_EBreak@Core_errorneko/Binast.nmlPNBAPPInvalid const tag :  QInvalid op tag QRS"SWSvSInvalid expr tag : SInvalid binast header;Wneko/Binast@Neko_Xml@List@Lexer@String@Neko_Ast@XmlXml@Core@List_iter@String_split@String_concat@Neko_Ast_Builtin@Neko_Ast_EConst@Neko_Ast_True@List_rev@Neko_Ast_String@Neko_Ast_ESwitch@Neko_Ast_EBlock@Core_@compare@Xml_attrib@String_unescape@String_length@Neko_Ast_EVars@Neko_Ast_EBinop@Neko_Ast_EWhile@Neko_Ast_EIf@Neko_Ast_Int@Neko_Ast_Float@Xml_Node@Neko_Ast_Null@Core_int@Core_@pcons@Core_Neko_error@Neko_Ast_EField@Neko_Ast_ECall@Core_throw@Core_@empty@Xml_node_text@List_append@Xml_node_name@Core_@print_union@Neko_Ast_ETry@Core_None@Core_assert@String_sub@Xml_firstNode@Neko_Ast_EFunction@Neko_Ast_NormalWhile@Neko_Ast_DoWhile@Neko_Ast_EObject@String_get@Neko_Ast_EReturn@Neko_Ast_s_constant@Core_invalid_arg@Neko_Ast_ELabel@Xml_nodes@Neko_Ast_Ident@Neko_Ast_EContinue@Neko_Ast_ENext@Core_Some@Neko_Ast_EArray@Xml_parse@Neko_Ast_False@Neko_Ast_This@Neko_Ast_EParenthesis@Lexer_null_pos@Neko_Ast_EBreak@Core_string@List_mapYErrorY neko/Xml.nmlYYNeko.Xml.errorZZifsbgconextobjectlabel=[[[[[case[Unknown node name : \Neko.Xml.parseccXdddkneko/Xml@Xml@List@IO@String@Buffer@Core@Core_@print_union@List_iter@List_find@IO_write@String_concat@List_filter@List_hd@String_lowercase@Buffer_string@IO_write_string@Core_snd@String_escape@Buffer_add@Buffer_create@Core_invalid_arg@IO_printf@List_mapPCDataCDataDocumentlNodeXlPCDatallCDataylDocumentllErrorl@parsero:0lll3mqm@parse std@parse_xmlmmmn Xml.firstNode'n Xml.nodespn Xml.node_namen Xml.node_textn-omo Xml.attrib~o<%s%s="o/> opXml@Sys@List@Array@String@Core@Array_make@Core_Some@String_split@Core_None@String_concat@Core_assert@List_rev@sys_exit std@sys_exit@get_env std@get_env@get_cwd std@get_cwd@exe_pathstd@sys_exe_path@sys_file_typestd@sys_file_type@sys_read_dirstd@sys_read_dirs}}\ core/Sys.nml ~r~~std@sys_exists~ std@put_env~ std@set_cwd~dir~~Sys@Zip@String@Buffer@Core@Buffer_add_sub@Core_@print_union@Buffer_string@String_create@Core_None@String_length@Core_throw@Core_string@String_sub@Buffer_create@Core_ErrorNOSYNCFULLFINISHBLOCKUNOSYNCFULLFINISHBLOCK@set_flush_modezlib@set_flush_mode@inflate_initzlib@inflate_init@deflate_bufferzlib@deflate_buffer@inflate_bufferzlib@inflate_buffer@deflate_initzlib@deflate_init@deflate_boundzlib@deflate_bound@deflate_endzlib@deflate_end@inflate_endzlib@inflate_end"2:DLfāCompression failedӁA{Zip@Stack@IO@Array@Core@Core_@print_union@IO_stdout@Array_iter@IO_write@IO_printf CFunctionPos>CFunctionModuleuPos@make_stackCalled from a C function $Called from %s (no debug available) Called from %s line %d etStack@Args@List@Sys@Hashtbl@Array@Core@Sys_exit@Core_int@Core_@print_union@List_iter@Core_Neko_error@Hashtbl_find@Array_length@Core_throw@Core_print@Hashtbl_add@Sys_args@Core_@aget@Core_printf@Hashtbl_createVoid-VoiddStringqInt~InvalidInvalid Options :  %s %s φ-help--helpۆInvalid argument : ̈ArgsBnekoml/Mainnekoml/Main.nmlIOcore/IO.nmlStringcore/String.nmlListcore/List.nmlArraycore/Array.nmlCorecore/Core.nmlBuffercore/Buffer.nmlneko/Printerneko/Printer.nmlneko/Astneko/Ast.nmlLexercore/Lexer.nmlLexEnginecore/LexEngine.nmlHashtblcore/Hashtbl.nmlnekoml/Typenekoml/Type.nmlneko/Compileneko/Compile.nmlMapcore/Map.nmlneko/Bytecodeneko/Bytecode.nmlReflectcore/Reflect.nmlnekoml/Nekonekoml/Neko.nmlnekoml/Typernekoml/Typer.nmlnekoml/Astnekoml/Ast.nmlnekoml/Matchnekoml/Match.nmlSetcore/Set.nmlnekoml/Parsernekoml/Parser.nmlnekoml/Lexernekoml/Lexer.nmlneko/Lexerneko/Lexer.nmlneko/Parserneko/Parser.nmlneko/Binastneko/Binast.nmlneko/Xmlneko/Xml.nmlXmlcore/Xml.nmlSyscore/Sys.nmlZipcore/Zip.nmlStackcore/Stack.nmlArgscore/Args.nmlʎ"pZ>>v$zz>>F&$>Jnz>Vf^f*$>Jn>vff*$fz>N>>j$>">b>>>>VZr 4>jbb>>$>Z>>PJ>h>.h>PT>,>>z~>>F $><>6" 0>bnn.D>>>>n&>>>Jj*6<>F*t~~>Vr~rr`RD.< x>b& Zj.*D>F*D~&$&T6F p<$2$^>>j>$v^^VVb>Jzr,v^^VVJf>J>rr>>"T~:>ZNJN>*x>"4x>\ZJNbz:>"D>lZ^bb>:$Z^2$Z^b>$Z^fn,bf&8ZZZ"T  D"$> $>V:$^>>j>$Rfb>Jzr>,^rr:$>Vb:$>V^*$>Vbr:$",bff& ZZZZ"$> " ZN^nDbv$>&$>>&$vv$vv<>Z&>$fj>ph>TV*$6$>>z   $,&4>6<*tn>>>b***$&,&&4>>6<*L2ph>>&$Z^VVb>r>Fr>>>>>>>>>>>>>>>>D6hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hT6h:h46h$6hh@>@@f>,ZvV>Jbr>>r>$ZvV>Jbr>>r>L$* "PNZ>$NN>6,>ZH> H<>Z&<>Z&<>Z>><>Z(>&(<>npp`"<>^&j>&`>Z&z>>.L>Z0>:0<>Zh>>h<>Z&>>&<>Z&>><>Z&>:<>ZH>:H<*$>Z>><>Z>>D>Z>.N><2$ZN>^&x>x<>Z>:D>Z>:L>Z&8>>8(N:Z>>>d>Zv>>Z">>Df.Zf*"JNVN^>V^^b4><$6,JVn>F>Rb:,&$:,ZN^b:4ZN^v:4NNV^j6F:4>4NVV^^>4NNV^z6N>.4>4NVN^>^N&"X >>>>*<>n>r>>F>rzz:ܞN>V^NbN^>J^^b*$ZNNrZ^^^>>Fb$Z^RNb^>J^^b"$nRfbbZZNR>FbN^>z^NfJR>FbbN^Z~>>N^N>Fj$~jR>>D $$:$2$NN$Zv$Zv$ $>V$$$2$$2$>$>$&$:$RZZ.,^RNjr>V^zZ.,fv^>fZ^f6<X > >>,>J>N>N>N>N>N>x44bR^^$ $$$$$ $44 $, $ $$ $ $ $ $ $&$ D>>>>>>>>>>>>>6 ~$$ t $ $dd d dt 4 ldD 4>>>>>>>> >>>>:44Z>< < <>>>.<><>>L><><><><:<6<$>>*<><>\>L:D6D d> <>>>>>>>>>>>*  "($&$$z~~~~>$ $ $ ,JN>>> >>>>:dJ4 $ $ 4 4< $&d66x*l*tz$>>>>>>>>> >>>>>>>>>4<>J>N>N><,jnnnnnn:D&, >L&, rvbb"< D $ $ 4 l tD4<T \ L $ $, 4 \<4D< $ D>>>>>>>>>>>>>>>>>>>>>>"8J N"$V>^&$>Z>$V~>*\>dVZj&Vz>^j2>Z2>~Z>2 VZjfZ6@Vn>>>>"P$ff> 4fZ:PV>PVj>F>PXVjZ>Pf>"D Lf.P>>fZ>P"frjZ> P28f^>n>^Pj>P&P2fv~>Pf>nj>P2R>zv~v>>&P>.P f:P>8.PHf2PpVj^2P&&P&f&>>|Rf>PP> P2`f^j^> 4 <>ZjfZ>Df>P Z>>F> (&,~jfrf*(&db>Jz&(nZj&>> 4&T.|r^f^*>!"# >>>>>>>>>>>>>"d>>>>>>>>>>>>:>>>>>>>>>>>>>>>>>>>>>>><>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>2,>$>$>.$> $> $> $> $>\V>^> &l>R>*X`>>>`N>`>`>`$>2`,>"`<,2`2l>>`2t>>>>>`2|>>`>`2>>`>2>L`>2>D.`>"`>4`2>>>>>.`>>>Lr>PV>>> XN6X*X2X$>X,> X4> X<> X2D>>>>XL> XT&X\> X>2d&LX>2l&D&Xt> X|> 4 X2>>>>2X>nRRR(,&(4(<> (D"(L(t>>RRRRRRRRRRRRR>>jRRRRRRRRRR(d&(l&(t(|2("(%"'>"$N,J~>D $J^NhNbNN@8$$Z^ff^^^"fzzVf>fVZ>nvvrr$Z^rV:,Fbvvf2>"<:>Fn^^^^z>RR^^V>N>vf>^vfvVb>VX^bb"P,>> d>Fj:>>,br>\>lZ>$>>>>^>JX>)"+h @>>>>>>>>>>>:$~ >>>>$^>>Z>>^.>*T&>Z>> h>>>hXN>4>v2>.<>&$>DJ &<>n>&$:,>>$^>^D^j>vl^j>v>"^>>>F&>*R>>"D>>>>>>>*>>R>b> @>>^>X>>4>"$>.>D~ &>"L>^f>.dF:(>"$Nrv>R(:d\>fJ:>"$Nrvz^r>F>>J>>2$>>>>0R8:Z^^VVVV:>> R>Jr>J<>V*DjRb>Z>j*4 <,jRn>JZ>f:DzH.4>^>$>>>J> $2$fn>>>:<( <( <( <( <( <( <( D( l>J:  <>J:  <>J: & fN^>f>^>. ~r>  D>V>f>.X ^>>X p RVbbrr>>~6 6 6 , >>n^r>v>"  >>  >*  -"/$"$$vn$:$:$:$>$*> $ $ $ 4 $ $ $ $>>>>-+>>>>>>>>>>>>>>>>>4>>>>>>\N>$> |l&$&4 D><:$>. d>,*, $|>6<:<6< <>>>>>>>>>>>>>>)'>>>>>>>>>>:<4>NL $ $ d L $ L"d,*8 T>>>>>>>:%#>>>>>>>>>>>>>d>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>,>>>>>>>>>>>>>>>>>>>$ $ $ $ $ $ $ $ t >>>>>>>&!>>>>>4 D ,, D>\$>>* >2|>>>>621"3 >>><>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>t>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>$>z*> D*$f$4F XT>">>>v`>``T.D &4$(>>* :<^&X>><^>...4>Z&00>$f>N>R>>j>60JNDZ>2$>ZR`>>>>>rV>R>>"$Nr>j>&TR>R> >"$Nr>F >&>>*>>>>> >~>&2 >f >> >>> ,jR>: >z: > 6 >>V>6X ^NJ>h >", z>>FRr> $>6 ,>> 4>. <> D>>: 2L>>> \ h :>Z>( ^N>v8 >~8 $>"8 ,>"8 4>8 <> 8 D>>"8 L>&8 >>>>>>>>>>> >>,>>>>>>>>>d,>>>>>>>>>d>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>4 $> D$ , $ DNn>& T> D<<&D<<<<> |< L < <>>. >D> >>>>>>>>>>>>>>>*15"7 >>>>>>>>>>>*X>>$ $>>>>>>>>>>>>N`x""2.N""".>>>>.">">$&$f>>V>J>0>nz>J06D^> ,>Fv>Z2<>>Zz>L>>"Zz>L>>XZz>4>"$JJ>>"$bzr>dNRVf^^> $.hVn*$.nnZ*$~>~>$>>,V>z^z >$ R< LZz>>j>F> r>,~>T~>0 ~> J>^ > $>J>n $ $ 4 h V>TVv>Fv>>>>h >R>Z*h >,>>>>: b>F $> $~>>6 Z>>>>( ( $~>>>( ( $~>& >t>R:4 h >>> r>^>Fv>>>jv>F>^V^v>Fv:> N:TZ>F>Fv>F>". >h >>>>" >F>"` r h > R>>v>>fVN 4>>>> ^>>>>> ~>>>~v>, 4>Z > $> >nrrr2 ,> 4>> <>> L>>>>r> > > $: ,: 4: <: D: L: &\>  FvfJ> >Vv>V 6D>b>>:p >"~>p > 0>>>JvfJ>X>Vv>VX6D2@>"|~"@20H0> rj0>>>rj0>"rjvj 0&X:0>n>>*>$> ,>2.d>n>>*>$> ,>j~2.|>>>>>>>>b*X*X*X$&X,&X4&X<&XD&XL&XT&X\&Xd&Xl&Xt&X|&X&X&X&X>>>>>>>>nv.4rjz\rjzfVnf>Zjv>>Nf~> fVnf>Zjv>>Nf~> Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.>>>>v*>>Dr*>>.,r*>>\r*>>>>>*t>> >>&rjv6r>&t>^2`\Z, pJhdRP$Nr>^>Fj>>r>jv>F> h$z>>>>>F>.><>zZ>~f.TRj>N:\>^>b>>>>tf>,r2>>>>>>v*>>:,r*>>:Dr*>>:\r*>>:tr*>>>>rjv*>>>>6rjv*>>>>>">>>>j:4>f"$6<D>>R>f^>j>2X>X$>Dx>&>*>>T>>~>>Vfvp$$r>>> $r^>">  $>JR>>>>Z2>:>>>$v:>> r2Dr2V>^2>$f>.(>z2Vjvz:4\V>vZ>&t V>ZzT$Vjjvj> >VVj>>>>&$&&4R>&dV>~v6> r>>>>>>>>>>>>>>>>f>N>>>>>>^>V>J>>z>>>>v~&6L>>>>&>>>>>>2>>> $rj~>>H H$rR>>>*>>r>>>"rjv>6<>> ^>RvjbvZjZ:"x^>RbvZv>f>2Rvjzv>"$^Zzv6.2@^VV^^>^v>v>v^Zj>>>jbZjV>^z~Z>>2>>>>>>vVV $>^2X>ZX>X$nV>b>>rV>b>> r>&f*&(>NJ>0>>r~06>>>>Z>>>>>fnZ>>>>>>>>> Fzvzj(>N H>b2`>`$^> L TV>>"rj> 4 <>^28 >>.8 $^>$ ` ,Vf> >!~>vf6$~>4zj>@"Vjj~:$`"  ^^ "T ,@!$Z(!JN< P!J$Zb!>bvnZ>~RR^^Z^~:$&!,>Z^~f.L@"Tf>b:>9";>>>>> \>jV8<>>2$^^j>>>>>R>>>>>f:.,6Tj>>>>>R>>>>>f:.,6T>>$>>jpn.pD>>V>>>J.D~ $r>"d HD 4>4>>n>v^f>f>>>">2`D>>n>J>F. >\*4>>n>R>>>>V  >2\hD>>n>>^ >D*,>Z>bj>N> L&,>Zp>ff>>&p`N> \"<>Z>>>&N> <6>>>*>>,, <$">D>D.T < < $ * l l >>>>>>>*972="?>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> L*4$>>>>>>>>>.h: h>  h h> h">>>>:h:h  >>>$ZJn>>>>":.$ZJn>>>>":.$ZJn>>>>":L|v>2Z^:d lR>V`$>J:>4bf>Nr^>V>n^>$VbZZV>J>zb^z>zz6$N^r^V>N>^~~VV>"|> *T>f>>>>2>>$>> ,>64>TbV>>>>>>>>>RRRR@ ,.@ 4>@ <.@ D.@ L>F@ \>@ d>@ l.@ t.@ |.@ >F@ nR@ .@ .@ .@ >>@ >>@ >>@ >>Z@ .@ .@ nRRRRRRRRRRRRRRRRRRRRRRRR@  .@  nRRRR@ @ >^*@ X J^>F>Z>vz>N>N6Vj>N~~f:L T $> 0 & ^^f.  >L"|"4ZbnVb>Z>RZrnZjVb>jr>Fn>F>Vbb>r>V>H R^Vb>z>NbVV>@ >> V*d>2X$^>X<^>XT.Xdv*X|.XXZb^Jn>0>",r20>HfzZ>>>>>b>p>p>p.$>p,&p*L>J>:Fnzbbb>>>Z>>.V~VV^fb>Z.>>>$>,&"<>>>>>>>>>N   $,4&<DL>>>>T\&d>>>>lt|>>>>>>>>>>>> (08@HPX`hpx> >N>j>F>R","DhL&, 4.>>> XV>n:`>n>:`,> `46`Drr>>`d6` X*>>>>>^>>>>>>>>>V& & & .$" ., .4" .< .D" .L" .T" .\ .d" .l" .t" .|" .6 .6 .6 .6 ." ." ." ." ."  2>.V>N>N>N>brf> PnrNV> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>L>N$ " : t> >>>>>>=7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>TDT>$ $ $ $ <&D*D*D*$ l T , 4, $ >" *(>>>2x>d>|>>>@>2>>>>>>" >>>>>>>>>>>>>> 52A"C>>>>>>>>>>>>>>>> ԮV^^^^^^^^VNfffffff><>nP*P*P$&P,&P4&P<&PD&PL&Pt$*$Z6$*46,FVV^b>,$2$2$2$$:$Z> $>> >>>>>>>>>lz~~~~~~~~ t $$, $$ l $$$$ $$,>>>>>>>> AE"G >>>|Nr:$Nr:$>$> $> $> \>Z2`>>`H>VR><.H&\&H>Z2>>>Z>>>>V>>>>R~>V>ZR><.&\&>6$p$p^p$p^p,pTb>>>$>:$z>2<>f PPP$PL>>>>>6$>>&$>>&$>>&$>2,T>F>:DF>>"$>^~>6h>r&h>>h>hL> h$:h4:h,>hD>>>h>"T>h\>h.d:h>>>>>"T>h\>h>>l> h> |>>>>>>hV>>V>>>F>&$&"4>>&`F>`>VRf>>"l.>f^>>.D^rz>>>>|N>>b>>>Z>f>>>>>fZr.8>28,VV>>f>>>>>>*2$ >>Z>>>:r>>>2(>>&>>8 >>>>22>>>2H r$ ` >>>~>>X >x>~>"D L>>.2rV>jz^>>>>> nzz>>8RbZv^z>>>>`:  >$ <~~RN>>>F>>>F>>>>>>$^b>>N>>>J>>>dn> >>b> ,z>>>Z>>>^>  ^>Z>.d>>b>&$>>rJ>r>>*  $V>F>&$>>> >Z2  6 ` >2D>>>` >  $>nV>r>>>> 2` T> 2` *D*` 6\N:<>:` p >>>>f>>>>>>>h >2$>>>>>>>>r   ,>vf.  ,>vf.  ,>vf.  ,>vf.  ,>vf.  ,>vf.  L>2 T>2 d>n >>>>>: .,>>>*  >R 6 >>>$>>>>br>^6 ><&  >>>r>>>>>>>>* >>>>>$>>>>br>^6 ><&  >*>>r>>>>>>>>* >>>>>"$>>>>br>^6 ><&  >*>>r>>>>>>>>* >>>>6 >Fr>>>>^> `N>>>n>h>h>h$>*h,>>h<>>>>&h>>L>F>>h>"dR>>>$ >h2>>>>>>h> ^>>RV>>>>>>>h2>>h>>h>&h>hh>J>>h>Z2>>>>>*h>>^>2>&>>>$>>,&h2>>*h8^>>>z>>>>>b>>F>>b>>>>^>>h>6h>j>>>N>>b>>>>h>>h x",>>>>>$>F>>&<&\N>bj>z>>r>>>>>R>Z>6\&>T 6\>| <>Z>>>">>>>>>>>">,>>>V>r>R>>\f^.f>>>>>J>>>>6D>Z2>>>& ,>(JP8v>$ ,>j: $R> <D>>>"I"K&>>>>>>>>>>>>L>>z>>*>*>>$",>4\:$> $>$>>$$"$.$>$fJ>>:>J>V>>Z>:J>>>N>2\>P$>6PT>Z>:J>R>>>"$>N>>d>$>6T>Z>:HJ>>:`>`>H8N>>\>$>6T>Z> J>>>N>&\>>J^>>$>h^hh$hLfN>6$>&D>L6T>>\>>vrf>>> $>r>&>"<>44.t>0,>@>&04>0<60D>>0L>0>d>,>~N>b>>> >>:$>>,>&>"4>&>>><~J>6>66>.\bJ> >6 6>:|bJ>0 >60 6>>>>.>JJ>f>P >6P 6>>>~J>6x >6x 6>">  > > >>Z>" .,>V>  >:>>>>R>J>>>n p >>2p >>>>p >$>.p 4Zz>V>b` .t&` . DF: >"$>bfv > >* >"$> >4>>&N>>T6 ` >v>.` ,>*` >.` >.` $>*` <>^>R>>` \>r>>b 6 >* ,>>` >` >>>>"D>>>>n X > X >X >2$X L>&. >F>>>>>>>>>>>4Z>>>f&,"$>^2 >$> ,"$>^2 >L>.$>^2 >>^*p >^*p >^>^>^.  4Z>>>f&,"$>^2 >$> ,"$>^2 >L>.$>^2 >>^*p >^*p >^>^>^.  4Z>>>f&,"$>^2 >$> ,"$>^2 >L>.$>^2 >>^*p >^*p >^>^>^.  4Z>>>f&,"$>^2 >$> ,"$>^2 >L>.$>^2 >>^*p >^*p >^>^>^.  4Z>>>f&,"$>^2 >$> ,"$>^2 >L>.$>^2 >>^*p >^*p >^>^>^.   >Z>^  >Z>^  >Z>^  >Z>^  >Z>^  >Z>^ >Z>^ >Z>^ X>^ X>^ X>^ X>^ X>^ X>^ X>^ X>^ p>>bp:,>>>>>>V>>v>b&&4&p.t>J>^>^&p >J>^>^>~>>: @> h>>V>>>N>^"p4>J>^"pT>Zpl>>J$>Zp&p>>R:@>>r>>F:@4>@D>J>>^V$>@Hj>j>>>">nn>>  $>V^V>j>>n>J 0> H$:0 L>^*x>&x $>^>>v>J>>,RRVb^rVZ>>>>>>>>>>>>>>>>ttttttttttt$>T>d>$>4>D>$>:$4>V>r >>> V>X>>VbVbz>Rrj^>f>F>>J>N>Z>8N~N^>.X &|Z>br>&.h>>>>>>>>>>~>6,>>>>>> >:$>x>:|>x>>h>6>*h*>>h>>j>>:0>0h&&hlbvtj>Rn>j>$V>^>& $>Z2.x>>J>>x>4^x>&L>F>6xlV>JZr>ZN>.\>>2d>z>~>~>>>(V>>>>0>$>024^r:$>p*,Zj>>0n>J>r>"$>2&L>f>^ l>.0>>>>>>>>>>>>>>>>R>0>>>.>>n>0>>> >>>>> 0>:>>>0>>>:j>>V>0>>&8n>>z>F>nR>>p>P.b>b>J>"P&00nr>Z>N>^>> 0>>xn>Zr>Z>>0>n>Zrr>^>>:0>>>J^>020>>:0`>>0@n>b>^>0>&h> 0>"xj>&0>~>>*02>>>>>nJ>f>v>>Z:>"<>>R^*$ <2(>J>>f.>&>J`>`$>,4>`d><D>` >>j>Nz>60@>>>~>^>608>>>j>j>^H*H $0D>.t> 4 <>"0pn>~>~>f>>0n>z>F>60n><><>>0>:0n>Zr>Z>20>Z*>6 $r4>X^>>^j> D>j*>"> $>" 4>V>>`>>>>`>Z*`>n>FJ:`>fv>J`:p.XV>>^J>rh>"$> h64>V2 : >>>Z>Z2 >>4fj>N>6 >"\f~>v>V>2 @V>"d>6>>T >v$,$>>>2d>>Z6> |>>>N>.>>>f>f>>>"T XH&t&H >&2>Z&>>^>>"4>r>>n>> > >>> 2,Zz~>>>V>>>>>`>>`>>>>>.`",>>>>Z~>6 .>>Vj>Z>>>Z>>J>>Jb>>  f>" >>"!b>>fVZvv>>F> jR^f>> l !t^>N>b!j>N:! Zj>>>>>v~N>* "&$& "!> d!.t! b>>" !:~6D>>"Z>>>>>^V"Ξ">4>J>>0#>>0#: #"DF^>`#`#> ##&#>>|.%Zn>&#F>#>"$>RJ>>#>f"#><LJ:H$ 8$ު$Z$$Fp$ $RV$~r>N^~>>n>%*$Z>"$> T&$ dzb>J#:@&>>>.% %J% %\6$&&%F%%,%">>>V>>Fn>>*p&>>$>>z>j>M"O>>>>>>>>>>>>>>>\>>>>>>>>>>>>|>>>>>>>>>>>>>>>>>>>>>>>>*>>>>>>>>.<>>>>>>> <>>>>>>D>>>>>>>>>>>>>>>>>>>>>>2\>>>>>>.4>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>v*$> 6,> 4<D>6lf><>>JRRRRRRRRRRR >>>NRRRRRRRRRRRN&&2">>>>>>>>>>>\>>>>>>>>>>>>|>>>>>>>>>>>>>>>>>>>>>>>><>>>><>>>4 >>>>>>>>>>>\>>>4>>>>>>>>>>>>>>>>>>>> >l < >>>MKQ"S >>>&TJ.4zN~*$&$&$>>V@>>@*@D&$>^>*>.<>^>*>.\>T>v>*>$>22,>>>>&4><>D6l>fxxxD>j.$.4.,<&d>>f  > $L~` ` `z$>Z2>"<>DZ>j>.X>Z2XR>2D>>X>>>^2>j>2LFnz" >"4>& :\>*4"$>Z>F6>>>>>4v>> H>>>$>>>H>>>>H>"L> H >2 R>:l> >>>>$&>>>>"T>N>>&>>>>N>>>>6>N>>>">>>&>N>>>> >>>>l>Nb>>>>>>>6D>>>>>>4>>>>>>>>>>>.>N>>>>>>>>>>>>>>>N>>F>>>>>>>>>&>>>>>>> >N>>>>>>>>>>> >N>>6>:0 >>2R>>>&H >p >2p >$>R>V>>>&p \>* >>$b>f>* >6T& >>6\^z>R>V>F>>>> >>>h >:$>J>V>>h >2D>J>V>>N>>>>:h .|&h  & & @ >( jb>>>R>( *$ ( &,>J>N>^` >2` >` $>>>>>>>>>>>>>>>>>>>>>>> >>>4R$L $ $> D $>> <><:l6D d L D> D $ < $ L\ $"$ \*>>h >2\>>> >>>>>>>>>>>>>>>>QK>U"W` >>>>:l>Z@@<>>&$^^j>>>J>n>>>>v:&,6\j>>>J>n>>>>v:0&,6d>>,>Z2>>>:D>Z&>>>D>N>>"D>>X6$j^R^>>>X|~66>>>>&$>>j>>n6>2<&d>N0>0&$>*0L>.x6$j^n^>n>>n>>x6(D `D 4jD>Zr>>N>D*,>Zhr>R>>>:hXN>2\"D>N>>>>>6$Z^>j>>b>j>>>2& >22D>N > >>"$>>>>> $>>.4&>l& >22pD>N >>>"$>>>>> $>>.4&>l& >228 <>Zp bZ> p ` N> L&>>6>>,< <$">*D6D2D>*|>"d6L>*:< < < < d*666>>>>>>>>>"UKY"[>>>>> ,>>n:.L:$>>>>>>>>>>>>>>>F pV pV pV pV pV pV pV p p p p p p p p p p p p p$p$p,p,p4p4p4p<p<p<p<pDplZ^ZNZ$^>br~>>8>,>>8T^>b>>">"<>Z>^>>v>> T>Z>^>>>>&L>>^`V`V`V``<:$$j2>>V2>>R6>>>2>>>>> >D>>>N2>>>>>N>(>>>*(>>>>>>>>>>4.>>4.>>4.>><>>>>>>>>>D.>>>>>>D.>>L>>>>b2`>>R>>&`>>`:>>>>>>l.>>l.>>>>>>l.>>l.>>l.>>t>>&>>>>>> |.>>>>>>>|:>>|V>:>>>>>>>>>>2.>>>&>>>>>>.>>>>>.>>>>>J>.>>>*>>>>>>&.>>>>>>>>.>>>>>J>>:>>>*>>>>>>>".>>>>>.>>>>>J>>:>>>*>>2(.>>0>X>>>>J2X>>>>>N>6h>>>*h>X>>>><~r.>>N>>X>>>>>.\> X>>d&X>>>>&t>X>>>|.X>>>>:>*X>> Z>>f>>2>>>*>>> >>>>Z2>>RZ>>>>>>>2>>$>>>J>> >>>* >>>>"L>>>>>^>>H>>>.H>>>>>N>>`>>>*`>H>>>>>*>>2>*>>N>&D>>>>N2>>RZ>>>>.(>>.(>>>.(6$&(>D>>l>>>>>Z>>>>>>> >>>><>>>>>>>>>b.>>Z2>>R>">>:>>2>>>>> 4.>><>d>>>>>>>>r.>>Z2>>R>>>>>2>> >D>>>>R X>>>>>>>2X>>2X>>>X>>2>V2>>R6>>>2>> >D>>>>>Z>>>>>2>>>>>> >D>>>N. >>R6 >>>>2 >>>* >>>6 >D>>>>Z2P >>R2P > P ><>>>>>j > ><>>>>>Z >>V2 >>R6 ><>>>N.0 >>R0 0 ><>>>>>>&h >>>>>>>2h >>>>>>>$>>h >>>>>>>>>*4>h >>>>><.h >><h <:h >><h >>&D>:h >>:lj. >>N F> >>R>. >64>>>N: >>R  ><>>>N.8 >>RZ> 8 >>>>>6$>68 >>>>>>>>,.8 >>>>>>>4>>*8 >>.D8 >l>>>>>>>b2 >>R6 > ><>>>>>>>^6 >>>>>2 >>>> > >D>>>>>>>f2 >>R6 >>*4>>>N.H >>RH H ><>>>r: >>N> 2 >>> > >>>>4* >>4> ><& >d>>>F& >>>>>: >> >>>: >> >>>>>>>>>$* >>$ $6 >>$V>6 >>>&T>>>F&0 >>>20 >>0 >>>>>.0 >>20 >>>>0 >>D>>>N2p >>Rp 2p >>p >>V2 >>Z2 >>>>>F. >>Z. >>>>>>>J: >$ >L>>>N2 >>Z2 >>R6 >>NZ>>>>>>>>>>>>8>>>>>>28>>Z>>>>>&8>,*8>>4>Z2h>6h8>(>>>>>J2>>>>>>>>>>>>>>>>.>>2>>>>:$>>.>>>>>>>>,> >>,*,:>>,V>:>>>>>>2D2>>>>T2>>>>>>>>6d>>>>>>&l.>>>>:t>>>>:|.>>>>:>&>> >>>>>>>f>X>>R>>X>>*X><>>>>>r2>>V.>>R>>">>:> 4*>>4.>>4> <>d>>>>>>>f2>>R6>>>>> >.<>>>N.(>>R( (>>V2`>>R6` `><>>>N.>>R >>V2>>R6 ><>>>N.>>R ><>>>>>>>>r.@>>Z2@>>R>@>>>>2@>>@ @>Dj.>>N>><>>>>^.>>R >Ln>>&$Z&>TFv>H>"$>.H>]"_>>>>>>>D>>b>NR $r T>,>4.$Z>>>>>$>:$>&$>t.$.$jnnnn~~nnnnn2,>R>^^Z>>>>Vb>>^^Z>>>>Vb>>Z>Z>Z>Z>Z>Z>>>N^>Z>^^>j>>nn.L>>r2>>"a"c(>>>>>>>> L>>j>>(>NRR(4r(d>,>4.$>:$>&$Z>>>>>d.$.$>nnnnnnnnnn24Z>^>>F>F>F>F^^Z>>>>Vb>>^^Z>>>>Vb>^^>j>>>V>V>F>>r2>DJ>n>n&$vzzzz>b>V>NnN>nv>r>n&>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>L>d ,Z^>>>>>>>>>.$$$*,Jfff$$$>N>F>F>F>F>F>F>F>F>F>F>Fnnnn>,~>F>F>F>F>D>D>4>b>f>F>>>>>>>>>>.Jn>F>>R4J>$>$>$>$>$>4~n>>>>R((Jnn>>R(>>>>>>>:a_>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>D>T ,Z^>>>>>>>>>$",$$,JNNNZ$ $J>F>F>F>F>F>V>F>F>F>F>F>F>Fnn>b~>F>F>D>D~>F>F>F>F>F>F>4>4~>F>F>Rnnnnnnn>>>>>>>>>>>>>>>R.>>>>>>>>][>>>>>>>>>>>>>>>>>>>>>>>>>>>>>,><$ l\>>"\>D:T6L <$ $>>>>>>>>>>>>>D>>>6P>>6>>*>l><>*d>D><>D>D>D><.<.<><><>*l>4><>*l><>D>4><>*d>T>D><>>L><>6>>6><>*d><><><><><><>D:<:<>>>>>>>>>>>>>>>>>>>>>>>>>>>"YK>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> \t>>>>>>L>>\$ $ $$ $ $ $ $*|&**>L6&L< t>> t>> >"X >>>>>< L2`*>"20>>>>>>>P>>>>: >>" l>%&&>>>>>>>>>>>>>>>>>>> IG>6e"g>>>>>>4>>R:&>D:$>>>>>>>>>>>>>>>~ xV xV xV xV xV xV xV xV xV xV xV x x x x x$x$x$x$x$x$x,x,x4x4x<x<x<xDxDxDxDxLxt$^>b>N~>>&>,>>"\j2h>>V2h>>R6h>>>2h>>h>>> h>>>>>b2>>R>>:>>>>>*>>>>>>>>>>>Z>">:>>>>&<>>>>D.>>L>>>J>">>>>>>>>l.>>t>>>J>6>>>>>>>>>*:>>V>6>>>>>.>>.>>>>">>>>>.>>>>>>.>>>>>>>>>>.>>>>>.>>>>&>>>>>>>>.>>.>>N>><>>>>>>>.>>>>>R2>>R>>>>>>>>>>>>n2>>N>>>>>>>>>>*n2>>N>>>>>>>>>>*@:>>>>2H.>>>>>>>>>>2H.>>P>>">>>>>>>X.>>`>>>>6>>>>>>>>>>>>>2>>$>>>J>>>>>>>>>>D*>>L>>>J>>>>>>>>>>>l*>>t26>>>>>>>>>V.@>>Z2@>>R>"@>>>>2@>>>>@>>:@>>2@>>>@>0> <.0>>D0>lj.>>V2>>R6>>>2>> >D>>>>>>>b.>>Z2>>R>>>>>2>> >Dj.>>>>~.>>Z2>>R>6>>>>>>>.>>2>>Z>^z>&0>:<>d>>>>>b2x>>R6x>>>2x>>x x>Dj.>>V2>>R6 ><>>>N.>>R ><>>>>>>>>>b.8>>Z>8>>R>>8>>8>>>68>(>6T>>>N:x>>Rxx>Ln>>&$Z&>TFv> >"$>.>LZr>^*i"k .,^^bnj>&$Zb>> ,>>R   $,.4.<*D*L*T*\.>>>>>V H H H$H,H4H<HDHLHTH\HdHlHtH|HHHHHHHHHHHHHHHHHHHPHX.HZ>4^b*^.$ ,b> $r:^b*8^^>Vf>Jx>>>>2x$>&x4>&xD2xTb>xlb>:xb> x6,>&xbf6xbf6xbf>xbb>x>R> x^ff>xx> x(x8> xHxXbf*xx>"x>"x.x>x>x>J> xb>:x.x&8Z 0$>^*>>>>>>>>>>>>>>>>>>>: 4\> L x>>,>\6<>>" >>>>>2ig"m"o>Jn>>N*>2> $>n20>> 0"tpRh&>":"$>>>>>>$H>>>F>>>>:d6>6T>>>>N>&> $>D>^>.\>^>n>D>>>>>>>>>>>>>F> ,j> Dj>" \j~>>b>>b222$.4> >> >* j>> >r">>> 0 X @"@* h x >>>>N>>>>>>>> j6 j6 >N>> >>>F>>>> >>>F>>>> 0 @ ` P"P* pj6 RVV>"|>^" >>  H>^& &`> Z>>f&> V>>>>>> H>>>64>>>> ^VVV>>>>20Z>0Z>0Z>TZ>lZ>Z>0Z>0Z>Z>*Z>>Zn>>Z>>> Z>>>"Z &>>@Z>>>""XZ>>>22pZ>>>>>>>&2Zr>>>*Z>V>>2Zr>>>*Z>>>>&Z>>>>&(Z>>>"@Z>2XZ>2pZ>R>>>>>>>6f>~j>N>>>v>2$*>q"s >>>>>>>><>"\>>^^JN^Z>r>RRR>>r2(RVVl*|RJj>bn24fVv>XN6X<>Vv>N6v& n&  ^, 4&T>xZ~>d>>>:,>>Nj*>>*&6>>N>trf& >>>>>>>>>>>>>><>$ :$ t < < 4<< < | D> t>>>>>>qo>>>>>>>>>>>>>>>>>>>>>>>>: >>&D> >>>mg>>>>>>>>>>>>>>>>>>>>>> >>>4>D $ t $>>>>:d>D>>*>6>*l>D>D>d>D><><> T:<*>>>>>>>>eG>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>,L 4 4 $ $ $ $ > T< $ <> L T>>L>>>>>> >>>D>*.L>6` >> >6>>>>>>:> >>>>>>>>>>>>>>>2E2u"wX8>>R88>>8D>>Rxf xx<>J>>V2T64Z>44$.$>>>>>z~~~~4 D < D4 4z:4 ,$$ $>>>>>>>u"y"{8>>>>>z~~~~~~> ,>$$&$$>*$>>:$>*$$:$:$Zf>V>R^>~>L>R>N>@^r^*8,>:,V^*>>>>> >>>>>D4 l $ $ $ $$ $$ $ $ $>T>>>>>>>y"}" >>>>>&\ZN^Z^Zf>Nv>4*$*,z2> >&4T>>>>>>>4$ $ $ T>>"}"">>>>>>4*,Z>V^ &4"HRb^>RrrxJfrr>>>>b>&$~rr2L~rr>>>J2&>"~^Z^2>>>>>>>>> >>>4>L>6>>>>>>>>>>>>>>>>>>>>>>>>>>2 D L \ d \>JN>v>FVRjV^T>n>R>f>f>R>>>>p>\>J>f>$>j*D"L>b^8Zf>^:p>>>>>2p>2p>2p>2p>2p>2p66p>>>newrethrowloaderloadprimsmakessetsgetsblitssubsfind@make@empty@consstringasizearrayamakeablitthrowasub@compare@print_unionnargsobjfieldsfieldobjgetinvalid_argintfloatprintgetposcacheNoneSomeNeko_errorInvalid_argumentAssert_failureErrorStream_errorNot_foundExit@print_record@aget@aset@pconsstream_tokenstream_posstream_junkstreamsprintfsndprintfordnstringnprintnekominmaxmagicignorefsterrorcomparechrassertsubsortsetmapmakelistlengthiteriiterinitindexcreateblitappendadd@rmaketlsplitrev_recrevphysnthnonememiter2hdfoldfindfilterexistsconcatchopassocallresetadd_subadd_charssizeuppercaseunserializeunescapeserializelowercaselist_depencyis_printableescape_charescapeOverflowEofClosedBlockedwrite_ui24write_ui16write_stringwrite_i8write_i32write_i16write_filewrite_charwrite_bytewritestdoutstdinstderrread_ui24read_ui16read_stringread_lineread_i32read_i16read_fileread_charread_byteread_bufread_allreadoutputinputflushfile_write_charfile_writefile_stdoutfile_stdinfile_stderrfile_read_charfile_readfile_outputfile_openfile_inputfile_flushfile_contentsfile_closecreate_outcreate_inclose_outclose_inhkeyhnewhcounthgethmemhaddhremovehsethiterreplaceremovehashEmptyMatchStarPlusNextChoiceInvalidRegexptransitionsstarsingleplusparseoptnodesnodenextmax_codemake_transmake_tablesis_emptyinvalidgroupescapeddeterminizecunioncintercemptycdiffccomplementcalladd_nodesadd_nodeInvalid_ruletokensourcepunionnull_poslineinc_lineemptydatacurrentcurposcharbuildTrueFalseNullThisIntFloatStringBuiltinIdentVarWhileDoIfElseFunctionReturnBreakContinueDefaultTryCatchSwitchSemicolonDotCommaArrowBraceOpenBraceCloseParentOpenParentCloseBracketOpenBracketCloseConstKeywordBinopCommentCommentLineNormalWhileDoWhileEConstEBlockEParenthesisEFieldECallEArrayEVarsEWhileEIfETryEFunctionEBinopEReturnEBreakEContinueENextEObjectELabelESwitchvar_argss_tokens_keywords_constantmk_stringmk_intmk_identmk_call1mk_call0mk_callmk_builtinmk_binopto_stringprint_listprint_astnewlinelevel_exprlevelMutableImmutableTAbstractTMonoTPolyTRecordTUnionTTupleTLinkTFunTNamedTVoidTIntTBoolTFloatTStringTCharTIdentTConstrTModuleMRootMFailureMHandleMExecuteMConstantsMFieldMTupleMTokenMRecordFieldMJunkMSwitchMBindMWhenMNextTConstTBlockTParenthesisTCallTFieldTArrayTVarTIfTFunctionTBinopTTupleDeclTTypeDeclTMutTRecordDeclTListDeclTUnopTMatchTTryTTupleGetTErrorDeclTWhiletlinkst_voidt_stringt_polymorpht_polyt_monot_intt_floatt_errort_chart_boolt_abstracts_types_mutables_funs_contextpolymorphizepoly_idmk_unionmk_tupmk_recordmk_funmkis_intgenidgeneratorfile_nameetypeduplicateabstractidivNoderemove_min_bindingmin_bindingmergeheightbalAccNullAccTrueAccFalseAccThisAccIntAccStackAccGlobalAccEnvAccFieldAccArrayAccIndexAccBuiltinSetStackSetGlobalSetEnvSetFieldSetArraySetIndexSetThisPushPopCallObjCallJumpJumpIfJumpIfNotTrapEndTrapRetMakeEnvMakeArrayBoolIsNullIsNotNullAddSubMultDivModShlShrUShrOrAndXorEqNeqGtGteLtLteNotTypeOfCompareHashNewJumpTableApplyAccStack0AccStack1AccIndex0AccIndex1PhysCompareTailCallLoopGlobalVarGlobalFunctionGlobalStringGlobalFloatGlobalDebugGlobalVersionInvalid_filewrite_debug_infostrap_stack_deltaread_debug_infosop_paraminullhash_fielddumpcode_tablesXEnvXStackXGlobalXFieldXIndexXArrayXThiswrite_optrapstack_deltaset_posscan_labelssave_breaksprocess_continuesprocess_breaksmake_arrayjmpgotoglobalget_cases_intserror_msgcompile_functioncompile_constantcompile_builtincompile_binopcompile_access_setcompile_access_getcompile_accesscompilecjmpcheck_stackcheck_breakspathVNullVIntVFloatVBoolVStringVObjectVAbstractVFunctionVArrayvalueneko_valuemodule_set_globalmodule_read_pathmodule_readmodule_namemodule_loadermodule_globals_countmodule_get_globalmodule_exportsmodule_executemodule_code_sizeloader_pathasetaget__list_depapplyCharConstrModuleTypeThenWhenExceptionQuoteVerticalStreamOpenStreamCloseETypeEPolyETupleEArrowEAbstractEAliasERecordEUnionATypedANamedATupleSPatternSExprSMagicExprPIdentPConstPTuplePRecordPConstrPAliasPTypedPStreamEVarEUnopETypeAnnotETupleDeclETypeDeclEErrorDeclERecordDeclEMatchETupleGetEApplys_pathTotalPartialDubioustotalt_conststream_patternstart_by_a_variablesplit_matchingpartialmswitchmake_token_matchmake_record_matchmake_construct_matchmake_constant_matchlines_of_matchingjunkhave_whenhandlefully_matched_reffully_matchedflattenfailureexecewhenerror_refdivide_matchingconquer_matchingconquer_divided_matchingcondbindalways_addadd_to_matchadd_to_divisionunionremove_min_eltmin_eltjoininterdiffadd_loopInvalid_characterUnterminated_stringUnclosed_commentUnclosed_nxmlInvalid_escaped_characterInvalid_escapestrnxmlmk_floatkeywordsidentexprestringenxmlecommentcommentbinopspacesnumbersnumbermodidentUnexpectedUnclosedwhen_clausevarsunion_declarationunclosedtype_path_nexttype_path_modtype_path_list_nexttype_path_listtype_pathtype_opttype_declarationtype_decl_plist_nexttype_decl_plisttype_decl_parametersstream_nextstream_liststream_ident_listrecord_fieldsrecord_declarationprogramprioritypatterns_beginpatternspattern_tuple_nextpattern_tuplepattern_recordpattern_optpattern_nextpattern_mod_pathpattern_list_nextpattern_listpattern_declpatternparameters_nextparameters_decl_nextparameters_declparametersmake_unopmake_list_patmake_listmake_binopis_unopident_optfunction_recexpr_shortexpr_nextexpr_constr2expr_constrcan_swapblock1blockCannot_unifyHave_no_fieldStackUnknown_fieldModule_not_loadedCustomNIntNFloatNStringNNanverboseunify_stackunifytype_unoptype_typetype_patterntype_matchtype_functionstype_formattype_exprtype_constanttype_blocktype_binoptype_argsave_localss_ttyperestore_localsregister_functionpropagateopen_filemodule_infosmoduleload_module_refload_modulelinkis_tupleis_recursiveis_aliasget_typeget_recordget_moduleget_identget_constrerror_msg_loopcontextaddableadd_localparse_switchparse_stringparse_opparse_listparse_from_stringparse_fieldparse_expr_optparse_exprparse_constantheaderdocstackcdatapcdataxmldonePCDataCDataDocumentnode_textnode_nameis_pcdatais_nodeis_cdatafirstNodeattrib__listto_xml_recto_xmlparse_xmlparse_posInvalid_nxmlvariables_nextvariablesswitch_casesparameter_namesobject_fieldsNativeStructuralrecord_indexno_labelis_funimportgenerategen_variablegen_type_printergen_typegen_matchinggen_match_recgen_matchgen_labelgen_functionsgen_exprgen_constructorgen_constantgen_callgen_blockgen_binopenullcoreconstruct_idcomparisonbuiltinarityargsversionwithout_extensionwithout_dirset_cwdread_directoryput_envis_directoryget_envget_cwdextensionexitexecutable_patharray_dependencyNOSYNCFULLFINISHBLOCKuncompressoutput_set_flush_modeoutput_endoutput_bufferoutput_boundinput_set_flush_modeinput_endinput_buffercompress__resultacopycallstackexcstackCFunctionPosexcVoidInvalidparse_argshelpFileNotFoundreportgen_nekocompletecapitalizeL/`S6_L5LL!fLL%LXVL\fLL%LXVL/f Ll^L`L4VL!f7LLVL.V7LnL-LZV^!7LoL)LOLLLczLZVL+rLGLLL)QL)LqLPVLgf rLL:VLLLLL3VLLLDVLL/LL-LAVL6aRrLGLLL)QL)LtLPVLgf uLL:V!LLLLLL3VL8VLLLDVLL)L2VL6YRrL!LXVLLabLzf^?L!L-L5LQVLL!L-LaLaLaLALaL9L[V襥xLLM9LL_ $zgfLL5L-L:V9L)L)L^+rj LLl^(LLf LBaLzLC^L/*LLIL?L>L9LLLJ*R9L@L)L=L9L%zgL9L9LL\9L9L@LLEL%zLKV=LNLLL!b L%b#^pgfLL9L0VLL:2^RQL)ULjL L=l^3LLf LBaL_ $fL)LV^ ^L/*A^r9L@L)L9L%z9f)L)L)L=3^)L)L)L3rgf uLL:VLhLlL-VL9LLkVLL%fQL*fUL^^^^^L襥L=LL`LFVL=!R9L}L-L0VL)LLL^+riL/`S7_LL9LLt! zLLLLLLL)LL/HoL#g%Zrrj9LLLL=Vl^$LLf LaL^L/*)r9L=j 9L=l^$LLf LaL^L/*L9LvLL=LvL)LLvzLf^L9VLL=!r9L=f LL=L9LVL-L-LL9LLV9L9L)r9L=f LL9LVL9L9L%!LLLLLLvLL-L-LLvzR9L=9L=L9LL=LvL)LLvL-LzLf^L9VLL=!r9L-L-L-LVr9LLLLLLL-LzLLLRLLzrLLL)LL)L!bL!b)Lb )L)Lf L-L-L-LCrL!f LL!f^YLL!L)LL!f<)L)L)LVLL!f L)L-L)L)L)_)RrL!f LL!f^LL!L)LjXL!fJLLL VLL!fL!f^LLL)LL)_l^FLLf LaLf$)L!f L-L!LLV^ ^L/*9RrLLLj"fLLL9VLV_Ll^/LLf LaLf )L^ ^L/*)RLLj5f%LLL f LLLV_LLVl^.LLf LaLUDf L^ ^L/*!L9LL9L)L9L-L9L-L-LL)LLLRL9LL9LLLRL9LL9L)L9L)L)LLLRL9LL9LLLLLL!f L^RLL!rLLQLLLF)LL-LzrL)rLLL)rLbLf LLLL9"r)LL)L!bL!b)Lb )L)Lf L-L-L-LCr!LLLL!f<)L)L)LVLL!f L)L-L)L)L)_RrLL9VLLL9VLLL9VLLL9"rL!bLf LLL9VLLL9"rLbLf LL!fLL)L9"^ LL9"rL!bLf  LLL9VLLL9VLLL9"rLULLL!rLLQL FLLLF)L)L)LVL9*r6L/`S7F_ L/jL!LLfLLL/%[VL%a_RrLL/ RVLLf &L r)L)L)L/%[Vf (L !rjLLLLL/(-Vl^Lf *L 1r)L)L)L/2[VLLf ,L r)L)L)L/,VLLf !LrLL#VLLL#.Z!rrLLL!b L%b^P^MUL!fQL9LLVR^4^^QL)UL9L)LV9L=LVL1^LLLL)LL-L0va)LL)RrL fL~LLL b$L b%L b&L\b'L"b(^.^*3^X^"4^P^5^H^6^@^ 7^8^LL9f8LL"LV^^^L%LL=*L9L=f L^9LLVLLL b$L b-L b6L\b?L"bH^V^RL3LV^^BL4LV^q^2L5LV^a^"L6LV^Q^L7LV^A^LLfL8L)L"LVLV^^^LLLVL%LLLLL-L9LL=LLL:va!L!RL9LL=L!L!LLg< L)L/ RVLL\g)L-L%)Lf <L L-L/ RVLLu^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_]____Q____E^v^t^r^p^n^l^j^h^f^d^b^`^^^\^Z^X^V^T^R^P^N^L^J^H^F^D^B^@^>^<^:^8^6^4_^0^.^,^*^(^&^$^"^ ^^^^^^^^_^ ^ ^_^___LL"L/%[V__LLf <L LL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f <L 0L"LL"LLdL-L"L)L L)L"L)LLf <L LL)LL/%[VR_ _LLf <L LL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f <L 0L"LL"LLdL-L"L)L L)L"L)LLf <L LL)LL/%[VR_K_BLLf <L LL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f <L 0L"LL"LLdL-L"L)L L)L"L)LLf <L LL)LL/%[VR__LLf <L LL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f <L 0L"LL"LLdL-L"L)L L)L"L)LLf <L LL)LL/%[VR__LLf <L LL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f <L 0L"LL"LLdL-L"L)L L)L"L)LLf <L LL)LL/%[VR__LLf <L LL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f <L 0L"LL"LLdL-L"L)L L)L"L)LLf <L LL)LL/%[VR_O_FLLf <L LL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f <L 0L"LL"LLdL-L"L)L L)L"L)LLf <L LL)LL/%[VR__LLf <L LL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f <L 0L"LL"LLdL-L"L)L L)L"L)LLf <L LL)LL/%[VR__LLf <L LL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f <L 0L"LL"LLdL-L"L)L L)L"L)LLf <L LL)LL/%[VR__ LLf <L LL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f <L 0L"LL"LLdL-L"L)L L)L"L)LLf <L LL)LL/%[VR^S^JLL\L/%[V^A^8LL L/%[V^/^&LL L/%[V^^LL L/%[V^ ^<L ^^^LL-L)L/%[VLL%L)L%_)L!L)LCRL9LL!L)L=VL!LaL"LAL"LLfHL)L/ RVLLAfLZf-L-L)L"LLL/%[V)L-L%_)RL9LL!L)L=VL!LAL"LaL"LLfHL)L/ RVLLafLzf-L-L)L"LLL/%[V)L-L%_)RL@L/HoLBF7L/`S7|_fJ#MRLLVLJL#1iZfrL)L)LJL#1iZLX"rrLJ#MRLXLLL!b L%b ^!^UL%LL9𭈥^LLL!b L%b^\LT^ QL^LLL!b L%b^^LT!^ UL^LLL!b L%b ^0R^,QL)ULKL)LLL-L9VL%z^rLLL!b L%b^$^!QL)ULLLL9B^rLLL!b L%b"^y)LL!f^ ^^bLT9^\QL)ULLLL!b L%b^2bLTQ^)QL)ULL)L VLL)L9s^^rLLL!b L%b^PRLR^GQL)QL-ULL9LLLKLL)L%zLKLLL%zR^LLL!b L%b^)^&QL)ULLf^ LL9B^rLLL!b L%b^0^-QL)ULLLOVL!f^ LL9B^rLLL!b L%b^@ULQ^7QL)QL-ULL-LOVL!f^ LL9^rLLL!b L%b^<ULQ^3QL)QL-ULL-L!f^ LL9^rLLL!b L%b^/ULQ^&QL)ULLf^ LL9^rLLL!b L%b ^*)^&QL)ULLKL-LL%zL9B^rLRL9LLL!b L%b ^+-^'QL)ULLL-LL)L9^rLLL!b L%b ^+)^'QL)ULKL)L)LL9VL%z^rLLL!b L%b ^')^#QL)ULLL-L9VL=B^rLL9L)LnvaLRL)"L!f^;LLL!b L%b^!pLT)^ULL%LL9:^rLLL!b L%b^)^&QL)ULLfLL9B^^rLLL!b L%b^)^&QL)ULLf^ LL9B^rLLL!b L%b^3tLT^*QL)ULL!f^LL%L9^rLLLuaL!f vLT)L)L)rLLL!b L%b ^?R^;QL)ULLfKL)LL-L9VL%z^ LL9B^rLLL!b L%b^/^,QL)UL9LL-LMVL%LL=B^rLLL!b L%b ^OLP!^GQL)UL%LL9L)LLVLLL)L)Lyva%L-L)VR^L9L)LLSVLN!r|7GL/`S7_LL)QL!LL)f.-L-L)$L~L#(02L%aL)f -L2_-L2-R9LL/1&L)zQ9L!L/m%zL)QLL/1&Lf,LL%L/~4"eL!LL!LL/}V-L)L)L@-LL%FRrLL"r)L)L)L3rL/~4"L!LLfL)L@L%a_9LL-zRrL/~4"L!LLfL)L)L@L%a_9LL-zRrQL!L)2L)f)L$LL%a_RrQL!L)2L)fL-L)$LVL%a_RrQL!LL/~4"L-2L-fLLL$L@L%e_9L-L)zRrLQL-L+rQL~#MRL)2L!fL%e)L)$LL~L#1iZa_RQL!L-2L)f)LL)$L9VL%a_Rr)QL)L)Lf L/&]9L)LLLL/[uVzrLLLLL/}UrQL)2!LL)f$-L$L-L~L#eZL!frL%a_RLr7}L/`S7_LLL!b L%b^ L-LL#KZ^L-LL#KZ^9LL%zLLL#KZ9LL9e*zLLL#KZ9LL% zLLL#KZ9L)L)LvzrrLLL#KZ9LL5/zLLL#KZLLL#KZLLL#KZLflLLf L/\L%f LrL)L/1&L!LL)f+)LL)$L2L%aL)f )L2_)L2)rRL/(0 L/mLL!L)L/1&L%LLfL-L)$LL/LLf )L%2^!LLL L-L/AVLL2-L%2R_)L2)RL/1&LLf)rL-L2L)f+-L-L)$L2L%aL)f -L2_-L2-rRr)L)L!f!r)Lf)L/1&L)L/1&LLfLr)Lf!LfLf LrQa_!LLf4L$LL)$LLLzLVLL!frL%e_!rR)LfLf!LfL-f -L-rQa_-L/mL!LL/1&LLfHL-L-$L/AVLLL$L/AVLLLL zLVLL!fr -L%2R_!rR)L)rrLLL+rL!b L)Qf LL#eK3L7L?O17LL7L?7.LL7L?%LL7L?x+LL7L?;WLL657L?LLw 7L?LLUD7L?>#-LL/HoL#g%Z77L?pL?K7L?eL?SL?!nL!777L?!|L?1iL?MRLLLLLL)LLLLLLLLLLLLLLLLLLLLLLLvLLLLLLLL?&]L ?(0L-?>9L?!L)?'}L?-L?L(L?iWL?a1L ?-XL ?TL ?/iL?L?yL?SL? SL?-qL?eK<L? PL?L?ML?ŖL?)L?iL ?-zKL?FR 7~~#!n7~#&]7~#S7~#7LL7LL/HoL#g%Z7L?.Z!LLLLLLLLLLLLLLLLLL LLLLL-?WL?(0L?^'XL ?WL? SL ?9VL?^L?L?Q L?ſL?;L?>L ?NL ?fL)?58L?L ?!IR7H7JJ#!|7KH#9V7LJ#!n7MH#^7NJ#e7OH#f7PJ#&]7QJ#MR7RH#^'X7SJ#eK<7TJ#7UW7VY7X|LZ? s|LV?.Z!LLL[a]L_LLLLLLLLLLLLL`2 LLa2LLc2LLd2LLe2LLf2-LLg-2)L-Lh)2L)LieLLjaLkLLLLLLLLLl2LLm2-LLo-2)L-Lq)2L)LreLLsawLLLLxaLzLL{L|L?xe|L?n|L?^'X|L ?4|L ?cV|L ?9W|L?bS|L? |L?S|L? S|L?|L? |L?ſ|L?Z|L?\|L ?9л|L-?5|L??|L? |L?k|L ?r9&|L)?m%|L?|L?!IR||7L/`S7 ^LL"rL 77L!L/HoL#g%Z7LL/HoL#g%Z7LL/HoL#g%Z7LL/HoL#g%Z7L%L/HoL#g%Z7L%L/HoL#g%Z7L L LLLL L-?(0 L?I L?f L)?" L?0 L?!IR  77#ſ7#(07#L(7#07#&]7#!I7#f7#-zK7#eK<7 #7!#T7"$LL/HoL#g%Z7#%L/jL/VhL'L)L+L-L.LL/L1L2LL L9vLLL-L;vL L LL=vL LL>vL LL?vLAL%L/HoL#g%Z7@CLL/HoL#g%Z7BDLELFL-?>FL?gFL?r!FL ?WFL?nFL ?WFL)?]FL?9VFL?1FL ?,(FL?FL?r FL?NFL ?9лFL?FL?CFL?fFL? FL ?58RFF6 66#K6#586#06#f6#W6#F6#T6#>#-6#"6#7.6#(06#L(6#&]6#6#N6#!I6#f6#-q6#-zK6#S6#eK<6LL6L?bLL6L?4LL^!6L?LLlq 6L?̢O6LLVLL%LVLL%LVLLLVLL%LVLLLVLLLVLL%LVLLLLvLLLvLLLLLLvL LLvLLL!LVLL!LVLL!LVL)LL)LL)LLLLLLLLLLLLLLLLLLLLLLLLLLL-LLLLL LL L LLLLL?uKL?tKL?qL?O$L?L?L ?uaL ?veL ?L?lYL?˿L?H L?&L?p>L?p>L"?ڥAL?~8L?9L ?9L#?Edž4L?W2L?1L?4L?x3L?VKL?a1L? L? >L-?bL&?L'?0L?n T<L?+L?EqL<L(?L)?9L!?YL,?OL$?L%?}r*L+?}~&L*?u2:L ?zL?L)?G9L ?LLR2mL/`S7L_O !LL)zL LVLFL)L)f%^L9rQfLLL LVLVLFLLLL!b L%b^X^UUL!fQLLR^?^^QL)ULL#LLL9VLLL-L=d^r#LL-L9"rL9=Qf=L'LV=LLL#LL9L=VLLL!b L%b^^QL9LLVL9^RLLL!b L%b^>LL*^UL!f3QL)QL?L)L9L=VL9LR^Q^^QL)QL-UL?L-L9L=VL9LLV9LL9^LLL9=LCLV=LLVL9=LL*RLLLL9LL^)^B^^__6_b__ ___$____'_P___wQL#LLLL=R_\QLL&LVLLV)LLLL(vLLVLL%LLVLI_ QLQf"LLVL-L)LV_^^QLL*LVL-L+LR_QLULL,LLL=Z_QLULLLLVL-LL-LVLLZ_`QLULLLLVLLLZ_2QLL.LVLLL=LLL/vL-LVL'LVLI_*LL!b L%b0^iQL)ULL0LVLLLLk^>QL)ULL1LVLLLVL0LVLLY^_pQLUL)*LL2LV)LL)L)LLVL!LVLLL!b L%b^#^ QL L3LV LLL^_QLUL)*LL4LVL-LLV5L)L L=VLLLk_QLULL6LVL-L#L L=LLVLLVLLLc_fQLUL)*LQLffLLV^ L&LVLLL9V7LL L=VLL-L9VffLLj^ LLj_QLL!b L%b^(L8LR^QQLL9LVLQ^_QLL!b L%b^(L:LR^QQLL;LVLQ^_gL<LJ_[QLULLL'LVLLQ_0QL!fL=LV_^^QLL&LVLLVLLL=LLLLL@vaLLLVLLZ^QLALLL=R^QLUL)*LLBLV)LL&LVLLLLLDvL)LVLLL!b L%b^/^,QL LELV LLVL LLV^LLVLY^RrL)LLLL%bLb/^{^wQf LGL9VLLLL=V^^PQLQf LGL9VL&L9VLLVLL)L=VLLVLL9VR^9^LLVLLLL=V-f L'L9VLLBRr9LL)L=V9Qf9L'LV9LLLL%f%QL-L9L=LLIvLLV^^^)LL-L93rLLLLL9LLL=V)LL)1RL7 7 |7F7L/`S7_8 L ^^^)^3^=^G^Q^[^e^n[L)LT"^b\L)LT"^V]L)LT"^J^L)LT"^>_L)LT"^2`L)LT"^&L)LT"^aL)LT"^bL)LT"^9LLz9LLz9LLz9LLz9LLzL ^^'^1^;^E^O^Y^c^m^w^^^^rL)LT"^sL)LT"^tL)LT"^zuL)LT"^nvL)LT"^bwL)LT"^VxL)LT"^JyL)LT"^>zL)LT"^2{L)LT"^&|L)LT"^}L)LT"^~L)LT"^L^#^-^7^A^K^U^_^i^s^}^^^^^^^L)LT"^L)LT"^L)LT"^L)LT"^L)LT"^L)LT"^zL)LT"^nL)LT"^bL)LT"^VL)LT"^JL)LT"^>L)LT"^2L)LT"^&L)LT"^L)LT"^L)LT"^9LL z9LL z9LL z9LLz9LLzLLL!b L%b^L-LT*^L-LT*^L^)^3^=^G^Q^[^e^o^y^^^^^^^^^^^L)LT"^L)LT"^L)LT"^L)LT"^L)LT"^L)LT"^L)LT"^L)LT"^L)LT"^zL)LT"^nL)LT"^bL)LT"^VL)LT"^JL)LT"^>L)LT"^2L)LT"^&L)LT"^L)LT"^L)LT"^9LL!z9LL%z9LLz9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9LLz9L-L-L-Lzrr9L-L-L-Lzrr9L-L-L-L zrr9L)L)L zrr9L-L-L-L zrr9LL z9LL z9L)L)Lzrr9LLz9LLz9L-L-L-LzrrLL-L-LVrL)LXLVrL-LRLLXL%zLVrL)LpLrL)LnLrL)LhLrL)LlLrLLLLVrLLLLL!b L%b ^V^QLL9LS^LRLLL9LRLLL9LL9RLLLL^)^+^?^P^i^^^^_F_p_____!_?_X_Z_)_QLLLZVL_QLLL_QLULLLLV_sQLULLLL)LZVLV_OQLULLLLLV_/QLLLLZVL_QLUL)*L)LL)LL)LV_QLUL)*L)LL)LL)LLL!b L%b ^V^QLL LS^LV_QLUL)*L)LL)L)L LV_`QLULLLLV_EQLUL)*L)L)LL)L LV_QLL%b L!b^ QQLLLSL^-^^QLL%b L!b^ QQLLLSL^-^^)^QLULLLLLV^QLLLLZVL^j)^fQLUL)*L)LLLL-LZVL)LLL!b L%b ^V^QLL LS^LV^RrLLLL!b L%b^^QLL91^LL9LLL9L9!RLLL^)^*^9^E^W^r^^^___%_=_h_______QLLLUB_QLL9_QLULLA_QLULLLLUJ_QLULLLA_QLLLLUB_QLULLLA_wQLUL)*L)LLLLL!b L%b^^QLL a^_*QL*LLLA_ULL9_UL*LLLA^QLL%b L!b^QQLLA^^^QLL%b L!b^QQLLA^^^^QLULLLA^qQLLLLUB^[^XQLUL)*L)LLL)LUVLLL!b L%b^^QLL a^^RrL ^^^^^^)^0^D^O^U^Q^M^I^EQLLY!^7QL^.QLLLWL^QLL숥^ QL^L ^^^!^#^%^'^)^+^-^/^1^3^5^6^2 ^. ^* ^&3^" ^ ^^<^^4^ ^^L^#^%^'^)^+^-^/^1^3^5^7^9^E^Q^X^g^q^m'^i}^e-^a^]&^Y^U^Q^M^I^EQLL9!^7QLL=!^)QL^ QLLL^QLL숥^7M|7NL/`S7U_;LL#9LLr9zL)QL)QL8VL-UL-UL-VLzrLLL&L)L!LL!LLL1L?L!L!LL z LrL!FL!FLUFLUFL-FLF L)F LF r*L* L)L3L)* L-*z*L!f*LUfVULL&LL)UL-QL!LUL$VL)*L-UFL)*L-UFLFL)ULF*L*LQL!L-QL*LL$VLFL!F*L)QL)LULL%VL)L-*L)F)L-*L)FRQL*L4VLL)*L%FL)*L%FL f LF ^L b* fLF L)*L%F rj8L9LL*L%FL*L%FLL=VL!l^*LLf L/aLf'^ ^L/*9L$L=L$LL)L,VLLL)LfLLLf .L5-L%L)L2Rr9L9LLf6=L)f&=L=*LL%F=L=*LL%F^=L=*L-F=L=*F=L=QL=*LL)V=L=*L-F=L=*F=L=* L-F !LL-f"=L=L)L4VLVLL%_RL+LL2LL!LL!LLLLL9LLLLLLvaLLL=LMvLj!L!LVNLL*Vl^nLLf L/aLLb LUDb6^?LfLL%LLL,VL-^^L-^ ^L/*LLf LQ^LL)L,VRrLj L6l^(LLf L/aL=L5^L/*!PL)L:VL2L-L:VL"LL-L-L"L0L(zRrRL9SL7LL9"U77|7F7L/`S7_L^^^#^-^7^A^JL)L^"^>L)L^"^2L)L^"^&L)L^"^L)L^"^L)L^"^9LL%z9LLz9LLz9L)L)Lzrr9L)L)LzrrLLlVL!L)LL!f^^^L!f)^^^L%fL%fQLLL-ULQLQLULL-fWL%L-fyLLL L9VL%z^1L)f-LyL-LL-L%zL9V^ LL9V^ LL9VR^"^^^^LGLc*rLLL!b L%b%^]-L9fyL9LLL%z^^=QL)QL-ULyL-L%LL-L%L-L=VL%z^rLL9L)LvaLL%f/QLf!QLULL%LLVR^^^^^LLL2L9LL9L=VL9rL9LL=VL9rLLL-zL9L!LL)LpVf^yLL-L%zLQL9"r9L)L)Ls+r9L9L%9L^^^7^n^^__QL9L=LLyLLLL%z襥^QL9L=LLLVLLyL)LyLLL%zL%zFR^QL9L=LLLVLLyL)LyLLL%zL%zFR^iQLULLLLVL:^IQLUL9L=LLyLLLVLyLLLVLL%zL%zF襥^r9L=LL)L)LV!LLLLL)L9L-LvaL9L)LvLL`2RLL%fUL%fxQLQL)ULQLQL)ULL)L!f$yLLLL9VL)L%zL=^yLLLL=L%zR^^^^^LL-LLLRrLLyL9L-L%zLL=LVRLLLL9L=VRLLL9RLL-LLyLyLLL%zLL-L9VLLL=LvLLVLL9LvLLVLVL%zLLLLfVL)LLVRrLLL)L9VLRLL-LLL-LiBRrLL9L)LvaL)LVLzLLL|VL)LLL=LLL9LvaLLL-LsVLLLLLLVLL\LLLdV}LL`VLgL)L`VR j9LLaVl^[LLf L{aLw f9=L=L=L%9L-L)LuVLyLLL%z^ ^L/*LL9Le"LLVLj9LLaVl^LLf L{aLw fx=L=L=L%9L-L)LuV-LLLLLLL)L`VLLLL`VLLyL-L-LzLLL%zR^ ^L/*!L9L9L)L=VL9LxLL9LyL-L=LzL9L%zR9L)LvLL_"rL)LL)Li2RrLLL)LjVLL|"L9LLLLL!L!LLLL-L-LvLLLLL=LLL LLvaLLLvLLmVL)LtLLLqVLLLLhLVL\LL-R QLL)LLL-f#9LL=LLvVLkVLL%_RLL]VLL)LvL-L_VrLL~f^L)LvVf^L%LL9"rQL!LL9"LL9LLvVL)L=*RLLLLLaLL)L`VL-L9LvL-L`VLLRRLL^9LL1.zLwLyLL)LL%zLLyL)LwL)LwLL%zRLLVL9L=L)Ls+LLLLnVLL)L%LLL\b2L+b3L*b4L?b5L[b6L]b7L-b8^>^:)^=^2)^5^*)^-^")^%^)^^)^^ )^ ^-L9)rLLf"QLULLL9LVR^^^LLLf"QLULLL9LVR^^^LLLf"QLULLL9LVR^^^LL"LL!f^^^)L)L*r9L=LnVL=L=L%L]fLbLlVL!f 9L_L-fLbLlVL!f 9LLLL!b L%b^VyL-LLL%zL)^+r)L)L)L/"3rLL#eL/@+r)L)L)L#eL/:37b[#F7cY#^'X7dW#S7eW#57f[#M7gW#cV7h[#i7iY#Q 7j[#!n7k[#e7lY#ſ7mZ#N7nZ#7oW#?7pY#;7q[#O177rW#\7s[#7tX#!I7u[#S7v[#T7wW#r9&7x[#!|7yW# 7z[#7.7{W#^'X7|[#iW7}Y#7~[#&]7[#MR7W# S7W#7X#f7LL!7VL?mL7VL?%PL7VL?57L7VL?zk35L7VL?3L7VL?3DLLyL)L!LL%zLLLLLaLLL)LvLL-LvLLLLLLeL)La)LLLLL L LLvLLLLvLLLLLL7VL?rL LLvLLLLLLL)L-L)2L)LeLLaL-L-L-LLLL LLLLv LL ?>UL?[L?f!9L?Z?ZL?3U=L-?3TL ?1L? L)?L? L ??B/L ?fL?8L?G;L??L? $L ?z2L?<<L?wuL?J.L?L? L?L?S5L? JR77  #O177!#m%7" #K7##587$# >7%#f7& #>37'#f7(#W7) #F7* #M7+ #S7, # S7- #>#-7. #7.7/#z270#ڥA71 #iW72#73#N74 #&]75#3U=76 #MR77 #S78 #eK<79# S7:<LL>7=L=?!L!L!L?zL@LALBLCLDLELFLGLHLILJLLLKvL)L)LOvLQLLTLUL-?+UL ?۰12UL?WUL?VKUL ?UL?1UL ?UL? >UL?5UL?:UL ?*VcUL?9UL?H>UL ?fUL?^UL)?.:RUU7OF7P7QQ#!|7RQ#O177SQ#K7TN#ſ7UQ#>37VP#C7WQ#MR7XQ#(07YN# S7ZcLL!7dMLd?n7L%7eMLe?|L7fMLf?3L7gMLg?~27Li7hMLh?7Lk7jMLj?|5Lm7lMLl?Lo7nMLn?*=Lq7pMLp?вʥLL!7ML?ǖAL%7ML?L7ML?;L7ML??L7ML?-L7ML?8gL7ML?=L7ML?L7ML?z L 7ML?L 7ML?!@L 7ML?NL 7ML? LL!7ML?4L%7ML?L7ML?i3L7ML?L7ML?8L7ML?b L7ML?e9L7ML?4wL7ML?"P=L 7ML?)L 7ML?L7ML?CiL7ML?nN L7ML?-L7ML??L7ML?q&LL!7ML?!;L%7ML?L;ʥLL7ML?N+L7ML?L7ML??L7ML?5`*L7ML?K9L7ML?\L7ML?^L7ML?,L7ML?4L7ML?-L7ML?}L7ML?#oL7ML? L7ML?:zL7ML?L7ML?طL7ML?L7ML?oc|L7ML?V/LLLLLLLLLLLLLLLLvLL ?d'L?"7>L)?':L-?L ?]UL?Ң8L?NL?SL ?L ?L ?_`L?I4L?ǚL? SL?ſR77 #ve7#ſ7 #q7#9V7#e7#>37 #G97 #lY7#7#F7 #a17#M7L LL!L"LLL)L)L$vaL%LLLL)LLLL LLLFveL-L-LLHvaL-LLJvLLLKvLLL?UJLL?a1LL?)LL?4LL)?-XLL?T LL-?LL?cLL?fR LL66|6L/`S7_(LLL!b L%b^L-L*^L-L*^L ^^^)^3^=^G^Q^[^e^nL)L"^bL)L"^VL)L"^JL)L"^>L)L"^2L)L"^&L)L"^L)L"^ L)L"^9LL%z9LLz9L)L)Lzrr9LLz9LLz9L)L)Lzrr9L-L-L-LzrrL ^^^)^3^=^G^Q^[^e^nL)L"^bL)L"^VL)L"^JL)L"^>L)L"^2 L)L"^&!L)L"^"L)L"^#L)L"^9LL%z9LLz9LLz9LLz9LLz9LLz9LLz9L)L)LzrrL^^)^3^=^G^Q^[^e^o^y^^^^^6L)L"^7L)L"^8L)L"^9L)L"^z:L)L"^n;L)L"^b<L)L"^V=L)L"^J>L)L"^>?L)L"^2@L)L"^&AL)L"^BL)L"^CL)L"^9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L-L-L-Lzrr9L-L-L-L zrr9L)L)L zrr9L-L-L-L zrr9L)L)L zrr9L)L)L zrrL^-^7^A^K^U^_^i^s^}^^^^^^^^^^^^^_L)L"^`L)L"^aL)L"^bL)L"^cL)L"^dL)L"^eL)L"^fL)L"^gL)L"^hL)L"^iL)L"^zjL)L"^nkL)L"^blL)L"^VmL)L"^JnL)L"^>oL)L"^2pL)L"^&qL)L"^rL)L"^sL)L"^9LL!z9LL%z9LLz9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L-L-L-Lzrr9LLLLLzrr9L-L-L-L zrr9LL z9LL z9LL z9LL z9LLz9L)L)Lzrr9L-L-L-Lzrr9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L)L)LzrrQLLLbLb^=^9QLLL9VR^+^#*LfLL9VR^^R^^rLL9"rLL%!LLzrLLL%zLL9LVLLLLbLbB^S^OQL%f,QQLfQUL!f ^,^^%^^^^^QLL9R^ ^L9L LLL9L9LLL-LL%zLL-LL%zL LLVLL=rLLLVLLL-LL%zLVf -L9^rLLLL)LVf )L9^rQLLLLL)LVf )L9^rLLLLLVLL)LVf )L9^rLLL!b L%b^L)^UL!fQLLR^^^QL)ULL!LVLLAbLZf)^@)L!LLLVLL!L-LLALLaLLLVLLlL-LL9VR^r!LLLL!zLf%LaLL)LL^ LLLLL!b L%b ^ ^^QLL)LL9LLLL=LLVRLLLLL9LL=VRL ^^^__@_h_____Lj$Lf LLVLQLVl^TLLf LaLw f2LLL%LL)LLQL%zF^ ^L/*L9L2_Lj%Lf L!LVULLVl^KLLf LaLw f)LLL%ULL)LV^ ^L/*L9L2_QLLL=LLLvL-LVLVL:_gULLLLLvL-LVLVL:_=QLLLLLL-LVLVL:_QLLL)LC^QLULLLLL-LVLVLLLLLLV^QLUL)*LLLL!bL%b^;^7^Y^/UL!fQLLL)LVLGR^4^^^LLLLLL-LVLVLL}LLVLfLLLLLLV^LR^rLLLbLb"^;^7QLLL)L9VR^0^LLLL=VL^^-L-L-L=;rQLL)LL9L=LLVL)zRLL9L=L-LVLRL!f_jLLVl_LLf LaLw ge LL9L-L-L)LVL-L ^^^!^4^S^{^^^_  _LWLV_)LL9L ^QLLL=LvLLVL^QLULLLL=LvL)LVLV^QLLL=LLVL^QLLL)L=VL^vQLULLL=L)LVLLL-L=VLV^AQLUL)*L)LLL=L-LVL L LL=VLV^^ ^L/*)rQL9L=L)L+L9L=L)L+Lf_L ^^^6^7^Q^k^^^^^QLLf)L)LL9^^QLLL=LvLL:^ULLL=LvLL:^QLLL=LL:^hQLLL)L=C^RQLULLL=L)LVLL)L=K^#UL*LLL=L)LB^r7|77U7F77#W7#K7#ſ7#9V7#9л7#W7#F7#!I7# 7#T7#!|7#L(7#7.7#N7#7#MR7#-zK7#(07#eK<7#?7#7#f7#9W7# S7LL!7L?L%7L?" LL!7 L ?Vf9L 7 L ?L7L?dL7L?L7L?$L7L?[NL7L?n4L7L?Kp7L7L?N?$LL!7%L%?ȩL'7&L&?7L)7(L(?j L+7*L*?+L-7,L,?EL/7.L.?JEA L170L0?L372L2?#{!L574L4? rDLL!7ELE?b L%7FLF?}wLH7GLG?կLJ7ILI?hLL7KLK?daL)L"^2bL)L"^&cL)L"^dL)L"^eL)L"^9LL!z9LL%z9LLz9LLz9LLzLL9L)L)LZg6zrrLLtVL8rLA^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^______ _ __________ _"_$_&_(_*_,_7_9_;_=_?_A_L_M!_I!_E!_A!_=!_9!_5!_1!_-!_)_%!_!!_!_!_!__ _ _!_%^QL!L쌥^QL!L쌥^QL!LL%^!^!^!^^!L^!^QL!L쌥^QL!L쌥^!^!^!^^^^^^|^x^t^p^l^h^d^`^\^X^T^P^L!^H!^D^@!^^`^u^_6_J_x___O__>_S_h_}___e_LLL9L)LJ:_*LLLL9L-LJVLF_lLLL9L)LJ:_ULLL9L)LJ:_?QL!g`QQLgOQQQLfUL%fUQLUULLf:LLLL9VLL9LvLLVL*L)LF^8LL9LvLLVLLLL9VL*L)LFR_^^^^QQQLULLfLLL9LLJVR_P^R^QQQLf\UL%fNUQLUULLL9LvLLVLLLL9VL*L)LFR_^^^^ ^^^^QLULLL9LvLLVLLLL9VL*L)LF_LLL9L)LJ:_zQL-fL-LL=VLL9LvLLB_JLLL9L)LJ:_3LLL9L)LJ:_QL*LL*LFL4L*L*L%zF LLLL9VL*LFL*LLL!b L%b^L<LV^ UL^F L*L%FLLL-L9VL*L%F_mQLULLL*LLF L*L-FLLLL9VL*L-FLF R_QLfUL*LLLLa)LLfL*L%FLLLL9VL*L%FLLLL9VL*L)f^%FRR_^^LLL9L)LJ:_zLLL9L)LJ:_cLLL9L)LJ:_LLLL9L)LJ:_5QLULLLLL9VLLL-L9\_QLL*LFLL9LvLLVL*LF_QLfL-LL=V_^^QL*LL#VfLL-LL=V_^^QL*LL*LALLzL*L)L)L S_GUL%frUUL!fbQLUQL)UQL-*LLLLLL-LLLLL,VLLL.VL9VR^ۥ^^^^QLUL)*LLLLL9VjLL0!l^*LLf LaLUDf%^ ^L/*LL*L)FLLL9LvL-LVLLL!b L%b^^QL L LL-L9V^L*L)F^rL ^^^)^3^=^Q^s^__-L/L92_-LFL92_-LGL92_-LL92_QLLLL9:_zQLLL)LL=VL L9:_VQLLL)LL=VL L9:_2QLLLLb@LbNLb\LbjLbxLbLbLbLb^^L!LL9V^^L%LL9V^^LLL9V^^LLL9V^^kLLL9V^l^VLLL9V^W^ALLL9V^B^,LLL9V^-^LLL9V^^LLLNL9J_QLjULLVLL *fuj*L LVl^QLLf LaLw f/ *L L *L%F L *L L-LVF^ ^L/*L LLL9V^0 *LL LL!fV^L%fX^L"L9Vl^HLLf LaLw f&L)LUL=VLLL L9V^ ^L/*9^rLEL^^ ^_ ^_4__QLLbLb_^QQLjULLVLL *fmj*L LVl^QLLf LaLw f/ *L L *L%F L *L L-LVF^ ^L/*LLg^Lil^@LLf LaLw fL)LUL9VLLk^ ^L/*R^^ r^^^QLULLL-L=VLHLVLmR^^UL!fGUQLf6QLUQQLLL-L=VLHLVLoR^_^^^^QLULLL)L=VLHLVLL-L=VLHLVqR^^L)LL*rL^^%^@^T^h^|^^QL-LLL92^yQL-L*L)LIL92^\QL-LLL92^FQL-LLL92^0QL-LLL92^)L*L9*^)LL9*^rL^^%^@^T^h^|^^QL-LLL92^QL-L*L)L"L92^uQL-LL L92^_QL-LL<L92^IQL-LL=L92^3)LHL9V)LL"L9V)LLL9*^)LL9*^rLLLbxLbLlbLbLbLbLbLbLbLbLbLbLbLbLbLbLc__LWL9V__L3L9V_^L L9V^^L:L9V^^LL9V^^L$L9V^^L?L9V^^LCL9V^^LL9V^^LTL9V^^rL L9V^p^bL-L9V^`^RLL9V^P^BL^L9V^@^2L1L9V^0^"LL9V^ ^LL9V^^L)L=2r-LLLbqLbLbLbLcLcLcoLcLcLcqLcLcLcsLcLcLcu__LL9VLLLL=VLLV__LLL=VLLLLLL=VL쭥_R_qLLL=VLLLLLL=VL쭥_ _?LHLV*LLL9VLLLVL*L-LILVLHLVLLL=VLL!LLLLVLLVLLVL!L"LVL%LLVR__LHLV*LLL9VLLLVL*L-LILVLHLVLLL=VLL!LLLLVLLVLLVL!L"LVL%LLVR__LL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV__LL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV_(_GLL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV__LL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV_n_LL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV__0LL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV__LL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV_W_vLL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV__LL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV_^LL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV_@^_LL9VLLLVLHLVLLL=VLL!LLL%LVLLVLLV_^-L-LzLLLbLbLb__QL!f0QQLfLLL=VLQLV_^^^^L!f1QLfLLL=VLQLV_H^_^_ _QL!f0QQLfLLL=VLDLV_^^^^L!f1QLfLLL=VLDLV^^^^^^L!f}QLfkQQL!fXQL!fGQQLf4QQQLLLL!LL2L!L=VR^W^^^^^^^^ ^^^LLL=VLHLVLLL=VLLL[r9L9*L%F9L9UL)L9*LVF9LL-L%+r9LLL=LLV9LHL)LLBLULL;L!L*L*L*LLLLLBL * L * LzLLL-LV*LLLL9VL)*L-*L L=VLLLLVLULL)L4L* L-LLLQzLQL%zF)ULLLZVLV)*L!fZ)*LLVLLL*LVLLL=LvLLVL)L L=VL*LL=J^LL L=BRrL)LL%fSL%fFQLUL)QL-UL-L)L)VL!f)LL9VR^^R^^^^^L-r9*Lf9L9*L)LL=V9L L=LLL9*f9L9*L)LL=V9*Lf9LHL=V_9LL9LHL=V9LLLLV9L%LOL=V9LL0)LLL!b L%b^i4LLLL%z^UQL)ULL9f"4LLLLL!L=VL%z^L4L-LL%zLL%L=S^r9LHL=V9LL)L#9LL)L=V9LHL9LL)L=V9LHL9LL)L=V9LHLL-LLLbGLbLbLbLc;LcxLcLcZLcLc_s_oL%f7UL!f&QLLL)L9VLL=VR_^_5^_/_+L%f7UL!f&QLLL)L9VLL=VR_Y^_^__L%f7UL!f&QLLL)L9VLL=VR_^_^__L%f7UL!f&QLLL)L9VLL=VR_^_i^_c__L%f7UL!f&QLLL)L9VLL=VR_^_%^__L%fkUL%fZUUL!fGQL)UQLLL-L9VLHL=VLL)L9VLML=VR_^_^_^__L%fkUL%fZUUL!fGQL)UQLLL-L9VLHL=VLL)L9VLL=VR_^_;^_5^_/_+L%gQL!gQQLgrUL!gcQQQLj *LL@Vl^6LLf LaLw fL)LLV^ ^L/*L*LLLLa*LL-L)VLLL L=LvL)LLV L=LLvLL]VLQL *f L *LQLL=VQL *f LHL=V_ LFULLL!b L%b ^3L4LLL *L%zF^QLLLL=V^ L=L LLLvLLVRR_^^^^ ^^^^L-LV__~L%g QL)ULLLLxL *fLfoLLLL)L)LvaLLL4LLL%zLL!LVL]VLVL L LL4LLL%zL LVR^mLf4LLL9VL=L9LvL)LVLLKL=V^2L9L=LvL)LVLLL9VLLKL=VR^ӥ^^i^eL%fVQL)ULL9L=LvLLVLL-L9VLLL!fLLL=VR^p^^^L9L=LvL-LVLLL-LVf#L-LL*L*L5VL=B^L-LLOL=BrLLL!b L%b^LL*^ULL!bL%b#^z^v)QL9L=L)LVR^^[)UQLfG)UUL!f4)QL-UQL9L=L-LV9L=L)LVR^;^^ ^^^QL)UL9LL-LVL1^9LL)L=V9LHL9LL)L=V9LHLLLLLL!b L%b^#9LGL=V^QL9LL)LV^9LHL=V9L9UL)L9*LVFR9*Lf9L9*L)LL=V9L L=LL9LHL=V9LL-LV9LLL=V9LVL=*RLLL9LL-LPL%3RL9L=LLLAL)VL!fL!RLLLLL%b L!b(^)QLL9L=L)LV9L^^RLLL9LVL=V9LHL=V9LL)LV9L-L=VLL9LRLLL9L=LL4LLL%zL'LV9LRLLLL)L9VL^)^;^^^__h___'_a_z__7 _ _ _2 _ _ _QLLLL=S_QL!fLGLV_ ^^QLUL*LLLLLLLva-LL*fL*L-LLVL)LLVL-FR_ QLLL)LS_n QLULLL-LVLL<LR_E UL%gUUL%gUUUL%g{UUUUL%ggUUUUUL%gQUUUUUUL%g9QLUQL)UUQL-UUUQLUUUUQLUUUUUQLUUUUUUQLUUUUUUULLL!f&QLfQQLf^^^ ^^^^gLLL!L L LLL!L4LL4L L4L L4L L4L L4L L L%zL%zL%zL%zL%zL%zL9VLLLfQLUL)LULLLL!LLLL4LLPLLL%zL+LVLLLL4LLLLVL4LL4L LL%zL%zL%zL9VLVL%LLVL)FRR^R^^LL LL4L L4LLRL!L4LLL%zL%zL%zL9VLVRR_ ^R^*^^^^^^^^ ^^^^QLL!bLbF^^QQLf-QQQL)ULLL-L-LLVR_R ^^s^oQQL)QUL-ULLLLvLLVLLLVLHLVL)L<LVLLLLVR_ ^QLULLLLvLLVLL-LVf"LLL*L*L5VLR^LLLOLR_q UL!f[UQLfJQLUQQLLL-LVLL!f^L%f^L=LVR_ ^^^^QLULLL-LVLHLVLL)LVLLLR_QLLLLvLLJ_*LL!b L%by^QL)ULLLLf LYLVLLLVLLLLL LLLVL  L-L VL L)iR^tQL)ULLLLf LYLVLLLLLVL LLLVL)L LLLVL aR^_QLUL)*L*LLLLVLLLLLLVL)LLV)LLL!b L%b ^BL-q^:QL L LL L L-LV LL LVL^R_ QLUL)*LL L*L* L LF  LF  L4L *L *L%zF  LLLV *LL)VL!f LLV * LL)VL!f LLV L)F  LF  L LV L *LLL!b L%b^LLV^ UL^F  L LL LHLV UL L ULL*LVF L LLV L%LLV LFL)yR_QLULL)L)L[_QLUL)*LL LLLLL L zL/c_QLLLL!b L%b^2LGLV^&QLL*LL)VL!L)LV^!L*LLLvL*LVL*L*L LVLFR_QLLLL!b L%b^^QLLL)LV^*L*f&*LL*L*LLVLFL4LLL L*L%zF _j*L*f&*LL*L*LLVLFL4LLL L* L%zF _QLULLL-LVLL)L[_QL!fLGLVLLV_^^QL&LEL)L]VL7VLj LL@Vl^ULLf LaLw f3LLLLULVLL-L)L V^ ^L/*LLL LVLLVLHLVLLLvL-LVL%LLZR_QLj *LL@Vl^2LLf LaLw fLLV^ ^L/*L*LQb*LLL)VL!f4LQL*LL[L-L[L *zL6VLLVL*LVLFLLLPF_CUL%ffUUL!fVQLUQL)UQL-*LLLLLLLL,VLLL.VLVR_^^^^QLUL)*LjLLLLLL LVLLLVLALVLLL-LVL LvLLVLLLV LLL!b L%b^$LGLV^QLLL)LV^L LLLL LvL)LVLL)LLVRl^LLf LaLUDfLLLVLHLVLLLLvL-L]VL)LLL!b L%b^9 LGLV^-QL L L L4LLL%zL'LV^L L L LLL LvL)L]VLL)LLV L%LLVR^ ^L/*Y^RrULQL)L-L9UL-L=LLLZVLVL=LVLL:R9LL-L"rL)LL)Rr9L=L LV9LHLV9LLLLL9LGL=V9LL=V9L)LL=V9L)L=LvLL*RLLLLBLLLLLLBLLzL)LLBLL;LL;L!L!L!LLLLLLBL!L!LL zL-LfULLLVLLLL9VLLL=VLQLL)VL!b LL!fQL* LLBLLBLLF L)FL!LLVL)L)LvLQLLVL!L-LLLVLBLLLL>VLLVLL vLLV-L)LVL-LVRUL*L)* L(VLVQL)URr 77|7U77L/`S74_KLLL!b L%b^L-L*^L-L*^9LLLLLL%zrrLLL%b L!b^*L^!^-L-L-L-LL9LL9LVL%LMr-L9LL9LLLfLLL%b L!b^QL)UL-*L*L-L9LL9f"-L-L-L-L L L L=VL=^qLLL%b L!bN^WQL)UL-*L*LLLLL=VL-L-L-LLLL=VL=^L;L^^L=LR^_L)Lf)LLL%b L!b^QL)UL-*L*LL9LL9f" L L LL=VL-L-L-L=^r-LLL%b L!bN^WQL)UL-*L*LLLLL=VL-L-L-L L L L=VL=^LFL^^LHLR^^!LLLLLLVL%L]RrLLL%b L!b9^?QL!fUL)*LL)R^$^^QLL9)^ L!^LLL%b L!bQ^WQL!f*LR^F^^QL)UL-*L*L-L9L-L-L-L=\^  L!^L)LL!f^;^^L!f)^*^^L9LLLL)L)LL=LTRrLLLLVL!LLL%b L!b^QL)UL-*L*L*L9LL=VLL!fL9LLLLu^@L!fLLLLLLt^)LLLLL-Lt^L9LLL%LE^)LLLL-LLL9L&vaLL)RrLLL%b L!bR^XQL)UL-*L*L9L-L=VLL!f L^L!f L^)^ L^LLL-L-L-L(va-LRrLLL%b L!bw^xQL)UL-*L*L9L-L=VLL!fL)LR^7L!fLLLLLd^LLLLLd^^LLL-L-L9LL=L*va-LL)RrLLL%b L!bH^HQL)UL-*L*L9L-L=VLL!bL!f^LI^^LLL-L-L-L,va-L)RrLLL!b L%b^;^8QL)UL-*L*L-L9)L)L=VL9A^LLLL.vaL!rLLL!b L%b ^U^QQL)UL-*L*L*LL9L)L9LLLL=L-LL}R^LLLL0vaLL)rLLL!b L%b ^>-^:QL)UL-*L*LLL9L)L=LL9^rLLLL2vaL-L)r47 7  #i7 #K7 #e7 #&]7 #F7 #7 #eK<7 # S7LL!7 L?mL7 L?"63LLLLLvLLLL)LeLLL!vaLLL"vL#L$L%LL'L)LLL+vL-L/L1L3L4L ?x 4L?D4L ?X4L ?4L)? S4L ?9V4L-?ſ4L?84L?L4L?\4L?9л4L??4L?:4L?f4L ?ͱJ4L?!IR447F77L/`S7Q_ LA^^^^^^^^^^^^^____%_/_9_C_M_W_a_k_u_______________ ___)_3_=_G_Q_[_e_o_y_______________hL)L?"_iL)L?"_jL)L?"_kL)L?"_lL)L?"_mL)L?"_nL)L?"_oL)L?"_pL)L?"_qL)L?"_rL)L?"_sL)L?"_~tL)L?"_ruL)L?"_fvL)L?"_ZwL)L?"_NxL)L?"_ByL)L?"_6zL)L?"_*{L)L?"_|L)L?"_}L)L?"_~L)L?"_L)L?"_L)L?"_L)L?"_L)L?"_L)L?"_L)L?"_L)L?"_L)L?"_L)L?"_L)L?"_L)L?"_vL)L?"_jL)L?"_^L)L?"_RL)L?"_FL)L?"_:L)L?"_.L)L?"_"L)L?"_L)L?"_ L)L?"^L)L?"^L)L?"^L)L?"^L)L?"^L)L?"^L)L?"^L)L?"^L)L?"^L)L?"^L)L?"^L)L?"^zL)L?"^nL)L?"^bL)L?"^VL)L?"^JL)L?"^>L)L?"^2L)L?"^&L)L?"^L)L?"^L)L?"^9LLz9LLz9LLz9LLz9LLz9LL z9LL z9LL z9LL z9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LL8z9LL9z9L)L)L?zrrL^^^#^-^7^A^JL)L?"^>L)L?"^2L)L?"^&L)L?"^L)L?"^ L)L?"^9LL!z9L)L)L%zrr9LLz9LLz9L)L)Lzrr9LLzLL?LA^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^}^z^w^t^q^n^k^h^e^b^_^\^Y^V^S^P^M^J^G^D^A^>^;^8^5^2^/^,^)^&^#^ ^^^^^^^ ^^^L^ ^^^^^^^^^^ ^^^^__{_yQLL9Lj+=LLBVLLfLLLLfl^?LLf L^aLw f=L)LLZVL-LUV^ ^L/*_^QLL9Lj+=LLBVLLfLLLLfl^?LLf L^aLw f=L)LLZVL-LUV^ ^L/*^^QLL9Lj+=LLBVLLfLLLLfl^?LLf L^aLw f=L)LLZVL-LUV^ ^L/*^^9L)L=LIV=L=L)Lf^%rLgLLAL9L)L)LvL-LMV!L-LbL%L!L=VLL)L=LvLLHVLLbL-LIVL)LzR9LL[V9L!LV9L!f|9Lf)=LLLLYV9L9LL^LLLL!fLf^!L=LLL9LLLYV9L!LL)RLLL9fDL=9Lf"LLL%LYVLLLYV^LL%L%LYVLfL=LfLL%^]LLL!fL fLLLLYV^,L-LLYVL-LLYVL-L LYVL-RLbLLLfL)LYV^7Lf)LL)LLLYVL)LLYV^ !LPL"LLMVL-LbLDV!L!L!LLL)LL-LL#va-LLL LLL$vLLMV)LQRrL^^2^b^^^^QL9L%LYV9LL[V9L!LV*^QLUL9LLYV9L=L-L\VL)LLD2^QL9LLYV9LLNLKV9LL[*^gQL9LLYV9LL[V9L!LV*^BQLUL9LLYV9L)L)L;^QL9LLYV9LLY*^9LL[V9L!LV9LLA^^^^^^^^^^^^____-_@_B_P_R_T_b_p_~______*_8_F_H_J_L_N_P_R_T_V_X_Z_\_^_`_b_d_f_h_j_l_n_p_r_t_v_x_________!_%___QL)L_QL)LL_QL)L_~QL)L_nQL)LL=_Y _UQL)LL _AQL)LL= _,QL)L _QL)L _ QL)L_QL)LL=__QL)L___QL)L_QL)L_QL)L_QL)LLL-L\VLLL\V_rQL)LLL-L\VLLL\V_IQL)LLL-L\VLLL\V_ QL)LLL-L\VLLL\V^^QL)L^QL)L^QL)L^^ ^!^"^#^$^%^&^'^(^)^*^+^,^-^.^/^0^{1^w2^s3^o4^k5^g6^c7^_QL)L8^OQL)L9^?:^;;^7<^3=^/>^+QLUL-L)L)L?^ L@!^LLL9fL)LLY:^yL fL!bL%fL)LL)LL%LY:^HL!fLfL)LLLYVLLY:^L)LLLYVLLD:RrLL-L&L[VL9LLL)QLLLbLDVL-LbLDVLLDVL)L=L'vLLMVL(L-LMVLL-LL)vLLHRRRr9LSLL!f =L_^=LLWVLLOLLL-L-L-L+vaL!R9L=L9f_Q=L>LL%L!fJf=L>LL%LL쨥^L%LLLbf /LPL)L!^LL!f`LLLLL!LL)f'LL)LLLIVLL%_LLL)L1R^LL!f3LL)LL)LLLIVL%L^O=L>L=L>LL-LL-LL)L LLLLIV-L%L)RL>LLLf^L)L>L)LLL쨥LL!f -LPLL9L.vLTVLLGL!L!L)L!L!L=VLLLL LLLLLLL0va!LLR 9L>L^^^^:^T^b^|^^9L=L ^^x9LGLLLLL V^c^Z9LFL9LLJVL^G^>9L=L^7^.9LLLLLLVR^^9L>L^ ^LcL!f^r9L=LLLj LLBVLLf Lcl^ALLf L^aLw fL)LLZV-L%L^ ^L/*)R9LL\VLLf LcL-rLL9L)L9LLQVL^6^4^2^0^.^,^*^(^&^$^"^ ^^^^^^^^^^ ^ ^ ^)^F^c^^~QLLL)L=VL^m^_QLLL)L=VL^N^@QLLL)L=VL^/^!QLLL)L=VL^^4LSLEVLX3RLL%f1QLUL9LL!LL=VL-L VLIVR^ ^^rkLLJVLL&f LcLGLLGLLGL)L!b)LbL!bLbL!bLf Lc)L L9L=L2vLTVLLgLLL L9LLLL3vaL-L%LL=VL!LdLLAL)LgL>LLL^ ^^-^T^f^dL)L^a^ULL%L)L^K^?LfLL>^L>L)L^"^LGL)L^^4LLEVLLLLA^^^^^^^^^^__ _P_X_`_h__________#_I_o_s_{________________________________ ___&_*_(_+_"_%_____L__LL__L__L__jLLBVl^/LLf L^aLw f Lc^ ^L/*L____LL__jLLBVl^/LLf L^aLw f Lc^ ^L/*L_O_FL_E_<L_;_2L_1_(jLLBVl^/LLf L^aLw f Lc^ ^L/*L____L______L__L__L__L]LLbLLL%zL__L]LLbLLL%zL_b_YL]LLbLLL%zL_:_1L]LLbLLL%zL__ _ _L_^L^^L^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^y^|^s^v^m^p^g^j^a^d^[^^^U^X^OL^N^EL^D^;^>^5^8^/^2^)^,^#^&^LL)LLV^^^ ^LcLLLLbLIVLL)Lf^%LLUVR_s)Lf Lc-L-L)LbLIV-L5LLL6vL-L@VLL7vLLHVLR l^KLLf L^aLLb Lt! b^Lc^^Lc^ ^L/*9L=L)L^^^\^p^^^QL.LLa^QLULL!fL=fL)LLIV>L)LeL?LLe^QL@LLaL^lQLALLa^ZQLULLLLLLLLLVBLL)LNLLbL`VR^QLCLLe^LLR+r9LFL)LNLfG^L-LNL LCVL-L=LzLR#LGLLer9L)L\Vf =L LVV=LJL-L-L:^t^r^p^n^p^^^^^b^^^^__$^T_1^P^N_@_S_f_y___^>___^6^4^2^0^.^,^*^(^&^$^"^ ^^^^^^^^^^ ^ ^^____QLlLLV__QLmLLV__QLnLLV__QLoLLV__QLKL숥__QLrLLV__QLLL숥__wQLtLLV_m_bQLuLLV_X_MQLvLLV_C_8QLML숥_2_'QLyLLV__QL|LLV_^QL}LLV^^QL~LLV^ޥ^QLLL)LV^ĥ^QLLL)LV^^QLLL)LV^^QLLL)LV^v^kQLLLV^a^VQLLLV^L^AQLLLV^7^,QLLLV^"^QLLLV^ ^LeLzLRVLL)Lf^%rLLL9LLL)QLL9LLbLRVL:LLbLRVL;L)LLbLRVL<LLRVLL=VLL)L)L=LDvLLHVLELLRVLLGvLLMVLHLLRVIL!L)L L-L-LLNvLLHVLOLLRsRRrQ757677|7879F7: 7;7<9#9V7=7#17><#K7?8#ſ7@9#f7A6#9л7B:#9V7C7#7D<#F7E7#p>7F7#97G9#Q 7H<#!n7I7#VK7J7#tK7K7#q7L9#ſ7M:#7N;#f7O<#eK<7P9#N7Q7#a17R7#W27S9#;7T9#!I7U7#ve7V;#07W9#W7X7#7Y6#!I7Z7#lY7[<#S7\<#!|7]<#7.7^;#(07_<#L(7`:#C7a9#7b<#&]7c<#MR7d<#(07e<#)7f6#f7gLL!75L?HL%75L?!L75L?Dm>L75L?L75L?Nƅ?L75L?gv)L75L?d]L75L?L?L75L?٣L 75L?|L75L?12L75L?WL75L?fL75L?,)L75L?#L75L?عyL75L?u L75L?0%L75L?oL75L?=:5L75L?q=L75L?D,L75L?%9L75L?B1L75L?L75L?j)L75L?L75L?J+L 75L? L!75L?P L"75L?1L#75L?`a?L$75L?>3L%75L?13L&75L?:L'75L?V?L(75L?V?L)75L?xn8L*75L?CEL+75L?1L,75L?{'CL-75L?<L.75L?:;L/75L?M>L075L?xE6L175L?BL275L?:L375L?;L475L?N L575L?@L675L?[/L775L?@;L75L? 8L75L?Nh7L:75L?#L;75L?#L<75L?@" L=75L?@" L>75L?\@L75L?n?L@75L?Ґ2 LL 7 5L ?$L7 5L ?ǀ L75L?Ɛ7L75L??L75L?AL75L?oLLg(75L?$<LLLLLL vL%LLLLL*vL,LL1LLLLLL8vLLLLLPvLQL?y/^QL?lYQL ?/ QL?ڥAQL-?pd{QL)?VKQL?77QL?p!>QL?IڕQL?4}rQL?UR QQ77#777#*=7#0%7#/ 7#?7#cV7#:7#J+7#Nh77#j)7#7#ſ7#,)7#:7#:;7#@" 7#W7#@" 7#CE7#7#7.7#5`*7#iW7#;7#Ɛ77#L?7#o7#MR7#%97#B17#7#9V7#K7#Nƅ?7#F7#W7#^'X7#@;7#q=7# 87#в7#!I7#\@7#d]7 #137 #A>7 #!I7 #{'C7 #>#-7#o7#N 7#7#عy7#B7#7#<7#7#ſ7#f7#H)Z7#ſ7##7#9л7#!I7#[/7# S7#Hwy7 #N+7!#gv)7"#?7##V?7$#!n7%#i7&#7'#A7(#e7)#u 7*#^7+##o7,#<7-#47.#!7/#70#xE671#772#`a?73#!|74#n?75#L(76#^'X77#&]78#K979#>37:#:7;#٣7<#127=#ſ7>#V?7?#9л7@#>37A#f7B#xn87C#P 7D#M7E#Dm>7F#H7G#=:57H#f7I#ſ7J#7K#|7L#@7M#W7N#D,7O#O177P# 7Q#~277R#17S#17T#$7U##7V#17W##7X#Ґ27Y#ǀ 7Z#(07[# 77\# S7]#M>7^fLLh7gLg?u_:Lj7iLi?ЗLl7kLk?w'Ln7mLm?B(Lp7oLo?˩L7qLq?!$L7rLr?>sLLu7tLt?;WvLwLxL)LzL{L|L-L}L)LLvL-L)LvLL-LvLLLvLLLLL LLLLLLLLLva LLvLLLLLLLLLLL)LLLv2LL2LL2LLLv2-LL)LLLL L Lv-2)LLLLL Lv)2LLLLLL LLLveLLLLLLLLLLLLLLL(LLL LLvaLL LL vL L?$ L?lY L? L?<* L?7 L ? L?z L?  L ?-8 L?]U L ?H> L?MP L?i L?c1' L ?) L?  L?) L?` L?̫( L-? L?7 L? L? L?0f L?s%o L? L?Q p- L ?`$R  6 U6 F6L/`S7_ L ^^^)^3^=^G^Q^[^e^nYL)LU"^bZL)LU"^V[L)LU"^J\L)LU"^>]L)LU"^2^L)LU"^&_L)LU"^`L)LU"^aL)LU"^9LL%z9LLz9LLz9LLz9LLz9LLz9LLz9LLzLWLLL!b?L%bLb@LbBLbDLbFLbHLbJ^Nc^J)Ld!^A)Lf!^8)Lh!^/)Lj!^&)Ll!^)Ln!^)Lp!^ )Lr!^L ^^^"^.^:^F^R^^^j^u^rQLLV!^dQLLV!^VQLLV!^HQLLV!^:QLLV!^,QLLV!^QLLV!^QLLV!^L/1&L$L9rL9L)LL)@rL/HoLt/Ho#QLSL#.Z!L-QL2L!fL%aLL)$e_LLLCRrLvL|L9LxL9LzL9L~LLVL9rL9L-L-L)L;rL7R|7S7TT#K7UT#-q7VT#eK<7WS# S7XbLL!7cRLc?]8Le7dRLd?99Lg7fRLf?f=uLi7hRLh?j0Lk7jRLj?ǁ=Lm7lRLl? Lo7nRLn?XILq7pRLp?Ls7rRLr?cmuLL/HoL#g%Z7twL%L/HoL#g%Z7vyL%L/HoL#g%Z7x{L%L/HoL#g%Z7z}L%L/HoL#g%Z7|L%L/HoL#g%Z7~LL/HoL#g%Z7LL/HoL#g%Z7L%L/HoL#g%Z7LL/HoL#g%Z7LLL)LL)LLLXLLLLLLLL LLL LL LLLL?q1L?L)?/L?۝L ? *5L?2L?RL?o>-L-?aL?sL?b$L?g|L?VL ?1&L ?MuL ?2lL ?NkR6L/`S7W_9-LLL!b L%b^L-L*^L-L*^*LL)*L%FLL*LL)*L%FLLLL)LVLLLLLLLLLLLL!b L%b^8 LML2^,QL)UL9L)f^L%LL=B^rLLVLLf0QLLLL)L va!L)L)V^^^ LTL*rLLL!b L%b^8 LbL2^,QL)UL9L)f^L%LL=B^rLLVL!f)^LjLLVl^2LLf LaLw f LZLV^ ^L/*LjLLVl^2LLf LaLw f L[LV^ ^L/*LLLVL!fLLL%zL9^OLLVLLf0ULLLL)Lva!L)L)V^^^ LiLJRrL ^^^^ ^ ^^^%^(^9^7^5^2^0^-QLL9^^^^*LL9^^-L9f+LLLLLLLL%zLV^L-L-LVrLLLLL-LVrLLL%f^!^^LLL-LL%zLL^^ ^ ^^^^^/^-!^+^'QLL^^QLL9^^%LLVLLfQL%fQQLLbLb@LbcLb^^QUL!fUL!f ^^^^^^QUL!fUL!f ^p^^h^^b^VQUL!fUL!f ^F^^>^^8^,QUL!fUL!f ^^^^^^^^^^)LLVL!fLQL9L-LV^L)LL%zLLj ULLVl^QLLf LaLw f/LLLVLLLULL)LV^ ^L/*LLrL)L ^^^_^s^^^^_?__L_VQLL!f#L!L9L!L-L9LV_,^^QLLL_QLf^L_QLLL_QLLL_QLLLL_QL*LLVfL=L!L9LV^ LL_QLLbLb#^<^8LLLLVL_W^LLLLVL_<^QLLL_%QLL%bL!b^^QQL*fxQUL!ffULfVUQLLbLb#R^p^8LLLLVLR^^LLLLVLR^^^^0^^*^^$^ ULLLLVLR^k^QLULL)L)LLLbLb^ ^QLR^^QLR^^ LLVLLVL^rLL9L=L-LVLL)LLVRLLLLLbLb3^D^@ULfQL)UQLL)R^-^^^QLL9R^^ LLVLLL=LLLVL9L-L-LVLRRjLULVL9l_LLf LaLw gQLLL=LL^^)^~^_j_o____O__I__,_ LLV_*f *Lf*^LLfLL^'LLLL-L9LL%zLLV_BQLULLLLLLVL L LLVLLL-LL LLLLLL%zL%zL%zLR_QLULg LLL9LLLL LVLVLLLLLLVLL LLLVLL%zLVLLLL9L-LVLLLLLLVL LLL VL L LLLL9LL%zLVLLVL LFLL!fLLV^!^^LLLVLLLVR^nLFfL)LV^VLLLL L9LL%zLLVLLLLLVLLLL%zL%zL_RUL%fUQLfUUL!f~QLUQQL)UQLLLLVLLLLLLLLL%zLLL L LL VLL%zL%zLR_^^ ^^^^QLULLL-LVLLLLLL L!vL)LVLL)L)L L LL VLLVR_KQLULLLLLVL)LL LV_QLULLLLLVL)L LV_QLULLLL"LLVLL LLLVLLL LL%zL%zLLV_QLUL)*LL LLLVL-L-L VL LV_cQLUL)*LLLLVL LFLLLLL#L LVLLLLL LL%zL%zL LVLL L LL VLL%zL%zL_QLULLLLLVL!L LVLL L LL L L$vL)LVLL)L)L L LL VLLVR_eQLUL)*LLL-LVL UL LLLLUL%zF L LLVL L)FLL LLLLLL%zLLLLL%zL%zLR^QLULL)LVLLL-LVL L LLVLL-L-L-LLVR^~QLUL*LLL LF LLLVL L-F L LLVLLL-LL LLLLLL%zL%zL%zLR^R^ ^L/*1rLLLLLL%zL9LL zL-f L=^9LLLLLVLfLL LLL LVLL LLL%zLVLLLLL LLL LVLL%zLVLLL LLLLLL%zLLLLL L LLLLL%zL%zL%zL%zLR^RrL9LL=LL L)LLLLLL zL/VL-LLLLLLL%zLL)LVLLL)LLLLLL%zL%zLRr(LL9LLLL9LL!f@L=LLLLL%zL%zLLVLLLL-LV^^^LL)LVLLL=LLLLL*LLVL%zL%zLLVLL)LLLLLLLL%zLLVLLLL-LVR-L9LLLLLL=LLL-LLLL+vL-LLL QL9LLVLLVLLL-L)LVRrL*LL%zL-LLVLLL)LVLLLLLLLLVLLLLLLLVLL%zL%zLVLL-LVLRrLL9LL-L=LVLLLVL)LRLL9L9L%=L LL-L9LLLzL/3RLLL!b L%b^6 LzL^*UL!fQLR^^^ULL9^L ^^ ^+^6^A^^___oLL_bLL_ULL_HLL_;ULLL9LLLL=L/vLLVLVLLLVL-LLLL%zL)LVLLLLLL L0vLLVLLLLLLL LLL%zLL-L%zLR^LL^|QLLL)LLT^cLL^V*LfLL^>^^QL*LLLL1aL-L)L-LLd^r9L=LL3L9LVLL=LLVLL=LLVLL%zL%zLVL9L)L)L!LLV9LL=LLVL=LLVLV9LL=LLLLVLLLLVLL%zL%zLVLL9L=LLLLL4vLLLLLL5vL)LLLLLL6vLLLL7b\L8bbL9bhLbnLbLbLcLc6LchL:cL;cL<cLlc__L__L__L__LLLL%b L!b^L^ L^_k_`LLLL%b L!b^L^ L^_2_'LLLL%b L!b^L^ L^__LLLL%b L!b^L^ L^__LLLL%b L!b^L^ L^__|LLLL%b L!b^L^ L^_N_CLLLL!LLV_,_!LLLL!LLV_ ^LLLbLb^^{L^^nQL)ULL L9L=L L=VLLLLVLLLLVLLLLVLL%zL%zL%zLVR^B^LLQL L LVL!LLVL L LVLV^4^)Lf Lf>L-^^^^L-QRr)LL!g+Q ^^^^ ^ ^^ ^___ QQL@f)LL%fQL!fxQQLfgUL!fYQQQLLLALVLVLLLLLLL-LLQLVLLR^^^^^ ^^^^ LLV_^_b_\QQLf)LL%fUL%fUUL!fQLUQLLLLLL%L9LL L=LBL LVLL LLVLLLLVLL%zL%zL%zL%zLVR^^^ ^^^^ LLV_^__QQLL!bL%c__uQULLbLbR_d_)QUQL@fLL%fQL!fxQQLfgUL!fYQQQLLLALVLVLLLLLLL-LL QLVLLR^^^^^ ^^^^ LLVR_^R_^)QUQLfLL%fUL%fUUL!fQLUQLLLLLL%L9LL L=LBL LVLLLLVLLLLVLL%zL%zL%zL%zLVR^^^ ^^^^ LLVR_^R_^_QQQL*gQQUL!gQULLbLbR__)QUQL@fLL%fQL!fxQQLfgUL!fYQQQLLLALVLVLLLLLLL-LL QLVLLR^^^^^ ^^^^ LLVR_^R^^)QUQLfLL%fUL%fUUL!fQLUQLLLLLL%L9LL L=LBL LVLLLLVLLLLVLL%zL%zL%zL%zLVR^^^ ^^^^ LLVR^N^R^^^^^^ ^^^^LLLVLLLLVLLVL9r9L9*L)LVF=L=L%LELL=LLVLLL)LL9L=VL)L9L=VL2RrL9LL="QLL^-^D^\^q^^_ __&___&_A_W____"_d__:_dQLLLL9VL_KQLLLL=VL_1QLLLVL_QLULLL-L-LLV_QLULL)LVLL-LVLLV_QLULLLDLLVLLLLVLLLLVLL%zL%zLV_|QL%f\QUL!fLQQLULL*L-LVFLL)LVLL-LL%zLR_"^^^^QLULLLL-LVLLELL-LLLLFvLLVL%zL_QLUL)*LL-LVLL-LVL)LLL!b L%b ^^QL LLVL^LV_[QLUL)*L-*L)Lf$L)LVLL)LVL LV^q-fCLLLLVLLLVL LVLLLL%zL^+LLLLL%zLL VLL%zL_QLUL)*LL-L-L-LL VL_yQLLLLVL-L VL_UQLLL)LL VL_8QLLLVL_ QL-LLGvLLVLLLHvLLVLL VL_QLLLL!b L%b^`LL V^TQL)ULLL-LVLL LLL L LVLVLL%zL%zLL V^L_aQLULLLLbLb7LIbNLb{^^L!LLLLVLV^^}L-LVL!LLV^m^_LLLLLLVLL%zLLVL^9^+LLLVLL%zLL VL^^ LLV_QLUL)*LLLLVL-L-LLVL_MQLULLLLLLLLLLLL%zLLVLLLVLLLLLLLL LLL LVLLLLL%zL LVLVLLVLL LLLLLLLzL/VLL LLLLLL%zLLVLLLLLLLLLL LLL%zL%zL%zL%zLL LLVLL)LVR_ QLULL)LVLLLV^QLULLL-L-LLVLVLLLLL%zLLLLL%zLLVLLL)LLLLL%zLLLL LLLLL L%zLLL LzL/VLVR^/QLULL)LVLL)LVLLV^LLRrLLfULfB*L*L9LL-LVL=L-LVLLVLLR^Q^^UL=L=*L)LVFLLL%zL9LVLL^^^ LL"QLLLfUL*L)*L)Lf9LL=VLLLLVL)LLVLLLLLL!LLVL-LVLLL)LL LL LL L LL!LLVLVLL%zL%zLLLLL-LV9L9*LLVFRR^^^ L+L*LLL9L=LLLKvL-LVLL-L9L=LLLLLvL-LVrLLL!b L%b:_9-LLVL!f%9LL=LLLLVL9L%z_QLLbL bY^^)QQLfA)QLUL*L)*LULLL L%zLLVR^^^4^0)QQL-ULLL-L-L%zLVR^s^QL)ULLLVL!f%9LL=LLLLVL9L%z9LL=LLVL9L%zLLB^r)*LLLL)LLL9LL=LNvaLL)VL-FL9RrLLVL9L9LQL=LRLVLLLLL9LVLLQL=LL%zL%zLVL9LLLLL-LVR9LL9LPL=LLVL-LLVLLL!b L%b^K L_LV^?QL)UL9LLL=L9LLL=LLVLV^LLL)LL%zrL9LLLLL!LLLzLQLLLL=LPLLVLLLLL9L=LSvLLVL)LL=LTvLLVLLLVLL%fQL^^^LLLL%zLLL=L9L-LUvLULV QLLLLLVL%zL-LLVLVLRrW7L/`S7 _SL^^^#^-^7^A^JL)L"^>L)L"^2"L)L"^& L)L"^ L)L"^ L)L"^9L)L)L!zrr9L)L)L%zrr9L)L)Lzrr9LLz9LLz9LLzLL9L)L)L?zrrL^^=^\^^^^QLUL LLLLVLLLL-LV^~QLULLL-LVL L숥^]QLULL)L9VL LL)L9V^3QL L숥^&QL L}L)LkVL ^ QL^rLLL9LLL)L#LL VLrL LL9"r LYL*rLf)*L-**L-L-LVFr***LFr*LL"rULLVLrLL!f -*^^^j*LLVl^6LLf LaLw fLLL9V^ ^L/*LL*LVL!f'*fL L-L=V**LL)LV襥rLLL!b L%b"^l& L9L=LVL LL*^OQL)ULjQL=LVl^/LLf LaLw f L^ ^L/*9^LLLLL9LL' va-LL!fL*LUL%zL)^#^^LLLL=VLL%zL)9rLLL!b L%b"^) L9L=LVL LL*^wQL)ULj9UL=LVLLLLL L*LVL!f^ zRl^/LLf LaLw f L^ ^L/*9^LLLLL9LLL* va-LL!fL*LUL%zL)^#^^LLLL=VLL%zL)9rLLL!b L%b"^, L9L=LVL LL*^kQL)ULj-*L=LVLL*LVL!f^l^/LLf LaLw f L^ ^L/*9^LLLLL9LLL- va-LL!fL*LUL%zL)^#^^LLLL=VLL%zL)9rLLL!b L%b^`9L L=L*^OQL)ULj*L9LVl^/LLf LaLw f L^ ^L/*9^LL-L-L9LL/ vaL*LUL%zLLLL)QLLLLLLrVL)LL-LLrVzRrL ^^^^ ^ ^ ^^^^/^-^+^(QLL9^^*LL9^^LL!f^L ^^^^^"^,^A^Q^y^^^^ LL*^ LL*^sQL-L9LL2^\QL-LL92^JQLULL9L)LVb LL9:^ UL*LL9L)L:^r)L)L9Vf)L)L VLL=V)L)Ll)L!f"Lf )L^)LL^Lf )LrLL?f:QL!f,QLULLLL VL VLL9R^^^^^LLrL ^^^^^^^^^^^^^^^^ ^^^L ^^^/^0^:^D^Y^i^^^QL-Lf)LL^^ L L*^v L L*^jQL-L9LL2^SQL-LL92^AQLULLL9VL9L)L:^UL-L9LL2^r9L)L)L=L4r9L)L)L=L4r9L)L)L=L4r)L)LVL!f_L-LLfQLLLLL9V_^^Lf QLLL)LL9V_g^^LfLLLL=V_F^^LfL-LLL=V_'^^L%f(QLLLLL=VLLV_^^L%f(QLLLLL=VLLV_^^LfLfQLUL)QL-UL-L)LVL!fSj L L9L7 vLLL~Vl^0LLf LaLLL)LV^ L/*R_:^R^^^*LLfLj LL L L9Vl^0LLf LaL)LL)LV^ L/*_^^^^Lfb*LLfLj L LL L9Vl^0LLf LaLL-L)LV^ L/*_g^^^^LLbLb_3_/LfQL)UL-QLUL-LL)Lfdj. L L9L8 vLLL~V LLL L9Vl^0LLf LaLLL)LV^ L/*R^^R^^^^LfxQL)QLLLLfSj L L9L9 vLLL~Vl^0LLf LaLLL)LV^ L/*R^(^R^^^^-L-L VL)L:r9L)L)L=L4r9L=LL-LL5LLf@QLUL9L=LLLLVLLLL%zL)LVR^4^^9L=LLLLVLLLoL)L;rL^ __,__QLUL)*L)LLL!b L%b ^'^#QL L L L-L L9VL^LL-L-LL=VLLLg7UL*LL)LLL!bL%b^^^ZL!f ^^^G^CUL!f2L%f#QL)QLLLL%zR^y^^ ^^^L%f?QLf/LQQLLL)Lf R^/^R^^^^^; LLLVL L LVLLL LLLrVL L)LrLLVL L LL< vLLL~VRR^^^ LZLrR_+QLj LLVl^YLLf LaLw f7f= L)L LLVLLL-L)LV^ ^L/*I^QLL!bL%b^J^F L:LV^^6QUL!f$QQLLLL-LL9VR^j^^^QLLLLLL9L> vL)LVLJ^2LLLLLL9LL? vaLL)J^rL^^/^K^g^^^__QLLLLLLK_QLLLLLLK_{QLLLLLLK_]QLLLLLLK_?QLLLLpLLK_!QLLL)LL9VLLLLLL)LrVL)LLLVLLLLkR^QLLL)LL=VLLL)QLLLL)LLL!bLb^'^#^8^QL LLLVR^!^ LLLL%zLLVLrVL-LLLVLLLLsR^!QLULL)L)LL\^rL^ ^^^)^2B L)L"^&C L)L"^D L)L"^E L)L"^LLVLLfQL%fQQLLbLb)Lb<^f^ZQUL!f G ^T^^L^@QUL!f H ^:^^2^&QUL!f-f I ^^^^^^^^^^J r9L=LLVLLL#LL9-L-L-L-LL vLLLLbLcfLc*LlcLcLcv Lc Lc L7c L8c> L9cp Lc Lc Lc Lc# Lc@ Lc] Lcz Lc L:c L;c L<c LcR _ _ LLLL9VLLL9VL^ ^W^^_^ ^^^ ^>L^5L^,pL^#LLLLL=VL^_H^ ^^^ ^>L^5L^,pL^#LLLLL=VL^^^ ^^^ ^>pL^5pL^,pL^#LLLLL=VL^^^ ^*^I^h^LLLLL=VL^yLLLLL=VL^XLLLLL=VL^7LLLLL=VLLLLL=VL^^_& _ LLLL9VLLL9VL^ ^W^^_^ ^^^ ^>L^5L^,pL^#LLLLL=VL^_H^ ^^^ ^>L^5L^,pL^#LLLLL=VL^^^ ^^^ ^>pL^5pL^,pL^#LLLLL=VL^^^ ^*^I^h^LLLLL=VL^yLLLLL=VL^XLLLLL=VL^7LLLLL=VLLLLL=VL^^_[ _D LLLL9VLLL9VL^ ^W^^_^ ^^^ ^>L^5L^,pL^#LLLLL=VL^_H^ ^^^ ^>L^5L^,pL^#LLLLL=VL^^^ ^^^ ^>pL^5pL^,pL^#LLLLL=VL^^^ ^*^I^h^LLLLL=VL^yLLLLL=VL^XLLLLL=VL^7LLLLL=VLLLLL=VL^^__yLLLL9VLLL9VL^ ^W^^_^ ^^^ ^>L^5L^,pL^#LLLLL=VL^_H^ ^^^ ^>L^5L^,pL^#LLLLL=VL^^^ ^^^ ^>pL^5pL^,pL^#LLLLL=VL^^^ ^*^I^h^LLLLL=VL^yLLLLL=VL^XLLLLL=VL^7LLLLL=VLLLLL=VL^^__LLLL9VLLL9VL^ ^W^^_^ ^^^ ^>L^5L^,pL^#LLLLL=VL^_H^ ^^^ ^>L^5L^,pL^#LLLLL=VL^^^ ^^^ ^>pL^5pL^,pL^#LLLLL=VL^^^ ^*^I^h^LLLLL=VL^yLLLLL=VL^XLLLLL=VL^7LLLLL=VLLLLL=VL^^__LLLLL=VLLLLL=VL-__LLLLL=VLLLLL=VL-__qLLLLL=VLLLLL=VL-_O_8LLLLL=VLLLLL=VL-__LLLLL=VLLLLL=VL-__LLLLL=VLLLLL=VL-__LLLLL=VLLLLL=VL-_k_TLLLLL=VLLLLL=VL-_2_LLLLL=VL-__LLLLL=VL-__LLLLL=VL-__LLLLL=VL-__LLLLL=VL-_~_gLLLLL=VL-_Z_CLLLLL=VL-_6_LLLLL=VL-__LLLbLb,__LLLLL=VL_(^QL)ULL)LVLLfQLjLM LLVl^2LLf LaLw f LLV^ ^L/*LLL)QLLLVL!fN LLO L LLLVL LLLL=VL R^^^ LLVR^Q^LP LVLLL LL)L LL=V LL-L LL=VLR^^LQ LVLLLLL)L LL=VLL-LLL=VLLL LLLVLLL LL LL%zL%zLVL-LLVR^^R LL L-LJr9L=LVLLL#)L)L)LT vL-LLLbLbLLIb{Lb^^LP LVLLLLL)LLL9VLR^^LP LVLLLLL-LLL9VLR^^LLLLL9VL-^r^dLL=VLLL!bL%b^ ^L^0^L^#^LLLLL9VL^^ LLBrLf9LL=L-LzL9L%z=L=L%L^ ^W^i^QLULLLLLL9VLLLLLL L LL L=VLLVL)R^QLLL^lQLV LLLLLLLL9L)LVLLLL!LLLLW vL-LV L)LVLR^rQLL)L9LLLL)LVLL9LLLLL%zL9LLVLL%zRrQLLVL!f L-LL!f+LLLLLLmVLzVLL%z^^^LLLL-LVLLLLL)L)LL9LLVLLLL!b L%b ^^ QL^L)LoLL!f^5^^LLY LL LL%zL)LVLLL|LLLL!b L%b^& L^QLLLL-L L=V^L LLLVL)LVL LLLLLLLLLzLQL%zF f LL)LVLLLf^L LR rLL!LLsLLgcL)LVL-g*-LLy^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~^|^z^x^v^t^r^p^n^l^j^h^f^d^b^`^^^\^Z^X^V^T^R^P^N^L^J^H^F^D^^@^>^<^:^8^6^4^2^0^^^^(^^$^"^ ^^^^^^^^^^^ ^^^____"_L__L_^L_^L^^L^^L^^L^^L^^L^^L^^L^^LLLL%z^^LLLL%z^^uLLLL%z^o^^LLLL%z^X^GLLLL%z^A^0LLpLL%z^*^LLLL%z^^[ L LL9V^LL%f L^^^)L-L%_)f[ L LL9V-LLL!bL%b^+^'^6^UL!fQLR^!^^^LLLoLZRrLL9LL-L=3R*L*L)*L-*LULQLLL9L=L9*L-Lf+9*LLVLf] LL^ Lt9LF9LL_ vLLV9LLVL9L-LV9L)F9LLLVL)LVL9LL)L LVLLL LLVL)L LVf9LLLVLLRRLLf9L=L-Lj3RQLLLVL!fFL)LF)L9L=LLLLL` vL)LoLVL-L)La vLL2RL)L9L)LL-LQL=V9L-LVLLL)LL%zRrL9L촥L-LLL%bL!c__L%gQL)UL-QLULL)LVLLg<QL%g.QQLj gQUL!gUL%gUUL!fUQLLL!fAQLf3QQL9LLQL=VL9LL)L QLV^^^^^LLVLLflQL%f^QQLj fOQUL!f?UL%f1UUL!f!UQL9LLL QLV^-^^^^^^^^ ^^^^k L LQLV^2^^^^^^^^ ^^^^9LLLLLVLL L%zLLL-LLVR^󥥥^^b^^L!f"LLoLVL-LLV^^^LLLoLVL9L)LLVLLVR^^L!fpLL-LVLLf@QLULLL LoLVLLLVLLLLVR^^^l L LLV^^^ LLBr9LL=L)L)LVQLL)LL9L=LLLVL)f^L=**L-L-L-LzLVL)LzRRLLLLL!b L%b ^ ^QLL9L=L-LLV^L=*UL)L)LLVL)RL9L촥LLL!b L%b?^-Lv L9LVfw LL L=L2^LL VL=L2^eQL)QQL-ULL-fL)R^D^R^QL)ULLLVLLLLL)L%zL)R^rLLL9L=VLLL9LLLVLLLL-LLVLRRLz LL{ L L9L="LLLf^^^L} LL"9L9L%L=L LVL=L)L=L-LiLVLLVL9L"LLLbLb^V^RQLL9R^K^?QLjL=LVl^$LLf LaL^L/*R^^LLLL^+^A^___&_5_=____9__k _ _ _M _ __)_QLLL)LL9T_sQLL!b L%b^LLLLK^QQL)QULL=LL-LVLLLLc vLLL-LL%zLLVLLL L LLVLoLLL LR^_ QLULL)LVLLLVLLfjQLj#Ld LLVLLL)QLRl^;LLf LaLw f-LL VLLV^ ^L/*^:^^L-LLVLLL)QL LLLLLVRLL-LyVLLLcR_ QL!gQQLLbLc@__QQQLLe bLf caLg cR__)UL%gC)UQL!g/)UQQLLbLbR_k_ -UQQULf-UUL!ft-UQQQLUQQUQLUQLLL LLLLL%zLVLL VL UL%zFLLL)LVR_ ^R_^R_^o-UUL!f\-UQQQLUQLLL LLLL%zLL VL UL%zFLLL)LVR_g ^R_a^^R_W^R_Q^)UL!f])QLLL)LLLLLLL L LLLL%zL%zLVLVR_ ^R^^T)UL!fC)QLLL)LLL *LLLL%zLVLVR_ ^R^^^QQQLh fsUL%fcUUL!fQUQLLLVLi LLLLLLVLzL{VLLLLVR_ ^^^^^^ ^^^QLULL)LVLLL!fLLLLL%z^^^)LLLLVLL-LVLLfKQLULLL L LLLLLm vaLLLLLVR^R^^LL Ln LLVL)LVL LL)L LVLLVL)L LRR_QLULL)LVLL)LVLLLL-LLVLLVLLL LL-LLLVLLVLL L{R_o L L-L:_u*LL!b L%bn^QL)ULL)LVLLLL-LLVL)LVLLLL-LLVLLLVLLLkR^QL)UL-*QLL-LVLLLL-LLVL-LVLL-LVL LL-L-LLV)L)L)LLVL)L L{R^_kQLUL)*L-*L*L L LLLLLL LzL/VLL襥_QLUL)*LL-LLLVLLLVLL m_QLULL)LL-LVLL \_QLULL)LVLLLLLLLVLL)L)LLLVLLLcR_gQLL!bL%b ^a^]LLLLV_8^EQUL!f3QQLLLVLLLL)LLVR_^^^QLLLLVLLLLp L-LVLVLLS_QLUL)*L*LL%f.QL*f!UL!fL-LL%z^&^^ ^^^^LLLLL%zLVLjg *LLVLLL)QL LLVL!f*L LVLL Lfq L L LLVLLzRl^LLf LaLw f*QLLVfr LL LLVLLLLs vLLVL-LLLVLL *QLL)LVLLVL!f *LL-LLzLVL-L)zR^ ^L/*LLL)QLL^ ^ ^%^R^~^zQLL-LL-LLV^`QL)L L LLLt vLLVL LLV^1QL)L L LLLu vLLVL LLV^L-LLfLLVL!f^  L-LLL-LV L!LLjV-LLL LR_1QLULLLL!b L%b ^$^ QLLLL L-L LV^L*UL-L)LLV)LLqVLLL[_QLj Ll^'LLf La LGLV^L/*LLLL)LLVLLL)QLL-LVLLfQL^^^ LKLVLLLL-L LLLLx vaLLLLLy vL LVL LL| vL-LVLLLLR _QLULL)LVLLL!f^^^~ L-LVLL)LLLVLLL)QLf)f L L LVL)LLVLL LR_IQLULL)LVLLL-LLVLLL)QL LLL LVL)LVLL L{R^QLULL)LVLLLLL vLLLLLL va)LLVL-L)LLkR^QLULLL-L-LVLJ^gQLULL)LVLLLL-LLVL)LVLLLL-LLVLLnVLLLcR^RrLLL!b L%b^*9L^ QLLLL9L-L=LV^L9L-L)LVrLLL)L9*RLLLLLLbLb_1_-QL)ULL9LL=VLLLLL vL-LLL!bL%b^C^? LLV^K^/UL!fQL)QLLLVR^(^^^ L)L LLVLVL LLLLLVLLVL-LVLLLVRR^i^PQLfBUL)*L-*L*LL LLLLLL LzL/VR^%^^^L9LL=BRr9LLVf L L=LV9L9L)LVjLLVl^RLLf LaLw f0LLL-L)LV-fL-L)LV^ ^L/*!rL9L촥LL9L L=LLLLLzL/VLLLj#L LLVLLL)QLRl^:LLf LaLw fLL VLL V^ ^L/*LL-L)LLL VLRR9QLLL^ ^P_._7QL9L L=LLLLLzL/VLLLL)LL-LLVL9R^QL%fhQUL!fXQQLULLLVLL-LVLLL-LQLVQLLL)LvLVRR^^^^^QLULLLVLLL-LVLLL)LVL-LQLVL LLVLL)QLL-LvLJR^ LL"^LLL)L9LL L=L vLL^^9^_^_"__a__)QL-LLf  L^ L)LV_QL-LL^^^#^+^3^;^E^O^XQL^NQL^DQL^:QL^0QLp^& LLV^ LLV^ LLV^_QL%fRQUL!fBQQLL L L L L LLzL/VLLLLL)R_1^^^^QL/n;$L L L L L L LzL/VLLVLLLLLL L-LVR_QLjLLl^'LLf La LLV^L/*L LLLVLLL)QLL-LVLLf;QLLLLLLLL LL9LL v LLV^^^ LLVLLLvLuVLR_QLUL)*LLLL!b L%b^TL^KQLLL LLLLLLzL/VLLLLL)LLR^LLL LLL LVLLL)QLLLL!f[LL!bL%b0^G^?L LLVLLLLLrV_^ L LL9V_^^^LL!b L%b_ L LL9V_QL)QLLLLLLrVLL)LLrVL LL%fQLLbL!bp^^QQL)QLLfILLLL%zLLVLLL-LLLL%zLLR^^R^4^(QQLfQLL R^Y^^ ^^^LLfQLLLLV^!^^LLLL%zLLVL LLL-LLfQLLLLV^!^^LLLL%zLLVLLL-L LV LLLVLR^R_0QLULL L L L LLLzL/VLLLLLVL L-L)LLLVL)LVLR^QLULL L L L L LLzL/VLLL L)LL LLL LVL LVLLVL)R^lQLUL L LVLLL LLL L L LLLL L L v LLVLL)L VLLVLR^LLLLL)RRr LL L L9L=LL9L L=LLLLLLzL/VLLLfLL^8-LLVLLLVLLL vL)L)LVLVRL)LLLVR9L)L)L=+rQLL)LLLLLL9L)L=LLLLLLL v LLVL=LL=LL vLLVLLL!b L%b ^2^.QL=LLVL=LLL-QLVL^L=LLVL=LL L-LLV=L-L VLLzRRLL%fQLLbL!b^^QULfQQL)QUQL-UL9L-L-LL=VLLL)QLLLVL!f^8L)LVLLfQLL L^^^ LHLVRR^^^^ ^ ^^^-LL9LL-L=LLLLLLLL v L-LVLLLL vL-LVLLLLL-zRr9LL)L9L%zr9LL-L9L%zrLLLL*LL%zLVL!b*LL*LL%zLVf^LL*LL%zLL%zLLL L*LVL L*LVLLzRLLL!b L%bc^j#9*L}L=LkVLVLLl^;LLf LaLw f LL LLV^ ^L/*)^MQL)ULjLLLLVLl^$LLf LaL^L/*9^L LVLLLLLLL9LL va*L1RrL)L9L-L=VLLL)LL%zRrj*LLVl_LLf LaLw g-L-L-L9VLLLj  *LL*LL%zLVLl^9LLf LaLw f*L-*L^ ^L/*LLLLLL-LL%zL L *LLLf *^. LLLLLLLLLLLLzL*L*L*Lz L*LL)*LVLL}LLLL%L!LwVLL=f  LL{VLL%fQL%fuQQLQUL)LL-LVLLL vLLL-LL%zLLVLLLLLoLLLLVRR^^^^^-L)LVL=f  LL{V-*LF-L*L)L*V-*R ^ ^L/*)r9LLLLLxVL=VL!r9*L9**L-L-LVFr!LLL LLLLL*LL%zLLLLLLLLLLLLzLLLLLLz LL9L vLL LLLLLLLLLL%zL%zLLVL LL%zLQ LLLLLL LLL LLLLQ LmVLL%zL%zLLLLL%zL%zLLV@L-LLLLL%zLLLVL)V)LL*LL%zLL=VL-Rr 7X7Y|7Z7[7\L/`S7 _ L^^^'^1^;^E^O^Y^b_L)L "^V L)L "^JL)L "^>`L)L "^2L)L "^&bL)L "^ L)L "^ L)L "^9LL!z9LL%z9LLz9LLz9LLz9LLz9LLz9L)L)LzrrL ^^%^/^9^C^M^W^a^k^u^^^rL)L "^uL)L "^zvL)L "^nwL)L "^b|L)L "^V}L)L "^J L)L "^>L)L "^2 L)L "^& L)L "^sL)L "^ L)L "^L^+^5^?^I^S^]^g^q^{^^^^^^^^^^^^L)L "^L)L "^L)L "^L)L "^ L)L "^L)L "^L)L "^L)L "^L)L "^L)L "^zL)L "^nL)L "^b L)L "^V L)L "^J L)L "^>L)L "^2L)L "^&L)L "^L)L "^L)L "^9LLz9LLz9LLz9LLz9LLz9LLzL^ ^^^)^2 L)L "^& L)L "^ L)L "^ L)L "^9L-L-L-L!zrr9LL%z9LLz9L)L)LzrrL^ ^^^)^2 L)L "^& L)L "^ L)L "^ L)L "^9LL%z9LLz9LLzL^ ^^^& L)L "^ L)L "^ L)L "^9L)L)L!zrr9LL%z9LLzL^ ^^^& L)L "^ L)L "^ L)L "^9LL!z9L)L)L%zrr9L)L)LzrrL^^^'^1^;^E^O^Y^b% L)L "^V& L)L "^J' L)L "^>( L)L "^2) L)L "^&* L)L "^+ L)L "^, L)L "^9LL!z9LL%z9LLz9L)L)Lzrr9L-L-L-Lzrr9L)L)Lzrr9L)L)Lzrr9L)L)LzrrL^ ^^^& L)L "^ L)L "^ L)L "^9LL!z9L)L)L%zrr9L)L)LzrrL^+^5^?^I^S^]^g^q^{^^^^^^^^^^^^L)L "^L)L "^L)L "^L)L "^L)L "^B L)L "^L)L "^L)L "^L)L "^C L)L "^zD L)L "^nE L)L "^bF L)L "^VG L)L "^JH L)L "^>I L)L "^2L)L "^&J L)L "^K L)L "^L)L "^9LL!z9LL%z9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L-L-L-Lzrr9LLLLLLzrr9L-L-L-Lzrr9L)L)L zrr9L)L)L zrr9LL z9L-L-L-L zrr9L)L)L zrr9LLz9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9L)L)LzrrL^^^3^B^I^]^d^k^QLL !^QLLL L^iQLf^^XQL^OQLLL L^9QL^0QL^'QLUL}L)L VL}LL9𭈥^LL!f^^^}L-L VL}L)rL ^^^^!^#^%^'^)^+^-^/^1^2^. ^*3^& ^"4^^w ^x ^y ^z ^  ^{ ^L^+^-^/^1^3^5^7^9^;^=^?^A^C^E^G^I^U^a^h^w^^}'^y}^u-^qA^m&^i^e^a^]^Y^U} ^Q^M~ ^I ^EQLL9!^7QLL=!^)QL^ QLLL ^QLL숥^ 7 U7 F7 7  #K7  #iW7  #C7  #(07  # 7  #7  LL 7  L ?7L 7  L ?,L 7  L ?J+L 7  L ?|5L 7  L ?L 7  L ?вL 7  L ?ϱpL 7  L ?̨g LL!7  L ?ǖAL%7  L ??L7  L ?-L7  L ?8gL7  L ?!@L7  L ?NL7  L ?7L7  L ?%PL7  L ?.7L 7  L ?9L 7  L ?L 7  L ?/l LL!7  L ?4L%7  L ?L7  L ?i3L7  L ?L7  L ?L7  L ?b L7  L ?e9L 7  L ?4wL7  L ?"P=L 7  L ?)L 7  L ?L 7  L ?8L 7  L ?xL 7  L ? L7  L ?[L 7  L ?CiL 7  L ?nN L 7  L ?-L 7  L ??L 7  L ?q& LL 7  L ?%L 7  L ?1L 7  L ?L 7  L ?D\ϥ LL!7  L ?GAL 7  L ? ^L 7  L ?L 7  L ?Х LL 7  L ?iT++L 7  L ?s&L 7  L ?( LL 7  L ?=.#L" 7!  L! ?(O9L$ 7#  L# ?/ܥ- LL/ 7.  L. ?3L1 70  L0 ?FL3 72  L2 ?'L5 74  L4 ?61L7 76  L6 ?%L9 78  L8 ? K1L; 7:  L: ?*L= 7<  L< ?vĥ> LL? 7  L ?=.#L@ 7!  L! ?(O9LA 7#  L# ?/ܥL LLN 7M  LM ?N+LP 7O  LO ?LR 7Q  LQ ?5`*LT 7S  LS ?K9LV 7U  LU ?\LX 7W  LW ?O-LZ 7Y  LY ?4L\ 7[  L[ ?}L^ 7]  L] ?#oL` 7_  L_ ?)Lb 7a  La ?' Ld 7c  Lc ?Lf 7e  Le ?]Lh 7g  Lg ?MLj 7i  Li ?@\ Ll 7k  Lk ?,Ln 7m  Lm ?-Lp 7o  Lo ?%Lr 7q  Lq ?Lt 7s  Ls ?, LLLLu av L| L)LL vL L?"7> L-?1m L)?': L? L?]UR  7]L/`S7 _eL^ ^^^& L)L "^ L)L "^ L)L "^ L.L "rLL9"rL L VL!f^L L VL!f^ LL "rLL LL "rLL%fPQL!fAUL!fQL^=^^QLULLL)L9VL VR^^^^^)L)L *rLL "rLL f4QLUL)*L)L)LLLL9VL VR^(^^LLf^LL)L CrLL f4QLUL)*L)L)LLLL9VL VR^(^^L-L!f^LL)L CrLLL9LRLLLL^^$^0^E^g^^^^QLL L ^QLL ^QL9LL VL ^QLUL9L L)L VLL V^QLUL)*L)L)L)LLL!b L%b ^ ^QLL9L ^L V^PQLULLL9L V^4QLULL9LL V^QLULLL V^RLLL bL b^ ^^^*LL9R^ ^L^^ ^0^@^P^`^p^nQLL ^j^\QLL ^X^JQLL ^F^8QLL ^4^&QLL ^"^QLL ^^ L~L "L)LLL!bL%b^%^!L!f  ^'^^^  ^^L%f ^^^ rL)LL!f^^^L!f ^^^ rLLLLbL!b^ ^ULL9R^^ ^^L)LL LL-L%zRrLLL!b L%b^' LL 2^ULL LL L%z^rL L)L L%zrL9f=^3f LL V^ LL VL LL-L%LL%zLLL!b L%b^T LL B^HQL)ULLLL-L LLL va!LL LL L%z^rL L9L)L=L VLL%zr)LLL!b L%b^I LL B^=QL)ULLL vLLL L VLL LL L%z^rj"LL VLLLL9Vl^ALLf L aLw f L)LLLL%z^ ^L/*1r LLL L-L%zrL9LLL!b L%b ^8 ^4QLLLfQL^^^ L)L L%z^LL%g9QL%g*QQ^^ ^ ^^^`^__ QQQLQUL)QL-ULL9LLLL)LL=LLVLLVRR^ڥ^QQQLQQUL)QUL-QLUL LL=LLVL LLL%zL)L%zL9R^w^OQQQLQUL)QL-UL L)L LLL%zL)L%zL9R^(^^^^^LLLL LLL!b L%b^P LL *^DL)LQLULLLLL9L=LLL vaLI^LLL!bL%b_@_< L9L L z_>_'QLL!bL%bR__  LL VR__)QQ^^^x_R__{__-R__)QQQL-QULQLULL=LLL)QLLL9LLL LLL LVzRR__p)QQQL!fW)QUL-QLULL=LLL)QL9LL)L LLLVLLzRR_-^^)QQQL-QULQLULL=LLL)QLLL L9LL)L LL L L VLVLLzRR__)QQQL-QQULQULQLULL=LLL)QLL9LL LL)L LL L L VL L VLVLLzRR_1_ )QQQL-QQULQQ*LQULQLULL=LLL)QLLLLL L9LL-L L L L VLLL L VLVL)LzRR__g)QQQL-QQULQULQLUL LLLL VL LLL%zL)L%zL=R_'_)QQQL-QULQLUL L)L LLL%zL)L%zL=R__)QQQLL%bL!cR__-QQQQLL!bLbR_y_QQQQQLQQQULQQULQQLQULQLULL=LLL)QL LLL VL9L%zL L)LL L L L L LLL%L VL L%zL%zL VLLzRR __)QQQQQLg,QQQQQLQQQQULQQQULQQULQQLQULQL ULL=LLL)QLEL L L LL VLL VL LL L L LL VL VL L-L9L%zL%zL L-LL L LEL L L LL L LLL!L VLL%zL%zL%zL VL)LzRR _^^QQQQQLQQQQULQQQULQQULQQLQULQL ULL=LLL)QL LLL L LL VL VL9L%zL L)LL L L L L LL!L VL L%zL%zL VLLzRR ^^^w-QQULQQLQULQLULL=LLL)QL9LL)LL LL VLL VLLzRR^-^^^^L L9L)L zLLL!b L%b^i LL *^]L)LQLULLLL)L9L=LLLLL LLLL L L vaLI^LLL!b L%b^z L L z^nQL)QL-ULL9LLL)QLL=LLL)QLL)LVLL)L VL LL LL%zzR^LLL!bL%b^^ L L9z_^oQL!f]QL)UL-L)L=f.L)LLLL)QLLLLLVzR^  L)LzR_t^^^L!f LCL V_O^^L%fQL%fL%fQQLLf)LLLLLLLL)QLLLLL)QLL L VL!f LLLL VLz^/L L VL!f ^ LL)L VLLLVzR _^^^^ ^^^^L%gcQL)LLL!f"L!fQLL_+^^^^L!f\LQLLLLL)QLLLLL)QLLL)L VL LL VLLVzRR^ĥ^^L!fLQLLLLL)QLLLLL)QL LL VL fL L VL!f# LLLL VL LL Vz^,L)L VLL)L VL LL VLLVzRR^^^ L\L V^^^ L_L "9L L)L L%zQLL)L)L9L)LLL!b L%b ^)^QLLL=V^LL L-L BRR9L=L vL)L VL L L L L%zLLLLLL)QLLLL!b L%b^B^?QLL!b L%b^$ LLV^)QQL LLV^^)L)L L VL!Rr 7 |7 7  7 7  #JEA 7  #K7  #в7  #>37  #7  #n7  #F7  #77  #F7  #*7  #-;7  #M7  #cV7  #}w7  #e7  #կ7  #617  #E7  #{7  #-q7  #^_7  #O177  #\7  ##{!7  #h7  #v7  #+7  #l7  #7  #7  #j 7  #r9&7  #!|7  # 7  # K17  #7.7  #!v7  #iW7  #o7  #d<7  #}7  #%7  #MR7  #b 7  #[ 7  #'7  #ȩ7  # r7  # S7  #7  #7  #?7  LL!7  L ?_'L%7  L ?a7L7  L ?գu L LL L L L L LLLL a LLLLL-LL -2)L-L )2L)L eLL a L L LLLL a L L L L LL L L LL L LLL vLL LLLLLL LL LL v LLLLL-LL veLLL-LLLL LLL LL!LL v aLL)LL vL L?S2 L? L?QD& L? L?< L?׬ L?! L ?.)j L ?h L ?LL\3 L ?[  L?9V L?f L?i L?1( L?7 L?C< L?o$ L?ī L?Jp L? L?=p L?n L?) L? L)?)Dd! L-?]K L? L? L?qY}  L ?_ L?StR   7_7aU7b47cF7dL/`S7 _4 LLL!b L%b^L-L *^L-L *^9LLLLL%zrrLLL!b L%b ^!^ *L^)L)L)LL9LL9L VL%L ^GQL)UL-*LLLL=VL)L)LLL=VL=^ L=L r^^ L?L J^^L)Lf)LLL%b L!b^QL)UL-*LL9L-L9fLLL=VL)L)L=k^b)LLL%b L!b>^GQL)UL-*L L LL=VL)L)LLL=VL=^ LIL r^^ LKL J^^LLLLL VL%L LRrLLL!b L%b^W LTL *^KQL!fUL)*LR^5^^QL)UL-*L)L9L)L)L=K^LLL!b L%b^I L ^@QL!fUL)*LR^*^^QL)UL-*L)L9^L)LL!fL^6^^L!fL^^^)L)L9L-L=L3rLLL!b L%b^} LL L%L L^kQL)UL-*LL)LVLL!f^=L!fLLL9VL-L-L=c^-L-LLLL9VL=c^rL-LL!fL-L-L9V^^^L!fL-LL9V^^^L%fL%fQLUL)*L-*LQLUL*L*LLLf LL LL L L=VLV^8LLf  L L LL=VL-L-LV^ L L LVR^$^^^^ LL :rL)LL!fL^9^^L!fL^"^^-L-L-L9LL=LDrLLL!b L%b^L L z^QL)UL-*LL)LVLL!f L)Lz^pL!f7LLL9VLLL)QLL L)LLL=VLzR^4LL-L9VLLL)QLLL LLLL=VzR^rLL-L9VL)r L L LL!f^^^LLL!b L%b^B^?QL)UL-*L9L)L=VLL!bL!f-^LA^LL)LL-L va)L!rLLL!b L%b ^l ^hQL)UL-*L9L)L=VLL!f-L)LJ^1L!f-LL-L-LS^-L-L-LLS^LL)LL9LL=L va)LL-rL)LL!fL_5^^L!fL_^^L%gL%fQLUL)*L-*LQLUL*L*LLfWL%f9L-L L=V^?9LL LVLLL)QL9L LLVL L LLVLVR^VL%f9LL L=V^?9L-L LVLLL)QL9L-LLVLL-LLVLVRR^$^^^^ LL *rLLL)L9L=LLL va-L-L)VL)RrL)LL!fL ^^^L!fL ^ե^^L%fQLUL)*L-L9L-L)L=VLLLbLb9^k^gL)QL9LL-LVLL-LVLVR^H^6L)QL9LL-LVLLLLVLVR^^ LL VR^^^ L L *rLLL)L9L-L=LL va-L-L)VL)RrL)LL!fL ^^^L!fL^ե^^L%fQLUL)*L-L9L-L)L=VLLLbLb<^k^gL)QL9LL-LVLLLLVLVR^E^3L)QL9LL-LVLL-LVLVR^^ L L VR^^^ L#L *rLLL)L9L-L=LL va-L-L)VL)RrLLL!b L%b^0^-QL)UL-*L)L9L=L99^LLLL vaL!r 7 7  #i7  #K7  #&]7  #F7  #7  # S7  LL!7  L ?mL 7  L ?"63 LL LLL vLLLL)LL veLL aL)LL vLLLL)LL veL)L)LLL va-LL)L vLLLL)LL veLL a L L L LL L vLLLL vLLL L vLL L L vL L L?e& L ?n L?c L?D L?H L ? L?9V L ?3e L?ſ L?8 L-? > L?L L?? L?: L)?\i L?f L ?  L?ͱJ L ?x L?!IR  7eL/`S7 _`OLLL!b L%b^[ L-L? *^\ L-L? *^9LL!z9LL%zLL? 9L)L)LL4zrrLLL!b L%b^!QLe LL+ ^QLf L숥^LLc VL9 rLLLbLbLbLbLbLbLbL<bLbLbLbLbLbLbLbLbL:bL;bLi bLbLbLbLbLlbL8bL7bL9bLbLbLbLb^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^z^x^r^p^j^h^b^`^Z!^X^R!^P^J%^H^B%^@^:^8^2^0^*^(^"^ ^^^^^ ^^L9LL9LLf^Lf )L^RrLLLLLfaQLUL)*L)LL9Vf<LL-L=VLLQ L)LQ LVLL)LL# VR^6^R^ ^^LQ LLQ LVLLLL# VRrLLLLLfAQLUL)*LLL9VL-L LL L=VL-L# VR^#^^L)L9VLLL VRrLLL!b L%b^o-L; LLA L: V^[QL)ULL6 LL0 LL0 LLL9VL; L%zL%zL< LL; LL-LN L: VR^rLLL!b L%b^h-LL7 L ^UQL)ULL6 LLLL7 L L0 LL0 LLL9VL; L%zL%zL& V^rLLLbLbLIbLb^"^^^^^^^ ^^L` LL9rL)rLLJ Lj L9l^$LL! f L-LJ f^S^L/*Lj L=l^%LL! f )LLJ fR^^L/*L0 L)L)L%zR^L!LL VL%fSL!LL VL)L%L@ Vj L=l^%LL! f )LLJ fR^L^L/*LR^E^^L!LL VL!f!L!LL VL)L%L@ V; R^^^! L/&]!LLJ LL!LL VLfL!LL VL)L%L@ Vj L9l^%LL! f )LLJ fR_ ^L/*LLLJ LL!LL VLf1L!LL VL)L%L@ V-LL)L=VLVR^K^^L!LL VL!f)L!LL VL)L%L@ V&LLVR^^^! L/&]R_ ^^L!LL VLgOL!LL VQL!g8L!LL VL)L%LL VLg)L%LL VQLf)L%LL VQQL-L%LL VLLL@ Vj  Ll^%LL! f LLJ fR_W ^L/*Lj  Ll^%LL! f LLJ fR_& ^L/*Lj  Ll^%LL! f LLJ fR_ ^L/*L0 L-LL-L%zLLP VLL)LQ L=VLVR_ ^^^^ ^^^^L!LL VLgL!LL VQL%gL!LL VL)L%L@ Vj Ll^%LL! f )LLJ fR_9 ^L/*L-L!LL VLgI-L!LL VQLg/-L!LL VLL%L@ Vj  Ll^%LL! f LLJ fR_ ^L/*LLLJ LL!LL VLfL!LL VQLfyL!LL VL)L%L@ Vj  Ll^%LL! f )LLJ fR^j^L/*LLL)LN L> VLL)LQ L=VLVR^=^^^^L-LA L> VLLLQ L=VLV^ ! L/&]R_^R^^R^^^^^L!LL VLgL!LL VQLgL!LL VL)L%L@ Vj Ll^%LL! f )LLJ fR_f^L/*Lj Ll^%LL! f -LLJ fR_5^L/*LL!LL VLfL!LL VQLL!LL VLL%L@ Vj  L l^%LL! f LLJ fR_^L/*Lj  Ll^%LL! f LLJ fR_^L/*Lj  Ll^%LL! f LLJ fR_l^L/*LLLL-LL, VLL)LQ L=VLVR _>^R^^^^^L!LL VLg"L!LL VQLg L!LL VL)L%L@ Vj L l^%LL! f )LLJ fR_^L/*L-L!LL VLf-L!LL VQLf-L!LL VQQLL!LL VLL%L@ VjL L Vl^%LL! f LLJ fR_8^L/*LLLLL-L$ VLL)L=VLVR_^R^^R^^^^^L!LL VLfL!LL VQL fL!LL VL)L%LL VLf)L%LL VQLf~)L%LL VQQL-L%LL VLLL@ Vj  Ll^%LL! f LLJ fR_C^L/*L)LL- VLL-L=VLVR_$^^^^ ^^^^L!LL VLgeL!LL VQLgNL!LL VL)L%L@ Vj Ll^%LL! f )LLJ fR_^L/*L-L!LL VLf-L!LL VLL%L@ Vj  L l^%LL! f LLJ fR_G^L/*LLLJ LL!LL VLf9L!LL VL)L%L@ VLL VLL)L=VLVR^K^^L!LL VL!f)L!LL VL)L%L@ V&LLVR^^^! L/&]R_^R^^^^^L!LL VLgL!LL VQLgL!LL VL)L%L@ Vj L l^%LL! f )LLJ fR_*^L/*L-L!LL VLg>-L!LL VQLg$-L!LL VLL%LL VLfL%LL VLLL@ Vj  L l^%LL! f LLJ fR_^L/*LLLJ LL!LL VLfKL!LL VL)L%L@ VLL=VLL) LLI VLL)L=VLVR^K^^L!LL VL!f)L!LL VL)L%L@ V&LLVR^^^! L/&]R_^R^^R^^R^^^^^L!LL VLgwL!LL VQL g`L!LL VL)L%L@ Vj Ll^%LL! f )LLJ fR_b^L/*L-L!LL VLf-L!LL VLL%L@ Vj  L l^%LL! f LLJ fR_ ^L/*LLLJ LL!LL VLfKL!LL VL)L%L@ VLL)L=VLL) L* VLL)L=VLVR^K^^L!LL VL!f)L!LL VL)L%L@ V&LLVR^^^! L/&]R^X^R^^^^^j Ll^$LL! f L-LJ f^^L/*LR^ ! L/&]!LLJ LL!LL VLfL!LL VQL)L!LL VL-L%L@ Vj L9l^%LL! f -LLJ fR_^L/*LLLJ LL!LL VLf;L!LL VL)L%L@ VLL=VLL. LLVR^K^^L!LL VL!f)L!LL VL)L%L@ VLLVR^^^! L/&]R_a^^L!LL VLfL!LL VQL)L!LL VL-L%L@ VLf ! L9 LLJ Lj  Ll^$LL! f L-LJ f^(^L/*LLLLVLLVR^ ! L/&]R_^^L!LL VLfL!LL VQLftL!LL VQQL)L!LL VL-L%L@ VjLL LVl^%LL! f -LLJ fR_*^L/*LLLVR_^^^^L!LL VLfCL!LL VQL)L!LL VL-L%L@ VL)L LLVR^^^L!LL VL fL!LL VL)L%L@ Vj Ll^%LL! f )LLJ fR^c^L/*L-L!LL VL f:-L!LL VLL%L@ V)LL=VL)L VLLVR^^R^ ^^! L/&]!LQ LLF LLLbLbE^^QL)UL9L0 L-L-L%zL' VL9LQ LL=VLVR^{^DQL)UL-*L)L)LL)L# VL9LQ LL=VLVR^;^9L0 LL; L%zL' VL9LQ LLQ L=VL*LLJ LL!LL VLfL!LL VQLfL!LL VL)L%L@ Vj L9l^%LL! f )LLJ fR_ ^L/*LLLLQ LL=VLL-L VLLVR_^^^^L!LL VLg L!LL VQLfL!LL VL)L%L@ Vj Ll^%LL! f )LLJ fR_d^L/*LLLJ LL!LL VLfCL!LL VL)L%L@ VLQ LL=VLLL& VLLVR^K^^L!LL VL!f)L!LL VL)L%L@ VLLVR^^^! L/&]R_^^^^L!LL VLgL!LL VL)L%L@ V-LLJ LL!LL VLflL!LL VQLfUL!LL VQQL)L!LL VL-L%L@ VLQ LL=VLL-L1 VLLVR_^^^^L!LL VL fL!LL VL)L%L@ Vj  Ll^%LL! f )LLJ fR^^L/*LLLJ LL!LL VL fCL!LL VL)L%L@ V LQ LL=VL LLO VL LVR^K^^L!LL VL!f)L!LL VL)L%L@ VLLVR^^^! L/&]R^^^! L/&]R^^^L!LL VLfnL!LL VQL)L!LL VL-L%L@ Vj Ll^%LL! f -LLJ fR^^L/*L)LL)LVR^s^^j Ll^$LL! f L-LJ f^6^L/*LLLL=LLLv vaL쭥R^-^ ! L/&])rLLJ LL!LL VLg9L!LL VL)L%L@ Vj L9l^%LL! f )LLJ fR_^L/*LLLLL!fQ^^^ ^ ^^ ^=^p^^QL0 L L; L%zLL3 VL LLL=VLV^^vQL0 L L; L%zLL3 VL LLL=VLV^S^AQQLQUL0 L L-L%zLL3 VL L LL=VLVR^^^^x LLE VR^/^^L7 L LLV^ ! L/&]1rLLJ LL!LL VLfZL!LL VQLfCL!LL VQQL)L!LL VL-L%L@ VLB L LL9VR^^^^^L!LL VLfL!LL VQLfjL!LL VQQL)L!LL VL-L%L@ VjLL L=Vl^%LL! f -LLJ fR^ ^L/*LR^^^^^! L/&]!LLJ LL!LL VLgL!LL VQLgL!LL VQQL)L!LL VL-L%L@ VLLJ LL!LL VLfL!LL VQLfL!LL VL)L%L@ Vj  L9l^%LL! f )LLJ fR^^L/*Lj  L=l^%LL! f -LLJ fR^^L/*L0 L)LL)L%zL4 R^^^^^jLLB L L LVl^$LL! f L-LJ f^X^L/*Lj  Ll^%LL! f )LLJ fR^'^L/*L0 L)L)L%zL) R^! L/&]R^S^^^^j Ll^$LL! f L-LJ f^^L/*LL) R^ ! L/&]!LLJ LL!LL VLfL!LL VQLfL!LL VQQL)L!LL VL-L%LL VLf-L%LL VQLf-L%LL VLLL@ Vj  L9l^%LL! f LLJ fR^^L/*Lj  L=l^%LL! f LLJ fR^^L/*L0 L)LL)L%zR^^R^^R^^^^^L!LL VL%fSL!LL VL)L%L@ Vj L=l^%LL! f )LLJ fR^ ^L/*LR^^^; ^ ! L/&]!LLJ LL!LL VLf7L!LL VQLf!L!LL VL)L%L@ V; R_^^^^L!LL VLfL!LL VL)L%LL VLf)L%LL VQLf)L%LL VQQL-L%LL VLLL@ Vj  L9l^%LL! f LLJ fR^n^L/*Lj  L=l^%LL! f LLJ fR^=^L/*L0 L)LL)L%zR^%^^^^^^! L/&]!LLJ Lj L9l^$LL! f L-LJ f^S^L/*Lj L=l^%LL! f )LLJ fR^^L/*L0 L)L)L%zR^yL!LL VL%fSL!LL VL)L%L@ Vj L=l^%LL! f )LLJ fR^ ^L/*LR^^^; ^ ! L/&]!LLJ LL!LL VLfWL!LL VQLf@L!LL VQQL)L!LL VL-L%L@ VL= LL9VR^˥^^^^L!LL VLfqL!LL VQL)L!LL VL-L%L@ Vj L=l^%LL! f -LLJ fR^\^L/*LLH LL9VR^G^^L!LL VLf!L!LL VL)L%L@ V; R^^^! L/&]!LLJ LL!LL VLf^L!LL VL)L%L@ Vj L9l^%LL! f )LLJ fR^^L/*L0 LL)L%zR^楥^^L!LL VLfL!LL VQLfoL!LL VL)L%L@ Vj L=l^%LL! f )LLJ fR^w^L/*LLLL)L( VLLVR^X^^^^L!LL VLf,L!LL VL)L%L@ V0 LL; L%zR^^^! L/&])rLLJ LL!LL VLfxL!LL VQLfbL!LL VL)L%L@ Vj L9l^%LL! f )LLJ fR^3^L/*LLLLN R^!^^^^A ^ ! L/&]!LLJ LL!LL VLfOL!LL VQLf8L!LL VQQL f L!LL VL)L%L@ VR^^^ ^^^^^ ! L/&]!LLJ LL!LL VLfNL!LL VQLf7L!LL VQQL)L!LL VL-L%L@ VLN R^^^^^A ^ ! L/&]!LLJ Lj L9l^$LL! f L-LJ f^S^L/*Lj L=l^%LL! f )LLJ fR^(^L/*L0 L)L)L%zR^; ^ ! L/&]!LLJ LL!LL VLfRL!LL VL)L%L@ Vj L9l^%LL! f )LLJ fR^ ^L/*LR^^^; ^ ! L/&]!LLJ LL!LL VLf`L!LL VQLfIL!LL VQQL)L!LL VL-L%L@ VA L; L-L VLLL9VR_^^^^L!LL VLg!L!LL VQLg L!LL VQQL)L!LL VL-L%LL VLf-L%LL VLLL@ Vj  L=l^%LL! f LLJ fR_E^L/*LL!LL VLfpL!LL VQLfVL!LL VQQLL!LL VLL%L@ VA L0 LLL%zL-L VLLL9VR_^R^^R^^R^^^^^L!LL VLfL!LL VL)L%LL VLf])L%LL VQLfC)L%LL VQQL-L%LL VLLL@ VLS LLL9VR_,^^^^^^L!LL VLfL!LL VQL)L!LL VL-L%L@ Vj Ll^%LL! f -LLJ fR^^L/*LLLjL LVl^%LL! f LLJ fR^y^L/*LLLL!LL VLf>L!LL VLL%L@ V0 LLL%zLZ L)L L9VR ^'^R^^^! L/&]!LLJ Lj L9l^$LL! f L-LJ f^q^L/*LLLjL L=Vl^%LL! f LLJ fR^7^L/*LLL0 LL-L%zLLVR^! L/&])rLLJ LL!LL VLfUL!LL VL)L%L@ VjLL9Vl^%LL! f )LLJ fR^%^L/*LR^^^-L; ^ ! L/&])rLLJ LL!LL VL flL!LL VL)L%L@ Vj L9l^%LL! f )LLJ fR_^L/*LLLL)L" VLL=VR_^^L!LL VLfeL!LL VQLfNL!LL VQQL)L!LL VL-L%L@ VLN L; L-L VLLLVR_Y^^^^L!LL VLg&L!LL VQLgL!LL VQQL)L!LL VL-L%LL VLf-L%LL VLLL@ Vj  Ll^%LL! f LLJ fR^^L/*LL!LL VLfuL!LL VQLf[L!LL VQQLL!LL VLL%L@ VLN L0 LLL%zL-L VLLLVR^<^R^^R^^R^^^^^-L^ ! L/&]1rLLJ LL!LL VLfL!LL VQLfL!LL VQQL)L!LL VL-L%LL VLf`-L%LL VLLL@ Vj  L9l^%LL! f LLJ fR^:^L/*L0 LL)L%zR^'^R^^^^^; ^ ! L/&]!LLJ LL!LL VLf~L!LL VL)L%LL VLfY)L%LL VQLf?)L%LL VQQL-L%LL VLLL@ V0 L)L; L%zR^˥^^^^^^L!LL VLfL!LL VQL)L!LL VL-L%L@ Vj L9l^%LL! f -LLJ fR^R^L/*LL!LL VLf!L!LL VLL%L@ VR^#^R^ ^^; ^ ! L/&]!LLJ LL!LL VLfL!LL VL)L%LL VLf)L%LL VQLfr)L%LL VQQL-L%LL VLLL@ Vj  L9l^%LL! f LLJ fR^6^L/*L0 L-L)L%zR^#^^^^^^! L/&]!LLJ LL!LL VLfRL!LL VL)L%L@ Vj L9l^%LL! f )LLJ fR^ ^L/*LR^^^; ^ ! L/&]!LLJ LL!LL VLfL!LL VL)L%L@ V-LLJ LjL L9Vl^$LL! f L-LJ f^*^L/*LLLLM LL=VR^^j  Ll^$LL! f L-LJ f^*^L/*LLLL LL=VR^! L/&]R^^^L!LL VLf~L!LL VQLfhL!LL VL)L%L@ Vj Ll^%LL! f )LLJ fR^B^L/*LLLL8 LL=VR^)^^^^U LL=V^ ! L/&])rLLJ LL!LL VLf(L!LL VL)L%L@ V; LL9VR_;^^L!LL VLfL!LL VQLfmL!LL VQQL fUL!LL VL)L%L@ VjLL=Vl^%LL! f )LLJ fR_^L/*LR_^^ ^^^^L!LL VL%fUL!LL VL)L%L@ VjLL=Vl^%LL! f )LLJ fR_I^L/*LR_B^^L!LL VLgL!LL VQLgL!LL VQQL)L!LL VL-L%LL VLf-L%LL VQLf-L%LL VLLL@ Vj  Ll^%LL! f LLJ fR^^L/*LLLjL L=Vl^%LL! f LLJ fR^Y^L/*LLL0 L LL zL-L%zLL9VR ^1^R^^R^^^^^! L/&])rLLJ LL!LL VLf(L!LL VL)L%L@ V; LL9VR_V^^L!LL VL%fSL!LL VL)L%L@ Vj L=l^%LL! f )LLJ fR^^L/*LR^^^L!LL VLfL!LL VQLfL!LL VQQL)L!LL VL-L%L@ Vj Ll^%LL! f -LLJ fR^u^L/*Lj  L=l^%LL! f LLJ fR^D^L/*LLL0 LLL-L%zLL9VR^^^^^! L/&]!LLJ LL!LL VL fSL!LL VL)L%L@ Vj L9l^%LL! f )LLJ fR^Q^L/*LR^J^^j L9l^$LL! f L-LJ f^^L/*LR^ ! L/&]!LLJ Lj L9l^$LL! f L-LJ f_h^L/*Lj L=l^%LL! f )LLJ fR_=^L/*Lj Ll^%LL! f -LLJ fR_ ^L/*LL!LL VL fL!LL VLL%L@ Vj  Ll^%LL! f LLJ fR^^L/*Lj  Ll^%LL! f LLJ fR^^L/*L-L)LL%fUL!fQL^^^^^-L) LLVL0 LLL%zzL0 LL-L%zR^#^R^; ^ ! L/&]!LLJ LL!LL VL fL!LL VL)L%L@ Vj L9l^%LL! f )LLJ fR^_^L/*Lj L=l^%LL! f -LLJ fR^.^L/*L0 L)L)L%zR^^^; ^ ! L/&]!LLJ Lj L9l^$LL! f L-LJ f_Q^L/*LLLLLJ LL!LL VLfL!LL VQLfL!LL VQQL fL!LL VL)L%LL VLfj)L%LL VQLfP)L%LL VQQL-L%LL VLLL@ VLLLV VLL)L=VLVR_y^^^^^^ ^^^^L!LL VLfL!LL VQLfL!LL VL)L%L@ Vj  Ll^%LL! f )LLJ fR^^L/*LLL; LLL-L=VL0 LL L0 LLL; L%zL%zL< LN L: VLL)L=VLVR^^^^^j  Ll^$LL! f L-LJ f^W^L/*LLLL!b L%b^,LLV^ QLLLL VLLV^R^ ! L/&]R^! L/&]!LLJ LL!LL VLfL!LL VQL)L!LL VL-L%L@ Vj L9l^%LL! f -LLJ fR_^L/*LL!LL VLf6L!LL VLL%L@ VL< L-L)L=VLVR_X^R^ ^^L!LL VLgoL!LL VL)L%LL VLgJ)L%LL VQLg0)L%LL VQQL-L%LL VLLLL VLfLLL VQLfLLL VLLL@ Vj  Ll^%LL! f LLJ fR_^L/*Lj  Ll^%LL! f LLJ fR_N^L/*LL!LL VLfJL!LL VLL%L@ V0 L-LL-L%zL!L% VLL)L=VLVR_^R^*^R^^R^^^^^^^L!LL VLfL!LL VQLfL!LL VQQL)L!LL VL-L%L@ VjLL LVl^%LL! f -LLJ fR_H^L/*LLL)QLjL LVl^%LL! f LLJ fR_ ^L/*LLLLL-L: VLL)L=VLVR _^^^^L!LL VLfUL!LL VQLf>L!LL VQQL)L!LL VL-L%L@ VLK LLVR_l^^^^L!LL VLf L)L "^2 L)L "^& L)L "^ L)L "^ L)L "^9LL!z9LLzLL 9L)L)LS_ zrrL^ ^!^#^%^4^5QL LL L *^ ^ ^QL LL *^ ^L)L L VL r9LL L)L #L LrL LLj9LL VL l^4LLf L aLw f)L L ^ ^L/*L="LL L L L L9LL L L L9LL L L9L L L L L L9L L9L L9L L9L L9LL L9LL L9L L9L L9L L9L L9L L9L9L LL L L9LL L L9L LL LL j L9l^7LLf L aLUDf L-L VL ^ ^L/*)L L)LL VL)L L L RL LL LL j L9l^7LLf L aLUDf L-L VL ^ ^L/*)L L)LL VL)L L RL L L L9L L L L9L L L L9L'L L L9L\L L L9L"L L L9LL L%L VL L L9L LLL VLL LLf)LL L9V)LL L L L=*RL LL LLL%L VL f^L-L-L!LLL VL L92RL L9L L9L L9LL L L L9L LLL!b L%b^$)L L9*^QL-LL L=2^E 7 7 |7  7 U7 F7 L/`S7 _KL^^^#^-^7^A^J L)Lt "^> L)Lt "^2 L)Lt "^& L)Lt "^ L)Lt "^ L)Lt "^9LL!z9LLzLLt 9L)L)L_:zrrL^^T^V^X^Z^i^jQLL L f L Lf LLk V^A^^QL LL Lk *^# ^ ^ ^QL LLk *^ ^L)L L VLo r9LLs L)L #L LrLL^ Lj Lc L L9LL^ Ld L L9L^ LLj9LLu VLP l^4LLf Ll aLw f)L~ L ^ ^L/*L="L9L L9L L9L zLLt 9LLI"W3zLQ L9Lv L9L L9LR L9Le L9LT L9Lf L9L` L9LU L9Lw L9L9L L^ LL%L)L_ L%Lx VL)LLV L L9*RLX L L9L L L9Lg L L9L L L9L9L LL LLh j L9l^7LLf Ll aLUDf L-L VLo ^ ^L/*)L L)LLW VL)L LZ L RL LL LLh j L9l^7LLf Ll aLUDf L-L VLo ^ ^L/*)L L)LLW VL)L L RL^ LL_ LLL%L| VL f^L-L-L!LLLx VL L92RLL^ Lr L9LL^ Lr L9LLr L9LLr L9LY LLL!b L%b^$)L L9*^QL-LL L=2^L LL^ L} VL9L LL^ L} VL9 Lo L L"L VL9L L\L VL9L L L VL9L L L VL9L L L VL9L^ L%LLx VLj LLfLL L9VL LLa L VL=L L9L LL^ L} VL9 Lo L Lo L L#-7 I #*Vc7 K #47 L #(07 K #ǖA7 K #q&7 I #+7 I #H>7 G #f7  LL 7 F L ?6L%7 F L ?T'qL7 F L ?UL7 F L ?L 7 F L ?E@7  #f7  #':7  #7  LL 7  L ?6L%7  L ?T'qL7  L ?UL 7  L ?E@ L? L LKL@ L L LMLA L} L LKLILJLB L LMLL LOL:L LQL;L LSL8L LUL7L LWL9L L\LYL L_LC LZL L%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL LLD vL VE L-?+E L?WE L?T8E L?i)E L?Ɇz!E L?lrE L ?NE L ?SE L ?Fq:E L?ǚE L ?^_E L ?jŠE L?By7E L? E L?)E L)?_zpE L?3RE E 7  7 U7 7  #,7  #' 7  #7  #N+7  #7  #*7  #)7  #%7  #7!  #D\7"  ##o7#  #]7$  #617%  #K97&  #7'  #iT++7(  #7)  #,7*  #"7>7+  #}7,  #M7-  #7.  #(O97/  #!|70  #5`*71  #772  #̨g73  #@\ 74  #7.75  #iW76  #ϱp77  # ^78  #&]79  #%7:  #MR7;  #'7<  #s&7=  #47>  #K7?  #'}7@  #>37A  #в7B  #-7C  #F7D  #F7E  #M7F  #+7G  #(7H  #-7I  #!7J  #37K  #>97L  #7M  #O177N  #\7O  #O-7P  #]U7Q  #v7R  #17S  #17T  #GA7U  # K17V  #=.#7W  #47X  #+7Y  #7Z ] LL_ 7^  L^ ? L?s L? / L? L?) L?t  L?  L?hz L?R< L ?\ L?W  L$? L? _7 L6? L+?J L4?d{>; L?: L?#6 L?0) L?B L?< L-?O L ? L ?ү L?u L?O L ?W L ?Pw L?3U= L?y L ? L!?_Es L?~ L,?^_ L1?% L0?sI L/??/; L2?W" L.?o  L?$\ L?i5D; L)?: L(?}  L&?Yo; L'? L*?5 L7?  L5?) L3?b L%?D.' L"?Mu4R:  7f 7g7ha#^7i\#!07jd# 7k\#n47l]#%7m\#7nZ#cV7o\#|7p\#^#7q\#!!7rd#7sh#-X7t]#617uh#-q7vb# >7w]#]7x\#S)7y]#iT++7zh#a17{]#7|b#f7}Z# 7~\#Sp7\#7h#S7]#77h#7.7\#:%7h#iW7h#MR7]#%7\# r7\#ȩ7\#77Z#7Z#7\#Q?7\#G 77]#/7h#K7\#Eg7\#N?7]#в7\#77_#9V7h#F7\#B%7\#. 7\#,7\#M 7e#e&7_#n7Y#D7d#N7g#f7Z#\7\#Ee7Y#!I7]#v7e#:7[#Edž47\#k \7\#{7\#U67]#GA7\#o7\#Y4$7]#=.#7Y#f7\#Q77\#?7c#ſ7]#7\#17\#JEA 7e#!I7\#7Z#ſ7c#!I7c#9л7\#7\#'7\#F$7Z#9л7]#N+7]#*7]#7Y#?7\#Z(7Z#!I7h#e7[#ڥA7\#^_7\#V7Z#?7]#K97]#7h#7]#7\#+7_#C<7\#}7\#.7h#!|7Z#Z7h#&]7\#7]#%7Z#bS7]#s&7]#'7c#:7Y#ſ7\#"7\#7Y#9л7h#>37\#d 7\#K77h#M7Y#4H(+7f#3U=7\#77\#7\#w7\#.+7]#37\#E7e#\i7\#QK,7e#ſ7h#O177a#;7\#7u7]#O-7]#1m7\##{!7b#17]#17\#j 7]# K17\#.7\#; 7\#7h#(07Z#n7e#?7\#]U7Z# S7 LL 7 XL ?L 7 XL ?+L 7 XL ?(8L 7 XL ?L 7 XL ?ĘlL 7 XL ?& LL 7 XL ?;WLLL aL L L LLL L L L! L" L# L$ LLL% vLLL( vLL)L+ vLL-L. vL L0 LLLL)L1 eLL2 aL L3 vL L4 L5 LLLLL-LL6 -2)L-LLLLLL: v)2L)L LLL@ veL L L-LA vaF LL!7G XLG ?Ai3L%7H XLH ?nZL7I XLI ?NL7J XLJ ?-)3K LLLLS vLL)LU vLLLLLLX vaLLLZ vLL\ LLLLLLLLLLLLLb v2-L LLLLLLL&LL LLLLLLL v-2)LLL LLL L v)2LLLLLLLLL#L L$L v eL)L LLL LL LL va LL LL LLLL vLLL vL L) L"?׹ L?e& L? [ L?C]& L ?e2 L?1 L? L?J L?V L?\م L?' L?ɞ L?v L ?# L ? L? L$?"ݏ L? L ?% L?i0 L-?Q L?2m' L?4 L!? L)?ܖ2 L? L? 7 L?K L?;M L?C L?Zs L?uZ1 L?G" L?xc8 L&?N  L%?  L#?) L?w L ?; L ?gR)  77|777U77L/`S7M _#L^ ^^^&[ L)L "^\ L)L "^, L)L "^9LL!z9LL%z9LLzLL 9L)L)L (I/zrrL^ ^^$^7QLe LL ^%QLf L숥^QL7 LL( L^LL5 VL% rLLLbLbLbLbLbLbLbLbLbLbLbLbLbLbLbLbLbLbLbLbLbLbLbLbLcLlcLcLcLcLcLcLcLc__ ___^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^z^x^r^p^j^h^b^`^Z!^X^R!^P^J%^H^B%^@^:^8^2^0^*^(^"^ ^^^^^ ^^L)rLLLLL fiQLUL)*L)L9LL9f>LL-L=VL-LL-L VLL L-L L VLVR^9^R^ ^^LLL VLL LL L VLJRrLL Lj L9l^$LL f L-L f^S^L/*Lj L=l^%LL f )LL fR^^L/*L L)L)L%zR^L!L VL%fSL!L VL)L%L Vj L=l^%LL f )LL fR^L^L/*LR^E^^L!L VL!f!L!L VL)L%L V) R^^^ L/&]!9LL LL!L VL fL!L VQLf~L!L VL)L%L Vj 9L=l^%LL f )LL fR^^L/*LLL L VLLL-L L VL9LVR^z^^^^L!L VL%f&L!L VL)L%L VLR^=^^LL L VLLL L VL9LV^  L/&]!LL LL!L VL fL!L VQLfL!L VQQL)L!L VL-L!L VQLL%L VLL LL!L VL fLL!L VQLf6L!L VL)L%L VL LL)L VL9VR^.^^^^-L-L LL=V^  L/&]R_ ^^^^L!L VL fCL!L VQL)L!L VL-L%L VL)L LL=VR_ ^^L!L VLfL!L VL)L%L Vj Ll^%LL f )LL fR_@ ^L/*LLL LL!L VLf6L!L VL)L%L VLL VLLL=VR^P^^L!L VL!f.L!L VL)L%L V&L0 LLVR^^^ L/&]R_ ^^L!L VLfL!L VL)L%L Vj Ll^%LL f )LL fR_B ^L/*LLL LL!L VLf;L!L VL)L%L VLL VLL LL=VR^P^^L!L VL!f.L!L VL)L%L VL0 LLVR^^^ L/&]R_ ^^L!L VL fL!L VQL!f{L!L VL)L%L VjLLVl^%LL f )LL fR_) ^L/*LLL-LL VL)L LL=VR_ ^^^^L!L VL fL!L VQL%fL!L VL)L%L Vj Ll^%LL f )LL fR_ ^L/*Lj Ll^%LL f -LL fR_X ^L/*L)LL L VL)L)L L VLL=VR_+ ^^^^L!L VL g L!L VQLfL!L VL)L%L Vj Ll^%LL f )LL fR_^L/*L-L!L VL f-L!L VQL%fy-L!L VLL%L Vj  Ll^%LL f LL fR_H^L/*L-LL L VLLL L VLL=VR_^R^^R^^^^^L!L VL g(L!L VQL gL!L VL)L%L Vj Ll^%LL f )LL fR_^L/*L-L!L VLf-L!L VLL%L Vj  Ll^%LL f LL fR_?^L/*LLLL!L VLfBL!L VLL%L VLL VLLLL VLL=VR_^R^^R^^^^^L!L VL fL!L VQLfL!L VL)L%L Vj Ll^%LL f )LL fR__^L/*Lj Ll^%LL f -LL fR_.^L/*LLLLLLLL=LL> vaL쭥R_^^^^L!L VL gjL!L VQLgSL!L VL)L%L VLg.)L%L VL-LL Vj Ll^%LL f -LL fR_h^L/*LLL LL!L VLfvL!L VL)L%L Vj  Ll^%LL f )LL fR^|^L/*LLL L VLL)L VLL=VR^R^^L!L VL!f.L!L VL)L%L VL0 LLVR^^^ L/&]R_^^ ^^^^L!L VL fL!L VQLfL!L VL)L%L V-LL Lj  Ll^$LL f L-L f^8^L/*L-LL L VLL L LL=VR^RL!L VL%f4L!L VL)L%L V-L L LL=VR^^^ L/&]R_^^^^L!L VL fL!L VQLfL!L VL)L%L V-LL Lj  Ll^$LL f L-L f^8^L/*L-LL L VLL L* LL=VR^RL!L VL%f4L!L VL)L%L V-L L* LL=VR^^^ L/&]R_^^^^L!L VL fEL!L VQLf.L!L VL)L%L VL LL=VR_/^^^^L!L VL g_L!L VQL gHL!L VL)L%L Vj Ll^%LL f )LL fR_^L/*L-L!L VL f-L!L VQL f-L!L VLL%L VL fL%L VQLfL%L VQQLL%L VLLL Vj  Ll^%LL f LL fR_^L/*LLL L VLLL-L VLL=VR^ᥥ^R^"^R^^R^^R^^^^^L!L VL fL!L VQLfL!L VL)L%L Vj Ll^%LL f )LL fR^N^L/*LLL L VLL-L!L L L-LVL R^^^^^ L/&]!LL LL!L VLfL!L VL)L%L VL fp)L%L VQLfV)L%L VQQL-L%L VLLL VL LL VLL-L" VLL9VR_^^^^^^L!L VLfL!L VL)L%L Vj L=l^%LL f )LL fR_P^L/*LLL LL!L VLfCL!L VL)L%L VL LL VLLL& VLL9VR^P^^L!L VL!f.L!L VL)L%L VL0 LLVR^^^ L/&]R_^^L!L VL fL!L VL)L%L Vj Ll^%LL f )LL fR_F^L/*LLL LL!L VL fCL!L VL)L%L VL LL VLLL VLL9VR^P^^L!L VL!f.L!L VL)L%L VL0 LLVR^^^ L/&]R^^^L!L VL fnL!L VQL)L!L VL-L%L Vj Ll^%LL f -LL fR^.^L/*L)LL)LVR^^^-^  L/&])rLL LL!L VL g2L!L VQLgL!L VQQL)L!L VL-L%L VLL LL!L VLfL!L VL)L%L Vj  L9l^%LL f )LL fR_^L/*Lj  L=l^%LL f -LL fR_[^L/*L L)LL)L%zL R_>^^L!L VL fL!L VQLfvL!L VL)L%L Vj  Ll^%LL f )LL fR^^L/*L LL-L VLL L)L%zL R^^^^^jLL L L LVl^$LL f L-L f^X^L/*Lj  Ll^%LL f )LL fR^'^L/*L L)L)L%zL R^ L/&]R^S^^^^j Ll^$LL f L-L f^^L/*LL R^  L/&]!LL Lj L9l^$LL f L-L f^S^L/*Lj L=l^%LL f )LL fR^^L/*L L)L)L%zR^yL!L VL%fSL!L VL)L%L Vj L=l^%LL f )LL fR^ ^L/*LR^^^) ^  L/&]!LL LL!L VL fL!L VQLfL!L VQQL)L!L VL-L%L VLf-L%L VLLL Vj  L9l^%LL f LL fR^^L/*Lj  L=l^%LL f LL fR^^L/*L L)LL)L%zR^^R^^^^^L!L VLfSL!L VL)L%L Vj L=l^%LL f )LL fR^ ^L/*LR^^^) ^  L/&]!LL Lj L9l^$LL f L-L f^^L/*L)L!L VLf)L!L VL-L%L Vj L9l^%LL f -LL fR_^L/*Lj  L=l^%LL f LL fR_d^L/*LLLL LLLL%zR_B^^L!L VL g L!L VQL fL!L VL)L%L VLf)L%L VL-LL Vj L9l^%LL f -LL fR^^L/*Lj  L=l^%LL f LL fR^z^L/*LLLLLL!b L%b^&L L^ L L. LLV^R^0^^ ^^^^ L) ^  L/&]!LL LL!L VL fL!L VQLfqL!L VQQL)L!L VL-L%L Vj L9l^%LL f -LL fR^^L/*L L-L)L%zR^^^^^L!L VLfSL!L VL)L%L Vj L9l^%LL f )LL fR^ ^L/*LR^^^) ^  L/&]!LL Lj L9l^$LL f L-L f^S^L/*Lj L=l^%LL f )LL fR^(^L/*L L)L)L%zR^) ^  L/&]!LL LL!L VLfRL!L VL)L%L Vj L9l^%LL f )LL fR^ ^L/*LR^^^) ^  L/&]!LL LL!L VL gL!L VQLgwL!L VQQL)L!L VL-L%L VLL LL!L VL fL!L VQLfL!L VL)L%L Vj  L9l^%LL f )LL fR^^L/*LjL L L=Vl^%LL f -LL fR^^L/*LLLL LL L LL%zR^v^^^^jL L=Vl^$LL f L-L f^3^L/*LLLL L LLL%zR^ L/&]R^^^^^ L/&])rLL LL!L VLfUL!L VL)L%L VjLL9Vl^%LL f )LL fR^%^L/*LR^^^-L) ^  L/&])r9L' L+ VLL LLLbLb^,^(QLL=R^#^QLL=R^^L)쥥 L! LLL-L)LLJ vajL L9L LL l^CLLf L# aL65f!)L L. L-L$ L=V^ ^L/*)RL LL L LL-L-LLQL VL9)RrM 7 7 L/`S7 _ L LX "rLT LL!f$LZ L)LLb VL-LLq VR^L)L} L)Lj "L!f ^()L)L{ LLLLL%L9VL%zrLT L ^^^ ^$^(^6^D^Q^^^k^x^v[ ^^pu ^z^jz ^t^dw ^n^^LT Lv ^^^NL^ Lv ^N^>L9Lx ^?^/L9L_ ^0^ L9LY ^!^L9Lm ^^L LL !LT L!^F^J^N^R^V^Z^^^b^f^j^n^r^v^z^~^^^^^^^^^^^^^^^^^^^^^^^^l^^^^^^^^^^^^^^^^^^^^^^z^^t^~^n^x^h^r^b^l^\^f^V^`^P^Z^J^T^D^N^>^H^8^B^2^<^,^6^&^0^ ^*^^$^^^^^^^L LL !L9LL=LL9LL9LL)RL9L)L9L L-L=VL-LL)L)L)L` CRrLT L!fV ^L9Lp 9L=L9LLL)RLT LLf37V Q #f7W S #F7X R #*=7Y O #p>7Z R #n77[ R #N+7\ S #M7] O #97^ R #7_ R #V/7` R #}7a O #VK7b R #7c R #!;7d R #L;7e R #7f O #p>7g R #^7h R # 7i Q #N7j R ##o7k R #oc|7l R #в7m R #7n R #ط7o S #O177p Q #!I7q R #\7r R #,7s R #47t R #|7u R #77v R #~277w R #|57x R #?7y R #37z S #!|7{ R #5`*7| Q #7} R #K97~ S #MR7 R #:z7 S #)7  L L LLLL aL L LLLLL-LL)L v-2)LLLL v)2LL eLL)LLLLLLLL v aLL vL L?y L?f0  L?Ȃ L?*x L ?f L?n# L-?e# L)?  L?0  L?3U= L? R   7 U7 L/`S7 _\LL 9LL3*z LL "rjL(L VLLL VLLL!bL%b^>^: L#L V^^*UL!fQLL L R^d^^^LL LLL!b L%b^5 L'L V^)QL)ULL LL)L L V^LLLL QL ULzRl^*LLf L aLw f)^ ^L/*!r L 9L LL%fUUL%fGUUL!f7QLUQL=L=L-LVL=L-LVLR^^^ ^^^^LjL L l^LLf L a ^L/*LLLL!b L%b ^ ^QL9LL=VL ^L)LL VLL L +rL)L L +rL9L)L +r9LL L=VLLL VL LLL bLb^^)L LL%fLUL%f>UUL!f.QLUQL9LL=VL9L-L=VR^^^ ^^^^LLL L)LL%z^i^9L L VL!fLL9LL L=VL ^2^L L VL!fLL9L-L=VL  L)L)L9VL)LL=LL vL-L LLL bL bL bLcL cL(cL cL c+L cLcL cL cL cL cL4cL cL cLckL<cL cL cL cLcL@c__LL VL LLL L __LL VLLL L __hLL VLLL L L _W_@LL VLL!L VL$f(LL%L-L L%L VL L ^LLLbLb(Lb3Lb>^N^JL L ^M^8L L ^;^&L L ^)^L L ^^L)L L __u-LL=LL L VL _g_P-LLL L=VL _G_0LL VLLLL L=VL)L V__L LLL!b L%b ^?L^7QL)ULLL-L=VLL=L-L VL V^__ L-__-LL=L vLL L VL __i L-_s_\ L-_f_OL LL%fUL%fUULL!bL%bA^^QL)UQLLL-L=VLL-L=VL L VR^~^hUUUL!fTQL)UQL-UUQLLLL=VLLL=VL LL=VL L VR^ ^^^^^^^L_z_cLL VLL L_\_ELL VLL L_>_'LL VLL VLLLLL L=VL V__j L L l^LLf L a ^L/*LLLLL!b L%b ^ ^QLLL=VL ^L __zj L L l^LLf L a ^L/*LLLLL!b L%b ^ ^QLLL=VL ^L __-L _^ L-_^-LL=L vLL L VL ^^LL VLLL ^^ L L LL=LLLLL vLL L VLLL!b L%b ^*L^"QLLLL LL V^R^?^(L LLVLLLL)R^^L LL L ARrL LL LL%f3QL!f%UL!fQL-LL9V^^^ ^^^^ L )rLLL L)LL L%zL-LLL!b L%b ^$ ^ QL L9L)L=VL L%z^L 3RLLL L)LL L%zL L9LL=VL L%zL 3RLL L L L9LL=VL L9LL=VL L%zL%zL 3RLLLL L LL^)_;_]____<_`_____r____W_{__-QLL ^^-^E^]^u^^^^^LL)L L ^LL)L L ^LL)L L ^LL)L L ^QLL LL L ^jQLL LL ^PQLL LL ^6LL)L L ^LL)L L ^_QLL )LL9L)L V_QLL()L LL-L9VL L%z_QLULL LL -L LLL9VL L%z_QLULL -L LLL9VLL9LL VL%z_RQLULL -L LLL9VL LLL9VL L%zL%z_QLL)LL9L vL)L V_*LL!b L%bJ^QL)ULL L LLL9VL L LL9VL L%zL%z^GQL)ULL L LL-L9VL L LL9VL L%zL%z^_DQLUL)*LL L LLL9VL L LL9VLLLL!b L%b ^$ ^ QL LL)L9VL L%z^L%zL%z_QLUL)*LL4L)L L LLL9VL L LL9VL L%zL%z_gQLULL LL-L VL -L LL-L9VL L%z_#QLUL)*LL L-L L LLL9VL L LL9VL L%zL%z_QLL )LLLL!b L%b ^$ ^ QL LL)L9VL L%z^_|QLL)LLLL!b L%b ^$ ^ QL LL)L9VL L%z^_,-L<_#QLULL -L LLL9VL LLL9VL L%zL%z^QLL )LL9L vL)L V^QLL -LL ^QLUL)*LLL9L vL)L VLL LLL9VLLLL!b L%b ^:^6QL LL L LLL9VL L%zL VLL%z^L%z^-Lf  LLLL(L L%z^(-Lf LL L(L L%z^ L)LLL!b L%b ^ ^QL LLL L%z^LL)L)L VLL kRr LL9 7 |7 U7 F7 7 L/`S7F_L^ ^^^)^2L)L"^&L)L"^L)L"^L)L"^9L-L-L-L!zrr9LL%z9LLz9LLzLL9LLT5z L #xBLL)L?xBL L #xBLL)L?xBLL/mLL/1&LL!LL-f.-L$L)LL)L/AVL)L/2L%e_ L)L #xBLL #Hg Lz?Hg  L?xBLRr #Hg L #xBLL L)QL-LL L# sLL L# sLV?xBL L)U?Hg R%LL?Hg L?xBLL&? L'?- L(?m[L)?m$Lj#LL+V#xBLL L# sLlrl^LLf L"L/*L/*!LL!f^^^LL%f^^^LLf^^^L^ ^^!^(^6*L9LL*^%1L^1L^QL9LL*^L^ ^^!^(^6*L9LL *^%3L^3L^QL9LL *^LL!fQL^^^5LLLLbL%b^0^,QL9LLVR^$^QL9LLVR^^7LLL!f+*LLLL8L)LVL ^^^7LLL L9L L)LL!f!UL)L:LLVL^^^;L)rLLGLL>L)LLRL^ ^^^^QLUL)*LL=LL?LLVLVLLVLL!fL@LV^0^^LLLVL9LLVLALL[^OQL-LL2^>QL-LBLV-LLV-LCL2^QL-L9LL2^rL LLLLL9VL)R7%%L? %L?xBL%L?m%L?- %L?Hg %L?m[F7 |7 7F7 77#K7 #ſ7 #9л7#lY7# 7 #57  #Z7 #17 #(07 #q7 #iW7#C7#!I7#f7#eK<7#a17 # S7LL7 L?"63L7 L?==L7 L? `L 7 L?;!LL#7" L"?;W L*7$,LL/HoL#g%Z7+-L.L/L0L)L2L-L4L6L9L<LLLLDaLELFL)?lYFL?UJFL ?3U=FL?1FL?JWFL? FL?+0FL?YsFL?2FL?RFL-?JFL ?~R FF7 7  #ſ7  #n7  # 7  #*=7  #N+7  #n77  #cV7  #7  #V/7  #7  #e7  #J7  #r!7  #7  #^7  ##o7  #,7  #47  #77  #|57  #"637  #37  # P7  #!|7  #7.7  #5`*7  #K97  #&]7  #MR7  #JW7  #7  # 7  #K7  #-7  #>37  #F7  #W7  #R7  #}7  #!;7  #L;7  #7  #N7  # 7  #7  #eK<7  #oc|7  #17  #в7  #7  #ط7  #O177  #\7  #3U=7  #|7  #~277  #?7  #17  #:z7  #(07  # S7  LL 7  L ?;W L LLL)L)LL vaL LLLL aL L L)? L?  L? L?f0  L?H L-?3U=R  7 7  7  7 7  #K7  #'}7  #-7  #>37  #nN 7  #7  #-7  #f0 7  #7  #N+7  #M7  #V/7  #}7  #!;7  #L;7  #7  #7  #!7  #7  #ڥA7  #"7>7  #^7  # 7  #f7  # >7  ##o7  #>97  #oc|7  #]U7  #7  #в7  #O177  #,7  #47  #\7  #f7  #77  #?7  #17  #f7  #!|7  #47!  #5`*7"  #7.7#  #iW7$  #&]7%  #K97&  #57'  #(07(  #MR7)  #:z7*  #+7+ - LL/ 7.  L. ?;M L?f0 M L)?3U=M L?yM L?~M L?r1]M L?9uM L?^_M L ?W"M L ?} M L ?5M L? M L?)M L ?D.'M L?Mu4RM M 7 7F77 77#47#^7#!I7#ſ7#7#n7# 7#*=7#N+7#n77#7#V/7#|7#cV7#7#i7#e7#ڥA7#^7# >7##o7#^_7#47#f7#,7#77#|57#}7#37#!|7#7.7#5`*7#e&7#iW7#^'X7#K97#MR7#b 7# r7#7#9W7#ſ7#7#K7#Eg7#-7#3U=7#9л7#>37#F7#. 7#M7#D7#}7#\PC37#!;7#}w7# 7#E7#f7#oc|7#в7#/7#ط7#O177#;7#\7#|7##{!7#!I7#h7#?7#17#T7#:7#o7#!v7#; 7#7#(07#?7#?7# S7#f7LL!7L?=L%7L?}YLLL L L LLLLL*LL%zLLLLLLaLLLLLLLaL LLLL L L LLLvaLLLLLLLLLLLLLL L LLL!LLL LL!LLL%v 2 L LL LLLLL&v2 LLL L'v2LLLLL,v2L.2LLL L LL2v2LL LLLLL?v2-LLLLLLCv-2)L L)LLLLLLL LL LLLL'L LL-LLLLJv)2L-LLLLLLMveL)LLOvaLLL LLVvLWL?MWL ?6WL?2WL?*WL? PWL ?eWL?By7WL?5_WL? gWL?dd,WL? WL ?WL ?g>WL?KWL?š9WL-?Z0WL?WL?#6WL ?3WL?PWL)? %WL?y(WL?l5WL?_WL?C4WL?IbWL?WL?WL?Mu4WL?m%WL?ݩ%RWW6 6 6L/`S7o_ZL}LNVLRLLL!b L%b ^<^8UL!fQLR^'^^QL)UL}LLRLP:^L}LNVLRLLL!b L%b ^#^UL!f ^^^QL^lLLaLNVLPVLLlLNVLRLLL!b L%b^bL8LQ2^ QL^/Ho#]tLIL#.Z!LSLULLfO^LMWYL[LlL]LHL#.Z!o7G|7H7IF7J7KI#9V7LK#O177MJ#n7NK#>37OJ# 7PK#F7QH#cV7RTL%L/HoL#g%Z7SVL%L/HoL#g%Z7UXL!L/HoL#g%Z7WZL!L/HoL#g%Z7Y\L%L/HoL#g%Z7[^L%L/HoL#g%Z7]_L`LcLLLdLeLfL%L/HoL#g%ZL/LL L/VL LL L)LdL/VzLgLhLL/HoL#g%ZLiLjL%L/HoL#g%ZLkLmLnLoL ?oL ?xoL?oL?oL?roL?=oL)?UoL?&oL?O&oL ?oL?oL??oL-?z_(?oL ?9oL ?]tRoo6E 6L/`S7_L^ ^^!^+^5^>L)Lu"^2L)Lu"^&L)Lu"^L)Lu"^L)Lu"^LL/HoL#g%Z7L%L/HoL#g%Z7LL/HoL#g%Z7LL/HoL#g%Z7L%L/HoL#g%Z7LL/HoL#g%Z7L%L/HoL#g%Z7L%L/HoL#g%Z7#VKL#lYL)#mzLLL"rLLLLLLVL91rLLL!b L%b^^ QL^LLLLLLVL91rLLL{L"rLL{L"rL9LLL=VL-LyLVLwLLL!L-L!LVL)Lb LLyfL~LzL!L)QL|CRr9L=L)LL!LVLLL!L-QLtVf LLxL9L%LLwLL}L)LL=VLLLLLLLLva!L-LLv1R7pF7q 7r7sr#"7ts#K7ur#(07vq#f7ws#>37xq#7ys#&]7zs#(07{q#W7|r#f7}s#;W7~LL!7pL?ADL%7pL?[ 7L7pL?.L7pL?S9L7pL?-2LLLLL-LLLLLLLLL)LLLLvLL)LLLvLL?. L?y#L?]l36L?L?@L ? L-?/L?iL? L? >L ?;L)?GL ?ӳ0R 6M 6L/`S7_HL^ ^^^&L)L"^ L)L"^L)L"^9LL%z9L)L)LzrrL/L!LL/1&LLfC)L)$L)LL)f^ )Lf )L^)L-LV@)L%2_)LL#.Z!rR/QL/V(LL^ ^^&^C9LL"^7QL9LL)L3^"QLUL9LL)LL;^LLL"rLL9L=7777#K7#˿7#ſ7#lY7#a17LL!7L?{2#L7L?̨gL7L?t=7LLL)LLvLL?-XL-? ML)?4}rL?R6! 6#L/`S7_L^ ^^^&L)L"^L)L"^_L)L"^9LL!z9LL%z9LLzLLQLLL)L)L*RLLLLV%Lr9L=LLL9LL-L3R9L=!LLLLLLL9LvLLLL)LVLL)LVLLLVk+Lg LLVLL L%j LLVl^6LLf LaLw fL LvL^ ^L/*LL^ ^^J^QLL쭥^QL L f LL LVL L L%L)^iQL L f LL LVL L L%j Ll^$LLf LaL^L/*LL-R^R_l^XLLf LaLuf6LL%LVLLL^ LLL9V^ ^L/*QRrLL-L-L-L9#. 6?)#!|6@#-X6A)#7.6B)#&]6C5#ua6D)#MR6E#ܖ26F#2m'6G#6H#;6I#ſ6J#6K5#}~&6L)#K6M)#>36N #6O #. 6P#W6Q# 6R%#t,96S# 6T#]6U!# M6V## 6W#N6X#w6Y5#a16Z#W6[)#O176\#G6]#!I6^5#lY6_ #16`)#T6a#V6b #۰126c # 6d# 6e)#(06f#׹6g#6h#f6i%#3U=6j# S6kmLpLsLvLwLyLL{6z1Lz?높kHL|LL}LL}LQL~L@LLEL%zLELLL\LNLLiLLL@LLLvL  J Compiling %s .n Dumping %s .dump Printing %s 2.neko' Releasing %s eBuilding documentation for %s .htmlException : %s  %s(%d): %s g/Neko Compiler v.@ - (c)2005-2013 Haxe Foundation Usage : neko [options] files... : dump bytecode-d : make bytecode release-z $ : parse and print neko source-p : make documentation-doc : set output directory-o+: run the console-console5 : link bytecodes files-linkB: verbose mode-vJ: set the bytecode version-versionRneko/Main@IO@String@Buffer@Core@Core_@print_union@String_blit@Buffer_add_char@String_create@String_sub@Core_assert@Core_ord@Core_Exit@Buffer_add_sub@Core_Neko_error@Buffer_string@Core_sprintf@Core_throw@String_length@String_get@Buffer_add@Buffer_create@Core_magic@Core_chr@Core_min@Core_invalid_argOverflowOverflowEofEofClosedClosedBlockedBlocked@loadstd@ file_open file_contents file_close file_readfile_read_char file_writefile_write_char file_flush&/_rbr>GPwbww file_stdin file_stdout file_stderrIO.inputIO.readA IO.read_buf} core/IO.nmlF        * 8 A  IO.write_i8S  IO.outputv    IO.write_ui16:  IO.write_i16e  IO.write_ui24        IO@String@List@Buffer@Core@List_iter@Buffer_string@Core_sprintf@Buffer_add_char@Core_throw@Buffer_add@Buffer_create@Core_chr@Core_invalid_arg@Core_Not_found@Core_ord@string_splitstd@string_splitA  String.getk  String.set  String.blit  String.sub      \n\t\r\\\"\%.3d T:String.unescapemW@serialize std@serialize@unserializestd@unserializeString@List@Array@Core@Core_@pcons@Array_make@Core_@aset@Array_list@Core_@compare@Array_create@Core_throw@Core_@empty@Array_sort@Core_invalid_arg@Core_Not_found@make@rmake7DList.hdwList.tl List.iter2[X?"-r List.chop` List.loopList.nth3 a  !l!List@Array@Core@Core_@aset@Core_throw@Core_@aget@Core_Not_found[, ]!@make!@merge_sortstd@merge_sort!!"Y"c"r"""#.#o###$asub#$*$Array@CoreNoneSomex$NoneSome$ Neko_error$Neko_error$Invalid_argument$Invalid_argument$Assert_failure$Assert_failure%Error%Error"% Stream_error/%Stream_error Not_found=%Not_foundExitK%Exit@sprintf std@sprintf@string()Y%{ __string = ; }%L&@compare&' Array.get' Array.set(@empty[]4(@pcons :: 8(@consP(_(b(j(y(((((Core.int( Core.float((Core.chr((()))%)<)S)])o:0l)Core.stream_token)Core.stream_junk)n*nekoCore@Buffer@Core@buffer_newstd@buffer_new@buffer_addstd@buffer_add@buffer_add_substd@buffer_add_sub@buffer_add_charstd@buffer_add_char@buffer_stringstd@buffer_string@buffer_resetstd@buffer_resetr0x00Buffer@Neko_Printer@IO@List@String@Neko_Astneko/Ast@Core@IO_write_char@List_iter@IO_write_string@String_make@Core_@compare@Core_None@IO_close_out@IO_write@Neko_Ast_s_constant@Core_assert@IO_printf@Core_fst66+6F6%sp66{;6 }(  ).%s,var 7while do if elsetrycatch %s function( %s return;return break;break continue $new(null)neko/Printer.nml%s => ^7%s:switch  => 8 default => :8 =>>.?neko/Printer@Neko_Ast@List@Lexer@String@Core@Core_@pcons@Core_Some@Core_@print_union@List_iter@Core_None@String_escape@Core_@empty@Core_string@List_mapTrueFalseNullThisIntFloatBuiltinIdentv?TrueFalseNullThisInt@Float@String@Builtin(@Ident5@VarWhileDoIfElseFunctionReturnBreakContinueDefaultTryCatchSwitchB@VarWhileDoIfElseFunctionReturnBreakContinueDefaultTryCatchSwitch SemicolonDotCommaArrow BraceOpen BraceClose ParentOpen ParentClose BracketOpen BracketCloseConstKeywordBinopComment CommentLineAEofSemicolonDotCommaArrowBraceOpenBraceCloseParentOpenParentCloseBracketOpenBracketCloseConstAKeywordABinop BCommentBCommentLine&B NormalWhileDoWhile3BNormalWhileDoWhileEConstEBlock EParenthesisEFieldECallEArrayEVarsEWhileEIfETry EFunctionEBinopEReturnEBreak EContinueENextEObjectELabelESwitchgBEConst~CEBlockCEParenthesisCEFieldCECallCEArrayCEVarsCEWhileCEIfCETry DEFunction!DEBinop2DEReturnFDEBreakSDEContinueENext`DEObjectqDELabel~DESwitchDDDDDDDEE*E=E|EEEHHHHtruefalsenullthis"$CKvarwhiledoiffunctionreturnbreakdefaultcatchswitchK=>/**///Lneko/Ast@Lexer@IO@List@String@LexEngine LexEngine@Core@Core_Some@List_array@Core_@print_union@String_blit@IO_input@String_create@Core_None@LexEngine_make_tables@String_sub@Core_assert@Core_fst@Core_@aget@Core_max@Core_Exit@Core_Neko_error@LexEngine_determinize@IO_read_string@Core_snd@String_length@String_get@Core_throw@LexEngine_parse@Core_@empty@Core_min@Core_invalid_arg@List_map Invalid_ruleLInvalid_ruleLLLLM=MAMHMMMMNN*OOcore/Lexer.nmlOPPQQLexer.empty_tableQQLexer@LexEngine@List@HashtblHashtbl@Array@String@Core@List_array@Array_make@Core_@print_union@List_iter@Array_map@Hashtbl_find@Core_None@Core_assert@Array_sort@List_mem@List_filter@Core_fst@List_rev@Core_compare@Array_iteri@Core_@aset@Core_@compare@Array_iter@String_get@String_length@List_exists@Array_init@Core_Some@List_fold@Core_ignore@Hashtbl_add@Core_@aget@Core_ord@List_assoc@Core_@pcons@List_concat@Core_Neko_error@List_sort@Core_snd@Array_length@Core_throw@Core_@empty@List_map@List_append@Hashtbl_createEmptyMatchStarPlusNextChoiceQEmptyMatchTRStaraRPlusnRNext{RChoiceRRcore/LexEngine.nmlRSTtTTTTTTTU%V?V|VWW.WQWhWyWWX,XX8Y\InvalidRegexpI\V\r\\\\W]]]]^\_LexEngine@Hashtbl@Core@Core_throw@Core_Not_found````a"a1a@aTaHashtbl@Neko_Binast@IO@Lexer@Array@Neko_Ast@Core@IO_read_byte@Neko_Ast_ETry@Core_None@Array_create@Core_assert@Neko_Ast_Builtin@IO_read_ui16@Neko_Ast_True@Neko_Ast_EConst@Core_fst@IO_read_i32@Neko_Ast_String@Neko_Ast_ESwitch@Neko_Ast_EFunction@IO_read@Neko_Ast_EBlock@Neko_Ast_NormalWhile@Neko_Ast_DoWhile@Neko_Ast_EObject@IO_read_ui24@Neko_Ast_EVars@Neko_Ast_EReturn@Array_get@Neko_Ast_EBinop@Neko_Ast_ELabel@Neko_Ast_Ident@Neko_Ast_EContinue@Neko_Ast_ENext@Core_Some@Array_add@Neko_Ast_EArray@Neko_Ast_EWhile@Neko_Ast_EIf@Neko_Ast_False@Neko_Ast_Int@Neko_Ast_This@Neko_Ast_Float@Neko_Ast_EParenthesis@Neko_Ast_Null@Core_@pcons@Neko_Ast_EField@Array_length@Neko_Ast_ECall@Core_@empty@Neko_Ast_EBreak@Core_errorneko/Binast.nml+lNBA7llInvalid const tag : l+-*%<<>>>>>|&^==!=>>=<<==&&||++=--=+=-=/=*=%=<<=>>=>>>=|=&=^=Invalid op tag \mnnnn oInvalid expr tag : #oInvalid binast headerrneko/Binast@Neko_Compile@Hashtbl@List@Lexer@Array@MapMap@String@Neko_Ast@Neko_Bytecode@Core@Neko_Bytecode_op_param@Neko_Ast_Builtin@Neko_Bytecode_SetIndex@Neko_Bytecode_trap_stack_delta@Neko_Bytecode_GlobalFloat@List_rev@Neko_Bytecode_Mod@Neko_Bytecode_Bool@Neko_Bytecode_Apply@Neko_Bytecode_MakeEnv@String_length@Array_iter@Neko_Bytecode_SetGlobal@Neko_Bytecode_Lte@Neko_Bytecode_Neq@Neko_Bytecode_AccIndex0@Array_set@Neko_Bytecode_AccIndex1@Neko_Bytecode_Or@Hashtbl_length@Core_Neko_error@Neko_Ast_EField@Core_snd@Neko_Bytecode_Not@Neko_Bytecode_GlobalString@Neko_Bytecode_AccEnv@Neko_Bytecode_SetThis@Core_@empty@Neko_Bytecode_ObjCall@Neko_Bytecode_Jump@List_length@Array_make@Core_@print_union@Neko_Bytecode_AccInt@Core_assert@String_sub@Array_sort@Neko_Bytecode_New@Neko_Bytecode_Pop@Neko_Bytecode_JumpTable@Neko_Ast_Ident@Array_add@Neko_Bytecode_PhysCompare@Neko_Bytecode_AccGlobal@Neko_Bytecode_Div@Neko_Bytecode_Ret@Hashtbl_add@Neko_Bytecode_Xor@Core_Exit@Neko_Bytecode_GlobalVersion@Neko_Bytecode_TypeOf@Array_length@Neko_Bytecode_SetField@Neko_Bytecode_Lt@Array_append@Neko_Bytecode_JumpIf@Neko_Bytecode_AccThis@Map_iter@Hashtbl_create@Neko_Bytecode_JumpIfNot@List_iter@Neko_Bytecode_SetEnv@Map_find@Map_add@Neko_Bytecode_Hash@Array_map@Neko_Bytecode_EndTrap@Neko_Ast_EConst@Neko_Bytecode_AccStack@Hashtbl_exists@Neko_Bytecode_Shl@Core_@aset@Core_compare@Neko_Ast_EBlock@Neko_Bytecode_GlobalDebug@Core_@compare@Neko_Bytecode_SetArray@Neko_Ast_EVars@Neko_Ast_EBinop@Neko_Bytecode_Eq@Neko_Ast_EIf@Neko_Bytecode_AccTrue@Core_ignore@Neko_Bytecode_Gte@Neko_Ast_Int@Neko_Bytecode_Sub@Core_@pcons@Neko_Bytecode_TailCall@Core_sprintf@List_sort@Core_throw@Neko_Ast_ECall@Neko_Bytecode_Mult@Map_empty@Neko_Bytecode_AccField@Neko_Bytecode_AccIndex@Hashtbl_iter@Neko_Bytecode_Shr@Hashtbl_find@Core_None@Array_create@Neko_Bytecode_UShr@Neko_Bytecode_IsNotNull@Core_fst@Neko_Bytecode_AccFalse@Neko_Bytecode_AccNull@Neko_Bytecode_Push@Neko_Bytecode_SetStack@Neko_Ast_iter@Neko_Bytecode_MakeArray@Neko_Bytecode_AccArray@Neko_Bytecode_Compare@Neko_Bytecode_AccBuiltin@Neko_Bytecode_Call@Core_Some@Neko_Bytecode_IsNull@Neko_Ast_This@Lexer_null_pos@Neko_Bytecode_And@Neko_Bytecode_GlobalVar@Neko_Bytecode_AccStack0@Neko_Bytecode_Add@Neko_Bytecode_AccStack1@Neko_Bytecode_Loop@Neko_Bytecode_GlobalFunction@Core_string@Neko_Bytecode_Trap@List_map@Neko_Bytecode_GtXEnvXStackXGlobalXFieldXIndexXArrayXThis*uXEnvuXStackuXGlobaluXFielduXIndexuXArrayXThisuErroruuvvStack alignment failurewwxxxyByiyyyyyNzzzzzBreak outside a loopzContinue outside a loopzzarray{>{{|-|applyL|k|0Variable declaration must be done inside a block|neko/Compile.nml|}2Label is not supported in this part of the programDuplicate label *}n}tnulltinttfloattbooltstringtobjecttarray tfunction tabstractKInvalid access(Unknown operation"Jo}istruenottypeofhashnewcomparepcomparegotoUnknown label [throwɖInvalid $goto statementaconcat֗call$tmp $#Break in try...catch is not allowed&Continue in try...catch is not allowedo:Label failure %d %d %s %s9<Р _mϯ9neko/Compile@Map@Core@Core_compare@Core_@print_union@Core_@compare@Core_throw@Core_assert@Core_Not_found@Core_invalid_arg@Core_maxNodeEmptyNode!;d core/Map.nmlMap.remove_min_bindingmŵε޵Ͷ?f*'Map@Neko_Bytecode@Hashtbl@IO@List@Array@String@Buffer@Core@Array_make@IO_read_byte@Core_@print_union@List_iter@Array_create@Hashtbl_find@String_make@IO_write_i32@Core_assert@IO_read_ui16@IO_read_i32@Array_iteri@Core_@aset@IO_read@IO_write_ui16@IO_write_string@Array_iter@String_length@Buffer_create@Core_invalid_arg@Array_get@IO_printf@IO_read_char@Array_init@Array_add@IO_write_char@Buffer_add_char@Array_set@IO_write_byte@Hashtbl_add@IO_write@Core_@aget@Core_@pcons@Core_Neko_error@Buffer_string@Core_sprintf@String_escape@Array_length@Core_throw@Core_@empty@Core_string@Core_error@Hashtbl_createAccNullAccTrueAccFalseAccThisAccIntAccStack AccGlobalAccEnvAccFieldAccArrayAccIndex AccBuiltinSetStack SetGlobalSetEnvSetFieldSetArraySetIndexSetThisPushPopCallObjCallJumpJumpIf JumpIfNotTrapEndTrapRetMakeEnv MakeArrayBoolIsNull IsNotNullAddSubMultDivModShlShrUShrOrAndXorEqNeqGtGteLtLteNotTypeOfCompareHashNew JumpTableApply AccStack0 AccStack1 AccIndex0 AccIndex1 PhysCompareTailCallLoopAccNullAccTrueAccFalseAccThisAccInt(AccStack5AccGlobalBAccEnvOAccField\AccArrayAccIndexiAccBuiltinvSetStackSetGlobalSetEnvSetFieldSetArraySetIndexSetThisPushPopĿCallѿObjCall޿JumpJumpIfJumpIfNotTrapEndTrapRetMakeEnv,MakeArray9BoolIsNullIsNotNullAddSubMultDivModShlShrUShrOrAndXorEqNeqGtGteLtLteNotTypeOfCompareHashNewJumpTableFApplySAccStack0AccStack1AccIndex0AccIndex1PhysCompareTailCall`Loop GlobalVarGlobalFunction GlobalString GlobalFloat GlobalDebug GlobalVersionqGlobalVarGlobalFunctionGlobalStringGlobalFloatGlobalDebug GlobalVersion Invalid_file(Invalid_file37Field hashing conflict  and /XNeko.Bytecode.write_debug_infosb5NEKO Neko.Bytecode.read_debug_infosNeko.Bytecode.loop8neko/Bytecode.nml/Unglobals : %d  nfields : %d codesize : %d ops , %d total  GLOBALS =  global %d : %s  function  nargs string "float debug %d ops %d bytesversion O FIELDS =  %s%s%.8X JCODE = %.6X %6d %s  AccField  AccBuiltin  SetField END dneko/Bytecode@Neko_Xml@List@Lexer@String@Neko_Ast@XmlXml@Core@List_iter@String_split@String_concat@Neko_Ast_Builtin@Neko_Ast_EConst@Neko_Ast_True@List_rev@Neko_Ast_String@Neko_Ast_ESwitch@Neko_Ast_EBlock@Core_@compare@Xml_attrib@String_unescape@String_length@Neko_Ast_EVars@Neko_Ast_EBinop@Neko_Ast_EWhile@Neko_Ast_EIf@Neko_Ast_Int@Neko_Ast_Float@Xml_Node@Neko_Ast_Null@Core_int@Core_@pcons@Core_Neko_error@Neko_Ast_EField@Neko_Ast_ECall@Core_throw@Core_@empty@Xml_node_text@List_append@Xml_node_name@Core_@print_union@Neko_Ast_ETry@Core_None@Core_assert@String_sub@Xml_firstNode@Neko_Ast_EFunction@Neko_Ast_NormalWhile@Neko_Ast_DoWhile@Neko_Ast_EObject@String_get@Neko_Ast_EReturn@Neko_Ast_s_constant@Core_invalid_arg@Neko_Ast_ELabel@Xml_nodes@Neko_Ast_Ident@Neko_Ast_EContinue@Neko_Ast_ENext@Core_Some@Neko_Ast_EArray@Xml_parse@Neko_Ast_False@Neko_Ast_This@Neko_Ast_EParenthesis@Lexer_null_pos@Neko_Ast_EBreak@Core_string@List_mapmErrorx neko/Xml.nmlp:Neko.Xml.errorifsvbgcaonextobjectlabelnekocaseUnknown node name : Neko.Xml.parser*eneko/Xml@Xml@List@IO@String@Buffer@Core@Core_@print_union@List_iter@List_find@IO_write@String_concat@List_filter@List_hd@String_lowercase@Buffer_string@IO_write_string@Core_snd@String_escape@Buffer_add@Buffer_create@Core_invalid_arg@IO_printf@List_mapPCDataCDataDocumentNode*PCData>CDataKDocumentXeErrorp@parsero:0}C@parse std@parse_xmlo Xml.firstNode Xml.nodesB Xml.node_name Xml.node_text? Xml.attribP<%s%s="/> Xml@Neko_Console@IO@Hashtbl@Neko_Compile@Lexer@Neko_Parser@Array@String@ReflectReflect@Stack@Neko_Lexer@Buffer@Neko_Bytecode@Core@Neko_Parser_parse@IO_input@Reflect_module_get_global@Hashtbl_find@Lexer_line@Stack_dump@Core_nprint@String_sub@Neko_Parser_error_msg@IO_close_in@Core_fst@Reflect_neko_value@Hashtbl_replace@Neko_Lexer_error_msg@Neko_Bytecode_write@Reflect_module_read@Array_iteri@IO_write_string@IO_read_all@IO_read_string@Reflect_module_set_global@Stack_exc@String_length@String_get@Buffer_add@Buffer_create@IO_stderr@Core_print@Lexer_input@Neko_Compile_compile@IO_printf@Buffer_add_char@Lexer_create@Lexer_source@IO_read_file@Reflect_module_execute@Buffer_string@Core_Neko_error@IO_stdout@Neko_Compile_error_msg@IO_read_line@Neko_Bytecode_read@IO_stdin@Hashtbl_createS> #load @console  Exception : e2neko/Console@Neko_Parser@IO@Neko_Binast@Lexer@Neko_Xml@Neko_Ast@Neko_Lexer@Buffer@Core@Core_@print_union@Core_stream_junk@Neko_Ast_ETry@Core_None@Neko_Ast_Keyword@Neko_Ast_Default@Core_stream@Neko_Xml_parse_string@Lexer_punion@Neko_Ast_EConst@Core_fst@Neko_Ast_ESwitch@Neko_Ast_EFunction@Neko_Ast_NormalWhile@Neko_Ast_DoWhile@Neko_Ast_EBlock@Core_Stream_error@Core_stream_pos@Neko_Ast_EObject@IO_read_string@Neko_Ast_s_token@Neko_Ast_EVars@Neko_Ast_EReturn@Buffer_create@Lexer_input@Neko_Ast_EBinop@Core_stream_token@Neko_Ast_ELabel@Neko_Ast_pos@Neko_Ast_EContinue@Neko_Ast_Ident@Core_Some@Neko_Ast_EWhile@Neko_Ast_EIf@Neko_Ast_EArray@Lexer_create@Neko_Ast_Int@Neko_Ast_EParenthesis@Lexer_null_pos@Neko_Binast_parse_from_string@Core_@pcons@Neko_Ast_Eof@Neko_Ast_EField@Core_Neko_error@Core_snd@Core_throw@Neko_Ast_ECall@Neko_Lexer_expr@Core_string@Core_@empty@Neko_Ast_EBreak@Lexer_token UnexpectedUnclosed Invalid_nxmlUnexpectedFUnclosedSInvalid_nxml`mErrorx Unexpected  Unclosed Invalid nxml (      !#6%O&&_')))*neko/Parser@Neko_Lexer@Hashtbl@List@Lexer@String@Neko_Ast@Buffer@Core@List_iter@Neko_Ast_Default@Neko_Ast_Keyword@Neko_Ast_Semicolon@Neko_Ast_BraceOpen@Neko_Ast_Function@Neko_Ast_ParentOpen@Neko_Ast_BracketClose@Neko_Ast_Builtin@Lexer_punion@Neko_Ast_True@Lexer_char@Neko_Ast_String@Neko_Ast_Return@Neko_Ast_Continue@Neko_Ast_While@Lexer_current@String_length@Neko_Ast_BracketOpen@Core_chr@Neko_Ast_Try@Neko_Ast_Int@Neko_Ast_Float@Neko_Ast_BraceClose@Neko_Ast_ParentClose@Neko_Ast_Null@Buffer_reset@Core_@pcons@Core_int@Core_sprintf@Core_Neko_error@Neko_Ast_Switch@Lexer_build@Core_throw@Neko_Ast_Do@Core_@empty@Neko_Ast_Binop@Neko_Ast_s_keyword@Core_@print_union@Hashtbl_find@Neko_Ast_Dot@Neko_Ast_Arrow@String_sub@Neko_Ast_If@Neko_Ast_Else@Neko_Ast_Catch@String_get@Buffer_add@Neko_Ast_Ident@Buffer_add_char@Neko_Ast_Break@Neko_Ast_Const@Neko_Ast_False@Neko_Ast_This@Hashtbl_add@Lexer_empty@Neko_Ast_Comma@Core_ord@Neko_Ast_Comment@Core_Exit@Lexer_data@Neko_Ast_Eof@Buffer_string@Neko_Ast_Var@Neko_Ast_CommentLine@Lexer_token@Lexer_curpos@Hashtbl_createInvalid_characterUnterminated_stringUnclosed_comment Unclosed_nxmlInvalid_escaped_characterInvalid_escape*Invalid_character8+Unterminated_stringUnclosed_commentUnclosed_nxmlInvalid_escaped_characterE+Invalid_escapeR+Error]+Invalid character '%c'Invalid character 0x%.2XUnterminated stringUnclosed comment Unclosed nxmlInvalid escaped character %dInvalid escape sequencen++,,#,A,Z,[a-zA-Z_@][a-zA-Z0-9_@]*[-!=\*/<>&|^%\+:],,,,Continue,,,---%-0-;-\[F-Q-\-[ ]+0x[0-9a-fA-F]+[0-9]+ [0-9]+.[0-9]*.[0-9]+h-------b./\*. //[^ ]* ?$/?8/L/\/l//\*//\*/[^*]+//\\"0\\\\0\\n10\\tG0\\r]0\\[0-9][0-9][0-9]000[^\\"]+0000[^<]+1neko/Lexer@Reflect@List@Core@Core_@print_union@Core_magic@Core_invalid_arg@List_mapVNullVIntVFloatVBoolVStringVObject VAbstract VFunctionVArray<<VNullVInt<VFloat<VBool<VString<VObject<VAbstract=VFunction=VArray"=@module_readstd@module_read@module_namestd@module_name@module_exportsstd@module_exports@module_loaderstd@module_loader@module_execstd@module_exec@module_nglobalsstd@module_nglobals@module_global_getstd@module_global_get@module_global_setstd@module_global_set@module_code_sizestd@module_code_size@module_read_pathstd@module_read_path Reflect.value/=8==f>n>y>>>>>>>???%?=?Reflect@Stack@IO@Array@Core@Core_@print_union@IO_stdout@Array_iter@IO_write@IO_printf CFunctionModulePosoACFunctionModuleAPosA@make_stackA,B7BCalled from a C function $Called from %s (no debug available) Called from %s line %d BBBBStack@Neko_Linker@Hashtbl@IO@List@Array@Neko_Bytecode@Core@Array_make@Neko_Bytecode_JumpIfNot@Array_list@List_iter@Neko_Bytecode_op_param@Core_None@Array_map@Hashtbl_find@Array_create@Core_assert@IO_close_in@Hashtbl_replace@Core_Error@Neko_Bytecode_write@Neko_Bytecode_AccNull@Neko_Bytecode_GlobalDebug@Core_@compare@Neko_Bytecode_Push@IO_close_out@Core_print@Array_index@Array_get@Neko_Bytecode_SetGlobal@Core_Some@Neko_Bytecode_AccBuiltin@Neko_Bytecode_Call@Array_add@Neko_Bytecode_AccGlobal@Array_set@Core_ignore@Hashtbl_add@Core_@aget@IO_read_file@Neko_Bytecode_GlobalVar@Core_@pcons@Neko_Bytecode_GlobalVersion@Core_Neko_error@Core_snd@Core_throw@Array_length@Array_append@Core_@empty@Neko_Bytecode_JumpIf@Neko_Bytecode_GlobalFunction@IO_write_file@Neko_Bytecode_read@Neko_Bytecode_Jump@Neko_Bytecode_Trap@Hashtbl_createFile not found : DE=E&Linking modules with different versionFFF8Gneko/Linker.nmlloader loadmoduleRecursive loading Cannot link not constant fileexportsoGaKKKNNneko/Linker@Neko_Doc@IO@List@Lexer@String@Xml@Buffer@Core@Core_@print_union@Core_stream_junk@List_iter@Core_None@Core_stream@String_split@Lexer_punion@String_concat@Lexer_char@Core_fst@Core_Stream_error@Core_stream_pos@Lexer_current@Buffer_add@Buffer_create@Core_stream_token@IO_printf@Core_Some@Xml_parse@Buffer_add_char@Xml_to_string@Lexer_empty@IO_write@Lexer_null_pos@String_escape_char@Buffer_reset@Core_Exit@Core_@pcons@Lexer_data@Core_int@Core_Neko_error@Buffer_string@Lexer_build@Core_snd@Core_throw@Core_string@Core_@empty@Lexer_token@Lexer_curposTBase TAbstractTCustomTFunTOptTStarTMultTObjTNamedTPoly TFunctionPTBaseUQTAbstractbQTCustomoQTFun|QTOptQTStarQTMultQTObjQTNamedQTPolyQTFunctionQQFunction$RDocument8RBeginEndQuestion DoubleDotPOpenPCloseBrOpenBrCloseFieldQuoteSharpDocEREofBeginEndStarQuestionArrowDoubleDotPOpenPCloseBrOpenBrCloseCommaFieldOrQuoteSharpInt\SDociSIdentvS Invalid_char Unknown_type Unclosed_doc Invalid_docSUnexpectedSInvalid_charSUnknown_typeSUnclosed_docInvalid_docSErrorTT/****/->'#(TInvalid character  Unknown type Unclosed doc tag Documentation is not XHTML validTU$U0U/\*\*EUQU[^/]+]UhU\*\*/}UUUUUUUUUUU\?UV VV[ ]+VV$?[a-zA-Z_@][a-zA-Z0-9_@]*V8W;WVWuW~WXY0ZintfloatstringboolanyvoidnumberZlist'_`abb'%s#%s ->  | Lcc%s :  %s function:%d^de  4f ]f' %s :  . %s(f  ghneko/Doc@Sys@List@Array@String@Core@Array_make@Core_Some@String_split@Core_None@String_concat@Core_assert@List_rev@sys_exit std@sys_exit@get_env std@get_env@get_cwd std@get_cwd@exe_pathstd@sys_exe_path@sys_file_typestd@sys_file_type@sys_read_dirstd@sys_read_dirprp\ core/Sys.nmlpqqstd@sys_exists$q std@put_env?q std@set_cwdEqdirKqWqSys@Args@List@Sys@Hashtbl@Array@Core@Sys_exit@Core_int@Core_@print_union@List_iter@Core_Neko_error@Hashtbl_find@Array_length@Core_throw@Core_print@Hashtbl_add@Sys_args@Core_@aget@Core_printf@Hashtbl_createVoidrVoid0sString=sIntJsInvalidWsInvalid Options :  %s %s bs|ss-help--helpssInvalid argument : suArgs6neko/Mainneko/Main.nmlIOcore/IO.nmlStringcore/String.nmlListcore/List.nmlArraycore/Array.nmlCorecore/Core.nmlBuffercore/Buffer.nmlneko/Printerneko/Printer.nmlneko/Astneko/Ast.nmlLexercore/Lexer.nmlLexEnginecore/LexEngine.nmlHashtblcore/Hashtbl.nmlneko/Binastneko/Binast.nmlneko/Compileneko/Compile.nmlMapcore/Map.nmlneko/Bytecodeneko/Bytecode.nmlneko/Xmlneko/Xml.nmlXmlcore/Xml.nmlneko/Consoleneko/Console.nmlneko/Parserneko/Parser.nmlneko/Lexerneko/Lexer.nmlReflectcore/Reflect.nmlStackcore/Stack.nmlneko/Linkerneko/Linker.nmlneko/Docneko/Doc.nmlSyscore/Sys.nmlArgscore/Args.nml{"@f>f>jR>Z>b>Z>b>Z>$Z>>v>>J>4^r>N2tv^j>Nf*$vf^Z>Nf*$v^>Jz*L>vfv^4 <>Jz*$vfr>N^^>Nf*$zz>>F&$Z>>vT^bbb>Njvb>fv>"" 0>bnn.D>>>>n&>>>Jj*6<>F*t~~>Vr~rr`RD.< x>b& Zj.*D>F*D~&$&T6F p<$2$^>>j>$v^^VVb>Jzr,v^^VVJf>J>rr>>"T~:>ZNJN>*x>"4x>\ZJNbz:>"D>lZ^bb>:$Z^2$Z^b>$Z^fn,bf&8ZZZ"T  D"$> $>V:$^>>j>$Rfb>Jzr>,^rr:$>Vb:$>V^*$>Vbr:$",bff& ZZZZ"$> " ZN^nDbv$>&$>>&$vv$vv<>Z&>$fj>ph>TV*$6$>>z   $,&4>6<*tn>>>b***$&,&&4>>6<*L2ph>>&$Z^VVb>r>Fr>>>>>>>>>>>>>>>>D6hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hd>R>F>Fr>>Vb>>~z>hT6h:h46h$6hh@>@@f>,ZvV>Jbr>>r>$ZvV>Jbr>>r>L$* "PNZ>$NN>6,>ZH> H<>Z&<>Z&<>Z>><>Z(>&(<>npp`"<>^&j>&`>Z&z>>.L>Z0>:0<>Zh>>h<>Z&>>&<>Z&>><>Z&>:<>ZH>:H<*$>Z>><>Z>>D>Z>.N><2$ZN>^&x>x<>Z>:D>Z>:L>Z&8>>8(N:Z>>>d>Zv>>Z">>Df.Zf*"JNVN^>V^^b4><$6,JVn>F>Rb:,&$:,ZN^b:4ZN^v:4NNV^j6F:4>4NVV^^>4NNV^z6N>.4>4NVN^>^N&"X >>>>*<>n>r>>F>rzz:ܞN>V^NbN^>J^^b*$ZNNrZ^^^>>Fb$Z^RNb^>J^^b"$nRfbbZZNR>FbN^>z^NfJR>FbbN^Z~>>N^N>Fj$~jR>>D $$:$2$NN$Zv$Zv$ $>V$$$2$$2$>$>$&$:$RZZ.,^RNjr>V^zZ.,fv^>fZ^f6<X > >>,>J>N>N>N>N>N>x44bR^^$ $$$$$ $44 $, $ $$ $ $ $ $ $&$ D>>>>>>>>>>>>>6 ~$$ t $ $dd d dt 4 ldD 4>>>>>>>> >>>>:44Z>< < <>>>.<><>>L><><><><:<6<$>>*<><>\>L:D6D d> <>>>>>>>>>>>*  "($&$$z~~~~>$ $ $ ,JN>>> >>>>:dJ4 $ $ 4 4< $&d66x*l*tz$>>>>>>>>> >>>>>>>>>4<>J>N>N><,jnnnnnn:D&, >L&, rvbb"< D $ $ 4 l tD4<T \ L $ $, 4 \<4D< $ D>>>>>>>>>>>>>>>>>>>>>>"8J N"$V>^&$>Z>$V~>*\>dVZj&Vz>^j2>Z2>~Z>2 VZjfZ6@Vn>>>>"P$ff> 4fZ:PV>PVj>F>PXVjZ>Pf>"D Lf.P>>fZ>P"frjZ> P28f^>n>^Pj>P&P2fv~>Pf>nj>P2R>zv~v>>&P>.P f:P>8.PHf2PpVj^2P&&P&f&>>|Rf>PP> P2`f^j^> 4 <>ZjfZ>Df>P Z>>F> (&,~jfrf*(&db>Jz&(nZj&>> 4&T.|r^f^*>!"# >>>>>>>>>>>>>"d>>>>>>>>>>>>:>>>>>>>>>>>>>>>>>>>>>>><>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>2,>$>$>.$> $> $> $> $>\V>^> &l>R>*X`>>>`N>`>`>`$>2`,>"`<,2`2l>>`2t>>>>>`2|>>`>`2>>`>2>L`>2>D.`>"`>4`2>>>>>.`>>>Lr>PV>>> XN6X*X2X$>X,> X4> X<> X2D>>>>XL> XT&X\> X>2d&LX>2l&D&Xt> X|> 4 X2>>>>2X>nRRR(,&(4(<> (D"(L(t>>RRRRRRRRRRRRR>>jRRRRRRRRRR(d&(l&(t(|2("(%"'>"$N,J~>D $J^NhNbNN@8$$Z^ff^^^"fzzVf>fVZ>nvvrr$Z^rV:,Fbvvf2>"<:>Fn^^^^z>RR^^V>N>vf>^vfvVb>VX^bb"P,>> d>Fj:>>,br>\>lZ>$>>>>^>JX>)"+h @>>>>>>>>>>>:$~ >>>>$^>>Z>>^.>*T&>Z>> h>>>hXN>4>v2>.<>&$>DJ &<>n>&$:,>>$^>^D^j>vl^j>v>"^>>>F&>*R>>"D>>>>>>>*>>R>b> @>>^>X>>4>"$>.>D~ &>"L>^f>.dF:(>"$Nrv>R(:d\>fJ:>"$Nrvz^r>F>>J>>2$>>>>0R8:Z^^VVVV:>> R>Jr>J<>V*DjRb>Z>j*4 <,jRn>JZ>f:DzH.4>^>$>>>J> $2$fn>>>:<( <( <( <( <( <( <( D( l>J:  <>J:  <>J: & fN^>f>^>. ~r>  D>V>f>.X ^>>X p RVbbrr>>~6 6 6 , >>n^r>v>"  >>  >*  -"/$"$$vn$:$:$:$>$*> $ $ $ 4 $ $ $ $>>>>-+>>>>>>>>>>>>>>>>>4>>>>>>\N>$> |l&$&4 D><:$>. d>,*, $|>6<:<6< <>>>>>>>>>>>>>>)'>>>>>>>>>>:<4>NL $ $ d L $ L"d,*8 T>>>>>>>:%#>>>>>>>>>>>>>d>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>,>>>>>>>>>>>>>>>>>>>$ $ $ $ $ $ $ $ t >>>>>>>&!>>>>>4 D ,, D>\$>>* >2|>>>>6"1"3 .,^^bnj>&$Zb>> ,>>R   $,.4.<*D*L*T*\.>>>>>V H H H$H,H4H<HDHLHTH\HdHlHtH|HHHHHHHHHHHHHHHHHHHPHX.HZ>4^b*^.$ ,b> $r:^b*8^^>Vf>Jx>>>>2x$>&x4>&xD2xTb>xlb>:xb> x6,>&xbf6xbf6xbf>xbb>x>R> x^ff>xx> x(x8> xHxXbf*xx>"x>"x.x>x>x>J> xb>:x.x&8Z 0$>^*>>>>>>>>>>>>>>>>>>>: 4\> L x>>,>\6<>>" >>>>>215"7 >>>>>>>>>>>*X>>$ $>>>>>>>>>>>>N`x""2.N""".>>>>.">">$&$f>>V>J>0>nz>J06D^> ,>Fv>Z2<>>Zz>L>>"Zz>L>>XZz>4>"$JJ>>"$bzr>dNRVf^^> $.hVn*$.nnZ*$~>~>$>>,V>z^z >$ R< LZz>>j>F> r>,~>T~>0 ~> J>^ > $>J>n $ $ 4 h V>TVv>Fv>>>>h >R>Z*h >,>>>>: b>F $> $~>>6 Z>>>>( ( $~>>>( ( $~>& >t>R:4 h >>> r>^>Fv>>>jv>F>^V^v>Fv:> N:TZ>F>Fv>F>". >h >>>>" >F>"` r h > R>>v>>fVN 4>>>> ^>>>>> ~>>>~v>, 4>Z > $> >nrrr2 ,> 4>> <>> L>>>>r> > > $: ,: 4: <: D: L: &\>  FvfJ> >Vv>V 6D>b>>:p >"~>p > 0>>>JvfJ>X>Vv>VX6D2@>"|~"@20H0> rj0>>>rj0>"rjvj 0&X:0>n>>*>$> ,>2.d>n>>*>$> ,>j~2.|>>>>>>>>b*X*X*X$&X,&X4&X<&XD&XL&XT&X\&Xd&Xl&Xt&X|&X&X&X&X>>>>>>>>nv.4rjz\rjzfVnf>Zjv>>Nf~> fVnf>Zjv>>Nf~> Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.Hjfjv>>N.>>>>v*>>Dr*>>.,r*>>\r*>>>>>*t>> >>&rjv6r>&t>^2`\Z, pJhdRP$Nr>^>Fj>>r>jv>F> h$z>>>>>F>.><>zZ>~f.TRj>N:\>^>b>>>>tf>,r2>>>>>>v*>>:,r*>>:Dr*>>:\r*>>:tr*>>>>rjv*>>>>6rjv*>>>>>">>>>j:4>f"$6<D>>R>f^>j>2X>X$>Dx>&>*>>T>>~>>Vfvp$$r>>> $r^>">  $>JR>>>>Z2>:>>>$v:>> r2Dr2V>^2>$f>.(>z2Vjvz:4\V>vZ>&t V>ZzT$Vjjvj> >VVj>>>>&$&&4R>&dV>~v6> r>>>>>>>>>>>>>>>>f>N>>>>>>^>V>J>>z>>>>v~&6L>>>>&>>>>>>2>>> $rj~>>H H$rR>>>*>>r>>>"rjv>6<>> ^>RvjbvZjZ:"x^>RbvZv>f>2Rvjzv>"$^Zzv6.2@^VV^^>^v>v>v^Zj>>>jbZjV>^z~Z>>2>>>>>>vVV $>^2X>ZX>X$nV>b>>rV>b>> r>&f*&(>NJ>0>>r~06>>>>Z>>>>>fnZ>>>>>>>>> Fzvzj(>N H>b2`>`$^> L TV>>"rj> 4 <>^28 >>.8 $^>$ ` ,Vf> >!~>vf6$~>4zj>@"Vjj~:$`"  ^^ "T ,@!$Z(!JN< P!J$Zb!>bvnZ>~RR^^Z^~:$&!,>Z^~f.L@"Tf>b:>9";>>>>> \>jV8<>>2$^^j>>>>>R>>>>>f:.,6Tj>>>>>R>>>>>f:.,6T>>$>>jpn.pD>>V>>>J.D~ $r>"d HD 4>4>>n>v^f>f>>>">2`D>>n>J>F. >\*4>>n>R>>>>V  >2\hD>>n>>^ >D*,>Z>bj>N> L&,>Zp>ff>>&p`N> \"<>Z>>>&N> <6>>>*>>,, <$">D>D.T < < $ * l l >>>>>>>*972="?>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> L*4$>>>>>>>>>.h: h>  h h> h">>>>:h:h  >>>$ZJn>>>>":.$ZJn>>>>":.$ZJn>>>>":L|v>2Z^:d lR>V`$>J:>4bf>Nr^>V>n^>$VbZZV>J>zb^z>zz6$N^r^V>N>^~~VV>"|> *T>f>>>>2>>$>> ,>64>TbV>>>>>>>>>RRRR@ ,.@ 4>@ <.@ D.@ L>F@ \>@ d>@ l.@ t.@ |.@ >F@ nR@ .@ .@ .@ >>@ >>@ >>@ >>Z@ .@ .@ nRRRRRRRRRRRRRRRRRRRRRRRR@  .@  nRRRR@ @ >^*@ X J^>F>Z>vz>N>N6Vj>N~~f:L T $> 0 & ^^f.  >L"|"4ZbnVb>Z>RZrnZjVb>jr>Fn>F>Vbb>r>V>H R^Vb>z>NbVV>@ >> V*d>2X$^>X<^>XT.Xdv*X|.XXZb^Jn>0>",r20>HfzZ>>>>>b>p>p>p.$>p,&p*L>J>:Fnzbbb>>>Z>>.V~VV^fb>Z.>>>$>,&"<>>>>>>>>>N   $,4&<DL>>>>T\&d>>>>lt|>>>>>>>>>>>> (08@HPX`hpx> >N>j>F>R","DhL&, 4.>>> XV>n:`>n>:`,> `46`Drr>>`d6` X*>>>>>^>>>>>>>>>V& & & .$" ., .4" .< .D" .L" .T" .\ .d" .l" .t" .|" .6 .6 .6 .6 ." ." ." ." ."  2>.V>N>N>N>brf> PnrNV> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>L>N$ " : t> >>>>>>=7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>TDT>$ $ $ $ <&D*D*D*$ l T , 4, $ >" *(>>>2x>d>|>>>@>2>>>>>>" >>>>>>>>>>>>>> 52A"C>Jn>>N*>2> $>n20>> 0"tpRh&>":"$>>>>>>$H>>>F>>>>:d6>6T>>>>N>&> $>D>^>.\>^>n>D>>>>>>>>>>>>>F> ,j> Dj>" \j~>>b>>b222$.4> >> >* j>> >r">>> 0 X @"@* h x >>>>N>>>>>>>> j6 j6 >N>> >>>F>>>> >>>F>>>> 0 @ ` P"P* pj6 RVV>"|>^" >>  H>^& &`> Z>>f&> V>>>>>> H>>>64>>>> ^VVV>>>>20Z>0Z>0Z>TZ>lZ>Z>0Z>0Z>Z>*Z>>Zn>>Z>>> Z>>>"Z &>>@Z>>>""XZ>>>22pZ>>>>>>>&2Zr>>>*Z>V>>2Zr>>>*Z>>>>&Z>>>>&(Z>>>"@Z>2XZ>2pZ>R>>>>>>>6f>~j>N>>>v>2$*>E"G >>>>>>>><>"\>>^^JN^Z>r>RRR>>r2(RVVl*|RJj>bn24fVv>XN6X<>Vv>N6v& n&  ^, 4&T>xZ~>d>>>:,>>Nj*>>*&6>>N>trf& >>>>>>>>>>>>>><>$ :$ t < < 4<< < | D> t>>>>>>EC>>>>>>>>>>>>>>>>>>>>>>>>: >>&D> >>>AI"K`^^>j>jj.>\R*$>> hJn>x>"$x2h&Dh>H&$HZ>>^f^Zj^Z^r>N^jvf6>b.\`lF>J.> ,Zf^z$"6|*<@hZ:JJ*>>>6>$2>,2>*>M"O>>>>>>4>>R:&>D:$>>>>>>>>>>>>>>>~ xV xV xV xV xV xV xV xV xV xV xV x x x x x$x$x$x$x$x$x,x,x4x4x<x<x<xDxDxDxDxLxt$^>b>N~>>&>,>>"\j2h>>V2h>>R6h>>>2h>>h>>> h>>>>>b2>>R>>:>>>>>*>>>>>>>>>>>Z>">:>>>>&<>>>>D.>>L>>>J>">>>>>>>>l.>>t>>>J>6>>>>>>>>>*:>>V>6>>>>>.>>.>>>>">>>>>.>>>>>>.>>>>>>>>>>.>>>>>.>>>>&>>>>>>>>.>>.>>N>><>>>>>>>.>>>>>R2>>R>>>>>>>>>>>>n2>>N>>>>>>>>>>*n2>>N>>>>>>>>>>*@:>>>>2H.>>>>>>>>>>2H.>>P>>">>>>>>>X.>>`>>>>6>>>>>>>>>>>>>2>>$>>>J>>>>>>>>>>D*>>L>>>J>>>>>>>>>>>l*>>t26>>>>>>>>>V.@>>Z2@>>R>"@>>>>2@>>>>@>>:@>>2@>>>@>0> <.0>>D0>lj.>>V2>>R6>>>2>> >D>>>>>>>b.>>Z2>>R>>>>>2>> >Dj.>>>>~.>>Z2>>R>6>>>>>>>.>>2>>Z>^z>&0>:<>d>>>>>b2x>>R6x>>>2x>>x x>Dj.>>V2>>R6 ><>>>N.>>R ><>>>>>>>>>b.8>>Z>8>>R>>8>>8>>>68>(>6T>>>N:x>>Rxx>Ln>>&$Z&>TFv> >"$>.>LZr>^*>"Q"S(>>>>>>>> L>>j>>(>NRR(4r(d>,>4.$>:$>&$Z>>>>>d.$.$>nnnnnnnnnn24Z>^>>F>F>F>F^^Z>>>>Vb>>^^Z>>>>Vb>^^>j>>>V>V>F>>r2>DJ>n>n&$vzzzz>b>V>NnN>nv>r>n&>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>L>d ,Z^>>>>>>>>>.$$$*,Jfff$$$>N>F>F>F>F>F>F>F>F>F>F>Fnnnn>,~>F>F>F>F>D>D>4>b>f>F>>>>>>>>>>.Jn>F>>R4J>$>$>$>$>$>4~n>>>>R((Jnn>>R(>>>>>>>:QO>>>>>>>>>>>>>>>>>>>>>& >>>4>D $ t $>>>>:d>D>>*>6>*l>D>D>d>D><><> T:<*>>>>>>>>MK2U"W>>>>>>>>>>>>>>>> ԮV^^^^^^^^VNfffffff><>nP*P*P$&P,&P4&P<&PD&PL&Pt$*$Z6$*46,FVV^b>,$2$2$2$$:$Z> $>> >>>>>>>>>lz~~~~~~~~ t $$, $$ l $$$$ $$,>>>>>>>> UKY"[ >>>>>&\ZN^Z^Zf>Nv>4*$*,z2> >&4T>>>>>>>4$ $ $ T>>"YK>>>>>>>>>>>>>>>>>>: $>>I"]"_@8>Z>8J> PP> 8(N>L>d>fn4bn>rJ>8>"$bn8>F>8>"$bn8:V>F">JnZxfr>&,f>Zrb>Z:$br>>Z>^20>>>>>>>>>>>>>>>>>>>>>>>&d>>>>>r>^>.nr> &\.0>>>>>> >N>>>>"$>>2.4>.D2.T2.d2.t2> 0~>r>n>>fnv^VVV>  >>$>*4bjr>F>>>>>n>j~bj>f>X"$ p,>"X TRV:L2(>>.z>Z$>V>F>J>Jl>XZ^^xP"D>F>nj>F*>>>>>>>>>>>>>>>>>>>>>Tl>@>>]a"c >>>>>>>>>>>>>>>>>>>>>t>>>>>&<>>>>>>>>>>>>>>>>>>>>> >>>>>>>>D>>$>>>FRRTRRRRRRRR&> >^:p:pfRpT.,ZL>Vrr>Znnnnnnnnnnnn^bZ>>>>Rb>>>j>r>j>>r2@>*@r>>F>>>J >>>2>>>>>2>>6>><>>>>>>J2>>Z2>>R6>>>>>&<>>>~ >>N*P>4>>>>>~>>>>>>>>>>.$>>>>>$>>>>>>F>:L>>>R2>>R&>:>>>*>>.>>>>:> >>>>.>>>>:>> >>>N.@>>R>@>>>>@>>>>@>>>>$>@>>>>&,>@64@>\>>>N.>>Z2>>R6 ><>>>>>>J.>>R>">>>" >T>nZ&>&,F>@>>2@>>Z * >$jj> t>Zx >jj*x >2 x >>R6> > ,jj>Lf:df:|&>TR>&` >|R> r> f>0 >X jj*X 4&X \>J>Nd>z> ., >Z & >$fj>  >>R: 6,& :Lrv*h ,fj6 $>T>>n > $.h f>b0 >*0 $>  >`  >>>>>>>>>>>>>>>>>*>>>>>>>>>>>t>>,>>>>>>>>>>>>>>>>>>>,>>>>>D>$ T $ F>F>>R"04F>F>F>F>F>F>F>F>F>F>F>F>F>F>F>L~>F>>>>>>>R.`pFn>F>>Rp4>>><><.<>4>6>\> <> D>t>&P :\ 4>>>>>>>>>>*ae"gX8>>R88>>8D>>Rxf xx<>J>>V2T64Z>44$.$>>>>>z~~~~4 D < D4 4z:4 ,$$ $>>>>>>>e>i"k>>>>>>4*,Z>V^ &4"HRb^>RrrxJfrr>>>>b>&$~rr2L~rr>>>J2&>"~^Z^2>>>>>>>>> >>>4>L>6i>>>>>>>>>>>>>>>>>>>>>>>6RD t|2L*T6D**d L DFN>vVV>f>f>f>f>r>f>f>f>>>>>.4>>>:@>>>>2@>2@>2@>2@66@>>>>>>"newloaderloadprimrethrowsmakessetsgetsblitssubsfind@make@empty@consstringasizearrayamakeablitthrowasub@compare@print_unionnargsobjfieldsfieldobjgetinvalid_argintfloatprintgetposcacheNoneSomeNeko_errorInvalid_argumentAssert_failureErrorStream_errorNot_foundExit@print_record@aget@aset@pconsstream_tokenstream_posstream_junkstreamsprintfsndprintfordnstringnprintnekominmaxmagicignorefsterrorcomparechrassertsubsortsetmapmakelistlengthiteriiterinitindexcreateblitappendadd@rmaketlsplitrev_recrevphysnthnonememiter2hdfoldfindfilterexistsconcatchopassocallresetadd_subadd_charssizeuppercaseunserializeunescapeserializelowercaselist_depencyis_printableescape_charescapeOverflowEofClosedBlockedwrite_ui24write_ui16write_stringwrite_i8write_i32write_i16write_filewrite_charwrite_bytewritestdoutstdinstderrread_ui24read_ui16read_stringread_lineread_i32read_i16read_fileread_charread_byteread_bufread_allreadoutputinputflushfile_write_charfile_writefile_stdoutfile_stdinfile_stderrfile_read_charfile_readfile_outputfile_openfile_inputfile_flushfile_contentsfile_closecreate_outcreate_inclose_outclose_inhkeyhnewhcounthgethmemhaddhremovehsethiterreplaceremovehashEmptyMatchStarPlusNextChoiceInvalidRegexptransitionsstarsingleplusparseoptnodesnodenextmax_codemake_transmake_tablesis_emptyinvalidgroupescapeddeterminizecunioncintercemptycdiffccomplementcalladd_nodesadd_nodeInvalid_ruletokensourcepunionnull_poslineinc_lineemptydatacurrentcurposcharbuildTrueFalseNullThisIntFloatStringBuiltinIdentVarWhileDoIfElseFunctionReturnBreakContinueDefaultTryCatchSwitchSemicolonDotCommaArrowBraceOpenBraceCloseParentOpenParentCloseBracketOpenBracketCloseConstKeywordBinopCommentCommentLineNormalWhileDoWhileEConstEBlockEParenthesisEFieldECallEArrayEVarsEWhileEIfETryEFunctionEBinopEReturnEBreakEContinueENextEObjectELabelESwitchvar_argss_tokens_keywords_constantmk_stringmk_intmk_identmk_call1mk_call0mk_callmk_builtinmk_binopto_stringprint_listprint_astnewlinelevel_exprlevelparse_switchparse_stringparse_opparse_listparse_from_stringparse_fieldparse_expr_optparse_exprparse_constantheaderidivNoderemove_min_bindingmin_bindingmergeheightbalAccNullAccTrueAccFalseAccThisAccIntAccStackAccGlobalAccEnvAccFieldAccArrayAccIndexAccBuiltinSetStackSetGlobalSetEnvSetFieldSetArraySetIndexSetThisPushPopCallObjCallJumpJumpIfJumpIfNotTrapEndTrapRetMakeEnvMakeArrayBoolIsNullIsNotNullAddSubMultDivModShlShrUShrOrAndXorEqNeqGtGteLtLteNotTypeOfCompareHashNewJumpTableApplyAccStack0AccStack1AccIndex0AccIndex1PhysCompareTailCallLoopGlobalVarGlobalFunctionGlobalStringGlobalFloatGlobalDebugGlobalVersionInvalid_filewrite_debug_infostrap_stack_deltaread_debug_infosop_paraminullhash_fielddumpcode_tablesXEnvXStackXGlobalXFieldXIndexXArrayXThiswrite_optrapstack_deltaset_posscan_labelssave_breaksprocess_continuesprocess_breaksmake_arrayjmpgotoglobalget_cases_intserror_msgcompile_functioncompile_constantcompile_builtincompile_binopcompile_access_setcompile_access_getcompile_accesscompilecjmpcheck_stackcheck_breaksdocstackcdatapcdataxmldonePCDataCDataDocumentnode_textnode_nameis_pcdatais_nodeis_cdatafirstNodeattrib__listto_xml_recto_xmlparse_xmlparse_posInvalid_characterUnterminated_stringUnclosed_commentUnclosed_nxmlInvalid_escaped_characterInvalid_escapestrnxmlmk_floatmkkeywordsidentexprestringenxmlecommentcommentbinopUnexpectedUnclosedInvalid_nxmlvariables_nextvariablesswitch_casesprogrampriorityparameters_nextparametersparameter_namesobject_fieldsmake_binopexpr_nextblock1blockpathVNullVIntVFloatVBoolVStringVObjectVAbstractVFunctionVArrayvalueneko_valuemodule_set_globalmodule_read_pathmodule_readmodule_namemodule_loadermodule_globals_countmodule_get_globalmodule_exportsmodule_executemodule_code_sizeloader_pathasetaget__list_depacopycallstackexcstackCFunctionModulePosexcrunreportneko_pathlinkdo_linkTBaseTAbstractTCustomTFunTOptTStarTMultTObjTNamedTPolyTFunctionBeginEndQuestionDoubleDotPOpenPCloseBrOpenBrCloseFieldQuoteSharpDocInvalid_charUnknown_typeUnclosed_docInvalid_doctype_write_partype_writeto_htmlstatusmk_tokformat_xmldocumentationdocumentdoc_type_nextdoc_type_listdoc_type_fieldsdoc_type_basedoc_typedoc_tokendoc_optiondoc_docdoc_contentargsversionwithout_extensionwithout_dirset_cwdread_directoryput_envis_directoryget_envget_cwdextensionexitexecutable_patharray_dependencyVoidInvalidparse_argshelpverbosereleaseparse_multiformatoutis_nxmldircompleteL/`S6_L_LL9LLL!b L%b ^)^QLLLU^rL3LL bL!LLKVLcfI^LLLLKVLdfLL)L LKVLT^\LLLLKVLefLL)LLKVLT^0LL L LKVLffLL)LLKVLT^ILGLL9LLL%b L!b^zQLLXLF:^i)L3Lf)L!LLKVL9f)L1LXL0V^8^^)L1LLRL;LLL-L%L!L6VLH9R^9f iLL:VL=L)LL7VL)LjLVLLAVLL)L/VL41Rr9f lLL:VLLYVLLDLL-)LmL=VLLAVLL)LVVL4)R9f oLL:VL=LLpLVLLAVLL+L)L?VL4!RLLL!bLb^ ^sLZ^^sLZ^^9f rLL:VLLYVLLDLLL-L-tL)L*VLLjL=VLLAVLL-L-L/VL4AR9f vLL:VLLYVLL`L;LL-L-L%L!L6VLWL)L--LwL=VLLAVLL)L5VL41RLXL2VL!f8LLPL,V8LyL-LSV^!8LzL)LJLLL[zLSVL)rL3LL!fLL%LQVL/fLL%LQVL\f L|^L9L9L9L99LL=LT9LO9LLT9L9L9LLL!b L%b^$=L-L*^L>LLL%z^iL/`S7_LL9LLt! zLLLLLLL)LL/HoL#g%Zrrj9LLLL=Vl^$LLf LaL^L/*)r9L=j 9L=l^$LLf LaL^L/*L9LvLL=LvL)LLvzLf^L9VLL=!r9L=f LL=L9LVL-L-LL9LLV9L9L)r9L=f LL9LVL9L9L%!LLLLLLvLL-L-LLvzR9L=9L=L9LL=LvL)LLvL-LzLf^L9VLL=!r9L-L-L-LVr9LLLLLLL-LzLLLRLLzrLLL)LL)L!bL!b)Lb )L)Lf L-L-L-LCrL!f LL!fs^YLL!L)LL!f<)L)L)LVLL!f L)L-L)L)L)_)RrL!f LL!fs^LL!L)LjXL!fJLLL VLL!fL!f^LLL)LL)_l^FLLf LaLf$)L!f L-L!LLV^ ^L/*9RrLLLj"fLLL9VLV_Ll^/LLf LaLf )L^ ^L/*)RLLj5f%LLL f LLLV_LLVl^.LLf LaLUDf L^ ^L/*!L9LL9L)L9L-L9L-L-LL)LLLRL9LL9LLLRL9LL9L)L9L)L)LLLRL9LL9LLLLLL!f L^RLL!rLLQLLLF)LL-LzrL)rLLL)rLbLf LLLL9"r)LL)L!bL!b)Lb )L)Lf L-L-L-LCr!LLLL!f<)L)L)LVLL!f L)L-L)L)L)_RrLL9VLLL9VLLL9VLLL9"rL!bLf LLL9VLLL9"rLbLf LL!fLL)L9"^ LL9"rL!bLf  LLL9VLLL9VLLL9"rLULLL!rLLQL FL LLF)L)L)LVL9*r6L/`S7E_ L/jL!LLfLLL/%[VL%a_RrLL/ RVLLf %Lr)L)L)L/%[Vf 'L!rjLLLLL/(-Vl^Lf )L1r)L)L)L/2[VLLf +Lr)L)L)L/,VLLf  LrLL"VLLL#.Z!rrLLL!b L%b^P^MUL!fQL9LLVR^4^^QL)UL9L)LV9L=LVL1^LLLL)LL-L/va)LL)RrL fL~LLL b$L b%L b&L\b'L"b(^.^*2^X^"3^P^4^H^5^@^ 6^8^LL9f7LL!LV^^^L%LL=*L9L=f L^9LLVLLL b$L b-L b6L\b?L"bH^V^RL2LV^^BL3LV^q^2L4LV^a^"L5LV^Q^L6LV^A^LLfL7L)L!LVLV^^^LLLVL%LLLLL-L9LL=LLL9va!L!RL9LL=L!L!LLg< L)L/ RVLL\g)L-L%)Lf ;LL-L/ RVLLu^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_]____Q____E^v^t^r^p^n^l^j^h^f^d^b^`^^^\^Z^X^V^T^R^P^N^L^J^H^F^D^B^@^>^<^:^8^6^4_^0^.^,^*^(^&^$^"^ ^^^^^^^^_^ ^ ^_^___LL"L/%[V__LLf ;LLL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f ;L0L!LL!LLdL-L!L)L L)L!L)LLf ;LLL)LL/%[VR_ _LLf ;LLL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f ;L0L!LL!LLdL-L!L)L L)L!L)LLf ;LLL)LL/%[VR_K_BLLf ;LLL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f ;L0L!LL!LLdL-L!L)L L)L!L)LLf ;LLL)LL/%[VR__LLf ;LLL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f ;L0L!LL!LLdL-L!L)L L)L!L)LLf ;LLL)LL/%[VR__LLf ;LLL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f ;L0L!LL!LLdL-L!L)L L)L!L)LLf ;LLL)LL/%[VR__LLf ;LLL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f ;L0L!LL!LLdL-L!L)L L)L!L)LLf ;LLL)LL/%[VR_O_FLLf ;LLL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f ;L0L!LL!LLdL-L!L)L L)L!L)LLf ;LLL)LL/%[VR__LLf ;LLL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f ;L0L!LL!LLdL-L!L)L L)L!L)LLf ;LLL)LL/%[VR__LLf ;LLL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f ;L0L!LL!LLdL-L!L)L L)L!L)LLf ;LLL)LL/%[VR__ LLf ;LLL%L/ RVLLLL/ RVLLLL0bL9bL0bL9f ;L0L!LL!LLdL-L!L)L L)L!L)LLf ;LLL)LL/%[VR^S^JLL\L/%[V^A^8LL L/%[V^/^&LL L/%[V^^LL L/%[V^ ^;L^^^LL-L)L/%[VLL%L)L%_)L!L)LCRL9LL!L)L=VL!LaL!LAL!LLfHL)L/ RVLLAfLZf-L-L)L!LLL/%[V)L-L%_)RL9LL!L)L=VL!LAL!LaL!LLfHL)L/ RVLLafLzf-L-L)L!LLL/%[V)L-L%_)RL?L/HoLAE7L/`S7z_fH#MRLLTLHL#1iZfrL)L)LHL#1iZLV"rrLH#MRLVLLL!b L%b ^!^UL%LL9𭈥^LLL!b L%b^ZLR^ QL^LLL!b L%b^\LR!^ UL^LLL!b L%b ^0P^,QL)ULIL)LLL-L9VL%z^rLLL!b L%b^$^!QL)ULLLL9B^rLLL!b L%b"^y)LL!f^ ^^`LR9^\QL)ULLLL!b L%b^2`LRQ^)QL)ULL)L VLL)L9s^^rLLL!b L%b^PPLP^GQL)QL-ULL9LLLILL)L%zLILLL%zR^LLL!b L%b^)^&QL)ULLf^ LL9B^rLLL!b L%b^0^-QL)ULLLMVL!f^ LL9B^rLLL!b L%b^@SLO^7QL)QL-ULL-LMVL!f^ LL9^rLLL!b L%b^<SLO^3QL)QL-ULL-L!f^ LL9^rLLL!b L%b^/SLO^&QL)ULLf^ LL9^rLLL!b L%b ^*)^&QL)ULLIL-LL%zL9B^rLPL9LLL!b L%b ^+-^'QL)ULLL-LL)L9^rLLL!b L%b ^+)^'QL)ULIL)L)LL9VL%z^rLLL!b L%b ^')^#QL)ULLL-L9VL=B^rLL9L)LlvaLPL)"L!f^;LLL!b L%b^!nLR)^ULL%LL9:^rLLL!b L%b^)^&QL)ULLfLL9B^^rLLL!b L%b^)^&QL)ULLf^ LL9B^rLLL!b L%b^3rLR^*QL)ULL!f^LL%L9^rLLLsaL!f tLR)L)L)rLLL!b L%b ^?P^;QL)ULLfIL)LL-L9VL%z^ LL9B^rLLL!b L%b^/^,QL)UL9LL-LKVL%LL=B^rLLL!b L%b ^OLN!^GQL)UL%LL9L)LJVLLL)L)Lwva%L-L)VR^L9L)LLQVLL!rz7FL/`S7_LL)QL!LL)f.-L-L)$L|L#(02L%aL)f -L2_-L2-R9LL/1&L)zQ9L!L/m%zL)QLL/1&Lf,LL%L/~4"eL!LL!LL/}V-L)L)L@-LL%FRrLL"r)L)L)L}3rL/~4"L!LLfL)L@L%a_9LL-zRrL/~4"L!LLfL)L)L@L%a_9LL-zRrQL!L)2L)f)L$LL%a_RrQL!L)2L)fL-L)$LVL%a_RrQL!LL/~4"L-2L-fLLL$L@L%e_9L-L)zRrLQL-L+rQL|#MRL)2L!fL%e)L)$LL|L#1iZa_RQL!L-2L)f)LL)$L9VL%a_Rr)QL)L)Lf L/&]9L)LLLL/[uVzrLLLLL/}UrQL)2!LL)f$-L$L-L|L#eZL!frL%a_RL~r7{L/`S7_LLL!b L%b^ L-LL#KZ^L-LL#KZ^9LL%zLLL#KZ9LL9e*zLLL#KZ9LL% zLLL#KZ9L)L)LvzrrLLL#KZ9LL5/zLLL#KZLLL#KZLLL#KZLflLLf L/\L%f LrL)L/1&L!LL)f+)LL)$L2L%aL)f )L2_)L2)rRL/(0 L/mLL!L)L/1&L%LLfL-L)$LL/LLf )L%2^!LLL L-L/AVLL2-L%2R_)L2)RL/1&LLf)rL-L2L)f+-L-L)$L2L%aL)f -L2_-L2-rRr)L)L!f!r)Lf)L/1&L)L/1&LLfLr)Lf!LfLf LrQa_!LLf4L$LL)$LLLzLVLL!frL%e_!rR)LfLf!LfL-f -L-rQa_-L/mL!LL/1&LLfHL-L-$L/AVLLL$L/AVLLLL zLVLL!fr -L%2R_!rR)L)rrLLL+rL!b L)Qf LL#eK3L7L?O17LL7L?7.LL7L?%LL7L?x+LL7L?;WLL657L?LLw 7L?LLUD7L?>#-LL/HoL#g%Z77L?pL?K7L?eL?SL?!nL!777L?!|L?1iL?MRLLLLLL)LLLLLLLLLLLLLLLLLLLLLLLvLLLLLLLL?&]L ?(0L-?>9L?!L)?'}L?-L?L(L?iWL?a1L ?-XL ?TL ?/iL?L?yL?SL? SL?-qL?eK<L? PL?L?ML?ŖL?)L?iL ?-zKL?FR 7||#!n7}|#&]7~|#S7|#7LL7LL/HoL#g%Z7L?.Z!LLLLLLLLLLLLLLLLLL LLLLL-?WL?(0L?^'XL ?WL? SL ?9VL?^L?L?Q L?ſL?;L?>L ?NL ?fL)?58L?L ?!IR7G7HH#!|7IG#9V7JH#!n7KG#^7LH#e7MG#f7NH#&]7OH#MR7PG#^'X7QH#eK<7RH#7SU7TW7VzLX? szLT?.Z!LLLYa[L]LLLLLLLLLLLLL^2 LL_2LLa2LLb2LLc2LLd2-LLe-2)L-Lf)2L)LgeLLhaLiLLLLLLLLLj2LLk2-LLm-2)L-Lo)2L)LpeLLqauLLLLvaLxLLyLzL?xezL?nzL?^'XzL ?4zL ?cVzL ?9WzL?bSzL? zL?SzL? SzL?zL? zL?ſzL?ZzL?\zL ?9лzL-?5zL??zL? zL?kzL ?r9&zL)?m%zL?zL?!IRzz7L/`S7 ^LL"rL 77L!L/HoL#g%Z7LL/HoL#g%Z7LL/HoL#g%Z7LL/HoL#g%Z7L%L/HoL#g%Z7L%L/HoL#g%Z7LLLLLL L-?(0 L?I L?f L)?" L?0 L?!IR  77#ſ7#(07#L(7#07#&]7#!I7#f7#-zK7#eK<7#7 #T7!#LL/HoL#g%Z7"$L/jL/VhL&L(L*L,L-LL.L0L1LL L8vLLL-L:vL L LL<vL LL=vL LL>vL@L%L/HoL#g%Z7?BLL/HoL#g%Z7ACLDLEL-?>EL?gEL?r!EL ?WEL?nEL ?WEL)?]EL?9VEL?1EL ?,(EL?EL?r EL?NEL ?9лEL?EL?CEL?fEL? EL ?58REE6 66#K6#586#06#f6#W6#F6#T6#>#-6#"6#7.6#(06#L(6#&]6#6#N6#!I6#f6#-q6#-zK6#S6#eK<6LL6L?bLL6L?4LL^!6L?LLlq 6L?̢O6LLVLL%LVLL%LVLLLVLL%LVLLLVLLLVLL%LVLLLLvLLLvLLLLLLvL LLvLLL!LVLL!LVLL!LVL)LL)LL)LLLLLLLLLLLLLLLLLLLLLLLLLLL-LLLLLLL L LLLLL?uKL?tKL?qL?O$L?L?L ?uaL ?veL ?L?lYL?˿L?H L?&L?p>L?p>L"?ڥAL?~8L?9L ?9L#?Edž4L?W2L?1L?4L?x3L?VKL?a1L? L? >L-?bL&?L'?0L?n T<L?+L?EqL<L(?L)?9L!?YL,?OL$?L%?}r*L+?}~&L*?u2:L ?zL?L)?G9L ?LLR2mL/`S7J_O !LL)zL LVLFL)L)f%^L9rQfLLL LVLVLFLLLL!b L%b^X^UUL!fQLLR^?^^QL)ULL!LLL9VLLL-L=d^r!LL-L9"rL9=Qf=L%LV=LLL!LL9L=VLLL!b L%b^^QL9LLVL9^RLLL!b L%b^<LL*^UL!f3QL)QL=L)L9L=VL9LR^Q^^QL)QL-UL=L-L9L=VL9LLV9LL9^LLL9=LALV=LLVL9=LL*RLLLL9LL^)^B^^__6_b__ ___$____'_P___wQL!LLLL=R_\QLL$LVLLV)LLLL&vLLVLL%LLVLI_ QLQf"LLVL-L'LV_^^QLL(LVL-L)LR_QLULL*LLL=Z_QLULLLLVL+LL-LVLLZ_`QLULLLLVLLLZ_2QLL,LVLLL=LLL-vL-LVL%LVLI_*LL!b L%b0^iQL)ULL.LVLLLLk^>QL)ULL/LVLLLVL.LVLLY^_pQLUL)*LL0LV)LL)L)LLVL!LVLLL!b L%b^#^ QL L1LV LLL^_QLUL)*LL2LVL-LLV3L)L L=VLLLk_QLULL4LVL+L!L L=LLVLLVLLLc_fQLUL)*LQLffLLV^ L$LVLLL9V5LL L=VLL-L9VffLLj^ LLj_QLL!b L%b^(L6LR^QQLL7LVLQ^_QLL!b L%b^(L8LR^QQLL9LVLQ^_gL:LJ_[QLULLL%LVLLQ_0QL!fL;LV_^^QLL$LVLLVLLL=LLLLL>vaLLLVLLZ^QL?LLL=R^QLUL)*LL@LV)LL$LVLLLLLBvL)LVLLL!b L%b^/^,QL LCLV LLVL LLV^LLVLY^RrL)LLLL%bLb/^{^wQf LEL9VLLLL=V^^PQLQf LEL9VL$L9VLLVLL)L=VLLVLL9VR^9^LLVLLLL=V-f L%L9VLLBRr9LL)L=V9Qf9L%LV9LLLL%f%QL-L9L=LLGvLLV^^^)LL-L93rLLLLL9LLL=V)LL)1RJ7 7 z7 E7 L/`S7_8 L ^^^)^3^=^G^Q^[^e^nYL)LR"^bZL)LR"^V[L)LR"^J\L)LR"^>]L)LR"^2^L)LR"^&L)LR"^_L)LR"^`L)LR"^9LLz9LLz9LLz9LLz9LLzL ^^'^1^;^E^O^Y^c^m^w^^^^pL)LR"^qL)LR"^rL)LR"^zsL)LR"^ntL)LR"^buL)LR"^VvL)LR"^JwL)LR"^>xL)LR"^2yL)LR"^&zL)LR"^{L)LR"^|L)LR"^L^#^-^7^A^K^U^_^i^s^}^^^^^^^L)LR"^L)LR"^L)LR"^L)LR"^L)LR"^L)LR"^zL)LR"^nL)LR"^bL)LR"^VL)LR"^JL)LR"^>L)LR"^2L)LR"^&L)LR"^L)LR"^L)LR"^9LL z9LL z9LL z9LLz9LLzLLL!b L%b^L-LR*^L-LR*^L^)^3^=^G^Q^[^e^o^y^^^^^^^^^^^L)LR"^L)LR"^L)LR"^L)LR"^L)LR"^L)LR"^L)LR"^L)LR"^L)LR"^zL)LR"^nL)LR"^bL)LR"^VL)LR"^JL)LR"^>L)LR"^2L)LR"^&L)LR"^L)LR"^L)LR"^9LL!z9LL%z9LLz9L)L)Lzrr9L)L)Lzrr9L)L)Lzrr9LLz9L-L-L-Lzrr9L-L-L-Lzrr9L-L-L-L zrr9L)L)L zrr9L-L-L-L zrr9LL z9LL z9L)L)Lzrr9LLz9LLz9L-L-L-LzrrLL-L-LVrL)LVLVrL-LPLLVL%zLVrL)LnLrL)LlLrL)LfLrL)LjLrLLLLVrLLLLL!b L%b ^T^QLL9LQ^LRLLL9LRLLL9LL9RLLLL^)^+^?^P^i^^^^_F_p_____!_?_X_Z_)_QLLLXVL_QLLL_QLULLLLV_sQLULLLL)LXVLV_OQLULLLLLV_/QLLLLXVL_QLUL)*L)LL)LL)LV_QLUL)*L)LL)LL)LLL!b L%b ^T^QLL LQ^LV_QLUL)*L)LL)L)L LV_`QLULLLLV_EQLUL)*L)L)LL)L LV_QLL%b L!b^ QQLLLQL^-^^QLL%b L!b^ QQLLLQL^-^^)^QLULLLLLV^QLLLLXVL^j)^fQLUL)*L)LLLL-LXVL)LLL!b L%b ^T^QLL LQ^LV^RrLLLL!b L%b^^QLL91^LL9LLL9L9!RLLL^)^*^9^E^W^r^^^___%_=_h_______QLLLSB_QLL9_QLULLA_QLULLLLSJ_QLULLLA_QLLLLSB_QLULLLA_wQLUL)*L)LLLLL!b L%b^^QLL a^_*QL*LLLA_ULL9_UL*LLLA^QLL%b L!b^QQLLA^^^QLL%b L!b^QQLLA^^^^QLULLLA^qQLLLLSB^[^XQLUL)*L)LLL)LSVLLL!b L%b^^QLL a^^RrL ^^^^^^)^0^D^O^U^Q^M^I^EQLLW!^7QL^.QLLLUL^QLL숥^ QL^L ^^^!^#^%^'^)^+^-^/^1^3^5^6^2^.^* ^&1^" ^ ^ ^:^ ^2^ ^^L^#^%^'^)^+^-^/^1^3^5^7^9^E^Q^X^g^q^m%^i^e+^a^]$^Y^U^Q^M^I^EQLL9!^7QLL=!^)QL^ QLLL^QLL숥^7Kz7LL/`S7S_9LL!9LLr9zL)QL)QL6VL-UL-UL+VLzrLsLL$L)L!LL!LLsL/L=L!L!LL z LrL!FL!FLUFLUFL-FLF L)F LF r*L* L)L1L)* L-*z*L!f*LUfVULL$LL)UL-QL!LUL"VL)*L-UFL)*L-UFLFL)ULF*L*LQL!L-QL*LL"VLFL!F*L)QL)LULL#VL)L-*L)F)L-*L)FRQL*L2VLL)*L%FL)*L%FL f LF ^L b* fLF L)*L%F rj8L9LL*L%FL*L%FLL=VLl^*LLf L-aLf%^ ^L/*9L$L=L$LL)L*VLLL)LfLLLf ,L3-L%L)L2Rr9L9LLf6=Ls)f&=L=*LL%F=L=*LL%F^=L=*L-F=L=*F=L=QL=*LL'V=L=*L-F=L=*F=L=* L-F !LL-f"=L=L)L2VLVLL%_RL)LL0LL!LL!LLLLL9LLLLLJvaLLL=LKvLj!L!LVLLL(Vl^nLLf L-aLLb LUDb6^?LfLL%LLL*VL-^^L-^ ^L/*LLf LQ^LL)L*VRrLj L4l^(LLf L-aL;L3^L/*!NL)L8VL0L-L8VL LL-L-L L.L&zRrPL7QL5LL9"S77z7E7L/`S7_L^^^#^-^7^A^JL)L]"^>L)L]"^2L)L]"^&L)L]"^L)L]"^L)L]"^9LL%z9LLz9LLz9L)L)Lzrr9L)L)LzrrLLkVL!L)LL!f^^^L!f)^^^L%fL%fQLLL-ULQLQLULL-fWL%L-fxLLL L9VL%z^1L)f-LxL-LL-L%zL9V^ LL9V^ LL9VR^"^^^^LGLb*rLLL!b L%b%^]-L9fxL9LLL%z^^=QL)QL-ULxL-L%LL-L%L-L=VL%z^rLL9L)LvaLL%f/QLf!QLULL%LLVR^^^^^LLL2L9LL9L=VL9rL9LL=VL9rLLL-zL9L!LL)LoVf^xLL-L%zLQL9"r9L)L)Lr+r9L9L%9L^^^7^n^^__QL9L=LLxLLLL%z襥^QL9L=LLLVLLxL)LxLLL%zL%zFR^QL9L=LLLVLLxL)LxLLL%zL%zFR^iQLULLLLVL:^IQLUL9L=LLxLLLVLxLLLVLL%zL%zF襥^r9L=LL)L)LV!LLLLL)L9L-LvaL9L)LvLL_2RLL%fUL%fxQLQL)ULQLQL)ULL)L!f$xLLLL9VL)L%zL=^xLLLL=L%zR^^^^^LL-LLLRrLLxL9L-L%zLL=LVRLLLL9L=VRLLL9RLL-LLxLxLLL%zLL-L9VLLL=LvLLVLL9LvLLVLVL%zLLLLeVL)LLVRrLLL)L9VLRLL-LLL-LhBRrLL9L)LvaL)LVLyLLL{VL)LLL=LLL9LvaLLL-LrVLLLLLLVLL[LLLcV|LL_VLfL)L_VR j9LL`Vl^[LLf LzaLw f9=L=L=L%9L-L)LtVLxLLL%z^ ^L/*LL9Ld"LLVLj9LL`Vl^LLf LzaLw fx=L=L=L%9L-L)LtV-LLLLLLL)L_VLLLL_VLLxL-L-LzLLL%zR^ ^L/*!L9L9L)L=VL9LwLL9LxL-L=LzL9L%zR9L)LvLL^"rL)LL)Lh2RrLLL)LiVLL{"L9LLLLL!L!LLLL-L-LvLLLLL=LLL LLvaLLLvLLlVL)LsLLLpVLLLLgLVL[LL-R QLL)LLL-f#9LL=LLuVLjVLL%_RLL\VLL)LvL-L^VrLL}f^L)LuVf^L%LL9"rQL!LL9"LL9LLuVL)L=*RLLLLLaLL)L_VL-L9LvL-L_VLLRRLL]9LL1.zLvLxLL)LL%zLLxL)LvL)LvLL%zRLLVL9L=L)Lr+LL~LLmVLL)L%LLL\b2L+b3L*b4L?b5L[b6L]b7L-b8^>^:)^=^2)^5^*)^-^")^%^)^^)^^ )^ ^-L9)rLLf"QLULLL9LVR^^^LLLf"QLULLL9LVR^^^LLLf"QLULLL9LVR^^^LL"LL!f^^^)L)L*r9L=LmVL=L=L%L]fLaLkVL!f 9L_L-fLaLkVL!f 9LLLL!b L%b^VxL-LLL%zL)^+r)L)L)L/"3rLL#eL/@+r)L)L)L#eL/:37aZ#F7bX#^'X7cU#S7dU#57eZ#M7fU#cV7gZ#i7hX#Q 7iZ#!n7jZ#e7kX#ſ7lY#N7mY#7nU#?7oX#;7pZ#O177qU#\7rZ#7sV#!I7tZ#S7uZ#T7vU#r9&7wZ#!|7xU# 7yZ#7.7zU#^'X7{Z#iW7|X#7}Z#&]7~Z#MR7U# S7U#7V#f7LL!7TL?mL7TL?%PL7TL?57L7TL?zk35L7TL?3L7TL?3DLLxL)L!LL%zLLLLLaLLL)LvLL-LvLLLLLLeL)La)LLLLL L LLvLLLLvLLLLLL7TL?rL LLvLLLLLLL)L-L)2L)LeLLaL-L-L-LLLL LLLLv LL ?>UL?[L?f!9L?Z?ZL?3U=L-?3TL ?1L? L)?L? L ??B/L ?fL?8L?G;L??L? $L ?z2L?<<L?wuL?J.L?L? L?L?S5L? JR77#O177#m%7 #K7!#587"# >7##f7$#>37%#f7&#W7'#F7(#M7)#S7*# S7+#>#-7,#7.7-#z27.#ڥA7/#iW70#71#N72#&]73#3U=74#MR75#S76#eK<77# S78:LL<7;L;?!L!L!L=zL>L?L@LALBLCLDLELFLGLHLLLIvL)L)LMvLOLLRLSL-?+SL ?۰12SL?WSL?VKSL ?SL?1SL ?SL? >SL?5SL?:SL ?*VcSL?9SL?H>SL ?fSL?^SL)?.:RSS7ME7N7OO#!|7PO#O177QO#K7RL#ſ7SO#>37TN#C7UO#MR7VO#(07WL# S7XaLL!7bKLb?n7L%7cKLc?|L7dKLd?3L7eKLe?~27Lg7fKLf?7Li7hKLh?|5Lk7jKLj?Lm7lKLl?*=Lo7nKLn?вʥ}LL!7~KL~?ǖAL%7KL?L7KL?;L7KL??L7KL?-L7KL?8gL7KL?=L7KL?L7KL?z L 7KL?L 7KL?!@L 7KL?NL 7KL? LL!7KL?4L%7KL?L7KL?i3L7KL?L7KL?8L7KL?b L7KL?e9L7KL?4wL7KL?"P=L 7KL?)L 7KL?L7KL?CiL7KL?nN L7KL?-L7KL??L7KL?q&LL!7KL?!;L%7KL?L;ʥLL7KL?N+L7KL?L7KL??L7KL?5`*L7KL?K9L7KL?\L7KL?^L7KL?,L7KL?4L7KL?-L7KL?}L7KL?#oL7KL? L7KL?:zL7KL?L7KL?طL7KL?L7KL?oc|L7KL?V/LLLLLLLLLLLLLLLLvLL ?d'L?"7>L)?':L-?L ?]UL?Ң8L?NL?SL ?L ?L ?_`L?I4L?ǚL? SL?ſR77 #ve7 #ſ7 #q7 #9V7#e7#>37 #G97 #lY7#7#F7 #a17#M7LLLL LLL)L)L"vaL#LLLL)LLLL LLLDveL-L-LLFvaL-LLHvLLLIvLJL?UJJL?a1JL?)JL?4JL)?-XJL?T JL-?JL?cJL?fR JJ6z6L/`S7C_L L"rLLL!f$LL)LLVL-LLVR^L)L L)L"L!f^()L)L LLLLL%L9VL%zrLL ^^^ ^$^(^6^D^Q^^^k^x^v^^p^z^j ^t^d^n^^LL^^^NLL^N^>L9L^?^/L9L^0^ L9L^!^L9L^^LLL!LL!^F^J^N^R^V^Z^^^b^f^j^n^r^v^z^~^^^^^^^^^^^^^^^^^^^^^^^^|^^^^^^^^^^^^^^ ^^!^^"^^#^^z$^^t%^~^n&^x^h'^r^b(^l^\)^f^V*^`^P+^Z^J,^T^D-^N^>.^H^8/^B^20^<^,1^6^&2^0^ 3^*^4^$^5^^6^^7^^L8LL!L9LL=LL9LL9LL)RL9L)L9L;L-L=VL-LL)L)L)LCRrLL!f^L9L9L=L9LLL)RLLLfvLLLLLVL_'_L=LL=LLLLVR__L=LL=LLLLVR__L=LL=LLLLLVR__L=LL9LLLL=LVR__L9LLLVLLL=LV_h_XLLL=LL=L)L)L)LVR_;_+L_0_ L=LL__ L_^L=LL^^^^L=LL=LLLVR^^LLLLVL^^LLLLVL^^L9L^^{LLLV^w^gLLLV^c^SLLLVLLLVL^<^,L=LLL=LLLVL V^^L?LLLLL-zLLLVL9f ALL=!rC77S7777#17#-7#>37#f7#F7#*=7#p>7#n77#N+7#M7#97#7#V/7#}7#VK7#7#!;7#L;7#7#p>7#^7# 7#N7##o7#oc|7#в7#7#ط7#O177#!I7#\7#,7#47#|7#77#~277#|57#?7#37 #!|7 #5`*7 #7 #K97 #MR7#:z7#)7LLLLLLaLL9LLLLL-LL)L:v-2)LLLL<v)2LL=eLL)LLLLLLLL@v aLLBvLCL?yCL?f0 CL?ȂCL?*xCL ?fCL?n#CL-?e#CL)? CL?0 CL?3U=CL? R CC6L/`S7\_<L^^^%^/^9^C^M^VL)Lo"^JL)Lo"^>L)Lo"^2L)Lo"^&L)Lo"^L)Lo"^L)Lo"^9LL!z9LL%z9LLz9LLz9LLzLLo9L)L)LZg6zrrLLVLrLA^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^______ _ __________ _"_$_&_(_*_,_7_9_;_=_?_A_L_M!_I!_E!_A!_=!_9!_5!_1!_-!_)_%!_!!_!_!_!__ _ _!_%^QL!L쌥^QL!L쌥^QL!LL%^!^!^!^R^!LR^!^QL!L쌥^QL!L쌥^!^!^!^^^^^^|^x^t^p^l^h^d^`^\^X^T^P^L!^H!^D^@!^^`^u^_6_J_x___O__>_S_h_}___e_LLL9L)L:_*LLLL9L-LVLF_lLLL9L)L:_ULLL9L)L:_?QL!g`QQLgOQQQLfUL%fUQLUULLf:LLLL9VLL9LvLLVL*L)LmF^8LL9LvLLVLLLL9VL*L)LmFR_^^^^QQQLULLfLLL9LLVR_P^R^QQQLf\UL%fNUQLUULLL9LvLLVLLLL9VL*L)LmFR_^^^^ ^^^^QLULLL9L vLLVLLLL9VL*L)LmF_LLL9L)L:_zQL-f L-LeL=VLL9L vLLB_JLLL9L)L:_3LLL9L)L:_QL*LL*LRFLL*L*L%zF LLLL9VL*LRFL*LLL!b L%b^ L<LqV^ UL^F L*L%FLLL-L9VL*L%F_mQLULLmL*LLjF L*L-FLLLL9VL*L-FLF R_QL(fUL*LLLL a)LLfL*L%FLLLL9VL*L%FLLLL9VL*L)f^%FRR_^^LLL9L)L:_zLLL9L)L:_cLLL9L)L:_LLLL9L)L:_5QLULLLLL9VLLL-L9\_QLL*LFLL9LvLLVL*LF_QLfL-LeL=V_^^QL*LLVfLL-LeL=V_^^QL*LTL*LLjLzL*L)L)L}S_GUL%frUUL!fbQLUQL)UQL-*LLeLLLL-LL"LLLVLLLVL9VR^ۥ^^^^QLUL)*LLLLL9VjLL!l^*LLf LcaLUDf%^ ^L/*LL*L)FLLL9LvL-LVLLL!b L%b^^QL L LL-L9V^L*L)F^rL ^^^)^3^=^Q^s^__-LL92_-LL92_-LL92_-LL92_QLLLpL9:_zQLLL)LSL=VLzL9:_VQLLL)LgL=VLzL9:_2QLLLLb@LbNLb\LbjLbxLbLbLbLb^^L!LpL9V^^L%LpL9V^^LLpL9V^^LLpL9V^^kLLpL9V^l^VLLpL9V^W^ALLpL9V^B^,LLpL9V^-^LLpL9V^^LLLL9J_QLjULLVLL *fuj*L LVl^QLLf LcaLw f/ *L L *L%F L *L L-LVF^ ^L/*L LLhL9V^0 *LL LL!f^L%f^LL9Vl^HLLf LcaLw f&L)LL=VLLLzL9V^ ^L/*9^rLL^^ ^_ ^_4__QLLbLb_^QQLjULLVLL *fmj*L LVl^QLLf LcaLw f/ *L L *L%F L *L L-LVF^ ^L/*LL^Ll^@LLf LcaLw fL)LL9VLL^ ^L/*R^^ ^^^QLULLL-L=VLLVLR^^UL!fGUQLf6QLUQQLLL-L=VLLVLR^_^^^^QLULLL)L=VLLVLL-L=VLLVR^^L)LeL*rL^^%^@^T^h^|^^QL-LLL92^yQL-L*L)LL92^\QL-LL[L92^FQL-LLL92^0QL-LLQL92^)LL9*^)LiL9*^rL^^%^@^T^h^|^^QL-LLhL92^QL-L*L)LL92^uQL-LLzL92^_QL-LLL92^IQL-LLL92^3)LL9V)LLL9V)LL9*^)LL9*^rLLLbxLbL|bLbLbLbLbLbLbL bL!bL"bL#bL$bL%bL&bL'c__LL9V__LL9V_^L{L9V^^LL9V^^LUL9V^^LL9V^^LL9V^^LL9V^^LaL9V^^LL9V^^rL~L9V^p^bLL9V^`^RL]L9V^P^BLL9V^@^2LL9V^0^"LL9V^ ^L\L9V^^!L)L=2r-LLL(bqL)bL*bL+bL,cL-cL.coL/cL0cL1cqL2cL3cL4csL5cL6cL7cu__LL9VLLLL=VLLV__LLL=VLLLLLL=VL쭥_R_qLLL=VLLLLLL=VL쭥_ _?LLV*LLL9VLLLVL*L-LLVLLVLLL=VLL!LLYLLrVLLVLLVL!LLVL%LuLVR__LLV*LLL9VLLLVL*L-LLVLLVLLL=VLL!LLYLLrVLLVLLVL!LLVL%LuLVR__LL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV__LL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV_(_GLL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV__LL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV_n_LL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV__0LL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV__LL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV_W_vLL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV__LL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV_^LL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV_@^_LL9VLLLVLLVLLL=VLL!LLYL%LrVLLVLLV_^-L-LzLLL"bL#bLb__QL!f0QQLfLLL=VLLV_^^^^L!f1QLfLLL=VLLV_H^_^_ _QL!f0QQLfLLL=VLLV_^^^^L!f1QLfLLL=VLLV^^^^^^L!f}QLfkQQL!fXQL!fGQQLf4QQQLLLL!LLLL=VR^W^^^^^^^^ ^^^LLL=VLLVLLL=VLLL[r9L9*L%F9L9UL)L9*LVF9LL-L+r9LLwL=LeLV9LL)LLLULLL!L*L*L*LjLjLjLLL * L * LzLL$L-LV*LLLL9VL)*L-*L|L=VLLLeLVLULL)LL* L-LLmLQzLQL%zF)ULLLVLxV)*L!fZ)*LsLnVLL%L*LVLLL=L&vLLZVL)LzL=VL*LXL=J^LLzL=BRrL)LL%fSL%fFQLUL)QL-UL-L)LVL!f)LL9VR^^R^^^^^L-r9*Lf9L9*L)LuL=V9LL=LRLL9*f9L9*L)LuL=V9*Lf9LL=V_9LL9LL=V9L4LPLLV9L%LL=V9LL)LLL!b L%b^iLLTLjL%z^UQL)ULL9f"LLTLLjL!L=VL%z^LL-LL%zLL%L=S^r9LL=V9LL)L#9LL)L=V9LL9LL)L=V9LL9LL)L=V9LLL-LLL(bGL)bL*bL+bL,c;L-cxL.cL/cZLcLc_s_oL%f7UL!f&QLLL)L9VLVL=VR_^_5^_/_+L%f7UL!f&QLLL)L9VLfL=VR_Y^_^__L%f7UL!f&QLLL)L9VLL=VR_^_^__L%f7UL!f&QLLL)L9VLL=VR_^_i^_c__L%f7UL!f&QLLL)L9VLtL=VR_^_%^__L%fkUL%fZUUL!fGQL)UQLLL-L9VLL=VLL)L9VLL=VR_^_^_^__L%fkUL%fZUUL!fGQL)UQLLL-L9VLL=VLL)L9VLyL=VR_^_;^_5^_/_+L%gQL!gQQLgrUL!gcQQQLj *LLVl^6LLf LcaLw f0L)LLV^ ^L/*L*LLLL1a*LTL-L)VLLL L=L2vL)LTLV L=LL3vLLVLQL *f L *LQLuL=VQL *f LL=V_ LFULLL!b L%b ^3LLLL *L%zF^QLLLlL=V^ L=L LLL5vLLVRR_^^^^ ^^^^6L-LV__~L%g QL)ULLmLLxL *fLfoLLLL)L)L7vaLLLLLL%zLjL!LVLVLVL L L8LLLjL%zL LVR^mLf4LLL9VL=L9L9vL)LVLLL=V^2L9L=L:vL)LVLLL9VLLL=VR^ӥ^^i^eL%fVQL)ULL9L=L;vLLVLL-L9VLmLL!fLLWL=VR^p^^^L9L=L<vL-LVLLPL-LVf#L-LmL*L*LVL=B^L-LmLL=BrLLL!b L%b^ LLq*^ULL!bL%b#^z^v)QL9L=L)LVR^^[)UQLfG)UUL!f4)QL-UQL9L=L-LV9L=L)LVR^;^^ ^^^QL)UL9LL-LVL1^9LL)L=V9LL9LL)L=V9LLLLLLL!b L%b^#9LL=V^QL9LL)LV^9LL=V9L9UL)L9*LVFR9*Lf9L9*L)LuL=V9LL=LL9LL=V9LL-LV9LLL=V9LL=*RLLL9LL-LL3RL9L=LLLLVL!fL!RLLLLL%b L!b(^)QLL9L=L)LV9L^N^RLLL9LL=V9LL=V9LL)LV9LL=VLL9LRLLL9L=LLLLjL%zLLV9LRLLLL)L9VL^)^;^^^__h___'_a_z__7 _ _ _2 _ _ _QLLLL=S_QL!fLLV_ ^^QLUL*LLLLLLL>va-LL*fL*L-LuLVL)LLVL-FR_ QLLL)LS_n QLULLL-LVLLLR_E UL%gUUL%gUUUL%g{UUUUL%ggUUUUUL%gQUUUUUUL%g9QLUQL)UUQL-UUUQLUUUUQLUUUUUQLUUUUUUQLUUUUUUULLL!f&QLfQQLf^^^ ^^^^gL?LPLL L LLPLLLLL LL LL LL LL L L%zL%zL%zL%zL%zL%zLVLLLfQLUL)LULL@LwLLLLLLLL@LjL%zLLVLLLLLLLLdVLLLL LjL%zL%zL%zLVLVL%LuLVL)FRR^R^^LL LLL LLLLLLLjL%zL%zL%zLVLVRR_ ^R^*^^^^^^^^ ^^^^QLL!bLbF^^QQLf-QQQL)ULLL-L-LLVR_R ^^s^oQQL)QUL-ULLLLAvLLVLLLVLLVL)LLVLLmLkLVR_ ^QLULLLLBvLLVLL-LVf"LLmL*L*LVLR^LLmLLR_q UL!f[UQLfJQLUQQLLL-LVLL!f^^L%f`^LLVR_ ^^^^QLULLL-LVLLVLL)LVLLR_QLLLLCvLLJ_*LL!b L%by^QL)ULLLLf LLVLLLVLLLLL LLLVL  L-L VL L)iR^tQL)ULLLLf LLVLLLLLVL LLLVL)L LLLVL aR^_QLUL)*L*LLLLVLLLLLLVL)LLV)LLL!b L%b ^BL-q^:QL L LL L L-LV LL LVL^R_ QLUL)*LL L*L* L LjF  LjF  LL *L *L%zF  LLLV *LjLVL!f DLLV * LjLVL!f ELLV L)F  LF  LLV L *LLL!b L%b^ LLqV^ UL^F  L LL LLV UL L ULL*LVF L LLV L%LuLV LFL)yR_QLULL)L)L[_QLUL)*LL LLLLL L zL/c_QLLLL!b L%b^2LLV^&QLL*LjLVL!L)LV^!L*LLLFvL*LVL*L*L|LVLFR_QLLLL!b L%b^^QLLL)LV^*L*f&*LL*L*LuLVLFLLLL L*L%zF _j*L*f&*LL*L*LuLVLFLLLL L* L%zF _QLULLL-LVLL)L[_QL!fLLVLtLV_^^QLLL)LVLVLj LLVl^ULLf LcaLw f3LGLLbLLVLL-L)L}V^ ^L/*LLLzLVLtLVLLVLLLHvL-LVL%LuLZR_QLj *LLVl^2LLf LcaLw f LLqV^ ^L/*L*LQb*LTLLVL!f4ILQL*LTLL-LL *zLVLLVJL*LVLjFLLLF_CUL%ffUUL!fVQLUQL)UQL-*LLLLL"LLLVLLLVLVR_^^^^QLUL)*LjLLLLLL LVLLvLVLLnVLLKL-LVL LLvLLVLMLLZV LLL!b L%b^$LLV^QLLL)LV^L LLLL LOvL)LVLL)PLLZVRl^LLf LcaLUDfLLLVLLVLLLLQvL-LVL)LLL!b L%b^9 LLV^-QL L L LLLjL%zLLV^L L L LLL LRvL)LVLL)SLLV L%LuLVR^ ^L/*Y^RrULQL)L-L9UL-L=LLLVL_VL=LVLL:R9LL-Lx"rL)LL)Rr9L=LzLV9LLV9LLLLL9LL=V9LtL=V9L)L[L=V9L)L=LYvLL*RLLjLLLLLLLLLLzL)LLLLLLL!L!L!LLjLjLjLLL!L!LUL zL-LfULLLxVLLLL9VLLL=VLQLjLVL!b LbL!fQL* LLLLLLF L)FL!LlLVL)L)LVvLQLTLVL!L-LLlL_VLLLWLLVXLLsVLLZvLLZV-L)LVL-LVRUL*L)* LVLxVQL)URr\7D7Ez7FS7G7HL/`S7_KLLL!b L%b^L-L`*^gL-L`*^9LLLLLL%zrrLLL%b L!b^*L^!^-L-L-L-LL9LL9LfVL%LjMr-L9LL9LLLfLLL%b L!b^QL)UL-*L*L-L9LL9f"-L-L-L-L L L L=VL=^qLLL%b L!bN^WQL)UL-*L*LLLLL=VL-L-L-LLLL=VL=^nL;Lc^^nL=LcR^_L)Lf)LLL%b L!b^QL)UL-*L*LL9LL9f" L L LL=VL-L-L-L=^r-LLL%b L!bN^WQL)UL-*L*LLLLL=VL-L-L-L L L L=VL=^nLFLc^^nLHLcR^^!LLLLLLfVL%Lj]RrLLL%b L!b9^?QL!fUL)*LL)R^$^^QLL9)^ dLb!^LLL%b L!bQ^WQL!f*LR^F^^QL)UL-*L*L-L9L-L-L-L=\^ qLe!^L)LL!f^;^^L!f)^*^^L9LLLL)L)LL=LTRriLiL_LiLaVL!LLL%b L!b^QL)UL-*L*L*L9LL=VLL!fL9LLLLju^@L!fLLLLLLt^)LLLLL-Lt^iL9LLiL%LjE^)LLLL-LLL9LwvaLL)RrLLL%b L!bR^XQL)UL-*L*L9L-L=VLL!f L^L!f L^)^ dLb^LLL-L-L-Lyva-LRrLLL%b L!bw^xQL)UL-*L*L9L-L=VLL!fL)LR^7L!fLLLLLd^LLLLLd^i^LLL-L-L9LL=L{va-LL)RrLLL%b L!bH^HQL)UL-*L*L9L-L=VLL!bL!f^LI^^LLL-L-L-L}va-L)RrLLL!b L%b^;^8QL)UL-*L*L-L9)L)L=VL9A^LLLLvaL!rLLL!b L%b ^Ui^QQL)UL-*L*L*LL9L)L9LLLL=L-LLj}R^LLLLvaLL)rLLL!b L%b ^>-^:QL)UL-*L*LLL9L)L=LL9^rLLLLvaL-L)r7]7^^#i7_^#K7`^#e7a^#&]7b^#F7c^#7d^#eK<7e^# S7fhLL!7i]Li?mLk7j]Lj?"63lLLmLLLovLLLL)LpeLLLrvaLLLsvLtLuLvLLxLzLLL|vL~LLLLL ?x L?DL ?XL ?L)? SL ?9VL-?ſL?8L?LL?\L?9лL??L?:L?fL ?ͱJL?!IR7IE7K7LL/`S7_ LA^^^^^^^^^^^^^____%_/_9_C_M_W_a_k_u_______________ ___)_3_=_G_Q_[_e_o_y_______________L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_~L)L"_rL)L"_fL)L"_ZL)L"_NL)L"_BL)L"_6L)L"_*L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_L)L"_vL)L"_jL)L"_^L)L"_RL)L"_FL)L"_:L)L"_.L)L"_"L)L"_L)L"_ L)L"^L)L"^L)L"^L)L"^L)L"^L)L"^L)L"^L)L"^L)L"^L)L"^L)L"^L)L"^zL)L"^nL)L"^bL)L"^VL)L"^JL)L"^>L)L"^2L)L"^&L)L"^L)L"^L)L"^9LLz9LLz9LLz9LLz9LLz9LL z9LL z9LL z9LL z9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LLz9LL8z9LL9z9L)L)L?zrrL^^^#^-^7^A^JUL)L"^>VL)L"^2WL)L"^&XL)L"^YL)L"^ZL)L"^9LL!z9L)L)L%zrr9LLz9LLz9L)L)Lzrr9LLzhLLLA^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^}^z^w^t^q^n^k^h^e^b^_^\^Y^V^S^P^M^J^G^D^A^>^;^8^5^2^/^,^)^&^#^ ^^^^^^^ ^^^L^ ^^^^^^^^^^ ^^^^__{_yQLL9Lj+=LLVLLfmLLnLLl^?LLf LaLw f=L)LLVL-LV^ ^L/*_^QLL9Lj+=LLVLLfmLLnLLl^?LLf LaLw f=L)LLVL-LV^ ^L/*^^QLL9Lj+=LLVLLfmLLnLLl^?LLf LaLw f=L)LLVL-LV^ ^L/*^^9L)L=LV=L=L)Lf^%rLLLL9L)L)LovL-LV!L-LL%L!LVLL)L=LpvLLVLLL-LVL)LzR9LLV9L!L9L!f|9Lf)=LLLLV9L9LL^LLLL!fLf^!L=LLL9LLLV9L!LL)RLLL9fDL=9Lf"LLL%LVLLLV^LL%L%LVLfL=LfLL%^]LLL!fL fLLLLV^,L-LLVL-LLVL-L LVL-RLLLLfL)LV^7Lf)LL)LLLVL)LLV^ rLLsLLVL-LLV!L!L!LLL)LL-LLtva-LLL LLLuvLLV)LQRrL^^2^b^^^^QL9L%LV9LLV9L!L*^QLUL9LLV9L=L-LVL)LL2^QL9LLV9LLLV9LL*^gQL9LLV9LLV9L!L*^BQLUL9LLV9L)L)L;^QL9LLV9LL*^9LLV9L!L9LLA^^^^^^^^^^^^____-_@_B_P_R_T_b_p_~______*_8_F_H_J_L_N_P_R_T_V_X_Z_\_^_`_b_d_f_h_j_l_n_p_r_t_v_x_________!_%___QL)L_QL)LL_QL)L_~QL)L_nQL)LL=_Y _UQL)LL _AQL)LL= _,QL)L _QL)L _ QL)L_QL)LL=__QL)L___QL)L_QL)L_QL)L_QL)LLL-LVLLLV_rQL)LLL-LVLLLV_IQL)LLL-LVLLLV_ QL)LLL-LVLLLV^^QL)L^QL)L^QL)L^^ ^!^"^#^$^%^&^'^(^)^*^+^,^-^.^/^0^{1^w2^s3^o4^k5^g6^c7^_QL)L8^OQL)L9^?:^;;^7<^3=^/>^+QLUL-L)L)L?^ L@!^LLL9fL)LL:^yL fL!bL%fL)LL)LL%L:^HL!fLfL)LLLVLL:^L)LLLVLL:RrLL-LwLVL9LLL)QLLLLVL-LLVLLVL)L=LxvLLVLyL-LVLL-LLzvLLRRRr9LLL!f =L^=LLVLLLLL-L-L-L|vaL!R9L=L9f_Q=LLL%L!fJf=LLL%LL쨥^L%LLLf LL)L!^LL!f`LLLLL!LL)f'LL)LLLVLL%_LLL)L1R^LL!f3LL)LL)LLLVL%L^O=LL=LLL-LL-LL)L LLLLV-L%L)RLLLLf^L)LL)LLL쨥LL!f ~LLL9LvLVLLL!L!L)L!L!LVLLLL LLLLLLLva!LLR 9LL^^^^:^T^b^|^^9L=L\^^x9LLLLLL^V^c^Z9LL9LLVL`^G^>9L=Lb^7^.9LLLLLLdVR^^9LLf^ ^jLL!f^r9L=LLLj LLVLLf jLl^ALLf LaLw fL)LLV-L%L^ ^L/*)R9LLVLLf jLL-rLL9L)L9LLVL^6^4^2^0^.^,^*^(^&^$^"^ ^^^^^^^^^^ ^ ^ ^)^F^c^^~QLLL)L=VL!^m^_QLLL)L=VL#^N^@QLLL)L=VL%^/^!QLLL)L=VL'^^LSLVL3RLL%f1QLUL9LL!LL=VL-L^VLVR^ ^^rkLLVLLwf jLLLLLLL)L!b)LbL!bLbL!bLf jL)L L9L=LvLVLLLLL L9LLLLvaL-L%LLVL!LLLL)LgLLLL^ ^^-^T^f^dL)L^a^ULL%L)L^K^?LfLL^LL)L^"^LL)L^^LLVLLLLA^^^^^^^^^^__ _P_X_`_h__________#_I_o_s_{________________________________ ___&_*_(_+_"_%_____L__LL__L__L__jLLVl^/LLf LaLw f jL^ ^L/*L__ __LL __jLLVl^/LLf LaLw f jL^ ^L/*L _O_FL_E_<L_;_2L_1_(jLLVl^/LLf LaLw f jL^ ^L/*L____L______L__L__L__LLLLLL%zL!__LLLLLL%zL#_b_YLLLLLL%zL%_:_1LLLLLL%zL'__ )_ _L*_^L,^^L.^^0^^1^^2^^3^^4^^5^^6^^7^^8^^9^^:^^;^^<^^=^^>^^?^^@^^A^^yB^|^sC^v^mD^p^gE^j^aF^d^[G^^^UH^X^OLI^N^ELK^D^;M^>^5N^8^/O^2^)P^,^#Q^&^LL)LLRV^^T^ ^jLLLLLLVLL)Lf^%LLVR_s)Lf jL-L-L)LLV-LLLLvL-LVLLvLLVLR l^KLLf LaLLb Lt! b^jL^^jL^ ^L/*9LL)L^^^\^p^^^QL,LL^QLULL!fL=fL)LLVL)LLLL^QLLLL^lQLLL^ZQLULLLLLLLLVLL)LLLLVR^QLLL^LL+r9LL)LLfE^L-LL LVL-L=LzL#LELLr9L)LVf =L LV=LL-L-L:^t^r^p^n^p^^^^^b^^^^__$^T_1^P^N_@_S_f_y___^>___^6^4^2^0^.^,^*^(^&^$^"^ ^^^^^^^^^^ ^ ^^____QLLLV__QLLLV__QLLLV__QLLLV__QLL숥__QLLLV__QLL숥__wQLLLV_m_bQLLLV_X_MQLLLV_C_8QLL숥_2_'QLLLV__QLLLV_^QLLLV^^QLLLV^ޥ^QLLL)LV^ĥ^QLLL)LV^^QLLL)LV^^QLLL)LV^v^kQLLLV^a^VQLLLV^L^AQLLLV^7^,QLLLV^"^QLLLV^ ^LLzLVLL)Lf^%rLLL9LLL)QLLLLLVLLLLVLL)LLLVLLLVLLVLL)L)L=LvLLVLLLVLLvLLVLLLVL!L)L L-L-LLvLLVLLLsRRr777z77E7 77#9V7#17#K7#ſ7#f7#9л7#9V7#7#F7#p>7#97#Q 7#!n7#VK7#tK7#q7#ſ7#7#f7#eK<7#N7#a17#W27#;7#!I7#ve7#07#W7#7#!I7#lY7#S7#!|7#7.7#(07#L(7#C7#7#&]7#MR7#(07#)7#f7LL!7L?HL%7L?!L7L?Dm>L7L?L7L?Nƅ?L7L?gv)L7L?d]L7L?L?L7L?٣L 7 L ?|L 7 L ?12L 7 L ?WL7L?fL7L?,)L7L?#L7L?عyL7L?u L7L?0%L7L?oL7L?=:5L7L?q=L7L?D,L 7L?%9L"7!L!?B1L$7#L#?L-7,L,?j)L/7.L.?L70L0?J+L 71L1? L!72L2?P L"73L3?1L#74L4?`a?L$75L5?>3L%76L6?13L&77L7?:L'78L8?V?L(79L9?V?L)7:L:?xn8L*7;L;?CEL+7<L<?1L,7=L=?{'CL-7>L>?<L.7?L??:;L/7@L@?M>L07ALA?xE6L17BLB?BL27CLC?:L37DLD?;L47ELE?N L57FLF?@L67GLG?[/L77HLH?@;LJ7ILI? 8LL7KLK?Nh7L:7MLM?#L;7NLN?#L<7OLO?@" L=7PLP?@" L>7QLQ?\@LS7RLR?n?L@7TLT?Ґ2[LL]7\L\?$L_7^L^?ǀ La7`L`?Ɛ7Lc7bLb??Le7dLd?ALg7fLf?oiLLg(7jLj?$<LLkLlLLLqvLvLLLLL{vL}LLLLLLLLvLLLLLvLL?y/^L?lYL ?/ L?ڥAL-?pd{L)?VKL?77L?p!>L?IڕL?4}rL?UR 7M7NM#777OL#*=7PM#0%7QM#/ 7RM#?7SF#cV7TM#:7UM#J+7VM#Nh77WM#j)7XK#7YH#ſ7ZM#,)7[M#:7\M#:;7]M#@" 7^H#W7_M#@" 7`M#CE7aE#7bN#7.7cL#5`*7dN#iW7eM#;7fM#Ɛ77gM#L?7hM#o7iN#MR7jM#%97kM#B17lF#7mH#9V7nN#K7oM#Nƅ?7pN#F7qK#W7rH#^'X7sM#@;7tM#q=7uM# 87vL#в7wH#!I7xM#\@7yM#d]7zM#137{M#A>7|E#!I7}M#{'C7~N#>#-7M#o7M#N 7H#7M#عy7M#B7H#7M#<7M#7I#ſ7E#f7M#H)Z7F#ſ7M##7I#9л7I#!I7M#[/7H# S7M#Hwy7L#N+7M#gv)7E#?7M#V?7N#!n7N#i7L#7M#A7N#e7M#u 7L#^7L##o7M#<7L#47M#!7N#7M#xE67L#77M#`a?7N#!|7M#n?7N#L(7F#^'X7N#&]7L#K97M#>37I#:7M#٣7M#127E#ſ7M#V?7E#9л7N#>37H#f7M#xn87M#P 7N#M7M#Dm>7M#H7M#=:57M#f7L#ſ7M#7M#|7M#@7M#W7M#D,7N#O177M# 7L#~277G#17M#17M#$7M##7M#17M##7M#Ґ27M#ǀ 7N#(07M# 77F# S7M#M>7LL7DL?u_:L7DL?ЗL7DL?w'L7DL?B(L7DL?˩L7DL?!$L7DL?>LL7DL?;WLLL)LLLL-LL)LLvL-L)LvLL-LvLLLvLLLLL LLLLLLLLLva LLvLLLLLLLLLLL)LLLv2LL2LL 2LLL"v2-LL)LLLL L L#v-2)LLLLL L'v)2LLLLLL LLL=veLLLLLLLLLLLLLLL(LLL LLTvaLL LL[vL\L?$\L?lY\L?\L?<*\L?7\L ?\L?z\L? \L ?-8\L?]U\L ?H>\L?MP\L?i\L?c1'\L ?)\L? \L?)\L?`\L?̫(\L-?\L?7\L?\L?\L?0f\L?s%o\L?\L?Q p-\L ?`$R\\6 S6 E6 L/`S7_\LL9LL3*zLL"rjLLVLLLVLLL!bL%b^>^:L#LV^^*UL!fQLLL R^d^^^LLLLL!b L%b^5L'LV^)QL)ULLLL)LLV^LLLL QL ULzRl^*LLf LaLw f)^ ^L/*!rL9LLL%fUUL%fGUUL!f7QLUQL=L=L-LVL=L-LVLR^^^ ^^^^LjLLl^LLf La^L/*LLLL!b L%b ^^QL9LL=VL^L)LLVLLL+rL)LL+rL9L)L+r9LLL=VLLLVLLLLbL b^^)LLL%fLUL%f>UUL!f.QLUQL9LL=VL9L-L=VR^^^ ^^^^LLLL)LL%z^i^9LLVL!fLL9LLL=VL^2^LLVL!fLL9L-L=VLL)L)L9VL)LL=LLvL-LLLLbLbLbLcLcLcLcLc+LcLcLcLcL cLcL2cL cL cL ckL:cLcLcLcLcLc__LLVLLLLL__LLVLLLL__hLLVLLLLL_W_@LLVLL!LVL$f(LL%L-LL%LVLL^LLLbLb(Lb3Lb>^N^JLL^M^8LL^;^&LL^)^LL^^L)LL__u-LL=LLLVL_g_P-LLLL=VL_G_0LLVLLLLL=VL)LV__LLLL!b L%b ^?L^7QL)ULLL-L=VLL=L-LVLV^__L-__-LL=LvLLLVL__iL-_s_\L-_f_OLLL%fUL%fUULL!bL%bA^^QL)UQLLL-L=VLL-L=VLLVR^~^hUUUL!fTQL)UQL-UUQLLLL=VLLL=VL LL=VLLVR^ ^^^^^^^L_z_cLLVLLL_\_ELLVLLL_>_'LLVLLVLLLLLL=VLV__j LLl^LLf La^L/*LLLLL!b L%b ^^QLLL=VL^L__zj LLl^LLf La^L/*LLLLL!b L%b ^^QLLL=VL^L__-L_^L-_^-LL=LvLLLVL^^LLVLLL^^LLLL=LLLLLvLLLVLLL!b L%b ^*L^"QLLLLLLV^R^?^(LLLVLLLL)R^^LLLLARrLLLLL%f3QL!f%UL!fQL-LL9V^^^ ^^^^ L)rLLLL)LLL%zL-LLL!b L%b ^$^ QLL9L)L=VLL%z^L3RLLLL)LLL%zLL9LL=VLL%zL3RLLLLL9LL=VLL9LL=VLL%zL%zL3RLLLsLLLL^)_;_]____<_`_____r____W_{__-QLL ^^-^E^]^u^^^^^LL)LL^LL)LL^LL)LL^LL)LL^QLLLLL^jQLLLL^PQLLLL^6LL)LL^LL)LL^_QLL)LL9L)LV_QLL)LLL-L9VLL%z_QLULLLL-LLLL9VLL%z_QLULL-LLLL9VLL9LLVL%z_RQLULL-LLLL9VLLLL9VLL%zL%z_QLL)LL9L vL)LV_*LL!b L%bJ^QL)ULLLLLL9VLL LL9VLL%zL%z^GQL)ULLLLL-L9VLL LL9VLL%zL%z^_DQLUL)*LL LLLL9VLL LL9VLLLL!b L%b ^$^ QLLL)L9VLL%z^L%zL%z_QLUL)*LL2L)LLLLL9VLL LL9VLL%zL%z_gQLULL LL-LVL-LLL-L9VLL%z_#QLUL)*LLL-LLLLL9VLL LL9VLL%zL%z_QLL )LLLL!b L%b ^$^ QLLL)L9VLL%z^_|QLL )LLLL!b L%b ^$^ QLLL)L9VLL%z^_,-L:_#QLULL-LLLL9VLLLL9VLL%zL%z^QLL)LL9L vL)LV^QLL-LL^QLUL)*LLL9L vL)LVLLLLL9VLLLL!b L%b ^:^6QLL LLLLL9VLL%zLVLL%z^L%z^-Lf LLLLLL%z^(-LfLLLLL%z^L)LLL!b L%b ^^QLLLLL%z^LL)L)LVLLkRrLL97z7S7E77L/`S7Y_L^ ^^^)^2gL)L"^&(L)L"^)L)L"^*L)L"^9L-L-L-L!zrr9LL%z9LLz9LLzLL9LLT5z L #xBLL)L0?xBL L #xBLL)L.?xBLL/mLL/1&LL!LL-f.-L$L)LL)L/AVL)L/2L%e_ L)L #xBLL #Hg Lz?Hg  L?xBLRr #Hg L #xBLL L)QL-LLL# sLLL# sL,V?xBL L)U?Hg R8LL?Hg L?xBLL9? L:?- L;?m[L<?m7Lj#LL>V#xBLLL# sL2lrl^LLf L5L/*L/*!LL!f^^^LL%f^^^LLf^^^L^ ^^!^(^6*L9LL*^%DL%^DL%^QL9LL*^L^ ^^!^(^6*L9LL*^%FL%^FL%^QL9LL*^LL!fQL^^^HL%LLLbL%b^0^,QL9LL#VR^$^QL9LL#VR^^JL%LL!f+*LL$LLKL)LVL^^^JL%LLL9LL)LL!f!UL)LMLLVL!^^^NL%)rLLELLQL)L"LRL^ ^^^^QLUL)*LLPLsLRLL'VLVLL&VLL!fLSLV^0^^LL$LVL9LLVLTLL&[^OQL-LL2^>QL-LULV-LLV-LVL2^QL-L9LL2^rL LLLLL9VL)R788L? 8L?xBL8L?m8L?- 8L?Hg 8L?m[Y7z77E7 77#K7#ſ7#9л7#lY7# 7#57#Z7#17#(07#q7 #iW7!#C7"#!I7##f7$#eK<7%#a17&# S7'+LL-7,L,?"63L/7.L.?==L170L0? `L372L2?;4LL675L5?;WL=77?LL/HoL#g%Z7>@LALBLCL)LEL-LGLILLLOLLLLWaLXLYL)?lYYL?UJYL ?3U=YL?1YL?JWYL? YL?+0YL?YsYL?2YL?RYL-?JYL ?~R YY77#ſ7#n7# 7#*=7#N+7#n77#cV7#7#V/7#7#e7#J7#r!7#7#^7##o7#,7#47#77#|57#"637#37# P7#!|7#7.7#5`*7#K97#&]7#MR7#JW7#7# 7#K7#-7#>37#F7#W7#R7#}7#!;7#L;7#7#N7# 7#7#eK<7#oc|7#17#в7#7#ط7#O177#\7#3U=7#|7#~277#?7#17#:z7#(07# S7LL7L?;WLLLL)L)LLvaL LLLLaLLL)?L? L?L?f0 L?HL-?3U=R6L/`S7_LLLLL!fLL%LVL!f9L)L!L-L%LpVL*^9L)LV9L LVL=!RLLLL)L)LvaLL!RLzL)LmLLLzL+rLL!fTQLj9LLlVL=L L)L}Vl^)LLf LaLw f^ ^L/*^ ^^rLL!f"QL9LL=LLkVLuV^ ^^rLL9LLLfL!LLpVLfOLL)LLLpVLLLVLLLLr)LLVLL{LLrL-R^ZL|LLLLLL-L%L!LVLiL=LLVLLzLLLLLwVLLRLLLL|LjLxL)LsLL)LvLLyVjLLtLoLol^jLLf LaLL~LLLnVLLL9e*fQLLo^^^)LL^ L/*L)LvLLyJRLL9L)L)LvLfj Ll^LLf LaLL_:bL (I/b,LZg6bE^bQL)ULLvLL=VR^P^BQL)ULLqLL=VR^0^"QL)ULLLL=VR^^L/*_\R7Z7[7\\7]S7^L/`S7_#L^ ^^^&L)L"^L)L"^L)L"^9LL!z9LL%z9LLzLL9L)L)L (I/zrrL^ ^^$^7QLLL^%QLL숥^QLLLL^LLVLrLLL(bL-bL.bL0bL/bL1bL2bL3bL4bL5bL6bL7bL+bL,bL)bL*bL"bL#bL$bL&bL'bL%bLbLbLcL|cLcL cL!cLcLcLcLc__ ___^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^z^x^r^p^j^h^b^`^Z!^X^R!^P^J%^H^B%^@^:^8^2^0^*^(^"^ ^^^^^ ^^L)rLLLLL fiQLUL)*L)L9LL9f>LL-L=VL-LL-LVLLL-LLVLVR^9^R^ ^^LLLVLLLLLVLJRrLLLj L9l^$LLf L-Lf^S^L/*Lj L=l^%LLf )LLfR^^L/*LL)L)L%zR^L!LVL%fSL!LVL)L%LVj L=l^%LLf )LLfR^L^L/*LR^E^^L!LVL!f!L!LVL)L%LVR^^^L/&]!9LLLL!LVL fL!LVQLf~L!LVL)L%LVj 9L=l^%LLf )LLfR^^L/*LLLLVLLL-LLVL9LVR^z^^^^L!LVL%f&L!LVL)L%LVLR^=^^LLLVLLLLVL9LV^ L/&]!LLLL!LVL fL!LVQLfL!LVQQL)L!LVL-L!LVQLL%LVLLLL!LVL fLL!LVQLf6L!LVL)L%LVLLL)LVL9VR^.^^^^-L-LLL=V^ L/&]R_ ^^^^L!LVL fCL!LVQL)L!LVL-L%LVL)LLL=VR_ ^^L!LVLfL!LVL)L%LVj Ll^%LLf )LLfR_@ ^L/*LLLLL!LVLf6L!LVL)L%LVLLVLLL=VR^P^^L!LVL!f.L!LVL)L%LV$LLLVR^^^L/&]R_ ^^L!LVLfL!LVL)L%LVj Ll^%LLf )LLfR_B ^L/*LLLLL!LVLf;L!LVL)L%LVLLVLLLL=VR^P^^L!LVL!f.L!LVL)L%LVLLLVR^^^L/&]R_ ^^L!LVL fL!LVQL!f{L!LVL)L%LVjLLVl^%LLf )LLfR_) ^L/*LLL-LLVL)LLL=VR_ ^^^^L!LVL fL!LVQL%fL!LVL)L%LVj Ll^%LLf )LLfR_ ^L/*Lj Ll^%LLf -LLfR_X ^L/*L)LLLVL)L)LLVLL=VR_+ ^^^^L!LVL g L!LVQLfL!LVL)L%LVj Ll^%LLf )LLfR_^L/*L-L!LVL f-L!LVQL%fy-L!LVLL%LVj  Ll^%LLf LLfR_H^L/*L-LLLVLLLLVLL=VR_^R^^R^^^^^L!LVL g(L!LVQL gL!LVL)L%LVj Ll^%LLf )LLfR_^L/*L-L!LVLf-L!LVLL%LVj  Ll^%LLf LLfR_?^L/*LLLL!LVLfBL!LVLL%LVLLVLLLLVLL=VR_^R^^R^^^^^L!LVL fL!LVQLfL!LVL)L%LVj Ll^%LLf )LLfR__^L/*Lj Ll^%LLf -LLfR_.^L/*LLLLLLLL=LLvaL쭥R_^^^^L!LVL gjL!LVQLgSL!LVL)L%LVLg.)L%LVL-LLVj Ll^%LLf -LLfR_h^L/*LLLLL!LVLfvL!LVL)L%LVj  Ll^%LLf )LLfR^|^L/*LLLLVLL)LVLL=VR^R^^L!LVL!f.L!LVL)L%LVLLLVR^^^L/&]R_^^ ^^^^L!LVL fL!LVQLfL!LVL)L%LV-LLLj  Ll^$LLf L-Lf^8^L/*L-LLLVLLLLL=VR^RL!LVL%f4L!LVL)L%LV-LLLL=VR^^^L/&]R_^^^^L!LVL fL!LVQLfL!LVL)L%LV-LLLj  Ll^$LLf L-Lf^8^L/*L-LLLVLLLLL=VR^RL!LVL%f4L!LVL)L%LV-LLLL=VR^^^L/&]R_^^^^L!LVL fEL!LVQLf.L!LVL)L%LVLLL=VR_/^^^^L!LVL g_L!LVQL gHL!LVL)L%LVj Ll^%LLf )LLfR_^L/*L-L!LVL f-L!LVQL f-L!LVLL%LVL fL%LVQLfL%LVQQLL%LVLLLVj  Ll^%LLf LLfR_^L/*LLLLVLLL-LVLL=VR^ᥥ^R^"^R^^R^^R^^^^^L!LVL fL!LVQLfL!LVL)L%LVj Ll^%LLf )LLfR^N^L/*LLLLVLL-L!LLL-LVLR^^^^^L/&]!LLLL!LVLfL!LVL)L%LVL fp)L%LVQLfV)L%LVQQL-L%LVLLLVLLLVLL-LVLL9VR_^^^^^^L!LVLfL!LVL)L%LVj L=l^%LLf )LLfR_P^L/*LLLLL!LVLfCL!LVL)L%LVLLLVLLLVLL9VR^P^^L!LVL!f.L!LVL)L%LVLLLVR^^^L/&]R_^^L!LVL fL!LVL)L%LVj Ll^%LLf )LLfR_F^L/*LLLLL!LVL fCL!LVL)L%LVLLLVLLLVLL9VR^P^^L!LVL!f.L!LVL)L%LVLLLVR^^^L/&]R^^^L!LVL fnL!LVQL)L!LVL-L%LVj Ll^%LLf -LLfR^.^L/*L)LL)LVR^^^-^ L/&])rLLLL!LVL g2L!LVQLgL!LVQQL)L!LVL-L%LVLLLL!LVLfL!LVL)L%LVj  L9l^%LLf )LLfR_^L/*Lj  L=l^%LLf -LLfR_[^L/*LL)LL)L%zLR_>^^L!LVL fL!LVQLfvL!LVL)L%LVj  Ll^%LLf )LLfR^^L/*LLL-LVLLL)L%zLR^^^^^jLLLL LVl^$LLf L-Lf^X^L/*Lj  Ll^%LLf )LLfR^'^L/*LL)L)L%zLR^L/&]R^S^^^^j Ll^$LLf L-Lf^^L/*LLR^ L/&]!LLLj L9l^$LLf L-Lf^S^L/*Lj L=l^%LLf )LLfR^^L/*LL)L)L%zR^yL!LVL%fSL!LVL)L%LVj L=l^%LLf )LLfR^ ^L/*LR^^^^ L/&]!LLLL!LVL fL!LVQLfL!LVQQL)L!LVL-L%LVLf-L%LVLLLVj  L9l^%LLf LLfR^^L/*Lj  L=l^%LLf LLfR^^L/*LL)LL)L%zR^^R^^^^^L!LVLfSL!LVL)L%LVj L=l^%LLf )LLfR^ ^L/*LR^^^^ L/&]!LLLj L9l^$LLf L-Lf^^L/*L)L!LVLf)L!LVL-L%LVj L9l^%LLf -LLfR_^L/*Lj  L=l^%LLf LLfR_d^L/*LLLLLLLL%zR_B^^L!LVL g L!LVQL fL!LVL)L%LVLf)L%LVL-LLVj L9l^%LLf -LLfR^^L/*Lj  L=l^%LLf LLfR^z^L/*LLLLLL!b L%b^&LL^LLLLV^R^0^^ ^^^^L^ L/&]!LLLL!LVL fL!LVQLfqL!LVQQL)L!LVL-L%LVj L9l^%LLf -LLfR^^L/*LL-L)L%zR^^^^^L!LVLfSL!LVL)L%LVj L9l^%LLf )LLfR^ ^L/*LR^^^^ L/&]!LLLj L9l^$LLf L-Lf^S^L/*Lj L=l^%LLf )LLfR^(^L/*LL)L)L%zR^^ L/&]!LLLL!LVLfRL!LVL)L%LVj L9l^%LLf )LLfR^ ^L/*LR^^^^ L/&]!LLLL!LVL gL!LVQLgwL!LVQQL)L!LVL-L%LVLLLL!LVL fL!LVQL(fL!LVL)L%LVj  L9l^%LLf )LLfR^^L/*LjLL L=Vl^%LLf -LLfR^^L/*LLLLLLL LL%zR^v^^^^jL L=Vl^$LLf L-Lf^3^L/*LLLLLLLL%zR^L/&]R^^^^^L/&])rLLLL!LVLfUL!LVL)L%LVjLL9Vl^%LLf )LLfR^%^L/*LR^^^-L^ L/&])r9LLVLLLLLbLb^,^(QLL=R^#^QLL=R^^L)쥥LLLL-L)LLvajLL9LLLl^CLLf LaL65f!)LLL-LL=V^ ^L/*)RLLLLLL-L-LLQLVL9)Rr77C7S777L/`S7_KL^^^#^-^7^A^JQL)L3"^>RL)L3"^2SL)L3"^&TL)L3"^UL)L3"^VL)L3"^9LL!z9LLzLL39L)L)L_:zrrL^^T^V^X^Z^i^jQLLFL f LFLfcLL*V^A^^QLdLLFL**^#e^f^g^QLhLL**^i^L)LOLaVL.r9LL2L)LC#LOLrLLL)L"L@L9LLL#L@L9LLLj9LL4VLl^4LLf L+aLw f)L=L@^ ^L/*L="L9LNL9LNL9LNxLL39LLI"W3zLL9L5L9LEL9LL9L$L9LL9L%L9LL9LL9L6L9L9LNLLL%L)LL%L7VL)LLL@L9*RLL@L9LAL@L9L&L@L9LBL@L9L9LOLLILL'j L9l^7LLf L+aLUDfZL-LaVL.^ ^L/*)LOL)LLVL)LKLL@RLOLLILL'j L9l^7LLf L+aLUDf[L-LaVL.^ ^L/*)LOL)LLVL)LKLGRLLLLLL%L;VL f^L-L-L!LLL7VLML92RLLL1L9LLL1L9LL1L9L4L1L9LLLL!b L%b^$)LJL9*^QL-LLXL=2^LILLL<VL9LILLL<VL9HL.LIL"L>VL9LIL\L>VL9LIL L>VL9LIL L>VL9LIL L>VL9LL%LL7VL)LLfLL]L9VLILL L>VL=L_L9LILLL<VL9HL.LwL.LILVLwL.LILLL<VL9HL.77z7S7E7 7  7 7 #ſ7  #7 #nN 7 #7 #b 7 #8g7 #4w7 #7 #*=7#7 #n77#^7 #7 #=7 #z 7 #7#97 #7 #)7 #-zK7  #!@7! #77" #|57# #e97$ #"P=7% #37& #I7' #!|7( # P7) #L(7* #7.7+ # 7,#.:7- #&]7. #;7/ #MR70 #-71 #':72 #K73#9л74 #i375 #876 #W77 #?78 #-79 #N7: #N7; #!I7< #в7= #07> #7? #Ci7@ #|7A #~277B#!I7C#:7D #7E #T7F #?7G #>#-7H#*Vc7I #47J #(07K #ǖA7L #q&7M#+7N#H>7O#f7PWLLY7XLX?6L%7ZLZ?T'qL7[L[?UL7\L\?L^7]L]?E@37#nN 7#7#-7#f0 7#7#N+7#M7#V/7#}7#!;7#L;7#7#7#!7#7#ڥA7#"7>7#^7# 7#f7# >7##o7#>97#oc|7#]U7#7#в7#O177#,7#47#\7#f7#77#?7#17#f7#!|7#47#5`*7#7.7#iW7#&]7#K97#57#(07#MR7#:z7#+7LL7L?;L?f0 L)?3U=L?yL?~L?r1]L?9uL?^_L ?W"L ?} L ?5L? L?)L ?D.'L?Mu4R7_7`E7aL/`S7 _ L ^^^)^3^=^G^Q^[^e^nL)L"^bL)L"^VL)L"^JL)L"^>L)L"^2L)L"^&L)L"^L)L"^L)L"^9LL%z9LLz9LLz9LLz9LLz9LLz9LLz9LLzLLLL!b?L%bLb@LbBLbDLbFLbHLbJ^N^J)L!^A)L!^8)L!^/)L!^&)L!^)L!^)L!^ )L!^L ^^^"^.^:^F^R^^^j^u^rQLL!^dQLL!^VQLL!^HQLL!^:QLL!^,QLL!^QLL!^QLL!^L/1&L$L9rL9L)LL)@rL/HoL/Ho#QLL#.Z!L-QL2L!fL%aLL)$e_LLLCRrLLL9LL9LL9LLLVL9rL9L-L-L)L;rL 7z77#K7#-q7#eK<7# S7LL!7L?]8L7L?99L7L?f=uL7L?j0L7L?ǁ=L7L? L7L?XIL7L?L7L?cmLL/HoL#g%Z7L%L/HoL#g%Z7L%L/HoL#g%Z7L%L/HoL#g%Z7L%L/HoL#g%Z7L%L/HoL#g%Z7LL/HoL#g%Z7LL/HoL#g%Z7L%L/HoL#g%Z7LL/HoL#g%Z7LLL)LL)LLLLLLLLLLL LLL LL LL L L?q1 L? L)?/ L?۝ L ? *5 L?2 L?R L?o>- L-?a L?s L?b$ L?g| L?V L ?1& L ?Mu L ?2l L ?NkR  7bL/`S7 _HL^ ^^^& L)L "^ L)L "^ L)L "^9LL%z9L)L)LzrrL/L!LL/1&LLfC)L)$L)LL)f ^ )Lf )L ^)L-L V@)L%2_)L L#.Z!rR/QL /V(L L^ ^^&^C9L L "^7QL9L L)L 3^"QLUL9L L)LL ;^L LL "r LL9L= 7 7 7 7  #K7  #˿7  #ſ7  #lY7  #a17  LL!7  L ?{2#L 7  L ?̨gL 7  L ?t= 7  L L L)LL vL L?-X L-? M L)?4}r L?R  7d7e 7f7g7h_#3U=7i[# >7jb#a7k\#9л7l^#7md#4}r7nh#7oa#W7p_# 7q[#LL7rh#M7sb#7t\#4H(+7ue# 7vg#lY7wb# *57x`#Q 7y[#q7z[#x37{[#ڥA7|b#/7}d# M7~a#7a#N7f#!I7f#f7[#&7h#-X7^# >7]#s%o7[#a17f#07^#f7^#۰127[#Edž47b#b$7f#(07h#7.7[#˿7]# 7[#~87g#VK7[#H 7\#f7LLLLvLL?KVL)?<L-?VKR66L/`S7l _m LLL!b L%b^WW L9L2 LL !^EQL)ULjL9LLF Vl^$LLf LJ aL=^L/*9^LL)L)LX vaH LsL9L%zLL^^&^d^^_"_[9LM L9L-L@ V_BQLUL9LM L9LL@ V=LH L-L-LzL=L%z襥_j9LL: Vl^?LLf LJ aLw f9LM L9LL@ V^ ^L/*!^j9LL: Vl^?LLf LJ aLw f9LM L9LL@ V^ ^L/*!^dQLUL9LFLL-L= ^>QL9*L+ L6 VL!f9LL= F9LLI L@ VL^9ULM L9UL)L@ VLLL9L)LE VR9LL@ V9QL=LL; VL@ VLL%L* f#9QL=LL; VL@ VLL%9LM L!LT L=LH L)LLLzLL%zrLLLLL!b L%b_` LL/ :_QLgUL%gvUQLgfUUL%gVUUQL gDUUQQLa g1UUUL%gUUUQLg UUUUL%gUUUUQL gUUUUQQLa gUUUUUL%gUUUUUQLgUUUUUUL%gUUUUUUQLgjUUUUUUQQLb gOUUUUUUUL%g5UUUUUUUQLgUUUUUUUQQLfQQL)UUUUUUUUL9L)L; VLLfQLj=*LL- Vl^8LLf LJ aLw f=L)LVL= ^ ^L/*LLLL!b L%b^Fc LLALL2 LL ^,QLLA LLL L L^^^^d L2 LL R_^^J^^F^^B^^>^^:^^6^^2^^.^^*^^&^^"^^^^^^^^^^^^ ^^^^QL)ULLL=LM LB VL^6^4^2^0^.^,^.^(^&^$^"^C^^\^^^^^^^^ ^ ^g^~^^^^QLLL; VLA L^^QLe fLA L^^^^QLLL; VL< L^q^fQLT LL)L V^X^MQLP LL)L V^?^4QL' LL)L V^&^QLU LL)L V^ ^)LLL%^RULQL)L-L9L-LL; VL9LL; VL=L-L)LLB KRQLL)L9L-L=L-L; VLLQ VLB ;RLL9 LjL9LLS LLL-L0 + LO L!LL)LL-LZ vLL, VL*LLL!b L%b^- LL= F^QLLf[ L2 LL ^LM LULM L UL L@ V L LG L@ V L@ LH L4 LH L7 LH L,L> LH L%L? LH L L< LO L%zL%zL%zL%zL%zL) VL!L)L& VL QLN V *L L+ LD VLM LLL& VLLLL!b L%b^H-LL!LL& V^3QL)QLL\ L)L, VLL] L)L, V^L!LO LL-L-L^ vLLL-L_ vLLLLL=LLLL LLL Lf v a L( L!LLK LO L6 VL!fLL-_LLg vLL) VLLh vL L) V*LL L= L1 VL LA L@ VQL!L L@ VQL!L L@ VRr9LL=VLC L. LL. LL. LLV L+ LLL. zLL9Lj vL)L) V*fLUL)QL5 VL@ V)LLR VLL)L-L3 VL8 )Rrl 7 7 7! z7" 7# 7$ 7% # #9V7& $ #H)Z7' # #^7( " #ſ7) $ #777* % #>37+ # # S7,  #9л7- # #f7. % #F7/ ! #LL70  #4H(+71 % #;W72 $ #lY73 $ #H74 $ #A75 % #e76 $ #=:577 ! #G978 % #-X79 # #>7: # #N7; $ #,)7< % #O177= $ #W7> $ #D,7? # #!I7@ $ #d]7A # #W7B % #7C  #!I7D % #S7E ! #Edž47F $ #$7G % #!|7H $ #o7I % #7.7J % #iW7K % #&]7L # #7M # #7N % #MR7O $ #<7P $ #ǀ 7Q ! #ua7R $ #VK7S $ #B17T $ # 77U  #f7V /Ho#QL" L#.Z!LLY LLL)L)Li vaLk Ll L? l L?l L-?Ol L)?nRl l 6L/`S7Q _L ^^#^-^7^A^K^U^_^i^s^}^ L)Lu "^z L)Lu "^n L)Lu "^b L)Lu "^V L)Lu "^J L)Lu "^> L)Lu "^2 L)Lu "^& L)Lu "^ L)Lu "^ L)Lu "^9LL!z9LL%z9LLz9L)L)Lzrr9LLz9LLz9LLz9LLz9L)L)Lzrr9L)L)L zrr9LL zLLL!b L%b^uL-Lu *^*L-Lu *^9L-L-L-L!zrr9LL%zL^)^3^=^G^Q^[^e^o^y^^^^^^^^^^^L)Lu "^ L)Lu "^ L)Lu "^L)Lu "^ L)Lu "^L)Lu "^ L)Lu "^ L)Lu "^ L)Lu "^z L)Lu "^n L)Lu "^bL)Lu "^V L)Lu "^JL)Lu "^> L)Lu "^2 L)Lu "^&]L)Lu "^ L)Lu "^`L)Lu "^9LLz9LLz9LLzL^ ^^!^+^5^>L)Lu "^2 L)Lu "^& L)Lu "^ L)Lu "^ L)Lu "^9LL!z9LL%z9LLzLLu 9L)L)Lr)zrrLL VL rL^)^+^-^/^1^3^5^7^9^;^=^?^A^C^E^G^I^U^i^o^k ^g ^c^_^[ ^W^S^O^K$^G^C+^?^;^7 ^3 ^/QLL !^!QL LL L ^ QL^L^ ^^-^8^:^;QLLL9^)QL LL ^QL L숥^  ^ ^L LrL LL LL L9L9L L9L L L9L LL L9L L9L L9L L9L L9L L9L L9L L9L L9L L9L L9L L9L L9L L9L LL LL jL9L Vl^2LLf L aLUDf L-L=V^ ^L/*)L LjL L l^'LLf L a LL=V^L/*L-L)L{ VLL RL9L LL L L L9LL L L9L} LLL!b L%b^))L L9*^QLL LL L=2^L LQLULL)L9VL; L VLL=:_QL-LL9V-LL 2^QL-LL9V-LL 2^QL-LL VLLL9L-L= vaLLL :^QL-LL VLLL=L-L> vaLLL :^aQLULL? L-L VLL9:^37x t #-7y q #n7z p #7{ q # 7| p #^7} t #M7~ t #7 t #!7 p #97 s #!I7 s #f7 t #>97 n #a17 t #O177 r #3U=7 s #07 r #UJ7 p #:7 n #lY7 p #17 q #7 s #I7 t #>#-7 t #!|7 p #*Vc7 t # P7 t #7.7 s #(07 p #.:7 t #iW7 t #&]7 t #(07 t #MR7 p #+7 p #H>7  LL 7 m L ?Β L 7 m L ?Vf9L 7 m L ?%1L 7 m L ?Kp7L 7 m L ??@7L 7 m L ?FL 7 m L ?dNL 7 m L ?47L 7 m L ?N?L 7 m L ?dL 7 m L ?:% LL 7 m L ?8gL 7 m L ?; LL!7 m L ?4L%7 m L ? ZL7 m L ?4L7 m L ?57L7 m L ?FWbL7 m L ?8L7 m L ?/L7 m L ?:L7 m L ?HeL 7 m L ?!;L 7 m L ?G(L 7 m L ?L 7 m L ?L 7 m L ?CEL7 m L ?L7 m L ?TJL 7 m L ?7L 7 m L ?X3L 7 m L ?вʥ LL 7 m L ?L7 m L ?A  LL 7 m L ?;W L LL L L LL LL LL L)L LL L L LL L|L LL L L L%zL%zL%zLL L VL LL L L LL LL LL LL L L LL L L L$L LL LL LL L+L LL LL LL LL LL L L LL LL LL L L LL L L LL L L LL$L vL L LL L L L$L LL L&L L! L L%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zL%zLLL" vL VL L# L L LL$ L&L LL% LL L%zL%zL%zL& L VLLLLLLLLLLL' v2LLL( v2L) 2LLL* v2-LLLLLL2 v-2)LLL4 v)2LL-L5 veLL)L6 vaL LLL8 vLLLLL-LB veL)LC aF LL-L-LP vLQ L-?9Q L?Zn#Q L?~1Q L?2Q L?"7>Q L?3U=Q L?Q L)?Q L? Q L?)Q L ?hQ L ?Q L? Q L?|FQ L?q Q L?/sQ L?!Q L?6 Q L ?a7Q L ?eQ L ?2aRQ Q 6L/`S7z _ZLLY VL] LLL!b L%b ^<s^8UL!fQLR^'^^QL)ULLL] L[ :^LLY VL] LLL!b L%b ^#s^UL!f s^^^QL^|LLl LY VL[ VLL|LY VL] LLL!b L%b^m L8L\ 2^ QL^/Ho#]tLT L#.Z!L^ L` LLfZ ^LX b d Lf Lw Lh LS L#.Z!z 7R z7S 7T E7U 7V T #9V7W V #O177X U #n7Y V #>37Z U # 7[ V #F7\ S #cV7] _ L%L/HoL#g%Z7^ a L%L/HoL#g%Z7` c L!L/HoL#g%Z7b e L!L/HoL#g%Z7d g L%L/HoL#g%Z7f i L%L/HoL#g%Z7h j Lk Ln LW Lo Lp Lq L%L/HoL#g%ZL/LL L/VL LL L)LdL/VzLr Ls LL/HoL#g%ZLt Lu L%L/HoL#g%ZLv Lx Ly Lz L ?z L ?xz L?z L?z L?rz L?=z L)?Uz L?&z L?O&z L ?z L?z L??z L-?z_(?z L ?9z L ?]tRz z 666 6L/`S7 _L^ ^^^& L)L "^L)L "^]L)L "^9LL!z9LL%z9LLz LL QLL L)L)L *RL  L  LL V%L r9L=LLL9LL-L 3R9L=!LL LL LLL9L vL LL L)L VL L)L VL LL Vk+Lg LL VLL L%j LL Vl^6LLf L aLw fL L vL ^ ^L/*LL^ ^^J^QLL쭥^QL L f  L L L VL L L%L)^iQL L f  L L L VL L L%j L l^$LLf L a L ^L/*LL-R^R_l^XLLf L aLuf6LL%L VL L L L LL9V^ ^L/*QRrL L-L-L-L966 #s%o675#&68# 69%#a16: #f6;!#6<!#76=%#!|6>#-X6?%#7.6@5#ua6A# 6B%#MR6C'#VK6D#6E#3U=6F5#}~&6G#3U=6H%#>36I #6J #W6K# 6L!#t,96M# 6N#KV6O# M6P #N6Q##f6R5#a16S%#O176T#x6U'#4}r6V#3U=6W #16X5#Edž46Y'#$6Z #۰126[#6\ # 6]%#(06^#6_#26`!#3U=6aILLLbLgLLhL-LLLkvLLLnvLL-LLqvLLLuvLLLxvL{L}LkEL~LLLLLQLLILCL!L>LLLLLLLLLLLLLLLvLL LLMLLzL>L LLL"LLMLLzL>LLL=LLzLCL%zL%zL%zL%zL%zL%zL%zL%zL%zLLLLLLLvLaV-LLL!b L%b^^QLLL.L\V^Rl^LLf L@aLL_:bL (I/b6LZg6bOLr)bh^^QL)ULLNLLVR^^bQL)ULLLLLVR^f^BQL)ULL]LLVR^F^"QL)ULLBLLVR^&^LL^LXLV^ L/*L ?׹L)?<L?DžL?4L?$0L?TL?5zL?4}rL-?hL ?M=LL?L?s%oR