diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:22 +0000 |
commit | c21c3b0befeb46a51b6bf3758ffa30813bea0ff0 (patch) | |
tree | 9754ff1ca740f6346cf8483ec915d4054bc5da2d /web/server/h2o/libh2o/deps/mruby | |
parent | Adding upstream version 1.43.2. (diff) | |
download | netdata-c21c3b0befeb46a51b6bf3758ffa30813bea0ff0.tar.xz netdata-c21c3b0befeb46a51b6bf3758ffa30813bea0ff0.zip |
Adding upstream version 1.44.3.upstream/1.44.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
454 files changed, 96933 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/deps/mruby-digest/.gitignore b/web/server/h2o/libh2o/deps/mruby-digest/.gitignore new file mode 100644 index 000000000..55ef3162f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/.gitignore @@ -0,0 +1,5 @@ +gem_* +gem-* +mrb-*.a +src/*.o +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-digest/.travis.yml b/web/server/h2o/libh2o/deps/mruby-digest/.travis.yml new file mode 100644 index 000000000..ffe227284 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-digest/Makefile b/web/server/h2o/libh2o/deps/mruby-digest/Makefile new file mode 100644 index 000000000..21f8afe00 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/Makefile @@ -0,0 +1,14 @@ +GEM := mruby-digest + +include $(MAKEFILE_4_GEM) + +GEM_C_FILES := $(wildcard $(SRC_DIR)/*.c) +GEM_OBJECTS := $(patsubst %.c, %.o, $(GEM_C_FILES)) + +GEM_RB_FILES := $(wildcard $(MRB_DIR)/*.rb) + +gem-all : $(GEM_OBJECTS) gem-c-and-rb-files + +gem-clean : gem-clean-c-and-rb-files + +gem-test : gem-test-c-and-rb-files diff --git a/web/server/h2o/libh2o/deps/mruby-digest/README.md b/web/server/h2o/libh2o/deps/mruby-digest/README.md new file mode 100644 index 000000000..2ae6552c8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/README.md @@ -0,0 +1,55 @@ +mruby-digest +========= + +This library is a fork of [github.com/iij/mruby-digest](https://github.com/iij/mruby-digest). +Unlike the original, this fork does not have any dependencies; it uses [picohash](https://github.com/kazuho/picohash) - a public domain library for hash calculation. + +## Features + +Message Digest and HMAC classes are available. They are compatible with CRuby's ones. + +- Digest::MD5, Digest::RMD160, Digest::SHA1, Digest::SHA256, Digest::SHA384 and + Digest::SHA512 + - Note: some of them are not available if libcrypto.a does not support them on your system. +- Digest::HMAC + +## Install + - add conf.gem line to `build_config.rb` + +```ruby +MRuby::Build.new do |conf| + + # ... (snip) ... + + conf.gem :git => 'https://github.com/iij/mruby-digest.git' +end +``` + +## Usage +```ruby +Digest::MD5.digest('ruby') +Digest::MD5.hexdigest('ruby') +``` + +## License + +Copyright (c) 2012-2015 Internet Initiative Japan Inc., Kazuho Oku + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/web/server/h2o/libh2o/deps/mruby-digest/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-digest/mrbgem.rake new file mode 100644 index 000000000..9324f169b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/mrbgem.rake @@ -0,0 +1,4 @@ +MRuby::Gem::Specification.new('mruby-digest') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan Inc.' +end diff --git a/web/server/h2o/libh2o/deps/mruby-digest/mrblib/digest.rb b/web/server/h2o/libh2o/deps/mruby-digest/mrblib/digest.rb new file mode 100644 index 000000000..7779f54b9 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/mrblib/digest.rb @@ -0,0 +1,46 @@ +if Object.const_defined? :Digest +module Digest + class Base + def self.digest(data) + self.new.update(data).digest + end + def self.file(path) + self.new.update(File.open(path).read) + end + def self.hexdigest(data) + self.new.update(data).hexdigest + end + def ==(other) + if other.kind_of? String + self.hexdigest == other + else + self.digest == other.digest + end + end + def file(path) + self.update(File.open(path).read) + end + def hexdigest! + x = self.hexdigest + self.reset + x + end + + alias length digest_length + alias size digest_length + alias to_s hexdigest + alias << update + end + + class HMAC + def self.digest(data, key, digest) + self.new(key, digest).update(data).digest + end + def self.hexdigest(data, key, digest) + self.new(key, digest).update(data).hexdigest + end + + alias << update + end +end +end diff --git a/web/server/h2o/libh2o/deps/mruby-digest/run_test.rb b/web/server/h2o/libh2o/deps/mruby-digest/run_test.rb new file mode 100644 index 000000000..3401ed86c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/run_test.rb @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +gemname = File.basename(File.dirname(File.expand_path __FILE__)) + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + build_args = ['all', 'test'] if build_args.nil? or build_args.empty? + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + enable_debug + enable_test + conf.gembox 'default' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-digest/src/digest.c b/web/server/h2o/libh2o/deps/mruby-digest/src/digest.c new file mode 100644 index 000000000..634376d96 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/src/digest.c @@ -0,0 +1,1007 @@ +/* +** digest.c - Digest and subclasses +** +** See Copyright Notice in mruby.h +*/ + +#include "mruby.h" + +#define USE_DIGEST_PICOHASH + +#if !defined(USE_DIGEST_PICOHASH) +#elif defined(__APPLE__) +#define USE_DIGEST_OSX_COMMONCRYPTO +#else +#define USE_DIGEST_OPENSSL +#endif + +#if defined(USE_DIGEST_PICOHASH) +#include "picohash.h" +#elif defined(USE_DIGEST_OPENSSL) +#include <openssl/evp.h> +#include <openssl/hmac.h> +#include <openssl/sha.h> +#elif defined(USE_DIGEST_OSX_COMMONCRYPTO) +#include <CommonCrypto/CommonDigest.h> +#include <CommonCrypto/CommonHMAC.h> +#else +#error "define USE_DIGEST_PICOHASH or USE_DIGEST_OPENSSL or USE_DIGEST_OSX_COMMONCRYPTO" +#endif +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include "mruby/array.h" +#include "mruby/class.h" +#include "mruby/data.h" +#include "mruby/string.h" +#include "mruby/variable.h" + +#define TYPESYM "__type__" + + +/* + * library-independent layer API + */ +enum { + MD_TYPE_MD5, + MD_TYPE_RMD160, + MD_TYPE_SHA1, + MD_TYPE_SHA256, + MD_TYPE_SHA384, + MD_TYPE_SHA512, +}; + +struct mrb_md; +struct mrb_hmac; + +static void lib_init(void); +static int lib_md_block_length(const struct mrb_md *); +static mrb_value lib_md_digest(mrb_state *, const struct mrb_md *); +static mrb_value lib_md_digest_bang(mrb_state *, struct mrb_md *); +static int lib_md_digest_length(const struct mrb_md *); +static void lib_md_free(mrb_state *, void *); +static void lib_md_init(mrb_state *, struct mrb_md *, int); +static void lib_md_init_copy(mrb_state *, struct mrb_md *, struct mrb_md *); +static void lib_md_reset(mrb_state *, struct mrb_md *); +static void lib_md_update(mrb_state *, struct mrb_md *, unsigned char *, mrb_int); + +static mrb_value lib_hmac_digest(mrb_state *, const struct mrb_hmac *); +static int lib_hmac_block_length(const struct mrb_hmac *); +static int lib_hmac_digest_length(const struct mrb_hmac *); +static void lib_hmac_free(mrb_state *, void *); +static void lib_hmac_init(mrb_state *, struct mrb_hmac *, int, const unsigned char *, mrb_int); +static void lib_hmac_update(mrb_state *, struct mrb_hmac *, unsigned char *, mrb_int); + + +#if defined(USE_DIGEST_PICOHASH) + +#define HAVE_MD5 +#define HAVE_SHA1 + +struct mrb_md { + picohash_ctx_t ctx; +}; + +struct mrb_hmac { + picohash_ctx_t ctx; +}; + +static void +lib_md_free(mrb_state *mrb, void *ptr) +{ + struct mrb_md *md = ptr; + if (md != NULL) + mrb_free(mrb, md); +} + +static void +lib_hmac_free(mrb_state *mrb, void *ptr) +{ + struct mrb_hmac *hmac = ptr; + if (hmac != NULL) + mrb_free(mrb, hmac); +} + +static struct mrb_data_type mrb_md_type = { "MD", lib_md_free }; +static struct mrb_data_type mrb_hmac_type = { "HMAC", lib_hmac_free }; + +static void +lib_init(void) +{ +} + +static int +lib_md_block_length(const struct mrb_md *md) +{ + return (int)md->ctx.block_length; +} + +static mrb_value +lib_md_digest(mrb_state *mrb, const struct mrb_md *md) +{ + picohash_ctx_t ctx; + unsigned char mdstr[PICOHASH_MAX_DIGEST_LENGTH]; + + ctx = md->ctx; + picohash_final(&ctx, mdstr); + return mrb_str_new(mrb, (char *)mdstr, ctx.digest_length); +} + +static mrb_value +lib_md_digest_bang(mrb_state *mrb, struct mrb_md *md) +{ + unsigned char mdstr[PICOHASH_MAX_DIGEST_LENGTH]; + + picohash_final(&md->ctx, mdstr); + picohash_reset(&md->ctx); + return mrb_str_new(mrb, (char *)mdstr, md->ctx.digest_length); +} + +static int +lib_md_digest_length(const struct mrb_md *md) +{ + return md->ctx.digest_length; +} + +static void (*md_type_md(int type))(picohash_ctx_t *) +{ + switch (type) { + case MD_TYPE_MD5: return picohash_init_md5; + case MD_TYPE_SHA1: return picohash_init_sha1; + default: return NULL; + } +} + +static void +lib_md_init(mrb_state *mrb, struct mrb_md *md, int type) +{ + void (*ctor)(picohash_ctx_t *) = md_type_md(type); + if (ctor == NULL) + mrb_raise(mrb, E_NOTIMP_ERROR, "not supported"); + ctor(&md->ctx); +} + +static void +lib_md_init_copy(mrb_state *mrb, struct mrb_md *mdnew, struct mrb_md *mdold) +{ + mdnew->ctx = mdold->ctx; + picohash_reset(&mdnew->ctx); +} + +static void +lib_md_reset(mrb_state *mrb, struct mrb_md *md) +{ + picohash_reset(&md->ctx); +} + +static void +lib_md_update(mrb_state *mrb, struct mrb_md *md, unsigned char *str, mrb_int len) +{ +#if MRB_INT_MAX > SIZE_MAX + if (len > SIZE_MAX) + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string (not supported yet)"); +#endif + picohash_update(&md->ctx, str, len); +} + +static mrb_value +lib_hmac_digest(mrb_state *mrb, const struct mrb_hmac *hmac) +{ + picohash_ctx_t ctx; + unsigned char mdstr[PICOHASH_MAX_DIGEST_LENGTH]; + + ctx = hmac->ctx; + picohash_final(&ctx, mdstr); + return mrb_str_new(mrb, (char *)mdstr, ctx.digest_length); +} + +static int +lib_hmac_block_length(const struct mrb_hmac *hmac) +{ + return hmac->ctx.block_length; +} + +static int +lib_hmac_digest_length(const struct mrb_hmac *hmac) +{ + return hmac->ctx.digest_length; +} + +static void +lib_hmac_init(mrb_state *mrb, struct mrb_hmac *hmac, int type, const unsigned char *key, mrb_int keylen) +{ + void (*ctor)(picohash_ctx_t *) = md_type_md(type); + +#if MRB_INT_MAX > SIZE_MAX + if (keylen > SIZE_MAX) + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long key"); +#endif + if (ctor == NULL) + mrb_raise(mrb, E_NOTIMP_ERROR, "not supported"); + picohash_init_hmac(&hmac->ctx, ctor, key, keylen); +} + +static void +lib_hmac_update(mrb_state *mrb, struct mrb_hmac *hmac, unsigned char *data, mrb_int len) +{ +#if MRB_INT_MAX > SIZE_MAX + if (len > SIZE_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string (not supported yet)"); + } +#endif + picohash_update(&hmac->ctx, data, len); +} + +#elif defined(USE_DIGEST_OPENSSL) +/* + * OpenSSL Implementation + */ + +#define HAVE_MD5 + +#ifndef OPENSSL_NO_RIPEMD +#define HAVE_RMD160 +#endif + +#define HAVE_SHA1 +#ifdef SHA256_DIGEST_LENGTH +#define HAVE_SHA256 +#endif +#ifdef SHA512_DIGEST_LENGTH +#define HAVE_SHA384 +#define HAVE_SHA512 +#endif + +struct mrb_md { + EVP_MD_CTX *ctx; +}; + +struct mrb_hmac { + HMAC_CTX ctx; + const EVP_MD *md; +}; + +static void +lib_md_free(mrb_state *mrb, void *ptr) +{ + struct mrb_md *md = ptr; + + if (md != NULL) { + if (md->ctx != NULL) { + EVP_MD_CTX_destroy(md->ctx); + } + mrb_free(mrb, md); + } +} + +static void +lib_hmac_free(mrb_state *mrb, void *ptr) +{ + struct mrb_hmac *hmac = ptr; + + if (hmac != NULL) { + HMAC_CTX_cleanup(&hmac->ctx); + mrb_free(mrb, hmac); + } +} + +static struct mrb_data_type mrb_md_type = { "MD", lib_md_free }; +static struct mrb_data_type mrb_hmac_type = { "HMAC", lib_hmac_free }; + +static void +lib_init(void) +{ + OpenSSL_add_all_digests(); +} + +static int +lib_md_block_length(const struct mrb_md *md) +{ + return EVP_MD_CTX_block_size(md->ctx); +} + +static mrb_value +lib_md_digest(mrb_state *mrb, const struct mrb_md *md) +{ + EVP_MD_CTX ctx; + unsigned int mdlen; + unsigned char mdstr[EVP_MAX_MD_SIZE]; + + EVP_MD_CTX_copy(&ctx, md->ctx); + EVP_DigestFinal(&ctx, mdstr, &mdlen); + return mrb_str_new(mrb, (char *)mdstr, mdlen); +} + +static mrb_value +lib_md_digest_bang(mrb_state *mrb, struct mrb_md *md) +{ + unsigned int mdlen; + unsigned char mdstr[EVP_MAX_MD_SIZE]; + + EVP_DigestFinal_ex(md->ctx, mdstr, &mdlen); + EVP_DigestInit_ex(md->ctx, EVP_MD_CTX_md(md->ctx), NULL); + return mrb_str_new(mrb, (char *)mdstr, mdlen); +} + +static int +lib_md_digest_length(const struct mrb_md *md) +{ + return EVP_MD_CTX_size(md->ctx); +} + +const EVP_MD * +md_type_md(int type) +{ + switch (type) { + case MD_TYPE_MD5: return EVP_md5(); +#ifdef HAVE_RMD160 + case MD_TYPE_RMD160: return EVP_ripemd160(); +#endif + case MD_TYPE_SHA1: return EVP_sha1(); +#ifdef HAVE_SHA256 + case MD_TYPE_SHA256: return EVP_sha256(); +#endif +#ifdef HAVE_SHA512 + case MD_TYPE_SHA384: return EVP_sha384(); + case MD_TYPE_SHA512: return EVP_sha512(); +#endif + default: return NULL; + } +} + +static void +lib_md_init(mrb_state *mrb, struct mrb_md *md, int type) +{ + const EVP_MD *evpmd; + + md->ctx = NULL; + evpmd = md_type_md(type); + if (!evpmd) { + mrb_raise(mrb, E_NOTIMP_ERROR, "not supported"); + } + md->ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md->ctx, evpmd, NULL); +} + +static void +lib_md_init_copy(mrb_state *mrb, struct mrb_md *mdnew, struct mrb_md *mdold) +{ + mdnew->ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdnew->ctx, EVP_MD_CTX_md(mdold->ctx), NULL); +} + +static void +lib_md_reset(mrb_state *mrb, struct mrb_md *md) +{ + //EVP_MD_CTX_init(&md->ctx); + EVP_DigestInit_ex(md->ctx, EVP_MD_CTX_md(md->ctx), NULL); +} + +static void +lib_md_update(mrb_state *mrb, struct mrb_md *md, unsigned char *str, mrb_int len) +{ +#if MRB_INT_MAX > SIZE_MAX + if (len > SIZE_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string (not supported yet)"); + } +#endif + EVP_DigestUpdate(md->ctx, str, len); +} + +static mrb_value +lib_hmac_digest(mrb_state *mrb, const struct mrb_hmac *hmac) +{ + HMAC_CTX ctx; + unsigned int mdlen; + unsigned char mdstr[EVP_MAX_MD_SIZE]; + + memcpy(&ctx, &hmac->ctx, sizeof(ctx)); + HMAC_Final(&ctx, mdstr, &mdlen); + return mrb_str_new(mrb, (char *)mdstr, mdlen); +} + +static int +lib_hmac_block_length(const struct mrb_hmac *hmac) +{ + return EVP_MD_block_size(hmac->md); +} + +static int +lib_hmac_digest_length(const struct mrb_hmac *hmac) +{ + return EVP_MD_size(hmac->md); +} + +static void +lib_hmac_init(mrb_state *mrb, struct mrb_hmac *hmac, int type, const unsigned char *key, mrb_int keylen) +{ +#if MRB_INT_MAX > INT_MAX + if (keylen > INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long key"); + } +#endif + hmac->md = md_type_md(type); + HMAC_CTX_init(&hmac->ctx); + HMAC_Init_ex(&hmac->ctx, key, keylen, hmac->md, NULL); +} + +static void +lib_hmac_update(mrb_state *mrb, struct mrb_hmac *hmac, unsigned char *data, mrb_int len) +{ +#if MRB_INT_MAX > INT_MAX + if (len > INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string (not supported yet)"); + } +#endif + HMAC_Update(&hmac->ctx, data, len); +} + +#elif defined(USE_DIGEST_OSX_COMMONCRYPTO) +/* + * Mac OS X CommonCrypto Implementation + */ + +#define HAVE_MD5 +/* #define HAVE_RMD160 */ +#define HAVE_SHA1 +#define HAVE_SHA256 +#define HAVE_SHA384 +#define HAVE_SHA512 + +struct mrb_md { + int type; + void *ctx; + int ctx_size; +}; + +struct mrb_hmac { + int type; + CCHmacContext ctx; +}; + +static int +md_ctx_size(int type) +{ + switch (type) { + case MD_TYPE_MD5: return sizeof(CC_MD5_CTX); + case MD_TYPE_SHA1: return sizeof(CC_SHA1_CTX); + case MD_TYPE_SHA256: return sizeof(CC_SHA256_CTX); + case MD_TYPE_SHA384: return sizeof(CC_SHA512_CTX); /* ! */ + case MD_TYPE_SHA512: return sizeof(CC_SHA512_CTX); + default: return 0; + } +} + +static void +lib_md_free(mrb_state *mrb, void *ptr) +{ + struct mrb_md *md = ptr; + + memset(md->ctx, 0, md_ctx_size(md->type)); + mrb_free(mrb, md->ctx); + mrb_free(mrb, md); +} + +static void +lib_hmac_free(mrb_state *mrb, void *ptr) +{ + struct mrb_hmac *hmac = ptr; + + memset(&hmac->ctx, 0, sizeof(hmac->ctx)); + mrb_free(mrb, hmac); +} + +static struct mrb_data_type mrb_md_type = { "MD", lib_md_free }; +static struct mrb_data_type mrb_hmac_type = { "HMAC", lib_hmac_free }; + +#define MAX_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH + +union ctx_union { + CC_MD5_CTX md5; + CC_SHA1_CTX sha1; + CC_SHA256_CTX sha256; + /* we don't have CC_SHA384_CTX! */ + CC_SHA512_CTX sha512; +}; + +static void +lib_init(void) +{ +} + +static int +md_block_length(int type) +{ + switch (type) { + case MD_TYPE_MD5: return CC_MD5_BLOCK_BYTES; + case MD_TYPE_SHA1: return CC_SHA1_BLOCK_BYTES; + case MD_TYPE_SHA256: return CC_SHA256_BLOCK_BYTES; + case MD_TYPE_SHA384: return CC_SHA384_BLOCK_BYTES; + case MD_TYPE_SHA512: return CC_SHA512_BLOCK_BYTES; + default: return 0; + } +} + +static int +lib_md_block_length(const struct mrb_md *md) +{ + return md_block_length(md->type); +} + +static void +md_init(int type, void *ctxp) +{ + switch (type) { + case MD_TYPE_MD5: CC_MD5_Init(ctxp); break; + case MD_TYPE_SHA1: CC_SHA1_Init(ctxp); break; + case MD_TYPE_SHA256: CC_SHA256_Init(ctxp); break; + case MD_TYPE_SHA384: CC_SHA384_Init(ctxp); break; + case MD_TYPE_SHA512: CC_SHA512_Init(ctxp); break; + default: break; + } +} + +static void +md_final(int type, unsigned char *str, void *ctx) +{ + switch (type) { + case MD_TYPE_MD5: CC_MD5_Final(str, ctx); break; + case MD_TYPE_SHA1: CC_SHA1_Final(str, ctx); break; + case MD_TYPE_SHA256: CC_SHA256_Final(str, ctx); break; + case MD_TYPE_SHA384: CC_SHA384_Final(str, ctx); break; + case MD_TYPE_SHA512: CC_SHA512_Final(str, ctx); break; + default: break; + } +} + +static int +md_digest_length(int type) +{ + switch (type) { + case MD_TYPE_MD5: return 16; + case MD_TYPE_SHA1: return 20; + case MD_TYPE_SHA256: return 32; + case MD_TYPE_SHA384: return 48; + case MD_TYPE_SHA512: return 64; + default: return 0; + } +} + +static mrb_value +lib_md_digest(mrb_state *mrb, const struct mrb_md *md) +{ + union ctx_union ctx; + unsigned char mdstr[MAX_DIGEST_LENGTH]; + + memcpy(&ctx, md->ctx, md_ctx_size(md->type)); + md_final(md->type, mdstr, &ctx); + return mrb_str_new(mrb, (char *)mdstr, md_digest_length(md->type)); +} + +static mrb_value +lib_md_digest_bang(mrb_state *mrb, struct mrb_md *md) +{ + unsigned char mdstr[MAX_DIGEST_LENGTH]; + + md_final(md->type, mdstr, md->ctx); + md_init(md->type, md->ctx); + return mrb_str_new(mrb, (char *)mdstr, md_digest_length(md->type)); +} + +static int +lib_md_digest_length(const struct mrb_md *md) +{ + return md_digest_length(md->type); +} + +static void +lib_md_init(mrb_state *mrb, struct mrb_md *md, int type) +{ + int ctxsize; + + ctxsize = md_ctx_size(type); + if (ctxsize == 0) { + mrb_raise(mrb, E_NOTIMP_ERROR, "not supported"); + } + md->type = type; + md->ctx = NULL; + md->ctx = mrb_malloc(mrb, ctxsize); + md_init(type, md->ctx); +} + +static void +lib_md_init_copy(mrb_state *mrb, struct mrb_md *mdnew, struct mrb_md *mdold) +{ + lib_md_init(mrb, mdnew, mdold->type); +} + +static void +lib_md_reset(mrb_state *mrb, struct mrb_md *md) +{ + md_init(md->type, md->ctx); +} + +static void +lib_md_update(mrb_state *mrb, struct mrb_md *md, unsigned char *data, mrb_int len) +{ + if (sizeof(len) > sizeof(CC_LONG)) { + if (len != (CC_LONG)len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string (not supported yet)"); + } + } + switch (md->type) { + case MD_TYPE_MD5: CC_MD5_Update(md->ctx, data, len); break; + case MD_TYPE_SHA1: CC_SHA1_Update(md->ctx, data, len); break; + case MD_TYPE_SHA256: CC_SHA256_Update(md->ctx, data, len); break; + case MD_TYPE_SHA384: CC_SHA384_Update(md->ctx, data, len); break; + case MD_TYPE_SHA512: CC_SHA512_Update(md->ctx, data, len); break; + default: break; + } +} + +static int +lib_hmac_block_length(const struct mrb_hmac *hmac) +{ + return md_block_length(hmac->type); +} + +static mrb_value +lib_hmac_digest(mrb_state *mrb, const struct mrb_hmac *hmac) +{ + CCHmacContext ctx; + unsigned char str[MAX_DIGEST_LENGTH]; + + memcpy(&ctx, &hmac->ctx, sizeof(ctx)); + CCHmacFinal(&ctx, str); + return mrb_str_new(mrb, (const char *)str, md_digest_length(hmac->type)); +} + +static int +lib_hmac_digest_length(const struct mrb_hmac *hmac) +{ + return md_digest_length(hmac->type); +} + +static void +lib_hmac_init(mrb_state *mrb, struct mrb_hmac *hmac, int type, const unsigned char *key, mrb_int keylen) +{ + CCHmacAlgorithm algorithm; + +#if MRB_INT_MAX > SIZE_MAX + if (len > SIZE_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long key"); + } +#endif + switch (type) { + case MD_TYPE_MD5: algorithm = kCCHmacAlgMD5; break; + case MD_TYPE_SHA1: algorithm = kCCHmacAlgSHA1; break; + case MD_TYPE_SHA256: algorithm = kCCHmacAlgSHA256; break; + case MD_TYPE_SHA384: algorithm = kCCHmacAlgSHA384; break; + case MD_TYPE_SHA512: algorithm = kCCHmacAlgSHA512; break; + default: + mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-digest: internal error: unexpected HMAC type: %S", mrb_fixnum_value(type)); + algorithm = 0; + break; + } + hmac->type = type; + CCHmacInit(&hmac->ctx, algorithm, key, keylen); +} + +static void +lib_hmac_update(mrb_state *mrb, struct mrb_hmac *hmac, unsigned char *data, mrb_int len) +{ +#if MRB_INT_MAX > SIZE_MAX + if (len > SIZE_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string"); + } +#endif + CCHmacUpdate(&hmac->ctx, data, len); +} + +#endif + +static void +basecheck(mrb_state *mrb, mrb_value self, struct mrb_md **mdp) +{ + struct RClass *c; + struct mrb_md *md; + mrb_value t; + + c = mrb_obj_class(mrb, self); + t = mrb_const_get(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, TYPESYM)); + if (mrb_nil_p(t)) { + mrb_raise(mrb, E_NOTIMP_ERROR, "Digest::Base is an abstract class"); + } + md = (struct mrb_md *)DATA_PTR(self); + if (!md) { + mrb_raise(mrb, E_RUNTIME_ERROR, "no md found (BUG?)"); + } + if (mdp) *mdp = md; +} + +static mrb_value +mrb_digest_block_length(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + + basecheck(mrb, self, &md); + return mrb_fixnum_value(lib_md_block_length(md)); +} + +static mrb_value +mrb_digest_digest(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + + md = (struct mrb_md *)DATA_PTR(self); + if (!md) return mrb_nil_value(); + return lib_md_digest(mrb, md); +} + +static mrb_value +mrb_digest_digest_bang(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + + md = (struct mrb_md *)DATA_PTR(self); + if (!md) return mrb_nil_value(); + return lib_md_digest_bang(mrb, md); +} + +static mrb_value +mrb_digest_digest_length(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + + basecheck(mrb, self, &md); + return mrb_fixnum_value(lib_md_digest_length(md)); +} + +static mrb_value +digest2hexdigest(mrb_state *mrb, mrb_value b) +{ + mrb_value h; + int i, len; + char *bp, buf[3]; + + bp = RSTRING_PTR(b); + len = RSTRING_LEN(b); + h = mrb_str_buf_new(mrb, len * 2); + for (i = 0; i < len; i++) { + snprintf(buf, sizeof(buf), "%02x", (unsigned char )bp[i]); + mrb_str_buf_cat(mrb, h, buf, 2); + } + return h; +} + +static mrb_value +mrb_digest_hexdigest(mrb_state *mrb, mrb_value self) +{ + return digest2hexdigest(mrb, mrb_digest_digest(mrb, self)); +} + +static mrb_value +mrb_digest_init(mrb_state *mrb, mrb_value self) +{ + struct RClass *c; + struct mrb_md *md; + mrb_value t; + + md = (struct mrb_md *)DATA_PTR(self); + if (md) { + lib_md_free(mrb, md); + } + DATA_TYPE(self) = &mrb_md_type; + DATA_PTR(self) = NULL; + + c = mrb_obj_class(mrb, self); + if (!mrb_const_defined(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, TYPESYM))) { + mrb_raise(mrb, E_NOTIMP_ERROR, "Digest::Base is an abstract class"); + } + t = mrb_const_get(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, TYPESYM)); +#if 0 + if (lib_md_supported(t)) { + mrb_raise(mrb, E_NOTIMP_ERROR, "unknown algorithm"); + } +#endif + + md = (struct mrb_md *)mrb_malloc(mrb, sizeof(*md)); + DATA_PTR(self) = md; + lib_md_init(mrb, md, mrb_fixnum(t)); + return self; +} + +static mrb_value +mrb_digest_init_copy(mrb_state *mrb, mrb_value copy) +{ + struct mrb_md *m1, *m2; + mrb_value src; + + mrb_get_args(mrb, "o", &src); + if (mrb_obj_equal(mrb, copy, src)) return copy; + if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) { + mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); + } + if (!DATA_PTR(copy)) { + DATA_PTR(copy) = mrb_malloc(mrb, sizeof(struct mrb_md)); + DATA_TYPE(copy) = &mrb_md_type; + } + m1 = DATA_PTR(src); + m2 = DATA_PTR(copy); + lib_md_init_copy(mrb, m2, m1); + return copy; +} + +static mrb_value +mrb_digest_reset(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + + md = (struct mrb_md *)DATA_PTR(self); + if (!md) return mrb_nil_value(); + lib_md_reset(mrb, md); + return self; +} + +static mrb_value +mrb_digest_update(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + mrb_int len; + char *str; + + md = (struct mrb_md *)DATA_PTR(self); + if (!md) return mrb_nil_value(); + mrb_get_args(mrb, "s", &str, &len); + lib_md_update(mrb, md, (unsigned char *)str, len); + return self; +} + +static mrb_value +mrb_hmac_block_length(mrb_state *mrb, mrb_value self) +{ + struct mrb_hmac *hmac; + + hmac = (struct mrb_hmac *)DATA_PTR(self); + if (!hmac) return mrb_nil_value(); + return mrb_fixnum_value(lib_hmac_block_length(hmac)); +} + +static mrb_value +mrb_hmac_digest(mrb_state *mrb, mrb_value self) +{ + struct mrb_hmac *hmac; + + hmac = (struct mrb_hmac *)DATA_PTR(self); + if (!hmac) return mrb_nil_value(); + return lib_hmac_digest(mrb, hmac); +} + +static mrb_value +mrb_hmac_digest_length(mrb_state *mrb, mrb_value self) +{ + struct mrb_hmac *hmac; + + hmac = (struct mrb_hmac *)DATA_PTR(self); + if (!hmac) return mrb_nil_value(); + return mrb_fixnum_value(lib_hmac_digest_length(hmac)); +} + +static mrb_value +mrb_hmac_hexdigest(mrb_state *mrb, mrb_value self) +{ + return digest2hexdigest(mrb, mrb_hmac_digest(mrb, self)); +} + +static mrb_value +mrb_hmac_init(mrb_state *mrb, mrb_value self) +{ + struct mrb_hmac *hmac; + mrb_value digest, t; + mrb_int keylen; + char *key; + + hmac = (struct mrb_hmac *)DATA_PTR(self); + if (hmac) { + lib_hmac_free(mrb, hmac); + } + DATA_TYPE(self) = &mrb_hmac_type; + DATA_PTR(self) = NULL; + + mrb_get_args(mrb, "so", &key, &keylen, &digest); + t = mrb_const_get(mrb, digest, mrb_intern_lit(mrb, TYPESYM)); + if (mrb_nil_p(t)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "not a digester"); + } + + hmac = (struct mrb_hmac *)mrb_malloc(mrb, sizeof(*hmac)); + DATA_PTR(self) = hmac; + lib_hmac_init(mrb, hmac, mrb_fixnum(t), (unsigned char *)key, keylen); + return self; +} + +static mrb_value +mrb_hmac_init_copy(mrb_state *mrb, mrb_value copy) +{ + mrb_raise(mrb, E_RUNTIME_ERROR, "cannot duplicate HMAC"); + return copy; +} + +static mrb_value +mrb_hmac_update(mrb_state *mrb, mrb_value self) +{ + struct mrb_hmac *hmac; + mrb_int len; + char *str; + + hmac = (struct mrb_hmac *)DATA_PTR(self); + if (!hmac) return mrb_nil_value(); + mrb_get_args(mrb, "s", &str, &len); + lib_hmac_update(mrb, hmac, (unsigned char *)str, len); + return self; +} + + +void +mrb_mruby_digest_gem_init(mrb_state *mrb) +{ + struct RClass *b, *d, *h; + + lib_init(); + + d = mrb_define_module(mrb, "Digest"); + + b = mrb_define_class_under(mrb, d, "Base", mrb->object_class); + mrb_define_method(mrb, b, "block_length", mrb_digest_block_length, MRB_ARGS_NONE()); + mrb_define_method(mrb, b, "digest", mrb_digest_digest, MRB_ARGS_NONE()); + mrb_define_method(mrb, b, "digest!", mrb_digest_digest_bang, MRB_ARGS_NONE()); /* XXX: can be defined in mrblib... */ + mrb_define_method(mrb, b, "digest_length", mrb_digest_digest_length, MRB_ARGS_NONE()); + //mrb_define_method(mrb, b, "file", mrb_digest_file, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, b, "hexdigest", mrb_digest_hexdigest, MRB_ARGS_NONE()); + //mrb_define_method(mrb, b, "hexdigest!", mrb_digest_hexdigest_bang, MRB_ARGS_NONE()); /* XXX: can be defined in mrblib... */ + mrb_define_method(mrb, b, "initialize", mrb_digest_init, MRB_ARGS_NONE()); + mrb_define_method(mrb, b, "initialize_copy", mrb_digest_init_copy, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, b, "reset", mrb_digest_reset, MRB_ARGS_NONE()); + mrb_define_method(mrb, b, "update", mrb_digest_update, MRB_ARGS_REQ(1)); + +#define DEFCLASS(n) \ +do { \ + struct RClass *a = mrb_define_class_under(mrb, d, #n, b); \ + MRB_SET_INSTANCE_TT(a, MRB_TT_DATA); \ + mrb_define_const(mrb, a, TYPESYM, mrb_fixnum_value(MD_TYPE_##n)); \ +} while (0) + +#ifdef HAVE_MD5 + DEFCLASS(MD5); +#endif +#ifdef HAVE_RMD160 + DEFCLASS(RMD160); +#endif +#ifdef HAVE_SHA1 + DEFCLASS(SHA1); +#endif +#ifdef HAVE_SHA256 + DEFCLASS(SHA256); +#endif +#ifdef HAVE_SHA384 + DEFCLASS(SHA384); +#endif +#ifdef HAVE_SHA512 + DEFCLASS(SHA512); +#endif + + h = mrb_define_class_under(mrb, d, "HMAC", mrb->object_class); + MRB_SET_INSTANCE_TT(h, MRB_TT_DATA); + mrb_define_method(mrb, h, "block_length", mrb_hmac_block_length, MRB_ARGS_NONE()); + mrb_define_method(mrb, h, "digest", mrb_hmac_digest, MRB_ARGS_NONE()); + mrb_define_method(mrb, h, "digest_length", mrb_hmac_digest_length, MRB_ARGS_NONE()); + mrb_define_method(mrb, h, "hexdigest", mrb_hmac_hexdigest, MRB_ARGS_NONE()); + mrb_define_method(mrb, h, "initialize", mrb_hmac_init, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, h, "initialize_copy", mrb_hmac_init_copy, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, h, "update", mrb_hmac_update, MRB_ARGS_REQ(1)); +} + +void +mrb_mruby_digest_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-digest/src/picohash.h b/web/server/h2o/libh2o/deps/mruby-digest/src/picohash.h new file mode 100644 index 000000000..4c0206d95 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/src/picohash.h @@ -0,0 +1,751 @@ +/* + * The code is placed under public domain by Kazuho Oku <kazuhooku@gmail.com>. + * + * The MD5 implementation is based on a public domain implementation written by + * Solar Designer <solar@openwall.com> in 2001, which is used by Dovecot. + * + * The SHA1 implementation is based on a public domain implementation written + * by Wei Dai and other contributors for libcrypt, used also in liboauth. + * + * The SHA224/SHA256 implementation is based on a public domain implementation + * by Sam Hocevar <sam@hocevar.net> for LibTomCrypt. + */ +#ifndef _picohash_h_ +#define _picohash_h_ + +#include <assert.h> +#include <inttypes.h> +#include <string.h> + +#ifdef __BIG_ENDIAN__ +#define _PICOHASH_BIG_ENDIAN +#elif defined __LITTLE_ENDIAN__ +/* override */ +#elif defined __BYTE_ORDER +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define _PICOHASH_BIG_ENDIAN +#endif +#else // ! defined __LITTLE_ENDIAN__ +#include <endian.h> // machine/endian.h +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define _PICOHASH_BIG_ENDIAN +#endif +#endif + +#define PICOHASH_MD5_BLOCK_LENGTH 64 +#define PICOHASH_MD5_DIGEST_LENGTH 16 + +typedef struct { + uint_fast32_t lo, hi; + uint_fast32_t a, b, c, d; + unsigned char buffer[64]; + uint_fast32_t block[PICOHASH_MD5_DIGEST_LENGTH]; +} _picohash_md5_ctx_t; + +static void _picohash_md5_init(_picohash_md5_ctx_t *ctx); +static void _picohash_md5_update(_picohash_md5_ctx_t *ctx, const void *data, size_t size); +static void _picohash_md5_final(_picohash_md5_ctx_t *ctx, void *digest); + +#define PICOHASH_SHA1_BLOCK_LENGTH 64 +#define PICOHASH_SHA1_DIGEST_LENGTH 20 + +typedef struct { + uint32_t buffer[PICOHASH_SHA1_BLOCK_LENGTH / 4]; + uint32_t state[PICOHASH_SHA1_DIGEST_LENGTH / 4]; + uint64_t byteCount; + uint8_t bufferOffset; +} _picohash_sha1_ctx_t; + +static void _picohash_sha1_init(_picohash_sha1_ctx_t *ctx); +static void _picohash_sha1_update(_picohash_sha1_ctx_t *ctx, const void *input, size_t len); +static void _picohash_sha1_final(_picohash_sha1_ctx_t *ctx, void *digest); + +#define PICOHASH_SHA256_BLOCK_LENGTH 64 +#define PICOHASH_SHA256_DIGEST_LENGTH 32 +#define PICOHASH_SHA224_BLOCK_LENGTH PICOHASH_SHA256_BLOCK_LENGTH +#define PICOHASH_SHA224_DIGEST_LENGTH 28 + +typedef struct { + uint64_t length; + uint32_t state[PICOHASH_SHA256_DIGEST_LENGTH / 4]; + uint32_t curlen; + unsigned char buf[PICOHASH_SHA256_BLOCK_LENGTH]; +} _picohash_sha256_ctx_t; + +static void _picohash_sha256_init(_picohash_sha256_ctx_t *ctx); +static void _picohash_sha256_update(_picohash_sha256_ctx_t *ctx, const void *data, size_t len); +static void _picohash_sha256_final(_picohash_sha256_ctx_t *ctx, void *digest); +static void _picohash_sha224_init(_picohash_sha256_ctx_t *ctx); +static void _picohash_sha224_final(_picohash_sha256_ctx_t *ctx, void *digest); + +#define PICOHASH_MAX_BLOCK_LENGTH 64 +#define PICOHASH_MAX_DIGEST_LENGTH 32 + +typedef struct { + union { + _picohash_md5_ctx_t _md5; + _picohash_sha1_ctx_t _sha1; + _picohash_sha256_ctx_t _sha256; + }; + size_t block_length; + size_t digest_length; + void (*_reset)(void *ctx); + void (*_update)(void *ctx, const void *input, size_t len); + void (*_final)(void *ctx, void *digest); + struct { + unsigned char key[PICOHASH_MAX_BLOCK_LENGTH]; + void (*hash_reset)(void *ctx); + void (*hash_final)(void *ctx, void *digest); + } _hmac; +} picohash_ctx_t; + +static void picohash_init_md5(picohash_ctx_t *ctx); +static void picohash_init_sha1(picohash_ctx_t *ctx); +static void picohash_init_sha224(picohash_ctx_t *ctx); +static void picohash_init_sha256(picohash_ctx_t *ctx); +static void picohash_update(picohash_ctx_t *ctx, const void *input, size_t len); +static void picohash_final(picohash_ctx_t *ctx, void *digest); +static void picohash_reset(picohash_ctx_t *ctx); + +static void picohash_init_hmac(picohash_ctx_t *ctx, void (*initf)(picohash_ctx_t *), const void *key, size_t key_len); + +/* following are private definitions */ + +/* + * The basic MD5 functions. + * + * F is optimized compared to its RFC 1321 definition just like in Colin + * Plumb's implementation. + */ +#define _PICOHASH_MD5_F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define _PICOHASH_MD5_G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define _PICOHASH_MD5_H(x, y, z) ((x) ^ (y) ^ (z)) +#define _PICOHASH_MD5_I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define _PICOHASH_MD5_STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them + * in a properly aligned word in host byte order. + * + * The check for little-endian architectures which tolerate unaligned + * memory accesses is just an optimization. Nothing will break if it + * doesn't work. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define _PICOHASH_MD5_SET(n) (*(const uint32_t *)&ptr[(n)*4]) +#define _PICOHASH_MD5_GET(n) _PICOHASH_MD5_SET(n) +#else +#define _PICOHASH_MD5_SET(n) \ + (ctx->block[(n)] = (uint_fast32_t)ptr[(n)*4] | ((uint_fast32_t)ptr[(n)*4 + 1] << 8) | ((uint_fast32_t)ptr[(n)*4 + 2] << 16) | \ + ((uint_fast32_t)ptr[(n)*4 + 3] << 24)) +#define _PICOHASH_MD5_GET(n) (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There're no alignment requirements. + */ +static const void *_picohash_md5_body(_picohash_md5_ctx_t *ctx, const void *data, size_t size) +{ + const unsigned char *ptr; + uint_fast32_t a, b, c, d; + uint_fast32_t saved_a, saved_b, saved_c, saved_d; + + ptr = data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + + /* Round 1 */ + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(0), 0xd76aa478, 7) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(1), 0xe8c7b756, 12) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(2), 0x242070db, 17) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(3), 0xc1bdceee, 22) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(4), 0xf57c0faf, 7) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(5), 0x4787c62a, 12) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(6), 0xa8304613, 17) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(7), 0xfd469501, 22) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(8), 0x698098d8, 7) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(9), 0x8b44f7af, 12) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(10), 0xffff5bb1, 17) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(11), 0x895cd7be, 22) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(12), 0x6b901122, 7) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(13), 0xfd987193, 12) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(14), 0xa679438e, 17) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(15), 0x49b40821, 22) + + /* Round 2 */ + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(1), 0xf61e2562, 5) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(6), 0xc040b340, 9) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(11), 0x265e5a51, 14) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(0), 0xe9b6c7aa, 20) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(5), 0xd62f105d, 5) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(10), 0x02441453, 9) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(15), 0xd8a1e681, 14) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(4), 0xe7d3fbc8, 20) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(9), 0x21e1cde6, 5) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(14), 0xc33707d6, 9) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(3), 0xf4d50d87, 14) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(8), 0x455a14ed, 20) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(13), 0xa9e3e905, 5) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(2), 0xfcefa3f8, 9) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(7), 0x676f02d9, 14) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(12), 0x8d2a4c8a, 20) + + /* Round 3 */ + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(5), 0xfffa3942, 4) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(8), 0x8771f681, 11) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(11), 0x6d9d6122, 16) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(14), 0xfde5380c, 23) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(1), 0xa4beea44, 4) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(4), 0x4bdecfa9, 11) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(7), 0xf6bb4b60, 16) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(10), 0xbebfbc70, 23) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(13), 0x289b7ec6, 4) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(0), 0xeaa127fa, 11) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(3), 0xd4ef3085, 16) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(6), 0x04881d05, 23) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(9), 0xd9d4d039, 4) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(12), 0xe6db99e5, 11) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(15), 0x1fa27cf8, 16) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(2), 0xc4ac5665, 23) + + /* Round 4 */ + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(0), 0xf4292244, 6) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(7), 0x432aff97, 10) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(14), 0xab9423a7, 15) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(5), 0xfc93a039, 21) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(12), 0x655b59c3, 6) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(3), 0x8f0ccc92, 10) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(10), 0xffeff47d, 15) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(1), 0x85845dd1, 21) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(8), 0x6fa87e4f, 6) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(15), 0xfe2ce6e0, 10) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(6), 0xa3014314, 15) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(13), 0x4e0811a1, 21) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(4), 0xf7537e82, 6) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(11), 0xbd3af235, 10) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(2), 0x2ad7d2bb, 15) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +inline void _picohash_md5_init(_picohash_md5_ctx_t *ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +inline void _picohash_md5_update(_picohash_md5_ctx_t *ctx, const void *data, size_t size) +{ + uint_fast32_t saved_lo; + unsigned long used, free; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) { + free = 64 - used; + + if (size < free) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, free); + data = (const unsigned char *)data + free; + size -= free; + _picohash_md5_body(ctx, ctx->buffer, 64); + } + + if (size >= 64) { + data = _picohash_md5_body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +inline void _picohash_md5_final(_picohash_md5_ctx_t *ctx, void *_digest) +{ + unsigned char *digest = _digest; + unsigned long used, free; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + free = 64 - used; + + if (free < 8) { + memset(&ctx->buffer[used], 0, free); + _picohash_md5_body(ctx, ctx->buffer, 64); + used = 0; + free = 64; + } + + memset(&ctx->buffer[used], 0, free - 8); + + ctx->lo <<= 3; + ctx->buffer[56] = ctx->lo; + ctx->buffer[57] = ctx->lo >> 8; + ctx->buffer[58] = ctx->lo >> 16; + ctx->buffer[59] = ctx->lo >> 24; + ctx->buffer[60] = ctx->hi; + ctx->buffer[61] = ctx->hi >> 8; + ctx->buffer[62] = ctx->hi >> 16; + ctx->buffer[63] = ctx->hi >> 24; + + _picohash_md5_body(ctx, ctx->buffer, 64); + + digest[0] = ctx->a; + digest[1] = ctx->a >> 8; + digest[2] = ctx->a >> 16; + digest[3] = ctx->a >> 24; + digest[4] = ctx->b; + digest[5] = ctx->b >> 8; + digest[6] = ctx->b >> 16; + digest[7] = ctx->b >> 24; + digest[8] = ctx->c; + digest[9] = ctx->c >> 8; + digest[10] = ctx->c >> 16; + digest[11] = ctx->c >> 24; + digest[12] = ctx->d; + digest[13] = ctx->d >> 8; + digest[14] = ctx->d >> 16; + digest[15] = ctx->d >> 24; + + memset(ctx, 0, sizeof(*ctx)); +} + +#define _PICOHASH_SHA1_K0 0x5a827999 +#define _PICOHASH_SHA1_K20 0x6ed9eba1 +#define _PICOHASH_SHA1_K40 0x8f1bbcdc +#define _PICOHASH_SHA1_K60 0xca62c1d6 + +static inline uint32_t _picohash_sha1_rol32(uint32_t number, uint8_t bits) +{ + return ((number << bits) | (number >> (32 - bits))); +} + +static inline void _picohash_sha1_hash_block(_picohash_sha1_ctx_t *s) +{ + uint8_t i; + uint32_t a, b, c, d, e, t; + + a = s->state[0]; + b = s->state[1]; + c = s->state[2]; + d = s->state[3]; + e = s->state[4]; + for (i = 0; i < 80; i++) { + if (i >= 16) { + t = s->buffer[(i + 13) & 15] ^ s->buffer[(i + 8) & 15] ^ s->buffer[(i + 2) & 15] ^ s->buffer[i & 15]; + s->buffer[i & 15] = _picohash_sha1_rol32(t, 1); + } + if (i < 20) { + t = (d ^ (b & (c ^ d))) + _PICOHASH_SHA1_K0; + } else if (i < 40) { + t = (b ^ c ^ d) + _PICOHASH_SHA1_K20; + } else if (i < 60) { + t = ((b & c) | (d & (b | c))) + _PICOHASH_SHA1_K40; + } else { + t = (b ^ c ^ d) + _PICOHASH_SHA1_K60; + } + t += _picohash_sha1_rol32(a, 5) + e + s->buffer[i & 15]; + e = d; + d = c; + c = _picohash_sha1_rol32(b, 30); + b = a; + a = t; + } + s->state[0] += a; + s->state[1] += b; + s->state[2] += c; + s->state[3] += d; + s->state[4] += e; +} + +static inline void _picohash_sha1_add_uncounted(_picohash_sha1_ctx_t *s, uint8_t data) +{ + uint8_t *const b = (uint8_t *)s->buffer; +#ifdef _PICOHASH_BIG_ENDIAN + b[s->bufferOffset] = data; +#else + b[s->bufferOffset ^ 3] = data; +#endif + s->bufferOffset++; + if (s->bufferOffset == PICOHASH_SHA1_BLOCK_LENGTH) { + _picohash_sha1_hash_block(s); + s->bufferOffset = 0; + } +} + +inline void _picohash_sha1_init(_picohash_sha1_ctx_t *s) +{ + s->state[0] = 0x67452301; + s->state[1] = 0xefcdab89; + s->state[2] = 0x98badcfe; + s->state[3] = 0x10325476; + s->state[4] = 0xc3d2e1f0; + s->byteCount = 0; + s->bufferOffset = 0; +} + +inline void _picohash_sha1_update(_picohash_sha1_ctx_t *s, const void *_data, size_t len) +{ + const uint8_t *data = _data; + for (; len != 0; --len) { + ++s->byteCount; + _picohash_sha1_add_uncounted(s, *data++); + } +} + +inline void _picohash_sha1_final(_picohash_sha1_ctx_t *s, void *digest) +{ + // Pad with 0x80 followed by 0x00 until the end of the block + _picohash_sha1_add_uncounted(s, 0x80); + while (s->bufferOffset != 56) + _picohash_sha1_add_uncounted(s, 0x00); + + // Append length in the last 8 bytes + _picohash_sha1_add_uncounted(s, s->byteCount >> 53); // Shifting to multiply by 8 + _picohash_sha1_add_uncounted(s, s->byteCount >> 45); // as SHA-1 supports bitstreams as well as + _picohash_sha1_add_uncounted(s, s->byteCount >> 37); // byte. + _picohash_sha1_add_uncounted(s, s->byteCount >> 29); + _picohash_sha1_add_uncounted(s, s->byteCount >> 21); + _picohash_sha1_add_uncounted(s, s->byteCount >> 13); + _picohash_sha1_add_uncounted(s, s->byteCount >> 5); + _picohash_sha1_add_uncounted(s, s->byteCount << 3); + +#ifndef SHA_BIG_ENDIAN + { // Swap byte order back + int i; + for (i = 0; i < 5; i++) { + s->state[i] = (((s->state[i]) << 24) & 0xff000000) | (((s->state[i]) << 8) & 0x00ff0000) | + (((s->state[i]) >> 8) & 0x0000ff00) | (((s->state[i]) >> 24) & 0x000000ff); + } + } +#endif + + memcpy(digest, s->state, sizeof(s->state)); +} + +#define _picohash_sha256_ch(x, y, z) (z ^ (x & (y ^ z))) +#define _picohash_sha256_maj(x, y, z) (((x | y) & z) | (x & y)) +#define _picohash_sha256_s(x, y) \ + (((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | ((uint32_t)(x) << (uint32_t)(32 - ((y)&31)))) & 0xFFFFFFFFUL) +#define _picohash_sha256_r(x, n) (((x)&0xFFFFFFFFUL) >> (n)) +#define _picohash_sha256_sigma0(x) (_picohash_sha256_s(x, 2) ^ _picohash_sha256_s(x, 13) ^ _picohash_sha256_s(x, 22)) +#define _picohash_sha256_sigma1(x) (_picohash_sha256_s(x, 6) ^ _picohash_sha256_s(x, 11) ^ _picohash_sha256_s(x, 25)) +#define _picohash_sha256_gamma0(x) (_picohash_sha256_s(x, 7) ^ _picohash_sha256_s(x, 18) ^ _picohash_sha256_r(x, 3)) +#define _picohash_sha256_gamma1(x) (_picohash_sha256_s(x, 17) ^ _picohash_sha256_s(x, 19) ^ _picohash_sha256_r(x, 10)) +#define _picohash_sha256_rnd(a, b, c, d, e, f, g, h, i) \ + t0 = h + _picohash_sha256_sigma1(e) + _picohash_sha256_ch(e, f, g) + K[i] + W[i]; \ + t1 = _picohash_sha256_sigma0(a) + _picohash_sha256_maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +static inline void _picohash_sha256_compress(_picohash_sha256_ctx_t *ctx, unsigned char *buf) +{ + static const uint32_t K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL}; + uint32_t S[8], W[64], t, t0, t1; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) + S[i] = ctx->state[i]; + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + W[i] = + (uint32_t)buf[4 * i] << 24 | (uint32_t)buf[4 * i + 1] << 16 | (uint32_t)buf[4 * i + 2] << 8 | (uint32_t)buf[4 * i + 3]; + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) + W[i] = _picohash_sha256_gamma1(W[i - 2]) + W[i - 7] + _picohash_sha256_gamma0(W[i - 15]) + W[i - 16]; + + /* Compress */ + for (i = 0; i < 64; ++i) { + _picohash_sha256_rnd(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); + t = S[7]; + S[7] = S[6]; + S[6] = S[5]; + S[5] = S[4]; + S[4] = S[3]; + S[3] = S[2]; + S[2] = S[1]; + S[1] = S[0]; + S[0] = t; + } + + /* feedback */ + for (i = 0; i < 8; i++) + ctx->state[i] = ctx->state[i] + S[i]; +} + +static inline void _picohash_sha256_do_final(_picohash_sha256_ctx_t *ctx, void *digest, size_t len) +{ + unsigned char *out = digest; + size_t i; + + /* increase the length of the message */ + ctx->length += ctx->curlen * 8; + + /* append the '1' bit */ + ctx->buf[ctx->curlen++] = (unsigned char)0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (ctx->curlen > 56) { + while (ctx->curlen < 64) { + ctx->buf[ctx->curlen++] = (unsigned char)0; + } + _picohash_sha256_compress(ctx, ctx->buf); + ctx->curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (ctx->curlen < 56) { + ctx->buf[ctx->curlen++] = (unsigned char)0; + } + + /* store length */ + for (i = 0; i != 8; ++i) + ctx->buf[56 + i] = ctx->length >> (56 - 8 * i); + _picohash_sha256_compress(ctx, ctx->buf); + + /* copy output */ + for (i = 0; i != len / 4; ++i) { + out[i * 4] = ctx->state[i] >> 24; + out[i * 4 + 1] = ctx->state[i] >> 16; + out[i * 4 + 2] = ctx->state[i] >> 8; + out[i * 4 + 3] = ctx->state[i]; + } +} + +inline void _picohash_sha256_init(_picohash_sha256_ctx_t *ctx) +{ + ctx->curlen = 0; + ctx->length = 0; + ctx->state[0] = 0x6A09E667UL; + ctx->state[1] = 0xBB67AE85UL; + ctx->state[2] = 0x3C6EF372UL; + ctx->state[3] = 0xA54FF53AUL; + ctx->state[4] = 0x510E527FUL; + ctx->state[5] = 0x9B05688CUL; + ctx->state[6] = 0x1F83D9ABUL; + ctx->state[7] = 0x5BE0CD19UL; +} + +inline void _picohash_sha256_update(_picohash_sha256_ctx_t *ctx, const void *data, size_t len) +{ + const unsigned char *in = data; + size_t n; + + while (len > 0) { + if (ctx->curlen == 0 && len >= PICOHASH_SHA256_BLOCK_LENGTH) { + _picohash_sha256_compress(ctx, (unsigned char *)in); + ctx->length += PICOHASH_SHA256_BLOCK_LENGTH * 8; + in += PICOHASH_SHA256_BLOCK_LENGTH; + len -= PICOHASH_SHA256_BLOCK_LENGTH; + } else { + n = PICOHASH_SHA256_BLOCK_LENGTH - ctx->curlen; + if (n > len) + n = len; + memcpy(ctx->buf + ctx->curlen, in, (size_t)n); + ctx->curlen += n; + in += n; + len -= n; + if (ctx->curlen == 64) { + _picohash_sha256_compress(ctx, ctx->buf); + ctx->length += 8 * PICOHASH_SHA256_BLOCK_LENGTH; + ctx->curlen = 0; + } + } + } +} + +inline void _picohash_sha256_final(_picohash_sha256_ctx_t *ctx, void *digest) +{ + _picohash_sha256_do_final(ctx, digest, PICOHASH_SHA256_DIGEST_LENGTH); +} + +inline void _picohash_sha224_init(_picohash_sha256_ctx_t *ctx) +{ + ctx->curlen = 0; + ctx->length = 0; + ctx->state[0] = 0xc1059ed8UL; + ctx->state[1] = 0x367cd507UL; + ctx->state[2] = 0x3070dd17UL; + ctx->state[3] = 0xf70e5939UL; + ctx->state[4] = 0xffc00b31UL; + ctx->state[5] = 0x68581511UL; + ctx->state[6] = 0x64f98fa7UL; + ctx->state[7] = 0xbefa4fa4UL; +} + +inline void _picohash_sha224_final(_picohash_sha256_ctx_t *ctx, void *digest) +{ + _picohash_sha256_do_final(ctx, digest, PICOHASH_SHA224_DIGEST_LENGTH); +} + +inline void picohash_init_md5(picohash_ctx_t *ctx) +{ + ctx->block_length = PICOHASH_MD5_BLOCK_LENGTH; + ctx->digest_length = PICOHASH_MD5_DIGEST_LENGTH; + ctx->_reset = (void *)_picohash_md5_init; + ctx->_update = (void *)_picohash_md5_update; + ctx->_final = (void *)_picohash_md5_final; + + _picohash_md5_init(&ctx->_md5); +} + +inline void picohash_init_sha1(picohash_ctx_t *ctx) +{ + ctx->block_length = PICOHASH_SHA1_BLOCK_LENGTH; + ctx->digest_length = PICOHASH_SHA1_DIGEST_LENGTH; + ctx->_reset = (void *)_picohash_sha1_init; + ctx->_update = (void *)_picohash_sha1_update; + ctx->_final = (void *)_picohash_sha1_final; + _picohash_sha1_init(&ctx->_sha1); +} + +inline void picohash_init_sha224(picohash_ctx_t *ctx) +{ + ctx->block_length = PICOHASH_SHA224_BLOCK_LENGTH; + ctx->digest_length = PICOHASH_SHA224_DIGEST_LENGTH; + ctx->_reset = (void *)_picohash_sha224_init; + ctx->_update = (void *)_picohash_sha256_update; + ctx->_final = (void *)_picohash_sha224_final; + _picohash_sha224_init(&ctx->_sha256); +} + +inline void picohash_init_sha256(picohash_ctx_t *ctx) +{ + ctx->block_length = PICOHASH_SHA256_BLOCK_LENGTH; + ctx->digest_length = PICOHASH_SHA256_DIGEST_LENGTH; + ctx->_reset = (void *)_picohash_sha256_init; + ctx->_update = (void *)_picohash_sha256_update; + ctx->_final = (void *)_picohash_sha256_final; + _picohash_sha256_init(&ctx->_sha256); +} + +inline void picohash_update(picohash_ctx_t *ctx, const void *input, size_t len) +{ + ctx->_update(ctx, input, len); +} + +inline void picohash_final(picohash_ctx_t *ctx, void *digest) +{ + ctx->_final(ctx, digest); +} + +inline void picohash_reset(picohash_ctx_t *ctx) +{ + ctx->_reset(ctx); +} + +static inline void _picohash_hmac_apply_key(picohash_ctx_t *ctx, unsigned char delta) +{ + size_t i; + for (i = 0; i != ctx->block_length; ++i) + ctx->_hmac.key[i] ^= delta; + picohash_update(ctx, ctx->_hmac.key, ctx->block_length); + for (i = 0; i != ctx->block_length; ++i) + ctx->_hmac.key[i] ^= delta; +} + +static void _picohash_hmac_final(picohash_ctx_t *ctx, void *digest) +{ + unsigned char inner_digest[PICOHASH_MAX_DIGEST_LENGTH]; + + ctx->_hmac.hash_final(ctx, inner_digest); + + ctx->_hmac.hash_reset(ctx); + _picohash_hmac_apply_key(ctx, 0x5c); + picohash_update(ctx, inner_digest, ctx->digest_length); + memset(inner_digest, 0, ctx->digest_length); + + ctx->_hmac.hash_final(ctx, digest); +} + +static inline void _picohash_hmac_reset(picohash_ctx_t *ctx) +{ + ctx->_hmac.hash_reset(ctx); + _picohash_hmac_apply_key(ctx, 0x36); +} + +inline void picohash_init_hmac(picohash_ctx_t *ctx, void (*initf)(picohash_ctx_t *), const void *key, size_t key_len) +{ + initf(ctx); + + memset(ctx->_hmac.key, 0, ctx->block_length); + if (key_len > ctx->block_length) { + /* hash the key if it is too long */ + picohash_update(ctx, key, key_len); + picohash_final(ctx, ctx->_hmac.key); + ctx->_hmac.hash_reset(ctx); + } else { + memcpy(ctx->_hmac.key, key, key_len); + } + + /* replace reset and final function */ + ctx->_hmac.hash_reset = ctx->_reset; + ctx->_hmac.hash_final = ctx->_final; + ctx->_reset = (void *)_picohash_hmac_reset; + ctx->_final = (void *)_picohash_hmac_final; + + /* start calculating the inner hash */ + _picohash_hmac_apply_key(ctx, 0x36); +} + +#endif diff --git a/web/server/h2o/libh2o/deps/mruby-digest/test/digest.rb b/web/server/h2o/libh2o/deps/mruby-digest/test/digest.rb new file mode 100644 index 000000000..fd13fa43a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/test/digest.rb @@ -0,0 +1,203 @@ +## +# Digest Test + +if Object.const_defined?(:Digest) + assert('Digest') do + Digest.class == Module + end + + assert('Digest::Base') do + Digest::Base.class == Class + end + + assert('Digest::Base#new') do + e1 = nil + begin + Digest::Base.new + rescue NotImplementedError => e + e1 = e + end + e1.class == NotImplementedError + end + + assert('Digest::MD5') do + Digest::MD5.class == Class + end + + assert('Digest::MD5 superclass') do + Digest::MD5.superclass == Digest::Base + end + + assert('Digest::MD5.digest') do + Digest::MD5.digest('ruby') == "X\xE5=\x13$\xEE\xF6&_\xDB\x97\xB0\x8E\xD9\xAA\xDF" + end + + #assert('Digest::MD5.file') + + assert('Digest::MD5.hexdigest') do + Digest::MD5.hexdigest('ruby') == "58e53d1324eef6265fdb97b08ed9aadf" + end + + assert('Digest::MD5#update') do + d = Digest::MD5.new + d.update('ruby') + d.hexdigest == "58e53d1324eef6265fdb97b08ed9aadf" + end + + assert('Digest::MD5#update 2') do + d = Digest::MD5.new + d.update('ruby') + d.update('digest') + d.hexdigest == "2ac1b3e3db06239e3244817f281450f1" + end + + assert('Digest::MD5#<<') do + a = Digest::MD5.new + b = Digest::MD5.new + a.update('ruby') + b << "r" << "u" << "b" << "y" + a.hexdigest == b.hexdigest + end + + assert('Digest::MD5#== with Digest::XXX') do + x1 = Digest::MD5.new.update("ruby") + x2 = Digest::MD5.new.update("ruby") + x3 = Digest::MD5.new.update("RUBY") + (x1 == x2) == true and + (x1 == x3) == false + end + + assert('Digest::MD5#== with String') do + Digest::MD5.new.update("ruby") == "58e53d1324eef6265fdb97b08ed9aadf" + end + + assert('Digest::MD5#block_length') do + Digest::MD5.new.block_length == 64 + end + + assert('Digest::MD5#digest') do + Digest::MD5.new.update("ruby").digest == "X\xE5=\x13$\xEE\xF6&_\xDB\x97\xB0\x8E\xD9\xAA\xDF" + end + + assert('Digest::MD5#digest!') do + d = Digest::MD5.new.update("ruby") + d.digest! + #d.digest! == "\xD4\x1D\x8C\xD9\x8F\x00\xB2\x04\xE9\x80\t\x98\xEC\xF8B~" + # XXX: mrbtest dumps core! + d.digest! == Digest::MD5.new.digest + end + + assert('Digest::MD5#digest_length') do + d = Digest::MD5.new + n = 16 + d.digest_length == n and + d.length == n and + d.size == n + end + + #assert('Digest::MD5#file') + + assert('Digest::MD5#hexdigest') do + d = Digest::MD5.new.update("ruby") + s = "58e53d1324eef6265fdb97b08ed9aadf" + d.hexdigest == s and + d.to_s == s + end + + assert('Digest::MD5#hexdigest!') do + d = Digest::MD5.new.update("ruby") + d.hexdigest! + d.hexdigest! == "d41d8cd98f00b204e9800998ecf8427e" + end + + assert('Digest::MD5#reset') do + d = Digest::MD5.new.update("ruby") + d.reset + d.hexdigest! == "d41d8cd98f00b204e9800998ecf8427e" + end + + if Digest.const_defined? :RMD160 + assert('Digest::RMD160#hexdigest') do + d = Digest::RMD160.new.update("ruby") + s = "29d9b710bc50866fa2399c3061cd02c0c8ffa197" + d.hexdigest == s + end + end + + if Digest.const_defined? :SHA1 + assert('Digest::SHA1#hexdigest') do + d = Digest::SHA1.new.update("ruby") + s = "18e40e1401eef67e1ae69efab09afb71f87ffb81" + d.hexdigest == s + end + end + + if Digest.const_defined? :SHA256 + assert('Digest::SHA256#hexdigest') do + d = Digest::SHA256.new.update("ruby") + s = "b9138194ffe9e7c8bb6d79d1ed56259553d18d9cb60b66e3ba5aa2e5b078055a" + d.hexdigest == s + end + end + + if Digest.const_defined? :SHA384 + assert('Digest::SHA384#hexdigest') do + d = Digest::SHA384.new.update("ruby") + s = "635365ef93ebf2c7a4e40b0b497da727ab8c2914eb9f052e6be40476f95d3daf44786790f5f0e843fab419b43022e069" + d.hexdigest == s + end + end + + if Digest.const_defined? :SHA512 + assert('Digest::SHA512#hexdigest') do + d = Digest::SHA512.new.update("ruby") + s = "423408d7723a3d80baefa804bd50b61a89667efec1713386a7b8efe28e5d13968307a908778cad210d7aa2dfe7db9a2aa86895f9fc1eeefcc99814310b207a6b" + d.hexdigest == s + end + end + + assert('Digest::HMAC') do + Digest::HMAC.class == Class + end + + assert('Digest::HMAC.digest') do + Digest::HMAC.digest("data", "hash key", Digest::SHA1) == "\xFD \xECC=\xFD\x97\x0E\xEC!FW\xCF\xB5Gl]\x913f" + end + + assert('Digest::HMAC.hexdigest') do + Digest::HMAC.hexdigest("data", "hash key", Digest::SHA1) == "fd20ec433dfd970eec214657cfb5476c5d913366" + end + + assert('Digest::HMAC#<<') do + a = Digest::HMAC.new('hash key', Digest::SHA1) + b = Digest::HMAC.new('hash key', Digest::SHA1) + a.update('ruby') + b << "r" << "u" << "b" << "y" + a.hexdigest == b.hexdigest + end + + assert('Digest::HMAC#block_length') do + d = Digest::HMAC.new("hash key", Digest::SHA1) + d.block_length == 64 + end + + assert('Digest::HMAC#digest_length') do + d = Digest::HMAC.new("hash key", Digest::SHA1) + d.digest_length == 20 + end + + # assert('Digest::HMAC#reset') + + assert('Digest::HMAC#update') do + d = Digest::HMAC.new("hash key", Digest::SHA1) + d.update('data') + d.hexdigest == "fd20ec433dfd970eec214657cfb5476c5d913366" + end + + assert('Digest::HMAC#update 2') do + d = Digest::HMAC.new("hash key", Digest::SHA1) + d.update('ruby') + d.update('digest') + d.hexdigest == "e4be3728777e43deba3aa522a4247ea83b19a1c7" + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-dir/.gitignore b/web/server/h2o/libh2o/deps/mruby-dir/.gitignore new file mode 100644 index 000000000..55ef3162f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-dir/.gitignore @@ -0,0 +1,5 @@ +gem_* +gem-* +mrb-*.a +src/*.o +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-dir/.travis.yml b/web/server/h2o/libh2o/deps/mruby-dir/.travis.yml new file mode 100644 index 000000000..ffe227284 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-dir/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-dir/README.md b/web/server/h2o/libh2o/deps/mruby-dir/README.md new file mode 100644 index 000000000..d7953036d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-dir/README.md @@ -0,0 +1,56 @@ +mruby-dir +========= + +Dir class for mruby. Supported methods are: + +`.chdir` +`.delete` +`.entries` +`.exist?` +`.foreach` +`.getwd` +`.mkdir` +`.open` +`#close` +`#each` +`#read` +`#rewind` +`#seek` +`#tell` + + +## License + +Copyright (c) 2012 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + +- On Windows platforms, you must agree on addional license too: + +Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that this copyright and permissions notice appear in all copies and +derivatives. + +This software is supplied "as is" without express or implied warranty. + +But that said, if there are any problems please get in touch. diff --git a/web/server/h2o/libh2o/deps/mruby-dir/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-dir/mrbgem.rake new file mode 100644 index 000000000..10864c81c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-dir/mrbgem.rake @@ -0,0 +1,6 @@ +MRuby::Gem::Specification.new('mruby-dir') do |spec| + spec.license = 'MIT and MIT-like license' + spec.authors = [ 'Internet Initiative Japan Inc.', 'Kevlin Henney'] + + spec.cc.include_paths << "#{build.root}/src" +end diff --git a/web/server/h2o/libh2o/deps/mruby-dir/mrblib/dir.rb b/web/server/h2o/libh2o/deps/mruby-dir/mrblib/dir.rb new file mode 100644 index 000000000..065ca1c22 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-dir/mrblib/dir.rb @@ -0,0 +1,64 @@ +class Dir + def each(&block) + while s = self.read + block.call(s) + end + self + end + + alias pos tell + alias pos= seek + + def self.entries(path) + a = [] + self.open(path) { |d| + while s = d.read + a << s + end + } + a + end + + def self.foreach(path, &block) + if block + self.open(path).each { |f| block.call(f) } + else + self.open(path).each + end + end + + def self.open(path, &block) + if block + d = self.new(path) + begin + block.call(d) + ensure + d.close + end + else + self.new(path) + end + end + + def self.chdir(path, &block) + my = self # workaround for https://github.com/mruby/mruby/issues/1579 + if block + wd = self.getwd + begin + self._chdir(path) + block.call(path) + ensure + my._chdir(wd) + end + else + self._chdir(path) + end + end + + class << self + alias exists? exist? + alias pwd getwd + alias rmdir delete + alias unlink delete + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-dir/run_test.rb b/web/server/h2o/libh2o/deps/mruby-dir/run_test.rb new file mode 100644 index 000000000..d9566a2a6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-dir/run_test.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +gemname = File.basename(File.dirname(File.expand_path __FILE__)) + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + build_args = ['all', 'test'] if build_args.nil? or build_args.empty? + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-dir/src/Win/dirent.c b/web/server/h2o/libh2o/deps/mruby-dir/src/Win/dirent.c new file mode 100644 index 000000000..98728bcf7 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-dir/src/Win/dirent.c @@ -0,0 +1,154 @@ +/* + + Implementation of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003 and July 2012. + Rights: See end of file. + +*/ + +#include <errno.h> +#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */ +#include <stdlib.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */ + +struct dirent +{ + char *d_name; +}; + +struct DIR +{ + handle_type handle; /* -1 for failed rewind */ + struct _finddata_t info; + struct dirent result; /* d_name null iff first time */ + char *name; /* null-terminated char string */ +}; + +typedef struct DIR DIR; + +DIR *opendir(const char *name) +{ + DIR *dir = 0; + + if(name && name[0]) + { + size_t base_length = strlen(name); + const char *all = /* search pattern must end with suitable wildcard */ + strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + + if((dir = (DIR *) malloc(sizeof *dir)) != 0 && + (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) + { + strcat(strcpy(dir->name, name), all); + + if((dir->handle = + (handle_type) _findfirst(dir->name, &dir->info)) != -1) + { + dir->result.d_name = 0; + } + else /* rollback */ + { + free(dir->name); + free(dir); + dir = 0; + } + } + else /* rollback */ + { + free(dir); + dir = 0; + errno = ENOMEM; + } + } + else + { + errno = EINVAL; + } + + return dir; +} + +int closedir(DIR *dir) +{ + int result = -1; + + if(dir) + { + if(dir->handle != -1) + { + result = _findclose(dir->handle); + } + + free(dir->name); + free(dir); + } + + if(result == -1) /* map all errors to EBADF */ + { + errno = EBADF; + } + + return result; +} + +struct dirent *readdir(DIR *dir) +{ + struct dirent *result = 0; + + if(dir && dir->handle != -1) + { + if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) + { + result = &dir->result; + result->d_name = dir->info.name; + } + } + else + { + errno = EBADF; + } + + return result; +} + +void rewinddir(DIR *dir) +{ + if(dir && dir->handle != -1) + { + _findclose(dir->handle); + dir->handle = (handle_type) _findfirst(dir->name, &dir->info); + dir->result.d_name = 0; + } + else + { + errno = EBADF; + } +} + +#ifdef __cplusplus +} +#endif + +/* + + Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. + +*/ diff --git a/web/server/h2o/libh2o/deps/mruby-dir/src/dir.c b/web/server/h2o/libh2o/deps/mruby-dir/src/dir.c new file mode 100644 index 000000000..0f55ed93d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-dir/src/dir.c @@ -0,0 +1,281 @@ +/* +** dir.c - Dir +** +** See Copyright Notice in mruby.h +*/ + +#include "mruby.h" +#include "mruby/class.h" +#include "mruby/data.h" +#include "mruby/string.h" +#include "error.h" +#include <sys/types.h> +#if defined(_WIN32) || defined(_WIN64) + #define MAXPATHLEN 1024 + #if !defined(PATH_MAX) + #define PATH_MAX MAX_PATH + #endif + #define S_ISDIR(B) ((B)&_S_IFDIR) + #include "Win/dirent.c" + #include <direct.h> + #define rmdir _rmdir + #define getcwd _getcwd + #define mkdir _mkdir + #define chdir _chdir +#else + #include <sys/param.h> + #include <dirent.h> + #include <unistd.h> +#endif +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> + +/* with/without IO module */ +#ifdef ENABLE_IO +#include "mruby/ext/io.h" +#else +#define E_IO_ERROR E_RUNTIME_ERROR +#endif + +struct mrb_dir { + DIR *dir; +}; + +void +mrb_dir_free(mrb_state *mrb, void *ptr) +{ + struct mrb_dir *mdir = ptr; + + if (mdir->dir) { + closedir(mdir->dir); + mdir->dir = NULL; + } + mrb_free(mrb, mdir); +} + +static struct mrb_data_type mrb_dir_type = { "DIR", mrb_dir_free }; + +mrb_value +mrb_dir_close(mrb_state *mrb, mrb_value self) +{ + struct mrb_dir *mdir; + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (!mdir) return mrb_nil_value(); + if (!mdir->dir) { + mrb_raise(mrb, E_IO_ERROR, "closed directory"); + } + if (closedir(mdir->dir) == -1) { + mrb_sys_fail(mrb, "closedir"); + } + mdir->dir = NULL; + return mrb_nil_value(); +} + +mrb_value +mrb_dir_init(mrb_state *mrb, mrb_value self) +{ + DIR *dir; + struct mrb_dir *mdir; + mrb_value path; + char *cpath; + + mdir = (struct mrb_dir *)DATA_PTR(self); + if (mdir) { + mrb_dir_free(mrb, mdir); + } + DATA_TYPE(self) = &mrb_dir_type; + DATA_PTR(self) = NULL; + + mdir = (struct mrb_dir *)mrb_malloc(mrb, sizeof(*mdir)); + mdir->dir = NULL; + DATA_PTR(self) = mdir; + + mrb_get_args(mrb, "S", &path); + cpath = mrb_str_to_cstr(mrb, path); + if ((dir = opendir(cpath)) == NULL) { + mrb_sys_fail(mrb, cpath); + } + mdir->dir = dir; + return self; +} + +mrb_value +mrb_dir_delete(mrb_state *mrb, mrb_value klass) +{ + mrb_value path; + char *cpath; + + mrb_get_args(mrb, "S", &path); + cpath = mrb_str_to_cstr(mrb, path); + if (rmdir(cpath) == -1) { + mrb_sys_fail(mrb, cpath); + } + return mrb_fixnum_value(0); +} + +mrb_value +mrb_dir_existp(mrb_state *mrb, mrb_value klass) +{ + mrb_value path; + struct stat sb; + char *cpath; + + mrb_get_args(mrb, "S", &path); + cpath = mrb_str_to_cstr(mrb, path); + if (stat(cpath, &sb) == 0 && S_ISDIR(sb.st_mode)) { + return mrb_true_value(); + } else { + return mrb_false_value(); + } +} + +mrb_value +mrb_dir_getwd(mrb_state *mrb, mrb_value klass) +{ + mrb_value path; + + path = mrb_str_buf_new(mrb, MAXPATHLEN); + if (getcwd(RSTRING_PTR(path), MAXPATHLEN) == NULL) { + mrb_sys_fail(mrb, "getcwd(2)"); + } + mrb_str_resize(mrb, path, strlen(RSTRING_PTR(path))); + return path; +} + +mrb_value +mrb_dir_mkdir(mrb_state *mrb, mrb_value klass) +{ + mrb_int mode; + mrb_value spath; + char *path; + + mode = 0777; + mrb_get_args(mrb, "S|i", &spath, &mode); + path = mrb_str_to_cstr(mrb, spath); +#ifndef _WIN32 + if (mkdir(path, mode) == -1) { +#else + if (mkdir(path) == -1) { +#endif + mrb_sys_fail(mrb, path); + } + return mrb_fixnum_value(0); +} + +mrb_value +mrb_dir_chdir(mrb_state *mrb, mrb_value klass) +{ + mrb_value spath; + char *path; + + mrb_get_args(mrb, "S", &spath); + path = mrb_str_to_cstr(mrb, spath); + if (chdir(path) == -1) { + mrb_sys_fail(mrb, path); + } + return mrb_fixnum_value(0); +} + +mrb_value +mrb_dir_read(mrb_state *mrb, mrb_value self) +{ + struct mrb_dir *mdir; + struct dirent *dp; + + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (!mdir) return mrb_nil_value(); + if (!mdir->dir) { + mrb_raise(mrb, E_IO_ERROR, "closed directory"); + } + dp = readdir(mdir->dir); + if (dp != NULL) { + return mrb_str_new_cstr(mrb, dp->d_name); + } else { + return mrb_nil_value(); + } +} + +mrb_value +mrb_dir_rewind(mrb_state *mrb, mrb_value self) +{ + struct mrb_dir *mdir; + + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (!mdir) return mrb_nil_value(); + if (!mdir->dir) { + mrb_raise(mrb, E_IO_ERROR, "closed directory"); + } + rewinddir(mdir->dir); + return self; +} + +mrb_value +mrb_dir_seek(mrb_state *mrb, mrb_value self) +{ + #if defined(_WIN32) || defined(_WIN64) || defined(__android__) + mrb_raise(mrb, E_RUNTIME_ERROR, "dirseek() unreliable on Win platforms"); + return self; + #else + struct mrb_dir *mdir; + mrb_int pos; + + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (!mdir) return mrb_nil_value(); + if (!mdir->dir) { + mrb_raise(mrb, E_IO_ERROR, "closed directory"); + } + mrb_get_args(mrb, "i", &pos); + seekdir(mdir->dir, (long)pos); + return self; + #endif +} + +mrb_value +mrb_dir_tell(mrb_state *mrb, mrb_value self) +{ + #if defined(_WIN32) || defined(_WIN64) || defined(__android__) + mrb_raise(mrb, E_RUNTIME_ERROR, "dirtell() unreliable on Win platforms"); + return mrb_fixnum_value(0); + #else + struct mrb_dir *mdir; + mrb_int pos; + + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (!mdir) return mrb_nil_value(); + if (!mdir->dir) { + mrb_raise(mrb, E_IO_ERROR, "closed directory"); + } + pos = (mrb_int)telldir(mdir->dir); + return mrb_fixnum_value(pos); + #endif +} + +void +mrb_mruby_dir_gem_init(mrb_state *mrb) +{ + struct RClass *d; + + d = mrb_define_class(mrb, "Dir", mrb->object_class); + MRB_SET_INSTANCE_TT(d, MRB_TT_DATA); + mrb_define_class_method(mrb, d, "delete", mrb_dir_delete, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, d, "exist?", mrb_dir_existp, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, d, "getwd", mrb_dir_getwd, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, d, "mkdir", mrb_dir_mkdir, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, d, "_chdir", mrb_dir_chdir, MRB_ARGS_REQ(1)); + + mrb_define_method(mrb, d, "close", mrb_dir_close, MRB_ARGS_NONE()); + mrb_define_method(mrb, d, "initialize", mrb_dir_init, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, d, "read", mrb_dir_read, MRB_ARGS_NONE()); + mrb_define_method(mrb, d, "rewind", mrb_dir_rewind, MRB_ARGS_NONE()); + mrb_define_method(mrb, d, "seek", mrb_dir_seek, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, d, "tell", mrb_dir_tell, MRB_ARGS_NONE()); +} + +void +mrb_mruby_dir_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-dir/test/dir.rb b/web/server/h2o/libh2o/deps/mruby-dir/test/dir.rb new file mode 100644 index 000000000..cb1f1e31b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-dir/test/dir.rb @@ -0,0 +1,128 @@ +assert('Dir') do + assert_equal(Class, Dir.class) +end + +assert('DirTest.setup') do + DirTest.setup +end + +assert('Dir.chdir') do + assert_equal 0, Dir.chdir(DirTest.sandbox) +end + +assert('Dir.entries') do + a = Dir.entries(DirTest.sandbox) + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('Dir.exist?') do + assert_true Dir.exist?(DirTest.sandbox) + assert_false Dir.exist?(DirTest.sandbox + "/nosuchdir") +end + +assert('Dir.foreach') do + a = [] + Dir.foreach(DirTest.sandbox) { |s| a << s } + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('Dir.getwd') do + s = Dir.getwd + assert_true s.kind_of? String +end + +assert('Dir.mkdir') do + m1 = DirTest.sandbox + "/mkdir1" + m2 = DirTest.sandbox + "/mkdir2" + assert_equal 0, Dir.mkdir(m1) + assert_equal 0, Dir.mkdir(m2, 0765) +end + +assert('Dir.delete') do + s = DirTest.sandbox + "/delete" + Dir.mkdir(s) + assert_true Dir.exist?(s) + + Dir.delete(s) + assert_false Dir.exist?(s) +end + +assert('Dir.open') do + a = [] + Dir.open(DirTest.sandbox) { |d| + d.each { |s| a << s } + } + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('Dir#initialize and Dir#close') do + d = Dir.new(".") + assert_true d.instance_of? Dir + assert_nil d.close +end + +assert('Dir#close') do + d = Dir.new(".") +end + +assert('Dir#each') do + a = [] + d = Dir.open(DirTest.sandbox) + d.each { |s| a << s } + d.close + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('Dir#read') do + a = [] + d = Dir.open(DirTest.sandbox) + while s = d.read + a << s + end + d.close + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('Dir#rewind') do + d = Dir.open(DirTest.sandbox) + while d.read; end + + assert_equal d, d.rewind + + a = [] + while s = d.read + a << s + end + d.close + assert_true a.include? "a" + assert_true a.include? "b" +end + +# Note: behaviors of seekdir(3) and telldir(3) are so platform-dependent +# that we cannot write portable tests here. + +assert('Dir#tell') do + n = nil + Dir.open(DirTest.sandbox) { |d| + n = d.tell + } + assert_true n.is_a? Integer +end + +assert('Dir#seek') do + d1 = Dir.open(DirTest.sandbox) + d1.read + n = d1.tell + d1.read + d2 = d1.seek(n) + assert_equal d1, d2 +end + +assert('DirTest.teardown') do + DirTest.teardown +end diff --git a/web/server/h2o/libh2o/deps/mruby-dir/test/dirtest.c b/web/server/h2o/libh2o/deps/mruby-dir/test/dirtest.c new file mode 100644 index 000000000..070f23a82 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-dir/test/dirtest.c @@ -0,0 +1,114 @@ +#include <sys/types.h> +#include <sys/stat.h> + +#include <dirent.h> +#include <unistd.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "mruby.h" +#include "mruby/string.h" +#include "mruby/variable.h" + + +mrb_value +mrb_dirtest_setup(mrb_state *mrb, mrb_value klass) +{ + mrb_value s; + char buf[1024]; + const char *aname = "a"; + const char *bname = "b"; + + /* save current working directory */ + if (getcwd(buf, sizeof(buf)) == NULL) { + mrb_raise(mrb, E_RUNTIME_ERROR, "getcwd() failed"); + } + mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "pwd"), mrb_str_new_cstr(mrb, buf)); + + /* create sandbox */ + snprintf(buf, sizeof(buf), "%s/mruby-dir-test.XXXXXX", P_tmpdir); + if (mkdtemp(buf) == NULL) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdtemp(%S) failed", mrb_str_new_cstr(mrb, buf)); + } + s = mrb_str_new_cstr(mrb, buf); + mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "sandbox"), s); + + /* go to sandbox */ + if (chdir(buf) == -1) { + rmdir(buf); + mrb_raisef(mrb, E_RUNTIME_ERROR, "chdir(%S) failed", s); + } + + /* make some directories in the sandbox */ + if (mkdir(aname, 0) == -1) { + chdir(".."); + rmdir(buf); + mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdir(%S) failed", mrb_str_new_cstr(mrb, aname)); + } + if (mkdir(bname, 0) == -1) { + rmdir(aname); + chdir(".."); + rmdir(buf); + mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdir(%S) failed", mrb_str_new_cstr(mrb, bname)); + } + + return mrb_true_value(); +} + +mrb_value +mrb_dirtest_teardown(mrb_state *mrb, mrb_value klass) +{ + mrb_value d, sandbox; + DIR *dirp; + struct dirent *dp; + const char *path; + + /* cleanup sandbox */ + sandbox = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "sandbox")); + path = mrb_str_to_cstr(mrb, sandbox); + + dirp = opendir(path); + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) + continue; + if (rmdir(dp->d_name) == -1) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "rmdir(%S) failed", mrb_str_new_cstr(mrb, dp->d_name)); + } + } + closedir(dirp); + + /* back to original pwd */ + d = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "pwd")); + path = mrb_str_to_cstr(mrb, d); + if (chdir(path) == -1) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "chdir(%S) failed", d); + } + + /* remove sandbox directory */ + sandbox = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "sandbox")); + path = mrb_str_to_cstr(mrb, sandbox); + if (rmdir(path) == -1) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "rmdir(%S) failed", sandbox); + } + + return mrb_true_value(); +} + +mrb_value +mrb_dirtest_sandbox(mrb_state *mrb, mrb_value klass) +{ + return mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "sandbox")); +} + +void +mrb_mruby_dir_gem_test(mrb_state *mrb) +{ + struct RClass *c = mrb_define_module(mrb, "DirTest"); + + mrb_define_class_method(mrb, c, "sandbox", mrb_dirtest_sandbox, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, c, "setup", mrb_dirtest_setup, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, c, "teardown", mrb_dirtest_teardown, MRB_ARGS_NONE()); +} + diff --git a/web/server/h2o/libh2o/deps/mruby-env/.gitignore b/web/server/h2o/libh2o/deps/mruby-env/.gitignore new file mode 100644 index 000000000..ceeb05b41 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-env/.gitignore @@ -0,0 +1 @@ +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-env/.travis.yml b/web/server/h2o/libh2o/deps/mruby-env/.travis.yml new file mode 100644 index 000000000..ffe227284 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-env/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-env/README.md b/web/server/h2o/libh2o/deps/mruby-env/README.md new file mode 100644 index 000000000..b6db22484 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-env/README.md @@ -0,0 +1,52 @@ +mruby-env +========= + +mruby-env provides "ENV" object, which is a hash-like accessor +for environment variables. + +### Methods + +``` +[] []= clear delete has_key? include? inspect key? keys +member? size store to_a to_hash to_s values +``` + + +### To build: + +Prerequisites: + + * mruby + * libc + + activate GEMs in *build_config.rb* + * conf.gem :github => 'iij/mruby-env' + ruby ./minirake + +### To run the tests: + + ruby ./minirake test + + +## License + +Copyright (c) 2012 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/web/server/h2o/libh2o/deps/mruby-env/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-env/mrbgem.rake new file mode 100644 index 000000000..03249be28 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-env/mrbgem.rake @@ -0,0 +1,4 @@ +MRuby::Gem::Specification.new('mruby-env') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan Inc.' +end diff --git a/web/server/h2o/libh2o/deps/mruby-env/mrblib/env.rb b/web/server/h2o/libh2o/deps/mruby-env/mrblib/env.rb new file mode 100644 index 000000000..67f9811a1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-env/mrblib/env.rb @@ -0,0 +1,16 @@ +class << ENV + alias include? has_key? + alias key? has_key? + alias member? has_key? + + def clear + self.keys.each { |k| self.delete(k) } + self + end + + def delete(key) + old = self[key] + self[key] = nil + old + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-env/run_test.rb b/web/server/h2o/libh2o/deps/mruby-env/run_test.rb new file mode 100644 index 000000000..eefc91434 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-env/run_test.rb @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem :core => 'mruby-time' + conf.gem :github => 'iij/mruby-io' + conf.gem :github => 'iij/mruby-mtest' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-env/src/env.c b/web/server/h2o/libh2o/deps/mruby-env/src/env.c new file mode 100644 index 000000000..0395e1bc1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-env/src/env.c @@ -0,0 +1,243 @@ +/* +** env.c - ENV is a Hash-like accessor for environment variables. +** +*/ + +#include "mruby.h" +#include "mruby/hash.h" +#include "mruby/khash.h" +#include "mruby/class.h" +#include "mruby/array.h" +#include "mruby/string.h" +#include "mruby/variable.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#ifdef _WIN32 +int +unsetenv(const char* name) +{ + int r; + char* p = malloc(strlen(name) + 2); + if (!p) return -1; + strcpy(p, name); + strcat(p, "="); + r = _putenv(p); + free(p); + return r; +} + +int +setenv(const char* name, const char* value, int overwrite) +{ + int r; + char* p = malloc(strlen(name) + strlen(value) + 2); + if (!p) return -1; + strcpy(p, name); + strcat(p, "="); + strcat(p, value); + r = _putenv(p); + free(p); + return r; +} +#define environ _environ +#else +extern char **environ; +#endif + + +mrb_value +mrb_env_aget(mrb_state *mrb, mrb_value self) +{ + mrb_value key; + const char *cname, *cvalue; + + mrb_get_args(mrb, "S", &key); + cname = mrb_string_value_cstr(mrb, &key); + cvalue = getenv(cname); + if (cvalue != NULL) { + return mrb_str_new_cstr(mrb, cvalue); + } else { + return mrb_nil_value(); + } +} + +mrb_value +mrb_env_has_key(mrb_state *mrb, mrb_value self) +{ + mrb_value name; + const char *key; + mrb_get_args(mrb, "S", &name); + key = mrb_str_to_cstr(mrb, name); + if (getenv(key) != NULL) { + return mrb_true_value(); + } else { + return mrb_false_value(); + } +} + +mrb_value +mrb_env_keys(mrb_state *mrb, mrb_value self) +{ + int i; + mrb_value ary; + + ary = mrb_ary_new(mrb); + for (i = 0; environ[i] != NULL; i++) { + char *str = strchr(environ[i], '='); + if (str != NULL) { + int len = str - environ[i]; + mrb_ary_push(mrb, ary, mrb_str_new(mrb, environ[i], len)); + } + } + + return ary; +} + +mrb_value +mrb_env_values(mrb_state *mrb, mrb_value self) +{ + int i; + mrb_value ary; + + ary = mrb_ary_new(mrb); + for (i = 0; environ[i] != NULL; i++) { + char *str = strchr(environ[i], '='); + if (str) { + int len; + str++; + len = strlen(str); + mrb_ary_push(mrb, ary, mrb_str_new(mrb, str, len)); + } + } + + return ary; +} + +static mrb_value +mrb_env_size(mrb_state *mrb, mrb_value self) +{ + int i; + + for (i = 0; environ[i] != NULL; i++) + ; + + return mrb_fixnum_value(i); +} + +static mrb_value +mrb_env_to_hash(mrb_state *mrb, mrb_value self) +{ + int i; + mrb_value hash; + + hash = mrb_hash_new(mrb); + for (i = 0; environ[i] != NULL; i++) { + char *str = strchr(environ[i], '='); + if (str != NULL) { + mrb_value val; + int ai = mrb_gc_arena_save(mrb); + int len = str - environ[i]; + mrb_value key = mrb_str_new(mrb, environ[i], len); + str++; + val = mrb_str_new(mrb, str, strlen(str)); + mrb_hash_set(mrb, hash, key, val); + mrb_gc_arena_restore(mrb, ai); + } + } + + return hash; +} + +static mrb_value +mrb_env_to_a(mrb_state *mrb, mrb_value self) +{ + int i; + mrb_value ary; + + ary = mrb_ary_new(mrb); + for (i = 0; environ[i] != NULL; i++) { + char *str = strchr(environ[i], '='); + if (str != NULL) { + int ai = mrb_gc_arena_save(mrb); + mrb_value elem = mrb_ary_new(mrb); + int len = str - environ[i]; + mrb_ary_push(mrb, elem, mrb_str_new(mrb, environ[i], len)); + str++; + mrb_ary_push(mrb, elem, mrb_str_new(mrb, str, strlen(str))); + mrb_ary_push(mrb, ary, elem); + mrb_gc_arena_restore(mrb, ai); + } + } + + return ary; +} + +static mrb_value +mrb_env_inspect(mrb_state *mrb, mrb_value self) +{ + mrb_value hash = mrb_env_to_hash(mrb, self); + return mrb_funcall(mrb, hash, "inspect", 0); +} + +static mrb_value +mrb_env_to_s(mrb_state *mrb, mrb_value self) +{ + return mrb_str_new_cstr(mrb, "ENV"); +} + +static mrb_value +mrb_env_aset(mrb_state *mrb, mrb_value self) +{ + mrb_value name, value; + const char *cname, *cvalue; + + mrb_get_args(mrb, "So", &name, &value); + cname = mrb_string_value_cstr(mrb, &name); + + if (mrb_nil_p(value)) { + if (unsetenv(cname) != 0) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't delete environment variable"); + } + } else { + mrb_convert_type(mrb, value, MRB_TT_STRING, "String", "to_str"); + cvalue = mrb_string_value_cstr(mrb, &value); + if (setenv(cname, cvalue, 1) != 0) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't change environment variable"); + } + } + return value; +} + +void +mrb_mruby_env_gem_init(mrb_state *mrb) +{ + struct RObject *e; + + e = (struct RObject*) mrb_obj_alloc(mrb, MRB_TT_OBJECT, mrb->object_class); +#if defined(MRUBY_RELEASE_NO) && MRUBY_RELEASE_NO >= 10000 + mrb_include_module(mrb, (struct RClass*)e, mrb_module_get(mrb, "Enumerable")); +#else + mrb_include_module(mrb, (struct RClass*)e, mrb_class_get(mrb, "Enumerable")); +#endif + + mrb_define_singleton_method(mrb, e,"[]", mrb_env_aget, MRB_ARGS_REQ(1)); + mrb_define_singleton_method(mrb, e,"[]=", mrb_env_aset, MRB_ARGS_REQ(2)); + mrb_define_singleton_method(mrb, e,"has_key?", mrb_env_has_key, MRB_ARGS_REQ(1)); + mrb_define_singleton_method(mrb, e,"inspect", mrb_env_inspect, MRB_ARGS_NONE()); + mrb_define_singleton_method(mrb, e,"keys", mrb_env_keys, MRB_ARGS_NONE()); + mrb_define_singleton_method(mrb, e,"size", mrb_env_size, MRB_ARGS_NONE()); + mrb_define_singleton_method(mrb, e,"store", mrb_env_aset, MRB_ARGS_REQ(2)); + mrb_define_singleton_method(mrb, e,"to_a", mrb_env_to_a, MRB_ARGS_NONE()); + mrb_define_singleton_method(mrb, e,"to_hash", mrb_env_to_hash, MRB_ARGS_NONE()); + mrb_define_singleton_method(mrb, e,"to_s", mrb_env_to_s, MRB_ARGS_NONE()); + mrb_define_singleton_method(mrb, e,"values", mrb_env_values, MRB_ARGS_NONE()); + + mrb_define_global_const(mrb, "ENV", mrb_obj_value(e)); +} + +void +mrb_mruby_env_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-env/test/env_test.rb b/web/server/h2o/libh2o/deps/mruby-env/test/env_test.rb new file mode 100644 index 000000000..2aa3dab2c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-env/test/env_test.rb @@ -0,0 +1,121 @@ +## +# ENV test +# + +if Object.const_defined?(:MTest) + class ENVTest < MTest::Unit::TestCase + def test_env_class + assert_equal(Object, ENV.class) + end + + def setup + @env_hash = ENV.to_hash + ENV.clear + end + + def teardown + ENV.clear + @env_hash.each do |k, v| + ENV[k] = v + end + end + + def set_dummy_env + ENV['FOO'] = 'bar' + end + + def test_size_empty + assert_equal(0, ENV.size) + end + + def test_keys_empty + assert_empty(ENV.keys) + end + + def test_values_empty + assert_empty(ENV.values) + end + + def test_env_to_s_empty + assert_equal("ENV", ENV.to_s) + end + + def test_env_inspect_empty + assert_equal("{}", ENV.inspect) + end + + def test_env_to_hash_empty + assert_equal({}, ENV.to_hash) + end + + def test_env_get_val + set_dummy_env + assert_equal('bar', ENV['FOO']) + end + + def test_env_keys + set_dummy_env + assert_equal(['FOO'], ENV.keys) + end + + def test_env_values + set_dummy_env + assert_equal(['bar'], ENV.values) + end + + def test_env_to_s + set_dummy_env + assert_equal("ENV", ENV.to_s) + end + + def test_env_has_key + set_dummy_env + assert_true ENV.has_key?("FOO") + assert_false ENV.has_key?("BAR") + end + + def test_env_inspect + set_dummy_env + assert_equal("{\"FOO\"=>\"bar\"}", ENV.inspect) + end + + def test_env_delete + set_dummy_env + old = ENV['FOO'] + ret = ENV.delete('FOO') + assert_equal(0, ENV.size) + assert_equal(old, ret) + assert_equal(nil, ENV.delete('nosuchenv')) + end + + def test_env_subst_nil + set_dummy_env + ENV['FOO'] = nil + assert_equal(0, ENV.size) + end + + def test_env_store + ENV['a'] = 'b' + assert_equal 'b', ENV['a'] + + ENV['a'] = 'c' + assert_equal 'c', ENV['a'] + + ENV['a'] = nil + assert_equal nil, ENV['a'] + + ENV['b'] = nil + assert_equal nil, ENV['b'] + assert_equal 0, ENV.size + end + end + + if $ok_test + MTest::Unit.new.mrbtest + else + MTest::Unit.new.run + end +else + $asserts << "test skip of mruby-env/test/env_test.rb" if $asserts +end + diff --git a/web/server/h2o/libh2o/deps/mruby-errno/.gitignore b/web/server/h2o/libh2o/deps/mruby-errno/.gitignore new file mode 100644 index 000000000..ceeb05b41 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/.gitignore @@ -0,0 +1 @@ +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-errno/.travis.yml b/web/server/h2o/libh2o/deps/mruby-errno/.travis.yml new file mode 100644 index 000000000..ffe227284 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-errno/README.md b/web/server/h2o/libh2o/deps/mruby-errno/README.md new file mode 100644 index 000000000..e3c594cb5 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/README.md @@ -0,0 +1,27 @@ +mruby-errno +=========== + +Errno module for mruby + + +## License + +Copyright (c) 2013 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/web/server/h2o/libh2o/deps/mruby-errno/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-errno/mrbgem.rake new file mode 100644 index 000000000..ba3d60dae --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/mrbgem.rake @@ -0,0 +1,6 @@ +MRuby::Gem::Specification.new('mruby-errno') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan Inc.' + + spec.cc.include_paths << "#{build.root}/src" +end diff --git a/web/server/h2o/libh2o/deps/mruby-errno/run_test.rb b/web/server/h2o/libh2o/deps/mruby-errno/run_test.rb new file mode 100644 index 000000000..d9566a2a6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/run_test.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +gemname = File.basename(File.dirname(File.expand_path __FILE__)) + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + build_args = ['all', 'test'] if build_args.nil? or build_args.empty? + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-errno/src/errno.c b/web/server/h2o/libh2o/deps/mruby-errno/src/errno.c new file mode 100644 index 000000000..3617efd45 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/src/errno.c @@ -0,0 +1,175 @@ +#include "mruby.h" +#include "mruby/array.h" +#include "mruby/class.h" +#include "mruby/hash.h" +#include "mruby/numeric.h" +#include "mruby/string.h" +#include "mruby/variable.h" +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#if MRUBY_RELEASE_NO < 10000 +static struct RClass * +mrb_module_get(mrb_state *mrb, const char *name) +{ + return mrb_class_get(mrb, name); +} +#endif + +static mrb_value +mrb_sce_init(mrb_state *mrb, mrb_value self) +{ + mrb_value c, e2c, m, str; + mrb_int n; + int argc, no_errno = 0; + char buf[20]; + + argc = mrb_get_args(mrb, "o|i", &m, &n); + if (argc == 1) { + if (mrb_type(m) == MRB_TT_FIXNUM) { + n = mrb_fixnum(m); + m = mrb_nil_value(); + } else { + no_errno = 1; + } + } + if (!no_errno) { + e2c = mrb_const_get(mrb, mrb_obj_value(mrb_module_get(mrb, "Errno")), mrb_intern_lit(mrb, "Errno2class")); + c = mrb_hash_fetch(mrb, e2c, mrb_fixnum_value(n), mrb_nil_value()); + if (!mrb_nil_p(c)) { + mrb_basic_ptr(self)->c = mrb_class_ptr(c); + str = mrb_str_new_cstr(mrb, strerror(n)); + } else { + mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "errno"), mrb_fixnum_value(n)); + str = mrb_str_new_cstr(mrb, "Unknown error: "); + snprintf(buf, sizeof(buf), "%d", (int)n); + mrb_str_cat2(mrb, str, buf); + } + } else { + str = mrb_str_new_cstr(mrb, "unknown error"); + } + if (!mrb_nil_p(m)) { + mrb_str_cat2(mrb, str, " - "); + mrb_str_append(mrb, str, m); + } + mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "mesg"), str); + return self; +} + +static mrb_value +mrb_sce_errno(mrb_state *mrb, mrb_value self) +{ + struct RClass *c; + mrb_sym sym; + + c = mrb_class(mrb, self); + sym = mrb_intern_lit(mrb, "Errno"); +#if MRUBY_RELEASE_NO < 10000 + if (mrb_const_defined_at(mrb, c, sym)) { +#else + if (mrb_const_defined_at(mrb, mrb_obj_value(c), sym)) { +#endif + return mrb_const_get(mrb, mrb_obj_value(c), sym); + } else { + sym = mrb_intern_lit(mrb, "errno"); + return mrb_attr_get(mrb, self, sym); + } +} + +static mrb_value +mrb_sce_to_s(mrb_state *mrb, mrb_value self) +{ + return mrb_attr_get(mrb, self, mrb_intern_lit(mrb, "mesg")); +} + +static mrb_value +mrb_sce_sys_fail(mrb_state *mrb, mrb_value cls) +{ + struct RClass *cl, *sce; + mrb_value e, msg; + mrb_int no; + int argc; + char name[8]; + + sce = mrb_class_get(mrb, "SystemCallError"); + argc = mrb_get_args(mrb, "i|S", &no, &msg); + if (argc == 1) { + e = mrb_funcall(mrb, mrb_obj_value(sce), "new", 1, mrb_fixnum_value(no)); + } else { + e = mrb_funcall(mrb, mrb_obj_value(sce), "new", 2, msg, mrb_fixnum_value(no)); + } + if (mrb_obj_class(mrb, e) == sce) { + snprintf(name, sizeof(name), "E%03ld", (long)no); + cl = mrb_define_class_under(mrb, mrb_module_get(mrb, "Errno"), name, sce); + mrb_define_const(mrb, cl, "Errno", mrb_fixnum_value(no)); + mrb_basic_ptr(e)->c = cl; + } + mrb_exc_raise(mrb, e); + return mrb_nil_value(); /* NOTREACHED */ +} + +static mrb_value +mrb_exxx_init(mrb_state *mrb, mrb_value self) +{ + mrb_value m, no, str; + + no = mrb_const_get(mrb, mrb_obj_value(mrb_class(mrb, self)), mrb_intern_lit(mrb, "Errno")); + str = mrb_str_new_cstr(mrb, strerror(mrb_fixnum(no))); + + m = mrb_nil_value(); + mrb_get_args(mrb, "|S", &m); + if (!mrb_nil_p(m)) { + mrb_str_cat2(mrb, str, " - "); + mrb_str_append(mrb, str, m); + } + mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "mesg"), str); + return self; +} + +void +mrb_mruby_errno_gem_init(mrb_state *mrb) +{ + struct RClass *e, *eno, *sce, *ste; + mrb_value h, noerror; + + ste = mrb_class_get(mrb, "StandardError"); + + sce = mrb_define_class(mrb, "SystemCallError", ste); + mrb_define_class_method(mrb, sce, "_sys_fail", mrb_sce_sys_fail, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, sce, "errno", mrb_sce_errno, MRB_ARGS_NONE()); + mrb_define_method(mrb, sce, "to_s", mrb_sce_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, sce, "initialize", mrb_sce_init, MRB_ARGS_ARG(1, 1)); + + eno = mrb_define_module(mrb, "Errno"); + h = mrb_hash_new(mrb); + mrb_define_const(mrb, eno, "Errno2class", h); + + e = mrb_define_class_under(mrb, eno, "NOERROR", sce); + mrb_define_const(mrb, e, "Errno", mrb_fixnum_value(0)); + mrb_define_method(mrb, e, "initialize", mrb_exxx_init, MRB_ARGS_OPT(1)); + //mrb_define_method(mrb, e, "===", mrb_exxx_cmp, MRB_ARGS_REQ(1)); + noerror = mrb_obj_value(e); + +#define itsdefined(SYM) \ + do { \ + int ai = mrb_gc_arena_save(mrb); \ + e = mrb_define_class_under(mrb, eno, #SYM, sce); \ + mrb_define_const(mrb, e, "Errno", mrb_fixnum_value(SYM)); \ + mrb_define_method(mrb, e, "initialize", mrb_exxx_init, MRB_ARGS_OPT(1)); \ + mrb_hash_set(mrb, h, mrb_fixnum_value(SYM), mrb_obj_value(e)); \ + mrb_gc_arena_restore(mrb, ai); \ + } while (0) + +#define itsnotdefined(SYM) \ + do { \ + mrb_define_const(mrb, eno, #SYM, noerror); \ + } while (0) + +#include "known_errors_def.cstub" +} + +void +mrb_mruby_errno_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-errno/src/gen.rb b/web/server/h2o/libh2o/deps/mruby-errno/src/gen.rb new file mode 100755 index 000000000..12e6b302e --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/src/gen.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname($0)) + +e = File.open("known_errors_e2c.cstub", "w") +d = File.open("known_errors_def.cstub", "w") + +IO.readlines("known_errors.def").each { |name| + next if name =~ /^#/ + name.strip! + + e.write <<CODE +#ifdef #{name} + { #{name}, NULL, }, +#endif +CODE + + d.write <<CODE +#ifdef #{name} + itsdefined(#{name}); +#else + itsnotdefined(#{name}); +#endif +CODE +} diff --git a/web/server/h2o/libh2o/deps/mruby-errno/src/known_errors.def b/web/server/h2o/libh2o/deps/mruby-errno/src/known_errors.def new file mode 100644 index 000000000..3cebe90a8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/src/known_errors.def @@ -0,0 +1,145 @@ +EPERM +ENOENT +ESRCH +EINTR +EIO +ENXIO +E2BIG +ENOEXEC +EBADF +ECHILD +EAGAIN +ENOMEM +EACCES +EFAULT +ENOTBLK +EBUSY +EEXIST +EXDEV +ENODEV +ENOTDIR +EISDIR +EINVAL +ENFILE +EMFILE +ENOTTY +ETXTBSY +EFBIG +ENOSPC +ESPIPE +EROFS +EMLINK +EPIPE +EDOM +ERANGE +EDEADLK +ENAMETOOLONG +ENOLCK +ENOSYS +ENOTEMPTY +ELOOP +EWOULDBLOCK +ENOMSG +EIDRM +ECHRNG +EL2NSYNC +EL3HLT +EL3RST +ELNRNG +EUNATCH +ENOCSI +EL2HLT +EBADE +EBADR +EXFULL +ENOANO +EBADRQC +EBADSLT +EDEADLOCK +EBFONT +ENOSTR +ENODATA +ETIME +ENOSR +ENONET +ENOPKG +EREMOTE +ENOLINK +EADV +ESRMNT +ECOMM +EPROTO +EMULTIHOP +EDOTDOT +EBADMSG +EOVERFLOW +ENOTUNIQ +EBADFD +EREMCHG +ELIBACC +ELIBBAD +ELIBSCN +ELIBMAX +ELIBEXEC +EILSEQ +ERESTART +ESTRPIPE +EUSERS +ENOTSOCK +EDESTADDRREQ +EMSGSIZE +EPROTOTYPE +ENOPROTOOPT +EPROTONOSUPPORT +ESOCKTNOSUPPORT +EOPNOTSUPP +EPFNOSUPPORT +EAFNOSUPPORT +EADDRINUSE +EADDRNOTAVAIL +ENETDOWN +ENETUNREACH +ENETRESET +ECONNABORTED +ECONNRESET +ENOBUFS +EISCONN +ENOTCONN +ESHUTDOWN +ETOOMANYREFS +ETIMEDOUT +ECONNREFUSED +EHOSTDOWN +EHOSTUNREACH +EALREADY +EINPROGRESS +ESTALE +EUCLEAN +ENOTNAM +ENAVAIL +EISNAM +EREMOTEIO +EDQUOT +ECANCELED +EKEYEXPIRED +EKEYREJECTED +EKEYREVOKED +EMEDIUMTYPE +ENOKEY +ENOMEDIUM +ENOTRECOVERABLE +EOWNERDEAD +ERFKILL +EAUTH +EBADRPC +EDOOFUS +EFTYPE +ENEEDAUTH +ENOATTR +ENOTSUP +EPROCLIM +EPROCUNAVAIL +EPROGMISMATCH +EPROGUNAVAIL +ERPCMISMATCH +EIPSEC diff --git a/web/server/h2o/libh2o/deps/mruby-errno/src/known_errors_def.cstub b/web/server/h2o/libh2o/deps/mruby-errno/src/known_errors_def.cstub new file mode 100644 index 000000000..83d8670ba --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/src/known_errors_def.cstub @@ -0,0 +1,725 @@ +#ifdef EPERM + itsdefined(EPERM); +#else + itsnotdefined(EPERM); +#endif +#ifdef ENOENT + itsdefined(ENOENT); +#else + itsnotdefined(ENOENT); +#endif +#ifdef ESRCH + itsdefined(ESRCH); +#else + itsnotdefined(ESRCH); +#endif +#ifdef EINTR + itsdefined(EINTR); +#else + itsnotdefined(EINTR); +#endif +#ifdef EIO + itsdefined(EIO); +#else + itsnotdefined(EIO); +#endif +#ifdef ENXIO + itsdefined(ENXIO); +#else + itsnotdefined(ENXIO); +#endif +#ifdef E2BIG + itsdefined(E2BIG); +#else + itsnotdefined(E2BIG); +#endif +#ifdef ENOEXEC + itsdefined(ENOEXEC); +#else + itsnotdefined(ENOEXEC); +#endif +#ifdef EBADF + itsdefined(EBADF); +#else + itsnotdefined(EBADF); +#endif +#ifdef ECHILD + itsdefined(ECHILD); +#else + itsnotdefined(ECHILD); +#endif +#ifdef EAGAIN + itsdefined(EAGAIN); +#else + itsnotdefined(EAGAIN); +#endif +#ifdef ENOMEM + itsdefined(ENOMEM); +#else + itsnotdefined(ENOMEM); +#endif +#ifdef EACCES + itsdefined(EACCES); +#else + itsnotdefined(EACCES); +#endif +#ifdef EFAULT + itsdefined(EFAULT); +#else + itsnotdefined(EFAULT); +#endif +#ifdef ENOTBLK + itsdefined(ENOTBLK); +#else + itsnotdefined(ENOTBLK); +#endif +#ifdef EBUSY + itsdefined(EBUSY); +#else + itsnotdefined(EBUSY); +#endif +#ifdef EEXIST + itsdefined(EEXIST); +#else + itsnotdefined(EEXIST); +#endif +#ifdef EXDEV + itsdefined(EXDEV); +#else + itsnotdefined(EXDEV); +#endif +#ifdef ENODEV + itsdefined(ENODEV); +#else + itsnotdefined(ENODEV); +#endif +#ifdef ENOTDIR + itsdefined(ENOTDIR); +#else + itsnotdefined(ENOTDIR); +#endif +#ifdef EISDIR + itsdefined(EISDIR); +#else + itsnotdefined(EISDIR); +#endif +#ifdef EINVAL + itsdefined(EINVAL); +#else + itsnotdefined(EINVAL); +#endif +#ifdef ENFILE + itsdefined(ENFILE); +#else + itsnotdefined(ENFILE); +#endif +#ifdef EMFILE + itsdefined(EMFILE); +#else + itsnotdefined(EMFILE); +#endif +#ifdef ENOTTY + itsdefined(ENOTTY); +#else + itsnotdefined(ENOTTY); +#endif +#ifdef ETXTBSY + itsdefined(ETXTBSY); +#else + itsnotdefined(ETXTBSY); +#endif +#ifdef EFBIG + itsdefined(EFBIG); +#else + itsnotdefined(EFBIG); +#endif +#ifdef ENOSPC + itsdefined(ENOSPC); +#else + itsnotdefined(ENOSPC); +#endif +#ifdef ESPIPE + itsdefined(ESPIPE); +#else + itsnotdefined(ESPIPE); +#endif +#ifdef EROFS + itsdefined(EROFS); +#else + itsnotdefined(EROFS); +#endif +#ifdef EMLINK + itsdefined(EMLINK); +#else + itsnotdefined(EMLINK); +#endif +#ifdef EPIPE + itsdefined(EPIPE); +#else + itsnotdefined(EPIPE); +#endif +#ifdef EDOM + itsdefined(EDOM); +#else + itsnotdefined(EDOM); +#endif +#ifdef ERANGE + itsdefined(ERANGE); +#else + itsnotdefined(ERANGE); +#endif +#ifdef EDEADLK + itsdefined(EDEADLK); +#else + itsnotdefined(EDEADLK); +#endif +#ifdef ENAMETOOLONG + itsdefined(ENAMETOOLONG); +#else + itsnotdefined(ENAMETOOLONG); +#endif +#ifdef ENOLCK + itsdefined(ENOLCK); +#else + itsnotdefined(ENOLCK); +#endif +#ifdef ENOSYS + itsdefined(ENOSYS); +#else + itsnotdefined(ENOSYS); +#endif +#ifdef ENOTEMPTY + itsdefined(ENOTEMPTY); +#else + itsnotdefined(ENOTEMPTY); +#endif +#ifdef ELOOP + itsdefined(ELOOP); +#else + itsnotdefined(ELOOP); +#endif +#ifdef EWOULDBLOCK + itsdefined(EWOULDBLOCK); +#else + itsnotdefined(EWOULDBLOCK); +#endif +#ifdef ENOMSG + itsdefined(ENOMSG); +#else + itsnotdefined(ENOMSG); +#endif +#ifdef EIDRM + itsdefined(EIDRM); +#else + itsnotdefined(EIDRM); +#endif +#ifdef ECHRNG + itsdefined(ECHRNG); +#else + itsnotdefined(ECHRNG); +#endif +#ifdef EL2NSYNC + itsdefined(EL2NSYNC); +#else + itsnotdefined(EL2NSYNC); +#endif +#ifdef EL3HLT + itsdefined(EL3HLT); +#else + itsnotdefined(EL3HLT); +#endif +#ifdef EL3RST + itsdefined(EL3RST); +#else + itsnotdefined(EL3RST); +#endif +#ifdef ELNRNG + itsdefined(ELNRNG); +#else + itsnotdefined(ELNRNG); +#endif +#ifdef EUNATCH + itsdefined(EUNATCH); +#else + itsnotdefined(EUNATCH); +#endif +#ifdef ENOCSI + itsdefined(ENOCSI); +#else + itsnotdefined(ENOCSI); +#endif +#ifdef EL2HLT + itsdefined(EL2HLT); +#else + itsnotdefined(EL2HLT); +#endif +#ifdef EBADE + itsdefined(EBADE); +#else + itsnotdefined(EBADE); +#endif +#ifdef EBADR + itsdefined(EBADR); +#else + itsnotdefined(EBADR); +#endif +#ifdef EXFULL + itsdefined(EXFULL); +#else + itsnotdefined(EXFULL); +#endif +#ifdef ENOANO + itsdefined(ENOANO); +#else + itsnotdefined(ENOANO); +#endif +#ifdef EBADRQC + itsdefined(EBADRQC); +#else + itsnotdefined(EBADRQC); +#endif +#ifdef EBADSLT + itsdefined(EBADSLT); +#else + itsnotdefined(EBADSLT); +#endif +#ifdef EDEADLOCK + itsdefined(EDEADLOCK); +#else + itsnotdefined(EDEADLOCK); +#endif +#ifdef EBFONT + itsdefined(EBFONT); +#else + itsnotdefined(EBFONT); +#endif +#ifdef ENOSTR + itsdefined(ENOSTR); +#else + itsnotdefined(ENOSTR); +#endif +#ifdef ENODATA + itsdefined(ENODATA); +#else + itsnotdefined(ENODATA); +#endif +#ifdef ETIME + itsdefined(ETIME); +#else + itsnotdefined(ETIME); +#endif +#ifdef ENOSR + itsdefined(ENOSR); +#else + itsnotdefined(ENOSR); +#endif +#ifdef ENONET + itsdefined(ENONET); +#else + itsnotdefined(ENONET); +#endif +#ifdef ENOPKG + itsdefined(ENOPKG); +#else + itsnotdefined(ENOPKG); +#endif +#ifdef EREMOTE + itsdefined(EREMOTE); +#else + itsnotdefined(EREMOTE); +#endif +#ifdef ENOLINK + itsdefined(ENOLINK); +#else + itsnotdefined(ENOLINK); +#endif +#ifdef EADV + itsdefined(EADV); +#else + itsnotdefined(EADV); +#endif +#ifdef ESRMNT + itsdefined(ESRMNT); +#else + itsnotdefined(ESRMNT); +#endif +#ifdef ECOMM + itsdefined(ECOMM); +#else + itsnotdefined(ECOMM); +#endif +#ifdef EPROTO + itsdefined(EPROTO); +#else + itsnotdefined(EPROTO); +#endif +#ifdef EMULTIHOP + itsdefined(EMULTIHOP); +#else + itsnotdefined(EMULTIHOP); +#endif +#ifdef EDOTDOT + itsdefined(EDOTDOT); +#else + itsnotdefined(EDOTDOT); +#endif +#ifdef EBADMSG + itsdefined(EBADMSG); +#else + itsnotdefined(EBADMSG); +#endif +#ifdef EOVERFLOW + itsdefined(EOVERFLOW); +#else + itsnotdefined(EOVERFLOW); +#endif +#ifdef ENOTUNIQ + itsdefined(ENOTUNIQ); +#else + itsnotdefined(ENOTUNIQ); +#endif +#ifdef EBADFD + itsdefined(EBADFD); +#else + itsnotdefined(EBADFD); +#endif +#ifdef EREMCHG + itsdefined(EREMCHG); +#else + itsnotdefined(EREMCHG); +#endif +#ifdef ELIBACC + itsdefined(ELIBACC); +#else + itsnotdefined(ELIBACC); +#endif +#ifdef ELIBBAD + itsdefined(ELIBBAD); +#else + itsnotdefined(ELIBBAD); +#endif +#ifdef ELIBSCN + itsdefined(ELIBSCN); +#else + itsnotdefined(ELIBSCN); +#endif +#ifdef ELIBMAX + itsdefined(ELIBMAX); +#else + itsnotdefined(ELIBMAX); +#endif +#ifdef ELIBEXEC + itsdefined(ELIBEXEC); +#else + itsnotdefined(ELIBEXEC); +#endif +#ifdef EILSEQ + itsdefined(EILSEQ); +#else + itsnotdefined(EILSEQ); +#endif +#ifdef ERESTART + itsdefined(ERESTART); +#else + itsnotdefined(ERESTART); +#endif +#ifdef ESTRPIPE + itsdefined(ESTRPIPE); +#else + itsnotdefined(ESTRPIPE); +#endif +#ifdef EUSERS + itsdefined(EUSERS); +#else + itsnotdefined(EUSERS); +#endif +#ifdef ENOTSOCK + itsdefined(ENOTSOCK); +#else + itsnotdefined(ENOTSOCK); +#endif +#ifdef EDESTADDRREQ + itsdefined(EDESTADDRREQ); +#else + itsnotdefined(EDESTADDRREQ); +#endif +#ifdef EMSGSIZE + itsdefined(EMSGSIZE); +#else + itsnotdefined(EMSGSIZE); +#endif +#ifdef EPROTOTYPE + itsdefined(EPROTOTYPE); +#else + itsnotdefined(EPROTOTYPE); +#endif +#ifdef ENOPROTOOPT + itsdefined(ENOPROTOOPT); +#else + itsnotdefined(ENOPROTOOPT); +#endif +#ifdef EPROTONOSUPPORT + itsdefined(EPROTONOSUPPORT); +#else + itsnotdefined(EPROTONOSUPPORT); +#endif +#ifdef ESOCKTNOSUPPORT + itsdefined(ESOCKTNOSUPPORT); +#else + itsnotdefined(ESOCKTNOSUPPORT); +#endif +#ifdef EOPNOTSUPP + itsdefined(EOPNOTSUPP); +#else + itsnotdefined(EOPNOTSUPP); +#endif +#ifdef EPFNOSUPPORT + itsdefined(EPFNOSUPPORT); +#else + itsnotdefined(EPFNOSUPPORT); +#endif +#ifdef EAFNOSUPPORT + itsdefined(EAFNOSUPPORT); +#else + itsnotdefined(EAFNOSUPPORT); +#endif +#ifdef EADDRINUSE + itsdefined(EADDRINUSE); +#else + itsnotdefined(EADDRINUSE); +#endif +#ifdef EADDRNOTAVAIL + itsdefined(EADDRNOTAVAIL); +#else + itsnotdefined(EADDRNOTAVAIL); +#endif +#ifdef ENETDOWN + itsdefined(ENETDOWN); +#else + itsnotdefined(ENETDOWN); +#endif +#ifdef ENETUNREACH + itsdefined(ENETUNREACH); +#else + itsnotdefined(ENETUNREACH); +#endif +#ifdef ENETRESET + itsdefined(ENETRESET); +#else + itsnotdefined(ENETRESET); +#endif +#ifdef ECONNABORTED + itsdefined(ECONNABORTED); +#else + itsnotdefined(ECONNABORTED); +#endif +#ifdef ECONNRESET + itsdefined(ECONNRESET); +#else + itsnotdefined(ECONNRESET); +#endif +#ifdef ENOBUFS + itsdefined(ENOBUFS); +#else + itsnotdefined(ENOBUFS); +#endif +#ifdef EISCONN + itsdefined(EISCONN); +#else + itsnotdefined(EISCONN); +#endif +#ifdef ENOTCONN + itsdefined(ENOTCONN); +#else + itsnotdefined(ENOTCONN); +#endif +#ifdef ESHUTDOWN + itsdefined(ESHUTDOWN); +#else + itsnotdefined(ESHUTDOWN); +#endif +#ifdef ETOOMANYREFS + itsdefined(ETOOMANYREFS); +#else + itsnotdefined(ETOOMANYREFS); +#endif +#ifdef ETIMEDOUT + itsdefined(ETIMEDOUT); +#else + itsnotdefined(ETIMEDOUT); +#endif +#ifdef ECONNREFUSED + itsdefined(ECONNREFUSED); +#else + itsnotdefined(ECONNREFUSED); +#endif +#ifdef EHOSTDOWN + itsdefined(EHOSTDOWN); +#else + itsnotdefined(EHOSTDOWN); +#endif +#ifdef EHOSTUNREACH + itsdefined(EHOSTUNREACH); +#else + itsnotdefined(EHOSTUNREACH); +#endif +#ifdef EALREADY + itsdefined(EALREADY); +#else + itsnotdefined(EALREADY); +#endif +#ifdef EINPROGRESS + itsdefined(EINPROGRESS); +#else + itsnotdefined(EINPROGRESS); +#endif +#ifdef ESTALE + itsdefined(ESTALE); +#else + itsnotdefined(ESTALE); +#endif +#ifdef EUCLEAN + itsdefined(EUCLEAN); +#else + itsnotdefined(EUCLEAN); +#endif +#ifdef ENOTNAM + itsdefined(ENOTNAM); +#else + itsnotdefined(ENOTNAM); +#endif +#ifdef ENAVAIL + itsdefined(ENAVAIL); +#else + itsnotdefined(ENAVAIL); +#endif +#ifdef EISNAM + itsdefined(EISNAM); +#else + itsnotdefined(EISNAM); +#endif +#ifdef EREMOTEIO + itsdefined(EREMOTEIO); +#else + itsnotdefined(EREMOTEIO); +#endif +#ifdef EDQUOT + itsdefined(EDQUOT); +#else + itsnotdefined(EDQUOT); +#endif +#ifdef ECANCELED + itsdefined(ECANCELED); +#else + itsnotdefined(ECANCELED); +#endif +#ifdef EKEYEXPIRED + itsdefined(EKEYEXPIRED); +#else + itsnotdefined(EKEYEXPIRED); +#endif +#ifdef EKEYREJECTED + itsdefined(EKEYREJECTED); +#else + itsnotdefined(EKEYREJECTED); +#endif +#ifdef EKEYREVOKED + itsdefined(EKEYREVOKED); +#else + itsnotdefined(EKEYREVOKED); +#endif +#ifdef EMEDIUMTYPE + itsdefined(EMEDIUMTYPE); +#else + itsnotdefined(EMEDIUMTYPE); +#endif +#ifdef ENOKEY + itsdefined(ENOKEY); +#else + itsnotdefined(ENOKEY); +#endif +#ifdef ENOMEDIUM + itsdefined(ENOMEDIUM); +#else + itsnotdefined(ENOMEDIUM); +#endif +#ifdef ENOTRECOVERABLE + itsdefined(ENOTRECOVERABLE); +#else + itsnotdefined(ENOTRECOVERABLE); +#endif +#ifdef EOWNERDEAD + itsdefined(EOWNERDEAD); +#else + itsnotdefined(EOWNERDEAD); +#endif +#ifdef ERFKILL + itsdefined(ERFKILL); +#else + itsnotdefined(ERFKILL); +#endif +#ifdef EAUTH + itsdefined(EAUTH); +#else + itsnotdefined(EAUTH); +#endif +#ifdef EBADRPC + itsdefined(EBADRPC); +#else + itsnotdefined(EBADRPC); +#endif +#ifdef EDOOFUS + itsdefined(EDOOFUS); +#else + itsnotdefined(EDOOFUS); +#endif +#ifdef EFTYPE + itsdefined(EFTYPE); +#else + itsnotdefined(EFTYPE); +#endif +#ifdef ENEEDAUTH + itsdefined(ENEEDAUTH); +#else + itsnotdefined(ENEEDAUTH); +#endif +#ifdef ENOATTR + itsdefined(ENOATTR); +#else + itsnotdefined(ENOATTR); +#endif +#ifdef ENOTSUP + itsdefined(ENOTSUP); +#else + itsnotdefined(ENOTSUP); +#endif +#ifdef EPROCLIM + itsdefined(EPROCLIM); +#else + itsnotdefined(EPROCLIM); +#endif +#ifdef EPROCUNAVAIL + itsdefined(EPROCUNAVAIL); +#else + itsnotdefined(EPROCUNAVAIL); +#endif +#ifdef EPROGMISMATCH + itsdefined(EPROGMISMATCH); +#else + itsnotdefined(EPROGMISMATCH); +#endif +#ifdef EPROGUNAVAIL + itsdefined(EPROGUNAVAIL); +#else + itsnotdefined(EPROGUNAVAIL); +#endif +#ifdef ERPCMISMATCH + itsdefined(ERPCMISMATCH); +#else + itsnotdefined(ERPCMISMATCH); +#endif +#ifdef EIPSEC + itsdefined(EIPSEC); +#else + itsnotdefined(EIPSEC); +#endif diff --git a/web/server/h2o/libh2o/deps/mruby-errno/src/known_errors_e2c.cstub b/web/server/h2o/libh2o/deps/mruby-errno/src/known_errors_e2c.cstub new file mode 100644 index 000000000..f203c3362 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/src/known_errors_e2c.cstub @@ -0,0 +1,435 @@ +#ifdef EPERM + { EPERM, NULL, }, +#endif +#ifdef ENOENT + { ENOENT, NULL, }, +#endif +#ifdef ESRCH + { ESRCH, NULL, }, +#endif +#ifdef EINTR + { EINTR, NULL, }, +#endif +#ifdef EIO + { EIO, NULL, }, +#endif +#ifdef ENXIO + { ENXIO, NULL, }, +#endif +#ifdef E2BIG + { E2BIG, NULL, }, +#endif +#ifdef ENOEXEC + { ENOEXEC, NULL, }, +#endif +#ifdef EBADF + { EBADF, NULL, }, +#endif +#ifdef ECHILD + { ECHILD, NULL, }, +#endif +#ifdef EAGAIN + { EAGAIN, NULL, }, +#endif +#ifdef ENOMEM + { ENOMEM, NULL, }, +#endif +#ifdef EACCES + { EACCES, NULL, }, +#endif +#ifdef EFAULT + { EFAULT, NULL, }, +#endif +#ifdef ENOTBLK + { ENOTBLK, NULL, }, +#endif +#ifdef EBUSY + { EBUSY, NULL, }, +#endif +#ifdef EEXIST + { EEXIST, NULL, }, +#endif +#ifdef EXDEV + { EXDEV, NULL, }, +#endif +#ifdef ENODEV + { ENODEV, NULL, }, +#endif +#ifdef ENOTDIR + { ENOTDIR, NULL, }, +#endif +#ifdef EISDIR + { EISDIR, NULL, }, +#endif +#ifdef EINVAL + { EINVAL, NULL, }, +#endif +#ifdef ENFILE + { ENFILE, NULL, }, +#endif +#ifdef EMFILE + { EMFILE, NULL, }, +#endif +#ifdef ENOTTY + { ENOTTY, NULL, }, +#endif +#ifdef ETXTBSY + { ETXTBSY, NULL, }, +#endif +#ifdef EFBIG + { EFBIG, NULL, }, +#endif +#ifdef ENOSPC + { ENOSPC, NULL, }, +#endif +#ifdef ESPIPE + { ESPIPE, NULL, }, +#endif +#ifdef EROFS + { EROFS, NULL, }, +#endif +#ifdef EMLINK + { EMLINK, NULL, }, +#endif +#ifdef EPIPE + { EPIPE, NULL, }, +#endif +#ifdef EDOM + { EDOM, NULL, }, +#endif +#ifdef ERANGE + { ERANGE, NULL, }, +#endif +#ifdef EDEADLK + { EDEADLK, NULL, }, +#endif +#ifdef ENAMETOOLONG + { ENAMETOOLONG, NULL, }, +#endif +#ifdef ENOLCK + { ENOLCK, NULL, }, +#endif +#ifdef ENOSYS + { ENOSYS, NULL, }, +#endif +#ifdef ENOTEMPTY + { ENOTEMPTY, NULL, }, +#endif +#ifdef ELOOP + { ELOOP, NULL, }, +#endif +#ifdef EWOULDBLOCK + { EWOULDBLOCK, NULL, }, +#endif +#ifdef ENOMSG + { ENOMSG, NULL, }, +#endif +#ifdef EIDRM + { EIDRM, NULL, }, +#endif +#ifdef ECHRNG + { ECHRNG, NULL, }, +#endif +#ifdef EL2NSYNC + { EL2NSYNC, NULL, }, +#endif +#ifdef EL3HLT + { EL3HLT, NULL, }, +#endif +#ifdef EL3RST + { EL3RST, NULL, }, +#endif +#ifdef ELNRNG + { ELNRNG, NULL, }, +#endif +#ifdef EUNATCH + { EUNATCH, NULL, }, +#endif +#ifdef ENOCSI + { ENOCSI, NULL, }, +#endif +#ifdef EL2HLT + { EL2HLT, NULL, }, +#endif +#ifdef EBADE + { EBADE, NULL, }, +#endif +#ifdef EBADR + { EBADR, NULL, }, +#endif +#ifdef EXFULL + { EXFULL, NULL, }, +#endif +#ifdef ENOANO + { ENOANO, NULL, }, +#endif +#ifdef EBADRQC + { EBADRQC, NULL, }, +#endif +#ifdef EBADSLT + { EBADSLT, NULL, }, +#endif +#ifdef EDEADLOCK + { EDEADLOCK, NULL, }, +#endif +#ifdef EBFONT + { EBFONT, NULL, }, +#endif +#ifdef ENOSTR + { ENOSTR, NULL, }, +#endif +#ifdef ENODATA + { ENODATA, NULL, }, +#endif +#ifdef ETIME + { ETIME, NULL, }, +#endif +#ifdef ENOSR + { ENOSR, NULL, }, +#endif +#ifdef ENONET + { ENONET, NULL, }, +#endif +#ifdef ENOPKG + { ENOPKG, NULL, }, +#endif +#ifdef EREMOTE + { EREMOTE, NULL, }, +#endif +#ifdef ENOLINK + { ENOLINK, NULL, }, +#endif +#ifdef EADV + { EADV, NULL, }, +#endif +#ifdef ESRMNT + { ESRMNT, NULL, }, +#endif +#ifdef ECOMM + { ECOMM, NULL, }, +#endif +#ifdef EPROTO + { EPROTO, NULL, }, +#endif +#ifdef EMULTIHOP + { EMULTIHOP, NULL, }, +#endif +#ifdef EDOTDOT + { EDOTDOT, NULL, }, +#endif +#ifdef EBADMSG + { EBADMSG, NULL, }, +#endif +#ifdef EOVERFLOW + { EOVERFLOW, NULL, }, +#endif +#ifdef ENOTUNIQ + { ENOTUNIQ, NULL, }, +#endif +#ifdef EBADFD + { EBADFD, NULL, }, +#endif +#ifdef EREMCHG + { EREMCHG, NULL, }, +#endif +#ifdef ELIBACC + { ELIBACC, NULL, }, +#endif +#ifdef ELIBBAD + { ELIBBAD, NULL, }, +#endif +#ifdef ELIBSCN + { ELIBSCN, NULL, }, +#endif +#ifdef ELIBMAX + { ELIBMAX, NULL, }, +#endif +#ifdef ELIBEXEC + { ELIBEXEC, NULL, }, +#endif +#ifdef EILSEQ + { EILSEQ, NULL, }, +#endif +#ifdef ERESTART + { ERESTART, NULL, }, +#endif +#ifdef ESTRPIPE + { ESTRPIPE, NULL, }, +#endif +#ifdef EUSERS + { EUSERS, NULL, }, +#endif +#ifdef ENOTSOCK + { ENOTSOCK, NULL, }, +#endif +#ifdef EDESTADDRREQ + { EDESTADDRREQ, NULL, }, +#endif +#ifdef EMSGSIZE + { EMSGSIZE, NULL, }, +#endif +#ifdef EPROTOTYPE + { EPROTOTYPE, NULL, }, +#endif +#ifdef ENOPROTOOPT + { ENOPROTOOPT, NULL, }, +#endif +#ifdef EPROTONOSUPPORT + { EPROTONOSUPPORT, NULL, }, +#endif +#ifdef ESOCKTNOSUPPORT + { ESOCKTNOSUPPORT, NULL, }, +#endif +#ifdef EOPNOTSUPP + { EOPNOTSUPP, NULL, }, +#endif +#ifdef EPFNOSUPPORT + { EPFNOSUPPORT, NULL, }, +#endif +#ifdef EAFNOSUPPORT + { EAFNOSUPPORT, NULL, }, +#endif +#ifdef EADDRINUSE + { EADDRINUSE, NULL, }, +#endif +#ifdef EADDRNOTAVAIL + { EADDRNOTAVAIL, NULL, }, +#endif +#ifdef ENETDOWN + { ENETDOWN, NULL, }, +#endif +#ifdef ENETUNREACH + { ENETUNREACH, NULL, }, +#endif +#ifdef ENETRESET + { ENETRESET, NULL, }, +#endif +#ifdef ECONNABORTED + { ECONNABORTED, NULL, }, +#endif +#ifdef ECONNRESET + { ECONNRESET, NULL, }, +#endif +#ifdef ENOBUFS + { ENOBUFS, NULL, }, +#endif +#ifdef EISCONN + { EISCONN, NULL, }, +#endif +#ifdef ENOTCONN + { ENOTCONN, NULL, }, +#endif +#ifdef ESHUTDOWN + { ESHUTDOWN, NULL, }, +#endif +#ifdef ETOOMANYREFS + { ETOOMANYREFS, NULL, }, +#endif +#ifdef ETIMEDOUT + { ETIMEDOUT, NULL, }, +#endif +#ifdef ECONNREFUSED + { ECONNREFUSED, NULL, }, +#endif +#ifdef EHOSTDOWN + { EHOSTDOWN, NULL, }, +#endif +#ifdef EHOSTUNREACH + { EHOSTUNREACH, NULL, }, +#endif +#ifdef EALREADY + { EALREADY, NULL, }, +#endif +#ifdef EINPROGRESS + { EINPROGRESS, NULL, }, +#endif +#ifdef ESTALE + { ESTALE, NULL, }, +#endif +#ifdef EUCLEAN + { EUCLEAN, NULL, }, +#endif +#ifdef ENOTNAM + { ENOTNAM, NULL, }, +#endif +#ifdef ENAVAIL + { ENAVAIL, NULL, }, +#endif +#ifdef EISNAM + { EISNAM, NULL, }, +#endif +#ifdef EREMOTEIO + { EREMOTEIO, NULL, }, +#endif +#ifdef EDQUOT + { EDQUOT, NULL, }, +#endif +#ifdef ECANCELED + { ECANCELED, NULL, }, +#endif +#ifdef EKEYEXPIRED + { EKEYEXPIRED, NULL, }, +#endif +#ifdef EKEYREJECTED + { EKEYREJECTED, NULL, }, +#endif +#ifdef EKEYREVOKED + { EKEYREVOKED, NULL, }, +#endif +#ifdef EMEDIUMTYPE + { EMEDIUMTYPE, NULL, }, +#endif +#ifdef ENOKEY + { ENOKEY, NULL, }, +#endif +#ifdef ENOMEDIUM + { ENOMEDIUM, NULL, }, +#endif +#ifdef ENOTRECOVERABLE + { ENOTRECOVERABLE, NULL, }, +#endif +#ifdef EOWNERDEAD + { EOWNERDEAD, NULL, }, +#endif +#ifdef ERFKILL + { ERFKILL, NULL, }, +#endif +#ifdef EAUTH + { EAUTH, NULL, }, +#endif +#ifdef EBADRPC + { EBADRPC, NULL, }, +#endif +#ifdef EDOOFUS + { EDOOFUS, NULL, }, +#endif +#ifdef EFTYPE + { EFTYPE, NULL, }, +#endif +#ifdef ENEEDAUTH + { ENEEDAUTH, NULL, }, +#endif +#ifdef ENOATTR + { ENOATTR, NULL, }, +#endif +#ifdef ENOTSUP + { ENOTSUP, NULL, }, +#endif +#ifdef EPROCLIM + { EPROCLIM, NULL, }, +#endif +#ifdef EPROCUNAVAIL + { EPROCUNAVAIL, NULL, }, +#endif +#ifdef EPROGMISMATCH + { EPROGMISMATCH, NULL, }, +#endif +#ifdef EPROGUNAVAIL + { EPROGUNAVAIL, NULL, }, +#endif +#ifdef ERPCMISMATCH + { ERPCMISMATCH, NULL, }, +#endif +#ifdef EIPSEC + { EIPSEC, NULL, }, +#endif diff --git a/web/server/h2o/libh2o/deps/mruby-errno/test/errno.rb b/web/server/h2o/libh2o/deps/mruby-errno/test/errno.rb new file mode 100644 index 000000000..790311566 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-errno/test/errno.rb @@ -0,0 +1,60 @@ +assert('Errno') do + Errno.class == Module +end + +assert('SystemCallError') do + SystemCallError.class == Class +end + +assert('SystemCallError superclass') do + SystemCallError.superclass == StandardError +end + +assert('SystemCallError#initialize') do + SystemCallError.new("a").message == "unknown error - a" and + SystemCallError.new("a", 12345).message == "Unknown error: 12345 - a" and + SystemCallError.new(12345).message == "Unknown error: 12345" +end + +assert('SystemCallError#errno') do + assert_equal 1, SystemCallError.new("a", 1).errno + assert_equal 1, SystemCallError.new(1).errno + assert_equal 12345, SystemCallError.new("a", 12345).errno + assert_equal 23456, SystemCallError.new(23456).errno +end + +assert('SystemCallError#inspect') do + SystemCallError.new("a").inspect == "SystemCallError: unknown error - a" + end + +assert('Errno::NOERROR') do + Errno::NOERROR.class == Class +end + +# Is there any platform does not have EPERM? +assert('Errno::EPERM') do + Errno::EPERM.class == Class +end + +assert('Errno::EPERM superclass') do + Errno::EPERM.superclass == SystemCallError +end + +assert('Errno::EPERM::Errno') do + Errno::EPERM::Errno.is_a? Fixnum +end + +assert('Errno::EPERM#message') do + msg = Errno::EPERM.new.message + Errno::EPERM.new("a").message == "#{msg} - a" +end + +assert('Errno::EPERM#inspect 1') do + msg = Errno::EPERM.new.message + Errno::EPERM.new.inspect == "Errno::EPERM: #{msg}" +end + +assert('Errno::EPERM#inspect 2') do + msg = Errno::EPERM.new.message + Errno::EPERM.new("a").inspect == "Errno::EPERM: #{msg} - a" +end diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/.gitignore b/web/server/h2o/libh2o/deps/mruby-file-stat/.gitignore new file mode 100644 index 000000000..415be3546 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/.gitignore @@ -0,0 +1,5 @@ +*.o +autom4te.cache/ +*.log +config.status +config.h diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/.travis.yml b/web/server/h2o/libh2o/deps/mruby-file-stat/.travis.yml new file mode 100644 index 000000000..e630dcb18 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/.travis.yml @@ -0,0 +1,15 @@ +language: c +compiler: + - gcc + - clang +before_install: + - sudo apt-get -qq update +install: + - sudo apt-get -qq install rake bison git gperf +before_script: + - cd ../ + - git clone https://github.com/mruby/mruby.git + - cd mruby + - cp -fp ../mruby-file-stat/.travis_build_config.rb build_config.rb +script: + - ruby minirake all test diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/.travis_build_config.rb b/web/server/h2o/libh2o/deps/mruby-file-stat/.travis_build_config.rb new file mode 100644 index 000000000..623303eb4 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/.travis_build_config.rb @@ -0,0 +1,7 @@ +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + conf.enable_test + + conf.gem '../mruby-file-stat' +end diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/README.md b/web/server/h2o/libh2o/deps/mruby-file-stat/README.md new file mode 100644 index 000000000..ebf7cec37 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/README.md @@ -0,0 +1,82 @@ +# mruby-file-stat + +[![Build Status](https://travis-ci.org/ksss/mruby-file-stat.svg?branch=master)](https://travis-ci.org/ksss/mruby-file-stat) +[![Build status](https://ci.appveyor.com/api/projects/status/04am84uda2cj49n3/branch/master?svg=true)](https://ci.appveyor.com/project/ksss/mruby-file-stat/branch/master) + +**File::Stat** class in mruby + +```ruby +stat = File::Stat.new('filename') # or File.stat('filename') +stat.dev #=> device id +stat.dev_major #=> device major id +stat.dev_minor #=> device minor id +stat.ino #=> i-node number +stat.mode #=> permission value (st_mode) +stat.nlink #=> hard link count +stat.uid #=> user id +stat.gid #=> group id +stat.rdev #=> device type +stat.rdev_major #=> rdev major id +stat.rdev_minor #=> rdev minor id +stat.atime #=> last access time +stat.mtime #=> last modify time +stat.ctime #=> last change attribute time +stat.birthtime #=> file created time +stat.size #=> file size(byte) +stat.blksize #=> file I/O block size +stat.blocks #=> attached block num +stat.grpowned #=> same gid? +stat.<=> #=> comparate mtime (-1,0,1 or nil) +stat.size? +stat.zero? +stat.symlink? +stat.file? +stat.directory? +stat.chardev? +stat.blockdev? +stat.pipe? +stat.socket? +stat.owned? +stat.owned_real? +stat.readable? +stat.readable_real? +stat.writable? +stat.writable_real? +stat.executable? +stat.executable_real? +stat.world_readable? +stat.world_writable? +stat.setuid? +stat.setgid? +stat.sticky? +stat.ftype #=> socket, link, file, blockSpecial, directory, characterSpecial, fifo or unknown +``` + +This library is wrap of struct stat. + +## Installation + +### use github repository + +Write in /mruby/build_config.rb + +```ruby +MRuby::Build.new do |conf| + # by mgem + conf.gem :mgem => 'mruby-file-stat' + # by github + conf.gem :github => 'ksss/mruby-file-stat', :branch => 'master' +end +``` + +## Homepage + +https://github.com/ksss/mruby-file-stat + +## License + +See [https://github.com/ruby/ruby/blob/trunk/file.c](https://github.com/ruby/ruby/blob/trunk/file.c) + +## Doc + +[http://ruby-doc.org/core-2.1.5/File/Stat.html](http://ruby-doc.org/core-2.1.5/File/Stat.html) diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/appveyor.yml b/web/server/h2o/libh2o/deps/mruby-file-stat/appveyor.yml new file mode 100644 index 000000000..f47afa996 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/appveyor.yml @@ -0,0 +1,19 @@ +--- +version: "#{build}" +environment: + MRUBY_CONFIG: "C:/projects/mruby-file-stat/.travis_build_config.rb" + matrix: + - Compiler: mingw + +install: + - SET PATH=C:\Ruby%ruby_version%\bin;%PATH% + - set PATH=C:\MinGW\bin;C:\MinGW\msys\1.0\bin;%PATH% + - ruby --version + - gem --version + - gcc --version + - gem install rake --force + - cd .. + - git clone --depth 1 https://github.com/mruby/mruby.git + - cd mruby +build_script: + - ruby minirake all test --trace --verbose diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/config.h.in b/web/server/h2o/libh2o/deps/mruby-file-stat/config.h.in new file mode 100644 index 000000000..27cc7e6fa --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/config.h.in @@ -0,0 +1,19 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if your system has a working `getgroups' function. */ +#undef HAVE_GETGROUPS + +/* Define to 1 if you have the `lstat' function. */ +#undef HAVE_LSTAT + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_BLKSIZE + +/* Define to 1 if `st_blocks' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_BLOCKS + +/* Define to 1 if `st_rdev' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_RDEV + +/* Define to 1 if `st_birthtimespec' is a member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/configure b/web/server/h2o/libh2o/deps/mruby-file-stat/configure new file mode 100755 index 000000000..517c66c49 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/configure @@ -0,0 +1,4320 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="src/file-stat.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval \${$4+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$4 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_member + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case <limits.h> declares $2. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_config_headers="$ac_config_headers config.h" + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" +if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 +_ACEOF + + +fi + +ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" +if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 +_ACEOF + + +fi + +ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" +if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_RDEV 1 +_ACEOF + + +fi + +ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtimespec" "ac_cv_member_struct_stat_st_birthtimespec" "$ac_includes_default" +if test "x$ac_cv_member_struct_stat_st_birthtimespec" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC 1 +_ACEOF + + +fi + + +for ac_func in getgroups +do : + ac_fn_c_check_func "$LINENO" "getgroups" "ac_cv_func_getgroups" +if test "x$ac_cv_func_getgroups" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETGROUPS 1 +_ACEOF + +fi +done + +for ac_func in lstat +do : + ac_fn_c_check_func "$LINENO" "lstat" "ac_cv_func_lstat" +if test "x$ac_cv_func_lstat" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LSTAT 1 +_ACEOF + +fi +done + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/configure.ac b/web/server/h2o/libh2o/deps/mruby-file-stat/configure.ac new file mode 100644 index 000000000..ce6be3fad --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/configure.ac @@ -0,0 +1,20 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.69]) +AC_INIT() + +AC_PROG_CC + +AC_CONFIG_SRCDIR([src/file-stat.c]) +AC_CONFIG_HEADERS([config.h]) + +AC_CHECK_MEMBERS([struct stat.st_blksize]) +AC_CHECK_MEMBERS([struct stat.st_blocks]) +AC_CHECK_MEMBERS([struct stat.st_rdev]) +AC_CHECK_MEMBERS([struct stat.st_birthtimespec]) + +AC_CHECK_FUNCS(getgroups) +AC_CHECK_FUNCS(lstat) + +AC_OUTPUT diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-file-stat/mrbgem.rake new file mode 100644 index 000000000..ff7d076b8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/mrbgem.rake @@ -0,0 +1,32 @@ +MRuby::Gem::Specification.new('mruby-file-stat') do |spec| + spec.license = 'MIT' + spec.author = 'ksss <co000ri@gmail.com>' + spec.add_dependency('mruby-time') + + env = { + 'CC' => "#{build.cc.command} #{build.cc.flags.join(' ')}", + 'CXX' => "#{build.cxx.command} #{build.cxx.flags.join(' ')}", + 'LD' => "#{build.linker.command} #{build.linker.flags.join(' ')}", + 'AR' => build.archiver.command + } + config = "#{build_dir}/config.h" + + file config do + FileUtils.mkdir_p build_dir, :verbose => true + Dir.chdir build_dir do + if ENV['OS'] == 'Windows_NT' + _pp 'on Windows', dir + FileUtils.touch "#{build_dir}/config.h", :verbose => true + else + _pp './configure', dir + system env, "#{dir}/configure" + end + end + end + file "#{dir}/src/file-stat.c" => config + task :clean do + FileUtils.rm_f config, :verbose => true + end + + cc.include_paths << build_dir +end diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/mrblib/ext.rb b/web/server/h2o/libh2o/deps/mruby-file-stat/mrblib/ext.rb new file mode 100644 index 000000000..1fda18697 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/mrblib/ext.rb @@ -0,0 +1,5 @@ +class File + def self.stat(fname) + File::Stat.new(fname) + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/mrblib/file-stat.rb b/web/server/h2o/libh2o/deps/mruby-file-stat/mrblib/file-stat.rb new file mode 100644 index 000000000..23ded179e --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/mrblib/file-stat.rb @@ -0,0 +1,52 @@ +class File + class Stat + include Comparable + + def <=>(other) + if other.kind_of?(self.class) + self.mtime <=> other.mtime + else + nil + end + end + + def inspect + _dev = dev + _dev = "0x#{_dev.to_s(16)}" if _dev.kind_of?(Fixnum) + _mode = mode + _mode = "0#{_mode.to_s(8)}" if _mode.kind_of?(Fixnum) + _rdev = rdev + _rdev = "0x#{_rdev.to_s(16)}" if _rdev.kind_of?(Fixnum) + + stats = { + 'dev' => _dev, + 'ino' => ino, + 'mode' => _mode, + 'nlink' => nlink, + 'uid' => uid, + 'gid' => gid, + 'rdev' => _rdev, + 'size' => size, + 'blksize' => blksize, + 'blocks' => blocks, + 'atime' => atime, + 'mtime' => mtime, + 'ctime' => ctime, + } + if respond_to? :birthtime + stats['birthtime'] = birthtime + end + + "#<#{self.class.to_s} #{stats.map{|k, v| "#{k}=#{v}"}.join(', ')}>" + end + + def size? + s = size + s == 0 ? nil : s + end + + def zero? + size == 0 + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/src/file-stat.c b/web/server/h2o/libh2o/deps/mruby-file-stat/src/file-stat.c new file mode 100644 index 000000000..f36ed197f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/src/file-stat.c @@ -0,0 +1,873 @@ +/** + * original is https://github.com/ruby/ruby/blob/trunk/file.c + */ + +#include "mruby.h" +#include "mruby/string.h" +#include "mruby/data.h" +#include "mruby/error.h" +#include "mruby/class.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + +#if defined(_WIN32) || defined(_WIN64) + +#if !defined S_IXUSR && !defined __MINGW32__ +# define S_IXUSR 0100 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0010 +#endif +#ifndef S_IXOTH +# define S_IXOTH 0001 +#endif + +#else +#include <unistd.h> +#endif + +#ifndef S_IRUGO +# define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH) +#endif + +#ifndef S_IWUGO +# define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) +#endif + +#ifndef S_IXUGO +# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) +#endif + +#ifndef S_ISLNK +# ifdef _S_ISLNK +# define S_ISLNK(m) _S_ISLNK(m) +# else +# ifdef _S_IFLNK +# define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK) +# else +# ifdef S_IFLNK +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +# endif +# endif +# endif +#endif + +#ifdef S_IFIFO +# ifndef S_ISFIFO +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# endif +#endif + +#ifndef S_ISSOCK +# ifdef _S_ISSOCK +# define S_ISSOCK(m) _S_ISSOCK(m) +# else +# ifdef _S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK) +# else +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# endif +# endif +# endif +#endif + +#ifndef S_ISBLK +# ifdef S_IFBLK +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +# else +# define S_ISBLK(m) (0) /* anytime false */ +# endif +#endif + +#ifndef S_ISCHR +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif + +#ifndef S_ISREG +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +#ifndef S_ISDIR +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +#include "config.h" + +#define STAT(p,s) stat(p,s) +#ifdef HAVE_LSTAT +# define LSTAT(p,s) lstat(p,s) +#else +# define LSTAT(p,s) stat(p,s) +#endif +#define MRB_MAX_GROUPS (65536) + +#if defined(_WIN32) || defined(_WIN64) +typedef unsigned int uid_t; +typedef unsigned int gid_t; +uid_t +getuid(void) +{ + return 0; +} +uid_t +geteuid(void) +{ + return 0; +} +gid_t +getgid(void) +{ + return 0; +} +gid_t +getegid(void) +{ + return 0; +} +#endif +#define GETGROUPS_T gid_t + +#if defined(S_IXGRP) && !defined(_WIN32) && !defined(__CYGWIN__) +# define USE_GETEUID 1 +#endif + +#ifdef __native_client__ +# undef USE_GETEUID +#endif + +struct mrb_data_type mrb_stat_type = { "File::Stat", mrb_free }; + +static struct stat * +mrb_stat_alloc(mrb_state *mrb) +{ + return (struct stat *)mrb_malloc(mrb, sizeof(struct stat)); +} + +static mrb_value +file_s_lstat(mrb_state *mrb, mrb_value klass) +{ + struct RClass *file_class; + struct RClass *stat_class; + struct stat st, *ptr; + mrb_value fname, tmp; + char *path; + + mrb_get_args(mrb, "o", &fname); + + tmp = mrb_check_convert_type(mrb, fname, MRB_TT_STRING, "String", "to_path"); + if (mrb_nil_p(tmp)) { + tmp = mrb_convert_type(mrb, fname, MRB_TT_STRING, "String", "to_str"); + } + path = mrb_str_to_cstr(mrb, tmp); + if (LSTAT(path, &st) == -1) { + mrb_sys_fail(mrb, path); + } + + file_class = mrb_class_ptr(klass); + stat_class = mrb_class_get_under(mrb, file_class, "Stat"); + ptr = mrb_stat_alloc(mrb); + *ptr = st; + + return mrb_obj_value(Data_Wrap_Struct(mrb, stat_class, &mrb_stat_type, ptr)); +} + +static mrb_value +stat_initialize(mrb_state *mrb, mrb_value self) +{ + struct stat st, *ptr; + mrb_value fname, tmp; + char *path; + + mrb_get_args(mrb, "o", &fname); + + tmp = mrb_check_convert_type(mrb, fname, MRB_TT_STRING, "String", "to_path"); + if (mrb_nil_p(tmp)) { + tmp = mrb_convert_type(mrb, fname, MRB_TT_STRING, "String", "to_str"); + } + path = mrb_str_to_cstr(mrb, tmp); + if (STAT(path, &st) == -1) { + mrb_sys_fail(mrb, path); + } + + ptr = (struct stat *)DATA_PTR(self); + if (ptr) { + mrb_free(mrb, ptr); + } + + ptr = mrb_stat_alloc(mrb); + *ptr = st; + + DATA_TYPE(self) = &mrb_stat_type; + DATA_PTR(self) = ptr; + + return mrb_nil_value(); +} + +static mrb_value +stat_initialize_copy(mrb_state *mrb, mrb_value copy) +{ + mrb_value orig; + + mrb_get_args(mrb, "o", &orig); + + if (mrb_obj_equal(mrb, copy, orig)) return copy; + + if (!mrb_obj_is_instance_of(mrb, orig, mrb_obj_class(mrb, copy))) { + mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); + } + + if (DATA_PTR(copy)) { + mrb_free(mrb, DATA_PTR(copy)); + DATA_PTR(copy) = 0; + } + + if (DATA_PTR(orig)) { + DATA_PTR(copy) = mrb_malloc(mrb, sizeof(struct stat)); + DATA_TYPE(copy) = &mrb_stat_type; + *(struct stat *)DATA_PTR(copy) = *(struct stat *)DATA_PTR(orig); + } + return copy; +} + +static struct stat * +get_stat(mrb_state *mrb, mrb_value self) +{ + struct stat *st; + + st = (struct stat *)mrb_data_get_ptr(mrb, self, &mrb_stat_type); + if (!st) mrb_raise(mrb, E_TYPE_ERROR, "uninitialized File::Stat"); + return st; +} + +static mrb_value +mrb_ll2num(mrb_state *mrb, long long t) +{ + if (MRB_INT_MIN <= t && t <= MRB_INT_MAX) { + return mrb_fixnum_value((mrb_int)t); + } else { + return mrb_float_value(mrb, (mrb_float)t); + } +} + +static mrb_value +io_stat(mrb_state *mrb, mrb_value self) +{ + struct RClass *file_class; + struct RClass *stat_class; + struct stat st, *ptr; + mrb_value fileno; + + if (mrb_respond_to(mrb, self, mrb_intern_lit(mrb, "fileno"))) { + fileno = mrb_funcall(mrb, self, "fileno", 0); + } + else { + mrb_raise(mrb, E_NOTIMP_ERROR, "`fileno' is not implemented"); + } + + if (fstat(mrb_fixnum(fileno), &st) == -1) { + mrb_sys_fail(mrb, "fstat"); + } + + file_class = mrb_class_get(mrb, "File"); + stat_class = mrb_class_get_under(mrb, file_class, "Stat"); + ptr = mrb_stat_alloc(mrb); + *ptr = st; + + return mrb_obj_value(Data_Wrap_Struct(mrb, stat_class, &mrb_stat_type, ptr)); +} + +static mrb_value +stat_dev(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(get_stat(mrb, self)->st_dev); +} + +static mrb_value +stat_dev_major(mrb_state *mrb, mrb_value self) +{ +#if defined(major) + return mrb_fixnum_value(major(get_stat(mrb, self)->st_dev)); +#else + return mrb_nil_value(); // NotImplemented +#endif +} + +static mrb_value +stat_dev_minor(mrb_state *mrb, mrb_value self) +{ +#if defined(minor) + return mrb_fixnum_value(minor(get_stat(mrb, self)->st_dev)); +#else + return mrb_nil_value(); // NotImplemented +#endif +} + +static mrb_value +stat_ino(mrb_state *mrb, mrb_value self) +{ + return mrb_ll2num(mrb, get_stat(mrb, self)->st_ino); +} + +static mrb_value +stat_mode(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(get_stat(mrb, self)->st_mode); +} + +static mrb_value +stat_nlink(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(get_stat(mrb, self)->st_nlink); +} + +static mrb_value +stat_uid(mrb_state *mrb, mrb_value self) +{ + return mrb_ll2num(mrb, get_stat(mrb, self)->st_uid); +} + +static mrb_value +stat_gid(mrb_state *mrb, mrb_value self) +{ + return mrb_ll2num(mrb, get_stat(mrb, self)->st_gid); +} + +static mrb_value +stat_rdev(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(get_stat(mrb, self)->st_rdev); +} + +static mrb_value +stat_rdev_major(mrb_state *mrb, mrb_value self) +{ +#if defined(major) + return mrb_fixnum_value(major(get_stat(mrb, self)->st_rdev)); +#else + return mrb_nil_value(); // NotImplemented +#endif +} + +static mrb_value +stat_rdev_minor(mrb_state *mrb, mrb_value self) +{ +#if defined(minor) + return mrb_fixnum_value(minor(get_stat(mrb, self)->st_rdev)); +#else + return mrb_nil_value(); // NotImplemented +#endif +} + +static mrb_value +time_at_with_sec(mrb_state *mrb, long long sec) +{ + return mrb_funcall(mrb, mrb_obj_value(mrb_class_get(mrb, "Time")), "at", 1, mrb_ll2num(mrb, sec)); +} + +static mrb_value +stat_atime(mrb_state *mrb, mrb_value self) +{ + return time_at_with_sec(mrb, get_stat(mrb, self)->st_atime); +} + +static mrb_value +stat_mtime(mrb_state *mrb, mrb_value self) +{ + return time_at_with_sec(mrb, get_stat(mrb, self)->st_mtime); +} + +static mrb_value +stat_ctime(mrb_state *mrb, mrb_value self) +{ + return time_at_with_sec(mrb, get_stat(mrb, self)->st_ctime); +} + +#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) +static mrb_value +stat_birthtime(mrb_state *mrb, mrb_value self) +{ + return time_at_with_sec(mrb, get_stat(mrb, self)->st_birthtimespec.tv_sec); +} +# define HAVE_METHOD_BIRTHTIME 1 +#elif defined(_WIN32) +# define stat_birthtime stat_ctime +# define HAVE_METHOD_BIRTHTIME 1 +#endif + +static mrb_value +stat_size(mrb_state *mrb, mrb_value self) +{ + return mrb_ll2num(mrb, get_stat(mrb, self)->st_size); +} + +static mrb_value +stat_blksize(mrb_state *mrb, mrb_value self) +{ +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + return mrb_fixnum_value(get_stat(mrb, self)->st_blksize); +#else + return mrb_nil_value(); +#endif +} + +static mrb_value +stat_blocks(mrb_state *mrb, mrb_value self) +{ +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + return mrb_ll2num(mrb, get_stat(mrb, self)->st_blocks); +#else + return mrb_nil_value(); +#endif +} + +static int +mrb_group_member(mrb_state *mrb, GETGROUPS_T gid) +{ +#if defined(_WIN32) || !defined(HAVE_GETGROUPS) + return FALSE; +#else + int rv = FALSE; + int groups = 16; + GETGROUPS_T *gary = NULL; + int anum = -1; + + if (getgid() == gid || getegid() == gid) + return TRUE; + + /* + * On Mac OS X (Mountain Lion), NGROUPS is 16. But libc and kernel + * accept more larger value. + * So we don't trunk NGROUPS anymore. + */ + while (groups <= MRB_MAX_GROUPS) { + gary = (GETGROUPS_T*)mrb_malloc(mrb, sizeof(GETGROUPS_T) * (unsigned int)groups); + anum = getgroups(groups, gary); + if (anum != -1 && anum != groups) + break; + groups *= 2; + if (gary) { + mrb_free(mrb, gary); + gary = 0; + } + } + if (anum == -1) + return FALSE; + + while (--anum >= 0) { + if (gary[anum] == gid) { + rv = TRUE; + break; + } + } + + if (gary) { + mrb_free(mrb, gary); + } + return rv; +#endif +} + +static mrb_value +stat_grpowned_p(mrb_state *mrb, mrb_value self) +{ +#ifndef _WIN32 + if (mrb_group_member(mrb, get_stat(mrb, self)->st_gid)) return mrb_true_value(); +#endif + return mrb_false_value(); +} + +static mrb_value +stat_readable_p(mrb_state *mrb, mrb_value self) +{ + struct stat *st; +#ifdef USE_GETEUID + if (geteuid() == 0) + return mrb_true_value(); +#endif + st = get_stat(mrb, self); +#ifdef S_IRUSR + if (st->st_uid == geteuid()) + return st->st_mode & S_IRUSR ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IRGRP + if (mrb_group_member(mrb, st->st_gid)) + return st->st_mode & S_IRGRP ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IROTH + if (!(st->st_mode & S_IROTH)) + return mrb_false_value(); +#endif + return mrb_true_value(); +} + +static mrb_value +stat_readable_real_p(mrb_state *mrb, mrb_value self) +{ + struct stat *st; + +#ifdef USE_GETEUID + if (getuid() == 0) + return mrb_true_value(); +#endif + st = get_stat(mrb, self); +#ifdef S_IRUSR + if (st->st_uid == getuid()) + return st->st_mode & S_IRUSR ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IRGRP + if (mrb_group_member(mrb, st->st_gid)) + return st->st_mode & S_IRGRP ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IROTH + if (!(st->st_mode & S_IROTH)) return mrb_false_value(); +#endif + return mrb_true_value(); +} + +static mrb_value +stat_world_readable_p(mrb_state *mrb, mrb_value self) +{ +#ifdef S_IROTH + struct stat *st = get_stat(mrb, self); + if ((st->st_mode & (S_IROTH)) == S_IROTH) { + return mrb_fixnum_value(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO)); + } + else { + return mrb_nil_value(); + } +#else + return mrb_nil_value(); +#endif +} + + +static mrb_value +stat_writable_p(mrb_state *mrb, mrb_value self) +{ + struct stat *st; + +#ifdef USE_GETEUID + if (geteuid() == 0) + return mrb_true_value(); +#endif + st = get_stat(mrb, self); +#ifdef S_IWUSR + if (st->st_uid == geteuid()) + return st->st_mode & S_IWUSR ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IWGRP + if (mrb_group_member(mrb, st->st_gid)) + return st->st_mode & S_IWGRP ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IWOTH + if (!(st->st_mode & S_IWOTH)) + return mrb_false_value(); +#endif + return mrb_true_value(); +} + +static mrb_value +stat_writable_real_p(mrb_state *mrb, mrb_value self) +{ + struct stat *st; + +#ifdef USE_GETEUID + if (getuid() == 0) + return mrb_true_value(); +#endif + st = get_stat(mrb, self); +#ifdef S_IWUSR + if (st->st_uid == getuid()) + return st->st_mode & S_IWUSR ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IWGRP + if (mrb_group_member(mrb, st->st_gid)) + return st->st_mode & S_IWGRP ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IWOTH + if (!(st->st_mode & S_IWOTH)) return mrb_false_value(); +#endif + return mrb_true_value(); +} + +static mrb_value +stat_world_writable_p(mrb_state *mrb, mrb_value self) +{ +#ifdef S_IROTH + struct stat *st = get_stat(mrb, self); + if ((st->st_mode & (S_IROTH)) == S_IROTH) { + return mrb_fixnum_value(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO)); + } + else { + return mrb_nil_value(); + } +#else + return mrb_nil_value(); +#endif +} + +static mrb_value +stat_executable_p(mrb_state *mrb, mrb_value self) +{ + struct stat *st = get_stat(mrb, self); + +#ifdef USE_GETEUID + if (geteuid() == 0) { + return st->st_mode & S_IXUGO ? mrb_true_value() : mrb_false_value(); +} +#endif +#ifdef S_IXUSR + if (st->st_uid == geteuid()) + return st->st_mode & S_IXUSR ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IXGRP + if (mrb_group_member(mrb, st->st_gid)) + return st->st_mode & S_IXGRP ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IXOTH + if (!(st->st_mode & S_IXOTH)) + return mrb_false_value(); +#endif + return mrb_true_value(); +} + +static mrb_value +stat_executable_real_p(mrb_state *mrb, mrb_value self) +{ + struct stat *st = get_stat(mrb, self); + +#ifdef USE_GETEUID + if (getuid() == 0) + return st->st_mode & S_IXUGO ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IXUSR + if (st->st_uid == getuid()) + return st->st_mode & S_IXUSR ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IXGRP + if (mrb_group_member(mrb, st->st_gid)) + return st->st_mode & S_IXGRP ? mrb_true_value() : mrb_false_value(); +#endif +#ifdef S_IXOTH + if (!(st->st_mode & S_IXOTH)) return mrb_false_value(); +#endif + return mrb_true_value(); +} + +static mrb_value +stat_symlink_p(mrb_state *mrb, mrb_value self) +{ +#ifdef S_ISLNK + if (S_ISLNK(get_stat(mrb, self)->st_mode)) + return mrb_true_value(); +#endif + return mrb_false_value(); +} + +static mrb_value +stat_file_p(mrb_state *mrb, mrb_value self) +{ + if (S_ISREG(get_stat(mrb, self)->st_mode)) + return mrb_true_value(); + return mrb_false_value(); +} + +static mrb_value +stat_directory_p(mrb_state *mrb, mrb_value self) +{ + if (S_ISDIR(get_stat(mrb, self)->st_mode)) + return mrb_true_value(); + return mrb_false_value(); +} + +static mrb_value +stat_chardev_p(mrb_state *mrb, mrb_value self) +{ + if (S_ISCHR(get_stat(mrb, self)->st_mode)) + return mrb_true_value(); + return mrb_false_value(); +} + +static mrb_value +stat_blockdev_p(mrb_state *mrb, mrb_value self) +{ +#ifdef S_ISBLK + if (S_ISBLK(get_stat(mrb, self)->st_mode)) + return mrb_true_value(); +#endif + return mrb_false_value(); +} + +static mrb_value +stat_pipe_p(mrb_state *mrb, mrb_value self) +{ +#ifdef S_ISFIFO + if (S_ISFIFO(get_stat(mrb, self)->st_mode)) + return mrb_true_value(); +#endif + return mrb_false_value(); +} + +static mrb_value +stat_socket_p(mrb_state *mrb, mrb_value self) +{ +#ifdef S_ISSOCK + if (S_ISSOCK(get_stat(mrb, self)->st_mode)) + return mrb_true_value(); +#endif + return mrb_false_value(); +} + +static mrb_value +stat_setuid_p(mrb_state *mrb, mrb_value self) +{ +#ifdef S_ISUID + if (get_stat(mrb, self)->st_mode & S_ISUID) + return mrb_true_value(); +#endif + return mrb_false_value(); +} + +static mrb_value +stat_setgid_p(mrb_state *mrb, mrb_value self) +{ +#ifdef S_ISGID + if (get_stat(mrb, self)->st_mode & S_ISGID) + return mrb_true_value(); +#endif + return mrb_false_value(); +} + +static mrb_value +stat_sticky_p(mrb_state *mrb, mrb_value self) +{ +#ifdef S_ISVTX + if (get_stat(mrb, self)->st_mode & S_ISVTX) + return mrb_true_value(); +#endif + return mrb_false_value(); +} + +static mrb_value +stat_ftype(mrb_state *mrb, mrb_value self) +{ + struct stat *st = get_stat(mrb, self); + const char *t; + + if (S_ISREG(st->st_mode)) { + t = "file"; + } + else if (S_ISDIR(st->st_mode)) { + t = "directory"; + } + else if (S_ISCHR(st->st_mode)) { + t = "characterSpecial"; + } +#ifdef S_ISBLK + else if (S_ISBLK(st->st_mode)) { + t = "blockSpecial"; + } +#endif +#ifdef S_ISFIFO + else if (S_ISFIFO(st->st_mode)) { + t = "fifo"; + } +#endif +#ifdef S_ISLNK + else if (S_ISLNK(st->st_mode)) { + t = "link"; + } +#endif +#ifdef S_ISSOCK + else if (S_ISSOCK(st->st_mode)) { + t = "socket"; + } +#endif + else { + t = "unknown"; + } + return mrb_str_new_static(mrb, t, (size_t)strlen(t)); +} + +static mrb_value +stat_owned_p(mrb_state *mrb, mrb_value self) +{ + return get_stat(mrb, self)->st_uid == geteuid() ? mrb_true_value() : mrb_false_value(); +} + +static mrb_value +stat_owned_real_p(mrb_state *mrb, mrb_value self) +{ + return get_stat(mrb, self)->st_uid == getuid() ? mrb_true_value() : mrb_false_value(); +} + +void +mrb_mruby_file_stat_gem_init(mrb_state* mrb) +{ + struct RClass *io = mrb_define_class(mrb, "IO", mrb->object_class); + struct RClass *file = mrb_define_class(mrb, "File", io); + struct RClass *stat = mrb_define_class_under(mrb, file, "Stat", mrb->object_class); + + MRB_SET_INSTANCE_TT(stat, MRB_TT_DATA); + + mrb_define_method(mrb, io, "stat", io_stat, MRB_ARGS_NONE()); + + mrb_define_class_method(mrb, file, "lstat", file_s_lstat, MRB_ARGS_REQ(1)); + + mrb_define_method(mrb, stat, "initialize", stat_initialize, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, stat, "initialize_copy", stat_initialize_copy, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, stat, "dev", stat_dev, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "dev_major", stat_dev_major, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "dev_minor", stat_dev_minor, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "ino", stat_ino, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "mode", stat_mode, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "nlink", stat_nlink, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "uid", stat_uid, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "gid", stat_gid, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "rdev", stat_rdev, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "rdev_major", stat_rdev_major, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "rdev_minor", stat_rdev_minor, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "atime", stat_atime, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "mtime", stat_mtime, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "ctime", stat_ctime, MRB_ARGS_NONE()); +#ifdef HAVE_METHOD_BIRTHTIME + mrb_define_method(mrb, stat, "birthtime", stat_birthtime, MRB_ARGS_NONE()); +#endif + mrb_define_method(mrb, stat, "size", stat_size, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "blksize", stat_blksize, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "blocks", stat_blocks, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "grpowned?", stat_grpowned_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "readable?", stat_readable_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "readable_real?", stat_readable_real_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "world_readable?", stat_world_readable_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "writable?", stat_writable_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "writable_real?", stat_writable_real_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "world_writable?", stat_world_writable_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "executable?", stat_executable_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "executable_real?", stat_executable_real_p, MRB_ARGS_NONE()); + + mrb_define_method(mrb, stat, "symlink?", stat_symlink_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "file?", stat_file_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "directory?", stat_directory_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "chardev?", stat_chardev_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "blockdev?", stat_blockdev_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "pipe?", stat_pipe_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "socket?", stat_socket_p, MRB_ARGS_NONE()); + + mrb_define_method(mrb, stat, "setuid?", stat_setuid_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "setgid?", stat_setgid_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "sticky?", stat_sticky_p, MRB_ARGS_NONE()); + + mrb_define_method(mrb, stat, "ftype", stat_ftype, MRB_ARGS_NONE()); + + mrb_define_method(mrb, stat, "owned?", stat_owned_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, stat, "owned_real?", stat_owned_real_p, MRB_ARGS_NONE()); +} + +void +mrb_mruby_file_stat_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/test/executable b/web/server/h2o/libh2o/deps/mruby-file-stat/test/executable new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/test/executable diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/test/file-stat.c b/web/server/h2o/libh2o/deps/mruby-file-stat/test/file-stat.c new file mode 100644 index 000000000..4e596648d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/test/file-stat.c @@ -0,0 +1,30 @@ +#include <mruby.h> +#include <stdlib.h> + +static mrb_value +test_system(mrb_state *mrb, mrb_value klass) +{ + char *cmd = NULL; + mrb_get_args(mrb, "z", &cmd); + system(cmd); + return mrb_nil_value(); +} + +static mrb_value +test_win_p(mrb_state *mrb, mrb_value klass) +{ +#if defined(_WIN32) + return mrb_true_value(); +#else + return mrb_false_value(); +#endif +} + +void mrb_mruby_file_stat_gem_test(mrb_state *mrb) +{ + struct RClass *t; + + t = mrb_define_class(mrb, "FileStatTest", mrb->object_class); + mrb_define_module_function(mrb, t, "system", test_system, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, t, "win?", test_win_p, MRB_ARGS_NONE()); +} diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/test/file-stat.rb b/web/server/h2o/libh2o/deps/mruby-file-stat/test/file-stat.rb new file mode 100644 index 000000000..63906d015 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/test/file-stat.rb @@ -0,0 +1,369 @@ +class FileStatTest + class << self + def chmod(mode, path) + system("chmod #{mode} #{path}") + yield + ensure + system("chmod 644 #{path}") + end + end +end + +assert 'File::Stat.new' do + assert_kind_of File::Stat, File::Stat.new('README.md') + assert_raise(RuntimeError){ File::Stat.new('unknown.file') } +end + +assert 'File.stat' do + assert_kind_of File::Stat, File.stat('README.md') +end + +assert 'File.lstat' do + assert_kind_of File::Stat, File.lstat('README.md') +end + +assert 'File::Stat#initialize_copy' do + orig = File::Stat.new('README.md') + copy = orig.dup + assert_equal orig.inspect, copy.inspect +end + +assert 'File::Stat#<=>' do + stat1 = File::Stat.new('README.md') + stat2 = File::Stat.new('README.md') + assert_equal 0, stat1.<=>(stat2) + assert_equal nil, stat1.<=>(1) + assert_raise(ArgumentError) { stat1 < 1 } +end + +assert 'File::Stat#dev' do + stat = File::Stat.new('README.md') + assert_kind_of Fixnum, stat.dev +end + +assert 'File::Stat#dev_major' do + stat = File::Stat.new('README.md') + if stat.dev_major + assert_equal Fixnum, stat.dev_major.class + else + assert_nil stat.dev_major ## not supported + end +end + +assert 'File::Stat#dev_minor' do + stat = File::Stat.new('README.md') + if stat.dev_minor + assert_equal Fixnum, stat.dev_minor.class + else + assert_nil stat.dev_minor ## not supported + end +end + +assert 'File::Stat#ino' do + stat = File::Stat.new('README.md') + assert_kind_of Numeric, stat.ino +end + +assert 'File::Stat#mode' do + stat = File::Stat.new('README.md') + assert_kind_of Fixnum, stat.mode +end + +assert 'File::Stat#nlink' do + stat = File::Stat.new('README.md') + assert_kind_of Fixnum, stat.nlink +end + +assert 'File::Stat#uid' do + stat = File::Stat.new('README.md') + assert_kind_of Numeric, stat.uid +end + +assert 'File::Stat#gid' do + stat = File::Stat.new('README.md') + assert_kind_of Numeric, stat.gid +end + +assert 'File::Stat#rdev' do + stat = File::Stat.new('README.md') + assert_kind_of Fixnum, stat.rdev +end + +assert 'File::Stat#rdev_major' do + stat = File::Stat.new('README.md') + if stat.rdev_major + assert_equal Fixnum, stat.rdev_major.class + else + assert_nil stat.rdev_major ## not supported + end +end + +assert 'File::Stat#rdev_minor' do + stat = File::Stat.new('README.md') + if stat.rdev_minor + assert_equal Fixnum, stat.rdev_minor.class + else + assert_nil stat.rdev_minor ## not supported + end +end + +assert 'File::Stat#blocks' do + stat = File::Stat.new('README.md') + blocks = stat.blocks + skip "This system not support `struct stat.st_blocks`" if blocks.nil? + + assert_kind_of Integer, blocks +end + +assert 'File::Stat#atime' do + stat = File::Stat.new('README.md') + assert_kind_of Time, stat.atime +end + +assert 'File::Stat#mtime' do + stat = File::Stat.new('README.md') + assert_kind_of Time, stat.mtime +end + +assert 'File::Stat#ctime' do + stat = File::Stat.new('README.md') + assert_kind_of Time, stat.ctime +end + +assert 'File::Stat#birthtime' do + stat = File::Stat.new('README.md') + begin + assert_kind_of Time, stat.birthtime + rescue NameError + skip 'This system not support `struct stat.birthtimespec`' + end +end + +assert 'File::Stat#size' do + stat = File::Stat.new('README.md') + assert_true 0 < stat.size +end + +assert 'File::Stat#blksize' do + stat = File::Stat.new('README.md') + blksize = stat.blksize + skip "This system not support `struct stat.st_blksize`" if blksize.nil? + + assert_kind_of Integer, blksize +end + +assert 'File::Stat#inspect' do + stat = File::Stat.new('README.md') + %w(dev ino mode nlink uid gid size blksize blocks atime mtime ctime).all? do |name| + assert_include stat.inspect, name + end +end + +assert 'File::Stat#ftype' do + stat = File::Stat.new('README.md') + assert_equal "file", stat.ftype + + stat = File::Stat.new('bin') + assert_equal "directory", stat.ftype +end + +assert 'File::Stat#directory?' do + stat = File::Stat.new('README.md') + assert_false stat.directory? + + stat = File::Stat.new('bin') + assert_true stat.directory? +end + +assert 'File::Stat#readable?' do + skip "when windows" if FileStatTest.win? + + dir = __FILE__[0..-18] # 18 = /test/file-stat.rb + FileStatTest.chmod("+r-w-x", "#{dir}/test/readable") do + assert_true File::Stat.new("#{dir}/test/readable").readable? + end + FileStatTest.chmod("-r+w-x", "#{dir}/test/writable") do + assert_false File::Stat.new("#{dir}/test/writable").readable? + end + FileStatTest.chmod("-r-w+x", "#{dir}/test/executable") do + assert_false File::Stat.new("#{dir}/test/executable").readable? + end +end + +assert 'File::Stat#readable_real?' do + skip "when windows" if FileStatTest.win? + + dir = __FILE__[0..-18] # 18 = /test/file-stat.rb + FileStatTest.chmod("+r-w-x", "#{dir}/test/readable") do + assert_true File::Stat.new("#{dir}/test/readable").readable_real? + end + FileStatTest.chmod("-r+w-x", "#{dir}/test/writable") do + assert_false File::Stat.new("#{dir}/test/writable").readable_real? + end + FileStatTest.chmod("-r-w+x", "#{dir}/test/executable") do + assert_false File::Stat.new("#{dir}/test/executable").readable_real? + end +end + +assert 'File::Stat#world_readable?' do + skip "when windows" if FileStatTest.win? + + dir = __FILE__[0..-18] # 18 = /test/file-stat.rb + FileStatTest.system("chmod 0400 #{dir}/test/readable") + assert_equal nil, File::Stat.new("#{dir}/test/readable").world_readable? + FileStatTest.system("chmod 0444 #{dir}/test/readable") + assert_equal 0444, File::Stat.new("#{dir}/test/readable").world_readable? +end + +assert 'File::Stat#writable?' do + dir = __FILE__[0..-18] # 18 = /test/file-stat.rb + FileStatTest.chmod("+r-w-x", "#{dir}/test/readable") do + assert_false File::Stat.new("#{dir}/test/readable").writable? + end + FileStatTest.chmod("-r+w-x", "#{dir}/test/writable") do + assert_true File::Stat.new("#{dir}/test/writable").writable? + end + FileStatTest.chmod("-r-w+x", "#{dir}/test/executable") do + assert_false File::Stat.new("#{dir}/test/executable").writable? + end +end + +assert 'File::Stat#writable_real?' do + dir = __FILE__[0..-18] # 18 = /test/file-stat.rb + FileStatTest.chmod("+r-w-x", "#{dir}/test/readable") do + assert_false File::Stat.new("#{dir}/test/readable").writable_real? + end + FileStatTest.chmod("-r+w-x", "#{dir}/test/writable") do + assert_true File::Stat.new("#{dir}/test/writable").writable_real? + end + FileStatTest.chmod("-r-w+x", "#{dir}/test/executable") do + assert_false File::Stat.new("#{dir}/test/executable").writable_real? + end +end + +assert 'File::Stat#world_writable?' do + skip "when windows" if FileStatTest.win? + + dir = __FILE__[0..-18] # 18 = /test/file-stat.rb + FileStatTest.chmod("0600", "#{dir}/test/writable") do + assert_equal nil, File::Stat.new("#{dir}/test/writable").world_writable? + end + FileStatTest.chmod("0666", "#{dir}/test/writable") do + assert_equal 0666, File::Stat.new("#{dir}/test/writable").world_writable? + end +end + +assert 'File::Stat#executable?' do + skip "when windows" if FileStatTest.win? + + dir = __FILE__[0..-18] # 18 = /test/file-stat.rb + FileStatTest.chmod("+r-w-x", "#{dir}/test/readable") do + assert_false File::Stat.new("#{dir}/test/readable").executable? + end + FileStatTest.chmod("-r+w-x", "#{dir}/test/writable") do + assert_false File::Stat.new("#{dir}/test/writable").executable? + end + FileStatTest.chmod("-r-w+x", "#{dir}/test/executable") do + assert_true File::Stat.new("#{dir}/test/executable").executable? + end +end + +assert 'File::Stat#executable_real?' do + skip "when windows" if FileStatTest.win? + + dir = __FILE__[0..-18] # 18 = /test/file-stat.rb + FileStatTest.chmod("+r-w-x", "#{dir}/test/readable") do + assert_false File::Stat.new("#{dir}/test/readable").executable_real? + end + FileStatTest.chmod("-r+w-x", "#{dir}/test/writable") do + assert_false File::Stat.new("#{dir}/test/writable").executable_real? + end + FileStatTest.chmod("-r-w+x", "#{dir}/test/executable") do + assert_true File::Stat.new("#{dir}/test/executable").executable_real? + end +end + +assert 'File::Stat#file?' do + stat = File::Stat.new('README.md') + assert_true stat.file? + + stat = File::Stat.new('bin') + assert_false stat.file? +end + +assert 'File::Stat#zero?' do + stat = File::Stat.new('README.md') + assert_false stat.zero? +end + +assert 'File::Stat#size?' do + stat = File::Stat.new('README.md') + assert_true 0 < stat.size? +end + +assert 'File::Stat#owned?' do + stat = File::Stat.new('README.md') + assert_true stat.owned? +end + +assert 'File::Stat#owned_real?' do + stat = File::Stat.new('README.md') + assert_true stat.owned_real? +end + +assert 'File::Stat#grpowned?' do + is_unix = File::Stat.new('/dev/tty') rescue false + if is_unix + stat = File::Stat.new('README.md') + assert_true stat.grpowned? + else + skip "is not supported" + end +end + +assert 'File::Stat#pipe?' do + stat = File::Stat.new('README.md') + assert_false stat.pipe? +end + +assert 'File::Stat#symlink?' do + stat = File::Stat.new('README.md') + assert_false stat.symlink? +end + +assert 'File::Stat#socket?' do + stat = File::Stat.new('README.md') + assert_false stat.socket? +end + +assert 'File::Stat#blockdev?' do + stat = File::Stat.new('README.md') + assert_false stat.blockdev? +end + +assert 'File::Stat#chardev?' do + stat = File::Stat.new('README.md') + assert_false stat.chardev? + + begin + stat = File::Stat.new('/dev/tty') + assert_true stat.chardev? + rescue RuntimeError + skip '/dev/tty is not found' + end +end + +assert 'File::Stat#setuid?' do + stat = File::Stat.new('README.md') + assert_false stat.setuid? +end + +assert 'File::Stat#setgid?' do + stat = File::Stat.new('README.md') + assert_false stat.setgid? +end + +assert 'File::Stat#sticky?' do + stat = File::Stat.new('README.md') + assert_false stat.sticky? +end diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/test/io.rb b/web/server/h2o/libh2o/deps/mruby-file-stat/test/io.rb new file mode 100644 index 000000000..47e63089a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/test/io.rb @@ -0,0 +1,7 @@ +assert 'IO#stat' do + # You can use IO#stat if implemented to IO#fileno + # mruby-file-stat is just not implemented this. + assert_raise(NotImplementedError) do + IO.new(1).stat + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/test/readable b/web/server/h2o/libh2o/deps/mruby-file-stat/test/readable new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/test/readable diff --git a/web/server/h2o/libh2o/deps/mruby-file-stat/test/writable b/web/server/h2o/libh2o/deps/mruby-file-stat/test/writable new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-file-stat/test/writable diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/.gitignore b/web/server/h2o/libh2o/deps/mruby-iijson/.gitignore new file mode 100644 index 000000000..ceeb05b41 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/.gitignore @@ -0,0 +1 @@ +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/.travis.yml b/web/server/h2o/libh2o/deps/mruby-iijson/.travis.yml new file mode 100644 index 000000000..ffe227284 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/README.md b/web/server/h2o/libh2o/deps/mruby-iijson/README.md new file mode 100644 index 000000000..bbbfeba6d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/README.md @@ -0,0 +1,87 @@ +# mruby-iijson +[![Build Status](https://travis-ci.org/iij/mruby-iijson.svg?branch=master)](https://travis-ci.org/iij/mruby-iijson) + +"mruby-iijson" is JSON module for mruby. + + +## Implemented Methods: + - [JSON.dump](http://docs.ruby-lang.org/en/2.2.0/JSON.html#method-i-dump) + - [JSON.generate](http://docs.ruby-lang.org/en/2.2.0/JSON.html#method-i-generate) + - [JSON.load](http://docs.ruby-lang.org/en/2.2.0/JSON.html#method-i-load) + - [JSON.parse](http://docs.ruby-lang.org/en/2.2.0/JSON.html#method-i-parse) + - `Array#to_json`, `Fixnum#to_json`, `Float#to_json`, `Hash#to_json`, `String#to_json`, ... + +## Example: + +```Ruby +str = '{ + "Image": { + "Width": 800, + "Height": 600, + "Title": "View from 15th Floor", + "Thumbnail": { + "Url": "http://www.example.com/image/481989943", + "Height": 125, + "Width": "100" + }, + "IDs": [116, 943, 234, 38793] + } +}' +p JSON.parse(str) + +h = { + :precision => "zip", + :Latitude => 37.7668, + :Longitude => -122.3959, + :Address => "", + :City => "SAN FRANCISCO", + :State => "CA", + :Zip => "94107", + :Country => "US" +} +p h.to_json +puts JSON.generate(h, {:pretty_print => true, :indent_with => 2}) +``` + +``` +{"Image"=>{"Width"=>800, "Height"=>600, "Title"=>"View from 15th Floor", "Thumbnail"=>{"Url"=>"http://www.example.com/image/481989943", "Height"=>125, "Width"=>"100"}, "IDs"=>[116, 943, 234, 38793]}} +"{\"precision\":\"zip\",\"Latitude\":37.766800000000003,\"Longitude\":-122.3959,\"Address\":\"\",\"City\":\"SAN FRANCISCO\",\"State\":\"CA\",\"Zip\":\"94107\",\"Country\":\"US\"}" +{ + "precision": "zip", + "Latitude": 37.766800000000003, + "Longitude": -122.3959, + "Address": "", + "City": "SAN FRANCISCO", + "State": "CA", + "Zip": "94107", + "Country": "US" +} +``` + + +## Caveats + + - JSON.generate won't return if input Array/Hash has circular reference. + + +## License + +Copyright (c) 2014 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-iijson/mrbgem.rake new file mode 100644 index 000000000..fef1c3dd8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/mrbgem.rake @@ -0,0 +1,6 @@ +MRuby::Gem::Specification.new('mruby-iijson') do |spec| + spec.license = 'MIT' + spec.author = 'Internet Initiative Japan Inc.' + + spec.add_dependency "mruby-sprintf", :core => "mruby-sprintf" +end diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/json.rb b/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/json.rb new file mode 100755 index 000000000..87b5a6bda --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/json.rb @@ -0,0 +1,129 @@ +module JSON + def self.dump(object, io=nil, limit=nil) + state = {} + state[:max_nesting] = limit if limit + begin + js = JSON.generate(object, nil, state) + rescue JSON::NestingError + raise ArgumentError, "exceeded depth limit" + end + if io + io.write js + io + else + js + end + end + + def self.generate(obj, options=nil, state=nil) + options = (options || {}).to_hash unless options.is_a? Hash + options[:pretty_print] ||= false + options[:indent_with] ||= 2 + state = (state || {}).to_hash unless state.is_a? Hash + state[:max_nesting] ||= 100 + state[:nesting] = 0 + self.generate0(obj, options, state) + end + + def self.generate0(obj, options, state) + if state[:nesting] >= state[:max_nesting] + raise JSON::NestingError, "nesting of #{state[:nesting]} is too deep" + end + + pretty = options[:pretty_print] + + if pretty + indent = options[:indent_with].class == Fixnum ? " " * options[:indent_with] : options[:indent_with] + else + indent = "" + end + + nl = pretty ? "\n" : "" + + if obj == false + return "false" + + elsif obj == nil + return "null" + + elsif obj == true + return "true" + + elsif obj.is_a? Hash + members = [] + state[:nesting] += 1 + obj.each { |k, v| + members << JSON.generate0(k, options, state) + ":" + (pretty ? " " : "") + JSON.generate0(v, options, state) + } + if pretty + members.map! { |k| (indent * state[:nesting]) + "#{k}" }.join("_") + end + state[:nesting] -= 1 + return "{" + nl + members.join("," + nl) + nl + (indent * state[:nesting]) + "}" + + elsif obj.is_a? Array + state[:nesting] += 1 + members = obj.map { |v| JSON.generate0(v, options, state) } + if pretty + members.map! { |k| (indent * state[:nesting]) + "#{k}" }.join("_") + end + state[:nesting] -= 1 + return "[" + nl + members.join("," + nl) + nl + (indent * state[:nesting]) + "]" + + elsif obj.is_a? Fixnum + return obj.to_s + + elsif obj.is_a? Float + if obj.infinite? or obj.nan? + raise GeneratorError, "#{obj.to_s} not allowed in JSON" + end + sprintf "%.17g", obj + + else + a = [] + obj.to_s.each_char { |ch| + a << if ch < "\x20" + case ch + when "\x08" + "\\b" + when "\x0c" + "\\f" + when "\x0a" + "\\n" + when "\x0d" + "\\r" + when "\x09" + "\\t" + else + raise GeneratorError, "cannot convert #{ch.inspect} to JSON" + end + elsif ch == '"' + '\\"' + elsif ch == '\\' + "\\\\" + else + ch + end + } + return '"' + a.join + '"' + end + end + + def self.load(source) # TODO: proc, options + source = source.read unless source.is_a? String + JSON.parse source + end + + class JSONError < StandardError; end + class GeneratorError < JSONError; end + class ParserError < JSONError; end + class NestingError < ParserError; end +end + +unless Float.method_defined? :nan? + class Float + def nan? + not (self == self) + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/to_json.rb b/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/to_json.rb new file mode 100644 index 000000000..ee97ac2c6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/mrblib/to_json.rb @@ -0,0 +1,47 @@ +class Array + def to_json + JSON.generate(self) + end +end + +class FalseClass + def to_json + JSON.generate(self) + end +end + +class Fixnum + def to_json + JSON.generate(self) + end +end + +class Float + def to_json + JSON.generate(self) + end +end + +class Hash + def to_json + JSON.generate(self) + end +end + +class NilClass + def to_json + JSON.generate(self) + end +end + +class String + def to_json + JSON.generate(self) + end +end + +class TrueClass + def to_json + JSON.generate(self) + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/run_test.rb b/web/server/h2o/libh2o/deps/mruby-iijson/run_test.rb new file mode 100644 index 000000000..dece5070a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/run_test.rb @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/src/json.c b/web/server/h2o/libh2o/deps/mruby-iijson/src/json.c new file mode 100644 index 000000000..6836e0907 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/src/json.c @@ -0,0 +1,641 @@ +#include <ctype.h> +#include <inttypes.h> +#include <string.h> + +#include "mruby.h" +#include "mruby/array.h" +#include "mruby/hash.h" +#include "mruby/string.h" +#include "mruby/value.h" + +#define E_JSON_PARSER_ERROR (mrb_class_get_under(mrb, mrb_module_get(mrb, "JSON"), "ParserError")) + +#define JSON_EOF -1 + +#define DEFAULT_MAX_NESTING 100 + +struct json_parser { + mrb_state *mrb; + mrb_value src; + unsigned int cursor; + unsigned int lineno; + int nesting; + + int max_nesting; +}; + +static void json_check_nesting(struct json_parser *); +static int json_delimiter_p(char ch); +static int json_getc(struct json_parser *); +static void json_skip_ws(struct json_parser *); +static void json_ungetc(struct json_parser *); +static int json_unicode2utf8(uint32_t, char *); +static int json_whitespace_p(char ch); + +static int json_parse_array(struct json_parser *, mrb_value *); +static int json_parse_object(struct json_parser *, mrb_value *); +static int json_parse_number2(struct json_parser *, int, mrb_value *, mrb_int, int); +static int json_parse_string(struct json_parser *, mrb_value *); +static int json_parse_value(struct json_parser *, mrb_value *); + +#if MRUBY_RELEASE_NO < 10000 +static struct RClass * +mrb_module_get(mrb_state *mrb, const char *name) +{ + return mrb_class_get(mrb, name); +} +#endif +#if !defined(MRB_PRId) +#if defined(MRB_INT64) +# define MRB_PRId PRId64 +#elif defined(MRB_INT16) +# define MRB_PRId PRId16 +#else +# define MRB_PRId PRId32 +#endif +#endif /* !defined(MRB_PRId) */ + +static void +json_check_nesting(struct json_parser *parser) +{ + mrb_state *mrb = parser->mrb; + + if (parser->max_nesting != -1) { + if (parser->nesting >= parser->max_nesting) { + // +1 for compatibility with CRuby + mrb_raisef(mrb, E_JSON_PARSER_ERROR, "nesting of %S is too deep", mrb_fixnum_value(parser->nesting+1)); + } + } +} + +static int +json_delimiter_p(char ch) +{ + return (json_whitespace_p(ch) || ch == ',' || ch == ']' || ch == '}'); +} + +static int +json_getc(struct json_parser *parser) +{ + if (parser->cursor < RSTRING_LEN(parser->src)) { + unsigned char ch = RSTRING_PTR(parser->src)[parser->cursor]; + parser->cursor++; + return ch; + } else { + return JSON_EOF; + } +} + +static int +json_parse_readstring(struct json_parser *parser, const char *str) +{ + size_t len; + int ch; + + len = strlen(str); + if (parser->cursor + len > RSTRING_LEN(parser->src)) + return 0; + if (memcmp(str, RSTRING_PTR(parser->src) + parser->cursor, len) != 0) + return -1; + parser->cursor += len; + if (parser->cursor == RSTRING_LEN(parser->src)) + return 1; + ch = RSTRING_PTR(parser->src)[parser->cursor]; + if (!json_delimiter_p(ch)) + return -1; + return 1; +} + +static void +json_skip_ws(struct json_parser *parser) +{ + int ch; + + do { + ch = json_getc(parser); + if (ch == 0x0a) + parser->lineno++; + } while (json_whitespace_p(ch)); + if (ch != JSON_EOF) { + json_ungetc(parser); + } +} + +static void +json_ungetc(struct json_parser *parser) +{ + if (parser->cursor > 0) + parser->cursor--; +} + +static int +json_unicode2utf8(uint32_t unicode, char *cp) +{ + int n = 0; + if (unicode < 0x80) { + cp[n++] = unicode; + } else if (unicode < 0x800) { + cp[n++] = 0xc0 + (unicode >> 6); + cp[n++] = 0x80 + (unicode & 0x3f); + } else if (unicode < 0x10000) { + cp[n++] = 0xe0 + (unicode >> 12); + cp[n++] = 0x80 + ((unicode >> 6) & 0x3f); + cp[n++] = 0x80 + (unicode & 0x3f); + } else { + cp[n++] = 0xf0 + (unicode >> 18); + cp[n++] = 0x80 + ((unicode >> 12) & 0x3f); + cp[n++] = 0x80 + ((unicode >> 6) & 0x3f); + cp[n++] = 0x80 + (unicode & 0x3f); + } + return n; +} + +static int +json_whitespace_p(char ch) +{ + return (ch == 0x20 || ch == 0x09 || ch == 0x0a || ch == 0x0d); +} + +static int +json_parse_array(struct json_parser *parser, mrb_value *result) +{ + mrb_state *mrb = parser->mrb; + mrb_value ary, v; + int ch; + + json_check_nesting(parser); + + ary = mrb_ary_new(mrb); + + json_skip_ws(parser); + ch = json_getc(parser); + if (ch == ']') { /* easy case */ + *result = ary; + return 1; + } + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "JSON_EOF in array(1)"); + } + json_ungetc(parser); + + while (1) { + parser->nesting++; + if (json_parse_value(parser, &v) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "error in array"); + } + parser->nesting--; + + mrb_ary_push(mrb, ary, v); + + json_skip_ws(parser); + ch = json_getc(parser); + if (ch == ']') { + break; + } + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "JSON_EOF in array(2)"); + } + if (ch != ',') { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "not ',' in array"); + } + } + *result = ary; + return 1; +} + +static int +json_parse_object(struct json_parser *parser, mrb_value *result) +{ + mrb_state *mrb = parser->mrb; + mrb_value h, k, v; + int ch; + + json_check_nesting(parser); + + h = mrb_hash_new(mrb); + + json_skip_ws(parser); + ch = json_getc(parser); + if (ch == '}') { /* easy case */ + *result = h; + return 1; + } + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "EOF in object(1)"); + } + json_ungetc(parser); + + while (1) { + parser->nesting++; + if (json_parse_value(parser, &k) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "error in object key"); + } + parser->nesting--; + if (! mrb_string_p(k)) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "key is not a string"); + } + + json_skip_ws(parser); + + ch = json_getc(parser); + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "EOF in object(2)"); + } + if (ch != ':') { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "no ':' in object"); + } + + parser->nesting++; + if (json_parse_value(parser, &v) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "error in object value"); + } + parser->nesting--; + + mrb_hash_set(mrb, h, k, v); + + json_skip_ws(parser); + ch = json_getc(parser); + if (ch == '}') { + break; + } + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "EOF in object(3)"); + } + if (ch != ',') { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "no ',' in object"); + } + } + *result = h; + return 1; +} + +static int +json_parse_number(struct json_parser *parser, int ch, mrb_value *result) +{ + mrb_state *mrb = parser->mrb; + mrb_int num; + int d, sign; + + if (ch == '-') { + sign = -1; + ch = json_getc(parser); + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "no character following minus"); + } + if (!isdigit(ch)) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "character following minus is not a digit"); + } + } else { + sign = 1; + } + num = (ch - '0') * sign; + while (1) { + ch = json_getc(parser); + if (ch == JSON_EOF) { + break; + } + if (isdigit(ch)) { + if (num == 0) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "leading zeros are not allowed"); + } + d = (ch - '0') * sign; + if (num < MRB_INT_MIN / 10 || + (num == MRB_INT_MIN / 10 && d < MRB_INT_MIN - num * 10) || + num > MRB_INT_MAX / 10 || + (num == MRB_INT_MAX / 10 && d > MRB_INT_MAX - num * 10)) { + return json_parse_number2(parser, ch, result, num, sign); + } + num = num * 10 + d; + } else if (ch == '.' || ch == 'e' || ch == 'E') { + return json_parse_number2(parser, ch, result, num, sign); + } else if (json_delimiter_p(ch)) { + json_ungetc(parser); + break; + } else { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "invalid number"); + } + } + *result = mrb_fixnum_value(num); + return 1; +} + +static int +json_parse_number2(struct json_parser *parser, int ch, mrb_value *result, mrb_int num, int sign) +{ + mrb_state *mrb = parser->mrb; + double d; + int i, state; + char buf[64]; + + /* + * "-"? ("0" | [1-9] digit* ) ("." digit+ )? ([eE][-+] digit+)? + * state: 000000 111 222222 33334444 555555 + */ + i = snprintf(buf, sizeof(buf), "%s%"MRB_PRId"%c", + (num == 0 && sign < 0) ? "-" : "", + num, ch); + + if (isdigit(ch)) + state = 0; + else if (ch == '.') + state = 1; + else /* (ch == 'e' || ch == 'E') */ + state = 3; + + while (1) { + ch = json_getc(parser); + if (ch == JSON_EOF) + break; + switch (state) { + case 0: + if (isdigit(ch)) + ; /* read more digits */ + else if (ch == '.') + state = 1; + else if (ch == 'e' || ch == 'E') + state = 3; + else if (json_delimiter_p(ch)) { + json_ungetc(parser); + state = -1; + } else + goto formaterr; + break; + case 1: + if (!isdigit(ch)) + goto formaterr; + state = 2; + break; + case 2: + if (isdigit(ch)) + ; /* read more digits */ + else if (ch == 'e' || ch == 'E') + state = 3; + else if (json_delimiter_p(ch)) { + json_ungetc(parser); + state = -1; + } else + goto formaterr; + break; + case 3: + if (ch == '-' || ch == '+') + state = 4; + else if (isdigit(ch)) + state = 5; + else + goto formaterr; + break; + case 4: + if (!isdigit(ch)) + goto formaterr; + state = 5; + break; + case 5: + default: + if (isdigit(ch)) + ; /* read more digits */ + else { + json_ungetc(parser); + state = -1; + } + break; + } + if (state == -1) + break; + if (i == sizeof(buf) - 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "floating point number too long"); + } + buf[i++] = ch; + } + buf[i] = '\0'; + sscanf(buf, "%lf", &d); + *result = mrb_float_value(mrb, d); + return 1; + +formaterr: + mrb_raise(mrb, E_JSON_PARSER_ERROR, "floating point number error"); + return -1; +} + +static int +json_parse_string(struct json_parser *parser, mrb_value *result) +{ + mrb_state *mrb = parser->mrb; + mrb_value str; + uint32_t unicode; + uint16_t utf16; + int ch, i, n; + char *cp; + + str = mrb_str_buf_new(mrb, 30); + cp = RSTRING_PTR(str); + n = 0; + unicode = 0; + + while (1) { + ch = json_getc(parser); + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "EOF in string"); + } + + if (ch == '"') { + break; + } else if (ch == '\\') { + ch = json_getc(parser); + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "EOF following escape char"); + } + switch (ch) { + case '"': + case '\\': + case '/': + break; + case 'b': + ch = 0x08; + break; + case 'f': + ch = 0x0c; + break; + case 'n': + ch = 0x0a; + break; + case 'r': + ch = 0x0d; + break; + case 't': + ch = 0x09; + break; + case 'u': + utf16 = 0; + for (i = 0; i < 4; i++) { + ch = json_getc(parser); + if (ch == JSON_EOF) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "invalid unicode escape"); + } + if (ch >= '0' && ch <= '9') { + ch -= '0'; + } else if (ch >= 'A' && ch <= 'F') { + ch = (ch - 'A') + 10; + } else if (ch >= 'a' && ch <= 'f') { + ch = (ch - 'a') + 10; + } else { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "invalid unicode character"); + } + utf16 *= 16; + utf16 += ch; + } + + if (n + 8 >= RSTRING_CAPA(str)) { + mrb_str_resize(mrb, str, RSTRING_CAPA(str)*2); + cp = RSTRING_PTR(str); + } + + if ((utf16 & 0xf800) == 0xd800) { + if ((utf16 & 0xfc00) == 0xd800) { + /* high surrogate */ + unicode = utf16; + continue; + } else { + /* low surrogate */ + if (unicode > 0) { + unicode = ((unicode & 0x03ff) + 0x040) << 10; + unicode += utf16 & 0x03ff; + } else { + /* error: low surrogate comes first... */ + } + } + } else { + if (unicode > 0) { + /* error: high surrogate not followed by low surrogate */ + n += json_unicode2utf8(unicode, &cp[n]); + } + unicode = utf16; + } + + n += json_unicode2utf8(unicode, &cp[n]); + unicode = 0; + continue; + default: + mrb_raise(mrb, E_JSON_PARSER_ERROR, "invalid escape char"); + break; + } + } else if (ch < 0x20) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "invalid char"); + } + + if (n + 1 == RSTRING_CAPA(str)) { + mrb_str_resize(mrb, str, RSTRING_CAPA(str)*2); + cp = RSTRING_PTR(str); + } + cp[n++] = ch; + } + cp[n] = '\0'; + mrb_str_resize(mrb, str, n); + *result = str; + return 1; +} + +static int +json_parse_value(struct json_parser *parser, mrb_value *result) +{ + mrb_state *mrb = parser->mrb; + int ch; + + do { + ch = json_getc(parser); + if (ch == JSON_EOF) + return 0; + } while (json_whitespace_p(ch)); + + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': + if (json_parse_number(parser, ch, result) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "number...?"); + } + break; + + case '"': + if (json_parse_string(parser, result) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "string...?"); + } + break; + + case '[': + if (json_parse_array(parser, result) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "array...?"); + } + break; + + case '{': + if (json_parse_object(parser, result) != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "object...?"); + } + break; + + case 'f': + if (json_parse_readstring(parser, "alse") != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "unexpected f"); + } + *result = mrb_false_value(); + break; + + case 'n': + if (json_parse_readstring(parser, "ull") != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "unexpected n"); + } + *result = mrb_nil_value(); + break; + + case 't': + if (json_parse_readstring(parser, "rue") != 1) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "unexpected t"); + } + *result = mrb_true_value(); + break; + + default: + mrb_raise(mrb, E_JSON_PARSER_ERROR, "unexpected character"); + } + + return 1; +} + +static mrb_value +mrb_json_parse(mrb_state *mrb, mrb_value mod) +{ + struct json_parser parser; + mrb_value obj, options, source; + + mrb_get_args(mrb, "S|H", &source, &options); + + parser.mrb = mrb; + parser.src = source; + parser.cursor = 0; + parser.lineno = 0; + parser.nesting = 0; + parser.max_nesting = DEFAULT_MAX_NESTING; + + if (json_parse_value(&parser, &obj) == 0) { + mrb_raise(mrb, E_JSON_PARSER_ERROR, "no JSON value"); + } + + // if we have extra characters: + // unexpected token at '3' (JSON::ParserError) + + return obj; +} + +void +mrb_mruby_iijson_gem_init(mrb_state *mrb) +{ + struct RClass *m; + + m = mrb_define_module(mrb, "JSON"); + mrb_define_module_function(mrb, m, "parse", mrb_json_parse, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); +} + +void +mrb_mruby_iijson_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/test/json.rb b/web/server/h2o/libh2o/deps/mruby-iijson/test/json.rb new file mode 100644 index 000000000..5b1e759c8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/test/json.rb @@ -0,0 +1,145 @@ +assert('JSON.dump') do + class JsonTestIo + def initialize + @buf = "" + end + def write(str) + @buf += str + end + attr_reader :buf + end + assert_equal "[1]", JSON.dump([1]) + + jio = JsonTestIo.new + JSON.dump(["abc"], jio) + assert_equal '["abc"]', jio.buf + + assert_raise(ArgumentError) do + JSON.dump({:a => {:b => {} } }, nil, 2) + end + JSON.dump({:a=>{:b=>{}}}, nil, 3) # should not raise +end + +assert('JSON.generate: false') do + assert_equal "false", JSON.generate(false) +end + +assert('JSON.generate: null') do + assert_equal "null", JSON.generate(nil) +end + +assert('JSON.generate: true') do + assert_equal "true", JSON.generate(true) +end + +assert('JSON.generate: object') do + assert_equal '{"key":"value"}', JSON.generate({ "key" => "value" }) + assert_equal '{"ten":10}', JSON.generate({ :ten => 10 }) +end + +assert('JSON.generate: array') do + assert_equal '[null,1,"two"]', JSON.generate([ nil, 1, "two"]) +end + +assert('JSON.generate: number (Fixnum)') do + str = JSON.generate [1] + assert_equal "[1]", str +end + +assert('JSON.generate: number (Float)') do + str = JSON.generate [134.625] + assert_equal "[134.625]", str +end + +assert('JSON.generate: string') do + assert_equal "\"abc\"", JSON.generate("abc") + assert_equal "\"\\\"\\\\/\\b\\f\\n\\r\\t\"", + JSON.generate("\x22\x5c\x2f\x08\x0c\x0a\x0d\x09") +end + +assert('JSON.load') do + assert_equal [1,2,3], JSON.load("[1,2,3]") + + class JsonTestReader + def read + '{"abc":123}' + end + end + assert_equal({"abc"=>123}, JSON.load(JsonTestReader.new)) +end + +assert('JSON.parse: text from RFC4726') do + str = '{ + "Image": { + "Width": 800, + "Height": 600, + "Title": "View from 15th Floor", + "Thumbnail": { + "Url": "http://www.example.com/image/481989943", + "Height": 125, + "Width": "100" + }, + "IDs": [116, 943, 234, 38793] + } + }' + hash = { + "Image" => { + "Width" => 800, + "Height" => 600, + "Title" => "View from 15th Floor", + "Thumbnail" => { + "Url" => "http://www.example.com/image/481989943", + "Height" => 125, + "Width" => "100" + }, + "IDs" => [116, 943, 234, 38793] + } + } + assert_equal hash, JSON.parse(str) + + # We cannot compare `str` with `JSON.generate(hash)` because Hash entries + # will be in a random order. + assert_equal hash, JSON.parse(JSON.generate(hash)) +end + +assert('JSON::ParserError') do + assert_raise(JSON::ParserError) do + JSON.parse "[xxx]" + end +end + +assert('JSON.parse: empty string is not a valid JSON text') do + assert_raise(JSON::ParserError) do + JSON.parse "" + end +end + +assert('JSON.parse: parsing numbers around MRB_INT_MIN/MRB_INT_MAX') do + int_min = TestJSON::MRB_INT_MIN + int_max = TestJSON::MRB_INT_MAX + + assert_kind_of Fixnum, JSON.load(int_min.to_s) + assert_equal int_min, JSON.load(int_min.to_s) + + assert_kind_of Fixnum, JSON.load(int_max.to_s) + assert_equal int_max, JSON.load(int_max.to_s) + + assert_kind_of Float, JSON.load((int_min-1).to_s) + assert_float (int_min-1)/int_min, JSON.load((int_min-1).to_s)/int_min + + assert_kind_of Float, JSON.load((int_max+1).to_s) + assert_float (int_max+1)/int_max, JSON.load((int_max+1).to_s)/int_max +end + +assert('#to_json') do + assert_equal 'false', false.to_json + assert_equal 'null', nil.to_json + assert_equal 'true', true.to_json + assert_equal '1', 1.to_json + assert_equal '3.125', 3.125.to_json + assert_equal '"str"', "str".to_json + assert_equal '["one",2]', [ "one", 2 ].to_json + assert_equal '{"a":1}', { "a" => 1 }.to_json + assert_equal TestJSON::MRB_INT_MIN.to_s, TestJSON::MRB_INT_MIN.to_json + assert_equal TestJSON::MRB_INT_MAX.to_s, TestJSON::MRB_INT_MAX.to_json +end diff --git a/web/server/h2o/libh2o/deps/mruby-iijson/test/testjson.c b/web/server/h2o/libh2o/deps/mruby-iijson/test/testjson.c new file mode 100644 index 000000000..f254e8bb9 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-iijson/test/testjson.c @@ -0,0 +1,11 @@ +#include "mruby.h" +#include "mruby/value.h" +#include "mruby/variable.h" + +void +mrb_mruby_iijson_gem_test(mrb_state* mrb) +{ + struct RClass *c = mrb_define_module(mrb, "TestJSON"); + mrb_const_set(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, "MRB_INT_MIN"), mrb_fixnum_value(MRB_INT_MIN)); + mrb_const_set(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, "MRB_INT_MAX"), mrb_fixnum_value(MRB_INT_MAX)); +} diff --git a/web/server/h2o/libh2o/deps/mruby-input-stream/.travis.yml b/web/server/h2o/libh2o/deps/mruby-input-stream/.travis.yml new file mode 100644 index 000000000..fc81cadad --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-input-stream/.travis.yml @@ -0,0 +1,6 @@ +sudo: false +script: + - export MRUBY_CONFIG="$TRAVIS_BUILD_DIR/build_config_sample.rb" + - git clone --depth 1 "https://github.com/mruby/mruby.git" + - cd mruby + - ./minirake test diff --git a/web/server/h2o/libh2o/deps/mruby-input-stream/LICENSE b/web/server/h2o/libh2o/deps/mruby-input-stream/LICENSE new file mode 100644 index 000000000..6e817bb59 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-input-stream/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Masayoshi Takahashi + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/web/server/h2o/libh2o/deps/mruby-input-stream/README.md b/web/server/h2o/libh2o/deps/mruby-input-stream/README.md new file mode 100644 index 000000000..a9efe87fa --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-input-stream/README.md @@ -0,0 +1,28 @@ +# mruby-input-stream + +[![Build Status](https://travis-ci.org/takahashim/mruby-input-stream.svg?branch=master)](https://travis-ci.org/takahashim/mruby-input-stream) + +Input Stream class for Rack. + + +## Install + +add conf.gem to `build_config.rb`: + + MRuby::Build.new do |conf| + + # ... (snip) ... + + conf.gem :github => 'takahashim/mruby-input-stream' + end + +## License + +MIT + +## Author + +Masayoshi Takahashi + + + diff --git a/web/server/h2o/libh2o/deps/mruby-input-stream/Rakefile b/web/server/h2o/libh2o/deps/mruby-input-stream/Rakefile new file mode 100644 index 000000000..0c0c78ea1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-input-stream/Rakefile @@ -0,0 +1,28 @@ +MRUBY_CONFIG=File.expand_path(ENV["MRUBY_CONFIG"] || "./build_config_sample.rb") +RAKE="ruby ./minirake" + +file :mruby do + sh "git clone --depth 1 git://github.com/mruby/mruby.git" +end + +task :default => :test + +desc "test this mrbgem" +task :test => :mruby do + sh "cd mruby && MRUBY_CONFIG=#{MRUBY_CONFIG} #{RAKE} test" +end + +desc "build mruby with this mrbgem" +task :build => :mruby do + sh "cd mruby && MRUBY_CONFIG=#{MRUBY_CONFIG} #{RAKE} all" +end + +desc "cleanup" +task :clean do + sh "cd mruby && rake deep_clean" if File.exist?("mruby") +end + +desc "cleanup including temporary files" +task :realclean do + sh "rm -rf mruby" +end diff --git a/web/server/h2o/libh2o/deps/mruby-input-stream/build_config_sample.rb b/web/server/h2o/libh2o/deps/mruby-input-stream/build_config_sample.rb new file mode 100644 index 000000000..9d2321d9c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-input-stream/build_config_sample.rb @@ -0,0 +1,17 @@ +MRuby::Build.new do |conf| + toolchain :gcc + + conf.gembox 'default' + conf.gem File.expand_path(File.dirname(__FILE__)) +end + +MRuby::Build.new('test') do |conf| + toolchain :gcc + + enable_debug + conf.enable_bintest + conf.enable_test + + conf.gembox 'default' + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-input-stream/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-input-stream/mrbgem.rake new file mode 100644 index 000000000..082a128aa --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-input-stream/mrbgem.rake @@ -0,0 +1,6 @@ +MRuby::Gem::Specification.new('mruby-input-stream') do |spec| + spec.license = 'MIT' + spec.authors = 'Masayoshi Takahashi' + spec.summary = 'InputStream class for Rack' + spec.version = '1.0.0' +end diff --git a/web/server/h2o/libh2o/deps/mruby-input-stream/mrblib/input_stream.rb b/web/server/h2o/libh2o/deps/mruby-input-stream/mrblib/input_stream.rb new file mode 100644 index 000000000..d452f7ff1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-input-stream/mrblib/input_stream.rb @@ -0,0 +1,16 @@ +class InputStream + include Enumerable + + # + # from String#each + def each(&block) + self.rewind + while pos = self.byteindex(0x0a) + block.call(self.read(pos+1)) + end + rest = self.read() + if rest + block.call(rest) + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-input-stream/src/mruby_input_stream.c b/web/server/h2o/libh2o/deps/mruby-input-stream/src/mruby_input_stream.c new file mode 100644 index 000000000..a5f90b981 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-input-stream/src/mruby_input_stream.c @@ -0,0 +1,278 @@ +#include <string.h> +#include "mruby.h" +#include "mruby/value.h" +#include "mruby/data.h" +#include "mruby/string.h" +#include "mruby_input_stream.h" + +typedef struct mrb_input_stream_t { + const char *base; + mrb_int len; + mrb_int pos; + mrb_input_stream_free_callback free_cb; + void *free_cb_data; +} mrb_input_stream_t; + +static mrb_input_stream_t* +mrb_input_stream_create(mrb_state *mrb, const char *base, mrb_int len, mrb_input_stream_free_callback cb, void *cb_data); + +static void +mrb_mruby_input_stream_free(mrb_state *mrb, void *ptr); + +static mrb_int +seek_char(mrb_input_stream_t *stream, const char chr); + +const static struct mrb_data_type mrb_input_stream_type = { + "InputStream", + mrb_mruby_input_stream_free, +}; + +static void +assert_is_open(mrb_state *mrb, mrb_input_stream_t *stream) +{ + if (stream->len < 0) { + struct RClass *klass = mrb_class_get(mrb, "IOError"); + if (klass == NULL) + klass = E_RUNTIME_ERROR; + mrb_raise(mrb, klass, "stream closed"); + } +} + +static mrb_value +mrb_input_stream_init(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + mrb_int len; + char *ptr; + mrb_input_stream_t *stream; + mrb_int n = mrb_get_args(mrb, "|S", &str); + if (n > 1) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(n)); + } + + if (n == 1) { + len = RSTRING_LEN(str); + ptr = RSTRING_PTR(str); + stream = mrb_input_stream_create(mrb, ptr, len, NULL, NULL); + } else { + stream = mrb_input_stream_create(mrb, NULL, 0, NULL, NULL); + } + + DATA_TYPE(self) = &mrb_input_stream_type; + DATA_PTR(self) = stream; + return self; +} + +static void +default_free_cb(mrb_state *mrb, const char *base, mrb_int len, void *cb_data) +{ + if (base != NULL) + mrb_free(mrb, (void *)base); +} + +static void +mrb_mruby_input_stream_free(mrb_state *mrb, void *ptr) +{ + mrb_input_stream_t *stream = (mrb_input_stream_t *)ptr; + if (stream->free_cb != NULL) + stream->free_cb(mrb, stream->base, stream->len, stream->free_cb_data); + mrb_free(mrb, stream); +} + +static void setup_stream(mrb_state *mrb, mrb_input_stream_t *stream, const char *base, mrb_int len, mrb_int pos, mrb_input_stream_free_callback free_cb, void *free_cb_data) +{ + if (free_cb == NULL) { + if (len > 0) { + char *dst_base = (char *)mrb_malloc(mrb, sizeof(char)*len); + memcpy(dst_base, base, len); + stream->base = dst_base; + stream->len = len; + } else { + stream->base = NULL; + stream->len = len; + } + stream->free_cb = default_free_cb; + stream->free_cb_data = NULL; + } else { + stream->base = base; + stream->len = len; + stream->free_cb = free_cb; + stream->free_cb_data = free_cb_data; + } + + stream->pos = pos; +} + +mrb_input_stream_t* +mrb_input_stream_create(mrb_state *mrb, const char *base, mrb_int len, mrb_input_stream_free_callback free_cb, void *free_cb_data) +{ + mrb_input_stream_t *stream = (mrb_input_stream_t *)mrb_malloc(mrb, sizeof(mrb_input_stream_t)); + + setup_stream(mrb, stream, base, len, 0, free_cb, free_cb_data); + return stream; +} + +mrb_value +mrb_input_stream_value(mrb_state *mrb, const char *base, mrb_int len) +{ + mrb_input_stream_t *stream = mrb_input_stream_create(mrb, base, len, NULL, NULL); + struct RClass *c = mrb_class_get(mrb, "InputStream"); + struct RData *d = mrb_data_object_alloc(mrb, c, stream, &mrb_input_stream_type); + + return mrb_obj_value(d); +} + +void +mrb_input_stream_get_data(mrb_state *mrb, mrb_value self, const char **base, mrb_int *len, mrb_int *pos, mrb_input_stream_free_callback *free_cb, void **free_cb_data) +{ + mrb_input_stream_t *stream = DATA_PTR(self); + + if (base != NULL) + *base = stream->base; + if (len != NULL) + *len = stream->len; + if (pos != NULL) + *pos = stream->pos; + if (free_cb != NULL) + *free_cb = stream->free_cb; + if (free_cb_data != NULL) + *free_cb_data = stream->free_cb_data; +} + +void +mrb_input_stream_set_data(mrb_state *mrb, mrb_value self, const char *base, mrb_int len, mrb_int pos, mrb_input_stream_free_callback free_cb, void *free_cb_data) +{ + mrb_input_stream_t *stream = DATA_PTR(self); + + if (stream->free_cb != NULL) + stream->free_cb(mrb, stream->base, stream->len, stream->free_cb_data); + setup_stream(mrb, stream, base, len, pos, free_cb, free_cb_data); +} + +static mrb_value +mrb_input_stream_gets(mrb_state *mrb, mrb_value self) +{ + mrb_input_stream_t *stream = DATA_PTR(self); + mrb_int pos, len; + + assert_is_open(mrb, stream); + + pos = stream->pos; + len = seek_char(stream, '\n'); + if (len < 0) { + return mrb_nil_value(); + } + if (stream->pos + len < stream->len) { + len++; + } + stream->pos += len; + return mrb_str_new(mrb, (stream->base + pos), len); +} + +static mrb_int +seek_char(mrb_input_stream_t *stream, char chr){ + const char *base = stream->base; + size_t len = stream->len; + mrb_int pos = stream->pos; + const char *end = base + len; + const char *start = base + pos; + const char *s = start; + + if (pos >= len) { + return -1; + } + + while (s < end) { + if (*s == chr) { + break; + } + s++; + } + return (s - start); +} + +static mrb_value +mrb_input_stream_read(mrb_state *mrb, mrb_value self) +{ + mrb_int len; + mrb_value buf; + mrb_int n = mrb_get_args(mrb, "|iS", &len, &buf), pos; + mrb_input_stream_t *stream = DATA_PTR(self); + const char *start; + + assert_is_open(mrb, stream); + + pos = stream->pos; + start = stream->base + pos; + + if (pos >= stream->len) { + return mrb_nil_value(); + } + if (n == 0) { + stream->pos = stream->len; + return mrb_str_new(mrb, start, stream->len - pos); + } else { + mrb_int newpos = pos + len; + if (newpos > stream->len) { + newpos = stream->len; + } + stream->pos = newpos; + if (n == 1) { + return mrb_str_new(mrb, start, newpos - pos); + } else { + return mrb_str_cat(mrb, buf, start, newpos - pos); + } + } +} + +static mrb_value +mrb_input_stream_rewind(mrb_state *mrb, mrb_value self) +{ + mrb_input_stream_t *stream = DATA_PTR(self); + assert_is_open(mrb, stream); + stream->pos = 0; + return self; +} + + +static mrb_value +mrb_input_stream_byteindex(mrb_state *mrb, mrb_value self) +{ + mrb_input_stream_t *stream = DATA_PTR(self); + mrb_int chr, n, len; + + assert_is_open(mrb, stream); + + n = mrb_get_args(mrb, "i", &chr); + if (n != 1) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(n)); + } + if (chr < 0 || chr > 255) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "index should be a byte (0 - 255)"); + } + + len = seek_char(stream, chr); + if (len < 0) { + return mrb_nil_value(); + } + + return mrb_fixnum_value(len); +} + + +void +mrb_mruby_input_stream_gem_init(mrb_state* mrb) +{ + struct RClass * c = mrb_define_class(mrb, "InputStream", mrb->object_class); + + mrb_define_method(mrb, c, "gets", mrb_input_stream_gets, MRB_ARGS_NONE()); + mrb_define_method(mrb, c, "read", mrb_input_stream_read, MRB_ARGS_ANY()); + mrb_define_method(mrb, c, "initialize", mrb_input_stream_init, MRB_ARGS_BLOCK()); + mrb_define_method(mrb, c, "rewind", mrb_input_stream_rewind, MRB_ARGS_NONE()); + mrb_define_method(mrb, c, "byteindex", mrb_input_stream_byteindex, MRB_ARGS_ANY()); +} + +void +mrb_mruby_input_stream_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-input-stream/src/mruby_input_stream.h b/web/server/h2o/libh2o/deps/mruby-input-stream/src/mruby_input_stream.h new file mode 100644 index 000000000..39150ad6d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-input-stream/src/mruby_input_stream.h @@ -0,0 +1,19 @@ +/* + * input_stream.h + * + */ +#ifndef mruby_input_stream_h +#define mruby_input_stream_h + +typedef void (*mrb_input_stream_free_callback)(mrb_state *mrb, const char *base, mrb_int len, void *cb_data); + +mrb_value +mrb_input_stream_value(mrb_state *mrb, const char *base, mrb_int len); + +void +mrb_input_stream_get_data(mrb_state *mrb, mrb_value self, const char **base, mrb_int *len, mrb_int *pos, mrb_input_stream_free_callback *free_cb, void **free_cb_data); + +void +mrb_input_stream_set_data(mrb_state *mrb, mrb_value self, const char *base, mrb_int len, mrb_int pos, mrb_input_stream_free_callback free_cb, void *free_cb_data); + +#endif /* input_stream_h */ diff --git a/web/server/h2o/libh2o/deps/mruby-input-stream/test/input_stream.rb b/web/server/h2o/libh2o/deps/mruby-input-stream/test/input_stream.rb new file mode 100644 index 000000000..8201786b1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-input-stream/test/input_stream.rb @@ -0,0 +1,111 @@ +assert('InputStream.new()') do + vec = InputStream.new + assert_equal InputStream, vec.class +end + +assert('InputStream.new("foo")') do + vec = InputStream.new("foo") + assert_equal InputStream, vec.class +end + +assert('InputStream#read') do + vec = InputStream.new("foo") + assert_equal "foo", vec.read +end + +assert('InputStream#read(2)') do + vec = InputStream.new("abcdef") + assert_equal "ab", vec.read(2) + assert_equal "cde", vec.read(3) + assert_equal "f", vec.read(4) + assert_equal nil, vec.read(5) +end + +assert('InputStream#read(2, "")') do + vec = InputStream.new("abcdef") + s1 = "" + assert_equal "ab", vec.read(2, s1) + assert_equal "ab", s1 + assert_equal "abcde", vec.read(3, s1) + assert_equal "abcde", s1 + assert_equal "abcdef", vec.read(4, s1) + assert_equal "abcdef", s1 + assert_equal nil, vec.read(5, s1) + assert_equal "abcdef", s1 +end + +assert('InputStream#read(10)') do + vec = InputStream.new("abc") + assert_equal "abc", vec.read(10) + assert_equal nil, vec.read(10) +end + +assert('InputStream#read ""') do + vec = InputStream.new("") + assert_equal nil, vec.read(2) + assert_equal nil, vec.read(0) + assert_equal nil, vec.read(2) +end + +assert('InputStream#read(0)') do + vec = InputStream.new("foo") + assert_equal "", vec.read(0) + assert_equal "", vec.read(0) + assert_equal "f", vec.read(1) +end + + +assert('InputStream#gets') do + vec = InputStream.new("foo") + assert_equal "foo", vec.gets + assert_equal nil, vec.gets +end + +assert('InputStream#gets ""') do + vec = InputStream.new("") + assert_equal nil, vec.gets +end + +assert('InputStream#gets long') do + vec = InputStream.new("foo\nbar\nbuz\n") + assert_equal "foo\n", vec.gets + assert_equal "bar\n", vec.gets + assert_equal "buz\n", vec.gets + assert_equal nil, vec.gets +end + +assert('InputStream#gets NN') do + vec = InputStream.new("\n\nbuz") + assert_equal "\n", vec.gets + assert_equal "\n", vec.gets + assert_equal "buz", vec.gets + assert_equal nil, vec.gets +end + +assert('InputStream#each') do + vec = InputStream.new("foo\nbar\nbuz\nzzz") + buf = [] + vec.each do |line| + buf << line + end + assert_equal ["foo\n", "bar\n", "buz\n", "zzz"], buf +end + +assert('InputStream#each ""') do + vec = InputStream.new("") + buf = [] + vec.each do |line| + buf << line + end + assert_equal [], buf +end + +assert('InputStream#rewind') do + vec = InputStream.new("abcdef") + assert_equal "ab", vec.read(2) + assert_equal "cde", vec.read(3) + vec.rewind + assert_equal "abcd", vec.read(4) + assert_equal "ef", vec.read(5) +end + diff --git a/web/server/h2o/libh2o/deps/mruby-io/.gitignore b/web/server/h2o/libh2o/deps/mruby-io/.gitignore new file mode 100644 index 000000000..ceeb05b41 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/.gitignore @@ -0,0 +1 @@ +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-io/.travis.yml b/web/server/h2o/libh2o/deps/mruby-io/.travis.yml new file mode 100644 index 000000000..ffe227284 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-io/README.md b/web/server/h2o/libh2o/deps/mruby-io/README.md new file mode 100644 index 000000000..d7fa6945b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/README.md @@ -0,0 +1,185 @@ +mruby-io +======== + +IO, File module for mruby + + +## Implemented methods + +### IO + - http://doc.ruby-lang.org/ja/1.9.3/class/IO.html + +| method | mruby-io | memo | +| ------------------------- | -------- | ---- | +| IO.binread | | | +| IO.binwrite | | | +| IO.copy_stream | | | +| IO.new, IO.for_fd, IO.open | o | | +| IO.foreach | | | +| IO.pipe | | | +| IO.popen | o | | +| IO.read | o | | +| IO.readlines | | | +| IO.select | o | | +| IO.sysopen | o | | +| IO.try_convert | | | +| IO.write | | | +| IO#<< | | | +| IO#advise | | | +| IO#autoclose= | | | +| IO#autoclose? | | | +| IO#binmode | | | +| IO#binmode? | | | +| IO#bytes | | obsolete | +| IO#chars | | obsolete | +| IO#clone, IO#dup | | | +| IO#close | o | | +| IO#close_on_exec= | o | | +| IO#close_on_exec? | o | | +| IO#close_read | | | +| IO#close_write | | | +| IO#closed? | o | | +| IO#codepoints | | obsolete | +| IO#each_byte | o | | +| IO#each_char | o | | +| IO#each_codepoint | | | +| IO#each_line | o | | +| IO#eof, IO#eof? | o | | +| IO#external_encoding | | | +| IO#fcntl | | | +| IO#fdatasync | | | +| IO#fileno, IO#to_i | o | | +| IO#flush | o | | +| IO#fsync | | | +| IO#getbyte | | | +| IO#getc | o | | +| IO#gets | o | | +| IO#internal_encoding | | | +| IO#ioctl | | | +| IO#isatty, IO#tty? | | | +| IO#lineno | | | +| IO#lineno= | | | +| IO#lines | | obsolete | +| IO#pid | o | | +| IO#pos, IO#tell | o | | +| IO#pos= | o | | +| IO#print | o | | +| IO#printf | o | | +| IO#putc | | | +| IO#puts | o | | +| IO#read | o | | +| IO#read_nonblock | | | +| IO#readbyte | | | +| IO#readchar | o | | +| IO#readline | o | | +| IO#readlines | o | | +| IO#readpartial | | | +| IO#reopen | | | +| IO#rewind | | | +| IO#seek | o | | +| IO#set_encoding | | | +| IO#stat | | | +| IO#sync | o | | +| IO#sync= | o | | +| IO#sysread | o | | +| IO#sysseek | o | | +| IO#syswrite | o | | +| IO#to_io | | | +| IO#ungetbyte | | | +| IO#ungetc | o | | +| IO#write | o | | +| IO#write_nonblock | | | + +### File + - http://doc.ruby-lang.org/ja/1.9.3/class/File.html + +| method | mruby-io | memo | +| --------------------------- | -------- | ---- | +| File.absolute_path | | | +| File.atime | | | +| File.basename | o | | +| File.blockdev? | | FileTest | +| File.chardev? | | FileTest | +| File.chmod | | | +| File.chown | | | +| File.ctime | | | +| File.delete, File.unlink | o | | +| File.directory? | o | FileTest | +| File.dirname | o | | +| File.executable? | | FileTest | +| File.executable_real? | | FileTest | +| File.exist?, exists? | o | FileTest | +| File.expand_path | o | | +| File.extname | o | | +| File.file? | o | FileTest | +| File.fnmatch, File.fnmatch? | | | +| File.ftype | | | +| File.grpowned? | | FileTest | +| File.identical? | | FileTest | +| File.join | o | | +| File.lchmod | | | +| File.lchown | | | +| File.link | | | +| File.lstat | | | +| File.mtime | | | +| File.new, File.open | o | | +| File.owned? | | FileTest | +| File.path | | | +| File.pipe? | o | FileTest | +| File.readable? | | FileTest | +| File.readable_real? | | FileTest | +| File.readlink | | | +| File.realdirpath | | | +| File.realpath | o | | +| File.rename | o | | +| File.setgid? | | FileTest | +| File.setuid? | | FileTest | +| File.size | o | | +| File.size? | o | FileTest | +| File.socket? | o | FileTest | +| File.split | | | +| File.stat | | | +| File.sticky? | | FileTest | +| File.symlink | | | +| File.symlink? | o | FileTest | +| File.truncate | | | +| File.umask | o | | +| File.utime | | | +| File.world_readable? | | | +| File.world_writable? | | | +| File.writable? | | FileTest | +| File.writable_real? | | FileTest | +| File.zero? | o | FileTest | +| File#atime | | | +| File#chmod | | | +| File#chown | | | +| File#ctime | | | +| File#flock | o | | +| File#lstat | | | +| File#mtime | | | +| File#path, File#to_path | o | | +| File#size | | | +| File#truncate | | | + + +## License + +Copyright (c) 2013 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/web/server/h2o/libh2o/deps/mruby-io/include/mruby/ext/io.h b/web/server/h2o/libh2o/deps/mruby-io/include/mruby/ext/io.h new file mode 100644 index 000000000..3107f1053 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/include/mruby/ext/io.h @@ -0,0 +1,36 @@ +/* +** io.h - IO class +*/ + +#ifndef MRUBY_IO_H +#define MRUBY_IO_H + +#if defined(__cplusplus) +extern "C" { +#endif + +struct mrb_io { + int fd; /* file descriptor, or -1 */ + int fd2; /* file descriptor to write if it's different from fd, or -1 */ + int pid; /* child's pid (for pipes) */ + unsigned int writable:1, + sync:1; +}; + +#define FMODE_READABLE 0x00000001 +#define FMODE_WRITABLE 0x00000002 +#define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE) +#define FMODE_BINMODE 0x00000004 +#define FMODE_APPEND 0x00000040 +#define FMODE_CREATE 0x00000080 +#define FMODE_TRUNC 0x00000800 + +#define E_IO_ERROR (mrb_class_get(mrb, "IOError")) +#define E_EOF_ERROR (mrb_class_get(mrb, "EOFError")) + +mrb_value mrb_io_fileno(mrb_state *mrb, mrb_value io); + +#if defined(__cplusplus) +} /* extern "C" { */ +#endif +#endif /* MRUBY_IO_H */ diff --git a/web/server/h2o/libh2o/deps/mruby-io/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-io/mrbgem.rake new file mode 100644 index 000000000..8120f7832 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/mrbgem.rake @@ -0,0 +1,16 @@ +MRuby::Gem::Specification.new('mruby-io') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan Inc.' + + spec.cc.include_paths << "#{build.root}/src" + + case RUBY_PLATFORM + when /mingw|mswin/ + spec.linker.libraries += ['Ws2_32'] + #spec.cc.include_paths += ["C:/Windows/system/include"] + spec.linker.library_paths += ["C:/Windows/system"] + end + if build.kind_of?(MRuby::CrossBuild) && %w(x86_64-w64-mingw32 i686-w64-mingw32).include?(build.host_target) + spec.linker.libraries += ['ws2_32'] + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-io/mrblib/file.rb b/web/server/h2o/libh2o/deps/mruby-io/mrblib/file.rb new file mode 100644 index 000000000..aa0981930 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/mrblib/file.rb @@ -0,0 +1,173 @@ +class File < IO + include Enumerable + + class FileError < Exception; end + class NoFileError < FileError; end + class UnableToStat < FileError; end + class PermissionError < FileError; end + + attr_accessor :path + + def initialize(fd_or_path, mode = "r", perm = 0666) + if fd_or_path.kind_of? Fixnum + super(fd_or_path, mode) + else + @path = fd_or_path + fd = IO.sysopen(@path, mode, perm) + super(fd, mode) + end + end + + def self.join(*names) + if names.size == 0 + "" + elsif names.size == 1 + names[0] + else + if names[0][-1] == File::SEPARATOR + s = names[0][0..-2] + else + s = names[0].dup + end + (1..names.size-2).each { |i| + t = names[i] + if t[0] == File::SEPARATOR and t[-1] == File::SEPARATOR + t = t[1..-2] + elsif t[0] == File::SEPARATOR + t = t[1..-1] + elsif t[-1] == File::SEPARATOR + t = t[0..-2] + end + s += File::SEPARATOR + t if t != "" + } + if names[-1][0] == File::SEPARATOR + s += File::SEPARATOR + names[-1][1..-1] + else + s += File::SEPARATOR + names[-1] + end + s + end + end + + def self.expand_path(path, default_dir = '.') + def concat_path(path, base_path) + if path[0] == "/" || path[1] == ':' # Windows root! + expanded_path = path + elsif path[0] == "~" + if (path[1] == "/" || path[1] == nil) + dir = path[1, path.size] + home_dir = _gethome + + unless home_dir + raise ArgumentError, "couldn't find HOME environment -- expanding '~'" + end + + expanded_path = home_dir + expanded_path += dir if dir + expanded_path += "/" + else + splitted_path = path.split("/") + user = splitted_path[0][1, splitted_path[0].size] + dir = "/" + splitted_path[1, splitted_path.size].join("/") + + home_dir = _gethome(user) + + unless home_dir + raise ArgumentError, "user #{user} doesn't exist" + end + + expanded_path = home_dir + expanded_path += dir if dir + expanded_path += "/" + end + else + expanded_path = concat_path(base_path, _getwd) + expanded_path += "/" + path + end + + expanded_path + end + + expanded_path = concat_path(path, default_dir) + expand_path_array = [] + while expanded_path.include?('//') + expanded_path = expanded_path.gsub('//', '/') + end + + if expanded_path == "/" + expanded_path + else + expanded_path.split('/').each do |path_token| + if path_token == '..' + if expand_path_array.size > 1 + expand_path_array.pop + end + elsif path_token == '.' + # nothing to do. + else + expand_path_array << path_token + end + end + + expand_path = expand_path_array.join("/") + expand_path.empty? ? '/' : expand_path + end + end + + def self.foreach(file) + if block_given? + self.open(file) do |f| + f.each {|l| yield l} + end + else + return self.new(file) + end + end + + def self.directory?(file) + FileTest.directory?(file) + end + + def self.exist?(file) + FileTest.exist?(file) + end + + def self.exists?(file) + FileTest.exists?(file) + end + + def self.file?(file) + FileTest.file?(file) + end + + def self.pipe?(file) + FileTest.pipe?(file) + end + + def self.size(file) + FileTest.size(file) + end + + def self.size?(file) + FileTest.size?(file) + end + + def self.socket?(file) + FileTest.socket?(file) + end + + def self.symlink?(file) + FileTest.symlink?(file) + end + + def self.zero?(file) + FileTest.zero?(file) + end + + def self.extname(filename) + fname = self.basename(filename) + return '' if fname[0] == '.' || fname.index('.').nil? + ext = fname.split('.').last + ext.empty? ? '' : ".#{ext}" + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-io/mrblib/file_constants.rb b/web/server/h2o/libh2o/deps/mruby-io/mrblib/file_constants.rb new file mode 100644 index 000000000..a68ee2598 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/mrblib/file_constants.rb @@ -0,0 +1,29 @@ +class File + module Constants + RDONLY = 0 + WRONLY = 1 + RDWR = 2 + NONBLOCK = 4 + APPEND = 8 + + BINARY = 0 + SYNC = 128 + NOFOLLOW = 256 + CREAT = 512 + TRUNC = 1024 + EXCL = 2048 + + NOCTTY = 131072 + DSYNC = 4194304 + + FNM_SYSCASE = 0 + FNM_NOESCAPE = 1 + FNM_PATHNAME = 2 + FNM_DOTMATCH = 4 + FNM_CASEFOLD = 8 + end +end + +class File + include File::Constants +end diff --git a/web/server/h2o/libh2o/deps/mruby-io/mrblib/io.rb b/web/server/h2o/libh2o/deps/mruby-io/mrblib/io.rb new file mode 100644 index 000000000..c838b96e5 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/mrblib/io.rb @@ -0,0 +1,372 @@ +## +# IO + +class IOError < StandardError; end +class EOFError < IOError; end + +class IO + SEEK_SET = 0 + SEEK_CUR = 1 + SEEK_END = 2 + + BUF_SIZE = 4096 + + def self.open(*args, &block) + io = self.new(*args) + + return io unless block + + begin + yield io + ensure + begin + io.close unless io.closed? + rescue StandardError + end + end + end + + def self.popen(command, mode = 'r', &block) + io = self._popen(command, mode) + return io unless block + + begin + yield io + ensure + begin + io.close unless io.closed? + rescue IOError + # nothing + end + end + end + + + def self.read(path, length=nil, offset=nil, opt=nil) + if not opt.nil? # 4 arguments + offset ||= 0 + elsif not offset.nil? # 3 arguments + if offset.is_a? Hash + opt = offset + offset = 0 + else + opt = {} + end + elsif not length.nil? # 2 arguments + if length.is_a? Hash + opt = length + offset = 0 + length = nil + else + offset = 0 + opt = {} + end + else # only 1 argument + opt = {} + offset = 0 + length = nil + end + + str = "" + fd = -1 + io = nil + begin + if path[0] == "|" + io = IO.popen(path[1..-1], (opt[:mode] || "r")) + else + fd = IO.sysopen(path) + io = IO.open(fd, opt[:mode] || "r") + end + io.seek(offset) if offset > 0 + str = io.read(length) + ensure + if io + io.close + elsif fd != -1 + IO._sysclose(fd) + end + end + str + end + + def flush + # mruby-io always writes immediately (no output buffer). + raise IOError, "closed stream" if self.closed? + self + end + + def write(string) + str = string.is_a?(String) ? string : string.to_s + return str.size unless str.size > 0 + + len = syswrite(str) + if len != -1 + @pos += len + return len + end + + raise IOError + end + + def eof? + return true if @buf && @buf.size > 0 + + ret = false + char = '' + + begin + char = sysread(1) + rescue EOFError => e + ret = true + ensure + _ungets(char) + end + + ret + end + alias_method :eof, :eof? + + def pos + raise IOError if closed? + @pos + end + alias_method :tell, :pos + + def pos=(i) + seek(i, SEEK_SET) + end + + def seek(i, whence = SEEK_SET) + raise IOError if closed? + @pos = sysseek(i, whence) + @buf = '' + 0 + end + + def _read_buf + return @buf if @buf && @buf.size > 0 + @buf = sysread(BUF_SIZE) + end + + def _ungets(substr) + raise TypeError.new "expect String, got #{substr.class}" unless substr.is_a?(String) + raise IOError if @pos == 0 || @pos.nil? + @pos -= substr.size + if @buf.empty? + @buf = substr + else + @buf = substr + @buf + end + nil + end + + def ungetc(char) + raise IOError if @pos == 0 || @pos.nil? + _ungets(char) + nil + end + + def read(length = nil) + unless length.nil? + unless length.is_a? Fixnum + raise TypeError.new "can't convert #{length.class} into Integer" + end + if length < 0 + raise ArgumentError.new "negative length: #{length} given" + end + if length == 0 + return "" # easy case + end + end + + array = [] + start_pos = @pos + while 1 + begin + _read_buf + rescue EOFError => e + array = nil if array.empty? and (not length.nil?) and length != 0 + break + end + + if length && (@pos - start_pos + @buf.size) >= length + len = length - (@pos - start_pos) + array.push @buf[0, len] + @pos += len + @buf = @buf[len, @buf.size - len] + break + else + array.push @buf + @pos += @buf.size + @buf = '' + end + end + + array && array.join + end + + def readline(arg = $/, limit = nil) + case arg + when String + rs = arg + when Fixnum + rs = $/ + limit = arg + else + raise ArgumentError + end + + if rs.nil? + return read + end + + if rs == "" + rs = $/ + $/ + end + + array = [] + start_pos = @pos + while 1 + begin + _read_buf + rescue EOFError => e + array = nil if array.empty? + break + end + + if limit && (@pos - start_pos + @buf.size) >= limit + len = limit - (@pos - start_pos) + array.push @buf[0, len] + @pos += len + @buf = @buf[len, @buf.size - len] + break + elsif idx = @buf.index(rs) + len = idx + rs.size + array.push @buf[0, len] + @pos += len + @buf = @buf[len, @buf.size - len] + break + else + array.push @buf + @pos += @buf.size + @buf = '' + end + end + + raise EOFError.new "end of file reached" if array.nil? + + array.join + end + + def gets(*args) + begin + readline(*args) + rescue EOFError => e + nil + end + end + + def readchar + _read_buf + c = @buf[0] + @buf = @buf[1, @buf.size] + @pos += 1 + c + end + + def getc + begin + readchar + rescue EOFError => e + nil + end + end + + # 15.2.20.5.3 + def each(&block) + while line = self.gets + block.call(line) + end + self + end + + # 15.2.20.5.4 + def each_byte(&block) + while char = self.getc + block.call(char) + end + self + end + + # 15.2.20.5.5 + alias each_line each + + alias each_char each_byte + + def readlines + ary = [] + while (line = gets) + ary << line + end + ary + end + + def puts(*args) + i = 0 + len = args.size + while i < len + s = args[i].to_s + write s + write "\n" if (s[-1] != "\n") + i += 1 + end + write "\n" if len == 0 + nil + end + + def print(*args) + i = 0 + len = args.size + while i < len + write args[i].to_s + i += 1 + end + end + + def printf(*args) + write sprintf(*args) + nil + end + + alias_method :to_i, :fileno +end + +STDIN = IO.open(0, "r") +STDOUT = IO.open(1, "w") +STDERR = IO.open(2, "w") + +$stdin = STDIN +$stdout = STDOUT +$stderr = STDERR + +module Kernel + def print(*args) + STDOUT.print(*args) + end + + def puts(*args) + STDOUT.puts(*args) + end + + def printf(*args) + STDOUT.printf(*args) + end + + def gets(*args) + STDIN.gets(*args) + end + + def getc(*args) + STDIN.getc(*args) + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-io/mrblib/kernel.rb b/web/server/h2o/libh2o/deps/mruby-io/mrblib/kernel.rb new file mode 100644 index 000000000..484b50160 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/mrblib/kernel.rb @@ -0,0 +1,15 @@ +module Kernel + def self.`(cmd) + IO.popen(cmd) { |io| io.read } + end + + def open(file, *rest, &block) + raise ArgumentError unless file.is_a?(String) + + if file[0] == "|" + IO.popen(file[1..-1], *rest, &block) + else + File.open(file, *rest, &block) + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-io/run_test.rb b/web/server/h2o/libh2o/deps/mruby-io/run_test.rb new file mode 100644 index 000000000..444d18fda --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/run_test.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem :git => 'https://github.com/iij/mruby-env.git' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-io/src/file.c b/web/server/h2o/libh2o/deps/mruby-io/src/file.c new file mode 100644 index 000000000..feb8558ed --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/src/file.c @@ -0,0 +1,325 @@ +/* +** file.c - File class +*/ + +#include "mruby.h" +#include "mruby/class.h" +#include "mruby/data.h" +#include "mruby/string.h" +#include "mruby/ext/io.h" + +#if MRUBY_RELEASE_NO < 10000 +#include "error.h" +#else +#include "mruby/error.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#include <fcntl.h> +#include <limits.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#if defined(_WIN32) || defined(_WIN64) + #define NULL_FILE "NUL" + #define UNLINK _unlink + #define GETCWD _getcwd + #define CHMOD(a, b) 0 + #define MAXPATHLEN 1024 + #if !defined(PATH_MAX) + #define PATH_MAX _MAX_PATH + #endif + #define realpath(N,R) _fullpath((R),(N),_MAX_PATH) + #include <direct.h> +#else + #define NULL_FILE "/dev/null" + #include <unistd.h> + #define UNLINK unlink + #define GETCWD getcwd + #define CHMOD(a, b) chmod(a,b) + #include <sys/file.h> + #include <libgen.h> + #include <sys/param.h> + #include <pwd.h> +#endif + +#if defined(_WIN32) || defined(_WIN64) + #define PATH_SEPARATOR ";" + #define FILE_SEPARATOR "\\" +#else + #define PATH_SEPARATOR ":" + #define FILE_SEPARATOR "/" +#endif + +#ifndef LOCK_SH +#define LOCK_SH 1 +#endif +#ifndef LOCK_EX +#define LOCK_EX 2 +#endif +#ifndef LOCK_NB +#define LOCK_NB 4 +#endif +#ifndef LOCK_UN +#define LOCK_UN 8 +#endif + +#define STAT(p, s) stat(p, s) + + +mrb_value +mrb_file_s_umask(mrb_state *mrb, mrb_value klass) +{ +#if defined(_WIN32) || defined(_WIN64) + /* nothing to do on windows */ + return mrb_fixnum_value(0); + +#else + mrb_int mask, omask; + if (mrb_get_args(mrb, "|i", &mask) == 0) { + omask = umask(0); + umask(omask); + } else { + omask = umask(mask); + } + return mrb_fixnum_value(omask); +#endif +} + +static mrb_value +mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) +{ + mrb_value *argv; + mrb_value pathv; + mrb_int argc, i; + const char *path; + + mrb_get_args(mrb, "*", &argv, &argc); + for (i = 0; i < argc; i++) { + pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str"); + path = mrb_string_value_cstr(mrb, &pathv); + if (UNLINK(path) < 0) { + mrb_sys_fail(mrb, path); + } + } + return mrb_fixnum_value(argc); +} + +static mrb_value +mrb_file_s_rename(mrb_state *mrb, mrb_value obj) +{ + mrb_value from, to; + const char *src, *dst; + + mrb_get_args(mrb, "SS", &from, &to); + src = mrb_string_value_cstr(mrb, &from); + dst = mrb_string_value_cstr(mrb, &to); + if (rename(src, dst) < 0) { + if (CHMOD(dst, 0666) == 0 && UNLINK(dst) == 0 && rename(src, dst) == 0) { + return mrb_fixnum_value(0); + } + mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to))); + } + return mrb_fixnum_value(0); +} + +static mrb_value +mrb_file_dirname(mrb_state *mrb, mrb_value klass) +{ + #if defined(_WIN32) || defined(_WIN64) + char dname[_MAX_DIR], vname[_MAX_DRIVE]; + char buffer[_MAX_DRIVE + _MAX_DIR]; + char *path; + mrb_value s; + mrb_get_args(mrb, "S", &s); + path = mrb_str_to_cstr(mrb, s); + _splitpath((const char*)path, vname, dname, NULL, NULL); + snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname); + return mrb_str_new_cstr(mrb, buffer); + #else + char *dname, *path; + mrb_value s; + mrb_get_args(mrb, "S", &s); + path = mrb_str_to_cstr(mrb, s); + + if ((dname = dirname(path)) == NULL) { + mrb_sys_fail(mrb, "dirname"); + } + #endif + return mrb_str_new_cstr(mrb, dname); +} + +static mrb_value +mrb_file_basename(mrb_state *mrb, mrb_value klass) +{ + #if defined(_WIN32) || defined(_WIN64) + char bname[_MAX_DIR]; + char extname[_MAX_EXT]; + char *path; + char buffer[_MAX_DIR + _MAX_EXT]; + mrb_value s; + mrb_get_args(mrb, "S", &s); + path = mrb_str_to_cstr(mrb, s); + _splitpath((const char*)path, NULL, NULL, bname, extname); + snprintf(buffer, _MAX_DIR + _MAX_EXT, "%s%s", bname, extname); + return mrb_str_new_cstr(mrb, buffer); + #else + char *bname, *path; + mrb_value s; + mrb_get_args(mrb, "S", &s); + path = mrb_str_to_cstr(mrb, s); + if ((bname = basename(path)) == NULL) { + mrb_sys_fail(mrb, "basename"); + } + return mrb_str_new_cstr(mrb, bname); + #endif +} + +static mrb_value +mrb_file_realpath(mrb_state *mrb, mrb_value klass) +{ + mrb_value pathname, dir_string, s, result; + int argc; + char *cpath; + + argc = mrb_get_args(mrb, "S|S", &pathname, &dir_string); + if (argc == 2) { + s = mrb_str_dup(mrb, dir_string); + s = mrb_str_append(mrb, s, mrb_str_new_cstr(mrb, FILE_SEPARATOR)); + s = mrb_str_append(mrb, s, pathname); + pathname = s; + } + cpath = mrb_str_to_cstr(mrb, pathname); + result = mrb_str_buf_new(mrb, PATH_MAX); + if (realpath(cpath, RSTRING_PTR(result)) == NULL) + mrb_sys_fail(mrb, cpath); + mrb_str_resize(mrb, result, strlen(RSTRING_PTR(result))); + return result; +} + +mrb_value +mrb_file__getwd(mrb_state *mrb, mrb_value klass) +{ + mrb_value path; + + path = mrb_str_buf_new(mrb, MAXPATHLEN); + if (GETCWD(RSTRING_PTR(path), MAXPATHLEN) == NULL) { + mrb_sys_fail(mrb, "getcwd(2)"); + } + mrb_str_resize(mrb, path, strlen(RSTRING_PTR(path))); + return path; +} + +static int +mrb_file_is_absolute_path(const char *path) +{ + return (path[0] == '/'); +} + +static mrb_value +mrb_file__gethome(mrb_state *mrb, mrb_value klass) +{ +#ifndef _WIN32 + mrb_value username; + int argc; + char *home; + + argc = mrb_get_args(mrb, "|S", &username); + if (argc == 0) { + home = getenv("HOME"); + if (home == NULL) { + return mrb_nil_value(); + } + if (!mrb_file_is_absolute_path(home)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home"); + } + } else { + const char *cuser = mrb_str_to_cstr(mrb, username); + struct passwd *pwd = getpwnam(cuser); + if (pwd == NULL) { + return mrb_nil_value(); + } + home = pwd->pw_dir; + if (!mrb_file_is_absolute_path(home)) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%S", username); + } + } + return mrb_str_new_cstr(mrb, home); +#else + + return mrb_nil_value(); +#endif +} + +#ifndef _WIN32 +mrb_value +mrb_file_flock(mrb_state *mrb, mrb_value self) +{ +#if defined(sun) + mrb_raise(mrb, E_RUNTIME_ERROR, "flock is not supported on Illumos/Solaris"); +#else + mrb_int operation; + int fd; + + mrb_get_args(mrb, "i", &operation); + fd = mrb_fixnum(mrb_io_fileno(mrb, self)); + + while (flock(fd, operation) == -1) { + switch (errno) { + case EINTR: + /* retry */ + break; + case EAGAIN: /* NetBSD */ +#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: /* FreeBSD OpenBSD Linux */ +#endif + if (operation & LOCK_NB) { + return mrb_false_value(); + } + /* FALLTHRU - should not happen */ + default: + mrb_sys_fail(mrb, "flock failed"); + break; + } + } +#endif + return mrb_fixnum_value(0); +} +#endif + +void +mrb_init_file(mrb_state *mrb) +{ + struct RClass *io, *file, *cnst; + + io = mrb_class_get(mrb, "IO"); + file = mrb_define_class(mrb, "File", io); + MRB_SET_INSTANCE_TT(file, MRB_TT_DATA); + mrb_define_class_method(mrb, file, "umask", mrb_file_s_umask, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "delete", mrb_file_s_unlink, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, MRB_ARGS_REQ(2)); + + mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "basename", mrb_file_basename, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "realpath", mrb_file_realpath, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1)); + + #ifndef _WIN32 + mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1)); + #endif + + cnst = mrb_define_module_under(mrb, file, "Constants"); + mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH)); + mrb_define_const(mrb, cnst, "LOCK_EX", mrb_fixnum_value(LOCK_EX)); + mrb_define_const(mrb, cnst, "LOCK_UN", mrb_fixnum_value(LOCK_UN)); + mrb_define_const(mrb, cnst, "LOCK_NB", mrb_fixnum_value(LOCK_NB)); + mrb_define_const(mrb, cnst, "SEPARATOR", mrb_str_new_cstr(mrb, FILE_SEPARATOR)); + mrb_define_const(mrb, cnst, "PATH_SEPARATOR", mrb_str_new_cstr(mrb, PATH_SEPARATOR)); + mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, NULL_FILE)); + +} diff --git a/web/server/h2o/libh2o/deps/mruby-io/src/file_test.c b/web/server/h2o/libh2o/deps/mruby-io/src/file_test.c new file mode 100644 index 000000000..6c380c4a5 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/src/file_test.c @@ -0,0 +1,365 @@ +/* +** file.c - File class +*/ + +#include "mruby.h" +#include "mruby/class.h" +#include "mruby/data.h" +#include "mruby/string.h" +#include "mruby/ext/io.h" + +#if MRUBY_RELEASE_NO < 10000 +#include "error.h" +#else +#include "mruby/error.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#if defined(_WIN32) || defined(_WIN64) + #define LSTAT stat + #include <winsock.h> +#else + #define LSTAT lstat + #include <sys/file.h> + #include <sys/param.h> + #include <sys/wait.h> + #include <libgen.h> + #include <pwd.h> + #include <unistd.h> +#endif + +#include <fcntl.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +extern struct mrb_data_type mrb_io_type; + +static int +mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) +{ + mrb_value tmp; + mrb_value io_klass, str_klass; + + io_klass = mrb_obj_value(mrb_class_get(mrb, "IO")); + str_klass = mrb_obj_value(mrb_class_get(mrb, "String")); + + tmp = mrb_funcall(mrb, obj, "is_a?", 1, io_klass); + if (mrb_test(tmp)) { + struct mrb_io *fptr; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type); + + if (fptr && fptr->fd >= 0) { + return fstat(fptr->fd, st); + } + + mrb_raise(mrb, E_IO_ERROR, "closed stream"); + return -1; + } + + tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); + if (mrb_test(tmp)) { + if (do_lstat) { + return LSTAT(mrb_str_to_cstr(mrb, obj), st); + } else { + return stat(mrb_str_to_cstr(mrb, obj), st); + } + } + + return -1; +} + +static int +mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st) +{ + return mrb_stat0(mrb, obj, st, 0); +} + +static int +mrb_lstat(mrb_state *mrb, mrb_value obj, struct stat *st) +{ + return mrb_stat0(mrb, obj, st, 1); +} + +/* + * Document-method: directory? + * + * call-seq: + * File.directory?(file_name) -> true or false + * + * Returns <code>true</code> if the named file is a directory, + * or a symlink that points at a directory, and <code>false</code> + * otherwise. + * + * File.directory?(".") + */ + +mrb_value +mrb_filetest_s_directory_p(mrb_state *mrb, mrb_value klass) +{ +#ifndef S_ISDIR +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (S_ISDIR(st.st_mode)) + return mrb_true_value(); + + return mrb_false_value(); +} + +/* + * call-seq: + * File.pipe?(file_name) -> true or false + * + * Returns <code>true</code> if the named file is a pipe. + */ + +mrb_value +mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass) +{ +#ifdef S_IFIFO +# ifndef S_ISFIFO +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# endif + + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (S_ISFIFO(st.st_mode)) + return mrb_true_value(); + +#endif + return mrb_false_value(); +} + +/* + * call-seq: + * File.symlink?(file_name) -> true or false + * + * Returns <code>true</code> if the named file is a symbolic link. + */ + +mrb_value +mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass) +{ +#ifndef S_ISLNK +# ifdef _S_ISLNK +# define S_ISLNK(m) _S_ISLNK(m) +# else +# ifdef _S_IFLNK +# define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK) +# else +# ifdef S_IFLNK +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +# endif +# endif +# endif +#endif + +#ifdef S_ISLNK + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_lstat(mrb, obj, &st) == -1) + return mrb_false_value(); + if (S_ISLNK(st.st_mode)) + return mrb_true_value(); +#endif + + return mrb_false_value(); +} + +/* + * call-seq: + * File.socket?(file_name) -> true or false + * + * Returns <code>true</code> if the named file is a socket. + */ + +mrb_value +mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass) +{ +#ifndef S_ISSOCK +# ifdef _S_ISSOCK +# define S_ISSOCK(m) _S_ISSOCK(m) +# else +# ifdef _S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK) +# else +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# endif +# endif +# endif +#endif + +#ifdef S_ISSOCK + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (S_ISSOCK(st.st_mode)) + return mrb_true_value(); +#endif + + return mrb_false_value(); +} + +/* + * call-seq: + * File.exist?(file_name) -> true or false + * File.exists?(file_name) -> true or false + * + * Return <code>true</code> if the named file exists. + */ + +mrb_value +mrb_filetest_s_exist_p(mrb_state *mrb, mrb_value klass) +{ + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + + return mrb_true_value(); +} + +/* + * call-seq: + * File.file?(file_name) -> true or false + * + * Returns <code>true</code> if the named file exists and is a + * regular file. + */ + +mrb_value +mrb_filetest_s_file_p(mrb_state *mrb, mrb_value klass) +{ +#ifndef S_ISREG +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (S_ISREG(st.st_mode)) + return mrb_true_value(); + + return mrb_false_value(); +} + +/* + * call-seq: + * File.zero?(file_name) -> true or false + * + * Returns <code>true</code> if the named file exists and has + * a zero size. + */ + +mrb_value +mrb_filetest_s_zero_p(mrb_state *mrb, mrb_value klass) +{ + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (st.st_size == 0) + return mrb_true_value(); + + return mrb_false_value(); +} + +/* + * call-seq: + * File.size(file_name) -> integer + * + * Returns the size of <code>file_name</code>. + * + * _file_name_ can be an IO object. + */ + +mrb_value +mrb_filetest_s_size(mrb_state *mrb, mrb_value klass) +{ + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + mrb_sys_fail(mrb, "mrb_stat"); + + return mrb_fixnum_value(st.st_size); +} + +/* + * call-seq: + * File.size?(file_name) -> Integer or nil + * + * Returns +nil+ if +file_name+ doesn't exist or has zero size, the size of the + * file otherwise. + */ + +mrb_value +mrb_filetest_s_size_p(mrb_state *mrb, mrb_value klass) +{ + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_nil_value(); + if (st.st_size == 0) + return mrb_nil_value(); + + return mrb_fixnum_value(st.st_size); +} + +void +mrb_init_file_test(mrb_state *mrb) +{ + struct RClass *f; + + f = mrb_define_class(mrb, "FileTest", mrb->object_class); + + mrb_define_class_method(mrb, f, "directory?", mrb_filetest_s_directory_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "exist?", mrb_filetest_s_exist_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "exists?", mrb_filetest_s_exist_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "file?", mrb_filetest_s_file_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "pipe?", mrb_filetest_s_pipe_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "size", mrb_filetest_s_size, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "size?", mrb_filetest_s_size_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "socket?", mrb_filetest_s_socket_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "symlink?", mrb_filetest_s_symlink_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "zero?", mrb_filetest_s_zero_p, MRB_ARGS_REQ(1)); +} diff --git a/web/server/h2o/libh2o/deps/mruby-io/src/io.c b/web/server/h2o/libh2o/deps/mruby-io/src/io.c new file mode 100644 index 000000000..1d2f98f3c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/src/io.c @@ -0,0 +1,941 @@ +/* +** io.c - IO class +*/ + +#include "mruby.h" +#include "mruby/array.h" +#include "mruby/class.h" +#include "mruby/data.h" +#include "mruby/hash.h" +#include "mruby/string.h" +#include "mruby/variable.h" +#include "mruby/ext/io.h" + +#if MRUBY_RELEASE_NO < 10000 +#include "error.h" +#else +#include "mruby/error.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#if defined(_WIN32) || defined(_WIN64) + #include <winsock.h> + #include <io.h> + #define open _open + #define close _close + #define read _read + #define write _write + #define lseek _lseek +#else + #include <sys/wait.h> + #include <unistd.h> +#endif + +#include <fcntl.h> + +#include <errno.h> +#include <stdio.h> +#include <string.h> + + +static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr); +static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags); +static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise); + +#if MRUBY_RELEASE_NO < 10000 +static struct RClass * +mrb_module_get(mrb_state *mrb, const char *name) +{ + return mrb_class_get(mrb, name); +} +#endif + +static int +mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) +{ + int flags = 0; + const char *m = mode; + + switch (*m++) { + case 'r': + flags |= FMODE_READABLE; + break; + case 'w': + flags |= FMODE_WRITABLE | FMODE_CREATE | FMODE_TRUNC; + break; + case 'a': + flags |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE; + break; + default: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode)); + } + + while (*m) { + switch (*m++) { + case 'b': + flags |= FMODE_BINMODE; + break; + case '+': + flags |= FMODE_READWRITE; + break; + case ':': + /* XXX: PASSTHROUGH*/ + default: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode)); + } + } + + return flags; +} + +static int +mrb_io_flags_to_modenum(mrb_state *mrb, int flags) +{ + int modenum = 0; + + switch(flags & (FMODE_READABLE|FMODE_WRITABLE|FMODE_READWRITE)) { + case FMODE_READABLE: + modenum = O_RDONLY; + break; + case FMODE_WRITABLE: + modenum = O_WRONLY; + break; + case FMODE_READWRITE: + modenum = O_RDWR; + break; + } + + if (flags & FMODE_APPEND) { + modenum |= O_APPEND; + } + if (flags & FMODE_TRUNC) { + modenum |= O_TRUNC; + } + if (flags & FMODE_CREATE) { + modenum |= O_CREAT; + } +#ifdef O_BINARY + if (flags & FMODE_BINMODE) { + modenum |= O_BINARY; + } +#endif + + return modenum; +} + +void +mrb_fd_cloexec(mrb_state *mrb, int fd) +{ + int flags, flags2; + +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) + flags = fcntl(fd, F_GETFD); + if (flags == -1) { + mrb_sys_fail(mrb, "fcntl"); + } + if (fd <= 2) { + flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */ + } + else { + flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */ + } + if (flags != flags2) { + if (fcntl(fd, F_SETFD, flags2) == -1) { + mrb_sys_fail(mrb, "fcntl"); + } + } +#endif +} + +#ifndef _WIN32 +static int +mrb_proc_exec(const char *pname) +{ + const char *s; + s = pname; + + while (*s == ' ' || *s == '\t' || *s == '\n') + s++; + + if (!*s) { + errno = ENOENT; + return -1; + } + + execl("/bin/sh", "sh", "-c", pname, (char *)NULL); + return -1; +} +#endif + +static void +mrb_io_free(mrb_state *mrb, void *ptr) +{ + struct mrb_io *io = (struct mrb_io *)ptr; + if (io != NULL) { + fptr_finalize(mrb, io, TRUE); + mrb_free(mrb, io); + } +} + +struct mrb_data_type mrb_io_type = { "IO", mrb_io_free }; + +static struct mrb_io * +mrb_io_alloc(mrb_state *mrb) +{ + struct mrb_io *fptr; + + fptr = (struct mrb_io *)mrb_malloc(mrb, sizeof(struct mrb_io)); + fptr->fd = -1; + fptr->fd2 = -1; + fptr->pid = 0; + fptr->writable = 0; + fptr->sync = 0; + return fptr; +} + +#ifndef NOFILE +#define NOFILE 64 +#endif + +#ifndef _WIN32 +mrb_value +mrb_io_s_popen(mrb_state *mrb, mrb_value klass) +{ + mrb_value cmd, io, result; + mrb_value mode = mrb_str_new_cstr(mrb, "r"); + mrb_value opt = mrb_hash_new(mrb); + + struct mrb_io *fptr; + const char *pname; + int pid, flags, fd, write_fd = -1; + int pr[2] = { -1, -1 }; + int pw[2] = { -1, -1 }; + int doexec; + int saved_errno; + + mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); + io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); + + pname = mrb_string_value_cstr(mrb, &cmd); + flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + + doexec = (strcmp("-", pname) != 0); + + if (flags & FMODE_READABLE) { + if (pipe(pr) == -1) { + mrb_sys_fail(mrb, "pipe"); + } + mrb_fd_cloexec(mrb, pr[0]); + mrb_fd_cloexec(mrb, pr[1]); + } + + if (flags & FMODE_WRITABLE) { + if (pipe(pw) == -1) { + if (pr[0] != -1) close(pr[0]); + if (pr[1] != -1) close(pr[1]); + mrb_sys_fail(mrb, "pipe"); + } + mrb_fd_cloexec(mrb, pw[0]); + mrb_fd_cloexec(mrb, pw[1]); + } + + if (!doexec) { + // XXX + fflush(stdin); + fflush(stdout); + fflush(stderr); + } + + result = mrb_nil_value(); + switch (pid = fork()) { + case 0: /* child */ + if (flags & FMODE_READABLE) { + close(pr[0]); + if (pr[1] != 1) { + dup2(pr[1], 1); + close(pr[1]); + } + } + if (flags & FMODE_WRITABLE) { + close(pw[1]); + if (pw[0] != 0) { + dup2(pw[0], 0); + close(pw[0]); + } + } + if (doexec) { + for (fd = 3; fd < NOFILE; fd++) { + close(fd); + } + mrb_proc_exec(pname); + mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd); + _exit(127); + } + result = mrb_nil_value(); + break; + + default: /* parent */ + if ((flags & FMODE_READABLE) && (flags & FMODE_WRITABLE)) { + close(pr[1]); + fd = pr[0]; + close(pw[0]); + write_fd = pw[1]; + } else if (flags & FMODE_READABLE) { + close(pr[1]); + fd = pr[0]; + } else { + close(pw[0]); + fd = pw[1]; + } + + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); + + fptr = mrb_io_alloc(mrb); + fptr->fd = fd; + fptr->fd2 = write_fd; + fptr->pid = pid; + fptr->writable = ((flags & FMODE_WRITABLE) != 0); + fptr->sync = 0; + + DATA_TYPE(io) = &mrb_io_type; + DATA_PTR(io) = fptr; + result = io; + break; + + case -1: /* error */ + saved_errno = errno; + if (flags & FMODE_READABLE) { + close(pr[0]); + close(pr[1]); + } + if (flags & FMODE_WRITABLE) { + close(pw[0]); + close(pw[1]); + } + errno = saved_errno; + mrb_sys_fail(mrb, "pipe_open failed."); + break; + } + return result; +} +#endif + +mrb_value +mrb_io_initialize(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + mrb_int fd; + mrb_value mode, opt; + int flags; + + mode = opt = mrb_nil_value(); + + mrb_get_args(mrb, "i|So", &fd, &mode, &opt); + if (mrb_nil_p(mode)) { + mode = mrb_str_new_cstr(mrb, "r"); + } + if (mrb_nil_p(opt)) { + opt = mrb_hash_new(mrb); + } + + flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); + + fptr = DATA_PTR(io); + if (fptr != NULL) { + fptr_finalize(mrb, fptr, 0); + mrb_free(mrb, fptr); + } + fptr = mrb_io_alloc(mrb); + + DATA_TYPE(io) = &mrb_io_type; + DATA_PTR(io) = fptr; + + fptr->fd = fd; + fptr->writable = ((flags & FMODE_WRITABLE) != 0); + fptr->sync = 0; + return io; +} + +static void +fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) +{ + int n = 0; + + if (fptr == NULL) { + return; + } + + if (fptr->fd > 2) { + n = close(fptr->fd); + if (n == 0) { + fptr->fd = -1; + } + } + if (fptr->fd2 > 2) { + n = close(fptr->fd2); + if (n == 0) { + fptr->fd2 = -1; + } + } + +#if !defined(_WIN32) && !defined(_WIN64) + if (fptr->pid != 0) { + pid_t pid; + do { + pid = waitpid(fptr->pid, NULL, 0); + } while (pid == -1 && errno == EINTR); + } +#endif + + if (!noraise && n != 0) { + mrb_sys_fail(mrb, "fptr_finalize failed."); + } +} + +mrb_value +mrb_io_s_for_fd(mrb_state *mrb, mrb_value klass) +{ + struct RClass *c = mrb_class_ptr(klass); + enum mrb_vtype ttype = MRB_INSTANCE_TT(c); + mrb_value obj; + + /* copied from mrb_instance_alloc() */ + if (ttype == 0) ttype = MRB_TT_OBJECT; + obj = mrb_obj_value((struct RObject*)mrb_obj_alloc(mrb, ttype, c)); + return mrb_io_initialize(mrb, obj); +} + +mrb_value +mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass) +{ + mrb_int fd; + mrb_get_args(mrb, "i", &fd); + if (close(fd) == -1) { + mrb_sys_fail(mrb, "close"); + } + return mrb_fixnum_value(0); +} + +int +mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode) +{ + int fd, retry = FALSE; + +#ifdef O_CLOEXEC + /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */ + flags |= O_CLOEXEC; +#elif defined O_NOINHERIT + flags |= O_NOINHERIT; +#endif +reopen: + fd = open(pathname, flags, mode); + if (fd == -1) { + if (!retry) { + switch (errno) { + case ENFILE: + case EMFILE: + mrb_garbage_collect(mrb); + retry = TRUE; + goto reopen; + } + } + mrb_sys_fail(mrb, "open"); + } + + if (fd <= 2) { + mrb_fd_cloexec(mrb, fd); + } + return fd; +} + +mrb_value +mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) +{ + mrb_value path = mrb_nil_value(); + mrb_value mode = mrb_nil_value(); + mrb_int fd, flags, perm = -1; + const char *pat; + int modenum; + + mrb_get_args(mrb, "S|Si", &path, &mode, &perm); + if (mrb_nil_p(mode)) { + mode = mrb_str_new_cstr(mrb, "r"); + } + if (perm < 0) { + perm = 0666; + } + + pat = mrb_string_value_cstr(mrb, &path); + flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + modenum = mrb_io_flags_to_modenum(mrb, flags); + fd = mrb_cloexec_open(mrb, pat, modenum, perm); + return mrb_fixnum_value(fd); +} + +mrb_value +mrb_io_sysread(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + mrb_value buf = mrb_nil_value(); + mrb_int maxlen; + int ret; + + mrb_get_args(mrb, "i|S", &maxlen, &buf); + if (maxlen < 0) { + return mrb_nil_value(); + } + + if (mrb_nil_p(buf)) { + buf = mrb_str_new(mrb, NULL, maxlen); + } + if (RSTRING_LEN(buf) != maxlen) { + buf = mrb_str_resize(mrb, buf, maxlen); + } + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + ret = read(fptr->fd, RSTRING_PTR(buf), maxlen); + switch (ret) { + case 0: /* EOF */ + if (maxlen == 0) { + buf = mrb_str_new_cstr(mrb, ""); + } else { + mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File"); + } + break; + case -1: /* Error */ + mrb_sys_fail(mrb, "sysread failed"); + break; + default: + if (RSTRING_LEN(buf) != ret) { + buf = mrb_str_resize(mrb, buf, ret); + } + break; + } + + return buf; +} + +mrb_value +mrb_io_sysseek(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + int pos; + mrb_int offset, whence = -1; + + mrb_get_args(mrb, "i|i", &offset, &whence); + if (whence < 0) { + whence = 0; + } + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + pos = lseek(fptr->fd, offset, whence); + if (pos < 0) { + mrb_raise(mrb, E_IO_ERROR, "sysseek faield"); + } + + return mrb_fixnum_value(pos); +} + +mrb_value +mrb_io_syswrite(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + mrb_value str, buf; + int fd, length; + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + if (! fptr->writable) { + mrb_raise(mrb, E_IO_ERROR, "not opened for writing"); + } + + mrb_get_args(mrb, "S", &str); + if (mrb_type(str) != MRB_TT_STRING) { + buf = mrb_funcall(mrb, str, "to_s", 0); + } else { + buf = str; + } + + if (fptr->fd2 == -1) { + fd = fptr->fd; + } else { + fd = fptr->fd2; + } + length = write(fd, RSTRING_PTR(buf), RSTRING_LEN(buf)); + + return mrb_fixnum_value(length); +} + +mrb_value +mrb_io_close(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + if (fptr && fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream."); + } + fptr_finalize(mrb, fptr, FALSE); + return mrb_nil_value(); +} + +mrb_value +mrb_io_closed(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + if (fptr->fd >= 0) { + return mrb_false_value(); + } + + return mrb_true_value(); +} + +mrb_value +mrb_io_pid(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + + if (fptr->pid > 0) { + return mrb_fixnum_value(fptr->pid); + } + + return mrb_nil_value(); +} + +static struct timeval +time2timeval(mrb_state *mrb, mrb_value time) +{ + struct timeval t = { 0, 0 }; + + switch (mrb_type(time)) { + case MRB_TT_FIXNUM: + t.tv_sec = mrb_fixnum(time); + t.tv_usec = 0; + break; + + case MRB_TT_FLOAT: + t.tv_sec = mrb_float(time); + t.tv_usec = (mrb_float(time) - t.tv_sec) * 1000000.0; + break; + + default: + mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); + } + + return t; +} + +static int +mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) +{ + mrb_value buf = mrb_iv_get(mrb, io, mrb_intern_cstr(mrb, "@buf")); + if (mrb_type(buf) == MRB_TT_STRING && RSTRING_LEN(buf) > 0) { + return 1; + } + return 0; +} + +static mrb_value +mrb_io_s_select(mrb_state *mrb, mrb_value klass) +{ + mrb_value *argv; + mrb_int argc; + mrb_value read, read_io, write, except, timeout, list; + struct timeval *tp, timerec; + fd_set pset, rset, wset, eset; + fd_set *rp, *wp, *ep; + struct mrb_io *fptr; + int pending = 0; + mrb_value result; + int max = 0; + int interrupt_flag = 0; + int i, n; + + mrb_get_args(mrb, "*", &argv, &argc); + + if (argc < 1 || argc > 4) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1..4)", mrb_fixnum_value(argc)); + } + + timeout = mrb_nil_value(); + except = mrb_nil_value(); + write = mrb_nil_value(); + if (argc > 3) + timeout = argv[3]; + if (argc > 2) + except = argv[2]; + if (argc > 1) + write = argv[1]; + read = argv[0]; + + if (mrb_nil_p(timeout)) { + tp = NULL; + } else { + timerec = time2timeval(mrb, timeout); + tp = &timerec; + } + + FD_ZERO(&pset); + if (!mrb_nil_p(read)) { + mrb_check_type(mrb, read, MRB_TT_ARRAY); + rp = &rset; + FD_ZERO(rp); + for (i = 0; i < RARRAY_LEN(read); i++) { + read_io = RARRAY_PTR(read)[i]; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, read_io, &mrb_io_type); + FD_SET(fptr->fd, rp); + if (mrb_io_read_data_pending(mrb, read_io)) { + pending++; + FD_SET(fptr->fd, &pset); + } + if (max < fptr->fd) + max = fptr->fd; + } + if (pending) { + timerec.tv_sec = timerec.tv_usec = 0; + tp = &timerec; + } + } else { + rp = NULL; + } + + if (!mrb_nil_p(write)) { + mrb_check_type(mrb, write, MRB_TT_ARRAY); + wp = &wset; + FD_ZERO(wp); + for (i = 0; i < RARRAY_LEN(write); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(write)[i], &mrb_io_type); + FD_SET(fptr->fd, wp); + if (max < fptr->fd) + max = fptr->fd; + if (fptr->fd2 >= 0) { + FD_SET(fptr->fd2, wp); + if (max < fptr->fd2) + max = fptr->fd2; + } + } + } else { + wp = NULL; + } + + if (!mrb_nil_p(except)) { + mrb_check_type(mrb, except, MRB_TT_ARRAY); + ep = &eset; + FD_ZERO(ep); + for (i = 0; i < RARRAY_LEN(except); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(except)[i], &mrb_io_type); + FD_SET(fptr->fd, ep); + if (max < fptr->fd) + max = fptr->fd; + if (fptr->fd2 >= 0) { + FD_SET(fptr->fd2, ep); + if (max < fptr->fd2) + max = fptr->fd2; + } + } + } else { + ep = NULL; + } + + max++; + +retry: + n = select(max, rp, wp, ep, tp); + if (n < 0) { + if (errno != EINTR) + mrb_sys_fail(mrb, "select failed"); + if (tp == NULL) + goto retry; + interrupt_flag = 1; + } + + if (!pending && n == 0) + return mrb_nil_value(); + + result = mrb_ary_new_capa(mrb, 3); + mrb_ary_push(mrb, result, rp? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0)); + mrb_ary_push(mrb, result, wp? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0)); + mrb_ary_push(mrb, result, ep? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0)); + + if (interrupt_flag == 0) { + if (rp) { + list = RARRAY_PTR(result)[0]; + for (i = 0; i < RARRAY_LEN(read); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(read)[i], &mrb_io_type); + if (FD_ISSET(fptr->fd, rp) || + FD_ISSET(fptr->fd, &pset)) { + mrb_ary_push(mrb, list, RARRAY_PTR(read)[i]); + } + } + } + + if (wp) { + list = RARRAY_PTR(result)[1]; + for (i = 0; i < RARRAY_LEN(write); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(write)[i], &mrb_io_type); + if (FD_ISSET(fptr->fd, wp)) { + mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]); + } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, wp)) { + mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]); + } + } + } + + if (ep) { + list = RARRAY_PTR(result)[2]; + for (i = 0; i < RARRAY_LEN(except); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(except)[i], &mrb_io_type); + if (FD_ISSET(fptr->fd, ep)) { + mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]); + } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, ep)) { + mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]); + } + } + } + } + + return result; +} + +mrb_value +mrb_io_fileno(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + return mrb_fixnum_value(fptr->fd); +} + +mrb_value +mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value io) +{ +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) + struct mrb_io *fptr; + int ret; + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + if (fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream"); + } + + if (fptr->fd2 >= 0) { + if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if (!(ret & FD_CLOEXEC)) return mrb_false_value(); + } + + if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if (!(ret & FD_CLOEXEC)) return mrb_false_value(); + return mrb_true_value(); + +#else + mrb_raise(mrb, E_NOTIMP_ERROR, "IO#close_on_exec? is not supported on the platform"); + return mrb_false_value(); +#endif +} + +mrb_value +mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value io) +{ +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) + struct mrb_io *fptr; + int flag, ret; + mrb_bool b; + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + if (fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream"); + } + + mrb_get_args(mrb, "b", &b); + flag = b ? FD_CLOEXEC : 0; + + if (fptr->fd2 >= 0) { + if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if ((ret & FD_CLOEXEC) != flag) { + ret = (ret & ~FD_CLOEXEC) | flag; + ret = fcntl(fptr->fd2, F_SETFD, ret); + + if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed"); + } + } + + if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if ((ret & FD_CLOEXEC) != flag) { + ret = (ret & ~FD_CLOEXEC) | flag; + ret = fcntl(fptr->fd, F_SETFD, ret); + if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed"); + } + + return mrb_bool_value(b); +#else + mrb_raise(mrb, E_NOTIMP_ERROR, "IO#close_on_exec= is not supported on the platform"); + return mrb_nil_value(); +#endif +} + +mrb_value +mrb_io_set_sync(mrb_state *mrb, mrb_value self) +{ + struct mrb_io *fptr; + mrb_bool b; + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type); + if (fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream."); + } + + mrb_get_args(mrb, "b", &b); + fptr->sync = b; + return mrb_bool_value(b); +} + +mrb_value +mrb_io_sync(mrb_state *mrb, mrb_value self) +{ + struct mrb_io *fptr; + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type); + if (fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream."); + } + return mrb_bool_value(fptr->sync); +} + +void +mrb_init_io(mrb_state *mrb) +{ + struct RClass *io; + + io = mrb_define_class(mrb, "IO", mrb->object_class); + MRB_SET_INSTANCE_TT(io, MRB_TT_DATA); + + mrb_include_module(mrb, io, mrb_module_get(mrb, "Enumerable")); /* 15.2.20.3 */ +#ifndef _WIN32 + mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, io, "_sysclose", mrb_io_s_sysclose, MRB_ARGS_REQ(1)); +#endif + mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); + + mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ + mrb_define_method(mrb, io, "sync", mrb_io_sync, MRB_ARGS_NONE()); + mrb_define_method(mrb, io, "sync=", mrb_io_set_sync, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, io, "sysread", mrb_io_sysread, MRB_ARGS_ANY()); + mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, io, "close", mrb_io_close, MRB_ARGS_NONE()); /* 15.2.20.5.1 */ + mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, io, "close_on_exec?", mrb_io_close_on_exec_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, io, "closed?", mrb_io_closed, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ + mrb_define_method(mrb, io, "pid", mrb_io_pid, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ + mrb_define_method(mrb, io, "fileno", mrb_io_fileno, MRB_ARGS_NONE()); + + + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n")); +} diff --git a/web/server/h2o/libh2o/deps/mruby-io/src/mruby_io_gem.c b/web/server/h2o/libh2o/deps/mruby-io/src/mruby_io_gem.c new file mode 100644 index 000000000..6880e6678 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/src/mruby_io_gem.c @@ -0,0 +1,20 @@ +#include "mruby.h" + +void mrb_init_io(mrb_state *mrb); +void mrb_init_file(mrb_state *mrb); +void mrb_init_file_test(mrb_state *mrb); + +#define DONE mrb_gc_arena_restore(mrb, 0) + +void +mrb_mruby_io_gem_init(mrb_state* mrb) +{ + mrb_init_io(mrb); DONE; + mrb_init_file(mrb); DONE; + mrb_init_file_test(mrb); DONE; +} + +void +mrb_mruby_io_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-io/test/file.rb b/web/server/h2o/libh2o/deps/mruby-io/test/file.rb new file mode 100644 index 000000000..d6f39ceb1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/test/file.rb @@ -0,0 +1,108 @@ +## +# IO Test + +assert('File', '15.2.21') do + File.class == Class +end + +assert('File', '15.2.21.2') do + File.superclass == IO +end + +assert('File TEST SETUP') do + MRubyIOTestUtil.io_test_setup +end + +assert('File#initialize', '15.2.21.4.1') do + io = File.open($mrbtest_io_rfname, "r") + assert_nil io.close + assert_raise IOError do + io.close + end +end + +assert('File#path', '15.2.21.4.2') do + io = File.open($mrbtest_io_rfname, "r") + assert_equal $mrbtest_io_msg, io.read + assert_equal $mrbtest_io_rfname, io.path + io.close + assert_equal $mrbtest_io_rfname, io.path + io.closed? +end + +assert('File.basename') do + assert_equal '/', File.basename('//') + assert_equal 'a', File.basename('/a/') + assert_equal 'b', File.basename('/a/b') + assert_equal 'b', File.basename('../a/b') +end + +assert('File.dirname') do + assert_equal '.', File.dirname('') + assert_equal '.', File.dirname('a') + assert_equal '/', File.dirname('/a') + assert_equal 'a', File.dirname('a/b') + assert_equal '/a', File.dirname('/a/b') +end + +assert('File.extname') do + assert_equal '.txt', File.extname('foo/foo.txt') + assert_equal '.gz', File.extname('foo/foo.tar.gz') + assert_equal '', File.extname('foo/bar') + assert_equal '', File.extname('foo/.bar') + assert_equal '', File.extname('foo.txt/bar') + assert_equal '', File.extname('.foo') +end + +assert('IO#flock') do + f = File.open $mrbtest_io_rfname + assert_equal(f.flock(File::LOCK_SH), 0) + assert_equal(f.flock(File::LOCK_UN), 0) + assert_equal(f.flock(File::LOCK_EX | File::LOCK_NB), 0) + assert_equal(f.flock(File::LOCK_UN), 0) + f.close + true +end + +assert('File.join') do + File.join() == "" and + File.join("a") == "a" and + File.join("/a") == "/a" and + File.join("a/") == "a/" and + File.join("a", "b", "c") == "a/b/c" and + File.join("/a", "b", "c") == "/a/b/c" and + File.join("a", "b", "c/") == "a/b/c/" and + File.join("a/", "/b/", "/c") == "a/b/c" +end + +assert('File.realpath') do + usrbin = IO.popen("cd bin; /bin/pwd -P") { |f| f.read.chomp } + assert_equal usrbin, File.realpath("bin") +end + +assert('File TEST CLEANUP') do + assert_nil MRubyIOTestUtil.io_test_cleanup +end + +assert('File.expand_path') do + assert_equal "/", File.expand_path("..", "/tmp"), "parent path with base_dir (1)" + assert_equal "/tmp", File.expand_path("..", "/tmp/mruby"), "parent path with base_dir (2)" + + assert_equal "/home", File.expand_path("/home"), "absolute" + assert_equal "/home", File.expand_path("/home", "."), "absolute with base_dir" + + assert_equal "/hoge", File.expand_path("/tmp/..//hoge") + assert_equal "/hoge", File.expand_path("////tmp/..///////hoge") + + assert_equal "/", File.expand_path("../../../..", "/") + assert_equal "/", File.expand_path(([".."] * 100).join("/")) +end + +assert('File.expand_path (with ENV)') do + skip unless Object.const_defined?(:ENV) && ENV['HOME'] + + assert_equal ENV['HOME'], File.expand_path("~/"), "home" + assert_equal ENV['HOME'], File.expand_path("~/", "/"), "home with base_dir" + + assert_equal "#{ENV['HOME']}/user", File.expand_path("user", ENV['HOME']), "relative with base_dir" +end diff --git a/web/server/h2o/libh2o/deps/mruby-io/test/file_test.rb b/web/server/h2o/libh2o/deps/mruby-io/test/file_test.rb new file mode 100644 index 000000000..11742f2db --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/test/file_test.rb @@ -0,0 +1,95 @@ +## +# FileTest + +assert('FileTest TEST SETUP') do + MRubyIOTestUtil.io_test_setup +end + +assert("FileTest.directory?") do + assert_equal true, FileTest.directory?("/tmp") + assert_equal false, FileTest.directory?("/bin/sh") +end + +assert("FileTest.exist?") do + assert_equal true, FileTest.exist?($mrbtest_io_rfname), "filename - exist" + assert_equal false, FileTest.exist?($mrbtest_io_rfname + "-"), "filename - not exist" + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + assert_equal true, FileTest.exist?(io), "io obj - exist" + io.close + assert_equal true, io.closed? + assert_raise IOError do + FileTest.exist?(io) + end +end + +assert("FileTest.file?") do + assert_equal false, FileTest.file?("/tmp") + assert_equal true, FileTest.file?("/bin/sh") +end + +assert("FileTest.pipe?") do + io = IO.popen("ls") + assert_equal true, FileTest.pipe?(io) + assert_equal false, FileTest.pipe?("/tmp") +end + +assert('FileTest.size') do + assert_equal FileTest.size($mrbtest_io_rfname), $mrbtest_io_msg.size + assert_equal FileTest.size($mrbtest_io_wfname), 0 +end + +assert("FileTest.size?") do + assert_equal $mrbtest_io_msg.size, FileTest.size?($mrbtest_io_rfname) + assert_equal nil, FileTest.size?($mrbtest_io_wfname) + assert_equal nil, FileTest.size?("not-exist-test-target-file") + + fp1 = File.open($mrbtest_io_rfname) + fp2 = File.open($mrbtest_io_wfname) + assert_equal $mrbtest_io_msg.size, FileTest.size?(fp1) + assert_equal nil, FileTest.size?(fp2) + fp1.close + fp2.close + + assert_raise IOError do + FileTest.size?(fp1) + end + assert_raise IOError do + FileTest.size?(fp2) + end + + fp1.closed? && fp2.closed? +end + +assert("FileTest.socket?") do + assert_true FileTest.socket?($mrbtest_io_socketname) +end + +assert("FileTest.symlink?") do + assert_true FileTest.symlink?($mrbtest_io_symlinkname) +end + +assert("FileTest.zero?") do + assert_equal false, FileTest.zero?($mrbtest_io_rfname) + assert_equal true, FileTest.zero?($mrbtest_io_wfname) + assert_equal false, FileTest.zero?("not-exist-test-target-file") + + fp1 = File.open($mrbtest_io_rfname) + fp2 = File.open($mrbtest_io_wfname) + assert_equal false, FileTest.zero?(fp1) + assert_equal true, FileTest.zero?(fp2) + fp1.close + fp2.close + + assert_raise IOError do + FileTest.zero?(fp1) + end + assert_raise IOError do + FileTest.zero?(fp2) + end + + fp1.closed? && fp2.closed? +end + +assert('FileTest TEST CLEANUP') do + assert_nil MRubyIOTestUtil.io_test_cleanup +end diff --git a/web/server/h2o/libh2o/deps/mruby-io/test/gc_filedes.sh b/web/server/h2o/libh2o/deps/mruby-io/test/gc_filedes.sh new file mode 100644 index 000000000..6e5d1bbf1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/test/gc_filedes.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +ulimit -n 20 +mruby -e '100.times { File.open "'$0'" }' diff --git a/web/server/h2o/libh2o/deps/mruby-io/test/io.rb b/web/server/h2o/libh2o/deps/mruby-io/test/io.rb new file mode 100644 index 000000000..b828fef49 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/test/io.rb @@ -0,0 +1,416 @@ +## +# IO Test + +assert('IO TEST SETUP') do + MRubyIOTestUtil.io_test_setup +end + +assert('IO', '15.2.20') do + assert_equal(Class, IO.class) +end + +assert('IO', '15.2.20.2') do + assert_equal(Object, IO.superclass) +end + +assert('IO', '15.2.20.3') do + assert_include(IO.included_modules, Enumerable) +end + +assert('IO.open', '15.2.20.4.1') do + fd = IO.sysopen $mrbtest_io_rfname + assert_equal Fixnum, fd.class + io = IO.open fd + assert_equal IO, io.class + assert_equal $mrbtest_io_msg, io.read + io.close + + fd = IO.sysopen $mrbtest_io_rfname + IO.open(fd) do |io| + assert_equal $mrbtest_io_msg, io.read + end + + true +end + +assert('IO#close', '15.2.20.5.1') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + assert_nil io.close +end + +assert('IO#closed?', '15.2.20.5.2') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + assert_false io.closed? + io.close + assert_true io.closed? +end + +#assert('IO#each', '15.2.20.5.3') do +#assert('IO#each_byte', '15.2.20.5.4') do +#assert('IO#each_line', '15.2.20.5.5') do + +assert('IO#eof?', '15.2.20.5.6') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + $mrbtest_io_msg.each_char { |ch| + # XXX + #assert_false io.eof? + io.getc + } + assert_true io.eof? + io.close + true +end + +assert('IO#flush', '15.2.20.5.7') do + # Note: mruby-io does not have any buffer to be flushed now. + io = IO.new(IO.sysopen($mrbtest_io_wfname)) + assert_equal io, io.flush + io.close + assert_raise(IOError) do + io.flush + end +end + +assert('IO#getc', '15.2.20.5.8') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + $mrbtest_io_msg.each_char { |ch| + assert_equal ch, io.getc + } + assert_equal nil, io.getc + io.close + true +end + +#assert('IO#gets', '15.2.20.5.9') do +#assert('IO#initialize_copy', '15.2.20.5.10') do +#assert('IO#print', '15.2.20.5.11') do +#assert('IO#putc', '15.2.20.5.12') do +#assert('IO#puts', '15.2.20.5.13') do + +assert('IO#read', '15.2.20.5.14') do + IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| + assert_raise(ArgumentError) { io.read(-5) } + assert_raise(TypeError) { io.read("str") } + + len = $mrbtest_io_msg.length + assert_equal '', io.read(0) + assert_equal 'mruby', io.read(5) + assert_equal $mrbtest_io_msg[5,len], io.read(len) + + assert_equal "", io.read + assert_nil io.read(1) + end + + IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| + assert_equal $mrbtest_io_msg, io.read + end +end + +assert('IO#readchar', '15.2.20.5.15') do + # almost same as IO#getc + IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| + $mrbtest_io_msg.each_char { |ch| + assert_equal ch, io.readchar + } + assert_raise(EOFError) do + io.readchar + end + end +end + +#assert('IO#readline', '15.2.20.5.16') do +#assert('IO#readlines', '15.2.20.5.17') do + +assert('IO#sync', '15.2.20.5.18') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + s = io.sync + assert_true(s == true || s == false) + io.close + assert_raise(IOError) do + io.sync + end +end + +assert('IO#sync=', '15.2.20.5.19') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + io.sync = true + assert_true io.sync + io.sync = false + assert_false io.sync + io.close + assert_raise(IOError) do + io.sync = true + end +end + +assert('IO#write', '15.2.20.5.20') do + io = IO.open(IO.sysopen($mrbtest_io_wfname)) + assert_equal 0, io.write("") + io.close + true +end + +assert('IO.for_fd') do + fd = IO.sysopen($mrbtest_io_rfname) + io = IO.for_fd(fd) + assert_equal $mrbtest_io_msg, io.read + io.close + true +end + +assert('IO.new') do + io = IO.new(0) + io.close + true +end + +assert('IO gc check') do + 100.times { IO.new(0) } +end + +assert('IO.sysopen("./nonexistent")') do + if Object.const_defined? :Errno + eclass = Errno::ENOENT + else + eclass = RuntimeError + end + assert_raise eclass do + fd = IO.sysopen "./nonexistent" + IO._sysclose fd + end +end + +assert('IO.sysopen, IO#sysread') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + str1 = " " + str2 = io.sysread(5, str1) + assert_equal $mrbtest_io_msg[0,5], str1 + assert_equal $mrbtest_io_msg[0,5], str2 + assert_raise EOFError do + io.sysread(10000) + io.sysread(10000) + end + io.close + io.closed? +end + +assert('IO.sysopen, IO#syswrite') do + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + str = "abcdefg" + len = io.syswrite(str) + assert_equal str.size, len + io.close + + io = IO.new(IO.sysopen($mrbtest_io_rfname), "r") + assert_raise(IOError) { io.syswrite("a") } + io.close + + true +end + +assert('IO#_read_buf') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + def io._buf + @buf + end + msg_len = $mrbtest_io_msg.size + assert_equal '', io._buf + assert_equal $mrbtest_io_msg, io._read_buf + assert_equal $mrbtest_io_msg, io._buf + assert_equal 'mruby', io.read(5) + assert_equal 5, io.pos + assert_equal msg_len - 5, io._buf.size + assert_equal $mrbtest_io_msg[5,100], io.read + assert_equal 0, io._buf.size + assert_raise EOFError do + io._read_buf + end + assert_equal true, io.eof + assert_equal true, io.eof? + io.close + io.closed? +end + +assert('IO#pos=, IO#seek') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + def io._buf + @buf + end + assert_equal 'm', io.getc + assert_equal 1, io.pos + assert_equal 0, io.seek(0) + assert_equal 0, io.pos + io.close + io.closed? +end + +assert('IO#gets') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + + # gets without arguments + assert_equal $mrbtest_io_msg, io.gets, "gets without arguments" + assert_equal nil, io.gets, "gets returns nil, when EOF" + + # gets with limit + io.pos = 0 + assert_equal $mrbtest_io_msg[0, 5], io.gets(5), "gets with limit" + + # gets with rs + io.pos = 0 + assert_equal $mrbtest_io_msg[0, 6], io.gets(' '), "gets with rs" + + # gets with rs, limit + io.pos = 0 + assert_equal $mrbtest_io_msg[0, 5], io.gets(' ', 5), "gets with rs, limit" + io.close + assert_equal true, io.closed?, "close success" + + # reading many-lines file. + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + io.write "0123456789" * 2 + "\na" + assert_equal 22, io.pos + io.close + assert_equal true, io.closed? + + fd = IO.sysopen $mrbtest_io_wfname + io = IO.new fd + line = io.gets + + # gets first line + assert_equal "0123456789" * 2 + "\n", line, "gets first line" + assert_equal 21, line.size + assert_equal 21, io.pos + + # gets second line + assert_equal "a", io.gets, "gets second line" + + # gets third line + assert_equal nil, io.gets, "gets third line; returns nil" + + io.close + io.closed? +end + +assert('IO#gets - paragraph mode') do + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + io.write "0" * 10 + "\n" + io.write "1" * 10 + "\n\n" + io.write "2" * 10 + "\n" + assert_equal 34, io.pos + io.close + assert_equal true, io.closed? + + fd = IO.sysopen $mrbtest_io_wfname + io = IO.new fd + para1 = "#{'0' * 10}\n#{'1' * 10}\n\n" + text1 = io.gets("") + assert_equal para1, text1 + para2 = "#{'2' * 10}\n" + text2 = io.gets("") + assert_equal para2, text2 + io.close + io.closed? +end + +assert('IO.popen') do + io = IO.popen("ls") + assert_true io.close_on_exec? + assert_equal Fixnum, io.pid.class + ls = io.read + assert_equal ls.class, String + assert_include ls, 'AUTHORS' + assert_include ls, 'mrblib' + io.close + io.closed? +end + +assert('IO.read') do + # empty file + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + io.close + assert_equal "", IO.read($mrbtest_io_wfname) + assert_equal nil, IO.read($mrbtest_io_wfname, 1) + + # one byte file + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + io.write "123" + io.close + assert_equal "123", IO.read($mrbtest_io_wfname) + assert_equal "", IO.read($mrbtest_io_wfname, 0) + assert_equal "1", IO.read($mrbtest_io_wfname, 1) + assert_equal "", IO.read($mrbtest_io_wfname, 0, 10) + assert_equal "23", IO.read($mrbtest_io_wfname, 2, 1) + assert_equal "23", IO.read($mrbtest_io_wfname, 10, 1) + assert_equal "", IO.read($mrbtest_io_wfname, nil, 10) + assert_equal nil, IO.read($mrbtest_io_wfname, 1, 10) +end + +assert('IO#fileno') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + assert_equal io.fileno, fd + assert_equal io.to_i, fd + io.close + io.closed? +end + +assert('IO#close_on_exec') do + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + begin + # IO.sysopen opens a file descripter with O_CLOEXEC flag. + assert_true io.close_on_exec? + rescue ScriptError + skip "IO\#close_on_exec is not implemented." + end + + io.close_on_exec = false + assert_equal(false, io.close_on_exec?) + io.close_on_exec = true + assert_equal(true, io.close_on_exec?) + io.close_on_exec = false + assert_equal(false, io.close_on_exec?) + + io.close + io.closed? + + # # Use below when IO.pipe is implemented. + # begin + # r, w = IO.pipe + # assert_equal(false, r.close_on_exec?) + # r.close_on_exec = true + # assert_equal(true, r.close_on_exec?) + # r.close_on_exec = false + # assert_equal(false, r.close_on_exec?) + # r.close_on_exec = true + # assert_equal(true, r.close_on_exec?) + + # assert_equal(false, w.close_on_exec?) + # w.close_on_exec = true + # assert_equal(true, w.close_on_exec?) + # w.close_on_exec = false + # assert_equal(false, w.close_on_exec?) + # w.close_on_exec = true + # assert_equal(true, w.close_on_exec?) + # ensure + # r.close unless r.closed? + # w.close unless w.closed? + # end +end + +assert('`cmd`') do + assert_equal `echo foo`, "foo\n" +end + +assert('IO TEST CLEANUP') do + assert_nil MRubyIOTestUtil.io_test_cleanup +end diff --git a/web/server/h2o/libh2o/deps/mruby-io/test/mruby_io_test.c b/web/server/h2o/libh2o/deps/mruby-io/test/mruby_io_test.c new file mode 100644 index 000000000..f58f9ff8c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-io/test/mruby_io_test.c @@ -0,0 +1,141 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "mruby.h" +#include "mruby/array.h" +#include "mruby/string.h" +#include "mruby/variable.h" + +static mrb_value +mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) +{ + char rfname[] = "tmp.mruby-io-test.XXXXXXXX"; + char wfname[] = "tmp.mruby-io-test.XXXXXXXX"; + char symlinkname[] = "tmp.mruby-io-test.XXXXXXXX"; + char socketname[] = "tmp.mruby-io-test.XXXXXXXX"; + char msg[] = "mruby io test\n"; + mode_t mask; + int fd0, fd1, fd2, fd3; + FILE *fp; + struct sockaddr_un sun0; + + mask = umask(077); + fd0 = mkstemp(rfname); + fd1 = mkstemp(wfname); + fd2 = mkstemp(symlinkname); + fd3 = mkstemp(socketname); + if (fd0 == -1 || fd1 == -1 || fd2 == -1 || fd3 == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file"); + return mrb_nil_value(); + } + umask(mask); + + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_str_new_cstr(mrb, rfname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_str_new_cstr(mrb, wfname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_str_new_cstr(mrb, symlinkname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_str_new_cstr(mrb, socketname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg)); + + fp = fopen(rfname, "w"); + if (fp == NULL) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file"); + return mrb_nil_value(); + } + fputs(msg, fp); + fclose(fp); + + fp = fopen(wfname, "w"); + if (fp == NULL) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file"); + return mrb_nil_value(); + } + fclose(fp); + + unlink(symlinkname); + close(fd2); + if (symlink("hoge", symlinkname) == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link"); + } + + unlink(socketname); + close(fd3); + fd3 = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd3 == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a socket"); + } + sun0.sun_family = AF_UNIX; + snprintf(sun0.sun_path, sizeof(sun0.sun_path), "%s", socketname); + if (bind(fd3, (struct sockaddr *)&sun0, sizeof(sun0)) == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a socket bi"); + } + close(fd3); + + return mrb_true_value(); +} + +static mrb_value +mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self) +{ + mrb_value rfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname")); + mrb_value wfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname")); + mrb_value symlinkname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname")); + mrb_value socketname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname")); + + if (mrb_type(rfname) == MRB_TT_STRING) { + remove(RSTRING_PTR(rfname)); + } + if (mrb_type(wfname) == MRB_TT_STRING) { + remove(RSTRING_PTR(wfname)); + } + if (mrb_type(symlinkname) == MRB_TT_STRING) { + remove(RSTRING_PTR(symlinkname)); + } + if (mrb_type(socketname) == MRB_TT_STRING) { + remove(RSTRING_PTR(socketname)); + } + + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_nil_value()); + + return mrb_nil_value(); +} + +static mrb_value +mrb_io_test_file_setup(mrb_state *mrb, mrb_value self) +{ + mrb_value ary = mrb_io_test_io_setup(mrb, self); + if (symlink("/usr/bin", "test-bin") == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link"); + } + + return ary; +} + +static mrb_value +mrb_io_test_file_cleanup(mrb_state *mrb, mrb_value self) +{ + mrb_io_test_io_cleanup(mrb, self); + remove("test-bin"); + + return mrb_nil_value(); +} + +void +mrb_mruby_io_gem_test(mrb_state* mrb) +{ + struct RClass *io_test = mrb_define_module(mrb, "MRubyIOTestUtil"); + mrb_define_class_method(mrb, io_test, "io_test_setup", mrb_io_test_io_setup, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, io_test, "io_test_cleanup", mrb_io_test_io_cleanup, MRB_ARGS_NONE()); + + mrb_define_class_method(mrb, io_test, "file_test_setup", mrb_io_test_file_setup, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, io_test, "file_test_cleanup", mrb_io_test_file_cleanup, MRB_ARGS_NONE()); + +} diff --git a/web/server/h2o/libh2o/deps/mruby-onig-regexp/.travis.yml b/web/server/h2o/libh2o/deps/mruby-onig-regexp/.travis.yml new file mode 100644 index 000000000..5a0d1ddf1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-onig-regexp/.travis.yml @@ -0,0 +1,10 @@ +sudo: false +addons: + apt: + packages: + - gperf +script: + - export MRUBY_CONFIG="$TRAVIS_BUILD_DIR/.travis_config.rb" + - git clone --depth 1 "https://github.com/mruby/mruby.git" + - cd mruby + - ./minirake all test diff --git a/web/server/h2o/libh2o/deps/mruby-onig-regexp/.travis_config.rb b/web/server/h2o/libh2o/deps/mruby-onig-regexp/.travis_config.rb new file mode 100644 index 000000000..769446c4c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-onig-regexp/.travis_config.rb @@ -0,0 +1,21 @@ +MRuby::Build.new do |conf| + toolchain :gcc + enable_debug + enable_test + + gem :core => 'mruby-print' + gem :core => 'mruby-sprintf' + gem "#{MRUBY_ROOT}/.." +end + +MRuby::Build.new("onigmo-bundled") do |conf| + toolchain :gcc + enable_debug + enable_test + + gem :core => 'mruby-print' + gem :core => 'mruby-sprintf' + gem "#{MRUBY_ROOT}/.." do |g| + g.bundle_onigmo + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-onig-regexp/Onigmo-6.1.1.tar.gz b/web/server/h2o/libh2o/deps/mruby-onig-regexp/Onigmo-6.1.1.tar.gz Binary files differnew file mode 100644 index 000000000..139226584 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-onig-regexp/Onigmo-6.1.1.tar.gz diff --git a/web/server/h2o/libh2o/deps/mruby-onig-regexp/README.md b/web/server/h2o/libh2o/deps/mruby-onig-regexp/README.md new file mode 100644 index 000000000..41eada48f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-onig-regexp/README.md @@ -0,0 +1,45 @@ +# mruby-onig-regexp + +[![Build Status](https://travis-ci.org/mattn/mruby-onig-regexp.svg)](https://travis-ci.org/mattn/mruby-onig-regexp) + +## install by mrbgems +```ruby +MRuby::Build.new do |conf| + + # ... (snip) ... + + conf.gem :github => 'mattn/mruby-onig-regexp' +end +``` + +## Example +```ruby + +def matchstr(str) + reg = Regexp.compile("abc") + + if reg =~ str then + p "match" + else + p "not match" + end +end + +matchstr("abcdef") # => match +matchstr("ghijkl") # => not match +matchstr("xyzabc") # => match +``` + +## License + +MIT + +### License of Onigmo +BSD licensed. + + Onigmo (Oniguruma-mod) -- (C) K.Takata <kentkt AT csc DOT jp> + Oniguruma ---- (C) K.Kosako <sndgk393 AT ybb DOT ne DOT jp> + +## Author + +Yasuhiro Matsumoto (a.k.a mattn) diff --git a/web/server/h2o/libh2o/deps/mruby-onig-regexp/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-onig-regexp/mrbgem.rake new file mode 100644 index 000000000..679986703 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-onig-regexp/mrbgem.rake @@ -0,0 +1,113 @@ +MRuby::Gem::Specification.new('mruby-onig-regexp') do |spec| + spec.license = 'MIT' + spec.authors = 'mattn' + + def spec.bundle_onigmo + return if @onigmo_bundled + @onigmo_bundled = true + + visualcpp = ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + + require 'open3' + + # remove libonig, instead link directly against pthread + unless ENV['OS'] == 'Windows_NT' + linker.libraries = ['pthread'] + end + + version = '6.1.1' + oniguruma_dir = "#{build_dir}/onigmo-#{version}" + oniguruma_lib = libfile "#{oniguruma_dir}/.libs/libonigmo" + unless ENV['OS'] == 'Windows_NT' + oniguruma_lib = libfile "#{oniguruma_dir}/.libs/libonigmo" + else + if ENV['PROCESSOR_ARCHITECTURE'] == 'AMD64' + oniguruma_lib = libfile "#{oniguruma_dir}/build-x86-64/onigmo" + else + oniguruma_lib = libfile "#{oniguruma_dir}/build-i686/onigmo" + end + end + header = "#{oniguruma_dir}/onigmo.h" + + task :clean do + FileUtils.rm_rf [oniguruma_dir] + end + + file header do |t| + FileUtils.mkdir_p oniguruma_dir + Dir.chdir(build_dir) do + _pp 'extracting', "Onigmo-#{version}" + `gzip -dc "#{dir}/Onigmo-#{version}.tar.gz" | tar xf -` + end + end + + def run_command(env, command) + STDOUT.sync = true + Open3.popen2e(env, command) do |stdin, stdout, thread| + print stdout.read + fail "#{command} failed" if thread.value != 0 + end + end + + libonig_objs_dir = "#{oniguruma_dir}/libonig_objs" + libmruby_a = libfile("#{build.build_dir}/lib/libmruby") + objext = visualcpp ? '.obj' : '.o' + + file oniguruma_lib => header do |t| + Dir.chdir(oniguruma_dir) do + e = { + 'CC' => "#{build.cc.command} #{build.cc.flags.join(' ')}", + 'CXX' => "#{build.cxx.command} #{build.cxx.flags.join(' ')}", + 'LD' => "#{build.linker.command} #{build.linker.flags.join(' ')}", + 'AR' => build.archiver.command } + unless ENV['OS'] == 'Windows_NT' + if build.kind_of? MRuby::CrossBuild + host = "--host #{build.name}" + end + + _pp 'autotools', oniguruma_dir + run_command e, './autogen.sh' if File.exists? 'autogen.sh' + run_command e, "./configure --disable-shared --enable-static #{host}" + run_command e, 'make' + else + run_command e, 'cmd /c "copy /Y win32 > NUL"' + if visualcpp + run_command e, 'nmake -f Makefile' + else + run_command e, 'make -f Makefile.mingw' + end + end + end + + FileUtils.mkdir_p libonig_objs_dir + Dir.chdir(libonig_objs_dir) do + unless visualcpp + `ar x #{oniguruma_lib}` + else + winname = oniguruma_lib.gsub(%'/', '\\') + `lib -nologo -list #{winname}`.each_line do |line| + line.chomp! + `lib -nologo -extract:#{line} #{winname}` + end + end + end + file libmruby_a => Dir.glob("#{libonig_objs_dir}/*#{objext}") + end + + file libmruby_a => Dir.glob("#{libonig_objs_dir}/*#{objext}") if File.exists? oniguruma_lib + + file "#{dir}/src/mruby_onig_regexp.c" => oniguruma_lib + cc.include_paths << oniguruma_dir + cc.defines += ['HAVE_ONIGMO_H'] + end + + if spec.respond_to? :search_package and spec.search_package 'onigmo' + spec.cc.defines += ['HAVE_ONIGMO_H'] + elsif spec.respond_to? :search_package and spec.search_package 'oniguruma' + spec.cc.defines += ['HAVE_ONIGURUMA_H'] + elsif build.cc.respond_to? :search_header_path and build.cc.search_header_path 'oniguruma.h' + spec.linker.libraries << 'onig' + else + spec.bundle_onigmo + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-onig-regexp/mrblib/onig_regexp.rb b/web/server/h2o/libh2o/deps/mruby-onig-regexp/mrblib/onig_regexp.rb new file mode 100644 index 000000000..2dc8d55e0 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-onig-regexp/mrblib/onig_regexp.rb @@ -0,0 +1,140 @@ +class OnigRegexp + @memo = {} + + # ISO 15.2.15.6.1 + def self.compile(*args) + as = args.to_s + unless @memo.key? as + @memo[as] = self.new(*args) + end + @memo[as] + end + + # ISO 15.2.15.6.3 + def self.last_match + @last_match + end + + # ISO 15.2.15.7.2 + def initialize_copy(other) + initialize(other.source, other.options) + end + + # ISO 15.2.15.7.4 + def ===(str) + not self.match(str).nil? + end + + # ISO 15.2.15.7.5 + def =~(str) + m = self.match(str) + m ? m.begin(0) : nil + end + + # ISO 15.2.15.7.8 + attr_reader :source +end + +class String + # ISO 15.2.10.5.5 + def =~(a) + begin + (a.class.to_s == 'String' ? Regexp.new(a.to_s) : a) =~ self + rescue + false + end + end + + # redefine methods with oniguruma regexp version + [:sub, :gsub, :split, :scan].each do |v| + alias_method "string_#{v}".to_sym, v + alias_method v, "onig_regexp_#{v}".to_sym + end + + alias_method :old_slice, :slice + alias_method :old_square_brancket, :[] + + def [](*args) + return old_square_brancket(*args) unless args[0].class == Regexp + + if args.size == 2 + match = args[0].match(self) + if match + if args[1] == 0 + str = match[0] + else + str = match.captures[args[1] - 1] + end + return str + end + end + + match_data = args[0].match(self) + if match_data + result = match_data.to_s + return result + end + end + + alias_method :slice, :[] + + def slice!(*args) + if args.size < 2 + result = slice(*args) + nth = args[0] + + if nth.class == Regexp + lm = Regexp.last_match + self[nth] = '' if result + Regexp.last_match = lm + else + self[nth] = '' if result + end + else + result = slice(*args) + + nth = args[0] + len = args[1] + + if nth.class == Regexp + lm = Regexp.last_match + self[nth, len] = '' if result + Regexp.last_match = lm + else + self[nth, len] = '' if result && nth != self.size + end + end + + result + end + + alias_method :old_index, :index + + def index(pattern, pos=0) + if pattern.class == Regexp + str = self[pos..-1] + if str + if num = (pattern =~ str) + if pos < 0 + num += self.size + end + return num + pos + end + end + nil + else + self.old_index(pattern, pos) + end + end +end + +module Kernel + def =~(_) + nil + end +end + +Regexp = OnigRegexp unless Object.const_defined?(:Regexp) +MatchData = OnigMatchData unless Object.const_defined? :MatchData + +# This is based on https://github.com/masamitsu-murase/mruby-hs-regexp diff --git a/web/server/h2o/libh2o/deps/mruby-onig-regexp/src/mruby_onig_regexp.c b/web/server/h2o/libh2o/deps/mruby-onig-regexp/src/mruby_onig_regexp.c new file mode 100644 index 000000000..38d93ccb9 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-onig-regexp/src/mruby_onig_regexp.c @@ -0,0 +1,1064 @@ +/* +The MIT License (MIT) + +Copyright (c) 2015 mattn. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION 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 <stdio.h> +#include <string.h> +#include <ctype.h> +#include <memory.h> +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/variable.h> +#include <mruby/array.h> +#include <mruby/string.h> +#include <mruby/data.h> +#include <mruby/variable.h> +#ifdef _MSC_VER +#define ONIG_EXTERN extern +#endif +#ifdef HAVE_ONIGMO_H +#include <onigmo.h> +#elif defined(HAVE_ONIGURUMA_H) +#include <oniguruma.h> +#else +#include "oniguruma.h" +#endif + +#ifdef MRUBY_VERSION +#define mrb_args_int mrb_int +#else +#define mrb_args_int int +#endif + +static const char utf8len_codepage[256] = +{ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1, +}; + +static mrb_int +utf8len(const char* p, const char* e) +{ + mrb_int len; + mrb_int i; + + len = utf8len_codepage[(unsigned char)*p]; + if (p + len > e) return 1; + for (i = 1; i < len; ++i) + if ((p[i] & 0xc0) != 0x80) + return 1; + return len; +} + +static void +onig_regexp_free(mrb_state *mrb, void *p) { + onig_free((OnigRegex) p); +} + +static struct mrb_data_type mrb_onig_regexp_type = { + "PosixRegexp", onig_regexp_free +}; + +static void +match_data_free(mrb_state* mrb, void* p) { + (void)mrb; + onig_region_free((OnigRegion*)p, 1); +} + +static struct mrb_data_type mrb_onig_region_type = { + "OnigRegion", match_data_free +}; + +static mrb_value +onig_regexp_initialize(mrb_state *mrb, mrb_value self) { + mrb_value str, flag = mrb_nil_value(), code = mrb_nil_value(); + mrb_get_args(mrb, "S|oo", &str, &flag, &code); + + int cflag = 0; + OnigEncoding enc = ONIG_ENCODING_UTF8; + if(mrb_string_p(code)) { + char const* str_code = mrb_string_value_ptr(mrb, code); + if(strchr(str_code, 'n') || strchr(str_code, 'N')) { + enc = ONIG_ENCODING_ASCII; + } + } + if(mrb_nil_p(flag)) { + } else if(mrb_type(flag) == MRB_TT_TRUE) { + cflag |= ONIG_OPTION_IGNORECASE; + } else if(mrb_fixnum_p(flag)) { + int int_flags = mrb_fixnum(flag); + if(int_flags & 0x1) { cflag |= ONIG_OPTION_IGNORECASE; } + if(int_flags & 0x2) { cflag |= ONIG_OPTION_EXTEND; } + if(int_flags & 0x4) { cflag |= ONIG_OPTION_MULTILINE; } + } else if(mrb_string_p(flag)) { + char const* str_flags = mrb_string_value_ptr(mrb, flag); + if(strchr(str_flags, 'i')) { cflag |= ONIG_OPTION_IGNORECASE; } + if(strchr(str_flags, 'x')) { cflag |= ONIG_OPTION_EXTEND; } + if(strchr(str_flags, 'm')) { cflag |= ONIG_OPTION_MULTILINE; } + } else { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown regexp flag: %S", flag); + } + + OnigErrorInfo einfo; + OnigRegex reg; + int result = onig_new(®, (OnigUChar*)RSTRING_PTR(str), (OnigUChar*) RSTRING_PTR(str) + RSTRING_LEN(str), + cflag, enc, ONIG_SYNTAX_RUBY, &einfo); + if (result != ONIG_NORMAL) { + char err[ONIG_MAX_ERROR_MESSAGE_LEN] = ""; + onig_error_code_to_str((OnigUChar*)err, result); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%S' is an invalid regular expression because %S.", + str, mrb_str_new_cstr(mrb, err)); + } + mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "@source"), str); + + DATA_PTR(self) = reg; + DATA_TYPE(self) = &mrb_onig_regexp_type; + + return self; +} + +static mrb_value +create_onig_region(mrb_state* mrb, mrb_value const str, mrb_value rex) { + mrb_assert(mrb_string_p(str)); + mrb_assert(mrb_type(rex) == MRB_TT_DATA && DATA_TYPE(rex) == &mrb_onig_regexp_type); + mrb_value const c = mrb_obj_value(mrb_data_object_alloc( + mrb, mrb_class_get(mrb, "OnigMatchData"), onig_region_new(), &mrb_onig_region_type)); + mrb_iv_set(mrb, c, mrb_intern_lit(mrb, "string"), mrb_str_dup(mrb, str)); + mrb_iv_set(mrb, c, mrb_intern_lit(mrb, "regexp"), rex); + return c; +} + +static int +onig_match_common(mrb_state* mrb, OnigRegex reg, mrb_value match_value, mrb_value str, int pos) { + mrb_assert(mrb_string_p(str)); + mrb_assert(DATA_TYPE(match_value) == &mrb_onig_region_type); + OnigRegion* const match = (OnigRegion*)DATA_PTR(match_value); + OnigUChar const* str_ptr = (OnigUChar const*)RSTRING_PTR(str); + int const result = onig_search(reg, str_ptr, str_ptr + RSTRING_LEN(str), + str_ptr + pos, str_ptr + RSTRING_LEN(str), match, 0); + if (result != ONIG_MISMATCH && result < 0) { + char err[ONIG_MAX_ERROR_MESSAGE_LEN] = ""; + onig_error_code_to_str((OnigUChar*)err, result); + mrb_raise(mrb, E_REGEXP_ERROR, err); + } + + struct RObject* const cls = (struct RObject*)mrb_class_get(mrb, "OnigRegexp"); + mrb_obj_iv_set(mrb, cls, mrb_intern_lit(mrb, "@last_match"), match_value); + + if (result != ONIG_MISMATCH && + mrb_class_get(mrb, "Regexp") == (struct RClass*)cls && + mrb_bool(mrb_obj_iv_get(mrb, (struct RObject*)cls, mrb_intern_lit(mrb, "@set_global_variables")))) + { + mrb_gv_set(mrb, mrb_intern_lit(mrb, "$~"), match_value); + mrb_gv_set(mrb, mrb_intern_lit(mrb, "$&"), + mrb_funcall(mrb, match_value, "[]", 1, mrb_fixnum_value(0))); + mrb_gv_set(mrb, mrb_intern_lit(mrb, "$`"), mrb_funcall(mrb, match_value, "pre_match", 0)); + mrb_gv_set(mrb, mrb_intern_lit(mrb, "$'"), mrb_funcall(mrb, match_value, "post_match", 0)); + mrb_gv_set(mrb, mrb_intern_lit(mrb, "$+"), + mrb_funcall(mrb, match_value, "[]", 1, mrb_fixnum_value(match->num_regs - 1))); + + // $1 to $9 + int idx = 1; + int const idx_max = match->num_regs > 10? 10 : match->num_regs; + for(; idx < idx_max; ++idx) { + char const n[] = { '$', '0' + idx }; + mrb_gv_set(mrb, mrb_intern(mrb, n, 2), + mrb_funcall(mrb, match_value, "[]", 1, mrb_fixnum_value(idx))); + } + + for(; idx < 10; ++idx) { + char const n[] = { '$', '0' + idx }; + mrb_gv_remove(mrb, mrb_intern(mrb, n, 2)); + } + } + + return result; +} + +static mrb_value +onig_regexp_match(mrb_state *mrb, mrb_value self) { + mrb_value str = mrb_nil_value(); + OnigRegex reg; + mrb_int pos = 0; + + mrb_get_args(mrb, "o|i", &str, &pos); + if (pos < 0 || (pos > 0 && pos >= RSTRING_LEN(str))) { + return mrb_nil_value(); + } + + if (mrb_nil_p(str)) { + return mrb_nil_value(); + } + str = mrb_string_type(mrb, str); + + Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, reg); + + mrb_value const ret = create_onig_region(mrb, str, self); + return (onig_match_common(mrb, reg, ret, str, pos) == ONIG_MISMATCH) + ? mrb_nil_value() : ret; +} + +static mrb_value +onig_regexp_equal(mrb_state *mrb, mrb_value self) { + mrb_value other; + OnigRegex self_reg, other_reg; + + mrb_get_args(mrb, "o", &other); + if (mrb_obj_equal(mrb, self, other)){ + return mrb_true_value(); + } + if (mrb_nil_p(other)) { + return mrb_false_value(); + } + if (!mrb_obj_is_kind_of(mrb, other, mrb_class_get(mrb, "OnigRegexp"))) { + return mrb_false_value(); + } + Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, self_reg); + Data_Get_Struct(mrb, other, &mrb_onig_regexp_type, other_reg); + + if (!self_reg || !other_reg){ + mrb_raise(mrb, E_RUNTIME_ERROR, "Invalid OnigRegexp"); + } + if (onig_get_options(self_reg) != onig_get_options(other_reg)){ + return mrb_false_value(); + } + return mrb_str_equal(mrb, mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@source")), mrb_iv_get(mrb, other, mrb_intern_lit(mrb, "@source"))) ? + mrb_true_value() : mrb_false_value(); +} + +static mrb_value +onig_regexp_casefold_p(mrb_state *mrb, mrb_value self) { + OnigRegex reg; + + Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, reg); + return (onig_get_options(reg) & ONIG_OPTION_IGNORECASE) ? mrb_true_value() : mrb_false_value(); +} + +static mrb_value +onig_regexp_options(mrb_state *mrb, mrb_value self) { + OnigRegex reg; + Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, reg); + return mrb_fixnum_value(onig_get_options(reg)); +} + +static char * +option_to_str(char str[4], int options) { + char *p = str; + if (options & ONIG_OPTION_MULTILINE) *p++ = 'm'; + if (options & ONIG_OPTION_IGNORECASE) *p++ = 'i'; + if (options & ONIG_OPTION_EXTEND) *p++ = 'x'; + *p = 0; + return str; +} + +static mrb_value +regexp_expr_str(mrb_state *mrb, mrb_value str, const char *p, int len) { + const char *pend; + char buf[5]; + + pend = (const char *) p + len; + for (;p < pend; p++) { + unsigned char c, cc; + + c = *p; + if (c == '/'|| c == '\\') { + buf[0] = '\\'; buf[1] = c; + mrb_str_cat(mrb, str, buf, 2); + continue; + } + if (ISPRINT(c)) { + buf[0] = c; + mrb_str_cat(mrb, str, buf, 1); + continue; + } + switch (c) { + case '\n': cc = 'n'; break; + case '\r': cc = 'r'; break; + case '\t': cc = 't'; break; + default: cc = 0; break; + } + if (cc) { + buf[0] = '\\'; + buf[1] = (char)cc; + mrb_str_cat(mrb, str, buf, 2); + continue; + } + else { + buf[0] = '\\'; + buf[3] = '0' + c % 8; c /= 8; + buf[2] = '0' + c % 8; c /= 8; + buf[1] = '0' + c % 8; + mrb_str_cat(mrb, str, buf, 4); + continue; + } + } + return str; +} + +static mrb_value +onig_regexp_inspect(mrb_state *mrb, mrb_value self) { + OnigRegex reg; + Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, reg); + mrb_value str = mrb_str_new_lit(mrb, "/"); + mrb_value src = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@source")); + regexp_expr_str(mrb, str, (const char *)RSTRING_PTR(src), RSTRING_LEN(src)); + mrb_str_cat_lit(mrb, str, "/"); + char opts[4]; + if (*option_to_str(opts, onig_get_options(reg))) { + mrb_str_cat_cstr(mrb, str, opts); + } + if (onig_get_encoding(reg) == ONIG_ENCODING_ASCII) { + mrb_str_cat_lit(mrb, str, "n"); + } + return str; +} + +static mrb_value +onig_regexp_to_s(mrb_state *mrb, mrb_value self) { + int options; + const int embeddable = ONIG_OPTION_MULTILINE|ONIG_OPTION_IGNORECASE|ONIG_OPTION_EXTEND; + long len; + const char* ptr; + mrb_value str = mrb_str_new_lit(mrb, "(?"); + char optbuf[5]; + + OnigRegex reg; + Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, reg); + options = onig_get_options(reg); + mrb_value src = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@source")); + ptr = RSTRING_PTR(src); + len = RSTRING_LEN(src); + + again: + if (len >= 4 && ptr[0] == '(' && ptr[1] == '?') { + int err = 1; + ptr += 2; + if ((len -= 2) > 0) { + do { + if(strchr(ptr, 'i')) { options |= ONIG_OPTION_IGNORECASE; } + if(strchr(ptr, 'x')) { options |= ONIG_OPTION_EXTEND; } + if(strchr(ptr, 'm')) { options |= ONIG_OPTION_MULTILINE; } + ++ptr; + } while (--len > 0); + } + if (len > 1 && *ptr == '-') { + ++ptr; + --len; + do { + if(strchr(ptr, 'i')) { options &= ~ONIG_OPTION_IGNORECASE; } + if(strchr(ptr, 'x')) { options &= ~ONIG_OPTION_EXTEND; } + if(strchr(ptr, 'm')) { options &= ~ONIG_OPTION_MULTILINE; } + ++ptr; + } while (--len > 0); + } + if (*ptr == ')') { + --len; + ++ptr; + goto again; + } + if (*ptr == ':' && ptr[len-1] == ')') { + OnigRegex rp; + ++ptr; + len -= 2; + err = onig_new(&rp, (OnigUChar*)ptr, (OnigUChar*)ptr + len, ONIG_OPTION_DEFAULT, + ONIG_ENCODING_UTF8, OnigDefaultSyntax, NULL); + onig_free(rp); + } + if (err) { + options = onig_get_options(reg); + ptr = RSTRING_PTR(src); + len = RSTRING_LEN(src); + } + } + + if (*option_to_str(optbuf, options)) mrb_str_cat_cstr(mrb, str, optbuf); + + if ((options & embeddable) != embeddable) { + optbuf[0] = '-'; + option_to_str(optbuf + 1, ~options); + mrb_str_cat_cstr(mrb, str, optbuf); + } + + mrb_str_cat_cstr(mrb, str, ":"); + regexp_expr_str(mrb, str, ptr, len); + mrb_str_cat_cstr(mrb, str, ")"); + return str; +} + + +static mrb_value +onig_regexp_version(mrb_state* mrb, mrb_value self) { + (void)self; + return mrb_str_new_cstr(mrb, onig_version()); +} + +static mrb_value +match_data_to_a(mrb_state* mrb, mrb_value self); + +static mrb_int +match_data_actual_index(mrb_state* mrb, mrb_value self, mrb_value idx_value) { + if(mrb_fixnum_p(idx_value)) { return mrb_fixnum(idx_value); } + + char const* name = NULL; + char const* name_end = NULL; + if(mrb_symbol_p(idx_value)) { + mrb_int sym_len; + name = mrb_sym2name_len(mrb, mrb_symbol(idx_value), &sym_len); + name_end = name + sym_len; + } else if(mrb_string_p(idx_value)) { + name = mrb_string_value_ptr(mrb, idx_value); + name_end = name + strlen(name); + } else { mrb_assert(FALSE); } + mrb_assert(name && name_end); + + mrb_value const regexp = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "regexp")); + mrb_assert(!mrb_nil_p(regexp)); + mrb_assert(DATA_TYPE(regexp) == &mrb_onig_regexp_type); + mrb_assert(DATA_TYPE(self) == &mrb_onig_region_type); + int const idx = onig_name_to_backref_number( + (OnigRegex)DATA_PTR(regexp), (OnigUChar const*)name, (OnigUChar const*)name_end, + (OnigRegion*)DATA_PTR(self)); + if (idx < 0) { + mrb_raisef(mrb, E_INDEX_ERROR, "undefined group name reference: %S", idx_value); + } + return idx; +} + +// ISO 15.2.16.3.1 +static mrb_value +match_data_index(mrb_state* mrb, mrb_value self) { + mrb_value src; + mrb_int argc; mrb_value *argv; + + mrb_get_args(mrb, "*", &argv, &argc); + + src = match_data_to_a(mrb, self); + + if (argc == 1) { + switch (mrb_type(argv[0])) { + case MRB_TT_FIXNUM: + case MRB_TT_SYMBOL: + case MRB_TT_STRING: + return mrb_ary_entry(src, match_data_actual_index(mrb, self, argv[0])); + default: break; + } + } + + return mrb_funcall_argv(mrb, src, mrb_intern_lit(mrb, "[]"), argc, argv); +} + +#define match_data_check_index(idx) \ + if(idx < 0 || reg->num_regs <= idx) \ + mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of matches", mrb_fixnum_value(idx)) \ + +// ISO 15.2.16.3.2 +static mrb_value +match_data_begin(mrb_state* mrb, mrb_value self) { + mrb_value idx_value; + mrb_get_args(mrb, "o", &idx_value); + OnigRegion* reg; + Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg); + mrb_int const idx = match_data_actual_index(mrb, self, idx_value); + match_data_check_index(idx); + return mrb_fixnum_value(reg->beg[idx]); +} + +// ISO 15.2.16.3.3 +static mrb_value +match_data_captures(mrb_state* mrb, mrb_value self) { + mrb_value ary = match_data_to_a(mrb, self); + return mrb_ary_new_from_values(mrb, RARRAY_LEN(ary) - 1, RARRAY_PTR(ary) + 1); +} + +// ISO 15.2.16.3.4 +static mrb_value +match_data_end(mrb_state* mrb, mrb_value self) { + mrb_value idx_value; + mrb_get_args(mrb, "o", &idx_value); + OnigRegion* reg; + Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg); + mrb_int const idx = match_data_actual_index(mrb, self, idx_value); + match_data_check_index(idx); + return mrb_fixnum_value(reg->end[idx]); +} + +// ISO 15.2.16.3.5 +static mrb_value +match_data_copy(mrb_state* mrb, mrb_value self) { + mrb_value src_val; + mrb_get_args(mrb, "o", &src_val); + + OnigRegion* src; + Data_Get_Struct(mrb, src_val, &mrb_onig_region_type, src); + + OnigRegion* dst = onig_region_new(); + onig_region_copy(dst, src); + + DATA_PTR(self) = dst; + DATA_TYPE(self) = &mrb_onig_region_type; + mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "string"), mrb_iv_get(mrb, src_val, mrb_intern_lit(mrb, "string"))); + mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "regexp"), mrb_iv_get(mrb, src_val, mrb_intern_lit(mrb, "regexp"))); + return self; +} + +// ISO 15.2.16.3.6 +// ISO 15.2.16.3.10 +static mrb_value +match_data_length(mrb_state* mrb, mrb_value self) { + OnigRegion* reg; + Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg); + return mrb_fixnum_value(reg->num_regs); +} + +// ISO 15.2.16.3.7 +static mrb_value +match_data_offset(mrb_state* mrb, mrb_value self) { + mrb_value idx_value; + mrb_get_args(mrb, "o", &idx_value); + OnigRegion* reg; + Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg); + mrb_int const idx = match_data_actual_index(mrb, self, idx_value); + match_data_check_index(idx); + mrb_value ret = mrb_ary_new_capa(mrb, 2); + mrb_ary_push(mrb, ret, mrb_fixnum_value(reg->beg[idx])); + mrb_ary_push(mrb, ret, mrb_fixnum_value(reg->end[idx])); + return ret; +} + +// ISO 15.2.16.3.8 +static mrb_value +match_data_post_match(mrb_state* mrb, mrb_value self) { + OnigRegion* reg; + Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg); + mrb_value str = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "string")); + return mrb_str_substr(mrb, str, reg->end[0], RSTRING_LEN(str) - reg->end[0]); +} + +// ISO 15.2.16.3.9 +static mrb_value +match_data_pre_match(mrb_state* mrb, mrb_value self) { + OnigRegion* reg; + Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg); + mrb_value str = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "string")); + return mrb_str_substr(mrb, str, 0, reg->beg[0]); +} + +// ISO 15.2.16.3.11 +static mrb_value +match_data_string(mrb_state* mrb, mrb_value self) { + return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "string")); +} + +static mrb_value +match_data_regexp(mrb_state* mrb, mrb_value self) { + return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "regexp")); +} + +// ISO 15.2.16.3.12 +static mrb_value +match_data_to_a(mrb_state* mrb, mrb_value self) { + mrb_value cache = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "cache")); + if(!mrb_nil_p(cache)) { + return cache; + } + + mrb_value str = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "string")); + OnigRegion* reg; + Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg); + + mrb_value ret = mrb_ary_new_capa(mrb, reg->num_regs); + int i, ai = mrb_gc_arena_save(mrb); + for(i = 0; i < reg->num_regs; ++i) { + if(reg->beg[i] == ONIG_REGION_NOTPOS) { + mrb_ary_push(mrb, ret, mrb_nil_value()); + } else { + mrb_ary_push(mrb, ret, mrb_str_substr(mrb, str, reg->beg[i], reg->end[i] - reg->beg[i])); + } + mrb_gc_arena_restore(mrb, ai); + } + return ret; +} + +// ISO 15.2.16.3.13 +static mrb_value +match_data_to_s(mrb_state* mrb, mrb_value self) { + mrb_value str = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "string")); + OnigRegion* reg; + Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg); + return mrb_str_substr(mrb, str, reg->beg[0], reg->end[0] - reg->beg[0]); +} + +static void +append_replace_str(mrb_state* mrb, mrb_value result, mrb_value replace, + mrb_value src, OnigRegex reg, OnigRegion* match) +{ + mrb_assert(mrb_string_p(replace)); + char const* ch; + char const* const end = RSTRING_PTR(replace) + RSTRING_LEN(replace); + for(ch = RSTRING_PTR(replace); ch < end; ++ch) { + if (*ch != '\\' || (ch + 1) >= end) { + mrb_str_cat(mrb, result, ch, 1); + continue; + } + + switch(*(++ch)) { // skip back slash and get next char + case 'k': { // group name + if ((ch + 2) >= end || ch[1] != '<') { goto replace_expr_error; } + char const* name_beg = ch += 2; + while (*ch != '>') { if(++ch == end) { goto replace_expr_error; } } + mrb_assert(ch < end); + mrb_assert(*ch == '>'); + int const idx = onig_name_to_backref_number( + reg, (OnigUChar const*)name_beg, (OnigUChar const*)ch, match); + if (idx < 0) { + mrb_raisef(mrb, E_INDEX_ERROR, "undefined group name reference: %S", + mrb_str_substr(mrb, replace, name_beg - RSTRING_PTR(replace), ch - name_beg)); + } + mrb_str_cat(mrb, result, RSTRING_PTR(src) + match->beg[idx], match->end[idx] - match->beg[idx]); + } break; + + case '\\': // escaped back slash + mrb_str_cat(mrb, result, ch, 1); + break; + + default: + if (isdigit(*ch)) { // group number 0-9 + int const idx = *ch - '0'; + if (idx < match->num_regs) { + mrb_str_cat(mrb, result, RSTRING_PTR(src) + match->beg[idx], match->end[idx] - match->beg[idx]); + } + } else { + char const str[] = { '\\', *ch }; + mrb_str_cat(mrb, result, str, 2); + } + break; + } + } + + if(ch == end) { return; } + +replace_expr_error: + mrb_raisef(mrb, E_REGEXP_ERROR, "invalid replace expression: %S", replace); +} + +// ISO 15.2.10.5.18 +static mrb_value +string_gsub(mrb_state* mrb, mrb_value self) { + mrb_value blk, match_expr, replace_expr = mrb_nil_value(); + int const argc = mrb_get_args(mrb, "&o|S", &blk, &match_expr, &replace_expr); + + if(mrb_string_p(match_expr)) { + mrb_value argv[] = { match_expr, replace_expr }; + return mrb_funcall_with_block(mrb, self, mrb_intern_lit(mrb, "string_gsub"), argc, argv, blk); + } + + if(!mrb_nil_p(blk) && !mrb_nil_p(replace_expr)) { + blk = mrb_nil_value(); + } + + OnigRegex reg; + Data_Get_Struct(mrb, match_expr, &mrb_onig_regexp_type, reg); + mrb_value const result = mrb_str_new(mrb, NULL, 0); + mrb_value const match_value = create_onig_region(mrb, self, match_expr); + OnigRegion* const match = (OnigRegion*)DATA_PTR(match_value); + int last_end_pos = 0; + + while(1) { + if(onig_match_common(mrb, reg, match_value, self, last_end_pos) == ONIG_MISMATCH) { break; } + + mrb_str_cat(mrb, result, RSTRING_PTR(self) + last_end_pos, match->beg[0] - last_end_pos); + + if(mrb_nil_p(blk)) { + append_replace_str(mrb, result, replace_expr, self, reg, match); + } else { + mrb_value const tmp_str = mrb_str_to_str(mrb, mrb_yield(mrb, blk, mrb_str_substr( + mrb, self, match->beg[0], match->end[0] - match->beg[0]))); + mrb_assert(mrb_string_p(tmp_str)); + mrb_str_concat(mrb, result, tmp_str); + } + + last_end_pos = match->end[0]; + if (match->beg[0] == match->end[0]) { + /* + * Always consume at least one character of the input string + * in order to prevent infinite loops. + */ + char* p = RSTRING_PTR(self) + last_end_pos; + char* e = p + RSTRING_LEN(self); + int len = utf8len(p, e); + if (RSTRING_LEN(self) < last_end_pos + len) break; + mrb_str_cat(mrb, result, p, len); + last_end_pos += len; + } + } + + mrb_str_cat(mrb, result, RSTRING_PTR(self) + last_end_pos, RSTRING_LEN(self) - last_end_pos); + return result; +} + +// ISO 15.2.10.5.32 +static mrb_value +string_scan(mrb_state* mrb, mrb_value self) { + mrb_value blk, match_expr; + mrb_get_args(mrb, "&o", &blk, &match_expr); + + if(mrb_string_p(match_expr)) { + return mrb_funcall_with_block(mrb, self, mrb_intern_lit(mrb, "string_scan"), + 1, &match_expr, blk); + } + + OnigRegex reg; + Data_Get_Struct(mrb, match_expr, &mrb_onig_regexp_type, reg); + mrb_value const result = mrb_nil_p(blk)? mrb_ary_new(mrb) : self; + mrb_value m_value = create_onig_region(mrb, self, match_expr); + OnigRegion* const m = (OnigRegion*)DATA_PTR(m_value); + int last_end_pos = 0; + int i; + + while (1) { + if(onig_match_common(mrb, reg, m_value, self, last_end_pos) == ONIG_MISMATCH) { break; } + + if(mrb_nil_p(blk)) { + mrb_assert(mrb_array_p(result)); + if(m->num_regs == 1) { + mrb_ary_push(mrb, result, mrb_str_substr(mrb, self, m->beg[0], m->end[0] - m->beg[0])); + } else { + mrb_value const elem = mrb_ary_new_capa(mrb, m->num_regs - 1); + for(i = 1; i < m->num_regs; ++i) { + mrb_ary_push(mrb, elem, mrb_str_substr(mrb, self, m->beg[i], m->end[i] - m->beg[i])); + } + mrb_ary_push(mrb, result, elem); + } + } else { // call block + mrb_assert(mrb_string_p(result)); + if(m->num_regs == 1) { + mrb_yield(mrb, blk, mrb_str_substr(mrb, self, m->beg[0], m->end[0] - m->beg[0])); + } else { + mrb_value argv = mrb_ary_new_capa(mrb, m->num_regs - 1); + for(i = 1; i < m->num_regs; ++i) { + mrb_ary_push(mrb, argv, mrb_str_substr(mrb, self, m->beg[i], m->end[i] - m->beg[i])); + } + mrb_yield(mrb, blk, argv); + } + } + + last_end_pos = m->end[0]; + } + + return result; +} + +// ISO 15.2.10.5.35 +static mrb_value +string_split(mrb_state* mrb, mrb_value self) { + mrb_value pattern = mrb_nil_value(); mrb_int limit = 0; + int argc = mrb_get_args(mrb, "|oi", &pattern, &limit); + + if(argc == 0) { // check $; global variable + pattern = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$;")); + if(!mrb_nil_p(pattern)) { argc = 1; } + } + + if(mrb_nil_p(pattern) || mrb_string_p(pattern)) { + return mrb_funcall(mrb, self, "string_split", argc, pattern, mrb_fixnum_value(limit)); + } + + mrb_value const result = mrb_ary_new(mrb); + if(RSTRING_LEN(self) == 0) { return result; } + + OnigRegex reg; + Data_Get_Struct(mrb, pattern, &mrb_onig_regexp_type, reg); + mrb_value const match_value = create_onig_region(mrb, self, pattern); + OnigRegion* const match = (OnigRegion*)DATA_PTR(match_value); + int last_end_pos = 0, next_match_pos = 0; + mrb_int num_matches = 0; + + while (limit <= 0 || (limit - 1) > num_matches) { + int i; + if(next_match_pos >= RSTRING_LEN(self) || + onig_match_common(mrb, reg, match_value, self, next_match_pos) == ONIG_MISMATCH) { break; } + + if (last_end_pos == match->end[0]) { + ++next_match_pos; + // Remove this loop if not using UTF-8 + for (; next_match_pos < RSTRING_LEN(self) && (RSTRING_PTR(self)[next_match_pos] & 0xC0) == 0x80; + ++next_match_pos) {} + } else { + mrb_ary_push(mrb, result, mrb_str_substr( + mrb, self, last_end_pos, match->beg[0] - last_end_pos)); + // If there are captures, add them to the array + for (i = 1; i < match->num_regs; ++i) { + mrb_ary_push(mrb, result, mrb_str_substr( + mrb, self, match->beg[i], match->end[i] - match->beg[i])); + } + last_end_pos = match->end[0]; + next_match_pos = last_end_pos; + ++num_matches; + } + } + if (last_end_pos <= RSTRING_LEN(self)) { + mrb_ary_push(mrb, result, mrb_str_substr( + mrb, self, last_end_pos, RSTRING_LEN(self) - last_end_pos)); + } + + if (limit == 0) { // remove empty trailing elements + int count = 0, i; + for (i = RARRAY_LEN(result); i > 0; --i) { + mrb_assert(mrb_string_p(RARRAY_PTR(result)[i - 1])); + if (RSTRING_LEN(RARRAY_PTR(result)[i - 1]) != 0) { break; } + else { ++count; } + } + if(count > 0) { + return mrb_ary_new_from_values(mrb, RARRAY_LEN(result) - count, RARRAY_PTR(result)); + } + } + + return result; +} + +// ISO 15.2.10.5.36 +static mrb_value +string_sub(mrb_state* mrb, mrb_value self) { + mrb_value blk, match_expr, replace_expr = mrb_nil_value(); + int const argc = mrb_get_args(mrb, "&o|S", &blk, &match_expr, &replace_expr); + + if(mrb_string_p(match_expr)) { + mrb_value argv[] = { match_expr, replace_expr }; + return mrb_funcall_with_block(mrb, self, mrb_intern_lit(mrb, "string_sub"), argc, argv, blk); + } + + if(!mrb_nil_p(blk) && !mrb_nil_p(replace_expr)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "both block and replace expression must not be passed"); + } + + OnigRegex reg; + Data_Get_Struct(mrb, match_expr, &mrb_onig_regexp_type, reg); + mrb_value const result = mrb_str_new(mrb, NULL, 0); + mrb_value const match_value = create_onig_region(mrb, self, match_expr); + OnigRegion* const match = (OnigRegion*)DATA_PTR(match_value); + + int const onig_result = onig_match_common(mrb, reg, match_value, self, 0); + if(onig_result == ONIG_MISMATCH) { return self; } + + mrb_str_cat(mrb, result, RSTRING_PTR(self), match->beg[0]); + + if(mrb_nil_p(blk)) { + append_replace_str(mrb, result, replace_expr, self, reg, match); + } else { + mrb_value const tmp_str = mrb_str_to_str(mrb, mrb_yield(mrb, blk, mrb_str_substr( + mrb, self, match->beg[0], match->end[0] - match->beg[0]))); + mrb_assert(mrb_string_p(tmp_str)); + mrb_str_concat(mrb, result, tmp_str); + } + + int const last_end_pos = match->end[0]; + mrb_str_cat(mrb, result, RSTRING_PTR(self) + last_end_pos, RSTRING_LEN(self) - last_end_pos); + + return result; +} + +static mrb_value +onig_regexp_clear_global_variables(mrb_state* mrb, mrb_value self) { + mrb_gv_remove(mrb, mrb_intern_lit(mrb, "$~")); + mrb_gv_remove(mrb, mrb_intern_lit(mrb, "$&")); + mrb_gv_remove(mrb, mrb_intern_lit(mrb, "$`")); + mrb_gv_remove(mrb, mrb_intern_lit(mrb, "$'")); + mrb_gv_remove(mrb, mrb_intern_lit(mrb, "$+")); + + int idx; + for(idx = 1; idx < 10; ++idx) { + char const n[] = { '$', '0' + idx }; + mrb_gv_remove(mrb, mrb_intern(mrb, n, 2)); + } + + return self; +} + +static mrb_value +onig_regexp_does_set_global_variables(mrb_state* mrb, mrb_value self) { + (void)self; + return mrb_obj_iv_get(mrb, (struct RObject*)mrb_class_get(mrb, "OnigRegexp"), + mrb_intern_lit(mrb, "@set_global_variables")); +} +static mrb_value +onig_regexp_set_set_global_variables(mrb_state* mrb, mrb_value self) { + mrb_value arg; + mrb_get_args(mrb, "o", &arg); + mrb_value const ret = mrb_bool_value(mrb_bool(arg)); + mrb_obj_iv_set(mrb, (struct RObject*)mrb_class_get(mrb, "OnigRegexp"), + mrb_intern_lit(mrb, "@set_global_variables"), ret); + onig_regexp_clear_global_variables(mrb, self); + return ret; +} + +// ISO 15.2.15.6.2 +static mrb_value +onig_regexp_escape(mrb_state* mrb, mrb_value self) { + char* str_begin; mrb_args_int str_len; + mrb_get_args(mrb, "s", &str_begin, &str_len); + + mrb_value const ret = mrb_str_new(mrb, NULL, 0); + char escaped_char = 0; + int substr_count = 0; + char const* str = str_begin; + + for(; str < (str_begin + str_len); ++str) { + switch(*str) { + case '\n': escaped_char = 'n'; break; + case '\t': escaped_char = 't'; break; + case '\r': escaped_char = 'r'; break; + case '\f': escaped_char = 'f'; break; + + case ' ': + case '#': + case '$': + case '(': + case ')': + case '*': + case '+': + case '-': + case '.': + case '?': + case '[': + case '\\': + case ']': + case '^': + case '{': + case '|': + case '}': + escaped_char = *str; break; + + default: ++substr_count; continue; + } + + mrb_str_cat(mrb, ret, str - substr_count, substr_count); + substr_count = 0; + + char const c[] = { '\\', escaped_char }; + mrb_str_cat(mrb, ret, c, 2); + } + mrb_str_cat(mrb, ret, str - substr_count, substr_count); + return ret; +} + +void +mrb_mruby_onig_regexp_gem_init(mrb_state* mrb) { + struct RClass *clazz; + + clazz = mrb_define_class(mrb, "OnigRegexp", mrb->object_class); + MRB_SET_INSTANCE_TT(clazz, MRB_TT_DATA); + + // enable global variables setting in onig_match_common by default + mrb_obj_iv_set(mrb, (struct RObject*)clazz, mrb_intern_lit(mrb, "@set_global_variables"), mrb_true_value()); + + mrb_define_const(mrb, clazz, "IGNORECASE", mrb_fixnum_value(ONIG_OPTION_IGNORECASE)); + mrb_define_const(mrb, clazz, "EXTENDED", mrb_fixnum_value(ONIG_OPTION_EXTEND)); + mrb_define_const(mrb, clazz, "MULTILINE", mrb_fixnum_value(ONIG_OPTION_MULTILINE)); + mrb_define_const(mrb, clazz, "SINGLELINE", mrb_fixnum_value(ONIG_OPTION_SINGLELINE)); + mrb_define_const(mrb, clazz, "FIND_LONGEST", mrb_fixnum_value(ONIG_OPTION_FIND_LONGEST)); + mrb_define_const(mrb, clazz, "FIND_NOT_EMPTY", mrb_fixnum_value(ONIG_OPTION_FIND_NOT_EMPTY)); + mrb_define_const(mrb, clazz, "NEGATE_SINGLELINE", mrb_fixnum_value(ONIG_OPTION_NEGATE_SINGLELINE)); + mrb_define_const(mrb, clazz, "DONT_CAPTURE_GROUP", mrb_fixnum_value(ONIG_OPTION_DONT_CAPTURE_GROUP)); + mrb_define_const(mrb, clazz, "CAPTURE_GROUP", mrb_fixnum_value(ONIG_OPTION_CAPTURE_GROUP)); + mrb_define_const(mrb, clazz, "NOTBOL", mrb_fixnum_value(ONIG_OPTION_NOTBOL)); + mrb_define_const(mrb, clazz, "NOTEOL", mrb_fixnum_value(ONIG_OPTION_NOTEOL)); +#ifdef ONIG_OPTION_POSIX_REGION + mrb_define_const(mrb, clazz, "POSIX_REGION", mrb_fixnum_value(ONIG_OPTION_POSIX_REGION)); +#endif +#ifdef ONIG_OPTION_ASCII_RANGE + mrb_define_const(mrb, clazz, "ASCII_RANGE", mrb_fixnum_value(ONIG_OPTION_ASCII_RANGE)); +#endif +#ifdef ONIG_OPTION_POSIX_BRACKET_ALL_RANGE + mrb_define_const(mrb, clazz, "POSIX_BRACKET_ALL_RANGE", mrb_fixnum_value(ONIG_OPTION_POSIX_BRACKET_ALL_RANGE)); +#endif +#ifdef ONIG_OPTION_WORD_BOUND_ALL_RANGE + mrb_define_const(mrb, clazz, "WORD_BOUND_ALL_RANGE", mrb_fixnum_value(ONIG_OPTION_WORD_BOUND_ALL_RANGE)); +#endif +#ifdef ONIG_OPTION_NEWLINE_CRLF + mrb_define_const(mrb, clazz, "NEWLINE_CRLF", mrb_fixnum_value(ONIG_OPTION_NEWLINE_CRLF)); +#endif +#ifdef ONIG_OPTION_NOTBOS + mrb_define_const(mrb, clazz, "NOTBOS", mrb_fixnum_value(ONIG_OPTION_NOTBOS)); +#endif +#ifdef ONIG_OPTION_NOTEOS + mrb_define_const(mrb, clazz, "NOTEOS", mrb_fixnum_value(ONIG_OPTION_NOTEOS)); +#endif + + mrb_define_method(mrb, clazz, "initialize", onig_regexp_initialize, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(2)); + mrb_define_method(mrb, clazz, "==", onig_regexp_equal, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, clazz, "match", onig_regexp_match, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); + mrb_define_method(mrb, clazz, "casefold?", onig_regexp_casefold_p, MRB_ARGS_NONE()); + + mrb_define_method(mrb, clazz, "options", onig_regexp_options, MRB_ARGS_NONE()); + mrb_define_method(mrb, clazz, "inspect", onig_regexp_inspect, MRB_ARGS_NONE()); + mrb_define_method(mrb, clazz, "to_s", onig_regexp_to_s, MRB_ARGS_NONE()); + + mrb_define_module_function(mrb, clazz, "escape", onig_regexp_escape, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, clazz, "quote", onig_regexp_escape, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, clazz, "version", onig_regexp_version, MRB_ARGS_NONE()); + mrb_define_module_function(mrb, clazz, "set_global_variables?", onig_regexp_does_set_global_variables, MRB_ARGS_NONE()); + mrb_define_module_function(mrb, clazz, "set_global_variables=", onig_regexp_set_set_global_variables, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, clazz, "clear_global_variables", onig_regexp_clear_global_variables, MRB_ARGS_NONE()); + + struct RClass* match_data = mrb_define_class(mrb, "OnigMatchData", mrb->object_class); + MRB_SET_INSTANCE_TT(clazz, MRB_TT_DATA); + mrb_undef_class_method(mrb, match_data, "new"); + + // mrb_define_method(mrb, match_data, "==", &match_data_eq); + mrb_define_method(mrb, match_data, "[]", &match_data_index, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, match_data, "begin", &match_data_begin, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, match_data, "captures", &match_data_captures, MRB_ARGS_NONE()); + mrb_define_method(mrb, match_data, "end", &match_data_end, MRB_ARGS_REQ(1)); + // mrb_define_method(mrb, match_data, "eql?", &match_data_eq); + // mrb_define_method(mrb, match_data, "hash", &match_data_hash); + mrb_define_method(mrb, match_data, "initialize_copy", &match_data_copy, MRB_ARGS_REQ(1)); + // mrb_define_method(mrb, match_data, "inspect", &match_data_inspect); + mrb_define_method(mrb, match_data, "length", &match_data_length, MRB_ARGS_NONE()); + // mrb_define_method(mrb, match_data, "names", &match_data_names); + mrb_define_method(mrb, match_data, "offset", &match_data_offset, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, match_data, "post_match", &match_data_post_match, MRB_ARGS_NONE()); + mrb_define_method(mrb, match_data, "pre_match", &match_data_pre_match, MRB_ARGS_NONE()); + mrb_define_method(mrb, match_data, "regexp", &match_data_regexp, MRB_ARGS_NONE()); + mrb_define_method(mrb, match_data, "size", &match_data_length, MRB_ARGS_NONE()); + mrb_define_method(mrb, match_data, "string", &match_data_string, MRB_ARGS_NONE()); + mrb_define_method(mrb, match_data, "to_a", &match_data_to_a, MRB_ARGS_NONE()); + mrb_define_method(mrb, match_data, "to_s", &match_data_to_s, MRB_ARGS_NONE()); + // mrb_define_method(mrb, match_data, "values_at", &match_data_values_at); + + mrb_define_method(mrb, mrb->string_class, "onig_regexp_gsub", &string_gsub, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1) | MRB_ARGS_BLOCK()); + mrb_define_method(mrb, mrb->string_class, "onig_regexp_sub", &string_sub, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1) | MRB_ARGS_BLOCK()); + mrb_define_method(mrb, mrb->string_class, "onig_regexp_split", &string_split, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mrb->string_class, "onig_regexp_scan", &string_scan, MRB_ARGS_REQ(1) | MRB_ARGS_BLOCK()); +} + +void +mrb_mruby_onig_regexp_gem_final(mrb_state* mrb) { + (void)mrb; +} + +// vim:set et: diff --git a/web/server/h2o/libh2o/deps/mruby-onig-regexp/test/mruby_onig_regexp.rb b/web/server/h2o/libh2o/deps/mruby-onig-regexp/test/mruby_onig_regexp.rb new file mode 100644 index 000000000..e70b06fd8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-onig-regexp/test/mruby_onig_regexp.rb @@ -0,0 +1,398 @@ + +# Constant +assert("OnigRegexp::CONSTANT") do + OnigRegexp::IGNORECASE == 1 and OnigRegexp::EXTENDED == 2 and OnigRegexp::MULTILINE == 4 +end + + +# Class method +assert('OnigRgexp.compile', '15.2.15.6.2') do + assert_equal OnigRegexp.compile('.*'), OnigRegexp.compile('.*') +end + +assert('OnigRegexp.escape', '15.2.15.6.2') do + escaping_chars = "\n\t\r\f #$()*+-.?[\\]^{|}" + assert_equal '\n\t\r\f\\ \#\$\(\)\*\+\-\.\?\[\\\\\]\^\{\|\}', OnigRegexp.escape(escaping_chars) + assert_equal 'cute\nmruby\tcute', OnigRegexp.escape("cute\nmruby\tcute") +end + +assert('OnigRegexp.last_match', '15.2.15.6.3') do + OnigRegexp.new('.*') =~ 'ginka' + assert_equal 'ginka', OnigRegexp.last_match[0] +end + +assert('OnigRegexp.quote', '15.2.15.6.4') do + assert_equal '\n', OnigRegexp.quote("\n") +end + +# Instance method +assert('OnigRegexp#initialize', '15.2.15.7.1') do + OnigRegexp.new(".*") and OnigRegexp.new(".*", OnigRegexp::MULTILINE) +end + +assert('OnigRegexp#initialize_copy', '15.2.15.7.2') do + r1 = OnigRegexp.new(".*") + r2 = r1.dup + assert_equal r1, r2 + assert_equal 'kawa', r2.match('kawa')[0] +end + +assert("OnigRegexp#==", '15.2.15.7.3') do + reg1 = reg2 = OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+") + reg3 = OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+") + reg4 = OnigRegexp.new("(https://[^/]+)[-a-zA-Z0-9./]+") + + assert_true(reg1 == reg2 && reg1 == reg3 && !(reg1 == reg4)) + + assert_false(OnigRegexp.new("a") == "a") +end + +assert("OnigRegexp#===", '15.2.15.7.4') do + reg = OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+") + assert_true reg === "http://example.com" + assert_false reg === "htt://example.com" +end + +assert('OnigRegexp#=~', '15.2.15.7.5') do + assert_equal(0) { OnigRegexp.new('.*') =~ 'akari' } + assert_equal(nil) { OnigRegexp.new('t') =~ 'akari' } +end + +assert("OnigRegexp#casefold?", '15.2.15.7.6') do + assert_false OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+", OnigRegexp::MULTILINE).casefold? + assert_true OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+", OnigRegexp::IGNORECASE | OnigRegexp::EXTENDED).casefold? + assert_true OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+", OnigRegexp::MULTILINE | OnigRegexp::IGNORECASE).casefold? + assert_false OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+").casefold? + assert_true OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+", true).casefold? +end + +assert("OnigRegexp#match", '15.2.15.7.7') do + reg = OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+") + assert_false reg.match("http://masamitsu-murase.12345/hoge.html").nil? + assert_nil reg.match("http:///masamitsu-murase.12345/hoge.html") +end + +assert("OnigRegexp#source", '15.2.15.7.8') do + str = "(https?://[^/]+)[-a-zA-Z0-9./]+" + reg = OnigRegexp.new(str) + + reg.source == str +end + +if OnigRegexp.const_defined? :ASCII_RANGE + assert('OnigRegexp#options (no options)') do + assert_equal OnigRegexp::ASCII_RANGE | OnigRegexp::POSIX_BRACKET_ALL_RANGE | OnigRegexp::WORD_BOUND_ALL_RANGE, OnigRegexp.new(".*").options + end + + assert('OnigRegexp#options (multiline)') do + assert_equal OnigRegexp::MULTILINE | OnigRegexp::ASCII_RANGE | OnigRegexp::POSIX_BRACKET_ALL_RANGE | OnigRegexp::WORD_BOUND_ALL_RANGE, OnigRegexp.new(".*", OnigRegexp::MULTILINE).options + end +end + +assert("OnigRegexp#inspect") do + reg = OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+") + + assert_equal '/(https?:\/\/[^\/]+)[-a-zA-Z0-9.\/]+/', reg.inspect + assert_equal '/abc\nd\te/mi', OnigRegexp.new("abc\nd\te", OnigRegexp::MULTILINE | OnigRegexp::IGNORECASE).inspect + assert_equal '/abc/min', OnigRegexp.new("abc", OnigRegexp::MULTILINE | OnigRegexp::IGNORECASE, "none").inspect +end + +assert("OnigRegexp#to_s") do + assert_equal '(?-mix:ab+c)', OnigRegexp.new("ab+c").to_s + assert_equal '(?-mix:ab+c)', /ab+c/.to_s + assert_equal '(?mx-i:ab+c)', OnigRegexp.new("ab+c", OnigRegexp::MULTILINE | OnigRegexp::EXTENDED).to_s + assert_equal '(?mi-x:ab+c)', /ab+c/im.to_s + assert_equal '(?mi-x:ab+c)', /ab+c/imn.to_s +end + +assert("OnigRegexp#to_s (composition)") do + re1 = OnigRegexp.new("ab+c") + re2 = OnigRegexp.new("xy#{re1}z") + assert_equal '(?-mix:xy(?-mix:ab+c)z)', re2.to_s + + re3 = OnigRegexp.new("ab.+c", OnigRegexp::MULTILINE) + re4 = OnigRegexp.new("xy#{re3}z", OnigRegexp::IGNORECASE) + assert_equal '(?i-mx:xy(?m-ix:ab.+c)z)', re4.to_s +end + +# Extended patterns. +assert("OnigRegexp#match (no flags)") do + [ + [ ".*", "abcd\nefg", "abcd" ], + [ "^a.", "abcd\naefg", "ab" ], + [ "^a.", "bacd\naefg", "ae" ], + [ ".$", "bacd\naefg", "d" ] + ].each do |reg, str, result| + m = OnigRegexp.new(reg).match(str) + assert_equal result, m[0] if assert_false m.nil? + end +end + +assert("OnigRegexp#match (multiline)") do + patterns = [ + [ OnigRegexp.new(".*", OnigRegexp::MULTILINE), "abcd\nefg", "abcd\nefg" ] + ] + + patterns.all?{ |reg, str, result| reg.match(str)[0] == result } +end + +assert("OnigRegexp#match (ignorecase)") do + [ + [ "aBcD", "00AbcDef", "AbcD" ], + [ "0x[a-f]+", "00XaBCdefG", "0XaBCdef" ], + [ "0x[^c-f]+", "00XaBCdefG", "0XaB" ] + ].each do |reg, str, result| + m = OnigRegexp.new(reg, OnigRegexp::IGNORECASE|OnigRegexp::EXTENDED).match(str) + assert_equal result, m[0] if assert_false m.nil? + end +end + +assert("OnigRegexp#match (none encoding)") do + assert_equal 2, /\x82/n =~ "あ" +end + +assert('OnigRegexp.version') do + OnigRegexp.version.kind_of? String +end + +def onig_match_data_example + OnigRegexp.new('(\w+)(\w)').match('+aaabb-') +end + +assert('OnigMatchData.new') do + assert_raise(NoMethodError) { OnigMatchData.new('aaa', 'i') } +end + +assert('OnigMatchData#[]', '15.2.16.3.1') do + m = onig_match_data_example + assert_equal 'aaabb', m[0] + assert_equal 'aaab', m[1] + assert_equal 'b', m[2] + assert_nil m[3] + + m = OnigRegexp.new('(?<name>\w\w)').match('aba') + assert_raise(TypeError) { m[[]] } + assert_raise(IndexError) { m['nam'] } + assert_equal 'ab', m[:name] + assert_equal 'ab', m['name'] + assert_equal 'ab', m[1] + + m = OnigRegexp.new('(\w) (\w) (\w) (\w)').match('a b c d') + assert_equal %w(a b c d), m[1..-1] +end + +assert('OnigMatchData#begin', '15.2.16.3.2') do + m = onig_match_data_example + assert_equal 1, m.begin(0) + assert_equal 1, m.begin(1) + assert_raise(IndexError) { m.begin 3 } +end + +assert('OnigMatchData#captures', '15.2.16.3.3') do + m = onig_match_data_example + assert_equal ['aaab', 'b'], m.captures + + m = OnigRegexp.new('(\w+)(\d)?').match('+aaabb-') + assert_equal ['aaabb', nil], m.captures +end + +assert('OnigMatchData#end', '15.2.16.3.4') do + m = onig_match_data_example + assert_equal 6, m.end(0) + assert_equal 5, m.end(1) + assert_raise(IndexError) { m.end 3 } +end + +assert('OnigMatchData#initialize_copy', '15.2.16.3.5') do + m = onig_match_data_example + c = m.dup + assert_equal m.to_a, c.to_a +end + +assert('OnigMatchData#length', '15.2.16.3.6') do + assert_equal 3, onig_match_data_example.length +end + +assert('OnigMatchData#offset', '15.2.16.3.7') do + assert_equal [1, 6], onig_match_data_example.offset(0) + assert_equal [1, 5], onig_match_data_example.offset(1) +end + +assert('OnigMatchData#post_match', '15.2.16.3.8') do + assert_equal '-', onig_match_data_example.post_match +end + +assert('OnigMatchData#pre_match', '15.2.16.3.9') do + assert_equal '+', onig_match_data_example.pre_match +end + +assert('OnigMatchData#size', '15.2.16.3.10') do + assert_equal 3, onig_match_data_example.length +end + +assert('OnigMatchData#string', '15.2.16.3.11') do + assert_equal '+aaabb-', onig_match_data_example.string +end + +assert('OnigMatchData#to_a', '15.2.16.3.12') do + assert_equal ['aaabb', 'aaab', 'b'], onig_match_data_example.to_a +end + +assert('OnigMatchData#to_s', '15.2.16.3.13') do + assert_equal 'aaabb', onig_match_data_example.to_s +end + +assert('OnigMatchData#regexp') do + assert_equal '(\w+)(\w)', onig_match_data_example.regexp.source +end + +assert('Invalid regexp') do + assert_raise(ArgumentError) { OnigRegexp.new '[aio' } +end + +assert('String#onig_regexp_gsub') do + test_str = 'hello mruby' + assert_equal 'h*ll* mr*by', test_str.onig_regexp_gsub(OnigRegexp.new('[aeiou]'), '*') + assert_equal 'h<e>ll<o> mr<u>by', test_str.onig_regexp_gsub(OnigRegexp.new('([aeiou])'), '<\1>') + assert_equal 'h e l l o m r u b y ', test_str.onig_regexp_gsub(OnigRegexp.new('\w')) { |v| v + ' ' } + assert_equal 'h{e}ll{o} mr{u}by', test_str.onig_regexp_gsub(OnigRegexp.new('(?<hoge>[aeiou])'), '{\k<hoge>}') + assert_equal '.h.e.l.l.o. .m.r.u.b.y.', test_str.onig_regexp_gsub(OnigRegexp.new(''), '.') + assert_equal " hello\n mruby", "hello\nmruby".onig_regexp_gsub(OnigRegexp.new('^'), ' ') + assert_equal "he<l><><l><>o mruby", test_str.onig_regexp_gsub(OnigRegexp.new('(l)'), '<\1><\2>') +end + +assert('String#onig_regexp_scan') do + test_str = 'mruby world' + assert_equal ['mruby', 'world'], test_str.onig_regexp_scan(OnigRegexp.new('\w+')) + assert_equal ['mru', 'by ', 'wor'], test_str.onig_regexp_scan(OnigRegexp.new('...')) + assert_equal [['mru'], ['by '], ['wor']], test_str.onig_regexp_scan(OnigRegexp.new('(...)')) + assert_equal [['mr', 'ub'], ['y ', 'wo']], test_str.onig_regexp_scan(OnigRegexp.new('(..)(..)')) + + result = [] + assert_equal test_str, test_str.onig_regexp_scan(OnigRegexp.new('\w+')) { |v| result << "<<#{v}>>" } + assert_equal ['<<mruby>>', '<<world>>'], result + + result = '' + assert_equal test_str, test_str.onig_regexp_scan(OnigRegexp.new('(.)(.)')) { |x, y| result += y; result += x } + assert_equal 'rmbu yowlr', result +end + +assert('String#onig_regexp_sub') do + test_str = 'hello mruby' + assert_equal 'h*llo mruby', test_str.onig_regexp_sub(OnigRegexp.new('[aeiou]'), '*') + assert_equal 'h<e>llo mruby', test_str.onig_regexp_sub(OnigRegexp.new('([aeiou])'), '<\1>') + assert_equal 'h ello mruby', test_str.onig_regexp_sub(OnigRegexp.new('\w')) { |v| v + ' ' } + assert_equal 'h{e}llo mruby', test_str.onig_regexp_sub(OnigRegexp.new('(?<hoge>[aeiou])'), '{\k<hoge>}') +end + +assert('String#onig_regexp_split') do + test_str = 'cute mruby cute' + assert_equal ['cute', 'mruby', 'cute'], test_str.onig_regexp_split + assert_equal ['cute', 'mruby', 'cute'], test_str.onig_regexp_split(OnigRegexp.new(' ')) + + prev_splitter = $; + $; = OnigRegexp.new ' \w' + assert_equal ['cute', 'ruby', 'ute'], test_str.onig_regexp_split + $; = 't' + assert_equal ['cu', 'e mruby cu', 'e'], test_str.onig_regexp_split + $; = prev_splitter + + assert_equal ['h', 'e', 'l', 'l', 'o'], 'hello'.onig_regexp_split(OnigRegexp.new('')) + assert_equal ['h', 'e', 'llo'], 'hello'.onig_regexp_split(OnigRegexp.new(''), 3) + assert_equal ['h', 'i', 'd', 'a', 'd'], 'hi dad'.onig_regexp_split(OnigRegexp.new('\s*')) + + test_str = '1, 2, 3, 4, 5,, 6' + assert_equal ['1', '2', '3', '4', '5', '', '6'], test_str.onig_regexp_split(OnigRegexp.new(',\s*')) + + test_str = '1,,2,3,,4,,' + assert_equal ['1', '', '2', '3', '', '4'], test_str.onig_regexp_split(OnigRegexp.new(',')) + assert_equal ['1', '', '2', '3,,4,,'], test_str.onig_regexp_split(OnigRegexp.new(','), 4) + assert_equal ['1', '', '2', '3', '', '4', '', ''], test_str.onig_regexp_split(OnigRegexp.new(','), -4) + + assert_equal [], ''.onig_regexp_split(OnigRegexp.new(','), -1) +end + +assert('String#index') do + assert_equal 0, 'abc'.index('a') + assert_nil 'abc'.index('d') + assert_equal 3, 'abcabc'.index('a', 1) + assert_equal 1, "hello".index(?e) + + assert_equal 0, 'abcabc'.index(/a/) + assert_nil 'abc'.index(/d/) + assert_equal 3, 'abcabc'.index(/a/, 1) + assert_equal 4, "hello".index(/[aeiou]/, -3) + assert_equal 3, "regexpindex".index(/e.*x/, 2) +end + +prev_regexp = Regexp + +Regexp = OnigRegexp + +# global variables +assert('$~') do + m = onig_match_data_example + assert_equal m[0], $~[0] +end + +assert('$&') do + m = onig_match_data_example + assert_equal m[0], $& +end + +assert('$`') do + m = onig_match_data_example + assert_equal m.pre_match, $` +end + +assert('$\'') do + m = onig_match_data_example + assert_equal m.post_match, $' +end + +assert('$+') do + m = onig_match_data_example + assert_equal m[-1], $+ +end + +assert('$1 to $9') do + onig_match_data_example + assert_equal 'aaab', $1 + assert_equal 'b', $2 + assert_nil $3 + assert_nil $4 + assert_nil $5 + assert_nil $6 + assert_nil $7 + assert_nil $8 + assert_nil $9 +end + +assert('default OnigRegexp.set_global_variables?') do + assert_true OnigRegexp.set_global_variables? +end + +assert('change set_global_variables') do + m = onig_match_data_example + assert_equal m[0], $~[0] + + OnigRegexp.set_global_variables = false + assert_false OnigRegexp.set_global_variables? + + # global variables must be cleared when OnigRegexp.set_global_variables gets change + assert_nil $~ + + onig_match_data_example + assert_nil $~ + + OnigRegexp.set_global_variables = true +end + +Regexp = Object + +assert('OnigRegexp not default') do + onig_match_data_example + assert_nil $~ +end + +Regexp = prev_regexp diff --git a/web/server/h2o/libh2o/deps/mruby-pack/.gitignore b/web/server/h2o/libh2o/deps/mruby-pack/.gitignore new file mode 100644 index 000000000..55ef3162f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-pack/.gitignore @@ -0,0 +1,5 @@ +gem_* +gem-* +mrb-*.a +src/*.o +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-pack/.travis.yml b/web/server/h2o/libh2o/deps/mruby-pack/.travis.yml new file mode 100644 index 000000000..ffe227284 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-pack/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-pack/README.md b/web/server/h2o/libh2o/deps/mruby-pack/README.md new file mode 100644 index 000000000..91addce80 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-pack/README.md @@ -0,0 +1,67 @@ +mruby-pack (pack / unpack) +========= + +mruby-pack provides `Array#pack` and `String#unpack` for mruby. + + +## Installation +Add the line below into your `build_config.rb`: + +``` + conf.gem :github => 'iij/mruby-pack' +``` + +There is no dependency on other mrbgems. + + +## Supported template string + - A : arbitrary binary string (space padded, count is width) + - a : arbitrary binary string (null padded, count is width) + - C : 8-bit unsigned (unsigned char) + - c : 8-bit signed (signed char) + - D, d: 64-bit float, native format + - E : 64-bit float, little endian byte order + - e : 32-bit float, little endian byte order + - F, f: 32-bit float, native format + - G : 64-bit float, network (big-endian) byte order + - g : 32-bit float, network (big-endian) byte order + - H : hex string (high nibble first) + - h : hex string (low nibble first) + - I : unsigned integer, native endian (`unsigned int` in C) + - i : signed integer, native endian (`int` in C) + - L : 32-bit unsigned, native endian (`uint32_t`) + - l : 32-bit signed, native endian (`int32_t`) + - m : base64 encoded string (see RFC 2045, count is width) + - N : 32-bit unsigned, network (big-endian) byte order + - n : 16-bit unsigned, network (big-endian) byte order + - Q : 64-bit unsigned, native endian (`uint64_t`) + - q : 64-bit signed, native endian (`int64_t`) + - S : 16-bit unsigned, native endian (`uint16_t`) + - s : 16-bit signed, native endian (`int16_t`) + - V : 32-bit unsigned, VAX (little-endian) byte order + - v : 16-bit unsigned, VAX (little-endian) byte order + - Z : same as "a", except that null is added with * + + +## License + +Copyright (c) 2012 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/web/server/h2o/libh2o/deps/mruby-pack/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-pack/mrbgem.rake new file mode 100644 index 000000000..2b9dea5b1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-pack/mrbgem.rake @@ -0,0 +1,6 @@ +MRuby::Gem::Specification.new('mruby-pack') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan Inc.' + + spec.cc.include_paths << "#{build.root}/src" +end diff --git a/web/server/h2o/libh2o/deps/mruby-pack/packtest.rb b/web/server/h2o/libh2o/deps/mruby-pack/packtest.rb new file mode 100644 index 000000000..e8be7c76c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-pack/packtest.rb @@ -0,0 +1,154 @@ +# encoding: ascii + +# a = Array, s = String, t = Template + +def packtest(a, s, t) + begin + r = a.pack(t) + return if r == s + puts "#{a.inspect}.pack(#{t.inspect}) -> #{r.inspect} should be #{s.inspect}" + rescue => r + unless r.is_a? s + puts "#{a.inspect}.pack(#{t.inspect}) -> #{r.inspect} should be #{s.inspect}" + end + end +end + +def unpacktest(a, s, t) + r = s.unpack(t) + return if r == a + puts "#{s.inspect}.unpack(#{t.inspect}) -> #{r.inspect} should be #{a.inspect}" +end + +def pptest(a, s, t) + packtest(a, s, t) + unpacktest(a, s, t) +end + +pptest [1], "\x01", "C" + +packtest [1.1], "\x01", "C" +packtest [-1], "\xff", "C" +packtest [1,2], "\x01\x02", "C2" +#packtest [1], "X", ArgumentError + +unpacktest [48, nil], "0", "CC" +unpacktest [160, -96], "\xa0\xa0", "Cc" +unpacktest [49, 50, 51], "123", "C*" + +pptest [12849], "12", "S" +unpacktest [nil], "0", "S" +unpacktest [12849, nil], "123", "SS" +unpacktest [12849], "123", "S*" + +pptest [10000], "\x27\x10", "s>" +pptest [-10000], "\xd8\xf0", "s>" +pptest [50000], "\xc3\x50", "S>" + +pptest [10000], "\x10\x27", "s<" +pptest [-10000], "\xf0\xd8", "s<" +pptest [50000], "\x50\xc3", "S<" + +pptest [1000000000], "\x3b\x9a\xca\x00", "l>" +pptest [-1000000000], "\xc4\x65\x36\x00", "l>" + +pptest [1], "\x01\x00\x00\x00", "L<" +pptest [258], "\x02\x01\x00\x00", "L<" +pptest [66051], "\x03\x02\x01\x00", "L<" +pptest [16909060], "\x04\x03\x02\x01", "L<" +pptest [16909060], "\x01\x02\x03\x04", "L>" + +packtest [-1], "\xff\xff\xff\xff", "L<" + +pptest [1000000000], "\x00\x00\x00\x00\x3b\x9a\xca\x00", "q>" +pptest [-1000000000], "\xff\xff\xff\xff\xc4\x65\x36\x00", "q>" + +if (2**33).is_a? Fixnum + pptest [81985529216486895], "\x01\x23\x45\x67\x89\xab\xcd\xef", "q>" + pptest [-1167088121787636991], "\x01\x23\x45\x67\x89\xab\xcd\xef", "q<" +end + +pptest [16909060], "\x01\x02\x03\x04", "N" +pptest [258], "\x01\x02", "n" +pptest [32769], "\x80\x01", "n" + +pptest [16909060], "\x04\x03\x02\x01", "V" +pptest [258], "\x02\x01", "v" + +packtest [""], "", "m" +packtest ["a"], "YQ==\n", "m" +packtest ["ab"], "YWI=\n", "m" +packtest ["abc"], "YWJj\n", "m" +packtest ["abcd"], "YWJjZA==\n", "m" + +unpacktest [""], "", "m" +unpacktest ["a"], "YQ==\n", "m" +unpacktest ["ab"], "YWI=\n", "m" +unpacktest ["abc"], "YWJj\n", "m" +unpacktest ["abcd"], "YWJjZA==\n", "m" + +packtest [""], "\0", "H" +packtest ["3"], "0", "H" +packtest ["34"], "", "H0" +packtest ["34"], "0", "H" +packtest ["34"], "4", "H2" +packtest ["34"], "4\0", "H3" +packtest ["3456"], "4P", "H3" +packtest ["34563"], "4V0", "H*" +packtest ["5a"], "Z", "H*" +packtest ["5A"], "Z", "H*" + +unpacktest [""], "", "H" +unpacktest [""], "0", "H0" +unpacktest ["3"], "0", "H" +unpacktest ["30"], "0", "H2" +unpacktest ["30"], "0", "H3" +unpacktest ["303"], "01", "H3" +unpacktest ["303132"], "012", "H*" +unpacktest ["3031", 50], "012", "H4C" +unpacktest ["5a"], "Z", "H*" + +packtest [""], "\0", "h" +packtest ["3"], "\03", "h" +packtest ["34"], "", "h0" +packtest ["34"], "\03", "h" +packtest ["34"], "C", "h2" +packtest ["34"], "C\0", "h3" +packtest ["3456"], "C\05", "h3" +packtest ["34563"], "Ce\03", "h*" + +packtest [""], " ", "A" +unpacktest [""], "", "A" +pptest ["1"], "1", "A" +pptest ["1"], "1 ", "A2" +unpacktest ["1"], "1", "A2" +unpacktest ["1"], "1 ", "A2" +unpacktest ["1"], "1\0", "A2" +packtest ["12"], "1", "A" +unpacktest ["1"], "12", "A" +pptest ["123"], "123", "A*" +packtest ["1","2"], "2", "A0A" +unpacktest ["","2"], "2", "A0A" + +packtest [""], "\0", "a" +unpacktest [""], "", "a" +pptest ["1"], "1", "a" +pptest ["1 "], "1 ", "a2" +pptest ["1\0"], "1\0", "a2" +packtest ["1"], "1\0", "a2" +pptest ["123"], "123", "a*" + +packtest [""], "\0", "Z" +unpacktest [""], "", "Z" +pptest ["1"], "1", "Z" +pptest ["1"], "1\0", "Z2" +pptest ["1 "], "1 ", "Z2" +pptest ["123"], "123\0", "Z*" +pptest ["1","2"], "12", "ZZ" +pptest ["1","2"], "1\0002", "Z*Z" +unpacktest ["1","3"], "1\00023", "Z3Z" + +packtest [1, 2], "\x01\x02", "CyC" + +packtest [65], "A", 'U' +packtest [59411], "\xEE\xA0\x93", 'U' diff --git a/web/server/h2o/libh2o/deps/mruby-pack/run_test.rb b/web/server/h2o/libh2o/deps/mruby-pack/run_test.rb new file mode 100644 index 000000000..d9566a2a6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-pack/run_test.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +gemname = File.basename(File.dirname(File.expand_path __FILE__)) + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + build_args = ['all', 'test'] if build_args.nil? or build_args.empty? + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-pack/src/pack.c b/web/server/h2o/libh2o/deps/mruby-pack/src/pack.c new file mode 100644 index 000000000..9095ad03b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-pack/src/pack.c @@ -0,0 +1,1144 @@ +/* + ** pack.c - Array#pack, String#unpack + */ + +#include "mruby.h" +#include "error.h" +#include "mruby/array.h" +#include "mruby/class.h" +#include "mruby/numeric.h" +#include "mruby/string.h" +#include "mruby/variable.h" + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> + +struct tmpl { + mrb_value str; + int idx; +}; + +enum { + PACK_DIR_CHAR, /* C */ + PACK_DIR_SHORT, /* S */ + PACK_DIR_LONG, /* L */ + PACK_DIR_QUAD, /* Q */ + //PACK_DIR_INT, /* i */ + //PACK_DIR_VAX, + PACK_DIR_UTF8, /* U */ + //PACK_DIR_BER, + PACK_DIR_DOUBLE, /* E */ + PACK_DIR_FLOAT, /* f */ + PACK_DIR_STR, /* A */ + PACK_DIR_HEX, /* h */ + PACK_DIR_BASE64, /* m */ + PACK_DIR_INVALID +}; + +enum { + PACK_TYPE_INTEGER, + PACK_TYPE_FLOAT, + PACK_TYPE_STRING, + PACK_TYPE_NONE +}; + +#define PACK_FLAG_s 0x00000001 /* native size ("_" "!") */ +#define PACK_FLAG_a 0x00000002 /* null padding ("a") */ +#define PACK_FLAG_Z 0x00000004 /* append nul char ("z") */ +#define PACK_FLAG_SIGNED 0x00000008 /* native size ("_" "!") */ +#define PACK_FLAG_GT 0x00000010 /* big endian (">") */ +#define PACK_FLAG_LT 0x00000020 /* little endian ("<") */ +#define PACK_FLAG_WIDTH 0x00000040 /* "count" is "width" */ +#define PACK_FLAG_LSB 0x00000080 /* LSB / low nibble first */ +#define PACK_FLAG_COUNT2 0x00000100 /* "count" is special... */ +#define PACK_FLAG_LITTLEENDIAN 0x00000200 /* little endian actually */ + +#define PACK_BASE64_IGNORE 0xff +#define PACK_BASE64_PADDING 0xfe + +static int littleendian = 0; + +const static unsigned char base64chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static signed char base64_dec_tab[128]; + + +static int +check_little_endian(void) +{ + unsigned int n = 1; + return (*(unsigned char *)&n == 1); +} + +static unsigned int +hex2int(unsigned char ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return 10 + (ch - 'A'); + else if (ch >= 'a' && ch <= 'f') + return 10 + (ch - 'a'); + else + return 0; +} + +static void +make_base64_dec_tab(void) +{ + int i; + memset(base64_dec_tab, PACK_BASE64_IGNORE, sizeof(base64_dec_tab)); + for (i = 0; i < 26; i++) + base64_dec_tab['A' + i] = i; + for (i = 0; i < 26; i++) + base64_dec_tab['a' + i] = i + 26; + for (i = 0; i < 10; i++) + base64_dec_tab['0' + i] = i + 52; + base64_dec_tab['+'] = 62; + base64_dec_tab['/'] = 63; + base64_dec_tab['='] = PACK_BASE64_PADDING; +} + +static mrb_value +str_len_ensure(mrb_state *mrb, mrb_value str, int len) +{ + int n = RSTRING_LEN(str); + if (len > n) { + do { + n *= 2; + } while (len > n); + str = mrb_str_resize(mrb, str, n); + } + return str; +} + + +static int +pack_c(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + str = str_len_ensure(mrb, str, sidx + 1); + RSTRING_PTR(str)[sidx] = mrb_fixnum(o); + return 1; +} + +static int +unpack_c(mrb_state *mrb, const void *src, int srclen, mrb_value ary, unsigned int flags) +{ + if (flags & PACK_FLAG_SIGNED) + mrb_ary_push(mrb, ary, mrb_fixnum_value(*(signed char *)src)); + else + mrb_ary_push(mrb, ary, mrb_fixnum_value(*(unsigned char *)src)); + return 1; +} + +static int +pack_s(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + unsigned short n; + + str = str_len_ensure(mrb, str, sidx + 2); + n = mrb_fixnum(o); + if (flags & PACK_FLAG_LITTLEENDIAN) { + RSTRING_PTR(str)[sidx+0] = n % 256; + RSTRING_PTR(str)[sidx+1] = n / 256; + } else { + RSTRING_PTR(str)[sidx+0] = n / 256; + RSTRING_PTR(str)[sidx+1] = n % 256; + } + return 2; +} + +static int +unpack_s(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) +{ + int n; + + if (flags & PACK_FLAG_LITTLEENDIAN) { + n = src[1] * 256 + src[0]; + } else { + n = src[0] * 256 + src[1]; + } + if ((flags & PACK_FLAG_SIGNED) && (n >= 0x8000)) { + n -= 0x10000; + } + mrb_ary_push(mrb, ary, mrb_fixnum_value(n)); + return 2; +} + +static int +pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + unsigned long n; + str = str_len_ensure(mrb, str, sidx + 4); + n = mrb_fixnum(o); + if (flags & PACK_FLAG_LITTLEENDIAN) { + RSTRING_PTR(str)[sidx+0] = n & 0xff; + RSTRING_PTR(str)[sidx+1] = n >> 8; + RSTRING_PTR(str)[sidx+2] = n >> 16; + RSTRING_PTR(str)[sidx+3] = n >> 24; + } else { + RSTRING_PTR(str)[sidx+0] = n >> 24; + RSTRING_PTR(str)[sidx+1] = n >> 16; + RSTRING_PTR(str)[sidx+2] = n >> 8; + RSTRING_PTR(str)[sidx+3] = n & 0xff; + } + return 4; +} + +static int +unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) +{ + char msg[60]; + uint32_t ul; + mrb_int n; + + if (flags & PACK_FLAG_LITTLEENDIAN) { + ul = (uint32_t)src[3] * 256*256*256; + ul += (uint32_t)src[2] *256*256; + ul += (uint32_t)src[1] *256; + ul += (uint32_t)src[0]; + } else { + ul = (uint32_t)src[0] * 256*256*256; + ul += (uint32_t)src[1] *256*256; + ul += (uint32_t)src[2] *256; + ul += (uint32_t)src[3]; + } + if (flags & PACK_FLAG_SIGNED) { + int32_t sl = ul; + if (!FIXABLE(sl)) { + snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %ld", (long)sl); + mrb_raise(mrb, E_RANGE_ERROR, msg); + } + n = sl; + } else { + if (!POSFIXABLE(ul)) { + snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %lu", (unsigned long)ul); + mrb_raise(mrb, E_RANGE_ERROR, msg); + } + n = ul; + } + mrb_ary_push(mrb, ary, mrb_fixnum_value(n)); + return 4; +} + +static int +pack_q(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + unsigned long long n; + str = str_len_ensure(mrb, str, sidx + 8); + n = mrb_fixnum(o); + if (flags & PACK_FLAG_LITTLEENDIAN) { + RSTRING_PTR(str)[sidx+0] = n & 0xff; + RSTRING_PTR(str)[sidx+1] = n >> 8; + RSTRING_PTR(str)[sidx+2] = n >> 16; + RSTRING_PTR(str)[sidx+3] = n >> 24; + RSTRING_PTR(str)[sidx+4] = n >> 32; + RSTRING_PTR(str)[sidx+5] = n >> 40; + RSTRING_PTR(str)[sidx+6] = n >> 48; + RSTRING_PTR(str)[sidx+7] = n >> 56; + } else { + RSTRING_PTR(str)[sidx+0] = n >> 56; + RSTRING_PTR(str)[sidx+1] = n >> 48; + RSTRING_PTR(str)[sidx+2] = n >> 40; + RSTRING_PTR(str)[sidx+3] = n >> 32; + RSTRING_PTR(str)[sidx+4] = n >> 24; + RSTRING_PTR(str)[sidx+5] = n >> 16; + RSTRING_PTR(str)[sidx+6] = n >> 8; + RSTRING_PTR(str)[sidx+7] = n & 0xff; + } + return 8; +} + +static int +unpack_q(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) +{ + char msg[60]; + uint64_t ull; + int i, pos, step; + mrb_int n; + + if (flags & PACK_FLAG_LITTLEENDIAN) { + pos = 7; + step = -1; + } else { + pos = 0; + step = 1; + } + ull = 0; + for (i = 0; i < 8; i++) { + ull = ull * 256 + (uint64_t)src[pos]; + pos += step; + } + if (flags & PACK_FLAG_SIGNED) { + int64_t sll = ull; + if (!FIXABLE(sll)) { + snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %lld", (long long)sll); + mrb_raise(mrb, E_RANGE_ERROR, msg); + } + n = sll; + } else { + if (!POSFIXABLE(ull)) { + snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %llu", (unsigned long long)ull); + mrb_raise(mrb, E_RANGE_ERROR, msg); + } + n = ull; + } + mrb_ary_push(mrb, ary, mrb_fixnum_value(n)); + return 8; +} + +static int +pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + int i; + double d; + uint8_t *buffer = (uint8_t *)&d; + str = str_len_ensure(mrb, str, sidx + 8); + d = mrb_float(o); + + if (flags & PACK_FLAG_LITTLEENDIAN) { +#ifdef MRB_ENDIAN_BIG + for (i = 0; i < 8; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + } +#else + memcpy(RSTRING_PTR(str) + sidx, buffer, 8); +#endif + } else { +#ifdef MRB_ENDIAN_BIG + memcpy(RSTRING_PTR(str) + sidx, buffer, 8); +#else + for (i = 0; i < 8; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + } +#endif + } + + return 8; +} + +static int +unpack_double(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ary, unsigned int flags) +{ + int i; + double d; + uint8_t *buffer = (uint8_t *)&d; + + if (flags & PACK_FLAG_LITTLEENDIAN) { +#ifdef MRB_ENDIAN_BIG + for (i = 0; i < 8; ++i) { + buffer[8 - i - 1] = src[i]; + } +#else + memcpy(buffer, src, 8); +#endif + } else { +#ifdef MRB_ENDIAN_BIG + memcpy(buffer, src, 8); +#else + for (i = 0; i < 8; ++i) { + buffer[8 - i - 1] = src[i]; + } +#endif + } + mrb_ary_push(mrb, ary, mrb_float_value(mrb, d)); + + return 8; +} + +static int +pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags) +{ + int i; + float f; + uint8_t *buffer = (uint8_t *)&f; + str = str_len_ensure(mrb, str, sidx + 4); + f = mrb_float(o); + + if (flags & PACK_FLAG_LITTLEENDIAN) { +#ifdef MRB_ENDIAN_BIG + for (i = 0; i < 4; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + } +#else + memcpy(RSTRING_PTR(str) + sidx, buffer, 4); +#endif + } else { +#ifdef MRB_ENDIAN_BIG + memcpy(RSTRING_PTR(str) + sidx, buffer, 4); +#else + for (i = 0; i < 4; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + } +#endif + } + + return 4; +} + +static int +unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ary, unsigned int flags) +{ + int i; + float f; + uint8_t *buffer = (uint8_t *)&f; + + if (flags & PACK_FLAG_LITTLEENDIAN) { +#ifdef MRB_ENDIAN_BIG + for (i = 0; i < 4; ++i) { + buffer[4 - i - 1] = src[i]; + } +#else + memcpy(buffer, src, 4); +#endif + } else { +#ifdef MRB_ENDIAN_BIG + memcpy(buffer, src, 4); +#else + for (i = 0; i < 4; ++i) { + buffer[4 - i - 1] = src[i]; + } +#endif + } + mrb_ary_push(mrb, ary, mrb_float_value(mrb, f)); + + return 4; +} + +static int +pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, unsigned int flags) +{ + char utf8[4]; + int len; + + unsigned long c = mrb_fixnum(o); + + /* Unicode character */ + /* from mruby-compiler gem */ + if (c < 0x80) { + utf8[0] = (char)c; + len = 1; + } + else if (c < 0x800) { + utf8[0] = (char)(0xC0 | (c >> 6)); + utf8[1] = (char)(0x80 | (c & 0x3F)); + len = 2; + } + else if (c < 0x10000) { + utf8[0] = (char)(0xE0 | (c >> 12) ); + utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[2] = (char)(0x80 | ( c & 0x3F)); + len = 3; + } + else { + utf8[0] = (char)(0xF0 | (c >> 18) ); + utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F)); + utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[3] = (char)(0x80 | ( c & 0x3F)); + len = 4; + } + + str = str_len_ensure(mrb, str, sidx + len); + memcpy(RSTRING_PTR(str) + sidx, utf8, len); + + return len; +} + +static int +pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) +{ + int copylen, slen, padlen; + char *dptr, *dptr0, pad, *sptr; + + sptr = RSTRING_PTR(src); + slen = RSTRING_LEN(src); + + if ((flags & PACK_FLAG_a) || (flags & PACK_FLAG_Z)) + pad = '\0'; + else + pad = ' '; + + if (count == 0) { + return 0; + } else if (count == -1) { + copylen = slen; + padlen = (flags & PACK_FLAG_Z) ? 1 : 0; + } else if (count < slen) { + copylen = count; + padlen = 0; + } else { + copylen = slen; + padlen = count - slen; + } + + dst = str_len_ensure(mrb, dst, didx + copylen + padlen); + dptr0 = dptr = RSTRING_PTR(dst) + didx; + memcpy(dptr, sptr, copylen); + dptr += copylen; + while (padlen-- > 0) { + *dptr++ = pad; + } + + return dptr - dptr0; +} + +static int +unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, unsigned int flags) +{ + mrb_value dst; + const char *cp, *sptr; + long copylen; + + sptr = (const char *)src; + if (count != -1 && count < slen) { + slen = count; + } + copylen = slen; + + if (flags & PACK_FLAG_Z) { /* "Z" */ + if ((cp = (const char *)memchr(sptr, '\0', slen)) != NULL) { + copylen = cp - sptr; + if (count == -1) { + slen = copylen + 1; + } + } + } else if (!(flags & PACK_FLAG_a)) { /* "A" */ + while (copylen > 0 && (sptr[copylen - 1] == '\0' || isspace(sptr[copylen - 1]))) { + copylen--; + } + } + + dst = mrb_str_new(mrb, sptr, copylen); + mrb_ary_push(mrb, ary, dst); + return slen; +} + + +static int +pack_h(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) +{ + unsigned int a, ashift, b, bshift; + int slen; + char *dptr, *dptr0, *sptr; + + sptr = RSTRING_PTR(src); + slen = RSTRING_LEN(src); + + if (flags & PACK_FLAG_LSB) { + ashift = 0; + bshift = 4; + } else { + ashift = 4; + bshift = 0; + } + + if (count == -1) { + count = slen; + } else if (slen > count) { + slen = count; + } + + dst = str_len_ensure(mrb, dst, didx + count); + dptr = RSTRING_PTR(dst) + didx; + + dptr0 = dptr; + for (; count > 0; count -= 2) { + a = b = 0; + if (slen > 0) { + a = hex2int(*sptr++); + slen--; + } + if (slen > 0) { + b = hex2int(*sptr++); + slen--; + } + *dptr++ = (a << ashift) + (b << bshift); + } + + return dptr - dptr0; +} + +static int +unpack_h(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags) +{ + mrb_value dst; + int a, ashift, b, bshift; + const char *sptr, *sptr0; + char *dptr, *dptr0; + const char hexadecimal[] = "0123456789abcdef"; + + if (flags & PACK_FLAG_LSB) { + ashift = 0; + bshift = 4; + } else { + ashift = 4; + bshift = 0; + } + + sptr = (const char *)src; + + if (count == -1) + count = slen * 2; + + dst = mrb_str_new(mrb, NULL, count); + dptr = RSTRING_PTR(dst); + + sptr0 = sptr; + dptr0 = dptr; + while (slen > 0 && count > 0) { + a = (*sptr >> ashift) & 0x0f; + b = (*sptr >> bshift) & 0x0f; + sptr++; + slen--; + + *dptr++ = hexadecimal[a]; + count--; + + if (count > 0) { + *dptr++ = hexadecimal[b]; + count--; + } + } + + dst = mrb_str_resize(mrb, dst, dptr - dptr0); + mrb_ary_push(mrb, ary, dst); + return sptr - sptr0; +} + + +static int +pack_m(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) +{ + mrb_int dstlen; + unsigned long l; + int column, srclen; + char *srcptr, *dstptr, *dstptr0; + + srcptr = RSTRING_PTR(src); + srclen = RSTRING_LEN(src); + + if (srclen == 0) /* easy case */ + return 0; + + if (count != 0 && count < 3) { /* -1, 1 or 2 */ + count = 45; + } else if (count >= 3) { + count -= count % 3; + } + + dstlen = srclen / 3 * 4; + if (count > 0) { + dstlen += (srclen / count) + ((srclen % count) == 0 ? 0 : 1); + } + dst = str_len_ensure(mrb, dst, didx + dstlen); + dstptr = RSTRING_PTR(dst) + didx; + + dstptr0 = dstptr; + for (column = 3; srclen >= 3; srclen -= 3, column += 3) { + l = (unsigned char)*srcptr++ << 16; + l += (unsigned char)*srcptr++ << 8; + l += (unsigned char)*srcptr++; + + *dstptr++ = base64chars[(l >> 18) & 0x3f]; + *dstptr++ = base64chars[(l >> 12) & 0x3f]; + *dstptr++ = base64chars[(l >> 6) & 0x3f]; + *dstptr++ = base64chars[ l & 0x3f]; + + if (column == count) { + *dstptr++ = '\n'; + column = 0; + } + } + if (srclen == 1) { + l = (unsigned char)*srcptr++ << 16; + *dstptr++ = base64chars[(l >> 18) & 0x3f]; + *dstptr++ = base64chars[(l >> 12) & 0x3f]; + *dstptr++ = '='; + *dstptr++ = '='; + column += 3; + } else if (srclen == 2) { + l = (unsigned char)*srcptr++ << 16; + l += (unsigned char)*srcptr++ << 8; + *dstptr++ = base64chars[(l >> 18) & 0x3f]; + *dstptr++ = base64chars[(l >> 12) & 0x3f]; + *dstptr++ = base64chars[(l >> 6) & 0x3f]; + *dstptr++ = '='; + column += 3; + } + if (column > 0 && count > 0) { + *dstptr++ = '\n'; + } + + return dstptr - dstptr0; +} + +static int +unpack_m(mrb_state *mrb, const void *src, int slen, mrb_value ary, unsigned int flags) +{ + mrb_value dst; + int dlen; + unsigned long l; + int i, padding; + unsigned char c, ch[4]; + const char *sptr, *sptr0; + char *dptr, *dptr0; + + sptr0 = sptr = (const char *)src; + + dlen = slen / 4 * 3; /* an estimated value - may be shorter */ + dst = mrb_str_new(mrb, NULL, dlen); + dptr0 = dptr = RSTRING_PTR(dst); + + padding = 0; + while (slen >= 4) { + for (i = 0; i < 4; i++) { + do { + if (slen-- == 0) + goto done; + c = *sptr++; + if (c >= sizeof(base64_dec_tab)) + continue; + ch[i] = base64_dec_tab[c]; + if (ch[i] == PACK_BASE64_PADDING) { + ch[i] = 0; + padding++; + } + } while (ch[i] == PACK_BASE64_IGNORE); + } + + l = (ch[0] << 18) + (ch[1] << 12) + (ch[2] << 6) + ch[3]; + + if (padding == 0) { + *dptr++ = (l >> 16) & 0xff; + *dptr++ = (l >> 8) & 0xff; + *dptr++ = l & 0xff; + } else if (padding == 1) { + *dptr++ = (l >> 16) & 0xff; + *dptr++ = (l >> 8) & 0xff; + break; + } else { + *dptr++ = (l >> 16) & 0xff; + break; + } + } + +done: + dst = mrb_str_resize(mrb, dst, dptr - dptr0); + mrb_ary_push(mrb, ary, dst); + return sptr - sptr0; +} + + +static void +prepare_tmpl(mrb_state *mrb, struct tmpl *tmpl) +{ + mrb_get_args(mrb, "S", &tmpl->str); + tmpl->idx = 0; +} + +static int +has_tmpl(const struct tmpl *tmpl) +{ + return (tmpl->idx < RSTRING_LEN(tmpl->str)); +} + +static void +read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, long *countp, unsigned int *flagsp) +{ + int ch, dir, t, tlen, type; + int size = 0; + long count = 1; + unsigned int flags = 0; + const char *tptr; + + tptr = RSTRING_PTR(tmpl->str); + tlen = RSTRING_LEN(tmpl->str); + + t = tptr[tmpl->idx++]; +alias: + switch (t) { + case 'A': + dir = PACK_DIR_STR; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2; + break; + case 'a': + dir = PACK_DIR_STR; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2 | PACK_FLAG_a; + break; + case 'C': + dir = PACK_DIR_CHAR; + type = PACK_TYPE_INTEGER; + size = 1; + break; + case 'c': + dir = PACK_DIR_CHAR; + type = PACK_TYPE_INTEGER; + size = 1; + flags |= PACK_FLAG_SIGNED; + break; + case 'D': case 'd': + dir = PACK_DIR_DOUBLE; + type = PACK_TYPE_FLOAT; + size = 8; + flags |= PACK_FLAG_SIGNED; + break; + case 'F': case 'f': + dir = PACK_DIR_FLOAT; + type = PACK_TYPE_FLOAT; + size = 4; + flags |= PACK_FLAG_SIGNED; + break; + case 'E': + dir = PACK_DIR_DOUBLE; + type = PACK_TYPE_FLOAT; + size = 8; + flags |= PACK_FLAG_SIGNED | PACK_FLAG_LT; + break; + case 'e': + dir = PACK_DIR_FLOAT; + type = PACK_TYPE_FLOAT; + size = 4; + flags |= PACK_FLAG_SIGNED | PACK_FLAG_LT; + break; + case 'G': + dir = PACK_DIR_DOUBLE; + type = PACK_TYPE_FLOAT; + size = 8; + flags |= PACK_FLAG_SIGNED | PACK_FLAG_GT; + break; + case 'g': + dir = PACK_DIR_FLOAT; + type = PACK_TYPE_FLOAT; + size = 4; + flags |= PACK_FLAG_SIGNED | PACK_FLAG_GT; + break; + case 'H': + dir = PACK_DIR_HEX; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_COUNT2; + break; + case 'h': + dir = PACK_DIR_HEX; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_COUNT2 | PACK_FLAG_LSB; + break; + case 'I': + switch (sizeof(int)) { + case 2: t = 'S'; goto alias; + case 4: t = 'L'; goto alias; + case 8: t = 'Q'; goto alias; + default: + mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %S", mrb_fixnum_value(sizeof(int))); + } + break; + case 'i': + switch (sizeof(int)) { + case 2: t = 's'; goto alias; + case 4: t = 'l'; goto alias; + case 8: t = 'q'; goto alias; + default: + mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %S", mrb_fixnum_value(sizeof(int))); + } + break; + case 'L': + dir = PACK_DIR_LONG; + type = PACK_TYPE_INTEGER; + size = 4; + break; + case 'l': + dir = PACK_DIR_LONG; + type = PACK_TYPE_INTEGER; + size = 4; + flags |= PACK_FLAG_SIGNED; + break; + case 'm': + dir = PACK_DIR_BASE64; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_WIDTH; + break; + case 'N': /* = "L>" */ + dir = PACK_DIR_LONG; + type = PACK_TYPE_INTEGER; + size = 4; + flags |= PACK_FLAG_GT; + break; + case 'n': /* = "S>" */ + dir = PACK_DIR_SHORT; + type = PACK_TYPE_INTEGER; + size = 2; + flags |= PACK_FLAG_GT; + break; + case 'Q': + dir = PACK_DIR_QUAD; + type = PACK_TYPE_INTEGER; + size = 8; + break; + case 'q': + dir = PACK_DIR_QUAD; + type = PACK_TYPE_INTEGER; + size = 8; + flags |= PACK_FLAG_SIGNED; + break; + case 'S': + dir = PACK_DIR_SHORT; + type = PACK_TYPE_INTEGER; + size = 2; + break; + case 's': + dir = PACK_DIR_SHORT; + type = PACK_TYPE_INTEGER; + size = 2; + flags |= PACK_FLAG_SIGNED; + break; + case 'U': + dir = PACK_DIR_UTF8; + type = PACK_TYPE_INTEGER; + break; + case 'V': /* = "L<" */ + dir = PACK_DIR_LONG; + type = PACK_TYPE_INTEGER; + size = 4; + flags |= PACK_FLAG_LT; + break; + case 'v': /* = "S<" */ + dir = PACK_DIR_SHORT; + type = PACK_TYPE_INTEGER; + size = 2; + flags |= PACK_FLAG_LT; + break; + case 'Z': + dir = PACK_DIR_STR; + type = PACK_TYPE_STRING; + flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2 | PACK_FLAG_Z; + break; + default: + dir = PACK_DIR_INVALID; + type = PACK_TYPE_NONE; + break; + } + + /* read suffix [0-9*_!<>] */ + while (tmpl->idx < tlen) { + ch = tptr[tmpl->idx++]; + if (isdigit(ch)) { + count = ch - '0'; + while (tmpl->idx < tlen && isdigit(tptr[tmpl->idx])) { + count = count * 10 + (tptr[tmpl->idx++] - '0'); + } + continue; /* special case */ + } else if (ch == '*') { + count = -1; + } else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') { + if (strchr("sSiIlLqQ", t) == NULL) { + char ch_str = ch; + mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%S' allowed only after types sSiIlLqQ", mrb_str_new(mrb, &ch_str, 1)); + } + if (ch == '_' || ch == '!') { + flags |= PACK_FLAG_s; + } else if (ch == '<') { + flags |= PACK_FLAG_LT; + } else if (ch == '>') { + flags |= PACK_FLAG_GT; + } + } else { + tmpl->idx--; + break; + } + } + + if ((flags & PACK_FLAG_LT) || (!(flags & PACK_FLAG_GT) && littleendian)) { + flags |= PACK_FLAG_LITTLEENDIAN; + } + + *dirp = dir; + *typep = type; + *sizep = size; + *countp = count; + *flagsp = flags; +} + +static mrb_value +mrb_pack_pack(mrb_state *mrb, mrb_value ary) +{ + mrb_value o, result; + mrb_int aidx; + struct tmpl tmpl; + long count; + unsigned int flags; + int dir, ridx, size, type; + + prepare_tmpl(mrb, &tmpl); + + result = mrb_str_new(mrb, NULL, 128); /* allocate initial buffer */ + aidx = 0; + ridx = 0; + while (has_tmpl(&tmpl)) { + read_tmpl(mrb, &tmpl, &dir, &type, &size, &count, &flags); + + if (dir == PACK_DIR_INVALID) + continue; + + for (; aidx < RARRAY_LEN(ary); aidx++) { + if (count == 0 && !(flags & PACK_FLAG_WIDTH)) + break; + + o = mrb_ary_ref(mrb, ary, aidx); + if (type == PACK_TYPE_INTEGER) { + if (mrb_float_p(o)) { + o = mrb_funcall(mrb, o, "to_i", 0); + } else if (!mrb_fixnum_p(o)) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into Integer", mrb_class_path(mrb, mrb_obj_class(mrb, o))); + } + } else if (type == PACK_TYPE_FLOAT) { + if (!mrb_float_p(o)) { + o = mrb_funcall(mrb, o, "to_f", 0); + } + } else if (type == PACK_TYPE_STRING) { + if (!mrb_string_p(o)) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into String", mrb_class_path(mrb, mrb_obj_class(mrb, o))); + } + } + + switch (dir) { + case PACK_DIR_CHAR: + ridx += pack_c(mrb, o, result, ridx, flags); + break; + case PACK_DIR_SHORT: + ridx += pack_s(mrb, o, result, ridx, flags); + break; + case PACK_DIR_LONG: + ridx += pack_l(mrb, o, result, ridx, flags); + break; + case PACK_DIR_QUAD: + ridx += pack_q(mrb, o, result, ridx, flags); + break; + case PACK_DIR_BASE64: + ridx += pack_m(mrb, o, result, ridx, count, flags); + break; + case PACK_DIR_HEX: + ridx += pack_h(mrb, o, result, ridx, count, flags); + break; + case PACK_DIR_STR: + ridx += pack_a(mrb, o, result, ridx, count, flags); + break; + case PACK_DIR_DOUBLE: + ridx += pack_double(mrb, o, result, ridx, flags); + break; + case PACK_DIR_FLOAT: + ridx += pack_float(mrb, o, result, ridx, flags); + break; + case PACK_DIR_UTF8: + ridx += pack_utf8(mrb, o, result, ridx, count, flags); + break; + default: + break; + } + if (dir == PACK_DIR_STR) { /* always consumes 1 entry */ + aidx++; + break; + } + if (count > 0) { + count--; + } + } + } + + mrb_str_resize(mrb, result, ridx); + return result; +} + +static mrb_value +mrb_pack_unpack(mrb_state *mrb, mrb_value str) +{ + mrb_value result; + struct tmpl tmpl; + long count; + unsigned int flags; + int dir, size, srcidx, srclen, type; + const unsigned char *sptr; + + prepare_tmpl(mrb, &tmpl); + + srcidx = 0; + srclen = RSTRING_LEN(str); + + result = mrb_ary_new(mrb); + while (has_tmpl(&tmpl)) { + read_tmpl(mrb, &tmpl, &dir, &type, &size, &count, &flags); + + if (dir == PACK_DIR_INVALID) + continue; + + if (flags & PACK_FLAG_COUNT2) { + sptr = (const unsigned char *)RSTRING_PTR(str) + srcidx; + switch (dir) { + case PACK_DIR_HEX: + srcidx += unpack_h(mrb, sptr, srclen - srcidx, result, count, flags); + break; + case PACK_DIR_STR: + srcidx += unpack_a(mrb, sptr, srclen - srcidx, result, count, flags); + break; + } + continue; + } + + while (count != 0) { + if (srclen - srcidx < size) { + while (count-- > 0) { + mrb_ary_push(mrb, result, mrb_nil_value()); + } + break; + } + + sptr = (const unsigned char *)RSTRING_PTR(str) + srcidx; + switch (dir) { + case PACK_DIR_CHAR: + srcidx += unpack_c(mrb, sptr, srclen - srcidx, result, flags); + break; + case PACK_DIR_SHORT: + srcidx += unpack_s(mrb, sptr, srclen - srcidx, result, flags); + break; + case PACK_DIR_LONG: + srcidx += unpack_l(mrb, sptr, srclen - srcidx, result, flags); + break; + case PACK_DIR_QUAD: + srcidx += unpack_q(mrb, sptr, srclen - srcidx, result, flags); + break; + case PACK_DIR_BASE64: + srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, flags); + break; + case PACK_DIR_FLOAT: + srcidx += unpack_float(mrb, sptr, srclen - srcidx, result, flags); + break; + case PACK_DIR_DOUBLE: + srcidx += unpack_double(mrb, sptr, srclen - srcidx, result, flags); + break; + } + if (count > 0) { + count--; + } + } + } + + return result; +} + +void +mrb_mruby_pack_gem_init(mrb_state *mrb) +{ + littleendian = check_little_endian(); + make_base64_dec_tab(); + + mrb_define_method(mrb, mrb->array_class, "pack", mrb_pack_pack, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mrb->string_class, "unpack", mrb_pack_unpack, MRB_ARGS_REQ(1)); +} + +void +mrb_mruby_pack_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-pack/test/pack.rb b/web/server/h2o/libh2o/deps/mruby-pack/test/pack.rb new file mode 100644 index 000000000..5e9932f4f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-pack/test/pack.rb @@ -0,0 +1,147 @@ +# pack & unpack 'm' (base64) +assert('[""].pack("m")') do + ary = "" + str = "" + [ary].pack("m") == str and + str.unpack("m") == [ary] +end + +assert('["\0"].pack("m")') do + ary = "\0" + str = "AA==\n" + [ary].pack("m") == str and + str.unpack("m") == [ary] +end + +assert('["\0\0"].pack("m")') do + ary = "\0\0" + str = "AAA=\n" + [ary].pack("m") == str and + str.unpack("m") == [ary] +end + +assert('["\0\0\0"].pack("m")') do + ary = "\0\0\0" + str = "AAAA\n" + [ary].pack("m") == str and + str.unpack("m") == [ary] +end + +assert('["abc..xyzABC..XYZ"].pack("m")') do + ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"].pack("m") == "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n" +end + +assert('"YWJ...".unpack("m") should "abc..xyzABC..XYZ"') do + str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n".unpack("m") == [str] and + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m") == [str] +end + +# pack & unpack 'H' +assert('["3031"].pack("H*")') do + ary = "3031" + str = "01" + [ary].pack("H*") == str and + str.unpack("H*") == [ary] +end + +assert('["10"].pack("H*")') do + ary = "10" + str = "\020" + [ary].pack("H*") == str and + str.unpack("H*") == [ary] +end + +assert('[0,1,127,128,255].pack("C*")') do + ary = [ 0, 1, 127, 128, 255 ] + str = "\x00\x01\x7F\x80\xFF" + ary.pack("C*") == str and str.unpack("C*") == ary +end + +# pack "a" +assert('["abc"].pack("a")') do + ["abc"].pack("a") == "a" and + ["abc"].pack("a*") == "abc" and + ["abc"].pack("a4") == "abc\0" +end + +# upack "a" +assert('["abc"].pack("a")') do + "abc\0".unpack("a4") == ["abc\0"] and + "abc ".unpack("a4") == ["abc "] +end + +# pack "A" +assert('["abc"].pack("A")') do + ["abc"].pack("A") == "a" and + ["abc"].pack("A*") == "abc" and + ["abc"].pack("A4") == "abc " +end + +# upack "A" +assert('["abc"].pack("A")') do + "abc\0".unpack("A4") == ["abc"] and + "abc ".unpack("A4") == ["abc"] +end + +# regression tests +assert('issue #1') do + [1, 2].pack("nn") == "\000\001\000\002" +end + +def assert_pack tmpl, packed, unpacked + assert_equal packed, unpacked.pack(tmpl) + assert_equal unpacked, packed.unpack(tmpl) +end + +PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 + +assert 'pack float' do + assert_pack 'e', "\x00\x00@@", [3.0] + assert_pack 'g', "@@\x00\x00", [3.0] + + if PACK_IS_LITTLE_ENDIAN + assert_pack 'f', "\x00\x00@@", [3.0] + assert_pack 'F', "\x00\x00@@", [3.0] + else + assert_pack 'f', "@@\x00\x00", [3.0] + assert_pack 'F', "@@\x00\x00", [3.0] + end +end + +assert 'pack double' do + assert_pack 'E', "\x00\x00\x00\x00\x00\x00\b@", [3.0] + assert_pack 'G', "@\b\x00\x00\x00\x00\x00\x00", [3.0] + + if PACK_IS_LITTLE_ENDIAN + assert_pack 'd', "\x00\x00\x00\x00\x00\x00\b@", [3.0] + assert_pack 'D', "\x00\x00\x00\x00\x00\x00\b@", [3.0] + else + assert_pack 'd', "@\b\x00\x00\x00\x00\x00\x00", [3.0] + assert_pack 'D', "@\b\x00\x00\x00\x00\x00\x00", [3.0] + end +end + +assert 'pack/unpack "i"' do + int_size = [0].pack('i').size + raise "pack('i').size is too small (#{int_size})" if int_size < 2 + + if PACK_IS_LITTLE_ENDIAN + str = "\xC7\xCF" + "\xFF" * (int_size-2) + else + str = "\xFF" * (int_size-2) + "\xC7\xCF" + end + assert_pack 'i', str, [-12345] +end + +assert 'pack/unpack "I"' do + uint_size = [0].pack('I').size + raise "pack('I').size is too small (#{uint_size})" if uint_size < 2 + + if PACK_IS_LITTLE_ENDIAN + str = "\x39\x30" + "\0" * (uint_size-2) + else + str = "\0" * (uint_size-2) + "\x39\x30" + end + assert_pack 'I', str, [12345] +end diff --git a/web/server/h2o/libh2o/deps/mruby-require/.gitignore b/web/server/h2o/libh2o/deps/mruby-require/.gitignore new file mode 100644 index 000000000..ceeb05b41 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/.gitignore @@ -0,0 +1 @@ +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-require/.travis.yml b/web/server/h2o/libh2o/deps/mruby-require/.travis.yml new file mode 100644 index 000000000..ffe227284 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-require/README.md b/web/server/h2o/libh2o/deps/mruby-require/README.md new file mode 100644 index 000000000..70818ffba --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/README.md @@ -0,0 +1,59 @@ +mruby-require +============= + +"mruby-require" is a mrbgem, provides +[require](http://docs.ruby-lang.org/ja/2.0.0/class/Kernel.html#M_REQUIRE) and +[load](http://docs.ruby-lang.org/ja/2.0.0/class/Kernel.html#M_LOAD) for mruby. + +### Example: + +```Ruby +# a.rb + +require "b" + +b = Bclass.new +p b.method +``` +```Ruby +# b.rb + +class Bclass + def method + "BBB" + end +end +``` +```sh +% mruby a.rb +"BBB" +``` + + +### To run the tests: + + ruby run_test.rb + + +## License + +Copyright (c) 2013 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/web/server/h2o/libh2o/deps/mruby-require/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-require/mrbgem.rake new file mode 100644 index 000000000..e95cdb8ca --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/mrbgem.rake @@ -0,0 +1,15 @@ +MRuby::Gem::Specification.new('mruby-require') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan Inc.' + + spec.add_dependency 'mruby-array-ext' + spec.add_dependency 'mruby-dir' + spec.add_dependency 'mruby-io' +# only used for testing? +# spec.add_dependency 'mruby-tempfile' + spec.add_dependency 'mruby-time' + spec.add_dependency 'mruby-eval' + + spec.cc.include_paths << "#{build.root}/src" +end + diff --git a/web/server/h2o/libh2o/deps/mruby-require/mrblib/require.rb b/web/server/h2o/libh2o/deps/mruby-require/mrblib/require.rb new file mode 100644 index 000000000..cdf25ace3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/mrblib/require.rb @@ -0,0 +1,97 @@ +class LoadError < ScriptError; end + +begin + eval "1", nil + def _require_eval_load(*args) + self.eval(*args) + end +rescue ArgumentError + def _require_eval_load(*args) + self.eval(args[0]) + end +end + +module Kernel + def load(path) + raise TypeError unless path.class == String + + if File.exist?(path) && File.extname(path) == ".mrb" + _load_mrb_file path + elsif File.exist?(path) + # _load_rb_str File.open(path).read.to_s, path + _require_eval_load File.open(path).read.to_s, nil, path + else + raise LoadError.new "File not found -- #{path}" + end + + true + end + + def require(path) + raise TypeError unless path.class == String + + # require method can load .rb, .mrb or without-ext filename only. + unless ["", ".rb", ".mrb"].include? File.extname(path) + raise LoadError.new "cannot load such file -- #{path}" + end + + filenames = [] + if File.extname(path).size == 0 + filenames << "#{path}.rb" + filenames << "#{path}.mrb" + else + filenames << path + end + + dir = nil + filename = nil + if ['/', '.'].include? path[0] + path0 = filenames.find do |fname| + File.file?(fname) && File.exist?(fname) + end + else + dir = ($LOAD_PATH || []).find do |dir0| + filename = filenames.find do |fname| + path0 = File.join dir0, fname + File.file?(path0) && File.exist?(path0) + end + end + path0 = dir && filename ? File.join(dir, filename) : nil + end + + if path0 && File.exist?(path0) && File.file?(path0) + __require__ path0 + else + raise LoadError.new "cannot load such file -- #{path}" + end + end + + def __require__(realpath) + raise LoadError.new "File not found -- #{realpath}" unless File.exist? realpath + $" ||= [] + $__mruby_loading_files__ ||= [] + + # already required + return false if ($" + $__mruby_loading_files__).include?(realpath) + + $__mruby_loading_files__ << realpath + load realpath + $" << realpath + $__mruby_loading_files__.delete realpath + + true + end +end + + +$LOAD_PATH ||= [] +$LOAD_PATH << '.' + +if Object.const_defined?(:ENV) + $LOAD_PATH.unshift(*ENV['MRBLIB'].split(':')) unless ENV['MRBLIB'].nil? +end + +$LOAD_PATH.uniq! + +$" ||= [] +$__mruby_loading_files__ ||= [] diff --git a/web/server/h2o/libh2o/deps/mruby-require/run_test.rb b/web/server/h2o/libh2o/deps/mruby-require/run_test.rb new file mode 100644 index 000000000..2a99a9ddf --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/run_test.rb @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + + build_args = ARGV + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem :core => 'mruby-eval' + conf.gem :git => 'https://github.com/iij/mruby-io.git' + conf.gem :git => 'https://github.com/iij/mruby-dir.git' + conf.gem :git => 'https://github.com/iij/mruby-tempfile.git' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-require/src/require.c b/web/server/h2o/libh2o/deps/mruby-require/src/require.c new file mode 100644 index 000000000..0f48c0378 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/src/require.c @@ -0,0 +1,208 @@ +#if !(defined(_WIN32) || defined(_WIN64)) +#include <err.h> +#endif +#include <fcntl.h> +#include <setjmp.h> +#include <unistd.h> + +#include "mruby.h" +#include "mruby/compile.h" +#include "mruby/dump.h" +#include "mruby/string.h" +#include "mruby/proc.h" + +#include "opcode.h" +#include "error.h" + +#include <stdlib.h> +#include <sys/stat.h> + +#define E_LOAD_ERROR (mrb_class_get(mrb, "LoadError")) + +#if MRUBY_RELEASE_NO < 10000 +mrb_value mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c); +#define mrb_yield_with_class mrb_yield_internal +#endif + +#if defined(_WIN32) || defined(_WIN64) + #include <windows.h> + int mkstemp(char *template) + { + DWORD pathSize; + char pathBuffer[1000]; + char tempFilename[MAX_PATH]; + UINT uniqueNum; + pathSize = GetTempPath(1000, pathBuffer); + if (pathSize < 1000) { pathBuffer[pathSize] = 0; } + else { pathBuffer[0] = 0; } + uniqueNum = GetTempFileName(pathBuffer, template, 0, tempFilename); + if (uniqueNum == 0) return -1; + strncpy(template, tempFilename, MAX_PATH); + return open(tempFilename, _O_RDWR|_O_BINARY); + } +#endif + +static void +replace_stop_with_return(mrb_state *mrb, mrb_irep *irep) +{ + if (irep->iseq[irep->ilen - 1] == MKOP_A(OP_STOP, 0)) { + irep->iseq = mrb_realloc(mrb, irep->iseq, (irep->ilen + 1) * sizeof(mrb_code)); + irep->iseq[irep->ilen - 1] = MKOP_A(OP_LOADNIL, 0); + irep->iseq[irep->ilen] = MKOP_AB(OP_RETURN, 0, OP_R_NORMAL); + irep->ilen++; + } +} + +static int +compile_rb2mrb(mrb_state *mrb0, const char *code, int code_len, const char *path, FILE* tmpfp) +{ + mrb_state *mrb = mrb_open(); + mrb_value result; + mrbc_context *c; + int ret = -1; + int debuginfo = 1; + mrb_irep *irep; + + c = mrbc_context_new(mrb); + c->no_exec = 1; + if (path != NULL) { + mrbc_filename(mrb, c, path); + } + + result = mrb_load_nstring_cxt(mrb, code, code_len, c); + if (mrb_undef_p(result)) { + mrbc_context_free(mrb, c); + mrb_close(mrb); + return MRB_DUMP_GENERAL_FAILURE; + } + + irep = mrb_proc_ptr(result)->body.irep; + ret = mrb_dump_irep_binary(mrb, irep, debuginfo, tmpfp); + + mrbc_context_free(mrb, c); + mrb_close(mrb); + + return ret; +} + +static void +eval_load_irep(mrb_state *mrb, mrb_irep *irep) +{ + int ai; + struct RProc *proc; + + replace_stop_with_return(mrb, irep); + proc = mrb_proc_new(mrb, irep); + proc->target_class = mrb->object_class; + + ai = mrb_gc_arena_save(mrb); + mrb_yield_with_class(mrb, mrb_obj_value(proc), 0, NULL, mrb_top_self(mrb), mrb->object_class); + mrb_gc_arena_restore(mrb, ai); +} + +static mrb_value +mrb_require_load_rb_str(mrb_state *mrb, mrb_value self) +{ + char *path_ptr = NULL; +#if defined(_WIN32) || defined(_WIN64) + char tmpname[MAX_PATH] = "tmp.XXXXXXXX"; +#else + char tmpname[] = "tmp.XXXXXXXX"; +#endif + mode_t mask; + FILE *tmpfp = NULL; + int fd = -1, ret; + mrb_irep *irep; + mrb_value code, path = mrb_nil_value(); + + mrb_get_args(mrb, "S|S", &code, &path); + if (!mrb_string_p(path)) { + path = mrb_str_new_cstr(mrb, "-"); + } + path_ptr = mrb_str_to_cstr(mrb, path); + + mask = umask(077); + fd = mkstemp(tmpname); + if (fd == -1) { + mrb_sys_fail(mrb, "can't create mkstemp() at mrb_require_load_rb_str"); + } + umask(mask); + + tmpfp = fdopen(fd, "r+"); + if (tmpfp == NULL) { + close(fd); + mrb_sys_fail(mrb, "can't open temporay file at mrb_require_load_rb_str"); + } + + ret = compile_rb2mrb(mrb, RSTRING_PTR(code), RSTRING_LEN(code), path_ptr, tmpfp); + if (ret != MRB_DUMP_OK) { + fclose(tmpfp); + remove(tmpname); + mrb_raisef(mrb, E_LOAD_ERROR, "can't load file -- %S", path); + return mrb_nil_value(); + } + + rewind(tmpfp); + irep = mrb_read_irep_file(mrb, tmpfp); + fclose(tmpfp); + remove(tmpname); + + if (irep) { + eval_load_irep(mrb, irep); + } else if (mrb->exc) { + // fail to load + longjmp(*(jmp_buf*)mrb->jmp, 1); + } else { + mrb_raisef(mrb, E_LOAD_ERROR, "can't load file -- %S", path); + return mrb_nil_value(); + } + + return mrb_true_value(); +} + +static mrb_value +mrb_require_load_mrb_file(mrb_state *mrb, mrb_value self) +{ + char *path_ptr = NULL; + FILE *fp = NULL; + mrb_irep *irep; + mrb_value path; + + mrb_get_args(mrb, "S", &path); + path_ptr = mrb_str_to_cstr(mrb, path); + + fp = fopen(path_ptr, "rb"); + if (fp == NULL) { + mrb_raisef(mrb, E_LOAD_ERROR, "can't open file -- %S", path); + } + + irep = mrb_read_irep_file(mrb, fp); + fclose(fp); + + if (irep) { + eval_load_irep(mrb, irep); + } else if (mrb->exc) { + // fail to load + longjmp(*(jmp_buf*)mrb->jmp, 1); + } else { + mrb_raisef(mrb, E_LOAD_ERROR, "can't load file -- %S", path); + return mrb_nil_value(); + } + + return mrb_true_value(); +} + +void +mrb_mruby_require_gem_init(mrb_state *mrb) +{ + struct RClass *krn; + krn = mrb->kernel_module; + + mrb_define_method(mrb, krn, "_load_rb_str", mrb_require_load_rb_str, MRB_ARGS_ANY()); + mrb_define_method(mrb, krn, "_load_mrb_file", mrb_require_load_mrb_file, MRB_ARGS_REQ(1)); +} + +void +mrb_mruby_require_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/d/required.rb b/web/server/h2o/libh2o/deps/mruby-require/test/d/required.rb new file mode 100644 index 000000000..d6218cd03 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/d/required.rb @@ -0,0 +1,19 @@ +# global variables +$gvar0 = 1 +$gvar1 = 1 + +# toplevel local variables +lvar0 = 1 +lvar1 = 1 + +# define a procedure +def proc0 + :proc0 +end + +# define a new method of an existing class. +class MrubyRequireClass + def foo + :foo + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/require.rb b/web/server/h2o/libh2o/deps/mruby-require/test/require.rb new file mode 100644 index 000000000..95e1ef022 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/require.rb @@ -0,0 +1,28 @@ +assert("Kernel.require") do + # see d/required.rb + $gvar1 = 0 + lvar1 = 0 + class MrubyRequireClass; end + + assert_true require(File.join(File.dirname(__FILE__), "d", "required.rb")) + + # Kernel.require can create a global variable + assert_equal 1, $gvar0 + + # Kernel.require can change value of a global variable + assert_equal 1, $gvar1 + + # Kernel.require cannot create a local variable + assert_raise(NoMethodError) do + lvar0 + end + + # Kernel.require cannot change value of a local variable + assert_equal 0, lvar1 + + # Kernel.require can define a toplevel procedure + assert_equal :proc0, proc0 + + # Kernel.require can add a method to an existing class + assert_equal :foo, MrubyRequireClass.new.foo +end diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/test.rb b/web/server/h2o/libh2o/deps/mruby-require/test/test.rb new file mode 100644 index 000000000..0886cabef --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/test.rb @@ -0,0 +1,34 @@ +$" = [] # init + +assert "Kernel#_load_rb_str" do + assert_equal true, self.methods.include?(:_load_rb_str) + assert_equal false, Object.const_defined?(:LOAD_RB_STR_TEST) + _load_rb_str("LOAD_RB_STR_TEST = 1") + assert_equal true, Object.const_defined?(:LOAD_RB_STR_TEST) +end + +assert "$LOAD_PATH check" do + assert_equal Array, $LOAD_PATH.class +end + +assert '$" check' do + assert_equal [], $" +end + +assert('load - error check') do + assert_raise TypeError, "load(nil) should raise TypeError" do + load nil + end + assert_raise LoadError, "load('notfound') should raise LoadError" do + load 'notfound' + end +end + +assert('require - error check') do + assert_raise TypeError, "require(nil) should raise TypeError" do + require nil + end + assert_raise LoadError, "require('notfound') should raise LoadError" do + require "notfound" + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/test2.rb b/web/server/h2o/libh2o/deps/mruby-require/test/test2.rb new file mode 100644 index 000000000..b66b9fdf3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/test2.rb @@ -0,0 +1,139 @@ +$dir = File.join(Dir.tmpdir, "mruby-require-test-#{Time.now.to_i}.#{Time.now.usec}") + +def test_setup + Dir.mkdir($dir) unless File.exist?($dir) + + File.open(File.join($dir, "test.rb"), "w") do |fp| + fp.puts "$require_test_variable = 123" + end + + File.open(File.join($dir, "test_dir.rb"), "w") do |fp| + fp.puts "$test_dir = 'test_dir'" + end + Dir.mkdir(File.join($dir, "test_dir")) + File.open(File.join($dir, "test_dir", "test_dir.rb"), "w") do |fp| + fp.puts "$test_dir2 = 'test_dir/test_dir'" + end + + File.open(File.join($dir, "test_conf.conf"), "w") do |fp| + fp.puts "$test_conf = 'test_conf'" + end + + File.open(File.join($dir, "empty.rb"), "w") + + test_reset +end + +def test_reset + $require_test_variable = nil + $test_dir = nil + $test_dir2 = nil + $test_conf = nil + $LOAD_PATH = [$dir] + $" = [] +end + +def remove_file_recursive(path) + if File.directory? path + Dir.entries(path).each do |entry| + next if ['.', '..'].include?(entry) + remove_file_recursive File.join(path, entry) + end + Dir.unlink path + else + File.unlink path + end +end + +def test_cleanup + if $dir && File.exist?($dir) + remove_file_recursive $dir + end +end + +##### +test_setup +##### + +assert("require 'test' should be success") do + test_reset + + assert_true require("test"), "require returns true when success" + assert_equal [File.join($dir, "test.rb")], $" + assert_equal 123, $require_test_variable + $require_test_variable = 789 + assert_false require("test"), "2nd require should returns false" + assert_equal 789, $require_test_variable + + test_reset + + assert_true require("test.rb"), "require should be success with '.rb'" + assert_equal [File.join($dir, "test.rb")], $" +end + +assert("require with absolute path should be success") do + test_reset + assert_true require(File.join($dir, "test")) + assert_equal [File.join($dir, "test.rb")], $" + + test_reset + assert_true require(File.join($dir, "test.rb")) + assert_equal [File.join($dir, "test.rb")], $" +end + +assert("require with absolute path && empty load_path") do + test_reset + $LOAD_PATH = [] + + assert_raise LoadError, "cannot load test.rb" do + require "test" + end + assert_equal true, require(File.join($dir, "test")) +end + +assert("require 'test_dir' should be success") do + test_reset + + assert_true require("test_dir"), "require 'test_dir' should be load 'test_dir.rb'" + assert_equal [File.join($dir, "test_dir.rb")], $" + assert_true require("test_dir/test_dir"), "require 'test_dir/test_dir' should be success" + assert_equal 'test_dir/test_dir', $test_dir2 +end + +assert("require 'test_conf' should be fail") do + test_reset + + assert_raise LoadError, "require 'test_conf.conf' should be fail" do + require("test_conf.conf") + end + assert_raise LoadError, "require method can't load *.conf" do + require File.join($dir, "test_conf.conf") + end +end + +assert("require 'empty' should be success") do + test_reset + + assert_true require("empty") + assert_equal 0, File.size(File.join($dir, "empty.rb")) +end + +assert("load 'test.rb' should be success") do + test_reset + + assert_true load(File.join($dir, "test.rb")) + assert_equal 123, $require_test_variable + assert_true $".empty? +end + +assert("load 'test_conf.conf' should be success") do + test_reset + + assert_equal true, load(File.join($dir, "test_conf.conf")) + assert_equal "test_conf", $test_conf +end + + +##### +test_cleanup +##### diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/test_context.rb b/web/server/h2o/libh2o/deps/mruby-require/test/test_context.rb new file mode 100644 index 000000000..001174748 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/test_context.rb @@ -0,0 +1,33 @@ +$dir = File.join(Dir.tmpdir, "mruby-require-test-#{Time.now.to_i}.#{Time.now.usec}") + +def test_setup + Dir.mkdir($dir) unless File.exist?($dir) + + File.open(File.join($dir, "foo.rb"), "w") do |f| + f.puts "$require_context = self" + end +end + +def test_cleanup + if $dir && File.exist?($dir) + Dir.entries($dir).each do |e| + next if ['.', '..'].include? e + File.unlink File.join($dir,e) + end + Dir.unlink $dir + end +end + + +##### +test_setup +##### + +assert("require context") do + require File.join($dir, 'foo.rb') + assert_equal self, $require_context +end + +##### +test_cleanup +##### diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/test_nest_loop.rb b/web/server/h2o/libh2o/deps/mruby-require/test/test_nest_loop.rb new file mode 100644 index 000000000..c5a4b18b0 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/test_nest_loop.rb @@ -0,0 +1,58 @@ +$dir = File.join(Dir.tmpdir, "mruby-require-test-#{Time.now.to_i}.#{Time.now.usec}") + +def test_setup + Dir.mkdir($dir) + + File.open(File.join($dir, "loop1.rb"), "w") do |fp| + fp.puts "require 'loop2.rb'" + fp.puts "$loop1 = 'loop1'" + end + File.open(File.join($dir, "loop2.rb"), "w") do |fp| + fp.puts "require 'loop1.rb'" + fp.puts "$loop2 = 'loop2'" + end + + $require_test_count = 10 + (1..$require_test_count-1).each do |i| + File.open(File.join($dir, "#{i+1}.rb"), "w") do |fp| + fp.puts "require '#{i}'" + fp.puts "s = 0" + (0..100).each{|num| fp.puts "s += #{num}" } + end + end + File.open(File.join($dir, "1.rb"), "w") do |fp| + fp.puts "$require_test_0 = 123" + end + + $LOAD_PATH = [$dir] +end + +def test_cleanup + if $dir && File.exist?($dir) + Dir.entries($dir).each do |e| + next if ['.', '..'].include? e + File.unlink File.join($dir,e) + end + Dir.unlink $dir + end +end + +##### +test_setup +##### + +assert("require loop check") do + require 'loop1' + assert_equal 'loop1', $loop1 + assert_equal 'loop2', $loop2 +end + +assert("require nest") do + before = $".size + require "#{$require_test_count}" + assert_equal before + $require_test_count, $".size +end + +##### +test_cleanup +##### diff --git a/web/server/h2o/libh2o/deps/mruby/.gitignore b/web/server/h2o/libh2o/deps/mruby/.gitignore new file mode 100644 index 000000000..4af3005ed --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/.gitignore @@ -0,0 +1,26 @@ +# / +*.bak +*.d +*.o +/benchmark/**/*.dat +/benchmark/*.pdf +/benchmark/*.png +*.orig +*.pdb +*.rej +*.sav +*.swp +*.tmp +*~ +.DS_Store +.ccmalloc +.svn +/.git +cscope.out +tags +/src/y.tab.c +/bin +/build +/mruby-source-*.gem +doc/api +.yardoc diff --git a/web/server/h2o/libh2o/deps/mruby/.gitlab-ci.yml b/web/server/h2o/libh2o/deps/mruby/.gitlab-ci.yml new file mode 100644 index 000000000..8f4179232 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/.gitlab-ci.yml @@ -0,0 +1,3214 @@ +--- +stages: +- pretest +- test +pretest: + stage: pretest + image: registry.gitlab.com/dabroz/mruby:gcc47_0.1 + tags: + - linux + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + script: "./minirake all test" +Test gcc-4.7 32bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 32bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.7 64bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc47_0.7 + variables: + CC: gcc-4.7 + CXX: g++-4.7 + LD: gcc-4.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 32bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.8 64bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc48_0.7 + variables: + CC: gcc-4.8 + CXX: g++-4.8 + LD: gcc-4.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 32bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-4.9 64bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc49_0.7 + variables: + CC: gcc-4.9 + CXX: g++-4.9 + LD: gcc-4.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 32bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 32bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-5 64bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-5 64bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc5_0.7 + variables: + CC: gcc-5 + CXX: g++-5 + LD: gcc-5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 32bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 32bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test gcc-6 64bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test gcc-6 64bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:gcc6_0.7 + variables: + CC: gcc-6 + CXX: g++-6 + LD: gcc-6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 32bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 32bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.5 64bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.5 64bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang35_0.7 + variables: + CC: clang-3.5 + CXX: clang++-3.5 + LD: clang-3.5 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 32bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 32bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.6 64bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.6 64bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang36_0.7 + variables: + CC: clang-3.6 + CXX: clang++-3.6 + LD: clang-3.6 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 32bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 32bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.7 64bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.7 64bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang37_0.7 + variables: + CC: clang-3.7 + CXX: clang++-3.7 + LD: clang-3.7 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 32bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 32bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.8 64bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.8 64bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang38_0.7 + variables: + CC: clang-3.8 + CXX: clang++-3.8 + LD: clang-3.8 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 32bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 32bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-m32 -DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_UTF8_STRING=1" + LDFLAGS: "-m32" + script: env; ./minirake --verbose all test +Test clang-3.9 64bit: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_int16_nan: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_int16_nan_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_INT16=1 -DMRB_NAN_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_float: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_float_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_float_int16: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_float_int16_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT16=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_float_int64: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test +Test clang-3.9 64bit_float_int64_utf8: + stage: test + image: registry.gitlab.com/dabroz/mruby:clang39_0.7 + variables: + CC: clang-3.9 + CXX: clang++-3.9 + LD: clang-3.9 + CFLAGS: "-DMRB_USE_FLOAT=1 -DMRB_INT64=1 -DMRB_WORD_BOXING=1 -DMRB_UTF8_STRING=1" + LDFLAGS: '' + script: env; ./minirake --verbose all test diff --git a/web/server/h2o/libh2o/deps/mruby/.travis.yml b/web/server/h2o/libh2o/deps/mruby/.travis.yml new file mode 100644 index 000000000..8d201515c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/.travis.yml @@ -0,0 +1,18 @@ +language: c + +sudo: false + +matrix: + include: + - os: linux + sudo: 9000 + - os: osx + osx_image: xcode7.1 + +addons: + apt: + packages: + - gperf + +env: MRUBY_CONFIG=travis_config.rb +script: "./minirake all test" diff --git a/web/server/h2o/libh2o/deps/mruby/.yardopts b/web/server/h2o/libh2o/deps/mruby/.yardopts new file mode 100644 index 000000000..27f6d59a1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/.yardopts @@ -0,0 +1,17 @@ +--markup markdown +--plugin mruby +--plugin coderay +--output-dir doc/api + +src/**/*.c +mrblib/**/*.rb +include/**/*.h + +mrbgems/*/src/**/*.c +mrbgems/*/mrblib/**/*.rb +mrbgems/*/include/**/*.h +- +AUTHORS +MITL +CONTRIBUTING.md +doc/guides/*.md diff --git a/web/server/h2o/libh2o/deps/mruby/AUTHORS b/web/server/h2o/libh2o/deps/mruby/AUTHORS new file mode 100644 index 000000000..a918ecdaa --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/AUTHORS @@ -0,0 +1,39 @@ +Original Authors "mruby developers" are: + Yukihiro Matsumoto + SCSK KYUSHU CORPORATION + Kyushu Institute of Technology + Network Applied Communication Laboratory, Inc. + Daniel Bovensiepen + Jon Maken + Bjorn De Meyer + Yuichiro MASUI + Masamitsu MURASE + Masaki Muranaka + Internet Initiative Japan Inc. + Tadashi FUKUZAWA + MATSUMOTO Ryosuke + Yasuhiro Matsumoto + Koji Yoshioka + Jun Hiroe + Narihiro Nakamura + Yuichi Nishiwaki + Tatsuhiko Kubo + Takeshi Watanabe + Yuki Kurihara + specified non-profit corporation mruby Forum + Kazuaki Tanaka + Hiromasa Ishii + Hiroshi Mimaki + Satoshi Odawara + Mitsubishi Electric Micro-Computer Application Software Co.,Ltd. + Ralph Desir(Mav7) + Hiroyuki Matsuzaki + Yuhei Okazaki + Manycolors, Inc. + Shota Nakano + Yuichi Osawa + Terence Lee + Zachary Scott + Tomasz Dąbrowski + Christopher Aue + Masahiro Wakame diff --git a/web/server/h2o/libh2o/deps/mruby/CONTRIBUTING.md b/web/server/h2o/libh2o/deps/mruby/CONTRIBUTING.md new file mode 100644 index 000000000..6bababb89 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/CONTRIBUTING.md @@ -0,0 +1,68 @@ +# How to contribute + +mruby is an open-source project which is looking forward to each contribution. + +## Your Pull Request + +To make it easy to review and understand your change please keep the following +things in mind before submitting your pull request: + +* Work on the latest possible state of **mruby/master** +* Create a branch which is dedicated to your change +* Test your changes before creating a pull request (```./minirake test```) +* If possible write a test case which confirms your change +* Don't mix several features or bug-fixes in one pull request +* Create a meaningful commit message +* Explain your change (i.e. with a link to the issue you are fixing) +* Use mrbgem to provide non ISO features (classes, modules and methods) unless + you have a special reason to implement them in the core + +## Coding conventions + +How to style your C and Ruby code which you want to submit. + +### C code + +The core part (parser, bytecode-interpreter, core-lib, etc.) of mruby is +written in the C programming language. Please note the following hints for your +C code: + +#### Comply with C99 (ISO/IEC 9899:1999) + +mruby should be highly portable to other systems and compilers. For this it is +recommended to keep your code as close as possible to the C99 standard +(http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf). + +Although we target C99, Visual C++ is also an important target for mruby. For +this reason a declaration of a local variable has to be at the beginning of a +scope block. + +#### Reduce library dependencies to a minimum + +The dependencies to libraries should be kept to an absolute minimum. This +increases the portability but makes it also easier to cut away parts of mruby +on-demand. + +#### Don't use C++ style comments + + /* This is the preferred comment style */ + +Use C++ style comments only for temporary comment e.g. commenting out some code lines. + +#### Insert a break after the method return value: + + int + main(void) + { + ... + } + +### Ruby code + +Parts of the standard library of mruby are written in the Ruby programming +language itself. Please note the following hints for your Ruby code: + +#### Comply with the Ruby standard (ISO/IEC 30170:2012) + +mruby is currently targeting to execute Ruby code which complies to ISO/IEC +30170:2012 (http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=59579). diff --git a/web/server/h2o/libh2o/deps/mruby/LEGAL b/web/server/h2o/libh2o/deps/mruby/LEGAL new file mode 100644 index 000000000..84929998c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/LEGAL @@ -0,0 +1,6 @@ +LEGAL NOTICE INFORMATION +------------------------ + +All the files in this distribution are covered under the MIT license +(see the file MITL) except some files mentioned below: + diff --git a/web/server/h2o/libh2o/deps/mruby/MITL b/web/server/h2o/libh2o/deps/mruby/MITL new file mode 100644 index 000000000..d02b8fe1c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/MITL @@ -0,0 +1,20 @@ +Copyright (c) 2017 mruby developers + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/web/server/h2o/libh2o/deps/mruby/Makefile b/web/server/h2o/libh2o/deps/mruby/Makefile new file mode 100644 index 000000000..4912f17e1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/Makefile @@ -0,0 +1,17 @@ +# mruby is using Rake (http://rake.rubyforge.org) as a build tool. +# We provide a minimalistic version called minirake inside of our +# codebase. + +RAKE = ruby ./minirake + +all : + $(RAKE) +.PHONY : all + +test : all + $(RAKE) test +.PHONY : test + +clean : + $(RAKE) clean +.PHONY : clean diff --git a/web/server/h2o/libh2o/deps/mruby/NEWS b/web/server/h2o/libh2o/deps/mruby/NEWS new file mode 100644 index 000000000..5c2523826 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/NEWS @@ -0,0 +1,13 @@ +* NEWS + +This document is a list of user visible feature changes made between +releases except for bug fixes. + +Note that each entry is kept so brief that no reason behind or +reference information is supplied with. For a full list of changes +with all sufficient information, see the ChangeLog file. + + +** Information about first release v1.0.0 + + diff --git a/web/server/h2o/libh2o/deps/mruby/README.md b/web/server/h2o/libh2o/deps/mruby/README.md new file mode 100644 index 000000000..9d0c611b2 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/README.md @@ -0,0 +1,92 @@ +[![Build Status][build-status-img]][travis-ci] + +## What is mruby + +mruby is the lightweight implementation of the Ruby language complying to (part +of) the [ISO standard][ISO-standard]. Its syntax is Ruby 1.9 compatible. + +mruby can be linked and embedded within your application. We provide the +interpreter program "mruby" and the interactive mruby shell "mirb" as examples. +You can also compile Ruby programs into compiled byte code using the mruby +compiler "mrbc". All those tools reside in the "bin" directory. "mrbc" is +also able to generate compiled byte code in a C source file, see the "mrbtest" +program under the "test" directory for an example. + +This achievement was sponsored by the Regional Innovation Creation R&D Programs +of the Ministry of Economy, Trade and Industry of Japan. + +## How to get mruby + +The stable version 1.3.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/1.3.0.zip](https://github.com/mruby/mruby/archive/1.3.0.zip) + +The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master) + +The trunk of the mruby source tree can be checked out with the +following command: + + $ git clone https://github.com/mruby/mruby.git + +You can also install and compile mruby using [ruby-install](https://github.com/postmodern/ruby-install), [ruby-build](https://github.com/rbenv/ruby-build) or [rvm](https://github.com/rvm/rvm). + +## mruby home-page + +The URL of the mruby home-page is: [http://www.mruby.org](http://www.mruby.org). + +## Mailing list + +We don't have a mailing list, but you can use [GitHub issues](https://github.com/mruby/mruby). + +## How to compile and install (mruby and gems) + +See the [doc/guides/compile.md](doc/guides/compile.md) file. + +## Running Tests + +To run the tests, execute the following from the project's root directory. + + $ make test + +Or + + $ ruby ./minirake test + +## How to customize mruby (mrbgems) + +mruby contains a package manager called *mrbgems*. To create extensions +in C and/or Ruby you should create a *GEM*. For a documentation of how to +use mrbgems consult the file [doc/guides/mrbgems.md](doc/guides/mrbgems.md). For example code of +how to use mrbgems look into the folder *examples/mrbgems/*. + +## License + +mruby is released under the [MIT License](MITL). + +## Note for License + +mruby has chosen a MIT License due to its permissive license allowing +developers to target various environments such as embedded systems. +However, the license requires the display of the copyright notice and license +information in manuals for instance. Doing so for big projects can be +complicated or troublesome. This is why mruby has decided to display "mruby +developers" as the copyright name to make it simple conventionally. +In the future, mruby might ask you to distribute your new code +(that you will commit,) under the MIT License as a member of +"mruby developers" but contributors will keep their copyright. +(We did not intend for contributors to transfer or waive their copyrights, +Actual copyright holder name (contributors) will be listed in the AUTHORS +file.) + +Please ask us if you want to distribute your code under another license. + +## How to Contribute + +See the [contribution guidelines][contribution-guidelines], and then send a pull +request to <http://github.com/mruby/mruby>. We consider you have granted +non-exclusive right to your contributed code under MIT license. If you want to +be named as one of mruby developers, please include an update to the AUTHORS +file in your pull request. + +[ISO-standard]: http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=59579 +[build-status-img]: https://travis-ci.org/mruby/mruby.svg?branch=master +[contribution-guidelines]: CONTRIBUTING.md +[travis-ci]: https://travis-ci.org/mruby/mruby diff --git a/web/server/h2o/libh2o/deps/mruby/Rakefile b/web/server/h2o/libh2o/deps/mruby/Rakefile new file mode 100644 index 000000000..2f6fa056f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/Rakefile @@ -0,0 +1,152 @@ +# encoding: utf-8 +# Build description. +# basic build file for mruby +MRUBY_ROOT = File.dirname(File.expand_path(__FILE__)) +MRUBY_BUILD_HOST_IS_CYGWIN = RUBY_PLATFORM.include?('cygwin') +MRUBY_BUILD_HOST_IS_OPENBSD = RUBY_PLATFORM.include?('openbsd') + +$LOAD_PATH << File.join(MRUBY_ROOT, "lib") + +# load build systems +require "mruby-core-ext" +require "mruby/build" +require "mruby/gem" + +# load configuration file +MRUBY_CONFIG = (ENV['MRUBY_CONFIG'] && ENV['MRUBY_CONFIG'] != '') ? ENV['MRUBY_CONFIG'] : "#{MRUBY_ROOT}/build_config.rb" +load MRUBY_CONFIG + +# load basic rules +MRuby.each_target do |build| + build.define_rules +end + +# load custom rules +load "#{MRUBY_ROOT}/src/mruby_core.rake" +load "#{MRUBY_ROOT}/mrblib/mrblib.rake" + +load "#{MRUBY_ROOT}/tasks/mrbgems.rake" +load "#{MRUBY_ROOT}/tasks/libmruby.rake" + +load "#{MRUBY_ROOT}/tasks/benchmark.rake" + +load "#{MRUBY_ROOT}/tasks/gitlab.rake" + +############################## +# generic build targets, rules +task :default => :all + +bin_path = ENV['INSTALL_DIR'] || "#{MRUBY_ROOT}/bin" +FileUtils.mkdir_p bin_path, { :verbose => $verbose } + +depfiles = MRuby.targets['host'].bins.map do |bin| + install_path = MRuby.targets['host'].exefile("#{bin_path}/#{bin}") + source_path = MRuby.targets['host'].exefile("#{MRuby.targets['host'].build_dir}/bin/#{bin}") + + file install_path => source_path do |t| + FileUtils.rm_f t.name, { :verbose => $verbose } + FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose } + end + + install_path +end + +MRuby.each_target do |target| + gems.map do |gem| + current_dir = gem.dir.relative_path_from(Dir.pwd) + relative_from_root = gem.dir.relative_path_from(MRUBY_ROOT) + current_build_dir = File.expand_path "#{build_dir}/#{relative_from_root}" + + if current_build_dir !~ /^#{build_dir}/ + current_build_dir = "#{build_dir}/mrbgems/#{gem.name}" + end + + gem.bins.each do |bin| + exec = exefile("#{build_dir}/bin/#{bin}") + objs = Dir.glob("#{current_dir}/tools/#{bin}/*.{c,cpp,cxx,cc}").map { |f| objfile(f.pathmap("#{current_build_dir}/tools/#{bin}/%n")) } + + file exec => objs + [libfile("#{build_dir}/lib/libmruby")] do |t| + gem_flags = gems.map { |g| g.linker.flags } + gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries } + gem_flags_after_libraries = gems.map { |g| g.linker.flags_after_libraries } + gem_libraries = gems.map { |g| g.linker.libraries } + gem_library_paths = gems.map { |g| g.linker.library_paths } + linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, gem_flags_before_libraries, gem_flags_after_libraries + end + + if target == MRuby.targets['host'] + install_path = MRuby.targets['host'].exefile("#{bin_path}/#{bin}") + + file install_path => exec do |t| + FileUtils.rm_f t.name, { :verbose => $verbose } + FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose } + end + depfiles += [ install_path ] + elsif target == MRuby.targets['host-debug'] + unless MRuby.targets['host'].gems.map {|g| g.bins}.include?([bin]) + install_path = MRuby.targets['host-debug'].exefile("#{bin_path}/#{bin}") + + file install_path => exec do |t| + FileUtils.rm_f t.name, { :verbose => $verbose } + FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose } + end + depfiles += [ install_path ] + end + else + depfiles += [ exec ] + end + end + end +end + +depfiles += MRuby.targets.map { |n, t| + [t.libfile("#{t.build_dir}/lib/libmruby")] +}.flatten + +depfiles += MRuby.targets.reject { |n, t| n == 'host' }.map { |n, t| + t.bins.map { |bin| t.exefile("#{t.build_dir}/bin/#{bin}") } +}.flatten + +desc "build all targets, install (locally) in-repo" +task :all => depfiles do + puts + puts "Build summary:" + puts + MRuby.each_target do + print_build_summary + end +end + +desc "run all mruby tests" +task :test => ["all"] do + MRuby.each_target do + run_test if test_enabled? + end +end + +desc "clean all built and in-repo installed artifacts" +task :clean do + MRuby.each_target do |t| + FileUtils.rm_rf t.build_dir, { :verbose => $verbose } + end + FileUtils.rm_f depfiles, { :verbose => $verbose } + puts "Cleaned up target build folder" +end + +desc "clean everything!" +task :deep_clean => ["clean"] do + MRuby.each_target do |t| + FileUtils.rm_rf t.gem_clone_dir, { :verbose => $verbose } + end + puts "Cleaned up mrbgems build folder" +end + +desc 'generate document' +task :doc do + begin + sh "mrbdoc" + rescue + puts "ERROR: To generate documents, you should install yard-mruby gem." + puts " $ gem install yard-mruby" + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/TODO b/web/server/h2o/libh2o/deps/mruby/TODO new file mode 100644 index 000000000..3e195f99b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/TODO @@ -0,0 +1,10 @@ +Things to do (Things that are not done yet) + +* special variables ($1,$2..) +* super in aliased methods +* multi-assignment decomposing +* keyword arguments in def statement + +Things to improve (Done but things to fix) + +* Make additions as they are noticed. diff --git a/web/server/h2o/libh2o/deps/mruby/appveyor.yml b/web/server/h2o/libh2o/deps/mruby/appveyor.yml new file mode 100644 index 000000000..c62b13573 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/appveyor.yml @@ -0,0 +1,27 @@ +version: "{build}" + +os: Visual Studio 2015 + +clone_depth: 50 + + +environment: + matrix: + # Visual Studio 2015 64bit + - visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat + machine: amd64 + + # Visual Studio 2013 64bit + - visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat + machine: amd64 + + +init: + - call "%visualcpp%" %machine% + # For using bison.exe + - set PATH=%PATH%;C:\cygwin\bin; + + +build_script: + - set MRUBY_CONFIG=appveyor_config.rb + - ruby .\minirake test diff --git a/web/server/h2o/libh2o/deps/mruby/appveyor_config.rb b/web/server/h2o/libh2o/deps/mruby/appveyor_config.rb new file mode 100644 index 000000000..57e103307 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/appveyor_config.rb @@ -0,0 +1,50 @@ +MRuby::Build.new('debug') do |conf| + toolchain :visualcpp + enable_debug + + # include all core GEMs + conf.gembox 'full-core' + conf.compilers.each do |c| + c.defines += %w(MRB_GC_STRESS MRB_GC_FIXED_ARENA) + end + + build_mrbc_exec +end + +MRuby::Build.new('full-debug') do |conf| + toolchain :visualcpp + enable_debug + + # include all core GEMs + conf.gembox 'full-core' + conf.cc.defines = %w(MRB_ENABLE_DEBUG_HOOK) + + conf.enable_test +end + +MRuby::Build.new do |conf| + toolchain :visualcpp + + # include all core GEMs + conf.gembox 'full-core' + conf.compilers.each do |c| + c.defines += %w(MRB_GC_FIXED_ARENA) + end + conf.enable_bintest + conf.enable_test +end + +MRuby::Build.new('cxx_abi') do |conf| + toolchain :visualcpp + + conf.gembox 'full-core' + conf.compilers.each do |c| + c.defines += %w(MRB_GC_FIXED_ARENA) + end + conf.enable_bintest + conf.enable_test + + enable_cxx_abi + + build_mrbc_exec +end diff --git a/web/server/h2o/libh2o/deps/mruby/benchmark/bm_ao_render.rb b/web/server/h2o/libh2o/deps/mruby/benchmark/bm_ao_render.rb new file mode 100644 index 000000000..8212c3a13 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/benchmark/bm_ao_render.rb @@ -0,0 +1,314 @@ +# AO render benchmark +# Original program (C) Syoyo Fujita in Javascript (and other languages) +# https://code.google.com/p/aobench/ +# Ruby(yarv2llvm) version by Hideki Miura +# mruby version by Hideki Miura +# + +IMAGE_WIDTH = 64 +IMAGE_HEIGHT = 64 +NSUBSAMPLES = 2 +NAO_SAMPLES = 8 + +module Rand + # Use xorshift + @@x = 123456789 + @@y = 362436069 + @@z = 521288629 + @@w = 88675123 + BNUM = 1 << 29 + BNUMF = BNUM.to_f + def self.rand + x = @@x + t = x ^ ((x & 0xfffff) << 11) + w = @@w + @@x, @@y, @@z = @@y, @@z, w + w = @@w = (w ^ (w >> 19) ^ (t ^ (t >> 8))) + (w % BNUM) / BNUMF + end +end + +class Vec + def initialize(x, y, z) + @x = x + @y = y + @z = z + end + + def x=(v); @x = v; end + def y=(v); @y = v; end + def z=(v); @z = v; end + def x; @x; end + def y; @y; end + def z; @z; end + + def vadd(b) + Vec.new(@x + b.x, @y + b.y, @z + b.z) + end + + def vsub(b) + Vec.new(@x - b.x, @y - b.y, @z - b.z) + end + + def vcross(b) + Vec.new(@y * b.z - @z * b.y, + @z * b.x - @x * b.z, + @x * b.y - @y * b.x) + end + + def vdot(b) + r = @x * b.x + @y * b.y + @z * b.z + r + end + + def vlength + Math.sqrt(@x * @x + @y * @y + @z * @z) + end + + def vnormalize + len = vlength + v = Vec.new(@x, @y, @z) + if len > 1.0e-17 then + v.x = v.x / len + v.y = v.y / len + v.z = v.z / len + end + v + end +end + + +class Sphere + def initialize(center, radius) + @center = center + @radius = radius + end + + def center; @center; end + def radius; @radius; end + + def intersect(ray, isect) + rs = ray.org.vsub(@center) + b = rs.vdot(ray.dir) + c = rs.vdot(rs) - (@radius * @radius) + d = b * b - c + if d > 0.0 then + t = - b - Math.sqrt(d) + + if t > 0.0 and t < isect.t then + isect.t = t + isect.hit = true + isect.pl = Vec.new(ray.org.x + ray.dir.x * t, + ray.org.y + ray.dir.y * t, + ray.org.z + ray.dir.z * t) + n = isect.pl.vsub(@center) + isect.n = n.vnormalize + end + end + end +end + +class Plane + def initialize(p, n) + @p = p + @n = n + end + + def intersect(ray, isect) + d = -@p.vdot(@n) + v = ray.dir.vdot(@n) + v0 = v + if v < 0.0 then + v0 = -v + end + if v0 < 1.0e-17 then + return + end + + t = -(ray.org.vdot(@n) + d) / v + + if t > 0.0 and t < isect.t then + isect.hit = true + isect.t = t + isect.n = @n + isect.pl = Vec.new(ray.org.x + t * ray.dir.x, + ray.org.y + t * ray.dir.y, + ray.org.z + t * ray.dir.z) + end + end +end + +class Ray + def initialize(org, dir) + @org = org + @dir = dir + end + + def org; @org; end + def org=(v); @org = v; end + def dir; @dir; end + def dir=(v); @dir = v; end +end + +class Isect + def initialize + @t = 10000000.0 + @hit = false + @pl = Vec.new(0.0, 0.0, 0.0) + @n = Vec.new(0.0, 0.0, 0.0) + end + + def t; @t; end + def t=(v); @t = v; end + def hit; @hit; end + def hit=(v); @hit = v; end + def pl; @pl; end + def pl=(v); @pl = v; end + def n; @n; end + def n=(v); @n = v; end +end + +def clamp(f) + i = f * 255.5 + if i > 255.0 then + i = 255.0 + end + if i < 0.0 then + i = 0.0 + end + i.to_i +end + +def otherBasis(basis, n) + basis[2] = Vec.new(n.x, n.y, n.z) + basis[1] = Vec.new(0.0, 0.0, 0.0) + + if n.x < 0.6 and n.x > -0.6 then + basis[1].x = 1.0 + elsif n.y < 0.6 and n.y > -0.6 then + basis[1].y = 1.0 + elsif n.z < 0.6 and n.z > -0.6 then + basis[1].z = 1.0 + else + basis[1].x = 1.0 + end + + basis[0] = basis[1].vcross(basis[2]) + basis[0] = basis[0].vnormalize + + basis[1] = basis[2].vcross(basis[0]) + basis[1] = basis[1].vnormalize +end + +class Scene + def initialize + @spheres = Array.new + @spheres[0] = Sphere.new(Vec.new(-2.0, 0.0, -3.5), 0.5) + @spheres[1] = Sphere.new(Vec.new(-0.5, 0.0, -3.0), 0.5) + @spheres[2] = Sphere.new(Vec.new(1.0, 0.0, -2.2), 0.5) + @plane = Plane.new(Vec.new(0.0, -0.5, 0.0), Vec.new(0.0, 1.0, 0.0)) + end + + def ambient_occlusion(isect) + basis = Array.new(3) + otherBasis(basis, isect.n) + + ntheta = NAO_SAMPLES + nphi = NAO_SAMPLES + eps = 0.0001 + occlusion = 0.0 + + p0 = Vec.new(isect.pl.x + eps * isect.n.x, + isect.pl.y + eps * isect.n.y, + isect.pl.z + eps * isect.n.z) + nphi.times do |j| + ntheta.times do |i| + r = Rand::rand + phi = 2.0 * 3.14159265 * Rand::rand + x = Math.cos(phi) * Math.sqrt(1.0 - r) + y = Math.sin(phi) * Math.sqrt(1.0 - r) + z = Math.sqrt(r) + + rx = x * basis[0].x + y * basis[1].x + z * basis[2].x + ry = x * basis[0].y + y * basis[1].y + z * basis[2].y + rz = x * basis[0].z + y * basis[1].z + z * basis[2].z + + raydir = Vec.new(rx, ry, rz) + ray = Ray.new(p0, raydir) + + occisect = Isect.new + @spheres[0].intersect(ray, occisect) + @spheres[1].intersect(ray, occisect) + @spheres[2].intersect(ray, occisect) + @plane.intersect(ray, occisect) + if occisect.hit then + occlusion = occlusion + 1.0 + else + 0.0 + end + end + end + + occlusion = (ntheta.to_f * nphi.to_f - occlusion) / (ntheta.to_f * nphi.to_f) + Vec.new(occlusion, occlusion, occlusion) + end + + def render(w, h, nsubsamples) + cnt = 0 + nsf = nsubsamples.to_f + h.times do |y| + w.times do |x| + rad = Vec.new(0.0, 0.0, 0.0) + + # Subsmpling + nsubsamples.times do |v| + nsubsamples.times do |u| + cnt = cnt + 1 + wf = w.to_f + hf = h.to_f + xf = x.to_f + yf = y.to_f + uf = u.to_f + vf = v.to_f + + px = (xf + (uf / nsf) - (wf / 2.0)) / (wf / 2.0) + py = -(yf + (vf / nsf) - (hf / 2.0)) / (hf / 2.0) + + eye = Vec.new(px, py, -1.0).vnormalize + + ray = Ray.new(Vec.new(0.0, 0.0, 0.0), eye) + + isect = Isect.new + @spheres[0].intersect(ray, isect) + @spheres[1].intersect(ray, isect) + @spheres[2].intersect(ray, isect) + @plane.intersect(ray, isect) + if isect.hit then + col = ambient_occlusion(isect) + rad.x = rad.x + col.x + rad.y = rad.y + col.y + rad.z = rad.z + col.z + else + 0.0 + end + end + end + + r = rad.x / (nsf * nsf) + g = rad.y / (nsf * nsf) + b = rad.z / (nsf * nsf) + printf("%c", clamp(r)) + printf("%c", clamp(g)) + printf("%c", clamp(b)) + end + end + end +end + +# File.open("ao.ppm", "w") do |fp| + printf("P6\n") + printf("%d %d\n", IMAGE_WIDTH, IMAGE_HEIGHT) + printf("255\n", IMAGE_WIDTH, IMAGE_HEIGHT) + Scene.new.render(IMAGE_WIDTH, IMAGE_HEIGHT, NSUBSAMPLES) +# Scene.new.render(256, 256, 2) +# end diff --git a/web/server/h2o/libh2o/deps/mruby/benchmark/bm_app_lc_fizzbuzz.rb b/web/server/h2o/libh2o/deps/mruby/benchmark/bm_app_lc_fizzbuzz.rb new file mode 100644 index 000000000..26283cc3f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/benchmark/bm_app_lc_fizzbuzz.rb @@ -0,0 +1,52 @@ +# +# FizzBuzz program using only lambda calculus +# +# This program is quoted from +# "Understanding Computation" by Tom Stuart +# http://computationbook.com/ +# +# You can understand why this program works fine by reading this book. +# + +solution = -> k { -> f { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[-> x { -> y { x } }] }[l]][x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } }] }[-> p { p[-> x { -> y { y } }] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } }] }[-> p { p[-> x { -> y { y } }] }[l]] }[l]][y] }] } } } }][k][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> l { -> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[l][f[x]] } }] } }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[m][n]][-> x { -> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[f[-> n { -> p { -> x { p[n[p][x]] } } }[m]][n]][m][x] }][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]] } } }][-> p { -> x { p[x] } }][-> p { -> x { p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[x]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] } }]][-> n { -> b { b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]][n][x] }][m] } } }][n][-> p { -> x { p[p[p[p[p[p[p[p[p[p[p[p[p[p[p[x]]]]]]]]]]]]]]] } }]]][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]][-> b { b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]][n][x] }][m] } } }][n][-> p { -> x { p[p[p[x]]] } }]]][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]][-> b { b }[-> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]][n][x] }][m] } } }][n][-> p { -> x { p[p[p[p[p[x]]]]] } }]]][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]]][-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> n { -> p { -> x { p[n[p][x]] } } }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]]]][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]][-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> n { -> l { -> x { -> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> l { -> x { -> g { -> b { b }[-> p { p[-> x { -> y { x } }] }[l]][x][-> y { g[f[-> l { -> p { p[-> x { -> y { y } }] }[-> p { p[-> x { -> y { y } }] }[l]] }[l]][x][g]][-> l { -> p { p[-> x { -> y { x } }] }[-> p { p[-> x { -> y { y } }] }[l]] }[l]][y] }] } } } }][l][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }[-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][x]][-> l { -> x { -> x { -> y { -> f { f[x][y] } } }[-> x { -> y { y } }][-> x { -> y { -> f { f[x][y] } } }[x][l]] } }] } }[-> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }[-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]]][-> x { -> y { -> f { f[x][y] } } }[-> x { -> y { x } }][-> x { -> y { x } }]][-> x { f[-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][m]][-> x { -> n { -> p { -> x { p[n[p][x]] } } }[f[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]][n]][x] }][-> p { -> x { x } }] } } }][n][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]][x] }]][-> f { -> x { f[-> y { x[x][y] }] }[-> x { f[-> y { x[x][y] }] }] }[-> f { -> m { -> n { -> b { b }[-> m { -> n { -> n { n[-> x { -> x { -> y { y } } }][-> x { -> y { x } }] }[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]] } }[n][m]][-> x { f[-> m { -> n { n[-> n { -> p { p[-> x { -> y { x } }] }[n[-> p { -> x { -> y { -> f { f[x][y] } } }[-> p { p[-> x { -> y { y } }] }[p]][-> n { -> p { -> x { p[n[p][x]] } } }[-> p { p[-> x { -> y { y } }] }[p]]] }][-> x { -> y { -> f { f[x][y] } } }[-> p { -> x { x } }][-> p { -> x { x } }]]] }][m] } }[m][n]][n][x] }][m] } } }][n][-> m { -> n { n[-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[m]][-> p { -> x { x } }] } }[-> p { -> x { p[p[x]] } }][-> p { -> x { p[p[p[p[p[x]]]]] } }]]] } }][n]]]] }] + +FIRST = -> l { LEFT[RIGHT[l]] } +IF = -> b { b } +LEFT = -> p { p[-> x { -> y { x } } ] } +RIGHT = -> p { p[-> x { -> y { y } } ] } +IS_EMPTY = LEFT +REST = -> l { RIGHT[RIGHT[l]] } + +def to_integer(proc) + proc[-> n { n + 1 }][0] +end + +def to_boolean(proc) + IF[proc][true][false] +end + +def to_array(proc) + array = [] + + until to_boolean(IS_EMPTY[proc]) + array.push(FIRST[proc]) + proc = REST[proc] + end + + array +end + +def to_char(c) + '0123456789BFiuz'.slice(to_integer(c)) +end + +def to_string(s) + to_array(s).map { |c| to_char(c) }.join +end + +answer = to_array(solution).map do |p| + to_string(p) +end + +answer_str = answer.to_a +# puts answer_str diff --git a/web/server/h2o/libh2o/deps/mruby/benchmark/bm_fib.rb b/web/server/h2o/libh2o/deps/mruby/benchmark/bm_fib.rb new file mode 100644 index 000000000..4b395f9cc --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/benchmark/bm_fib.rb @@ -0,0 +1,7 @@ + +def fib n + return n if n < 2 + fib(n-2) + fib(n-1) +end + +puts fib(37) diff --git a/web/server/h2o/libh2o/deps/mruby/benchmark/bm_so_lists.rb b/web/server/h2o/libh2o/deps/mruby/benchmark/bm_so_lists.rb new file mode 100644 index 000000000..e8f4a2a5f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/benchmark/bm_so_lists.rb @@ -0,0 +1,47 @@ +#from http://www.bagley.org/~doug/shootout/bench/lists/lists.ruby + +NUM = 300 +SIZE = 10000 + +def test_lists() + # create a list of integers (Li1) from 1 to SIZE + li1 = (1..SIZE).to_a + # copy the list to li2 (not by individual items) + li2 = li1.dup + # remove each individual item from left side of li2 and + # append to right side of li3 (preserving order) + li3 = Array.new + while (not li2.empty?) + li3.push(li2.shift) + end + # li2 must now be empty + # remove each individual item from right side of li3 and + # append to right side of li2 (reversing list) + while (not li3.empty?) + li2.push(li3.pop) + end + # li3 must now be empty + # reverse li1 in place + li1.reverse! + # check that first item is now SIZE + if li1[0] != SIZE then + p "not SIZE" + 0 + else + # compare li1 and li2 for equality + if li1 != li2 then + return(0) + else + # return the length of the list + li1.length + end + end +end + +i = 0 +while i<NUM + i += 1 + result = test_lists() +end + +result diff --git a/web/server/h2o/libh2o/deps/mruby/benchmark/build_config_boxing.rb b/web/server/h2o/libh2o/deps/mruby/benchmark/build_config_boxing.rb new file mode 100644 index 000000000..b478c9005 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/benchmark/build_config_boxing.rb @@ -0,0 +1,28 @@ +MRuby::Build.new do |conf| + toolchain :gcc +end + +MRuby::Build.new('no_boxing') do |conf| + toolchain :gcc + + conf.gembox 'default' +end + +MRuby::Build.new('word_boxing') do |conf| + toolchain :gcc + + conf.gembox 'default' + conf.compilers.each do |c| + c.defines += %w(MRB_WORD_BOXING) + end +end + +MRuby::Build.new('nan_boxing') do |conf| + toolchain :gcc + + conf.gembox 'default' + conf.compilers.each do |c| + c.defines += %w(MRB_NAN_BOXING) + end +end + diff --git a/web/server/h2o/libh2o/deps/mruby/benchmark/build_config_cc.rb b/web/server/h2o/libh2o/deps/mruby/benchmark/build_config_cc.rb new file mode 100644 index 000000000..56d725bc7 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/benchmark/build_config_cc.rb @@ -0,0 +1,13 @@ +MRuby::Build.new do |conf| + toolchain :gcc +end + +MRuby::Build.new('gcc') do |conf| + toolchain :gcc + conf.gembox 'default' +end + +MRuby::Build.new('clang') do |conf| + toolchain :clang + conf.gembox 'default' +end diff --git a/web/server/h2o/libh2o/deps/mruby/benchmark/plot.gpl b/web/server/h2o/libh2o/deps/mruby/benchmark/plot.gpl new file mode 100644 index 000000000..725e2ec1c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/benchmark/plot.gpl @@ -0,0 +1,5 @@ +set yrange [0:] +set terminal pngcairo font 'Sans, 8' lw 1 size 1400,1024 +set xtics rotate by -45 +set style histogram errorbars gap 2 lw 1 +set style fill solid border -1 diff --git a/web/server/h2o/libh2o/deps/mruby/bin/.gitkeep b/web/server/h2o/libh2o/deps/mruby/bin/.gitkeep new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/bin/.gitkeep diff --git a/web/server/h2o/libh2o/deps/mruby/build_config.rb b/web/server/h2o/libh2o/deps/mruby/build_config.rb new file mode 100644 index 000000000..8293092ab --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/build_config.rb @@ -0,0 +1,152 @@ +MRuby::Build.new do |conf| + # load specific toolchain settings + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # Use mrbgems + # conf.gem 'examples/mrbgems/ruby_extension_example' + # conf.gem 'examples/mrbgems/c_extension_example' do |g| + # g.cc.flags << '-g' # append cflags in this gem + # end + # conf.gem 'examples/mrbgems/c_and_ruby_extension_example' + # conf.gem :core => 'mruby-eval' + # conf.gem :mgem => 'mruby-io' + # conf.gem :github => 'iij/mruby-io' + # conf.gem :git => 'git@github.com:iij/mruby-io.git', :branch => 'master', :options => '-v' + + # include the default GEMs + conf.gembox 'default' + # C compiler settings + # conf.cc do |cc| + # cc.command = ENV['CC'] || 'gcc' + # cc.flags = [ENV['CFLAGS'] || %w()] + # cc.include_paths = ["#{root}/include"] + # cc.defines = %w(DISABLE_GEMS) + # cc.option_include_path = '-I%s' + # cc.option_define = '-D%s' + # cc.compile_options = "%{flags} -MMD -o %{outfile} -c %{infile}" + # end + + # mrbc settings + # conf.mrbc do |mrbc| + # mrbc.compile_options = "-g -B%{funcname} -o-" # The -g option is required for line numbers + # end + + # Linker settings + # conf.linker do |linker| + # linker.command = ENV['LD'] || 'gcc' + # linker.flags = [ENV['LDFLAGS'] || []] + # linker.flags_before_libraries = [] + # linker.libraries = %w() + # linker.flags_after_libraries = [] + # linker.library_paths = [] + # linker.option_library = '-l%s' + # linker.option_library_path = '-L%s' + # linker.link_options = "%{flags} -o %{outfile} %{objs} %{libs}" + # end + + # Archiver settings + # conf.archiver do |archiver| + # archiver.command = ENV['AR'] || 'ar' + # archiver.archive_options = 'rs %{outfile} %{objs}' + # end + + # Parser generator settings + # conf.yacc do |yacc| + # yacc.command = ENV['YACC'] || 'bison' + # yacc.compile_options = '-o %{outfile} %{infile}' + # end + + # gperf settings + # conf.gperf do |gperf| + # gperf.command = 'gperf' + # gperf.compile_options = '-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" %{infile} > %{outfile}' + # end + + # file extensions + # conf.exts do |exts| + # exts.object = '.o' + # exts.executable = '' # '.exe' if Windows + # exts.library = '.a' + # end + + # file separetor + # conf.file_separator = '/' + + # bintest + # conf.enable_bintest +end + +MRuby::Build.new('host-debug') do |conf| + # load specific toolchain settings + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' + + # C compiler settings + conf.cc.defines = %w(MRB_ENABLE_DEBUG_HOOK) + + # Generate mruby debugger command (require mruby-eval) + conf.gem :core => "mruby-bin-debugger" + + # bintest + # conf.enable_bintest +end + +MRuby::Build.new('test') do |conf| + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + conf.enable_bintest + conf.enable_test + + conf.gembox 'default' +end + +MRuby::Build.new('bench') do |conf| + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + conf.cc.flags << '-O3' + end + + conf.gembox 'default' +end + +# Define cross build settings +# MRuby::CrossBuild.new('32bit') do |conf| +# toolchain :gcc +# +# conf.cc.flags << "-m32" +# conf.linker.flags << "-m32" +# +# conf.build_mrbtest_lib_only +# +# conf.gem 'examples/mrbgems/c_and_ruby_extension_example' +# +# conf.test_runner.command = 'env' +# +# end diff --git a/web/server/h2o/libh2o/deps/mruby/doc/guides/compile.md b/web/server/h2o/libh2o/deps/mruby/doc/guides/compile.md new file mode 100644 index 000000000..2aaf6f1fe --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/doc/guides/compile.md @@ -0,0 +1,488 @@ +# Compile + +mruby uses Rake to compile and cross-compile all libraries and +binaries. + +## Prerequisites + +To compile mruby out of the source code you need the following tools: +* C Compiler (i.e. ```gcc```) +* Linker (i.e. ```gcc```) +* Archive utility (i.e. ```ar```) +* Parser generator (i.e. ```bison```) +* Ruby 1.8 or 1.9 (i.e. ```ruby``` or ```jruby```) + +Optional: +* GIT (to update mruby source and integrate mrbgems easier) +* C++ compiler (to use GEMs which include \*.cpp, \*.cxx, \*.cc) +* Assembler (to use GEMs which include \*.asm) + +## Usage + +Inside of the root directory of the mruby source a file exists +called *build_config.rb*. This file contains the build configuration +of mruby and looks like this for example: +```ruby +MRuby::Build.new do |conf| + toolchain :gcc +end +``` + +All tools necessary to compile mruby can be set or modified here. In case +you want to maintain an additional *build_config.rb* you can define a +customized path using the *$MRUBY_CONFIG* environment variable. + +To compile just call ```./minirake``` inside of the mruby source root. To +generate and execute the test tools call ```./minirake test```. To clean +all build files call ```./minirake clean```. To see full command line on +build, call ```./minirake -v```. + +## Build Configuration + +Inside of the *build_config.rb* the following options can be configured +based on your environment. + +### Toolchains + +The mruby build system already contains a set of toolchain templates which +configure the build environment for specific compiler infrastructures. + +#### GCC + +Toolchain configuration for the GNU C Compiler. +```ruby +toolchain :gcc +``` + +#### clang + +Toolchain configuration for the LLVM C Compiler clang. Mainly equal to the +GCC toolchain. +```ruby +toolchain :clang +``` + +#### Visual Studio 2010, 2012 and 2013 + +Toolchain configuration for Visual Studio on Windows. If you use the +[Visual Studio Command Prompt](http://msdn.microsoft.com/en-us/library/ms229859\(v=vs.110\).aspx), +you normally do not have to specify this manually, since it gets automatically detected by our build process. +```ruby +toolchain :visualcpp +``` + +#### Android + +Toolchain configuration for Android. +```ruby +toolchain :android +``` + +Requires the custom standalone Android NDK and the toolchain path +in ```ANDROID_STANDALONE_TOOLCHAIN```. + +### Binaries + +It is possible to select which tools should be compiled during the compilation +process. The following tools can be selected: +* mruby (mruby interpreter) +* mirb (mruby interactive shell) + +To select them declare conf.gem as follows: +```ruby +conf.gem "#{root}/mrbgems/mruby-bin-mruby" +conf.gem "#{root}/mrbgems/mruby-bin-mirb" +``` + +### File Separator + +Some environments require a different file separator character. It is possible to +set the character via ```conf.file_separator```. +```ruby +conf.file_separator = '/' +``` + +### C Compiler + +Configuration of the C compiler binary, flags and include paths. +```ruby +conf.cc do |cc| + cc.command = ... + cc.flags = ... + cc.include_paths = ... + cc.defines = ... + cc.option_include_path = ... + cc.option_define = ... + cc.compile_options = ... +end +``` + +C Compiler has header searcher to detect installed library. + +If you need a include path of header file use ```search_header_path```: +```ruby +# Searches ```iconv.h```. +# If found it will return include path of the header file. +# Otherwise it will return nil . +fail 'iconv.h not found' unless conf.cc.search_header_path 'iconv.h' +``` + +If you need a full file name of header file use ```search_header```: +```ruby +# Searches ```iconv.h```. +# If found it will return full path of the header file. +# Otherwise it will return nil . +iconv_h = conf.cc.search_header 'iconv.h' +print "iconv.h found: #{iconv_h}\n" +``` + +Header searcher uses compiler's ```include_paths``` by default. +When you are using GCC toolchain (including clang toolchain since its base is gcc toolchain) +it will use compiler specific include paths too. (For example ```/usr/local/include```, ```/usr/include```) + +If you need a special header search paths define a singleton method ```header_search_paths``` to C compiler: +```ruby +def conf.cc.header_search_paths + ['/opt/local/include'] + include_paths +end +``` + +### Linker + +Configuration of the Linker binary, flags and library paths. +```ruby +conf.linker do |linker| + linker.command = ... + linker.flags = ... + linker.flags_before_libraries = ... + linker.libraries = ... + linker.flags_after_libraries = ... + linker.library_paths = .... + linker.option_library = ... + linker.option_library_path = ... + linker.link_options = ... +end +``` + +### Archiver + +Configuration of the Archiver binary and flags. +```ruby +conf.archiver do |archiver| + archiver.command = ... + archiver.archive_options = ... +end +``` + +### Parser Generator + +Configuration of the Parser Generator binary and flags. +```ruby +conf.yacc do |yacc| + yacc.command = ... + yacc.compile_options = ... +end +``` + +### GPerf + +Configuration of the GPerf binary and flags. +```ruby +conf.gperf do |gperf| + gperf.command = ... + gperf.compile_options = ... +end +``` + +### File Extensions +```ruby +conf.exts do |exts| + exts.object = ... + exts.executable = ... + exts.library = ... +end +``` + +### Mrbgems + +Integrate GEMs in the build process. +```ruby +# Integrate GEM with additional configuration +conf.gem 'path/to/gem' do |g| + g.cc.flags << ... +end + +# Integrate GEM without additional configuration +conf.gem 'path/to/another/gem' +``` + +See doc/mrbgems/README.md for more option about mrbgems. + +### Mrbtest + +Configuration Mrbtest build process. + +If you want mrbtest.a only, You should set ```conf.build_mrbtest_lib_only``` +```ruby +conf.build_mrbtest_lib_only +``` + +### Bintest + +Tests for mrbgem tools using CRuby. +To have bintests place \*.rb scripts to ```bintest/``` directory of mrbgems. +See ```mruby-bin-*/bintest/*.rb``` if you need examples. +If you want a temporary files use `tempfile` module of CRuby instead of ```/tmp/```. + +You can enable it with following: +```ruby +conf.enable_bintest +``` + +### C++ ABI + +By default, mruby uses setjmp/longjmp to implement its +exceptions. But it doesn't release C++ stack object +correctly. To support mrbgems written in C++, mruby can be +configured to use C++ exception. + +There are two levels of C++ exception handling. The one is +```enable_cxx_exception``` that enables C++ exception, but +uses C ABI. The other is ```enable_cxx_abi``` where all +files are compiled by C++ compiler. + +When you mix C++ code, C++ exception would be enabled automatically. +If you need to enable C++ exception explicitly add the following: +```ruby +conf.enable_cxx_exception +``` + +#### C++ exception disabling. + +If your compiler does not support C++ and you want to ensure +you don't use mrbgem written in C++, you can explicitly disable +C++ exception, add following: +```ruby +conf.disable_cxx_exception +``` +and you will get an error when you try to use C++ gem. +Note that it must be called before ```enable_cxx_exception``` or ```gem``` method. + +### Debugging mode + +To enable debugging mode add the following: +```ruby +conf.enable_debug +``` + +When debugging mode is enabled +* Macro ```MRB_DEBUG``` would be defined. + * Which means ```mrb_assert()``` macro is enabled. +* Debug information of irep would be generated by ```mrbc```. + * Because ```-g``` flag would be added to ```mrbc``` runner. + * You can have better backtrace of mruby scripts with this. + +## Cross-Compilation + +mruby can also be cross-compiled from one platform to another. To +achieve this the *build_config.rb* needs to contain an instance of +```MRuby::CrossBuild```. This instance defines the compilation +tools and flags for the target platform. An example could look +like this: +```ruby +MRuby::CrossBuild.new('32bit') do |conf| + toolchain :gcc + + conf.cc.flags << "-m32" + conf.linker.flags << "-m32" +end +``` + +All configuration options of ```MRuby::Build``` can also be used +in ```MRuby::CrossBuild```. + +### Mrbtest in Cross-Compilation + +In cross compilation, you can run ```mrbtest``` on emulator if +you have it by changing configuration of test runner. +```ruby +conf.test_runner do |t| + t.command = ... # set emulator. this value must be non nil or false + t.flags = ... # set flags of emulator + + def t.run(bin) # override `run` if you need to change the behavior of it + ... # `bin` is the full path of mrbtest + end +end +``` + +## Build process + +During the build process the directory *build* will be created in the +root directory. The structure of this directory will look like this: + + +- build + | + +- host + | + +- bin <- Binaries (mirb, mrbc and mruby) + | + +- lib <- Libraries (libmruby.a and libmruby_core.a) + | + +- mrblib + | + +- src + | + +- test <- mrbtest tool + | + +- tools + | + +- mirb + | + +- mrbc + | + +- mruby + +The compilation workflow will look like this: +* compile all files under *src* (object files will be stored +in *build/host/src*) +* generate parser grammar out of *src/parse.y* (generated +result will be stored in *build/host/src/y.tab.c*) +* compile *build/host/src/y.tab.c* to *build/host/src/y.tab.o* +* create *build/host/lib/libmruby_core.a* out of all object files (C only) +* create ```build/host/bin/mrbc``` by compiling *tools/mrbc/mrbc.c* and +linking with *build/host/lib/libmruby_core.a* +* create *build/host/mrblib/mrblib.c* by compiling all \*.rb files +under *mrblib* with ```build/host/bin/mrbc``` +* compile *build/host/mrblib/mrblib.c* to *build/host/mrblib/mrblib.o* +* create *build/host/lib/libmruby.a* out of all object files (C and Ruby) +* create ```build/host/bin/mruby``` by compiling *mrbgems/mruby-bin-mruby/tools/mruby/mruby.c* and +linking with *build/host/lib/libmruby.a* +* create ```build/host/bin/mirb``` by compiling *mrbgems/mruby-bin-mirb/tools/mirb/mirb.c* and +linking with *build/host/lib/libmruby.a* + +``` + _____ _____ ______ ____ ____ _____ _____ ____ +| CC |->|GEN |->|AR |->|CC |->|CC |->|AR |->|CC |->|CC | +| *.c | |y.tab| |core.a| |mrbc| |*.rb| |lib.a| |mruby| |mirb| + ----- ----- ------ ---- ---- ----- ----- ---- +``` + +### Cross-Compilation + +In case of a cross-compilation to *i386* the *build* directory structure looks +like this: + + +- build + | + +- host + | | + | +- bin <- Native Binaries + | | + | +- lib <- Native Libraries + | | + | +- mrblib + | | + | +- src + | | + | +- test <- Native mrbtest tool + | | + | +- tools + | | + | +- mirb + | | + | +- mrbc + | | + | +- mruby + +- i386 + | + +- bin <- Cross-compiled Binaries + | + +- lib <- Cross-compiled Libraries + | + +- mrblib + | + +- src + | + +- test <- Cross-compiled mrbtest tool + | + +- tools + | + +- mirb + | + +- mrbc + | + +- mruby + +An extra directory is created for the target platform. In case you +compile for *i386* a directory called *i386* is created under the +build directory. + +The cross compilation workflow starts in the same way as the normal +compilation by compiling all *native* libraries and binaries. +Afterwards the cross compilation process proceeds like this: +* cross-compile all files under *src* (object files will be stored +in *build/i386/src*) +* generate parser grammar out of *src/parse.y* (generated +result will be stored in *build/i386/src/y.tab.c*) +* cross-compile *build/i386/src/y.tab.c* to *build/i386/src/y.tab.o* +* create *build/i386/mrblib/mrblib.c* by compiling all \*.rb files +under *mrblib* with the native ```build/host/bin/mrbc``` +* cross-compile *build/host/mrblib/mrblib.c* to *build/host/mrblib/mrblib.o* +* create *build/i386/lib/libmruby.a* out of all object files (C and Ruby) +* create ```build/i386/bin/mruby``` by cross-compiling *mrbgems/mruby-bin-mruby/tools/mruby/mruby.c* and +linking with *build/i386/lib/libmruby.a* +* create ```build/i386/bin/mirb``` by cross-compiling *mrbgems/mruby-bin-mirb/tools/mirb/mirb.c* and +linking with *build/i386/lib/libmruby.a* +* create *build/i386/lib/libmruby_core.a* out of all object files (C only) +* create ```build/i386/bin/mrbc``` by cross-compiling *tools/mrbc/mrbc.c* and +linking with *build/i386/lib/libmruby_core.a* + +``` + _______________________________________________________________ +| Native Compilation for Host System | +| _____ ______ _____ ____ ____ _____ | +| | CC | -> |AR | -> |GEN | -> |CC | -> |CC | -> |AR | | +| | *.c | |core.a| |y.tab| |mrbc| |*.rb| |lib.a| | +| ----- ------ ----- ---- ---- ----- | + --------------------------------------------------------------- + || + \||/ + \/ + ________________________________________________________________ +| Cross Compilation for Target System | +| _____ _____ _____ ____ ______ _____ | +| | CC | -> |AR | -> |CC | -> |CC | -> |AR | -> |CC | | +| | *.c | |lib.a| |mruby| |mirb| |core.a| |mrbc | | +| ----- ----- ----- ---- ------ ----- | + ---------------------------------------------------------------- +``` + +## Build Configuration Examples + +### Minimal Library + +To build a minimal mruby library you need to use the Cross Compiling +feature due to the reason that there are functions (i.e. stdio) which +can't be disabled for the main build. + +```ruby +MRuby::CrossBuild.new('Minimal') do |conf| + toolchain :gcc + + conf.cc.defines = %w(MRB_DISABLE_STDIO) + conf.bins = [] +end +``` + +This configuration defines a cross compile build called 'Minimal' which +is using the GCC and compiles for the host machine. It also disables +all usages of stdio and doesn't compile any binaries (i.e. mrbc). + +## Test Environment + +mruby's build process includes a test environment. In case you start the testing +of mruby, a native binary called ```mrbtest``` will be generated and executed. +This binary contains all test cases which are defined under *test/t*. In case +of a cross-compilation an additional cross-compiled *mrbtest* binary is +generated. You can copy this binary and run on your target system. diff --git a/web/server/h2o/libh2o/deps/mruby/doc/guides/debugger.md b/web/server/h2o/libh2o/deps/mruby/doc/guides/debugger.md new file mode 100644 index 000000000..72f2c2b32 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/doc/guides/debugger.md @@ -0,0 +1,370 @@ +# How to Use the mruby Debugger + +copyright (c) 2014 Specified Non-Profit Corporation mruby Forum + +## 1. Summary + +This file documents the mruby debugger ('mrdb') methods. + +## 2 Debugging with mrdb + +## 2.1 Building mrdb + +The trunk of the mruby source tree, with the most recent mrdb, can be checked out with the following command: + +```bash +$ git clone https://github.com/mruby/mruby.git +``` + +To run the `make` command: + +```bash +$ cd mruby +$ make +``` + +By default, the `make` command will install the debugger files into mruby/bin. + +You can add the path for mrdb on your host environment with the following command: + +```bash +$ echo "export PATH=\$PATH:MRUBY_ROOT/bin" >> ~/.bashrc +$ source ~/.bashrc +``` + +`*MRUBY_ROOT` is the directory in which mruby source code will be installed. + +To confirm mrdb was installed properly, run mrdb with the `--version` option: + +```bash +$ mrdb --version +mruby 1.3.0 (2017-7-4) +``` + +## 2.2 Basic Operation + +### 2.2.1 Debugging mruby Script Files (rb file) with mrdb + +To invoke the mruby debugger, just type `mrdb`. + +To specify the script file: + +```bash +$ mrdb [option] file name +``` + +For example: Debugging sample.rb + +```bash +$ mrdb sample.rb +``` + +You can execute the shell commands listed below: + +|command|description| +|:-:|:--| +|run|execute programs| +|step|execute stepping| +|continue|execute continuing program| +|break|configure the breaking point| +|delete|deleting the breaking points| +|disable|disabling the breaking points| +|enable|enabling the breaking points| +|info breakpoints|showing list of the breaking points| +|print|evaluating and printing the values of the mruby expressions in the script| +|list|displaying the source cords| +|help|showing help| +|quit|terminating the mruby debugger| + +### 2.2.2 Debugging mruby Binary Files (mrb file) with mrdb + +You can debug the mruby binary files. + +#### 2.2.2.1 Debugging the binary files + +* notice +To debug mruby binary files, you need to compile mruby files with option `-g`. + +```bash +$ mrbc -g sample.rb +``` + +You can debug the mruby binary files with following command and the option `-b`. + +```bash +$ mrdb -b sample.mrb +``` + +Then you can execute all debugger shell commands. + +#### Break Command + +You can use any breakpoint to stop the program by specifying the line number and method name. +The breakpoint list will be displayed after you have set the breakpoint successfully. + +Usage: + +``` +break [file:]linenum +b [file:]linenum +break [class:]method +b [class:]method +``` + +The breakpoint will be ordered in serial from 1. +The number, which was given to the deleted breakpoint, will never be given to another breakpoint again. + +You can give multiple breakpoints to specified the line number and method. +Be ware that breakpoint command will not check the validity of the class name and method name. + +You can get the current breakpoint information by the following options. + +breakpoint breakpoint number : file name. line number + +breakpoint breakpoint number : [class name,] method name + +#### Continue Command + +Usage: + +``` +continue [N] +c [N] +``` + +N: the next breakpoint number + +When resuming the program, it will stop at breakpoint N (N-1 breakpoint will be ignored). + +When you run the `continue` command without specifying N, the program will be stopped at the next breakpoint. + +Example: + +``` +(foo.rb:1) continue 3 +``` + +This will resume the program and stop it at the third breakpoint. + +#### Delete Command + +This will delete the specified breakpoint. + +Usage: + +``` +delete [breakpoint-no] +d [breakpoint-no] +``` + +breakpoint-no: breakpoint number + +Example: + +``` +(foo.rb:1) delete +``` + +This will delete all of the breakpoints. + +``` +(foo.rb:1) delete 1 3 +``` + +This will delete the breakpoint at 1 and 3. + +#### Disable Command + +This will disable the specified breakpoint. + +Usage: + +``` +disable [breakpoint-no] +dis [breakpoint-no] +``` + +reappointing: breakpoint number + +Example: + +``` +(foo.rb:1) disable +``` + +Use `disable` if you would like to disable all of the breakpoints. + +``` +(foo.rb:1) disable 1 3 +``` + +This will disable the breakpoints at 1 and 3. + +#### Enable Command + +This will enable the specified breakpoints. + +Usage: + +``` +enable [breakpoint-no] +e [breakpoint-no] +``` + +breakpoint-no: breakpoint number + +Example: + +``` +(foo.rb:1) enable +``` + +Enabling all breakpoints +``` +(foo.rb:1) enable 1 3 +``` + +Enabling the breakpoint 1 and 3 + +#### eval command + +Evaluating the string as source code and printing the value. + +Same as print command, please see print command. + +#### help command + +Displaying the help message. + +Usage: + +``` +help [command] +h [command] +``` + +Typing `help` without any options will display the command list. + +#### Info Breakpoints Command + +Displaying the specified breakpoint information. + +Usage: + +``` +info breakpoints [breakpoint-no] +i b [breakpoint-no] +``` + +breakpoint-no: breakpoint number + +Typing "info breakpoints" without ant option will display all breakpoint information. +Example: + +``` +(sample.rb:1) info breakpoints +Num Type Enb What +1 breakpoint y at sample.rb:3 -> file name,line number +2 breakpoint n in Sample_class:sample_class_method -> [class:]method name +3 breakpoint y in sample_global_method +``` + +Displaying the specified breakpoint number: + +``` +(foo.rb:1) info breakpoints 1 3 +Num Type Enb What +1 breakpoint y at sample.rb:3 +3 breakpoint y in sample_global_method +``` + +#### List Command + +To display the code of the source file. + +Usage: + +``` +list [filename:]first[,last] +l [filename]:first[,last] +``` + +first: the opening row number +last : the closing row number + +When you specify the `first`, but not the `last` option, you will receive 10 rows. +When you do not specify both the `first` and `last` options, you will receive the next 10 rows. + +Example: + +``` +Specifying file name and first row number +sample.rb:1) list sample2.rb:5 +``` + +Specifying the file name and the first and last row number: + +``` +(sample.rb:1) list sample2.rb:6,7 +``` + +#### Print Command + +Evaluating the string as source code and printing the value. + +Usage: + +``` +print [expr] +p [expr] +``` + +expr: expression + +The expression is mandatory. +The displayed expressions will be serially ordered from 1. +If an exception occurs, the exception information will be displayed and the debugging will be continued. + +Example: + +``` +(sample.rb:1) print 1+2 +$1 = 3 +(sample.rb:1) print self +$2 = main +``` + +Below is the case of the exception: + +``` +(sample.rb:1) print (1+2 +$1 = SyntaxError: line 1: syntax error, unexpected $end, expecting ')' +``` + +#### Quit Command + +Quitting the debugger. + +Usage: + +``` +quit +q +``` + +#### Run Command + +Running the program and stopping at the first breakpoint. + +Usage: + +``` +run +r +``` + +#### Step Command + +This will run the program step by step. +When the method and the block are invoked, the program will be stop at the first row. +The program, which is developed in C, will be ignored. diff --git a/web/server/h2o/libh2o/deps/mruby/doc/guides/gc-arena-howto.md b/web/server/h2o/libh2o/deps/mruby/doc/guides/gc-arena-howto.md new file mode 100644 index 000000000..aff7360e9 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/doc/guides/gc-arena-howto.md @@ -0,0 +1,177 @@ +# How to use `mrb_gc_arena_save()`/`mrb_gc_arena_restore()`/`mrb_gc_protect()` + +_This is an English translation of [Matz's blog post][matz blog post] +written in Japanese._ +_Some parts are updated to reflect recent changes._ +[matz blog post]: http://www.rubyist.net/~matz/20130731.html + +When you are extending mruby using C language, you may encounter +mysterious "arena overflow error" or memory leak or very slow +execution speed. This is an error indicating overflow of "GC arena" +implementing "conservative GC". + +GC (garbage collector) must ensure that object is "alive", in other +words, that it is referenced by somewhere from program. This can be +determined by checking if the object can be directly or indirectly +referenced by root. The local variables, global variables and +constants etc are root. + +If program execution is performed inside mruby VM, there is nothing to +worry about because GC can access all roots owned by VM. + +The problem arises when executing C functions. The object referenced +by C variable is also "alive", but mruby GC cannot aware of this, so +it might mistakenly recognize the objects referenced by only C +variables as dead. + +This can be a fatal bug if the GC tries to collect a live object. + +In CRuby, we scan C stack area, and use C variable as root to check +whether object is alive or not. Of course, because we are accessing C +stack just as memory region, we never know it is an integer or a +pointer. We workaround this by assuming that if it looks like a +pointer, then assume it as a pointer. We call it "conservative". + +By the way, CRuby's "conservative GC" has some problems. + +The biggest problem is we have no way to access to the stack area in +portable way. Therefore, we cannot use this method if we'd like to +implement highly portable runtime, like mruby. + +So we came up with an another plan to implement "conservative GC" in mruby. + +Again, the problem is when an object which was created in C function, becomes +no longer referenced in the Ruby world, and cannot be treated as garbage. + +In mruby, we recognize all objects created in C function are alive. +Then we have no problem such as confusing a live object as dead. + +This means that because we cannot collect truly dead object, we may +lose efficiency, but as a trade-off the GC itself is highly portable. +We can say goodbye to the problem that GC deletes live objects due to +optimization which sometimes occurs in CRuby. + +According to this idea, we have a table, called "GC arena", which +remembers objects created in C function. + +The arena is stack structure, when C function execution is returned to mruby +VM, all objects registered in the arena are popped. + +This works very well, but can cause another problem: "arena overflow error" or +memory leak. + +As of this writing, mruby automatically extend arena to remember +objects (See `MRB_GC_FIXED_ARENA` and `MRB_GC_ARENA_SIZE` in +doc/guides/mrbconf.md). + +If you create many objects in C functions, memory usage will increase, since +GC never kick in. This memory usage may look like memory leak, but will also +make execution slower as more memory will need to be allocated. + +With the build time configuration, you can limit the maximum size of +arena (e.g., 100). Then if you create many objects, arena overflows, +thus you will get an "arena overflow error". + +To workaround these problems, we have `mrb_gc_arena_save()` and +`mrb_gc_arena_restore()` functions. + +`int mrb_gc_arena_save(mrb)` returns the current position of the stack +top of GC arena, and `void mrb_gc_arena_restore(mrb, idx)` sets the +stack top position to back to given `idx`. + +We can use them like this: + +```c +int arena_idx = mrb_gc_arena_save(mrb); + +// ...create objects... +mrb_gc_arena_restore(mrb, arena_idx); + +``` + +In mruby, C function calls are surrounded by this save/restore, but we +can further optimize memory usage by surrounding save/restore, and can +avoid creating arena overflow bugs. + +Let's take a real example. Here is the source code of `Array#inspect`: + +```c +static mrb_value +inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list) +{ + mrb_int i; + mrb_value s, arystr; + char head[] = { '[' }; + char sep[] = { ',', ' ' }; + char tail[] = { ']' }; + + /* check recursive */ + for(i=0; i<RARRAY_LEN(list); i++) { + if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) { + return mrb_str_new(mrb, "[...]", 5); + } + } + + mrb_ary_push(mrb, list, ary); + + arystr = mrb_str_new_capa(mrb, 64); + mrb_str_cat(mrb, arystr, head, sizeof(head)); + + for(i=0; i<RARRAY_LEN(ary); i++) { + int ai = mrb_gc_arena_save(mrb); + + if (i > 0) { + mrb_str_cat(mrb, arystr, sep, sizeof(sep)); + } + if (mrb_array_p(RARRAY_PTR(ary)[i])) { + s = inspect_ary(mrb, RARRAY_PTR(ary)[i], list); + } + else { + s = mrb_inspect(mrb, RARRAY_PTR(ary)[i]); + } + mrb_str_cat(mrb, arystr, RSTRING_PTR(s), RSTRING_LEN(s)); + mrb_gc_arena_restore(mrb, ai); + } + + mrb_str_cat(mrb, arystr, tail, sizeof(tail)); + mrb_ary_pop(mrb, list); + + return arystr; +} +``` + +This is a real example, so a little bit complicated, but bear with me. +The essence of `Array#inspect` is that after stringifying each element +of array using `inspect` method, we join them together so that we can +get `inspect` representation of the entire array. + +After the `inspect` representation is created, we no longer require the +individual string representation. This means that we don't have to register +these temporal objects into GC arena. + +Therefore, in order to keep the arena size small; the `ary_inspect()` function +will do the following: + +* save the position of the stack top using `mrb_gc_arena_save()`. +* get `inspect` representation of each element. +* append it to the constructing entire `inspect` representation of array. +* restore stack top position using `mrb_gc_arena_restore()`. + +Please note that the final `inspect` representation of entire array +was created before the call of `mrb_gc_arena_restore()`. Otherwise, +required temporal object may be deleted by GC. + +We may have a usecase where after creating many temporal objects, we'd +like to keep some of them. In this case, we cannot use the same idea +in `ary_inspect()` like appending objects to existing one. +Instead, after `mrb_gc_arena_restore()`, we must re-register the objects we +want to keep in the arena using `mrb_gc_protect(mrb, obj)`. +Use `mrb_gc_protect()` with caution because it could also lead to an "arena +overflow error". + +We must also mention that when `mrb_funcall` is called in top level, the return +value is also registered to GC arena, so repeated use of `mrb_funcall` may +eventually lead to an "arena overflow error". + +Use `mrb_gc_arena_save()` and `mrb_gc_arena_restore()` or possible use of +`mrb_gc_protect()` to workaround this. diff --git a/web/server/h2o/libh2o/deps/mruby/doc/guides/mrbconf.md b/web/server/h2o/libh2o/deps/mruby/doc/guides/mrbconf.md new file mode 100644 index 000000000..f957f8ce2 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/doc/guides/mrbconf.md @@ -0,0 +1,146 @@ +# mruby configuration macros. + +## How to use these macros. +You can use mrbconfs with following ways: +* Write them in `mrbconf.h`. + * Using compiler flags is preferred when building a cross binaries or multiple mruby binaries + since it's easier to use different mrbconf per each `MRuby::Build`. + * Most flags can be enabled by just commenting in. +* Pass them as compiler flags. + * Make sure you pass the same flags to all compilers since some mrbconf(e.g., `MRB_GC_FIXED_ARENA`) + changes `struct` layout and cause memory access error when C and other language(e.g., C++) is mixed. + +## stdio setting. +`MRB_DISABLE_STDIO` +* When defined `<stdio.h>` functions won't be used. +* Some features will be disabled when this is enabled: + * `mrb_irep` load/dump from/to file. + * Compiling mruby script from file. + * Printing features in **src/print.c**. + +## Debug macros. +`MRB_ENABLE_DEBUG_HOOK` +* When defined code fetch hook and debug OP hook will be enabled. +* When using any of the hook set function pointer `code_fetch_hook` and/or `debug_op_hook` of `mrb_state`. +* Fetch hook will be called before any OP. +* Debug OP hook will be called when dispatching `OP_DEBUG`. + +`MRB_DEBUG` +* When defined `mrb_assert*` macro will be defined with macros from `<assert.h>`. +* Could be enabled via `enable_debug` method of `MRuby::Build`. + +## Stack configuration + +`MRB_STACK_EXTEND_DOUBLING` +* If defined doubles the stack size when extending it. +* Else extends stack with `MRB_STACK_GROWTH`. + +`MRB_STACK_GROWTH` +* Default value is `128`. +* Used in stack extending. +* Ignored when `MRB_STACK_EXTEND_DOUBLING` is defined. + +`MRB_STACK_MAX` +* Default value is `0x40000 - MRB_STACK_GROWTH`. +* Raises `RuntimeError` when stack size exceeds this value. + +## Primitive type configuration. + +`MRB_USE_FLOAT` +* When defined single precision floating point type(C type `float`) is used as `mrb_float`. +* Else double precision floating point type(C type `double`) is used as `mrb_float`. + +`MRB_INT16` +* When defined `int16_t` will be defined as `mrb_int`. +* Conflicts with `MRB_INT64`. + +`MRB_INT64` +* When defined `int64_t` will be defined as `mrb_int`. +* Conflicts with `MRB_INT16`. +* When `MRB_INT16` or `MRB_INT64` isn't defined `int`(most of the times 32-bit integer) +will be defined as `mrb_int`. + +## Garbage collector configuration. + +`MRB_GC_STRESS` +* When defined full GC is emitted per each `RBasic` allocation. +* Mainly used in memory manager debugging. + +`MRB_GC_TURN_OFF_GENERATIONAL` +* When defined turns generational GC by default. + +`MRB_GC_FIXED_ARENA` +* When defined used fixed size GC arena. +* Raises `RuntimeError` when this is defined and GC arena size exceeds `MRB_GC_ARENA_SIZE`. +* Useful tracking unnecessary mruby object allocation. + +`MRB_GC_ARENA_SIZE` +* Default value is `100`. +* Ignored when `MRB_GC_FIXED_ARENA` isn't defined. +* Defines fixed GC arena size. + +`MRB_HEAP_PAGE_SIZE` +* Defines value is `1024`. +* Specifies number of `RBasic` per each heap page. + +## Memory pool configuration. + +`POOL_ALIGNMENT` +* Default value is `4`. +* If you're allocating data types that requires alignment more than default value define the +largest value of required alignment. + +`POOL_PAGE_SIZE` +* Default value is `16000`. +* Specifies page size of pool page. +* Smaller the value is increases memory overhead. + +## State atexit configuration. + +`MRB_FIXED_STATE_ATEXIT_STACK` +* If defined enables fixed size `mrb_state` atexit stack. +* Raises `RuntimeError` when `mrb_state_atexit` call count to same `mrb_state` exceeds +`MRB_FIXED_STATE_ATEXIT_STACK_SIZE`'s value. + +`MRB_FIXED_STATE_ATEXIT_STACK_SIZE` +* Default value is `5`. +* If `MRB_FIXED_STATE_ATEXIT_STACK` isn't defined this macro is ignored. + +## `mrb_value` configuration. + +`MRB_ENDIAN_BIG` +* If defined compiles mruby for big endian machines. +* Used in `MRB_NAN_BOXING`. +* Some mrbgem use this mrbconf. + +`MRB_NAN_BOXING` +* If defined represent `mrb_value` in boxed `double`. +* Conflicts with `MRB_USE_FLOAT`. + +`MRB_WORD_BOXING` +* If defined represent `mrb_value` as a word. +* If defined `Float` will be a mruby object with `RBasic`. + +## Instance variable configuration. +`MRB_IV_SEGMENT_SIZE` +* Default value is `4`. +* Specifies size of each segment in segment list. + +## Other configuration. +`MRB_UTF8_STRING` +* Adds UTF-8 encoding support to character-oriented String instance methods. +* If it isn't defined, they only support the US-ASCII encoding. + +`MRB_FUNCALL_ARGC_MAX` +* Default value is `16`. +* Specifies 4th argument(`argc`) max value of `mrb_funcall`. +* Raises `ArgumentError` when the `argc` argument is bigger then this value `mrb_funcall`. + +`KHASH_DEFAULT_SIZE` +* Default value is `32`. +* Specifies default size of khash table bucket. +* Used in `kh_init_ ## name` function. + +`MRB_STR_BUF_MIN_SIZE` +* Default value is `128`. +* Specifies initial capacity of `RString` created by `mrb_str_buf_new` function.. diff --git a/web/server/h2o/libh2o/deps/mruby/doc/guides/mrbgems.md b/web/server/h2o/libh2o/deps/mruby/doc/guides/mrbgems.md new file mode 100644 index 000000000..258f405b5 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/doc/guides/mrbgems.md @@ -0,0 +1,340 @@ +# mrbgems + +mrbgems is a library manager to integrate C and Ruby extension in an easy and +standardised way into mruby. + +## Usage + +By default mrbgems is currently deactivated. As soon as you add a GEM to your +build configuration (i.e. *build_config.rb*), mrbgems will be activated and the +extension integrated. + +To add a GEM into the *build_config.rb* add the following line for example: +```ruby +conf.gem '/path/to/your/gem/dir' +``` + +You can also use a relative path which would be relative from the mruby root: +```ruby +conf.gem 'examples/mrbgems/ruby_extension_example' +``` + +A remote GIT repository location for a GEM is also supported: +```ruby +conf.gem :git => 'https://github.com/masuidrive/mrbgems-example.git', :branch => 'master' +conf.gem :github => 'masuidrive/mrbgems-example', :branch => 'master' +conf.gem :bitbucket => 'mruby/mrbgems-example', :branch => 'master' +``` + +To use mrbgem from [mgem-list](https://github.com/mruby/mgem-list) use `:mgem` option: +```ruby +conf.gem :mgem => 'mruby-yaml' +conf.gem :mgem => 'yaml' # 'mruby-' prefix could be omitted +``` + +If there is missing dependencies, mrbgem dependencies solver will reference +mrbgem from core or mgem-list. + +To pull all gems from remote GIT repository on build, call ```./minirake -p```, +or ```./minirake --pull-gems```. + +NOTE: `:bitbucket` option supports only git. Hg is unsupported in this version. + +## GemBox + +There are instances when you wish to add a collection of mrbgems into mruby at +once, or be able to substitute mrbgems based on configuration, without having to +add each gem to the *build_config.rb* file. A packaged collection of mrbgems +is called a GemBox. A GemBox is a file that contains a list of mrbgems to load +into mruby, in the same format as if you were adding them to *build_config.rb* +via `config.gem`, but wrapped in an `MRuby::GemBox` object. GemBoxes are +loaded into mruby via `config.gembox 'boxname'`. + +Below we have created a GemBox containing *mruby-time* and *mrbgems-example*: +```ruby +MRuby::GemBox.new do |conf| + conf.gem "#{root}/mrbgems/mruby-time" + conf.gem :github => 'masuidrive/mrbgems-example' +end +``` + +As mentioned, the GemBox uses the same conventions as `MRuby::Build`. The GemBox +must be saved with a *.gembox* extension inside the *mrbgems* directory to to be +picked up by mruby. + +To use this example GemBox, we save it as `custom.gembox` inside the *mrbgems* +directory in mruby, and add the following to our *build_config.rb* file inside +the build block: +```ruby +conf.gembox 'custom' +``` +This will cause the *custom* GemBox to be read in during the build process, +adding *mruby-time* and *mrbgems-example* to the build. + +If you want, you can put GemBox outside of mruby directory. In that case you must +specify an absolute path like below. +```ruby +conf.gembox "#{ENV["HOME"]}/mygemboxes/custom" +``` + +There are two GemBoxes that ship with mruby: [default](../../mrbgems/default.gembox) +and [full-core](../../mrbgems/full-core.gembox). The [default](../../mrbgems/default.gembox) GemBox +contains several core components of mruby, and [full-core](../../mrbgems/full-core.gembox) +contains every gem found in the *mrbgems* directory. + +## GEM Structure + +The maximal GEM structure looks like this: + + +- GEM_NAME <- Name of GEM + | + +- include/ <- Header for Ruby extension (will exported) + | + +- mrblib/ <- Source for Ruby extension + | + +- src/ <- Source for C extension + | + +- test/ <- Test code (Ruby) + | + +- mrbgem.rake <- GEM Specification + | + +- README.md <- Readme for GEM + +The folder *mrblib* contains pure Ruby files to extend mruby. The folder *src* +contains C/C++ files to extend mruby. The folder *include* contains C/C++ header +files. The folder *test* contains C/C++ and pure Ruby files for testing purposes +which will be used by `mrbtest`. *mrbgem.rake* contains the specification +to compile C and Ruby files. *README.md* is a short description of your GEM. + +## Build process + +mrbgems expects a specification file called *mrbgem.rake* inside of your +GEM directory. A typical GEM specification could look like this for example: +```ruby +MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Example mrbgem using C and ruby' +end +``` + +The mrbgems build process will use this specification to compile Object and Ruby +files. The compilation results will be added to *lib/libmruby.a*. This file exposes +the GEM functionality to tools like `mruby` and `mirb`. + +The following properties can be set inside of your `MRuby::Gem::Specification` for +information purpose: + +* `spec.license` or `spec.licenses` (A single license or a list of them under which this GEM is licensed) +* `spec.author` or `spec.authors` (Developer name or a list of them) +* `spec.version` (Current version) +* `spec.description` (Detailed description) +* `spec.summary` + * One line short description of mrbgem. + * Printed in build summary of rake when set. +* `spec.homepage` (Homepage) +* `spec.requirements` (External requirements as information for user) + +The `license` and `author` properties are required in every GEM! + +In case your GEM is depending on other GEMs please use +`spec.add_dependency(gem, *requirements[, default_get_info])` like: +```ruby +MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + + # Add GEM dependency mruby-parser. + # The version must be between 1.0.0 and 1.5.2 . + spec.add_dependency('mruby-parser', '>= 1.0.0', '<= 1.5.2') + + # Use any version of mruby-uv from github. + spec.add_dependency('mruby-uv', '>= 0.0.0', :github => 'mattn/mruby-uv') + + # Use latest mruby-onig-regexp from github. (version requirements can be omitted) + spec.add_dependency('mruby-onig-regexp', :github => 'mattn/mruby-onig-regexp') + + # You can add extra mgems active only on test + spec.add_test_dependency('mruby-process', :github => 'iij/mruby-process') +end +``` + +The version requirements and default gem information are optional. + +Version requirement supports following operators: +* '=': is equal +* '!=': is not equal +* '>': is greater +* '<': is lesser +* '>=': is equal or greater +* '<=': is equal or lesser +* '~>': is equal or greater and is lesser than the next major version + * example 1: '~> 2.2.2' means '>= 2.2.2' and '< 2.3.0' + * example 2: '~> 2.2' means '>= 2.2.0' and '< 3.0.0' + +When more than one version requirements is passed, the dependency must satisfy all of it. + +You can have default gem to use as depedency when it's not defined in *build_config.rb*. +When the last argument of `add_dependency` call is `Hash`, it will be treated as default gem information. +Its format is same as argument of method `MRuby::Build#gem`, expect that it can't be treated as path gem location. + +When a special version of depedency is required, +use `MRuby::Build#gem` in *build_config.rb* to override default gem. + +If you have conflicting GEMs use the following method: +* `spec.add_conflict(gem, *requirements)` + * The `requirements` argument is same as in `add_dependency` method. + +like following code: +```ruby +MRuby::Gem::Specification.new 'some-regexp-binding' do |spec| + spec.license = 'BSD' + spec.author = 'John Doe' + + spec.add_conflict 'mruby-onig-regexp', '> 0.0.0' + spec.add_conflict 'mruby-hs-regexp' + spec.add_conflict 'mruby-pcre-regexp' + spec.add_conflict 'mruby-regexp-pcre' +end +``` + +In case your GEM has more complex build requirements you can use +the following options additionally inside of your GEM specification: + +* `spec.cc.flags` (C compiler flags) +* `spec.cc.defines` (C compiler defines) +* `spec.cc.include_paths` (C compiler include paths) +* `spec.linker.flags` (Linker flags) +* `spec.linker.libraries` (Linker libraries) +* `spec.linker.library_paths` (Linker additional library path) +* `spec.bins` (Generate binary file) +* `spec.rbfiles` (Ruby files to compile) +* `spec.objs` (Object files to compile) +* `spec.test_rbfiles` (Ruby test files for integration into mrbtest) +* `spec.test_objs` (Object test files for integration into mrbtest) +* `spec.test_preload` (Initialization files for mrbtest) + +You also can use `spec.mruby.cc` and `spec.mruby.linker` to add extra global parameters for compiler and linker. + +### include_paths and dependency + +Your GEM can export include paths to another GEMs that depends on your GEM. +By default, `/...absolute path.../{GEM_NAME}/include` will be exported. +So it is recommended not to put GEM's local header files on include/. + +These exports are retroactive. +For example: when B depends to C and A depends to B, A will get include paths exported by C. + +Exported include_paths are automatically appended to GEM local include_paths by Minirake. +You can use `spec.export_include_paths` accessor if you want more complex build. + + +## C Extension + +mruby can be extended with C. This is possible by using the C API to +integrate C libraries into mruby. + +### Preconditions + +mrbgems expects that you have implemented a C method called +`mrb_YOURGEMNAME_gem_init(mrb_state)`. `YOURGEMNAME` will be replaced +by the name of your GEM. If you call your GEM *c_extension_example*, your +initialisation method could look like this: +```C +void +mrb_c_extension_example_gem_init(mrb_state* mrb) { + struct RClass *class_cextension = mrb_define_module(mrb, "CExtension"); + mrb_define_class_method(mrb, class_cextension, "c_method", mrb_c_method, MRB_ARGS_NONE()); +} +``` + +### Finalize + +mrbgems expects that you have implemented a C method called +`mrb_YOURGEMNAME_gem_final(mrb_state)`. `YOURGEMNAME` will be replaced +by the name of your GEM. If you call your GEM *c_extension_example*, your +finalizer method could look like this: + +```C +void +mrb_c_extension_example_gem_final(mrb_state* mrb) { + free(someone); +} +``` + +### Example + + +- c_extension_example/ + | + +- src/ + | | + | +- example.c <- C extension source + | + +- test/ + | | + | +- example.rb <- Test code for C extension + | + +- mrbgem.rake <- GEM specification + | + +- README.md + +## Ruby Extension + +mruby can be extended with pure Ruby. It is possible to override existing +classes or add new ones in this way. Put all Ruby files into the *mrblib* +folder. + + +### Pre-Conditions + +none + +### Example + + +- ruby_extension_example/ + | + +- mrblib/ + | | + | +- example.rb <- Ruby extension source + | + +- test/ + | | + | +- example.rb <- Test code for Ruby extension + | + +- mrbgem.rake <- GEM specification + | + +- README.md + +## C and Ruby Extension + +mruby can be extended with C and Ruby at the same time. It is possible to +override existing classes or add new ones in this way. Put all Ruby files +into the *mrblib* folder and all C files into the *src* folder. + +mruby codes under *mrblib* directory would be executed after gem init C +function is called. Make sure *mruby script* depends on *C code* and +*C code* doesn't depend on *mruby script*. + +### Pre-Conditions + +See C and Ruby example. + +### Example + + +- c_and_ruby_extension_example/ + | + +- mrblib/ + | | + | +- example.rb <- Ruby extension source + | + +- src/ + | | + | +- example.c <- C extension source + | + +- test/ + | | + | +- example.rb <- Test code for C and Ruby extension + | + +- mrbgem.rake <- GEM specification + | + +- README.md diff --git a/web/server/h2o/libh2o/deps/mruby/doc/limitations.md b/web/server/h2o/libh2o/deps/mruby/doc/limitations.md new file mode 100644 index 000000000..db8db9a5c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/doc/limitations.md @@ -0,0 +1,208 @@ +# Limitations and Differences + +The philosophy of mruby is to be a lightweight implementation of +the Ruby ISO standard. These two objectives are partially contradicting. +Ruby is an expressive language with complex implementation details which +are difficult to implement in a lightweight manner. To cope with this, +limitations to the "Ruby Compatibility" are defined. + +This document is collecting these limitations. + +## Integrity + +This document does not contain a complete list of limitations. +Please help to improve it by submitting your findings. + + +## ```1/2``` gives ```0.5``` + +Since mruby does not have ```Bignum```, bigger integers are represented +by ```Float``` numbers. To enhance interoperability between ```Fixnum``` +and ```Float```, mruby provides ```Float#upto``` and other iterating +methods for the ```Float``` class. As a side effect, ```1/2``` gives ```0.5``` +not ```0```. + +## ```Array``` passed to ```puts``` + +Passing an Array to ```puts``` results in different output. + +```ruby +puts [1,2,3] +``` + +#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)] + +``` +1 +2 +3 +``` + +#### mruby [1.3.0 (2017-7-4)] + +``` +[1, 2, 3] +``` + +## ```Kernel.raise``` in rescue clause + +```Kernel.raise``` without arguments does not raise the current exception within +a rescue clause. + +```ruby +begin + 1 / 0 +rescue + raise +end +``` + +#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)] + +```ZeroDivisionError``` is raised. + +#### mruby [1.3.0 (2017-7-4)] + +No exception is raised. + +## Check of infinite recursion + +mruby does not check infinite recursion across C extensions. + +```ruby +def test; eval 'test'; end; test +``` + +#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)] + +```SystemStackError``` is raised. + +#### mruby [1.3.0 (2017-7-4)] + +Segmentation fault. + +## Fiber execution can't cross C function boundary + +mruby's ```Fiber``` is implemented in a similar way to Lua's co-routine. This +results in the consequence that you can't switch context within C functions. +Only exception is ```mrb_fiber_yield``` at return. + +## ```Array``` does not support instance variables + +To reduce memory consumption ```Array``` does not support instance variables. + +```ruby +class Liste < Array + def initialize(str = nil) + @feld = str + end +end + +p Liste.new "foobar" +``` + +#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)] + +``` [] ``` + +#### mruby [1.3.0 (2017-7-4)] + +```ArgumentError``` is raised. + +## Method visibility + +For simplicity reasons no method visibility (public/private/protected) is +supported. + +```ruby +class VisibleTest + + def public_method; end + + private + def private_method; end + +end + +p VisibleTest.new.respond_to?(:private_method, false) +p VisibleTest.new.respond_to?(:private_method, true) +``` + +#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)] + +``` +false +true +``` + +#### mruby [1.3.0 (2017-7-4)] + +``` +true +true +``` + +## defined? + +The ```defined?``` keyword is considered too complex to be fully +implemented. It is recommended to use ```const_defined?``` and +other reflection methods instead. + +```ruby +defined?(Foo) +``` + +#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)] + +``` +nil +``` + +#### mruby [1.3.0 (2017-7-4)] + +```NameError``` is raised. + +## ```alias``` on global variables + +Aliasing a global variable works in CRuby but is not part +of the ISO standard. + +```ruby +alias $a $__a__ +``` + +#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)] + +``` nil ``` + +#### mruby [1.3.0 (2017-7-4)] + +Syntax error + +## Operator modification + +An operator can't be overwritten by the user. + +```ruby +class String + def + + end +end + +'a' + 'b' +``` + +#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)] + +```ArgumentError``` is raised. +The re-defined ```+``` operator does not accept any arguments. + +#### mruby [1.3.0 (2017-7-4)] + +``` 'ab' ``` +Behavior of the operator wasn't changed. + +## ```Kernel.binding``` missing + +```Kernel.binding``` is not implemented as it is not in the +ISO standard. diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/README.md b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/README.md new file mode 100644 index 000000000..0b428b0b6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/README.md @@ -0,0 +1,4 @@ +C and Ruby Extension Example +========= + +This is an example gem which implements a C and Ruby extension. diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/mrbgem.rake new file mode 100644 index 000000000..6b4595b35 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/mrbgem.rake @@ -0,0 +1,23 @@ +MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + + # Add compile flags + # spec.cc.flags << '' + + # Add cflags to all + # spec.mruby.cc.flags << '-g' + + # Add libraries + # spec.linker.libraries << 'external_lib' + + # Default build files + # spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb") + # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } + # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") + # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } + # spec.test_preload = 'test/assert.rb' + + # Values accessible as TEST_ARGS inside test scripts + # spec.test_args = {'tmp_dir' => Dir::tmpdir} +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/mrblib/example.rb b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/mrblib/example.rb new file mode 100644 index 000000000..d3899c301 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/mrblib/example.rb @@ -0,0 +1,5 @@ +module CRubyExtension + def CRubyExtension.ruby_method + puts "A Ruby Extension" + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/src/example.c b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/src/example.c new file mode 100644 index 000000000..7b780d016 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/src/example.c @@ -0,0 +1,20 @@ +#include <mruby.h> +#include <stdio.h> + +static mrb_value +mrb_c_method(mrb_state *mrb, mrb_value self) +{ + puts("A C Extension"); + return self; +} + +void +mrb_c_and_ruby_extension_example_gem_init(mrb_state* mrb) { + struct RClass *class_cextension = mrb_define_module(mrb, "CRubyExtension"); + mrb_define_class_method(mrb, class_cextension, "c_method", mrb_c_method, MRB_ARGS_NONE()); +} + +void +mrb_c_and_ruby_extension_example_gem_final(mrb_state* mrb) { + /* finalizer */ +} diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/test/example.rb b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/test/example.rb new file mode 100644 index 000000000..fffad710f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_and_ruby_extension_example/test/example.rb @@ -0,0 +1,7 @@ +assert('C and Ruby Extension Example 1') do + CRubyExtension.respond_to? :c_method +end + +assert('C and Ruby Extension Example 2') do + CRubyExtension.respond_to? :ruby_method +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/README.md b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/README.md new file mode 100644 index 000000000..3803c2065 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/README.md @@ -0,0 +1,4 @@ +C Extension Example +========= + +This is an example gem which implements a C extension. diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/mrbgem.rake new file mode 100644 index 000000000..6e4c5b165 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/mrbgem.rake @@ -0,0 +1,23 @@ +MRuby::Gem::Specification.new('c_extension_example') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + + # Add compile flags + # spec.cc.flags << '-g' + + # Add cflags to all + # spec.mruby.cc.flags << '-g' + + # Add libraries + # spec.linker.libraries << 'external_lib' + + # Default build files + # spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb") + # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } + # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") + # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } + # spec.test_preload = 'test/assert.rb' + + # Values accessible as TEST_ARGS inside test scripts + # spec.test_args = {'tmp_dir' => Dir::tmpdir} +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/src/example.c b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/src/example.c new file mode 100644 index 000000000..e70ee42f8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/src/example.c @@ -0,0 +1,20 @@ +#include <mruby.h> +#include <stdio.h> + +static mrb_value +mrb_c_method(mrb_state *mrb, mrb_value self) +{ + puts("A C Extension"); + return self; +} + +void +mrb_c_extension_example_gem_init(mrb_state* mrb) { + struct RClass *class_cextension = mrb_define_module(mrb, "CExtension"); + mrb_define_class_method(mrb, class_cextension, "c_method", mrb_c_method, MRB_ARGS_NONE()); +} + +void +mrb_c_extension_example_gem_final(mrb_state* mrb) { + /* finalizer */ +} diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/test/example.c b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/test/example.c new file mode 100644 index 000000000..ab410333d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/test/example.c @@ -0,0 +1,7 @@ +#include <mruby.h> + +void +mrb_c_extension_example_gem_test(mrb_state *mrb) +{ + /* test initializer in C */ +} diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/test/example.rb b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/test/example.rb new file mode 100644 index 000000000..367d18029 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/c_extension_example/test/example.rb @@ -0,0 +1,3 @@ +assert('C Extension Example') do + CExtension.respond_to? :c_method +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/README.md b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/README.md new file mode 100644 index 000000000..906a0d8f2 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/README.md @@ -0,0 +1,4 @@ +Pure Ruby Extension Example +========= + +This is an example gem which implements a pure Ruby extension. diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/mrbgem.rake new file mode 100644 index 000000000..6e5a5b729 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/mrbgem.rake @@ -0,0 +1,25 @@ +MRuby::Gem::Specification.new('ruby_extension_example') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + + # Add compile flags + # spec.cc.flags << '' + + # Add cflags to all + # spec.mruby.cc.flags << '-g' + + # Add libraries + # spec.linker.libraries << 'external_lib' + + spec.add_dependency('mruby-print', :core => 'mruby-print') + + # Default build files + # spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb") + # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } + # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") + # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } + # spec.test_preload = 'test/assert.rb' + + # Values accessible as TEST_ARGS inside test scripts + # spec.test_args = {'tmp_dir' => Dir::tmpdir} +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/mrblib/example.rb b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/mrblib/example.rb new file mode 100644 index 000000000..b07a2b580 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/mrblib/example.rb @@ -0,0 +1,5 @@ +class RubyExtension + def RubyExtension.ruby_method + puts "A Ruby Extension" + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/test/example.rb b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/test/example.rb new file mode 100644 index 000000000..0c1b63469 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/mrbgems/ruby_extension_example/test/example.rb @@ -0,0 +1,3 @@ +assert('Ruby Extension Example') do + RubyExtension.respond_to? :ruby_method +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_ArduinoDue.rb b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_ArduinoDue.rb new file mode 100644 index 000000000..527aaa4f6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_ArduinoDue.rb @@ -0,0 +1,90 @@ +MRuby::Build.new do |conf| + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' + +end + +# Cross Compiling configuration for Arduino Due +# http://arduino.cc/en/Main/ArduinoBoardDue +# +# Requires Arduino IDE >= 1.5 +MRuby::CrossBuild.new("ArduinoDue") do |conf| + toolchain :gcc + + # Mac OS X, Arduino IDE <= 1.5.6 + # ARDUINO_PATH = '/Applications/Arduino.app/Contents/Resources/Java' + # Mac OS X, Arduino IDE >= 1.5.7 + # ARDUINO_PATH = '/Applications/Arduino.app/Contents/Java' + # GNU Linux + ARDUINO_PATH = '/opt/arduino' + # Arduino IDE <= 1.5.6 + BIN_PATH = "#{ARDUINO_PATH}/hardware/tools/g++_arm_none_eabi/bin" + # Arduino IDE >= 1.5.7 + # BIN_PATH = "#{ARDUINO_PATH}/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin" + SAM_PATH = "#{ARDUINO_PATH}/hardware/arduino/sam" + TARGET_PATH = "#{SAM_PATH}/variants/arduino_due_x" + + conf.cc do |cc| + cc.command = "#{BIN_PATH}/arm-none-eabi-gcc" + cc.include_paths << ["#{SAM_PATH}/system/libsam", "#{SAM_PATH}/system/CMSIS/CMSIS/Include/", + "#{SAM_PATH}/system/CMSIS/Device/ATMEL/", + "#{SAM_PATH}/cores/arduino", "#{SAM_PATH}/libraries","#{TARGET_PATH}"] + cc.flags = %w(-g -Os -w -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 + -Dprintf=iprintf -mcpu=cortex-m3 -DF_CPU=84000000L -DARDUINO=156 -DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM + -D__SAM3X8E__ -mthumb -DUSB_PID=0x003e -DUSB_VID=0x2341 -DUSBCON -DUSB_MANUFACTURER="Unknown" -DUSB_PRODUCT="Arduino Due") + cc.compile_options = "%{flags} -o %{outfile} -c %{infile}" + + #configuration for low memory environment + cc.defines << %w(MRB_HEAP_PAGE_SIZE=64) + cc.defines << %w(KHASH_DEFAULT_SIZE=8) + cc.defines << %w(MRB_STR_BUF_MIN_SIZE=20) + cc.defines << %w(MRB_GC_STRESS) + #cc.defines << %w(MRB_DISABLE_STDIO) #if you dont need stdio. + #cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval + end + + conf.cxx do |cxx| + cxx.command = conf.cc.command.dup + cxx.include_paths = conf.cc.include_paths.dup + cxx.flags = conf.cc.flags.dup + cxx.flags << %w(-fno-rtti -fno-exceptions) + cxx.defines = conf.cc.defines.dup + cxx.compile_options = conf.cc.compile_options.dup + end + + conf.archiver do |archiver| + archiver.command = "#{BIN_PATH}/arm-none-eabi-ar" + archiver.archive_options = 'rcs %{outfile} %{objs}' + end + + #no executables + conf.bins = [] + + #do not build executable test + conf.build_mrbtest_lib_only + + #disable C++ exception + conf.disable_cxx_exception + + #gems from core + conf.gem :core => "mruby-print" + conf.gem :core => "mruby-math" + conf.gem :core => "mruby-enum-ext" + + #light-weight regular expression + conf.gem :github => "masamitsu-murase/mruby-hs-regexp", :branch => "master" + + #Arduino API + #conf.gem :github =>"kyab/mruby-arduino", :branch => "master" + +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_IntelEdison.rb b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_IntelEdison.rb new file mode 100644 index 000000000..8fa3aa0c0 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_IntelEdison.rb @@ -0,0 +1,69 @@ +# Cross-compiling setup for Intel Edison (poky linux) platform +# Get SDK from here: https://software.intel.com/en-us/iot/hardware/edison/downloads +# REMEMBER to check and update the SDK root in the constant POKY_EDISON_PATH + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + conf.cc.defines = %w(ENABLE_READLINE) + conf.gembox 'default' + + #lightweight regular expression + conf.gem :github => "pbosetti/mruby-hs-regexp", :branch => "master" + +end + +# Define cross build settings +MRuby::CrossBuild.new('core2-32-poky-linux') do |conf| + toolchain :gcc + + # Mac OS X + # + POKY_EDISON_PATH = '/opt/poky-edison/1.7.2' + + POKY_EDISON_SYSROOT = "#{POKY_EDISON_PATH}/sysroots/core2-32-poky-linux" + POKY_EDISON_X86_PATH = "#{POKY_EDISON_PATH}/sysroots/i386-pokysdk-darwin" + POKY_EDISON_BIN_PATH = "#{POKY_EDISON_X86_PATH}/usr/bin/i586-poky-linux" + + + conf.cc do |cc| + cc.command = "#{POKY_EDISON_BIN_PATH}/i586-poky-linux-gcc" + cc.include_paths << ["#{POKY_EDISON_SYSROOT}/usr/include", "#{POKY_EDISON_X86_PATH}/usr/include"] + cc.flags = %w(-m32 -march=core2 -mtune=core2 -msse3 -mfpmath=sse -mstackrealign -fno-omit-frame-pointer) + cc.flags << %w(-O2 -pipe -g -feliminate-unused-debug-types) + cc.flags << "--sysroot=#{POKY_EDISON_SYSROOT}" + cc.compile_options = "%{flags} -o %{outfile} -c %{infile}" + cc.defines = %w(ENABLE_READLINE) + end + + conf.cxx do |cxx| + cxx.command = "#{POKY_EDISON_BIN_PATH}/i586-poky-linux-g++" + cxx.include_paths = conf.cc.include_paths.dup + cxx.include_paths << ["#{POKY_EDISON_SYSROOT}/usr/include/c++/4.9.1"] + cxx.flags = conf.cc.flags.dup + cxx.defines = conf.cc.defines.dup + cxx.compile_options = conf.cc.compile_options.dup + end + + conf.archiver do |archiver| + archiver.command = "#{POKY_EDISON_BIN_PATH}/i586-poky-linux-ar" + archiver.archive_options = 'rcs %{outfile} %{objs}' + end + + conf.linker do |linker| + linker.command = "#{POKY_EDISON_BIN_PATH}/i586-poky-linux-g++" + linker.flags = %w(-m32 -march=i586) + linker.flags << "--sysroot=#{POKY_EDISON_SYSROOT}" + linker.flags << %w(-O1) + linker.libraries = %w(m pthread) + end + + #do not build executable test + conf.build_mrbtest_lib_only + + conf.gembox 'default' + + #lightweight regular expression + conf.gem :github => "pbosetti/mruby-hs-regexp", :branch => "master" + +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_IntelGalileo.rb b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_IntelGalileo.rb new file mode 100644 index 000000000..42f800d9f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_IntelGalileo.rb @@ -0,0 +1,106 @@ +MRuby::Build.new do |conf| + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' + +end + + +# Cross Compiling configuration for Intel Galileo on Arduino environment +# http://arduino.cc/en/ArduinoCertified/IntelGalileo +# +# Requires Arduino IDE for Intel Galileo +MRuby::CrossBuild.new("Galileo") do |conf| + toolchain :gcc + + # Mac OS X + # Assume you renamed Arduino.app to Arduino_Galileo.app + GALILEO_ARDUINO_PATH = '/Applications/Arduino_Galileo.app/Contents/Resources/Java' + # GNU Linux + #ARDUINO_GALILEO_PATH = '/opt/arduino' + + GALILEO_BIN_PATH = "#{GALILEO_ARDUINO_PATH}/hardware/tools/x86/i386-pokysdk-darwin/usr/bin/i586-poky-linux-uclibc" + GALILEO_SYSROOT = "#{GALILEO_ARDUINO_PATH}/hardware/tools/x86/i586-poky-linux-uclibc" + GALILEO_X86_PATH = "#{GALILEO_ARDUINO_PATH}/hardware/arduino/x86" + + + conf.cc do |cc| + cc.command = "#{GALILEO_BIN_PATH}/i586-poky-linux-uclibc-gcc" + cc.include_paths << ["#{GALILEO_X86_PATH}/cores/arduino", "#{GALILEO_X86_PATH}/variants/galileo_fab_d"] + cc.flags = %w(-m32 -march=i586 -c -g -Os -w + -ffunction-sections -fdata-sections -MMD -DARDUINO=153) + cc.flags << "--sysroot=#{GALILEO_SYSROOT}" + cc.compile_options = "%{flags} -o %{outfile} -c %{infile}" + end + + conf.cxx do |cxx| + cxx.command = "#{GALILEO_BIN_PATH}/i586-poky-linux-uclibc-g++" + cxx.include_paths = conf.cc.include_paths.dup + cxx.include_paths << "#{GALILEO_ARDUINO_PATH}/hardware/tools/x86/i586-poky-linux-uclibc/usr/include/c++" + cxx.include_paths << "#{GALILEO_ARDUINO_PATH}/hardware/tools/x86/i586-poky-linux-uclibc/usr/include/c++/i586-poky-linux-uclibc" + cxx.flags = conf.cc.flags.dup + cxx.defines = conf.cc.defines.dup + cxx.compile_options = conf.cc.compile_options.dup + end + + conf.archiver do |archiver| + archiver.command = "#{GALILEO_BIN_PATH}/i586-poky-linux-uclibc-ar" + archiver.archive_options = 'rcs %{outfile} %{objs}' + end + + conf.linker do |linker| + linker.command = "#{GALILEO_BIN_PATH}/i586-poky-linux-uclibc-g++" + linker.flags = %w(-m32 -march=i586) + linker.flags << "--sysroot=#{GALILEO_SYSROOT}" + linker.flags << %w(-Os -Wl,--gc-sections) + linker.libraries = %w(m pthread) + end + + #no executables + conf.bins = [] + + #do not build executable test + conf.build_mrbtest_lib_only + + #official mrbgems + conf.gem :core => "mruby-sprintf" + conf.gem :core => "mruby-print" + conf.gem :core => "mruby-math" + conf.gem :core => "mruby-time" + conf.gem :core => "mruby-struct" + conf.gem :core => "mruby-enum-ext" + conf.gem :core => "mruby-string-ext" + conf.gem :core => "mruby-numeric-ext" + conf.gem :core => "mruby-array-ext" + conf.gem :core => "mruby-hash-ext" + conf.gem :core => "mruby-range-ext" + conf.gem :core => "mruby-proc-ext" + conf.gem :core => "mruby-symbol-ext" + conf.gem :core => "mruby-random" + conf.gem :core => "mruby-object-ext" + conf.gem :core => "mruby-objectspace" + conf.gem :core => "mruby-fiber" + conf.gem :core => "mruby-toplevel-ext" + + #lightweigh regular expression + conf.gem :github => "masamitsu-murase/mruby-hs-regexp", :branch => "master" + + #Arduino API + #conf.gem :github =>"kyab/mruby-arduino", :branch => "master" do |g| + # g.cxx.include_paths << "#{GALILEO_X86_PATH}/libraries/Wire" + # g.cxx.include_paths << "#{GALILEO_X86_PATH}/libraries/Servo" + + #enable unsupported Servo class + # g.cxx.defines << "MRUBY_ARDUINO_GALILEO_ENABLE_SERVO" + #end + +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_RX630.rb b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_RX630.rb new file mode 100644 index 000000000..fd17eae99 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_RX630.rb @@ -0,0 +1,81 @@ +MRuby::Build.new do |conf| + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' + +end + +# Cross Compiling configuration for RX630 +# http://gadget.renesas.com/ +# +# Requires gnurx_v14.03 +MRuby::CrossBuild.new("RX630") do |conf| + toolchain :gcc + + # Linux + BIN_PATH = "/usr/share/gnurx_v14.03_elf-1/bin" + + conf.cc do |cc| + cc.command = "#{BIN_PATH}/rx-elf-gcc" + cc.flags = "-Wall -g -O2 -flto -mcpu=rx600 -m64bit-doubles" + cc.compile_options = "%{flags} -o %{outfile} -c %{infile}" + + #configuration for low memory environment + cc.defines << %w(MRB_USE_FLOAT) + cc.defines << %w(MRB_HEAP_PAGE_SIZE=64) + cc.defines << %w(KHASH_DEFAULT_SIZE=8) + cc.defines << %w(MRB_STR_BUF_MIN_SIZE=20) + cc.defines << %w(MRB_GC_STRESS) + cc.defines << %w(MRB_DISABLE_STDIO) #if you dont need stdio. + #cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval + end + + conf.cxx do |cxx| + cxx.command = conf.cc.command.dup + cxx.include_paths = conf.cc.include_paths.dup + cxx.flags = conf.cc.flags.dup + cxx.defines = conf.cc.defines.dup + cxx.compile_options = conf.cc.compile_options.dup + end + + conf.linker do |linker| + linker.command="#{BIN_PATH}/rx-elf-ld" + end + + conf.archiver do |archiver| + archiver.command = "#{BIN_PATH}/rx-elf-ar" + archiver.archive_options = 'rcs %{outfile} %{objs}' + end + + #no executables + conf.bins = [] + + #do not build executable test + conf.build_mrbtest_lib_only + + #disable C++ exception + conf.disable_cxx_exception + + #gems from core + conf.gem :core => "mruby-sprintf" + conf.gem :core => "mruby-print" + conf.gem :core => "mruby-math" + conf.gem :core => "mruby-enum-ext" + conf.gem :core => "mruby-numeric-ext" + + #light-weight regular expression + #conf.gem :github => "masamitsu-murase/mruby-hs-regexp", :branch => "master" + + #Arduino API + #conf.gem :github =>"kyab/mruby-arduino", :branch => "master" + +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_android_arm64-v8a.rb b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_android_arm64-v8a.rb new file mode 100644 index 000000000..6188c13ec --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_android_arm64-v8a.rb @@ -0,0 +1,26 @@ +MRuby::Build.new do |conf| + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' +end + +# Requires Android NDK r13 or later. +MRuby::CrossBuild.new('android-arm64-v8a') do |conf| + params = { + :arch => 'arm64-v8a', + :platform => 'android-24', + :toolchain => :clang, + } + toolchain :android, params + + conf.gembox 'default' +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_android_armeabi.rb b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_android_armeabi.rb new file mode 100644 index 000000000..b7eb33a92 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_android_armeabi.rb @@ -0,0 +1,26 @@ +MRuby::Build.new do |conf| + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' +end + +# Requires Android NDK r13 or later. +MRuby::CrossBuild.new('android-armeabi') do |conf| + params = { + :arch => 'armeabi', + :platform => 'android-24', + :toolchain => :clang, + } + toolchain :android, params + + conf.gembox 'default' +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_android_armeabi_v7a_neon_hard.rb b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_android_armeabi_v7a_neon_hard.rb new file mode 100644 index 000000000..3788bba7f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_android_armeabi_v7a_neon_hard.rb @@ -0,0 +1,28 @@ +MRuby::Build.new do |conf| + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' +end + +# Requires Android NDK r13 or later. +MRuby::CrossBuild.new('android-armeabi-v7a-neon-hard') do |conf| + params = { + :arch => 'armeabi-v7a', + :mfpu => 'neon', + :mfloat_abi => 'hard', + :platform => 'android-24', + :toolchain => :clang, + } + toolchain :android, params + + conf.gembox 'default' +end diff --git a/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_chipKITMax32.rb b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_chipKITMax32.rb new file mode 100644 index 000000000..951f71483 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/examples/targets/build_config_chipKITMax32.rb @@ -0,0 +1,86 @@ +MRuby::Build.new do |conf| + + # Gets set by the VS command prompts. + if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + enable_debug + + # include the default GEMs + conf.gembox 'default' + +end + +# Cross Compiling configuration for Digilent chipKIT Max32 +# http://www.digilentinc.com/Products/Detail.cfm?Prod=CHIPKIT-MAX32 +# +# Requires MPIDE (https://github.com/chipKIT32/chipKIT32-MAX) +# +# This configuration is based on @kyab's version +# http://d.hatena.ne.jp/kyab/20130201 +MRuby::CrossBuild.new("chipKITMax32") do |conf| + toolchain :gcc + + # Mac OS X + # MPIDE_PATH = '/Applications/Mpide.app/Contents/Resources/Java' + # GNU Linux + MPIDE_PATH = '/opt/mpide-0023-linux-20120903' + + PIC32_PATH = "#{MPIDE_PATH}/hardware/pic32" + + conf.cc do |cc| + cc.command = "#{PIC32_PATH}/compiler/pic32-tools/bin/pic32-gcc" + cc.include_paths << ["#{PIC32_PATH}/cores/pic32", + "#{PIC32_PATH}/variants/Max32", + "#{PIC32_PATH}/libraries"] + cc.flags = %w(-O2 -mno-smart-io -w -ffunction-sections -fdata-sections -g -mdebugger -Wcast-align + -fno-short-double -mprocessor=32MX795F512L -DF_CPU=80000000L -DARDUINO=23 -D_BOARD_MEGA_ + -DMPIDEVER=0x01000202 -DMPIDE=23) + cc.compile_options = "%{flags} -o %{outfile} -c %{infile}" + + #configuration for low memory environment + cc.defines << %w(MRB_HEAP_PAGE_SIZE=64) + cc.defines << %w(KHASH_DEFAULT_SIZE=8) + cc.defines << %w(MRB_STR_BUF_MIN_SIZE=20) + cc.defines << %w(MRB_GC_STRESS) + #cc.defines << %w(MRB_DISABLE_STDIO) #if you dont need stdio. + #cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval + end + + conf.cxx do |cxx| + cxx.command = conf.cc.command.dup + cxx.include_paths = conf.cc.include_paths.dup + cxx.flags = conf.cc.flags.dup + cxx.defines = conf.cc.defines.dup + cxx.compile_options = conf.cc.compile_options.dup + end + + conf.archiver do |archiver| + archiver.command = "#{PIC32_PATH}/compiler/pic32-tools/bin/pic32-ar" + archiver.archive_options = 'rcs %{outfile} %{objs}' + end + + #no executables + conf.bins = [] + + #do not build test executable + conf.build_mrbtest_lib_only + + #disable C++ exception + conf.disable_cxx_exception + + #gems from core + conf.gem :core => "mruby-print" + conf.gem :core => "mruby-math" + conf.gem :core => "mruby-enum-ext" + + #light-weight regular expression + conf.gem :github => "masamitsu-murase/mruby-hs-regexp", :branch => "master" + + #Arduino API + #conf.gem :github =>"kyab/mruby-arduino", :branch => "master" + +end diff --git a/web/server/h2o/libh2o/deps/mruby/include/mrbconf.h b/web/server/h2o/libh2o/deps/mruby/include/mrbconf.h new file mode 100644 index 000000000..b8d603e1c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mrbconf.h @@ -0,0 +1,130 @@ +/* +** mrbconf.h - mruby core configuration +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBYCONF_H +#define MRUBYCONF_H + +#include <limits.h> +#include <stdint.h> + +/* architecture selection: */ +/* specify -DMRB_32BIT or -DMRB_64BIT to override */ +#if !defined(MRB_32BIT) && !defined(MRB_64BIT) +#if UINT64_MAX == SIZE_MAX +#define MRB_64BIT +#else +#define MRB_32BIT +#endif +#endif + +#if defined(MRB_32BIT) && defined(MRB_64BIT) +#error Cannot build for 32 and 64 bit architecture at the same time +#endif + +/* configuration options: */ +/* add -DMRB_USE_FLOAT to use float instead of double for floating point numbers */ +//#define MRB_USE_FLOAT + +/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT64 */ +//#define MRB_INT16 + +/* add -DMRB_INT64 to use 64bit integer for mrb_int; conflict with MRB_INT16 */ +//#define MRB_INT64 + +/* if no specific integer type is chosen */ +#if !defined(MRB_INT16) && !defined(MRB_INT32) && !defined(MRB_INT64) +# if defined(MRB_64BIT) && !defined(MRB_NAN_BOXING) +/* Use 64bit integers on 64bit architecture (without MRB_NAN_BOXING) */ +# define MRB_INT64 +# else +/* Otherwise use 32bit integers */ +# define MRB_INT32 +# endif +#endif + +/* represent mrb_value in boxed double; conflict with MRB_USE_FLOAT */ +//#define MRB_NAN_BOXING + +/* define on big endian machines; used by MRB_NAN_BOXING */ +//#define MRB_ENDIAN_BIG + +/* represent mrb_value as a word (natural unit of data for the processor) */ +//#define MRB_WORD_BOXING + +/* string class to handle UTF-8 encoding */ +//#define MRB_UTF8_STRING + +/* argv max size in mrb_funcall */ +//#define MRB_FUNCALL_ARGC_MAX 16 + +/* number of object per heap page */ +//#define MRB_HEAP_PAGE_SIZE 1024 + +/* if _etext and _edata available, mruby can reduce memory used by symbols */ +//#define MRB_USE_ETEXT_EDATA + +/* do not use __init_array_start to determine readonly data section; + effective only when MRB_USE_ETEXT_EDATA is defined */ +//#define MRB_NO_INIT_ARRAY_START + +/* turn off generational GC by default */ +//#define MRB_GC_TURN_OFF_GENERATIONAL + +/* default size of khash table bucket */ +//#define KHASH_DEFAULT_SIZE 32 + +/* allocated memory address alignment */ +//#define POOL_ALIGNMENT 4 + +/* page size of memory pool */ +//#define POOL_PAGE_SIZE 16000 + +/* initial minimum size for string buffer */ +//#define MRB_STR_BUF_MIN_SIZE 128 + +/* arena size */ +//#define MRB_GC_ARENA_SIZE 100 + +/* fixed size GC arena */ +//#define MRB_GC_FIXED_ARENA + +/* state atexit stack size */ +//#define MRB_FIXED_STATE_ATEXIT_STACK_SIZE 5 + +/* fixed size state atexit stack */ +//#define MRB_FIXED_STATE_ATEXIT_STACK + +/* -DMRB_DISABLE_XXXX to drop following features */ +//#define MRB_DISABLE_STDIO /* use of stdio */ + +/* -DMRB_ENABLE_XXXX to enable following features */ +//#define MRB_ENABLE_DEBUG_HOOK /* hooks for debugger */ + +/* end of configuration */ + +/* define MRB_DISABLE_XXXX from DISABLE_XXX (for compatibility) */ +#ifdef DISABLE_STDIO +#define MRB_DISABLE_STDIO +#endif + +/* define MRB_ENABLE_XXXX from ENABLE_XXX (for compatibility) */ +#ifdef ENABLE_DEBUG +#define MRB_ENABLE_DEBUG_HOOK +#endif + +#ifndef MRB_DISABLE_STDIO +# include <stdio.h> +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef TRUE +# define TRUE 1 +#endif + +#endif /* MRUBYCONF_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby.h b/web/server/h2o/libh2o/deps/mruby/include/mruby.h new file mode 100644 index 000000000..ced9c104d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby.h @@ -0,0 +1,1257 @@ +/* +** mruby - An embeddable Ruby implementation +** +** Copyright (c) mruby developers 2010-2017 +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] +*/ + +#ifndef MRUBY_H +#define MRUBY_H + +#ifdef __cplusplus +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include <stdint.h> +#include <stddef.h> +#include <limits.h> + +#ifdef __cplusplus +#ifndef SIZE_MAX +#ifdef __SIZE_MAX__ +#define SIZE_MAX __SIZE_MAX__ +#else +#define SIZE_MAX std::numeric_limits<size_t>::max() +#endif +#endif +#endif + +#ifdef MRB_DEBUG +#include <assert.h> +#define mrb_assert(p) assert(p) +#define mrb_assert_int_fit(t1,n,t2,max) assert((n)>=0 && ((sizeof(n)<=sizeof(t2))||(n<=(t1)(max)))) +#else +#define mrb_assert(p) ((void)0) +#define mrb_assert_int_fit(t1,n,t2,max) ((void)0) +#endif + +#if __STDC_VERSION__ >= 201112L +#define mrb_static_assert(exp, str) _Static_assert(exp, str) +#else +#define mrb_static_assert(exp, str) mrb_assert(exp) +#endif + +#include "mrbconf.h" + +#ifndef FLT_EPSILON +#define FLT_EPSILON (1.19209290e-07f) +#endif +#ifndef DBL_EPSILON +#define DBL_EPSILON ((double)2.22044604925031308085e-16L) +#endif +#ifndef LDBL_EPSILON +#define LDBL_EPSILON (1.08420217248550443401e-19L) +#endif + +#ifdef MRB_USE_FLOAT +#define MRB_FLOAT_EPSILON FLT_EPSILON +#else +#define MRB_FLOAT_EPSILON DBL_EPSILON +#endif + +#include "mruby/common.h" +#include <mruby/value.h> +#include <mruby/gc.h> +#include <mruby/version.h> + +/** + * MRuby C API entry point + */ +MRB_BEGIN_DECL + +typedef uint32_t mrb_code; + +/** + * Required arguments signature type. + */ +typedef uint32_t mrb_aspec; + + +struct mrb_irep; +struct mrb_state; + +/** + * Function pointer type of custom allocator used in @see mrb_open_allocf. + * + * The function pointing it must behave similarly as realloc except: + * - If ptr is NULL it must allocate new space. + * - If s is NULL, ptr must be freed. + * + * See @see mrb_default_allocf for the default implementation. + */ +typedef void* (*mrb_allocf) (struct mrb_state *mrb, void*, size_t, void *ud); + +#ifndef MRB_FIXED_STATE_ATEXIT_STACK_SIZE +#define MRB_FIXED_STATE_ATEXIT_STACK_SIZE 5 +#endif + +typedef struct { + mrb_sym mid; + struct RProc *proc; + mrb_value *stackent; + int nregs; + int ridx; + int epos; + struct REnv *env; + mrb_code *pc; /* return address */ + mrb_code *err; /* error position */ + int argc; + int acc; + struct RClass *target_class; +} mrb_callinfo; + +enum mrb_fiber_state { + MRB_FIBER_CREATED = 0, + MRB_FIBER_RUNNING, + MRB_FIBER_RESUMED, + MRB_FIBER_SUSPENDED, + MRB_FIBER_TRANSFERRED, + MRB_FIBER_TERMINATED, +}; + +struct mrb_context { + struct mrb_context *prev; + + mrb_value *stack; /* stack of virtual machine */ + mrb_value *stbase, *stend; + + mrb_callinfo *ci; + mrb_callinfo *cibase, *ciend; + + mrb_code **rescue; /* exception handler stack */ + int rsize; + struct RProc **ensure; /* ensure handler stack */ + int esize, eidx; + + enum mrb_fiber_state status; + mrb_bool vmexec; + struct RFiber *fib; +}; + +#ifdef MRB_METHOD_CACHE_SIZE +# define MRB_METHOD_CACHE +#else +/* default method cache size: 128 */ +/* cache size needs to be power of 2 */ +# define MRB_METHOD_CACHE_SIZE (1<<7) +#endif + +#ifdef MRB_METHOD_CACHE +struct mrb_cache_entry { + struct RClass *c; + mrb_sym mid; + struct RProc *m; +}; +#endif + +struct mrb_jmpbuf; + +typedef void (*mrb_atexit_func)(struct mrb_state*); + +#define MRB_STATE_NO_REGEXP 1 +#define MRB_STATE_REGEXP 2 + +typedef struct mrb_state { + struct mrb_jmpbuf *jmp; + + uint32_t flags; + mrb_allocf allocf; /* memory allocation function */ + void *allocf_ud; /* auxiliary data of allocf */ + + struct mrb_context *c; + struct mrb_context *root_c; + struct iv_tbl *globals; /* global variable table */ + + struct RObject *exc; /* exception */ + + struct RObject *top_self; + struct RClass *object_class; /* Object class */ + struct RClass *class_class; + struct RClass *module_class; + struct RClass *proc_class; + struct RClass *string_class; + struct RClass *array_class; + struct RClass *hash_class; + struct RClass *range_class; + + struct RClass *float_class; + struct RClass *fixnum_class; + struct RClass *true_class; + struct RClass *false_class; + struct RClass *nil_class; + struct RClass *symbol_class; + struct RClass *kernel_module; + + struct alloca_header *mems; + mrb_gc gc; + +#ifdef MRB_METHOD_CACHE + struct mrb_cache_entry cache[MRB_METHOD_CACHE_SIZE]; +#endif + + mrb_sym symidx; + struct kh_n2s *name2sym; /* symbol hash */ + struct symbol_name *symtbl; /* symbol table */ + size_t symcapa; + +#ifdef MRB_ENABLE_DEBUG_HOOK + void (*code_fetch_hook)(struct mrb_state* mrb, struct mrb_irep *irep, mrb_code *pc, mrb_value *regs); + void (*debug_op_hook)(struct mrb_state* mrb, struct mrb_irep *irep, mrb_code *pc, mrb_value *regs); +#endif + +#ifdef MRB_BYTECODE_DECODE_OPTION + mrb_code (*bytecode_decoder)(struct mrb_state* mrb, mrb_code code); +#endif + + struct RClass *eException_class; + struct RClass *eStandardError_class; + struct RObject *nomem_err; /* pre-allocated NoMemoryError */ + struct RObject *stack_err; /* pre-allocated SysStackError */ +#ifdef MRB_GC_FIXED_ARENA + struct RObject *arena_err; /* pre-allocated arena overfow error */ +#endif + + void *ud; /* auxiliary data */ + +#ifdef MRB_FIXED_STATE_ATEXIT_STACK + mrb_atexit_func atexit_stack[MRB_FIXED_STATE_ATEXIT_STACK_SIZE]; +#else + mrb_atexit_func *atexit_stack; +#endif + mrb_int atexit_stack_len; +} mrb_state; + + +typedef mrb_value (*mrb_func_t)(mrb_state *mrb, mrb_value); + +/** + * Defines a new class. + * + * If you're creating a gem it may look something like this: + * + * !!!c + * void mrb_example_gem_init(mrb_state* mrb) { + * struct RClass *example_class; + * example_class = mrb_define_class(mrb, "Example_Class", mrb->object_class); + * } + * + * void mrb_example_gem_final(mrb_state* mrb) { + * //free(TheAnimals); + * } + * + * @param [mrb_state *] mrb The current mruby state. + * @param [const char *] name The name of the defined class. + * @param [struct RClass *] super The new class parent. + * @return [struct RClass *] Reference to the newly defined class. + * @see mrb_define_class_under + */ +MRB_API struct RClass *mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super); + +/** + * Defines a new module. + * + * @param [mrb_state *] mrb_state* The current mruby state. + * @param [const char *] char* The name of the module. + * @return [struct RClass *] Reference to the newly defined module. + */ +MRB_API struct RClass *mrb_define_module(mrb_state *, const char*); +MRB_API mrb_value mrb_singleton_class(mrb_state*, mrb_value); + +/** + * Include a module in another class or module. + * Equivalent to: + * + * module B + * include A + * end + * @param [mrb_state *] mrb_state* The current mruby state. + * @param [struct RClass *] RClass* A reference to module or a class. + * @param [struct RClass *] RClass* A reference to the module to be included. + */ +MRB_API void mrb_include_module(mrb_state*, struct RClass*, struct RClass*); + +/** + * Prepends a module in another class or module. + * + * Equivalent to: + * module B + * prepend A + * end + * @param [mrb_state *] mrb_state* The current mruby state. + * @param [struct RClass *] RClass* A reference to module or a class. + * @param [struct RClass *] RClass* A reference to the module to be prepended. + */ +MRB_API void mrb_prepend_module(mrb_state*, struct RClass*, struct RClass*); + +/** + * Defines a global function in ruby. + * + * If you're creating a gem it may look something like this + * + * Example: + * + * !!!c + * mrb_value example_method(mrb_state* mrb, mrb_value self) + * { + * puts("Executing example command!"); + * return self; + * } + * + * void mrb_example_gem_init(mrb_state* mrb) + * { + * mrb_define_method(mrb, mrb->kernel_module, "example_method", example_method, MRB_ARGS_NONE()); + * } + * + * @param [mrb_state *] mrb The MRuby state reference. + * @param [struct RClass *] cla The class pointer where the method will be defined. + * @param [const char *] name The name of the method being defined. + * @param [mrb_func_t] func The function pointer to the method definition. + * @param [mrb_aspec] aspec The method parameters declaration. + */ +MRB_API void mrb_define_method(mrb_state *mrb, struct RClass *cla, const char *name, mrb_func_t func, mrb_aspec aspec); + +/** + * Defines a class method. + * + * Example: + * + * # Ruby style + * class Foo + * def Foo.bar + * end + * end + * // C style + * mrb_value bar_method(mrb_state* mrb, mrb_value self){ + * return mrb_nil_value(); + * } + * void mrb_example_gem_init(mrb_state* mrb){ + * struct RClass *foo; + * foo = mrb_define_class(mrb, "Foo", mrb->object_class); + * mrb_define_class_method(mrb, foo, "bar", bar_method, MRB_ARGS_NONE()); + * } + * @param [mrb_state *] mrb_state* The MRuby state reference. + * @param [struct RClass *] RClass* The class where the class method will be defined. + * @param [const char *] char* The name of the class method being defined. + * @param [mrb_func_t] mrb_func_t The function pointer to the class method definition. + * @param [mrb_aspec] mrb_aspec The method parameters declaration. + */ +MRB_API void mrb_define_class_method(mrb_state *, struct RClass *, const char *, mrb_func_t, mrb_aspec); +MRB_API void mrb_define_singleton_method(mrb_state*, struct RObject*, const char*, mrb_func_t, mrb_aspec); + +/** + * Defines a module fuction. + * + * Example: + * + * # Ruby style + * module Foo + * def Foo.bar + * end + * end + * // C style + * mrb_value bar_method(mrb_state* mrb, mrb_value self){ + * return mrb_nil_value(); + * } + * void mrb_example_gem_init(mrb_state* mrb){ + * struct RClass *foo; + * foo = mrb_define_module(mrb, "Foo"); + * mrb_define_module_function(mrb, foo, "bar", bar_method, MRB_ARGS_NONE()); + * } + * @param [mrb_state *] mrb_state* The MRuby state reference. + * @param [struct RClass *] RClass* The module where the module function will be defined. + * @param [const char *] char* The name of the module function being defined. + * @param [mrb_func_t] mrb_func_t The function pointer to the module function definition. + * @param [mrb_aspec] mrb_aspec The method parameters declaration. + */ +MRB_API void mrb_define_module_function(mrb_state*, struct RClass*, const char*, mrb_func_t, mrb_aspec); + +/** + * Defines a constant. + * + * Example: + * + * # Ruby style + * class ExampleClass + * AGE = 22 + * end + * // C style + * #include <stdio.h> + * #include <mruby.h> + * + * void + * mrb_example_gem_init(mrb_state* mrb){ + * mrb_define_const(mrb, mrb->kernel_module, "AGE", mrb_fixnum_value(22)); + * } + * + * mrb_value + * mrb_example_gem_final(mrb_state* mrb){ + * } + * @param [mrb_state *] mrb_state* The MRuby state reference. + * @param [struct RClass *] RClass* A class or module the constant is defined in. + * @param [const char *] name The name of the constant being defined. + * @param [mrb_value] mrb_value The value for the constant. + */ +MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_value); + +/** + * Undefines a method. + * + * Example: + * + * # Ruby style + * + * class ExampleClassA + * def example_method + * "example" + * end + * end + * ExampleClassA.new.example_method # => example + * + * class ExampleClassB < ExampleClassA + * undef_method :example_method + * end + * + * ExampleClassB.new.example_method # => undefined method 'example_method' for ExampleClassB (NoMethodError) + * + * // C style + * #include <stdio.h> + * #include <mruby.h> + * + * mrb_value + * mrb_example_method(mrb_state *mrb){ + * return mrb_str_new_lit(mrb, "example"); + * } + * + * void + * mrb_example_gem_init(mrb_state* mrb){ + * struct RClass *example_class_a; + * struct RClass *example_class_b; + * struct RClass *example_class_c; + * + * example_class_a = mrb_define_class(mrb, "ExampleClassA", mrb->object_class); + * mrb_define_method(mrb, example_class_a, "example_method", mrb_example_method, MRB_ARGS_NONE()); + * example_class_b = mrb_define_class(mrb, "ExampleClassB", example_class_a); + * example_class_c = mrb_define_class(mrb, "ExampleClassC", example_class_b); + * mrb_undef_method(mrb, example_class_c, "example_method"); + * } + * + * mrb_example_gem_final(mrb_state* mrb){ + * } + * @param [mrb_state*] mrb_state* The mruby state reference. + * @param [struct RClass*] RClass* A class the method will be undefined from. + * @param [const char*] constchar* The name of the method to be undefined. + */ +MRB_API void mrb_undef_method(mrb_state*, struct RClass*, const char*); + +/** + * Undefine a class method. + * Example: + * + * # Ruby style + * class ExampleClass + * def self.example_method + * "example" + * end + * end + * + * ExampleClass.example_method + * + * // C style + * #include <stdio.h> + * #include <mruby.h> + * + * mrb_value + * mrb_example_method(mrb_state *mrb){ + * return mrb_str_new_lit(mrb, "example"); + * } + * + * void + * mrb_example_gem_init(mrb_state* mrb){ + * struct RClass *example_class; + * example_class = mrb_define_class(mrb, "ExampleClass", mrb->object_class); + * mrb_define_class_method(mrb, example_class, "example_method", mrb_example_method, MRB_ARGS_NONE()); + * mrb_undef_class_method(mrb, example_class, "example_method"); + * } + * + * void + * mrb_example_gem_final(mrb_state* mrb){ + * } + * @param [mrb_state*] mrb_state* The mruby state reference. + * @param [RClass*] RClass* A class the class method will be undefined from. + * @param [constchar*] constchar* The name of the class method to be undefined. + */ +MRB_API void mrb_undef_class_method(mrb_state*, struct RClass*, const char*); + +/** + * Initialize a new object instace of c class. + * + * Example: + * + * # Ruby style + * class ExampleClass + * end + * + * p ExampleClass # => #<ExampleClass:0x9958588> + * // C style + * #include <stdio.h> + * #include <mruby.h> + * + * void + * mrb_example_gem_init(mrb_state* mrb) { + * struct RClass *example_class; + * mrb_value obj; + * example_class = mrb_define_class(mrb, "ExampleClass", mrb->object_class); # => class ExampleClass; end + * obj = mrb_obj_new(mrb, example_class, 0, NULL); # => ExampleClass.new + * mrb_p(mrb, obj); // => Kernel#p + * } + * @param [mrb_state*] mrb The current mruby state. + * @param [RClass*] c Reference to the class of the new object. + * @param [mrb_int] argc Number of arguments in argv + * @param [const mrb_value *] argv Array of mrb_value to initialize the object + * @return [mrb_value] The newly initialized object + */ +MRB_API mrb_value mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv); + +/** @see mrb_obj_new */ +MRB_INLINE mrb_value mrb_class_new_instance(mrb_state *mrb, mrb_int argc, const mrb_value *argv, struct RClass *c) +{ + return mrb_obj_new(mrb,c,argc,argv); +} + +MRB_API mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); + +/** + * Creates a new instance of Class, Class. + * + * Example: + * + * void + * mrb_example_gem_init(mrb_state* mrb) { + * struct RClass *example_class; + * + * mrb_value obj; + * example_class = mrb_class_new(mrb, mrb->object_class); + * obj = mrb_obj_new(mrb, example_class, 0, NULL); // => #<#<Class:0x9a945b8>:0x9a94588> + * mrb_p(mrb, obj); // => Kernel#p + * } + * + * @param [mrb_state*] mrb The current mruby state. + * @param [struct RClass *] super The super class or parent. + * @return [struct RClass *] Reference to the new class. + */ +MRB_API struct RClass * mrb_class_new(mrb_state *mrb, struct RClass *super); + +/** + * Creates a new module, Module. + * + * Example: + * void + * mrb_example_gem_init(mrb_state* mrb) { + * struct RClass *example_module; + * + * example_module = mrb_module_new(mrb); + * } + * + * @param [mrb_state*] mrb The current mruby state. + * @return [struct RClass *] Reference to the new module. + */ +MRB_API struct RClass * mrb_module_new(mrb_state *mrb); + +/** + * Returns an mrb_bool. True if class was defined, and false if the class was not defined. + * + * Example: + * void + * mrb_example_gem_init(mrb_state* mrb) { + * struct RClass *example_class; + * mrb_bool cd; + * + * example_class = mrb_define_class(mrb, "ExampleClass", mrb->object_class); + * cd = mrb_class_defined(mrb, "ExampleClass"); + * + * // If mrb_class_defined returns 1 then puts "True" + * // If mrb_class_defined returns 0 then puts "False" + * if (cd == 1){ + * puts("True"); + * } + * else { + * puts("False"); + * } + * } + * + * @param [mrb_state*] mrb The current mruby state. + * @param [const char *] name A string representing the name of the class. + * @return [mrb_bool] A boolean value. + */ +MRB_API mrb_bool mrb_class_defined(mrb_state *mrb, const char *name); + +/** + * Gets a class. + * @param [mrb_state*] mrb The current mruby state. + * @param [const char *] name The name of the class. + * @return [struct RClass *] A reference to the class. +*/ +MRB_API struct RClass * mrb_class_get(mrb_state *mrb, const char *name); + +/** + * Gets a exception class. + * @param [mrb_state*] mrb The current mruby state. + * @param [const char *] name The name of the class. + * @return [struct RClass *] A reference to the class. +*/ +MRB_API struct RClass * mrb_exc_get(mrb_state *mrb, const char *name); + +/** + * Returns an mrb_bool. True if inner class was defined, and false if the inner class was not defined. + * + * Example: + * void + * mrb_example_gem_init(mrb_state* mrb) { + * struct RClass *example_outer, *example_inner; + * mrb_bool cd; + * + * example_outer = mrb_define_module(mrb, "ExampleOuter"); + * + * example_inner = mrb_define_class_under(mrb, example_outer, "ExampleInner", mrb->object_class); + * cd = mrb_class_defined_under(mrb, example_outer, "ExampleInner"); + * + * // If mrb_class_defined_under returns 1 then puts "True" + * // If mrb_class_defined_under returns 0 then puts "False" + * if (cd == 1){ + * puts("True"); + * } + * else { + * puts("False"); + * } + * } + * + * @param [mrb_state*] mrb The current mruby state. + * @param [struct RClass *] outer The name of the outer class. + * @param [const char *] name A string representing the name of the inner class. + * @return [mrb_bool] A boolean value. + */ +MRB_API mrb_bool mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name); + +/** + * Gets a child class. + * @param [mrb_state*] mrb The current mruby state. + * @param [struct RClass *] outer The name of the parent class. + * @param [const char *] name The name of the class. + * @return [struct RClass *] A reference to the class. +*/ +MRB_API struct RClass * mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name); + +/** + * Gets a module. + * @param [mrb_state*] mrb The current mruby state. + * @param [const char *] name The name of the module. + * @return [struct RClass *] A reference to the module. +*/ +MRB_API struct RClass * mrb_module_get(mrb_state *mrb, const char *name); + +/** + * Gets a module defined under another module. + * @param [mrb_state*] mrb The current mruby state. + * @param [struct RClass *] outer The name of the outer module. + * @param [const char *] name The name of the module. + * @return [struct RClass *] A reference to the module. +*/ +MRB_API struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name); +MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value); + +/** + * Duplicate an object. + * + * Equivalent to: + * Object#dup + * @param [mrb_state*] mrb The current mruby state. + * @param [mrb_value] obj Object to be duplicate. + * @return [mrb_value] The newly duplicated object. + */ +MRB_API mrb_value mrb_obj_dup(mrb_state *mrb, mrb_value obj); +MRB_API mrb_value mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method); + +/** + * Returns true if obj responds to the given method. If the method was defined for that + * class it returns true, it returns false otherwise. + * + * Example: + * # Ruby style + * class ExampleClass + * def example_method + * end + * end + * + * ExampleClass.new.respond_to?(:example_method) # => true + * + * // C style + * void + * mrb_example_gem_init(mrb_state* mrb) { + * struct RClass *example_class; + * mrb_sym mid; + * mrb_bool obj_resp; + * + * example_class = mrb_define_class(mrb, "ExampleClass", mrb->object_class); + * mrb_define_method(mrb, example_class, "example_method", exampleMethod, MRB_ARGS_NONE()); + * mid = mrb_intern_str(mrb, mrb_str_new_lit(mrb, "example_method" )); + * obj_resp = mrb_obj_respond_to(mrb, example_class, mid); // => 1(true in Ruby world) + * + * // If mrb_obj_respond_to returns 1 then puts "True" + * // If mrb_obj_respond_to returns 0 then puts "False" + * if (obj_resp == 1) { + * puts("True"); + * } + * else if (obj_resp == 0) { + * puts("False"); + * } + * } + * + * @param [mrb_state*] mrb The current mruby state. + * @param [struct RClass *] c A reference to a class. + * @param [mrb_sym] mid A symbol referencing a method id. + * @return [mrb_bool] A boolean value. + */ +MRB_API mrb_bool mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid); + +/** + * Defines a new class under a given module + * + * @param [mrb_state*] mrb The current mruby state. + * @param [struct RClass *] outer Reference to the module under which the new class will be defined + * @param [const char *] name The name of the defined class + * @param [struct RClass *] super The new class parent + * @return [struct RClass *] Reference to the newly defined class + * @see mrb_define_class + */ +MRB_API struct RClass * mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super); + +MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name); + +/** + * Function requires n arguments. + * + * @param n + * The number of required arguments. + */ +#define MRB_ARGS_REQ(n) ((mrb_aspec)((n)&0x1f) << 18) + +/** + * Funtion takes n optional arguments + * + * @param n + * The number of optional arguments. + */ +#define MRB_ARGS_OPT(n) ((mrb_aspec)((n)&0x1f) << 13) + +/** + * Funtion takes n1 mandatory arguments and n2 optional arguments + * + * @param n1 + * The number of required arguments. + * @param n2 + * The number of optional arguments. + */ +#define MRB_ARGS_ARG(n1,n2) (MRB_ARGS_REQ(n1)|MRB_ARGS_OPT(n2)) + +/** rest argument */ +#define MRB_ARGS_REST() ((mrb_aspec)(1 << 12)) + +/** required arguments after rest */ +#define MRB_ARGS_POST(n) ((mrb_aspec)((n)&0x1f) << 7) + +/** keyword arguments (n of keys, kdict) */ +#define MRB_ARGS_KEY(n1,n2) ((mrb_aspec)((((n1)&0x1f) << 2) | ((n2)?(1<<1):0))) + +/** + * Function takes a block argument + */ +#define MRB_ARGS_BLOCK() ((mrb_aspec)1) + +/** + * Function accepts any number of arguments + */ +#define MRB_ARGS_ANY() MRB_ARGS_REST() + +/** + * Function accepts no arguments + */ +#define MRB_ARGS_NONE() ((mrb_aspec)0) + +/** + * Format specifiers for {mrb_get_args} function + * + * Must be a C string composed of the following format specifiers: + * + * | char | Ruby type | C types | Notes | + * |:----:|----------------|-------------------|----------------------------------------------------| + * | `o` | {Object} | {mrb_value} | Could be used to retrieve any type of argument | + * | `C` | {Class}/{Module} | {mrb_value} | | + * | `S` | {String} | {mrb_value} | when `!` follows, the value may be `nil` | + * | `A` | {Array} | {mrb_value} | when `!` follows, the value may be `nil` | + * | `H` | {Hash} | {mrb_value} | when `!` follows, the value may be `nil` | + * | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` | + * | `z` | {String} | char * | `NULL` terminated string; `z!` gives `NULL` for `nil` | + * | `a` | {Array} | {mrb_value} *, {mrb_int} | Receive two arguments; `a!` gives (`NULL`,`0`) for `nil` | + * | `f` | {Float} | {mrb_float} | | + * | `i` | {Integer} | {mrb_int} | | + * | `b` | boolean | {mrb_bool} | | + * | `n` | {Symbol} | {mrb_sym} | | + * | `&` | block | {mrb_value} | | + * | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array. | + * | | | optional | | After this spec following specs would be optional. | + * | `?` | optional given | {mrb_bool} | `TRUE` if preceding argument is given. Used to check optional argument is given. | + * + * @see mrb_get_args + */ +typedef const char *mrb_args_format; + +/** + * Retrieve arguments from mrb_state. + * + * When applicable, implicit conversions (such as `to_str`, `to_ary`, `to_hash`) are + * applied to received arguments. + * Used inside a function of mrb_func_t type. + * + * @param mrb The current MRuby state. + * @param format [mrb_args_format] is a list of format specifiers + * @param ... The passing variadic arguments must be a pointer of retrieving type. + * @return the number of arguments retrieved. + * @see mrb_args_format + */ +MRB_API mrb_int mrb_get_args(mrb_state *mrb, mrb_args_format format, ...); + +static inline mrb_sym +mrb_get_mid(mrb_state *mrb) /* get method symbol */ +{ + return mrb->c->ci->mid; +} + +static inline int +mrb_get_argc(mrb_state *mrb) /* get argc */ +{ + return mrb->c->ci->argc; +} + +/* `strlen` for character string literals (use with caution or `strlen` instead) + Adjacent string literals are concatenated in C/C++ in translation phase 6. + If `lit` is not one, the compiler will report a syntax error: + MSVC: "error C2143: syntax error : missing ')' before 'string'" + GCC: "error: expected ')' before string constant" +*/ +#define mrb_strlen_lit(lit) (sizeof(lit "") - 1) + +/** + * Call existing ruby functions. + * + * #include <stdio.h> + * #include <mruby.h> + * #include "mruby/compile.h" + * + * int + * main() + * { + * mrb_int i = 99; + * mrb_state *mrb = mrb_open(); + * + * if (!mrb) { } + * FILE *fp = fopen("test.rb","r"); + * mrb_value obj = mrb_load_file(mrb,fp); + * mrb_funcall(mrb, obj, "method_name", 1, mrb_fixnum_value(i)); + * fclose(fp); + * mrb_close(mrb); + * } + * @param [mrb_state*] mrb_state* The current mruby state. + * @param [mrb_value] mrb_value A reference to an mruby value. + * @param [const char*] const char* The name of the method. + * @param [mrb_int] mrb_int The number of arguments the method has. + * @param [...] ... Variadic values(not type safe!). + * @return [mrb_value] mrb_value mruby function value. + */ +MRB_API mrb_value mrb_funcall(mrb_state*, mrb_value, const char*, mrb_int,...); +/** + * Call existing ruby functions. This is basically the type safe version of mrb_funcall. + * + * #include <stdio.h> + * #include <mruby.h> + * #include "mruby/compile.h" + * int + * main() + * { + * mrb_int i = 99; + * mrb_state *mrb = mrb_open(); + * + * if (!mrb) { } + * mrb_sym m_sym = mrb_intern_lit(mrb, "method_name"); // Symbol for method. + * + * FILE *fp = fopen("test.rb","r"); + * mrb_value obj = mrb_load_file(mrb,fp); + * mrb_funcall_argv(mrb, obj, m_sym, 1, &obj); // Calling ruby function from test.rb. + * fclose(fp); + * mrb_close(mrb); + * } + * @param [mrb_state*] mrb_state* The current mruby state. + * @param [mrb_value] mrb_value A reference to an mruby value. + * @param [mrb_sym] mrb_sym The symbol representing the method. + * @param [mrb_int] mrb_int The number of arguments the method has. + * @param [const mrb_value*] mrb_value* Pointer to the object. + * @return [mrb_value] mrb_value mruby function value. + * @see mrb_funcall + */ +MRB_API mrb_value mrb_funcall_argv(mrb_state*, mrb_value, mrb_sym, mrb_int, const mrb_value*); +/** + * Call existing ruby functions with a block. + */ +MRB_API mrb_value mrb_funcall_with_block(mrb_state*, mrb_value, mrb_sym, mrb_int, const mrb_value*, mrb_value); +/** + * Create a symbol + * + * # Ruby style: + * :pizza # => :pizza + * + * // C style: + * mrb_sym m_sym = mrb_intern_lit(mrb, "pizza"); // => :pizza + * @param [mrb_state*] mrb_state* The current mruby state. + * @param [const char*] const char* The name of the method. + * @return [mrb_sym] mrb_sym A symbol. + */ +MRB_API mrb_sym mrb_intern_cstr(mrb_state*,const char*); +MRB_API mrb_sym mrb_intern(mrb_state*,const char*,size_t); +MRB_API mrb_sym mrb_intern_static(mrb_state*,const char*,size_t); +#define mrb_intern_lit(mrb, lit) mrb_intern_static(mrb, lit, mrb_strlen_lit(lit)) +MRB_API mrb_sym mrb_intern_str(mrb_state*,mrb_value); +MRB_API mrb_value mrb_check_intern_cstr(mrb_state*,const char*); +MRB_API mrb_value mrb_check_intern(mrb_state*,const char*,size_t); +MRB_API mrb_value mrb_check_intern_str(mrb_state*,mrb_value); +MRB_API const char *mrb_sym2name(mrb_state*,mrb_sym); +MRB_API const char *mrb_sym2name_len(mrb_state*,mrb_sym,mrb_int*); +MRB_API mrb_value mrb_sym2str(mrb_state*,mrb_sym); + +MRB_API void *mrb_malloc(mrb_state*, size_t); /* raise RuntimeError if no mem */ +MRB_API void *mrb_calloc(mrb_state*, size_t, size_t); /* ditto */ +MRB_API void *mrb_realloc(mrb_state*, void*, size_t); /* ditto */ +MRB_API void *mrb_realloc_simple(mrb_state*, void*, size_t); /* return NULL if no memory available */ +MRB_API void *mrb_malloc_simple(mrb_state*, size_t); /* return NULL if no memory available */ +MRB_API struct RBasic *mrb_obj_alloc(mrb_state*, enum mrb_vtype, struct RClass*); +MRB_API void mrb_free(mrb_state*, void*); + +MRB_API mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len); + +/** + * Turns a C string into a Ruby string value. + */ +MRB_API mrb_value mrb_str_new_cstr(mrb_state*, const char*); +MRB_API mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len); +#define mrb_str_new_lit(mrb, lit) mrb_str_new_static(mrb, (lit), mrb_strlen_lit(lit)) + +#ifdef _WIN32 +char* mrb_utf8_from_locale(const char *p, int len); +char* mrb_locale_from_utf8(const char *p, int len); +#define mrb_locale_free(p) free(p) +#define mrb_utf8_free(p) free(p) +#else +#define mrb_utf8_from_locale(p, l) (p) +#define mrb_locale_from_utf8(p, l) (p) +#define mrb_locale_free(p) +#define mrb_utf8_free(p) +#endif + +/** + * Creates new mrb_state. + * + * @return + * Pointer to the newly created mrb_state. + */ +MRB_API mrb_state* mrb_open(void); + +/** + * Create new mrb_state with custom allocators. + * + * @param f + * Reference to the allocation function. + * @param ud + * User data will be passed to custom allocator f. + * If user data isn't required just pass NULL. + * @return + * Pointer to the newly created mrb_state. + */ +MRB_API mrb_state* mrb_open_allocf(mrb_allocf f, void *ud); + +/** + * Create new mrb_state with just the MRuby core + * + * @param f + * Reference to the allocation function. + * Use mrb_default_allocf for the default + * @param ud + * User data will be passed to custom allocator f. + * If user data isn't required just pass NULL. + * @return + * Pointer to the newly created mrb_state. + */ +MRB_API mrb_state* mrb_open_core(mrb_allocf f, void *ud); + +/** + * Closes and frees a mrb_state. + * + * @param mrb + * Pointer to the mrb_state to be closed. + */ +MRB_API void mrb_close(mrb_state *mrb); + +/** + * The default allocation function. + * + * @see mrb_allocf + */ +MRB_API void* mrb_default_allocf(mrb_state*, void*, size_t, void*); + +MRB_API mrb_value mrb_top_self(mrb_state *); +MRB_API mrb_value mrb_run(mrb_state*, struct RProc*, mrb_value); +MRB_API mrb_value mrb_top_run(mrb_state*, struct RProc*, mrb_value, unsigned int); +MRB_API mrb_value mrb_vm_run(mrb_state*, struct RProc*, mrb_value, unsigned int); +MRB_API mrb_value mrb_vm_exec(mrb_state*, struct RProc*, mrb_code*); +/* compatibility macros */ +#define mrb_toplevel_run_keep(m,p,k) mrb_top_run((m),(p),mrb_top_self(m),(k)) +#define mrb_toplevel_run(m,p) mrb_toplevel_run_keep((m),(p),0) +#define mrb_context_run(m,p,s,k) mrb_vm_run((m),(p),(s),(k)) + +MRB_API void mrb_p(mrb_state*, mrb_value); +MRB_API mrb_int mrb_obj_id(mrb_value obj); +MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name); + +MRB_API mrb_bool mrb_obj_eq(mrb_state*, mrb_value, mrb_value); +MRB_API mrb_bool mrb_obj_equal(mrb_state*, mrb_value, mrb_value); +MRB_API mrb_bool mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2); +MRB_API mrb_value mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base); +MRB_API mrb_value mrb_Integer(mrb_state *mrb, mrb_value val); +MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val); +MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj); +MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2); + +static inline int mrb_gc_arena_save(mrb_state*); +static inline void mrb_gc_arena_restore(mrb_state*,int); + +static inline int +mrb_gc_arena_save(mrb_state *mrb) +{ + return mrb->gc.arena_idx; +} + +static inline void +mrb_gc_arena_restore(mrb_state *mrb, int idx) +{ + mrb->gc.arena_idx = idx; +} + +MRB_API int mrb_gc_arena_save(mrb_state*); +MRB_API void mrb_gc_arena_restore(mrb_state*,int); + +MRB_API void mrb_garbage_collect(mrb_state*); +MRB_API void mrb_full_gc(mrb_state*); +MRB_API void mrb_incremental_gc(mrb_state *); +MRB_API void mrb_gc_mark(mrb_state*,struct RBasic*); +#define mrb_gc_mark_value(mrb,val) do {\ + if (!mrb_immediate_p(val)) mrb_gc_mark((mrb), mrb_basic_ptr(val)); \ +} while (0) +MRB_API void mrb_field_write_barrier(mrb_state *, struct RBasic*, struct RBasic*); +#define mrb_field_write_barrier_value(mrb, obj, val) do{\ + if (!mrb_immediate_p(val)) mrb_field_write_barrier((mrb), (obj), mrb_basic_ptr(val)); \ +} while (0) +MRB_API void mrb_write_barrier(mrb_state *, struct RBasic*); + +MRB_API mrb_value mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method); +MRB_API mrb_value mrb_any_to_s(mrb_state *mrb, mrb_value obj); +MRB_API const char * mrb_obj_classname(mrb_state *mrb, mrb_value obj); +MRB_API struct RClass* mrb_obj_class(mrb_state *mrb, mrb_value obj); +MRB_API mrb_value mrb_class_path(mrb_state *mrb, struct RClass *c); +MRB_API mrb_value mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method); +MRB_API mrb_bool mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c); +MRB_API mrb_value mrb_obj_inspect(mrb_state *mrb, mrb_value self); +MRB_API mrb_value mrb_obj_clone(mrb_state *mrb, mrb_value self); + +#ifndef ISPRINT +#define ISASCII(c) ((unsigned)(c) <= 0x7f) +#define ISPRINT(c) (((unsigned)(c) - 0x20) < 0x5f) +#define ISSPACE(c) ((c) == ' ' || (unsigned)(c) - '\t' < 5) +#define ISUPPER(c) (((unsigned)(c) - 'A') < 26) +#define ISLOWER(c) (((unsigned)(c) - 'a') < 26) +#define ISALPHA(c) ((((unsigned)(c) | 0x20) - 'a') < 26) +#define ISDIGIT(c) (((unsigned)(c) - '0') < 10) +#define ISXDIGIT(c) (ISDIGIT(c) || ((unsigned)(c) | 0x20) - 'a' < 6) +#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c)) +#define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#define ISCNTRL(c) ((unsigned)(c) < 0x20 || (c) == 0x7f) +#define TOUPPER(c) (ISLOWER(c) ? ((c) & 0x5f) : (c)) +#define TOLOWER(c) (ISUPPER(c) ? ((c) | 0x20) : (c)) +#endif + +MRB_API mrb_value mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len); +MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc); + +MRB_API mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg); +MRB_API mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...); +MRB_API mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...); +MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...); +MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...); +MRB_API void mrb_print_backtrace(mrb_state *mrb); +MRB_API void mrb_print_error(mrb_state *mrb); + +/* macros to get typical exception objects + note: + + those E_* macros requires mrb_state* variable named mrb. + + exception objects obtained from those macros are local to mrb +*/ +#define E_RUNTIME_ERROR (mrb_exc_get(mrb, "RuntimeError")) +#define E_TYPE_ERROR (mrb_exc_get(mrb, "TypeError")) +#define E_ARGUMENT_ERROR (mrb_exc_get(mrb, "ArgumentError")) +#define E_INDEX_ERROR (mrb_exc_get(mrb, "IndexError")) +#define E_RANGE_ERROR (mrb_exc_get(mrb, "RangeError")) +#define E_NAME_ERROR (mrb_exc_get(mrb, "NameError")) +#define E_NOMETHOD_ERROR (mrb_exc_get(mrb, "NoMethodError")) +#define E_SCRIPT_ERROR (mrb_exc_get(mrb, "ScriptError")) +#define E_SYNTAX_ERROR (mrb_exc_get(mrb, "SyntaxError")) +#define E_LOCALJUMP_ERROR (mrb_exc_get(mrb, "LocalJumpError")) +#define E_REGEXP_ERROR (mrb_exc_get(mrb, "RegexpError")) + +#define E_NOTIMP_ERROR (mrb_exc_get(mrb, "NotImplementedError")) +#define E_FLOATDOMAIN_ERROR (mrb_exc_get(mrb, "FloatDomainError")) + +#define E_KEY_ERROR (mrb_exc_get(mrb, "KeyError")) + +MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg); +MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv); +MRB_API mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c); + +/* continue execution to the proc */ +/* this function should always be called as the last function of a method */ +/* e.g. return mrb_yield_cont(mrb, proc, self, argc, argv); */ +mrb_value mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb_value *argv); + +/* mrb_gc_protect() leaves the object in the arena */ +MRB_API void mrb_gc_protect(mrb_state *mrb, mrb_value obj); +/* mrb_gc_register() keeps the object from GC. */ +MRB_API void mrb_gc_register(mrb_state *mrb, mrb_value obj); +/* mrb_gc_unregister() removes the object from GC root. */ +MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj); + +MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); +#define mrb_int(mrb, val) mrb_fixnum(mrb_to_int(mrb, val)) +MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); + +typedef enum call_type { + CALL_PUBLIC, + CALL_FCALL, + CALL_VCALL, + CALL_TYPE_MAX +} call_type; + +MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2); +MRB_API const char *mrb_class_name(mrb_state *mrb, struct RClass* klass); +MRB_API void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val); + +MRB_API mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id); + +MRB_API mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid); +MRB_API mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c); +MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func); + + +/* + * Resume a Fiber + * + * @mrbgem mruby-fiber + */ +MRB_API mrb_value mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int argc, const mrb_value *argv); + +/* + * Yield a Fiber + * + * @mrbgem mruby-fiber + */ +MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int argc, const mrb_value *argv); + +/* + * FiberError reference + * + * @mrbgem mruby-fiber + */ +#define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError")) + +/* memory pool implementation */ +typedef struct mrb_pool mrb_pool; +MRB_API struct mrb_pool* mrb_pool_open(mrb_state*); +MRB_API void mrb_pool_close(struct mrb_pool*); +MRB_API void* mrb_pool_alloc(struct mrb_pool*, size_t); +MRB_API void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen); +MRB_API mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t); +MRB_API void* mrb_alloca(mrb_state *mrb, size_t); + +MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func); + +MRB_API void mrb_show_version(mrb_state *mrb); +MRB_API void mrb_show_copyright(mrb_state *mrb); + +MRB_API mrb_value mrb_format(mrb_state *mrb, const char *format, ...); + +#if 0 +/* memcpy and memset does not work with gdb reverse-next on my box */ +/* use naive memcpy and memset instead */ +#undef memcpy +#undef memset +static inline void* +mrbmemcpy(void *dst, const void *src, size_t n) +{ + char *d = (char*)dst; + const char *s = (const char*)src; + while (n--) + *d++ = *s++; + return d; +} +#define memcpy(a,b,c) mrbmemcpy(a,b,c) + +static inline void* +mrbmemset(void *s, int c, size_t n) +{ + char *t = (char*)s; + while (n--) + *t++ = c; + return s; +} +#define memset(a,b,c) mrbmemset(a,b,c) +#endif + +MRB_END_DECL + +#endif /* MRUBY_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/array.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/array.h new file mode 100644 index 000000000..542715554 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/array.h @@ -0,0 +1,279 @@ +/* +** mruby/array.h - Array class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_ARRAY_H +#define MRUBY_ARRAY_H + +#include "common.h" + +/* + * Array class + */ +MRB_BEGIN_DECL + + +typedef struct mrb_shared_array { + int refcnt; + mrb_int len; + mrb_value *ptr; +} mrb_shared_array; + +#define MRB_ARY_EMBED_LEN_MAX ((mrb_int)(sizeof(void*)*3/sizeof(mrb_value))) +struct RArray { + MRB_OBJECT_HEADER; + union { + struct { + mrb_int len; + union { + mrb_int capa; + mrb_shared_array *shared; + } aux; + mrb_value *ptr; + } heap; + mrb_value embed[MRB_ARY_EMBED_LEN_MAX]; + } as; +}; + +#define mrb_ary_ptr(v) ((struct RArray*)(mrb_ptr(v))) +#define mrb_ary_value(p) mrb_obj_value((void*)(p)) +#define RARRAY(v) ((struct RArray*)(mrb_ptr(v))) + +#define MRB_ARY_EMBED_MASK 7 +#define ARY_EMBED_P(a) ((a)->flags & MRB_ARY_EMBED_MASK) +#define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED_MASK)) +#define ARY_EMBED_LEN(a) ((mrb_int)(((a)->flags & MRB_ARY_EMBED_MASK) - 1)) +#define ARY_SET_EMBED_LEN(a,len) ((a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | (len + 1)) +#define ARY_EMBED_PTR(a) (&((a)->as.embed[0])) + +#define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len) +#define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr) +#define RARRAY_LEN(a) ARY_LEN(RARRAY(a)) +#define RARRAY_PTR(a) ARY_PTR(RARRAY(a)) +#define ARY_SET_LEN(a,n) do {\ + if (ARY_EMBED_P(a)) {\ + mrb_assert((n) <= MRB_ARY_EMBED_LEN_MAX); \ + ARY_SET_EMBED_LEN(a,n);\ + }\ + else\ + (a)->as.heap.len = (n);\ +} while (0) +#define ARY_CAPA(a) (ARY_EMBED_P(a)?MRB_ARY_EMBED_LEN_MAX:(a)->as.heap.aux.capa) +#define MRB_ARY_SHARED 256 +#define ARY_SHARED_P(a) ((a)->flags & MRB_ARY_SHARED) +#define ARY_SET_SHARED_FLAG(a) ((a)->flags |= MRB_ARY_SHARED) +#define ARY_UNSET_SHARED_FLAG(a) ((a)->flags &= ~MRB_ARY_SHARED) + +void mrb_ary_decref(mrb_state*, mrb_shared_array*); +MRB_API void mrb_ary_modify(mrb_state*, struct RArray*); +MRB_API mrb_value mrb_ary_new_capa(mrb_state*, mrb_int); + +/* + * Initializes a new array. + * + * Equivalent to: + * + * Array.new + * + * @param mrb The mruby state reference. + * @return The initialized array. + */ +MRB_API mrb_value mrb_ary_new(mrb_state *mrb); + +/* + * Initializes a new array with initial values + * + * Equivalent to: + * + * Array[value1, value2, ...] + * + * @param mrb The mruby state reference. + * @param size The numer of values. + * @param vals The actual values. + * @return The initialized array. + */ +MRB_API mrb_value mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals); + +/* + * Initializes a new array with two initial values + * + * Equivalent to: + * + * Array[car, cdr] + * + * @param mrb The mruby state reference. + * @param car The first value. + * @param cdr The second value. + * @return The initialized array. + */ +MRB_API mrb_value mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr); + +/* + * Concatenate two arrays. The target array will be modified + * + * Equivalent to: + * ary.concat(other) + * + * @param mrb The mruby state reference. + * @param self The target array. + * @param other The array that will be concatenated to self. + */ +MRB_API void mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other); + +/* + * Create an array from the input. It tries calling to_a on the + * value. If value does not respond to that, it creates a new + * array with just this value. + * + * @param mrb The mruby state reference. + * @param value The value to change into an array. + * @return An array representation of value. + */ +MRB_API mrb_value mrb_ary_splat(mrb_state *mrb, mrb_value value); + +/* + * Pushes value into array. + * + * Equivalent to: + * + * ary << value + * + * @param mrb The mruby state reference. + * @param ary The array in which the value will be pushed + * @param value The value to be pushed into array + */ +MRB_API void mrb_ary_push(mrb_state *mrb, mrb_value array, mrb_value value); + +/* + * Pops the last element from the array. + * + * Equivalent to: + * + * ary.pop + * + * @param mrb The mruby state reference. + * @param ary The array from which the value will be popped. + * @return The popped value. + */ +MRB_API mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary); + +/* + * Returns a reference to an element of the array on the given index. + * + * Equivalent to: + * + * ary[n] + * + * @param mrb The mruby state reference. + * @param ary The target array. + * @param n The array index being referenced + * @return The referenced value. + */ +MRB_API mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n); + +/* + * Sets a value on an array at the given index + * + * Equivalent to: + * + * ary[n] = val + * + * @param mrb The mruby state reference. + * @param ary The target array. + * @param n The array index being referenced. + * @param val The value being setted. + */ +MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val); + +/* + * Replace the array with another array + * + * Equivalent to: + * + * ary.replace(other) + * + * @param mrb The mruby state reference + * @param self The target array. + * @param other The array to replace it with. + */ +MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other); +MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self); + +/* + * Unshift an element into the array + * + * Equivalent to: + * + * ary.unshift(item) + * + * @param mrb The mruby state reference. + * @param self The target array. + * @param item The item to unshift. + */ +MRB_API mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item); + +/* + * Get nth element in the array + * + * Equivalent to: + * + * ary[offset] + * + * @param ary The target array. + * @param offset The element position (negative counts from the tail). + */ +MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset); + +/* + * Shifts the first element from the array. + * + * Equivalent to: + * + * ary.shift + * + * @param mrb The mruby state reference. + * @param self The array from which the value will be shifted. + * @return The shifted value. + */ +MRB_API mrb_value mrb_ary_shift(mrb_state *mrb, mrb_value self); + +/* + * Removes all elements from the array + * + * Equivalent to: + * + * ary.clear + * + * @param mrb The mruby state reference. + * @param self The target array. + * @return self + */ +MRB_API mrb_value mrb_ary_clear(mrb_state *mrb, mrb_value self); + +/* + * Join the array elements together in a string + * + * Equivalent to: + * + * ary.join(sep="") + * + * @param mrb The mruby state reference. + * @param ary The target array + * @param sep The separater, can be NULL + */ +MRB_API mrb_value mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep); + +/* + * Update the capacity of the array + * + * @param mrb The mruby state reference. + * @param ary The target array. + * @param new_len The new capacity of the array + */ +MRB_API mrb_value mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len); + +MRB_END_DECL + +#endif /* MRUBY_ARRAY_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/boxing_nan.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/boxing_nan.h new file mode 100644 index 000000000..700ea2ed3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/boxing_nan.h @@ -0,0 +1,98 @@ +/* +** mruby/boxing_nan.h - nan boxing mrb_value definition +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_BOXING_NAN_H +#define MRUBY_BOXING_NAN_H + +#ifdef MRB_USE_FLOAT +# error ---->> MRB_NAN_BOXING and MRB_USE_FLOAT conflict <<---- +#endif + +#ifdef MRB_INT64 +# error ---->> MRB_NAN_BOXING and MRB_INT64 conflict <<---- +#endif + +#define MRB_FIXNUM_SHIFT 0 +#define MRB_TT_HAS_BASIC MRB_TT_OBJECT + +#ifdef MRB_ENDIAN_BIG +#define MRB_ENDIAN_LOHI(a,b) a b +#else +#define MRB_ENDIAN_LOHI(a,b) b a +#endif + +/* value representation by nan-boxing: + * float : FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF + * object: 111111111111TTTT TTPPPPPPPPPPPPPP PPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPP + * int : 1111111111110001 0000000000000000 IIIIIIIIIIIIIIII IIIIIIIIIIIIIIII + * sym : 1111111111110001 0100000000000000 SSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSS + * In order to get enough bit size to save TT, all pointers are shifted 2 bits + * in the right direction. Also, TTTTTT is the mrb_vtype + 1; + */ +typedef struct mrb_value { + union { + mrb_float f; + union { + void *p; + struct { + MRB_ENDIAN_LOHI( + uint32_t ttt; + ,union { + mrb_int i; + mrb_sym sym; + }; + ) + }; + } value; + }; +} mrb_value; + +#define mrb_float_pool(mrb,f) mrb_float_value(mrb,f) + +#define mrb_tt(o) ((enum mrb_vtype)(((o).value.ttt & 0xfc000)>>14)-1) +#define mrb_type(o) (enum mrb_vtype)((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT) +#define mrb_ptr(o) ((void*)((((uintptr_t)0x3fffffffffff)&((uintptr_t)((o).value.p)))<<2)) +#define mrb_float(o) (o).f +#define mrb_cptr(o) mrb_ptr(o) +#define mrb_fixnum(o) (o).value.i +#define mrb_symbol(o) (o).value.sym + +#ifdef MRB_64BIT +#define BOXNAN_SHIFT_LONG_POINTER(v) (((uintptr_t)(v)>>34)&0x3fff) +#else +#define BOXNAN_SHIFT_LONG_POINTER(v) 0 +#endif + +#define BOXNAN_SET_VALUE(o, tt, attr, v) do {\ + (o).attr = (v);\ + (o).value.ttt = 0xfff00000 | (((tt)+1)<<14);\ +} while (0) + +#define BOXNAN_SET_OBJ_VALUE(o, tt, v) do {\ + (o).value.p = (void*)((uintptr_t)(v)>>2);\ + (o).value.ttt = (0xfff00000|(((tt)+1)<<14)|BOXNAN_SHIFT_LONG_POINTER(v));\ +} while (0) + +#define SET_FLOAT_VALUE(mrb,r,v) do { \ + if (v != v) { \ + (r).value.ttt = 0x7ff80000; \ + (r).value.i = 0; \ + } \ + else { \ + (r).f = v; \ + }} while(0) + +#define SET_NIL_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_FALSE, value.i, 0) +#define SET_FALSE_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_FALSE, value.i, 1) +#define SET_TRUE_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_TRUE, value.i, 1) +#define SET_BOOL_VALUE(r,b) BOXNAN_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1) +#define SET_INT_VALUE(r,n) BOXNAN_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n)) +#define SET_SYM_VALUE(r,v) BOXNAN_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v)) +#define SET_OBJ_VALUE(r,v) BOXNAN_SET_OBJ_VALUE(r, (((struct RObject*)(v))->tt), (v)) +#define SET_CPTR_VALUE(mrb,r,v) BOXNAN_SET_OBJ_VALUE(r, MRB_TT_CPTR, v) +#define SET_UNDEF_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0) + +#endif /* MRUBY_BOXING_NAN_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/boxing_no.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/boxing_no.h new file mode 100644 index 000000000..7ee44a934 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/boxing_no.h @@ -0,0 +1,48 @@ +/* +** mruby/boxing_no.h - unboxed mrb_value definition +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_BOXING_NO_H +#define MRUBY_BOXING_NO_H + +#define MRB_FIXNUM_SHIFT 0 +#define MRB_TT_HAS_BASIC MRB_TT_OBJECT + +typedef struct mrb_value { + union { + mrb_float f; + void *p; + mrb_int i; + mrb_sym sym; + } value; + enum mrb_vtype tt; +} mrb_value; + +#define mrb_float_pool(mrb,f) mrb_float_value(mrb,f) + +#define mrb_ptr(o) (o).value.p +#define mrb_cptr(o) mrb_ptr(o) +#define mrb_float(o) (o).value.f +#define mrb_fixnum(o) (o).value.i +#define mrb_symbol(o) (o).value.sym +#define mrb_type(o) (o).tt + +#define BOXNIX_SET_VALUE(o, ttt, attr, v) do {\ + (o).tt = ttt;\ + (o).attr = v;\ +} while (0) + +#define SET_NIL_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_FALSE, value.i, 0) +#define SET_FALSE_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_FALSE, value.i, 1) +#define SET_TRUE_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_TRUE, value.i, 1) +#define SET_BOOL_VALUE(r,b) BOXNIX_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1) +#define SET_INT_VALUE(r,n) BOXNIX_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n)) +#define SET_FLOAT_VALUE(mrb,r,v) BOXNIX_SET_VALUE(r, MRB_TT_FLOAT, value.f, (v)) +#define SET_SYM_VALUE(r,v) BOXNIX_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v)) +#define SET_OBJ_VALUE(r,v) BOXNIX_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v)) +#define SET_CPTR_VALUE(mrb,r,v) BOXNIX_SET_VALUE(r, MRB_TT_CPTR, value.p, v) +#define SET_UNDEF_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0) + +#endif /* MRUBY_BOXING_NO_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/boxing_word.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/boxing_word.h new file mode 100644 index 000000000..d1c457fae --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/boxing_word.h @@ -0,0 +1,120 @@ +/* +** mruby/boxing_word.h - word boxing mrb_value definition +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_BOXING_WORD_H +#define MRUBY_BOXING_WORD_H + +#if defined(MRB_INT16) +# error MRB_INT16 is too small for MRB_WORD_BOXING. +#endif + +#if defined(MRB_INT64) && !defined(MRB_64BIT) +#error MRB_INT64 cannot be used with MRB_WORD_BOXING in 32-bit mode. +#endif + +struct RFloat { + MRB_OBJECT_HEADER; + mrb_float f; +}; + +struct RCptr { + MRB_OBJECT_HEADER; + void *p; +}; + +#define MRB_FIXNUM_SHIFT 1 +#define MRB_TT_HAS_BASIC MRB_TT_FLOAT + +enum mrb_special_consts { + MRB_Qnil = 0, + MRB_Qfalse = 2, + MRB_Qtrue = 4, + MRB_Qundef = 6, +}; + +#define MRB_FIXNUM_FLAG 0x01 +#define MRB_SYMBOL_FLAG 0x0e +#define MRB_SPECIAL_SHIFT 8 + +typedef union mrb_value { + union { + void *p; + struct { + unsigned int i_flag : MRB_FIXNUM_SHIFT; + mrb_int i : (MRB_INT_BIT - MRB_FIXNUM_SHIFT); + }; + struct { + unsigned int sym_flag : MRB_SPECIAL_SHIFT; + mrb_sym sym : (sizeof(mrb_sym) * CHAR_BIT); + }; + struct RBasic *bp; + struct RFloat *fp; + struct RCptr *vp; + } value; + unsigned long w; +} mrb_value; + +MRB_API mrb_value mrb_word_boxing_cptr_value(struct mrb_state*, void*); +MRB_API mrb_value mrb_word_boxing_float_value(struct mrb_state*, mrb_float); +MRB_API mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float); + +#define mrb_float_pool(mrb,f) mrb_word_boxing_float_pool(mrb,f) + +#define mrb_ptr(o) (o).value.p +#define mrb_cptr(o) (o).value.vp->p +#define mrb_float(o) (o).value.fp->f +#define mrb_fixnum(o) ((mrb_int)(o).value.i) +#define mrb_symbol(o) (o).value.sym + +static inline enum mrb_vtype +mrb_type(mrb_value o) +{ + switch (o.w) { + case MRB_Qfalse: + case MRB_Qnil: + return MRB_TT_FALSE; + case MRB_Qtrue: + return MRB_TT_TRUE; + case MRB_Qundef: + return MRB_TT_UNDEF; + } + if (o.value.i_flag == MRB_FIXNUM_FLAG) { + return MRB_TT_FIXNUM; + } + if (o.value.sym_flag == MRB_SYMBOL_FLAG) { + return MRB_TT_SYMBOL; + } + return o.value.bp->tt; +} + +#define mrb_bool(o) ((o).w != MRB_Qnil && (o).w != MRB_Qfalse) +#define mrb_fixnum_p(o) ((o).value.i_flag == MRB_FIXNUM_FLAG) +#define mrb_undef_p(o) ((o).w == MRB_Qundef) +#define mrb_nil_p(o) ((o).w == MRB_Qnil) + +#define BOXWORD_SET_VALUE(o, ttt, attr, v) do { \ + switch (ttt) {\ + case MRB_TT_FALSE: (o).w = (v) ? MRB_Qfalse : MRB_Qnil; break;\ + case MRB_TT_TRUE: (o).w = MRB_Qtrue; break;\ + case MRB_TT_UNDEF: (o).w = MRB_Qundef; break;\ + case MRB_TT_FIXNUM: (o).w = 0;(o).value.i_flag = MRB_FIXNUM_FLAG; (o).attr = (v); break;\ + case MRB_TT_SYMBOL: (o).w = 0;(o).value.sym_flag = MRB_SYMBOL_FLAG; (o).attr = (v); break;\ + default: (o).w = 0; (o).attr = (v); if ((o).value.bp) (o).value.bp->tt = ttt; break;\ + }\ +} while (0) + +#define SET_FLOAT_VALUE(mrb,r,v) r = mrb_word_boxing_float_value(mrb, v) +#define SET_CPTR_VALUE(mrb,r,v) r = mrb_word_boxing_cptr_value(mrb, v) +#define SET_NIL_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 0) +#define SET_FALSE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 1) +#define SET_TRUE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_TRUE, value.i, 1) +#define SET_BOOL_VALUE(r,b) BOXWORD_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1) +#define SET_INT_VALUE(r,n) BOXWORD_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n)) +#define SET_SYM_VALUE(r,v) BOXWORD_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v)) +#define SET_OBJ_VALUE(r,v) BOXWORD_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v)) +#define SET_UNDEF_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0) + +#endif /* MRUBY_BOXING_WORD_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/class.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/class.h new file mode 100644 index 000000000..c0317b458 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/class.h @@ -0,0 +1,92 @@ +/* +** mruby/class.h - Class class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_CLASS_H +#define MRUBY_CLASS_H + +#include "common.h" + +/** + * Class class + */ +MRB_BEGIN_DECL + +struct RClass { + MRB_OBJECT_HEADER; + struct iv_tbl *iv; + struct kh_mt *mt; + struct RClass *super; +}; + +#define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v))) +#define RCLASS_SUPER(v) (((struct RClass*)(mrb_ptr(v)))->super) +#define RCLASS_IV_TBL(v) (((struct RClass*)(mrb_ptr(v)))->iv) +#define RCLASS_M_TBL(v) (((struct RClass*)(mrb_ptr(v)))->mt) + +static inline struct RClass* +mrb_class(mrb_state *mrb, mrb_value v) +{ + switch (mrb_type(v)) { + case MRB_TT_FALSE: + if (mrb_fixnum(v)) + return mrb->false_class; + return mrb->nil_class; + case MRB_TT_TRUE: + return mrb->true_class; + case MRB_TT_SYMBOL: + return mrb->symbol_class; + case MRB_TT_FIXNUM: + return mrb->fixnum_class; + case MRB_TT_FLOAT: + return mrb->float_class; + case MRB_TT_CPTR: + return mrb->object_class; + case MRB_TT_ENV: + return NULL; + default: + return mrb_obj_ptr(v)->c; + } +} + +/* TODO: figure out where to put user flags */ +#define MRB_FLAG_IS_FROZEN (1 << 18) +#define MRB_FLAG_IS_PREPENDED (1 << 19) +#define MRB_FLAG_IS_ORIGIN (1 << 20) +#define MRB_CLASS_ORIGIN(c) do {\ + if (c->flags & MRB_FLAG_IS_PREPENDED) {\ + c = c->super;\ + while (!(c->flags & MRB_FLAG_IS_ORIGIN)) {\ + c = c->super;\ + }\ + }\ +} while (0) +#define MRB_FLAG_IS_INHERITED (1 << 21) +#define MRB_INSTANCE_TT_MASK (0xFF) +#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt) +#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK) + +MRB_API struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*); +MRB_API struct RClass* mrb_define_module_id(mrb_state*, mrb_sym); +MRB_API struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb_sym); +MRB_API struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym); +MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, struct RProc *); +MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec); +MRB_API void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b); + +MRB_API struct RProc *mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); +MRB_API struct RProc *mrb_method_search(mrb_state*, struct RClass*, mrb_sym); + +MRB_API struct RClass* mrb_class_real(struct RClass* cl); + +void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym); +mrb_value mrb_class_find_path(mrb_state*, struct RClass*); +void mrb_gc_mark_mt(mrb_state*, struct RClass*); +size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*); +void mrb_gc_free_mt(mrb_state*, struct RClass*); + +MRB_END_DECL + +#endif /* MRUBY_CLASS_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/common.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/common.h new file mode 100644 index 000000000..d6ec78b0d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/common.h @@ -0,0 +1,72 @@ +/* +**"common.h - mruby common platform definition" +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_COMMON_H +#define MRUBY_COMMON_H + + +#ifdef __cplusplus +#ifdef MRB_ENABLE_CXX_ABI +#define MRB_BEGIN_DECL +#define MRB_END_DECL +#else +# define MRB_BEGIN_DECL extern "C" { +# define MRB_END_DECL } +#endif +#else +/** Start declarations in C mode */ +# define MRB_BEGIN_DECL +/** End declarations in C mode */ +# define MRB_END_DECL +#endif + +/** + * Shared compiler macros + */ +MRB_BEGIN_DECL + +/** Declare a function that never returns. */ +#if __STDC_VERSION__ >= 201112L +# define mrb_noreturn _Noreturn +#elif defined __GNUC__ && !defined __STRICT_ANSI__ +# define mrb_noreturn __attribute__((noreturn)) +#elif defined _MSC_VER +# define mrb_noreturn __declspec(noreturn) +#else +# define mrb_noreturn +#endif + +/** Mark a function as deprecated. */ +#if defined __GNUC__ && !defined __STRICT_ANSI__ +# define mrb_deprecated __attribute__((deprecated)) +#elif defined _MSC_VER +# define mrb_deprecated __declspec(deprecated) +#else +# define mrb_deprecated +#endif + +/** Declare a function as always inlined. */ +#if defined(_MSC_VER) +# define MRB_INLINE static __inline +#else +# define MRB_INLINE static inline +#endif + + +/** Declare a public MRuby API function. */ +#if defined(MRB_BUILD_AS_DLL) +#if defined(MRB_CORE) || defined(MRB_LIB) +# define MRB_API __declspec(dllexport) +#else +# define MRB_API __declspec(dllimport) +#endif +#else +# define MRB_API extern +#endif + +MRB_END_DECL + +#endif /* MRUBY_COMMON_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/compile.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/compile.h new file mode 100644 index 000000000..d1ff0530f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/compile.h @@ -0,0 +1,195 @@ +/* +** mruby/compile.h - mruby parser +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_COMPILE_H +#define MRUBY_COMPILE_H + +#include "common.h" + +/** + * MRuby Compiler + */ +MRB_BEGIN_DECL + +#include <mruby.h> + +struct mrb_jmpbuf; + +struct mrb_parser_state; +/* load context */ +typedef struct mrbc_context { + mrb_sym *syms; + int slen; + char *filename; + short lineno; + int (*partial_hook)(struct mrb_parser_state*); + void *partial_data; + struct RClass *target_class; + mrb_bool capture_errors:1; + mrb_bool dump_result:1; + mrb_bool no_exec:1; + mrb_bool keep_lv:1; + mrb_bool no_optimize:1; + + size_t parser_nerr; +} mrbc_context; + +MRB_API mrbc_context* mrbc_context_new(mrb_state *mrb); +MRB_API void mrbc_context_free(mrb_state *mrb, mrbc_context *cxt); +MRB_API const char *mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s); +MRB_API void mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*partial_hook)(struct mrb_parser_state*), void*data); + +/* AST node structure */ +typedef struct mrb_ast_node { + struct mrb_ast_node *car, *cdr; + uint16_t lineno, filename_index; +} mrb_ast_node; + +/* lexer states */ +enum mrb_lex_state_enum { + EXPR_BEG, /* ignore newline, +/- is a sign. */ + EXPR_END, /* newline significant, +/- is an operator. */ + EXPR_ENDARG, /* ditto, and unbound braces. */ + EXPR_ENDFN, /* ditto, and unbound braces. */ + EXPR_ARG, /* newline significant, +/- is an operator. */ + EXPR_CMDARG, /* newline significant, +/- is an operator. */ + EXPR_MID, /* newline significant, +/- is an operator. */ + EXPR_FNAME, /* ignore newline, no reserved words. */ + EXPR_DOT, /* right after '.' or '::', no reserved words. */ + EXPR_CLASS, /* immediate after 'class', no here document. */ + EXPR_VALUE, /* alike EXPR_BEG but label is disallowed. */ + EXPR_MAX_STATE +}; + +/* saved error message */ +struct mrb_parser_message { + int lineno; + int column; + char* message; +}; + +#define STR_FUNC_PARSING 0x01 +#define STR_FUNC_EXPAND 0x02 +#define STR_FUNC_REGEXP 0x04 +#define STR_FUNC_WORD 0x08 +#define STR_FUNC_SYMBOL 0x10 +#define STR_FUNC_ARRAY 0x20 +#define STR_FUNC_HEREDOC 0x40 +#define STR_FUNC_XQUOTE 0x80 + +enum mrb_string_type { + str_not_parsing = (0), + str_squote = (STR_FUNC_PARSING), + str_dquote = (STR_FUNC_PARSING|STR_FUNC_EXPAND), + str_regexp = (STR_FUNC_PARSING|STR_FUNC_REGEXP|STR_FUNC_EXPAND), + str_sword = (STR_FUNC_PARSING|STR_FUNC_WORD|STR_FUNC_ARRAY), + str_dword = (STR_FUNC_PARSING|STR_FUNC_WORD|STR_FUNC_ARRAY|STR_FUNC_EXPAND), + str_ssym = (STR_FUNC_PARSING|STR_FUNC_SYMBOL), + str_ssymbols = (STR_FUNC_PARSING|STR_FUNC_SYMBOL|STR_FUNC_ARRAY), + str_dsymbols = (STR_FUNC_PARSING|STR_FUNC_SYMBOL|STR_FUNC_ARRAY|STR_FUNC_EXPAND), + str_heredoc = (STR_FUNC_PARSING|STR_FUNC_HEREDOC), + str_xquote = (STR_FUNC_PARSING|STR_FUNC_XQUOTE|STR_FUNC_EXPAND), +}; + +/* heredoc structure */ +struct mrb_parser_heredoc_info { + mrb_bool allow_indent:1; + mrb_bool line_head:1; + enum mrb_string_type type; + const char *term; + int term_len; + mrb_ast_node *doc; +}; + +#define MRB_PARSER_TOKBUF_MAX 65536 +#define MRB_PARSER_TOKBUF_SIZE 256 + +/* parser structure */ +struct mrb_parser_state { + mrb_state *mrb; + struct mrb_pool *pool; + mrb_ast_node *cells; + const char *s, *send; +#ifndef MRB_DISABLE_STDIO + FILE *f; +#endif + mrbc_context *cxt; + char const *filename; + int lineno; + int column; + + enum mrb_lex_state_enum lstate; + mrb_ast_node *lex_strterm; /* (type nest_level beg . end) */ + + unsigned int cond_stack; + unsigned int cmdarg_stack; + int paren_nest; + int lpar_beg; + int in_def, in_single; + mrb_bool cmd_start:1; + mrb_ast_node *locals; + + mrb_ast_node *pb; + char *tokbuf; + char buf[MRB_PARSER_TOKBUF_SIZE]; + int tidx; + int tsiz; + + mrb_ast_node *all_heredocs; /* list of mrb_parser_heredoc_info* */ + mrb_ast_node *heredocs_from_nextline; + mrb_ast_node *parsing_heredoc; + mrb_ast_node *lex_strterm_before_heredoc; + mrb_bool heredoc_end_now:1; /* for mirb */ + + void *ylval; + + size_t nerr; + size_t nwarn; + mrb_ast_node *tree; + + mrb_bool no_optimize:1; + mrb_bool capture_errors:1; + struct mrb_parser_message error_buffer[10]; + struct mrb_parser_message warn_buffer[10]; + + mrb_sym* filename_table; + size_t filename_table_length; + int current_filename_index; + + struct mrb_jmpbuf* jmp; +}; + +MRB_API struct mrb_parser_state* mrb_parser_new(mrb_state*); +MRB_API void mrb_parser_free(struct mrb_parser_state*); +MRB_API void mrb_parser_parse(struct mrb_parser_state*,mrbc_context*); +MRB_API double mrb_float_read(const char*, char**); + +MRB_API void mrb_parser_set_filename(struct mrb_parser_state*, char const*); +MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx); + +/* utility functions */ +#ifndef MRB_DISABLE_STDIO +MRB_API struct mrb_parser_state* mrb_parse_file(mrb_state*,FILE*,mrbc_context*); +#endif +MRB_API struct mrb_parser_state* mrb_parse_string(mrb_state*,const char*,mrbc_context*); +MRB_API struct mrb_parser_state* mrb_parse_nstring(mrb_state*,const char*,size_t,mrbc_context*); +MRB_API struct RProc* mrb_generate_code(mrb_state*, struct mrb_parser_state*); +MRB_API mrb_value mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c); + +/* program load functions */ +#ifndef MRB_DISABLE_STDIO +MRB_API mrb_value mrb_load_file(mrb_state*,FILE*); +MRB_API mrb_value mrb_load_file_cxt(mrb_state*,FILE*, mrbc_context *cxt); +#endif +MRB_API mrb_value mrb_load_string(mrb_state *mrb, const char *s); +MRB_API mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, size_t len); +MRB_API mrb_value mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *cxt); +MRB_API mrb_value mrb_load_nstring_cxt(mrb_state *mrb, const char *s, size_t len, mrbc_context *cxt); + +/** @} */ +MRB_END_DECL + +#endif /* MRUBY_COMPILE_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/data.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/data.h new file mode 100644 index 000000000..590470528 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/data.h @@ -0,0 +1,75 @@ +/* +** mruby/data.h - Data class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_DATA_H +#define MRUBY_DATA_H + +#include "common.h" + +/** + * Custom C wrapped data. + * + * Defining Ruby wrappers around native objects. + */ +MRB_BEGIN_DECL + +/** + * Custom data type description. + */ +typedef struct mrb_data_type { + /** data type name */ + const char *struct_name; + + /** data type release function pointer */ + void (*dfree)(mrb_state *mrb, void*); +} mrb_data_type; + +struct RData { + MRB_OBJECT_HEADER; + struct iv_tbl *iv; + const mrb_data_type *type; + void *data; +}; + +MRB_API struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass, void *datap, const mrb_data_type *type); + +#define Data_Wrap_Struct(mrb,klass,type,ptr)\ + mrb_data_object_alloc(mrb,klass,ptr,type) + +#define Data_Make_Struct(mrb,klass,strct,type,sval,data) do { \ + sval = mrb_malloc(mrb, sizeof(strct)); \ + { static const strct zero = { 0 }; *sval = zero; };\ + data = Data_Wrap_Struct(mrb,klass,type,sval);\ +} while (0) + +#define RDATA(obj) ((struct RData *)(mrb_ptr(obj))) +#define DATA_PTR(d) (RDATA(d)->data) +#define DATA_TYPE(d) (RDATA(d)->type) +MRB_API void mrb_data_check_type(mrb_state *mrb, mrb_value, const mrb_data_type*); +MRB_API void *mrb_data_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*); +#define DATA_GET_PTR(mrb,obj,dtype,type) (type*)mrb_data_get_ptr(mrb,obj,dtype) +MRB_API void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_type*); +#define DATA_CHECK_GET_PTR(mrb,obj,dtype,type) (type*)mrb_data_check_get_ptr(mrb,obj,dtype) + +/* obsolete functions and macros */ +#define mrb_data_check_and_get(mrb,obj,dtype) mrb_data_get_ptr(mrb,obj,dtype) +#define mrb_get_datatype(mrb,val,type) mrb_data_get_ptr(mrb, val, type) +#define mrb_check_datatype(mrb,val,type) mrb_data_get_ptr(mrb, val, type) +#define Data_Get_Struct(mrb,obj,type,sval) do {\ + *(void**)&sval = mrb_data_get_ptr(mrb, obj, type); \ +} while (0) + +static inline void +mrb_data_init(mrb_value v, void *ptr, const mrb_data_type *type) +{ + mrb_assert(mrb_type(v) == MRB_TT_DATA); + DATA_PTR(v) = ptr; + DATA_TYPE(v) = type; +} + +MRB_END_DECL + +#endif /* MRUBY_DATA_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/debug.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/debug.h new file mode 100644 index 000000000..d1de34882 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/debug.h @@ -0,0 +1,66 @@ +/* +** mruby/debug.h - mruby debug info +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_DEBUG_H +#define MRUBY_DEBUG_H + +#include "common.h" + +/** + * MRuby Debugging. + */ +MRB_BEGIN_DECL + +typedef enum mrb_debug_line_type { + mrb_debug_line_ary = 0, + mrb_debug_line_flat_map = 1 +} mrb_debug_line_type; + +typedef struct mrb_irep_debug_info_line { + uint32_t start_pos; + uint16_t line; +} mrb_irep_debug_info_line; + +typedef struct mrb_irep_debug_info_file { + uint32_t start_pos; + const char *filename; + mrb_sym filename_sym; + uint32_t line_entry_count; + mrb_debug_line_type line_type; + union { + void *ptr; + mrb_irep_debug_info_line *flat_map; + uint16_t *ary; + } lines; +} mrb_irep_debug_info_file; + +typedef struct mrb_irep_debug_info { + uint32_t pc_count; + uint16_t flen; + mrb_irep_debug_info_file **files; +} mrb_irep_debug_info; + +/* + * get line from irep's debug info and program counter + * @return returns NULL if not found + */ +MRB_API const char *mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc); + +/* + * get line from irep's debug info and program counter + * @return returns -1 if not found + */ +MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc); + +MRB_API mrb_irep_debug_info_file *mrb_debug_info_append_file( + mrb_state *mrb, mrb_irep *irep, + uint32_t start_pos, uint32_t end_pos); +MRB_API mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep); +MRB_API void mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d); + +MRB_END_DECL + +#endif /* MRUBY_DEBUG_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/dump.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/dump.h new file mode 100644 index 000000000..f56d66a32 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/dump.h @@ -0,0 +1,196 @@ +/* +** mruby/dump.h - mruby binary dumper (mrbc binary format) +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_DUMP_H +#define MRUBY_DUMP_H + +#include <mruby.h> +#include <mruby/irep.h> +#include "common.h" + +/** + * Dumping compiled mruby script. + */ +MRB_BEGIN_DECL + +#define DUMP_DEBUG_INFO 1 +#define DUMP_ENDIAN_BIG 2 +#define DUMP_ENDIAN_LIL 4 +#define DUMP_ENDIAN_NAT 6 +#define DUMP_ENDIAN_MASK 6 + +int mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size); +#ifndef MRB_DISABLE_STDIO +int mrb_dump_irep_binary(mrb_state*, mrb_irep*, uint8_t, FILE*); +int mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep*, uint8_t flags, FILE *f, const char *initname); +mrb_irep *mrb_read_irep_file(mrb_state*, FILE*); +MRB_API mrb_value mrb_load_irep_file(mrb_state*,FILE*); +MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*); +#endif +MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); + +/* dump/load error code + * + * NOTE: MRB_DUMP_GENERAL_FAILURE is caused by + * unspecified issues like malloc failed. + */ +#define MRB_DUMP_OK 0 +#define MRB_DUMP_GENERAL_FAILURE (-1) +#define MRB_DUMP_WRITE_FAULT (-2) +#define MRB_DUMP_READ_FAULT (-3) +#define MRB_DUMP_CRC_ERROR (-4) +#define MRB_DUMP_INVALID_FILE_HEADER (-5) +#define MRB_DUMP_INVALID_IREP (-6) +#define MRB_DUMP_INVALID_ARGUMENT (-7) + +/* null symbol length */ +#define MRB_DUMP_NULL_SYM_LEN 0xFFFF + +/* Rite Binary File header */ +#define RITE_BINARY_IDENT "RITE" +#define RITE_BINARY_IDENT_LIL "ETIR" +#define RITE_BINARY_FORMAT_VER "0004" +#define RITE_COMPILER_NAME "MATZ" +#define RITE_COMPILER_VERSION "0000" + +#define RITE_VM_VER "0000" + +#define RITE_BINARY_EOF "END\0" +#define RITE_SECTION_IREP_IDENT "IREP" +#define RITE_SECTION_LINENO_IDENT "LINE" +#define RITE_SECTION_DEBUG_IDENT "DBG\0" +#define RITE_SECTION_LV_IDENT "LVAR" + +#define MRB_DUMP_DEFAULT_STR_LEN 128 +#define MRB_DUMP_ALIGNMENT sizeof(uint32_t) + +/* binary header */ +struct rite_binary_header { + uint8_t binary_ident[4]; /* Binary Identifier */ + uint8_t binary_version[4]; /* Binary Format Version */ + uint8_t binary_crc[2]; /* Binary CRC */ + uint8_t binary_size[4]; /* Binary Size */ + uint8_t compiler_name[4]; /* Compiler name */ + uint8_t compiler_version[4]; +}; + +/* section header */ +#define RITE_SECTION_HEADER \ + uint8_t section_ident[4]; \ + uint8_t section_size[4] + +struct rite_section_header { + RITE_SECTION_HEADER; +}; + +struct rite_section_irep_header { + RITE_SECTION_HEADER; + + uint8_t rite_version[4]; /* Rite Instruction Specification Version */ +}; + +struct rite_section_lineno_header { + RITE_SECTION_HEADER; +}; + +struct rite_section_debug_header { + RITE_SECTION_HEADER; +}; + +struct rite_section_lv_header { + RITE_SECTION_HEADER; +}; + +#define RITE_LV_NULL_MARK UINT16_MAX + +struct rite_binary_footer { + RITE_SECTION_HEADER; +}; + +static inline int +bigendian_p() +{ + int i; + char *p; + + i = 1; + p = (char*)&i; + return p[0]?0:1; +} + +static inline size_t +uint8_to_bin(uint8_t s, uint8_t *bin) +{ + *bin = s; + return sizeof(uint8_t); +} + +static inline size_t +uint16_to_bin(uint16_t s, uint8_t *bin) +{ + *bin++ = (s >> 8) & 0xff; + *bin = s & 0xff; + return sizeof(uint16_t); +} + +static inline size_t +uint32_to_bin(uint32_t l, uint8_t *bin) +{ + *bin++ = (l >> 24) & 0xff; + *bin++ = (l >> 16) & 0xff; + *bin++ = (l >> 8) & 0xff; + *bin = l & 0xff; + return sizeof(uint32_t); +} + +static inline size_t +uint32l_to_bin(uint32_t l, uint8_t *bin) +{ + bin[3] = (l >> 24) & 0xff; + bin[2] = (l >> 16) & 0xff; + bin[1] = (l >> 8) & 0xff; + bin[0] = l & 0xff; + return sizeof(uint32_t); +} + +static inline uint32_t +bin_to_uint32(const uint8_t *bin) +{ + return (uint32_t)bin[0] << 24 | + (uint32_t)bin[1] << 16 | + (uint32_t)bin[2] << 8 | + (uint32_t)bin[3]; +} + +static inline uint32_t +bin_to_uint32l(const uint8_t *bin) +{ + return (uint32_t)bin[3] << 24 | + (uint32_t)bin[2] << 16 | + (uint32_t)bin[1] << 8 | + (uint32_t)bin[0]; +} + +static inline uint16_t +bin_to_uint16(const uint8_t *bin) +{ + return (uint16_t)bin[0] << 8 | + (uint16_t)bin[1]; +} + +static inline uint8_t +bin_to_uint8(const uint8_t *bin) +{ + return (uint8_t)bin[0]; +} + +MRB_END_DECL + +/** @internal crc.c */ +uint16_t +calc_crc_16_ccitt(const uint8_t *src, size_t nbytes, uint16_t crc); + +#endif /* MRUBY_DUMP_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/error.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/error.h new file mode 100644 index 000000000..0a262550e --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/error.h @@ -0,0 +1,76 @@ +/* +** mruby/error.h - Exception class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_ERROR_H +#define MRUBY_ERROR_H + +#include "common.h" + +/** + * MRuby error handling. + */ +MRB_BEGIN_DECL + +struct RException { + MRB_OBJECT_HEADER; + struct iv_tbl *iv; +}; + +#define mrb_exc_ptr(v) ((struct RException*)mrb_ptr(v)) + +MRB_API void mrb_sys_fail(mrb_state *mrb, const char *mesg); +MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str); +#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit)) +MRB_API mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv); +MRB_API mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc); +MRB_API mrb_value mrb_get_backtrace(mrb_state *mrb); +MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...); + +/* declaration for fail method */ +MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value); + +struct RBreak { + MRB_OBJECT_HEADER; + struct iv_tbl *iv; + struct RProc *proc; + mrb_value val; +}; + +/** + * Protect + * + * @mrbgem mruby-error + */ +MRB_API mrb_value mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state); + +/** + * Ensure + * + * @mrbgem mruby-error + */ +MRB_API mrb_value mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t ensure, mrb_value e_data); + +/** + * Rescue + * + * @mrbgem mruby-error + */ +MRB_API mrb_value mrb_rescue(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t rescue, mrb_value r_data); + +/** + * Rescue exception + * + * @mrbgem mruby-error + */ +MRB_API mrb_value mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t rescue, mrb_value r_data, + mrb_int len, struct RClass **classes); + +MRB_END_DECL + +#endif /* MRUBY_ERROR_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/gc.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/gc.h new file mode 100644 index 000000000..ce214aa56 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/gc.h @@ -0,0 +1,80 @@ +/* +** mruby/gc.h - garbage collector for mruby +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_GC_H +#define MRUBY_GC_H + +#include "common.h" + +/** + * Uncommon memory management stuffs. + */ +MRB_BEGIN_DECL + + +struct mrb_state; + +#define MRB_EACH_OBJ_OK 0 +#define MRB_EACH_OBJ_BREAK 1 +typedef int (mrb_each_object_callback)(struct mrb_state *mrb, struct RBasic *obj, void *data); +void mrb_objspace_each_objects(struct mrb_state *mrb, mrb_each_object_callback *callback, void *data); +MRB_API void mrb_free_context(struct mrb_state *mrb, struct mrb_context *c); + +#ifndef MRB_GC_ARENA_SIZE +#define MRB_GC_ARENA_SIZE 100 +#endif + +typedef enum { + MRB_GC_STATE_ROOT = 0, + MRB_GC_STATE_MARK, + MRB_GC_STATE_SWEEP +} mrb_gc_state; + +typedef struct mrb_heap_page { + struct RBasic *freelist; + struct mrb_heap_page *prev; + struct mrb_heap_page *next; + struct mrb_heap_page *free_next; + struct mrb_heap_page *free_prev; + mrb_bool old:1; + void *objects[]; +} mrb_heap_page; + +typedef struct mrb_gc { + mrb_heap_page *heaps; /* heaps for GC */ + mrb_heap_page *sweeps; + mrb_heap_page *free_heaps; + size_t live; /* count of live objects */ +#ifdef MRB_GC_FIXED_ARENA + struct RBasic *arena[MRB_GC_ARENA_SIZE]; /* GC protection array */ +#else + struct RBasic **arena; /* GC protection array */ + int arena_capa; +#endif + int arena_idx; + + mrb_gc_state state; /* state of gc */ + int current_white_part; /* make white object by white_part */ + struct RBasic *gray_list; /* list of gray objects to be traversed incrementally */ + struct RBasic *atomic_gray_list; /* list of objects to be traversed atomically */ + size_t live_after_mark; + size_t threshold; + int interval_ratio; + int step_ratio; + mrb_bool iterating :1; + mrb_bool disabled :1; + mrb_bool full :1; + mrb_bool generational :1; + mrb_bool out_of_memory :1; + size_t majorgc_old_threshold; +} mrb_gc; + +MRB_API mrb_bool +mrb_object_dead_p(struct mrb_state *mrb, struct RBasic *object); + +MRB_END_DECL + +#endif /* MRUBY_GC_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/hash.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/hash.h new file mode 100644 index 000000000..1a870785a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/hash.h @@ -0,0 +1,182 @@ +/* +** mruby/hash.h - Hash class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_HASH_H +#define MRUBY_HASH_H + +#include "common.h" +#include <mruby/khash.h> + +/** + * Hash class + */ +MRB_BEGIN_DECL + +struct RHash { + MRB_OBJECT_HEADER; + struct iv_tbl *iv; + struct kh_ht *ht; +}; + +#define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v))) +#define mrb_hash_value(p) mrb_obj_value((void*)(p)) + +MRB_API mrb_value mrb_hash_new_capa(mrb_state*, mrb_int); + +/* + * Initializes a new hash. + * + * Equivalent to: + * + * Hash.new + * + * @param mrb The mruby state reference. + * @return The initialized hash. + */ +MRB_API mrb_value mrb_hash_new(mrb_state *mrb); + +/* + * Sets a keys and values to hashes. + * + * Equivalent to: + * + * hash[key] = val + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to set. + * @param val The value to set. + * @return The value. + */ +MRB_API void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val); + +/* + * Gets a value from a key. If the key is not found, the default of the + * hash is used. + * + * Equivalent to: + * + * hash[key] + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to get. + * @return The found value. + */ +MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key); + +/* + * Gets a value from a key. If the key is not found, the default parameter is + * used. + * + * Equivalent to: + * + * hash.hash_key?(key) ? hash[key] : def + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to get. + * @param def The default value. + * @return The found value. + */ +MRB_API mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def); + +/* + * Deletes hash key and value pair. + * + * Equivalent to: + * + * hash.delete(key) + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to delete. + * @return The deleted value. + */ +MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key); + +/* + * Gets an array of keys. + * + * Equivalent to: + * + * hash.keys + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return An array with the keys of the hash. + */ +MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash); +MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); + +/* + * Check if the hash is empty + * + * Equivalent to: + * + * hash.empty? + * + * @param mrb The mruby state reference. + * @param self The target hash. + * @return True if the hash is empty, false otherwise. + */ +MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self); + +/* + * Gets an array of values. + * + * Equivalent to: + * + * hash.values + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return An array with the values of the hash. + */ +MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash); + +/* + * Clears the hash. + * + * Equivalent to: + * + * hash.clear + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return The hash + */ +MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); + +/* declaration of struct kh_ht */ +/* be careful when you touch the internal */ +typedef struct { + mrb_value v; + mrb_int n; +} mrb_hash_value; + +KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE) + +/* RHASH_TBL allocates st_table if not available. */ +#define RHASH(obj) ((struct RHash*)(mrb_ptr(obj))) +#define RHASH_TBL(h) (RHASH(h)->ht) +#define RHASH_IFNONE(h) mrb_iv_get(mrb, (h), mrb_intern_lit(mrb, "ifnone")) +#define RHASH_PROCDEFAULT(h) RHASH_IFNONE(h) +MRB_API struct kh_ht * mrb_hash_tbl(mrb_state *mrb, mrb_value hash); + +#define MRB_HASH_DEFAULT 1 +#define MRB_HASH_PROC_DEFAULT 2 +#define MRB_RHASH_DEFAULT_P(h) (RHASH(h)->flags & MRB_HASH_DEFAULT) +#define MRB_RHASH_PROCDEFAULT_P(h) (RHASH(h)->flags & MRB_HASH_PROC_DEFAULT) + +/* GC functions */ +void mrb_gc_mark_hash(mrb_state*, struct RHash*); +size_t mrb_gc_mark_hash_size(mrb_state*, struct RHash*); +void mrb_gc_free_hash(mrb_state*, struct RHash*); + +MRB_END_DECL + +#endif /* MRUBY_HASH_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/irep.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/irep.h new file mode 100644 index 000000000..2717b09c3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/irep.h @@ -0,0 +1,64 @@ +/* +** mruby/irep.h - mrb_irep structure +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_IREP_H +#define MRUBY_IREP_H + +#include "common.h" +#include <mruby/compile.h> + +/** + * Compiled mruby scripts. + */ +MRB_BEGIN_DECL + +enum irep_pool_type { + IREP_TT_STRING, + IREP_TT_FIXNUM, + IREP_TT_FLOAT, +}; + +struct mrb_locals { + mrb_sym name; + uint16_t r; +}; + +/* Program data array struct */ +typedef struct mrb_irep { + uint16_t nlocals; /* Number of local variables */ + uint16_t nregs; /* Number of register variables */ + uint8_t flags; + + mrb_code *iseq; + mrb_value *pool; + mrb_sym *syms; + struct mrb_irep **reps; + + struct mrb_locals *lv; + /* debug info */ + mrb_bool own_filename; + const char *filename; + uint16_t *lines; + struct mrb_irep_debug_info* debug_info; + + int ilen, plen, slen, rlen, refcnt; + + struct mrb_irep *outer; /* Refers outer scope */ + struct RClass *target_class; +} mrb_irep; + +#define MRB_ISEQ_NO_FREE 1 + +MRB_API mrb_irep *mrb_add_irep(mrb_state *mrb); +MRB_API mrb_value mrb_load_irep(mrb_state*, const uint8_t*); +MRB_API mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*); +void mrb_irep_free(mrb_state*, struct mrb_irep*); +void mrb_irep_incref(mrb_state*, struct mrb_irep*); +void mrb_irep_decref(mrb_state*, struct mrb_irep*); + +MRB_END_DECL + +#endif /* MRUBY_IREP_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/istruct.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/istruct.h new file mode 100644 index 000000000..4d2393ccd --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/istruct.h @@ -0,0 +1,47 @@ +/* +** mruby/istruct.h - Inline structures +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_ISTRUCT_H +#define MRUBY_ISTRUCT_H + +#include "common.h" +#include <string.h> + +/** + * Inline structures that fit in RVALUE + * + * They cannot have finalizer, and cannot have instance variables. + */ +MRB_BEGIN_DECL + +#define ISTRUCT_DATA_SIZE (sizeof(void*) * 3) + +struct RIstruct { + MRB_OBJECT_HEADER; + char inline_data[ISTRUCT_DATA_SIZE]; +}; + +#define RISTRUCT(obj) ((struct RIstruct*)(mrb_ptr(obj))) +#define ISTRUCT_PTR(obj) (RISTRUCT(obj)->inline_data) + +MRB_INLINE mrb_int mrb_istruct_size() +{ + return ISTRUCT_DATA_SIZE; +} + +MRB_INLINE void* mrb_istruct_ptr(mrb_value object) +{ + return ISTRUCT_PTR(object); +} + +MRB_INLINE void mrb_istruct_copy(mrb_value dest, mrb_value src) +{ + memcpy(ISTRUCT_PTR(dest), ISTRUCT_PTR(src), ISTRUCT_DATA_SIZE); +} + +MRB_END_DECL + +#endif /* MRUBY_ISTRUCT_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/khash.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/khash.h new file mode 100644 index 000000000..9c40c6b80 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/khash.h @@ -0,0 +1,274 @@ +/* +** mruby/khash.c - Hash for mruby +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_KHASH_H +#define MRUBY_KHASH_H + +#include <string.h> + +#include <mruby.h> +#include "common.h" + +/** + * khash definitions used in mruby's hash table. + */ +MRB_BEGIN_DECL + +typedef uint32_t khint_t; +typedef khint_t khiter_t; + +#ifndef KHASH_DEFAULT_SIZE +# define KHASH_DEFAULT_SIZE 32 +#endif +#define KHASH_MIN_SIZE 8 + +#define UPPER_BOUND(x) ((x)>>2|(x)>>1) + +/* extern uint8_t __m[]; */ + +/* mask for flags */ +static const uint8_t __m_empty[] = {0x02, 0x08, 0x20, 0x80}; +static const uint8_t __m_del[] = {0x01, 0x04, 0x10, 0x40}; +static const uint8_t __m_either[] = {0x03, 0x0c, 0x30, 0xc0}; + + +#define __ac_isempty(ed_flag, i) (ed_flag[(i)/4]&__m_empty[(i)%4]) +#define __ac_isdel(ed_flag, i) (ed_flag[(i)/4]&__m_del[(i)%4]) +#define __ac_iseither(ed_flag, i) (ed_flag[(i)/4]&__m_either[(i)%4]) +#define khash_power2(v) do { \ + v--;\ + v |= v >> 1;\ + v |= v >> 2;\ + v |= v >> 4;\ + v |= v >> 8;\ + v |= v >> 16;\ + v++;\ +} while (0) +#define khash_mask(h) ((h)->n_buckets-1) +#define khash_upper_bound(h) (UPPER_BOUND((h)->n_buckets)) + +/* declare struct kh_xxx and kh_xxx_funcs + + name: hash name + khkey_t: key data type + khval_t: value data type + kh_is_map: (0: hash set / 1: hash map) +*/ +#define KHASH_DECLARE(name, khkey_t, khval_t, kh_is_map) \ + typedef struct kh_##name { \ + khint_t n_buckets; \ + khint_t size; \ + khint_t n_occupied; \ + uint8_t *ed_flags; \ + khkey_t *keys; \ + khval_t *vals; \ + } kh_##name##_t; \ + void kh_alloc_##name(mrb_state *mrb, kh_##name##_t *h); \ + kh_##name##_t *kh_init_##name##_size(mrb_state *mrb, khint_t size); \ + kh_##name##_t *kh_init_##name(mrb_state *mrb); \ + void kh_destroy_##name(mrb_state *mrb, kh_##name##_t *h); \ + void kh_clear_##name(mrb_state *mrb, kh_##name##_t *h); \ + khint_t kh_get_##name(mrb_state *mrb, kh_##name##_t *h, khkey_t key); \ + khint_t kh_put_##name(mrb_state *mrb, kh_##name##_t *h, khkey_t key, int *ret); \ + void kh_resize_##name(mrb_state *mrb, kh_##name##_t *h, khint_t new_n_buckets); \ + void kh_del_##name(mrb_state *mrb, kh_##name##_t *h, khint_t x); \ + kh_##name##_t *kh_copy_##name(mrb_state *mrb, kh_##name##_t *h); + +static inline void +kh_fill_flags(uint8_t *p, uint8_t c, size_t len) +{ + while (len-- > 0) { + *p++ = c; + } +} + +/* define kh_xxx_funcs + + name: hash name + khkey_t: key data type + khval_t: value data type + kh_is_map: (0: hash set / 1: hash map) + __hash_func: hash function + __hash_equal: hash comparation function +*/ +#define KHASH_DEFINE(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ + void kh_alloc_##name(mrb_state *mrb, kh_##name##_t *h) \ + { \ + khint_t sz = h->n_buckets; \ + size_t len = sizeof(khkey_t) + (kh_is_map ? sizeof(khval_t) : 0); \ + uint8_t *p = (uint8_t*)mrb_malloc(mrb, sizeof(uint8_t)*sz/4+len*sz); \ + h->size = h->n_occupied = 0; \ + h->keys = (khkey_t *)p; \ + h->vals = kh_is_map ? (khval_t *)(p+sizeof(khkey_t)*sz) : NULL; \ + h->ed_flags = p+len*sz; \ + kh_fill_flags(h->ed_flags, 0xaa, sz/4); \ + } \ + kh_##name##_t *kh_init_##name##_size(mrb_state *mrb, khint_t size) { \ + kh_##name##_t *h = (kh_##name##_t*)mrb_calloc(mrb, 1, sizeof(kh_##name##_t)); \ + if (size < KHASH_MIN_SIZE) \ + size = KHASH_MIN_SIZE; \ + khash_power2(size); \ + h->n_buckets = size; \ + kh_alloc_##name(mrb, h); \ + return h; \ + } \ + kh_##name##_t *kh_init_##name(mrb_state *mrb) { \ + return kh_init_##name##_size(mrb, KHASH_DEFAULT_SIZE); \ + } \ + void kh_destroy_##name(mrb_state *mrb, kh_##name##_t *h) \ + { \ + if (h) { \ + mrb_free(mrb, h->keys); \ + mrb_free(mrb, h); \ + } \ + } \ + void kh_clear_##name(mrb_state *mrb, kh_##name##_t *h) \ + { \ + (void)mrb; \ + if (h && h->ed_flags) { \ + kh_fill_flags(h->ed_flags, 0xaa, h->n_buckets/4); \ + h->size = h->n_occupied = 0; \ + } \ + } \ + khint_t kh_get_##name(mrb_state *mrb, kh_##name##_t *h, khkey_t key) \ + { \ + khint_t k = __hash_func(mrb,key) & khash_mask(h), step = 0; \ + (void)mrb; \ + while (!__ac_isempty(h->ed_flags, k)) { \ + if (!__ac_isdel(h->ed_flags, k)) { \ + if (__hash_equal(mrb,h->keys[k], key)) return k; \ + } \ + k = (k+(++step)) & khash_mask(h); \ + } \ + return kh_end(h); \ + } \ + void kh_resize_##name(mrb_state *mrb, kh_##name##_t *h, khint_t new_n_buckets) \ + { \ + if (new_n_buckets < KHASH_MIN_SIZE) \ + new_n_buckets = KHASH_MIN_SIZE; \ + khash_power2(new_n_buckets); \ + { \ + kh_##name##_t hh; \ + uint8_t *old_ed_flags = h->ed_flags; \ + khkey_t *old_keys = h->keys; \ + khval_t *old_vals = h->vals; \ + khint_t old_n_buckets = h->n_buckets; \ + khint_t i; \ + hh.n_buckets = new_n_buckets; \ + kh_alloc_##name(mrb, &hh); \ + /* relocate */ \ + for (i=0 ; i<old_n_buckets ; i++) { \ + if (!__ac_iseither(old_ed_flags, i)) { \ + khint_t k = kh_put_##name(mrb, &hh, old_keys[i], NULL); \ + if (kh_is_map) kh_value(&hh,k) = old_vals[i]; \ + } \ + } \ + /* copy hh to h */ \ + *h = hh; \ + mrb_free(mrb, old_keys); \ + } \ + } \ + khint_t kh_put_##name(mrb_state *mrb, kh_##name##_t *h, khkey_t key, int *ret) \ + { \ + khint_t k, del_k, step = 0; \ + if (h->n_occupied >= khash_upper_bound(h)) { \ + kh_resize_##name(mrb, h, h->n_buckets*2); \ + } \ + k = __hash_func(mrb,key) & khash_mask(h); \ + del_k = kh_end(h); \ + while (!__ac_isempty(h->ed_flags, k)) { \ + if (!__ac_isdel(h->ed_flags, k)) { \ + if (__hash_equal(mrb,h->keys[k], key)) { \ + if (ret) *ret = 0; \ + return k; \ + } \ + } \ + else if (del_k == kh_end(h)) { \ + del_k = k; \ + } \ + k = (k+(++step)) & khash_mask(h); \ + } \ + if (del_k != kh_end(h)) { \ + /* put at del */ \ + h->keys[del_k] = key; \ + h->ed_flags[del_k/4] &= ~__m_del[del_k%4]; \ + h->size++; \ + if (ret) *ret = 2; \ + return del_k; \ + } \ + else { \ + /* put at empty */ \ + h->keys[k] = key; \ + h->ed_flags[k/4] &= ~__m_empty[k%4]; \ + h->size++; \ + h->n_occupied++; \ + if (ret) *ret = 1; \ + return k; \ + } \ + } \ + void kh_del_##name(mrb_state *mrb, kh_##name##_t *h, khint_t x) \ + { \ + (void)mrb; \ + mrb_assert(x != h->n_buckets && !__ac_iseither(h->ed_flags, x)); \ + h->ed_flags[x/4] |= __m_del[x%4]; \ + h->size--; \ + } \ + kh_##name##_t *kh_copy_##name(mrb_state *mrb, kh_##name##_t *h) \ + { \ + kh_##name##_t *h2; \ + khiter_t k, k2; \ + \ + h2 = kh_init_##name(mrb); \ + for (k = kh_begin(h); k != kh_end(h); k++) { \ + if (kh_exist(h, k)) { \ + k2 = kh_put_##name(mrb, h2, kh_key(h, k), NULL); \ + if (kh_is_map) kh_value(h2, k2) = kh_value(h, k); \ + } \ + } \ + return h2; \ + } + + +#define khash_t(name) kh_##name##_t + +#define kh_init_size(name,mrb,size) kh_init_##name##_size(mrb,size) +#define kh_init(name,mrb) kh_init_##name(mrb) +#define kh_destroy(name, mrb, h) kh_destroy_##name(mrb, h) +#define kh_clear(name, mrb, h) kh_clear_##name(mrb, h) +#define kh_resize(name, mrb, h, s) kh_resize_##name(mrb, h, s) +#define kh_put(name, mrb, h, k) kh_put_##name(mrb, h, k, NULL) +#define kh_put2(name, mrb, h, k, r) kh_put_##name(mrb, h, k, r) +#define kh_get(name, mrb, h, k) kh_get_##name(mrb, h, k) +#define kh_del(name, mrb, h, k) kh_del_##name(mrb, h, k) +#define kh_copy(name, mrb, h) kh_copy_##name(mrb, h) + +#define kh_exist(h, x) (!__ac_iseither((h)->ed_flags, (x))) +#define kh_key(h, x) ((h)->keys[x]) +#define kh_val(h, x) ((h)->vals[x]) +#define kh_value(h, x) ((h)->vals[x]) +#define kh_begin(h) (khint_t)(0) +#define kh_end(h) ((h)->n_buckets) +#define kh_size(h) ((h)->size) +#define kh_n_buckets(h) ((h)->n_buckets) + +#define kh_int_hash_func(mrb,key) (khint_t)((key)^((key)<<2)^((key)>>2)) +#define kh_int_hash_equal(mrb,a, b) (a == b) +#define kh_int64_hash_func(mrb,key) (khint_t)((key)>>33^(key)^(key)<<11) +#define kh_int64_hash_equal(mrb,a, b) (a == b) +static inline khint_t __ac_X31_hash_string(const char *s) +{ + khint_t h = *s; + if (h) for (++s ; *s; ++s) h = (h << 5) - h + *s; + return h; +} +#define kh_str_hash_func(mrb,key) __ac_X31_hash_string(key) +#define kh_str_hash_equal(mrb,a, b) (strcmp(a, b) == 0) + +typedef const char *kh_cstr_t; + +MRB_END_DECL + +#endif /* MRUBY_KHASH_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/numeric.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/numeric.h new file mode 100644 index 000000000..40c8c4a20 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/numeric.h @@ -0,0 +1,155 @@ +/* +** mruby/numeric.h - Numeric, Integer, Float, Fixnum class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_NUMERIC_H +#define MRUBY_NUMERIC_H + +#include "common.h" + +/** + * Numeric class and it's sub-classes. + * + * Integer, Float and Fixnum + */ +MRB_BEGIN_DECL + +#define TYPED_POSFIXABLE(f,t) ((f) <= (t)MRB_INT_MAX) +#define TYPED_NEGFIXABLE(f,t) ((f) >= (t)MRB_INT_MIN) +#define TYPED_FIXABLE(f,t) (TYPED_POSFIXABLE(f,t) && TYPED_NEGFIXABLE(f,t)) +#define POSFIXABLE(f) TYPED_POSFIXABLE(f,mrb_int) +#define NEGFIXABLE(f) TYPED_NEGFIXABLE(f,mrb_int) +#define FIXABLE(f) TYPED_FIXABLE(f,mrb_int) +#define FIXABLE_FLOAT(f) TYPED_FIXABLE(f,double) + +MRB_API mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value val); +MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base); +/* ArgumentError if format string doesn't match /%(\.[0-9]+)?[aAeEfFgG]/ */ +MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt); +MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); + +mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y); +mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y); +mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y); +mrb_value mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y); + +#ifndef __has_builtin + #define __has_builtin(x) 0 +#endif + +#if (defined(__GNUC__) && __GNUC__ >= 5) || \ + (__has_builtin(__builtin_add_overflow) && \ + __has_builtin(__builtin_sub_overflow) && \ + __has_builtin(__builtin_mul_overflow)) +# define MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS +#endif + +/* +// Clang 3.8 and 3.9 have problem compiling mruby in 32-bit mode, when MRB_INT64 is set +// because of missing __mulodi4 and similar functions in its runtime. We need to use custom +// implementation for them. +*/ +#ifdef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS +#if defined(__clang__) && (__clang_major__ == 3) && (__clang_minor__ >= 8) && \ + defined(MRB_32BIT) && defined(MRB_INT64) +#undef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS +#endif +#endif + +#ifdef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS + +#ifndef MRB_WORD_BOXING +# define WBCHK(x) 0 +#else +# define WBCHK(x) !FIXABLE(x) +#endif + +static inline mrb_bool +mrb_int_add_overflow(mrb_int augend, mrb_int addend, mrb_int *sum) +{ + return __builtin_add_overflow(augend, addend, sum) || WBCHK(*sum); +} + +static inline mrb_bool +mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference) +{ + return __builtin_sub_overflow(minuend, subtrahend, difference) || WBCHK(*difference); +} + +static inline mrb_bool +mrb_int_mul_overflow(mrb_int multiplier, mrb_int multiplicand, mrb_int *product) +{ + return __builtin_mul_overflow(multiplier, multiplicand, product) || WBCHK(*product); +} + +#undef WBCHK + +#else + +#define MRB_UINT_MAKE2(n) uint ## n ## _t +#define MRB_UINT_MAKE(n) MRB_UINT_MAKE2(n) +#define mrb_uint MRB_UINT_MAKE(MRB_INT_BIT) + +#define MRB_INT_OVERFLOW_MASK ((mrb_uint)1 << (MRB_INT_BIT - 1 - MRB_FIXNUM_SHIFT)) + +static inline mrb_bool +mrb_int_add_overflow(mrb_int augend, mrb_int addend, mrb_int *sum) +{ + mrb_uint x = (mrb_uint)augend; + mrb_uint y = (mrb_uint)addend; + mrb_uint z = (mrb_uint)(x + y); + *sum = (mrb_int)z; + return !!(((x ^ z) & (y ^ z)) & MRB_INT_OVERFLOW_MASK); +} + +static inline mrb_bool +mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference) +{ + mrb_uint x = (mrb_uint)minuend; + mrb_uint y = (mrb_uint)subtrahend; + mrb_uint z = (mrb_uint)(x - y); + *difference = (mrb_int)z; + return !!(((x ^ z) & (~y ^ z)) & MRB_INT_OVERFLOW_MASK); +} + +static inline mrb_bool +mrb_int_mul_overflow(mrb_int multiplier, mrb_int multiplicand, mrb_int *product) +{ +#if MRB_INT_BIT == 32 + int64_t n = (int64_t)multiplier * multiplicand; + *product = (mrb_int)n; + return !FIXABLE(n); +#else + if (multiplier > 0) { + if (multiplicand > 0) { + if (multiplier > MRB_INT_MAX / multiplicand) return TRUE; + } + else { + if (multiplicand < MRB_INT_MAX / multiplier) return TRUE; + } + } + else { + if (multiplicand > 0) { + if (multiplier < MRB_INT_MAX / multiplicand) return TRUE; + } + else { + if (multiplier != 0 && multiplicand < MRB_INT_MAX / multiplier) return TRUE; + } + } + *product = multiplier * multiplicand; + return FALSE; +#endif +} + +#undef MRB_INT_OVERFLOW_MASK +#undef mrb_uint +#undef MRB_UINT_MAKE +#undef MRB_UINT_MAKE2 + +#endif + +MRB_END_DECL + +#endif /* MRUBY_NUMERIC_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/object.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/object.h new file mode 100644 index 000000000..9347981d4 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/object.h @@ -0,0 +1,43 @@ +/* +** mruby/object.h - mruby object definition +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_OBJECT_H +#define MRUBY_OBJECT_H + +#define MRB_OBJECT_HEADER \ + enum mrb_vtype tt:8;\ + uint32_t color:3;\ + uint32_t flags:21;\ + struct RClass *c;\ + struct RBasic *gcnext + +#define MRB_FLAG_TEST(obj, flag) ((obj)->flags & flag) + + +struct RBasic { + MRB_OBJECT_HEADER; +}; +#define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v))) + +#define MRB_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN) +#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN) +#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN) + +struct RObject { + MRB_OBJECT_HEADER; + struct iv_tbl *iv; +}; +#define mrb_obj_ptr(v) ((struct RObject*)(mrb_ptr(v))) + +#define mrb_immediate_p(x) (mrb_type(x) < MRB_TT_HAS_BASIC) +#define mrb_special_const_p(x) mrb_immediate_p(x) + +struct RFiber { + MRB_OBJECT_HEADER; + struct mrb_context *cxt; +}; + +#endif /* MRUBY_OBJECT_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/opcode.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/opcode.h new file mode 100644 index 000000000..9a5116275 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/opcode.h @@ -0,0 +1,161 @@ +/* +** mruby/opcode.h - RiteVM operation codes +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_OPCODE_H +#define MRUBY_OPCODE_H + +#define MAXARG_Bx (0xffff) +#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */ + +/* instructions: packed 32 bit */ +/* ------------------------------- */ +/* A:B:C:OP = 9: 9: 7: 7 */ +/* A:Bx:OP = 9:16: 7 */ +/* Ax:OP = 25: 7 */ +/* A:Bz:Cz:OP = 9:14: 2: 7 */ + +#define GET_OPCODE(i) ((int)(((mrb_code)(i)) & 0x7f)) +#define GETARG_A(i) ((int)((((mrb_code)(i)) >> 23) & 0x1ff)) +#define GETARG_B(i) ((int)((((mrb_code)(i)) >> 14) & 0x1ff)) +#define GETARG_C(i) ((int)((((mrb_code)(i)) >> 7) & 0x7f)) +#define GETARG_Bx(i) ((int)((((mrb_code)(i)) >> 7) & 0xffff)) +#define GETARG_sBx(i) ((int)(GETARG_Bx(i)-MAXARG_sBx)) +#define GETARG_Ax(i) ((int32_t)((((mrb_code)(i)) >> 7) & 0x1ffffff)) +#define GETARG_UNPACK_b(i,n1,n2) ((int)((((mrb_code)(i)) >> (7+(n2))) & (((1<<(n1))-1)))) +#define GETARG_UNPACK_c(i,n1,n2) ((int)((((mrb_code)(i)) >> 7) & (((1<<(n2))-1)))) +#define GETARG_b(i) GETARG_UNPACK_b(i,14,2) +#define GETARG_c(i) GETARG_UNPACK_c(i,14,2) + +#define MKOPCODE(op) ((op) & 0x7f) +#define MKARG_A(c) ((mrb_code)((c) & 0x1ff) << 23) +#define MKARG_B(c) ((mrb_code)((c) & 0x1ff) << 14) +#define MKARG_C(c) (((c) & 0x7f) << 7) +#define MKARG_Bx(v) ((mrb_code)((v) & 0xffff) << 7) +#define MKARG_sBx(v) MKARG_Bx((v)+MAXARG_sBx) +#define MKARG_Ax(v) ((mrb_code)((v) & 0x1ffffff) << 7) +#define MKARG_PACK(b,n1,c,n2) ((((b) & ((1<<n1)-1)) << (7+n2))|(((c) & ((1<<n2)-1)) << 7)) +#define MKARG_bc(b,c) MKARG_PACK(b,14,c,2) + +#define MKOP_A(op,a) (MKOPCODE(op)|MKARG_A(a)) +#define MKOP_AB(op,a,b) (MKOP_A(op,a)|MKARG_B(b)) +#define MKOP_ABC(op,a,b,c) (MKOP_AB(op,a,b)|MKARG_C(c)) +#define MKOP_ABx(op,a,bx) (MKOP_A(op,a)|MKARG_Bx(bx)) +#define MKOP_Bx(op,bx) (MKOPCODE(op)|MKARG_Bx(bx)) +#define MKOP_sBx(op,sbx) (MKOPCODE(op)|MKARG_sBx(sbx)) +#define MKOP_AsBx(op,a,sbx) (MKOP_A(op,a)|MKARG_sBx(sbx)) +#define MKOP_Ax(op,ax) (MKOPCODE(op)|MKARG_Ax(ax)) +#define MKOP_Abc(op,a,b,c) (MKOP_A(op,a)|MKARG_bc(b,c)) + +enum { + /*----------------------------------------------------------------------- + operation code operand description + ------------------------------------------------------------------------*/ + OP_NOP=0,/* */ + OP_MOVE,/* A B R(A) := R(B) */ + OP_LOADL,/* A Bx R(A) := Pool(Bx) */ + OP_LOADI,/* A sBx R(A) := sBx */ + OP_LOADSYM,/* A Bx R(A) := Syms(Bx) */ + OP_LOADNIL,/* A R(A) := nil */ + OP_LOADSELF,/* A R(A) := self */ + OP_LOADT,/* A R(A) := true */ + OP_LOADF,/* A R(A) := false */ + + OP_GETGLOBAL,/* A Bx R(A) := getglobal(Syms(Bx)) */ + OP_SETGLOBAL,/* A Bx setglobal(Syms(Bx), R(A)) */ + OP_GETSPECIAL,/*A Bx R(A) := Special[Bx] */ + OP_SETSPECIAL,/*A Bx Special[Bx] := R(A) */ + OP_GETIV,/* A Bx R(A) := ivget(Syms(Bx)) */ + OP_SETIV,/* A Bx ivset(Syms(Bx),R(A)) */ + OP_GETCV,/* A Bx R(A) := cvget(Syms(Bx)) */ + OP_SETCV,/* A Bx cvset(Syms(Bx),R(A)) */ + OP_GETCONST,/* A Bx R(A) := constget(Syms(Bx)) */ + OP_SETCONST,/* A Bx constset(Syms(Bx),R(A)) */ + OP_GETMCNST,/* A Bx R(A) := R(A)::Syms(Bx) */ + OP_SETMCNST,/* A Bx R(A+1)::Syms(Bx) := R(A) */ + OP_GETUPVAR,/* A B C R(A) := uvget(B,C) */ + OP_SETUPVAR,/* A B C uvset(B,C,R(A)) */ + + OP_JMP,/* sBx pc+=sBx */ + OP_JMPIF,/* A sBx if R(A) pc+=sBx */ + OP_JMPNOT,/* A sBx if !R(A) pc+=sBx */ + OP_ONERR,/* sBx rescue_push(pc+sBx) */ + OP_RESCUE,/* A B C if A (if C exc=R(A) else R(A) := exc); + if B R(B) := exc.isa?(R(B)); clear(exc) */ + OP_POPERR,/* A A.times{rescue_pop()} */ + OP_RAISE,/* A raise(R(A)) */ + OP_EPUSH,/* Bx ensure_push(SEQ[Bx]) */ + OP_EPOP,/* A A.times{ensure_pop().call} */ + + OP_SEND,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ + OP_SENDB,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/ + OP_FSEND,/* A B C R(A) := fcall(R(A),Syms(B),R(A+1),...,R(A+C-1)) */ + OP_CALL,/* A R(A) := self.call(frame.argc, frame.argv) */ + OP_SUPER,/* A C R(A) := super(R(A+1),... ,R(A+C+1)) */ + OP_ARGARY,/* A Bx R(A) := argument array (16=6:1:5:4) */ + OP_ENTER,/* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */ + OP_KARG,/* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */ + OP_KDICT,/* A C R(A) := kdict */ + + OP_RETURN,/* A B return R(A) (B=normal,in-block return/break) */ + OP_TAILCALL,/* A B C return call(R(A),Syms(B),*R(C)) */ + OP_BLKPUSH,/* A Bx R(A) := block (16=6:1:5:4) */ + + OP_ADD,/* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1) */ + OP_ADDI,/* A B C R(A) := R(A)+C (Syms[B]=:+) */ + OP_SUB,/* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1) */ + OP_SUBI,/* A B C R(A) := R(A)-C (Syms[B]=:-) */ + OP_MUL,/* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1) */ + OP_DIV,/* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1) */ + OP_EQ,/* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1) */ + OP_LT,/* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1) */ + OP_LE,/* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1) */ + OP_GT,/* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1) */ + OP_GE,/* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1) */ + + OP_ARRAY,/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ + OP_ARYCAT,/* A B ary_cat(R(A),R(B)) */ + OP_ARYPUSH,/* A B ary_push(R(A),R(B)) */ + OP_AREF,/* A B C R(A) := R(B)[C] */ + OP_ASET,/* A B C R(B)[C] := R(A) */ + OP_APOST,/* A B C *R(A),R(A+1)..R(A+C) := R(A) */ + + OP_STRING,/* A Bx R(A) := str_dup(Lit(Bx)) */ + OP_STRCAT,/* A B str_cat(R(A),R(B)) */ + + OP_HASH,/* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ + OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cz) */ + OP_RANGE,/* A B C R(A) := range_new(R(B),R(B+1),C) */ + + OP_OCLASS,/* A R(A) := ::Object */ + OP_CLASS,/* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ + OP_MODULE,/* A B R(A) := newmodule(R(A),Syms(B)) */ + OP_EXEC,/* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ + OP_METHOD,/* A B R(A).newmethod(Syms(B),R(A+1)) */ + OP_SCLASS,/* A B R(A) := R(B).singleton_class */ + OP_TCLASS,/* A R(A) := target_class */ + + OP_DEBUG,/* A B C print R(A),R(B),R(C) */ + OP_STOP,/* stop VM */ + OP_ERR,/* Bx raise RuntimeError with message Lit(Bx) */ + + OP_RSVD1,/* reserved instruction #1 */ + OP_RSVD2,/* reserved instruction #2 */ + OP_RSVD3,/* reserved instruction #3 */ + OP_RSVD4,/* reserved instruction #4 */ + OP_RSVD5,/* reserved instruction #5 */ +}; + +#define OP_L_STRICT 1 +#define OP_L_CAPTURE 2 +#define OP_L_METHOD OP_L_STRICT +#define OP_L_LAMBDA (OP_L_STRICT|OP_L_CAPTURE) +#define OP_L_BLOCK OP_L_CAPTURE + +#define OP_R_NORMAL 0 +#define OP_R_BREAK 1 +#define OP_R_RETURN 2 + +#endif /* MRUBY_OPCODE_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/proc.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/proc.h new file mode 100644 index 000000000..9c2666289 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/proc.h @@ -0,0 +1,83 @@ +/* +** mruby/proc.h - Proc class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_PROC_H +#define MRUBY_PROC_H + +#include "common.h" +#include <mruby/irep.h> + +/** + * Proc class + */ +MRB_BEGIN_DECL + +struct REnv { + MRB_OBJECT_HEADER; + mrb_value *stack; + ptrdiff_t cioff; + union { + mrb_sym mid; + struct mrb_context *c; + } cxt; +}; + +#define MRB_SET_ENV_STACK_LEN(e,len) (e)->flags = (unsigned int)(len) +#define MRB_ENV_STACK_LEN(e) ((mrb_int)(e)->flags) +#define MRB_ENV_UNSHARE_STACK(e) ((e)->cioff = -1) +#define MRB_ENV_STACK_SHARED_P(e) ((e)->cioff >= 0) + +MRB_API void mrb_env_unshare(mrb_state*, struct REnv*); + +struct RProc { + MRB_OBJECT_HEADER; + union { + mrb_irep *irep; + mrb_func_t func; + } body; + struct RClass *target_class; + struct REnv *env; +}; + +/* aspec access */ +#define MRB_ASPEC_REQ(a) (((a) >> 18) & 0x1f) +#define MRB_ASPEC_OPT(a) (((a) >> 13) & 0x1f) +#define MRB_ASPEC_REST(a) (((a) >> 12) & 0x1) +#define MRB_ASPEC_POST(a) (((a) >> 7) & 0x1f) +#define MRB_ASPEC_KEY(a) (((a) >> 2) & 0x1f) +#define MRB_ASPEC_KDICT(a) ((a) & (1<<1)) +#define MRB_ASPEC_BLOCK(a) ((a) & 1) + +#define MRB_PROC_CFUNC 128 +#define MRB_PROC_CFUNC_P(p) (((p)->flags & MRB_PROC_CFUNC) != 0) +#define MRB_PROC_STRICT 256 +#define MRB_PROC_STRICT_P(p) (((p)->flags & MRB_PROC_STRICT) != 0) +#define MRB_PROC_ORPHAN 512 +#define MRB_PROC_ORPHAN_P(p) (((p)->flags & MRB_PROC_ORPHAN) != 0) + +#define mrb_proc_ptr(v) ((struct RProc*)(mrb_ptr(v))) + +struct RProc *mrb_proc_new(mrb_state*, mrb_irep*); +struct RProc *mrb_closure_new(mrb_state*, mrb_irep*); +MRB_API struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t); +MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals); +void mrb_proc_copy(struct RProc *a, struct RProc *b); + +/* implementation of #send method */ +MRB_API mrb_value mrb_f_send(mrb_state *mrb, mrb_value self); + +/* following functions are defined in mruby-proc-ext so please include it when using */ +MRB_API struct RProc *mrb_proc_new_cfunc_with_env(mrb_state*, mrb_func_t, mrb_int, const mrb_value*); +MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state*, mrb_int); +/* old name */ +#define mrb_cfunc_env_get(mrb, idx) mrb_proc_cfunc_env_get(mrb, idx) + +#include <mruby/khash.h> +KHASH_DECLARE(mt, mrb_sym, struct RProc*, TRUE) + +MRB_END_DECL + +#endif /* MRUBY_PROC_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/range.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/range.h new file mode 100644 index 000000000..b166e586b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/range.h @@ -0,0 +1,49 @@ +/* +** mruby/range.h - Range class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_RANGE_H +#define MRUBY_RANGE_H + +#include "common.h" + +/** + * Range class + */ +MRB_BEGIN_DECL + +typedef struct mrb_range_edges { + mrb_value beg; + mrb_value end; +} mrb_range_edges; + +struct RRange { + MRB_OBJECT_HEADER; + mrb_range_edges *edges; + mrb_bool excl : 1; +}; + +MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v); +#define mrb_range_raw_ptr(v) ((struct RRange*)mrb_ptr(v)) +#define mrb_range_value(p) mrb_obj_value((void*)(p)) + +/* + * Initializes a Range. + * + * If the third parameter is FALSE then it includes the last value in the range. + * If the third parameter is TRUE then it excludes the last value in the range. + * + * @param start the beginning value. + * @param end the ending value. + * @param exclude represents the inclusion or exclusion of the last value. + */ +MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, mrb_bool exclude); + +MRB_API mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); +mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)); + +MRB_END_DECL + +#endif /* MRUBY_RANGE_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/re.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/re.h new file mode 100644 index 000000000..1d09d06c9 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/re.h @@ -0,0 +1,16 @@ +/* +** mruby/re.h - Regexp class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_RE_H +#define MRUBY_RE_H + +MRB_BEGIN_DECL + +#define REGEXP_CLASS "Regexp" + +MRB_END_DECL + +#endif /* RE_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/string.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/string.h new file mode 100644 index 000000000..df6fb25c3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/string.h @@ -0,0 +1,430 @@ +/* +** mruby/string.h - String class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_STRING_H +#define MRUBY_STRING_H + +#include "common.h" + +/** + * String class + */ +MRB_BEGIN_DECL + +extern const char mrb_digitmap[]; + +#define RSTRING_EMBED_LEN_MAX ((mrb_int)(sizeof(void*) * 3 - 1)) + +struct RString { + MRB_OBJECT_HEADER; + union { + struct { + mrb_int len; + union { + mrb_int capa; + struct mrb_shared_string *shared; + } aux; + char *ptr; + } heap; + char ary[RSTRING_EMBED_LEN_MAX + 1]; + } as; +}; + +#define RSTR_EMBED_P(s) ((s)->flags & MRB_STR_EMBED) +#define RSTR_SET_EMBED_FLAG(s) ((s)->flags |= MRB_STR_EMBED) +#define RSTR_UNSET_EMBED_FLAG(s) ((s)->flags &= ~(MRB_STR_EMBED|MRB_STR_EMBED_LEN_MASK)) +#define RSTR_SET_EMBED_LEN(s, n) do {\ + size_t tmp_n = (n);\ + s->flags &= ~MRB_STR_EMBED_LEN_MASK;\ + s->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\ +} while (0) +#define RSTR_SET_LEN(s, n) do {\ + if (RSTR_EMBED_P(s)) {\ + RSTR_SET_EMBED_LEN((s),(n));\ + }\ + else {\ + s->as.heap.len = (mrb_int)(n);\ + }\ +} while (0) +#define RSTR_EMBED_LEN(s)\ + (mrb_int)(((s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT) +#define RSTR_PTR(s) ((RSTR_EMBED_P(s)) ? (s)->as.ary : (s)->as.heap.ptr) +#define RSTR_LEN(s) ((RSTR_EMBED_P(s)) ? RSTR_EMBED_LEN(s) : (s)->as.heap.len) +#define RSTR_CAPA(s) (RSTR_EMBED_P(s) ? RSTRING_EMBED_LEN_MAX : (s)->as.heap.aux.capa) + +#define RSTR_SHARED_P(s) ((s)->flags & MRB_STR_SHARED) +#define RSTR_SET_SHARED_FLAG(s) ((s)->flags |= MRB_STR_SHARED) +#define RSTR_UNSET_SHARED_FLAG(s) ((s)->flags &= ~MRB_STR_SHARED) + +#define RSTR_NOFREE_P(s) ((s)->flags & MRB_STR_NOFREE) +#define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE) +#define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE) + +/* + * Returns a pointer from a Ruby string + */ +#define mrb_str_ptr(s) ((struct RString*)(mrb_ptr(s))) +#define RSTRING(s) mrb_str_ptr(s) +#define RSTRING_PTR(s) RSTR_PTR(RSTRING(s)) +#define RSTRING_EMBED_LEN(s) RSTR_EMBED_LEN(RSTRING(s)) +#define RSTRING_LEN(s) RSTR_LEN(RSTRING(s)) +#define RSTRING_CAPA(s) RSTR_CAPA(RSTRING(s)) +#define RSTRING_END(s) (RSTRING_PTR(s) + RSTRING_LEN(s)) +MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); + +#define MRB_STR_SHARED 1 +#define MRB_STR_NOFREE 2 +#define MRB_STR_NO_UTF 8 +#define MRB_STR_EMBED 16 +#define MRB_STR_EMBED_LEN_MASK 0x3e0 +#define MRB_STR_EMBED_LEN_SHIFT 5 + +void mrb_gc_free_str(mrb_state*, struct RString*); +MRB_API void mrb_str_modify(mrb_state*, struct RString*); + +/* + * Finds the index of a substring in a string + */ +MRB_API mrb_int mrb_str_index(mrb_state*, mrb_value, const char*, mrb_int, mrb_int); +#define mrb_str_index_lit(mrb, str, lit, off) mrb_str_index(mrb, str, lit, mrb_strlen_lit(lit), off); + +/* + * Appends self to other. Returns self as a concatnated string. + * + * + * Example: + * + * !!!c + * int + * main(int argc, + * char **argv) + * { + * // Variable declarations. + * mrb_value str1; + * mrb_value str2; + * + * mrb_state *mrb = mrb_open(); + * if (!mrb) + * { + * // handle error + * } + * + * // Creates new Ruby strings. + * str1 = mrb_str_new_lit(mrb, "abc"); + * str2 = mrb_str_new_lit(mrb, "def"); + * + * // Concatnates str2 to str1. + * mrb_str_concat(mrb, str1, str2); + * + * // Prints new Concatnated Ruby string. + * mrb_p(mrb, str1); + * + * mrb_close(mrb); + * return 0; + * } + * + * + * Result: + * + * => "abcdef" + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] self String to concatenate. + * @param [mrb_value] other String to append to self. + * @return [mrb_value] Returns a new String appending other to self. + */ +MRB_API void mrb_str_concat(mrb_state*, mrb_value, mrb_value); + +/* + * Adds two strings together. + * + * + * Example: + * + * !!!c + * int + * main(int argc, + * char **argv) + * { + * // Variable declarations. + * mrb_value a; + * mrb_value b; + * mrb_value c; + * + * mrb_state *mrb = mrb_open(); + * if (!mrb) + * { + * // handle error + * } + * + * // Creates two Ruby strings from the passed in C strings. + * a = mrb_str_new_lit(mrb, "abc"); + * b = mrb_str_new_lit(mrb, "def"); + * + * // Prints both C strings. + * mrb_p(mrb, a); + * mrb_p(mrb, b); + * + * // Concatnates both Ruby strings. + * c = mrb_str_plus(mrb, a, b); + * + * // Prints new Concatnated Ruby string. + * mrb_p(mrb, c); + * + * mrb_close(mrb); + * return 0; + * } + * + * + * Result: + * + * => "abc" # First string + * => "def" # Second string + * => "abcdef" # First & Second concatnated. + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] a First string to concatenate. + * @param [mrb_value] b Second string to concatenate. + * @return [mrb_value] Returns a new String containing a concatenated to b. + */ +MRB_API mrb_value mrb_str_plus(mrb_state*, mrb_value, mrb_value); + +/* + * Converts pointer into a Ruby string. + * + * @param [mrb_state] mrb The current mruby state. + * @param [void*] p The pointer to convert to Ruby string. + * @return [mrb_value] Returns a new Ruby String. + */ +MRB_API mrb_value mrb_ptr_to_str(mrb_state *, void*); + +/* + * Returns an object as a Ruby string. + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] obj An object to return as a Ruby string. + * @return [mrb_value] An object as a Ruby string. + */ +MRB_API mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj); + +/* + * Resizes the string's length. Returns the amount of characters + * in the specified by len. + * + * Example: + * + * !!!c + * int + * main(int argc, + * char **argv) + * { + * // Variable declaration. + * mrb_value str; + * + * mrb_state *mrb = mrb_open(); + * if (!mrb) + * { + * // handle error + * } + * // Creates a new string. + * str = mrb_str_new_lit(mrb, "Hello, world!"); + * // Returns 5 characters of + * mrb_str_resize(mrb, str, 5); + * mrb_p(mrb, str); + * + * mrb_close(mrb); + * return 0; + * } + * + * Result: + * + * => "Hello" + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str The Ruby string to resize. + * @param [mrb_value] len The length. + * @return [mrb_value] An object as a Ruby string. + */ +MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len); + +/* + * Returns a sub string. + * + * Example: + * + * !!!c + * int + * main(int argc, + * char const **argv) + * { + * // Variable declarations. + * mrb_value str1; + * mrb_value str2; + * + * mrb_state *mrb = mrb_open(); + * if (!mrb) + * { + * // handle error + * } + * // Creates new string. + * str1 = mrb_str_new_lit(mrb, "Hello, world!"); + * // Returns a sub-string within the range of 0..2 + * str2 = mrb_str_substr(mrb, str1, 0, 2); + * + * // Prints sub-string. + * mrb_p(mrb, str2); + * + * mrb_close(mrb); + * return 0; + * } + * + * Result: + * + * => "He" + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @param [mrb_int] beg The beginning point of the sub-string. + * @param [mrb_int] len The end point of the sub-string. + * @return [mrb_value] An object as a Ruby sub-string. + */ +MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); + +/* + * Returns a Ruby string type. + * + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @return [mrb_value] A Ruby string. + */ +MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str); + +MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str); +MRB_API mrb_value mrb_str_new_capa(mrb_state *mrb, size_t capa); +MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa); + +MRB_API const char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr); +MRB_API const char *mrb_string_value_ptr(mrb_state *mrb, mrb_value str); +/* + * Returns the length of the Ruby string. + * + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @return [mrb_int] The length of the passed in Ruby string. + */ +MRB_API mrb_int mrb_string_value_len(mrb_state *mrb, mrb_value str); + +/* + * Duplicates a string object. + * + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @return [mrb_value] Duplicated Ruby string. + */ +MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str); + +/* + * Returns a symbol from a passed in Ruby string. + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] self Ruby string. + * @return [mrb_value] A symbol. + */ +MRB_API mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self); + +MRB_API mrb_value mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck); +MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck); + +/* + * Returns a converted string type. + */ +MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str); + +/* + * Returns true if the strings match and false if the strings don't match. + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str1 Ruby string to compare. + * @param [mrb_value] str2 Ruby string to compare. + * @return [mrb_value] boolean value. + */ +MRB_API mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2); + +/* + * Returns a concated string comprised of a Ruby string and a C string. + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @param [const char *] ptr A C string. + * @param [size_t] len length of C string. + * @return [mrb_value] A Ruby string. + * @see mrb_str_cat_cstr + */ +MRB_API mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len); + +/* + * Returns a concated string comprised of a Ruby string and a C string. + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @param [const char *] ptr A C string. + * @return [mrb_value] A Ruby string. + * @see mrb_str_cat + */ +MRB_API mrb_value mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr); +MRB_API mrb_value mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2); +#define mrb_str_cat_lit(mrb, str, lit) mrb_str_cat(mrb, str, lit, mrb_strlen_lit(lit)) + +/* + * Adds str2 to the end of str1. + */ +MRB_API mrb_value mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2); + +/* + * Returns 0 if both Ruby strings are equal. Returns a value < 0 if Ruby str1 is less than Ruby str2. Returns a value > 0 if Ruby str2 is greater than Ruby str1. + */ +MRB_API int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2); + +/* + * Returns a newly allocated C string from a Ruby string. + * This is an utility function to pass a Ruby string to C library functions. + * + * - Returned string does not contain any NUL characters (but terminator). + * - It raises an ArgumentError exception if Ruby string contains + * NUL characters. + * - Retured string will be freed automatically on next GC. + * - Caller can modify returned string without affecting Ruby string + * (e.g. it can be used for mkstemp(3)). + * + * @param [mrb_state *] mrb The current mruby state. + * @param [mrb_value] str Ruby string. Must be an instance of String. + * @return [char *] A newly allocated C string. + */ +MRB_API char *mrb_str_to_cstr(mrb_state *mrb, mrb_value str); + +mrb_value mrb_str_pool(mrb_state *mrb, mrb_value str); +mrb_int mrb_str_hash(mrb_state *mrb, mrb_value str); +mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str); + +/* + * Returns a printable version of str, surrounded by quote marks, with special characters escaped. + */ +mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); + +void mrb_noregexp(mrb_state *mrb, mrb_value self); +void mrb_regexp_check(mrb_state *mrb, mrb_value obj); + +/* For backward compatibility */ +#define mrb_str_cat2(mrb, str, ptr) mrb_str_cat_cstr(mrb, str, ptr) +#define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len) +#define mrb_str_buf_append(mrb, str, str2) mrb_str_cat_str(mrb, str, str2) + +MRB_END_DECL + +#endif /* MRUBY_STRING_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/throw.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/throw.h new file mode 100644 index 000000000..5d3d214e7 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/throw.h @@ -0,0 +1,55 @@ +/* +** mruby/throw.h - mruby exception throwing handler +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRB_THROW_H +#define MRB_THROW_H + +#if defined(MRB_ENABLE_CXX_ABI) +# if !defined(__cplusplus) +# error Trying to use C++ exception handling in C code +# endif +#endif + +#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus) + +#define MRB_TRY(buf) do { try { +#define MRB_CATCH(buf) } catch(mrb_jmpbuf_impl e) { if (e != (buf)->impl) { throw e; } +#define MRB_END_EXC(buf) } } while(0) + +#define MRB_THROW(buf) throw((buf)->impl) +typedef mrb_int mrb_jmpbuf_impl; + +#else + +#include <setjmp.h> + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#define MRB_SETJMP _setjmp +#define MRB_LONGJMP _longjmp +#else +#define MRB_SETJMP setjmp +#define MRB_LONGJMP longjmp +#endif + +#define MRB_TRY(buf) do { if (MRB_SETJMP((buf)->impl) == 0) { +#define MRB_CATCH(buf) } else { +#define MRB_END_EXC(buf) } } while(0) + +#define MRB_THROW(buf) MRB_LONGJMP((buf)->impl, 1); +#define mrb_jmpbuf_impl jmp_buf + +#endif + +struct mrb_jmpbuf { + mrb_jmpbuf_impl impl; + +#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus) + static mrb_int jmpbuf_id; + mrb_jmpbuf() : impl(jmpbuf_id++) {} +#endif +}; + +#endif /* MRB_THROW_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/value.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/value.h new file mode 100644 index 000000000..98c68d657 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/value.h @@ -0,0 +1,303 @@ +/* +** mruby/value.h - mruby value definitions +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_VALUE_H +#define MRUBY_VALUE_H + +#include "common.h" + +/** + * MRuby Value definition functions and macros. + */ +MRB_BEGIN_DECL + +typedef uint32_t mrb_sym; +typedef uint8_t mrb_bool; +struct mrb_state; + +#if defined(MRB_INT16) && defined(MRB_INT64) +# error "You can't define MRB_INT16 and MRB_INT64 at the same time." +#endif + +#if defined _MSC_VER && _MSC_VER < 1800 +# define PRIo64 "llo" +# define PRId64 "lld" +# define PRIx64 "llx" +# define PRIo16 "ho" +# define PRId16 "hd" +# define PRIx16 "hx" +# define PRIo32 "o" +# define PRId32 "d" +# define PRIx32 "x" +#else +# include <inttypes.h> +#endif + +#if defined(MRB_INT64) + typedef int64_t mrb_int; +# define MRB_INT_BIT 64 +# define MRB_INT_MIN (INT64_MIN>>MRB_FIXNUM_SHIFT) +# define MRB_INT_MAX (INT64_MAX>>MRB_FIXNUM_SHIFT) +# define MRB_PRIo PRIo64 +# define MRB_PRId PRId64 +# define MRB_PRIx PRIx64 +#elif defined(MRB_INT16) + typedef int16_t mrb_int; +# define MRB_INT_BIT 16 +# define MRB_INT_MIN (INT16_MIN>>MRB_FIXNUM_SHIFT) +# define MRB_INT_MAX (INT16_MAX>>MRB_FIXNUM_SHIFT) +# define MRB_PRIo PRIo16 +# define MRB_PRId PRId16 +# define MRB_PRIx PRIx16 +#else + typedef int32_t mrb_int; +# define MRB_INT_BIT 32 +# define MRB_INT_MIN (INT32_MIN>>MRB_FIXNUM_SHIFT) +# define MRB_INT_MAX (INT32_MAX>>MRB_FIXNUM_SHIFT) +# define MRB_PRIo PRIo32 +# define MRB_PRId PRId32 +# define MRB_PRIx PRIx32 +#endif + + +MRB_API double mrb_float_read(const char*, char**); +#ifdef MRB_USE_FLOAT + typedef float mrb_float; +#else + typedef double mrb_float; +#endif + +#if defined _MSC_VER && _MSC_VER < 1900 +# ifndef __cplusplus +# define inline __inline +# endif +# include <stdarg.h> +MRB_API int mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg); +MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...); +# define vsnprintf(s, n, format, arg) mrb_msvc_vsnprintf(s, n, format, arg) +# define snprintf(s, n, format, ...) mrb_msvc_snprintf(s, n, format, __VA_ARGS__) +# if _MSC_VER < 1800 +# include <float.h> +# define isfinite(n) _finite(n) +# define isnan _isnan +# define isinf(n) (!_finite(n) && !_isnan(n)) +# define signbit(n) (_copysign(1.0, (n)) < 0.0) +static const unsigned int IEEE754_INFINITY_BITS_SINGLE = 0x7F800000; +# define INFINITY (*(float *)&IEEE754_INFINITY_BITS_SINGLE) +# define NAN ((float)(INFINITY - INFINITY)) +# endif +#endif + +enum mrb_vtype { + MRB_TT_FALSE = 0, /* 0 */ + MRB_TT_FREE, /* 1 */ + MRB_TT_TRUE, /* 2 */ + MRB_TT_FIXNUM, /* 3 */ + MRB_TT_SYMBOL, /* 4 */ + MRB_TT_UNDEF, /* 5 */ + MRB_TT_FLOAT, /* 6 */ + MRB_TT_CPTR, /* 7 */ + MRB_TT_OBJECT, /* 8 */ + MRB_TT_CLASS, /* 9 */ + MRB_TT_MODULE, /* 10 */ + MRB_TT_ICLASS, /* 11 */ + MRB_TT_SCLASS, /* 12 */ + MRB_TT_PROC, /* 13 */ + MRB_TT_ARRAY, /* 14 */ + MRB_TT_HASH, /* 15 */ + MRB_TT_STRING, /* 16 */ + MRB_TT_RANGE, /* 17 */ + MRB_TT_EXCEPTION, /* 18 */ + MRB_TT_FILE, /* 19 */ + MRB_TT_ENV, /* 20 */ + MRB_TT_DATA, /* 21 */ + MRB_TT_FIBER, /* 22 */ + MRB_TT_ISTRUCT, /* 23 */ + MRB_TT_BREAK, /* 24 */ + MRB_TT_MAXDEFINE /* 25 */ +}; + +#include <mruby/object.h> + +#ifdef MRB_DOCUMENTATION_BLOCK + +/** + * @abstract + * MRuby value boxing. + * + * Actual implementation depends on configured boxing type. + * + * @see mruby/boxing_no.h Default boxing representation + * @see mruby/boxing_word.h Word representation + * @see mruby/boxing_nan.h Boxed double representation + */ +typedef void mrb_value; + +#endif + +#if defined(MRB_NAN_BOXING) +#include "boxing_nan.h" +#elif defined(MRB_WORD_BOXING) +#include "boxing_word.h" +#else +#include "boxing_no.h" +#endif + +#ifndef mrb_fixnum_p +#define mrb_fixnum_p(o) (mrb_type(o) == MRB_TT_FIXNUM) +#endif +#ifndef mrb_undef_p +#define mrb_undef_p(o) (mrb_type(o) == MRB_TT_UNDEF) +#endif +#ifndef mrb_nil_p +#define mrb_nil_p(o) (mrb_type(o) == MRB_TT_FALSE && !mrb_fixnum(o)) +#endif +#ifndef mrb_bool +#define mrb_bool(o) (mrb_type(o) != MRB_TT_FALSE) +#endif +#define mrb_float_p(o) (mrb_type(o) == MRB_TT_FLOAT) +#define mrb_symbol_p(o) (mrb_type(o) == MRB_TT_SYMBOL) +#define mrb_array_p(o) (mrb_type(o) == MRB_TT_ARRAY) +#define mrb_string_p(o) (mrb_type(o) == MRB_TT_STRING) +#define mrb_hash_p(o) (mrb_type(o) == MRB_TT_HASH) +#define mrb_cptr_p(o) (mrb_type(o) == MRB_TT_CPTR) +#define mrb_exception_p(o) (mrb_type(o) == MRB_TT_EXCEPTION) +#define mrb_test(o) mrb_bool(o) +MRB_API mrb_bool mrb_regexp_p(struct mrb_state*, mrb_value); + +/* + * Returns a float in Ruby. + */ +MRB_INLINE mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) +{ + mrb_value v; + (void) mrb; + SET_FLOAT_VALUE(mrb, v, f); + return v; +} + +static inline mrb_value +mrb_cptr_value(struct mrb_state *mrb, void *p) +{ + mrb_value v; + (void) mrb; + SET_CPTR_VALUE(mrb,v,p); + return v; +} + +/* + * Returns a fixnum in Ruby. + */ +MRB_INLINE mrb_value mrb_fixnum_value(mrb_int i) +{ + mrb_value v; + SET_INT_VALUE(v, i); + return v; +} + +static inline mrb_value +mrb_symbol_value(mrb_sym i) +{ + mrb_value v; + SET_SYM_VALUE(v, i); + return v; +} + +static inline mrb_value +mrb_obj_value(void *p) +{ + mrb_value v; + SET_OBJ_VALUE(v, (struct RBasic*)p); + mrb_assert(p == mrb_ptr(v)); + mrb_assert(((struct RBasic*)p)->tt == mrb_type(v)); + return v; +} + + +/* + * Get a nil mrb_value object. + * + * @return + * nil mrb_value object reference. + */ +MRB_INLINE mrb_value mrb_nil_value(void) +{ + mrb_value v; + SET_NIL_VALUE(v); + return v; +} + +/* + * Returns false in Ruby. + */ +MRB_INLINE mrb_value mrb_false_value(void) +{ + mrb_value v; + SET_FALSE_VALUE(v); + return v; +} + +/* + * Returns true in Ruby. + */ +MRB_INLINE mrb_value mrb_true_value(void) +{ + mrb_value v; + SET_TRUE_VALUE(v); + return v; +} + +static inline mrb_value +mrb_bool_value(mrb_bool boolean) +{ + mrb_value v; + SET_BOOL_VALUE(v, boolean); + return v; +} + +static inline mrb_value +mrb_undef_value(void) +{ + mrb_value v; + SET_UNDEF_VALUE(v); + return v; +} + +#ifdef MRB_USE_ETEXT_EDATA +#if (defined(__APPLE__) && defined(__MACH__)) +#include <mach-o/getsect.h> +static inline mrb_bool +mrb_ro_data_p(const char *p) +{ + return (const char*)get_etext() < p && p < (const char*)get_edata(); +} +#else +extern char _etext[]; +#ifdef MRB_NO_INIT_ARRAY_START +extern char _edata[]; + +static inline mrb_bool +mrb_ro_data_p(const char *p) +{ + return _etext < p && p < _edata; +} +#else +extern char __init_array_start[]; + +static inline mrb_bool +mrb_ro_data_p(const char *p) +{ + return _etext < p && p < (char*)&__init_array_start; +} +#endif +#endif +#else +# define mrb_ro_data_p(p) FALSE +#endif + +MRB_END_DECL + +#endif /* MRUBY_VALUE_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/variable.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/variable.h new file mode 100644 index 000000000..5fef83faf --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/variable.h @@ -0,0 +1,138 @@ +/* +** mruby/variable.h - mruby variables +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_VARIABLE_H +#define MRUBY_VARIABLE_H + +#include "common.h" + +/** + * Functions to access mruby variables. + */ +MRB_BEGIN_DECL + +typedef struct global_variable { + int counter; + mrb_value *data; + mrb_value (*getter)(void); + void (*setter)(void); + /* void (*marker)(); */ + /* int block_trace; */ + /* struct trace_var *trace; */ +} global_variable; + +struct global_entry { + global_variable *var; + mrb_sym id; +}; + +mrb_value mrb_vm_special_get(mrb_state*, mrb_sym); +void mrb_vm_special_set(mrb_state*, mrb_sym, mrb_value); +mrb_value mrb_vm_iv_get(mrb_state*, mrb_sym); +void mrb_vm_iv_set(mrb_state*, mrb_sym, mrb_value); +mrb_value mrb_vm_cv_get(mrb_state*, mrb_sym); +void mrb_vm_cv_set(mrb_state*, mrb_sym, mrb_value); +mrb_value mrb_vm_const_get(mrb_state*, mrb_sym); +void mrb_vm_const_set(mrb_state*, mrb_sym, mrb_value); +MRB_API mrb_value mrb_const_get(mrb_state*, mrb_value, mrb_sym); +MRB_API void mrb_const_set(mrb_state*, mrb_value, mrb_sym, mrb_value); +MRB_API mrb_bool mrb_const_defined(mrb_state*, mrb_value, mrb_sym); +MRB_API void mrb_const_remove(mrb_state*, mrb_value, mrb_sym); + +MRB_API mrb_bool mrb_iv_p(mrb_state *mrb, mrb_sym sym); +MRB_API void mrb_iv_check(mrb_state *mrb, mrb_sym sym); +MRB_API mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym); +MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); +MRB_API mrb_bool mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym); +MRB_API mrb_value mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym); +MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v); +MRB_API mrb_bool mrb_iv_defined(mrb_state*, mrb_value, mrb_sym); +MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym); +MRB_API void mrb_iv_copy(mrb_state *mrb, mrb_value dst, mrb_value src); +MRB_API mrb_bool mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id); + +/** + * Get a global variable. Will return nil if the var does not exist + * + * Example: + * + * !!!ruby + * # Ruby style + * var = $value + * + * !!!c + * // C style + * mrb_sym sym = mrb_intern_lit(mrb, "$value"); + * mrb_value var = mrb_gv_get(mrb, sym); + * + * @param mrb The mruby state reference + * @param sym The name of the global variable + * @return The value of that global variable. May be nil + */ +MRB_API mrb_value mrb_gv_get(mrb_state *mrb, mrb_sym sym); + +/** + * Set a global variable + * + * Example: + * + * !!!ruby + * # Ruby style + * $value = "foo" + * + * !!!c + * // C style + * mrb_sym sym = mrb_intern_lit(mrb, "$value"); + * mrb_gv_set(mrb, sym, mrb_str_new_lit("foo")); + * + * @param mrb The mruby state reference + * @param sym The name of the global variable + * @param val The value of the global variable + */ +MRB_API void mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value val); + +/** + * Remove a global variable. + * + * Example: + * + * !!!ruby + * # Ruby style + * $value = nil + * + * !!!c + * // C style + * mrb_sym sym = mrb_intern_lit(mrb, "$value"); + * mrb_gv_remove(mrb, sym); + * + * @param mrb The mruby state reference + * @param sym The name of the global variable + * @param val The value of the global variable + */ +MRB_API void mrb_gv_remove(mrb_state *mrb, mrb_sym sym); + +MRB_API mrb_value mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym); +MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_value v); +MRB_API void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v); +MRB_API mrb_bool mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym); +mrb_value mrb_obj_iv_inspect(mrb_state*, struct RObject*); +mrb_value mrb_mod_constants(mrb_state *mrb, mrb_value mod); +mrb_value mrb_f_global_variables(mrb_state *mrb, mrb_value self); +mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value); +mrb_value mrb_mod_class_variables(mrb_state*, mrb_value); +mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym); +mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym); + +/* GC functions */ +void mrb_gc_mark_gv(mrb_state*); +void mrb_gc_free_gv(mrb_state*); +void mrb_gc_mark_iv(mrb_state*, struct RObject*); +size_t mrb_gc_mark_iv_size(mrb_state*, struct RObject*); +void mrb_gc_free_iv(mrb_state*, struct RObject*); + +MRB_END_DECL + +#endif /* MRUBY_VARIABLE_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/include/mruby/version.h b/web/server/h2o/libh2o/deps/mruby/include/mruby/version.h new file mode 100644 index 000000000..8414bf204 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/include/mruby/version.h @@ -0,0 +1,110 @@ +/* +** mruby/version.h - mruby version definition +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_VERSION_H +#define MRUBY_VERSION_H + +#include "common.h" + +/** + * mruby version definition macros + */ +MRB_BEGIN_DECL + +/* + * A passed in expression. + */ +#define MRB_STRINGIZE0(expr) #expr + +/* + * Passes in an expression to MRB_STRINGIZE0. + */ +#define MRB_STRINGIZE(expr) MRB_STRINGIZE0(expr) + +/* + * The version of Ruby used by mruby. + */ +#define MRUBY_RUBY_VERSION "1.9" + +/* + * Ruby engine. + */ +#define MRUBY_RUBY_ENGINE "mruby" + +/* + * Major release version number. + */ +#define MRUBY_RELEASE_MAJOR 1 + +/* + * Minor release version number. + */ +#define MRUBY_RELEASE_MINOR 3 + +/* + * Tiny release version number. + */ +#define MRUBY_RELEASE_TEENY 0 + +/* + * The mruby version. + */ +#define MRUBY_VERSION MRB_STRINGIZE(MRUBY_RELEASE_MAJOR) "." MRB_STRINGIZE(MRUBY_RELEASE_MINOR) "." MRB_STRINGIZE(MRUBY_RELEASE_TEENY) + +/* + * Release number. + */ +#define MRUBY_RELEASE_NO (MRUBY_RELEASE_MAJOR * 100 * 100 + MRUBY_RELEASE_MINOR * 100 + MRUBY_RELEASE_TEENY) + +/* + * Release year. + */ +#define MRUBY_RELEASE_YEAR 2017 + +/* + * Release month. + */ +#define MRUBY_RELEASE_MONTH 7 + +/* + * Release day. + */ +#define MRUBY_RELEASE_DAY 4 + +/* + * Release date as a string. + */ +#define MRUBY_RELEASE_DATE MRB_STRINGIZE(MRUBY_RELEASE_YEAR) "-" MRB_STRINGIZE(MRUBY_RELEASE_MONTH) "-" MRB_STRINGIZE(MRUBY_RELEASE_DAY) + +/* + * The year mruby was first created. + */ +#define MRUBY_BIRTH_YEAR 2010 + +/* + * MRuby's authors. + */ +#define MRUBY_AUTHOR "mruby developers" + +/* + * mruby's version, and release date. + */ +#define MRUBY_DESCRIPTION \ + "mruby " MRUBY_VERSION \ + " (" MRUBY_RELEASE_DATE ") " \ + +/* + * mruby's copyright information. + */ +#define MRUBY_COPYRIGHT \ + "mruby - Copyright (c) " \ + MRB_STRINGIZE(MRUBY_BIRTH_YEAR)"-" \ + MRB_STRINGIZE(MRUBY_RELEASE_YEAR)" " \ + MRUBY_AUTHOR \ + +MRB_END_DECL + +#endif /* MRUBY_VERSION_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/lib/mruby-core-ext.rb b/web/server/h2o/libh2o/deps/mruby/lib/mruby-core-ext.rb new file mode 100644 index 000000000..4c6d3ca76 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/lib/mruby-core-ext.rb @@ -0,0 +1,79 @@ +class Object + class << self + def attr_block(*syms) + syms.flatten.each do |sym| + class_eval "def #{sym}(&block);block.call(@#{sym}) if block_given?;@#{sym};end" + end + end + end +end + +class String + def relative_path_from(dir) + Pathname.new(File.expand_path(self)).relative_path_from(Pathname.new(File.expand_path(dir))).to_s + end + + def relative_path + relative_path_from(Dir.pwd) + end + + # Compatible with 1.9 on 1.8 + def %(params) + if params.is_a?(Hash) + str = self.clone + params.each do |k, v| + str.gsub!("%{#{k}}") { v } + end + str + else + if params.is_a?(Array) + sprintf(self, *params) + else + sprintf(self, params) + end + end + end +end + +class Symbol + # Compatible with 1.9 on 1.8 + def to_proc + proc { |obj, *args| obj.send(self, *args) } + end +end + +module Enumerable + # Compatible with 1.9 on 1.8 + def each_with_object(memo) + return to_enum :each_with_object, memo unless block_given? + each { |obj| yield obj, memo } + memo + end +end + +$pp_show = true + +if $verbose.nil? + if Rake.respond_to?(:verbose) && !Rake.verbose.nil? + if Rake.verbose.class == TrueClass + # verbose message logging + $pp_show = false + else + $pp_show = true + Rake.verbose(false) + end + else + # could not identify rake version + $pp_show = false + end +else + $pp_show = false if $verbose +end + +def _pp(cmd, src, tgt=nil, options={}) + return unless $pp_show + + width = 5 + template = options[:indent] ? "%#{width*options[:indent]}s %s %s" : "%-#{width}s %s %s" + puts template % [cmd, src, tgt ? "-> #{tgt}" : nil] +end diff --git a/web/server/h2o/libh2o/deps/mruby/lib/mruby/build.rb b/web/server/h2o/libh2o/deps/mruby/lib/mruby/build.rb new file mode 100644 index 000000000..7d6aa49e1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/lib/mruby/build.rb @@ -0,0 +1,355 @@ +require "mruby/build/load_gems" +require "mruby/build/command" + +module MRuby + class << self + def targets + @targets ||= {} + end + + def each_target(&block) + return to_enum(:each_target) if block.nil? + @targets.each do |key, target| + target.instance_eval(&block) + end + end + end + + class Toolchain + class << self + attr_accessor :toolchains + end + + def initialize(name, &block) + @name, @initializer = name.to_s, block + MRuby::Toolchain.toolchains ||= {} + MRuby::Toolchain.toolchains[@name] = self + end + + def setup(conf,params={}) + conf.instance_exec(conf, params, &@initializer) + end + + def self.load + Dir.glob("#{MRUBY_ROOT}/tasks/toolchains/*.rake").each do |file| + Kernel.load file + end + end + end + Toolchain.load + + class Build + class << self + attr_accessor :current + end + include Rake::DSL + include LoadGems + attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir + attr_reader :libmruby, :gems, :toolchains + attr_writer :enable_bintest, :enable_test + + COMPILERS = %w(cc cxx objc asm) + COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc) + attr_block MRuby::Build::COMMANDS + + Exts = Struct.new(:object, :executable, :library) + + def initialize(name='host', build_dir=nil, &block) + @name = name.to_s + + unless MRuby.targets[@name] + if ENV['OS'] == 'Windows_NT' + @exts = Exts.new('.o', '.exe', '.a') + else + @exts = Exts.new('.o', '', '.a') + end + + build_dir = build_dir || ENV['MRUBY_BUILD_DIR'] || "#{MRUBY_ROOT}/build" + + @file_separator = '/' + @build_dir = "#{build_dir}/#{@name}" + @gem_clone_dir = "#{build_dir}/mrbgems" + @cc = Command::Compiler.new(self, %w(.c)) + @cxx = Command::Compiler.new(self, %w(.cc .cxx .cpp)) + @objc = Command::Compiler.new(self, %w(.m)) + @asm = Command::Compiler.new(self, %w(.S .asm)) + @linker = Command::Linker.new(self) + @archiver = Command::Archiver.new(self) + @yacc = Command::Yacc.new(self) + @gperf = Command::Gperf.new(self) + @git = Command::Git.new(self) + @mrbc = Command::Mrbc.new(self) + + @bins = [] + @gems, @libmruby = MRuby::Gem::List.new, [] + @build_mrbtest_lib_only = false + @cxx_exception_enabled = false + @cxx_exception_disabled = false + @cxx_abi_enabled = false + @enable_bintest = false + @enable_test = false + @toolchains = [] + + MRuby.targets[@name] = self + end + + MRuby::Build.current = MRuby.targets[@name] + MRuby.targets[@name].instance_eval(&block) + + build_mrbc_exec if name == 'host' + build_mrbtest if test_enabled? + end + + def enable_debug + compilers.each do |c| + c.defines += %w(MRB_DEBUG) + if toolchains.any? { |toolchain| toolchain == "gcc" } + c.flags += %w(-g3 -O0) + end + end + @mrbc.compile_options += ' -g' + end + + def disable_cxx_exception + if @cxx_exception_enabled or @cxx_abi_enabled + raise "cxx_exception already enabled" + end + @cxx_exception_disabled = true + end + + def enable_cxx_exception + return if @cxx_exception_enabled + return if @cxx_abi_enabled + if @cxx_exception_disabled + raise "cxx_exception disabled" + end + @cxx_exception_enabled = true + compilers.each { |c| + c.defines += %w(MRB_ENABLE_CXX_EXCEPTION) + c.flags << c.cxx_exception_flag + } + linker.command = cxx.command if toolchains.find { |v| v == 'gcc' } + end + + def cxx_exception_enabled? + @cxx_exception_enabled + end + + def cxx_abi_enabled? + @cxx_abi_enabled + end + + def enable_cxx_abi + return if @cxx_abi_enabled + if @cxx_exception_enabled + raise "cxx_exception already enabled" + end + compilers.each { |c| + c.defines += %w(MRB_ENABLE_CXX_EXCEPTION MRB_ENABLE_CXX_ABI) + c.flags << c.cxx_compile_flag + } + compilers.each { |c| c.flags << c.cxx_compile_flag } + linker.command = cxx.command if toolchains.find { |v| v == 'gcc' } + @cxx_abi_enabled = true + end + + def compile_as_cxx src, cxx_src, obj = nil, includes = [] + src = File.absolute_path src + cxx_src = File.absolute_path cxx_src + obj = objfile(cxx_src) if obj.nil? + + file cxx_src => [src, __FILE__] do |t| + FileUtils.mkdir_p File.dirname t.name + IO.write t.name, <<EOS +#define __STDC_CONSTANT_MACROS +#define __STDC_LIMIT_MACROS + +#ifndef MRB_ENABLE_CXX_ABI +extern "C" { +#endif +#include "#{src}" +#ifndef MRB_ENABLE_CXX_ABI +} +#endif +EOS + end + + file obj => cxx_src do |t| + cxx.run t.name, t.prerequisites.first, [], ["#{MRUBY_ROOT}/src"] + includes + end + + obj + end + + def enable_bintest + @enable_bintest = true + end + + def bintest_enabled? + @enable_bintest + end + + def toolchain(name, params={}) + tc = Toolchain.toolchains[name.to_s] + fail "Unknown #{name} toolchain" unless tc + tc.setup(self, params) + @toolchains.unshift name.to_s + end + + def primary_toolchain + @toolchains.first + end + + def root + MRUBY_ROOT + end + + def enable_test + @enable_test = true + end + + def test_enabled? + @enable_test + end + + def build_mrbtest + gem :core => 'mruby-test' + end + + def build_mrbc_exec + gem :core => 'mruby-bin-mrbc' + end + + def mrbcfile + return @mrbcfile if @mrbcfile + + mrbc_build = MRuby.targets['host'] + gems.each { |v| mrbc_build = self if v.name == 'mruby-bin-mrbc' } + @mrbcfile = mrbc_build.exefile("#{mrbc_build.build_dir}/bin/mrbc") + end + + def compilers + COMPILERS.map do |c| + instance_variable_get("@#{c}") + end + end + + def define_rules + compilers.each do |compiler| + if respond_to?(:enable_gems?) && enable_gems? + compiler.defines -= %w(DISABLE_GEMS) + else + compiler.defines += %w(DISABLE_GEMS) + end + compiler.define_rules build_dir, File.expand_path(File.join(File.dirname(__FILE__), '..', '..')) + end + end + + def filename(name) + if name.is_a?(Array) + name.flatten.map { |n| filename(n) } + else + '"%s"' % name.gsub('/', file_separator) + end + end + + def cygwin_filename(name) + if name.is_a?(Array) + name.flatten.map { |n| cygwin_filename(n) } + else + '"%s"' % `cygpath -w "#{filename(name)}"`.strip + end + end + + def exefile(name) + if name.is_a?(Array) + name.flatten.map { |n| exefile(n) } + else + "#{name}#{exts.executable}" + end + end + + def objfile(name) + if name.is_a?(Array) + name.flatten.map { |n| objfile(n) } + else + "#{name}#{exts.object}" + end + end + + def libfile(name) + if name.is_a?(Array) + name.flatten.map { |n| libfile(n) } + else + "#{name}#{exts.library}" + end + end + + def build_mrbtest_lib_only + @build_mrbtest_lib_only = true + end + + def build_mrbtest_lib_only? + @build_mrbtest_lib_only + end + + def run_test + puts ">>> Test #{name} <<<" + mrbtest = exefile("#{build_dir}/bin/mrbtest") + sh "#{filename mrbtest.relative_path}#{$verbose ? ' -v' : ''}" + puts + run_bintest if bintest_enabled? + end + + def run_bintest + targets = @gems.select { |v| File.directory? "#{v.dir}/bintest" }.map { |v| filename v.dir } + targets << filename(".") if File.directory? "./bintest" + sh "ruby test/bintest.rb #{targets.join ' '}" + end + + def print_build_summary + puts "================================================" + puts " Config Name: #{@name}" + puts " Output Directory: #{self.build_dir.relative_path}" + puts " Binaries: #{@bins.join(', ')}" unless @bins.empty? + unless @gems.empty? + puts " Included Gems:" + @gems.map do |gem| + gem_version = " - #{gem.version}" if gem.version != '0.0.0' + gem_summary = " - #{gem.summary}" if gem.summary + puts " #{gem.name}#{gem_version}#{gem_summary}" + puts " - Binaries: #{gem.bins.join(', ')}" unless gem.bins.empty? + end + end + puts "================================================" + puts + end + end # Build + + class CrossBuild < Build + attr_block %w(test_runner) + # cross compiling targets for building native extensions. + # host - arch of where the built binary will run + # build - arch of the machine building the binary + attr_accessor :host_target, :build_target + + def initialize(name, build_dir=nil, &block) + @test_runner = Command::CrossTestRunner.new(self) + super + end + + def mrbcfile + MRuby.targets['host'].exefile("#{MRuby.targets['host'].build_dir}/bin/mrbc") + end + + def run_test + mrbtest = exefile("#{build_dir}/bin/mrbtest") + if (@test_runner.command == nil) + puts "You should run #{mrbtest} on target device." + puts + else + @test_runner.run(mrbtest) + end + end + end # CrossBuild +end # MRuby diff --git a/web/server/h2o/libh2o/deps/mruby/lib/mruby/build/command.rb b/web/server/h2o/libh2o/deps/mruby/lib/mruby/build/command.rb new file mode 100644 index 000000000..694b4a24c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/lib/mruby/build/command.rb @@ -0,0 +1,324 @@ +require 'forwardable' + +module MRuby + class Command + include Rake::DSL + extend Forwardable + def_delegators :@build, :filename, :objfile, :libfile, :exefile, :cygwin_filename + attr_accessor :build, :command + + def initialize(build) + @build = build + end + + # clone is deep clone without @build + def clone + target = super + excepts = %w(@build) + instance_variables.each do |attr| + unless excepts.include?(attr.to_s) + val = Marshal::load(Marshal.dump(instance_variable_get(attr))) # deep clone + target.instance_variable_set(attr, val) + end + end + target + end + + NotFoundCommands = {} + + private + def _run(options, params={}) + return sh command + ' ' + ( options % params ) if NotFoundCommands.key? @command + begin + sh build.filename(command) + ' ' + ( options % params ) + rescue RuntimeError + NotFoundCommands[@command] = true + _run options, params + end + end + end + + class Command::Compiler < Command + attr_accessor :flags, :include_paths, :defines, :source_exts + attr_accessor :compile_options, :option_define, :option_include_path, :out_ext + attr_accessor :cxx_compile_flag, :cxx_exception_flag + + def initialize(build, source_exts=[]) + super(build) + @command = ENV['CC'] || 'cc' + @flags = [ENV['CFLAGS'] || []] + @source_exts = source_exts + @include_paths = ["#{MRUBY_ROOT}/include"] + @defines = %w() + @option_include_path = '-I%s' + @option_define = '-D%s' + @compile_options = '%{flags} -o %{outfile} -c %{infile}' + end + + alias header_search_paths include_paths + def search_header_path(name) + header_search_paths.find do |v| + File.exist? build.filename("#{v}/#{name}").sub(/^"(.*)"$/, '\1') + end + end + + def search_header(name) + path = search_header_path name + path && build.filename("#{path}/#{name}").sub(/^"(.*)"$/, '\1') + end + + def all_flags(_defineds=[], _include_paths=[], _flags=[]) + define_flags = [defines, _defineds].flatten.map{ |d| option_define % d } + include_path_flags = [include_paths, _include_paths].flatten.map do |f| + if MRUBY_BUILD_HOST_IS_CYGWIN + option_include_path % cygwin_filename(f) + else + option_include_path % filename(f) + end + end + [flags, define_flags, include_path_flags, _flags].flatten.join(' ') + end + + def run(outfile, infile, _defineds=[], _include_paths=[], _flags=[]) + FileUtils.mkdir_p File.dirname(outfile) + _pp "CC", infile.relative_path, outfile.relative_path + if MRUBY_BUILD_HOST_IS_CYGWIN + _run compile_options, { :flags => all_flags(_defineds, _include_paths, _flags), + :infile => cygwin_filename(infile), :outfile => cygwin_filename(outfile) } + else + _run compile_options, { :flags => all_flags(_defineds, _include_paths, _flags), + :infile => filename(infile), :outfile => filename(outfile) } + end + end + + def define_rules(build_dir, source_dir='') + @out_ext = build.exts.object + gemrake = File.join(source_dir, "mrbgem.rake") + rakedep = File.exist?(gemrake) ? [ gemrake ] : [] + + if build_dir.include? "mrbgems/" + generated_file_matcher = Regexp.new("^#{Regexp.escape build_dir}/(.*)#{Regexp.escape out_ext}$") + else + generated_file_matcher = Regexp.new("^#{Regexp.escape build_dir}/(?!mrbgems/.+/)(.*)#{Regexp.escape out_ext}$") + end + source_exts.each do |ext, compile| + rule generated_file_matcher => [ + proc { |file| + file.sub(generated_file_matcher, "#{source_dir}/\\1#{ext}") + }, + proc { |file| + get_dependencies(file) + rakedep + } + ] do |t| + run t.name, t.prerequisites.first + end + + rule generated_file_matcher => [ + proc { |file| + file.sub(generated_file_matcher, "#{build_dir}/\\1#{ext}") + }, + proc { |file| + get_dependencies(file) + rakedep + } + ] do |t| + run t.name, t.prerequisites.first + end + end + end + + private + def get_dependencies(file) + file = file.ext('d') unless File.extname(file) == '.d' + if File.exist?(file) + File.read(file).gsub("\\\n ", "").scan(/^\S+:\s+(.+)$/).flatten.map {|s| s.split(' ') }.flatten + else + [] + end + [ MRUBY_CONFIG ] + end + end + + class Command::Linker < Command + attr_accessor :flags, :library_paths, :flags_before_libraries, :libraries, :flags_after_libraries + attr_accessor :link_options, :option_library, :option_library_path + + def initialize(build) + super + @command = ENV['LD'] || 'ld' + @flags = (ENV['LDFLAGS'] || []) + @flags_before_libraries, @flags_after_libraries = [], [] + @libraries = [] + @library_paths = [] + @option_library = '-l%s' + @option_library_path = '-L%s' + @link_options = "%{flags} -o %{outfile} %{objs} %{flags_before_libraries} %{libs} %{flags_after_libraries}" + end + + def all_flags(_library_paths=[], _flags=[]) + library_path_flags = [library_paths, _library_paths].flatten.map do |f| + if MRUBY_BUILD_HOST_IS_CYGWIN + option_library_path % cygwin_filename(f) + else + option_library_path % filename(f) + end + end + [flags, library_path_flags, _flags].flatten.join(' ') + end + + def library_flags(_libraries) + [libraries, _libraries].flatten.map{ |d| option_library % d }.join(' ') + end + + def run(outfile, objfiles, _libraries=[], _library_paths=[], _flags=[], _flags_before_libraries=[], _flags_after_libraries=[]) + FileUtils.mkdir_p File.dirname(outfile) + library_flags = [libraries, _libraries].flatten.map { |d| option_library % d } + + _pp "LD", outfile.relative_path + if MRUBY_BUILD_HOST_IS_CYGWIN + _run link_options, { :flags => all_flags(_library_paths, _flags), + :outfile => cygwin_filename(outfile) , :objs => cygwin_filename(objfiles).join(' '), + :flags_before_libraries => [flags_before_libraries, _flags_before_libraries].flatten.join(' '), + :flags_after_libraries => [flags_after_libraries, _flags_after_libraries].flatten.join(' '), + :libs => library_flags.join(' ') } + else + _run link_options, { :flags => all_flags(_library_paths, _flags), + :outfile => filename(outfile) , :objs => filename(objfiles).join(' '), + :flags_before_libraries => [flags_before_libraries, _flags_before_libraries].flatten.join(' '), + :flags_after_libraries => [flags_after_libraries, _flags_after_libraries].flatten.join(' '), + :libs => library_flags.join(' ') } + end + end + end + + class Command::Archiver < Command + attr_accessor :archive_options + + def initialize(build) + super + @command = ENV['AR'] || 'ar' + @archive_options = 'rs %{outfile} %{objs}' + end + + def run(outfile, objfiles) + FileUtils.mkdir_p File.dirname(outfile) + _pp "AR", outfile.relative_path + if MRUBY_BUILD_HOST_IS_CYGWIN + _run archive_options, { :outfile => cygwin_filename(outfile), :objs => cygwin_filename(objfiles).join(' ') } + else + _run archive_options, { :outfile => filename(outfile), :objs => filename(objfiles).join(' ') } + end + end + end + + class Command::Yacc < Command + attr_accessor :compile_options + + def initialize(build) + super + @command = 'bison' + @compile_options = '-o %{outfile} %{infile}' + end + + def run(outfile, infile) + FileUtils.mkdir_p File.dirname(outfile) + _pp "YACC", infile.relative_path, outfile.relative_path + _run compile_options, { :outfile => filename(outfile) , :infile => filename(infile) } + end + end + + class Command::Gperf < Command + attr_accessor :compile_options + + def initialize(build) + super + @command = 'gperf' + @compile_options = '-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" %{infile} > %{outfile}' + end + + def run(outfile, infile) + FileUtils.mkdir_p File.dirname(outfile) + _pp "GPERF", infile.relative_path, outfile.relative_path + _run compile_options, { :outfile => filename(outfile) , :infile => filename(infile) } + end + end + + class Command::Git < Command + attr_accessor :flags + attr_accessor :clone_options, :pull_options, :checkout_options + + def initialize(build) + super + @command = 'git' + @flags = %w[] + @clone_options = "clone %{flags} %{url} %{dir}" + @pull_options = "pull" + @checkout_options = "checkout %{checksum_hash}" + end + + def run_clone(dir, url, _flags = []) + _pp "GIT", url, dir.relative_path + _run clone_options, { :flags => [flags, _flags].flatten.join(' '), :url => url, :dir => filename(dir) } + end + + def run_pull(dir, url) + root = Dir.pwd + Dir.chdir dir + _pp "GIT PULL", url, dir.relative_path + _run pull_options + Dir.chdir root + end + + def run_checkout(dir, checksum_hash) + root = Dir.pwd + Dir.chdir dir + _pp "GIT CHECKOUT", checksum_hash + _run checkout_options, { :checksum_hash => checksum_hash } + Dir.chdir root + end + end + + class Command::Mrbc < Command + attr_accessor :compile_options + + def initialize(build) + super + @command = nil + @compile_options = "-B%{funcname} -o-" + end + + def run(out, infiles, funcname) + @command ||= @build.mrbcfile + infiles = [infiles].flatten + infiles.each do |f| + _pp "MRBC", f.relative_path, nil, :indent => 2 + end + IO.popen("#{filename @command} #{@compile_options % {:funcname => funcname}} #{filename(infiles).join(' ')}", 'r+') do |io| + out.puts io.read + end + # if mrbc execution fail, drop the file + if $?.exitstatus != 0 + File.delete(out.path) + exit(-1) + end + end + end + + class Command::CrossTestRunner < Command + attr_accessor :runner_options + attr_accessor :verbose_flag + attr_accessor :flags + + def initialize(build) + super + @command = nil + @runner_options = '%{flags} %{infile}' + @verbose_flag = '' + @flags = [] + end + + def run(testbinfile) + puts "TEST for " + @build.name + _run runner_options, { :flags => [flags, verbose_flag].flatten.join(' '), :infile => testbinfile } + end + end + +end diff --git a/web/server/h2o/libh2o/deps/mruby/lib/mruby/build/load_gems.rb b/web/server/h2o/libh2o/deps/mruby/lib/mruby/build/load_gems.rb new file mode 100644 index 000000000..b48df6510 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/lib/mruby/build/load_gems.rb @@ -0,0 +1,122 @@ +module MRuby + module LoadGems + def gembox(gemboxfile) + gembox = File.expand_path("#{gemboxfile}.gembox", "#{MRUBY_ROOT}/mrbgems") + fail "Can't find gembox '#{gembox}'" unless File.exist?(gembox) + + GemBox.config = self + GemBox.path = gembox + + instance_eval File.read(gembox) + + GemBox.path = nil + end + + def gem(gemdir, &block) + caller_dir = File.expand_path(File.dirname(/^(.*?):\d/.match(caller.first).to_a[1])) + + if gemdir.is_a?(Hash) + gemdir = load_special_path_gem(gemdir) + elsif GemBox.path && gemdir.is_a?(String) + gemdir = File.expand_path(gemdir, File.dirname(GemBox.path)) + else + gemdir = File.expand_path(gemdir, caller_dir) + end + + gemrake = File.join(gemdir, "mrbgem.rake") + + fail "Can't find #{gemrake}" unless File.exist?(gemrake) + Gem.current = nil + load gemrake + return nil unless Gem.current + + Gem.current.dir = gemdir + Gem.current.build = self.is_a?(MRuby::Build) ? self : MRuby::Build.current + Gem.current.build_config_initializer = block + gems << Gem.current + + cxx_srcs = ['src', 'test', 'tools'].map do |subdir| + Dir.glob("#{Gem.current.dir}/#{subdir}/*.{cpp,cxx,cc}") + end.flatten + enable_cxx_exception unless cxx_srcs.empty? + + Gem.current + end + + def load_special_path_gem(params) + if params[:github] + params[:git] = "https://github.com/#{params[:github]}.git" + elsif params[:bitbucket] + if params[:method] == "ssh" + params[:git] = "git@bitbucket.org:#{params[:bitbucket]}.git" + else + params[:git] = "https://bitbucket.org/#{params[:bitbucket]}.git" + end + elsif params[:mgem] + mgem_list_dir = "#{gem_clone_dir}/mgem-list" + mgem_list_url = 'https://github.com/mruby/mgem-list.git' + if File.exist? mgem_list_dir + git.run_pull mgem_list_dir, mgem_list_url if $pull_gems + else + FileUtils.mkdir_p mgem_list_dir + git.run_clone mgem_list_dir, mgem_list_url, "--depth 1" + end + + require 'yaml' + + conf_path = "#{mgem_list_dir}/#{params[:mgem]}.gem" + conf_path = "#{mgem_list_dir}/mruby-#{params[:mgem]}.gem" unless File.exist? conf_path + fail "mgem not found: #{params[:mgem]}" unless File.exist? conf_path + conf = YAML.load File.read conf_path + + fail "unknown mgem protocol: #{conf['protocol']}" if conf['protocol'] != 'git' + params[:git] = conf['repository'] + params[:branch] = conf['branch'] if conf['branch'] + end + + if params[:core] + gemdir = "#{root}/mrbgems/#{params[:core]}" + elsif params[:path] + require 'pathname' + gemdir = Pathname.new(params[:path]).absolute? ? params[:path] : "#{root}/#{params[:path]}" + elsif params[:git] + url = params[:git] + gemdir = "#{gem_clone_dir}/#{url.match(/([-\w]+)(\.[-\w]+|)$/).to_a[1]}" + + # by default the 'master' branch is used + branch = params[:branch] ? params[:branch] : 'master' + + if File.exist?(gemdir) + if $pull_gems + git.run_pull gemdir, url + else + gemdir + end + else + options = [params[:options]] || [] + options << "--recursive" + options << "--branch \"#{branch}\"" + options << "--depth 1" unless params[:checksum_hash] + FileUtils.mkdir_p "#{gem_clone_dir}" + git.run_clone gemdir, url, options + end + + if params[:checksum_hash] + # Jump to the specified commit + git.run_checkout gemdir, params[:checksum_hash] + else + # Jump to the top of the branch + git.run_checkout gemdir, branch if $pull_gems + end + else + fail "unknown gem option #{params}" + end + + gemdir + end + + def enable_gems? + !@gems.empty? + end + end # LoadGems +end # MRuby diff --git a/web/server/h2o/libh2o/deps/mruby/lib/mruby/gem.rb b/web/server/h2o/libh2o/deps/mruby/lib/mruby/gem.rb new file mode 100644 index 000000000..27a1d358c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/lib/mruby/gem.rb @@ -0,0 +1,459 @@ +require 'pathname' +require 'forwardable' +require 'tsort' +require 'shellwords' + +module MRuby + module Gem + class << self + attr_accessor :current + end + LinkerConfig = Struct.new(:libraries, :library_paths, :flags, :flags_before_libraries, :flags_after_libraries) + + class Specification + include Rake::DSL + extend Forwardable + def_delegators :@build, :filename, :objfile, :libfile, :exefile + + attr_accessor :name, :dir, :build + alias mruby build + attr_accessor :build_config_initializer + attr_accessor :mrblib_dir, :objs_dir + + attr_accessor :version + attr_accessor :description, :summary + attr_accessor :homepage + attr_accessor :licenses, :authors + alias :license= :licenses= + alias :author= :authors= + + attr_accessor :rbfiles, :objs + attr_accessor :test_objs, :test_rbfiles, :test_args + attr_accessor :test_preload + + attr_accessor :bins + + attr_accessor :requirements + attr_reader :dependencies, :conflicts + + attr_accessor :export_include_paths + + attr_reader :generate_functions + + attr_block MRuby::Build::COMMANDS + + def initialize(name, &block) + @name = name + @initializer = block + @version = "0.0.0" + @mrblib_dir = "mrblib" + @objs_dir = "src" + MRuby::Gem.current = self + end + + def setup + MRuby::Gem.current = self + MRuby::Build::COMMANDS.each do |command| + instance_variable_set("@#{command}", @build.send(command).clone) + end + @linker = LinkerConfig.new([], [], [], [], []) + + @rbfiles = Dir.glob("#{@dir}/#{@mrblib_dir}/**/*.rb").sort + @objs = Dir.glob("#{@dir}/#{@objs_dir}/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| + objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X")) + end + + @test_rbfiles = Dir.glob("#{dir}/test/**/*.rb") + @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| + objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X")) + end + @custom_test_init = !@test_objs.empty? + @test_preload = nil # 'test/assert.rb' + @test_args = {} + + @bins = [] + + @requirements = [] + @dependencies, @conflicts = [], [] + @export_include_paths = [] + @export_include_paths << "#{dir}/include" if File.directory? "#{dir}/include" + + instance_eval(&@initializer) + + @generate_functions = !(@rbfiles.empty? && @objs.empty?) + @objs << objfile("#{build_dir}/gem_init") if @generate_functions + + if !name || !licenses || !authors + fail "#{name || dir} required to set name, license(s) and author(s)" + end + + build.libmruby << @objs + + instance_eval(&@build_config_initializer) if @build_config_initializer + end + + def setup_compilers + compilers.each do |compiler| + compiler.define_rules build_dir, "#{dir}" + compiler.defines << %Q[MRBGEM_#{funcname.upcase}_VERSION=#{version}] + compiler.include_paths << "#{dir}/include" if File.directory? "#{dir}/include" + end + + define_gem_init_builder if @generate_functions + end + + def add_dependency(name, *requirements) + default_gem = requirements.last.kind_of?(Hash) ? requirements.pop : nil + requirements = ['>= 0.0.0'] if requirements.empty? + requirements.flatten! + @dependencies << {:gem => name, :requirements => requirements, :default => default_gem} + end + + def add_test_dependency(*args) + add_dependency(*args) if build.test_enabled? + end + + def add_conflict(name, *req) + @conflicts << {:gem => name, :requirements => req.empty? ? nil : req} + end + + def self.bin=(bin) + @bins = [bin].flatten + end + + def build_dir + "#{build.build_dir}/mrbgems/#{name}" + end + + def test_rbireps + "#{build_dir}/gem_test.c" + end + + def search_package(name, version_query=nil) + package_query = name + package_query += " #{version_query}" if version_query + _pp "PKG-CONFIG", package_query + escaped_package_query = Shellwords.escape(package_query) + if system("pkg-config --exists #{escaped_package_query}") + cc.flags += [`pkg-config --cflags #{escaped_package_query}`.strip] + cxx.flags += [`pkg-config --cflags #{escaped_package_query}`.strip] + linker.flags_before_libraries += [`pkg-config --libs #{escaped_package_query}`.strip] + true + else + false + end + end + + def funcname + @funcname ||= @name.gsub('-', '_') + end + + def compilers + MRuby::Build::COMPILERS.map do |c| + instance_variable_get("@#{c}") + end + end + + def define_gem_init_builder + file objfile("#{build_dir}/gem_init") => [ "#{build_dir}/gem_init.c", File.join(dir, "mrbgem.rake") ] + file "#{build_dir}/gem_init.c" => [build.mrbcfile, __FILE__] + [rbfiles].flatten do |t| + FileUtils.mkdir_p build_dir + generate_gem_init("#{build_dir}/gem_init.c") + end + end + + def generate_gem_init(fname) + open(fname, 'w') do |f| + print_gem_init_header f + build.mrbc.run f, rbfiles, "gem_mrblib_irep_#{funcname}" unless rbfiles.empty? + f.puts %Q[void mrb_#{funcname}_gem_init(mrb_state *mrb);] + f.puts %Q[void mrb_#{funcname}_gem_final(mrb_state *mrb);] + f.puts %Q[] + f.puts %Q[void GENERATED_TMP_mrb_#{funcname}_gem_init(mrb_state *mrb) {] + f.puts %Q[ int ai = mrb_gc_arena_save(mrb);] + f.puts %Q[ mrb_#{funcname}_gem_init(mrb);] if objs != [objfile("#{build_dir}/gem_init")] + unless rbfiles.empty? + f.puts %Q[ mrb_load_irep(mrb, gem_mrblib_irep_#{funcname});] + f.puts %Q[ if (mrb->exc) {] + f.puts %Q[ mrb_print_error(mrb);] + f.puts %Q[ exit(EXIT_FAILURE);] + f.puts %Q[ }] + end + f.puts %Q[ mrb_gc_arena_restore(mrb, ai);] + f.puts %Q[}] + f.puts %Q[] + f.puts %Q[void GENERATED_TMP_mrb_#{funcname}_gem_final(mrb_state *mrb) {] + f.puts %Q[ mrb_#{funcname}_gem_final(mrb);] if objs != [objfile("#{build_dir}/gem_init")] + f.puts %Q[}] + end + end # generate_gem_init + + def print_gem_comment(f) + f.puts %Q[/*] + f.puts %Q[ * This file is loading the irep] + f.puts %Q[ * Ruby GEM code.] + f.puts %Q[ *] + f.puts %Q[ * IMPORTANT:] + f.puts %Q[ * This file was generated!] + f.puts %Q[ * All manual changes will get lost.] + f.puts %Q[ */] + end + + def print_gem_init_header(f) + print_gem_comment(f) + f.puts %Q[#include <stdlib.h>] unless rbfiles.empty? + f.puts %Q[#include <mruby.h>] + f.puts %Q[#include <mruby/irep.h>] unless rbfiles.empty? + end + + def print_gem_test_header(f) + print_gem_comment(f) + f.puts %Q[#include <stdio.h>] + f.puts %Q[#include <stdlib.h>] + f.puts %Q[#include <mruby.h>] + f.puts %Q[#include <mruby/irep.h>] + f.puts %Q[#include <mruby/variable.h>] + f.puts %Q[#include <mruby/hash.h>] unless test_args.empty? + end + + def test_dependencies + [@name] + end + + def custom_test_init? + @custom_test_init + end + + def version_ok?(req_versions) + req_versions.map do |req| + cmp, ver = req.split + cmp_result = Version.new(version) <=> Version.new(ver) + case cmp + when '=' then cmp_result == 0 + when '!=' then cmp_result != 0 + when '>' then cmp_result == 1 + when '<' then cmp_result == -1 + when '>=' then cmp_result >= 0 + when '<=' then cmp_result <= 0 + when '~>' + Version.new(version).twiddle_wakka_ok?(Version.new(ver)) + else + fail "Comparison not possible with '#{cmp}'" + end + end.all? + end + end # Specification + + class Version + include Comparable + include Enumerable + + def <=>(other) + ret = 0 + own = to_enum + + other.each do |oth| + begin + ret = own.next <=> oth + rescue StopIteration + ret = 0 <=> oth + end + + break unless ret == 0 + end + + ret + end + + # ~> compare algorithm + # + # Example: + # ~> 2.2 means >= 2.2.0 and < 3.0.0 + # ~> 2.2.0 means >= 2.2.0 and < 2.3.0 + def twiddle_wakka_ok?(other) + gr_or_eql = (self <=> other) >= 0 + still_minor = (self <=> other.skip_minor) < 0 + gr_or_eql and still_minor + end + + def skip_minor + a = @ary.dup + a.slice!(-1) + a[-1] = a[-1].succ + a + end + + def initialize(str) + @str = str + @ary = @str.split('.').map(&:to_i) + end + + def each(&block); @ary.each(&block); end + def [](index); @ary[index]; end + def []=(index, value) + @ary[index] = value + @str = @ary.join('.') + end + def slice!(index) + @ary.slice!(index) + @str = @ary.join('.') + end + end # Version + + class List + include Enumerable + + def initialize + @ary = [] + end + + def each(&b) + @ary.each(&b) + end + + def <<(gem) + unless @ary.detect {|g| g.dir == gem.dir } + @ary << gem + else + # GEM was already added to this list + end + end + + def empty? + @ary.empty? + end + + def generate_gem_table build + gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res } + + default_gems = [] + each do |g| + g.dependencies.each do |dep| + unless gem_table.key? dep[:gem] + if dep[:default]; default_gems << dep + elsif File.exist? "#{MRUBY_ROOT}/mrbgems/#{dep[:gem]}" # check core + default_gems << { :gem => dep[:gem], :default => { :core => dep[:gem] } } + else # fallback to mgem-list + default_gems << { :gem => dep[:gem], :default => { :mgem => dep[:gem] } } + end + end + end + end + + until default_gems.empty? + def_gem = default_gems.pop + + spec = build.gem def_gem[:default] + fail "Invalid gem name: #{spec.name} (Expected: #{def_gem[:gem]})" if spec.name != def_gem[:gem] + spec.setup + + spec.dependencies.each do |dep| + unless gem_table.key? dep[:gem] + if dep[:default]; default_gems << dep + else default_gems << { :gem => dep[:gem], :default => { :mgem => dep[:gem] } } + end + end + end + gem_table[spec.name] = spec + end + + each do |g| + g.dependencies.each do |dep| + name = dep[:gem] + req_versions = dep[:requirements] + dep_g = gem_table[name] + + # check each GEM dependency against all available GEMs + if dep_g.nil? + fail "The GEM '#{g.name}' depends on the GEM '#{name}' but it could not be found" + end + unless dep_g.version_ok? req_versions + fail "#{name} version should be #{req_versions.join(' and ')} but was '#{dep_g.version}'" + end + end + + cfls = g.conflicts.select { |c| + cfl_g = gem_table[c[:gem]] + cfl_g and cfl_g.version_ok?(c[:requirements] || ['>= 0.0.0']) + }.map { |c| "#{c[:gem]}(#{gem_table[c[:gem]].version})" } + fail "Conflicts of gem `#{g.name}` found: #{cfls.join ', '}" unless cfls.empty? + end + + gem_table + end + + def tsort_dependencies ary, table, all_dependency_listed = false + unless all_dependency_listed + left = ary.dup + until left.empty? + v = left.pop + table[v].dependencies.each do |dep| + left.push dep[:gem] + ary.push dep[:gem] + end + end + end + + ary.uniq! + table.instance_variable_set :@root_gems, ary + class << table + include TSort + def tsort_each_node &b + @root_gems.each &b + end + + def tsort_each_child(n, &b) + fetch(n).dependencies.each do |v| + b.call v[:gem] + end + end + end + + begin + table.tsort.map { |v| table[v] } + rescue TSort::Cyclic => e + fail "Circular mrbgem dependency found: #{e.message}" + end + end + + def check(build) + gem_table = generate_gem_table build + + @ary = tsort_dependencies gem_table.keys, gem_table, true + + each(&:setup_compilers) + + each do |g| + import_include_paths(g) + end + end + + def import_include_paths(g) + gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res } + g.dependencies.each do |dep| + dep_g = gem_table[dep[:gem]] + # We can do recursive call safely + # as circular dependency has already detected in the caller. + import_include_paths(dep_g) + + dep_g.export_include_paths.uniq! + g.compilers.each do |compiler| + compiler.include_paths += dep_g.export_include_paths + g.export_include_paths += dep_g.export_include_paths + compiler.include_paths.uniq! + g.export_include_paths.uniq! + end + end + end + end # List + end # Gem + + GemBox = Object.new + class << GemBox + attr_accessor :path + + def new(&block); block.call(self); end + def config=(obj); @config = obj; end + def gem(gemdir, &block); @config.gem(gemdir, &block); end + end # GemBox +end # MRuby diff --git a/web/server/h2o/libh2o/deps/mruby/lib/mruby/source.rb b/web/server/h2o/libh2o/deps/mruby/lib/mruby/source.rb new file mode 100644 index 000000000..5819a322b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/lib/mruby/source.rb @@ -0,0 +1,30 @@ +require "pathname" + +module MRuby + module Source + # MRuby's source root directory + ROOT = Pathname.new(File.expand_path('../../../',__FILE__)) + + # Reads a constant defined at version.h + MRUBY_READ_VERSION_CONSTANT = Proc.new { |name| ROOT.join('include','mruby','version.h').read.match(/^#define #{name} +"?([\w\. ]+)"?$/)[1] } + + MRUBY_RUBY_VERSION = MRUBY_READ_VERSION_CONSTANT['MRUBY_RUBY_VERSION'] + MRUBY_RUBY_ENGINE = MRUBY_READ_VERSION_CONSTANT['MRUBY_RUBY_ENGINE'] + + MRUBY_RELEASE_MAJOR = Integer(MRUBY_READ_VERSION_CONSTANT['MRUBY_RELEASE_MAJOR']) + MRUBY_RELEASE_MINOR = Integer(MRUBY_READ_VERSION_CONSTANT['MRUBY_RELEASE_MINOR']) + MRUBY_RELEASE_TEENY = Integer(MRUBY_READ_VERSION_CONSTANT['MRUBY_RELEASE_TEENY']) + + MRUBY_VERSION = [MRUBY_RELEASE_MAJOR,MRUBY_RELEASE_MINOR,MRUBY_RELEASE_TEENY].join('.') + MRUBY_RELEASE_NO = (MRUBY_RELEASE_MAJOR * 100 * 100 + MRUBY_RELEASE_MINOR * 100 + MRUBY_RELEASE_TEENY) + + MRUBY_RELEASE_YEAR = Integer(MRUBY_READ_VERSION_CONSTANT['MRUBY_RELEASE_YEAR']) + MRUBY_RELEASE_MONTH = Integer(MRUBY_READ_VERSION_CONSTANT['MRUBY_RELEASE_MONTH']) + MRUBY_RELEASE_DAY = Integer(MRUBY_READ_VERSION_CONSTANT['MRUBY_RELEASE_DAY']) + MRUBY_RELEASE_DATE = [MRUBY_RELEASE_YEAR,MRUBY_RELEASE_MONTH,MRUBY_RELEASE_DAY].join('.') + + MRUBY_BIRTH_YEAR = Integer(MRUBY_READ_VERSION_CONSTANT['MRUBY_BIRTH_YEAR']) + + MRUBY_AUTHOR = MRUBY_READ_VERSION_CONSTANT['MRUBY_AUTHOR'] + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/minirake b/web/server/h2o/libh2o/deps/mruby/minirake new file mode 100755 index 000000000..542c37a79 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/minirake @@ -0,0 +1,484 @@ +#!/usr/bin/env ruby + +# Original is https://github.com/jimweirich/rake/ +# Copyright (c) 2003 Jim Weirich +# License: MIT-LICENSE + +require 'getoptlong' +require 'fileutils' + +class String + def ext(newext='') + return self.dup if ['.', '..'].include? self + if newext != '' + newext = (newext =~ /^\./) ? newext : ("." + newext) + end + self.chomp(File.extname(self)) << newext + end + + def pathmap(spec=nil, &block) + return self if spec.nil? + result = '' + spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag| + case frag + when '%f' + result << File.basename(self) + when '%n' + result << File.basename(self).ext + when '%d' + result << File.dirname(self) + when '%x' + result << File.extname(self) + when '%X' + result << self.ext + when '%p' + result << self + when '%s' + result << (File::ALT_SEPARATOR || File::SEPARATOR) + when '%-' + # do nothing + when '%%' + result << "%" + when /%(-?\d+)d/ + result << pathmap_partial($1.to_i) + when /^%\{([^}]*)\}(\d*[dpfnxX])/ + patterns, operator = $1, $2 + result << pathmap('%' + operator).pathmap_replace(patterns, &block) + when /^%/ + fail ArgumentError, "Unknown pathmap specifier #{frag} in '#{spec}'" + else + result << frag + end + end + result + end +end + +module MiniRake + class Task + TASKS = Hash.new + RULES = Array.new + + # List of prerequisites for a task. + attr_reader :prerequisites + + # Source dependency for rule synthesized tasks. Nil if task was not + # sythesized from a rule. + attr_accessor :source + + # Create a task named +task_name+ with no actions or prerequisites.. + # use +enhance+ to add actions and prerequisites. + def initialize(task_name) + @name = task_name + @prerequisites = [] + @actions = [] + end + + # Enhance a task with prerequisites or actions. Returns self. + def enhance(deps=nil, &block) + @prerequisites |= deps if deps + @actions << block if block_given? + self + end + + # Name of the task. + def name + @name.to_s + end + + # Invoke the task if it is needed. Prerequites are invoked first. + def invoke + puts "Invoke #{name} (already=[#{@already_invoked}], needed=[#{needed?}])" if $trace + return if @already_invoked + @already_invoked = true + prerequisites = @prerequisites.collect{ |n| n.is_a?(Proc) ? n.call(name) : n }.flatten + prerequisites.each { |n| Task[n].invoke } + execute if needed? + end + + # Execute the actions associated with this task. + def execute + puts "Execute #{name}" if $trace + self.class.enhance_with_matching_rule(name) if @actions.empty? + unless $dryrun + @actions.each { |act| act.call(self) } + end + end + + # Is this task needed? + def needed? + true + end + + # Timestamp for this task. Basic tasks return the current time for + # their time stamp. Other tasks can be more sophisticated. + def timestamp + Time.now + end + + # Class Methods ---------------------------------------------------- + + class << self + + # Clear the task list. This cause rake to immediately forget all + # the tasks that have been assigned. (Normally used in the unit + # tests.) + def clear + TASKS.clear + RULES.clear + end + + # List of all defined tasks. + def tasks + TASKS.keys.sort.collect { |tn| Task[tn] } + end + + # Return a task with the given name. If the task is not currently + # known, try to synthesize one from the defined rules. If no + # rules are found, but an existing file matches the task name, + # assume it is a file task with no dependencies or actions. + def [](task_name) + task_name = task_name.to_s + if task = TASKS[task_name] + return task + end + if task = enhance_with_matching_rule(task_name) + return task + end + if File.exist?(task_name) + return FileTask.define_task(task_name) + end + fail "Don't know how to rake #{task_name}" + end + + # Define a task given +args+ and an option block. If a rule with + # the given name already exists, the prerequisites and actions are + # added to the existing task. + def define_task(args, &block) + task_name, deps = resolve_args(args) + lookup(task_name).enhance([deps].flatten, &block) + end + + # Define a rule for synthesizing tasks. + def create_rule(args, &block) + pattern, deps = resolve_args(args) + pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern + RULES << [pattern, deps, block] + end + + + # Lookup a task. Return an existing task if found, otherwise + # create a task of the current type. + def lookup(task_name) + name = task_name.to_s + TASKS[name] ||= self.new(name) + end + + # If a rule can be found that matches the task name, enhance the + # task with the prerequisites and actions from the rule. Set the + # source attribute of the task appropriately for the rule. Return + # the enhanced task or nil of no rule was found. + def enhance_with_matching_rule(task_name) + RULES.each do |pattern, extensions, block| + if pattern.match(task_name) + ext = extensions.first + deps = extensions[1..-1] + case ext + when String + source = task_name.sub(/\.[^.]*$/, ext) + when Proc + source = ext.call(task_name) + else + fail "Don't know how to handle rule dependent: #{ext.inspect}" + end + if File.exist?(source) + task = FileTask.define_task({task_name => [source]+deps}, &block) + task.source = source + return task + end + end + end + nil + end + + private + + # Resolve the arguments for a task/rule. + def resolve_args(args) + case args + when Hash + fail "Too Many Task Names: #{args.keys.join(' ')}" if args.size > 1 + fail "No Task Name Given" if args.size < 1 + task_name = args.keys[0] + deps = args[task_name] + deps = [deps] if (String===deps) || (Regexp===deps) || (Proc===deps) + else + task_name = args + deps = [] + end + [task_name, deps] + end + end + end + + + ###################################################################### + class FileTask < Task + # Is this file task needed? Yes if it doesn't exist, or if its time + # stamp is out of date. + def needed? + return true unless File.exist?(name) + prerequisites = @prerequisites.collect{ |n| n.is_a?(Proc) ? n.call(name) : n }.flatten + latest_prereq = prerequisites.collect{|n| Task[n].timestamp}.max + return false if latest_prereq.nil? + timestamp < latest_prereq + end + + # Time stamp for file task. + def timestamp + return Time.at(0) unless File.exist?(name) + stat = File::stat(name.to_s) + stat.directory? ? Time.at(0) : stat.mtime + end + end + + module DSL + # Declare a basic task. + def task(args, &block) + MiniRake::Task.define_task(args, &block) + end + + # Declare a file task. + def file(args, &block) + MiniRake::FileTask.define_task(args, &block) + end + + # Declare a set of files tasks to create the given directories on + # demand. + def directory(args, &block) + MiniRake::FileTask.define_task(args) do |t| + block.call(t) unless block.nil? + dir = args.is_a?(Hash) ? args.keys.first : args + (dir.split(File::SEPARATOR) + ['']).inject do |acc, part| + (acc + File::SEPARATOR).tap do |d| + Dir.mkdir(d) unless File.exists? d + end + part + end + end + end + + # Declare a rule for auto-tasks. + def rule(args, &block) + MiniRake::Task.create_rule(args, &block) + end + + # Write a message to standard out if $verbose is enabled. + def log(msg) + print " " if $trace && $verbose + puts msg if $verbose + end + + # Run the system command +cmd+. + def sh(cmd) + puts cmd if $verbose + system(cmd) or fail "Command Failed: [#{cmd}]" + end + + def desc(text) + end + end +end + +Rake = MiniRake +extend MiniRake::DSL + + +###################################################################### +# Task Definition Functions ... + +###################################################################### +# Rake main application object. When invoking +rake+ from the command +# line, a RakeApp object is created and run. +# +class RakeApp + RAKEFILES = ['rakefile', 'Rakefile'] + + OPTIONS = [ + ['--dry-run', '-n', GetoptLong::NO_ARGUMENT, + "Do a dry run without executing actions."], + ['--help', '-H', GetoptLong::NO_ARGUMENT, + "Display this help message."], + ['--libdir', '-I', GetoptLong::REQUIRED_ARGUMENT, + "Include LIBDIR in the search path for required modules."], + ['--nosearch', '-N', GetoptLong::NO_ARGUMENT, + "Do not search parent directories for the Rakefile."], + ['--quiet', '-q', GetoptLong::NO_ARGUMENT, + "Do not log messages to standard output (default)."], + ['--rakefile', '-f', GetoptLong::REQUIRED_ARGUMENT, + "Use FILE as the rakefile."], + ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT, + "Require MODULE before executing rakefile."], + ['--tasks', '-T', GetoptLong::NO_ARGUMENT, + "Display the tasks and dependencies, then exit."], + ['--pull-gems','-p', GetoptLong::NO_ARGUMENT, + "Pull all git mrbgems."], + ['--trace', '-t', GetoptLong::NO_ARGUMENT, + "Turn on invoke/execute tracing."], + ['--usage', '-h', GetoptLong::NO_ARGUMENT, + "Display usage."], + ['--verbose', '-v', GetoptLong::NO_ARGUMENT, + "Log message to standard output."], + ['--directory', '-C', GetoptLong::REQUIRED_ARGUMENT, + "Change executing directory of rakefiles."] + ] + + # Create a RakeApp object. + def initialize + @rakefile = nil + @nosearch = false + end + + # True if one of the files in RAKEFILES is in the current directory. + # If a match is found, it is copied into @rakefile. + def have_rakefile + RAKEFILES.each do |fn| + if File.exist?(fn) + @rakefile = fn + return true + end + end + return false + end + + # Display the program usage line. + def usage + puts "rake [-f rakefile] {options} targets..." + end + + # Display the rake command line help. + def help + usage + puts + puts "Options are ..." + puts + OPTIONS.sort.each do |long, short, mode, desc| + if mode == GetoptLong::REQUIRED_ARGUMENT + if desc =~ /\b([A-Z]{2,})\b/ + long = long + "=#{$1}" + end + end + printf " %-20s (%s)\n", long, short + printf " %s\n", desc + end + end + + # Display the tasks and dependencies. + def display_tasks + MiniRake::Task.tasks.each do |t| + puts "#{t.class} #{t.name}" + t.prerequisites.each { |pre| puts " #{pre}" } + end + end + + # Return a list of the command line options supported by the + # program. + def command_line_options + OPTIONS.collect { |lst| lst[0..-2] } + end + + # Do the option defined by +opt+ and +value+. + def do_option(opt, value) + case opt + when '--dry-run' + $dryrun = true + $trace = true + when '--help' + help + exit + when '--libdir' + $:.push(value) + when '--nosearch' + @nosearch = true + when '--quiet' + $verbose = false + when '--rakefile' + RAKEFILES.clear + RAKEFILES << value + when '--require' + require value + when '--tasks' + $show_tasks = true + when '--pull-gems' + $pull_gems = true + when '--trace' + $trace = true + when '--usage' + usage + exit + when '--verbose' + $verbose = true + when '--version' + puts "rake, version #{RAKEVERSION}" + exit + when '--directory' + Dir.chdir value + else + fail "Unknown option: #{opt}" + end + end + + # Read and handle the command line options. + def handle_options + $verbose = false + $pull_gems = false + opts = GetoptLong.new(*command_line_options) + opts.each { |opt, value| do_option(opt, value) } + end + + # Run the +rake+ application. + def run + handle_options + begin + here = Dir.pwd + while ! have_rakefile + Dir.chdir("..") + if Dir.pwd == here || @nosearch + fail "No Rakefile found (looking for: #{RAKEFILES.join(', ')})" + end + here = Dir.pwd + end + tasks = [] + ARGV.each do |task_name| + if /^(\w+)=(.*)/.match(task_name) + ENV[$1] = $2 + else + tasks << task_name + end + end + puts "(in #{Dir.pwd})" + $rakefile = @rakefile + load @rakefile + if $show_tasks + display_tasks + else + tasks.push("default") if tasks.size == 0 + tasks.each do |task_name| + MiniRake::Task[task_name].invoke + end + end + rescue Exception => ex + puts "rake aborted!" + puts ex.message + if $trace + puts ex.backtrace.join("\n") + else + puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || "" + end + exit 1 + end + end +end + +if __FILE__ == $0 then + RakeApp.new.run +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/default.gembox b/web/server/h2o/libh2o/deps/mruby/mrbgems/default.gembox new file mode 100644 index 000000000..64f05de10 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/default.gembox @@ -0,0 +1,79 @@ +MRuby::GemBox.new do |conf| + # Use standard Kernel#sprintf method + conf.gem :core => "mruby-sprintf" + + # Use standard print/puts/p + conf.gem :core => "mruby-print" + + # Use standard Math module + conf.gem :core => "mruby-math" + + # Use standard Time class + conf.gem :core => "mruby-time" + + # Use standard Struct class + conf.gem :core => "mruby-struct" + + # Use Enumerable module extension + conf.gem :core => "mruby-enum-ext" + + # Use String class extension + conf.gem :core => "mruby-string-ext" + + # Use Numeric class extension + conf.gem :core => "mruby-numeric-ext" + + # Use Array class extension + conf.gem :core => "mruby-array-ext" + + # Use Hash class extension + conf.gem :core => "mruby-hash-ext" + + # Use Range class extension + conf.gem :core => "mruby-range-ext" + + # Use Proc class extension + conf.gem :core => "mruby-proc-ext" + + # Use Symbol class extension + conf.gem :core => "mruby-symbol-ext" + + # Use Random class + conf.gem :core => "mruby-random" + + # Use Object class extension + conf.gem :core => "mruby-object-ext" + + # Use ObjectSpace class + conf.gem :core => "mruby-objectspace" + + # Use Fiber class + conf.gem :core => "mruby-fiber" + + # Use Enumerator class (require mruby-fiber) + conf.gem :core => "mruby-enumerator" + + # Use Enumerator::Lazy class (require mruby-enumerator) + conf.gem :core => "mruby-enum-lazy" + + # Use toplevel object (main) methods extension + conf.gem :core => "mruby-toplevel-ext" + + # Generate mirb command + conf.gem :core => "mruby-bin-mirb" + + # Generate mruby command + conf.gem :core => "mruby-bin-mruby" + + # Generate mruby-strip command + conf.gem :core => "mruby-bin-strip" + + # Use Kernel module extension + conf.gem :core => "mruby-kernel-ext" + + # Use class/module extension + conf.gem :core => "mruby-class-ext" + + # Use mruby-compiler to build other mrbgems + conf.gem :core => "mruby-compiler" +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/full-core.gembox b/web/server/h2o/libh2o/deps/mruby/mrbgems/full-core.gembox new file mode 100644 index 000000000..9a5b7081b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/full-core.gembox @@ -0,0 +1,9 @@ +MRuby::GemBox.new do |conf| + conf.gem :core => "mruby-sprintf" + conf.gem :core => "mruby-print" + + Dir.glob("#{root}/mrbgems/mruby-*/mrbgem.rake") do |x| + g = File.basename File.dirname x + conf.gem :core => g unless g =~ /^mruby-(print|sprintf|bin-debugger|test)$/ + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/mrbgem.rake new file mode 100644 index 000000000..882caf1ab --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-array-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Array class extension' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/mrblib/array.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/mrblib/array.rb new file mode 100644 index 000000000..e28e5238d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/mrblib/array.rb @@ -0,0 +1,811 @@ +class Array + ## + # call-seq: + # Array.try_convert(obj) -> array or nil + # + # Tries to convert +obj+ into an array, using +to_ary+ method. + # converted array or +nil+ if +obj+ cannot be converted for any reason. + # This method can be used to check if an argument is an array. + # + # Array.try_convert([1]) #=> [1] + # Array.try_convert("1") #=> nil + # + # if tmp = Array.try_convert(arg) + # # the argument is an array + # elsif tmp = String.try_convert(arg) + # # the argument is a string + # end + # + def self.try_convert(obj) + if obj.respond_to?(:to_ary) + obj.to_ary + else + nil + end + end + + ## + # call-seq: + # ary.uniq! -> ary or nil + # ary.uniq! { |item| ... } -> ary or nil + # + # Removes duplicate elements from +self+. + # Returns <code>nil</code> if no changes are made (that is, no + # duplicates are found). + # + # a = [ "a", "a", "b", "b", "c" ] + # a.uniq! #=> ["a", "b", "c"] + # b = [ "a", "b", "c" ] + # b.uniq! #=> nil + # c = [["student","sam"], ["student","george"], ["teacher","matz"]] + # c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] + # + def uniq!(&block) + ary = self.dup + result = [] + if block + hash = {} + while ary.size > 0 + val = ary.shift + key = block.call(val) + hash[key] = val unless hash.has_key?(key) + end + hash.each_value do |value| + result << value + end + else + while ary.size > 0 + result << ary.shift + ary.delete(result.last) + end + end + if result.size == self.size + nil + else + self.replace(result) + end + end + + ## + # call-seq: + # ary.uniq -> new_ary + # ary.uniq { |item| ... } -> new_ary + # + # Returns a new array by removing duplicate values in +self+. + # + # a = [ "a", "a", "b", "b", "c" ] + # a.uniq #=> ["a", "b", "c"] + # + # b = [["student","sam"], ["student","george"], ["teacher","matz"]] + # b.uniq { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] + # + def uniq(&block) + ary = self.dup + ary.uniq!(&block) + ary + end + + ## + # call-seq: + # ary - other_ary -> new_ary + # + # Array Difference---Returns a new array that is a copy of + # the original array, removing any items that also appear in + # <i>other_ary</i>. (If you need set-like behavior, see the + # library class Set.) + # + # [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ] + # + def -(elem) + raise TypeError, "can't convert #{elem.class} into Array" unless elem.class == Array + + hash = {} + array = [] + idx = 0 + len = elem.size + while idx < len + hash[elem[idx]] = true + idx += 1 + end + idx = 0 + len = size + while idx < len + v = self[idx] + array << v unless hash[v] + idx += 1 + end + array + end + + ## + # call-seq: + # ary | other_ary -> new_ary + # + # Set Union---Returns a new array by joining this array with + # <i>other_ary</i>, removing duplicates. + # + # [ "a", "b", "c" ] | [ "c", "d", "a" ] + # #=> [ "a", "b", "c", "d" ] + # + def |(elem) + raise TypeError, "can't convert #{elem.class} into Array" unless elem.class == Array + + ary = self + elem + ary.uniq! or ary + end + + ## + # call-seq: + # ary & other_ary -> new_ary + # + # Set Intersection---Returns a new array + # containing elements common to the two arrays, with no duplicates. + # + # [ 1, 1, 3, 5 ] & [ 1, 2, 3 ] #=> [ 1, 3 ] + # + def &(elem) + raise TypeError, "can't convert #{elem.class} into Array" unless elem.class == Array + + hash = {} + array = [] + idx = 0 + len = elem.size + while idx < len + hash[elem[idx]] = true + idx += 1 + end + idx = 0 + len = size + while idx < len + v = self[idx] + if hash[v] + array << v + hash.delete v + end + idx += 1 + end + array + end + + ## + # call-seq: + # ary.flatten -> new_ary + # ary.flatten(level) -> new_ary + # + # Returns a new array that is a one-dimensional flattening of this + # array (recursively). That is, for every element that is an array, + # extract its elements into the new array. If the optional + # <i>level</i> argument determines the level of recursion to flatten. + # + # s = [ 1, 2, 3 ] #=> [1, 2, 3] + # t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] + # a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] + # a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + # a = [ 1, 2, [3, [4, 5] ] ] + # a.flatten(1) #=> [1, 2, 3, [4, 5]] + # + def flatten(depth=nil) + res = dup + res.flatten! depth + res + end + + ## + # call-seq: + # ary.flatten! -> ary or nil + # ary.flatten!(level) -> array or nil + # + # Flattens +self+ in place. + # Returns <code>nil</code> if no modifications were made (i.e., + # <i>ary</i> contains no subarrays.) If the optional <i>level</i> + # argument determines the level of recursion to flatten. + # + # a = [ 1, 2, [3, [4, 5] ] ] + # a.flatten! #=> [1, 2, 3, 4, 5] + # a.flatten! #=> nil + # a #=> [1, 2, 3, 4, 5] + # a = [ 1, 2, [3, [4, 5] ] ] + # a.flatten!(1) #=> [1, 2, 3, [4, 5]] + # + def flatten!(depth=nil) + modified = false + ar = [] + idx = 0 + len = size + while idx < len + e = self[idx] + if e.is_a?(Array) && (depth.nil? || depth > 0) + ar += e.flatten(depth.nil? ? nil : depth - 1) + modified = true + else + ar << e + end + idx += 1 + end + if modified + self.replace(ar) + else + nil + end + end + + ## + # call-seq: + # ary.compact -> new_ary + # + # Returns a copy of +self+ with all +nil+ elements removed. + # + # [ "a", nil, "b", nil, "c", nil ].compact + # #=> [ "a", "b", "c" ] + # + def compact + result = self.dup + result.compact! + result + end + + ## + # call-seq: + # ary.compact! -> ary or nil + # + # Removes +nil+ elements from the array. + # Returns +nil+ if no changes were made, otherwise returns + # <i>ary</i>. + # + # [ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ] + # [ "a", "b", "c" ].compact! #=> nil + # + def compact! + result = self.select { |e| !e.nil? } + if result.size == self.size + nil + else + self.replace(result) + end + end + + # for efficiency + def reverse_each(&block) + return to_enum :reverse_each unless block + + i = self.size - 1 + while i>=0 + block.call(self[i]) + i -= 1 + end + self + end + + NONE=Object.new + ## + # call-seq: + # ary.fetch(index) -> obj + # ary.fetch(index, default) -> obj + # ary.fetch(index) { |index| block } -> obj + # + # Tries to return the element at position +index+, but throws an IndexError + # exception if the referenced +index+ lies outside of the array bounds. This + # error can be prevented by supplying a second argument, which will act as a + # +default+ value. + # + # Alternatively, if a block is given it will only be executed when an + # invalid +index+ is referenced. + # + # Negative values of +index+ count from the end of the array. + # + # a = [ 11, 22, 33, 44 ] + # a.fetch(1) #=> 22 + # a.fetch(-1) #=> 44 + # a.fetch(4, 'cat') #=> "cat" + # a.fetch(100) { |i| puts "#{i} is out of bounds" } + # #=> "100 is out of bounds" + # + + def fetch(n=nil, ifnone=NONE, &block) + warn "block supersedes default value argument" if !n.nil? && ifnone != NONE && block + + idx = n + if idx < 0 + idx += size + end + if idx < 0 || size <= idx + return block.call(n) if block + if ifnone == NONE + raise IndexError, "index #{n} outside of array bounds: #{-size}...#{size}" + end + return ifnone + end + self[idx] + end + + ## + # call-seq: + # ary.fill(obj) -> ary + # ary.fill(obj, start [, length]) -> ary + # ary.fill(obj, range ) -> ary + # ary.fill { |index| block } -> ary + # ary.fill(start [, length] ) { |index| block } -> ary + # ary.fill(range) { |index| block } -> ary + # + # The first three forms set the selected elements of +self+ (which + # may be the entire array) to +obj+. + # + # A +start+ of +nil+ is equivalent to zero. + # + # A +length+ of +nil+ is equivalent to the length of the array. + # + # The last three forms fill the array with the value of the given block, + # which is passed the absolute index of each element to be filled. + # + # Negative values of +start+ count from the end of the array, where +-1+ is + # the last element. + # + # a = [ "a", "b", "c", "d" ] + # a.fill("x") #=> ["x", "x", "x", "x"] + # a.fill("w", -1) #=> ["x", "x", "x", "w"] + # a.fill("z", 2, 2) #=> ["x", "x", "z", "z"] + # a.fill("y", 0..1) #=> ["y", "y", "z", "z"] + # a.fill { |i| i*i } #=> [0, 1, 4, 9] + # a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27] + # a.fill(1, 2) { |i| i+1 } #=> [0, 2, 3, 27] + # a.fill(0..1) { |i| i+1 } #=> [1, 2, 3, 27] + # + + def fill(arg0=nil, arg1=nil, arg2=nil, &block) + if arg0.nil? && arg1.nil? && arg2.nil? && !block + raise ArgumentError, "wrong number of arguments (0 for 1..3)" + end + + beg = len = 0 + ary = [] + if block + if arg0.nil? && arg1.nil? && arg2.nil? + # ary.fill { |index| block } -> ary + beg = 0 + len = self.size + elsif !arg0.nil? && arg0.kind_of?(Range) + # ary.fill(range) { |index| block } -> ary + beg = arg0.begin + beg += self.size if beg < 0 + len = arg0.end + len += self.size if len < 0 + len += 1 unless arg0.exclude_end? + elsif !arg0.nil? + # ary.fill(start [, length] ) { |index| block } -> ary + beg = arg0 + beg += self.size if beg < 0 + if arg1.nil? + len = self.size + else + len = arg0 + arg1 + end + end + else + if !arg0.nil? && arg1.nil? && arg2.nil? + # ary.fill(obj) -> ary + beg = 0 + len = self.size + elsif !arg0.nil? && !arg1.nil? && arg1.kind_of?(Range) + # ary.fill(obj, range ) -> ary + beg = arg1.begin + beg += self.size if beg < 0 + len = arg1.end + len += self.size if len < 0 + len += 1 unless arg1.exclude_end? + elsif !arg0.nil? && !arg1.nil? + # ary.fill(obj, start [, length]) -> ary + beg = arg1 + beg += self.size if beg < 0 + if arg2.nil? + len = self.size + else + len = beg + arg2 + end + end + end + + i = beg + if block + while i < len + self[i] = block.call(i) + i += 1 + end + else + while i < len + self[i] = arg0 + i += 1 + end + end + self + end + + ## + # call-seq: + # ary.rotate(count=1) -> new_ary + # + # Returns a new array by rotating +self+ so that the element at +count+ is + # the first element of the new array. + # + # If +count+ is negative then it rotates in the opposite direction, starting + # from the end of +self+ where +-1+ is the last element. + # + # a = [ "a", "b", "c", "d" ] + # a.rotate #=> ["b", "c", "d", "a"] + # a #=> ["a", "b", "c", "d"] + # a.rotate(2) #=> ["c", "d", "a", "b"] + # a.rotate(-3) #=> ["b", "c", "d", "a"] + + def rotate(count=1) + ary = [] + len = self.length + + if len > 0 + idx = (count < 0) ? (len - (~count % len) - 1) : (count % len) # rotate count + len.times do + ary << self[idx] + idx += 1 + idx = 0 if idx > len-1 + end + end + ary + end + + ## + # call-seq: + # ary.rotate!(count=1) -> ary + # + # Rotates +self+ in place so that the element at +count+ comes first, and + # returns +self+. + # + # If +count+ is negative then it rotates in the opposite direction, starting + # from the end of the array where +-1+ is the last element. + # + # a = [ "a", "b", "c", "d" ] + # a.rotate! #=> ["b", "c", "d", "a"] + # a #=> ["b", "c", "d", "a"] + # a.rotate!(2) #=> ["d", "a", "b", "c"] + # a.rotate!(-3) #=> ["a", "b", "c", "d"] + + def rotate!(count=1) + self.replace(self.rotate(count)) + end + + ## + # call-seq: + # ary.delete_if { |item| block } -> ary + # ary.delete_if -> Enumerator + # + # Deletes every element of +self+ for which block evaluates to +true+. + # + # The array is changed instantly every time the block is called, not after + # the iteration is over. + # + # See also Array#reject! + # + # If no block is given, an Enumerator is returned instead. + # + # scores = [ 97, 42, 75 ] + # scores.delete_if {|score| score < 80 } #=> [97] + + def delete_if(&block) + return to_enum :delete_if unless block + + idx = 0 + while idx < self.size do + if block.call(self[idx]) + self.delete_at(idx) + else + idx += 1 + end + end + self + end + + ## + # call-seq: + # ary.reject! { |item| block } -> ary or nil + # ary.reject! -> Enumerator + # + # Equivalent to Array#delete_if, deleting elements from +self+ for which the + # block evaluates to +true+, but returns +nil+ if no changes were made. + # + # The array is changed instantly every time the block is called, not after + # the iteration is over. + # + # See also Enumerable#reject and Array#delete_if. + # + # If no block is given, an Enumerator is returned instead. + + def reject!(&block) + return to_enum :reject! unless block + + len = self.size + idx = 0 + while idx < self.size do + if block.call(self[idx]) + self.delete_at(idx) + else + idx += 1 + end + end + if self.size == len + nil + else + self + end + end + + ## + # call-seq: + # ary.insert(index, obj...) -> ary + # + # Inserts the given values before the element with the given +index+. + # + # Negative indices count backwards from the end of the array, where +-1+ is + # the last element. + # + # a = %w{ a b c d } + # a.insert(2, 99) #=> ["a", "b", 99, "c", "d"] + # a.insert(-2, 1, 2, 3) #=> ["a", "b", 99, "c", 1, 2, 3, "d"] + + def insert(idx, *args) + idx += self.size + 1 if idx < 0 + self[idx, 0] = args + self + end + + ## + # call-seq: + # ary.bsearch {|x| block } -> elem + # + # By using binary search, finds a value from this array which meets + # the given condition in O(log n) where n is the size of the array. + # + # You can use this method in two use cases: a find-minimum mode and + # a find-any mode. In either case, the elements of the array must be + # monotone (or sorted) with respect to the block. + # + # In find-minimum mode (this is a good choice for typical use case), + # the block must return true or false, and there must be an index i + # (0 <= i <= ary.size) so that: + # + # - the block returns false for any element whose index is less than + # i, and + # - the block returns true for any element whose index is greater + # than or equal to i. + # + # This method returns the i-th element. If i is equal to ary.size, + # it returns nil. + # + # ary = [0, 4, 7, 10, 12] + # ary.bsearch {|x| x >= 4 } #=> 4 + # ary.bsearch {|x| x >= 6 } #=> 7 + # ary.bsearch {|x| x >= -1 } #=> 0 + # ary.bsearch {|x| x >= 100 } #=> nil + # + # In find-any mode (this behaves like libc's bsearch(3)), the block + # must return a number, and there must be two indices i and j + # (0 <= i <= j <= ary.size) so that: + # + # - the block returns a positive number for ary[k] if 0 <= k < i, + # - the block returns zero for ary[k] if i <= k < j, and + # - the block returns a negative number for ary[k] if + # j <= k < ary.size. + # + # Under this condition, this method returns any element whose index + # is within i...j. If i is equal to j (i.e., there is no element + # that satisfies the block), this method returns nil. + # + # ary = [0, 4, 7, 10, 12] + # # try to find v such that 4 <= v < 8 + # ary.bsearch {|x| 1 - (x / 4).truncate } #=> 4 or 7 + # # try to find v such that 8 <= v < 10 + # ary.bsearch {|x| 4 - (x / 2).truncate } #=> nil + # + # You must not mix the two modes at a time; the block must always + # return either true/false, or always return a number. It is + # undefined which value is actually picked up at each iteration. + + def bsearch(&block) + return to_enum :bsearch unless block + + if idx = bsearch_index(&block) + self[idx] + else + nil + end + end + + ## + # call-seq: + # ary.bsearch_index {|x| block } -> int or nil + # + # By using binary search, finds an index of a value from this array which + # meets the given condition in O(log n) where n is the size of the array. + # + # It supports two modes, depending on the nature of the block and they are + # exactly the same as in the case of #bsearch method with the only difference + # being that this method returns the index of the element instead of the + # element itself. For more details consult the documentation for #bsearch. + + def bsearch_index(&block) + return to_enum :bsearch_index unless block + + low = 0 + high = size + satisfied = false + + while low < high + mid = ((low+high)/2).truncate + res = block.call self[mid] + + case res + when 0 # find-any mode: Found! + return mid + when Numeric # find-any mode: Continue... + in_lower_half = res < 0 + when true # find-min mode + in_lower_half = true + satisfied = true + when false, nil # find-min mode + in_lower_half = false + else + raise TypeError, 'invalid block result (must be numeric, true, false or nil)' + end + + if in_lower_half + high = mid + else + low = mid + 1 + end + end + + satisfied ? low : nil + end + + ## + # call-seq: + # ary.delete_if { |item| block } -> ary + # ary.delete_if -> Enumerator + # + # Deletes every element of +self+ for which block evaluates to +true+. + # + # The array is changed instantly every time the block is called, not after + # the iteration is over. + # + # See also Array#reject! + # + # If no block is given, an Enumerator is returned instead. + # + # scores = [ 97, 42, 75 ] + # scores.delete_if {|score| score < 80 } #=> [97] + + def delete_if(&block) + return to_enum :delete_if unless block + + idx = 0 + while idx < self.size do + if block.call(self[idx]) + self.delete_at(idx) + else + idx += 1 + end + end + self + end + + ## + # call-seq: + # ary.keep_if { |item| block } -> ary + # ary.keep_if -> Enumerator + # + # Deletes every element of +self+ for which the given block evaluates to + # +false+. + # + # See also Array#select! + # + # If no block is given, an Enumerator is returned instead. + # + # a = [1, 2, 3, 4, 5] + # a.keep_if { |val| val > 3 } #=> [4, 5] + + def keep_if(&block) + return to_enum :keep_if unless block + + idx = 0 + len = self.size + while idx < self.size do + if block.call(self[idx]) + idx += 1 + else + self.delete_at(idx) + end + end + self + end + + ## + # call-seq: + # ary.select! {|item| block } -> ary or nil + # ary.select! -> Enumerator + # + # Invokes the given block passing in successive elements from +self+, + # deleting elements for which the block returns a +false+ value. + # + # If changes were made, it will return +self+, otherwise it returns +nil+. + # + # See also Array#keep_if + # + # If no block is given, an Enumerator is returned instead. + + def select!(&block) + return to_enum :select! unless block + + result = [] + idx = 0 + len = size + while idx < len + elem = self[idx] + result << elem if block.call(elem) + idx += 1 + end + return nil if len == result.size + self.replace(result) + end + + ## + # call-seq: + # ary.index(val) -> int or nil + # ary.index {|item| block } -> int or nil + # + # Returns the _index_ of the first object in +ary+ such that the object is + # <code>==</code> to +obj+. + # + # If a block is given instead of an argument, returns the _index_ of the + # first object for which the block returns +true+. Returns +nil+ if no + # match is found. + # + # ISO 15.2.12.5.14 + def index(val=NONE, &block) + return to_enum(:find_index, val) if !block && val == NONE + + if block + idx = 0 + len = size + while idx < len + return idx if block.call self[idx] + idx += 1 + end + else + return self.__ary_index(val) + end + nil + end + + ## + # call-seq: + # ary.to_ary -> ary + # + # Returns +self+. + # + def to_ary + self + end + + ## + # call-seq: + # ary.dig(idx, ...) -> object + # + # Extracts the nested value specified by the sequence of <i>idx</i> + # objects by calling +dig+ at each step, returning +nil+ if any + # intermediate step is +nil+. + # + def dig(idx,*args) + n = self[idx] + if args.size > 0 + n&.dig(*args) + else + n + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/src/array.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/src/array.c new file mode 100644 index 000000000..e99599b09 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/src/array.c @@ -0,0 +1,244 @@ +#include <mruby.h> +#include <mruby/value.h> +#include <mruby/array.h> +#include <mruby/range.h> +#include <mruby/hash.h> + +/* + * call-seq: + * ary.assoc(obj) -> new_ary or nil + * + * Searches through an array whose elements are also arrays + * comparing _obj_ with the first element of each contained array + * using obj.==. + * Returns the first contained array that matches (that + * is, the first associated array), + * or +nil+ if no match is found. + * See also <code>Array#rassoc</code>. + * + * s1 = [ "colors", "red", "blue", "green" ] + * s2 = [ "letters", "a", "b", "c" ] + * s3 = "foo" + * a = [ s1, s2, s3 ] + * a.assoc("letters") #=> [ "letters", "a", "b", "c" ] + * a.assoc("foo") #=> nil + */ + +static mrb_value +mrb_ary_assoc(mrb_state *mrb, mrb_value ary) +{ + mrb_int i; + mrb_value v, k; + + mrb_get_args(mrb, "o", &k); + + for (i = 0; i < RARRAY_LEN(ary); ++i) { + v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]); + if (!mrb_nil_p(v) && RARRAY_LEN(v) > 0 && + mrb_equal(mrb, RARRAY_PTR(v)[0], k)) + return v; + } + return mrb_nil_value(); +} + +/* + * call-seq: + * ary.rassoc(obj) -> new_ary or nil + * + * Searches through the array whose elements are also arrays. Compares + * _obj_ with the second element of each contained array using + * <code>==</code>. Returns the first contained array that matches. See + * also <code>Array#assoc</code>. + * + * a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ] + * a.rassoc("two") #=> [2, "two"] + * a.rassoc("four") #=> nil + */ + +static mrb_value +mrb_ary_rassoc(mrb_state *mrb, mrb_value ary) +{ + mrb_int i; + mrb_value v, value; + + mrb_get_args(mrb, "o", &value); + + for (i = 0; i < RARRAY_LEN(ary); ++i) { + v = RARRAY_PTR(ary)[i]; + if (mrb_type(v) == MRB_TT_ARRAY && + RARRAY_LEN(v) > 1 && + mrb_equal(mrb, RARRAY_PTR(v)[1], value)) + return v; + } + return mrb_nil_value(); +} + +/* + * call-seq: + * ary.at(index) -> obj or nil + * + * Returns the element at _index_. A + * negative index counts from the end of +self+. Returns +nil+ + * if the index is out of range. See also <code>Array#[]</code>. + * + * a = [ "a", "b", "c", "d", "e" ] + * a.at(0) #=> "a" + * a.at(-1) #=> "e" + */ + +static mrb_value +mrb_ary_at(mrb_state *mrb, mrb_value ary) +{ + mrb_int pos; + mrb_get_args(mrb, "i", &pos); + + return mrb_ary_entry(ary, pos); +} + +static mrb_value +mrb_ary_values_at(mrb_state *mrb, mrb_value self) +{ + mrb_int argc; + mrb_value *argv; + + mrb_get_args(mrb, "*", &argv, &argc); + + return mrb_get_values_at(mrb, self, RARRAY_LEN(self), argc, argv, mrb_ary_ref); +} + +/* + * call-seq: + * ary.to_h -> Hash + * + * Returns the result of interpreting <i>aray</i> as an array of + * <tt>[key, value]</tt> paris. + * + * [[:foo, :bar], [1, 2]].to_h + * # => {:foo => :bar, 1 => 2} + * + */ + +static mrb_value +mrb_ary_to_h(mrb_state *mrb, mrb_value ary) +{ + mrb_int i; + mrb_value v, hash; + + hash = mrb_hash_new_capa(mrb, 0); + + for (i = 0; i < RARRAY_LEN(ary); ++i) { + mrb_value elt = RARRAY_PTR(ary)[i]; + v = mrb_check_array_type(mrb, elt); + + if (mrb_nil_p(v)) { + mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)", + mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, elt)), + mrb_fixnum_value(i) + ); + } + + if (RARRAY_LEN(v) != 2) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong array length at %S (expected 2, was %S)", + mrb_fixnum_value(i), + mrb_fixnum_value(RARRAY_LEN(v)) + ); + } + + mrb_hash_set(mrb, hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]); + } + + return hash; +} + +/* + * call-seq: + * ary.slice!(index) -> obj or nil + * ary.slice!(start, length) -> new_ary or nil + * ary.slice!(range) -> new_ary or nil + * + * Deletes the element(s) given by an +index+ (optionally up to +length+ + * elements) or by a +range+. + * + * Returns the deleted object (or objects), or +nil+ if the +index+ is out of + * range. + * + * a = [ "a", "b", "c" ] + * a.slice!(1) #=> "b" + * a #=> ["a", "c"] + * a.slice!(-1) #=> "c" + * a #=> ["a"] + * a.slice!(100) #=> nil + * a #=> ["a"] + */ + +static mrb_value +mrb_ary_slice_bang(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + mrb_int i, j, k, len, alen = ARY_LEN(a); + mrb_value index; + mrb_value val; + mrb_value *ptr; + mrb_value ary; + + mrb_ary_modify(mrb, a); + + if (mrb_get_args(mrb, "o|i", &index, &len) == 1) { + switch (mrb_type(index)) { + case MRB_TT_RANGE: + if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) { + goto delete_pos_len; + } + else { + return mrb_nil_value(); + } + case MRB_TT_FIXNUM: + val = mrb_funcall(mrb, self, "delete_at", 1, index); + return val; + default: + val = mrb_funcall(mrb, self, "delete_at", 1, index); + return val; + } + } + + i = mrb_fixnum(index); + delete_pos_len: + if (i < 0) i += alen; + if (i < 0 || alen < i) return mrb_nil_value(); + if (len < 0) return mrb_nil_value(); + if (alen == i) return mrb_ary_new(mrb); + if (len > alen - i) len = alen - i; + + ary = mrb_ary_new_capa(mrb, len); + ptr = ARY_PTR(a); + for (j = i, k = 0; k < len; ++j, ++k) { + mrb_ary_push(mrb, ary, ptr[j]); + } + + ptr += i; + for (j = i; j < alen - len; ++j) { + *ptr = *(ptr+len); + ++ptr; + } + + mrb_ary_resize(mrb, self, alen - len); + return ary; +} + +void +mrb_mruby_array_ext_gem_init(mrb_state* mrb) +{ + struct RClass * a = mrb->array_class; + + mrb_define_method(mrb, a, "assoc", mrb_ary_assoc, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY()); + mrb_define_method(mrb, a, "to_h", mrb_ary_to_h, MRB_ARGS_REQ(0)); + mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang, MRB_ARGS_ANY()); +} + +void +mrb_mruby_array_ext_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/test/array.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/test/array.rb new file mode 100644 index 000000000..c0db1b1cc --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-array-ext/test/array.rb @@ -0,0 +1,383 @@ +## +# Array(Ext) Test + +assert("Array.try_convert") do + assert_nil Array.try_convert(0) + assert_nil Array.try_convert(nil) + assert_equal [], Array.try_convert([]) + assert_equal [1,2,3], Array.try_convert([1,2,3]) +end + +assert("Array#assoc") do + s1 = [ "colors", "red", "blue", "green" ] + s2 = [ "letters", "a", "b", "c" ] + s3 = "foo" + a = [ s1, s2, s3 ] + + assert_equal [ "letters", "a", "b", "c" ], a.assoc("letters") + assert_nil a.assoc("foo") +end + +assert("Array#at") do + a = [ "a", "b", "c", "d", "e" ] + assert_equal "a", a.at(0) + assert_equal "e", a.at(-1) +end + +assert("Array#rassoc") do + a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ] + + assert_equal [2, "two"], a.rassoc("two") + assert_nil a.rassoc("four") +end + +assert("Array#uniq!") do + a = [1, 2, 3, 1] + a.uniq! + assert_equal [1, 2, 3], a + + b = [ "a", "b", "c" ] + assert_nil b.uniq! + + c = [["student","sam"], ["student","george"], ["teacher","matz"]] + assert_equal [["student", "sam"], ["teacher", "matz"]], c.uniq! { |s| s.first } + + d = [["student","sam"], ["teacher","matz"]] + assert_nil d.uniq! { |s| s.first } +end + +assert("Array#uniq") do + a = [1, 2, 3, 1] + assert_equal [1, 2, 3], a.uniq + assert_equal [1, 2, 3, 1], a + + b = [["student","sam"], ["student","george"], ["teacher","matz"]] + assert_equal [["student", "sam"], ["teacher", "matz"]], b.uniq { |s| s.first } +end + +assert("Array#-") do + a = [1, 2, 3, 1] + b = [1] + c = 1 + + assert_raise(TypeError) { a - c } + assert_equal [2, 3], (a - b) + assert_equal [1, 2, 3, 1], a +end + +assert("Array#|") do + a = [1, 2, 3, 1] + b = [1, 4] + c = 1 + + assert_raise(TypeError) { a | c } + assert_equal [1, 2, 3, 4], (a | b) + assert_equal [1, 2, 3, 1], a +end + +assert("Array#&") do + a = [1, 2, 3, 1] + b = [1, 4] + c = 1 + + assert_raise(TypeError) { a & c } + assert_equal [1], (a & b) + assert_equal [1, 2, 3, 1], a +end + +assert("Array#flatten") do + assert_equal [1, 2, "3", {4=>5}, :'6'], [1, 2, "3", {4=>5}, :'6'].flatten + assert_equal [1, 2, 3, 4, 5, 6], [1, 2, [3, 4, 5], 6].flatten + assert_equal [1, 2, 3, 4, 5, 6], [1, 2, [3, [4, 5], 6]].flatten + assert_equal [1, [2, [3, [4, [5, [6]]]]]], [1, [2, [3, [4, [5, [6]]]]]].flatten(0) + assert_equal [1, 2, [3, [4, [5, [6]]]]], [1, [2, [3, [4, [5, [6]]]]]].flatten(1) + assert_equal [1, 2, 3, [4, [5, [6]]]], [1, [2, [3, [4, [5, [6]]]]]].flatten(2) + assert_equal [1, 2, 3, 4, [5, [6]]], [1, [2, [3, [4, [5, [6]]]]]].flatten(3) + assert_equal [1, 2, 3, 4, 5, [6]], [1, [2, [3, [4, [5, [6]]]]]].flatten(4) + assert_equal [1, 2, 3, 4, 5, 6], [1, [2, [3, [4, [5, [6]]]]]].flatten(5) +end + +assert("Array#flatten!") do + assert_equal [1, 2, 3, 4, 5, 6], [1, 2, [3, [4, 5], 6]].flatten! +end + +assert("Array#compact") do + a = [1, nil, "2", nil, :t, false, nil] + assert_equal [1, "2", :t, false], a.compact + assert_equal [1, nil, "2", nil, :t, false, nil], a +end + +assert("Array#compact!") do + a = [1, nil, "2", nil, :t, false, nil] + a.compact! + assert_equal [1, "2", :t, false], a +end + +assert("Array#fetch") do + a = [ 11, 22, 33, 44 ] + assert_equal 22, a.fetch(1) + assert_equal 44, a.fetch(-1) + assert_equal 'cat', a.fetch(4, 'cat') + ret = 0 + a.fetch(100) { |i| ret = i } + assert_equal 100, ret + assert_raise(IndexError) { a.fetch(100) } +end + +assert("Array#fill") do + a = [ "a", "b", "c", "d" ] + assert_equal ["x", "x", "x", "x"], a.fill("x") + assert_equal ["x", "x", "x", "w"], a.fill("w", -1) + assert_equal ["x", "x", "z", "z"], a.fill("z", 2, 2) + assert_equal ["y", "y", "z", "z"], a.fill("y", 0..1) + assert_equal [0, 1, 4, 9], a.fill { |i| i*i } + assert_equal [0, 1, 8, 27], a.fill(-2) { |i| i*i*i } + assert_equal [0, 2, 3, 27], a.fill(1, 2) { |i| i+1 } + assert_equal [1, 2, 3, 27], a.fill(0..1) { |i| i+1 } + assert_raise(ArgumentError) { a.fill } + + assert_equal([0, 1, 2, 3, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, -2, 1)) + assert_equal([0, 1, 2, 3, -1, -1, -1], [0, 1, 2, 3, 4, 5].fill(-1, -2, 3)) + assert_equal([0, 1, 2, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3..4)) + assert_equal([0, 1, 2, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 3...4)) + assert_equal([0, 1, -1, -1, -1, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2..-2)) + assert_equal([0, 1, -1, -1, 4, 5], [0, 1, 2, 3, 4, 5].fill(-1, 2...-2)) + assert_equal([0, 1, 2, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(3..4){|i| i+10}) + assert_equal([0, 1, 2, 13, 4, 5], [0, 1, 2, 3, 4, 5].fill(3...4){|i| i+10}) + assert_equal([0, 1, 12, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(2..-2){|i| i+10}) + assert_equal([0, 1, 12, 13, 4, 5], [0, 1, 2, 3, 4, 5].fill(2...-2){|i| i+10}) + + assert_equal [1, 2, 3, 4, 'x', 'x'], [1, 2, 3, 4, 5, 6].fill('x', -2..-1) + assert_equal [1, 2, 3, 4, 'x', 6], [1, 2, 3, 4, 5, 6].fill('x', -2...-1) + assert_equal [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6].fill('x', -2...-2) + assert_equal [1, 2, 3, 4, 'x', 6], [1, 2, 3, 4, 5, 6].fill('x', -2..-2) + assert_equal [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6].fill('x', -2..0) +end + +assert("Array#reverse_each") do + a = [ "a", "b", "c", "d" ] + b = [] + a.reverse_each do |i| + b << i + end + assert_equal [ "d", "c", "b", "a" ], b + + if Object.const_defined?(:Enumerator) + assert_equal [ "d", "c", "b", "a" ], a.reverse_each.to_a + else + true + end +end + +assert("Array#rotate") do + a = ["a", "b", "c", "d"] + assert_equal ["b", "c", "d", "a"], a.rotate + assert_equal ["a", "b", "c", "d"], a + assert_equal ["c", "d", "a", "b"], a.rotate(2) + assert_equal ["b", "c", "d", "a"], a.rotate(-3) + assert_equal ["c", "d", "a", "b"], a.rotate(10) + assert_equal [], [].rotate +end + +assert("Array#rotate!") do + a = ["a", "b", "c", "d"] + assert_equal ["b", "c", "d", "a"], a.rotate! + assert_equal ["b", "c", "d", "a"], a + assert_equal ["d", "a", "b", "c"], a.rotate!(2) + assert_equal ["a", "b", "c", "d"], a.rotate!(-3) + assert_equal ["c", "d", "a", "b"], a.rotate(10) + assert_equal [], [].rotate! +end + +assert("Array#delete_if") do + a = [1, 2, 3, 4, 5] + assert_equal [1, 2, 3, 4, 5], a.delete_if { false } + assert_equal [1, 2, 3, 4, 5], a + + a = [1, 2, 3, 4, 5] + assert_equal [], a.delete_if { true } + assert_equal [], a + + a = [1, 2, 3, 4, 5] + assert_equal [1, 2, 3], a.delete_if { |i| i > 3 } + assert_equal [1, 2, 3], a +end + +assert("Array#reject!") do + a = [1, 2, 3, 4, 5] + assert_nil a.reject! { false } + assert_equal [1, 2, 3, 4, 5], a + + a = [1, 2, 3, 4, 5] + assert_equal [], a.reject! { true } + assert_equal [], a + + a = [1, 2, 3, 4, 5] + assert_equal [1, 2, 3], a.reject! { |val| val > 3 } + assert_equal [1, 2, 3], a +end + +assert("Array#insert") do + a = ["a", "b", "c", "d"] + assert_equal ["a", "b", 99, "c", "d"], a.insert(2, 99) + assert_equal ["a", "b", 99, "c", 1, 2, 3, "d"], a.insert(-2, 1, 2, 3) + + b = ["a", "b", "c", "d"] + assert_equal ["a", "b", "c", "d", nil, nil, 99], b.insert(6, 99) +end + +assert("Array#bsearch") do + # Find minimum mode + a = [0, 2, 4] + assert_equal 0, a.bsearch{ |x| x >= -1 } + assert_equal 0, a.bsearch{ |x| x >= 0 } + assert_equal 2, a.bsearch{ |x| x >= 1 } + assert_equal 2, a.bsearch{ |x| x >= 2 } + assert_equal 4, a.bsearch{ |x| x >= 3 } + assert_equal 4, a.bsearch{ |x| x >= 4 } + assert_nil a.bsearch{ |x| x >= 5 } + + # Find any mode + a = [0, 4, 8] + def between(lo, x, hi) + if x < lo + 1 + elsif x > hi + -1 + else + 0 + end + end + assert_nil a.bsearch{ |x| between(-3, x, -1) } + assert_equal 0, a.bsearch{ |x| between(-1, x, 1) } + assert_nil a.bsearch{ |x| between( 1, x, 3) } + assert_equal 4, a.bsearch{ |x| between( 3, x, 5) } + assert_nil a.bsearch{ |x| between( 5, x, 7) } + assert_equal 8, a.bsearch{ |x| between( 7, x, 9) } + assert_nil a.bsearch{ |x| between( 9, x, 11) } + + assert_equal 0, a.bsearch{ |x| between( 0, x, 3) } + assert_equal 4, a.bsearch{ |x| between( 0, x, 4) } + assert_equal 4, a.bsearch{ |x| between( 4, x, 8) } + assert_equal 8, a.bsearch{ |x| between( 5, x, 8) } + + # Invalid block result + assert_raise TypeError, 'invalid block result (must be numeric, true, false or nil)' do + a.bsearch{ 'I like to watch the world burn' } + end +end + +assert("Array#bsearch_index") do + # tested through Array#bsearch +end + +assert("Array#delete_if") do + a = [1, 2, 3, 4, 5] + assert_equal [1, 2, 3, 4, 5], a.delete_if { false } + assert_equal [1, 2, 3, 4, 5], a + + a = [1, 2, 3, 4, 5] + assert_equal [], a.delete_if { true } + assert_equal [], a + + a = [ 1, 2, 3, 4, 5 ] + assert_equal [1, 2, 3], a.delete_if { |val| val > 3 } +end + +assert("Array#keep_if") do + a = [1, 2, 3, 4, 5] + assert_equal [1, 2, 3, 4, 5], a.keep_if { true } + assert_equal [1, 2, 3, 4, 5], a + + a = [1, 2, 3, 4, 5] + assert_equal [], a.keep_if { false } + assert_equal [], a + + a = [1, 2, 3, 4, 5] + assert_equal [4, 5], a.keep_if { |val| val > 3 } + assert_equal [4, 5], a +end + +assert("Array#select!") do + a = [1, 2, 3, 4, 5] + assert_nil a.select! { true } + assert_equal [1, 2, 3, 4, 5], a + + a = [1, 2, 3, 4, 5] + assert_equal [], a.select! { false } + assert_equal [], a + + a = [1, 2, 3, 4, 5] + assert_equal [4, 5], a.select! { |val| val > 3 } + assert_equal [4, 5], a +end + +assert('Array#values_at') do + a = %w{red green purple white none} + + assert_equal %w{red purple none}, a.values_at(0, 2, 4) + assert_equal ['green', 'white', nil, nil], a.values_at(1, 3, 5, 7) + assert_equal ['none', 'white', 'white', nil], a.values_at(-1, -2, -2, -7) + assert_equal ['none', nil, nil, 'red', 'green', 'purple'], a.values_at(4..6, 0...3) + assert_raise(TypeError) { a.values_at 'tt' } +end + +assert('Array#to_h') do + assert_equal({}, [].to_h) + assert_equal({a: 1, b:2}, [[:a, 1], [:b, 2]].to_h) + + assert_raise(TypeError) { [1].to_h } + assert_raise(ArgumentError) { [[1]].to_h } +end + +assert('Array#to_h (Modified)') do + class A + def to_ary + $a.clear + nil + end + end + $a = [A.new] + assert_raise(TypeError) { $a.to_h } +end + +assert("Array#index (block)") do + assert_nil (1..10).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } + assert_equal 34, (1..100).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } +end + +assert("Array#to_ary") do + assert_equal [], [].to_ary + assert_equal [1,2,3], [1,2,3].to_ary +end + +assert("Array#dig") do + h = [[[1]], 0] + assert_equal(1, h.dig(0, 0, 0)) + assert_nil(h.dig(2, 0)) + assert_raise(TypeError) {h.dig(:a)} +end + +assert("Array#slice!") do + a = [1, 2, 3] + b = a.slice!(0) + c = [1, 2, 3, 4, 5] + d = c.slice!(0, 2) + e = [1, 2, 3, 4, 5] + f = e.slice!(1..3) + g = [1, 2, 3] + h = g.slice!(-1) + i = [1, 2, 3] + j = i.slice!(0, -1) + + assert_equal(a, [2, 3]) + assert_equal(b, 1) + assert_equal(c, [3, 4, 5]) + assert_equal(d, [1, 2]) + assert_equal(e, [1, 5]) + assert_equal(f, [2, 3, 4]) + assert_equal(g, [1, 2]) + assert_equal(h, 3) + assert_equal(i, [1, 2, 3]) + assert_equal(j, nil) +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/bintest/mrdb.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/bintest/mrdb.rb new file mode 100644 index 000000000..26f3138aa --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/bintest/mrdb.rb @@ -0,0 +1,286 @@ +require 'open3' +require 'tempfile' + +class BinTest_MrubyBinDebugger + @debug1=false + @debug2=true + @debug3=true + def self.test(rubysource, testcase) + script, bin = Tempfile.new(['test', '.rb']), Tempfile.new(['test', '.mrb']) + + # .rb + script.write rubysource + script.flush + + # compile + `./bin/mrbc -g -o "#{bin.path}" "#{script.path}"` + + # add mrdb quit + testcase << {:cmd=>"quit"} + + stdin_data = testcase.map{|t| t[:cmd]}.join("\n") << "\n" + + ["bin/mrdb #{script.path}","bin/mrdb -b #{bin.path}"].each do |cmd| + o, s = Open3.capture2(cmd, :stdin_data => stdin_data) + + exp_vals = testcase.map{|t| t.fetch(:exp, nil)} + unexp_vals = testcase.map{|t| t.fetch(:unexp, nil)} + +if @debug1 + o.split("\n").each_with_index do |i,actual| + p [i,actual] + end +end + # compare actual / expected + o.split("\n").each do |actual| + next if actual.empty? + exp = exp_vals.shift +if @debug2 + a = true + a = actual.include?(exp) unless exp.nil? + p [actual, exp] unless a +end + assert_true actual.include?(exp) unless exp.nil? + end + # compare actual / unexpected + o.split("\n").each do |actual| + next if actual.empty? + unexp = unexp_vals.shift +if @debug3 + a = false + a = actual.include?(unexp) unless unexp.nil? + p [actual, unexp] if a +end + assert_false actual.include?(unexp) unless unexp.nil? + end + end + end +end + +INVCMD = "invalid command" + +assert('mruby-bin-debugger(mrdb) command line') do + # ruby source + src = "foo = 'foo'\n" + + str = "" + 103.times { + str += "1234567890" + } + cmd = "p a=#{str}" + + # test case + BinTest_MrubyBinDebugger.test(src, [{:cmd=>cmd[0...1023], :unexp=>'command line too long.'}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>cmd[0...1024], :unexp=>'command line too long.'}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>cmd[0...1025], :exp=>'command line too long.'}]) +end + +assert('mruby-bin-debugger(mrdb) command: "break"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"b", :unexp=>INVCMD} + tc << {:cmd=>"br", :unexp=>INVCMD} + tc << {:cmd=>"brea", :unexp=>INVCMD} + tc << {:cmd=>"break", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"bl", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"breaka", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "continue"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"c", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"co", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"continu", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"continue", :unexp=>INVCMD}]) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"cn", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"continuee", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "delete"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"d 1", :unexp=>INVCMD} + tc << {:cmd=>"de 1", :unexp=>INVCMD} + tc << {:cmd=>"delet 1", :unexp=>INVCMD} + tc << {:cmd=>"delete 1", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"dd 1", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"deletee 1", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "disable"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"dis", :unexp=>INVCMD} + tc << {:cmd=>"disa", :unexp=>INVCMD} + tc << {:cmd=>"disabl", :unexp=>INVCMD} + tc << {:cmd=>"disable", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"di", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"disb", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"disablee", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "enable"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"en", :unexp=>INVCMD} + tc << {:cmd=>"ena", :unexp=>INVCMD} + tc << {:cmd=>"enabl", :unexp=>INVCMD} + tc << {:cmd=>"enable", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"e", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"enb", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"enablee", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "eval"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"ev", :unexp=>INVCMD} + tc << {:cmd=>"eva", :unexp=>INVCMD} + tc << {:cmd=>"eval", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"e", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"evl", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"evall", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "help"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"h", :unexp=>INVCMD} + tc << {:cmd=>"he", :unexp=>INVCMD} + tc << {:cmd=>"hel", :unexp=>INVCMD} + tc << {:cmd=>"help", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"hl", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"helpp", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "info breakpoints"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"i b", :unexp=>INVCMD} + tc << {:cmd=>"in b", :unexp=>INVCMD} + tc << {:cmd=>"i br", :unexp=>INVCMD} + tc << {:cmd=>"inf breakpoint", :unexp=>INVCMD} + tc << {:cmd=>"info breakpoints", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"ii b", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"i bb", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"infoo breakpoints", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"info breakpointss", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "list"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"l", :unexp=>INVCMD} + tc << {:cmd=>"li", :unexp=>INVCMD} + tc << {:cmd=>"lis", :unexp=>INVCMD} + tc << {:cmd=>"list", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"ll", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"listt", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "print"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"p", :unexp=>INVCMD} + tc << {:cmd=>"pr", :unexp=>INVCMD} + tc << {:cmd=>"prin", :unexp=>INVCMD} + tc << {:cmd=>"print", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"pp", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"printt", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "quit"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"q", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"qu", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"qui", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"quit", :unexp=>INVCMD}]) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"qq", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"quitt", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "run"') do + # ruby source + src = "foo = 'foo'\n" + + # test case + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"r", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"ru", :unexp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"run", :unexp=>INVCMD}]) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"rr", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"runn", :exp=>INVCMD}]) +end + +assert('mruby-bin-debugger(mrdb) command: "step"') do + # ruby source + src = <<"SRC" +while true + foo = 'foo' +end +SRC + + # test case + tc = [] + tc << {:cmd=>"s", :unexp=>INVCMD} + tc << {:cmd=>"st", :unexp=>INVCMD} + tc << {:cmd=>"ste", :unexp=>INVCMD} + tc << {:cmd=>"step", :unexp=>INVCMD} + BinTest_MrubyBinDebugger.test(src, tc) + + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"ss", :exp=>INVCMD}]) + BinTest_MrubyBinDebugger.test(src, [{:cmd=>"stepp", :exp=>INVCMD}]) +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/bintest/print.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/bintest/print.rb new file mode 100644 index 000000000..1bc96c478 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/bintest/print.rb @@ -0,0 +1,701 @@ +require 'open3' +require 'tempfile' + +class BinTest_MrubyBinDebugger + @debug1=false + @debug2=true + def self.test(rubysource, testcase) + script, bin = Tempfile.new(['test', '.rb']), Tempfile.new(['test', '.mrb']) + + # .rb + script.write rubysource + script.flush + + # compile + `./bin/mrbc -g -o "#{bin.path}" "#{script.path}"` + + # add mrdb quit + testcase << {:cmd=>"quit"} + + stdin_data = testcase.map{|t| t[:cmd]}.join("\n") << "\n" + + ["bin/mrdb #{script.path}","bin/mrdb -b #{bin.path}"].each do |cmd| + o, s = Open3.capture2(cmd, :stdin_data => stdin_data) + + exp_vals = testcase.map{|t| t.fetch(:exp, nil)} +=begin +if @debug1 + o.split("\n").each_with_index do |i,actual| + p [i,actual] + end +end + # compare actual / expected + o.split("\n").each do |actual| + next if actual.empty? + exp = exp_vals.shift +if @debug2 + a = true + a = actual.include?(exp) unless exp.nil? + p [actual, exp] unless a +end + assert_true actual.include?(exp) unless exp.nil? + end +=end + idx = 0 + exp_vals.each do |exp| + next if exp.nil? + idx = o.index(exp, idx) + assert_false idx.nil? + break unless idx + idx += 1 + end + end + end +end + +assert('mruby-bin-debugger(print) invalid arguments') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"p", :exp=>"Parameter not specified."} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) nomal') do + # ruby source + src = <<"SRC" +foo = 'foo' +bar = foo +baz = bar +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"p (1+2)", :exp=>'$1 = 3'} + tc << {:cmd=>"p foo", :exp=>'$2 = "foo"'} + tc << {:cmd=>"p foo*=2", :exp=>'$3 = "foofoo"'} + tc << {:cmd=>"s"} + tc << {:cmd=>"p bar", :exp=>'$4 = "foofoo"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) error') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"p (1+2", :exp=>'$1 = SyntaxError'} + tc << {:cmd=>"p bar", :exp=>'$2 = NoMethodError'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +# Kernel#instance_eval(string) does't work multiple statements. +=begin +assert('mruby-bin-debugger(print) multiple statements') do + # ruby source + src = <<"SRC" +x = 0 +y = 0 +z = 0 +SRC + + # test case + tc = [] + tc << {:cmd=>"s",} + tc << {:cmd=>"p x=1;x+=2", :exp=>"3"} + tc << {:cmd=>"s",} + tc << {:cmd=>"p x", :exp=>"3"} + + BinTest_MrubyBinDebugger.test(src, tc) +end +=end + +assert('mruby-bin-debugger(print) scope:top') do + # ruby source (bp is break point) + src = "bp=nil\n" + + # test case + tc = [] + tc << {:cmd=>"p self", :exp=>'$1 = main'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) scope:class') do + # ruby source (bp is break point) + src = <<"SRC" +class TestClassScope + bp = nil +end +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"p self", :exp=>'$1 = TestClassScope'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) scope:module') do + # ruby source (bp is break point) + src = <<"SRC" +class TestModuleScope + bp = nil +end +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"p self", :exp=>'$1 = TestModuleScope'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) scope:instance method') do + # ruby source (bp is break point) + src = <<"SRC" +class TestMethodScope + def m + bp = nil + end +end +TestMethodScope.new.m +SRC + + tc = [] + tc << {:cmd=>"b 3"} + tc << {:cmd=>"r"} + tc << {:cmd=>"p self", :exp=>'$1 = #<TestMethodScope:'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) scope:class method') do + # ruby source (bp is break point) + src = <<"SRC" +class TestClassMethodScope + def self.cm + bp = nil + end +end +TestClassMethodScope.cm +SRC + + tc = [] + tc << {:cmd=>"b 3"} + tc << {:cmd=>"r"} + tc << {:cmd=>"p self", :exp=>'$1 = TestClassMethodScope'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) scope:block') do + # ruby source (bp is break point) + src = <<"SRC" +1.times do + bp = nil +end +class TestBlockScope + 1.times do + bp = nil + end + def m + 1.times do + bp = nil + end + end +end +TestBlockScope.new.m +SRC + + tc = [] + tc << {:cmd=>"b 2"} + tc << {:cmd=>"b 6"} + tc << {:cmd=>"b 10"} + tc << {:cmd=>"c"} + tc << {:cmd=>"p self", :exp=>'$1 = main'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p self", :exp=>'$2 = TestBlockScope'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p self", :exp=>'$3 = #<TestBlockScope:'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) same name:local variabe') do + # ruby source (bp is break point) + src = <<"SRC" +lv = 'top' +class TestLocalVariableName + lv = 'class' + def m + lv = 'instance method' + bp = nil + end + bp = nil +end +TestLocalVariableName.new.m +bp = nil +SRC + + tc = [] + tc << {:cmd=>"b 6"} + tc << {:cmd=>"b 8"} + tc << {:cmd=>"b 11"} + tc << {:cmd=>"r"} + tc << {:cmd=>"p lv", :exp=>'$1 = "class"'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p lv", :exp=>'$2 = "instance method"'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p lv", :exp=>'$3 = "top"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) same name:instance variabe') do + # ruby source (bp is break point) + src = <<"SRC" +@iv = 'top' +class TestInstanceVariableName + def initialize(v) + @iv = v + end + def m + bp = nil + end +end +i1 = TestInstanceVariableName.new('instance1') +i2 = TestInstanceVariableName.new('instance2') +i1.m +i2.m +bp = nil +SRC + + tc = [] + tc << {:cmd=>"b 7"} + tc << {:cmd=>"b 14"} + tc << {:cmd=>"r"} + tc << {:cmd=>"p @iv", :exp=>'$1 = "instance1"'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p @iv", :exp=>'$2 = "instance2"'} + tc << {:cmd=>"c"} + tc << {:cmd=>"p @iv", :exp=>'$3 = "top"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +# Kernel#instance_eval(string) does't work const. +=begin +assert('mruby-bin-debugger(print) same name:const') do + # ruby source (bp is break point) + src = <<"SRC" +CONST='top' +class TestConstNameSuperClass + CONST='super class' + def m + bp = nil + end +end +class TestConstNameSubClass < TestConstNameSuperClass + CONST='sub class' + def m + bp = nil + end +end + +TestConstNameSuperClass.new.m() +TestConstNameSubClass.new.m() +bp = nil +SRC + + # todo: wait for 'break' to be implimented + tc = [] + 9.times { tc << {:cmd=>"s"} } + tc << {:cmd=>"p CONST", :exp=>"super class"} + 3.times { tc << {:cmd=>"s"} } + tc << {:cmd=>"p CONST", :exp=>"sub class"} + 1.times { tc << {:cmd=>"s"} } + tc << {:cmd=>"p CONST", :exp=>"top"} + + BinTest_MrubyBinDebugger.test(src, tc) +end +=end + +assert('mruby-bin-debugger(print) Literal:Numeric') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>"p 100", :exp=>'$1 = 100'} + tc << {:cmd=>"p -0b100", :exp=>'$2 = -4'} + tc << {:cmd=>"p +0100", :exp=>'$3 = 64'} + tc << {:cmd=>"p 0x100", :exp=>'$4 = 256'} + tc << {:cmd=>"p 1_234", :exp=>'$5 = 1234'} + tc << {:cmd=>"p 0b1000_0000", :exp=>"$6 = #{0b1000_0000}"} + tc << {:cmd=>"p 0x1000_0000", :exp=>"$7 = #{0x1000_0000}"} + + tc << {:cmd=>"p 3.14", :exp=>'$8 = 3.14'} + tc << {:cmd=>"p -12.3", :exp=>'$9 = -12.3'} + tc << {:cmd=>"p +12.000", :exp=>'$10 = 12.0'} + tc << {:cmd=>"p 1e4", :exp=>'$11 = 10000.0'} + tc << {:cmd=>"p -0.1e-2", :exp=>'$12 = -0.001'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Literal:String') do + # ruby source + src = <<"SRC" +foo = 'foo' +bar = "bar" +baz = "baz" +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"s"} + + tc << {:cmd=>'p "str"', :exp=>'$1 = "str"'} + tc << {:cmd=>'p "s\tt\rr\n"', :exp=>'$2 = "s\\tt\\rr\\n"'} + tc << {:cmd=>'p "\C-a\C-z"', :exp=>'$3 = "\\001\\032"'} + tc << {:cmd=>'p "#{foo+bar}"', :exp=>'$4 = "foobar"'} + + tc << {:cmd=>'p \'str\'', :exp=>'$5 = "str"'} + tc << {:cmd=>'p \'s\\tt\\rr\\n\'', :exp=>'$6 = "s\\\\tt\\\\rr\\\\n"'} + tc << {:cmd=>'p \'\\C-a\\C-z\'', :exp=>'$7 = "\\\\C-a\\\\C-z"'} + tc << {:cmd=>'p \'#{foo+bar}\'', :exp=>'$8 = "#{foo+bar}"'} + + tc << {:cmd=>'p %!str!', :exp=>'$9 = "str"'} + tc << {:cmd=>'p %!s\tt\rr\n!', :exp=>'$10 = "s\\tt\\rr\\n"'} + tc << {:cmd=>'p %!\C-a\C-z!', :exp=>'$11 = "\\001\\032"'} + tc << {:cmd=>'p %!#{foo+bar}!', :exp=>'$12 = "foobar"'} + + tc << {:cmd=>'p %Q!str!', :exp=>'$13 = "str"'} + tc << {:cmd=>'p %Q!s\tt\rr\n!', :exp=>'$14 = "s\\tt\\rr\\n"'} + tc << {:cmd=>'p %Q!\C-a\C-z!', :exp=>'$15 = "\\001\\032"'} + tc << {:cmd=>'p %Q!#{foo+bar}!', :exp=>'$16 = "foobar"'} + + tc << {:cmd=>'p %q!str!', :exp=>'$17 = "str"'} + tc << {:cmd=>'p %q!s\\tt\\rr\\n!', :exp=>'$18 = "s\\\\tt\\\\rr\\\\n"'} + tc << {:cmd=>'p %q!\\C-a\\C-z!', :exp=>'$19 = "\\\\C-a\\\\C-z"'} + tc << {:cmd=>'p %q!#{foo+bar}!', :exp=>'$20 = "#{foo+bar}"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Literal:Array') do + # ruby source + src = <<"SRC" +foo = 'foo' +bar = "bar" +baz = "baz" +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"s"} + + tc << {:cmd=>'p []', :exp=>'$1 = []'} + tc << {:cmd=>'p [ 5, 12, 8, 10, ]', :exp=>'$2 = [5, 12, 8, 10]'} + tc << {:cmd=>'p [1,2.5,"#{foo+bar}"]', :exp=>'$3 = [1, 2.5, "foobar"]'} + tc << {:cmd=>'p %w[3.14 A\ &\ B #{foo}]', :exp=>'$4 = ["3.14", "A & B", "#{foo}"]'} + tc << {:cmd=>'p %W[3.14 A\ &\ B #{foo}]', :exp=>'$5 = ["3.14", "A & B", "foo"]'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Literal:Hash') do + # ruby source + src = <<"SRC" +foo = 'foo' +bar = "bar" +baz = "baz" +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"s"} + + tc << {:cmd=>'p {}', :exp=>'$1 = {}'} + tc << {:cmd=>'p {"one"=>1,"two"=>2}', :exp=>'$2 = {"one"=>1, "two"=>2}'} + tc << {:cmd=>'p {:eins=>"1", :zwei=>"2", }', :exp=>'$3 = {:eins=>"1", :zwei=>"2"}'} + tc << {:cmd=>'p {uno:"one", dos: 2}', :exp=>'$4 = {:uno=>"one", :dos=>2}'} + tc << {:cmd=>'p {"one"=>1, :zwei=>2, tres:3}', :exp=>'$5 = {"one"=>1, :zwei=>2, :tres=>3}'} + tc << {:cmd=>'p {:foo=>"#{foo}",:bar=>"#{bar}"}', :exp=>'$6 = {:foo=>"foo", :bar=>"bar"}'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Literal:Range') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>'p 1..10', :exp=>'$1 = 1..10'} + tc << {:cmd=>'p 1...10', :exp=>'$2 = 1...10'} + tc << {:cmd=>'p 100..10', :exp=>'$3 = 100..10'} + tc << {:cmd=>'p 1 ... 10', :exp=>'$4 = 1...10'} + + tc << {:cmd=>'p "1" .. "9"', :exp=>'$5 = "1".."9"'} + tc << {:cmd=>'p "A" ... "Z"', :exp=>'$6 = "A"..."Z"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Literal:Symbol') do + # ruby source + src = <<"SRC" +foo = 'foo' +bar = "bar" +baz = "baz" +SRC + + # test case + tc = [] + tc << {:cmd=>"s"} + tc << {:cmd=>"s"} + + tc << {:cmd=>'p :sym', :exp=>'$1 = :sym'} + tc << {:cmd=>'p :"sd"', :exp=>'$2 = :sd'} + tc << {:cmd=>"p :'ss'", :exp=>'$3 = :ss'} + tc << {:cmd=>'p :"123"', :exp=>'$4 = :"123"'} + tc << {:cmd=>'p :"#{foo} baz"', :exp=>'$5 = :"foo baz"'} + tc << {:cmd=>'p %s!symsym!', :exp=>'$6 = :symsym'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Unary operation') do + # ruby source + src = "foo = 'foo'\n" + + # test case + tc = [] + tc << {:cmd=>'p +10', :exp=>'$1 = 10'} + tc << {:cmd=>'p -100', :exp=>'$2 = -100'} + tc << {:cmd=>'p !true', :exp=>'$3 = false'} + tc << {:cmd=>'p !false', :exp=>'$4 = true'} + tc << {:cmd=>'p !nil', :exp=>'$5 = true'} + tc << {:cmd=>'p !1', :exp=>'$6 = false'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Binary operation') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, 8 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p a+1', :exp=>'$1 = 2'} + tc << {:cmd=>'p 2-b', :exp=>'$2 = -3'} + tc << {:cmd=>'p c * 3', :exp=>'$3 = 24'} + tc << {:cmd=>'p a/b', :exp=>'$4 = 0.2'} + tc << {:cmd=>'p c%b', :exp=>'$5 = 3'} + tc << {:cmd=>'p 2**10', :exp=>'$6 = 1024'} + tc << {:cmd=>'p ~3', :exp=>'$7 = -4'} + + tc << {:cmd=>'p 1<<2', :exp=>'$8 = 4'} + tc << {:cmd=>'p 64>>5', :exp=>'$9 = 2'} + + tc << {:cmd=>'p a|c', :exp=>'$10 = 9'} + tc << {:cmd=>'p a&b', :exp=>'$11 = 1'} + tc << {:cmd=>'p a^b', :exp=>'$12 = 4'} + + tc << {:cmd=>'p a>b', :exp=>'$13 = false'} + tc << {:cmd=>'p a<b', :exp=>'$14 = true'} + tc << {:cmd=>'p b>=5', :exp=>'$15 = true'} + tc << {:cmd=>'p b<=5', :exp=>'$16 = true'} + + tc << {:cmd=>'p "A"<=>"B"', :exp=>'$17 = -1'} + tc << {:cmd=>'p "A"=="B"', :exp=>'$18 = false'} + tc << {:cmd=>'p "A"==="B"', :exp=>'$19 = false'} + tc << {:cmd=>'p "A"!="B"', :exp=>'$20 = true'} + + tc << {:cmd=>'p false || true', :exp=>'$21 = true'} + tc << {:cmd=>'p false && true', :exp=>'$22 = false'} + + tc << {:cmd=>'p not nil', :exp=>'$23 = true'} + tc << {:cmd=>'p false or true', :exp=>'$24 = true'} + tc << {:cmd=>'p false and true', :exp=>'$25 = false'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Ternary operation') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, -10 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p (a < b) ? a : b', :exp=>'$1 = 1'} + tc << {:cmd=>'p (a > b) ? a : b', :exp=>'$2 = 5'} + tc << {:cmd=>'p true ? "true" : "false"', :exp=>'$3 = "true"'} + tc << {:cmd=>'p false ? "true" : "false"', :exp=>'$4 = "false"'} + tc << {:cmd=>'p nil ? "true" : "false"', :exp=>'$5 = "false"'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Substitution:simple') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, -10 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p a=2', :exp=>'$1 = 2'} + tc << {:cmd=>'p foo=[foo,bar,baz]', :exp=>'$2 = ["foo", "bar", "baz"]'} + + tc << {:cmd=>'p undefined=-1', :exp=>'$3 = -1'} + tc << {:cmd=>'p "#{undefined}"', :exp=>'$4 = NoMethodError'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Substitution:self') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, -10 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p a+=9', :exp=>'$1 = 10'} + tc << {:cmd=>'p b-=c', :exp=>'$2 = 15'} + tc << {:cmd=>'p bar*=2', :exp=>'$3 = "barbar"'} + tc << {:cmd=>'p a/=4', :exp=>'$4 = 2.5'} + tc << {:cmd=>'p c%=4', :exp=>'$5 = 2'} + + tc << {:cmd=>'p b&=0b0101', :exp=>'$6 = 5'} + tc << {:cmd=>'p c|=0x10', :exp=>'$7 = 18'} + + tc << {:cmd=>'p "#{a} #{b} #{c}"', :exp=>'$8 = "2.5 5 18"'} + tc << {:cmd=>'p "#{foo}#{bar}#{baz}"', :exp=>'$9 = "foobarbarbaz"'} + + tc << {:cmd=>'p a,b,c=[10,20,30]',:exp=>'$10 = [10, 20, 30]'} + tc << {:cmd=>'p [a,b,c]', :exp=>'$11 = [10, 20, 30]'} + tc << {:cmd=>'p a,b=b,a', :exp=>'$12 = [20, 10]'} + tc << {:cmd=>'p [a,b]', :exp=>'$13 = [20, 10]'} + + tc << {:cmd=>'p undefined=-1', :exp=>'$14 = -1'} + tc << {:cmd=>'p "#{undefined}"', :exp=>'$15 = NoMethodError'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Substitution:multiple') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, -10 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p a,b=[10,20]', :exp=>'$1 = [10, 20]'} + tc << {:cmd=>'p [a,b,c]', :exp=>'$2 = [10, 20, -10]'} + + tc << {:cmd=>'p foo,bar=["FOO","BAR","BAZ"]', :exp=>'$3 = ["FOO", "BAR", "BAZ"]'} + tc << {:cmd=>'p [foo,bar,baz]', :exp=>'$4 = ["FOO", "BAR", "baz"]'} + + tc << {:cmd=>'p a,foo=foo,a', :exp=>'$5 = ["FOO", 10]'} + tc << {:cmd=>'p [a,foo]', :exp=>'$6 = ["FOO", 10]'} + +# tc << {:cmd=>'p a,*b=[123, 456, 789]'} +# tc << {:cmd=>'p [a,b]', :exp=>'[123, [456, 789]]'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + +assert('mruby-bin-debugger(print) Substitution:self') do + # ruby source + src = <<"SRC" +CONST = 100 +a,b,c = 1, 5, -10 +foo,bar,baz = 'foo','bar','baz' +ary = [] +SRC + + # test case + tc = [] + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + tc << {:cmd=>'s'} + + tc << {:cmd=>'p a+=9', :exp=>'$1 = 10'} + tc << {:cmd=>'p b-=c', :exp=>'$2 = 15'} + tc << {:cmd=>'p bar*=2', :exp=>'$3 = "barbar"'} + tc << {:cmd=>'p a/=4', :exp=>'$4 = 2.5'} + tc << {:cmd=>'p c%=4', :exp=>'$5 = 2'} + + tc << {:cmd=>'p b&=0b0101', :exp=>'$6 = 5'} + tc << {:cmd=>'p c|=0x10', :exp=>'$7 = 18'} + + tc << {:cmd=>'p "#{a} #{b} #{c}"', :exp=>'$8 = "2.5 5 18"'} + tc << {:cmd=>'p "#{foo}#{bar}#{baz}"', :exp=>'$9 = "foobarbarbaz"'} + + tc << {:cmd=>'p a,b,c=[10,20,30]',:exp=>'$10 = [10, 20, 30]'} + tc << {:cmd=>'p [a,b,c]', :exp=>'$11 = [10, 20, 30]'} + tc << {:cmd=>'p a,b=b,a', :exp=>'$12 = [20, 10]'} + tc << {:cmd=>'p [a,b]', :exp=>'$13 = [20, 10]'} + + tc << {:cmd=>'p undefined=-1', :exp=>'$14 = -1'} + tc << {:cmd=>'p "#{undefined}"', :exp=>'$15 = NoMethodError'} + + BinTest_MrubyBinDebugger.test(src, tc) +end + diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/mrbgem.rake new file mode 100644 index 000000000..764f431af --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/mrbgem.rake @@ -0,0 +1,9 @@ +MRuby::Gem::Specification.new('mruby-bin-debugger') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby debugger command' + + spec.add_dependency('mruby-eval', :core => 'mruby-eval') + + spec.bins = %w(mrdb) +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c new file mode 100644 index 000000000..dead4b2a8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c @@ -0,0 +1,507 @@ +/* +** apibreak.c +** +*/ + +#include <string.h> +#include <mruby.h> +#include <mruby/irep.h> +#include "mrdb.h" +#include <mruby/debug.h> +#include <mruby/opcode.h> +#include <mruby/class.h> +#include <mruby/proc.h> +#include <mruby/variable.h> +#include "mrdberror.h" +#include "apibreak.h" + +#define MAX_BREAKPOINTNO (MAX_BREAKPOINT * 1024) +#define MRB_DEBUG_BP_FILE_OK (0x0001) +#define MRB_DEBUG_BP_LINENO_OK (0x0002) + +static uint16_t +check_lineno(mrb_irep_debug_info_file *info_file, uint16_t lineno) +{ + uint32_t count = info_file->line_entry_count; + uint16_t l_idx; + + if (info_file->line_type == mrb_debug_line_ary) { + for (l_idx = 0; l_idx < count; ++l_idx) { + if (lineno == info_file->lines.ary[l_idx]) { + return lineno; + } + } + } + else { + for (l_idx = 0; l_idx < count; ++l_idx) { + if (lineno == info_file->lines.flat_map[l_idx].line) { + return lineno; + } + } + } + + return 0; +} + +static int32_t +get_break_index(mrb_debug_context *dbg, uint32_t bpno) +{ + uint32_t i; + int32_t index; + char hit = FALSE; + + for(i = 0 ; i < dbg->bpnum; i++) { + if (dbg->bp[i].bpno == bpno) { + hit = TRUE; + index = i; + break; + } + } + + if (hit == FALSE) { + return MRB_DEBUG_BREAK_INVALID_NO; + } + + return index; +} + +static void +free_breakpoint(mrb_state *mrb, mrb_debug_breakpoint *bp) +{ + switch(bp->type) { + case MRB_DEBUG_BPTYPE_LINE: + mrb_free(mrb, (void*)bp->point.linepoint.file); + break; + case MRB_DEBUG_BPTYPE_METHOD: + mrb_free(mrb, (void*)bp->point.methodpoint.method_name); + if (bp->point.methodpoint.class_name != NULL) { + mrb_free(mrb, (void*)bp->point.methodpoint.class_name); + } + break; + default: + break; + } +} + +static uint16_t +check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno) +{ + mrb_irep_debug_info_file *info_file; + uint16_t result = 0; + uint16_t f_idx; + uint16_t fix_lineno; + uint16_t i; + + for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { + info_file = irep->debug_info->files[f_idx]; + if (!strcmp(info_file->filename, file)) { + result = MRB_DEBUG_BP_FILE_OK; + + fix_lineno = check_lineno(info_file, lineno); + if (fix_lineno != 0) { + return result | MRB_DEBUG_BP_LINENO_OK; + } + } + for (i=0; i < irep->rlen; ++i) { + result |= check_file_lineno(irep->reps[i], file, lineno); + if (result == (MRB_DEBUG_BP_FILE_OK | MRB_DEBUG_BP_LINENO_OK)) { + return result; + } + } + } + return result; +} + +static int32_t +compare_break_method(mrb_state *mrb, mrb_debug_breakpoint *bp, struct RClass *class_obj, mrb_sym method_sym, mrb_bool* isCfunc) +{ + const char* class_name; + const char* method_name; + struct RProc* m; + struct RClass* sc; + const char* sn; + mrb_sym ssym; + mrb_debug_methodpoint *method_p; + mrb_bool is_defined; + + method_name = mrb_sym2name(mrb, method_sym); + + method_p = &bp->point.methodpoint; + if (strcmp(method_p->method_name, method_name) == 0) { + class_name = mrb_class_name(mrb, class_obj); + if (class_name == NULL) { + if (method_p->class_name == NULL) { + return bp->bpno; + } + } + else if (method_p->class_name != NULL) { + m = mrb_method_search_vm(mrb, &class_obj, method_sym); + if (m == NULL) { + return MRB_DEBUG_OK; + } + if (MRB_PROC_CFUNC_P(m)) { + *isCfunc = TRUE; + } + + is_defined = mrb_class_defined(mrb, method_p->class_name); + if (is_defined == FALSE) { + return MRB_DEBUG_OK; + } + + sc = mrb_class_get(mrb, method_p->class_name); + ssym = mrb_symbol(mrb_check_intern_cstr(mrb, method_p->method_name)); + m = mrb_method_search_vm(mrb, &sc, ssym); + if (m == NULL) { + return MRB_DEBUG_OK; + } + + class_name = mrb_class_name(mrb, class_obj); + sn = mrb_class_name(mrb, sc); + if (strcmp(sn, class_name) == 0) { + return bp->bpno; + } + } + } + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_set_break_line(mrb_state *mrb, mrb_debug_context *dbg, const char *file, uint16_t lineno) +{ + int32_t index; + char* set_file; + uint16_t result; + + if ((mrb == NULL)||(dbg == NULL)||(file == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if (dbg->bpnum >= MAX_BREAKPOINT) { + return MRB_DEBUG_BREAK_NUM_OVER; + } + + if (dbg->next_bpno > MAX_BREAKPOINTNO) { + return MRB_DEBUG_BREAK_NO_OVER; + } + + /* file and lineno check (line type mrb_debug_line_ary only.) */ + result = check_file_lineno(dbg->root_irep, file, lineno); + if (result == 0) { + return MRB_DEBUG_BREAK_INVALID_FILE; + } + else if (result == MRB_DEBUG_BP_FILE_OK) { + return MRB_DEBUG_BREAK_INVALID_LINENO; + } + + set_file = mrb_malloc(mrb, strlen(file) + 1); + + index = dbg->bpnum; + dbg->bp[index].bpno = dbg->next_bpno; + dbg->next_bpno++; + dbg->bp[index].enable = TRUE; + dbg->bp[index].type = MRB_DEBUG_BPTYPE_LINE; + dbg->bp[index].point.linepoint.lineno = lineno; + dbg->bpnum++; + + strncpy(set_file, file, strlen(file) + 1); + + dbg->bp[index].point.linepoint.file = set_file; + + return dbg->bp[index].bpno; +} + +int32_t +mrb_debug_set_break_method(mrb_state *mrb, mrb_debug_context *dbg, const char *class_name, const char *method_name) +{ + int32_t index; + char* set_class; + char* set_method; + + if ((mrb == NULL) || (dbg == NULL) || (method_name == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if (dbg->bpnum >= MAX_BREAKPOINT) { + return MRB_DEBUG_BREAK_NUM_OVER; + } + + if (dbg->next_bpno > MAX_BREAKPOINTNO) { + return MRB_DEBUG_BREAK_NO_OVER; + } + + if (class_name != NULL) { + set_class = mrb_malloc(mrb, strlen(class_name) + 1); + strncpy(set_class, class_name, strlen(class_name) + 1); + } + else { + set_class = NULL; + } + + set_method = mrb_malloc(mrb, strlen(method_name) + 1); + + strncpy(set_method, method_name, strlen(method_name) + 1); + + index = dbg->bpnum; + dbg->bp[index].bpno = dbg->next_bpno; + dbg->next_bpno++; + dbg->bp[index].enable = TRUE; + dbg->bp[index].type = MRB_DEBUG_BPTYPE_METHOD; + dbg->bp[index].point.methodpoint.method_name = set_method; + dbg->bp[index].point.methodpoint.class_name = set_class; + dbg->bpnum++; + + return dbg->bp[index].bpno; +} + +int32_t +mrb_debug_get_breaknum(mrb_state *mrb, mrb_debug_context *dbg) +{ + if ((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + return dbg->bpnum; +} + +int32_t +mrb_debug_get_break_all(mrb_state *mrb, mrb_debug_context *dbg, uint32_t size, mrb_debug_breakpoint *bp) +{ + uint32_t get_size = 0; + + if ((mrb == NULL) || (dbg == NULL) || (bp == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if (dbg->bpnum >= size) { + get_size = size; + } + else { + get_size = dbg->bpnum; + } + + memcpy(bp, dbg->bp, sizeof(mrb_debug_breakpoint) * get_size); + + return get_size; +} + +int32_t +mrb_debug_get_break(mrb_state *mrb, mrb_debug_context *dbg, uint32_t bpno, mrb_debug_breakpoint *bp) +{ + int32_t index; + + if ((mrb == NULL) || (dbg == NULL) || (bp == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + index = get_break_index(dbg, bpno); + if (index == MRB_DEBUG_BREAK_INVALID_NO) { + return MRB_DEBUG_BREAK_INVALID_NO; + } + + bp->bpno = dbg->bp[index].bpno; + bp->enable = dbg->bp[index].enable; + bp->point = dbg->bp[index].point; + bp->type = dbg->bp[index].type; + + return 0; +} + +int32_t +mrb_debug_delete_break(mrb_state *mrb, mrb_debug_context *dbg, uint32_t bpno) +{ + uint32_t i; + int32_t index; + + if ((mrb == NULL) ||(dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + index = get_break_index(dbg, bpno); + if (index == MRB_DEBUG_BREAK_INVALID_NO) { + return MRB_DEBUG_BREAK_INVALID_NO; + } + + free_breakpoint(mrb, &dbg->bp[index]); + + for(i = index ; i < dbg->bpnum; i++) { + if ((i + 1) == dbg->bpnum) { + memset(&dbg->bp[i], 0, sizeof(mrb_debug_breakpoint)); + } + else { + memcpy(&dbg->bp[i], &dbg->bp[i + 1], sizeof(mrb_debug_breakpoint)); + } + } + + dbg->bpnum--; + + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_delete_break_all(mrb_state *mrb, mrb_debug_context *dbg) +{ + uint32_t i; + + if ((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + for(i = 0 ; i < dbg->bpnum ; i++) { + free_breakpoint(mrb, &dbg->bp[i]); + } + + dbg->bpnum = 0; + + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_enable_break(mrb_state *mrb, mrb_debug_context *dbg, uint32_t bpno) +{ + int32_t index = 0; + + if ((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + index = get_break_index(dbg, bpno); + if (index == MRB_DEBUG_BREAK_INVALID_NO) { + return MRB_DEBUG_BREAK_INVALID_NO; + } + + dbg->bp[index].enable = TRUE; + + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_enable_break_all(mrb_state *mrb, mrb_debug_context *dbg) +{ + uint32_t i; + + if ((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + for(i = 0 ; i < dbg->bpnum; i++) { + dbg->bp[i].enable = TRUE; + } + + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_disable_break(mrb_state *mrb, mrb_debug_context *dbg, uint32_t bpno) +{ + int32_t index = 0; + + if ((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + index = get_break_index(dbg, bpno); + if (index == MRB_DEBUG_BREAK_INVALID_NO) { + return MRB_DEBUG_BREAK_INVALID_NO; + } + + dbg->bp[index].enable = FALSE; + + return MRB_DEBUG_OK; +} + +int32_t +mrb_debug_disable_break_all(mrb_state *mrb, mrb_debug_context *dbg) +{ + uint32_t i; + + if ((mrb == NULL) || (dbg == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + for(i = 0 ; i < dbg->bpnum; i++) { + dbg->bp[i].enable = FALSE; + } + + return MRB_DEBUG_OK; +} + +static mrb_bool +check_start_pc_for_line(mrb_irep *irep, mrb_code *pc, uint16_t line) +{ + if (pc > irep->iseq) { + if (line == mrb_debug_get_line(irep, pc - irep->iseq - 1)) { + return FALSE; + } + } + return TRUE; +} + +int32_t +mrb_debug_check_breakpoint_line(mrb_state *mrb, mrb_debug_context *dbg, const char *file, uint16_t line) +{ + mrb_debug_breakpoint *bp; + mrb_debug_linepoint *line_p; + uint32_t i; + + if ((mrb == NULL) || (dbg == NULL) || (file == NULL) || (line <= 0)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if (!check_start_pc_for_line(dbg->irep, dbg->pc, line)) { + return MRB_DEBUG_OK; + } + + bp = dbg->bp; + for(i=0; i<dbg->bpnum; i++) { + switch (bp->type) { + case MRB_DEBUG_BPTYPE_LINE: + if (bp->enable == TRUE) { + line_p = &bp->point.linepoint; + if ((strcmp(line_p->file, file) == 0) && (line_p->lineno == line)) { + return bp->bpno; + } + } + break; + case MRB_DEBUG_BPTYPE_METHOD: + break; + case MRB_DEBUG_BPTYPE_NONE: + default: + return MRB_DEBUG_OK; + } + bp++; + } + return MRB_DEBUG_OK; +} + + +int32_t +mrb_debug_check_breakpoint_method(mrb_state *mrb, mrb_debug_context *dbg, struct RClass *class_obj, mrb_sym method_sym, mrb_bool* isCfunc) +{ + mrb_debug_breakpoint *bp; + int32_t bpno; + uint32_t i; + + if ((mrb == NULL) || (dbg == NULL) || (class_obj == NULL)) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + bp = dbg->bp; + for(i=0; i<dbg->bpnum; i++) { + if (bp->type == MRB_DEBUG_BPTYPE_METHOD) { + if (bp->enable == TRUE) { + bpno = compare_break_method(mrb, bp, class_obj, method_sym, isCfunc); + if (bpno > 0) { + return bpno; + } + } + } + else if (bp->type == MRB_DEBUG_BPTYPE_NONE) { + break; + } + bp++; + } + + return 0; +} + + diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.h b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.h new file mode 100644 index 000000000..08f1d8080 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.h @@ -0,0 +1,26 @@ +/* +** apibreak.h +** +*/ + +#ifndef APIBREAK_H_ +#define APIBREAK_H_ + +#include <mruby.h> +#include "mrdb.h" + +int32_t mrb_debug_set_break_line(mrb_state *, mrb_debug_context *, const char *, uint16_t); +int32_t mrb_debug_set_break_method(mrb_state *, mrb_debug_context *, const char *, const char *); +int32_t mrb_debug_get_breaknum(mrb_state *, mrb_debug_context *); +int32_t mrb_debug_get_break_all(mrb_state *, mrb_debug_context *, uint32_t, mrb_debug_breakpoint bp[]); +int32_t mrb_debug_get_break(mrb_state *, mrb_debug_context *, uint32_t, mrb_debug_breakpoint *); +int32_t mrb_debug_delete_break(mrb_state *, mrb_debug_context *, uint32_t); +int32_t mrb_debug_delete_break_all(mrb_state *, mrb_debug_context *); +int32_t mrb_debug_enable_break(mrb_state *, mrb_debug_context *, uint32_t); +int32_t mrb_debug_enable_break_all(mrb_state *, mrb_debug_context *); +int32_t mrb_debug_disable_break(mrb_state *, mrb_debug_context *, uint32_t); +int32_t mrb_debug_disable_break_all(mrb_state *, mrb_debug_context *); +int32_t mrb_debug_check_breakpoint_line(mrb_state *, mrb_debug_context *, const char *, uint16_t); +int32_t mrb_debug_check_breakpoint_method(mrb_state *, mrb_debug_context *, struct RClass *, mrb_sym, mrb_bool*); + +#endif /* APIBREAK_H_ */ diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c new file mode 100644 index 000000000..8aaa30bcd --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c @@ -0,0 +1,239 @@ +/* + * apilist.c + */ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "mrdb.h" +#include "mrdberror.h" +#include "apilist.h" +#include <mruby/compile.h> +#include <mruby/irep.h> +#include <mruby/debug.h> + +#define LINE_BUF_SIZE MAX_COMMAND_LINE + +typedef struct source_file { + char *path; + uint16_t lineno; + FILE *fp; +} source_file; + +static void +source_file_free(mrb_state *mrb, source_file *file) +{ + if (file != NULL) { + if (file->path != NULL) { + mrb_free(mrb, file->path); + } + if (file->fp != NULL) { + fclose(file->fp); + file->fp = NULL; + } + mrb_free(mrb, file); + } +} + +static char* +build_path(mrb_state *mrb, const char *dir, const char *base) +{ + int len; + char *path = NULL; + + len = strlen(base) + 1; + + if (strcmp(dir, ".")) { + len += strlen(dir) + sizeof("/") - 1; + } + + path = mrb_malloc(mrb, len); + memset(path, 0, len); + + if (strcmp(dir, ".")) { + strcat(path, dir); + strcat(path, "/"); + } + strcat(path, base); + + return path; +} + +static char* +dirname(mrb_state *mrb, const char *path) +{ + size_t len; + char *p, *dir; + + if (path == NULL) { + return NULL; + } + + p = strrchr(path, '/'); + len = p != NULL ? (size_t)(p - path) : strlen(path); + + dir = mrb_malloc(mrb, len + 1); + strncpy(dir, path, len); + dir[len] = '\0'; + + return dir; +} + +static source_file* +source_file_new(mrb_state *mrb, mrb_debug_context *dbg, char *filename) +{ + source_file *file = NULL; + + file = mrb_malloc(mrb, sizeof(source_file)); + + memset(file, '\0', sizeof(source_file)); + file->fp = fopen(filename, "rb"); + + if (file->fp == NULL) { + source_file_free(mrb, file); + return NULL; + } + + file->lineno = 1; + file->path = mrb_malloc(mrb, strlen(filename) + 1); + strcpy(file->path, filename); + return file; +} + +static mrb_bool +remove_newlines(char *s, FILE *fp) +{ + int c; + char *p; + size_t len; + + if ((len = strlen(s)) == 0) { + return FALSE; + } + + p = s + len - 1; + + if (*p != '\r' && *p != '\n') { + return FALSE; + } + + if (*p == '\r') { + /* peek the next character and skip '\n' */ + if ((c = fgetc(fp)) != '\n') { + ungetc(c, fp); + } + } + + /* remove trailing newline characters */ + while (s <= p && (*p == '\r' || *p == '\n')) { + *p-- = '\0'; + } + + return TRUE; +} + +static void +show_lines(source_file *file, uint16_t line_min, uint16_t line_max) +{ + char buf[LINE_BUF_SIZE]; + int show_lineno = 1, found_newline = 0, is_printed = 0; + + if (file->fp == NULL) { + return; + } + + while (fgets(buf, sizeof(buf), file->fp) != NULL) { + found_newline = remove_newlines(buf, file->fp); + + if (line_min <= file->lineno) { + if (show_lineno) { + printf("%-8d", file->lineno); + } + show_lineno = found_newline; + printf(found_newline ? "%s\n" : "%s", buf); + is_printed = 1; + } + + if (found_newline) { + if (line_max < ++file->lineno) { + break; + } + } + } + + if (is_printed && !found_newline) { + printf("\n"); + } +} + +char* +mrb_debug_get_source(mrb_state *mrb, mrdb_state *mrdb, const char *srcpath, const char *filename) +{ + int i; + FILE *fp; + const char *search_path[3]; + char *path = NULL; + const char *srcname = strrchr(filename, '/'); + + if (srcname) srcname++; + else srcname = filename; + + search_path[0] = srcpath; + search_path[1] = dirname(mrb, mrb_debug_get_filename(mrdb->dbg->irep, 0)); + search_path[2] = "."; + + for (i = 0; i < 3; i++) { + if (search_path[i] == NULL) { + continue; + } + + if ((path = build_path(mrb, search_path[i], srcname)) == NULL) { + continue; + } + + if ((fp = fopen(path, "rb")) == NULL) { + mrb_free(mrb, path); + path = NULL; + continue; + } + fclose(fp); + break; + } + + mrb_free(mrb, (void *)search_path[1]); + + return path; +} + +int32_t +mrb_debug_list(mrb_state *mrb, mrb_debug_context *dbg, char *filename, uint16_t line_min, uint16_t line_max) +{ + char *ext; + source_file *file; + + if (mrb == NULL || dbg == NULL || filename == NULL) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + ext = strrchr(filename, '.'); + + if (ext == NULL || strcmp(ext, ".rb")) { + printf("List command only supports .rb file.\n"); + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if (line_min > line_max) { + return MRB_DEBUG_INVALID_ARGUMENT; + } + + if ((file = source_file_new(mrb, dbg, filename)) != NULL) { + show_lines(file, line_min, line_max); + source_file_free(mrb, file); + return MRB_DEBUG_OK; + } + else { + printf("Invalid source file named %s.\n", filename); + return MRB_DEBUG_INVALID_ARGUMENT; + } +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.h b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.h new file mode 100644 index 000000000..6c4107885 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.h @@ -0,0 +1,14 @@ +/* + * apilist.h + */ + +#ifndef APILIST_H_ +#define APILIST_H_ + +#include <mruby.h> +#include "mrdb.h" + +int32_t mrb_debug_list(mrb_state *, mrb_debug_context *, char *, uint16_t, uint16_t); +char* mrb_debug_get_source(mrb_state *, mrdb_state *, const char *, const char *); + +#endif /* APILIST_H_ */ diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c new file mode 100644 index 000000000..a9c895b55 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c @@ -0,0 +1,78 @@ +/* +** apiprint.c +** +*/ + +#include <string.h> +#include "mrdb.h" +#include <mruby/value.h> +#include <mruby/class.h> +#include <mruby/compile.h> +#include <mruby/error.h> +#include <mruby/numeric.h> +#include <mruby/string.h> +#include "apiprint.h" + +static void +mrdb_check_syntax(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t len) +{ + mrbc_context *c; + + c = mrbc_context_new(mrb); + c->no_exec = TRUE; + c->capture_errors = TRUE; + c->filename = (char*)dbg->prvfile; + c->lineno = dbg->prvline; + + /* Load program */ + mrb_load_nstring_cxt(mrb, expr, len, c); + + mrbc_context_free(mrb, c); +} + +mrb_value +mrb_debug_eval(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t len, mrb_bool *exc) +{ + void (*tmp)(struct mrb_state *, struct mrb_irep *, mrb_code *, mrb_value *); + mrb_value ruby_code; + mrb_value s; + mrb_value v; + mrb_value recv; + + /* disable code_fetch_hook */ + tmp = mrb->code_fetch_hook; + mrb->code_fetch_hook = NULL; + + mrdb_check_syntax(mrb, dbg, expr, len); + if (mrb->exc) { + v = mrb_obj_value(mrb->exc); + mrb->exc = 0; + } + else { + /* + * begin + * expr + * rescue => e + * e + * end + */ + ruby_code = mrb_str_new_lit(mrb, "begin\n"); + ruby_code = mrb_str_cat(mrb, ruby_code, expr, len); + ruby_code = mrb_str_cat_lit(mrb, ruby_code, "\nrescue => e\ne\nend"); + + recv = dbg->regs[0]; + + v = mrb_funcall(mrb, recv, "instance_eval", 1, ruby_code); + } + + if (exc) { + *exc = mrb_obj_is_kind_of(mrb, v, mrb->eException_class); + } + + s = mrb_funcall(mrb, v, "inspect", 0); + + /* enable code_fetch_hook */ + mrb->code_fetch_hook = tmp; + + return s; +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h new file mode 100644 index 000000000..e256f6262 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h @@ -0,0 +1,13 @@ +/* + * apiprint.h + */ + +#ifndef APIPRINT_H_ +#define APIPRINT_H_ + +#include <mruby.h> +#include "mrdb.h" + +mrb_value mrb_debug_eval(mrb_state*, mrb_debug_context*, const char*, size_t, mrb_bool*); + +#endif /* APIPRINT_H_ */ diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c new file mode 100644 index 000000000..8e5901754 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c @@ -0,0 +1,436 @@ +/* +** cmdbreak.c +** +*/ + +#include <ctype.h> +#include <string.h> +#include <mruby.h> +#include <mruby/dump.h> +#include <mruby/debug.h> +#include <mruby/string.h> +#include "mrdb.h" +#include "mrdberror.h" +#include "apibreak.h" + +#define BREAK_SET_MSG_LINE "Breakpoint %d: file %s, line %d.\n" +#define BREAK_SET_MSG_METHOD "Breakpoint %d: method %s.\n" +#define BREAK_SET_MSG_CLASS_METHOD "Breakpoint %d: class %s, method %s.\n" +#define BREAK_INFO_MSG_HEADER "Num Type Enb What" +#define BREAK_INFO_MSG_LINEBREAK "%-8ubreakpoint %s at %s:%u\n" +#define BREAK_INFO_MSG_METHODBREAK "%-8ubreakpoint %s in %s:%s\n" +#define BREAK_INFO_MSG_METHODBREAK_NOCLASS "%-8ubreakpoint %s in %s\n" +#define BREAK_INFO_MSG_ENABLE "y" +#define BREAK_INFO_MSG_DISABLE "n" + +#define BREAK_ERR_MSG_INVALIDARG "Internal error." +#define BREAK_ERR_MSG_BLANK "Try \'help break\' for more information." +#define BREAK_ERR_MSG_RANGEOVER "The line number range is from 1 to 65535." +#define BREAK_ERR_MSG_NUMOVER "Exceeded the setable number of breakpoint." +#define BREAK_ERR_MSG_NOOVER "Breakno is over the available number.Please 'quit' and restart mrdb." +#define BREAK_ERR_MSG_INVALIDSTR "String \'%s\' is invalid.\n" +#define BREAK_ERR_MSG_INVALIDLINENO "Line %d in file \"%s\" is unavailable.\n" +#define BREAK_ERR_MSG_INVALIDCLASS "Class name \'%s\' is invalid.\n" +#define BREAK_ERR_MSG_INVALIDMETHOD "Method name \'%s\' is invalid.\n" +#define BREAK_ERR_MSG_INVALIDFILE "Source file named \"%s\" is unavailable.\n" +#define BREAK_ERR_MSG_INVALIDBPNO "warning: bad breakpoint number at or near '%s'\n" +#define BREAK_ERR_MSG_INVALIDBPNO_INFO "Args must be numbers variables." +#define BREAK_ERR_MSG_NOBPNO "No breakpoint number %d.\n" +#define BREAK_ERR_MSG_NOBPNO_INFO "No breakpoint matching '%d'\n" +#define BREAK_ERR_MSG_NOBPNO_INFOALL "No breakpoints." + +#define LINENO_MAX_DIGIT 6 +#define BPNO_LETTER_NUM 9 + +typedef int32_t (*all_command_func)(mrb_state *, mrb_debug_context *); +typedef int32_t (*select_command_func)(mrb_state *, mrb_debug_context *, uint32_t); + +static void +print_api_common_error(int32_t error) +{ + switch(error) { + case MRB_DEBUG_INVALID_ARGUMENT: + puts(BREAK_ERR_MSG_INVALIDARG); + break; + default: + break; + } +} + +#undef STRTOUL +#define STRTOUL(ul,s) { \ + int i; \ + ul = 0; \ + for(i=0; ISDIGIT(s[i]); i++) ul = 10*ul + (s[i] -'0'); \ +} + +static int32_t +parse_breakpoint_no(char* args) +{ + char* ps = args; + uint32_t l; + + if ((*ps == '0')||(strlen(ps) >= BPNO_LETTER_NUM)) { + return 0; + } + + while (!(ISBLANK(*ps)||ISCNTRL(*ps))) { + if (!ISDIGIT(*ps)) { + return 0; + } + ps++; + } + + STRTOUL(l, args); + return l; +} + +static mrb_bool +exe_set_command_all(mrb_state *mrb, mrdb_state *mrdb, all_command_func func) +{ + int32_t ret = MRB_DEBUG_OK; + + if (mrdb->wcnt == 1) { + ret = func(mrb, mrdb->dbg); + print_api_common_error(ret); + return TRUE; + } + return FALSE; +} + +static void +exe_set_command_select(mrb_state *mrb, mrdb_state *mrdb, select_command_func func) +{ + char* ps; + int32_t ret = MRB_DEBUG_OK; + int32_t bpno = 0; + int32_t i; + + for(i=1; i<mrdb->wcnt; i++) { + ps = mrdb->words[i]; + bpno = parse_breakpoint_no(ps); + if (bpno == 0) { + printf(BREAK_ERR_MSG_INVALIDBPNO, ps); + break; + } + ret = func(mrb, mrdb->dbg, (uint32_t)bpno); + if (ret == MRB_DEBUG_BREAK_INVALID_NO) { + printf(BREAK_ERR_MSG_NOBPNO, bpno); + } + else if (ret != MRB_DEBUG_OK) { + print_api_common_error(ret); + } + } +} + +mrb_debug_bptype +check_bptype(char* args) +{ + char* ps = args; + + if (ISBLANK(*ps)||ISCNTRL(*ps)) { + puts(BREAK_ERR_MSG_BLANK); + return MRB_DEBUG_BPTYPE_NONE; + } + + if (!ISDIGIT(*ps)) { + return MRB_DEBUG_BPTYPE_METHOD; + } + + while (!(ISBLANK(*ps)||ISCNTRL(*ps))) { + if (!ISDIGIT(*ps)) { + printf(BREAK_ERR_MSG_INVALIDSTR, args); + return MRB_DEBUG_BPTYPE_NONE; + } + ps++; + } + + if ((*args == '0')||(strlen(args) >= LINENO_MAX_DIGIT)) { + puts(BREAK_ERR_MSG_RANGEOVER); + return MRB_DEBUG_BPTYPE_NONE; + } + + return MRB_DEBUG_BPTYPE_LINE; +} + +static void +print_breakpoint(mrb_debug_breakpoint *bp) +{ + const char* enable_letter[] = {BREAK_INFO_MSG_DISABLE, BREAK_INFO_MSG_ENABLE}; + + if (bp->type == MRB_DEBUG_BPTYPE_LINE) { + printf(BREAK_INFO_MSG_LINEBREAK, + bp->bpno, enable_letter[bp->enable], bp->point.linepoint.file, bp->point.linepoint.lineno); + } + else { + if (bp->point.methodpoint.class_name == NULL) { + printf(BREAK_INFO_MSG_METHODBREAK_NOCLASS, + bp->bpno, enable_letter[bp->enable], bp->point.methodpoint.method_name); + } + else { + printf(BREAK_INFO_MSG_METHODBREAK, + bp->bpno, enable_letter[bp->enable], bp->point.methodpoint.class_name, bp->point.methodpoint.method_name); + } + } +} + +static void +info_break_all(mrb_state *mrb, mrdb_state *mrdb) +{ + int32_t bpnum = 0; + int32_t i = 0; + int32_t ret = MRB_DEBUG_OK; + mrb_debug_breakpoint *bp_list; + + bpnum = mrb_debug_get_breaknum(mrb, mrdb->dbg); + if (bpnum < 0) { + print_api_common_error(bpnum); + return; + } + else if (bpnum == 0) { + puts(BREAK_ERR_MSG_NOBPNO_INFOALL); + return; + } + bp_list = (mrb_debug_breakpoint*)mrb_malloc(mrb, bpnum * sizeof(mrb_debug_breakpoint)); + + ret = mrb_debug_get_break_all(mrb, mrdb->dbg, (uint32_t)bpnum, bp_list); + if (ret < 0) { + print_api_common_error(ret); + return; + } + puts(BREAK_INFO_MSG_HEADER); + for(i = 0 ; i < bpnum ; i++) { + print_breakpoint(&bp_list[i]); + } + + mrb_free(mrb, bp_list); +} + +static void +info_break_select(mrb_state *mrb, mrdb_state *mrdb) +{ + int32_t ret = MRB_DEBUG_OK; + int32_t bpno = 0; + char* ps = mrdb->command; + mrb_debug_breakpoint bp; + mrb_bool isFirst = TRUE; + int32_t i; + + for(i=2; i<mrdb->wcnt; i++) { + ps = mrdb->words[i]; + bpno = parse_breakpoint_no(ps); + if (bpno == 0) { + puts(BREAK_ERR_MSG_INVALIDBPNO_INFO); + break; + } + + ret = mrb_debug_get_break(mrb, mrdb->dbg, bpno, &bp); + if (ret == MRB_DEBUG_BREAK_INVALID_NO) { + printf(BREAK_ERR_MSG_NOBPNO_INFO, bpno); + break; + } + else if (ret != MRB_DEBUG_OK) { + print_api_common_error(ret); + break; + } + else if (isFirst == TRUE) { + isFirst = FALSE; + puts(BREAK_INFO_MSG_HEADER); + } + print_breakpoint(&bp); + } +} + +mrb_debug_bptype +parse_breakcommand(mrdb_state *mrdb, const char **file, uint32_t *line, char **cname, char **method) +{ + mrb_debug_context *dbg = mrdb->dbg; + char *args; + char *body; + mrb_debug_bptype type; + uint32_t l; + + if (mrdb->wcnt <= 1) { + puts(BREAK_ERR_MSG_BLANK); + return MRB_DEBUG_BPTYPE_NONE; + } + + args = mrdb->words[1]; + if ((body = strrchr(args, ':')) == NULL) { + body = args; + type = check_bptype(body); + } + else { + if (body == args) { + printf(BREAK_ERR_MSG_INVALIDSTR, args); + return MRB_DEBUG_BPTYPE_NONE; + } + *body = '\0'; + type = check_bptype(++body); + } + + switch(type) { + case MRB_DEBUG_BPTYPE_LINE: + STRTOUL(l, body); + if (l <= 65535) { + *line = l; + *file = (body == args)? mrb_debug_get_filename(dbg->irep, dbg->pc - dbg->irep->iseq): args; + } + else { + puts(BREAK_ERR_MSG_RANGEOVER); + type = MRB_DEBUG_BPTYPE_NONE; + } + break; + case MRB_DEBUG_BPTYPE_METHOD: + if (body == args) { + /* method only */ + if (ISUPPER(*body)||ISLOWER(*body)||(*body == '_')) { + *method = body; + *cname = NULL; + } + else { + printf(BREAK_ERR_MSG_INVALIDMETHOD, args); + type = MRB_DEBUG_BPTYPE_NONE; + } + } + else { + if (ISUPPER(*args)) { + switch(*body) { + case '@': case '$': case '?': case '.': case ',': case ':': + case ';': case '#': case '\\': case '\'': case '\"': + printf(BREAK_ERR_MSG_INVALIDMETHOD, body); + type = MRB_DEBUG_BPTYPE_NONE; + break; + default: + *method = body; + *cname = args; + break; + } + } + else { + printf(BREAK_ERR_MSG_INVALIDCLASS, args); + type = MRB_DEBUG_BPTYPE_NONE; + } + } + break; + case MRB_DEBUG_BPTYPE_NONE: + default: + break; + } + + return type; +} + +dbgcmd_state +dbgcmd_break(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_debug_bptype type; + mrb_debug_context *dbg = mrdb->dbg; + const char *file = NULL; + uint32_t line = 0; + char *cname = NULL; + char *method = NULL; + int32_t ret; + + type = parse_breakcommand(mrdb, &file, &line, &cname, &method); + switch (type) { + case MRB_DEBUG_BPTYPE_LINE: + ret = mrb_debug_set_break_line(mrb, dbg, file, line); + break; + case MRB_DEBUG_BPTYPE_METHOD: + ret = mrb_debug_set_break_method(mrb, dbg, cname, method); + break; + case MRB_DEBUG_BPTYPE_NONE: + default: + return DBGST_PROMPT; + } + + if (ret >= 0) { + if (type == MRB_DEBUG_BPTYPE_LINE) { + printf(BREAK_SET_MSG_LINE, ret, file, line); + } + else if ((type == MRB_DEBUG_BPTYPE_METHOD)&&(cname == NULL)) { + printf(BREAK_SET_MSG_METHOD, ret, method); + } + else { + printf(BREAK_SET_MSG_CLASS_METHOD, ret, cname, method); + } + } + else { + switch (ret) { + case MRB_DEBUG_BREAK_INVALID_LINENO: + printf(BREAK_ERR_MSG_INVALIDLINENO, line, file); + break; + case MRB_DEBUG_BREAK_INVALID_FILE: + printf(BREAK_ERR_MSG_INVALIDFILE, file); + break; + case MRB_DEBUG_BREAK_NUM_OVER: + puts(BREAK_ERR_MSG_NUMOVER); + break; + case MRB_DEBUG_BREAK_NO_OVER: + puts(BREAK_ERR_MSG_NOOVER); + break; + case MRB_DEBUG_INVALID_ARGUMENT: + puts(BREAK_ERR_MSG_INVALIDARG); + break; + case MRB_DEBUG_NOBUF: + puts("T.B.D."); + break; + default: + break; + } + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_info_break(mrb_state *mrb, mrdb_state *mrdb) +{ + if (mrdb->wcnt == 2) { + info_break_all(mrb, mrdb); + } + else { + info_break_select(mrb, mrdb); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_delete(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_bool ret = FALSE; + + ret = exe_set_command_all(mrb, mrdb, mrb_debug_delete_break_all); + if (ret != TRUE) { + exe_set_command_select(mrb, mrdb, mrb_debug_delete_break); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_enable(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_bool ret = FALSE; + + ret = exe_set_command_all(mrb, mrdb, mrb_debug_enable_break_all); + if (ret != TRUE) { + exe_set_command_select(mrb, mrdb, mrb_debug_enable_break); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_disable(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_bool ret = FALSE; + + ret = exe_set_command_all(mrb, mrdb, mrb_debug_disable_break_all); + if (ret != TRUE) { + exe_set_command_select(mrb, mrdb, mrb_debug_disable_break); + } + return DBGST_PROMPT; +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c new file mode 100644 index 000000000..5984b623b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c @@ -0,0 +1,501 @@ +/* +** cmdmisc.c - mruby debugger miscellaneous command functions +** +*/ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "apilist.h" +#include <mruby/compile.h> + +typedef struct help_msg { + const char *cmd1; + const char *cmd2; + const char *short_msg; + const char *long_msg; +} help_msg; + +static help_msg help_msg_list[] = { + { + "b[reak]", NULL, "Set breakpoint", + "Usage: break [file:]line\n" + " break [class:]method\n" + "\n" + "Set breakpoint at specified line or method.\n" + "If \'[file:]line\' is specified, break at start of code for that line (in a file).\n" + "If \'[class:]method\' is specified, break at start of code for that method (of the class).\n" + }, + { + "c[ontinue]", NULL, "Continue program being debugged", + "Usage: continue [N]\n" + "\n" + "Continue program stopped by a breakpoint.\n" + "If N, which is non negative value, is passed,\n" + "proceed program until the N-th breakpoint is coming.\n" + "If N is not passed, N is assumed 1.\n" + }, + { + "d[elete]", NULL, "Delete some breakpoints", + "Usage: delete [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Delete some breakpoints.\n" + "Arguments are breakpoint numbers with spaces in between.\n" + "To delete all breakpoints, give no argument.\n" + }, + { + "dis[able]", NULL, "Disable some breakpoints", + "Usage: disable [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Disable some breakpoints.\n" + "Arguments are breakpoint numbers with spaces in between.\n" + "To disable all breakpoints, give no argument.\n" + }, + { + "en[able]", NULL, "Enable some breakpoints", + "Usage: enable [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Enable some breakpoints.\n" + "Arguments are breakpoint numbers with spaces in between.\n" + "To enable all breakpoints, give no argument.\n" + }, + { + "ev[al]", NULL, "Evaluate expression", + "Usage: eval expr\n" + "\n" + "It evaluates and prints the value of the mruby expression.\n" + "This is equivalent to the \'print\' command.\n" + }, + { + "h[elp]", NULL, "Print this help", + "Usage: help [command]\n" + "\n" + "With no arguments, help displays a short list of commands.\n" + "With a command name as help argument, help displays how to use that command.\n" + }, + { + "i[nfo]", "b[reakpoints]", "Status of breakpoints", + "Usage: info breakpoints [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Status of specified breakpoints (all user-settable breakpoints if no argument).\n" + "Arguments are breakpoint numbers with spaces in between.\n" + }, + { + "l[ist]", NULL, "List specified line", + "Usage: list\n" + " list first[,last]\n" + " list filename:first[,last]\n" + "\n" + "Print lines from a source file.\n" + "\n" + "With first and last, list prints lines from first to last.\n" + "When last is empty, it stands for ten lines away from first.\n" + "With filename, list prints lines in the specified source file.\n" + }, + { + "p[rint]", NULL, "Print value of expression", + "Usage: print expr\n" + "\n" + "It evaluates and prints the value of the mruby expression.\n" + "This is equivalent to the \'eval\' command.\n" + }, + { + "q[uit]", NULL, "Exit mrdb", + "Usage: quit\n" + "\n" + "Exit mrdb.\n" + }, + { + "r[un]", NULL, "Start debugged program", + "Usage: run\n" + "\n" + "Start debugged program.\n" + }, + { + "s[tep]", NULL, "Step program until it reaches a different source line", + "Usage: step\n" + "\n" + "Step program until it reaches a different source line.\n" + }, + { NULL, NULL, NULL, NULL } +}; + +typedef struct listcmd_parser_state { + mrb_bool parse_error; + mrb_bool has_line_min; + mrb_bool has_line_max; + char *filename; + uint16_t line_min; + uint16_t line_max; +} listcmd_parser_state; + +static listcmd_parser_state* +listcmd_parser_state_new(mrb_state *mrb) +{ + listcmd_parser_state *st = mrb_malloc(mrb, sizeof(listcmd_parser_state)); + memset(st, 0, sizeof(listcmd_parser_state)); + return st; +} + +static void +listcmd_parser_state_free(mrb_state *mrb, listcmd_parser_state *st) +{ + if (st != NULL) { + if (st->filename != NULL) { + mrb_free(mrb, st->filename); + } + mrb_free(mrb, st); + } +} + +static mrb_bool +parse_uint(char **sp, uint16_t *n) +{ + char *p; + int i; + + if (*sp == NULL || **sp == '\0') { + return FALSE; + } + + for (p = *sp; *p != '\0' && ISDIGIT(*p); p++) ; + + if (p != *sp && (i = atoi(*sp)) >= 0) { + *n = (uint16_t)i; + *sp = p; + return TRUE; + } + return FALSE; +} + +static mrb_bool +skip_char(char **sp, char c) +{ + if (*sp != NULL && **sp == c) { + ++*sp; + return TRUE; + } + return FALSE; +} + +static mrb_bool +parse_lineno(mrb_state *mrb, char **sp, listcmd_parser_state *st) +{ + if (*sp == NULL || **sp == '\0') { + return FALSE; + } + + st->has_line_min = FALSE; + st->has_line_max = FALSE; + + if (parse_uint(sp, &st->line_min)) { + st->has_line_min = TRUE; + } + else { + return FALSE; + } + + if (skip_char(sp, ',')) { + if (parse_uint(sp, &st->line_max)) { + st->has_line_max = TRUE; + } + else { + st->parse_error = TRUE; + return FALSE; + } + } + return TRUE; +} + +static mrb_bool +parse_filename(mrb_state *mrb, char **sp, listcmd_parser_state *st) +{ + char *p; + int len; + + if (st->filename != NULL) { + mrb_free(mrb, st->filename); + st->filename = NULL; + } + + if ((p = strchr(*sp, ':')) != NULL) { + len = p - *sp; + } + else { + len = strlen(*sp); + } + + if (len > 0) { + st->filename = mrb_malloc(mrb, len + 1); + strncpy(st->filename, *sp, len); + st->filename[len] = '\0'; + *sp += len; + return TRUE; + } + else { + return FALSE; + } +} + +char* +replace_ext(mrb_state *mrb, const char *filename, const char *ext) +{ + size_t len; + char *p, *s; + + if (filename == NULL) { + return NULL; + } + + if ((p = strrchr(filename, '.')) != NULL && strchr(p, '/') == NULL) { + len = p - filename; + } + else { + len = strlen(filename); + } + + s = mrb_malloc(mrb, len + strlen(ext) + 1); + memset(s, '\0', len + strlen(ext) + 1); + strncpy(s, filename, len); + strcat(s, ext); + + return s; +} + +static mrb_bool +parse_listcmd_args(mrb_state *mrb, mrdb_state *mrdb, listcmd_parser_state *st) +{ + char *p; + + switch (mrdb->wcnt) { + case 2: + p = mrdb->words[1]; + + /* mrdb->words[1] ::= <lineno> | <filename> ':' <lineno> | <filename> */ + if (!parse_lineno(mrb, &p, st)) { + if (parse_filename(mrb, &p, st)) { + if (skip_char(&p, ':')) { + if (!parse_lineno(mrb, &p, st)) { + st->parse_error = TRUE; + } + } + } + else { + st->parse_error = TRUE; + } + } + if (*p != '\0') { + st->parse_error = TRUE; + } + break; + case 1: + case 0: + /* do nothing */ + break; + default: + st->parse_error = TRUE; + printf("too many arguments\n"); + break; + } + + if (!st->parse_error) { + if (!st->has_line_min) { + st->line_min = (!st->filename && mrdb->dbg->prvline > 0) ? mrdb->dbg->prvline : 1; + } + + if (!st->has_line_max) { + st->line_max = st->line_min + 9; + } + + if (st->filename == NULL) { + if (mrdb->dbg->prvfile && strcmp(mrdb->dbg->prvfile, "-")) { + st->filename = replace_ext(mrb, mrdb->dbg->prvfile, ".rb"); + } + } + } + + if (st->parse_error || st->filename == NULL) { + return FALSE; + } + + return TRUE; +} + +static mrb_bool +check_cmd_pattern(const char *pattern, const char *cmd) +{ + char *lbracket, *rbracket, *p, *q; + + if (pattern == NULL && cmd == NULL) { + return TRUE; + } + if (pattern == NULL || cmd == NULL) { + return FALSE; + } + if ((lbracket = strchr(pattern, '[')) == NULL) { + return !strcmp(pattern, cmd); + } + if ((rbracket = strchr(pattern, ']')) == NULL) { + return FALSE; + } + if (strncmp(pattern, cmd, lbracket - pattern)) { + return FALSE; + } + + p = lbracket + 1; + q = (char *)cmd + (lbracket - pattern); + + for ( ; p < rbracket && *q != '\0'; p++, q++) { + if (*p != *q) { + break; + } + } + return *q == '\0'; +} + +static help_msg* +get_help_msg(char *cmd1, char *cmd2) +{ + help_msg *p; + + if (cmd1 == NULL) { + return NULL; + } + for (p = help_msg_list; p->cmd1 != NULL; p++) { + if (check_cmd_pattern(p->cmd1, cmd1) && check_cmd_pattern(p->cmd2, cmd2)) { + return p; + } + } + return NULL; +} + +static mrb_bool +show_short_help(void) +{ + help_msg *p; + + printf("Commands\n"); + + for (p = help_msg_list; p->cmd1 != NULL; p++) { + if (p->cmd2 == NULL) { + printf(" %s -- %s\n", p->cmd1, p->short_msg); + } + else { + printf(" %s %s -- %s\n", p->cmd1, p->cmd2, p->short_msg); + } + } + return TRUE; +} + +static mrb_bool +show_long_help(char *cmd1, char *cmd2) +{ + help_msg *help; + + if ((help = get_help_msg(cmd1, cmd2)) == NULL) { + return FALSE; + } + printf("%s", help->long_msg); + return TRUE; +} + +dbgcmd_state +dbgcmd_list(mrb_state *mrb, mrdb_state *mrdb) +{ + char *filename; + listcmd_parser_state *st = listcmd_parser_state_new(mrb); + + if (parse_listcmd_args(mrb, mrdb, st)) { + if ((filename = mrb_debug_get_source(mrb, mrdb, mrdb->srcpath, st->filename)) == NULL) { + filename = st->filename; + } + mrb_debug_list(mrb, mrdb->dbg, filename, st->line_min, st->line_max); + + if (filename != NULL && filename != st->filename) { + mrb_free(mrb, filename); + } + listcmd_parser_state_free(mrb, st); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_help(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_bool is_valid; + int i; + + switch (mrdb->wcnt) { + case 0: + case 1: + is_valid = show_short_help(); + break; + case 2: + is_valid = show_long_help(mrdb->words[1], NULL); + break; + case 3: + is_valid = show_long_help(mrdb->words[1], mrdb->words[2]); + break; + default: + is_valid = FALSE; + break; + } + + if (!is_valid) { + printf("Invalid command \""); + for (i = 1; i < mrdb->wcnt; i++) { + printf("%s%s", i == 1 ? "" : " ", mrdb->words[i]); + } + printf("\". Try \"help\".\n"); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_quit(mrb_state *mrb, mrdb_state *mrdb) +{ + switch (mrdb->dbg->xm) { + case DBG_RUN: + case DBG_STEP: + case DBG_NEXT: + while (1) { + char c; + int buf; + + printf("The program is running. Exit anyway? (y or n) "); + fflush(stdout); + + if ((buf = getchar()) == EOF) { + mrdb->dbg->xm = DBG_QUIT; + break; + } + c = buf; + while (buf != '\n' && (buf = getchar()) != EOF) ; + + if (c == 'y' || c == 'Y') { + mrdb->dbg->xm = DBG_QUIT; + break; + } + else if (c == 'n' || c == 'N') { + break; + } + else { + printf("Please answer y or n.\n"); + } + } + break; + default: + mrdb->dbg->xm = DBG_QUIT; + break; + } + + if (mrdb->dbg->xm == DBG_QUIT) { + struct RClass *exc; + exc = mrb_define_class(mrb, "DebuggerExit", mrb_class_get(mrb, "Exception")); + mrb_raise(mrb, exc, "Exit mrdb."); + } + return DBGST_PROMPT; +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c new file mode 100644 index 000000000..cca636711 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c @@ -0,0 +1,58 @@ +/* +** cmdprint.c - mruby debugger print command functions +** +*/ + +#include <string.h> +#include "mrdb.h" +#include <mruby/value.h> +#include <mruby/class.h> +#include <mruby/compile.h> +#include <mruby/error.h> +#include <mruby/numeric.h> +#include <mruby/string.h> +#include "apiprint.h" + +dbgcmd_state +dbgcmd_print(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_value expr; + mrb_value result; + mrb_value s; + uint8_t wcnt; + int ai; + + if (mrdb->wcnt <= 1) { + puts("Parameter not specified."); + return DBGST_PROMPT; + } + + ai = mrb_gc_arena_save(mrb); + + /* eval expr */ + expr = mrb_str_new_cstr(mrb, NULL); + for (wcnt=1; wcnt<mrdb->wcnt; wcnt++) { + expr = mrb_str_cat_lit(mrb, expr, " "); + expr = mrb_str_cat_cstr(mrb, expr, mrdb->words[wcnt]); + } + + result = mrb_debug_eval(mrb, mrdb->dbg, RSTRING_PTR(expr), RSTRING_LEN(expr), NULL); + + /* $print_no = result */ + s = mrb_str_cat_lit(mrb, result, "\0"); + printf("$%lu = %s\n", (unsigned long)mrdb->print_no++, RSTRING_PTR(s)); + + if (mrdb->print_no == 0) { + mrdb->print_no = 1; + } + + mrb_gc_arena_restore(mrb, ai); + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_eval(mrb_state *mrb, mrdb_state *mrdb) +{ + return dbgcmd_print(mrb, mrdb); +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c new file mode 100644 index 000000000..cb4c738fc --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c @@ -0,0 +1,64 @@ +/* +** cmdrun.c - mruby debugger run command functions +** +*/ + +#include <mruby/opcode.h> +#include "mrdb.h" + +dbgcmd_state +dbgcmd_run(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_debug_context *dbg = mrdb->dbg; + + if (dbg->xm == DBG_INIT){ + dbg->xm = DBG_RUN; + } + else { + dbg->xm = DBG_QUIT; + if (dbg->xphase == DBG_PHASE_RUNNING){ + struct RClass *exc; + puts("Start it from the beginning."); + exc = mrb_define_class(mrb, "DebuggerRestart", mrb_class_get(mrb, "Exception")); + mrb_raise(mrb, exc, "Restart mrdb."); + } + } + + return DBGST_RESTART; +} + +dbgcmd_state +dbgcmd_continue(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_debug_context *dbg = mrdb->dbg; + int ccnt = 1; + + if (mrdb->wcnt > 1){ + sscanf(mrdb->words[1], "%d", &ccnt); + } + dbg->ccnt = (uint16_t)(ccnt > 0 ? ccnt : 1); /* count of continue */ + + if (dbg->xphase == DBG_PHASE_AFTER_RUN){ + puts("The program is not running."); + dbg->xm = DBG_QUIT; + } + else { + dbg->xm = DBG_RUN; + } + return DBGST_CONTINUE; +} + +dbgcmd_state +dbgcmd_step(mrb_state *mrb, mrdb_state *mrdb) +{ + mrdb->dbg->xm = DBG_STEP; + return DBGST_CONTINUE; +} + +dbgcmd_state +dbgcmd_next(mrb_state *mrb, mrdb_state *mrdb) +{ + mrdb->dbg->xm = DBG_NEXT; + mrdb->dbg->prvci = mrb->c->ci; + return DBGST_CONTINUE; +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c new file mode 100644 index 000000000..d12dcd5da --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -0,0 +1,759 @@ +/* +** mrdb.c - mruby debugger +** +*/ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include <mruby.h> +#include <mruby/dump.h> +#include <mruby/debug.h> +#include <mruby/class.h> +#include <mruby/opcode.h> +#include <mruby/variable.h> + +#include "mrdb.h" +#include "apibreak.h" +#include "apilist.h" + +void mrdb_state_free(mrb_state *); + +static mrb_debug_context *_debug_context = NULL; +static mrdb_state *_mrdb_state = NULL; + +struct _args { + FILE *rfp; + char* fname; + char* srcpath; + int argc; + char** argv; + mrb_bool mrbfile : 1; +}; + +typedef struct debug_command { + const char *cmd1; + const char *cmd2; + uint8_t len1; + uint8_t len2; + uint8_t div; + debug_command_id id; + debug_command_func func; +} debug_command; + +static const debug_command debug_command_list[] = { + {"break", NULL, 1, 0, 0, DBGCMD_BREAK, dbgcmd_break}, /* b[reak] */ + {"continue", NULL, 1, 0, 0, DBGCMD_CONTINUE, dbgcmd_continue}, /* c[ontinue] */ + {"delete", NULL, 1, 0, 1, DBGCMD_DELETE, dbgcmd_delete}, /* d[elete] */ + {"disable", NULL, 3, 0, 1, DBGCMD_DISABLE, dbgcmd_disable}, /* dis[able] */ + {"enable", NULL, 2, 0, 1, DBGCMD_ENABLE, dbgcmd_enable}, /* en[able] */ + {"eval", NULL, 2, 0, 0, DBGCMD_EVAL, dbgcmd_eval}, /* ev[al] */ + {"help", NULL, 1, 0, 1, DBGCMD_HELP, dbgcmd_help}, /* h[elp] */ + {"info", "breakpoints", 1, 1, 1, DBGCMD_INFO_BREAK, dbgcmd_info_break}, /* i[nfo] b[reakpoints] */ + {"list", NULL, 1, 0, 1, DBGCMD_LIST, dbgcmd_list}, /* l[ist] */ + {"print", NULL, 1, 0, 0, DBGCMD_PRINT, dbgcmd_print}, /* p[rint] */ + {"quit", NULL, 1, 0, 0, DBGCMD_QUIT, dbgcmd_quit}, /* q[uit] */ + {"run", NULL, 1, 0, 0, DBGCMD_RUN, dbgcmd_run}, /* r[un] */ + {"step", NULL, 1, 0, 1, DBGCMD_STEP, dbgcmd_step}, /* s[tep] */ + {"next", NULL, 1, 0, 1, DBGCMD_NEXT, dbgcmd_next}, /* n[ext] */ + {NULL} +}; + + +static void +usage(const char *name) +{ + static const char *const usage_msg[] = { + "switches:", + "-b load and execute RiteBinary (mrb) file", + "-d specify source directory", + "--version print the version", + "--copyright print the copyright", + NULL + }; + const char *const *p = usage_msg; + + printf("Usage: %s [switches] programfile\n", name); + while (*p) { + printf(" %s\n", *p++); + } +} + +static int +parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args) +{ + char **origargv = argv; + static const struct _args args_zero = { 0 }; + + *args = args_zero; + + for (argc--,argv++; argc > 0; argc--,argv++) { + char *item; + if (argv[0][0] != '-') break; + + item = argv[0] + 1; + switch (*item++) { + case 'b': + args->mrbfile = TRUE; + break; + case 'd': + if (item[0]) { + goto append_srcpath; + } + else if (argc > 1) { + argc--; argv++; + item = argv[0]; +append_srcpath: + if (!args->srcpath) { + size_t buflen; + char *buf; + + buflen = strlen(item) + 1; + buf = (char *)mrb_malloc(mrb, buflen); + memcpy(buf, item, buflen); + args->srcpath = buf; + } + else { + size_t srcpathlen; + size_t itemlen; + + srcpathlen = strlen(args->srcpath); + itemlen = strlen(item); + args->srcpath = + (char *)mrb_realloc(mrb, args->srcpath, srcpathlen + itemlen + 2); + args->srcpath[srcpathlen] = '\n'; + memcpy(args->srcpath + srcpathlen + 1, item, itemlen + 1); + } + } + else { + printf("%s: No path specified for -d\n", *origargv); + return EXIT_SUCCESS; + } + break; + case '-': + if (strcmp((*argv) + 2, "version") == 0) { + mrb_show_version(mrb); + exit(EXIT_SUCCESS); + } + else if (strcmp((*argv) + 2, "copyright") == 0) { + mrb_show_copyright(mrb); + exit(EXIT_SUCCESS); + } + default: + return EXIT_FAILURE; + } + } + + if (args->rfp == NULL) { + if (*argv == NULL) { + printf("%s: Program file not specified.\n", *origargv); + return EXIT_FAILURE; + } + else { + args->rfp = fopen(argv[0], args->mrbfile ? "rb" : "r"); + if (args->rfp == NULL) { + printf("%s: Cannot open program file. (%s)\n", *origargv, *argv); + return EXIT_FAILURE; + } + args->fname = argv[0]; + argc--; argv++; + } + } + args->argv = (char **)mrb_realloc(mrb, args->argv, sizeof(char*) * (argc + 1)); + memcpy(args->argv, argv, (argc+1) * sizeof(char*)); + args->argc = argc; + + return EXIT_SUCCESS; +} + +static void +cleanup(mrb_state *mrb, struct _args *args) +{ + if (args->rfp) + fclose(args->rfp); + if (args->srcpath) + mrb_free(mrb, args->srcpath); + if (args->argv) + mrb_free(mrb, args->argv); + mrdb_state_free(mrb); + mrb_close(mrb); +} + +static mrb_debug_context* +mrb_debug_context_new(mrb_state *mrb) +{ + mrb_debug_context *dbg = mrb_malloc(mrb, sizeof(mrb_debug_context)); + + memset(dbg, 0, sizeof(mrb_debug_context)); + + dbg->xm = DBG_INIT; + dbg->xphase = DBG_PHASE_BEFORE_RUN; + dbg->next_bpno = 1; + + return dbg; +} + +mrb_debug_context* +mrb_debug_context_get(mrb_state *mrb) +{ + if (!_debug_context) { + _debug_context = mrb_debug_context_new(mrb); + } + return _debug_context; +} + +void +mrb_debug_context_set(mrb_debug_context *dbg) +{ + _debug_context = dbg; +} + +void +mrb_debug_context_free(mrb_state *mrb) +{ + if (_debug_context) { + mrb_debug_delete_break_all(mrb, _debug_context); + mrb_free(mrb, _debug_context); + _debug_context = NULL; + } +} + +static mrdb_state* +mrdb_state_new(mrb_state *mrb) +{ + mrdb_state *mrdb = mrb_malloc(mrb, sizeof(mrdb_state)); + + memset(mrdb, 0, sizeof(mrdb_state)); + + mrdb->dbg = mrb_debug_context_get(mrb); + mrdb->command = mrb_malloc(mrb, MAX_COMMAND_LINE+1); + mrdb->print_no = 1; + + return mrdb; +} + +mrdb_state* +mrdb_state_get(mrb_state *mrb) +{ + if (!_mrdb_state) { + _mrdb_state = mrdb_state_new(mrb); + } + return _mrdb_state; +} + +void +mrdb_state_set(mrdb_state *mrdb) +{ + _mrdb_state = mrdb; +} + +void +mrdb_state_free(mrb_state *mrb) +{ + mrb_debug_context_free(mrb); + if (_mrdb_state) { + mrb_free(mrb, _mrdb_state->command); + mrb_free(mrb, _mrdb_state); + _mrdb_state = NULL; + } +} + +static char* +get_command(mrb_state *mrb, mrdb_state *mrdb) +{ + int i; + int c; + + for (i=0; i<MAX_COMMAND_LINE; i++) { + if ((c=getchar()) == EOF || c == '\n') break; + mrdb->command[i] = c; + } + + if (i == 0 && feof(stdin)) { + clearerr(stdin); + strcpy(mrdb->command, "quit"); + i += sizeof("quit") - 1; + } + + if (i == MAX_COMMAND_LINE) { + for ( ; (c=getchar()) != EOF && c !='\n'; i++) ; + } + + if (i > MAX_COMMAND_LINE) { + printf("command line too long.\n"); + i = 0; /* discard command data */ + } + mrdb->command[i] = '\0'; + + return mrdb->command; +} + +static char* +pick_out_word(mrb_state *mrb, char **pp) +{ + char *ps; + + for (ps=*pp; ISBLANK(*ps); ps++) ; + if (*ps == '\0') { + return NULL; + } + + if (*ps == '\"' || *ps == '\'') { + *pp = strchr(ps+1, *ps); + if (*pp) (*pp)++; + } + else { + *pp = strpbrk(ps, " \t"); + } + + if (!*pp) { + *pp = ps + strlen(ps); + } + + if (**pp != '\0') { + **pp = '\0'; + (*pp)++; + } + + return ps; +} + +static debug_command* +parse_command(mrb_state *mrb, mrdb_state *mrdb, char *buf) +{ + debug_command *cmd = NULL; + char *p = buf; + size_t wlen; + + /* get word #1 */ + mrdb->words[0] = pick_out_word(mrb, &p); + if (!mrdb->words[0]) { + return NULL; + } + mrdb->wcnt = 1; + /* set remain parameter */ + for ( ; *p && ISBLANK(*p); p++) ; + if (*p) { + mrdb->words[mrdb->wcnt++] = p; + } + + /* check word #1 */ + for (cmd=(debug_command*)debug_command_list; cmd->cmd1; cmd++) { + wlen = strlen(mrdb->words[0]); + if (wlen >= cmd->len1 && + strncmp(mrdb->words[0], cmd->cmd1, wlen) == 0) { + break; + } + } + + if (cmd->cmd2) { + if (mrdb->wcnt > 1) { + /* get word #2 */ + mrdb->words[1] = pick_out_word(mrb, &p); + if (mrdb->words[1]) { + /* update remain parameter */ + for ( ; *p && ISBLANK(*p); p++) ; + if (*p) { + mrdb->words[mrdb->wcnt++] = p; + } + } + } + + /* check word #1,#2 */ + for ( ; cmd->cmd1; cmd++) { + wlen = strlen(mrdb->words[0]); + if (wlen < cmd->len1 || + strncmp(mrdb->words[0], cmd->cmd1, wlen)) { + continue; + } + + if (!cmd->cmd2) break; /* word #1 only */ + + if (mrdb->wcnt == 1) continue; /* word #2 not specified */ + + wlen = strlen(mrdb->words[1]); + if (wlen >= cmd->len2 && + strncmp(mrdb->words[1], cmd->cmd2, wlen) == 0) { + break; /* word #1 and #2 */ + } + } + } + + /* divide remain parameters */ + if (cmd->cmd1 && cmd->div) { + p = mrdb->words[--mrdb->wcnt]; + for ( ; mrdb->wcnt<MAX_COMMAND_WORD; mrdb->wcnt++) { + mrdb->words[mrdb->wcnt] = pick_out_word(mrb, &p); + if (!mrdb->words[mrdb->wcnt]) { + break; + } + } + } + + return cmd->cmd1 ? cmd : NULL; +} + +static void +print_info_stopped_break(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_debug_breakpoint bp; + int32_t ret; + uint16_t lineno; + const char *file; + const char *method_name; + const char *class_name; + + ret = mrb_debug_get_break(mrb, mrdb->dbg, mrdb->dbg->stopped_bpno, &bp); + if (ret == 0) { + switch(bp.type) { + case MRB_DEBUG_BPTYPE_LINE: + file = bp.point.linepoint.file; + lineno = bp.point.linepoint.lineno; + printf("Breakpoint %d, at %s:%d\n", bp.bpno, file, lineno); + break; + case MRB_DEBUG_BPTYPE_METHOD: + method_name = bp.point.methodpoint.method_name; + class_name = bp.point.methodpoint.class_name; + if (class_name == NULL) { + printf("Breakpoint %d, %s\n", bp.bpno, method_name); + } + else { + printf("Breakpoint %d, %s:%s\n", bp.bpno, class_name, method_name); + } + if (mrdb->dbg->isCfunc) { + printf("Stopped before calling the C function.\n"); + } + break; + default: + break; + } + } +} + +static void +print_info_stopped_step_next(mrb_state *mrb, mrdb_state *mrdb) +{ + const char* file = mrdb->dbg->prvfile; + uint16_t lineno = mrdb->dbg->prvline; + printf("%s:%d\n", file, lineno); +} + +static void +print_info_stopped_code(mrb_state *mrb, mrdb_state *mrdb) +{ + char* file = mrb_debug_get_source(mrb, mrdb, mrdb->srcpath, mrdb->dbg->prvfile); + uint16_t lineno = mrdb->dbg->prvline; + if (file != NULL) { + mrb_debug_list(mrb, mrdb->dbg, file, lineno, lineno); + mrb_free(mrb, file); + } +} + +static void +print_info_stopped(mrb_state *mrb, mrdb_state *mrdb) +{ + switch(mrdb->dbg->bm) { + case BRK_BREAK: + print_info_stopped_break(mrb, mrdb); + print_info_stopped_code(mrb, mrdb); + break; + case BRK_STEP: + case BRK_NEXT: + print_info_stopped_step_next(mrb, mrdb); + print_info_stopped_code(mrb, mrdb); + break; + default: + break; + } +} + +static debug_command* +get_and_parse_command(mrb_state *mrb, mrdb_state *mrdb) +{ + debug_command *cmd = NULL; + char *p; + int i; + + while (!cmd) { + for (p=NULL; !p || *p=='\0'; ) { + printf("(%s:%d) ", mrdb->dbg->prvfile, mrdb->dbg->prvline); + fflush(stdout); + p = get_command(mrb, mrdb); + } + + cmd = parse_command(mrb, mrdb, p); +#ifdef _DBG_MRDB_PARSER_ + for (i=0; i<mrdb->wcnt; i++) { + printf("%d: %s\n", i, mrdb->words[i]); + } +#endif + if (!cmd) { + printf("invalid command ("); + for (i=0; i<mrdb->wcnt; i++) { + if (i>0) { + printf(" "); + } + printf("%s", mrdb->words[i]); + } + puts(")"); + } + } + return cmd; +} + +static int32_t +check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *regs) +{ + struct RClass* c; + mrb_sym sym; + int32_t bpno; + mrb_bool isCfunc; + + mrb_debug_context *dbg = mrb_debug_context_get(mrb); + + isCfunc = FALSE; + bpno = dbg->method_bpno; + dbg->method_bpno = 0; + + switch(GET_OPCODE(*pc)) { + case OP_SEND: + case OP_SENDB: + c = mrb_class(mrb, regs[GETARG_A(*pc)]); + sym = irep->syms[GETARG_B(*pc)]; + break; + case OP_SUPER: + c = mrb->c->ci->target_class->super; + sym = mrb->c->ci->mid; + break; + default: + sym = 0; + break; + } + if (sym != 0) { + dbg->method_bpno = mrb_debug_check_breakpoint_method(mrb, dbg, c, sym, &isCfunc); + if (isCfunc) { + bpno = dbg->method_bpno; + dbg->method_bpno = 0; + } + } + dbg->isCfunc = isCfunc; + return bpno; +} + +static void +mrb_code_fetch_hook(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *regs) +{ + const char *file; + int32_t line; + int32_t bpno; + + mrb_debug_context *dbg = mrb_debug_context_get(mrb); + + mrb_assert(dbg); + + dbg->irep = irep; + dbg->pc = pc; + dbg->regs = regs; + + if (dbg->xphase == DBG_PHASE_RESTART) { + dbg->root_irep = irep; + dbg->prvfile = NULL; + dbg->prvline = 0; + dbg->prvci = NULL; + dbg->xm = DBG_RUN; + dbg->xphase = DBG_PHASE_RUNNING; + } + + file = mrb_debug_get_filename(irep, pc - irep->iseq); + line = mrb_debug_get_line(irep, pc - irep->iseq); + + switch (dbg->xm) { + case DBG_STEP: + if (!file || (dbg->prvfile == file && dbg->prvline == line)) { + return; + } + dbg->method_bpno = 0; + dbg->bm = BRK_STEP; + break; + + case DBG_NEXT: + if (!file || (dbg->prvfile == file && dbg->prvline == line)) { + return; + } + if ((intptr_t)(dbg->prvci) < (intptr_t)(mrb->c->ci)) { + return; + } + dbg->prvci = NULL; + dbg->method_bpno = 0; + dbg->bm = BRK_NEXT; + break; + + case DBG_RUN: + bpno = check_method_breakpoint(mrb, irep, pc, regs); + if (bpno > 0) { + dbg->stopped_bpno = bpno; + dbg->bm = BRK_BREAK; + break; + } + if (dbg->prvfile != file || dbg->prvline != line) { + bpno = mrb_debug_check_breakpoint_line(mrb, dbg, file, line); + if (bpno > 0) { + dbg->stopped_bpno = bpno; + dbg->bm = BRK_BREAK; + break; + } + } + dbg->prvfile = file; + dbg->prvline = line; + return; + case DBG_INIT: + dbg->root_irep = irep; + dbg->bm = BRK_INIT; + if (!file || line < 0) { + puts("Cannot get debugging information."); + } + break; + + default: + return; + } + + dbg->prvfile = file; + dbg->prvline = line; + + if (dbg->bm == BRK_BREAK && --dbg->ccnt > 0) { + return; + } + dbg->break_hook(mrb, dbg); + + dbg->xphase = DBG_PHASE_RUNNING; +} + +static mrdb_exemode +mrb_debug_break_hook(mrb_state *mrb, mrb_debug_context *dbg) +{ + debug_command *cmd; + dbgcmd_state st = DBGST_CONTINUE; + mrdb_state *mrdb = mrdb_state_get(mrb); + + print_info_stopped(mrb, mrdb); + + while (1) { + cmd = get_and_parse_command(mrb, mrdb); + mrb_assert(cmd); + + st = cmd->func(mrb, mrdb); + + if ((st == DBGST_CONTINUE) || (st == DBGST_RESTART)) break; + } + return dbg->xm; +} + +int +main(int argc, char **argv) +{ + mrb_state *mrb = mrb_open(); + int n = -1; + struct _args args; + mrb_value v; + mrdb_state *mrdb; + mrdb_state *mrdb_backup; + mrb_debug_context* dbg_backup; + debug_command *cmd; + + l_restart: + + if (mrb == NULL) { + fputs("Invalid mrb_state, exiting mruby\n", stderr); + return EXIT_FAILURE; + } + + /* parse command parameters */ + n = parse_args(mrb, argc, argv, &args); + if (n == EXIT_FAILURE || args.rfp == NULL) { + cleanup(mrb, &args); + usage(argv[0]); + return n; + } + + /* initialize debugger information */ + mrdb = mrdb_state_get(mrb); + mrb_assert(mrdb && mrdb->dbg); + mrdb->srcpath = args.srcpath; + + if (mrdb->dbg->xm == DBG_QUIT) { + mrdb->dbg->xphase = DBG_PHASE_RESTART; + } + else { + mrdb->dbg->xphase = DBG_PHASE_BEFORE_RUN; + } + mrdb->dbg->xm = DBG_INIT; + mrdb->dbg->ccnt = 1; + + /* setup hook functions */ + mrb->code_fetch_hook = mrb_code_fetch_hook; + mrdb->dbg->break_hook = mrb_debug_break_hook; + + if (args.mrbfile) { /* .mrb */ + v = mrb_load_irep_file(mrb, args.rfp); + } + else { /* .rb */ + mrbc_context *cc = mrbc_context_new(mrb); + mrbc_filename(mrb, cc, args.fname); + v = mrb_load_file_cxt(mrb, args.rfp, cc); + mrbc_context_free(mrb, cc); + } + if (mrdb->dbg->xm == DBG_QUIT && !mrb_undef_p(v) && mrb->exc) { + const char *classname = mrb_obj_classname(mrb, mrb_obj_value(mrb->exc)); + if (!strcmp(classname, "DebuggerExit")) { + cleanup(mrb, &args); + return 0; + } + if (!strcmp(classname, "DebuggerRestart")) { + mrdb_backup = mrdb_state_get(mrb); + dbg_backup = mrb_debug_context_get(mrb); + + mrdb_state_set(NULL); + mrb_debug_context_set(NULL); + + cleanup(mrb, &args); + mrb = mrb_open(); + + mrdb_state_set(mrdb_backup); + mrb_debug_context_set(dbg_backup); + + goto l_restart; + } + } + puts("mruby application exited."); + mrdb->dbg->xphase = DBG_PHASE_AFTER_RUN; + if (!mrb_undef_p(v)) { + if (mrb->exc) { + mrb_print_error(mrb); + } + else { + printf(" => "); + mrb_p(mrb, v); + } + } + + mrdb->dbg->prvfile = "-"; + mrdb->dbg->prvline = 0; + + while (1) { + cmd = get_and_parse_command(mrb, mrdb); + mrb_assert(cmd); + + if (cmd->id == DBGCMD_QUIT) { + break; + } + + if ( cmd->func(mrb, mrdb) == DBGST_RESTART ) goto l_restart; + } + + cleanup(mrb, &args); + + return 0; +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h new file mode 100644 index 000000000..5ac12c1cd --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h @@ -0,0 +1,165 @@ +/* +** mrdb.h - mruby debugger +** +*/ + +#ifndef MRDB_H +#define MRDB_H + +#include <mruby.h> + +#include "mrdbconf.h" + +#ifdef _MSC_VER +# define __func__ __FUNCTION__ +#endif + +#define MAX_COMMAND_WORD (16) + +typedef enum debug_command_id { + DBGCMD_RUN, + DBGCMD_CONTINUE, + DBGCMD_NEXT, + DBGCMD_STEP, + DBGCMD_BREAK, + DBGCMD_INFO_BREAK, + DBGCMD_WATCH, + DBGCMD_INFO_WATCH, + DBGCMD_ENABLE, + DBGCMD_DISABLE, + DBGCMD_DELETE, + DBGCMD_PRINT, + DBGCMD_DISPLAY, + DBGCMD_INFO_DISPLAY, + DBGCMD_DELETE_DISPLAY, + DBGCMD_EVAL, + DBGCMD_BACKTRACE, + DBGCMD_LIST, + DBGCMD_HELP, + DBGCMD_QUIT, + DBGCMD_UNKNOWN +} debug_command_id; + +typedef enum dbgcmd_state { + DBGST_CONTINUE, + DBGST_PROMPT, + DBGST_COMMAND_ERROR, + DBGST_MAX, + DBGST_RESTART +} dbgcmd_state; + +typedef enum mrdb_exemode { + DBG_INIT, + DBG_RUN, + DBG_STEP, + DBG_NEXT, + DBG_QUIT, +} mrdb_exemode; + +typedef enum mrdb_exephase { + DBG_PHASE_BEFORE_RUN, + DBG_PHASE_RUNNING, + DBG_PHASE_AFTER_RUN, + DBG_PHASE_RESTART, +} mrdb_exephase; + +typedef enum mrdb_brkmode { + BRK_INIT, + BRK_BREAK, + BRK_STEP, + BRK_NEXT, + BRK_QUIT, +} mrdb_brkmode; + +typedef enum { + MRB_DEBUG_BPTYPE_NONE, + MRB_DEBUG_BPTYPE_LINE, + MRB_DEBUG_BPTYPE_METHOD, +} mrb_debug_bptype; + +struct mrb_irep; +struct mrbc_context; +struct mrb_debug_context; + +typedef struct mrb_debug_linepoint { + const char *file; + uint16_t lineno; +} mrb_debug_linepoint; + +typedef struct mrb_debug_methodpoint { + const char *class_name; + const char *method_name; +} mrb_debug_methodpoint; + +typedef struct mrb_debug_breakpoint { + uint32_t bpno; + uint8_t enable; + mrb_debug_bptype type; + union point { + mrb_debug_linepoint linepoint; + mrb_debug_methodpoint methodpoint; + } point; +} mrb_debug_breakpoint; + +typedef struct mrb_debug_context { + struct mrb_irep *root_irep; + struct mrb_irep *irep; + mrb_code *pc; + mrb_value *regs; + + const char *prvfile; + int32_t prvline; + mrb_callinfo *prvci; + + mrdb_exemode xm; + mrdb_exephase xphase; + mrdb_brkmode bm; + int16_t bmi; + + uint16_t ccnt; + uint16_t scnt; + + mrb_debug_breakpoint bp[MAX_BREAKPOINT]; + uint32_t bpnum; + int32_t next_bpno; + int32_t method_bpno; + int32_t stopped_bpno; + mrb_bool isCfunc; + + mrdb_exemode (*break_hook)(mrb_state *mrb, struct mrb_debug_context *dbg); + +} mrb_debug_context; + +typedef struct mrdb_state { + char *command; + uint8_t wcnt; + uint8_t pi; + char *words[MAX_COMMAND_WORD]; + const char *srcpath; + uint32_t print_no; + + mrb_debug_context *dbg; +} mrdb_state; + +typedef dbgcmd_state (*debug_command_func)(mrb_state*, mrdb_state*); + +/* cmdrun.c */ +dbgcmd_state dbgcmd_run(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_continue(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_step(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_next(mrb_state*, mrdb_state*); +/* cmdbreak.c */ +dbgcmd_state dbgcmd_break(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_info_break(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_delete(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_enable(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_disable(mrb_state*, mrdb_state*); +/* cmdprint.c */ +dbgcmd_state dbgcmd_print(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_eval(mrb_state*, mrdb_state*); +/* cmdmisc.c */ +dbgcmd_state dbgcmd_list(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_help(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_quit(mrb_state*, mrdb_state*); + +#endif diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h new file mode 100644 index 000000000..f17f9c57d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h @@ -0,0 +1,16 @@ +/* +** mrdbconf.h - mruby debugger configuration +** +*/ + +#ifndef MRDBCONF_H +#define MRDBCONF_H + +/* configuration options: */ +/* maximum size for command buffer */ +#define MAX_COMMAND_LINE 1024 + +/* maximum number of setable breakpoint */ +#define MAX_BREAKPOINT 5 + +#endif diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdberror.h b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdberror.h new file mode 100644 index 000000000..c7812b0d6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/mrdberror.h @@ -0,0 +1,20 @@ +/* +** mrdberror.h - mruby debugger error code +** +*/ + +#ifndef MRDBERROR_H +#define MRDBERROR_H + +#define MRB_DEBUG_OK (0) +#define MRB_DEBUG_NOBUF (-1) +#define MRB_DEBUG_INVALID_ARGUMENT (-2) + +#define MRB_DEBUG_BREAK_INVALID_LINENO (-11) +#define MRB_DEBUG_BREAK_INVALID_FILE (-12) +#define MRB_DEBUG_BREAK_INVALID_NO (-13) +#define MRB_DEBUG_BREAK_NUM_OVER (-14) +#define MRB_DEBUG_BREAK_NO_OVER (-15) + +#endif + diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mirb/bintest/mirb.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mirb/bintest/mirb.rb new file mode 100644 index 000000000..ed53321bd --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mirb/bintest/mirb.rb @@ -0,0 +1,12 @@ +require 'open3' + +assert('mirb normal operations') do + o, s = Open3.capture2('bin/mirb', :stdin_data => "a=1\nb=2\na+b\n") + assert_true o.include?('=> 3') + assert_true o.include?('=> 2') +end + +assert('regression for #1563') do + o, s = Open3.capture2('bin/mirb', :stdin_data => "a=1;b=2;c=3\nb\nc") + assert_true o.include?('=> 3') +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mirb/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mirb/mrbgem.rake new file mode 100644 index 000000000..a74871d81 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mirb/mrbgem.rake @@ -0,0 +1,33 @@ +MRuby::Gem::Specification.new('mruby-bin-mirb') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mirb command' + + if spec.build.cc.search_header_path 'readline/readline.h' + spec.cc.defines << "ENABLE_READLINE" + if spec.build.cc.search_header_path 'termcap.h' + if MRUBY_BUILD_HOST_IS_CYGWIN || MRUBY_BUILD_HOST_IS_OPENBSD + if spec.build.cc.search_header_path 'termcap.h' + if MRUBY_BUILD_HOST_IS_CYGWIN then + spec.linker.libraries << 'ncurses' + else + spec.linker.libraries << 'termcap' + end + end + end + end + if RUBY_PLATFORM.include?('netbsd') + spec.linker.libraries << 'edit' + else + spec.linker.libraries << 'readline' + if spec.build.cc.search_header_path 'curses.h' + spec.linker.libraries << 'ncurses' + end + end + elsif spec.build.cc.search_header_path 'linenoise.h' + spec.cc.defines << "ENABLE_LINENOISE" + end + + spec.bins = %w(mirb) + spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c new file mode 100644 index 000000000..fe311d830 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -0,0 +1,584 @@ +/* +** mirb - Embeddable Interactive Ruby Shell +** +** This program takes code from the user in +** an interactive way and executes it +** immediately. It's a REPL... +*/ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include <signal.h> +#include <setjmp.h> + +#ifdef ENABLE_READLINE +#include <readline/readline.h> +#include <readline/history.h> +#define MIRB_ADD_HISTORY(line) add_history(line) +#define MIRB_READLINE(ch) readline(ch) +#define MIRB_WRITE_HISTORY(path) write_history(path) +#define MIRB_READ_HISTORY(path) read_history(path) +#define MIRB_USING_HISTORY() using_history() +#elif defined(ENABLE_LINENOISE) +#define ENABLE_READLINE +#include <linenoise.h> +#define MIRB_ADD_HISTORY(line) linenoiseHistoryAdd(line) +#define MIRB_READLINE(ch) linenoise(ch) +#define MIRB_WRITE_HISTORY(path) linenoiseHistorySave(path) +#define MIRB_READ_HISTORY(path) linenoiseHistoryLoad(history_path) +#define MIRB_USING_HISTORY() +#endif + +#ifndef _WIN32 +#define MIRB_SIGSETJMP(env) sigsetjmp(env, 1) +#define MIRB_SIGLONGJMP(env, val) siglongjmp(env, val) +#define SIGJMP_BUF sigjmp_buf +#else +#define MIRB_SIGSETJMP(env) setjmp(env) +#define MIRB_SIGLONGJMP(env, val) longjmp(env, val) +#define SIGJMP_BUF jmp_buf +#endif + +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/proc.h> +#include <mruby/compile.h> +#include <mruby/string.h> + +#ifdef ENABLE_READLINE + +static const char history_file_name[] = ".mirb_history"; + +static char * +get_history_path(mrb_state *mrb) +{ + char *path = NULL; + const char *home = getenv("HOME"); + +#ifdef _WIN32 + if (home != NULL) { + home = getenv("USERPROFILE"); + } +#endif + + if (home != NULL) { + int len = snprintf(NULL, 0, "%s/%s", home, history_file_name); + if (len >= 0) { + size_t size = len + 1; + path = (char *)mrb_malloc_simple(mrb, size); + if (path != NULL) { + int n = snprintf(path, size, "%s/%s", home, history_file_name); + if (n != len) { + mrb_free(mrb, path); + path = NULL; + } + } + } + } + + return path; +} + +#endif + +static void +p(mrb_state *mrb, mrb_value obj, int prompt) +{ + mrb_value val; + + val = mrb_funcall(mrb, obj, "inspect", 0); + if (prompt) { + if (!mrb->exc) { + fputs(" => ", stdout); + } + else { + val = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); + } + } + if (!mrb_string_p(val)) { + val = mrb_obj_as_string(mrb, obj); + } + fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout); + putc('\n', stdout); +} + +/* Guess if the user might want to enter more + * or if he wants an evaluation of his code now */ +static mrb_bool +is_code_block_open(struct mrb_parser_state *parser) +{ + mrb_bool code_block_open = FALSE; + + /* check for heredoc */ + if (parser->parsing_heredoc != NULL) return TRUE; + if (parser->heredoc_end_now) { + parser->heredoc_end_now = FALSE; + return FALSE; + } + + /* check for unterminated string */ + if (parser->lex_strterm) return TRUE; + + /* check if parser error are available */ + if (0 < parser->nerr) { + const char unexpected_end[] = "syntax error, unexpected $end"; + const char *message = parser->error_buffer[0].message; + + /* a parser error occur, we have to check if */ + /* we need to read one more line or if there is */ + /* a different issue which we have to show to */ + /* the user */ + + if (strncmp(message, unexpected_end, sizeof(unexpected_end) - 1) == 0) { + code_block_open = TRUE; + } + else if (strcmp(message, "syntax error, unexpected keyword_end") == 0) { + code_block_open = FALSE; + } + else if (strcmp(message, "syntax error, unexpected tREGEXP_BEG") == 0) { + code_block_open = FALSE; + } + return code_block_open; + } + + switch (parser->lstate) { + + /* all states which need more code */ + + case EXPR_BEG: + /* beginning of a statement, */ + /* that means previous line ended */ + code_block_open = FALSE; + break; + case EXPR_DOT: + /* a message dot was the last token, */ + /* there has to come more */ + code_block_open = TRUE; + break; + case EXPR_CLASS: + /* a class keyword is not enough! */ + /* we need also a name of the class */ + code_block_open = TRUE; + break; + case EXPR_FNAME: + /* a method name is necessary */ + code_block_open = TRUE; + break; + case EXPR_VALUE: + /* if, elsif, etc. without condition */ + code_block_open = TRUE; + break; + + /* now all the states which are closed */ + + case EXPR_ARG: + /* an argument is the last token */ + code_block_open = FALSE; + break; + + /* all states which are unsure */ + + case EXPR_CMDARG: + break; + case EXPR_END: + /* an expression was ended */ + break; + case EXPR_ENDARG: + /* closing parenthese */ + break; + case EXPR_ENDFN: + /* definition end */ + break; + case EXPR_MID: + /* jump keyword like break, return, ... */ + break; + case EXPR_MAX_STATE: + /* don't know what to do with this token */ + break; + default: + /* this state is unexpected! */ + break; + } + + return code_block_open; +} + +struct _args { + FILE *rfp; + mrb_bool verbose : 1; + int argc; + char** argv; +}; + +static void +usage(const char *name) +{ + static const char *const usage_msg[] = { + "switches:", + "-v print version number, then run in verbose mode", + "--verbose run in verbose mode", + "--version print the version", + "--copyright print the copyright", + NULL + }; + const char *const *p = usage_msg; + + printf("Usage: %s [switches]\n", name); + while (*p) + printf(" %s\n", *p++); +} + +static int +parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args) +{ + static const struct _args args_zero = { 0 }; + + *args = args_zero; + + for (argc--,argv++; argc > 0; argc--,argv++) { + char *item; + if (argv[0][0] != '-') break; + + item = argv[0] + 1; + switch (*item++) { + case 'v': + if (!args->verbose) mrb_show_version(mrb); + args->verbose = TRUE; + break; + case '-': + if (strcmp((*argv) + 2, "version") == 0) { + mrb_show_version(mrb); + exit(EXIT_SUCCESS); + } + else if (strcmp((*argv) + 2, "verbose") == 0) { + args->verbose = TRUE; + break; + } + else if (strcmp((*argv) + 2, "copyright") == 0) { + mrb_show_copyright(mrb); + exit(EXIT_SUCCESS); + } + default: + return EXIT_FAILURE; + } + } + + if (args->rfp == NULL) { + if (*argv != NULL) { + args->rfp = fopen(argv[0], "r"); + if (args->rfp == NULL) { + printf("Cannot open program file. (%s)\n", *argv); + return EXIT_FAILURE; + } + argc--; argv++; + } + } + args->argv = (char **)mrb_realloc(mrb, args->argv, sizeof(char*) * (argc + 1)); + memcpy(args->argv, argv, (argc+1) * sizeof(char*)); + args->argc = argc; + + return EXIT_SUCCESS; +} + +static void +cleanup(mrb_state *mrb, struct _args *args) +{ + if (args->rfp) + fclose(args->rfp); + mrb_free(mrb, args->argv); + mrb_close(mrb); +} + +/* Print a short remark for the user */ +static void +print_hint(void) +{ + printf("mirb - Embeddable Interactive Ruby Shell\n\n"); +} + +#ifndef ENABLE_READLINE +/* Print the command line prompt of the REPL */ +static void +print_cmdline(int code_block_open) +{ + if (code_block_open) { + printf("* "); + } + else { + printf("> "); + } + fflush(stdout); +} +#endif + +void mrb_codedump_all(mrb_state*, struct RProc*); + +static int +check_keyword(const char *buf, const char *word) +{ + const char *p = buf; + size_t len = strlen(word); + + /* skip preceding spaces */ + while (*p && isspace((unsigned char)*p)) { + p++; + } + /* check keyword */ + if (strncmp(p, word, len) != 0) { + return 0; + } + p += len; + /* skip trailing spaces */ + while (*p) { + if (!isspace((unsigned char)*p)) return 0; + p++; + } + return 1; +} + + +#ifndef ENABLE_READLINE +volatile sig_atomic_t input_canceled = 0; +void +ctrl_c_handler(int signo) +{ + input_canceled = 1; +} +#else +SIGJMP_BUF ctrl_c_buf; +void +ctrl_c_handler(int signo) +{ + MIRB_SIGLONGJMP(ctrl_c_buf, 1); +} +#endif + +int +main(int argc, char **argv) +{ + char ruby_code[4096] = { 0 }; + char last_code_line[1024] = { 0 }; +#ifndef ENABLE_READLINE + int last_char; + size_t char_index; +#else + char *history_path; + char* line; +#endif + mrbc_context *cxt; + struct mrb_parser_state *parser; + mrb_state *mrb; + mrb_value result; + struct _args args; + mrb_value ARGV; + int n; + int i; + mrb_bool code_block_open = FALSE; + int ai; + unsigned int stack_keep = 0; + + /* new interpreter instance */ + mrb = mrb_open(); + if (mrb == NULL) { + fputs("Invalid mrb interpreter, exiting mirb\n", stderr); + return EXIT_FAILURE; + } + + n = parse_args(mrb, argc, argv, &args); + if (n == EXIT_FAILURE) { + cleanup(mrb, &args); + usage(argv[0]); + return n; + } + + ARGV = mrb_ary_new_capa(mrb, args.argc); + for (i = 0; i < args.argc; i++) { + char* utf8 = mrb_utf8_from_locale(args.argv[i], -1); + if (utf8) { + mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, utf8)); + mrb_utf8_free(utf8); + } + } + mrb_define_global_const(mrb, "ARGV", ARGV); + +#ifdef ENABLE_READLINE + history_path = get_history_path(mrb); + if (history_path == NULL) { + fputs("failed to get history path\n", stderr); + mrb_close(mrb); + return EXIT_FAILURE; + } + + MIRB_USING_HISTORY(); + MIRB_READ_HISTORY(history_path); +#endif + + print_hint(); + + cxt = mrbc_context_new(mrb); + cxt->capture_errors = TRUE; + cxt->lineno = 1; + mrbc_filename(mrb, cxt, "(mirb)"); + if (args.verbose) cxt->dump_result = TRUE; + + ai = mrb_gc_arena_save(mrb); + + while (TRUE) { + char *utf8; + + if (args.rfp) { + if (fgets(last_code_line, sizeof(last_code_line)-1, args.rfp) != NULL) + goto done; + break; + } + +#ifndef ENABLE_READLINE + print_cmdline(code_block_open); + + signal(SIGINT, ctrl_c_handler); + char_index = 0; + while ((last_char = getchar()) != '\n') { + if (last_char == EOF) break; + if (char_index >= sizeof(last_code_line)-2) { + fputs("input string too long\n", stderr); + continue; + } + last_code_line[char_index++] = last_char; + } + signal(SIGINT, SIG_DFL); + if (input_canceled) { + ruby_code[0] = '\0'; + last_code_line[0] = '\0'; + code_block_open = FALSE; + puts("^C"); + input_canceled = 0; + continue; + } + if (last_char == EOF) { + fputs("\n", stdout); + break; + } + + last_code_line[char_index++] = '\n'; + last_code_line[char_index] = '\0'; +#else + if (MIRB_SIGSETJMP(ctrl_c_buf) == 0) { + ; + } + else { + ruby_code[0] = '\0'; + last_code_line[0] = '\0'; + code_block_open = FALSE; + puts("^C"); + } + signal(SIGINT, ctrl_c_handler); + line = MIRB_READLINE(code_block_open ? "* " : "> "); + signal(SIGINT, SIG_DFL); + + if (line == NULL) { + printf("\n"); + break; + } + if (strlen(line) > sizeof(last_code_line)-2) { + fputs("input string too long\n", stderr); + continue; + } + strcpy(last_code_line, line); + strcat(last_code_line, "\n"); + MIRB_ADD_HISTORY(line); + free(line); +#endif + +done: + + if (code_block_open) { + if (strlen(ruby_code)+strlen(last_code_line) > sizeof(ruby_code)-1) { + fputs("concatenated input string too long\n", stderr); + continue; + } + strcat(ruby_code, last_code_line); + } + else { + if (check_keyword(last_code_line, "quit") || check_keyword(last_code_line, "exit")) { + break; + } + strcpy(ruby_code, last_code_line); + } + + utf8 = mrb_utf8_from_locale(ruby_code, -1); + if (!utf8) abort(); + + /* parse code */ + parser = mrb_parser_new(mrb); + if (parser == NULL) { + fputs("create parser state error\n", stderr); + break; + } + parser->s = utf8; + parser->send = utf8 + strlen(utf8); + parser->lineno = cxt->lineno; + mrb_parser_parse(parser, cxt); + code_block_open = is_code_block_open(parser); + mrb_utf8_free(utf8); + + if (code_block_open) { + /* no evaluation of code */ + } + else { + if (0 < parser->nerr) { + /* syntax error */ + printf("line %d: %s\n", parser->error_buffer[0].lineno, parser->error_buffer[0].message); + } + else { + /* generate bytecode */ + struct RProc *proc = mrb_generate_code(mrb, parser); + if (proc == NULL) { + fputs("codegen error\n", stderr); + mrb_parser_free(parser); + break; + } + + if (args.verbose) { + mrb_codedump_all(mrb, proc); + } + /* pass a proc for evaluation */ + /* evaluate the bytecode */ + result = mrb_vm_run(mrb, + proc, + mrb_top_self(mrb), + stack_keep); + stack_keep = proc->body.irep->nlocals; + /* did an exception occur? */ + if (mrb->exc) { + p(mrb, mrb_obj_value(mrb->exc), 0); + mrb->exc = 0; + } + else { + /* no */ + if (!mrb_respond_to(mrb, result, mrb_intern_lit(mrb, "inspect"))){ + result = mrb_any_to_s(mrb, result); + } + p(mrb, result, 1); + } + } + ruby_code[0] = '\0'; + last_code_line[0] = '\0'; + mrb_gc_arena_restore(mrb, ai); + } + mrb_parser_free(parser); + cxt->lineno++; + } + +#ifdef ENABLE_READLINE + MIRB_WRITE_HISTORY(history_path); + mrb_free(mrb, history_path); +#endif + + mrbc_context_free(mrb, cxt); + mrb_close(mrb); + + return 0; +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mrbc/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mrbc/mrbgem.rake new file mode 100644 index 000000000..e710b5a49 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mrbc/mrbgem.rake @@ -0,0 +1,16 @@ +MRuby::Gem::Specification.new 'mruby-bin-mrbc' do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby compiler executable' + + spec.add_dependency 'mruby-compiler', :core => 'mruby-compiler' + + exec = exefile("#{build.build_dir}/bin/mrbc") + mrbc_objs = Dir.glob("#{spec.dir}/tools/mrbc/*.c").map { |f| objfile(f.pathmap("#{spec.build_dir}/tools/mrbc/%n")) }.flatten + + file exec => mrbc_objs + [libfile("#{build.build_dir}/lib/libmruby_core")] do |t| + build.linker.run t.name, t.prerequisites + end + + build.bins << 'mrbc' unless build.bins.find { |v| v == 'mrbc' } +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c new file mode 100644 index 000000000..580c2e25b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c @@ -0,0 +1,336 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <mruby.h> +#include <mruby/compile.h> +#include <mruby/dump.h> +#include <mruby/proc.h> + +#define RITEBIN_EXT ".mrb" +#define C_EXT ".c" + +struct mrbc_args { + int argc; + char **argv; + int idx; + const char *prog; + const char *outfile; + const char *initname; + mrb_bool check_syntax : 1; + mrb_bool verbose : 1; + unsigned int flags : 4; +}; + +static void +usage(const char *name) +{ + static const char *const usage_msg[] = { + "switches:", + "-c check syntax only", + "-o<outfile> place the output into <outfile>", + "-v print version number, then turn on verbose mode", + "-g produce debugging information", + "-B<symbol> binary <symbol> output in C language format", + "-e generate little endian iseq data", + "-E generate big endian iseq data", + "--verbose run at verbose mode", + "--version print the version", + "--copyright print the copyright", + NULL + }; + const char *const *p = usage_msg; + + printf("Usage: %s [switches] programfile\n", name); + while (*p) + printf(" %s\n", *p++); +} + +static char * +get_outfilename(mrb_state *mrb, char *infile, const char *ext) +{ + size_t infilelen; + size_t extlen; + char *outfile; + char *p; + + infilelen = strlen(infile); + extlen = strlen(ext); + outfile = (char*)mrb_malloc(mrb, infilelen + extlen + 1); + memcpy(outfile, infile, infilelen + 1); + if (*ext) { + if ((p = strrchr(outfile, '.')) == NULL) + p = outfile + infilelen; + memcpy(p, ext, extlen + 1); + } + + return outfile; +} + +static int +parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) +{ + char *outfile = NULL; + static const struct mrbc_args args_zero = { 0 }; + int i; + + *args = args_zero; + args->argc = argc; + args->argv = argv; + args->prog = argv[0]; + + for (i=1; i<argc; i++) { + if (argv[i][0] == '-') { + switch ((argv[i])[1]) { + case 'o': + if (args->outfile) { + fprintf(stderr, "%s: an output file is already specified. (%s)\n", + args->prog, outfile); + return -1; + } + if (argv[i][2] == '\0' && argv[i+1]) { + i++; + args->outfile = get_outfilename(mrb, argv[i], ""); + } + else { + args->outfile = get_outfilename(mrb, argv[i] + 2, ""); + } + break; + case 'B': + if (argv[i][2] == '\0' && argv[i+1]) { + i++; + args->initname = argv[i]; + } + else { + args->initname = argv[i]+2; + } + if (*args->initname == '\0') { + fprintf(stderr, "%s: function name is not specified.\n", args->prog); + return -1; + } + break; + case 'c': + args->check_syntax = TRUE; + break; + case 'v': + if (!args->verbose) mrb_show_version(mrb); + args->verbose = TRUE; + break; + case 'g': + args->flags |= DUMP_DEBUG_INFO; + break; + case 'E': + args->flags = DUMP_ENDIAN_BIG | (args->flags & ~DUMP_ENDIAN_MASK); + break; + case 'e': + args->flags = DUMP_ENDIAN_LIL | (args->flags & ~DUMP_ENDIAN_MASK); + break; + case 'h': + return -1; + case '-': + if (argv[i][1] == '\n') { + return i; + } + if (strcmp(argv[i] + 2, "version") == 0) { + mrb_show_version(mrb); + exit(EXIT_SUCCESS); + } + else if (strcmp(argv[i] + 2, "verbose") == 0) { + args->verbose = TRUE; + break; + } + else if (strcmp(argv[i] + 2, "copyright") == 0) { + mrb_show_copyright(mrb); + exit(EXIT_SUCCESS); + } + return -1; + default: + return i; + } + } + else { + break; + } + } + if (args->verbose && args->initname && (args->flags & DUMP_ENDIAN_MASK) == 0) { + fprintf(stderr, "%s: generating %s endian C file. specify -e/-E for cross compiling.\n", + args->prog, bigendian_p() ? "big" : "little"); + } + return i; +} + +static void +cleanup(mrb_state *mrb, struct mrbc_args *args) +{ + mrb_free(mrb, (void*)args->outfile); + mrb_close(mrb); +} + +static int +partial_hook(struct mrb_parser_state *p) +{ + mrbc_context *c = p->cxt; + struct mrbc_args *args = (struct mrbc_args *)c->partial_data; + const char *fn; + + if (p->f) fclose(p->f); + if (args->idx >= args->argc) { + p->f = NULL; + return -1; + } + fn = args->argv[args->idx++]; + p->f = fopen(fn, "r"); + if (p->f == NULL) { + fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, fn); + return -1; + } + mrb_parser_set_filename(p, fn); + return 0; +} + +static mrb_value +load_file(mrb_state *mrb, struct mrbc_args *args) +{ + mrbc_context *c; + mrb_value result; + char *input = args->argv[args->idx]; + FILE *infile; + mrb_bool need_close = FALSE; + + c = mrbc_context_new(mrb); + if (args->verbose) + c->dump_result = TRUE; + c->no_exec = TRUE; + if (input[0] == '-' && input[1] == '\0') { + infile = stdin; + } + else { + need_close = TRUE; + if ((infile = fopen(input, "r")) == NULL) { + fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, input); + return mrb_nil_value(); + } + } + mrbc_filename(mrb, c, input); + args->idx++; + if (args->idx < args->argc) { + need_close = FALSE; + mrbc_partial_hook(mrb, c, partial_hook, (void*)args); + } + + result = mrb_load_file_cxt(mrb, infile, c); + if (need_close) fclose(infile); + mrbc_context_free(mrb, c); + if (mrb_undef_p(result)) { + return mrb_nil_value(); + } + return result; +} + +static int +dump_file(mrb_state *mrb, FILE *wfp, const char *outfile, struct RProc *proc, struct mrbc_args *args) +{ + int n = MRB_DUMP_OK; + mrb_irep *irep = proc->body.irep; + + if (args->initname) { + n = mrb_dump_irep_cfunc(mrb, irep, args->flags, wfp, args->initname); + if (n == MRB_DUMP_INVALID_ARGUMENT) { + fprintf(stderr, "%s: invalid C language symbol name\n", args->initname); + } + } + else { + n = mrb_dump_irep_binary(mrb, irep, args->flags, wfp); + } + if (n != MRB_DUMP_OK) { + fprintf(stderr, "%s: error in mrb dump (%s) %d\n", args->prog, outfile, n); + } + return n; +} + +int +main(int argc, char **argv) +{ + mrb_state *mrb = mrb_open(); + int n, result; + struct mrbc_args args; + FILE *wfp; + mrb_value load; + + if (mrb == NULL) { + fputs("Invalid mrb_state, exiting mrbc\n", stderr); + return EXIT_FAILURE; + } + + n = parse_args(mrb, argc, argv, &args); + if (n < 0) { + cleanup(mrb, &args); + usage(argv[0]); + return EXIT_FAILURE; + } + if (n == argc) { + fprintf(stderr, "%s: no program file given\n", args.prog); + return EXIT_FAILURE; + } + if (args.outfile == NULL && !args.check_syntax) { + if (n + 1 == argc) { + args.outfile = get_outfilename(mrb, argv[n], args.initname ? C_EXT : RITEBIN_EXT); + } + else { + fprintf(stderr, "%s: output file should be specified to compile multiple files\n", args.prog); + return EXIT_FAILURE; + } + } + + args.idx = n; + load = load_file(mrb, &args); + if (mrb_nil_p(load)) { + cleanup(mrb, &args); + return EXIT_FAILURE; + } + if (args.check_syntax) { + printf("%s:%s:Syntax OK\n", args.prog, argv[n]); + } + + if (args.check_syntax) { + cleanup(mrb, &args); + return EXIT_SUCCESS; + } + + if (args.outfile) { + if (strcmp("-", args.outfile) == 0) { + wfp = stdout; + } + else if ((wfp = fopen(args.outfile, "wb")) == NULL) { + fprintf(stderr, "%s: cannot open output file:(%s)\n", args.prog, args.outfile); + return EXIT_FAILURE; + } + } + else { + fprintf(stderr, "Output file is required\n"); + return EXIT_FAILURE; + } + result = dump_file(mrb, wfp, args.outfile, mrb_proc_ptr(load), &args); + fclose(wfp); + cleanup(mrb, &args); + if (result != MRB_DUMP_OK) { + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +void +mrb_init_mrblib(mrb_state *mrb) +{ +} + +#ifndef DISABLE_GEMS +void +mrb_init_mrbgems(mrb_state *mrb) +{ +} + +void +mrb_final_mrbgems(mrb_state *mrb) +{ +} +#endif diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby-config/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby-config/mrbgem.rake new file mode 100644 index 000000000..66d6ef80b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby-config/mrbgem.rake @@ -0,0 +1,30 @@ +module MRuby + class Build + def exefile(name) + if name.is_a?(Array) + name.flatten.map { |n| exefile(n) } + elsif name !~ /\./ + "#{name}#{exts.executable}" + else + name + end + end + end +end + +MRuby.each_target do + next if kind_of? MRuby::CrossBuild + + mruby_config = 'mruby-config' + (ENV['OS'] == 'Windows_NT' ? '.bat' : '') + mruby_config_path = "#{build_dir}/bin/#{mruby_config}" + @bins << mruby_config + + file mruby_config_path => libfile("#{build_dir}/lib/libmruby") do |t| + FileUtils.copy "#{File.dirname(__FILE__)}/#{mruby_config}", t.name + config = Hash[open("#{build_dir}/lib/libmruby.flags.mak").read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}] + IO.write(t.name, File.open(t.name) {|f| + f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LIBS|MRUBY_LDFLAGS_BEFORE_LIBS|MRUBY_LDFLAGS|MRUBY_LIBMRUBY_PATH)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"} + }) + FileUtils.chmod(0755, t.name) + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby-config/mruby-config b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby-config/mruby-config new file mode 100644 index 000000000..57346c03f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby-config/mruby-config @@ -0,0 +1,20 @@ +#!/bin/sh + +while [ $# -gt 0 ]; do + case $1 in + --cflags) echo MRUBY_CFLAGS;; + --ldflags) echo MRUBY_LDFLAGS;; + --ldflags-before-libs) echo MRUBY_LDFLAGS_BEFORE_LIBS;; + --libs) echo MRUBY_LIBS;; + --libmruby-path) echo MRUBY_LIBMRUBY_PATH;; + --help) echo "Usage: mruby-config [switches]" + echo " switches:" + echo " --cflags print flags passed to compiler" + echo " --ldflags print flags passed to linker" + echo " --ldflags-before-libs print flags passed to linker before linked libraries" + echo " --libs print linked libraries" + echo " --libmruby-path print libmruby path" + exit 0;; + esac + shift +done diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby-config/mruby-config.bat b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby-config/mruby-config.bat new file mode 100644 index 000000000..a1f7bfdd1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby-config/mruby-config.bat @@ -0,0 +1,42 @@ +@echo off + +:top +shift +if "%0" equ "" goto :eof +if "%0" equ "--cflags" goto cflags +if "%0" equ "--ldflags" goto ldflags +if "%0" equ "--ldflags-before-libs" goto ldflagsbeforelibs +if "%0" equ "--libs" goto libs +if "%0" equ "--libmruby-path" goto libmrubypath +if "%0" equ "--help" goto showhelp +echo Invalid Option +goto :eof + +:cflags +echo MRUBY_CFLAGS +goto top + +:libs +echo MRUBY_LIBS +goto top + +:ldflags +echo MRUBY_LDFLAGS +goto top + +:ldflagsbeforelibs +echo MRUBY_LDFLAGS_BEFORE_LIBS +goto top + +:libmrubypath +echo MRUBY_LIBMRUBY_PATH +goto top + +:showhelp +echo Usage: mruby-config [switches] +echo switches: +echo --cflags print flags passed to compiler +echo --ldflags print flags passed to linker +echo --ldflags-before-libs print flags passed to linker before linked libraries +echo --libs print linked libraries +echo --libmruby-path print libmruby path diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby/bintest/mruby.rb new file mode 100644 index 000000000..b6b090185 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -0,0 +1,60 @@ +require 'tempfile' + +assert('regression for #1564') do + o = `#{cmd('mruby')} -e #{shellquote('<<')} 2>&1` + assert_include o, "-e:1:2: syntax error" + o = `#{cmd('mruby')} -e #{shellquote('<<-')} 2>&1` + assert_include o, "-e:1:3: syntax error" +end + +assert('regression for #1572') do + script, bin = Tempfile.new('test.rb'), Tempfile.new('test.mrb') + File.write script.path, 'p "ok"' + system "#{cmd('mrbc')} -g -o #{bin.path} #{script.path}" + o = `#{cmd('mruby')} -b #{bin.path}`.strip + assert_equal o, '"ok"' +end + +assert '$0 value' do + script, bin = Tempfile.new('test.rb'), Tempfile.new('test.mrb') + + # .rb script + script.write "p $0\n" + script.flush + assert_equal "\"#{script.path}\"", `#{cmd('mruby')} "#{script.path}"`.chomp + + # .mrb file + `#{cmd('mrbc')} -o "#{bin.path}" "#{script.path}"` + assert_equal "\"#{bin.path}\"", `#{cmd('mruby')} -b "#{bin.path}"`.chomp + + # one liner + assert_equal '"-e"', `#{cmd('mruby')} -e #{shellquote('p $0')}`.chomp +end + +assert '__END__', '8.6' do + script = Tempfile.new('test.rb') + + script.write <<EOS +p 'test' + __END__ = 'fin' +p __END__ +__END__ +p 'legend' +EOS + script.flush + assert_equal "\"test\"\n\"fin\"\n", `#{cmd('mruby')} #{script.path}` +end + +assert('garbage collecting built-in classes') do + script = Tempfile.new('test.rb') + + script.write <<RUBY +NilClass = nil +GC.start +Array.dup +print nil.class.to_s +RUBY + script.flush + assert_equal "NilClass", `#{cmd('mruby')} #{script.path}` + assert_equal 0, $?.exitstatus +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby/mrbgem.rake new file mode 100644 index 000000000..fbec13847 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby/mrbgem.rake @@ -0,0 +1,12 @@ +MRuby::Gem::Specification.new('mruby-bin-mruby') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby command' + spec.bins = %w(mruby) + spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') + spec.add_dependency('mruby-error', :core => 'mruby-error') + + if build.cxx_exception_enabled? + build.compile_as_cxx("#{spec.dir}/tools/mruby/mruby.c", "#{spec.build_dir}/tools/mruby/mruby.cxx") + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c new file mode 100644 index 000000000..61d4cde94 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -0,0 +1,254 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/compile.h> +#include <mruby/dump.h> +#include <mruby/variable.h> + +#ifdef MRB_DISABLE_STDIO +static void +p(mrb_state *mrb, mrb_value obj) +{ + mrb_value val = mrb_inspect(mrb, obj); + + fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout); + putc('\n', stdout); +} +#else +#define p(mrb,obj) mrb_p(mrb,obj) +#endif + +struct _args { + FILE *rfp; + char* cmdline; + mrb_bool fname : 1; + mrb_bool mrbfile : 1; + mrb_bool check_syntax : 1; + mrb_bool verbose : 1; + int argc; + char** argv; +}; + +static void +usage(const char *name) +{ + static const char *const usage_msg[] = { + "switches:", + "-b load and execute RiteBinary (mrb) file", + "-c check syntax only", + "-e 'command' one line of script", + "-v print version number, then run in verbose mode", + "--verbose run in verbose mode", + "--version print the version", + "--copyright print the copyright", + NULL + }; + const char *const *p = usage_msg; + + printf("Usage: %s [switches] programfile\n", name); + while (*p) + printf(" %s\n", *p++); +} + +static int +parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args) +{ + char **origargv = argv; + static const struct _args args_zero = { 0 }; + + *args = args_zero; + + for (argc--,argv++; argc > 0; argc--,argv++) { + char *item; + if (argv[0][0] != '-') break; + + if (strlen(*argv) <= 1) { + argc--; argv++; + args->rfp = stdin; + break; + } + + item = argv[0] + 1; + switch (*item++) { + case 'b': + args->mrbfile = TRUE; + break; + case 'c': + args->check_syntax = TRUE; + break; + case 'e': + if (item[0]) { + goto append_cmdline; + } + else if (argc > 1) { + argc--; argv++; + item = argv[0]; +append_cmdline: + if (!args->cmdline) { + size_t buflen; + char *buf; + + buflen = strlen(item) + 1; + buf = (char *)mrb_malloc(mrb, buflen); + memcpy(buf, item, buflen); + args->cmdline = buf; + } + else { + size_t cmdlinelen; + size_t itemlen; + + cmdlinelen = strlen(args->cmdline); + itemlen = strlen(item); + args->cmdline = + (char *)mrb_realloc(mrb, args->cmdline, cmdlinelen + itemlen + 2); + args->cmdline[cmdlinelen] = '\n'; + memcpy(args->cmdline + cmdlinelen + 1, item, itemlen + 1); + } + } + else { + printf("%s: No code specified for -e\n", *origargv); + return EXIT_SUCCESS; + } + break; + case 'v': + if (!args->verbose) mrb_show_version(mrb); + args->verbose = TRUE; + break; + case '-': + if (strcmp((*argv) + 2, "version") == 0) { + mrb_show_version(mrb); + exit(EXIT_SUCCESS); + } + else if (strcmp((*argv) + 2, "verbose") == 0) { + args->verbose = TRUE; + break; + } + else if (strcmp((*argv) + 2, "copyright") == 0) { + mrb_show_copyright(mrb); + exit(EXIT_SUCCESS); + } + default: + return EXIT_FAILURE; + } + } + + if (args->rfp == NULL && args->cmdline == NULL) { + if (*argv == NULL) args->rfp = stdin; + else { + args->rfp = fopen(argv[0], args->mrbfile ? "rb" : "r"); + if (args->rfp == NULL) { + printf("%s: Cannot open program file. (%s)\n", *origargv, *argv); + return EXIT_FAILURE; + } + args->fname = TRUE; + args->cmdline = argv[0]; + argc--; argv++; + } + } + args->argv = (char **)mrb_realloc(mrb, args->argv, sizeof(char*) * (argc + 1)); + memcpy(args->argv, argv, (argc+1) * sizeof(char*)); + args->argc = argc; + + return EXIT_SUCCESS; +} + +static void +cleanup(mrb_state *mrb, struct _args *args) +{ + if (args->rfp && args->rfp != stdin) + fclose(args->rfp); + if (!args->fname) + mrb_free(mrb, args->cmdline); + mrb_free(mrb, args->argv); + mrb_close(mrb); +} + +int +main(int argc, char **argv) +{ + mrb_state *mrb = mrb_open(); + int n = -1; + int i; + struct _args args; + mrb_value ARGV; + mrbc_context *c; + mrb_value v; + mrb_sym zero_sym; + + if (mrb == NULL) { + fputs("Invalid mrb_state, exiting mruby\n", stderr); + return EXIT_FAILURE; + } + + n = parse_args(mrb, argc, argv, &args); + if (n == EXIT_FAILURE || (args.cmdline == NULL && args.rfp == NULL)) { + cleanup(mrb, &args); + usage(argv[0]); + return n; + } + else { + int ai = mrb_gc_arena_save(mrb); + ARGV = mrb_ary_new_capa(mrb, args.argc); + for (i = 0; i < args.argc; i++) { + char* utf8 = mrb_utf8_from_locale(args.argv[i], -1); + if (utf8) { + mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, utf8)); + mrb_utf8_free(utf8); + } + } + mrb_define_global_const(mrb, "ARGV", ARGV); + + c = mrbc_context_new(mrb); + if (args.verbose) + c->dump_result = TRUE; + if (args.check_syntax) + c->no_exec = TRUE; + + /* Set $0 */ + zero_sym = mrb_intern_lit(mrb, "$0"); + if (args.rfp) { + const char *cmdline; + cmdline = args.cmdline ? args.cmdline : "-"; + mrbc_filename(mrb, c, cmdline); + mrb_gv_set(mrb, zero_sym, mrb_str_new_cstr(mrb, cmdline)); + } + else { + mrbc_filename(mrb, c, "-e"); + mrb_gv_set(mrb, zero_sym, mrb_str_new_lit(mrb, "-e")); + } + + /* Load program */ + if (args.mrbfile) { + v = mrb_load_irep_file_cxt(mrb, args.rfp, c); + } + else if (args.rfp) { + v = mrb_load_file_cxt(mrb, args.rfp, c); + } + else { + char* utf8 = mrb_utf8_from_locale(args.cmdline, -1); + if (!utf8) abort(); + v = mrb_load_string_cxt(mrb, utf8, c); + mrb_utf8_free(utf8); + } + + mrb_gc_arena_restore(mrb, ai); + mrbc_context_free(mrb, c); + if (mrb->exc) { + if (mrb_undef_p(v)) { + mrb_p(mrb, mrb_obj_value(mrb->exc)); + } + else { + mrb_print_error(mrb); + } + n = -1; + } + else if (args.check_syntax) { + printf("Syntax OK\n"); + } + } + cleanup(mrb, &args); + + return n == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb new file mode 100644 index 000000000..bb664a2b1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb @@ -0,0 +1,73 @@ +require 'tempfile' + +assert('no files') do + o = `#{cmd('mruby-strip')} 2>&1` + assert_equal 1, $?.exitstatus + assert_equal "no files to strip", o.split("\n")[0] +end + +assert('file not found') do + o = `#{cmd('mruby-strip')} not_found.mrb 2>&1` + assert_equal 1, $?.exitstatus + assert_equal "can't open file for reading not_found.mrb\n", o +end + +assert('not irep file') do + t = Tempfile.new('script.rb') + t.write 'p test\n' + t.flush + o = `#{cmd('mruby-strip')} #{t.path} 2>&1` + assert_equal 1, $?.exitstatus + assert_equal "can't read irep file #{t.path}\n", o +end + +assert('success') do + script_file, compiled1, compiled2 = + Tempfile.new('script.rb'), Tempfile.new('c1.mrb'), Tempfile.new('c2.mrb') + script_file.write "p 'test'\n" + script_file.flush + `#{cmd('mrbc')} -g -o #{compiled1.path} #{script_file.path}` + `#{cmd('mrbc')} -g -o #{compiled2.path} #{script_file.path}` + + o = `#{cmd('mruby-strip')} #{compiled1.path}` + assert_equal 0, $?.exitstatus + assert_equal "", o + assert_equal `#{cmd('mruby')} #{script_file.path}`, `#{cmd('mruby')} -b #{compiled1.path}` + + o = `#{cmd('mruby-strip')} #{compiled1.path} #{compiled2.path}` + assert_equal 0, $?.exitstatus + assert_equal "", o +end + +assert('check debug section') do + script_file, with_debug, without_debug = + Tempfile.new('script.rb'), Tempfile.new('c1.mrb'), Tempfile.new('c2.mrb') + script_file.write "p 'test'\n" + script_file.flush + `#{cmd('mrbc')} -o #{without_debug.path} #{script_file.path}` + `#{cmd('mrbc')} -g -o #{with_debug.path} #{script_file.path}` + + assert_true with_debug.size >= without_debug.size + + `#{cmd('mruby-strip')} #{with_debug.path}` + assert_equal without_debug.size, with_debug.size +end + +assert('check lv section') do + script_file, with_lv, without_lv = + Tempfile.new('script.rb'), Tempfile.new('c1.mrb'), Tempfile.new('c2.mrb') + script_file.write <<EOS +a, b = 0, 1 +a += b +p Kernel.local_variables +EOS + script_file.flush + `#{cmd('mrbc')} -o #{with_lv.path} #{script_file.path}` + `#{cmd('mrbc')} -o #{without_lv.path} #{script_file.path}` + + `#{cmd('mruby-strip')} -l #{without_lv.path}` + assert_true without_lv.size < with_lv.size + + assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp + assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-strip/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-strip/mrbgem.rake new file mode 100644 index 000000000..2abd25eea --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-strip/mrbgem.rake @@ -0,0 +1,6 @@ +MRuby::Gem::Specification.new('mruby-bin-strip') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'irep dump debug section remover command' + spec.bins = %w(mruby-strip) +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c new file mode 100644 index 000000000..deb66d54c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c @@ -0,0 +1,155 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <mruby.h> +#include <mruby/irep.h> +#include <mruby/dump.h> + +struct strip_args { + int argc_start; + int argc; + char **argv; + mrb_bool lvar; +}; + + +static void +irep_remove_lv(mrb_state *mrb, mrb_irep *irep) +{ + int i; + + if (irep->lv) { + mrb_free(mrb, irep->lv); + irep->lv = NULL; + } + + for (i = 0; i < irep->rlen; ++i) { + irep_remove_lv(mrb, irep->reps[i]); + } +} + +static void +print_usage(const char *f) +{ + printf("Usage: %s [switches] irepfiles\n", f); + printf("switches:\n"); + printf(" -l, --lvar remove LVAR section too.\n"); +} + +static int +parse_args(int argc, char **argv, struct strip_args *args) +{ + int i; + + args->argc_start = 0; + args->argc = argc; + args->argv = argv; + args->lvar = FALSE; + + for (i = 1; i < argc; ++i) { + const size_t len = strlen(argv[i]); + if (len >= 2 && argv[i][0] == '-') { + switch (argv[i][1]) { + case 'l': + args->lvar = TRUE; + break; + case '-': + if (strncmp((*argv) + 2, "lvar", len) == 0) { + args->lvar = TRUE; + break; + } + default: + return -1; + } + } + else { + break; + } + } + + args->argc_start = i; + return i; +} + +static int +strip(mrb_state *mrb, struct strip_args *args) +{ + int i; + + for (i = args->argc_start; i < args->argc; ++i) { + char *filename; + FILE *rfile; + mrb_irep *irep; + FILE *wfile; + int dump_result; + + filename = args->argv[i]; + rfile = fopen(filename, "rb"); + if (rfile == NULL) { + fprintf(stderr, "can't open file for reading %s\n", filename); + return EXIT_FAILURE; + } + + irep = mrb_read_irep_file(mrb, rfile); + fclose(rfile); + if (irep == NULL) { + fprintf(stderr, "can't read irep file %s\n", filename); + return EXIT_FAILURE; + } + + /* clear lv if --lvar is enabled */ + if (args->lvar) { + irep_remove_lv(mrb, irep); + } + + wfile = fopen(filename, "wb"); + if (wfile == NULL) { + fprintf(stderr, "can't open file for writing %s\n", filename); + mrb_irep_decref(mrb, irep); + return EXIT_FAILURE; + } + + /* debug flag must always be false */ + dump_result = mrb_dump_irep_binary(mrb, irep, FALSE, wfile); + + fclose(wfile); + mrb_irep_decref(mrb, irep); + + if (dump_result != MRB_DUMP_OK) { + fprintf(stderr, "error occurred during dumping %s\n", filename); + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; +} + +int +main(int argc, char **argv) +{ + struct strip_args args; + int args_result; + mrb_state *mrb; + int ret; + + if (argc <= 1) { + printf("no files to strip\n"); + print_usage(argv[0]); + return EXIT_FAILURE; + } + + args_result = parse_args(argc, argv, &args); + if (args_result < 0) { + print_usage(argv[0]); + return EXIT_FAILURE; + } + mrb = mrb_open_core(mrb_default_allocf, NULL); + if (mrb == NULL) { + fputs("Invalid mrb_state, exiting mruby-strip\n", stderr); + return EXIT_FAILURE; + } + + ret = strip(mrb, &args); + + mrb_close(mrb); + return ret; +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-class-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-class-ext/mrbgem.rake new file mode 100644 index 000000000..a384b1eef --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-class-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-class-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'class/module extension' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-class-ext/src/class.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-class-ext/src/class.c new file mode 100644 index 000000000..5506c4829 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-class-ext/src/class.c @@ -0,0 +1,30 @@ +#include "mruby.h" +#include "mruby/class.h" +#include "mruby/string.h" + +static mrb_value +mrb_mod_name(mrb_state *mrb, mrb_value self) +{ + mrb_value name = mrb_class_path(mrb, mrb_class_ptr(self)); + return mrb_nil_p(name)? name : mrb_str_dup(mrb, name); +} + +static mrb_value +mrb_mod_singleton_class_p(mrb_state *mrb, mrb_value self) +{ + return mrb_bool_value(mrb_type(self) == MRB_TT_SCLASS); +} + +void +mrb_mruby_class_ext_gem_init(mrb_state *mrb) +{ + struct RClass *mod = mrb->module_class; + + mrb_define_method(mrb, mod, "name", mrb_mod_name, MRB_ARGS_NONE()); + mrb_define_method(mrb, mod, "singleton_class?", mrb_mod_singleton_class_p, MRB_ARGS_NONE()); +} + +void +mrb_mruby_class_ext_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-class-ext/test/module.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-class-ext/test/module.rb new file mode 100644 index 000000000..65abde108 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-class-ext/test/module.rb @@ -0,0 +1,34 @@ +assert 'Module#name' do + module Outer + class Inner; end + const_set :SetInner, Class.new + end + + assert_equal 'Outer', Outer.name + assert_equal 'Outer::Inner', Outer::Inner.name + assert_equal 'Outer::SetInner', Outer::SetInner.name + + outer = Module.new do + const_set :SetInner, Class.new + end + Object.const_set :SetOuter, outer + + assert_equal 'SetOuter', SetOuter.name + assert_equal 'SetOuter::SetInner', SetOuter::SetInner.name + + mod = Module.new + cls = Class.new + + assert_nil mod.name + assert_nil cls.name +end + +assert 'Module#singleton_class?' do + mod = Module.new + cls = Class.new + scl = cls.singleton_class + + assert_false mod.singleton_class? + assert_false cls.singleton_class? + assert_true scl.singleton_class? +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/bintest/mrbc.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/bintest/mrbc.rb new file mode 100644 index 000000000..f4d9208b3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/bintest/mrbc.rb @@ -0,0 +1,30 @@ +require 'tempfile' + +assert('Compiling multiple files without new line in last line. #2361') do + a, b, out = Tempfile.new('a.rb'), Tempfile.new('b.rb'), Tempfile.new('out.mrb') + a.write('module A; end') + a.flush + b.write('module B; end') + b.flush + result = `#{cmd('mrbc')} -c -o #{out.path} #{a.path} #{b.path} 2>&1` + assert_equal "#{cmd('mrbc')}:#{a.path}:Syntax OK", result.chomp + assert_equal 0, $?.exitstatus +end + +assert('parsing function with void argument') do + a, out = Tempfile.new('a.rb'), Tempfile.new('out.mrb') + a.write('f ()') + a.flush + result = `#{cmd('mrbc')} -c -o #{out.path} #{a.path} 2>&1` + assert_equal "#{cmd('mrbc')}:#{a.path}:Syntax OK", result.chomp + assert_equal 0, $?.exitstatus +end + +assert('embedded document with invalid terminator') do + a, out = Tempfile.new('a.rb'), Tempfile.new('out.mrb') + a.write("=begin\n=endx\n") + a.flush + result = `#{cmd('mrbc')} -c -o #{out.path} #{a.path} 2>&1` + assert_equal "#{a.path}:3:0: embedded document meets end of file", result.chomp + assert_equal 1, $?.exitstatus +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/codegen.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/codegen.c new file mode 100644 index 000000000..8f15a9b18 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/codegen.c @@ -0,0 +1,3026 @@ +/* +** codegen.c - mruby code generator +** +** See Copyright Notice in mruby.h +*/ + +#include <ctype.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <mruby.h> +#include <mruby/compile.h> +#include <mruby/proc.h> +#include <mruby/numeric.h> +#include <mruby/string.h> +#include <mruby/debug.h> +#include "node.h" +#include <mruby/opcode.h> +#include <mruby/re.h> +#include <mruby/throw.h> + +#ifndef MRB_CODEGEN_LEVEL_MAX +#define MRB_CODEGEN_LEVEL_MAX 1024 +#endif + +typedef mrb_ast_node node; +typedef struct mrb_parser_state parser_state; + +enum looptype { + LOOP_NORMAL, + LOOP_BLOCK, + LOOP_FOR, + LOOP_BEGIN, + LOOP_RESCUE, +}; + +struct loopinfo { + enum looptype type; + int pc1, pc2, pc3, acc; + int ensure_level; + struct loopinfo *prev; +}; + +typedef struct scope { + mrb_state *mrb; + mrb_pool *mpool; + struct mrb_jmpbuf jmp; + + struct scope *prev; + + node *lv; + + int sp; + int pc; + int lastlabel; + int ainfo:15; + mrb_bool mscope:1; + + struct loopinfo *loop; + int ensure_level; + char const *filename; + uint16_t lineno; + + mrb_code *iseq; + uint16_t *lines; + int icapa; + + mrb_irep *irep; + int pcapa, scapa, rcapa; + + uint16_t nlocals; + uint16_t nregs; + int ai; + + int debug_start_pos; + uint16_t filename_index; + parser_state* parser; + + int rlev; /* recursion levels */ +} codegen_scope; + +static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv); +static void scope_finish(codegen_scope *s); +static struct loopinfo *loop_push(codegen_scope *s, enum looptype t); +static void loop_break(codegen_scope *s, node *tree); +static void loop_pop(codegen_scope *s, int val); + +static void gen_assignment(codegen_scope *s, node *tree, int sp, int val); +static void gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val); + +static void codegen(codegen_scope *s, node *tree, int val); +static void raise_error(codegen_scope *s, const char *msg); + +static void +codegen_error(codegen_scope *s, const char *message) +{ + if (!s) return; + while (s->prev) { + codegen_scope *tmp = s->prev; + mrb_free(s->mrb, s->iseq); + mrb_pool_close(s->mpool); + s = tmp; + } +#ifndef MRB_DISABLE_STDIO + if (s->filename && s->lineno) { + fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message); + } + else { + fprintf(stderr, "codegen error: %s\n", message); + } +#endif + MRB_THROW(&s->jmp); +} + +static void* +codegen_palloc(codegen_scope *s, size_t len) +{ + void *p = mrb_pool_alloc(s->mpool, len); + + if (!p) codegen_error(s, "pool memory allocation"); + return p; +} + +static void* +codegen_malloc(codegen_scope *s, size_t len) +{ + void *p = mrb_malloc_simple(s->mrb, len); + + if (!p) codegen_error(s, "mrb_malloc"); + return p; +} + +static void* +codegen_realloc(codegen_scope *s, void *p, size_t len) +{ + p = mrb_realloc_simple(s->mrb, p, len); + + if (!p && len > 0) codegen_error(s, "mrb_realloc"); + return p; +} + +static int +new_label(codegen_scope *s) +{ + s->lastlabel = s->pc; + return s->pc; +} + +static inline int +genop(codegen_scope *s, mrb_code i) +{ + if (s->pc == s->icapa) { + s->icapa *= 2; + s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa); + if (s->lines) { + s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa); + s->irep->lines = s->lines; + } + } + s->iseq[s->pc] = i; + if (s->lines) { + s->lines[s->pc] = s->lineno; + } + return s->pc++; +} + +#define NOVAL 0 +#define VAL 1 + +static mrb_bool +no_optimize(codegen_scope *s) +{ + if (s && s->parser && s->parser->no_optimize) + return TRUE; + return FALSE; +} + +static int +genop_peep(codegen_scope *s, mrb_code i, int val) +{ + /* peephole optimization */ + if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) { + mrb_code i0 = s->iseq[s->pc-1]; + int c1 = GET_OPCODE(i); + int c0 = GET_OPCODE(i0); + + switch (c1) { + case OP_MOVE: + if (GETARG_A(i) == GETARG_B(i)) { + /* skip useless OP_MOVE */ + return 0; + } + if (val) break; + switch (c0) { + case OP_MOVE: + if (GETARG_A(i) == GETARG_A(i0)) { + /* skip overriden OP_MOVE */ + s->pc--; + s->iseq[s->pc] = i; + } + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { + /* skip swapping OP_MOVE */ + return 0; + } + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->pc--; + return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val); + } + break; + case OP_LOADI: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0)); + return 0; + } + break; + case OP_ARRAY: + case OP_HASH: + case OP_RANGE: + case OP_AREF: + case OP_GETUPVAR: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0)); + return 0; + } + break; + case OP_LOADSYM: + case OP_GETGLOBAL: + case OP_GETIV: + case OP_GETCV: + case OP_GETCONST: + case OP_GETSPECIAL: + case OP_LOADL: + case OP_STRING: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0)); + return 0; + } + break; + case OP_SCLASS: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0)); + return 0; + } + break; + case OP_LOADNIL: + case OP_LOADSELF: + case OP_LOADT: + case OP_LOADF: + case OP_OCLASS: + if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i)); + return 0; + } + break; + default: + break; + } + break; + case OP_SETIV: + case OP_SETCV: + case OP_SETCONST: + case OP_SETMCNST: + case OP_SETGLOBAL: + if (val) break; + if (c0 == OP_MOVE) { + if (GETARG_A(i) == GETARG_A(i0)) { + s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i)); + return 0; + } + } + break; + case OP_SETUPVAR: + if (val) break; + if (c0 == OP_MOVE) { + if (GETARG_A(i) == GETARG_A(i0)) { + s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i)); + return 0; + } + } + break; + case OP_EPOP: + if (c0 == OP_EPOP) { + s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i)); + return 0; + } + break; + case OP_POPERR: + if (c0 == OP_POPERR) { + s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i)); + return 0; + } + break; + case OP_RETURN: + switch (c0) { + case OP_RETURN: + return 0; + case OP_MOVE: + if (GETARG_A(i0) >= s->nlocals) { + s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL); + return 0; + } + break; + case OP_SETIV: + case OP_SETCV: + case OP_SETCONST: + case OP_SETMCNST: + case OP_SETUPVAR: + case OP_SETGLOBAL: + s->pc--; + genop_peep(s, i0, NOVAL); + i0 = s->iseq[s->pc-1]; + return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL)); +#if 0 + case OP_SEND: + if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) { + s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0)); + return; + } + break; +#endif + default: + break; + } + break; + case OP_ADD: + case OP_SUB: + if (c0 == OP_LOADI) { + int c = GETARG_sBx(i0); + + if (c1 == OP_SUB) c = -c; + if (c > 127 || c < -127) break; + if (0 <= c) + s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c); + else + s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c); + return 0; + } + case OP_STRCAT: + if (c0 == OP_STRING) { + mrb_value v = s->irep->pool[GETARG_Bx(i0)]; + + if (mrb_string_p(v) && RSTRING_LEN(v) == 0) { + s->pc--; + return 0; + } + } + if (c0 == OP_LOADNIL) { + if (GETARG_B(i) == GETARG_A(i0)) { + s->pc--; + return 0; + } + } + break; + case OP_JMPIF: + case OP_JMPNOT: + if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) { + s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i)); + return s->pc-1; + } + break; + default: + break; + } + } + return genop(s, i); +} + +static void +scope_error(codegen_scope *s) +{ + exit(EXIT_FAILURE); +} + +static inline void +dispatch(codegen_scope *s, int pc) +{ + int diff = s->pc - pc; + mrb_code i = s->iseq[pc]; + int c = GET_OPCODE(i); + + s->lastlabel = s->pc; + switch (c) { + case OP_JMP: + case OP_JMPIF: + case OP_JMPNOT: + case OP_ONERR: + break; + default: +#ifndef MRB_DISABLE_STDIO + fprintf(stderr, "bug: dispatch on non JMP op\n"); +#endif + scope_error(s); + break; + } + if (diff > MAXARG_sBx) { + codegen_error(s, "too distant jump address"); + } + s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff); +} + +static void +dispatch_linked(codegen_scope *s, int pc) +{ + mrb_code i; + int pos; + + if (!pc) return; + for (;;) { + i = s->iseq[pc]; + pos = GETARG_sBx(i); + dispatch(s, pc); + if (!pos) break; + pc = pos; + } +} + +#define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0) +static void +push_(codegen_scope *s) +{ + if (s->sp > 511) { + codegen_error(s, "too complex expression"); + } + s->sp++; + nregs_update; +} + +static void +push_n_(codegen_scope *s, int n) +{ + if (s->sp+n > 511) { + codegen_error(s, "too complex expression"); + } + s->sp+=n; + nregs_update; +} + +#define push() push_(s) +#define push_n(n) push_n_(s,n) +#define pop_(s) ((s)->sp--) +#define pop() pop_(s) +#define pop_n(n) (s->sp-=(n)) +#define cursp() (s->sp) + +static inline int +new_lit(codegen_scope *s, mrb_value val) +{ + int i; + mrb_value *pv; + + switch (mrb_type(val)) { + case MRB_TT_STRING: + for (i=0; i<s->irep->plen; i++) { + mrb_int len; + pv = &s->irep->pool[i]; + + if (mrb_type(*pv) != MRB_TT_STRING) continue; + if ((len = RSTRING_LEN(*pv)) != RSTRING_LEN(val)) continue; + if (memcmp(RSTRING_PTR(*pv), RSTRING_PTR(val), len) == 0) + return i; + } + break; + case MRB_TT_FLOAT: + for (i=0; i<s->irep->plen; i++) { + pv = &s->irep->pool[i]; + if (mrb_type(*pv) != MRB_TT_FLOAT) continue; + if (mrb_float(*pv) == mrb_float(val)) return i; + } + break; + case MRB_TT_FIXNUM: + for (i=0; i<s->irep->plen; i++) { + pv = &s->irep->pool[i]; + if (!mrb_fixnum_p(*pv)) continue; + if (mrb_fixnum(*pv) == mrb_fixnum(val)) return i; + } + break; + default: + /* should not happen */ + return 0; + } + + if (s->irep->plen == s->pcapa) { + s->pcapa *= 2; + s->irep->pool = (mrb_value *)codegen_realloc(s, s->irep->pool, sizeof(mrb_value)*s->pcapa); + } + + pv = &s->irep->pool[s->irep->plen]; + i = s->irep->plen++; + + switch (mrb_type(val)) { + case MRB_TT_STRING: + *pv = mrb_str_pool(s->mrb, val); + break; + + case MRB_TT_FLOAT: +#ifdef MRB_WORD_BOXING + *pv = mrb_float_pool(s->mrb, mrb_float(val)); + break; +#endif + case MRB_TT_FIXNUM: + *pv = val; + break; + + default: + /* should not happen */ + break; + } + return i; +} + +/* method symbols should be fit in 9 bits */ +#define MAXMSYMLEN 512 +/* maximum symbol numbers */ +#define MAXSYMLEN 65536 + +static int +new_msym(codegen_scope *s, mrb_sym sym) +{ + int i, len; + + mrb_assert(s->irep); + + len = s->irep->slen; + if (len > MAXMSYMLEN) len = MAXMSYMLEN; + for (i=0; i<len; i++) { + if (s->irep->syms[i] == sym) return i; + if (s->irep->syms[i] == 0) break; + } + if (i == MAXMSYMLEN) { + codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXMSYMLEN) ")"); + } + s->irep->syms[i] = sym; + if (i == s->irep->slen) s->irep->slen++; + return i; +} + +static int +new_sym(codegen_scope *s, mrb_sym sym) +{ + int i; + + for (i=0; i<s->irep->slen; i++) { + if (s->irep->syms[i] == sym) return i; + } + if (s->irep->slen == MAXSYMLEN) { + codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXSYMLEN) ")"); + } + + if (s->irep->slen > MAXMSYMLEN/2 && s->scapa == MAXMSYMLEN) { + s->scapa = MAXSYMLEN; + s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*MAXSYMLEN); + for (i = s->irep->slen; i < MAXMSYMLEN; i++) { + static const mrb_sym mrb_sym_zero = { 0 }; + s->irep->syms[i] = mrb_sym_zero; + } + s->irep->slen = MAXMSYMLEN; + } + s->irep->syms[s->irep->slen] = sym; + return s->irep->slen++; +} + +static int +node_len(node *tree) +{ + int n = 0; + + while (tree) { + n++; + tree = tree->cdr; + } + return n; +} + +#define nsym(x) ((mrb_sym)(intptr_t)(x)) +#define lv_name(lv) nsym((lv)->car) +static int +lv_idx(codegen_scope *s, mrb_sym id) +{ + node *lv = s->lv; + int n = 1; + + while (lv) { + if (lv_name(lv) == id) return n; + n++; + lv = lv->cdr; + } + return 0; +} + +static void +for_body(codegen_scope *s, node *tree) +{ + codegen_scope *prev = s; + int idx; + struct loopinfo *lp; + node *n2; + mrb_code c; + + /* generate receiver */ + codegen(s, tree->cdr->car, VAL); + /* generate loop-block */ + s = scope_new(s->mrb, s, NULL); + if (s == NULL) { + raise_error(prev, "unexpected scope"); + } + + push(); /* push for a block parameter */ + + /* generate loop variable */ + n2 = tree->car; + genop(s, MKOP_Ax(OP_ENTER, 0x40000)); + if (n2->car && !n2->car->cdr && !n2->cdr) { + gen_assignment(s, n2->car->car, 1, NOVAL); + } + else { + gen_vmassignment(s, n2, 1, VAL); + } + /* construct loop */ + lp = loop_push(s, LOOP_FOR); + lp->pc2 = new_label(s); + + /* loop body */ + codegen(s, tree->cdr->cdr->car, VAL); + pop(); + if (s->pc > 0) { + c = s->iseq[s->pc-1]; + if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) + genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + } + loop_pop(s, NOVAL); + scope_finish(s); + s = prev; + genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK)); + push();pop(); /* space for a block */ + pop(); + idx = new_msym(s, mrb_intern_lit(s->mrb, "each")); + genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0)); +} + +static int +lambda_body(codegen_scope *s, node *tree, int blk) +{ + mrb_code c; + codegen_scope *parent = s; + s = scope_new(s->mrb, s, tree->car); + if (s == NULL) { + raise_error(parent, "unexpected scope"); + } + + s->mscope = !blk; + + if (blk) { + struct loopinfo *lp = loop_push(s, LOOP_BLOCK); + lp->pc1 = new_label(s); + } + tree = tree->cdr; + if (tree->car) { + mrb_aspec a; + int ma, oa, ra, pa, ka, kd, ba; + int pos, i; + node *n, *opt; + + ma = node_len(tree->car->car); + n = tree->car->car; + while (n) { + n = n->cdr; + } + oa = node_len(tree->car->cdr->car); + ra = tree->car->cdr->cdr->car ? 1 : 0; + pa = node_len(tree->car->cdr->cdr->cdr->car); + ka = kd = 0; + ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0; + + if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) { + codegen_error(s, "too many formal arguments"); + } + a = ((mrb_aspec)(ma & 0x1f) << 18) + | ((mrb_aspec)(oa & 0x1f) << 13) + | ((ra & 1) << 12) + | ((pa & 0x1f) << 7) + | ((ka & 0x1f) << 2) + | ((kd & 1)<< 1) + | (ba & 1); + s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */ + | ((ra & 1) << 5) + | (pa & 0x1f); + genop(s, MKOP_Ax(OP_ENTER, a)); + pos = new_label(s); + for (i=0; i<oa; i++) { + new_label(s); + genop(s, MKOP_sBx(OP_JMP, 0)); + } + if (oa > 0) { + genop(s, MKOP_sBx(OP_JMP, 0)); + } + opt = tree->car->cdr->car; + i = 0; + while (opt) { + int idx; + + dispatch(s, pos+i); + codegen(s, opt->car->cdr, VAL); + idx = lv_idx(s, nsym(opt->car->car)); + pop(); + genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL); + i++; + opt = opt->cdr; + } + if (oa > 0) { + dispatch(s, pos+i); + } + } + codegen(s, tree->cdr->car, VAL); + pop(); + if (s->pc > 0) { + c = s->iseq[s->pc-1]; + if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) { + if (s->nregs == 0) { + genop(s, MKOP_A(OP_LOADNIL, 0)); + genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); + } + else { + genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + } + } + } + if (blk) { + loop_pop(s, NOVAL); + } + scope_finish(s); + return parent->irep->rlen - 1; +} + +static int +scope_body(codegen_scope *s, node *tree, int val) +{ + codegen_scope *scope = scope_new(s->mrb, s, tree->car); + if (scope == NULL) { + raise_error(s, "unexpected scope"); + } + + codegen(scope, tree->cdr, VAL); + if (!s->iseq) { + genop(scope, MKOP_A(OP_STOP, 0)); + } + else if (!val) { + genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); + } + else { + if (scope->nregs == 0) { + genop(scope, MKOP_A(OP_LOADNIL, 0)); + genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); + } + else { + genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL); + } + } + scope_finish(scope); + if (!s->irep) { + /* should not happen */ + return 0; + } + return s->irep->rlen - 1; +} + +#define nint(x) ((int)(intptr_t)(x)) +#define nchar(x) ((char)(intptr_t)(x)) + +static mrb_bool +nosplat(node *t) +{ + while (t) { + if (nint(t->car->car) == NODE_SPLAT) return FALSE; + t = t->cdr; + } + return TRUE; +} + +static mrb_sym +attrsym(codegen_scope *s, mrb_sym a) +{ + const char *name; + mrb_int len; + char *name2; + + name = mrb_sym2name_len(s->mrb, a, &len); + name2 = (char *)codegen_palloc(s, + (size_t)len + + 1 /* '=' */ + + 1 /* '\0' */ + ); + mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); + memcpy(name2, name, (size_t)len); + name2[len] = '='; + name2[len+1] = '\0'; + + return mrb_intern(s->mrb, name2, len+1); +} + +#define CALL_MAXARGS 127 + +static int +gen_values(codegen_scope *s, node *t, int val, int extra) +{ + int n = 0; + int is_splat; + + while (t) { + is_splat = nint(t->car->car) == NODE_SPLAT; /* splat mode */ + if ( + n+extra >= CALL_MAXARGS - 1 /* need to subtract one because vm.c expects an array if n == CALL_MAXARGS */ + || is_splat) { + if (val) { + if (is_splat && n == 0 && nint(t->car->cdr->car) == NODE_ARRAY) { + codegen(s, t->car->cdr, VAL); + pop(); + } + else { + pop_n(n); + genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); + push(); + codegen(s, t->car, VAL); + pop(); pop(); + if (is_splat) { + genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); + } + else { + genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + } + } + t = t->cdr; + while (t) { + push(); + codegen(s, t->car, VAL); + pop(); pop(); + if (nint(t->car->car) == NODE_SPLAT) { + genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); + } + else { + genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + } + t = t->cdr; + } + } + else { + while (t) { + codegen(s, t->car, NOVAL); + t = t->cdr; + } + } + return -1; + } + /* normal (no splat) mode */ + codegen(s, t->car, val); + n++; + t = t->cdr; + } + return n; +} + +static void +gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) +{ + mrb_sym sym = name ? name : nsym(tree->cdr->car); + int idx, skip = 0; + int n = 0, noop = 0, sendv = 0, blk = 0; + + codegen(s, tree->car, VAL); /* receiver */ + if (safe) { + int recv = cursp()-1; + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + genop(s, MKOP_AB(OP_MOVE, cursp(), recv)); + push_n(2); pop_n(2); /* space for one arg and a block */ + pop(); + idx = new_msym(s, mrb_intern_lit(s->mrb, "==")); + genop(s, MKOP_ABC(OP_EQ, cursp(), idx, 1)); + skip = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); + } + idx = new_msym(s, sym); + tree = tree->cdr->cdr->car; + if (tree) { + n = gen_values(s, tree->car, VAL, sp?1:0); + if (n < 0) { + n = noop = sendv = 1; + push(); + } + } + if (sp) { + if (sendv) { + pop(); + genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp)); + push(); + } + else { + genop(s, MKOP_AB(OP_MOVE, cursp(), sp)); + push(); + n++; + } + } + if (tree && tree->cdr) { + noop = 1; + codegen(s, tree->cdr, VAL); + pop(); + } + else { + blk = cursp(); + } + push();pop(); + pop_n(n+1); + { + mrb_int symlen; + const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen); + + if (!noop && symlen == 1 && symname[0] == '+' && n == 1) { + genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val); + } + else if (!noop && symlen == 1 && symname[0] == '-' && n == 1) { + genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val); + } + else if (!noop && symlen == 1 && symname[0] == '*' && n == 1) { + genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n)); + } + else if (!noop && symlen == 1 && symname[0] == '/' && n == 1) { + genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n)); + } + else if (!noop && symlen == 1 && symname[0] == '<' && n == 1) { + genop(s, MKOP_ABC(OP_LT, cursp(), idx, n)); + } + else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1) { + genop(s, MKOP_ABC(OP_LE, cursp(), idx, n)); + } + else if (!noop && symlen == 1 && symname[0] == '>' && n == 1) { + genop(s, MKOP_ABC(OP_GT, cursp(), idx, n)); + } + else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1) { + genop(s, MKOP_ABC(OP_GE, cursp(), idx, n)); + } + else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1) { + genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n)); + } + else { + if (sendv) n = CALL_MAXARGS; + if (blk > 0) { /* no block */ + genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n)); + } + else { + genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n)); + } + } + } + if (safe) { + dispatch(s, skip); + } + if (val) { + push(); + } +} + +static void +gen_assignment(codegen_scope *s, node *tree, int sp, int val) +{ + int idx; + int type = nint(tree->car); + + tree = tree->cdr; + switch (type) { + case NODE_GVAR: + idx = new_sym(s, nsym(tree)); + genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val); + break; + case NODE_LVAR: + idx = lv_idx(s, nsym(tree)); + if (idx > 0) { + if (idx != sp) { + genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val); + } + break; + } + else { /* upvar */ + int lv = 0; + codegen_scope *up = s->prev; + + while (up) { + idx = lv_idx(up, nsym(tree)); + if (idx > 0) { + genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val); + break; + } + lv++; + up = up->prev; + } + } + break; + case NODE_IVAR: + idx = new_sym(s, nsym(tree)); + genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val); + break; + case NODE_CVAR: + idx = new_sym(s, nsym(tree)); + genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val); + break; + case NODE_CONST: + idx = new_sym(s, nsym(tree)); + genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val); + break; + case NODE_COLON2: + idx = new_sym(s, nsym(tree->cdr)); + genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL); + push(); + codegen(s, tree->car, VAL); + pop_n(2); + genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val); + break; + + case NODE_CALL: + case NODE_SCALL: + push(); + gen_call(s, tree, attrsym(s, nsym(tree->cdr->car)), sp, NOVAL, + type == NODE_SCALL); + pop(); + if (val) { + genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val); + } + break; + + case NODE_MASGN: + gen_vmassignment(s, tree->car, sp, val); + break; + + /* splat without assignment */ + case NODE_NIL: + break; + + default: +#ifndef MRB_DISABLE_STDIO + fprintf(stderr, "unknown lhs %d\n", type); +#endif + break; + } + if (val) push(); +} + +static void +gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) +{ + int n = 0, post = 0; + node *t, *p; + + if (tree->car) { /* pre */ + t = tree->car; + n = 0; + while (t) { + genop(s, MKOP_ABC(OP_AREF, cursp(), rhs, n)); + gen_assignment(s, t->car, cursp(), NOVAL); + n++; + t = t->cdr; + } + } + t = tree->cdr; + if (t) { + if (t->cdr) { /* post count */ + p = t->cdr->car; + while (p) { + post++; + p = p->cdr; + } + } + if (val) { + genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); + } + else { + pop(); + } + push_n(post); + pop_n(post); + genop(s, MKOP_ABC(OP_APOST, cursp(), n, post)); + n = 1; + if (t->car) { /* rest */ + gen_assignment(s, t->car, cursp(), NOVAL); + } + if (t->cdr && t->cdr->car) { + t = t->cdr->car; + while (t) { + gen_assignment(s, t->car, cursp()+n, NOVAL); + t = t->cdr; + n++; + } + } + if (!val) { + push(); + } + } +} + +static void +gen_send_intern(codegen_scope *s) +{ + push();pop(); /* space for a block */ + pop(); + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0)); + push(); +} +static void +gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) +{ + if (val) { + int i = 0, j = 0; + + while (tree) { + switch (nint(tree->car->car)) { + case NODE_STR: + if ((tree->cdr == NULL) && (nint(tree->car->cdr->cdr) == 0)) + break; + /* fall through */ + case NODE_BEGIN: + codegen(s, tree->car, VAL); + ++j; + break; + + case NODE_LITERAL_DELIM: + if (j > 0) { + j = 0; + ++i; + if (sym) + gen_send_intern(s); + } + break; + } + if (j >= 2) { + pop(); pop(); + genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + push(); + j = 1; + } + tree = tree->cdr; + } + if (j > 0) { + ++i; + if (sym) + gen_send_intern(s); + } + pop_n(i); + genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i)); + push(); + } + else { + while (tree) { + switch (nint(tree->car->car)) { + case NODE_BEGIN: case NODE_BLOCK: + codegen(s, tree->car, NOVAL); + } + tree = tree->cdr; + } + } +} + +static void +raise_error(codegen_scope *s, const char *msg) +{ + int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg)); + + genop(s, MKOP_ABx(OP_ERR, 1, idx)); +} + +static double +readint_float(codegen_scope *s, const char *p, int base) +{ + const char *e = p + strlen(p); + double f = 0; + int n; + + if (*p == '+') p++; + while (p < e) { + char c = *p; + c = tolower((unsigned char)c); + for (n=0; n<base; n++) { + if (mrb_digitmap[n] == c) { + f *= base; + f += n; + break; + } + } + if (n == base) { + codegen_error(s, "malformed readint input"); + } + p++; + } + return f; +} + +static mrb_int +readint_mrb_int(codegen_scope *s, const char *p, int base, mrb_bool neg, mrb_bool *overflow) +{ + const char *e = p + strlen(p); + mrb_int result = 0; + int n; + + mrb_assert(base >= 2 && base <= 36); + if (*p == '+') p++; + while (p < e) { + char c = *p; + c = tolower((unsigned char)c); + for (n=0; n<base; n++) { + if (mrb_digitmap[n] == c) { + break; + } + } + if (n == base) { + codegen_error(s, "malformed readint input"); + } + + if (neg) { + if ((MRB_INT_MIN + n)/base > result) { + *overflow = TRUE; + return 0; + } + result *= base; + result -= n; + } + else { + if ((MRB_INT_MAX - n)/base < result) { + *overflow = TRUE; + return 0; + } + result *= base; + result += n; + } + p++; + } + *overflow = FALSE; + return result; +} + +static void +gen_retval(codegen_scope *s, node *tree) +{ + if (nint(tree->car) == NODE_SPLAT) { + genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), 0)); + push(); + codegen(s, tree, VAL); + pop(); pop(); + genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); + } + else { + codegen(s, tree, VAL); + pop(); + } +} + +static void +codegen(codegen_scope *s, node *tree, int val) +{ + int nt; + int rlev = s->rlev; + + if (!tree) { + if (val) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + return; + } + + s->rlev++; + if (s->rlev > MRB_CODEGEN_LEVEL_MAX) { + codegen_error(s, "too complex expression"); + } + if (s->irep && s->filename_index != tree->filename_index) { + s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); + mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc); + s->debug_start_pos = s->pc; + s->filename_index = tree->filename_index; + s->filename = mrb_parser_get_filename(s->parser, tree->filename_index); + } + + nt = nint(tree->car); + s->lineno = tree->lineno; + tree = tree->cdr; + switch (nt) { + case NODE_BEGIN: + if (val && !tree) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + while (tree) { + codegen(s, tree->car, tree->cdr ? NOVAL : val); + tree = tree->cdr; + } + break; + + case NODE_RESCUE: + { + int onerr, noexc, exend, pos1, pos2, tmp; + struct loopinfo *lp; + + if (tree->car == NULL) goto exit; + onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); + lp = loop_push(s, LOOP_BEGIN); + lp->pc1 = onerr; + codegen(s, tree->car, VAL); + pop(); + lp->type = LOOP_RESCUE; + noexc = genop(s, MKOP_Bx(OP_JMP, 0)); + dispatch(s, onerr); + tree = tree->cdr; + exend = 0; + pos1 = 0; + if (tree->car) { + node *n2 = tree->car; + int exc = cursp(); + + genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0)); + push(); + while (n2) { + node *n3 = n2->car; + node *n4 = n3->car; + + if (pos1) dispatch(s, pos1); + pos2 = 0; + do { + if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) { + codegen(s, n4->car, VAL); + genop(s, MKOP_AB(OP_MOVE, cursp(), exc)); + push_n(2); pop_n(2); /* space for one arg and a block */ + pop(); + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + } + else { + if (n4) { + codegen(s, n4->car, VAL); + } + else { + genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError")))); + push(); + } + pop(); + genop(s, MKOP_ABC(OP_RESCUE, exc, cursp(), 1)); + } + tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); + pos2 = tmp; + if (n4) { + n4 = n4->cdr; + } + } while (n4); + pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); + dispatch_linked(s, pos2); + + pop(); + if (n3->cdr->car) { + gen_assignment(s, n3->cdr->car, exc, NOVAL); + } + if (n3->cdr->cdr->car) { + codegen(s, n3->cdr->cdr->car, val); + if (val) pop(); + } + tmp = genop(s, MKOP_sBx(OP_JMP, exend)); + exend = tmp; + n2 = n2->cdr; + push(); + } + if (pos1) { + dispatch(s, pos1); + genop(s, MKOP_A(OP_RAISE, exc)); + } + } + pop(); + tree = tree->cdr; + dispatch(s, noexc); + genop(s, MKOP_A(OP_POPERR, 1)); + if (tree->car) { + codegen(s, tree->car, val); + } + else if (val) { + push(); + } + dispatch_linked(s, exend); + loop_pop(s, NOVAL); + } + break; + + case NODE_ENSURE: + if (!tree->cdr || !tree->cdr->cdr || + (nint(tree->cdr->cdr->car) == NODE_BEGIN && + tree->cdr->cdr->cdr)) { + int idx; + int epush = s->pc; + + genop(s, MKOP_Bx(OP_EPUSH, 0)); + s->ensure_level++; + codegen(s, tree->car, val); + idx = scope_body(s, tree->cdr, NOVAL); + s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx); + s->ensure_level--; + genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL); + } + else { /* empty ensure ignored */ + codegen(s, tree->car, val); + } + break; + + case NODE_LAMBDA: + if (val) { + int idx = lambda_body(s, tree, 1); + + genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA)); + push(); + } + break; + + case NODE_BLOCK: + if (val) { + int idx = lambda_body(s, tree, 1); + + genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK)); + push(); + } + break; + + case NODE_IF: + { + int pos1, pos2; + node *e = tree->cdr->cdr->car; + + if (!tree->car) { + codegen(s, e, val); + goto exit; + } + switch (nint(tree->car->car)) { + case NODE_TRUE: + case NODE_INT: + case NODE_STR: + codegen(s, tree->cdr->car, val); + goto exit; + case NODE_FALSE: + case NODE_NIL: + codegen(s, e, val); + goto exit; + } + codegen(s, tree->car, VAL); + pop(); + pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL); + + codegen(s, tree->cdr->car, val); + if (e) { + if (val) pop(); + pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); + dispatch(s, pos1); + codegen(s, e, val); + dispatch(s, pos2); + } + else { + if (val) { + pop(); + pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); + dispatch(s, pos1); + genop(s, MKOP_A(OP_LOADNIL, cursp())); + dispatch(s, pos2); + push(); + } + else { + dispatch(s, pos1); + } + } + } + break; + + case NODE_AND: + { + int pos; + + codegen(s, tree->car, VAL); + pop(); + pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0)); + codegen(s, tree->cdr, val); + dispatch(s, pos); + } + break; + + case NODE_OR: + { + int pos; + + codegen(s, tree->car, VAL); + pop(); + pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); + codegen(s, tree->cdr, val); + dispatch(s, pos); + } + break; + + case NODE_WHILE: + { + struct loopinfo *lp = loop_push(s, LOOP_NORMAL); + + lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); + lp->pc2 = new_label(s); + codegen(s, tree->cdr, NOVAL); + dispatch(s, lp->pc1); + codegen(s, tree->car, VAL); + pop(); + genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc)); + + loop_pop(s, val); + } + break; + + case NODE_UNTIL: + { + struct loopinfo *lp = loop_push(s, LOOP_NORMAL); + + lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); + lp->pc2 = new_label(s); + codegen(s, tree->cdr, NOVAL); + dispatch(s, lp->pc1); + codegen(s, tree->car, VAL); + pop(); + genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc)); + + loop_pop(s, val); + } + break; + + case NODE_FOR: + for_body(s, tree); + if (val) push(); + break; + + case NODE_CASE: + { + int head = 0; + int pos1, pos2, pos3, tmp; + node *n; + + pos3 = 0; + if (tree->car) { + head = cursp(); + codegen(s, tree->car, VAL); + } + tree = tree->cdr; + while (tree) { + n = tree->car->car; + pos1 = pos2 = 0; + while (n) { + codegen(s, n->car, VAL); + if (head) { + genop(s, MKOP_AB(OP_MOVE, cursp(), head)); + push_n(2); pop_n(2); /* space for one arg and a block */ + pop(); + if (nint(n->car->car) == NODE_SPLAT) { + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + } + else { + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1)); + } + } + else { + pop(); + } + tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); + pos2 = tmp; + n = n->cdr; + } + if (tree->car->car) { + pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); + dispatch_linked(s, pos2); + } + codegen(s, tree->car->cdr, val); + if (val) pop(); + tmp = genop(s, MKOP_sBx(OP_JMP, pos3)); + pos3 = tmp; + if (pos1) dispatch(s, pos1); + tree = tree->cdr; + } + if (val) { + int pos = cursp(); + genop(s, MKOP_A(OP_LOADNIL, cursp())); + if (pos3) dispatch_linked(s, pos3); + if (head) pop(); + if (cursp() != pos) { + genop(s, MKOP_AB(OP_MOVE, cursp(), pos)); + } + push(); + } + else { + if (pos3) { + dispatch_linked(s, pos3); + } + if (head) { + pop(); + } + } + } + break; + + case NODE_SCOPE: + scope_body(s, tree, NOVAL); + break; + + case NODE_FCALL: + case NODE_CALL: + gen_call(s, tree, 0, 0, val, 0); + break; + case NODE_SCALL: + gen_call(s, tree, 0, 0, val, 1); + break; + + case NODE_DOT2: + codegen(s, tree->car, val); + codegen(s, tree->cdr, val); + if (val) { + pop(); pop(); + genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE)); + push(); + } + break; + + case NODE_DOT3: + codegen(s, tree->car, val); + codegen(s, tree->cdr, val); + if (val) { + pop(); pop(); + genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE)); + push(); + } + break; + + case NODE_COLON2: + { + int sym = new_sym(s, nsym(tree->cdr)); + + codegen(s, tree->car, VAL); + pop(); + genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + if (val) push(); + } + break; + + case NODE_COLON3: + { + int sym = new_sym(s, nsym(tree)); + + genop(s, MKOP_A(OP_OCLASS, cursp())); + genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + if (val) push(); + } + break; + + case NODE_ARRAY: + { + int n; + + n = gen_values(s, tree, val, 0); + if (n >= 0) { + if (val) { + pop_n(n); + genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); + push(); + } + } + else if (val) { + push(); + } + } + break; + + case NODE_HASH: + { + int len = 0; + mrb_bool update = FALSE; + + while (tree) { + codegen(s, tree->car->car, val); + codegen(s, tree->car->cdr, val); + len++; + tree = tree->cdr; + if (val && len == 126) { + pop_n(len*2); + genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); + if (update) { + pop(); + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + } + push(); + update = TRUE; + len = 0; + } + } + if (val) { + pop_n(len*2); + genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); + if (update) { + pop(); + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + } + push(); + } + } + break; + + case NODE_SPLAT: + codegen(s, tree, val); + break; + + case NODE_ASGN: + codegen(s, tree->cdr, VAL); + pop(); + gen_assignment(s, tree->car, cursp(), val); + break; + + case NODE_MASGN: + { + int len = 0, n = 0, post = 0; + node *t = tree->cdr, *p; + int rhs = cursp(); + + if (nint(t->car) == NODE_ARRAY && t->cdr && nosplat(t->cdr)) { + /* fixed rhs */ + t = t->cdr; + while (t) { + codegen(s, t->car, VAL); + len++; + t = t->cdr; + } + tree = tree->car; + if (tree->car) { /* pre */ + t = tree->car; + n = 0; + while (t) { + if (n < len) { + gen_assignment(s, t->car, rhs+n, NOVAL); + n++; + } + else { + genop(s, MKOP_A(OP_LOADNIL, rhs+n)); + gen_assignment(s, t->car, rhs+n, NOVAL); + } + t = t->cdr; + } + } + t = tree->cdr; + if (t) { + if (t->cdr) { /* post count */ + p = t->cdr->car; + while (p) { + post++; + p = p->cdr; + } + } + if (t->car) { /* rest (len - pre - post) */ + int rn; + + if (len < post + n) { + rn = 0; + } + else { + rn = len - post - n; + } + genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn)); + gen_assignment(s, t->car, cursp(), NOVAL); + n += rn; + } + if (t->cdr && t->cdr->car) { + t = t->cdr->car; + while (n<len) { + gen_assignment(s, t->car, rhs+n, NOVAL); + t = t->cdr; + n++; + } + } + } + pop_n(len); + if (val) { + genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len)); + push(); + } + } + else { + /* variable rhs */ + codegen(s, t, VAL); + gen_vmassignment(s, tree->car, rhs, val); + if (!val) { + pop(); + } + } + } + break; + + case NODE_OP_ASGN: + { + mrb_sym sym = nsym(tree->cdr->car); + mrb_int len; + const char *name = mrb_sym2name_len(s->mrb, sym, &len); + int idx, callargs = -1, vsp = -1; + + if ((len == 2 && name[0] == '|' && name[1] == '|') && + (nint(tree->car->car) == NODE_CONST || + nint(tree->car->car) == NODE_CVAR)) { + int onerr, noexc, exc; + struct loopinfo *lp; + + onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); + lp = loop_push(s, LOOP_BEGIN); + lp->pc1 = onerr; + exc = cursp(); + codegen(s, tree->car, VAL); + lp->type = LOOP_RESCUE; + genop(s, MKOP_A(OP_POPERR, 1)); + noexc = genop(s, MKOP_Bx(OP_JMP, 0)); + dispatch(s, onerr); + genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0)); + genop(s, MKOP_A(OP_LOADF, exc)); + dispatch(s, noexc); + loop_pop(s, NOVAL); + } + else if (nint(tree->car->car) == NODE_CALL) { + node *n = tree->car->cdr; + int base, i, nargs = 0; + callargs = 0; + + if (val) { + vsp = cursp(); + push(); + } + codegen(s, n->car, VAL); /* receiver */ + idx = new_msym(s, nsym(n->cdr->car)); + base = cursp()-1; + if (n->cdr->cdr->car) { + nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1); + if (nargs >= 0) { + callargs = nargs; + } + else { /* varargs */ + push(); + nargs = 1; + callargs = CALL_MAXARGS; + } + } + /* copy receiver and arguments */ + genop(s, MKOP_AB(OP_MOVE, cursp(), base)); + for (i=0; i<nargs; i++) { + genop(s, MKOP_AB(OP_MOVE, cursp()+i+1, base+i+1)); + } + push_n(nargs+2);pop_n(nargs+2); /* space for receiver, arguments and a block */ + genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + push(); + } + else { + codegen(s, tree->car, VAL); + } + if (len == 2 && + ((name[0] == '|' && name[1] == '|') || + (name[0] == '&' && name[1] == '&'))) { + int pos; + + pop(); + if (val) { + if (vsp >= 0) { + genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + } + pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0)); + } + else { + pos = genop_peep(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0), NOVAL); + } + codegen(s, tree->cdr->cdr->car, VAL); + pop(); + if (val && vsp >= 0) { + genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + } + if (nint(tree->car->car) == NODE_CALL) { + if (callargs == CALL_MAXARGS) { + pop(); + genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + } + else { + pop_n(callargs); + callargs++; + } + pop(); + idx = new_msym(s, attrsym(s, nsym(tree->car->cdr->cdr->car))); + genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + } + else { + gen_assignment(s, tree->car, cursp(), val); + } + dispatch(s, pos); + goto exit; + } + codegen(s, tree->cdr->cdr->car, VAL); + push(); pop(); + pop(); pop(); + + idx = new_msym(s, sym); + if (len == 1 && name[0] == '+') { + genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val); + } + else if (len == 1 && name[0] == '-') { + genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val); + } + else if (len == 1 && name[0] == '*') { + genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1)); + } + else if (len == 1 && name[0] == '/') { + genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1)); + } + else if (len == 1 && name[0] == '<') { + genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1)); + } + else if (len == 2 && name[0] == '<' && name[1] == '=') { + genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1)); + } + else if (len == 1 && name[0] == '>') { + genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1)); + } + else if (len == 2 && name[0] == '>' && name[1] == '=') { + genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1)); + } + else { + genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1)); + } + if (callargs < 0) { + gen_assignment(s, tree->car, cursp(), val); + } + else { + if (val && vsp >= 0) { + genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + } + if (callargs == CALL_MAXARGS) { + pop(); + genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + } + else { + pop_n(callargs); + callargs++; + } + pop(); + idx = new_msym(s, attrsym(s,nsym(tree->car->cdr->cdr->car))); + genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + } + } + break; + + case NODE_SUPER: + { + codegen_scope *s2 = s; + int lv = 0; + int n = 0, noop = 0, sendv = 0; + + push(); /* room for receiver */ + while (!s2->mscope) { + lv++; + s2 = s2->prev; + if (!s2) break; + } + genop(s, MKOP_ABx(OP_ARGARY, cursp(), (lv & 0xf))); + push(); push(); /* ARGARY pushes two values */ + pop(); pop(); + if (tree) { + node *args = tree->car; + if (args) { + n = gen_values(s, args, VAL, 0); + if (n < 0) { + n = noop = sendv = 1; + push(); + } + } + } + if (tree && tree->cdr) { + codegen(s, tree->cdr, VAL); + pop(); + } + else { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); pop(); + } + pop_n(n+1); + if (sendv) n = CALL_MAXARGS; + genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n)); + if (val) push(); + } + break; + + case NODE_ZSUPER: + { + codegen_scope *s2 = s; + int lv = 0, ainfo = 0; + + push(); /* room for receiver */ + while (!s2->mscope) { + lv++; + s2 = s2->prev; + if (!s2) break; + } + if (s2) ainfo = s2->ainfo; + genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf))); + push(); push(); pop(); /* ARGARY pushes two values */ + if (tree && tree->cdr) { + codegen(s, tree->cdr, VAL); + pop(); + } + pop(); pop(); + genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS)); + if (val) push(); + } + break; + + case NODE_RETURN: + if (tree) { + gen_retval(s, tree); + } + else { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + } + if (s->loop) { + genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN)); + } + else { + genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + } + if (val) push(); + break; + + case NODE_YIELD: + { + codegen_scope *s2 = s; + int lv = 0, ainfo = 0; + int n = 0, sendv = 0; + + while (!s2->mscope) { + lv++; + s2 = s2->prev; + if (!s2) break; + } + if (s2) ainfo = s2->ainfo; + push(); + if (tree) { + n = gen_values(s, tree, VAL, 0); + if (n < 0) { + n = sendv = 1; + push(); + } + } + push();pop(); /* space for a block */ + pop_n(n+1); + genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf))); + if (sendv) n = CALL_MAXARGS; + genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n)); + if (val) push(); + } + break; + + case NODE_BREAK: + loop_break(s, tree); + if (val) push(); + break; + + case NODE_NEXT: + if (!s->loop) { + raise_error(s, "unexpected next"); + } + else if (s->loop->type == LOOP_NORMAL) { + if (s->ensure_level > s->loop->ensure_level) { + genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + } + codegen(s, tree, NOVAL); + genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc)); + } + else { + if (tree) { + codegen(s, tree, VAL); + pop(); + } + else { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + } + genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + } + if (val) push(); + break; + + case NODE_REDO: + if (!s->loop || s->loop->type == LOOP_BEGIN || s->loop->type == LOOP_RESCUE) { + raise_error(s, "unexpected redo"); + } + else { + if (s->ensure_level > s->loop->ensure_level) { + genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + } + genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc)); + } + if (val) push(); + break; + + case NODE_RETRY: + { + const char *msg = "unexpected retry"; + + if (!s->loop) { + raise_error(s, msg); + } + else { + struct loopinfo *lp = s->loop; + int n = 0; + + while (lp && lp->type != LOOP_RESCUE) { + if (lp->type == LOOP_BEGIN) { + n++; + } + lp = lp->prev; + } + if (!lp) { + raise_error(s, msg); + } + else { + if (n > 0) { + genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL); + } + if (s->ensure_level > lp->ensure_level) { + genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL); + } + genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc)); + } + } + if (val) push(); + } + break; + + case NODE_LVAR: + if (val) { + int idx = lv_idx(s, nsym(tree)); + + if (idx > 0) { + genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL); + } + else { + int lv = 0; + codegen_scope *up = s->prev; + + while (up) { + idx = lv_idx(up, nsym(tree)); + if (idx > 0) { + genop(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv)); + break; + } + lv++; + up = up->prev; + } + } + push(); + } + break; + + case NODE_GVAR: + if (val) { + int sym = new_sym(s, nsym(tree)); + + genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + push(); + } + break; + + case NODE_IVAR: + if (val) { + int sym = new_sym(s, nsym(tree)); + + genop(s, MKOP_ABx(OP_GETIV, cursp(), sym)); + push(); + } + break; + + case NODE_CVAR: + if (val) { + int sym = new_sym(s, nsym(tree)); + + genop(s, MKOP_ABx(OP_GETCV, cursp(), sym)); + push(); + } + break; + + case NODE_CONST: + { + int sym = new_sym(s, nsym(tree)); + + genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym)); + if (val) { + push(); + } + } + break; + + case NODE_DEFINED: + codegen(s, tree, VAL); + break; + + case NODE_BACK_REF: + if (val) { + char buf[3]; + int sym; + + buf[0] = '$'; + buf[1] = nchar(tree); + buf[2] = 0; + sym = new_sym(s, mrb_intern_cstr(s->mrb, buf)); + genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + push(); + } + break; + + case NODE_NTH_REF: + if (val) { + mrb_state *mrb = s->mrb; + mrb_value str; + int sym; + + str = mrb_format(mrb, "$%S", mrb_fixnum_value(nint(tree))); + sym = new_sym(s, mrb_intern_str(mrb, str)); + genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + push(); + } + break; + + case NODE_ARG: + /* should not happen */ + break; + + case NODE_BLOCK_ARG: + codegen(s, tree, VAL); + break; + + case NODE_INT: + if (val) { + char *p = (char*)tree->car; + int base = nint(tree->cdr->car); + mrb_int i; + mrb_code co; + mrb_bool overflow; + + i = readint_mrb_int(s, p, base, FALSE, &overflow); + if (overflow) { + double f = readint_float(s, p, base); + int off = new_lit(s, mrb_float_value(s->mrb, f)); + + genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + } + else { + if (i < MAXARG_sBx && i > -MAXARG_sBx) { + co = MKOP_AsBx(OP_LOADI, cursp(), i); + } + else { + int off = new_lit(s, mrb_fixnum_value(i)); + co = MKOP_ABx(OP_LOADL, cursp(), off); + } + genop(s, co); + } + push(); + } + break; + + case NODE_FLOAT: + if (val) { + char *p = (char*)tree; + mrb_float f = mrb_float_read(p, NULL); + int off = new_lit(s, mrb_float_value(s->mrb, f)); + + genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + push(); + } + break; + + case NODE_NEGATE: + { + nt = nint(tree->car); + tree = tree->cdr; + switch (nt) { + case NODE_FLOAT: + if (val) { + char *p = (char*)tree; + mrb_float f = mrb_float_read(p, NULL); + int off = new_lit(s, mrb_float_value(s->mrb, -f)); + + genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + push(); + } + break; + + case NODE_INT: + if (val) { + char *p = (char*)tree->car; + int base = nint(tree->cdr->car); + mrb_int i; + mrb_code co; + mrb_bool overflow; + + i = readint_mrb_int(s, p, base, TRUE, &overflow); + if (overflow) { + double f = readint_float(s, p, base); + int off = new_lit(s, mrb_float_value(s->mrb, -f)); + + genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + } + else { + if (i < MAXARG_sBx && i > -MAXARG_sBx) { + co = MKOP_AsBx(OP_LOADI, cursp(), i); + } + else { + int off = new_lit(s, mrb_fixnum_value(i)); + co = MKOP_ABx(OP_LOADL, cursp(), off); + } + genop(s, co); + } + push(); + } + break; + + default: + if (val) { + int sym = new_msym(s, mrb_intern_lit(s->mrb, "-")); + + genop(s, MKOP_ABx(OP_LOADI, cursp(), 0)); + push(); + codegen(s, tree, VAL); + pop(); pop(); + genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2)); + } + else { + codegen(s, tree, NOVAL); + } + break; + } + } + break; + + case NODE_STR: + if (val) { + char *p = (char*)tree->car; + size_t len = (intptr_t)tree->cdr; + int ai = mrb_gc_arena_save(s->mrb); + int off = new_lit(s, mrb_str_new(s->mrb, p, len)); + + mrb_gc_arena_restore(s->mrb, ai); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + push(); + } + break; + + case NODE_HEREDOC: + tree = ((struct mrb_parser_heredoc_info *)tree)->doc; + /* fall through */ + case NODE_DSTR: + if (val) { + node *n = tree; + + if (!n) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + break; + } + codegen(s, n->car, VAL); + n = n->cdr; + while (n) { + codegen(s, n->car, VAL); + pop(); pop(); + genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + push(); + n = n->cdr; + } + } + else { + node *n = tree; + + while (n) { + if (nint(n->car->car) != NODE_STR) { + codegen(s, n->car, NOVAL); + } + n = n->cdr; + } + } + break; + + case NODE_WORDS: + gen_literal_array(s, tree, FALSE, val); + break; + + case NODE_SYMBOLS: + gen_literal_array(s, tree, TRUE, val); + break; + + case NODE_DXSTR: + { + node *n; + int ai = mrb_gc_arena_save(s->mrb); + int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel")); + + genop(s, MKOP_A(OP_LOADSELF, cursp())); + push(); + codegen(s, tree->car, VAL); + n = tree->cdr; + while (n) { + if (nint(n->car->car) == NODE_XSTR) { + n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR; + mrb_assert(!n->cdr); /* must be the end */ + } + codegen(s, n->car, VAL); + pop(); pop(); + genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + push(); + n = n->cdr; + } + push(); /* for block */ + pop_n(3); + sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); + genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); + if (val) push(); + mrb_gc_arena_restore(s->mrb, ai); + } + break; + + case NODE_XSTR: + { + char *p = (char*)tree->car; + size_t len = (intptr_t)tree->cdr; + int ai = mrb_gc_arena_save(s->mrb); + int off = new_lit(s, mrb_str_new(s->mrb, p, len)); + int sym; + + genop(s, MKOP_A(OP_LOADSELF, cursp())); + push(); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + push(); push(); + pop_n(3); + sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); + genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); + if (val) push(); + mrb_gc_arena_restore(s->mrb, ai); + } + break; + + case NODE_REGX: + if (val) { + char *p1 = (char*)tree->car; + char *p2 = (char*)tree->cdr->car; + char *p3 = (char*)tree->cdr->cdr; + int ai = mrb_gc_arena_save(s->mrb); + int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); + int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1)); + int argc = 1; + + genop(s, MKOP_A(OP_OCLASS, cursp())); + genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + push(); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + push(); + if (p2 || p3) { + if (p2) { /* opt */ + off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + } + else { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + } + push(); + argc++; + if (p3) { /* enc */ + off = new_lit(s, mrb_str_new(s->mrb, p3, 1)); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + push(); + argc++; + } + } + push(); /* space for a block */ + pop_n(argc+2); + sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); + genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); + mrb_gc_arena_restore(s->mrb, ai); + push(); + } + break; + + case NODE_DREGX: + if (val) { + node *n = tree->car; + int ai = mrb_gc_arena_save(s->mrb); + int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS)); + int argc = 1; + int off; + char *p; + + genop(s, MKOP_A(OP_OCLASS, cursp())); + genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + push(); + codegen(s, n->car, VAL); + n = n->cdr; + while (n) { + codegen(s, n->car, VAL); + pop(); pop(); + genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + push(); + n = n->cdr; + } + n = tree->cdr->cdr; + if (n->car) { /* tail */ + p = (char*)n->car; + off = new_lit(s, mrb_str_new_cstr(s->mrb, p)); + codegen(s, tree->car, VAL); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + pop(); + genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + push(); + } + if (n->cdr->car) { /* opt */ + char *p2 = (char*)n->cdr->car; + off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + push(); + argc++; + } + if (n->cdr->cdr) { /* enc */ + char *p2 = (char*)n->cdr->cdr; + off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); + genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + push(); + argc++; + } + push(); /* space for a block */ + pop_n(argc+2); + sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); + genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); + mrb_gc_arena_restore(s->mrb, ai); + push(); + } + else { + node *n = tree->car; + + while (n) { + if (nint(n->car->car) != NODE_STR) { + codegen(s, n->car, NOVAL); + } + n = n->cdr; + } + } + break; + + case NODE_SYM: + if (val) { + int sym = new_sym(s, nsym(tree)); + + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + push(); + } + break; + + case NODE_DSYM: + codegen(s, tree, val); + if (val) { + gen_send_intern(s); + } + break; + + case NODE_SELF: + if (val) { + genop(s, MKOP_A(OP_LOADSELF, cursp())); + push(); + } + break; + + case NODE_NIL: + if (val) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + break; + + case NODE_TRUE: + if (val) { + genop(s, MKOP_A(OP_LOADT, cursp())); + push(); + } + break; + + case NODE_FALSE: + if (val) { + genop(s, MKOP_A(OP_LOADF, cursp())); + push(); + } + break; + + case NODE_ALIAS: + { + int a = new_msym(s, nsym(tree->car)); + int b = new_msym(s, nsym(tree->cdr)); + int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method")); + + genop(s, MKOP_A(OP_TCLASS, cursp())); + push(); + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a)); + push(); + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b)); + push(); + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); /* space for a block */ + pop_n(4); + genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2)); + if (val) { + push(); + } + } + break; + + case NODE_UNDEF: + { + int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method")); + int num = 0; + node *t = tree; + + genop(s, MKOP_A(OP_TCLASS, cursp())); + push(); + while (t) { + int symbol; + if (num >= CALL_MAXARGS - 1) { + pop_n(num); + genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), num)); + while (t) { + symbol = new_msym(s, nsym(t->car)); + push(); + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); + pop(); + genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + t = t->cdr; + } + num = CALL_MAXARGS; + break; + } + symbol = new_msym(s, nsym(t->car)); + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); + push(); + t = t->cdr; + num++; + } + push();pop(); /* space for a block */ + pop(); + if (num < CALL_MAXARGS) { + pop_n(num); + } + genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num)); + if (val) { + push(); + } + } + break; + + case NODE_CLASS: + { + int idx; + + if (tree->car->car == (node*)0) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + else if (tree->car->car == (node*)1) { + genop(s, MKOP_A(OP_OCLASS, cursp())); + push(); + } + else { + codegen(s, tree->car->car, VAL); + } + if (tree->cdr->car) { + codegen(s, tree->cdr->car, VAL); + } + else { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + pop(); pop(); + idx = new_msym(s, nsym(tree->car->cdr)); + genop(s, MKOP_AB(OP_CLASS, cursp(), idx)); + idx = scope_body(s, tree->cdr->cdr->car, val); + genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + if (val) { + push(); + } + } + break; + + case NODE_MODULE: + { + int idx; + + if (tree->car->car == (node*)0) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + push(); + } + else if (tree->car->car == (node*)1) { + genop(s, MKOP_A(OP_OCLASS, cursp())); + push(); + } + else { + codegen(s, tree->car->car, VAL); + } + pop(); + idx = new_msym(s, nsym(tree->car->cdr)); + genop(s, MKOP_AB(OP_MODULE, cursp(), idx)); + idx = scope_body(s, tree->cdr->car, val); + genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + if (val) { + push(); + } + } + break; + + case NODE_SCLASS: + { + int idx; + + codegen(s, tree->car, VAL); + pop(); + genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); + idx = scope_body(s, tree->cdr->car, val); + genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + if (val) { + push(); + } + } + break; + + case NODE_DEF: + { + int sym = new_msym(s, nsym(tree->car)); + int idx = lambda_body(s, tree->cdr, 0); + + genop(s, MKOP_A(OP_TCLASS, cursp())); + push(); + genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); + push(); pop(); + pop(); + genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); + if (val) { + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + push(); + } + } + break; + + case NODE_SDEF: + { + node *recv = tree->car; + int sym = new_msym(s, nsym(tree->cdr->car)); + int idx = lambda_body(s, tree->cdr->cdr, 0); + + codegen(s, recv, VAL); + pop(); + genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); + push(); + genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); + pop(); + genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); + if (val) { + genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + push(); + } + } + break; + + case NODE_POSTEXE: + codegen(s, tree, NOVAL); + break; + + default: + break; + } + exit: + s->rlev = rlev; +} + +static void +scope_add_irep(codegen_scope *s, mrb_irep *irep) +{ + if (s->irep == NULL) { + s->irep = irep; + return; + } + if (s->irep->rlen == s->rcapa) { + s->rcapa *= 2; + s->irep->reps = (mrb_irep**)codegen_realloc(s, s->irep->reps, sizeof(mrb_irep*)*s->rcapa); + } + s->irep->reps[s->irep->rlen] = irep; + s->irep->rlen++; +} + +static codegen_scope* +scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) +{ + static const codegen_scope codegen_scope_zero = { 0 }; + mrb_pool *pool = mrb_pool_open(mrb); + codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope)); + + if (!p) return NULL; + *p = codegen_scope_zero; + p->mrb = mrb; + p->mpool = pool; + if (!prev) return p; + p->prev = prev; + p->ainfo = -1; + p->mscope = 0; + + p->irep = mrb_add_irep(mrb); + scope_add_irep(prev, p->irep); + + p->rcapa = 8; + p->irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*p->rcapa); + + p->icapa = 1024; + p->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*p->icapa); + p->irep->iseq = NULL; + + p->pcapa = 32; + p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa); + p->irep->plen = 0; + + p->scapa = MAXMSYMLEN; + p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa); + p->irep->slen = 0; + + p->lv = lv; + p->sp += node_len(lv)+1; /* add self */ + p->nlocals = p->sp; + if (lv) { + node *n = lv; + size_t i = 0; + + p->irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (p->nlocals - 1)); + for (i=0, n=lv; n; i++,n=n->cdr) { + p->irep->lv[i].name = lv_name(n); + if (lv_name(n)) { + p->irep->lv[i].r = lv_idx(p, lv_name(n)); + } + else { + p->irep->lv[i].r = 0; + } + } + mrb_assert(i + 1 == p->nlocals); + } + p->ai = mrb_gc_arena_save(mrb); + + p->filename = prev->filename; + if (p->filename) { + p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa); + } + p->lineno = prev->lineno; + + /* debug setting */ + p->debug_start_pos = 0; + if (p->filename) { + mrb_debug_info_alloc(mrb, p->irep); + p->irep->filename = p->filename; + p->irep->lines = p->lines; + } + else { + p->irep->debug_info = NULL; + } + p->parser = prev->parser; + p->filename_index = prev->filename_index; + + p->rlev = prev->rlev+1; + + return p; +} + +static void +scope_finish(codegen_scope *s) +{ + mrb_state *mrb = s->mrb; + mrb_irep *irep = s->irep; + size_t fname_len; + char *fname; + + irep->flags = 0; + if (s->iseq) { + irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc); + irep->ilen = s->pc; + if (s->lines) { + irep->lines = (uint16_t *)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->pc); + } + else { + irep->lines = 0; + } + } + irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen); + irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen); + irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen); + if (s->filename) { + irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); + mrb_debug_info_append_file(mrb, irep, s->debug_start_pos, s->pc); + + fname_len = strlen(s->filename); + fname = (char*)codegen_malloc(s, fname_len + 1); + memcpy(fname, s->filename, fname_len); + fname[fname_len] = '\0'; + irep->filename = fname; + irep->own_filename = TRUE; + } + + irep->nlocals = s->nlocals; + irep->nregs = s->nregs; + + mrb_gc_arena_restore(mrb, s->ai); + mrb_pool_close(s->mpool); +} + +static struct loopinfo* +loop_push(codegen_scope *s, enum looptype t) +{ + struct loopinfo *p = (struct loopinfo *)codegen_palloc(s, sizeof(struct loopinfo)); + + p->type = t; + p->pc1 = p->pc2 = p->pc3 = 0; + p->prev = s->loop; + p->ensure_level = s->ensure_level; + p->acc = cursp(); + s->loop = p; + + return p; +} + +static void +loop_break(codegen_scope *s, node *tree) +{ + if (!s->loop) { + codegen(s, tree, NOVAL); + raise_error(s, "unexpected break"); + } + else { + struct loopinfo *loop; + int n = 0; + + if (tree) { + gen_retval(s, tree); + } + + loop = s->loop; + while (loop) { + if (loop->type == LOOP_BEGIN) { + n++; + loop = loop->prev; + } + else if (loop->type == LOOP_RESCUE) { + loop = loop->prev; + } + else{ + break; + } + } + if (!loop) { + raise_error(s, "unexpected break"); + return; + } + if (n > 0) { + genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL); + } + + if (loop->type == LOOP_NORMAL) { + int tmp; + + if (s->ensure_level > s->loop->ensure_level) { + genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + } + if (tree) { + genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL); + } + tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3)); + loop->pc3 = tmp; + } + else { + if (!tree) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + } + genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK)); + } + } +} + +static void +loop_pop(codegen_scope *s, int val) +{ + if (val) { + genop(s, MKOP_A(OP_LOADNIL, cursp())); + } + dispatch_linked(s, s->loop->pc3); + s->loop = s->loop->prev; + if (val) push(); +} + +MRB_API struct RProc* +mrb_generate_code(mrb_state *mrb, parser_state *p) +{ + codegen_scope *scope = scope_new(mrb, 0, 0); + struct RProc *proc; + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + + if (!scope) { + return NULL; + } + scope->mrb = mrb; + scope->parser = p; + scope->filename = p->filename; + scope->filename_index = p->current_filename_index; + + MRB_TRY(&scope->jmp) { + mrb->jmp = &scope->jmp; + /* prepare irep */ + codegen(scope, p->tree, NOVAL); + proc = mrb_proc_new(mrb, scope->irep); + mrb_irep_decref(mrb, scope->irep); + mrb_pool_close(scope->mpool); + proc->c = NULL; + mrb->jmp = prev_jmp; + return proc; + } + MRB_CATCH(&scope->jmp) { + mrb_irep_decref(mrb, scope->irep); + mrb_pool_close(scope->mpool); + mrb->jmp = prev_jmp; + return NULL; + } + MRB_END_EXC(&scope->jmp); +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/keywords b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/keywords new file mode 100644 index 000000000..9cb86608c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/keywords @@ -0,0 +1,50 @@ +%{ +struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; +const struct kwtable *mrb_reserved_word(const char *, unsigned int); +static const struct kwtable *reserved_word(const char *, unsigned int); +#define mrb_reserved_word(str, len) reserved_word(str, len) +%} + +struct kwtable; +%% +__ENCODING__, {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END +__FILE__, {keyword__FILE__, keyword__FILE__}, EXPR_END +__LINE__, {keyword__LINE__, keyword__LINE__}, EXPR_END +BEGIN, {keyword_BEGIN, keyword_BEGIN}, EXPR_END +END, {keyword_END, keyword_END}, EXPR_END +alias, {keyword_alias, keyword_alias}, EXPR_FNAME +and, {keyword_and, keyword_and}, EXPR_VALUE +begin, {keyword_begin, keyword_begin}, EXPR_BEG +break, {keyword_break, keyword_break}, EXPR_MID +case, {keyword_case, keyword_case}, EXPR_VALUE +class, {keyword_class, keyword_class}, EXPR_CLASS +def, {keyword_def, keyword_def}, EXPR_FNAME +do, {keyword_do, keyword_do}, EXPR_BEG +else, {keyword_else, keyword_else}, EXPR_BEG +elsif, {keyword_elsif, keyword_elsif}, EXPR_VALUE +end, {keyword_end, keyword_end}, EXPR_END +ensure, {keyword_ensure, keyword_ensure}, EXPR_BEG +false, {keyword_false, keyword_false}, EXPR_END +for, {keyword_for, keyword_for}, EXPR_VALUE +if, {keyword_if, modifier_if}, EXPR_VALUE +in, {keyword_in, keyword_in}, EXPR_VALUE +module, {keyword_module, keyword_module}, EXPR_VALUE +next, {keyword_next, keyword_next}, EXPR_MID +nil, {keyword_nil, keyword_nil}, EXPR_END +not, {keyword_not, keyword_not}, EXPR_ARG +or, {keyword_or, keyword_or}, EXPR_VALUE +redo, {keyword_redo, keyword_redo}, EXPR_END +rescue, {keyword_rescue, modifier_rescue}, EXPR_MID +retry, {keyword_retry, keyword_retry}, EXPR_END +return, {keyword_return, keyword_return}, EXPR_MID +self, {keyword_self, keyword_self}, EXPR_END +super, {keyword_super, keyword_super}, EXPR_ARG +then, {keyword_then, keyword_then}, EXPR_BEG +true, {keyword_true, keyword_true}, EXPR_END +undef, {keyword_undef, keyword_undef}, EXPR_FNAME +unless, {keyword_unless, modifier_unless}, EXPR_VALUE +until, {keyword_until, modifier_until}, EXPR_VALUE +when, {keyword_when, keyword_when}, EXPR_VALUE +while, {keyword_while, modifier_while}, EXPR_VALUE +yield, {keyword_yield, keyword_yield}, EXPR_ARG +%% diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/lex.def b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/lex.def new file mode 100644 index 000000000..58e302965 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/lex.def @@ -0,0 +1,212 @@ +/* ANSI-C code produced by gperf version 3.0.4 */ +/* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' /home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." +#endif + +#line 1 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + +struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; +const struct kwtable *mrb_reserved_word(const char *, unsigned int); +static const struct kwtable *reserved_word(const char *, unsigned int); +#define mrb_reserved_word(str, len) reserved_word(str, len) +#line 8 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +struct kwtable; + +#define TOTAL_KEYWORDS 40 +#define MIN_WORD_LENGTH 2 +#define MAX_WORD_LENGTH 12 +#define MIN_HASH_VALUE 8 +#define MAX_HASH_VALUE 50 +/* maximum key range = 43, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash (register const char *str, register unsigned int len) +{ + static const unsigned char asso_values[] = + { + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 14, 51, 16, 8, + 11, 13, 51, 51, 51, 51, 10, 51, 13, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 11, 51, 13, 1, 26, + 4, 1, 8, 28, 51, 23, 51, 1, 1, 27, + 5, 19, 21, 51, 8, 3, 3, 11, 51, 21, + 24, 16, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51 + }; + register int hval = len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[2]]; + /*FALLTHROUGH*/ + case 2: + case 1: + hval += asso_values[(unsigned char)str[0]]; + break; + } + return hval + asso_values[(unsigned char)str[len - 1]]; +} + +#ifdef __GNUC__ +__inline +#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ +__attribute__ ((__gnu_inline__)) +#endif +#endif +const struct kwtable * +mrb_reserved_word (register const char *str, register unsigned int len) +{ + static const struct kwtable wordlist[] = + { + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 18 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"break", {keyword_break, keyword_break}, EXPR_MID}, +#line 23 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"else", {keyword_else, keyword_else}, EXPR_BEG}, +#line 33 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"nil", {keyword_nil, keyword_nil}, EXPR_END}, +#line 26 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG}, +#line 25 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"end", {keyword_end, keyword_end}, EXPR_END}, +#line 42 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"then", {keyword_then, keyword_then}, EXPR_BEG}, +#line 34 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"not", {keyword_not, keyword_not}, EXPR_ARG}, +#line 27 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"false", {keyword_false, keyword_false}, EXPR_END}, +#line 40 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"self", {keyword_self, keyword_self}, EXPR_END}, +#line 24 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE}, +#line 37 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID}, +#line 43 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"true", {keyword_true, keyword_true}, EXPR_END}, +#line 46 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"until", {keyword_until, modifier_until}, EXPR_VALUE}, +#line 45 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"unless", {keyword_unless, modifier_unless}, EXPR_VALUE}, +#line 39 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"return", {keyword_return, keyword_return}, EXPR_MID}, +#line 21 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"def", {keyword_def, keyword_def}, EXPR_FNAME}, +#line 16 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"and", {keyword_and, keyword_and}, EXPR_VALUE}, +#line 22 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"do", {keyword_do, keyword_do}, EXPR_BEG}, +#line 49 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"yield", {keyword_yield, keyword_yield}, EXPR_ARG}, +#line 28 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"for", {keyword_for, keyword_for}, EXPR_VALUE}, +#line 44 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"undef", {keyword_undef, keyword_undef}, EXPR_FNAME}, +#line 35 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"or", {keyword_or, keyword_or}, EXPR_VALUE}, +#line 30 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"in", {keyword_in, keyword_in}, EXPR_VALUE}, +#line 47 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"when", {keyword_when, keyword_when}, EXPR_VALUE}, +#line 38 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"retry", {keyword_retry, keyword_retry}, EXPR_END}, +#line 29 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"if", {keyword_if, modifier_if}, EXPR_VALUE}, +#line 19 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"case", {keyword_case, keyword_case}, EXPR_VALUE}, +#line 36 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"redo", {keyword_redo, keyword_redo}, EXPR_END}, +#line 32 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"next", {keyword_next, keyword_next}, EXPR_MID}, +#line 41 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"super", {keyword_super, keyword_super}, EXPR_ARG}, +#line 31 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"module", {keyword_module, keyword_module}, EXPR_VALUE}, +#line 17 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"begin", {keyword_begin, keyword_begin}, EXPR_BEG}, +#line 12 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END}, +#line 11 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END}, +#line 10 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END}, +#line 14 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"END", {keyword_END, keyword_END}, EXPR_END}, +#line 15 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"alias", {keyword_alias, keyword_alias}, EXPR_FNAME}, +#line 13 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END}, + {""}, +#line 20 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"class", {keyword_class, keyword_class}, EXPR_CLASS}, + {""}, {""}, +#line 48 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + {"while", {keyword_while, modifier_while}, EXPR_VALUE} + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register const char *s = wordlist[key].name; + + if (*str == *s && !strcmp (str + 1, s + 1)) + return &wordlist[key]; + } + } + return 0; +} +#line 50 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/node.h b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/node.h new file mode 100644 index 000000000..9636dd759 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/node.h @@ -0,0 +1,118 @@ +/* +** node.h - nodes of abstract syntax tree +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_COMPILER_NODE_H +#define MRUBY_COMPILER_NODE_H + +enum node_type { + NODE_METHOD, + NODE_FBODY, + NODE_CFUNC, + NODE_SCOPE, + NODE_BLOCK, + NODE_IF, + NODE_CASE, + NODE_WHEN, + NODE_OPT_N, + NODE_WHILE, + NODE_UNTIL, + NODE_ITER, + NODE_FOR, + NODE_BREAK, + NODE_NEXT, + NODE_REDO, + NODE_RETRY, + NODE_BEGIN, + NODE_RESCUE, + NODE_ENSURE, + NODE_AND, + NODE_OR, + NODE_NOT, + NODE_MASGN, + NODE_ASGN, + NODE_CDECL, + NODE_CVASGN, + NODE_CVDECL, + NODE_OP_ASGN, + NODE_CALL, + NODE_SCALL, + NODE_FCALL, + NODE_VCALL, + NODE_SUPER, + NODE_ZSUPER, + NODE_ARRAY, + NODE_ZARRAY, + NODE_HASH, + NODE_RETURN, + NODE_YIELD, + NODE_LVAR, + NODE_DVAR, + NODE_GVAR, + NODE_IVAR, + NODE_CONST, + NODE_CVAR, + NODE_NTH_REF, + NODE_BACK_REF, + NODE_MATCH, + NODE_MATCH2, + NODE_MATCH3, + NODE_INT, + NODE_FLOAT, + NODE_NEGATE, + NODE_LAMBDA, + NODE_SYM, + NODE_STR, + NODE_DSTR, + NODE_XSTR, + NODE_DXSTR, + NODE_REGX, + NODE_DREGX, + NODE_DREGX_ONCE, + NODE_LIST, + NODE_ARG, + NODE_ARGSCAT, + NODE_ARGSPUSH, + NODE_SPLAT, + NODE_TO_ARY, + NODE_SVALUE, + NODE_BLOCK_ARG, + NODE_DEF, + NODE_SDEF, + NODE_ALIAS, + NODE_UNDEF, + NODE_CLASS, + NODE_MODULE, + NODE_SCLASS, + NODE_COLON2, + NODE_COLON3, + NODE_CREF, + NODE_DOT2, + NODE_DOT3, + NODE_FLIP2, + NODE_FLIP3, + NODE_ATTRSET, + NODE_SELF, + NODE_NIL, + NODE_TRUE, + NODE_FALSE, + NODE_DEFINED, + NODE_NEWLINE, + NODE_POSTEXE, + NODE_ALLOCA, + NODE_DMETHOD, + NODE_BMETHOD, + NODE_MEMO, + NODE_IFUNC, + NODE_DSYM, + NODE_ATTRASGN, + NODE_HEREDOC, + NODE_LITERAL_DELIM, + NODE_WORDS, + NODE_SYMBOLS, + NODE_LAST +}; + +#endif /* MRUBY_COMPILER_NODE_H */ diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/parse.y b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/parse.y new file mode 100644 index 000000000..0e425b189 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/core/parse.y @@ -0,0 +1,6652 @@ +/* +** parse.y - mruby parser +** +** See Copyright Notice in mruby.h +*/ + +%{ +#undef PARSER_DEBUG +#ifdef PARSER_DEBUG +# define YYDEBUG 1 +#endif +#define YYERROR_VERBOSE 1 +/* + * Force yacc to use our memory management. This is a little evil because + * the macros assume that "parser_state *p" is in scope + */ +#define YYMALLOC(n) mrb_malloc(p->mrb, (n)) +#define YYFREE(o) mrb_free(p->mrb, (o)) +#define YYSTACK_USE_ALLOCA 0 + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <mruby.h> +#include <mruby/compile.h> +#include <mruby/proc.h> +#include <mruby/error.h> +#include <mruby/throw.h> +#include "node.h" + +#define YYLEX_PARAM p + +typedef mrb_ast_node node; +typedef struct mrb_parser_state parser_state; +typedef struct mrb_parser_heredoc_info parser_heredoc_info; + +static int yyparse(parser_state *p); +static int yylex(void *lval, parser_state *p); +static void yyerror(parser_state *p, const char *s); +static void yywarn(parser_state *p, const char *s); +static void yywarning(parser_state *p, const char *s); +static void backref_error(parser_state *p, node *n); +static void void_expr_error(parser_state *p, node *n); +static void tokadd(parser_state *p, int32_t c); + +#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) + +typedef unsigned int stack_type; + +#define BITSTACK_PUSH(stack, n) ((stack) = ((stack)<<1)|((n)&1)) +#define BITSTACK_POP(stack) ((stack) = (stack) >> 1) +#define BITSTACK_LEXPOP(stack) ((stack) = ((stack) >> 1) | ((stack) & 1)) +#define BITSTACK_SET_P(stack) ((stack)&1) + +#define COND_PUSH(n) BITSTACK_PUSH(p->cond_stack, (n)) +#define COND_POP() BITSTACK_POP(p->cond_stack) +#define COND_LEXPOP() BITSTACK_LEXPOP(p->cond_stack) +#define COND_P() BITSTACK_SET_P(p->cond_stack) + +#define CMDARG_PUSH(n) BITSTACK_PUSH(p->cmdarg_stack, (n)) +#define CMDARG_POP() BITSTACK_POP(p->cmdarg_stack) +#define CMDARG_LEXPOP() BITSTACK_LEXPOP(p->cmdarg_stack) +#define CMDARG_P() BITSTACK_SET_P(p->cmdarg_stack) + +#define SET_LINENO(c,n) ((c)->lineno = (n)) +#define NODE_LINENO(c,n) do {\ + if (n) {\ + (c)->filename_index = (n)->filename_index;\ + (c)->lineno = (n)->lineno;\ + }\ +} while (0) + +#define sym(x) ((mrb_sym)(intptr_t)(x)) +#define nsym(x) ((node*)(intptr_t)(x)) +#define nint(x) ((node*)(intptr_t)(x)) +#define intn(x) ((int)(intptr_t)(x)) + +static inline mrb_sym +intern_cstr_gen(parser_state *p, const char *s) +{ + return mrb_intern_cstr(p->mrb, s); +} +#define intern_cstr(s) intern_cstr_gen(p,(s)) + +static inline mrb_sym +intern_gen(parser_state *p, const char *s, size_t len) +{ + return mrb_intern(p->mrb, s, len); +} +#define intern(s,len) intern_gen(p,(s),(len)) + +static inline mrb_sym +intern_gen_c(parser_state *p, const char c) +{ + return mrb_intern(p->mrb, &c, 1); +} +#define intern_c(c) intern_gen_c(p,(c)) + +static void +cons_free_gen(parser_state *p, node *cons) +{ + cons->cdr = p->cells; + p->cells = cons; +} +#define cons_free(c) cons_free_gen(p, (c)) + +static void* +parser_palloc(parser_state *p, size_t size) +{ + void *m = mrb_pool_alloc(p->pool, size); + + if (!m) { + MRB_THROW(p->jmp); + } + return m; +} + +static node* +cons_gen(parser_state *p, node *car, node *cdr) +{ + node *c; + + if (p->cells) { + c = p->cells; + p->cells = p->cells->cdr; + } + else { + c = (node *)parser_palloc(p, sizeof(mrb_ast_node)); + } + + c->car = car; + c->cdr = cdr; + c->lineno = p->lineno; + c->filename_index = p->current_filename_index; + return c; +} +#define cons(a,b) cons_gen(p,(a),(b)) + +static node* +list1_gen(parser_state *p, node *a) +{ + return cons(a, 0); +} +#define list1(a) list1_gen(p, (a)) + +static node* +list2_gen(parser_state *p, node *a, node *b) +{ + return cons(a, cons(b,0)); +} +#define list2(a,b) list2_gen(p, (a),(b)) + +static node* +list3_gen(parser_state *p, node *a, node *b, node *c) +{ + return cons(a, cons(b, cons(c,0))); +} +#define list3(a,b,c) list3_gen(p, (a),(b),(c)) + +static node* +list4_gen(parser_state *p, node *a, node *b, node *c, node *d) +{ + return cons(a, cons(b, cons(c, cons(d, 0)))); +} +#define list4(a,b,c,d) list4_gen(p, (a),(b),(c),(d)) + +static node* +list5_gen(parser_state *p, node *a, node *b, node *c, node *d, node *e) +{ + return cons(a, cons(b, cons(c, cons(d, cons(e, 0))))); +} +#define list5(a,b,c,d,e) list5_gen(p, (a),(b),(c),(d),(e)) + +static node* +list6_gen(parser_state *p, node *a, node *b, node *c, node *d, node *e, node *f) +{ + return cons(a, cons(b, cons(c, cons(d, cons(e, cons(f, 0)))))); +} +#define list6(a,b,c,d,e,f) list6_gen(p, (a),(b),(c),(d),(e),(f)) + +static node* +append_gen(parser_state *p, node *a, node *b) +{ + node *c = a; + + if (!a) return b; + while (c->cdr) { + c = c->cdr; + } + if (b) { + c->cdr = b; + } + return a; +} +#define append(a,b) append_gen(p,(a),(b)) +#define push(a,b) append_gen(p,(a),list1(b)) + +static char* +parser_strndup(parser_state *p, const char *s, size_t len) +{ + char *b = (char *)parser_palloc(p, len+1); + + memcpy(b, s, len); + b[len] = '\0'; + return b; +} +#undef strndup +#define strndup(s,len) parser_strndup(p, s, len) + +static char* +parser_strdup(parser_state *p, const char *s) +{ + return parser_strndup(p, s, strlen(s)); +} +#undef strdup +#define strdup(s) parser_strdup(p, s) + +/* xxx ----------------------------- */ + +static node* +local_switch(parser_state *p) +{ + node *prev = p->locals; + + p->locals = cons(0, 0); + return prev; +} + +static void +local_resume(parser_state *p, node *prev) +{ + p->locals = prev; +} + +static void +local_nest(parser_state *p) +{ + p->locals = cons(0, p->locals); +} + +static void +local_unnest(parser_state *p) +{ + if (p->locals) { + p->locals = p->locals->cdr; + } +} + +static mrb_bool +local_var_p(parser_state *p, mrb_sym sym) +{ + node *l = p->locals; + + while (l) { + node *n = l->car; + while (n) { + if (sym(n->car) == sym) return TRUE; + n = n->cdr; + } + l = l->cdr; + } + return FALSE; +} + +static void +local_add_f(parser_state *p, mrb_sym sym) +{ + if (p->locals) { + p->locals->car = push(p->locals->car, nsym(sym)); + } +} + +static void +local_add(parser_state *p, mrb_sym sym) +{ + if (!local_var_p(p, sym)) { + local_add_f(p, sym); + } +} + +static node* +locals_node(parser_state *p) +{ + return p->locals ? p->locals->car : NULL; +} + +/* (:scope (vars..) (prog...)) */ +static node* +new_scope(parser_state *p, node *body) +{ + return cons((node*)NODE_SCOPE, cons(locals_node(p), body)); +} + +/* (:begin prog...) */ +static node* +new_begin(parser_state *p, node *body) +{ + if (body) { + return list2((node*)NODE_BEGIN, body); + } + return cons((node*)NODE_BEGIN, 0); +} + +#define newline_node(n) (n) + +/* (:rescue body rescue else) */ +static node* +new_rescue(parser_state *p, node *body, node *resq, node *els) +{ + return list4((node*)NODE_RESCUE, body, resq, els); +} + +static node* +new_mod_rescue(parser_state *p, node *body, node *resq) +{ + return new_rescue(p, body, list1(list3(0, 0, resq)), 0); +} + +/* (:ensure body ensure) */ +static node* +new_ensure(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_ENSURE, cons(a, cons(0, b))); +} + +/* (:nil) */ +static node* +new_nil(parser_state *p) +{ + return list1((node*)NODE_NIL); +} + +/* (:true) */ +static node* +new_true(parser_state *p) +{ + return list1((node*)NODE_TRUE); +} + +/* (:false) */ +static node* +new_false(parser_state *p) +{ + return list1((node*)NODE_FALSE); +} + +/* (:alias new old) */ +static node* +new_alias(parser_state *p, mrb_sym a, mrb_sym b) +{ + return cons((node*)NODE_ALIAS, cons(nsym(a), nsym(b))); +} + +/* (:if cond then else) */ +static node* +new_if(parser_state *p, node *a, node *b, node *c) +{ + void_expr_error(p, a); + return list4((node*)NODE_IF, a, b, c); +} + +/* (:unless cond then else) */ +static node* +new_unless(parser_state *p, node *a, node *b, node *c) +{ + void_expr_error(p, a); + return list4((node*)NODE_IF, a, c, b); +} + +/* (:while cond body) */ +static node* +new_while(parser_state *p, node *a, node *b) +{ + void_expr_error(p, a); + return cons((node*)NODE_WHILE, cons(a, b)); +} + +/* (:until cond body) */ +static node* +new_until(parser_state *p, node *a, node *b) +{ + void_expr_error(p, a); + return cons((node*)NODE_UNTIL, cons(a, b)); +} + +/* (:for var obj body) */ +static node* +new_for(parser_state *p, node *v, node *o, node *b) +{ + void_expr_error(p, o); + return list4((node*)NODE_FOR, v, o, b); +} + +/* (:case a ((when ...) body) ((when...) body)) */ +static node* +new_case(parser_state *p, node *a, node *b) +{ + node *n = list2((node*)NODE_CASE, a); + node *n2 = n; + + void_expr_error(p, a); + while (n2->cdr) { + n2 = n2->cdr; + } + n2->cdr = b; + return n; +} + +/* (:postexe a) */ +static node* +new_postexe(parser_state *p, node *a) +{ + return cons((node*)NODE_POSTEXE, a); +} + +/* (:self) */ +static node* +new_self(parser_state *p) +{ + return list1((node*)NODE_SELF); +} + +/* (:call a b c) */ +static node* +new_call(parser_state *p, node *a, mrb_sym b, node *c, int pass) +{ + node *n = list4(nint(pass?NODE_CALL:NODE_SCALL), a, nsym(b), c); + void_expr_error(p, a); + NODE_LINENO(n, a); + return n; +} + +/* (:fcall self mid args) */ +static node* +new_fcall(parser_state *p, mrb_sym b, node *c) +{ + node *n = new_self(p); + NODE_LINENO(n, c); + n = list4((node*)NODE_FCALL, n, nsym(b), c); + NODE_LINENO(n, c); + return n; +} + +/* (:super . c) */ +static node* +new_super(parser_state *p, node *c) +{ + return cons((node*)NODE_SUPER, c); +} + +/* (:zsuper) */ +static node* +new_zsuper(parser_state *p) +{ + return list1((node*)NODE_ZSUPER); +} + +/* (:yield . c) */ +static node* +new_yield(parser_state *p, node *c) +{ + if (c) { + if (c->cdr) { + yyerror(p, "both block arg and actual block given"); + } + return cons((node*)NODE_YIELD, c->car); + } + return cons((node*)NODE_YIELD, 0); +} + +/* (:return . c) */ +static node* +new_return(parser_state *p, node *c) +{ + return cons((node*)NODE_RETURN, c); +} + +/* (:break . c) */ +static node* +new_break(parser_state *p, node *c) +{ + return cons((node*)NODE_BREAK, c); +} + +/* (:next . c) */ +static node* +new_next(parser_state *p, node *c) +{ + return cons((node*)NODE_NEXT, c); +} + +/* (:redo) */ +static node* +new_redo(parser_state *p) +{ + return list1((node*)NODE_REDO); +} + +/* (:retry) */ +static node* +new_retry(parser_state *p) +{ + return list1((node*)NODE_RETRY); +} + +/* (:dot2 a b) */ +static node* +new_dot2(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_DOT2, cons(a, b)); +} + +/* (:dot3 a b) */ +static node* +new_dot3(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_DOT3, cons(a, b)); +} + +/* (:colon2 b c) */ +static node* +new_colon2(parser_state *p, node *b, mrb_sym c) +{ + void_expr_error(p, b); + return cons((node*)NODE_COLON2, cons(b, nsym(c))); +} + +/* (:colon3 . c) */ +static node* +new_colon3(parser_state *p, mrb_sym c) +{ + return cons((node*)NODE_COLON3, nsym(c)); +} + +/* (:and a b) */ +static node* +new_and(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_AND, cons(a, b)); +} + +/* (:or a b) */ +static node* +new_or(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_OR, cons(a, b)); +} + +/* (:array a...) */ +static node* +new_array(parser_state *p, node *a) +{ + return cons((node*)NODE_ARRAY, a); +} + +/* (:splat . a) */ +static node* +new_splat(parser_state *p, node *a) +{ + return cons((node*)NODE_SPLAT, a); +} + +/* (:hash (k . v) (k . v)...) */ +static node* +new_hash(parser_state *p, node *a) +{ + return cons((node*)NODE_HASH, a); +} + +/* (:sym . a) */ +static node* +new_sym(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_SYM, nsym(sym)); +} + +static mrb_sym +new_strsym(parser_state *p, node* str) +{ + const char *s = (const char*)str->cdr->car; + size_t len = (size_t)str->cdr->cdr; + + return mrb_intern(p->mrb, s, len); +} + +/* (:lvar . a) */ +static node* +new_lvar(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_LVAR, nsym(sym)); +} + +/* (:gvar . a) */ +static node* +new_gvar(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_GVAR, nsym(sym)); +} + +/* (:ivar . a) */ +static node* +new_ivar(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_IVAR, nsym(sym)); +} + +/* (:cvar . a) */ +static node* +new_cvar(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_CVAR, nsym(sym)); +} + +/* (:const . a) */ +static node* +new_const(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_CONST, nsym(sym)); +} + +/* (:undef a...) */ +static node* +new_undef(parser_state *p, mrb_sym sym) +{ + return list2((node*)NODE_UNDEF, nsym(sym)); +} + +/* (:class class super body) */ +static node* +new_class(parser_state *p, node *c, node *s, node *b) +{ + void_expr_error(p, s); + return list4((node*)NODE_CLASS, c, s, cons(locals_node(p), b)); +} + +/* (:sclass obj body) */ +static node* +new_sclass(parser_state *p, node *o, node *b) +{ + void_expr_error(p, o); + return list3((node*)NODE_SCLASS, o, cons(locals_node(p), b)); +} + +/* (:module module body) */ +static node* +new_module(parser_state *p, node *m, node *b) +{ + return list3((node*)NODE_MODULE, m, cons(locals_node(p), b)); +} + +/* (:def m lv (arg . body)) */ +static node* +new_def(parser_state *p, mrb_sym m, node *a, node *b) +{ + return list5((node*)NODE_DEF, nsym(m), locals_node(p), a, b); +} + +/* (:sdef obj m lv (arg . body)) */ +static node* +new_sdef(parser_state *p, node *o, mrb_sym m, node *a, node *b) +{ + void_expr_error(p, o); + return list6((node*)NODE_SDEF, o, nsym(m), locals_node(p), a, b); +} + +/* (:arg . sym) */ +static node* +new_arg(parser_state *p, mrb_sym sym) +{ + return cons((node*)NODE_ARG, nsym(sym)); +} + +/* (m o r m2 b) */ +/* m: (a b c) */ +/* o: ((a . e1) (b . e2)) */ +/* r: a */ +/* m2: (a b c) */ +/* b: a */ +static node* +new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk) +{ + node *n; + + n = cons(m2, nsym(blk)); + n = cons(nsym(rest), n); + n = cons(opt, n); + return cons(m, n); +} + +/* (:block_arg . a) */ +static node* +new_block_arg(parser_state *p, node *a) +{ + return cons((node*)NODE_BLOCK_ARG, a); +} + +/* (:block arg body) */ +static node* +new_block(parser_state *p, node *a, node *b) +{ + return list4((node*)NODE_BLOCK, locals_node(p), a, b); +} + +/* (:lambda arg body) */ +static node* +new_lambda(parser_state *p, node *a, node *b) +{ + return list4((node*)NODE_LAMBDA, locals_node(p), a, b); +} + +/* (:asgn lhs rhs) */ +static node* +new_asgn(parser_state *p, node *a, node *b) +{ + void_expr_error(p, b); + return cons((node*)NODE_ASGN, cons(a, b)); +} + +/* (:masgn mlhs=(pre rest post) mrhs) */ +static node* +new_masgn(parser_state *p, node *a, node *b) +{ + void_expr_error(p, b); + return cons((node*)NODE_MASGN, cons(a, b)); +} + +/* (:asgn lhs rhs) */ +static node* +new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b) +{ + void_expr_error(p, b); + return list4((node*)NODE_OP_ASGN, a, nsym(op), b); +} + +/* (:int . i) */ +static node* +new_int(parser_state *p, const char *s, int base) +{ + return list3((node*)NODE_INT, (node*)strdup(s), nint(base)); +} + +/* (:float . i) */ +static node* +new_float(parser_state *p, const char *s) +{ + return cons((node*)NODE_FLOAT, (node*)strdup(s)); +} + +/* (:str . (s . len)) */ +static node* +new_str(parser_state *p, const char *s, size_t len) +{ + return cons((node*)NODE_STR, cons((node*)strndup(s, len), nint(len))); +} + +/* (:dstr . a) */ +static node* +new_dstr(parser_state *p, node *a) +{ + return cons((node*)NODE_DSTR, a); +} + +/* (:str . (s . len)) */ +static node* +new_xstr(parser_state *p, const char *s, int len) +{ + return cons((node*)NODE_XSTR, cons((node*)strndup(s, len), nint(len))); +} + +/* (:xstr . a) */ +static node* +new_dxstr(parser_state *p, node *a) +{ + return cons((node*)NODE_DXSTR, a); +} + +/* (:dsym . a) */ +static node* +new_dsym(parser_state *p, node *a) +{ + return cons((node*)NODE_DSYM, new_dstr(p, a)); +} + +/* (:regx . (s . (opt . enc))) */ +static node* +new_regx(parser_state *p, const char *p1, const char* p2, const char* p3) +{ + return cons((node*)NODE_REGX, cons((node*)p1, cons((node*)p2, (node*)p3))); +} + +/* (:dregx . (a . b)) */ +static node* +new_dregx(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_DREGX, cons(a, b)); +} + +/* (:backref . n) */ +static node* +new_back_ref(parser_state *p, int n) +{ + return cons((node*)NODE_BACK_REF, nint(n)); +} + +/* (:nthref . n) */ +static node* +new_nth_ref(parser_state *p, int n) +{ + return cons((node*)NODE_NTH_REF, nint(n)); +} + +/* (:heredoc . a) */ +static node* +new_heredoc(parser_state *p) +{ + parser_heredoc_info *inf = (parser_heredoc_info *)parser_palloc(p, sizeof(parser_heredoc_info)); + return cons((node*)NODE_HEREDOC, (node*)inf); +} + +static void +new_bv(parser_state *p, mrb_sym id) +{ +} + +static node* +new_literal_delim(parser_state *p) +{ + return cons((node*)NODE_LITERAL_DELIM, 0); +} + +/* (:words . a) */ +static node* +new_words(parser_state *p, node *a) +{ + return cons((node*)NODE_WORDS, a); +} + +/* (:symbols . a) */ +static node* +new_symbols(parser_state *p, node *a) +{ + return cons((node*)NODE_SYMBOLS, a); +} + +/* xxx ----------------------------- */ + +/* (:call a op) */ +static node* +call_uni_op(parser_state *p, node *recv, const char *m) +{ + void_expr_error(p, recv); + return new_call(p, recv, intern_cstr(m), 0, 1); +} + +/* (:call a op b) */ +static node* +call_bin_op(parser_state *p, node *recv, const char *m, node *arg1) +{ + return new_call(p, recv, intern_cstr(m), list1(list1(arg1)), 1); +} + +static void +args_with_block(parser_state *p, node *a, node *b) +{ + if (b) { + if (a->cdr) { + yyerror(p, "both block arg and actual block given"); + } + a->cdr = b; + } +} + +static void +call_with_block(parser_state *p, node *a, node *b) +{ + node *n; + + switch ((enum node_type)intn(a->car)) { + case NODE_SUPER: + case NODE_ZSUPER: + if (!a->cdr) a->cdr = cons(0, b); + else { + args_with_block(p, a->cdr, b); + } + break; + case NODE_CALL: + case NODE_FCALL: + case NODE_SCALL: + n = a->cdr->cdr->cdr; + if (!n->car) n->car = cons(0, b); + else { + args_with_block(p, n->car, b); + } + break; + default: + break; + } +} + +static node* +negate_lit(parser_state *p, node *n) +{ + return cons((node*)NODE_NEGATE, n); +} + +static node* +cond(node *n) +{ + return n; +} + +static node* +ret_args(parser_state *p, node *n) +{ + if (n->cdr) { + yyerror(p, "block argument should not be given"); + return NULL; + } + if (!n->car->cdr) return n->car->car; + return new_array(p, n->car); +} + +static void +assignable(parser_state *p, node *lhs) +{ + if (intn(lhs->car) == NODE_LVAR) { + local_add(p, sym(lhs->cdr)); + } +} + +static node* +var_reference(parser_state *p, node *lhs) +{ + node *n; + + if (intn(lhs->car) == NODE_LVAR) { + if (!local_var_p(p, sym(lhs->cdr))) { + n = new_fcall(p, sym(lhs->cdr), 0); + cons_free(lhs); + return n; + } + } + + return lhs; +} + +typedef enum mrb_string_type string_type; + +static node* +new_strterm(parser_state *p, string_type type, int term, int paren) +{ + return cons(nint(type), cons((node*)0, cons(nint(paren), nint(term)))); +} + +static void +end_strterm(parser_state *p) +{ + cons_free(p->lex_strterm->cdr->cdr); + cons_free(p->lex_strterm->cdr); + cons_free(p->lex_strterm); + p->lex_strterm = NULL; +} + +static parser_heredoc_info * +parsing_heredoc_inf(parser_state *p) +{ + node *nd = p->parsing_heredoc; + if (nd == NULL) + return NULL; + /* mrb_assert(nd->car->car == NODE_HEREDOC); */ + return (parser_heredoc_info*)nd->car->cdr; +} + +static void +heredoc_treat_nextline(parser_state *p) +{ + if (p->heredocs_from_nextline == NULL) + return; + if (p->parsing_heredoc == NULL) { + node *n; + p->parsing_heredoc = p->heredocs_from_nextline; + p->lex_strterm_before_heredoc = p->lex_strterm; + p->lex_strterm = new_strterm(p, parsing_heredoc_inf(p)->type, 0, 0); + n = p->all_heredocs; + if (n) { + while (n->cdr) + n = n->cdr; + n->cdr = p->parsing_heredoc; + } + else { + p->all_heredocs = p->parsing_heredoc; + } + } + else { + node *n, *m; + m = p->heredocs_from_nextline; + while (m->cdr) + m = m->cdr; + n = p->all_heredocs; + mrb_assert(n != NULL); + if (n == p->parsing_heredoc) { + m->cdr = n; + p->all_heredocs = p->heredocs_from_nextline; + p->parsing_heredoc = p->heredocs_from_nextline; + } + else { + while (n->cdr != p->parsing_heredoc) { + n = n->cdr; + mrb_assert(n != NULL); + } + m->cdr = n->cdr; + n->cdr = p->heredocs_from_nextline; + p->parsing_heredoc = p->heredocs_from_nextline; + } + } + p->heredocs_from_nextline = NULL; +} + +static void +heredoc_end(parser_state *p) +{ + p->parsing_heredoc = p->parsing_heredoc->cdr; + if (p->parsing_heredoc == NULL) { + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + end_strterm(p); + p->lex_strterm = p->lex_strterm_before_heredoc; + p->lex_strterm_before_heredoc = NULL; + p->heredoc_end_now = TRUE; + } + else { + /* next heredoc */ + p->lex_strterm->car = nint(parsing_heredoc_inf(p)->type); + } +} +#define is_strterm_type(p,str_func) (intn((p)->lex_strterm->car) & (str_func)) + +/* xxx ----------------------------- */ + +%} + +%pure-parser +%parse-param {parser_state *p} +%lex-param {parser_state *p} + +%union { + node *nd; + mrb_sym id; + int num; + stack_type stack; + const struct vtable *vars; +} + +%token <num> + keyword_class + keyword_module + keyword_def + keyword_begin + keyword_if + keyword_unless + keyword_while + keyword_until + keyword_for + +%token + keyword_undef + keyword_rescue + keyword_ensure + keyword_end + keyword_then + keyword_elsif + keyword_else + keyword_case + keyword_when + keyword_break + keyword_next + keyword_redo + keyword_retry + keyword_in + keyword_do + keyword_do_cond + keyword_do_block + keyword_do_LAMBDA + keyword_return + keyword_yield + keyword_super + keyword_self + keyword_nil + keyword_true + keyword_false + keyword_and + keyword_or + keyword_not + modifier_if + modifier_unless + modifier_while + modifier_until + modifier_rescue + keyword_alias + keyword_BEGIN + keyword_END + keyword__LINE__ + keyword__FILE__ + keyword__ENCODING__ + +%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL +%token <nd> tINTEGER tFLOAT tCHAR tXSTRING tREGEXP +%token <nd> tSTRING tSTRING_PART tSTRING_MID tLABEL_END +%token <nd> tNTH_REF tBACK_REF +%token <num> tREGEXP_END + +%type <nd> singleton string string_rep string_interp xstring regexp +%type <nd> literal numeric cpath symbol +%type <nd> top_compstmt top_stmts top_stmt +%type <nd> bodystmt compstmt stmts stmt expr arg primary command command_call method_call +%type <nd> expr_value arg_rhs primary_value +%type <nd> if_tail opt_else case_body cases opt_rescue exc_list exc_var opt_ensure +%type <nd> args call_args opt_call_args +%type <nd> paren_args opt_paren_args variable +%type <nd> command_args aref_args opt_block_arg block_arg var_ref var_lhs +%type <nd> command_asgn command_rhs mrhs superclass block_call block_command +%type <nd> f_block_optarg f_block_opt +%type <nd> f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs +%type <nd> assoc_list assocs assoc undef_list backref for_var +%type <nd> block_param opt_block_param block_param_def f_opt +%type <nd> bv_decls opt_bv_decl bvar f_larglist lambda_body +%type <nd> brace_block cmd_brace_block do_block lhs none f_bad_arg +%type <nd> mlhs mlhs_list mlhs_post mlhs_basic mlhs_item mlhs_node mlhs_inner +%type <id> fsym sym basic_symbol operation operation2 operation3 +%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_opt_asgn +%type <nd> heredoc words symbols +%type <num> call_op call_op2 /* 0:'&.', 1:'.', 2:'::' */ + +%token tUPLUS /* unary+ */ +%token tUMINUS /* unary- */ +%token tPOW /* ** */ +%token tCMP /* <=> */ +%token tEQ /* == */ +%token tEQQ /* === */ +%token tNEQ /* != */ +%token tGEQ /* >= */ +%token tLEQ /* <= */ +%token tANDOP tOROP /* && and || */ +%token tMATCH tNMATCH /* =~ and !~ */ +%token tDOT2 tDOT3 /* .. and ... */ +%token tAREF tASET /* [] and []= */ +%token tLSHFT tRSHFT /* << and >> */ +%token tCOLON2 /* :: */ +%token tCOLON3 /* :: at EXPR_BEG */ +%token <id> tOP_ASGN /* +=, -= etc. */ +%token tASSOC /* => */ +%token tLPAREN /* ( */ +%token tLPAREN_ARG /* ( */ +%token tRPAREN /* ) */ +%token tLBRACK /* [ */ +%token tLBRACE /* { */ +%token tLBRACE_ARG /* { */ +%token tSTAR /* * */ +%token tAMPER /* & */ +%token tLAMBDA /* -> */ +%token tANDDOT /* &. */ +%token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG +%token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG +%token <nd> tHEREDOC_BEG /* <<, <<- */ +%token tHEREDOC_END tLITERAL_DELIM tHD_LITERAL_DELIM +%token <nd> tHD_STRING_PART tHD_STRING_MID + +/* + * precedence table + */ + +%nonassoc tLOWEST +%nonassoc tLBRACE_ARG + +%nonassoc modifier_if modifier_unless modifier_while modifier_until +%left keyword_or keyword_and +%right keyword_not +%right '=' tOP_ASGN +%left modifier_rescue +%right '?' ':' +%nonassoc tDOT2 tDOT3 +%left tOROP +%left tANDOP +%nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH +%left '>' tGEQ '<' tLEQ +%left '|' '^' +%left '&' +%left tLSHFT tRSHFT +%left '+' '-' +%left '*' '/' '%' +%right tUMINUS_NUM tUMINUS +%right tPOW +%right '!' '~' tUPLUS + +%token tLAST_TOKEN + +%% +program : { + p->lstate = EXPR_BEG; + if (!p->locals) p->locals = cons(0,0); + } + top_compstmt + { + p->tree = new_scope(p, $2); + NODE_LINENO(p->tree, $2); + } + ; + +top_compstmt : top_stmts opt_terms + { + $$ = $1; + } + ; + +top_stmts : none + { + $$ = new_begin(p, 0); + } + | top_stmt + { + $$ = new_begin(p, $1); + NODE_LINENO($$, $1); + } + | top_stmts terms top_stmt + { + $$ = push($1, newline_node($3)); + } + | error top_stmt + { + $$ = new_begin(p, 0); + } + ; + +top_stmt : stmt + | keyword_BEGIN + { + $<nd>$ = local_switch(p); + } + '{' top_compstmt '}' + { + yyerror(p, "BEGIN not supported"); + local_resume(p, $<nd>2); + $$ = 0; + } + ; + +bodystmt : compstmt + opt_rescue + opt_else + opt_ensure + { + if ($2) { + $$ = new_rescue(p, $1, $2, $3); + NODE_LINENO($$, $1); + } + else if ($3) { + yywarn(p, "else without rescue is useless"); + $$ = push($1, $3); + } + else { + $$ = $1; + } + if ($4) { + if ($$) { + $$ = new_ensure(p, $$, $4); + } + else { + $$ = push($4, new_nil(p)); + } + } + } + ; + +compstmt : stmts opt_terms + { + $$ = $1; + } + ; + +stmts : none + { + $$ = new_begin(p, 0); + } + | stmt + { + $$ = new_begin(p, $1); + NODE_LINENO($$, $1); + } + | stmts terms stmt + { + $$ = push($1, newline_node($3)); + } + | error stmt + { + $$ = new_begin(p, $2); + } + ; + +stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym + { + $$ = new_alias(p, $2, $4); + } + | keyword_undef undef_list + { + $$ = $2; + } + | stmt modifier_if expr_value + { + $$ = new_if(p, cond($3), $1, 0); + } + | stmt modifier_unless expr_value + { + $$ = new_unless(p, cond($3), $1, 0); + } + | stmt modifier_while expr_value + { + $$ = new_while(p, cond($3), $1); + } + | stmt modifier_until expr_value + { + $$ = new_until(p, cond($3), $1); + } + | stmt modifier_rescue stmt + { + $$ = new_mod_rescue(p, $1, $3); + } + | keyword_END '{' compstmt '}' + { + yyerror(p, "END not supported"); + $$ = new_postexe(p, $3); + } + | command_asgn + | mlhs '=' command_call + { + $$ = new_masgn(p, $1, $3); + } + | lhs '=' mrhs + { + $$ = new_asgn(p, $1, new_array(p, $3)); + } + | mlhs '=' arg + { + $$ = new_masgn(p, $1, $3); + } + | mlhs '=' mrhs + { + $$ = new_masgn(p, $1, new_array(p, $3)); + } + | expr + ; + +command_asgn : lhs '=' command_rhs + { + $$ = new_asgn(p, $1, $3); + } + | var_lhs tOP_ASGN command_rhs + { + $$ = new_op_asgn(p, $1, $2, $3); + } + | primary_value '[' opt_call_args rbracket tOP_ASGN command_rhs + { + $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3, '.'), $5, $6); + } + | primary_value call_op tIDENTIFIER tOP_ASGN command_rhs + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0, $2), $4, $5); + } + | primary_value call_op tCONSTANT tOP_ASGN command_rhs + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0, $2), $4, $5); + } + | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call + { + yyerror(p, "constant re-assignment"); + $$ = 0; + } + | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_rhs + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0, tCOLON2), $4, $5); + } + | backref tOP_ASGN command_rhs + { + backref_error(p, $1); + $$ = new_begin(p, 0); + } + ; + +command_rhs : command_call %prec tOP_ASGN + | command_call modifier_rescue stmt + { + $$ = new_mod_rescue(p, $1, $3); + } + | command_asgn + ; + + +expr : command_call + | expr keyword_and expr + { + $$ = new_and(p, $1, $3); + } + | expr keyword_or expr + { + $$ = new_or(p, $1, $3); + } + | keyword_not opt_nl expr + { + $$ = call_uni_op(p, cond($3), "!"); + } + | '!' command_call + { + $$ = call_uni_op(p, cond($2), "!"); + } + | arg + ; + +expr_value : expr + { + if (!$1) $$ = new_nil(p); + else { + $$ = $1; + } + } + ; + +command_call : command + | block_command + ; + +block_command : block_call + | block_call call_op2 operation2 command_args + { + $$ = new_call(p, $1, $3, $4, $2); + } + ; + +cmd_brace_block : tLBRACE_ARG + { + local_nest(p); + } + opt_block_param + compstmt + '}' + { + $$ = new_block(p, $3, $4); + local_unnest(p); + } + ; + +command : operation command_args %prec tLOWEST + { + $$ = new_fcall(p, $1, $2); + } + | operation command_args cmd_brace_block + { + args_with_block(p, $2, $3); + $$ = new_fcall(p, $1, $2); + } + | primary_value call_op operation2 command_args %prec tLOWEST + { + $$ = new_call(p, $1, $3, $4, $2); + } + | primary_value call_op operation2 command_args cmd_brace_block + { + args_with_block(p, $4, $5); + $$ = new_call(p, $1, $3, $4, $2); + } + | primary_value tCOLON2 operation2 command_args %prec tLOWEST + { + $$ = new_call(p, $1, $3, $4, tCOLON2); + } + | primary_value tCOLON2 operation2 command_args cmd_brace_block + { + args_with_block(p, $4, $5); + $$ = new_call(p, $1, $3, $4, tCOLON2); + } + | keyword_super command_args + { + $$ = new_super(p, $2); + } + | keyword_yield command_args + { + $$ = new_yield(p, $2); + } + | keyword_return call_args + { + $$ = new_return(p, ret_args(p, $2)); + } + | keyword_break call_args + { + $$ = new_break(p, ret_args(p, $2)); + } + | keyword_next call_args + { + $$ = new_next(p, ret_args(p, $2)); + } + ; + +mlhs : mlhs_basic + { + $$ = $1; + } + | tLPAREN mlhs_inner rparen + { + $$ = $2; + } + ; + +mlhs_inner : mlhs_basic + | tLPAREN mlhs_inner rparen + { + $$ = $2; + } + ; + +mlhs_basic : mlhs_list + { + $$ = list1($1); + } + | mlhs_list mlhs_item + { + $$ = list1(push($1,$2)); + } + | mlhs_list tSTAR mlhs_node + { + $$ = list2($1, $3); + } + | mlhs_list tSTAR mlhs_node ',' mlhs_post + { + $$ = list3($1, $3, $5); + } + | mlhs_list tSTAR + { + $$ = list2($1, new_nil(p)); + } + | mlhs_list tSTAR ',' mlhs_post + { + $$ = list3($1, new_nil(p), $4); + } + | tSTAR mlhs_node + { + $$ = list2(0, $2); + } + | tSTAR mlhs_node ',' mlhs_post + { + $$ = list3(0, $2, $4); + } + | tSTAR + { + $$ = list2(0, new_nil(p)); + } + | tSTAR ',' mlhs_post + { + $$ = list3(0, new_nil(p), $3); + } + ; + +mlhs_item : mlhs_node + | tLPAREN mlhs_inner rparen + { + $$ = new_masgn(p, $2, NULL); + } + ; + +mlhs_list : mlhs_item ',' + { + $$ = list1($1); + } + | mlhs_list mlhs_item ',' + { + $$ = push($1, $2); + } + ; + +mlhs_post : mlhs_item + { + $$ = list1($1); + } + | mlhs_list mlhs_item + { + $$ = push($1, $2); + } + ; + +mlhs_node : variable + { + assignable(p, $1); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3, '.'); + } + | primary_value call_op tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0, $2); + } + | primary_value tCOLON2 tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0, tCOLON2); + } + | primary_value call_op tCONSTANT + { + $$ = new_call(p, $1, $3, 0, $2); + } + | primary_value tCOLON2 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon3(p, $2); + } + | backref + { + backref_error(p, $1); + $$ = 0; + } + ; + +lhs : variable + { + assignable(p, $1); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3, '.'); + } + | primary_value call_op tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0, $2); + } + | primary_value tCOLON2 tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0, tCOLON2); + } + | primary_value call_op tCONSTANT + { + $$ = new_call(p, $1, $3, 0, $2); + } + | primary_value tCOLON2 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon3(p, $2); + } + | backref + { + backref_error(p, $1); + $$ = 0; + } + ; + +cname : tIDENTIFIER + { + yyerror(p, "class/module name must be CONSTANT"); + } + | tCONSTANT + ; + +cpath : tCOLON3 cname + { + $$ = cons((node*)1, nsym($2)); + } + | cname + { + $$ = cons((node*)0, nsym($1)); + } + | primary_value tCOLON2 cname + { + void_expr_error(p, $1); + $$ = cons($1, nsym($3)); + } + ; + +fname : tIDENTIFIER + | tCONSTANT + | tFID + | op + { + p->lstate = EXPR_ENDFN; + $$ = $1; + } + | reswords + { + p->lstate = EXPR_ENDFN; + $$ = $<id>1; + } + ; + +fsym : fname + | basic_symbol + ; + +undef_list : fsym + { + $$ = new_undef(p, $1); + } + | undef_list ',' {p->lstate = EXPR_FNAME;} fsym + { + $$ = push($1, nsym($4)); + } + ; + +op : '|' { $$ = intern_c('|'); } + | '^' { $$ = intern_c('^'); } + | '&' { $$ = intern_c('&'); } + | tCMP { $$ = intern("<=>",3); } + | tEQ { $$ = intern("==",2); } + | tEQQ { $$ = intern("===",3); } + | tMATCH { $$ = intern("=~",2); } + | tNMATCH { $$ = intern("!~",2); } + | '>' { $$ = intern_c('>'); } + | tGEQ { $$ = intern(">=",2); } + | '<' { $$ = intern_c('<'); } + | tLEQ { $$ = intern("<=",2); } + | tNEQ { $$ = intern("!=",2); } + | tLSHFT { $$ = intern("<<",2); } + | tRSHFT { $$ = intern(">>",2); } + | '+' { $$ = intern_c('+'); } + | '-' { $$ = intern_c('-'); } + | '*' { $$ = intern_c('*'); } + | tSTAR { $$ = intern_c('*'); } + | '/' { $$ = intern_c('/'); } + | '%' { $$ = intern_c('%'); } + | tPOW { $$ = intern("**",2); } + | '!' { $$ = intern_c('!'); } + | '~' { $$ = intern_c('~'); } + | tUPLUS { $$ = intern("+@",2); } + | tUMINUS { $$ = intern("-@",2); } + | tAREF { $$ = intern("[]",2); } + | tASET { $$ = intern("[]=",3); } + | '`' { $$ = intern_c('`'); } + ; + +reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__ + | keyword_BEGIN | keyword_END + | keyword_alias | keyword_and | keyword_begin + | keyword_break | keyword_case | keyword_class | keyword_def + | keyword_do | keyword_else | keyword_elsif + | keyword_end | keyword_ensure | keyword_false + | keyword_for | keyword_in | keyword_module | keyword_next + | keyword_nil | keyword_not | keyword_or | keyword_redo + | keyword_rescue | keyword_retry | keyword_return | keyword_self + | keyword_super | keyword_then | keyword_true | keyword_undef + | keyword_when | keyword_yield | keyword_if | keyword_unless + | keyword_while | keyword_until + ; + +arg : lhs '=' arg_rhs + { + $$ = new_asgn(p, $1, $3); + } + | var_lhs tOP_ASGN arg_rhs + { + $$ = new_op_asgn(p, $1, $2, $3); + } + | primary_value '[' opt_call_args rbracket tOP_ASGN arg_rhs + { + $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3, '.'), $5, $6); + } + | primary_value call_op tIDENTIFIER tOP_ASGN arg_rhs + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0, $2), $4, $5); + } + | primary_value call_op tCONSTANT tOP_ASGN arg_rhs + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0, $2), $4, $5); + } + | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg_rhs + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0, tCOLON2), $4, $5); + } + | primary_value tCOLON2 tCONSTANT tOP_ASGN arg_rhs + { + yyerror(p, "constant re-assignment"); + $$ = new_begin(p, 0); + } + | tCOLON3 tCONSTANT tOP_ASGN arg_rhs + { + yyerror(p, "constant re-assignment"); + $$ = new_begin(p, 0); + } + | backref tOP_ASGN arg_rhs + { + backref_error(p, $1); + $$ = new_begin(p, 0); + } + | arg tDOT2 arg + { + $$ = new_dot2(p, $1, $3); + } + | arg tDOT3 arg + { + $$ = new_dot3(p, $1, $3); + } + | arg '+' arg + { + $$ = call_bin_op(p, $1, "+", $3); + } + | arg '-' arg + { + $$ = call_bin_op(p, $1, "-", $3); + } + | arg '*' arg + { + $$ = call_bin_op(p, $1, "*", $3); + } + | arg '/' arg + { + $$ = call_bin_op(p, $1, "/", $3); + } + | arg '%' arg + { + $$ = call_bin_op(p, $1, "%", $3); + } + | arg tPOW arg + { + $$ = call_bin_op(p, $1, "**", $3); + } + | tUMINUS_NUM tINTEGER tPOW arg + { + $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); + } + | tUMINUS_NUM tFLOAT tPOW arg + { + $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); + } + | tUPLUS arg + { + $$ = call_uni_op(p, $2, "+@"); + } + | tUMINUS arg + { + $$ = call_uni_op(p, $2, "-@"); + } + | arg '|' arg + { + $$ = call_bin_op(p, $1, "|", $3); + } + | arg '^' arg + { + $$ = call_bin_op(p, $1, "^", $3); + } + | arg '&' arg + { + $$ = call_bin_op(p, $1, "&", $3); + } + | arg tCMP arg + { + $$ = call_bin_op(p, $1, "<=>", $3); + } + | arg '>' arg + { + $$ = call_bin_op(p, $1, ">", $3); + } + | arg tGEQ arg + { + $$ = call_bin_op(p, $1, ">=", $3); + } + | arg '<' arg + { + $$ = call_bin_op(p, $1, "<", $3); + } + | arg tLEQ arg + { + $$ = call_bin_op(p, $1, "<=", $3); + } + | arg tEQ arg + { + $$ = call_bin_op(p, $1, "==", $3); + } + | arg tEQQ arg + { + $$ = call_bin_op(p, $1, "===", $3); + } + | arg tNEQ arg + { + $$ = call_bin_op(p, $1, "!=", $3); + } + | arg tMATCH arg + { + $$ = call_bin_op(p, $1, "=~", $3); + } + | arg tNMATCH arg + { + $$ = call_bin_op(p, $1, "!~", $3); + } + | '!' arg + { + $$ = call_uni_op(p, cond($2), "!"); + } + | '~' arg + { + $$ = call_uni_op(p, cond($2), "~"); + } + | arg tLSHFT arg + { + $$ = call_bin_op(p, $1, "<<", $3); + } + | arg tRSHFT arg + { + $$ = call_bin_op(p, $1, ">>", $3); + } + | arg tANDOP arg + { + $$ = new_and(p, $1, $3); + } + | arg tOROP arg + { + $$ = new_or(p, $1, $3); + } + | arg '?' arg opt_nl ':' arg + { + $$ = new_if(p, cond($1), $3, $6); + } + | primary + { + $$ = $1; + } + ; + +aref_args : none + | args trailer + { + $$ = $1; + NODE_LINENO($$, $1); + } + | args comma assocs trailer + { + $$ = push($1, new_hash(p, $3)); + } + | assocs trailer + { + $$ = cons(new_hash(p, $1), 0); + NODE_LINENO($$, $1); + } + ; + +arg_rhs : arg %prec tOP_ASGN + { + $$ = $1; + } + | arg modifier_rescue arg + { + void_expr_error(p, $1); + void_expr_error(p, $3); + $$ = new_mod_rescue(p, $1, $3); + } + ; + +paren_args : '(' opt_call_args rparen + { + $$ = $2; + } + ; + +opt_paren_args : none + | paren_args + ; + +opt_call_args : none + | call_args + | args ',' + { + $$ = cons($1,0); + NODE_LINENO($$, $1); + } + | args comma assocs ',' + { + $$ = cons(push($1, new_hash(p, $3)), 0); + NODE_LINENO($$, $1); + } + | assocs ',' + { + $$ = cons(list1(new_hash(p, $1)), 0); + NODE_LINENO($$, $1); + } + ; + +call_args : command + { + void_expr_error(p, $1); + $$ = cons(list1($1), 0); + NODE_LINENO($$, $1); + } + | args opt_block_arg + { + $$ = cons($1, $2); + NODE_LINENO($$, $1); + } + | assocs opt_block_arg + { + $$ = cons(list1(new_hash(p, $1)), $2); + NODE_LINENO($$, $1); + } + | args comma assocs opt_block_arg + { + $$ = cons(push($1, new_hash(p, $3)), $4); + NODE_LINENO($$, $1); + } + | block_arg + { + $$ = cons(0, $1); + NODE_LINENO($$, $1); + } + ; + +command_args : { + $<stack>$ = p->cmdarg_stack; + CMDARG_PUSH(1); + } + call_args + { + p->cmdarg_stack = $<stack>1; + $$ = $2; + } + ; + +block_arg : tAMPER arg + { + $$ = new_block_arg(p, $2); + } + ; + +opt_block_arg : comma block_arg + { + $$ = $2; + } + | none + { + $$ = 0; + } + ; + +comma : ',' + | ',' heredoc_bodies + ; + +args : arg + { + void_expr_error(p, $1); + $$ = cons($1, 0); + NODE_LINENO($$, $1); + } + | tSTAR arg + { + void_expr_error(p, $2); + $$ = cons(new_splat(p, $2), 0); + NODE_LINENO($$, $2); + } + | args comma arg + { + void_expr_error(p, $3); + $$ = push($1, $3); + } + | args comma tSTAR arg + { + void_expr_error(p, $4); + $$ = push($1, new_splat(p, $4)); + } + ; + +mrhs : args comma arg + { + void_expr_error(p, $3); + $$ = push($1, $3); + } + | args comma tSTAR arg + { + void_expr_error(p, $4); + $$ = push($1, new_splat(p, $4)); + } + | tSTAR arg + { + void_expr_error(p, $2); + $$ = list1(new_splat(p, $2)); + } + ; + +primary : literal + | string + | xstring + | regexp + | heredoc + | var_ref + | backref + | tFID + { + $$ = new_fcall(p, $1, 0); + } + | keyword_begin + { + $<stack>$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + bodystmt + keyword_end + { + p->cmdarg_stack = $<stack>2; + $$ = $3; + } + | tLPAREN_ARG + { + $<stack>$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + stmt {p->lstate = EXPR_ENDARG;} rparen + { + p->cmdarg_stack = $<stack>2; + $$ = $3; + } + | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen + { + $$ = new_nil(p); + } + | tLPAREN compstmt ')' + { + $$ = $2; + } + | primary_value tCOLON2 tCONSTANT + { + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + $$ = new_colon3(p, $2); + } + | tLBRACK aref_args ']' + { + $$ = new_array(p, $2); + NODE_LINENO($$, $2); + } + | tLBRACE assoc_list '}' + { + $$ = new_hash(p, $2); + NODE_LINENO($$, $2); + } + | keyword_return + { + $$ = new_return(p, 0); + } + | keyword_yield opt_paren_args + { + $$ = new_yield(p, $2); + } + | keyword_not '(' expr rparen + { + $$ = call_uni_op(p, cond($3), "!"); + } + | keyword_not '(' rparen + { + $$ = call_uni_op(p, new_nil(p), "!"); + } + | operation brace_block + { + $$ = new_fcall(p, $1, cons(0, $2)); + } + | method_call + | method_call brace_block + { + call_with_block(p, $1, $2); + $$ = $1; + } + | tLAMBDA + { + local_nest(p); + $<num>$ = p->lpar_beg; + p->lpar_beg = ++p->paren_nest; + } + f_larglist + { + $<stack>$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + lambda_body + { + p->lpar_beg = $<num>2; + $$ = new_lambda(p, $3, $5); + local_unnest(p); + p->cmdarg_stack = $<stack>4; + CMDARG_LEXPOP(); + } + | keyword_if expr_value then + compstmt + if_tail + keyword_end + { + $$ = new_if(p, cond($2), $4, $5); + SET_LINENO($$, $1); + } + | keyword_unless expr_value then + compstmt + opt_else + keyword_end + { + $$ = new_unless(p, cond($2), $4, $5); + SET_LINENO($$, $1); + } + | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();} + compstmt + keyword_end + { + $$ = new_while(p, cond($3), $6); + SET_LINENO($$, $1); + } + | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();} + compstmt + keyword_end + { + $$ = new_until(p, cond($3), $6); + SET_LINENO($$, $1); + } + | keyword_case expr_value opt_terms + case_body + keyword_end + { + $$ = new_case(p, $2, $4); + } + | keyword_case opt_terms case_body keyword_end + { + $$ = new_case(p, 0, $3); + } + | keyword_for for_var keyword_in + {COND_PUSH(1);} + expr_value do + {COND_POP();} + compstmt + keyword_end + { + $$ = new_for(p, $2, $5, $8); + SET_LINENO($$, $1); + } + | keyword_class + cpath superclass + { + if (p->in_def || p->in_single) + yyerror(p, "class definition in method body"); + $<nd>$ = local_switch(p); + } + bodystmt + keyword_end + { + $$ = new_class(p, $2, $3, $5); + SET_LINENO($$, $1); + local_resume(p, $<nd>4); + } + | keyword_class + tLSHFT expr + { + $<num>$ = p->in_def; + p->in_def = 0; + } + term + { + $<nd>$ = cons(local_switch(p), nint(p->in_single)); + p->in_single = 0; + } + bodystmt + keyword_end + { + $$ = new_sclass(p, $3, $7); + SET_LINENO($$, $1); + local_resume(p, $<nd>6->car); + p->in_def = $<num>4; + p->in_single = intn($<nd>6->cdr); + } + | keyword_module + cpath + { + if (p->in_def || p->in_single) + yyerror(p, "module definition in method body"); + $<nd>$ = local_switch(p); + } + bodystmt + keyword_end + { + $$ = new_module(p, $2, $4); + SET_LINENO($$, $1); + local_resume(p, $<nd>3); + } + | keyword_def fname + { + $<stack>$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + { + p->in_def++; + $<nd>$ = local_switch(p); + } + f_arglist + bodystmt + keyword_end + { + $$ = new_def(p, $2, $5, $6); + SET_LINENO($$, $1); + local_resume(p, $<nd>4); + p->in_def--; + p->cmdarg_stack = $<stack>3; + } + | keyword_def singleton dot_or_colon + { + p->lstate = EXPR_FNAME; + $<stack>$ = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + fname + { + p->in_single++; + p->lstate = EXPR_ENDFN; /* force for args */ + $<nd>$ = local_switch(p); + } + f_arglist + bodystmt + keyword_end + { + $$ = new_sdef(p, $2, $5, $7, $8); + SET_LINENO($$, $1); + local_resume(p, $<nd>6); + p->in_single--; + p->cmdarg_stack = $<stack>4; + } + | keyword_break + { + $$ = new_break(p, 0); + } + | keyword_next + { + $$ = new_next(p, 0); + } + | keyword_redo + { + $$ = new_redo(p); + } + | keyword_retry + { + $$ = new_retry(p); + } + ; + +primary_value : primary + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + ; + +then : term + | keyword_then + | term keyword_then + ; + +do : term + | keyword_do_cond + ; + +if_tail : opt_else + | keyword_elsif expr_value then + compstmt + if_tail + { + $$ = new_if(p, cond($2), $4, $5); + } + ; + +opt_else : none + | keyword_else compstmt + { + $$ = $2; + } + ; + +for_var : lhs + { + $$ = list1(list1($1)); + } + | mlhs + ; + +f_marg : f_norm_arg + { + $$ = new_arg(p, $1); + } + | tLPAREN f_margs rparen + { + $$ = new_masgn(p, $2, 0); + } + ; + +f_marg_list : f_marg + { + $$ = list1($1); + } + | f_marg_list ',' f_marg + { + $$ = push($1, $3); + } + ; + +f_margs : f_marg_list + { + $$ = list3($1,0,0); + } + | f_marg_list ',' tSTAR f_norm_arg + { + $$ = list3($1, new_arg(p, $4), 0); + } + | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list + { + $$ = list3($1, new_arg(p, $4), $6); + } + | f_marg_list ',' tSTAR + { + $$ = list3($1, (node*)-1, 0); + } + | f_marg_list ',' tSTAR ',' f_marg_list + { + $$ = list3($1, (node*)-1, $5); + } + | tSTAR f_norm_arg + { + $$ = list3(0, new_arg(p, $2), 0); + } + | tSTAR f_norm_arg ',' f_marg_list + { + $$ = list3(0, new_arg(p, $2), $4); + } + | tSTAR + { + $$ = list3(0, (node*)-1, 0); + } + | tSTAR ',' f_marg_list + { + $$ = list3(0, (node*)-1, $3); + } + ; + +block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, 0, $6); + } + | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, $7, $8); + } + | f_arg ',' f_block_optarg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, 0, $4); + } + | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, $5, $6); + } + | f_arg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, 0, $4); + } + | f_arg ',' + { + $$ = new_args(p, $1, 0, 0, 0, 0); + } + | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, $5, $6); + } + | f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, 0, 0, $2); + } + | f_block_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, 0, $4); + } + | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, $5, $6); + } + | f_block_optarg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, 0, $2); + } + | f_block_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, $3, $4); + } + | f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, 0, $2); + } + | f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, $3, $4); + } + | f_block_arg + { + $$ = new_args(p, 0, 0, 0, 0, $1); + } + ; + +opt_block_param : none + | block_param_def + { + p->cmd_start = TRUE; + $$ = $1; + } + ; + +block_param_def : '|' opt_bv_decl '|' + { + $$ = 0; + } + | tOROP + { + $$ = 0; + } + | '|' block_param opt_bv_decl '|' + { + $$ = $2; + } + ; + + +opt_bv_decl : opt_nl + { + $$ = 0; + } + | opt_nl ';' bv_decls opt_nl + { + $$ = 0; + } + ; + +bv_decls : bvar + | bv_decls ',' bvar + ; + +bvar : tIDENTIFIER + { + local_add_f(p, $1); + new_bv(p, $1); + } + | f_bad_arg + ; + +f_larglist : '(' f_args opt_bv_decl ')' + { + $$ = $2; + } + | f_args + { + $$ = $1; + } + ; + +lambda_body : tLAMBEG compstmt '}' + { + $$ = $2; + } + | keyword_do_LAMBDA compstmt keyword_end + { + $$ = $2; + } + ; + +do_block : keyword_do_block + { + local_nest(p); + } + opt_block_param + compstmt + keyword_end + { + $$ = new_block(p,$3,$4); + local_unnest(p); + } + ; + +block_call : command do_block + { + if ($1->car == (node*)NODE_YIELD) { + yyerror(p, "block given to yield"); + } + else { + call_with_block(p, $1, $2); + } + $$ = $1; + } + | block_call call_op2 operation2 opt_paren_args + { + $$ = new_call(p, $1, $3, $4, $2); + } + | block_call call_op2 operation2 opt_paren_args brace_block + { + $$ = new_call(p, $1, $3, $4, $2); + call_with_block(p, $$, $5); + } + | block_call call_op2 operation2 command_args do_block + { + $$ = new_call(p, $1, $3, $4, $2); + call_with_block(p, $$, $5); + } + ; + +method_call : operation paren_args + { + $$ = new_fcall(p, $1, $2); + } + | primary_value call_op operation2 opt_paren_args + { + $$ = new_call(p, $1, $3, $4, $2); + } + | primary_value tCOLON2 operation2 paren_args + { + $$ = new_call(p, $1, $3, $4, tCOLON2); + } + | primary_value tCOLON2 operation3 + { + $$ = new_call(p, $1, $3, 0, tCOLON2); + } + | primary_value call_op paren_args + { + $$ = new_call(p, $1, intern("call",4), $3, $2); + } + | primary_value tCOLON2 paren_args + { + $$ = new_call(p, $1, intern("call",4), $3, tCOLON2); + } + | keyword_super paren_args + { + $$ = new_super(p, $2); + } + | keyword_super + { + $$ = new_zsuper(p); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3, '.'); + } + ; + +brace_block : '{' + { + local_nest(p); + $<num>$ = p->lineno; + } + opt_block_param + compstmt '}' + { + $$ = new_block(p,$3,$4); + SET_LINENO($$, $<num>2); + local_unnest(p); + } + | keyword_do + { + local_nest(p); + $<num>$ = p->lineno; + } + opt_block_param + compstmt keyword_end + { + $$ = new_block(p,$3,$4); + SET_LINENO($$, $<num>2); + local_unnest(p); + } + ; + +case_body : keyword_when args then + compstmt + cases + { + $$ = cons(cons($2, $4), $5); + } + ; + +cases : opt_else + { + if ($1) { + $$ = cons(cons(0, $1), 0); + } + else { + $$ = 0; + } + } + | case_body + ; + +opt_rescue : keyword_rescue exc_list exc_var then + compstmt + opt_rescue + { + $$ = list1(list3($2, $3, $5)); + if ($6) $$ = append($$, $6); + } + | none + ; + +exc_list : arg + { + $$ = list1($1); + } + | mrhs + | none + ; + +exc_var : tASSOC lhs + { + $$ = $2; + } + | none + ; + +opt_ensure : keyword_ensure compstmt + { + $$ = $2; + } + | none + ; + +literal : numeric + | symbol + | words + | symbols + ; + +string : tCHAR + | tSTRING + | tSTRING_BEG tSTRING + { + $$ = $2; + } + | tSTRING_BEG string_rep tSTRING + { + $$ = new_dstr(p, push($2, $3)); + } + ; + +string_rep : string_interp + | string_rep string_interp + { + $$ = append($1, $2); + } + ; + +string_interp : tSTRING_MID + { + $$ = list1($1); + } + | tSTRING_PART + { + $<nd>$ = p->lex_strterm; + p->lex_strterm = NULL; + } + compstmt + '}' + { + p->lex_strterm = $<nd>2; + $$ = list2($1, $3); + } + | tLITERAL_DELIM + { + $$ = list1(new_literal_delim(p)); + } + | tHD_LITERAL_DELIM heredoc_bodies + { + $$ = list1(new_literal_delim(p)); + } + ; + +xstring : tXSTRING_BEG tXSTRING + { + $$ = $2; + } + | tXSTRING_BEG string_rep tXSTRING + { + $$ = new_dxstr(p, push($2, $3)); + } + ; + +regexp : tREGEXP_BEG tREGEXP + { + $$ = $2; + } + | tREGEXP_BEG string_rep tREGEXP + { + $$ = new_dregx(p, $2, $3); + } + ; + +heredoc : tHEREDOC_BEG + ; + +heredoc_bodies : heredoc_body + | heredoc_bodies heredoc_body + ; + +heredoc_body : tHEREDOC_END + { + parser_heredoc_info * inf = parsing_heredoc_inf(p); + inf->doc = push(inf->doc, new_str(p, "", 0)); + heredoc_end(p); + } + | heredoc_string_rep tHEREDOC_END + { + heredoc_end(p); + } + ; + +heredoc_string_rep : heredoc_string_interp + | heredoc_string_rep heredoc_string_interp + ; + +heredoc_string_interp : tHD_STRING_MID + { + parser_heredoc_info * inf = parsing_heredoc_inf(p); + inf->doc = push(inf->doc, $1); + heredoc_treat_nextline(p); + } + | tHD_STRING_PART + { + $<nd>$ = p->lex_strterm; + p->lex_strterm = NULL; + } + compstmt + '}' + { + parser_heredoc_info * inf = parsing_heredoc_inf(p); + p->lex_strterm = $<nd>2; + inf->doc = push(push(inf->doc, $1), $3); + } + ; + +words : tWORDS_BEG tSTRING + { + $$ = new_words(p, list1($2)); + } + | tWORDS_BEG string_rep tSTRING + { + $$ = new_words(p, push($2, $3)); + } + ; + + +symbol : basic_symbol + { + $$ = new_sym(p, $1); + } + | tSYMBEG tSTRING_BEG string_rep tSTRING + { + p->lstate = EXPR_END; + $$ = new_dsym(p, push($3, $4)); + } + ; + +basic_symbol : tSYMBEG sym + { + p->lstate = EXPR_END; + $$ = $2; + } + ; + +sym : fname + | tIVAR + | tGVAR + | tCVAR + | tSTRING + { + $$ = new_strsym(p, $1); + } + | tSTRING_BEG tSTRING + { + $$ = new_strsym(p, $2); + } + ; + +symbols : tSYMBOLS_BEG tSTRING + { + $$ = new_symbols(p, list1($2)); + } + | tSYMBOLS_BEG string_rep tSTRING + { + $$ = new_symbols(p, push($2, $3)); + } + ; + +numeric : tINTEGER + | tFLOAT + | tUMINUS_NUM tINTEGER %prec tLOWEST + { + $$ = negate_lit(p, $2); + } + | tUMINUS_NUM tFLOAT %prec tLOWEST + { + $$ = negate_lit(p, $2); + } + ; + +variable : tIDENTIFIER + { + $$ = new_lvar(p, $1); + } + | tIVAR + { + $$ = new_ivar(p, $1); + } + | tGVAR + { + $$ = new_gvar(p, $1); + } + | tCVAR + { + $$ = new_cvar(p, $1); + } + | tCONSTANT + { + $$ = new_const(p, $1); + } + ; + +var_lhs : variable + { + assignable(p, $1); + } + ; + +var_ref : variable + { + $$ = var_reference(p, $1); + } + | keyword_nil + { + $$ = new_nil(p); + } + | keyword_self + { + $$ = new_self(p); + } + | keyword_true + { + $$ = new_true(p); + } + | keyword_false + { + $$ = new_false(p); + } + | keyword__FILE__ + { + const char *fn = p->filename; + if (!fn) { + fn = "(null)"; + } + $$ = new_str(p, fn, strlen(fn)); + } + | keyword__LINE__ + { + char buf[16]; + + snprintf(buf, sizeof(buf), "%d", p->lineno); + $$ = new_int(p, buf, 10); + } + | keyword__ENCODING__ + { +#ifdef MRB_UTF8_STRING + const char *enc = "UTF-8"; +#else + const char *enc = "ASCII-8BIT"; +#endif + $$ = new_str(p, enc, strlen(enc)); + } + ; + +backref : tNTH_REF + | tBACK_REF + ; + +superclass : /* term */ + { + $$ = 0; + } + | '<' + { + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + } + expr_value term + { + $$ = $3; + } /* + | error term + { + yyerrok; + $$ = 0; + } */ + ; + +f_arglist : '(' f_args rparen + { + $$ = $2; + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + } + | f_args term + { + $$ = $1; + } + ; + +f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, 0, $6); + } + | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, $7, $8); + } + | f_arg ',' f_optarg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, 0, $4); + } + | f_arg ',' f_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, $5, $6); + } + | f_arg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, 0, $4); + } + | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, $5, $6); + } + | f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, 0, 0, $2); + } + | f_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, 0, $4); + } + | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, $5, $6); + } + | f_optarg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, 0, $2); + } + | f_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, $3, $4); + } + | f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, 0, $2); + } + | f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, $3, $4); + } + | f_block_arg + { + $$ = new_args(p, 0, 0, 0, 0, $1); + } + | /* none */ + { + local_add_f(p, 0); + $$ = new_args(p, 0, 0, 0, 0, 0); + } + ; + +f_bad_arg : tCONSTANT + { + yyerror(p, "formal argument cannot be a constant"); + $$ = 0; + } + | tIVAR + { + yyerror(p, "formal argument cannot be an instance variable"); + $$ = 0; + } + | tGVAR + { + yyerror(p, "formal argument cannot be a global variable"); + $$ = 0; + } + | tCVAR + { + yyerror(p, "formal argument cannot be a class variable"); + $$ = 0; + } + ; + +f_norm_arg : f_bad_arg + { + $$ = 0; + } + | tIDENTIFIER + { + local_add_f(p, $1); + $$ = $1; + } + ; + +f_arg_item : f_norm_arg + { + $$ = new_arg(p, $1); + } + | tLPAREN f_margs rparen + { + $$ = new_masgn(p, $2, 0); + } + ; + +f_arg : f_arg_item + { + $$ = list1($1); + } + | f_arg ',' f_arg_item + { + $$ = push($1, $3); + } + ; + +f_opt_asgn : tIDENTIFIER '=' + { + local_add_f(p, $1); + $$ = $1; + } + ; + +f_opt : f_opt_asgn arg + { + void_expr_error(p, $2); + $$ = cons(nsym($1), $2); + } + ; + +f_block_opt : f_opt_asgn primary_value + { + void_expr_error(p, $2); + $$ = cons(nsym($1), $2); + } + ; + +f_block_optarg : f_block_opt + { + $$ = list1($1); + } + | f_block_optarg ',' f_block_opt + { + $$ = push($1, $3); + } + ; + +f_optarg : f_opt + { + $$ = list1($1); + } + | f_optarg ',' f_opt + { + $$ = push($1, $3); + } + ; + +restarg_mark : '*' + | tSTAR + ; + +f_rest_arg : restarg_mark tIDENTIFIER + { + local_add_f(p, $2); + $$ = $2; + } + | restarg_mark + { + local_add_f(p, 0); + $$ = -1; + } + ; + +blkarg_mark : '&' + | tAMPER + ; + +f_block_arg : blkarg_mark tIDENTIFIER + { + local_add_f(p, $2); + $$ = $2; + } + ; + +opt_f_block_arg : ',' f_block_arg + { + $$ = $2; + } + | none + { + local_add_f(p, 0); + $$ = 0; + } + ; + +singleton : var_ref + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + | '(' {p->lstate = EXPR_BEG;} expr rparen + { + if ($3 == 0) { + yyerror(p, "can't define singleton method for ()."); + } + else { + switch ((enum node_type)intn($3->car)) { + case NODE_STR: + case NODE_DSTR: + case NODE_XSTR: + case NODE_DXSTR: + case NODE_DREGX: + case NODE_MATCH: + case NODE_FLOAT: + case NODE_ARRAY: + case NODE_HEREDOC: + yyerror(p, "can't define singleton method for literals"); + default: + break; + } + } + $$ = $3; + } + ; + +assoc_list : none + | assocs trailer + { + $$ = $1; + } + ; + +assocs : assoc + { + $$ = list1($1); + NODE_LINENO($$, $1); + } + | assocs ',' assoc + { + $$ = push($1, $3); + } + ; + +assoc : arg tASSOC arg + { + void_expr_error(p, $1); + void_expr_error(p, $3); + $$ = cons($1, $3); + } + | tLABEL arg + { + void_expr_error(p, $2); + $$ = cons(new_sym(p, $1), $2); + } + | tLABEL_END arg + { + void_expr_error(p, $2); + $$ = cons(new_sym(p, new_strsym(p, $1)), $2); + } + | tSTRING_BEG tLABEL_END arg + { + void_expr_error(p, $3); + $$ = cons(new_sym(p, new_strsym(p, $2)), $3); + } + | tSTRING_BEG string_rep tLABEL_END arg + { + void_expr_error(p, $4); + $$ = cons(new_dsym(p, push($2, $3)), $4); + } + ; + +operation : tIDENTIFIER + | tCONSTANT + | tFID + ; + +operation2 : tIDENTIFIER + | tCONSTANT + | tFID + | op + ; + +operation3 : tIDENTIFIER + | tFID + | op + ; + +dot_or_colon : '.' + | tCOLON2 + ; + +call_op : '.' + { + $$ = '.'; + } + | tANDDOT + { + $$ = 0; + } + ; + +call_op2 : call_op + | tCOLON2 + { + $$ = tCOLON2; + } + ; + +opt_terms : /* none */ + | terms + ; + +opt_nl : /* none */ + | nl + ; + +rparen : opt_nl ')' + ; + +rbracket : opt_nl ']' + ; + +trailer : /* none */ + | nl + | comma + ; + +term : ';' {yyerrok;} + | nl + | heredoc_body + ; + +nl : '\n' + { + p->lineno++; + p->column = 0; + } + ; + +terms : term + | terms term + ; + +none : /* none */ + { + $$ = 0; + } + ; +%% +#define pylval (*((YYSTYPE*)(p->ylval))) + +static void +yyerror(parser_state *p, const char *s) +{ + char* c; + size_t n; + + if (! p->capture_errors) { +#ifndef MRB_DISABLE_STDIO + if (p->filename) { + fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); + } + else { + fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); + } +#endif + } + else if (p->nerr < sizeof(p->error_buffer) / sizeof(p->error_buffer[0])) { + n = strlen(s); + c = (char *)parser_palloc(p, n + 1); + memcpy(c, s, n + 1); + p->error_buffer[p->nerr].message = c; + p->error_buffer[p->nerr].lineno = p->lineno; + p->error_buffer[p->nerr].column = p->column; + } + p->nerr++; +} + +static void +yyerror_i(parser_state *p, const char *fmt, int i) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), fmt, i); + yyerror(p, buf); +} + +static void +yywarn(parser_state *p, const char *s) +{ + char* c; + size_t n; + + if (! p->capture_errors) { +#ifndef MRB_DISABLE_STDIO + if (p->filename) { + fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); + } + else { + fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); + } +#endif + } + else if (p->nwarn < sizeof(p->warn_buffer) / sizeof(p->warn_buffer[0])) { + n = strlen(s); + c = (char *)parser_palloc(p, n + 1); + memcpy(c, s, n + 1); + p->warn_buffer[p->nwarn].message = c; + p->warn_buffer[p->nwarn].lineno = p->lineno; + p->warn_buffer[p->nwarn].column = p->column; + } + p->nwarn++; +} + +static void +yywarning(parser_state *p, const char *s) +{ + yywarn(p, s); +} + +static void +yywarning_s(parser_state *p, const char *fmt, const char *s) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), fmt, s); + yywarning(p, buf); +} + +static void +backref_error(parser_state *p, node *n) +{ + int c; + + c = (int)(intptr_t)n->car; + + if (c == NODE_NTH_REF) { + yyerror_i(p, "can't set variable $%" MRB_PRId, (mrb_int)(intptr_t)n->cdr); + } + else if (c == NODE_BACK_REF) { + yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr); + } + else { + mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); + } +} + +static void +void_expr_error(parser_state *p, node *n) +{ + int c; + + if (n == NULL) return; + c = (int)(intptr_t)n->car; + switch (c) { + case NODE_BREAK: + case NODE_RETURN: + case NODE_NEXT: + case NODE_REDO: + case NODE_RETRY: + yyerror(p, "void value expression"); + break; + case NODE_AND: + case NODE_OR: + void_expr_error(p, n->cdr->car); + void_expr_error(p, n->cdr->cdr); + break; + case NODE_BEGIN: + if (n->cdr) { + while (n->cdr) { + n = n->cdr; + } + void_expr_error(p, n->car); + } + break; + default: + break; + } +} + +static void pushback(parser_state *p, int c); +static mrb_bool peeks(parser_state *p, const char *s); +static mrb_bool skips(parser_state *p, const char *s); + +static inline int +nextc(parser_state *p) +{ + int c; + + if (p->pb) { + node *tmp; + + c = (int)(intptr_t)p->pb->car; + tmp = p->pb; + p->pb = p->pb->cdr; + cons_free(tmp); + } + else { +#ifndef MRB_DISABLE_STDIO + if (p->f) { + if (feof(p->f)) goto eof; + c = fgetc(p->f); + if (c == EOF) goto eof; + } + else +#endif + if (!p->s || p->s >= p->send) { + goto eof; + } + else { + c = (unsigned char)*p->s++; + } + } + if (c >= 0) { + p->column++; + } + if (c == '\r') { + c = nextc(p); + if (c != '\n') { + pushback(p, c); + return '\r'; + } + return c; + } + return c; + + eof: + if (!p->cxt) return -1; + else { + if (p->cxt->partial_hook(p) < 0) + return -1; /* end of program(s) */ + return -2; /* end of a file in the program files */ + } +} + +static void +pushback(parser_state *p, int c) +{ + if (c >= 0) { + p->column--; + } + p->pb = cons((node*)(intptr_t)c, p->pb); +} + +static void +skip(parser_state *p, char term) +{ + int c; + + for (;;) { + c = nextc(p); + if (c < 0) break; + if (c == term) break; + } +} + +static int +peekc_n(parser_state *p, int n) +{ + node *list = 0; + int c0; + + do { + c0 = nextc(p); + if (c0 == -1) return c0; /* do not skip partial EOF */ + if (c0 >= 0) --p->column; + list = push(list, (node*)(intptr_t)c0); + } while(n--); + if (p->pb) { + p->pb = append((node*)list, p->pb); + } + else { + p->pb = list; + } + return c0; +} + +static mrb_bool +peek_n(parser_state *p, int c, int n) +{ + return peekc_n(p, n) == c && c >= 0; +} +#define peek(p,c) peek_n((p), (c), 0) + +static mrb_bool +peeks(parser_state *p, const char *s) +{ + size_t len = strlen(s); + +#ifndef MRB_DISABLE_STDIO + if (p->f) { + int n = 0; + while (*s) { + if (!peek_n(p, *s++, n++)) return FALSE; + } + return TRUE; + } + else +#endif + if (p->s && p->s + len <= p->send) { + if (memcmp(p->s, s, len) == 0) return TRUE; + } + return FALSE; +} + +static mrb_bool +skips(parser_state *p, const char *s) +{ + int c; + + for (;;) { + /* skip until first char */ + for (;;) { + c = nextc(p); + if (c < 0) return FALSE; + if (c == '\n') { + p->lineno++; + p->column = 0; + } + if (c == *s) break; + } + s++; + if (peeks(p, s)) { + size_t len = strlen(s); + + while (len--) { + if (nextc(p) == '\n') { + p->lineno++; + p->column = 0; + } + } + return TRUE; + } + else{ + s--; + } + } + return FALSE; +} + + +static int +newtok(parser_state *p) +{ + if (p->tokbuf != p->buf) { + mrb_free(p->mrb, p->tokbuf); + p->tokbuf = p->buf; + p->tsiz = MRB_PARSER_TOKBUF_SIZE; + } + p->tidx = 0; + return p->column - 1; +} + +static void +tokadd(parser_state *p, int32_t c) +{ + char utf8[4]; + int i, len; + + /* mrb_assert(-0x10FFFF <= c && c <= 0xFF); */ + if (c >= 0) { + /* Single byte from source or non-Unicode escape */ + utf8[0] = (char)c; + len = 1; + } + else { + /* Unicode character */ + c = -c; + if (c < 0x80) { + utf8[0] = (char)c; + len = 1; + } + else if (c < 0x800) { + utf8[0] = (char)(0xC0 | (c >> 6)); + utf8[1] = (char)(0x80 | (c & 0x3F)); + len = 2; + } + else if (c < 0x10000) { + utf8[0] = (char)(0xE0 | (c >> 12) ); + utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[2] = (char)(0x80 | ( c & 0x3F)); + len = 3; + } + else { + utf8[0] = (char)(0xF0 | (c >> 18) ); + utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F)); + utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[3] = (char)(0x80 | ( c & 0x3F)); + len = 4; + } + } + if (p->tidx+len >= p->tsiz) { + if (p->tsiz >= MRB_PARSER_TOKBUF_MAX) { + p->tidx += len; + return; + } + p->tsiz *= 2; + if (p->tokbuf == p->buf) { + p->tokbuf = (char*)mrb_malloc(p->mrb, p->tsiz); + memcpy(p->tokbuf, p->buf, MRB_PARSER_TOKBUF_SIZE); + } + else { + p->tokbuf = (char*)mrb_realloc(p->mrb, p->tokbuf, p->tsiz); + } + } + for (i = 0; i < len; i++) { + p->tokbuf[p->tidx++] = utf8[i]; + } +} + +static int +toklast(parser_state *p) +{ + return p->tokbuf[p->tidx-1]; +} + +static void +tokfix(parser_state *p) +{ + if (p->tidx >= MRB_PARSER_TOKBUF_MAX) { + p->tidx = MRB_PARSER_TOKBUF_MAX-1; + yyerror(p, "string too long (truncated)"); + } + p->tokbuf[p->tidx] = '\0'; +} + +static const char* +tok(parser_state *p) +{ + return p->tokbuf; +} + +static int +toklen(parser_state *p) +{ + return p->tidx; +} + +#define IS_ARG() (p->lstate == EXPR_ARG || p->lstate == EXPR_CMDARG) +#define IS_END() (p->lstate == EXPR_END || p->lstate == EXPR_ENDARG || p->lstate == EXPR_ENDFN) +#define IS_BEG() (p->lstate == EXPR_BEG || p->lstate == EXPR_MID || p->lstate == EXPR_VALUE || p->lstate == EXPR_CLASS) +#define IS_SPCARG(c) (IS_ARG() && space_seen && !ISSPACE(c)) +#define IS_LABEL_POSSIBLE() ((p->lstate == EXPR_BEG && !cmd_state) || IS_ARG()) +#define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1)) + +static int32_t +scan_oct(const int *start, int len, int *retlen) +{ + const int *s = start; + int32_t retval = 0; + + /* mrb_assert(len <= 3) */ + while (len-- && *s >= '0' && *s <= '7') { + retval <<= 3; + retval |= *s++ - '0'; + } + *retlen = (int)(s - start); + + return retval; +} + +static int32_t +scan_hex(parser_state *p, const int *start, int len, int *retlen) +{ + static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; + const int *s = start; + uint32_t retval = 0; + char *tmp; + + /* mrb_assert(len <= 8) */ + while (len-- && *s && (tmp = (char*)strchr(hexdigit, *s))) { + retval <<= 4; + retval |= (tmp - hexdigit) & 15; + s++; + } + *retlen = (int)(s - start); + + return (int32_t)retval; +} + +static int32_t +read_escape_unicode(parser_state *p, int limit) +{ + int buf[9]; + int i; + int32_t hex; + + /* Look for opening brace */ + i = 0; + buf[0] = nextc(p); + if (buf[0] < 0) { + eof: + yyerror(p, "invalid escape character syntax"); + return -1; + } + if (ISXDIGIT(buf[0])) { + /* \uxxxx form */ + for (i=1; i<limit; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (!ISXDIGIT(buf[i])) { + pushback(p, buf[i]); + break; + } + } + } + else { + pushback(p, buf[0]); + } + hex = scan_hex(p, buf, i, &i); + if (i == 0 || hex > 0x10FFFF || (hex & 0xFFFFF800) == 0xD800) { + yyerror(p, "invalid Unicode code point"); + return -1; + } + return hex; +} + +/* Return negative to indicate Unicode code point */ +static int32_t +read_escape(parser_state *p) +{ + int32_t c; + + switch (c = nextc(p)) { + case '\\':/* Backslash */ + return c; + + case 'n':/* newline */ + return '\n'; + + case 't':/* horizontal tab */ + return '\t'; + + case 'r':/* carriage-return */ + return '\r'; + + case 'f':/* form-feed */ + return '\f'; + + case 'v':/* vertical tab */ + return '\13'; + + case 'a':/* alarm(bell) */ + return '\007'; + + case 'e':/* escape */ + return 033; + + case '0': case '1': case '2': case '3': /* octal constant */ + case '4': case '5': case '6': case '7': + { + int buf[3]; + int i; + + buf[0] = c; + for (i=1; i<3; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (buf[i] < '0' || '7' < buf[i]) { + pushback(p, buf[i]); + break; + } + } + c = scan_oct(buf, i, &i); + } + return c; + + case 'x': /* hex constant */ + { + int buf[2]; + int i; + + for (i=0; i<2; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (!ISXDIGIT(buf[i])) { + pushback(p, buf[i]); + break; + } + } + if (i == 0) { + yyerror(p, "invalid hex escape"); + return -1; + } + return scan_hex(p, buf, i, &i); + } + + case 'u': /* Unicode */ + if (peek(p, '{')) { + /* \u{xxxxxxxx} form */ + nextc(p); + c = read_escape_unicode(p, 8); + if (c < 0) return 0; + if (nextc(p) != '}') goto eof; + } + else { + c = read_escape_unicode(p, 4); + if (c < 0) return 0; + } + return -c; + + case 'b':/* backspace */ + return '\010'; + + case 's':/* space */ + return ' '; + + case 'M': + if ((c = nextc(p)) != '-') { + yyerror(p, "Invalid escape character syntax"); + pushback(p, c); + return '\0'; + } + if ((c = nextc(p)) == '\\') { + return read_escape(p) | 0x80; + } + else if (c < 0) goto eof; + else { + return ((c & 0xff) | 0x80); + } + + case 'C': + if ((c = nextc(p)) != '-') { + yyerror(p, "Invalid escape character syntax"); + pushback(p, c); + return '\0'; + } + case 'c': + if ((c = nextc(p))== '\\') { + c = read_escape(p); + } + else if (c == '?') + return 0177; + else if (c < 0) goto eof; + return c & 0x9f; + + eof: + case -1: + case -2: /* end of a file */ + yyerror(p, "Invalid escape character syntax"); + return '\0'; + + default: + return c; + } +} + +static int +parse_string(parser_state *p) +{ + int c; + string_type type = (string_type)(intptr_t)p->lex_strterm->car; + int nest_level = intn(p->lex_strterm->cdr->car); + int beg = intn(p->lex_strterm->cdr->cdr->car); + int end = intn(p->lex_strterm->cdr->cdr->cdr); + parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL; + int cmd_state = p->cmd_start; + + if (beg == 0) beg = -3; /* should never happen */ + if (end == 0) end = -3; + newtok(p); + while ((c = nextc(p)) != end || nest_level != 0) { + if (hinf && (c == '\n' || c < 0)) { + mrb_bool line_head; + tokadd(p, '\n'); + tokfix(p); + p->lineno++; + p->column = 0; + line_head = hinf->line_head; + hinf->line_head = TRUE; + if (line_head) { + /* check whether end of heredoc */ + const char *s = tok(p); + int len = toklen(p); + if (hinf->allow_indent) { + while (ISSPACE(*s) && len > 0) { + ++s; + --len; + } + } + if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) { + if (c < 0) { + p->parsing_heredoc = NULL; + } + else { + return tHEREDOC_END; + } + } + } + if (c < 0) { + char buf[256]; + snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term); + yyerror(p, buf); + return 0; + } + pylval.nd = new_str(p, tok(p), toklen(p)); + return tHD_STRING_MID; + } + if (c < 0) { + yyerror(p, "unterminated string meets end of file"); + return 0; + } + else if (c == beg) { + nest_level++; + p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; + } + else if (c == end) { + nest_level--; + p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; + } + else if (c == '\\') { + c = nextc(p); + if (type & STR_FUNC_EXPAND) { + if (c == end || c == beg) { + tokadd(p, c); + } + else if (c == '\n') { + p->lineno++; + p->column = 0; + if (type & STR_FUNC_ARRAY) { + tokadd(p, '\n'); + } + } + else if (type & STR_FUNC_REGEXP) { + tokadd(p, '\\'); + tokadd(p, c); + } + else if (c == 'u' && peek(p, '{')) { + /* \u{xxxx xxxx xxxx} form */ + nextc(p); + while (1) { + do c = nextc(p); while (ISSPACE(c)); + if (c == '}') break; + pushback(p, c); + c = read_escape_unicode(p, 8); + if (c < 0) break; + tokadd(p, -c); + } + if (hinf) + hinf->line_head = FALSE; + } + else { + pushback(p, c); + tokadd(p, read_escape(p)); + if (hinf) + hinf->line_head = FALSE; + } + } + else { + if (c != beg && c != end) { + if (c == '\n') { + p->lineno++; + p->column = 0; + } + if (!(c == '\\' || ((type & STR_FUNC_ARRAY) && ISSPACE(c)))) { + tokadd(p, '\\'); + } + } + tokadd(p, c); + } + continue; + } + else if ((c == '#') && (type & STR_FUNC_EXPAND)) { + c = nextc(p); + if (c == '{') { + tokfix(p); + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + pylval.nd = new_str(p, tok(p), toklen(p)); + if (hinf) { + hinf->line_head = FALSE; + return tHD_STRING_PART; + } + return tSTRING_PART; + } + tokadd(p, '#'); + pushback(p, c); + continue; + } + if ((type & STR_FUNC_ARRAY) && ISSPACE(c)) { + if (toklen(p) == 0) { + do { + if (c == '\n') { + p->lineno++; + p->column = 0; + heredoc_treat_nextline(p); + if (p->parsing_heredoc != NULL) { + return tHD_LITERAL_DELIM; + } + } + c = nextc(p); + } while (ISSPACE(c)); + pushback(p, c); + return tLITERAL_DELIM; + } + else { + pushback(p, c); + tokfix(p); + pylval.nd = new_str(p, tok(p), toklen(p)); + return tSTRING_MID; + } + } + if (c == '\n') { + p->lineno++; + p->column = 0; + } + tokadd(p, c); + } + + tokfix(p); + p->lstate = EXPR_END; + end_strterm(p); + + if (type & STR_FUNC_XQUOTE) { + pylval.nd = new_xstr(p, tok(p), toklen(p)); + return tXSTRING; + } + + if (type & STR_FUNC_REGEXP) { + int f = 0; + int re_opt; + char *s = strndup(tok(p), toklen(p)); + char flags[3]; + char *flag = flags; + char enc = '\0'; + char *encp; + char *dup; + + newtok(p); + while (re_opt = nextc(p), re_opt >= 0 && ISALPHA(re_opt)) { + switch (re_opt) { + case 'i': f |= 1; break; + case 'x': f |= 2; break; + case 'm': f |= 4; break; + case 'u': f |= 16; break; + case 'n': f |= 32; break; + default: tokadd(p, re_opt); break; + } + } + pushback(p, re_opt); + if (toklen(p)) { + char msg[128]; + tokfix(p); + snprintf(msg, sizeof(msg), "unknown regexp option%s - %s", + toklen(p) > 1 ? "s" : "", tok(p)); + yyerror(p, msg); + } + if (f != 0) { + if (f & 1) *flag++ = 'i'; + if (f & 2) *flag++ = 'x'; + if (f & 4) *flag++ = 'm'; + if (f & 16) enc = 'u'; + if (f & 32) enc = 'n'; + } + if (flag > flags) { + dup = strndup(flags, (size_t)(flag - flags)); + } + else { + dup = NULL; + } + if (enc) { + encp = strndup(&enc, 1); + } + else { + encp = NULL; + } + pylval.nd = new_regx(p, s, dup, encp); + + return tREGEXP; + } + pylval.nd = new_str(p, tok(p), toklen(p)); + if (IS_LABEL_POSSIBLE()) { + if (IS_LABEL_SUFFIX(0)) { + p->lstate = EXPR_BEG; + nextc(p); + return tLABEL_END; + } + } + + return tSTRING; +} + + +static int +heredoc_identifier(parser_state *p) +{ + int c; + int type = str_heredoc; + mrb_bool indent = FALSE; + mrb_bool quote = FALSE; + node *newnode; + parser_heredoc_info *info; + + c = nextc(p); + if (ISSPACE(c) || c == '=') { + pushback(p, c); + return 0; + } + if (c == '-') { + indent = TRUE; + c = nextc(p); + } + if (c == '\'' || c == '"') { + int term = c; + if (c == '\'') + quote = TRUE; + newtok(p); + while ((c = nextc(p)) >= 0 && c != term) { + if (c == '\n') { + c = -1; + break; + } + tokadd(p, c); + } + if (c < 0) { + yyerror(p, "unterminated here document identifier"); + return 0; + } + } + else { + if (c < 0) { + return 0; /* missing here document identifier */ + } + if (! identchar(c)) { + pushback(p, c); + if (indent) pushback(p, '-'); + return 0; + } + newtok(p); + do { + tokadd(p, c); + } while ((c = nextc(p)) >= 0 && identchar(c)); + pushback(p, c); + } + tokfix(p); + newnode = new_heredoc(p); + info = (parser_heredoc_info*)newnode->cdr; + info->term = strndup(tok(p), toklen(p)); + info->term_len = toklen(p); + if (! quote) + type |= STR_FUNC_EXPAND; + info->type = (string_type)type; + info->allow_indent = indent; + info->line_head = TRUE; + info->doc = NULL; + p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode); + p->lstate = EXPR_END; + + pylval.nd = newnode; + return tHEREDOC_BEG; +} + +static int +arg_ambiguous(parser_state *p) +{ + yywarning(p, "ambiguous first argument; put parentheses or even spaces"); + return 1; +} + +#include "lex.def" + +static int +parser_yylex(parser_state *p) +{ + int32_t c; + int space_seen = 0; + int cmd_state; + enum mrb_lex_state_enum last_state; + int token_column; + + if (p->lex_strterm) { + if (is_strterm_type(p, STR_FUNC_HEREDOC)) { + if (p->parsing_heredoc != NULL) + return parse_string(p); + } + else + return parse_string(p); + } + cmd_state = p->cmd_start; + p->cmd_start = FALSE; + retry: + last_state = p->lstate; + switch (c = nextc(p)) { + case '\004': /* ^D */ + case '\032': /* ^Z */ + case '\0': /* NUL */ + case -1: /* end of script. */ + if (p->heredocs_from_nextline) + goto maybe_heredoc; + return 0; + + /* white spaces */ + case ' ': case '\t': case '\f': case '\r': + case '\13': /* '\v' */ + space_seen = 1; + goto retry; + + case '#': /* it's a comment */ + skip(p, '\n'); + /* fall through */ + case -2: /* end of a file */ + case '\n': + maybe_heredoc: + heredoc_treat_nextline(p); + switch (p->lstate) { + case EXPR_BEG: + case EXPR_FNAME: + case EXPR_DOT: + case EXPR_CLASS: + case EXPR_VALUE: + p->lineno++; + p->column = 0; + if (p->parsing_heredoc != NULL) { + if (p->lex_strterm) { + return parse_string(p); + } + } + goto retry; + default: + break; + } + if (p->parsing_heredoc != NULL) { + return '\n'; + } + while ((c = nextc(p))) { + switch (c) { + case ' ': case '\t': case '\f': case '\r': + case '\13': /* '\v' */ + space_seen = 1; + break; + case '.': + if ((c = nextc(p)) != '.') { + pushback(p, c); + pushback(p, '.'); + goto retry; + } + case -1: /* EOF */ + case -2: /* end of a file */ + goto normal_newline; + default: + pushback(p, c); + goto normal_newline; + } + } + normal_newline: + p->cmd_start = TRUE; + p->lstate = EXPR_BEG; + return '\n'; + + case '*': + if ((c = nextc(p)) == '*') { + if ((c = nextc(p)) == '=') { + pylval.id = intern("**",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + c = tPOW; + } + else { + if (c == '=') { + pylval.id = intern_c('*'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + if (IS_SPCARG(c)) { + yywarning(p, "'*' interpreted as argument prefix"); + c = tSTAR; + } + else if (IS_BEG()) { + c = tSTAR; + } + else { + c = '*'; + } + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + return c; + + case '!': + c = nextc(p); + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + if (c == '@') { + return '!'; + } + } + else { + p->lstate = EXPR_BEG; + } + if (c == '=') { + return tNEQ; + } + if (c == '~') { + return tNMATCH; + } + pushback(p, c); + return '!'; + + case '=': + if (p->column == 1) { + static const char begin[] = "begin"; + static const char end[] = "\n=end"; + if (peeks(p, begin)) { + c = peekc_n(p, sizeof(begin)-1); + if (c < 0 || ISSPACE(c)) { + do { + if (!skips(p, end)) { + yyerror(p, "embedded document meets end of file"); + return 0; + } + c = nextc(p); + } while (!(c < 0 || ISSPACE(c))); + if (c != '\n') skip(p, '\n'); + p->lineno++; + p->column = 0; + goto retry; + } + } + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + if ((c = nextc(p)) == '=') { + if ((c = nextc(p)) == '=') { + return tEQQ; + } + pushback(p, c); + return tEQ; + } + if (c == '~') { + return tMATCH; + } + else if (c == '>') { + return tASSOC; + } + pushback(p, c); + return '='; + + case '<': + c = nextc(p); + if (c == '<' && + p->lstate != EXPR_DOT && + p->lstate != EXPR_CLASS && + !IS_END() && + (!IS_ARG() || space_seen)) { + int token = heredoc_identifier(p); + if (token) + return token; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + if (p->lstate == EXPR_CLASS) { + p->cmd_start = TRUE; + } + } + if (c == '=') { + if ((c = nextc(p)) == '>') { + return tCMP; + } + pushback(p, c); + return tLEQ; + } + if (c == '<') { + if ((c = nextc(p)) == '=') { + pylval.id = intern("<<",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + return tLSHFT; + } + pushback(p, c); + return '<'; + + case '>': + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + if ((c = nextc(p)) == '=') { + return tGEQ; + } + if (c == '>') { + if ((c = nextc(p)) == '=') { + pylval.id = intern(">>",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + return tRSHFT; + } + pushback(p, c); + return '>'; + + case '"': + p->lex_strterm = new_strterm(p, str_dquote, '"', 0); + return tSTRING_BEG; + + case '\'': + p->lex_strterm = new_strterm(p, str_squote, '\'', 0); + return parse_string(p); + + case '`': + if (p->lstate == EXPR_FNAME) { + p->lstate = EXPR_ENDFN; + return '`'; + } + if (p->lstate == EXPR_DOT) { + if (cmd_state) + p->lstate = EXPR_CMDARG; + else + p->lstate = EXPR_ARG; + return '`'; + } + p->lex_strterm = new_strterm(p, str_xquote, '`', 0); + return tXSTRING_BEG; + + case '?': + if (IS_END()) { + p->lstate = EXPR_VALUE; + return '?'; + } + c = nextc(p); + if (c < 0) { + yyerror(p, "incomplete character syntax"); + return 0; + } + if (ISSPACE(c)) { + if (!IS_ARG()) { + int c2; + switch (c) { + case ' ': + c2 = 's'; + break; + case '\n': + c2 = 'n'; + break; + case '\t': + c2 = 't'; + break; + case '\v': + c2 = 'v'; + break; + case '\r': + c2 = 'r'; + break; + case '\f': + c2 = 'f'; + break; + default: + c2 = 0; + break; + } + if (c2) { + char buf[256]; + snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2); + yyerror(p, buf); + } + } + ternary: + pushback(p, c); + p->lstate = EXPR_VALUE; + return '?'; + } + newtok(p); + /* need support UTF-8 if configured */ + if ((isalnum(c) || c == '_')) { + int c2 = nextc(p); + pushback(p, c2); + if ((isalnum(c2) || c2 == '_')) { + goto ternary; + } + } + if (c == '\\') { + c = read_escape(p); + tokadd(p, c); + } + else { + tokadd(p, c); + } + tokfix(p); + pylval.nd = new_str(p, tok(p), toklen(p)); + p->lstate = EXPR_END; + return tCHAR; + + case '&': + if ((c = nextc(p)) == '&') { + p->lstate = EXPR_BEG; + if ((c = nextc(p)) == '=') { + pylval.id = intern("&&",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + return tANDOP; + } + else if (c == '.') { + p->lstate = EXPR_DOT; + return tANDDOT; + } + else if (c == '=') { + pylval.id = intern_c('&'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + if (IS_SPCARG(c)) { + yywarning(p, "'&' interpreted as argument prefix"); + c = tAMPER; + } + else if (IS_BEG()) { + c = tAMPER; + } + else { + c = '&'; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + return c; + + case '|': + if ((c = nextc(p)) == '|') { + p->lstate = EXPR_BEG; + if ((c = nextc(p)) == '=') { + pylval.id = intern("||",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + return tOROP; + } + if (c == '=') { + pylval.id = intern_c('|'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + pushback(p, c); + return '|'; + + case '+': + c = nextc(p); + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + if (c == '@') { + return tUPLUS; + } + pushback(p, c); + return '+'; + } + if (c == '=') { + pylval.id = intern_c('+'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { + p->lstate = EXPR_BEG; + pushback(p, c); + if (c >= 0 && ISDIGIT(c)) { + c = '+'; + goto start_num; + } + return tUPLUS; + } + p->lstate = EXPR_BEG; + pushback(p, c); + return '+'; + + case '-': + c = nextc(p); + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + if (c == '@') { + return tUMINUS; + } + pushback(p, c); + return '-'; + } + if (c == '=') { + pylval.id = intern_c('-'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + if (c == '>') { + p->lstate = EXPR_ENDFN; + return tLAMBDA; + } + if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { + p->lstate = EXPR_BEG; + pushback(p, c); + if (c >= 0 && ISDIGIT(c)) { + return tUMINUS_NUM; + } + return tUMINUS; + } + p->lstate = EXPR_BEG; + pushback(p, c); + return '-'; + + case '.': + p->lstate = EXPR_BEG; + if ((c = nextc(p)) == '.') { + if ((c = nextc(p)) == '.') { + return tDOT3; + } + pushback(p, c); + return tDOT2; + } + pushback(p, c); + if (c >= 0 && ISDIGIT(c)) { + yyerror(p, "no .<digit> floating literal anymore; put 0 before dot"); + } + p->lstate = EXPR_DOT; + return '.'; + + start_num: + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int is_float, seen_point, seen_e, nondigit; + + is_float = seen_point = seen_e = nondigit = 0; + p->lstate = EXPR_END; + newtok(p); + if (c == '-' || c == '+') { + tokadd(p, c); + c = nextc(p); + } + if (c == '0') { +#define no_digits() do {yyerror(p,"numeric literal without digits"); return 0;} while (0) + int start = toklen(p); + c = nextc(p); + if (c == 'x' || c == 'X') { + /* hexadecimal */ + c = nextc(p); + if (c >= 0 && ISXDIGIT(c)) { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (!ISXDIGIT(c)) break; + nondigit = 0; + tokadd(p, tolower(c)); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + pylval.nd = new_int(p, tok(p), 16); + return tINTEGER; + } + if (c == 'b' || c == 'B') { + /* binary */ + c = nextc(p); + if (c == '0' || c == '1') { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (c != '0' && c != '1') break; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + pylval.nd = new_int(p, tok(p), 2); + return tINTEGER; + } + if (c == 'd' || c == 'D') { + /* decimal */ + c = nextc(p); + if (c >= 0 && ISDIGIT(c)) { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (!ISDIGIT(c)) break; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + pylval.nd = new_int(p, tok(p), 10); + return tINTEGER; + } + if (c == '_') { + /* 0_0 */ + goto octal_number; + } + if (c == 'o' || c == 'O') { + /* prefixed octal */ + c = nextc(p); + if (c < 0 || c == '_' || !ISDIGIT(c)) { + no_digits(); + } + } + if (c >= '0' && c <= '7') { + /* octal */ + octal_number: + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (c < '0' || c > '9') break; + if (c > '7') goto invalid_octal; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + + if (toklen(p) > start) { + pushback(p, c); + tokfix(p); + if (nondigit) goto trailing_uc; + pylval.nd = new_int(p, tok(p), 8); + return tINTEGER; + } + if (nondigit) { + pushback(p, c); + goto trailing_uc; + } + } + if (c > '7' && c <= '9') { + invalid_octal: + yyerror(p, "Invalid octal digit"); + } + else if (c == '.' || c == 'e' || c == 'E') { + tokadd(p, '0'); + } + else { + pushback(p, c); + pylval.nd = new_int(p, "0", 10); + return tINTEGER; + } + } + + for (;;) { + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + nondigit = 0; + tokadd(p, c); + break; + + case '.': + if (nondigit) goto trailing_uc; + if (seen_point || seen_e) { + goto decode_num; + } + else { + int c0 = nextc(p); + if (c0 < 0 || !ISDIGIT(c0)) { + pushback(p, c0); + goto decode_num; + } + c = c0; + } + tokadd(p, '.'); + tokadd(p, c); + is_float++; + seen_point++; + nondigit = 0; + break; + + case 'e': + case 'E': + if (nondigit) { + pushback(p, c); + c = nondigit; + goto decode_num; + } + if (seen_e) { + goto decode_num; + } + tokadd(p, c); + seen_e++; + is_float++; + nondigit = c; + c = nextc(p); + if (c != '-' && c != '+') continue; + tokadd(p, c); + nondigit = c; + break; + + case '_': /* '_' in number just ignored */ + if (nondigit) goto decode_num; + nondigit = c; + break; + + default: + goto decode_num; + } + c = nextc(p); + } + + decode_num: + pushback(p, c); + if (nondigit) { + trailing_uc: + yyerror_i(p, "trailing '%c' in number", nondigit); + } + tokfix(p); + if (is_float) { + double d; + char *endp; + + errno = 0; + d = mrb_float_read(tok(p), &endp); + if (d == 0 && endp == tok(p)) { + yywarning_s(p, "corrupted float value %s", tok(p)); + } + else if (errno == ERANGE) { + yywarning_s(p, "float %s out of range", tok(p)); + errno = 0; + } + pylval.nd = new_float(p, tok(p)); + return tFLOAT; + } + pylval.nd = new_int(p, tok(p), 10); + return tINTEGER; + } + + case ')': + case ']': + p->paren_nest--; + /* fall through */ + case '}': + COND_LEXPOP(); + CMDARG_LEXPOP(); + if (c == ')') + p->lstate = EXPR_ENDFN; + else + p->lstate = EXPR_ENDARG; + return c; + + case ':': + c = nextc(p); + if (c == ':') { + if (IS_BEG() || p->lstate == EXPR_CLASS || IS_SPCARG(-1)) { + p->lstate = EXPR_BEG; + return tCOLON3; + } + p->lstate = EXPR_DOT; + return tCOLON2; + } + if (IS_END() || ISSPACE(c)) { + pushback(p, c); + p->lstate = EXPR_BEG; + return ':'; + } + pushback(p, c); + p->lstate = EXPR_FNAME; + return tSYMBEG; + + case '/': + if (IS_BEG()) { + p->lex_strterm = new_strterm(p, str_regexp, '/', 0); + return tREGEXP_BEG; + } + if ((c = nextc(p)) == '=') { + pylval.id = intern_c('/'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + pushback(p, c); + if (IS_SPCARG(c)) { + p->lex_strterm = new_strterm(p, str_regexp, '/', 0); + return tREGEXP_BEG; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + return '/'; + + case '^': + if ((c = nextc(p)) == '=') { + pylval.id = intern_c('^'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + pushback(p, c); + return '^'; + + case ';': + p->lstate = EXPR_BEG; + return ';'; + + case ',': + p->lstate = EXPR_BEG; + return ','; + + case '~': + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + if ((c = nextc(p)) != '@') { + pushback(p, c); + } + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + return '~'; + + case '(': + if (IS_BEG()) { + c = tLPAREN; + } + else if (IS_SPCARG(-1)) { + c = tLPAREN_ARG; + } + p->paren_nest++; + COND_PUSH(0); + CMDARG_PUSH(0); + p->lstate = EXPR_BEG; + return c; + + case '[': + p->paren_nest++; + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + if ((c = nextc(p)) == ']') { + if ((c = nextc(p)) == '=') { + return tASET; + } + pushback(p, c); + return tAREF; + } + pushback(p, c); + return '['; + } + else if (IS_BEG()) { + c = tLBRACK; + } + else if (IS_ARG() && space_seen) { + c = tLBRACK; + } + p->lstate = EXPR_BEG; + COND_PUSH(0); + CMDARG_PUSH(0); + return c; + + case '{': + if (p->lpar_beg && p->lpar_beg == p->paren_nest) { + p->lstate = EXPR_BEG; + p->lpar_beg = 0; + p->paren_nest--; + COND_PUSH(0); + CMDARG_PUSH(0); + return tLAMBEG; + } + if (IS_ARG() || p->lstate == EXPR_END || p->lstate == EXPR_ENDFN) + c = '{'; /* block (primary) */ + else if (p->lstate == EXPR_ENDARG) + c = tLBRACE_ARG; /* block (expr) */ + else + c = tLBRACE; /* hash */ + COND_PUSH(0); + CMDARG_PUSH(0); + p->lstate = EXPR_BEG; + return c; + + case '\\': + c = nextc(p); + if (c == '\n') { + p->lineno++; + p->column = 0; + space_seen = 1; + goto retry; /* skip \\n */ + } + pushback(p, c); + return '\\'; + + case '%': + if (IS_BEG()) { + int term; + int paren; + + c = nextc(p); + quotation: + if (c < 0 || !ISALNUM(c)) { + term = c; + c = 'Q'; + } + else { + term = nextc(p); + if (isalnum(term)) { + yyerror(p, "unknown type of %string"); + return 0; + } + } + if (c < 0 || term < 0) { + yyerror(p, "unterminated quoted string meets end of file"); + return 0; + } + paren = term; + if (term == '(') term = ')'; + else if (term == '[') term = ']'; + else if (term == '{') term = '}'; + else if (term == '<') term = '>'; + else paren = 0; + + switch (c) { + case 'Q': + p->lex_strterm = new_strterm(p, str_dquote, term, paren); + return tSTRING_BEG; + + case 'q': + p->lex_strterm = new_strterm(p, str_squote, term, paren); + return parse_string(p); + + case 'W': + p->lex_strterm = new_strterm(p, str_dword, term, paren); + return tWORDS_BEG; + + case 'w': + p->lex_strterm = new_strterm(p, str_sword, term, paren); + return tWORDS_BEG; + + case 'x': + p->lex_strterm = new_strterm(p, str_xquote, term, paren); + return tXSTRING_BEG; + + case 'r': + p->lex_strterm = new_strterm(p, str_regexp, term, paren); + return tREGEXP_BEG; + + case 's': + p->lex_strterm = new_strterm(p, str_ssym, term, paren); + return tSYMBEG; + + case 'I': + p->lex_strterm = new_strterm(p, str_dsymbols, term, paren); + return tSYMBOLS_BEG; + + case 'i': + p->lex_strterm = new_strterm(p, str_ssymbols, term, paren); + return tSYMBOLS_BEG; + + default: + yyerror(p, "unknown type of %string"); + return 0; + } + } + if ((c = nextc(p)) == '=') { + pylval.id = intern_c('%'); + p->lstate = EXPR_BEG; + return tOP_ASGN; + } + if (IS_SPCARG(c)) { + goto quotation; + } + if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { + p->lstate = EXPR_ARG; + } + else { + p->lstate = EXPR_BEG; + } + pushback(p, c); + return '%'; + + case '$': + p->lstate = EXPR_END; + token_column = newtok(p); + c = nextc(p); + if (c < 0) { + yyerror(p, "incomplete global variable syntax"); + return 0; + } + switch (c) { + case '_': /* $_: last read line string */ + c = nextc(p); + if (c >= 0 && identchar(c)) { /* if there is more after _ it is a variable */ + tokadd(p, '$'); + tokadd(p, c); + break; + } + pushback(p, c); + c = '_'; + /* fall through */ + case '~': /* $~: match-data */ + case '*': /* $*: argv */ + case '$': /* $$: pid */ + case '?': /* $?: last status */ + case '!': /* $!: error string */ + case '@': /* $@: error position */ + case '/': /* $/: input record separator */ + case '\\': /* $\: output record separator */ + case ';': /* $;: field separator */ + case ',': /* $,: output field separator */ + case '.': /* $.: last read line number */ + case '=': /* $=: ignorecase */ + case ':': /* $:: load path */ + case '<': /* $<: reading filename */ + case '>': /* $>: default output handle */ + case '\"': /* $": already loaded files */ + tokadd(p, '$'); + tokadd(p, c); + tokfix(p); + pylval.id = intern_cstr(tok(p)); + return tGVAR; + + case '-': + tokadd(p, '$'); + tokadd(p, c); + c = nextc(p); + pushback(p, c); + gvar: + tokfix(p); + pylval.id = intern_cstr(tok(p)); + return tGVAR; + + case '&': /* $&: last match */ + case '`': /* $`: string before last match */ + case '\'': /* $': string after last match */ + case '+': /* $+: string matches last pattern */ + if (last_state == EXPR_FNAME) { + tokadd(p, '$'); + tokadd(p, c); + goto gvar; + } + pylval.nd = new_back_ref(p, c); + return tBACK_REF; + + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + do { + tokadd(p, c); + c = nextc(p); + } while (c >= 0 && isdigit(c)); + pushback(p, c); + if (last_state == EXPR_FNAME) goto gvar; + tokfix(p); + { + unsigned long n = strtoul(tok(p), NULL, 10); + if (n > INT_MAX) { + yyerror_i(p, "capture group index must be <= %d", INT_MAX); + return 0; + } + pylval.nd = new_nth_ref(p, (int)n); + } + return tNTH_REF; + + default: + if (!identchar(c)) { + pushback(p, c); + return '$'; + } + /* fall through */ + case '0': + tokadd(p, '$'); + } + break; + + case '@': + c = nextc(p); + token_column = newtok(p); + tokadd(p, '@'); + if (c == '@') { + tokadd(p, '@'); + c = nextc(p); + } + if (c < 0) { + if (p->tidx == 1) { + yyerror(p, "incomplete instance variable syntax"); + } + else { + yyerror(p, "incomplete class variable syntax"); + } + return 0; + } + else if (isdigit(c)) { + if (p->tidx == 1) { + yyerror_i(p, "'@%c' is not allowed as an instance variable name", c); + } + else { + yyerror_i(p, "'@@%c' is not allowed as a class variable name", c); + } + return 0; + } + if (!identchar(c)) { + pushback(p, c); + return '@'; + } + break; + + case '_': + token_column = newtok(p); + break; + + default: + if (!identchar(c)) { + yyerror_i(p, "Invalid char '\\x%02X' in expression", c); + goto retry; + } + + token_column = newtok(p); + break; + } + + do { + tokadd(p, c); + c = nextc(p); + if (c < 0) break; + } while (identchar(c)); + if (token_column == 0 && toklen(p) == 7 && (c < 0 || c == '\n') && + strncmp(tok(p), "__END__", toklen(p)) == 0) + return -1; + + switch (tok(p)[0]) { + case '@': case '$': + pushback(p, c); + break; + default: + if ((c == '!' || c == '?') && !peek(p, '=')) { + tokadd(p, c); + } + else { + pushback(p, c); + } + } + tokfix(p); + { + int result = 0; + + switch (tok(p)[0]) { + case '$': + p->lstate = EXPR_END; + result = tGVAR; + break; + case '@': + p->lstate = EXPR_END; + if (tok(p)[1] == '@') + result = tCVAR; + else + result = tIVAR; + break; + + default: + if (toklast(p) == '!' || toklast(p) == '?') { + result = tFID; + } + else { + if (p->lstate == EXPR_FNAME) { + if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') && + (!peek(p, '=') || (peek_n(p, '>', 1)))) { + result = tIDENTIFIER; + tokadd(p, c); + tokfix(p); + } + else { + pushback(p, c); + } + } + if (result == 0 && ISUPPER(tok(p)[0])) { + result = tCONSTANT; + } + else { + result = tIDENTIFIER; + } + } + + if (IS_LABEL_POSSIBLE()) { + if (IS_LABEL_SUFFIX(0)) { + p->lstate = EXPR_BEG; + nextc(p); + tokfix(p); + pylval.id = intern_cstr(tok(p)); + return tLABEL; + } + } + if (p->lstate != EXPR_DOT) { + const struct kwtable *kw; + + /* See if it is a reserved word. */ + kw = mrb_reserved_word(tok(p), toklen(p)); + if (kw) { + enum mrb_lex_state_enum state = p->lstate; + pylval.num = p->lineno; + p->lstate = kw->state; + if (state == EXPR_FNAME) { + pylval.id = intern_cstr(kw->name); + return kw->id[0]; + } + if (p->lstate == EXPR_BEG) { + p->cmd_start = TRUE; + } + if (kw->id[0] == keyword_do) { + if (p->lpar_beg && p->lpar_beg == p->paren_nest) { + p->lpar_beg = 0; + p->paren_nest--; + return keyword_do_LAMBDA; + } + if (COND_P()) return keyword_do_cond; + if (CMDARG_P() && state != EXPR_CMDARG) + return keyword_do_block; + if (state == EXPR_ENDARG || state == EXPR_BEG) + return keyword_do_block; + return keyword_do; + } + if (state == EXPR_BEG || state == EXPR_VALUE) + return kw->id[0]; + else { + if (kw->id[0] != kw->id[1]) + p->lstate = EXPR_BEG; + return kw->id[1]; + } + } + } + + if (IS_BEG() || p->lstate == EXPR_DOT || IS_ARG()) { + if (cmd_state) { + p->lstate = EXPR_CMDARG; + } + else { + p->lstate = EXPR_ARG; + } + } + else if (p->lstate == EXPR_FNAME) { + p->lstate = EXPR_ENDFN; + } + else { + p->lstate = EXPR_END; + } + } + { + mrb_sym ident = intern_cstr(tok(p)); + + pylval.id = ident; +#if 0 + if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) { + p->lstate = EXPR_END; + } +#endif + } + return result; + } +} + +static int +yylex(void *lval, parser_state *p) +{ + p->ylval = lval; + return parser_yylex(p); +} + +static void +parser_init_cxt(parser_state *p, mrbc_context *cxt) +{ + if (!cxt) return; + if (cxt->filename) mrb_parser_set_filename(p, cxt->filename); + if (cxt->lineno) p->lineno = cxt->lineno; + if (cxt->syms) { + int i; + + p->locals = cons(0,0); + for (i=0; i<cxt->slen; i++) { + local_add_f(p, cxt->syms[i]); + } + } + p->capture_errors = cxt->capture_errors; + p->no_optimize = cxt->no_optimize; + if (cxt->partial_hook) { + p->cxt = cxt; + } +} + +static void +parser_update_cxt(parser_state *p, mrbc_context *cxt) +{ + node *n, *n0; + int i = 0; + + if (!cxt) return; + if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return; + n0 = n = p->tree->cdr->car; + while (n) { + i++; + n = n->cdr; + } + cxt->syms = (mrb_sym *)mrb_realloc(p->mrb, cxt->syms, i*sizeof(mrb_sym)); + cxt->slen = i; + for (i=0, n=n0; n; i++,n=n->cdr) { + cxt->syms[i] = sym(n->car); + } +} + +void mrb_codedump_all(mrb_state*, struct RProc*); +void mrb_parser_dump(mrb_state *mrb, node *tree, int offset); + +MRB_API void +mrb_parser_parse(parser_state *p, mrbc_context *c) +{ + struct mrb_jmpbuf buf1; + p->jmp = &buf1; + + MRB_TRY(p->jmp) { + int n = 1; + + p->cmd_start = TRUE; + p->in_def = p->in_single = 0; + p->nerr = p->nwarn = 0; + p->lex_strterm = NULL; + + parser_init_cxt(p, c); + + if (p->mrb->jmp) { + n = yyparse(p); + } + else { + struct mrb_jmpbuf buf2; + + p->mrb->jmp = &buf2; + MRB_TRY(p->mrb->jmp) { + n = yyparse(p); + } + MRB_CATCH(p->mrb->jmp) { + p->nerr++; + } + MRB_END_EXC(p->mrb->jmp); + p->mrb->jmp = 0; + } + if (n != 0 || p->nerr > 0) { + p->tree = 0; + return; + } + if (!p->tree) { + p->tree = new_nil(p); + } + parser_update_cxt(p, c); + if (c && c->dump_result) { + mrb_parser_dump(p->mrb, p->tree, 0); + } + } + MRB_CATCH(p->jmp) { + yyerror(p, "memory allocation error"); + p->nerr++; + p->tree = 0; + return; + } + MRB_END_EXC(p->jmp); +} + +MRB_API parser_state* +mrb_parser_new(mrb_state *mrb) +{ + mrb_pool *pool; + parser_state *p; + static const parser_state parser_state_zero = { 0 }; + + pool = mrb_pool_open(mrb); + if (!pool) return NULL; + p = (parser_state *)mrb_pool_alloc(pool, sizeof(parser_state)); + if (!p) return NULL; + + *p = parser_state_zero; + p->mrb = mrb; + p->pool = pool; + + p->s = p->send = NULL; +#ifndef MRB_DISABLE_STDIO + p->f = NULL; +#endif + + p->cmd_start = TRUE; + p->in_def = p->in_single = 0; + + p->capture_errors = FALSE; + p->lineno = 1; + p->column = 0; +#if defined(PARSER_TEST) || defined(PARSER_DEBUG) + yydebug = 1; +#endif + p->tsiz = MRB_PARSER_TOKBUF_SIZE; + p->tokbuf = p->buf; + + p->lex_strterm = NULL; + p->all_heredocs = p->parsing_heredoc = NULL; + p->lex_strterm_before_heredoc = NULL; + + p->current_filename_index = -1; + p->filename_table = NULL; + p->filename_table_length = 0; + + return p; +} + +MRB_API void +mrb_parser_free(parser_state *p) { + if (p->tokbuf != p->buf) { + mrb_free(p->mrb, p->tokbuf); + } + mrb_pool_close(p->pool); +} + +MRB_API mrbc_context* +mrbc_context_new(mrb_state *mrb) +{ + return (mrbc_context *)mrb_calloc(mrb, 1, sizeof(mrbc_context)); +} + +MRB_API void +mrbc_context_free(mrb_state *mrb, mrbc_context *cxt) +{ + mrb_free(mrb, cxt->filename); + mrb_free(mrb, cxt->syms); + mrb_free(mrb, cxt); +} + +MRB_API const char* +mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s) +{ + if (s) { + size_t len = strlen(s); + char *p = (char *)mrb_malloc(mrb, len + 1); + + memcpy(p, s, len + 1); + if (c->filename) { + mrb_free(mrb, c->filename); + } + c->filename = p; + } + return c->filename; +} + +MRB_API void +mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*func)(struct mrb_parser_state*), void *data) +{ + c->partial_hook = func; + c->partial_data = data; +} + +MRB_API void +mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) +{ + mrb_sym sym; + size_t i; + mrb_sym* new_table; + + sym = mrb_intern_cstr(p->mrb, f); + p->filename = mrb_sym2name_len(p->mrb, sym, NULL); + p->lineno = (p->filename_table_length > 0)? 0 : 1; + + for (i = 0; i < p->filename_table_length; ++i) { + if (p->filename_table[i] == sym) { + p->current_filename_index = (int)i; + return; + } + } + + p->current_filename_index = (int)p->filename_table_length++; + + new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length); + if (p->filename_table) { + memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length); + } + p->filename_table = new_table; + p->filename_table[p->filename_table_length - 1] = sym; +} + +MRB_API char const* +mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { + if (idx >= p->filename_table_length) { return NULL; } + else { + return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL); + } +} + +#ifndef MRB_DISABLE_STDIO +MRB_API parser_state* +mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c) +{ + parser_state *p; + + p = mrb_parser_new(mrb); + if (!p) return NULL; + p->s = p->send = NULL; + p->f = f; + + mrb_parser_parse(p, c); + return p; +} +#endif + +MRB_API parser_state* +mrb_parse_nstring(mrb_state *mrb, const char *s, size_t len, mrbc_context *c) +{ + parser_state *p; + + p = mrb_parser_new(mrb); + if (!p) return NULL; + p->s = s; + p->send = s + len; + + mrb_parser_parse(p, c); + return p; +} + +MRB_API parser_state* +mrb_parse_string(mrb_state *mrb, const char *s, mrbc_context *c) +{ + return mrb_parse_nstring(mrb, s, strlen(s), c); +} + +MRB_API mrb_value +mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c) +{ + struct RClass *target = mrb->object_class; + struct RProc *proc; + mrb_value v; + unsigned int keep = 0; + + if (!p) { + return mrb_undef_value(); + } + if (!p->tree || p->nerr) { + if (c) c->parser_nerr = p->nerr; + if (p->capture_errors) { + char buf[256]; + int n; + + n = snprintf(buf, sizeof(buf), "line %d: %s\n", + p->error_buffer[0].lineno, p->error_buffer[0].message); + mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n)); + mrb_parser_free(p); + return mrb_undef_value(); + } + else { + if (mrb->exc == NULL) { + mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error")); + } + mrb_parser_free(p); + return mrb_undef_value(); + } + } + proc = mrb_generate_code(mrb, p); + mrb_parser_free(p); + if (proc == NULL) { + if (mrb->exc == NULL) { + mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "codegen error")); + } + return mrb_undef_value(); + } + if (c) { + if (c->dump_result) mrb_codedump_all(mrb, proc); + if (c->no_exec) return mrb_obj_value(proc); + if (c->target_class) { + target = c->target_class; + } + if (c->keep_lv) { + keep = c->slen + 1; + } + else { + c->keep_lv = TRUE; + } + } + proc->target_class = target; + if (mrb->c->ci) { + mrb->c->ci->target_class = target; + } + v = mrb_top_run(mrb, proc, mrb_top_self(mrb), keep); + if (mrb->exc) return mrb_nil_value(); + return v; +} + +#ifndef MRB_DISABLE_STDIO +MRB_API mrb_value +mrb_load_file_cxt(mrb_state *mrb, FILE *f, mrbc_context *c) +{ + return mrb_load_exec(mrb, mrb_parse_file(mrb, f, c), c); +} + +MRB_API mrb_value +mrb_load_file(mrb_state *mrb, FILE *f) +{ + return mrb_load_file_cxt(mrb, f, NULL); +} +#endif + +MRB_API mrb_value +mrb_load_nstring_cxt(mrb_state *mrb, const char *s, size_t len, mrbc_context *c) +{ + return mrb_load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c); +} + +MRB_API mrb_value +mrb_load_nstring(mrb_state *mrb, const char *s, size_t len) +{ + return mrb_load_nstring_cxt(mrb, s, len, NULL); +} + +MRB_API mrb_value +mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *c) +{ + return mrb_load_nstring_cxt(mrb, s, strlen(s), c); +} + +MRB_API mrb_value +mrb_load_string(mrb_state *mrb, const char *s) +{ + return mrb_load_string_cxt(mrb, s, NULL); +} + +#ifndef MRB_DISABLE_STDIO + +static void +dump_prefix(node *tree, int offset) +{ + printf("%05d ", tree->lineno); + while (offset--) { + putc(' ', stdout); + putc(' ', stdout); + } +} + +static void +dump_recur(mrb_state *mrb, node *tree, int offset) +{ + while (tree) { + mrb_parser_dump(mrb, tree->car, offset); + tree = tree->cdr; + } +} + +#endif + +void +mrb_parser_dump(mrb_state *mrb, node *tree, int offset) +{ +#ifndef MRB_DISABLE_STDIO + int nodetype; + + if (!tree) return; + again: + dump_prefix(tree, offset); + nodetype = (int)(intptr_t)tree->car; + tree = tree->cdr; + switch (nodetype) { + case NODE_BEGIN: + printf("NODE_BEGIN:\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_RESCUE: + printf("NODE_RESCUE:\n"); + if (tree->car) { + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + } + tree = tree->cdr; + if (tree->car) { + node *n2 = tree->car; + + dump_prefix(n2, offset+1); + printf("rescue:\n"); + while (n2) { + node *n3 = n2->car; + if (n3->car) { + dump_prefix(n2, offset+2); + printf("handle classes:\n"); + dump_recur(mrb, n3->car, offset+3); + } + if (n3->cdr->car) { + dump_prefix(n3, offset+2); + printf("exc_var:\n"); + mrb_parser_dump(mrb, n3->cdr->car, offset+3); + } + if (n3->cdr->cdr->car) { + dump_prefix(n3, offset+2); + printf("rescue body:\n"); + mrb_parser_dump(mrb, n3->cdr->cdr->car, offset+3); + } + n2 = n2->cdr; + } + } + tree = tree->cdr; + if (tree->car) { + dump_prefix(tree, offset+1); + printf("else:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + } + break; + + case NODE_ENSURE: + printf("NODE_ENSURE:\n"); + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + dump_prefix(tree, offset+1); + printf("ensure:\n"); + mrb_parser_dump(mrb, tree->cdr->cdr, offset+2); + break; + + case NODE_LAMBDA: + printf("NODE_BLOCK:\n"); + goto block; + + case NODE_BLOCK: + block: + printf("NODE_BLOCK:\n"); + tree = tree->cdr; + if (tree->car) { + node *n = tree->car; + + if (n->car) { + dump_prefix(n, offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(n2, offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } + } + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + if (n->cdr) { + dump_prefix(n, offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); + } + } + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); + break; + + case NODE_IF: + printf("NODE_IF:\n"); + dump_prefix(tree, offset+1); + printf("cond:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + dump_prefix(tree, offset+1); + printf("then:\n"); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); + if (tree->cdr->cdr->car) { + dump_prefix(tree, offset+1); + printf("else:\n"); + mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2); + } + break; + + case NODE_AND: + printf("NODE_AND:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); + break; + + case NODE_OR: + printf("NODE_OR:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); + break; + + case NODE_CASE: + printf("NODE_CASE:\n"); + if (tree->car) { + mrb_parser_dump(mrb, tree->car, offset+1); + } + tree = tree->cdr; + while (tree) { + dump_prefix(tree, offset+1); + printf("case:\n"); + dump_recur(mrb, tree->car->car, offset+2); + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->car->cdr, offset+2); + tree = tree->cdr; + } + break; + + case NODE_WHILE: + printf("NODE_WHILE:\n"); + dump_prefix(tree, offset+1); + printf("cond:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + break; + + case NODE_UNTIL: + printf("NODE_UNTIL:\n"); + dump_prefix(tree, offset+1); + printf("cond:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + break; + + case NODE_FOR: + printf("NODE_FOR:\n"); + dump_prefix(tree, offset+1); + printf("var:\n"); + { + node *n2 = tree->car; + + if (n2->car) { + dump_prefix(n2, offset+2); + printf("pre:\n"); + dump_recur(mrb, n2->car, offset+3); + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(n2, offset+2); + printf("rest:\n"); + mrb_parser_dump(mrb, n2->car, offset+3); + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(n2, offset+2); + printf("post:\n"); + dump_recur(mrb, n2->car, offset+3); + } + } + } + } + tree = tree->cdr; + dump_prefix(tree, offset+1); + printf("in:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + tree = tree->cdr; + dump_prefix(tree, offset+1); + printf("do:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + break; + + case NODE_SCOPE: + printf("NODE_SCOPE:\n"); + { + node *n2 = tree->car; + mrb_bool first_lval = TRUE; + + if (n2 && (n2->car || n2->cdr)) { + dump_prefix(n2, offset+1); + printf("local variables:\n"); + dump_prefix(n2, offset+2); + while (n2) { + if (n2->car) { + if (!first_lval) printf(", "); + printf("%s", mrb_sym2name(mrb, sym(n2->car))); + first_lval = FALSE; + } + n2 = n2->cdr; + } + printf("\n"); + } + } + tree = tree->cdr; + offset++; + goto again; + + case NODE_FCALL: + case NODE_CALL: + case NODE_SCALL: + switch (nodetype) { + case NODE_FCALL: + printf("NODE_FCALL:\n"); break; + case NODE_CALL: + printf("NODE_CALL(.):\n"); break; + case NODE_SCALL: + printf("NODE_SCALL(&.):\n"); break; + default: + break; + } + mrb_parser_dump(mrb, tree->car, offset+1); + dump_prefix(tree, offset+1); + printf("method='%s' (%d)\n", + mrb_sym2name(mrb, sym(tree->cdr->car)), + (int)(intptr_t)tree->cdr->car); + tree = tree->cdr->cdr->car; + if (tree) { + dump_prefix(tree, offset+1); + printf("args:\n"); + dump_recur(mrb, tree->car, offset+2); + if (tree->cdr) { + dump_prefix(tree, offset+1); + printf("block:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + } + } + break; + + case NODE_DOT2: + printf("NODE_DOT2:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); + break; + + case NODE_DOT3: + printf("NODE_DOT3:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); + break; + + case NODE_COLON2: + printf("NODE_COLON2:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr))); + break; + + case NODE_COLON3: + printf("NODE_COLON3: ::%s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_ARRAY: + printf("NODE_ARRAY:\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_HASH: + printf("NODE_HASH:\n"); + while (tree) { + dump_prefix(tree, offset+1); + printf("key:\n"); + mrb_parser_dump(mrb, tree->car->car, offset+2); + dump_prefix(tree, offset+1); + printf("value:\n"); + mrb_parser_dump(mrb, tree->car->cdr, offset+2); + tree = tree->cdr; + } + break; + + case NODE_SPLAT: + printf("NODE_SPLAT:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_ASGN: + printf("NODE_ASGN:\n"); + dump_prefix(tree, offset+1); + printf("lhs:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + dump_prefix(tree, offset+1); + printf("rhs:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + break; + + case NODE_MASGN: + printf("NODE_MASGN:\n"); + dump_prefix(tree, offset+1); + printf("mlhs:\n"); + { + node *n2 = tree->car; + + if (n2->car) { + dump_prefix(tree, offset+2); + printf("pre:\n"); + dump_recur(mrb, n2->car, offset+3); + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(n2, offset+2); + printf("rest:\n"); + if (n2->car == (node*)-1) { + dump_prefix(n2, offset+2); + printf("(empty)\n"); + } + else { + mrb_parser_dump(mrb, n2->car, offset+3); + } + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(n2, offset+2); + printf("post:\n"); + dump_recur(mrb, n2->car, offset+3); + } + } + } + } + dump_prefix(tree, offset+1); + printf("rhs:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + break; + + case NODE_OP_ASGN: + printf("NODE_OP_ASGN:\n"); + dump_prefix(tree, offset+1); + printf("lhs:\n"); + mrb_parser_dump(mrb, tree->car, offset+2); + tree = tree->cdr; + dump_prefix(tree, offset+1); + printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car); + tree = tree->cdr; + mrb_parser_dump(mrb, tree->car, offset+1); + break; + + case NODE_SUPER: + printf("NODE_SUPER:\n"); + if (tree) { + dump_prefix(tree, offset+1); + printf("args:\n"); + dump_recur(mrb, tree->car, offset+2); + if (tree->cdr) { + dump_prefix(tree, offset+1); + printf("block:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); + } + } + break; + + case NODE_ZSUPER: + printf("NODE_ZSUPER\n"); + break; + + case NODE_RETURN: + printf("NODE_RETURN:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_YIELD: + printf("NODE_YIELD:\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_BREAK: + printf("NODE_BREAK:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_NEXT: + printf("NODE_NEXT:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_REDO: + printf("NODE_REDO\n"); + break; + + case NODE_RETRY: + printf("NODE_RETRY\n"); + break; + + case NODE_LVAR: + printf("NODE_LVAR %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_GVAR: + printf("NODE_GVAR %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_IVAR: + printf("NODE_IVAR %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_CVAR: + printf("NODE_CVAR %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_CONST: + printf("NODE_CONST %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_MATCH: + printf("NODE_MATCH:\n"); + dump_prefix(tree, offset + 1); + printf("lhs:\n"); + mrb_parser_dump(mrb, tree->car, offset + 2); + dump_prefix(tree, offset + 1); + printf("rhs:\n"); + mrb_parser_dump(mrb, tree->cdr, offset + 2); + break; + + case NODE_BACK_REF: + printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree); + break; + + case NODE_NTH_REF: + printf("NODE_NTH_REF: $%" MRB_PRId "\n", (mrb_int)(intptr_t)tree); + break; + + case NODE_ARG: + printf("NODE_ARG %s\n", mrb_sym2name(mrb, sym(tree))); + break; + + case NODE_BLOCK_ARG: + printf("NODE_BLOCK_ARG:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_INT: + printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car); + break; + + case NODE_FLOAT: + printf("NODE_FLOAT %s\n", (char*)tree); + break; + + case NODE_NEGATE: + printf("NODE_NEGATE\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_STR: + printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); + break; + + case NODE_DSTR: + printf("NODE_DSTR\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_XSTR: + printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); + break; + + case NODE_DXSTR: + printf("NODE_DXSTR\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_REGX: + printf("NODE_REGX /%s/%s\n", (char*)tree->car, (char*)tree->cdr); + break; + + case NODE_DREGX: + printf("NODE_DREGX\n"); + dump_recur(mrb, tree->car, offset+1); + dump_prefix(tree, offset); + printf("tail: %s\n", (char*)tree->cdr->cdr->car); + if (tree->cdr->cdr->cdr->car) { + dump_prefix(tree, offset); + printf("opt: %s\n", (char*)tree->cdr->cdr->cdr->car); + } + if (tree->cdr->cdr->cdr->cdr) { + dump_prefix(tree, offset); + printf("enc: %s\n", (char*)tree->cdr->cdr->cdr->cdr); + } + break; + + case NODE_SYM: + printf("NODE_SYM :%s (%d)\n", mrb_sym2name(mrb, sym(tree)), + (int)(intptr_t)tree); + break; + + case NODE_SELF: + printf("NODE_SELF\n"); + break; + + case NODE_NIL: + printf("NODE_NIL\n"); + break; + + case NODE_TRUE: + printf("NODE_TRUE\n"); + break; + + case NODE_FALSE: + printf("NODE_FALSE\n"); + break; + + case NODE_ALIAS: + printf("NODE_ALIAS %s %s:\n", + mrb_sym2name(mrb, sym(tree->car)), + mrb_sym2name(mrb, sym(tree->cdr))); + break; + + case NODE_UNDEF: + printf("NODE_UNDEF"); + { + node *t = tree; + while (t) { + printf(" %s", mrb_sym2name(mrb, sym(t->car))); + t = t->cdr; + } + } + printf(":\n"); + break; + + case NODE_CLASS: + printf("NODE_CLASS:\n"); + if (tree->car->car == (node*)0) { + dump_prefix(tree, offset+1); + printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + else if (tree->car->car == (node*)1) { + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + else { + mrb_parser_dump(mrb, tree->car->car, offset+1); + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + if (tree->cdr->car) { + dump_prefix(tree, offset+1); + printf("super:\n"); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); + } + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2); + break; + + case NODE_MODULE: + printf("NODE_MODULE:\n"); + if (tree->car->car == (node*)0) { + dump_prefix(tree, offset+1); + printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + else if (tree->car->car == (node*)1) { + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + else { + mrb_parser_dump(mrb, tree->car->car, offset+1); + dump_prefix(tree, offset+1); + printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); + } + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); + break; + + case NODE_SCLASS: + printf("NODE_SCLASS:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + dump_prefix(tree, offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); + break; + + case NODE_DEF: + printf("NODE_DEF:\n"); + dump_prefix(tree, offset+1); + printf("%s\n", mrb_sym2name(mrb, sym(tree->car))); + tree = tree->cdr; + { + node *n2 = tree->car; + mrb_bool first_lval = TRUE; + + if (n2 && (n2->car || n2->cdr)) { + dump_prefix(n2, offset+1); + printf("local variables:\n"); + dump_prefix(n2, offset+2); + while (n2) { + if (n2->car) { + if (!first_lval) printf(", "); + printf("%s", mrb_sym2name(mrb, sym(n2->car))); + first_lval = FALSE; + } + n2 = n2->cdr; + } + printf("\n"); + } + } + tree = tree->cdr; + if (tree->car) { + node *n = tree->car; + + if (n->car) { + dump_prefix(n, offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(n2, offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } + } + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + if (n->cdr) { + dump_prefix(n, offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); + } + } + mrb_parser_dump(mrb, tree->cdr->car, offset+1); + break; + + case NODE_SDEF: + printf("NODE_SDEF:\n"); + mrb_parser_dump(mrb, tree->car, offset+1); + tree = tree->cdr; + dump_prefix(tree, offset+1); + printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); + tree = tree->cdr->cdr; + if (tree->car) { + node *n = tree->car; + + if (n->car) { + dump_prefix(n, offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(n2, offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } + } + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n) { + dump_prefix(n, offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + } + } + tree = tree->cdr; + mrb_parser_dump(mrb, tree->car, offset+1); + break; + + case NODE_POSTEXE: + printf("NODE_POSTEXE:\n"); + mrb_parser_dump(mrb, tree, offset+1); + break; + + case NODE_HEREDOC: + printf("NODE_HEREDOC (<<%s):\n", ((parser_heredoc_info*)tree)->term); + dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); + break; + + default: + printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype); + break; + } +#endif +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/mrbgem.rake new file mode 100644 index 000000000..3bf6d6ae3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-compiler/mrbgem.rake @@ -0,0 +1,40 @@ +MRuby::Gem::Specification.new 'mruby-compiler' do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby compiler library' + + current_dir = spec.dir + current_build_dir = spec.build_dir + + lex_def = "#{current_dir}/core/lex.def" + core_objs = Dir.glob("#{current_dir}/core/*.c").map { |f| + next nil if build.cxx_exception_enabled? and f =~ /(codegen).c$/ + objfile(f.pathmap("#{current_build_dir}/core/%n")) + }.compact + + if build.cxx_exception_enabled? + core_objs << + build.compile_as_cxx("#{current_build_dir}/core/y.tab.c", "#{current_build_dir}/core/y.tab.cxx", + objfile("#{current_build_dir}/y.tab"), ["#{current_dir}/core"]) << + build.compile_as_cxx("#{current_dir}/core/codegen.c", "#{current_build_dir}/core/codegen.cxx") + else + core_objs << objfile("#{current_build_dir}/core/y.tab") + file objfile("#{current_build_dir}/core/y.tab") => "#{current_build_dir}/core/y.tab.c" do |t| + cc.run t.name, t.prerequisites.first, [], ["#{current_dir}/core"] + end + end + file objfile("#{current_build_dir}/core/y.tab") => lex_def + + # Parser + file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y"] do |t| + yacc.run t.name, t.prerequisites.first + end + + # Lexical analyzer + file lex_def => "#{current_dir}/core/keywords" do |t| + gperf.run t.name, t.prerequisites.first + end + + file libfile("#{build.build_dir}/lib/libmruby_core") => core_objs + build.libmruby << core_objs +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-ext/mrbgem.rake new file mode 100644 index 000000000..d5816b80f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-enum-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Enumerable module extension' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-ext/mrblib/enum.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-ext/mrblib/enum.rb new file mode 100644 index 000000000..7741e515d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -0,0 +1,711 @@ +## +# Enumerable +# +module Enumerable + ## + # call-seq: + # enum.drop(n) -> array + # + # Drops first n elements from <i>enum</i>, and returns rest elements + # in an array. + # + # a = [1, 2, 3, 4, 5, 0] + # a.drop(3) #=> [4, 5, 0] + + def drop(n) + raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + raise ArgumentError, "attempt to drop negative size" if n < 0 + + n = n.to_int + ary = [] + self.each {|*val| n == 0 ? ary << val.__svalue : n -= 1 } + ary + end + + ## + # call-seq: + # enum.drop_while {|arr| block } -> array + # enum.drop_while -> an_enumerator + # + # Drops elements up to, but not including, the first element for + # which the block returns +nil+ or +false+ and returns an array + # containing the remaining elements. + # + # If no block is given, an enumerator is returned instead. + # + # a = [1, 2, 3, 4, 5, 0] + # a.drop_while {|i| i < 3 } #=> [3, 4, 5, 0] + + def drop_while(&block) + return to_enum :drop_while unless block + + ary, state = [], false + self.each do |*val| + state = true if !state and !block.call(*val) + ary << val.__svalue if state + end + ary + end + + ## + # call-seq: + # enum.take(n) -> array + # + # Returns first n elements from <i>enum</i>. + # + # a = [1, 2, 3, 4, 5, 0] + # a.take(3) #=> [1, 2, 3] + + def take(n) + raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + i = n.to_int + raise ArgumentError, "attempt to take negative size" if i < 0 + ary = [] + return ary if i == 0 + self.each do |*val| + ary << val.__svalue + i -= 1 + break if i == 0 + end + ary + end + + ## + # call-seq: + # enum.take_while {|arr| block } -> array + # enum.take_while -> an_enumerator + # + # Passes elements to the block until the block returns +nil+ or +false+, + # then stops iterating and returns an array of all prior elements. + # + # If no block is given, an enumerator is returned instead. + # + # a = [1, 2, 3, 4, 5, 0] + # a.take_while {|i| i < 3 } #=> [1, 2] + # + def take_while(&block) + return to_enum :take_while unless block + + ary = [] + self.each do |*val| + return ary unless block.call(*val) + ary << val.__svalue + end + ary + end + + ## + # Iterates the given block for each array of consecutive <n> + # elements. + # + # @return [nil] + # + # @example + # (1..10).each_cons(3) {|a| p a} + # # outputs below + # [1, 2, 3] + # [2, 3, 4] + # [3, 4, 5] + # [4, 5, 6] + # [5, 6, 7] + # [6, 7, 8] + # [7, 8, 9] + # [8, 9, 10] + + def each_cons(n, &block) + raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + raise ArgumentError, "invalid size" if n <= 0 + + return to_enum(:each_cons,n) unless block + ary = [] + n = n.to_int + self.each do |*val| + ary.shift if ary.size == n + ary << val.__svalue + block.call(ary.dup) if ary.size == n + end + nil + end + + ## + # Iterates the given block for each slice of <n> elements. + # + # @return [nil] + # + # @example + # (1..10).each_slice(3) {|a| p a} + # # outputs below + # [1, 2, 3] + # [4, 5, 6] + # [7, 8, 9] + # [10] + + def each_slice(n, &block) + raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + raise ArgumentError, "invalid slice size" if n <= 0 + + return to_enum(:each_slice,n) unless block + ary = [] + n = n.to_int + self.each do |*val| + ary << val.__svalue + if ary.size == n + block.call(ary) + ary = [] + end + end + block.call(ary) unless ary.empty? + nil + end + + ## + # call-seq: + # enum.group_by {| obj | block } -> a_hash + # enum.group_by -> an_enumerator + # + # Returns a hash, which keys are evaluated result from the + # block, and values are arrays of elements in <i>enum</i> + # corresponding to the key. + # + # (1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]} + # + def group_by(&block) + return to_enum :group_by unless block + + h = {} + self.each do |*val| + key = block.call(*val) + sv = val.__svalue + h.key?(key) ? (h[key] << sv) : (h[key] = [sv]) + end + h + end + + ## + # call-seq: + # enum.sort_by { |obj| block } -> array + # enum.sort_by -> an_enumerator + # + # Sorts <i>enum</i> using a set of keys generated by mapping the + # values in <i>enum</i> through the given block. + # + # If no block is given, an enumerator is returned instead. + + def sort_by(&block) + return to_enum :sort_by unless block + + ary = [] + orig = [] + self.each_with_index{|e, i| + orig.push(e) + ary.push([block.call(e), i]) + } + if ary.size > 1 + __sort_sub__(ary, 0, ary.size - 1) do |a,b| + a <=> b + end + end + ary.collect{|e,i| orig[i]} + end + + NONE = Object.new + ## + # call-seq: + # enum.first -> obj or nil + # enum.first(n) -> an_array + # + # Returns the first element, or the first +n+ elements, of the enumerable. + # If the enumerable is empty, the first form returns <code>nil</code>, and the + # second form returns an empty array. + def first(*args) + case args.length + when 0 + self.each do |*val| + return val.__svalue + end + return nil + when 1 + n = args[0] + raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + i = n.to_int + raise ArgumentError, "attempt to take negative size" if i < 0 + ary = [] + return ary if i == 0 + self.each do |*val| + ary << val.__svalue + i -= 1 + break if i == 0 + end + ary + else + raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 0..1)" + end + end + + ## + # call-seq: + # enum.count -> int + # enum.count(item) -> int + # enum.count { |obj| block } -> int + # + # Returns the number of items in +enum+ through enumeration. + # If an argument is given, the number of items in +enum+ that + # are equal to +item+ are counted. If a block is given, it + # counts the number of elements yielding a true value. + def count(v=NONE, &block) + count = 0 + if block + self.each do |*val| + count += 1 if block.call(*val) + end + else + if v == NONE + self.each { count += 1 } + else + self.each do |*val| + count += 1 if val.__svalue == v + end + end + end + count + end + + ## + # call-seq: + # enum.flat_map { |obj| block } -> array + # enum.collect_concat { |obj| block } -> array + # enum.flat_map -> an_enumerator + # enum.collect_concat -> an_enumerator + # + # Returns a new array with the concatenated results of running + # <em>block</em> once for every element in <i>enum</i>. + # + # If no block is given, an enumerator is returned instead. + # + # [1, 2, 3, 4].flat_map { |e| [e, -e] } #=> [1, -1, 2, -2, 3, -3, 4, -4] + # [[1, 2], [3, 4]].flat_map { |e| e + [100] } #=> [1, 2, 100, 3, 4, 100] + def flat_map(&block) + return to_enum :flat_map unless block + + ary = [] + self.each do |*e| + e2 = block.call(*e) + if e2.respond_to? :each + e2.each {|e3| ary.push(e3) } + else + ary.push(e2) + end + end + ary + end + alias collect_concat flat_map + + ## + # call-seq: + # enum.max_by {|obj| block } -> obj + # enum.max_by -> an_enumerator + # + # Returns the object in <i>enum</i> that gives the maximum + # value from the given block. + # + # If no block is given, an enumerator is returned instead. + # + # %w[albatross dog horse].max_by {|x| x.length } #=> "albatross" + + def max_by(&block) + return to_enum :max_by unless block + + first = true + max = nil + max_cmp = nil + + self.each do |*val| + if first + max = val.__svalue + max_cmp = block.call(*val) + first = false + else + if (cmp = block.call(*val)) > max_cmp + max = val.__svalue + max_cmp = cmp + end + end + end + max + end + + ## + # call-seq: + # enum.min_by {|obj| block } -> obj + # enum.min_by -> an_enumerator + # + # Returns the object in <i>enum</i> that gives the minimum + # value from the given block. + # + # If no block is given, an enumerator is returned instead. + # + # %w[albatross dog horse].min_by {|x| x.length } #=> "dog" + + def min_by(&block) + return to_enum :min_by unless block + + first = true + min = nil + min_cmp = nil + + self.each do |*val| + if first + min = val.__svalue + min_cmp = block.call(*val) + first = false + else + if (cmp = block.call(*val)) < min_cmp + min = val.__svalue + min_cmp = cmp + end + end + end + min + end + + ## + # call-seq: + # enum.minmax -> [min, max] + # enum.minmax { |a, b| block } -> [min, max] + # + # Returns two elements array which contains the minimum and the + # maximum value in the enumerable. The first form assumes all + # objects implement <code>Comparable</code>; the second uses the + # block to return <em>a <=> b</em>. + # + # a = %w(albatross dog horse) + # a.minmax #=> ["albatross", "horse"] + # a.minmax { |a, b| a.length <=> b.length } #=> ["dog", "albatross"] + + def minmax(&block) + max = nil + min = nil + first = true + + self.each do |*val| + if first + val = val.__svalue + max = val + min = val + first = false + else + val = val.__svalue + if block + max = val if block.call(val, max) > 0 + min = val if block.call(val, min) < 0 + else + max = val if (val <=> max) > 0 + min = val if (val <=> min) < 0 + end + end + end + [min, max] + end + + ## + # call-seq: + # enum.minmax_by { |obj| block } -> [min, max] + # enum.minmax_by -> an_enumerator + # + # Returns a two element array containing the objects in + # <i>enum</i> that correspond to the minimum and maximum values respectively + # from the given block. + # + # If no block is given, an enumerator is returned instead. + # + # %w(albatross dog horse).minmax_by { |x| x.length } #=> ["dog", "albatross"] + + def minmax_by(&block) + return to_enum :minmax_by unless block + + max = nil + max_cmp = nil + min = nil + min_cmp = nil + first = true + + self.each do |*val| + if first + max = min = val.__svalue + max_cmp = min_cmp = block.call(*val) + first = false + else + if (cmp = block.call(*val)) > max_cmp + max = val.__svalue + max_cmp = cmp + end + if (cmp = block.call(*val)) < min_cmp + min = val.__svalue + min_cmp = cmp + end + end + end + [min, max] + end + + ## + # call-seq: + # enum.none? [{ |obj| block }] -> true or false + # + # Passes each element of the collection to the given block. The method + # returns <code>true</code> if the block never returns <code>true</code> + # for all elements. If the block is not given, <code>none?</code> will return + # <code>true</code> only if none of the collection members is true. + # + # %w(ant bear cat).none? { |word| word.length == 5 } #=> true + # %w(ant bear cat).none? { |word| word.length >= 4 } #=> false + # [].none? #=> true + # [nil, false].none? #=> true + # [nil, true].none? #=> false + + def none?(&block) + if block + self.each do |*val| + return false if block.call(*val) + end + else + self.each do |*val| + return false if val.__svalue + end + end + true + end + + ## + # call-seq: + # enum.one? [{ |obj| block }] -> true or false + # + # Passes each element of the collection to the given block. The method + # returns <code>true</code> if the block returns <code>true</code> + # exactly once. If the block is not given, <code>one?</code> will return + # <code>true</code> only if exactly one of the collection members is + # true. + # + # %w(ant bear cat).one? { |word| word.length == 4 } #=> true + # %w(ant bear cat).one? { |word| word.length > 4 } #=> false + # %w(ant bear cat).one? { |word| word.length < 4 } #=> false + # [nil, true, 99].one? #=> false + # [nil, true, false].one? #=> true + # + + def one?(&block) + count = 0 + if block + self.each do |*val| + count += 1 if block.call(*val) + return false if count > 1 + end + else + self.each do |*val| + count += 1 if val.__svalue + return false if count > 1 + end + end + + count == 1 ? true : false + end + + ## + # call-seq: + # enum.each_with_object(obj) { |(*args), memo_obj| ... } -> obj + # enum.each_with_object(obj) -> an_enumerator + # + # Iterates the given block for each element with an arbitrary + # object given, and returns the initially given object. + # + # If no block is given, returns an enumerator. + # + # (1..10).each_with_object([]) { |i, a| a << i*2 } + # #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] + # + + def each_with_object(obj=nil, &block) + raise ArgumentError, "wrong number of arguments (0 for 1)" if obj.nil? + + return to_enum(:each_with_object, obj) unless block + + self.each {|*val| block.call(val.__svalue, obj) } + obj + end + + ## + # call-seq: + # enum.reverse_each { |item| block } -> enum + # enum.reverse_each -> an_enumerator + # + # Builds a temporary array and traverses that array in reverse order. + # + # If no block is given, an enumerator is returned instead. + # + # (1..3).reverse_each { |v| p v } + # + # produces: + # + # 3 + # 2 + # 1 + # + + def reverse_each(&block) + return to_enum :reverse_each unless block + + ary = self.to_a + i = ary.size - 1 + while i>=0 + block.call(ary[i]) + i -= 1 + end + self + end + + ## + # call-seq: + # enum.cycle(n=nil) { |obj| block } -> nil + # enum.cycle(n=nil) -> an_enumerator + # + # Calls <i>block</i> for each element of <i>enum</i> repeatedly _n_ + # times or forever if none or +nil+ is given. If a non-positive + # number is given or the collection is empty, does nothing. Returns + # +nil+ if the loop has finished without getting interrupted. + # + # Enumerable#cycle saves elements in an internal array so changes + # to <i>enum</i> after the first pass have no effect. + # + # If no block is given, an enumerator is returned instead. + # + # a = ["a", "b", "c"] + # a.cycle { |x| puts x } # print, a, b, c, a, b, c,.. forever. + # a.cycle(2) { |x| puts x } # print, a, b, c, a, b, c. + # + + def cycle(nv = nil, &block) + return to_enum(:cycle, nv) unless block + + n = nil + + if nv.nil? + n = -1 + else + unless nv.respond_to?(:to_int) + raise TypeError, "no implicit conversion of #{nv.class} into Integer" + end + n = nv.to_int + unless n.kind_of?(Integer) + raise TypeError, "no implicit conversion of #{nv.class} into Integer" + end + return nil if n <= 0 + end + + ary = [] + each do |*i| + ary.push(i) + yield(*i) + end + return nil if ary.empty? + + while n < 0 || 0 < (n -= 1) + ary.each do |i| + yield(*i) + end + end + + nil + end + + ## + # call-seq: + # enum.find_index(value) -> int or nil + # enum.find_index { |obj| block } -> int or nil + # enum.find_index -> an_enumerator + # + # Compares each entry in <i>enum</i> with <em>value</em> or passes + # to <em>block</em>. Returns the index for the first for which the + # evaluated value is non-false. If no object matches, returns + # <code>nil</code> + # + # If neither block nor argument is given, an enumerator is returned instead. + # + # (1..10).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> nil + # (1..100).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> 34 + # (1..100).find_index(50) #=> 49 + # + + def find_index(val=NONE, &block) + return to_enum(:find_index, val) if !block && val == NONE + + idx = 0 + if block + self.each do |*e| + return idx if block.call(*e) + idx += 1 + end + else + self.each do |*e| + return idx if e.__svalue == val + idx += 1 + end + end + nil + end + + ## + # call-seq: + # enum.zip(arg, ...) -> an_array_of_array + # + # Takes one element from <i>enum</i> and merges corresponding + # elements from each <i>args</i>. This generates a sequence of + # <em>n</em>-element arrays, where <em>n</em> is one more than the + # count of arguments. The length of the resulting sequence will be + # <code>enum#size</code>. If the size of any argument is less than + # <code>enum#size</code>, <code>nil</code> values are supplied. + # + + def zip(*arg) + ary = [] + arg = arg.map{|a|a.to_a} + i = 0 + self.each do |*val| + a = [] + a.push(val.__svalue) + idx = 0 + while idx < arg.size + a.push(arg[idx][i]) + idx += 1 + end + ary.push(a) + i += 1 + end + ary + end + + ## + # call-seq: + # enum.to_h -> hash + # + # Returns the result of interpreting <i>enum</i> as a list of + # <tt>[key, value]</tt> pairs. + # + # %i[hello world].each_with_index.to_h + # # => {:hello => 0, :world => 1} + # + + def to_h + h = {} + self.each do |*v| + v = v.__svalue + raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array + raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2 + h[v[0]] = v[1] + end + h + end + + def nil.to_h + {} + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-ext/test/enum.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-ext/test/enum.rb new file mode 100644 index 000000000..e772f85bf --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-ext/test/enum.rb @@ -0,0 +1,171 @@ +## +# Enumerable(Ext) Test + +assert("Enumerable#drop") do + a = [1, 2, 3, 4, 5, 0] + + assert_equal [4, 5, 0], a.drop(3) + assert_equal [], a.drop(6) +end + +assert("Enumerable#drop_while") do + a = [1, 2, 3, 4, 5, 0] + assert_equal [3, 4, 5, 0], a.drop_while {|i| i < 3 } +end + +assert("Enumerable#take") do + a = [1, 2, 3, 4, 5, 0] + assert_equal [1, 2, 3], a.take(3) +end + +assert("Enumerable#take_while") do + a = [1, 2, 3, 4, 5, 0] + assert_equal [1, 2], a.take_while {|i| i < 3} +end + +assert("Enumerable#each_cons") do + a = [] + b = (1..5).each_cons(3){|e| a << e} + assert_equal [[1, 2, 3], [2, 3, 4], [3, 4, 5]], a + assert_equal nil, b +end + +assert("Enumerable#each_slice") do + a = [] + b = (1..10).each_slice(3){|e| a << e} + assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], a + assert_equal nil, b +end + +assert("Enumerable#group_by") do + r = (1..6).group_by {|i| i % 3 } + assert_equal [3, 6], r[0] + assert_equal [1, 4], r[1] + assert_equal [2, 5], r[2] +end + +assert("Enumerable#sort_by") do + assert_equal ["car", "train", "bicycle"], %w{car bicycle train}.sort_by {|e| e.length} +end + +assert("Enumerable#first") do + a = Object.new + a.extend Enumerable + def a.each + yield 1 + yield 2 + yield 3 + end + assert_equal 1, a.first + assert_equal [1, 2], a.first(2) + assert_equal [1, 2, 3], a.first(10) + a = Object.new + a.extend Enumerable + def a.each + end + assert_nil a.first +end + +assert("Enumerable#count") do + a = [1, 2, 4, 2] + assert_equal 4, a.count + assert_equal 2, a.count(2) + assert_equal 3, a.count{|x| x % 2 == 0} +end + +assert("Enumerable#flat_map") do + assert_equal [1, 2, 3, 4], [1, 2, 3, 4].flat_map { |e| e } + assert_equal [1, -1, 2, -2, 3, -3, 4, -4], [1, 2, 3, 4].flat_map { |e| [e, -e] } + assert_equal [1, 2, 100, 3, 4, 100], [[1, 2], [3, 4]].flat_map { |e| e + [100] } +end + +assert("Enumerable#max_by") do + assert_equal "albatross", %w[albatross dog horse].max_by { |x| x.length } +end + +assert("Enumerable#min_by") do + assert_equal "dog", %w[albatross dog horse].min_by { |x| x.length } +end + +assert("Enumerable#minmax") do + a = %w(albatross dog horse) + assert_equal ["albatross", "horse"], a.minmax + assert_equal ["dog", "albatross"], a.minmax { |a, b| a.length <=> b.length } +end + +assert("Enumerable#minmax_by") do + assert_equal ["dog", "albatross"], %w(albatross dog horse).minmax_by { |x| x.length } +end + +assert("Enumerable#none?") do + assert_true %w(ant bear cat).none? { |word| word.length == 5 } + assert_false %w(ant bear cat).none? { |word| word.length >= 4 } + assert_true [].none? + assert_true [nil, false].none? + assert_false [nil, true].none? +end + +assert("Enumerable#one?") do + assert_true %w(ant bear cat).one? { |word| word.length == 4 } + assert_false %w(ant bear cat).one? { |word| word.length > 4 } + assert_false %w(ant bear cat).one? { |word| word.length < 4 } + assert_false [nil, true, 99].one? + assert_true [nil, true, false].one? +end + +assert("Enumerable#each_with_object") do + assert_true [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], (1..10).each_with_object([]) { |i, a| a << i*2 } + assert_raise(ArgumentError) { (1..10).each_with_object() { |i, a| a << i*2 } } +end + +assert("Enumerable#reverse_each") do + r = (1..3) + a = [] + assert_equal (1..3), r.reverse_each { |v| a << v } + assert_equal [3, 2, 1], a +end + +assert("Enumerable#cycle") do + a = [] + ["a", "b", "c"].cycle(2) { |v| a << v } + assert_equal ["a", "b", "c", "a", "b", "c"], a + assert_raise(TypeError) { ["a", "b", "c"].cycle("a") { |v| a << v } } + + empty = Class.new do + include Enumerable + def each + end + end + assert_nil empty.new.cycle { break :nope } +end + +assert("Enumerable#find_index") do + assert_nil (1..10).find_index { |i| i % 5 == 0 and i % 7 == 0 } + assert_equal 34, (1..100).find_index { |i| i % 5 == 0 and i % 7 == 0 } + assert_equal 49 ,(1..100).find_index(50) +end + +assert("Enumerable#zip") do + a = [ 4, 5, 6 ] + b = [ 7, 8, 9 ] + assert_equal [[4, 7], [5, 8], [6, 9]], a.zip(b) + assert_equal [[1, 4, 7], [2, 5, 8], [3, 6, 9]], [1, 2, 3].zip(a, b) + assert_equal [[1, 4, 7], [2, 5, 8]], [1, 2].zip(a, b) + assert_equal [[4, 1, 8], [5, 2, nil], [6, nil, nil]], a.zip([1, 2], [8]) +end + +assert("Enumerable#to_h") do + c = Class.new { + include Enumerable + def each + yield [1,2] + yield [3,4] + end + } + h0 = {1=>2, 3=>4} + h = c.new.to_h + assert_equal Hash, h.class + assert_equal h0, h + # mruby-enum-ext also provides nil.to_h + assert_equal Hash.new, nil.to_h +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrbgem.rake new file mode 100644 index 000000000..682134c41 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrbgem.rake @@ -0,0 +1,7 @@ +MRuby::Gem::Specification.new('mruby-enum-lazy') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Enumerator::Lazy class' + spec.add_dependency('mruby-enumerator', :core => 'mruby-enumerator') + spec.add_dependency('mruby-enum-ext', :core => 'mruby-enum-ext') +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrblib/lazy.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrblib/lazy.rb new file mode 100644 index 000000000..c98681edf --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/mrblib/lazy.rb @@ -0,0 +1,163 @@ +module Enumerable + + # = Enumerable#lazy implementation + # + # Enumerable#lazy returns an instance of Enumerator::Lazy. + # You can use it just like as normal Enumerable object, + # except these methods act as 'lazy': + # + # - map collect + # - select find_all + # - reject + # - grep + # - drop + # - drop_while + # - take_while + # - flat_map collect_concat + # - zip + def lazy + Enumerator::Lazy.new(self) + end +end + +class Enumerator + # == Acknowledgements + # + # Based on https://github.com/yhara/enumerable-lazy + # Inspired by https://github.com/antimon2/enumerable_lz + # http://jp.rubyist.net/magazine/?0034-Enumerable_lz (ja) + class Lazy < Enumerator + def initialize(obj, &block) + super(){|yielder| + begin + obj.each{|x| + if block + block.call(yielder, x) + else + yielder << x + end + } + rescue StopIteration + end + } + end + + def to_enum(meth=:each, *args, &block) + unless self.respond_to?(meth) + raise NoMethodError, "undefined method #{meth}" + end + lz = Lazy.new(self, &block) + lz.obj = self + lz.meth = meth + lz.args = args + lz + end + alias enum_for to_enum + + def map(&block) + Lazy.new(self){|yielder, val| + yielder << block.call(val) + } + end + alias collect map + + def select(&block) + Lazy.new(self){|yielder, val| + if block.call(val) + yielder << val + end + } + end + alias find_all select + + def reject(&block) + Lazy.new(self){|yielder, val| + unless block.call(val) + yielder << val + end + } + end + + def grep(pattern) + Lazy.new(self){|yielder, val| + if pattern === val + yielder << val + end + } + end + + def drop(n) + dropped = 0 + Lazy.new(self){|yielder, val| + if dropped < n + dropped += 1 + else + yielder << val + end + } + end + + def drop_while(&block) + dropping = true + Lazy.new(self){|yielder, val| + if dropping + if not block.call(val) + yielder << val + dropping = false + end + else + yielder << val + end + } + end + + def take(n) + if n == 0 + return Lazy.new(self){raise StopIteration} + end + taken = 0 + Lazy.new(self){|yielder, val| + yielder << val + taken += 1 + if taken >= n + raise StopIteration + end + } + end + + def take_while(&block) + Lazy.new(self){|yielder, val| + if block.call(val) + yielder << val + else + raise StopIteration + end + } + end + + def flat_map(&block) + Lazy.new(self){|yielder, val| + ary = block.call(val) + # TODO: check ary is an Array + ary.each{|x| + yielder << x + } + } + end + alias collect_concat flat_map + + def zip(*args, &block) + enums = [self] + args + Lazy.new(self){|yielder, val| + ary = enums.map{|e| e.next} + if block + yielder << block.call(ary) + else + yielder << ary + end + } + end + + alias force to_a + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/test/lazy.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/test/lazy.rb new file mode 100644 index 000000000..940d070e8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enum-lazy/test/lazy.rb @@ -0,0 +1,53 @@ +assert("Enumerator::Lazy") do + a = [1, 2] + assert_equal Enumerator::Lazy, a.lazy.class +end + +assert("Enumerator::Lazy laziness") do + a = Object.new + def a.each + return to_enum :each unless block_given? + self.b << 10 + yield 1 + self.b << 20 + yield 2 + self.b << 30 + yield 3 + self.b << 40 + yield 4 + self.b << 50 + yield 5 + end + def a.b(b=nil) + @b = b if b + @b + end + + a.b([]) + assert_equal [1,2], a.each.lazy.take(2).force + assert_equal [10,20], a.b + + a.b([]) + assert_equal [2,4], a.each.lazy.select{|x|x%2==0}.take(2).force + assert_equal [10,20,30,40], a.b + + a.b([]) + assert_equal [1], a.each.lazy.take_while{|x|x<2}.take(1).force + assert_equal [10], a.b + + a.b([]) + assert_equal [1], a.each.lazy.take_while{|x|x<2}.take(4).force + assert_equal [10,20], a.b +end + +assert("Enumrator::Lazy#to_enum") do + lazy_enum = (0..Float::INFINITY).lazy.to_enum(:each_slice, 2) + assert_kind_of Enumerator::Lazy, lazy_enum + assert_equal [0*1, 2*3, 4*5, 6*7], lazy_enum.map { |a| a.first * a.last }.first(4) +end + +assert("Enumerator::Lazy#zip with cycle") do + e1 = [1, 2, 3].cycle + e2 = [:a, :b].cycle + assert_equal [[1,:a],[2,:b],[3,:a]], e1.lazy.zip(e2).first(3) +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enumerator/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enumerator/mrbgem.rake new file mode 100644 index 000000000..8757a15ea --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enumerator/mrbgem.rake @@ -0,0 +1,7 @@ +MRuby::Gem::Specification.new('mruby-enumerator') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.add_dependency('mruby-fiber', :core => 'mruby-fiber') + spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext' + spec.summary = 'Enumerator class' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb new file mode 100644 index 000000000..1e77af369 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -0,0 +1,645 @@ +## +# enumerator.rb Enumerator class +# See Copyright Notice in mruby.h + +## +# A class which allows both internal and external iteration. +# +# An Enumerator can be created by the following methods. +# - {Kernel#to_enum} +# - {Kernel#enum_for} +# - {Enumerator#initialize Enumerator.new} +# +# Most methods have two forms: a block form where the contents +# are evaluated for each item in the enumeration, and a non-block form +# which returns a new Enumerator wrapping the iteration. +# +# enumerator = %w(one two three).each +# puts enumerator.class # => Enumerator +# +# enumerator.each_with_object("foo") do |item, obj| +# puts "#{obj}: #{item}" +# end +# +# # foo: one +# # foo: two +# # foo: three +# +# enum_with_obj = enumerator.each_with_object("foo") +# puts enum_with_obj.class # => Enumerator +# +# enum_with_obj.each do |item, obj| +# puts "#{obj}: #{item}" +# end +# +# # foo: one +# # foo: two +# # foo: three +# +# This allows you to chain Enumerators together. For example, you +# can map a list's elements to strings containing the index +# and the element as a string via: +# +# puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" } +# # => ["0:foo", "1:bar", "2:baz"] +# +# An Enumerator can also be used as an external iterator. +# For example, Enumerator#next returns the next value of the iterator +# or raises StopIteration if the Enumerator is at the end. +# +# e = [1,2,3].each # returns an enumerator object. +# puts e.next # => 1 +# puts e.next # => 2 +# puts e.next # => 3 +# puts e.next # raises StopIteration +# +# You can use this to implement an internal iterator as follows: +# +# def ext_each(e) +# while true +# begin +# vs = e.next_values +# rescue StopIteration +# return $!.result +# end +# y = yield(*vs) +# e.feed y +# end +# end +# +# o = Object.new +# +# def o.each +# puts yield +# puts yield(1) +# puts yield(1, 2) +# 3 +# end +# +# # use o.each as an internal iterator directly. +# puts o.each {|*x| puts x; [:b, *x] } +# # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3 +# +# # convert o.each to an external iterator for +# # implementing an internal iterator. +# puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] } +# # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3 +# +class Enumerator + include Enumerable + + ## + # @overload initialize(size = nil, &block) + # @overload initialize(obj, method = :each, *args) + # + # Creates a new Enumerator object, which can be used as an + # Enumerable. + # + # In the first form, iteration is defined by the given block, in + # which a "yielder" object, given as block parameter, can be used to + # yield a value by calling the +yield+ method (aliased as +<<+): + # + # fib = Enumerator.new do |y| + # a = b = 1 + # loop do + # y << a + # a, b = b, a + b + # end + # end + # + # p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] + # + def initialize(obj=nil, meth=:each, *args, &block) + if block + obj = Generator.new(&block) + else + raise ArgumentError unless obj + end + if @obj and !self.respond_to?(meth) + raise NoMethodError, "undefined method #{meth}" + end + + @obj = obj + @meth = meth + @args = args.dup + @fib = nil + @dst = nil + @lookahead = nil + @feedvalue = nil + @stop_exc = false + end + attr_accessor :obj, :meth, :args, :fib + private :obj, :meth, :args, :fib + + def initialize_copy(obj) + raise TypeError, "can't copy type #{obj.class}" unless obj.kind_of? Enumerator + raise TypeError, "can't copy execution context" if obj.fib + @obj = obj.obj + @meth = obj.meth + @args = obj.args + @fib = nil + @lookahead = nil + @feedvalue = nil + self + end + + ## + # call-seq: + # e.with_index(offset = 0) {|(*args), idx| ... } + # e.with_index(offset = 0) + # + # Iterates the given block for each element with an index, which + # starts from +offset+. If no block is given, returns a new Enumerator + # that includes the index, starting from +offset+ + # + # +offset+:: the starting index to use + # + def with_index(offset=0, &block) + return to_enum :with_index, offset unless block + + offset = if offset.nil? + 0 + elsif offset.respond_to?(:to_int) + offset.to_int + else + raise TypeError, "no implicit conversion of #{offset.class} into Integer" + end + + n = offset - 1 + enumerator_block_call do |*i| + n += 1 + block.call i.__svalue, n + end + end + + ## + # call-seq: + # e.each_with_index {|(*args), idx| ... } + # e.each_with_index + # + # Same as Enumerator#with_index(0), i.e. there is no starting offset. + # + # If no block is given, a new Enumerator is returned that includes the index. + # + def each_with_index(&block) + with_index(0, &block) + end + + ## + # call-seq: + # e.each_with_object(obj) {|(*args), obj| ... } + # e.each_with_object(obj) + # e.with_object(obj) {|(*args), obj| ... } + # e.with_object(obj) + # + # Iterates the given block for each element with an arbitrary object, +obj+, + # and returns +obj+ + # + # If no block is given, returns a new Enumerator. + # + # @example + # to_three = Enumerator.new do |y| + # 3.times do |x| + # y << x + # end + # end + # + # to_three_with_string = to_three.with_object("foo") + # to_three_with_string.each do |x,string| + # puts "#{string}: #{x}" + # end + # + # # => foo:0 + # # => foo:1 + # # => foo:2 + # + def with_object(object, &block) + return to_enum(:with_object, object) unless block + + enumerator_block_call do |i| + block.call [i,object] + end + object + end + + def inspect + return "#<#{self.class}: uninitialized>" unless @obj + + if @args && @args.size > 0 + args = @args.join(", ") + "#<#{self.class}: #{@obj}:#{@meth}(#{args})>" + else + "#<#{self.class}: #{@obj}:#{@meth}>" + end + end + + ## + # call-seq: + # enum.each { |elm| block } -> obj + # enum.each -> enum + # enum.each(*appending_args) { |elm| block } -> obj + # enum.each(*appending_args) -> an_enumerator + # + # Iterates over the block according to how this Enumerator was constructed. + # If no block and no arguments are given, returns self. + # + # === Examples + # + # "Hello, world!".scan(/\w+/) #=> ["Hello", "world"] + # "Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"] + # "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"] + # + # obj = Object.new + # + # def obj.each_arg(a, b=:b, *rest) + # yield a + # yield b + # yield rest + # :method_returned + # end + # + # enum = obj.to_enum :each_arg, :a, :x + # + # enum.each.to_a #=> [:a, :x, []] + # enum.each.equal?(enum) #=> true + # enum.each { |elm| elm } #=> :method_returned + # + # enum.each(:y, :z).to_a #=> [:a, :x, [:y, :z]] + # enum.each(:y, :z).equal?(enum) #=> false + # enum.each(:y, :z) { |elm| elm } #=> :method_returned + # + def each(*argv, &block) + obj = self + if 0 < argv.length + obj = self.dup + args = obj.args + if !args.empty? + args = args.dup + args.concat argv + else + args = argv.dup + end + obj.args = args + end + return obj unless block + enumerator_block_call(&block) + end + + def enumerator_block_call(&block) + @obj.__send__ @meth, *@args, &block + end + private :enumerator_block_call + + ## + # call-seq: + # e.next -> object + # + # Returns the next object in the enumerator, and move the internal position + # forward. When the position reached at the end, StopIteration is raised. + # + # === Example + # + # a = [1,2,3] + # e = a.to_enum + # p e.next #=> 1 + # p e.next #=> 2 + # p e.next #=> 3 + # p e.next #raises StopIteration + # + # Note that enumeration sequence by +next+ does not affect other non-external + # enumeration methods, unless the underlying iteration methods itself has + # side-effect + # + def next + next_values.__svalue + end + + ## + # call-seq: + # e.next_values -> array + # + # Returns the next object as an array in the enumerator, and move the + # internal position forward. When the position reached at the end, + # StopIteration is raised. + # + # This method can be used to distinguish <code>yield</code> and <code>yield + # nil</code>. + # + # === Example + # + # o = Object.new + # def o.each + # yield + # yield 1 + # yield 1, 2 + # yield nil + # yield [1, 2] + # end + # e = o.to_enum + # p e.next_values + # p e.next_values + # p e.next_values + # p e.next_values + # p e.next_values + # e = o.to_enum + # p e.next + # p e.next + # p e.next + # p e.next + # p e.next + # + # ## yield args next_values next + # # yield [] nil + # # yield 1 [1] 1 + # # yield 1, 2 [1, 2] [1, 2] + # # yield nil [nil] nil + # # yield [1, 2] [[1, 2]] [1, 2] + # + # Note that +next_values+ does not affect other non-external enumeration + # methods unless underlying iteration method itself has side-effect + # + def next_values + if @lookahead + vs = @lookahead + @lookahead = nil + return vs + end + raise @stop_exc if @stop_exc + + curr = Fiber.current + + if !@fib || !@fib.alive? + @dst = curr + @fib = Fiber.new do + result = each do |*args| + feedvalue = nil + Fiber.yield args + if @feedvalue + feedvalue = @feedvalue + @feedvalue = nil + end + feedvalue + end + @stop_exc = StopIteration.new "iteration reached an end" + @stop_exc.result = result + Fiber.yield nil + end + @lookahead = nil + end + + vs = @fib.resume curr + if @stop_exc + @fib = nil + @dst = nil + @lookahead = nil + @feedvalue = nil + raise @stop_exc + end + vs + end + + ## + # call-seq: + # e.peek -> object + # + # Returns the next object in the enumerator, but doesn't move the internal + # position forward. If the position is already at the end, StopIteration + # is raised. + # + # === Example + # + # a = [1,2,3] + # e = a.to_enum + # p e.next #=> 1 + # p e.peek #=> 2 + # p e.peek #=> 2 + # p e.peek #=> 2 + # p e.next #=> 2 + # p e.next #=> 3 + # p e.next #raises StopIteration + # + def peek + peek_values.__svalue + end + + ## + # call-seq: + # e.peek_values -> array + # + # Returns the next object as an array, similar to Enumerator#next_values, but + # doesn't move the internal position forward. If the position is already at + # the end, StopIteration is raised. + # + # === Example + # + # o = Object.new + # def o.each + # yield + # yield 1 + # yield 1, 2 + # end + # e = o.to_enum + # p e.peek_values #=> [] + # e.next + # p e.peek_values #=> [1] + # p e.peek_values #=> [1] + # e.next + # p e.peek_values #=> [1, 2] + # e.next + # p e.peek_values # raises StopIteration + # + def peek_values + if @lookahead.nil? + @lookahead = next_values + end + @lookahead.dup + end + + ## + # call-seq: + # e.rewind -> e + # + # Rewinds the enumeration sequence to the beginning. + # + # If the enclosed object responds to a "rewind" method, it is called. + # + def rewind + @obj.rewind if @obj.respond_to? :rewind + @fib = nil + @dst = nil + @lookahead = nil + @feedvalue = nil + @stop_exc = false + self + end + + ## + # call-seq: + # e.feed obj -> nil + # + # Sets the value to be returned by the next yield inside +e+. + # + # If the value is not set, the yield returns nil. + # + # This value is cleared after being yielded. + # + # # Array#map passes the array's elements to "yield" and collects the + # # results of "yield" as an array. + # # Following example shows that "next" returns the passed elements and + # # values passed to "feed" are collected as an array which can be + # # obtained by StopIteration#result. + # e = [1,2,3].map + # p e.next #=> 1 + # e.feed "a" + # p e.next #=> 2 + # e.feed "b" + # p e.next #=> 3 + # e.feed "c" + # begin + # e.next + # rescue StopIteration + # p $!.result #=> ["a", "b", "c"] + # end + # + # o = Object.new + # def o.each + # x = yield # (2) blocks + # p x # (5) => "foo" + # x = yield # (6) blocks + # p x # (8) => nil + # x = yield # (9) blocks + # p x # not reached w/o another e.next + # end + # + # e = o.to_enum + # e.next # (1) + # e.feed "foo" # (3) + # e.next # (4) + # e.next # (7) + # # (10) + # + def feed(value) + raise TypeError, "feed value already set" if @feedvalue + @feedvalue = value + nil + end + + # just for internal + class Generator + include Enumerable + def initialize(&block) + raise TypeError, "wrong argument type #{self.class} (expected Proc)" unless block.kind_of? Proc + + @proc = block + end + + def each(*args, &block) + args.unshift Yielder.new(&block) + @proc.call(*args) + end + end + + # just for internal + class Yielder + def initialize(&block) + raise LocalJumpError, "no block given" unless block + + @proc = block + end + + def yield(*args) + @proc.call(*args) + end + + def << *args + self.yield(*args) + self + end + end +end + +module Kernel + ## + # call-seq: + # obj.to_enum(method = :each, *args) -> enum + # obj.enum_for(method = :each, *args) -> enum + # obj.to_enum(method = :each, *args) {|*args| block} -> enum + # obj.enum_for(method = :each, *args){|*args| block} -> enum + # + # Creates a new Enumerator which will enumerate by calling +method+ on + # +obj+, passing +args+ if any. + # + # If a block is given, it will be used to calculate the size of + # the enumerator without the need to iterate it (see Enumerator#size). + # + # === Examples + # + # str = "xyz" + # + # enum = str.enum_for(:each_byte) + # enum.each { |b| puts b } + # # => 120 + # # => 121 + # # => 122 + # + # # protect an array from being modified by some_method + # a = [1, 2, 3] + # some_method(a.to_enum) + # + # It is typical to call to_enum when defining methods for + # a generic Enumerable, in case no block is passed. + # + # Here is such an example, with parameter passing and a sizing block: + # + # module Enumerable + # # a generic method to repeat the values of any enumerable + # def repeat(n) + # raise ArgumentError, "#{n} is negative!" if n < 0 + # unless block_given? + # return to_enum(__method__, n) do # __method__ is :repeat here + # sz = size # Call size and multiply by n... + # sz * n if sz # but return nil if size itself is nil + # end + # end + # each do |*val| + # n.times { yield *val } + # end + # end + # end + # + # %i[hello world].repeat(2) { |w| puts w } + # # => Prints 'hello', 'hello', 'world', 'world' + # enum = (1..14).repeat(3) + # # => returns an Enumerator when called without a block + # enum.first(4) # => [1, 1, 1, 2] + # + def to_enum(meth=:each, *args) + Enumerator.new self, meth, *args + end + alias enum_for to_enum +end + +module Enumerable + # use Enumerator to use infinite sequence + def zip(*arg) + ary = [] + arg = arg.map{|a|a.each} + i = 0 + self.each do |*val| + a = [] + a.push(val.__svalue) + idx = 0 + while idx < arg.size + begin + a.push(arg[idx].next) + rescue StopIteration + a.push(nil) + end + idx += 1 + end + ary.push(a) + i += 1 + end + ary + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enumerator/test/enumerator.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enumerator/test/enumerator.rb new file mode 100644 index 000000000..763cd36e2 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-enumerator/test/enumerator.rb @@ -0,0 +1,546 @@ +@obj = Object.new +class << @obj + include Enumerable + def foo *a + a.each { |x| yield x } + end +end + +assert 'Enumerator' do + assert_equal Class, Enumerator.class +end + +assert 'Enumerator' do + assert_equal Object, Enumerator.superclass +end + +assert 'Enumerator.new' do + assert_equal [0,1,2], 3.times.map{|i| i}.sort + assert_equal [:x,:y,:z], [:x,:y,:z].each.map{|i| i}.sort + assert_equal [[:x,1],[:y,2]], {x:1, y:2}.each.map{|i| i}.sort + assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a + assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a + assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3) + assert_raise(ArgumentError) { Enumerator.new } + enum = @obj.to_enum + assert_raise(NoMethodError) { enum.each {} } + + # examples + fib = Enumerator.new do |y| + a = b = 1 + loop do + y << a + a, b = b, a + b + end + end + assert_equal fib.take(10), [1,1,2,3,5,8,13,21,34,55] +end + +assert 'Enumerator#initialize_copy' do + assert_equal [1, 2, 3], @obj.to_enum(:foo, 1, 2, 3).dup.to_a + e = @obj.to_enum :foo, 1, 2, 3 + assert_nothing_raised { assert_equal(1, e.next) } + assert_raise(TypeError) { e.dup } + + e = Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.dup + assert_nothing_raised { assert_equal(1, e.next) } + assert_raise(TypeError) { e.dup } +end + +assert 'Enumerator#with_index' do + assert_equal([[1,0],[2,1],[3,2]], @obj.to_enum(:foo, 1, 2, 3).with_index.to_a) + assert_equal([[1,5],[2,6],[3,7]], @obj.to_enum(:foo, 1, 2, 3).with_index(5).to_a) + a = [] + @obj.to_enum(:foo, 1, 2, 3).with_index(10).with_index(20) { |*i| a << i } + assert_equal [[[1, 10], 20], [[2, 11], 21], [[3, 12], 22]], a +end + +assert 'Enumerator#with_index nonnum offset' do + s = Object.new + def s.to_int; 1 end + assert_equal([[1,1],[2,2],[3,3]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a) +end + +assert 'Enumerator#with_index string offset' do + assert_raise(TypeError){ @obj.to_enum(:foo, 1, 2, 3).with_index('1').to_a } +end + +assert 'Enumerator#each_with_index' do + assert_equal([[1,0],[2,1],[3,2]], @obj.to_enum(:foo, 1, 2, 3).each_with_index.to_a) + a = [] + @obj.to_enum(:foo, 1, 2, 3).each_with_index {|*i| a << i} + assert_equal([[1, 0], [2, 1], [3, 2]], a) +end + +assert 'Enumerator#with_object' do + obj = [0, 1] + ret = (1..10).each.with_object(obj) {|i, memo| + memo[0] += i + memo[1] *= i + } + assert_true(obj.equal?(ret)) + assert_equal([55, 3628800], ret) +end + +assert 'Enumerator#with_object arguments' do + to_three = Enumerator.new do |y| + 3.times do |x| + y << x + end + end + + a = [] + to_three_with_string = to_three.with_object("foo") + to_three_with_string.each do |x,string| + a << "#{string}:#{x}" + end + assert_equal ["foo:0","foo:1","foo:2"], a +end + +assert 'Enumerator#inspect' do + e = (0..10).each + assert_equal("#<Enumerator: 0..10:each>", e.inspect) + e = Enumerator.new("FooObject", :foo, 1) + assert_equal("#<Enumerator: FooObject:foo(1)>", e.inspect) + e = Enumerator.new("FooObject", :foo, 1, 2, 3) + assert_equal("#<Enumerator: FooObject:foo(1, 2, 3)>", e.inspect) +end + +assert 'Enumerator#each' do + o = Object.new + def o.each(ary) + ary << 1 + yield + end + ary = [] + e = o.to_enum.each(ary) + e.next + assert_equal([1], ary) +end + +assert 'Enumerator#each arguments' do + obj = Object.new + + def obj.each_arg(a, b=:b, *rest) + yield a + yield b + yield rest + :method_returned + end + + enum = obj.to_enum :each_arg, :a, :x + + assert_equal [:a, :x, []], enum.each.to_a + assert_true enum.each.equal?(enum) + assert_equal :method_returned, enum.each { |elm| elm } + + assert_equal [:a, :x, [:y, :z]], enum.each(:y, :z).to_a + assert_false enum.each(:y, :z).equal?(enum) + assert_equal :method_returned, enum.each(:y, :z) { |elm| elm } +end + +assert 'Enumerator#next' do + e = 3.times + 3.times { |i| + assert_equal i, e.next + } + assert_raise(StopIteration) { e.next } +end + +assert 'Enumerator#next_values' do + o = Object.new + def o.each + yield + yield 1 + yield 1, 2 + end + e = o.to_enum + assert_equal nil, e.next + assert_equal 1, e.next + assert_equal [1,2], e.next + e = o.to_enum + assert_equal [], e.next_values + assert_equal [1], e.next_values + assert_equal [1,2], e.next_values +end + +assert 'Enumerator#peek' do + a = [1] + e = a.each + assert_equal 1, e.peek + assert_equal 1, e.peek + assert_equal 1, e.next + assert_raise(StopIteration) { e.peek } + assert_raise(StopIteration) { e.peek } +end + +assert 'Enumerator#peek modify' do + o = Object.new + def o.each + yield 1,2 + end + e = o.to_enum + a = e.peek + a << 3 + assert_equal([1,2], e.peek) +end + +assert 'Enumerator#peek_values' do + o = Object.new + def o.each + yield + yield 1 + yield 1, 2 + end + e = o.to_enum + assert_equal nil, e.peek + assert_equal nil, e.next + assert_equal 1, e.peek + assert_equal 1, e.next + assert_equal [1,2], e.peek + assert_equal [1,2], e.next + e = o.to_enum + assert_equal [], e.peek_values + assert_equal [], e.next_values + assert_equal [1], e.peek_values + assert_equal [1], e.next_values + assert_equal [1,2], e.peek_values + assert_equal [1,2], e.next_values + e = o.to_enum + assert_equal [], e.peek_values + assert_equal nil, e.next + assert_equal [1], e.peek_values + assert_equal 1, e.next + assert_equal [1,2], e.peek_values + assert_equal [1,2], e.next + e = o.to_enum + assert_equal nil, e.peek + assert_equal [], e.next_values + assert_equal 1, e.peek + assert_equal [1], e.next_values + assert_equal [1,2], e.peek + assert_equal [1,2], e.next_values +end + +assert 'Enumerator#peek_values modify' do + o = Object.new + def o.each + yield 1,2 + end + e = o.to_enum + a = e.peek_values + a << 3 + assert_equal [1,2], e.peek +end + +assert 'Enumerator#feed' do + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum :each, ary + e.next + e.feed 1 + e.next + e.feed 2 + e.next + e.feed 3 + assert_raise(StopIteration) { e.next } + assert_equal [1,2,3], ary +end + +assert 'Enumerator#feed mixed' do + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum :each, ary + e.next + e.feed 1 + e.next + e.next + e.feed 3 + assert_raise(StopIteration) { e.next } + assert_equal [1,nil,3], ary +end + +assert 'Enumerator#feed twice' do + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum :each, ary + e.feed 1 + assert_raise(TypeError) { e.feed 2 } +end + +assert 'Enumerator#feed before first next' do + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum :each, ary + e.feed 1 + e.next + e.next + assert_equal [1], ary +end + +assert 'Enumerator#feed yielder' do + x = nil + e = Enumerator.new {|y| x = y.yield; 10 } + e.next + e.feed 100 + assert_raise(StopIteration) { e.next } + assert_equal 100, x +end + +assert 'Enumerator#rewind' do + e = @obj.to_enum(:foo, 1, 2, 3) + assert_equal 1, e.next + assert_equal 2, e.next + e.rewind + assert_equal 1, e.next + assert_equal 2, e.next + assert_equal 3, e.next + assert_raise(StopIteration) { e.next } +end + +assert 'Enumerator#rewind clear feed' do + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum(:each, ary) + e.next + e.feed 1 + e.next + e.feed 2 + e.rewind + e.next + e.next + assert_equal([1,nil], ary) +end + +assert 'Enumerator#rewind clear' do + o = Object.new + def o.each(ary) + ary << yield + ary << yield + ary << yield + end + ary = [] + e = o.to_enum :each, ary + e.next + e.feed 1 + e.next + e.feed 2 + e.rewind + e.next + e.next + assert_equal [1,nil], ary +end + +assert 'Enumerator::Generator' do + # note: Enumerator::Generator is a class just for internal + g = Enumerator::Generator.new {|y| y << 1 << 2 << 3; :foo } + g2 = g.dup + a = [] + assert_equal(:foo, g.each {|x| a << x }) + assert_equal([1, 2, 3], a) + a = [] + assert_equal(:foo, g2.each {|x| a << x }) + assert_equal([1, 2, 3], a) +end + +assert 'Enumerator::Generator args' do + g = Enumerator::Generator.new {|y, x| y << 1 << 2 << 3; x } + a = [] + assert_equal(:bar, g.each(:bar) {|x| a << x }) + assert_equal([1, 2, 3], a) +end + +assert 'Enumerator::Yielder' do + # note: Enumerator::Yielder is a class just for internal + a = [] + y = Enumerator::Yielder.new {|x| a << x } + assert_equal(y, y << 1 << 2 << 3) + assert_equal([1, 2, 3], a) + + a = [] + y = Enumerator::Yielder.new {|x| a << x } + assert_equal([1], y.yield(1)) + assert_equal([1, 2], y.yield(2)) + assert_equal([1, 2, 3], y.yield(3)) + + assert_raise(LocalJumpError) { Enumerator::Yielder.new } +end + +assert 'next after StopIteration' do + a = [1] + e = a.each + assert_equal(1, e.next) + assert_raise(StopIteration) { e.next } + assert_raise(StopIteration) { e.next } + e.rewind + assert_equal(1, e.next) + assert_raise(StopIteration) { e.next } + assert_raise(StopIteration) { e.next } +end + +assert 'gc' do + assert_nothing_raised do + 1.times do + foo = [1,2,3].to_enum + GC.start + end + GC.start + end +end + +assert 'nested iteration' do + def (o = Object.new).each + yield :ok1 + yield [:ok2, :x].each.next + end + e = o.to_enum + assert_equal :ok1, e.next + assert_equal :ok2, e.next + assert_raise(StopIteration) { e.next } +end + +assert 'Kernel#to_enum' do + assert_equal Enumerator, [].to_enum.class + assert_raise(ArgumentError){ nil.to_enum } +end + +assert 'modifying existing methods' do + assert_equal Enumerator, loop.class + e = 3.times + i = 0 + loop_ret = loop { + assert_equal i, e.next + i += 1 + } +end + +assert 'Integral#times' do + a = 3 + b = a.times + c = [] + b.with_object(c) do |i, obj| + obj << i + end + assert_equal 3, a + assert_equal Enumerator, b.class + assert_equal [0,1,2], c +end + +assert 'Enumerable#each_with_index' do + assert_equal [['a',0],['b',1],['c',2]], ['a','b','c'].each_with_index.to_a +end + +assert 'Enumerable#map' do + a = [1,2,3] + b = a.map + c = b.with_index do |i, index| + [i*i, index*index] + end + assert_equal [1,2,3], a + assert_equal [[1,0],[4,1],[9,4]], c +end + +assert 'Enumerable#find_all' do + assert_equal [[3,4]], [[1,2],[3,4],[5,6]].find_all.each{ |i| i[1] == 4 } +end + +assert 'Array#each_index' do + a = [1,2,3] + b = a.each_index + c = [] + b.with_index do |index1,index2| + c << [index1+2,index2+5] + end + assert_equal [1,2,3], a + assert_equal [[2,5],[3,6],[4,7]], c +end + +assert 'Array#map!' do + a = [1,2,3] + b = a.map! + b.with_index do |i, index| + [i*i, index*index] + end + assert_equal [[1,0],[4,1],[9,4]], a +end + +assert 'Hash#each' do + a = {a:1,b:2} + b = a.each + c = [] + b.each do |k,v| + c << [k,v] + end + assert_equal [[:a,1], [:b,2]], c.sort +end + +assert 'Hash#each_key' do + assert_equal [:a,:b], {a:1,b:2}.each_key.to_a.sort +end + +assert 'Hash#each_value' do + assert_equal [1,2], {a:1,b:2}.each_value.to_a.sort +end + +assert 'Hash#select' do + h = {1=>2,3=>4,5=>6} + hret = h.select.with_index {|a,b| a[1] == 4} + assert_equal({3=>4}, hret) + assert_equal({1=>2,3=>4,5=>6}, h) +end + +assert 'Hash#select!' do + h = {1=>2,3=>4,5=>6} + hret = h.select!.with_index {|a,b| a[1] == 4} + assert_equal h, hret + assert_equal({3=>4}, h) +end + +assert 'Hash#reject' do + h = {1=>2,3=>4,5=>6} + hret = h.reject.with_index {|a,b| a[1] == 4} + assert_equal({1=>2,5=>6}, hret) + assert_equal({1=>2,3=>4,5=>6}, h) +end + +assert 'Hash#reject!' do + h = {1=>2,3=>4,5=>6} + hret = h.reject!.with_index {|a,b| a[1] == 4} + assert_equal h, hret + assert_equal({1=>2,5=>6}, h) +end + +assert 'Range#each' do + a = (1..5) + b = a.each + c = [] + b.each do |i| + c << i + end + assert_equal [1,2,3,4,5], c +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/mrbgem.rake new file mode 100644 index 000000000..30a4259a8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/mrbgem.rake @@ -0,0 +1,10 @@ +MRuby::Gem::Specification.new('mruby-error') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'extensional error handling' + + if build.cxx_exception_enabled? + @objs << build.compile_as_cxx("#{spec.dir}/src/exception.c", "#{spec.build_dir}/src/exception.cxx") + @objs.delete_if { |v| v == objfile("#{spec.build_dir}/src/exception") } + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/src/exception.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/src/exception.c new file mode 100644 index 000000000..170abb699 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/src/exception.c @@ -0,0 +1,100 @@ +#include <mruby.h> +#include <mruby/throw.h> +#include <mruby/error.h> + +MRB_API mrb_value +mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result = mrb_nil_value(); + + if (state) { *state = FALSE; } + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + result = body(mrb, data); + mrb->jmp = prev_jmp; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + result = mrb_obj_value(mrb->exc); + mrb->exc = NULL; + if (state) { *state = TRUE; } + } MRB_END_EXC(&c_jmp); + + mrb_gc_protect(mrb, result); + return result; +} + +MRB_API mrb_value +mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t ensure, mrb_value e_data) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result; + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + result = body(mrb, b_data); + mrb->jmp = prev_jmp; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + ensure(mrb, e_data); + MRB_THROW(mrb->jmp); /* rethrow catched exceptions */ + } MRB_END_EXC(&c_jmp); + + ensure(mrb, e_data); + mrb_gc_protect(mrb, result); + return result; +} + +MRB_API mrb_value +mrb_rescue(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t rescue, mrb_value r_data) +{ + return mrb_rescue_exceptions(mrb, body, b_data, rescue, r_data, 1, &mrb->eStandardError_class); +} + +MRB_API mrb_value +mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t rescue, mrb_value r_data, + mrb_int len, struct RClass **classes) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result; + mrb_bool error_matched = FALSE; + mrb_int i; + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + result = body(mrb, b_data); + mrb->jmp = prev_jmp; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + + for (i = 0; i < len; ++i) { + if (mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), classes[i])) { + error_matched = TRUE; + break; + } + } + + if (!error_matched) { MRB_THROW(mrb->jmp); } + + mrb->exc = NULL; + result = rescue(mrb, r_data); + } MRB_END_EXC(&c_jmp); + + mrb_gc_protect(mrb, result); + return result; +} + +void +mrb_mruby_error_gem_init(mrb_state *mrb) +{ +} + +void +mrb_mruby_error_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/test/exception.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/test/exception.c new file mode 100644 index 000000000..4de0e9607 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/test/exception.c @@ -0,0 +1,59 @@ +#include <mruby.h> +#include <mruby/error.h> +#include <mruby/array.h> + +static mrb_value +protect_cb(mrb_state *mrb, mrb_value b) +{ + return mrb_yield_argv(mrb, b, 0, NULL); +} + +static mrb_value +run_protect(mrb_state *mrb, mrb_value self) +{ + mrb_value b; + mrb_value ret[2]; + mrb_bool state; + mrb_get_args(mrb, "&", &b); + ret[0] = mrb_protect(mrb, protect_cb, b, &state); + ret[1] = mrb_bool_value(state); + return mrb_ary_new_from_values(mrb, 2, ret); +} + +static mrb_value +run_ensure(mrb_state *mrb, mrb_value self) +{ + mrb_value b, e; + mrb_get_args(mrb, "oo", &b, &e); + return mrb_ensure(mrb, protect_cb, b, protect_cb, e); +} + +static mrb_value +run_rescue(mrb_state *mrb, mrb_value self) +{ + mrb_value b, r; + mrb_get_args(mrb, "oo", &b, &r); + return mrb_rescue(mrb, protect_cb, b, protect_cb, r); +} + +static mrb_value +run_rescue_exceptions(mrb_state *mrb, mrb_value self) +{ + mrb_value b, r; + struct RClass *cls[1]; + mrb_get_args(mrb, "oo", &b, &r); + cls[0] = E_TYPE_ERROR; + return mrb_rescue_exceptions(mrb, protect_cb, b, protect_cb, r, 1, cls); +} + +void +mrb_mruby_error_gem_test(mrb_state *mrb) +{ + struct RClass *cls; + + cls = mrb_define_class(mrb, "ExceptionTest", mrb->object_class); + mrb_define_module_function(mrb, cls, "mrb_protect", run_protect, MRB_ARGS_NONE() | MRB_ARGS_BLOCK()); + mrb_define_module_function(mrb, cls, "mrb_ensure", run_ensure, MRB_ARGS_REQ(2)); + mrb_define_module_function(mrb, cls, "mrb_rescue", run_rescue, MRB_ARGS_REQ(2)); + mrb_define_module_function(mrb, cls, "mrb_rescue_exceptions", run_rescue_exceptions, MRB_ARGS_REQ(2)); +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/test/exception.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/test/exception.rb new file mode 100644 index 000000000..908465045 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-error/test/exception.rb @@ -0,0 +1,55 @@ +assert 'mrb_protect' do + # no failure in protect returns [result, false] + assert_equal ['test', false] do + ExceptionTest.mrb_protect { 'test' } + end + # failure in protect returns [exception, true] + result = ExceptionTest.mrb_protect { raise 'test' } + assert_kind_of RuntimeError, result[0] + assert_true result[1] +end + +assert 'mrb_ensure' do + a = false + assert_equal 'test' do + ExceptionTest.mrb_ensure Proc.new { 'test' }, Proc.new { a = true } + end + assert_true a + + a = false + assert_raise RuntimeError do + ExceptionTest.mrb_ensure Proc.new { raise 'test' }, Proc.new { a = true } + end + assert_true a +end + +assert 'mrb_rescue' do + assert_equal 'test' do + ExceptionTest.mrb_rescue Proc.new { 'test' }, Proc.new {} + end + + class CustomExp < Exception + end + + assert_raise CustomExp do + ExceptionTest.mrb_rescue Proc.new { raise CustomExp.new 'test' }, Proc.new { 'rescue' } + end + + assert_equal 'rescue' do + ExceptionTest.mrb_rescue Proc.new { raise 'test' }, Proc.new { 'rescue' } + end +end + +assert 'mrb_rescue_exceptions' do + assert_equal 'test' do + ExceptionTest.mrb_rescue_exceptions Proc.new { 'test' }, Proc.new {} + end + + assert_raise RangeError do + ExceptionTest.mrb_rescue_exceptions Proc.new { raise RangeError.new 'test' }, Proc.new { 'rescue' } + end + + assert_equal 'rescue' do + ExceptionTest.mrb_rescue_exceptions Proc.new { raise TypeError.new 'test' }, Proc.new { 'rescue' } + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-eval/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-eval/mrbgem.rake new file mode 100644 index 000000000..cb8835b32 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-eval/mrbgem.rake @@ -0,0 +1,7 @@ +MRuby::Gem::Specification.new('mruby-eval') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'standard Kernel#eval method' + + add_dependency 'mruby-compiler', :core => 'mruby-compiler' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-eval/src/eval.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-eval/src/eval.c new file mode 100644 index 000000000..5c0ea82f4 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-eval/src/eval.c @@ -0,0 +1,346 @@ +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/compile.h> +#include <mruby/irep.h> +#include <mruby/proc.h> +#include <mruby/opcode.h> +#include <mruby/error.h> + +mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p); +mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self); + +static struct mrb_irep * +get_closure_irep(mrb_state *mrb, int level) +{ + struct mrb_context *c = mrb->c; + struct REnv *e = c->ci[-1].proc->env; + struct RProc *proc; + + if (level == 0) { + proc = c->ci[-1].proc; + if (MRB_PROC_CFUNC_P(proc)) { + return NULL; + } + return proc->body.irep; + } + + while (--level) { + e = (struct REnv*)e->c; + if (!e) return NULL; + } + + if (!e) return NULL; + if (!MRB_ENV_STACK_SHARED_P(e)) return NULL; + c = e->cxt.c; + proc = c->cibase[e->cioff].proc; + + if (!proc || MRB_PROC_CFUNC_P(proc)) { + return NULL; + } + return proc->body.irep; +} + +/* search for irep lev above the bottom */ +static mrb_irep* +search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom) +{ + int i; + + for (i=0; i<top->rlen; i++) { + mrb_irep* tmp = top->reps[i]; + + if (tmp == bottom) return top; + tmp = search_irep(tmp, bnest-1, lev, bottom); + if (tmp) { + if (bnest == lev) return top; + return tmp; + } + } + return NULL; +} + +static inline mrb_code +search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) +{ + mrb_irep *virep; + int level; + int pos; + + for (level = 0; (virep = get_closure_irep(mrb, level)); level++) { + if (!virep || virep->lv == NULL) { + continue; + } + for (pos = 0; pos < virep->nlocals - 1; pos++) { + if (vsym == virep->lv[pos].name) { + return (MKARG_B(pos + 1) | MKARG_C(level + bnest)); + } + } + } + + return 0; +} + +static int +irep_argc(mrb_irep *irep) +{ + mrb_code c; + + c = irep->iseq[0]; + if (GET_OPCODE(c) == OP_ENTER) { + mrb_aspec ax = GETARG_Ax(c); + /* extra 1 means a slot for block */ + return MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1; + } + return 0; +} + +static mrb_bool +potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals) +{ + if (v >= nlocals) return FALSE; + /* skip arguments */ + if (v < argc+1) return FALSE; + return TRUE; +} + +static void +patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) +{ + int i; + mrb_code c; + int argc = irep_argc(irep); + + for (i = 0; i < irep->ilen; i++) { + c = irep->iseq[i]; + switch(GET_OPCODE(c)){ + case OP_EPUSH: + patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1, top); + break; + + case OP_LAMBDA: + { + int arg_c = GETARG_c(c); + if (arg_c & OP_L_CAPTURE) { + patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1, top); + } + } + break; + + case OP_SEND: + if (GETARG_C(c) != 0) { + break; + } + { + mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest); + if (arg != 0) { + /* must replace */ + irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + } + } + break; + + case OP_MOVE: + /* src part */ + if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) { + mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest); + if (arg != 0) { + /* must replace */ + irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + } + } + /* dst part */ + if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) { + mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest); + if (arg != 0) { + /* must replace */ + irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg; + } + } + break; + + case OP_GETUPVAR: + { + int lev = GETARG_C(c)+1; + mrb_irep *tmp = search_irep(top, bnest, lev, irep); + if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) { + mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest); + if (arg != 0) { + /* must replace */ + irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + } + } + } + break; + + case OP_SETUPVAR: + { + int lev = GETARG_C(c)+1; + mrb_irep *tmp = search_irep(top, bnest, lev, irep); + if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) { + mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest); + if (arg != 0) { + /* must replace */ + irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + } + } + } + break; + + case OP_STOP: + if (mrb->c->ci->acc >= 0) { + irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL); + } + break; + } + } +} + +void mrb_codedump_all(mrb_state*, struct RProc*); + +static struct RProc* +create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, const char *file, mrb_int line) +{ + mrbc_context *cxt; + struct mrb_parser_state *p; + struct RProc *proc; + struct REnv *e; + struct mrb_context *c = mrb->c; + + if (!mrb_nil_p(binding)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "Binding of eval must be nil."); + } + + cxt = mrbc_context_new(mrb); + cxt->lineno = line; + + mrbc_filename(mrb, cxt, file ? file : "(eval)"); + cxt->capture_errors = TRUE; + cxt->no_optimize = TRUE; + + p = mrb_parse_nstring(mrb, s, len, cxt); + + /* only occur when memory ran out */ + if (!p) { + mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to create parser state."); + } + + if (0 < p->nerr) { + /* parse error */ + mrb_value str; + + if (file) { + str = mrb_format(mrb, " file %S line %S: %S", + mrb_str_new_cstr(mrb, file), + mrb_fixnum_value(p->error_buffer[0].lineno), + mrb_str_new_cstr(mrb, p->error_buffer[0].message)); + } + else { + str = mrb_format(mrb, " line %S: %S", + mrb_fixnum_value(p->error_buffer[0].lineno), + mrb_str_new_cstr(mrb, p->error_buffer[0].message)); + } + mrb_parser_free(p); + mrbc_context_free(mrb, cxt); + mrb_exc_raise(mrb, mrb_exc_new_str(mrb, E_SYNTAX_ERROR, str)); + } + + proc = mrb_generate_code(mrb, p); + if (proc == NULL) { + /* codegen error */ + mrb_parser_free(p); + mrbc_context_free(mrb, cxt); + mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error"); + } + if (c->ci[-1].proc->target_class) { + proc->target_class = c->ci[-1].proc->target_class; + } + e = c->ci[-1].proc->env; + if (!e) e = c->ci[-1].env; + e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)e); + e->cxt.c = c; + e->cioff = c->ci - c->cibase; + e->stack = c->ci->stackent; + MRB_SET_ENV_STACK_LEN(e, c->ci->proc->body.irep->nlocals); + c->ci->target_class = proc->target_class; + c->ci->env = 0; + proc->env = e; + patch_irep(mrb, proc->body.irep, 0, proc->body.irep); + /* mrb_codedump_all(mrb, proc); */ + + mrb_parser_free(p); + mrbc_context_free(mrb, cxt); + + return proc; +} + +static mrb_value +exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc) +{ + if (mrb->c->ci->acc < 0) { + mrb_value ret = mrb_top_run(mrb, proc, mrb->c->stack[0], 0); + if (mrb->exc) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); + } + return ret; + } + return mrb_exec_irep(mrb, self, proc); +} + +static mrb_value +f_eval(mrb_state *mrb, mrb_value self) +{ + char *s; + mrb_int len; + mrb_value binding = mrb_nil_value(); + char *file = NULL; + mrb_int line = 1; + struct RProc *proc; + + mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line); + + proc = create_proc_from_string(mrb, s, len, binding, file, line); + mrb_assert(!MRB_PROC_CFUNC_P(proc)); + return exec_irep(mrb, self, proc); +} + +static mrb_value +f_instance_eval(mrb_state *mrb, mrb_value self) +{ + mrb_value b; + mrb_int argc; mrb_value *argv; + + mrb_get_args(mrb, "*!&", &argv, &argc, &b); + + if (mrb_nil_p(b)) { + char *s; + mrb_int len; + char *file = NULL; + mrb_int line = 1; + mrb_value cv; + struct RProc *proc; + + mrb_get_args(mrb, "s|zi", &s, &len, &file, &line); + cv = mrb_singleton_class(mrb, self); + proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line); + proc->target_class = mrb_class_ptr(cv); + mrb->c->ci->env = NULL; + mrb_assert(!MRB_PROC_CFUNC_P(proc)); + return exec_irep(mrb, self, proc); + } + else { + mrb_get_args(mrb, "&", &b); + return mrb_obj_instance_eval(mrb, self); + } +} + +void +mrb_mruby_eval_gem_init(mrb_state* mrb) +{ + mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_ARG(1, 3)); + mrb_define_method(mrb, mrb->kernel_module, "instance_eval", f_instance_eval, MRB_ARGS_ARG(1, 2)); +} + +void +mrb_mruby_eval_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-eval/test/eval.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-eval/test/eval.rb new file mode 100644 index 000000000..66ca1fcdb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-eval/test/eval.rb @@ -0,0 +1,101 @@ +assert('Kernel.eval', '15.3.1.2.3') do + assert_equal(10) { Kernel.eval '1 * 10' } + assert_equal('aaa') { Kernel.eval "'a' * 3" } + assert_equal(10) { + a = 10 + Kernel.eval "a" + } + assert_equal(20) { + a = 10 + Kernel.eval "a = 20" + a + } + assert_equal(15) { + c = 5 + lambda { + a = 10 + Kernel.eval "c = a + c" + }.call + c + } + assert_equal(5) { + c = 5 + lambda { + Kernel.eval 'lambda { c }.call' + }.call + } + assert_equal(15) { + c = 5 + lambda { + a = 10 + Kernel.eval 'lambda { c = a + c }.call' + }.call + c + } + assert_equal(2) { + a = 10 + Kernel.eval 'def f(a); b=a.send(:+, 1); end' + f(1) + } +end + +assert('Kernel#eval', '15.3.1.3.12') do + assert_equal(10) { eval '1 * 10' } +end + +assert('rest arguments of eval') do + assert_raise(ArgumentError) { Kernel.eval('0', 0, 'test', 0) } + assert_equal ['test', 'test.rb', 10] do + Kernel.eval('[\'test\', __FILE__, __LINE__]', nil, 'test.rb', 10) + end +end + +assert 'eval syntax error' do + assert_raise(SyntaxError) do + eval 'p "test' + end +end + +assert('String instance_eval') do + obj = Object.new + obj.instance_variable_set :@test, 'test' + assert_raise(ArgumentError) { obj.instance_eval(0) { } } + assert_raise(ArgumentError) { obj.instance_eval('0', 'test', 0, 'test') } + assert_equal(['test.rb', 10]) { obj.instance_eval('[__FILE__, __LINE__]', 'test.rb', 10)} + assert_equal('test') { obj.instance_eval('@test') } + assert_equal('test') { obj.instance_eval { @test } } + o = Object.new + assert_equal ['', o, o], o.instance_eval("[''].each { |s| break [s, o, self] }") +end + +assert('Kernel.#eval(string) context') do + class TestEvalConstScope + EVAL_CONST_CLASS = 'class' + def const_string + eval 'EVAL_CONST_CLASS' + end + end + obj = TestEvalConstScope.new + assert_raise(NameError) { eval 'EVAL_CONST_CLASS' } + assert_equal('class') { obj.const_string } +end + +assert('Object#instance_eval with begin-rescue-ensure execution order') do + class HellRaiser + def raise_hell + order = [:enter_raise_hell] + begin + order.push :begin + self.instance_eval("raise 'error'") + rescue + order.push :rescue + ensure + order.push :ensure + end + order + end + end + + hell_raiser = HellRaiser.new + assert_equal([:enter_raise_hell, :begin, :rescue, :ensure], hell_raiser.raise_hell) +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-exit/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-exit/mrbgem.rake new file mode 100644 index 000000000..d193528da --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-exit/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-exit') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Kernel#exit method' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-exit/src/mruby-exit.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-exit/src/mruby-exit.c new file mode 100644 index 000000000..3e147f80b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-exit/src/mruby-exit.c @@ -0,0 +1,24 @@ +#include <stdlib.h> +#include <mruby.h> + +static mrb_value +f_exit(mrb_state *mrb, mrb_value self) +{ + mrb_int i = EXIT_SUCCESS; + + mrb_get_args(mrb, "|i", &i); + exit(i); + /* not reached */ + return mrb_nil_value(); +} + +void +mrb_mruby_exit_gem_init(mrb_state* mrb) +{ + mrb_define_method(mrb, mrb->kernel_module, "exit", f_exit, MRB_ARGS_OPT(1)); +} + +void +mrb_mruby_exit_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-fiber/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-fiber/mrbgem.rake new file mode 100644 index 000000000..815cd3c4b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-fiber/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-fiber') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Fiber class' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-fiber/src/fiber.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-fiber/src/fiber.c new file mode 100644 index 000000000..9de175f34 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-fiber/src/fiber.c @@ -0,0 +1,420 @@ +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/proc.h> + +#define fiber_ptr(o) ((struct RFiber*)mrb_ptr(o)) + +#define FIBER_STACK_INIT_SIZE 64 +#define FIBER_CI_INIT_SIZE 8 +#define CI_ACC_RESUMED -3 + +/* + * call-seq: + * Fiber.new{...} -> obj + * + * Creates a fiber, whose execution is suspend until it is explicitly + * resumed using <code>Fiber#resume</code> method. + * The code running inside the fiber can give up control by calling + * <code>Fiber.yield</code> in which case it yields control back to caller + * (the caller of the <code>Fiber#resume</code>). + * + * Upon yielding or termination the Fiber returns the value of the last + * executed expression + * + * For instance: + * + * fiber = Fiber.new do + * Fiber.yield 1 + * 2 + * end + * + * puts fiber.resume + * puts fiber.resume + * puts fiber.resume + * + * <em>produces</em> + * + * 1 + * 2 + * resuming dead fiber (FiberError) + * + * The <code>Fiber#resume</code> method accepts an arbitrary number of + * parameters, if it is the first call to <code>resume</code> then they + * will be passed as block arguments. Otherwise they will be the return + * value of the call to <code>Fiber.yield</code> + * + * Example: + * + * fiber = Fiber.new do |first| + * second = Fiber.yield first + 2 + * end + * + * puts fiber.resume 10 + * puts fiber.resume 14 + * puts fiber.resume 18 + * + * <em>produces</em> + * + * 12 + * 14 + * resuming dead fiber (FiberError) + * + */ +static mrb_value +fiber_init(mrb_state *mrb, mrb_value self) +{ + static const struct mrb_context mrb_context_zero = { 0 }; + struct RFiber *f = fiber_ptr(self); + struct mrb_context *c; + struct RProc *p; + mrb_callinfo *ci; + mrb_value blk; + size_t slen; + + mrb_get_args(mrb, "&", &blk); + + if (f->cxt) { + mrb_raise(mrb, E_RUNTIME_ERROR, "cannot initialize twice"); + } + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Fiber object without a block"); + } + p = mrb_proc_ptr(blk); + if (MRB_PROC_CFUNC_P(p)) { + mrb_raise(mrb, E_FIBER_ERROR, "tried to create Fiber from C defined method"); + } + + c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context)); + *c = mrb_context_zero; + f->cxt = c; + + /* initialize VM stack */ + slen = FIBER_STACK_INIT_SIZE; + if (p->body.irep->nregs > slen) { + slen += p->body.irep->nregs; + } + c->stbase = (mrb_value *)mrb_malloc(mrb, slen*sizeof(mrb_value)); + c->stend = c->stbase + slen; + c->stack = c->stbase; + +#ifdef MRB_NAN_BOXING + { + mrb_value *p = c->stbase; + mrb_value *pend = c->stend; + + while (p < pend) { + SET_NIL_VALUE(*p); + p++; + } + } +#else + memset(c->stbase, 0, slen * sizeof(mrb_value)); +#endif + + /* copy receiver from a block */ + c->stack[0] = mrb->c->stack[0]; + + /* initialize callinfo stack */ + c->cibase = (mrb_callinfo *)mrb_calloc(mrb, FIBER_CI_INIT_SIZE, sizeof(mrb_callinfo)); + c->ciend = c->cibase + FIBER_CI_INIT_SIZE; + c->ci = c->cibase; + c->ci->stackent = c->stack; + + /* adjust return callinfo */ + ci = c->ci; + ci->target_class = p->target_class; + ci->proc = p; + mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p); + ci->pc = p->body.irep->iseq; + ci->nregs = p->body.irep->nregs; + ci[1] = ci[0]; + c->ci++; /* push dummy callinfo */ + + c->fib = f; + c->status = MRB_FIBER_CREATED; + + return self; +} + +static struct mrb_context* +fiber_check(mrb_state *mrb, mrb_value fib) +{ + struct RFiber *f = fiber_ptr(fib); + + mrb_assert(f->tt == MRB_TT_FIBER); + if (!f->cxt) { + mrb_raise(mrb, E_FIBER_ERROR, "uninitialized Fiber"); + } + return f->cxt; +} + +static mrb_value +fiber_result(mrb_state *mrb, const mrb_value *a, mrb_int len) +{ + if (len == 0) return mrb_nil_value(); + if (len == 1) return a[0]; + return mrb_ary_new_from_values(mrb, len, a); +} + +/* mark return from context modifying method */ +#define MARK_CONTEXT_MODIFY(c) (c)->ci->target_class = NULL + +static void +fiber_check_cfunc(mrb_state *mrb, struct mrb_context *c) +{ + mrb_callinfo *ci; + + for (ci = c->ci; ci >= c->cibase; ci--) { + if (ci->acc < 0) { + mrb_raise(mrb, E_FIBER_ERROR, "can't cross C function boundary"); + } + } +} + +static void +fiber_switch_context(mrb_state *mrb, struct mrb_context *c) +{ + if (mrb->c->fib) { + mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib); + } + c->status = MRB_FIBER_RUNNING; + mrb->c = c; +} + +static mrb_value +fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume, mrb_bool vmexec) +{ + struct mrb_context *c = fiber_check(mrb, self); + struct mrb_context *old_c = mrb->c; + mrb_value value; + + fiber_check_cfunc(mrb, c); + if (resume && c->status == MRB_FIBER_TRANSFERRED) { + mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber"); + } + if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMED) { + mrb_raise(mrb, E_FIBER_ERROR, "double resume (fib)"); + } + if (c->status == MRB_FIBER_TERMINATED) { + mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber"); + } + mrb->c->status = resume ? MRB_FIBER_RESUMED : MRB_FIBER_TRANSFERRED; + c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c); + if (c->status == MRB_FIBER_CREATED) { + mrb_value *b, *e; + + if (len >= c->stend - c->stack) { + mrb_raise(mrb, E_FIBER_ERROR, "too many arguments to fiber"); + } + b = c->stack+1; + e = b + len; + while (b<e) { + *b++ = *a++; + } + c->cibase->argc = len; + value = c->stack[0] = c->ci->proc->env->stack[0]; + } + else { + value = fiber_result(mrb, a, len); + } + fiber_switch_context(mrb, c); + + if (vmexec) { + c->vmexec = TRUE; + value = mrb_vm_exec(mrb, c->ci[-1].proc, c->ci->pc); + mrb->c = old_c; + } + else { + MARK_CONTEXT_MODIFY(c); + } + return value; +} + +/* + * call-seq: + * fiber.resume(args, ...) -> obj + * + * Resumes the fiber from the point at which the last <code>Fiber.yield</code> + * was called, or starts running it if it is the first call to + * <code>resume</code>. Arguments passed to resume will be the value of + * the <code>Fiber.yield</code> expression or will be passed as block + * parameters to the fiber's block if this is the first <code>resume</code>. + * + * Alternatively, when resume is called it evaluates to the arguments passed + * to the next <code>Fiber.yield</code> statement inside the fiber's block + * or to the block value if it runs to completion without any + * <code>Fiber.yield</code> + */ +static mrb_value +fiber_resume(mrb_state *mrb, mrb_value self) +{ + mrb_value *a; + mrb_int len; + mrb_bool vmexec = FALSE; + + mrb_get_args(mrb, "*!", &a, &len); + if (mrb->c->ci->acc < 0) { + vmexec = TRUE; + } + return fiber_switch(mrb, self, len, a, TRUE, vmexec); +} + +/* resume thread with given arguments */ +MRB_API mrb_value +mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int len, const mrb_value *a) +{ + return fiber_switch(mrb, fib, len, a, TRUE, TRUE); +} + +/* + * call-seq: + * fiber.alive? -> true or false + * + * Returns true if the fiber can still be resumed. After finishing + * execution of the fiber block this method will always return false. + */ +static mrb_value +fiber_alive_p(mrb_state *mrb, mrb_value self) +{ + struct mrb_context *c = fiber_check(mrb, self); + return mrb_bool_value(c->status != MRB_FIBER_TERMINATED); +} + +static mrb_value +fiber_eq(mrb_state *mrb, mrb_value self) +{ + mrb_value other; + mrb_get_args(mrb, "o", &other); + + if (mrb_type(other) != MRB_TT_FIBER) { + return mrb_false_value(); + } + return mrb_bool_value(fiber_ptr(self) == fiber_ptr(other)); +} + +/* + * call-seq: + * fiber.transfer(args, ...) -> obj + * + * Transfers control to receiver fiber of the method call. + * Unlike <code>resume</code> the receiver wouldn't be pushed to call + * stack of fibers. Instead it will switch to the call stack of + * transferring fiber. + * When resuming a fiber that was transferred to another fiber it would + * cause double resume error. Though when the fiber is re-transferred + * and <code>Fiber.yield</code> is called, the fiber would be resumable. + */ +static mrb_value +fiber_transfer(mrb_state *mrb, mrb_value self) +{ + struct mrb_context *c = fiber_check(mrb, self); + mrb_value* a; + mrb_int len; + + fiber_check_cfunc(mrb, mrb->c); + mrb_get_args(mrb, "*!", &a, &len); + + if (c == mrb->root_c) { + mrb->c->status = MRB_FIBER_TRANSFERRED; + fiber_switch_context(mrb, c); + MARK_CONTEXT_MODIFY(c); + return fiber_result(mrb, a, len); + } + + if (c == mrb->c) { + return fiber_result(mrb, a, len); + } + + return fiber_switch(mrb, self, len, a, FALSE, FALSE); +} + +/* yield values to the caller fiber */ +/* mrb_fiber_yield() must be called as `return mrb_fiber_yield(...)` */ +MRB_API mrb_value +mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a) +{ + struct mrb_context *c = mrb->c; + + if (!c->prev) { + mrb_raise(mrb, E_FIBER_ERROR, "can't yield from root fiber"); + } + + fiber_check_cfunc(mrb, c); + c->prev->status = MRB_FIBER_RUNNING; + c->status = MRB_FIBER_SUSPENDED; + fiber_switch_context(mrb, c->prev); + c->prev = NULL; + if (c->vmexec) { + c->vmexec = FALSE; + mrb->c->ci->acc = CI_ACC_RESUMED; + } + MARK_CONTEXT_MODIFY(mrb->c); + return fiber_result(mrb, a, len); +} + +/* + * call-seq: + * Fiber.yield(args, ...) -> obj + * + * Yields control back to the context that resumed the fiber, passing + * along any arguments that were passed to it. The fiber will resume + * processing at this point when <code>resume</code> is called next. + * Any arguments passed to the next <code>resume</code> will be the + * + * mruby limitation: Fiber resume/yield cannot cross C function boundary. + * thus you cannot yield from #initialize which is called by mrb_funcall(). + */ +static mrb_value +fiber_yield(mrb_state *mrb, mrb_value self) +{ + mrb_value *a; + mrb_int len; + + mrb_get_args(mrb, "*!", &a, &len); + return mrb_fiber_yield(mrb, len, a); +} + +/* + * call-seq: + * Fiber.current() -> fiber + * + * Returns the current fiber. If you are not running in the context of + * a fiber this method will return the root fiber. + */ +static mrb_value +fiber_current(mrb_state *mrb, mrb_value self) +{ + if (!mrb->c->fib) { + struct RFiber *f = (struct RFiber*)mrb_obj_alloc(mrb, MRB_TT_FIBER, mrb_class_ptr(self)); + + f->cxt = mrb->c; + mrb->c->fib = f; + } + return mrb_obj_value(mrb->c->fib); +} + +void +mrb_mruby_fiber_gem_init(mrb_state* mrb) +{ + struct RClass *c; + + c = mrb_define_class(mrb, "Fiber", mrb->object_class); + MRB_SET_INSTANCE_TT(c, MRB_TT_FIBER); + + mrb_define_method(mrb, c, "initialize", fiber_init, MRB_ARGS_NONE()); + mrb_define_method(mrb, c, "resume", fiber_resume, MRB_ARGS_ANY()); + mrb_define_method(mrb, c, "transfer", fiber_transfer, MRB_ARGS_ANY()); + mrb_define_method(mrb, c, "alive?", fiber_alive_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, c, "==", fiber_eq, MRB_ARGS_REQ(1)); + + mrb_define_class_method(mrb, c, "yield", fiber_yield, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, c, "current", fiber_current, MRB_ARGS_NONE()); + + mrb_define_class(mrb, "FiberError", mrb->eStandardError_class); +} + +void +mrb_mruby_fiber_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-fiber/test/fiber.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-fiber/test/fiber.rb new file mode 100644 index 000000000..d063a0a62 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-fiber/test/fiber.rb @@ -0,0 +1,208 @@ +assert('Fiber.new') do + f = Fiber.new{} + assert_kind_of Fiber, f +end + +assert('Fiber#resume') do + f = Fiber.new{|x| x } + assert_equal 2, f.resume(2) +end + +assert('Fiber#transfer') do + f2 = nil + f1 = Fiber.new do |v| + Fiber.yield v + f2.transfer + end + f2 = Fiber.new do + f1.transfer(1) + f1.transfer(1) + Fiber.yield 2 + end + assert_equal 1, f2.resume + assert_raise(FiberError) { f2.resume } + assert_equal 2, f2.transfer + assert_raise(FiberError) { f1.resume } + f1.transfer + f2.resume + assert_false f1.alive? + assert_false f2.alive? +end + +assert('Fiber#alive?') do + f = Fiber.new{ Fiber.yield } + f.resume + assert_true f.alive? + f.resume + assert_false f.alive? +end + +assert('Fiber#==') do + root = Fiber.current + assert_equal root, root + assert_equal root, Fiber.current + assert_false root != Fiber.current + f = Fiber.new { + assert_false root == Fiber.current + } + f.resume + assert_false f == root + assert_true f != root +end + +assert('Fiber.yield') do + f = Fiber.new{|x| Fiber.yield x } + assert_equal 3, f.resume(3) + assert_true f.alive? +end + +assert('FiberError') do + assert_equal StandardError, FiberError.superclass +end + +assert('Fiber iteration') do + f1 = Fiber.new{ + [1,2,3].each{|x| Fiber.yield(x)} + } + f2 = Fiber.new{ + [9,8,7].each{|x| Fiber.yield(x)} + } + a = [] + 3.times { + a << f1.resume + a << f2.resume + } + assert_equal [1,9,2,8,3,7], a +end + +assert('Fiber with splat in the block argument list') { + Fiber.new{|*x|x}.resume(1) == [1] +} + +assert('Fiber raises on resume when dead') do + assert_raise(FiberError) do + f = Fiber.new{} + f.resume + assert_false f.alive? + f.resume + end +end + +assert('Yield raises when called on root fiber') do + assert_raise(FiberError) { Fiber.yield } +end + +assert('Double resume of Fiber') do + f1 = Fiber.new {} + f2 = Fiber.new { + f1.resume + assert_raise(FiberError) { f2.resume } + Fiber.yield 0 + } + assert_equal 0, f2.resume + f2.resume + assert_false f1.alive? + assert_false f2.alive? +end + +assert('Recursive resume of Fiber') do + f1, f2 = nil, nil + f1 = Fiber.new { assert_raise(FiberError) { f2.resume } } + f2 = Fiber.new { + f1.resume + Fiber.yield 0 + } + f3 = Fiber.new { + f2.resume + } + assert_equal 0, f3.resume + f2.resume + assert_false f1.alive? + assert_false f2.alive? + assert_false f3.alive? +end + +assert('Root fiber resume') do + root = Fiber.current + assert_raise(FiberError) { root.resume } + f = Fiber.new { + assert_raise(FiberError) { root.resume } + } + f.resume + assert_false f.alive? +end + +assert('Fiber without block') do + assert_raise(ArgumentError) { Fiber.new } +end + + +assert('Transfer to self.') do + result = [] + f = Fiber.new { result << :start; f.transfer; result << :end } + f.transfer + assert_equal [:start, :end], result + + result = [] + f = Fiber.new { result << :start; f.transfer; result << :end } + f.resume + assert_equal [:start, :end], result +end + +assert('Resume transferred fiber') do + f = Fiber.new { + assert_raise(FiberError) { f.resume } + } + f.transfer +end + +assert('Root fiber transfer.') do + result = nil + root = Fiber.current + f = Fiber.new { + result = :ok + root.transfer + } + f.resume + assert_true f.alive? + assert_equal :ok, result +end + +assert('Break nested fiber with root fiber transfer') do + root = Fiber.current + + result = nil + f2 = nil + f1 = Fiber.new { + Fiber.yield f2.resume + result = :f1 + } + f2 = Fiber.new { + result = :to_root + root.transfer :from_f2 + result = :f2 + } + assert_equal :from_f2, f1.resume + assert_equal :to_root, result + assert_equal :f2, f2.transfer + assert_equal :f2, result + assert_false f2.alive? + assert_equal :f1, f1.resume + assert_equal :f1, result + assert_false f1.alive? +end + +assert('CRuby Fiber#transfer test.') do + ary = [] + f2 = nil + f1 = Fiber.new{ + ary << f2.transfer(:foo) + :ok + } + f2 = Fiber.new{ + ary << f1.transfer(:baz) + :ng + } + assert_equal :ok, f1.transfer + assert_equal [:baz], ary +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/mrbgem.rake new file mode 100644 index 000000000..103410ab9 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/mrbgem.rake @@ -0,0 +1,8 @@ +MRuby::Gem::Specification.new('mruby-hash-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Hash class extension' + spec.add_dependency 'mruby-enum-ext', core: 'mruby-enum-ext' + spec.add_dependency 'mruby-array-ext', core: 'mruby-array-ext' + spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/mrblib/hash.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/mrblib/hash.rb new file mode 100644 index 000000000..73d1fbe6d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -0,0 +1,477 @@ +class Hash + + # ISO does not define Hash#each_pair, so each_pair is defined in gem. + alias each_pair each + + ## + # call-seq: + # Hash[ key, value, ... ] -> new_hash + # Hash[ [ [key, value], ... ] ] -> new_hash + # Hash[ object ] -> new_hash + # + # Creates a new hash populated with the given objects. + # + # Similar to the literal `{ _key_ => _value_, ... }`. In the first + # form, keys and values occur in pairs, so there must be an even number of + # arguments. + # + # The second and third form take a single argument which is either an array + # of key-value pairs or an object convertible to a hash. + # + # Hash["a", 100, "b", 200] #=> {"a"=>100, "b"=>200} + # Hash[ [ ["a", 100], ["b", 200] ] ] #=> {"a"=>100, "b"=>200} + # Hash["a" => 100, "b" => 200] #=> {"a"=>100, "b"=>200} + # + + def self.[](*object) + length = object.length + if length == 1 + o = object[0] + if o.respond_to?(:to_hash) + h = self.new + object[0].to_hash.each { |k, v| h[k] = v } + return h + elsif o.respond_to?(:to_a) + h = self.new + o.to_a.each do |i| + raise ArgumentError, "wrong element type #{i.class} (expected array)" unless i.respond_to?(:to_a) + k, v = nil + case i.size + when 2 + k = i[0] + v = i[1] + when 1 + k = i[0] + else + raise ArgumentError, "invalid number of elements (#{i.size} for 1..2)" + end + h[k] = v + end + return h + end + end + unless length % 2 == 0 + raise ArgumentError, 'odd number of arguments for Hash' + end + h = self.new + 0.step(length - 2, 2) do |i| + h[object[i]] = object[i + 1] + end + h + end + + ## + # call-seq: + # Hash.try_convert(obj) -> hash or nil + # + # Try to convert <i>obj</i> into a hash, using to_hash method. + # Returns converted hash or nil if <i>obj</i> cannot be converted + # for any reason. + # + # Hash.try_convert({1=>2}) # => {1=>2} + # Hash.try_convert("1=>2") # => nil + # + def self.try_convert(obj) + if obj.respond_to?(:to_hash) + obj.to_hash + else + nil + end + end + + ## + # call-seq: + # hsh.merge!(other_hash) -> hsh + # hsh.merge!(other_hash){|key, oldval, newval| block} -> hsh + # + # Adds the contents of _other_hash_ to _hsh_. If no block is specified, + # entries with duplicate keys are overwritten with the values from + # _other_hash_, otherwise the value of each duplicate key is determined by + # calling the block with the key, its value in _hsh_ and its value in + # _other_hash_. + # + # h1 = { "a" => 100, "b" => 200 } + # h2 = { "b" => 254, "c" => 300 } + # h1.merge!(h2) #=> {"a"=>100, "b"=>254, "c"=>300} + # + # h1 = { "a" => 100, "b" => 200 } + # h2 = { "b" => 254, "c" => 300 } + # h1.merge!(h2) { |key, v1, v2| v1 } + # #=> {"a"=>100, "b"=>200, "c"=>300} + # + + def merge!(other, &block) + raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash) + if block + other.each_key{|k| + self[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k] + } + else + other.each_key{|k| self[k] = other[k]} + end + self + end + + alias update merge! + + ## + # call-seq: + # hsh.compact -> new_hsh + # + # Returns a new hash with the nil values/key pairs removed + # + # h = { a: 1, b: false, c: nil } + # h.compact #=> { a: 1, b: false } + # h #=> { a: 1, b: false, c: nil } + # + def compact + result = self.dup + result.compact! + result + end + + ## + # call-seq: + # hsh.fetch(key [, default] ) -> obj + # hsh.fetch(key) {| key | block } -> obj + # + # Returns a value from the hash for the given key. If the key can't be + # found, there are several options: With no other arguments, it will + # raise an <code>KeyError</code> exception; if <i>default</i> is + # given, then that will be returned; if the optional code block is + # specified, then that will be run and its result returned. + # + # h = { "a" => 100, "b" => 200 } + # h.fetch("a") #=> 100 + # h.fetch("z", "go fish") #=> "go fish" + # h.fetch("z") { |el| "go fish, #{el}"} #=> "go fish, z" + # + # The following example shows that an exception is raised if the key + # is not found and a default value is not supplied. + # + # h = { "a" => 100, "b" => 200 } + # h.fetch("z") + # + # <em>produces:</em> + # + # prog.rb:2:in 'fetch': key not found (KeyError) + # from prog.rb:2 + # + + def fetch(key, none=NONE, &block) + unless self.key?(key) + if block + block.call(key) + elsif none != NONE + none + else + raise KeyError, "Key not found: #{key}" + end + else + self[key] + end + end + + ## + # call-seq: + # hsh.delete_if {| key, value | block } -> hsh + # hsh.delete_if -> an_enumerator + # + # Deletes every key-value pair from <i>hsh</i> for which <i>block</i> + # evaluates to <code>true</code>. + # + # If no block is given, an enumerator is returned instead. + # + # h = { "a" => 100, "b" => 200, "c" => 300 } + # h.delete_if {|key, value| key >= "b" } #=> {"a"=>100} + # + + def delete_if(&block) + return to_enum :delete_if unless block + + self.each do |k, v| + self.delete(k) if block.call(k, v) + end + self + end + + ## + # call-seq: + # hash.flatten -> an_array + # hash.flatten(level) -> an_array + # + # Returns a new array that is a one-dimensional flattening of this + # hash. That is, for every key or value that is an array, extract + # its elements into the new array. Unlike Array#flatten, this + # method does not flatten recursively by default. The optional + # <i>level</i> argument determines the level of recursion to flatten. + # + # a = {1=> "one", 2 => [2,"two"], 3 => "three"} + # a.flatten # => [1, "one", 2, [2, "two"], 3, "three"] + # a.flatten(2) # => [1, "one", 2, 2, "two", 3, "three"] + # + + def flatten(level=1) + self.to_a.flatten(level) + end + + ## + # call-seq: + # hsh.invert -> new_hash + # + # Returns a new hash created by using <i>hsh</i>'s values as keys, and + # the keys as values. + # + # h = { "n" => 100, "m" => 100, "y" => 300, "d" => 200, "a" => 0 } + # h.invert #=> {0=>"a", 100=>"m", 200=>"d", 300=>"y"} + # + + def invert + h = self.class.new + self.each {|k, v| h[v] = k } + h + end + + ## + # call-seq: + # hsh.keep_if {| key, value | block } -> hsh + # hsh.keep_if -> an_enumerator + # + # Deletes every key-value pair from <i>hsh</i> for which <i>block</i> + # evaluates to false. + # + # If no block is given, an enumerator is returned instead. + # + + def keep_if(&block) + return to_enum :keep_if unless block + + keys = [] + self.each do |k, v| + unless block.call([k, v]) + self.delete(k) + end + end + self + end + + ## + # call-seq: + # hsh.key(value) -> key + # + # Returns the key of an occurrence of a given value. If the value is + # not found, returns <code>nil</code>. + # + # h = { "a" => 100, "b" => 200, "c" => 300, "d" => 300 } + # h.key(200) #=> "b" + # h.key(300) #=> "c" + # h.key(999) #=> nil + # + + def key(val) + self.each do |k, v| + return k if v == val + end + nil + end + + ## + # call-seq: + # hsh.to_h -> hsh or new_hash + # + # Returns +self+. If called on a subclass of Hash, converts + # the receiver to a Hash object. + # + def to_h + self + end + + ## + # call-seq: + # hash < other -> true or false + # + # Returns <code>true</code> if <i>hash</i> is subset of + # <i>other</i>. + # + # h1 = {a:1, b:2} + # h2 = {a:1, b:2, c:3} + # h1 < h2 #=> true + # h2 < h1 #=> false + # h1 < h1 #=> false + # + def <(hash) + begin + hash = hash.to_hash + rescue NoMethodError + raise TypeError, "can't convert #{hash.class} to Hash" + end + size < hash.size and all? {|key, val| + hash.key?(key) and hash[key] == val + } + end + + ## + # call-seq: + # hash <= other -> true or false + # + # Returns <code>true</code> if <i>hash</i> is subset of + # <i>other</i> or equals to <i>other</i>. + # + # h1 = {a:1, b:2} + # h2 = {a:1, b:2, c:3} + # h1 <= h2 #=> true + # h2 <= h1 #=> false + # h1 <= h1 #=> true + # + def <=(hash) + begin + hash = hash.to_hash + rescue NoMethodError + raise TypeError, "can't convert #{hash.class} to Hash" + end + size <= hash.size and all? {|key, val| + hash.key?(key) and hash[key] == val + } + end + + ## + # call-seq: + # hash > other -> true or false + # + # Returns <code>true</code> if <i>other</i> is subset of + # <i>hash</i>. + # + # h1 = {a:1, b:2} + # h2 = {a:1, b:2, c:3} + # h1 > h2 #=> false + # h2 > h1 #=> true + # h1 > h1 #=> false + # + def >(hash) + begin + hash = hash.to_hash + rescue NoMethodError + raise TypeError, "can't convert #{hash.class} to Hash" + end + size > hash.size and hash.all? {|key, val| + key?(key) and self[key] == val + } + end + + ## + # call-seq: + # hash >= other -> true or false + # + # Returns <code>true</code> if <i>other</i> is subset of + # <i>hash</i> or equals to <i>hash</i>. + # + # h1 = {a:1, b:2} + # h2 = {a:1, b:2, c:3} + # h1 >= h2 #=> false + # h2 >= h1 #=> true + # h1 >= h1 #=> true + # + def >=(hash) + begin + hash = hash.to_hash + rescue NoMethodError + raise TypeError, "can't convert #{hash.class} to Hash" + end + size >= hash.size and hash.all? {|key, val| + key?(key) and self[key] == val + } + end + + ## + # call-seq: + # hsh.dig(key,...) -> object + # + # Extracts the nested value specified by the sequence of <i>key</i> + # objects by calling +dig+ at each step, returning +nil+ if any + # intermediate step is +nil+. + # + def dig(idx,*args) + n = self[idx] + if args.size > 0 + n&.dig(*args) + else + n + end + end + + ## + # call-seq: + # hsh.transform_keys {|key| block } -> new_hash + # hsh.transform_keys -> an_enumerator + # + # Returns a new hash, with the keys computed from running the block + # once for each key in the hash, and the values unchanged. + # + # If no block is given, an enumerator is returned instead. + # + def transform_keys(&block) + return to_enum :transform_keys unless block + hash = {} + self.keys.each do |k| + new_key = block.call(k) + hash[new_key] = self[k] + end + hash + end + ## + # call-seq: + # hsh.transform_keys! {|key| block } -> hsh + # hsh.transform_keys! -> an_enumerator + # + # Invokes the given block once for each key in <i>hsh</i>, replacing it + # with the new key returned by the block, and then returns <i>hsh</i>. + # + # If no block is given, an enumerator is returned instead. + # + def transform_keys!(&block) + return to_enum :transform_keys! unless block + self.keys.each do |k| + value = self[k] + new_key = block.call(k) + self.__delete(k) + self[new_key] = value + end + self + end + ## + # call-seq: + # hsh.transform_values {|value| block } -> new_hash + # hsh.transform_values -> an_enumerator + # + # Returns a new hash with the results of running the block once for + # every value. + # This method does not change the keys. + # + # If no block is given, an enumerator is returned instead. + # + def transform_values(&b) + return to_enum :transform_values unless block_given? + hash = {} + self.keys.each do |k| + hash[k] = yield(self[k]) + end + hash + end + ## + # call-seq: + # hsh.transform_values! {|key| block } -> hsh + # hsh.transform_values! -> an_enumerator + # + # Invokes the given block once for each value in the hash, replacing + # with the new value returned by the block, and then returns <i>hsh</i>. + # + # If no block is given, an enumerator is returned instead. + # + def transform_values!(&b) + return to_enum :transform_values! unless block_given? + self.keys.each do |k| + self[k] = yield(self[k]) + end + self + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/src/hash-ext.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/src/hash-ext.c new file mode 100644 index 000000000..952f2eb64 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/src/hash-ext.c @@ -0,0 +1,88 @@ +/* +** hash.c - Hash class +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/hash.h> + +/* + * call-seq: + * hsh.values_at(key, ...) -> array + * + * Return an array containing the values associated with the given keys. + * Also see <code>Hash.select</code>. + * + * h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" } + * h.values_at("cow", "cat") #=> ["bovine", "feline"] + */ + +static mrb_value +hash_values_at(mrb_state *mrb, mrb_value hash) +{ + mrb_value *argv, result; + mrb_int argc, i; + int ai; + + mrb_get_args(mrb, "*", &argv, &argc); + result = mrb_ary_new_capa(mrb, argc); + ai = mrb_gc_arena_save(mrb); + for (i = 0; i < argc; i++) { + mrb_ary_push(mrb, result, mrb_hash_get(mrb, hash, argv[i])); + mrb_gc_arena_restore(mrb, ai); + } + return result; +} + +/* + * call-seq: + * hsh.compact! -> hsh + * + * Removes all nil values from the hash. Returns the hash. + * + * h = { a: 1, b: false, c: nil } + * h.compact! #=> { a: 1, b: false } + */ +static mrb_value +hash_compact_bang(mrb_state *mrb, mrb_value hash) +{ + khiter_t k; + khash_t(ht) *h = RHASH_TBL(hash); + mrb_int n = -1; + + if (!h) return mrb_nil_value(); + for (k = kh_begin(h); k != kh_end(h); k++) { + if (kh_exist(h, k)) { + mrb_value val = kh_value(h, k).v; + khiter_t k2; + + if (mrb_nil_p(val)) { + kh_del(ht, mrb, h, k); + n = kh_value(h, k).n; + for (k2 = kh_begin(h); k2 != kh_end(h); k2++) { + if (!kh_exist(h, k2)) continue; + if (kh_value(h, k2).n > n) kh_value(h, k2).n--; + } + } + } + } + if (n < 0) return mrb_nil_value(); + return hash; +} + +void +mrb_mruby_hash_ext_gem_init(mrb_state *mrb) +{ + struct RClass *h; + + h = mrb->hash_class; + mrb_define_method(mrb, h, "values_at", hash_values_at, MRB_ARGS_ANY()); + mrb_define_method(mrb, h, "compact!", hash_compact_bang, MRB_ARGS_NONE()); +} + +void +mrb_mruby_hash_ext_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/test/hash.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/test/hash.rb new file mode 100644 index 000000000..ca4e346fb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-hash-ext/test/hash.rb @@ -0,0 +1,294 @@ +## +# Hash(Ext) Test + +assert('Hash.[] Hash') do + a = Hash['a_key' => 'a_value'] + + assert_equal({'a_key' => 'a_value'}, a) +end + +assert('Hash.[] [ [ ["b_key", "b_value" ] ] ]') do + a = Hash[ [ ['b_key', 'b_value'] ] ] + + assert_equal({'b_key' => 'b_value'}, a) + + a = Hash[ [ ] ] + + assert_equal({}, a) + + assert_raise(ArgumentError) do + Hash[ [ ['b_key', 'b_value', 'b_over'] ] ] + end + + assert_raise(ArgumentError) do + Hash[ [ [] ] ] + end +end + +assert('Hash.[] "c_key", "c_value"') do + a = Hash['c_key', 'c_value', 'd_key', 1] + + assert_equal({'c_key' => 'c_value', 'd_key' => 1}, a) + + a = Hash[] + + assert_equal({}, a) + + assert_raise(ArgumentError) do + Hash['d_key'] + end +end + +assert('Hash.[] for sub class') do + sub_hash_class = Class.new(Hash) + sub_hash = sub_hash_class[] + assert_equal(sub_hash_class, sub_hash.class) +end + +assert('Hash.try_convert') do + assert_nil Hash.try_convert(nil) + assert_nil Hash.try_convert("{1=>2}") + assert_equal({1=>2}, Hash.try_convert({1=>2})) +end + +assert('Hash#merge!') do + a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' } + b = { 'cba_key' => 'XXX', 'xyz_key' => 'xyz_value' } + + result_1 = a.merge! b + + a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' } + result_2 = a.merge!(b) do |key, original, new| + original + end + + assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'XXX', + 'xyz_key' => 'xyz_value' }, result_1) + assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'cba_value', + 'xyz_key' => 'xyz_value' }, result_2) + + assert_raise(TypeError) do + { 'abc_key' => 'abc_value' }.merge! "a" + end +end + +assert('Hash#values_at') do + h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" } + assert_equal ["bovine", "feline"], h.values_at("cow", "cat") + + keys = [] + (0...1000).each { |v| keys.push "#{v}" } + h = Hash.new { |hash,k| hash[k] = k } + assert_equal keys, h.values_at(*keys) +end + +assert('Hash#compact') do + h = { "cat" => "feline", "dog" => nil, "cow" => false } + + assert_equal({ "cat" => "feline", "cow" => false }, h.compact) + assert_equal({ "cat" => "feline", "dog" => nil, "cow" => false }, h) +end + +assert('Hash#compact!') do + h = { "cat" => "feline", "dog" => nil, "cow" => false } + + h.compact! + assert_equal({ "cat" => "feline", "cow" => false }, h) +end + +assert('Hash#fetch') do + h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" } + assert_equal "feline", h.fetch("cat") + assert_equal "mickey", h.fetch("mouse", "mickey") + assert_equal "minny", h.fetch("mouse"){"minny"} + assert_equal "mouse", h.fetch("mouse"){|k| k} + assert_raise(KeyError) do + h.fetch("gnu") + end +end + +assert("Hash#delete_if") do + base = { 1 => 'one', 2 => false, true => 'true', 'cat' => 99 } + h1 = { 1 => 'one', 2 => false, true => 'true' } + h2 = { 2 => false, 'cat' => 99 } + h3 = { 2 => false } + + h = base.dup + assert_equal(h, h.delete_if { false }) + assert_equal({}, h.delete_if { true }) + + h = base.dup + assert_equal(h1, h.delete_if {|k,v| k.instance_of?(String) }) + assert_equal(h1, h) + + h = base.dup + assert_equal(h2, h.delete_if {|k,v| v.instance_of?(String) }) + assert_equal(h2, h) + + h = base.dup + assert_equal(h3, h.delete_if {|k,v| v }) + assert_equal(h3, h) + + h = base.dup + n = 0 + h.delete_if {|*a| + n += 1 + assert_equal(2, a.size) + assert_equal(base[a[0]], a[1]) + h.shift + true + } + assert_equal(base.size, n) +end + +assert("Hash#flatten") do + a = {1=> "one", 2 => [2,"two"], 3 => [3, ["three"]]} + assert_equal [1, "one", 2, [2, "two"], 3, [3, ["three"]]], a.flatten + assert_equal [[1, "one"], [2, [2, "two"]], [3, [3, ["three"]]]], a.flatten(0) + assert_equal [1, "one", 2, [2, "two"], 3, [3, ["three"]]], a.flatten(1) + assert_equal [1, "one", 2, 2, "two", 3, 3, ["three"]], a.flatten(2) + assert_equal [1, "one", 2, 2, "two", 3, 3, "three"], a.flatten(3) +end + +assert("Hash#invert") do + h = { 1 => 'one', 2 => 'two', 3 => 'three', + true => 'true', nil => 'nil' }.invert + assert_equal 1, h['one'] + assert_equal true, h['true'] + assert_equal nil, h['nil'] + + h = { 'a' => 1, 'b' => 2, 'c' => 1 }.invert + assert_equal(2, h.length) + assert_include(%w[a c], h[1]) + assert_equal('b', h[2]) +end + +assert("Hash#invert with sub class") do + sub_hash_class = Class.new(Hash) + sub_hash = sub_hash_class.new + assert_equal(sub_hash_class, sub_hash.invert.class) +end + +assert("Hash#keep_if") do + h = { 1 => 2, 3 => 4, 5 => 6 } + assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 }) + h = { 1 => 2, 3 => 4, 5 => 6 } + assert_equal({ 1 => 2, 3=> 4, 5 =>6} , h.keep_if { true }) +end + +assert("Hash#key") do + h = { "a" => 100, "b" => 200, "c" => 300, "d" => 300, nil => 'nil', 'nil' => nil } + assert_equal "b", h.key(200) + assert_equal "c", h.key(300) + assert_nil h.key(999) + assert_nil h.key('nil') + assert_equal 'nil', h.key(nil) +end + +assert("Hash#to_h") do + h = { "a" => 100, "b" => 200 } + assert_equal Hash, h.to_h.class + assert_equal h, h.to_h +end + +assert('Hash#<') do + h1 = {a:1, b:2} + h2 = {a:1, b:2, c:3} + + assert_false(h1 < h1) + assert_true(h1 < h2) + assert_false(h2 < h1) + assert_false(h2 < h2) + + h1 = {a:1} + h2 = {a:2} + + assert_false(h1 < h1) + assert_false(h1 < h2) + assert_false(h2 < h1) + assert_false(h2 < h2) +end + +assert('Hash#<=') do + h1 = {a:1, b:2} + h2 = {a:1, b:2, c:3} + + assert_true(h1 <= h1) + assert_true(h1 <= h2) + assert_false(h2 <= h1) + assert_true(h2 <= h2) + + h1 = {a:1} + h2 = {a:2} + + assert_true(h1 <= h1) + assert_false(h1 <= h2) + assert_false(h2 <= h1) + assert_true(h2 <= h2) +end + +assert('Hash#>=') do + h1 = {a:1, b:2} + h2 = {a:1, b:2, c:3} + + assert_true(h1 >= h1) + assert_false(h1 >= h2) + assert_true(h2 >= h1) + assert_true(h2 >= h2) + + h1 = {a:1} + h2 = {a:2} + + assert_true(h1 >= h1) + assert_false(h1 >= h2) + assert_false(h2 >= h1) + assert_true(h2 >= h2) +end + +assert('Hash#>') do + h1 = {a:1, b:2} + h2 = {a:1, b:2, c:3} + + assert_false(h1 > h1) + assert_false(h1 > h2) + assert_true(h2 > h1) + assert_false(h2 > h2) + + h1 = {a:1} + h2 = {a:2} + + assert_false(h1 > h1) + assert_false(h1 > h2) + assert_false(h2 > h1) + assert_false(h2 > h2) +end + +assert("Hash#dig") do + h = {a:{b:{c:1}}} + assert_equal(1, h.dig(:a, :b, :c)) + assert_nil(h.dig(:d)) +end + +assert("Hash#transform_keys") do + h = {"1" => 100, "2" => 200} + assert_equal(h.transform_keys{|k| k+"!"}, + {"1!" => 100, "2!" => 200}) + assert_equal(h.transform_keys{|k|k.to_i}, + {1 => 100, 2 => 200}) + assert_equal(h.transform_keys.with_index{|k, i| "#{k}.#{i}"}, + {"1.0" => 100, "2.1" => 200}) + assert_equal(h.transform_keys!{|k|k.to_i}, h) + assert_equal(h, {1 => 100, 2 => 200}) +end + +assert("Hash#transform_values") do + h = {a: 1, b: 2, c: 3} + assert_equal(h.transform_values{|v| v * v + 1}, + {a: 2, b: 5, c: 10}) + assert_equal(h.transform_values{|v|v.to_s}, + {a: "1", b: "2", c: "3"}) + assert_equal(h.transform_values.with_index{|v, i| "#{v}.#{i}"}, + {a: "1.0", b: "2.1", c: "3.2"}) + assert_equal(h.transform_values!{|v|v.to_s}, h) + assert_equal(h, {a: "1", b: "2", c: "3"}) +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-inline-struct/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-inline-struct/mrbgem.rake new file mode 100644 index 000000000..91ad9f44b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-inline-struct/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-inline-struct') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'inline structure' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-inline-struct/test/inline.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-inline-struct/test/inline.c new file mode 100644 index 000000000..0baaab617 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-inline-struct/test/inline.c @@ -0,0 +1,83 @@ +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/string.h> +#include <mruby/istruct.h> + +static mrb_value +istruct_test_initialize(mrb_state *mrb, mrb_value self) +{ + char *string = (char*)mrb_istruct_ptr(self); + mrb_int size = mrb_istruct_size(); + mrb_value object; + mrb_get_args(mrb, "o", &object); + + if (mrb_float_p(object)) + { + snprintf(string, size, "float(%.3f)", mrb_float(object)); + } + else if (mrb_fixnum_p(object)) + { + snprintf(string, size, "fixnum(%" MRB_PRId ")", mrb_fixnum(object)); + } + else if (mrb_string_p(object)) + { + snprintf(string, size, "string(%s)", mrb_string_value_cstr(mrb, &object)); + } + + string[size - 1] = 0; // force NULL at the end + return self; +} + +static mrb_value +istruct_test_to_s(mrb_state *mrb, mrb_value self) +{ + return mrb_str_new_cstr(mrb, (const char*)mrb_istruct_ptr(self)); +} + +static mrb_value +istruct_test_length(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(mrb_istruct_size()); +} + +static mrb_value +istruct_test_test_receive(mrb_state *mrb, mrb_value self) +{ + mrb_value object; + mrb_get_args(mrb, "o", &object); + if (mrb_obj_class(mrb, object) != mrb_class_get(mrb, "InlineStructTest")) + { + mrb_raisef(mrb, E_TYPE_ERROR, "Expected InlineStructTest"); + } + return mrb_bool_value(((char*)mrb_istruct_ptr(object))[0] == 's'); +} + +static mrb_value +istruct_test_test_receive_direct(mrb_state *mrb, mrb_value self) +{ + char *ptr; + mrb_get_args(mrb, "I", &ptr); + return mrb_bool_value(ptr[0] == 's'); +} + +static mrb_value +istruct_test_mutate(mrb_state *mrb, mrb_value self) +{ + char *ptr = (char*)mrb_istruct_ptr(self); + memcpy(ptr, "mutate", 6); + return mrb_nil_value(); +} + +void mrb_mruby_inline_struct_gem_test(mrb_state *mrb) +{ + struct RClass *cls; + + cls = mrb_define_class(mrb, "InlineStructTest", mrb->object_class); + MRB_SET_INSTANCE_TT(cls, MRB_TT_ISTRUCT); + mrb_define_method(mrb, cls, "initialize", istruct_test_initialize, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, cls, "to_s", istruct_test_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, cls, "mutate", istruct_test_mutate, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "length", istruct_test_length, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "test_receive", istruct_test_test_receive, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, cls, "test_receive_direct", istruct_test_test_receive_direct, MRB_ARGS_REQ(1)); +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-inline-struct/test/inline.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-inline-struct/test/inline.rb new file mode 100644 index 000000000..495859232 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-inline-struct/test/inline.rb @@ -0,0 +1,151 @@ +## +# InlineStruct Test + +class InlineStructTest + def extra_method + :ok + end + + def test_ivar_set + @var = :ivar + end + + def test_ivar_get + @vat + end +end + +assert('InlineStructTest#dup') do + obj = InlineStructTest.new(1) + assert_equal obj.to_s, 'fixnum(1)' + assert_equal obj.dup.to_s, 'fixnum(1)' +end + +assert('InlineStructTest#clone') do + obj = InlineStructTest.new(1) + assert_equal obj.to_s, 'fixnum(1)' + assert_equal obj.clone.to_s, 'fixnum(1)' +end + +assert('InlineStruct#object_id') do + obj1 = InlineStructTest.new(1) + obj2 = InlineStructTest.new(1) + assert_not_equal obj1, obj2 + assert_not_equal obj1.object_id, obj2.object_id + assert_not_equal obj1.object_id, obj1.dup.object_id + assert_not_equal obj1.object_id, obj1.clone.object_id +end + +assert('InlineStructTest#mutate (dup)') do + obj1 = InlineStructTest.new("foo") + assert_equal obj1.to_s, "string(foo)" + obj2 = obj1.dup + assert_equal obj2.to_s, "string(foo)" + obj1.mutate + assert_equal obj1.to_s, "mutate(foo)" + assert_equal obj2.to_s, "string(foo)" +end + +assert('InlineStructTest#mutate (clone)') do + obj1 = InlineStructTest.new("foo") + assert_equal obj1.to_s, "string(foo)" + obj2 = obj1.clone + assert_equal obj2.to_s, "string(foo)" + obj1.mutate + assert_equal obj1.to_s, "mutate(foo)" + assert_equal obj2.to_s, "string(foo)" +end + +assert('InlineStructTest#test_receive(string)') do + assert_equal InlineStructTest.test_receive(InlineStructTest.new('a')), true +end + +assert('InlineStructTest#test_receive(float)') do + assert_equal InlineStructTest.test_receive(InlineStructTest.new(1.25)), false +end + +assert('InlineStructTest#test_receive(invalid object)') do + assert_raise(TypeError) do + InlineStructTest.test_receive([]) + end +end + +assert('InlineStructTest#test_receive(string)') do + assert_equal InlineStructTest.test_receive_direct(InlineStructTest.new('a')), true +end + +assert('InlineStructTest#test_receive(float)') do + assert_equal InlineStructTest.test_receive_direct(InlineStructTest.new(1.25)), false +end + +assert('InlineStructTest#test_receive(invalid object)') do + assert_raise(TypeError) do + InlineStructTest.test_receive_direct([]) + end +end + +assert('InlineStructTest#extra_method') do + assert_equal InlineStructTest.new(1).extra_method, :ok +end + +assert('InlineStructTest instance variable') do + obj = InlineStructTest.new(1) + assert_raise(ArgumentError) do + obj.test_ivar_set + end + assert_equal obj.test_ivar_get, nil +end + +# 64-bit mode +if InlineStructTest.length == 24 + assert('InlineStructTest length [64 bit]') do + assert_equal InlineStructTest.length, 3 * 8 + end + + assert('InlineStructTest w/float [64 bit]') do + obj = InlineStructTest.new(1.25) + assert_equal obj.to_s, "float(1.250)" + end + + assert('InlineStructTest w/fixnum [64 bit]') do + obj = InlineStructTest.new(42) + assert_equal obj.to_s, "fixnum(42)" + end + + assert('InlineStructTest w/string [64 bit]') do + obj = InlineStructTest.new("hello") + assert_equal obj.to_s, "string(hello)" + end + + assert('InlineStructTest w/long string [64 bit]') do + obj = InlineStructTest.new("this won't fit in 3 * 8 bytes available for the structure") + assert_equal obj.to_s, "string(this won't fit i" + end +end + +# 32-bit mode +if InlineStructTest.length == 12 + assert('InlineStructTest length [32 bit]') do + assert_equal InlineStructTest.length, 3 * 4 + end + + assert('InlineStructTest w/float [32 bit]') do + obj = InlineStructTest.new(1.25) + assert_equal obj.to_s, "float(1.250" + end + + assert('InlineStructTest w/fixnum [32 bit]') do + obj = InlineStructTest.new(42) + assert_equal obj.to_s, "fixnum(42)" + end + + assert('InlineStructTest w/string [32 bit]') do + obj = InlineStructTest.new("hello") + assert_equal obj.to_s, "string(hell" + end + + assert('InlineStructTest w/long string [32 bit]') do + obj = InlineStructTest.new("this won't fit in 3 * 4 bytes available for the structure") + assert_equal obj.to_s, "string(this" + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-kernel-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-kernel-ext/mrbgem.rake new file mode 100644 index 000000000..fcb3a83b0 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-kernel-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-kernel-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Kernel module extension' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-kernel-ext/src/kernel.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-kernel-ext/src/kernel.c new file mode 100644 index 000000000..7e6fa28bd --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-kernel-ext/src/kernel.c @@ -0,0 +1,243 @@ +#include <mruby.h> +#include <mruby/error.h> +#include <mruby/array.h> +#include <mruby/hash.h> +#include <mruby/range.h> + +static mrb_value +mrb_f_caller(mrb_state *mrb, mrb_value self) +{ + mrb_value bt, v, length; + mrb_int bt_len, argc, lev, n; + + bt = mrb_get_backtrace(mrb); + bt_len = RARRAY_LEN(bt); + argc = mrb_get_args(mrb, "|oo", &v, &length); + + switch (argc) { + case 0: + lev = 1; + n = bt_len - lev; + break; + case 1: + if (mrb_type(v) == MRB_TT_RANGE) { + mrb_int beg, len; + if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == 1) { + lev = beg; + n = len; + } + else { + return mrb_nil_value(); + } + } + else { + v = mrb_to_int(mrb, v); + lev = mrb_fixnum(v); + if (lev < 0) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%S)", v); + } + n = bt_len - lev; + } + break; + case 2: + lev = mrb_fixnum(mrb_to_int(mrb, v)); + n = mrb_fixnum(mrb_to_int(mrb, length)); + if (lev < 0) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%S)", v); + } + if (n < 0) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative size (%S)", length); + } + break; + default: + lev = n = 0; + break; + } + + if (n == 0) { + return mrb_ary_new(mrb); + } + + return mrb_funcall(mrb, bt, "[]", 2, mrb_fixnum_value(lev), mrb_fixnum_value(n)); +} + +/* + * call-seq: + * __method__ -> symbol + * + * Returns the name at the definition of the current method as a + * Symbol. + * If called outside of a method, it returns <code>nil</code>. + * + */ +static mrb_value +mrb_f_method(mrb_state *mrb, mrb_value self) +{ + mrb_callinfo *ci = mrb->c->ci; + ci--; + if (ci->mid) + return mrb_symbol_value(ci->mid); + else + return mrb_nil_value(); +} + +/* + * call-seq: + * Integer(arg,base=0) -> integer + * + * Converts <i>arg</i> to a <code>Fixnum</code>. + * Numeric types are converted directly (with floating point numbers + * being truncated). <i>base</i> (0, or between 2 and 36) is a base for + * integer string representation. If <i>arg</i> is a <code>String</code>, + * when <i>base</i> is omitted or equals to zero, radix indicators + * (<code>0</code>, <code>0b</code>, and <code>0x</code>) are honored. + * In any case, strings should be strictly conformed to numeric + * representation. This behavior is different from that of + * <code>String#to_i</code>. Non string values will be converted using + * <code>to_int</code>, and <code>to_i</code>. Passing <code>nil</code> + * raises a TypeError. + * + * Integer(123.999) #=> 123 + * Integer("0x1a") #=> 26 + * Integer(Time.new) #=> 1204973019 + * Integer("0930", 10) #=> 930 + * Integer("111", 2) #=> 7 + * Integer(nil) #=> TypeError + */ +static mrb_value +mrb_f_integer(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + mrb_int base = 0; + + mrb_get_args(mrb, "o|i", &arg, &base); + return mrb_convert_to_integer(mrb, arg, base); +} + +/* + * call-seq: + * Float(arg) -> float + * + * Returns <i>arg</i> converted to a float. Numeric types are converted + * directly, the rest are converted using <i>arg</i>.to_f. + * + * Float(1) #=> 1.0 + * Float(123.456) #=> 123.456 + * Float("123.456") #=> 123.456 + * Float(nil) #=> TypeError + */ +static mrb_value +mrb_f_float(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + + mrb_get_args(mrb, "o", &arg); + return mrb_Float(mrb, arg); +} + +/* + * call-seq: + * String(arg) -> string + * + * Returns <i>arg</i> as an <code>String</code>. + * + * First tries to call its <code>to_str</code> method, then its to_s method. + * + * String(self) #=> "main" + * String(self.class) #=> "Object" + * String(123456) #=> "123456" + */ +static mrb_value +mrb_f_string(mrb_state *mrb, mrb_value self) +{ + mrb_value arg, tmp; + + mrb_get_args(mrb, "o", &arg); + tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_str"); + if (mrb_nil_p(tmp)) { + tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s"); + } + return tmp; +} + +/* + * call-seq: + * Array(arg) -> array + * + * Returns +arg+ as an Array. + * + * First tries to call Array#to_ary on +arg+, then Array#to_a. + * + * Array(1..5) #=> [1, 2, 3, 4, 5] + * + */ +static mrb_value +mrb_f_array(mrb_state *mrb, mrb_value self) +{ + mrb_value arg, tmp; + + mrb_get_args(mrb, "o", &arg); + tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_ary"); + if (mrb_nil_p(tmp)) { + tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a"); + } + if (mrb_nil_p(tmp)) { + return mrb_ary_new_from_values(mrb, 1, &arg); + } + + return tmp; +} + +/* + * call-seq: + * Hash(arg) -> hash + * + * Converts <i>arg</i> to a <code>Hash</code> by calling + * <i>arg</i><code>.to_hash</code>. Returns an empty <code>Hash</code> when + * <i>arg</i> is <tt>nil</tt> or <tt>[]</tt>. + * + * Hash([]) #=> {} + * Hash(nil) #=> {} + * Hash(key: :value) #=> {:key => :value} + * Hash([1, 2, 3]) #=> TypeError + * + */ +static mrb_value +mrb_f_hash(mrb_state *mrb, mrb_value self) +{ + mrb_value arg, tmp; + + mrb_get_args(mrb, "o", &arg); + if (mrb_nil_p(arg)) { + return mrb_hash_new(mrb); + } + tmp = mrb_check_convert_type(mrb, arg, MRB_TT_HASH, "Hash", "to_hash"); + if (mrb_nil_p(tmp)) { + if (mrb_array_p(arg) && RARRAY_LEN(arg) == 0) { + return mrb_hash_new(mrb); + } + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into Hash", + mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, arg))); + } + return tmp; +} + +void +mrb_mruby_kernel_ext_gem_init(mrb_state *mrb) +{ + struct RClass *krn = mrb->kernel_module; + + mrb_define_module_function(mrb, krn, "fail", mrb_f_raise, MRB_ARGS_OPT(2)); + mrb_define_module_function(mrb, krn, "caller", mrb_f_caller, MRB_ARGS_OPT(2)); + mrb_define_method(mrb, krn, "__method__", mrb_f_method, MRB_ARGS_NONE()); + mrb_define_module_function(mrb, krn, "Integer", mrb_f_integer, MRB_ARGS_ANY()); + mrb_define_module_function(mrb, krn, "Float", mrb_f_float, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, krn, "String", mrb_f_string, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, krn, "Array", mrb_f_array, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, krn, "Hash", mrb_f_hash, MRB_ARGS_REQ(1)); +} + +void +mrb_mruby_kernel_ext_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-kernel-ext/test/kernel.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-kernel-ext/test/kernel.rb new file mode 100644 index 000000000..89cedaf27 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-kernel-ext/test/kernel.rb @@ -0,0 +1,86 @@ +assert('Kernel.fail, Kernel#fail') do + assert_raise(RuntimeError) { fail } + assert_raise(RuntimeError) { Kernel.fail } +end + +assert('Kernel.caller, Kernel#caller') do + skip "backtrace isn't available" if caller(0).empty? + + caller_lineno = __LINE__ + 3 + c = Class.new do + def foo(*args) + caller(*args) + end + + def bar(*args) + foo(*args) + end + + def baz(*args) + bar(*args) + end + end + assert_equal "kernel.rb:#{caller_lineno}:in foo", c.new.baz(0)[0][-19..-1] + assert_equal "bar", c.new.baz[0][-3..-1] + assert_equal "foo", c.new.baz(0)[0][-3..-1] + assert_equal "bar", c.new.baz(1)[0][-3..-1] + assert_equal "baz", c.new.baz(2)[0][-3..-1] + assert_equal ["foo", "bar"], c.new.baz(0, 2).map { |i| i[-3..-1] } + assert_equal ["bar", "baz"], c.new.baz(1..2).map { |i| i[-3..-1] } + assert_nil c.new.baz(10..20) + assert_raise(ArgumentError) { c.new.baz(-1) } + assert_raise(ArgumentError) { c.new.baz(-1, 1) } + assert_raise(ArgumentError) { c.new.baz(1, -1) } + assert_raise(TypeError) { c.new.baz(nil) } +end + +assert('Kernel#__method__') do + assert_equal(:m, Class.new {def m; __method__; end}.new.m) + assert_equal(:m, Class.new {define_method(:m) {__method__}}.new.m) + c = Class.new do + [:m1, :m2].each do |m| + define_method(m) do + __method__ + end + end + end + assert_equal(:m1, c.new.m1) + assert_equal(:m2, c.new.m2) +end + +assert('Kernel#Integer') do + assert_equal(123, Integer(123.999)) + assert_equal(26, Integer("0x1a")) + assert_equal(930, Integer("0930", 10)) + assert_equal(7, Integer("111", 2)) + assert_equal(0, Integer("0")) + assert_equal(0, Integer("00000")) + assert_raise(TypeError) { Integer(nil) } +end + +assert('Kernel#Float') do + assert_equal(1.0, Float(1)) + assert_equal(123.456, Float(123.456)) + assert_equal(123.456, Float("123.456")) + assert_raise(TypeError) { Float(nil) } +end + +assert('Kernel#String') do + assert_equal("main", String(self)) + assert_equal("Object", String(self.class)) + assert_equal("123456", String(123456)) +end + +assert('Kernel#Array') do + assert_equal([1], Kernel.Array(1)) + assert_equal([1, 2, 3, 4, 5], Kernel.Array([1, 2, 3, 4, 5])) + assert_equal([1, 2, 3, 4, 5], Kernel.Array(1..5)) + assert_equal([[:a, 1], [:b, 2], [:c, 3]], Kernel.Array({a:1, b:2, c:3})) +end + +assert('Kernel#Hash') do + assert_equal({}, Hash([])) + assert_equal({}, Hash(nil)) + assert_equal({:key => :value}, Hash(key: :value)) + assert_raise(TypeError) { Hash([1, 2, 3]) } +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-math/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-math/mrbgem.rake new file mode 100644 index 000000000..66eb5c8d0 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-math/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-math') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'standard Math module' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-math/src/math.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-math/src/math.c new file mode 100644 index 000000000..7302b92d7 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-math/src/math.c @@ -0,0 +1,783 @@ +/* +** math.c - Math module +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/array.h> + +#include <math.h> + +static void +domain_error(mrb_state *mrb, const char *func) +{ + struct RClass *math = mrb_module_get(mrb, "Math"); + struct RClass *domainerror = mrb_class_get_under(mrb, math, "DomainError"); + mrb_value str = mrb_str_new_cstr(mrb, func); + mrb_raisef(mrb, domainerror, "Numerical argument is out of domain - %S", str); +} + +/* math functions not provided by Microsoft Visual C++ 2012 or older */ +#if defined _MSC_VER && _MSC_VER <= 1700 + +#include <float.h> + +#define MATH_TOLERANCE 1E-12 + +double +asinh(double x) +{ + double xa, ya, y; + + /* Basic formula loses precision for x < 0, but asinh is an odd function */ + xa = fabs(x); + if (xa > 3.16227E+18) { + /* Prevent x*x from overflowing; basic formula reduces to log(2*x) */ + ya = log(xa) + 0.69314718055994530942; + } + else { + /* Basic formula for asinh */ + ya = log(xa + sqrt(xa*xa + 1.0)); + } + + y = _copysign(ya, x); + return y; +} + +double +acosh(double x) +{ + double y; + + if (x > 3.16227E+18) { + /* Prevent x*x from overflowing; basic formula reduces to log(2*x) */ + y = log(x) + 0.69314718055994530942; + } + else { + /* Basic formula for acosh */ + y = log(x + sqrt(x*x - 1.0)); + } + + return y; +} + +double +atanh(double x) +{ + double y; + + if (fabs(x) < 1E-2) { + /* The sums 1+x and 1-x lose precision for small x. Use the polynomial + instead. */ + double x2 = x * x; + y = x*(1.0 + x2*(1.0/3.0 + x2*(1.0/5.0 + x2*(1.0/7.0)))); + } + else { + /* Basic formula for atanh */ + y = 0.5 * (log(1.0+x) - log(1.0-x)); + } + + return y; +} + +double +cbrt(double x) +{ + double xa, ya, y; + + /* pow(x, y) is undefined for x < 0 and y not an integer, but cbrt is an + odd function */ + xa = fabs(x); + ya = pow(xa, 1.0/3.0); + y = _copysign(ya, x); + return y; +} + +/* Declaration of complementary Error function */ +double +erfc(double x); + +/* +** Implementations of error functions +** credits to http://www.digitalmars.com/archives/cplusplus/3634.html +*/ + +/* Implementation of Error function */ +double +erf(double x) +{ + static const double two_sqrtpi = 1.128379167095512574; + double sum = x; + double term = x; + double xsqr = x*x; + int j= 1; + if (fabs(x) > 2.2) { + return 1.0 - erfc(x); + } + do { + term *= xsqr/j; + sum -= term/(2*j+1); + ++j; + term *= xsqr/j; + sum += term/(2*j+1); + ++j; + } while (fabs(term/sum) > MATH_TOLERANCE); + return two_sqrtpi*sum; +} + +/* Implementation of complementary Error function */ +double +erfc(double x) +{ + static const double one_sqrtpi= 0.564189583547756287; + double a = 1; + double b = x; + double c = x; + double d = x*x+0.5; + double q1; + double q2 = b/d; + double n = 1.0; + double t; + if (fabs(x) < 2.2) { + return 1.0 - erf(x); + } + if (x < 0.0) { /*signbit(x)*/ + return 2.0 - erfc(-x); + } + do { + t = a*n+b*x; + a = b; + b = t; + t = c*n+d*x; + c = d; + d = t; + n += 0.5; + q1 = q2; + q2 = b/d; + } while (fabs(q1-q2)/q2 > MATH_TOLERANCE); + return one_sqrtpi*exp(-x*x)*q2; +} + +#endif + +#if (defined _MSC_VER && _MSC_VER < 1800) || defined __ANDROID__ || (defined __FreeBSD__ && __FreeBSD_version < 803000) + +double +log2(double x) +{ + return log10(x)/log10(2.0); +} + +#endif + +/* + TRIGONOMETRIC FUNCTIONS +*/ + +/* + * call-seq: + * Math.sin(x) -> float + * + * Computes the sine of <i>x</i> (expressed in radians). Returns + * -1..1. + */ +static mrb_value +math_sin(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = sin(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.cos(x) -> float + * + * Computes the cosine of <i>x</i> (expressed in radians). Returns + * -1..1. + */ +static mrb_value +math_cos(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = cos(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.tan(x) -> float + * + * Returns the tangent of <i>x</i> (expressed in radians). + */ +static mrb_value +math_tan(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = tan(x); + + return mrb_float_value(mrb, x); +} + +/* + INVERSE TRIGONOMETRIC FUNCTIONS +*/ + +/* + * call-seq: + * Math.asin(x) -> float + * + * Computes the arc sine of <i>x</i>. + * @return computed value between `-(PI/2)` and `(PI/2)`. + */ +static mrb_value +math_asin(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + if (x < -1.0 || x > 1.0) { + domain_error(mrb, "asin"); + } + x = asin(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.acos(x) -> float + * + * Computes the arc cosine of <i>x</i>. Returns 0..PI. + */ +static mrb_value +math_acos(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + if (x < -1.0 || x > 1.0) { + domain_error(mrb, "acos"); + } + x = acos(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.atan(x) -> float + * + * Computes the arc tangent of <i>x</i>. Returns `-(PI/2) .. (PI/2)`. + */ +static mrb_value +math_atan(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = atan(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.atan2(y, x) -> float + * + * Computes the arc tangent given <i>y</i> and <i>x</i>. Returns + * -PI..PI. + * + * Math.atan2(-0.0, -1.0) #=> -3.141592653589793 + * Math.atan2(-1.0, -1.0) #=> -2.356194490192345 + * Math.atan2(-1.0, 0.0) #=> -1.5707963267948966 + * Math.atan2(-1.0, 1.0) #=> -0.7853981633974483 + * Math.atan2(-0.0, 1.0) #=> -0.0 + * Math.atan2(0.0, 1.0) #=> 0.0 + * Math.atan2(1.0, 1.0) #=> 0.7853981633974483 + * Math.atan2(1.0, 0.0) #=> 1.5707963267948966 + * Math.atan2(1.0, -1.0) #=> 2.356194490192345 + * Math.atan2(0.0, -1.0) #=> 3.141592653589793 + * + */ +static mrb_value +math_atan2(mrb_state *mrb, mrb_value obj) +{ + mrb_float x, y; + + mrb_get_args(mrb, "ff", &x, &y); + x = atan2(x, y); + + return mrb_float_value(mrb, x); +} + + + +/* + HYPERBOLIC TRIG FUNCTIONS +*/ +/* + * call-seq: + * Math.sinh(x) -> float + * + * Computes the hyperbolic sine of <i>x</i> (expressed in + * radians). + */ +static mrb_value +math_sinh(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = sinh(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.cosh(x) -> float + * + * Computes the hyperbolic cosine of <i>x</i> (expressed in radians). + */ +static mrb_value +math_cosh(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = cosh(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.tanh() -> float + * + * Computes the hyperbolic tangent of <i>x</i> (expressed in + * radians). + */ +static mrb_value +math_tanh(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = tanh(x); + + return mrb_float_value(mrb, x); +} + + +/* + INVERSE HYPERBOLIC TRIG FUNCTIONS +*/ + +/* + * call-seq: + * Math.asinh(x) -> float + * + * Computes the inverse hyperbolic sine of <i>x</i>. + */ +static mrb_value +math_asinh(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + + x = asinh(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.acosh(x) -> float + * + * Computes the inverse hyperbolic cosine of <i>x</i>. + */ +static mrb_value +math_acosh(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + if (x < 1.0) { + domain_error(mrb, "acosh"); + } + x = acosh(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.atanh(x) -> float + * + * Computes the inverse hyperbolic tangent of <i>x</i>. + */ +static mrb_value +math_atanh(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + if (x < -1.0 || x > 1.0) { + domain_error(mrb, "atanh"); + } + x = atanh(x); + + return mrb_float_value(mrb, x); +} + +/* + EXPONENTIALS AND LOGARITHMS +*/ + +/* + * call-seq: + * Math.exp(x) -> float + * + * Returns e**x. + * + * Math.exp(0) #=> 1.0 + * Math.exp(1) #=> 2.718281828459045 + * Math.exp(1.5) #=> 4.4816890703380645 + * + */ +static mrb_value +math_exp(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = exp(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.log(numeric) -> float + * Math.log(num,base) -> float + * + * Returns the natural logarithm of <i>numeric</i>. + * If additional second argument is given, it will be the base + * of logarithm. + * + * Math.log(1) #=> 0.0 + * Math.log(Math::E) #=> 1.0 + * Math.log(Math::E**3) #=> 3.0 + * Math.log(12,3) #=> 2.2618595071429146 + * + */ +static mrb_value +math_log(mrb_state *mrb, mrb_value obj) +{ + mrb_float x, base; + int argc; + + argc = mrb_get_args(mrb, "f|f", &x, &base); + if (x < 0.0) { + domain_error(mrb, "log"); + } + x = log(x); + if (argc == 2) { + if (base < 0.0) { + domain_error(mrb, "log"); + } + x /= log(base); + } + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.log2(numeric) -> float + * + * Returns the base 2 logarithm of <i>numeric</i>. + * + * Math.log2(1) #=> 0.0 + * Math.log2(2) #=> 1.0 + * Math.log2(32768) #=> 15.0 + * Math.log2(65536) #=> 16.0 + * + */ +static mrb_value +math_log2(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + if (x < 0.0) { + domain_error(mrb, "log2"); + } + x = log2(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.log10(numeric) -> float + * + * Returns the base 10 logarithm of <i>numeric</i>. + * + * Math.log10(1) #=> 0.0 + * Math.log10(10) #=> 1.0 + * Math.log10(10**100) #=> 100.0 + * + */ +static mrb_value +math_log10(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + if (x < 0.0) { + domain_error(mrb, "log10"); + } + x = log10(x); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.sqrt(numeric) -> float + * + * Returns the square root of <i>numeric</i>. + * + */ +static mrb_value +math_sqrt(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + if (x < 0.0) { + domain_error(mrb, "sqrt"); + } + x = sqrt(x); + + return mrb_float_value(mrb, x); +} + + +/* + * call-seq: + * Math.cbrt(numeric) -> float + * + * Returns the cube root of <i>numeric</i>. + * + * -9.upto(9) {|x| + * p [x, Math.cbrt(x), Math.cbrt(x)**3] + * } + * #=> + * [-9, -2.0800838230519, -9.0] + * [-8, -2.0, -8.0] + * [-7, -1.91293118277239, -7.0] + * [-6, -1.81712059283214, -6.0] + * [-5, -1.7099759466767, -5.0] + * [-4, -1.5874010519682, -4.0] + * [-3, -1.44224957030741, -3.0] + * [-2, -1.25992104989487, -2.0] + * [-1, -1.0, -1.0] + * [0, 0.0, 0.0] + * [1, 1.0, 1.0] + * [2, 1.25992104989487, 2.0] + * [3, 1.44224957030741, 3.0] + * [4, 1.5874010519682, 4.0] + * [5, 1.7099759466767, 5.0] + * [6, 1.81712059283214, 6.0] + * [7, 1.91293118277239, 7.0] + * [8, 2.0, 8.0] + * [9, 2.0800838230519, 9.0] + * + */ +static mrb_value +math_cbrt(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = cbrt(x); + + return mrb_float_value(mrb, x); +} + + +/* + * call-seq: + * Math.frexp(numeric) -> [ fraction, exponent ] + * + * Returns a two-element array containing the normalized fraction (a + * <code>Float</code>) and exponent (a <code>Fixnum</code>) of + * <i>numeric</i>. + * + * fraction, exponent = Math.frexp(1234) #=> [0.6025390625, 11] + * fraction * 2**exponent #=> 1234.0 + */ +static mrb_value +math_frexp(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + int exp; + + mrb_get_args(mrb, "f", &x); + x = frexp(x, &exp); + + return mrb_assoc_new(mrb, mrb_float_value(mrb, x), mrb_fixnum_value(exp)); +} + +/* + * call-seq: + * Math.ldexp(flt, int) -> float + * + * Returns the value of <i>flt</i>*(2**<i>int</i>). + * + * fraction, exponent = Math.frexp(1234) + * Math.ldexp(fraction, exponent) #=> 1234.0 + */ +static mrb_value +math_ldexp(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + mrb_int i; + + mrb_get_args(mrb, "fi", &x, &i); + x = ldexp(x, i); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.hypot(x, y) -> float + * + * Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled triangle + * with sides <i>x</i> and <i>y</i>. + * + * Math.hypot(3, 4) #=> 5.0 + */ +static mrb_value +math_hypot(mrb_state *mrb, mrb_value obj) +{ + mrb_float x, y; + + mrb_get_args(mrb, "ff", &x, &y); + x = hypot(x, y); + + return mrb_float_value(mrb, x); +} + +/* + * call-seq: + * Math.erf(x) -> float + * + * Calculates the error function of x. + */ +static mrb_value +math_erf(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = erf(x); + + return mrb_float_value(mrb, x); +} + + +/* + * call-seq: + * Math.erfc(x) -> float + * + * Calculates the complementary error function of x. + */ +static mrb_value +math_erfc(mrb_state *mrb, mrb_value obj) +{ + mrb_float x; + + mrb_get_args(mrb, "f", &x); + x = erfc(x); + + return mrb_float_value(mrb, x); +} + +/* ------------------------------------------------------------------------*/ +void +mrb_mruby_math_gem_init(mrb_state* mrb) +{ + struct RClass *mrb_math; + mrb_math = mrb_define_module(mrb, "Math"); + + mrb_define_class_under(mrb, mrb_math, "DomainError", mrb->eStandardError_class); + +#ifdef M_PI + mrb_define_const(mrb, mrb_math, "PI", mrb_float_value(mrb, M_PI)); +#else + mrb_define_const(mrb, mrb_math, "PI", mrb_float_value(mrb, atan(1.0)*4.0)); +#endif + +#ifdef M_E + mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, M_E)); +#else + mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, exp(1.0))); +#endif + +#ifdef MRB_USE_FLOAT + mrb_define_const(mrb, mrb_math, "TOLERANCE", mrb_float_value(mrb, 1e-5)); +#else + mrb_define_const(mrb, mrb_math, "TOLERANCE", mrb_float_value(mrb, 1e-12)); +#endif + + mrb_define_module_function(mrb, mrb_math, "sin", math_sin, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "cos", math_cos, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "tan", math_tan, MRB_ARGS_REQ(1)); + + mrb_define_module_function(mrb, mrb_math, "asin", math_asin, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "acos", math_acos, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "atan", math_atan, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "atan2", math_atan2, MRB_ARGS_REQ(2)); + + mrb_define_module_function(mrb, mrb_math, "sinh", math_sinh, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "cosh", math_cosh, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "tanh", math_tanh, MRB_ARGS_REQ(1)); + + mrb_define_module_function(mrb, mrb_math, "asinh", math_asinh, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "acosh", math_acosh, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "atanh", math_atanh, MRB_ARGS_REQ(1)); + + mrb_define_module_function(mrb, mrb_math, "exp", math_exp, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "log", math_log, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_module_function(mrb, mrb_math, "log2", math_log2, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "log10", math_log10, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "sqrt", math_sqrt, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "cbrt", math_cbrt, MRB_ARGS_REQ(1)); + + mrb_define_module_function(mrb, mrb_math, "frexp", math_frexp, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "ldexp", math_ldexp, MRB_ARGS_REQ(2)); + + mrb_define_module_function(mrb, mrb_math, "hypot", math_hypot, MRB_ARGS_REQ(2)); + + mrb_define_module_function(mrb, mrb_math, "erf", math_erf, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, mrb_math, "erfc", math_erfc, MRB_ARGS_REQ(1)); +} + +void +mrb_mruby_math_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-math/test/math.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-math/test/math.rb new file mode 100644 index 000000000..e9ea07cc1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-math/test/math.rb @@ -0,0 +1,152 @@ +## +# Math Test + +## +# Performs fuzzy check for equality on methods returning floats +# on the basis of the Math::TOLERANCE constant. +def check_float(a, b) + tolerance = Math::TOLERANCE + a = a.to_f + b = b.to_f + if a.finite? and b.finite? + (a-b).abs < tolerance + else + true + end +end + +assert('Math.sin 0') do + check_float(Math.sin(0), 0) +end + +assert('Math.sin PI/2') do + check_float(Math.sin(Math::PI / 2), 1) +end + +assert('Math.cos 0') do + check_float(Math.cos(0), 1) +end + +assert('Math.cos PI/2') do + check_float(Math.cos(Math::PI / 2), 0) +end + +assert('Math.tan 0') do + check_float(Math.tan(0), 0) +end + +assert('Math.tan PI/4') do + check_float(Math.tan(Math::PI / 4), 1) +end + +assert('Fundamental trig identities') do + result = true + N = 13 + N.times do |i| + a = Math::PI / N * i + ca = Math::PI / 2 - a + s = Math.sin(a) + c = Math.cos(a) + t = Math.tan(a) + result &= check_float(s, Math.cos(ca)) + result &= check_float(t, 1 / Math.tan(ca)) + result &= check_float(s ** 2 + c ** 2, 1) + result &= check_float(t ** 2 + 1, (1/c) ** 2) + result &= check_float((1/t) ** 2 + 1, (1/s) ** 2) + end + result +end + +assert('Math.erf 0') do + check_float(Math.erf(0), 0) +end + +assert('Math.exp 0') do + check_float(Math.exp(0), 1.0) +end + +assert('Math.exp 1') do + check_float(Math.exp(1), 2.718281828459045) +end + +assert('Math.exp 1.5') do + check_float(Math.exp(1.5), 4.4816890703380645) +end + +assert('Math.log 1') do + check_float(Math.log(1), 0) +end + +assert('Math.log E') do + check_float(Math.log(Math::E), 1.0) +end + +assert('Math.log E**3') do + check_float(Math.log(Math::E**3), 3.0) +end + +assert('Math.log2 1') do + check_float(Math.log2(1), 0.0) +end + +assert('Math.log2 2') do + check_float(Math.log2(2), 1.0) +end + +assert('Math.log10 1') do + check_float(Math.log10(1), 0.0) +end + +assert('Math.log10 10') do + check_float(Math.log10(10), 1.0) +end + +assert('Math.log10 10**100') do + check_float(Math.log10(10**100), 100.0) +end + +assert('Math.sqrt') do + num = [0.0, 1.0, 2.0, 3.0, 4.0] + sqr = [0, 1, 4, 9, 16] + result = true + sqr.each_with_index do |v,i| + result &= check_float(Math.sqrt(v), num[i]) + end + result +end + +assert('Math.cbrt') do + num = [-2.0, -1.0, 0.0, 1.0, 2.0] + cub = [-8, -1, 0, 1, 8] + result = true + cub.each_with_index do |v,i| + result &= check_float(Math.cbrt(v), num[i]) + end + result +end + +assert('Math.hypot') do + check_float(Math.hypot(3, 4), 5.0) +end + +assert('Math.frexp 1234') do + n = 1234 + fraction, exponent = Math.frexp(n) + check_float(Math.ldexp(fraction, exponent), n) +end + +assert('Math.erf 1') do + check_float(Math.erf(1), 0.842700792949715) +end + +assert('Math.erfc 1') do + check_float(Math.erfc(1), 0.157299207050285) +end + +assert('Math.erf -1') do + check_float(Math.erf(-1), -0.8427007929497148) +end + +assert('Math.erfc -1') do + check_float(Math.erfc(-1), 1.8427007929497148) +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/mrbgem.rake new file mode 100644 index 000000000..6db7e589e --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-numeric-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Numeric class extension' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb new file mode 100644 index 000000000..0bf3c6ab6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb @@ -0,0 +1,17 @@ +module Integral + def div(other) + self.divmod(other)[0] + end + + def zero? + self == 0 + end + + def nonzero? + if self == 0 + nil + else + self + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/src/numeric_ext.c new file mode 100644 index 000000000..f71236a32 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/src/numeric_ext.c @@ -0,0 +1,30 @@ +#include <limits.h> +#include <mruby.h> + +static mrb_value +mrb_int_chr(mrb_state *mrb, mrb_value x) +{ + mrb_int chr; + char c; + + chr = mrb_fixnum(x); + if (chr >= (1 << CHAR_BIT)) { + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", x); + } + c = (char)chr; + + return mrb_str_new(mrb, &c, 1); +} + +void +mrb_mruby_numeric_ext_gem_init(mrb_state* mrb) +{ + struct RClass *i = mrb_class_get(mrb, "Integer"); + + mrb_define_method(mrb, i, "chr", mrb_int_chr, MRB_ARGS_NONE()); +} + +void +mrb_mruby_numeric_ext_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/test/numeric.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/test/numeric.rb new file mode 100644 index 000000000..8bead2489 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-numeric-ext/test/numeric.rb @@ -0,0 +1,28 @@ +## +# Numeric(Ext) Test + +assert('Integer#chr') do + assert_equal("A", 65.chr) + assert_equal("B", 0x42.chr) + + # multibyte encoding (not support yet) + assert_raise(RangeError) { 256.chr } +end + +assert('Integer#div') do + assert_equal 52, 365.div(7) +end + +assert('Float#div') do + assert_float 52, 365.2425.div(7) +end + +assert('Integer#zero?') do + assert_equal true, 0.zero? + assert_equal false, 1.zero? +end + +assert('Integer#nonzero?') do + assert_equal nil, 0.nonzero? + assert_equal 1000, 1000.nonzero? +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/mrbgem.rake new file mode 100644 index 000000000..6d14b4a51 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-object-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Object class extension' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/mrblib/object.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/mrblib/object.rb new file mode 100644 index 000000000..581156cb0 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/mrblib/object.rb @@ -0,0 +1,19 @@ +class Object + ## + # call-seq: + # obj.tap{|x|...} -> obj + # + # Yields <code>x</code> to the block, and then returns <code>x</code>. + # The primary purpose of this method is to "tap into" a method chain, + # in order to perform operations on intermediate results within the chain. + # + # (1..10) .tap {|x| puts "original: #{x.inspect}"} + # .to_a .tap {|x| puts "array: #{x.inspect}"} + # .select {|x| x%2==0} .tap {|x| puts "evens: #{x.inspect}"} + # .map { |x| x*x } .tap {|x| puts "squares: #{x.inspect}"} + # + def tap + yield self + self + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/src/object.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/src/object.c new file mode 100644 index 000000000..35a07b584 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/src/object.c @@ -0,0 +1,106 @@ +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/proc.h> + +/* + * call-seq: + * nil.to_a -> [] + * + * Always returns an empty array. + */ + +static mrb_value +nil_to_a(mrb_state *mrb, mrb_value obj) +{ + return mrb_ary_new(mrb); +} + +/* + * call-seq: + * nil.to_f -> 0.0 + * + * Always returns zero. + */ + +static mrb_value +nil_to_f(mrb_state *mrb, mrb_value obj) +{ + return mrb_float_value(mrb, 0.0); +} + +/* + * call-seq: + * nil.to_i -> 0 + * + * Always returns zero. + */ + +static mrb_value +nil_to_i(mrb_state *mrb, mrb_value obj) +{ + return mrb_fixnum_value(0); +} + +/* + * call-seq: + * obj.instance_exec(arg...) {|var...| block } -> obj + * + * Executes the given block within the context of the receiver + * (_obj_). In order to set the context, the variable +self+ is set + * to _obj_ while the code is executing, giving the code access to + * _obj_'s instance variables. Arguments are passed as block parameters. + * + * class KlassWithSecret + * def initialize + * @secret = 99 + * end + * end + * k = KlassWithSecret.new + * k.instance_exec(5) {|x| @secret+x } #=> 104 + */ + +static mrb_value +mrb_obj_instance_exec(mrb_state *mrb, mrb_value self) +{ + const mrb_value *argv; + mrb_int argc; + mrb_value blk; + struct RClass *c; + + mrb_get_args(mrb, "*&", &argv, &argc, &blk); + + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + + switch (mrb_type(self)) { + case MRB_TT_SYMBOL: + case MRB_TT_FIXNUM: + case MRB_TT_FLOAT: + c = NULL; + break; + default: + c = mrb_class_ptr(mrb_singleton_class(mrb, self)); + break; + } + mrb->c->ci->target_class = c; + return mrb_yield_cont(mrb, blk, self, argc, argv); +} + +void +mrb_mruby_object_ext_gem_init(mrb_state* mrb) +{ + struct RClass * n = mrb->nil_class; + + mrb_define_method(mrb, n, "to_a", nil_to_a, MRB_ARGS_NONE()); + mrb_define_method(mrb, n, "to_f", nil_to_f, MRB_ARGS_NONE()); + mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE()); + + mrb_define_method(mrb, mrb->kernel_module, "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK()); +} + +void +mrb_mruby_object_ext_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/test/nil.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/test/nil.rb new file mode 100644 index 000000000..5cd1cf4ed --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/test/nil.rb @@ -0,0 +1,11 @@ +assert('NilClass#to_a') do + assert_equal [], nil.to_a +end + +assert('NilClass#to_f') do + assert_equal 0.0, nil.to_f +end + +assert('NilClass#to_i') do + assert_equal 0, nil.to_i +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/test/object.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/test/object.rb new file mode 100644 index 000000000..f0742f8ce --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-object-ext/test/object.rb @@ -0,0 +1,53 @@ +assert('Object#instance_exec') do + class KlassWithSecret + def initialize + @secret = 99 + end + end + k = KlassWithSecret.new + assert_equal 104, k.instance_exec(5) {|x| @secret+x } +end + +assert('Object#tap') do + ret = [] + (1..10) .tap {|x| ret << "original: #{x.inspect}"} + .to_a .tap {|x| ret << "array: #{x.inspect}"} + .select {|x| x%2==0} .tap {|x| ret << "evens: #{x.inspect}"} + .map { |x| x*x } .tap {|x| ret << "squares: #{x.inspect}"} + + assert_equal [ + "original: 1..10", + "array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", + "evens: [2, 4, 6, 8, 10]", + "squares: [4, 16, 36, 64, 100]" + ], ret + assert_equal(:tap_ok, Class.new {def m; tap{return :tap_ok}; end}.new.m) +end + +assert('instance_exec on primitives with class and module definition') do + begin + class A + 1.instance_exec do + class B + end + end + end + + assert_kind_of Class, A::B + ensure + Object.remove_const :A + end + + begin + class A + 1.instance_exec do + module B + end + end + end + + assert_kind_of Module, A::B + ensure + Object.remove_const :A + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-objectspace/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-objectspace/mrbgem.rake new file mode 100644 index 000000000..fa35136a1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-objectspace/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-objectspace') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'ObjectSpace class' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-objectspace/src/mruby_objectspace.c new file mode 100644 index 000000000..3887091d3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-objectspace/src/mruby_objectspace.c @@ -0,0 +1,187 @@ +#include <mruby.h> +#include <mruby/gc.h> +#include <mruby/hash.h> +#include <mruby/class.h> + +struct os_count_struct { + mrb_int total; + mrb_int freed; + mrb_int counts[MRB_TT_MAXDEFINE+1]; +}; + +static int +os_count_object_type(mrb_state *mrb, struct RBasic *obj, void *data) +{ + struct os_count_struct *obj_count; + obj_count = (struct os_count_struct*)data; + + obj_count->total++; + + if (mrb_object_dead_p(mrb, obj)) { + obj_count->freed++; + } + else { + obj_count->counts[obj->tt]++; + } + return MRB_EACH_OBJ_OK; +} + +/* + * call-seq: + * ObjectSpace.count_objects([result_hash]) -> hash + * + * Counts objects for each type. + * + * It returns a hash, such as: + * { + * :TOTAL=>10000, + * :FREE=>3011, + * :T_OBJECT=>6, + * :T_CLASS=>404, + * # ... + * } + * + * If the optional argument +result_hash+ is given, + * it is overwritten and returned. This is intended to avoid probe effect. + * + */ + +static mrb_value +os_count_objects(mrb_state *mrb, mrb_value self) +{ + struct os_count_struct obj_count = { 0 }; + mrb_int i; + mrb_value hash; + + if (mrb_get_args(mrb, "|H", &hash) == 0) { + hash = mrb_hash_new(mrb); + } + + if (!mrb_test(mrb_hash_empty_p(mrb, hash))) { + mrb_hash_clear(mrb, hash); + } + + mrb_objspace_each_objects(mrb, os_count_object_type, &obj_count); + + mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_lit(mrb, "TOTAL")), mrb_fixnum_value(obj_count.total)); + mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_lit(mrb, "FREE")), mrb_fixnum_value(obj_count.freed)); + + for (i = MRB_TT_FALSE; i < MRB_TT_MAXDEFINE; i++) { + mrb_value type; + switch (i) { +#define COUNT_TYPE(t) case (MRB_T ## t): type = mrb_symbol_value(mrb_intern_lit(mrb, #t)); break; + COUNT_TYPE(T_FALSE); + COUNT_TYPE(T_FREE); + COUNT_TYPE(T_TRUE); + COUNT_TYPE(T_FIXNUM); + COUNT_TYPE(T_SYMBOL); + COUNT_TYPE(T_UNDEF); + COUNT_TYPE(T_FLOAT); + COUNT_TYPE(T_CPTR); + COUNT_TYPE(T_OBJECT); + COUNT_TYPE(T_CLASS); + COUNT_TYPE(T_MODULE); + COUNT_TYPE(T_ICLASS); + COUNT_TYPE(T_SCLASS); + COUNT_TYPE(T_PROC); + COUNT_TYPE(T_ARRAY); + COUNT_TYPE(T_HASH); + COUNT_TYPE(T_STRING); + COUNT_TYPE(T_RANGE); + COUNT_TYPE(T_EXCEPTION); + COUNT_TYPE(T_FILE); + COUNT_TYPE(T_ENV); + COUNT_TYPE(T_DATA); + COUNT_TYPE(T_FIBER); +#undef COUNT_TYPE + default: + type = mrb_fixnum_value(i); break; + } + if (obj_count.counts[i]) + mrb_hash_set(mrb, hash, type, mrb_fixnum_value(obj_count.counts[i])); + } + + return hash; +} + +struct os_each_object_data { + mrb_value block; + struct RClass *target_module; + mrb_int count; +}; + +static int +os_each_object_cb(mrb_state *mrb, struct RBasic *obj, void *ud) +{ + struct os_each_object_data *d = (struct os_each_object_data*)ud; + + /* filter dead objects */ + if (mrb_object_dead_p(mrb, obj)) { + return MRB_EACH_OBJ_OK; + } + + /* filter internal objects */ + switch (obj->tt) { + case MRB_TT_ENV: + case MRB_TT_ICLASS: + return MRB_EACH_OBJ_OK; + default: + break; + } + + /* filter half baked (or internal) objects */ + if (!obj->c) return MRB_EACH_OBJ_OK; + + /* filter class kind if target module defined */ + if (d->target_module && !mrb_obj_is_kind_of(mrb, mrb_obj_value(obj), d->target_module)) { + return MRB_EACH_OBJ_OK; + } + + mrb_yield(mrb, d->block, mrb_obj_value(obj)); + ++d->count; + return MRB_EACH_OBJ_OK; +} + +/* + * call-seq: + * ObjectSpace.each_object([module]) {|obj| ... } -> fixnum + * + * Calls the block once for each object in this Ruby process. + * Returns the number of objects found. + * If the optional argument +module+ is given, + * calls the block for only those classes or modules + * that match (or are a subclass of) +module+. + * + * If no block is given, ArgumentError is raised. + * + */ + +static mrb_value +os_each_object(mrb_state *mrb, mrb_value self) +{ + mrb_value cls = mrb_nil_value(); + struct os_each_object_data d; + mrb_get_args(mrb, "&|C", &d.block, &cls); + + if (mrb_nil_p(d.block)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "Expected block in ObjectSpace.each_object."); + } + + d.target_module = mrb_nil_p(cls) ? NULL : mrb_class_ptr(cls); + d.count = 0; + mrb_objspace_each_objects(mrb, os_each_object_cb, &d); + return mrb_fixnum_value(d.count); +} + +void +mrb_mruby_objectspace_gem_init(mrb_state *mrb) +{ + struct RClass *os = mrb_define_module(mrb, "ObjectSpace"); + mrb_define_class_method(mrb, os, "count_objects", os_count_objects, MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, os, "each_object", os_each_object, MRB_ARGS_OPT(1)); +} + +void +mrb_mruby_objectspace_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-objectspace/test/objectspace.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-objectspace/test/objectspace.rb new file mode 100644 index 000000000..4731d53b5 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-objectspace/test/objectspace.rb @@ -0,0 +1,60 @@ +assert('ObjectSpace.count_objects') do + h = {} + f = Fiber.new {} if Object.const_defined? :Fiber + ObjectSpace.count_objects(h) + assert_kind_of(Hash, h) + assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) }) + assert_true(h.values.all? {|x| x.is_a?(Integer) }) + + assert_true(h.has_key?(:TOTAL)) + assert_true(h.has_key?(:FREE)) + assert_true(h.has_key?(:T_FIBER)) if Object.const_defined? :Fiber + + assert_equal(h[:TOTAL] * 2, h.values.reduce(:+)) + + h = ObjectSpace.count_objects + assert_kind_of(Hash, h) + assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) }) + assert_true(h.values.all? {|x| x.is_a?(Integer) }) + + assert_raise(TypeError) { ObjectSpace.count_objects(1) } + + h0 = {:T_FOO=>1000} + h = ObjectSpace.count_objects(h0) + assert_false(h0.has_key?(:T_FOO)) + + GC.start + h_after = {} + h_before = ObjectSpace.count_objects + + objs = [] + 1000.times do + objs << {} + end + objs = nil + ObjectSpace.count_objects(h) + GC.start + ObjectSpace.count_objects(h_after) + + assert_equal(h[:T_HASH], h_before[:T_HASH] + 1000) + assert_equal(h_after[:T_HASH], h_before[:T_HASH]) +end + +assert('ObjectSpace.each_object') do + objs = [] + objs_count = ObjectSpace.each_object { |obj| + objs << obj + } + assert_equal objs.length, objs_count + + arys = [] + arys_count = ObjectSpace.each_object(Array) { |obj| + arys << obj + } + assert_equal arys.length, arys_count + assert_true arys.length < objs.length +end + +assert 'Check class pointer of ObjectSpace.each_object.' do + ObjectSpace.each_object { |obj| !obj } +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-print/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-print/mrbgem.rake new file mode 100644 index 000000000..2ea6e3126 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-print/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-print') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'standard print/puts/p' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-print/mrblib/print.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-print/mrblib/print.rb new file mode 100644 index 000000000..38a10661b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-print/mrblib/print.rb @@ -0,0 +1,64 @@ +## +# Kernel +# +# ISO 15.3.1 +module Kernel + ## + # Invoke method +print+ on STDOUT and passing +*args+ + # + # ISO 15.3.1.2.10 + def print(*args) + i = 0 + len = args.size + while i < len + __printstr__ args[i].to_s + i += 1 + end + end + + ## + # Invoke method +puts+ on STDOUT and passing +*args*+ + # + # ISO 15.3.1.2.11 + def puts(*args) + i = 0 + len = args.size + while i < len + s = args[i].to_s + __printstr__ s + __printstr__ "\n" if (s[-1] != "\n") + i += 1 + end + __printstr__ "\n" if len == 0 + nil + end + + ## + # Print human readable object description + # + # ISO 15.3.1.3.34 + def p(*args) + i = 0 + len = args.size + while i < len + __printstr__ args[i].inspect + __printstr__ "\n" + i += 1 + end + args[0] + end + + unless Kernel.respond_to?(:sprintf) + def printf(*args) + raise NotImplementedError.new('printf not available') + end + def sprintf(*args) + raise NotImplementedError.new('sprintf not available') + end + else + def printf(*args) + __printstr__(sprintf(*args)) + nil + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-print/src/print.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-print/src/print.c new file mode 100644 index 000000000..d0c522d24 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-print/src/print.c @@ -0,0 +1,64 @@ +#include <mruby.h> +#include <mruby/string.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#if defined(_WIN32) +# include <windows.h> +# include <io.h> +#ifdef _MSC_VER +# define isatty(x) _isatty(x) +# define fileno(x) _fileno(x) +#endif +#endif + +static void +printstr(mrb_state *mrb, mrb_value obj) +{ + if (mrb_string_p(obj)) { +#if defined(_WIN32) + if (isatty(fileno(stdout))) { + DWORD written; + int mlen = RSTRING_LEN(obj); + char* utf8 = RSTRING_PTR(obj); + int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, NULL, 0); + wchar_t* utf16 = (wchar_t*)mrb_malloc(mrb, (wlen+1) * sizeof(wchar_t)); + if (utf16 == NULL) return; + if (MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, utf16, wlen) > 0) { + utf16[wlen] = 0; + WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), + utf16, wlen, &written, NULL); + } + mrb_free(mrb, utf16); + } else +#endif + fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stdout); + fflush(stdout); + } +} + +/* 15.3.1.2.9 */ +/* 15.3.1.3.34 */ +mrb_value +mrb_printstr(mrb_state *mrb, mrb_value self) +{ + mrb_value argv; + + mrb_get_args(mrb, "o", &argv); + printstr(mrb, argv); + + return argv; +} + +void +mrb_mruby_print_gem_init(mrb_state* mrb) +{ + struct RClass *krn; + krn = mrb->kernel_module; + mrb_define_method(mrb, krn, "__printstr__", mrb_printstr, MRB_ARGS_REQ(1)); +} + +void +mrb_mruby_print_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/mrbgem.rake new file mode 100644 index 000000000..e4d15a140 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-proc-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Proc class extension' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/mrblib/proc.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/mrblib/proc.rb new file mode 100644 index 000000000..b71663938 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/mrblib/proc.rb @@ -0,0 +1,42 @@ +class Proc + + def ===(*args) + call(*args) + end + + def yield(*args) + call(*args) + end + + def to_proc + self + end + + def curry(arity=self.arity) + type = :proc + abs = lambda {|a| a < 0 ? -a - 1 : a} + arity = abs[arity] + if lambda? + type = :lambda + self_arity = self.arity + if (self_arity >= 0 && arity != self_arity) || + (self_arity < 0 && abs[self_arity] > arity) + raise ArgumentError, "wrong number of arguments (#{arity} for #{abs[self_arity]})" + end + end + + pproc = self + make_curry = proc do |given_args=[]| + send(type) do |*args| + new_args = given_args + args + if new_args.size >= arity + pproc[*new_args] + else + make_curry[new_args] + end + end + end + make_curry.call + end + +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/src/proc.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/src/proc.c new file mode 100644 index 000000000..b13606f5f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/src/proc.c @@ -0,0 +1,173 @@ +#include <mruby.h> +#include <mruby/proc.h> +#include <mruby/opcode.h> +#include <mruby/array.h> +#include <mruby/string.h> +#include <mruby/debug.h> + +static mrb_value +mrb_proc_lambda(mrb_state *mrb, mrb_value self) +{ + struct RProc *p = mrb_proc_ptr(self); + return mrb_bool_value(MRB_PROC_STRICT_P(p)); +} + +static mrb_value +mrb_proc_source_location(mrb_state *mrb, mrb_value self) +{ + struct RProc *p = mrb_proc_ptr(self); + + if (MRB_PROC_CFUNC_P(p)) { + return mrb_nil_value(); + } + else { + mrb_irep *irep = p->body.irep; + int32_t line; + const char *filename; + + filename = mrb_debug_get_filename(irep, 0); + line = mrb_debug_get_line(irep, 0); + + return (!filename && line == -1)? mrb_nil_value() + : mrb_assoc_new(mrb, mrb_str_new_cstr(mrb, filename), mrb_fixnum_value(line)); + } +} + +static mrb_value +mrb_proc_inspect(mrb_state *mrb, mrb_value self) +{ + struct RProc *p = mrb_proc_ptr(self); + mrb_value str = mrb_str_new_lit(mrb, "#<Proc:"); + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(self))); + + if (!MRB_PROC_CFUNC_P(p)) { + mrb_irep *irep = p->body.irep; + const char *filename; + int32_t line; + mrb_str_cat_lit(mrb, str, "@"); + + filename = mrb_debug_get_filename(irep, 0); + mrb_str_cat_cstr(mrb, str, filename ? filename : "-"); + mrb_str_cat_lit(mrb, str, ":"); + + line = mrb_debug_get_line(irep, 0); + if (line != -1) { + str = mrb_format(mrb, "%S:%S", str, mrb_fixnum_value(line)); + } + else { + mrb_str_cat_lit(mrb, str, "-"); + } + } + + if (MRB_PROC_STRICT_P(p)) { + mrb_str_cat_lit(mrb, str, " (lambda)"); + } + + mrb_str_cat_lit(mrb, str, ">"); + return str; +} + +static mrb_value +mrb_kernel_proc(mrb_state *mrb, mrb_value self) +{ + mrb_value blk; + + mrb_get_args(mrb, "&", &blk); + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); + } + + return blk; +} + +/* + * call-seq: + * prc.parameters -> array + * + * Returns the parameter information of this proc. + * + * prc = lambda{|x, y=42, *other|} + * prc.parameters #=> [[:req, :x], [:opt, :y], [:rest, :other]] + */ + +static mrb_value +mrb_proc_parameters(mrb_state *mrb, mrb_value self) +{ + struct parameters_type { + int size; + const char *name; + } *p, parameters_list [] = { + {0, "req"}, + {0, "opt"}, + {0, "rest"}, + {0, "req"}, + {0, "block"}, + {0, NULL} + }; + const struct RProc *proc = mrb_proc_ptr(self); + const struct mrb_irep *irep = proc->body.irep; + mrb_aspec aspec; + mrb_value sname, parameters; + int i, j; + + if (MRB_PROC_CFUNC_P(proc)) { + // TODO cfunc aspec is not implemented yet + return mrb_ary_new(mrb); + } + if (!irep) { + return mrb_ary_new(mrb); + } + if (!irep->lv) { + return mrb_ary_new(mrb); + } + if (GET_OPCODE(*irep->iseq) != OP_ENTER) { + return mrb_ary_new(mrb); + } + + if (!MRB_PROC_STRICT_P(proc)) { + parameters_list[0].name = "opt"; + parameters_list[3].name = "opt"; + } + + aspec = GETARG_Ax(*irep->iseq); + parameters_list[0].size = MRB_ASPEC_REQ(aspec); + parameters_list[1].size = MRB_ASPEC_OPT(aspec); + parameters_list[2].size = MRB_ASPEC_REST(aspec); + parameters_list[3].size = MRB_ASPEC_POST(aspec); + parameters_list[4].size = MRB_ASPEC_BLOCK(aspec); + + parameters = mrb_ary_new_capa(mrb, irep->nlocals-1); + + for (i = 0, p = parameters_list; p->name; p++) { + if (p->size <= 0) continue; + sname = mrb_symbol_value(mrb_intern_cstr(mrb, p->name)); + for (j = 0; j < p->size; i++, j++) { + mrb_value a = mrb_ary_new(mrb); + mrb_ary_push(mrb, a, sname); + if (irep->lv[i].name) { + mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i].name)); + } + mrb_ary_push(mrb, parameters, a); + } + } + return parameters; +} + +void +mrb_mruby_proc_ext_gem_init(mrb_state* mrb) +{ + struct RClass *p = mrb->proc_class; + mrb_define_method(mrb, p, "lambda?", mrb_proc_lambda, MRB_ARGS_NONE()); + mrb_define_method(mrb, p, "source_location", mrb_proc_source_location, MRB_ARGS_NONE()); + mrb_define_method(mrb, p, "to_s", mrb_proc_inspect, MRB_ARGS_NONE()); + mrb_define_method(mrb, p, "inspect", mrb_proc_inspect, MRB_ARGS_NONE()); + mrb_define_method(mrb, p, "parameters", mrb_proc_parameters, MRB_ARGS_NONE()); + + mrb_define_class_method(mrb, mrb->kernel_module, "proc", mrb_kernel_proc, MRB_ARGS_NONE()); + mrb_define_method(mrb, mrb->kernel_module, "proc", mrb_kernel_proc, MRB_ARGS_NONE()); +} + +void +mrb_mruby_proc_ext_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/test/proc.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/test/proc.c new file mode 100644 index 000000000..a77b68e9d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/test/proc.c @@ -0,0 +1,56 @@ +#include <mruby.h> +#include <mruby/proc.h> +#include <mruby/class.h> + +static mrb_value +return_func_name(mrb_state *mrb, mrb_value self) +{ + return mrb_cfunc_env_get(mrb, 0); +} + +static mrb_value +proc_new_cfunc_with_env(mrb_state *mrb, mrb_value self) +{ + mrb_sym n; + mrb_value n_val; + mrb_get_args(mrb, "n", &n); + n_val = mrb_symbol_value(n); + mrb_define_method_raw(mrb, mrb_class_ptr(self), n, + mrb_proc_new_cfunc_with_env(mrb, return_func_name, 1, &n_val)); + return self; +} + +static mrb_value +return_env(mrb_state *mrb, mrb_value self) +{ + mrb_int idx; + mrb_get_args(mrb, "i", &idx); + return mrb_cfunc_env_get(mrb, idx); +} + +static mrb_value +cfunc_env_get(mrb_state *mrb, mrb_value self) +{ + mrb_sym n; + mrb_value *argv; mrb_int argc; + mrb_get_args(mrb, "na", &n, &argv, &argc); + mrb_define_method_raw(mrb, mrb_class_ptr(self), n, + mrb_proc_new_cfunc_with_env(mrb, return_env, argc, argv)); + return self; +} + +static mrb_value +cfunc_without_env(mrb_state *mrb, mrb_value self) +{ + return mrb_cfunc_env_get(mrb, 0); +} + +void mrb_mruby_proc_ext_gem_test(mrb_state *mrb) +{ + struct RClass *cls; + + cls = mrb_define_class(mrb, "ProcExtTest", mrb->object_class); + mrb_define_module_function(mrb, cls, "mrb_proc_new_cfunc_with_env", proc_new_cfunc_with_env, MRB_ARGS_REQ(1)); + mrb_define_module_function(mrb, cls, "mrb_cfunc_env_get", cfunc_env_get, MRB_ARGS_REQ(2)); + mrb_define_module_function(mrb, cls, "cfunc_without_env", cfunc_without_env, MRB_ARGS_NONE()); +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/test/proc.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/test/proc.rb new file mode 100644 index 000000000..037d8d124 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-proc-ext/test/proc.rb @@ -0,0 +1,96 @@ +## +# Proc(Ext) Test + +assert('Proc#source_location') do + loc = Proc.new {}.source_location + next true if loc.nil? + assert_equal loc[0][-7, 7], 'proc.rb' + assert_equal loc[1], 5 +end + +assert('Proc#inspect') do + ins = Proc.new{}.inspect + assert_kind_of String, ins +end + +assert('Proc#lambda?') do + assert_true lambda{}.lambda? + assert_true !Proc.new{}.lambda? +end + +assert('Proc#===') do + proc = Proc.new {|a| a * 2} + assert_equal 20, (proc === 10) +end + +assert('Proc#yield') do + proc = Proc.new {|a| a * 2} + assert_equal 20, proc.yield(10) +end + +assert('Proc#curry') do + b = proc {|x, y, z| (x||0) + (y||0) + (z||0) } + assert_equal 6, b.curry[1][2][3] + assert_equal 6, b.curry[1, 2][3, 4] + assert_equal 6, b.curry(5)[1][2][3][4][5] + assert_equal 6, b.curry(5)[1, 2][3, 4][5] + assert_equal 1, b.curry(1)[1] + + b = lambda {|x, y, z| (x||0) + (y||0) + (z||0) } + assert_equal 6, b.curry[1][2][3] + assert_raise(ArgumentError) { b.curry[1, 2][3, 4] } + assert_raise(ArgumentError) { b.curry(5) } + assert_raise(ArgumentError) { b.curry(1) } + + assert_false(proc{}.curry.lambda?) + assert_true(lambda{}.curry.lambda?) +end + +assert('Proc#parameters') do + assert_equal([], Proc.new {}.parameters) + assert_equal([], Proc.new {||}.parameters) + assert_equal([[:opt, :a]], Proc.new {|a|}.parameters) + assert_equal([[:req, :a]], lambda {|a|}.parameters) + assert_equal([[:opt, :a]], lambda {|a=nil|}.parameters) + assert_equal([[:req, :a]], ->(a){}.parameters) + assert_equal([[:rest]], lambda { |*| }.parameters) + assert_equal([[:rest, :a]], Proc.new {|*a|}.parameters) + assert_equal([[:opt, :a], [:opt, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:opt, :f], [:opt, :g], [:block, :h]], Proc.new {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters) + assert_equal([[:req, :a], [:req, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:req, :f], [:req, :g], [:block, :h]], lambda {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters) +end + +assert('Proc#to_proc') do + proc = Proc.new {} + assert_equal proc, proc.to_proc +end + +assert('Kernel#proc') do + assert_true !proc{|a|}.lambda? + + assert_raise LocalJumpError do + proc{ break }.call + end +end + +assert('mrb_proc_new_cfunc_with_env') do + ProcExtTest.mrb_proc_new_cfunc_with_env(:test) + ProcExtTest.mrb_proc_new_cfunc_with_env(:mruby) + + t = ProcExtTest.new + + assert_equal :test, t.test + assert_equal :mruby, t.mruby +end + +assert('mrb_cfunc_env_get') do + ProcExtTest.mrb_cfunc_env_get :get_int, [0, 1, 2] + + t = ProcExtTest.new + + assert_raise(TypeError) { t.cfunc_without_env } + + assert_raise(IndexError) { t.get_int(-1) } + assert_raise(IndexError) { t.get_int(3) } + + assert_equal 1, t.get_int(1) +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/mrbgem.rake new file mode 100644 index 000000000..3a3fd2bdb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-random') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Random class' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/mt19937ar.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/mt19937ar.c new file mode 100644 index 000000000..405bd5c20 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/mt19937ar.c @@ -0,0 +1,224 @@ +/* +** mt19937ar.c - MT Random functions +** +** Copyright (C) 1997 - 2016, Makoto Matsumoto and Takuji Nishimura, +** All rights reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] +** +** Any feedback is very welcome. +** http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html +** email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) +** +** This version is modified by mruby developers. If you see any problem, +** contact us first at https://github.com/mruby/mruby/issues +*/ + +#include <mruby.h> +#include "mt19937ar.h" + +/* Period parameters */ +/* #define N 624 */ +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +#if 0 /* dead_code */ +static unsigned long mt[N]; /* the array for the state vector */ +static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ +#endif /* dead_code */ + +void mrb_random_init_genrand(mt_state *t, unsigned long s) +{ + t->mt[0]= s & 0xffffffffUL; + for (t->mti=1; t->mti<N; t->mti++) { + t->mt[t->mti] = (1812433253UL * (t->mt[t->mti-1] ^ (t->mt[t->mti-1] >> 30)) + t->mti); + t->mt[t->mti] &= 0xffffffffUL; + } +} + +unsigned long mrb_random_genrand_int32(mt_state *t) +{ + unsigned long y; + static const unsigned long mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (t->mti >= N) { /* generate N words at one time */ + int kk; + + if (t->mti == N+1) /* if init_genrand() has not been called, */ + mrb_random_init_genrand(t, 5489UL); /* a default initial seed is used */ + + for (kk=0;kk<N-M;kk++) { + y = (t->mt[kk]&UPPER_MASK)|(t->mt[kk+1]&LOWER_MASK); + t->mt[kk] = t->mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + for (;kk<N-1;kk++) { + y = (t->mt[kk]&UPPER_MASK)|(t->mt[kk+1]&LOWER_MASK); + t->mt[kk] = t->mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + y = (t->mt[N-1]&UPPER_MASK)|(t->mt[0]&LOWER_MASK); + t->mt[N-1] = t->mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + t->mti = 0; + } + + y = t->mt[t->mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + t->gen.int_ = y; + + return y; +} + +double mrb_random_genrand_real1(mt_state *t) +{ + mrb_random_genrand_int32(t); + t->gen.double_ = t->gen.int_*(1.0/4294967295.0); + return t->gen.double_; + /* divided by 2^32-1 */ +} + +#if 0 /* dead_code */ +/* initializes mt[N] with a seed */ +void init_genrand(unsigned long s) +{ + mt[0]= s & 0xffffffffUL; + for (mti=1; mti<N; mti++) { + mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } +} + +/* initialize by an array with array-length */ +/* init_key is the array for initializing keys */ +/* key_length is its length */ +/* slight change for C++, 2004/2/26 */ +void init_by_array(unsigned long init_key[], int key_length) +{ + int i, j, k; + init_genrand(19650218UL); + i=1; j=0; + k = (N>key_length ? N : key_length); + for (; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + + init_key[j] + j; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; j++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + if (j>=key_length) j=0; + } + for (k=N-1; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) + - i; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + } + + mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ +} + +/* generates a random number on [0,0xffffffff]-interval */ +unsigned long genrand_int32(void) +{ + unsigned long y; + static const unsigned long mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (mti >= N) { /* generate N words at one time */ + int kk; + + if (mti == N+1) /* if init_genrand() has not been called, */ + init_genrand(5489UL); /* a default initial seed is used */ + + for (kk=0;kk<N-M;kk++) { + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); + mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + for (;kk<N-1;kk++) { + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); + mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + mti = 0; + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + +/* generates a random number on [0,0x7fffffff]-interval */ +long genrand_int31(void) +{ + return (long)(genrand_int32()>>1); +} + +/* generates a random number on [0,1]-real-interval */ +double genrand_real1(void) +{ + return genrand_int32()*(1.0/4294967295.0); + /* divided by 2^32-1 */ +} + +/* generates a random number on [0,1)-real-interval */ +double genrand_real2(void) +{ + return genrand_int32()*(1.0/4294967296.0); + /* divided by 2^32 */ +} + +/* generates a random number on (0,1)-real-interval */ +double genrand_real3(void) +{ + return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); + /* divided by 2^32 */ +} + +/* generates a random number on [0,1) with 53-bit resolution*/ +double genrand_res53(void) +{ + unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; + return(a*67108864.0+b)*(1.0/9007199254740992.0); +} +/* These real versions are due to Isaku Wada, 2002/01/09 added */ +#endif /* dead_code */ diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/mt19937ar.h b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/mt19937ar.h new file mode 100644 index 000000000..7d382320d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/mt19937ar.h @@ -0,0 +1,80 @@ +/* +** mt19937ar.h - MT Random functions +** +** Copyright (C) 1997 - 2016, Makoto Matsumoto and Takuji Nishimura, +** All rights reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] +** +** Any feedback is very welcome. +** http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html +** email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) +** +** This version is modified by mruby developers. If you see any problem, +** contact us first at https://github.com/mruby/mruby/issues +*/ + +#define N 624 + +typedef struct { + unsigned long mt[N]; + int mti; + union { + unsigned long int_; + double double_; + } gen; + + mrb_int seed; + mrb_bool has_seed : 1; +} mt_state; + +void mrb_random_init_genrand(mt_state *, unsigned long); +unsigned long mrb_random_genrand_int32(mt_state *); +double mrb_random_genrand_real1(mt_state *t); + +/* initializes mt[N] with a seed */ +void init_genrand(unsigned long s); + +/* initialize by an array with array-length */ +/* init_key is the array for initializing keys */ +/* key_length is its length */ +/* slight change for C++, 2004/2/26 */ +void init_by_array(unsigned long init_key[], int key_length); + +/* generates a random number on [0,0xffffffff]-interval */ +unsigned long genrand_int32(void); + +/* generates a random number on [0,0x7fffffff]-interval */ +long genrand_int31(void); + +/* These real versions are due to Isaku Wada, 2002/01/09 added */ +/* generates a random number on [0,1]-real-interval */ +double genrand_real1(void); + +/* generates a random number on [0,1)-real-interval */ +double genrand_real2(void); + +/* generates a random number on (0,1)-real-interval */ +double genrand_real3(void); + +/* generates a random number on [0,1) with 53-bit resolution*/ +double genrand_res53(void); diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/random.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/random.c new file mode 100644 index 000000000..b865244cc --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/random.c @@ -0,0 +1,349 @@ +/* +** random.c - Random module +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/variable.h> +#include <mruby/class.h> +#include <mruby/data.h> +#include <mruby/array.h> +#include "mt19937ar.h" + +#include <time.h> + +static char const MT_STATE_KEY[] = "$mrb_i_mt_state"; + +static const struct mrb_data_type mt_state_type = { + MT_STATE_KEY, mrb_free, +}; + +static mrb_value mrb_random_rand(mrb_state *mrb, mrb_value self); +static mrb_value mrb_random_srand(mrb_state *mrb, mrb_value self); + +static void +mt_srand(mt_state *t, unsigned long seed) +{ + mrb_random_init_genrand(t, seed); +} + +static unsigned long +mt_rand(mt_state *t) +{ + return mrb_random_genrand_int32(t); +} + +static double +mt_rand_real(mt_state *t) +{ + return mrb_random_genrand_real1(t); +} + +static mrb_value +mrb_random_mt_srand(mrb_state *mrb, mt_state *t, mrb_value seed) +{ + if (mrb_nil_p(seed)) { + seed = mrb_fixnum_value((mrb_int)(time(NULL) + mt_rand(t))); + if (mrb_fixnum(seed) < 0) { + seed = mrb_fixnum_value(0 - mrb_fixnum(seed)); + } + } + + mt_srand(t, (unsigned) mrb_fixnum(seed)); + + return seed; +} + +static mrb_value +mrb_random_mt_rand(mrb_state *mrb, mt_state *t, mrb_value max) +{ + mrb_value value; + + if (mrb_fixnum(max) == 0) { + value = mrb_float_value(mrb, mt_rand_real(t)); + } + else { + value = mrb_fixnum_value(mt_rand(t) % mrb_fixnum(max)); + } + + return value; +} + +static mrb_value +get_opt(mrb_state* mrb) +{ + mrb_value arg; + + arg = mrb_nil_value(); + mrb_get_args(mrb, "|o", &arg); + + if (!mrb_nil_p(arg)) { + arg = mrb_check_convert_type(mrb, arg, MRB_TT_FIXNUM, "Fixnum", "to_int"); + if (mrb_nil_p(arg)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument type"); + } + if (mrb_fixnum(arg) < 0) { + arg = mrb_fixnum_value(0 - mrb_fixnum(arg)); + } + } + return arg; +} + +static mrb_value +get_random(mrb_state *mrb) { + return mrb_const_get(mrb, + mrb_obj_value(mrb_class_get(mrb, "Random")), + mrb_intern_lit(mrb, "DEFAULT")); +} + +static mt_state * +get_random_state(mrb_state *mrb) +{ + mrb_value random_val = get_random(mrb); + return DATA_GET_PTR(mrb, random_val, &mt_state_type, mt_state); +} + +static mrb_value +mrb_random_g_rand(mrb_state *mrb, mrb_value self) +{ + mrb_value random = get_random(mrb); + return mrb_random_rand(mrb, random); +} + +static mrb_value +mrb_random_g_srand(mrb_state *mrb, mrb_value self) +{ + mrb_value random = get_random(mrb); + return mrb_random_srand(mrb, random); +} + +static mrb_value +mrb_random_init(mrb_state *mrb, mrb_value self) +{ + mrb_value seed; + mt_state *t; + + seed = get_opt(mrb); + + /* avoid memory leaks */ + t = (mt_state*)DATA_PTR(self); + if (t) { + mrb_free(mrb, t); + } + mrb_data_init(self, NULL, &mt_state_type); + + t = (mt_state *)mrb_malloc(mrb, sizeof(mt_state)); + t->mti = N + 1; + + seed = mrb_random_mt_srand(mrb, t, seed); + if (mrb_nil_p(seed)) { + t->has_seed = FALSE; + } + else { + mrb_assert(mrb_fixnum_p(seed)); + t->has_seed = TRUE; + t->seed = mrb_fixnum(seed); + } + + mrb_data_init(self, t, &mt_state_type); + + return self; +} + +static void +mrb_random_rand_seed(mrb_state *mrb, mt_state *t) +{ + if (!t->has_seed) { + mrb_random_mt_srand(mrb, t, mrb_nil_value()); + } +} + +static mrb_value +mrb_random_rand(mrb_state *mrb, mrb_value self) +{ + mrb_value max; + mt_state *t = DATA_GET_PTR(mrb, self, &mt_state_type, mt_state); + + max = get_opt(mrb); + mrb_random_rand_seed(mrb, t); + return mrb_random_mt_rand(mrb, t, max); +} + +static mrb_value +mrb_random_srand(mrb_state *mrb, mrb_value self) +{ + mrb_value seed; + mrb_value old_seed; + mt_state *t = DATA_GET_PTR(mrb, self, &mt_state_type, mt_state); + + seed = get_opt(mrb); + seed = mrb_random_mt_srand(mrb, t, seed); + old_seed = t->has_seed? mrb_fixnum_value(t->seed) : mrb_nil_value(); + if (mrb_nil_p(seed)) { + t->has_seed = FALSE; + } + else { + mrb_assert(mrb_fixnum_p(seed)); + t->has_seed = TRUE; + t->seed = mrb_fixnum(seed); + } + + return old_seed; +} + +/* + * call-seq: + * ary.shuffle! -> ary + * + * Shuffles elements in self in place. + */ + +static mrb_value +mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) +{ + mrb_int i; + mt_state *random = NULL; + + if (RARRAY_LEN(ary) > 1) { + mrb_get_args(mrb, "|d", &random, &mt_state_type); + + if (random == NULL) { + random = get_random_state(mrb); + } + mrb_random_rand_seed(mrb, random); + + mrb_ary_modify(mrb, mrb_ary_ptr(ary)); + + for (i = RARRAY_LEN(ary) - 1; i > 0; i--) { + mrb_int j; + mrb_value *ptr = RARRAY_PTR(ary); + mrb_value tmp; + + + j = mrb_fixnum(mrb_random_mt_rand(mrb, random, mrb_fixnum_value(RARRAY_LEN(ary)))); + + tmp = ptr[i]; + ptr[i] = ptr[j]; + ptr[j] = tmp; + } + } + + return ary; +} + +/* + * call-seq: + * ary.shuffle -> new_ary + * + * Returns a new array with elements of self shuffled. + */ + +static mrb_value +mrb_ary_shuffle(mrb_state *mrb, mrb_value ary) +{ + mrb_value new_ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary)); + mrb_ary_shuffle_bang(mrb, new_ary); + + return new_ary; +} + +/* + * call-seq: + * ary.sample -> obj + * ary.sample(n) -> new_ary + * + * Choose a random element or +n+ random elements from the array. + * + * The elements are chosen by using random and unique indices into the array + * in order to ensure that an element doesn't repeat itself unless the array + * already contained duplicate elements. + * + * If the array is empty the first form returns +nil+ and the second form + * returns an empty array. + */ + +static mrb_value +mrb_ary_sample(mrb_state *mrb, mrb_value ary) +{ + mrb_int n = 0; + mrb_bool given; + mt_state *random = NULL; + mrb_int len; + + mrb_get_args(mrb, "|i?d", &n, &given, &random, &mt_state_type); + if (random == NULL) { + random = get_random_state(mrb); + } + mrb_random_rand_seed(mrb, random); + mt_rand(random); + len = RARRAY_LEN(ary); + if (!given) { /* pick one element */ + switch (len) { + case 0: + return mrb_nil_value(); + case 1: + return RARRAY_PTR(ary)[0]; + default: + return RARRAY_PTR(ary)[mt_rand(random) % len]; + } + } + else { + mrb_value result; + mrb_int i, j; + + if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative sample number"); + if (n > len) n = len; + result = mrb_ary_new_capa(mrb, n); + for (i=0; i<n; i++) { + mrb_int r; + + for (;;) { + retry: + r = mt_rand(random) % len; + + for (j=0; j<i; j++) { + if (mrb_fixnum(RARRAY_PTR(result)[j]) == r) { + goto retry; /* retry if duplicate */ + } + } + break; + } + mrb_ary_push(mrb, result, mrb_fixnum_value(r)); + } + for (i=0; i<n; i++) { + mrb_ary_set(mrb, result, i, RARRAY_PTR(ary)[mrb_fixnum(RARRAY_PTR(result)[i])]); + } + return result; + } +} + + +void mrb_mruby_random_gem_init(mrb_state *mrb) +{ + struct RClass *random; + struct RClass *array = mrb->array_class; + + mrb_define_method(mrb, mrb->kernel_module, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, mrb->kernel_module, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1)); + + random = mrb_define_class(mrb, "Random", mrb->object_class); + MRB_SET_INSTANCE_TT(random, MRB_TT_DATA); + mrb_define_class_method(mrb, random, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, random, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1)); + + mrb_define_method(mrb, random, "initialize", mrb_random_init, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, random, "rand", mrb_random_rand, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, random, "srand", mrb_random_srand, MRB_ARGS_OPT(1)); + + mrb_define_method(mrb, array, "shuffle", mrb_ary_shuffle, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, array, "shuffle!", mrb_ary_shuffle_bang, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, array, "sample", mrb_ary_sample, MRB_ARGS_OPT(2)); + + mrb_const_set(mrb, mrb_obj_value(random), mrb_intern_lit(mrb, "DEFAULT"), + mrb_obj_new(mrb, random, 0, NULL)); +} + +void mrb_mruby_random_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/random.h b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/random.h new file mode 100644 index 000000000..a4785ae5a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/src/random.h @@ -0,0 +1,12 @@ +/* +** random.h - Random module +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_RANDOM_H +#define MRUBY_RANDOM_H + +void mrb_mruby_random_gem_init(mrb_state *mrb); + +#endif diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/test/random.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/test/random.rb new file mode 100644 index 000000000..1c59be3a6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-random/test/random.rb @@ -0,0 +1,88 @@ +## +# Random Test + +assert("Random#srand") do + r1 = Random.new(123) + r2 = Random.new(123) + r1.rand == r2.rand +end + +assert("Kernel::srand") do + srand(234) + r1 = rand + srand(234) + r2 = rand + r1 == r2 +end + +assert("Random::srand") do + Random.srand(345) + r1 = rand + srand(345) + r2 = Random.rand + r1 == r2 +end + +assert("fixnum") do + rand(3).class == Fixnum +end + +assert("float") do + rand.class == Float +end + +assert("Array#shuffle") do + ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + shuffled = ary.shuffle + + ary == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and shuffled != ary and 10.times { |x| ary.include? x } +end + +assert('Array#shuffle!') do + ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ary.shuffle! + + ary != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary.include? x } +end + +assert("Array#shuffle(random)") do + assert_raise(TypeError) do + # this will cause an exception due to the wrong argument + [1, 2].shuffle "Not a Random instance" + end + + # verify that the same seed causes the same results + ary1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + shuffle1 = ary1.shuffle Random.new 345 + ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + shuffle2 = ary2.shuffle Random.new 345 + + ary1 != shuffle1 and 10.times { |x| shuffle1.include? x } and shuffle1 == shuffle2 +end + +assert('Array#shuffle!(random)') do + assert_raise(TypeError) do + # this will cause an exception due to the wrong argument + [1, 2].shuffle! "Not a Random instance" + end + + # verify that the same seed causes the same results + ary1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ary1.shuffle! Random.new 345 + ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ary2.shuffle! Random.new 345 + + ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2 +end + +assert('Array#sample checks input length after reading arguments') do + $ary = [1, 2, 3] + class ArrayChange + def to_i + $ary << 4 + 4 + end + end + + assert_equal [1, 2, 3, 4], $ary.sample(ArrayChange.new).sort +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/mrbgem.rake new file mode 100644 index 000000000..e6fa7df5f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-range-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Range class extension' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/mrblib/range.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/mrblib/range.rb new file mode 100644 index 000000000..e5d1fb079 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/mrblib/range.rb @@ -0,0 +1,31 @@ +class Range + ## + # call-seq: + # rng.first -> obj + # rng.first(n) -> an_array + # + # Returns the first object in the range, or an array of the first +n+ + # elements. + # + # (10..20).first #=> 10 + # (10..20).first(3) #=> [10, 11, 12] + # + def first(*args) + return self.begin if args.empty? + + raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 1)" unless args.length == 1 + nv = args[0] + raise TypeError, "no implicit conversion from nil to integer" if nv.nil? + raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless nv.respond_to?(:to_int) + n = nv.to_int + raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless n.kind_of?(Integer) + raise ArgumentError, "negative array size (or size too big)" unless 0 <= n + ary = [] + each do |i| + break if n <= 0 + ary.push(i) + n -= 1 + end + ary + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/src/range.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/src/range.c new file mode 100644 index 000000000..aca71cc01 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/src/range.c @@ -0,0 +1,176 @@ +#include <mruby.h> +#include <mruby/range.h> +#include <math.h> + +static mrb_bool +r_le(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == -1) return TRUE; + } + + return FALSE; +} + +static mrb_bool +r_lt(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + return mrb_fixnum_p(r) && mrb_fixnum(r) == -1; +} + +/* + * call-seq: + * rng.cover?(obj) -> true or false + * + * Returns <code>true</code> if +obj+ is between the begin and end of + * the range. + * + * This tests <code>begin <= obj <= end</code> when #exclude_end? is +false+ + * and <code>begin <= obj < end</code> when #exclude_end? is +true+. + * + * ("a".."z").cover?("c") #=> true + * ("a".."z").cover?("5") #=> false + * ("a".."z").cover?("cc") #=> true + */ +static mrb_value +mrb_range_cover(mrb_state *mrb, mrb_value range) +{ + mrb_value val; + struct RRange *r = mrb_range_ptr(mrb, range); + mrb_value beg, end; + + mrb_get_args(mrb, "o", &val); + + beg = r->edges->beg; + end = r->edges->end; + + if (r_le(mrb, beg, val)) { + if (r->excl) { + if (r_lt(mrb, val, end)) + return mrb_true_value(); + } + else { + if (r_le(mrb, val, end)) + return mrb_true_value(); + } + } + + return mrb_false_value(); +} + +/* + * call-seq: + * rng.last -> obj + * rng.last(n) -> an_array + * + * Returns the last object in the range, + * or an array of the last +n+ elements. + * + * Note that with no arguments +last+ will return the object that defines + * the end of the range even if #exclude_end? is +true+. + * + * (10..20).last #=> 20 + * (10...20).last #=> 20 + * (10..20).last(3) #=> [18, 19, 20] + * (10...20).last(3) #=> [17, 18, 19] + */ +static mrb_value +mrb_range_last(mrb_state *mrb, mrb_value range) +{ + mrb_value num; + mrb_value array; + struct RRange *r = mrb_range_ptr(mrb, range); + + if (mrb_get_args(mrb, "|o", &num) == 0) { + return r->edges->end; + } + + array = mrb_funcall(mrb, range, "to_a", 0); + return mrb_funcall(mrb, array, "last", 1, mrb_to_int(mrb, num)); +} + +/* + * call-seq: + * rng.size -> num + * + * Returns the number of elements in the range. Both the begin and the end of + * the Range must be Numeric, otherwise nil is returned. + * + * (10..20).size #=> 11 + * ('a'..'z').size #=> nil + */ + +static mrb_value +mrb_range_size(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_ptr(mrb, range); + mrb_value beg, end; + mrb_float beg_f, end_f; + mrb_bool num_p = TRUE; + mrb_bool excl; + + beg = r->edges->beg; + end = r->edges->end; + excl = r->excl; + if (mrb_fixnum_p(beg)) { + beg_f = (mrb_float)mrb_fixnum(beg); + } + else if (mrb_float_p(beg)) { + beg_f = mrb_float(beg); + } + else { + num_p = FALSE; + } + if (mrb_fixnum_p(end)) { + end_f = (mrb_float)mrb_fixnum(end); + } + else if (mrb_float_p(end)) { + end_f = mrb_float(end); + } + else { + num_p = FALSE; + } + if (num_p) { + mrb_float n = end_f - beg_f; + mrb_float err = (fabs(beg_f) + fabs(end_f) + fabs(end_f-beg_f)) * MRB_FLOAT_EPSILON; + + if (err>0.5) err=0.5; + if (excl) { + if (n<=0) return mrb_fixnum_value(0); + if (n<1) + n = 0; + else + n = floor(n - err); + } + else { + if (n<0) return mrb_fixnum_value(0); + n = floor(n + err); + } + if (isinf(n+1)) + return mrb_float_value(mrb, INFINITY); + return mrb_fixnum_value((mrb_int)n+1); + } + return mrb_nil_value(); +} + +void +mrb_mruby_range_ext_gem_init(mrb_state* mrb) +{ + struct RClass * s = mrb_class_get(mrb, "Range"); + + mrb_define_method(mrb, s, "cover?", mrb_range_cover, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "last", mrb_range_last, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, s, "size", mrb_range_size, MRB_ARGS_NONE()); +} + +void +mrb_mruby_range_ext_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/test/range.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/test/range.rb new file mode 100644 index 000000000..efcbdabe4 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-range-ext/test/range.rb @@ -0,0 +1,32 @@ +## +# Range(Ext) Test + +assert('Range#cover?') do + assert_true ("a".."z").cover?("c") + assert_true !("a".."z").cover?("5") + assert_true ("a".."z").cover?("cc") +end + +assert('Range#first') do + assert_equal 10, (10..20).first + assert_equal [10, 11, 12], (10..20).first(3) + assert_equal [0, 1, 2], (0..Float::INFINITY).first(3) +end + +assert('Range#last') do + assert_equal 20, (10..20).last + assert_equal 20, (10...20).last + assert_equal [18, 19, 20], (10..20).last(3) + assert_equal [17, 18, 19], (10...20).last(3) +end + +assert('Range#size') do + assert_equal 42, (1..42).size + assert_equal 41, (1...42).size + assert_equal 6, (1...6.3).size + assert_equal 5, (1...6.0).size + assert_equal 5, (1.1...6).size + assert_equal 15, (1.0..15.9).size + assert_equal Float::INFINITY, (0..Float::INFINITY).size + assert_nil ('a'..'z').size +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/mrbgem.rake new file mode 100644 index 000000000..bc897243d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-sprintf') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'standard Kernel#sprintf method' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/mrblib/string.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/mrblib/string.rb new file mode 100644 index 000000000..d7e55536a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/mrblib/string.rb @@ -0,0 +1,9 @@ +class String + def %(args) + if args.is_a? Array + sprintf(self, *args) + else + sprintf(self, args) + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/src/kernel.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/src/kernel.c new file mode 100644 index 000000000..946b43a8a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/src/kernel.c @@ -0,0 +1,30 @@ +/* +** kernel.c - Kernel module suppliment +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> + +mrb_value mrb_f_sprintf(mrb_state *mrb, mrb_value obj); /* in sprintf.c */ + +void +mrb_mruby_sprintf_gem_init(mrb_state* mrb) +{ + struct RClass *krn; + + if (mrb->kernel_module == NULL) { + mrb->kernel_module = mrb_define_module(mrb, "Kernel"); /* Might be PARANOID. */ + } + krn = mrb->kernel_module; + + mrb_define_method(mrb, krn, "sprintf", mrb_f_sprintf, MRB_ARGS_ANY()); + mrb_define_method(mrb, krn, "format", mrb_f_sprintf, MRB_ARGS_ANY()); +} + +void +mrb_mruby_sprintf_gem_final(mrb_state* mrb) +{ + /* nothing to do. */ +} + diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/src/sprintf.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/src/sprintf.c new file mode 100644 index 000000000..d20699247 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/src/sprintf.c @@ -0,0 +1,1113 @@ +/* +** sprintf.c - Kernel.#sprintf +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> + +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <mruby/string.h> +#include <mruby/hash.h> +#include <mruby/numeric.h> +#include <math.h> +#include <ctype.h> + +#define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */ +#define BITSPERDIG MRB_INT_BIT +#define EXTENDSIGN(n, l) (((~0U << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0U << (n))) + +mrb_value mrb_str_format(mrb_state *, int, const mrb_value *, mrb_value); +static void fmt_setup(char*,size_t,int,int,mrb_int,mrb_int); + +static char* +remove_sign_bits(char *str, int base) +{ + char *t; + + t = str; + if (base == 16) { + while (*t == 'f') { + t++; + } + } + else if (base == 8) { + *t |= EXTENDSIGN(3, strlen(t)); + while (*t == '7') { + t++; + } + } + else if (base == 2) { + while (*t == '1') { + t++; + } + } + + return t; +} + +static char +sign_bits(int base, const char *p) +{ + char c; + + switch (base) { + case 16: + if (*p == 'X') c = 'F'; + else c = 'f'; + break; + case 8: + c = '7'; break; + case 2: + c = '1'; break; + default: + c = '.'; break; + } + return c; +} + +static mrb_value +mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base) +{ + char buf[66], *b = buf + sizeof buf; + mrb_int num = mrb_fixnum(x); + uint64_t val = (uint64_t)num; + char d; + + if (base != 2) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base)); + } + if (val == 0) { + return mrb_str_new_lit(mrb, "0"); + } + *--b = '\0'; + do { + *--b = mrb_digitmap[(int)(val % base)]; + } while (val /= base); + + if (num < 0) { + b = remove_sign_bits(b, base); + switch (base) { + case 16: d = 'f'; break; + case 8: d = '7'; break; + case 2: d = '1'; break; + default: d = 0; break; + } + + if (d && *b != d) { + *--b = d; + } + } + + return mrb_str_new_cstr(mrb, b); +} + +#define FNONE 0 +#define FSHARP 1 +#define FMINUS 2 +#define FPLUS 4 +#define FZERO 8 +#define FSPACE 16 +#define FWIDTH 32 +#define FPREC 64 +#define FPREC0 128 + +#define CHECK(l) do {\ +/* int cr = ENC_CODERANGE(result);*/\ + while ((l) >= bsiz - blen) {\ + bsiz*=2;\ + if (bsiz < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "too big specifier"); \ + }\ + mrb_str_resize(mrb, result, bsiz);\ +/* ENC_CODERANGE_SET(result, cr);*/\ + buf = RSTRING_PTR(result);\ +} while (0) + +#define PUSH(s, l) do { \ + CHECK(l);\ + memcpy(&buf[blen], s, l);\ + blen += (mrb_int)(l);\ +} while (0) + +#define FILL(c, l) do { \ + CHECK(l);\ + memset(&buf[blen], c, l);\ + blen += (l);\ +} while (0) + +static void +check_next_arg(mrb_state *mrb, int posarg, int nextarg) +{ + switch (posarg) { + case -1: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with numbered", mrb_fixnum_value(nextarg)); + break; + case -2: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with named", mrb_fixnum_value(nextarg)); + break; + default: + break; + } +} + +static void +check_pos_arg(mrb_state *mrb, int posarg, int n) +{ + if (posarg > 0) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after unnumbered(%S)", + mrb_fixnum_value(n), mrb_fixnum_value(posarg)); + } + if (posarg == -2) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after named", mrb_fixnum_value(n)); + } + if (n < 1) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid index - %S$", mrb_fixnum_value(n)); + } +} + +static void +check_name_arg(mrb_state *mrb, int posarg, const char *name, int len) +{ + if (posarg > 0) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after unnumbered(%S)", + mrb_str_new(mrb, (name), (len)), mrb_fixnum_value(posarg)); + } + if (posarg == -1) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after numbered", mrb_str_new(mrb, (name), (len))); + } +} + +#define GETNEXTARG() (\ + check_next_arg(mrb, posarg, nextarg),\ + (posarg = nextarg++, GETNTHARG(posarg))) + +#define GETARG() (!mrb_undef_p(nextvalue) ? nextvalue : GETNEXTARG()) + +#define GETPOSARG(n) (\ + check_pos_arg(mrb, posarg, n),\ + (posarg = -1, GETNTHARG(n))) + +#define GETNTHARG(nth) \ + ((nth >= argc) ? (mrb_raise(mrb, E_ARGUMENT_ERROR, "too few arguments"), mrb_undef_value()) : argv[nth]) + +#define GETNAMEARG(id, name, len) (\ + check_name_arg(mrb, posarg, name, len),\ + (posarg = -2, mrb_hash_fetch(mrb, get_hash(mrb, &hash, argc, argv), id, mrb_undef_value()))) + +#define GETNUM(n, val) \ + for (; p < end && ISDIGIT(*p); p++) {\ + int next_n = 10 * n + (*p - '0'); \ + if (next_n / 10 != n) {\ + mrb_raise(mrb, E_ARGUMENT_ERROR, #val " too big"); \ + } \ + n = next_n; \ + } \ + if (p >= end) { \ + mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed format string - %*[0-9]"); \ + } + +#define GETASTER(num) do { \ + mrb_value tmp_v; \ + t = p++; \ + n = 0; \ + GETNUM(n, val); \ + if (*p == '$') { \ + tmp_v = GETPOSARG(n); \ + } \ + else { \ + tmp_v = GETNEXTARG(); \ + p = t; \ + } \ + num = mrb_int(mrb, tmp_v); \ +} while (0) + +static mrb_value +get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv) +{ + mrb_value tmp; + + if (!mrb_undef_p(*hash)) return *hash; + if (argc != 2) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required"); + } + tmp = mrb_check_convert_type(mrb, argv[1], MRB_TT_HASH, "Hash", "to_hash"); + if (mrb_nil_p(tmp)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required"); + } + return (*hash = tmp); +} + +/* + * call-seq: + * format(format_string [, arguments...] ) -> string + * sprintf(format_string [, arguments...] ) -> string + * + * Returns the string resulting from applying <i>format_string</i> to + * any additional arguments. Within the format string, any characters + * other than format sequences are copied to the result. + * + * The syntax of a format sequence is follows. + * + * %[flags][width][.precision]type + * + * A format + * sequence consists of a percent sign, followed by optional flags, + * width, and precision indicators, then terminated with a field type + * character. The field type controls how the corresponding + * <code>sprintf</code> argument is to be interpreted, while the flags + * modify that interpretation. + * + * The field type characters are: + * + * Field | Integer Format + * ------+-------------------------------------------------------------- + * b | Convert argument as a binary number. + * | Negative numbers will be displayed as a two's complement + * | prefixed with '..1'. + * B | Equivalent to 'b', but uses an uppercase 0B for prefix + * | in the alternative format by #. + * d | Convert argument as a decimal number. + * i | Identical to 'd'. + * o | Convert argument as an octal number. + * | Negative numbers will be displayed as a two's complement + * | prefixed with '..7'. + * u | Identical to 'd'. + * x | Convert argument as a hexadecimal number. + * | Negative numbers will be displayed as a two's complement + * | prefixed with '..f' (representing an infinite string of + * | leading 'ff's). + * X | Equivalent to 'x', but uses uppercase letters. + * + * Field | Float Format + * ------+-------------------------------------------------------------- + * e | Convert floating point argument into exponential notation + * | with one digit before the decimal point as [-]d.dddddde[+-]dd. + * | The precision specifies the number of digits after the decimal + * | point (defaulting to six). + * E | Equivalent to 'e', but uses an uppercase E to indicate + * | the exponent. + * f | Convert floating point argument as [-]ddd.dddddd, + * | where the precision specifies the number of digits after + * | the decimal point. + * g | Convert a floating point number using exponential form + * | if the exponent is less than -4 or greater than or + * | equal to the precision, or in dd.dddd form otherwise. + * | The precision specifies the number of significant digits. + * G | Equivalent to 'g', but use an uppercase 'E' in exponent form. + * a | Convert floating point argument as [-]0xh.hhhhp[+-]dd, + * | which is consisted from optional sign, "0x", fraction part + * | as hexadecimal, "p", and exponential part as decimal. + * A | Equivalent to 'a', but use uppercase 'X' and 'P'. + * + * Field | Other Format + * ------+-------------------------------------------------------------- + * c | Argument is the numeric code for a single character or + * | a single character string itself. + * p | The valuing of argument.inspect. + * s | Argument is a string to be substituted. If the format + * | sequence contains a precision, at most that many characters + * | will be copied. + * % | A percent sign itself will be displayed. No argument taken. + * + * The flags modifies the behavior of the formats. + * The flag characters are: + * + * Flag | Applies to | Meaning + * ---------+---------------+----------------------------------------- + * space | bBdiouxX | Leave a space at the start of + * | aAeEfgG | non-negative numbers. + * | (numeric fmt) | For 'o', 'x', 'X', 'b' and 'B', use + * | | a minus sign with absolute value for + * | | negative values. + * ---------+---------------+----------------------------------------- + * (digit)$ | all | Specifies the absolute argument number + * | | for this field. Absolute and relative + * | | argument numbers cannot be mixed in a + * | | sprintf string. + * ---------+---------------+----------------------------------------- + * # | bBoxX | Use an alternative format. + * | aAeEfgG | For the conversions 'o', increase the precision + * | | until the first digit will be '0' if + * | | it is not formatted as complements. + * | | For the conversions 'x', 'X', 'b' and 'B' + * | | on non-zero, prefix the result with "0x", + * | | "0X", "0b" and "0B", respectively. + * | | For 'a', 'A', 'e', 'E', 'f', 'g', and 'G', + * | | force a decimal point to be added, + * | | even if no digits follow. + * | | For 'g' and 'G', do not remove trailing zeros. + * ---------+---------------+----------------------------------------- + * + | bBdiouxX | Add a leading plus sign to non-negative + * | aAeEfgG | numbers. + * | (numeric fmt) | For 'o', 'x', 'X', 'b' and 'B', use + * | | a minus sign with absolute value for + * | | negative values. + * ---------+---------------+----------------------------------------- + * - | all | Left-justify the result of this conversion. + * ---------+---------------+----------------------------------------- + * 0 (zero) | bBdiouxX | Pad with zeros, not spaces. + * | aAeEfgG | For 'o', 'x', 'X', 'b' and 'B', radix-1 + * | (numeric fmt) | is used for negative numbers formatted as + * | | complements. + * ---------+---------------+----------------------------------------- + * * | all | Use the next argument as the field width. + * | | If negative, left-justify the result. If the + * | | asterisk is followed by a number and a dollar + * | | sign, use the indicated argument as the width. + * + * Examples of flags: + * + * # '+' and space flag specifies the sign of non-negative numbers. + * sprintf("%d", 123) #=> "123" + * sprintf("%+d", 123) #=> "+123" + * sprintf("% d", 123) #=> " 123" + * + * # '#' flag for 'o' increases number of digits to show '0'. + * # '+' and space flag changes format of negative numbers. + * sprintf("%o", 123) #=> "173" + * sprintf("%#o", 123) #=> "0173" + * sprintf("%+o", -123) #=> "-173" + * sprintf("%o", -123) #=> "..7605" + * sprintf("%#o", -123) #=> "..7605" + * + * # '#' flag for 'x' add a prefix '0x' for non-zero numbers. + * # '+' and space flag disables complements for negative numbers. + * sprintf("%x", 123) #=> "7b" + * sprintf("%#x", 123) #=> "0x7b" + * sprintf("%+x", -123) #=> "-7b" + * sprintf("%x", -123) #=> "..f85" + * sprintf("%#x", -123) #=> "0x..f85" + * sprintf("%#x", 0) #=> "0" + * + * # '#' for 'X' uses the prefix '0X'. + * sprintf("%X", 123) #=> "7B" + * sprintf("%#X", 123) #=> "0X7B" + * + * # '#' flag for 'b' add a prefix '0b' for non-zero numbers. + * # '+' and space flag disables complements for negative numbers. + * sprintf("%b", 123) #=> "1111011" + * sprintf("%#b", 123) #=> "0b1111011" + * sprintf("%+b", -123) #=> "-1111011" + * sprintf("%b", -123) #=> "..10000101" + * sprintf("%#b", -123) #=> "0b..10000101" + * sprintf("%#b", 0) #=> "0" + * + * # '#' for 'B' uses the prefix '0B'. + * sprintf("%B", 123) #=> "1111011" + * sprintf("%#B", 123) #=> "0B1111011" + * + * # '#' for 'e' forces to show the decimal point. + * sprintf("%.0e", 1) #=> "1e+00" + * sprintf("%#.0e", 1) #=> "1.e+00" + * + * # '#' for 'f' forces to show the decimal point. + * sprintf("%.0f", 1234) #=> "1234" + * sprintf("%#.0f", 1234) #=> "1234." + * + * # '#' for 'g' forces to show the decimal point. + * # It also disables stripping lowest zeros. + * sprintf("%g", 123.4) #=> "123.4" + * sprintf("%#g", 123.4) #=> "123.400" + * sprintf("%g", 123456) #=> "123456" + * sprintf("%#g", 123456) #=> "123456." + * + * The field width is an optional integer, followed optionally by a + * period and a precision. The width specifies the minimum number of + * characters that will be written to the result for this field. + * + * Examples of width: + * + * # padding is done by spaces, width=20 + * # 0 or radix-1. <------------------> + * sprintf("%20d", 123) #=> " 123" + * sprintf("%+20d", 123) #=> " +123" + * sprintf("%020d", 123) #=> "00000000000000000123" + * sprintf("%+020d", 123) #=> "+0000000000000000123" + * sprintf("% 020d", 123) #=> " 0000000000000000123" + * sprintf("%-20d", 123) #=> "123 " + * sprintf("%-+20d", 123) #=> "+123 " + * sprintf("%- 20d", 123) #=> " 123 " + * sprintf("%020x", -123) #=> "..ffffffffffffffff85" + * + * For + * numeric fields, the precision controls the number of decimal places + * displayed. For string fields, the precision determines the maximum + * number of characters to be copied from the string. (Thus, the format + * sequence <code>%10.10s</code> will always contribute exactly ten + * characters to the result.) + * + * Examples of precisions: + * + * # precision for 'd', 'o', 'x' and 'b' is + * # minimum number of digits <------> + * sprintf("%20.8d", 123) #=> " 00000123" + * sprintf("%20.8o", 123) #=> " 00000173" + * sprintf("%20.8x", 123) #=> " 0000007b" + * sprintf("%20.8b", 123) #=> " 01111011" + * sprintf("%20.8d", -123) #=> " -00000123" + * sprintf("%20.8o", -123) #=> " ..777605" + * sprintf("%20.8x", -123) #=> " ..ffff85" + * sprintf("%20.8b", -11) #=> " ..110101" + * + * # "0x" and "0b" for '#x' and '#b' is not counted for + * # precision but "0" for '#o' is counted. <------> + * sprintf("%#20.8d", 123) #=> " 00000123" + * sprintf("%#20.8o", 123) #=> " 00000173" + * sprintf("%#20.8x", 123) #=> " 0x0000007b" + * sprintf("%#20.8b", 123) #=> " 0b01111011" + * sprintf("%#20.8d", -123) #=> " -00000123" + * sprintf("%#20.8o", -123) #=> " ..777605" + * sprintf("%#20.8x", -123) #=> " 0x..ffff85" + * sprintf("%#20.8b", -11) #=> " 0b..110101" + * + * # precision for 'e' is number of + * # digits after the decimal point <------> + * sprintf("%20.8e", 1234.56789) #=> " 1.23456789e+03" + * + * # precision for 'f' is number of + * # digits after the decimal point <------> + * sprintf("%20.8f", 1234.56789) #=> " 1234.56789000" + * + * # precision for 'g' is number of + * # significant digits <-------> + * sprintf("%20.8g", 1234.56789) #=> " 1234.5679" + * + * # <-------> + * sprintf("%20.8g", 123456789) #=> " 1.2345679e+08" + * + * # precision for 's' is + * # maximum number of characters <------> + * sprintf("%20.8s", "string test") #=> " string t" + * + * Examples: + * + * sprintf("%d %04x", 123, 123) #=> "123 007b" + * sprintf("%08b '%4s'", 123, 123) #=> "01111011 ' 123'" + * sprintf("%1$*2$s %2$d %1$s", "hello", 8) #=> " hello 8 hello" + * sprintf("%1$*2$s %2$d", "hello", -8) #=> "hello -8" + * sprintf("%+g:% g:%-g", 1.23, 1.23, 1.23) #=> "+1.23: 1.23:1.23" + * sprintf("%u", -123) #=> "-123" + * + * For more complex formatting, Ruby supports a reference by name. + * %<name>s style uses format style, but %{name} style doesn't. + * + * Exapmles: + * sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 }) + * #=> 1 : 2.000000 + * sprintf("%{foo}f", { :foo => 1 }) + * # => "1f" + */ + +mrb_value +mrb_f_sprintf(mrb_state *mrb, mrb_value obj) +{ + mrb_int argc; + mrb_value *argv; + + mrb_get_args(mrb, "*", &argv, &argc); + + if (argc <= 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too few arguments"); + return mrb_nil_value(); + } + else { + return mrb_str_format(mrb, argc - 1, argv + 1, argv[0]); + } +} + +mrb_value +mrb_str_format(mrb_state *mrb, int argc, const mrb_value *argv, mrb_value fmt) +{ + const char *p, *end; + char *buf; + mrb_int blen; + mrb_int bsiz; + mrb_value result; + mrb_int n; + mrb_int width; + mrb_int prec; + int nextarg = 1; + int posarg = 0; + mrb_value nextvalue; + mrb_value str; + mrb_value hash = mrb_undef_value(); + +#define CHECK_FOR_WIDTH(f) \ + if ((f) & FWIDTH) { \ + mrb_raise(mrb, E_ARGUMENT_ERROR, "width given twice"); \ + } \ + if ((f) & FPREC0) { \ + mrb_raise(mrb, E_ARGUMENT_ERROR, "width after precision"); \ + } +#define CHECK_FOR_FLAGS(f) \ + if ((f) & FWIDTH) { \ + mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after width"); \ + } \ + if ((f) & FPREC0) { \ + mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after precision"); \ + } + + ++argc; + --argv; + fmt = mrb_str_to_str(mrb, fmt); + p = RSTRING_PTR(fmt); + end = p + RSTRING_LEN(fmt); + blen = 0; + bsiz = 120; + result = mrb_str_new_capa(mrb, bsiz); + buf = RSTRING_PTR(result); + memset(buf, 0, bsiz); + + for (; p < end; p++) { + const char *t; + mrb_sym id = 0; + int flags = FNONE; + + for (t = p; t < end && *t != '%'; t++) ; + if (t + 1 == end) ++t; + PUSH(p, t - p); + if (t >= end) + goto sprint_exit; /* end of fmt string */ + + p = t + 1; /* skip '%' */ + + width = prec = -1; + nextvalue = mrb_undef_value(); + +retry: + switch (*p) { + default: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - \\%%S", mrb_str_new(mrb, p, 1)); + break; + + case ' ': + CHECK_FOR_FLAGS(flags); + flags |= FSPACE; + p++; + goto retry; + + case '#': + CHECK_FOR_FLAGS(flags); + flags |= FSHARP; + p++; + goto retry; + + case '+': + CHECK_FOR_FLAGS(flags); + flags |= FPLUS; + p++; + goto retry; + + case '-': + CHECK_FOR_FLAGS(flags); + flags |= FMINUS; + p++; + goto retry; + + case '0': + CHECK_FOR_FLAGS(flags); + flags |= FZERO; + p++; + goto retry; + + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + GETNUM(n, width); + if (*p == '$') { + if (!mrb_undef_p(nextvalue)) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "value given twice - %S$", mrb_fixnum_value(n)); + } + nextvalue = GETPOSARG(n); + p++; + goto retry; + } + CHECK_FOR_WIDTH(flags); + width = n; + flags |= FWIDTH; + goto retry; + + case '<': + case '{': { + const char *start = p; + char term = (*p == '<') ? '>' : '}'; + mrb_value symname; + + for (; p < end && *p != term; ) + p++; + if (id) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "name%S after <%S>", + mrb_str_new(mrb, start, p - start + 1), mrb_sym2str(mrb, id)); + } + symname = mrb_str_new(mrb, start + 1, p - start - 1); + id = mrb_intern_str(mrb, symname); + nextvalue = GETNAMEARG(mrb_symbol_value(id), start, (int)(p - start + 1)); + if (mrb_undef_p(nextvalue)) { + mrb_raisef(mrb, E_KEY_ERROR, "key%S not found", mrb_str_new(mrb, start, p - start + 1)); + } + if (term == '}') goto format_s; + p++; + goto retry; + } + + case '*': + CHECK_FOR_WIDTH(flags); + flags |= FWIDTH; + GETASTER(width); + if (width < 0) { + flags |= FMINUS; + width = -width; + } + p++; + goto retry; + + case '.': + if (flags & FPREC0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "precision given twice"); + } + flags |= FPREC|FPREC0; + + prec = 0; + p++; + if (*p == '*') { + GETASTER(prec); + if (prec < 0) { /* ignore negative precision */ + flags &= ~FPREC; + } + p++; + goto retry; + } + + GETNUM(prec, precision); + goto retry; + + case '\n': + case '\0': + p--; + /* fallthrough */ + case '%': + if (flags != FNONE) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format character - %"); + } + PUSH("%", 1); + break; + + case 'c': { + mrb_value val = GETARG(); + mrb_value tmp; + char *c; + + tmp = mrb_check_string_type(mrb, val); + if (!mrb_nil_p(tmp)) { + if (RSTRING_LEN(tmp) != 1) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "%c requires a character"); + } + } + else if (mrb_fixnum_p(val)) { + mrb_int n = mrb_fixnum(val); + + if (n < 0x80) { + char buf[1]; + + buf[0] = (char)n; + tmp = mrb_str_new(mrb, buf, 1); + } + else { + tmp = mrb_funcall(mrb, val, "chr", 0); + mrb_check_type(mrb, tmp, MRB_TT_STRING); + } + } + else { + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character"); + } + c = RSTRING_PTR(tmp); + n = RSTRING_LEN(tmp); + if (!(flags & FWIDTH)) { + PUSH(c, n); + } + else if ((flags & FMINUS)) { + PUSH(c, n); + if (width>0) FILL(' ', width-1); + } + else { + if (width>0) FILL(' ', width-1); + PUSH(c, n); + } + } + break; + + case 's': + case 'p': + format_s: + { + mrb_value arg = GETARG(); + mrb_int len; + mrb_int slen; + + if (*p == 'p') arg = mrb_inspect(mrb, arg); + str = mrb_obj_as_string(mrb, arg); + len = RSTRING_LEN(str); + if (RSTRING(result)->flags & MRB_STR_EMBED) { + mrb_int tmp_n = len; + RSTRING(result)->flags &= ~MRB_STR_EMBED_LEN_MASK; + RSTRING(result)->flags |= tmp_n << MRB_STR_EMBED_LEN_SHIFT; + } + else { + RSTRING(result)->as.heap.len = blen; + } + if (flags&(FPREC|FWIDTH)) { + slen = RSTRING_LEN(str); + if (slen < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid mbstring sequence"); + } + if ((flags&FPREC) && (prec < slen)) { + char *p = RSTRING_PTR(str) + prec; + slen = prec; + len = (mrb_int)(p - RSTRING_PTR(str)); + } + /* need to adjust multi-byte string pos */ + if ((flags&FWIDTH) && (width > slen)) { + width -= (int)slen; + if (!(flags&FMINUS)) { + FILL(' ', width); + } + PUSH(RSTRING_PTR(str), len); + if (flags&FMINUS) { + FILL(' ', width); + } + break; + } + } + PUSH(RSTRING_PTR(str), len); + } + break; + + case 'd': + case 'i': + case 'o': + case 'x': + case 'X': + case 'b': + case 'B': + case 'u': { + mrb_value val = GETARG(); + char nbuf[68], *s; + const char *prefix = NULL; + int sign = 0, dots = 0; + char sc = 0; + mrb_int v = 0; + int base; + mrb_int len; + + if (flags & FSHARP) { + switch (*p) { + case 'o': prefix = "0"; break; + case 'x': prefix = "0x"; break; + case 'X': prefix = "0X"; break; + case 'b': prefix = "0b"; break; + case 'B': prefix = "0B"; break; + default: break; + } + } + + bin_retry: + switch (mrb_type(val)) { + case MRB_TT_FLOAT: + val = mrb_flo_to_fixnum(mrb, val); + if (mrb_fixnum_p(val)) goto bin_retry; + break; + case MRB_TT_STRING: + val = mrb_str_to_inum(mrb, val, 0, TRUE); + goto bin_retry; + case MRB_TT_FIXNUM: + v = mrb_fixnum(val); + break; + default: + val = mrb_Integer(mrb, val); + goto bin_retry; + } + + switch (*p) { + case 'o': + base = 8; break; + case 'x': + case 'X': + base = 16; break; + case 'b': + case 'B': + base = 2; break; + case 'u': + case 'd': + case 'i': + sign = 1; + default: + base = 10; break; + } + + if (sign) { + if (v >= 0) { + if (flags & FPLUS) { + sc = '+'; + width--; + } + else if (flags & FSPACE) { + sc = ' '; + width--; + } + } + else { + sc = '-'; + width--; + } + mrb_assert(base == 10); + snprintf(nbuf, sizeof(nbuf), "%" MRB_PRId, v); + s = nbuf; + if (v < 0) s++; /* skip minus sign */ + } + else { + s = nbuf; + if (v < 0) { + dots = 1; + } + switch (base) { + case 2: + if (v < 0) { + val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base); + } + else { + val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base); + } + strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-1); + break; + case 8: + snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIo, v); + break; + case 16: + snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIx, v); + break; + } + if (v < 0) { + char d; + + s = remove_sign_bits(s, base); + switch (base) { + case 16: d = 'f'; break; + case 8: d = '7'; break; + case 2: d = '1'; break; + default: d = 0; break; + } + + if (d && *s != d) { + *--s = d; + } + } + } + { + size_t size; + size = strlen(s); + /* PARANOID: assert(size <= MRB_INT_MAX) */ + len = (mrb_int)size; + } + + if (*p == 'X') { + char *pp = s; + int c; + while ((c = (int)(unsigned char)*pp) != 0) { + *pp = toupper(c); + pp++; + } + } + + if (prefix && !prefix[1]) { /* octal */ + if (dots) { + prefix = NULL; + } + else if (len == 1 && *s == '0') { + len = 0; + if (flags & FPREC) prec--; + } + else if ((flags & FPREC) && (prec > len)) { + prefix = NULL; + } + } + else if (len == 1 && *s == '0') { + prefix = NULL; + } + + if (prefix) { + size_t size; + size = strlen(prefix); + /* PARANOID: assert(size <= MRB_INT_MAX). + * this check is absolutely paranoid. */ + width -= (mrb_int)size; + } + + if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) { + prec = width; + width = 0; + } + else { + if (prec < len) { + if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0; + prec = len; + } + width -= prec; + } + + if (!(flags&FMINUS) && width > 0) { + FILL(' ', width); + width = 0; + } + + if (sc) PUSH(&sc, 1); + + if (prefix) { + int plen = (int)strlen(prefix); + PUSH(prefix, plen); + } + if (dots) { + prec -= 2; + width -= 2; + PUSH("..", 2); + } + + if (prec > len) { + CHECK(prec - len); + if ((flags & (FMINUS|FPREC)) != FMINUS) { + char c = '0'; + FILL(c, prec - len); + } else if (v < 0) { + char c = sign_bits(base, p); + FILL(c, prec - len); + } + } + PUSH(s, len); + if (width > 0) { + FILL(' ', width); + } + } + break; + + case 'f': + case 'g': + case 'G': + case 'e': + case 'E': + case 'a': + case 'A': { + mrb_value val = GETARG(); + double fval; + int i, need = 6; + char fbuf[32]; + + fval = mrb_float(mrb_Float(mrb, val)); + if (!isfinite(fval)) { + const char *expr; + const int elen = 3; + char sign = '\0'; + + if (isnan(fval)) { + expr = "NaN"; + } + else { + expr = "Inf"; + } + need = elen; + if (!isnan(fval) && fval < 0.0) + sign = '-'; + else if (flags & (FPLUS|FSPACE)) + sign = (flags & FPLUS) ? '+' : ' '; + if (sign) + ++need; + if ((flags & FWIDTH) && need < width) + need = width; + + if (need < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "width too big"); + } + FILL(' ', need); + if (flags & FMINUS) { + if (sign) + buf[blen - need--] = sign; + memcpy(&buf[blen - need], expr, elen); + } + else { + if (sign) + buf[blen - elen - 1] = sign; + memcpy(&buf[blen - elen], expr, elen); + } + break; + } + + fmt_setup(fbuf, sizeof(fbuf), *p, flags, width, prec); + need = 0; + if (*p != 'e' && *p != 'E') { + i = INT_MIN; + frexp(fval, &i); + if (i > 0) + need = BIT_DIGITS(i); + } + need += (flags&FPREC) ? prec : 6; + if ((flags&FWIDTH) && need < width) + need = width; + need += 20; + if (need <= 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, + (width > prec ? "width too big" : "prec too big")); + } + + CHECK(need); + n = snprintf(&buf[blen], need, fbuf, fval); + if (n < 0) { + mrb_raise(mrb, E_RUNTIME_ERROR, "formatting error"); + } + blen += n; + } + break; + } + flags = FNONE; + } + + sprint_exit: +#if 0 + /* XXX - We cannot validate the number of arguments if (digit)$ style used. + */ + if (posarg >= 0 && nextarg < argc) { + const char *mesg = "too many arguments for format string"; + if (mrb_test(ruby_debug)) mrb_raise(mrb, E_ARGUMENT_ERROR, mesg); + if (mrb_test(ruby_verbose)) mrb_warn(mrb, "%S", mrb_str_new_cstr(mrb, mesg)); + } +#endif + mrb_str_resize(mrb, result, blen); + + return result; +} + +static void +fmt_setup(char *buf, size_t size, int c, int flags, mrb_int width, mrb_int prec) +{ + char *end = buf + size; + int n; + + *buf++ = '%'; + if (flags & FSHARP) *buf++ = '#'; + if (flags & FPLUS) *buf++ = '+'; + if (flags & FMINUS) *buf++ = '-'; + if (flags & FZERO) *buf++ = '0'; + if (flags & FSPACE) *buf++ = ' '; + + if (flags & FWIDTH) { + n = snprintf(buf, end - buf, "%d", (int)width); + buf += n; + } + + if (flags & FPREC) { + n = snprintf(buf, end - buf, ".%d", (int)prec); + buf += n; + } + + *buf++ = c; + *buf = '\0'; +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/test/sprintf.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/test/sprintf.rb new file mode 100644 index 000000000..e3b66ef9c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-sprintf/test/sprintf.rb @@ -0,0 +1,109 @@ +#assert('Kernel.sprintf') do +#end + +assert('String#%') do + assert_equal "one=1", "one=%d" % 1 + assert_equal "1 one 1.0", "%d %s %3.1f" % [ 1, "one", 1.01 ] + assert_equal "123 < 456", "%{num} < %<str>s" % { num: 123, str: "456" } + assert_equal 15, ("%b" % (1<<14)).size +end + +assert('String#% with inf') do + inf = Float::INFINITY + + assert_equal "Inf", "%f" % inf + assert_equal "Inf", "%2f" % inf + assert_equal "Inf", "%3f" % inf + assert_equal " Inf", "%4f" % inf + assert_equal " Inf", "%5f" % inf + + assert_equal "+Inf", "%+f" % inf + assert_equal "+Inf", "%+2f" % inf + assert_equal "+Inf", "%+3f" % inf + assert_equal "+Inf", "%+4f" % inf + assert_equal " +Inf", "%+5f" % inf + + assert_equal "Inf", "%-f" % inf + assert_equal "Inf", "%-2f" % inf + assert_equal "Inf", "%-3f" % inf + assert_equal "Inf ", "%-4f" % inf + assert_equal "Inf ", "%-5f" % inf + + assert_equal " Inf", "% f" % inf + assert_equal " Inf", "% 2f" % inf + assert_equal " Inf", "% 3f" % inf + assert_equal " Inf", "% 4f" % inf + assert_equal " Inf", "% 5f" % inf +end + +assert('String#% with nan') do + nan = Float::NAN + + assert_equal "NaN", "%f" % nan + assert_equal "NaN", "%2f" % nan + assert_equal "NaN", "%3f" % nan + assert_equal " NaN", "%4f" % nan + assert_equal " NaN", "%5f" % nan + + assert_equal "+NaN", "%+f" % nan + assert_equal "+NaN", "%+2f" % nan + assert_equal "+NaN", "%+3f" % nan + assert_equal "+NaN", "%+4f" % nan + assert_equal " +NaN", "%+5f" % nan + + assert_equal "NaN", "%-f" % nan + assert_equal "NaN", "%-2f" % nan + assert_equal "NaN", "%-3f" % nan + assert_equal "NaN ", "%-4f" % nan + assert_equal "NaN ", "%-5f" % nan + + assert_equal " NaN", "% f" % nan + assert_equal " NaN", "% 2f" % nan + assert_equal " NaN", "% 3f" % nan + assert_equal " NaN", "% 4f" % nan + assert_equal " NaN", "% 5f" % nan +end + +assert("String#% with invalid chr") do + begin + class Fixnum + alias_method :chr_, :chr if method_defined?(:chr) + + def chr + nil + end + end + + assert_raise TypeError do + "%c" % 0x80 + end + ensure + class Fixnum + if method_defined?(:chr_) + alias_method :chr, :chr_ + remove_method :chr_ + end + end + end +end + +assert("String#% %b") do + assert_equal("..10115", "%0b5" % -5) +end + +assert("String#% %d") do + assert_equal(" 10", "%4d" % 10) + assert_equal("1000", "%4d" % 1000) + assert_equal("10000", "%4d" % 10000) +end + +assert("String#% invalid format") do + assert_raise ArgumentError do + "%?" % "" + end +end + +assert("String#% invalid format shared substring") do + fmt = ("x"*30+"%!")[0...-1] + assert_equal fmt, sprintf(fmt, "") +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/mrbgem.rake new file mode 100644 index 000000000..9812f2cc9 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/mrbgem.rake @@ -0,0 +1,6 @@ +MRuby::Gem::Specification.new('mruby-string-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'String class extension' + spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/mrblib/string.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/mrblib/string.rb new file mode 100644 index 000000000..c3a7eb380 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/mrblib/string.rb @@ -0,0 +1,355 @@ +class String + + ## + # call-seq: + # String.try_convert(obj) -> string or nil + # + # Try to convert <i>obj</i> into a String, using to_str method. + # Returns converted string or nil if <i>obj</i> cannot be converted + # for any reason. + # + # String.try_convert("str") #=> "str" + # String.try_convert(/re/) #=> nil + # + def self.try_convert(obj) + if obj.respond_to?(:to_str) + obj.to_str + else + nil + end + end + + ## + # call-seq: + # string.clear -> string + # + # Makes string empty. + # + # a = "abcde" + # a.clear #=> "" + # + def clear + self.replace("") + end + + ## + # call-seq: + # str.lstrip -> new_str + # + # Returns a copy of <i>str</i> with leading whitespace removed. See also + # <code>String#rstrip</code> and <code>String#strip</code>. + # + # " hello ".lstrip #=> "hello " + # "hello".lstrip #=> "hello" + # + def lstrip + a = 0 + z = self.size - 1 + a += 1 while a <= z and " \f\n\r\t\v".include?(self[a]) + (z >= 0) ? self[a..z] : "" + end + + ## + # call-seq: + # str.rstrip -> new_str + # + # Returns a copy of <i>str</i> with trailing whitespace removed. See also + # <code>String#lstrip</code> and <code>String#strip</code>. + # + # " hello ".rstrip #=> " hello" + # "hello".rstrip #=> "hello" + # + def rstrip + a = 0 + z = self.size - 1 + z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z]) + (z >= 0) ? self[a..z] : "" + end + + ## + # call-seq: + # str.strip -> new_str + # + # Returns a copy of <i>str</i> with leading and trailing whitespace removed. + # + # " hello ".strip #=> "hello" + # "\tgoodbye\r\n".strip #=> "goodbye" + # + def strip + a = 0 + z = self.size - 1 + a += 1 while a <= z and " \f\n\r\t\v".include?(self[a]) + z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z]) + (z >= 0) ? self[a..z] : "" + end + + ## + # call-seq: + # str.lstrip! -> self or nil + # + # Removes leading whitespace from <i>str</i>, returning <code>nil</code> if no + # change was made. See also <code>String#rstrip!</code> and + # <code>String#strip!</code>. + # + # " hello ".lstrip #=> "hello " + # "hello".lstrip! #=> nil + # + def lstrip! + raise RuntimeError, "can't modify frozen String" if frozen? + s = self.lstrip + (s == self) ? nil : self.replace(s) + end + + ## + # call-seq: + # str.rstrip! -> self or nil + # + # Removes trailing whitespace from <i>str</i>, returning <code>nil</code> if + # no change was made. See also <code>String#lstrip!</code> and + # <code>String#strip!</code>. + # + # " hello ".rstrip #=> " hello" + # "hello".rstrip! #=> nil + # + def rstrip! + raise RuntimeError, "can't modify frozen String" if frozen? + s = self.rstrip + (s == self) ? nil : self.replace(s) + end + + ## + # call-seq: + # str.strip! -> str or nil + # + # Removes leading and trailing whitespace from <i>str</i>. Returns + # <code>nil</code> if <i>str</i> was not altered. + # + def strip! + raise RuntimeError, "can't modify frozen String" if frozen? + s = self.strip + (s == self) ? nil : self.replace(s) + end + + ## + # call-seq: + # str.casecmp(other_str) -> -1, 0, +1 or nil + # + # Case-insensitive version of <code>String#<=></code>. + # + # "abcdef".casecmp("abcde") #=> 1 + # "aBcDeF".casecmp("abcdef") #=> 0 + # "abcdef".casecmp("abcdefg") #=> -1 + # "abcdef".casecmp("ABCDEF") #=> 0 + # + def casecmp(str) + self.downcase <=> str.to_str.downcase + rescue NoMethodError + raise TypeError, "no implicit conversion of #{str.class} into String" + end + + def partition(sep) + raise TypeError, "type mismatch: #{sep.class} given" unless sep.is_a? String + n = index(sep) + unless n.nil? + m = n + sep.size + [ slice(0, n), sep, slice(m, size - m) ] + else + [ self, "", "" ] + end + end + + def rpartition(sep) + raise TypeError, "type mismatch: #{sep.class} given" unless sep.is_a? String + n = rindex(sep) + unless n.nil? + m = n + sep.size + [ slice(0, n), sep, slice(m, size - m) ] + else + [ "", "", self ] + end + end + + ## + # call-seq: + # str.slice!(fixnum) -> new_str or nil + # str.slice!(fixnum, fixnum) -> new_str or nil + # str.slice!(range) -> new_str or nil + # str.slice!(other_str) -> new_str or nil + # + # Deletes the specified portion from <i>str</i>, and returns the portion + # deleted. + # + # string = "this is a string" + # string.slice!(2) #=> "i" + # string.slice!(3..6) #=> " is " + # string.slice!("r") #=> "r" + # string #=> "thsa sting" + # + def slice!(arg1, arg2=nil) + raise RuntimeError, "can't modify frozen String" if frozen? + raise "wrong number of arguments (for 1..2)" if arg1.nil? && arg2.nil? + + if !arg1.nil? && !arg2.nil? + idx = arg1 + idx += self.size if arg1 < 0 + if idx >= 0 && idx <= self.size && arg2 > 0 + str = self[idx, arg2] + else + return nil + end + else + validated = false + if arg1.kind_of?(Range) + beg = arg1.begin + ed = arg1.end + beg += self.size if beg < 0 + ed += self.size if ed < 0 + ed -= 1 if arg1.exclude_end? + validated = true + elsif arg1.kind_of?(String) + validated = true + else + idx = arg1 + idx += self.size if arg1 < 0 + validated = true if idx >=0 && arg1 < self.size + end + if validated + str = self[arg1] + else + return nil + end + end + unless str.nil? || str == "" + if !arg1.nil? && !arg2.nil? + idx = arg1 >= 0 ? arg1 : self.size+arg1 + str2 = self[0...idx] + self[idx+arg2..-1].to_s + else + if arg1.kind_of?(Range) + idx = beg >= 0 ? beg : self.size+beg + idx2 = ed>= 0 ? ed : self.size+ed + str2 = self[0...idx] + self[idx2+1..-1].to_s + elsif arg1.kind_of?(String) + idx = self.index(arg1) + str2 = self[0...idx] + self[idx+arg1.size..-1] unless idx.nil? + else + idx = arg1 >= 0 ? arg1 : self.size+arg1 + str2 = self[0...idx] + self[idx+1..-1].to_s + end + end + self.replace(str2) unless str2.nil? + end + str + end + + ## + # call-seq: + # str.insert(index, other_str) -> str + # + # Inserts <i>other_str</i> before the character at the given + # <i>index</i>, modifying <i>str</i>. Negative indices count from the + # end of the string, and insert <em>after</em> the given character. + # The intent is insert <i>aString</i> so that it starts at the given + # <i>index</i>. + # + # "abcd".insert(0, 'X') #=> "Xabcd" + # "abcd".insert(3, 'X') #=> "abcXd" + # "abcd".insert(4, 'X') #=> "abcdX" + # "abcd".insert(-3, 'X') #=> "abXcd" + # "abcd".insert(-1, 'X') #=> "abcdX" + # + def insert(idx, str) + if idx == -1 + return self << str + elsif idx < 0 + idx += 1 + end + self[idx, 0] = str + self + end + + ## + # call-seq: + # str.ljust(integer, padstr=' ') -> new_str + # + # If <i>integer</i> is greater than the length of <i>str</i>, returns a new + # <code>String</code> of length <i>integer</i> with <i>str</i> left justified + # and padded with <i>padstr</i>; otherwise, returns <i>str</i>. + # + # "hello".ljust(4) #=> "hello" + # "hello".ljust(20) #=> "hello " + # "hello".ljust(20, '1234') #=> "hello123412341234123" + def ljust(idx, padstr = ' ') + raise ArgumentError, 'zero width padding' if padstr == '' + return self if idx <= self.size + pad_repetitions = (idx / padstr.length).ceil + padding = (padstr * pad_repetitions)[0...(idx - self.length)] + self + padding + end + + ## + # call-seq: + # str.rjust(integer, padstr=' ') -> new_str + # + # If <i>integer</i> is greater than the length of <i>str</i>, returns a new + # <code>String</code> of length <i>integer</i> with <i>str</i> right justified + # and padded with <i>padstr</i>; otherwise, returns <i>str</i>. + # + # "hello".rjust(4) #=> "hello" + # "hello".rjust(20) #=> " hello" + # "hello".rjust(20, '1234') #=> "123412341234123hello" + def rjust(idx, padstr = ' ') + raise ArgumentError, 'zero width padding' if padstr == '' + return self if idx <= self.size + pad_repetitions = (idx / padstr.length).ceil + padding = (padstr * pad_repetitions)[0...(idx - self.length)] + padding + self + end + + def chars(&block) + if block_given? + self.split('').each do |i| + block.call(i) + end + self + else + self.split('') + end + end + + def each_char(&block) + return to_enum :each_char unless block + + split('').each do |i| + block.call(i) + end + self + end + + def codepoints(&block) + len = self.size + + if block_given? + self.split('').each do|x| + block.call(x.ord) + end + self + else + self.split('').map{|x| x.ord} + end + end + alias each_codepoint codepoints + + ## + # call-seq: + # str.prepend(other_str) -> str + # + # Prepend---Prepend the given string to <i>str</i>. + # + # a = "world" + # a.prepend("hello ") #=> "hello world" + # a #=> "hello world" + def prepend(arg) + self[0, 0] = arg + self + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/src/string.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/src/string.c new file mode 100644 index 000000000..6bc035d6a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/src/string.c @@ -0,0 +1,685 @@ +#include <string.h> +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/string.h> +#include <mruby/range.h> + +static mrb_value +mrb_str_getbyte(mrb_state *mrb, mrb_value str) +{ + mrb_int pos; + mrb_get_args(mrb, "i", &pos); + + if (pos < 0) + pos += RSTRING_LEN(str); + if (pos < 0 || RSTRING_LEN(str) <= pos) + return mrb_nil_value(); + + return mrb_fixnum_value((unsigned char)RSTRING_PTR(str)[pos]); +} + +static mrb_value +mrb_str_setbyte(mrb_state *mrb, mrb_value str) +{ + mrb_int pos, byte; + long len; + + mrb_get_args(mrb, "ii", &pos, &byte); + + len = RSTRING_LEN(str); + if (pos < -len || len <= pos) + mrb_raisef(mrb, E_INDEX_ERROR, "index %S is out of array", mrb_fixnum_value(pos)); + if (pos < 0) + pos += len; + + mrb_str_modify(mrb, mrb_str_ptr(str)); + byte &= 0xff; + RSTRING_PTR(str)[pos] = byte; + return mrb_fixnum_value((unsigned char)byte); +} + +static mrb_value +mrb_str_byteslice(mrb_state *mrb, mrb_value str) +{ + mrb_value a1; + mrb_int len; + int argc; + + argc = mrb_get_args(mrb, "o|i", &a1, &len); + if (argc == 2) { + return mrb_str_substr(mrb, str, mrb_fixnum(a1), len); + } + switch (mrb_type(a1)) { + case MRB_TT_RANGE: + { + mrb_int beg; + + len = RSTRING_LEN(str); + switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) { + case 0: /* not range */ + break; + case 1: /* range */ + return mrb_str_substr(mrb, str, beg, len); + case 2: /* out of range */ + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1); + break; + } + return mrb_nil_value(); + } + case MRB_TT_FLOAT: + a1 = mrb_fixnum_value((mrb_int)mrb_float(a1)); + /* fall through */ + case MRB_TT_FIXNUM: + return mrb_str_substr(mrb, str, mrb_fixnum(a1), 1); + default: + mrb_raise(mrb, E_TYPE_ERROR, "wrong type of argument"); + } + /* not reached */ + return mrb_nil_value(); +} + +/* + * call-seq: + * str.swapcase! -> str or nil + * + * Equivalent to <code>String#swapcase</code>, but modifies the receiver in + * place, returning <i>str</i>, or <code>nil</code> if no changes were made. + * Note: case conversion is effective only in ASCII region. + */ +static mrb_value +mrb_str_swapcase_bang(mrb_state *mrb, mrb_value str) +{ + char *p, *pend; + int modify = 0; + struct RString *s = mrb_str_ptr(str); + + mrb_str_modify(mrb, s); + p = RSTRING_PTR(str); + pend = p + RSTRING_LEN(str); + while (p < pend) { + if (ISUPPER(*p)) { + *p = TOLOWER(*p); + modify = 1; + } + else if (ISLOWER(*p)) { + *p = TOUPPER(*p); + modify = 1; + } + p++; + } + + if (modify) return str; + return mrb_nil_value(); +} + +/* + * call-seq: + * str.swapcase -> new_str + * + * Returns a copy of <i>str</i> with uppercase alphabetic characters converted + * to lowercase and lowercase characters converted to uppercase. + * Note: case conversion is effective only in ASCII region. + * + * "Hello".swapcase #=> "hELLO" + * "cYbEr_PuNk11".swapcase #=> "CyBeR_pUnK11" + */ +static mrb_value +mrb_str_swapcase(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + + str = mrb_str_dup(mrb, self); + mrb_str_swapcase_bang(mrb, str); + return str; +} + +static mrb_value mrb_fixnum_chr(mrb_state *mrb, mrb_value num); + +/* + * call-seq: + * str << integer -> str + * str.concat(integer) -> str + * str << obj -> str + * str.concat(obj) -> str + * + * Append---Concatenates the given object to <i>str</i>. If the object is a + * <code>Integer</code>, it is considered as a codepoint, and is converted + * to a character before concatenation. + * + * a = "hello " + * a << "world" #=> "hello world" + * a.concat(33) #=> "hello world!" + */ +static mrb_value +mrb_str_concat_m(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + + mrb_get_args(mrb, "o", &str); + if (mrb_fixnum_p(str)) + str = mrb_fixnum_chr(mrb, str); + else + str = mrb_string_type(mrb, str); + mrb_str_concat(mrb, self, str); + return self; +} + +/* + * call-seq: + * str.start_with?([prefixes]+) -> true or false + * + * Returns true if +str+ starts with one of the +prefixes+ given. + * + * "hello".start_with?("hell") #=> true + * + * # returns true if one of the prefixes matches. + * "hello".start_with?("heaven", "hell") #=> true + * "hello".start_with?("heaven", "paradise") #=> false + * "h".start_with?("heaven", "hell") #=> false + */ +static mrb_value +mrb_str_start_with(mrb_state *mrb, mrb_value self) +{ + mrb_value *argv, sub; + mrb_int argc, i; + mrb_get_args(mrb, "*", &argv, &argc); + + for (i = 0; i < argc; i++) { + size_t len_l, len_r; + int ai = mrb_gc_arena_save(mrb); + sub = mrb_string_type(mrb, argv[i]); + mrb_gc_arena_restore(mrb, ai); + len_l = RSTRING_LEN(self); + len_r = RSTRING_LEN(sub); + if (len_l >= len_r) { + if (memcmp(RSTRING_PTR(self), RSTRING_PTR(sub), len_r) == 0) { + return mrb_true_value(); + } + } + } + return mrb_false_value(); +} + +/* + * call-seq: + * str.end_with?([suffixes]+) -> true or false + * + * Returns true if +str+ ends with one of the +suffixes+ given. + */ +static mrb_value +mrb_str_end_with(mrb_state *mrb, mrb_value self) +{ + mrb_value *argv, sub; + mrb_int argc, i; + mrb_get_args(mrb, "*", &argv, &argc); + + for (i = 0; i < argc; i++) { + size_t len_l, len_r; + int ai = mrb_gc_arena_save(mrb); + sub = mrb_string_type(mrb, argv[i]); + mrb_gc_arena_restore(mrb, ai); + len_l = RSTRING_LEN(self); + len_r = RSTRING_LEN(sub); + if (len_l >= len_r) { + if (memcmp(RSTRING_PTR(self) + (len_l - len_r), + RSTRING_PTR(sub), + len_r) == 0) { + return mrb_true_value(); + } + } + } + return mrb_false_value(); +} + +static mrb_value +mrb_str_hex(mrb_state *mrb, mrb_value self) +{ + return mrb_str_to_inum(mrb, self, 16, FALSE); +} + +static mrb_value +mrb_str_oct(mrb_state *mrb, mrb_value self) +{ + return mrb_str_to_inum(mrb, self, 8, FALSE); +} + +/* + * call-seq: + * string.chr -> string + * + * Returns a one-character string at the beginning of the string. + * + * a = "abcde" + * a.chr #=> "a" + */ +static mrb_value +mrb_str_chr(mrb_state *mrb, mrb_value self) +{ + return mrb_str_substr(mrb, self, 0, 1); +} + +static mrb_value +mrb_fixnum_chr(mrb_state *mrb, mrb_value num) +{ + mrb_int cp = mrb_fixnum(num); +#ifdef MRB_UTF8_STRING + char utf8[4]; + mrb_int len; + + if (cp < 0 || 0x10FFFF < cp) { + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num); + } + if (cp < 0x80) { + utf8[0] = (char)cp; + len = 1; + } + else if (cp < 0x800) { + utf8[0] = (char)(0xC0 | (cp >> 6)); + utf8[1] = (char)(0x80 | (cp & 0x3F)); + len = 2; + } + else if (cp < 0x10000) { + utf8[0] = (char)(0xE0 | (cp >> 12)); + utf8[1] = (char)(0x80 | ((cp >> 6) & 0x3F)); + utf8[2] = (char)(0x80 | ( cp & 0x3F)); + len = 3; + } + else { + utf8[0] = (char)(0xF0 | (cp >> 18)); + utf8[1] = (char)(0x80 | ((cp >> 12) & 0x3F)); + utf8[2] = (char)(0x80 | ((cp >> 6) & 0x3F)); + utf8[3] = (char)(0x80 | ( cp & 0x3F)); + len = 4; + } + return mrb_str_new(mrb, utf8, len); +#else + char c; + + if (cp < 0 || 0xff < cp) { + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num); + } + c = (char)cp; + return mrb_str_new(mrb, &c, 1); +#endif +} + +/* + * call-seq: + * string.lines -> array of string + * + * Returns strings per line; + * + * a = "abc\ndef" + * a.lines #=> ["abc\n", "def"] + */ +static mrb_value +mrb_str_lines(mrb_state *mrb, mrb_value self) +{ + mrb_value result; + mrb_value blk; + int ai; + mrb_int len; + mrb_value arg; + char *b = RSTRING_PTR(self); + char *p = b, *t; + char *e = b + RSTRING_LEN(self); + + mrb_get_args(mrb, "&", &blk); + + result = mrb_ary_new(mrb); + ai = mrb_gc_arena_save(mrb); + if (!mrb_nil_p(blk)) { + while (p < e) { + t = p; + while (p < e && *p != '\n') p++; + if (*p == '\n') p++; + len = (mrb_int) (p - t); + arg = mrb_str_new(mrb, t, len); + mrb_yield_argv(mrb, blk, 1, &arg); + mrb_gc_arena_restore(mrb, ai); + if (b != RSTRING_PTR(self)) { + ptrdiff_t diff = p - b; + b = RSTRING_PTR(self); + p = b + diff; + } + e = b + RSTRING_LEN(self); + } + return self; + } + while (p < e) { + t = p; + while (p < e && *p != '\n') p++; + if (*p == '\n') p++; + len = (mrb_int) (p - t); + mrb_ary_push(mrb, result, mrb_str_new(mrb, t, len)); + mrb_gc_arena_restore(mrb, ai); + } + return result; +} + +/* + * call-seq: + * string.succ -> string + * + * Returns next sequence of the string; + * + * a = "abc" + * a.succ #=> "abd" + */ +static mrb_value +mrb_str_succ_bang(mrb_state *mrb, mrb_value self) +{ + mrb_value result; + unsigned char *p, *e, *b, *t; + const char *prepend; + struct RString *s = mrb_str_ptr(self); + mrb_int l; + + if (RSTRING_LEN(self) == 0) + return self; + + mrb_str_modify(mrb, s); + l = RSTRING_LEN(self); + b = p = (unsigned char*) RSTRING_PTR(self); + t = e = p + l; + *(e--) = 0; + + // find trailing ascii/number + while (e >= b) { + if (ISALNUM(*e)) + break; + e--; + } + if (e < b) { + e = p + l - 1; + result = mrb_str_new_lit(mrb, ""); + } + else { + // find leading letter of the ascii/number + b = e; + while (b > p) { + if (!ISALNUM(*b) || (ISALNUM(*b) && *b != '9' && *b != 'z' && *b != 'Z')) + break; + b--; + } + if (!ISALNUM(*b)) + b++; + result = mrb_str_new(mrb, (char*) p, b - p); + } + + while (e >= b) { + if (!ISALNUM(*e)) { + if (*e == 0xff) { + mrb_str_cat_lit(mrb, result, "\x01"); + (*e) = 0; + } + else + (*e)++; + break; + } + prepend = NULL; + if (*e == '9') { + if (e == b) prepend = "1"; + *e = '0'; + } + else if (*e == 'z') { + if (e == b) prepend = "a"; + *e = 'a'; + } + else if (*e == 'Z') { + if (e == b) prepend = "A"; + *e = 'A'; + } + else { + (*e)++; + break; + } + if (prepend) mrb_str_cat_cstr(mrb, result, prepend); + e--; + } + result = mrb_str_cat(mrb, result, (char*) b, t - b); + l = RSTRING_LEN(result); + mrb_str_resize(mrb, self, l); + memcpy(RSTRING_PTR(self), RSTRING_PTR(result), l); + return self; +} + +static mrb_value +mrb_str_succ(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + + str = mrb_str_dup(mrb, self); + mrb_str_succ_bang(mrb, str); + return str; +} + +#ifdef MRB_UTF8_STRING +static const char utf8len_codepage_zero[256] = +{ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 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,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, +}; + +static mrb_int +utf8code(unsigned char* p) +{ + mrb_int len; + + if (p[0] < 0x80) + return p[0]; + + len = utf8len_codepage_zero[p[0]]; + if (len > 1 && (p[1] & 0xc0) == 0x80) { + if (len == 2) + return ((p[0] & 0x1f) << 6) + (p[1] & 0x3f); + if ((p[2] & 0xc0) == 0x80) { + if (len == 3) + return ((p[0] & 0x0f) << 12) + ((p[1] & 0x3f) << 6) + + (p[2] & 0x3f); + if ((p[3] & 0xc0) == 0x80) { + if (len == 4) + return ((p[0] & 0x07) << 18) + ((p[1] & 0x3f) << 12) + + ((p[2] & 0x3f) << 6) + (p[3] & 0x3f); + if ((p[4] & 0xc0) == 0x80) { + if (len == 5) + return ((p[0] & 0x03) << 24) + ((p[1] & 0x3f) << 18) + + ((p[2] & 0x3f) << 12) + ((p[3] & 0x3f) << 6) + + (p[4] & 0x3f); + if ((p[5] & 0xc0) == 0x80 && len == 6) + return ((p[0] & 0x01) << 30) + ((p[1] & 0x3f) << 24) + + ((p[2] & 0x3f) << 18) + ((p[3] & 0x3f) << 12) + + ((p[4] & 0x3f) << 6) + (p[5] & 0x3f); + } + } + } + } + return p[0]; +} + +static mrb_value +mrb_str_ord(mrb_state* mrb, mrb_value str) +{ + if (RSTRING_LEN(str) == 0) + mrb_raise(mrb, E_ARGUMENT_ERROR, "empty string"); + return mrb_fixnum_value(utf8code((unsigned char*) RSTRING_PTR(str))); +} +#else +static mrb_value +mrb_str_ord(mrb_state* mrb, mrb_value str) +{ + if (RSTRING_LEN(str) == 0) + mrb_raise(mrb, E_ARGUMENT_ERROR, "empty string"); + return mrb_fixnum_value((unsigned char)RSTRING_PTR(str)[0]); +} +#endif + +static mrb_bool +all_digits_p(const char *s, mrb_int len) +{ + while (len-- > 0) { + if (!ISDIGIT(*s)) return FALSE; + s++; + } + return TRUE; +} + +/* + * call-seq: + * str.upto(other_str, exclusive=false) {|s| block } -> str + * str.upto(other_str, exclusive=false) -> an_enumerator + * + * Iterates through successive values, starting at <i>str</i> and + * ending at <i>other_str</i> inclusive, passing each value in turn to + * the block. The <code>String#succ</code> method is used to generate + * each value. If optional second argument exclusive is omitted or is false, + * the last value will be included; otherwise it will be excluded. + * + * If no block is given, an enumerator is returned instead. + * + * "a8".upto("b6") {|s| print s, ' ' } + * for s in "a8".."b6" + * print s, ' ' + * end + * + * <em>produces:</em> + * + * a8 a9 b0 b1 b2 b3 b4 b5 b6 + * a8 a9 b0 b1 b2 b3 b4 b5 b6 + * + * If <i>str</i> and <i>other_str</i> contains only ascii numeric characters, + * both are recognized as decimal numbers. In addition, the width of + * string (e.g. leading zeros) is handled appropriately. + * + * "9".upto("11").to_a #=> ["9", "10", "11"] + * "25".upto("5").to_a #=> [] + * "07".upto("11").to_a #=> ["07", "08", "09", "10", "11"] + */ +static mrb_value +mrb_str_upto(mrb_state *mrb, mrb_value beg) +{ + mrb_value end; + mrb_value exclusive = mrb_false_value(); + mrb_value block = mrb_nil_value(); + mrb_value current, after_end; + mrb_int n; + mrb_bool excl; + + mrb_get_args(mrb, "o|o&", &end, &exclusive, &block); + + if (mrb_nil_p(block)) { + return mrb_funcall(mrb, beg, "to_enum", 3, mrb_symbol_value(mrb_intern_lit(mrb, "upto")), end, exclusive); + } + end = mrb_string_type(mrb, end); + excl = mrb_test(exclusive); + + /* single character */ + if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && + ISASCII(RSTRING_PTR(beg)[0]) && ISASCII(RSTRING_PTR(end)[0])) { + char c = RSTRING_PTR(beg)[0]; + char e = RSTRING_PTR(end)[0]; + int ai = mrb_gc_arena_save(mrb); + + if (c > e || (excl && c == e)) return beg; + for (;;) { + mrb_yield(mrb, block, mrb_str_new(mrb, &c, 1)); + mrb_gc_arena_restore(mrb, ai); + if (!excl && c == e) break; + c++; + if (excl && c == e) break; + } + return beg; + } + /* both edges are all digits */ + if (ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) && + all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) && + all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) { + mrb_int min_width = RSTRING_LEN(beg); + mrb_int bi = mrb_int(mrb, mrb_str_to_inum(mrb, beg, 10, FALSE)); + mrb_int ei = mrb_int(mrb, mrb_str_to_inum(mrb, end, 10, FALSE)); + int ai = mrb_gc_arena_save(mrb); + + while (bi <= ei) { + mrb_value ns, str; + + if (excl && bi == ei) break; + ns = mrb_format(mrb, "%S", mrb_fixnum_value(bi)); + if (min_width > RSTRING_LEN(ns)) { + str = mrb_str_new(mrb, NULL, min_width); + memset(RSTRING_PTR(str), '0', min_width-RSTRING_LEN(ns)); + memcpy(RSTRING_PTR(str)+min_width-RSTRING_LEN(ns), + RSTRING_PTR(ns), RSTRING_LEN(ns)); + } + else { + str = ns; + } + mrb_yield(mrb, block, str); + mrb_gc_arena_restore(mrb, ai); + bi++; + } + + return beg; + } + /* normal case */ + n = mrb_int(mrb, mrb_funcall(mrb, beg, "<=>", 1, end)); + if (n > 0 || (excl && n == 0)) return beg; + + after_end = mrb_funcall(mrb, end, "succ", 0); + current = mrb_str_dup(mrb, beg); + while (!mrb_str_equal(mrb, current, after_end)) { + int ai = mrb_gc_arena_save(mrb); + mrb_value next = mrb_nil_value(); + if (excl || !mrb_str_equal(mrb, current, end)) + next = mrb_funcall(mrb, current, "succ", 0); + mrb_yield(mrb, block, current); + if (mrb_nil_p(next)) break; + current = mrb_str_to_str(mrb, next); + if (excl && mrb_str_equal(mrb, current, end)) break; + if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0) + break; + mrb_gc_arena_restore(mrb, ai); + } + + return beg; +} + +void +mrb_mruby_string_ext_gem_init(mrb_state* mrb) +{ + struct RClass * s = mrb->string_class; + + mrb_define_method(mrb, s, "dump", mrb_str_dump, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_method(mrb, s, "swapcase!", mrb_str_swapcase_bang, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "swapcase", mrb_str_swapcase, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "concat", mrb_str_concat_m, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "<<", mrb_str_concat_m, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "start_with?", mrb_str_start_with, MRB_ARGS_REST()); + mrb_define_method(mrb, s, "end_with?", mrb_str_end_with, MRB_ARGS_REST()); + mrb_define_method(mrb, s, "hex", mrb_str_hex, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "oct", mrb_str_oct, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "lines", mrb_str_lines, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "succ", mrb_str_succ, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "succ!", mrb_str_succ_bang, MRB_ARGS_NONE()); + mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ")); + mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!")); + mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "upto", mrb_str_upto, MRB_ARGS_ANY()); + + mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE()); +} + +void +mrb_mruby_string_ext_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/test/string.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/test/string.rb new file mode 100644 index 000000000..2a568c7d6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-string-ext/test/string.rb @@ -0,0 +1,667 @@ +## +# String(Ext) Test + +UTF8STRING = ("\343\201\202".size == 1) + +assert('String.try_convert') do + assert_nil String.try_convert(nil) + assert_nil String.try_convert(:foo) + assert_equal "", String.try_convert("") + assert_equal "1,2,3", String.try_convert("1,2,3") +end + +assert('String#getbyte') do + str1 = "hello" + bytes1 = [104, 101, 108, 108, 111] + assert_equal bytes1[0], str1.getbyte(0) + assert_equal bytes1[-1], str1.getbyte(-1) + assert_equal bytes1[6], str1.getbyte(6) + + str2 = "\xFF" + bytes2 = [0xFF] + assert_equal bytes2[0], str2.getbyte(0) +end + +assert('String#setbyte') do + str1 = "hello" + h = "H".getbyte(0) + str1.setbyte(0, h) + assert_equal(h, str1.getbyte(0)) + assert_equal("Hello", str1) +end + +assert("String#setbyte raises IndexError if arg conversion resizes String") do + $s = "01234\n" + class Tmp + def to_i + $s.chomp! '' + 95 + end + end + tmp = Tmp.new + assert_raise(IndexError) { $s.setbyte(5, tmp) } +end + +assert('String#byteslice') do + str1 = "hello" + assert_equal("e", str1.byteslice(1)) + assert_equal("o", str1.byteslice(-1)) + assert_equal("ell", str1.byteslice(1..3)) + assert_equal("el", str1.byteslice(1...3)) +end + +assert('String#dump') do + ("\1" * 100).dump # should not raise an exception - regress #1210 + "\0".inspect == "\"\\000\"" and + "foo".dump == "\"foo\"" +end + +assert('String#strip') do + s = " abc " + "".strip == "" and " \t\r\n\f\v".strip == "" and + "\0a\0".strip == "\0a" and + "abc".strip == "abc" and + " abc".strip == "abc" and + "abc ".strip == "abc" and + " abc ".strip == "abc" and + s == " abc " +end + +assert('String#lstrip') do + s = " abc " + s.lstrip + "".lstrip == "" and " \t\r\n\f\v".lstrip == "" and + "\0a\0".lstrip == "\0a\0" and + "abc".lstrip == "abc" and + " abc".lstrip == "abc" and + "abc ".lstrip == "abc " and + " abc ".lstrip == "abc " and + s == " abc " +end + +assert('String#rstrip') do + s = " abc " + s.rstrip + "".rstrip == "" and " \t\r\n\f\v".rstrip == "" and + "\0a\0".rstrip == "\0a" and + "abc".rstrip == "abc" and + " abc".rstrip == " abc" and + "abc ".rstrip == "abc" and + " abc ".rstrip == " abc" and + s == " abc " +end + +assert('String#strip!') do + s = " abc " + t = "abc" + s.strip! == "abc" and s == "abc" and t.strip! == nil +end + +assert('String#lstrip!') do + s = " abc " + t = "abc " + s.lstrip! == "abc " and s == "abc " and t.lstrip! == nil +end + +assert('String#rstrip!') do + s = " abc " + t = " abc" + s.rstrip! == " abc" and s == " abc" and t.rstrip! == nil +end + +assert('String#swapcase') do + assert_equal "hELLO", "Hello".swapcase + assert_equal "CyBeR_pUnK11", "cYbEr_PuNk11".swapcase +end + +assert('String#swapcase!') do + s = "Hello" + t = s.clone + t.swapcase! + assert_equal s.swapcase, t +end + +assert('String#concat') do + assert_equal "Hello World!", "Hello " << "World" << 33 + assert_equal "Hello World!", "Hello ".concat("World").concat(33) + + o = Object.new + def o.to_str + "to_str" + end + assert_equal "hi to_str", "hi " << o + + assert_raise(TypeError) { "".concat(Object.new) } +end + +assert('String#casecmp') do + assert_equal 1, "abcdef".casecmp("abcde") + assert_equal 0, "aBcDeF".casecmp("abcdef") + assert_equal(-1, "abcdef".casecmp("abcdefg")) + assert_equal 0, "abcdef".casecmp("ABCDEF") + o = Object.new + def o.to_str + "ABCDEF" + end + assert_equal 0, "abcdef".casecmp(o) +end + +assert('String#start_with?') do + assert_true "hello".start_with?("heaven", "hell") + assert_true !"hello".start_with?("heaven", "paradise") + assert_true !"h".start_with?("heaven", "hell") + assert_raise TypeError do "hello".start_with?(true) end +end + +assert('String#end_with?') do + assert_true "string".end_with?("ing", "mng") + assert_true !"string".end_with?("str", "tri") + assert_true !"ng".end_with?("ing", "mng") + assert_raise TypeError do "hello".end_with?(true) end +end + +assert('String#partition') do + assert_equal ["a", "x", "axa"], "axaxa".partition("x") + assert_equal ["aaaaa", "", ""], "aaaaa".partition("x") + assert_equal ["", "", "aaaaa"], "aaaaa".partition("") + assert_equal ["", "a", "aaaa"], "aaaaa".partition("a") + assert_equal ["aaaa", "b", ""], "aaaab".partition("b") + assert_equal ["", "b", "aaaa"], "baaaa".partition("b") + assert_equal ["", "", ""], "".partition("a") +end + +assert('String#rpartition') do + assert_equal ["axa", "x", "a"], "axaxa".rpartition("x") + assert_equal ["", "", "aaaaa"], "aaaaa".rpartition("x") + assert_equal ["aaaaa", "", ""], "aaaaa".rpartition("") + assert_equal ["aaaa", "a", ""], "aaaaa".rpartition("a") + assert_equal ["aaaa", "b", ""], "aaaab".rpartition("b") + assert_equal ["", "b", "aaaa"], "baaaa".rpartition("b") + assert_equal ["", "", ""], "".rpartition("a") +end + +assert('String#hex') do + assert_equal 16, "10".hex + assert_equal 255, "ff".hex + assert_equal 16, "0x10".hex + assert_equal (-16), "-0x10".hex + assert_equal 0, "xyz".hex + assert_equal 16, "10z".hex + assert_equal 16, "1_0".hex + assert_equal 0, "".hex +end + +assert('String#oct') do + assert_equal 8, "10".oct + assert_equal 7, "7".oct + assert_equal 0, "8".oct + assert_equal 0, "9".oct + assert_equal 0, "xyz".oct + assert_equal 8, "10z".oct + assert_equal 8, "1_0".oct + assert_equal 8, "010".oct + assert_equal (-8), "-10".oct +end + +assert('String#chr') do + assert_equal "a", "abcde".chr + # test Fixnum#chr as well + assert_equal "a", 97.chr +end + +assert('String#lines') do + assert_equal ["Hel\n", "lo\n", "World!"], "Hel\nlo\nWorld!".lines + assert_equal ["Hel\n", "lo\n", "World!\n"], "Hel\nlo\nWorld!\n".lines + assert_equal ["\n", "\n", "\n"], "\n\n\n".lines + assert_equal [], "".lines +end + +assert('String#clear') do + # embed string + s = "foo" + assert_equal("", s.clear) + assert_equal("", s) + + # not embed string and not shared string + s = "foo" * 100 + a = s + assert_equal("", s.clear) + assert_equal("", s) + assert_equal("", a) + + # shared string + s = "foo" * 100 + a = s[10, 90] # create shared string + assert_equal("", s.clear) # clear + assert_equal("", s) # s is cleared + assert_not_equal("", a) # a should not be affected +end + +assert('String#slice!') do + a = "AooBar" + b = a.dup + assert_equal "A", a.slice!(0) + assert_equal "AooBar", b + + a = "FooBar" + assert_equal "r", a.slice!(-1) + assert_equal "FooBa", a + + a = "FooBar" + assert_nil a.slice!(6) + assert_nil a.slice!(-7) + assert_equal "FooBar", a + + a = "FooBar" + assert_equal "Foo", a.slice!(0, 3) + assert_equal "Bar", a + + a = "FooBar" + assert_equal "Bar", a.slice!(-3, 3) + assert_equal "Foo", a + + a = "FooBar" + assert_equal "", a.slice!(6, 2) + assert_equal "FooBar", a + + a = "FooBar" + assert_nil a.slice!(-7,10) + assert_equal "FooBar", a + + a = "FooBar" + assert_equal "Foo", a.slice!(0..2) + assert_equal "Bar", a + + a = "FooBar" + assert_equal "Bar", a.slice!(-3..-1) + assert_equal "Foo", a + + a = "FooBar" + assert_equal "", a.slice!(6..2) + assert_equal "FooBar", a + + a = "FooBar" + assert_nil a.slice!(-10..-7) + assert_equal "FooBar", a + + a = "FooBar" + assert_equal "Foo", a.slice!("Foo") + assert_equal "Bar", a + + a = "FooBar" + assert_nil a.slice!("xyzzy") + assert_equal "FooBar", a + + assert_raise(ArgumentError) { "foo".slice! } +end + +assert('String#succ') do + assert_equal "", "".succ + assert_equal "1", "0".succ + assert_equal "10", "9".succ + assert_equal "01", "00".succ + assert_equal "a1", "a0".succ + assert_equal "A1", "A0".succ + assert_equal "10", "09".succ + assert_equal "b0", "a9".succ + assert_equal "B0", "A9".succ + + assert_equal "b", "a".succ + assert_equal "aa", "z".succ + assert_equal "ab", "aa".succ + assert_equal "Ab", "Aa".succ + assert_equal "0b", "0a".succ + assert_equal "ba", "az".succ + assert_equal "Ba", "Az".succ + assert_equal "1a", "0z".succ + + assert_equal "B", "A".succ + assert_equal "AA", "Z".succ + assert_equal "AB", "AA".succ + assert_equal "aB", "aA".succ + assert_equal "0B", "0A".succ + assert_equal "BA", "AZ".succ + assert_equal "bA", "aZ".succ + assert_equal "1A", "0Z".succ + + assert_equal ".", "-".succ + assert_equal "\x01\x00", "\xff".succ + assert_equal "-b", "-a".succ + assert_equal "-aa", "-z".succ + assert_equal "-a-b-", "-a-a-".succ + assert_equal "-b-", "-a-".succ + assert_equal "-aa-", "-z-".succ + assert_equal "あb", "あa".succ + assert_equal "あba", "あaz".succ + + a = ""; a.succ! + assert_equal "", a + a = "0"; a.succ! + assert_equal "1", a + a = "9"; a.succ! + assert_equal "10", a + a = "00"; a.succ! + assert_equal "01", a + a = "a0"; a.succ! + assert_equal "a1", a + a = "A0"; a.succ! + assert_equal "A1", a + a = "09"; a.succ! + assert_equal "10", a + a = "a9"; a.succ! + assert_equal "b0", a + a = "A9"; a.succ! + assert_equal "B0", a + + a = "a"; a.succ! + assert_equal "b", a + a = "z"; a.succ! + assert_equal "aa", a + a = "aa"; a.succ! + assert_equal "ab", a + a = "Aa"; a.succ! + assert_equal "Ab", a + a = "0a"; a.succ! + assert_equal "0b", a + a = "az"; a.succ! + assert_equal "ba", a + a = "Az"; a.succ! + assert_equal "Ba", a + a = "0z"; a.succ! + assert_equal "1a", a + + a = "A"; a.succ! + assert_equal "B", a + a = "Z"; a.succ! + assert_equal "AA", a + a = "AA"; a.succ! + assert_equal "AB", a + a = "aA"; a.succ! + assert_equal "aB", a + a = "0A"; a.succ! + assert_equal "0B", a + a = "AZ"; a.succ! + assert_equal "BA", a + a = "aZ"; a.succ! + assert_equal "bA", a + a = "0Z"; a.succ! + assert_equal "1A", a + + a = "-"; a.succ! + assert_equal ".", a + a = "\xff"; a.succ! + assert_equal "\x01\x00", a + a = "-a"; a.succ! + assert_equal "-b", a + a = "-z"; a.succ! + assert_equal "-aa", a + a = "-a-a-"; a.succ! + assert_equal "-a-b-", a + a = "-a-"; a.succ! + assert_equal "-b-", a + a = "-z-"; a.succ! + assert_equal "-aa-", a + a = "あb"; a.succ! + assert_equal "あc", a + a = "あaz"; a.succ! + assert_equal "あba", a +end + +assert('String#next') do + assert_equal "01", "00".next + + a = "00"; a.next! + assert_equal "01", a +end + +assert('String#insert') do + assert_equal "Xabcd", "abcd".insert(0, 'X') + assert_equal "abcXd", "abcd".insert(3, 'X') + assert_equal "abcdX", "abcd".insert(4, 'X') + assert_equal "abXcd", "abcd".insert(-3, 'X') + assert_equal "abcdX", "abcd".insert(-1, 'X') + assert_raise(IndexError) { "abcd".insert(5, 'X') } + assert_raise(IndexError) { "abcd".insert(-6, 'X') } + + a = "abcd" + a.insert(0, 'X') + assert_equal "Xabcd", a +end + +assert('String#prepend') do + a = "world" + assert_equal "hello world", a.prepend("hello ") + assert_equal "hello world", a +end + +assert('String#ljust') do + assert_equal "hello", "hello".ljust(4) + assert_equal "hello ", "hello".ljust(20) + assert_equal 20, "hello".ljust(20).length + assert_equal "hello123412341234123", "hello".ljust(20, '1234') + assert_equal "hello", "hello".ljust(-3) +end + +assert('String#rjust') do + assert_equal "hello", "hello".rjust(4) + assert_equal " hello", "hello".rjust(20) + assert_equal 20, "hello".rjust(20).length + assert_equal "123412341234123hello", "hello".rjust(20, '1234') + assert_equal "hello", "hello".rjust(-3) +end + +if UTF8STRING + assert('String#ljust with UTF8') do + assert_equal "helloん ", "helloん".ljust(20) + assert_equal "helloó ", "helloó".ljust(34) + assert_equal 34, "helloó".ljust(34).length + assert_equal "helloんんんんんんんんんんんんんん", "hello".ljust(19, 'ん') + assert_equal "helloんんんんんんんんんんんんんんん", "hello".ljust(20, 'ん') + end + + assert('String#rjust with UTF8') do + assert_equal " helloん", "helloん".rjust(20) + assert_equal " helloó", "helloó".rjust(34) + # assert_equal 34, "helloó".rjust(34).length + assert_equal "んんんんんんんんんんんんんんhello", "hello".rjust(19, 'ん') + assert_equal "んんんんんんんんんんんんんんんhello", "hello".rjust(20, 'ん') + end + + assert('UTF8 byte counting') do + ret = ' ' + ret[-6..-1] = "helloó" + assert_equal 34, ret.length + end +end + +assert('String#ljust should not change string') do + a = "hello" + a.ljust(20) + assert_equal "hello", a +end + +assert('String#rjust should not change string') do + a = "hello" + a.rjust(20) + assert_equal "hello", a +end + +assert('String#ljust should raise on zero width padding') do + assert_raise(ArgumentError) { "foo".ljust(10, '') } +end + +assert('String#rjust should raise on zero width padding') do + assert_raise(ArgumentError) { "foo".rjust(10, '') } +end + +assert('String#upto') do + assert_equal %w(a8 a9 b0 b1 b2 b3 b4 b5 b6), "a8".upto("b6").to_a + assert_equal ["9", "10", "11"], "9".upto("11").to_a + assert_equal [], "25".upto("5").to_a + assert_equal ["07", "08", "09", "10", "11"], "07".upto("11").to_a + +if UTF8STRING + assert_equal ["あ", "ぃ", "い", "ぅ", "う", "ぇ", "え", "ぉ", "お"], "あ".upto("お").to_a +end + + assert_equal ["9", ":", ";", "<", "=", ">", "?", "@", "A"], "9".upto("A").to_a + + a = "aa" + start = "aa" + count = 0 + assert_equal("aa", a.upto("zz") {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(676, count) + + a = "a" + start = "a" + count = 0 + assert_equal("a", a.upto("a") {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(1, count) + + a = "a" + start = "a" + count = 0 + assert_equal("a", a.upto("b", true) {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(1, count) + + a = "0" + start = "0" + count = 0 + assert_equal("0", a.upto("0") {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(1, count) + + a = "0" + start = "0" + count = 0 + assert_equal("0", a.upto("-1") {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(0, count) + + a = "-1" + start = "-1" + count = 0 + assert_equal("-1", a.upto("-2") {|s| + assert_equal(start, s) + start.succ! + count += 1 + }) + assert_equal(2, count) + + assert_raise(TypeError) { "a".upto(:c) {} } +end + +assert('String#ord') do + got = "hello!".split('').map {|x| x.ord} + expect = [104, 101, 108, 108, 111, 33] + unless UTF8STRING + got << "\xff".ord + expect << 0xff + end + assert_equal expect, got +end + +assert('String#ord(UTF-8)') do + got = "こんにちは世界!".split('').map {|x| x.ord} + expect = [0x3053,0x3093,0x306b,0x3061,0x306f,0x4e16,0x754c,0x21] + assert_equal expect, got +end if UTF8STRING + +assert('String#chr') do + assert_equal "h", "hello!".chr +end +assert('String#chr(UTF-8)') do + assert_equal "こ", "こんにちは世界!".chr +end if UTF8STRING + +assert('String#chars') do + expect = ["h", "e", "l", "l", "o", "!"] + assert_equal expect, "hello!".chars + s = "" + "hello!".chars do |x| + s += x + end + assert_equal "hello!", s +end + +assert('String#chars(UTF-8)') do + expect = ['こ', 'ん', 'に', 'ち', 'は', '世', '界', '!'] + assert_equal expect, "こんにちは世界!".chars + s = "" + "こんにちは世界!".chars do |x| + s += x + end + assert_equal "こんにちは世界!", s +end if UTF8STRING + +assert('String#each_char') do + s = "" + "hello!".each_char do |x| + s += x + end + assert_equal "hello!", s +end + +assert('String#each_char(UTF-8)') do + s = "" + "こんにちは世界!".each_char do |x| + s += x + end + assert_equal "こんにちは世界!", s +end if UTF8STRING + +assert('String#codepoints') do + expect = [104, 101, 108, 108, 111, 33] + assert_equal expect, "hello!".codepoints + cp = [] + "hello!".codepoints do |x| + cp << x + end + assert_equal expect, cp +end + +assert('String#codepoints(UTF-8)') do + expect = [12371, 12435, 12395, 12385, 12399, 19990, 30028, 33] + assert_equal expect, "こんにちは世界!".codepoints + cp = [] + "こんにちは世界!".codepoints do |x| + cp << x + end + assert_equal expect, cp +end if UTF8STRING + +assert('String#each_codepoint') do + expect = [104, 101, 108, 108, 111, 33] + cp = [] + "hello!".each_codepoint do |x| + cp << x + end + assert_equal expect, cp +end + +assert('String#each_codepoint(UTF-8)') do + expect = [12371, 12435, 12395, 12385, 12399, 19990, 30028, 33] + cp = [] + "こんにちは世界!".each_codepoint do |x| + cp << x + end + assert_equal expect, cp +end if UTF8STRING diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/mrbgem.rake new file mode 100644 index 000000000..2826ad2ad --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-struct') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'standard Struct class' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/mrblib/struct.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/mrblib/struct.rb new file mode 100644 index 000000000..7cf3dd3ab --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/mrblib/struct.rb @@ -0,0 +1,103 @@ +## +# Struct +# +# ISO 15.2.18 + +if Object.const_defined?(:Struct) + class Struct + + ## + # Calls the given block for each element of +self+ + # and pass the respective element. + # + # ISO 15.2.18.4.4 + def each(&block) + self.class.members.each{|field| + block.call(self[field]) + } + self + end + + ## + # Calls the given block for each element of +self+ + # and pass the name and value of the respectiev + # element. + # + # ISO 15.2.18.4.5 + def each_pair(&block) + self.class.members.each{|field| + block.call(field.to_sym, self[field]) + } + self + end + + ## + # Calls the given block for each element of +self+ + # and returns an array with all elements of which + # block is not false. + # + # ISO 15.2.18.4.7 + def select(&block) + ary = [] + self.class.members.each{|field| + val = self[field] + ary.push(val) if block.call(val) + } + ary + end + + def _inspect + name = self.class.to_s + if name[0] == "#" + str = "#<struct " + else + str = "#<struct #{name} " + end + buf = [] + self.each_pair do |k,v| + buf.push [k.to_s + "=" + v._inspect] + end + str + buf.join(", ") + ">" + end + + ## + # call-seq: + # struct.to_s -> string + # struct.inspect -> string + # + # Describe the contents of this struct in a string. + # + # 15.2.18.4.10(x) + # + def inspect + begin + self._inspect + rescue SystemStackError + "#<struct #{self.class.to_s}:...>" + end + end + + ## + # 15.2.18.4.11(x) + # + alias to_s inspect + end + + ## + # call-seq: + # hsh.dig(key,...) -> object + # + # Extracts the nested value specified by the sequence of <i>key</i> + # objects by calling +dig+ at each step, returning +nil+ if any + # intermediate step is +nil+. + # + def dig(idx,*args) + n = self[idx] + if args.size > 0 + n&.dig(*args) + else + n + end + end +end + diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/src/struct.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/src/struct.c new file mode 100644 index 000000000..67762a948 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/src/struct.c @@ -0,0 +1,714 @@ +/* +** struct.c - Struct class +** +** See Copyright Notice in mruby.h +*/ + +#include <string.h> +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/string.h> +#include <mruby/class.h> +#include <mruby/variable.h> +#include <mruby/hash.h> +#include <mruby/range.h> + +#define RSTRUCT_LEN(st) RARRAY_LEN(st) +#define RSTRUCT_PTR(st) RARRAY_PTR(st) + +static struct RClass * +struct_class(mrb_state *mrb) +{ + return mrb_class_get(mrb, "Struct"); +} + +static inline mrb_value +struct_ivar_get(mrb_state *mrb, mrb_value c, mrb_sym id) +{ + struct RClass* kclass; + struct RClass* sclass = struct_class(mrb); + mrb_value ans; + + for (;;) { + ans = mrb_iv_get(mrb, c, id); + if (!mrb_nil_p(ans)) return ans; + kclass = RCLASS_SUPER(c); + if (kclass == 0 || kclass == sclass) + return mrb_nil_value(); + c = mrb_obj_value(kclass); + } +} + +static mrb_value +struct_s_members(mrb_state *mrb, struct RClass *klass) +{ + mrb_value members = struct_ivar_get(mrb, mrb_obj_value(klass), mrb_intern_lit(mrb, "__members__")); + + if (mrb_nil_p(members)) { + mrb_raise(mrb, E_TYPE_ERROR, "uninitialized struct"); + } + if (!mrb_array_p(members)) { + mrb_raise(mrb, E_TYPE_ERROR, "corrupted struct"); + } + return members; +} + +static mrb_value +struct_members(mrb_state *mrb, mrb_value s) +{ + mrb_value members = struct_s_members(mrb, mrb_obj_class(mrb, s)); + if (!mrb_array_p(s)) { + mrb_raise(mrb, E_TYPE_ERROR, "corrupted struct"); + } + if (RSTRUCT_LEN(s) != RARRAY_LEN(members)) { + if (RSTRUCT_LEN(s) == 0) { /* probably uninitialized */ + mrb_ary_resize(mrb, s, RARRAY_LEN(members)); + } + else { + mrb_raisef(mrb, E_TYPE_ERROR, + "struct size differs (%S required %S given)", + mrb_fixnum_value(RARRAY_LEN(members)), mrb_fixnum_value(RSTRUCT_LEN(s))); + } + } + return members; +} + +static mrb_value +mrb_struct_s_members_m(mrb_state *mrb, mrb_value klass) +{ + mrb_value members, ary; + + members = struct_s_members(mrb, mrb_class_ptr(klass)); + ary = mrb_ary_new_capa(mrb, RARRAY_LEN(members)); + mrb_ary_replace(mrb, ary, members); + return ary; +} + +static void +mrb_struct_modify(mrb_state *mrb, mrb_value strct) +{ + if (MRB_FROZEN_P(mrb_basic_ptr(strct))) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen struct"); + } + + mrb_write_barrier(mrb, mrb_basic_ptr(strct)); +} + +/* 15.2.18.4.6 */ +/* + * call-seq: + * struct.members -> array + * + * Returns an array of strings representing the names of the instance + * variables. + * + * Customer = Struct.new(:name, :address, :zip) + * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) + * joe.members #=> [:name, :address, :zip] + */ + +static mrb_value +mrb_struct_members(mrb_state *mrb, mrb_value obj) +{ + return mrb_struct_s_members_m(mrb, mrb_obj_value(mrb_obj_class(mrb, obj))); +} + +static mrb_value struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id); + +static mrb_value +mrb_struct_ref(mrb_state *mrb, mrb_value obj) +{ + return struct_aref_sym(mrb, obj, mrb->c->ci->mid); +} + +static mrb_sym +mrb_id_attrset(mrb_state *mrb, mrb_sym id) +{ + const char *name; + char *buf; + mrb_int len; + mrb_sym mid; + + name = mrb_sym2name_len(mrb, id, &len); + buf = (char *)mrb_malloc(mrb, (size_t)len+2); + memcpy(buf, name, (size_t)len); + buf[len] = '='; + buf[len+1] = '\0'; + + mid = mrb_intern(mrb, buf, len+1); + mrb_free(mrb, buf); + return mid; +} + +static mrb_value mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val); + +static mrb_value +mrb_struct_set_m(mrb_state *mrb, mrb_value obj) +{ + mrb_value val; + + const char *name; + mrb_int slen; + mrb_sym mid; + + mrb_get_args(mrb, "o", &val); + + /* get base id */ + name = mrb_sym2name_len(mrb, mrb->c->ci->mid, &slen); + mid = mrb_intern(mrb, name, slen-1); /* omit last "=" */ + + return mrb_struct_aset_sym(mrb, obj, mid, val); +} + +static mrb_bool +is_local_id(mrb_state *mrb, const char *name) +{ + if (!name) return FALSE; + return !ISUPPER(name[0]); +} + +static mrb_bool +is_const_id(mrb_state *mrb, const char *name) +{ + if (!name) return FALSE; + return ISUPPER(name[0]); +} + +static void +make_struct_define_accessors(mrb_state *mrb, mrb_value members, struct RClass *c) +{ + const mrb_value *ptr_members = RARRAY_PTR(members); + mrb_int i; + mrb_int len = RARRAY_LEN(members); + int ai = mrb_gc_arena_save(mrb); + + for (i=0; i<len; i++) { + mrb_sym id = mrb_symbol(ptr_members[i]); + const char *name = mrb_sym2name_len(mrb, id, NULL); + + if (is_local_id(mrb, name) || is_const_id(mrb, name)) { + mrb_define_method_id(mrb, c, id, mrb_struct_ref, MRB_ARGS_NONE()); + mrb_define_method_id(mrb, c, mrb_id_attrset(mrb, id), mrb_struct_set_m, MRB_ARGS_REQ(1)); + mrb_gc_arena_restore(mrb, ai); + } + } +} + +static mrb_value +make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * klass) +{ + mrb_value nstr; + mrb_sym id; + struct RClass *c; + + if (mrb_nil_p(name)) { + c = mrb_class_new(mrb, klass); + } + else { + /* old style: should we warn? */ + name = mrb_str_to_str(mrb, name); + id = mrb_obj_to_sym(mrb, name); + if (!is_const_id(mrb, mrb_sym2name_len(mrb, id, NULL))) { + mrb_name_error(mrb, id, "identifier %S needs to be constant", name); + } + if (mrb_const_defined_at(mrb, mrb_obj_value(klass), id)) { + mrb_warn(mrb, "redefining constant Struct::%S", name); + mrb_const_remove(mrb, mrb_obj_value(klass), id); + } + c = mrb_define_class_under(mrb, klass, RSTRING_PTR(name), klass); + } + MRB_SET_INSTANCE_TT(c, MRB_TT_ARRAY); + nstr = mrb_obj_value(c); + mrb_iv_set(mrb, nstr, mrb_intern_lit(mrb, "__members__"), members); + + mrb_define_class_method(mrb, c, "new", mrb_instance_new, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, c, "[]", mrb_instance_new, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, c, "members", mrb_struct_s_members_m, MRB_ARGS_NONE()); + /* RSTRUCT(nstr)->basic.c->super = c->c; */ + make_struct_define_accessors(mrb, members, c); + return nstr; +} + +/* 15.2.18.3.1 */ +/* + * call-seq: + * Struct.new( [aString] [, aSym]+> ) -> StructClass + * StructClass.new(arg, ...) -> obj + * StructClass[arg, ...] -> obj + * + * Creates a new class, named by <i>aString</i>, containing accessor + * methods for the given symbols. If the name <i>aString</i> is + * omitted, an anonymous structure class will be created. Otherwise, + * the name of this struct will appear as a constant in class + * <code>Struct</code>, so it must be unique for all + * <code>Struct</code>s in the system and should start with a capital + * letter. Assigning a structure class to a constant effectively gives + * the class the name of the constant. + * + * <code>Struct::new</code> returns a new <code>Class</code> object, + * which can then be used to create specific instances of the new + * structure. The number of actual parameters must be + * less than or equal to the number of attributes defined for this + * class; unset parameters default to <code>nil</code>. Passing too many + * parameters will raise an <code>ArgumentError</code>. + * + * The remaining methods listed in this section (class and instance) + * are defined for this generated class. + * + * # Create a structure with a name in Struct + * Struct.new("Customer", :name, :address) #=> Struct::Customer + * Struct::Customer.new("Dave", "123 Main") #=> #<struct Struct::Customer name="Dave", address="123 Main"> + * + * # Create a structure named by its constant + * Customer = Struct.new(:name, :address) #=> Customer + * Customer.new("Dave", "123 Main") #=> #<struct Customer name="Dave", address="123 Main"> + */ +static mrb_value +mrb_struct_s_def(mrb_state *mrb, mrb_value klass) +{ + mrb_value name, rest; + mrb_value *pargv; + mrb_int argcnt; + mrb_int i; + mrb_value b, st; + mrb_sym id; + mrb_value *argv; + mrb_int argc; + + name = mrb_nil_value(); + mrb_get_args(mrb, "*&", &argv, &argc, &b); + if (argc == 0) { /* special case to avoid crash */ + rest = mrb_ary_new(mrb); + } + else { + if (argc > 0) name = argv[0]; + pargv = &argv[1]; + argcnt = argc-1; + if (!mrb_nil_p(name) && mrb_symbol_p(name)) { + /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */ + name = mrb_nil_value(); + pargv = &argv[0]; + argcnt++; + } + rest = mrb_ary_new_from_values(mrb, argcnt, pargv); + for (i=0; i<RARRAY_LEN(rest); i++) { + id = mrb_obj_to_sym(mrb, RARRAY_PTR(rest)[i]); + mrb_ary_set(mrb, rest, i, mrb_symbol_value(id)); + } + } + st = make_struct(mrb, name, rest, mrb_class_ptr(klass)); + if (!mrb_nil_p(b)) { + mrb_yield_with_class(mrb, b, 1, &st, st, mrb_class_ptr(st)); + } + + return st; +} + +static mrb_int +num_members(mrb_state *mrb, struct RClass *klass) +{ + mrb_value members; + + members = struct_ivar_get(mrb, mrb_obj_value(klass), mrb_intern_lit(mrb, "__members__")); + if (!mrb_array_p(members)) { + mrb_raise(mrb, E_TYPE_ERROR, "broken members"); + } + return RARRAY_LEN(members); +} + +/* 15.2.18.4.8 */ +/* + */ +static mrb_value +mrb_struct_initialize_withArg(mrb_state *mrb, mrb_int argc, mrb_value *argv, mrb_value self) +{ + struct RClass *klass = mrb_obj_class(mrb, self); + mrb_int i, n; + + n = num_members(mrb, klass); + if (n < argc) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "struct size differs"); + } + + for (i = 0; i < argc; i++) { + mrb_ary_set(mrb, self, i, argv[i]); + } + for (i = argc; i < n; i++) { + mrb_ary_set(mrb, self, i, mrb_nil_value()); + } + return self; +} + +static mrb_value +mrb_struct_initialize(mrb_state *mrb, mrb_value self) +{ + mrb_value *argv; + mrb_int argc; + + mrb_get_args(mrb, "*!", &argv, &argc); + return mrb_struct_initialize_withArg(mrb, argc, argv, self); +} + +/* 15.2.18.4.9 */ +/* :nodoc: */ +static mrb_value +mrb_struct_init_copy(mrb_state *mrb, mrb_value copy) +{ + mrb_value s; + + mrb_get_args(mrb, "o", &s); + + if (mrb_obj_equal(mrb, copy, s)) return copy; + if (!mrb_obj_is_instance_of(mrb, s, mrb_obj_class(mrb, copy))) { + mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); + } + if (!mrb_array_p(s)) { + mrb_raise(mrb, E_TYPE_ERROR, "corrupted struct"); + } + mrb_ary_replace(mrb, copy, s); + return copy; +} + +static mrb_value +struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id) +{ + mrb_value members, *ptr; + const mrb_value *ptr_members; + mrb_int i, len; + + members = struct_members(mrb, obj); + ptr_members = RARRAY_PTR(members); + len = RARRAY_LEN(members); + ptr = RSTRUCT_PTR(obj); + for (i=0; i<len; i++) { + mrb_value slot = ptr_members[i]; + if (mrb_symbol_p(slot) && mrb_symbol(slot) == id) { + return ptr[i]; + } + } + mrb_raisef(mrb, E_INDEX_ERROR, "'%S' is not a struct member", mrb_sym2str(mrb, id)); + return mrb_nil_value(); /* not reached */ +} + +static mrb_value +struct_aref_int(mrb_state *mrb, mrb_value s, mrb_int i) +{ + if (i < 0) i = RSTRUCT_LEN(s) + i; + if (i < 0) + mrb_raisef(mrb, E_INDEX_ERROR, + "offset %S too small for struct(size:%S)", + mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); + if (RSTRUCT_LEN(s) <= i) + mrb_raisef(mrb, E_INDEX_ERROR, + "offset %S too large for struct(size:%S)", + mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); + return RSTRUCT_PTR(s)[i]; +} + +/* 15.2.18.4.2 */ +/* + * call-seq: + * struct[symbol] -> anObject + * struct[fixnum] -> anObject + * + * Attribute Reference---Returns the value of the instance variable + * named by <i>symbol</i>, or indexed (0..length-1) by + * <i>fixnum</i>. Will raise <code>NameError</code> if the named + * variable does not exist, or <code>IndexError</code> if the index is + * out of range. + * + * Customer = Struct.new(:name, :address, :zip) + * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) + * + * joe["name"] #=> "Joe Smith" + * joe[:name] #=> "Joe Smith" + * joe[0] #=> "Joe Smith" + */ +static mrb_value +mrb_struct_aref(mrb_state *mrb, mrb_value s) +{ + mrb_value idx; + + mrb_get_args(mrb, "o", &idx); + if (mrb_string_p(idx)) { + mrb_value sym = mrb_check_intern_str(mrb, idx); + + if (mrb_nil_p(sym)) { + mrb_name_error(mrb, mrb_intern_str(mrb, idx), "no member '%S' in struct", idx); + } + idx = sym; + } + if (mrb_symbol_p(idx)) { + return struct_aref_sym(mrb, s, mrb_symbol(idx)); + } + return struct_aref_int(mrb, s, mrb_int(mrb, idx)); +} + +static mrb_value +mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val) +{ + mrb_value members, *ptr; + const mrb_value *ptr_members; + mrb_int i, len; + + members = struct_members(mrb, s); + len = RARRAY_LEN(members); + ptr = RSTRUCT_PTR(s); + ptr_members = RARRAY_PTR(members); + for (i=0; i<len; i++) { + if (mrb_symbol(ptr_members[i]) == id) { + mrb_struct_modify(mrb, s); + ptr[i] = val; + return val; + } + } + mrb_name_error(mrb, id, "no member '%S' in struct", mrb_sym2str(mrb, id)); + return val; /* not reach */ +} + +/* 15.2.18.4.3 */ +/* + * call-seq: + * struct[symbol] = obj -> obj + * struct[fixnum] = obj -> obj + * + * Attribute Assignment---Assigns to the instance variable named by + * <i>symbol</i> or <i>fixnum</i> the value <i>obj</i> and + * returns it. Will raise a <code>NameError</code> if the named + * variable does not exist, or an <code>IndexError</code> if the index + * is out of range. + * + * Customer = Struct.new(:name, :address, :zip) + * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) + * + * joe["name"] = "Luke" + * joe[:zip] = "90210" + * + * joe.name #=> "Luke" + * joe.zip #=> "90210" + */ + +static mrb_value +mrb_struct_aset(mrb_state *mrb, mrb_value s) +{ + mrb_int i; + mrb_value idx; + mrb_value val; + + mrb_get_args(mrb, "oo", &idx, &val); + + if (mrb_string_p(idx)) { + mrb_value sym = mrb_check_intern_str(mrb, idx); + + if (mrb_nil_p(sym)) { + mrb_name_error(mrb, mrb_intern_str(mrb, idx), "no member '%S' in struct", idx); + } + idx = sym; + } + if (mrb_symbol_p(idx)) { + return mrb_struct_aset_sym(mrb, s, mrb_symbol(idx), val); + } + + i = mrb_int(mrb, idx); + if (i < 0) i = RSTRUCT_LEN(s) + i; + if (i < 0) { + mrb_raisef(mrb, E_INDEX_ERROR, + "offset %S too small for struct(size:%S)", + mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); + } + if (RSTRUCT_LEN(s) <= i) { + mrb_raisef(mrb, E_INDEX_ERROR, + "offset %S too large for struct(size:%S)", + mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); + } + mrb_struct_modify(mrb, s); + return RSTRUCT_PTR(s)[i] = val; +} + +/* 15.2.18.4.1 */ +/* + * call-seq: + * struct == other_struct -> true or false + * + * Equality---Returns <code>true</code> if <i>other_struct</i> is + * equal to this one: they must be of the same class as generated by + * <code>Struct::new</code>, and the values of all instance variables + * must be equal (according to <code>Object#==</code>). + * + * Customer = Struct.new(:name, :address, :zip) + * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) + * joejr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) + * jane = Customer.new("Jane Doe", "456 Elm, Anytown NC", 12345) + * joe == joejr #=> true + * joe == jane #=> false + */ + +static mrb_value +mrb_struct_equal(mrb_state *mrb, mrb_value s) +{ + mrb_value s2; + mrb_value *ptr, *ptr2; + mrb_int i, len; + + mrb_get_args(mrb, "o", &s2); + if (mrb_obj_equal(mrb, s, s2)) { + return mrb_true_value(); + } + if (mrb_obj_class(mrb, s) != mrb_obj_class(mrb, s2)) { + return mrb_false_value(); + } + if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) { + mrb_bug(mrb, "inconsistent struct"); /* should never happen */ + } + ptr = RSTRUCT_PTR(s); + ptr2 = RSTRUCT_PTR(s2); + len = RSTRUCT_LEN(s); + for (i=0; i<len; i++) { + if (!mrb_equal(mrb, ptr[i], ptr2[i])) { + return mrb_false_value(); + } + } + + return mrb_true_value(); +} + +/* 15.2.18.4.12(x) */ +/* + * code-seq: + * struct.eql?(other) -> true or false + * + * Two structures are equal if they are the same object, or if all their + * fields are equal (using <code>eql?</code>). + */ +static mrb_value +mrb_struct_eql(mrb_state *mrb, mrb_value s) +{ + mrb_value s2; + mrb_value *ptr, *ptr2; + mrb_int i, len; + + mrb_get_args(mrb, "o", &s2); + if (mrb_obj_equal(mrb, s, s2)) { + return mrb_true_value(); + } + if (mrb_obj_class(mrb, s) != mrb_obj_class(mrb, s2)) { + return mrb_false_value(); + } + if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) { + mrb_bug(mrb, "inconsistent struct"); /* should never happen */ + } + ptr = RSTRUCT_PTR(s); + ptr2 = RSTRUCT_PTR(s2); + len = RSTRUCT_LEN(s); + for (i=0; i<len; i++) { + if (!mrb_eql(mrb, ptr[i], ptr2[i])) { + return mrb_false_value(); + } + } + + return mrb_true_value(); +} + +/* + * call-seq: + * struct.length -> Fixnum + * struct.size -> Fixnum + * + * Returns number of struct members. + */ +static mrb_value +mrb_struct_len(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(RSTRUCT_LEN(self)); +} + +/* + * call-seq: + * struct.to_a -> array + * struct.values -> array + * + * Create an array from struct values. + */ +static mrb_value +mrb_struct_to_a(mrb_state *mrb, mrb_value self) +{ + return mrb_ary_new_from_values(mrb, RSTRUCT_LEN(self), RSTRUCT_PTR(self)); +} + +/* + * call-seq: + * struct.to_h -> hash + * + * Create a hash from member names and struct values. + */ +static mrb_value +mrb_struct_to_h(mrb_state *mrb, mrb_value self) +{ + mrb_value members, ret; + mrb_int i; + + members = struct_members(mrb, self); + ret = mrb_hash_new_capa(mrb, RARRAY_LEN(members)); + + for (i = 0; i < RARRAY_LEN(members); ++i) { + mrb_hash_set(mrb, ret, RARRAY_PTR(members)[i], RSTRUCT_PTR(self)[i]); + } + + return ret; +} + +static mrb_value +mrb_struct_values_at(mrb_state *mrb, mrb_value self) +{ + mrb_int argc; + mrb_value *argv; + + mrb_get_args(mrb, "*", &argv, &argc); + + return mrb_get_values_at(mrb, self, RSTRUCT_LEN(self), argc, argv, struct_aref_int); +} + +/* + * A <code>Struct</code> is a convenient way to bundle a number of + * attributes together, using accessor methods, without having to write + * an explicit class. + * + * The <code>Struct</code> class is a generator of specific classes, + * each one of which is defined to hold a set of variables and their + * accessors. In these examples, we'll call the generated class + * "<i>Customer</i>Class," and we'll show an example instance of that + * class as "<i>Customer</i>Inst." + * + * In the descriptions that follow, the parameter <i>symbol</i> refers + * to a symbol, which is either a quoted string or a + * <code>Symbol</code> (such as <code>:name</code>). + */ +void +mrb_mruby_struct_gem_init(mrb_state* mrb) +{ + struct RClass *st; + st = mrb_define_class(mrb, "Struct", mrb->object_class); + MRB_SET_INSTANCE_TT(st, MRB_TT_ARRAY); + + mrb_define_class_method(mrb, st, "new", mrb_struct_s_def, MRB_ARGS_ANY()); /* 15.2.18.3.1 */ + + mrb_define_method(mrb, st, "==", mrb_struct_equal, MRB_ARGS_REQ(1)); /* 15.2.18.4.1 */ + mrb_define_method(mrb, st, "[]", mrb_struct_aref, MRB_ARGS_REQ(1)); /* 15.2.18.4.2 */ + mrb_define_method(mrb, st, "[]=", mrb_struct_aset, MRB_ARGS_REQ(2)); /* 15.2.18.4.3 */ + mrb_define_method(mrb, st, "members", mrb_struct_members, MRB_ARGS_NONE()); /* 15.2.18.4.6 */ + mrb_define_method(mrb, st, "initialize", mrb_struct_initialize, MRB_ARGS_ANY()); /* 15.2.18.4.8 */ + mrb_define_method(mrb, st, "initialize_copy", mrb_struct_init_copy, MRB_ARGS_REQ(1)); /* 15.2.18.4.9 */ + mrb_define_method(mrb, st, "eql?", mrb_struct_eql, MRB_ARGS_REQ(1)); /* 15.2.18.4.12(x) */ + + mrb_define_method(mrb, st, "size", mrb_struct_len, MRB_ARGS_NONE()); + mrb_define_method(mrb, st, "length", mrb_struct_len, MRB_ARGS_NONE()); + mrb_define_method(mrb, st, "to_a", mrb_struct_to_a, MRB_ARGS_NONE()); + mrb_define_method(mrb, st, "values", mrb_struct_to_a, MRB_ARGS_NONE()); + mrb_define_method(mrb, st, "to_h", mrb_struct_to_h, MRB_ARGS_NONE()); + mrb_define_method(mrb, st, "values_at", mrb_struct_values_at, MRB_ARGS_ANY()); +} + +void +mrb_mruby_struct_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/test/struct.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/test/struct.rb new file mode 100644 index 000000000..421fe4b5d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-struct/test/struct.rb @@ -0,0 +1,212 @@ +## +# Struct ISO Test + +assert('Struct', '15.2.18') do + assert_equal Class, Struct.class +end + +assert('Struct.new', '15.2.18.3.1') do + c = Struct.new(:m1, :m2) + assert_equal Struct, c.superclass + assert_equal [:m1, :m2], c.members +end + +# Check crash bug with Struc.new and no params. +assert('Struct.new', '15.2.18.3.1') do + c = Struct.new() + assert_equal Struct, c.superclass + assert_equal [], c.members +end + +assert('Struct#==', '15.2.18.4.1') do + c = Struct.new(:m1, :m2) + cc1 = c.new(1,2) + cc2 = c.new(1,2) + assert_true cc1 == cc2 + + Struct.new(:m1, :m2) { def foo; end } + assert_raise(NoMethodError) { Struct.new(:m1).new.foo } +end + +assert('Struct#[]', '15.2.18.4.2') do + c = Struct.new(:m1, :m2) + cc = c.new(1,2) + assert_equal 1, cc[:m1] + assert_equal 2, cc["m2"] + assert_equal 1, cc[0] + assert_equal 2, cc[-1] + assert_raise(TypeError) { cc[[]] } + assert_raise(IndexError) { cc[2] } + assert_raise(NameError) { cc['tama'] } +end + +assert('Struct#[]=', '15.2.18.4.3') do + c = Struct.new(:m1, :m2) + cc = c.new(1,2) + cc[:m1] = 3 + assert_equal 3, cc[:m1] + cc["m2"] = 3 + assert_equal 3, cc["m2"] + cc[0] = 4 + assert_equal 4, cc[0] + cc[-1] = 5 + assert_equal 5, cc[-1] + assert_raise(TypeError) { cc[[]] = 3 } + assert_raise(IndexError) { cc[2] = 7 } + assert_raise(NameError) { cc['pochi'] = 8 } +end + +assert('Struct#each', '15.2.18.4.4') do + c = Struct.new(:m1, :m2) + cc = c.new(1,2) + a = [] + cc.each{|x| + a << x + } + assert_equal [1, 2], a +end + +assert('Struct#each_pair', '15.2.18.4.5') do + c = Struct.new(:m1, :m2) + cc = c.new(1,2) + a = [] + cc.each_pair{|k,v| + a << [k,v] + } + assert_equal [[:m1, 1], [:m2, 2]], a +end + +assert('Struct#members', '15.2.18.4.6') do + c = Struct.new(:m1, :m2) + assert_equal [:m1, :m2], c.new(1,2).members +end + +assert('Struct#select', '15.2.18.4.7') do + c = Struct.new(:m1, :m2) + assert_equal([2]) { c.new(1,2).select{|v| v % 2 == 0} } +end + +assert('large struct') do + c = Struct.new(:m1, :m2, :m3, :m4, :m5, :m6, :m7, :m8, :m9, :m10, :m11, :m12, :m13) + cc = c.new(1,2,3,4,5,6,7,8,9,10,11,12,13) + assert_equal 1, cc.m1 + assert_equal 2, cc.m2 + assert_equal 3, cc.m3 + assert_equal 4, cc.m4 + assert_equal 5, cc.m5 + assert_equal 6, cc.m6 + assert_equal 7, cc.m7 + assert_equal 8, cc.m8 + assert_equal 9, cc.m9 + assert_equal 10, cc.m10 + assert_equal 13, cc.m13 + + cc.m13 = 'test' + assert_equal 'test', cc.m13 + + assert_raise(NoMethodError) { cc.m14 } +end + +assert('wrong struct arg count') do + c = Struct.new(:m1) + assert_raise ArgumentError do + cc = c.new(1,2,3) + end +end + +assert('struct dup') do + c = Struct.new(:m1, :m2, :m3, :m4, :m5) + cc = c.new(1,2,3,4,5) + assert_nothing_raised { + assert_equal(cc, cc.dup) + } +end + +assert('struct inspect') do + c = Struct.new(:m1, :m2, :m3, :m4, :m5) + cc = c.new(1,2,3,4,5) + assert_equal "#<struct m1=1, m2=2, m3=3, m4=4, m5=5>", cc.inspect +end + +assert('Struct#length, Struct#size') do + s = Struct.new(:f1, :f2).new(0, 1) + assert_equal 2, s.size + assert_equal 2, s.length +end + +assert('Struct#to_a, Struct#values') do + s = Struct.new(:mem1, :mem2).new('a', 'b') + assert_equal ['a', 'b'], s.to_a + assert_equal ['a', 'b'], s.values +end + +assert('Struct#to_h') do + s = Struct.new(:white, :red, :green).new('ruuko', 'yuzuki', 'hitoe') + assert_equal(:white => 'ruuko', :red => 'yuzuki', :green => 'hitoe') { s.to_h } +end + +assert('Struct#values_at') do + a = Struct.new(:blue, :purple).new('aki', 'io') + assert_equal ['aki'], a.values_at(0) + assert_equal ['io', 'aki'], a.values_at(1, 0) + assert_raise(IndexError) { a.values_at 2 } +end + +assert("Struct#dig") do + a = Struct.new(:blue, :purple).new('aki', Struct.new(:red).new(1)) + assert_equal 'aki', a.dig(:blue) + assert_equal 1, a.dig(:purple, :red) + assert_equal 1, a.dig(1, 0) +end + +assert("Struct.new removes existing constant") do + skip "redefining Struct with same name cause warnings" + begin + assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b) + ensure + Struct.remove_const :Test + end +end + +assert("Struct#initialize_copy requires struct to be the same type") do + begin + Struct.new("Test", :a) + a = Struct::Test.new("a") + Struct.remove_const :Test + Struct.new("Test", :a, :b) + assert_raise(TypeError) do + a.initialize_copy(Struct::Test.new("a", "b")) + end + ensure + Struct.remove_const :Test + end +end + +assert("Struct.new does not allow array") do + assert_raise(TypeError) do + Struct.new("Test", [:a]) + end +end + +assert("Struct.new generates subclass of Struct") do + begin + original_struct = Struct + Struct = String + assert_equal original_struct, original_struct.new.superclass + ensure + Struct = original_struct + end +end + +assert 'Struct#freeze' do + c = Struct.new :m + + o = c.new + o.m = :test + assert_equal :test, o.m + + o.freeze + assert_raise(RuntimeError) { o.m = :modify } + assert_raise(RuntimeError) { o[:m] = :modify } + assert_equal :test, o.m +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/mrbgem.rake new file mode 100644 index 000000000..4f3fa43bb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-symbol-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Symbol class extension' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/mrblib/symbol.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/mrblib/symbol.rb new file mode 100644 index 000000000..1e3d24b80 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/mrblib/symbol.rb @@ -0,0 +1,65 @@ +class Symbol + include Comparable + + alias intern to_sym + + def to_proc + ->(obj,*args,&block) do + obj.__send__(self, *args, &block) + end + end + + ## + # call-seq: + # sym.capitalize -> symbol + # + # Same as <code>sym.to_s.capitalize.intern</code>. + + def capitalize + (self.to_s.capitalize! || self).to_sym + end + + ## + # call-seq: + # sym.downcase -> symbol + # + # Same as <code>sym.to_s.downcase.intern</code>. + + def downcase + (self.to_s.downcase! || self).to_sym + end + + ## + # call-seq: + # sym.upcase -> symbol + # + # Same as <code>sym.to_s.upcase.intern</code>. + + def upcase + (self.to_s.upcase! || self).to_sym + end + + ## + # call-seq: + # sym.casecmp(other) -> -1, 0, +1 or nil + # + # Case-insensitive version of <code>Symbol#<=></code>. + + def casecmp(other) + return nil unless other.kind_of?(Symbol) + lhs = self.to_s; lhs.upcase! + rhs = other.to_s; rhs.upcase! + lhs <=> rhs + end + + # + # call-seq: + # sym.empty? -> true or false + # + # Returns that _sym_ is :"" or not. + + def empty? + self.length == 0 + end + +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/src/symbol.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/src/symbol.c new file mode 100644 index 000000000..a992dbfce --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/src/symbol.c @@ -0,0 +1,64 @@ +#include <mruby.h> +#include <mruby/khash.h> +#include <mruby/array.h> + +typedef struct symbol_name { + size_t len; + const char *name; +} symbol_name; + +/* + * call-seq: + * Symbol.all_symbols => array + * + * Returns an array of all the symbols currently in Ruby's symbol + * table. + * + * Symbol.all_symbols.size #=> 903 + * Symbol.all_symbols[1,20] #=> [:floor, :ARGV, :Binding, :symlink, + * :chown, :EOFError, :$;, :String, + * :LOCK_SH, :"setuid?", :$<, + * :default_proc, :compact, :extend, + * :Tms, :getwd, :$=, :ThreadGroup, + * :wait2, :$>] + */ +static mrb_value +mrb_sym_all_symbols(mrb_state *mrb, mrb_value self) +{ + mrb_sym i, lim; + mrb_value ary = mrb_ary_new_capa(mrb, mrb->symidx); + + for (i=1, lim=mrb->symidx+1; i<lim; i++) { + mrb_ary_push(mrb, ary, mrb_symbol_value(i)); + } + + return ary; +} + +/* + * call-seq: + * sym.length -> integer + * + * Same as <code>sym.to_s.length</code>. + */ +static mrb_value +mrb_sym_length(mrb_state *mrb, mrb_value self) +{ + mrb_int len; + mrb_sym2name_len(mrb, mrb_symbol(self), &len); + return mrb_fixnum_value(len); +} + +void +mrb_mruby_symbol_ext_gem_init(mrb_state* mrb) +{ + struct RClass *s = mrb->symbol_class; + mrb_define_class_method(mrb, s, "all_symbols", mrb_sym_all_symbols, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "length", mrb_sym_length, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "size", mrb_sym_length, MRB_ARGS_NONE()); +} + +void +mrb_mruby_symbol_ext_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/test/symbol.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/test/symbol.rb new file mode 100644 index 000000000..6070d1418 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-symbol-ext/test/symbol.rb @@ -0,0 +1,48 @@ +## +# Symbol(Ext) Test + +assert('Symbol#to_proc') do + assert_equal 5, :abs.to_proc[-5] +end + +assert('Symbol.all_symbols') do + foo = [:__symbol_test_1, :__symbol_test_2, :__symbol_test_3].sort + symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort + assert_equal foo, symbols +end + +assert("Symbol#length") do + assert_equal 5, :hello.size + assert_equal 5, :mruby.length +end + +assert("Symbol#capitalize") do + assert_equal :Hello, :hello.capitalize + assert_equal :Hello, :HELLO.capitalize + assert_equal :Hello, :Hello.capitalize +end + +assert("Symbol#downcase") do + assert_equal :hello, :hEllO.downcase + assert_equal :hello, :hello.downcase +end + +assert("Symbol#upcase") do + assert_equal :HELLO, :hEllO.upcase + assert_equal :HELLO, :HELLO.upcase +end + +assert("Symbol#casecmp") do + assert_equal 0, :HELLO.casecmp(:hEllO) + assert_equal 1, :HELLO.casecmp(:hEllN) + assert_equal(-1, :HELLO.casecmp(:hEllP)) + assert_nil :HELLO.casecmp("hEllO") +end + +assert("Symbol#empty?") do + assert_true :''.empty? +end + +assert('Symbol#intern') do + assert_equal :test, :test.intern +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/README.md b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/README.md new file mode 100644 index 000000000..fa4b91e3a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/README.md @@ -0,0 +1,7 @@ +Running Tests +============= + +To run the tests, execute the following from the project's root directory. + + $ make test + diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/driver.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/driver.c new file mode 100644 index 000000000..14e93ff33 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/driver.c @@ -0,0 +1,172 @@ +/* +** mrbtest - Test for Embeddable Ruby +** +** This program runs Ruby test programs in test/t directory +** against the current mruby implementation. +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <mruby.h> +#include <mruby/proc.h> +#include <mruby/data.h> +#include <mruby/compile.h> +#include <mruby/string.h> +#include <mruby/variable.h> +#include <mruby/array.h> + +void +mrb_init_mrbtest(mrb_state *); + +/* Print a short remark for the user */ +static void +print_hint(void) +{ + printf("mrbtest - Embeddable Ruby Test\n\n"); +} + +static int +check_error(mrb_state *mrb) +{ + /* Error check */ + /* $ko_test and $kill_test should be 0 */ + mrb_value ko_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$ko_test")); + mrb_value kill_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$kill_test")); + + return mrb_fixnum_p(ko_test) && mrb_fixnum(ko_test) == 0 && mrb_fixnum_p(kill_test) && mrb_fixnum(kill_test) == 0; +} + +static int +eval_test(mrb_state *mrb) +{ + /* evaluate the test */ + mrb_funcall(mrb, mrb_top_self(mrb), "report", 0); + /* did an exception occur? */ + if (mrb->exc) { + mrb_print_error(mrb); + mrb->exc = 0; + return EXIT_FAILURE; + } + else if (!check_error(mrb)) { + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +static void +t_printstr(mrb_state *mrb, mrb_value obj) +{ + char *s; + int len; + + if (mrb_string_p(obj)) { + s = RSTRING_PTR(obj); + len = RSTRING_LEN(obj); + fwrite(s, len, 1, stdout); + } +} + +mrb_value +mrb_t_printstr(mrb_state *mrb, mrb_value self) +{ + mrb_value argv; + + mrb_get_args(mrb, "o", &argv); + t_printstr(mrb, argv); + + return argv; +} + +void +mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) +{ + struct RClass *krn, *mrbtest; + + krn = mrb->kernel_module; + mrb_define_method(mrb, krn, "__t_printstr__", mrb_t_printstr, MRB_ARGS_REQ(1)); + + mrbtest = mrb_define_module(mrb, "Mrbtest"); + + mrb_define_const(mrb, mrbtest, "FIXNUM_MAX", mrb_fixnum_value(MRB_INT_MAX)); + mrb_define_const(mrb, mrbtest, "FIXNUM_MIN", mrb_fixnum_value(MRB_INT_MIN)); + mrb_define_const(mrb, mrbtest, "FIXNUM_BIT", mrb_fixnum_value(MRB_INT_BIT)); + +#ifdef MRB_USE_FLOAT + mrb_define_const(mrb, mrbtest, "FLOAT_TOLERANCE", mrb_float_value(mrb, 1e-6)); +#else + mrb_define_const(mrb, mrbtest, "FLOAT_TOLERANCE", mrb_float_value(mrb, 1e-12)); +#endif + + if (verbose) { + mrb_gv_set(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"), mrb_true_value()); + } +} + +void +mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src) +{ + mrb_value res_src; + + if (mrb_src->exc) { + mrb_print_error(mrb_src); + exit(EXIT_FAILURE); + } + +#define TEST_COUNT_PASS(name) \ + do { \ + res_src = mrb_gv_get(mrb_src, mrb_intern_lit(mrb_src, "$" #name)); \ + if (mrb_fixnum_p(res_src)) { \ + mrb_value res_dst = mrb_gv_get(mrb_dst, mrb_intern_lit(mrb_dst, "$" #name)); \ + mrb_gv_set(mrb_dst, mrb_intern_lit(mrb_dst, "$" #name), mrb_fixnum_value(mrb_fixnum(res_dst) + mrb_fixnum(res_src))); \ + } \ + } while (FALSE) \ + + TEST_COUNT_PASS(ok_test); + TEST_COUNT_PASS(ko_test); + TEST_COUNT_PASS(kill_test); + +#undef TEST_COUNT_PASS + + res_src = mrb_gv_get(mrb_src, mrb_intern_lit(mrb_src, "$asserts")); + + if (mrb_array_p(res_src)) { + mrb_int i; + mrb_value res_dst = mrb_gv_get(mrb_dst, mrb_intern_lit(mrb_dst, "$asserts")); + for (i = 0; i < RARRAY_LEN(res_src); ++i) { + mrb_value val_src = RARRAY_PTR(res_src)[i]; + mrb_ary_push(mrb_dst, res_dst, mrb_str_new(mrb_dst, RSTRING_PTR(val_src), RSTRING_LEN(val_src))); + } + } +} + +int +main(int argc, char **argv) +{ + mrb_state *mrb; + int ret; + mrb_bool verbose = FALSE; + + print_hint(); + + /* new interpreter instance */ + mrb = mrb_open(); + if (mrb == NULL) { + fprintf(stderr, "Invalid mrb_state, exiting test driver"); + return EXIT_FAILURE; + } + + if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'v') { + printf("verbose mode: enable\n\n"); + verbose = TRUE; + } + + mrb_init_test_driver(mrb, verbose); + mrb_init_mrbtest(mrb); + ret = eval_test(mrb); + mrb_close(mrb); + + return ret; +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/init_mrbtest.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/init_mrbtest.c new file mode 100644 index 000000000..17ac1bdef --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/init_mrbtest.c @@ -0,0 +1,38 @@ +#include <stdlib.h> +#include <mruby.h> +#include <mruby/irep.h> +#include <mruby/variable.h> + +extern const uint8_t mrbtest_assert_irep[]; + +void mrbgemtest_init(mrb_state* mrb); +void mrb_init_test_driver(mrb_state* mrb, mrb_bool verbose); +void mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src); + +void +mrb_init_mrbtest(mrb_state *mrb) +{ + mrb_state *core_test; + + mrb_load_irep(mrb, mrbtest_assert_irep); + + core_test = mrb_open_core(mrb_default_allocf, NULL); + if (core_test == NULL) { + fprintf(stderr, "Invalid mrb_state, exiting %s", __FUNCTION__); + exit(EXIT_FAILURE); + } + mrb_init_test_driver(core_test, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose")))); + mrb_load_irep(core_test, mrbtest_assert_irep); + mrb_t_pass_result(mrb, core_test); + +#ifndef DISABLE_GEMS + mrbgemtest_init(mrb); +#endif + + if (mrb->exc) { + mrb_print_error(mrb); + exit(EXIT_FAILURE); + } + mrb_close(core_test); +} + diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/mrbgem.rake new file mode 100644 index 000000000..ae4c2f131 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-test/mrbgem.rake @@ -0,0 +1,187 @@ +MRuby::Gem::Specification.new('mruby-test') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'mruby test' + + build.bins << 'mrbtest' + spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') + + spec.test_rbfiles = Dir.glob("#{MRUBY_ROOT}/test/t/*.rb") + + clib = "#{build_dir}/mrbtest.c" + mlib = clib.ext(exts.object) + exec = exefile("#{build.build_dir}/bin/mrbtest") + + libmruby = libfile("#{build.build_dir}/lib/libmruby") + libmruby_core = libfile("#{build.build_dir}/lib/libmruby_core") + + mrbtest_lib = libfile("#{build_dir}/mrbtest") + mrbtest_objs = [] + + driver_obj = objfile("#{build_dir}/driver") + driver = "#{spec.dir}/driver.c" + + assert_c = "#{build_dir}/assert.c" + assert_rb = "#{MRUBY_ROOT}/test/assert.rb" + assert_lib = assert_c.ext(exts.object) + mrbtest_objs << assert_lib + + file assert_lib => assert_c + file assert_c => assert_rb do |t| + open(t.name, 'w') do |f| + mrbc.run f, assert_rb, 'mrbtest_assert_irep' + end + end + + gem_table = build.gems.generate_gem_table build + + build.gems.each do |g| + test_rbobj = g.test_rbireps.ext(exts.object) + g.test_objs << test_rbobj + dep_list = build.gems.tsort_dependencies(g.test_dependencies, gem_table).select(&:generate_functions) + + file test_rbobj => g.test_rbireps + file g.test_rbireps => [g.test_rbfiles].flatten do |t| + FileUtils.mkdir_p File.dirname(t.name) + open(t.name, 'w') do |f| + g.print_gem_test_header(f) + test_preload = g.test_preload and [g.dir, MRUBY_ROOT].map {|dir| + File.expand_path(g.test_preload, dir) + }.find {|file| File.exist?(file) } + + f.puts %Q[/*] + f.puts %Q[ * This file contains a test code for #{g.name} gem.] + f.puts %Q[ *] + f.puts %Q[ * IMPORTANT:] + f.puts %Q[ * This file was generated!] + f.puts %Q[ * All manual changes will get lost.] + f.puts %Q[ */] + if test_preload.nil? + f.puts %Q[extern const uint8_t mrbtest_assert_irep[];] + else + g.build.mrbc.run f, test_preload, "gem_test_irep_#{g.funcname}_preload" + end + g.test_rbfiles.flatten.each_with_index do |rbfile, i| + g.build.mrbc.run f, rbfile, "gem_test_irep_#{g.funcname}_#{i}" + end + f.puts %Q[void mrb_#{g.funcname}_gem_test(mrb_state *mrb);] unless g.test_objs.empty? + dep_list.each do |d| + f.puts %Q[void GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb_state *mrb);] + f.puts %Q[void GENERATED_TMP_mrb_#{d.funcname}_gem_final(mrb_state *mrb);] + end + f.puts %Q[void mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose);] + f.puts %Q[void mrb_t_pass_result(mrb_state *dst, mrb_state *src);] + f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb) {] + unless g.test_rbfiles.empty? + f.puts %Q[ mrb_state *mrb2;] + unless g.test_args.empty? + f.puts %Q[ mrb_value test_args_hash;] + end + f.puts %Q[ int ai;] + g.test_rbfiles.count.times do |i| + f.puts %Q[ ai = mrb_gc_arena_save(mrb);] + f.puts %Q[ mrb2 = mrb_open_core(mrb_default_allocf, NULL);] + f.puts %Q[ if (mrb2 == NULL) {] + f.puts %Q[ fprintf(stderr, "Invalid mrb_state, exiting \%s", __FUNCTION__);] + f.puts %Q[ exit(EXIT_FAILURE);] + f.puts %Q[ }] + dep_list.each do |d| + f.puts %Q[ GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb2);] + f.puts %Q[ mrb_state_atexit(mrb2, GENERATED_TMP_mrb_#{d.funcname}_gem_final);] + end + f.puts %Q[ mrb_init_test_driver(mrb2, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"))));] + if test_preload.nil? + f.puts %Q[ mrb_load_irep(mrb2, mrbtest_assert_irep);] + else + f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_preload);] + end + f.puts %Q[ if (mrb2->exc) {] + f.puts %Q[ mrb_print_error(mrb2);] + f.puts %Q[ exit(EXIT_FAILURE);] + f.puts %Q[ }] + f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "GEMNAME"), mrb_str_new(mrb2, "#{g.name}", #{g.name.length}));] + + unless g.test_args.empty? + f.puts %Q[ test_args_hash = mrb_hash_new_capa(mrb, #{g.test_args.length}); ] + g.test_args.each do |arg_name, arg_value| + escaped_arg_name = arg_name.gsub('\\', '\\\\\\\\').gsub('"', '\"') + escaped_arg_value = arg_value.gsub('\\', '\\\\\\\\').gsub('"', '\"') + f.puts %Q[ mrb_hash_set(mrb2, test_args_hash, mrb_str_new(mrb2, "#{escaped_arg_name.to_s}", #{escaped_arg_name.to_s.length}), mrb_str_new(mrb2, "#{escaped_arg_value.to_s}", #{escaped_arg_value.to_s.length})); ] + end + f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "TEST_ARGS"), test_args_hash); ] + end + + f.puts %Q[ mrb_#{g.funcname}_gem_test(mrb2);] if g.custom_test_init? + + f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_#{i});] + f.puts %Q[ ] + + f.puts %Q[ mrb_t_pass_result(mrb, mrb2);] + f.puts %Q[ mrb_close(mrb2);] + f.puts %Q[ mrb_gc_arena_restore(mrb, ai);] + end + end + f.puts %Q[}] + end + end + end + + build.gems.each do |v| + mrbtest_objs.concat v.test_objs + end + + file mrbtest_lib => mrbtest_objs do |t| + build.archiver.run t.name, t.prerequisites + end + + unless build.build_mrbtest_lib_only? + file exec => [driver_obj, mlib, mrbtest_lib, libmruby_core, libmruby] do |t| + gem_flags = build.gems.map { |g| g.linker.flags } + gem_flags_before_libraries = build.gems.map { |g| g.linker.flags_before_libraries } + gem_flags_after_libraries = build.gems.map { |g| g.linker.flags_after_libraries } + gem_libraries = build.gems.map { |g| g.linker.libraries } + gem_library_paths = build.gems.map { |g| g.linker.library_paths } + build.linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, gem_flags_before_libraries + end + end + + init = "#{spec.dir}/init_mrbtest.c" + + # store the last gem selection and make the re-build + # of the test gem depending on a change to the gem + # selection + active_gems = "#{build_dir}/active_gems.lst" + FileUtils.mkdir_p File.dirname(active_gems) + open(active_gems, 'w+') do |f| + build.gems.each do |g| + f.puts g.name + end + end + file clib => active_gems + + file mlib => clib + file clib => init do |t| + _pp "GEN", "*.rb", "#{clib.relative_path}" + FileUtils.mkdir_p File.dirname(clib) + open(clib, 'w') do |f| + f.puts %Q[/*] + f.puts %Q[ * This file contains a list of all] + f.puts %Q[ * test functions.] + f.puts %Q[ *] + f.puts %Q[ * IMPORTANT:] + f.puts %Q[ * This file was generated!] + f.puts %Q[ * All manual changes will get lost.] + f.puts %Q[ */] + f.puts %Q[] + f.puts IO.read(init) + build.gems.each do |g| + f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);] + end + f.puts %Q[void mrbgemtest_init(mrb_state* mrb) {] + build.gems.each do |g| + f.puts %Q[ GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb);] + end + f.puts %Q[}] + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/mrbgem.rake new file mode 100644 index 000000000..45b2ead72 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-time') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'standard Time class' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/mrblib/time.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/mrblib/time.rb new file mode 100644 index 000000000..df0d8ca82 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/mrblib/time.rb @@ -0,0 +1,9 @@ +class Time + def sunday?; wday == 0 end + def monday?; wday == 1 end + def tuesday?; wday == 2 end + def wednesday?; wday == 3 end + def thursday?; wday == 4 end + def friday?; wday == 5 end + def saturday?; wday == 6 end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/src/time.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/src/time.c new file mode 100644 index 000000000..5e8624830 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/src/time.c @@ -0,0 +1,869 @@ +/* +** time.c - Time class +** +** See Copyright Notice in mruby.h +*/ + +#include <math.h> +#include <time.h> +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/data.h> + +#ifndef DISABLE_STDIO +#include <stdio.h> +#else +#include <string.h> +#endif + +#define NDIV(x,y) (-(-((x)+1)/(y))-1) + +#if defined(_MSC_VER) && _MSC_VER < 1800 +double round(double x) { + return floor(x + 0.5); +} +#endif + +#if !defined(__MINGW64__) && defined(_WIN32) +# define llround(x) round(x) +#endif + +#if defined(__MINGW64__) || defined(__MINGW32__) +# include <sys/time.h> +#endif + +/** Time class configuration */ + +/* gettimeofday(2) */ +/* C99 does not have gettimeofday that is required to retrieve microseconds */ +/* uncomment following macro on platforms without gettimeofday(2) */ +/* #define NO_GETTIMEOFDAY */ + +/* gmtime(3) */ +/* C99 does not have reentrant gmtime_r() so it might cause troubles under */ +/* multi-threading environment. undef following macro on platforms that */ +/* does not have gmtime_r() and localtime_r(). */ +/* #define NO_GMTIME_R */ + +#ifdef _WIN32 +#if _MSC_VER +/* Win32 platform do not provide gmtime_r/localtime_r; emulate them using gmtime_s/localtime_s */ +#define gmtime_r(tp, tm) ((gmtime_s((tm), (tp)) == 0) ? (tm) : NULL) +#define localtime_r(tp, tm) ((localtime_s((tm), (tp)) == 0) ? (tm) : NULL) +#else +#define NO_GMTIME_R +#endif +#endif + +/* asctime(3) */ +/* mruby usually use its own implementation of struct tm to string conversion */ +/* except when DISABLE_STDIO is set. In that case, it uses asctime() or asctime_r(). */ +/* By default mruby tries to use asctime_r() which is reentrant. */ +/* Undef following macro on platforms that does not have asctime_r(). */ +/* #define NO_ASCTIME_R */ + +/* timegm(3) */ +/* mktime() creates tm structure for localtime; timegm() is for UTC time */ +/* define following macro to use probably faster timegm() on the platform */ +/* #define USE_SYSTEM_TIMEGM */ + +/** end of Time class configuration */ + +#ifndef NO_GETTIMEOFDAY +# ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN /* don't include winsock.h */ +# include <windows.h> +# define gettimeofday my_gettimeofday + +# ifdef _MSC_VER +# define UI64(x) x##ui64 +# else +# define UI64(x) x##ull +# endif + +typedef long suseconds_t; + +# if (!defined __MINGW64__) && (!defined __MINGW32__) +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; +# endif + +static int +gettimeofday(struct timeval *tv, void *tz) +{ + if (tz) { + mrb_assert(0); /* timezone is not supported */ + } + if (tv) { + union { + FILETIME ft; + unsigned __int64 u64; + } t; + GetSystemTimeAsFileTime(&t.ft); /* 100 ns intervals since Windows epoch */ + t.u64 -= UI64(116444736000000000); /* Unix epoch bias */ + t.u64 /= 10; /* to microseconds */ + tv->tv_sec = (time_t)(t.u64 / (1000 * 1000)); + tv->tv_usec = t.u64 % (1000 * 1000); + } + return 0; +} +# else +# include <sys/time.h> +# endif +#endif +#ifdef NO_GMTIME_R +#define gmtime_r(t,r) gmtime(t) +#define localtime_r(t,r) localtime(t) +#endif + +#ifndef USE_SYSTEM_TIMEGM +#define timegm my_timgm + +static unsigned int +is_leapyear(unsigned int y) +{ + return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0); +} + +static time_t +timegm(struct tm *tm) +{ + static const unsigned int ndays[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} + }; + time_t r = 0; + int i; + unsigned int *nday = (unsigned int*) ndays[is_leapyear(tm->tm_year+1900)]; + + for (i = 70; i < tm->tm_year; ++i) + r += is_leapyear(i+1900) ? 366*24*60*60 : 365*24*60*60; + for (i = 0; i < tm->tm_mon; ++i) + r += nday[i] * 24 * 60 * 60; + r += (tm->tm_mday - 1) * 24 * 60 * 60; + r += tm->tm_hour * 60 * 60; + r += tm->tm_min * 60; + r += tm->tm_sec; + return r; +} +#endif + +/* Since we are limited to using ISO C99, this implementation is based +* on time_t. That means the resolution of time is only precise to the +* second level. Also, there are only 2 timezones, namely UTC and LOCAL. +*/ + +enum mrb_timezone { + MRB_TIMEZONE_NONE = 0, + MRB_TIMEZONE_UTC = 1, + MRB_TIMEZONE_LOCAL = 2, + MRB_TIMEZONE_LAST = 3 +}; + +typedef struct mrb_timezone_name { + const char name[8]; + size_t len; +} mrb_timezone_name; + +static const mrb_timezone_name timezone_names[] = { + { "none", sizeof("none") - 1 }, + { "UTC", sizeof("UTC") - 1 }, + { "LOCAL", sizeof("LOCAL") - 1 }, +}; + +#ifndef DISABLE_STDIO +static const char mon_names[12][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", +}; + +static const char wday_names[7][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", +}; +#endif + +struct mrb_time { + time_t sec; + time_t usec; + enum mrb_timezone timezone; + struct tm datetime; +}; + +static const struct mrb_data_type mrb_time_type = { "Time", mrb_free }; + +/** Updates the datetime of a mrb_time based on it's timezone and +seconds setting. Returns self on success, NULL of failure. */ +static struct mrb_time* +time_update_datetime(mrb_state *mrb, struct mrb_time *self) +{ + struct tm *aid; + + if (self->timezone == MRB_TIMEZONE_UTC) { + aid = gmtime_r(&self->sec, &self->datetime); + } + else { + aid = localtime_r(&self->sec, &self->datetime); + } + if (!aid) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, (mrb_float)self->sec)); + /* not reached */ + return NULL; + } +#ifdef NO_GMTIME_R + self->datetime = *aid; /* copy data */ +#endif + + return self; +} + +static mrb_value +mrb_time_wrap(mrb_state *mrb, struct RClass *tc, struct mrb_time *tm) +{ + return mrb_obj_value(Data_Wrap_Struct(mrb, tc, &mrb_time_type, tm)); +} + +void mrb_check_num_exact(mrb_state *mrb, mrb_float num); + +/* Allocates a mrb_time object and initializes it. */ +static struct mrb_time* +time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) +{ + struct mrb_time *tm; + time_t tsec = 0; + + mrb_check_num_exact(mrb, (mrb_float)sec); + mrb_check_num_exact(mrb, (mrb_float)usec); + + if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) { + goto out_of_range; + } + if (sizeof(time_t) == 8 && (sec > (double)INT64_MAX || (double)INT64_MIN > sec)) { + goto out_of_range; + } + tsec = (time_t)sec; + if ((sec > 0 && tsec < 0) || (sec < 0 && (double)tsec > sec)) { + out_of_range: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); + } + tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time)); + tm->sec = tsec; + tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec); + if (tm->usec < 0) { + long sec2 = (long)NDIV(usec,1000000); /* negative div */ + tm->usec -= sec2 * 1000000; + tm->sec += sec2; + } + else if (tm->usec >= 1000000) { + long sec2 = (long)(usec / 1000000); + tm->usec -= sec2 * 1000000; + tm->sec += sec2; + } + tm->timezone = timezone; + time_update_datetime(mrb, tm); + + return tm; +} + +static mrb_value +mrb_time_make(mrb_state *mrb, struct RClass *c, double sec, double usec, enum mrb_timezone timezone) +{ + return mrb_time_wrap(mrb, c, time_alloc(mrb, sec, usec, timezone)); +} + +static struct mrb_time* +current_mrb_time(mrb_state *mrb) +{ + struct mrb_time *tm; + + tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); +#if defined(TIME_UTC) + { + struct timespec ts; + if (timespec_get(&ts, TIME_UTC) == 0) { + mrb_free(mrb, tm); + mrb_raise(mrb, E_RUNTIME_ERROR, "timespec_get() failed for unknown reasons"); + } + tm->sec = ts.tv_sec; + tm->usec = ts.tv_nsec / 1000; + } +#elif defined(NO_GETTIMEOFDAY) + { + static time_t last_sec = 0, last_usec = 0; + + tm->sec = time(NULL); + if (tm->sec != last_sec) { + last_sec = tm->sec; + last_usec = 0; + } + else { + /* add 1 usec to differentiate two times */ + last_usec += 1; + } + tm->usec = last_usec; + } +#else + { + struct timeval tv; + + gettimeofday(&tv, NULL); + tm->sec = tv.tv_sec; + tm->usec = tv.tv_usec; + } +#endif + tm->timezone = MRB_TIMEZONE_LOCAL; + time_update_datetime(mrb, tm); + + return tm; +} + +/* Allocates a new Time object with given millis value. */ +static mrb_value +mrb_time_now(mrb_state *mrb, mrb_value self) +{ + return mrb_time_wrap(mrb, mrb_class_ptr(self), current_mrb_time(mrb)); +} + +/* 15.2.19.6.1 */ +/* Creates an instance of time at the given time in seconds, etc. */ +static mrb_value +mrb_time_at(mrb_state *mrb, mrb_value self) +{ + mrb_float f, f2 = 0; + + mrb_get_args(mrb, "f|f", &f, &f2); + return mrb_time_make(mrb, mrb_class_ptr(self), f, f2, MRB_TIMEZONE_LOCAL); +} + +static struct mrb_time* +time_mktime(mrb_state *mrb, mrb_int ayear, mrb_int amonth, mrb_int aday, + mrb_int ahour, mrb_int amin, mrb_int asec, mrb_int ausec, + enum mrb_timezone timezone) +{ + time_t nowsecs; + struct tm nowtime = { 0 }; + + nowtime.tm_year = (int)ayear - 1900; + nowtime.tm_mon = (int)amonth - 1; + nowtime.tm_mday = (int)aday; + nowtime.tm_hour = (int)ahour; + nowtime.tm_min = (int)amin; + nowtime.tm_sec = (int)asec; + nowtime.tm_isdst = -1; + + if (nowtime.tm_mon < 0 || nowtime.tm_mon > 11 + || nowtime.tm_mday < 1 || nowtime.tm_mday > 31 + || nowtime.tm_hour < 0 || nowtime.tm_hour > 24 + || (nowtime.tm_hour == 24 && (nowtime.tm_min > 0 || nowtime.tm_sec > 0)) + || nowtime.tm_min < 0 || nowtime.tm_min > 59 + || nowtime.tm_sec < 0 || nowtime.tm_sec > 60) + mrb_raise(mrb, E_RUNTIME_ERROR, "argument out of range"); + + if (timezone == MRB_TIMEZONE_UTC) { + nowsecs = timegm(&nowtime); + } + else { + nowsecs = mktime(&nowtime); + } + if (nowsecs == (time_t)-1) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time."); + } + + return time_alloc(mrb, (double)nowsecs, ausec, timezone); +} + +/* 15.2.19.6.2 */ +/* Creates an instance of time at the given time in UTC. */ +static mrb_value +mrb_time_gm(mrb_state *mrb, mrb_value self) +{ + mrb_int ayear = 0, amonth = 1, aday = 1, ahour = 0, amin = 0, asec = 0, ausec = 0; + + mrb_get_args(mrb, "i|iiiiii", + &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec); + return mrb_time_wrap(mrb, mrb_class_ptr(self), + time_mktime(mrb, ayear, amonth, aday, ahour, amin, asec, ausec, MRB_TIMEZONE_UTC)); +} + + +/* 15.2.19.6.3 */ +/* Creates an instance of time at the given time in local time zone. */ +static mrb_value +mrb_time_local(mrb_state *mrb, mrb_value self) +{ + mrb_int ayear = 0, amonth = 1, aday = 1, ahour = 0, amin = 0, asec = 0, ausec = 0; + + mrb_get_args(mrb, "i|iiiiii", + &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec); + return mrb_time_wrap(mrb, mrb_class_ptr(self), + time_mktime(mrb, ayear, amonth, aday, ahour, amin, asec, ausec, MRB_TIMEZONE_LOCAL)); +} + +static struct mrb_time* +time_get_ptr(mrb_state *mrb, mrb_value time) +{ + struct mrb_time *tm; + + tm = DATA_GET_PTR(mrb, time, &mrb_time_type, struct mrb_time); + if (!tm) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized time"); + } + return tm; +} + +static mrb_value +mrb_time_eq(mrb_state *mrb, mrb_value self) +{ + mrb_value other; + struct mrb_time *tm1, *tm2; + mrb_bool eq_p; + + mrb_get_args(mrb, "o", &other); + tm1 = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time); + tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time); + eq_p = tm1 && tm2 && tm1->sec == tm2->sec && tm1->usec == tm2->usec; + + return mrb_bool_value(eq_p); +} + +static mrb_value +mrb_time_cmp(mrb_state *mrb, mrb_value self) +{ + mrb_value other; + struct mrb_time *tm1, *tm2; + + mrb_get_args(mrb, "o", &other); + tm1 = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time); + tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time); + if (!tm1 || !tm2) return mrb_nil_value(); + if (tm1->sec > tm2->sec) { + return mrb_fixnum_value(1); + } + else if (tm1->sec < tm2->sec) { + return mrb_fixnum_value(-1); + } + /* tm1->sec == tm2->sec */ + if (tm1->usec > tm2->usec) { + return mrb_fixnum_value(1); + } + else if (tm1->usec < tm2->usec) { + return mrb_fixnum_value(-1); + } + return mrb_fixnum_value(0); +} + +static mrb_value +mrb_time_plus(mrb_state *mrb, mrb_value self) +{ + mrb_float f; + struct mrb_time *tm; + + mrb_get_args(mrb, "f", &f); + tm = time_get_ptr(mrb, self); + return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec+f, (double)tm->usec, tm->timezone); +} + +static mrb_value +mrb_time_minus(mrb_state *mrb, mrb_value self) +{ + mrb_float f; + mrb_value other; + struct mrb_time *tm, *tm2; + + mrb_get_args(mrb, "o", &other); + tm = time_get_ptr(mrb, self); + tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time); + if (tm2) { + f = (mrb_float)(tm->sec - tm2->sec) + + (mrb_float)(tm->usec - tm2->usec) / 1.0e6; + return mrb_float_value(mrb, f); + } + else { + mrb_get_args(mrb, "f", &f); + return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec-f, (double)tm->usec, tm->timezone); + } +} + +/* 15.2.19.7.30 */ +/* Returns week day number of time. */ +static mrb_value +mrb_time_wday(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_fixnum_value(tm->datetime.tm_wday); +} + +/* 15.2.19.7.31 */ +/* Returns year day number of time. */ +static mrb_value +mrb_time_yday(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_fixnum_value(tm->datetime.tm_yday + 1); +} + +/* 15.2.19.7.32 */ +/* Returns year of time. */ +static mrb_value +mrb_time_year(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_fixnum_value(tm->datetime.tm_year + 1900); +} + +/* 15.2.19.7.33 */ +/* Returns name of time's timezone. */ +static mrb_value +mrb_time_zone(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + if (tm->timezone <= MRB_TIMEZONE_NONE) return mrb_nil_value(); + if (tm->timezone >= MRB_TIMEZONE_LAST) return mrb_nil_value(); + return mrb_str_new_static(mrb, + timezone_names[tm->timezone].name, + timezone_names[tm->timezone].len); +} + +/* 15.2.19.7.4 */ +/* Returns a string that describes the time. */ +static mrb_value +mrb_time_asctime(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm = time_get_ptr(mrb, self); + struct tm *d = &tm->datetime; + int len; + +#if defined(DISABLE_STDIO) + char *s; +# ifdef NO_ASCTIME_R + s = asctime(d); +# else + char buf[32]; + s = asctime_r(d, buf); +# endif + len = strlen(s)-1; /* truncate the last newline */ +#else + char buf[256]; + + len = snprintf(buf, sizeof(buf), "%s %s %02d %02d:%02d:%02d %s%d", + wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday, + d->tm_hour, d->tm_min, d->tm_sec, + tm->timezone == MRB_TIMEZONE_UTC ? "UTC " : "", + d->tm_year + 1900); +#endif + return mrb_str_new(mrb, buf, len); +} + +/* 15.2.19.7.6 */ +/* Returns the day in the month of the time. */ +static mrb_value +mrb_time_day(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_fixnum_value(tm->datetime.tm_mday); +} + + +/* 15.2.19.7.7 */ +/* Returns true if daylight saving was applied for this time. */ +static mrb_value +mrb_time_dst_p(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_bool_value(tm->datetime.tm_isdst); +} + +/* 15.2.19.7.8 */ +/* 15.2.19.7.10 */ +/* Returns the Time object of the UTC(GMT) timezone. */ +static mrb_value +mrb_time_getutc(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm, *tm2; + + tm = time_get_ptr(mrb, self); + tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); + *tm2 = *tm; + tm2->timezone = MRB_TIMEZONE_UTC; + time_update_datetime(mrb, tm2); + return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2); +} + +/* 15.2.19.7.9 */ +/* Returns the Time object of the LOCAL timezone. */ +static mrb_value +mrb_time_getlocal(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm, *tm2; + + tm = time_get_ptr(mrb, self); + tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); + *tm2 = *tm; + tm2->timezone = MRB_TIMEZONE_LOCAL; + time_update_datetime(mrb, tm2); + return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2); +} + +/* 15.2.19.7.15 */ +/* Returns hour of time. */ +static mrb_value +mrb_time_hour(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_fixnum_value(tm->datetime.tm_hour); +} + +/* 15.2.19.7.16 */ +/* Initializes a time by setting the amount of milliseconds since the epoch.*/ +static mrb_value +mrb_time_initialize(mrb_state *mrb, mrb_value self) +{ + mrb_int ayear = 0, amonth = 1, aday = 1, ahour = 0, + amin = 0, asec = 0, ausec = 0; + int n; + struct mrb_time *tm; + + n = mrb_get_args(mrb, "|iiiiiii", + &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec); + tm = (struct mrb_time*)DATA_PTR(self); + if (tm) { + mrb_free(mrb, tm); + } + mrb_data_init(self, NULL, &mrb_time_type); + + if (n == 0) { + tm = current_mrb_time(mrb); + } + else { + tm = time_mktime(mrb, ayear, amonth, aday, ahour, amin, asec, ausec, MRB_TIMEZONE_LOCAL); + } + mrb_data_init(self, tm, &mrb_time_type); + return self; +} + +/* 15.2.19.7.17(x) */ +/* Initializes a copy of this time object. */ +static mrb_value +mrb_time_initialize_copy(mrb_state *mrb, mrb_value copy) +{ + mrb_value src; + struct mrb_time *t1, *t2; + + mrb_get_args(mrb, "o", &src); + if (mrb_obj_equal(mrb, copy, src)) return copy; + if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) { + mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); + } + t1 = (struct mrb_time *)DATA_PTR(copy); + t2 = (struct mrb_time *)DATA_PTR(src); + if (!t2) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized time"); + } + if (!t1) { + t1 = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time)); + mrb_data_init(copy, t1, &mrb_time_type); + } + *t1 = *t2; + return copy; +} + +/* 15.2.19.7.18 */ +/* Sets the timezone attribute of the Time object to LOCAL. */ +static mrb_value +mrb_time_localtime(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + tm->timezone = MRB_TIMEZONE_LOCAL; + time_update_datetime(mrb, tm); + return self; +} + +/* 15.2.19.7.19 */ +/* Returns day of month of time. */ +static mrb_value +mrb_time_mday(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_fixnum_value(tm->datetime.tm_mday); +} + +/* 15.2.19.7.20 */ +/* Returns minutes of time. */ +static mrb_value +mrb_time_min(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_fixnum_value(tm->datetime.tm_min); +} + +/* 15.2.19.7.21 and 15.2.19.7.22 */ +/* Returns month of time. */ +static mrb_value +mrb_time_mon(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_fixnum_value(tm->datetime.tm_mon + 1); +} + +/* 15.2.19.7.23 */ +/* Returns seconds in minute of time. */ +static mrb_value +mrb_time_sec(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_fixnum_value(tm->datetime.tm_sec); +} + + +/* 15.2.19.7.24 */ +/* Returns a Float with the time since the epoch in seconds. */ +static mrb_value +mrb_time_to_f(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_float_value(mrb, (mrb_float)tm->sec + (mrb_float)tm->usec/1.0e6); +} + +/* 15.2.19.7.25 */ +/* Returns a Fixnum with the time since the epoch in seconds. */ +static mrb_value +mrb_time_to_i(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + if (tm->sec > MRB_INT_MAX || tm->sec < MRB_INT_MIN) { + return mrb_float_value(mrb, (mrb_float)tm->sec); + } + return mrb_fixnum_value((mrb_int)tm->sec); +} + +/* 15.2.19.7.26 */ +/* Returns a Float with the time since the epoch in microseconds. */ +static mrb_value +mrb_time_usec(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + if (tm->usec > MRB_INT_MAX || tm->usec < MRB_INT_MIN) { + return mrb_float_value(mrb, (mrb_float)tm->usec); + } + return mrb_fixnum_value((mrb_int)tm->usec); +} + +/* 15.2.19.7.27 */ +/* Sets the timezone attribute of the Time object to UTC. */ +static mrb_value +mrb_time_utc(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + tm->timezone = MRB_TIMEZONE_UTC; + time_update_datetime(mrb, tm); + return self; +} + +/* 15.2.19.7.28 */ +/* Returns true if this time is in the UTC timezone false if not. */ +static mrb_value +mrb_time_utc_p(mrb_state *mrb, mrb_value self) +{ + struct mrb_time *tm; + + tm = time_get_ptr(mrb, self); + return mrb_bool_value(tm->timezone == MRB_TIMEZONE_UTC); +} + + +void +mrb_mruby_time_gem_init(mrb_state* mrb) +{ + struct RClass *tc; + /* ISO 15.2.19.2 */ + tc = mrb_define_class(mrb, "Time", mrb->object_class); + MRB_SET_INSTANCE_TT(tc, MRB_TT_DATA); + mrb_include_module(mrb, tc, mrb_module_get(mrb, "Comparable")); + mrb_define_class_method(mrb, tc, "at", mrb_time_at, MRB_ARGS_ARG(1, 1)); /* 15.2.19.6.1 */ + mrb_define_class_method(mrb, tc, "gm", mrb_time_gm, MRB_ARGS_ARG(1,6)); /* 15.2.19.6.2 */ + mrb_define_class_method(mrb, tc, "local", mrb_time_local, MRB_ARGS_ARG(1,6)); /* 15.2.19.6.3 */ + mrb_define_class_method(mrb, tc, "mktime", mrb_time_local, MRB_ARGS_ARG(1,6));/* 15.2.19.6.4 */ + mrb_define_class_method(mrb, tc, "now", mrb_time_now, MRB_ARGS_NONE()); /* 15.2.19.6.5 */ + mrb_define_class_method(mrb, tc, "utc", mrb_time_gm, MRB_ARGS_ARG(1,6)); /* 15.2.19.6.6 */ + + mrb_define_method(mrb, tc, "==" , mrb_time_eq , MRB_ARGS_REQ(1)); + mrb_define_method(mrb, tc, "<=>" , mrb_time_cmp , MRB_ARGS_REQ(1)); /* 15.2.19.7.1 */ + mrb_define_method(mrb, tc, "+" , mrb_time_plus , MRB_ARGS_REQ(1)); /* 15.2.19.7.2 */ + mrb_define_method(mrb, tc, "-" , mrb_time_minus , MRB_ARGS_REQ(1)); /* 15.2.19.7.3 */ + mrb_define_method(mrb, tc, "to_s" , mrb_time_asctime, MRB_ARGS_NONE()); + mrb_define_method(mrb, tc, "inspect", mrb_time_asctime, MRB_ARGS_NONE()); + mrb_define_method(mrb, tc, "asctime", mrb_time_asctime, MRB_ARGS_NONE()); /* 15.2.19.7.4 */ + mrb_define_method(mrb, tc, "ctime" , mrb_time_asctime, MRB_ARGS_NONE()); /* 15.2.19.7.5 */ + mrb_define_method(mrb, tc, "day" , mrb_time_day , MRB_ARGS_NONE()); /* 15.2.19.7.6 */ + mrb_define_method(mrb, tc, "dst?" , mrb_time_dst_p , MRB_ARGS_NONE()); /* 15.2.19.7.7 */ + mrb_define_method(mrb, tc, "getgm" , mrb_time_getutc , MRB_ARGS_NONE()); /* 15.2.19.7.8 */ + mrb_define_method(mrb, tc, "getlocal",mrb_time_getlocal,MRB_ARGS_NONE()); /* 15.2.19.7.9 */ + mrb_define_method(mrb, tc, "getutc" , mrb_time_getutc , MRB_ARGS_NONE()); /* 15.2.19.7.10 */ + mrb_define_method(mrb, tc, "gmt?" , mrb_time_utc_p , MRB_ARGS_NONE()); /* 15.2.19.7.11 */ + mrb_define_method(mrb, tc, "gmtime" , mrb_time_utc , MRB_ARGS_NONE()); /* 15.2.19.7.13 */ + mrb_define_method(mrb, tc, "hour" , mrb_time_hour, MRB_ARGS_NONE()); /* 15.2.19.7.15 */ + mrb_define_method(mrb, tc, "localtime", mrb_time_localtime, MRB_ARGS_NONE()); /* 15.2.19.7.18 */ + mrb_define_method(mrb, tc, "mday" , mrb_time_mday, MRB_ARGS_NONE()); /* 15.2.19.7.19 */ + mrb_define_method(mrb, tc, "min" , mrb_time_min, MRB_ARGS_NONE()); /* 15.2.19.7.20 */ + + mrb_define_method(mrb, tc, "mon" , mrb_time_mon, MRB_ARGS_NONE()); /* 15.2.19.7.21 */ + mrb_define_method(mrb, tc, "month", mrb_time_mon, MRB_ARGS_NONE()); /* 15.2.19.7.22 */ + + mrb_define_method(mrb, tc, "sec" , mrb_time_sec, MRB_ARGS_NONE()); /* 15.2.19.7.23 */ + mrb_define_method(mrb, tc, "to_i", mrb_time_to_i, MRB_ARGS_NONE()); /* 15.2.19.7.25 */ + mrb_define_method(mrb, tc, "to_f", mrb_time_to_f, MRB_ARGS_NONE()); /* 15.2.19.7.24 */ + mrb_define_method(mrb, tc, "usec", mrb_time_usec, MRB_ARGS_NONE()); /* 15.2.19.7.26 */ + mrb_define_method(mrb, tc, "utc" , mrb_time_utc, MRB_ARGS_NONE()); /* 15.2.19.7.27 */ + mrb_define_method(mrb, tc, "utc?", mrb_time_utc_p,MRB_ARGS_NONE()); /* 15.2.19.7.28 */ + mrb_define_method(mrb, tc, "wday", mrb_time_wday, MRB_ARGS_NONE()); /* 15.2.19.7.30 */ + mrb_define_method(mrb, tc, "yday", mrb_time_yday, MRB_ARGS_NONE()); /* 15.2.19.7.31 */ + mrb_define_method(mrb, tc, "year", mrb_time_year, MRB_ARGS_NONE()); /* 15.2.19.7.32 */ + mrb_define_method(mrb, tc, "zone", mrb_time_zone, MRB_ARGS_NONE()); /* 15.2.19.7.33 */ + + mrb_define_method(mrb, tc, "initialize", mrb_time_initialize, MRB_ARGS_REQ(1)); /* 15.2.19.7.16 */ + mrb_define_method(mrb, tc, "initialize_copy", mrb_time_initialize_copy, MRB_ARGS_REQ(1)); /* 15.2.19.7.17 */ + + /* + methods not available: + gmt_offset(15.2.19.7.12) + gmtoff(15.2.19.7.14) + utc_offset(15.2.19.7.29) + */ +} + +void +mrb_mruby_time_gem_final(mrb_state* mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/test/time.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/test/time.rb new file mode 100644 index 000000000..52b931177 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-time/test/time.rb @@ -0,0 +1,228 @@ +## +# Time ISO Test + +assert('Time.new', '15.2.3.3.3') do + Time.new.class == Time +end + +assert('Time', '15.2.19') do + Time.class == Class +end + +assert('Time.at', '15.2.19.6.1') do + assert_kind_of(Time, Time.at(1300000000.0)) + + assert_raise(FloatDomainError) { Time.at(Float::NAN) } + assert_raise(FloatDomainError) { Time.at(Float::INFINITY) } + assert_raise(FloatDomainError) { Time.at(-Float::INFINITY) } + assert_raise(FloatDomainError) { Time.at(0, Float::NAN) } + assert_raise(FloatDomainError) { Time.at(0, Float::INFINITY) } + assert_raise(FloatDomainError) { Time.at(0, -Float::INFINITY) } +end + +assert('Time.gm', '15.2.19.6.2') do + Time.gm(2012, 12, 23) +end + +assert('Time.local', '15.2.19.6.3') do + Time.local(2012, 12, 23) +end + +assert('Time.mktime', '15.2.19.6.4') do + Time.mktime(2012, 12, 23) +end + +assert('Time.now', '15.2.19.6.5') do + Time.now.class == Time +end + +assert('Time.utc', '15.2.19.6.6') do + Time.utc(2012, 12, 23) +end + +assert('Time#+', '15.2.19.7.1') do + t1 = Time.at(1300000000.0) + t2 = t1.+(60) + + assert_equal(t2.utc.asctime, "Sun Mar 13 07:07:40 UTC 2011") + + assert_raise(FloatDomainError) { Time.at(0) + Float::NAN } + assert_raise(FloatDomainError) { Time.at(0) + Float::INFINITY } + assert_raise(FloatDomainError) { Time.at(0) + -Float::INFINITY } +end + +assert('Time#-', '15.2.19.7.2') do + t1 = Time.at(1300000000.0) + t2 = t1.-(60) + + assert_equal(t2.utc.asctime, "Sun Mar 13 07:05:40 UTC 2011") + + assert_raise(FloatDomainError) { Time.at(0) - Float::NAN } + assert_raise(FloatDomainError) { Time.at(0) - Float::INFINITY } + assert_raise(FloatDomainError) { Time.at(0) - -Float::INFINITY } +end + +assert('Time#<=>', '15.2.19.7.3') do + t1 = Time.at(1300000000.0) + t2 = Time.at(1400000000.0) + t3 = Time.at(1500000000.0) + + t2.<=>(t1) == 1 and + t2.<=>(t2) == 0 and + t2.<=>(t3) == -1 and + t2.<=>(nil) == nil +end + +assert('Time#asctime', '15.2.19.7.4') do + Time.at(1300000000.0).utc.asctime == "Sun Mar 13 07:06:40 UTC 2011" +end + +assert('Time#ctime', '15.2.19.7.5') do + Time.at(1300000000.0).utc.ctime == "Sun Mar 13 07:06:40 UTC 2011" +end + +assert('Time#day', '15.2.19.7.6') do + Time.gm(2012, 12, 23).day == 23 +end + +assert('Time#dst?', '15.2.19.7.7') do + not Time.gm(2012, 12, 23).utc.dst? +end + +assert('Time#getgm', '15.2.19.7.8') do + Time.at(1300000000.0).getgm.asctime == "Sun Mar 13 07:06:40 UTC 2011" +end + +assert('Time#getlocal', '15.2.19.7.9') do + t1 = Time.at(1300000000.0) + t2 = Time.at(1300000000.0) + t3 = t1.getlocal + + t1 == t3 and t3 == t2.getlocal +end + +assert('Time#getutc', '15.2.19.7.10') do + Time.at(1300000000.0).getutc.asctime == "Sun Mar 13 07:06:40 UTC 2011" +end + +assert('Time#gmt?', '15.2.19.7.11') do + Time.at(1300000000.0).utc.gmt? +end + +# ATM not implemented +# assert('Time#gmt_offset', '15.2.19.7.12') do + +assert('Time#gmtime', '15.2.19.7.13') do + Time.at(1300000000.0).gmtime +end + +# ATM not implemented +# assert('Time#gmtoff', '15.2.19.7.14') do + +assert('Time#hour', '15.2.19.7.15') do + Time.gm(2012, 12, 23, 7, 6).hour == 7 +end + +# ATM doesn't really work +# assert('Time#initialize', '15.2.19.7.16') do + +assert('Time#initialize_copy', '15.2.19.7.17') do + time_tmp_2 = Time.at(7.0e6) + time_tmp_2.clone == time_tmp_2 +end + +assert('Time#localtime', '15.2.19.7.18') do + t1 = Time.at(1300000000.0) + t2 = Time.at(1300000000.0) + + t1.localtime + t1 == t2.getlocal +end + +assert('Time#mday', '15.2.19.7.19') do + Time.gm(2012, 12, 23).mday == 23 +end + +assert('Time#min', '15.2.19.7.20') do + Time.gm(2012, 12, 23, 7, 6).min == 6 +end + +assert('Time#mon', '15.2.19.7.21') do + Time.gm(2012, 12, 23).mon == 12 +end + +assert('Time#month', '15.2.19.7.22') do + Time.gm(2012, 12, 23).month == 12 +end + +assert('Times#sec', '15.2.19.7.23') do + Time.gm(2012, 12, 23, 7, 6, 40).sec == 40 +end + +assert('Time#to_f', '15.2.19.7.24') do + Time.at(1300000000.0).to_f == 1300000000.0 +end + +assert('Time#to_i', '15.2.19.7.25') do + Time.at(1300000000.0).to_i == 1300000000 +end + +assert('Time#usec', '15.2.19.7.26') do + Time.at(1300000000.0).usec == 0 +end + +assert('Time#utc', '15.2.19.7.27') do + Time.at(1300000000.0).utc +end + +assert('Time#utc?', '15.2.19.7.28') do + Time.at(1300000000.0).utc.utc? +end + +# ATM not implemented +# assert('Time#utc_offset', '15.2.19.7.29') do + +assert('Time#wday', '15.2.19.7.30') do + Time.gm(2012, 12, 23).wday == 0 +end + +assert('Time#yday', '15.2.19.7.31') do + Time.gm(2012, 12, 23).yday == 358 +end + +assert('Time#year', '15.2.19.7.32') do + Time.gm(2012, 12, 23).year == 2012 +end + +assert('Time#zone', '15.2.19.7.33') do + Time.at(1300000000.0).utc.zone == 'UTC' +end + +# Not ISO specified + +assert('Time#to_s') do + Time.at(1300000000.0).utc.to_s == "Sun Mar 13 07:06:40 UTC 2011" +end + +assert('Time#inspect') do + Time.at(1300000000.0).utc.inspect == "Sun Mar 13 07:06:40 UTC 2011" +end + +assert('day of week methods') do + t = Time.gm(2012, 12, 24) + assert_false t.sunday? + assert_true t.monday? + assert_false t.tuesday? + assert_false t.wednesday? + assert_false t.thursday? + assert_false t.friday? + assert_false t.saturday? +end + +assert('2000 times 500us make a second') do + t = Time.utc 2015 + 2000.times do + t += 0.0005 + end + t.usec == 0 +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-toplevel-ext/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-toplevel-ext/mrbgem.rake new file mode 100644 index 000000000..ce77e0bcf --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-toplevel-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-toplevel-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'toplevel object (main) methods extension' +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-toplevel-ext/mrblib/toplevel.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-toplevel-ext/mrblib/toplevel.rb new file mode 100644 index 000000000..774562398 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-toplevel-ext/mrblib/toplevel.rb @@ -0,0 +1,11 @@ + +def self.include (*modules) + self.class.include(*modules) +end + +def self.private(*methods) +end +def self.protected(*methods) +end +def self.public(*methods) +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-toplevel-ext/test/toplevel.rb b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-toplevel-ext/test/toplevel.rb new file mode 100644 index 000000000..aebdd8b4b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-toplevel-ext/test/toplevel.rb @@ -0,0 +1,24 @@ +## +# Toplevel Self(Ext) Test + +assert('Toplevel#include') do + module ToplevelTestModule1 + def method_foo + :foo + end + + CONST_BAR = :bar + end + + module ToplevelTestModule2 + CONST_BAR = :bar2 + end + + self.include ToplevelTestModule2, ToplevelTestModule1 + + assert_true self.class.included_modules.include?( ToplevelTestModule1 ) + assert_true self.class.included_modules.include?( ToplevelTestModule2 ) + assert_equal :foo, method_foo + assert_equal :bar2, CONST_BAR +end + diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/00class.rb b/web/server/h2o/libh2o/deps/mruby/mrblib/00class.rb new file mode 100644 index 000000000..1a2d833c8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/00class.rb @@ -0,0 +1,28 @@ +class Module + # 15.2.2.4.12 + def attr_accessor(*names) + attr_reader(*names) + attr_writer(*names) + end + # 15.2.2.4.11 + def attr(name) + attr_reader(name) + end + + # 15.2.2.4.27 + def include(*args) + args.reverse.each do |m| + m.append_features(self) + m.included(self) + end + self + end + + def prepend(*args) + args.reverse.each do |m| + m.prepend_features(self) + m.prepended(self) + end + self + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/10error.rb b/web/server/h2o/libh2o/deps/mruby/mrblib/10error.rb new file mode 100644 index 000000000..22a8d1ad7 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/10error.rb @@ -0,0 +1,56 @@ +# ISO 15.2.24 +class ArgumentError < StandardError +end + +# ISO 15.2.25 says "LocalJumpError < StandardError" +class LocalJumpError < ScriptError +end + +# ISO 15.2.26 +class RangeError < StandardError +end + +class FloatDomainError < RangeError +end + +# ISO 15.2.26 +class RegexpError < StandardError +end + +# ISO 15.2.29 +class TypeError < StandardError +end + +# ISO 15.2.31 +class NameError < StandardError + attr_accessor :name + + def initialize(message=nil, name=nil) + @name = name + super(message) + end +end + +# ISO 15.2.32 +class NoMethodError < NameError + attr_reader :args + + def initialize(message=nil, name=nil, args=nil) + @args = args + super message, name + end +end + +# ISO 15.2.33 +class IndexError < StandardError +end + +class KeyError < IndexError +end + +class NotImplementedError < ScriptError +end + +class StopIteration < IndexError + attr_accessor :result +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/array.rb b/web/server/h2o/libh2o/deps/mruby/mrblib/array.rb new file mode 100644 index 000000000..a75ed6223 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/array.rb @@ -0,0 +1,243 @@ +# coding: utf-8 +## +# Array +# +# ISO 15.2.12 +class Array + + ## + # Calls the given block for each element of +self+ + # and pass the respective element. + # + # ISO 15.2.12.5.10 + def each(&block) + return to_enum :each unless block + + idx = 0 + while idx < length + block.call(self[idx]) + idx += 1 + end + self + end + + ## + # Calls the given block for each element of +self+ + # and pass the index of the respective element. + # + # ISO 15.2.12.5.11 + def each_index(&block) + return to_enum :each_index unless block + + idx = 0 + while idx < length + block.call(idx) + idx += 1 + end + self + end + + ## + # Calls the given block for each element of +self+ + # and pass the respective element. Each element will + # be replaced by the resulting values. + # + # ISO 15.2.12.5.7 + def collect!(&block) + return to_enum :collect! unless block + + idx = 0 + len = size + while idx < len + self[idx] = block.call self[idx] + idx += 1 + end + self + end + + ## + # Alias for collect! + # + # ISO 15.2.12.5.20 + alias map! collect! + + ## + # Private method for Array creation. + # + # ISO 15.2.12.5.15 + def initialize(size=0, obj=nil, &block) + raise TypeError, "expected Integer for 1st argument" unless size.kind_of? Integer + raise ArgumentError, "negative array size" if size < 0 + + self.clear + if size > 0 + self[size - 1] = nil # allocate + + idx = 0 + while idx < size + self[idx] = (block)? block.call(idx): obj + idx += 1 + end + end + + self + end + + def _inspect + return "[]" if self.size == 0 + "["+self.map{|x|x.inspect}.join(", ")+"]" + end + ## + # Return the contents of this array as a string. + # + # ISO 15.2.12.5.31 (x) + def inspect + begin + self._inspect + rescue SystemStackError + "[...]" + end + end + # ISO 15.2.12.5.32 (x) + alias to_s inspect + + ## + # Equality---Two arrays are equal if they contain the same number + # of elements and if each element is equal to (according to + # Object.==) the corresponding element in the other array. + # + # ISO 15.2.12.5.33 (x) + def ==(other) + other = self.__ary_eq(other) + return false if other == false + return true if other == true + len = self.size + i = 0 + while i < len + return false if self[i] != other[i] + i += 1 + end + return true + end + + ## + # Returns <code>true</code> if +self+ and _other_ are the same object, + # or are both arrays with the same content. + # + # ISO 15.2.12.5.34 (x) + def eql?(other) + other = self.__ary_eq(other) + return false if other == false + return true if other == true + len = self.size + i = 0 + while i < len + return false unless self[i].eql?(other[i]) + i += 1 + end + return true + end + + ## + # Comparison---Returns an integer (-1, 0, or +1) + # if this array is less than, equal to, or greater than <i>other_ary</i>. + # Each object in each array is compared (using <=>). If any value isn't + # equal, then that inequality is the return value. If all the + # values found are equal, then the return is based on a + # comparison of the array lengths. Thus, two arrays are + # "equal" according to <code>Array#<=></code> if and only if they have + # the same length and the value of each element is equal to the + # value of the corresponding element in the other array. + # + # ISO 15.2.12.5.36 (x) + def <=>(other) + other = self.__ary_cmp(other) + return 0 if 0 == other + return nil if nil == other + + len = self.size + n = other.size + len = n if len > n + i = 0 + while i < len + n = (self[i] <=> other[i]) + return n if n.nil? || n != 0 + i += 1 + end + len = self.size - other.size + if len == 0 + 0 + elsif len > 0 + 1 + else + -1 + end + end + + ## + # Delete element with index +key+ + def delete(key, &block) + while i = self.index(key) + self.delete_at(i) + ret = key + end + return block.call if ret.nil? && block + ret + end + + # internal method to convert multi-value to single value + def __svalue + return self.first if self.size < 2 + self + end +end + +## +# Array is enumerable +class Array + # ISO 15.2.12.3 + include Enumerable + + ## + # Quick sort + # a : the array to sort + # left : the beginning of sort region + # right : the end of sort region + def __sort_sub__(a, left, right, &block) + if left < right + i = left + j = right + pivot = a[i + (j - i) / 2] + while true + while ((block)? block.call(a[i], pivot): (a[i] <=> pivot)) < 0 + i += 1 + end + while ((block)? block.call(pivot, a[j]): (pivot <=> a[j])) < 0 + j -= 1 + end + break if (i >= j) + tmp = a[i]; a[i] = a[j]; a[j] = tmp; + i += 1 + j -= 1 + end + __sort_sub__(a, left, i-1, &block) + __sort_sub__(a, j+1, right, &block) + end + end + # private :__sort_sub__ + + ## + # Sort all elements and replace +self+ with these + # elements. + def sort!(&block) + size = self.size + if size > 1 + __sort_sub__(self, 0, size - 1, &block) + end + self + end + + def sort(&block) + self.dup.sort!(&block) + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/compar.rb b/web/server/h2o/libh2o/deps/mruby/mrblib/compar.rb new file mode 100644 index 000000000..84b962598 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/compar.rb @@ -0,0 +1,84 @@ +## +# Comparable +# +# ISO 15.3.3 +module Comparable + + ## + # Return true if +self+ is less + # than +other+. Otherwise return + # false. + # + # ISO 15.3.3.2.1 + def < other + cmp = self <=> other + if cmp.nil? + raise ArgumentError, "comparison of #{self.class} with #{other.class} failed" + end + cmp < 0 + end + + ## + # Return true if +self+ is less + # than or equal to +other+. + # Otherwise return false. + # + # ISO 15.3.3.2.2 + def <= other + cmp = self <=> other + if cmp.nil? + raise ArgumentError, "comparison of #{self.class} with #{other.class} failed" + end + cmp <= 0 + end + + ## + # Return true if +self+ is equal + # to +other+. Otherwise return + # false. + # + # ISO 15.3.3.2.3 + def == other + cmp = self <=> other + cmp == 0 + end + + ## + # Return true if +self+ is greater + # than +other+. Otherwise return + # false. + # + # ISO 15.3.3.2.4 + def > other + cmp = self <=> other + if cmp.nil? + raise ArgumentError, "comparison of #{self.class} with #{other.class} failed" + end + cmp > 0 + end + + ## + # Return true if +self+ is greater + # than or equal to +other+. + # Otherwise return false. + # + # ISO 15.3.3.2.5 + def >= other + cmp = self <=> other + if cmp.nil? + raise ArgumentError, "comparison of #{self.class} with #{other.class} failed" + end + cmp >= 0 + end + + ## + # Return true if +self+ is greater + # than or equal to +min+ and + # less than or equal to +max+. + # Otherwise return false. + # + # ISO 15.3.3.2.6 + def between?(min, max) + self >= min and self <= max + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/enum.rb b/web/server/h2o/libh2o/deps/mruby/mrblib/enum.rb new file mode 100644 index 000000000..12bd1d37b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/enum.rb @@ -0,0 +1,348 @@ +## +# Enumerable +# +# The <code>Enumerable</code> mixin provides collection classes with +# several traversal and searching methods, and with the ability to +# sort. The class must provide a method `each`, which +# yields successive members of the collection. If +# {Enumerable#max}, {#min}, or +# {#sort} is used, the objects in the collection must also +# implement a meaningful `<=>` operator, as these methods +# rely on an ordering between members of the collection. +# +# @ISO 15.3.2 +module Enumerable + + ## + # Call the given block for each element + # which is yield by +each+. Return false + # if one block value is false. Otherwise + # return true. If no block is given and + # +self+ is false return false. + # + # ISO 15.3.2.2.1 + def all?(&block) + if block + self.each{|*val| return false unless block.call(*val)} + else + self.each{|*val| return false unless val.__svalue} + end + true + end + + ## + # Call the given block for each element + # which is yield by +each+. Return true + # if one block value is true. Otherwise + # return false. If no block is given and + # +self+ is true object return true. + # + # ISO 15.3.2.2.2 + def any?(&block) + if block + self.each{|*val| return true if block.call(*val)} + else + self.each{|*val| return true if val.__svalue} + end + false + end + + ## + # Call the given block for each element + # which is yield by +each+. Append all + # values of each block together and + # return this value. + # + # ISO 15.3.2.2.3 + def collect(&block) + return to_enum :collect unless block + + ary = [] + self.each{|*val| ary.push(block.call(*val))} + ary + end + + ## + # Call the given block for each element + # which is yield by +each+. Return + # +ifnone+ if no block value was true. + # Otherwise return the first block value + # which had was true. + # + # ISO 15.3.2.2.4 + def detect(ifnone=nil, &block) + ret = ifnone + self.each{|*val| + if block.call(*val) + ret = val.__svalue + break + end + } + ret + end + + ## + # Call the given block for each element + # which is yield by +each+. Pass an + # index to the block which starts at 0 + # and increase by 1 for each element. + # + # ISO 15.3.2.2.5 + def each_with_index(&block) + return to_enum :each_with_index unless block + + i = 0 + self.each{|*val| + block.call(val.__svalue, i) + i += 1 + } + self + end + + ## + # Return an array of all elements which + # are yield by +each+. + # + # ISO 15.3.2.2.6 + def entries + ary = [] + self.each{|*val| + # __svalue is an internal method + ary.push val.__svalue + } + ary + end + + ## + # Alias for find + # + # ISO 15.3.2.2.7 + alias find detect + + ## + # Call the given block for each element + # which is yield by +each+. Return an array + # which contains all elements whose block + # value was true. + # + # ISO 15.3.2.2.8 + def find_all(&block) + return to_enum :find_all unless block + + ary = [] + self.each{|*val| + ary.push(val.__svalue) if block.call(*val) + } + ary + end + + ## + # Call the given block for each element + # which is yield by +each+ and which return + # value was true when invoking === with + # +pattern+. Return an array with all + # elements or the respective block values. + # + # ISO 15.3.2.2.9 + def grep(pattern, &block) + ary = [] + self.each{|*val| + sv = val.__svalue + if pattern === sv + ary.push((block)? block.call(*val): sv) + end + } + ary + end + + ## + # Return true if at least one element which + # is yield by +each+ returns a true value + # by invoking == with +obj+. Otherwise return + # false. + # + # ISO 15.3.2.2.10 + def include?(obj) + self.each{|*val| + return true if val.__svalue == obj + } + false + end + + ## + # Call the given block for each element + # which is yield by +each+. Return value + # is the sum of all block values. Pass + # to each block the current sum and the + # current element. + # + # ISO 15.3.2.2.11 + def inject(*args, &block) + raise ArgumentError, "too many arguments" if args.size > 2 + if Symbol === args[-1] + sym = args[-1] + block = ->(x,y){x.__send__(sym,y)} + args.pop + end + if args.empty? + flag = true # no initial argument + result = nil + else + flag = false + result = args[0] + end + self.each{|*val| + val = val.__svalue + if flag + # push first element as initial + flag = false + result = val + else + result = block.call(result, val) + end + } + result + end + alias reduce inject + + ## + # Alias for collect + # + # ISO 15.3.2.2.12 + alias map collect + + ## + # Return the maximum value of all elements + # yield by +each+. If no block is given <=> + # will be invoked to define this value. If + # a block is given it will be used instead. + # + # ISO 15.3.2.2.13 + def max(&block) + flag = true # 1st element? + result = nil + self.each{|*val| + val = val.__svalue + if flag + # 1st element + result = val + flag = false + else + if block + result = val if block.call(val, result) > 0 + else + result = val if (val <=> result) > 0 + end + end + } + result + end + + ## + # Return the minimum value of all elements + # yield by +each+. If no block is given <=> + # will be invoked to define this value. If + # a block is given it will be used instead. + # + # ISO 15.3.2.2.14 + def min(&block) + flag = true # 1st element? + result = nil + self.each{|*val| + val = val.__svalue + if flag + # 1st element + result = val + flag = false + else + if block + result = val if block.call(val, result) < 0 + else + result = val if (val <=> result) < 0 + end + end + } + result + end + + ## + # Alias for include? + # + # ISO 15.3.2.2.15 + alias member? include? + + ## + # Call the given block for each element + # which is yield by +each+. Return an + # array which contains two arrays. The + # first array contains all elements + # whose block value was true. The second + # array contains all elements whose + # block value was false. + # + # ISO 15.3.2.2.16 + def partition(&block) + ary_T = [] + ary_F = [] + self.each{|*val| + if block.call(*val) + ary_T.push(val.__svalue) + else + ary_F.push(val.__svalue) + end + } + [ary_T, ary_F] + end + + ## + # Call the given block for each element + # which is yield by +each+. Return an + # array which contains only the elements + # whose block value was false. + # + # ISO 15.3.2.2.17 + def reject(&block) + ary = [] + self.each{|*val| + ary.push(val.__svalue) unless block.call(*val) + } + ary + end + + ## + # Alias for find_all. + # + # ISO 15.3.2.2.18 + alias select find_all + + ## + # Return a sorted array of all elements + # which are yield by +each+. If no block + # is given <=> will be invoked on each + # element to define the order. Otherwise + # the given block will be used for + # sorting. + # + # ISO 15.3.2.2.19 + def sort(&block) + self.map{|*val| val.__svalue}.sort + end + + ## + # Alias for entries. + # + # ISO 15.3.2.2.20 + alias to_a entries + + # redefine #hash 15.3.1.3.15 + def hash + h = 12347 + i = 0 + self.each do |e| + n = (e.hash & (0x7fffffff >> (i % 16))) << (i % 16) + h ^= n + i += 1 + end + h + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/hash.rb b/web/server/h2o/libh2o/deps/mruby/mrblib/hash.rb new file mode 100644 index 000000000..6b4803ccb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/hash.rb @@ -0,0 +1,358 @@ +## +# Hash +# +# ISO 15.2.13 +class Hash + ## + # Equality---Two hashes are equal if they each contain the same number + # of keys and if each key-value pair is equal to (according to + # <code>Object#==</code>) the corresponding elements in the other + # hash. + # + # ISO 15.2.13.4.1 + def ==(hash) + return true if self.equal?(hash) + begin + hash = hash.to_hash + rescue NoMethodError + return false + end + return false if self.size != hash.size + self.each do |k,v| + return false unless hash.key?(k) + return false unless self[k] == hash[k] + end + return true + end + + ## + # Returns <code>true</code> if <i>hash</i> and <i>other</i> are + # both hashes with the same content compared by eql?. + # + # ISO 15.2.13.4.32 (x) + def eql?(hash) + return true if self.equal?(hash) + begin + hash = hash.to_hash + rescue NoMethodError + return false + end + return false if self.size != hash.size + self.each do |k,v| + return false unless hash.key?(k) + return false unless self[k].eql?(hash[k]) + end + return true + end + + ## + # Delete the element with the key +key+. + # Return the value of the element if +key+ + # was found. Return nil if nothing was + # found. If a block is given, call the + # block with the value of the element. + # + # ISO 15.2.13.4.8 + def delete(key, &block) + if block && !self.has_key?(key) + block.call(key) + else + self.__delete(key) + end + end + + ## + # Calls the given block for each element of +self+ + # and pass the key and value of each element. + # + # call-seq: + # hsh.each {| key, value | block } -> hsh + # hsh.each_pair {| key, value | block } -> hsh + # hsh.each -> an_enumerator + # hsh.each_pair -> an_enumerator + # + # + # If no block is given, an enumerator is returned instead. + # + # h = { "a" => 100, "b" => 200 } + # h.each {|key, value| puts "#{key} is #{value}" } + # + # <em>produces:</em> + # + # a is 100 + # b is 200 + # + # ISO 15.2.13.4.9 + def each(&block) + return to_enum :each unless block + + keys = self.keys + vals = self.values + len = self.size + i = 0 + while i < len + block.call [keys[i], vals[i]] + i += 1 + end + self + end + + ## + # Calls the given block for each element of +self+ + # and pass the key of each element. + # + # call-seq: + # hsh.each_key {| key | block } -> hsh + # hsh.each_key -> an_enumerator + # + # If no block is given, an enumerator is returned instead. + # + # h = { "a" => 100, "b" => 200 } + # h.each_key {|key| puts key } + # + # <em>produces:</em> + # + # a + # b + # + # ISO 15.2.13.4.10 + def each_key(&block) + return to_enum :each_key unless block + + self.keys.each{|k| block.call(k)} + self + end + + ## + # Calls the given block for each element of +self+ + # and pass the value of each element. + # + # call-seq: + # hsh.each_value {| value | block } -> hsh + # hsh.each_value -> an_enumerator + # + # If no block is given, an enumerator is returned instead. + # + # h = { "a" => 100, "b" => 200 } + # h.each_value {|value| puts value } + # + # <em>produces:</em> + # + # 100 + # 200 + # + # ISO 15.2.13.4.11 + def each_value(&block) + return to_enum :each_value unless block + + self.keys.each{|k| block.call(self[k])} + self + end + + ## + # Replaces the contents of <i>hsh</i> with the contents of other hash + # + # ISO 15.2.13.4.23 + def replace(hash) + raise TypeError, "can't convert argument into Hash" unless hash.respond_to?(:to_hash) + self.clear + hash = hash.to_hash + hash.each_key{|k| + self[k] = hash[k] + } + if hash.default_proc + self.default_proc = hash.default_proc + else + self.default = hash.default + end + self + end + # ISO 15.2.13.4.17 + alias initialize_copy replace + + ## + # Return a hash which contains the content of + # +self+ and +other+. If a block is given + # it will be called for each element with + # a duplicate key. The value of the block + # will be the final value of this element. + # + # ISO 15.2.13.4.22 + def merge(other, &block) + h = {} + raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash) + other = other.to_hash + self.each_key{|k| h[k] = self[k]} + if block + other.each_key{|k| + h[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k] + } + else + other.each_key{|k| h[k] = other[k]} + end + h + end + + # internal method for Hash inspection + def _inspect + return "{}" if self.size == 0 + "{"+self.map {|k,v| + k._inspect + "=>" + v._inspect + }.join(", ")+"}" + end + ## + # Return the contents of this hash as a string. + # + # ISO 15.2.13.4.30 (x) + def inspect + begin + self._inspect + rescue SystemStackError + "{...}" + end + end + # ISO 15.2.13.4.31 (x) + alias to_s inspect + + ## + # call-seq: + # hsh.reject! {| key, value | block } -> hsh or nil + # hsh.reject! -> an_enumerator + # + # Equivalent to <code>Hash#delete_if</code>, but returns + # <code>nil</code> if no changes were made. + # + # 1.8/1.9 Hash#reject! returns Hash; ISO says nothing. + # + def reject!(&block) + return to_enum :reject! unless block + + keys = [] + self.each{|k,v| + if block.call([k, v]) + keys.push(k) + end + } + return nil if keys.size == 0 + keys.each{|k| + self.delete(k) + } + self + end + + ## + # call-seq: + # hsh.reject {|key, value| block} -> a_hash + # hsh.reject -> an_enumerator + # + # Returns a new hash consisting of entries for which the block returns false. + # + # If no block is given, an enumerator is returned instead. + # + # h = { "a" => 100, "b" => 200, "c" => 300 } + # h.reject {|k,v| k < "b"} #=> {"b" => 200, "c" => 300} + # h.reject {|k,v| v > 100} #=> {"a" => 100} + # + # 1.8/1.9 Hash#reject returns Hash; ISO says nothing. + # + def reject(&block) + return to_enum :reject unless block + + h = {} + self.each{|k,v| + unless block.call([k, v]) + h[k] = v + end + } + h + end + + ## + # call-seq: + # hsh.select! {| key, value | block } -> hsh or nil + # hsh.select! -> an_enumerator + # + # Equivalent to <code>Hash#keep_if</code>, but returns + # <code>nil</code> if no changes were made. + # + # 1.9 Hash#select! returns Hash; ISO says nothing. + # + def select!(&block) + return to_enum :select! unless block + + keys = [] + self.each{|k,v| + unless block.call([k, v]) + keys.push(k) + end + } + return nil if keys.size == 0 + keys.each{|k| + self.delete(k) + } + self + end + + ## + # call-seq: + # hsh.select {|key, value| block} -> a_hash + # hsh.select -> an_enumerator + # + # Returns a new hash consisting of entries for which the block returns true. + # + # If no block is given, an enumerator is returned instead. + # + # h = { "a" => 100, "b" => 200, "c" => 300 } + # h.select {|k,v| k > "a"} #=> {"b" => 200, "c" => 300} + # h.select {|k,v| v < 200} #=> {"a" => 100} + # + # 1.9 Hash#select returns Hash; ISO says nothing + # + def select(&block) + return to_enum :select unless block + + h = {} + self.each{|k,v| + if block.call([k, v]) + h[k] = v + end + } + h + end + + ## + # call-seq: + # hsh.rehash -> hsh + # + # Rebuilds the hash based on the current hash values for each key. If + # values of key objects have changed since they were inserted, this + # method will reindex <i>hsh</i>. + # + # h = {"AAA" => "b"} + # h.keys[0].chop! + # h #=> {"AA"=>"b"} + # h["AA"] #=> nil + # h.rehash #=> {"AA"=>"b"} + # h["AA"] #=> "b" + # + def rehash + h = {} + self.each{|k,v| + h[k] = v + } + self.replace(h) + end + + def __update(h) + h.each_key{|k| self[k] = h[k]} + self + end +end + +## +# Hash is enumerable +# +# ISO 15.2.13.3 +class Hash + include Enumerable +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/init_mrblib.c b/web/server/h2o/libh2o/deps/mruby/mrblib/init_mrblib.c new file mode 100644 index 000000000..4d4bcd25a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/init_mrblib.c @@ -0,0 +1,11 @@ +#include <mruby.h> +#include <mruby/irep.h> + +extern const uint8_t mrblib_irep[]; + +void +mrb_init_mrblib(mrb_state *mrb) +{ + mrb_load_irep(mrb, mrblib_irep); +} + diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/kernel.rb b/web/server/h2o/libh2o/deps/mruby/mrblib/kernel.rb new file mode 100644 index 000000000..550ae8172 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/kernel.rb @@ -0,0 +1,50 @@ +## +# Kernel +# +# ISO 15.3.1 +module Kernel + + # 15.3.1.2.1 Kernel.` + # provided by Kernel#` + # 15.3.1.3.5 + def `(s) + raise NotImplementedError.new("backquotes not implemented") + end + + ## + # 15.3.1.2.3 Kernel.eval + # 15.3.1.3.12 Kernel#eval + # NotImplemented by mruby core; use mruby-eval gem + + ## + # ISO 15.3.1.2.8 Kernel.loop + # provided by Kernel#loop + + ## + # Calls the given block repetitively. + # + # ISO 15.3.1.3.29 + def loop(&block) + return to_enum :loop unless block + + while true + yield + end + rescue StopIteration => e + e.result + end + + # 11.4.4 Step c) + def !~(y) + !(self =~ y) + end + + # internal method for inspect + def _inspect + self.inspect + end + + def to_enum(*a) + raise NotImplementedError.new("fiber required for enumerator") + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/mrblib.rake b/web/server/h2o/libh2o/deps/mruby/mrblib/mrblib.rake new file mode 100644 index 000000000..19fd00d66 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/mrblib.rake @@ -0,0 +1,18 @@ +MRuby.each_target do + current_dir = File.dirname(__FILE__) + relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) + current_build_dir = "#{build_dir}/#{relative_from_root}" + + self.libmruby << objfile("#{current_build_dir}/mrblib") + + file objfile("#{current_build_dir}/mrblib") => "#{current_build_dir}/mrblib.c" + file "#{current_build_dir}/mrblib.c" => [mrbcfile, __FILE__] + Dir.glob("#{current_dir}/*.rb").sort do |t| + _, _, *rbfiles = t.prerequisites + FileUtils.mkdir_p File.dirname(t.name) + open(t.name, 'w') do |f| + _pp "GEN", "*.rb", "#{t.name.relative_path}" + f.puts File.read("#{current_dir}/init_mrblib.c") + mrbc.run f, rbfiles, 'mrblib_irep' + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/numeric.rb b/web/server/h2o/libh2o/deps/mruby/mrblib/numeric.rb new file mode 100644 index 000000000..89401a084 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/numeric.rb @@ -0,0 +1,173 @@ +## +# Numeric +# +# ISO 15.2.7 +class Numeric + include Comparable + ## + # Returns the receiver simply. + # + # ISO 15.2.7.4.1 + def +@ + self + end + + ## + # Returns the receiver's value, negated. + # + # ISO 15.2.7.4.2 + def -@ + 0 - self + end + + ## + # Returns the absolute value of the receiver. + # + # ISO 15.2.7.4.3 + def abs + if self < 0 + -self + else + self + end + end +end + +## +# Integral +# +# mruby special - module to share methods between Floats and Integers +# to make them compatible +module Integral + ## + # Calls the given block once for each Integer + # from +self+ downto +num+. + # + # ISO 15.2.8.3.15 + def downto(num, &block) + return to_enum(:downto, num) unless block + + i = self.to_i + while i >= num + block.call(i) + i -= 1 + end + self + end + + ## + # Returns self + 1 + # + # ISO 15.2.8.3.19 + def next + self + 1 + end + # ISO 15.2.8.3.21 + alias succ next + + ## + # Calls the given block +self+ times. + # + # ISO 15.2.8.3.22 + def times &block + return to_enum :times unless block + + i = 0 + while i < self + block.call i + i += 1 + end + self + end + + ## + # Calls the given block once for each Integer + # from +self+ upto +num+. + # + # ISO 15.2.8.3.27 + def upto(num, &block) + return to_enum(:upto, num) unless block + + i = self.to_i + while i <= num + block.call(i) + i += 1 + end + self + end + + ## + # Calls the given block from +self+ to +num+ + # incremented by +step+ (default 1). + # + def step(num=nil, step=1, &block) + raise ArgumentError, "step can't be 0" if step == 0 + return to_enum(:step, num, step) unless block + + i = if num.kind_of? Float then self.to_f else self end + if num == nil + while true + block.call(i) + i+=step + end + return self + end + if step > 0 + while i <= num + block.call(i) + i += step + end + else + while i >= num + block.call(i) + i += step + end + end + self + end +end + +## +# Integer +# +# ISO 15.2.8 +class Integer + include Integral + ## + # Returns the receiver simply. + # + # ISO 15.2.8.3.14 + def ceil + self + end + + ## + # Returns the receiver simply. + # + # ISO 15.2.8.3.17 + def floor + self + end + + ## + # Returns the receiver simply. + # + # ISO 15.2.8.3.24 + alias round floor + + ## + # Returns the receiver simply. + # + # ISO 15.2.8.3.26 + alias truncate floor +end + +## +# Float +# +# ISO 15.2.9 +class Float + # mruby special - since mruby integers may be upgraded to floats, + # floats should be compatible to integers. + include Integral +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/range.rb b/web/server/h2o/libh2o/deps/mruby/mrblib/range.rb new file mode 100644 index 000000000..5bd2521e8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/range.rb @@ -0,0 +1,67 @@ +## +# Range +# +# ISO 15.2.14 +class Range + + ## + # Calls the given block for each element of +self+ + # and pass the respective element. + # + # ISO 15.2.14.4.4 + def each(&block) + return to_enum :each unless block + + val = self.first + last = self.last + + if val.kind_of?(Fixnum) && last.kind_of?(Fixnum) # fixnums are special + lim = last + lim += 1 unless exclude_end? + i = val + while i < lim + block.call(i) + i += 1 + end + return self + end + + if val.kind_of?(String) && last.kind_of?(String) # fixnums are special + if val.respond_to? :upto + return val.upto(last, exclude_end?, &block) + else + str_each = true + end + end + + raise TypeError, "can't iterate" unless val.respond_to? :succ + + return self if (val <=> last) > 0 + + while (val <=> last) < 0 + block.call(val) + val = val.succ + if str_each + break if val.size > last.size + end + end + + block.call(val) if !exclude_end? && (val <=> last) == 0 + self + end + + # redefine #hash 15.3.1.3.15 + def hash + h = first.hash ^ last.hash + h += 1 if self.exclude_end? + h + end +end + +## +# Range is enumerable +# +# ISO 15.2.14.3 +class Range + include Enumerable +end diff --git a/web/server/h2o/libh2o/deps/mruby/mrblib/string.rb b/web/server/h2o/libh2o/deps/mruby/mrblib/string.rb new file mode 100644 index 000000000..4c6114ecb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrblib/string.rb @@ -0,0 +1,275 @@ +## +# String +# +# ISO 15.2.10 +class String + include Comparable + ## + # Calls the given block for each line + # and pass the respective line. + # + # ISO 15.2.10.5.15 + def each_line(rs = "\n", &block) + return to_enum(:each_line, rs, &block) unless block + return block.call(self) if rs.nil? + rs = rs.to_str + offset = 0 + rs_len = rs.length + this = dup + while pos = this.index(rs, offset) + block.call(this[offset, pos + rs_len - offset]) + offset = pos + rs_len + end + block.call(this[offset, this.size - offset]) if this.size > offset + self + end + + # private method for gsub/sub + def __sub_replace(pre, m, post) + s = "" + i = 0 + while j = index("\\", i) + break if j == length-1 + t = case self[j+1] + when "\\" + "\\" + when "`" + pre + when "&", "0" + m + when "'" + post + when "1", "2", "3", "4", "5", "6", "7", "8", "9" + "" + else + self[j, 2] + end + s += self[i, j-i] + t + i = j + 2 + end + s + self[i, length-i] + end + + ## + # Replace all matches of +pattern+ with +replacement+. + # Call block (if given) for each match and replace + # +pattern+ with the value of the block. Return the + # final value. + # + # ISO 15.2.10.5.18 + def gsub(*args, &block) + return to_enum(:gsub, *args) if args.length == 1 && !block + raise ArgumentError, "wrong number of arguments" unless (1..2).include?(args.length) + + pattern, replace = *args + plen = pattern.length + if args.length == 2 && block + block = nil + end + if !replace.nil? || !block + replace = replace.to_str + end + offset = 0 + result = [] + while found = index(pattern, offset) + result << self[offset, found - offset] + offset = found + plen + result << if block + block.call(pattern).to_s + else + replace.__sub_replace(self[0, found], pattern, self[offset..-1] || "") + end + if plen == 0 + result << self[offset, 1] + offset += 1 + end + end + result << self[offset..-1] if offset < length + result.join + end + + ## + # Replace all matches of +pattern+ with +replacement+. + # Call block (if given) for each match and replace + # +pattern+ with the value of the block. Modify + # +self+ with the final value. + # + # ISO 15.2.10.5.19 + def gsub!(*args, &block) + raise RuntimeError, "can't modify frozen String" if frozen? + return to_enum(:gsub!, *args) if args.length == 1 && !block + str = self.gsub(*args, &block) + return nil if str == self + self.replace(str) + end + + ## + # Calls the given block for each match of +pattern+ + # If no block is given return an array with all + # matches of +pattern+. + # + # ISO 15.2.10.5.32 + def scan(reg, &block) + ### *** TODO *** ### + unless Object.const_defined?(:Regexp) + raise NotImplementedError, "scan not available (yet)" + end + end + + ## + # Replace only the first match of +pattern+ with + # +replacement+. Call block (if given) for each + # match and replace +pattern+ with the value of the + # block. Return the final value. + # + # ISO 15.2.10.5.36 + def sub(*args, &block) + unless (1..2).include?(args.length) + raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 2)" + end + + pattern, replace = *args + pattern = pattern.to_str + if args.length == 2 && block + block = nil + end + unless block + replace = replace.to_str + end + result = [] + this = dup + found = index(pattern) + return this unless found + result << this[0, found] + offset = found + pattern.length + result << if block + block.call(pattern).to_s + else + replace.__sub_replace(this[0, found], pattern, this[offset..-1] || "") + end + result << this[offset..-1] if offset < length + result.join + end + + ## + # Replace only the first match of +pattern+ with + # +replacement+. Call block (if given) for each + # match and replace +pattern+ with the value of the + # block. Modify +self+ with the final value. + # + # ISO 15.2.10.5.37 + def sub!(*args, &block) + raise RuntimeError, "can't modify frozen String" if frozen? + str = self.sub(*args, &block) + return nil if str == self + self.replace(str) + end + + ## + # Call the given block for each character of + # +self+. + def each_char(&block) + pos = 0 + while pos < self.size + block.call(self[pos]) + pos += 1 + end + self + end + + ## + # Call the given block for each byte of +self+. + def each_byte(&block) + bytes = self.bytes + pos = 0 + while pos < bytes.size + block.call(bytes[pos]) + pos += 1 + end + self + end + + ## + # Modify +self+ by replacing the content of +self+. + # The portion of the string affected is determined using the same criteria as +String#[]+. + def []=(*args) + anum = args.size + if anum == 2 + pos, value = args + case pos + when String + posnum = self.index(pos) + if posnum + b = self[0, posnum.to_i] + a = self[(posnum + pos.length)..-1] + self.replace([b, value, a].join('')) + else + raise IndexError, "string not matched" + end + when Range + head = pos.begin + tail = pos.end + tail += self.length if tail < 0 + unless pos.exclude_end? + tail += 1 + end + return self[head, tail-head]=value + else + pos += self.length if pos < 0 + if pos < 0 || pos > self.length + raise IndexError, "index #{args[0]} out of string" + end + b = self[0, pos.to_i] + a = self[pos + 1..-1] + self.replace([b, value, a].join('')) + end + return value + elsif anum == 3 + pos, len, value = args + pos += self.length if pos < 0 + if pos < 0 || pos > self.length + raise IndexError, "index #{args[0]} out of string" + end + if len < 0 + raise IndexError, "negative length #{len}" + end + b = self[0, pos.to_i] + a = self[pos + len..-1] + self.replace([b, value, a].join('')) + return value + else + raise ArgumentError, "wrong number of arguments (#{anum} for 2..3)" + end + end + + ## + # ISO 15.2.10.5.3 + def =~(re) + raise TypeError, "type mismatch: String given" if re.respond_to? :to_str + re =~ self + end + + ## + # ISO 15.2.10.5.27 + def match(re, &block) + if re.respond_to? :to_str + if Object.const_defined?(:Regexp) + r = Regexp.new(re) + r.match(self, &block) + else + raise NotImplementedError, "String#match needs Regexp class" + end + else + re.match(self, &block) + end + end +end + +## +# String is comparable +# +# ISO 15.2.10.3 +module Comparable; end +class String + include Comparable +end diff --git a/web/server/h2o/libh2o/deps/mruby/mruby-source.gemspec b/web/server/h2o/libh2o/deps/mruby/mruby-source.gemspec new file mode 100644 index 000000000..62d4c0d12 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mruby-source.gemspec @@ -0,0 +1,18 @@ +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'mruby/source' + +Gem::Specification.new do |spec| + spec.name = "mruby-source" + spec.version = MRuby::Source::MRUBY_VERSION + spec.authors = [ MRuby::Source::MRUBY_AUTHOR ] + + spec.summary = %q{MRuby source code wrapper.} + spec.description = %q{MRuby source code wrapper for use with Ruby libs.} + spec.homepage = "http://www.mruby.org/" + spec.license = "MIT" + + spec.files = `git ls-files -z`.split("\x0") + spec.require_paths = ["lib"] +end diff --git a/web/server/h2o/libh2o/deps/mruby/src/array.c b/web/server/h2o/libh2o/deps/mruby/src/array.c new file mode 100644 index 000000000..8f33defe6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/array.c @@ -0,0 +1,1249 @@ +/* +** array.c - Array class +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/string.h> +#include <mruby/range.h> +#include "value_array.h" + +#define ARY_DEFAULT_LEN 4 +#define ARY_SHRINK_RATIO 5 /* must be larger than 2 */ +#define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value)) +#define ARY_MAX_SIZE ((mrb_int)((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? ARY_C_MAX_SIZE : MRB_INT_MAX-1)) + +static struct RArray* +ary_new_capa(mrb_state *mrb, mrb_int capa) +{ + struct RArray *a; + size_t blen; + + if (capa > ARY_MAX_SIZE) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + blen = capa * sizeof(mrb_value); + + a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class); + if (capa <= MRB_ARY_EMBED_LEN_MAX) { + ARY_SET_EMBED_LEN(a, 0); + } + else { + a->as.heap.ptr = (mrb_value *)mrb_malloc(mrb, blen); + a->as.heap.aux.capa = capa; + a->as.heap.len = 0; + } + + return a; +} + +MRB_API mrb_value +mrb_ary_new_capa(mrb_state *mrb, mrb_int capa) +{ + struct RArray *a = ary_new_capa(mrb, capa); + return mrb_obj_value(a); +} + +MRB_API mrb_value +mrb_ary_new(mrb_state *mrb) +{ + return mrb_ary_new_capa(mrb, 0); +} + +/* + * to copy array, use this instead of memcpy because of portability + * * gcc on ARM may fail optimization of memcpy + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3934.html + * * gcc on MIPS also fail + * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39755 + * * memcpy doesn't exist on freestanding environment + * + * If you optimize for binary size, use memcpy instead of this at your own risk + * of above portability issue. + * + * see also http://togetter.com/li/462898 + * + */ +static inline void +array_copy(mrb_value *dst, const mrb_value *src, mrb_int size) +{ + mrb_int i; + + for (i = 0; i < size; i++) { + dst[i] = src[i]; + } +} + +MRB_API mrb_value +mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals) +{ + struct RArray *a = ary_new_capa(mrb, size); + + array_copy(ARY_PTR(a), vals, size); + ARY_SET_LEN(a, size); + + return mrb_obj_value(a); +} + +MRB_API mrb_value +mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr) +{ + struct RArray *a; + + a = ary_new_capa(mrb, 2); + ARY_PTR(a)[0] = car; + ARY_PTR(a)[1] = cdr; + ARY_SET_LEN(a, 2); + return mrb_obj_value(a); +} + +static void +ary_fill_with_nil(mrb_value *ptr, mrb_int size) +{ + mrb_value nil = mrb_nil_value(); + + while (size--) { + *ptr++ = nil; + } +} + +static void +ary_modify_check(mrb_state *mrb, struct RArray *a) +{ + if (MRB_FROZEN_P(a)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array"); + } +} + +static void +ary_modify(mrb_state *mrb, struct RArray *a) +{ + ary_modify_check(mrb, a); + + if (ARY_SHARED_P(a)) { + mrb_shared_array *shared = a->as.heap.aux.shared; + + if (shared->refcnt == 1 && a->as.heap.ptr == shared->ptr) { + a->as.heap.ptr = shared->ptr; + a->as.heap.aux.capa = a->as.heap.len; + mrb_free(mrb, shared); + } + else { + mrb_value *ptr, *p; + mrb_int len; + + p = a->as.heap.ptr; + len = a->as.heap.len * sizeof(mrb_value); + ptr = (mrb_value *)mrb_malloc(mrb, len); + if (p) { + array_copy(ptr, p, a->as.heap.len); + } + a->as.heap.ptr = ptr; + a->as.heap.aux.capa = a->as.heap.len; + mrb_ary_decref(mrb, shared); + } + ARY_UNSET_SHARED_FLAG(a); + } +} + +MRB_API void +mrb_ary_modify(mrb_state *mrb, struct RArray* a) +{ + mrb_write_barrier(mrb, (struct RBasic*)a); + ary_modify(mrb, a); +} + +static void +ary_make_shared(mrb_state *mrb, struct RArray *a) +{ + if (!ARY_SHARED_P(a) && !ARY_EMBED_P(a)) { + mrb_shared_array *shared = (mrb_shared_array *)mrb_malloc(mrb, sizeof(mrb_shared_array)); + mrb_value *ptr = a->as.heap.ptr; + mrb_int len = a->as.heap.len; + + shared->refcnt = 1; + if (a->as.heap.aux.capa > len) { + a->as.heap.ptr = shared->ptr = (mrb_value *)mrb_realloc(mrb, ptr, sizeof(mrb_value)*len+1); + } + else { + shared->ptr = ptr; + } + shared->len = len; + a->as.heap.aux.shared = shared; + ARY_SET_SHARED_FLAG(a); + } +} + +static void +ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) +{ + mrb_int capa = ARY_CAPA(a); + + if (len > ARY_MAX_SIZE || len < 0) { + size_error: + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + + if (capa < ARY_DEFAULT_LEN) { + capa = ARY_DEFAULT_LEN; + } + while (capa < len) { + if (capa <= ARY_MAX_SIZE / 2) { + capa *= 2; + } + else { + capa = len; + } + } + if (capa < len || capa > ARY_MAX_SIZE) { + goto size_error; + } + + if (ARY_EMBED_P(a)) { + mrb_value *ptr = ARY_EMBED_PTR(a); + mrb_int len = ARY_EMBED_LEN(a); + mrb_value *expanded_ptr = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*capa); + + ARY_UNSET_EMBED_FLAG(a); + array_copy(expanded_ptr, ptr, len); + a->as.heap.len = len; + a->as.heap.aux.capa = capa; + a->as.heap.ptr = expanded_ptr; + } + else if (capa > a->as.heap.aux.capa) { + mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->as.heap.ptr, sizeof(mrb_value)*capa); + + a->as.heap.aux.capa = capa; + a->as.heap.ptr = expanded_ptr; + } +} + +static void +ary_shrink_capa(mrb_state *mrb, struct RArray *a) +{ + + mrb_int capa; + + if (ARY_EMBED_P(a)) return; + + capa = a->as.heap.aux.capa; + if (capa < ARY_DEFAULT_LEN * 2) return; + if (capa <= a->as.heap.len * ARY_SHRINK_RATIO) return; + + do { + capa /= 2; + if (capa < ARY_DEFAULT_LEN) { + capa = ARY_DEFAULT_LEN; + break; + } + } while (capa > a->as.heap.len * ARY_SHRINK_RATIO); + + if (capa > a->as.heap.len && capa < a->as.heap.aux.capa) { + a->as.heap.aux.capa = capa; + a->as.heap.ptr = (mrb_value *)mrb_realloc(mrb, a->as.heap.ptr, sizeof(mrb_value)*capa); + } +} + +MRB_API mrb_value +mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len) +{ + mrb_int old_len; + struct RArray *a = mrb_ary_ptr(ary); + + ary_modify(mrb, a); + old_len = RARRAY_LEN(ary); + if (old_len != new_len) { + ARY_SET_LEN(a, new_len); + if (new_len < old_len) { + ary_shrink_capa(mrb, a); + } + else { + ary_expand_capa(mrb, a, new_len); + ary_fill_with_nil(ARY_PTR(a) + old_len, new_len - old_len); + } + } + + return ary; +} + +static mrb_value +mrb_ary_s_create(mrb_state *mrb, mrb_value klass) +{ + mrb_value ary; + mrb_value *vals; + mrb_int len; + struct RArray *a; + + mrb_get_args(mrb, "*!", &vals, &len); + ary = mrb_ary_new_from_values(mrb, len, vals); + a = mrb_ary_ptr(ary); + a->c = mrb_class_ptr(klass); + + return ary; +} + +static void +ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2) +{ + mrb_int len; + + if (ARY_LEN(a2) > ARY_MAX_SIZE - ARY_LEN(a)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + len = ARY_LEN(a) + ARY_LEN(a2); + + ary_modify(mrb, a); + if (ARY_CAPA(a) < len) { + ary_expand_capa(mrb, a, len); + } + array_copy(ARY_PTR(a)+ARY_LEN(a), ARY_PTR(a2), ARY_LEN(a2)); + mrb_write_barrier(mrb, (struct RBasic*)a); + ARY_SET_LEN(a, len); +} + +MRB_API void +mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other) +{ + struct RArray *a2 = mrb_ary_ptr(other); + + ary_concat(mrb, mrb_ary_ptr(self), a2); +} + +static mrb_value +mrb_ary_concat_m(mrb_state *mrb, mrb_value self) +{ + mrb_value ary; + + mrb_get_args(mrb, "A", &ary); + mrb_ary_concat(mrb, self, ary); + return self; +} + +static mrb_value +mrb_ary_plus(mrb_state *mrb, mrb_value self) +{ + struct RArray *a1 = mrb_ary_ptr(self); + struct RArray *a2; + mrb_value *ptr; + mrb_int blen, len1; + + mrb_get_args(mrb, "a", &ptr, &blen); + if (ARY_MAX_SIZE - blen < ARY_LEN(a1)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + len1 = ARY_LEN(a1); + a2 = ary_new_capa(mrb, len1 + blen); + array_copy(ARY_PTR(a2), ARY_PTR(a1), len1); + array_copy(ARY_PTR(a2) + len1, ptr, blen); + ARY_SET_LEN(a2, len1+blen); + + return mrb_obj_value(a2); +} + +static void +ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len) +{ + ary_modify(mrb, a); + if (ARY_CAPA(a) < len) + ary_expand_capa(mrb, a, len); + array_copy(ARY_PTR(a), argv, len); + mrb_write_barrier(mrb, (struct RBasic*)a); + ARY_SET_LEN(a, len); +} + +MRB_API void +mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other) +{ + struct RArray *a1 = mrb_ary_ptr(self); + struct RArray *a2 = mrb_ary_ptr(other); + + if (a1 != a2) { + ary_replace(mrb, a1, ARY_PTR(a2), ARY_LEN(a2)); + } +} + +static mrb_value +mrb_ary_replace_m(mrb_state *mrb, mrb_value self) +{ + mrb_value other; + + mrb_get_args(mrb, "A", &other); + mrb_ary_replace(mrb, self, other); + + return self; +} + +static mrb_value +mrb_ary_times(mrb_state *mrb, mrb_value self) +{ + struct RArray *a1 = mrb_ary_ptr(self); + struct RArray *a2; + mrb_value *ptr; + mrb_int times, len1; + + mrb_get_args(mrb, "i", ×); + if (times < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument"); + } + if (times == 0) return mrb_ary_new(mrb); + if (ARY_MAX_SIZE / times < ARY_LEN(a1)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + len1 = ARY_LEN(a1); + a2 = ary_new_capa(mrb, len1 * times); + ARY_SET_LEN(a2, len1 * times); + ptr = ARY_PTR(a2); + while (times--) { + array_copy(ptr, ARY_PTR(a1), len1); + ptr += len1; + } + + return mrb_obj_value(a2); +} + +static mrb_value +mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + mrb_int len = ARY_LEN(a); + + if (len > 1) { + mrb_value *p1, *p2; + + ary_modify(mrb, a); + p1 = ARY_PTR(a); + p2 = p1 + len - 1; + + while (p1 < p2) { + mrb_value tmp = *p1; + *p1++ = *p2; + *p2-- = tmp; + } + } + return self; +} + +static mrb_value +mrb_ary_reverse(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self), *b = ary_new_capa(mrb, ARY_LEN(a)); + mrb_int len = ARY_LEN(a); + + if (len > 0) { + mrb_value *p1, *p2, *e; + + p1 = ARY_PTR(a); + e = p1 + len; + p2 = ARY_PTR(b) + len - 1; + while (p1 < e) { + *p2-- = *p1++; + } + ARY_SET_LEN(b, len); + } + return mrb_obj_value(b); +} + +MRB_API void +mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem) +{ + struct RArray *a = mrb_ary_ptr(ary); + mrb_int len = ARY_LEN(a); + + ary_modify(mrb, a); + if (len == ARY_CAPA(a)) + ary_expand_capa(mrb, a, len + 1); + ARY_PTR(a)[len] = elem; + ARY_SET_LEN(a, len+1); + mrb_field_write_barrier_value(mrb, (struct RBasic*)a, elem); +} + +static mrb_value +mrb_ary_push_m(mrb_state *mrb, mrb_value self) +{ + mrb_value *argv; + mrb_int len, len2, alen; + struct RArray *a; + + mrb_get_args(mrb, "*!", &argv, &alen); + a = mrb_ary_ptr(self); + ary_modify(mrb, a); + len = ARY_LEN(a); + len2 = len + alen; + if (ARY_CAPA(a) < len2) { + ary_expand_capa(mrb, a, len2); + } + array_copy(ARY_PTR(a)+len, argv, alen); + ARY_SET_LEN(a, len2); + mrb_write_barrier(mrb, (struct RBasic*)a); + + return self; +} + +MRB_API mrb_value +mrb_ary_pop(mrb_state *mrb, mrb_value ary) +{ + struct RArray *a = mrb_ary_ptr(ary); + mrb_int len = ARY_LEN(a); + + ary_modify_check(mrb, a); + if (len == 0) return mrb_nil_value(); + ARY_SET_LEN(a, len-1); + return ARY_PTR(a)[len-1]; +} + +#define ARY_SHIFT_SHARED_MIN 10 + +MRB_API mrb_value +mrb_ary_shift(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + mrb_int len = ARY_LEN(a); + mrb_value val; + + ary_modify_check(mrb, a); + if (len == 0) return mrb_nil_value(); + if (ARY_SHARED_P(a)) { + L_SHIFT: + val = a->as.heap.ptr[0]; + a->as.heap.ptr++; + a->as.heap.len--; + return val; + } + if (len > ARY_SHIFT_SHARED_MIN) { + ary_make_shared(mrb, a); + goto L_SHIFT; + } + else { + mrb_value *ptr = ARY_PTR(a); + mrb_int size = len; + + val = *ptr; + while (--size) { + *ptr = *(ptr+1); + ++ptr; + } + ARY_SET_LEN(a, len-1); + } + return val; +} + +/* self = [1,2,3] + item = 0 + self.unshift item + p self #=> [0, 1, 2, 3] */ +MRB_API mrb_value +mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item) +{ + struct RArray *a = mrb_ary_ptr(self); + mrb_int len = ARY_LEN(a); + + if (ARY_SHARED_P(a) + && a->as.heap.aux.shared->refcnt == 1 /* shared only referenced from this array */ + && a->as.heap.ptr - a->as.heap.aux.shared->ptr >= 1) /* there's room for unshifted item */ { + a->as.heap.ptr--; + a->as.heap.ptr[0] = item; + } + else { + mrb_value *ptr; + + ary_modify(mrb, a); + if (ARY_CAPA(a) < len + 1) + ary_expand_capa(mrb, a, len + 1); + ptr = ARY_PTR(a); + value_move(ptr + 1, ptr, len); + ptr[0] = item; + } + ARY_SET_LEN(a, len+1); + mrb_field_write_barrier_value(mrb, (struct RBasic*)a, item); + + return self; +} + +static mrb_value +mrb_ary_unshift_m(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + mrb_value *vals, *ptr; + mrb_int alen, len; + + mrb_get_args(mrb, "*!", &vals, &alen); + if (alen == 0) { + ary_modify_check(mrb, a); + return self; + } + len = ARY_LEN(a); + if (alen > ARY_MAX_SIZE - len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } + if (ARY_SHARED_P(a) + && a->as.heap.aux.shared->refcnt == 1 /* shared only referenced from this array */ + && a->as.heap.ptr - a->as.heap.aux.shared->ptr >= alen) /* there's room for unshifted item */ { + ary_modify_check(mrb, a); + a->as.heap.ptr -= alen; + ptr = a->as.heap.ptr; + } + else { + ary_modify(mrb, a); + if (ARY_CAPA(a) < len + alen) + ary_expand_capa(mrb, a, len + alen); + ptr = ARY_PTR(a); + value_move(ptr + alen, ptr, len); + } + array_copy(ptr, vals, alen); + ARY_SET_LEN(a, len+alen); + while (alen--) { + mrb_field_write_barrier_value(mrb, (struct RBasic*)a, vals[alen]); + } + + return self; +} + +MRB_API mrb_value +mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n) +{ + struct RArray *a = mrb_ary_ptr(ary); + mrb_int len = ARY_LEN(a); + + /* range check */ + if (n < 0) n += len; + if (n < 0 || len <= n) return mrb_nil_value(); + + return ARY_PTR(a)[n]; +} + +MRB_API void +mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) +{ + struct RArray *a = mrb_ary_ptr(ary); + mrb_int len = ARY_LEN(a); + + ary_modify(mrb, a); + /* range check */ + if (n < 0) { + n += len; + if (n < 0) { + mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - len)); + } + } + if (len <= n) { + if (ARY_CAPA(a) <= n) + ary_expand_capa(mrb, a, n + 1); + ary_fill_with_nil(ARY_PTR(a) + len, n + 1 - len); + ARY_SET_LEN(a, n+1); + } + + ARY_PTR(a)[n] = val; + mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val); +} + +static struct RArray* +ary_dup(mrb_state *mrb, struct RArray *a) +{ + mrb_int len = ARY_LEN(a); + struct RArray *d = ary_new_capa(mrb, len); + + ary_replace(mrb, d, ARY_PTR(a), len); + return d; +} + +MRB_API mrb_value +mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl) +{ + struct RArray *a = mrb_ary_ptr(ary); + mrb_int alen = ARY_LEN(a); + const mrb_value *argv; + mrb_int argc; + mrb_int tail; + + ary_modify(mrb, a); + + /* len check */ + if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%S)", mrb_fixnum_value(len)); + + /* range check */ + if (head < 0) { + head += alen; + if (head < 0) { + mrb_raise(mrb, E_INDEX_ERROR, "index is out of array"); + } + } + tail = head + len; + if (alen < len || alen < tail) { + len = alen - head; + } + + /* size check */ + if (mrb_array_p(rpl)) { + argc = RARRAY_LEN(rpl); + argv = RARRAY_PTR(rpl); + if (argv == ARY_PTR(a)) { + struct RArray *r; + + if (argc > 32767) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too big recursive splice"); + } + r = ary_dup(mrb, a); + argv = ARY_PTR(r); + } + } + else { + argc = 1; + argv = &rpl; + } + if (head >= alen) { + if (head > ARY_MAX_SIZE - argc) { + mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head)); + } + len = head + argc; + if (len > ARY_CAPA(a)) { + ary_expand_capa(mrb, a, head + argc); + } + ary_fill_with_nil(ARY_PTR(a) + alen, head - alen); + if (argc > 0) { + array_copy(ARY_PTR(a) + head, argv, argc); + } + ARY_SET_LEN(a, len); + } + else { + mrb_int newlen; + + if (alen - len > ARY_MAX_SIZE - argc) { + mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(alen + argc - len)); + } + newlen = alen + argc - len; + if (newlen > ARY_CAPA(a)) { + ary_expand_capa(mrb, a, newlen); + } + + if (len != argc) { + mrb_value *ptr = ARY_PTR(a); + tail = head + len; + value_move(ptr + head + argc, ptr + tail, alen - tail); + ARY_SET_LEN(a, newlen); + } + if (argc > 0) { + value_move(ARY_PTR(a) + head, argv, argc); + } + } + mrb_write_barrier(mrb, (struct RBasic*)a); + return ary; +} + +void +mrb_ary_decref(mrb_state *mrb, mrb_shared_array *shared) +{ + shared->refcnt--; + if (shared->refcnt == 0) { + mrb_free(mrb, shared->ptr); + mrb_free(mrb, shared); + } +} + +static mrb_value +ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len) +{ + struct RArray *b; + + if (!ARY_SHARED_P(a) && len <= ARY_SHIFT_SHARED_MIN) { + return mrb_ary_new_from_values(mrb, len, ARY_PTR(a)+beg); + } + ary_make_shared(mrb, a); + b = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class); + b->as.heap.ptr = a->as.heap.ptr + beg; + b->as.heap.len = len; + b->as.heap.aux.shared = a->as.heap.aux.shared; + b->as.heap.aux.shared->refcnt++; + ARY_SET_SHARED_FLAG(b); + + return mrb_obj_value(b); +} + +static mrb_int +aget_index(mrb_state *mrb, mrb_value index) +{ + if (mrb_fixnum_p(index)) { + return mrb_fixnum(index); + } + else if (mrb_float_p(index)) { + return (mrb_int)mrb_float(index); + } + else { + mrb_int i, argc; + mrb_value *argv; + + mrb_get_args(mrb, "i*!", &i, &argv, &argc); + return i; + } +} + +/* + * call-seq: + * ary[index] -> obj or nil + * ary[start, length] -> new_ary or nil + * ary[range] -> new_ary or nil + * ary.slice(index) -> obj or nil + * ary.slice(start, length) -> new_ary or nil + * ary.slice(range) -> new_ary or nil + * + * Element Reference --- Returns the element at +index+, or returns a + * subarray starting at the +start+ index and continuing for +length+ + * elements, or returns a subarray specified by +range+ of indices. + * + * Negative indices count backward from the end of the array (-1 is the last + * element). For +start+ and +range+ cases the starting index is just before + * an element. Additionally, an empty array is returned when the starting + * index for an element range is at the end of the array. + * + * Returns +nil+ if the index (or starting index) are out of range. + * + * a = [ "a", "b", "c", "d", "e" ] + * a[1] => "b" + * a[1,2] => ["b", "c"] + * a[1..-2] => ["b", "c", "d"] + * + */ + +static mrb_value +mrb_ary_aget(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + mrb_int i, len, alen = ARY_LEN(a); + mrb_value index; + + if (mrb_get_args(mrb, "o|i", &index, &len) == 1) { + switch (mrb_type(index)) { + /* a[n..m] */ + case MRB_TT_RANGE: + if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) { + return ary_subseq(mrb, a, i, len); + } + else { + return mrb_nil_value(); + } + case MRB_TT_FIXNUM: + return mrb_ary_ref(mrb, self, mrb_fixnum(index)); + default: + return mrb_ary_ref(mrb, self, aget_index(mrb, index)); + } + } + + i = aget_index(mrb, index); + if (i < 0) i += alen; + if (i < 0 || alen < i) return mrb_nil_value(); + if (len < 0) return mrb_nil_value(); + if (alen == i) return mrb_ary_new(mrb); + if (len > alen - i) len = alen - i; + + return ary_subseq(mrb, a, i, len); +} + +/* + * call-seq: + * ary[index] = obj -> obj + * ary[start, length] = obj or other_ary or nil -> obj or other_ary or nil + * ary[range] = obj or other_ary or nil -> obj or other_ary or nil + * + * Element Assignment --- Sets the element at +index+, or replaces a subarray + * from the +start+ index for +length+ elements, or replaces a subarray + * specified by the +range+ of indices. + * + * If indices are greater than the current capacity of the array, the array + * grows automatically. Elements are inserted into the array at +start+ if + * +length+ is zero. + * + * Negative indices will count backward from the end of the array. For + * +start+ and +range+ cases the starting index is just before an element. + * + * An IndexError is raised if a negative index points past the beginning of + * the array. + * + * See also Array#push, and Array#unshift. + * + * a = Array.new + * a[4] = "4"; #=> [nil, nil, nil, nil, "4"] + * a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"] + * a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"] + * a[0, 2] = "?" #=> ["?", 2, nil, "4"] + * a[0..2] = "A" #=> ["A", "4"] + * a[-1] = "Z" #=> ["A", "Z"] + * a[1..-1] = nil #=> ["A", nil] + * a[1..-1] = [] #=> ["A"] + * a[0, 0] = [ 1, 2 ] #=> [1, 2, "A"] + * a[3, 0] = "B" #=> [1, 2, "A", "B"] + */ + +static mrb_value +mrb_ary_aset(mrb_state *mrb, mrb_value self) +{ + mrb_value v1, v2, v3; + mrb_int i, len; + + mrb_ary_modify(mrb, mrb_ary_ptr(self)); + if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { + /* a[n..m] = v */ + switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) { + case 0: /* not range */ + mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); + break; + case 1: /* range */ + mrb_ary_splice(mrb, self, i, len, v2); + break; + case 2: /* out of range */ + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1); + break; + } + return v2; + } + + /* a[n,m] = v */ + mrb_ary_splice(mrb, self, aget_index(mrb, v1), aget_index(mrb, v2), v3); + return v3; +} + +static mrb_value +mrb_ary_delete_at(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + mrb_int index; + mrb_value val; + mrb_value *ptr; + mrb_int len, alen = ARY_LEN(a); + + mrb_get_args(mrb, "i", &index); + if (index < 0) index += alen; + if (index < 0 || alen <= index) return mrb_nil_value(); + + ary_modify(mrb, a); + ptr = ARY_PTR(a); + val = ptr[index]; + + ptr += index; + len = alen - index; + while (--len) { + *ptr = *(ptr+1); + ++ptr; + } + ARY_SET_LEN(a, alen-1); + + ary_shrink_capa(mrb, a); + + return val; +} + +static mrb_value +mrb_ary_first(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + mrb_int size, alen = ARY_LEN(a); + + if (mrb->c->ci->argc == 0) { + return (alen > 0)? ARY_PTR(a)[0]: mrb_nil_value(); + } + mrb_get_args(mrb, "|i", &size); + if (size < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size"); + } + + if (size > alen) size = alen; + if (ARY_SHARED_P(a)) { + return ary_subseq(mrb, a, 0, size); + } + return mrb_ary_new_from_values(mrb, size, ARY_PTR(a)); +} + +static mrb_value +mrb_ary_last(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + mrb_int size, alen = ARY_LEN(a); + + if (mrb_get_args(mrb, "|i", &size) == 0) + return (alen > 0)? ARY_PTR(a)[alen - 1]: mrb_nil_value(); + + if (size < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size"); + } + if (size > alen) size = alen; + if (ARY_SHARED_P(a) || size > ARY_DEFAULT_LEN) { + return ary_subseq(mrb, a, alen - size, size); + } + return mrb_ary_new_from_values(mrb, size, ARY_PTR(a) + alen - size); +} + +static mrb_value +mrb_ary_index_m(mrb_state *mrb, mrb_value self) +{ + mrb_value obj; + mrb_int i; + + mrb_get_args(mrb, "o", &obj); + for (i = 0; i < RARRAY_LEN(self); i++) { + if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { + return mrb_fixnum_value(i); + } + } + return mrb_nil_value(); +} + +static mrb_value +mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) +{ + mrb_value obj; + mrb_int i, len; + + mrb_get_args(mrb, "o", &obj); + for (i = RARRAY_LEN(self) - 1; i >= 0; i--) { + if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { + return mrb_fixnum_value(i); + } + if (i > (len = RARRAY_LEN(self))) { + i = len; + } + } + return mrb_nil_value(); +} + +MRB_API mrb_value +mrb_ary_splat(mrb_state *mrb, mrb_value v) +{ + mrb_value a, recv_class; + + if (mrb_array_p(v)) { + return v; + } + + if (!mrb_respond_to(mrb, v, mrb_intern_lit(mrb, "to_a"))) { + return mrb_ary_new_from_values(mrb, 1, &v); + } + + a = mrb_funcall(mrb, v, "to_a", 0); + if (mrb_array_p(a)) { + return a; + } + else if (mrb_nil_p(a)) { + return mrb_ary_new_from_values(mrb, 1, &v); + } + else { + recv_class = mrb_obj_value(mrb_obj_class(mrb, v)); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Array (%S#to_a gives %S)", + recv_class, + recv_class, + mrb_obj_value(mrb_obj_class(mrb, a)) + ); + /* not reached */ + return mrb_undef_value(); + } +} + +static mrb_value +mrb_ary_size(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + + return mrb_fixnum_value(ARY_LEN(a)); +} + +MRB_API mrb_value +mrb_ary_clear(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + + ary_modify(mrb, a); + if (ARY_SHARED_P(a)) { + mrb_ary_decref(mrb, a->as.heap.aux.shared); + ARY_UNSET_SHARED_FLAG(a); + } + else if (!ARY_EMBED_P(a)){ + mrb_free(mrb, a->as.heap.ptr); + } + ARY_SET_EMBED_LEN(a, 0); + + return self; +} + +static mrb_value +mrb_ary_empty_p(mrb_state *mrb, mrb_value self) +{ + struct RArray *a = mrb_ary_ptr(self); + + return mrb_bool_value(ARY_LEN(a) == 0); +} + +MRB_API mrb_value +mrb_check_array_type(mrb_state *mrb, mrb_value ary) +{ + return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary"); +} + +MRB_API mrb_value +mrb_ary_entry(mrb_value ary, mrb_int offset) +{ + if (offset < 0) { + offset += RARRAY_LEN(ary); + } + if (offset < 0 || RARRAY_LEN(ary) <= offset) { + return mrb_nil_value(); + } + return RARRAY_PTR(ary)[offset]; +} + +static mrb_value +join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list) +{ + mrb_int i; + mrb_value result, val, tmp; + + /* check recursive */ + for (i=0; i<RARRAY_LEN(list); i++) { + if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "recursive array join"); + } + } + + mrb_ary_push(mrb, list, ary); + + result = mrb_str_new_capa(mrb, 64); + + for (i=0; i<RARRAY_LEN(ary); i++) { + if (i > 0 && !mrb_nil_p(sep)) { + mrb_str_cat_str(mrb, result, sep); + } + + val = RARRAY_PTR(ary)[i]; + switch (mrb_type(val)) { + case MRB_TT_ARRAY: + ary_join: + val = join_ary(mrb, val, sep, list); + /* fall through */ + + case MRB_TT_STRING: + str_join: + mrb_str_cat_str(mrb, result, val); + break; + + default: + if (!mrb_immediate_p(val)) { + tmp = mrb_check_string_type(mrb, val); + if (!mrb_nil_p(tmp)) { + val = tmp; + goto str_join; + } + tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); + if (!mrb_nil_p(tmp)) { + val = tmp; + goto ary_join; + } + } + val = mrb_obj_as_string(mrb, val); + goto str_join; + } + } + + mrb_ary_pop(mrb, list); + + return result; +} + +MRB_API mrb_value +mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep) +{ + if (!mrb_nil_p(sep)) { + sep = mrb_obj_as_string(mrb, sep); + } + return join_ary(mrb, ary, sep, mrb_ary_new(mrb)); +} + +/* + * call-seq: + * ary.join(sep="") -> str + * + * Returns a string created by converting each element of the array to + * a string, separated by <i>sep</i>. + * + * [ "a", "b", "c" ].join #=> "abc" + * [ "a", "b", "c" ].join("-") #=> "a-b-c" + */ + +static mrb_value +mrb_ary_join_m(mrb_state *mrb, mrb_value ary) +{ + mrb_value sep = mrb_nil_value(); + + mrb_get_args(mrb, "|S!", &sep); + return mrb_ary_join(mrb, ary, sep); +} + +static mrb_value +mrb_ary_eq(mrb_state *mrb, mrb_value ary1) +{ + mrb_value ary2; + + mrb_get_args(mrb, "o", &ary2); + if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value(); + if (!mrb_array_p(ary2)) { + return mrb_false_value(); + } + if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return mrb_false_value(); + + return ary2; +} + +static mrb_value +mrb_ary_cmp(mrb_state *mrb, mrb_value ary1) +{ + mrb_value ary2; + + mrb_get_args(mrb, "o", &ary2); + if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0); + if (!mrb_array_p(ary2)) { + return mrb_nil_value(); + } + + return ary2; +} + +void +mrb_init_array(mrb_state *mrb) +{ + struct RClass *a; + + mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ + MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY); + + mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ + + mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ + mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ + mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ + mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */ + mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */ + mrb_define_method(mrb, a, "clear", mrb_ary_clear, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ + mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ + mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ + mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ + mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ + mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ + mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ + mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_ANY()); /* 15.2.12.5.17 */ + mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_ANY()); /* 15.2.12.5.18 */ + mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ + mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ + mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ + mrb_define_method(mrb, a, "append", mrb_ary_push_m, MRB_ARGS_ANY()); + mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ + mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ + mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ + mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ + mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ + mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ + mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */ + mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ + mrb_define_method(mrb, a, "prepend", mrb_ary_unshift_m, MRB_ARGS_ANY()); + + mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/backtrace.c b/web/server/h2o/libh2o/deps/mruby/src/backtrace.c new file mode 100644 index 000000000..3e4e1a438 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/backtrace.c @@ -0,0 +1,281 @@ +/* +** backtrace.c - +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/variable.h> +#include <mruby/proc.h> +#include <mruby/array.h> +#include <mruby/string.h> +#include <mruby/class.h> +#include <mruby/debug.h> +#include <mruby/error.h> +#include <mruby/numeric.h> +#include <mruby/data.h> + +struct backtrace_location { + int lineno; + const char *filename; + mrb_sym method_id; +}; + +typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location*, void*); + +static const mrb_data_type bt_type = { "Backtrace", mrb_free }; + +static void +each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_func func, void *data) +{ + ptrdiff_t i, j; + + if (ciidx >= mrb->c->ciend - mrb->c->cibase) + ciidx = 10; /* ciidx is broken... */ + + for (i=ciidx, j=0; i >= 0; i--,j++) { + struct backtrace_location loc; + mrb_callinfo *ci; + mrb_irep *irep; + mrb_code *pc; + + ci = &mrb->c->cibase[i]; + + if (!ci->proc) continue; + if (MRB_PROC_CFUNC_P(ci->proc)) continue; + + irep = ci->proc->body.irep; + if (!irep) continue; + + if (mrb->c->cibase[i].err) { + pc = mrb->c->cibase[i].err; + } + else if (i+1 <= ciidx) { + pc = mrb->c->cibase[i+1].pc - 1; + } + else { + pc = pc0; + } + loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq); + loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq); + + if (loc.lineno == -1) continue; + + if (!loc.filename) { + loc.filename = "(unknown)"; + } + + loc.method_id = ci->mid; + func(mrb, &loc, data); + } +} + +#ifndef MRB_DISABLE_STDIO + +static void +print_backtrace(mrb_state *mrb, mrb_value backtrace) +{ + int i, n; + FILE *stream = stderr; + + if (!mrb_array_p(backtrace)) return; + + n = RARRAY_LEN(backtrace) - 1; + if (n == 0) return; + + fprintf(stream, "trace:\n"); + for (i=0; i<n; i++) { + mrb_value entry = RARRAY_PTR(backtrace)[n-i-1]; + + if (mrb_string_p(entry)) { + fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry)); + } + } +} + +static int +packed_bt_len(struct backtrace_location *bt, int n) +{ + int len = 0; + int i; + + for (i=0; i<n; i++) { + if (!bt[i].filename && !bt[i].lineno && !bt[i].method_id) + continue; + len++; + } + return len; +} + +static void +print_packed_backtrace(mrb_state *mrb, mrb_value packed) +{ + FILE *stream = stderr; + struct backtrace_location *bt; + int n, i; + int ai = mrb_gc_arena_save(mrb); + + bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, packed, &bt_type); + if (bt == NULL) return; + n = (mrb_int)RDATA(packed)->flags; + + if (packed_bt_len(bt, n) == 0) return; + fprintf(stream, "trace:\n"); + for (i = 0; i<n; i++) { + struct backtrace_location *entry = &bt[n-i-1]; + if (entry->filename == NULL) continue; + fprintf(stream, "\t[%d] %s:%d", i, entry->filename, entry->lineno); + if (entry->method_id != 0) { + const char *method_name; + + method_name = mrb_sym2name(mrb, entry->method_id); + fprintf(stream, ":in %s", method_name); + mrb_gc_arena_restore(mrb, ai); + } + fprintf(stream, "\n"); + } +} + +/* mrb_print_backtrace + + function to retrieve backtrace information from the last exception. +*/ + +MRB_API void +mrb_print_backtrace(mrb_state *mrb) +{ + mrb_value backtrace; + + if (!mrb->exc) { + return; + } + + backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace")); + if (mrb_nil_p(backtrace)) return; + if (mrb_array_p(backtrace)) { + print_backtrace(mrb, backtrace); + } + else { + print_packed_backtrace(mrb, backtrace); + } +} +#else + +MRB_API void +mrb_print_backtrace(mrb_state *mrb) +{ +} + +#endif + +static void +count_backtrace_i(mrb_state *mrb, + struct backtrace_location *loc, + void *data) +{ + int *lenp = (int*)data; + + if (loc->filename == NULL) return; + (*lenp)++; +} + +static void +pack_backtrace_i(mrb_state *mrb, + struct backtrace_location *loc, + void *data) +{ + struct backtrace_location **pptr = (struct backtrace_location**)data; + struct backtrace_location *ptr = *pptr; + + if (loc->filename == NULL) return; + *ptr = *loc; + *pptr = ptr+1; +} + +static mrb_value +packed_backtrace(mrb_state *mrb) +{ + struct RData *backtrace; + ptrdiff_t ciidx = mrb->c->ci - mrb->c->cibase; + int len = 0; + int size; + void *ptr; + + each_backtrace(mrb, ciidx, mrb->c->ci->pc, count_backtrace_i, &len); + size = len * sizeof(struct backtrace_location); + ptr = mrb_malloc(mrb, size); + if (ptr) memset(ptr, 0, size); + backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type); + backtrace->flags = (unsigned int)len; + each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, &ptr); + return mrb_obj_value(backtrace); +} + +void +mrb_keep_backtrace(mrb_state *mrb, mrb_value exc) +{ + mrb_value backtrace; + int ai = mrb_gc_arena_save(mrb); + + backtrace = packed_backtrace(mrb); + mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace); + mrb_gc_arena_restore(mrb, ai); +} + +mrb_value +mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) +{ + struct backtrace_location *bt; + mrb_int n, i; + int ai; + + if (mrb_nil_p(backtrace)) { + empty_backtrace: + return mrb_ary_new_capa(mrb, 0); + } + if (mrb_array_p(backtrace)) return backtrace; + bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, backtrace, &bt_type); + if (bt == NULL) goto empty_backtrace; + n = (mrb_int)RDATA(backtrace)->flags; + backtrace = mrb_ary_new_capa(mrb, n); + ai = mrb_gc_arena_save(mrb); + for (i = 0; i < n; i++) { + struct backtrace_location *entry = &bt[i]; + mrb_value btline; + + if (entry->filename == NULL) continue; + btline = mrb_format(mrb, "%S:%S", + mrb_str_new_cstr(mrb, entry->filename), + mrb_fixnum_value(entry->lineno)); + if (entry->method_id != 0) { + mrb_str_cat_lit(mrb, btline, ":in "); + mrb_str_cat_cstr(mrb, btline, mrb_sym2name(mrb, entry->method_id)); + } + mrb_ary_push(mrb, backtrace, btline); + mrb_gc_arena_restore(mrb, ai); + } + + return backtrace; +} + +MRB_API mrb_value +mrb_exc_backtrace(mrb_state *mrb, mrb_value exc) +{ + mrb_sym attr_name; + mrb_value backtrace; + + attr_name = mrb_intern_lit(mrb, "backtrace"); + backtrace = mrb_iv_get(mrb, exc, attr_name); + if (mrb_nil_p(backtrace) || mrb_array_p(backtrace)) { + return backtrace; + } + backtrace = mrb_unpack_backtrace(mrb, backtrace); + mrb_iv_set(mrb, exc, attr_name, backtrace); + return backtrace; +} + +MRB_API mrb_value +mrb_get_backtrace(mrb_state *mrb) +{ + return mrb_unpack_backtrace(mrb, packed_backtrace(mrb)); +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/class.c b/web/server/h2o/libh2o/deps/mruby/src/class.c new file mode 100644 index 000000000..e3888001b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/class.c @@ -0,0 +1,2474 @@ +/* +** class.c - Class class +** +** See Copyright Notice in mruby.h +*/ + +#include <stdarg.h> +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/numeric.h> +#include <mruby/proc.h> +#include <mruby/string.h> +#include <mruby/variable.h> +#include <mruby/error.h> +#include <mruby/data.h> +#include <mruby/istruct.h> + +KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal) + +void +mrb_gc_mark_mt(mrb_state *mrb, struct RClass *c) +{ + khiter_t k; + khash_t(mt) *h = c->mt; + + if (!h) return; + for (k = kh_begin(h); k != kh_end(h); k++) { + if (kh_exist(h, k)) { + struct RProc *m = kh_value(h, k); + if (m) { + mrb_gc_mark(mrb, (struct RBasic*)m); + } + } + } +} + +size_t +mrb_gc_mark_mt_size(mrb_state *mrb, struct RClass *c) +{ + khash_t(mt) *h = c->mt; + + if (!h) return 0; + return kh_size(h); +} + +void +mrb_gc_free_mt(mrb_state *mrb, struct RClass *c) +{ + kh_destroy(mt, mrb, c->mt); +} + +void +mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id) +{ + mrb_value name; + mrb_sym nsym = mrb_intern_lit(mrb, "__classname__"); + + if (mrb_obj_iv_defined(mrb, (struct RObject*)c, nsym)) return; + if (outer == NULL || outer == mrb->object_class) { + name = mrb_symbol_value(id); + } + else { + name = mrb_class_path(mrb, outer); + if (mrb_nil_p(name)) { /* unnamed outer class */ + if (outer != mrb->object_class) { + mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), + mrb_obj_value(outer)); + } + return; + } + mrb_str_cat_cstr(mrb, name, "::"); + mrb_str_cat_cstr(mrb, name, mrb_sym2name(mrb, id)); + } + mrb_obj_iv_set(mrb, (struct RObject*)c, nsym, name); +} + +static void +setup_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id) +{ + mrb_class_name_class(mrb, outer, c, id); + mrb_obj_iv_set(mrb, (struct RObject*)outer, id, mrb_obj_value(c)); +} + +#define make_metaclass(mrb, c) prepare_singleton_class((mrb), (struct RBasic*)(c)) + +static void +prepare_singleton_class(mrb_state *mrb, struct RBasic *o) +{ + struct RClass *sc, *c; + + if (o->c->tt == MRB_TT_SCLASS) return; + sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); + sc->flags |= MRB_FLAG_IS_INHERITED; + sc->mt = kh_init(mt, mrb); + sc->iv = 0; + if (o->tt == MRB_TT_CLASS) { + c = (struct RClass*)o; + if (!c->super) { + sc->super = mrb->class_class; + } + else { + sc->super = c->super->c; + } + } + else if (o->tt == MRB_TT_SCLASS) { + c = (struct RClass*)o; + while (c->super->tt == MRB_TT_ICLASS) + c = c->super; + make_metaclass(mrb, c->super); + sc->super = c->super->c; + } + else { + sc->super = o->c; + prepare_singleton_class(mrb, (struct RBasic*)sc); + } + o->c = sc; + mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc); + mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o); + mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o)); +} + +static struct RClass* +class_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id) +{ + mrb_value c = mrb_const_get(mrb, mrb_obj_value(klass), id); + + mrb_check_type(mrb, c, MRB_TT_CLASS); + return mrb_class_ptr(c); +} + +static struct RClass* +module_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id) +{ + mrb_value c = mrb_const_get(mrb, mrb_obj_value(klass), id); + + mrb_check_type(mrb, c, MRB_TT_MODULE); + return mrb_class_ptr(c); +} + +static mrb_bool +class_ptr_p(mrb_value obj) +{ + switch (mrb_type(obj)) { + case MRB_TT_CLASS: + case MRB_TT_SCLASS: + case MRB_TT_MODULE: + return TRUE; + default: + return FALSE; + } +} + +static void +check_if_class_or_module(mrb_state *mrb, mrb_value obj) +{ + if (!class_ptr_p(obj)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj)); + } +} + +static struct RClass* +define_module(mrb_state *mrb, mrb_sym name, struct RClass *outer) +{ + struct RClass *m; + + if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) { + return module_from_sym(mrb, outer, name); + } + m = mrb_module_new(mrb); + setup_class(mrb, outer, m, name); + + return m; +} + +MRB_API struct RClass* +mrb_define_module_id(mrb_state *mrb, mrb_sym name) +{ + return define_module(mrb, name, mrb->object_class); +} + +MRB_API struct RClass* +mrb_define_module(mrb_state *mrb, const char *name) +{ + return define_module(mrb, mrb_intern_cstr(mrb, name), mrb->object_class); +} + +MRB_API struct RClass* +mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id) +{ + check_if_class_or_module(mrb, outer); + if (mrb_const_defined_at(mrb, outer, id)) { + mrb_value old = mrb_const_get(mrb, outer, id); + + if (mrb_type(old) != MRB_TT_MODULE) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old)); + } + return mrb_class_ptr(old); + } + return define_module(mrb, id, mrb_class_ptr(outer)); +} + +MRB_API struct RClass* +mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name) +{ + mrb_sym id = mrb_intern_cstr(mrb, name); + struct RClass * c = define_module(mrb, id, outer); + + setup_class(mrb, outer, c, id); + return c; +} + +static struct RClass* +find_origin(struct RClass *c) +{ + MRB_CLASS_ORIGIN(c); + return c; +} + +static struct RClass* +define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *outer) +{ + struct RClass * c; + + if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) { + c = class_from_sym(mrb, outer, name); + MRB_CLASS_ORIGIN(c); + if (super && mrb_class_real(c->super) != super) { + mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)", + mrb_sym2str(mrb, name), + mrb_obj_value(c->super), mrb_obj_value(super)); + } + return c; + } + + c = mrb_class_new(mrb, super); + setup_class(mrb, outer, c, name); + + return c; +} + +MRB_API struct RClass* +mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super) +{ + if (!super) { + mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name)); + } + return define_class(mrb, name, super, mrb->object_class); +} + +MRB_API struct RClass* +mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super) +{ + return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super); +} + +static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value); +#ifdef MRB_METHOD_CACHE +static void mc_clear_all(mrb_state *mrb); +static void mc_clear_by_class(mrb_state *mrb, struct RClass*); +static void mc_clear_by_id(mrb_state *mrb, struct RClass*, mrb_sym); +#else +#define mc_clear_all(mrb) +#define mc_clear_by_class(mrb,c) +#define mc_clear_by_id(mrb,c,s) +#endif + +static void +mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) +{ + mrb_value s; + mrb_sym mid; + + if (!super) + super = mrb->object_class; + super->flags |= MRB_FLAG_IS_INHERITED; + s = mrb_obj_value(super); + mc_clear_by_class(mrb, klass); + mid = mrb_intern_lit(mrb, "inherited"); + if (!mrb_func_basic_p(mrb, s, mid, mrb_bob_init)) { + mrb_value c = mrb_obj_value(klass); + mrb_funcall_argv(mrb, s, mid, 1, &c); + } +} + +MRB_API struct RClass* +mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id) +{ + struct RClass *s; + struct RClass *c; + + if (!mrb_nil_p(super)) { + if (mrb_type(super) != MRB_TT_CLASS) { + mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", + mrb_inspect(mrb, super)); + } + s = mrb_class_ptr(super); + } + else { + s = 0; + } + check_if_class_or_module(mrb, outer); + if (mrb_const_defined_at(mrb, outer, id)) { + mrb_value old = mrb_const_get(mrb, outer, id); + + if (mrb_type(old) != MRB_TT_CLASS) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old)); + } + c = mrb_class_ptr(old); + if (s) { + /* check super class */ + if (mrb_class_real(c->super) != s) { + mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old); + } + } + return c; + } + c = define_class(mrb, id, s, mrb_class_ptr(outer)); + mrb_class_inherited(mrb, mrb_class_real(c->super), c); + + return c; +} + +MRB_API mrb_bool +mrb_class_defined(mrb_state *mrb, const char *name) +{ + mrb_value sym = mrb_check_intern_cstr(mrb, name); + if (mrb_nil_p(sym)) { + return FALSE; + } + return mrb_const_defined(mrb, mrb_obj_value(mrb->object_class), mrb_symbol(sym)); +} + +MRB_API mrb_bool +mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name) +{ + mrb_value sym = mrb_check_intern_cstr(mrb, name); + if (mrb_nil_p(sym)) { + return FALSE; + } + return mrb_const_defined_at(mrb, mrb_obj_value(outer), mrb_symbol(sym)); +} + +MRB_API struct RClass* +mrb_class_get_under(mrb_state *mrb, struct RClass *outer, const char *name) +{ + return class_from_sym(mrb, outer, mrb_intern_cstr(mrb, name)); +} + +MRB_API struct RClass* +mrb_class_get(mrb_state *mrb, const char *name) +{ + return mrb_class_get_under(mrb, mrb->object_class, name); +} + +MRB_API struct RClass* +mrb_exc_get(mrb_state *mrb, const char *name) +{ + struct RClass *exc, *e; + mrb_value c = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), + mrb_intern_cstr(mrb, name)); + + if (mrb_type(c) != MRB_TT_CLASS) { + mrb_raise(mrb, mrb->eException_class, "exception corrupted"); + } + exc = e = mrb_class_ptr(c); + + while (e) { + if (e == mrb->eException_class) + return exc; + e = e->super; + } + return mrb->eException_class; +} + +MRB_API struct RClass* +mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name) +{ + return module_from_sym(mrb, outer, mrb_intern_cstr(mrb, name)); +} + +MRB_API struct RClass* +mrb_module_get(mrb_state *mrb, const char *name) +{ + return mrb_module_get_under(mrb, mrb->object_class, name); +} + +/*! + * Defines a class under the namespace of \a outer. + * \param outer a class which contains the new class. + * \param id name of the new class + * \param super a class from which the new class will derive. + * NULL means \c Object class. + * \return the created class + * \throw TypeError if the constant name \a name is already taken but + * the constant is not a \c Class. + * \throw NameError if the class is already defined but the class can not + * be reopened because its superclass is not \a super. + * \post top-level constant named \a name refers the returned class. + * + * \note if a class named \a name is already defined and its superclass is + * \a super, the function just returns the defined class. + */ +MRB_API struct RClass* +mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, struct RClass *super) +{ + mrb_sym id = mrb_intern_cstr(mrb, name); + struct RClass * c; + +#if 0 + if (!super) { + mrb_warn(mrb, "no super class for '%S::%S', Object assumed", + mrb_obj_value(outer), mrb_sym2str(mrb, id)); + } +#endif + c = define_class(mrb, id, super, outer); + setup_class(mrb, outer, c, id); + return c; +} + +MRB_API void +mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RProc *p) +{ + khash_t(mt) *h; + khiter_t k; + MRB_CLASS_ORIGIN(c); + h = c->mt; + + if (MRB_FROZEN_P(c)) { + if (c->tt == MRB_TT_MODULE) + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen module"); + else + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen class"); + } + if (!h) h = c->mt = kh_init(mt, mrb); + k = kh_put(mt, mrb, h, mid); + kh_value(h, k) = p; + if (p) { + p->c = NULL; + mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p); + } + mc_clear_by_id(mrb, c, mid); +} + +MRB_API void +mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec) +{ + struct RProc *p; + int ai = mrb_gc_arena_save(mrb); + + p = mrb_proc_new_cfunc(mrb, func); + p->target_class = c; + mrb_define_method_raw(mrb, c, mid, p); + mrb_gc_arena_restore(mrb, ai); +} + +MRB_API void +mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec) +{ + mrb_define_method_id(mrb, c, mrb_intern_cstr(mrb, name), func, aspec); +} + +/* a function to raise NotImplementedError with current method name */ +MRB_API void +mrb_notimplement(mrb_state *mrb) +{ + const char *str; + mrb_int len; + mrb_callinfo *ci = mrb->c->ci; + + if (ci->mid) { + str = mrb_sym2name_len(mrb, ci->mid, &len); + mrb_raisef(mrb, E_NOTIMP_ERROR, + "%S() function is unimplemented on this machine", + mrb_str_new_static(mrb, str, (size_t)len)); + } +} + +/* a function to be replacement of unimplemented method */ +MRB_API mrb_value +mrb_notimplement_m(mrb_state *mrb, mrb_value self) +{ + mrb_notimplement(mrb); + /* not reached */ + return mrb_nil_value(); +} + +static mrb_value +check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const char *m) +{ + mrb_value tmp; + + tmp = mrb_check_convert_type(mrb, val, t, c, m); + if (mrb_nil_p(tmp)) { + mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_cstr(mrb, c)); + } + return tmp; +} + +static mrb_value +to_str(mrb_state *mrb, mrb_value val) +{ + return check_type(mrb, val, MRB_TT_STRING, "String", "to_str"); +} + +static mrb_value +to_ary(mrb_state *mrb, mrb_value val) +{ + return check_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); +} + +static mrb_value +to_hash(mrb_state *mrb, mrb_value val) +{ + return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash"); +} + +static mrb_sym +to_sym(mrb_state *mrb, mrb_value ss) +{ + if (mrb_type(ss) == MRB_TT_SYMBOL) { + return mrb_symbol(ss); + } + else if (mrb_string_p(ss)) { + return mrb_intern_str(mrb, to_str(mrb, ss)); + } + else { + mrb_value obj = mrb_funcall(mrb, ss, "inspect", 0); + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj); + /* not reached */ + return 0; + } +} + +/* + retrieve arguments from mrb_state. + + mrb_get_args(mrb, format, ...) + + returns number of arguments parsed. + + format specifiers: + + string mruby type C type note + ---------------------------------------------------------------------------------------------- + o: Object [mrb_value] + C: class/module [mrb_value] + S: String [mrb_value] when ! follows, the value may be nil + A: Array [mrb_value] when ! follows, the value may be nil + H: Hash [mrb_value] when ! follows, the value may be nil + s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil + z: String [char*] NUL terminated string; z! gives NULL for nil + a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil + f: Float [mrb_float] + i: Integer [mrb_int] + b: Boolean [mrb_bool] + n: Symbol [mrb_sym] + d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified + I: Inline struct [void*] + &: Block [mrb_value] + *: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack + |: optional Following arguments are optional + ?: optional given [mrb_bool] true if preceding argument (optional) is given + */ +MRB_API mrb_int +mrb_get_args(mrb_state *mrb, const char *format, ...) +{ + const char *fmt = format; + char c; + int i = 0; + va_list ap; + int argc = mrb->c->ci->argc; + int arg_i = 0; + mrb_value *array_argv; + mrb_bool opt = FALSE; + mrb_bool opt_skip = TRUE; + mrb_bool given = TRUE; + + va_start(ap, format); + if (argc < 0) { + struct RArray *a = mrb_ary_ptr(mrb->c->stack[1]); + + argc = ARY_LEN(a); + array_argv = ARY_PTR(a); + } + else { + array_argv = NULL; + } + +#define ARGV \ + (array_argv ? array_argv : (mrb->c->stack + 1)) + + while ((c = *fmt++)) { + switch (c) { + case '|': + opt = TRUE; + break; + case '*': + opt_skip = FALSE; + goto check_exit; + case '!': + break; + case '&': case '?': + if (opt) opt_skip = FALSE; + break; + default: + break; + } + } + + check_exit: + opt = FALSE; + i = 0; + while ((c = *format++)) { + switch (c) { + case '|': case '*': case '&': case '?': + break; + default: + if (argc <= i) { + if (opt) { + given = FALSE; + } + else { + mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); + } + } + break; + } + + switch (c) { + case 'o': + { + mrb_value *p; + + p = va_arg(ap, mrb_value*); + if (i < argc) { + *p = ARGV[arg_i++]; + i++; + } + } + break; + case 'C': + { + mrb_value *p; + + p = va_arg(ap, mrb_value*); + if (i < argc) { + mrb_value ss; + + ss = ARGV[arg_i++]; + if (!class_ptr_p(ss)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss); + } + *p = ss; + i++; + } + } + break; + case 'S': + { + mrb_value *p; + + p = va_arg(ap, mrb_value*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(ARGV[arg_i])) { + *p = ARGV[arg_i++]; + i++; + break; + } + } + if (i < argc) { + *p = to_str(mrb, ARGV[arg_i++]); + i++; + } + } + break; + case 'A': + { + mrb_value *p; + + p = va_arg(ap, mrb_value*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(ARGV[arg_i])) { + *p = ARGV[arg_i++]; + i++; + break; + } + } + if (i < argc) { + *p = to_ary(mrb, ARGV[arg_i++]); + i++; + } + } + break; + case 'H': + { + mrb_value *p; + + p = va_arg(ap, mrb_value*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(ARGV[arg_i])) { + *p = ARGV[arg_i++]; + i++; + break; + } + } + if (i < argc) { + *p = to_hash(mrb, ARGV[arg_i++]); + i++; + } + } + break; + case 's': + { + mrb_value ss; + char **ps = 0; + mrb_int *pl = 0; + + ps = va_arg(ap, char**); + pl = va_arg(ap, mrb_int*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(ARGV[arg_i])) { + *ps = NULL; + *pl = 0; + i++; arg_i++; + break; + } + } + if (i < argc) { + ss = to_str(mrb, ARGV[arg_i++]); + *ps = RSTRING_PTR(ss); + *pl = RSTRING_LEN(ss); + i++; + } + } + break; + case 'z': + { + mrb_value ss; + const char **ps; + + ps = va_arg(ap, const char**); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(ARGV[arg_i])) { + *ps = NULL; + i++; arg_i++; + break; + } + } + if (i < argc) { + ss = to_str(mrb, ARGV[arg_i++]); + *ps = mrb_string_value_cstr(mrb, &ss); + i++; + } + } + break; + case 'a': + { + mrb_value aa; + struct RArray *a; + mrb_value **pb; + mrb_int *pl; + + pb = va_arg(ap, mrb_value**); + pl = va_arg(ap, mrb_int*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(ARGV[arg_i])) { + *pb = 0; + *pl = 0; + i++; arg_i++; + break; + } + } + if (i < argc) { + aa = to_ary(mrb, ARGV[arg_i++]); + a = mrb_ary_ptr(aa); + *pb = ARY_PTR(a); + *pl = ARY_LEN(a); + i++; + } + } + break; + case 'I': + { + void* *p; + mrb_value ss; + + p = va_arg(ap, void**); + if (i < argc) { + ss = ARGV[arg_i]; + if (mrb_type(ss) != MRB_TT_ISTRUCT) + { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss); + } + *p = mrb_istruct_ptr(ss); + arg_i++; + i++; + } + } + break; + case 'f': + { + mrb_float *p; + + p = va_arg(ap, mrb_float*); + if (i < argc) { + *p = mrb_to_flo(mrb, ARGV[arg_i]); + arg_i++; + i++; + } + } + break; + case 'i': + { + mrb_int *p; + + p = va_arg(ap, mrb_int*); + if (i < argc) { + switch (mrb_type(ARGV[arg_i])) { + case MRB_TT_FIXNUM: + *p = mrb_fixnum(ARGV[arg_i]); + break; + case MRB_TT_FLOAT: + { + mrb_float f = mrb_float(ARGV[arg_i]); + + if (!FIXABLE_FLOAT(f)) { + mrb_raise(mrb, E_RANGE_ERROR, "float too big for int"); + } + *p = (mrb_int)f; + } + break; + case MRB_TT_STRING: + mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer"); + break; + default: + *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i])); + break; + } + arg_i++; + i++; + } + } + break; + case 'b': + { + mrb_bool *boolp = va_arg(ap, mrb_bool*); + + if (i < argc) { + mrb_value b = ARGV[arg_i++]; + *boolp = mrb_test(b); + i++; + } + } + break; + case 'n': + { + mrb_sym *symp; + + symp = va_arg(ap, mrb_sym*); + if (i < argc) { + mrb_value ss; + + ss = ARGV[arg_i++]; + *symp = to_sym(mrb, ss); + i++; + } + } + break; + case 'd': + { + void** datap; + struct mrb_data_type const* type; + + datap = va_arg(ap, void**); + type = va_arg(ap, struct mrb_data_type const*); + if (*format == '!') { + format++; + if (i < argc && mrb_nil_p(ARGV[arg_i])) { + *datap = 0; + i++; arg_i++; + break; + } + } + if (i < argc) { + *datap = mrb_data_get_ptr(mrb, ARGV[arg_i++], type); + ++i; + } + } + break; + + case '&': + { + mrb_value *p, *bp; + + p = va_arg(ap, mrb_value*); + if (mrb->c->ci->argc < 0) { + bp = mrb->c->stack + 2; + } + else { + bp = mrb->c->stack + mrb->c->ci->argc + 1; + } + *p = *bp; + } + break; + case '|': + if (opt_skip && i == argc) return argc; + opt = TRUE; + break; + case '?': + { + mrb_bool *p; + + p = va_arg(ap, mrb_bool*); + *p = given; + } + break; + + case '*': + { + mrb_value **var; + mrb_int *pl; + mrb_bool nocopy = array_argv ? TRUE : FALSE; + + if (*format == '!') { + format++; + nocopy = TRUE; + } + var = va_arg(ap, mrb_value**); + pl = va_arg(ap, mrb_int*); + if (argc > i) { + *pl = argc-i; + if (*pl > 0) { + if (nocopy) { + *var = ARGV+arg_i; + } + else { + mrb_value args = mrb_ary_new_from_values(mrb, *pl, ARGV+arg_i); + RARRAY(args)->c = NULL; + *var = RARRAY_PTR(args); + } + } + i = argc; + arg_i += *pl; + } + else { + *pl = 0; + *var = NULL; + } + } + break; + default: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %S", mrb_str_new(mrb, &c, 1)); + break; + } + } + +#undef ARGV + + if (!c && argc > i) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); + } + va_end(ap); + return i; +} + +static struct RClass* +boot_defclass(mrb_state *mrb, struct RClass *super) +{ + struct RClass *c; + + c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class); + if (super) { + c->super = super; + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super); + } + else { + c->super = mrb->object_class; + } + c->mt = kh_init(mt, mrb); + return c; +} + +static void +boot_initmod(mrb_state *mrb, struct RClass *mod) +{ + if (!mod->mt) { + mod->mt = kh_init(mt, mrb); + } +} + +static struct RClass* +include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) +{ + struct RClass *ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class); + if (m->tt == MRB_TT_ICLASS) { + m = m->c; + } + MRB_CLASS_ORIGIN(m); + ic->iv = m->iv; + ic->mt = m->mt; + ic->super = super; + if (m->tt == MRB_TT_ICLASS) { + ic->c = m->c; + } + else { + ic->c = m; + } + return ic; +} + +static int +include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super) +{ + struct RClass *p, *ic; + void *klass_mt = find_origin(c)->mt; + + while (m) { + int superclass_seen = 0; + + if (m->flags & MRB_FLAG_IS_PREPENDED) + goto skip; + + if (klass_mt && klass_mt == m->mt) + return -1; + + p = c->super; + while (p) { + if (p->tt == MRB_TT_ICLASS) { + if (p->mt == m->mt) { + if (!superclass_seen) { + ins_pos = p; /* move insert point */ + } + goto skip; + } + } else if (p->tt == MRB_TT_CLASS) { + if (!search_super) break; + superclass_seen = 1; + } + p = p->super; + } + + ic = include_class_new(mrb, m, ins_pos->super); + m->flags |= MRB_FLAG_IS_INHERITED; + ins_pos->super = ic; + mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic); + mc_clear_by_class(mrb, ins_pos); + ins_pos = ic; + skip: + m = m->super; + } + mc_clear_all(mrb); + return 0; +} + +MRB_API void +mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +{ + int changed = include_module_at(mrb, c, find_origin(c), m, 1); + if (changed < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); + } +} + +MRB_API void +mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) +{ + struct RClass *origin; + int changed = 0; + + if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); + origin->flags |= MRB_FLAG_IS_ORIGIN | MRB_FLAG_IS_INHERITED; + origin->super = c->super; + c->super = origin; + origin->mt = c->mt; + c->mt = kh_init(mt, mrb); + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin); + c->flags |= MRB_FLAG_IS_PREPENDED; + } + changed = include_module_at(mrb, c, c, m, 0); + if (changed < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic prepend detected"); + } +} + +static mrb_value +mrb_mod_prepend_features(mrb_state *mrb, mrb_value mod) +{ + mrb_value klass; + + mrb_check_type(mrb, mod, MRB_TT_MODULE); + mrb_get_args(mrb, "C", &klass); + mrb_prepend_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod)); + return mod; +} + +static mrb_value +mrb_mod_append_features(mrb_state *mrb, mrb_value mod) +{ + mrb_value klass; + + mrb_check_type(mrb, mod, MRB_TT_MODULE); + mrb_get_args(mrb, "C", &klass); + mrb_include_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod)); + return mod; +} + +/* 15.2.2.4.28 */ +/* + * call-seq: + * mod.include?(module) -> true or false + * + * Returns <code>true</code> if <i>module</i> is included in + * <i>mod</i> or one of <i>mod</i>'s ancestors. + * + * module A + * end + * class B + * include A + * end + * class C < B + * end + * B.include?(A) #=> true + * C.include?(A) #=> true + * A.include?(A) #=> false + */ +static mrb_value +mrb_mod_include_p(mrb_state *mrb, mrb_value mod) +{ + mrb_value mod2; + struct RClass *c = mrb_class_ptr(mod); + + mrb_get_args(mrb, "C", &mod2); + mrb_check_type(mrb, mod2, MRB_TT_MODULE); + + while (c) { + if (c->tt == MRB_TT_ICLASS) { + if (c->c == mrb_class_ptr(mod2)) return mrb_true_value(); + } + c = c->super; + } + return mrb_false_value(); +} + +static mrb_value +mrb_mod_ancestors(mrb_state *mrb, mrb_value self) +{ + mrb_value result; + struct RClass *c = mrb_class_ptr(self); + result = mrb_ary_new(mrb); + while (c) { + if (c->tt == MRB_TT_ICLASS) { + mrb_ary_push(mrb, result, mrb_obj_value(c->c)); + } + else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + mrb_ary_push(mrb, result, mrb_obj_value(c)); + } + c = c->super; + } + + return result; +} + +static mrb_value +mrb_mod_extend_object(mrb_state *mrb, mrb_value mod) +{ + mrb_value obj; + + mrb_check_type(mrb, mod, MRB_TT_MODULE); + mrb_get_args(mrb, "o", &obj); + mrb_include_module(mrb, mrb_class_ptr(mrb_singleton_class(mrb, obj)), mrb_class_ptr(mod)); + return mod; +} + +static mrb_value +mrb_mod_included_modules(mrb_state *mrb, mrb_value self) +{ + mrb_value result; + struct RClass *c = mrb_class_ptr(self); + struct RClass *origin = c; + + MRB_CLASS_ORIGIN(origin); + result = mrb_ary_new(mrb); + while (c) { + if (c != origin && c->tt == MRB_TT_ICLASS) { + if (c->c->tt == MRB_TT_MODULE) { + mrb_ary_push(mrb, result, mrb_obj_value(c->c)); + } + } + c = c->super; + } + + return result; +} + +static mrb_value +mrb_mod_initialize(mrb_state *mrb, mrb_value mod) +{ + mrb_value b; + struct RClass *m = mrb_class_ptr(mod); + boot_initmod(mrb, m); /* bootstrap a newly initialized module */ + mrb_get_args(mrb, "|&", &b); + if (!mrb_nil_p(b)) { + mrb_yield_with_class(mrb, b, 1, &mod, mod, m); + } + return mod; +} + +mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); + +/* 15.2.2.4.33 */ +/* + * call-seq: + * mod.instance_methods(include_super=true) -> array + * + * Returns an array containing the names of the public and protected instance + * methods in the receiver. For a module, these are the public and protected methods; + * for a class, they are the instance (not singleton) methods. With no + * argument, or with an argument that is <code>false</code>, the + * instance methods in <i>mod</i> are returned, otherwise the methods + * in <i>mod</i> and <i>mod</i>'s superclasses are returned. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * def method3() end + * end + * + * A.instance_methods #=> [:method1] + * B.instance_methods(false) #=> [:method2] + * C.instance_methods(false) #=> [:method3] + * C.instance_methods(true).length #=> 43 + */ + +static mrb_value +mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) +{ + struct RClass *c = mrb_class_ptr(mod); + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_class_instance_method_list(mrb, recur, c, 0); +} + +/* implementation of module_eval/class_eval */ +mrb_value mrb_mod_module_eval(mrb_state*, mrb_value); + +static mrb_value +mrb_mod_dummy_visibility(mrb_state *mrb, mrb_value mod) +{ + return mod; +} + +MRB_API mrb_value +mrb_singleton_class(mrb_state *mrb, mrb_value v) +{ + struct RBasic *obj; + + switch (mrb_type(v)) { + case MRB_TT_FALSE: + if (mrb_nil_p(v)) + return mrb_obj_value(mrb->nil_class); + return mrb_obj_value(mrb->false_class); + case MRB_TT_TRUE: + return mrb_obj_value(mrb->true_class); + case MRB_TT_CPTR: + return mrb_obj_value(mrb->object_class); + case MRB_TT_SYMBOL: + case MRB_TT_FIXNUM: + case MRB_TT_FLOAT: + mrb_raise(mrb, E_TYPE_ERROR, "can't define singleton"); + return mrb_nil_value(); /* not reached */ + default: + break; + } + obj = mrb_basic_ptr(v); + prepare_singleton_class(mrb, obj); + return mrb_obj_value(obj->c); +} + +MRB_API void +mrb_define_singleton_method(mrb_state *mrb, struct RObject *o, const char *name, mrb_func_t func, mrb_aspec aspec) +{ + prepare_singleton_class(mrb, (struct RBasic*)o); + mrb_define_method_id(mrb, o->c, mrb_intern_cstr(mrb, name), func, aspec); +} + +MRB_API void +mrb_define_class_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec) +{ + mrb_define_singleton_method(mrb, (struct RObject*)c, name, func, aspec); +} + +MRB_API void +mrb_define_module_function(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t func, mrb_aspec aspec) +{ + mrb_define_class_method(mrb, c, name, func, aspec); + mrb_define_method(mrb, c, name, func, aspec); +} + +#ifdef MRB_METHOD_CACHE +static void +mc_clear_all(mrb_state *mrb) +{ + struct mrb_cache_entry *mc = mrb->cache; + int i; + + for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) { + mc[i].c = 0; + } +} + +static void +mc_clear_by_class(mrb_state *mrb, struct RClass *c) +{ + struct mrb_cache_entry *mc = mrb->cache; + int i; + + if (c->flags & MRB_FLAG_IS_INHERITED) { + mc_clear_all(mrb); + c->flags &= ~MRB_FLAG_IS_INHERITED; + return; + } + for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) { + if (mc[i].c == c) mc[i].c = 0; + } +} + +static void +mc_clear_by_id(mrb_state *mrb, struct RClass *c, mrb_sym mid) +{ + struct mrb_cache_entry *mc = mrb->cache; + int i; + + if (c->flags & MRB_FLAG_IS_INHERITED) { + mc_clear_all(mrb); + c->flags &= ~MRB_FLAG_IS_INHERITED; + return; + } + for (i=0; i<MRB_METHOD_CACHE_SIZE; i++) { + if (mc[i].c == c || mc[i].mid == mid) + mc[i].c = 0; + } +} +#endif + +MRB_API struct RProc* +mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid) +{ + khiter_t k; + struct RProc *m; + struct RClass *c = *cp; +#ifdef MRB_METHOD_CACHE + struct RClass *oc = c; + int h = kh_int_hash_func(mrb, ((intptr_t)oc) ^ mid) & (MRB_METHOD_CACHE_SIZE-1); + struct mrb_cache_entry *mc = &mrb->cache[h]; + + if (mc->c == c && mc->mid == mid) { + return mc->m; + } +#endif + + while (c) { + khash_t(mt) *h = c->mt; + + if (h) { + k = kh_get(mt, mrb, h, mid); + if (k != kh_end(h)) { + m = kh_value(h, k); + if (!m) break; + *cp = c; +#ifdef MRB_METHOD_CACHE + mc->c = oc; + mc->mid = mid; + mc->m = m; +#endif + return m; + } + } + c = c->super; + } + return NULL; /* no method */ +} + +MRB_API struct RProc* +mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid) +{ + struct RProc *m; + + m = mrb_method_search_vm(mrb, &c, mid); + if (!m) { + mrb_value inspect = mrb_funcall(mrb, mrb_obj_value(c), "inspect", 0); + if (mrb_string_p(inspect) && RSTRING_LEN(inspect) > 64) { + inspect = mrb_any_to_s(mrb, mrb_obj_value(c)); + } + mrb_name_error(mrb, mid, "undefined method '%S' for class %S", + mrb_sym2str(mrb, mid), inspect); + } + return m; +} + +static mrb_value +attr_reader(mrb_state *mrb, mrb_value obj) +{ + mrb_value name = mrb_proc_cfunc_env_get(mrb, 0); + return mrb_iv_get(mrb, obj, to_sym(mrb, name)); +} + +static mrb_value +mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) +{ + struct RClass *c = mrb_class_ptr(mod); + mrb_value *argv; + mrb_int argc, i; + int ai; + + mrb_get_args(mrb, "*", &argv, &argc); + ai = mrb_gc_arena_save(mrb); + for (i=0; i<argc; i++) { + mrb_value name, str; + mrb_sym method, sym; + + method = to_sym(mrb, argv[i]); + name = mrb_sym2str(mrb, method); + str = mrb_str_new_capa(mrb, RSTRING_LEN(name)+1); + mrb_str_cat_lit(mrb, str, "@"); + mrb_str_cat_str(mrb, str, name); + sym = mrb_intern_str(mrb, str); + mrb_iv_check(mrb, sym); + name = mrb_symbol_value(sym); + mrb_define_method_raw(mrb, c, method, + mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name)); + mrb_gc_arena_restore(mrb, ai); + } + return mrb_nil_value(); +} + +static mrb_value +attr_writer(mrb_state *mrb, mrb_value obj) +{ + mrb_value name = mrb_proc_cfunc_env_get(mrb, 0); + mrb_value val; + + mrb_get_args(mrb, "o", &val); + mrb_iv_set(mrb, obj, to_sym(mrb, name), val); + return val; +} + +static mrb_value +mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod) +{ + struct RClass *c = mrb_class_ptr(mod); + mrb_value *argv; + mrb_int argc, i; + int ai; + + mrb_get_args(mrb, "*", &argv, &argc); + ai = mrb_gc_arena_save(mrb); + for (i=0; i<argc; i++) { + mrb_value name, str, attr; + mrb_sym method, sym; + + method = to_sym(mrb, argv[i]); + + /* prepare iv name (@name) */ + name = mrb_sym2str(mrb, method); + str = mrb_str_new_capa(mrb, RSTRING_LEN(name)+1); + mrb_str_cat_lit(mrb, str, "@"); + mrb_str_cat_str(mrb, str, name); + sym = mrb_intern_str(mrb, str); + mrb_iv_check(mrb, sym); + attr = mrb_symbol_value(sym); + + /* prepare method name (name=) */ + str = mrb_str_new_capa(mrb, RSTRING_LEN(str)); + mrb_str_cat_str(mrb, str, name); + mrb_str_cat_lit(mrb, str, "="); + method = mrb_intern_str(mrb, str); + + mrb_define_method_raw(mrb, c, method, + mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr)); + mrb_gc_arena_restore(mrb, ai); + } + return mrb_nil_value(); +} + +static mrb_value +mrb_instance_alloc(mrb_state *mrb, mrb_value cv) +{ + struct RClass *c = mrb_class_ptr(cv); + struct RObject *o; + enum mrb_vtype ttype = MRB_INSTANCE_TT(c); + + if (c->tt == MRB_TT_SCLASS) + mrb_raise(mrb, E_TYPE_ERROR, "can't create instance of singleton class"); + + if (ttype == 0) ttype = MRB_TT_OBJECT; + if (ttype <= MRB_TT_CPTR) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv); + } + o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c); + return mrb_obj_value(o); +} + +/* + * call-seq: + * class.new(args, ...) -> obj + * + * Creates a new object of <i>class</i>'s class, then + * invokes that object's <code>initialize</code> method, + * passing it <i>args</i>. This is the method that ends + * up getting called whenever an object is constructed using + * `.new`. + * + */ + +MRB_API mrb_value +mrb_instance_new(mrb_state *mrb, mrb_value cv) +{ + mrb_value obj, blk; + mrb_value *argv; + mrb_int argc; + mrb_sym init; + + mrb_get_args(mrb, "*&", &argv, &argc, &blk); + obj = mrb_instance_alloc(mrb, cv); + init = mrb_intern_lit(mrb, "initialize"); + if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) { + mrb_funcall_with_block(mrb, obj, init, argc, argv, blk); + } + + return obj; +} + +MRB_API mrb_value +mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv) +{ + mrb_value obj; + mrb_sym mid; + + obj = mrb_instance_alloc(mrb, mrb_obj_value(c)); + mid = mrb_intern_lit(mrb, "initialize"); + if (!mrb_func_basic_p(mrb, obj, mid, mrb_bob_init)) { + mrb_funcall_argv(mrb, obj, mid, argc, argv); + } + return obj; +} + +static mrb_value +mrb_class_initialize(mrb_state *mrb, mrb_value c) +{ + mrb_value a, b; + + mrb_get_args(mrb, "|C&", &a, &b); + if (!mrb_nil_p(b)) { + mrb_yield_with_class(mrb, b, 1, &c, c, mrb_class_ptr(c)); + } + return c; +} + +static mrb_value +mrb_class_new_class(mrb_state *mrb, mrb_value cv) +{ + mrb_int n; + mrb_value super, blk; + mrb_value new_class; + mrb_sym mid; + + n = mrb_get_args(mrb, "|C&", &super, &blk); + if (n == 0) { + super = mrb_obj_value(mrb->object_class); + } + new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super))); + mid = mrb_intern_lit(mrb, "initialize"); + if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) { + mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk); + } + mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class)); + return new_class; +} + +static mrb_value +mrb_class_superclass(mrb_state *mrb, mrb_value klass) +{ + struct RClass *c; + + c = mrb_class_ptr(klass); + c = find_origin(c)->super; + while (c && c->tt == MRB_TT_ICLASS) { + c = find_origin(c)->super; + } + if (!c) return mrb_nil_value(); + return mrb_obj_value(c); +} + +static mrb_value +mrb_bob_init(mrb_state *mrb, mrb_value cv) +{ + return mrb_nil_value(); +} + +static mrb_value +mrb_bob_not(mrb_state *mrb, mrb_value cv) +{ + return mrb_bool_value(!mrb_test(cv)); +} + +/* 15.3.1.3.1 */ +/* 15.3.1.3.10 */ +/* 15.3.1.3.11 */ +/* + * call-seq: + * obj == other -> true or false + * obj.equal?(other) -> true or false + * obj.eql?(other) -> true or false + * + * Equality---At the <code>Object</code> level, <code>==</code> returns + * <code>true</code> only if <i>obj</i> and <i>other</i> are the + * same object. Typically, this method is overridden in descendant + * classes to provide class-specific meaning. + * + * Unlike <code>==</code>, the <code>equal?</code> method should never be + * overridden by subclasses: it is used to determine object identity + * (that is, <code>a.equal?(b)</code> iff <code>a</code> is the same + * object as <code>b</code>). + * + * The <code>eql?</code> method returns <code>true</code> if + * <i>obj</i> and <i>anObject</i> have the same value. Used by + * <code>Hash</code> to test members for equality. For objects of + * class <code>Object</code>, <code>eql?</code> is synonymous with + * <code>==</code>. Subclasses normally continue this tradition, but + * there are exceptions. <code>Numeric</code> types, for example, + * perform type conversion across <code>==</code>, but not across + * <code>eql?</code>, so: + * + * 1 == 1.0 #=> true + * 1.eql? 1.0 #=> false + */ +mrb_value +mrb_obj_equal_m(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + + mrb_get_args(mrb, "o", &arg); + return mrb_bool_value(mrb_obj_equal(mrb, self, arg)); +} + +static mrb_value +mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + + mrb_get_args(mrb, "o", &arg); + return mrb_bool_value(!mrb_equal(mrb, self, arg)); +} + +MRB_API mrb_bool +mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid) +{ + struct RProc *m; + + m = mrb_method_search_vm(mrb, &c, mid); + if (!m) { + return FALSE; + } + return TRUE; +} + +MRB_API mrb_bool +mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid) +{ + return mrb_obj_respond_to(mrb, mrb_class(mrb, obj), mid); +} + +MRB_API mrb_value +mrb_class_path(mrb_state *mrb, struct RClass *c) +{ + mrb_value path; + mrb_sym nsym = mrb_intern_lit(mrb, "__classname__"); + + path = mrb_obj_iv_get(mrb, (struct RObject*)c, nsym); + if (mrb_nil_p(path)) { + /* no name (yet) */ + return mrb_class_find_path(mrb, c); + } + else if (mrb_symbol_p(path)) { + /* topleve class/module */ + const char *str; + mrb_int len; + + str = mrb_sym2name_len(mrb, mrb_symbol(path), &len); + return mrb_str_new(mrb, str, len); + } + return mrb_str_dup(mrb, path); +} + +MRB_API struct RClass* +mrb_class_real(struct RClass* cl) +{ + if (cl == 0) + return NULL; + while ((cl->tt == MRB_TT_SCLASS) || (cl->tt == MRB_TT_ICLASS)) { + cl = cl->super; + } + return cl; +} + +MRB_API const char* +mrb_class_name(mrb_state *mrb, struct RClass* c) +{ + mrb_value path = mrb_class_path(mrb, c); + if (mrb_nil_p(path)) { + path = mrb_str_new_lit(mrb, "#<Class:"); + mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c)); + mrb_str_cat_lit(mrb, path, ">"); + } + return RSTRING_PTR(path); +} + +MRB_API const char* +mrb_obj_classname(mrb_state *mrb, mrb_value obj) +{ + return mrb_class_name(mrb, mrb_obj_class(mrb, obj)); +} + +/*! + * Ensures a class can be derived from super. + * + * \param super a reference to an object. + * \exception TypeError if \a super is not a Class or \a super is a singleton class. + */ +static void +mrb_check_inheritable(mrb_state *mrb, struct RClass *super) +{ + if (super->tt != MRB_TT_CLASS) { + mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", mrb_obj_value(super)); + } + if (super->tt == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of singleton class"); + } + if (super == mrb->class_class) { + mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of Class"); + } +} + +/*! + * Creates a new class. + * \param super a class from which the new class derives. + * \exception TypeError \a super is not inheritable. + * \exception TypeError \a super is the Class class. + */ +MRB_API struct RClass* +mrb_class_new(mrb_state *mrb, struct RClass *super) +{ + struct RClass *c; + + if (super) { + mrb_check_inheritable(mrb, super); + } + c = boot_defclass(mrb, super); + if (super) { + MRB_SET_INSTANCE_TT(c, MRB_INSTANCE_TT(super)); + } + make_metaclass(mrb, c); + + return c; +} + +/*! + * Creates a new module. + */ +MRB_API struct RClass* +mrb_module_new(mrb_state *mrb) +{ + struct RClass *m = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_MODULE, mrb->module_class); + boot_initmod(mrb, m); + return m; +} + +/* + * call-seq: + * obj.class => class + * + * Returns the class of <i>obj</i>, now preferred over + * <code>Object#type</code>, as an object's type in Ruby is only + * loosely tied to that object's class. This method must always be + * called with an explicit receiver, as <code>class</code> is also a + * reserved word in Ruby. + * + * 1.class #=> Fixnum + * self.class #=> Object + */ + +MRB_API struct RClass* +mrb_obj_class(mrb_state *mrb, mrb_value obj) +{ + return mrb_class_real(mrb_class(mrb, obj)); +} + +MRB_API void +mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b) +{ + struct RProc *m = mrb_method_search(mrb, c, b); + + mrb_define_method_raw(mrb, c, a, m); +} + +/*! + * Defines an alias of a method. + * \param klass the class which the original method belongs to + * \param name1 a new name for the method + * \param name2 the original name of the method + */ +MRB_API void +mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2) +{ + mrb_alias_method(mrb, klass, mrb_intern_cstr(mrb, name1), mrb_intern_cstr(mrb, name2)); +} + +/* + * call-seq: + * mod.to_s -> string + * + * Return a string representing this module or class. For basic + * classes and modules, this is the name. For singletons, we + * show information on the thing we're attached to as well. + */ + +static mrb_value +mrb_mod_to_s(mrb_state *mrb, mrb_value klass) +{ + mrb_value str; + + if (mrb_type(klass) == MRB_TT_SCLASS) { + mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__")); + + str = mrb_str_new_lit(mrb, "#<Class:"); + + if (class_ptr_p(v)) { + mrb_str_cat_str(mrb, str, mrb_inspect(mrb, v)); + } + else { + mrb_str_cat_str(mrb, str, mrb_any_to_s(mrb, v)); + } + return mrb_str_cat_lit(mrb, str, ">"); + } + else { + struct RClass *c; + mrb_value path; + + str = mrb_str_new_capa(mrb, 32); + c = mrb_class_ptr(klass); + path = mrb_class_path(mrb, c); + + if (mrb_nil_p(path)) { + switch (mrb_type(klass)) { + case MRB_TT_CLASS: + mrb_str_cat_lit(mrb, str, "#<Class:"); + break; + + case MRB_TT_MODULE: + mrb_str_cat_lit(mrb, str, "#<Module:"); + break; + + default: + /* Shouldn't be happened? */ + mrb_str_cat_lit(mrb, str, "#<??????:"); + break; + } + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c)); + return mrb_str_cat_lit(mrb, str, ">"); + } + else { + return path; + } + } +} + +static mrb_value +mrb_mod_alias(mrb_state *mrb, mrb_value mod) +{ + struct RClass *c = mrb_class_ptr(mod); + mrb_sym new_name, old_name; + + mrb_get_args(mrb, "nn", &new_name, &old_name); + mrb_alias_method(mrb, c, new_name, old_name); + return mrb_nil_value(); +} + +static void +undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) +{ + if (!mrb_obj_respond_to(mrb, c, a)) { + mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c)); + } + else { + mrb_define_method_raw(mrb, c, a, NULL); + } +} + +MRB_API void +mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name) +{ + undef_method(mrb, c, mrb_intern_cstr(mrb, name)); +} + +MRB_API void +mrb_undef_class_method(mrb_state *mrb, struct RClass *c, const char *name) +{ + mrb_undef_method(mrb, mrb_class_ptr(mrb_singleton_class(mrb, mrb_obj_value(c))), name); +} + +static mrb_value +mrb_mod_undef(mrb_state *mrb, mrb_value mod) +{ + struct RClass *c = mrb_class_ptr(mod); + mrb_int argc; + mrb_value *argv; + + mrb_get_args(mrb, "*", &argv, &argc); + while (argc--) { + undef_method(mrb, c, to_sym(mrb, *argv)); + argv++; + } + return mrb_nil_value(); +} + +static mrb_value +mod_define_method(mrb_state *mrb, mrb_value self) +{ + struct RClass *c = mrb_class_ptr(self); + struct RProc *p; + mrb_sym mid; + mrb_value proc = mrb_undef_value(); + mrb_value blk; + + mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); + switch (mrb_type(proc)) { + case MRB_TT_PROC: + blk = proc; + break; + case MRB_TT_UNDEF: + /* ignored */ + break; + default: + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); + break; + } + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + p->flags |= MRB_PROC_STRICT; + mrb_define_method_raw(mrb, c, mid, p); + return mrb_symbol_value(mid); +} + +static void +check_cv_name_str(mrb_state *mrb, mrb_value str) +{ + const char *s = RSTRING_PTR(str); + mrb_int len = RSTRING_LEN(str); + + if (len < 3 || !(s[0] == '@' && s[1] == '@')) { + mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); + } +} + +static void +check_cv_name_sym(mrb_state *mrb, mrb_sym id) +{ + check_cv_name_str(mrb, mrb_sym2str(mrb, id)); +} + +/* 15.2.2.4.16 */ +/* + * call-seq: + * obj.class_variable_defined?(symbol) -> true or false + * + * Returns <code>true</code> if the given class variable is defined + * in <i>obj</i>. + * + * class Fred + * @@foo = 99 + * end + * Fred.class_variable_defined?(:@@foo) #=> true + * Fred.class_variable_defined?(:@@bar) #=> false + */ + +static mrb_value +mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + return mrb_bool_value(mrb_cv_defined(mrb, mod, id)); +} + +/* 15.2.2.4.17 */ +/* + * call-seq: + * mod.class_variable_get(symbol) -> obj + * + * Returns the value of the given class variable (or throws a + * <code>NameError</code> exception). The <code>@@</code> part of the + * variable name should be included for regular class variables + * + * class Fred + * @@foo = 99 + * end + * Fred.class_variable_get(:@@foo) #=> 99 + */ + +static mrb_value +mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + return mrb_cv_get(mrb, mod, id); +} + +/* 15.2.2.4.18 */ +/* + * call-seq: + * obj.class_variable_set(symbol, obj) -> obj + * + * Sets the class variable names by <i>symbol</i> to + * <i>object</i>. + * + * class Fred + * @@foo = 99 + * def foo + * @@foo + * end + * end + * Fred.class_variable_set(:@@foo, 101) #=> 101 + * Fred.new.foo #=> 101 + */ + +static mrb_value +mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod) +{ + mrb_value value; + mrb_sym id; + + mrb_get_args(mrb, "no", &id, &value); + check_cv_name_sym(mrb, id); + mrb_cv_set(mrb, mod, id, value); + return value; +} + +/* 15.2.2.4.39 */ +/* + * call-seq: + * remove_class_variable(sym) -> obj + * + * Removes the definition of the <i>sym</i>, returning that + * constant's value. + * + * class Dummy + * @@var = 99 + * puts @@var + * p class_variables + * remove_class_variable(:@@var) + * p class_variables + * end + * + * <em>produces:</em> + * + * 99 + * [:@@var] + * [] + */ + +static mrb_value +mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) +{ + mrb_value val; + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + + val = mrb_iv_remove(mrb, mod, id); + if (!mrb_undef_p(val)) return val; + + if (mrb_cv_defined(mrb, mod, id)) { + mrb_name_error(mrb, id, "cannot remove %S for %S", + mrb_sym2str(mrb, id), mod); + } + + mrb_name_error(mrb, id, "class variable %S not defined for %S", + mrb_sym2str(mrb, id), mod); + + /* not reached */ + return mrb_nil_value(); +} + +/* 15.2.2.4.34 */ +/* + * call-seq: + * mod.method_defined?(symbol) -> true or false + * + * Returns +true+ if the named method is defined by + * _mod_ (or its included modules and, if _mod_ is a class, + * its ancestors). Public and protected methods are matched. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * include A + * def method3() end + * end + * + * A.method_defined? :method1 #=> true + * C.method_defined? "method1" #=> true + * C.method_defined? "method2" #=> true + * C.method_defined? "method3" #=> true + * C.method_defined? "method4" #=> false + */ + +static mrb_value +mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); +} + +static void +remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) +{ + struct RClass *c = mrb_class_ptr(mod); + khash_t(mt) *h = find_origin(c)->mt; + khiter_t k; + + if (h) { + k = kh_get(mt, mrb, h, mid); + if (k != kh_end(h)) { + kh_del(mt, mrb, h, k); + mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid)); + return; + } + } + + mrb_name_error(mrb, mid, "method '%S' not defined in %S", + mrb_sym2str(mrb, mid), mod); +} + +/* 15.2.2.4.41 */ +/* + * call-seq: + * remove_method(symbol) -> self + * + * Removes the method identified by _symbol_ from the current + * class. For an example, see <code>Module.undef_method</code>. + */ + +static mrb_value +mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) +{ + mrb_int argc; + mrb_value *argv; + + mrb_get_args(mrb, "*", &argv, &argc); + while (argc--) { + remove_method(mrb, mod, to_sym(mrb, *argv)); + argv++; + } + return mod; +} + + + +static void +check_const_name_str(mrb_state *mrb, mrb_value str) +{ + if (RSTRING_LEN(str) < 1 || !ISUPPER(*RSTRING_PTR(str))) { + mrb_name_error(mrb, mrb_intern_str(mrb, str), "wrong constant name %S", str); + } +} + +static void +check_const_name_sym(mrb_state *mrb, mrb_sym id) +{ + check_const_name_str(mrb, mrb_sym2str(mrb, id)); +} + +static mrb_value +const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool inherit) +{ + if (inherit) { + return mrb_bool_value(mrb_const_defined(mrb, mod, id)); + } + return mrb_bool_value(mrb_const_defined_at(mrb, mod, id)); +} + +static mrb_value +mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + mrb_bool inherit = TRUE; + + mrb_get_args(mrb, "n|b", &id, &inherit); + check_const_name_sym(mrb, id); + return const_defined(mrb, mod, id, inherit); +} + +static mrb_value +mrb_const_get_sym(mrb_state *mrb, mrb_value mod, mrb_sym id) +{ + check_const_name_sym(mrb, id); + return mrb_const_get(mrb, mod, id); +} + +static mrb_value +mrb_mod_const_get(mrb_state *mrb, mrb_value mod) +{ + mrb_value path; + mrb_sym id; + char *ptr; + mrb_int off, end, len; + + mrb_get_args(mrb, "o", &path); + + if (mrb_symbol_p(path)) { + /* const get with symbol */ + id = mrb_symbol(path); + return mrb_const_get_sym(mrb, mod, id); + } + + /* const get with class path string */ + path = mrb_string_type(mrb, path); + ptr = RSTRING_PTR(path); + len = RSTRING_LEN(path); + off = 0; + + while (off < len) { + end = mrb_str_index_lit(mrb, path, "::", off); + end = (end == -1) ? len : end; + id = mrb_intern(mrb, ptr+off, end-off); + mod = mrb_const_get_sym(mrb, mod, id); + off = (end == len) ? end : end+2; + } + + return mod; +} + +static mrb_value +mrb_mod_const_set(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + mrb_value value; + + mrb_get_args(mrb, "no", &id, &value); + check_const_name_sym(mrb, id); + mrb_const_set(mrb, mod, id, value); + return value; +} + +static mrb_value +mrb_mod_remove_const(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + mrb_value val; + + mrb_get_args(mrb, "n", &id); + check_const_name_sym(mrb, id); + val = mrb_iv_remove(mrb, mod, id); + if (mrb_undef_p(val)) { + mrb_name_error(mrb, id, "constant %S not defined", mrb_sym2str(mrb, id)); + } + return val; +} + +static mrb_value +mrb_mod_const_missing(mrb_state *mrb, mrb_value mod) +{ + mrb_sym sym; + + mrb_get_args(mrb, "n", &sym); + + if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) { + mrb_name_error(mrb, sym, "uninitialized constant %S::%S", + mod, + mrb_sym2str(mrb, sym)); + } + else { + mrb_name_error(mrb, sym, "uninitialized constant %S", + mrb_sym2str(mrb, sym)); + } + /* not reached */ + return mrb_nil_value(); +} + +static mrb_value +mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) +{ + mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented"); + return mrb_nil_value(); /* not reached */ +} + +static mrb_value +mrb_mod_eqq(mrb_state *mrb, mrb_value mod) +{ + mrb_value obj; + mrb_bool eqq; + + mrb_get_args(mrb, "o", &obj); + eqq = mrb_obj_is_kind_of(mrb, obj, mrb_class_ptr(mod)); + + return mrb_bool_value(eqq); +} + +MRB_API mrb_value +mrb_mod_module_function(mrb_state *mrb, mrb_value mod) +{ + mrb_value *argv; + mrb_int argc, i; + mrb_sym mid; + struct RProc *method_rproc; + struct RClass *rclass; + int ai; + + mrb_check_type(mrb, mod, MRB_TT_MODULE); + + mrb_get_args(mrb, "*", &argv, &argc); + if (argc == 0) { + /* set MODFUNC SCOPE if implemented */ + return mod; + } + + /* set PRIVATE method visibility if implemented */ + /* mrb_mod_dummy_visibility(mrb, mod); */ + + for (i=0; i<argc; i++) { + mrb_check_type(mrb, argv[i], MRB_TT_SYMBOL); + + mid = mrb_symbol(argv[i]); + rclass = mrb_class_ptr(mod); + method_rproc = mrb_method_search(mrb, rclass, mid); + + prepare_singleton_class(mrb, (struct RBasic*)rclass); + ai = mrb_gc_arena_save(mrb); + mrb_define_method_raw(mrb, rclass->c, mid, method_rproc); + mrb_gc_arena_restore(mrb, ai); + } + + return mod; +} + +/* implementation of __id__ */ +mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self); +/* implementation of instance_eval */ +mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); +/* implementation of Module.nesting */ +mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); + +void +mrb_init_class(mrb_state *mrb) +{ + struct RClass *bob; /* BasicObject */ + struct RClass *obj; /* Object */ + struct RClass *mod; /* Module */ + struct RClass *cls; /* Class */ + + /* boot class hierarchy */ + bob = boot_defclass(mrb, 0); + obj = boot_defclass(mrb, bob); mrb->object_class = obj; + mod = boot_defclass(mrb, obj); mrb->module_class = mod;/* obj -> mod */ + cls = boot_defclass(mrb, mod); mrb->class_class = cls; /* obj -> cls */ + /* fix-up loose ends */ + bob->c = obj->c = mod->c = cls->c = cls; + make_metaclass(mrb, bob); + make_metaclass(mrb, obj); + make_metaclass(mrb, mod); + make_metaclass(mrb, cls); + + /* name basic classes */ + mrb_define_const(mrb, bob, "BasicObject", mrb_obj_value(bob)); + mrb_define_const(mrb, obj, "BasicObject", mrb_obj_value(bob)); + mrb_define_const(mrb, obj, "Object", mrb_obj_value(obj)); + mrb_define_const(mrb, obj, "Module", mrb_obj_value(mod)); + mrb_define_const(mrb, obj, "Class", mrb_obj_value(cls)); + + /* name each classes */ + mrb_class_name_class(mrb, NULL, bob, mrb_intern_lit(mrb, "BasicObject")); + mrb_class_name_class(mrb, NULL, obj, mrb_intern_lit(mrb, "Object")); /* 15.2.1 */ + mrb_class_name_class(mrb, NULL, mod, mrb_intern_lit(mrb, "Module")); /* 15.2.2 */ + mrb_class_name_class(mrb, NULL, cls, mrb_intern_lit(mrb, "Class")); /* 15.2.3 */ + + mrb->proc_class = mrb_define_class(mrb, "Proc", mrb->object_class); /* 15.2.17 */ + MRB_SET_INSTANCE_TT(mrb->proc_class, MRB_TT_PROC); + + MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS); + mrb_define_method(mrb, bob, "initialize", mrb_bob_init, MRB_ARGS_NONE()); + mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE()); + mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ + mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ + mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ + mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ + + mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */ + mrb_define_method(mrb, cls, "new", mrb_instance_new, MRB_ARGS_ANY()); /* 15.2.3.3.3 */ + mrb_define_method(mrb, cls, "initialize", mrb_class_initialize, MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */ + mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1)); + + MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE); + mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */ + mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */ + mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */ + mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ + mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ + mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "prepend_features", mrb_mod_prepend_features, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "include?", mrb_mod_include_p, MRB_ARGS_REQ(1)); /* 15.2.2.4.28 */ + mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */ + mrb_define_method(mrb, mod, "class_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.15 */ + mrb_define_method(mrb, mod, "included", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.29 */ + mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */ + mrb_define_method(mrb, mod, "initialize", mrb_mod_initialize, MRB_ARGS_NONE()); /* 15.2.2.4.31 */ + mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */ + mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ + mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.35 */ + mrb_define_method(mrb, mod, "module_function", mrb_mod_module_function, MRB_ARGS_ANY()); + mrb_define_method(mrb, mod, "private", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.36 */ + mrb_define_method(mrb, mod, "protected", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.37 */ + mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */ + mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ + mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ + mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */ + mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */ + mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, mod, "inspect", mrb_mod_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, mod, "alias_method", mrb_mod_alias, MRB_ARGS_ANY()); /* 15.2.2.4.8 */ + mrb_define_method(mrb, mod, "ancestors", mrb_mod_ancestors, MRB_ARGS_NONE()); /* 15.2.2.4.9 */ + mrb_define_method(mrb, mod, "undef_method", mrb_mod_undef, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ + mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, MRB_ARGS_ARG(1,1)); /* 15.2.2.4.20 */ + mrb_define_method(mrb, mod, "const_get", mrb_mod_const_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.21 */ + mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */ + mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ + mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */ + mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); + mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ + mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ + mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */ + + mrb_undef_method(mrb, cls, "append_features"); + mrb_undef_method(mrb, cls, "extend_object"); +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/codedump.c b/web/server/h2o/libh2o/deps/mruby/src/codedump.c new file mode 100644 index 000000000..e3a33419c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/codedump.c @@ -0,0 +1,474 @@ +#include <mruby.h> +#include <mruby/irep.h> +#include <mruby/debug.h> +#include <mruby/opcode.h> +#include <mruby/string.h> +#include <mruby/proc.h> + +#ifndef MRB_DISABLE_STDIO +static int +print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre) +{ + size_t i; + + if (n == 0) return 0; + + for (i=0; i+1<irep->nlocals; i++) { + if (irep->lv[i].r == n) { + mrb_sym sym = irep->lv[i].name; + if (pre) printf(" "); + printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym)); + return 1; + } + } + return 0; +} + +#define RA 1 +#define RB 2 +#define RAB 3 + +static void +print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r) +{ + int pre = 0; + + if (!irep->lv + || ((!(r & RA) || GETARG_A(c) >= irep->nlocals) + && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) { + printf("\n"); + return; + } + printf("\t; "); + if (r & RA) { + pre = print_r(mrb, irep, GETARG_A(c), 0); + } + if (r & RB) { + print_r(mrb, irep, GETARG_B(c), pre); + } + printf("\n"); +} +#endif + +static void +codedump(mrb_state *mrb, mrb_irep *irep) +{ +#ifndef MRB_DISABLE_STDIO + int i; + int ai; + mrb_code c; + const char *file = NULL, *next_file; + int32_t line; + + if (!irep) return; + printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, + irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); + + for (i = 0; i < (int)irep->ilen; i++) { + ai = mrb_gc_arena_save(mrb); + + next_file = mrb_debug_get_filename(irep, i); + if (next_file && file != next_file) { + printf("file: %s\n", next_file); + file = next_file; + } + line = mrb_debug_get_line(irep, i); + if (line < 0) { + printf(" "); + } + else { + printf("%5d ", line); + } + + printf("%03d ", i); + c = irep->iseq[i]; + switch (GET_OPCODE(c)) { + case OP_NOP: + printf("OP_NOP\n"); + break; + case OP_MOVE: + printf("OP_MOVE\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_LOADL: + { + mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value s = mrb_inspect(mrb, v); + printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + } + print_lv(mrb, irep, c, RA); + break; + case OP_LOADI: + printf("OP_LOADI\tR%d\t%d\t", GETARG_A(c), GETARG_sBx(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_LOADSYM: + printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_LOADNIL: + printf("OP_LOADNIL\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_LOADSELF: + printf("OP_LOADSELF\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_LOADT: + printf("OP_LOADT\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_LOADF: + printf("OP_LOADF\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETGLOBAL: + printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_SETGLOBAL: + printf("OP_SETGLOBAL\t:%s\tR%d\t", + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), + GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETCONST: + printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_SETCONST: + printf("OP_SETCONST\t:%s\tR%d\t", + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), + GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETMCNST: + printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RAB); + break; + case OP_SETMCNST: + printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1, + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), + GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETIV: + printf("OP_GETIV\tR%d\t%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_SETIV: + printf("OP_SETIV\t%s\tR%d", + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), + GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETUPVAR: + printf("OP_GETUPVAR\tR%d\t%d\t%d", + GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_SETUPVAR: + printf("OP_SETUPVAR\tR%d\t%d\t%d", + GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_GETCV: + printf("OP_GETCV\tR%d\t%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_SETCV: + printf("OP_SETCV\t%s\tR%d", + mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), + GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_JMP: + printf("OP_JMP\t%03d\n", i+GETARG_sBx(c)); + break; + case OP_JMPIF: + printf("OP_JMPIF\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c)); + break; + case OP_JMPNOT: + printf("OP_JMPNOT\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c)); + break; + case OP_SEND: + printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_SENDB: + printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_TAILCALL: + printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_SUPER: + printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c), + GETARG_C(c)); + break; + case OP_ARGARY: + printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c), + (GETARG_Bx(c)>>10)&0x3f, + (GETARG_Bx(c)>>9)&0x1, + (GETARG_Bx(c)>>4)&0x1f, + (GETARG_Bx(c)>>0)&0xf); + print_lv(mrb, irep, c, RA); + break; + + case OP_ENTER: + printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", + (GETARG_Ax(c)>>18)&0x1f, + (GETARG_Ax(c)>>13)&0x1f, + (GETARG_Ax(c)>>12)&0x1, + (GETARG_Ax(c)>>7)&0x1f, + (GETARG_Ax(c)>>2)&0x1f, + (GETARG_Ax(c)>>1)&0x1, + GETARG_Ax(c) & 0x1); + break; + case OP_RETURN: + printf("OP_RETURN\tR%d", GETARG_A(c)); + switch (GETARG_B(c)) { + case OP_R_NORMAL: + printf("\tnormal\t"); break; + case OP_R_RETURN: + printf("\treturn\t"); break; + case OP_R_BREAK: + printf("\tbreak\t"); break; + default: + printf("\tbroken\t"); break; + } + print_lv(mrb, irep, c, RA); + break; + case OP_BLKPUSH: + printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c), + (GETARG_Bx(c)>>10)&0x3f, + (GETARG_Bx(c)>>9)&0x1, + (GETARG_Bx(c)>>4)&0x1f, + (GETARG_Bx(c)>>0)&0xf); + print_lv(mrb, irep, c, RA); + break; + + case OP_LAMBDA: + printf("OP_LAMBDA\tR%d\tI(%+d)\t", GETARG_A(c), GETARG_b(c)+1); + switch (GETARG_c(c)) { + case OP_L_METHOD: + printf("method"); break; + case OP_L_BLOCK: + printf("block"); break; + case OP_L_LAMBDA: + printf("lambda"); break; + } + print_lv(mrb, irep, c, RA); + break; + case OP_RANGE: + printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_METHOD: + printf("OP_METHOD\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); + print_lv(mrb, irep, c, RA); + break; + + case OP_ADD: + printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_ADDI: + printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_SUB: + printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_SUBI: + printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_MUL: + printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_DIV: + printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_LT: + printf("OP_LT\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_LE: + printf("OP_LE\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_GT: + printf("OP_GT\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_GE: + printf("OP_GE\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + case OP_EQ: + printf("OP_EQ\t\tR%d\t:%s\t%d\n", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), + GETARG_C(c)); + break; + + case OP_STOP: + printf("OP_STOP\n"); + break; + + case OP_ARRAY: + printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_ARYCAT: + printf("OP_ARYCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_ARYPUSH: + printf("OP_ARYPUSH\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_AREF: + printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_APOST: + printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_STRING: + { + mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); + printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + } + print_lv(mrb, irep, c, RA); + break; + case OP_STRCAT: + printf("OP_STRCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_HASH: + printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); + print_lv(mrb, irep, c, RAB); + break; + + case OP_OCLASS: + printf("OP_OCLASS\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_CLASS: + printf("OP_CLASS\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_MODULE: + printf("OP_MODULE\tR%d\t:%s", GETARG_A(c), + mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); + print_lv(mrb, irep, c, RA); + break; + case OP_EXEC: + printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1); + print_lv(mrb, irep, c, RA); + break; + case OP_SCLASS: + printf("OP_SCLASS\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); + print_lv(mrb, irep, c, RAB); + break; + case OP_TCLASS: + printf("OP_TCLASS\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_ERR: + { + mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); + printf("OP_ERR\t%s\n", RSTRING_PTR(s)); + } + break; + case OP_EPUSH: + printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1); + break; + case OP_ONERR: + printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c)); + break; + case OP_RESCUE: + { + int a = GETARG_A(c); + int b = GETARG_B(c); + int cnt = GETARG_C(c); + + if (b == 0) { + printf("OP_RESCUE\tR%d\t\t%s", a, cnt ? "cont" : ""); + print_lv(mrb, irep, c, RA); + break; + } + else { + printf("OP_RESCUE\tR%d\tR%d\t%s", a, b, cnt ? "cont" : ""); + print_lv(mrb, irep, c, RAB); + break; + } + } + break; + case OP_RAISE: + printf("OP_RAISE\tR%d\t\t", GETARG_A(c)); + print_lv(mrb, irep, c, RA); + break; + case OP_POPERR: + printf("OP_POPERR\t%d\t\t\n", GETARG_A(c)); + break; + case OP_EPOP: + printf("OP_EPOP\t%d\n", GETARG_A(c)); + break; + + default: + printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c), + GETARG_A(c), GETARG_B(c), GETARG_C(c)); + break; + } + mrb_gc_arena_restore(mrb, ai); + } + printf("\n"); +#endif +} + +static void +codedump_recur(mrb_state *mrb, mrb_irep *irep) +{ + int i; + + codedump(mrb, irep); + for (i=0; i<irep->rlen; i++) { + codedump_recur(mrb, irep->reps[i]); + } +} + +void +mrb_codedump_all(mrb_state *mrb, struct RProc *proc) +{ + codedump_recur(mrb, proc->body.irep); +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/compar.c b/web/server/h2o/libh2o/deps/mruby/src/compar.c new file mode 100644 index 000000000..0032fc859 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/compar.c @@ -0,0 +1,13 @@ +/* +** compar.c - Comparable module +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> + +void +mrb_init_comparable(mrb_state *mrb) +{ + mrb_define_module(mrb, "Comparable"); /* 15.3.3 */ +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/crc.c b/web/server/h2o/libh2o/deps/mruby/src/crc.c new file mode 100644 index 000000000..290b2ca0e --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/crc.c @@ -0,0 +1,39 @@ +/* +** crc.c - calculate CRC +** +** See Copyright Notice in mruby.h +*/ + +#include <limits.h> +#include <stdint.h> +#include <stddef.h> + +/* Calculate CRC (CRC-16-CCITT) +** +** 0000_0000_0000_0000_0000_0000_0000_0000 +** ^|------- CRC -------|- work --| +** carry +*/ +#define CRC_16_CCITT 0x11021ul /* x^16+x^12+x^5+1 */ +#define CRC_XOR_PATTERN (CRC_16_CCITT << 8) +#define CRC_CARRY_BIT (0x01000000) + +uint16_t +calc_crc_16_ccitt(const uint8_t *src, size_t nbytes, uint16_t crc) +{ + size_t ibyte; + uint32_t ibit; + uint32_t crcwk = crc << 8; + + for (ibyte = 0; ibyte < nbytes; ibyte++) { + crcwk |= *src++; + for (ibit = 0; ibit < CHAR_BIT; ibit++) { + crcwk <<= 1; + if (crcwk & CRC_CARRY_BIT) { + crcwk ^= CRC_XOR_PATTERN; + } + } + } + return (uint16_t)(crcwk >> 8); +} + diff --git a/web/server/h2o/libh2o/deps/mruby/src/debug.c b/web/server/h2o/libh2o/deps/mruby/src/debug.c new file mode 100644 index 000000000..e55f11d4f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/debug.c @@ -0,0 +1,217 @@ +#include <string.h> +#include <mruby.h> +#include <mruby/irep.h> +#include <mruby/debug.h> + +static mrb_irep_debug_info_file* +get_file(mrb_irep_debug_info *info, uint32_t pc) +{ + mrb_irep_debug_info_file **ret; + int32_t count; + + if (pc >= info->pc_count) { return NULL; } + /* get upper bound */ + ret = info->files; + count = info->flen; + while (count > 0) { + int32_t step = count / 2; + mrb_irep_debug_info_file **it = ret + step; + if (!(pc < (*it)->start_pos)) { + ret = it + 1; + count -= step + 1; + } + else { count = step; } + } + + --ret; + + /* check returning file exists inside debug info */ + mrb_assert(info->files <= ret && ret < (info->files + info->flen)); + /* check pc is within the range of returning file */ + mrb_assert((*ret)->start_pos <= pc && + pc < (((ret + 1 - info->files) < info->flen) + ? (*(ret+1))->start_pos : info->pc_count)); + + return *ret; +} + +static mrb_debug_line_type +select_line_type(const uint16_t *lines, size_t lines_len) +{ + size_t line_count = 0; + int prev_line = -1; + size_t i; + for (i = 0; i < lines_len; ++i) { + if (lines[i] != prev_line) { + ++line_count; + } + } + return (sizeof(uint16_t) * lines_len) <= (sizeof(mrb_irep_debug_info_line) * line_count) + ? mrb_debug_line_ary : mrb_debug_line_flat_map; +} + +MRB_API char const* +mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc) +{ + if (irep && pc >= 0 && pc < irep->ilen) { + mrb_irep_debug_info_file* f = NULL; + if (!irep->debug_info) { return irep->filename; } + else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { + return f->filename; + } + } + return NULL; +} + +MRB_API int32_t +mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc) +{ + if (irep && pc >= 0 && pc < irep->ilen) { + mrb_irep_debug_info_file* f = NULL; + if (!irep->debug_info) { + return irep->lines? irep->lines[pc] : -1; + } + else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { + switch (f->line_type) { + case mrb_debug_line_ary: + mrb_assert(f->start_pos <= pc && pc < (f->start_pos + f->line_entry_count)); + return f->lines.ary[pc - f->start_pos]; + + case mrb_debug_line_flat_map: { + /* get upper bound */ + mrb_irep_debug_info_line *ret = f->lines.flat_map; + uint32_t count = f->line_entry_count; + while (count > 0) { + int32_t step = count / 2; + mrb_irep_debug_info_line *it = ret + step; + if (!(pc < it->start_pos)) { + ret = it + 1; + count -= step + 1; + } + else { count = step; } + } + + --ret; + + /* check line entry pointer range */ + mrb_assert(f->lines.flat_map <= ret && ret < (f->lines.flat_map + f->line_entry_count)); + /* check pc range */ + mrb_assert(ret->start_pos <= pc && + pc < (((uint32_t)(ret + 1 - f->lines.flat_map) < f->line_entry_count) + ? (ret+1)->start_pos : irep->debug_info->pc_count)); + + return ret->line; + } + } + } + } + return -1; +} + +MRB_API mrb_irep_debug_info* +mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep) +{ + static const mrb_irep_debug_info initial = { 0, 0, NULL }; + mrb_irep_debug_info *ret; + + mrb_assert(!irep->debug_info); + ret = (mrb_irep_debug_info *)mrb_malloc(mrb, sizeof(*ret)); + *ret = initial; + irep->debug_info = ret; + return ret; +} + +MRB_API mrb_irep_debug_info_file* +mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, + uint32_t start_pos, uint32_t end_pos) +{ + mrb_irep_debug_info *info; + mrb_irep_debug_info_file *ret; + uint32_t file_pc_count; + size_t fn_len; + mrb_int len; + uint32_t i; + + if (!irep->debug_info) { return NULL; } + + mrb_assert(irep->filename); + mrb_assert(irep->lines); + + info = irep->debug_info; + + if (info->flen > 0 && strcmp(irep->filename, info->files[info->flen - 1]->filename) == 0) { + return NULL; + } + + ret = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*ret)); + info->files = + (mrb_irep_debug_info_file**)( + info->files + ? mrb_realloc(mrb, info->files, sizeof(mrb_irep_debug_info_file*) * (info->flen + 1)) + : mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file*))); + info->files[info->flen++] = ret; + + file_pc_count = end_pos - start_pos; + + ret->start_pos = start_pos; + info->pc_count = end_pos; + + fn_len = strlen(irep->filename); + ret->filename_sym = mrb_intern(mrb, irep->filename, fn_len); + len = 0; + ret->filename = mrb_sym2name_len(mrb, ret->filename_sym, &len); + + ret->line_type = select_line_type(irep->lines + start_pos, end_pos - start_pos); + ret->lines.ptr = NULL; + + switch (ret->line_type) { + case mrb_debug_line_ary: + ret->line_entry_count = file_pc_count; + ret->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count); + for (i = 0; i < file_pc_count; ++i) { + ret->lines.ary[i] = irep->lines[start_pos + i]; + } + break; + + case mrb_debug_line_flat_map: { + uint16_t prev_line = 0; + mrb_irep_debug_info_line m; + ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1); + ret->line_entry_count = 0; + for (i = 0; i < file_pc_count; ++i) { + if (irep->lines[start_pos + i] == prev_line) { continue; } + + ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc( + mrb, ret->lines.flat_map, + sizeof(mrb_irep_debug_info_line) * (ret->line_entry_count + 1)); + m.start_pos = start_pos + i; + m.line = irep->lines[start_pos + i]; + ret->lines.flat_map[ret->line_entry_count] = m; + + /* update */ + ++ret->line_entry_count; + prev_line = irep->lines[start_pos + i]; + } + } break; + + default: mrb_assert(0); break; + } + + return ret; +} + +MRB_API void +mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d) +{ + uint32_t i; + + if (!d) { return; } + + for (i = 0; i < d->flen; ++i) { + mrb_assert(d->files[i]); + mrb_free(mrb, d->files[i]->lines.ptr); + mrb_free(mrb, d->files[i]); + } + mrb_free(mrb, d->files); + mrb_free(mrb, d); +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/dump.c b/web/server/h2o/libh2o/deps/mruby/src/dump.c new file mode 100644 index 000000000..d479a1a4f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/dump.c @@ -0,0 +1,1100 @@ +/* +** dump.c - mruby binary dumper (mrbc binary format) +** +** See Copyright Notice in mruby.h +*/ + +#include <string.h> +#include <limits.h> +#include <mruby/dump.h> +#include <mruby/string.h> +#include <mruby/irep.h> +#include <mruby/numeric.h> +#include <mruby/debug.h> + +#define FLAG_BYTEORDER_NATIVE 2 +#define FLAG_BYTEORDER_NONATIVE 0 + +#ifdef MRB_USE_FLOAT +#define MRB_FLOAT_FMT "%.8e" +#else +#define MRB_FLOAT_FMT "%.16e" +#endif + +static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep); + +#if UINT32_MAX > SIZE_MAX +# error This code cannot be built on your environment. +#endif + +static size_t +write_padding(uint8_t *buf) +{ + const size_t align = MRB_DUMP_ALIGNMENT; + size_t pad_len = -(intptr_t)buf & (align-1); + if (pad_len > 0) { + memset(buf, 0, pad_len); + } + return pad_len; +} + +static size_t +get_irep_header_size(mrb_state *mrb) +{ + size_t size = 0; + + size += sizeof(uint32_t) * 1; + size += sizeof(uint16_t) * 3; + + return size; +} + +static ptrdiff_t +write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) +{ + uint8_t *cur = buf; + + cur += uint32_to_bin((uint32_t)get_irep_record_size_1(mrb, irep), cur); /* record size */ + cur += uint16_to_bin((uint16_t)irep->nlocals, cur); /* number of local variable */ + cur += uint16_to_bin((uint16_t)irep->nregs, cur); /* number of register variable */ + cur += uint16_to_bin((uint16_t)irep->rlen, cur); /* number of child irep */ + + return cur - buf; +} + + +static size_t +get_iseq_block_size(mrb_state *mrb, mrb_irep *irep) +{ + size_t size = 0; + + size += sizeof(uint32_t); /* ilen */ + size += sizeof(uint32_t); /* max padding */ + size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */ + + return size; +} + +static ptrdiff_t +write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) +{ + uint8_t *cur = buf; + int iseq_no; + + cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */ + cur += write_padding(cur); + switch (flags & DUMP_ENDIAN_NAT) { + case DUMP_ENDIAN_BIG: + if (bigendian_p()) goto native; + for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { + cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */ + } + break; + case DUMP_ENDIAN_LIL: + if (!bigendian_p()) goto native; + for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { + cur += uint32l_to_bin(irep->iseq[iseq_no], cur); /* opcode */ + } + break; + + native: + case DUMP_ENDIAN_NAT: + memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); + cur += irep->ilen * sizeof(mrb_code); + break; + } + + return cur - buf; +} + + +static size_t +get_pool_block_size(mrb_state *mrb, mrb_irep *irep) +{ + int pool_no; + size_t size = 0; + mrb_value str; + + size += sizeof(uint32_t); /* plen */ + size += irep->plen * (sizeof(uint8_t) + sizeof(uint16_t)); /* len(n) */ + + for (pool_no = 0; pool_no < irep->plen; pool_no++) { + int ai = mrb_gc_arena_save(mrb); + + switch (mrb_type(irep->pool[pool_no])) { + case MRB_TT_FIXNUM: + str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10); + { + mrb_int len = RSTRING_LEN(str); + mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); + size += (size_t)len; + } + break; + + case MRB_TT_FLOAT: + str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); + { + mrb_int len = RSTRING_LEN(str); + mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); + size += (size_t)len; + } + break; + + case MRB_TT_STRING: + { + mrb_int len = RSTRING_LEN(irep->pool[pool_no]); + mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); + size += (size_t)len; + } + break; + + default: + break; + } + mrb_gc_arena_restore(mrb, ai); + } + + return size; +} + +static ptrdiff_t +write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) +{ + int pool_no; + uint8_t *cur = buf; + uint16_t len; + mrb_value str; + const char *char_ptr; + + cur += uint32_to_bin(irep->plen, cur); /* number of pool */ + + for (pool_no = 0; pool_no < irep->plen; pool_no++) { + int ai = mrb_gc_arena_save(mrb); + + switch (mrb_type(irep->pool[pool_no])) { + case MRB_TT_FIXNUM: + cur += uint8_to_bin(IREP_TT_FIXNUM, cur); /* data type */ + str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10); + break; + + case MRB_TT_FLOAT: + cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */ + str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); + break; + + case MRB_TT_STRING: + cur += uint8_to_bin(IREP_TT_STRING, cur); /* data type */ + str = irep->pool[pool_no]; + break; + + default: + continue; + } + + char_ptr = RSTRING_PTR(str); + { + mrb_int tlen = RSTRING_LEN(str); + mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX); + len = (uint16_t)tlen; + } + + cur += uint16_to_bin(len, cur); /* data length */ + memcpy(cur, char_ptr, (size_t)len); + cur += len; + + mrb_gc_arena_restore(mrb, ai); + } + + return cur - buf; +} + + +static size_t +get_syms_block_size(mrb_state *mrb, mrb_irep *irep) +{ + size_t size = 0; + int sym_no; + mrb_int len; + + size += sizeof(uint32_t); /* slen */ + for (sym_no = 0; sym_no < irep->slen; sym_no++) { + size += sizeof(uint16_t); /* snl(n) */ + if (irep->syms[sym_no] != 0) { + mrb_sym2name_len(mrb, irep->syms[sym_no], &len); + size += len + 1; /* sn(n) + null char */ + } + } + + return size; +} + +static ptrdiff_t +write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) +{ + int sym_no; + uint8_t *cur = buf; + const char *name; + + cur += uint32_to_bin(irep->slen, cur); /* number of symbol */ + + for (sym_no = 0; sym_no < irep->slen; sym_no++) { + if (irep->syms[sym_no] != 0) { + mrb_int len; + + name = mrb_sym2name_len(mrb, irep->syms[sym_no], &len); + + mrb_assert_int_fit(mrb_int, len, uint16_t, UINT16_MAX); + cur += uint16_to_bin((uint16_t)len, cur); /* length of symbol name */ + memcpy(cur, name, len); /* symbol name */ + cur += (uint16_t)len; + *cur++ = '\0'; + } + else { + cur += uint16_to_bin(MRB_DUMP_NULL_SYM_LEN, cur); /* length of symbol name */ + } + } + + return cur - buf; +} + +static size_t +get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep) +{ + size_t size = 0; + + size += get_irep_header_size(mrb); + size += get_iseq_block_size(mrb, irep); + size += get_pool_block_size(mrb, irep); + size += get_syms_block_size(mrb, irep); + return size; +} + +static size_t +get_irep_record_size(mrb_state *mrb, mrb_irep *irep) +{ + size_t size = 0; + int irep_no; + + size = get_irep_record_size_1(mrb, irep); + for (irep_no = 0; irep_no < irep->rlen; irep_no++) { + size += get_irep_record_size(mrb, irep->reps[irep_no]); + } + return size; +} + +static int +write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *irep_record_size, uint8_t flags) +{ + int i; + uint8_t *src = bin; + + if (irep == NULL) { + return MRB_DUMP_INVALID_IREP; + } + + *irep_record_size = get_irep_record_size_1(mrb, irep); + if (*irep_record_size == 0) { + return MRB_DUMP_GENERAL_FAILURE; + } + + bin += write_irep_header(mrb, irep, bin); + bin += write_iseq_block(mrb, irep, bin, flags); + bin += write_pool_block(mrb, irep, bin); + bin += write_syms_block(mrb, irep, bin); + + for (i = 0; i < irep->rlen; i++) { + int result; + size_t rsize; + + result = write_irep_record(mrb, irep->reps[i], bin, &rsize, flags); + if (result != MRB_DUMP_OK) { + return result; + } + bin += rsize; + } + *irep_record_size = bin - src; + return MRB_DUMP_OK; +} + +static uint32_t +write_footer(mrb_state *mrb, uint8_t *bin) +{ + struct rite_binary_footer footer; + + memcpy(footer.section_ident, RITE_BINARY_EOF, sizeof(footer.section_ident)); + uint32_to_bin(sizeof(struct rite_binary_footer), footer.section_size); + memcpy(bin, &footer, sizeof(struct rite_binary_footer)); + + return sizeof(struct rite_binary_footer); +} + + +static int +write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin) +{ + struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin; + + memcpy(header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(header->section_ident)); + + mrb_assert_int_fit(size_t, section_size, uint32_t, UINT32_MAX); + uint32_to_bin((uint32_t)section_size, header->section_size); + memcpy(header->rite_version, RITE_VM_VER, sizeof(header->rite_version)); + + return MRB_DUMP_OK; +} + +static int +write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, uint8_t flags) +{ + int result; + size_t rsize = 0; + uint8_t *cur = bin; + + if (mrb == NULL || bin == NULL) { + return MRB_DUMP_INVALID_ARGUMENT; + } + + cur += sizeof(struct rite_section_irep_header); + + result = write_irep_record(mrb, irep, cur, &rsize, flags); + if (result != MRB_DUMP_OK) { + return result; + } + *len_p = cur - bin + rsize; + write_section_irep_header(mrb, *len_p, bin); + + return MRB_DUMP_OK; +} + +static int +write_section_lineno_header(mrb_state *mrb, size_t section_size, uint8_t *bin) +{ + struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin; + + memcpy(header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(header->section_ident)); + uint32_to_bin((uint32_t)section_size, header->section_size); + + return MRB_DUMP_OK; +} + +static size_t +get_lineno_record_size(mrb_state *mrb, mrb_irep *irep) +{ + size_t size = 0; + + size += sizeof(uint32_t); /* record size */ + size += sizeof(uint16_t); /* filename size */ + if (irep->filename) { + size += strlen(irep->filename); /* filename */ + } + size += sizeof(uint32_t); /* niseq */ + if (irep->lines) { + size += sizeof(uint16_t) * irep->ilen; /* lineno */ + } + + return size; +} + +static size_t +write_lineno_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t* bin) +{ + uint8_t *cur = bin; + int iseq_no; + size_t filename_len; + ptrdiff_t diff; + + cur += sizeof(uint32_t); /* record size */ + + if (irep->filename) { + filename_len = strlen(irep->filename); + } + else { + filename_len = 0; + } + mrb_assert_int_fit(size_t, filename_len, uint16_t, UINT16_MAX); + cur += uint16_to_bin((uint16_t)filename_len, cur); /* filename size */ + + if (filename_len) { + memcpy(cur, irep->filename, filename_len); + cur += filename_len; /* filename */ + } + + if (irep->lines) { + mrb_assert_int_fit(size_t, irep->ilen, uint32_t, UINT32_MAX); + cur += uint32_to_bin((uint32_t)(irep->ilen), cur); /* niseq */ + for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { + cur += uint16_to_bin(irep->lines[iseq_no], cur); /* opcode */ + } + } + else { + cur += uint32_to_bin(0, cur); /* niseq */ + } + + diff = cur - bin; + mrb_assert_int_fit(ptrdiff_t, diff, uint32_t, UINT32_MAX); + + uint32_to_bin((uint32_t)diff, bin); /* record size */ + + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + return (size_t)diff; +} + +static size_t +write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin) +{ + size_t rlen, size = 0; + int i; + + rlen = write_lineno_record_1(mrb, irep, bin); + bin += rlen; + size += rlen; + for (i=0; i<irep->rlen; i++) { + rlen = write_lineno_record(mrb, irep, bin); + bin += rlen; + size += rlen; + } + return size; +} + +static int +write_section_lineno(mrb_state *mrb, mrb_irep *irep, uint8_t *bin) +{ + size_t section_size = 0; + size_t rlen = 0; /* size of irep record */ + uint8_t *cur = bin; + + if (mrb == NULL || bin == NULL) { + return MRB_DUMP_INVALID_ARGUMENT; + } + + cur += sizeof(struct rite_section_lineno_header); + section_size += sizeof(struct rite_section_lineno_header); + + rlen = write_lineno_record(mrb, irep, cur); + section_size += rlen; + + write_section_lineno_header(mrb, section_size, bin); + + return MRB_DUMP_OK; +} + +static size_t +get_debug_record_size(mrb_state *mrb, mrb_irep *irep) +{ + size_t ret = 0; + uint16_t f_idx; + int i; + + ret += sizeof(uint32_t); /* record size */ + ret += sizeof(uint16_t); /* file count */ + + for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { + mrb_irep_debug_info_file const* file = irep->debug_info->files[f_idx]; + + ret += sizeof(uint32_t); /* position */ + ret += sizeof(uint16_t); /* filename index */ + + /* lines */ + ret += sizeof(uint32_t); /* entry count */ + ret += sizeof(uint8_t); /* line type */ + switch (file->line_type) { + case mrb_debug_line_ary: + ret += sizeof(uint16_t) * (size_t)(file->line_entry_count); + break; + + case mrb_debug_line_flat_map: + ret += (sizeof(uint32_t) + sizeof(uint16_t)) * (size_t)(file->line_entry_count); + break; + + default: mrb_assert(0); break; + } + } + for (i=0; i<irep->rlen; i++) { + ret += get_debug_record_size(mrb, irep->reps[i]); + } + + return ret; +} + +static int +find_filename_index(const mrb_sym *ary, int ary_len, mrb_sym s) +{ + int i; + + for (i = 0; i < ary_len; ++i) { + if (ary[i] == s) { return i; } + } + return -1; +} + +static size_t +get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t *lp) +{ + mrb_sym *filenames = *fp; + size_t size = 0; + mrb_irep_debug_info *di = irep->debug_info; + int i; + + mrb_assert(lp); + for (i = 0; i < di->flen; ++i) { + mrb_irep_debug_info_file *file; + mrb_int filename_len; + + file = di->files[i]; + if (find_filename_index(filenames, *lp, file->filename_sym) == -1) { + /* register filename */ + *lp += 1; + *fp = filenames = (mrb_sym *)mrb_realloc(mrb, filenames, sizeof(mrb_sym) * (*lp)); + filenames[*lp - 1] = file->filename_sym; + + /* filename */ + mrb_sym2name_len(mrb, file->filename_sym, &filename_len); + size += sizeof(uint16_t) + (size_t)filename_len; + } + } + for (i=0; i<irep->rlen; i++) { + size += get_filename_table_size(mrb, irep->reps[i], fp, lp); + } + return size; +} + +static size_t +write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len) +{ + uint8_t *cur; + uint16_t f_idx; + ptrdiff_t ret; + + cur = bin + sizeof(uint32_t); /* skip record size */ + cur += uint16_to_bin(irep->debug_info->flen, cur); /* file count */ + + for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { + int filename_idx; + const mrb_irep_debug_info_file *file = irep->debug_info->files[f_idx]; + + /* position */ + cur += uint32_to_bin(file->start_pos, cur); + + /* filename index */ + filename_idx = find_filename_index(filenames, filenames_len, + file->filename_sym); + mrb_assert_int_fit(int, filename_idx, uint16_t, UINT16_MAX); + cur += uint16_to_bin((uint16_t)filename_idx, cur); + + /* lines */ + cur += uint32_to_bin(file->line_entry_count, cur); + cur += uint8_to_bin(file->line_type, cur); + switch (file->line_type) { + case mrb_debug_line_ary: { + uint32_t l; + for (l = 0; l < file->line_entry_count; ++l) { + cur += uint16_to_bin(file->lines.ary[l], cur); + } + } break; + + case mrb_debug_line_flat_map: { + uint32_t line; + for (line = 0; line < file->line_entry_count; ++line) { + cur += uint32_to_bin(file->lines.flat_map[line].start_pos, cur); + cur += uint16_to_bin(file->lines.flat_map[line].line, cur); + } + } break; + + default: mrb_assert(0); break; + } + } + + ret = cur - bin; + mrb_assert_int_fit(ptrdiff_t, ret, uint32_t, UINT32_MAX); + uint32_to_bin((uint32_t)ret, bin); + + mrb_assert_int_fit(ptrdiff_t, ret, size_t, SIZE_MAX); + return (size_t)ret; +} + +static size_t +write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len) +{ + size_t size, len; + int irep_no; + + size = len = write_debug_record_1(mrb, irep, bin, filenames, filenames_len); + bin += len; + for (irep_no = 0; irep_no < irep->rlen; irep_no++) { + len = write_debug_record(mrb, irep->reps[irep_no], bin, filenames, filenames_len); + bin += len; + size += len; + } + + mrb_assert(size == get_debug_record_size(mrb, irep)); + return size; +} + +static int +write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const *filenames, uint16_t filenames_len) +{ + size_t section_size = 0; + const uint8_t *bin = cur; + struct rite_section_debug_header *header; + size_t dlen; + uint16_t i; + char const *sym; mrb_int sym_len; + + if (mrb == NULL || cur == NULL) { + return MRB_DUMP_INVALID_ARGUMENT; + } + + header = (struct rite_section_debug_header *)bin; + cur += sizeof(struct rite_section_debug_header); + section_size += sizeof(struct rite_section_debug_header); + + /* filename table */ + cur += uint16_to_bin(filenames_len, cur); + section_size += sizeof(uint16_t); + for (i = 0; i < filenames_len; ++i) { + sym = mrb_sym2name_len(mrb, filenames[i], &sym_len); + mrb_assert(sym); + cur += uint16_to_bin(sym_len, cur); + memcpy(cur, sym, sym_len); + cur += sym_len; + section_size += sizeof(uint16_t) + sym_len; + } + + /* debug records */ + dlen = write_debug_record(mrb, irep, cur, filenames, filenames_len); + section_size += dlen; + + memcpy(header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(header->section_ident)); + mrb_assert(section_size <= INT32_MAX); + uint32_to_bin((uint32_t)section_size, header->section_size); + + return MRB_DUMP_OK; +} + +static void +create_lv_sym_table(mrb_state *mrb, const mrb_irep *irep, mrb_sym **syms, uint32_t *syms_len) +{ + int i; + + if (*syms == NULL) { + *syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * 1); + } + + for (i = 0; i + 1 < irep->nlocals; ++i) { + mrb_sym const name = irep->lv[i].name; + if (name == 0) continue; + if (find_filename_index(*syms, *syms_len, name) != -1) continue; + + ++(*syms_len); + *syms = (mrb_sym*)mrb_realloc(mrb, *syms, sizeof(mrb_sym) * (*syms_len)); + (*syms)[*syms_len - 1] = name; + } + + for (i = 0; i < irep->rlen; ++i) { + create_lv_sym_table(mrb, irep->reps[i], syms, syms_len); + } +} + +static int +write_lv_sym_table(mrb_state *mrb, uint8_t **start, mrb_sym const *syms, uint32_t syms_len) +{ + uint8_t *cur = *start; + uint32_t i; + const char *str; + mrb_int str_len; + + cur += uint32_to_bin(syms_len, cur); + + for (i = 0; i < syms_len; ++i) { + str = mrb_sym2name_len(mrb, syms[i], &str_len); + cur += uint16_to_bin(str_len, cur); + memcpy(cur, str, str_len); + cur += str_len; + } + + *start = cur; + + return MRB_DUMP_OK; +} + +static int +write_lv_record(mrb_state *mrb, const mrb_irep *irep, uint8_t **start, mrb_sym const *syms, uint32_t syms_len) +{ + uint8_t *cur = *start; + int i; + + for (i = 0; i + 1 < irep->nlocals; ++i) { + if (irep->lv[i].name == 0) { + cur += uint16_to_bin(RITE_LV_NULL_MARK, cur); + cur += uint16_to_bin(0, cur); + } + else { + int const sym_idx = find_filename_index(syms, syms_len, irep->lv[i].name); + mrb_assert(sym_idx != -1); /* local variable name must be in syms */ + + cur += uint16_to_bin(sym_idx, cur); + cur += uint16_to_bin(irep->lv[i].r, cur); + } + } + + for (i = 0; i < irep->rlen; ++i) { + write_lv_record(mrb, irep->reps[i], &cur, syms, syms_len); + } + + *start = cur; + + return MRB_DUMP_OK; +} + +static size_t +get_lv_record_size(mrb_state *mrb, mrb_irep *irep) +{ + size_t ret = 0; + int i; + + ret += (sizeof(uint16_t) + sizeof(uint16_t)) * (irep->nlocals - 1); + + for (i = 0; i < irep->rlen; ++i) { + ret += get_lv_record_size(mrb, irep->reps[i]); + } + + return ret; +} + +static size_t +get_lv_section_size(mrb_state *mrb, mrb_irep *irep, mrb_sym const *syms, uint32_t syms_len) +{ + size_t ret = 0, i; + + ret += sizeof(uint32_t); /* syms_len */ + ret += sizeof(uint16_t) * syms_len; /* symbol name lengths */ + for (i = 0; i < syms_len; ++i) { + mrb_int str_len; + mrb_sym2name_len(mrb, syms[i], &str_len); + ret += str_len; + } + + ret += get_lv_record_size(mrb, irep); + + return ret; +} + +static int +write_section_lv(mrb_state *mrb, mrb_irep *irep, uint8_t *start, mrb_sym const *syms, uint32_t const syms_len) +{ + uint8_t *cur = start; + struct rite_section_lv_header *header; + ptrdiff_t diff; + int result = MRB_DUMP_OK; + + if (mrb == NULL || cur == NULL) { + return MRB_DUMP_INVALID_ARGUMENT; + } + + header = (struct rite_section_lv_header*)cur; + cur += sizeof(struct rite_section_lv_header); + + result = write_lv_sym_table(mrb, &cur, syms, syms_len); + if (result != MRB_DUMP_OK) { + goto lv_section_exit; + } + + result = write_lv_record(mrb, irep, &cur, syms, syms_len); + if (result != MRB_DUMP_OK) { + goto lv_section_exit; + } + + memcpy(header->section_ident, RITE_SECTION_LV_IDENT, sizeof(header->section_ident)); + + diff = cur - start; + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + uint32_to_bin((uint32_t)diff, header->section_size); + +lv_section_exit: + return result; +} + +static int +write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8_t flags) +{ + struct rite_binary_header *header = (struct rite_binary_header *)bin; + uint16_t crc; + uint32_t offset; + + switch (flags & DUMP_ENDIAN_NAT) { + endian_big: + case DUMP_ENDIAN_BIG: + memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)); + break; + endian_little: + case DUMP_ENDIAN_LIL: + memcpy(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)); + break; + + case DUMP_ENDIAN_NAT: + if (bigendian_p()) goto endian_big; + goto endian_little; + break; + } + + memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)); + memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name)); + memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version)); + mrb_assert(binary_size <= UINT32_MAX); + uint32_to_bin((uint32_t)binary_size, header->binary_size); + + offset = (uint32_t)((&(header->binary_crc[0]) - bin) + sizeof(uint16_t)); + crc = calc_crc_16_ccitt(bin + offset, binary_size - offset, 0); + uint16_to_bin(crc, header->binary_crc); + + return MRB_DUMP_OK; +} + +static mrb_bool +is_debug_info_defined(mrb_irep *irep) +{ + int i; + + if (!irep->debug_info) return FALSE; + for (i=0; i<irep->rlen; i++) { + if (!is_debug_info_defined(irep->reps[i])) return FALSE; + } + return TRUE; +} + +static mrb_bool +is_lv_defined(mrb_irep *irep) +{ + int i; + + if (irep->lv) { return TRUE; } + + for (i = 0; i < irep->rlen; ++i) { + if (is_lv_defined(irep->reps[i])) { return TRUE; } + } + + return FALSE; +} + +static uint8_t +dump_flags(uint8_t flags, uint8_t native) +{ + if (native == FLAG_BYTEORDER_NATIVE) { + if ((flags & DUMP_ENDIAN_NAT) == 0) { + return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_NAT; + } + return flags; + } + if ((flags & DUMP_ENDIAN_NAT) == 0) { + return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_BIG; + } + return flags; +} + +static int +dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size) +{ + int result = MRB_DUMP_GENERAL_FAILURE; + size_t malloc_size; + size_t section_irep_size; + size_t section_lineno_size = 0, section_lv_size = 0; + uint8_t *cur = NULL; + mrb_bool const debug_info_defined = is_debug_info_defined(irep), lv_defined = is_lv_defined(irep); + mrb_sym *lv_syms = NULL; uint32_t lv_syms_len = 0; + mrb_sym *filenames = NULL; uint16_t filenames_len = 0; + + if (mrb == NULL) { + *bin = NULL; + return MRB_DUMP_GENERAL_FAILURE; + } + + section_irep_size = sizeof(struct rite_section_irep_header); + section_irep_size += get_irep_record_size(mrb, irep); + + /* DEBUG section size */ + if (flags & DUMP_DEBUG_INFO) { + if (debug_info_defined) { + section_lineno_size += sizeof(struct rite_section_debug_header); + /* filename table */ + filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) + 1); + + /* filename table size */ + section_lineno_size += sizeof(uint16_t); + section_lineno_size += get_filename_table_size(mrb, irep, &filenames, &filenames_len); + + section_lineno_size += get_debug_record_size(mrb, irep); + } + else { + section_lineno_size += sizeof(struct rite_section_lineno_header); + section_lineno_size += get_lineno_record_size(mrb, irep); + } + } + + if (lv_defined) { + section_lv_size += sizeof(struct rite_section_lv_header); + create_lv_sym_table(mrb, irep, &lv_syms, &lv_syms_len); + section_lv_size += get_lv_section_size(mrb, irep, lv_syms, lv_syms_len); + } + + malloc_size = sizeof(struct rite_binary_header) + + section_irep_size + section_lineno_size + section_lv_size + + sizeof(struct rite_binary_footer); + cur = *bin = (uint8_t*)mrb_malloc(mrb, malloc_size); + cur += sizeof(struct rite_binary_header); + + result = write_section_irep(mrb, irep, cur, §ion_irep_size, flags); + if (result != MRB_DUMP_OK) { + goto error_exit; + } + cur += section_irep_size; + *bin_size = sizeof(struct rite_binary_header) + + section_irep_size + section_lineno_size + section_lv_size + + sizeof(struct rite_binary_footer); + + /* write DEBUG section */ + if (flags & DUMP_DEBUG_INFO) { + if (debug_info_defined) { + result = write_section_debug(mrb, irep, cur, filenames, filenames_len); + } + else { + result = write_section_lineno(mrb, irep, cur); + } + if (result != MRB_DUMP_OK) { + goto error_exit; + } + cur += section_lineno_size; + } + + if (lv_defined) { + result = write_section_lv(mrb, irep, cur, lv_syms, lv_syms_len); + if (result != MRB_DUMP_OK) { + goto error_exit; + } + cur += section_lv_size; + } + + write_footer(mrb, cur); + write_rite_binary_header(mrb, *bin_size, *bin, flags); + +error_exit: + if (result != MRB_DUMP_OK) { + mrb_free(mrb, *bin); + *bin = NULL; + } + mrb_free(mrb, lv_syms); + mrb_free(mrb, filenames); + return result; +} + +int +mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size) +{ + return dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), bin, bin_size); +} + +#ifndef MRB_DISABLE_STDIO + +int +mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp) +{ + uint8_t *bin = NULL; + size_t bin_size = 0; + int result; + + if (fp == NULL) { + return MRB_DUMP_INVALID_ARGUMENT; + } + + result = dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), &bin, &bin_size); + if (result == MRB_DUMP_OK) { + if (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) { + result = MRB_DUMP_WRITE_FAULT; + } + } + + mrb_free(mrb, bin); + return result; +} + +static mrb_bool +dump_bigendian_p(uint8_t flags) +{ + switch (flags & DUMP_ENDIAN_NAT) { + case DUMP_ENDIAN_BIG: + return TRUE; + case DUMP_ENDIAN_LIL: + return FALSE; + default: + case DUMP_ENDIAN_NAT: + return bigendian_p(); + } +} + +int +mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname) +{ + uint8_t *bin = NULL; + size_t bin_size = 0, bin_idx = 0; + int result; + + if (fp == NULL || initname == NULL || initname[0] == '\0') { + return MRB_DUMP_INVALID_ARGUMENT; + } + flags = dump_flags(flags, FLAG_BYTEORDER_NATIVE); + result = dump_irep(mrb, irep, flags, &bin, &bin_size); + if (result == MRB_DUMP_OK) { + if (!dump_bigendian_p(flags)) { + if (fprintf(fp, "/* dumped in little endian order.\n" + " use `mrbc -E` option for big endian CPU. */\n") < 0) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + } + else { + if (fprintf(fp, "/* dumped in big endian order.\n" + " use `mrbc -e` option for better performance on little endian CPU. */\n") < 0) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + } + if (fprintf(fp, "#include <stdint.h>\n") < 0) { /* for uint8_t under at least Darwin */ + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + if (fprintf(fp, + "extern const uint8_t %s[];\n" + "const uint8_t\n" + "#if defined __GNUC__\n" + "__attribute__((aligned(%u)))\n" + "#elif defined _MSC_VER\n" + "__declspec(align(%u))\n" + "#endif\n" + "%s[] = {", + initname, + (uint16_t)MRB_DUMP_ALIGNMENT, (uint16_t)MRB_DUMP_ALIGNMENT, initname) < 0) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + while (bin_idx < bin_size) { + if (bin_idx % 16 == 0) { + if (fputs("\n", fp) == EOF) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + } + if (fprintf(fp, "0x%02x,", bin[bin_idx++]) < 0) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + } + if (fputs("\n};\n", fp) == EOF) { + mrb_free(mrb, bin); + return MRB_DUMP_WRITE_FAULT; + } + } + + mrb_free(mrb, bin); + return result; +} + +#endif /* MRB_DISABLE_STDIO */ diff --git a/web/server/h2o/libh2o/deps/mruby/src/enum.c b/web/server/h2o/libh2o/deps/mruby/src/enum.c new file mode 100644 index 000000000..adb815bf1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/enum.c @@ -0,0 +1,14 @@ +/* +** enum.c - Enumerable module +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> + +void +mrb_init_enumerable(mrb_state *mrb) +{ + mrb_define_module(mrb, "Enumerable"); /* 15.3.2 */ +} + diff --git a/web/server/h2o/libh2o/deps/mruby/src/error.c b/web/server/h2o/libh2o/deps/mruby/src/error.c new file mode 100644 index 000000000..2c4fd1a40 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/error.c @@ -0,0 +1,503 @@ +/* +** error.c - Exception class +** +** See Copyright Notice in mruby.h +*/ + +#include <errno.h> +#include <stdarg.h> +#include <stdlib.h> +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/irep.h> +#include <mruby/proc.h> +#include <mruby/string.h> +#include <mruby/variable.h> +#include <mruby/debug.h> +#include <mruby/error.h> +#include <mruby/class.h> +#include <mruby/throw.h> + +MRB_API mrb_value +mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len) +{ + mrb_value arg = mrb_str_new(mrb, ptr, len); + return mrb_obj_new(mrb, c, 1, &arg); +} + +MRB_API mrb_value +mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str) +{ + str = mrb_str_to_str(mrb, str); + return mrb_obj_new(mrb, c, 1, &str); +} + +/* + * call-seq: + * Exception.new(msg = nil) -> exception + * + * Construct a new Exception object, optionally passing in + * a message. + */ + +static mrb_value +exc_initialize(mrb_state *mrb, mrb_value exc) +{ + mrb_value mesg; + mrb_int argc; + mrb_value *argv; + + if (mrb_get_args(mrb, "|o*!", &mesg, &argv, &argc) >= 1) { + mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg); + } + return exc; +} + +/* + * Document-method: exception + * + * call-seq: + * exc.exception(string) -> an_exception or exc + * + * With no argument, or if the argument is the same as the receiver, + * return the receiver. Otherwise, create a new + * exception object of the same class as the receiver, but with a + * message equal to <code>string</code>. + * + */ + +static mrb_value +exc_exception(mrb_state *mrb, mrb_value self) +{ + mrb_value exc; + mrb_value a; + int argc; + + argc = mrb_get_args(mrb, "|o", &a); + if (argc == 0) return self; + if (mrb_obj_equal(mrb, self, a)) return self; + exc = mrb_obj_clone(mrb, self); + mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), a); + + return exc; +} + +/* + * call-seq: + * exception.to_s -> string + * + * Returns exception's message (or the name of the exception if + * no message is set). + */ + +static mrb_value +exc_to_s(mrb_state *mrb, mrb_value exc) +{ + mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg")); + struct RObject *p; + + if (!mrb_string_p(mesg)) { + return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc)); + } + p = mrb_obj_ptr(mesg); + if (!p->c) { + p->c = mrb->string_class; + } + return mesg; +} + +/* + * call-seq: + * exception.message -> string + * + * Returns the result of invoking <code>exception.to_s</code>. + * Normally this returns the exception's message or name. + */ + +static mrb_value +exc_message(mrb_state *mrb, mrb_value exc) +{ + return mrb_funcall(mrb, exc, "to_s", 0); +} + +/* + * call-seq: + * exception.inspect -> string + * + * Returns this exception's file name, line number, + * message and class name. + * If file name or line number is not set, + * returns message and class name. + */ + +static mrb_value +exc_inspect(mrb_state *mrb, mrb_value exc) +{ + mrb_value str, mesg, file, line; + mrb_bool append_mesg; + const char *cname; + + mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg")); + file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file")); + line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line")); + + append_mesg = !mrb_nil_p(mesg); + if (append_mesg) { + mesg = mrb_obj_as_string(mrb, mesg); + append_mesg = RSTRING_LEN(mesg) > 0; + } + + cname = mrb_obj_classname(mrb, exc); + str = mrb_str_new_cstr(mrb, cname); + if (mrb_string_p(file) && mrb_fixnum_p(line)) { + if (append_mesg) { + str = mrb_format(mrb, "%S:%S: %S (%S)", file, line, mesg, str); + } + else { + str = mrb_format(mrb, "%S:%S: %S", file, line, str); + } + } + else if (append_mesg) { + str = mrb_format(mrb, "%S: %S", str, mesg); + } + return str; +} + +void mrb_keep_backtrace(mrb_state *mrb, mrb_value exc); + +static void +set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace) +{ + if (!mrb_array_p(backtrace)) { + type_err: + mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String"); + } + else { + const mrb_value *p = RARRAY_PTR(backtrace); + const mrb_value *pend = p + RARRAY_LEN(backtrace); + + while (p < pend) { + if (!mrb_string_p(*p)) goto type_err; + p++; + } + } + mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace); +} + +static mrb_value +exc_set_backtrace(mrb_state *mrb, mrb_value exc) +{ + mrb_value backtrace; + + mrb_get_args(mrb, "o", &backtrace); + set_backtrace(mrb, exc, backtrace); + return backtrace; +} + +static void +exc_debug_info(mrb_state *mrb, struct RObject *exc) +{ + mrb_callinfo *ci = mrb->c->ci; + mrb_code *pc = ci->pc; + + while (ci >= mrb->c->cibase) { + mrb_code *err = ci->err; + + if (!err && pc) err = pc - 1; + if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) { + mrb_irep *irep = ci->proc->body.irep; + + int32_t const line = mrb_debug_get_line(irep, err - irep->iseq); + char const* file = mrb_debug_get_filename(irep, err - irep->iseq); + if (line != -1 && file) { + mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file)); + mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line)); + return; + } + } + pc = ci->pc; + ci--; + } +} + +void +mrb_exc_set(mrb_state *mrb, mrb_value exc) +{ + if (mrb_nil_p(exc)) { + mrb->exc = 0; + } + else { + mrb->exc = mrb_obj_ptr(exc); + if (!mrb->gc.out_of_memory) { + exc_debug_info(mrb, mrb->exc); + mrb_keep_backtrace(mrb, exc); + } + } +} + +MRB_API mrb_noreturn void +mrb_exc_raise(mrb_state *mrb, mrb_value exc) +{ + if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) { + mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); + } + mrb_exc_set(mrb, exc); + if (!mrb->jmp) { + mrb_p(mrb, exc); + abort(); + } + MRB_THROW(mrb->jmp); +} + +MRB_API mrb_noreturn void +mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) +{ + mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mrb_str_new_cstr(mrb, msg))); +} + +MRB_API mrb_value +mrb_vformat(mrb_state *mrb, const char *format, va_list ap) +{ + const char *p = format; + const char *b = p; + ptrdiff_t size; + mrb_value ary = mrb_ary_new_capa(mrb, 4); + int ai = mrb_gc_arena_save(mrb); + + while (*p) { + const char c = *p++; + + if (c == '%') { + if (*p == 'S') { + mrb_value val; + + size = p - b - 1; + mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); + val = va_arg(ap, mrb_value); + mrb_ary_push(mrb, ary, mrb_obj_as_string(mrb, val)); + b = p + 1; + } + } + else if (c == '\\') { + if (*p) { + size = p - b - 1; + mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); + mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1)); + b = ++p; + } + else { + break; + } + } + mrb_gc_arena_restore(mrb, ai); + } + if (b == format) { + return mrb_str_new_cstr(mrb, format); + } + else { + size = p - b; + if (size > 0) { + mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); + mrb_gc_arena_restore(mrb, ai); + } + return mrb_ary_join(mrb, ary, mrb_nil_value()); + } +} + +MRB_API mrb_value +mrb_format(mrb_state *mrb, const char *format, ...) +{ + va_list ap; + mrb_value str; + + va_start(ap, format); + str = mrb_vformat(mrb, format, ap); + va_end(ap); + + return str; +} + +static mrb_noreturn void +raise_va(mrb_state *mrb, struct RClass *c, const char *fmt, va_list ap, int argc, mrb_value *argv) +{ + mrb_value mesg; + + mesg = mrb_vformat(mrb, fmt, ap); + if (argv == NULL) { + argv = &mesg; + } + else { + argv[0] = mesg; + } + mrb_exc_raise(mrb, mrb_obj_new(mrb, c, argc+1, argv)); +} + +MRB_API mrb_noreturn void +mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + raise_va(mrb, c, fmt, args, 0, NULL); + va_end(args); +} + +MRB_API mrb_noreturn void +mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...) +{ + mrb_value argv[2]; + va_list args; + + va_start(args, fmt); + argv[1] = mrb_symbol_value(id); + raise_va(mrb, E_NAME_ERROR, fmt, args, 1, argv); + va_end(args); +} + +MRB_API void +mrb_warn(mrb_state *mrb, const char *fmt, ...) +{ +#ifndef MRB_DISABLE_STDIO + va_list ap; + mrb_value str; + + va_start(ap, fmt); + str = mrb_vformat(mrb, fmt, ap); + fputs("warning: ", stderr); + fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr); + va_end(ap); +#endif +} + +MRB_API mrb_noreturn void +mrb_bug(mrb_state *mrb, const char *fmt, ...) +{ +#ifndef MRB_DISABLE_STDIO + va_list ap; + mrb_value str; + + va_start(ap, fmt); + str = mrb_vformat(mrb, fmt, ap); + fputs("bug: ", stderr); + fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr); + va_end(ap); +#endif + exit(EXIT_FAILURE); +} + +MRB_API mrb_value +mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv) +{ + mrb_value mesg; + int n; + + mesg = mrb_nil_value(); + switch (argc) { + case 0: + break; + case 1: + if (mrb_nil_p(argv[0])) + break; + if (mrb_string_p(argv[0])) { + mesg = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, argv[0]); + break; + } + n = 0; + goto exception_call; + + case 2: + case 3: + n = 1; +exception_call: + { + mrb_sym exc = mrb_intern_lit(mrb, "exception"); + if (mrb_respond_to(mrb, argv[0], exc)) { + mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1); + } + else { + /* undef */ + mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected"); + } + } + + break; + default: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc)); + break; + } + if (argc > 0) { + if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class)) + mrb_raise(mrb, mrb->eException_class, "exception object expected"); + if (argc > 2) + set_backtrace(mrb, mesg, argv[2]); + } + + return mesg; +} + +MRB_API void +mrb_sys_fail(mrb_state *mrb, const char *mesg) +{ + struct RClass *sce; + mrb_int no; + + no = (mrb_int)errno; + if (mrb_class_defined(mrb, "SystemCallError")) { + sce = mrb_class_get(mrb, "SystemCallError"); + if (mesg != NULL) { + mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 2, mrb_fixnum_value(no), mrb_str_new_cstr(mrb, mesg)); + } + else { + mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 1, mrb_fixnum_value(no)); + } + } + else { + mrb_raise(mrb, E_RUNTIME_ERROR, mesg); + } +} + +MRB_API mrb_noreturn void +mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, ...) +{ + mrb_value exc; + mrb_value argv[3]; + va_list ap; + + va_start(ap, fmt); + argv[0] = mrb_vformat(mrb, fmt, ap); + argv[1] = mrb_symbol_value(id); + argv[2] = args; + va_end(ap); + exc = mrb_obj_new(mrb, E_NOMETHOD_ERROR, 3, argv); + mrb_exc_raise(mrb, exc); +} + +void +mrb_init_exception(mrb_state *mrb) +{ + struct RClass *exception, *script_error, *stack_error, *nomem_error; + + mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */ + MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION); + mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_ANY()); + mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_ANY()); + mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_ANY()); + mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE()); + mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE()); + mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE()); + mrb_define_method(mrb, exception, "set_backtrace", exc_set_backtrace, MRB_ARGS_REQ(1)); + + mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */ + mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */ + script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */ + mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */ + stack_error = mrb_define_class(mrb, "SystemStackError", exception); + mrb->stack_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, stack_error, "stack level too deep")); + + nomem_error = mrb_define_class(mrb, "NoMemoryError", exception); + mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "Out of memory")); +#ifdef MRB_GC_FIXED_ARENA + mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "arena overflow error")); +#endif +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/error.h b/web/server/h2o/libh2o/deps/mruby/src/error.h new file mode 100644 index 000000000..eb755ec7f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/error.h @@ -0,0 +1,3 @@ +/* this header file is to be removed soon. + added for compatibility purpose (1.0.0) */ +#include <mruby/error.h> diff --git a/web/server/h2o/libh2o/deps/mruby/src/etc.c b/web/server/h2o/libh2o/deps/mruby/src/etc.c new file mode 100644 index 000000000..9475ae304 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/etc.c @@ -0,0 +1,234 @@ +/* +** etc.c - +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/string.h> +#include <mruby/data.h> +#include <mruby/class.h> +#include <mruby/re.h> +#include <mruby/irep.h> + +MRB_API struct RData* +mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type) +{ + struct RData *data; + + data = (struct RData*)mrb_obj_alloc(mrb, MRB_TT_DATA, klass); + data->data = ptr; + data->type = type; + + return data; +} + +MRB_API void +mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) +{ + if (mrb_type(obj) != MRB_TT_DATA) { + mrb_check_type(mrb, obj, MRB_TT_DATA); + } + if (DATA_TYPE(obj) != type) { + const mrb_data_type *t2 = DATA_TYPE(obj); + + if (t2) { + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)", + mrb_str_new_cstr(mrb, t2->struct_name), mrb_str_new_cstr(mrb, type->struct_name)); + } + else { + struct RClass *c = mrb_class(mrb, obj); + + mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %S (expected %S)", + mrb_obj_value(c), mrb_str_new_cstr(mrb, type->struct_name)); + } + } +} + +MRB_API void* +mrb_data_check_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) +{ + if (mrb_type(obj) != MRB_TT_DATA) { + return NULL; + } + if (DATA_TYPE(obj) != type) { + return NULL; + } + return DATA_PTR(obj); +} + +MRB_API void* +mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) +{ + mrb_data_check_type(mrb, obj, type); + return DATA_PTR(obj); +} + +MRB_API mrb_sym +mrb_obj_to_sym(mrb_state *mrb, mrb_value name) +{ + mrb_sym id; + + switch (mrb_type(name)) { + default: + name = mrb_check_string_type(mrb, name); + if (mrb_nil_p(name)) { + name = mrb_inspect(mrb, name); + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); + } + /* fall through */ + case MRB_TT_STRING: + name = mrb_str_intern(mrb, name); + /* fall through */ + case MRB_TT_SYMBOL: + id = mrb_symbol(name); + } + return id; +} + +MRB_API mrb_int +mrb_float_id(mrb_float f) +{ + const char *p = (const char*)&f; + int len = sizeof(f); + mrb_int id = 0; + + /* normalize -0.0 to 0.0 */ + if (f == 0) f = 0.0; + while (len--) { + id = id*65599 + *p; + p++; + } + id = id + (id>>5); + + return id; +} + +MRB_API mrb_int +mrb_obj_id(mrb_value obj) +{ + mrb_int tt = mrb_type(obj); + +#define MakeID2(p,t) (mrb_int)(((intptr_t)(p))^(t)) +#define MakeID(p) MakeID2(p,tt) + + switch (tt) { + case MRB_TT_FREE: + case MRB_TT_UNDEF: + return MakeID(0); /* not define */ + case MRB_TT_FALSE: + if (mrb_nil_p(obj)) + return MakeID(1); + return MakeID(0); + case MRB_TT_TRUE: + return MakeID(1); + case MRB_TT_SYMBOL: + return MakeID(mrb_symbol(obj)); + case MRB_TT_FIXNUM: + return MakeID2(mrb_float_id((mrb_float)mrb_fixnum(obj)), MRB_TT_FLOAT); + case MRB_TT_FLOAT: + return MakeID(mrb_float_id(mrb_float(obj))); + case MRB_TT_STRING: + case MRB_TT_OBJECT: + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_ICLASS: + case MRB_TT_SCLASS: + case MRB_TT_PROC: + case MRB_TT_ARRAY: + case MRB_TT_HASH: + case MRB_TT_RANGE: + case MRB_TT_EXCEPTION: + case MRB_TT_FILE: + case MRB_TT_DATA: + case MRB_TT_ISTRUCT: + default: + return MakeID(mrb_ptr(obj)); + } +} + +#ifdef MRB_WORD_BOXING +MRB_API mrb_value +mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) +{ + mrb_value v; + + v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class); + v.value.fp->f = f; + return v; +} + +MRB_API mrb_value +mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) +{ + struct RFloat *nf = (struct RFloat *)mrb_malloc(mrb, sizeof(struct RFloat)); + nf->tt = MRB_TT_FLOAT; + nf->c = mrb->float_class; + nf->f = f; + return mrb_obj_value(nf); +} + +MRB_API mrb_value +mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) +{ + mrb_value v; + + v.value.p = mrb_obj_alloc(mrb, MRB_TT_CPTR, mrb->object_class); + v.value.vp->p = p; + return v; +} +#endif /* MRB_WORD_BOXING */ + +MRB_API mrb_bool +mrb_regexp_p(mrb_state *mrb, mrb_value v) +{ + if (mrb->flags & MRB_STATE_NO_REGEXP) { + return FALSE; + } + if ((mrb->flags & MRB_STATE_REGEXP) || mrb_class_defined(mrb, REGEXP_CLASS)) { + mrb->flags |= MRB_STATE_REGEXP; + return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS)); + } + else { + mrb->flags |= MRB_STATE_REGEXP; + mrb->flags |= MRB_STATE_NO_REGEXP; + } + return FALSE; +} + +#if defined _MSC_VER && _MSC_VER < 1900 + +#ifndef va_copy +static void +mrb_msvc_va_copy(va_list *dest, va_list src) +{ + *dest = src; +} +#define va_copy(dest, src) mrb_msvc_va_copy(&(dest), src) +#endif + +MRB_API int +mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg) +{ + int cnt; + va_list argcp; + va_copy(argcp, arg); + if (n == 0 || (cnt = _vsnprintf_s(s, n, _TRUNCATE, format, argcp)) < 0) { + cnt = _vscprintf(format, arg); + } + va_end(argcp); + return cnt; +} + +MRB_API int +mrb_msvc_snprintf(char *s, size_t n, const char *format, ...) +{ + va_list arg; + int ret; + va_start(arg, format); + ret = mrb_msvc_vsnprintf(s, n, format, arg); + va_end(arg); + return ret; +} + +#endif /* defined _MSC_VER && _MSC_VER < 1900 */ diff --git a/web/server/h2o/libh2o/deps/mruby/src/ext/.gitkeep b/web/server/h2o/libh2o/deps/mruby/src/ext/.gitkeep new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/ext/.gitkeep diff --git a/web/server/h2o/libh2o/deps/mruby/src/fmt_fp.c b/web/server/h2o/libh2o/deps/mruby/src/fmt_fp.c new file mode 100644 index 000000000..0a8b22b41 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/fmt_fp.c @@ -0,0 +1,372 @@ +/* + +Most code in this file originates from musl (src/stdio/vfprintf.c) +which, just like mruby itself, is licensed under the MIT license. + +Copyright (c) 2005-2014 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 <limits.h> +#include <string.h> +#include <stdint.h> +#include <math.h> +#include <float.h> +#include <ctype.h> + +#include <mruby.h> +#include <mruby/string.h> + +struct fmt_args { + mrb_state *mrb; + mrb_value str; +}; + +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#define MIN(a,b) ((a)<(b) ? (a) : (b)) + +/* Convenient bit representation for modifier flags, which all fall + * within 31 codepoints of the space character. */ + +#define ALT_FORM (1U<<('#'-' ')) +#define ZERO_PAD (1U<<('0'-' ')) +#define LEFT_ADJ (1U<<('-'-' ')) +#define PAD_POS (1U<<(' '-' ')) +#define MARK_POS (1U<<('+'-' ')) + +static void +out(struct fmt_args *f, const char *s, size_t l) +{ + mrb_str_cat(f->mrb, f->str, s, l); +} + +#define PAD_SIZE 256 +static void +pad(struct fmt_args *f, char c, ptrdiff_t w, ptrdiff_t l, uint8_t fl) +{ + char pad[PAD_SIZE]; + if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return; + l = w - l; + memset(pad, c, l>PAD_SIZE ? PAD_SIZE : l); + for (; l >= PAD_SIZE; l -= PAD_SIZE) + out(f, pad, PAD_SIZE); + out(f, pad, l); +} + +static const char xdigits[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +static char* +fmt_u(uint32_t x, char *s) +{ + for (; x; x /= 10) *--s = '0' + x % 10; + return s; +} + +/* Do not override this check. The floating point printing code below + * depends on the float.h constants being right. If they are wrong, it + * may overflow the stack. */ +#if LDBL_MANT_DIG == 53 +typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; +#endif + +static int +fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) +{ + uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion + + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion + uint32_t *a, *d, *r, *z; + uint32_t i; + int e2=0, e, j; + ptrdiff_t l; + char buf[9+LDBL_MANT_DIG/4], *s; + const char *prefix="-0X+0X 0X-0x+0x 0x"; + ptrdiff_t pl; + char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr; + + pl=1; + if (signbit(y)) { + y=-y; + } else if (fl & MARK_POS) { + prefix+=3; + } else if (fl & PAD_POS) { + prefix+=6; + } else prefix++, pl=0; + + if (!isfinite(y)) { + const char *ss = (t&32)?"inf":"INF"; + if (y!=y) ss=(t&32)?"nan":"NAN"; + pad(f, ' ', 0, 3+pl, fl&~ZERO_PAD); + out(f, prefix, pl); + out(f, ss, 3); + pad(f, ' ', 0, 3+pl, fl^LEFT_ADJ); + return 3+(int)pl; + } + + y = frexp((double)y, &e2) * 2; + if (y) e2--; + + if ((t|32)=='a') { + long double round = 8.0; + ptrdiff_t re; + + if (t&32) prefix += 9; + pl += 2; + + if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0; + else re=LDBL_MANT_DIG/4-1-p; + + if (re) { + while (re--) round*=16; + if (*prefix=='-') { + y=-y; + y-=round; + y+=round; + y=-y; + } + else { + y+=round; + y-=round; + } + } + + estr=fmt_u(e2<0 ? -e2 : e2, ebuf); + if (estr==ebuf) *--estr='0'; + *--estr = (e2<0 ? '-' : '+'); + *--estr = t+('p'-'a'); + + s=buf; + do { + int x=(int)y; + *s++=xdigits[x]|(t&32); + y=16*(y-x); + if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.'; + } while (y); + + if (p && s-buf-2 < p) + l = (p+2) + (ebuf-estr); + else + l = (s-buf) + (ebuf-estr); + + pad(f, ' ', 0, pl+l, fl); + out(f, prefix, pl); + pad(f, '0', 0, pl+l, fl^ZERO_PAD); + out(f, buf, s-buf); + pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0); + out(f, estr, ebuf-estr); + pad(f, ' ', 0, pl+l, fl^LEFT_ADJ); + return (int)pl+(int)l; + } + if (p<0) p=6; + + if (y) y *= 268435456.0, e2-=28; + + if (e2<0) a=r=z=big; + else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1; + + do { + *z = (uint32_t)y; + y = 1000000000*(y-*z++); + } while (y); + + while (e2>0) { + uint32_t carry=0; + int sh=MIN(29,e2); + for (d=z-1; d>=a; d--) { + uint64_t x = ((uint64_t)*d<<sh)+carry; + *d = x % 1000000000; + carry = (uint32_t)(x / 1000000000); + } + if (carry) *--a = carry; + while (z>a && !z[-1]) z--; + e2-=sh; + } + while (e2<0) { + uint32_t carry=0, *b; + int sh=MIN(9,-e2), need=1+((int)p+LDBL_MANT_DIG/3+8)/9; + for (d=a; d<z; d++) { + uint32_t rm = *d & ((1<<sh)-1); + *d = (*d>>sh) + carry; + carry = (1000000000>>sh) * rm; + } + if (!*a) a++; + if (carry) *z++ = carry; + /* Avoid (slow!) computation past requested precision */ + b = (t|32)=='f' ? r : a; + if (z-b > need) z = b+need; + e2+=sh; + } + + if (a<z) for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++); + else e=0; + + /* Perform rounding: j is precision after the radix (possibly neg) */ + j = (int)p - ((t|32)!='f')*e - ((t|32)=='g' && p); + if (j < 9*(z-r-1)) { + uint32_t x; + /* We avoid C's broken division of negative numbers */ + d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP); + j += 9*LDBL_MAX_EXP; + j %= 9; + for (i=10, j++; j<9; i*=10, j++); + x = *d % i; + /* Are there any significant digits past j? */ + if (x || d+1!=z) { + long double round = 2/LDBL_EPSILON; + long double small; + if (*d/i & 1) round += 2; + if (x<i/2) small=0.5; + else if (x==i/2 && d+1==z) small=1.0; + else small=1.5; + if (pl && *prefix=='-') round*=-1, small*=-1; + *d -= x; + /* Decide whether to round by probing round+small */ + if (round+small != round) { + *d = *d + i; + while (*d > 999999999) { + *d--=0; + if (d<a) *--a=0; + (*d)++; + } + for (i=10, e=9*(int)(r-a); *a>=i; i*=10, e++); + } + } + if (z>d+1) z=d+1; + } + for (; z>a && !z[-1]; z--); + + if ((t|32)=='g') { + if (!p) p++; + if (p>e && e>=-4) { + t--; + p-=e+1; + } + else { + t-=2; + p--; + } + if (!(fl&ALT_FORM)) { + /* Count trailing zeros in last place */ + if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++); + else j=9; + if ((t|32)=='f') + p = MIN(p,MAX(0,9*(z-r-1)-j)); + else + p = MIN(p,MAX(0,9*(z-r-1)+e-j)); + } + } + l = 1 + p + (p || (fl&ALT_FORM)); + if ((t|32)=='f') { + if (e>0) l+=e; + } + else { + estr=fmt_u(e<0 ? -e : e, ebuf); + while(ebuf-estr<2) *--estr='0'; + *--estr = (e<0 ? '-' : '+'); + *--estr = t; + l += ebuf-estr; + } + + pad(f, ' ', 0, pl+l, fl); + out(f, prefix, pl); + pad(f, '0', 0, pl+l, fl^ZERO_PAD); + + if ((t|32)=='f') { + if (a>r) a=r; + for (d=a; d<=r; d++) { + char *ss = fmt_u(*d, buf+9); + if (d!=a) while (ss>buf) *--ss='0'; + else if (ss==buf+9) *--ss='0'; + out(f, ss, buf+9-ss); + } + if (p || (fl&ALT_FORM)) out(f, ".", 1); + for (; d<z && p>0; d++, p-=9) { + char *ss = fmt_u(*d, buf+9); + while (ss>buf) *--ss='0'; + out(f, ss, MIN(9,p)); + } + pad(f, '0', p+9, 9, 0); + } + else { + if (z<=a) z=a+1; + for (d=a; d<z && p>=0; d++) { + char *ss = fmt_u(*d, buf+9); + if (ss==buf+9) *--ss='0'; + if (d!=a) while (ss>buf) *--ss='0'; + else { + out(f, ss++, 1); + if (p>0||(fl&ALT_FORM)) out(f, ".", 1); + } + out(f, ss, MIN(buf+9-ss, p)); + p -= (int)(buf+9-ss); + } + pad(f, '0', p+18, 18, 0); + out(f, estr, ebuf-estr); + } + + pad(f, ' ', 0, pl+l, fl^LEFT_ADJ); + + return (int)pl+(int)l; +} + +static int +fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo) +{ + ptrdiff_t p; + + if (*fmt != '%') { + return -1; + } + ++fmt; + + if (*fmt == '.') { + ++fmt; + for (p = 0; ISDIGIT(*fmt); ++fmt) { + p = 10 * p + (*fmt - '0'); + } + } + else { + p = -1; + } + + switch (*fmt) { + case 'e': case 'f': case 'g': case 'a': + case 'E': case 'F': case 'G': case 'A': + return fmt_fp(f, flo, p, 0, *fmt); + default: + return -1; + } +} + +mrb_value +mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) +{ + struct fmt_args f; + + f.mrb = mrb; + f.str = mrb_str_new_capa(mrb, 24); + if (fmt_core(&f, fmt, mrb_float(flo)) < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string"); + } + return f.str; +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/gc.c b/web/server/h2o/libh2o/deps/mruby/src/gc.c new file mode 100644 index 000000000..d602bfb70 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/gc.c @@ -0,0 +1,1824 @@ +/* +** gc.c - garbage collector for mruby +** +** See Copyright Notice in mruby.h +*/ + +#include <string.h> +#include <stdlib.h> +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/data.h> +#include <mruby/hash.h> +#include <mruby/proc.h> +#include <mruby/range.h> +#include <mruby/string.h> +#include <mruby/variable.h> +#include <mruby/gc.h> +#include <mruby/error.h> +#include <mruby/throw.h> + +/* + = Tri-color Incremental Garbage Collection + + mruby's GC is Tri-color Incremental GC with Mark & Sweep. + Algorithm details are omitted. + Instead, the implementation part is described below. + + == Object's Color + + Each object can be painted in three colors: + + * White - Unmarked. + * Gray - Marked, But the child objects are unmarked. + * Black - Marked, the child objects are also marked. + + == Two White Types + + There're two white color types in a flip-flop fashion: White-A and White-B, + which respectively represent the Current White color (the newly allocated + objects in the current GC cycle) and the Sweep Target White color (the + dead objects to be swept). + + A and B will be switched just at the beginning of the next GC cycle. At + that time, all the dead objects have been swept, while the newly created + objects in the current GC cycle which finally remains White are now + regarded as dead objects. Instead of traversing all the White-A objects and + painting them as White-B, just switch the meaning of White-A and White-B as + this will be much cheaper. + + As a result, the objects we sweep in the current GC cycle are always + left from the previous GC cycle. This allows us to sweep objects + incrementally, without the disturbance of the newly created objects. + + == Execution Timing + + GC Execution Time and Each step interval are decided by live objects count. + List of Adjustment API: + + * gc_interval_ratio_set + * gc_step_ratio_set + + For details, see the comments for each function. + + == Write Barrier + + mruby implementer and C extension library writer must insert a write + barrier when updating a reference from a field of an object. + When updating a reference from a field of object A to object B, + two different types of write barrier are available: + + * mrb_field_write_barrier - target B object for a mark. + * mrb_write_barrier - target A object for a mark. + + == Generational Mode + + mruby's GC offers an Generational Mode while re-using the tri-color GC + infrastructure. It will treat the Black objects as Old objects after each + sweep phase, instead of painting them White. The key ideas are still the same + as traditional generational GC: + + * Minor GC - just traverse the Young objects (Gray objects) in the mark + phase, then only sweep the newly created objects, and leave + the Old objects live. + + * Major GC - same as a full regular GC cycle. + + The difference from "traditional" generational GC is, that the major GC + in mruby is triggered incrementally in a tri-color manner. + + + For details, see the comments for each function. + +*/ + +struct free_obj { + MRB_OBJECT_HEADER; + struct RBasic *next; +}; + +typedef struct { + union { + struct free_obj free; + struct RBasic basic; + struct RObject object; + struct RClass klass; + struct RString string; + struct RArray array; + struct RHash hash; + struct RRange range; + struct RData data; + struct RProc proc; + struct REnv env; + struct RException exc; + struct RBreak brk; +#ifdef MRB_WORD_BOXING + struct RFloat floatv; + struct RCptr cptr; +#endif + } as; +} RVALUE; + +#ifdef GC_PROFILE +#include <stdio.h> +#include <sys/time.h> + +static double program_invoke_time = 0; +static double gc_time = 0; +static double gc_total_time = 0; + +static double +gettimeofday_time(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec + tv.tv_usec * 1e-6; +} + +#define GC_INVOKE_TIME_REPORT(with) do {\ + fprintf(stderr, "%s\n", with);\ + fprintf(stderr, "gc_invoke: %19.3f\n", gettimeofday_time() - program_invoke_time);\ + fprintf(stderr, "is_generational: %d\n", is_generational(gc));\ + fprintf(stderr, "is_major_gc: %d\n", is_major_gc(gc));\ +} while(0) + +#define GC_TIME_START do {\ + gc_time = gettimeofday_time();\ +} while(0) + +#define GC_TIME_STOP_AND_REPORT do {\ + gc_time = gettimeofday_time() - gc_time;\ + gc_total_time += gc_time;\ + fprintf(stderr, "gc_state: %d\n", gc->state);\ + fprintf(stderr, "live: %zu\n", gc->live);\ + fprintf(stderr, "majorgc_old_threshold: %zu\n", gc->majorgc_old_threshold);\ + fprintf(stderr, "gc_threshold: %zu\n", gc->threshold);\ + fprintf(stderr, "gc_time: %30.20f\n", gc_time);\ + fprintf(stderr, "gc_total_time: %30.20f\n\n", gc_total_time);\ +} while(0) +#else +#define GC_INVOKE_TIME_REPORT(s) +#define GC_TIME_START +#define GC_TIME_STOP_AND_REPORT +#endif + +#ifdef GC_DEBUG +#define DEBUG(x) (x) +#else +#define DEBUG(x) +#endif + +#ifndef MRB_HEAP_PAGE_SIZE +#define MRB_HEAP_PAGE_SIZE 1024 +#endif + +#define GC_STEP_SIZE 1024 + +/* white: 011, black: 100, gray: 000 */ +#define GC_GRAY 0 +#define GC_WHITE_A 1 +#define GC_WHITE_B (1 << 1) +#define GC_BLACK (1 << 2) +#define GC_WHITES (GC_WHITE_A | GC_WHITE_B) +#define GC_COLOR_MASK 7 + +#define paint_gray(o) ((o)->color = GC_GRAY) +#define paint_black(o) ((o)->color = GC_BLACK) +#define paint_white(o) ((o)->color = GC_WHITES) +#define paint_partial_white(s, o) ((o)->color = (s)->current_white_part) +#define is_gray(o) ((o)->color == GC_GRAY) +#define is_white(o) ((o)->color & GC_WHITES) +#define is_black(o) ((o)->color & GC_BLACK) +#define flip_white_part(s) ((s)->current_white_part = other_white_part(s)) +#define other_white_part(s) ((s)->current_white_part ^ GC_WHITES) +#define is_dead(s, o) (((o)->color & other_white_part(s) & GC_WHITES) || (o)->tt == MRB_TT_FREE) + +#define objects(p) ((RVALUE *)p->objects) + +MRB_API void* +mrb_realloc_simple(mrb_state *mrb, void *p, size_t len) +{ + void *p2; + + p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud); + if (!p2 && len > 0 && mrb->gc.heaps) { + mrb_full_gc(mrb); + p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud); + } + + return p2; +} + +MRB_API void* +mrb_realloc(mrb_state *mrb, void *p, size_t len) +{ + void *p2; + + p2 = mrb_realloc_simple(mrb, p, len); + if (len == 0) return p2; + if (p2 == NULL) { + if (mrb->gc.out_of_memory) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err)); + /* mrb_panic(mrb); */ + } + else { + mrb->gc.out_of_memory = TRUE; + mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err)); + } + } + else { + mrb->gc.out_of_memory = FALSE; + } + + return p2; +} + +MRB_API void* +mrb_malloc(mrb_state *mrb, size_t len) +{ + return mrb_realloc(mrb, 0, len); +} + +MRB_API void* +mrb_malloc_simple(mrb_state *mrb, size_t len) +{ + return mrb_realloc_simple(mrb, 0, len); +} + +MRB_API void* +mrb_calloc(mrb_state *mrb, size_t nelem, size_t len) +{ + void *p; + + if (nelem > 0 && len > 0 && + nelem <= SIZE_MAX / len) { + size_t size; + size = nelem * len; + p = mrb_malloc(mrb, size); + + memset(p, 0, size); + } + else { + p = NULL; + } + + return p; +} + +MRB_API void +mrb_free(mrb_state *mrb, void *p) +{ + (mrb->allocf)(mrb, p, 0, mrb->allocf_ud); +} + +MRB_API mrb_bool +mrb_object_dead_p(mrb_state *mrb, struct RBasic *object) { + return is_dead(&mrb->gc, object); +} + +static void +link_heap_page(mrb_gc *gc, mrb_heap_page *page) +{ + page->next = gc->heaps; + if (gc->heaps) + gc->heaps->prev = page; + gc->heaps = page; +} + +static void +unlink_heap_page(mrb_gc *gc, mrb_heap_page *page) +{ + if (page->prev) + page->prev->next = page->next; + if (page->next) + page->next->prev = page->prev; + if (gc->heaps == page) + gc->heaps = page->next; + page->prev = NULL; + page->next = NULL; +} + +static void +link_free_heap_page(mrb_gc *gc, mrb_heap_page *page) +{ + page->free_next = gc->free_heaps; + if (gc->free_heaps) { + gc->free_heaps->free_prev = page; + } + gc->free_heaps = page; +} + +static void +unlink_free_heap_page(mrb_gc *gc, mrb_heap_page *page) +{ + if (page->free_prev) + page->free_prev->free_next = page->free_next; + if (page->free_next) + page->free_next->free_prev = page->free_prev; + if (gc->free_heaps == page) + gc->free_heaps = page->free_next; + page->free_prev = NULL; + page->free_next = NULL; +} + +static void +add_heap(mrb_state *mrb, mrb_gc *gc) +{ + mrb_heap_page *page = (mrb_heap_page *)mrb_calloc(mrb, 1, sizeof(mrb_heap_page) + MRB_HEAP_PAGE_SIZE * sizeof(RVALUE)); + RVALUE *p, *e; + struct RBasic *prev = NULL; + + for (p = objects(page), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) { + p->as.free.tt = MRB_TT_FREE; + p->as.free.next = prev; + prev = &p->as.basic; + } + page->freelist = prev; + + link_heap_page(gc, page); + link_free_heap_page(gc, page); +} + +#define DEFAULT_GC_INTERVAL_RATIO 200 +#define DEFAULT_GC_STEP_RATIO 200 +#define DEFAULT_MAJOR_GC_INC_RATIO 200 +#define is_generational(gc) ((gc)->generational) +#define is_major_gc(gc) (is_generational(gc) && (gc)->full) +#define is_minor_gc(gc) (is_generational(gc) && !(gc)->full) + +void +mrb_gc_init(mrb_state *mrb, mrb_gc *gc) +{ +#ifndef MRB_GC_FIXED_ARENA + gc->arena = (struct RBasic**)mrb_malloc(mrb, sizeof(struct RBasic*)*MRB_GC_ARENA_SIZE); + gc->arena_capa = MRB_GC_ARENA_SIZE; +#endif + + gc->current_white_part = GC_WHITE_A; + gc->heaps = NULL; + gc->free_heaps = NULL; + add_heap(mrb, gc); + gc->interval_ratio = DEFAULT_GC_INTERVAL_RATIO; + gc->step_ratio = DEFAULT_GC_STEP_RATIO; +#ifndef MRB_GC_TURN_OFF_GENERATIONAL + gc->generational = TRUE; + gc->full = TRUE; +#endif + +#ifdef GC_PROFILE + program_invoke_time = gettimeofday_time(); +#endif +} + +static void obj_free(mrb_state *mrb, struct RBasic *obj, int end); + +void +free_heap(mrb_state *mrb, mrb_gc *gc) +{ + mrb_heap_page *page = gc->heaps; + mrb_heap_page *tmp; + RVALUE *p, *e; + + while (page) { + tmp = page; + page = page->next; + for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) { + if (p->as.free.tt != MRB_TT_FREE) + obj_free(mrb, &p->as.basic, TRUE); + } + mrb_free(mrb, tmp); + } +} + +void +mrb_gc_destroy(mrb_state *mrb, mrb_gc *gc) +{ + free_heap(mrb, gc); +#ifndef MRB_GC_FIXED_ARENA + mrb_free(mrb, gc->arena); +#endif +} + +static void +gc_protect(mrb_state *mrb, mrb_gc *gc, struct RBasic *p) +{ +#ifdef MRB_GC_FIXED_ARENA + if (gc->arena_idx >= MRB_GC_ARENA_SIZE) { + /* arena overflow error */ + gc->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */ + mrb_exc_raise(mrb, mrb_obj_value(mrb->arena_err)); + } +#else + if (gc->arena_idx >= gc->arena_capa) { + /* extend arena */ + gc->arena_capa = (int)(gc->arena_capa * 1.5); + gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*gc->arena_capa); + } +#endif + gc->arena[gc->arena_idx++] = p; +} + +/* mrb_gc_protect() leaves the object in the arena */ +MRB_API void +mrb_gc_protect(mrb_state *mrb, mrb_value obj) +{ + if (mrb_immediate_p(obj)) return; + gc_protect(mrb, &mrb->gc, mrb_basic_ptr(obj)); +} + +#define GC_ROOT_NAME "_gc_root_" + +/* mrb_gc_register() keeps the object from GC. + + Register your object when it's exported to C world, + without reference from Ruby world, e.g. callback + arguments. Don't forget to remove the object using + mrb_gc_unregister, otherwise your object will leak. +*/ + +MRB_API void +mrb_gc_register(mrb_state *mrb, mrb_value obj) +{ + mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); + mrb_value table = mrb_gv_get(mrb, root); + + if (mrb_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) { + table = mrb_ary_new(mrb); + mrb_gv_set(mrb, root, table); + } + mrb_ary_push(mrb, table, obj); +} + +/* mrb_gc_unregister() removes the object from GC root. */ +MRB_API void +mrb_gc_unregister(mrb_state *mrb, mrb_value obj) +{ + mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); + mrb_value table = mrb_gv_get(mrb, root); + struct RArray *a; + mrb_int i; + + if (mrb_nil_p(table)) return; + if (mrb_type(table) != MRB_TT_ARRAY) { + mrb_gv_set(mrb, root, mrb_nil_value()); + return; + } + a = mrb_ary_ptr(table); + mrb_ary_modify(mrb, a); + for (i = 0; i < ARY_LEN(a); i++) { + if (mrb_obj_eq(mrb, ARY_PTR(a)[i], obj)) { + mrb_int len = ARY_LEN(a)-1; + mrb_value *ptr = ARY_PTR(a); + + ARY_SET_LEN(a, len); + memmove(&ptr[i], &ptr[i + 1], (len - i) * sizeof(mrb_value)); + break; + } + } +} + +MRB_API struct RBasic* +mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) +{ + struct RBasic *p; + static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } }; + mrb_gc *gc = &mrb->gc; + + if (cls) { + enum mrb_vtype tt; + + switch (cls->tt) { + case MRB_TT_CLASS: + case MRB_TT_SCLASS: + case MRB_TT_MODULE: + case MRB_TT_ENV: + break; + default: + mrb_raise(mrb, E_TYPE_ERROR, "allocation failure"); + } + tt = MRB_INSTANCE_TT(cls); + if (tt != MRB_TT_FALSE && + ttype != MRB_TT_SCLASS && + ttype != MRB_TT_ICLASS && + ttype != MRB_TT_ENV && + ttype != tt) { + mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls)); + } + } + +#ifdef MRB_GC_STRESS + mrb_full_gc(mrb); +#endif + if (gc->threshold < gc->live) { + mrb_incremental_gc(mrb); + } + if (gc->free_heaps == NULL) { + add_heap(mrb, gc); + } + + p = gc->free_heaps->freelist; + gc->free_heaps->freelist = ((struct free_obj*)p)->next; + if (gc->free_heaps->freelist == NULL) { + unlink_free_heap_page(gc, gc->free_heaps); + } + + gc->live++; + gc_protect(mrb, gc, p); + *(RVALUE *)p = RVALUE_zero; + p->tt = ttype; + p->c = cls; + paint_partial_white(gc, p); + return p; +} + +static inline void +add_gray_list(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) +{ +#ifdef MRB_GC_STRESS + if (obj->tt > MRB_TT_MAXDEFINE) { + abort(); + } +#endif + paint_gray(obj); + obj->gcnext = gc->gray_list; + gc->gray_list = obj; +} + +static void +mark_context_stack(mrb_state *mrb, struct mrb_context *c) +{ + size_t i; + size_t e; + mrb_value nil; + int nregs; + + if (c->stack == NULL) return; + e = c->stack - c->stbase; + if (c->ci) { + nregs = c->ci->argc + 2; + if (c->ci->nregs > nregs) + nregs = c->ci->nregs; + e += nregs; + } + if (c->stbase + e > c->stend) e = c->stend - c->stbase; + for (i=0; i<e; i++) { + mrb_value v = c->stbase[i]; + + if (!mrb_immediate_p(v)) { + mrb_gc_mark(mrb, mrb_basic_ptr(v)); + } + } + e = c->stend - c->stbase; + nil = mrb_nil_value(); + for (; i<e; i++) { + c->stbase[i] = nil; + } +} + +static void +mark_context(mrb_state *mrb, struct mrb_context *c) +{ + int i; + mrb_callinfo *ci; + + if (c->status == MRB_FIBER_TERMINATED) return; + + /* mark VM stack */ + mark_context_stack(mrb, c); + + /* mark call stack */ + if (c->cibase) { + for (ci = c->cibase; ci <= c->ci; ci++) { + mrb_gc_mark(mrb, (struct RBasic*)ci->env); + mrb_gc_mark(mrb, (struct RBasic*)ci->proc); + mrb_gc_mark(mrb, (struct RBasic*)ci->target_class); + } + } + /* mark ensure stack */ + for (i=0; i<c->esize; i++) { + if (c->ensure[i] == NULL) break; + mrb_gc_mark(mrb, (struct RBasic*)c->ensure[i]); + } + /* mark fibers */ + mrb_gc_mark(mrb, (struct RBasic*)c->fib); + if (c->prev) { + mark_context(mrb, c->prev); + } +} + +static void +gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) +{ + mrb_assert(is_gray(obj)); + paint_black(obj); + gc->gray_list = obj->gcnext; + mrb_gc_mark(mrb, (struct RBasic*)obj->c); + switch (obj->tt) { + case MRB_TT_ICLASS: + { + struct RClass *c = (struct RClass*)obj; + if (MRB_FLAG_TEST(c, MRB_FLAG_IS_ORIGIN)) + mrb_gc_mark_mt(mrb, c); + mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super); + } + break; + + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_SCLASS: + { + struct RClass *c = (struct RClass*)obj; + + mrb_gc_mark_mt(mrb, c); + mrb_gc_mark(mrb, (struct RBasic*)c->super); + } + /* fall through */ + + case MRB_TT_OBJECT: + case MRB_TT_DATA: + case MRB_TT_EXCEPTION: + mrb_gc_mark_iv(mrb, (struct RObject*)obj); + break; + + case MRB_TT_PROC: + { + struct RProc *p = (struct RProc*)obj; + + mrb_gc_mark(mrb, (struct RBasic*)p->env); + mrb_gc_mark(mrb, (struct RBasic*)p->target_class); + if (!MRB_PROC_CFUNC_P(p) && p->body.irep) { + mrb_gc_mark(mrb, (struct RBasic*)p->body.irep->target_class); + } + } + break; + + case MRB_TT_ENV: + { + struct REnv *e = (struct REnv*)obj; + mrb_int i, len; + + if (MRB_ENV_STACK_SHARED_P(e)) { + if (e->cxt.c->fib) { + mrb_gc_mark(mrb, (struct RBasic*)e->cxt.c->fib); + } + break; + } + len = MRB_ENV_STACK_LEN(e); + for (i=0; i<len; i++) { + mrb_gc_mark_value(mrb, e->stack[i]); + } + } + break; + + case MRB_TT_FIBER: + { + struct mrb_context *c = ((struct RFiber*)obj)->cxt; + + if (c) mark_context(mrb, c); + } + break; + + case MRB_TT_ARRAY: + { + struct RArray *a = (struct RArray*)obj; + size_t i, e; + + for (i=0,e=ARY_LEN(a); i<e; i++) { + mrb_gc_mark_value(mrb, ARY_PTR(a)[i]); + } + } + break; + + case MRB_TT_HASH: + mrb_gc_mark_iv(mrb, (struct RObject*)obj); + mrb_gc_mark_hash(mrb, (struct RHash*)obj); + break; + + case MRB_TT_STRING: + break; + + case MRB_TT_RANGE: + { + struct RRange *r = (struct RRange*)obj; + + if (r->edges) { + mrb_gc_mark_value(mrb, r->edges->beg); + mrb_gc_mark_value(mrb, r->edges->end); + } + } + break; + + default: + break; + } +} + +MRB_API void +mrb_gc_mark(mrb_state *mrb, struct RBasic *obj) +{ + if (obj == 0) return; + if (!is_white(obj)) return; + mrb_assert((obj)->tt != MRB_TT_FREE); + add_gray_list(mrb, &mrb->gc, obj); +} + +static void +obj_free(mrb_state *mrb, struct RBasic *obj, int end) +{ + DEBUG(fprintf(stderr, "obj_free(%p,tt=%d)\n",obj,obj->tt)); + switch (obj->tt) { + /* immediate - no mark */ + case MRB_TT_TRUE: + case MRB_TT_FIXNUM: + case MRB_TT_SYMBOL: + /* cannot happen */ + return; + + case MRB_TT_FLOAT: +#ifdef MRB_WORD_BOXING + break; +#else + return; +#endif + + case MRB_TT_OBJECT: + mrb_gc_free_iv(mrb, (struct RObject*)obj); + break; + + case MRB_TT_EXCEPTION: + mrb_gc_free_iv(mrb, (struct RObject*)obj); + break; + + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_SCLASS: + mrb_gc_free_mt(mrb, (struct RClass*)obj); + mrb_gc_free_iv(mrb, (struct RObject*)obj); + break; + case MRB_TT_ICLASS: + if (MRB_FLAG_TEST(obj, MRB_FLAG_IS_ORIGIN)) + mrb_gc_free_mt(mrb, (struct RClass*)obj); + break; + case MRB_TT_ENV: + { + struct REnv *e = (struct REnv*)obj; + + if (MRB_ENV_STACK_SHARED_P(e)) { + /* cannot be freed */ + return; + } + mrb_free(mrb, e->stack); + e->stack = NULL; + } + break; + + case MRB_TT_FIBER: + { + struct mrb_context *c = ((struct RFiber*)obj)->cxt; + + if (!end && c && c != mrb->root_c) { + mrb_callinfo *ci = c->ci; + mrb_callinfo *ce = c->cibase; + + while (ce <= ci) { + struct REnv *e = ci->env; + if (e && !is_dead(&mrb->gc, e) && + e->tt == MRB_TT_ENV && MRB_ENV_STACK_SHARED_P(e)) { + mrb_env_unshare(mrb, e); + } + ci--; + } + mrb_free_context(mrb, c); + } + } + break; + + case MRB_TT_ARRAY: + if (ARY_SHARED_P(obj)) + mrb_ary_decref(mrb, ((struct RArray*)obj)->as.heap.aux.shared); + else if (!ARY_EMBED_P(obj)) + mrb_free(mrb, ((struct RArray*)obj)->as.heap.ptr); + break; + + case MRB_TT_HASH: + mrb_gc_free_iv(mrb, (struct RObject*)obj); + mrb_gc_free_hash(mrb, (struct RHash*)obj); + break; + + case MRB_TT_STRING: + mrb_gc_free_str(mrb, (struct RString*)obj); + break; + + case MRB_TT_PROC: + { + struct RProc *p = (struct RProc*)obj; + + if (!MRB_PROC_CFUNC_P(p) && p->body.irep) { + mrb_irep_decref(mrb, p->body.irep); + } + } + break; + + case MRB_TT_RANGE: + mrb_free(mrb, ((struct RRange*)obj)->edges); + break; + + case MRB_TT_DATA: + { + struct RData *d = (struct RData*)obj; + if (d->type && d->type->dfree) { + d->type->dfree(mrb, d->data); + } + mrb_gc_free_iv(mrb, (struct RObject*)obj); + } + break; + + default: + break; + } + obj->tt = MRB_TT_FREE; +} + +static void +root_scan_phase(mrb_state *mrb, mrb_gc *gc) +{ + int i, e; + + if (!is_minor_gc(gc)) { + gc->gray_list = NULL; + gc->atomic_gray_list = NULL; + } + + mrb_gc_mark_gv(mrb); + /* mark arena */ + for (i=0,e=gc->arena_idx; i<e; i++) { + mrb_gc_mark(mrb, gc->arena[i]); + } + /* mark class hierarchy */ + mrb_gc_mark(mrb, (struct RBasic*)mrb->object_class); + + /* mark built-in classes */ + mrb_gc_mark(mrb, (struct RBasic*)mrb->class_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->module_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->proc_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->string_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->array_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->hash_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->range_class); + + mrb_gc_mark(mrb, (struct RBasic*)mrb->float_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->fixnum_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->true_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->false_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->nil_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->symbol_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->kernel_module); + + mrb_gc_mark(mrb, (struct RBasic*)mrb->eException_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->eStandardError_class); + + /* mark top_self */ + mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self); + /* mark exception */ + mrb_gc_mark(mrb, (struct RBasic*)mrb->exc); + /* mark pre-allocated exception */ + mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err); + mrb_gc_mark(mrb, (struct RBasic*)mrb->stack_err); +#ifdef MRB_GC_FIXED_ARENA + mrb_gc_mark(mrb, (struct RBasic*)mrb->arena_err); +#endif + + mark_context(mrb, mrb->c); + if (mrb->root_c != mrb->c) { + mark_context(mrb, mrb->root_c); + } +} + +static size_t +gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) +{ + size_t children = 0; + + gc_mark_children(mrb, gc, obj); + + switch (obj->tt) { + case MRB_TT_ICLASS: + children++; + break; + + case MRB_TT_CLASS: + case MRB_TT_SCLASS: + case MRB_TT_MODULE: + { + struct RClass *c = (struct RClass*)obj; + + children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj); + children += mrb_gc_mark_mt_size(mrb, c); + children++; + } + break; + + case MRB_TT_OBJECT: + case MRB_TT_DATA: + case MRB_TT_EXCEPTION: + children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj); + break; + + case MRB_TT_ENV: + children += (int)obj->flags; + break; + + case MRB_TT_FIBER: + { + struct mrb_context *c = ((struct RFiber*)obj)->cxt; + size_t i; + mrb_callinfo *ci; + + if (!c) break; + /* mark stack */ + i = c->stack - c->stbase; + if (c->ci) i += c->ci->nregs; + if (c->stbase + i > c->stend) i = c->stend - c->stbase; + children += i; + + /* mark ensure stack */ + children += c->eidx; + + /* mark closure */ + if (c->cibase) { + for (i=0, ci = c->cibase; ci <= c->ci; i++, ci++) + ; + } + children += i; + } + break; + + case MRB_TT_ARRAY: + { + struct RArray *a = (struct RArray*)obj; + children += ARY_LEN(a); + } + break; + + case MRB_TT_HASH: + children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj); + children += mrb_gc_mark_hash_size(mrb, (struct RHash*)obj); + break; + + case MRB_TT_PROC: + case MRB_TT_RANGE: + children+=2; + break; + + default: + break; + } + return children; +} + + +static void +gc_mark_gray_list(mrb_state *mrb, mrb_gc *gc) { + while (gc->gray_list) { + if (is_gray(gc->gray_list)) + gc_mark_children(mrb, gc, gc->gray_list); + else + gc->gray_list = gc->gray_list->gcnext; + } +} + + +static size_t +incremental_marking_phase(mrb_state *mrb, mrb_gc *gc, size_t limit) +{ + size_t tried_marks = 0; + + while (gc->gray_list && tried_marks < limit) { + tried_marks += gc_gray_mark(mrb, gc, gc->gray_list); + } + + return tried_marks; +} + +static void +final_marking_phase(mrb_state *mrb, mrb_gc *gc) +{ + int i, e; + + /* mark arena */ + for (i=0,e=gc->arena_idx; i<e; i++) { + mrb_gc_mark(mrb, gc->arena[i]); + } + mrb_gc_mark_gv(mrb); + mark_context(mrb, mrb->c); + mark_context(mrb, mrb->root_c); + mrb_gc_mark(mrb, (struct RBasic*)mrb->exc); + gc_mark_gray_list(mrb, gc); + mrb_assert(gc->gray_list == NULL); + gc->gray_list = gc->atomic_gray_list; + gc->atomic_gray_list = NULL; + gc_mark_gray_list(mrb, gc); + mrb_assert(gc->gray_list == NULL); +} + +static void +prepare_incremental_sweep(mrb_state *mrb, mrb_gc *gc) +{ + gc->state = MRB_GC_STATE_SWEEP; + gc->sweeps = gc->heaps; + gc->live_after_mark = gc->live; +} + +static size_t +incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit) +{ + mrb_heap_page *page = gc->sweeps; + size_t tried_sweep = 0; + + while (page && (tried_sweep < limit)) { + RVALUE *p = objects(page); + RVALUE *e = p + MRB_HEAP_PAGE_SIZE; + size_t freed = 0; + mrb_bool dead_slot = TRUE; + mrb_bool full = (page->freelist == NULL); + + if (is_minor_gc(gc) && page->old) { + /* skip a slot which doesn't contain any young object */ + p = e; + dead_slot = FALSE; + } + while (p<e) { + if (is_dead(gc, &p->as.basic)) { + if (p->as.basic.tt != MRB_TT_FREE) { + obj_free(mrb, &p->as.basic, FALSE); + if (p->as.basic.tt == MRB_TT_FREE) { + p->as.free.next = page->freelist; + page->freelist = (struct RBasic*)p; + freed++; + } + else { + dead_slot = FALSE; + } + } + } + else { + if (!is_generational(gc)) + paint_partial_white(gc, &p->as.basic); /* next gc target */ + dead_slot = FALSE; + } + p++; + } + + /* free dead slot */ + if (dead_slot && freed < MRB_HEAP_PAGE_SIZE) { + mrb_heap_page *next = page->next; + + unlink_heap_page(gc, page); + unlink_free_heap_page(gc, page); + mrb_free(mrb, page); + page = next; + } + else { + if (full && freed > 0) { + link_free_heap_page(gc, page); + } + if (page->freelist == NULL && is_minor_gc(gc)) + page->old = TRUE; + else + page->old = FALSE; + page = page->next; + } + tried_sweep += MRB_HEAP_PAGE_SIZE; + gc->live -= freed; + gc->live_after_mark -= freed; + } + gc->sweeps = page; + return tried_sweep; +} + +static size_t +incremental_gc(mrb_state *mrb, mrb_gc *gc, size_t limit) +{ + switch (gc->state) { + case MRB_GC_STATE_ROOT: + root_scan_phase(mrb, gc); + gc->state = MRB_GC_STATE_MARK; + flip_white_part(gc); + return 0; + case MRB_GC_STATE_MARK: + if (gc->gray_list) { + return incremental_marking_phase(mrb, gc, limit); + } + else { + final_marking_phase(mrb, gc); + prepare_incremental_sweep(mrb, gc); + return 0; + } + case MRB_GC_STATE_SWEEP: { + size_t tried_sweep = 0; + tried_sweep = incremental_sweep_phase(mrb, gc, limit); + if (tried_sweep == 0) + gc->state = MRB_GC_STATE_ROOT; + return tried_sweep; + } + default: + /* unknown state */ + mrb_assert(0); + return 0; + } +} + +static void +incremental_gc_until(mrb_state *mrb, mrb_gc *gc, mrb_gc_state to_state) +{ + do { + incremental_gc(mrb, gc, SIZE_MAX); + } while (gc->state != to_state); +} + +static void +incremental_gc_step(mrb_state *mrb, mrb_gc *gc) +{ + size_t limit = 0, result = 0; + limit = (GC_STEP_SIZE/100) * gc->step_ratio; + while (result < limit) { + result += incremental_gc(mrb, gc, limit); + if (gc->state == MRB_GC_STATE_ROOT) + break; + } + + gc->threshold = gc->live + GC_STEP_SIZE; +} + +static void +clear_all_old(mrb_state *mrb, mrb_gc *gc) +{ + mrb_bool origin_mode = gc->generational; + + mrb_assert(is_generational(gc)); + if (is_major_gc(gc)) { + /* finish the half baked GC */ + incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); + } + + /* Sweep the dead objects, then reset all the live objects + * (including all the old objects, of course) to white. */ + gc->generational = FALSE; + prepare_incremental_sweep(mrb, gc); + incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); + gc->generational = origin_mode; + + /* The gray objects have already been painted as white */ + gc->atomic_gray_list = gc->gray_list = NULL; +} + +MRB_API void +mrb_incremental_gc(mrb_state *mrb) +{ + mrb_gc *gc = &mrb->gc; + + if (gc->disabled || gc->iterating) return; + + GC_INVOKE_TIME_REPORT("mrb_incremental_gc()"); + GC_TIME_START; + + if (is_minor_gc(gc)) { + incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); + } + else { + incremental_gc_step(mrb, gc); + } + + if (gc->state == MRB_GC_STATE_ROOT) { + mrb_assert(gc->live >= gc->live_after_mark); + gc->threshold = (gc->live_after_mark/100) * gc->interval_ratio; + if (gc->threshold < GC_STEP_SIZE) { + gc->threshold = GC_STEP_SIZE; + } + + if (is_major_gc(gc)) { + gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; + gc->full = FALSE; + } + else if (is_minor_gc(gc)) { + if (gc->live > gc->majorgc_old_threshold) { + clear_all_old(mrb, gc); + gc->full = TRUE; + } + } + } + + GC_TIME_STOP_AND_REPORT; +} + +/* Perform a full gc cycle */ +MRB_API void +mrb_full_gc(mrb_state *mrb) +{ + mrb_gc *gc = &mrb->gc; + + if (gc->disabled || gc->iterating) return; + + GC_INVOKE_TIME_REPORT("mrb_full_gc()"); + GC_TIME_START; + + if (is_generational(gc)) { + /* clear all the old objects back to young */ + clear_all_old(mrb, gc); + gc->full = TRUE; + } + else if (gc->state != MRB_GC_STATE_ROOT) { + /* finish half baked GC cycle */ + incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); + } + + incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); + gc->threshold = (gc->live_after_mark/100) * gc->interval_ratio; + + if (is_generational(gc)) { + gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; + gc->full = FALSE; + } + + GC_TIME_STOP_AND_REPORT; +} + +MRB_API void +mrb_garbage_collect(mrb_state *mrb) +{ + mrb_full_gc(mrb); +} + +/* + * Field write barrier + * Paint obj(Black) -> value(White) to obj(Black) -> value(Gray). + */ + +MRB_API void +mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value) +{ + mrb_gc *gc = &mrb->gc; + + if (!is_black(obj)) return; + if (!is_white(value)) return; + + mrb_assert(gc->state == MRB_GC_STATE_MARK || (!is_dead(gc, value) && !is_dead(gc, obj))); + mrb_assert(is_generational(gc) || gc->state != MRB_GC_STATE_ROOT); + + if (is_generational(gc) || gc->state == MRB_GC_STATE_MARK) { + add_gray_list(mrb, gc, value); + } + else { + mrb_assert(gc->state == MRB_GC_STATE_SWEEP); + paint_partial_white(gc, obj); /* for never write barriers */ + } +} + +/* + * Write barrier + * Paint obj(Black) to obj(Gray). + * + * The object that is painted gray will be traversed atomically in final + * mark phase. So you use this write barrier if it's frequency written spot. + * e.g. Set element on Array. + */ + +MRB_API void +mrb_write_barrier(mrb_state *mrb, struct RBasic *obj) +{ + mrb_gc *gc = &mrb->gc; + + if (!is_black(obj)) return; + + mrb_assert(!is_dead(gc, obj)); + mrb_assert(is_generational(gc) || gc->state != MRB_GC_STATE_ROOT); + paint_gray(obj); + obj->gcnext = gc->atomic_gray_list; + gc->atomic_gray_list = obj; +} + +/* + * call-seq: + * GC.start -> nil + * + * Initiates full garbage collection. + * + */ + +static mrb_value +gc_start(mrb_state *mrb, mrb_value obj) +{ + mrb_full_gc(mrb); + return mrb_nil_value(); +} + +/* + * call-seq: + * GC.enable -> true or false + * + * Enables garbage collection, returning <code>true</code> if garbage + * collection was previously disabled. + * + * GC.disable #=> false + * GC.enable #=> true + * GC.enable #=> false + * + */ + +static mrb_value +gc_enable(mrb_state *mrb, mrb_value obj) +{ + mrb_bool old = mrb->gc.disabled; + + mrb->gc.disabled = FALSE; + + return mrb_bool_value(old); +} + +/* + * call-seq: + * GC.disable -> true or false + * + * Disables garbage collection, returning <code>true</code> if garbage + * collection was already disabled. + * + * GC.disable #=> false + * GC.disable #=> true + * + */ + +static mrb_value +gc_disable(mrb_state *mrb, mrb_value obj) +{ + mrb_bool old = mrb->gc.disabled; + + mrb->gc.disabled = TRUE; + + return mrb_bool_value(old); +} + +/* + * call-seq: + * GC.interval_ratio -> fixnum + * + * Returns ratio of GC interval. Default value is 200(%). + * + */ + +static mrb_value +gc_interval_ratio_get(mrb_state *mrb, mrb_value obj) +{ + return mrb_fixnum_value(mrb->gc.interval_ratio); +} + +/* + * call-seq: + * GC.interval_ratio = fixnum -> nil + * + * Updates ratio of GC interval. Default value is 200(%). + * GC start as soon as after end all step of GC if you set 100(%). + * + */ + +static mrb_value +gc_interval_ratio_set(mrb_state *mrb, mrb_value obj) +{ + mrb_int ratio; + + mrb_get_args(mrb, "i", &ratio); + mrb->gc.interval_ratio = ratio; + return mrb_nil_value(); +} + +/* + * call-seq: + * GC.step_ratio -> fixnum + * + * Returns step span ratio of Incremental GC. Default value is 200(%). + * + */ + +static mrb_value +gc_step_ratio_get(mrb_state *mrb, mrb_value obj) +{ + return mrb_fixnum_value(mrb->gc.step_ratio); +} + +/* + * call-seq: + * GC.step_ratio = fixnum -> nil + * + * Updates step span ratio of Incremental GC. Default value is 200(%). + * 1 step of incrementalGC becomes long if a rate is big. + * + */ + +static mrb_value +gc_step_ratio_set(mrb_state *mrb, mrb_value obj) +{ + mrb_int ratio; + + mrb_get_args(mrb, "i", &ratio); + mrb->gc.step_ratio = ratio; + return mrb_nil_value(); +} + +static void +change_gen_gc_mode(mrb_state *mrb, mrb_gc *gc, mrb_bool enable) +{ + if (gc->disabled || gc->iterating) { + mrb_raise(mrb, E_RUNTIME_ERROR, "generational mode changed when GC disabled"); + return; + } + if (is_generational(gc) && !enable) { + clear_all_old(mrb, gc); + mrb_assert(gc->state == MRB_GC_STATE_ROOT); + gc->full = FALSE; + } + else if (!is_generational(gc) && enable) { + incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); + gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; + gc->full = FALSE; + } + gc->generational = enable; +} + +/* + * call-seq: + * GC.generational_mode -> true or false + * + * Returns generational or normal gc mode. + * + */ + +static mrb_value +gc_generational_mode_get(mrb_state *mrb, mrb_value self) +{ + return mrb_bool_value(mrb->gc.generational); +} + +/* + * call-seq: + * GC.generational_mode = true or false -> true or false + * + * Changes to generational or normal gc mode. + * + */ + +static mrb_value +gc_generational_mode_set(mrb_state *mrb, mrb_value self) +{ + mrb_bool enable; + + mrb_get_args(mrb, "b", &enable); + if (mrb->gc.generational != enable) + change_gen_gc_mode(mrb, &mrb->gc, enable); + + return mrb_bool_value(enable); +} + + +static void +gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback, void *data) +{ + mrb_heap_page* page; + + mrb_full_gc(mrb); + page = gc->heaps; + while (page != NULL) { + RVALUE *p; + int i; + + p = objects(page); + for (i=0; i < MRB_HEAP_PAGE_SIZE; i++) { + if ((*callback)(mrb, &p[i].as.basic, data) == MRB_EACH_OBJ_BREAK) + return; + } + page = page->next; + } +} + +void +mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data) +{ + mrb_bool iterating = mrb->gc.iterating; + + mrb->gc.iterating = TRUE; + if (iterating) { + gc_each_objects(mrb, &mrb->gc, callback, data); + } + else { + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + gc_each_objects(mrb, &mrb->gc, callback, data); + mrb->jmp = prev_jmp; + mrb->gc.iterating = iterating; + } MRB_CATCH(&c_jmp) { + mrb->gc.iterating = iterating; + mrb->jmp = prev_jmp; + MRB_THROW(prev_jmp); + } MRB_END_EXC(&c_jmp); + } +} + +#ifdef GC_TEST +#ifdef GC_DEBUG +static mrb_value gc_test(mrb_state *, mrb_value); +#endif +#endif + +void +mrb_init_gc(mrb_state *mrb) +{ + struct RClass *gc; + + gc = mrb_define_module(mrb, "GC"); + + mrb_define_class_method(mrb, gc, "start", gc_start, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, gc, "enable", gc_enable, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, gc, "disable", gc_disable, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, gc, "interval_ratio", gc_interval_ratio_get, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, gc, "interval_ratio=", gc_interval_ratio_set, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, gc, "step_ratio", gc_step_ratio_get, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, gc, "step_ratio=", gc_step_ratio_set, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, gc, "generational_mode=", gc_generational_mode_set, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, gc, "generational_mode", gc_generational_mode_get, MRB_ARGS_NONE()); +#ifdef GC_TEST +#ifdef GC_DEBUG + mrb_define_class_method(mrb, gc, "test", gc_test, MRB_ARGS_NONE()); +#endif +#endif +} + +#ifdef GC_TEST +#ifdef GC_DEBUG +void +test_mrb_field_write_barrier(void) +{ + mrb_state *mrb = mrb_open(); + struct RBasic *obj, *value; + mrb_gc *gc = &mrb->gc; + + puts("test_mrb_field_write_barrier"); + gc->generational = FALSE; + obj = mrb_basic_ptr(mrb_ary_new(mrb)); + value = mrb_basic_ptr(mrb_str_new_lit(mrb, "value")); + paint_black(obj); + paint_partial_white(gc, value); + + + puts(" in MRB_GC_STATE_MARK"); + gc->state = MRB_GC_STATE_MARK; + mrb_field_write_barrier(mrb, obj, value); + + mrb_assert(is_gray(value)); + + + puts(" in MRB_GC_STATE_SWEEP"); + paint_partial_white(gc, value); + gc->state = MRB_GC_STATE_SWEEP; + mrb_field_write_barrier(mrb, obj, value); + + mrb_assert(obj->color & gc->current_white_part); + mrb_assert(value->color & gc->current_white_part); + + + puts(" fail with black"); + gc->state = MRB_GC_STATE_MARK; + paint_white(obj); + paint_partial_white(gc, value); + mrb_field_write_barrier(mrb, obj, value); + + mrb_assert(obj->color & gc->current_white_part); + + + puts(" fail with gray"); + gc->state = MRB_GC_STATE_MARK; + paint_black(obj); + paint_gray(value); + mrb_field_write_barrier(mrb, obj, value); + + mrb_assert(is_gray(value)); + + + { + puts("test_mrb_field_write_barrier_value"); + obj = mrb_basic_ptr(mrb_ary_new(mrb)); + mrb_value value = mrb_str_new_lit(mrb, "value"); + paint_black(obj); + paint_partial_white(gc, mrb_basic_ptr(value)); + + gc->state = MRB_GC_STATE_MARK; + mrb_field_write_barrier_value(mrb, obj, value); + + mrb_assert(is_gray(mrb_basic_ptr(value))); + } + + mrb_close(mrb); +} + +void +test_mrb_write_barrier(void) +{ + mrb_state *mrb = mrb_open(); + struct RBasic *obj; + mrb_gc *gc = &mrb->gc; + + puts("test_mrb_write_barrier"); + obj = mrb_basic_ptr(mrb_ary_new(mrb)); + paint_black(obj); + + puts(" in MRB_GC_STATE_MARK"); + gc->state = MRB_GC_STATE_MARK; + mrb_write_barrier(mrb, obj); + + mrb_assert(is_gray(obj)); + mrb_assert(gc->atomic_gray_list == obj); + + + puts(" fail with gray"); + paint_gray(obj); + mrb_write_barrier(mrb, obj); + + mrb_assert(is_gray(obj)); + + mrb_close(mrb); +} + +void +test_add_gray_list(void) +{ + mrb_state *mrb = mrb_open(); + struct RBasic *obj1, *obj2; + mrb_gc *gc = &mrb->gc; + + puts("test_add_gray_list"); + change_gen_gc_mode(mrb, gc, FALSE); + mrb_assert(gc->gray_list == NULL); + obj1 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test")); + add_gray_list(mrb, gc, obj1); + mrb_assert(gc->gray_list == obj1); + mrb_assert(is_gray(obj1)); + + obj2 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test")); + add_gray_list(mrb, gc, obj2); + mrb_assert(gc->gray_list == obj2); + mrb_assert(gc->gray_list->gcnext == obj1); + mrb_assert(is_gray(obj2)); + + mrb_close(mrb); +} + +void +test_gc_gray_mark(void) +{ + mrb_state *mrb = mrb_open(); + mrb_value obj_v, value_v; + struct RBasic *obj; + size_t gray_num = 0; + mrb_gc *gc = &mrb->gc; + + puts("test_gc_gray_mark"); + + puts(" in MRB_TT_CLASS"); + obj = (struct RBasic*)mrb->object_class; + paint_gray(obj); + gray_num = gc_gray_mark(mrb, gc, obj); + mrb_assert(is_black(obj)); + mrb_assert(gray_num > 1); + + puts(" in MRB_TT_ARRAY"); + obj_v = mrb_ary_new(mrb); + value_v = mrb_str_new_lit(mrb, "test"); + paint_gray(mrb_basic_ptr(obj_v)); + paint_partial_white(gc, mrb_basic_ptr(value_v)); + mrb_ary_push(mrb, obj_v, value_v); + gray_num = gc_gray_mark(mrb, gc, mrb_basic_ptr(obj_v)); + mrb_assert(is_black(mrb_basic_ptr(obj_v))); + mrb_assert(is_gray(mrb_basic_ptr(value_v))); + mrb_assert(gray_num == 1); + + mrb_close(mrb); +} + +void +test_incremental_gc(void) +{ + mrb_state *mrb = mrb_open(); + size_t max = ~0, live = 0, total = 0, freed = 0; + RVALUE *free; + mrb_heap_page *page; + mrb_gc *gc = &mrb->gc; + + puts("test_incremental_gc"); + change_gen_gc_mode(mrb, gc, FALSE); + + puts(" in mrb_full_gc"); + mrb_full_gc(mrb); + + mrb_assert(gc->state == MRB_GC_STATE_ROOT); + puts(" in MRB_GC_STATE_ROOT"); + incremental_gc(mrb, gc, max); + mrb_assert(gc->state == MRB_GC_STATE_MARK); + puts(" in MRB_GC_STATE_MARK"); + incremental_gc_until(mrb, gc, MRB_GC_STATE_SWEEP); + mrb_assert(gc->state == MRB_GC_STATE_SWEEP); + + puts(" in MRB_GC_STATE_SWEEP"); + page = gc->heaps; + while (page) { + RVALUE *p = objects(page); + RVALUE *e = p + MRB_HEAP_PAGE_SIZE; + while (p<e) { + if (is_black(&p->as.basic)) { + live++; + } + if (is_gray(&p->as.basic) && !is_dead(gc, &p->as.basic)) { + printf("%p\n", &p->as.basic); + } + p++; + } + page = page->next; + total += MRB_HEAP_PAGE_SIZE; + } + + mrb_assert(gc->gray_list == NULL); + + incremental_gc(mrb, gc, max); + mrb_assert(gc->state == MRB_GC_STATE_SWEEP); + + incremental_gc(mrb, gc, max); + mrb_assert(gc->state == MRB_GC_STATE_ROOT); + + free = (RVALUE*)gc->heaps->freelist; + while (free) { + freed++; + free = (RVALUE*)free->as.free.next; + } + + mrb_assert(gc->live == live); + mrb_assert(gc->live == total-freed); + + puts("test_incremental_gc(gen)"); + incremental_gc_until(mrb, gc, MRB_GC_STATE_SWEEP); + change_gen_gc_mode(mrb, gc, TRUE); + + mrb_assert(gc->full == FALSE); + mrb_assert(gc->state == MRB_GC_STATE_ROOT); + + puts(" in minor"); + mrb_assert(is_minor_gc(gc)); + mrb_assert(gc->majorgc_old_threshold > 0); + gc->majorgc_old_threshold = 0; + mrb_incremental_gc(mrb); + mrb_assert(gc->full == TRUE); + mrb_assert(gc->state == MRB_GC_STATE_ROOT); + + puts(" in major"); + mrb_assert(is_major_gc(gc)); + do { + mrb_incremental_gc(mrb); + } while (gc->state != MRB_GC_STATE_ROOT); + mrb_assert(gc->full == FALSE); + + mrb_close(mrb); +} + +void +test_incremental_sweep_phase(void) +{ + mrb_state *mrb = mrb_open(); + mrb_gc *gc = &mrb->gc; + + puts("test_incremental_sweep_phase"); + + add_heap(mrb, gc); + gc->sweeps = gc->heaps; + + mrb_assert(gc->heaps->next->next == NULL); + mrb_assert(gc->free_heaps->next->next == NULL); + incremental_sweep_phase(mrb, gc, MRB_HEAP_PAGE_SIZE * 3); + + mrb_assert(gc->heaps->next == NULL); + mrb_assert(gc->heaps == gc->free_heaps); + + mrb_close(mrb); +} + +static mrb_value +gc_test(mrb_state *mrb, mrb_value self) +{ + test_mrb_field_write_barrier(); + test_mrb_write_barrier(); + test_add_gray_list(); + test_gc_gray_mark(); + test_incremental_gc(); + test_incremental_sweep_phase(); + return mrb_nil_value(); +} +#endif /* GC_DEBUG */ +#endif /* GC_TEST */ diff --git a/web/server/h2o/libh2o/deps/mruby/src/hash.c b/web/server/h2o/libh2o/deps/mruby/src/hash.c new file mode 100644 index 000000000..93d550187 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/hash.c @@ -0,0 +1,905 @@ +/* +** hash.c - Hash class +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/hash.h> +#include <mruby/khash.h> +#include <mruby/string.h> +#include <mruby/variable.h> + +/* a function to get hash value of a float number */ +mrb_int mrb_float_id(mrb_float f); + +static inline khint_t +mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key) +{ + enum mrb_vtype t = mrb_type(key); + mrb_value hv; + khint_t h; + + switch (t) { + case MRB_TT_STRING: + h = mrb_str_hash(mrb, key); + break; + + case MRB_TT_TRUE: + case MRB_TT_FALSE: + case MRB_TT_SYMBOL: + case MRB_TT_FIXNUM: + case MRB_TT_FLOAT: + h = (khint_t)mrb_obj_id(key); + break; + + default: + hv = mrb_funcall(mrb, key, "hash", 0); + h = (khint_t)t ^ mrb_fixnum(hv); + break; + } + return kh_int_hash_func(mrb, h); +} + +static inline khint_t +mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) +{ + enum mrb_vtype t = mrb_type(a); + + switch (t) { + case MRB_TT_STRING: + return mrb_str_equal(mrb, a, b); + + case MRB_TT_SYMBOL: + if (mrb_type(b) != MRB_TT_SYMBOL) return FALSE; + return mrb_symbol(a) == mrb_symbol(b); + + case MRB_TT_FIXNUM: + switch (mrb_type(b)) { + case MRB_TT_FIXNUM: + return mrb_fixnum(a) == mrb_fixnum(b); + case MRB_TT_FLOAT: + return (mrb_float)mrb_fixnum(a) == mrb_float(b); + default: + return FALSE; + } + + case MRB_TT_FLOAT: + switch (mrb_type(b)) { + case MRB_TT_FIXNUM: + return mrb_float(a) == (mrb_float)mrb_fixnum(b); + case MRB_TT_FLOAT: + return mrb_float(a) == mrb_float(b); + default: + return FALSE; + } + + default: + return mrb_eql(mrb, a, b); + } +} + +KHASH_DEFINE (ht, mrb_value, mrb_hash_value, TRUE, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal) + +static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); + +static inline mrb_value +mrb_hash_ht_key(mrb_state *mrb, mrb_value key) +{ + if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) { + key = mrb_str_dup(mrb, key); + MRB_SET_FROZEN_FLAG(mrb_str_ptr(key)); + } + return key; +} + +#define KEY(key) mrb_hash_ht_key(mrb, key) + +void +mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash) +{ + khiter_t k; + khash_t(ht) *h = hash->ht; + + if (!h) return; + for (k = kh_begin(h); k != kh_end(h); k++) { + if (kh_exist(h, k)) { + mrb_value key = kh_key(h, k); + mrb_value val = kh_value(h, k).v; + + mrb_gc_mark_value(mrb, key); + mrb_gc_mark_value(mrb, val); + } + } +} + +size_t +mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash) +{ + if (!hash->ht) return 0; + return kh_size(hash->ht)*2; +} + +void +mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash) +{ + if (hash->ht) kh_destroy(ht, mrb, hash->ht); +} + + +MRB_API mrb_value +mrb_hash_new_capa(mrb_state *mrb, mrb_int capa) +{ + struct RHash *h; + + h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); + /* khash needs 1/4 empty space so it is not resized immediately */ + h->ht = kh_init_size(ht, mrb, capa*4/3); + h->iv = 0; + return mrb_obj_value(h); +} + +MRB_API mrb_value +mrb_hash_new(mrb_state *mrb) +{ + return mrb_hash_new_capa(mrb, 0); +} + +static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash); +static mrb_value hash_default(mrb_state *mrb, mrb_value hash, mrb_value key); + +MRB_API mrb_value +mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) +{ + khash_t(ht) *h = RHASH_TBL(hash); + khiter_t k; + mrb_sym mid; + + if (h) { + k = kh_get(ht, mrb, h, key); + if (k != kh_end(h)) + return kh_value(h, k).v; + } + + mid = mrb_intern_lit(mrb, "default"); + if (mrb_func_basic_p(mrb, hash, mid, mrb_hash_default)) { + return hash_default(mrb, hash, key); + } + /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */ + return mrb_funcall_argv(mrb, hash, mid, 1, &key); +} + +MRB_API mrb_value +mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) +{ + khash_t(ht) *h = RHASH_TBL(hash); + khiter_t k; + + if (h) { + k = kh_get(ht, mrb, h, key); + if (k != kh_end(h)) + return kh_value(h, k).v; + } + + /* not found */ + return def; +} + +MRB_API void +mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) +{ + khash_t(ht) *h; + khiter_t k; + int r; + + mrb_hash_modify(mrb, hash); + h = RHASH_TBL(hash); + + if (!h) h = RHASH_TBL(hash) = kh_init(ht, mrb); + k = kh_put2(ht, mrb, h, key, &r); + kh_value(h, k).v = val; + + if (r != 0) { + /* expand */ + int ai = mrb_gc_arena_save(mrb); + key = kh_key(h, k) = KEY(key); + mrb_gc_arena_restore(mrb, ai); + kh_value(h, k).n = kh_size(h)-1; + } + + mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key); + mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val); + return; +} + +static mrb_value +mrb_hash_dup(mrb_state *mrb, mrb_value hash) +{ + struct RHash* ret; + khash_t(ht) *h, *ret_h; + khiter_t k, ret_k; + mrb_value ifnone, vret; + + h = RHASH_TBL(hash); + ret = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); + ret->ht = kh_init(ht, mrb); + + if (h && kh_size(h) > 0) { + ret_h = ret->ht; + + for (k = kh_begin(h); k != kh_end(h); k++) { + if (kh_exist(h, k)) { + int ai = mrb_gc_arena_save(mrb); + ret_k = kh_put(ht, mrb, ret_h, KEY(kh_key(h, k))); + mrb_gc_arena_restore(mrb, ai); + kh_val(ret_h, ret_k).v = kh_val(h, k).v; + kh_val(ret_h, ret_k).n = kh_size(ret_h)-1; + } + } + } + + if (MRB_RHASH_DEFAULT_P(hash)) { + ret->flags |= MRB_HASH_DEFAULT; + } + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + ret->flags |= MRB_HASH_PROC_DEFAULT; + } + vret = mrb_obj_value(ret); + ifnone = RHASH_IFNONE(hash); + if (!mrb_nil_p(ifnone)) { + mrb_iv_set(mrb, vret, mrb_intern_lit(mrb, "ifnone"), ifnone); + } + return vret; +} + +MRB_API mrb_value +mrb_check_hash_type(mrb_state *mrb, mrb_value hash) +{ + return mrb_check_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); +} + +MRB_API khash_t(ht)* +mrb_hash_tbl(mrb_state *mrb, mrb_value hash) +{ + khash_t(ht) *h = RHASH_TBL(hash); + + if (!h) { + return RHASH_TBL(hash) = kh_init(ht, mrb); + } + return h; +} + +static void +mrb_hash_modify(mrb_state *mrb, mrb_value hash) +{ + if (MRB_FROZEN_P(mrb_hash_ptr(hash))) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen hash"); + } + mrb_hash_tbl(mrb, hash); +} + +/* 15.2.13.4.16 */ +/* + * call-seq: + * Hash.new -> new_hash + * Hash.new(obj) -> new_hash + * Hash.new {|hash, key| block } -> new_hash + * + * Returns a new, empty hash. If this hash is subsequently accessed by + * a key that doesn't correspond to a hash entry, the value returned + * depends on the style of <code>new</code> used to create the hash. In + * the first form, the access returns <code>nil</code>. If + * <i>obj</i> is specified, this single object will be used for + * all <em>default values</em>. If a block is specified, it will be + * called with the hash object and the key, and should return the + * default value. It is the block's responsibility to store the value + * in the hash if required. + * + * h = Hash.new("Go Fish") + * h["a"] = 100 + * h["b"] = 200 + * h["a"] #=> 100 + * h["c"] #=> "Go Fish" + * # The following alters the single default object + * h["c"].upcase! #=> "GO FISH" + * h["d"] #=> "GO FISH" + * h.keys #=> ["a", "b"] + * + * # While this creates a new default object each time + * h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" } + * h["c"] #=> "Go Fish: c" + * h["c"].upcase! #=> "GO FISH: C" + * h["d"] #=> "Go Fish: d" + * h.keys #=> ["c", "d"] + * + */ + +static mrb_value +mrb_hash_init(mrb_state *mrb, mrb_value hash) +{ + mrb_value block, ifnone; + mrb_bool ifnone_p; + + ifnone = mrb_nil_value(); + mrb_get_args(mrb, "&|o?", &block, &ifnone, &ifnone_p); + mrb_hash_modify(mrb, hash); + if (!mrb_nil_p(block)) { + if (ifnone_p) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); + } + RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT; + ifnone = block; + } + if (!mrb_nil_p(ifnone)) { + RHASH(hash)->flags |= MRB_HASH_DEFAULT; + mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone); + } + return hash; +} + +/* 15.2.13.4.2 */ +/* + * call-seq: + * hsh[key] -> value + * + * Element Reference---Retrieves the <i>value</i> object corresponding + * to the <i>key</i> object. If not found, returns the default value (see + * <code>Hash::new</code> for details). + * + * h = { "a" => 100, "b" => 200 } + * h["a"] #=> 100 + * h["c"] #=> nil + * + */ +static mrb_value +mrb_hash_aget(mrb_state *mrb, mrb_value self) +{ + mrb_value key; + + mrb_get_args(mrb, "o", &key); + return mrb_hash_get(mrb, self, key); +} + +static mrb_value +hash_default(mrb_state *mrb, mrb_value hash, mrb_value key) +{ + if (MRB_RHASH_DEFAULT_P(hash)) { + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); + } + else { + return RHASH_IFNONE(hash); + } + } + return mrb_nil_value(); +} + +/* 15.2.13.4.5 */ +/* + * call-seq: + * hsh.default(key=nil) -> obj + * + * Returns the default value, the value that would be returned by + * <i>hsh</i>[<i>key</i>] if <i>key</i> did not exist in <i>hsh</i>. + * See also <code>Hash::new</code> and <code>Hash#default=</code>. + * + * h = Hash.new #=> {} + * h.default #=> nil + * h.default(2) #=> nil + * + * h = Hash.new("cat") #=> {} + * h.default #=> "cat" + * h.default(2) #=> "cat" + * + * h = Hash.new {|h,k| h[k] = k.to_i*10} #=> {} + * h.default #=> nil + * h.default(2) #=> 20 + */ + +static mrb_value +mrb_hash_default(mrb_state *mrb, mrb_value hash) +{ + mrb_value key; + mrb_bool given; + + mrb_get_args(mrb, "|o?", &key, &given); + if (MRB_RHASH_DEFAULT_P(hash)) { + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + if (!given) return mrb_nil_value(); + return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); + } + else { + return RHASH_IFNONE(hash); + } + } + return mrb_nil_value(); +} + +/* 15.2.13.4.6 */ +/* + * call-seq: + * hsh.default = obj -> obj + * + * Sets the default value, the value returned for a key that does not + * exist in the hash. It is not possible to set the default to a + * <code>Proc</code> that will be executed on each key lookup. + * + * h = { "a" => 100, "b" => 200 } + * h.default = "Go fish" + * h["a"] #=> 100 + * h["z"] #=> "Go fish" + * # This doesn't do what you might hope... + * h.default = proc do |hash, key| + * hash[key] = key + key + * end + * h[2] #=> #<Proc:0x401b3948@-:6> + * h["cat"] #=> #<Proc:0x401b3948@-:6> + */ + +static mrb_value +mrb_hash_set_default(mrb_state *mrb, mrb_value hash) +{ + mrb_value ifnone; + + mrb_get_args(mrb, "o", &ifnone); + mrb_hash_modify(mrb, hash); + mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone); + RHASH(hash)->flags &= ~MRB_HASH_PROC_DEFAULT; + if (!mrb_nil_p(ifnone)) { + RHASH(hash)->flags |= MRB_HASH_DEFAULT; + } + else { + RHASH(hash)->flags &= ~MRB_HASH_DEFAULT; + } + return ifnone; +} + +/* 15.2.13.4.7 */ +/* + * call-seq: + * hsh.default_proc -> anObject + * + * If <code>Hash::new</code> was invoked with a block, return that + * block, otherwise return <code>nil</code>. + * + * h = Hash.new {|h,k| h[k] = k*k } #=> {} + * p = h.default_proc #=> #<Proc:0x401b3d08@-:1> + * a = [] #=> [] + * p.call(a, 2) + * a #=> [nil, nil, 4] + */ + + +static mrb_value +mrb_hash_default_proc(mrb_state *mrb, mrb_value hash) +{ + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + return RHASH_PROCDEFAULT(hash); + } + return mrb_nil_value(); +} + +/* + * call-seq: + * hsh.default_proc = proc_obj -> proc_obj + * + * Sets the default proc to be executed on each key lookup. + * + * h.default_proc = proc do |hash, key| + * hash[key] = key + key + * end + * h[2] #=> 4 + * h["cat"] #=> "catcat" + */ + +static mrb_value +mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash) +{ + mrb_value ifnone; + + mrb_get_args(mrb, "o", &ifnone); + mrb_hash_modify(mrb, hash); + mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone); + if (!mrb_nil_p(ifnone)) { + RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT; + RHASH(hash)->flags |= MRB_HASH_DEFAULT; + } + else { + RHASH(hash)->flags &= ~MRB_HASH_DEFAULT; + RHASH(hash)->flags &= ~MRB_HASH_PROC_DEFAULT; + } + + return ifnone; +} + +MRB_API mrb_value +mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key) +{ + khash_t(ht) *h = RHASH_TBL(hash); + khiter_t k; + mrb_value delVal; + mrb_int n; + + if (h) { + k = kh_get(ht, mrb, h, key); + if (k != kh_end(h)) { + delVal = kh_value(h, k).v; + n = kh_value(h, k).n; + kh_del(ht, mrb, h, k); + for (k = kh_begin(h); k != kh_end(h); k++) { + if (!kh_exist(h, k)) continue; + if (kh_value(h, k).n > n) kh_value(h, k).n--; + } + return delVal; + } + } + + /* not found */ + return mrb_nil_value(); +} + +/* 15.2.13.4.8 */ +/* + * call-seq: + * hsh.delete(key) -> value + * hsh.delete(key) {| key | block } -> value + * + * Deletes and returns a key-value pair from <i>hsh</i> whose key is + * equal to <i>key</i>. If the key is not found, returns the + * <em>default value</em>. If the optional code block is given and the + * key is not found, pass in the key and return the result of + * <i>block</i>. + * + * h = { "a" => 100, "b" => 200 } + * h.delete("a") #=> 100 + * h.delete("z") #=> nil + * h.delete("z") { |el| "#{el} not found" } #=> "z not found" + * + */ +static mrb_value +mrb_hash_delete(mrb_state *mrb, mrb_value self) +{ + mrb_value key; + + mrb_get_args(mrb, "o", &key); + mrb_hash_modify(mrb, self); + return mrb_hash_delete_key(mrb, self, key); +} + +/* 15.2.13.4.24 */ +/* + * call-seq: + * hsh.shift -> anArray or obj + * + * Removes a key-value pair from <i>hsh</i> and returns it as the + * two-item array <code>[</code> <i>key, value</i> <code>]</code>, or + * the hash's default value if the hash is empty. + * + * h = { 1 => "a", 2 => "b", 3 => "c" } + * h.shift #=> [1, "a"] + * h #=> {2=>"b", 3=>"c"} + */ + +static mrb_value +mrb_hash_shift(mrb_state *mrb, mrb_value hash) +{ + khash_t(ht) *h = RHASH_TBL(hash); + khiter_t k; + mrb_value delKey, delVal; + + mrb_hash_modify(mrb, hash); + if (h && kh_size(h) > 0) { + for (k = kh_begin(h); k != kh_end(h); k++) { + if (!kh_exist(h, k)) continue; + + delKey = kh_key(h, k); + mrb_gc_protect(mrb, delKey); + delVal = mrb_hash_delete_key(mrb, hash, delKey); + mrb_gc_protect(mrb, delVal); + + return mrb_assoc_new(mrb, delKey, delVal); + } + } + + if (MRB_RHASH_DEFAULT_P(hash)) { + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, mrb_nil_value()); + } + else { + return RHASH_IFNONE(hash); + } + } + return mrb_nil_value(); +} + +/* 15.2.13.4.4 */ +/* + * call-seq: + * hsh.clear -> hsh + * + * Removes all key-value pairs from `hsh`. + * + * h = { "a" => 100, "b" => 200 } #=> {"a"=>100, "b"=>200} + * h.clear #=> {} + * + */ + +MRB_API mrb_value +mrb_hash_clear(mrb_state *mrb, mrb_value hash) +{ + khash_t(ht) *h = RHASH_TBL(hash); + + mrb_hash_modify(mrb, hash); + if (h) kh_clear(ht, mrb, h); + return hash; +} + +/* 15.2.13.4.3 */ +/* 15.2.13.4.26 */ +/* + * call-seq: + * hsh[key] = value -> value + * hsh.store(key, value) -> value + * + * Element Assignment---Associates the value given by + * <i>value</i> with the key given by <i>key</i>. + * <i>key</i> should not have its value changed while it is in + * use as a key (a <code>String</code> passed as a key will be + * duplicated and frozen). + * + * h = { "a" => 100, "b" => 200 } + * h["a"] = 9 + * h["c"] = 4 + * h #=> {"a"=>9, "b"=>200, "c"=>4} + * + */ +static mrb_value +mrb_hash_aset(mrb_state *mrb, mrb_value self) +{ + mrb_value key, val; + + mrb_get_args(mrb, "oo", &key, &val); + mrb_hash_set(mrb, self, key, val); + return val; +} + +/* 15.2.13.4.20 */ +/* 15.2.13.4.25 */ +/* + * call-seq: + * hsh.length -> fixnum + * hsh.size -> fixnum + * + * Returns the number of key-value pairs in the hash. + * + * h = { "d" => 100, "a" => 200, "v" => 300, "e" => 400 } + * h.length #=> 4 + * h.delete("a") #=> 200 + * h.length #=> 3 + */ +static mrb_value +mrb_hash_size_m(mrb_state *mrb, mrb_value self) +{ + khash_t(ht) *h = RHASH_TBL(self); + + if (!h) return mrb_fixnum_value(0); + return mrb_fixnum_value(kh_size(h)); +} + +/* 15.2.13.4.12 */ +/* + * call-seq: + * hsh.empty? -> true or false + * + * Returns <code>true</code> if <i>hsh</i> contains no key-value pairs. + * + * {}.empty? #=> true + * + */ +MRB_API mrb_value +mrb_hash_empty_p(mrb_state *mrb, mrb_value self) +{ + khash_t(ht) *h = RHASH_TBL(self); + + if (h) return mrb_bool_value(kh_size(h) == 0); + return mrb_true_value(); +} + +/* 15.2.13.4.29 (x)*/ +/* + * call-seq: + * hsh.to_hash => hsh + * + * Returns +self+. + */ + +static mrb_value +mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) +{ + return hash; +} + +/* 15.2.13.4.19 */ +/* + * call-seq: + * hsh.keys -> array + * + * Returns a new array populated with the keys from this hash. See also + * <code>Hash#values</code>. + * + * h = { "a" => 100, "b" => 200, "c" => 300, "d" => 400 } + * h.keys #=> ["a", "b", "c", "d"] + * + */ + +MRB_API mrb_value +mrb_hash_keys(mrb_state *mrb, mrb_value hash) +{ + khash_t(ht) *h = RHASH_TBL(hash); + khiter_t k; + mrb_int end; + mrb_value ary; + mrb_value *p; + + if (!h || kh_size(h) == 0) return mrb_ary_new(mrb); + ary = mrb_ary_new_capa(mrb, kh_size(h)); + end = kh_size(h)-1; + mrb_ary_set(mrb, ary, end, mrb_nil_value()); + p = RARRAY_PTR(ary); + for (k = kh_begin(h); k != kh_end(h); k++) { + if (kh_exist(h, k)) { + mrb_value kv = kh_key(h, k); + mrb_hash_value hv = kh_value(h, k); + + if (hv.n <= end) { + p[hv.n] = kv; + } + else { + p[end] = kv; + } + } + } + return ary; +} + +/* 15.2.13.4.28 */ +/* + * call-seq: + * hsh.values -> array + * + * Returns a new array populated with the values from <i>hsh</i>. See + * also <code>Hash#keys</code>. + * + * h = { "a" => 100, "b" => 200, "c" => 300 } + * h.values #=> [100, 200, 300] + * + */ + +MRB_API mrb_value +mrb_hash_values(mrb_state *mrb, mrb_value hash) +{ + khash_t(ht) *h = RHASH_TBL(hash); + khiter_t k; + mrb_value ary; + + if (!h) return mrb_ary_new(mrb); + ary = mrb_ary_new_capa(mrb, kh_size(h)); + for (k = kh_begin(h); k != kh_end(h); k++) { + if (kh_exist(h, k)) { + mrb_hash_value hv = kh_value(h, k); + + mrb_ary_set(mrb, ary, hv.n, hv.v); + } + } + return ary; +} + +/* 15.2.13.4.13 */ +/* 15.2.13.4.15 */ +/* 15.2.13.4.18 */ +/* 15.2.13.4.21 */ +/* + * call-seq: + * hsh.has_key?(key) -> true or false + * hsh.include?(key) -> true or false + * hsh.key?(key) -> true or false + * hsh.member?(key) -> true or false + * + * Returns <code>true</code> if the given key is present in <i>hsh</i>. + * + * h = { "a" => 100, "b" => 200 } + * h.has_key?("a") #=> true + * h.has_key?("z") #=> false + * + */ + +static mrb_value +mrb_hash_has_key(mrb_state *mrb, mrb_value hash) +{ + mrb_value key; + khash_t(ht) *h; + khiter_t k; + + mrb_get_args(mrb, "o", &key); + + h = RHASH_TBL(hash); + if (h) { + k = kh_get(ht, mrb, h, key); + return mrb_bool_value(k != kh_end(h)); + } + return mrb_false_value(); +} + +/* 15.2.13.4.14 */ +/* 15.2.13.4.27 */ +/* + * call-seq: + * hsh.has_value?(value) -> true or false + * hsh.value?(value) -> true or false + * + * Returns <code>true</code> if the given value is present for some key + * in <i>hsh</i>. + * + * h = { "a" => 100, "b" => 200 } + * h.has_value?(100) #=> true + * h.has_value?(999) #=> false + */ + +static mrb_value +mrb_hash_has_value(mrb_state *mrb, mrb_value hash) +{ + mrb_value val; + khash_t(ht) *h; + khiter_t k; + + mrb_get_args(mrb, "o", &val); + h = RHASH_TBL(hash); + + if (h) { + for (k = kh_begin(h); k != kh_end(h); k++) { + if (!kh_exist(h, k)) continue; + + if (mrb_equal(mrb, kh_value(h, k).v, val)) { + return mrb_true_value(); + } + } + } + return mrb_false_value(); +} + +void +mrb_init_hash(mrb_state *mrb) +{ + struct RClass *h; + + mrb->hash_class = h = mrb_define_class(mrb, "Hash", mrb->object_class); /* 15.2.13 */ + MRB_SET_INSTANCE_TT(h, MRB_TT_HASH); + + mrb_define_method(mrb, h, "[]", mrb_hash_aget, MRB_ARGS_REQ(1)); /* 15.2.13.4.2 */ + mrb_define_method(mrb, h, "[]=", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.3 */ + mrb_define_method(mrb, h, "clear", mrb_hash_clear, MRB_ARGS_NONE()); /* 15.2.13.4.4 */ + mrb_define_method(mrb, h, "default", mrb_hash_default, MRB_ARGS_ANY()); /* 15.2.13.4.5 */ + mrb_define_method(mrb, h, "default=", mrb_hash_set_default, MRB_ARGS_REQ(1)); /* 15.2.13.4.6 */ + mrb_define_method(mrb, h, "default_proc", mrb_hash_default_proc,MRB_ARGS_NONE()); /* 15.2.13.4.7 */ + mrb_define_method(mrb, h, "default_proc=", mrb_hash_set_default_proc,MRB_ARGS_REQ(1)); /* 15.2.13.4.7 */ + mrb_define_method(mrb, h, "__delete", mrb_hash_delete, MRB_ARGS_REQ(1)); /* core of 15.2.13.4.8 */ + mrb_define_method(mrb, h, "empty?", mrb_hash_empty_p, MRB_ARGS_NONE()); /* 15.2.13.4.12 */ + mrb_define_method(mrb, h, "has_key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.13 */ + mrb_define_method(mrb, h, "has_value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.14 */ + mrb_define_method(mrb, h, "include?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.15 */ + mrb_define_method(mrb, h, "initialize", mrb_hash_init, MRB_ARGS_OPT(1)); /* 15.2.13.4.16 */ + mrb_define_method(mrb, h, "key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.18 */ + mrb_define_method(mrb, h, "keys", mrb_hash_keys, MRB_ARGS_NONE()); /* 15.2.13.4.19 */ + mrb_define_method(mrb, h, "length", mrb_hash_size_m, MRB_ARGS_NONE()); /* 15.2.13.4.20 */ + mrb_define_method(mrb, h, "member?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.21 */ + mrb_define_method(mrb, h, "shift", mrb_hash_shift, MRB_ARGS_NONE()); /* 15.2.13.4.24 */ + mrb_define_method(mrb, h, "dup", mrb_hash_dup, MRB_ARGS_NONE()); + mrb_define_method(mrb, h, "size", mrb_hash_size_m, MRB_ARGS_NONE()); /* 15.2.13.4.25 */ + mrb_define_method(mrb, h, "store", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.26 */ + mrb_define_method(mrb, h, "value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.27 */ + mrb_define_method(mrb, h, "values", mrb_hash_values, MRB_ARGS_NONE()); /* 15.2.13.4.28 */ + + mrb_define_method(mrb, h, "to_hash", mrb_hash_to_hash, MRB_ARGS_NONE()); /* 15.2.13.4.29 (x)*/ +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/init.c b/web/server/h2o/libh2o/deps/mruby/src/init.c new file mode 100644 index 000000000..afd69975a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/init.c @@ -0,0 +1,51 @@ +/* +** init.c - initialize mruby core +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> + +void mrb_init_symtbl(mrb_state*); +void mrb_init_class(mrb_state*); +void mrb_init_object(mrb_state*); +void mrb_init_kernel(mrb_state*); +void mrb_init_comparable(mrb_state*); +void mrb_init_enumerable(mrb_state*); +void mrb_init_symbol(mrb_state*); +void mrb_init_string(mrb_state*); +void mrb_init_exception(mrb_state*); +void mrb_init_proc(mrb_state*); +void mrb_init_array(mrb_state*); +void mrb_init_hash(mrb_state*); +void mrb_init_numeric(mrb_state*); +void mrb_init_range(mrb_state*); +void mrb_init_gc(mrb_state*); +void mrb_init_math(mrb_state*); +void mrb_init_version(mrb_state*); +void mrb_init_mrblib(mrb_state*); + +#define DONE mrb_gc_arena_restore(mrb, 0); +void +mrb_init_core(mrb_state *mrb) +{ + mrb_init_symtbl(mrb); DONE; + + mrb_init_class(mrb); DONE; + mrb_init_object(mrb); DONE; + mrb_init_kernel(mrb); DONE; + mrb_init_comparable(mrb); DONE; + mrb_init_enumerable(mrb); DONE; + + mrb_init_symbol(mrb); DONE; + mrb_init_string(mrb); DONE; + mrb_init_exception(mrb); DONE; + mrb_init_proc(mrb); DONE; + mrb_init_array(mrb); DONE; + mrb_init_hash(mrb); DONE; + mrb_init_numeric(mrb); DONE; + mrb_init_range(mrb); DONE; + mrb_init_gc(mrb); DONE; + mrb_init_version(mrb); DONE; + mrb_init_mrblib(mrb); DONE; +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/kernel.c b/web/server/h2o/libh2o/deps/mruby/src/kernel.c new file mode 100644 index 000000000..4e95ab24b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/kernel.c @@ -0,0 +1,1238 @@ +/* +** kernel.c - Kernel module +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/hash.h> +#include <mruby/class.h> +#include <mruby/proc.h> +#include <mruby/string.h> +#include <mruby/variable.h> +#include <mruby/error.h> +#include <mruby/istruct.h> + +typedef enum { + NOEX_PUBLIC = 0x00, + NOEX_NOSUPER = 0x01, + NOEX_PRIVATE = 0x02, + NOEX_PROTECTED = 0x04, + NOEX_MASK = 0x06, + NOEX_BASIC = 0x08, + NOEX_UNDEF = NOEX_NOSUPER, + NOEX_MODFUNC = 0x12, + NOEX_SUPER = 0x20, + NOEX_VCALL = 0x40, + NOEX_RESPONDS = 0x80 +} mrb_method_flag_t; + +MRB_API mrb_bool +mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func) +{ + struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mid); + if (MRB_PROC_CFUNC_P(me) && (me->body.func == func)) + return TRUE; + return FALSE; +} + +static mrb_bool +mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj) +{ + return mrb_func_basic_p(mrb, obj, mrb_intern_lit(mrb, "to_s"), mrb_any_to_s); +} + +/* 15.3.1.3.17 */ +/* + * call-seq: + * obj.inspect -> string + * + * Returns a string containing a human-readable representation of + * <i>obj</i>. If not overridden and no instance variables, uses the + * <code>to_s</code> method to generate the string. + * <i>obj</i>. If not overridden, uses the <code>to_s</code> method to + * generate the string. + * + * [ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]" + * Time.new.inspect #=> "2008-03-08 19:43:39 +0900" + */ +MRB_API mrb_value +mrb_obj_inspect(mrb_state *mrb, mrb_value obj) +{ + if ((mrb_type(obj) == MRB_TT_OBJECT) && mrb_obj_basic_to_s_p(mrb, obj)) { + return mrb_obj_iv_inspect(mrb, mrb_obj_ptr(obj)); + } + return mrb_any_to_s(mrb, obj); +} + +/* 15.3.1.3.2 */ +/* + * call-seq: + * obj === other -> true or false + * + * Case Equality---For class <code>Object</code>, effectively the same + * as calling <code>#==</code>, but typically overridden by descendants + * to provide meaningful semantics in <code>case</code> statements. + */ +static mrb_value +mrb_equal_m(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + + mrb_get_args(mrb, "o", &arg); + return mrb_bool_value(mrb_equal(mrb, self, arg)); +} + +/* 15.3.1.3.3 */ +/* 15.3.1.3.33 */ +/* + * Document-method: __id__ + * Document-method: object_id + * + * call-seq: + * obj.__id__ -> fixnum + * obj.object_id -> fixnum + * + * Returns an integer identifier for <i>obj</i>. The same number will + * be returned on all calls to <code>id</code> for a given object, and + * no two active objects will share an id. + * <code>Object#object_id</code> is a different concept from the + * <code>:name</code> notation, which returns the symbol id of + * <code>name</code>. Replaces the deprecated <code>Object#id</code>. + */ +mrb_value +mrb_obj_id_m(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(mrb_obj_id(self)); +} + +/* 15.3.1.2.2 */ +/* 15.3.1.2.5 */ +/* 15.3.1.3.6 */ +/* 15.3.1.3.25 */ +/* + * call-seq: + * block_given? -> true or false + * iterator? -> true or false + * + * Returns <code>true</code> if <code>yield</code> would execute a + * block in the current context. The <code>iterator?</code> form + * is mildly deprecated. + * + * def try + * if block_given? + * yield + * else + * "no block" + * end + * end + * try #=> "no block" + * try { "hello" } #=> "hello" + * try do "hello" end #=> "hello" + */ +static mrb_value +mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) +{ + mrb_callinfo *ci = mrb->c->ci; + mrb_value *bp; + + bp = ci->stackent + 1; + ci--; + if (ci <= mrb->c->cibase) { + return mrb_false_value(); + } + /* block_given? called within block; check upper scope */ + if (ci->proc->env) { + struct REnv *e = ci->proc->env; + + while (e->c) { + e = (struct REnv*)e->c; + } + /* top-level does not have block slot (always false) */ + if (e->stack == mrb->c->stbase) + return mrb_false_value(); + if (e->stack && e->cioff < 0) { + /* use saved block arg position */ + bp = &e->stack[-e->cioff]; + ci = 0; /* no callinfo available */ + } + else { + ci = e->cxt.c->cibase + e->cioff; + bp = ci[1].stackent + 1; + } + } + if (ci && ci->argc > 0) { + bp += ci->argc; + } + if (mrb_nil_p(*bp)) + return mrb_false_value(); + return mrb_true_value(); +} + +/* 15.3.1.3.7 */ +/* + * call-seq: + * obj.class -> class + * + * Returns the class of <i>obj</i>. This method must always be + * called with an explicit receiver, as <code>class</code> is also a + * reserved word in Ruby. + * + * 1.class #=> Fixnum + * self.class #=> Object + */ +static mrb_value +mrb_obj_class_m(mrb_state *mrb, mrb_value self) +{ + return mrb_obj_value(mrb_obj_class(mrb, self)); +} + +static struct RClass* +mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj) +{ + struct RClass *klass = mrb_basic_ptr(obj)->c; + + if (klass->tt != MRB_TT_SCLASS) + return klass; + else { + /* copy singleton(unnamed) class */ + struct RClass *clone = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, mrb->class_class); + + switch (mrb_type(obj)) { + case MRB_TT_CLASS: + case MRB_TT_SCLASS: + break; + default: + clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass)); + break; + } + clone->super = klass->super; + if (klass->iv) { + mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass)); + mrb_obj_iv_set(mrb, (struct RObject*)clone, mrb_intern_lit(mrb, "__attached__"), obj); + } + if (klass->mt) { + clone->mt = kh_copy(mt, mrb, klass->mt); + } + else { + clone->mt = kh_init(mt, mrb); + } + clone->tt = MRB_TT_SCLASS; + return clone; + } +} + +static void +copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) +{ + struct RClass *dc = mrb_class_ptr(dst); + struct RClass *sc = mrb_class_ptr(src); + /* if the origin is not the same as the class, then the origin and + the current class need to be copied */ + if (sc->flags & MRB_FLAG_IS_PREPENDED) { + struct RClass *c0 = sc->super; + struct RClass *c1 = dc; + + /* copy prepended iclasses */ + while (!(c0->flags & MRB_FLAG_IS_ORIGIN)) { + c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); + c1 = c1->super; + c0 = c0->super; + } + c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); + c1->super->flags |= MRB_FLAG_IS_ORIGIN; + } + if (sc->mt) { + dc->mt = kh_copy(mt, mrb, sc->mt); + } + else { + dc->mt = kh_init(mt, mrb); + } + dc->super = sc->super; + MRB_SET_INSTANCE_TT(dc, MRB_INSTANCE_TT(sc)); +} + +static void +init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj) +{ + switch (mrb_type(obj)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + copy_class(mrb, dest, obj); + /* fall through */ + case MRB_TT_OBJECT: + case MRB_TT_SCLASS: + case MRB_TT_HASH: + case MRB_TT_DATA: + case MRB_TT_EXCEPTION: + mrb_iv_copy(mrb, dest, obj); + break; + case MRB_TT_ISTRUCT: + mrb_istruct_copy(dest, obj); + break; + + default: + break; + } + mrb_funcall(mrb, dest, "initialize_copy", 1, obj); +} + +/* 15.3.1.3.8 */ +/* + * call-seq: + * obj.clone -> an_object + * + * Produces a shallow copy of <i>obj</i>---the instance variables of + * <i>obj</i> are copied, but not the objects they reference. Copies + * the frozen state of <i>obj</i>. See also the discussion + * under <code>Object#dup</code>. + * + * class Klass + * attr_accessor :str + * end + * s1 = Klass.new #=> #<Klass:0x401b3a38> + * s1.str = "Hello" #=> "Hello" + * s2 = s1.clone #=> #<Klass:0x401b3998 @str="Hello"> + * s2.str[1,4] = "i" #=> "i" + * s1.inspect #=> "#<Klass:0x401b3a38 @str=\"Hi\">" + * s2.inspect #=> "#<Klass:0x401b3998 @str=\"Hi\">" + * + * This method may have class-specific behavior. If so, that + * behavior will be documented under the #+initialize_copy+ method of + * the class. + * + * Some Class(True False Nil Symbol Fixnum Float) Object cannot clone. + */ +MRB_API mrb_value +mrb_obj_clone(mrb_state *mrb, mrb_value self) +{ + struct RObject *p; + mrb_value clone; + + if (mrb_immediate_p(self)) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self); + } + if (mrb_type(self) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class"); + } + p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self)); + p->c = mrb_singleton_class_clone(mrb, self); + mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)p->c); + clone = mrb_obj_value(p); + init_copy(mrb, clone, self); + + return clone; +} + +/* 15.3.1.3.9 */ +/* + * call-seq: + * obj.dup -> an_object + * + * Produces a shallow copy of <i>obj</i>---the instance variables of + * <i>obj</i> are copied, but not the objects they reference. + * <code>dup</code> copies the frozen state of <i>obj</i>. See also + * the discussion under <code>Object#clone</code>. In general, + * <code>clone</code> and <code>dup</code> may have different semantics + * in descendant classes. While <code>clone</code> is used to duplicate + * an object, including its internal state, <code>dup</code> typically + * uses the class of the descendant object to create the new instance. + * + * This method may have class-specific behavior. If so, that + * behavior will be documented under the #+initialize_copy+ method of + * the class. + */ + +MRB_API mrb_value +mrb_obj_dup(mrb_state *mrb, mrb_value obj) +{ + struct RBasic *p; + mrb_value dup; + + if (mrb_immediate_p(obj)) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj); + } + if (mrb_type(obj) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class"); + } + p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj)); + dup = mrb_obj_value(p); + init_copy(mrb, dup, obj); + + return dup; +} + +static mrb_value +mrb_obj_extend(mrb_state *mrb, mrb_int argc, mrb_value *argv, mrb_value obj) +{ + mrb_int i; + + if (argc == 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (at least 1)"); + } + for (i = 0; i < argc; i++) { + mrb_check_type(mrb, argv[i], MRB_TT_MODULE); + } + while (argc--) { + mrb_funcall(mrb, argv[argc], "extend_object", 1, obj); + mrb_funcall(mrb, argv[argc], "extended", 1, obj); + } + return obj; +} + +/* 15.3.1.3.13 */ +/* + * call-seq: + * obj.extend(module, ...) -> obj + * + * Adds to _obj_ the instance methods from each module given as a + * parameter. + * + * module Mod + * def hello + * "Hello from Mod.\n" + * end + * end + * + * class Klass + * def hello + * "Hello from Klass.\n" + * end + * end + * + * k = Klass.new + * k.hello #=> "Hello from Klass.\n" + * k.extend(Mod) #=> #<Klass:0x401b3bc8> + * k.hello #=> "Hello from Mod.\n" + */ +static mrb_value +mrb_obj_extend_m(mrb_state *mrb, mrb_value self) +{ + mrb_value *argv; + mrb_int argc; + + mrb_get_args(mrb, "*", &argv, &argc); + return mrb_obj_extend(mrb, argc, argv, self); +} + +static mrb_value +mrb_obj_freeze(mrb_state *mrb, mrb_value self) +{ + struct RBasic *b; + + switch (mrb_type(self)) { + case MRB_TT_FALSE: + case MRB_TT_TRUE: + case MRB_TT_FIXNUM: + case MRB_TT_SYMBOL: + case MRB_TT_FLOAT: + return self; + default: + break; + } + + b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + MRB_SET_FROZEN_FLAG(b); + } + return self; +} + +static mrb_value +mrb_obj_frozen(mrb_state *mrb, mrb_value self) +{ + struct RBasic *b; + + switch (mrb_type(self)) { + case MRB_TT_FALSE: + case MRB_TT_TRUE: + case MRB_TT_FIXNUM: + case MRB_TT_SYMBOL: + case MRB_TT_FLOAT: + return mrb_true_value(); + default: + break; + } + + b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + return mrb_false_value(); + } + return mrb_true_value(); +} + +/* 15.3.1.3.15 */ +/* + * call-seq: + * obj.hash -> fixnum + * + * Generates a <code>Fixnum</code> hash value for this object. This + * function must have the property that <code>a.eql?(b)</code> implies + * <code>a.hash == b.hash</code>. The hash value is used by class + * <code>Hash</code>. Any hash value that exceeds the capacity of a + * <code>Fixnum</code> will be truncated before being used. + */ +MRB_API mrb_value +mrb_obj_hash(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(mrb_obj_id(self)); +} + +/* 15.3.1.3.16 */ +static mrb_value +mrb_obj_init_copy(mrb_state *mrb, mrb_value self) +{ + mrb_value orig; + + mrb_get_args(mrb, "o", &orig); + if (mrb_obj_equal(mrb, self, orig)) return self; + if ((mrb_type(self) != mrb_type(orig)) || (mrb_obj_class(mrb, self) != mrb_obj_class(mrb, orig))) { + mrb_raise(mrb, E_TYPE_ERROR, "initialize_copy should take same class object"); + } + return self; +} + + +MRB_API mrb_bool +mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c) +{ + if (mrb_obj_class(mrb, obj) == c) return TRUE; + return FALSE; +} + +/* 15.3.1.3.19 */ +/* + * call-seq: + * obj.instance_of?(class) -> true or false + * + * Returns <code>true</code> if <i>obj</i> is an instance of the given + * class. See also <code>Object#kind_of?</code>. + */ +static mrb_value +obj_is_instance_of(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + + mrb_get_args(mrb, "C", &arg); + + return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg))); +} + +/* 15.3.1.3.20 */ +/* + * call-seq: + * obj.instance_variable_defined?(symbol) -> true or false + * + * Returns <code>true</code> if the given instance variable is + * defined in <i>obj</i>. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_defined?(:@a) #=> true + * fred.instance_variable_defined?("@b") #=> true + * fred.instance_variable_defined?("@c") #=> false + */ +static mrb_value +mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) +{ + mrb_sym sym; + + mrb_get_args(mrb, "n", &sym); + mrb_iv_check(mrb, sym); + return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); +} + +/* 15.3.1.3.21 */ +/* + * call-seq: + * obj.instance_variable_get(symbol) -> obj + * + * Returns the value of the given instance variable, or nil if the + * instance variable is not set. The <code>@</code> part of the + * variable name should be included for regular instance + * variables. Throws a <code>NameError</code> exception if the + * supplied symbol is not valid as an instance variable name. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_get(:@a) #=> "cat" + * fred.instance_variable_get("@b") #=> 99 + */ +static mrb_value +mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) +{ + mrb_sym iv_name; + + mrb_get_args(mrb, "n", &iv_name); + mrb_iv_check(mrb, iv_name); + return mrb_iv_get(mrb, self, iv_name); +} + +/* 15.3.1.3.22 */ +/* + * call-seq: + * obj.instance_variable_set(symbol, obj) -> obj + * + * Sets the instance variable names by <i>symbol</i> to + * <i>object</i>, thereby frustrating the efforts of the class's + * author to attempt to provide proper encapsulation. The variable + * did not have to exist prior to this call. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_set(:@a, 'dog') #=> "dog" + * fred.instance_variable_set(:@c, 'cat') #=> "cat" + * fred.inspect #=> "#<Fred:0x401b3da8 @a=\"dog\", @b=99, @c=\"cat\">" + */ +static mrb_value +mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) +{ + mrb_sym iv_name; + mrb_value val; + + mrb_get_args(mrb, "no", &iv_name, &val); + mrb_iv_check(mrb, iv_name); + mrb_iv_set(mrb, self, iv_name, val); + return val; +} + +/* 15.3.1.3.24 */ +/* 15.3.1.3.26 */ +/* + * call-seq: + * obj.is_a?(class) -> true or false + * obj.kind_of?(class) -> true or false + * + * Returns <code>true</code> if <i>class</i> is the class of + * <i>obj</i>, or if <i>class</i> is one of the superclasses of + * <i>obj</i> or modules included in <i>obj</i>. + * + * module M; end + * class A + * include M + * end + * class B < A; end + * class C < B; end + * b = B.new + * b.instance_of? A #=> false + * b.instance_of? B #=> true + * b.instance_of? C #=> false + * b.instance_of? M #=> false + * b.kind_of? A #=> true + * b.kind_of? B #=> true + * b.kind_of? C #=> false + * b.kind_of? M #=> true + */ +static mrb_value +mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + + mrb_get_args(mrb, "C", &arg); + + return mrb_bool_value(mrb_obj_is_kind_of(mrb, self, mrb_class_ptr(arg))); +} + +KHASH_DECLARE(st, mrb_sym, char, FALSE) +KHASH_DEFINE(st, mrb_sym, char, FALSE, kh_int_hash_func, kh_int_hash_equal) + +static void +method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) +{ + khint_t i; + + khash_t(mt) *h = klass->mt; + if (!h) return; + for (i=0;i<kh_end(h);i++) { + if (kh_exist(h, i) && kh_value(h, i)) { + kh_put(st, mrb, set, kh_key(h, i)); + } + } +} + +mrb_value +mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj) +{ + khint_t i; + mrb_value ary; + mrb_bool prepended = FALSE; + struct RClass* oldklass; + khash_t(st)* set = kh_init(st, mrb); + + if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) { + MRB_CLASS_ORIGIN(klass); + prepended = TRUE; + } + + oldklass = 0; + while (klass && (klass != oldklass)) { + method_entry_loop(mrb, klass, set); + if ((klass->tt == MRB_TT_ICLASS && !prepended) || + (klass->tt == MRB_TT_SCLASS)) { + } + else { + if (!recur) break; + } + oldklass = klass; + klass = klass->super; + } + + ary = mrb_ary_new(mrb); + for (i=0;i<kh_end(set);i++) { + if (kh_exist(set, i)) { + mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i))); + } + } + kh_destroy(st, mrb, set); + + return ary; +} + +static mrb_value +mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj) +{ + khint_t i; + mrb_value ary; + struct RClass* klass; + khash_t(st)* set = kh_init(st, mrb); + + klass = mrb_class(mrb, obj); + + if (klass && (klass->tt == MRB_TT_SCLASS)) { + method_entry_loop(mrb, klass, set); + klass = klass->super; + } + if (recur) { + while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) { + method_entry_loop(mrb, klass, set); + klass = klass->super; + } + } + + ary = mrb_ary_new(mrb); + for (i=0;i<kh_end(set);i++) { + if (kh_exist(set, i)) { + mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i))); + } + } + kh_destroy(st, mrb, set); + + return ary; +} + +static mrb_value +mrb_obj_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj, mrb_method_flag_t flag) +{ + return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0); +} +/* 15.3.1.3.31 */ +/* + * call-seq: + * obj.methods -> array + * + * Returns a list of the names of methods publicly accessible in + * <i>obj</i>. This will include all the methods accessible in + * <i>obj</i>'s ancestors. + * + * class Klass + * def kMethod() + * end + * end + * k = Klass.new + * k.methods[0..9] #=> [:kMethod, :respond_to?, :nil?, :is_a?, + * # :class, :instance_variable_set, + * # :methods, :extend, :__send__, :instance_eval] + * k.methods.length #=> 42 + */ +static mrb_value +mrb_obj_methods_m(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */ +} + +/* 15.3.1.3.32 */ +/* + * call_seq: + * nil.nil? -> true + * <anything_else>.nil? -> false + * + * Only the object <i>nil</i> responds <code>true</code> to <code>nil?</code>. + */ +static mrb_value +mrb_false(mrb_state *mrb, mrb_value self) +{ + return mrb_false_value(); +} + +/* 15.3.1.3.36 */ +/* + * call-seq: + * obj.private_methods(all=true) -> array + * + * Returns the list of private methods accessible to <i>obj</i>. If + * the <i>all</i> parameter is set to <code>false</code>, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_private_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */ +} + +/* 15.3.1.3.37 */ +/* + * call-seq: + * obj.protected_methods(all=true) -> array + * + * Returns the list of protected methods accessible to <i>obj</i>. If + * the <i>all</i> parameter is set to <code>false</code>, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_protected_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */ +} + +/* 15.3.1.3.38 */ +/* + * call-seq: + * obj.public_methods(all=true) -> array + * + * Returns the list of public methods accessible to <i>obj</i>. If + * the <i>all</i> parameter is set to <code>false</code>, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_public_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */ +} + +/* 15.3.1.2.12 */ +/* 15.3.1.3.40 */ +/* + * call-seq: + * raise + * raise(string) + * raise(exception [, string]) + * + * With no arguments, raises a <code>RuntimeError</code> + * With a single +String+ argument, raises a + * +RuntimeError+ with the string as a message. Otherwise, + * the first parameter should be the name of an +Exception+ + * class (or an object that returns an +Exception+ object when sent + * an +exception+ message). The optional second parameter sets the + * message associated with the exception, and the third parameter is an + * array of callback information. Exceptions are caught by the + * +rescue+ clause of <code>begin...end</code> blocks. + * + * raise "Failed to create socket" + * raise ArgumentError, "No parameters", caller + */ +MRB_API mrb_value +mrb_f_raise(mrb_state *mrb, mrb_value self) +{ + mrb_value a[2], exc; + int argc; + + + argc = mrb_get_args(mrb, "|oo", &a[0], &a[1]); + switch (argc) { + case 0: + mrb_raise(mrb, E_RUNTIME_ERROR, ""); + break; + case 1: + if (mrb_string_p(a[0])) { + a[1] = a[0]; + argc = 2; + a[0] = mrb_obj_value(E_RUNTIME_ERROR); + } + /* fall through */ + default: + exc = mrb_make_exception(mrb, argc, a); + mrb_exc_raise(mrb, exc); + break; + } + return mrb_nil_value(); /* not reached */ +} + +/* 15.3.1.3.41 */ +/* + * call-seq: + * obj.remove_instance_variable(symbol) -> obj + * + * Removes the named instance variable from <i>obj</i>, returning that + * variable's value. + * + * class Dummy + * attr_reader :var + * def initialize + * @var = 99 + * end + * def remove + * remove_instance_variable(:@var) + * end + * end + * d = Dummy.new + * d.var #=> 99 + * d.remove #=> 99 + * d.var #=> nil + */ +static mrb_value +mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) +{ + mrb_sym sym; + mrb_value val; + + mrb_get_args(mrb, "n", &sym); + mrb_iv_check(mrb, sym); + val = mrb_iv_remove(mrb, self, sym); + if (mrb_undef_p(val)) { + mrb_name_error(mrb, sym, "instance variable %S not defined", mrb_sym2str(mrb, sym)); + } + return val; +} + +void +mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) +{ + mrb_sym inspect; + mrb_value repr; + + inspect = mrb_intern_lit(mrb, "inspect"); + if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) { + /* method missing in inspect; avoid recursion */ + repr = mrb_any_to_s(mrb, self); + } + else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 16) { + repr = mrb_funcall_argv(mrb, self, inspect, 0, 0); + if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) { + repr = mrb_any_to_s(mrb, self); + } + } + else { + repr = mrb_any_to_s(mrb, self); + } + + mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S", + mrb_sym2str(mrb, name), repr); +} + +/* 15.3.1.3.30 */ +/* + * call-seq: + * obj.method_missing(symbol [, *args] ) -> result + * + * Invoked by Ruby when <i>obj</i> is sent a message it cannot handle. + * <i>symbol</i> is the symbol for the method called, and <i>args</i> + * are any arguments that were passed to it. By default, the interpreter + * raises an error when this method is called. However, it is possible + * to override the method to provide more dynamic behavior. + * If it is decided that a particular method should not be handled, then + * <i>super</i> should be called, so that ancestors can pick up the + * missing method. + * The example below creates + * a class <code>Roman</code>, which responds to methods with names + * consisting of roman numerals, returning the corresponding integer + * values. + * + * class Roman + * def romanToInt(str) + * # ... + * end + * def method_missing(methId) + * str = methId.id2name + * romanToInt(str) + * end + * end + * + * r = Roman.new + * r.iv #=> 4 + * r.xxiii #=> 23 + * r.mm #=> 2000 + */ +#ifdef MRB_DEFAULT_METHOD_MISSING +static mrb_value +mrb_obj_missing(mrb_state *mrb, mrb_value mod) +{ + mrb_sym name; + mrb_value *a; + mrb_int alen; + + mrb_get_args(mrb, "n*!", &name, &a, &alen); + mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a)); + /* not reached */ + return mrb_nil_value(); +} +#endif + +static inline mrb_bool +basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) +{ + return mrb_respond_to(mrb, obj, id); +} +/* 15.3.1.3.43 */ +/* + * call-seq: + * obj.respond_to?(symbol, include_private=false) -> true or false + * + * Returns +true+ if _obj_ responds to the given + * method. Private methods are included in the search only if the + * optional second parameter evaluates to +true+. + * + * If the method is not implemented, + * as Process.fork on Windows, File.lchmod on GNU/Linux, etc., + * false is returned. + * + * If the method is not defined, <code>respond_to_missing?</code> + * method is called and the result is returned. + */ +static mrb_value +obj_respond_to(mrb_state *mrb, mrb_value self) +{ + mrb_value mid; + mrb_sym id, rtm_id; + mrb_bool priv = FALSE, respond_to_p = TRUE; + + mrb_get_args(mrb, "o|b", &mid, &priv); + + if (mrb_symbol_p(mid)) { + id = mrb_symbol(mid); + } + else { + mrb_value tmp; + if (mrb_string_p(mid)) { + tmp = mrb_check_intern_str(mrb, mid); + } + else { + tmp = mrb_check_string_type(mrb, mid); + if (mrb_nil_p(tmp)) { + tmp = mrb_inspect(mrb, mid); + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp); + } + tmp = mrb_check_intern_str(mrb, tmp); + } + if (mrb_nil_p(tmp)) { + respond_to_p = FALSE; + } + else { + id = mrb_symbol(tmp); + } + } + + if (respond_to_p) { + respond_to_p = basic_obj_respond_to(mrb, self, id, !priv); + } + + if (!respond_to_p) { + rtm_id = mrb_intern_lit(mrb, "respond_to_missing?"); + if (basic_obj_respond_to(mrb, self, rtm_id, !priv)) { + mrb_value args[2], v; + args[0] = mid; + args[1] = mrb_bool_value(priv); + v = mrb_funcall_argv(mrb, self, rtm_id, 2, args); + return mrb_bool_value(mrb_bool(v)); + } + } + return mrb_bool_value(respond_to_p); +} + +/* 15.3.1.3.45 */ +/* + * call-seq: + * obj.singleton_methods(all=true) -> array + * + * Returns an array of the names of singleton methods for <i>obj</i>. + * If the optional <i>all</i> parameter is true, the list will include + * methods in modules included in <i>obj</i>. + * Only public and protected singleton methods are returned. + * + * module Other + * def three() end + * end + * + * class Single + * def Single.four() end + * end + * + * a = Single.new + * + * def a.one() + * end + * + * class << a + * include Other + * def two() + * end + * end + * + * Single.singleton_methods #=> [:four] + * a.singleton_methods(false) #=> [:two, :one] + * a.singleton_methods #=> [:two, :one, :three] + */ +static mrb_value +mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_singleton_methods(mrb, recur, self); +} + +static mrb_value +mod_define_singleton_method(mrb_state *mrb, mrb_value self) +{ + struct RProc *p; + mrb_sym mid; + mrb_value blk = mrb_nil_value(); + + mrb_get_args(mrb, "n&", &mid, &blk); + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + p->flags |= MRB_PROC_STRICT; + mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, p); + return mrb_symbol_value(mid); +} + +static mrb_value +mrb_obj_ceqq(mrb_state *mrb, mrb_value self) +{ + mrb_value v; + mrb_int i, len; + mrb_sym eqq = mrb_intern_lit(mrb, "==="); + mrb_value ary = mrb_ary_splat(mrb, self); + + mrb_get_args(mrb, "o", &v); + len = RARRAY_LEN(ary); + for (i=0; i<len; i++) { + mrb_value c = mrb_funcall_argv(mrb, mrb_ary_entry(ary, i), eqq, 1, &v); + if (mrb_test(c)) return mrb_true_value(); + } + return mrb_false_value(); +} + +/* 15.3.1.2.7 */ +/* + * call-seq: + * local_variables -> array + * + * Returns the names of local variables in the current scope. + * + * [mruby limitation] + * If variable symbol information was stripped out from + * compiled binary files using `mruby-strip -l`, this + * method always returns an empty array. + */ +static mrb_value +mrb_local_variables(mrb_state *mrb, mrb_value self) +{ + struct RProc *proc; + mrb_irep *irep; + mrb_value vars; + size_t i; + + proc = mrb->c->ci[-1].proc; + + if (MRB_PROC_CFUNC_P(proc)) { + return mrb_ary_new(mrb); + } + vars = mrb_hash_new(mrb); + irep = proc->body.irep; + while (irep) { + if (!irep->lv) break; + for (i = 0; i + 1 < irep->nlocals; ++i) { + if (irep->lv[i].name) { + mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value()); + } + } + if (!proc->env) break; + irep = irep->outer; + } + + return mrb_hash_keys(mrb, vars); +} + +mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); +void +mrb_init_kernel(mrb_state *mrb) +{ + struct RClass *krn; + + mrb->kernel_module = krn = mrb_define_module(mrb, "Kernel"); /* 15.3.1 */ + mrb_define_class_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.2 */ + mrb_define_class_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ + mrb_define_class_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.5 */ + mrb_define_class_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.2.7 */ +; /* 15.3.1.2.11 */ + mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_OPT(2)); /* 15.3.1.2.12 */ + + mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); + + mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */ + mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */ + mrb_define_method(mrb, krn, "class", mrb_obj_class_m, MRB_ARGS_NONE()); /* 15.3.1.3.7 */ + mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */ + mrb_define_method(mrb, krn, "dup", mrb_obj_dup, MRB_ARGS_NONE()); /* 15.3.1.3.9 */ + mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */ + mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ + mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ + mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); + mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); + mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ + mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ + mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ + mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ + mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, MRB_ARGS_REQ(1)); /* 15.3.1.3.19 */ + mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ + mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */ + mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */ + mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */ + mrb_define_method(mrb, krn, "is_a?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.24 */ + mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */ + mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */ + mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ +#ifdef MRB_DEFAULT_METHOD_MISSING + mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */ +#endif + mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ + mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */ + mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */ + mrb_define_method(mrb, krn, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */ + mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */ + mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */ + mrb_define_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.3.40 */ + mrb_define_method(mrb, krn, "remove_instance_variable", mrb_obj_remove_instance_variable,MRB_ARGS_REQ(1)); /* 15.3.1.3.41 */ + mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */ + mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */ + mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ + mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY()); + mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ + mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ + + mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); + mrb_alias_method(mrb, mrb->module_class, mrb_intern_lit(mrb, "dup"), mrb_intern_lit(mrb, "clone")); +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/load.c b/web/server/h2o/libh2o/deps/mruby/src/load.c new file mode 100644 index 000000000..8ae607ffa --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/load.c @@ -0,0 +1,704 @@ +/* +** load.c - mruby binary loader +** +** See Copyright Notice in mruby.h +*/ + +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <mruby/dump.h> +#include <mruby/irep.h> +#include <mruby/proc.h> +#include <mruby/string.h> +#include <mruby/debug.h> +#include <mruby/error.h> + +#if SIZE_MAX < UINT32_MAX +# error size_t must be at least 32 bits wide +#endif + +#define FLAG_BYTEORDER_BIG 2 +#define FLAG_BYTEORDER_LIL 4 +#define FLAG_BYTEORDER_NATIVE 8 +#define FLAG_SRC_MALLOC 1 +#define FLAG_SRC_STATIC 0 + +#define SIZE_ERROR_MUL(nmemb, size) ((size_t)(nmemb) > SIZE_MAX / (size)) + +static size_t +skip_padding(const uint8_t *buf) +{ + const size_t align = MRB_DUMP_ALIGNMENT; + return -(intptr_t)buf & (align-1); +} + +static size_t +offset_crc_body(void) +{ + struct rite_binary_header header; + return ((uint8_t *)header.binary_crc - (uint8_t *)&header) + sizeof(header.binary_crc); +} + +static mrb_irep* +read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags) +{ + int i; + const uint8_t *src = bin; + ptrdiff_t diff; + uint16_t tt, pool_data_len, snl; + int plen; + int ai = mrb_gc_arena_save(mrb); + mrb_irep *irep = mrb_add_irep(mrb); + + /* skip record size */ + src += sizeof(uint32_t); + + /* number of local variable */ + irep->nlocals = bin_to_uint16(src); + src += sizeof(uint16_t); + + /* number of register variable */ + irep->nregs = bin_to_uint16(src); + src += sizeof(uint16_t); + + /* number of child irep */ + irep->rlen = (size_t)bin_to_uint16(src); + src += sizeof(uint16_t); + + /* Binary Data Section */ + /* ISEQ BLOCK */ + irep->ilen = (size_t)bin_to_uint32(src); + src += sizeof(uint32_t); + src += skip_padding(src); + + if (irep->ilen > 0) { + if (SIZE_ERROR_MUL(irep->ilen, sizeof(mrb_code))) { + return NULL; + } + if ((flags & FLAG_SRC_MALLOC) == 0 && + (flags & FLAG_BYTEORDER_NATIVE)) { + irep->iseq = (mrb_code*)src; + src += sizeof(uint32_t) * irep->ilen; + irep->flags |= MRB_ISEQ_NO_FREE; + } + else { + irep->iseq = (mrb_code *)mrb_malloc(mrb, sizeof(mrb_code) * irep->ilen); + if (flags & FLAG_BYTEORDER_NATIVE) { + memcpy(irep->iseq, src, sizeof(uint32_t) * irep->ilen); + src += sizeof(uint32_t) * irep->ilen; + } + else if (flags & FLAG_BYTEORDER_BIG) { + for (i = 0; i < irep->ilen; i++) { + irep->iseq[i] = (mrb_code)bin_to_uint32(src); /* iseq */ + src += sizeof(uint32_t); + } + } + else { + for (i = 0; i < irep->ilen; i++) { + irep->iseq[i] = (mrb_code)bin_to_uint32l(src); /* iseq */ + src += sizeof(uint32_t); + } + } + } + } + + /* POOL BLOCK */ + plen = bin_to_uint32(src); /* number of pool */ + src += sizeof(uint32_t); + if (plen > 0) { + if (SIZE_ERROR_MUL(plen, sizeof(mrb_value))) { + return NULL; + } + irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * plen); + + for (i = 0; i < plen; i++) { + mrb_value s; + + tt = *src++; /* pool TT */ + pool_data_len = bin_to_uint16(src); /* pool data length */ + src += sizeof(uint16_t); + if (flags & FLAG_SRC_MALLOC) { + s = mrb_str_new(mrb, (char *)src, pool_data_len); + } + else { + s = mrb_str_new_static(mrb, (char *)src, pool_data_len); + } + src += pool_data_len; + switch (tt) { /* pool data */ + case IREP_TT_FIXNUM: + irep->pool[i] = mrb_str_to_inum(mrb, s, 10, FALSE); + break; + + case IREP_TT_FLOAT: + irep->pool[i] = mrb_float_pool(mrb, mrb_str_to_dbl(mrb, s, FALSE)); + break; + + case IREP_TT_STRING: + irep->pool[i] = mrb_str_pool(mrb, s); + break; + + default: + /* should not happen */ + irep->pool[i] = mrb_nil_value(); + break; + } + irep->plen++; + mrb_gc_arena_restore(mrb, ai); + } + } + + /* SYMS BLOCK */ + irep->slen = (size_t)bin_to_uint32(src); /* syms length */ + src += sizeof(uint32_t); + if (irep->slen > 0) { + if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) { + return NULL; + } + irep->syms = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym) * irep->slen); + + for (i = 0; i < irep->slen; i++) { + snl = bin_to_uint16(src); /* symbol name length */ + src += sizeof(uint16_t); + + if (snl == MRB_DUMP_NULL_SYM_LEN) { + irep->syms[i] = 0; + continue; + } + + if (flags & FLAG_SRC_MALLOC) { + irep->syms[i] = mrb_intern(mrb, (char *)src, snl); + } + else { + irep->syms[i] = mrb_intern_static(mrb, (char *)src, snl); + } + src += snl + 1; + + mrb_gc_arena_restore(mrb, ai); + } + } + + irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*irep->rlen); + + diff = src - bin; + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + *len = (size_t)diff; + + return irep; +} + +static mrb_irep* +read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags) +{ + mrb_irep *irep = read_irep_record_1(mrb, bin, len, flags); + int i; + + if (irep == NULL) { + return NULL; + } + + bin += *len; + for (i=0; i<irep->rlen; i++) { + size_t rlen; + + irep->reps[i] = read_irep_record(mrb, bin, &rlen, flags); + if (irep->reps[i] == NULL) { + return NULL; + } + bin += rlen; + *len += rlen; + } + return irep; +} + +static mrb_irep* +read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) +{ + size_t len; + + bin += sizeof(struct rite_section_irep_header); + return read_irep_record(mrb, bin, &len, flags); +} + +static int +read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len) +{ + size_t i, fname_len, niseq; + char *fname; + uint16_t *lines; + + *len = 0; + bin += sizeof(uint32_t); /* record size */ + *len += sizeof(uint32_t); + fname_len = bin_to_uint16(bin); + bin += sizeof(uint16_t); + *len += sizeof(uint16_t); + fname = (char *)mrb_malloc(mrb, fname_len + 1); + memcpy(fname, bin, fname_len); + fname[fname_len] = '\0'; + bin += fname_len; + *len += fname_len; + + niseq = (size_t)bin_to_uint32(bin); + bin += sizeof(uint32_t); /* niseq */ + *len += sizeof(uint32_t); + + if (SIZE_ERROR_MUL(niseq, sizeof(uint16_t))) { + return MRB_DUMP_GENERAL_FAILURE; + } + lines = (uint16_t *)mrb_malloc(mrb, niseq * sizeof(uint16_t)); + for (i = 0; i < niseq; i++) { + lines[i] = bin_to_uint16(bin); + bin += sizeof(uint16_t); /* niseq */ + *len += sizeof(uint16_t); + } + + irep->filename = fname; + irep->lines = lines; + return MRB_DUMP_OK; +} + +static int +read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *lenp) +{ + int result = read_lineno_record_1(mrb, bin, irep, lenp); + int i; + + if (result != MRB_DUMP_OK) return result; + for (i = 0; i < irep->rlen; i++) { + size_t len; + + result = read_lineno_record(mrb, bin, irep->reps[i], &len); + if (result != MRB_DUMP_OK) break; + bin += len; + *lenp += len; + } + return result; +} + +static int +read_section_lineno(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep) +{ + size_t len; + + len = 0; + bin += sizeof(struct rite_section_lineno_header); + + /* Read Binary Data Section */ + return read_lineno_record(mrb, bin, irep, &len); +} + +static int +read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len) +{ + const uint8_t *bin = start; + ptrdiff_t diff; + size_t record_size; + uint16_t f_idx; + int i; + + if (irep->debug_info) { return MRB_DUMP_INVALID_IREP; } + + irep->debug_info = (mrb_irep_debug_info*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info)); + irep->debug_info->pc_count = (uint32_t)irep->ilen; + + record_size = (size_t)bin_to_uint32(bin); + bin += sizeof(uint32_t); + + irep->debug_info->flen = bin_to_uint16(bin); + irep->debug_info->files = (mrb_irep_debug_info_file**)mrb_malloc(mrb, sizeof(mrb_irep_debug_info*) * irep->debug_info->flen); + bin += sizeof(uint16_t); + + for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { + mrb_irep_debug_info_file *file; + uint16_t filename_idx; + mrb_int len; + + file = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*file)); + irep->debug_info->files[f_idx] = file; + + file->start_pos = bin_to_uint32(bin); + bin += sizeof(uint32_t); + + /* filename */ + filename_idx = bin_to_uint16(bin); + bin += sizeof(uint16_t); + mrb_assert(filename_idx < filenames_len); + file->filename_sym = filenames[filename_idx]; + len = 0; + file->filename = mrb_sym2name_len(mrb, file->filename_sym, &len); + + file->line_entry_count = bin_to_uint32(bin); + bin += sizeof(uint32_t); + file->line_type = (mrb_debug_line_type)bin_to_uint8(bin); + bin += sizeof(uint8_t); + switch (file->line_type) { + case mrb_debug_line_ary: { + uint32_t l; + + file->lines.ary = (uint16_t *)mrb_malloc(mrb, sizeof(uint16_t) * (size_t)(file->line_entry_count)); + for (l = 0; l < file->line_entry_count; ++l) { + file->lines.ary[l] = bin_to_uint16(bin); + bin += sizeof(uint16_t); + } + } break; + + case mrb_debug_line_flat_map: { + uint32_t l; + + file->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc( + mrb, sizeof(mrb_irep_debug_info_line) * (size_t)(file->line_entry_count)); + for (l = 0; l < file->line_entry_count; ++l) { + file->lines.flat_map[l].start_pos = bin_to_uint32(bin); + bin += sizeof(uint32_t); + file->lines.flat_map[l].line = bin_to_uint16(bin); + bin += sizeof(uint16_t); + } + } break; + + default: return MRB_DUMP_GENERAL_FAILURE; + } + } + + diff = bin - start; + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + + if (record_size != (size_t)diff) { + return MRB_DUMP_GENERAL_FAILURE; + } + + for (i = 0; i < irep->rlen; i++) { + size_t len; + int ret; + + ret = read_debug_record(mrb, bin, irep->reps[i], &len, filenames, filenames_len); + if (ret != MRB_DUMP_OK) return ret; + bin += len; + } + + diff = bin - start; + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + *record_len = (size_t)diff; + + return MRB_DUMP_OK; +} + +static int +read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags) +{ + const uint8_t *bin; + ptrdiff_t diff; + struct rite_section_debug_header *header; + uint16_t i; + size_t len = 0; + int result; + uint16_t filenames_len; + mrb_sym *filenames; + + bin = start; + header = (struct rite_section_debug_header *)bin; + bin += sizeof(struct rite_section_debug_header); + + filenames_len = bin_to_uint16(bin); + bin += sizeof(uint16_t); + filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)filenames_len); + for (i = 0; i < filenames_len; ++i) { + uint16_t f_len = bin_to_uint16(bin); + bin += sizeof(uint16_t); + if (flags & FLAG_SRC_MALLOC) { + filenames[i] = mrb_intern(mrb, (const char *)bin, (size_t)f_len); + } + else { + filenames[i] = mrb_intern_static(mrb, (const char *)bin, (size_t)f_len); + } + bin += f_len; + } + + result = read_debug_record(mrb, bin, irep, &len, filenames, filenames_len); + if (result != MRB_DUMP_OK) goto debug_exit; + + bin += len; + diff = bin - start; + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + if ((uint32_t)diff != bin_to_uint32(header->section_size)) { + result = MRB_DUMP_GENERAL_FAILURE; + } + +debug_exit: + mrb_free(mrb, filenames); + return result; +} + +static int +read_lv_record(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, size_t *record_len, mrb_sym const *syms, uint32_t syms_len) +{ + const uint8_t *bin = start; + ptrdiff_t diff; + int i; + + irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (irep->nlocals - 1)); + + for (i = 0; i + 1< irep->nlocals; ++i) { + uint16_t const sym_idx = bin_to_uint16(bin); + bin += sizeof(uint16_t); + if (sym_idx == RITE_LV_NULL_MARK) { + irep->lv[i].name = 0; + irep->lv[i].r = 0; + } + else { + if (sym_idx >= syms_len) { + return MRB_DUMP_GENERAL_FAILURE; + } + irep->lv[i].name = syms[sym_idx]; + + irep->lv[i].r = bin_to_uint16(bin); + } + bin += sizeof(uint16_t); + } + + for (i = 0; i < irep->rlen; ++i) { + size_t len; + int ret; + + ret = read_lv_record(mrb, bin, irep->reps[i], &len, syms, syms_len); + if (ret != MRB_DUMP_OK) return ret; + bin += len; + } + + diff = bin - start; + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + *record_len = (size_t)diff; + + return MRB_DUMP_OK; +} + +static int +read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags) +{ + const uint8_t *bin; + ptrdiff_t diff; + struct rite_section_lv_header const *header; + uint32_t i; + size_t len = 0; + int result; + uint32_t syms_len; + mrb_sym *syms; + mrb_sym (*intern_func)(mrb_state*, const char*, size_t) = + (flags & FLAG_SRC_MALLOC)? mrb_intern : mrb_intern_static; + + bin = start; + header = (struct rite_section_lv_header const*)bin; + bin += sizeof(struct rite_section_lv_header); + + syms_len = bin_to_uint32(bin); + bin += sizeof(uint32_t); + syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)syms_len); + for (i = 0; i < syms_len; ++i) { + uint16_t const str_len = bin_to_uint16(bin); + bin += sizeof(uint16_t); + + syms[i] = intern_func(mrb, (const char*)bin, str_len); + bin += str_len; + } + + result = read_lv_record(mrb, bin, irep, &len, syms, syms_len); + if (result != MRB_DUMP_OK) goto lv_exit; + + bin += len; + diff = bin - start; + mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); + if ((uint32_t)diff != bin_to_uint32(header->section_size)) { + result = MRB_DUMP_GENERAL_FAILURE; + } + +lv_exit: + mrb_free(mrb, syms); + return result; +} + +static int +read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t *flags) +{ + const struct rite_binary_header *header = (const struct rite_binary_header *)bin; + + if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) { + if (bigendian_p()) + *flags |= FLAG_BYTEORDER_NATIVE; + else + *flags |= FLAG_BYTEORDER_BIG; + } + else if (memcmp(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)) == 0) { + if (bigendian_p()) + *flags |= FLAG_BYTEORDER_LIL; + else + *flags |= FLAG_BYTEORDER_NATIVE; + } + else { + return MRB_DUMP_INVALID_FILE_HEADER; + } + + if (crc) { + *crc = bin_to_uint16(header->binary_crc); + } + *bin_size = (size_t)bin_to_uint32(header->binary_size); + + return MRB_DUMP_OK; +} + +static mrb_irep* +read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) +{ + int result; + mrb_irep *irep = NULL; + const struct rite_section_header *section_header; + uint16_t crc; + size_t bin_size = 0; + size_t n; + + if ((mrb == NULL) || (bin == NULL)) { + return NULL; + } + + result = read_binary_header(bin, &bin_size, &crc, &flags); + if (result != MRB_DUMP_OK) { + return NULL; + } + + n = offset_crc_body(); + if (crc != calc_crc_16_ccitt(bin + n, bin_size - n, 0)) { + return NULL; + } + + bin += sizeof(struct rite_binary_header); + do { + section_header = (const struct rite_section_header *)bin; + if (memcmp(section_header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(section_header->section_ident)) == 0) { + irep = read_section_irep(mrb, bin, flags); + if (!irep) return NULL; + } + else if (memcmp(section_header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(section_header->section_ident)) == 0) { + if (!irep) return NULL; /* corrupted data */ + result = read_section_lineno(mrb, bin, irep); + if (result < MRB_DUMP_OK) { + return NULL; + } + } + else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) { + if (!irep) return NULL; /* corrupted data */ + result = read_section_debug(mrb, bin, irep, flags); + if (result < MRB_DUMP_OK) { + return NULL; + } + } + else if (memcmp(section_header->section_ident, RITE_SECTION_LV_IDENT, sizeof(section_header->section_ident)) == 0) { + if (!irep) return NULL; + result = read_section_lv(mrb, bin, irep, flags); + if (result < MRB_DUMP_OK) { + return NULL; + } + } + bin += bin_to_uint32(section_header->section_size); + } while (memcmp(section_header->section_ident, RITE_BINARY_EOF, sizeof(section_header->section_ident)) != 0); + + return irep; +} + +mrb_irep* +mrb_read_irep(mrb_state *mrb, const uint8_t *bin) +{ +#ifdef MRB_USE_ETEXT_EDATA + uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC; +#else + uint8_t flags = FLAG_SRC_STATIC; +#endif + + return read_irep(mrb, bin, flags); +} + +void mrb_exc_set(mrb_state *mrb, mrb_value exc); + +static void +irep_error(mrb_state *mrb) +{ + mrb_exc_set(mrb, mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error")); +} + +void mrb_codedump_all(mrb_state*, struct RProc*); + +static mrb_value +load_irep(mrb_state *mrb, mrb_irep *irep, mrbc_context *c) +{ + struct RProc *proc; + + if (!irep) { + irep_error(mrb); + return mrb_nil_value(); + } + proc = mrb_proc_new(mrb, irep); + proc->c = NULL; + mrb_irep_decref(mrb, irep); + if (c && c->dump_result) mrb_codedump_all(mrb, proc); + if (c && c->no_exec) return mrb_obj_value(proc); + return mrb_top_run(mrb, proc, mrb_top_self(mrb), 0); +} + +MRB_API mrb_value +mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c) +{ + return load_irep(mrb, mrb_read_irep(mrb, bin), c); +} + +MRB_API mrb_value +mrb_load_irep(mrb_state *mrb, const uint8_t *bin) +{ + return mrb_load_irep_cxt(mrb, bin, NULL); +} + +#ifndef MRB_DISABLE_STDIO + +mrb_irep* +mrb_read_irep_file(mrb_state *mrb, FILE* fp) +{ + mrb_irep *irep = NULL; + uint8_t *buf; + const size_t header_size = sizeof(struct rite_binary_header); + size_t buf_size = 0; + uint8_t flags = 0; + int result; + + if ((mrb == NULL) || (fp == NULL)) { + return NULL; + } + + buf = (uint8_t*)mrb_malloc(mrb, header_size); + if (fread(buf, header_size, 1, fp) == 0) { + goto irep_exit; + } + result = read_binary_header(buf, &buf_size, NULL, &flags); + if (result != MRB_DUMP_OK || buf_size <= header_size) { + goto irep_exit; + } + + buf = (uint8_t*)mrb_realloc(mrb, buf, buf_size); + if (fread(buf+header_size, buf_size-header_size, 1, fp) == 0) { + goto irep_exit; + } + irep = read_irep(mrb, buf, FLAG_SRC_MALLOC); + +irep_exit: + mrb_free(mrb, buf); + return irep; +} + +MRB_API mrb_value +mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c) +{ + return load_irep(mrb, mrb_read_irep_file(mrb, fp), c); +} + +MRB_API mrb_value +mrb_load_irep_file(mrb_state *mrb, FILE* fp) +{ + return mrb_load_irep_file_cxt(mrb, fp, NULL); +} +#endif /* MRB_DISABLE_STDIO */ diff --git a/web/server/h2o/libh2o/deps/mruby/src/mruby_core.rake b/web/server/h2o/libh2o/deps/mruby/src/mruby_core.rake new file mode 100644 index 000000000..4558493d9 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/mruby_core.rake @@ -0,0 +1,19 @@ +MRuby.each_target do + current_dir = File.dirname(__FILE__).relative_path_from(Dir.pwd) + relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) + current_build_dir = "#{build_dir}/#{relative_from_root}" + + objs = Dir.glob("#{current_dir}/*.c").map { |f| + next nil if cxx_exception_enabled? and f =~ /(error|vm).c$/ + objfile(f.pathmap("#{current_build_dir}/%n")) + }.compact + + if cxx_exception_enabled? + objs += %w(vm error).map { |v| compile_as_cxx "#{current_dir}/#{v}.c", "#{current_build_dir}/#{v}.cxx" } + end + self.libmruby << objs + + file libfile("#{build_dir}/lib/libmruby_core") => objs do |t| + archiver.run t.name, t.prerequisites + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/src/numeric.c b/web/server/h2o/libh2o/deps/mruby/src/numeric.c new file mode 100644 index 000000000..afb8415a0 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/numeric.c @@ -0,0 +1,1355 @@ +/* +** numeric.c - Numeric, Integer, Float, Fixnum class +** +** See Copyright Notice in mruby.h +*/ + +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdlib.h> + +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/numeric.h> +#include <mruby/string.h> +#include <mruby/class.h> + +#ifdef MRB_USE_FLOAT +#define trunc(f) truncf(f) +#define floor(f) floorf(f) +#define ceil(f) ceilf(f) +#define fmod(x,y) fmodf(x,y) +#define MRB_FLO_TO_STR_FMT "%.7g" +#else +#define MRB_FLO_TO_STR_FMT "%.14g" +#endif + +MRB_API mrb_float +mrb_to_flo(mrb_state *mrb, mrb_value val) +{ + switch (mrb_type(val)) { + case MRB_TT_FIXNUM: + return (mrb_float)mrb_fixnum(val); + case MRB_TT_FLOAT: + break; + default: + mrb_raise(mrb, E_TYPE_ERROR, "non float value"); + } + return mrb_float(val); +} + +/* + * call-seq: + * + * num ** other -> num + * + * Raises <code>num</code> the <code>other</code> power. + * + * 2.0**3 #=> 8.0 + */ +static mrb_value +num_pow(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + mrb_float d; + + mrb_get_args(mrb, "o", &y); + if (mrb_fixnum_p(x) && mrb_fixnum_p(y)) { + /* try ipow() */ + mrb_int base = mrb_fixnum(x); + mrb_int exp = mrb_fixnum(y); + mrb_int result = 1; + + if (exp < 0) goto float_pow; + for (;;) { + if (exp & 1) { + if (mrb_int_mul_overflow(result, base, &result)) { + goto float_pow; + } + } + exp >>= 1; + if (exp == 0) break; + if (mrb_int_mul_overflow(base, base, &base)) { + goto float_pow; + } + } + return mrb_fixnum_value(result); + } + float_pow: + d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, d); +} + +/* 15.2.8.3.4 */ +/* 15.2.9.3.4 */ +/* + * call-seq: + * num / other -> num + * + * Performs division: the class of the resulting object depends on + * the class of <code>num</code> and on the magnitude of the + * result. + */ + +mrb_value +mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) +{ + return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y)); +} + +/* 15.2.9.3.19(x) */ +/* + * call-seq: + * num.quo(numeric) -> real + * + * Returns most exact division. + */ + +static mrb_value +num_div(mrb_state *mrb, mrb_value x) +{ + mrb_float y; + + mrb_get_args(mrb, "f", &y); + return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y); +} + +/******************************************************************** + * + * Document-class: Float + * + * <code>Float</code> objects represent inexact real numbers using + * the native architecture's double-precision floating point + * representation. + */ + +/* 15.2.9.3.16(x) */ +/* + * call-seq: + * flt.to_s -> string + * + * Returns a string containing a representation of self. As well as a + * fixed or exponential form of the number, the call may return + * "<code>NaN</code>", "<code>Infinity</code>", and + * "<code>-Infinity</code>". + */ + +static mrb_value +flo_to_s(mrb_state *mrb, mrb_value flt) +{ + if (isnan(mrb_float(flt))) { + return mrb_str_new_lit(mrb, "NaN"); + } + return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT); +} + +/* 15.2.9.3.2 */ +/* + * call-seq: + * float - other -> float + * + * Returns a new float which is the difference of <code>float</code> + * and <code>other</code>. + */ + +static mrb_value +flo_minus(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); +} + +/* 15.2.9.3.3 */ +/* + * call-seq: + * float * other -> float + * + * Returns a new float which is the product of <code>float</code> + * and <code>other</code>. + */ + +static mrb_value +flo_mul(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y)); +} + +static void +flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp) +{ + mrb_float div; + mrb_float mod; + + if (y == 0.0) { + if (x > 0.0) div = INFINITY; + else if (x < 0.0) div = -INFINITY; + else div = NAN; /* x == 0.0 */ + mod = NAN; + } + else { + mod = fmod(x, y); + if (isinf(x) && isfinite(y)) + div = x; + else + div = (x - mod) / y; + if (y*mod < 0) { + mod += y; + div -= 1.0; + } + } + + if (modp) *modp = mod; + if (divp) *divp = div; +} + +/* 15.2.9.3.5 */ +/* + * call-seq: + * flt % other -> float + * flt.modulo(other) -> float + * + * Return the modulo after division of <code>flt</code> by <code>other</code>. + * + * 6543.21.modulo(137) #=> 104.21 + * 6543.21.modulo(137.24) #=> 92.9299999999996 + */ + +static mrb_value +flo_mod(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + mrb_float mod; + + mrb_get_args(mrb, "o", &y); + + flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod); + return mrb_float_value(mrb, mod); +} + +/* 15.2.8.3.16 */ +/* + * call-seq: + * num.eql?(numeric) -> true or false + * + * Returns <code>true</code> if <i>num</i> and <i>numeric</i> are the + * same type and have equal values. + * + * 1 == 1.0 #=> true + * 1.eql?(1.0) #=> false + * (1.0).eql?(1.0) #=> true + */ +static mrb_value +fix_eql(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + if (!mrb_fixnum_p(y)) return mrb_false_value(); + return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y)); +} + +static mrb_value +flo_eql(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + if (!mrb_float_p(y)) return mrb_false_value(); + return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y)); +} + +/* 15.2.9.3.7 */ +/* + * call-seq: + * flt == obj -> true or false + * + * Returns <code>true</code> only if <i>obj</i> has the same value + * as <i>flt</i>. Contrast this with <code>Float#eql?</code>, which + * requires <i>obj</i> to be a <code>Float</code>. + * + * 1.0 == 1 #=> true + * + */ + +static mrb_value +flo_eq(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + mrb_get_args(mrb, "o", &y); + + switch (mrb_type(y)) { + case MRB_TT_FIXNUM: + return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y)); + case MRB_TT_FLOAT: + return mrb_bool_value(mrb_float(x) == mrb_float(y)); + default: + return mrb_false_value(); + } +} + +static int64_t +value_int64(mrb_state *mrb, mrb_value x) +{ + switch (mrb_type(x)) { + case MRB_TT_FIXNUM: + return (int64_t)mrb_fixnum(x); + break; + case MRB_TT_FLOAT: + return (int64_t)mrb_float(x); + default: + mrb_raise(mrb, E_TYPE_ERROR, "cannot convert to Integer"); + break; + } + /* not reached */ + return 0; +} + +static mrb_value +int64_value(mrb_state *mrb, int64_t v) +{ + if (FIXABLE(v)) { + return mrb_fixnum_value((mrb_int)v); + } + return mrb_float_value(mrb, (mrb_float)v); +} + +static mrb_value +flo_rev(mrb_state *mrb, mrb_value x) +{ + int64_t v1; + mrb_get_args(mrb, ""); + v1 = (int64_t)mrb_float(x); + return int64_value(mrb, ~v1); +} + +static mrb_value +flo_and(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + int64_t v1, v2; + mrb_get_args(mrb, "o", &y); + + v1 = (int64_t)mrb_float(x); + v2 = value_int64(mrb, y); + return int64_value(mrb, v1 & v2); +} + +static mrb_value +flo_or(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + int64_t v1, v2; + mrb_get_args(mrb, "o", &y); + + v1 = (int64_t)mrb_float(x); + v2 = value_int64(mrb, y); + return int64_value(mrb, v1 | v2); +} + +static mrb_value +flo_xor(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + int64_t v1, v2; + mrb_get_args(mrb, "o", &y); + + v1 = (int64_t)mrb_float(x); + v2 = value_int64(mrb, y); + return int64_value(mrb, v1 ^ v2); +} + +static mrb_value +flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) +{ + mrb_float val; + + if (width == 0) { + return x; + } + val = mrb_float(x); + if (width < 0) { + while (width++) { + val /= 2; + } +#if defined(_ISOC99_SOURCE) + val = trunc(val); +#else + if (val > 0){ + val = floor(val); + } else { + val = ceil(val); + } +#endif + if (val == 0 && mrb_float(x) < 0) { + return mrb_fixnum_value(-1); + } + } + else { + while (width--) { + val *= 2; + } + } + if (FIXABLE_FLOAT(val)) { + return mrb_fixnum_value((mrb_int)val); + } + return mrb_float_value(mrb, val); +} + +static mrb_value +flo_lshift(mrb_state *mrb, mrb_value x) +{ + mrb_int width; + + mrb_get_args(mrb, "i", &width); + return flo_shift(mrb, x, -width); +} + +static mrb_value +flo_rshift(mrb_state *mrb, mrb_value x) +{ + mrb_int width; + + mrb_get_args(mrb, "i", &width); + return flo_shift(mrb, x, width); +} + +/* 15.2.9.3.13 */ +/* + * call-seq: + * flt.to_f -> self + * + * As <code>flt</code> is already a float, returns +self+. + */ + +static mrb_value +flo_to_f(mrb_state *mrb, mrb_value num) +{ + return num; +} + +/* 15.2.9.3.11 */ +/* + * call-seq: + * flt.infinite? -> nil, -1, +1 + * + * Returns <code>nil</code>, -1, or +1 depending on whether <i>flt</i> + * is finite, -infinity, or +infinity. + * + * (0.0).infinite? #=> nil + * (-1.0/0.0).infinite? #=> -1 + * (+1.0/0.0).infinite? #=> 1 + */ + +static mrb_value +flo_infinite_p(mrb_state *mrb, mrb_value num) +{ + mrb_float value = mrb_float(num); + + if (isinf(value)) { + return mrb_fixnum_value(value < 0 ? -1 : 1); + } + return mrb_nil_value(); +} + +/* 15.2.9.3.9 */ +/* + * call-seq: + * flt.finite? -> true or false + * + * Returns <code>true</code> if <i>flt</i> is a valid IEEE floating + * point number (it is not infinite, and <code>nan?</code> is + * <code>false</code>). + * + */ + +static mrb_value +flo_finite_p(mrb_state *mrb, mrb_value num) +{ + return mrb_bool_value(isfinite(mrb_float(num))); +} + +void +mrb_check_num_exact(mrb_state *mrb, mrb_float num) +{ + if (isinf(num)) { + mrb_raise(mrb, E_FLOATDOMAIN_ERROR, num < 0 ? "-Infinity" : "Infinity"); + } + if (isnan(num)) { + mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN"); + } +} + +/* 15.2.9.3.10 */ +/* + * call-seq: + * flt.floor -> integer + * + * Returns the largest integer less than or equal to <i>flt</i>. + * + * 1.2.floor #=> 1 + * 2.0.floor #=> 2 + * (-1.2).floor #=> -2 + * (-2.0).floor #=> -2 + */ + +static mrb_value +flo_floor(mrb_state *mrb, mrb_value num) +{ + mrb_float f = floor(mrb_float(num)); + + mrb_check_num_exact(mrb, f); + if (!FIXABLE_FLOAT(f)) { + return mrb_float_value(mrb, f); + } + return mrb_fixnum_value((mrb_int)f); +} + +/* 15.2.9.3.8 */ +/* + * call-seq: + * flt.ceil -> integer + * + * Returns the smallest <code>Integer</code> greater than or equal to + * <i>flt</i>. + * + * 1.2.ceil #=> 2 + * 2.0.ceil #=> 2 + * (-1.2).ceil #=> -1 + * (-2.0).ceil #=> -2 + */ + +static mrb_value +flo_ceil(mrb_state *mrb, mrb_value num) +{ + mrb_float f = ceil(mrb_float(num)); + + mrb_check_num_exact(mrb, f); + if (!FIXABLE_FLOAT(f)) { + return mrb_float_value(mrb, f); + } + return mrb_fixnum_value((mrb_int)f); +} + +/* 15.2.9.3.12 */ +/* + * call-seq: + * flt.round([ndigits]) -> integer or float + * + * Rounds <i>flt</i> to a given precision in decimal digits (default 0 digits). + * Precision may be negative. Returns a floating point number when ndigits + * is more than zero. + * + * 1.4.round #=> 1 + * 1.5.round #=> 2 + * 1.6.round #=> 2 + * (-1.5).round #=> -2 + * + * 1.234567.round(2) #=> 1.23 + * 1.234567.round(3) #=> 1.235 + * 1.234567.round(4) #=> 1.2346 + * 1.234567.round(5) #=> 1.23457 + * + * 34567.89.round(-5) #=> 0 + * 34567.89.round(-4) #=> 30000 + * 34567.89.round(-3) #=> 35000 + * 34567.89.round(-2) #=> 34600 + * 34567.89.round(-1) #=> 34570 + * 34567.89.round(0) #=> 34568 + * 34567.89.round(1) #=> 34567.9 + * 34567.89.round(2) #=> 34567.89 + * 34567.89.round(3) #=> 34567.89 + * + */ + +static mrb_value +flo_round(mrb_state *mrb, mrb_value num) +{ + double number, f; + mrb_int ndigits = 0; + mrb_int i; + + mrb_get_args(mrb, "|i", &ndigits); + number = mrb_float(num); + + if (0 < ndigits && (isinf(number) || isnan(number))) { + return num; + } + mrb_check_num_exact(mrb, number); + + f = 1.0; + i = ndigits >= 0 ? ndigits : -ndigits; + while (--i >= 0) + f = f*10.0; + + if (isinf(f)) { + if (ndigits < 0) number = 0; + } + else { + double d; + + if (ndigits < 0) number /= f; + else number *= f; + + /* home-made inline implementation of round(3) */ + if (number > 0.0) { + d = floor(number); + number = d + (number - d >= 0.5); + } + else if (number < 0.0) { + d = ceil(number); + number = d - (d - number >= 0.5); + } + + if (ndigits < 0) number *= f; + else number /= f; + } + + if (ndigits > 0) { + if (!isfinite(number)) return num; + return mrb_float_value(mrb, number); + } + return mrb_fixnum_value((mrb_int)number); +} + +/* 15.2.9.3.14 */ +/* 15.2.9.3.15 */ +/* + * call-seq: + * flt.to_i -> integer + * flt.to_int -> integer + * flt.truncate -> integer + * + * Returns <i>flt</i> truncated to an <code>Integer</code>. + */ + +static mrb_value +flo_truncate(mrb_state *mrb, mrb_value num) +{ + mrb_float f = mrb_float(num); + + if (f > 0.0) f = floor(f); + if (f < 0.0) f = ceil(f); + + mrb_check_num_exact(mrb, f); + if (!FIXABLE_FLOAT(f)) { + return mrb_float_value(mrb, f); + } + return mrb_fixnum_value((mrb_int)f); +} + +static mrb_value +flo_nan_p(mrb_state *mrb, mrb_value num) +{ + return mrb_bool_value(isnan(mrb_float(num))); +} + +/* + * Document-class: Integer + * + * <code>Integer</code> is the basis for the two concrete classes that + * hold whole numbers, <code>Bignum</code> and <code>Fixnum</code>. + * + */ + + +/* + * call-seq: + * int.to_i -> integer + * int.to_int -> integer + * + * As <i>int</i> is already an <code>Integer</code>, all these + * methods simply return the receiver. + */ + +static mrb_value +int_to_i(mrb_state *mrb, mrb_value num) +{ + return num; +} + +mrb_value +mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) +{ + mrb_int a; + + a = mrb_fixnum(x); + if (mrb_fixnum_p(y)) { + mrb_int b, c; + + if (a == 0) return x; + b = mrb_fixnum(y); + if (mrb_int_mul_overflow(a, b, &c)) { + return mrb_float_value(mrb, (mrb_float)a * (mrb_float)b); + } + return mrb_fixnum_value(c); + } + return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y)); +} + +/* 15.2.8.3.3 */ +/* + * call-seq: + * fix * numeric -> numeric_result + * + * Performs multiplication: the class of the resulting object depends on + * the class of <code>numeric</code> and on the magnitude of the + * result. + */ + +static mrb_value +fix_mul(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + return mrb_fixnum_mul(mrb, x, y); +} + +static void +fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp) +{ + mrb_int div, mod; + + /* TODO: add mrb_assert(y != 0) to make sure */ + + if (y < 0) { + if (x < 0) + div = -x / -y; + else + div = - (x / -y); + } + else { + if (x < 0) + div = - (-x / y); + else + div = x / y; + } + mod = x - div*y; + if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) { + mod += y; + div -= 1; + } + if (divp) *divp = div; + if (modp) *modp = mod; +} + +/* 15.2.8.3.5 */ +/* + * call-seq: + * fix % other -> real + * fix.modulo(other) -> real + * + * Returns <code>fix</code> modulo <code>other</code>. + * See <code>numeric.divmod</code> for more information. + */ + +static mrb_value +fix_mod(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + mrb_int a; + + mrb_get_args(mrb, "o", &y); + a = mrb_fixnum(x); + if (mrb_fixnum_p(y)) { + mrb_int b, mod; + + if ((b=mrb_fixnum(y)) == 0) { + return mrb_float_value(mrb, NAN); + } + fixdivmod(mrb, a, b, 0, &mod); + return mrb_fixnum_value(mod); + } + else { + mrb_float mod; + + flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod); + return mrb_float_value(mrb, mod); + } +} + +/* + * call-seq: + * fix.divmod(numeric) -> array + * + * See <code>Numeric#divmod</code>. + */ +static mrb_value +fix_divmod(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + + if (mrb_fixnum_p(y)) { + mrb_int div, mod; + + if (mrb_fixnum(y) == 0) { + return mrb_assoc_new(mrb, ((mrb_fixnum(x) == 0) ? + mrb_float_value(mrb, NAN): + mrb_float_value(mrb, INFINITY)), + mrb_float_value(mrb, NAN)); + } + fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod); + return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod)); + } + else { + mrb_float div, mod; + mrb_value a, b; + + flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod); + a = mrb_float_value(mrb, div); + b = mrb_float_value(mrb, mod); + return mrb_assoc_new(mrb, a, b); + } +} + +static mrb_value +flo_divmod(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + mrb_float div, mod; + mrb_value a, b; + + mrb_get_args(mrb, "o", &y); + + flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod); + a = mrb_float_value(mrb, div); + b = mrb_float_value(mrb, mod); + return mrb_assoc_new(mrb, a, b); +} + +/* 15.2.8.3.7 */ +/* + * call-seq: + * fix == other -> true or false + * + * Return <code>true</code> if <code>fix</code> equals <code>other</code> + * numerically. + * + * 1 == 2 #=> false + * 1 == 1.0 #=> true + */ + +static mrb_value +fix_equal(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + switch (mrb_type(y)) { + case MRB_TT_FIXNUM: + return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y)); + case MRB_TT_FLOAT: + return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y)); + default: + return mrb_false_value(); + } +} + +/* 15.2.8.3.8 */ +/* + * call-seq: + * ~fix -> integer + * + * One's complement: returns a number where each bit is flipped. + * ex.0---00001 (1)-> 1---11110 (-2) + * ex.0---00010 (2)-> 1---11101 (-3) + * ex.0---00100 (4)-> 1---11011 (-5) + */ + +static mrb_value +fix_rev(mrb_state *mrb, mrb_value num) +{ + mrb_int val = mrb_fixnum(num); + + return mrb_fixnum_value(~val); +} + +static mrb_value flo_and(mrb_state *mrb, mrb_value x); +static mrb_value flo_or(mrb_state *mrb, mrb_value x); +static mrb_value flo_xor(mrb_state *mrb, mrb_value x); +#define bit_op(x,y,op1,op2) do {\ + if (mrb_fixnum_p(y)) return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\ + return flo_ ## op1(mrb, mrb_float_value(mrb, mrb_fixnum(x)));\ +} while(0) + +/* 15.2.8.3.9 */ +/* + * call-seq: + * fix & integer -> integer_result + * + * Bitwise AND. + */ + +static mrb_value +fix_and(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + bit_op(x, y, and, &); +} + +/* 15.2.8.3.10 */ +/* + * call-seq: + * fix | integer -> integer_result + * + * Bitwise OR. + */ + +static mrb_value +fix_or(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + bit_op(x, y, or, |); +} + +/* 15.2.8.3.11 */ +/* + * call-seq: + * fix ^ integer -> integer_result + * + * Bitwise EXCLUSIVE OR. + */ + +static mrb_value +fix_xor(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + bit_op(x, y, or, ^); +} + +#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1) + +static mrb_value +lshift(mrb_state *mrb, mrb_int val, mrb_int width) +{ + if (width < 0) { /* mrb_int overflow */ + return mrb_float_value(mrb, INFINITY); + } + if (val > 0) { + if ((width > NUMERIC_SHIFT_WIDTH_MAX) || + (val > (MRB_INT_MAX >> width))) { + goto bit_overflow; + } + return mrb_fixnum_value(val << width); + } + else { + if ((width > NUMERIC_SHIFT_WIDTH_MAX) || + (val < (MRB_INT_MIN >> width))) { + goto bit_overflow; + } + return mrb_fixnum_value(val * (1u << width)); + } + +bit_overflow: + { + mrb_float f = (mrb_float)val; + while (width--) { + f *= 2; + } + return mrb_float_value(mrb, f); + } +} + +static mrb_value +rshift(mrb_int val, mrb_int width) +{ + if (width < 0) { /* mrb_int overflow */ + return mrb_fixnum_value(0); + } + if (width >= NUMERIC_SHIFT_WIDTH_MAX) { + if (val < 0) { + return mrb_fixnum_value(-1); + } + return mrb_fixnum_value(0); + } + return mrb_fixnum_value(val >> width); +} + +/* 15.2.8.3.12 */ +/* + * call-seq: + * fix << count -> integer or float + * + * Shifts _fix_ left _count_ positions (right if _count_ is negative). + */ + +static mrb_value +fix_lshift(mrb_state *mrb, mrb_value x) +{ + mrb_int width, val; + + mrb_get_args(mrb, "i", &width); + if (width == 0) { + return x; + } + val = mrb_fixnum(x); + if (val == 0) return x; + if (width < 0) { + return rshift(val, -width); + } + return lshift(mrb, val, width); +} + +/* 15.2.8.3.13 */ +/* + * call-seq: + * fix >> count -> integer or float + * + * Shifts _fix_ right _count_ positions (left if _count_ is negative). + */ + +static mrb_value +fix_rshift(mrb_state *mrb, mrb_value x) +{ + mrb_int width, val; + + mrb_get_args(mrb, "i", &width); + if (width == 0) { + return x; + } + val = mrb_fixnum(x); + if (val == 0) return x; + if (width < 0) { + return lshift(mrb, val, -width); + } + return rshift(val, width); +} + +/* 15.2.8.3.23 */ +/* + * call-seq: + * fix.to_f -> float + * + * Converts <i>fix</i> to a <code>Float</code>. + * + */ + +static mrb_value +fix_to_f(mrb_state *mrb, mrb_value num) +{ + return mrb_float_value(mrb, (mrb_float)mrb_fixnum(num)); +} + +/* + * Document-class: FloatDomainError + * + * Raised when attempting to convert special float values + * (in particular infinite or NaN) + * to numerical classes which don't support them. + * + * Float::INFINITY.to_r + * + * <em>raises the exception:</em> + * + * FloatDomainError: Infinity + */ +/* ------------------------------------------------------------------------*/ +MRB_API mrb_value +mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) +{ + mrb_int z = 0; + + if (!mrb_float_p(x)) { + mrb_raise(mrb, E_TYPE_ERROR, "non float value"); + z = 0; /* not reached. just suppress warnings. */ + } + else { + mrb_float d = mrb_float(x); + + if (isinf(d)) { + mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity"); + } + if (isnan(d)) { + mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN"); + } + if (FIXABLE_FLOAT(d)) { + z = (mrb_int)d; + } + else { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x); + } + } + return mrb_fixnum_value(z); +} + +mrb_value +mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + mrb_int a; + + a = mrb_fixnum(x); + if (mrb_fixnum_p(y)) { + mrb_int b, c; + + if (a == 0) return y; + b = mrb_fixnum(y); + if (mrb_int_add_overflow(a, b, &c)) { + return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b); + } + return mrb_fixnum_value(c); + } + return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y)); +} + +/* 15.2.8.3.1 */ +/* + * call-seq: + * fix + numeric -> numeric_result + * + * Performs addition: the class of the resulting object depends on + * the class of <code>numeric</code> and on the magnitude of the + * result. + */ +static mrb_value +fix_plus(mrb_state *mrb, mrb_value self) +{ + mrb_value other; + + mrb_get_args(mrb, "o", &other); + return mrb_fixnum_plus(mrb, self, other); +} + +mrb_value +mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + mrb_int a; + + a = mrb_fixnum(x); + if (mrb_fixnum_p(y)) { + mrb_int b, c; + + b = mrb_fixnum(y); + if (mrb_int_sub_overflow(a, b, &c)) { + return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b); + } + return mrb_fixnum_value(c); + } + return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y)); +} + +/* 15.2.8.3.2 */ +/* 15.2.8.3.16 */ +/* + * call-seq: + * fix - numeric -> numeric_result + * + * Performs subtraction: the class of the resulting object depends on + * the class of <code>numeric</code> and on the magnitude of the + * result. + */ +static mrb_value +fix_minus(mrb_state *mrb, mrb_value self) +{ + mrb_value other; + + mrb_get_args(mrb, "o", &other); + return mrb_fixnum_minus(mrb, self, other); +} + + +MRB_API mrb_value +mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base) +{ + char buf[MRB_INT_BIT+1]; + char *b = buf + sizeof buf; + mrb_int val = mrb_fixnum(x); + + if (base < 2 || 36 < base) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base)); + } + + if (val == 0) { + *--b = '0'; + } + else if (val < 0) { + do { + *--b = mrb_digitmap[-(val % base)]; + } while (val /= base); + *--b = '-'; + } + else { + do { + *--b = mrb_digitmap[(int)(val % base)]; + } while (val /= base); + } + + return mrb_str_new(mrb, b, buf + sizeof(buf) - b); +} + +/* 15.2.8.3.25 */ +/* + * call-seq: + * fix.to_s(base=10) -> string + * + * Returns a string containing the representation of <i>fix</i> radix + * <i>base</i> (between 2 and 36). + * + * 12345.to_s #=> "12345" + * 12345.to_s(2) #=> "11000000111001" + * 12345.to_s(8) #=> "30071" + * 12345.to_s(10) #=> "12345" + * 12345.to_s(16) #=> "3039" + * 12345.to_s(36) #=> "9ix" + * + */ +static mrb_value +fix_to_s(mrb_state *mrb, mrb_value self) +{ + mrb_int base = 10; + + mrb_get_args(mrb, "|i", &base); + return mrb_fixnum_to_str(mrb, self, base); +} + +/* 15.2.9.3.6 */ +/* + * call-seq: + * self.f <=> other.f => -1, 0, +1 + * < => -1 + * = => 0 + * > => +1 + * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is + * less than, equal to, or greater than <i>numeric</i>. This is the + * basis for the tests in <code>Comparable</code>. + */ +static mrb_value +num_cmp(mrb_state *mrb, mrb_value self) +{ + mrb_value other; + mrb_float x, y; + + mrb_get_args(mrb, "o", &other); + + x = mrb_to_flo(mrb, self); + switch (mrb_type(other)) { + case MRB_TT_FIXNUM: + y = (mrb_float)mrb_fixnum(other); + break; + case MRB_TT_FLOAT: + y = mrb_float(other); + break; + default: + return mrb_nil_value(); + } + if (x > y) + return mrb_fixnum_value(1); + else { + if (x < y) + return mrb_fixnum_value(-1); + return mrb_fixnum_value(0); + } +} + +/* 15.2.9.3.1 */ +/* + * call-seq: + * float + other -> float + * + * Returns a new float which is the sum of <code>float</code> + * and <code>other</code>. + */ +static mrb_value +flo_plus(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + + mrb_get_args(mrb, "o", &y); + return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y)); +} + +/* ------------------------------------------------------------------------*/ +void +mrb_init_numeric(mrb_state *mrb) +{ + struct RClass *numeric, *integer, *fixnum, *fl; + + /* Numeric Class */ + numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ + + mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ + mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ + + /* Integer Class */ + integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ + MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM); + mrb_undef_class_method(mrb, integer, "new"); + mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ + mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE()); + mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */ + mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */ + mrb_define_method(mrb, integer, "round", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 (x) */ + mrb_define_method(mrb, integer, "truncate", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.15 (x) */ + + /* Fixnum Class */ + mrb->fixnum_class = fixnum = mrb_define_class(mrb, "Fixnum", integer); + mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */ + mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */ + mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */ + mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */ + mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */ + mrb_define_method(mrb, fixnum, "~", fix_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */ + mrb_define_method(mrb, fixnum, "&", fix_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */ + mrb_define_method(mrb, fixnum, "|", fix_or, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */ + mrb_define_method(mrb, fixnum, "^", fix_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */ + mrb_define_method(mrb, fixnum, "<<", fix_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */ + mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */ + mrb_define_method(mrb, fixnum, "eql?", fix_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */ + mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */ + mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_NONE()); /* 15.2.8.3.25 */ + mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */ + + /* Float Class */ + mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */ + MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT); + mrb_undef_class_method(mrb, fl, "new"); + mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */ + mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */ + mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */ + mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */ + mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */ + mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE()); + mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */ + mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */ + mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */ + mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */ + mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */ + mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ + mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ + mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE()); + mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */ + mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */ + + mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */ + mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE()); + +#ifdef INFINITY + mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY)); +#endif +#ifdef NAN + mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN)); +#endif +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/object.c b/web/server/h2o/libh2o/deps/mruby/src/object.c new file mode 100644 index 000000000..368e90b9f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/object.c @@ -0,0 +1,610 @@ +/* +** object.c - Object, NilClass, TrueClass, FalseClass class +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/numeric.h> +#include <mruby/string.h> +#include <mruby/class.h> + +MRB_API mrb_bool +mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2) +{ + if (mrb_type(v1) != mrb_type(v2)) return FALSE; + switch (mrb_type(v1)) { + case MRB_TT_TRUE: + return TRUE; + + case MRB_TT_FALSE: + case MRB_TT_FIXNUM: + return (mrb_fixnum(v1) == mrb_fixnum(v2)); + case MRB_TT_SYMBOL: + return (mrb_symbol(v1) == mrb_symbol(v2)); + + case MRB_TT_FLOAT: + return (mrb_float(v1) == mrb_float(v2)); + + default: + return (mrb_ptr(v1) == mrb_ptr(v2)); + } +} + +MRB_API mrb_bool +mrb_obj_equal(mrb_state *mrb, mrb_value v1, mrb_value v2) +{ + /* temporary definition */ + return mrb_obj_eq(mrb, v1, v2); +} + +MRB_API mrb_bool +mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2) +{ + mrb_value result; + + if (mrb_obj_eq(mrb, obj1, obj2)) return TRUE; + result = mrb_funcall(mrb, obj1, "==", 1, obj2); + if (mrb_test(result)) return TRUE; + return FALSE; +} + +/* + * Document-class: NilClass + * + * The class of the singleton object <code>nil</code>. + */ + +/* 15.2.4.3.4 */ +/* + * call_seq: + * nil.nil? -> true + * + * Only the object <i>nil</i> responds <code>true</code> to <code>nil?</code>. + */ + +static mrb_value +mrb_true(mrb_state *mrb, mrb_value obj) +{ + return mrb_true_value(); +} + +/* 15.2.4.3.5 */ +/* + * call-seq: + * nil.to_s -> "" + * + * Always returns the empty string. + */ + +static mrb_value +nil_to_s(mrb_state *mrb, mrb_value obj) +{ + return mrb_str_new(mrb, 0, 0); +} + +static mrb_value +nil_inspect(mrb_state *mrb, mrb_value obj) +{ + return mrb_str_new_lit(mrb, "nil"); +} + +/*********************************************************************** + * Document-class: TrueClass + * + * The global value <code>true</code> is the only instance of class + * <code>TrueClass</code> and represents a logically true value in + * boolean expressions. The class provides operators allowing + * <code>true</code> to be used in logical expressions. + */ + +/* 15.2.5.3.1 */ +/* + * call-seq: + * true & obj -> true or false + * + * And---Returns <code>false</code> if <i>obj</i> is + * <code>nil</code> or <code>false</code>, <code>true</code> otherwise. + */ + +static mrb_value +true_and(mrb_state *mrb, mrb_value obj) +{ + mrb_bool obj2; + + mrb_get_args(mrb, "b", &obj2); + + return mrb_bool_value(obj2); +} + +/* 15.2.5.3.2 */ +/* + * call-seq: + * true ^ obj -> !obj + * + * Exclusive Or---Returns <code>true</code> if <i>obj</i> is + * <code>nil</code> or <code>false</code>, <code>false</code> + * otherwise. + */ + +static mrb_value +true_xor(mrb_state *mrb, mrb_value obj) +{ + mrb_bool obj2; + + mrb_get_args(mrb, "b", &obj2); + return mrb_bool_value(!obj2); +} + +/* 15.2.5.3.3 */ +/* + * call-seq: + * true.to_s -> "true" + * + * The string representation of <code>true</code> is "true". + */ + +static mrb_value +true_to_s(mrb_state *mrb, mrb_value obj) +{ + return mrb_str_new_lit(mrb, "true"); +} + +/* 15.2.5.3.4 */ +/* + * call-seq: + * true | obj -> true + * + * Or---Returns <code>true</code>. As <i>anObject</i> is an argument to + * a method call, it is always evaluated; there is no short-circuit + * evaluation in this case. + * + * true | puts("or") + * true || puts("logical or") + * + * <em>produces:</em> + * + * or + */ + +static mrb_value +true_or(mrb_state *mrb, mrb_value obj) +{ + return mrb_true_value(); +} + +/* + * Document-class: FalseClass + * + * The global value <code>false</code> is the only instance of class + * <code>FalseClass</code> and represents a logically false value in + * boolean expressions. The class provides operators allowing + * <code>false</code> to participate correctly in logical expressions. + * + */ + +/* 15.2.4.3.1 */ +/* 15.2.6.3.1 */ +/* + * call-seq: + * false & obj -> false + * nil & obj -> false + * + * And---Returns <code>false</code>. <i>obj</i> is always + * evaluated as it is the argument to a method call---there is no + * short-circuit evaluation in this case. + */ + +static mrb_value +false_and(mrb_state *mrb, mrb_value obj) +{ + return mrb_false_value(); +} + +/* 15.2.4.3.2 */ +/* 15.2.6.3.2 */ +/* + * call-seq: + * false ^ obj -> true or false + * nil ^ obj -> true or false + * + * Exclusive Or---If <i>obj</i> is <code>nil</code> or + * <code>false</code>, returns <code>false</code>; otherwise, returns + * <code>true</code>. + * + */ + +static mrb_value +false_xor(mrb_state *mrb, mrb_value obj) +{ + mrb_bool obj2; + + mrb_get_args(mrb, "b", &obj2); + return mrb_bool_value(obj2); +} + +/* 15.2.4.3.3 */ +/* 15.2.6.3.4 */ +/* + * call-seq: + * false | obj -> true or false + * nil | obj -> true or false + * + * Or---Returns <code>false</code> if <i>obj</i> is + * <code>nil</code> or <code>false</code>; <code>true</code> otherwise. + */ + +static mrb_value +false_or(mrb_state *mrb, mrb_value obj) +{ + mrb_bool obj2; + + mrb_get_args(mrb, "b", &obj2); + return mrb_bool_value(obj2); +} + +/* 15.2.6.3.3 */ +/* + * call-seq: + * false.to_s -> "false" + * + * 'nuf said... + */ + +static mrb_value +false_to_s(mrb_state *mrb, mrb_value obj) +{ + return mrb_str_new_lit(mrb, "false"); +} + +void +mrb_init_object(mrb_state *mrb) +{ + struct RClass *n; + struct RClass *t; + struct RClass *f; + + mrb->nil_class = n = mrb_define_class(mrb, "NilClass", mrb->object_class); + MRB_SET_INSTANCE_TT(n, MRB_TT_TRUE); + mrb_undef_class_method(mrb, n, "new"); + mrb_define_method(mrb, n, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.4.3.1 */ + mrb_define_method(mrb, n, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.4.3.2 */ + mrb_define_method(mrb, n, "|", false_or, MRB_ARGS_REQ(1)); /* 15.2.4.3.3 */ + mrb_define_method(mrb, n, "nil?", mrb_true, MRB_ARGS_NONE()); /* 15.2.4.3.4 */ + mrb_define_method(mrb, n, "to_s", nil_to_s, MRB_ARGS_NONE()); /* 15.2.4.3.5 */ + mrb_define_method(mrb, n, "inspect", nil_inspect, MRB_ARGS_NONE()); + + mrb->true_class = t = mrb_define_class(mrb, "TrueClass", mrb->object_class); + MRB_SET_INSTANCE_TT(t, MRB_TT_TRUE); + mrb_undef_class_method(mrb, t, "new"); + mrb_define_method(mrb, t, "&", true_and, MRB_ARGS_REQ(1)); /* 15.2.5.3.1 */ + mrb_define_method(mrb, t, "^", true_xor, MRB_ARGS_REQ(1)); /* 15.2.5.3.2 */ + mrb_define_method(mrb, t, "to_s", true_to_s, MRB_ARGS_NONE()); /* 15.2.5.3.3 */ + mrb_define_method(mrb, t, "|", true_or, MRB_ARGS_REQ(1)); /* 15.2.5.3.4 */ + mrb_define_method(mrb, t, "inspect", true_to_s, MRB_ARGS_NONE()); + + mrb->false_class = f = mrb_define_class(mrb, "FalseClass", mrb->object_class); + MRB_SET_INSTANCE_TT(f, MRB_TT_TRUE); + mrb_undef_class_method(mrb, f, "new"); + mrb_define_method(mrb, f, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.6.3.1 */ + mrb_define_method(mrb, f, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.6.3.2 */ + mrb_define_method(mrb, f, "to_s", false_to_s, MRB_ARGS_NONE()); /* 15.2.6.3.3 */ + mrb_define_method(mrb, f, "|", false_or, MRB_ARGS_REQ(1)); /* 15.2.6.3.4 */ + mrb_define_method(mrb, f, "inspect", false_to_s, MRB_ARGS_NONE()); +} + +static mrb_value +inspect_type(mrb_state *mrb, mrb_value val) +{ + if (mrb_type(val) == MRB_TT_FALSE || mrb_type(val) == MRB_TT_TRUE) { + return mrb_inspect(mrb, val); + } + else { + return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, val)); + } +} + +static mrb_value +convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *method, mrb_bool raise) +{ + mrb_sym m = 0; + + m = mrb_intern_cstr(mrb, method); + if (!mrb_respond_to(mrb, val, m)) { + if (raise) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into %S", inspect_type(mrb, val), mrb_str_new_cstr(mrb, tname)); + } + return mrb_nil_value(); + } + return mrb_funcall_argv(mrb, val, m, 0, 0); +} + +MRB_API mrb_value +mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method) +{ + mrb_value v; + + if (mrb_fixnum_p(val)) return val; + v = convert_type(mrb, val, "Integer", method, FALSE); + if (mrb_nil_p(v) || !mrb_fixnum_p(v)) { + return mrb_nil_value(); + } + return v; +} + +MRB_API mrb_value +mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method) +{ + mrb_value v; + + if (mrb_type(val) == type) return val; + v = convert_type(mrb, val, tname, method, TRUE); + if (mrb_type(v) != type) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to %S by #%S", val, + mrb_str_new_cstr(mrb, tname), mrb_str_new_cstr(mrb, method)); + } + return v; +} + +MRB_API mrb_value +mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method) +{ + mrb_value v; + + if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_ISTRUCT) return val; + v = convert_type(mrb, val, tname, method, FALSE); + if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value(); + return v; +} + +static const struct types { + unsigned char type; + const char *name; +} builtin_types[] = { +/* {MRB_TT_NIL, "nil"}, */ + {MRB_TT_FALSE, "false"}, + {MRB_TT_TRUE, "true"}, + {MRB_TT_FIXNUM, "Fixnum"}, + {MRB_TT_SYMBOL, "Symbol"}, /* :symbol */ + {MRB_TT_MODULE, "Module"}, + {MRB_TT_OBJECT, "Object"}, + {MRB_TT_CLASS, "Class"}, + {MRB_TT_ICLASS, "iClass"}, /* internal use: mixed-in module holder */ + {MRB_TT_SCLASS, "SClass"}, + {MRB_TT_PROC, "Proc"}, + {MRB_TT_FLOAT, "Float"}, + {MRB_TT_ARRAY, "Array"}, + {MRB_TT_HASH, "Hash"}, + {MRB_TT_STRING, "String"}, + {MRB_TT_RANGE, "Range"}, +/* {MRB_TT_BIGNUM, "Bignum"}, */ + {MRB_TT_FILE, "File"}, + {MRB_TT_DATA, "Data"}, /* internal use: wrapped C pointers */ +/* {MRB_TT_VARMAP, "Varmap"}, */ /* internal use: dynamic variables */ +/* {MRB_TT_NODE, "Node"}, */ /* internal use: syntax tree node */ +/* {MRB_TT_UNDEF, "undef"}, */ /* internal use: #undef; should not happen */ + {MRB_TT_MAXDEFINE, 0} +}; + +MRB_API void +mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) +{ + const struct types *type = builtin_types; + enum mrb_vtype xt; + + xt = mrb_type(x); + if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_ISTRUCT)) { + while (type->type < MRB_TT_MAXDEFINE) { + if (type->type == t) { + const char *etype; + + if (mrb_nil_p(x)) { + etype = "nil"; + } + else if (mrb_fixnum_p(x)) { + etype = "Fixnum"; + } + else if (mrb_type(x) == MRB_TT_SYMBOL) { + etype = "Symbol"; + } + else if (mrb_immediate_p(x)) { + etype = RSTRING_PTR(mrb_obj_as_string(mrb, x)); + } + else { + etype = mrb_obj_classname(mrb, x); + } + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)", + mrb_str_new_cstr(mrb, etype), mrb_str_new_cstr(mrb, type->name)); + } + type++; + } + mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %S (%S given)", + mrb_fixnum_value(t), mrb_fixnum_value(mrb_type(x))); + } +} + +/* 15.3.1.3.46 */ +/* + * call-seq: + * obj.to_s => string + * + * Returns a string representing <i>obj</i>. The default + * <code>to_s</code> prints the object's class and an encoding of the + * object id. As a special case, the top-level object that is the + * initial execution context of Ruby programs returns "main." + */ + +MRB_API mrb_value +mrb_any_to_s(mrb_state *mrb, mrb_value obj) +{ + mrb_value str = mrb_str_new_capa(mrb, 20); + const char *cname = mrb_obj_classname(mrb, obj); + + mrb_str_cat_lit(mrb, str, "#<"); + mrb_str_cat_cstr(mrb, str, cname); + mrb_str_cat_lit(mrb, str, ":"); + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); + mrb_str_cat_lit(mrb, str, ">"); + + return str; +} + +/* + * call-seq: + * obj.is_a?(class) => true or false + * obj.kind_of?(class) => true or false + * + * Returns <code>true</code> if <i>class</i> is the class of + * <i>obj</i>, or if <i>class</i> is one of the superclasses of + * <i>obj</i> or modules included in <i>obj</i>. + * + * module M; end + * class A + * include M + * end + * class B < A; end + * class C < B; end + * b = B.new + * b.instance_of? A #=> false + * b.instance_of? B #=> true + * b.instance_of? C #=> false + * b.instance_of? M #=> false + * b.kind_of? A #=> true + * b.kind_of? B #=> true + * b.kind_of? C #=> false + * b.kind_of? M #=> true + */ + +MRB_API mrb_bool +mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) +{ + struct RClass *cl = mrb_class(mrb, obj); + + switch (c->tt) { + case MRB_TT_MODULE: + case MRB_TT_CLASS: + case MRB_TT_ICLASS: + case MRB_TT_SCLASS: + break; + + default: + mrb_raise(mrb, E_TYPE_ERROR, "class or module required"); + } + + MRB_CLASS_ORIGIN(c); + while (cl) { + if (cl == c || cl->mt == c->mt) + return TRUE; + cl = cl->super; + } + return FALSE; +} + +static mrb_value +mrb_to_integer(mrb_state *mrb, mrb_value val, const char *method) +{ + mrb_value v; + + if (mrb_fixnum_p(val)) return val; + v = convert_type(mrb, val, "Integer", method, TRUE); + if (!mrb_obj_is_kind_of(mrb, v, mrb->fixnum_class)) { + mrb_value type = inspect_type(mrb, val); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer (%S#%S gives %S)", + type, type, mrb_str_new_cstr(mrb, method), inspect_type(mrb, v)); + } + return v; +} + +MRB_API mrb_value +mrb_to_int(mrb_state *mrb, mrb_value val) +{ + return mrb_to_integer(mrb, val, "to_int"); +} + +MRB_API mrb_value +mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base) +{ + mrb_value tmp; + + if (mrb_nil_p(val)) { + if (base != 0) goto arg_error; + mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); + } + switch (mrb_type(val)) { + case MRB_TT_FLOAT: + if (base != 0) goto arg_error; + else { + mrb_float f = mrb_float(val); + if (FIXABLE_FLOAT(f)) { + break; + } + } + return mrb_flo_to_fixnum(mrb, val); + + case MRB_TT_FIXNUM: + if (base != 0) goto arg_error; + return val; + + case MRB_TT_STRING: + string_conv: + return mrb_str_to_inum(mrb, val, base, TRUE); + + default: + break; + } + if (base != 0) { + tmp = mrb_check_string_type(mrb, val); + if (!mrb_nil_p(tmp)) { + val = tmp; + goto string_conv; + } +arg_error: + mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value"); + } + tmp = convert_type(mrb, val, "Integer", "to_int", FALSE); + if (mrb_nil_p(tmp)) { + return mrb_to_integer(mrb, val, "to_i"); + } + return tmp; +} + +MRB_API mrb_value +mrb_Integer(mrb_state *mrb, mrb_value val) +{ + return mrb_convert_to_integer(mrb, val, 0); +} + +MRB_API mrb_value +mrb_Float(mrb_state *mrb, mrb_value val) +{ + if (mrb_nil_p(val)) { + mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Float"); + } + switch (mrb_type(val)) { + case MRB_TT_FIXNUM: + return mrb_float_value(mrb, (mrb_float)mrb_fixnum(val)); + + case MRB_TT_FLOAT: + return val; + + case MRB_TT_STRING: + return mrb_float_value(mrb, mrb_str_to_dbl(mrb, val, TRUE)); + + default: + return mrb_convert_type(mrb, val, MRB_TT_FLOAT, "Float", "to_f"); + } +} + +MRB_API mrb_value +mrb_inspect(mrb_state *mrb, mrb_value obj) +{ + return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "inspect", 0)); +} + +MRB_API mrb_bool +mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2) +{ + if (mrb_obj_eq(mrb, obj1, obj2)) return TRUE; + return mrb_test(mrb_funcall(mrb, obj1, "eql?", 1, obj2)); +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/opcode.h b/web/server/h2o/libh2o/deps/mruby/src/opcode.h new file mode 100644 index 000000000..fe4d17a21 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/opcode.h @@ -0,0 +1,2 @@ +/* this header file is to be removed soon. */ +#include <mruby/opcode.h> diff --git a/web/server/h2o/libh2o/deps/mruby/src/pool.c b/web/server/h2o/libh2o/deps/mruby/src/pool.c new file mode 100644 index 000000000..db4546abf --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/pool.c @@ -0,0 +1,198 @@ +/* +** pool.c - memory pool +** +** See Copyright Notice in mruby.h +*/ + +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <mruby.h> + +/* configuration section */ +/* allocated memory address should be multiple of POOL_ALIGNMENT */ +/* or undef it if alignment does not matter */ +#ifndef POOL_ALIGNMENT +#if INTPTR_MAX == INT64_MAX +#define POOL_ALIGNMENT 8 +#else +#define POOL_ALIGNMENT 4 +#endif +#endif +/* page size of memory pool */ +#ifndef POOL_PAGE_SIZE +#define POOL_PAGE_SIZE 16000 +#endif +/* end of configuration section */ + +struct mrb_pool_page { + struct mrb_pool_page *next; + size_t offset; + size_t len; + void *last; + char page[]; +}; + +struct mrb_pool { + mrb_state *mrb; + struct mrb_pool_page *pages; +}; + +#undef TEST_POOL +#ifdef TEST_POOL + +#define mrb_malloc_simple(m,s) malloc(s) +#define mrb_free(m,p) free(p) +#endif + +#ifdef POOL_ALIGNMENT +# define ALIGN_PADDING(x) ((SIZE_MAX - (x) + 1) & (POOL_ALIGNMENT - 1)) +#else +# define ALIGN_PADDING(x) (0) +#endif + +MRB_API mrb_pool* +mrb_pool_open(mrb_state *mrb) +{ + mrb_pool *pool = (mrb_pool *)mrb_malloc_simple(mrb, sizeof(mrb_pool)); + + if (pool) { + pool->mrb = mrb; + pool->pages = NULL; + } + + return pool; +} + +MRB_API void +mrb_pool_close(mrb_pool *pool) +{ + struct mrb_pool_page *page, *tmp; + + if (!pool) return; + page = pool->pages; + while (page) { + tmp = page; + page = page->next; + mrb_free(pool->mrb, tmp); + } + mrb_free(pool->mrb, pool); +} + +static struct mrb_pool_page* +page_alloc(mrb_pool *pool, size_t len) +{ + struct mrb_pool_page *page; + + if (len < POOL_PAGE_SIZE) + len = POOL_PAGE_SIZE; + page = (struct mrb_pool_page *)mrb_malloc_simple(pool->mrb, sizeof(struct mrb_pool_page)+len); + if (page) { + page->offset = 0; + page->len = len; + } + + return page; +} + +MRB_API void* +mrb_pool_alloc(mrb_pool *pool, size_t len) +{ + struct mrb_pool_page *page; + size_t n; + + if (!pool) return NULL; + len += ALIGN_PADDING(len); + page = pool->pages; + while (page) { + if (page->offset + len <= page->len) { + n = page->offset; + page->offset += len; + page->last = (char*)page->page+n; + return page->last; + } + page = page->next; + } + page = page_alloc(pool, len); + if (!page) return NULL; + page->offset = len; + page->next = pool->pages; + pool->pages = page; + + page->last = (void*)page->page; + return page->last; +} + +MRB_API mrb_bool +mrb_pool_can_realloc(mrb_pool *pool, void *p, size_t len) +{ + struct mrb_pool_page *page; + + if (!pool) return FALSE; + len += ALIGN_PADDING(len); + page = pool->pages; + while (page) { + if (page->last == p) { + size_t beg; + + beg = (char*)p - page->page; + if (beg + len > page->len) return FALSE; + return TRUE; + } + page = page->next; + } + return FALSE; +} + +MRB_API void* +mrb_pool_realloc(mrb_pool *pool, void *p, size_t oldlen, size_t newlen) +{ + struct mrb_pool_page *page; + void *np; + + if (!pool) return NULL; + oldlen += ALIGN_PADDING(oldlen); + newlen += ALIGN_PADDING(newlen); + page = pool->pages; + while (page) { + if (page->last == p) { + size_t beg; + + beg = (char*)p - page->page; + if (beg + oldlen != page->offset) break; + if (beg + newlen > page->len) { + page->offset = beg; + break; + } + page->offset = beg + newlen; + return p; + } + page = page->next; + } + np = mrb_pool_alloc(pool, newlen); + if (np == NULL) { + return NULL; + } + memcpy(np, p, oldlen); + return np; +} + +#ifdef TEST_POOL +int +main(void) +{ + int i, len = 250; + mrb_pool *pool; + void *p; + + pool = mrb_pool_open(NULL); + p = mrb_pool_alloc(pool, len); + for (i=1; i<20; i++) { + printf("%p (len=%d) %ud\n", p, len, mrb_pool_can_realloc(pool, p, len*2)); + p = mrb_pool_realloc(pool, p, len, len*2); + len *= 2; + } + mrb_pool_close(pool); + return 0; +} +#endif diff --git a/web/server/h2o/libh2o/deps/mruby/src/print.c b/web/server/h2o/libh2o/deps/mruby/src/print.c new file mode 100644 index 000000000..03b5eadfa --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/print.c @@ -0,0 +1,47 @@ +/* +** print.c - Kernel.#p +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/string.h> +#include <mruby/variable.h> + +#ifndef MRB_DISABLE_STDIO +static void +printstr(mrb_value obj, FILE *stream) +{ + if (mrb_string_p(obj)) { + fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stream); + putc('\n', stream); + } +} +#else +# define printstr(obj, stream) (void)0 +#endif + +MRB_API void +mrb_p(mrb_state *mrb, mrb_value obj) +{ + printstr(mrb_inspect(mrb, obj), stdout); +} + +MRB_API void +mrb_print_error(mrb_state *mrb) +{ + mrb_print_backtrace(mrb); + printstr(mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0), stderr); +} + +MRB_API void +mrb_show_version(mrb_state *mrb) +{ + printstr(mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_DESCRIPTION")), stdout); +} + +MRB_API void +mrb_show_copyright(mrb_state *mrb) +{ + printstr(mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "MRUBY_COPYRIGHT")), stdout); +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/proc.c b/web/server/h2o/libh2o/deps/mruby/src/proc.c new file mode 100644 index 000000000..10a2c4f33 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/proc.c @@ -0,0 +1,294 @@ +/* +** proc.c - Proc class +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/proc.h> +#include <mruby/opcode.h> + +static mrb_code call_iseq[] = { + MKOP_A(OP_CALL, 0), +}; + +struct RProc* +mrb_proc_new(mrb_state *mrb, mrb_irep *irep) +{ + struct RProc *p; + mrb_callinfo *ci = mrb->c->ci; + + p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + p->target_class = 0; + if (ci) { + if (ci->proc) + p->target_class = ci->proc->target_class; + if (!p->target_class) + p->target_class = ci->target_class; + } + p->body.irep = irep; + p->env = 0; + mrb_irep_incref(mrb, irep); + + return p; +} + +static struct REnv* +env_new(mrb_state *mrb, int nlocals) +{ + struct REnv *e; + + e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env); + MRB_SET_ENV_STACK_LEN(e, nlocals); + e->cxt.c = mrb->c; + e->cioff = mrb->c->ci - mrb->c->cibase; + e->stack = mrb->c->stack; + + return e; +} + +static void +closure_setup(mrb_state *mrb, struct RProc *p, int nlocals) +{ + struct REnv *e; + + if (!mrb->c->ci->env) { + e = env_new(mrb, nlocals); + mrb->c->ci->env = e; + } + else { + e = mrb->c->ci->env; + } + p->env = e; + mrb_field_write_barrier(mrb, (struct RBasic *)p, (struct RBasic *)p->env); +} + +struct RProc* +mrb_closure_new(mrb_state *mrb, mrb_irep *irep) +{ + struct RProc *p = mrb_proc_new(mrb, irep); + + closure_setup(mrb, p, mrb->c->ci->proc->body.irep->nlocals); + return p; +} + +MRB_API struct RProc* +mrb_proc_new_cfunc(mrb_state *mrb, mrb_func_t func) +{ + struct RProc *p; + + p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + p->body.func = func; + p->flags |= MRB_PROC_CFUNC; + p->env = 0; + + return p; +} + +MRB_API struct RProc* +mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const mrb_value *argv) +{ + struct RProc *p = mrb_proc_new_cfunc(mrb, func); + struct REnv *e; + int i; + + p->env = e = env_new(mrb, argc); + mrb_field_write_barrier(mrb, (struct RBasic *)p, (struct RBasic *)p->env); + MRB_ENV_UNSHARE_STACK(e); + e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc); + if (argv) { + for (i = 0; i < argc; ++i) { + e->stack[i] = argv[i]; + } + } + else { + for (i = 0; i < argc; ++i) { + SET_NIL_VALUE(e->stack[i]); + } + } + return p; +} + +MRB_API struct RProc* +mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals) +{ + return mrb_proc_new_cfunc_with_env(mrb, func, nlocals, NULL); +} + +MRB_API mrb_value +mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx) +{ + struct RProc *p = mrb->c->ci->proc; + struct REnv *e = p->env; + + if (!MRB_PROC_CFUNC_P(p)) { + mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc."); + } + if (!e) { + mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv."); + } + if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) { + mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)", + mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e))); + } + + return e->stack[idx]; +} + +void +mrb_proc_copy(struct RProc *a, struct RProc *b) +{ + if (a->body.irep) { + /* already initialized proc */ + return; + } + a->flags = b->flags; + a->body = b->body; + if (!MRB_PROC_CFUNC_P(a) && a->body.irep) { + a->body.irep->refcnt++; + } + a->target_class = b->target_class; + a->env = b->env; +} + +static mrb_value +mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class) +{ + mrb_value blk; + mrb_value proc; + struct RProc *p; + + mrb_get_args(mrb, "&", &blk); + if (mrb_nil_p(blk)) { + /* Calling Proc.new without a block is not implemented yet */ + mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); + } + p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class)); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + proc = mrb_obj_value(p); + mrb_funcall_with_block(mrb, proc, mrb_intern_lit(mrb, "initialize"), 0, NULL, proc); + if (!MRB_PROC_STRICT_P(p) && + mrb->c->ci > mrb->c->cibase && p->env == mrb->c->ci[-1].env) { + p->flags |= MRB_PROC_ORPHAN; + } + return proc; +} + +static mrb_value +mrb_proc_init_copy(mrb_state *mrb, mrb_value self) +{ + mrb_value proc; + + mrb_get_args(mrb, "o", &proc); + if (mrb_type(proc) != MRB_TT_PROC) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc"); + } + mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(proc)); + return self; +} + +int +mrb_proc_cfunc_p(struct RProc *p) +{ + return MRB_PROC_CFUNC_P(p); +} + +mrb_value +mrb_proc_call_cfunc(mrb_state *mrb, struct RProc *p, mrb_value self) +{ + return (p->body.func)(mrb, self); +} + +/* 15.2.17.4.2 */ +static mrb_value +mrb_proc_arity(mrb_state *mrb, mrb_value self) +{ + struct RProc *p = mrb_proc_ptr(self); + struct mrb_irep *irep; + mrb_code *iseq; + mrb_aspec aspec; + int ma, op, ra, pa, arity; + + if (MRB_PROC_CFUNC_P(p)) { + /* TODO cfunc aspec not implemented yet */ + return mrb_fixnum_value(-1); + } + + irep = p->body.irep; + if (!irep) { + return mrb_fixnum_value(0); + } + + iseq = irep->iseq; + /* arity is depend on OP_ENTER */ + if (GET_OPCODE(*iseq) != OP_ENTER) { + return mrb_fixnum_value(0); + } + + aspec = GETARG_Ax(*iseq); + ma = MRB_ASPEC_REQ(aspec); + op = MRB_ASPEC_OPT(aspec); + ra = MRB_ASPEC_REST(aspec); + pa = MRB_ASPEC_POST(aspec); + arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; + + return mrb_fixnum_value(arity); +} + +/* 15.3.1.2.6 */ +/* 15.3.1.3.27 */ +/* + * call-seq: + * lambda { |...| block } -> a_proc + * + * Equivalent to <code>Proc.new</code>, except the resulting Proc objects + * check the number of parameters passed when called. + */ +static mrb_value +proc_lambda(mrb_state *mrb, mrb_value self) +{ + mrb_value blk; + struct RProc *p; + + mrb_get_args(mrb, "&", &blk); + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); + } + if (mrb_type(blk) != MRB_TT_PROC) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "not a proc"); + } + p = mrb_proc_ptr(blk); + if (!MRB_PROC_STRICT_P(p)) { + struct RProc *p2 = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, p->c); + mrb_proc_copy(p2, p); + p2->flags |= MRB_PROC_STRICT; + return mrb_obj_value(p2); + } + return blk; +} + +void +mrb_init_proc(mrb_state *mrb) +{ + struct RProc *m; + mrb_irep *call_irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep)); + static const mrb_irep mrb_irep_zero = { 0 }; + + *call_irep = mrb_irep_zero; + call_irep->flags = MRB_ISEQ_NO_FREE; + call_irep->iseq = call_iseq; + call_irep->ilen = 1; + call_irep->nregs = 2; /* receiver and block */ + + mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY()); + mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE()); + + m = mrb_proc_new(mrb, call_irep); + mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m); + mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m); + + mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.2.6 */ + mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.3.27 */ +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/range.c b/web/server/h2o/libh2o/deps/mruby/src/range.c new file mode 100644 index 000000000..eb9a9c61f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/range.c @@ -0,0 +1,442 @@ +/* +** range.c - Range class +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/range.h> +#include <mruby/string.h> +#include <mruby/array.h> + +MRB_API struct RRange* +mrb_range_ptr(mrb_state *mrb, mrb_value v) +{ + struct RRange *r = (struct RRange*)mrb_ptr(v); + + if (r->edges == NULL) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); + } + return r; +} + +static void +range_check(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value ans; + enum mrb_vtype ta; + enum mrb_vtype tb; + + ta = mrb_type(a); + tb = mrb_type(b); + if ((ta == MRB_TT_FIXNUM || ta == MRB_TT_FLOAT) && + (tb == MRB_TT_FIXNUM || tb == MRB_TT_FLOAT)) { + return; + } + + ans = mrb_funcall(mrb, a, "<=>", 1, b); + if (mrb_nil_p(ans)) { + /* can not be compared */ + mrb_raise(mrb, E_ARGUMENT_ERROR, "bad value for range"); + } +} + +MRB_API mrb_value +mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +{ + struct RRange *r; + + range_check(mrb, beg, end); + r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); + r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); + r->edges->beg = beg; + r->edges->end = end; + r->excl = excl; + return mrb_range_value(r); +} + +/* + * call-seq: + * rng.first => obj + * rng.begin => obj + * + * Returns the first object in <i>rng</i>. + */ +mrb_value +mrb_range_beg(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_ptr(mrb, range); + + return r->edges->beg; +} + +/* + * call-seq: + * rng.end => obj + * rng.last => obj + * + * Returns the object that defines the end of <i>rng</i>. + * + * (1..10).end #=> 10 + * (1...10).end #=> 10 + */ + +mrb_value +mrb_range_end(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_ptr(mrb, range); + + return r->edges->end; +} + +/* + * call-seq: + * range.exclude_end? => true or false + * + * Returns <code>true</code> if <i>range</i> excludes its end value. + */ +mrb_value +mrb_range_excl(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_ptr(mrb, range); + + return mrb_bool_value(r->excl); +} + +static void +range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end) +{ + struct RRange *r = mrb_range_raw_ptr(range); + + range_check(mrb, beg, end); + r->excl = exclude_end; + if (!r->edges) { + r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); + } + r->edges->beg = beg; + r->edges->end = end; +} +/* + * call-seq: + * Range.new(start, end, exclusive=false) => range + * + * Constructs a range using the given <i>start</i> and <i>end</i>. If the third + * parameter is omitted or is <code>false</code>, the <i>range</i> will include + * the end object; otherwise, it will be excluded. + */ + +mrb_value +mrb_range_initialize(mrb_state *mrb, mrb_value range) +{ + mrb_value beg, end; + mrb_bool exclusive; + int n; + + n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); + if (n != 3) { + exclusive = FALSE; + } + /* Ranges are immutable, so that they should be initialized only once. */ + if (mrb_range_raw_ptr(range)->edges) { + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); + } + range_init(mrb, range, beg, end, exclusive); + return range; +} +/* + * call-seq: + * range == obj => true or false + * + * Returns <code>true</code> only if + * 1) <i>obj</i> is a Range, + * 2) <i>obj</i> has equivalent beginning and end items (by comparing them with <code>==</code>), + * 3) <i>obj</i> has the same #exclude_end? setting as <i>rng</t>. + * + * (0..2) == (0..2) #=> true + * (0..2) == Range.new(0,2) #=> true + * (0..2) == (0...2) #=> false + * + */ + +mrb_value +mrb_range_eq(mrb_state *mrb, mrb_value range) +{ + struct RRange *rr; + struct RRange *ro; + mrb_value obj, v1, v2; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); + if (!mrb_obj_is_instance_of(mrb, obj, mrb_obj_class(mrb, range))) { /* same class? */ + return mrb_false_value(); + } + + rr = mrb_range_ptr(mrb, range); + ro = mrb_range_ptr(mrb, obj); + v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg); + v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end); + if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) { + return mrb_false_value(); + } + return mrb_true_value(); +} + +static mrb_bool +r_le(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == -1) return TRUE; + } + + return FALSE; +} + +static mrb_bool +r_gt(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + return mrb_fixnum_p(r) && mrb_fixnum(r) == 1; +} + +static mrb_bool +r_ge(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == 1) return TRUE; + } + + return FALSE; +} + +/* + * call-seq: + * range === obj => true or false + * range.member?(val) => true or false + * range.include?(val) => true or false + * + */ +mrb_value +mrb_range_include(mrb_state *mrb, mrb_value range) +{ + mrb_value val; + struct RRange *r = mrb_range_ptr(mrb, range); + mrb_value beg, end; + mrb_bool include_p; + + mrb_get_args(mrb, "o", &val); + + beg = r->edges->beg; + end = r->edges->end; + include_p = r_le(mrb, beg, val) && /* beg <= val */ + (r->excl ? r_gt(mrb, end, val) /* end > val */ + : r_ge(mrb, end, val)); /* end >= val */ + + return mrb_bool_value(include_p); +} + +MRB_API mrb_int +mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) +{ + mrb_int beg, end; + struct RRange *r; + + if (mrb_type(range) != MRB_TT_RANGE) return 0; + r = mrb_range_ptr(mrb, range); + + beg = mrb_int(mrb, r->edges->beg); + end = mrb_int(mrb, r->edges->end); + + if (beg < 0) { + beg += len; + if (beg < 0) return 2; + } + + if (trunc) { + if (beg > len) return 2; + if (end > len) end = len; + } + + if (end < 0) end += len; + if (!r->excl && (!trunc || end < len)) + end++; /* include end point */ + len = end - beg; + if (len < 0) len = 0; + + *begp = beg; + *lenp = len; + return 1; +} + +/* 15.2.14.4.12(x) */ +/* + * call-seq: + * rng.to_s -> string + * + * Convert this range object to a printable form. + */ + +static mrb_value +range_to_s(mrb_state *mrb, mrb_value range) +{ + mrb_value str, str2; + struct RRange *r = mrb_range_ptr(mrb, range); + + str = mrb_obj_as_string(mrb, r->edges->beg); + str2 = mrb_obj_as_string(mrb, r->edges->end); + str = mrb_str_dup(mrb, str); + mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat_str(mrb, str, str2); + + return str; +} + +/* 15.2.14.4.13(x) */ +/* + * call-seq: + * rng.inspect -> string + * + * Convert this range object to a printable form (using + * <code>inspect</code> to convert the start and end + * objects). + */ + +static mrb_value +range_inspect(mrb_state *mrb, mrb_value range) +{ + mrb_value str, str2; + struct RRange *r = mrb_range_ptr(mrb, range); + + str = mrb_inspect(mrb, r->edges->beg); + str2 = mrb_inspect(mrb, r->edges->end); + str = mrb_str_dup(mrb, str); + mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat_str(mrb, str, str2); + + return str; +} + +/* 15.2.14.4.14(x) */ +/* + * call-seq: + * rng.eql?(obj) -> true or false + * + * Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent + * beginning and end items (by comparing them with #eql?), and has the same + * #exclude_end? setting as <i>rng</i>. + * + * (0..2).eql?(0..2) #=> true + * (0..2).eql?(Range.new(0,2)) #=> true + * (0..2).eql?(0...2) #=> false + * + */ + +static mrb_value +range_eql(mrb_state *mrb, mrb_value range) +{ + mrb_value obj; + struct RRange *r, *o; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); + if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) { + return mrb_false_value(); + } + if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); + + r = mrb_range_ptr(mrb, range); + o = mrb_range_ptr(mrb, obj); + if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) || + !mrb_eql(mrb, r->edges->end, o->edges->end) || + (r->excl != o->excl)) { + return mrb_false_value(); + } + return mrb_true_value(); +} + +/* 15.2.14.4.15(x) */ +static mrb_value +range_initialize_copy(mrb_state *mrb, mrb_value copy) +{ + mrb_value src; + struct RRange *r; + + mrb_get_args(mrb, "o", &src); + + if (mrb_obj_equal(mrb, copy, src)) return copy; + if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) { + mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); + } + + r = mrb_range_ptr(mrb, src); + range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); + + return copy; +} + +mrb_value +mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)) +{ + mrb_int i, j, beg, len; + mrb_value result; + result = mrb_ary_new(mrb); + + for (i = 0; i < argc; ++i) { + if (mrb_fixnum_p(argv[i])) { + mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i]))); + } + else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) { + mrb_int const end = olen < beg + len ? olen : beg + len; + for (j = beg; j < end; ++j) { + mrb_ary_push(mrb, result, func(mrb, obj, j)); + } + + for (; j < beg + len; ++j) { + mrb_ary_push(mrb, result, mrb_nil_value()); + } + } + else { + mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %S", argv[i]); + } + } + + return result; +} + +void +mrb_init_range(mrb_state *mrb) +{ + struct RClass *r; + + r = mrb_define_class(mrb, "Range", mrb->object_class); /* 15.2.14 */ + mrb->range_class = r; + MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE); + + mrb_define_method(mrb, r, "begin", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ + mrb_define_method(mrb, r, "end", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ + mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ + mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ + mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ + mrb_define_method(mrb, r, "first", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ + mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ + mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ + mrb_define_method(mrb, r, "last", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ + mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ + + mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */ + mrb_define_method(mrb, r, "inspect", range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */ + mrb_define_method(mrb, r, "eql?", range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */ + mrb_define_method(mrb, r, "initialize_copy", range_initialize_copy, MRB_ARGS_REQ(1)); /* 15.2.14.4.15(x) */ +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/state.c b/web/server/h2o/libh2o/deps/mruby/src/state.c new file mode 100644 index 000000000..039d67d57 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/state.c @@ -0,0 +1,303 @@ +/* +** state.c - mrb_state open/close functions +** +** See Copyright Notice in mruby.h +*/ + +#include <stdlib.h> +#include <string.h> +#include <mruby.h> +#include <mruby/irep.h> +#include <mruby/variable.h> +#include <mruby/debug.h> +#include <mruby/string.h> + +void mrb_init_core(mrb_state*); +void mrb_init_mrbgems(mrb_state*); + +void mrb_gc_init(mrb_state*, mrb_gc *gc); +void mrb_gc_destroy(mrb_state*, mrb_gc *gc); + +static mrb_value +inspect_main(mrb_state *mrb, mrb_value mod) +{ + return mrb_str_new_lit(mrb, "main"); +} + +MRB_API mrb_state* +mrb_open_core(mrb_allocf f, void *ud) +{ + static const mrb_state mrb_state_zero = { 0 }; + static const struct mrb_context mrb_context_zero = { 0 }; + mrb_state *mrb; + + mrb = (mrb_state *)(f)(NULL, NULL, sizeof(mrb_state), ud); + if (mrb == NULL) return NULL; + + *mrb = mrb_state_zero; + mrb->allocf_ud = ud; + mrb->allocf = f; + mrb->atexit_stack_len = 0; + + mrb_gc_init(mrb, &mrb->gc); + mrb->c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context)); + *mrb->c = mrb_context_zero; + mrb->root_c = mrb->c; + + mrb_init_core(mrb); + + return mrb; +} + +void* +mrb_default_allocf(mrb_state *mrb, void *p, size_t size, void *ud) +{ + if (size == 0) { + free(p); + return NULL; + } + else { + return realloc(p, size); + } +} + +struct alloca_header { + struct alloca_header *next; + char buf[]; +}; + +MRB_API void* +mrb_alloca(mrb_state *mrb, size_t size) +{ + struct alloca_header *p; + + p = (struct alloca_header*) mrb_malloc(mrb, sizeof(struct alloca_header)+size); + p->next = mrb->mems; + mrb->mems = p; + return (void*)p->buf; +} + +static void +mrb_alloca_free(mrb_state *mrb) +{ + struct alloca_header *p; + struct alloca_header *tmp; + + if (mrb == NULL) return; + p = mrb->mems; + + while (p) { + tmp = p; + p = p->next; + mrb_free(mrb, tmp); + } +} + +MRB_API mrb_state* +mrb_open(void) +{ + mrb_state *mrb = mrb_open_allocf(mrb_default_allocf, NULL); + + return mrb; +} + +MRB_API mrb_state* +mrb_open_allocf(mrb_allocf f, void *ud) +{ + mrb_state *mrb = mrb_open_core(f, ud); + + if (mrb == NULL) { + return NULL; + } + +#ifndef DISABLE_GEMS + mrb_init_mrbgems(mrb); + mrb_gc_arena_restore(mrb, 0); +#endif + return mrb; +} + +void mrb_free_symtbl(mrb_state *mrb); + +void +mrb_irep_incref(mrb_state *mrb, mrb_irep *irep) +{ + irep->refcnt++; +} + +void +mrb_irep_decref(mrb_state *mrb, mrb_irep *irep) +{ + irep->refcnt--; + if (irep->refcnt == 0) { + mrb_irep_free(mrb, irep); + } +} + +void +mrb_irep_free(mrb_state *mrb, mrb_irep *irep) +{ + int i; + + if (!(irep->flags & MRB_ISEQ_NO_FREE)) + mrb_free(mrb, irep->iseq); + if (irep->pool) for (i=0; i<irep->plen; i++) { + if (mrb_type(irep->pool[i]) == MRB_TT_STRING) { + mrb_gc_free_str(mrb, RSTRING(irep->pool[i])); + mrb_free(mrb, mrb_obj_ptr(irep->pool[i])); + } +#ifdef MRB_WORD_BOXING + else if (mrb_type(irep->pool[i]) == MRB_TT_FLOAT) { + mrb_free(mrb, mrb_obj_ptr(irep->pool[i])); + } +#endif + } + mrb_free(mrb, irep->pool); + mrb_free(mrb, irep->syms); + for (i=0; i<irep->rlen; i++) { + mrb_irep_decref(mrb, irep->reps[i]); + } + if (irep->outer) + mrb_irep_decref(mrb, irep->outer); + mrb_free(mrb, irep->reps); + mrb_free(mrb, irep->lv); + if (irep->own_filename) { + mrb_free(mrb, (void *)irep->filename); + } + mrb_free(mrb, irep->lines); + mrb_debug_info_free(mrb, irep->debug_info); + mrb_free(mrb, irep); +} + +mrb_value +mrb_str_pool(mrb_state *mrb, mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + struct RString *ns; + char *ptr; + mrb_int len; + + ns = (struct RString *)mrb_malloc(mrb, sizeof(struct RString)); + ns->tt = MRB_TT_STRING; + ns->c = mrb->string_class; + + if (RSTR_NOFREE_P(s)) { + ns->flags = MRB_STR_NOFREE; + ns->as.heap.ptr = s->as.heap.ptr; + ns->as.heap.len = s->as.heap.len; + ns->as.heap.aux.capa = 0; + } + else { + ns->flags = 0; + if (RSTR_EMBED_P(s)) { + ptr = s->as.ary; + len = RSTR_EMBED_LEN(s); + } + else { + ptr = s->as.heap.ptr; + len = s->as.heap.len; + } + + if (len < RSTRING_EMBED_LEN_MAX) { + RSTR_SET_EMBED_FLAG(ns); + RSTR_SET_EMBED_LEN(ns, len); + if (ptr) { + memcpy(ns->as.ary, ptr, len); + } + ns->as.ary[len] = '\0'; + } + else { + ns->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1); + ns->as.heap.len = len; + ns->as.heap.aux.capa = len; + if (ptr) { + memcpy(ns->as.heap.ptr, ptr, len); + } + ns->as.heap.ptr[len] = '\0'; + } + } + return mrb_obj_value(ns); +} + +void mrb_free_backtrace(mrb_state *mrb); + +MRB_API void +mrb_free_context(mrb_state *mrb, struct mrb_context *c) +{ + if (!c) return; + mrb_free(mrb, c->stbase); + mrb_free(mrb, c->cibase); + mrb_free(mrb, c->rescue); + mrb_free(mrb, c->ensure); + mrb_free(mrb, c); +} + +MRB_API void +mrb_close(mrb_state *mrb) +{ + if (!mrb) return; + if (mrb->atexit_stack_len > 0) { + mrb_int i; + for (i = mrb->atexit_stack_len; i > 0; --i) { + mrb->atexit_stack[i - 1](mrb); + } +#ifndef MRB_FIXED_STATE_ATEXIT_STACK + mrb_free(mrb, mrb->atexit_stack); +#endif + } + + /* free */ + mrb_gc_free_gv(mrb); + mrb_free_context(mrb, mrb->root_c); + mrb_free_symtbl(mrb); + mrb_alloca_free(mrb); + mrb_gc_destroy(mrb, &mrb->gc); + mrb_free(mrb, mrb); +} + +MRB_API mrb_irep* +mrb_add_irep(mrb_state *mrb) +{ + static const mrb_irep mrb_irep_zero = { 0 }; + mrb_irep *irep; + + irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep)); + *irep = mrb_irep_zero; + irep->refcnt = 1; + irep->own_filename = FALSE; + + return irep; +} + +MRB_API mrb_value +mrb_top_self(mrb_state *mrb) +{ + if (!mrb->top_self) { + mrb->top_self = (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mrb->object_class); + mrb_define_singleton_method(mrb, mrb->top_self, "inspect", inspect_main, MRB_ARGS_NONE()); + mrb_define_singleton_method(mrb, mrb->top_self, "to_s", inspect_main, MRB_ARGS_NONE()); + } + return mrb_obj_value(mrb->top_self); +} + +MRB_API void +mrb_state_atexit(mrb_state *mrb, mrb_atexit_func f) +{ +#ifdef MRB_FIXED_STATE_ATEXIT_STACK + if (mrb->atexit_stack_len + 1 > MRB_FIXED_STATE_ATEXIT_STACK_SIZE) { + mrb_raise(mrb, E_RUNTIME_ERROR, "exceeded fixed state atexit stack limit"); + } +#else + size_t stack_size; + + stack_size = sizeof(mrb_atexit_func) * (mrb->atexit_stack_len + 1); + if (mrb->atexit_stack_len == 0) { + mrb->atexit_stack = (mrb_atexit_func*)mrb_malloc(mrb, stack_size); + } + else { + mrb->atexit_stack = (mrb_atexit_func*)mrb_realloc(mrb, mrb->atexit_stack, stack_size); + } +#endif + + mrb->atexit_stack[mrb->atexit_stack_len++] = f; +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/string.c b/web/server/h2o/libh2o/deps/mruby/src/string.c new file mode 100644 index 000000000..01d706fa3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/string.c @@ -0,0 +1,3013 @@ +/* +** string.c - String class +** +** See Copyright Notice in mruby.h +*/ + +#ifdef _MSC_VER +# define _CRT_NONSTDC_NO_DEPRECATE +#endif + +#include <float.h> +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/range.h> +#include <mruby/string.h> +#include <mruby/re.h> + +typedef struct mrb_shared_string { + mrb_bool nofree : 1; + int refcnt; + char *ptr; + mrb_int len; +} mrb_shared_string; + +const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + +#define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class)) + +static struct RString* +str_new_static(mrb_state *mrb, const char *p, size_t len) +{ + struct RString *s; + + if (len >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); + } + s = mrb_obj_alloc_string(mrb); + s->as.heap.len = (mrb_int)len; + s->as.heap.aux.capa = 0; /* nofree */ + s->as.heap.ptr = (char *)p; + s->flags = MRB_STR_NOFREE; + + return s; +} + +static struct RString* +str_new(mrb_state *mrb, const char *p, size_t len) +{ + struct RString *s; + + if (p && mrb_ro_data_p(p)) { + return str_new_static(mrb, p, len); + } + s = mrb_obj_alloc_string(mrb); + if (len < RSTRING_EMBED_LEN_MAX) { + RSTR_SET_EMBED_FLAG(s); + RSTR_SET_EMBED_LEN(s, len); + if (p) { + memcpy(s->as.ary, p, len); + } + } + else { + if (len >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); + } + s->as.heap.len = (mrb_int)len; + s->as.heap.aux.capa = (mrb_int)len; + s->as.heap.ptr = (char *)mrb_malloc(mrb, len+1); + if (p) { + memcpy(s->as.heap.ptr, p, len); + } + } + RSTR_PTR(s)[len] = '\0'; + return s; +} + +static inline void +str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj) +{ + s->c = mrb_str_ptr(obj)->c; +} + +static mrb_value +mrb_str_new_empty(mrb_state *mrb, mrb_value str) +{ + struct RString *s = str_new(mrb, 0, 0); + + str_with_class(mrb, s, str); + return mrb_obj_value(s); +} + +MRB_API mrb_value +mrb_str_new_capa(mrb_state *mrb, size_t capa) +{ + struct RString *s; + + s = mrb_obj_alloc_string(mrb); + + if (capa >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string capacity size too big"); + } + s->as.heap.len = 0; + s->as.heap.aux.capa = (mrb_int)capa; + s->as.heap.ptr = (char *)mrb_malloc(mrb, capa+1); + RSTR_PTR(s)[0] = '\0'; + + return mrb_obj_value(s); +} + +#ifndef MRB_STR_BUF_MIN_SIZE +# define MRB_STR_BUF_MIN_SIZE 128 +#endif + +MRB_API mrb_value +mrb_str_buf_new(mrb_state *mrb, size_t capa) +{ + if (capa < MRB_STR_BUF_MIN_SIZE) { + capa = MRB_STR_BUF_MIN_SIZE; + } + return mrb_str_new_capa(mrb, capa); +} + +static void +resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) +{ +#if SIZE_MAX > MRB_INT_MAX + mrb_assert(capacity < MRB_INT_MAX); +#endif + if (RSTR_EMBED_P(s)) { + if (RSTRING_EMBED_LEN_MAX < capacity) { + char *const tmp = (char *)mrb_malloc(mrb, capacity+1); + const mrb_int len = RSTR_EMBED_LEN(s); + memcpy(tmp, s->as.ary, len); + RSTR_UNSET_EMBED_FLAG(s); + s->as.heap.ptr = tmp; + s->as.heap.len = len; + s->as.heap.aux.capa = (mrb_int)capacity; + } + } + else { + s->as.heap.ptr = (char*)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); + s->as.heap.aux.capa = (mrb_int)capacity; + } +} + +MRB_API mrb_value +mrb_str_new(mrb_state *mrb, const char *p, size_t len) +{ + return mrb_obj_value(str_new(mrb, p, len)); +} + +/* + * call-seq: (Caution! NULL string) + * String.new(str="") => new_str + * + * Returns a new string object containing a copy of <i>str</i>. + */ + +MRB_API mrb_value +mrb_str_new_cstr(mrb_state *mrb, const char *p) +{ + struct RString *s; + size_t len; + + if (p) { + len = strlen(p); + } + else { + len = 0; + } + + s = str_new(mrb, p, len); + + return mrb_obj_value(s); +} + +MRB_API mrb_value +mrb_str_new_static(mrb_state *mrb, const char *p, size_t len) +{ + struct RString *s = str_new_static(mrb, p, len); + return mrb_obj_value(s); +} + +static void +str_decref(mrb_state *mrb, mrb_shared_string *shared) +{ + shared->refcnt--; + if (shared->refcnt == 0) { + if (!shared->nofree) { + mrb_free(mrb, shared->ptr); + } + mrb_free(mrb, shared); + } +} + +void +mrb_gc_free_str(mrb_state *mrb, struct RString *str) +{ + if (RSTR_EMBED_P(str)) + /* no code */; + else if (RSTR_SHARED_P(str)) + str_decref(mrb, str->as.heap.aux.shared); + else if (!RSTR_NOFREE_P(str)) + mrb_free(mrb, str->as.heap.ptr); +} + +#ifdef MRB_UTF8_STRING +static const char utf8len_codepage[256] = +{ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1, +}; + +static mrb_int +utf8len(const char* p, const char* e) +{ + mrb_int len; + mrb_int i; + + len = utf8len_codepage[(unsigned char)*p]; + if (p + len > e) return 1; + for (i = 1; i < len; ++i) + if ((p[i] & 0xc0) != 0x80) + return 1; + return len; +} + +static mrb_int +utf8_strlen(mrb_value str, mrb_int len) +{ + mrb_int total = 0; + char* p = RSTRING_PTR(str); + char* e = p; + if (RSTRING(str)->flags & MRB_STR_NO_UTF) { + return RSTRING_LEN(str); + } + e += len < 0 ? RSTRING_LEN(str) : len; + while (p<e) { + p += utf8len(p, e); + total++; + } + if (RSTRING_LEN(str) == total) { + RSTRING(str)->flags |= MRB_STR_NO_UTF; + } + return total; +} + +#define RSTRING_CHAR_LEN(s) utf8_strlen(s, -1) + +/* map character index to byte offset index */ +static mrb_int +chars2bytes(mrb_value s, mrb_int off, mrb_int idx) +{ + mrb_int i, b, n; + const char *p = RSTRING_PTR(s) + off; + const char *e = RSTRING_END(s); + + for (b=i=0; p<e && i<idx; i++) { + n = utf8len(p, e); + b += n; + p += n; + } + return b; +} + +/* map byte offset to character index */ +static mrb_int +bytes2chars(char *p, mrb_int bi) +{ + mrb_int i, b, n; + + for (b=i=0; b<bi; i++) { + n = utf8len_codepage[(unsigned char)*p]; + b += n; + p += n; + } + if (b != bi) return -1; + return i; +} + +#define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value(); +#else +#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s) +#define chars2bytes(p, off, ci) (ci) +#define bytes2chars(p, bi) (bi) +#define BYTES_ALIGN_CHECK(pos) +#endif + +static inline mrb_int +mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n) +{ + const unsigned char *x = xs, *xe = xs + m; + const unsigned char *y = ys; + int i; + ptrdiff_t qstable[256]; + + /* Preprocessing */ + for (i = 0; i < 256; ++i) + qstable[i] = m + 1; + for (; x < xe; ++x) + qstable[*x] = xe - x; + /* Searching */ + for (; y + m <= ys + n; y += *(qstable + y[m])) { + if (*xs == *y && memcmp(xs, y, m) == 0) + return (mrb_int)(y - ys); + } + return -1; +} + +static mrb_int +mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n) +{ + const unsigned char *x = (const unsigned char *)x0, *y = (const unsigned char *)y0; + + if (m > n) return -1; + else if (m == n) { + return memcmp(x0, y0, m) == 0 ? 0 : -1; + } + else if (m < 1) { + return 0; + } + else if (m == 1) { + const unsigned char *ys = (const unsigned char *)memchr(y, *x, n); + + if (ys) + return (mrb_int)(ys - y); + else + return -1; + } + return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n); +} + +static void +str_make_shared(mrb_state *mrb, struct RString *s) +{ + if (!RSTR_SHARED_P(s)) { + mrb_shared_string *shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string)); + + shared->refcnt = 1; + if (RSTR_EMBED_P(s)) { + const mrb_int len = RSTR_EMBED_LEN(s); + char *const tmp = (char *)mrb_malloc(mrb, len+1); + memcpy(tmp, s->as.ary, len); + tmp[len] = '\0'; + RSTR_UNSET_EMBED_FLAG(s); + s->as.heap.ptr = tmp; + s->as.heap.len = len; + shared->nofree = FALSE; + shared->ptr = s->as.heap.ptr; + } + else if (RSTR_NOFREE_P(s)) { + shared->nofree = TRUE; + shared->ptr = s->as.heap.ptr; + RSTR_UNSET_NOFREE_FLAG(s); + } + else { + shared->nofree = FALSE; + if (s->as.heap.aux.capa > s->as.heap.len) { + s->as.heap.ptr = shared->ptr = (char *)mrb_realloc(mrb, s->as.heap.ptr, s->as.heap.len+1); + } + else { + shared->ptr = s->as.heap.ptr; + } + } + shared->len = s->as.heap.len; + s->as.heap.aux.shared = shared; + RSTR_SET_SHARED_FLAG(s); + } +} + +static mrb_value +byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + struct RString *orig, *s; + mrb_shared_string *shared; + + orig = mrb_str_ptr(str); + if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0) { + s = str_new(mrb, orig->as.ary+beg, len); + } + else { + str_make_shared(mrb, orig); + shared = orig->as.heap.aux.shared; + s = mrb_obj_alloc_string(mrb); + s->as.heap.ptr = orig->as.heap.ptr + beg; + s->as.heap.len = len; + s->as.heap.aux.shared = shared; + RSTR_SET_SHARED_FLAG(s); + shared->refcnt++; + } + + return mrb_obj_value(s); +} +#ifdef MRB_UTF8_STRING +static inline mrb_value +str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + beg = chars2bytes(str, 0, beg); + len = chars2bytes(str, beg, len); + + return byte_subseq(mrb, str, beg, len); +} +#else +#define str_subseq(mrb, str, beg, len) byte_subseq(mrb, str, beg, len) +#endif + +static mrb_value +str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + mrb_int clen = RSTRING_CHAR_LEN(str); + + if (len < 0) return mrb_nil_value(); + if (clen == 0) { + len = 0; + } + else if (beg < 0) { + beg = clen + beg; + } + if (beg > clen) return mrb_nil_value(); + if (beg < 0) { + beg += clen; + if (beg < 0) return mrb_nil_value(); + } + if (len > clen - beg) + len = clen - beg; + if (len <= 0) { + len = 0; + } + return str_subseq(mrb, str, beg, len); +} + +MRB_API mrb_int +mrb_str_index(mrb_state *mrb, mrb_value str, const char *sptr, mrb_int slen, mrb_int offset) +{ + mrb_int pos; + char *s; + mrb_int len; + + len = RSTRING_LEN(str); + if (offset < 0) { + offset += len; + if (offset < 0) return -1; + } + if (len - offset < slen) return -1; + s = RSTRING_PTR(str); + if (offset) { + s += offset; + } + if (slen == 0) return offset; + /* need proceed one character at a time */ + len = RSTRING_LEN(str) - offset; + pos = mrb_memsearch(sptr, slen, s, len); + if (pos < 0) return pos; + return pos + offset; +} + +static mrb_int +str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset) +{ + const char *ptr; + mrb_int len; + + ptr = RSTRING_PTR(str2); + len = RSTRING_LEN(str2); + + return mrb_str_index(mrb, str, ptr, len, offset); +} + +static void +check_frozen(mrb_state *mrb, struct RString *s) +{ + if (MRB_FROZEN_P(s)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string"); + } +} + +static mrb_value +str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) +{ + long len; + + check_frozen(mrb, s1); + if (s1 == s2) return mrb_obj_value(s1); + s1->flags &= ~MRB_STR_NO_UTF; + s1->flags |= s2->flags&MRB_STR_NO_UTF; + len = RSTR_LEN(s2); + if (RSTR_SHARED_P(s1)) { + str_decref(mrb, s1->as.heap.aux.shared); + } + else if (!RSTR_EMBED_P(s1) && !RSTR_NOFREE_P(s1)) { + mrb_free(mrb, s1->as.heap.ptr); + } + + RSTR_UNSET_NOFREE_FLAG(s1); + + if (RSTR_SHARED_P(s2)) { +L_SHARE: + RSTR_UNSET_EMBED_FLAG(s1); + s1->as.heap.ptr = s2->as.heap.ptr; + s1->as.heap.len = len; + s1->as.heap.aux.shared = s2->as.heap.aux.shared; + RSTR_SET_SHARED_FLAG(s1); + s1->as.heap.aux.shared->refcnt++; + } + else { + if (len <= RSTRING_EMBED_LEN_MAX) { + RSTR_UNSET_SHARED_FLAG(s1); + RSTR_SET_EMBED_FLAG(s1); + memcpy(s1->as.ary, RSTR_PTR(s2), len); + RSTR_SET_EMBED_LEN(s1, len); + } + else { + str_make_shared(mrb, s2); + goto L_SHARE; + } + } + + return mrb_obj_value(s1); +} + +static mrb_int +str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) +{ + char *s, *sbeg, *t; + struct RString *ps = mrb_str_ptr(str); + mrb_int len = RSTRING_LEN(sub); + + /* substring longer than string */ + if (RSTR_LEN(ps) < len) return -1; + if (RSTR_LEN(ps) - pos < len) { + pos = RSTR_LEN(ps) - len; + } + sbeg = RSTR_PTR(ps); + s = RSTR_PTR(ps) + pos; + t = RSTRING_PTR(sub); + if (len) { + while (sbeg <= s) { + if (memcmp(s, t, len) == 0) { + return (mrb_int)(s - RSTR_PTR(ps)); + } + s--; + } + return -1; + } + else { + return pos; + } +} + +MRB_API mrb_int +mrb_str_strlen(mrb_state *mrb, struct RString *s) +{ + mrb_int i, max = RSTR_LEN(s); + char *p = RSTR_PTR(s); + + if (!p) return 0; + for (i=0; i<max; i++) { + if (p[i] == '\0') { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); + } + } + return max; +} + +#ifdef _WIN32 +#include <windows.h> + +char* +mrb_utf8_from_locale(const char *str, int len) +{ + wchar_t* wcsp; + char* mbsp; + int mbssize, wcssize; + + if (len == 0) + return strdup(""); + if (len == -1) + len = (int)strlen(str); + wcssize = MultiByteToWideChar(GetACP(), 0, str, len, NULL, 0); + wcsp = (wchar_t*) malloc((wcssize + 1) * sizeof(wchar_t)); + if (!wcsp) + return NULL; + wcssize = MultiByteToWideChar(GetACP(), 0, str, len, wcsp, wcssize + 1); + wcsp[wcssize] = 0; + + mbssize = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wcsp, -1, NULL, 0, NULL, NULL); + mbsp = (char*) malloc((mbssize + 1)); + if (!mbsp) { + free(wcsp); + return NULL; + } + mbssize = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wcsp, -1, mbsp, mbssize, NULL, NULL); + mbsp[mbssize] = 0; + free(wcsp); + return mbsp; +} + +char* +mrb_locale_from_utf8(const char *utf8, int len) +{ + wchar_t* wcsp; + char* mbsp; + int mbssize, wcssize; + + if (len == 0) + return strdup(""); + if (len == -1) + len = (int)strlen(utf8); + wcssize = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0); + wcsp = (wchar_t*) malloc((wcssize + 1) * sizeof(wchar_t)); + if (!wcsp) + return NULL; + wcssize = MultiByteToWideChar(CP_UTF8, 0, utf8, len, wcsp, wcssize + 1); + wcsp[wcssize] = 0; + mbssize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR) wcsp, -1, NULL, 0, NULL, NULL); + mbsp = (char*) malloc((mbssize + 1)); + if (!mbsp) { + free(wcsp); + return NULL; + } + mbssize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR) wcsp, -1, mbsp, mbssize, NULL, NULL); + mbsp[mbssize] = 0; + free(wcsp); + return mbsp; +} +#endif + +MRB_API void +mrb_str_modify(mrb_state *mrb, struct RString *s) +{ + check_frozen(mrb, s); + s->flags &= ~MRB_STR_NO_UTF; + if (RSTR_SHARED_P(s)) { + mrb_shared_string *shared = s->as.heap.aux.shared; + + if (shared->nofree == 0 && shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { + s->as.heap.ptr = shared->ptr; + s->as.heap.aux.capa = shared->len; + RSTR_PTR(s)[s->as.heap.len] = '\0'; + mrb_free(mrb, shared); + } + else { + char *ptr, *p; + mrb_int len; + + p = RSTR_PTR(s); + len = s->as.heap.len; + if (len < RSTRING_EMBED_LEN_MAX) { + RSTR_SET_EMBED_FLAG(s); + RSTR_SET_EMBED_LEN(s, len); + ptr = RSTR_PTR(s); + } + else { + ptr = (char *)mrb_malloc(mrb, (size_t)len + 1); + s->as.heap.ptr = ptr; + s->as.heap.aux.capa = len; + } + if (p) { + memcpy(ptr, p, len); + } + ptr[len] = '\0'; + str_decref(mrb, shared); + } + RSTR_UNSET_SHARED_FLAG(s); + return; + } + if (RSTR_NOFREE_P(s)) { + char *p = s->as.heap.ptr; + mrb_int len = s->as.heap.len; + + RSTR_UNSET_NOFREE_FLAG(s); + if (len < RSTRING_EMBED_LEN_MAX) { + RSTR_SET_EMBED_FLAG(s); + RSTR_SET_EMBED_LEN(s, len); + } + else { + s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1); + s->as.heap.aux.capa = len; + } + if (p) { + memcpy(RSTR_PTR(s), p, len); + } + RSTR_PTR(s)[len] = '\0'; + return; + } +} + +MRB_API mrb_value +mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) +{ + mrb_int slen; + struct RString *s = mrb_str_ptr(str); + + mrb_str_modify(mrb, s); + slen = RSTR_LEN(s); + if (len != slen) { + if (slen < len || slen - len > 256) { + resize_capa(mrb, s, len); + } + RSTR_SET_LEN(s, len); + RSTR_PTR(s)[len] = '\0'; /* sentinel */ + } + return str; +} + +MRB_API char* +mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) +{ + struct RString *s; + + if (!mrb_string_p(str0)) { + mrb_raise(mrb, E_TYPE_ERROR, "expected String"); + } + + s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0)); + if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); + } + return RSTR_PTR(s); +} + +/* + * call-seq: (Caution! String("abcd") change) + * String("abcdefg") = String("abcd") + String("efg") + * + * Returns a new string object containing a copy of <i>str</i>. + */ +MRB_API void +mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) +{ + if (!mrb_string_p(other)) { + other = mrb_str_to_str(mrb, other); + } + mrb_str_cat_str(mrb, self, other); +} + +/* + * call-seq: (Caution! String("abcd") remain) + * String("abcdefg") = String("abcd") + String("efg") + * + * Returns a new string object containing a copy of <i>str</i>. + */ +MRB_API mrb_value +mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) +{ + struct RString *s = mrb_str_ptr(a); + struct RString *s2 = mrb_str_ptr(b); + struct RString *t; + + t = str_new(mrb, 0, RSTR_LEN(s) + RSTR_LEN(s2)); + memcpy(RSTR_PTR(t), RSTR_PTR(s), RSTR_LEN(s)); + memcpy(RSTR_PTR(t) + RSTR_LEN(s), RSTR_PTR(s2), RSTR_LEN(s2)); + + return mrb_obj_value(t); +} + +/* 15.2.10.5.2 */ + +/* + * call-seq: (Caution! String("abcd") remain) for stack_argument + * String("abcdefg") = String("abcd") + String("efg") + * + * Returns a new string object containing a copy of <i>str</i>. + */ +static mrb_value +mrb_str_plus_m(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + + mrb_get_args(mrb, "S", &str); + return mrb_str_plus(mrb, self, str); +} + +/* 15.2.10.5.26 */ +/* 15.2.10.5.33 */ +/* + * call-seq: + * "abcd".size => int + * + * Returns the length of string. + */ +static mrb_value +mrb_str_size(mrb_state *mrb, mrb_value self) +{ + mrb_int len = RSTRING_CHAR_LEN(self); + return mrb_fixnum_value(len); +} + +static mrb_value +mrb_str_bytesize(mrb_state *mrb, mrb_value self) +{ + mrb_int len = RSTRING_LEN(self); + return mrb_fixnum_value(len); +} + +/* 15.2.10.5.1 */ +/* + * call-seq: + * str * integer => new_str + * + * Copy---Returns a new <code>String</code> containing <i>integer</i> copies of + * the receiver. + * + * "Ho! " * 3 #=> "Ho! Ho! Ho! " + */ +static mrb_value +mrb_str_times(mrb_state *mrb, mrb_value self) +{ + mrb_int n,len,times; + struct RString *str2; + char *p; + + mrb_get_args(mrb, "i", ×); + if (times < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument"); + } + if (times && MRB_INT_MAX / times < RSTRING_LEN(self)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "argument too big"); + } + + len = RSTRING_LEN(self)*times; + str2 = str_new(mrb, 0, len); + str_with_class(mrb, str2, self); + p = RSTR_PTR(str2); + if (len > 0) { + n = RSTRING_LEN(self); + memcpy(p, RSTRING_PTR(self), n); + while (n <= len/2) { + memcpy(p + n, p, n); + n *= 2; + } + memcpy(p + n, p, len-n); + } + p[RSTR_LEN(str2)] = '\0'; + + return mrb_obj_value(str2); +} +/* -------------------------------------------------------------- */ + +#define lesser(a,b) (((a)>(b))?(b):(a)) + +/* ---------------------------*/ +/* + * call-seq: + * mrb_value str1 <=> mrb_value str2 => int + * > 1 + * = 0 + * < -1 + */ +MRB_API int +mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2) +{ + mrb_int len; + mrb_int retval; + struct RString *s1 = mrb_str_ptr(str1); + struct RString *s2 = mrb_str_ptr(str2); + + len = lesser(RSTR_LEN(s1), RSTR_LEN(s2)); + retval = memcmp(RSTR_PTR(s1), RSTR_PTR(s2), len); + if (retval == 0) { + if (RSTR_LEN(s1) == RSTR_LEN(s2)) return 0; + if (RSTR_LEN(s1) > RSTR_LEN(s2)) return 1; + return -1; + } + if (retval > 0) return 1; + return -1; +} + +/* 15.2.10.5.3 */ + +/* + * call-seq: + * str <=> other_str => -1, 0, +1 + * + * Comparison---Returns -1 if <i>other_str</i> is less than, 0 if + * <i>other_str</i> is equal to, and +1 if <i>other_str</i> is greater than + * <i>str</i>. If the strings are of different lengths, and the strings are + * equal when compared up to the shortest length, then the longer string is + * considered greater than the shorter one. If the variable <code>$=</code> is + * <code>false</code>, the comparison is based on comparing the binary values + * of each character in the string. In older versions of Ruby, setting + * <code>$=</code> allowed case-insensitive comparisons; this is now deprecated + * in favor of using <code>String#casecmp</code>. + * + * <code><=></code> is the basis for the methods <code><</code>, + * <code><=</code>, <code>></code>, <code>>=</code>, and <code>between?</code>, + * included from module <code>Comparable</code>. The method + * <code>String#==</code> does not use <code>Comparable#==</code>. + * + * "abcdef" <=> "abcde" #=> 1 + * "abcdef" <=> "abcdef" #=> 0 + * "abcdef" <=> "abcdefg" #=> -1 + * "abcdef" <=> "ABCDEF" #=> 1 + */ +static mrb_value +mrb_str_cmp_m(mrb_state *mrb, mrb_value str1) +{ + mrb_value str2; + mrb_int result; + + mrb_get_args(mrb, "o", &str2); + if (!mrb_string_p(str2)) { + if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_s"))) { + return mrb_nil_value(); + } + else if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "<=>"))) { + return mrb_nil_value(); + } + else { + mrb_value tmp = mrb_funcall(mrb, str2, "<=>", 1, str1); + + if (!mrb_nil_p(tmp)) return mrb_nil_value(); + if (!mrb_fixnum_p(tmp)) { + return mrb_funcall(mrb, mrb_fixnum_value(0), "-", 1, tmp); + } + result = -mrb_fixnum(tmp); + } + } + else { + result = mrb_str_cmp(mrb, str1, str2); + } + return mrb_fixnum_value(result); +} + +static mrb_bool +str_eql(mrb_state *mrb, const mrb_value str1, const mrb_value str2) +{ + const mrb_int len = RSTRING_LEN(str1); + + if (len != RSTRING_LEN(str2)) return FALSE; + if (memcmp(RSTRING_PTR(str1), RSTRING_PTR(str2), (size_t)len) == 0) + return TRUE; + return FALSE; +} + +MRB_API mrb_bool +mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2) +{ + if (mrb_immediate_p(str2)) return FALSE; + if (!mrb_string_p(str2)) { + if (mrb_nil_p(str2)) return FALSE; + if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_str"))) { + return FALSE; + } + str2 = mrb_funcall(mrb, str2, "to_str", 0); + return mrb_equal(mrb, str2, str1); + } + return str_eql(mrb, str1, str2); +} + +/* 15.2.10.5.4 */ +/* + * call-seq: + * str == obj => true or false + * + * Equality--- + * If <i>obj</i> is not a <code>String</code>, returns <code>false</code>. + * Otherwise, returns <code>false</code> or <code>true</code> + * + * caution:if <i>str</i> <code><=></code> <i>obj</i> returns zero. + */ +static mrb_value +mrb_str_equal_m(mrb_state *mrb, mrb_value str1) +{ + mrb_value str2; + + mrb_get_args(mrb, "o", &str2); + + return mrb_bool_value(mrb_str_equal(mrb, str1, str2)); +} +/* ---------------------------------- */ +MRB_API mrb_value +mrb_str_to_str(mrb_state *mrb, mrb_value str) +{ + mrb_value s; + + if (!mrb_string_p(str)) { + s = mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); + if (mrb_nil_p(s)) { + s = mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); + } + return s; + } + return str; +} + +MRB_API const char* +mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr) +{ + mrb_value str = mrb_str_to_str(mrb, ptr); + return RSTRING_PTR(str); +} + +MRB_API mrb_int +mrb_string_value_len(mrb_state *mrb, mrb_value ptr) +{ + mrb_value str = mrb_str_to_str(mrb, ptr); + return RSTRING_LEN(str); +} + +void +mrb_noregexp(mrb_state *mrb, mrb_value self) +{ + mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented"); +} + +void +mrb_regexp_check(mrb_state *mrb, mrb_value obj) +{ + if (mrb_regexp_p(mrb, obj)) { + mrb_noregexp(mrb, obj); + } +} + +MRB_API mrb_value +mrb_str_dup(mrb_state *mrb, mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + struct RString *dup = str_new(mrb, 0, 0); + + str_with_class(mrb, dup, str); + return str_replace(mrb, dup, s); +} + +static mrb_value +mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) +{ + mrb_int idx; + + mrb_regexp_check(mrb, indx); + switch (mrb_type(indx)) { + case MRB_TT_FIXNUM: + idx = mrb_fixnum(indx); + +num_index: + str = str_substr(mrb, str, idx, 1); + if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); + return str; + + case MRB_TT_STRING: + if (str_index_str(mrb, str, indx, 0) != -1) + return mrb_str_dup(mrb, indx); + return mrb_nil_value(); + + case MRB_TT_RANGE: + goto range_arg; + + default: + indx = mrb_Integer(mrb, indx); + if (mrb_nil_p(indx)) { + range_arg: + { + mrb_int beg, len; + + len = RSTRING_CHAR_LEN(str); + switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) { + case 1: + return str_subseq(mrb, str, beg, len); + case 2: + return mrb_nil_value(); + default: + break; + } + } + mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); + } + idx = mrb_fixnum(indx); + goto num_index; + } + return mrb_nil_value(); /* not reached */ +} + +/* 15.2.10.5.6 */ +/* 15.2.10.5.34 */ +/* + * call-seq: + * str[fixnum] => fixnum or nil + * str[fixnum, fixnum] => new_str or nil + * str[range] => new_str or nil + * str[regexp] => new_str or nil + * str[regexp, fixnum] => new_str or nil + * str[other_str] => new_str or nil + * str.slice(fixnum) => fixnum or nil + * str.slice(fixnum, fixnum) => new_str or nil + * str.slice(range) => new_str or nil + * str.slice(other_str) => new_str or nil + * + * Element Reference---If passed a single <code>Fixnum</code>, returns the code + * of the character at that position. If passed two <code>Fixnum</code> + * objects, returns a substring starting at the offset given by the first, and + * a length given by the second. If given a range, a substring containing + * characters at offsets given by the range is returned. In all three cases, if + * an offset is negative, it is counted from the end of <i>str</i>. Returns + * <code>nil</code> if the initial offset falls outside the string, the length + * is negative, or the beginning of the range is greater than the end. + * + * If a <code>String</code> is given, that string is returned if it occurs in + * <i>str</i>. In both cases, <code>nil</code> is returned if there is no + * match. + * + * a = "hello there" + * a[1] #=> 101(1.8.7) "e"(1.9.2) + * a[1.1] #=> "e"(1.9.2) + * a[1,3] #=> "ell" + * a[1..3] #=> "ell" + * a[-3,2] #=> "er" + * a[-4..-2] #=> "her" + * a[12..-1] #=> nil + * a[-2..-4] #=> "" + * a["lo"] #=> "lo" + * a["bye"] #=> nil + */ +static mrb_value +mrb_str_aref_m(mrb_state *mrb, mrb_value str) +{ + mrb_value a1, a2; + int argc; + + argc = mrb_get_args(mrb, "o|o", &a1, &a2); + if (argc == 2) { + mrb_int n1, n2; + + mrb_regexp_check(mrb, a1); + mrb_get_args(mrb, "ii", &n1, &n2); + return str_substr(mrb, str, n1, n2); + } + if (argc != 1) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc)); + } + return mrb_str_aref(mrb, str, a1); +} + +/* 15.2.10.5.8 */ +/* + * call-seq: + * str.capitalize! => str or nil + * + * Modifies <i>str</i> by converting the first character to uppercase and the + * remainder to lowercase. Returns <code>nil</code> if no changes are made. + * + * a = "hello" + * a.capitalize! #=> "Hello" + * a #=> "Hello" + * a.capitalize! #=> nil + */ +static mrb_value +mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str) +{ + char *p, *pend; + mrb_bool modify = FALSE; + struct RString *s = mrb_str_ptr(str); + + mrb_str_modify(mrb, s); + if (RSTR_LEN(s) == 0 || !RSTR_PTR(s)) return mrb_nil_value(); + p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); + if (ISLOWER(*p)) { + *p = TOUPPER(*p); + modify = TRUE; + } + while (++p < pend) { + if (ISUPPER(*p)) { + *p = TOLOWER(*p); + modify = TRUE; + } + } + if (modify) return str; + return mrb_nil_value(); +} + +/* 15.2.10.5.7 */ +/* + * call-seq: + * str.capitalize => new_str + * + * Returns a copy of <i>str</i> with the first character converted to uppercase + * and the remainder to lowercase. + * + * "hello".capitalize #=> "Hello" + * "HELLO".capitalize #=> "Hello" + * "123ABC".capitalize #=> "123abc" + */ +static mrb_value +mrb_str_capitalize(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + + str = mrb_str_dup(mrb, self); + mrb_str_capitalize_bang(mrb, str); + return str; +} + +/* 15.2.10.5.10 */ +/* + * call-seq: + * str.chomp!(separator="\n") => str or nil + * + * Modifies <i>str</i> in place as described for <code>String#chomp</code>, + * returning <i>str</i>, or <code>nil</code> if no modifications were made. + */ +static mrb_value +mrb_str_chomp_bang(mrb_state *mrb, mrb_value str) +{ + mrb_value rs; + mrb_int newline; + char *p, *pp; + mrb_int rslen; + mrb_int len; + mrb_int argc; + struct RString *s = mrb_str_ptr(str); + + mrb_str_modify(mrb, s); + argc = mrb_get_args(mrb, "|S", &rs); + len = RSTR_LEN(s); + if (argc == 0) { + if (len == 0) return mrb_nil_value(); + smart_chomp: + if (RSTR_PTR(s)[len-1] == '\n') { + RSTR_SET_LEN(s, RSTR_LEN(s) - 1); + if (RSTR_LEN(s) > 0 && + RSTR_PTR(s)[RSTR_LEN(s)-1] == '\r') { + RSTR_SET_LEN(s, RSTR_LEN(s) - 1); + } + } + else if (RSTR_PTR(s)[len-1] == '\r') { + RSTR_SET_LEN(s, RSTR_LEN(s) - 1); + } + else { + return mrb_nil_value(); + } + RSTR_PTR(s)[RSTR_LEN(s)] = '\0'; + return str; + } + + if (len == 0 || mrb_nil_p(rs)) return mrb_nil_value(); + p = RSTR_PTR(s); + rslen = RSTRING_LEN(rs); + if (rslen == 0) { + while (len>0 && p[len-1] == '\n') { + len--; + if (len>0 && p[len-1] == '\r') + len--; + } + if (len < RSTR_LEN(s)) { + RSTR_SET_LEN(s, len); + p[len] = '\0'; + return str; + } + return mrb_nil_value(); + } + if (rslen > len) return mrb_nil_value(); + newline = RSTRING_PTR(rs)[rslen-1]; + if (rslen == 1 && newline == '\n') + newline = RSTRING_PTR(rs)[rslen-1]; + if (rslen == 1 && newline == '\n') + goto smart_chomp; + + pp = p + len - rslen; + if (p[len-1] == newline && + (rslen <= 1 || + memcmp(RSTRING_PTR(rs), pp, rslen) == 0)) { + RSTR_SET_LEN(s, len - rslen); + p[RSTR_LEN(s)] = '\0'; + return str; + } + return mrb_nil_value(); +} + +/* 15.2.10.5.9 */ +/* + * call-seq: + * str.chomp(separator="\n") => new_str + * + * Returns a new <code>String</code> with the given record separator removed + * from the end of <i>str</i> (if present). If <code>$/</code> has not been + * changed from the default Ruby record separator, then <code>chomp</code> also + * removes carriage return characters (that is it will remove <code>\n</code>, + * <code>\r</code>, and <code>\r\n</code>). + * + * "hello".chomp #=> "hello" + * "hello\n".chomp #=> "hello" + * "hello\r\n".chomp #=> "hello" + * "hello\n\r".chomp #=> "hello\n" + * "hello\r".chomp #=> "hello" + * "hello \n there".chomp #=> "hello \n there" + * "hello".chomp("llo") #=> "he" + */ +static mrb_value +mrb_str_chomp(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + + str = mrb_str_dup(mrb, self); + mrb_str_chomp_bang(mrb, str); + return str; +} + +/* 15.2.10.5.12 */ +/* + * call-seq: + * str.chop! => str or nil + * + * Processes <i>str</i> as for <code>String#chop</code>, returning <i>str</i>, + * or <code>nil</code> if <i>str</i> is the empty string. See also + * <code>String#chomp!</code>. + */ +static mrb_value +mrb_str_chop_bang(mrb_state *mrb, mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + + mrb_str_modify(mrb, s); + if (RSTR_LEN(s) > 0) { + mrb_int len; +#ifdef MRB_UTF8_STRING + const char* t = RSTR_PTR(s), *p = t; + const char* e = p + RSTR_LEN(s); + while (p<e) { + mrb_int clen = utf8len(p, e); + if (p + clen>=e) break; + p += clen; + } + len = p - t; +#else + len = RSTR_LEN(s) - 1; +#endif + if (RSTR_PTR(s)[len] == '\n') { + if (len > 0 && + RSTR_PTR(s)[len-1] == '\r') { + len--; + } + } + RSTR_SET_LEN(s, len); + RSTR_PTR(s)[len] = '\0'; + return str; + } + return mrb_nil_value(); +} + +/* 15.2.10.5.11 */ +/* + * call-seq: + * str.chop => new_str + * + * Returns a new <code>String</code> with the last character removed. If the + * string ends with <code>\r\n</code>, both characters are removed. Applying + * <code>chop</code> to an empty string returns an empty + * string. <code>String#chomp</code> is often a safer alternative, as it leaves + * the string unchanged if it doesn't end in a record separator. + * + * "string\r\n".chop #=> "string" + * "string\n\r".chop #=> "string\n" + * "string\n".chop #=> "string" + * "string".chop #=> "strin" + * "x".chop #=> "" + */ +static mrb_value +mrb_str_chop(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + str = mrb_str_dup(mrb, self); + mrb_str_chop_bang(mrb, str); + return str; +} + +/* 15.2.10.5.14 */ +/* + * call-seq: + * str.downcase! => str or nil + * + * Downcases the contents of <i>str</i>, returning <code>nil</code> if no + * changes were made. + */ +static mrb_value +mrb_str_downcase_bang(mrb_state *mrb, mrb_value str) +{ + char *p, *pend; + mrb_bool modify = FALSE; + struct RString *s = mrb_str_ptr(str); + + mrb_str_modify(mrb, s); + p = RSTR_PTR(s); + pend = RSTR_PTR(s) + RSTR_LEN(s); + while (p < pend) { + if (ISUPPER(*p)) { + *p = TOLOWER(*p); + modify = TRUE; + } + p++; + } + + if (modify) return str; + return mrb_nil_value(); +} + +/* 15.2.10.5.13 */ +/* + * call-seq: + * str.downcase => new_str + * + * Returns a copy of <i>str</i> with all uppercase letters replaced with their + * lowercase counterparts. The operation is locale insensitive---only + * characters 'A' to 'Z' are affected. + * + * "hEllO".downcase #=> "hello" + */ +static mrb_value +mrb_str_downcase(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + + str = mrb_str_dup(mrb, self); + mrb_str_downcase_bang(mrb, str); + return str; +} + +/* 15.2.10.5.16 */ +/* + * call-seq: + * str.empty? => true or false + * + * Returns <code>true</code> if <i>str</i> has a length of zero. + * + * "hello".empty? #=> false + * "".empty? #=> true + */ +static mrb_value +mrb_str_empty_p(mrb_state *mrb, mrb_value self) +{ + struct RString *s = mrb_str_ptr(self); + + return mrb_bool_value(RSTR_LEN(s) == 0); +} + +/* 15.2.10.5.17 */ +/* + * call-seq: + * str.eql?(other) => true or false + * + * Two strings are equal if the have the same length and content. + */ +static mrb_value +mrb_str_eql(mrb_state *mrb, mrb_value self) +{ + mrb_value str2; + mrb_bool eql_p; + + mrb_get_args(mrb, "o", &str2); + eql_p = (mrb_type(str2) == MRB_TT_STRING) && str_eql(mrb, self, str2); + + return mrb_bool_value(eql_p); +} + +MRB_API mrb_value +mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + return str_substr(mrb, str, beg, len); +} + +mrb_int +mrb_str_hash(mrb_state *mrb, mrb_value str) +{ + /* 1-8-7 */ + struct RString *s = mrb_str_ptr(str); + mrb_int len = RSTR_LEN(s); + char *p = RSTR_PTR(s); + uint64_t key = 0; + + while (len--) { + key = key*65599 + *p; + p++; + } + return (mrb_int)(key + (key>>5)); +} + +/* 15.2.10.5.20 */ +/* + * call-seq: + * str.hash => fixnum + * + * Return a hash based on the string's length and content. + */ +static mrb_value +mrb_str_hash_m(mrb_state *mrb, mrb_value self) +{ + mrb_int key = mrb_str_hash(mrb, self); + return mrb_fixnum_value(key); +} + +/* 15.2.10.5.21 */ +/* + * call-seq: + * str.include? other_str => true or false + * str.include? fixnum => true or false + * + * Returns <code>true</code> if <i>str</i> contains the given string or + * character. + * + * "hello".include? "lo" #=> true + * "hello".include? "ol" #=> false + * "hello".include? ?h #=> true + */ +static mrb_value +mrb_str_include(mrb_state *mrb, mrb_value self) +{ + mrb_value str2; + + mrb_get_args(mrb, "S", &str2); + if (str_index_str(mrb, self, str2, 0) < 0) + return mrb_bool_value(FALSE); + return mrb_bool_value(TRUE); +} + +/* 15.2.10.5.22 */ +/* + * call-seq: + * str.index(substring [, offset]) => fixnum or nil + * str.index(fixnum [, offset]) => fixnum or nil + * str.index(regexp [, offset]) => fixnum or nil + * + * Returns the index of the first occurrence of the given + * <i>substring</i>, + * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. + * Returns + * <code>nil</code> if not found. + * If the second parameter is present, it + * specifies the position in the string to begin the search. + * + * "hello".index('e') #=> 1 + * "hello".index('lo') #=> 3 + * "hello".index('a') #=> nil + * "hello".index(101) #=> 1(101=0x65='e') + * "hello".index(/[aeiou]/, -3) #=> 4 + */ +static mrb_value +mrb_str_index_m(mrb_state *mrb, mrb_value str) +{ + mrb_value *argv; + mrb_int argc; + mrb_value sub; + mrb_int pos, clen; + + mrb_get_args(mrb, "*!", &argv, &argc); + if (argc == 2) { + mrb_get_args(mrb, "oi", &sub, &pos); + } + else { + pos = 0; + if (argc > 0) + sub = argv[0]; + else + sub = mrb_nil_value(); + } + mrb_regexp_check(mrb, sub); + clen = RSTRING_CHAR_LEN(str); + if (pos < 0) { + pos += clen; + if (pos < 0) { + return mrb_nil_value(); + } + } + if (pos > clen) return mrb_nil_value(); + pos = chars2bytes(str, 0, pos); + + switch (mrb_type(sub)) { + default: { + mrb_value tmp; + + tmp = mrb_check_string_type(mrb, sub); + if (mrb_nil_p(tmp)) { + mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub); + } + sub = tmp; + } + /* fall through */ + case MRB_TT_STRING: + pos = str_index_str(mrb, str, sub, pos); + break; + } + + if (pos == -1) return mrb_nil_value(); + pos = bytes2chars(RSTRING_PTR(str), pos); + BYTES_ALIGN_CHECK(pos); + return mrb_fixnum_value(pos); +} + +#define STR_REPLACE_SHARED_MIN 10 + +/* 15.2.10.5.24 */ +/* 15.2.10.5.28 */ +/* + * call-seq: + * str.replace(other_str) => str + * + * s = "hello" #=> "hello" + * s.replace "world" #=> "world" + */ +static mrb_value +mrb_str_replace(mrb_state *mrb, mrb_value str) +{ + mrb_value str2; + + mrb_get_args(mrb, "S", &str2); + return str_replace(mrb, mrb_str_ptr(str), mrb_str_ptr(str2)); +} + +/* 15.2.10.5.23 */ +/* + * call-seq: + * String.new(str="") => new_str + * + * Returns a new string object containing a copy of <i>str</i>. + */ +static mrb_value +mrb_str_init(mrb_state *mrb, mrb_value self) +{ + mrb_value str2; + + if (mrb_get_args(mrb, "|S", &str2) == 0) { + struct RString *s = str_new(mrb, 0, 0); + str2 = mrb_obj_value(s); + } + str_replace(mrb, mrb_str_ptr(self), mrb_str_ptr(str2)); + return self; +} + +/* 15.2.10.5.25 */ +/* 15.2.10.5.41 */ +/* + * call-seq: + * str.intern => symbol + * str.to_sym => symbol + * + * Returns the <code>Symbol</code> corresponding to <i>str</i>, creating the + * symbol if it did not previously exist. See <code>Symbol#id2name</code>. + * + * "Koala".intern #=> :Koala + * s = 'cat'.to_sym #=> :cat + * s == :cat #=> true + * s = '@cat'.to_sym #=> :@cat + * s == :@cat #=> true + * + * This can also be used to create symbols that cannot be represented using the + * <code>:xxx</code> notation. + * + * 'cat and dog'.to_sym #=> :"cat and dog" + */ +MRB_API mrb_value +mrb_str_intern(mrb_state *mrb, mrb_value self) +{ + return mrb_symbol_value(mrb_intern_str(mrb, self)); +} +/* ---------------------------------- */ +MRB_API mrb_value +mrb_obj_as_string(mrb_state *mrb, mrb_value obj) +{ + mrb_value str; + + if (mrb_string_p(obj)) { + return obj; + } + str = mrb_funcall(mrb, obj, "to_s", 0); + if (!mrb_string_p(str)) + return mrb_any_to_s(mrb, obj); + return str; +} + +MRB_API mrb_value +mrb_ptr_to_str(mrb_state *mrb, void *p) +{ + struct RString *p_str; + char *p1; + char *p2; + uintptr_t n = (uintptr_t)p; + + p_str = str_new(mrb, NULL, 2 + sizeof(uintptr_t) * CHAR_BIT / 4); + p1 = RSTR_PTR(p_str); + *p1++ = '0'; + *p1++ = 'x'; + p2 = p1; + + do { + *p2++ = mrb_digitmap[n % 16]; + n /= 16; + } while (n > 0); + *p2 = '\0'; + RSTR_SET_LEN(p_str, (mrb_int)(p2 - RSTR_PTR(p_str))); + + while (p1 < p2) { + const char c = *p1; + *p1++ = *--p2; + *p2 = c; + } + + return mrb_obj_value(p_str); +} + +MRB_API mrb_value +mrb_string_type(mrb_state *mrb, mrb_value str) +{ + return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); +} + +MRB_API mrb_value +mrb_check_string_type(mrb_state *mrb, mrb_value str) +{ + return mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); +} + +/* 15.2.10.5.30 */ +/* + * call-seq: + * str.reverse! => str + * + * Reverses <i>str</i> in place. + */ +static mrb_value +mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) +{ +#ifdef MRB_UTF8_STRING + mrb_int utf8_len = RSTRING_CHAR_LEN(str); + mrb_int len = RSTRING_LEN(str); + + if (utf8_len == len) goto bytes; + if (utf8_len > 1) { + char *buf; + char *p, *e, *r; + + mrb_str_modify(mrb, mrb_str_ptr(str)); + len = RSTRING_LEN(str); + buf = (char*)mrb_malloc(mrb, (size_t)len); + p = buf; + e = buf + len; + + memcpy(buf, RSTRING_PTR(str), len); + r = RSTRING_PTR(str) + len; + + while (p<e) { + mrb_int clen = utf8len(p, e); + r -= clen; + memcpy(r, p, clen); + p += clen; + } + mrb_free(mrb, buf); + } + return str; + + bytes: +#endif + { + struct RString *s = mrb_str_ptr(str); + char *p, *e; + char c; + + mrb_str_modify(mrb, s); + if (RSTR_LEN(s) > 1) { + p = RSTR_PTR(s); + e = p + RSTR_LEN(s) - 1; + while (p < e) { + c = *p; + *p++ = *e; + *e-- = c; + } + } + return str; + } +} + +/* ---------------------------------- */ +/* 15.2.10.5.29 */ +/* + * call-seq: + * str.reverse => new_str + * + * Returns a new string with the characters from <i>str</i> in reverse order. + * + * "stressed".reverse #=> "desserts" + */ +static mrb_value +mrb_str_reverse(mrb_state *mrb, mrb_value str) +{ + mrb_value str2 = mrb_str_dup(mrb, str); + mrb_str_reverse_bang(mrb, str2); + return str2; +} + +/* 15.2.10.5.31 */ +/* + * call-seq: + * str.rindex(substring [, fixnum]) => fixnum or nil + * str.rindex(fixnum [, fixnum]) => fixnum or nil + * str.rindex(regexp [, fixnum]) => fixnum or nil + * + * Returns the index of the last occurrence of the given <i>substring</i>, + * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. Returns + * <code>nil</code> if not found. If the second parameter is present, it + * specifies the position in the string to end the search---characters beyond + * this point will not be considered. + * + * "hello".rindex('e') #=> 1 + * "hello".rindex('l') #=> 3 + * "hello".rindex('a') #=> nil + * "hello".rindex(101) #=> 1 + * "hello".rindex(/[aeiou]/, -2) #=> 1 + */ +static mrb_value +mrb_str_rindex(mrb_state *mrb, mrb_value str) +{ + mrb_value *argv; + mrb_int argc; + mrb_value sub; + mrb_int pos, len = RSTRING_CHAR_LEN(str); + + mrb_get_args(mrb, "*!", &argv, &argc); + if (argc == 2) { + mrb_get_args(mrb, "oi", &sub, &pos); + if (pos < 0) { + pos += len; + if (pos < 0) { + mrb_regexp_check(mrb, sub); + return mrb_nil_value(); + } + } + if (pos > len) pos = len; + } + else { + pos = len; + if (argc > 0) + sub = argv[0]; + else + sub = mrb_nil_value(); + } + pos = chars2bytes(str, 0, pos); + mrb_regexp_check(mrb, sub); + + switch (mrb_type(sub)) { + default: { + mrb_value tmp; + + tmp = mrb_check_string_type(mrb, sub); + if (mrb_nil_p(tmp)) { + mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub); + } + sub = tmp; + } + /* fall through */ + case MRB_TT_STRING: + pos = str_rindex(mrb, str, sub, pos); + if (pos >= 0) { + pos = bytes2chars(RSTRING_PTR(str), pos); + BYTES_ALIGN_CHECK(pos); + return mrb_fixnum_value(pos); + } + break; + + } /* end of switch (TYPE(sub)) */ + return mrb_nil_value(); +} + +/* 15.2.10.5.35 */ + +/* + * call-seq: + * str.split(pattern="\n", [limit]) => anArray + * + * Divides <i>str</i> into substrings based on a delimiter, returning an array + * of these substrings. + * + * If <i>pattern</i> is a <code>String</code>, then its contents are used as + * the delimiter when splitting <i>str</i>. If <i>pattern</i> is a single + * space, <i>str</i> is split on whitespace, with leading whitespace and runs + * of contiguous whitespace characters ignored. + * + * If <i>pattern</i> is a <code>Regexp</code>, <i>str</i> is divided where the + * pattern matches. Whenever the pattern matches a zero-length string, + * <i>str</i> is split into individual characters. + * + * If <i>pattern</i> is omitted, the value of <code>$;</code> is used. If + * <code>$;</code> is <code>nil</code> (which is the default), <i>str</i> is + * split on whitespace as if ' ' were specified. + * + * If the <i>limit</i> parameter is omitted, trailing null fields are + * suppressed. If <i>limit</i> is a positive number, at most that number of + * fields will be returned (if <i>limit</i> is <code>1</code>, the entire + * string is returned as the only entry in an array). If negative, there is no + * limit to the number of fields returned, and trailing null fields are not + * suppressed. + * + * " now's the time".split #=> ["now's", "the", "time"] + * " now's the time".split(' ') #=> ["now's", "the", "time"] + * " now's the time".split(/ /) #=> ["", "now's", "", "the", "time"] + * "hello".split(//) #=> ["h", "e", "l", "l", "o"] + * "hello".split(//, 3) #=> ["h", "e", "llo"] + * + * "mellow yellow".split("ello") #=> ["m", "w y", "w"] + * "1,2,,3,4,,".split(',') #=> ["1", "2", "", "3", "4"] + * "1,2,,3,4,,".split(',', 4) #=> ["1", "2", "", "3,4,,"] + * "1,2,,3,4,,".split(',', -4) #=> ["1", "2", "", "3", "4", "", ""] + */ + +static mrb_value +mrb_str_split_m(mrb_state *mrb, mrb_value str) +{ + int argc; + mrb_value spat = mrb_nil_value(); + enum {awk, string, regexp} split_type = string; + mrb_int i = 0; + mrb_int beg; + mrb_int end; + mrb_int lim = 0; + mrb_bool lim_p; + mrb_value result, tmp; + + argc = mrb_get_args(mrb, "|oi", &spat, &lim); + lim_p = (lim > 0 && argc == 2); + if (argc == 2) { + if (lim == 1) { + if (RSTRING_LEN(str) == 0) + return mrb_ary_new_capa(mrb, 0); + return mrb_ary_new_from_values(mrb, 1, &str); + } + i = 1; + } + + if (argc == 0 || mrb_nil_p(spat)) { + split_type = awk; + } + else { + if (mrb_string_p(spat)) { + split_type = string; + if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { + split_type = awk; + } + } + else { + mrb_noregexp(mrb, str); + } + } + + result = mrb_ary_new(mrb); + beg = 0; + if (split_type == awk) { + mrb_bool skip = TRUE; + mrb_int idx = 0; + mrb_int str_len = RSTRING_LEN(str); + unsigned int c; + int ai = mrb_gc_arena_save(mrb); + + idx = end = beg; + while (idx < str_len) { + c = (unsigned char)RSTRING_PTR(str)[idx++]; + if (skip) { + if (ISSPACE(c)) { + beg = idx; + } + else { + end = idx; + skip = FALSE; + if (lim_p && lim <= i) break; + } + } + else if (ISSPACE(c)) { + mrb_ary_push(mrb, result, byte_subseq(mrb, str, beg, end-beg)); + mrb_gc_arena_restore(mrb, ai); + skip = TRUE; + beg = idx; + if (lim_p) ++i; + } + else { + end = idx; + } + } + } + else if (split_type == string) { + mrb_int str_len = RSTRING_LEN(str); + mrb_int pat_len = RSTRING_LEN(spat); + mrb_int idx = 0; + int ai = mrb_gc_arena_save(mrb); + + while (idx < str_len) { + if (pat_len > 0) { + end = mrb_memsearch(RSTRING_PTR(spat), pat_len, RSTRING_PTR(str)+idx, str_len - idx); + if (end < 0) break; + } + else { + end = chars2bytes(str, idx, 1); + } + mrb_ary_push(mrb, result, byte_subseq(mrb, str, idx, end)); + mrb_gc_arena_restore(mrb, ai); + idx += end + pat_len; + if (lim_p && lim <= ++i) break; + } + beg = idx; + } + else { + mrb_noregexp(mrb, str); + } + if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) { + if (RSTRING_LEN(str) == beg) { + tmp = mrb_str_new_empty(mrb, str); + } + else { + tmp = byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); + } + mrb_ary_push(mrb, result, tmp); + } + if (!lim_p && lim == 0) { + mrb_int len; + while ((len = RARRAY_LEN(result)) > 0 && + (tmp = RARRAY_PTR(result)[len-1], RSTRING_LEN(tmp) == 0)) + mrb_ary_pop(mrb, result); + } + + return result; +} + +MRB_API mrb_value +mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, int base, int badcheck) +{ + const char *p = str; + const char *pend = str + len; + char sign = 1; + int c; + uint64_t n = 0; + mrb_int val; + +#define conv_digit(c) \ + (ISDIGIT(c) ? ((c) - '0') : \ + ISLOWER(c) ? ((c) - 'a' + 10) : \ + ISUPPER(c) ? ((c) - 'A' + 10) : \ + -1) + + if (!p) { + if (badcheck) goto bad; + return mrb_fixnum_value(0); + } + while (p<pend && ISSPACE(*p)) + p++; + + if (p[0] == '+') { + p++; + } + else if (p[0] == '-') { + p++; + sign = 0; + } + if (base <= 0) { + if (p[0] == '0') { + switch (p[1]) { + case 'x': case 'X': + base = 16; + break; + case 'b': case 'B': + base = 2; + break; + case 'o': case 'O': + base = 8; + break; + case 'd': case 'D': + base = 10; + break; + default: + base = 8; + break; + } + } + else if (base < -1) { + base = -base; + } + else { + base = 10; + } + } + switch (base) { + case 2: + if (p[0] == '0' && (p[1] == 'b'||p[1] == 'B')) { + p += 2; + } + break; + case 3: + break; + case 8: + if (p[0] == '0' && (p[1] == 'o'||p[1] == 'O')) { + p += 2; + } + case 4: case 5: case 6: case 7: + break; + case 10: + if (p[0] == '0' && (p[1] == 'd'||p[1] == 'D')) { + p += 2; + } + case 9: case 11: case 12: case 13: case 14: case 15: + break; + case 16: + if (p[0] == '0' && (p[1] == 'x'||p[1] == 'X')) { + p += 2; + } + break; + default: + if (base < 2 || 36 < base) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base)); + } + break; + } /* end of switch (base) { */ + if (p>=pend) { + if (badcheck) goto bad; + return mrb_fixnum_value(0); + } + if (*p == '0') { /* squeeze preceding 0s */ + p++; + while (p<pend) { + c = *p++; + if (c == '_') { + if (p<pend && *p == '_') { + if (badcheck) goto bad; + break; + } + continue; + } + if (c != '0') { + p--; + break; + } + } + if (*(p - 1) == '0') + p--; + } + if (p == pend) { + if (badcheck) goto bad; + return mrb_fixnum_value(0); + } + for ( ;p<pend;p++) { + if (*p == '_') { + p++; + if (p==pend) { + if (badcheck) goto bad; + continue; + } + if (*p == '_') { + if (badcheck) goto bad; + break; + } + } + if (badcheck && *p == '\0') { + goto nullbyte; + } + c = conv_digit(*p); + if (c < 0 || c >= base) { + break; + } + n *= base; + n += c; + if (n > (uint64_t)MRB_INT_MAX + (sign ? 0 : 1)) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", + mrb_str_new(mrb, str, pend-str)); + } + } + val = (mrb_int)n; + if (badcheck) { + if (p == str) goto bad; /* no number */ + while (p<pend && ISSPACE(*p)) p++; + if (p<pend) goto bad; /* trailing garbage */ + } + + return mrb_fixnum_value(sign ? val : -val); + nullbyte: + mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); + /* not reached */ + bad: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%S)", + mrb_inspect(mrb, mrb_str_new(mrb, str, pend-str))); + /* not reached */ + return mrb_fixnum_value(0); +} + +MRB_API mrb_value +mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) +{ + return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck); +} + +MRB_API const char* +mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) +{ + mrb_value str = mrb_str_to_str(mrb, *ptr); + struct RString *ps = mrb_str_ptr(str); + mrb_int len = mrb_str_strlen(mrb, ps); + char *p = RSTR_PTR(ps); + + if (!p || p[len] != '\0') { + if (MRB_FROZEN_P(ps)) { + *ptr = str = mrb_str_dup(mrb, str); + ps = mrb_str_ptr(str); + } + mrb_str_modify(mrb, ps); + return RSTR_PTR(ps); + } + return p; +} + +MRB_API mrb_value +mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) +{ + const char *s; + mrb_int len; + + s = mrb_string_value_ptr(mrb, str); + len = RSTRING_LEN(str); + return mrb_str_len_to_inum(mrb, s, len, base, badcheck); +} + +/* 15.2.10.5.38 */ +/* + * call-seq: + * str.to_i(base=10) => integer + * + * Returns the result of interpreting leading characters in <i>str</i> as an + * integer base <i>base</i> (between 2 and 36). Extraneous characters past the + * end of a valid number are ignored. If there is not a valid number at the + * start of <i>str</i>, <code>0</code> is returned. This method never raises an + * exception. + * + * "12345".to_i #=> 12345 + * "99 red balloons".to_i #=> 99 + * "0a".to_i #=> 0 + * "0a".to_i(16) #=> 10 + * "hello".to_i #=> 0 + * "1100101".to_i(2) #=> 101 + * "1100101".to_i(8) #=> 294977 + * "1100101".to_i(10) #=> 1100101 + * "1100101".to_i(16) #=> 17826049 + */ +static mrb_value +mrb_str_to_i(mrb_state *mrb, mrb_value self) +{ + mrb_int base = 10; + + mrb_get_args(mrb, "|i", &base); + if (base < 0) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base)); + } + return mrb_str_to_inum(mrb, self, base, FALSE); +} + +MRB_API double +mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) +{ + char *end; + char buf[DBL_DIG * 4 + 10]; + double d; + + enum {max_width = 20}; + + if (!p) return 0.0; + while (ISSPACE(*p)) p++; + + if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + return 0.0; + } + d = mrb_float_read(p, &end); + if (p == end) { + if (badcheck) { +bad: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%S)", mrb_str_new_cstr(mrb, p)); + /* not reached */ + } + return d; + } + if (*end) { + char *n = buf; + char *e = buf + sizeof(buf) - 1; + char prev = 0; + + while (p < end && n < e) prev = *n++ = *p++; + while (*p) { + if (*p == '_') { + /* remove underscores between digits */ + if (badcheck) { + if (n == buf || !ISDIGIT(prev)) goto bad; + ++p; + if (!ISDIGIT(*p)) goto bad; + } + else { + while (*++p == '_'); + continue; + } + } + prev = *p++; + if (n < e) *n++ = prev; + } + *n = '\0'; + p = buf; + + if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + return 0.0; + } + + d = mrb_float_read(p, &end); + if (badcheck) { + if (!end || p == end) goto bad; + while (*end && ISSPACE(*end)) end++; + if (*end) goto bad; + } + } + return d; +} + +MRB_API double +mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) +{ + char *s; + mrb_int len; + + str = mrb_str_to_str(mrb, str); + s = RSTRING_PTR(str); + len = RSTRING_LEN(str); + if (s) { + if (badcheck && memchr(s, '\0', len)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte"); + } + if (s[len]) { /* no sentinel somehow */ + struct RString *temp_str = str_new(mrb, s, len); + s = RSTR_PTR(temp_str); + } + } + return mrb_cstr_to_dbl(mrb, s, badcheck); +} + +/* 15.2.10.5.39 */ +/* + * call-seq: + * str.to_f => float + * + * Returns the result of interpreting leading characters in <i>str</i> as a + * floating point number. Extraneous characters past the end of a valid number + * are ignored. If there is not a valid number at the start of <i>str</i>, + * <code>0.0</code> is returned. This method never raises an exception. + * + * "123.45e1".to_f #=> 1234.5 + * "45.67 degrees".to_f #=> 45.67 + * "thx1138".to_f #=> 0.0 + */ +static mrb_value +mrb_str_to_f(mrb_state *mrb, mrb_value self) +{ + return mrb_float_value(mrb, mrb_str_to_dbl(mrb, self, FALSE)); +} + +/* 15.2.10.5.40 */ +/* + * call-seq: + * str.to_s => str + * str.to_str => str + * + * Returns the receiver. + */ +static mrb_value +mrb_str_to_s(mrb_state *mrb, mrb_value self) +{ + if (mrb_obj_class(mrb, self) != mrb->string_class) { + return mrb_str_dup(mrb, self); + } + return self; +} + +/* 15.2.10.5.43 */ +/* + * call-seq: + * str.upcase! => str or nil + * + * Upcases the contents of <i>str</i>, returning <code>nil</code> if no changes + * were made. + */ +static mrb_value +mrb_str_upcase_bang(mrb_state *mrb, mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + char *p, *pend; + mrb_bool modify = FALSE; + + mrb_str_modify(mrb, s); + p = RSTRING_PTR(str); + pend = RSTRING_END(str); + while (p < pend) { + if (ISLOWER(*p)) { + *p = TOUPPER(*p); + modify = TRUE; + } + p++; + } + + if (modify) return str; + return mrb_nil_value(); +} + +/* 15.2.10.5.42 */ +/* + * call-seq: + * str.upcase => new_str + * + * Returns a copy of <i>str</i> with all lowercase letters replaced with their + * uppercase counterparts. The operation is locale insensitive---only + * characters 'a' to 'z' are affected. + * + * "hEllO".upcase #=> "HELLO" + */ +static mrb_value +mrb_str_upcase(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + + str = mrb_str_dup(mrb, self); + mrb_str_upcase_bang(mrb, str); + return str; +} + +#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{')) + +/* + * call-seq: + * str.dump -> new_str + * + * Produces a version of <i>str</i> with all nonprinting characters replaced by + * <code>\nnn</code> notation and all special characters escaped. + */ +mrb_value +mrb_str_dump(mrb_state *mrb, mrb_value str) +{ + mrb_int len; + const char *p, *pend; + char *q; + struct RString *result; + + len = 2; /* "" */ + p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); + while (p < pend) { + unsigned char c = *p++; + switch (c) { + case '"': case '\\': + case '\n': case '\r': + case '\t': case '\f': + case '\013': case '\010': case '\007': case '\033': + len += 2; + break; + + case '#': + len += IS_EVSTR(p, pend) ? 2 : 1; + break; + + default: + if (ISPRINT(c)) { + len++; + } + else { + len += 4; /* \NNN */ + } + break; + } + } + + result = str_new(mrb, 0, len); + str_with_class(mrb, result, str); + p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); + q = RSTR_PTR(result); + *q++ = '"'; + while (p < pend) { + unsigned char c = *p++; + + switch (c) { + case '"': + case '\\': + *q++ = '\\'; + *q++ = c; + break; + + case '\n': + *q++ = '\\'; + *q++ = 'n'; + break; + + case '\r': + *q++ = '\\'; + *q++ = 'r'; + break; + + case '\t': + *q++ = '\\'; + *q++ = 't'; + break; + + case '\f': + *q++ = '\\'; + *q++ = 'f'; + break; + + case '\013': + *q++ = '\\'; + *q++ = 'v'; + break; + + case '\010': + *q++ = '\\'; + *q++ = 'b'; + break; + + case '\007': + *q++ = '\\'; + *q++ = 'a'; + break; + + case '\033': + *q++ = '\\'; + *q++ = 'e'; + break; + + case '#': + if (IS_EVSTR(p, pend)) *q++ = '\\'; + *q++ = '#'; + break; + + default: + if (ISPRINT(c)) { + *q++ = c; + } + else { + *q++ = '\\'; + q[2] = '0' + c % 8; c /= 8; + q[1] = '0' + c % 8; c /= 8; + q[0] = '0' + c % 8; + q += 3; + } + } + } + *q = '"'; + return mrb_obj_value(result); +} + +MRB_API mrb_value +mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len) +{ + struct RString *s = mrb_str_ptr(str); + size_t capa; + size_t total; + ptrdiff_t off = -1; + + if (len == 0) return str; + mrb_str_modify(mrb, s); + if (ptr >= RSTR_PTR(s) && ptr <= RSTR_PTR(s) + (size_t)RSTR_LEN(s)) { + off = ptr - RSTR_PTR(s); + } + + capa = RSTR_CAPA(s); + total = RSTR_LEN(s)+len; + if (total >= MRB_INT_MAX) { + size_error: + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); + } + if (capa <= total) { + if (capa == 0) capa = 1; + while (capa <= total) { + if (capa <= MRB_INT_MAX / 2) { + capa *= 2; + } + else { + capa = total+1; + } + } + if (capa <= total || capa > MRB_INT_MAX) { + goto size_error; + } + resize_capa(mrb, s, capa); + } + if (off != -1) { + ptr = RSTR_PTR(s) + off; + } + memcpy(RSTR_PTR(s) + RSTR_LEN(s), ptr, len); + mrb_assert_int_fit(size_t, total, mrb_int, MRB_INT_MAX); + RSTR_SET_LEN(s, total); + RSTR_PTR(s)[total] = '\0'; /* sentinel */ + return str; +} + +MRB_API mrb_value +mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr) +{ + return mrb_str_cat(mrb, str, ptr, strlen(ptr)); +} + +MRB_API mrb_value +mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2) +{ + return mrb_str_cat(mrb, str, RSTRING_PTR(str2), RSTRING_LEN(str2)); +} + +MRB_API mrb_value +mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) +{ + str2 = mrb_str_to_str(mrb, str2); + return mrb_str_cat_str(mrb, str1, str2); +} + +#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */ + +/* + * call-seq: + * str.inspect -> string + * + * Returns a printable version of _str_, surrounded by quote marks, + * with special characters escaped. + * + * str = "hello" + * str[3] = "\b" + * str.inspect #=> "\"hel\\bo\"" + */ +mrb_value +mrb_str_inspect(mrb_state *mrb, mrb_value str) +{ + const char *p, *pend; + char buf[CHAR_ESC_LEN + 1]; + mrb_value result = mrb_str_new_lit(mrb, "\""); + + p = RSTRING_PTR(str); pend = RSTRING_END(str); + for (;p < pend; p++) { + unsigned char c, cc; +#ifdef MRB_UTF8_STRING + mrb_int clen; + + clen = utf8len(p, pend); + if (clen > 1) { + mrb_int i; + + for (i=0; i<clen; i++) { + buf[i] = p[i]; + } + mrb_str_cat(mrb, result, buf, clen); + p += clen-1; + continue; + } +#endif + c = *p; + if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p+1, pend))) { + buf[0] = '\\'; buf[1] = c; + mrb_str_cat(mrb, result, buf, 2); + continue; + } + if (ISPRINT(c)) { + buf[0] = c; + mrb_str_cat(mrb, result, buf, 1); + continue; + } + switch (c) { + case '\n': cc = 'n'; break; + case '\r': cc = 'r'; break; + case '\t': cc = 't'; break; + case '\f': cc = 'f'; break; + case '\013': cc = 'v'; break; + case '\010': cc = 'b'; break; + case '\007': cc = 'a'; break; + case 033: cc = 'e'; break; + default: cc = 0; break; + } + if (cc) { + buf[0] = '\\'; + buf[1] = (char)cc; + mrb_str_cat(mrb, result, buf, 2); + continue; + } + else { + buf[0] = '\\'; + buf[3] = '0' + c % 8; c /= 8; + buf[2] = '0' + c % 8; c /= 8; + buf[1] = '0' + c % 8; + mrb_str_cat(mrb, result, buf, 4); + continue; + } + } + mrb_str_cat_lit(mrb, result, "\""); + + return result; +} + +/* + * call-seq: + * str.bytes -> array of fixnums + * + * Returns an array of bytes in _str_. + * + * str = "hello" + * str.bytes #=> [104, 101, 108, 108, 111] + */ +static mrb_value +mrb_str_bytes(mrb_state *mrb, mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + mrb_value a = mrb_ary_new_capa(mrb, RSTR_LEN(s)); + unsigned char *p = (unsigned char *)(RSTR_PTR(s)), *pend = p + RSTR_LEN(s); + + while (p < pend) { + mrb_ary_push(mrb, a, mrb_fixnum_value(p[0])); + p++; + } + return a; +} + +/* ---------------------------*/ +void +mrb_init_string(mrb_state *mrb) +{ + struct RClass *s; + + mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << 5), "pointer size too big for embedded string"); + + mrb->string_class = s = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */ + MRB_SET_INSTANCE_TT(s, MRB_TT_STRING); + + mrb_define_method(mrb, s, "bytesize", mrb_str_bytesize, MRB_ARGS_NONE()); + + mrb_define_method(mrb, s, "<=>", mrb_str_cmp_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.1 */ + mrb_define_method(mrb, s, "==", mrb_str_equal_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.2 */ + mrb_define_method(mrb, s, "+", mrb_str_plus_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.4 */ + mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.5 */ + mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.6 */ + mrb_define_method(mrb, s, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */ + mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */ + mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */ + mrb_define_method(mrb, s, "chomp!", mrb_str_chomp_bang, MRB_ARGS_ANY()); /* 15.2.10.5.10 */ + mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_NONE()); /* 15.2.10.5.11 */ + mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_NONE()); /* 15.2.10.5.12 */ + mrb_define_method(mrb, s, "downcase", mrb_str_downcase, MRB_ARGS_NONE()); /* 15.2.10.5.13 */ + mrb_define_method(mrb, s, "downcase!", mrb_str_downcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.14 */ + mrb_define_method(mrb, s, "empty?", mrb_str_empty_p, MRB_ARGS_NONE()); /* 15.2.10.5.16 */ + mrb_define_method(mrb, s, "eql?", mrb_str_eql, MRB_ARGS_REQ(1)); /* 15.2.10.5.17 */ + + mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_NONE()); /* 15.2.10.5.20 */ + mrb_define_method(mrb, s, "include?", mrb_str_include, MRB_ARGS_REQ(1)); /* 15.2.10.5.21 */ + mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ANY()); /* 15.2.10.5.22 */ + mrb_define_method(mrb, s, "initialize", mrb_str_init, MRB_ARGS_REQ(1)); /* 15.2.10.5.23 */ + mrb_define_method(mrb, s, "initialize_copy", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.24 */ + mrb_define_method(mrb, s, "intern", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.25 */ + mrb_define_method(mrb, s, "length", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.26 */ + mrb_define_method(mrb, s, "replace", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.28 */ + mrb_define_method(mrb, s, "reverse", mrb_str_reverse, MRB_ARGS_NONE()); /* 15.2.10.5.29 */ + mrb_define_method(mrb, s, "reverse!", mrb_str_reverse_bang, MRB_ARGS_NONE()); /* 15.2.10.5.30 */ + mrb_define_method(mrb, s, "rindex", mrb_str_rindex, MRB_ARGS_ANY()); /* 15.2.10.5.31 */ + mrb_define_method(mrb, s, "size", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.33 */ + mrb_define_method(mrb, s, "slice", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.34 */ + mrb_define_method(mrb, s, "split", mrb_str_split_m, MRB_ARGS_ANY()); /* 15.2.10.5.35 */ + + mrb_define_method(mrb, s, "to_f", mrb_str_to_f, MRB_ARGS_NONE()); /* 15.2.10.5.38 */ + mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */ + mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */ + mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */ + mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */ + mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ + mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */ + mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE()); +} + +/* + * Source code for the "strtod" library procedure. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * RCS: @(#) $Id: strtod.c 11708 2007-02-12 23:01:19Z shyouhei $ + */ + +#include <ctype.h> +#include <errno.h> + +static const int maxExponent = 511; /* Largest possible base 10 exponent. Any + * exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. + */ +static const double powersOf10[] = {/* Table giving binary powers of 10. Entry */ + 10., /* is 10^2^i. Used to convert decimal */ + 100., /* exponents into floating-point numbers. */ + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +MRB_API double +mrb_float_read(const char *string, char **endPtr) +/* const char *string; A decimal ASCII floating-point number, + * optionally preceded by white space. + * Must have form "-I.FE-X", where I is the + * integer part of the mantissa, F is the + * fractional part of the mantissa, and X + * is the exponent. Either of the signs + * may be "+", "-", or omitted. Either I + * or F may be omitted, or both. The decimal + * point isn't necessary unless F is present. + * The "E" may actually be an "e". E and X + * may both be omitted (but not just one). + */ +/* char **endPtr; If non-NULL, store terminating character's + * address here. */ +{ + int sign, expSign = FALSE; + double fraction, dblExp; + const double *d; + register const char *p; + register int c; + int exp = 0; /* Exponent read from "EX" field. */ + int fracExp = 0; /* Exponent that derives from the fractional + * part. Under normal circumstatnces, it is + * the negative of the number of digits in F. + * However, if I is very long, the last digits + * of I get dropped (otherwise a long I with a + * large negative exponent could cause an + * unnecessary overflow on I alone). In this + * case, fracExp is incremented one for each + * dropped digit. */ + int mantSize; /* Number of digits in mantissa. */ + int decPt; /* Number of mantissa digits BEFORE decimal + * point. */ + const char *pExp; /* Temporarily holds location of exponent + * in string. */ + + /* + * Strip off leading blanks and check for a sign. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + if (*p == '-') { + sign = TRUE; + p += 1; + } + else { + if (*p == '+') { + p += 1; + } + sign = FALSE; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + + decPt = -1; + for (mantSize = 0; ; mantSize += 1) + { + c = *p; + if (!isdigit(c)) { + if ((c != '.') || (decPt >= 0)) { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) { + decPt = mantSize; + } + else { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) { + if (decPt - 18 > 29999) { + fracExp = 29999; + } + else { + fracExp = decPt - 18; + } + mantSize = 18; + } + else { + fracExp = decPt - mantSize; + } + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } + else { + int frac1, frac2; + frac1 = 0; + for ( ; mantSize > 9; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10*frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10*frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) { + p += 1; + if (*p == '-') { + expSign = TRUE; + p += 1; + } + else { + if (*p == '+') { + p += 1; + } + expSign = FALSE; + } + while (isdigit(*p)) { + exp = exp * 10 + (*p - '0'); + if (exp > 19999) { + exp = 19999; + } + p += 1; + } + } + if (expSign) { + exp = fracExp - exp; + } + else { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < 0) { + expSign = TRUE; + exp = -exp; + } + else { + expSign = FALSE; + } + if (exp > maxExponent) { + exp = maxExponent; + errno = ERANGE; + } + dblExp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) { + dblExp *= *d; + } + } + if (expSign) { + fraction /= dblExp; + } + else { + fraction *= dblExp; + } + +done: + if (endPtr != NULL) { + *endPtr = (char *) p; + } + + if (sign) { + return -fraction; + } + return fraction; +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/symbol.c b/web/server/h2o/libh2o/deps/mruby/src/symbol.c new file mode 100644 index 000000000..a3ab05c85 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/symbol.c @@ -0,0 +1,494 @@ +/* +** symbol.c - Symbol class +** +** See Copyright Notice in mruby.h +*/ + +#include <limits.h> +#include <string.h> +#include <mruby.h> +#include <mruby/khash.h> +#include <mruby/string.h> +#include <mruby/dump.h> +#include <mruby/class.h> + +/* ------------------------------------------------------ */ +typedef struct symbol_name { + mrb_bool lit : 1; + uint16_t len; + const char *name; +} symbol_name; + +static inline khint_t +sym_hash_func(mrb_state *mrb, mrb_sym s) +{ + khint_t h = 0; + size_t i, len = mrb->symtbl[s].len; + const char *p = mrb->symtbl[s].name; + + for (i=0; i<len; i++) { + h = (h << 5) - h + *p++; + } + return h; +} +#define sym_hash_equal(mrb,a, b) (mrb->symtbl[a].len == mrb->symtbl[b].len && memcmp(mrb->symtbl[a].name, mrb->symtbl[b].name, mrb->symtbl[a].len) == 0) + +KHASH_DECLARE(n2s, mrb_sym, mrb_sym, FALSE) +KHASH_DEFINE (n2s, mrb_sym, mrb_sym, FALSE, sym_hash_func, sym_hash_equal) +/* ------------------------------------------------------ */ + +static void +sym_validate_len(mrb_state *mrb, size_t len) +{ + if (len >= RITE_LV_NULL_MARK) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); + } +} + +static mrb_sym +sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) +{ + khash_t(n2s) *h = mrb->name2sym; + symbol_name *sname = mrb->symtbl; /* symtbl[0] for working memory */ + khiter_t k; + mrb_sym sym; + char *p; + + sym_validate_len(mrb, len); + if (sname) { + sname->lit = lit; + sname->len = (uint16_t)len; + sname->name = name; + k = kh_get(n2s, mrb, h, 0); + if (k != kh_end(h)) + return kh_key(h, k); + } + + /* registering a new symbol */ + sym = ++mrb->symidx; + if (mrb->symcapa < sym) { + if (mrb->symcapa == 0) mrb->symcapa = 100; + else mrb->symcapa = (size_t)(mrb->symcapa * 1.2); + mrb->symtbl = (symbol_name*)mrb_realloc(mrb, mrb->symtbl, sizeof(symbol_name)*(mrb->symcapa+1)); + } + sname = &mrb->symtbl[sym]; + sname->len = (uint16_t)len; + if (lit || mrb_ro_data_p(name)) { + sname->name = name; + sname->lit = TRUE; + } + else { + p = (char *)mrb_malloc(mrb, len+1); + memcpy(p, name, len); + p[len] = 0; + sname->name = (const char*)p; + sname->lit = FALSE; + } + kh_put(n2s, mrb, h, sym); + + return sym; +} + +MRB_API mrb_sym +mrb_intern(mrb_state *mrb, const char *name, size_t len) +{ + return sym_intern(mrb, name, len, FALSE); +} + +MRB_API mrb_sym +mrb_intern_static(mrb_state *mrb, const char *name, size_t len) +{ + return sym_intern(mrb, name, len, TRUE); +} + +MRB_API mrb_sym +mrb_intern_cstr(mrb_state *mrb, const char *name) +{ + return mrb_intern(mrb, name, strlen(name)); +} + +MRB_API mrb_sym +mrb_intern_str(mrb_state *mrb, mrb_value str) +{ + return mrb_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); +} + +MRB_API mrb_value +mrb_check_intern(mrb_state *mrb, const char *name, size_t len) +{ + khash_t(n2s) *h = mrb->name2sym; + symbol_name *sname = mrb->symtbl; + khiter_t k; + + sym_validate_len(mrb, len); + sname->len = (uint16_t)len; + sname->name = name; + + k = kh_get(n2s, mrb, h, 0); + if (k != kh_end(h)) { + return mrb_symbol_value(kh_key(h, k)); + } + return mrb_nil_value(); +} + +MRB_API mrb_value +mrb_check_intern_cstr(mrb_state *mrb, const char *name) +{ + return mrb_check_intern(mrb, name, (mrb_int)strlen(name)); +} + +MRB_API mrb_value +mrb_check_intern_str(mrb_state *mrb, mrb_value str) +{ + return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); +} + +/* lenp must be a pointer to a size_t variable */ +MRB_API const char* +mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) +{ + if (sym == 0 || mrb->symidx < sym) { + if (lenp) *lenp = 0; + return NULL; + } + + if (lenp) *lenp = mrb->symtbl[sym].len; + return mrb->symtbl[sym].name; +} + +void +mrb_free_symtbl(mrb_state *mrb) +{ + mrb_sym i, lim; + + for (i=1, lim=mrb->symidx+1; i<lim; i++) { + if (!mrb->symtbl[i].lit) { + mrb_free(mrb, (char*)mrb->symtbl[i].name); + } + } + mrb_free(mrb, mrb->symtbl); + kh_destroy(n2s, mrb, mrb->name2sym); +} + +void +mrb_init_symtbl(mrb_state *mrb) +{ + mrb->name2sym = kh_init(n2s, mrb); +} + +/********************************************************************** + * Document-class: Symbol + * + * <code>Symbol</code> objects represent names and some strings + * inside the Ruby + * interpreter. They are generated using the <code>:name</code> and + * <code>:"string"</code> literals + * syntax, and by the various <code>to_sym</code> methods. The same + * <code>Symbol</code> object will be created for a given name or string + * for the duration of a program's execution, regardless of the context + * or meaning of that name. Thus if <code>Fred</code> is a constant in + * one context, a method in another, and a class in a third, the + * <code>Symbol</code> <code>:Fred</code> will be the same object in + * all three contexts. + * + * module One + * class Fred + * end + * $f1 = :Fred + * end + * module Two + * Fred = 1 + * $f2 = :Fred + * end + * def Fred() + * end + * $f3 = :Fred + * $f1.object_id #=> 2514190 + * $f2.object_id #=> 2514190 + * $f3.object_id #=> 2514190 + * + */ + + +/* 15.2.11.3.1 */ +/* + * call-seq: + * sym == obj -> true or false + * + * Equality---If <i>sym</i> and <i>obj</i> are exactly the same + * symbol, returns <code>true</code>. + */ + +static mrb_value +sym_equal(mrb_state *mrb, mrb_value sym1) +{ + mrb_value sym2; + + mrb_get_args(mrb, "o", &sym2); + + return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2)); +} + +/* 15.2.11.3.2 */ +/* 15.2.11.3.3 */ +/* + * call-seq: + * sym.id2name -> string + * sym.to_s -> string + * + * Returns the name or string corresponding to <i>sym</i>. + * + * :fred.id2name #=> "fred" + */ +static mrb_value +mrb_sym_to_s(mrb_state *mrb, mrb_value sym) +{ + mrb_sym id = mrb_symbol(sym); + const char *p; + mrb_int len; + + p = mrb_sym2name_len(mrb, id, &len); + return mrb_str_new_static(mrb, p, len); +} + +/* 15.2.11.3.4 */ +/* + * call-seq: + * sym.to_sym -> sym + * sym.intern -> sym + * + * In general, <code>to_sym</code> returns the <code>Symbol</code> corresponding + * to an object. As <i>sym</i> is already a symbol, <code>self</code> is returned + * in this case. + */ + +static mrb_value +sym_to_sym(mrb_state *mrb, mrb_value sym) +{ + return sym; +} + +/* 15.2.11.3.5(x) */ +/* + * call-seq: + * sym.inspect -> string + * + * Returns the representation of <i>sym</i> as a symbol literal. + * + * :fred.inspect #=> ":fred" + */ + +#if __STDC__ +# define SIGN_EXTEND_CHAR(c) ((signed char)(c)) +#else /* not __STDC__ */ +/* As in Harbison and Steele. */ +# define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128) +#endif +#define is_identchar(c) (SIGN_EXTEND_CHAR(c)!=-1&&(ISALNUM(c) || (c) == '_')) + +static mrb_bool +is_special_global_name(const char* m) +{ + switch (*m) { + case '~': case '*': case '$': case '?': case '!': case '@': + case '/': case '\\': case ';': case ',': case '.': case '=': + case ':': case '<': case '>': case '\"': + case '&': case '`': case '\'': case '+': + case '0': + ++m; + break; + case '-': + ++m; + if (is_identchar(*m)) m += 1; + break; + default: + if (!ISDIGIT(*m)) return FALSE; + do ++m; while (ISDIGIT(*m)); + break; + } + return !*m; +} + +static mrb_bool +symname_p(const char *name) +{ + const char *m = name; + mrb_bool localid = FALSE; + + if (!m) return FALSE; + switch (*m) { + case '\0': + return FALSE; + + case '$': + if (is_special_global_name(++m)) return TRUE; + goto id; + + case '@': + if (*++m == '@') ++m; + goto id; + + case '<': + switch (*++m) { + case '<': ++m; break; + case '=': if (*++m == '>') ++m; break; + default: break; + } + break; + + case '>': + switch (*++m) { + case '>': case '=': ++m; break; + default: break; + } + break; + + case '=': + switch (*++m) { + case '~': ++m; break; + case '=': if (*++m == '=') ++m; break; + default: return FALSE; + } + break; + + case '*': + if (*++m == '*') ++m; + break; + case '!': + switch (*++m) { + case '=': case '~': ++m; + } + break; + case '+': case '-': + if (*++m == '@') ++m; + break; + case '|': + if (*++m == '|') ++m; + break; + case '&': + if (*++m == '&') ++m; + break; + + case '^': case '/': case '%': case '~': case '`': + ++m; + break; + + case '[': + if (*++m != ']') return FALSE; + if (*++m == '=') ++m; + break; + + default: + localid = !ISUPPER(*m); +id: + if (*m != '_' && !ISALPHA(*m)) return FALSE; + while (is_identchar(*m)) m += 1; + if (localid) { + switch (*m) { + case '!': case '?': case '=': ++m; + default: break; + } + } + break; + } + return *m ? FALSE : TRUE; +} + +static mrb_value +sym_inspect(mrb_state *mrb, mrb_value sym) +{ + mrb_value str; + const char *name; + mrb_int len; + mrb_sym id = mrb_symbol(sym); + char *sp; + + name = mrb_sym2name_len(mrb, id, &len); + str = mrb_str_new(mrb, 0, len+1); + sp = RSTRING_PTR(str); + RSTRING_PTR(str)[0] = ':'; + memcpy(sp+1, name, len); + mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); + if (!symname_p(name) || strlen(name) != (size_t)len) { + str = mrb_str_dump(mrb, str); + sp = RSTRING_PTR(str); + sp[0] = ':'; + sp[1] = '"'; + } + return str; +} + +MRB_API mrb_value +mrb_sym2str(mrb_state *mrb, mrb_sym sym) +{ + mrb_int len; + const char *name = mrb_sym2name_len(mrb, sym, &len); + + if (!name) return mrb_undef_value(); /* can't happen */ + return mrb_str_new_static(mrb, name, len); +} + +MRB_API const char* +mrb_sym2name(mrb_state *mrb, mrb_sym sym) +{ + mrb_int len; + const char *name = mrb_sym2name_len(mrb, sym, &len); + + if (!name) return NULL; + if (symname_p(name) && strlen(name) == (size_t)len) { + return name; + } + else { + mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len)); + return RSTRING_PTR(str); + } +} + +#define lesser(a,b) (((a)>(b))?(b):(a)) + +static mrb_value +sym_cmp(mrb_state *mrb, mrb_value s1) +{ + mrb_value s2; + mrb_sym sym1, sym2; + + mrb_get_args(mrb, "o", &s2); + if (mrb_type(s2) != MRB_TT_SYMBOL) return mrb_nil_value(); + sym1 = mrb_symbol(s1); + sym2 = mrb_symbol(s2); + if (sym1 == sym2) return mrb_fixnum_value(0); + else { + const char *p1, *p2; + int retval; + mrb_int len, len1, len2; + + p1 = mrb_sym2name_len(mrb, sym1, &len1); + p2 = mrb_sym2name_len(mrb, sym2, &len2); + len = lesser(len1, len2); + retval = memcmp(p1, p2, len); + if (retval == 0) { + if (len1 == len2) return mrb_fixnum_value(0); + if (len1 > len2) return mrb_fixnum_value(1); + return mrb_fixnum_value(-1); + } + if (retval > 0) return mrb_fixnum_value(1); + return mrb_fixnum_value(-1); + } +} + +void +mrb_init_symbol(mrb_state *mrb) +{ + struct RClass *sym; + + mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */ + MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL); + mrb_undef_class_method(mrb, sym, "new"); + + mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */ + mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ + mrb_define_method(mrb, sym, "to_s", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ + mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ + mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */ + mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1)); +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/value_array.h b/web/server/h2o/libh2o/deps/mruby/src/value_array.h new file mode 100644 index 000000000..bc5f28b06 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/value_array.h @@ -0,0 +1,27 @@ +#ifndef MRB_VALUE_ARRAY_H__ +#define MRB_VALUE_ARRAY_H__ + +#include <mruby.h> + +static inline void +value_move(mrb_value *s1, const mrb_value *s2, size_t n) +{ + if (s1 > s2 && s1 < s2 + n) + { + s1 += n; + s2 += n; + while (n-- > 0) { + *--s1 = *--s2; + } + } + else if (s1 != s2) { + while (n-- > 0) { + *s1++ = *s2++; + } + } + else { + /* nothing to do. */ + } +} + +#endif /* MRB_VALUE_ARRAY_H__ */ diff --git a/web/server/h2o/libh2o/deps/mruby/src/variable.c b/web/server/h2o/libh2o/deps/mruby/src/variable.c new file mode 100644 index 000000000..50fc70682 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/variable.c @@ -0,0 +1,987 @@ +/* +** variable.c - mruby variables +** +** See Copyright Notice in mruby.h +*/ + +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/proc.h> +#include <mruby/string.h> + +typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); + +#include <mruby/khash.h> + +#ifndef MRB_IVHASH_INIT_SIZE +#define MRB_IVHASH_INIT_SIZE KHASH_MIN_SIZE +#endif + +KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE) +KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal) + +/* Instance variable table structure */ +typedef struct iv_tbl { + khash_t(iv) h; +} iv_tbl; + +/* + * Creates the instance variable table. + * + * Parameters + * mrb + * Returns + * the instance variable table. + */ +static iv_tbl* +iv_new(mrb_state *mrb) +{ + return (iv_tbl*)kh_init_size(iv, mrb, MRB_IVHASH_INIT_SIZE); +} + +/* + * Set the value for the symbol in the instance variable table. + * + * Parameters + * mrb + * t the instance variable table to be set in. + * sym the symbol to be used as the key. + * val the value to be set. + */ +static void +iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) +{ + khash_t(iv) *h = &t->h; + khiter_t k; + + k = kh_put(iv, mrb, h, sym); + kh_value(h, k) = val; +} + +/* + * Get a value for a symbol from the instance variable table. + * + * Parameters + * mrb + * t the variable table to be searched. + * sym the symbol to be used as the key. + * vp the value pointer. Receives the value if the specified symbol is + * contained in the instance variable table. + * Returns + * true if the specified symbol is contained in the instance variable table. + */ +static mrb_bool +iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) +{ + khash_t(iv) *h = &t->h; + khiter_t k; + + k = kh_get(iv, mrb, h, sym); + if (k != kh_end(h)) { + if (vp) *vp = kh_value(h, k); + return TRUE; + } + return FALSE; +} + +/* + * Deletes the value for the symbol from the instance variable table. + * + * Parameters + * t the variable table to be searched. + * sym the symbol to be used as the key. + * vp the value pointer. Receive the deleted value if the symbol is + * contained in the instance variable table. + * Returns + * true if the specified symbol is contained in the instance variable table. + */ +static mrb_bool +iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) +{ + if (t == NULL) return FALSE; + else { + khash_t(iv) *h = &t->h; + khiter_t k; + + k = kh_get(iv, mrb, h, sym); + if (k != kh_end(h)) { + mrb_value val = kh_value(h, k); + kh_del(iv, mrb, h, k); + if (vp) *vp = val; + return TRUE; + } + } + return FALSE; +} + +static mrb_bool +iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) +{ + if (t == NULL) { + return TRUE; + } + else { + khash_t(iv) *h = &t->h; + khiter_t k; + int n; + + for (k = kh_begin(h); k != kh_end(h); k++) { + if (kh_exist(h, k)) { + n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p); + if (n > 0) return FALSE; + if (n < 0) { + kh_del(iv, mrb, h, k); + } + } + } + } + return TRUE; +} + +static size_t +iv_size(mrb_state *mrb, iv_tbl *t) +{ + if (t) { + return kh_size(&t->h); + } + return 0; +} + +static iv_tbl* +iv_copy(mrb_state *mrb, iv_tbl *t) +{ + return (iv_tbl*)kh_copy(iv, mrb, &t->h); +} + +static void +iv_free(mrb_state *mrb, iv_tbl *t) +{ + kh_destroy(iv, mrb, &t->h); +} + +static int +iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) +{ + mrb_gc_mark_value(mrb, v); + return 0; +} + +static void +mark_tbl(mrb_state *mrb, iv_tbl *t) +{ + if (t) { + iv_foreach(mrb, t, iv_mark_i, 0); + } +} + +void +mrb_gc_mark_gv(mrb_state *mrb) +{ + mark_tbl(mrb, mrb->globals); +} + +void +mrb_gc_free_gv(mrb_state *mrb) +{ + if (mrb->globals) + iv_free(mrb, mrb->globals); +} + +void +mrb_gc_mark_iv(mrb_state *mrb, struct RObject *obj) +{ + mark_tbl(mrb, obj->iv); +} + +size_t +mrb_gc_mark_iv_size(mrb_state *mrb, struct RObject *obj) +{ + return iv_size(mrb, obj->iv); +} + +void +mrb_gc_free_iv(mrb_state *mrb, struct RObject *obj) +{ + if (obj->iv) { + iv_free(mrb, obj->iv); + } +} + +mrb_value +mrb_vm_special_get(mrb_state *mrb, mrb_sym i) +{ + return mrb_fixnum_value(0); +} + +void +mrb_vm_special_set(mrb_state *mrb, mrb_sym i, mrb_value v) +{ +} + +static mrb_bool +obj_iv_p(mrb_value obj) +{ + switch (mrb_type(obj)) { + case MRB_TT_OBJECT: + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_SCLASS: + case MRB_TT_HASH: + case MRB_TT_DATA: + case MRB_TT_EXCEPTION: + return TRUE; + default: + return FALSE; + } +} + +MRB_API mrb_value +mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym) +{ + mrb_value v; + + if (obj->iv && iv_get(mrb, obj->iv, sym, &v)) + return v; + return mrb_nil_value(); +} + +MRB_API mrb_value +mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) +{ + if (obj_iv_p(obj)) { + return mrb_obj_iv_get(mrb, mrb_obj_ptr(obj), sym); + } + return mrb_nil_value(); +} + +MRB_API void +mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + iv_tbl *t = obj->iv; + + if (MRB_FROZEN_P(obj)) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); + } + if (!t) { + t = obj->iv = iv_new(mrb); + } + mrb_write_barrier(mrb, (struct RBasic*)obj); + iv_put(mrb, t, sym, v); +} + +MRB_API void +mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) +{ + if (obj_iv_p(obj)) { + mrb_obj_iv_set(mrb, mrb_obj_ptr(obj), sym, v); + } + else { + mrb_raise(mrb, E_ARGUMENT_ERROR, "cannot set instance variable"); + } +} + +MRB_API mrb_bool +mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym) +{ + iv_tbl *t; + + t = obj->iv; + if (t) { + return iv_get(mrb, t, sym, NULL); + } + return FALSE; +} + +MRB_API mrb_bool +mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) +{ + if (!obj_iv_p(obj)) return FALSE; + return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym); +} + +#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) + +MRB_API mrb_bool +mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) +{ + const char *s; + mrb_int i, len; + + s = mrb_sym2name_len(mrb, iv_name, &len); + if (len < 2) return FALSE; + if (s[0] != '@') return FALSE; + if (s[1] == '@') return FALSE; + for (i=1; i<len; i++) { + if (!identchar(s[i])) return FALSE; + } + return TRUE; +} + +MRB_API void +mrb_iv_check(mrb_state *mrb, mrb_sym iv_name) +{ + if (!mrb_iv_p(mrb, iv_name)) { + mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); + } +} + +MRB_API void +mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src) +{ + struct RObject *d = mrb_obj_ptr(dest); + struct RObject *s = mrb_obj_ptr(src); + + if (d->iv) { + iv_free(mrb, d->iv); + d->iv = 0; + } + if (s->iv) { + mrb_write_barrier(mrb, (struct RBasic*)d); + d->iv = iv_copy(mrb, s->iv); + } +} + +static int +inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) +{ + mrb_value str = *(mrb_value*)p; + const char *s; + mrb_int len; + mrb_value ins; + char *sp = RSTRING_PTR(str); + + /* need not to show internal data */ + if (sp[0] == '-') { /* first element */ + sp[0] = '#'; + mrb_str_cat_lit(mrb, str, " "); + } + else { + mrb_str_cat_lit(mrb, str, ", "); + } + s = mrb_sym2name_len(mrb, sym, &len); + mrb_str_cat(mrb, str, s, len); + mrb_str_cat_lit(mrb, str, "="); + if (mrb_type(v) == MRB_TT_OBJECT) { + ins = mrb_any_to_s(mrb, v); + } + else { + ins = mrb_inspect(mrb, v); + } + mrb_str_cat_str(mrb, str, ins); + return 0; +} + +mrb_value +mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) +{ + iv_tbl *t = obj->iv; + size_t len = iv_size(mrb, t); + + if (len > 0) { + const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj)); + mrb_value str = mrb_str_new_capa(mrb, 30); + + mrb_str_cat_lit(mrb, str, "-<"); + mrb_str_cat_cstr(mrb, str, cn); + mrb_str_cat_lit(mrb, str, ":"); + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, obj)); + + iv_foreach(mrb, t, inspect_i, &str); + mrb_str_cat_lit(mrb, str, ">"); + return str; + } + return mrb_any_to_s(mrb, mrb_obj_value(obj)); +} + +MRB_API mrb_value +mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) +{ + if (obj_iv_p(obj)) { + iv_tbl *t = mrb_obj_ptr(obj)->iv; + mrb_value val; + + if (t && iv_del(mrb, t, sym, &val)) { + return val; + } + } + return mrb_undef_value(); +} + +mrb_value +mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym) +{ + /* get self */ + return mrb_iv_get(mrb, mrb->c->stack[0], sym); +} + +void +mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) +{ + /* get self */ + mrb_iv_set(mrb, mrb->c->stack[0], sym, v); +} + +static int +iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) +{ + mrb_value ary; + const char* s; + mrb_int len; + + ary = *(mrb_value*)p; + s = mrb_sym2name_len(mrb, sym, &len); + if (len > 1 && s[0] == '@' && s[1] != '@') { + mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); + } + return 0; +} + +/* 15.3.1.3.23 */ +/* + * call-seq: + * obj.instance_variables -> array + * + * Returns an array of instance variable names for the receiver. Note + * that simply defining an accessor does not create the corresponding + * instance variable. + * + * class Fred + * attr_accessor :a1 + * def initialize + * @iv = 3 + * end + * end + * Fred.new.instance_variables #=> [:@iv] + */ +mrb_value +mrb_obj_instance_variables(mrb_state *mrb, mrb_value self) +{ + mrb_value ary; + + ary = mrb_ary_new(mrb); + if (obj_iv_p(self) && mrb_obj_ptr(self)->iv) { + iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary); + } + return ary; +} + +static int +cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) +{ + mrb_value ary; + const char* s; + mrb_int len; + + ary = *(mrb_value*)p; + s = mrb_sym2name_len(mrb, sym, &len); + if (len > 2 && s[0] == '@' && s[1] == '@') { + mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); + } + return 0; +} + +/* 15.2.2.4.19 */ +/* + * call-seq: + * mod.class_variables -> array + * + * Returns an array of the names of class variables in <i>mod</i>. + * + * class One + * @@var1 = 1 + * end + * class Two < One + * @@var2 = 2 + * end + * One.class_variables #=> [:@@var1] + * Two.class_variables #=> [:@@var2] + */ +mrb_value +mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) +{ + mrb_value ary; + struct RClass *c; + + ary = mrb_ary_new(mrb); + c = mrb_class_ptr(mod); + while (c) { + if (c->iv) { + iv_foreach(mrb, c->iv, cv_i, &ary); + } + c = c->super; + } + return ary; +} + +MRB_API mrb_value +mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) +{ + struct RClass * cls = c; + mrb_value v; + int given = FALSE; + + while (c) { + if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + given = TRUE; + } + c = c->super; + } + if (given) return v; + if (cls && cls->tt == MRB_TT_SCLASS) { + mrb_value klass; + + klass = mrb_obj_iv_get(mrb, (struct RObject *)cls, + mrb_intern_lit(mrb, "__attached__")); + c = mrb_class_ptr(klass); + if (c->tt == MRB_TT_CLASS || c->tt == MRB_TT_MODULE) { + given = FALSE; + while (c) { + if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + given = TRUE; + } + c = c->super; + } + if (given) return v; + } + } + mrb_name_error(mrb, sym, "uninitialized class variable %S in %S", + mrb_sym2str(mrb, sym), mrb_obj_value(cls)); + /* not reached */ + return mrb_nil_value(); +} + +MRB_API mrb_value +mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) +{ + return mrb_mod_cv_get(mrb, mrb_class_ptr(mod), sym); +} + +MRB_API void +mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) +{ + struct RClass * cls = c; + + while (c) { + if (c->iv) { + iv_tbl *t = c->iv; + + if (iv_get(mrb, t, sym, NULL)) { + mrb_write_barrier(mrb, (struct RBasic*)c); + iv_put(mrb, t, sym, v); + return; + } + } + c = c->super; + } + + if (cls && cls->tt == MRB_TT_SCLASS) { + mrb_value klass; + + klass = mrb_obj_iv_get(mrb, (struct RObject*)cls, + mrb_intern_lit(mrb, "__attached__")); + switch (mrb_type(klass)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_SCLASS: + c = mrb_class_ptr(klass); + break; + default: + c = cls; + break; + } + } + else{ + c = cls; + } + + if (!c->iv) { + c->iv = iv_new(mrb); + } + + mrb_write_barrier(mrb, (struct RBasic*)c); + iv_put(mrb, c->iv, sym, v); +} + +MRB_API void +mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) +{ + mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v); +} + +MRB_API mrb_bool +mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) +{ + while (c) { + if (c->iv) { + iv_tbl *t = c->iv; + if (iv_get(mrb, t, sym, NULL)) return TRUE; + } + c = c->super; + } + + return FALSE; +} + +MRB_API mrb_bool +mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym) +{ + return mrb_mod_cv_defined(mrb, mrb_class_ptr(mod), sym); +} + +mrb_value +mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym) +{ + struct RClass *c = mrb->c->ci->proc->target_class; + + if (!c) c = mrb->c->ci->target_class; + + return mrb_mod_cv_get(mrb, c, sym); +} + +void +mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) +{ + struct RClass *c = mrb->c->ci->proc->target_class; + + if (!c) c = mrb->c->ci->target_class; + mrb_mod_cv_set(mrb, c, sym, v); +} + +static void +mod_const_check(mrb_state *mrb, mrb_value mod) +{ + switch (mrb_type(mod)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_SCLASS: + break; + default: + mrb_raise(mrb, E_TYPE_ERROR, "constant look-up for non class/module"); + break; + } +} + +static mrb_value +const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym) +{ + struct RClass *c = base; + mrb_value v; + iv_tbl *t; + mrb_bool retry = FALSE; + mrb_value name; + +L_RETRY: + while (c) { + if (c->iv) { + t = c->iv; + if (iv_get(mrb, t, sym, &v)) + return v; + } + c = c->super; + } + if (!retry && base && base->tt == MRB_TT_MODULE) { + c = mrb->object_class; + retry = TRUE; + goto L_RETRY; + } + name = mrb_symbol_value(sym); + return mrb_funcall_argv(mrb, mrb_obj_value(base), mrb_intern_lit(mrb, "const_missing"), 1, &name); +} + +MRB_API mrb_value +mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) +{ + mod_const_check(mrb, mod); + return const_get(mrb, mrb_class_ptr(mod), sym); +} + +mrb_value +mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) +{ + struct RClass *c = mrb->c->ci->proc->target_class; + struct RClass *c2; + mrb_value v; + mrb_irep *irep; + + if (!c) c = mrb->c->ci->target_class; + mrb_assert(c != NULL); + + if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + return v; + } + c2 = c; + while (c2 && c2->tt == MRB_TT_SCLASS) { + mrb_value klass; + klass = mrb_obj_iv_get(mrb, (struct RObject *)c2, + mrb_intern_lit(mrb, "__attached__")); + c2 = mrb_class_ptr(klass); + } + if (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE) c = c2; + mrb_assert(!MRB_PROC_CFUNC_P(mrb->c->ci->proc)); + irep = mrb->c->ci->proc->body.irep; + while (irep) { + if (irep->target_class) { + c2 = irep->target_class; + if (c2->iv && iv_get(mrb, c2->iv, sym, &v)) { + return v; + } + } + irep = irep->outer; + } + return const_get(mrb, c, sym); +} + +MRB_API void +mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) +{ + mod_const_check(mrb, mod); + if (mrb_type(v) == MRB_TT_CLASS || mrb_type(v) == MRB_TT_MODULE) { + mrb_class_name_class(mrb, mrb_class_ptr(mod), mrb_class_ptr(v), sym); + } + mrb_iv_set(mrb, mod, sym, v); +} + +void +mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v) +{ + struct RClass *c = mrb->c->ci->proc->target_class; + + if (!c) c = mrb->c->ci->target_class; + mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v); +} + +MRB_API void +mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym) +{ + mod_const_check(mrb, mod); + mrb_iv_remove(mrb, mod, sym); +} + +MRB_API void +mrb_define_const(mrb_state *mrb, struct RClass *mod, const char *name, mrb_value v) +{ + mrb_obj_iv_set(mrb, (struct RObject*)mod, mrb_intern_cstr(mrb, name), v); +} + +MRB_API void +mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val) +{ + mrb_define_const(mrb, mrb->object_class, name, val); +} + +static int +const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) +{ + mrb_value ary; + const char* s; + mrb_int len; + + ary = *(mrb_value*)p; + s = mrb_sym2name_len(mrb, sym, &len); + if (len >= 1 && ISUPPER(s[0])) { + mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); + } + return 0; +} + +/* 15.2.2.4.24 */ +/* + * call-seq: + * mod.constants -> array + * + * Returns an array of all names of contants defined in the receiver. + */ +mrb_value +mrb_mod_constants(mrb_state *mrb, mrb_value mod) +{ + mrb_value ary; + mrb_bool inherit = TRUE; + struct RClass *c = mrb_class_ptr(mod); + + mrb_get_args(mrb, "|b", &inherit); + ary = mrb_ary_new(mrb); + while (c) { + if (c->iv) { + iv_foreach(mrb, c->iv, const_i, &ary); + } + if (!inherit) break; + c = c->super; + if (c == mrb->object_class) break; + } + return ary; +} + +MRB_API mrb_value +mrb_gv_get(mrb_state *mrb, mrb_sym sym) +{ + mrb_value v; + + if (!mrb->globals) { + return mrb_nil_value(); + } + if (iv_get(mrb, mrb->globals, sym, &v)) + return v; + return mrb_nil_value(); +} + +MRB_API void +mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) +{ + iv_tbl *t; + + if (!mrb->globals) { + t = mrb->globals = iv_new(mrb); + } + else { + t = mrb->globals; + } + iv_put(mrb, t, sym, v); +} + +MRB_API void +mrb_gv_remove(mrb_state *mrb, mrb_sym sym) +{ + if (!mrb->globals) { + return; + } + iv_del(mrb, mrb->globals, sym, NULL); +} + +static int +gv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) +{ + mrb_value ary; + + ary = *(mrb_value*)p; + mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); + return 0; +} + +/* 15.3.1.2.4 */ +/* 15.3.1.3.14 */ +/* + * call-seq: + * global_variables -> array + * + * Returns an array of the names of global variables. + * + * global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr] + */ +mrb_value +mrb_f_global_variables(mrb_state *mrb, mrb_value self) +{ + iv_tbl *t = mrb->globals; + mrb_value ary = mrb_ary_new(mrb); + size_t i; + char buf[3]; + + if (t) { + iv_foreach(mrb, t, gv_i, &ary); + } + buf[0] = '$'; + buf[2] = 0; + for (i = 1; i <= 9; ++i) { + buf[1] = (char)(i + '0'); + mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2))); + } + return ary; +} + +static mrb_bool +mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, mrb_bool recurse) +{ + struct RClass *klass = mrb_class_ptr(mod); + struct RClass *tmp; + mrb_bool mod_retry = 0; + + tmp = klass; +retry: + while (tmp) { + if (tmp->iv && iv_get(mrb, tmp->iv, id, NULL)) { + return TRUE; + } + if (!recurse && (klass != mrb->object_class)) break; + tmp = tmp->super; + } + if (!exclude && !mod_retry && (klass->tt == MRB_TT_MODULE)) { + mod_retry = 1; + tmp = mrb->object_class; + goto retry; + } + return FALSE; +} + +MRB_API mrb_bool +mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id) +{ + return mrb_const_defined_0(mrb, mod, id, TRUE, TRUE); +} + +MRB_API mrb_bool +mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id) +{ + return mrb_const_defined_0(mrb, mod, id, TRUE, FALSE); +} + +MRB_API mrb_value +mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id) +{ + return mrb_iv_get(mrb, obj, id); +} + +struct csym_arg { + struct RClass *c; + mrb_sym sym; +}; + +static int +csym_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) +{ + struct csym_arg *a = (struct csym_arg*)p; + struct RClass *c = a->c; + + if (mrb_type(v) == c->tt && mrb_class_ptr(v) == c) { + a->sym = sym; + return 1; /* stop iteration */ + } + return 0; +} + +static mrb_sym +find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c) +{ + struct csym_arg arg; + + if (!outer) return 0; + arg.c = c; + arg.sym = 0; + iv_foreach(mrb, outer->iv, csym_i, &arg); + return arg.sym; +} + +mrb_value +mrb_class_find_path(mrb_state *mrb, struct RClass *c) +{ + mrb_value outer, path; + mrb_sym name; + const char *str; + mrb_int len; + mrb_sym osym = mrb_intern_lit(mrb, "__outer__"); + + outer = mrb_obj_iv_get(mrb, (struct RObject*)c, osym); + if (mrb_nil_p(outer)) return outer; + name = find_class_sym(mrb, mrb_class_ptr(outer), c); + if (name == 0) return mrb_nil_value(); + str = mrb_class_name(mrb, mrb_class_ptr(outer)); + path = mrb_str_new_capa(mrb, 40); + mrb_str_cat_cstr(mrb, path, str); + mrb_str_cat_cstr(mrb, path, "::"); + + str = mrb_sym2name_len(mrb, name, &len); + mrb_str_cat(mrb, path, str, len); + iv_del(mrb, c->iv, osym, NULL); + iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); + mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); + return path; +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/version.c b/web/server/h2o/libh2o/deps/mruby/src/version.c new file mode 100644 index 000000000..350bc1673 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/version.c @@ -0,0 +1,17 @@ +#include <mruby.h> +#include <mruby/variable.h> + +void +mrb_init_version(mrb_state* mrb) +{ + mrb_value mruby_version = mrb_str_new_lit(mrb, MRUBY_VERSION); + + mrb_define_global_const(mrb, "RUBY_VERSION", mrb_str_new_lit(mrb, MRUBY_RUBY_VERSION)); + mrb_define_global_const(mrb, "RUBY_ENGINE", mrb_str_new_lit(mrb, MRUBY_RUBY_ENGINE)); + mrb_define_global_const(mrb, "RUBY_ENGINE_VERSION", mruby_version); + mrb_define_global_const(mrb, "MRUBY_VERSION", mruby_version); + mrb_define_global_const(mrb, "MRUBY_RELEASE_NO", mrb_fixnum_value(MRUBY_RELEASE_NO)); + mrb_define_global_const(mrb, "MRUBY_RELEASE_DATE", mrb_str_new_lit(mrb, MRUBY_RELEASE_DATE)); + mrb_define_global_const(mrb, "MRUBY_DESCRIPTION", mrb_str_new_lit(mrb, MRUBY_DESCRIPTION)); + mrb_define_global_const(mrb, "MRUBY_COPYRIGHT", mrb_str_new_lit(mrb, MRUBY_COPYRIGHT)); +} diff --git a/web/server/h2o/libh2o/deps/mruby/src/vm.c b/web/server/h2o/libh2o/deps/mruby/src/vm.c new file mode 100644 index 000000000..f413211e7 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/src/vm.c @@ -0,0 +1,2909 @@ +/* +** vm.c - virtual machine for mruby +** +** See Copyright Notice in mruby.h +*/ + +#include <stddef.h> +#include <stdarg.h> +#include <math.h> +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/hash.h> +#include <mruby/irep.h> +#include <mruby/numeric.h> +#include <mruby/proc.h> +#include <mruby/range.h> +#include <mruby/string.h> +#include <mruby/variable.h> +#include <mruby/error.h> +#include <mruby/opcode.h> +#include "value_array.h" +#include <mruby/throw.h> + +#ifdef MRB_DISABLE_STDIO +#if defined(__cplusplus) +extern "C" { +#endif +void abort(void); +#if defined(__cplusplus) +} /* extern "C" { */ +#endif +#endif + +#define STACK_INIT_SIZE 128 +#define CALLINFO_INIT_SIZE 32 + +#ifndef ENSURE_STACK_INIT_SIZE +#define ENSURE_STACK_INIT_SIZE 16 +#endif + +#ifndef RESCUE_STACK_INIT_SIZE +#define RESCUE_STACK_INIT_SIZE 16 +#endif + +/* Define amount of linear stack growth. */ +#ifndef MRB_STACK_GROWTH +#define MRB_STACK_GROWTH 128 +#endif + +/* Maximum mrb_funcall() depth. Should be set lower on memory constrained systems. */ +#ifndef MRB_FUNCALL_DEPTH_MAX +#define MRB_FUNCALL_DEPTH_MAX 512 +#endif + +/* Maximum stack depth. Should be set lower on memory constrained systems. +The value below allows about 60000 recursive calls in the simplest case. */ +#ifndef MRB_STACK_MAX +#define MRB_STACK_MAX (0x40000 - MRB_STACK_GROWTH) +#endif + +#ifdef VM_DEBUG +# define DEBUG(x) (x) +#else +# define DEBUG(x) +#endif + + +#ifndef MRB_GC_FIXED_ARENA +static void +mrb_gc_arena_shrink(mrb_state *mrb, int idx) +{ + mrb_gc *gc = &mrb->gc; + int capa = gc->arena_capa; + + if (idx < capa / 4) { + capa >>= 2; + if (capa < MRB_GC_ARENA_SIZE) { + capa = MRB_GC_ARENA_SIZE; + } + if (capa != gc->arena_capa) { + gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*capa); + gc->arena_capa = capa; + } + } +} +#else +#define mrb_gc_arena_shrink(mrb,idx) +#endif + +#define CALL_MAXARGS 127 + +void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); + +static inline void +stack_clear(mrb_value *from, size_t count) +{ +#ifndef MRB_NAN_BOXING + const mrb_value mrb_value_zero = { { 0 } }; + + while (count-- > 0) { + *from++ = mrb_value_zero; + } +#else + while (count-- > 0) { + SET_NIL_VALUE(*from); + from++; + } +#endif +} + +static inline void +stack_copy(mrb_value *dst, const mrb_value *src, size_t size) +{ + while (size-- > 0) { + *dst++ = *src++; + } +} + +static void +stack_init(mrb_state *mrb) +{ + struct mrb_context *c = mrb->c; + + /* mrb_assert(mrb->stack == NULL); */ + c->stbase = (mrb_value *)mrb_calloc(mrb, STACK_INIT_SIZE, sizeof(mrb_value)); + c->stend = c->stbase + STACK_INIT_SIZE; + c->stack = c->stbase; + + /* mrb_assert(ci == NULL); */ + c->cibase = (mrb_callinfo *)mrb_calloc(mrb, CALLINFO_INIT_SIZE, sizeof(mrb_callinfo)); + c->ciend = c->cibase + CALLINFO_INIT_SIZE; + c->ci = c->cibase; + c->ci->target_class = mrb->object_class; + c->ci->stackent = c->stack; +} + +static inline void +envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) +{ + mrb_callinfo *ci = mrb->c->cibase; + + if (newbase == oldbase) return; + while (ci <= mrb->c->ci) { + struct REnv *e = ci->env; + mrb_value *st; + + if (e && MRB_ENV_STACK_SHARED_P(e) && + (st = e->stack) && oldbase <= st && st < oldbase+size) { + ptrdiff_t off = e->stack - oldbase; + + e->stack = newbase + off; + } + ci->stackent = newbase + (ci->stackent - oldbase); + ci++; + } +} + +/** def rec ; $deep =+ 1 ; if $deep > 1000 ; return 0 ; end ; rec ; end */ + +static void +stack_extend_alloc(mrb_state *mrb, int room) +{ + mrb_value *oldbase = mrb->c->stbase; + mrb_value *newstack; + size_t oldsize = mrb->c->stend - mrb->c->stbase; + size_t size = oldsize; + size_t off = mrb->c->stack - mrb->c->stbase; + + if (off > size) size = off; +#ifdef MRB_STACK_EXTEND_DOUBLING + if (room <= size) + size *= 2; + else + size += room; +#else + /* Use linear stack growth. + It is slightly slower than doubling the stack space, + but it saves memory on small devices. */ + if (room <= MRB_STACK_GROWTH) + size += MRB_STACK_GROWTH; + else + size += room; +#endif + + newstack = (mrb_value *)mrb_realloc(mrb, mrb->c->stbase, sizeof(mrb_value) * size); + if (newstack == NULL) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); + } + stack_clear(&(newstack[oldsize]), size - oldsize); + envadjust(mrb, oldbase, newstack, size); + mrb->c->stbase = newstack; + mrb->c->stack = mrb->c->stbase + off; + mrb->c->stend = mrb->c->stbase + size; + + /* Raise an exception if the new stack size will be too large, + to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */ + if (size > MRB_STACK_MAX) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); + } +} + +static inline void +stack_extend(mrb_state *mrb, int room) +{ + if (mrb->c->stack + room >= mrb->c->stend) { + stack_extend_alloc(mrb, room); + } +} + +static inline struct REnv* +uvenv(mrb_state *mrb, int up) +{ + struct REnv *e = mrb->c->ci->proc->env; + + while (up--) { + if (!e) return NULL; + e = (struct REnv*)e->c; + } + return e; +} + +static inline mrb_bool +is_strict(mrb_state *mrb, struct REnv *e) +{ + ptrdiff_t cioff = e->cioff; + + if (MRB_ENV_STACK_SHARED_P(e) && e->cxt.c->cibase[cioff].proc && + MRB_PROC_STRICT_P(e->cxt.c->cibase[cioff].proc)) { + return TRUE; + } + return FALSE; +} + +static inline struct REnv* +top_env(mrb_state *mrb, struct RProc *proc) +{ + struct REnv *e = proc->env; + + if (is_strict(mrb, e)) return e; + while (e->c) { + e = (struct REnv*)e->c; + if (is_strict(mrb, e)) return e; + } + return e; +} + +#define CI_ACC_SKIP -1 +#define CI_ACC_DIRECT -2 +#define CI_ACC_RESUMED -3 + +static inline mrb_callinfo* +cipush(mrb_state *mrb) +{ + struct mrb_context *c = mrb->c; + static const mrb_callinfo ci_zero = { 0 }; + mrb_callinfo *ci = c->ci; + + int ridx = ci->ridx; + + if (ci + 1 == c->ciend) { + ptrdiff_t size = ci - c->cibase; + + c->cibase = (mrb_callinfo *)mrb_realloc(mrb, c->cibase, sizeof(mrb_callinfo)*size*2); + c->ci = c->cibase + size; + c->ciend = c->cibase + size * 2; + } + ci = ++c->ci; + *ci = ci_zero; + ci->epos = mrb->c->eidx; + ci->ridx = ridx; + + return ci; +} + +MRB_API void +mrb_env_unshare(mrb_state *mrb, struct REnv *e) +{ + if (e == NULL) return; + else { + size_t len = (size_t)MRB_ENV_STACK_LEN(e); + ptrdiff_t cioff = e->cioff; + mrb_value *p; + + if (!MRB_ENV_STACK_SHARED_P(e)) return; + if (e->cxt.c != mrb->c) return; + if (e->cioff == 0 && e->cxt.c == mrb->root_c) return; + MRB_ENV_UNSHARE_STACK(e); + if (!e->c) { + /* save block argument position (negated) */ + e->cioff = -e->cxt.c->cibase[cioff].argc-1; + if (e->cioff == 0) e->cioff = -2; /* blkarg position for vararg (1:args, 2:blk) */ + } + e->cxt.mid = e->cxt.c->cibase[cioff].mid; + p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len); + if (len > 0) { + stack_copy(p, e->stack, len); + } + e->stack = p; + mrb_write_barrier(mrb, (struct RBasic *)e); + } +} + +static inline void +cipop(mrb_state *mrb) +{ + struct mrb_context *c = mrb->c; + struct REnv *env = c->ci->env; + + c->ci--; + mrb_env_unshare(mrb, env); +} + +void mrb_exc_set(mrb_state *mrb, mrb_value exc); + +static void +ecall(mrb_state *mrb, int i) +{ + struct RProc *p; + mrb_callinfo *ci = mrb->c->ci; + mrb_value *self = mrb->c->stack; + struct RObject *exc; + ptrdiff_t cioff; + int ai = mrb_gc_arena_save(mrb); + + if (i<0) return; + if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); + } + p = mrb->c->ensure[i]; + if (!p) return; + mrb->c->ensure[i] = NULL; + cioff = ci - mrb->c->cibase; + ci = cipush(mrb); + ci->stackent = mrb->c->stack; + ci->mid = ci[-1].mid; + ci->acc = CI_ACC_SKIP; + ci->argc = 0; + ci->proc = p; + ci->nregs = p->body.irep->nregs; + ci->target_class = p->target_class; + mrb->c->stack = mrb->c->stack + ci[-1].nregs; + exc = mrb->exc; mrb->exc = 0; + if (exc) { + mrb_gc_protect(mrb, mrb_obj_value(exc)); + } + mrb_run(mrb, p, *self); + mrb->c->ci = mrb->c->cibase + cioff; + if (!mrb->exc) mrb->exc = exc; + mrb_gc_arena_restore(mrb, ai); +} + +#ifndef MRB_FUNCALL_ARGC_MAX +#define MRB_FUNCALL_ARGC_MAX 16 +#endif + +MRB_API mrb_value +mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...) +{ + mrb_value argv[MRB_FUNCALL_ARGC_MAX]; + va_list ap; + mrb_int i; + mrb_sym mid = mrb_intern_cstr(mrb, name); + + if (argc > MRB_FUNCALL_ARGC_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=" MRB_STRINGIZE(MRB_FUNCALL_ARGC_MAX) ")"); + } + + va_start(ap, argc); + for (i = 0; i < argc; i++) { + argv[i] = va_arg(ap, mrb_value); + } + va_end(ap); + return mrb_funcall_argv(mrb, self, mid, argc, argv); +} + +MRB_API mrb_value +mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk) +{ + mrb_value val; + + if (!mrb->jmp) { + struct mrb_jmpbuf c_jmp; + ptrdiff_t nth_ci = mrb->c->ci - mrb->c->cibase; + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + /* recursive call */ + val = mrb_funcall_with_block(mrb, self, mid, argc, argv, blk); + mrb->jmp = 0; + } + MRB_CATCH(&c_jmp) { /* error */ + while (nth_ci < (mrb->c->ci - mrb->c->cibase)) { + mrb->c->stack = mrb->c->ci->stackent; + cipop(mrb); + } + mrb->jmp = 0; + val = mrb_obj_value(mrb->exc); + } + MRB_END_EXC(&c_jmp); + mrb->jmp = 0; + } + else { + struct RProc *p; + struct RClass *c; + mrb_callinfo *ci; + int n; + ptrdiff_t voff = -1; + + if (!mrb->c->stack) { + stack_init(mrb); + } + n = mrb->c->ci->nregs; + if (argc < 0) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc)); + } + c = mrb_class(mrb, self); + p = mrb_method_search_vm(mrb, &c, mid); + if (!p) { + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); + p = mrb_method_search_vm(mrb, &c, missing); + if (!p) { + mrb_method_missing(mrb, mid, self, args); + } + mrb_ary_unshift(mrb, args, mrb_symbol_value(mid)); + stack_extend(mrb, n+2); + mrb->c->stack[n+1] = args; + argc = -1; + } + if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); + } + ci = cipush(mrb); + ci->mid = mid; + ci->proc = p; + ci->stackent = mrb->c->stack; + ci->argc = argc; + ci->target_class = c; + mrb->c->stack = mrb->c->stack + n; + if (mrb->c->stbase <= argv && argv < mrb->c->stend) { + voff = argv - mrb->c->stbase; + } + if (MRB_PROC_CFUNC_P(p)) { + ci->nregs = argc + 2; + stack_extend(mrb, ci->nregs); + } + else if (argc >= CALL_MAXARGS) { + mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); + stack_extend(mrb, ci->nregs); + mrb->c->stack[1] = args; + ci->argc = -1; + argc = 1; + } + else { + if (argc < 0) argc = 1; + ci->nregs = p->body.irep->nregs + argc; + stack_extend(mrb, ci->nregs); + } + if (voff >= 0) { + argv = mrb->c->stbase + voff; + } + mrb->c->stack[0] = self; + if (ci->argc > 0) { + stack_copy(mrb->c->stack+1, argv, argc); + } + mrb->c->stack[argc+1] = blk; + + if (MRB_PROC_CFUNC_P(p)) { + int ai = mrb_gc_arena_save(mrb); + + ci->acc = CI_ACC_DIRECT; + val = p->body.func(mrb, self); + mrb->c->stack = mrb->c->ci->stackent; + cipop(mrb); + mrb_gc_arena_restore(mrb, ai); + } + else { + ci->acc = CI_ACC_SKIP; + val = mrb_run(mrb, p, self); + } + } + mrb_gc_protect(mrb, val); + return val; +} + +MRB_API mrb_value +mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv) +{ + return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value()); +} + +mrb_value +mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) +{ + mrb_callinfo *ci = mrb->c->ci; + + mrb->c->stack[0] = self; + ci->proc = p; + ci->target_class = p->target_class; + if (MRB_PROC_CFUNC_P(p)) { + return p->body.func(mrb, self); + } + ci->nregs = p->body.irep->nregs; + stack_extend(mrb, (ci->argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + + ci = cipush(mrb); + ci->nregs = 0; + ci->target_class = 0; + ci->pc = p->body.irep->iseq; + ci->stackent = mrb->c->stack; + ci->acc = 0; + + return self; +} + +/* 15.3.1.3.4 */ +/* 15.3.1.3.44 */ +/* + * call-seq: + * obj.send(symbol [, args...]) -> obj + * obj.__send__(symbol [, args...]) -> obj + * + * Invokes the method identified by _symbol_, passing it any + * arguments specified. You can use <code>__send__</code> if the name + * +send+ clashes with an existing method in _obj_. + * + * class Klass + * def hello(*args) + * "Hello " + args.join(' ') + * end + * end + * k = Klass.new + * k.send :hello, "gentle", "readers" #=> "Hello gentle readers" + */ +MRB_API mrb_value +mrb_f_send(mrb_state *mrb, mrb_value self) +{ + mrb_sym name; + mrb_value block, *argv, *regs; + mrb_int argc, i, len; + struct RProc *p; + struct RClass *c; + mrb_callinfo *ci; + + mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block); + ci = mrb->c->ci; + if (ci->acc < 0) { + funcall: + return mrb_funcall_with_block(mrb, self, name, argc, argv, block); + } + + c = mrb_class(mrb, self); + p = mrb_method_search_vm(mrb, &c, name); + + if (!p) { /* call method_mising */ + goto funcall; + } + + ci->mid = name; + ci->target_class = c; + regs = mrb->c->stack+1; + /* remove first symbol from arguments */ + if (ci->argc >= 0) { + for (i=0,len=ci->argc; i<len; i++) { + regs[i] = regs[i+1]; + } + ci->argc--; + } + else { /* variable length arguments */ + mrb_ary_shift(mrb, regs[0]); + } + + return mrb_exec_irep(mrb, self, p); +} + +static mrb_value +eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) +{ + struct RProc *p; + mrb_callinfo *ci; + + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + ci = mrb->c->ci; + if (ci->acc == CI_ACC_DIRECT) { + ci->target_class = c; + return mrb_yield_cont(mrb, blk, self, 1, &self); + } + ci->target_class = c; + p = mrb_proc_ptr(blk); + ci->proc = p; + ci->argc = 1; + ci->mid = ci[-1].mid; + if (MRB_PROC_CFUNC_P(p)) { + stack_extend(mrb, 3); + mrb->c->stack[0] = self; + mrb->c->stack[1] = self; + mrb->c->stack[2] = mrb_nil_value(); + return p->body.func(mrb, self); + } + ci->nregs = p->body.irep->nregs; + stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs); + mrb->c->stack[0] = self; + mrb->c->stack[1] = self; + mrb->c->stack[2] = mrb_nil_value(); + ci = cipush(mrb); + ci->nregs = 0; + ci->target_class = 0; + ci->pc = p->body.irep->iseq; + ci->stackent = mrb->c->stack; + ci->acc = 0; + + return self; +} + +/* 15.2.2.4.35 */ +/* + * call-seq: + * mod.class_eval {| | block } -> obj + * mod.module_eval {| | block } -> obj + * + * Evaluates block in the context of _mod_. This can + * be used to add methods to a class. <code>module_eval</code> returns + * the result of evaluating its argument. + */ +mrb_value +mrb_mod_module_eval(mrb_state *mrb, mrb_value mod) +{ + mrb_value a, b; + + if (mrb_get_args(mrb, "|S&", &a, &b) == 1) { + mrb_raise(mrb, E_NOTIMP_ERROR, "module_eval/class_eval with string not implemented"); + } + return eval_under(mrb, mod, b, mrb_class_ptr(mod)); +} + +/* 15.3.1.3.18 */ +/* + * call-seq: + * obj.instance_eval {| | block } -> obj + * + * Evaluates the given block,within the context of the receiver (_obj_). + * In order to set the context, the variable +self+ is set to _obj_ while + * the code is executing, giving the code access to _obj_'s + * instance variables. In the version of <code>instance_eval</code> + * that takes a +String+, the optional second and third + * parameters supply a filename and starting line number that are used + * when reporting compilation errors. + * + * class KlassWithSecret + * def initialize + * @secret = 99 + * end + * end + * k = KlassWithSecret.new + * k.instance_eval { @secret } #=> 99 + */ +mrb_value +mrb_obj_instance_eval(mrb_state *mrb, mrb_value self) +{ + mrb_value a, b; + mrb_value cv; + struct RClass *c; + + if (mrb_get_args(mrb, "|S&", &a, &b) == 1) { + mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented"); + } + switch (mrb_type(self)) { + case MRB_TT_SYMBOL: + case MRB_TT_FIXNUM: + case MRB_TT_FLOAT: + c = 0; + break; + default: + cv = mrb_singleton_class(mrb, self); + c = mrb_class_ptr(cv); + break; + } + return eval_under(mrb, self, b, c); +} + +MRB_API mrb_value +mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c) +{ + struct RProc *p; + mrb_sym mid = mrb->c->ci->mid; + mrb_callinfo *ci; + int n = mrb->c->ci->nregs; + mrb_value val; + + if (mrb_nil_p(b)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); + } + p = mrb_proc_ptr(b); + ci = cipush(mrb); + ci->mid = mid; + ci->proc = p; + ci->stackent = mrb->c->stack; + ci->argc = argc; + ci->target_class = c; + ci->acc = CI_ACC_SKIP; + mrb->c->stack = mrb->c->stack + n; + ci->nregs = MRB_PROC_CFUNC_P(p) ? argc+2 : p->body.irep->nregs; + stack_extend(mrb, ci->nregs); + + mrb->c->stack[0] = self; + if (argc > 0) { + stack_copy(mrb->c->stack+1, argv, argc); + } + mrb->c->stack[argc+1] = mrb_nil_value(); + + if (MRB_PROC_CFUNC_P(p)) { + val = p->body.func(mrb, self); + mrb->c->stack = mrb->c->ci->stackent; + } + else { + ptrdiff_t cioff = mrb->c->ci - mrb->c->cibase; + val = mrb_run(mrb, p, self); + mrb->c->ci = mrb->c->cibase + cioff; + } + cipop(mrb); + return val; +} + +MRB_API mrb_value +mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv) +{ + struct RProc *p = mrb_proc_ptr(b); + + return mrb_yield_with_class(mrb, b, argc, argv, p->env->stack[0], p->target_class); +} + +MRB_API mrb_value +mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg) +{ + struct RProc *p = mrb_proc_ptr(b); + + return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class); +} + +mrb_value +mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb_value *argv) +{ + struct RProc *p; + mrb_callinfo *ci; + + if (mrb_nil_p(b)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + if (mrb_type(b) != MRB_TT_PROC) { + mrb_raise(mrb, E_TYPE_ERROR, "not a block"); + } + + p = mrb_proc_ptr(b); + ci = mrb->c->ci; + + stack_extend(mrb, 3); + mrb->c->stack[1] = mrb_ary_new_from_values(mrb, argc, argv); + mrb->c->stack[2] = mrb_nil_value(); + ci->argc = -1; + return mrb_exec_irep(mrb, self, p); +} + +mrb_value +mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) +{ + struct RProc *proc; + mrb_irep *irep; + mrb_value ary; + struct RClass *c; + + mrb_get_args(mrb, ""); + ary = mrb_ary_new(mrb); + proc = mrb->c->ci[-1].proc; /* callee proc */ + c = proc->target_class; + mrb_ary_push(mrb, ary, mrb_obj_value(c)); + mrb_assert(!MRB_PROC_CFUNC_P(proc)); + irep = proc->body.irep; + while (irep) { + if (irep->target_class && irep->target_class != c) { + c = irep->target_class; + mrb_ary_push(mrb, ary, mrb_obj_value(c)); + } + irep = irep->outer; + } + return ary; +} + +static struct RBreak* +break_new(mrb_state *mrb, struct RProc *p, mrb_value val) +{ + struct RBreak *brk; + + brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL); + brk->iv = NULL; + brk->proc = p; + brk->val = val; + + return brk; +} + +typedef enum { + LOCALJUMP_ERROR_RETURN = 0, + LOCALJUMP_ERROR_BREAK = 1, + LOCALJUMP_ERROR_YIELD = 2 +} localjump_error_kind; + +static void +localjump_error(mrb_state *mrb, localjump_error_kind kind) +{ + char kind_str[3][7] = { "return", "break", "yield" }; + char kind_str_len[] = { 6, 5, 5 }; + static const char lead[] = "unexpected "; + mrb_value msg; + mrb_value exc; + + msg = mrb_str_new_capa(mrb, sizeof(lead) + 7); + mrb_str_cat(mrb, msg, lead, sizeof(lead) - 1); + mrb_str_cat(mrb, msg, kind_str[kind], kind_str_len[kind]); + exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); + mrb_exc_set(mrb, exc); +} + +static void +argnum_error(mrb_state *mrb, mrb_int num) +{ + mrb_value exc; + mrb_value str; + mrb_int argc = mrb->c->ci->argc; + + if (argc < 0) { + mrb_value args = mrb->c->stack[1]; + if (mrb_array_p(args)) { + argc = RARRAY_LEN(args); + } + } + if (mrb->c->ci->mid) { + str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)", + mrb_sym2str(mrb, mrb->c->ci->mid), + mrb_fixnum_value(argc), mrb_fixnum_value(num)); + } + else { + str = mrb_format(mrb, "wrong number of arguments (%S for %S)", + mrb_fixnum_value(argc), mrb_fixnum_value(num)); + } + exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str); + mrb_exc_set(mrb, exc); +} + +void +irep_uplink(mrb_state *mrb, mrb_irep *outer, mrb_irep *irep) +{ + if (irep->outer != outer) { + if (irep->outer) { + mrb_irep_decref(mrb, irep->outer); + } + irep->outer = outer; + mrb_irep_incref(mrb, outer); + } +} + +#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc; +#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0; +#ifdef MRB_ENABLE_DEBUG_HOOK +#define CODE_FETCH_HOOK(mrb, irep, pc, regs) if ((mrb)->code_fetch_hook) (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs)); +#else +#define CODE_FETCH_HOOK(mrb, irep, pc, regs) +#endif + +#ifdef MRB_BYTECODE_DECODE_OPTION +#define BYTECODE_DECODER(x) ((mrb)->bytecode_decoder)?(mrb)->bytecode_decoder((mrb), (x)):(x) +#else +#define BYTECODE_DECODER(x) (x) +#endif + + +#if defined __GNUC__ || defined __clang__ || defined __INTEL_COMPILER +#define DIRECT_THREADED +#endif + +#ifndef DIRECT_THREADED + +#define INIT_DISPATCH for (;;) { i = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (GET_OPCODE(i)) { +#define CASE(op) case op: +#define NEXT pc++; break +#define JUMP break +#define END_DISPATCH }} + +#else + +#define INIT_DISPATCH JUMP; return mrb_nil_value(); +#define CASE(op) L_ ## op: +#define NEXT i=BYTECODE_DECODER(*++pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)] +#define JUMP i=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)] + +#define END_DISPATCH + +#endif + +MRB_API mrb_value +mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep) +{ + mrb_irep *irep = proc->body.irep; + mrb_value result; + struct mrb_context *c = mrb->c; + ptrdiff_t cioff = c->ci - c->cibase; + unsigned int nregs = irep->nregs; + + if (!c->stack) { + stack_init(mrb); + } + if (stack_keep > nregs) + nregs = stack_keep; + stack_extend(mrb, nregs); + stack_clear(c->stack + stack_keep, nregs - stack_keep); + c->stack[0] = self; + result = mrb_vm_exec(mrb, proc, irep->iseq); + if (c->ci - c->cibase > cioff) { + c->ci = c->cibase + cioff; + } + if (mrb->c != c) { + if (mrb->c->fib) { + mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib); + } + mrb->c = c; + } + return result; +} + +MRB_API mrb_value +mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) +{ + /* mrb_assert(mrb_proc_cfunc_p(proc)) */ + mrb_irep *irep = proc->body.irep; + mrb_value *pool = irep->pool; + mrb_sym *syms = irep->syms; + mrb_code i; + int ai = mrb_gc_arena_save(mrb); + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + +#ifdef DIRECT_THREADED + static void *optable[] = { + &&L_OP_NOP, &&L_OP_MOVE, + &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL, + &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF, + &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL, + &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV, + &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST, + &&L_OP_GETUPVAR, &&L_OP_SETUPVAR, + &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT, + &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP, + &&L_OP_SEND, &&L_OP_SENDB, &&L_OP_FSEND, + &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER, + &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH, + &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV, + &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE, + &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST, + &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH, + &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS, + &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC, + &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS, + &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR, + }; +#endif + + mrb_bool exc_catched = FALSE; +RETRY_TRY_BLOCK: + + MRB_TRY(&c_jmp) { + + if (exc_catched) { + exc_catched = FALSE; + if (mrb->exc && mrb->exc->tt == MRB_TT_BREAK) + goto L_BREAK; + goto L_RAISE; + } + mrb->jmp = &c_jmp; + mrb->c->ci->proc = proc; + mrb->c->ci->nregs = irep->nregs; + +#define regs (mrb->c->stack) + INIT_DISPATCH { + CASE(OP_NOP) { + /* do nothing */ + NEXT; + } + + CASE(OP_MOVE) { + /* A B R(A) := R(B) */ + int a = GETARG_A(i); + int b = GETARG_B(i); + regs[a] = regs[b]; + NEXT; + } + + CASE(OP_LOADL) { + /* A Bx R(A) := Pool(Bx) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); +#ifdef MRB_WORD_BOXING + mrb_value val = pool[bx]; + if (mrb_float_p(val)) { + val = mrb_float_value(mrb, mrb_float(val)); + } + regs[a] = val; +#else + regs[a] = pool[bx]; +#endif + NEXT; + } + + CASE(OP_LOADI) { + /* A sBx R(A) := sBx */ + SET_INT_VALUE(regs[GETARG_A(i)], GETARG_sBx(i)); + NEXT; + } + + CASE(OP_LOADSYM) { + /* A Bx R(A) := Syms(Bx) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + SET_SYM_VALUE(regs[a], syms[bx]); + NEXT; + } + + CASE(OP_LOADSELF) { + /* A R(A) := self */ + int a = GETARG_A(i); + regs[a] = regs[0]; + NEXT; + } + + CASE(OP_LOADT) { + /* A R(A) := true */ + int a = GETARG_A(i); + SET_TRUE_VALUE(regs[a]); + NEXT; + } + + CASE(OP_LOADF) { + /* A R(A) := false */ + int a = GETARG_A(i); + SET_FALSE_VALUE(regs[a]); + NEXT; + } + + CASE(OP_GETGLOBAL) { + /* A Bx R(A) := getglobal(Syms(Bx)) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_value val = mrb_gv_get(mrb, syms[bx]); + regs[a] = val; + NEXT; + } + + CASE(OP_SETGLOBAL) { + /* A Bx setglobal(Syms(Bx), R(A)) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_gv_set(mrb, syms[bx], regs[a]); + NEXT; + } + + CASE(OP_GETSPECIAL) { + /* A Bx R(A) := Special[Bx] */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_value val = mrb_vm_special_get(mrb, bx); + regs[a] = val; + NEXT; + } + + CASE(OP_SETSPECIAL) { + /* A Bx Special[Bx] := R(A) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_vm_special_set(mrb, bx, regs[a]); + NEXT; + } + + CASE(OP_GETIV) { + /* A Bx R(A) := ivget(Bx) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_value val = mrb_vm_iv_get(mrb, syms[bx]); + regs[a] = val; + NEXT; + } + + CASE(OP_SETIV) { + /* A Bx ivset(Syms(Bx),R(A)) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_vm_iv_set(mrb, syms[bx], regs[a]); + NEXT; + } + + CASE(OP_GETCV) { + /* A Bx R(A) := cvget(Syms(Bx)) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_value val; + ERR_PC_SET(mrb, pc); + val = mrb_vm_cv_get(mrb, syms[bx]); + ERR_PC_CLR(mrb); + regs[a] = val; + NEXT; + } + + CASE(OP_SETCV) { + /* A Bx cvset(Syms(Bx),R(A)) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_vm_cv_set(mrb, syms[bx], regs[a]); + NEXT; + } + + CASE(OP_GETCONST) { + /* A Bx R(A) := constget(Syms(Bx)) */ + mrb_value val; + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_sym sym = syms[bx]; + + ERR_PC_SET(mrb, pc); + val = mrb_vm_const_get(mrb, sym); + ERR_PC_CLR(mrb); + regs[a] = val; + NEXT; + } + + CASE(OP_SETCONST) { + /* A Bx constset(Syms(Bx),R(A)) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_vm_const_set(mrb, syms[bx], regs[a]); + NEXT; + } + + CASE(OP_GETMCNST) { + /* A Bx R(A) := R(A)::Syms(Bx) */ + mrb_value val; + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + + ERR_PC_SET(mrb, pc); + val = mrb_const_get(mrb, regs[a], syms[bx]); + ERR_PC_CLR(mrb); + regs[a] = val; + NEXT; + } + + CASE(OP_SETMCNST) { + /* A Bx R(A+1)::Syms(Bx) := R(A) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_const_set(mrb, regs[a+1], syms[bx], regs[a]); + NEXT; + } + + CASE(OP_GETUPVAR) { + /* A B C R(A) := uvget(B,C) */ + int a = GETARG_A(i); + int b = GETARG_B(i); + int c = GETARG_C(i); + mrb_value *regs_a = regs + a; + struct REnv *e = uvenv(mrb, c); + + if (!e) { + *regs_a = mrb_nil_value(); + } + else { + *regs_a = e->stack[b]; + } + NEXT; + } + + CASE(OP_SETUPVAR) { + /* A B C uvset(B,C,R(A)) */ + int a = GETARG_A(i); + int b = GETARG_B(i); + int c = GETARG_C(i); + + struct REnv *e = uvenv(mrb, c); + + if (e) { + mrb_value *regs_a = regs + a; + + if (b < MRB_ENV_STACK_LEN(e)) { + e->stack[b] = *regs_a; + mrb_write_barrier(mrb, (struct RBasic*)e); + } + } + NEXT; + } + + CASE(OP_JMP) { + /* sBx pc+=sBx */ + int sbx = GETARG_sBx(i); + pc += sbx; + JUMP; + } + + CASE(OP_JMPIF) { + /* A sBx if R(A) pc+=sBx */ + int a = GETARG_A(i); + int sbx = GETARG_sBx(i); + if (mrb_test(regs[a])) { + pc += sbx; + JUMP; + } + NEXT; + } + + CASE(OP_JMPNOT) { + /* A sBx if !R(A) pc+=sBx */ + int a = GETARG_A(i); + int sbx = GETARG_sBx(i); + if (!mrb_test(regs[a])) { + pc += sbx; + JUMP; + } + NEXT; + } + + CASE(OP_ONERR) { + /* sBx pc+=sBx on exception */ + int sbx = GETARG_sBx(i); + if (mrb->c->rsize <= mrb->c->ci->ridx) { + if (mrb->c->rsize == 0) mrb->c->rsize = RESCUE_STACK_INIT_SIZE; + else mrb->c->rsize *= 2; + mrb->c->rescue = (mrb_code **)mrb_realloc(mrb, mrb->c->rescue, sizeof(mrb_code*) * mrb->c->rsize); + } + mrb->c->rescue[mrb->c->ci->ridx++] = pc + sbx; + NEXT; + } + + CASE(OP_RESCUE) { + /* A B R(A) := exc; clear(exc); R(B) := matched (bool) */ + int a = GETARG_A(i); + int b = GETARG_B(i); + int c = GETARG_C(i); + mrb_value exc; + + if (c == 0) { + exc = mrb_obj_value(mrb->exc); + mrb->exc = 0; + } + else { /* continued; exc taken from R(A) */ + exc = regs[a]; + } + if (b != 0) { + mrb_value e = regs[b]; + struct RClass *ec; + + switch (mrb_type(e)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + break; + default: + { + mrb_value exc; + + exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, + "class or module required for rescue clause"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + } + ec = mrb_class_ptr(e); + regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec)); + } + if (a != 0 && c == 0) { + regs[a] = exc; + } + NEXT; + } + + CASE(OP_POPERR) { + /* A A.times{rescue_pop()} */ + int a = GETARG_A(i); + + mrb->c->ci->ridx -= a; + NEXT; + } + + CASE(OP_RAISE) { + /* A raise(R(A)) */ + int a = GETARG_A(i); + + mrb_exc_set(mrb, regs[a]); + goto L_RAISE; + } + + CASE(OP_EPUSH) { + /* Bx ensure_push(SEQ[Bx]) */ + int bx = GETARG_Bx(i); + struct RProc *p; + + p = mrb_closure_new(mrb, irep->reps[bx]); + /* push ensure_stack */ + if (mrb->c->esize <= mrb->c->eidx+1) { + if (mrb->c->esize == 0) mrb->c->esize = ENSURE_STACK_INIT_SIZE; + else mrb->c->esize *= 2; + mrb->c->ensure = (struct RProc **)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*) * mrb->c->esize); + } + mrb->c->ensure[mrb->c->eidx++] = p; + mrb->c->ensure[mrb->c->eidx] = NULL; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_EPOP) { + /* A A.times{ensure_pop().call} */ + int a = GETARG_A(i); + mrb_callinfo *ci = mrb->c->ci; + int n, epos = ci->epos; + + for (n=0; n<a && mrb->c->eidx > epos; n++) { + ecall(mrb, --mrb->c->eidx); + mrb_gc_arena_restore(mrb, ai); + } + NEXT; + } + + CASE(OP_LOADNIL) { + /* A R(A) := nil */ + int a = GETARG_A(i); + + SET_NIL_VALUE(regs[a]); + NEXT; + } + + CASE(OP_SENDB) { + /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/ + /* fall through */ + }; + + L_SEND: + CASE(OP_SEND) { + /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ + int a = GETARG_A(i); + int n = GETARG_C(i); + int argc = (n == CALL_MAXARGS) ? -1 : n; + int bidx = (argc < 0) ? a+2 : a+n+1; + struct RProc *m; + struct RClass *c; + mrb_callinfo *ci = mrb->c->ci; + mrb_value recv, blk; + mrb_sym mid = syms[GETARG_B(i)]; + + mrb_assert(bidx < ci->nregs); + + recv = regs[a]; + if (GET_OPCODE(i) != OP_SENDB) { + SET_NIL_VALUE(regs[bidx]); + blk = regs[bidx]; + } + else { + blk = regs[bidx]; + if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { + blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); + /* The stack might have been reallocated during mrb_convert_type(), + see #3622 */ + regs[bidx] = blk; + } + } + c = mrb_class(mrb, recv); + m = mrb_method_search_vm(mrb, &c, mid); + if (!m) { + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1); + ERR_PC_SET(mrb, pc); + mrb_method_missing(mrb, mid, recv, args); + } + if (argc >= 0) { + if (a+2 >= irep->nregs) { + stack_extend(mrb, a+3); + } + regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + regs[a+2] = blk; + argc = -1; + } + mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(mid)); + mid = missing; + } + + /* push callinfo */ + ci = cipush(mrb); + ci->mid = mid; + ci->proc = m; + ci->stackent = mrb->c->stack; + ci->target_class = c; + ci->argc = argc; + + ci->pc = pc + 1; + ci->acc = a; + + /* prepare stack */ + mrb->c->stack += a; + + if (MRB_PROC_CFUNC_P(m)) { + ci->nregs = (argc < 0) ? 3 : n+2; + recv = m->body.func(mrb, recv); + mrb_gc_arena_restore(mrb, ai); + mrb_gc_arena_shrink(mrb, ai); + if (mrb->exc) goto L_RAISE; + ci = mrb->c->ci; + if (GET_OPCODE(i) == OP_SENDB) { + if (mrb_type(blk) == MRB_TT_PROC) { + struct RProc *p = mrb_proc_ptr(blk); + if (p && !MRB_PROC_STRICT_P(p) && p->env == ci[-1].env) { + p->flags |= MRB_PROC_ORPHAN; + } + } + } + if (!ci->target_class) { /* return from context modifying method (resume/yield) */ + if (ci->acc == CI_ACC_RESUMED) { + mrb->jmp = prev_jmp; + return recv; + } + else { + mrb_assert(!MRB_PROC_CFUNC_P(ci[-1].proc)); + proc = ci[-1].proc; + irep = proc->body.irep; + pool = irep->pool; + syms = irep->syms; + } + } + mrb->c->stack[0] = recv; + /* pop stackpos */ + mrb->c->stack = ci->stackent; + pc = ci->pc; + cipop(mrb); + JUMP; + } + else { + /* setup environment for calling method */ + proc = mrb->c->ci->proc = m; + irep = m->body.irep; + pool = irep->pool; + syms = irep->syms; + ci->nregs = irep->nregs; + stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + pc = irep->iseq; + JUMP; + } + } + + CASE(OP_FSEND) { + /* A B C R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */ + /* not implemented yet */ + NEXT; + } + + CASE(OP_CALL) { + /* A R(A) := self.call(frame.argc, frame.argv) */ + mrb_callinfo *ci; + mrb_value recv = mrb->c->stack[0]; + struct RProc *m = mrb_proc_ptr(recv); + + /* replace callinfo */ + ci = mrb->c->ci; + ci->target_class = m->target_class; + ci->proc = m; + if (m->env) { + mrb_sym mid; + + if (MRB_ENV_STACK_SHARED_P(m->env)) { + mid = m->env->cxt.c->cibase[m->env->cioff].mid; + } + else { + mid = m->env->cxt.mid; + } + if (mid) ci->mid = mid; + if (!m->env->stack) { + m->env->stack = mrb->c->stack; + } + } + + /* prepare stack */ + if (MRB_PROC_CFUNC_P(m)) { + recv = m->body.func(mrb, recv); + mrb_gc_arena_restore(mrb, ai); + mrb_gc_arena_shrink(mrb, ai); + if (mrb->exc) goto L_RAISE; + /* pop stackpos */ + ci = mrb->c->ci; + mrb->c->stack = ci->stackent; + regs[ci->acc] = recv; + pc = ci->pc; + cipop(mrb); + irep = mrb->c->ci->proc->body.irep; + pool = irep->pool; + syms = irep->syms; + JUMP; + } + else { + /* setup environment for calling method */ + proc = m; + irep = m->body.irep; + if (!irep) { + mrb->c->stack[0] = mrb_nil_value(); + goto L_RETURN; + } + pool = irep->pool; + syms = irep->syms; + ci->nregs = irep->nregs; + stack_extend(mrb, ci->nregs); + if (ci->argc < 0) { + if (irep->nregs > 3) { + stack_clear(regs+3, irep->nregs-3); + } + } + else if (ci->argc+2 < irep->nregs) { + stack_clear(regs+ci->argc+2, irep->nregs-ci->argc-2); + } + if (m->env) { + regs[0] = m->env->stack[0]; + } + pc = irep->iseq; + JUMP; + } + } + + CASE(OP_SUPER) { + /* A C R(A) := super(R(A+1),... ,R(A+C+1)) */ + int a = GETARG_A(i); + int n = GETARG_C(i); + int argc = (n == CALL_MAXARGS) ? -1 : n; + int bidx = (argc < 0) ? a+2 : a+n+1; + struct RProc *m; + struct RClass *c; + mrb_callinfo *ci = mrb->c->ci; + mrb_value recv, blk; + mrb_sym mid = ci->mid; + + mrb_assert(bidx < ci->nregs); + + if (mid == 0 || !ci->target_class) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + recv = regs[0]; + blk = regs[bidx]; + if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { + blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); + /* The stack or ci stack might have been reallocated during + mrb_convert_type(), see #3622 and #3784 */ + regs[bidx] = blk; + ci = mrb->c->ci; + } + c = ci->target_class->super; + m = mrb_method_search_vm(mrb, &c, mid); + if (!m) { + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1); + ERR_PC_SET(mrb, pc); + mrb_method_missing(mrb, mid, recv, args); + } + mid = missing; + if (argc >= 0) { + if (a+2 >= ci->nregs) { + stack_extend(mrb, a+3); + } + regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + regs[a+2] = blk; + argc = -1; + } + mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); + } + + /* push callinfo */ + ci = cipush(mrb); + ci->mid = mid; + ci->proc = m; + ci->stackent = mrb->c->stack; + ci->target_class = c; + ci->pc = pc + 1; + ci->argc = argc; + + /* prepare stack */ + mrb->c->stack += a; + mrb->c->stack[0] = recv; + + if (MRB_PROC_CFUNC_P(m)) { + mrb_value v; + ci->nregs = (argc < 0) ? 3 : n+2; + v = m->body.func(mrb, recv); + mrb_gc_arena_restore(mrb, ai); + if (mrb->exc) goto L_RAISE; + ci = mrb->c->ci; + if (!ci->target_class) { /* return from context modifying method (resume/yield) */ + if (ci->acc == CI_ACC_RESUMED) { + mrb->jmp = prev_jmp; + return v; + } + else { + mrb_assert(!MRB_PROC_CFUNC_P(ci[-1].proc)); + proc = ci[-1].proc; + irep = proc->body.irep; + pool = irep->pool; + syms = irep->syms; + } + } + mrb->c->stack[0] = v; + /* pop stackpos */ + mrb->c->stack = ci->stackent; + pc = ci->pc; + cipop(mrb); + JUMP; + } + else { + /* fill callinfo */ + ci->acc = a; + + /* setup environment for calling method */ + ci->proc = m; + irep = m->body.irep; + pool = irep->pool; + syms = irep->syms; + ci->nregs = irep->nregs; + stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + pc = irep->iseq; + JUMP; + } + } + + CASE(OP_ARGARY) { + /* A Bx R(A) := argument array (16=6:1:5:4) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + int m1 = (bx>>10)&0x3f; + int r = (bx>>9)&0x1; + int m2 = (bx>>4)&0x1f; + int lv = (bx>>0)&0xf; + mrb_value *stack; + + if (mrb->c->ci->mid == 0 || mrb->c->ci->target_class == NULL) { + mrb_value exc; + + L_NOSUPER: + exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + if (lv == 0) stack = regs + 1; + else { + struct REnv *e = uvenv(mrb, lv-1); + if (!e) goto L_NOSUPER; + if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) + goto L_NOSUPER; + stack = e->stack + 1; + } + if (r == 0) { + regs[a] = mrb_ary_new_from_values(mrb, m1+m2, stack); + } + else { + mrb_value *pp = NULL; + struct RArray *rest; + int len = 0; + + if (mrb_array_p(stack[m1])) { + struct RArray *ary = mrb_ary_ptr(stack[m1]); + + pp = ARY_PTR(ary); + len = ARY_LEN(ary); + } + regs[a] = mrb_ary_new_capa(mrb, m1+len+m2); + rest = mrb_ary_ptr(regs[a]); + if (m1 > 0) { + stack_copy(ARY_PTR(rest), stack, m1); + } + if (len > 0) { + stack_copy(ARY_PTR(rest)+m1, pp, len); + } + if (m2 > 0) { + stack_copy(ARY_PTR(rest)+m1+len, stack+m1+1, m2); + } + ARY_SET_LEN(rest, m1+len+m2); + } + regs[a+1] = stack[m1+r+m2]; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_ENTER) { + /* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */ + /* number of optional arguments times OP_JMP should follow */ + mrb_aspec ax = GETARG_Ax(i); + int m1 = MRB_ASPEC_REQ(ax); + int o = MRB_ASPEC_OPT(ax); + int r = MRB_ASPEC_REST(ax); + int m2 = MRB_ASPEC_POST(ax); + /* unused + int k = MRB_ASPEC_KEY(ax); + int kd = MRB_ASPEC_KDICT(ax); + int b = MRB_ASPEC_BLOCK(ax); + */ + int argc = mrb->c->ci->argc; + mrb_value *argv = regs+1; + mrb_value *argv0 = argv; + int len = m1 + o + r + m2; + mrb_value *blk = &argv[argc < 0 ? 1 : argc]; + + if (argc < 0) { + struct RArray *ary = mrb_ary_ptr(regs[1]); + argv = ARY_PTR(ary); + argc = ARY_LEN(ary); + mrb_gc_protect(mrb, regs[1]); + } + if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) { + if (argc >= 0) { + if (argc < m1 + m2 || (r == 0 && argc > len)) { + argnum_error(mrb, m1+m2); + goto L_RAISE; + } + } + } + else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) { + mrb_gc_protect(mrb, argv[0]); + argc = RARRAY_LEN(argv[0]); + argv = RARRAY_PTR(argv[0]); + } + if (argc < len) { + int mlen = m2; + if (argc < m1+m2) { + if (m1 < argc) + mlen = argc - m1; + else + mlen = 0; + } + regs[len+1] = *blk; /* move block */ + SET_NIL_VALUE(regs[argc+1]); + if (argv0 != argv) { + value_move(®s[1], argv, argc-mlen); /* m1 + o */ + } + if (argc < m1) { + stack_clear(®s[argc+1], m1-argc); + } + if (mlen) { + value_move(®s[len-m2+1], &argv[argc-mlen], mlen); + } + if (mlen < m2) { + stack_clear(®s[len-m2+mlen+1], m2-mlen); + } + if (r) { + regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); + } + if (o == 0 || argc < m1+m2) pc++; + else + pc += argc - m1 - m2 + 1; + } + else { + int rnum = 0; + if (argv0 != argv) { + regs[len+1] = *blk; /* move block */ + value_move(®s[1], argv, m1+o); + } + if (r) { + rnum = argc-m1-o-m2; + regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); + } + if (m2) { + if (argc-m2 > m1) { + value_move(®s[m1+o+r+1], &argv[m1+o+rnum], m2); + } + } + if (argv0 == argv) { + regs[len+1] = *blk; /* move block */ + } + pc += o + 1; + } + mrb->c->ci->argc = len; + /* clear local (but non-argument) variables */ + if (irep->nlocals-len-2 > 0) { + stack_clear(®s[len+2], irep->nlocals-len-2); + } + JUMP; + } + + CASE(OP_KARG) { + /* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */ + /* if C == 2; raise unless kdict.empty? */ + /* OP_JMP should follow to skip init code */ + NEXT; + } + + CASE(OP_KDICT) { + /* A C R(A) := kdict */ + NEXT; + } + + L_RETURN: + i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL); + /* fall through */ + CASE(OP_RETURN) { + /* A B return R(A) (B=normal,in-block return/break) */ + mrb_callinfo *ci; + + ci = mrb->c->ci; + if (ci->mid) { + mrb_value blk; + + if (ci->argc < 0) { + blk = regs[2]; + } + else { + blk = regs[ci->argc+1]; + } + if (mrb_type(blk) == MRB_TT_PROC) { + struct RProc *p = mrb_proc_ptr(blk); + + if (!MRB_PROC_STRICT_P(p) && + ci > mrb->c->cibase && p->env == ci[-1].env) { + p->flags |= MRB_PROC_ORPHAN; + } + } + } + + if (mrb->exc) { + mrb_callinfo *ci0; + mrb_value *stk; + + L_RAISE: + ci0 = ci = mrb->c->ci; + if (ci == mrb->c->cibase) { + if (ci->ridx == 0) goto L_FTOP; + goto L_RESCUE; + } + stk = mrb->c->stack; + while (ci[0].ridx == ci[-1].ridx) { + cipop(mrb); + mrb->c->stack = ci->stackent; + if (ci->acc == CI_ACC_SKIP && prev_jmp) { + mrb->jmp = prev_jmp; + MRB_THROW(prev_jmp); + } + ci = mrb->c->ci; + if (ci == mrb->c->cibase) { + mrb->c->stack = stk; + if (ci->ridx == 0) { + L_FTOP: /* fiber top */ + if (mrb->c == mrb->root_c) { + mrb->c->stack = mrb->c->stbase; + goto L_STOP; + } + else { + struct mrb_context *c = mrb->c; + + if (c->fib) { + mrb_write_barrier(mrb, (struct RBasic*)c->fib); + } + mrb->c = c->prev; + c->prev = NULL; + goto L_RAISE; + } + } + break; + } + /* call ensure only when we skip this callinfo */ + if (ci[0].ridx == ci[-1].ridx) { + mrb_value *org_stbase = mrb->c->stbase; + while (mrb->c->eidx > ci->epos) { + ecall(mrb, --mrb->c->eidx); + ci = mrb->c->ci; + if (org_stbase != mrb->c->stbase) { + stk = mrb->c->stack; + } + } + } + } + L_RESCUE: + if (ci->ridx == 0) goto L_STOP; + proc = ci->proc; + irep = proc->body.irep; + pool = irep->pool; + syms = irep->syms; + if (ci != ci0) { + mrb->c->stack = ci[1].stackent; + } + stack_extend(mrb, irep->nregs); + pc = mrb->c->rescue[--ci->ridx]; + } + else { + int acc; + mrb_value v; + + v = regs[GETARG_A(i)]; + mrb_gc_protect(mrb, v); + switch (GETARG_B(i)) { + case OP_R_RETURN: + /* Fall through to OP_R_NORMAL otherwise */ + if (ci->acc >=0 && proc->env && !MRB_PROC_STRICT_P(proc)) { + struct REnv *e = top_env(mrb, proc); + mrb_callinfo *ce; + + if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt.c != mrb->c) { + localjump_error(mrb, LOCALJUMP_ERROR_RETURN); + goto L_RAISE; + } + + ce = mrb->c->cibase + e->cioff; + while (ci > ce) { + mrb_env_unshare(mrb, ci->env); + if (ci->acc < 0) { + localjump_error(mrb, LOCALJUMP_ERROR_RETURN); + goto L_RAISE; + } + ci--; + } + mrb_env_unshare(mrb, ci->env); + if (ce == mrb->c->cibase) { + localjump_error(mrb, LOCALJUMP_ERROR_RETURN); + goto L_RAISE; + } + mrb->c->stack = mrb->c->ci->stackent; + mrb->c->ci = ce; + break; + } + case OP_R_NORMAL: + NORMAL_RETURN: + if (ci == mrb->c->cibase) { + if (!mrb->c->prev) { /* toplevel return */ + localjump_error(mrb, LOCALJUMP_ERROR_RETURN); + goto L_RAISE; + } + if (mrb->c->prev->ci == mrb->c->prev->cibase) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + while (mrb->c->eidx > 0) { + ecall(mrb, --mrb->c->eidx); + } + /* automatic yield at the end */ + mrb->c->status = MRB_FIBER_TERMINATED; + mrb->c = mrb->c->prev; + mrb->c->status = MRB_FIBER_RUNNING; + } + ci = mrb->c->ci; + break; + case OP_R_BREAK: + if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN; + if (MRB_PROC_ORPHAN_P(proc)) { + mrb_value exc; + + L_BREAK_ERROR: + exc = mrb_exc_new_str_lit(mrb, E_LOCALJUMP_ERROR, + "break from proc-closure"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) { + goto L_BREAK_ERROR; + } + if (proc->env->cxt.c != mrb->c) { + goto L_BREAK_ERROR; + } + while (mrb->c->eidx > mrb->c->ci->epos) { + ecall(mrb, --mrb->c->eidx); + } + /* break from fiber block */ + if (mrb->c->ci == mrb->c->cibase && mrb->c->ci->pc) { + struct mrb_context *c = mrb->c; + + mrb->c = c->prev; + c->prev = NULL; + } + ci = mrb->c->ci; + if (ci->acc < 0) { + mrb_gc_arena_restore(mrb, ai); + mrb->c->vmexec = FALSE; + mrb->exc = (struct RObject*)break_new(mrb, proc, v); + mrb->jmp = prev_jmp; + MRB_THROW(prev_jmp); + } + if (FALSE) { + L_BREAK: + v = ((struct RBreak*)mrb->exc)->val; + proc = ((struct RBreak*)mrb->exc)->proc; + mrb->exc = NULL; + ci = mrb->c->ci; + } + mrb->c->stack = ci->stackent; + mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1; + while (ci > mrb->c->ci) { + mrb_env_unshare(mrb, ci->env); + if (ci[-1].acc == CI_ACC_SKIP) { + mrb->c->ci = ci; + goto L_BREAK_ERROR; + } + ci--; + } + mrb_env_unshare(mrb, ci->env); + break; + default: + /* cannot happen */ + break; + } + while (mrb->c->eidx > mrb->c->ci->epos) { + ecall(mrb, --mrb->c->eidx); + } + if (mrb->c->vmexec && !mrb->c->ci->target_class) { + mrb_gc_arena_restore(mrb, ai); + mrb->c->vmexec = FALSE; + mrb->jmp = prev_jmp; + return v; + } + ci = mrb->c->ci; + acc = ci->acc; + mrb->c->stack = ci->stackent; + cipop(mrb); + if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) { + mrb_gc_arena_restore(mrb, ai); + mrb->jmp = prev_jmp; + return v; + } + pc = ci->pc; + DEBUG(fprintf(stderr, "from :%s\n", mrb_sym2name(mrb, ci->mid))); + proc = mrb->c->ci->proc; + irep = proc->body.irep; + pool = irep->pool; + syms = irep->syms; + + regs[acc] = v; + mrb_gc_arena_restore(mrb, ai); + } + JUMP; + } + + CASE(OP_TAILCALL) { + /* A B C return call(R(A),Syms(B),R(A+1),... ,R(A+C+1)) */ + int a = GETARG_A(i); + int n = GETARG_C(i); + struct RProc *m; + struct RClass *c; + mrb_callinfo *ci; + mrb_value recv; + mrb_sym mid = syms[GETARG_B(i)]; + + recv = regs[a]; + c = mrb_class(mrb, recv); + m = mrb_method_search_vm(mrb, &c, mid); + if (!m) { + mrb_value sym = mrb_symbol_value(mid); + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_value args; + + if (n == CALL_MAXARGS) { + args = regs[a+1]; + } + else { + args = mrb_ary_new_from_values(mrb, n, regs+a+1); + } + ERR_PC_SET(mrb, pc); + mrb_method_missing(mrb, mid, recv, args); + } + mid = missing; + if (n == CALL_MAXARGS) { + mrb_ary_unshift(mrb, regs[a+1], sym); + } + else { + value_move(regs+a+2, regs+a+1, ++n); + regs[a+1] = sym; + } + } + + /* replace callinfo */ + ci = mrb->c->ci; + ci->mid = mid; + ci->target_class = c; + if (n == CALL_MAXARGS) { + ci->argc = -1; + } + else { + ci->argc = n; + } + + /* move stack */ + value_move(mrb->c->stack, ®s[a], ci->argc+1); + + if (MRB_PROC_CFUNC_P(m)) { + mrb_value v = m->body.func(mrb, recv); + mrb->c->stack[0] = v; + mrb_gc_arena_restore(mrb, ai); + goto L_RETURN; + } + else { + /* setup environment for calling method */ + irep = m->body.irep; + pool = irep->pool; + syms = irep->syms; + if (ci->argc < 0) { + stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs); + } + else { + stack_extend(mrb, irep->nregs); + } + pc = irep->iseq; + } + JUMP; + } + + CASE(OP_BLKPUSH) { + /* A Bx R(A) := block (16=6:1:5:4) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + int m1 = (bx>>10)&0x3f; + int r = (bx>>9)&0x1; + int m2 = (bx>>4)&0x1f; + int lv = (bx>>0)&0xf; + mrb_value *stack; + + if (lv == 0) stack = regs + 1; + else { + struct REnv *e = uvenv(mrb, lv-1); + if (!e || e->cioff == 0 || + (!MRB_ENV_STACK_SHARED_P(e) && e->cxt.mid == 0) || + MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) { + localjump_error(mrb, LOCALJUMP_ERROR_YIELD); + goto L_RAISE; + } + stack = e->stack + 1; + } + if (mrb_nil_p(stack[m1+r+m2])) { + localjump_error(mrb, LOCALJUMP_ERROR_YIELD); + goto L_RAISE; + } + regs[a] = stack[m1+r+m2]; + NEXT; + } + +#define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff)) +#define OP_MATH_BODY(op,v1,v2) do {\ + v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ +} while(0) + + CASE(OP_ADD) { + /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/ + int a = GETARG_A(i); + + /* need to check if op is overridden */ + switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { + case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): + { + mrb_int x, y, z; + mrb_value *regs_a = regs + a; + + x = mrb_fixnum(regs_a[0]); + y = mrb_fixnum(regs_a[1]); + if (mrb_int_add_overflow(x, y, &z)) { + SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y); + break; + } + SET_INT_VALUE(regs[a], z); + } + break; + case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): + { + mrb_int x = mrb_fixnum(regs[a]); + mrb_float y = mrb_float(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y); + } + break; + case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): +#ifdef MRB_WORD_BOXING + { + mrb_float x = mrb_float(regs[a]); + mrb_int y = mrb_fixnum(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], x + y); + } +#else + OP_MATH_BODY(+,mrb_float,mrb_fixnum); +#endif + break; + case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): +#ifdef MRB_WORD_BOXING + { + mrb_float x = mrb_float(regs[a]); + mrb_float y = mrb_float(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], x + y); + } +#else + OP_MATH_BODY(+,mrb_float,mrb_float); +#endif + break; + case TYPES2(MRB_TT_STRING,MRB_TT_STRING): + regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); + break; + default: + goto L_SEND; + } + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_SUB) { + /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/ + int a = GETARG_A(i); + + /* need to check if op is overridden */ + switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { + case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): + { + mrb_int x, y, z; + + x = mrb_fixnum(regs[a]); + y = mrb_fixnum(regs[a+1]); + if (mrb_int_sub_overflow(x, y, &z)) { + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y); + break; + } + SET_INT_VALUE(regs[a], z); + } + break; + case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): + { + mrb_int x = mrb_fixnum(regs[a]); + mrb_float y = mrb_float(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y); + } + break; + case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): +#ifdef MRB_WORD_BOXING + { + mrb_float x = mrb_float(regs[a]); + mrb_int y = mrb_fixnum(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], x - y); + } +#else + OP_MATH_BODY(-,mrb_float,mrb_fixnum); +#endif + break; + case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): +#ifdef MRB_WORD_BOXING + { + mrb_float x = mrb_float(regs[a]); + mrb_float y = mrb_float(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], x - y); + } +#else + OP_MATH_BODY(-,mrb_float,mrb_float); +#endif + break; + default: + goto L_SEND; + } + NEXT; + } + + CASE(OP_MUL) { + /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/ + int a = GETARG_A(i); + + /* need to check if op is overridden */ + switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { + case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): + { + mrb_int x, y, z; + + x = mrb_fixnum(regs[a]); + y = mrb_fixnum(regs[a+1]); + if (mrb_int_mul_overflow(x, y, &z)) { + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y); + break; + } + SET_INT_VALUE(regs[a], z); + } + break; + case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): + { + mrb_int x = mrb_fixnum(regs[a]); + mrb_float y = mrb_float(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y); + } + break; + case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): +#ifdef MRB_WORD_BOXING + { + mrb_float x = mrb_float(regs[a]); + mrb_int y = mrb_fixnum(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], x * y); + } +#else + OP_MATH_BODY(*,mrb_float,mrb_fixnum); +#endif + break; + case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): +#ifdef MRB_WORD_BOXING + { + mrb_float x = mrb_float(regs[a]); + mrb_float y = mrb_float(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], x * y); + } +#else + OP_MATH_BODY(*,mrb_float,mrb_float); +#endif + break; + default: + goto L_SEND; + } + NEXT; + } + + CASE(OP_DIV) { + /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/ + int a = GETARG_A(i); + + /* need to check if op is overridden */ + switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { + case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): + { + mrb_int x = mrb_fixnum(regs[a]); + mrb_int y = mrb_fixnum(regs[a+1]); + double f; + if (y == 0) { + if (x > 0) f = INFINITY; + else if (x < 0) f = -INFINITY; + else /* if (x == 0) */ f = NAN; + } + else { + f = (mrb_float)x / (mrb_float)y; + } + SET_FLOAT_VALUE(mrb, regs[a], f); + } + break; + case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): + { + mrb_int x = mrb_fixnum(regs[a]); + mrb_float y = mrb_float(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x / y); + } + break; + case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): +#ifdef MRB_WORD_BOXING + { + mrb_float x = mrb_float(regs[a]); + mrb_int y = mrb_fixnum(regs[a+1]); + double f; + if (y == 0) { + f = INFINITY; + } + else { + f = x / y; + } + SET_FLOAT_VALUE(mrb, regs[a], f); + } +#else + OP_MATH_BODY(/,mrb_float,mrb_fixnum); +#endif + break; + case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): +#ifdef MRB_WORD_BOXING + { + mrb_float x = mrb_float(regs[a]); + mrb_float y = mrb_float(regs[a+1]); + SET_FLOAT_VALUE(mrb, regs[a], x / y); + } +#else + OP_MATH_BODY(/,mrb_float,mrb_float); +#endif + break; + default: + goto L_SEND; + } +#ifdef MRB_NAN_BOXING + if (isnan(mrb_float(regs[a]))) { + mrb_value v = mrb_float_value(mrb, mrb_float(regs[a])); + regs[a] = v; + } +#endif + NEXT; + } + + CASE(OP_ADDI) { + /* A B C R(A) := R(A)+C (Syms[B]=:+)*/ + int a = GETARG_A(i); + + /* need to check if + is overridden */ + switch (mrb_type(regs[a])) { + case MRB_TT_FIXNUM: + { + mrb_int x = mrb_fixnum(regs[a]); + mrb_int y = GETARG_C(i); + mrb_int z; + + if (mrb_int_add_overflow(x, y, &z)) { + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y); + break; + } + SET_INT_VALUE(regs[a], z); + } + break; + case MRB_TT_FLOAT: +#ifdef MRB_WORD_BOXING + { + mrb_float x = mrb_float(regs[a]); + SET_FLOAT_VALUE(mrb, regs[a], x + GETARG_C(i)); + } +#else + mrb_float(regs[a]) += GETARG_C(i); +#endif + break; + default: + SET_INT_VALUE(regs[a+1], GETARG_C(i)); + i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); + goto L_SEND; + } + NEXT; + } + + CASE(OP_SUBI) { + /* A B C R(A) := R(A)-C (Syms[B]=:-)*/ + int a = GETARG_A(i); + mrb_value *regs_a = regs + a; + + /* need to check if + is overridden */ + switch (mrb_type(regs_a[0])) { + case MRB_TT_FIXNUM: + { + mrb_int x = mrb_fixnum(regs_a[0]); + mrb_int y = GETARG_C(i); + mrb_int z; + + if (mrb_int_sub_overflow(x, y, &z)) { + SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y); + } + else { + SET_INT_VALUE(regs_a[0], z); + } + } + break; + case MRB_TT_FLOAT: +#ifdef MRB_WORD_BOXING + { + mrb_float x = mrb_float(regs[a]); + SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i)); + } +#else + mrb_float(regs_a[0]) -= GETARG_C(i); +#endif + break; + default: + SET_INT_VALUE(regs_a[1], GETARG_C(i)); + i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); + goto L_SEND; + } + NEXT; + } + +#define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) + +#define OP_CMP(op) do {\ + int result;\ + /* need to check if - is overridden */\ + switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ + case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\ + result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\ + break;\ + case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\ + result = OP_CMP_BODY(op,mrb_fixnum,mrb_float);\ + break;\ + case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\ + result = OP_CMP_BODY(op,mrb_float,mrb_fixnum);\ + break;\ + case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\ + result = OP_CMP_BODY(op,mrb_float,mrb_float);\ + break;\ + default:\ + goto L_SEND;\ + }\ + if (result) {\ + SET_TRUE_VALUE(regs[a]);\ + }\ + else {\ + SET_FALSE_VALUE(regs[a]);\ + }\ +} while(0) + + CASE(OP_EQ) { + /* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1)*/ + int a = GETARG_A(i); + if (mrb_obj_eq(mrb, regs[a], regs[a+1])) { + SET_TRUE_VALUE(regs[a]); + } + else { + OP_CMP(==); + } + NEXT; + } + + CASE(OP_LT) { + /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ + int a = GETARG_A(i); + OP_CMP(<); + NEXT; + } + + CASE(OP_LE) { + /* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1)*/ + int a = GETARG_A(i); + OP_CMP(<=); + NEXT; + } + + CASE(OP_GT) { + /* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1)*/ + int a = GETARG_A(i); + OP_CMP(>); + NEXT; + } + + CASE(OP_GE) { + /* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)*/ + int a = GETARG_A(i); + OP_CMP(>=); + NEXT; + } + + CASE(OP_ARRAY) { + /* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ + int a = GETARG_A(i); + int b = GETARG_B(i); + int c = GETARG_C(i); + mrb_value v = mrb_ary_new_from_values(mrb, c, ®s[b]); + regs[a] = v; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_ARYCAT) { + /* A B mrb_ary_concat(R(A),R(B)) */ + int a = GETARG_A(i); + int b = GETARG_B(i); + mrb_value splat = mrb_ary_splat(mrb, regs[b]); + mrb_ary_concat(mrb, regs[a], splat); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_ARYPUSH) { + /* A B R(A).push(R(B)) */ + int a = GETARG_A(i); + int b = GETARG_B(i); + mrb_ary_push(mrb, regs[a], regs[b]); + NEXT; + } + + CASE(OP_AREF) { + /* A B C R(A) := R(B)[C] */ + int a = GETARG_A(i); + int b = GETARG_B(i); + int c = GETARG_C(i); + mrb_value v = regs[b]; + + if (!mrb_array_p(v)) { + if (c == 0) { + regs[a] = v; + } + else { + SET_NIL_VALUE(regs[a]); + } + } + else { + v = mrb_ary_ref(mrb, v, c); + regs[a] = v; + } + NEXT; + } + + CASE(OP_ASET) { + /* A B C R(B)[C] := R(A) */ + int a = GETARG_A(i); + int b = GETARG_B(i); + int c = GETARG_C(i); + mrb_ary_set(mrb, regs[b], c, regs[a]); + NEXT; + } + + CASE(OP_APOST) { + /* A B C *R(A),R(A+1)..R(A+C) := R(A) */ + int a = GETARG_A(i); + mrb_value v = regs[a]; + int pre = GETARG_B(i); + int post = GETARG_C(i); + struct RArray *ary; + int len, idx; + + if (!mrb_array_p(v)) { + v = mrb_ary_new_from_values(mrb, 1, ®s[a]); + } + ary = mrb_ary_ptr(v); + len = ARY_LEN(ary); + if (len > pre + post) { + v = mrb_ary_new_from_values(mrb, len - pre - post, ARY_PTR(ary)+pre); + regs[a++] = v; + while (post--) { + regs[a++] = ARY_PTR(ary)[len-post-1]; + } + } + else { + v = mrb_ary_new_capa(mrb, 0); + regs[a++] = v; + for (idx=0; idx+pre<len; idx++) { + regs[a+idx] = ARY_PTR(ary)[pre+idx]; + } + while (idx < post) { + SET_NIL_VALUE(regs[a+idx]); + idx++; + } + } + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_STRING) { + /* A Bx R(A) := str_new(Lit(Bx)) */ + mrb_value str = mrb_str_dup(mrb, pool[GETARG_Bx(i)]); + regs[GETARG_A(i)] = str; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_STRCAT) { + /* A B R(A).concat(R(B)) */ + mrb_str_concat(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]); + NEXT; + } + + CASE(OP_HASH) { + /* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ + int b = GETARG_B(i); + int c = GETARG_C(i); + int lim = b+c*2; + mrb_value hash = mrb_hash_new_capa(mrb, c); + + while (b < lim) { + mrb_hash_set(mrb, hash, regs[b], regs[b+1]); + b+=2; + } + regs[GETARG_A(i)] = hash; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_LAMBDA) { + /* A b c R(A) := lambda(SEQ[b],c) (b:c = 14:2) */ + struct RProc *p; + int a = GETARG_A(i); + int b = GETARG_b(i); + int c = GETARG_c(i); + mrb_irep *nirep = irep->reps[b]; + + irep_uplink(mrb, irep, nirep); + if (c & OP_L_CAPTURE) { + p = mrb_closure_new(mrb, nirep); + } + else { + p = mrb_proc_new(mrb, nirep); + } + if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT; + regs[a] = mrb_obj_value(p); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_OCLASS) { + /* A R(A) := ::Object */ + regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class); + NEXT; + } + + CASE(OP_CLASS) { + /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ + struct RClass *c = 0, *baseclass; + int a = GETARG_A(i); + mrb_value base, super; + mrb_sym id = syms[GETARG_B(i)]; + + base = regs[a]; + super = regs[a+1]; + if (mrb_nil_p(base)) { + baseclass = mrb->c->ci->proc->target_class; + if (!baseclass) baseclass = mrb->c->ci->target_class; + + base = mrb_obj_value(baseclass); + } + c = mrb_vm_define_class(mrb, base, super, id); + regs[a] = mrb_obj_value(c); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_MODULE) { + /* A B R(A) := newmodule(R(A),Syms(B)) */ + struct RClass *c = 0, *baseclass; + int a = GETARG_A(i); + mrb_value base; + mrb_sym id = syms[GETARG_B(i)]; + + base = regs[a]; + if (mrb_nil_p(base)) { + baseclass = mrb->c->ci->proc->target_class; + if (!baseclass) baseclass = mrb->c->ci->target_class; + + base = mrb_obj_value(baseclass); + } + c = mrb_vm_define_module(mrb, base, id); + regs[a] = mrb_obj_value(c); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_EXEC) { + /* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ + int a = GETARG_A(i); + int bx = GETARG_Bx(i); + mrb_callinfo *ci; + mrb_value recv = regs[a]; + struct RProc *p; + mrb_irep *nirep = irep->reps[bx]; + + irep_uplink(mrb, irep, nirep); + nirep->target_class = mrb_class_ptr(recv); + /* prepare closure */ + p = mrb_closure_new(mrb, nirep); + p->c = NULL; + + /* prepare stack */ + ci = cipush(mrb); + ci->pc = pc + 1; + ci->acc = a; + ci->mid = 0; + ci->stackent = mrb->c->stack; + ci->argc = 0; + ci->target_class = mrb_class_ptr(recv); + + /* prepare stack */ + mrb->c->stack += a; + + /* setup closure */ + p->target_class = ci->target_class; + ci->proc = p; + + irep = p->body.irep; + pool = irep->pool; + syms = irep->syms; + ci->nregs = irep->nregs; + stack_extend(mrb, ci->nregs); + stack_clear(regs+1, ci->nregs-1); + pc = irep->iseq; + JUMP; + } + + CASE(OP_METHOD) { + /* A B R(A).newmethod(Syms(B),R(A+1)) */ + int a = GETARG_A(i); + struct RClass *c = mrb_class_ptr(regs[a]); + struct RProc *p = mrb_proc_ptr(regs[a+1]); + + mrb_define_method_raw(mrb, c, syms[GETARG_B(i)], p); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_SCLASS) { + /* A B R(A) := R(B).singleton_class */ + regs[GETARG_A(i)] = mrb_singleton_class(mrb, regs[GETARG_B(i)]); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_TCLASS) { + /* A R(A) := target_class */ + if (!mrb->c->ci->target_class) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class); + NEXT; + } + + CASE(OP_RANGE) { + /* A B C R(A) := range_new(R(B),R(B+1),C) */ + int b = GETARG_B(i); + mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); + regs[GETARG_A(i)] = val; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_DEBUG) { + /* A B C debug print R(A),R(B),R(C) */ +#ifdef MRB_ENABLE_DEBUG_HOOK + mrb->debug_op_hook(mrb, irep, pc, regs); +#else +#ifndef MRB_DISABLE_STDIO + printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i)); +#else + abort(); +#endif +#endif + NEXT; + } + + CASE(OP_STOP) { + /* stop VM */ + L_STOP: + { + int epos = mrb->c->ci->epos; + + while (mrb->c->eidx > epos) { + ecall(mrb, --mrb->c->eidx); + } + } + ERR_PC_CLR(mrb); + mrb->jmp = prev_jmp; + if (mrb->exc) { + return mrb_obj_value(mrb->exc); + } + return regs[irep->nlocals]; + } + + CASE(OP_ERR) { + /* Bx raise RuntimeError with message Lit(Bx) */ + mrb_value msg = mrb_str_dup(mrb, pool[GETARG_Bx(i)]); + mrb_value exc; + + if (GETARG_A(i) == 0) { + exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, msg); + } + else { + exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); + } + ERR_PC_SET(mrb, pc); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + } + END_DISPATCH; +#undef regs + + } + MRB_CATCH(&c_jmp) { + exc_catched = TRUE; + goto RETRY_TRY_BLOCK; + } + MRB_END_EXC(&c_jmp); +} + +MRB_API mrb_value +mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) +{ + if (mrb->c->ci->argc < 0) { + return mrb_vm_run(mrb, proc, self, 3); /* receiver, args and block) */ + } + else { + return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ + } +} + +MRB_API mrb_value +mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep) +{ + mrb_callinfo *ci; + mrb_value v; + + if (!mrb->c->cibase) { + return mrb_vm_run(mrb, proc, self, stack_keep); + } + if (mrb->c->ci == mrb->c->cibase) { + mrb->c->ci->env = NULL; + return mrb_vm_run(mrb, proc, self, stack_keep); + } + ci = cipush(mrb); + ci->mid = 0; + ci->nregs = 1; /* protect the receiver */ + ci->acc = CI_ACC_SKIP; + ci->target_class = mrb->object_class; + v = mrb_vm_run(mrb, proc, self, stack_keep); + cipop(mrb); + + return v; +} + +#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus) +# if !defined(MRB_ENABLE_CXX_ABI) +} /* end of extern "C" */ +# endif +mrb_int mrb_jmpbuf::jmpbuf_id = 0; +# if !defined(MRB_ENABLE_CXX_ABI) +extern "C" { +# endif +#endif diff --git a/web/server/h2o/libh2o/deps/mruby/tasks/benchmark.rake b/web/server/h2o/libh2o/deps/mruby/tasks/benchmark.rake new file mode 100644 index 000000000..84e69ebee --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/tasks/benchmark.rake @@ -0,0 +1,91 @@ +module MRuby + BENCHMARK_REPEAT = 4 +end + +$dat_files = [] + +def bm_files + Dir.glob("#{MRUBY_ROOT}/benchmark/bm_*.rb") +end + +def build_config_name + if ENV['MRUBY_CONFIG'] + File.basename(ENV['MRUBY_CONFIG'], '.rb').gsub('build_config_', '') + else + "build" + end +end + +def plot_file + File.join(MRUBY_ROOT, 'benchmark', "#{build_config_name}.png") +end + +def plot + opts_file = "#{MRUBY_ROOT}/benchmark/plot.gpl" + opts = File.read(opts_file).each_line.to_a.map(&:strip).join(';') + + dat_files = $dat_files.group_by {|f| File.dirname(f).split(File::SEPARATOR)[-1]} + + opts += ";set output '#{plot_file}'" + + opts += ';plot ' + + opts += dat_files.keys.map do |data_file| + %Q['-' u 2:3:4:xtic(1) w hist title columnheader(1)] + end.join(',') + opts += ';' + + cmd = %Q{gnuplot -p -e "#{opts}"} + + IO.popen(cmd, 'w') do |p| + dat_files.each do |target_name, bm_files| + p.puts target_name.gsub('_', '-') + bm_files.each do |bm_file| + p.write File.read(bm_file) + end + p.puts "e" + end + end +end + + +MRuby.each_target do |target| + next if target.name == 'host' + mruby_bin = "#{target.build_dir}/bin/mruby" + + bm_files.each do |bm_file| + bm_name = File.basename bm_file, ".rb" + + dat_dir = File.join('benchmark', build_config_name, target.name) + dat_file = File.join(dat_dir, "#{bm_name}.dat") + $dat_files << dat_file + + directory dat_dir + + file dat_file => [bm_file, dat_dir, mruby_bin] do |task| + print bm_name + puts "..." + + data = (0...MRuby::BENCHMARK_REPEAT).map do |n| + str = %x{(time -f "%e %S %U" #{mruby_bin} #{bm_file}) 2>&1 >/dev/null} + str.split(' ').map(&:to_f) + end + + File.open(task.name, "w") do |f| + data = data.map {|_,r,s| (r + s) / 2.0} + min = data.min + max = data.max + avg = data.inject(&:+) / data.size + f.puts "#{bm_name.gsub('_', '-')} #{avg} #{min} #{max}" + end + end + end +end + +file plot_file => $dat_files do + plot +end + +task :benchmark => plot_file do + plot +end diff --git a/web/server/h2o/libh2o/deps/mruby/tasks/gitlab.rake b/web/server/h2o/libh2o/deps/mruby/tasks/gitlab.rake new file mode 100644 index 000000000..471172377 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/tasks/gitlab.rake @@ -0,0 +1,118 @@ +CI_VERSION = '0.7'.freeze +CI_BASE = 'ubuntu:16.10'.freeze +CI_COMPILERS = ['gcc-4.7', + 'gcc-4.8', + 'gcc-4.9', + 'gcc-5', + 'gcc-6', + 'clang-3.5', + 'clang-3.6', + 'clang-3.7', + 'clang-3.8', + 'clang-3.9'].freeze + +def ci_image_tag(compiler) + compiler.tr('+', 'c').delete('-').delete('.') +end + +def ci_docker_tag(compiler) + tag = ci_image_tag(compiler) + "registry.gitlab.com/dabroz/mruby:#{tag}_#{CI_VERSION}" +end + +def run_cmd(cmd) + puts cmd + raise 'error' unless system cmd +end + +desc 'recreate docker images for GitLab builds' +task :gitlab_dockers do + CI_COMPILERS.each do |compiler| + tag = ci_image_tag(compiler) + filename = "Dockerfile.#{tag}" + File.open(filename, 'wb') do |f| + f << "# #{compiler} - #{tag}\n" + f << "FROM #{CI_BASE}\n" + f << "RUN apt-get update && apt-get install -y git ruby2.3 ruby2.3-dev bison\n" + f << "RUN apt-get update && apt-get install -y binutils manpages\n" + f << "RUN apt-get update && apt-get install -y #{compiler}\n" + if compiler['gcc'] + f << "RUN apt-get update && apt-get install -y libx32#{compiler}-dev\n" + f << "RUN apt-get update && apt-get install --no-install-recommends -y #{compiler}-multilib\n" + end + f << "RUN dpkg --add-architecture i386\n" + f << "RUN apt-get update && apt-get install -y linux-libc-dev:i386\n" + if compiler['clang'] + f << "RUN apt-get update && apt-get install --no-install-recommends -y libc6-dev-i386\n" + f << "RUN apt-get update && apt-get install -y gcc gcc-multilib\n" + end + end + docker_tag = ci_docker_tag(compiler) + cmd1 = "docker build -t #{docker_tag} -f #{filename} ." + cmd2 = "docker push #{docker_tag}" + run_cmd cmd1 + run_cmd cmd2 + File.delete(filename) + end +end + +desc 'create build configurations and update .gitlab-ci.yml' +task :gitlab_config do + require 'yaml' + + configs = [] + [true, false].each do |mode_32| + ['', 'MRB_USE_FLOAT'].each do |float_conf| + ['', 'MRB_INT16', 'MRB_INT64'].each do |int_conf| + ['', 'MRB_NAN_BOXING', 'MRB_WORD_BOXING'].each do |boxing_conf| + ['', 'MRB_UTF8_STRING'].each do |utf8_conf| + next if (float_conf == 'MRB_USE_FLOAT') && (boxing_conf == 'MRB_NAN_BOXING') + next if (int_conf == 'MRB_INT64') && (boxing_conf == 'MRB_NAN_BOXING') + next if (int_conf == 'MRB_INT16') && (boxing_conf == 'MRB_WORD_BOXING') + next if (int_conf == 'MRB_INT64') && (boxing_conf == 'MRB_WORD_BOXING') && mode_32 + env = [float_conf, int_conf, boxing_conf, utf8_conf].map do |conf| + conf == '' ? nil : "-D#{conf}=1" + end.compact.join(' ') + bit = mode_32 ? '-m32 ' : '' + _info = '' + _info += mode_32 ? '32bit ' : '64bit ' + _info += float_conf['USE'] ? 'float ' : '' + _info += int_conf['16'] ? 'int16 ' : '' + _info += int_conf['64'] ? 'int64 ' : '' + _info += boxing_conf['NAN'] ? 'nan ' : '' + _info += boxing_conf['word'] ? 'word ' : '' + _info += utf8_conf['UTF8'] ? 'utf8 ' : '' + _info = _info.gsub(/ +/, ' ').strip.tr(' ', '_') + configs << { '_info' => _info, 'CFLAGS' => "#{bit}#{env}", 'LDFLAGS' => bit.strip.to_s } + end + end + end + end + end + path = './.gitlab-ci.yml' + data = YAML.load_file(path) + data.keys.select do |key| + key.start_with? 'Test' + end.each do |key| + data.delete(key) + end + CI_COMPILERS.each do |compiler| + configs.each do |config| + name = "Test #{compiler} #{config['_info']}" + hash = { + 'CC' => compiler, + 'CXX' => compiler.gsub('gcc', 'g++').gsub('clang', 'clang++'), + 'LD' => compiler + } + hash = hash.merge(config) + hash.delete('_info') + data[name] = { + 'stage' => 'test', + 'image' => ci_docker_tag(compiler), + 'variables' => hash, + 'script' => 'env; ./minirake --verbose all test' + } + end + end + File.open(path, 'w') { |f| YAML.dump(data, f) } +end diff --git a/web/server/h2o/libh2o/deps/mruby/tasks/libmruby.rake b/web/server/h2o/libh2o/deps/mruby/tasks/libmruby.rake new file mode 100644 index 000000000..540aa3eb5 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/tasks/libmruby.rake @@ -0,0 +1,24 @@ +MRuby.each_target do + file libfile("#{build_dir}/lib/libmruby") => libmruby.flatten do |t| + archiver.run t.name, t.prerequisites + end + + file "#{build_dir}/lib/libmruby.flags.mak" => [__FILE__, libfile("#{build_dir}/lib/libmruby")] do |t| + open(t.name, 'w') do |f| + f.puts "MRUBY_CFLAGS = #{cc.all_flags}" + + gem_flags = gems.map { |g| g.linker.flags } + gem_library_paths = gems.map { |g| g.linker.library_paths } + f.puts "MRUBY_LDFLAGS = #{linker.all_flags(gem_library_paths, gem_flags)} #{linker.option_library_path % "#{build_dir}/lib"}" + + gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries } + f.puts "MRUBY_LDFLAGS_BEFORE_LIBS = #{[linker.flags_before_libraries, gem_flags_before_libraries].flatten.join(' ')}" + + gem_libraries = gems.map { |g| g.linker.libraries } + f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries)}" + + f.puts "MRUBY_LIBMRUBY_PATH = #{libfile("#{build_dir}/lib/libmruby")}" + end + end + task :all => "#{build_dir}/lib/libmruby.flags.mak" +end diff --git a/web/server/h2o/libh2o/deps/mruby/tasks/mrbgems.rake b/web/server/h2o/libh2o/deps/mruby/tasks/mrbgems.rake new file mode 100644 index 000000000..65368c303 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/tasks/mrbgems.rake @@ -0,0 +1,96 @@ +MRuby.each_target do + if enable_gems? + # set up all gems + gems.each(&:setup) + gems.check self + + # loader all gems + self.libmruby << objfile("#{build_dir}/mrbgems/gem_init") + file objfile("#{build_dir}/mrbgems/gem_init") => ["#{build_dir}/mrbgems/gem_init.c", "#{build_dir}/LEGAL"] + file "#{build_dir}/mrbgems/gem_init.c" => [MRUBY_CONFIG, __FILE__] do |t| + FileUtils.mkdir_p "#{build_dir}/mrbgems" + open(t.name, 'w') do |f| + gem_func_gems = gems.select { |g| g.generate_functions } + gem_func_decls = gem_func_gems.each_with_object('') do |g, s| + s << "void GENERATED_TMP_mrb_#{g.funcname}_gem_init(mrb_state*);\n" \ + "void GENERATED_TMP_mrb_#{g.funcname}_gem_final(mrb_state*);\n" + end + gem_init_calls = gem_func_gems.each_with_object('') do |g, s| + s << " GENERATED_TMP_mrb_#{g.funcname}_gem_init(mrb);\n" + end + gem_final_calls = gem_func_gems.each_with_object('') do |g, s| + s << " GENERATED_TMP_mrb_#{g.funcname}_gem_final(mrb);\n" + end + f.puts %Q[/*] + f.puts %Q[ * This file contains a list of all] + f.puts %Q[ * initializing methods which are] + f.puts %Q[ * necessary to bootstrap all gems.] + f.puts %Q[ *] + f.puts %Q[ * IMPORTANT:] + f.puts %Q[ * This file was generated!] + f.puts %Q[ * All manual changes will get lost.] + f.puts %Q[ */] + f.puts %Q[] + f.puts %Q[#include <mruby.h>] + f.puts %Q[] + f.write gem_func_decls + f.puts %Q[] + f.puts %Q[static void] + f.puts %Q[mrb_final_mrbgems(mrb_state *mrb) {] + f.write gem_final_calls + f.puts %Q[}] + f.puts %Q[] + f.puts %Q[void] + f.puts %Q[mrb_init_mrbgems(mrb_state *mrb) {] + f.write gem_init_calls + f.puts %Q[ mrb_state_atexit(mrb, mrb_final_mrbgems);] unless gem_final_calls.empty? + f.puts %Q[}] + end + end + end + + # legal documents + file "#{build_dir}/LEGAL" => [MRUBY_CONFIG, __FILE__] do |t| + open(t.name, 'w+') do |f| + f.puts <<LEGAL +Copyright (c) #{Time.now.year} mruby developers + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +LEGAL + + if enable_gems? + f.puts <<GEMS_LEGAL + +Additional Licenses + +Due to the reason that you choosed additional mruby packages (GEMS), +please check the following additional licenses too: +GEMS_LEGAL + + gems.map do |g| + authors = [g.authors].flatten.sort.join(", ") + f.puts + f.puts "GEM: #{g.name}" + f.puts "Copyright (c) #{Time.now.year} #{authors}" + f.puts "License: #{g.licenses}" + end + end + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/android.rake b/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/android.rake new file mode 100644 index 000000000..c59da7fcb --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/android.rake @@ -0,0 +1,321 @@ +class MRuby::Toolchain::Android + + DEFAULT_ARCH = 'armeabi' # TODO : Revise if arch should have a default + + DEFAULT_TOOLCHAIN = :clang + + DEFAULT_NDK_HOMES = %w{ + /usr/local/opt/android-sdk/ndk-bundle + /usr/local/opt/android-ndk + %LOCALAPPDATA%/Android/android-sdk/ndk-bundle + %LOCALAPPDATA%/Android/android-ndk + ~/Library/Android/sdk/ndk-bundle + ~/Library/Android/ndk + } + + TOOLCHAINS = [:clang, :gcc] + + ARCHITECTURES = %w{ + armeabi armeabi-v7a arm64-v8a + x86 x86_64 + mips mips64 + } + + class AndroidNDKHomeNotFound < StandardError + def message + <<-EOM +Couldn't find Android NDK Home. +Set ANDROID_NDK_HOME environment variable or set :ndk_home parameter + EOM + end + end + + class PlatformDirNotFound < StandardError + def message + <<-EOM +Couldn't find Android NDK platform directories. +Set ANDROID_PLATFORM environment variable or set :platform parameter + EOM + end + end + + attr_reader :params + + def initialize(params) + @params = params + end + + def bin_gcc(command) + command = command.to_s + + command = case arch + when /armeabi/ then 'arm-linux-androideabi-' + when /arm64-v8a/ then 'aarch64-linux-android-' + when /x86_64/ then 'x86_64-linux-android-' + when /x86/ then 'i686-linux-android-' + when /mips64/ then 'mips64el-linux-android-' + when /mips/ then 'mipsel-linux-android-' + end + command + + gcc_toolchain_path.join('bin', command).to_s + end + + def bin(command) + command = command.to_s + toolchain_path.join('bin', command).to_s + end + + def home_path + @home_path ||= Pathname( + params[:ndk_home] || + ENV['ANDROID_NDK_HOME'] || + DEFAULT_NDK_HOMES.find { |path| + path.gsub! '%LOCALAPPDATA%', ENV['LOCALAPPDATA'] || '%LOCALAPPDATA%' + path.gsub! '\\', '/' + path.gsub! '~', Dir.home || '~' + File.directory?(path) + } || raise(AndroidNDKHomeNotFound) + ) + end + + def toolchain + @toolchain ||= params.fetch(:toolchain){ DEFAULT_TOOLCHAIN } + end + + def toolchain_path + @toolchain_path ||= case toolchain + when :gcc + gcc_toolchain_path + when :clang + home_path.join('toolchains', 'llvm' , 'prebuilt', host_platform) + end + end + + def gcc_toolchain_path + if @gcc_toolchain_path === nil then + prefix = case arch + when /armeabi/ then 'arm-linux-androideabi-' + when /arm64-v8a/ then 'aarch64-linux-android-' + when /x86_64/ then 'x86_64-' + when /x86/ then 'x86-' + when /mips64/ then 'mips64el-linux-android-' + when /mips/ then 'mipsel-linux-android-' + end + + test = case arch + when /armeabi/ then 'arm-linux-androideabi-*' + when /arm64-v8a/ then 'aarch64-linux-android-*' + when /x86_64/ then 'x86_64-*' + when /x86/ then 'x86-*' + when /mips64/ then 'mips64el-linux-android-*' + when /mips/ then 'mipsel-linux-android-*' + end + + gcc_toolchain_version = Dir[home_path.join('toolchains', test)].map{|t| t.match(/-(\d+\.\d+)$/); $1.to_f }.max + @gcc_toolchain_path = home_path.join('toolchains', prefix + gcc_toolchain_version.to_s, 'prebuilt', host_platform) + end + @gcc_toolchain_path + end + + def host_platform + @host_platform ||= case RUBY_PLATFORM + when /cygwin|mswin|mingw|bccwin|wince|emx/i + path = home_path.join('toolchains', 'llvm' , 'prebuilt', 'windows*') + Dir.glob(path.to_s){ |item| + next if File.file?(item) + path = Pathname(item) + break + } + path.basename + when /x86_64-darwin/i + 'darwin-x86_64' + when /darwin/i + 'darwin-x86' + when /x86_64-linux/i + 'linux-x86_64' + when /linux/i + 'linux-x86' + else + raise NotImplementedError, "Unknown host platform (#{RUBY_PLATFORM})" + end + end + + def arch + @arch ||= (params[:arch] || ENV['ANDROID_ARCH'] || DEFAULT_ARCH).to_s + end + + def sysroot + @sysroot ||= home_path.join('platforms', platform, + case arch + when /armeabi/ then 'arch-arm' + when /arm64-v8a/ then 'arch-arm64' + when /x86_64/ then 'arch-x86_64' + when /x86/ then 'arch-x86' + when /mips64/ then 'arch-mips64' + when /mips/ then 'arch-mips' + end + ).to_s + end + + def platform + if @platform === nil then + @platform = params[:platform] || ENV['ANDROID_PLATFORM'] || nil + if @platform === nil + Dir.glob(home_path.join('platforms/android-*').to_s){ |item| + next if File.file?(item) + if @platform === nil + @platform = Integer(item.rpartition('-')[2]) + else + platform = Integer(item.rpartition('-')[2]) + @platform = platform > @platform ? platform : @platform + end + } + if @platform === nil + raise(PlatformDirNotFound) + else + @platform = "android-#{@platform}" + end + end + end + if Integer(@platform.rpartition('-')[2]) < 21 + case arch + when /arm64-v8a/, /x86_64/, /mips64/ + raise NotImplementedError, "Platform (#{@platform}) has no implementation for architecture (#{arch})" + end + end + @platform + end + + def armeabi_v7a_mfpu + @armeabi_v7a_mfpu ||= (params[:mfpu] || 'vfpv3-d16').to_s + end + + def armeabi_v7a_mfloat_abi + @armeabi_v7a_mfloat_abi ||= (params[:mfloat_abi] || 'softfp').to_s + end + + def no_warn_mismatch + if %W(soft softfp).include? armeabi_v7a_mfloat_abi + '' + else + ',--no-warn-mismatch' + end + end + + def cc + case toolchain + when :gcc then bin_gcc('gcc') + when :clang then bin('clang') + end + end + + def ar + case toolchain + when :gcc then bin_gcc('ar') + when :clang then bin_gcc('ar') + end + end + + def ctarget + flags = [] + + case toolchain + when :gcc + case arch + when /armeabi-v7a/ then flags += %W(-march=armv7-a) + when /armeabi/ then flags += %W(-march=armv5te) + when /arm64-v8a/ then flags += %W(-march=armv8-a) + when /x86_64/ then flags += %W(-march=x86-64) + when /x86/ then flags += %W(-march=i686) + when /mips64/ then flags += %W(-march=mips64r6) + when /mips/ then flags += %W(-march=mips32) + end + when :clang + case arch + when /armeabi-v7a/ then flags += %W(-target armv7-none-linux-androideabi) + when /armeabi/ then flags += %W(-target armv5te-none-linux-androideabi) + when /arm64-v8a/ then flags += %W(-target aarch64-none-linux-android) + when /x86_64/ then flags += %W(-target x86_64-none-linux-android) + when /x86/ then flags += %W(-target i686-none-linux-android) + when /mips64/ then flags += %W(-target mips64el-none-linux-android) + when /mips/ then flags += %W(-target mipsel-none-linux-android) + end + end + + case arch + when /armeabi-v7a/ then flags += %W(-mfpu=#{armeabi_v7a_mfpu} -mfloat-abi=#{armeabi_v7a_mfloat_abi}) + when /armeabi/ then flags += %W(-mtune=xscale -msoft-float) + when /arm64-v8a/ then flags += %W() + when /x86_64/ then flags += %W() + when /x86/ then flags += %W() + when /mips64/ then flags += %W(-fmessage-length=0) + when /mips/ then flags += %W(-fmessage-length=0) + end + + flags + end + + def cflags + flags = [] + + flags += %W(-MMD -MP -D__android__ -DANDROID --sysroot="#{sysroot}") + flags += ctarget + case toolchain + when :gcc + when :clang + flags += %W(-gcc-toolchain "#{gcc_toolchain_path}" -Wno-invalid-command-line-argument -Wno-unused-command-line-argument) + end + flags += %W(-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes) + + flags + end + + def ldflags + flags = [] + + flags += %W(--sysroot="#{sysroot}") + + flags + end + + def ldflags_before_libraries + flags = [] + + case toolchain + when :gcc + case arch + when /armeabi-v7a/ then flags += %W(-Wl#{no_warn_mismatch}) + end + when :clang + flags += %W(-gcc-toolchain "#{gcc_toolchain_path.to_s}") + case arch + when /armeabi-v7a/ then flags += %W(-target armv7-none-linux-androideabi -Wl,--fix-cortex-a8#{no_warn_mismatch}) + when /armeabi/ then flags += %W(-target armv5te-none-linux-androideabi) + when /arm64-v8a/ then flags += %W(-target aarch64-none-linux-android) + when /x86_64/ then flags += %W(-target x86_64-none-linux-android) + when /x86/ then flags += %W(-target i686-none-linux-android) + when /mips64/ then flags += %W(-target mips64el-none-linux-android) + when /mips/ then flags += %W(-target mipsel-none-linux-android) + end + end + flags += %W(-no-canonical-prefixes) + + flags + end +end + +MRuby::Toolchain.new(:android) do |conf, params| + android = MRuby::Toolchain::Android.new(params) + + toolchain android.toolchain + + [conf.cc, conf.cxx, conf.objc, conf.asm].each do |cc| + cc.command = android.cc + cc.flags = android.cflags + end + + conf.archiver.command = android.ar + conf.linker.command = android.cc + conf.linker.flags = android.ldflags + conf.linker.flags_before_libraries = android.ldflags_before_libraries +end diff --git a/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/clang.rake b/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/clang.rake new file mode 100644 index 000000000..c75fa030c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/clang.rake @@ -0,0 +1,9 @@ +MRuby::Toolchain.new(:clang) do |conf, _params| + toolchain :gcc + + [conf.cc, conf.objc, conf.asm].each do |cc| + cc.command = ENV['CC'] || 'clang' + end + conf.cxx.command = ENV['CXX'] || 'clang++' + conf.linker.command = ENV['LD'] || 'clang' +end diff --git a/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/gcc.rake b/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/gcc.rake new file mode 100644 index 000000000..f370c0abf --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/gcc.rake @@ -0,0 +1,58 @@ +MRuby::Toolchain.new(:gcc) do |conf, _params| + [conf.cc, conf.objc, conf.asm].each do |cc| + cc.command = ENV['CC'] || 'gcc' + cc.flags = [ENV['CFLAGS'] || %w(-g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wwrite-strings)] + cc.defines = %w(DISABLE_GEMS) + cc.option_include_path = '-I%s' + cc.option_define = '-D%s' + cc.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}' + cc.cxx_compile_flag = '-x c++ -std=c++03' + cc.cxx_exception_flag = '-fexceptions' + end + + [conf.cxx].each do |cxx| + cxx.command = ENV['CXX'] || 'g++' + cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration)] + cxx.defines = %w(DISABLE_GEMS) + cxx.option_include_path = '-I%s' + cxx.option_define = '-D%s' + cxx.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}' + cxx.cxx_compile_flag = '-x c++ -std=c++03' + cxx.cxx_exception_flag = '-fexceptions' + end + + conf.linker do |linker| + linker.command = ENV['LD'] || 'gcc' + linker.flags = [ENV['LDFLAGS'] || %w()] + linker.libraries = %w(m) + linker.library_paths = [] + linker.option_library = '-l%s' + linker.option_library_path = '-L%s' + linker.link_options = '%{flags} -o %{outfile} %{objs} %{flags_before_libraries} %{libs} %{flags_after_libraries}' + end + + [[conf.cc, 'c'], [conf.cxx, 'c++']].each do |cc, lang| + cc.instance_variable_set :@header_search_language, lang + def cc.header_search_paths + if @header_search_command != command + result = `echo | #{build.filename command} -x#{@header_search_language} -Wp,-v - -fsyntax-only 2>&1` + result = `echo | #{command} -x#{@header_search_language} -Wp,-v - -fsyntax-only 2>&1` if $?.exitstatus != 0 + return include_paths if $?.exitstatus != 0 + + @frameworks = [] + @header_search_paths = result.lines.map { |v| + framework = v.match(/^ (.*)(?: \(framework directory\))$/) + if framework + @frameworks << framework[1] + next nil + end + + v.match(/^ (.*)$/) + }.compact.map { |v| v[1] }.select { |v| File.directory? v } + @header_search_paths += include_paths + @header_search_command = command + end + @header_search_paths + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/openwrt.rake b/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/openwrt.rake new file mode 100644 index 000000000..1637f6d91 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/openwrt.rake @@ -0,0 +1,38 @@ +# usage of environmental variables to set the +# cross compiling toolchain proper +MRuby::Toolchain.new(:openwrt) do |conf| + [conf.cc, conf.objc, conf.asm].each do |cc| + cc.command = ENV['TARGET_CC'] + cc.flags = ENV['TARGET_CFLAGS'] + cc.include_paths = ["#{MRUBY_ROOT}/include"] + cc.defines = %w(DISABLE_GEMS) + cc.option_include_path = '-I%s' + cc.option_define = '-D%s' + cc.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}' + end + + [conf.cxx].each do |cxx| + cxx.command = ENV['TARGET_CXX'] + cxx.flags = ENV['TARGET_CXXFLAGS'] + cxx.include_paths = ["#{MRUBY_ROOT}/include"] + cxx.defines = %w(DISABLE_GEMS) + cxx.option_include_path = '-I%s' + cxx.option_define = '-D%s' + cxx.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}' + end + + conf.linker do |linker| + linker.command = ENV['TARGET_CC'] + linker.flags = ENV['TARGET_LDFLAGS'] + linker.libraries = %w(m) + linker.library_paths = [] + linker.option_library = '-l%s' + linker.option_library_path = '-L%s' + linker.link_options = '%{flags} -o %{outfile} %{objs} %{flags_before_libraries} %{libs} %{flags_after_libraries}' + end + + conf.archiver do |archiver| + archiver.command = ENV['TARGET_AR'] + archiver.archive_options = 'rs %{outfile} %{objs}' + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/visualcpp.rake b/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/visualcpp.rake new file mode 100644 index 000000000..5bc24a73a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/tasks/toolchains/visualcpp.rake @@ -0,0 +1,68 @@ +MRuby::Toolchain.new(:visualcpp) do |conf, _params| + conf.cc do |cc| + cc.command = ENV['CC'] || 'cl.exe' + # C4013: implicit function declaration + cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /we4013 /Zi /MD /O2 /D_CRT_SECURE_NO_WARNINGS)] + cc.defines = %w(DISABLE_GEMS MRB_STACK_EXTEND_DOUBLING) + cc.option_include_path = '/I%s' + cc.option_define = '/D%s' + cc.compile_options = "%{flags} /Fo%{outfile} %{infile}" + cc.cxx_compile_flag = '/TP' + cc.cxx_exception_flag = '/EHs' + end + + conf.cxx do |cxx| + cxx.command = ENV['CXX'] || 'cl.exe' + cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(/c /nologo /W3 /Zi /MD /O2 /EHs /D_CRT_SECURE_NO_WARNINGS)] + cxx.defines = %w(DISABLE_GEMS MRB_STACK_EXTEND_DOUBLING) + cxx.option_include_path = '/I%s' + cxx.option_define = '/D%s' + cxx.compile_options = "%{flags} /Fo%{outfile} %{infile}" + cxx.cxx_compile_flag = '/TP' + cxx.cxx_exception_flag = '/EHs' + end + + conf.linker do |linker| + linker.command = ENV['LD'] || 'link.exe' + linker.flags = [ENV['LDFLAGS'] || %w(/NOLOGO /DEBUG /INCREMENTAL:NO /OPT:ICF /OPT:REF)] + linker.libraries = %w() + linker.library_paths = %w() + linker.option_library = '%s.lib' + linker.option_library_path = '/LIBPATH:%s' + linker.link_options = "%{flags} /OUT:%{outfile} %{objs} %{flags_before_libraries} %{libs} %{flags_after_libraries}" + end + + conf.archiver do |archiver| + archiver.command = ENV['AR'] || 'lib.exe' + archiver.archive_options = '/nologo /OUT:%{outfile} %{objs}' + end + + conf.yacc do |yacc| + yacc.command = ENV['YACC'] || 'bison.exe' + yacc.compile_options = '-o %{outfile} %{infile}' + end + + conf.gperf do |gperf| + gperf.command = 'gperf.exe' + gperf.compile_options = '-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" %{infile} > %{outfile}' + end + + conf.exts do |exts| + exts.object = '.obj' + exts.executable = '.exe' + exts.library = '.lib' + end + + conf.file_separator = '\\' + + if require 'open3' + Open3.popen3 conf.cc.command do |_, _, e, _| + if /Version (\d{2})\.\d{2}\.\d{5}/ =~ e.gets && $1.to_i <= 17 + m = "# VS2010/2012 support will be dropped after the next release! #" + h = "#" * m.length + puts h, m, h + end + end + end + +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/assert.rb b/web/server/h2o/libh2o/deps/mruby/test/assert.rb new file mode 100644 index 000000000..fb7ae9ab8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/assert.rb @@ -0,0 +1,248 @@ +$ok_test = 0 +$ko_test = 0 +$kill_test = 0 +$asserts = [] +$test_start = Time.now if Object.const_defined?(:Time) + +# Implementation of print due to the reason that there might be no print +def t_print(*args) + i = 0 + len = args.size + while i < len + str = args[i].to_s + __t_printstr__ str rescue print str + i += 1 + end +end + +## +# Create the assertion in a readable way +def assertion_string(err, str, iso=nil, e=nil, bt=nil) + msg = "#{err}#{str}" + msg += " [#{iso}]" if iso && iso != '' + msg += " => #{e.message}" if e + msg += " (mrbgems: #{GEMNAME})" if Object.const_defined?(:GEMNAME) + if $mrbtest_assert && $mrbtest_assert.size > 0 + $mrbtest_assert.each do |idx, assert_msg, diff| + msg += "\n - Assertion[#{idx}] Failed: #{assert_msg}\n#{diff}" + end + end + msg += "\nbacktrace:\n\t#{bt.join("\n\t")}" if bt + msg +end + +## +# Verify a code block. +# +# str : A remark which will be printed in case +# this assertion fails +# iso : The ISO reference code of the feature +# which will be tested by this +# assertion +def assert(str = 'Assertion failed', iso = '') + t_print(str, (iso != '' ? " [#{iso}]" : ''), ' : ') if $mrbtest_verbose + begin + $mrbtest_assert = [] + $mrbtest_assert_idx = 0 + yield + if($mrbtest_assert.size > 0) + $asserts.push(assertion_string('Fail: ', str, iso, nil)) + $ko_test += 1 + t_print('F') + else + $ok_test += 1 + t_print('.') + end + rescue Exception => e + bt = e.backtrace if $mrbtest_verbose + if e.class.to_s == 'MRubyTestSkip' + $asserts.push "Skip: #{str} #{iso} #{e.cause}" + t_print('?') + else + $asserts.push(assertion_string("#{e.class}: ", str, iso, e, bt)) + $kill_test += 1 + t_print('X') + end + ensure + $mrbtest_assert = nil + end + t_print("\n") if $mrbtest_verbose +end + +def assertion_diff(exp, act) + " Expected: #{exp.inspect}\n" + + " Actual: #{act.inspect}" +end + +def assert_true(ret, msg = nil, diff = nil) + if $mrbtest_assert + $mrbtest_assert_idx += 1 + unless ret + msg = "Expected #{ret.inspect} to be true" unless msg + diff = assertion_diff(true, ret) unless diff + $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) + end + end + ret +end + +def assert_false(ret, msg = nil, diff = nil) + if $mrbtest_assert + $mrbtest_assert_idx += 1 + if ret + msg = "Expected #{ret.inspect} to be false" unless msg + diff = assertion_diff(false, ret) unless diff + + $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) + end + end + !ret +end + +def assert_equal(arg1, arg2 = nil, arg3 = nil) + if block_given? + exp, act, msg = arg1, yield, arg2 + else + exp, act, msg = arg1, arg2, arg3 + end + + msg = "Expected to be equal" unless msg + diff = assertion_diff(exp, act) + assert_true(exp == act, msg, diff) +end + +def assert_not_equal(arg1, arg2 = nil, arg3 = nil) + if block_given? + exp, act, msg = arg1, yield, arg2 + else + exp, act, msg = arg1, arg2, arg3 + end + + msg = "Expected to be not equal" unless msg + diff = assertion_diff(exp, act) + assert_false(exp == act, msg, diff) +end + +def assert_nil(obj, msg = nil) + msg = "Expected #{obj.inspect} to be nil" unless msg + diff = assertion_diff(nil, obj) + assert_true(obj.nil?, msg, diff) +end + +def assert_include(collection, obj, msg = nil) + msg = "Expected #{collection.inspect} to include #{obj.inspect}" unless msg + diff = " Collection: #{collection.inspect}\n" + + " Object: #{obj.inspect}" + assert_true(collection.include?(obj), msg, diff) +end + +def assert_not_include(collection, obj, msg = nil) + msg = "Expected #{collection.inspect} to not include #{obj.inspect}" unless msg + diff = " Collection: #{collection.inspect}\n" + + " Object: #{obj.inspect}" + assert_false(collection.include?(obj), msg, diff) +end + +def assert_raise(*exc) + return true unless $mrbtest_assert + $mrbtest_assert_idx += 1 + + msg = (exc.last.is_a? String) ? exc.pop : nil + + begin + yield + msg ||= "Expected to raise #{exc} but nothing was raised." + diff = nil + $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff] + false + rescue *exc + true + rescue Exception => e + msg ||= "Expected to raise #{exc}, not" + diff = " Class: <#{e.class}>\n" + + " Message: #{e.message}" + $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff] + false + end +end + +def assert_nothing_raised(msg = nil) + return true unless $mrbtest_assert + $mrbtest_assert_idx += 1 + + begin + yield + true + rescue Exception => e + msg ||= "Expected not to raise #{exc.join(', ')} but it raised" + diff = " Class: <#{e.class}>\n" + + " Message: #{e.message}" + $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff] + false + end +end + +## +# Fails unless +obj+ is a kind of +cls+. +def assert_kind_of(cls, obj, msg = nil) + msg = "Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}" unless msg + diff = assertion_diff(cls, obj.class) + assert_true(obj.kind_of?(cls), msg, diff) +end + +## +# Fails unless +exp+ is equal to +act+ in terms of a Float +def assert_float(exp, act, msg = nil) + msg = "Float #{exp} expected to be equal to float #{act}" unless msg + diff = assertion_diff(exp, act) + assert_true check_float(exp, act), msg, diff +end + +## +# Report the test result and print all assertions +# which were reported broken. +def report() + t_print("\n") + + $asserts.each do |msg| + t_print "#{msg}\n" + end + + $total_test = $ok_test+$ko_test+$kill_test + t_print("Total: #{$total_test}\n") + + t_print(" OK: #{$ok_test}\n") + t_print(" KO: #{$ko_test}\n") + t_print("Crash: #{$kill_test}\n") + + if Object.const_defined?(:Time) + t_time = Time.now - $test_start + t_print(" Time: #{t_time.round(2)} seconds\n") + end +end + +## +# Performs fuzzy check for equality on methods returning floats +def check_float(a, b) + tolerance = Mrbtest::FLOAT_TOLERANCE + a = a.to_f + b = b.to_f + if a.finite? and b.finite? + (a-b).abs < tolerance + else + true + end +end + +## +# Skip the test +class MRubyTestSkip < NotImplementedError + attr_accessor :cause + def initialize(cause) + @cause = cause + end +end + +def skip(cause = "") + raise MRubyTestSkip.new(cause) +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/bintest.rb b/web/server/h2o/libh2o/deps/mruby/test/bintest.rb new file mode 100644 index 000000000..12971a9d9 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/bintest.rb @@ -0,0 +1,33 @@ +$:.unshift File.dirname(File.dirname(File.expand_path(__FILE__))) +require 'test/assert.rb' + +def cmd(s) + case RbConfig::CONFIG['host_os'] + when /mswin(?!ce)|mingw|bccwin/ + "bin\\#{s}.exe" + else + "bin/#{s}" + end +end + +def shellquote(s) + case RbConfig::CONFIG['host_os'] + when /mswin(?!ce)|mingw|bccwin/ + "\"#{s}\"" + else + "'#{s}'" + end +end + +ARGV.each do |gem| + case RbConfig::CONFIG['host_os'] + when /mswin(?!ce)|mingw|bccwin/ + gem = gem.gsub('\\', '/') + end + + Dir["#{gem}/bintest/**/*.rb"].each do |file| + load file + end +end + +load 'test/report.rb' diff --git a/web/server/h2o/libh2o/deps/mruby/test/report.rb b/web/server/h2o/libh2o/deps/mruby/test/report.rb new file mode 100644 index 000000000..fb77fd0aa --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/report.rb @@ -0,0 +1,4 @@ +report +if $ko_test > 0 or $kill_test > 0 + raise "mrbtest failed (KO:#{$ko_test}, Crash:#{$kill_test})" +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/argumenterror.rb b/web/server/h2o/libh2o/deps/mruby/test/t/argumenterror.rb new file mode 100644 index 000000000..abb53429b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/argumenterror.rb @@ -0,0 +1,16 @@ +## +# ArgumentError ISO Test + +assert('ArgumentError', '15.2.24') do + e2 = nil + a = [] + begin + # this will cause an exception due to the wrong arguments + a[] + rescue => e1 + e2 = e1 + end + + assert_equal(Class, ArgumentError.class) + assert_equal(ArgumentError, e2.class) +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/array.rb b/web/server/h2o/libh2o/deps/mruby/test/t/array.rb new file mode 100644 index 000000000..7c11265a4 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/array.rb @@ -0,0 +1,394 @@ +## +# Array ISO Test + +assert('Array', '15.2.12') do + assert_equal(Class, Array.class) +end + +assert('Array inclueded modules', '15.2.12.3') do + assert_true(Array.include?(Enumerable)) +end + +assert('Array.[]', '15.2.12.4.1') do + assert_equal([1, 2, 3], Array.[](1,2,3)) +end + +class SubArray < Array +end + +assert('SubArray.[]') do + a = SubArray[1, 2, 3] + assert_equal(SubArray, a.class) +end + +assert('Array#+', '15.2.12.5.1') do + assert_equal([1, 1], [1].+([1])) +end + +assert('Array#*', '15.2.12.5.2') do + assert_raise(ArgumentError) do + # this will cause an exception due to the wrong argument + [1].*(-1) + end + assert_equal([1, 1, 1], [1].*(3)) + assert_equal([], [1].*(0)) +end + +assert('Array#<<', '15.2.12.5.3') do + assert_equal([1, 1], [1].<<(1)) +end + +assert('Array#[]', '15.2.12.5.4') do + a = Array.new + assert_raise(ArgumentError) do + # this will cause an exception due to the wrong arguments + a.[]() + end + assert_raise(ArgumentError) do + # this will cause an exception due to the wrong arguments + a.[](1,2,3) + end + + assert_equal(2, [1,2,3].[](1)) + assert_equal(nil, [1,2,3].[](4)) + assert_equal(3, [1,2,3].[](-1)) + assert_equal(nil, [1,2,3].[](-4)) + + a = [ "a", "b", "c", "d", "e" ] + assert_equal("b", a[1.1]) + assert_equal(["b", "c"], a[1,2]) + assert_equal(["b", "c", "d"], a[1..-2]) +end + +assert('Array#[]=', '15.2.12.5.5') do + a = Array.new + assert_raise(ArgumentError) do + # this will cause an exception due to the wrong arguments + a.[]=() + end + assert_raise(ArgumentError) do + # this will cause an exception due to the wrong arguments + a.[]=(1,2,3,4) + end + assert_raise(IndexError) do + # this will cause an exception due to the wrong arguments + a = [1,2,3,4,5] + a[1, -1] = 10 + end + + assert_equal(4, [1,2,3].[]=(1,4)) + assert_equal(3, [1,2,3].[]=(1,2,3)) + + a = [1,2,3,4,5] + a[3..-1] = 6 + assert_equal([1,2,3,6], a) + + a = [1,2,3,4,5] + a[3..-1] = [] + assert_equal([1,2,3], a) + + a = [1,2,3,4,5] + a[2...4] = 6 + assert_equal([1,2,6,5], a) + + # passing self (#3274) + a = [1,2,3] + a[1,0] = a + assert_equal([1,1,2,3,2,3], a) + a = [1,2,3] + a[-1,0] = a + assert_equal([1,2,1,2,3,3], a) +end + +assert('Array#clear', '15.2.12.5.6') do + a = [1] + a.clear + assert_equal([], a) +end + +assert('Array#collect!', '15.2.12.5.7') do + a = [1,2,3] + a.collect! { |i| i + i } + assert_equal([2,4,6], a) +end + +assert('Array#concat', '15.2.12.5.8') do + assert_equal([1,2,3,4], [1, 2].concat([3, 4])) + + # passing self (#3302) + a = [1,2,3] + a.concat(a) + assert_equal([1,2,3,1,2,3], a) +end + +assert('Array#delete_at', '15.2.12.5.9') do + a = [1,2,3] + assert_equal(2, a.delete_at(1)) + assert_equal([1,3], a) + assert_equal(nil, a.delete_at(3)) + assert_equal([1,3], a) + assert_equal(nil, a.delete_at(-3)) + assert_equal([1,3], a) + assert_equal(3, a.delete_at(-1)) + assert_equal([1], a) +end + +assert('Array#each', '15.2.12.5.10') do + a = [1,2,3] + b = 0 + a.each {|i| b += i} + assert_equal(6, b) +end + +assert('Array#each_index', '15.2.12.5.11') do + a = [1] + b = nil + a.each_index {|i| b = i} + assert_equal(0, b) +end + +assert('Array#empty?', '15.2.12.5.12') do + a = [] + b = [b] + assert_true([].empty?) + assert_false([1].empty?) +end + +assert('Array#first', '15.2.12.5.13') do + assert_raise(ArgumentError) do + # this will cause an exception due to the wrong argument + [1,2,3].first(-1) + end + assert_raise(ArgumentError) do + # this will cause an exception due to the wrong argument + [1,2,3].first(1,2) + end + + assert_nil([].first) + + b = [1,2,3] + assert_equal(1, b.first) + assert_equal([], b.first(0)) + assert_equal([1], b.first(1)) + assert_equal([1,2,3], b.first(4)) +end + +assert('Array#index', '15.2.12.5.14') do + a = [1,2,3] + + assert_equal(1, a.index(2)) + assert_equal(nil, a.index(0)) +end + +assert('Array#initialize', '15.2.12.5.15') do + a = [].initialize(1) + b = [].initialize(2) + c = [].initialize(2, 1) + d = [].initialize(2) {|i| i} + + assert_equal([nil], a) + assert_equal([nil,nil], b) + assert_equal([1,1], c) + assert_equal([0,1], d) +end + +assert('Array#initialize_copy', '15.2.12.5.16') do + a = [1,2,3] + b = [].initialize_copy(a) + + assert_equal([1,2,3], b) +end + +assert('Array#join', '15.2.12.5.17') do + a = [1,2,3].join + b = [1,2,3].join(',') + + assert_equal('123', a) + assert_equal('1,2,3', b) +end + +assert('Array#last', '15.2.12.5.18') do + assert_raise(ArgumentError) do + # this will cause an exception due to the wrong argument + [1,2,3].last(-1) + end + + a = [1,2,3] + assert_equal(3, a.last) + assert_nil([].last) +end + +assert('Array#length', '15.2.12.5.19') do + a = [1,2,3] + + assert_equal(3, a.length) +end + +assert('Array#map!', '15.2.12.5.20') do + a = [1,2,3] + a.map! { |i| i + i } + assert_equal([2,4,6], a) +end + +assert('Array#pop', '15.2.12.5.21') do + a = [1,2,3] + b = a.pop + + assert_nil([].pop) + assert_equal([1,2], a) + assert_equal(3, b) + + assert_raise(RuntimeError) { [].freeze.pop } +end + +assert('Array#push', '15.2.12.5.22') do + a = [1,2,3] + b = a.push(4) + + assert_equal([1,2,3,4], a) + assert_equal([1,2,3,4], b) +end + +assert('Array#replace', '15.2.12.5.23') do + a = [1,2,3] + b = [].replace(a) + + assert_equal([1,2,3], b) +end + +assert('Array#reverse', '15.2.12.5.24') do + a = [1,2,3] + b = a.reverse + + assert_equal([1,2,3], a) + assert_equal([3,2,1], b) +end + +assert('Array#reverse!', '15.2.12.5.25') do + a = [1,2,3] + b = a.reverse! + + assert_equal([3,2,1], a) + assert_equal([3,2,1], b) +end + +assert('Array#rindex', '15.2.12.5.26') do + a = [1,2,3] + + assert_equal(1, a.rindex(2)) + assert_equal(nil, a.rindex(0)) +end + +assert('Array#shift', '15.2.12.5.27') do + a = [1,2,3] + b = a.shift + + assert_nil([].shift) + assert_equal([2,3], a) + assert_equal(1, b) + + assert_raise(RuntimeError) { [].freeze.shift } +end + +assert('Array#size', '15.2.12.5.28') do + a = [1,2,3] + + assert_equal(3, a.size) +end + +assert('Array#slice', '15.2.12.5.29') do + a = "12345".slice(1, 3) + b = a.slice(0) + + assert_equal("2:", "#{b}:") + assert_equal(2, [1,2,3].[](1)) +end + +assert('Array#unshift', '15.2.12.5.30') do + a = [2,3] + b = a.unshift(1) + c = [2,3] + d = c.unshift(0, 1) + + assert_equal([1,2,3], a) + assert_equal([1,2,3], b) + assert_equal([0,1,2,3], c) + assert_equal([0,1,2,3], d) +end + +assert('Array#to_s', '15.2.12.5.31 / 15.2.12.5.32') do + a = [2, 3, 4, 5] + r1 = a.to_s + r2 = a.inspect + + assert_equal(r2, r1) + assert_equal("[2, 3, 4, 5]", r1) +end + +assert('Array#==', '15.2.12.5.33') do + assert_false(["a", "c"] == ["a", "c", 7]) + assert_true(["a", "c", 7] == ["a", "c", 7]) + assert_false(["a", "c", 7] == ["a", "d", "f"]) +end + +assert('Array#eql?', '15.2.12.5.34') do + a1 = [ 1, 2, 3 ] + a2 = [ 1, 2, 3 ] + a3 = [ 1.0, 2.0, 3.0 ] + + assert_true(a1.eql? a2) + assert_false(a1.eql? a3) +end + +assert('Array#hash', '15.2.12.5.35') do + a = [ 1, 2, 3 ] + + #assert_true(a.hash.is_a? Integer) + assert_true(a.hash.is_a? Integral) # mruby special + assert_equal([1,2].hash, [1,2].hash) +end + +assert('Array#<=>', '15.2.12.5.36') do + r1 = [ "a", "a", "c" ] <=> [ "a", "b", "c" ] #=> -1 + r2 = [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ] #=> +1 + r3 = [ "a", "b", "c" ] <=> [ "a", "b", "c" ] #=> 0 + + assert_equal(-1, r1) + assert_equal(+1, r2) + assert_equal(0, r3) +end + +# Not ISO specified + +assert("Array (Shared Array Corruption)") do + a = [ "a", "b", "c", "d", "e", "f" ] + b = a.slice(1, 3) + a.clear + b.clear +end + +assert("Array (Longish inline array)") do + ary = [[0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], [11, 11], [12, 12], [13, 13], [14, 14], [15, 15], [16, 16], [17, 17], [18, 18], [19, 19], [20, 20], [21, 21], [22, 22], [23, 23], [24, 24], [25, 25], [26, 26], [27, 27], [28, 28], [29, 29], [30, 30], [31, 31], [32, 32], [33, 33], [34, 34], [35, 35], [36, 36], [37, 37], [38, 38], [39, 39], [40, 40], [41, 41], [42, 42], [43, 43], [44, 44], [45, 45], [46, 46], [47, 47], [48, 48], [49, 49], [50, 50], [51, 51], [52, 52], [53, 53], [54, 54], [55, 55], [56, 56], [57, 57], [58, 58], [59, 59], [60, 60], [61, 61], [62, 62], [63, 63], [64, 64], [65, 65], [66, 66], [67, 67], [68, 68], [69, 69], [70, 70], [71, 71], [72, 72], [73, 73], [74, 74], [75, 75], [76, 76], [77, 77], [78, 78], [79, 79], [80, 80], [81, 81], [82, 82], [83, 83], [84, 84], [85, 85], [86, 86], [87, 87], [88, 88], [89, 89], [90, 90], [91, 91], [92, 92], [93, 93], [94, 94], [95, 95], [96, 96], [97, 97], [98, 98], [99, 99], [100, 100], [101, 101], [102, 102], [103, 103], [104, 104], [105, 105], [106, 106], [107, 107], [108, 108], [109, 109], [110, 110], [111, 111], [112, 112], [113, 113], [114, 114], [115, 115], [116, 116], [117, 117], [118, 118], [119, 119], [120, 120], [121, 121], [122, 122], [123, 123], [124, 124], [125, 125], [126, 126], [127, 127], [128, 128], [129, 129], [130, 130], [131, 131], [132, 132], [133, 133], [134, 134], [135, 135], [136, 136], [137, 137], [138, 138], [139, 139], [140, 140], [141, 141], [142, 142], [143, 143], [144, 144], [145, 145], [146, 146], [147, 147], [148, 148], [149, 149], [150, 150], [151, 151], [152, 152], [153, 153], [154, 154], [155, 155], [156, 156], [157, 157], [158, 158], [159, 159], [160, 160], [161, 161], [162, 162], [163, 163], [164, 164], [165, 165], [166, 166], [167, 167], [168, 168], [169, 169], [170, 170], [171, 171], [172, 172], [173, 173], [174, 174], [175, 175], [176, 176], [177, 177], [178, 178], [179, 179], [180, 180], [181, 181], [182, 182], [183, 183], [184, 184], [185, 185], [186, 186], [187, 187], [188, 188], [189, 189], [190, 190], [191, 191], [192, 192], [193, 193], [194, 194], [195, 195], [196, 196], [197, 197], [198, 198], [199, 199]] + h = Hash.new(0) + ary.each {|p| h[p.class] += 1} + assert_equal({Array=>200}, h) +end + +assert("Array#rindex") do + class Sneaky + def ==(*) + $a.clear + $a.replace([1]) + false + end + end + $a = [2, 3, 4, 5, 6, 7, 8, 9, 10, Sneaky.new] + assert_equal 0, $a.rindex(1) +end + +assert('Array#freeze') do + a = [].freeze + assert_raise(RuntimeError) do + a[0] = 1 + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/basicobject.rb b/web/server/h2o/libh2o/deps/mruby/test/t/basicobject.rb new file mode 100644 index 000000000..f33171266 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/basicobject.rb @@ -0,0 +1,11 @@ +## +# BasicObject + +assert('BasicObject') do + assert_equal(Class, BasicObject.class) +end + +assert('BasicObject superclass') do + assert_nil(BasicObject.superclass) +end + diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/bs_block.rb b/web/server/h2o/libh2o/deps/mruby/test/t/bs_block.rb new file mode 100644 index 000000000..04a4a15ba --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/bs_block.rb @@ -0,0 +1,521 @@ +## +# Bootstrap tests for blocks + +assert('BS Block 1') do + assert_equal(1) do + 1.times{ + begin + a = 1 + ensure + foo = nil + end + } + end +end + +assert('BS Block 2') do + assert_equal 2, [1,2,3].find{|x| x == 2} +end + +assert('BS Block 3') do + class E + include Enumerable + def each(&block) + [1, 2, 3].each(&block) + end + end + assert_equal 2, E.new.find {|x| x == 2 } +end + +assert('BS Block 3') do + sum = 0 + for x in [1, 2, 3] + sum += x + end + assert_equal 6, sum +end + +assert('BS Block 4') do + sum = 0 + for x in (1..5) + sum += x + end + assert_equal 15, sum +end + +assert('BS Block 5') do + sum = 0 + for x in [] + sum += x + end + assert_equal 0, sum +end + +assert('BS Block 6') do + ans = [] + assert_equal(1) do + 1.times{ + for n in 1..3 + a = n + ans << a + end + } + end +end + +assert('BS Block 7') do + ans = [] + assert_equal((1..3)) do + for m in 1..3 + for n in 2..4 + a = [m, n] + ans << a + end + end + end +end + +assert('BS Block 8') do + assert_equal [1, 2, 3], (1..3).to_a +end + +assert('BS Block 9') do + assert_equal([4, 8, 12]) do + (1..3).map{|e| + e * 4 + } + end +end + +assert('BS Block 10') do + def m + yield + end + def n + yield + end + + assert_equal(100) do + m{ + n{ + 100 + } + } + end +end + +assert('BS Block 11') do + def m + yield 1 + end + + assert_equal(20) do + m{|ib| + m{|jb| + i = 20 + } + } + end +end + +assert('BS Block 12') do + def m + yield 1 + end + + assert_equal(2) do + m{|ib| + m{|jb| + ib = 20 + kb = 2 + } + } + end +end + +assert('BS Block 13') do + def iter1 + iter2{ + yield + } + end + + def iter2 + yield + end + + assert_equal(3) do + iter1{ + jb = 2 + iter1{ + jb = 3 + } + jb + } + end +end + +assert('BS Block 14') do + def iter1 + iter2{ + yield + } + end + + def iter2 + yield + end + + assert_equal(2) do + iter1{ + jb = 2 + iter1{ + jb + } + jb + } + end +end + +assert('BS Block 15') do + def m + yield 1 + end + assert_equal(2) do + m{|ib| + ib*2 + } + end +end + +assert('BS Block 16') do + def m + yield 12345, 67890 + end + assert_equal(92580) do + m{|ib,jb| + ib*2+jb + } + end +end + +assert('BS Block 17') do + def iter + yield 10 + end + + a = nil + assert_equal [10, nil] do + [iter{|a| + a + }, a] + end +end + +assert('BS Block 18') do + def iter + yield 10 + end + + assert_equal(21) do + iter{|a| + iter{|a| + a + 1 + } + a + } + end +end + +assert('BS Block 19') do + def iter + yield 10, 20, 30, 40 + end + + a = b = c = d = nil + assert_equal([10, 20, 30, 40, nil, nil, nil, nil]) do + iter{|a, b, c, d| + [a, b, c, d] + } + [a, b, c, d] + end +end + +assert('BS Block 20') do + def iter + yield 10, 20, 30, 40 + end + + a = b = nil + assert_equal([10, 20, 30, 40, nil, nil]) do + iter{|a, b, c, d| + [a, b, c, d] + } + [a, b] + end +end + +assert('BS Block 21') do + def iter + yield 1, 2 + end + + assert_equal([1, [2]]) do + iter{|a, *b| + [a, b] + } + end +end + +assert('BS Block 22') do + def iter + yield 1, 2 + end + + assert_equal([[1, 2]]) do + iter{|*a| + [a] + } + end +end + +assert('BS Block 23') do + def iter + yield 1, 2 + end + + assert_equal([1, 2, []]) do + iter{|a, b, *c| + [a, b, c] + } + end +end + +assert('BS Block 24') do + def m + yield + end + assert_equal(1) do + m{ + 1 + } + end +end + +assert('BS Block 25') do + def m + yield 123 + end + assert_equal(15129) do + m{|ib| + m{|jb| + ib*jb + } + } + end +end + +assert('BS Block 26') do + def m a + yield a + end + assert_equal(2) do + m(1){|ib| + m(2){|jb| + ib*jb + } + } + end +end + +assert('BS Block 27') do + sum = 0 + 3.times{|ib| + 2.times{|jb| + sum += ib + jb + }} + assert_equal sum, 9 +end + +assert('BS Block 28') do + assert_equal(10) do + 3.times{|bl| + break 10 + } + end +end + +assert('BS Block 29') do + def iter + yield 1,2,3 + end + + assert_equal([1, 2]) do + iter{|i, j| + [i, j] + } + end +end + +assert('BS Block 30') do + def iter + yield 1 + end + + assert_equal([1, nil]) do + iter{|i, j| + [i, j] + } + end +end + +assert('BS Block [ruby-dev:31147]') do + def m + yield + end + assert_nil m{|&b| b} +end + +assert('BS Block [ruby-dev:31160]') do + def m() + yield + end + assert_nil m {|(v,(*))|} +end + +assert('BS Block [issue #750]') do + def m(a, *b) + yield + end + args = [1, 2, 3] + assert_equal m(*args){ 1 }, 1 +end + +assert('BS Block 31') do + def m() + yield + end + assert_nil m {|((*))|} +end + +assert('BS Block [ruby-dev:31440]') do + def m + yield [0] + end + assert_equal m{|v, &b| v}, [0] +end + +assert('BS Block 32') do + r = false; 1.times{|&b| r = b} + assert_equal NilClass, r.class +end + +assert('BS Block [ruby-core:14395]') do + class Controller + def respond_to(&block) + responder = Responder.new + block.call(responder) + responder.respond + end + def test_for_bug + respond_to{|format| + format.js{ + "in test" + render{|obj| + obj + } + } + } + end + def render(&block) + "in render" + end + end + + class Responder + def method_missing(symbol, &block) + "enter method_missing" + @response = Proc.new{ + 'in method missing' + block.call + } + "leave method_missing" + end + def respond + @response.call + end + end + t = Controller.new + assert_true t.test_for_bug +end + +assert("BS Block 33") do + module TestReturnFromNestedBlock + def self.test + 1.times do + 1.times do + return :ok + end + end + :bad + end + end + assert_equal :ok, TestReturnFromNestedBlock.test +end + +assert("BS Block 34") do + module TestReturnFromNestedBlock_BSBlock34 + def self.test + 1.times do + while true + return :ok + end + end + :bad + end + end + assert_equal :ok, TestReturnFromNestedBlock_BSBlock34.test +end + +assert("BS Block 35") do + module TestReturnFromNestedBlock_BSBlock35 + def self.test + 1.times do + until false + return :ok + end + end + :bad + end + end + assert_equal :ok, TestReturnFromNestedBlock_BSBlock35.test +end + +assert('BS Block 36') do + def iter + yield 1, 2, 3, 4, 5 + end + + assert_equal([1, 2, [3, 4], 5]) do + iter{|a, b, *c, d| + [a, b, c, d] + } + end +end + +assert('BS Block 37') do + def iter + yield 1, 2, 3 + end + + assert_equal([1, 2, [], 3]) do + iter{|a, b, *c, d| + [a, b, c, d] + } + end +end + +assert('BS Block 38') do + def iter + yield 1,2,3,4,5,6 + end + + assert_equal [1,2,3,4,5], iter{|a,b,c=:c,d,e| [a,b,c,d,e]} +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/bs_literal.rb b/web/server/h2o/libh2o/deps/mruby/test/t/bs_literal.rb new file mode 100644 index 000000000..c6c38140b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/bs_literal.rb @@ -0,0 +1,38 @@ +## +# Bootstrap test for literals + +assert('BS Literal 1') do + assert_true true +end + +assert('BS Literal 2') do + assert_equal TrueClass, true.class +end + +assert('BS Literal 3') do + assert_false false +end + +assert('BS Literal 4') do + assert_equal FalseClass, false.class +end + +assert('BS Literal 5') do + assert_equal 'nil', nil.inspect +end + +assert('BS Literal 6') do + assert_equal NilClass, nil.class +end + +assert('BS Literal 7') do + assert_equal Symbol, :sym.class +end + +assert('BS Literal 8') do + assert_equal 1234, 1234 +end + +assert('BS Literal 9') do + assert_equal Fixnum, 1234.class +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/class.rb b/web/server/h2o/libh2o/deps/mruby/test/t/class.rb new file mode 100644 index 000000000..eb077fce6 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/class.rb @@ -0,0 +1,451 @@ +## +# Class ISO Test + +assert('Class', '15.2.3') do + assert_equal(Class, Class.class) +end + +assert('Class#initialize', '15.2.3.3.1') do + c = Class.new do + def test + :test + end + end.new + + assert_equal(c.test, :test) +end + +assert('Class#initialize_copy', '15.2.3.3.2') do + class TestClass + attr_accessor :n + def initialize(n) + @n = n + end + def initialize_copy(obj) + @n = n + end + end + + c1 = TestClass.new('Foo') + c2 = c1.dup + c3 = TestClass.new('Bar') + + assert_equal(c1.n, c2.n) + assert_not_equal(c1.n, c3.n) +end + +assert('Class#new', '15.2.3.3.3') do + assert_raise(TypeError, 'Singleton should raise TypeError') do + "a".singleton_class.new + end + + class TestClass + def initialize args, &block + @result = if not args.nil? and block.nil? + # only arguments + :only_args + elsif not args.nil? and not block.nil? + # args and block is given + :args_and_block + else + # this should never happen + :broken + end + end + + def result; @result; end + end + + assert_equal(:only_args, TestClass.new(:arg).result) + # with block doesn't work yet +end + +assert('Class#superclass', '15.2.3.3.4') do + class SubClass < String; end + assert_equal(String, SubClass.superclass) +end + +# Not ISO specified + +assert('Class 1') do + class C1; end + assert_equal(Class, C1.class) +end + +assert('Class 2') do + class C2; end + assert_equal(C2, C2.new.class) +end + +assert('Class 3') do + class C3; end + assert_equal(Class, C3.new.class.class) +end + +assert('Class 4') do + class C4_A; end + class C4 < C4_A; end + assert_equal(Class, C4.class) +end + +assert('Class 5') do + class C5_A; end + class C5 < C5_A; end + assert_equal(C5, C5.new.class) +end + +assert('Class 6') do + class C6_A; end + class C6 < C6_A; end + assert_equal(Class, C6.new.class.class) +end + +assert('Class 7') do + class C7_A; end + class C7_B; end + + class C7 < C7_A; end + + assert_raise(TypeError) do + # Different superclass. + class C7 < C7_B; end + end +end + +assert('Class 8') do + class C8_A; end + + class C8; end # superclass is Object + + assert_raise(TypeError) do + # Different superclass. + class C8 < C8_A; end + end +end + +assert('Class 9') do + Class9Const = "a" + + assert_raise(TypeError) do + class Class9Const; end + end +end + +assert('Class Module 1') do + module M; end + assert_equal(Module, M.class) +end + +assert('Class Module 2') do + module M; end + class C; include M; end + assert_equal(C, C.new.class) +end + +# nested class +assert('Class Nested 1') do + class A; end + class A::B; end + assert_equal(A::B, A::B) +end + +assert('Class Nested 2') do + class A; end + class A::B; end + assert_equal(A::B, A::B.new.class) +end + +assert('Class Nested 3') do + class A; end + class A::B; end + assert_equal(Class, A::B.new.class.class) +end + +assert('Class Nested 4') do + class A; end + class A::B; end + class A::B::C; end + assert_equal(A::B::C, A::B::C) +end + +assert('Class Nested 5') do + class A; end + class A::B; end + class A::B::C; end + assert_equal(Class, A::B::C.class) +end + +assert('Class Nested 6') do + class A; end + class A::B; end + class A::B::C; end + assert_equal(A::B::C, A::B::C.new.class) +end + +assert('Class Nested 7') do + class A; end + class A::B; end + class A::B2 < A::B; end + assert_equal(A::B2, A::B2) +end + +assert('Class Nested 8') do + class A; end + class A::B; end + class A::B2 < A::B; end + assert_equal(Class, A::B2.class) +end + +assert('Class Colon 1') do + class A; end + A::C = 1 + assert_equal(1, A::C) +end + +assert('Class Colon 2') do + class A; class ::C; end end + assert_equal(C, C) +end + +assert('Class Colon 3') do + class A; class ::C; end end + assert_equal(Class, C.class) +end + +assert('Class Dup 1') do + class C; end + assert_equal(Class, C.dup.class) +end + +assert('Class Dup 2') do + module M; end + assert_equal(Module, M.dup.class) +end + +assert('Class.new') do + assert_equal(Class, Class.new.class) + a = [] + klass = Class.new do |c| + a << c + end + assert_equal([klass], a) +end + +assert('class to return the last value') do + m = class C; :m end + assert_equal(m, :m) +end + +assert('raise when superclass is not a class') do + module FirstModule; end + assert_raise(TypeError, 'should raise TypeError') do + class FirstClass < FirstModule; end + end + + class SecondClass; end + assert_raise(TypeError, 'should raise TypeError') do + class SecondClass < false; end + end + + class ThirdClass; end + assert_raise(TypeError, 'should raise TypeError') do + class ThirdClass < ThirdClass; end + end +end + +assert('Class#inherited') do + class Foo + @@subclass_name = nil + def self.inherited(subclass) + @@subclass_name = subclass + end + def self.subclass_name + @@subclass_name + end + end + + assert_equal(nil, Foo.subclass_name) + + class Bar < Foo + end + + assert_equal(Bar, Foo.subclass_name) + + class Baz < Bar + end + + assert_equal(Baz, Foo.subclass_name) +end + +assert('singleton tests') do + module FooMod + def run_foo_mod + 100 + end + end + + bar = String.new + + baz = class << bar + extend FooMod + def self.run_baz + 200 + end + end + + assert_false baz.singleton_methods.include? :run_foo_mod + assert_false baz.singleton_methods.include? :run_baz + + assert_raise(NoMethodError, 'should raise NoMethodError') do + baz.run_foo_mod + end + assert_raise(NoMethodError, 'should raise NoMethodError') do + baz.run_baz + end + + assert_raise(NoMethodError, 'should raise NoMethodError') do + bar.run_foo_mod + end + assert_raise(NoMethodError, 'should raise NoMethodError') do + bar.run_baz + end + + baz = class << bar + extend FooMod + def self.run_baz + 300 + end + self + end + + assert_true baz.singleton_methods.include? :run_baz + assert_true baz.singleton_methods.include? :run_foo_mod + assert_equal 100, baz.run_foo_mod + assert_equal 300, baz.run_baz + + assert_raise(NoMethodError, 'should raise NoMethodError') do + bar.run_foo_mod + end + assert_raise(NoMethodError, 'should raise NoMethodError') do + bar.run_baz + end + + fv = false + class << fv + def self.run_false + 5 + end + end + + nv = nil + class << nv + def self.run_nil + 6 + end + end + + tv = true + class << tv + def self.run_nil + 7 + end + end + + assert_raise(TypeError, 'should raise TypeError') do + num = 1.0 + class << num + def self.run_nil + 7 + end + end + end +end + +assert('clone Class') do + class Foo + def func + true + end + end + + Foo.clone.new.func +end + +assert('class variable and class << self style class method') do + class ClassVariableTest + @@class_variable = "value" + class << self + def class_variable + @@class_variable + end + end + end + + assert_equal("value", ClassVariableTest.class_variable) +end + +assert('class variable definition in singleton_class') do + class ClassVariableDefinitionInSingletonTest + class << self + @@class_variable = "value" + end + def class_variable + @@class_variable + end + end + + assert_equal("value", ClassVariableDefinitionInSingletonTest.new.class_variable) +end + +assert('class variable in module and class << self style class method') do + module ClassVariableInModuleTest + @@class_variable = "value" + class << self + def class_variable + @@class_variable + end + end + end + + assert_equal("value", ClassVariableInModuleTest.class_variable) +end + +assert('child class/module defined in singleton class get parent constant') do + actual = module GetParentConstantTest + EXPECT = "value" + class << self + class CHILD + class << self + EXPECT + end + end + end + end + assert_equal("value", actual) +end + +assert('overriding class variable with a module (#3235)') do + module ModuleWithCVar + @@class_variable = 1 + end + class CVarOverrideTest + @@class_variable = 2 + include ModuleWithCVar + + assert_equal(1, @@class_variable) + end +end + +assert('class with non-class/module outer raises TypeError') do + assert_raise(TypeError) { class 0::C1; end } + assert_raise(TypeError) { class []::C2; end } +end + +assert("remove_method doesn't segfault if the passed in argument isn't a symbol") do + klass = Class.new + assert_raise(TypeError) { klass.remove_method nil } + assert_raise(TypeError) { klass.remove_method 123 } + assert_raise(TypeError) { klass.remove_method 1.23 } + assert_raise(NameError) { klass.remove_method "hello" } + assert_raise(TypeError) { klass.remove_method Class.new } +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/codegen.rb b/web/server/h2o/libh2o/deps/mruby/test/t/codegen.rb new file mode 100644 index 000000000..4c9e2c594 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/codegen.rb @@ -0,0 +1,197 @@ +## +# Codegen tests + +assert('peephole optimization does not eliminate move whose result is reused') do + assert_raise LocalJumpError do + def method + yield + end + method(&a &&= 0) + end +end + +assert('empty condition in ternary expression parses correctly') do + assert_equal(() ? 1 : 2, 2) +end + +assert('method call with exactly 127 arguments') do + def args_to_ary(*args) + args + end + + assert_equal [0]*127, args_to_ary( + 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, \ + 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,0 + ) +end + +assert('nested empty heredoc') do + _, a = nil, <<B +#{<<A} +A +B + assert_equal "\n", a +end + +assert('splat in case splat') do + a = *case + when 0 + * = 1 + end + + assert_equal [1], a +end + +assert('undef with 127 or more arguments') do + assert_raise NameError do + undef + a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, + a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, + a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, + a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a + end +end + +assert('next in normal loop with 127 arguments') do + assert_raise NameError do + while true + next A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A + end + end +end + +assert('negate literal register alignment') do + a = *case + when 0 + -0.0 + 2 + end + + assert_equal [2], a +end + +assert('register window of calls (#3783)') do + # NODE_FOR + assert_nothing_raised do + for i in []; end + end + + # NODE_SYMBOLS + assert_nothing_raised do + %i(sym) + end + + # NODE_SCALL + assert_nothing_raised do + Object.new&.__id__ + end + + # NODE_RESCUE with splat + assert_nothing_raised do + begin + raise + rescue *[Exception] + end + end + + # NODE_CASE + assert_nothing_raised do + case 1 + when nil + end + end + + # NODE_CASE with splat + assert_nothing_raised do + case 1 + when *nil + end + end + + # NODE_HASH + assert_nothing_raised do + {}.merge( + 0=>0, 1=>1, 2=>2, 3=>3, 4=>4, 5=>5, 6=>6, 7=>7, 8=>8, 9=>9, + 10=>10, 11=>11, 12=>12, 13=>13, 14=>14, 15=>15, 16=>16, 17=>17, 18=>18, 19=>19, + 20=>20, 21=>21, 22=>22, 23=>23, 24=>24, 25=>25, 26=>26, 27=>27, 28=>28, 29=>29, + 30=>30, 31=>31, 32=>32, 33=>33, 34=>34, 35=>35, 36=>36, 37=>37, 38=>38, 39=>39, + 40=>40, 41=>41, 42=>42, 43=>43, 44=>44, 45=>45, 46=>46, 47=>47, 48=>48, 49=>49, + 50=>50, 51=>51, 52=>52, 53=>53, 54=>54, 55=>55, 56=>56, 57=>57, 58=>58, 59=>59, + 60=>60, 61=>61, 62=>62, 63=>63, 64=>64, 65=>65, 66=>66, 67=>67, 68=>68, 69=>69, + 70=>70, 71=>71, 72=>72, 73=>73, 74=>74, 75=>75, 76=>76, 77=>77, 78=>78, 79=>79, + 80=>80, 81=>81, 82=>82, 83=>83, 84=>84, 85=>85, 86=>86, 87=>87, 88=>88, 89=>89, + 90=>90, 91=>91, 92=>92, 93=>93, 94=>94, 95=>95, 96=>96, 97=>97, 98=>98, 99=>99, + 100=>100, 101=>101, 102=>102, 103=>103, 104=>104, 105=>105, 106=>106, 107=>107, 108=>108, 109=>109, + 110=>110, 111=>111, 112=>112, 113=>113, 114=>114, 115=>115, 116=>116, 117=>117, 118=>118, 119=>119, + 120=>120, 121=>121, 122=>122, 123=>123, 124=>124, 125=>125, 126=>126) + end + + # NODE_OP_ASGN + o = Object.new + class << o + attr_accessor :a + end + + o.a = 1 + assert_nothing_raised{ o.a += 1 } + o.a = 1 + assert_nothing_raised{ o.a <<= 1 } + o.a = 1 + assert_nothing_raised{ o.a &&= 1 } + + o = { k: 1 } + assert_nothing_raised{ o[:k] += 1 } + o = { k: 1 } + assert_nothing_raised{ o[:k] <<= 1 } + o = { k: 1 } + assert_nothing_raised{ o[:k] &&= 1 } + + o = { k: 1 } + assert_nothing_raised{ o[*[:k]] += 1 } + o = { k: 1 } + assert_nothing_raised{ o[*[:k]] <<= 1 } + o = { k: 1 } + assert_nothing_raised{ o[*[:k]] &&= 1 } + + # NODE_YIELD + def check_node_yield + yield + end + assert_nothing_raised do + check_node_yield{} + end + + # NODE_DXSTR + assert_raise(NotImplementedError){ `#{:dynamic}` } + + # NODE_XSTR + assert_raise(NotImplementedError){ `static` } + + # NODE_DREGX + class Regexp; end + assert_raise(NoMethodError){ /#{'dynamic'}tail/ } + assert_raise(NoMethodError){ /#{'dynamic'}tail/iu } + + # NODE_REGX + assert_raise(NoMethodError){ /static/ } + assert_raise(NoMethodError){ /static/iu } + Object.remove_const :Regexp + + # NODE_UNDEF + assert_nothing_raised do + class << Object.new + undef send + end + end + + # NODE_ALIAS + assert_nothing_raised do + class << Object.new + alias send2 send + end + end +end
\ No newline at end of file diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/comparable.rb b/web/server/h2o/libh2o/deps/mruby/test/t/comparable.rb new file mode 100644 index 000000000..2ee28de7b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/comparable.rb @@ -0,0 +1,80 @@ + +assert('Comparable#<', '15.3.3.2.1') do + class Foo + include Comparable + def <=>(x) + x + end + end + assert_false(Foo.new < 0) + assert_false(Foo.new < 1) + assert_true(Foo.new < -1) + assert_raise(ArgumentError){ Foo.new < nil } +end + +assert('Comparable#<=', '15.3.3.2.2') do + class Foo + include Comparable + def <=>(x) + x + end + end + assert_true(Foo.new <= 0) + assert_false(Foo.new <= 1) + assert_true(Foo.new <= -1) + assert_raise(ArgumentError){ Foo.new <= nil } +end + +assert('Comparable#==', '15.3.3.2.3') do + class Foo + include Comparable + def <=>(x) + 0 + end + end + + assert_true(Foo.new == Foo.new) +end + +assert('Comparable#>', '15.3.3.2.4') do + class Foo + include Comparable + def <=>(x) + x + end + end + assert_false(Foo.new > 0) + assert_true(Foo.new > 1) + assert_false(Foo.new > -1) + assert_raise(ArgumentError){ Foo.new > nil } +end + +assert('Comparable#>=', '15.3.3.2.5') do + class Foo + include Comparable + def <=>(x) + x + end + end + assert_true(Foo.new >= 0) + assert_true(Foo.new >= 1) + assert_false(Foo.new >= -1) + assert_raise(ArgumentError){ Foo.new >= nil } +end + +assert('Comparable#between?', '15.3.3.2.6') do + class Foo + include Comparable + def <=>(x) + x + end + end + + c = Foo.new + + assert_false(c.between?(-1, 1)) + assert_false(c.between?(-1, -1)) + assert_false(c.between?( 1, 1)) + assert_true(c.between?( 1, -1)) + assert_true(c.between?(0, 0)) +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/ensure.rb b/web/server/h2o/libh2o/deps/mruby/test/t/ensure.rb new file mode 100644 index 000000000..bef397059 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/ensure.rb @@ -0,0 +1,54 @@ +## +# ensure Test + +assert('ensure - context - yield') do + class EnsureYieldBreak + attr_reader :ensure_context + def try + yield + ensure + @ensure_context = self + end + end + + yielder = EnsureYieldBreak.new + yielder.try do + end + assert_equal yielder, yielder.ensure_context +end + +assert('ensure - context - yield and break') do + class EnsureYieldBreak + attr_reader :ensure_context + def try + yield + ensure + @ensure_context = self + end + end + + yielder = EnsureYieldBreak.new + yielder.try do + break + end + assert_equal yielder, yielder.ensure_context +end + +assert('ensure - context - yield and return') do + class EnsureYieldBreak + attr_reader :ensure_context + def try + yield + ensure + @ensure_context = self + end + end + + yielder = EnsureYieldBreak.new + lambda do + yielder.try do + return + end + end.call + assert_equal yielder, yielder.ensure_context +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/enumerable.rb b/web/server/h2o/libh2o/deps/mruby/test/t/enumerable.rb new file mode 100644 index 000000000..359c3451b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/enumerable.rb @@ -0,0 +1,134 @@ +## +# Enumerable ISO Test + +assert('Enumerable', '15.3.2') do + assert_equal(Module, Enumerable.class) +end + +assert('Enumerable#all?', '15.3.2.2.1') do + assert_true([1,2,3].all?) + assert_false([1,false,3].all?) + + a = [2,4,6] + all = a.all? do |e| + e % 2 == 0 + end + assert_true(all) + + a = [2,4,7] + all = a.all? do |e| + e % 2 == 0 + end + assert_false(all) +end + +assert('Enumerable#any?', '15.3.2.2.2') do + assert_true([false,true,false].any?) + assert_false([false,false,false].any?) + + a = [1,3,6] + any = a.any? do |e| + e % 2 == 0 + end + assert_true(any) + + a = [1,3,5] + any = a.any? do |e| + e % 2 == 0 + end + assert_false(any) +end + +assert('Enumerable#collect', '15.3.2.2.3') do + assert_true [1,2,3].collect { |i| i + i } == [2,4,6] +end + +assert('Enumerable#detect', '15.3.2.2.4') do + assert_equal 1, [1,2,3].detect() { true } + assert_equal 'a', [1,2,3].detect("a") { false } +end + +assert('Array#each_with_index', '15.3.2.2.5') do + a = nil + b = nil + + [1].each_with_index {|e,i| a = e; b = i} + + assert_equal(1, a) + assert_equal(0, b) +end + +assert('Enumerable#entries', '15.3.2.2.6') do + assert_equal([1], [1].entries) +end + +assert('Enumerable#find', '15.3.2.2.7') do + assert_equal 1, [1,2,3].find() { true } + assert_equal 'a', [1,2,3].find("a") { false } +end + +assert('Enumerable#find_all', '15.3.2.2.8') do + assert_true [1,2,3,4,5,6,7,8,9].find_all() {|i| i%2 == 0}, [2,4,6,8] +end + +assert('Enumerable#grep', '15.3.2.2.9') do + assert_equal [4,5,6], [1,2,3,4,5,6,7,8,9].grep(4..6) +end + +assert('Enumerable#include?', '15.3.2.2.10') do + assert_true [1,2,3,4,5,6,7,8,9].include?(5) + assert_false [1,2,3,4,5,6,7,8,9].include?(0) +end + +assert('Enumerable#inject', '15.3.2.2.11') do + assert_equal 21, [1,2,3,4,5,6].inject() {|s, n| s + n} + assert_equal 22, [1,2,3,4,5,6].inject(1) {|s, n| s + n} +end + +assert('Enumerable#map', '15.3.2.2.12') do + assert_equal [2,4,6], [1,2,3].map { |i| i + i } +end + +assert('Enumerable#max', '15.3.2.2.13') do + a = ['aaa', 'bb', 'c'] + assert_equal 'c', a.max + assert_equal 'aaa', a.max {|i1,i2| i1.length <=> i2.length} +end + +assert('Enumerable#min', '15.3.2.2.14') do + a = ['aaa', 'bb', 'c'] + assert_equal 'aaa', a.min + assert_equal 'c', a.min {|i1,i2| i1.length <=> i2.length} +end + +assert('Enumerable#member?', '15.3.2.2.15') do + assert_true [1,2,3,4,5,6,7,8,9].member?(5) + assert_false [1,2,3,4,5,6,7,8,9].member?(0) +end + +assert('Enumerable#partition', '15.3.2.2.16') do + partition = [0,1,2,3,4,5,6,7,8,9].partition do |i| + i % 2 == 0 + end + assert_equal [[0,2,4,6,8], [1,3,5,7,9]], partition +end + +assert('Enumerable#reject', '15.3.2.2.17') do + reject = [0,1,2,3,4,5,6,7,8,9].reject do |i| + i % 2 == 0 + end + assert_equal [1,3,5,7,9], reject +end + +assert('Enumerable#select', '15.3.2.2.18') do + assert_equal [2,4,6,8], [1,2,3,4,5,6,7,8,9].select() {|i| i%2 == 0} +end + +assert('Enumerable#sort', '15.3.2.2.19') do + assert_equal [1,2,3,4,6,7], [7,3,1,2,6,4].sort + assert_equal [7,6,4,3,2,1], [7,3,1,2,6,4].sort {|e1,e2|e2<=>e1} +end + +assert('Enumerable#to_a', '15.3.2.2.20') do + assert_equal [1], [1].to_a +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/exception.rb b/web/server/h2o/libh2o/deps/mruby/test/t/exception.rb new file mode 100644 index 000000000..ce7b5841e --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/exception.rb @@ -0,0 +1,422 @@ +## +# Exception ISO Test + +assert('Exception', '15.2.22') do + assert_equal Class, Exception.class +end + +assert('Exception.exception', '15.2.22.4.1') do + e = Exception.exception('a') + + assert_equal Exception, e.class +end + +assert('Exception#exception', '15.2.22.5.1') do + e = Exception.new + re = RuntimeError.new + assert_equal e, e.exception + assert_equal e, e.exception(e) + assert_equal re, re.exception(re) + changed_re = re.exception('message has changed') + assert_not_equal re, changed_re + assert_equal 'message has changed', changed_re.message +end + +assert('Exception#message', '15.2.22.5.2') do + e = Exception.exception('a') + + assert_equal 'a', e.message +end + +assert('Exception#to_s', '15.2.22.5.3') do + e = Exception.exception('a') + + assert_equal 'a', e.to_s +end + +assert('Exception.exception', '15.2.22.4.1') do + e = Exception.exception() + e.initialize('a') + + assert_equal 'a', e.message +end + +assert('NameError', '15.2.31') do + assert_raise(NameError) do + raise NameError.new + end + + e = NameError.new "msg", "name" + assert_equal "msg", e.message + assert_equal "name", e.name +end + +assert('ScriptError', '15.2.37') do + assert_raise(ScriptError) do + raise ScriptError.new + end +end + +assert('SyntaxError', '15.2.38') do + assert_raise(SyntaxError) do + raise SyntaxError.new + end +end + +# Not ISO specified + +assert('Exception 1') do +r=begin + 1+1 + ensure + 2+2 + end + assert_equal 2, r +end + +assert('Exception 2') do +r=begin + 1+1 + begin + 2+2 + ensure + 3+3 + end + ensure + 4+4 + end + assert_equal 4, r +end + +assert('Exception 3') do +r=begin + 1+1 + begin + 2+2 + ensure + 3+3 + end + ensure + 4+4 + begin + 5+5 + ensure + 6+6 + end + end + assert_equal 4, r +end + +assert('Exception 4') do + a = nil + 1.times{|e| + begin + rescue => err + end + a = err.class + } + assert_equal NilClass, a +end + +assert('Exception 5') do + $ans = [] + def m + $! + end + def m2 + 1.times{ + begin + return + ensure + $ans << m + end + } + end + m2 + assert_equal [nil], $ans +end + +assert('Exception 6') do + $i = 0 + def m + iter{ + begin + $i += 1 + begin + $i += 2 + break + ensure + + end + ensure + $i += 4 + end + $i = 0 + } + end + + def iter + yield + end + m + assert_equal 7, $i +end + +assert('Exception 7') do + $i = 0 + def m + begin + $i += 1 + begin + $i += 2 + return + ensure + $i += 3 + end + ensure + $i += 4 + end + p :end + end + m + assert_equal 10, $i +end + +assert('Exception 8') do +r=begin + 1 + rescue + 2 + else + 3 + end + assert_equal 3, r +end + +assert('Exception 9') do +r=begin + 1+1 + rescue + 2+2 + else + 3+3 + ensure + 4+4 + end + assert_equal 6, r +end + +assert('Exception 10') do +r=begin + 1+1 + begin + 2+2 + rescue + 3+3 + else + 4+4 + end + rescue + 5+5 + else + 6+6 + ensure + 7+7 + end + assert_equal 12, r +end + +assert('Exception 11') do + a = :ok + begin + begin + raise Exception + rescue + a = :ng + end + rescue Exception + end + assert_equal :ok, a +end + +assert('Exception 12') do + a = :ok + begin + raise Exception rescue a = :ng + rescue Exception + end + assert_equal :ok, a +end + +assert('Exception 13') do + a = :ng + begin + raise StandardError + rescue TypeError, ArgumentError + a = :ng + rescue + a = :ok + else + a = :ng + end + assert_equal :ok, a +end + +assert('Exception 14') do + def exception_test14; UnknownConstant; end + a = :ng + begin + send(:exception_test14) + rescue + a = :ok + end + + assert_equal :ok, a +end + +assert('Exception 15') do + a = begin + :ok + rescue + :ko + end + assert_equal :ok, a +end + +assert('Exception 16') do + begin + raise "foo" + false + rescue => e + assert_equal "foo", e.message + end +end + +assert('Exception 17') do +r=begin + raise "a" # RuntimeError + rescue ArgumentError + 1 + rescue StandardError + 2 + else + 3 + ensure + 4 + end + assert_equal 2, r +end + +assert('Exception 18') do +r=begin + 0 + rescue ArgumentError + 1 + rescue StandardError + 2 + else + 3 + ensure + 4 + end + assert_equal 3, r +end + +assert('Exception 19') do + class Class4Exception19 + def a + r = @e = false + begin + b + rescue TypeError + r = self.z + end + [ r, @e ] + end + + def b + begin + 1 * "b" + ensure + @e = self.zz + end + end + + def zz + true + end + def z + true + end + end + assert_equal [true, true], Class4Exception19.new.a +end + +assert('Exception#inspect without message') do + assert_equal "Exception", Exception.new.inspect +end + +assert('Exception#backtrace') do + assert_nothing_raised do + begin + raise "get backtrace" + rescue => e + e.backtrace + end + end +end + +assert('Raise in ensure') do + assert_raise(ArgumentError) do + begin + raise "" # RuntimeError + ensure + raise ArgumentError + end + end +end + +def backtrace_available? + begin + raise "XXX" + rescue => exception + not exception.backtrace.empty? + end +end + +assert('GC in rescue') do + skip "backtrace isn't available" unless backtrace_available? + + line = nil + begin + [1].each do + [2].each do + [3].each do + line = __LINE__; raise "XXX" + end + end + end + rescue => exception + GC.start + assert_equal("#{__FILE__}:#{line}:in call", + exception.backtrace.first) + end +end + +assert('Method call in rescue') do + skip "backtrace isn't available" unless backtrace_available? + + line = nil + begin + [1].each do + [2].each do + line = __LINE__; raise "XXX" + end + end + rescue => exception + [3].each do + end + assert_equal("#{__FILE__}:#{line}:in call", + exception.backtrace.first) + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/false.rb b/web/server/h2o/libh2o/deps/mruby/test/t/false.rb new file mode 100644 index 000000000..3582f697a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/false.rb @@ -0,0 +1,31 @@ +## +# FalseClass ISO Test + +assert('FalseClass', '15.2.6') do + assert_equal Class, FalseClass.class +end + +assert('FalseClass false', '15.2.6.1') do + assert_false false + assert_equal FalseClass, false.class + assert_false FalseClass.method_defined? :new +end + +assert('FalseClass#&', '15.2.6.3.1') do + assert_false false.&(true) + assert_false false.&(false) +end + +assert('FalseClass#^', '15.2.6.3.2') do + assert_true false.^(true) + assert_false false.^(false) +end + +assert('FalseClass#to_s', '15.2.6.3.3') do + assert_equal 'false', false.to_s +end + +assert('FalseClass#|', '15.2.6.3.4') do + assert_true false.|(true) + assert_false false.|(false) +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/float.rb b/web/server/h2o/libh2o/deps/mruby/test/t/float.rb new file mode 100644 index 000000000..7e8c98988 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/float.rb @@ -0,0 +1,205 @@ +## +# Float ISO Test + +assert('Float', '15.2.9') do + assert_equal Class, Float.class +end + +assert('Float#+', '15.2.9.3.1') do + a = 3.123456788 + 0.000000001 + b = 3.123456789 + 1 + + assert_float(3.123456789, a) + assert_float(4.123456789, b) + + assert_raise(TypeError){ 0.0+nil } + assert_raise(TypeError){ 1.0+nil } +end + +assert('Float#-', '15.2.9.3.2') do + a = 3.123456790 - 0.000000001 + b = 5.123456789 - 1 + + assert_float(3.123456789, a) + assert_float(4.123456789, b) +end + +assert('Float#*', '15.2.9.3.3') do + a = 3.125 * 3.125 + b = 3.125 * 1 + + assert_float(9.765625, a) + assert_float(3.125 , b) +end + +assert('Float#/', '15.2.9.3.4') do + a = 3.123456789 / 3.123456789 + b = 3.123456789 / 1 + + assert_float(1.0 , a) + assert_float(3.123456789, b) +end + +assert('Float#%', '15.2.9.3.5') do + a = 3.125 % 3.125 + b = 3.125 % 1 + + assert_float(0.0 , a) + assert_float(0.125, b) +end + +assert('Float#<=>', '15.2.9.3.6') do + a = 3.125 <=> 3.123 + b = 3.125 <=> 3.125 + c = 3.125 <=> 3.126 + a2 = 3.125 <=> 3 + c2 = 3.125 <=> 4 + + assert_equal( 1, a) + assert_equal( 0, b) + assert_equal(-1, c) + assert_equal( 1, a2) + assert_equal(-1, c2) +end + +assert('Float#==', '15.2.9.3.7') do + assert_true 3.1 == 3.1 + assert_false 3.1 == 3.2 +end + +assert('Float#ceil', '15.2.9.3.8') do + a = 3.123456789.ceil + b = 3.0.ceil + c = -3.123456789.ceil + d = -3.0.ceil + + assert_equal( 4, a) + assert_equal( 3, b) + assert_equal(-3, c) + assert_equal(-3, d) +end + +assert('Float#finite?', '15.2.9.3.9') do + assert_true 3.123456789.finite? + assert_false (1.0 / 0.0).finite? +end + +assert('Float#floor', '15.2.9.3.10') do + a = 3.123456789.floor + b = 3.0.floor + c = -3.123456789.floor + d = -3.0.floor + + assert_equal( 3, a) + assert_equal( 3, b) + assert_equal(-4, c) + assert_equal(-3, d) +end + +assert('Float#infinite?', '15.2.9.3.11') do + a = 3.123456789.infinite? + b = (1.0 / 0.0).infinite? + c = (-1.0 / 0.0).infinite? + + assert_nil a + assert_equal( 1, b) + assert_equal(-1, c) +end + +assert('Float#round', '15.2.9.3.12') do + a = 3.123456789.round + b = 3.5.round + c = 3.4999.round + d = (-3.123456789).round + e = (-3.5).round + f = 12345.67.round(-1) + g = 3.423456789.round(0) + h = 3.423456789.round(1) + i = 3.423456789.round(3) + + assert_equal( 3, a) + assert_equal( 4, b) + assert_equal( 3, c) + assert_equal( -3, d) + assert_equal( -4, e) + assert_equal(12350, f) + assert_equal( 3, g) + assert_float( 3.4, h) + assert_float(3.423, i) + + assert_equal(42.0, 42.0.round(307)) + assert_equal(1.0e307, 1.0e307.round(2)) + + inf = 1.0/0.0 + assert_raise(FloatDomainError){ inf.round } + assert_raise(FloatDomainError){ inf.round(-1) } + assert_equal(inf, inf.round(1)) + nan = 0.0/0.0 + assert_raise(FloatDomainError){ nan.round } + assert_raise(FloatDomainError){ nan.round(-1) } + assert_true(nan.round(1).nan?) +end + +assert('Float#to_f', '15.2.9.3.13') do + a = 3.123456789 + + assert_float(a, a.to_f) +end + +assert('Float#to_i', '15.2.9.3.14') do + assert_equal(3, 3.123456789.to_i) + assert_raise(FloatDomainError) { Float::INFINITY.to_i } + assert_raise(FloatDomainError) { (-Float::INFINITY).to_i } + assert_raise(FloatDomainError) { Float::NAN.to_i } +end + +assert('Float#truncate', '15.2.9.3.15') do + assert_equal( 3, 3.123456789.truncate) + assert_equal(-3, -3.1.truncate) +end + +assert('Float#divmod') do + def check_floats exp, act + assert_float exp[0], act[0] + assert_float exp[1], act[1] + end + + # Note: quotients are Float because mruby does not have Bignum. + check_floats [ 0, 0.0], 0.0.divmod(1) + check_floats [ 0, 1.1], 1.1.divmod(3) + check_floats [ 3, 0.2], 3.2.divmod(1) + check_floats [ 2, 6.3], 20.3.divmod(7) + check_floats [-1, 1.6], -3.4.divmod(5) + check_floats [-2, -0.5], 25.5.divmod(-13) + check_floats [ 1, -6.6], -13.6.divmod(-7) + check_floats [ 3, 0.2], 9.8.divmod(3.2) +end + +assert('Float#nan?') do + assert_true (0.0/0.0).nan? + assert_false 0.0.nan? + assert_false (1.0/0.0).nan? + assert_false (-1.0/0.0).nan? +end + +assert('Float#<<') do + # Left Shift by one + assert_equal 46, 23.0 << 1 + + # Left Shift by a negative is Right Shift + assert_equal 23, 46.0 << -1 +end + +assert('Float#>>') do + # Right Shift by one + assert_equal 23, 46.0 >> 1 + + # Right Shift by a negative is Left Shift + assert_equal 46, 23.0 >> -1 + + # Don't raise on large Right Shift + assert_equal 0, 23.0 >> 128 + + # Don't raise on large Right Shift + assert_equal(-1, -23.0 >> 128) +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/gc.rb b/web/server/h2o/libh2o/deps/mruby/test/t/gc.rb new file mode 100644 index 000000000..4b800e945 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/gc.rb @@ -0,0 +1,45 @@ +# Not ISO specified + +assert('GC.enable') do + assert_false GC.disable + assert_true GC.enable + assert_false GC.enable +end + +assert('GC.disable') do + begin + assert_false GC.disable + assert_true GC.disable + ensure + GC.enable + end +end + +assert('GC.interval_ratio=') do + origin = GC.interval_ratio + begin + assert_equal 150, (GC.interval_ratio = 150) + ensure + GC.interval_ratio = origin + end +end + +assert('GC.step_ratio=') do + origin = GC.step_ratio + begin + assert_equal 150, (GC.step_ratio = 150) + ensure + GC.step_ratio = origin + end +end + +assert('GC.generational_mode=') do + origin = GC.generational_mode + begin + assert_false (GC.generational_mode = false) + assert_true (GC.generational_mode = true) + assert_true (GC.generational_mode = true) + ensure + GC.generational_mode = origin + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/hash.rb b/web/server/h2o/libh2o/deps/mruby/test/t/hash.rb new file mode 100644 index 000000000..c63b8c009 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/hash.rb @@ -0,0 +1,375 @@ +## +# Hash ISO Test + +assert('Hash', '15.2.13') do + assert_equal Class, Hash.class +end + +assert('Hash#==', '15.2.13.4.1') do + assert_true({ 'abc' => 'abc' } == { 'abc' => 'abc' }) + assert_false({ 'abc' => 'abc' } == { 'cba' => 'cba' }) + assert_true({ :equal => 1 } == { :equal => 1.0 }) + assert_false({ :a => 1 } == true) +end + +assert('Hash#[]', '15.2.13.4.2') do + a = { 'abc' => 'abc' } + + assert_equal 'abc', a['abc'] + + # Hash#[] should call #default (#3272) + hash = {} + def hash.default(k); self[k] = 1; end + hash[:foo] += 1 + + assert_equal 2, hash[:foo] +end + +assert('Hash#[]=', '15.2.13.4.3') do + a = Hash.new + a['abc'] = 'abc' + + assert_equal 'abc', a['abc'] +end + +assert('Hash#clear', '15.2.13.4.4') do + a = { 'abc' => 'abc' } + a.clear + + assert_equal({ }, a) +end + +assert('Hash#dup') do + a = { 'a' => 1 } + b = a.dup + a['a'] = 2 + assert_equal({'a' => 1}, b) + + c = Hash.new { |h, k| h[k] = k.upcase } + d = c.dup + assert_equal("FOO", d["foo"]) +end + +assert('Hash#default', '15.2.13.4.5') do + a = Hash.new + b = Hash.new('abc') + c = Hash.new {|s,k| s[k] = k} + + assert_nil a.default + assert_equal 'abc', b.default + assert_nil c.default + assert_equal 'abc', c.default('abc') +end + +assert('Hash#default=', '15.2.13.4.6') do + a = { 'abc' => 'abc' } + a.default = 'cba' + + assert_equal 'abc', a['abc'] + assert_equal 'cba', a['notexist'] +end + +assert('Hash#default_proc', '15.2.13.4.7') do + a = Hash.new + b = Hash.new {|s,k| s[k] = k + k} + c = b[2] + d = b['cat'] + + assert_nil a.default_proc + assert_equal Proc, b.default_proc.class + assert_equal 4, c + assert_equal 'catcat', d +end + +assert('Hash#delete', '15.2.13.4.8') do + a = { 'abc' => 'abc' } + b = { 'abc' => 'abc' } + b_tmp_1 = false + b_tmp_2 = false + + a.delete('abc') + b.delete('abc') do |k| + b_tmp_1 = true + end + b.delete('abc') do |k| + b_tmp_2 = true + end + + assert_nil a.delete('cba') + assert_false a.has_key?('abc') + assert_false b_tmp_1 + assert_true b_tmp_2 +end + +assert('Hash#each', '15.2.13.4.9') do + a = { 'abc_key' => 'abc_value' } + key = nil + value = nil + + a.each do |k,v| + key = k + value = v + end + + assert_equal 'abc_key', key + assert_equal 'abc_value', value +end + +assert('Hash#each_key', '15.2.13.4.10') do + a = { 'abc_key' => 'abc_value' } + key = nil + + a.each_key do |k| + key = k + end + + assert_equal 'abc_key', key +end + +assert('Hash#each_value', '15.2.13.4.11') do + a = { 'abc_key' => 'abc_value' } + value = nil + + a.each_value do |v| + value = v + end + + assert_equal 'abc_value', value +end + +assert('Hash#empty?', '15.2.13.4.12') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new + + assert_false a.empty? + assert_true b.empty? +end + +assert('Hash#has_key?', '15.2.13.4.13') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new + + assert_true a.has_key?('abc_key') + assert_false b.has_key?('cba') +end + +assert('Hash#has_value?', '15.2.13.4.14') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new + + assert_true a.has_value?('abc_value') + assert_false b.has_value?('cba') +end + +assert('Hash#include?', '15.2.13.4.15') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new + + assert_true a.include?('abc_key') + assert_false b.include?('cba') +end + +assert('Hash#initialize', '15.2.13.4.16') do + # Testing initialize by new. + h = Hash.new + h2 = Hash.new(:not_found) + + assert_true h.is_a? Hash + assert_equal({ }, h) + assert_nil h["hello"] + assert_equal :not_found, h2["hello"] +end + +assert('Hash#initialize_copy', '15.2.13.4.17') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new.initialize_copy(a) + + assert_equal({ 'abc_key' => 'abc_value' }, b) +end + +assert('Hash#key?', '15.2.13.4.18') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new + + assert_true a.key?('abc_key') + assert_false b.key?('cba') +end + +assert('Hash#keys', '15.2.13.4.19') do + a = { 'abc_key' => 'abc_value' } + + assert_equal ['abc_key'], a.keys +end + +assert('Hash#length', '15.2.13.4.20') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new + + assert_equal 1, a.length + assert_equal 0, b.length +end + +assert('Hash#member?', '15.2.13.4.21') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new + + assert_true a.member?('abc_key') + assert_false b.member?('cba') +end + +assert('Hash#merge', '15.2.13.4.22') do + a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' } + b = { 'cba_key' => 'XXX', 'xyz_key' => 'xyz_value' } + + result_1 = a.merge b + result_2 = a.merge(b) do |key, original, new| + original + end + + assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'XXX', + 'xyz_key' => 'xyz_value' }, result_1) + assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'cba_value', + 'xyz_key' => 'xyz_value' }, result_2) + + assert_raise(TypeError) do + { 'abc_key' => 'abc_value' }.merge "a" + end +end + +assert('Hash#replace', '15.2.13.4.23') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new.replace(a) + + assert_equal({ 'abc_key' => 'abc_value' }, b) + + a = Hash.new(42) + b = {} + b.replace(a) + assert_equal(42, b[1]) + + a = Hash.new{|h,x| x} + b.replace(a) + assert_equal(127, b[127]) + + assert_raise(TypeError) do + { 'abc_key' => 'abc_value' }.replace "a" + end +end + +assert('Hash#shift', '15.2.13.4.24') do + a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' } + b = a.shift + + assert_equal Array, b.class + assert_equal 2, b.size + assert_equal 1, a.size + + b = a.shift + + assert_equal Array, b.class + assert_equal 2, b.size + assert_equal 0, a.size +end + +assert('Hash#size', '15.2.13.4.25') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new + + assert_equal 1, a.size + assert_equal 0, b.size +end + +assert('Hash#store', '15.2.13.4.26') do + a = Hash.new + a.store('abc', 'abc') + + assert_equal 'abc', a['abc'] +end + +assert('Hash#value?', '15.2.13.4.27') do + a = { 'abc_key' => 'abc_value' } + b = Hash.new + + assert_true a.value?('abc_value') + assert_false b.value?('cba') +end + +assert('Hash#values', '15.2.13.4.28') do + a = { 'abc_key' => 'abc_value' } + + assert_equal ['abc_value'], a.values +end + +# Not ISO specified + +assert('Hash#eql?') do + a = { 'a' => 1, 'b' => 2, 'c' => 3 } + b = { 'a' => 1, 'b' => 2, 'c' => 3 } + c = { 'a' => 1.0, 'b' => 2, 'c' => 3 } + assert_true(a.eql?(b)) + assert_false(a.eql?(c)) + assert_false(a.eql?(true)) +end + +assert('Hash#reject') do + h = {:one => 1, :two => 2, :three => 3, :four => 4} + ret = h.reject do |k,v| + v % 2 == 0 + end + assert_equal({:one => 1, :three => 3}, ret) + assert_equal({:one => 1, :two => 2, :three => 3, :four => 4}, h) +end + +assert('Hash#reject!') do + h = {:one => 1, :two => 2, :three => 3, :four => 4} + ret = h.reject! do |k,v| + v % 2 == 0 + end + assert_equal({:one => 1, :three => 3}, ret) + assert_equal({:one => 1, :three => 3}, h) +end + +assert('Hash#select') do + h = {:one => 1, :two => 2, :three => 3, :four => 4} + ret = h.select do |k,v| + v % 2 == 0 + end + assert_equal({:two => 2, :four => 4}, ret) + assert_equal({:one => 1, :two => 2, :three => 3, :four => 4}, h) +end + +assert('Hash#select!') do + h = {:one => 1, :two => 2, :three => 3, :four => 4} + ret = h.select! do |k,v| + v % 2 == 0 + end + assert_equal({:two => 2, :four => 4}, ret) + assert_equal({:two => 2, :four => 4}, h) +end + +# Not ISO specified + +assert('Hash#inspect') do + h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 } + ret = h.to_s + + assert_include ret, '"c"=>300' + assert_include ret, '"a"=>100' + assert_include ret, '"d"=>400' +end + +assert('Hash#rehash') do + h = {[:a] => "b"} + # hash key modified + h.keys[0][0] = :b + # h[[:b]] => nil + h.rehash + assert_equal("b", h[[:b]]) +end + +assert('Hash#freeze') do + h = {}.freeze + assert_raise(RuntimeError) do + h[:a] = 'b' + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/indexerror.rb b/web/server/h2o/libh2o/deps/mruby/test/t/indexerror.rb new file mode 100644 index 000000000..a8dce23a0 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/indexerror.rb @@ -0,0 +1,6 @@ +## +# IndexError ISO Test + +assert('IndexError', '15.2.33') do + assert_equal Class, IndexError.class +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/integer.rb b/web/server/h2o/libh2o/deps/mruby/test/t/integer.rb new file mode 100644 index 000000000..d4ef8b519 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/integer.rb @@ -0,0 +1,268 @@ +## +# Integer ISO Test + +assert('Integer', '15.2.8') do + assert_equal Class, Integer.class +end + +assert('Integer#+', '15.2.8.3.1') do + a = 1+1 + b = 1+1.0 + + assert_equal 2, a + assert_equal 2.0, b + + assert_raise(TypeError){ 0+nil } + assert_raise(TypeError){ 1+nil } + + c = Mrbtest::FIXNUM_MAX + 1 + d = Mrbtest::FIXNUM_MAX.__send__(:+, 1) + e = Mrbtest::FIXNUM_MAX + 1.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d +end + +assert('Integer#-', '15.2.8.3.2') do + a = 2-1 + b = 2-1.0 + + assert_equal 1, a + assert_equal 1.0, b + + c = Mrbtest::FIXNUM_MIN - 1 + d = Mrbtest::FIXNUM_MIN.__send__(:-, 1) + e = Mrbtest::FIXNUM_MIN - 1.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d +end + +assert('Integer#*', '15.2.8.3.3') do + a = 1*1 + b = 1*1.0 + + assert_equal 1, a + assert_equal 1.0, b + + assert_raise(TypeError){ 0*nil } + assert_raise(TypeError){ 1*nil } + + c = Mrbtest::FIXNUM_MAX * 2 + d = Mrbtest::FIXNUM_MAX.__send__(:*, 2) + e = Mrbtest::FIXNUM_MAX * 2.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d +end + +assert('Integer#/', '15.2.8.3.4') do + a = 2/1 + b = 2/1.0 + + assert_equal 2, a + assert_equal 2.0, b +end + +assert('Integer#%', '15.2.8.3.5') do + a = 1%1 + b = 1%1.0 + c = 2%4 + d = 2%5 + e = 2%-5 + f = -2%5 + g = -2%-5 + h = 2%-2 + i = -2%2 + j = -2%-2 + + assert_equal 0, a + assert_equal 0.0, b + assert_equal 2, c + assert_equal 2, d + assert_equal(-3, e) + assert_equal 3, f + assert_equal(-2, g) + assert_equal 0, h + assert_equal 0, i + assert_equal 0, j +end + +assert('Integer#<=>', '15.2.9.3.6') do + a = 1<=>0 + b = 1<=>1 + c = 1<=>2 + + assert_equal 1, a + assert_equal 0, b + assert_equal(-1, c) +end + +assert('Integer#==', '15.2.8.3.7') do + a = 1==0 + b = 1==1 + + assert_false a + assert_true b +end + +assert('Integer#~', '15.2.8.3.8') do + # Complement + assert_equal(-1, ~0) + assert_equal(-3, ~2) +end + +assert('Integer#&', '15.2.8.3.9') do + # Bitwise AND + # 0101 (5) + # & 0011 (3) + # = 0001 (1) + assert_equal 1, 5 & 3 +end + +assert('Integer#|', '15.2.8.3.10') do + # Bitwise OR + # 0101 (5) + # | 0011 (3) + # = 0111 (7) + assert_equal 7, 5 | 3 +end + +assert('Integer#^', '15.2.8.3.11') do + # Bitwise XOR + # 0101 (5) + # ^ 0011 (3) + # = 0110 (6) + assert_equal 6, 5 ^ 3 +end + +assert('Integer#<<', '15.2.8.3.12') do + # Left Shift by one + # 00010111 (23) + # = 00101110 (46) + assert_equal 46, 23 << 1 + + # Left Shift by a negative is Right Shift + assert_equal 23, 46 << -1 + + # Left Shift by 31 is bitShift overflow to SignedInt + assert_equal 2147483648, 1 << 31 + + # -3 Left Shift by 30 is bitShift overflow to SignedInt + assert_equal(-3221225472, -3 << 30) +end + +assert('Integer#>>', '15.2.8.3.13') do + # Right Shift by one + # 00101110 (46) + # = 00010111 (23) + assert_equal 23, 46 >> 1 + + # Right Shift by a negative is Left Shift + assert_equal 46, 23 >> -1 + + # Don't raise on large Right Shift + assert_equal 0, 23 >> 128 +end + +assert('Integer#ceil', '15.2.8.3.14') do + assert_equal 10, 10.ceil +end + +assert('Integer#downto', '15.2.8.3.15') do + a = 0 + 3.downto(1) do |i| + a += i + end + assert_equal 6, a +end + +assert('Integer#eql?', '15.2.8.3.16') do + a = 1.eql?(1) + b = 1.eql?(2) + c = 1.eql?(nil) + + assert_true a + assert_false b + assert_false c +end + +assert('Integer#floor', '15.2.8.3.17') do + a = 1.floor + + assert_equal 1, a +end + +assert('Integer#next', '15.2.8.3.19') do + assert_equal 2, 1.next +end + +assert('Integer#round', '15.2.8.3.20') do + assert_equal 1, 1.round +end + +assert('Integer#succ', '15.2.8.3.21') do + assert_equal 2, 1.succ +end + +assert('Integer#times', '15.2.8.3.22') do + a = 0 + 3.times do + a += 1 + end + assert_equal 3, a +end + +assert('Integer#to_f', '15.2.8.3.23') do + assert_equal 1.0, 1.to_f +end + +assert('Integer#to_i', '15.2.8.3.24') do + assert_equal 1, 1.to_i +end + +assert('Integer#to_s', '15.2.8.3.25') do + assert_equal '1', 1.to_s + assert_equal("-1", -1.to_s) +end + +assert('Integer#truncate', '15.2.8.3.26') do + assert_equal 1, 1.truncate +end + +assert('Integer#upto', '15.2.8.3.27') do + a = 0 + 1.upto(3) do |i| + a += i + end + assert_equal 6, a +end + +assert('Integer#divmod', '15.2.8.3.30') do + assert_equal [ 0, 0], 0.divmod(1) + assert_equal [ 0, 1], 1.divmod(3) + assert_equal [ 3, 0], 3.divmod(1) + assert_equal [ 2, 6], 20.divmod(7) + assert_equal [-1, 2], -3.divmod(5) + assert_equal [-2, -1], 25.divmod(-13) + assert_equal [ 1, -6], -13.divmod(-7) +end + +# Not ISO specified + +assert('Integer#step') do + a = [] + b = [] + 1.step(3) do |i| + a << i + end + 1.step(6, 2) do |i| + b << i + end + + assert_equal [1, 2, 3], a + assert_equal [1, 3, 5], b +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/iterations.rb b/web/server/h2o/libh2o/deps/mruby/test/t/iterations.rb new file mode 100644 index 000000000..f227a6037 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/iterations.rb @@ -0,0 +1,61 @@ +assert('while expression', '11.5.2.3.2') do + idx = 10 + all = [] + res = while idx > 0 + all << idx + idx -= 1 + end + + assert_equal nil, res + assert_equal [10,9,8,7,6,5,4,3,2,1], all +end + +assert('until expression', '11.5.2.3.3') do + idx = 10 + all = [] + res = until idx == 0 + all << idx + idx -= 1 + end + + assert_equal nil, res + assert_equal [10,9,8,7,6,5,4,3,2,1], all +end + +assert('break expression', '11.5.2.4.3') do + assert_equal :result do + while true + break :result + end + end + + assert_equal :result do + until false + break :result + end + end +end + +assert('next expression', '11.5.2.4.4') do + assert_equal [8,6,4,2,0] do + all = [] + idx = 10 + while idx > 0 + idx -= 1 + next if (idx % 2) == 1 + all << idx + end + all + end + + assert_equal [8,6,4,2,0] do + all = [] + idx = 10 + until idx == 0 + idx -= 1 + next if (idx % 2) == 1 + all << idx + end + all + end +end
\ No newline at end of file diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/kernel.rb b/web/server/h2o/libh2o/deps/mruby/test/t/kernel.rb new file mode 100644 index 000000000..e9bd24dc3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/kernel.rb @@ -0,0 +1,643 @@ +## +# Kernel ISO Test + +assert('Kernel', '15.3.1') do + assert_equal Module, Kernel.class +end + +assert('Kernel.block_given?', '15.3.1.2.2') do + def bg_try(&b) + if Kernel.block_given? + yield + else + "no block" + end + end + + assert_false Kernel.block_given? + # test without block + assert_equal "no block", bg_try + # test with block + assert_equal "block" do + bg_try { "block" } + end + # test with block + assert_equal "block" do + bg_try do + "block" + end + end +end + +# Kernel.eval is provided by the mruby-gem mrbgem. '15.3.1.2.3' + +assert('Kernel.global_variables', '15.3.1.2.4') do + assert_equal Array, Kernel.global_variables.class +end + +assert('Kernel.iterator?', '15.3.1.2.5') do + assert_false Kernel.iterator? +end + +assert('Kernel.lambda', '15.3.1.2.6') do + l = Kernel.lambda do + true + end + + m = Kernel.lambda(&l) + + assert_true l.call + assert_equal Proc, l.class + assert_true m.call + assert_equal Proc, m.class +end + +# Not implemented at the moment +#assert('Kernel.local_variables', '15.3.1.2.7') do +# Kernel.local_variables.class == Array +#end + +assert('Kernel.loop', '15.3.1.2.8') do + i = 0 + + Kernel.loop do + i += 1 + break if i == 100 + end + + assert_equal 100, i +end + +assert('Kernel.p', '15.3.1.2.9') do + # TODO search for a way to test p to stdio + assert_true true +end + +assert('Kernel.print', '15.3.1.2.10') do + # TODO search for a way to test print to stdio + assert_true true +end + +assert('Kernel.puts', '15.3.1.2.11') do + # TODO search for a way to test puts to stdio + assert_true true +end + +assert('Kernel.raise', '15.3.1.2.12') do + assert_raise RuntimeError do + Kernel.raise + end + + assert_raise RuntimeError do + Kernel.raise RuntimeError.new + end +end + +assert('Kernel#__id__', '15.3.1.3.3') do + assert_equal Fixnum, __id__.class +end + +assert('Kernel#__send__', '15.3.1.3.4') do + # test with block + l = __send__(:lambda) do + true + end + + assert_true l.call + assert_equal Proc, l.class + # test with argument + assert_true __send__(:respond_to?, :nil?) + # test without argument and without block + assert_equal Array, __send__(:public_methods).class +end + +assert('Kernel#block_given?', '15.3.1.3.6') do + def bg_try(&b) + if block_given? + yield + else + "no block" + end + end + + assert_false block_given? + assert_equal "no block", bg_try + assert_equal "block" do + bg_try { "block" } + end + assert_equal "block" do + bg_try do + "block" + end + end +end + +assert('Kernel#class', '15.3.1.3.7') do + assert_equal Module, Kernel.class +end + +assert('Kernel#clone', '15.3.1.3.8') do + class KernelCloneTest + def initialize + @v = 0 + end + + def get + @v + end + + def set(v) + @v = v + end + end + + a = KernelCloneTest.new + a.set(1) + b = a.clone + + def a.test + end + a.set(2) + c = a.clone + + immutables = [ 1, :foo, true, false, nil ] + error_count = 0 + immutables.each do |i| + begin + i.clone + rescue TypeError + error_count += 1 + end + end + + assert_equal 2, a.get + assert_equal 1, b.get + assert_equal 2, c.get + assert_true a.respond_to?(:test) + assert_false b.respond_to?(:test) + assert_true c.respond_to?(:test) +end + +assert('Kernel#dup', '15.3.1.3.9') do + class KernelDupTest + def initialize + @v = 0 + end + + def get + @v + end + + def set(v) + @v = v + end + end + + a = KernelDupTest.new + a.set(1) + b = a.dup + + def a.test + end + a.set(2) + c = a.dup + + immutables = [ 1, :foo, true, false, nil ] + error_count = 0 + immutables.each do |i| + begin + i.dup + rescue TypeError + error_count += 1 + end + end + + assert_equal immutables.size, error_count + assert_equal 2, a.get + assert_equal 1, b.get + assert_equal 2, c.get + assert_true a.respond_to?(:test) + assert_false b.respond_to?(:test) + assert_false c.respond_to?(:test) +end + +assert('Kernel#dup class') do + assert_nothing_raised do + Array.dup.new(200) + Range.dup.new(2, 3) + String.dup.new("a"*50) + end +end + +# Kernel#eval is provided by mruby-eval mrbgem '15.3.1.3.12' + +assert('Kernel#extend', '15.3.1.3.13') do + class Test4ExtendClass + end + + module Test4ExtendModule + def test_method; end + end + + a = Test4ExtendClass.new + a.extend(Test4ExtendModule) + b = Test4ExtendClass.new + + assert_true a.respond_to?(:test_method) + assert_false b.respond_to?(:test_method) +end + +assert('Kernel#extend works on toplevel', '15.3.1.3.13') do + module Test4ExtendModule + def test_method; end + end + # This would crash... + extend(Test4ExtendModule) + + assert_true respond_to?(:test_method) +end + +assert('Kernel#freeze') do + obj = Object.new + assert_equal obj, obj.freeze + assert_equal 0, 0.freeze + assert_equal :a, :a.freeze +end + +assert('Kernel#global_variables', '15.3.1.3.14') do + assert_equal Array, global_variables.class +end + +assert('Kernel#hash', '15.3.1.3.15') do + assert_equal hash, hash +end + +assert('Kernel#inspect', '15.3.1.3.17') do + s = inspect + + assert_equal String, s.class + assert_equal "main", s +end + +assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do + o = Object.new + o.instance_variable_set(:@a, 1) + + assert_true o.instance_variable_defined?("@a") + assert_false o.instance_variable_defined?("@b") + assert_true o.instance_variable_defined?("@a"[0,2]) + assert_true o.instance_variable_defined?("@abc"[0,2]) +end + +assert('Kernel#instance_variables', '15.3.1.3.23') do + o = Object.new + o.instance_eval do + @a = 11 + @b = 12 + end + ivars = o.instance_variables + + assert_equal Array, ivars.class, + assert_equal(2, ivars.size) + assert_true ivars.include?(:@a) + assert_true ivars.include?(:@b) +end + +assert('Kernel#is_a?', '15.3.1.3.24') do + assert_true is_a?(Kernel) + assert_false is_a?(Array) + + assert_raise TypeError do + 42.is_a?(42) + end +end + +assert('Kernel#iterator?', '15.3.1.3.25') do + assert_false iterator? +end + +assert('Kernel#kind_of?', '15.3.1.3.26') do + assert_true kind_of?(Kernel) + assert_false kind_of?(Array) +end + +assert('Kernel#lambda', '15.3.1.3.27') do + l = lambda do + true + end + + m = lambda(&l) + + assert_true l.call + assert_equal Proc, l.class + assert_true m.call + assert_equal Proc, m.class +end + +# Not implemented yet +#assert('Kernel#local_variables', '15.3.1.3.28') do +# local_variables.class == Array +#end + +assert('Kernel#loop', '15.3.1.3.29') do + i = 0 + + loop do + i += 1 + break if i == 100 + end + + assert_equal i, 100 +end + +assert('Kernel#method_missing', '15.3.1.3.30') do + class MMTestClass + def method_missing(sym) + "A call to #{sym}" + end + end + mm_test = MMTestClass.new + assert_equal 'A call to no_method_named_this', mm_test.no_method_named_this + + class SuperMMTestClass < MMTestClass + def no_super_method_named_this + super + end + end + super_mm_test = SuperMMTestClass.new + assert_equal 'A call to no_super_method_named_this', super_mm_test.no_super_method_named_this + + class NoSuperMethodTestClass + def no_super_method_named_this + super + end + end + no_super_test = NoSuperMethodTestClass.new + begin + no_super_test.no_super_method_named_this + rescue NoMethodError => e + assert_equal "undefined method 'no_super_method_named_this' for #{no_super_test}", e.message + end + + a = String.new + begin + a.no_method_named_this + rescue NoMethodError => e + assert_equal "undefined method 'no_method_named_this' for \"\"", e.message + end + + class ShortInspectClass + def inspect + 'An inspect string' + end + end + b = ShortInspectClass.new + begin + b.no_method_named_this + rescue NoMethodError => e + assert_equal "undefined method 'no_method_named_this' for An inspect string", e.message + end + + class LongInspectClass + def inspect + "A" * 70 + end + end + c = LongInspectClass.new + begin + c.no_method_named_this + rescue NoMethodError => e + assert_equal "undefined method 'no_method_named_this' for #{c}", e.message + end + + class NoInspectClass + undef inspect + end + d = NoInspectClass.new + begin + d.no_method_named_this + rescue NoMethodError => e + assert_equal "undefined method 'no_method_named_this' for #{d}", e.message + end +end + +assert('Kernel#methods', '15.3.1.3.31') do + assert_equal Array, methods.class +end + +assert('Kernel#nil?', '15.3.1.3.32') do + assert_false nil? +end + +assert('Kernel#object_id', '15.3.1.3.33') do + a = "" + b = "" + assert_not_equal a.object_id, b.object_id + + assert_kind_of Numeric, object_id + assert_kind_of Numeric, "".object_id + assert_kind_of Numeric, true.object_id + assert_kind_of Numeric, false.object_id + assert_kind_of Numeric, nil.object_id + assert_kind_of Numeric, :no.object_id + assert_kind_of Numeric, 1.object_id + assert_kind_of Numeric, 1.0.object_id +end + +# Kernel#p is defined in mruby-print mrbgem. '15.3.1.3.34' + +# Kernel#print is defined in mruby-print mrbgem. '15.3.1.3.35' + +assert('Kernel#private_methods', '15.3.1.3.36') do + assert_equal Array, private_methods.class +end + +assert('Kernel#protected_methods', '15.3.1.3.37') do + assert_equal Array, protected_methods.class +end + +assert('Kernel#public_methods', '15.3.1.3.38') do + assert_equal Array, public_methods.class + class Foo + def foo + end + end + assert_equal [:foo], Foo.new.public_methods(false) +end + +# Kernel#puts is defined in mruby-print mrbgem. '15.3.1.3.39' + +assert('Kernel#raise', '15.3.1.3.40') do + assert_raise RuntimeError do + raise + end + + assert_raise RuntimeError do + raise RuntimeError.new + end +end + +assert('Kernel#remove_instance_variable', '15.3.1.3.41') do + class Test4RemoveInstanceVar + attr_reader :var + def initialize + @var = 99 + end + def remove + remove_instance_variable(:@var) + end + end + + tri = Test4RemoveInstanceVar.new + assert_equal 99, tri.var + tri.remove + assert_equal nil, tri.var + assert_raise NameError do + tri.remove + end +end + +# Kernel#require is defined in mruby-require. '15.3.1.3.42' + +assert('Kernel#respond_to?', '15.3.1.3.43') do + class Test4RespondTo + def valid_method; end + + def test_method; end + undef test_method + end + + assert_raise TypeError do + Test4RespondTo.new.respond_to?(1) + end + + assert_raise ArgumentError do + Test4RespondTo.new.respond_to? + end + + assert_raise ArgumentError do + Test4RespondTo.new.respond_to? :a, true, :aa + end + + assert_true respond_to?(:nil?) + assert_true Test4RespondTo.new.respond_to?(:valid_method) + assert_true Test4RespondTo.new.respond_to?('valid_method') + assert_false Test4RespondTo.new.respond_to?(:test_method) +end + +assert('Kernel#send', '15.3.1.3.44') do + # test with block + l = send(:lambda) do + true + end + + assert_true l.call + assert_equal l.class, Proc + # test with argument + assert_true send(:respond_to?, :nil?) + # test without argument and without block + assert_equal send(:public_methods).class, Array +end + +assert('Kernel#singleton_methods', '15.3.1.3.45') do + assert_equal singleton_methods.class, Array +end + +assert('Kernel#to_s', '15.3.1.3.46') do + assert_equal to_s.class, String +end + +assert('Kernel#to_s on primitives') do + begin + Fixnum.alias_method :to_s_, :to_s + Fixnum.remove_method :to_s + + assert_nothing_raised do + # segfaults if mrb_cptr is used + 1.to_s + end + ensure + Fixnum.alias_method :to_s, :to_s_ + Fixnum.remove_method :to_s_ + end +end + +assert('Kernel.local_variables', '15.3.1.2.7') do + a, b = 0, 1 + a += b + + vars = Kernel.local_variables.sort + assert_equal [:a, :b, :vars], vars + + assert_equal [:a, :b, :c, :vars], Proc.new { |a, b| + c = 2 + Kernel.local_variables.sort + }.call(-1, -2) +end + +assert('Kernel#!=') do + str1 = "hello" + str2 = str1 + str3 = "world" + + assert_false (str1[1] != 'e') + assert_true (str1 != str3) + assert_false (str2 != str1) +end + +# operator "!~" is defined in ISO Ruby 11.4.4. +assert('Kernel#!~') do + x = "x" + def x.=~(other) + other == "x" + end + assert_false x !~ "x" + assert_true x !~ "z" + + y = "y" + def y.=~(other) + other == "y" + end + def y.!~(other) + other == "not y" + end + assert_false y !~ "y" + assert_false y !~ "z" + assert_true y !~ "not y" +end + +assert('Kernel#respond_to_missing?') do + class Test4RespondToMissing + def respond_to_missing?(method_name, include_private = false) + method_name == :a_method + end + end + + assert_true Test4RespondToMissing.new.respond_to?(:a_method) + assert_false Test4RespondToMissing.new.respond_to?(:no_method) +end + +assert('Kernel#global_variables') do + variables = global_variables + 1.upto(9) do |i| + assert_equal variables.include?(:"$#{i}"), true + end +end + +assert('Kernel#define_singleton_method') do + o = Object.new + ret = o.define_singleton_method(:test_method) do + :singleton_method_ok + end + assert_equal :test_method, ret + assert_equal :singleton_method_ok, o.test_method +end + +assert('stack extend') do + def recurse(count, stop) + return count if count > stop + recurse(count+1, stop) + end + + assert_equal 6, recurse(0, 5) +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/lang.rb b/web/server/h2o/libh2o/deps/mruby/test/t/lang.rb new file mode 100755 index 000000000..57c375643 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/lang.rb @@ -0,0 +1,74 @@ +# The aim of these tests is to detect pitfall for optimized VM.
+
+# Test for or/and
+#
+# You may think instruction fusion(OP_EQ and OP_JMPIF) for avoiding
+# generate intermediate boolean value.
+# But and/or is pitfall for this fusioning.
+#
+# For example, the following mruby code:
+#
+# if i > 0 and i < 10 then
+#
+# compiles to the following byte code:
+#
+# 1 000 OP_LOADI R1 0 ; R1:i
+# 2 001 OP_MOVE R2 R1 ; R1:i
+# 2 002 OP_LOADI R3 0
+# 2 003 OP_GT R2 :> 1
+# 2 004 OP_JMPNOT R2 008
+# 2 005 OP_MOVE R2 R1 ; R1:i
+# 2 006 OP_LOADI R3 10
+# 2 007 OP_LT R2 :< 1
+# 2 008 OP_JMPNOT R2 (The address of end of then part)
+#
+# When the instruction fusion the OP_GT and OP_JMPNOT you fell into the pitfalls.
+# The deleted intermediate boolean value is used in OP_JMPNOT (address 008).
+
+assert('and', '11.2.3') do
+ a = 1
+ if a > 0 and a < 10 then
+ b = 1
+ else
+ b = 0
+ end
+ assert_equal 1, b
+
+ if a < 0 and a < 10 then
+ b = 1
+ else
+ b = 0
+ end
+ assert_equal 0, b
+
+ if a < 0 and a > 10 then
+ b = 1
+ else
+ b = 0
+ end
+ assert_equal 0, b
+end
+
+assert('or','11.2.4') do
+ a = 1
+ if a > 0 or a < 10 then
+ b = 1
+ else
+ b = 0
+ end
+ assert_equal 1, b
+
+ if a < 0 or a < 10 then
+ b = 1
+ else
+ b = 0
+ end
+ assert_equal 1, b
+
+ if a < 0 or a > 10 then
+ b = 1
+ else
+ b = 0
+ end
+ assert_equal 0, b
+end
diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/literals.rb b/web/server/h2o/libh2o/deps/mruby/test/t/literals.rb new file mode 100644 index 000000000..51a37c32d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/literals.rb @@ -0,0 +1,337 @@ +## +# Literals ISO Test + +assert('Literals Numerical', '8.7.6.2') do + # signed and unsigned integer + assert_equal 1, 1 + assert_equal(-1, -1) + assert_equal(+1, +1) + # signed and unsigned float + assert_equal 1.0, 1.0 + assert_equal(-1.0, -1.0) + # binary + assert_equal 128, 0b10000000 + assert_equal 128, 0B10000000 + # octal + assert_equal 8, 0o10 + assert_equal 8, 0O10 + assert_equal 8, 0_10 + # hex + assert_equal 255, 0xff + assert_equal 255, 0Xff + # decimal + assert_equal 999, 0d999 + assert_equal 999, 0D999 + # decimal seperator + assert_equal 10000000, 10_000_000 + assert_equal 10, 1_0 + # integer with exponent + assert_equal 10.0, 1e1 + assert_equal(0.1, 1e-1) + assert_equal 10.0, 1e+1 + # float with exponent + assert_equal 10.0, 1.0e1 + assert_equal(0.1, 1.0e-1) + assert_equal 10.0, 1.0e+1 +end + +assert('Literals Strings Single Quoted', '8.7.6.3.2') do + assert_equal 'abc', 'abc' + assert_equal '\'', '\'' + assert_equal '\\', '\\' +end + +assert('Literals Strings Double Quoted', '8.7.6.3.3') do + a = "abc" + + assert_equal "abc", "abc" + assert_equal "\"", "\"" + assert_equal "\\", "\\" + assert_equal "abc", "#{a}" +end + +assert('Literals Strings Quoted Non-Expanded', '8.7.6.3.4') do + a = %q{abc} + b = %q(abc) + c = %q[abc] + d = %q<abc> + e = %q/abc/ + f = %q/ab\/c/ + g = %q{#{a}} + + assert_equal 'abc', a + assert_equal 'abc', b + assert_equal 'abc', c + assert_equal 'abc', d + assert_equal 'abc', e + assert_equal 'ab/c', f + assert_equal '#{a}', g +end + +assert('Literals Strings Quoted Expanded', '8.7.6.3.5') do + a = %Q{abc} + b = %Q(abc) + c = %Q[abc] + d = %Q<abc> + e = %Q/abc/ + f = %Q/ab\/c/ + g = %Q{#{a}} + + assert_equal 'abc', a + assert_equal 'abc', b + assert_equal 'abc', c + assert_equal 'abc', d + assert_equal 'abc', e + assert_equal 'ab/c', f + assert_equal 'abc', g +end + +assert('Literals Strings Here documents', '8.7.6.3.6') do + a = <<AAA +aaa +AAA + b = <<b_b +bbb +b_b + c = [<<CCC1, <<"CCC2", <<'CCC3'] +c1 +CCC1 +c 2 +CCC2 +c 3 +CCC3 + + d = <<DDD +d#{1+2}DDD +d\t +DDD\n +DDD + e = <<'EEE' +e#{1+2}EEE +e\t +EEE\n +EEE + f = <<"FFF" +F +FF#{"f"}FFF +F +FFF + + g = <<-GGG + ggg + GGG + h = <<-"HHH" + hhh + HHH + i = <<-'III' + iii + III + j = [<<-JJJ1 , <<-"JJJ2" , <<-'JJJ3' ] + j#{1}j + JJJ1 + j#{2}j + JJJ2 + j#{3}j + JJJ3 + + k = <<'KKK'.to_i +123 +KKK + + m = [<<MM1, <<MM2] +x#{m2 = {x:<<MM3}}y +mm3 +MM3 +mm1 +MM1 +mm2 +MM2 + + n = [1, "#{<<NN1}", 3, +nn1 +NN1 + 4] + + qqq = Proc.new {|*x| x.join(' $ ')} + q1 = qqq.call("a", <<QQ1, "c", +q +QQ1 + "d") + q2 = qqq.call("l", "m#{<<QQ2}n", +qq +QQ2 + "o") + + w = %W( 1 #{<<WWW} 3 +www +WWW + 4 5 ) + + x = [1, <<XXX1, +foo #{<<XXX2} bar +222 #{<<XXX3} 444 +333 +XXX3 +5 +XXX2 +6 +XXX1 + 9] + + z = <<'ZZZ' +ZZZ + + assert_equal "aaa\n", a + assert_equal "bbb\n", b + assert_equal ["c1\n", "c 2\n", "c 3\n"], c + assert_equal "d3DDD\nd\t\nDDD\n\n", d + assert_equal "e\#{1+2}EEE\ne\\t\nEEE\\n\n", e + assert_equal "F\nFFfFFF\nF\n", f + assert_equal " ggg\n", g + assert_equal " hhh\n", h + assert_equal " iii\n", i + assert_equal [" j1j\n", " j2j\n", " j\#{3}j\n"], j + assert_equal 123, k + assert_equal ["x{:x=>\"mm3\\n\"}y\nmm1\n", "mm2\n"], m + assert_equal ({:x=>"mm3\n"}), m2 + assert_equal [1, "nn1\n", 3, 4], n + assert_equal "a $ q\n $ c $ d", q1 + assert_equal "l $ mqq\nn $ o", q2 + assert_equal ["1", "www\n", "3", "4", "5"], w + assert_equal [1, "foo 222 333\n 444\n5\n bar\n6\n", 9], x + assert_equal "", z + +end + + +assert('Literals Array', '8.7.6.4') do + a = %W{abc#{1+2}def \}g} + b = %W(abc #{2+3} def \(g) + c = %W[#{3+4}] + d = %W< #{4+5} > + e = %W// + f = %W[[ab cd][ef]] + g = %W{ + ab + #{-1}1 + 2#{2} + } + h = %W(a\nb + test\ abc + c\ +d + x\y x\\y x\\\y) + + assert_equal ['abc3def', '}g'], a + assert_equal ['abc', '5', 'def', '(g'], b + assert_equal ['7'],c + assert_equal ['9'], d + assert_equal [], e + assert_equal ['[ab', 'cd][ef]'], f + assert_equal ['ab', '-11', '22'], g + assert_equal ["a\nb", 'test abc', "c\nd", "xy", "x\\y", "x\\y"], h + + a = %w{abc#{1+2}def \}g} + b = %w(abc #{2+3} def \(g) + c = %w[#{3+4}] + d = %w< #{4+5} > + e = %w// + f = %w[[ab cd][ef]] + g = %w{ + ab + #{-1}1 + 2#{2} + } + h = %w(a\nb + test\ abc + c\ +d + x\y x\\y x\\\y) + + assert_equal ['abc#{1+2}def', '}g'], a + assert_equal ['abc', '#{2+3}', 'def', '(g'], b + assert_equal ['#{3+4}'], c + assert_equal ['#{4+5}'], d + assert_equal [], e + assert_equal ['[ab', 'cd][ef]'], f + assert_equal ['ab', '#{-1}1', '2#{2}'], g + assert_equal ["a\\nb", "test abc", "c\nd", "x\\y", "x\\y", "x\\\\y"], h +end + + +assert('Literals Array of symbols') do + a = %I{abc#{1+2}def \}g} + b = %I(abc #{2+3} def \(g) + c = %I[#{3+4}] + d = %I< #{4+5} > + e = %I// + f = %I[[ab cd][ef]] + g = %I{ + ab + #{-1}1 + 2#{2} + } + + assert_equal [:'abc3def', :'}g'], a + assert_equal [:'abc', :'5', :'def', :'(g'], b + assert_equal [:'7'],c + assert_equal [:'9'], d + assert_equal [], e + assert_equal [:'[ab', :'cd][ef]'], f + assert_equal [:'ab', :'-11', :'22'], g + + a = %i{abc#{1+2}def \}g} + b = %i(abc #{2+3} def \(g) + c = %i[#{3+4}] + d = %i< #{4+5} > + e = %i// + f = %i[[ab cd][ef]] + g = %i{ + ab + #{-1}1 + 2#{2} + } + + assert_equal [:'abc#{1+2}def', :'}g'], a + assert_equal [:'abc', :'#{2+3}', :'def', :'(g'], b + assert_equal [:'#{3+4}'], c + assert_equal [:'#{4+5}'], d + assert_equal [] ,e + assert_equal [:'[ab', :'cd][ef]'], f + assert_equal [:'ab', :'#{-1}1', :'2#{2}'], g +end + +assert('Literals Symbol', '8.7.6.6') do + # do not compile error + :$asd + :@asd + :@@asd + :asd= + :asd! + :asd? + :+ + :+@ + :if + :BEGIN + + a = :"asd qwe" + b = :'foo bar' + c = :"a#{1+2}b" + d = %s(asd) + e = %s( foo \)) + f = %s[asd \[ +qwe] + g = %s/foo#{1+2}bar/ + h = %s{{foo bar}} + + assert_equal :'asd qwe', a + assert_equal :"foo bar", b + assert_equal :a3b, c + assert_equal :asd, d + assert_equal :' foo )', e + assert_equal :"asd [\nqwe", f + assert_equal :'foo#{1+2}bar', g + assert_equal :'{foo bar}', h +end + +# Not Implemented ATM assert('Literals Regular expression', '8.7.6.5') do diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/localjumperror.rb b/web/server/h2o/libh2o/deps/mruby/test/t/localjumperror.rb new file mode 100644 index 000000000..1780cb518 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/localjumperror.rb @@ -0,0 +1,13 @@ +## +# LocalJumpError ISO Test + +assert('LocalJumpError', '15.2.25') do + assert_equal Class, LocalJumpError.class +# assert_raise LocalJumpError do +# # this will cause an exception due to the wrong location +# retry +# end +end + +# TODO 15.2.25.2.1 LocalJumpError#exit_value +# TODO 15.2.25.2.2 LocalJumpError#reason diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/methods.rb b/web/server/h2o/libh2o/deps/mruby/test/t/methods.rb new file mode 100644 index 000000000..f9c25dc33 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/methods.rb @@ -0,0 +1,109 @@ +## +# Chapter 13.3 "Methods" ISO Test + +assert('The alias statement', '13.3.6 a) 4)') do + # check aliasing in all possible ways + + def alias_test_method_original; true; end + + alias alias_test_method_a alias_test_method_original + alias :alias_test_method_b :alias_test_method_original + + assert_true(alias_test_method_original) + assert_true(alias_test_method_a) + assert_true(alias_test_method_b) +end + +assert('The alias statement (overwrite original)', '13.3.6 a) 4)') do + # check that an aliased method can be overwritten + # without side effect + + def alias_test_method_original; true; end + + alias alias_test_method_a alias_test_method_original + alias :alias_test_method_b :alias_test_method_original + + assert_true(alias_test_method_original) + + def alias_test_method_original; false; end + + assert_false(alias_test_method_original) + assert_true(alias_test_method_a) + assert_true(alias_test_method_b) +end + +assert('The alias statement', '13.3.6 a) 5)') do + # check that alias is raising NameError if + # non-existing method should be undefined + + assert_raise(NameError) do + alias new_name_a non_existing_method + end + + assert_raise(NameError) do + alias :new_name_b :non_existing_method + end +end + +assert('The undef statement', '13.3.7 a) 4)') do + # check that undef is undefining method + # based on the method name + + def existing_method_a; true; end + def existing_method_b; true; end + def existing_method_c; true; end + def existing_method_d; true; end + def existing_method_e; true; end + def existing_method_f; true; end + + # check that methods are defined + + assert_true(existing_method_a, 'Method should be defined') + assert_true(existing_method_b, 'Method should be defined') + assert_true(existing_method_c, 'Method should be defined') + assert_true(existing_method_d, 'Method should be defined') + assert_true(existing_method_e, 'Method should be defined') + assert_true(existing_method_f, 'Method should be defined') + + # undefine in all possible ways and check that method + # is undefined + + undef existing_method_a + assert_raise(NoMethodError) do + existing_method_a + end + + undef :existing_method_b + assert_raise(NoMethodError) do + existing_method_b + end + + undef existing_method_c, existing_method_d + assert_raise(NoMethodError) do + existing_method_c + end + assert_raise(NoMethodError) do + existing_method_d + end + + undef :existing_method_e, :existing_method_f + assert_raise(NoMethodError) do + existing_method_e + end + assert_raise(NoMethodError) do + existing_method_f + end +end + +assert('The undef statement (method undefined)', '13.3.7 a) 5)') do + # check that undef is raising NameError if + # non-existing method should be undefined + + assert_raise(NameError) do + undef non_existing_method + end + + assert_raise(NameError) do + undef :non_existing_method + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/module.rb b/web/server/h2o/libh2o/deps/mruby/test/t/module.rb new file mode 100644 index 000000000..5a46c24ff --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/module.rb @@ -0,0 +1,914 @@ +## +# Module ISO Test + +def labeled_module(name, &block) + Module.new do + singleton_class.class_eval do + define_method(:to_s) { name } + alias_method :inspect, :to_s + end + class_eval(&block) if block + end +end + +def labeled_class(name, supklass = Object, &block) + Class.new(supklass) do + singleton_class.class_eval do + define_method(:to_s) { name } + alias_method :inspect, :to_s + end + class_eval(&block) if block + end +end + +assert('Module', '15.2.2') do + assert_equal Class, Module.class +end + +# TODO not implemented ATM assert('Module.constants', '15.2.2.3.1') do + +# TODO not implemented ATM assert('Module.nesting', '15.2.2.3.2') do + +assert('Module.nesting', '15.2.2.2.2') do + module Test4ModuleNesting + module Test4ModuleNesting2 + assert_equal [Test4ModuleNesting2, Test4ModuleNesting], + Module.nesting + end + end + module Test4ModuleNesting::Test4ModuleNesting2 + assert_equal [Test4ModuleNesting::Test4ModuleNesting2], Module.nesting + end +end + +assert('Module#ancestors', '15.2.2.4.9') do + class Test4ModuleAncestors + end + sc = Test4ModuleAncestors.singleton_class + r = String.ancestors + + assert_equal Array, r.class + assert_true r.include?(String) + assert_true r.include?(Object) +end + +assert('Module#append_features', '15.2.2.4.10') do + module Test4AppendFeatures + def self.append_features(mod) + Test4AppendFeatures2.const_set(:Const4AppendFeatures2, mod) + end + end + module Test4AppendFeatures2 + include Test4AppendFeatures + end + + assert_equal Test4AppendFeatures2, Test4AppendFeatures2.const_get(:Const4AppendFeatures2) +end + +assert('Module#attr NameError') do + %w[ + foo? + @foo + @@foo + $foo + ].each do |name| + module NameTest; end + + assert_raise(NameError) do + NameTest.module_eval { attr_reader name.to_sym } + end + + assert_raise(NameError) do + NameTest.module_eval { attr_writer name.to_sym } + end + + assert_raise(NameError) do + NameTest.module_eval { attr name.to_sym } + end + + assert_raise(NameError) do + NameTest.module_eval { attr_accessor name.to_sym } + end + end + +end + +assert('Module#attr', '15.2.2.4.11') do + class AttrTest + class << self + attr :cattr + def cattr_val=(val) + @cattr = val + end + end + attr :iattr + def iattr_val=(val) + @iattr = val + end + end + + test = AttrTest.new + assert_true AttrTest.respond_to?(:cattr) + assert_true test.respond_to?(:iattr) + + assert_false AttrTest.respond_to?(:cattr=) + assert_false test.respond_to?(:iattr=) + + test.iattr_val = 'test' + assert_equal 'test', test.iattr + + AttrTest.cattr_val = 'test' + assert_equal 'test', AttrTest.cattr +end + +assert('Module#attr_accessor', '15.2.2.4.12') do + class AttrTestAccessor + class << self + attr_accessor :cattr + end + attr_accessor :iattr, 'iattr2' + end + + attr_instance = AttrTestAccessor.new + assert_true AttrTestAccessor.respond_to?(:cattr=) + assert_true attr_instance.respond_to?(:iattr=) + assert_true attr_instance.respond_to?(:iattr2=) + assert_true AttrTestAccessor.respond_to?(:cattr) + assert_true attr_instance.respond_to?(:iattr) + assert_true attr_instance.respond_to?(:iattr2) + + attr_instance.iattr = 'test' + assert_equal 'test', attr_instance.iattr + + AttrTestAccessor.cattr = 'test' + assert_equal 'test', AttrTestAccessor.cattr +end + +assert('Module#attr_reader', '15.2.2.4.13') do + class AttrTestReader + class << self + attr_reader :cattr + def cattr_val=(val) + @cattr = val + end + end + attr_reader :iattr, 'iattr2' + def iattr_val=(val) + @iattr = val + end + end + + attr_instance = AttrTestReader.new + assert_true AttrTestReader.respond_to?(:cattr) + assert_true attr_instance.respond_to?(:iattr) + assert_true attr_instance.respond_to?(:iattr2) + + assert_false AttrTestReader.respond_to?(:cattr=) + assert_false attr_instance.respond_to?(:iattr=) + assert_false attr_instance.respond_to?(:iattr2=) + + attr_instance.iattr_val = 'test' + assert_equal 'test', attr_instance.iattr + + AttrTestReader.cattr_val = 'test' + assert_equal 'test', AttrTestReader.cattr +end + +assert('Module#attr_writer', '15.2.2.4.14') do + class AttrTestWriter + class << self + attr_writer :cattr + def cattr_val + @cattr + end + end + attr_writer :iattr, 'iattr2' + def iattr_val + @iattr + end + end + + attr_instance = AttrTestWriter.new + assert_true AttrTestWriter.respond_to?(:cattr=) + assert_true attr_instance.respond_to?(:iattr=) + assert_true attr_instance.respond_to?(:iattr2=) + + assert_false AttrTestWriter.respond_to?(:cattr) + assert_false attr_instance.respond_to?(:iattr) + assert_false attr_instance.respond_to?(:iattr2) + + attr_instance.iattr = 'test' + assert_equal 'test', attr_instance.iattr_val + + AttrTestWriter.cattr = 'test' + assert_equal 'test', AttrTestWriter.cattr_val +end + +assert('Module#class_eval', '15.2.2.4.15') do + class Test4ClassEval + @a = 11 + @b = 12 + end + Test4ClassEval.class_eval do + def method1 + end + end + r = Test4ClassEval.instance_methods + + assert_equal 11, Test4ClassEval.class_eval{ @a } + assert_equal 12, Test4ClassEval.class_eval{ @b } + assert_equal Array, r.class + assert_true r.include?(:method1) +end + +assert('Module#class_variable_defined?', '15.2.2.4.16') do + class Test4ClassVariableDefined + @@cv = 99 + end + + assert_true Test4ClassVariableDefined.class_variable_defined?(:@@cv) + assert_false Test4ClassVariableDefined.class_variable_defined?(:@@noexisting) +end + +assert('Module#class_variable_get', '15.2.2.4.17') do + class Test4ClassVariableGet + @@cv = 99 + end + + assert_equal 99, Test4ClassVariableGet.class_variable_get(:@@cv) +end + +assert('Module#class_variable_set', '15.2.2.4.18') do + class Test4ClassVariableSet + @@foo = 100 + def foo + @@foo + end + end + + assert_true Test4ClassVariableSet.class_variable_set(:@@cv, 99) + assert_true Test4ClassVariableSet.class_variable_set(:@@foo, 101) + assert_true Test4ClassVariableSet.class_variables.include? :@@cv + assert_equal 99, Test4ClassVariableSet.class_variable_get(:@@cv) + assert_equal 101, Test4ClassVariableSet.new.foo +end + +assert('Module#class_variables', '15.2.2.4.19') do + class Test4ClassVariables1 + @@var1 = 1 + end + class Test4ClassVariables2 < Test4ClassVariables1 + @@var2 = 2 + end + + assert_equal [:@@var1], Test4ClassVariables1.class_variables + assert_equal [:@@var2, :@@var1], Test4ClassVariables2.class_variables +end + +assert('Module#const_defined?', '15.2.2.4.20') do + module Test4ConstDefined + Const4Test4ConstDefined = true + end + + assert_true Test4ConstDefined.const_defined?(:Const4Test4ConstDefined) + assert_false Test4ConstDefined.const_defined?(:NotExisting) +end + +assert('Module#const_get', '15.2.2.4.21') do + module Test4ConstGet + Const4Test4ConstGet = 42 + end + + assert_equal 42, Test4ConstGet.const_get(:Const4Test4ConstGet) + assert_equal 42, Test4ConstGet.const_get("Const4Test4ConstGet") + assert_equal 42, Object.const_get("Test4ConstGet::Const4Test4ConstGet") + + assert_raise(TypeError){ Test4ConstGet.const_get(123) } + assert_raise(NameError){ Test4ConstGet.const_get(:I_DO_NOT_EXIST) } + assert_raise(NameError){ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") } +end + +assert('Module#const_missing', '15.2.2.4.22') do + module Test4ConstMissing + def self.const_missing(sym) + 42 # the answer to everything + end + end + + assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist) +end + +assert('Module#const_set', '15.2.2.4.23') do + module Test4ConstSet + Const4Test4ConstSet = 42 + end + + assert_true Test4ConstSet.const_set(:Const4Test4ConstSet, 23) + assert_equal 23, Test4ConstSet.const_get(:Const4Test4ConstSet) +end + +assert('Module#constants', '15.2.2.4.24') do + $n = [] + module TestA + C = 1 + end + class TestB + include TestA + C2 = 1 + $n = constants.sort + end + + assert_equal [ :C ], TestA.constants + assert_equal [ :C, :C2 ], $n +end + +assert('Module#include', '15.2.2.4.27') do + module Test4Include + Const4Include = 42 + end + module Test4Include2 + @include_result = include Test4Include + class << self + attr_reader :include_result + end + end + + assert_equal 42, Test4Include2.const_get(:Const4Include) + assert_equal Test4Include2, Test4Include2.include_result +end + +assert('Module#include?', '15.2.2.4.28') do + module Test4IncludeP + end + class Test4IncludeP2 + include Test4IncludeP + end + class Test4IncludeP3 < Test4IncludeP2 + end + + assert_true Test4IncludeP2.include?(Test4IncludeP) + assert_true Test4IncludeP3.include?(Test4IncludeP) + assert_false Test4IncludeP.include?(Test4IncludeP) +end + +assert('Module#included', '15.2.2.4.29') do + module Test4Included + Const4Included = 42 + def self.included mod + Test4Included.const_set(:Const4Included2, mod) + end + end + module Test4Included2 + include Test4Included + end + + assert_equal 42, Test4Included2.const_get(:Const4Included) + assert_equal Test4Included2, Test4Included2.const_get(:Const4Included2) +end + +assert('Module#included_modules', '15.2.2.4.30') do + module Test4includedModules + end + module Test4includedModules2 + include Test4includedModules + end + r = Test4includedModules2.included_modules + + assert_equal Array, r.class + assert_true r.include?(Test4includedModules) +end + +assert('Module#initialize', '15.2.2.4.31') do + assert_kind_of Module, Module.new + mod = Module.new { def hello; "hello"; end } + assert_equal [:hello], mod.instance_methods + a = nil + mod = Module.new { |m| a = m } + assert_equal mod, a +end + +assert('Module#instance_methods', '15.2.2.4.33') do + module Test4InstanceMethodsA + def method1() end + end + class Test4InstanceMethodsB + def method2() end + end + class Test4InstanceMethodsC < Test4InstanceMethodsB + def method3() end + end + + r = Test4InstanceMethodsC.instance_methods(true) + + assert_equal [:method1], Test4InstanceMethodsA.instance_methods + assert_equal [:method2], Test4InstanceMethodsB.instance_methods(false) + assert_equal [:method3], Test4InstanceMethodsC.instance_methods(false) + assert_equal Array, r.class + assert_true r.include?(:method3) + assert_true r.include?(:method2) +end + +assert('Module#method_defined?', '15.2.2.4.34') do + module Test4MethodDefined + module A + def method1() end + end + + class B + def method2() end + end + + class C < B + include A + def method3() end + end + end + + assert_true Test4MethodDefined::A.method_defined? :method1 + assert_true Test4MethodDefined::C.method_defined? :method1 + assert_true Test4MethodDefined::C.method_defined? "method2" + assert_true Test4MethodDefined::C.method_defined? "method3" + assert_false Test4MethodDefined::C.method_defined? "method4" +end + + +assert('Module#module_eval', '15.2.2.4.35') do + module Test4ModuleEval + @a = 11 + @b = 12 + end + + assert_equal 11, Test4ModuleEval.module_eval{ @a } + assert_equal 12, Test4ModuleEval.module_eval{ @b } +end + +assert('Module#remove_class_variable', '15.2.2.4.39') do + class Test4RemoveClassVariable + @@cv = 99 + end + + assert_equal 99, Test4RemoveClassVariable.remove_class_variable(:@@cv) + assert_false Test4RemoveClassVariable.class_variables.include? :@@cv +end + +assert('Module#remove_const', '15.2.2.4.40') do + module Test4RemoveConst + ExistingConst = 23 + end + + result = Test4RemoveConst.module_eval { remove_const :ExistingConst } + + name_error = false + begin + Test4RemoveConst.module_eval { remove_const :NonExistingConst } + rescue NameError + name_error = true + end + + # Constant removed from Module + assert_false Test4RemoveConst.const_defined? :ExistingConst + # Return value of binding + assert_equal 23, result + # Name Error raised when Constant doesn't exist + assert_true name_error +end + +assert('Module#remove_method', '15.2.2.4.41') do + module Test4RemoveMethod + class Parent + def hello + end + end + + class Child < Parent + def hello + end + end + end + + assert_true Test4RemoveMethod::Child.class_eval{ remove_method :hello } + assert_true Test4RemoveMethod::Child.instance_methods.include? :hello + assert_false Test4RemoveMethod::Child.instance_methods(false).include? :hello +end + +assert('Module#undef_method', '15.2.2.4.42') do + module Test4UndefMethod + class Parent + def hello + end + end + + class Child < Parent + def hello + end + end + + class GrandChild < Child + end + end + Test4UndefMethod::Child.class_eval{ undef_method :hello } + + assert_true Test4UndefMethod::Parent.new.respond_to?(:hello) + assert_false Test4UndefMethod::Child.new.respond_to?(:hello) + assert_false Test4UndefMethod::GrandChild.new.respond_to?(:hello) + assert_false Test4UndefMethod::Child.instance_methods(false).include? :hello +end + +# Not ISO specified + +assert('Module#define_method') do + c = Class.new { + define_method(:m1) { :ok } + define_method(:m2, Proc.new { :ok }) + } + assert_equal c.new.m1, :ok + assert_equal c.new.m2, :ok + assert_raise(TypeError) do + Class.new { define_method(:n1, nil) } + end +end + +# @!group prepend + assert('Module#prepend') do + module M0 + def m1; [:M0] end + end + module M1 + def m1; [:M1, super, :M1] end + end + module M2 + def m1; [:M2, super, :M2] end + end + M3 = Module.new do + def m1; [:M3, super, :M3] end + end + module M4 + def m1; [:M4, super, :M4] end + end + + class P0 + include M0 + prepend M1 + def m1; [:C0, super, :C0] end + end + class P1 < P0 + prepend M2, M3 + include M4 + def m1; [:C1, super, :C1] end + end + + obj = P1.new + expected = [:M2,[:M3,[:C1,[:M4,[:M1,[:C0,[:M0],:C0],:M1],:M4],:C1],:M3],:M2] + assert_equal(expected, obj.m1) + end + + assert('Module#prepend result') do + module TestPrepended; end + module TestPrependResult + @prepend_result = prepend TestPrepended + class << self + attr_reader :prepend_result + end + end + + assert_equal TestPrependResult, TestPrependResult.prepend_result + end + + # mruby shouldn't be affected by this since there is + # no visibility control (yet) + assert('Module#prepend public') do + assert_nothing_raised('ruby/ruby #8846') do + Class.new.prepend(Module.new) + end + end + + assert('Module#prepend inheritance') do + bug6654 = '[ruby-core:45914]' + a = labeled_module('a') + b = labeled_module('b') { include a } + c = labeled_module('c') { prepend b } + + #assert bug6654 do + # the Module#< operator should be used here instead, but we don't have it + assert_include(c.ancestors, a) + assert_include(c.ancestors, b) + #end + + bug8357 = '[ruby-core:54736] [Bug #8357]' + b = labeled_module('b') { prepend a } + c = labeled_class('c') { include b } + + #assert bug8357 do + # the Module#< operator should be used here instead, but we don't have it + assert_include(c.ancestors, a) + assert_include(c.ancestors, b) + #end + + bug8357 = '[ruby-core:54742] [Bug #8357]' + assert_kind_of(b, c.new, bug8357) + end + + assert('Moduler#prepend + #instance_methods') do + bug6655 = '[ruby-core:45915]' + assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655) + end + + assert 'Module#prepend + #singleton_methods' do + o = Object.new + o.singleton_class.class_eval {prepend Module.new} + assert_equal([], o.singleton_methods) + end + + assert 'Module#prepend + #remove_method' do + c = Class.new do + prepend Module.new { def foo; end } + end + assert_raise(NameError) do + c.class_eval do + remove_method(:foo) + end + end + c.class_eval do + def foo; end + end + removed = nil + c.singleton_class.class_eval do + define_method(:method_removed) {|id| removed = id} + end + assert_nothing_raised('[Bug #7843]') do + c.class_eval do + remove_method(:foo) + end + end + assert_equal(:foo, removed) + end + + assert 'Module#prepend + Class#ancestors' do + bug6658 = '[ruby-core:45919]' + m = labeled_module("m") + c = labeled_class("c") {prepend m} + assert_equal([m, c], c.ancestors[0, 2], bug6658) + + bug6662 = '[ruby-dev:45868]' + c2 = labeled_class("c2", c) + anc = c2.ancestors + assert_equal([c2, m, c, Object], anc[0..anc.index(Object)], bug6662) + end + + assert 'Module#prepend + Module#ancestors' do + bug6659 = '[ruby-dev:45861]' + m0 = labeled_module("m0") { def x; [:m0, *super] end } + m1 = labeled_module("m1") { def x; [:m1, *super] end; prepend m0 } + m2 = labeled_module("m2") { def x; [:m2, *super] end; prepend m1 } + c0 = labeled_class("c0") { def x; [:c0] end } + c1 = labeled_class("c1") { def x; [:c1] end; prepend m2 } + c2 = labeled_class("c2", c0) { def x; [:c2, *super] end; include m2 } + # + assert_equal([m0, m1], m1.ancestors, bug6659) + # + bug6662 = '[ruby-dev:45868]' + assert_equal([m0, m1, m2], m2.ancestors, bug6662) + assert_equal([m0, m1, m2, c1], c1.ancestors[0, 4], bug6662) + assert_equal([:m0, :m1, :m2, :c1], c1.new.x) + assert_equal([c2, m0, m1, m2, c0], c2.ancestors[0, 5], bug6662) + assert_equal([:c2, :m0, :m1, :m2, :c0], c2.new.x) + # + m3 = labeled_module("m3") { include m1; prepend m1 } + assert_equal([m3, m0, m1], m3.ancestors) + m3 = labeled_module("m3") { prepend m1; include m1 } + assert_equal([m0, m1, m3], m3.ancestors) + m3 = labeled_module("m3") { prepend m1; prepend m1 } + assert_equal([m0, m1, m3], m3.ancestors) + m3 = labeled_module("m3") { include m1; include m1 } + assert_equal([m3, m0, m1], m3.ancestors) + end + + assert 'Module#prepend #instance_methods(false)' do + bug6660 = '[ruby-dev:45863]' + assert_equal([:m1], Class.new{ prepend Module.new; def m1; end }.instance_methods(false), bug6660) + assert_equal([:m1], Class.new(Class.new{def m2;end}){ prepend Module.new; def m1; end }.instance_methods(false), bug6660) + end + + assert 'cyclic Module#prepend' do + bug7841 = '[ruby-core:52205] [Bug #7841]' + m1 = Module.new + m2 = Module.new + m1.instance_eval { prepend(m2) } + assert_raise(ArgumentError, bug7841) do + m2.instance_eval { prepend(m1) } + end + end + + # these assertions will not run without a #assert_seperately method + #assert 'test_prepend_optmethod' do + # bug7983 = '[ruby-dev:47124] [Bug #7983]' + # assert_separately [], %{ + # module M + # def /(other) + # to_f / other + # end + # end + # Fixnum.send(:prepend, M) + # assert_equal(0.5, 1 / 2, "#{bug7983}") + # } + # assert_equal(0, 1 / 2) + #end + + # mruby has no visibility control + assert 'Module#prepend visibility' do + bug8005 = '[ruby-core:53106] [Bug #8005]' + c = Class.new do + prepend Module.new {} + def foo() end + protected :foo + end + a = c.new + assert_true a.respond_to?(:foo), bug8005 + assert_nothing_raised(bug8005) {a.send :foo} + end + + # mruby has no visibility control + assert 'Module#prepend inherited visibility' do + bug8238 = '[ruby-core:54105] [Bug #8238]' + module Test4PrependVisibilityInherited + class A + def foo() A; end + private :foo + end + class B < A + public :foo + prepend Module.new + end + end + assert_equal(Test4PrependVisibilityInherited::A, Test4PrependVisibilityInherited::B.new.foo, "#{bug8238}") + end + + assert 'Module#prepend + #included_modules' do + bug8025 = '[ruby-core:53158] [Bug #8025]' + mixin = labeled_module("mixin") + c = labeled_module("c") {prepend mixin} + im = c.included_modules + assert_not_include(im, c, bug8025) + assert_include(im, mixin, bug8025) + c1 = labeled_class("c1") {prepend mixin} + c2 = labeled_class("c2", c1) + im = c2.included_modules + assert_not_include(im, c1, bug8025) + assert_not_include(im, c2, bug8025) + assert_include(im, mixin, bug8025) + end + + assert 'Module#prepend super in alias' do + skip "super does not currently work in aliased methods" + bug7842 = '[Bug #7842]' + + p = labeled_module("P") do + def m; "P"+super; end + end + + a = labeled_class("A") do + def m; "A"; end + end + + b = labeled_class("B", a) do + def m; "B"+super; end + alias m2 m + prepend p + alias m3 m + end + + assert_nothing_raised do + assert_equal("BA", b.new.m2, bug7842) + end + + assert_nothing_raised do + assert_equal("PBA", b.new.m3, bug7842) + end + end + + assert 'Module#prepend each class' do + m = labeled_module("M") + c1 = labeled_class("C1") {prepend m} + c2 = labeled_class("C2", c1) {prepend m} + assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should be able to prepend each class") + end + + assert 'Module#prepend no duplication' do + m = labeled_module("M") + c = labeled_class("C") {prepend m; prepend m} + assert_equal([m, c], c.ancestors[0, 2], "should never duplicate") + end + + assert 'Module#prepend in superclass' do + m = labeled_module("M") + c1 = labeled_class("C1") + c2 = labeled_class("C2", c1) {prepend m} + c1.class_eval {prepend m} + assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should accesisble prepended module in superclass") + end + + # requires #assert_seperately + #assert 'Module#prepend call super' do + # assert_separately([], <<-'end;') #do + # bug10847 = '[ruby-core:68093] [Bug #10847]' + # module M; end + # Float.prepend M + # assert_nothing_raised(SystemStackError, bug10847) do + # 0.3.numerator + # end + # end; + #end +# @!endgroup prepend + +assert('Module#to_s') do + module Outer + class Inner; end + const_set :SetInner, Class.new + end + + assert_equal 'Outer', Outer.to_s + assert_equal 'Outer::Inner', Outer::Inner.to_s + assert_equal 'Outer::SetInner', Outer::SetInner.to_s + + outer = Module.new do + const_set :SetInner, Class.new + end + Object.const_set :SetOuter, outer + + assert_equal 'SetOuter', SetOuter.to_s + assert_equal 'SetOuter::SetInner', SetOuter::SetInner.to_s + + mod = Module.new + cls = Class.new + + assert_equal "#<Module:0x", mod.to_s[0,11] + assert_equal "#<Class:0x", cls.to_s[0,10] +end + +assert('Module#inspect') do + module Test4to_sModules + end + + assert_equal 'Test4to_sModules', Test4to_sModules.inspect +end + +assert('Issue 1467') do + module M1 + def initialize() + super() + end + end + + class C1 + include M1 + def initialize() + super() + end + end + + class C2 + include M1 + end + + C1.new + C2.new +end + +assert('clone Module') do + module M1 + def foo + true + end + end + + class B + include M1.clone + end + + B.new.foo +end + +assert('Module#module_function') do + module M + def modfunc; end + module_function :modfunc + end + + assert_true M.respond_to?(:modfunc) +end + +assert('module with non-class/module outer raises TypeError') do + assert_raise(TypeError) { module 0::M1 end } + assert_raise(TypeError) { module []::M2 end } +end + +assert('get constant of parent module in singleton class; issue #3568') do + actual = module GetConstantInSingletonTest + EXPECTED = "value" + class << self + EXPECTED + end + end + + assert_equal("value", actual) +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/nameerror.rb b/web/server/h2o/libh2o/deps/mruby/test/t/nameerror.rb new file mode 100644 index 000000000..28682bedc --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/nameerror.rb @@ -0,0 +1,28 @@ +## +# NameError ISO Test + +assert('NameError', '15.2.31') do + assert_equal Class, NameError.class +end + +assert('NameError#name', '15.2.31.2.1') do + + # This check is not duplicate with 15.2.31.2.2 check. + # Because the NameError in this test is generated in + # C API. + class TestDummy + alias foo bar + rescue NameError => e + $test_dummy_result = e.name + end + + assert_equal :bar, $test_dummy_result +end + +assert('NameError#initialize', '15.2.31.2.2') do + e = NameError.new('a', :foo) + + assert_equal NameError, e.class + assert_equal 'a', e.message + assert_equal :foo, e.name +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/nil.rb b/web/server/h2o/libh2o/deps/mruby/test/t/nil.rb new file mode 100644 index 000000000..b49878fc1 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/nil.rb @@ -0,0 +1,39 @@ +## +# NilClass ISO Test + +assert('NilClass', '15.2.4') do + assert_equal Class, NilClass.class +end + +assert('NilClass', '15.2.4.1') do + assert_equal NilClass, nil.class + assert_false NilClass.method_defined? :new +end + +assert('NilClass#&', '15.2.4.3.1') do + assert_false nil.&(true) + assert_false nil.&(nil) +end + +assert('NilClass#^', '15.2.4.3.2') do + assert_true nil.^(true) + assert_false nil.^(false) +end + +assert('NilClass#|', '15.2.4.3.3') do + assert_true nil.|(true) + assert_false nil.|(false) +end + +assert('NilClass#nil?', '15.2.4.3.4') do + assert_true nil.nil? +end + +assert('NilClass#to_s', '15.2.4.3.5') do + assert_equal '', nil.to_s +end + +assert('safe navigation') do + assert_nil nil&.size + assert_equal 0, []&.size +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/nomethoderror.rb b/web/server/h2o/libh2o/deps/mruby/test/t/nomethoderror.rb new file mode 100644 index 000000000..5fed79689 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/nomethoderror.rb @@ -0,0 +1,22 @@ +## +# NoMethodError ISO Test + +assert('NoMethodError', '15.2.32') do + NoMethodError.class == Class + assert_raise NoMethodError do + doesNotExistAsAMethodNameForVerySure("") + end +end + +assert('NoMethodError#args', '15.2.32.2.1') do + a = NoMethodError.new 'test', :test, [1, 2] + assert_equal [1, 2], a.args + + assert_nothing_raised do + begin + doesNotExistAsAMethodNameForVerySure 3, 1, 4 + rescue NoMethodError => e + assert_equal [3, 1, 4], e.args + end + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/numeric.rb b/web/server/h2o/libh2o/deps/mruby/test/t/numeric.rb new file mode 100644 index 000000000..120cc960d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/numeric.rb @@ -0,0 +1,43 @@ +## +# Numeric ISO Test + +assert('Numeric', '15.2.7') do + assert_equal Class, Numeric.class +end + +assert('Numeric#+@', '15.2.7.4.1') do + assert_equal(+1, +1) +end + +assert('Numeric#-@', '15.2.7.4.2') do + assert_equal(-1, -1) +end + +assert('Numeric#abs', '15.2.7.4.3') do + assert_equal(1, 1.abs) + assert_equal(1.0, -1.abs) +end + +assert('Numeric#pow') do + assert_equal(8, 2 ** 3) + assert_equal(-8, -2 ** 3) + assert_equal(1, 2 ** 0) + assert_equal(1, 2.2 ** 0) + assert_equal(0.5, 2 ** -1) +end + +assert('Numeric#/', '15.2.8.3.4') do + n = Class.new(Numeric){ def /(x); 15.1;end }.new + + assert_equal(2, 10/5) + assert_equal(0.0625, 1/16) + assert_equal(15.1, n/10) + assert_raise(TypeError){ 1/n } + assert_raise(TypeError){ 1/nil } +end + +# Not ISO specified + +assert('Numeric#**') do + assert_equal 8.0, 2.0**3 +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/object.rb b/web/server/h2o/libh2o/deps/mruby/test/t/object.rb new file mode 100644 index 000000000..6a755d3ba --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/object.rb @@ -0,0 +1,11 @@ +## +# Object ISO Test + +assert('Object', '15.2.1') do + assert_equal Class, Object.class +end + +assert('Object superclass', '15.2.1.2') do + assert_equal BasicObject, Object.superclass +end + diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/proc.rb b/web/server/h2o/libh2o/deps/mruby/test/t/proc.rb new file mode 100644 index 000000000..42ac3b941 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/proc.rb @@ -0,0 +1,180 @@ +## +# Proc ISO Test + +assert('Proc', '15.2.17') do + assert_equal Class, Proc.class +end + +assert('Proc.new', '15.2.17.3.1') do + assert_raise ArgumentError do + Proc.new + end + + assert_equal (Proc.new {}).class, Proc + + assert_raise LocalJumpError do + Proc.new{ break }.call + end +end + +assert('Proc#[]', '15.2.17.4.1') do + a = 0 + b = Proc.new { a += 1 } + b.[] + + a2 = 0 + b2 = Proc.new { |i| a2 += i } + b2.[](5) + + assert_equal 1, a + assert_equal 5, a2 +end + +assert('Proc#arity', '15.2.17.4.2') do + a = Proc.new {|x, y|}.arity + b = Proc.new {|x, *y, z|}.arity + c = Proc.new {|x=0, y|}.arity + d = Proc.new {|(x, y), z=0|}.arity + + assert_equal 2, a + assert_equal(-3, b) + assert_equal 1, c + assert_equal 1, d + + e = ->(x=0, y){}.arity + f = ->((x, y), z=0){}.arity + g = ->(x=0){}.arity + + assert_equal(-2, e) + assert_equal(-2, f) + assert_equal(-1, g) +end + +assert('Proc#call', '15.2.17.4.3') do + a = 0 + b = Proc.new { a += 1 } + b.call + + a2 = 0 + b2 = Proc.new { |i| a2 += i } + b2.call(5) + + assert_equal 1, a + assert_equal 5, a2 +end + +assert('Proc#call proc args pos block') do + pr = Proc.new {|a,b,&c| + [a, b, c.class, c&&c.call(:x)] + } + assert_equal [nil, nil, Proc, :proc], (pr.call(){ :proc }) + assert_equal [1, nil, Proc, :proc], (pr.call(1){ :proc }) + assert_equal [1, 2, Proc, :proc], (pr.call(1, 2){ :proc }) + assert_equal [1, 2, Proc, :proc], (pr.call(1, 2, 3){ :proc }) + assert_equal [1, 2, Proc, :proc], (pr.call(1, 2, 3, 4){ :proc }) + + assert_equal [nil, nil, Proc, :x], (pr.call(){|x| x}) + assert_equal [1, nil, Proc, :x], (pr.call(1){|x| x}) + assert_equal [1, 2, Proc, :x], (pr.call(1, 2){|x| x}) + assert_equal [1, 2, Proc, :x], (pr.call(1, 2, 3){|x| x}) + assert_equal [1, 2, Proc, :x], (pr.call(1, 2, 3, 4){|x| x}) +end + +assert('Proc#call proc args pos rest post') do + pr = Proc.new {|a,b,*c,d,e| + [a,b,c,d,e] + } + assert_equal [nil, nil, [], nil, nil], pr.call() + assert_equal [1, nil, [], nil, nil], pr.call(1) + assert_equal [1, 2, [], nil, nil], pr.call(1,2) + assert_equal [1, 2, [], 3, nil], pr.call(1,2,3) + assert_equal [1, 2, [], 3, 4], pr.call(1,2,3,4) + assert_equal [1, 2, [3], 4, 5], pr.call(1,2,3,4,5) + assert_equal [1, 2, [3, 4], 5, 6], pr.call(1,2,3,4,5,6) + assert_equal [1, 2, [3, 4, 5], 6,7], pr.call(1,2,3,4,5,6,7) + + assert_equal [nil, nil, [], nil, nil], pr.call([]) + assert_equal [1, nil, [], nil, nil], pr.call([1]) + assert_equal [1, 2, [], nil, nil], pr.call([1,2]) + assert_equal [1, 2, [], 3, nil], pr.call([1,2,3]) + assert_equal [1, 2, [], 3, 4], pr.call([1,2,3,4]) + assert_equal [1, 2, [3], 4, 5], pr.call([1,2,3,4,5]) + assert_equal [1, 2, [3, 4], 5, 6], pr.call([1,2,3,4,5,6]) + assert_equal [1, 2, [3, 4, 5], 6,7], pr.call([1,2,3,4,5,6,7]) +end + +assert('Proc#return_does_not_break_self') do + class TestClass + attr_accessor :block + def initialize + end + def return_array + @block = Proc.new { self } + return [] + end + def return_instance_variable + @block = Proc.new { self } + return @block + end + def return_const_fixnum + @block = Proc.new { self } + return 123 + end + def return_nil + @block = Proc.new { self } + return nil + end + end + + c = TestClass.new + assert_equal [], c.return_array + assert_equal c, c.block.call + + c.return_instance_variable + assert_equal c, c.block.call + + assert_equal 123, c.return_const_fixnum + assert_equal c, c.block.call + + assert_equal nil, c.return_nil + assert_equal c, c.block.call +end + +assert('call Proc#initialize if defined') do + a = [] + c = Class.new(Proc) do + define_method(:initialize) do + a << :ok + end + end + + assert_kind_of c, c.new{} + assert_equal [:ok], a +end + +assert('&obj call to_proc if defined') do + pr = Proc.new{} + def mock(&b) + b + end + assert_equal pr.object_id, mock(&pr).object_id + assert_equal pr, mock(&pr) + + obj = Object.new + def obj.to_proc + Proc.new{ :from_to_proc } + end + assert_equal :from_to_proc, mock(&obj).call + + assert_raise(TypeError){ mock(&(Object.new)) } +end + +assert('Creation of a proc through the block of a method') do + def m(&b) b end + + assert_equal m{}.class, Proc + + assert_raise LocalJumpError do + m{ break }.call + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/range.rb b/web/server/h2o/libh2o/deps/mruby/test/t/range.rb new file mode 100644 index 000000000..5391369de --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/range.rb @@ -0,0 +1,95 @@ +## +# Range ISO Test + +assert('Range', '15.2.14') do + assert_equal Class, Range.class +end + +assert('Range#==', '15.2.14.4.1') do + assert_true (1..10) == (1..10) + assert_false (1..10) == (1..100) + assert_true (1..10) == Range.new(1.0, 10.0) +end + +assert('Range#===', '15.2.14.4.2') do + a = (1..10) + + assert_true a === 5 + assert_false a === 20 +end + +assert('Range#begin', '15.2.14.4.3') do + assert_equal 1, (1..10).begin +end + +assert('Range#each', '15.2.14.4.4') do + a = (1..3) + b = 0 + a.each {|i| b += i} + assert_equal 6, b +end + +assert('Range#end', '15.2.14.4.5') do + assert_equal 10, (1..10).end +end + +assert('Range#exclude_end?', '15.2.14.4.6') do + assert_true (1...10).exclude_end? + assert_false (1..10).exclude_end? +end + +assert('Range#first', '15.2.14.4.7') do + assert_equal 1, (1..10).first +end + +assert('Range#include?', '15.2.14.4.8') do + assert_true (1..10).include?(10) + assert_false (1..10).include?(11) + + assert_true (1...10).include?(9) + assert_false (1...10).include?(10) +end + +assert('Range#initialize', '15.2.14.4.9') do + a = Range.new(1, 10, true) + b = Range.new(1, 10, false) + + assert_equal (1...10), a + assert_true a.exclude_end? + assert_equal (1..10), b + assert_false b.exclude_end? + + assert_raise(NameError) { (0..1).send(:initialize, 1, 3) } +end + +assert('Range#last', '15.2.14.4.10') do + assert_equal 10, (1..10).last +end + +assert('Range#member?', '15.2.14.4.11') do + a = (1..10) + + assert_true a.member?(5) + assert_false a.member?(20) +end + +assert('Range#to_s', '15.2.14.4.12') do + assert_equal "0..1", (0..1).to_s + assert_equal "0...1", (0...1).to_s + assert_equal "a..b", ("a".."b").to_s + assert_equal "a...b", ("a"..."b").to_s +end + +assert('Range#inspect', '15.2.14.4.13') do + assert_equal "0..1", (0..1).inspect + assert_equal "0...1", (0...1).inspect + assert_equal "\"a\"..\"b\"", ("a".."b").inspect + assert_equal "\"a\"...\"b\"", ("a"..."b").inspect +end + +assert('Range#eql?', '15.2.14.4.14') do + assert_true (1..10).eql? (1..10) + assert_false (1..10).eql? (1..100) + assert_false (1..10).eql? (Range.new(1.0, 10.0)) + assert_false (1..10).eql? "1..10" +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/rangeerror.rb b/web/server/h2o/libh2o/deps/mruby/test/t/rangeerror.rb new file mode 100644 index 000000000..97878096e --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/rangeerror.rb @@ -0,0 +1,6 @@ +## +# RangeError ISO Test + +assert('RangeError', '15.2.26') do + assert_equal Class, RangeError.class +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/regexperror.rb b/web/server/h2o/libh2o/deps/mruby/test/t/regexperror.rb new file mode 100644 index 000000000..b8f8c2c1f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/regexperror.rb @@ -0,0 +1,4 @@ +## +# RegexpError ISO Test + +# TODO broken ATM assert('RegexpError', '15.2.27') do diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/runtimeerror.rb b/web/server/h2o/libh2o/deps/mruby/test/t/runtimeerror.rb new file mode 100644 index 000000000..d02cba96d --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/runtimeerror.rb @@ -0,0 +1,6 @@ +## +# RuntimeError ISO Test + +assert('RuntimeError', '15.2.28') do + assert_equal Class, RuntimeError.class +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/standarderror.rb b/web/server/h2o/libh2o/deps/mruby/test/t/standarderror.rb new file mode 100644 index 000000000..c349b08cf --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/standarderror.rb @@ -0,0 +1,6 @@ +## +# StandardError ISO Test + +assert('StandardError', '15.2.23') do + assert_equal Class, StandardError.class +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/string.rb b/web/server/h2o/libh2o/deps/mruby/test/t/string.rb new file mode 100644 index 000000000..a4139622a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/string.rb @@ -0,0 +1,727 @@ +# coding: utf-8 +## +# String ISO Test + +UTF8STRING = ("\343\201\202".size == 1) + +assert('String', '15.2.10') do + assert_equal Class, String.class +end + +assert('String#<=>', '15.2.10.5.1') do + a = '' <=> '' + b = '' <=> 'not empty' + c = 'not empty' <=> '' + d = 'abc' <=> 'cba' + e = 'cba' <=> 'abc' + + assert_equal 0, a + assert_equal(-1, b) + assert_equal 1, c + assert_equal(-1, d) + assert_equal 1, e +end + +assert('String#==', '15.2.10.5.2') do + assert_equal 'abc', 'abc' + assert_not_equal 'abc', 'cba' +end + +# 'String#=~', '15.2.10.5.3' will be tested in mrbgems. + +assert('String#+', '15.2.10.5.4') do + assert_equal 'ab', 'a' + 'b' +end + +assert('String#*', '15.2.10.5.5') do + assert_equal 'aaaaa', 'a' * 5 + assert_equal '', 'a' * 0 + assert_raise(ArgumentError) do + 'a' * -1 + end +end + +assert('String#[]', '15.2.10.5.6') do + # length of args is 1 + a = 'abc'[0] + b = 'abc'[-1] + c = 'abc'[10] + d = 'abc'[-10] + e = 'abc'[1.1] + + # length of args is 2 + a1 = 'abc'[0, -1] + b1 = 'abc'[10, 0] + c1 = 'abc'[-10, 0] + d1 = 'abc'[0, 0] + e1 = 'abc'[1, 2] + + # args is RegExp + # It will be tested in mrbgems. + + # args is String + a3 = 'abc'['bc'] + b3 = 'abc'['XX'] + + assert_equal 'a', 'a' + # assert_equal 'c', b + # assert_nil c + # assert_nil d + # assert_equal 'b', e + # assert_nil a1 + # assert_nil b1 + # assert_nil c1 + # assert_equal '', d1 + # assert_equal 'bc', e1 + # assert_equal 'bc', a3 + # assert_nil b3 + + # assert_raise(TypeError) do + # a[nil] + # end +end + +assert('String#[](UTF-8)', '15.2.10.5.6') do + assert_equal "ち", "こんにちは世界"[3] + assert_equal nil, "こんにちは世界"[20] + assert_equal "世", "こんにちは世界"[-2] + assert_equal "世界", "こんにちは世界"[-2..-1] + assert_equal "んに", "こんにちは世界"[1,2] + assert_equal "世", "こんにちは世界"["世"] +end if UTF8STRING + +assert('String#[] with Range') do + a1 = 'abc'[1..0] + b1 = 'abc'[1..1] + c1 = 'abc'[1..2] + d1 = 'abc'[1..3] + e1 = 'abc'[1..4] + f1 = 'abc'[0..-2] + g1 = 'abc'[-2..3] + h1 = 'abc'[3..4] + i1 = 'abc'[4..5] + j1 = 'abcdefghijklmnopqrstuvwxyz'[1..3] + a2 = 'abc'[1...0] + b2 = 'abc'[1...1] + c2 = 'abc'[1...2] + d2 = 'abc'[1...3] + e2 = 'abc'[1...4] + f2 = 'abc'[0...-2] + g2 = 'abc'[-2...3] + h2 = 'abc'[3...4] + i2 = 'abc'[4...5] + j2 = 'abcdefghijklmnopqrstuvwxyz'[1...3] + + assert_equal '', a1 + assert_equal 'b', b1 + assert_equal 'bc', c1 + assert_equal 'bc', d1 + assert_equal 'bc', e1 + assert_equal 'ab', f1 + assert_equal 'bc', g1 + assert_equal '', h1 + assert_nil i2 + assert_equal 'bcd', j1 + assert_equal '', a2 + assert_equal '', b2 + assert_equal 'b', c2 + assert_equal 'bc', d2 + assert_equal 'bc', e2 + assert_equal 'a', f2 + assert_equal 'bc', g2 + assert_equal '', h2 + assert_nil i2 + assert_equal 'bc', j2 +end + +assert('String#[]=') do + # length of args is 1 + a = 'abc' + a[0] = 'X' + assert_equal 'Xbc', a + + b = 'abc' + b[-1] = 'X' + assert_equal 'abX', b + + c = 'abc' + assert_raise(IndexError) do + c[10] = 'X' + end + + d = 'abc' + assert_raise(IndexError) do + d[-10] = 'X' + end + + e = 'abc' + e[1.1] = 'X' + assert_equal 'aXc', e + + + # length of args is 2 + a1 = 'abc' + assert_raise(IndexError) do + a1[0, -1] = 'X' + end + + b1 = 'abc' + assert_raise(IndexError) do + b1[10, 0] = 'X' + end + + c1 = 'abc' + assert_raise(IndexError) do + c1[-10, 0] = 'X' + end + + d1 = 'abc' + d1[0, 0] = 'X' + assert_equal 'Xabc', d1 + + e1 = 'abc' + e1[1, 3] = 'X' + assert_equal 'aX', e1 + + # args is RegExp + # It will be tested in mrbgems. + + # args is String + a3 = 'abc' + a3['bc'] = 'X' + assert_equal a3, 'aX' + + b3 = 'abc' + assert_raise(IndexError) do + b3['XX'] = 'Y' + end +end + +assert('String#capitalize', '15.2.10.5.7') do + a = 'abc' + a.capitalize + + assert_equal 'abc', a + assert_equal 'Abc', 'abc'.capitalize +end + +assert('String#capitalize!', '15.2.10.5.8') do + a = 'abc' + a.capitalize! + + assert_equal 'Abc', a + assert_equal nil, 'Abc'.capitalize! +end + +assert('String#chomp', '15.2.10.5.9') do + a = 'abc'.chomp + b = ''.chomp + c = "abc\n".chomp + d = "abc\n\n".chomp + e = "abc\t".chomp("\t") + f = "abc\n" + + f.chomp + + assert_equal 'abc', a + assert_equal '', b + assert_equal 'abc', c + assert_equal "abc\n", d + assert_equal 'abc', e + assert_equal "abc\n", f +end + +assert('String#chomp!', '15.2.10.5.10') do + a = 'abc' + b = '' + c = "abc\n" + d = "abc\n\n" + e = "abc\t" + + a.chomp! + b.chomp! + c.chomp! + d.chomp! + e.chomp!("\t") + + assert_equal 'abc', a + assert_equal '', b + assert_equal 'abc', c + assert_equal "abc\n", d + assert_equal 'abc', e +end + +assert('String#chomp! uses the correct length') do + class A + def to_str + $s.replace("AA") + "A" + end + end + + $s = "AAA" + $s.chomp!(A.new) + assert_equal $s, "A" +end + +assert('String#chop', '15.2.10.5.11') do + a = ''.chop + b = 'abc'.chop + c = 'abc' + + c.chop + + assert_equal '', a + assert_equal 'ab', b + assert_equal 'abc', c +end + +assert('String#chop(UTF-8)', '15.2.10.5.11') do + a = ''.chop + b = 'あいう'.chop + c = "あ\nい".chop.chop + + assert_equal '', a + assert_equal 'あい', b + assert_equal 'あ', c +end if UTF8STRING + +assert('String#chop!', '15.2.10.5.12') do + a = '' + b = 'abc' + + a.chop! + b.chop! + + assert_equal a, '' + assert_equal b, 'ab' +end + +assert('String#chop!(UTF-8)', '15.2.10.5.12') do + a = '' + b = "あいうえ\n" + c = "あいうえ\n" + + a.chop! + b.chop! + c.chop! + c.chop! + + assert_equal a, '' + assert_equal b, 'あいうえ' + assert_equal c, 'あいう' +end if UTF8STRING + +assert('String#downcase', '15.2.10.5.13') do + a = 'ABC'.downcase + b = 'ABC' + + b.downcase + + assert_equal 'abc', a + assert_equal 'ABC', b +end + +assert('String#downcase!', '15.2.10.5.14') do + a = 'ABC' + + a.downcase! + + assert_equal 'abc', a + assert_equal nil, 'abc'.downcase! +end + +assert('String#each_line', '15.2.10.5.15') do + a = "first line\nsecond line\nthird line" + list = ["first line\n", "second line\n", "third line"] + n_list = [] + + a.each_line do |line| + n_list << line + end + + assert_equal list, n_list + + n_list.clear + a.each_line("li") do |line| + n_list << line + end + assert_equal ["first li", "ne\nsecond li", "ne\nthird li", "ne"], n_list +end + +assert('String#empty?', '15.2.10.5.16') do + a = '' + b = 'not empty' + + assert_true a.empty? + assert_false b.empty? +end + +assert('String#eql?', '15.2.10.5.17') do + assert_true 'abc'.eql?('abc') + assert_false 'abc'.eql?('cba') +end + +assert('String#gsub', '15.2.10.5.18') do + assert_equal('aBcaBc', 'abcabc'.gsub('b', 'B'), 'gsub without block') + assert_equal('aBcaBc', 'abcabc'.gsub('b'){|w| w.capitalize }, 'gsub with block') + assert_equal('$a$a$', '#a#a#'.gsub('#', '$'), 'mruby/mruby#847') + assert_equal('$a$a$', '#a#a#'.gsub('#'){|w| '$' }, 'mruby/mruby#847 with block') + assert_equal('$$a$$', '##a##'.gsub('##', '$$'), 'mruby/mruby#847 another case') + assert_equal('$$a$$', '##a##'.gsub('##'){|w| '$$' }, 'mruby/mruby#847 another case with block') + assert_equal('A', 'a'.gsub('a', 'A')) + assert_equal('A', 'a'.gsub('a'){|w| w.capitalize }) + assert_equal("<a><><>", 'a'.gsub('a', '<\0><\1><\2>')) + assert_equal(".h.e.l.l.o.", "hello".gsub("", ".")) + a = [] + assert_equal(".h.e.l.l.o.", "hello".gsub("") { |i| a << i; "." }) + assert_equal(["", "", "", "", "", ""], a) + assert_raise(ArgumentError) { "".gsub } + assert_raise(ArgumentError) { "".gsub("", "", "") } +end + +assert('String#gsub with backslash') do + s = 'abXcdXef' + assert_equal 'ab<\\>cd<\\>ef', s.gsub('X', '<\\\\>') + assert_equal 'ab<X>cd<X>ef', s.gsub('X', '<\\&>') + assert_equal 'ab<X>cd<X>ef', s.gsub('X', '<\\0>') + assert_equal 'ab<ab>cd<abXcd>ef', s.gsub('X', '<\\`>') + assert_equal 'ab<cdXef>cd<ef>ef', s.gsub('X', '<\\\'>') +end + +assert('String#gsub!', '15.2.10.5.19') do + a = 'abcabc' + a.gsub!('b', 'B') + + b = 'abcabc' + b.gsub!('b') { |w| w.capitalize } + + assert_equal 'aBcaBc', a + assert_equal 'aBcaBc', b +end + +assert('String#hash', '15.2.10.5.20') do + a = 'abc' + + assert_equal 'abc'.hash, a.hash +end + +assert('String#include?', '15.2.10.5.21') do + assert_true 'abc'.include?('a') + assert_false 'abc'.include?('d') +end + +assert('String#index', '15.2.10.5.22') do + assert_equal 0, 'abc'.index('a') + assert_nil 'abc'.index('d') + assert_equal 3, 'abcabc'.index('a', 1) + assert_equal 5, "hello".index("", 5) + assert_equal nil, "hello".index("", 6) +end + +assert('String#initialize', '15.2.10.5.23') do + a = '' + a.initialize('abc') + assert_equal 'abc', a + + a.initialize('abcdefghijklmnopqrstuvwxyz') + assert_equal 'abcdefghijklmnopqrstuvwxyz', a +end + +assert('String#initialize_copy', '15.2.10.5.24') do + a = '' + a.initialize_copy('abc') + + assert_equal 'abc', a +end + +assert('String#intern', '15.2.10.5.25') do + assert_equal :abc, 'abc'.intern +end + +assert('String#length', '15.2.10.5.26') do + assert_equal 3, 'abc'.length +end + +# 'String#match', '15.2.10.5.27' will be tested in mrbgems. + +assert('String#replace', '15.2.10.5.28') do + a = '' + a.replace('abc') + + assert_equal 'abc', a + assert_equal 'abc', 'cba'.replace(a) + + b = 'abc' * 10 + c = ('cba' * 10).dup + b.replace(c); + c.replace(b); + assert_equal c, b + + # shared string + s = "foo" * 100 + a = s[10, 90] # create shared string + assert_equal("", s.replace("")) # clear + assert_equal("", s) # s is cleared + assert_not_equal("", a) # a should not be affected +end + +assert('String#reverse', '15.2.10.5.29') do + a = 'abc' + a.reverse + + assert_equal 'abc', a + assert_equal 'cba', 'abc'.reverse +end + +assert('String#reverse(UTF-8)', '15.2.10.5.29') do + assert_equal "ち", "こんにちは世界"[3] + assert_equal nil, "こんにちは世界"[20] + assert_equal "世", "こんにちは世界"[-2] + assert_equal "世界", "こんにちは世界"[-2..-1] + assert_equal "んに", "こんにちは世界"[1,2] + assert_equal "世", "こんにちは世界"["世"] +end if UTF8STRING + +assert('String#reverse!', '15.2.10.5.30') do + a = 'abc' + a.reverse! + + assert_equal 'cba', a + assert_equal 'cba', 'abc'.reverse! +end + +assert('String#reverse!(UTF-8)', '15.2.10.5.30') do + a = 'こんにちは世界!' + a.reverse! + + assert_equal '!界世はちにんこ', a + assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse! +end if UTF8STRING + +assert('String#rindex', '15.2.10.5.31') do + assert_equal 0, 'abc'.rindex('a') + assert_nil 'abc'.rindex('d') + assert_equal 0, 'abcabc'.rindex('a', 1) + assert_equal 3, 'abcabc'.rindex('a', 4) +end + +assert('String#rindex(UTF-8)', '15.2.10.5.31') do + str = "こんにちは世界!\nこんにちは世界!" + assert_nil str.index('さ') + assert_equal 3, str.index('ち') + assert_equal 12, str.index('ち', 10) + assert_equal nil, str.index("さ") +end if UTF8STRING + +# 'String#scan', '15.2.10.5.32' will be tested in mrbgems. + +assert('String#size', '15.2.10.5.33') do + assert_equal 3, 'abc'.size +end + +assert('String#size(UTF-8)', '15.2.10.5.33') do + str = 'こんにちは世界!' + assert_equal 8, str.size + assert_not_equal str.bytesize, str.size + assert_equal 2, str[1, 2].size +end if UTF8STRING + +assert('String#slice', '15.2.10.5.34') do + # length of args is 1 + a = 'abc'.slice(0) + b = 'abc'.slice(-1) + c = 'abc'.slice(10) + d = 'abc'.slice(-10) + + # length of args is 2 + a1 = 'abc'.slice(0, -1) + b1 = 'abc'.slice(10, 0) + c1 = 'abc'.slice(-10, 0) + d1 = 'abc'.slice(0, 0) + e1 = 'abc'.slice(1, 2) + + # slice of shared string + e11 = e1.slice(0) + + # args is RegExp + # It will be tested in mrbgems. + + # args is String + a3 = 'abc'.slice('bc') + b3 = 'abc'.slice('XX') + + assert_equal 'a', a + assert_equal 'c', b + assert_nil c + assert_nil d + assert_nil a1 + assert_nil b1 + assert_nil c1 + assert_equal '', d1 + assert_equal 'bc', e1 + assert_equal 'b', e11 + assert_equal 'bc', a3 + assert_nil b3 +end + +# TODO Broken ATM +assert('String#split', '15.2.10.5.35') do + # without RegExp behavior is actually unspecified + assert_equal ['abc', 'abc', 'abc'], 'abc abc abc'.split + assert_equal ["a", "b", "c", "", "d"], 'a,b,c,,d'.split(',') + assert_equal ['abc', 'abc', 'abc'], 'abc abc abc'.split(nil) + assert_equal ['a', 'b', 'c'], 'abc'.split("") +end + +assert('String#split(UTF-8)', '15.2.10.5.35') do + got = "こんにちは世界!".split('') + assert_equal ['こ', 'ん', 'に', 'ち', 'は', '世', '界', '!'], got + got = "こんにちは世界!".split('に') + assert_equal ['こん', 'ちは世界!'], got +end if UTF8STRING + +assert('String#sub', '15.2.10.5.36') do + assert_equal 'aBcabc', 'abcabc'.sub('b', 'B') + assert_equal 'aBcabc', 'abcabc'.sub('b') { |w| w.capitalize } + assert_equal 'aa$', 'aa#'.sub('#', '$') + assert_equal '.abc', "abc".sub("", ".") + + str = "abc" + miss = str.sub("X", "Z") + assert_equal str, miss + assert_not_equal str.object_id, miss.object_id + + a = [] + assert_equal '.abc', "abc".sub("") { |i| a << i; "." } + assert_equal [""], a +end + +assert('String#sub with backslash') do + s = 'abXcdXef' + assert_equal 'ab<\\>cdXef', s.sub('X', '<\\\\>') + assert_equal 'ab<X>cdXef', s.sub('X', '<\\&>') + assert_equal 'ab<X>cdXef', s.sub('X', '<\\0>') + assert_equal 'ab<ab>cdXef', s.sub('X', '<\\`>') + assert_equal 'ab<cdXef>cdXef', s.sub('X', '<\\\'>') +end + +assert('String#sub!', '15.2.10.5.37') do + a = 'abcabc' + a.sub!('b', 'B') + + b = 'abcabc' + b.sub!('b') { |w| w.capitalize } + + assert_equal 'aBcabc', a + assert_equal 'aBcabc', b +end + +assert('String#to_f', '15.2.10.5.38') do + a = ''.to_f + b = '123456789'.to_f + c = '12345.6789'.to_f + d = '1e-2147483648'.to_f + e = '1e2147483648'.to_f + + assert_float(0.0, a) + assert_float(123456789.0, b) + assert_float(12345.6789, c) + assert_float(0, d) + assert_float(Float::INFINITY, e) +end + +assert('String#to_i', '15.2.10.5.39') do + a = ''.to_i + b = '32143'.to_i + c = 'a'.to_i(16) + d = '100'.to_i(2) + e = '1_000'.to_i + + assert_equal 0, a + assert_equal 32143, b + assert_equal 10, c + assert_equal 4, d + assert_equal 1_000, e +end + +assert('String#to_s', '15.2.10.5.40') do + assert_equal 'abc', 'abc'.to_s +end + +assert('String#to_sym', '15.2.10.5.41') do + assert_equal :abc, 'abc'.to_sym +end + +assert('String#upcase', '15.2.10.5.42') do + a = 'abc'.upcase + b = 'abc' + + b.upcase + + assert_equal 'ABC', a + assert_equal 'abc', b +end + +assert('String#upcase!', '15.2.10.5.43') do + a = 'abc' + + a.upcase! + + assert_equal 'ABC', a + assert_equal nil, 'ABC'.upcase! + + a = 'abcdefghijklmnopqrstuvwxyz' + b = a.dup + a.upcase! + b.upcase! + assert_equal 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', b +end + +assert('String#inspect', '15.2.10.5.46') do + # should not raise an exception - regress #1210 + assert_nothing_raised do + ("\1" * 100).inspect + end + + assert_equal "\"\\000\"", "\0".inspect +end + +# Not ISO specified + +assert('String interpolation (mrb_str_concat for shared strings)') do + a = "A" * 32 + assert_equal "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:", "#{a}:" +end + +assert('Check the usage of a NUL character') do + "qqq\0ppp" +end + +assert('String#bytes') do + str1 = "hello" + bytes1 = [104, 101, 108, 108, 111] + + str2 = "\xFF" + bytes2 = [0xFF] + + assert_equal bytes1, str1.bytes + assert_equal bytes2, str2.bytes +end + +assert('String#each_byte') do + str1 = "hello" + bytes1 = [104, 101, 108, 108, 111] + bytes2 = [] + + str1.each_byte {|b| bytes2 << b } + + assert_equal bytes1, bytes2 +end + +assert('String#freeze') do + str = "hello" + str.freeze + + assert_raise(RuntimeError) { str.upcase! } +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/superclass.rb b/web/server/h2o/libh2o/deps/mruby/test/t/superclass.rb new file mode 100644 index 000000000..10b6438d3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/superclass.rb @@ -0,0 +1,47 @@ +[ + # [:Object, :implementation_defined_value, '15.2.2.1'], + [:Module, :Object, '15.2.2.2'], + [:Class, :Module, '15.2.3.2'], + [:NilClass, :Object, '15.2.4.2'], + [:TrueClass, :Object, '15.2.5.2'], + [:FalseClass, :Object, '15.2.6.2'], + [:Numeric, :Object, '15.2.7.2'], + [:Integer, :Numeric, '15.2.8.2'], + [:Float, :Numeric, '15.2.9.2'], + [:String, :Object, '15.2.10.2'], + [:Symbol, :Object, '15.2.11.2'], + [:Array, :Object, '15.2.12.2'], + [:Hash, :Object, '15.2.13.2'], + [:Range, :Object, '15.2.14.2'], +# [:Regexp, :Object, '15.2.15.2'], #No Regexp in mruby core +# [:MatchData, :Object, '15.2.16.2'], + [:Proc, :Object, '15.2.17.2'], +# [:Struct, :Object, '15.2.18.2'], +# [:Time, :Object, '15.2.19.2'], +# [:IO, :Object, '15.2.20.2'], +# [:File, :IO, '15.2.21.2'], + [:Exception, :Object, '15.2.22.2'], + [:StandardError, :Exception, '15.2.23.2'], + [:ArgumentError, :StandardError, '15.2.24.2'], + # [:LocalJumpError, :StandardError, '15.2.25.2'], + [:LocalJumpError, :ScriptError, '15.2.25.2'], # mruby specific + [:RangeError, :StandardError, '12.2.26.2'], + [:RegexpError, :StandardError, '12.2.27.2'], + [:RuntimeError, :StandardError, '12.2.28.2'], + [:TypeError, :StandardError, '12.2.29.2'], +# [:ZeroDivisionError, :StandardError, '12.2.30.2'], # No ZeroDivisionError in mruby + [:NameError, :StandardError, '15.2.31.2'], + [:NoMethodError, :NameError, '15.2.32.2'], + [:IndexError, :StandardError, '15.2.33.2'], +# [:IOError, :StandardError, '12.2.34.2'], +# [:EOFError, :IOError, '12.2.35.2'], +# [:SystemCallError, :StandardError, '15.2.36.2'], + [:ScriptError, :Exception, '12.2.37.2'], + [:SyntaxError, :ScriptError, '12.2.38.2'], +# [:LoadError, :ScriptError, '12.2.39,2'], +].each do |cls, super_cls, iso| + assert "Direct superclass of #{cls}", iso do + skip "#{cls} isn't defined" unless Object.const_defined? cls + assert_equal Object.const_get(super_cls), Object.const_get(cls).superclass + end +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/symbol.rb b/web/server/h2o/libh2o/deps/mruby/test/t/symbol.rb new file mode 100644 index 000000000..9059f45c2 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/symbol.rb @@ -0,0 +1,30 @@ +## +# Symbol ISO Test + +assert('Symbol') do + assert_equal :"a", :a + assert_equal :"a#{1}", :a1 + assert_equal :'a', :a + assert_equal :'a#{1}', :"a\#{1}" +end + +assert('Symbol', '15.2.11') do + assert_equal Class, Symbol.class +end + +assert('Symbol#===', '15.2.11.3.1') do + assert_true :abc == :abc + assert_false :abc == :cba +end + +assert('Symbol#id2name', '15.2.11.3.2') do + assert_equal 'abc', :abc.id2name +end + +assert('Symbol#to_s', '15.2.11.3.3') do + assert_equal 'abc', :abc.to_s +end + +assert('Symbol#to_sym', '15.2.11.3.4') do + assert_equal :abc, :abc.to_sym +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/syntax.rb b/web/server/h2o/libh2o/deps/mruby/test/t/syntax.rb new file mode 100644 index 000000000..299394557 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/syntax.rb @@ -0,0 +1,468 @@ +assert('__FILE__') do + file = __FILE__[-9, 9] + assert_equal 'syntax.rb', file +end + +assert('__LINE__') do + assert_equal 7, __LINE__ +end + +assert('super', '11.3.4') do + assert_raise NoMethodError do + super + end + + class SuperFoo + def foo + true + end + def bar(*a) + a + end + end + class SuperBar < SuperFoo + def foo + super + end + def bar(*a) + super(*a) + end + end + bar = SuperBar.new + + assert_true bar.foo + assert_equal [1,2,3], bar.bar(1,2,3) +end + +assert('yield', '11.3.5') do + assert_raise LocalJumpError do + yield + end + assert_raise LocalJumpError do + o = Object.new + def o.foo + yield + end + o.foo + end +end + +assert('redo in a for loop (#3275)') do + sum = 0 + for i in 1..10 + sum += i + i -= 1 + if i > 0 + redo + end + end + + assert_equal 220, sum +end + +assert('Abbreviated variable assignment', '11.4.2.3.2') do + a ||= 1 + b &&= 1 + c = 1 + c += 2 + + assert_equal 1, a + assert_nil b + assert_equal 3, c +end + +assert('case expression', '11.5.2.2.4') do + # case-expression-with-expression, one when-clause + x = 0 + case "a" + when "a" + x = 1 + end + assert_equal 1, x + + # case-expression-with-expression, multiple when-clauses + x = 0 + case "b" + when "a" + x = 1 + when "b" + x = 2 + end + assert_equal 2, x + + # no matching when-clause + x = 0 + case "c" + when "a" + x = 1 + when "b" + x = 2 + end + assert_equal 0, x + + # case-expression-with-expression, one when-clause and one else-clause + a = 0 + case "c" + when "a" + x = 1 + else + x = 3 + end + assert_equal 3, x + + # case-expression-without-expression, one when-clause + x = 0 + case + when true + x = 1 + end + assert_equal 1, x + + # case-expression-without-expression, multiple when-clauses + x = 0 + case + when 0 == 1 + x = 1 + when 1 == 1 + x = 2 + end + assert_equal 2, x + + # case-expression-without-expression, one when-clause and one else-clause + x = 0 + case + when 0 == 1 + x = 1 + else + x = 3 + end + assert_equal 3, x + + # multiple when-arguments + x = 0 + case 4 + when 1, 3, 5 + x = 1 + when 2, 4, 6 + x = 2 + end + assert_equal 2, x + + # when-argument with splatting argument + x = :integer + odds = [ 1, 3, 5, 7, 9 ] + evens = [ 2, 4, 6, 8 ] + case 5 + when *odds + x = :odd + when *evens + x = :even + end + assert_equal :odd, x + + true +end + +assert('Nested const reference') do + module Syntax4Const + CONST1 = "hello world" + class Const2 + def const1 + CONST1 + end + end + end + assert_equal "hello world", Syntax4Const::CONST1 + assert_equal "hello world", Syntax4Const::Const2.new.const1 +end + +assert('Abbreviated variable assignment as returns') do + module Syntax4AbbrVarAsgnAsReturns + class A + def b + @c ||= 1 + end + end + end + assert_equal 1, Syntax4AbbrVarAsgnAsReturns::A.new.b +end + +assert('Splat and multiple assignment') do + *a = *[1,2,3] + b, *c = *[7,8,9] + + assert_equal [1,2,3], a + assert_equal 7, b + assert_equal [8,9], c + + (a, b), c = [1,2],3 + assert_equal [1,2,3], [a,b,c] + (a, b), c = 1,2,3 + assert_equal [1,nil,2], [a,b,c] +end + +assert('Splat and multiple assignment from variable') do + a = [1, 2, 3] + b, *c = a + + assert_equal 1, b + assert_equal [2, 3], c +end + +assert('Splat and multiple assignment from variables') do + a = [1, 2, 3] + b = [4, 5, 6, 7] + c, d, *e, f, g = *a, *b + + assert_equal 1, c + assert_equal 2, d + assert_equal [3, 4, 5], e + assert_equal 6, f + assert_equal 7, g +end + +assert('Splat and multiple assignment in for') do + a = [1, 2, 3, 4, 5, 6, 7] + for b, c, *d, e, f in [a] do + end + + assert_equal 1, b + assert_equal 2, c + assert_equal [3, 4, 5], d + assert_equal 6, e + assert_equal 7, f +end + +assert('Splat without assignment') do + * = [0] + a, * = [1, 2] + assert_equal 1, a +end + +assert('multiple assignment (rest)') do + *a = 0 + assert_equal [0], a +end + +assert('multiple assignment (rest+post)') do + *a, b = 0, 1, 2 + *c, d = 3 + + assert_equal [0, 1], a + assert_equal 2, b + assert_equal [], c + assert_equal 3, d +end + +assert('multiple assignment (nosplat array rhs)') do + a, *b = [] + *c, d = [0] + e, *f, g = [1, 2] + + assert_nil a + assert_equal [], b + assert_equal [], c + assert_equal 0, d + assert_equal 1, e + assert_equal [], f + assert_equal 2, g +end + +assert('multiple assignment (empty array rhs #3236, #3239)') do + a,b,*c = []; assert_equal [nil, nil, []], [a, b, c] + a,b,*c = [1]; assert_equal [1, nil, []], [a, b, c] + a,b,*c = [nil]; assert_equal [nil,nil, []], [a, b, c] + a,b,*c = [[]]; assert_equal [[], nil, []], [a, b, c] +end + +assert('Return values of case statements') do + a = [] << case 1 + when 3 then 2 + when 2 then 2 + when 1 then 2 + end + + b = [] << case 1 + when 2 then 2 + else + end + + def fb + n = 0 + Proc.new do + n += 1 + case + when n % 15 == 0 + else n + end + end + end + + assert_equal [2], a + assert_equal [nil], b + assert_equal 1, fb.call +end + +assert('Return values of if and case statements') do + true_clause_value = + if true + 1 + else + case 2 + when 3 + end + 4 + end + + assert_equal 1, true_clause_value +end + +assert('Return values of no expression case statement') do + when_value = + case + when true + 1 + end + + assert_equal 1, when_value +end + +assert('splat object in assignment') do + o = Object.new + def o.to_a + nil + end + assert_equal [o], (a = *o) + + def o.to_a + 1 + end + assert_raise(TypeError) { a = *o } + + def o.to_a + [2] + end + assert_equal [2], (a = *o) +end + +assert('splat object in case statement') do + o = Object.new + def o.to_a + nil + end + a = case o + when *o + 1 + end + assert_equal 1, a +end + +assert('splat in case statement') do + values = [3,5,1,7,8] + testa = [1,2,7] + testb = [5,6] + resulta = [] + resultb = [] + resultc = [] + values.each do |value| + case value + when *testa + resulta << value + when *testb + resultb << value + else + resultc << value + end + end + + assert_equal [1,7], resulta + assert_equal [5], resultb + assert_equal [3,8], resultc +end + +assert('External command execution.') do + module Kernel + sym = '`'.to_sym + alias_method :old_cmd, sym + + results = [] + define_method(sym) do |str| + results.push str + str + end + + `test` # NOVAL NODE_XSTR + `test dynamic #{sym}` # NOVAL NODE_DXSTR + assert_equal ['test', 'test dynamic `'], results + + t = `test` # VAL NODE_XSTR + assert_equal 'test', t + assert_equal ['test', 'test dynamic `', 'test'], results + + t = `test dynamic #{sym}` # VAL NODE_DXSTR + assert_equal 'test dynamic `', t + assert_equal ['test', 'test dynamic `', 'test', 'test dynamic `'], results + + alias_method sym, :old_cmd + end + true +end + +assert('parenthesed do-block in cmdarg') do + class ParenDoBlockCmdArg + def test(block) + block.call + end + end + x = ParenDoBlockCmdArg.new + result = x.test (Proc.new do :ok; end) + assert_equal :ok, result +end + +assert('method definition in cmdarg') do + if false + bar def foo; self.each do end end + end + true +end + +assert('optional argument in the rhs default expressions') do + class OptArgInRHS + def foo + "method called" + end + def t(foo = foo) + foo + end + def t2(foo = foo()) + foo + end + end + o = OptArgInRHS.new + assert_nil(o.t) + assert_equal("method called", o.t2) +end + +assert('optional block argument in the rhs default expressions') do + assert_nil(Proc.new {|foo = foo| foo}.call) +end + +assert('multiline comments work correctly') do +=begin +this is a comment with nothing after begin and end +=end +=begin this is a comment +this is a comment with extra after =begin +=end +=begin +this is a comment that has =end with spaces after it +=end +=begin this is a comment +this is a comment that has extra after =begin and =end with spaces after it +=end + line = __LINE__ +=begin this is a comment +this is a comment that has extra after =begin and =end with tabs after it +=end xxxxxxxxxxxxxxxxxxxxxxxxxx + assert_equal(line + 4, __LINE__) +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/true.rb b/web/server/h2o/libh2o/deps/mruby/test/t/true.rb new file mode 100644 index 000000000..74f605ef0 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/true.rb @@ -0,0 +1,31 @@ +## +# TrueClass ISO Test + +assert('TrueClass', '15.2.5') do + assert_equal Class, TrueClass.class +end + +assert('TrueClass true', '15.2.5.1') do + assert_true true + assert_equal TrueClass, true.class + assert_false TrueClass.method_defined? :new +end + +assert('TrueClass#&', '15.2.5.3.1') do + assert_true true.&(true) + assert_false true.&(false) +end + +assert('TrueClass#^', '15.2.5.3.2') do + assert_false true.^(true) + assert_true true.^(false) +end + +assert('TrueClass#to_s', '15.2.5.3.3') do + assert_equal 'true', true.to_s +end + +assert('TrueClass#|', '15.2.5.3.4') do + assert_true true.|(true) + assert_true true.|(false) +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/typeerror.rb b/web/server/h2o/libh2o/deps/mruby/test/t/typeerror.rb new file mode 100644 index 000000000..32536a74f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/typeerror.rb @@ -0,0 +1,6 @@ +## +# TypeError ISO Test + +assert('TypeError', '15.2.29') do + assert_equal Class, TypeError.class +end diff --git a/web/server/h2o/libh2o/deps/mruby/test/t/unicode.rb b/web/server/h2o/libh2o/deps/mruby/test/t/unicode.rb new file mode 100644 index 000000000..8622ae08a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/test/t/unicode.rb @@ -0,0 +1,39 @@ +# Test of the \u notation + +assert('bare \u notation test') do + # Mininum and maximum one byte characters + assert_equal("\x00", "\u0000") + assert_equal("\x7F", "\u007F") + + # Mininum and maximum two byte characters + assert_equal("\xC2\x80", "\u0080") + assert_equal("\xDF\xBF", "\u07FF") + + # Mininum and maximum three byte characters + assert_equal("\xE0\xA0\x80", "\u0800") + assert_equal("\xEF\xBF\xBF", "\uFFFF") + + # Four byte characters require the \U notation +end + +assert('braced \u notation test') do + # Mininum and maximum one byte characters + assert_equal("\x00", "\u{0000}") + assert_equal("\x7F", "\u{007F}") + + # Mininum and maximum two byte characters + assert_equal("\xC2\x80", "\u{0080}") + assert_equal("\xDF\xBF", "\u{07FF}") + + # Mininum and maximum three byte characters + assert_equal("\xE0\xA0\x80", "\u{0800}") + assert_equal("\xEF\xBF\xBF", "\u{FFFF}") + + # Mininum and maximum four byte characters + assert_equal("\xF0\x90\x80\x80", "\u{10000}") + assert_equal("\xF4\x8F\xBF\xBF", "\u{10FFFF}") +end + +assert('braced multiple \u notation test') do + assert_equal("ABC", "\u{41 42 43}") +end diff --git a/web/server/h2o/libh2o/deps/mruby/travis_config.rb b/web/server/h2o/libh2o/deps/mruby/travis_config.rb new file mode 100644 index 000000000..5904d6880 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/travis_config.rb @@ -0,0 +1,53 @@ +MRuby::Build.new('debug') do |conf| + toolchain :gcc + enable_debug + + # include all core GEMs + conf.gembox 'full-core' + conf.cc.flags += %w(-Werror=declaration-after-statement) + conf.compilers.each do |c| + c.defines += %w(MRB_GC_STRESS MRB_GC_FIXED_ARENA MRB_METHOD_CACHE) + end + + build_mrbc_exec +end + +MRuby::Build.new('full-debug') do |conf| + toolchain :gcc + enable_debug + + # include all core GEMs + conf.gembox 'full-core' + conf.cc.defines = %w(MRB_ENABLE_DEBUG_HOOK) + + conf.enable_test +end + +MRuby::Build.new do |conf| + toolchain :gcc + + # include all core GEMs + conf.gembox 'full-core' + conf.cc.flags += %w(-Werror=declaration-after-statement) + conf.compilers.each do |c| + c.defines += %w(MRB_GC_FIXED_ARENA) + end + conf.enable_bintest + conf.enable_test +end + +MRuby::Build.new('cxx_abi') do |conf| + toolchain :gcc + + conf.gembox 'full-core' + conf.cc.flags += %w(-Werror=declaration-after-statement) + conf.compilers.each do |c| + c.defines += %w(MRB_GC_FIXED_ARENA) + end + conf.enable_bintest + conf.enable_test + + enable_cxx_abi + + build_mrbc_exec +end |