renamed stix to moo

This commit is contained in:
hyunghwan.chung
2017-01-09 10:25:22 +00:00
parent f7e98b7fc7
commit b2fb361df4
135 changed files with 0 additions and 0 deletions

84
moo/lib/Makefile.am Normal file
View File

@ -0,0 +1,84 @@
AUTOMAKE_OPTIONS = nostdinc
CPPFLAGS_ALL_COMMON = \
-I$(abs_builddir) \
-I$(abs_srcdir) \
-I$(includedir)
LDFLAGS_ALL_COMMON = -L$(abs_builddir) -L$(libdir)
##################################################
# MAIN LIBRARY
##################################################
CPPFLAGS_LIB_COMMON = $(CPPFLAGS_ALL_COMMON) $(LTDLINCL)
LDFLAGS_LIB_COMMON = $(LDFLAGS_ALL_COMMON) -version-info 1:0:0 -no-undefined
LIBADD_LIB_COMMON = $(LIBM) $(LIBLTDL)
if WIN32
# you must adjust the value of DEFAULT_MODPOSTFIX according
# to the first number in -version-info above
CPPFLAGS_LIB_COMMON += -DMOO_DEFAULT_MODPREFIX=\"libmoo-\" -DMOO_DEFAULT_MODPOSTFIX=\"-1\"
else
CPPFLAGS_LIB_COMMON += -DMOO_DEFAULT_MODPREFIX=\"$(libdir)/libmoo-\" -DMOO_DEFAULT_MODPOSTFIX=\"\"
endif
pkgincludedir = $(includedir)
pkglibdir = $(libdir)
pkginclude_HEADERS = \
moo-cfg.h \
moo-cmn.h \
moo-rbt.h \
moo-utl.h \
moo.h
noinst_HEADERS = moo-prv.h
pkglib_LTLIBRARIES = libmoo.la
libmoo_la_SOURCES = \
bigint.c \
comp.c \
debug.c \
decode.c \
dic.c \
err.c \
exec.c \
logfmtv.h \
logfmt.c \
gc.c \
heap.c \
obj.c \
proc.c \
rbt.c \
moo.c \
sym.c \
utf8.c \
utl.c
libmoo_la_CPPFLAGS = $(CPPFLAGS_LIB_COMMON)
libmoo_la_LDFLAGS = $(LDFLAGS_LIB_COMMON)
libmoo_la_LIBADD = $(LIBADD_LIB_COMMON)
if ENABLE_STATIC_MODULE
libmoo_la_LDFLAGS += -L$(abs_builddir)/../mod
libmoo_la_LIBADD += -lmoo-console -lmoo-stdio -ltermcap
endif
bin_PROGRAMS = moo
moo_SOURCES = main.c
moo_CPPFLAGS = $(CPPFLAGS_LIB_COMMON)
moo_LDFLAGS = $(LDFLAGS_LIB_COMMON)
moo_LDADD = $(LIBADD_LIB_COMMON) -lmoo #-ldyncall_s
install-data-hook:
@echo "#ifndef _MOO_CFG_H_" > "$(DESTDIR)$(pkgincludedir)/moo-cfg.h"
@echo "#define _MOO_CFG_H_" >> "$(DESTDIR)$(pkgincludedir)/moo-cfg.h"
@$(EGREP) "#define[ ]+MOO_" "$(abs_builddir)/moo-cfg.h" >> "$(DESTDIR)$(pkgincludedir)/moo-cfg.h"
@echo "#endif" >> "$(DESTDIR)$(pkgincludedir)/moo-cfg.h"
@rm -f "$(DESTDIR)$(pkgincludedir)/moo-cfg.h.in"
@$(SED) 's|/\*#define MOO_HAVE_CFG_H\*/|#define MOO_HAVE_CFG_H|' "$(srcdir)/moo-cmn.h" > "$(DESTDIR)$(pkgincludedir)/moo-cmn.h"
uninstall-hook:
@rm -f "$(DESTDIR)$(pkgincludedir)/moo-cfg.h"

1013
moo/lib/Makefile.in Normal file

File diff suppressed because it is too large Load Diff

4137
moo/lib/bigint.c Normal file

File diff suppressed because it is too large Load Diff

5728
moo/lib/comp.c Normal file

File diff suppressed because it is too large Load Diff

71
moo/lib/debug.c Normal file
View File

@ -0,0 +1,71 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
void moo_dumpsymtab (moo_t* moo)
{
moo_oow_t i;
moo_oop_char_t symbol;
MOO_DEBUG0 (moo, "--------------------------------------------\n");
MOO_DEBUG1 (moo, "Stix Symbol Table %zu\n", MOO_OBJ_GET_SIZE(moo->symtab->bucket));
MOO_DEBUG0 (moo, "--------------------------------------------\n");
for (i = 0; i < MOO_OBJ_GET_SIZE(moo->symtab->bucket); i++)
{
symbol = (moo_oop_char_t)moo->symtab->bucket->slot[i];
if ((moo_oop_t)symbol != moo->_nil)
{
MOO_DEBUG2 (moo, " %07zu %O\n", i, symbol);
}
}
MOO_DEBUG0 (moo, "--------------------------------------------\n");
}
void moo_dumpdic (moo_t* moo, moo_oop_set_t dic, const moo_bch_t* title)
{
moo_oow_t i, j;
moo_oop_association_t ass;
MOO_DEBUG0 (moo, "--------------------------------------------\n");
MOO_DEBUG2 (moo, "%s %zu\n", title, MOO_OBJ_GET_SIZE(dic->bucket));
MOO_DEBUG0 (moo, "--------------------------------------------\n");
for (i = 0; i < MOO_OBJ_GET_SIZE(dic->bucket); i++)
{
ass = (moo_oop_association_t)dic->bucket->slot[i];
if ((moo_oop_t)ass != moo->_nil)
{
MOO_DEBUG2 (moo, " %07zu %O\n", i, ass->key);
}
}
MOO_DEBUG0 (moo, "--------------------------------------------\n");
}

513
moo/lib/decode.c Normal file
View File

@ -0,0 +1,513 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
#define DECODE_LOG_MASK (MOO_LOG_MNEMONIC)
#define LOG_INST_0(moo,fmt) MOO_LOG1(moo, DECODE_LOG_MASK, " %06zd " fmt "\n", fetched_instruction_pointer)
#define LOG_INST_1(moo,fmt,a1) MOO_LOG2(moo, DECODE_LOG_MASK, " %06zd " fmt "\n", fetched_instruction_pointer, a1)
#define LOG_INST_2(moo,fmt,a1,a2) MOO_LOG3(moo, DECODE_LOG_MASK, " %06zd " fmt "\n", fetched_instruction_pointer, a1, a2)
#define LOG_INST_3(moo,fmt,a1,a2,a3) MOO_LOG4(moo, DECODE_LOG_MASK, " %06zd " fmt "\n", fetched_instruction_pointer, a1, a2, a3)
#define FETCH_BYTE_CODE(moo) (cdptr[ip++])
#define FETCH_BYTE_CODE_TO(moo,v_oow) (v_oow = FETCH_BYTE_CODE(moo))
#if (MOO_BCODE_LONG_PARAM_SIZE == 2)
# define FETCH_PARAM_CODE_TO(moo,v_oow) \
do { \
v_oow = FETCH_BYTE_CODE(moo); \
v_oow = (v_oow << 8) | FETCH_BYTE_CODE(moo); \
} while (0)
#else
# define FETCH_PARAM_CODE_TO(moo,v_oow) (v_oow = FETCH_BYTE_CODE(moo))
#endif
/* TODO: check if ip shoots beyond the maximum length in fetching code and parameters */
int moo_decode (moo_t* moo, moo_oop_method_t mth, const moo_oocs_t* classfqn)
{
moo_oob_t bcode, * cdptr;
moo_ooi_t ip = 0, cdlen; /* byte code length is limited by the compiler. so moo_ooi_t is good enough */
moo_ooi_t fetched_instruction_pointer;
moo_oow_t b1, b2;
cdptr = MOO_METHOD_GET_CODE_BYTE(mth);
cdlen = MOO_METHOD_GET_CODE_SIZE(mth);
if (classfqn)
MOO_LOG3 (moo, DECODE_LOG_MASK, "%.*js>>%O\n", classfqn->len, classfqn->ptr, mth->name);
else
MOO_LOG2 (moo, DECODE_LOG_MASK, "%O>>%O\n", mth->owner, mth->name);
/* TODO: check if ip increases beyond bcode when fetching parameters too */
while (ip < cdlen)
{
fetched_instruction_pointer = ip;
FETCH_BYTE_CODE_TO(moo, bcode);
switch (bcode)
{
case BCODE_PUSH_INSTVAR_X:
FETCH_PARAM_CODE_TO (moo, b1);
goto push_instvar;
case BCODE_PUSH_INSTVAR_0:
case BCODE_PUSH_INSTVAR_1:
case BCODE_PUSH_INSTVAR_2:
case BCODE_PUSH_INSTVAR_3:
case BCODE_PUSH_INSTVAR_4:
case BCODE_PUSH_INSTVAR_5:
case BCODE_PUSH_INSTVAR_6:
case BCODE_PUSH_INSTVAR_7:
b1 = bcode & 0x7; /* low 3 bits */
push_instvar:
LOG_INST_1 (moo, "push_instvar %zu", b1);
break;
/* ------------------------------------------------- */
case BCODE_STORE_INTO_INSTVAR_X:
FETCH_PARAM_CODE_TO (moo, b1);
goto store_instvar;
case BCODE_STORE_INTO_INSTVAR_0:
case BCODE_STORE_INTO_INSTVAR_1:
case BCODE_STORE_INTO_INSTVAR_2:
case BCODE_STORE_INTO_INSTVAR_3:
case BCODE_STORE_INTO_INSTVAR_4:
case BCODE_STORE_INTO_INSTVAR_5:
case BCODE_STORE_INTO_INSTVAR_6:
case BCODE_STORE_INTO_INSTVAR_7:
b1 = bcode & 0x7; /* low 3 bits */
store_instvar:
LOG_INST_1 (moo, "store_into_instvar %zu", b1);
break;
case BCODE_POP_INTO_INSTVAR_X:
FETCH_PARAM_CODE_TO (moo, b1);
goto pop_into_instvar;
case BCODE_POP_INTO_INSTVAR_0:
case BCODE_POP_INTO_INSTVAR_1:
case BCODE_POP_INTO_INSTVAR_2:
case BCODE_POP_INTO_INSTVAR_3:
case BCODE_POP_INTO_INSTVAR_4:
case BCODE_POP_INTO_INSTVAR_5:
case BCODE_POP_INTO_INSTVAR_6:
case BCODE_POP_INTO_INSTVAR_7:
b1 = bcode & 0x7; /* low 3 bits */
pop_into_instvar:
LOG_INST_1 (moo, "pop_into_instvar %zu", b1);
break;
/* ------------------------------------------------- */
case BCODE_PUSH_TEMPVAR_X:
case BCODE_STORE_INTO_TEMPVAR_X:
case BCODE_POP_INTO_TEMPVAR_X:
FETCH_PARAM_CODE_TO (moo, b1);
goto handle_tempvar;
case BCODE_PUSH_TEMPVAR_0:
case BCODE_PUSH_TEMPVAR_1:
case BCODE_PUSH_TEMPVAR_2:
case BCODE_PUSH_TEMPVAR_3:
case BCODE_PUSH_TEMPVAR_4:
case BCODE_PUSH_TEMPVAR_5:
case BCODE_PUSH_TEMPVAR_6:
case BCODE_PUSH_TEMPVAR_7:
case BCODE_STORE_INTO_TEMPVAR_0:
case BCODE_STORE_INTO_TEMPVAR_1:
case BCODE_STORE_INTO_TEMPVAR_2:
case BCODE_STORE_INTO_TEMPVAR_3:
case BCODE_STORE_INTO_TEMPVAR_4:
case BCODE_STORE_INTO_TEMPVAR_5:
case BCODE_STORE_INTO_TEMPVAR_6:
case BCODE_STORE_INTO_TEMPVAR_7:
case BCODE_POP_INTO_TEMPVAR_0:
case BCODE_POP_INTO_TEMPVAR_1:
case BCODE_POP_INTO_TEMPVAR_2:
case BCODE_POP_INTO_TEMPVAR_3:
case BCODE_POP_INTO_TEMPVAR_4:
case BCODE_POP_INTO_TEMPVAR_5:
case BCODE_POP_INTO_TEMPVAR_6:
case BCODE_POP_INTO_TEMPVAR_7:
b1 = bcode & 0x7; /* low 3 bits */
handle_tempvar:
if ((bcode >> 4) & 1)
{
/* push - bit 4 on */
LOG_INST_1 (moo, "push_tempvar %zu", b1);
}
else
{
/* store or pop - bit 5 off */
if ((bcode >> 3) & 1)
{
/* pop - bit 3 on */
LOG_INST_1 (moo, "pop_into_tempvar %zu", b1);
}
else
{
LOG_INST_1 (moo, "store_into_tempvar %zu", b1);
}
}
break;
/* ------------------------------------------------- */
case BCODE_PUSH_LITERAL_X:
FETCH_PARAM_CODE_TO (moo, b1);
goto push_literal;
case BCODE_PUSH_LITERAL_0:
case BCODE_PUSH_LITERAL_1:
case BCODE_PUSH_LITERAL_2:
case BCODE_PUSH_LITERAL_3:
case BCODE_PUSH_LITERAL_4:
case BCODE_PUSH_LITERAL_5:
case BCODE_PUSH_LITERAL_6:
case BCODE_PUSH_LITERAL_7:
b1 = bcode & 0x7; /* low 3 bits */
push_literal:
LOG_INST_1 (moo, "push_literal @%zu", b1);
break;
/* ------------------------------------------------- */
case BCODE_PUSH_OBJECT_X:
case BCODE_STORE_INTO_OBJECT_X:
case BCODE_POP_INTO_OBJECT_X:
FETCH_PARAM_CODE_TO (moo, b1);
goto handle_object;
case BCODE_PUSH_OBJECT_0:
case BCODE_PUSH_OBJECT_1:
case BCODE_PUSH_OBJECT_2:
case BCODE_PUSH_OBJECT_3:
case BCODE_STORE_INTO_OBJECT_0:
case BCODE_STORE_INTO_OBJECT_1:
case BCODE_STORE_INTO_OBJECT_2:
case BCODE_STORE_INTO_OBJECT_3:
case BCODE_POP_INTO_OBJECT_0:
case BCODE_POP_INTO_OBJECT_1:
case BCODE_POP_INTO_OBJECT_2:
case BCODE_POP_INTO_OBJECT_3:
b1 = bcode & 0x3; /* low 2 bits */
handle_object:
if ((bcode >> 3) & 1)
{
if ((bcode >> 2) & 1)
{
LOG_INST_1 (moo, "pop_into_object @%zu", b1);
}
else
{
LOG_INST_1 (moo, "store_into_object @%zu", b1);
}
}
else
{
LOG_INST_1 (moo, "push_object @%zu", b1);
}
break;
/* -------------------------------------------------------- */
case BCODE_JUMP_FORWARD_X:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump_forward %zu", b1);
break;
case BCODE_JUMP_FORWARD_0:
case BCODE_JUMP_FORWARD_1:
case BCODE_JUMP_FORWARD_2:
case BCODE_JUMP_FORWARD_3:
LOG_INST_1 (moo, "jump_forward %zu", (moo_oow_t)(bcode & 0x3)); /* low 2 bits */
break;
case BCODE_JUMP_BACKWARD_X:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump_backward %zu", b1);
moo->ip += b1;
break;
case BCODE_JUMP_BACKWARD_0:
case BCODE_JUMP_BACKWARD_1:
case BCODE_JUMP_BACKWARD_2:
case BCODE_JUMP_BACKWARD_3:
LOG_INST_1 (moo, "jump_backward %zu", (moo_oow_t)(bcode & 0x3)); /* low 2 bits */
break;
case BCODE_JUMP_IF_TRUE_X:
case BCODE_JUMP_IF_FALSE_X:
case BCODE_JUMP_IF_TRUE_0:
case BCODE_JUMP_IF_TRUE_1:
case BCODE_JUMP_IF_TRUE_2:
case BCODE_JUMP_IF_TRUE_3:
case BCODE_JUMP_IF_FALSE_0:
case BCODE_JUMP_IF_FALSE_1:
case BCODE_JUMP_IF_FALSE_2:
case BCODE_JUMP_IF_FALSE_3:
LOG_INST_0 (moo, "<<<<<<<<<<<<<< JUMP NOT IMPLEMENTED YET >>>>>>>>>>>>");
moo->errnum = MOO_ENOIMPL;
return -1;
case BCODE_JUMP2_FORWARD:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump2_forward %zu", b1);
break;
case BCODE_JUMP2_BACKWARD:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "jump2_backward %zu", b1);
break;
/* -------------------------------------------------------- */
case BCODE_PUSH_CTXTEMPVAR_X:
case BCODE_STORE_INTO_CTXTEMPVAR_X:
case BCODE_POP_INTO_CTXTEMPVAR_X:
FETCH_PARAM_CODE_TO (moo, b1);
FETCH_PARAM_CODE_TO (moo, b2);
goto handle_ctxtempvar;
case BCODE_PUSH_CTXTEMPVAR_0:
case BCODE_PUSH_CTXTEMPVAR_1:
case BCODE_PUSH_CTXTEMPVAR_2:
case BCODE_PUSH_CTXTEMPVAR_3:
case BCODE_STORE_INTO_CTXTEMPVAR_0:
case BCODE_STORE_INTO_CTXTEMPVAR_1:
case BCODE_STORE_INTO_CTXTEMPVAR_2:
case BCODE_STORE_INTO_CTXTEMPVAR_3:
case BCODE_POP_INTO_CTXTEMPVAR_0:
case BCODE_POP_INTO_CTXTEMPVAR_1:
case BCODE_POP_INTO_CTXTEMPVAR_2:
case BCODE_POP_INTO_CTXTEMPVAR_3:
b1 = bcode & 0x3; /* low 2 bits */
FETCH_BYTE_CODE_TO (moo, b2);
handle_ctxtempvar:
if ((bcode >> 3) & 1)
{
/* store or pop */
if ((bcode >> 2) & 1)
{
LOG_INST_2 (moo, "pop_into_ctxtempvar %zu %zu", b1, b2);
}
else
{
LOG_INST_2 (moo, "store_into_ctxtempvar %zu %zu", b1, b2);
}
}
else
{
/* push */
LOG_INST_2 (moo, "push_ctxtempvar %zu %zu", b1, b2);
}
break;
/* -------------------------------------------------------- */
case BCODE_PUSH_OBJVAR_X:
case BCODE_STORE_INTO_OBJVAR_X:
case BCODE_POP_INTO_OBJVAR_X:
FETCH_PARAM_CODE_TO (moo, b1);
FETCH_PARAM_CODE_TO (moo, b2);
goto handle_objvar;
case BCODE_PUSH_OBJVAR_0:
case BCODE_PUSH_OBJVAR_1:
case BCODE_PUSH_OBJVAR_2:
case BCODE_PUSH_OBJVAR_3:
case BCODE_STORE_INTO_OBJVAR_0:
case BCODE_STORE_INTO_OBJVAR_1:
case BCODE_STORE_INTO_OBJVAR_2:
case BCODE_STORE_INTO_OBJVAR_3:
case BCODE_POP_INTO_OBJVAR_0:
case BCODE_POP_INTO_OBJVAR_1:
case BCODE_POP_INTO_OBJVAR_2:
case BCODE_POP_INTO_OBJVAR_3:
/* b1 -> variable index to the object indicated by b2.
* b2 -> object index stored in the literal frame. */
b1 = bcode & 0x3; /* low 2 bits */
FETCH_BYTE_CODE_TO (moo, b2);
handle_objvar:
if ((bcode >> 3) & 1)
{
/* store or pop */
if ((bcode >> 2) & 1)
{
LOG_INST_2 (moo, "pop_into_objvar %zu %zu", b1, b2);
}
else
{
LOG_INST_2 (moo, "store_into_objvar %zu %zu", b1, b2);
}
}
else
{
LOG_INST_2 (moo, "push_objvar %zu %zu", b1, b2);
}
break;
/* -------------------------------------------------------- */
case BCODE_SEND_MESSAGE_X:
case BCODE_SEND_MESSAGE_TO_SUPER_X:
/* b1 -> number of arguments
* b2 -> selector index stored in the literal frame */
FETCH_PARAM_CODE_TO (moo, b1);
FETCH_PARAM_CODE_TO (moo, b2);
goto handle_send_message;
case BCODE_SEND_MESSAGE_0:
case BCODE_SEND_MESSAGE_1:
case BCODE_SEND_MESSAGE_2:
case BCODE_SEND_MESSAGE_3:
case BCODE_SEND_MESSAGE_TO_SUPER_0:
case BCODE_SEND_MESSAGE_TO_SUPER_1:
case BCODE_SEND_MESSAGE_TO_SUPER_2:
case BCODE_SEND_MESSAGE_TO_SUPER_3:
b1 = bcode & 0x3; /* low 2 bits */
FETCH_BYTE_CODE_TO (moo, b2);
handle_send_message:
LOG_INST_3 (moo, "send_message%hs %zu @%zu", (((bcode >> 2) & 1)? "_to_super": ""), b1, b2);
break;
/* -------------------------------------------------------- */
case BCODE_PUSH_RECEIVER:
LOG_INST_0 (moo, "push_receiver");
break;
case BCODE_PUSH_NIL:
LOG_INST_0 (moo, "push_nil");
break;
case BCODE_PUSH_TRUE:
LOG_INST_0 (moo, "push_true");
break;
case BCODE_PUSH_FALSE:
LOG_INST_0 (moo, "push_false");
break;
case BCODE_PUSH_CONTEXT:
LOG_INST_0 (moo, "push_context");
break;
case BCODE_PUSH_PROCESS:
LOG_INST_0 (moo, "push_process");
break;
case BCODE_PUSH_NEGONE:
LOG_INST_0 (moo, "push_negone");
break;
case BCODE_PUSH_ZERO:
LOG_INST_0 (moo, "push_zero");
break;
case BCODE_PUSH_ONE:
LOG_INST_0 (moo, "push_one");
break;
case BCODE_PUSH_TWO:
LOG_INST_0 (moo, "push_two");
break;
case BCODE_PUSH_INTLIT:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "push_intlit %zu", b1);
break;
case BCODE_PUSH_NEGINTLIT:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "push_negintlit %zu", b1);
break;
case BCODE_PUSH_CHARLIT:
FETCH_PARAM_CODE_TO (moo, b1);
LOG_INST_1 (moo, "push_charlit %zu", b1);
break;
/* -------------------------------------------------------- */
case BCODE_DUP_STACKTOP:
LOG_INST_0 (moo, "dup_stacktop");
break;
case BCODE_POP_STACKTOP:
LOG_INST_0 (moo, "pop_stacktop");
break;
case BCODE_RETURN_STACKTOP:
LOG_INST_0 (moo, "return_stacktop");
break;
case BCODE_RETURN_RECEIVER:
LOG_INST_0 (moo, "return_receiver");
break;
case BCODE_RETURN_FROM_BLOCK:
LOG_INST_0 (moo, "return_from_block");
break;
case BCODE_MAKE_BLOCK:
/* b1 - number of block arguments
* b2 - number of block temporaries */
FETCH_PARAM_CODE_TO (moo, b1);
FETCH_PARAM_CODE_TO (moo, b2);
LOG_INST_2 (moo, "make_block %zu %zu", b1, b2);
MOO_ASSERT (moo, b1 >= 0);
MOO_ASSERT (moo, b2 >= b1);
break;
case BCODE_SEND_BLOCK_COPY:
LOG_INST_0 (moo, "send_block_copy");
break;
case BCODE_NOOP:
/* do nothing */
LOG_INST_0 (moo, "noop");
break;
default:
LOG_INST_1 (moo, "UNKNOWN BYTE CODE ENCOUNTERED %x", (int)bcode);
moo->errnum = MOO_EINTERN;
break;
}
}
/* print literal frame contents */
for (ip = 0; ip < MOO_OBJ_GET_SIZE(mth) - MOO_METHOD_NAMED_INSTVARS; ip++)
{
MOO_LOG2(moo, DECODE_LOG_MASK, " @%-5zd %O\n", ip, mth->slot[ip]);
}
return 0;
}

354
moo/lib/dic.c Normal file
View File

@ -0,0 +1,354 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
static moo_oop_oop_t expand_bucket (moo_t* moo, moo_oop_oop_t oldbuc)
{
moo_oop_oop_t newbuc;
moo_oow_t oldsz, newsz, index;
moo_oop_association_t ass;
moo_oop_char_t key;
oldsz = MOO_OBJ_GET_SIZE(oldbuc);
/* TODO: better growth policy? */
if (oldsz < 5000) newsz = oldsz + oldsz;
else if (oldsz < 50000) newsz = oldsz + (oldsz / 2);
else if (oldsz < 100000) newsz = oldsz + (oldsz / 4);
else if (oldsz < 200000) newsz = oldsz + (oldsz / 8);
else if (oldsz < 400000) newsz = oldsz + (oldsz / 16);
else if (oldsz < 800000) newsz = oldsz + (oldsz / 32);
else if (oldsz < 1600000) newsz = oldsz + (oldsz / 64);
else
{
moo_oow_t inc, inc_max;
inc = oldsz / 128;
inc_max = MOO_OBJ_SIZE_MAX - oldsz;
if (inc > inc_max)
{
if (inc_max > 0) inc = inc_max;
else
{
moo->errnum = MOO_EOOMEM;
return MOO_NULL;
}
}
newsz = oldsz + inc;
}
moo_pushtmp (moo, (moo_oop_t*)&oldbuc);
newbuc = (moo_oop_oop_t)moo_instantiate (moo, moo->_array, MOO_NULL, newsz);
moo_poptmp (moo);
if (!newbuc) return MOO_NULL;
while (oldsz > 0)
{
ass = (moo_oop_association_t)oldbuc->slot[--oldsz];
if ((moo_oop_t)ass != moo->_nil)
{
MOO_ASSERT (moo, MOO_CLASSOF(moo,ass) == moo->_association);
key = (moo_oop_char_t)ass->key;
MOO_ASSERT (moo, MOO_CLASSOF(moo,key) == (moo_oop_t)moo->_symbol);
index = moo_hashoochars(key->slot, MOO_OBJ_GET_SIZE(key)) % newsz;
while (newbuc->slot[index] != moo->_nil) index = (index + 1) % newsz;
newbuc->slot[index] = (moo_oop_t)ass;
}
}
return newbuc;
}
static moo_oop_association_t find_or_upsert (moo_t* moo, moo_oop_set_t dic, moo_oop_char_t key, moo_oop_t value)
{
moo_ooi_t tally;
moo_oow_t hv, index;
moo_oop_association_t ass;
moo_oow_t tmp_count = 0;
/* the system dictionary is not a generic dictionary.
* it accepts only a symbol as a key. */
MOO_ASSERT (moo, MOO_CLASSOF(moo,key) == moo->_symbol);
MOO_ASSERT (moo, MOO_CLASSOF(moo,dic->tally) == moo->_small_integer);
MOO_ASSERT (moo, MOO_CLASSOF(moo,dic->bucket) == moo->_array);
hv = moo_hashoochars(key->slot, MOO_OBJ_GET_SIZE(key));
index = hv % MOO_OBJ_GET_SIZE(dic->bucket);
/* find */
while (dic->bucket->slot[index] != moo->_nil)
{
ass = (moo_oop_association_t)dic->bucket->slot[index];
MOO_ASSERT (moo, MOO_CLASSOF(moo,ass) == moo->_association);
MOO_ASSERT (moo, MOO_CLASSOF(moo,ass->key) == moo->_symbol);
if (MOO_OBJ_GET_SIZE(key) == MOO_OBJ_GET_SIZE(ass->key) &&
moo_equaloochars (key->slot, ((moo_oop_char_t)ass->key)->slot, MOO_OBJ_GET_SIZE(key)))
{
/* the value of MOO_NULL indicates no insertion or update. */
if (value) ass->value = value; /* update */
return ass;
}
index = (index + 1) % MOO_OBJ_GET_SIZE(dic->bucket);
}
if (!value)
{
/* when value is MOO_NULL, perform no insertion.
* the value of MOO_NULL indicates no insertion or update. */
moo->errnum = MOO_ENOENT;
return MOO_NULL;
}
/* the key is not found. insert it. */
MOO_ASSERT (moo, MOO_OOP_IS_SMOOI(dic->tally));
tally = MOO_OOP_TO_SMOOI(dic->tally);
if (tally >= MOO_SMOOI_MAX)
{
/* this built-in dictionary is not allowed to hold more than
* MOO_SMOOI_MAX items for efficiency sake */
moo->errnum = MOO_EDFULL;
return MOO_NULL;
}
moo_pushtmp (moo, (moo_oop_t*)&dic); tmp_count++;
moo_pushtmp (moo, (moo_oop_t*)&key); tmp_count++;
moo_pushtmp (moo, &value); tmp_count++;
/* no conversion to moo_oow_t is necessary for tally + 1.
* the maximum value of tally is checked to be MOO_SMOOI_MAX - 1.
* tally + 1 can produce at most MOO_SMOOI_MAX. above all,
* MOO_SMOOI_MAX is way smaller than MOO_TYPE_MAX(moo_ooi_t). */
if (tally + 1 >= MOO_OBJ_GET_SIZE(dic->bucket))
{
moo_oop_oop_t bucket;
/* TODO: make the growth policy configurable instead of growing
it just before it gets full. The polcy can be grow it
if it's 70% full */
/* enlarge the bucket before it gets full to
* make sure that it has at least one free slot left
* after having added a new symbol. this is to help
* traversal end at a _nil slot if no entry is found. */
bucket = expand_bucket (moo, dic->bucket);
if (!bucket) goto oops;
dic->bucket = bucket;
/* recalculate the index for the expanded bucket */
index = hv % MOO_OBJ_GET_SIZE(dic->bucket);
while (dic->bucket->slot[index] != moo->_nil)
index = (index + 1) % MOO_OBJ_GET_SIZE(dic->bucket);
}
/* create a new assocation of a key and a value since
* the key isn't found in the root dictionary */
ass = (moo_oop_association_t)moo_instantiate (moo, moo->_association, MOO_NULL, 0);
if (!ass) goto oops;
ass->key = (moo_oop_t)key;
ass->value = value;
/* the current tally must be less than the maximum value. otherwise,
* it overflows after increment below */
MOO_ASSERT (moo, tally < MOO_SMOOI_MAX);
dic->tally = MOO_SMOOI_TO_OOP(tally + 1);
dic->bucket->slot[index] = (moo_oop_t)ass;
moo_poptmps (moo, tmp_count);
return ass;
oops:
moo_poptmps (moo, tmp_count);
return MOO_NULL;
}
static moo_oop_association_t lookup (moo_t* moo, moo_oop_set_t dic, const moo_oocs_t* name)
{
/* this is special version of moo_getatsysdic() that performs
* lookup using a plain string specified */
moo_oow_t index;
moo_oop_association_t ass;
MOO_ASSERT (moo, MOO_CLASSOF(moo,dic->tally) == moo->_small_integer);
MOO_ASSERT (moo, MOO_CLASSOF(moo,dic->bucket) == moo->_array);
index = moo_hashoochars(name->ptr, name->len) % MOO_OBJ_GET_SIZE(dic->bucket);
while (dic->bucket->slot[index] != moo->_nil)
{
ass = (moo_oop_association_t)dic->bucket->slot[index];
MOO_ASSERT (moo, MOO_CLASSOF(moo,ass) == moo->_association);
MOO_ASSERT (moo, MOO_CLASSOF(moo,ass->key) == moo->_symbol);
if (name->len == MOO_OBJ_GET_SIZE(ass->key) &&
moo_equaloochars(name->ptr, ((moo_oop_char_t)ass->key)->slot, name->len))
{
return ass;
}
index = (index + 1) % MOO_OBJ_GET_SIZE(dic->bucket);
}
/* when value is MOO_NULL, perform no insertion */
moo->errnum = MOO_ENOENT;
return MOO_NULL;
}
moo_oop_association_t moo_putatsysdic (moo_t* moo, moo_oop_t key, moo_oop_t value)
{
MOO_ASSERT (moo, MOO_CLASSOF(moo,key) == moo->_symbol);
return find_or_upsert (moo, moo->sysdic, (moo_oop_char_t)key, value);
}
moo_oop_association_t moo_getatsysdic (moo_t* moo, moo_oop_t key)
{
MOO_ASSERT (moo, MOO_CLASSOF(moo,key) == moo->_symbol);
return find_or_upsert (moo, moo->sysdic, (moo_oop_char_t)key, MOO_NULL);
}
moo_oop_association_t moo_lookupsysdic (moo_t* moo, const moo_oocs_t* name)
{
return lookup (moo, moo->sysdic, name);
}
moo_oop_association_t moo_putatdic (moo_t* moo, moo_oop_set_t dic, moo_oop_t key, moo_oop_t value)
{
MOO_ASSERT (moo, MOO_CLASSOF(moo,key) == moo->_symbol);
return find_or_upsert (moo, dic, (moo_oop_char_t)key, value);
}
moo_oop_association_t moo_getatdic (moo_t* moo, moo_oop_set_t dic, moo_oop_t key)
{
MOO_ASSERT (moo, MOO_CLASSOF(moo,key) == moo->_symbol);
return find_or_upsert (moo, dic, (moo_oop_char_t)key, MOO_NULL);
}
moo_oop_association_t moo_lookupdic (moo_t* moo, moo_oop_set_t dic, const moo_oocs_t* name)
{
return lookup (moo, dic, name);
}
int moo_deletedic (moo_t* moo, moo_oop_set_t dic, const moo_oocs_t* name)
{
moo_ooi_t tally;
moo_oow_t hv, index, bs, i, x, y, z;
moo_oop_association_t ass;
MOO_ASSERT (moo, MOO_CLASSOF(moo,dic->tally) == moo->_small_integer);
MOO_ASSERT (moo, MOO_CLASSOF(moo,dic->bucket) == moo->_array);
tally = MOO_OOP_TO_SMOOI(dic->tally);
bs = MOO_OBJ_GET_SIZE(dic->bucket);
hv = moo_hashoochars(name->ptr, name->len) % bs;
index = hv % bs;
/* find */
while (dic->bucket->slot[index] != moo->_nil)
{
ass = (moo_oop_association_t)dic->bucket->slot[index];
MOO_ASSERT (moo, MOO_CLASSOF(moo,ass) == moo->_association);
MOO_ASSERT (moo, MOO_CLASSOF(moo,ass->key) == moo->_symbol);
if (name->len == MOO_OBJ_GET_SIZE(ass->key) &&
moo_equaloochars(name->ptr, ((moo_oop_char_t)ass->key)->slot, name->len))
{
goto found;
}
index = (index + 1) % bs;
}
moo->errnum = MOO_ENOENT;
return -1;
found:
/* compact the cluster */
for (i = 0, x = index, y = index; i < tally; i++)
{
y = (y + 1) % bs;
/* done if the slot at the current index is empty */
if (dic->bucket->slot[y] == moo->_nil) break;
/* get the natural hash index for the data in the slot at
* the current hash index */
ass = (moo_oop_association_t)dic->bucket->slot[y];
z = moo_hashoochars(((moo_oop_char_t)ass->key)->slot, MOO_OBJ_GET_SIZE(ass->key)) % bs;
/* move an element if necesary */
if ((y > x && (z <= x || z > y)) ||
(y < x && (z <= x && z > y)))
{
dic->bucket->slot[x] = dic->bucket->slot[y];
x = y;
}
}
dic->bucket->slot[x] = moo->_nil;
tally--;
dic->tally = MOO_SMOOI_TO_OOP(tally);
return 0;
}
moo_oop_set_t moo_makedic (moo_t* moo, moo_oop_t cls, moo_oow_t size)
{
moo_oop_set_t dic;
moo_oop_t tmp;
MOO_ASSERT (moo, MOO_CLASSOF(moo,cls) == moo->_class);
dic = (moo_oop_set_t)moo_instantiate (moo, cls, MOO_NULL, 0);
if (!dic) return MOO_NULL;
MOO_ASSERT (moo, MOO_OBJ_GET_SIZE(dic) == MOO_SET_NAMED_INSTVARS);
moo_pushtmp (moo, (moo_oop_t*)&dic);
tmp = moo_instantiate (moo, moo->_array, MOO_NULL, size);
moo_poptmp (moo);
if (!tmp) return MOO_NULL;
dic->tally = MOO_SMOOI_TO_OOP(0);
dic->bucket = (moo_oop_oop_t)tmp;
MOO_ASSERT (moo, MOO_OBJ_GET_SIZE(dic) == MOO_SET_NAMED_INSTVARS);
MOO_ASSERT (moo, MOO_OBJ_GET_SIZE(dic->bucket) == size);
return dic;
}

243
moo/lib/err.c Normal file
View File

@ -0,0 +1,243 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
/* BEGIN: GENERATED WITH generr.st */
static moo_ooch_t errstr_0[] = {'n','o',' ','e','r','r','o','r','\0'};
static moo_ooch_t errstr_1[] = {'g','e','n','e','r','i','c',' ','e','r','r','o','r','\0'};
static moo_ooch_t errstr_2[] = {'n','o','t',' ','i','m','p','l','e','m','e','n','t','e','d','\0'};
static moo_ooch_t errstr_3[] = {'s','u','b','s','y','s','t','e','m',' ','e','r','r','o','r','\0'};
static moo_ooch_t errstr_4[] = {'i','n','t','e','r','n','a','l',' ','e','r','r','o','r',' ','t','h','a','t',' ','s','h','o','u','l','d',' ','n','e','v','e','r',' ','h','a','v','e',' ','h','a','p','p','e','n','e','d','\0'};
static moo_ooch_t errstr_5[] = {'i','n','s','u','f','f','i','c','i','e','n','t',' ','s','y','s','t','e','m',' ','m','e','m','o','r','y','\0'};
static moo_ooch_t errstr_6[] = {'i','n','s','u','f','f','i','c','i','e','n','t',' ','o','b','j','e','c','t',' ','m','e','m','o','r','y','\0'};
static moo_ooch_t errstr_7[] = {'i','n','v','a','l','i','d',' ','p','a','r','a','m','e','t','e','r',' ','o','r',' ','a','r','g','u','m','e','n','t','\0'};
static moo_ooch_t errstr_8[] = {'d','a','t','a',' ','n','o','t',' ','f','o','u','n','d','\0'};
static moo_ooch_t errstr_9[] = {'e','x','i','s','t','i','n','g','/','d','u','p','l','i','c','a','t','e',' ','d','a','t','a','\0'};
static moo_ooch_t errstr_10[] = {'b','u','s','y','\0'};
static moo_ooch_t errstr_11[] = {'a','c','c','e','s','s',' ','d','e','n','i','e','d','\0'};
static moo_ooch_t errstr_12[] = {'o','p','e','r','a','t','i','o','n',' ','n','o','t',' ','p','e','r','m','i','t','t','e','d','\0'};
static moo_ooch_t errstr_13[] = {'n','o','t',' ','a',' ','d','i','r','e','c','t','o','r','y','\0'};
static moo_ooch_t errstr_14[] = {'i','n','t','e','r','r','u','p','t','e','d','\0'};
static moo_ooch_t errstr_15[] = {'p','i','p','e',' ','e','r','r','o','r','\0'};
static moo_ooch_t errstr_16[] = {'r','e','s','o','u','r','c','e',' ','t','e','m','p','o','r','a','r','i','l','y',' ','u','n','a','v','a','i','l','a','b','l','e','\0'};
static moo_ooch_t errstr_17[] = {'d','a','t','a',' ','t','o','o',' ','l','a','r','g','e','\0'};
static moo_ooch_t errstr_18[] = {'m','e','s','s','a','g','e',' ','s','e','n','d','i','n','g',' ','e','r','r','o','r','\0'};
static moo_ooch_t errstr_19[] = {'r','a','n','g','e',' ','e','r','r','o','r','\0'};
static moo_ooch_t errstr_20[] = {'b','y','t','e','-','c','o','d','e',' ','f','u','l','l','\0'};
static moo_ooch_t errstr_21[] = {'d','i','c','t','i','o','n','a','r','y',' ','f','u','l','l','\0'};
static moo_ooch_t errstr_22[] = {'p','r','o','c','e','s','s','o','r',' ','f','u','l','l','\0'};
static moo_ooch_t errstr_23[] = {'s','e','m','a','p','h','o','r','e',' ','h','e','a','p',' ','f','u','l','l','\0'};
static moo_ooch_t errstr_24[] = {'s','e','m','a','p','h','o','r','e',' ','l','i','s','t',' ','f','u','l','l','\0'};
static moo_ooch_t errstr_25[] = {'d','i','v','i','d','e',' ','b','y',' ','z','e','r','o','\0'};
static moo_ooch_t errstr_26[] = {'I','/','O',' ','e','r','r','o','r','\0'};
static moo_ooch_t errstr_27[] = {'e','n','c','o','d','i','n','g',' ','c','o','n','v','e','r','s','i','o','n',' ','e','r','r','o','r','\0'};
static moo_ooch_t* errstr[] =
{
errstr_0, errstr_1, errstr_2, errstr_3, errstr_4, errstr_5, errstr_6, errstr_7,
errstr_8, errstr_9, errstr_10, errstr_11, errstr_12, errstr_13, errstr_14, errstr_15,
errstr_16, errstr_17, errstr_18, errstr_19, errstr_20, errstr_21, errstr_22, errstr_23,
errstr_24, errstr_25, errstr_26, errstr_27
};
#if defined(MOO_INCLUDE_COMPILER)
static moo_ooch_t synerrstr_0[] = {'n','o',' ','e','r','r','o','r','\0'};
static moo_ooch_t synerrstr_1[] = {'i','l','l','e','g','a','l',' ','c','h','a','r','a','c','t','e','r','\0'};
static moo_ooch_t synerrstr_2[] = {'c','o','m','m','e','n','t',' ','n','o','t',' ','c','l','o','s','e','d','\0'};
static moo_ooch_t synerrstr_3[] = {'s','t','r','i','n','g',' ','n','o','t',' ','c','l','o','s','e','d','\0'};
static moo_ooch_t synerrstr_4[] = {'n','o',' ','c','h','a','r','a','c','t','e','r',' ','a','f','t','e','r',' ','$','\0'};
static moo_ooch_t synerrstr_5[] = {'n','o',' ','v','a','l','i','d',' ','c','h','a','r','a','c','t','e','r',' ','a','f','t','e','r',' ','#','\0'};
static moo_ooch_t synerrstr_6[] = {'w','r','o','n','g',' ','c','h','a','r','a','c','t','e','r',' ','l','i','t','e','r','a','l','\0'};
static moo_ooch_t synerrstr_7[] = {'c','o','l','o','n',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_8[] = {'s','t','r','i','n','g',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_9[] = {'i','n','v','a','l','i','d',' ','r','a','d','i','x','\0'};
static moo_ooch_t synerrstr_10[] = {'i','n','v','a','l','i','d',' ','n','u','m','e','r','i','c',' ','l','i','t','e','r','a','l','\0'};
static moo_ooch_t synerrstr_11[] = {'b','y','t','e',' ','t','o','o',' ','s','m','a','l','l',' ','o','r',' ','t','o','o',' ','l','a','r','g','e','\0'};
static moo_ooch_t synerrstr_12[] = {'w','r','o','n','g',' ','e','r','r','o','r',' ','l','i','t','e','r','a','l','\0'};
static moo_ooch_t synerrstr_13[] = {'{',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_14[] = {'}',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_15[] = {'(',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_16[] = {')',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_17[] = {']',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_18[] = {'.',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_19[] = {' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_20[] = {'|',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_21[] = {'>',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_22[] = {':','=',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_23[] = {'i','d','e','n','t','i','f','i','e','r',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_24[] = {'i','n','t','e','g','e','r',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_25[] = {'p','r','i','m','i','t','i','v','e',':',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t synerrstr_26[] = {'w','r','o','n','g',' ','d','i','r','e','c','t','i','v','e','\0'};
static moo_ooch_t synerrstr_27[] = {'u','n','d','e','f','i','n','e','d',' ','c','l','a','s','s','\0'};
static moo_ooch_t synerrstr_28[] = {'d','u','p','l','i','c','a','t','e',' ','c','l','a','s','s','\0'};
static moo_ooch_t synerrstr_29[] = {'c','o','n','t','r','a','d','i','c','t','o','r','y',' ','c','l','a','s','s',' ','d','e','f','i','n','i','t','i','o','n','\0'};
static moo_ooch_t synerrstr_30[] = {'w','r','o','n','g',' ','c','l','a','s','s',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_31[] = {'#','d','c','l',' ','n','o','t',' ','a','l','l','o','w','e','d','\0'};
static moo_ooch_t synerrstr_32[] = {'w','r','o','n','g',' ','m','e','t','h','o','d',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_33[] = {'d','u','p','l','i','c','a','t','e',' ','m','e','t','h','o','d',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_34[] = {'d','u','p','l','i','c','a','t','e',' ','a','r','g','u','m','e','n','t',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_35[] = {'d','u','p','l','i','c','a','t','e',' ','t','e','m','p','o','r','a','r','y',' ','v','a','r','i','a','b','l','e',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_36[] = {'d','u','p','l','i','c','a','t','e',' ','v','a','r','i','a','b','l','e',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_37[] = {'d','u','p','l','i','c','a','t','e',' ','b','l','o','c','k',' ','a','r','g','u','m','e','n','t',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_38[] = {'c','a','n','n','o','t',' ','a','s','s','i','g','n',' ','t','o',' ','a','r','g','u','m','e','n','t','\0'};
static moo_ooch_t synerrstr_39[] = {'u','n','d','e','c','l','a','r','e','d',' ','v','a','r','i','a','b','l','e','\0'};
static moo_ooch_t synerrstr_40[] = {'u','n','u','s','a','b','l','e',' ','v','a','r','i','a','b','l','e',' ','i','n',' ','c','o','m','p','i','l','e','d',' ','c','o','d','e','\0'};
static moo_ooch_t synerrstr_41[] = {'i','n','a','c','c','e','s','s','i','b','l','e',' ','v','a','r','i','a','b','l','e','\0'};
static moo_ooch_t synerrstr_42[] = {'a','m','b','i','g','u','o','u','s',' ','v','a','r','i','a','b','l','e','\0'};
static moo_ooch_t synerrstr_43[] = {'w','r','o','n','g',' ','e','x','p','r','e','s','s','i','o','n',' ','p','r','i','m','a','r','y','\0'};
static moo_ooch_t synerrstr_44[] = {'t','o','o',' ','m','a','n','y',' ','t','e','m','p','o','r','a','r','i','e','s','\0'};
static moo_ooch_t synerrstr_45[] = {'t','o','o',' ','m','a','n','y',' ','a','r','g','u','m','e','n','t','s','\0'};
static moo_ooch_t synerrstr_46[] = {'t','o','o',' ','m','a','n','y',' ','b','l','o','c','k',' ','t','e','m','p','o','r','a','r','i','e','s','\0'};
static moo_ooch_t synerrstr_47[] = {'t','o','o',' ','m','a','n','y',' ','b','l','o','c','k',' ','a','r','g','u','m','e','n','t','s','\0'};
static moo_ooch_t synerrstr_48[] = {'t','o','o',' ','l','a','r','g','e',' ','b','l','o','c','k','\0'};
static moo_ooch_t synerrstr_49[] = {'w','r','o','n','g',' ','p','r','i','m','i','t','i','v','e',' ','f','u','n','c','t','i','o','n',' ','n','u','m','b','e','r','\0'};
static moo_ooch_t synerrstr_50[] = {'w','r','o','n','g',' ','p','r','i','m','i','t','i','v','e',' ','f','u','n','c','t','i','o','n',' ','i','d','e','n','t','i','f','i','e','r','\0'};
static moo_ooch_t synerrstr_51[] = {'w','r','o','n','g',' ','m','o','d','u','l','e',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_52[] = {'#','i','n','c','l','u','d','e',' ','e','r','r','o','r','\0'};
static moo_ooch_t synerrstr_53[] = {'w','r','o','n','g',' ','n','a','m','e','s','p','a','c','e',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_54[] = {'w','r','o','n','g',' ','p','o','o','l',' ','d','i','c','t','i','o','n','a','r','y',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_55[] = {'d','u','p','l','i','c','a','t','e',' ','p','o','o','l',' ','d','i','c','t','i','o','n','a','r','y',' ','n','a','m','e','\0'};
static moo_ooch_t synerrstr_56[] = {'l','i','t','e','r','a','l',' ','e','x','p','e','c','t','e','d','\0'};
static moo_ooch_t* synerrstr[] =
{
synerrstr_0, synerrstr_1, synerrstr_2, synerrstr_3, synerrstr_4, synerrstr_5, synerrstr_6, synerrstr_7,
synerrstr_8, synerrstr_9, synerrstr_10, synerrstr_11, synerrstr_12, synerrstr_13, synerrstr_14, synerrstr_15,
synerrstr_16, synerrstr_17, synerrstr_18, synerrstr_19, synerrstr_20, synerrstr_21, synerrstr_22, synerrstr_23,
synerrstr_24, synerrstr_25, synerrstr_26, synerrstr_27, synerrstr_28, synerrstr_29, synerrstr_30, synerrstr_31,
synerrstr_32, synerrstr_33, synerrstr_34, synerrstr_35, synerrstr_36, synerrstr_37, synerrstr_38, synerrstr_39,
synerrstr_40, synerrstr_41, synerrstr_42, synerrstr_43, synerrstr_44, synerrstr_45, synerrstr_46, synerrstr_47,
synerrstr_48, synerrstr_49, synerrstr_50, synerrstr_51, synerrstr_52, synerrstr_53, synerrstr_54, synerrstr_55,
synerrstr_56
};
#endif
/* END: GENERATED WITH generr.st */
/* --------------------------------------------------------------------------
* ERROR NUMBER TO STRING CONVERSION
* -------------------------------------------------------------------------- */
const moo_ooch_t* moo_errnumtoerrstr (moo_errnum_t errnum)
{
static moo_ooch_t e_unknown[] = {'u','n','k','n','o','w','n',' ','e','r','r','o','r','\0'};
return (errnum >= 0 && errnum < MOO_COUNTOF(errstr))? errstr[errnum]: e_unknown;
}
#if defined(MOO_INCLUDE_COMPILER)
const moo_ooch_t* moo_synerrnumtoerrstr (moo_synerrnum_t errnum)
{
static moo_ooch_t e_unknown[] = {'u','n','k','n','o','w','n',' ','e','r','r','o','r','\0'};
return (errnum >= 0 && errnum < MOO_COUNTOF(synerrstr))? synerrstr[errnum]: e_unknown;
}
#endif
/* --------------------------------------------------------------------------
* SYSTEM DEPENDENT FUNCTIONS
* -------------------------------------------------------------------------- */
#if defined(_WIN32)
# include <windows.h>
#elif defined(__OS2__)
# define INCL_DOSPROCESS
# define INCL_DOSFILEMGR
# include <os2.h>
#elif defined(__DOS__)
# include <dos.h>
# include <dosfunc.h>
#elif defined(vms) || defined(__vms)
# define __NEW_STARLET 1
# include <starlet.h> /* (SYS$...) */
# include <ssdef.h> /* (SS$...) */
# include <lib$routines.h> /* (lib$...) */
#elif defined(macintosh)
# include <Process.h>
# include <Dialogs.h>
# include <TextUtils.h>
#else
# include <sys/types.h>
# include <unistd.h>
# include <signal.h>
# include <errno.h>
#endif
moo_errnum_t moo_syserrtoerrnum (int e)
{
switch (e)
{
case ENOMEM: return MOO_ESYSMEM;
case EINVAL: return MOO_EINVAL;
case EBUSY: return MOO_EBUSY;
case EACCES: return MOO_EACCES;
case EPERM: return MOO_EPERM;
case ENOTDIR: return MOO_ENOTDIR;
case ENOENT: return MOO_ENOENT;
case EEXIST: return MOO_EEXIST;
case EINTR: return MOO_EINTR;
case EPIPE: return MOO_EPIPE;
#if defined(EAGAIN) && defined(EWOULDBLOCK) && (EAGAIN != EWOULDBLOCK)
case EAGAIN:
case EWOULDBLOCK: return MOO_EAGAIN;
#elif defined(EAGAIN)
case EAGAIN: return MOO_EAGAIN;
#elif defined(EWOULDBLOCK)
case EWOULDBLOCK: return MOO_EAGAIN;
#endif
default: return MOO_ESYSERR;
}
}
/* --------------------------------------------------------------------------
* ASSERTION FAILURE HANDLER
* -------------------------------------------------------------------------- */
void moo_assertfailed (moo_t* moo, const moo_bch_t* expr, const moo_bch_t* file, moo_oow_t line)
{
moo_logbfmt (moo, MOO_LOG_DEBUG, "ASSERTION FAILURE: %s at %s:%zu\n", expr, file, line);
#if defined(_WIN32)
ExitProcess (249);
#elif defined(__OS2__)
DosExit (EXIT_PROCESS, 249);
#elif defined(__DOS__)
{
union REGS regs;
regs.h.ah = DOS_EXIT;
regs.h.al = 249;
intdos (&regs, &regs);
}
#elif defined(vms) || defined(__vms)
lib$stop (SS$_ABORT); /* use SS$_OPCCUS instead? */
/* this won't be reached since lib$stop() terminates the process */
sys$exit (SS$_ABORT); /* this condition code can be shown with
* 'show symbol $status' from the command-line. */
#elif defined(macintosh)
ExitToShell ();
#else
kill (getpid(), SIGABRT);
_exit (1);
#endif
}

4444
moo/lib/exec.c Normal file

File diff suppressed because it is too large Load Diff

742
moo/lib/gc.c Normal file
View File

@ -0,0 +1,742 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
/*
* Stix .....................
* ^ ^ ^ : .......
* | | | v v :
* | | +------------------- Class .....
* | | ^ ^
* | +-------- NilObject ......: :
* | ^........ nil :
* Object ...........................:
* ^
* |
*
* The class hierarchy is roughly as follows:
*
* Stix
* Class
* NilObject
* Object
* Collection
* IndexedCollection
* FixedSizedCollection
* Array
* ByteArray
* String
* Symbol
* Set
* Dictionary
* SystemDictionary
* SymbolSet
* Magnitude
* Association
* Character
* Number
* Integer
* SmallInteger
* LargeInteger
* LargePositiveInteger
* LargeNegativeInteger
*
* Stix has no instance variables.
* Stix has 1 class variable: Sysdic
*
*/
struct kernel_class_info_t
{
moo_oow_t len;
moo_ooch_t name[20];
moo_oow_t offset;
};
typedef struct kernel_class_info_t kernel_class_info_t;
static kernel_class_info_t kernel_classes[] =
{
{ 4, { 'A','p','e','x' }, MOO_OFFSETOF(moo_t,_apex) },
{ 15, { 'U','n','d','e','f','i','n','e','d','O','b','j','e','c','t' }, MOO_OFFSETOF(moo_t,_undefined_object) },
{ 5, { 'C','l','a','s','s' }, MOO_OFFSETOF(moo_t,_class) },
{ 6, { 'O','b','j','e','c','t' }, MOO_OFFSETOF(moo_t,_object) },
{ 6, { 'S','t','r','i','n','g' }, MOO_OFFSETOF(moo_t,_string) },
{ 6, { 'S','y','m','b','o','l' }, MOO_OFFSETOF(moo_t,_symbol) },
{ 5, { 'A','r','r','a','y' }, MOO_OFFSETOF(moo_t,_array) },
{ 9, { 'B','y','t','e','A','r','r','a','y' }, MOO_OFFSETOF(moo_t,_byte_array) },
{ 9, { 'S','y','m','b','o','l','S','e','t' }, MOO_OFFSETOF(moo_t,_symbol_set) },
{ 16, { 'S','y','s','t','e','m','D','i','c','t','i','o','n','a','r','y' }, MOO_OFFSETOF(moo_t, _system_dictionary) },
{ 9, { 'N','a','m','e','s','p','a','c','e' }, MOO_OFFSETOF(moo_t, _namespace) },
{ 14, { 'P','o','o','l','D','i','c','t','i','o','n','a','r','y' }, MOO_OFFSETOF(moo_t, _pool_dictionary) },
{ 16, { 'M','e','t','h','o','d','D','i','c','t','i','o','n','a','r','y' }, MOO_OFFSETOF(moo_t, _method_dictionary) },
{ 14, { 'C','o','m','p','i','l','e','d','M','e','t','h','o','d' }, MOO_OFFSETOF(moo_t, _method) },
{ 11, { 'A','s','s','o','c','i','a','t','i','o','n' }, MOO_OFFSETOF(moo_t, _association) },
{ 13, { 'M','e','t','h','o','d','C','o','n','t','e','x','t' }, MOO_OFFSETOF(moo_t, _method_context) },
{ 12, { 'B','l','o','c','k','C','o','n','t','e','x','t' }, MOO_OFFSETOF(moo_t, _block_context) },
{ 7, { 'P','r','o','c','e','s','s' }, MOO_OFFSETOF(moo_t, _process) },
{ 9, { 'S','e','m','a','p','h','o','r','e' }, MOO_OFFSETOF(moo_t, _semaphore) },
{ 16, { 'P','r','o','c','e','s','s','S','c','h','e','d','u','l','e','r' }, MOO_OFFSETOF(moo_t, _process_scheduler) },
{ 5, { 'E','r','r','o','r' }, MOO_OFFSETOF(moo_t, _error_class) },
{ 4, { 'T','r','u','e' }, MOO_OFFSETOF(moo_t, _true_class) },
{ 5, { 'F','a','l','s','e' }, MOO_OFFSETOF(moo_t, _false_class) },
{ 9, { 'C','h','a','r','a','c','t','e','r' }, MOO_OFFSETOF(moo_t, _character) },
{ 12, { 'S','m','a','l','l','I','n','t','e','g','e','r' }, MOO_OFFSETOF(moo_t, _small_integer) },
{ 20, { 'L','a','r','g','e','P','o','s','i','t','i','v','e','I','n','t','e','g','e','r' }, MOO_OFFSETOF(moo_t, _large_positive_integer) },
{ 20, { 'L','a','r','g','e','N','e','g','a','t','i','v','e','I','n','t','e','g','e','r' }, MOO_OFFSETOF(moo_t, _large_negative_integer) }
};
/* -----------------------------------------------------------------------
* BOOTSTRAPPER
* ----------------------------------------------------------------------- */
static moo_oop_t alloc_kernel_class (moo_t* moo, moo_oow_t indexed_classvars, moo_oow_t spec)
{
moo_oop_class_t c;
c = (moo_oop_class_t)moo_allocoopobj (moo, MOO_CLASS_NAMED_INSTVARS + indexed_classvars);
if (!c) return MOO_NULL;
MOO_OBJ_SET_FLAGS_KERNEL (c, 1);
MOO_OBJ_SET_CLASS (c, moo->_class);
c->spec = MOO_SMOOI_TO_OOP(spec);
c->selfspec = MOO_SMOOI_TO_OOP(MOO_CLASS_SELFSPEC_MAKE(indexed_classvars, 0));
return (moo_oop_t)c;
}
static int ignite_1 (moo_t* moo)
{
/*
* Create fundamental class objects with some fields mis-initialized yet.
* Such fields include 'superclass', 'subclasses', 'name', etc.
*/
MOO_ASSERT (moo, moo->_nil != MOO_NULL);
MOO_ASSERT (moo, MOO_OBJ_GET_CLASS(moo->_nil) == MOO_NULL);
MOO_ASSERT (moo, moo->_class == MOO_NULL);
/* --------------------------------------------------------------
* Class
* The instance of Class can have indexed instance variables
* which are actually class variables.
* -------------------------------------------------------------- */
moo->_class = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_CLASS_NAMED_INSTVARS, 1, MOO_OBJ_TYPE_OOP));
if (!moo->_class) return -1;
MOO_ASSERT (moo, MOO_OBJ_GET_CLASS(moo->_class) == MOO_NULL);
MOO_OBJ_SET_CLASS (moo->_class, moo->_class);
/* --------------------------------------------------------------
* Apex - proto-object with 1 class variable.
* UndefinedObject - class for the nil object.
* Object - top of all ordinary objects.
* String
* Symbol
* Array
* ByteArray
* SymbolSet
* Character
* SmallIntger
* -------------------------------------------------------------- */
moo->_apex = alloc_kernel_class (moo, 1, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_undefined_object = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_object = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_string = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_CHAR));
moo->_symbol = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_CHAR));
moo->_array = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_OOP));
moo->_byte_array = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_BYTE));
moo->_symbol_set = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_system_dictionary = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_namespace = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_pool_dictionary = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_method_dictionary = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_method = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_METHOD_NAMED_INSTVARS, 1, MOO_OBJ_TYPE_OOP));
moo->_association = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_ASSOCIATION_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_method_context = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_CONTEXT_NAMED_INSTVARS, 1, MOO_OBJ_TYPE_OOP));
moo->_block_context = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_CONTEXT_NAMED_INSTVARS, 1, MOO_OBJ_TYPE_OOP));
moo->_process = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_PROCESS_NAMED_INSTVARS, 1, MOO_OBJ_TYPE_OOP));
moo->_semaphore = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_SEMAPHORE_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_process_scheduler = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(MOO_PROCESS_SCHEDULER_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_error_class = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_true_class = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_false_class = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
/* TOOD: what is a proper spec for Character and SmallInteger?
* If the fixed part is 0, its instance must be an object of 0 payload fields.
* Does this make sense? */
moo->_character = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_small_integer = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_large_positive_integer = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_LIWORD));
moo->_large_negative_integer = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_LIWORD));
if (!moo->_apex || !moo->_undefined_object ||
!moo->_object || !moo->_string ||
!moo->_symbol || !moo->_array ||
!moo->_byte_array || !moo->_symbol_set || !moo->_system_dictionary ||
!moo->_namespace || !moo->_pool_dictionary ||
!moo->_method_dictionary || !moo->_method || !moo->_association ||
!moo->_method_context || !moo->_block_context ||
!moo->_process || !moo->_semaphore || !moo->_process_scheduler ||
!moo->_true_class || !moo->_false_class ||
!moo->_character || !moo->_small_integer ||
!moo->_large_positive_integer || !moo->_large_negative_integer) return -1;
MOO_OBJ_SET_CLASS (moo->_nil, moo->_undefined_object);
return 0;
}
static int ignite_2 (moo_t* moo)
{
moo_oop_t tmp;
/* Create 'true' and 'false objects */
moo->_true = moo_instantiate (moo, moo->_true_class, MOO_NULL, 0);
moo->_false = moo_instantiate (moo, moo->_false_class, MOO_NULL, 0);
if (!moo->_true || !moo->_false) return -1;
/* Create the symbol table */
tmp = moo_instantiate (moo, moo->_symbol_set, MOO_NULL, 0);
if (!tmp) return -1;
moo->symtab = (moo_oop_set_t)tmp;
moo->symtab->tally = MOO_SMOOI_TO_OOP(0);
/* It's important to assign the result of moo_instantiate() to a temporary
* variable first and then assign it to moo->symtab->bucket.
* The pointer 'moo->symtab; can change in moo_instantiate() and the
* target address of assignment may get set before moo_instantiate()
* is called. */
tmp = moo_instantiate (moo, moo->_array, MOO_NULL, moo->option.dfl_symtab_size);
if (!tmp) return -1;
moo->symtab->bucket = (moo_oop_oop_t)tmp;
/* Create the system dictionary */
tmp = (moo_oop_t)moo_makedic (moo, moo->_system_dictionary, moo->option.dfl_sysdic_size);
if (!tmp) return -1;
moo->sysdic = (moo_oop_set_t)tmp;
/* Create a nil process used to simplify nil check in GC.
* only accessible by VM. not exported via the global dictionary. */
tmp = (moo_oop_t)moo_instantiate (moo, moo->_process, MOO_NULL, 0);
if (!tmp) return -1;
moo->nil_process = (moo_oop_process_t)tmp;
moo->nil_process->sp = MOO_SMOOI_TO_OOP(-1);
/* Create a process scheduler */
tmp = (moo_oop_t)moo_instantiate (moo, moo->_process_scheduler, MOO_NULL, 0);
if (!tmp) return -1;
moo->processor = (moo_oop_process_scheduler_t)tmp;
moo->processor->tally = MOO_SMOOI_TO_OOP(0);
moo->processor->active = moo->nil_process;
/* Export the system dictionary via the first class variable of the Stix class */
((moo_oop_class_t)moo->_apex)->slot[0] = (moo_oop_t)moo->sysdic;
return 0;
}
static int ignite_3 (moo_t* moo)
{
/* Register kernel classes manually created so far to the system dictionary */
static moo_ooch_t str_system[] = { 'S','y','s','t','e', 'm' };
static moo_ooch_t str_processor[] = { 'P', 'r', 'o', 'c', 'e', 's', 's', 'o', 'r' };
moo_oow_t i;
moo_oop_t sym, cls;
moo_oop_t* moo_ptr;
for (i = 0; i < MOO_COUNTOF(kernel_classes); i++)
{
sym = moo_makesymbol (moo, kernel_classes[i].name, kernel_classes[i].len);
if (!sym) return -1;
cls = *(moo_oop_t*)((moo_uint8_t*)moo + kernel_classes[i].offset);
if (!moo_putatsysdic(moo, sym, cls)) return -1;
moo_ptr++;
}
/* Make the system dictionary available as the global name 'Stix' */
sym = moo_makesymbol (moo, str_system, 6);
if (!sym) return -1;
if (!moo_putatsysdic(moo, sym, (moo_oop_t)moo->sysdic)) return -1;
/* Make the process scheduler avaialble as the global name 'Processor' */
sym = moo_makesymbol (moo, str_processor, 9);
if (!sym) return -1;
if (!moo_putatsysdic(moo, sym, (moo_oop_t)moo->processor)) return -1;
return 0;
}
int moo_ignite (moo_t* moo)
{
MOO_ASSERT (moo, moo->_nil == MOO_NULL);
moo->_nil = moo_allocbytes (moo, MOO_SIZEOF(moo_obj_t));
if (!moo->_nil) return -1;
moo->_nil->_flags = MOO_OBJ_MAKE_FLAGS (MOO_OBJ_TYPE_OOP, MOO_SIZEOF(moo_oop_t), 0, 1, 0, 0, 0);
moo->_nil->_size = 0;
if (ignite_1(moo) <= -1 || ignite_2(moo) <= -1 || ignite_3(moo)) return -1;
return 0;
}
/* -----------------------------------------------------------------------
* GARBAGE COLLECTOR
* ----------------------------------------------------------------------- */
static void compact_symbol_table (moo_t* moo, moo_oop_t _nil)
{
moo_oop_char_t symbol;
moo_oow_t i, x, y, z;
moo_oow_t bucket_size, index;
moo_ooi_t tally;
#if defined(MOO_SUPPORT_GC_DURING_IGNITION)
if (!moo->symtab) return; /* symbol table has not been created */
#endif
/* the symbol table doesn't allow more data items than MOO_SMOOI_MAX.
* so moo->symtab->tally must always be a small integer */
MOO_ASSERT (moo, MOO_OOP_IS_SMOOI(moo->symtab->tally));
tally = MOO_OOP_TO_SMOOI(moo->symtab->tally);
MOO_ASSERT (moo, tally >= 0); /* it must not be less than 0 */
if (tally <= 0) return;
/* NOTE: in theory, the bucket size can be greater than MOO_SMOOI_MAX
* as it is an internal header field and is of an unsigned type */
bucket_size = MOO_OBJ_GET_SIZE(moo->symtab->bucket);
for (index = 0; index < bucket_size; )
{
if (MOO_OBJ_GET_FLAGS_MOVED(moo->symtab->bucket->slot[index]))
{
index++;
continue;
}
MOO_ASSERT (moo, moo->symtab->bucket->slot[index] != _nil);
for (i = 0, x = index, y = index; i < bucket_size; i++)
{
y = (y + 1) % bucket_size;
/* done if the slot at the current hash index is _nil */
if (moo->symtab->bucket->slot[y] == _nil) break;
/* get the natural hash index for the data in the slot
* at the current hash index */
symbol = (moo_oop_char_t)moo->symtab->bucket->slot[y];
MOO_ASSERT (moo, MOO_CLASSOF(moo,symbol) == moo->_symbol);
z = moo_hashoochars(symbol->slot, MOO_OBJ_GET_SIZE(symbol)) % bucket_size;
/* move an element if necessary */
if ((y > x && (z <= x || z > y)) ||
(y < x && (z <= x && z > y)))
{
moo->symtab->bucket->slot[x] = moo->symtab->bucket->slot[y];
x = y;
}
}
moo->symtab->bucket->slot[x] = _nil;
tally--;
}
MOO_ASSERT (moo, tally >= 0);
MOO_ASSERT (moo, tally <= MOO_SMOOI_MAX);
moo->symtab->tally = MOO_SMOOI_TO_OOP(tally);
}
static MOO_INLINE moo_oow_t get_payload_bytes (moo_t* moo, moo_oop_t oop)
{
moo_oow_t nbytes_aligned;
#if defined(MOO_USE_OBJECT_TRAILER)
if (MOO_OBJ_GET_FLAGS_TRAILER(oop))
{
moo_oow_t nbytes;
/* only an OOP object can have the trailer.
*
* | _flags |
* | _size | <-- if it's 3
* | _class |
* | X |
* | X |
* | X |
* | Y | <-- it may exist if EXTRA is set in _flags.
* | Z | <-- if TRAILER is set, it is the number of bytes in the trailer
* | | | | |
*/
MOO_ASSERT (moo, MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_OOP);
MOO_ASSERT (moo, MOO_OBJ_GET_FLAGS_UNIT(oop) == MOO_SIZEOF(moo_oow_t));
MOO_ASSERT (moo, MOO_OBJ_GET_FLAGS_EXTRA(oop) == 0); /* no 'extra' for an OOP object */
nbytes = MOO_OBJ_BYTESOF(oop) + MOO_SIZEOF(moo_oow_t) + \
(moo_oow_t)((moo_oop_oop_t)oop)->slot[MOO_OBJ_GET_SIZE(oop)];
nbytes_aligned = MOO_ALIGN (nbytes, MOO_SIZEOF(moo_oop_t));
}
else
{
#endif
/* calculate the payload size in bytes */
nbytes_aligned = MOO_ALIGN (MOO_OBJ_BYTESOF(oop), MOO_SIZEOF(moo_oop_t));
#if defined(MOO_USE_OBJECT_TRAILER)
}
#endif
return nbytes_aligned;
}
moo_oop_t moo_moveoop (moo_t* moo, moo_oop_t oop)
{
#if defined(MOO_SUPPORT_GC_DURING_IGNITION)
if (!oop) return oop;
#endif
if (!MOO_OOP_IS_POINTER(oop)) return oop;
if (MOO_OBJ_GET_FLAGS_MOVED(oop))
{
/* this object has migrated to the new heap.
* the class field has been updated to the new object
* in the 'else' block below. i can simply return it
* without further migration. */
return MOO_OBJ_GET_CLASS(oop);
}
else
{
moo_oow_t nbytes_aligned;
moo_oop_t tmp;
nbytes_aligned = get_payload_bytes (moo, oop);
/* allocate space in the new heap */
tmp = moo_allocheapmem (moo, moo->newheap, MOO_SIZEOF(moo_obj_t) + nbytes_aligned);
/* allocation here must not fail because
* i'm allocating the new space in a new heap for
* moving an existing object in the current heap.
*
* assuming the new heap is as large as the old heap,
* and garbage collection doesn't allocate more objects
* than in the old heap, it must not fail. */
MOO_ASSERT (moo, tmp != MOO_NULL);
/* copy the payload to the new object */
MOO_MEMCPY (tmp, oop, MOO_SIZEOF(moo_obj_t) + nbytes_aligned);
/* mark the old object that it has migrated to the new heap */
MOO_OBJ_SET_FLAGS_MOVED(oop, 1);
/* let the class field of the old object point to the new
* object allocated in the new heap. it is returned in
* the 'if' block at the top of this function. */
MOO_OBJ_SET_CLASS (oop, tmp);
/* return the new object */
return tmp;
}
}
static moo_uint8_t* scan_new_heap (moo_t* moo, moo_uint8_t* ptr)
{
while (ptr < moo->newheap->ptr)
{
moo_oow_t i;
moo_oow_t nbytes_aligned;
moo_oop_t oop;
oop = (moo_oop_t)ptr;
#if defined(MOO_USE_OBJECT_TRAILER)
if (MOO_OBJ_GET_FLAGS_TRAILER(oop))
{
moo_oow_t nbytes;
MOO_ASSERT (moo, MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_OOP);
MOO_ASSERT (moo, MOO_OBJ_GET_FLAGS_UNIT(oop) == MOO_SIZEOF(moo_oow_t));
MOO_ASSERT (moo, MOO_OBJ_GET_FLAGS_EXTRA(oop) == 0); /* no 'extra' for an OOP object */
nbytes = MOO_OBJ_BYTESOF(oop) + MOO_SIZEOF(moo_oow_t) + \
(moo_oow_t)((moo_oop_oop_t)oop)->slot[MOO_OBJ_GET_SIZE(oop)];
nbytes_aligned = MOO_ALIGN (nbytes, MOO_SIZEOF(moo_oop_t));
}
else
{
#endif
nbytes_aligned = MOO_ALIGN (MOO_OBJ_BYTESOF(oop), MOO_SIZEOF(moo_oop_t));
#if defined(MOO_USE_OBJECT_TRAILER)
}
#endif
MOO_OBJ_SET_CLASS (oop, moo_moveoop(moo, MOO_OBJ_GET_CLASS(oop)));
if (MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_OOP)
{
moo_oop_oop_t xtmp;
moo_oow_t size;
if (moo->_process && MOO_OBJ_GET_CLASS(oop) == moo->_process)
{
/* the stack in a process object doesn't need to be
* scanned in full. the slots above the stack pointer
* are garbages. */
size = MOO_PROCESS_NAMED_INSTVARS +
MOO_OOP_TO_SMOOI(((moo_oop_process_t)oop)->sp) + 1;
MOO_ASSERT (moo, size <= MOO_OBJ_GET_SIZE(oop));
}
else
{
size = MOO_OBJ_GET_SIZE(oop);
}
xtmp = (moo_oop_oop_t)oop;
for (i = 0; i < size; i++)
{
if (MOO_OOP_IS_POINTER(xtmp->slot[i]))
xtmp->slot[i] = moo_moveoop (moo, xtmp->slot[i]);
}
}
ptr = ptr + MOO_SIZEOF(moo_obj_t) + nbytes_aligned;
}
/* return the pointer to the beginning of the free space in the heap */
return ptr;
}
void moo_gc (moo_t* moo)
{
/*
* move a referenced object to the new heap.
* inspect the fields of the moved object in the new heap.
* move objects pointed to by the fields to the new heap.
* finally perform some tricky symbol table clean-up.
*/
moo_uint8_t* ptr;
moo_heap_t* tmp;
moo_oop_t old_nil;
moo_oow_t i;
moo_cb_t* cb;
if (moo->active_context)
{
/* TODO: verify if this is correct */
MOO_ASSERT (moo, (moo_oop_t)moo->processor != moo->_nil);
MOO_ASSERT (moo, (moo_oop_t)moo->processor->active != moo->_nil);
/* store the stack pointer to the active process */
moo->processor->active->sp = MOO_SMOOI_TO_OOP(moo->sp);
/* store the instruction pointer to the active context */
moo->active_context->ip = MOO_SMOOI_TO_OOP(moo->ip);
}
MOO_LOG4 (moo, MOO_LOG_GC | MOO_LOG_INFO,
"Starting GC curheap base %p ptr %p newheap base %p ptr %p\n",
moo->curheap->base, moo->curheap->ptr, moo->newheap->base, moo->newheap->ptr);
/* TODO: allocate common objects like _nil and the root dictionary
* in the permanant heap. minimize moving around */
old_nil = moo->_nil;
/* move _nil and the root object table */
moo->_nil = moo_moveoop (moo, moo->_nil);
moo->_true = moo_moveoop (moo, moo->_true);
moo->_false = moo_moveoop (moo, moo->_false);
for (i = 0; i < MOO_COUNTOF(kernel_classes); i++)
{
moo_oop_t tmp;
tmp = *(moo_oop_t*)((moo_uint8_t*)moo + kernel_classes[i].offset);
tmp = moo_moveoop (moo, tmp);
*(moo_oop_t*)((moo_uint8_t*)moo + kernel_classes[i].offset) = tmp;
}
moo->sysdic = (moo_oop_set_t) moo_moveoop (moo, (moo_oop_t)moo->sysdic);
moo->processor = (moo_oop_process_scheduler_t) moo_moveoop (moo, (moo_oop_t)moo->processor);
moo->nil_process = (moo_oop_process_t) moo_moveoop (moo, (moo_oop_t)moo->nil_process);
for (i = 0; i < moo->sem_list_count; i++)
{
moo->sem_list[i] = (moo_oop_semaphore_t)moo_moveoop (moo, (moo_oop_t)moo->sem_list[i]);
}
for (i = 0; i < moo->sem_heap_count; i++)
{
moo->sem_heap[i] = (moo_oop_semaphore_t)moo_moveoop (moo, (moo_oop_t)moo->sem_heap[i]);
}
for (i = 0; i < moo->tmp_count; i++)
{
*moo->tmp_stack[i] = moo_moveoop (moo, *moo->tmp_stack[i]);
}
if (moo->initial_context)
moo->initial_context = (moo_oop_context_t)moo_moveoop (moo, (moo_oop_t)moo->initial_context);
if (moo->active_context)
moo->active_context = (moo_oop_context_t)moo_moveoop (moo, (moo_oop_t)moo->active_context);
if (moo->active_method)
moo->active_method = (moo_oop_method_t)moo_moveoop (moo, (moo_oop_t)moo->active_method);
for (cb = moo->cblist; cb; cb = cb->next)
{
if (cb->gc) cb->gc (moo);
}
/* scan the new heap to move referenced objects */
ptr = (moo_uint8_t*) MOO_ALIGN ((moo_uintptr_t)moo->newheap->base, MOO_SIZEOF(moo_oop_t));
ptr = scan_new_heap (moo, ptr);
/* traverse the symbol table for unreferenced symbols.
* if the symbol has not moved to the new heap, the symbol
* is not referenced by any other objects than the symbol
* table itself */
compact_symbol_table (moo, old_nil);
/* move the symbol table itself */
moo->symtab = (moo_oop_set_t)moo_moveoop (moo, (moo_oop_t)moo->symtab);
/* scan the new heap again from the end position of
* the previous scan to move referenced objects by
* the symbol table. */
ptr = scan_new_heap (moo, ptr);
/* the contents of the current heap is not needed any more.
* reset the upper bound to the base. don't forget to align the heap
* pointer to the OOP size. See moo_makeheap() also */
moo->curheap->ptr = (moo_uint8_t*)MOO_ALIGN(((moo_uintptr_t)moo->curheap->base), MOO_SIZEOF(moo_oop_t));
/* swap the current heap and old heap */
tmp = moo->curheap;
moo->curheap = moo->newheap;
moo->newheap = tmp;
/*
if (moo->symtab && MOO_LOG_ENABLED(moo, MOO_LOG_GC | MOO_LOG_DEBUG))
{
moo_oow_t index;
moo_oop_oop_t buc;
MOO_LOG0 (moo, MOO_LOG_GC | MOO_LOG_DEBUG, "--------- SURVIVING SYMBOLS IN GC ----------\n");
buc = (moo_oop_oop_t) moo->symtab->bucket;
for (index = 0; index < MOO_OBJ_GET_SIZE(buc); index++)
{
if ((moo_oop_t)buc->slot[index] != moo->_nil)
{
MOO_LOG1 (moo, MOO_LOG_GC | MOO_LOG_DEBUG, "\t%O\n", buc->slot[index]);
}
}
MOO_LOG0 (moo, MOO_LOG_GC | MOO_LOG_DEBUG, "--------------------------------------------\n");
}
*/
if (moo->active_method) SET_ACTIVE_METHOD_CODE (moo); /* update moo->active_code */
/* TODO: include some gc statstics like number of live objects, gc performance, etc */
MOO_LOG4 (moo, MOO_LOG_GC | MOO_LOG_INFO,
"Finished GC curheap base %p ptr %p newheap base %p ptr %p\n",
moo->curheap->base, moo->curheap->ptr, moo->newheap->base, moo->newheap->ptr);
}
void moo_pushtmp (moo_t* moo, moo_oop_t* oop_ptr)
{
/* if you have too many temporaries pushed, something must be wrong.
* change your code not to exceede the stack limit */
MOO_ASSERT (moo, moo->tmp_count < MOO_COUNTOF(moo->tmp_stack));
moo->tmp_stack[moo->tmp_count++] = oop_ptr;
}
void moo_poptmp (moo_t* moo)
{
MOO_ASSERT (moo, moo->tmp_count > 0);
moo->tmp_count--;
}
void moo_poptmps (moo_t* moo, moo_oow_t count)
{
MOO_ASSERT (moo, moo->tmp_count >= count);
moo->tmp_count -= count;
}
moo_oop_t moo_shallowcopy (moo_t* moo, moo_oop_t oop)
{
if (MOO_OOP_IS_POINTER(oop) && MOO_OBJ_GET_CLASS(oop) != moo->_symbol)
{
#if 0
moo_oop_t z;
moo_oop_class_t c;
c = (moo_oop_class_t)MOO_OBJ_GET_CLASS(oop);
moo_pushtmp (moo, &oop);
z = moo_instantiate (moo, (moo_oop_t)c, MOO_NULL, MOO_OBJ_GET_SIZE(oop) - MOO_CLASS_SPEC_NAMED_INSTVAR(MOO_OOP_TO_SMOOI(c->spec)));
moo_poptmp(moo);
if (!z) return z;
/* copy the payload */
MOO_MEMCPY (z + 1, oop + 1, get_payload_bytes(moo, oop));
return z;
#else
moo_oop_t z;
moo_oow_t total_bytes;
total_bytes = MOO_SIZEOF(moo_obj_t) + get_payload_bytes(moo, oop);
moo_pushtmp (moo, &oop);
z = moo_allocbytes (moo, total_bytes);
moo_poptmp(moo);
MOO_MEMCPY (z, oop, total_bytes);
return z;
#endif
}
return oop;
}

81
moo/lib/heap.c Normal file
View File

@ -0,0 +1,81 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
moo_heap_t* moo_makeheap (moo_t* moo, moo_oow_t size)
{
moo_heap_t* heap;
heap = (moo_heap_t*)MOO_MMGR_ALLOC(moo->mmgr, MOO_SIZEOF(*heap) + size);
if (!heap)
{
moo->errnum = MOO_ESYSMEM;
return MOO_NULL;
}
MOO_MEMSET (heap, 0, MOO_SIZEOF(*heap) + size);
heap->base = (moo_uint8_t*)(heap + 1);
/* adjust the initial allocation pointer to a multiple of the oop size */
heap->ptr = (moo_uint8_t*)MOO_ALIGN(((moo_uintptr_t)heap->base), MOO_SIZEOF(moo_oop_t));
heap->limit = heap->base + size;
MOO_ASSERT (moo, heap->ptr >= heap->base);
MOO_ASSERT (moo, heap->limit >= heap->base );
MOO_ASSERT (moo, heap->limit - heap->base == size);
/* if size is too small, heap->ptr may go past heap->limit even at
* this moment depending on the alignment of heap->base. subsequent
* calls to submoo_allocheapmem() are bound to fail. Make sure to
* pass a heap size large enough */
return heap;
}
void moo_killheap (moo_t* moo, moo_heap_t* heap)
{
MOO_MMGR_FREE (moo->mmgr, heap);
}
void* moo_allocheapmem (moo_t* moo, moo_heap_t* heap, moo_oow_t size)
{
moo_uint8_t* ptr;
/* check the heap size limit */
if (heap->ptr >= heap->limit || heap->limit - heap->ptr < size)
{
MOO_LOG4 (moo, MOO_LOG_ERROR, "Cannot allocate %zd bytes from heap - ptr %p limit %p size %zd\n", size, heap->ptr, heap->limit, (moo_oow_t)(heap->limit - heap->ptr));
moo->errnum = MOO_EOOMEM;
return MOO_NULL;
}
/* allocation is as simple as moving the heap pointer */
ptr = heap->ptr;
heap->ptr += size;
return ptr;
}

550
moo/lib/logfmt.c Normal file
View File

@ -0,0 +1,550 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
/*#include <stdio.h>*/ /* for snrintf(). used for floating-point number formatting */
#include <stdarg.h>
#if defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1200))
# define snprintf _snprintf
# if !defined(HAVE_SNPRINTF)
# define HAVE_SNPRINTF
# endif
#endif
#if defined(HAVE_QUADMATH_H)
# include <quadmath.h> /* for quadmath_snprintf() */
#endif
/* TODO: remove stdio.h and quadmath.h once snprintf gets replaced by own
floting-point conversion implementation*/
/* Max number conversion buffer length:
* moo_intmax_t in base 2, plus NUL byte. */
#define MAXNBUF (MOO_SIZEOF(moo_intmax_t) * 8 + 1)
enum
{
/* integer */
LF_C = (1 << 0),
LF_H = (1 << 1),
LF_J = (1 << 2),
LF_L = (1 << 3),
LF_Q = (1 << 4),
LF_T = (1 << 5),
LF_Z = (1 << 6),
/* long double */
LF_LD = (1 << 7),
/* __float128 */
LF_QD = (1 << 8)
};
static struct
{
moo_uint8_t flag; /* for single occurrence */
moo_uint8_t dflag; /* for double occurrence */
} lm_tab[26] =
{
{ 0, 0 }, /* a */
{ 0, 0 }, /* b */
{ 0, 0 }, /* c */
{ 0, 0 }, /* d */
{ 0, 0 }, /* e */
{ 0, 0 }, /* f */
{ 0, 0 }, /* g */
{ LF_H, LF_C }, /* h */
{ 0, 0 }, /* i */
{ LF_J, 0 }, /* j */
{ 0, 0 }, /* k */
{ LF_L, LF_Q }, /* l */
{ 0, 0 }, /* m */
{ 0, 0 }, /* n */
{ 0, 0 }, /* o */
{ 0, 0 }, /* p */
{ LF_Q, 0 }, /* q */
{ 0, 0 }, /* r */
{ 0, 0 }, /* s */
{ LF_T, 0 }, /* t */
{ 0, 0 }, /* u */
{ 0, 0 }, /* v */
{ 0, 0 }, /* w */
{ 0, 0 }, /* z */
{ 0, 0 }, /* y */
{ LF_Z, 0 }, /* z */
};
enum
{
FLAGC_DOT = (1 << 0),
FLAGC_SPACE = (1 << 1),
FLAGC_SHARP = (1 << 2),
FLAGC_SIGN = (1 << 3),
FLAGC_LEFTADJ = (1 << 4),
FLAGC_ZEROPAD = (1 << 5),
FLAGC_WIDTH = (1 << 6),
FLAGC_PRECISION = (1 << 7),
FLAGC_STAR1 = (1 << 8),
FLAGC_STAR2 = (1 << 9),
FLAGC_LENMOD = (1 << 10) /* length modifier */
};
static const moo_bch_t hex2ascii_lower[] =
{
'0','1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z'
};
static const moo_bch_t hex2ascii_upper[] =
{
'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','H','Z'
};
static moo_uch_t uch_nullstr[] = { '(','n','u','l','l', ')','\0' };
static moo_bch_t bch_nullstr[] = { '(','n','u','l','l', ')','\0' };
typedef int (*moo_fmtout_putch_t) (
moo_t* moo,
moo_oow_t mask,
moo_ooch_t c,
moo_oow_t len
);
typedef int (*moo_fmtout_putcs_t) (
moo_t* moo,
moo_oow_t mask,
const moo_ooch_t* ptr,
moo_oow_t len
);
typedef struct moo_fmtout_t moo_fmtout_t;
struct moo_fmtout_t
{
moo_oow_t count; /* out */
moo_oow_t mask; /* in */
moo_fmtout_putch_t putch; /* in */
moo_fmtout_putcs_t putcs; /* in */
};
/* ------------------------------------------------------------------------- */
/*
* Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
* order; return an optional length and a pointer to the last character
* written in the buffer (i.e., the first character of the string).
* The buffer pointed to by `nbuf' must have length >= MAXNBUF.
*/
static moo_bch_t* sprintn_lower (moo_bch_t* nbuf, moo_uintmax_t num, int base, moo_ooi_t *lenp)
{
moo_bch_t* p;
p = nbuf;
*p = '\0';
do { *++p = hex2ascii_lower[num % base]; } while (num /= base);
if (lenp) *lenp = p - nbuf;
return p; /* returns the end */
}
static moo_bch_t* sprintn_upper (moo_bch_t* nbuf, moo_uintmax_t num, int base, moo_ooi_t *lenp)
{
moo_bch_t* p;
p = nbuf;
*p = '\0';
do { *++p = hex2ascii_upper[num % base]; } while (num /= base);
if (lenp) *lenp = p - nbuf;
return p; /* returns the end */
}
/* ------------------------------------------------------------------------- */
static int put_ooch (moo_t* moo, moo_oow_t mask, moo_ooch_t ch, moo_oow_t len)
{
if (len <= 0) return 1;
if (moo->log.len > 0 && moo->log.last_mask != mask)
{
/* the mask has changed. commit the buffered text */
/* TODO: HANDLE LINE ENDING CONVENTION BETTER... */
if (moo->log.ptr[moo->log.len - 1] != '\n')
{
/* no line ending - append a line terminator */
moo->log.ptr[moo->log.len++] = '\n';
}
moo->vmprim.log_write (moo, moo->log.last_mask, moo->log.ptr, moo->log.len);
moo->log.len = 0;
}
redo:
if (len > moo->log.capa - moo->log.len)
{
moo_oow_t newcapa;
moo_ooch_t* tmp;
if (len > MOO_TYPE_MAX(moo_oow_t) - moo->log.len)
{
/* data too big */
moo->errnum = MOO_ETOOBIG;
return -1;
}
newcapa = MOO_ALIGN(moo->log.len + len, 512); /* TODO: adjust this capacity */
/* +1 to handle line ending injection more easily */
tmp = moo_reallocmem (moo, moo->log.ptr, (newcapa + 1) * MOO_SIZEOF(*tmp));
if (!tmp)
{
if (moo->log.len > 0)
{
/* can't expand the buffer. just flush the existing contents */
moo->vmprim.log_write (moo, moo->log.last_mask, moo->log.ptr, moo->log.len);
moo->log.len = 0;
goto redo;
}
return -1;
}
moo->log.ptr = tmp;
moo->log.capa = newcapa;
}
while (len > 0)
{
moo->log.ptr[moo->log.len++] = ch;
len--;
}
moo->log.last_mask = mask;
return 1; /* success */
}
static int put_oocs (moo_t* moo, moo_oow_t mask, const moo_ooch_t* ptr, moo_oow_t len)
{
if (len <= 0) return 1;
if (moo->log.len > 0 && moo->log.last_mask != mask)
{
/* the mask has changed. commit the buffered text */
/* TODO: HANDLE LINE ENDING CONVENTION BETTER... */
if (moo->log.ptr[moo->log.len - 1] != '\n')
{
/* no line ending - append a line terminator */
moo->log.ptr[moo->log.len++] = '\n';
}
moo->vmprim.log_write (moo, moo->log.last_mask, moo->log.ptr, moo->log.len);
moo->log.len = 0;
}
if (len > moo->log.capa - moo->log.len)
{
moo_oow_t newcapa;
moo_ooch_t* tmp;
if (len > MOO_TYPE_MAX(moo_oow_t) - moo->log.len)
{
/* data too big */
moo->errnum = MOO_ETOOBIG;
return -1;
}
newcapa = MOO_ALIGN(moo->log.len + len, 512); /* TODO: adjust this capacity */
/* +1 to handle line ending injection more easily */
tmp = moo_reallocmem (moo, moo->log.ptr, (newcapa + 1) * MOO_SIZEOF(*tmp));
if (!tmp) return -1;
moo->log.ptr = tmp;
moo->log.capa = newcapa;
}
MOO_MEMCPY (&moo->log.ptr[moo->log.len], ptr, len * MOO_SIZEOF(*ptr));
moo->log.len += len;
moo->log.last_mask = mask;
return 1; /* success */
}
/* ------------------------------------------------------------------------- */
static void print_object (moo_t* moo, moo_oow_t mask, moo_oop_t oop)
{
if (oop == moo->_nil)
{
moo_logbfmt (moo, mask, "nil");
}
else if (oop == moo->_true)
{
moo_logbfmt (moo, mask, "true");
}
else if (oop == moo->_false)
{
moo_logbfmt (moo, mask, "false");
}
else if (MOO_OOP_IS_SMOOI(oop))
{
moo_logbfmt (moo, mask, "%zd", MOO_OOP_TO_SMOOI(oop));
}
else if (MOO_OOP_IS_CHAR(oop))
{
moo_logbfmt (moo, mask, "$%.1C", MOO_OOP_TO_CHAR(oop));
}
else if (MOO_OOP_IS_ERROR(oop))
{
moo_logbfmt (moo, mask, "error(%zd)", MOO_OOP_TO_ERROR(oop));
}
else
{
moo_oop_class_t c;
moo_oow_t i;
MOO_ASSERT (moo, MOO_OOP_IS_POINTER(oop));
c = (moo_oop_class_t)MOO_OBJ_GET_CLASS(oop); /*MOO_CLASSOF(moo, oop);*/
if ((moo_oop_t)c == moo->_large_negative_integer)
{
moo_oow_t i;
moo_logbfmt (moo, mask, "-16r");
for (i = MOO_OBJ_GET_SIZE(oop); i > 0;)
{
moo_logbfmt (moo, mask, "%0*lX", (int)(MOO_SIZEOF(moo_liw_t) * 2), (unsigned long)((moo_oop_liword_t)oop)->slot[--i]);
}
}
else if ((moo_oop_t)c == moo->_large_positive_integer)
{
moo_oow_t i;
moo_logbfmt (moo, mask, "16r");
for (i = MOO_OBJ_GET_SIZE(oop); i > 0;)
{
moo_logbfmt (moo, mask, "%0*lX", (int)(MOO_SIZEOF(moo_liw_t) * 2), (unsigned long)((moo_oop_liword_t)oop)->slot[--i]);
}
}
else if (MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_CHAR)
{
if ((moo_oop_t)c == moo->_symbol)
{
moo_logbfmt (moo, mask, "#%.*js", MOO_OBJ_GET_SIZE(oop), ((moo_oop_char_t)oop)->slot);
}
else /*if ((moo_oop_t)c == moo->_string)*/
{
moo_ooch_t ch;
int escape = 0;
for (i = 0; i < MOO_OBJ_GET_SIZE(oop); i++)
{
ch = ((moo_oop_char_t)oop)->slot[i];
if (ch < ' ')
{
escape = 1;
break;
}
}
if (escape)
{
moo_ooch_t escaped;
moo_logbfmt (moo, mask, "S'");
for (i = 0; i < MOO_OBJ_GET_SIZE(oop); i++)
{
ch = ((moo_oop_char_t)oop)->slot[i];
if (ch < ' ')
{
switch (ch)
{
case '\0':
escaped = '0';
break;
case '\n':
escaped = 'n';
break;
case '\r':
escaped = 'r';
break;
case '\t':
escaped = 't';
break;
case '\f':
escaped = 'f';
break;
case '\b':
escaped = 'b';
break;
case '\v':
escaped = 'v';
break;
case '\a':
escaped = 'a';
break;
default:
escaped = ch;
break;
}
if (escaped == ch)
moo_logbfmt (moo, mask, "\\x%X", ch);
else
moo_logbfmt (moo, mask, "\\%jc", escaped);
}
else
{
moo_logbfmt (moo, mask, "%jc", ch);
}
}
moo_logbfmt (moo, mask, "'");
}
else
{
moo_logbfmt (moo, mask, "'%.*js'", MOO_OBJ_GET_SIZE(oop), ((moo_oop_char_t)oop)->slot);
}
}
}
else if (MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_BYTE)
{
moo_logbfmt (moo, mask, "#[");
for (i = 0; i < MOO_OBJ_GET_SIZE(oop); i++)
{
moo_logbfmt (moo, mask, " %d", ((moo_oop_byte_t)oop)->slot[i]);
}
moo_logbfmt (moo, mask, "]");
}
else if (MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_HALFWORD)
{
moo_logbfmt (moo, mask, "#[["); /* TODO: fix this symbol/notation */
for (i = 0; i < MOO_OBJ_GET_SIZE(oop); i++)
{
moo_logbfmt (moo, mask, " %zX", (moo_oow_t)((moo_oop_halfword_t)oop)->slot[i]);
}
moo_logbfmt (moo, mask, "]]");
}
else if (MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_WORD)
{
moo_logbfmt (moo, mask, "#[[["); /* TODO: fix this symbol/notation */
for (i = 0; i < MOO_OBJ_GET_SIZE(oop); i++)
{
moo_logbfmt (moo, mask, " %zX", ((moo_oop_word_t)oop)->slot[i]);
}
moo_logbfmt (moo, mask, "]]]");
}
else if ((moo_oop_t)c == moo->_array)
{
moo_logbfmt (moo, mask, "#(");
for (i = 0; i < MOO_OBJ_GET_SIZE(oop); i++)
{
moo_logbfmt (moo, mask, " ");
print_object (moo, mask, ((moo_oop_oop_t)oop)->slot[i]);
}
moo_logbfmt (moo, mask, ")");
}
else if ((moo_oop_t)c == moo->_class)
{
/* print the class name */
moo_logbfmt (moo, mask, "%.*js", MOO_OBJ_GET_SIZE(((moo_oop_class_t)oop)->name), ((moo_oop_class_t)oop)->name->slot);
}
else if ((moo_oop_t)c == moo->_association)
{
moo_logbfmt (moo, mask, "%O -> %O", ((moo_oop_association_t)oop)->key, ((moo_oop_association_t)oop)->value);
}
else
{
moo_logbfmt (moo, mask, "instance of %.*js(%p)", MOO_OBJ_GET_SIZE(c->name), ((moo_oop_char_t)c->name)->slot, oop);
}
}
}
/* ------------------------------------------------------------------------- */
#undef fmtchar_t
#undef logfmtv
#define fmtchar_t moo_bch_t
#define FMTCHAR_IS_BCH
#if defined(MOO_OOCH_IS_BCH)
# define FMTCHAR_IS_OOCH
#endif
#define logfmtv moo_logbfmtv
#include "logfmtv.h"
#undef fmtchar_t
#undef logfmtv
#define fmtchar_t moo_uch_t
#define logfmtv moo_logufmtv
#define FMTCHAR_IS_UCH
#if defined(MOO_OOCH_IS_UCH)
# define FMTCHAR_IS_OOCH
#endif
#include "logfmtv.h"
moo_ooi_t moo_logbfmt (moo_t* moo, moo_oow_t mask, const moo_bch_t* fmt, ...)
{
int x;
va_list ap;
moo_fmtout_t fo;
fo.mask = mask;
fo.putch = put_ooch;
fo.putcs = put_oocs;
va_start (ap, fmt);
x = moo_logbfmtv (moo, fmt, &fo, ap);
va_end (ap);
if (moo->log.len > 0 && moo->log.ptr[moo->log.len - 1] == '\n')
{
moo->vmprim.log_write (moo, moo->log.last_mask, moo->log.ptr, moo->log.len);
moo->log.len = 0;
}
return (x <= -1)? -1: fo.count;
}
moo_ooi_t moo_logufmt (moo_t* moo, moo_oow_t mask, const moo_uch_t* fmt, ...)
{
int x;
va_list ap;
moo_fmtout_t fo;
fo.mask = mask;
fo.putch = put_ooch;
fo.putcs = put_oocs;
va_start (ap, fmt);
x = moo_logufmtv (moo, fmt, &fo, ap);
va_end (ap);
if (moo->log.len > 0 && moo->log.ptr[moo->log.len - 1] == '\n')
{
moo->vmprim.log_write (moo, moo->log.last_mask, moo->log.ptr, moo->log.len);
moo->log.len = 0;
}
return (x <= -1)? -1: fo.count;
}

967
moo/lib/logfmtv.h Normal file
View File

@ -0,0 +1,967 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This file contains a formatted output routine derived from kvprintf()
* of FreeBSD. It has been heavily modified and bug-fixed.
*/
/*
* Copyright (c) 1986, 1988, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/* NOTE: data output is aborted if the data limit is reached or
* I/O error occurs */
#undef PUT_OOCH
#undef PUT_OOCS
#define PUT_OOCH(c,n) do { \
int xx; \
if ((xx = data->putch (moo, data->mask, c, n)) <= -1) goto oops; \
if (xx == 0) goto done; \
data->count += n; \
} while (0)
#define PUT_OOCS(ptr,len) do { \
int xx; \
if ((xx = data->putcs (moo, data->mask, ptr, len)) <= -1) goto oops; \
if (xx == 0) goto done; \
data->count += len; \
} while (0)
int logfmtv (moo_t* moo, const fmtchar_t* fmt, moo_fmtout_t* data, va_list ap)
{
const fmtchar_t* percent;
#if defined(FMTCHAR_IS_OOCH)
const fmtchar_t* checkpoint;
#endif
moo_bch_t nbuf[MAXNBUF], bch;
const moo_bch_t* nbufp;
int n, base, neg, sign;
moo_ooi_t tmp, width, precision;
moo_ooch_t ch, padc;
int lm_flag, lm_dflag, flagc, numlen;
moo_uintmax_t num = 0;
int stop = 0;
#if 0
moo_bchbuf_t* fltfmt;
moo_oochbuf_t* fltout;
#endif
moo_bch_t* (*sprintn) (moo_bch_t* nbuf, moo_uintmax_t num, int base, moo_ooi_t* lenp);
data->count = 0;
#if 0
fltfmt = &moo->d->fltfmt;
fltout = &moo->d->fltout;
fltfmt->ptr = fltfmt->buf;
fltfmt->capa = MOO_COUNTOF(fltfmt->buf) - 1;
fltout->ptr = fltout->buf;
fltout->capa = MOO_COUNTOF(fltout->buf) - 1;
#endif
while (1)
{
#if defined(FMTCHAR_IS_OOCH)
checkpoint = fmt;
while ((ch = *fmt++) != '%' || stop)
{
if (ch == '\0')
{
PUT_OOCS (checkpoint, fmt - checkpoint - 1);
goto done;
}
}
PUT_OOCS (checkpoint, fmt - checkpoint - 1);
#else
while ((ch = *fmt++) != '%' || stop)
{
if (ch == '\0') goto done;
PUT_OOCH (ch, 1);
}
#endif
percent = fmt - 1;
padc = ' ';
width = 0; precision = 0;
neg = 0; sign = 0;
lm_flag = 0; lm_dflag = 0; flagc = 0;
sprintn = sprintn_lower;
reswitch:
switch (ch = *fmt++)
{
case '%': /* %% */
bch = ch;
goto print_lowercase_c;
/* flag characters */
case '.':
if (flagc & FLAGC_DOT) goto invalid_format;
flagc |= FLAGC_DOT;
goto reswitch;
case '#':
if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format;
flagc |= FLAGC_SHARP;
goto reswitch;
case ' ':
if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format;
flagc |= FLAGC_SPACE;
goto reswitch;
case '+': /* place sign for signed conversion */
if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format;
flagc |= FLAGC_SIGN;
goto reswitch;
case '-': /* left adjusted */
if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format;
if (flagc & FLAGC_DOT)
{
goto invalid_format;
}
else
{
flagc |= FLAGC_LEFTADJ;
if (flagc & FLAGC_ZEROPAD)
{
padc = ' ';
flagc &= ~FLAGC_ZEROPAD;
}
}
goto reswitch;
case '*': /* take the length from the parameter */
if (flagc & FLAGC_DOT)
{
if (flagc & (FLAGC_STAR2 | FLAGC_PRECISION)) goto invalid_format;
flagc |= FLAGC_STAR2;
precision = va_arg(ap, moo_ooi_t); /* this deviates from the standard printf that accepts 'int' */
if (precision < 0)
{
/* if precision is less than 0,
* treat it as if no .precision is specified */
flagc &= ~FLAGC_DOT;
precision = 0;
}
}
else
{
if (flagc & (FLAGC_STAR1 | FLAGC_WIDTH)) goto invalid_format;
flagc |= FLAGC_STAR1;
width = va_arg(ap, moo_ooi_t); /* it deviates from the standard printf that accepts 'int' */
if (width < 0)
{
/*
if (flagc & FLAGC_LEFTADJ)
flagc &= ~FLAGC_LEFTADJ;
else
*/
flagc |= FLAGC_LEFTADJ;
width = -width;
}
}
goto reswitch;
case '0': /* zero pad */
if (flagc & FLAGC_LENMOD) goto invalid_format;
if (!(flagc & (FLAGC_DOT | FLAGC_LEFTADJ)))
{
padc = '0';
flagc |= FLAGC_ZEROPAD;
goto reswitch;
}
/* end of flags characters */
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (n = 0;; ++fmt)
{
n = n * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9') break;
}
if (flagc & FLAGC_DOT)
{
if (flagc & FLAGC_STAR2) goto invalid_format;
precision = n;
flagc |= FLAGC_PRECISION;
}
else
{
if (flagc & FLAGC_STAR1) goto invalid_format;
width = n;
flagc |= FLAGC_WIDTH;
}
goto reswitch;
/* length modifiers */
case 'h': /* short int */
case 'l': /* long int */
case 'q': /* long long int */
case 'j': /* moo_intmax_t/moo_uintmax_t */
case 'z': /* moo_ooi_t/moo_oow_t */
case 't': /* ptrdiff_t */
if (lm_flag & (LF_LD | LF_QD)) goto invalid_format;
flagc |= FLAGC_LENMOD;
if (lm_dflag)
{
/* error */
goto invalid_format;
}
else if (lm_flag)
{
if (lm_tab[ch - 'a'].dflag && lm_flag == lm_tab[ch - 'a'].flag)
{
lm_flag &= ~lm_tab[ch - 'a'].flag;
lm_flag |= lm_tab[ch - 'a'].dflag;
lm_dflag |= lm_flag;
goto reswitch;
}
else
{
/* error */
goto invalid_format;
}
}
else
{
lm_flag |= lm_tab[ch - 'a'].flag;
goto reswitch;
}
break;
case 'L': /* long double */
if (flagc & FLAGC_LENMOD)
{
/* conflict with other length modifier */
goto invalid_format;
}
flagc |= FLAGC_LENMOD;
lm_flag |= LF_LD;
goto reswitch;
case 'Q': /* __float128 */
if (flagc & FLAGC_LENMOD)
{
/* conflict with other length modifier */
goto invalid_format;
}
flagc |= FLAGC_LENMOD;
lm_flag |= LF_QD;
goto reswitch;
/* end of length modifiers */
case 'n':
if (lm_flag & LF_J) /* j */
*(va_arg(ap, moo_intmax_t*)) = data->count;
else if (lm_flag & LF_Z) /* z */
*(va_arg(ap, moo_ooi_t*)) = data->count;
#if (MOO_SIZEOF_LONG_LONG > 0)
else if (lm_flag & LF_Q) /* ll */
*(va_arg(ap, long long int*)) = data->count;
#endif
else if (lm_flag & LF_L) /* l */
*(va_arg(ap, long int*)) = data->count;
else if (lm_flag & LF_H) /* h */
*(va_arg(ap, short int*)) = data->count;
else if (lm_flag & LF_C) /* hh */
*(va_arg(ap, char*)) = data->count;
else if (flagc & FLAGC_LENMOD)
{
moo->errnum = MOO_EINVAL;
goto oops;
}
else
*(va_arg(ap, int*)) = data->count;
break;
/* signed integer conversions */
case 'd':
case 'i': /* signed conversion */
base = 10;
sign = 1;
goto handle_sign;
/* end of signed integer conversions */
/* unsigned integer conversions */
case 'o':
base = 8;
goto handle_nosign;
case 'u':
base = 10;
goto handle_nosign;
case 'X':
sprintn = sprintn_upper;
case 'x':
base = 16;
goto handle_nosign;
/* end of unsigned integer conversions */
case 'p': /* pointer */
base = 16;
if (width == 0) flagc |= FLAGC_SHARP;
else flagc &= ~FLAGC_SHARP;
num = (moo_uintptr_t)va_arg(ap, void*);
goto number;
case 'c':
{
/* zeropad must not take effect for 'c' */
if (flagc & FLAGC_ZEROPAD) padc = ' ';
if (lm_flag & LF_L) goto uppercase_c;
#if defined(MOO_OOCH_IS_UCH)
if (lm_flag & LF_J) goto uppercase_c;
#endif
lowercase_c:
bch = MOO_SIZEOF(moo_bch_t) < MOO_SIZEOF(int)? va_arg(ap, int): va_arg(ap, moo_bch_t);
print_lowercase_c:
/* precision 0 doesn't kill the letter */
width--;
if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
PUT_OOCH (bch, 1);
if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
break;
}
case 'C':
{
moo_uch_t ooch;
/* zeropad must not take effect for 'C' */
if (flagc & FLAGC_ZEROPAD) padc = ' ';
if (lm_flag & LF_H) goto lowercase_c;
#if defined(MOO_OOCH_IS_BCH)
if (lm_flag & LF_J) goto lowercase_c;
#endif
uppercase_c:
ooch = MOO_SIZEOF(moo_uch_t) < MOO_SIZEOF(int)? va_arg(ap, int): va_arg(ap, moo_uch_t);
/* precision 0 doesn't kill the letter */
width--;
if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
PUT_OOCH (ooch, 1);
if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
break;
}
case 's':
{
const moo_bch_t* bsp;
moo_oow_t bslen, slen;
/* zeropad must not take effect for 'S' */
if (flagc & FLAGC_ZEROPAD) padc = ' ';
if (lm_flag & LF_L) goto uppercase_s;
#if defined(MOO_OOCH_IS_UCH)
if (lm_flag & LF_J) goto uppercase_s;
#endif
lowercase_s:
bsp = va_arg (ap, moo_bch_t*);
if (bsp == MOO_NULL) bsp = bch_nullstr;
#if defined(MOO_OOCH_IS_UCH)
/* get the length */
for (bslen = 0; bsp[bslen]; bslen++);
if (moo_convbtooochars (moo, bsp, &bslen, MOO_NULL, &slen) <= -1)
{
/* conversion error */
moo->errnum = MOO_EECERR;
goto oops;
}
/* slen holds the length after conversion */
n = slen;
if ((flagc & FLAGC_DOT) && precision < slen) n = precision;
width -= n;
if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
{
moo_ooch_t conv_buf[32];
moo_oow_t conv_len, src_len, tot_len = 0;
while (n > 0)
{
MOO_ASSERT (moo, bslen > tot_len);
src_len = bslen - tot_len;
conv_len = MOO_COUNTOF(conv_buf);
/* this must not fail since the dry-run above was successful */
moo_convbtooochars (moo, &bsp[tot_len], &src_len, conv_buf, &conv_len);
tot_len += src_len;
if (conv_len > n) conv_len = n;
PUT_OOCS (conv_buf, conv_len);
n -= conv_len;
}
}
if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
#else
if (flagc & FLAGC_DOT)
{
for (n = 0; n < precision && bsp[n]; n++);
}
else
{
for (n = 0; bsp[n]; n++);
}
width -= n;
if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
PUT_OOCS (bsp, n);
if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
#endif
break;
}
case 'S':
{
const moo_uch_t* usp;
moo_oow_t uslen, slen;
/* zeropad must not take effect for 's' */
if (flagc & FLAGC_ZEROPAD) padc = ' ';
if (lm_flag & LF_H) goto lowercase_s;
#if defined(MOO_OOCH_IS_UCH)
if (lm_flag & LF_J) goto lowercase_s;
#endif
uppercase_s:
usp = va_arg (ap, moo_uch_t*);
if (usp == MOO_NULL) usp = uch_nullstr;
#if defined(MOO_OOCH_IS_BCH)
/* get the length */
for (uslen = 0; usp[uslen]; uslen++);
if (moo_convutooochars (moo, usp, &uslen, MOO_NULL, &slen) <= -1)
{
/* conversion error */
moo->errnum = MOO_EECERR;
goto oops;
}
/* slen holds the length after conversion */
n = slen;
if ((flagc & FLAGC_DOT) && precision < slen) n = precision;
width -= n;
if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
{
moo_ooch_t conv_buf[32];
moo_oow_t conv_len, src_len, tot_len = 0;
while (n > 0)
{
MOO_ASSERT (moo, uslen > tot_len);
src_len = uslen - tot_len;
conv_len = MOO_COUNTOF(conv_buf);
/* this must not fail since the dry-run above was successful */
moo_convutooochars (moo, &usp[tot_len], &src_len, conv_buf, &conv_len);
tot_len += src_len;
if (conv_len > n) conv_len = n;
PUT_OOCS (conv_buf, conv_len);
n -= conv_len;
}
}
if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
#else
if (flagc & FLAGC_DOT)
{
for (n = 0; n < precision && usp[n]; n++);
}
else
{
for (n = 0; usp[n]; n++);
}
width -= n;
if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
PUT_OOCS (usp, n);
if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width);
#endif
break;
}
case 'O': /* object - ignore precision, width, adjustment */
print_object (moo, data->mask, va_arg (ap, moo_oop_t));
break;
#if 0
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
/*
case 'a':
case 'A':
*/
{
/* let me rely on snprintf until i implement float-point to string conversion */
int q;
moo_oow_t fmtlen;
#if (MOO_SIZEOF___FLOAT128 > 0) && defined(HAVE_QUADMATH_SNPRINTF)
__float128 v_qd;
#endif
long double v_ld;
double v_d;
int dtype = 0;
moo_oow_t newcapa;
if (lm_flag & LF_J)
{
#if (MOO_SIZEOF___FLOAT128 > 0) && defined(HAVE_QUADMATH_SNPRINTF) && (MOO_SIZEOF_FLTMAX_T == MOO_SIZEOF___FLOAT128)
v_qd = va_arg (ap, moo_fltmax_t);
dtype = LF_QD;
#elif MOO_SIZEOF_FLTMAX_T == MOO_SIZEOF_DOUBLE
v_d = va_arg (ap, moo_fltmax_t);
#elif MOO_SIZEOF_FLTMAX_T == MOO_SIZEOF_LONG_DOUBLE
v_ld = va_arg (ap, moo_fltmax_t);
dtype = LF_LD;
#else
#error Unsupported moo_flt_t
#endif
}
else if (lm_flag & LF_Z)
{
/* moo_flt_t is limited to double or long double */
/* precedence goes to double if sizeof(double) == sizeof(long double)
* for example, %Lf didn't work on some old platforms.
* so i prefer the format specifier with no modifier.
*/
#if MOO_SIZEOF_FLT_T == MOO_SIZEOF_DOUBLE
v_d = va_arg (ap, moo_flt_t);
#elif MOO_SIZEOF_FLT_T == MOO_SIZEOF_LONG_DOUBLE
v_ld = va_arg (ap, moo_flt_t);
dtype = LF_LD;
#else
#error Unsupported moo_flt_t
#endif
}
else if (lm_flag & (LF_LD | LF_L))
{
v_ld = va_arg (ap, long double);
dtype = LF_LD;
}
#if (MOO_SIZEOF___FLOAT128 > 0) && defined(HAVE_QUADMATH_SNPRINTF)
else if (lm_flag & (LF_QD | LF_Q))
{
v_qd = va_arg (ap, __float128);
dtype = LF_QD;
}
#endif
else if (flagc & FLAGC_LENMOD)
{
moo->errnum = MOO_EINVAL;
goto oops;
}
else
{
v_d = va_arg (ap, double);
}
fmtlen = fmt - percent;
if (fmtlen > fltfmt->capa)
{
if (fltfmt->ptr == fltfmt->buf)
{
fltfmt->ptr = MOO_MMGR_ALLOC (MOO_MMGR_GETDFL(), MOO_SIZEOF(*fltfmt->ptr) * (fmtlen + 1));
if (fltfmt->ptr == MOO_NULL) goto oops;
}
else
{
moo_mchar_t* tmpptr;
tmpptr = MOO_MMGR_REALLOC (MOO_MMGR_GETDFL(), fltfmt->ptr, MOO_SIZEOF(*fltfmt->ptr) * (fmtlen + 1));
if (tmpptr == MOO_NULL) goto oops;
fltfmt->ptr = tmpptr;
}
fltfmt->capa = fmtlen;
}
/* compose back the format specifier */
fmtlen = 0;
fltfmt->ptr[fmtlen++] = '%';
if (flagc & FLAGC_SPACE) fltfmt->ptr[fmtlen++] = ' ';
if (flagc & FLAGC_SHARP) fltfmt->ptr[fmtlen++] = '#';
if (flagc & FLAGC_SIGN) fltfmt->ptr[fmtlen++] = '+';
if (flagc & FLAGC_LEFTADJ) fltfmt->ptr[fmtlen++] = '-';
if (flagc & FLAGC_ZEROPAD) fltfmt->ptr[fmtlen++] = '0';
if (flagc & FLAGC_STAR1) fltfmt->ptr[fmtlen++] = '*';
else if (flagc & FLAGC_WIDTH)
{
fmtlen += moo_fmtuintmaxtombs (
&fltfmt->ptr[fmtlen], fltfmt->capa - fmtlen,
width, 10, -1, '\0', MOO_NULL);
}
if (flagc & FLAGC_DOT) fltfmt->ptr[fmtlen++] = '.';
if (flagc & FLAGC_STAR2) fltfmt->ptr[fmtlen++] = '*';
else if (flagc & FLAGC_PRECISION)
{
fmtlen += moo_fmtuintmaxtombs (
&fltfmt->ptr[fmtlen], fltfmt->capa - fmtlen,
precision, 10, -1, '\0', MOO_NULL);
}
if (dtype == LF_LD)
fltfmt->ptr[fmtlen++] = 'L';
#if (MOO_SIZEOF___FLOAT128 > 0)
else if (dtype == LF_QD)
fltfmt->ptr[fmtlen++] = 'Q';
#endif
fltfmt->ptr[fmtlen++] = ch;
fltfmt->ptr[fmtlen] = '\0';
#if defined(HAVE_SNPRINTF)
/* nothing special here */
#else
/* best effort to avoid buffer overflow when no snprintf is available.
* i really can't do much if it happens. */
newcapa = precision + width + 32;
if (fltout->capa < newcapa)
{
MOO_ASSERT (moo, fltout->ptr == fltout->buf);
fltout->ptr = MOO_MMGR_ALLOC (MOO_MMGR_GETDFL(), MOO_SIZEOF(char_t) * (newcapa + 1));
if (fltout->ptr == MOO_NULL) goto oops;
fltout->capa = newcapa;
}
#endif
while (1)
{
if (dtype == LF_LD)
{
#if defined(HAVE_SNPRINTF)
q = snprintf ((moo_mchar_t*)fltout->ptr, fltout->capa + 1, fltfmt->ptr, v_ld);
#else
q = sprintf ((moo_mchar_t*)fltout->ptr, fltfmt->ptr, v_ld);
#endif
}
#if (MOO_SIZEOF___FLOAT128 > 0) && defined(HAVE_QUADMATH_SNPRINTF)
else if (dtype == LF_QD)
{
q = quadmath_snprintf ((moo_mchar_t*)fltout->ptr, fltout->capa + 1, fltfmt->ptr, v_qd);
}
#endif
else
{
#if defined(HAVE_SNPRINTF)
q = snprintf ((moo_mchar_t*)fltout->ptr, fltout->capa + 1, fltfmt->ptr, v_d);
#else
q = sprintf ((moo_mchar_t*)fltout->ptr, fltfmt->ptr, v_d);
#endif
}
if (q <= -1) goto oops;
if (q <= fltout->capa) break;
newcapa = fltout->capa * 2;
if (newcapa < q) newcapa = q;
if (fltout->ptr == fltout->sbuf)
{
fltout->ptr = MOO_MMGR_ALLOC (MOO_MMGR_GETDFL(), MOO_SIZEOF(char_t) * (newcapa + 1));
if (fltout->ptr == MOO_NULL) goto oops;
}
else
{
char_t* tmpptr;
tmpptr = MOO_MMGR_REALLOC (MOO_MMGR_GETDFL(), fltout->ptr, MOO_SIZEOF(char_t) * (newcapa + 1));
if (tmpptr == MOO_NULL) goto oops;
fltout->ptr = tmpptr;
}
fltout->capa = newcapa;
}
if (MOO_SIZEOF(char_t) != MOO_SIZEOF(moo_mchar_t))
{
fltout->ptr[q] = '\0';
while (q > 0)
{
q--;
fltout->ptr[q] = ((moo_mchar_t*)fltout->ptr)[q];
}
}
sp = fltout->ptr;
flagc &= ~FLAGC_DOT;
width = 0;
precision = 0;
goto print_lowercase_s;
}
#endif
handle_nosign:
sign = 0;
if (lm_flag & LF_J)
{
#if defined(__GNUC__) && \
(MOO_SIZEOF_UINTMAX_T > MOO_SIZEOF_OOW_T) && \
(MOO_SIZEOF_UINTMAX_T != MOO_SIZEOF_LONG_LONG) && \
(MOO_SIZEOF_UINTMAX_T != MOO_SIZEOF_LONG)
/* GCC-compiled binaries crashed when getting moo_uintmax_t with va_arg.
* This is just a work-around for it */
int i;
for (i = 0, num = 0; i < MOO_SIZEOF(moo_uintmax_t) / MOO_SIZEOF(moo_oow_t); i++)
{
#if defined(MOO_ENDIAN_BIG)
num = num << (8 * MOO_SIZEOF(moo_oow_t)) | (va_arg (ap, moo_oow_t));
#else
register int shift = i * MOO_SIZEOF(moo_oow_t);
moo_oow_t x = va_arg (ap, moo_oow_t);
num |= (moo_uintmax_t)x << (shift * 8);
#endif
}
#else
num = va_arg (ap, moo_uintmax_t);
#endif
}
#if 0
else if (lm_flag & LF_T)
num = va_arg (ap, moo_ptrdiff_t);
#endif
else if (lm_flag & LF_Z)
num = va_arg (ap, moo_oow_t);
#if (MOO_SIZEOF_LONG_LONG > 0)
else if (lm_flag & LF_Q)
num = va_arg (ap, unsigned long long int);
#endif
else if (lm_flag & (LF_L | LF_LD))
num = va_arg (ap, unsigned long int);
else if (lm_flag & LF_H)
num = (unsigned short int)va_arg (ap, int);
else if (lm_flag & LF_C)
num = (unsigned char)va_arg (ap, int);
else
num = va_arg (ap, unsigned int);
goto number;
handle_sign:
if (lm_flag & LF_J)
{
#if defined(__GNUC__) && \
(MOO_SIZEOF_INTMAX_T > MOO_SIZEOF_OOI_T) && \
(MOO_SIZEOF_UINTMAX_T != MOO_SIZEOF_LONG_LONG) && \
(MOO_SIZEOF_UINTMAX_T != MOO_SIZEOF_LONG)
/* GCC-compiled binraries crashed when getting moo_uintmax_t with va_arg.
* This is just a work-around for it */
int i;
for (i = 0, num = 0; i < MOO_SIZEOF(moo_intmax_t) / MOO_SIZEOF(moo_oow_t); i++)
{
#if defined(MOO_ENDIAN_BIG)
num = num << (8 * MOO_SIZEOF(moo_oow_t)) | (va_arg (ap, moo_oow_t));
#else
register int shift = i * MOO_SIZEOF(moo_oow_t);
moo_oow_t x = va_arg (ap, moo_oow_t);
num |= (moo_uintmax_t)x << (shift * 8);
#endif
}
#else
num = va_arg (ap, moo_intmax_t);
#endif
}
#if 0
else if (lm_flag & LF_T)
num = va_arg(ap, moo_ptrdiff_t);
#endif
else if (lm_flag & LF_Z)
num = va_arg (ap, moo_ooi_t);
#if (MOO_SIZEOF_LONG_LONG > 0)
else if (lm_flag & LF_Q)
num = va_arg (ap, long long int);
#endif
else if (lm_flag & (LF_L | LF_LD))
num = va_arg (ap, long int);
else if (lm_flag & LF_H)
num = (short int)va_arg (ap, int);
else if (lm_flag & LF_C)
num = (char)va_arg (ap, int);
else
num = va_arg (ap, int);
number:
if (sign && (moo_intmax_t)num < 0)
{
neg = 1;
num = -(moo_intmax_t)num;
}
nbufp = sprintn (nbuf, num, base, &tmp);
if ((flagc & FLAGC_SHARP) && num != 0)
{
if (base == 8) tmp++;
else if (base == 16) tmp += 2;
}
if (neg) tmp++;
else if (flagc & FLAGC_SIGN) tmp++;
else if (flagc & FLAGC_SPACE) tmp++;
numlen = (int)((const moo_bch_t*)nbufp - (const moo_bch_t*)nbuf);
if ((flagc & FLAGC_DOT) && precision > numlen)
{
/* extra zeros for precision specified */
tmp += (precision - numlen);
}
if (!(flagc & FLAGC_LEFTADJ) && !(flagc & FLAGC_ZEROPAD) && width > 0 && (width -= tmp) > 0)
{
PUT_OOCH (padc, width);
width = 0;
}
if (neg) PUT_OOCH ('-', 1);
else if (flagc & FLAGC_SIGN) PUT_OOCH ('+', 1);
else if (flagc & FLAGC_SPACE) PUT_OOCH (' ', 1);
if ((flagc & FLAGC_SHARP) && num != 0)
{
if (base == 8)
{
PUT_OOCH ('0', 1);
}
else if (base == 16)
{
PUT_OOCH ('0', 1);
PUT_OOCH ('x', 1);
}
}
if ((flagc & FLAGC_DOT) && precision > numlen)
{
/* extra zeros for precision specified */
PUT_OOCH ('0', precision - numlen);
}
if (!(flagc & FLAGC_LEFTADJ) && width > 0 && (width -= tmp) > 0)
{
PUT_OOCH (padc, width);
}
while (*nbufp) PUT_OOCH (*nbufp--, 1); /* output actual digits */
if ((flagc & FLAGC_LEFTADJ) && width > 0 && (width -= tmp) > 0)
{
PUT_OOCH (padc, width);
}
break;
invalid_format:
#if defined(FMTCHAR_IS_OOCH)
PUT_OOCS (percent, fmt - percent);
#else
while (percent < fmt) PUT_OOCH (*percent++, 1);
#endif
break;
default:
#if defined(FMTCHAR_IS_OOCH)
PUT_OOCS (percent, fmt - percent);
#else
while (percent < fmt) PUT_OOCH (*percent++, 1);
#endif
/*
* Since we ignore an formatting argument it is no
* longer safe to obey the remaining formatting
* arguments as the arguments will no longer match
* the format specs.
*/
stop = 1;
break;
}
}
done:
return 0;
oops:
return -1;
}
#undef PUT_OOCH

767
moo/lib/main.c Normal file
View File

@ -0,0 +1,767 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#if defined(_WIN32)
# include <windows.h>
# include <tchar.h>
# if defined(MOO_HAVE_CFG_H)
# include <ltdl.h>
# define USE_LTDL
# endif
#elif defined(__OS2__)
# define INCL_DOSMODULEMGR
# define INCL_DOSPROCESS
# define INCL_DOSERRORS
# include <os2.h>
#elif defined(__MSDOS__)
# include <dos.h>
#elif defined(macintosh)
# include <Timer.h>
#else
# include <unistd.h>
# include <ltdl.h>
# define USE_LTDL
# if defined(HAVE_TIME_H)
# include <time.h>
# endif
# if defined(HAVE_SYS_TIME_H)
# include <sys/time.h>
# endif
# if defined(HAVE_SIGNAL_H)
# include <signal.h>
# endif
#endif
#if !defined(MOO_DEFAULT_MODPREFIX)
# if defined(_WIN32)
# define MOO_DEFAULT_MODPREFIX "moo-"
# elif defined(__OS2__)
# define MOO_DEFAULT_MODPREFIX "st-"
# elif defined(__MSDOS__)
# define MOO_DEFAULT_MODPREFIX "st-"
# else
# define MOO_DEFAULT_MODPREFIX "libmoo-"
# endif
#endif
#if !defined(MOO_DEFAULT_MODPOSTFIX)
# if defined(_WIN32)
# define MOO_DEFAULT_MODPOSTFIX ""
# elif defined(__OS2__)
# define MOO_DEFAULT_MODPOSTFIX ""
# elif defined(__MSDOS__)
# define MOO_DEFAULT_MODPOSTFIX ""
# else
# define MOO_DEFAULT_MODPOSTFIX ""
# endif
#endif
typedef struct bb_t bb_t;
struct bb_t
{
char buf[1024];
moo_oow_t pos;
moo_oow_t len;
FILE* fp;
};
typedef struct xtn_t xtn_t;
struct xtn_t
{
const char* source_path; /* main source file */
};
/* ========================================================================= */
static void* sys_alloc (moo_mmgr_t* mmgr, moo_oow_t size)
{
return malloc (size);
}
static void* sys_realloc (moo_mmgr_t* mmgr, void* ptr, moo_oow_t size)
{
return realloc (ptr, size);
}
static void sys_free (moo_mmgr_t* mmgr, void* ptr)
{
free (ptr);
}
static moo_mmgr_t sys_mmgr =
{
sys_alloc,
sys_realloc,
sys_free,
MOO_NULL
};
/* ========================================================================= */
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
# define IS_PATH_SEP(c) ((c) == '/' || (c) == '\\')
#else
# define IS_PATH_SEP(c) ((c) == '/')
#endif
static const moo_bch_t* get_base_name (const moo_bch_t* path)
{
const moo_bch_t* p, * last = MOO_NULL;
for (p = path; *p != '\0'; p++)
{
if (IS_PATH_SEP(*p)) last = p;
}
return (last == MOO_NULL)? path: (last + 1);
}
static MOO_INLINE moo_ooi_t open_input (moo_t* moo, moo_ioarg_t* arg)
{
xtn_t* xtn = moo_getxtn(moo);
bb_t* bb;
FILE* fp;
if (arg->includer)
{
/* includee */
moo_bch_t bcs[1024]; /* TODO: right buffer size */
moo_oow_t bcslen = MOO_COUNTOF(bcs);
moo_oow_t ucslen;
if (moo_convootobcstr (moo, arg->name, &ucslen, bcs, &bcslen) <= -1)
{
moo_seterrnum (moo, MOO_EECERR);
return -1;
}
/* TODO: make bcs relative to the includer */
#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__)
fp = fopen (bcs, "rb");
#else
fp = fopen (bcs, "r");
#endif
}
else
{
/* main stream */
#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__)
fp = fopen (xtn->source_path, "rb");
#else
fp = fopen (xtn->source_path, "r");
#endif
}
if (!fp)
{
moo_seterrnum (moo, MOO_EIOERR);
return -1;
}
bb = moo_callocmem (moo, MOO_SIZEOF(*bb));
if (!bb)
{
fclose (fp);
return -1;
}
bb->fp = fp;
arg->handle = bb;
return 0;
}
static MOO_INLINE moo_ooi_t close_input (moo_t* moo, moo_ioarg_t* arg)
{
xtn_t* xtn = moo_getxtn(moo);
bb_t* bb;
bb = (bb_t*)arg->handle;
MOO_ASSERT (moo, bb != MOO_NULL && bb->fp != MOO_NULL);
fclose (bb->fp);
moo_freemem (moo, bb);
arg->handle = MOO_NULL;
return 0;
}
static MOO_INLINE moo_ooi_t read_input (moo_t* moo, moo_ioarg_t* arg)
{
/*xtn_t* xtn = hcl_getxtn(hcl);*/
bb_t* bb;
moo_oow_t bcslen, ucslen, remlen;
int x;
bb = (bb_t*)arg->handle;
MOO_ASSERT (moo, bb != MOO_NULL && bb->fp != MOO_NULL);
do
{
x = fgetc (bb->fp);
if (x == EOF)
{
if (ferror((FILE*)bb->fp))
{
moo_seterrnum (moo, MOO_EIOERR);
return -1;
}
break;
}
bb->buf[bb->len++] = x;
}
while (bb->len < MOO_COUNTOF(bb->buf) && x != '\r' && x != '\n');
bcslen = bb->len;
ucslen = MOO_COUNTOF(arg->buf);
x = moo_convbtooochars (moo, bb->buf, &bcslen, arg->buf, &ucslen);
x = moo_convbtooochars (moo, bb->buf, &bcslen, arg->buf, &ucslen);
if (x <= -1 && ucslen <= 0)
{
moo_seterrnum (moo, MOO_EECERR);
return -1;
}
remlen = bb->len - bcslen;
if (remlen > 0) memmove (bb->buf, &bb->buf[bcslen], remlen);
bb->len = remlen;
return ucslen;
}
static moo_ooi_t input_handler (moo_t* moo, moo_iocmd_t cmd, moo_ioarg_t* arg)
{
switch (cmd)
{
case MOO_IO_OPEN:
return open_input (moo, arg);
case MOO_IO_CLOSE:
return close_input (moo, arg);
case MOO_IO_READ:
return read_input (moo, arg);
default:
moo->errnum = MOO_EINTERN;
return -1;
}
}
/* ========================================================================= */
static void* dl_open (moo_t* moo, const moo_ooch_t* name)
{
#if defined(USE_LTDL)
/* TODO: support various platforms */
moo_bch_t buf[1024]; /* TODO: use a proper path buffer */
moo_oow_t ucslen, bcslen;
moo_oow_t len;
void* handle;
/* TODO: using MODPREFIX isn't a good idea for all kind of modules.
* OK to use it for a primitive module.
* NOT OK to use it for a FFI target.
* Attempting /home/hyung-hwan/xxx/lib/libmoo-libc.so.6 followed by libc.so.6 is bad.
* Need to accept the type or flags?
*
* dl_open (moo, "xxxx", MOO_MOD_EXTERNAL);
* if external, don't use DEFAULT_MODPERFIX and MODPOSTFIX???
*/
len = moo_copybcstr (buf, MOO_COUNTOF(buf), MOO_DEFAULT_MODPREFIX);
/* TODO: proper error checking and overflow checking */
bcslen = MOO_COUNTOF(buf) - len;
moo_convootobcstr (moo, name, &ucslen, &buf[len], &bcslen);
moo_copybcstr (&buf[bcslen + len], MOO_COUNTOF(buf) - bcslen - len, MOO_DEFAULT_MODPOSTFIX);
handle = lt_dlopenext (buf);
if (!handle)
{
buf[bcslen + len] = '\0';
handle = lt_dlopenext (&buf[len]);
if (handle) MOO_DEBUG2 (moo, "Opened module file %s handle %p\n", &buf[len], handle);
}
else
{
MOO_DEBUG2 (moo, "Opened module file %s handle %p\n", buf, handle);
}
return handle;
#else
/* TODO: implemenent this */
return MOO_NULL;
#endif
}
static void dl_close (moo_t* moo, void* handle)
{
MOO_DEBUG1 (moo, "Closed module handle %p\n", handle);
#if defined(USE_LTDL)
lt_dlclose (handle);
#elif defined(_WIN32)
FreeLibrary ((HMODULE)handle);
#elif defined(__OS2__)
DosFreeModule ((HMODULE)handle);
#elif defined(__MSDOS__) && defined(QSE_ENABLE_DOS_DYNAMIC_MODULE)
FreeModule (handle);
#else
/* nothing to do */
#endif
}
static void* dl_getsym (moo_t* moo, void* handle, const moo_ooch_t* name)
{
#if defined(USE_LTDL)
moo_bch_t buf[1024]; /* TODO: use a proper buffer. dynamically allocated if conversion result in too a large value */
moo_oow_t ucslen, bcslen;
void* sym;
const char* symname;
buf[0] = '_';
bcslen = MOO_COUNTOF(buf) - 2;
moo_convootobcstr (moo, name, &ucslen, &buf[1], &bcslen); /* TODO: error check */
symname = &buf[1];
sym = lt_dlsym (handle, symname);
if (!sym)
{
symname = &buf[0];
sym = lt_dlsym (handle, symname);
if (!sym)
{
buf[bcslen + 1] = '_';
buf[bcslen + 2] = '\0';
symname = &buf[1];
sym = lt_dlsym (handle, symname);
if (!sym)
{
symname = &buf[0];
sym = lt_dlsym (handle, symname);
}
}
}
if (sym) MOO_DEBUG2 (moo, "Loaded module symbol %s from handle %p\n", symname, handle);
return sym;
#else
/* TODO: IMPLEMENT THIS */
return MOO_NULL;
#endif
}
/* ========================================================================= */
static int write_all (int fd, const char* ptr, moo_oow_t len)
{
while (len > 0)
{
moo_ooi_t wr;
wr = write (1, ptr, len);
if (wr <= -1)
{
/*if (errno == EAGAIN || errno == EWOULDBLOCK)
{
push it to internal buffers? before writing data just converted, need to write buffered data first.
}*/
return -1;
}
ptr += wr;
len -= wr;
}
return 0;
}
static void log_write (moo_t* moo, moo_oow_t mask, const moo_ooch_t* msg, moo_oow_t len)
{
#if defined(_WIN32)
# error NOT IMPLEMENTED
#else
moo_bch_t buf[256];
moo_oow_t ucslen, bcslen, msgidx;
int n;
char ts[32];
size_t tslen;
struct tm tm, *tmp;
time_t now;
if (mask & MOO_LOG_GC) return; /* don't show gc logs */
/* TODO: beautify the log message.
* do classification based on mask. */
now = time(NULL);
#if defined(__MSDOS__)
tmp = localtime (&now);
#else
tmp = localtime_r (&now, &tm);
#endif
tslen = strftime (ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %z ", tmp);
if (tslen == 0)
{
strcpy (ts, "0000-00-00 00:00:00 +0000");
tslen = 25;
}
write_all (1, ts, tslen);
msgidx = 0;
while (len > 0)
{
ucslen = len;
bcslen = MOO_COUNTOF(buf);
n = moo_convootobchars (moo, &msg[msgidx], &ucslen, buf, &bcslen);
if (n == 0 || n == -2)
{
/* n = 0:
* converted all successfully
* n == -2:
* buffer not sufficient. not all got converted yet.
* write what have been converted this round. */
MOO_ASSERT (moo, ucslen > 0); /* if this fails, the buffer size must be increased */
/* attempt to write all converted characters */
if (write_all (1, buf, bcslen) <= -1) break;
if (n == 0) break;
else
{
msgidx += ucslen;
len -= ucslen;
}
}
else if (n <= -1)
{
/* conversion error */
break;
}
}
#endif
}
/* ========================================================================= */
static moo_ooch_t str_my_object[] = { 'M', 'y', 'O', 'b','j','e','c','t' };
static moo_ooch_t str_main[] = { 'm', 'a', 'i', 'n' };
static moo_t* g_moo = MOO_NULL;
/* ========================================================================= */
#if defined(__MSDOS__) && defined(_INTELC32_)
static void (*prev_timer_intr_handler) (void);
#pragma interrupt(timer_intr_handler)
static void timer_intr_handler (void)
{
/*
_XSTACK *stk;
int r;
stk = (_XSTACK *)_get_stk_frame();
r = (unsigned short)stk_ptr->eax;
*/
/* The timer interrupt (normally) occurs 18.2 times per second. */
if (g_moo) moo_switchprocess (g_moo);
_chain_intr(prev_timer_intr_handler);
}
#elif defined(macintosh)
static TMTask g_tmtask;
static ProcessSerialNumber g_psn;
#define TMTASK_DELAY 50 /* milliseconds if positive, microseconds(after negation) if negative */
static pascal void timer_intr_handler (TMTask* task)
{
if (g_moo) moo_switchprocess (g_moo);
WakeUpProcess (&g_psn);
PrimeTime ((QElem*)&g_tmtask, TMTASK_DELAY);
}
#else
static void arrange_process_switching (int sig)
{
if (g_moo) moo_switchprocess (g_moo);
}
#endif
static void setup_tick (void)
{
#if defined(__MSDOS__) && defined(_INTELC32_)
prev_timer_intr_handler = _dos_getvect (0x1C);
_dos_setvect (0x1C, timer_intr_handler);
#elif defined(macintosh)
GetCurrentProcess (&g_psn);
memset (&g_tmtask, 0, MOO_SIZEOF(g_tmtask));
g_tmtask.tmAddr = NewTimerProc (timer_intr_handler);
InsXTime ((QElem*)&g_tmtask);
PrimeTime ((QElem*)&g_tmtask, TMTASK_DELAY);
#elif defined(HAVE_SETITIMER) && defined(SIGVTALRM) && defined(ITIMER_VIRTUAL)
struct itimerval itv;
struct sigaction act;
sigemptyset (&act.sa_mask);
act.sa_handler = arrange_process_switching;
act.sa_flags = 0;
sigaction (SIGVTALRM, &act, MOO_NULL);
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 100; /* 100 microseconds */
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 100;
setitimer (ITIMER_VIRTUAL, &itv, MOO_NULL);
#else
# error UNSUPPORTED
#endif
}
static void cancel_tick (void)
{
#if defined(__MSDOS__) && defined(_INTELC32_)
_dos_setvect (0x1C, prev_timer_intr_handler);
#elif defined(macintosh)
RmvTime ((QElem*)&g_tmtask);
/*DisposeTimerProc (g_tmtask.tmAddr);*/
#elif defined(HAVE_SETITIMER) && defined(SIGVTALRM) && defined(ITIMER_VIRTUAL)
struct itimerval itv;
struct sigaction act;
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 0; /* make setitimer() one-shot only */
itv.it_value.tv_usec = 0;
setitimer (ITIMER_VIRTUAL, &itv, MOO_NULL);
sigemptyset (&act.sa_mask);
act.sa_handler = SIG_IGN; /* ignore the signal potentially fired by the one-shot arrange above */
act.sa_flags = 0;
sigaction (SIGVTALRM, &act, MOO_NULL);
#else
# error UNSUPPORTED
#endif
}
/* ========================================================================= */
int main (int argc, char* argv[])
{
moo_t* moo;
xtn_t* xtn;
moo_oocs_t objname;
moo_oocs_t mthname;
moo_vmprim_t vmprim;
int i, xret;
#if !defined(macintosh)
if (argc < 2)
{
fprintf (stderr, "Usage: %s filename ...\n", argv[0]);
return -1;
}
#endif
vmprim.dl_open = dl_open;
vmprim.dl_close = dl_close;
vmprim.dl_getsym = dl_getsym;
vmprim.log_write = log_write;
#if defined(USE_LTDL)
lt_dlinit ();
#endif
moo = moo_open (&sys_mmgr, MOO_SIZEOF(xtn_t), 2048000lu, &vmprim, MOO_NULL);
if (!moo)
{
printf ("cannot open moo\n");
return -1;
}
{
moo_oow_t tab_size;
tab_size = 5000;
moo_setoption (moo, MOO_SYMTAB_SIZE, &tab_size);
tab_size = 5000;
moo_setoption (moo, MOO_SYSDIC_SIZE, &tab_size);
tab_size = 600;
moo_setoption (moo, MOO_PROCSTK_SIZE, &tab_size);
}
{
int trait = 0;
/*trait |= MOO_NOGC;*/
trait |= MOO_AWAIT_PROCS;
moo_setoption (moo, MOO_TRAIT, &trait);
}
if (moo_ignite(moo) <= -1)
{
printf ("cannot ignite moo - %d\n", moo_geterrnum(moo));
moo_close (moo);
return -1;
}
xtn = moo_getxtn (moo);
#if defined(macintosh)
i = 20;
xtn->source_path = "test.st";
goto compile;
#endif
for (i = 1; i < argc; i++)
{
xtn->source_path = argv[i];
compile:
if (moo_compile (moo, input_handler) <= -1)
{
if (moo->errnum == MOO_ESYNTAX)
{
moo_synerr_t synerr;
moo_bch_t bcs[1024]; /* TODO: right buffer size */
moo_oow_t bcslen, ucslen;
moo_getsynerr (moo, &synerr);
printf ("ERROR: ");
if (synerr.loc.file)
{
bcslen = MOO_COUNTOF(bcs);
if (moo_convootobcstr (moo, synerr.loc.file, &ucslen, bcs, &bcslen) >= 0)
{
printf ("%.*s ", (int)bcslen, bcs);
}
}
else
{
printf ("%s ", xtn->source_path);
}
printf ("syntax error at line %lu column %lu - ",
(unsigned long int)synerr.loc.line, (unsigned long int)synerr.loc.colm);
bcslen = MOO_COUNTOF(bcs);
if (moo_convootobcstr (moo, moo_synerrnumtoerrstr(synerr.num), &ucslen, bcs, &bcslen) >= 0)
{
printf (" [%.*s]", (int)bcslen, bcs);
}
if (synerr.tgt.len > 0)
{
bcslen = MOO_COUNTOF(bcs);
ucslen = synerr.tgt.len;
if (moo_convootobchars (moo, synerr.tgt.ptr, &ucslen, bcs, &bcslen) >= 0)
{
printf (" [%.*s]", (int)bcslen, bcs);
}
}
printf ("\n");
}
else
{
printf ("ERROR: cannot compile code - %d\n", moo_geterrnum(moo));
}
moo_close (moo);
#if defined(USE_LTDL)
lt_dlexit ();
#endif
return -1;
}
}
printf ("COMPILE OK. STARTING EXECUTION ...\n");
xret = 0;
g_moo = moo;
setup_tick ();
objname.ptr = str_my_object;
objname.len = 8;
mthname.ptr = str_main;
mthname.len = 4;
if (moo_invoke (moo, &objname, &mthname) <= -1)
{
printf ("ERROR: cannot execute code - %d\n", moo_geterrnum(moo));
xret = -1;
}
cancel_tick ();
g_moo = MOO_NULL;
/*moo_dumpsymtab(moo);
*moo_dumpdic(moo, moo->sysdic, "System dictionary");*/
moo_close (moo);
#if defined(USE_LTDL)
lt_dlexit ();
#endif
#if defined(_WIN32) && defined(_DEBUG)
getchar();
#endif
return xret;
}

637
moo/lib/memo.txt Normal file
View File

@ -0,0 +1,637 @@
/*
* Multi-Process within a single threaded-process.
* How to embed in a single threaded web server
*
*
* moo_exec
* VM(shceduler) ---> Context1(obj1,method1)
* ---> Context2(obj2,method2)
* ---> Context3(obj3,method3)
*
* all functions must be asynchronous
* blocking functions will block scheduler.
*/
class Stix::Stix # Namespace name is indicated by ::
{
}
class Stix::Array
{
+ makeSymbol: aString
{
| s |
s := Symbol new: aString. # Symbol belongs to the Stix namespace.
^s.
}
}
A name space is stored in the namespace table of Stix.Namespaces.
Stix.Symbols - symbols are global. not affected by namespaces.
Stix.Sysdict -
(#QSE => Namespace( Another Sysdict))
(
class Stix::Namespace
{
}
class Stix::Class
{
}
Stix.Namespaces is a system dictionary
class QSE::Array
{
}
class QSE::Tiara::Array
{
}
Stix.Namespaces -> 'QSE'
'QSE::Tiara'
------------------------------------------------------------
ARRAY CONSTANT TO ALLOW DYNAMIC VALUES.
#( ...... ) array literal
in original smalltalk, a block can't be placed inside the array literal
arrayConstant := '#' array
array := "(" { number | string | symbol | array | characterConstant }* ")".
So #(1 2 [^20]) is illegal.
if a block is there, treat it as a valid moo expression and evaluate it.
#(1 2 [1 + 2] 5)
t = Array new: 4.
t at: 1 put: 1.
t at: 2 put: 2.
t at: 3 put: (1 + 2).
t at: 4 put: 5.
Evaluate the expressions in the array first
Create an array
Put the right element.
-----------------------------------------------
command line
libmoo.a
moo moo.im Class1.st Class2.st Main.st Main
--> load the image, compile Class1.st, compile Class2.st compile Main.st
-->
moo moo.im
--> load the image
-------------------------------------------------------------------------
#!/usr/bin/moo
###################################
## Main.st
###################################
#include 'Class1.st'
#include 'Class2.st'
#class(#byte) Association(Magnitude)
{
declare a, b, c.
declare(#classinst) x.
declare(#class) MAX_SIZE.
function(#class) initialize
{
MAX_SIZE := 20.
true whileTrue: [
Stdout print: 10.
].
}
function(#class) new: anInteger
{
Stix error: 'invalid message'.
}
}
#main
| a |
a := Class1 new.
Stdout format: #( 1 2 [a toInteger] ) with: '%.5d %.6d\n'.
^0.
-------------------------------------------------------------------------
The statements after the #main directives are compiled as a class method of Stix.
That is, 'Stix::main'. It becomes the entry point.
-------------------------------------------------------------------------
If no #main directive is found, there is no official entry point.
However, if you have the initialize class method, it's invoked when a class
is compiled, the statement in the class is executed before #main.
if the statement creates a certain loop, it can act as a entry point as well.
--------------------------------------------------------------------------
Top level directive
#main, #class, #include,
#include is avaialble everywheren. It doesn't have to be in the top level.
Do i need #import?
---------------------------------------------------------------------------
if there are multiple #main, do i need to concatenate all?
or disallow only 1 #main??
---------------------------------------------------------------------------
#namespace directive?
#namespace Stix::Compiler
naming convention for multiple ?? . conflicts with the statement terminator.
:: is ok a single : is used for various purpose but more than 1 is illegal in smalltalk.
so use :: as a namespace separator.
Relative naming and absoluate naming?
Stix::Compiler <- is Stix the absolute top or a subname class under the current space?
::Stix::Compiler <- i don't like this
----------------------------------------------------------------------------
"
Stix
Class
NilObject
Object
NilObject
Collection
IndexedCollection
FixedSizedCollection
Array
ByteArray
String
Symbol
Set
Dictionary
SystemDictionary
SymbolSet
Magnitude
Association
Character
Number
Integer
SmallInteger
LargeInteger
"
class Stix
{
+ alloc
{
<primitive: 1>
}
+ new
{
^self alloc init.
}
- init
{
^self.
}
- finalize
{
}
+ findClass: aString
{
| a b c |
}
}
class Class extends Stix
{
}
class NilObject extends Stix
{
}
class Object extends Stix
{
}
-----------------------------------------
class variable
and class instance variable
-----------------------------------------
A CV X Y
CIV x y
B CV Z
civ z
C civ q
A: getX
return x (return instance variable 1)
B getX
return A'X (return invance variable 3)
x is index 1.
y is index 2.
z is index 3.
X is index 3 of A.
Y is index 3 of A.
Z is index 2 of B.
q is index 4 of C.
A has x y X Y
B has x y z Z
C has x y z q
place class intance variables before class variables.
-------------------------------------------
class Magnitude extends Stix
{
}
%include 'Association.st'
%class Association(Magnitude)
{
%category(Association class)
%constant
ABC := XXX
BCD := KKK
TTT := 20
%self(private)
%self(instance creation)
| Key Value | "class variables" <--- index
| xxx yyy | "class instance variables" <--- index
key: aKey
{
^self key: aKey value: nil.
}
key: aKey value: aValue
{
| ass |
ass := self new.
ass key: aKey value: aValue.
^ass.
}
%instance(initialization)
| key value | "instance variables"
key: aKey value: aValue
{
key := aKey.
value := aValue.
}
key
{
^key
}
value
{
^value
}
value: value
{
self->value := aValue
}
= anAssociation
{
^self->key = anAssociation key.
}
hash
{
^self->key hash
}
}
"Creates a new class Association inheriting nil"
%class Association(nil)
{
%func more
{
^self
}
}
"Extends an existing Association class"
%class Association
{
}
class Character extends Magnitude
{
}
class Number extends Magnitude
{
}
class Integer extends Number
{
}
class SmallInteger extends Integer
{
}
class LargeInteger extends Integer
{
}
Association
{
%class
| x y z |
value: xxx
{
}
}
Association: Magnitude
{
}
Association: <- for extending
{
}
Association:
{
}
Association key: xxx
{
}
Association key: xxx
{
}
----------------------------------------------------------------
class ByteArray(FixedSizeCollection): #byte
{
fun at: anIndex put: aValue
{
^self basicAt: anIndex put: aValue.
}
}
class(#byte) ByteArray(FixedSizedCollection)
{
}
class(#byte) ByteArray(Stix)
{
}
class Association(Magnitude) -> new Association inheriting Magnitude
class Association() -> new Association inheriting Stix
class(#byte) Association() -> new Association class inheriting Stix, but it's byte indexed.
class(#word) Association() -> new Association class inheriting Stix, but it's word indexed.
class(#pointer) Association() -> new Association class inheriting Stix, but it's oop indexed. (it can have the variable part on top of the fixed part. response to the 'new: aSize' message)
class(#word) Association(Magnitude) -> new Association class inheriting Magnitude, but it's word indexed.
class(#character) Association(Magnitude)
class Association -> revisit the Association class defined previsously. Revisiting can add new methods.
#include 'Magnitude.st'
#class(#byte) Association(Magnitude)
{
## class variables can be accessed by class methods and instance methods.
## methods of subclasses can also access them.
declare(#class) a b c.
## class instance variable can be accessed inside the class method only.
declare(#classinst) d, e, f
## All instance variables are protected by default.
declare key, value.
##
## declare(#class) a, b, c. ## class variables
## declare(#classinst) a, b, c. ## class instance variables
## declare(#instance) a, b, c. ## isntance variables
## declare a,b, c. ## instance variables
## function(#class) ## class method
## function(#instance) ## instance method
## function ## instance method
## dcl(#class) a, b, c. ## short form
## dcl(#classinst) a, b, c
## fun(#class)
## var and fun are not keywords. they can be a method name or a variable name.
## Casing is not used to differentiate variable kinds like global local temporary etc.
## other modifiers (EXPERIMENTAL. JUST THINKING).
## declare(#class #public #rw) x. x can be accessed by other classes in read-write mode.
## function(#private) xxx xxx is a private method
## function(#class #private) xxx xxx is private class method.
function(#class) initialize
{
## This is the initilizer for the class object.
## executed when this class is added to the system.
## initialize the class variables and class instance variables.
SIZE := 20.
}
function(#class) key: aKey
{
^self key: aKey value: nil.
}
function(#class) key: aKey value: aValue
{
| ass |
ass := self new.
ass key: aKey value: aValue.
^ass.
}
function key: aKey value: aValue
{
key := aKey.
value := aValue.
}
function key
{
^key
}
function value
{
^value
}
function value: value
{
self->value := aValue
}
function = anAssociation
{
^self->key = anAssociation key.
}
function hash
{
^self->key hash
}
function value: aBlock
{
|a |
a := [ :t1 | t1 value ] with: 10.
^a + 10.
}
}
; message cascading
. steatement terminator or flaoting point if in number and followed by a digit.
^ return
[ ] block
# symbol or array
() grouping
$ character constant
| temporary variable or end of block arguments.
"" comment
'' string
: at the of the keyword or before block argument name.
-------------------
avaialbel
' !
--------------------------------------------------
#! for comment
## for comment
-----------------------------
@ binarySelector for coordianate number @ number.
----------------------------------------------------------------------------
Single line comment
## comment text
#! comment text (easy handling to skip hash bang)
Multi-line comments - double quoted as in smalltalk
" comment text "
#class X(Y)
{
#dcl a b c.
#fun print
{
}
}

541
moo/lib/moo-cfg.h.in Normal file
View File

@ -0,0 +1,541 @@
/* lib/moo-cfg.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
/* Define to 1 if you have the `acosq' function. */
#undef HAVE_ACOSQ
/* Define to 1 if you have the `argz_add' function. */
#undef HAVE_ARGZ_ADD
/* Define to 1 if you have the `argz_append' function. */
#undef HAVE_ARGZ_APPEND
/* Define to 1 if you have the `argz_count' function. */
#undef HAVE_ARGZ_COUNT
/* Define to 1 if you have the `argz_create_sep' function. */
#undef HAVE_ARGZ_CREATE_SEP
/* Define to 1 if you have the <argz.h> header file. */
#undef HAVE_ARGZ_H
/* Define to 1 if you have the `argz_insert' function. */
#undef HAVE_ARGZ_INSERT
/* Define to 1 if you have the `argz_next' function. */
#undef HAVE_ARGZ_NEXT
/* Define to 1 if you have the `argz_stringify' function. */
#undef HAVE_ARGZ_STRINGIFY
/* Define to 1 if you have the `asinq' function. */
#undef HAVE_ASINQ
/* Define to 1 if you have the `atan2q' function. */
#undef HAVE_ATAN2Q
/* Define to 1 if you have the `atanq' function. */
#undef HAVE_ATANQ
/* Define to 1 if you have the `backtrace' function. */
#undef HAVE_BACKTRACE
/* Define to 1 if you have the `backtrace_symbols' function. */
#undef HAVE_BACKTRACE_SYMBOLS
/* Define to 1 if you have the `ceilq' function. */
#undef HAVE_CEILQ
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
/* Define to 1 if you have the `clock_settime' function. */
#undef HAVE_CLOCK_SETTIME
/* Define to 1 if you have the `closedir' function. */
#undef HAVE_CLOSEDIR
/* Define to 1 if you have the `coshq' function. */
#undef HAVE_COSHQ
/* Define to 1 if you have the `cosq' function. */
#undef HAVE_COSQ
/* Define if c++ supports namespace std. */
#undef HAVE_CXX_NAMESPACE_STD
/* Define to 1 if you have the declaration of `cygwin_conv_path', and to 0 if
you don't. */
#undef HAVE_DECL_CYGWIN_CONV_PATH
/* Define to 1 if you have the <dirent.h> header file. */
#undef HAVE_DIRENT_H
/* Define if you have the GNU dld library. */
#undef HAVE_DLD
/* Define to 1 if you have the <dld.h> header file. */
#undef HAVE_DLD_H
/* Define to 1 if you have the `dlerror' function. */
#undef HAVE_DLERROR
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <dl.h> header file. */
#undef HAVE_DL_H
/* Define if you have the _dyld_func_lookup function. */
#undef HAVE_DYLD
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
/* Define to 1 if the system has the type `error_t'. */
#undef HAVE_ERROR_T
/* Define to 1 if you have the <execinfo.h> header file. */
#undef HAVE_EXECINFO_H
/* Define to 1 if you have the `expq' function. */
#undef HAVE_EXPQ
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `floorq' function. */
#undef HAVE_FLOORQ
/* Define to 1 if you have the `fmodq' function. */
#undef HAVE_FMODQ
/* Define to 1 if you have the `getcontext' function. */
#undef HAVE_GETCONTEXT
/* Define to 1 if you have the `getitimer' function. */
#undef HAVE_GETITIMER
/* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define if you have the libdl library or equivalent. */
#undef HAVE_LIBDL
/* Define if libdlloader will be built on this platform */
#undef HAVE_LIBDLLOADER
/* Define to 1 if you have the `ltdl' library (-lltdl). */
#undef HAVE_LIBLTDL
/* Define to 1 if you have the `log10q' function. */
#undef HAVE_LOG10Q
/* Define to 1 if you have the `logq' function. */
#undef HAVE_LOGQ
/* Define this if a modern libltdl is already installed */
#undef HAVE_LTDL
/* Define to 1 if you have the <mach-o/dyld.h> header file. */
#undef HAVE_MACH_O_DYLD_H
/* Define to 1 if you have the `makecontext' function. */
#undef HAVE_MAKECONTEXT
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `opendir' function. */
#undef HAVE_OPENDIR
/* Define to 1 if you have the `powq' function. */
#undef HAVE_POWQ
/* Define if libtool can extract symbol lists from object files. */
#undef HAVE_PRELOADED_SYMBOLS
/* Define to 1 if you have the `quadmath_snprintf' function. */
#undef HAVE_QUADMATH_SNPRINTF
/* Define to 1 if you have the `readdir' function. */
#undef HAVE_READDIR
/* Define to 1 if you have the `roundq' function. */
#undef HAVE_ROUNDQ
/* Define to 1 if you have the `setcontext' function. */
#undef HAVE_SETCONTEXT
/* Define to 1 if you have the `setitimer' function. */
#undef HAVE_SETITIMER
/* Define to 1 if you have the `settimeofday' function. */
#undef HAVE_SETTIMEOFDAY
/* Define if you have the shl_load function. */
#undef HAVE_SHL_LOAD
/* Define to 1 if you have the <signal.h> header file. */
#undef HAVE_SIGNAL_H
/* Define to 1 if you have the `sinhq' function. */
#undef HAVE_SINHQ
/* Define to 1 if you have the `sinq' function. */
#undef HAVE_SINQ
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Define to 1 if you have the <spawn.h> header file. */
#undef HAVE_SPAWN_H
/* Define to 1 if you have the `sqrtq' function. */
#undef HAVE_SQRTQ
/* Define to 1 if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */
#undef HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the `strtoflt128' function. */
#undef HAVE_STRTOFLT128
/* Define to 1 if you have the `swapcontext' function. */
#undef HAVE_SWAPCONTEXT
/* Define to 1 if you have the <sys/dl.h> header file. */
#undef HAVE_SYS_DL_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the `tanhq' function. */
#undef HAVE_TANHQ
/* Define to 1 if you have the `tanq' function. */
#undef HAVE_TANQ
/* Define to 1 if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define to 1 if you have the <ucontext.h> header file. */
#undef HAVE_UCONTEXT_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the <utime.h> header file. */
#undef HAVE_UTIME_H
/* va_copy is available */
#undef HAVE_VA_COPY
/* Define to 1 if you have the <wchar.h> header file. */
#undef HAVE_WCHAR_H
/* Define to 1 if you have the <wctype.h> header file. */
#undef HAVE_WCTYPE_H
/* This value is set to 1 to indicate that the system argz facility works */
#undef HAVE_WORKING_ARGZ
/* Define to 1 if you have the `_vsnprintf' function. */
#undef HAVE__VSNPRINTF
/* Define to 1 if you have the `_vsnwprintf' function. */
#undef HAVE__VSNWPRINTF
/* __builtin_memcmp */
#undef HAVE___BUILTIN_MEMCMP
/* __builtin_memcpy */
#undef HAVE___BUILTIN_MEMCPY
/* __builtin_memmove */
#undef HAVE___BUILTIN_MEMMOVE
/* __builtin_memset */
#undef HAVE___BUILTIN_MEMSET
/* __va_copy is available */
#undef HAVE___VA_COPY
/* Define if the OS needs help to load dependent libraries for dlopen(). */
#undef LTDL_DLOPEN_DEPLIBS
/* Define to the system default library search path. */
#undef LT_DLSEARCH_PATH
/* The archive extension */
#undef LT_LIBEXT
/* The archive prefix */
#undef LT_LIBPREFIX
/* Define to the extension used for runtime loadable modules, say, ".so". */
#undef LT_MODULE_EXT
/* Define to the name of the environment variable that determines the run-time
module search path. */
#undef LT_MODULE_PATH_VAR
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Define to the shared library suffix, say, ".dylib". */
#undef LT_SHARED_EXT
/* link modules statically into the main library */
#undef MOO_ENABLE_STATIC_MODULE
/* Big Endian */
#undef MOO_ENDIAN_BIG
/* Little Endian */
#undef MOO_ENDIAN_LITTLE
/* Unknown Endian */
#undef MOO_ENDIAN_UNKNOWN
/* MB_LEN_MAX */
#undef MOO_MBLEN_MAX
/* Author */
#undef MOO_PACKAGE_AUTHOR
/* package name */
#undef MOO_PACKAGE_NAME
/* Project URL */
#undef MOO_PACKAGE_URL
/* Package version */
#undef MOO_PACKAGE_VERSION
/* Major version number */
#undef MOO_PACKAGE_VERSION_MAJOR
/* Minor version number */
#undef MOO_PACKAGE_VERSION_MINOR
/* Patch level */
#undef MOO_PACKAGE_VERSION_PATCH
/* sizeof(char) */
#undef MOO_SIZEOF_CHAR
/* sizeof(double) */
#undef MOO_SIZEOF_DOUBLE
/* sizeof(float) */
#undef MOO_SIZEOF_FLOAT
/* sizeof(int) */
#undef MOO_SIZEOF_INT
/* sizeof(long) */
#undef MOO_SIZEOF_LONG
/* sizeof(long double) */
#undef MOO_SIZEOF_LONG_DOUBLE
/* sizeof(long long) */
#undef MOO_SIZEOF_LONG_LONG
/* sizeof(mbstate_t) */
#undef MOO_SIZEOF_MBSTATE_T
/* sizeof(off64_t) */
#undef MOO_SIZEOF_OFF64_T
/* sizeof(off_t) */
#undef MOO_SIZEOF_OFF_T
/* sizeof(short) */
#undef MOO_SIZEOF_SHORT
/* sizeof(void*) */
#undef MOO_SIZEOF_VOID_P
/* sizeof(wchar_t) */
#undef MOO_SIZEOF_WCHAR_T
/* sizeof(__float128) */
#undef MOO_SIZEOF___FLOAT128
/* sizeof(__int128) */
#undef MOO_SIZEOF___INT128
/* sizeof(__int128_t) */
#undef MOO_SIZEOF___INT128_T
/* sizeof(__int16) */
#undef MOO_SIZEOF___INT16
/* sizeof(__int32) */
#undef MOO_SIZEOF___INT32
/* sizeof(__int64) */
#undef MOO_SIZEOF___INT64
/* sizeof(__int8) */
#undef MOO_SIZEOF___INT8
/* sizeof(__uint128_t) */
#undef MOO_SIZEOF___UINT128_T
/* Define if dlsym() requires a leading underscore in symbol names. */
#undef NEED_USCORE
/* The size of `MB_LEN_MAX', as computed by valueof. */
#undef NUMVALOF_MB_LEN_MAX
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* The size of `char', as computed by sizeof. */
#undef SIZEOF_CHAR
/* The size of `double', as computed by sizeof. */
#undef SIZEOF_DOUBLE
/* The size of `float', as computed by sizeof. */
#undef SIZEOF_FLOAT
/* The size of `int', as computed by sizeof. */
#undef SIZEOF_INT
/* The size of `long', as computed by sizeof. */
#undef SIZEOF_LONG
/* The size of `long double', as computed by sizeof. */
#undef SIZEOF_LONG_DOUBLE
/* The size of `long long', as computed by sizeof. */
#undef SIZEOF_LONG_LONG
/* The size of `mbstate_t', as computed by sizeof. */
#undef SIZEOF_MBSTATE_T
/* The size of `off64_t', as computed by sizeof. */
#undef SIZEOF_OFF64_T
/* The size of `off_t', as computed by sizeof. */
#undef SIZEOF_OFF_T
/* The size of `short', as computed by sizeof. */
#undef SIZEOF_SHORT
/* The size of `void *', as computed by sizeof. */
#undef SIZEOF_VOID_P
/* The size of `wchar_t', as computed by sizeof. */
#undef SIZEOF_WCHAR_T
/* The size of `__float128', as computed by sizeof. */
#undef SIZEOF___FLOAT128
/* The size of `__int128', as computed by sizeof. */
#undef SIZEOF___INT128
/* The size of `__int128_t', as computed by sizeof. */
#undef SIZEOF___INT128_T
/* The size of `__int16', as computed by sizeof. */
#undef SIZEOF___INT16
/* The size of `__int16_t', as computed by sizeof. */
#undef SIZEOF___INT16_T
/* The size of `__int32', as computed by sizeof. */
#undef SIZEOF___INT32
/* The size of `__int32_t', as computed by sizeof. */
#undef SIZEOF___INT32_T
/* The size of `__int64', as computed by sizeof. */
#undef SIZEOF___INT64
/* The size of `__int64_t', as computed by sizeof. */
#undef SIZEOF___INT64_T
/* The size of `__int8', as computed by sizeof. */
#undef SIZEOF___INT8
/* The size of `__int8_t', as computed by sizeof. */
#undef SIZEOF___INT8_T
/* The size of `__uint128_t', as computed by sizeof. */
#undef SIZEOF___UINT128_T
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif
/* Define so that glibc/gnulib argp.h does not typedef error_t. */
#undef __error_t_defined
/* Define to a type to use for `error_t' if it is not otherwise available. */
#undef error_t

723
moo/lib/moo-cmn.h Normal file
View File

@ -0,0 +1,723 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MOO_CMN_H_
#define _MOO_CMN_H_
/* WARNING: NEVER CHANGE/DELETE THE FOLLOWING MOO_HAVE_CFG_H DEFINITION.
* IT IS USED FOR DEPLOYMENT BY MAKEFILE.AM */
/*#define MOO_HAVE_CFG_H*/
#if defined(MOO_HAVE_CFG_H)
# include "moo-cfg.h"
#elif defined(_WIN32)
# include "moo-msw.h"
#elif defined(__OS2__)
# include "moo-os2.h"
#elif defined(__MSDOS__)
# include "moo-dos.h"
#elif defined(macintosh)
# include "moo-mac.h" /* class mac os */
#else
# error UNSUPPORTED SYSTEM
#endif
#if defined(EMSCRIPTEN)
# if defined(MOO_SIZEOF___INT128)
# undef MOO_SIZEOF___INT128
# define MOO_SIZEOF___INT128 0
# endif
# if defined(MOO_SIZEOF_LONG) && defined(MOO_SIZEOF_INT) && (MOO_SIZEOF_LONG > MOO_SIZEOF_INT)
/* autoconf doesn't seem to match actual emscripten */
# undef MOO_SIZEOF_LONG
# define MOO_SIZEOF_LONG MOO_SIZEOF_INT
# endif
#endif
/* =========================================================================
* PRIMITIVE TYPE DEFINTIONS
* ========================================================================= */
/* moo_int8_t */
#if defined(MOO_SIZEOF_CHAR) && (MOO_SIZEOF_CHAR == 1)
# define MOO_HAVE_UINT8_T
# define MOO_HAVE_INT8_T
typedef unsigned char moo_uint8_t;
typedef signed char moo_int8_t;
#elif defined(MOO_SIZEOF___INT8) && (MOO_SIZEOF___INT8 == 1)
# define MOO_HAVE_UINT8_T
# define MOO_HAVE_INT8_T
typedef unsigned __int8 moo_uint8_t;
typedef signed __int8 moo_int8_t;
#elif defined(MOO_SIZEOF___INT8_T) && (MOO_SIZEOF___INT8_T == 1)
# define MOO_HAVE_UINT8_T
# define MOO_HAVE_INT8_T
typedef unsigned __int8_t moo_uint8_t;
typedef signed __int8_t moo_int8_t;
#else
# define MOO_HAVE_UINT8_T
# define MOO_HAVE_INT8_T
typedef unsigned char moo_uint8_t;
typedef signed char moo_int8_t;
#endif
/* moo_int16_t */
#if defined(MOO_SIZEOF_SHORT) && (MOO_SIZEOF_SHORT == 2)
# define MOO_HAVE_UINT16_T
# define MOO_HAVE_INT16_T
typedef unsigned short int moo_uint16_t;
typedef signed short int moo_int16_t;
#elif defined(MOO_SIZEOF___INT16) && (MOO_SIZEOF___INT16 == 2)
# define MOO_HAVE_UINT16_T
# define MOO_HAVE_INT16_T
typedef unsigned __int16 moo_uint16_t;
typedef signed __int16 moo_int16_t;
#elif defined(MOO_SIZEOF___INT16_T) && (MOO_SIZEOF___INT16_T == 2)
# define MOO_HAVE_UINT16_T
# define MOO_HAVE_INT16_T
typedef unsigned __int16_t moo_uint16_t;
typedef signed __int16_t moo_int16_t;
#else
# define MOO_HAVE_UINT16_T
# define MOO_HAVE_INT16_T
typedef unsigned short int moo_uint16_t;
typedef signed short int moo_int16_t;
#endif
/* moo_int32_t */
#if defined(MOO_SIZEOF_INT) && (MOO_SIZEOF_INT == 4)
# define MOO_HAVE_UINT32_T
# define MOO_HAVE_INT32_T
typedef unsigned int moo_uint32_t;
typedef signed int moo_int32_t;
#elif defined(MOO_SIZEOF_LONG) && (MOO_SIZEOF_LONG == 4)
# define MOO_HAVE_UINT32_T
# define MOO_HAVE_INT32_T
typedef unsigned long moo_uint32_t;
typedef signed long moo_int32_t;
#elif defined(MOO_SIZEOF___INT32) && (MOO_SIZEOF___INT32 == 4)
# define MOO_HAVE_UINT32_T
# define MOO_HAVE_INT32_T
typedef unsigned __int32 moo_uint32_t;
typedef signed __int32 moo_int32_t;
#elif defined(MOO_SIZEOF___INT32_T) && (MOO_SIZEOF___INT32_T == 4)
# define MOO_HAVE_UINT32_T
# define MOO_HAVE_INT32_T
typedef unsigned __int32_t moo_uint32_t;
typedef signed __int32_t moo_int32_t;
#elif defined(__MSDOS__)
# define MOO_HAVE_UINT32_T
# define MOO_HAVE_INT32_T
typedef unsigned long int moo_uint32_t;
typedef signed long int moo_int32_t;
#else
# define MOO_HAVE_UINT32_T
# define MOO_HAVE_INT32_T
typedef unsigned int moo_uint32_t;
typedef signed int moo_int32_t;
#endif
/* moo_int64_t */
#if defined(MOO_SIZEOF_INT) && (MOO_SIZEOF_INT == 8)
# define MOO_HAVE_UINT64_T
# define MOO_HAVE_INT64_T
typedef unsigned int moo_uint64_t;
typedef signed int moo_int64_t;
#elif defined(MOO_SIZEOF_LONG) && (MOO_SIZEOF_LONG == 8)
# define MOO_HAVE_UINT64_T
# define MOO_HAVE_INT64_T
typedef unsigned long moo_uint64_t;
typedef signed long moo_int64_t;
#elif defined(MOO_SIZEOF_LONG_LONG) && (MOO_SIZEOF_LONG_LONG == 8)
# define MOO_HAVE_UINT64_T
# define MOO_HAVE_INT64_T
typedef unsigned long long moo_uint64_t;
typedef signed long long moo_int64_t;
#elif defined(MOO_SIZEOF___INT64) && (MOO_SIZEOF___INT64 == 8)
# define MOO_HAVE_UINT64_T
# define MOO_HAVE_INT64_T
typedef unsigned __int64 moo_uint64_t;
typedef signed __int64 moo_int64_t;
#elif defined(MOO_SIZEOF___INT64_T) && (MOO_SIZEOF___INT64_T == 8)
# define MOO_HAVE_UINT64_T
# define MOO_HAVE_INT64_T
typedef unsigned __int64_t moo_uint64_t;
typedef signed __int64_t moo_int64_t;
#else
/* no 64-bit integer */
#endif
/* moo_int128_t */
#if defined(MOO_SIZEOF_INT) && (MOO_SIZEOF_INT == 16)
# define MOO_HAVE_UINT128_T
# define MOO_HAVE_INT128_T
typedef unsigned int moo_uint128_t;
typedef signed int moo_int128_t;
#elif defined(MOO_SIZEOF_LONG) && (MOO_SIZEOF_LONG == 16)
# define MOO_HAVE_UINT128_T
# define MOO_HAVE_INT128_T
typedef unsigned long moo_uint128_t;
typedef signed long moo_int128_t;
#elif defined(MOO_SIZEOF_LONG_LONG) && (MOO_SIZEOF_LONG_LONG == 16)
# define MOO_HAVE_UINT128_T
# define MOO_HAVE_INT128_T
typedef unsigned long long moo_uint128_t;
typedef signed long long moo_int128_t;
#elif defined(MOO_SIZEOF___INT128) && (MOO_SIZEOF___INT128 == 16)
# define MOO_HAVE_UINT128_T
# define MOO_HAVE_INT128_T
typedef unsigned __int128 moo_uint128_t;
typedef signed __int128 moo_int128_t;
#elif defined(MOO_SIZEOF___INT128_T) && (MOO_SIZEOF___INT128_T == 16)
# define MOO_HAVE_UINT128_T
# define MOO_HAVE_INT128_T
#if defined(MOO_SIZEOF___UINT128_T) && (MOO_SIZEOF___UINT128_T == MOO_SIZEOF___INT128_T)
typedef __uint128_t moo_uint128_t;
typedef __int128_t moo_int128_t;
#elif defined(__clang__)
typedef __uint128_t moo_uint128_t;
typedef __int128_t moo_int128_t;
#else
typedef unsigned __int128_t moo_uint128_t;
typedef signed __int128_t moo_int128_t;
#endif
#else
/* no 128-bit integer */
#endif
#if defined(MOO_HAVE_UINT8_T) && (MOO_SIZEOF_VOID_P == 1)
# error UNSUPPORTED POINTER SIZE
#elif defined(MOO_HAVE_UINT16_T) && (MOO_SIZEOF_VOID_P == 2)
typedef moo_uint16_t moo_uintptr_t;
typedef moo_int16_t moo_intptr_t;
typedef moo_uint8_t moo_ushortptr_t;
typedef moo_int8_t moo_shortptr_t;
#elif defined(MOO_HAVE_UINT32_T) && (MOO_SIZEOF_VOID_P == 4)
typedef moo_uint32_t moo_uintptr_t;
typedef moo_int32_t moo_intptr_t;
typedef moo_uint16_t moo_ushortptr_t;
typedef moo_int16_t moo_shortptr_t;
#elif defined(MOO_HAVE_UINT64_T) && (MOO_SIZEOF_VOID_P == 8)
typedef moo_uint64_t moo_uintptr_t;
typedef moo_int64_t moo_intptr_t;
typedef moo_uint32_t moo_ushortptr_t;
typedef moo_int32_t moo_shortptr_t;
#elif defined(MOO_HAVE_UINT128_T) && (MOO_SIZEOF_VOID_P == 16)
typedef moo_uint128_t moo_uintptr_t;
typedef moo_int128_t moo_intptr_t;
typedef moo_uint64_t moo_ushortptr_t;
typedef moo_int64_t moo_shortptr_t;
#else
# error UNKNOWN POINTER SIZE
#endif
#define MOO_SIZEOF_INTPTR_T MOO_SIZEOF_VOID_P
#define MOO_SIZEOF_UINTPTR_T MOO_SIZEOF_VOID_P
#define MOO_SIZEOF_SHORTPTR_T (MOO_SIZEOF_VOID_P / 2)
#define MOO_SIZEOF_USHORTPTR_T (MOO_SIZEOF_VOID_P / 2)
#if defined(MOO_HAVE_INT128_T)
# define MOO_SIZEOF_INTMAX_T 16
# define MOO_SIZEOF_UINTMAX_T 16
typedef moo_int128_t moo_intmax_t;
typedef moo_uint128_t moo_uintmax_t;
#elif defined(MOO_HAVE_INT64_T)
# define MOO_SIZEOF_INTMAX_T 8
# define MOO_SIZEOF_UINTMAX_T 8
typedef moo_int64_t moo_intmax_t;
typedef moo_uint64_t moo_uintmax_t;
#elif defined(MOO_HAVE_INT32_T)
# define MOO_SIZEOF_INTMAX_T 4
# define MOO_SIZEOF_UINTMAX_T 4
typedef moo_int32_t moo_intmax_t;
typedef moo_uint32_t moo_uintmax_t;
#elif defined(MOO_HAVE_INT16_T)
# define MOO_SIZEOF_INTMAX_T 2
# define MOO_SIZEOF_UINTMAX_T 2
typedef moo_int16_t moo_intmax_t;
typedef moo_uint16_t moo_uintmax_t;
#elif defined(MOO_HAVE_INT8_T)
# define MOO_SIZEOF_INTMAX_T 1
# define MOO_SIZEOF_UINTMAX_T 1
typedef moo_int8_t moo_intmax_t;
typedef moo_uint8_t moo_uintmax_t;
#else
# error UNKNOWN INTMAX SIZE
#endif
/* =========================================================================
* BASIC MOO TYPES
* =========================================================================*/
typedef char moo_bch_t;
typedef int moo_bci_t;
typedef moo_uint16_t moo_uch_t; /* TODO ... wchar_t??? */
typedef moo_int32_t moo_uci_t;
typedef moo_uint8_t moo_oob_t;
/* NOTE: sizeof(moo_oop_t) must be equal to sizeof(moo_oow_t) */
typedef moo_uintptr_t moo_oow_t;
typedef moo_intptr_t moo_ooi_t;
#define MOO_SIZEOF_OOW_T MOO_SIZEOF_UINTPTR_T
#define MOO_SIZEOF_OOI_T MOO_SIZEOF_INTPTR_T
typedef moo_ushortptr_t moo_oohw_t; /* half word - half word */
typedef moo_shortptr_t moo_oohi_t; /* signed half word */
#define MOO_SIZEOF_OOHW_T MOO_SIZEOF_USHORTPTR_T
#define MOO_SIZEOF_OOHI_T MOO_SIZEOF_SHORTPTR_T
struct moo_ucs_t
{
moo_uch_t* ptr;
moo_oow_t len;
};
typedef struct moo_ucs_t moo_ucs_t;
struct moo_bcs_t
{
moo_bch_t* ptr;
moo_oow_t len;
};
typedef struct moo_bcs_t moo_bcs_t;
typedef moo_uch_t moo_ooch_t;
typedef moo_uci_t moo_ooci_t;
typedef moo_ucs_t moo_oocs_t;
#define MOO_OOCH_IS_UCH
/* =========================================================================
* TIME-RELATED TYPES
* =========================================================================*/
#define MOO_MSECS_PER_SEC (1000)
#define MOO_MSECS_PER_MIN (MOO_MSECS_PER_SEC * MOO_SECS_PER_MIN)
#define MOO_MSECS_PER_HOUR (MOO_MSECS_PER_SEC * MOO_SECS_PER_HOUR)
#define MOO_MSECS_PER_DAY (MOO_MSECS_PER_SEC * MOO_SECS_PER_DAY)
#define MOO_USECS_PER_MSEC (1000)
#define MOO_NSECS_PER_USEC (1000)
#define MOO_NSECS_PER_MSEC (MOO_NSECS_PER_USEC * MOO_USECS_PER_MSEC)
#define MOO_USECS_PER_SEC (MOO_USECS_PER_MSEC * MOO_MSECS_PER_SEC)
#define MOO_NSECS_PER_SEC (MOO_NSECS_PER_USEC * MOO_USECS_PER_MSEC * MOO_MSECS_PER_SEC)
#define MOO_SECNSEC_TO_MSEC(sec,nsec) \
(((moo_intptr_t)(sec) * MOO_MSECS_PER_SEC) + ((moo_intptr_t)(nsec) / MOO_NSECS_PER_MSEC))
#define MOO_SECNSEC_TO_USEC(sec,nsec) \
(((moo_intptr_t)(sec) * MOO_USECS_PER_SEC) + ((moo_intptr_t)(nsec) / MOO_NSECS_PER_USEC))
#define MOO_SECNSEC_TO_NSEC(sec,nsec) \
(((moo_intptr_t)(sec) * MOO_NSECS_PER_SEC) + (moo_intptr_t)(nsec))
#define MOO_SEC_TO_MSEC(sec) ((sec) * MOO_MSECS_PER_SEC)
#define MOO_MSEC_TO_SEC(sec) ((sec) / MOO_MSECS_PER_SEC)
#define MOO_USEC_TO_NSEC(usec) ((usec) * MOO_NSECS_PER_USEC)
#define MOO_NSEC_TO_USEC(nsec) ((nsec) / MOO_NSECS_PER_USEC)
#define MOO_MSEC_TO_NSEC(msec) ((msec) * MOO_NSECS_PER_MSEC)
#define MOO_NSEC_TO_MSEC(nsec) ((nsec) / MOO_NSECS_PER_MSEC)
#define MOO_SEC_TO_NSEC(sec) ((sec) * MOO_NSECS_PER_SEC)
#define MOO_NSEC_TO_SEC(nsec) ((nsec) / MOO_NSECS_PER_SEC)
#define MOO_SEC_TO_USEC(sec) ((sec) * MOO_USECS_PER_SEC)
#define MOO_USEC_TO_SEC(usec) ((usec) / MOO_USECS_PER_SEC)
typedef struct moo_ntime_t moo_ntime_t;
struct moo_ntime_t
{
moo_intptr_t sec;
moo_int32_t nsec; /* nanoseconds */
};
#define MOO_INITNTIME(c,s,ns) (((c)->sec = (s)), ((c)->nsec = (ns)))
#define MOO_CLEARNTIME(c) MOO_INITNTIME(c, 0, 0)
#define MOO_ADDNTIME(c,a,b) \
do { \
(c)->sec = (a)->sec + (b)->sec; \
(c)->nsec = (a)->nsec + (b)->nsec; \
while ((c)->nsec >= MOO_NSECS_PER_SEC) { (c)->sec++; (c)->nsec -= MOO_NSECS_PER_SEC; } \
} while(0)
#define MOO_ADDNTIMESNS(c,a,s,ns) \
do { \
(c)->sec = (a)->sec + (s); \
(c)->nsec = (a)->nsec + (ns); \
while ((c)->nsec >= MOO_NSECS_PER_SEC) { (c)->sec++; (c)->nsec -= MOO_NSECS_PER_SEC; } \
} while(0)
#define MOO_SUBNTIME(c,a,b) \
do { \
(c)->sec = (a)->sec - (b)->sec; \
(c)->nsec = (a)->nsec - (b)->nsec; \
while ((c)->nsec < 0) { (c)->sec--; (c)->nsec += MOO_NSECS_PER_SEC; } \
} while(0)
#define MOO_SUBNTIMESNS(c,a,s,ns) \
do { \
(c)->sec = (a)->sec - s; \
(c)->nsec = (a)->nsec - ns; \
while ((c)->nsec < 0) { (c)->sec--; (c)->nsec += MOO_NSECS_PER_SEC; } \
} while(0)
#define MOO_CMPNTIME(a,b) (((a)->sec == (b)->sec)? ((a)->nsec - (b)->nsec): ((a)->sec - (b)->sec))
/* =========================================================================
* PRIMITIVE MACROS
* ========================================================================= */
#define MOO_UCI_EOF ((moo_ooci_t)-1)
#define MOO_SIZEOF(x) (sizeof(x))
#define MOO_COUNTOF(x) (sizeof(x) / sizeof(x[0]))
/**
* The MOO_OFFSETOF() macro returns the offset of a field from the beginning
* of a structure.
*/
#define MOO_OFFSETOF(type,member) ((moo_uintptr_t)&((type*)0)->member)
/**
* The MOO_ALIGNOF() macro returns the alignment size of a structure.
* Note that this macro may not work reliably depending on the type given.
*/
#define MOO_ALIGNOF(type) MOO_OFFSETOF(struct { moo_uint8_t d1; type d2; }, d2)
/*(sizeof(struct { moo_uint8_t d1; type d2; }) - sizeof(type))*/
#if defined(__cplusplus)
# if (__cplusplus >= 201103L) /* C++11 */
# define MOO_NULL nullptr
# else
# define MOO_NULL (0)
# endif
#else
# define MOO_NULL ((void*)0)
#endif
/* make a bit mask that can mask off low n bits */
#define MOO_LBMASK(type,n) (~(~((type)0) << (n)))
#define MOO_LBMASK_SAFE(type,n) (((n) < MOO_SIZEOF(type) * 8)? MOO_LBMASK(type,n): ~(type)0)
/* make a bit mask that can mask off hig n bits */
#define MOO_HBMASK(type,n) (~(~((type)0) >> (n)))
#define MOO_HBMASK_SAFE(type,n) (((n) < MOO_SIZEOF(type) * 8)? MOO_HBMASK(type,n): ~(type)0)
/* get 'length' bits starting from the bit at the 'offset' */
#define MOO_GETBITS(type,value,offset,length) \
((((type)(value)) >> (offset)) & MOO_LBMASK(type,length))
#define MOO_CLEARBITS(type,value,offset,length) \
(((type)(value)) & ~(MOO_LBMASK(type,length) << (offset)))
#define MOO_SETBITS(type,value,offset,length,bits) \
(value = (MOO_CLEARBITS(type,value,offset,length) | (((bits) & MOO_LBMASK(type,length)) << (offset))))
#define MOO_FLIPBITS(type,value,offset,length) \
(((type)(value)) ^ (MOO_LBMASK(type,length) << (offset)))
#define MOO_ORBITS(type,value,offset,length,bits) \
(value = (((type)(value)) | (((bits) & MOO_LBMASK(type,length)) << (offset))))
/**
* The MOO_BITS_MAX() macros calculates the maximum value that the 'nbits'
* bits of an unsigned integer of the given 'type' can hold.
* \code
* printf ("%u", MOO_BITS_MAX(unsigned int, 5));
* \endcode
*/
/*#define MOO_BITS_MAX(type,nbits) ((((type)1) << (nbits)) - 1)*/
#define MOO_BITS_MAX(type,nbits) ((~(type)0) >> (MOO_SIZEOF(type) * 8 - (nbits)))
/* =========================================================================
* MMGR
* ========================================================================= */
typedef struct moo_mmgr_t moo_mmgr_t;
/**
* allocate a memory chunk of the size \a n.
* \return pointer to a memory chunk on success, #MOO_NULL on failure.
*/
typedef void* (*moo_mmgr_alloc_t) (moo_mmgr_t* mmgr, moo_oow_t n);
/**
* resize a memory chunk pointed to by \a ptr to the size \a n.
* \return pointer to a memory chunk on success, #MOO_NULL on failure.
*/
typedef void* (*moo_mmgr_realloc_t) (moo_mmgr_t* mmgr, void* ptr, moo_oow_t n);
/**
* free a memory chunk pointed to by \a ptr.
*/
typedef void (*moo_mmgr_free_t) (moo_mmgr_t* mmgr, void* ptr);
/**
* The moo_mmgr_t type defines the memory management interface.
* As the type is merely a structure, it is just used as a single container
* for memory management functions with a pointer to user-defined data.
* The user-defined data pointer \a ctx is passed to each memory management
* function whenever it is called. You can allocate, reallocate, and free
* a memory chunk.
*
* For example, a moo_xxx_open() function accepts a pointer of the moo_mmgr_t
* type and the xxx object uses it to manage dynamic data within the object.
*/
struct moo_mmgr_t
{
moo_mmgr_alloc_t alloc; /**< allocation function */
moo_mmgr_realloc_t realloc; /**< resizing function */
moo_mmgr_free_t free; /**< disposal function */
void* ctx; /**< user-defined data pointer */
};
/**
* The MOO_MMGR_ALLOC() macro allocates a memory block of the \a size bytes
* using the \a mmgr memory manager.
*/
#define MOO_MMGR_ALLOC(mmgr,size) ((mmgr)->alloc(mmgr,size))
/**
* The MOO_MMGR_REALLOC() macro resizes a memory block pointed to by \a ptr
* to the \a size bytes using the \a mmgr memory manager.
*/
#define MOO_MMGR_REALLOC(mmgr,ptr,size) ((mmgr)->realloc(mmgr,ptr,size))
/**
* The MOO_MMGR_FREE() macro deallocates the memory block pointed to by \a ptr.
*/
#define MOO_MMGR_FREE(mmgr,ptr) ((mmgr)->free(mmgr,ptr))
/* =========================================================================
* CMGR
* =========================================================================*/
typedef struct moo_cmgr_t moo_cmgr_t;
typedef moo_oow_t (*moo_cmgr_bctouc_t) (
const moo_bch_t* mb,
moo_oow_t size,
moo_uch_t* wc
);
typedef moo_oow_t (*moo_cmgr_uctobc_t) (
moo_uch_t wc,
moo_bch_t* mb,
moo_oow_t size
);
/**
* The moo_cmgr_t type defines the character-level interface to
* multibyte/wide-character conversion. This interface doesn't
* provide any facility to store conversion state in a context
* independent manner. This leads to the limitation that it can
* handle a stateless multibyte encoding only.
*/
struct moo_cmgr_t
{
moo_cmgr_bctouc_t bctouc;
moo_cmgr_uctobc_t uctobc;
};
/* =========================================================================
* FORWARD DECLARATION FOR MAIN MOO STRUCTURE
* =========================================================================*/
typedef struct moo_t moo_t;
/* =========================================================================
* MACROS THAT CHANGES THE BEHAVIORS OF THE C COMPILER/LINKER
* =========================================================================*/
#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
# define MOO_IMPORT
# define MOO_EXPORT
# define MOO_PRIVATE
#elif defined(_WIN32) || (defined(__WATCOMC__) && !defined(__WINDOWS_386__))
# define MOO_IMPORT __declspec(dllimport)
# define MOO_EXPORT __declspec(dllexport)
# define MOO_PRIVATE
#elif defined(__GNUC__) && (__GNUC__>=4)
# define MOO_IMPORT __attribute__((visibility("default")))
# define MOO_EXPORT __attribute__((visibility("default")))
# define MOO_PRIVATE __attribute__((visibility("hidden")))
/*# define MOO_PRIVATE __attribute__((visibility("internal")))*/
#else
# define MOO_IMPORT
# define MOO_EXPORT
# define MOO_PRIVATE
#endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__>=199901L)
/* C99 has inline */
# define MOO_INLINE inline
# define MOO_HAVE_INLINE
#elif defined(__GNUC__) && defined(__GNUC_GNU_INLINE__)
/* gcc disables inline when -std=c89 or -ansi is used.
* so use __inline__ supported by gcc regardless of the options */
# define MOO_INLINE /*extern*/ __inline__
# define MOO_HAVE_INLINE
#else
# define MOO_INLINE
# undef MOO_HAVE_INLINE
#endif
/**
* The MOO_TYPE_IS_SIGNED() macro determines if a type is signed.
* \code
* printf ("%d\n", (int)MOO_TYPE_IS_SIGNED(int));
* printf ("%d\n", (int)MOO_TYPE_IS_SIGNED(unsigned int));
* \endcode
*/
#define MOO_TYPE_IS_SIGNED(type) (((type)0) > ((type)-1))
/**
* The MOO_TYPE_IS_SIGNED() macro determines if a type is unsigned.
* \code
* printf ("%d\n", MOO_TYPE_IS_UNSIGNED(int));
* printf ("%d\n", MOO_TYPE_IS_UNSIGNED(unsigned int));
* \endcode
*/
#define MOO_TYPE_IS_UNSIGNED(type) (((type)0) < ((type)-1))
#define MOO_TYPE_SIGNED_MAX(type) \
((type)~((type)1 << ((type)MOO_SIZEOF(type) * 8 - 1)))
#define MOO_TYPE_UNSIGNED_MAX(type) ((type)(~(type)0))
#define MOO_TYPE_SIGNED_MIN(type) \
((type)((type)1 << ((type)MOO_SIZEOF(type) * 8 - 1)))
#define MOO_TYPE_UNSIGNED_MIN(type) ((type)0)
#define MOO_TYPE_MAX(type) \
((MOO_TYPE_IS_SIGNED(type)? MOO_TYPE_SIGNED_MAX(type): MOO_TYPE_UNSIGNED_MAX(type)))
#define MOO_TYPE_MIN(type) \
((MOO_TYPE_IS_SIGNED(type)? MOO_TYPE_SIGNED_MIN(type): MOO_TYPE_UNSIGNED_MIN(type)))
/* =========================================================================
* COMPILER FEATURE TEST MACROS
* =========================================================================*/
#if !defined(__has_builtin) && defined(_INTELC32_)
/* intel c code builder 1.0 ended up with an error without this override */
#define __has_builtin(x) 0
#endif
/*
#if !defined(__is_identifier)
#define __is_identifier(x) 0
#endif
#if !defined(__has_attribute)
#define __has_attribute(x) 0
#endif
*/
#if defined(__has_builtin)
#if __has_builtin(__builtin_ctz)
#define MOO_HAVE_BUILTIN_CTZ
#endif
#if __has_builtin(__builtin_uadd_overflow)
#define MOO_HAVE_BUILTIN_UADD_OVERFLOW
#endif
#if __has_builtin(__builtin_uaddl_overflow)
#define MOO_HAVE_BUILTIN_UADDL_OVERFLOW
#endif
#if __has_builtin(__builtin_uaddll_overflow)
#define MOO_HAVE_BUILTIN_UADDLL_OVERFLOW
#endif
#if __has_builtin(__builtin_umul_overflow)
#define MOO_HAVE_BUILTIN_UMUL_OVERFLOW
#endif
#if __has_builtin(__builtin_umull_overflow)
#define MOO_HAVE_BUILTIN_UMULL_OVERFLOW
#endif
#if __has_builtin(__builtin_umulll_overflow)
#define MOO_HAVE_BUILTIN_UMULLL_OVERFLOW
#endif
#if __has_builtin(__builtin_sadd_overflow)
#define MOO_HAVE_BUILTIN_SADD_OVERFLOW
#endif
#if __has_builtin(__builtin_saddl_overflow)
#define MOO_HAVE_BUILTIN_SADDL_OVERFLOW
#endif
#if __has_builtin(__builtin_saddll_overflow)
#define MOO_HAVE_BUILTIN_SADDLL_OVERFLOW
#endif
#if __has_builtin(__builtin_smul_overflow)
#define MOO_HAVE_BUILTIN_SMUL_OVERFLOW
#endif
#if __has_builtin(__builtin_smull_overflow)
#define MOO_HAVE_BUILTIN_SMULL_OVERFLOW
#endif
#if __has_builtin(__builtin_smulll_overflow)
#define MOO_HAVE_BUILTIN_SMULLL_OVERFLOW
#endif
#if __has_builtin(__builtin_expect)
#define MOO_HAVE_BUILTIN_EXPECT
#endif
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
#define MOO_HAVE_BUILTIN_CTZ
#define MOO_HAVE_BUILTIN_EXPECT
#endif
#if (__GNUC__ >= 5)
#define MOO_HAVE_BUILTIN_UADD_OVERFLOW
#define MOO_HAVE_BUILTIN_UADDL_OVERFLOW
#define MOO_HAVE_BUILTIN_UADDLL_OVERFLOW
#define MOO_HAVE_BUILTIN_UMUL_OVERFLOW
#define MOO_HAVE_BUILTIN_UMULL_OVERFLOW
#define MOO_HAVE_BUILTIN_UMULLL_OVERFLOW
#define MOO_HAVE_BUILTIN_SADD_OVERFLOW
#define MOO_HAVE_BUILTIN_SADDL_OVERFLOW
#define MOO_HAVE_BUILTIN_SADDLL_OVERFLOW
#define MOO_HAVE_BUILTIN_SMUL_OVERFLOW
#define MOO_HAVE_BUILTIN_SMULL_OVERFLOW
#define MOO_HAVE_BUILTIN_SMULLL_OVERFLOW
#endif
#endif
#if defined(MOO_HAVE_BUILTIN_EXPECT)
# define MOO_LIKELY(x) (__builtin_expect(!!x,1))
# define MOO_UNLIKELY(x) (__builtin_expect(!!x,0))
#else
# define MOO_LIKELY(x) (x)
# define MOO_UNLIKELY(x) (x)
#endif
#endif

167
moo/lib/moo-dos.h Normal file
View File

@ -0,0 +1,167 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* DOS for other platforms than x86?
* If so, the endian should be defined selectively
*/
#define MOO_ENDIAN_LITTLE
#if defined(__WATCOMC__) && defined(__386__)
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 4
# define MOO_SIZEOF_LONG 4
# if (__WATCOMC__ < 1200)
# define MOO_SIZEOF_LONG_LONG 0
# else
# define MOO_SIZEOF_LONG_LONG 8
# endif
# define MOO_SIZEOF_VOID_P 4
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 8
# define MOO_SIZEOF_WCHAR_T 2
# define MOO_SIZEOF___INT8 1
# define MOO_SIZEOF___INT16 2
# define MOO_SIZEOF___INT32 4
# define MOO_SIZEOF___INT64 8
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 4
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 8
#elif defined(__WATCOMC__) && !defined(__386__)
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 2
# define MOO_SIZEOF_LONG 4
# define MOO_SIZEOF_LONG_LONG 8
# define MOO_SIZEOF_VOID_P 4
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 8
# define MOO_SIZEOF_WCHAR_T 2
# define MOO_SIZEOF___INT8 1
# define MOO_SIZEOF___INT16 2
# define MOO_SIZEOF___INT32 4
# define MOO_SIZEOF___INT64 8
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 4
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 8
#elif defined(__TURBOC__)
/* TODO: be more version specific wchar_t may be available in newer BCC */
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 2
# define MOO_SIZEOF_LONG 4
# define MOO_SIZEOF_LONG_LONG 0
# define MOO_SIZEOF_VOID_P 4
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 10
# define MOO_SIZEOF_WCHAR_T 0
# define MOO_SIZEOF___INT8 0
# define MOO_SIZEOF___INT16 0
# define MOO_SIZEOF___INT32 0
# define MOO_SIZEOF___INT64 0
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 4
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 8
#elif defined(__ZTC__) && defined(DOS386)
/* Zortech in DOSX 386 mode (ztc -mx) */
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 4
# define MOO_SIZEOF_LONG 4
# define MOO_SIZEOF_LONG_LONG 0
# define MOO_SIZEOF_VOID_P 4
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 8
# define MOO_SIZEOF_WCHAR_T 1
# define MOO_SIZEOF___INT8 0
# define MOO_SIZEOF___INT16 0
# define MOO_SIZEOF___INT32 0
# define MOO_SIZEOF___INT64 0
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 4
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 8
#elif defined(_INTELC32_)
/* Intel C Code Builder 1.0 */
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 4
# define MOO_SIZEOF_LONG 4
# define MOO_SIZEOF_LONG_LONG 0
# define MOO_SIZEOF_VOID_P 4
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 8
# define MOO_SIZEOF_WCHAR_T 1
# define MOO_SIZEOF___INT8 0
# define MOO_SIZEOF___INT16 0
# define MOO_SIZEOF___INT32 0
# define MOO_SIZEOF___INT64 0
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 4
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 8
#else
# error Define the size of various data types.
#endif

58
moo/lib/moo-mac.h Normal file
View File

@ -0,0 +1,58 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* This file is for class Mac OS */
/* Mac OS on PPC and m68k uses the big endian mode */
#define MOO_ENDIAN_BIG
#if defined(__MWERKS__)
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 4
# define MOO_SIZEOF_LONG 4
# define MOO_SIZEOF_LONG_LONG 8
# define MOO_SIZEOF_VOID_P 4
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 8
# define MOO_SIZEOF_WCHAR_T 2
# define MOO_SIZEOF___INT8 1
# define MOO_SIZEOF___INT16 2
# define MOO_SIZEOF___INT32 4
# define MOO_SIZEOF___INT64 8
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 8
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 16
#else
# error Define the size of various data types.
#endif

174
moo/lib/moo-msw.h Normal file
View File

@ -0,0 +1,174 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Macro Meaning
_WIN64 A 64-bit platform.
_WIN32 A 32-bit platform. This value is also defined by the 64-bit
compiler for backward compatibility.
_WIN16 A 16-bit platform
The following macros are specific to the architecture.
Macro Meaning
_M_IA64 Intel Itanium Processor Family
_M_IX86 x86 platform
_M_X64 x64 platform
*/
/* windows for most of non-x86 platforms dropped.
* make it selective to support old non-x86 windows platforms. */
#define MOO_ENDIAN_LITTLE
#if defined(__WATCOMC__)
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 4
# define MOO_SIZEOF_LONG 4
# if (__WATCOMC__ < 1200)
# define MOO_SIZEOF_LONG_LONG 0
# else
# define MOO_SIZEOF_LONG_LONG 8
# endif
# if defined(_WIN64)
# define MOO_SIZEOF_VOID_P 8
# else
# define MOO_SIZEOF_VOID_P 4
# endif
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 8
# define MOO_SIZEOF_WCHAR_T 2
# define MOO_SIZEOF___INT8 1
# define MOO_SIZEOF___INT16 2
# define MOO_SIZEOF___INT32 4
# define MOO_SIZEOF___INT64 8
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 8
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 16
#elif defined(__GNUC__) || defined(__DMC__) || defined(__POCC__)
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 4
# define MOO_SIZEOF_LONG 4
# define MOO_SIZEOF_LONG_LONG 8
# if defined(_WIN64)
# define MOO_SIZEOF_VOID_P 8
# else
# define MOO_SIZEOF_VOID_P 4
# endif
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 16
# define MOO_SIZEOF_WCHAR_T 2
# define MOO_SIZEOF___INT8 0
# define MOO_SIZEOF___INT16 0
# define MOO_SIZEOF___INT32 0
# define MOO_SIZEOF___INT64 0
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 8
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 16
#elif defined(_MSC_VER)
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 4
# define MOO_SIZEOF_LONG 4
# if (_MSC_VER>=1310)
# define MOO_SIZEOF_LONG_LONG 8
# else
# define MOO_SIZEOF_LONG_LONG 0
# endif
# if defined(_WIN64)
# define MOO_SIZEOF_VOID_P 8
# else
# define MOO_SIZEOF_VOID_P 4
# endif
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 8
# define MOO_SIZEOF_WCHAR_T 2
# define MOO_SIZEOF___INT8 1
# define MOO_SIZEOF___INT16 2
# define MOO_SIZEOF___INT32 4
# define MOO_SIZEOF___INT64 8
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 8
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 8
#elif defined(__BORLANDC__)
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 4
# define MOO_SIZEOF_LONG 4
# define MOO_SIZEOF_LONG_LONG 0
# if defined(_WIN64)
# define MOO_SIZEOF_VOID_P 8
# else
# define MOO_SIZEOF_VOID_P 4
# endif
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 8
# define MOO_SIZEOF_WCHAR_T 2
# define MOO_SIZEOF___INT8 1
# define MOO_SIZEOF___INT16 2
# define MOO_SIZEOF___INT32 4
# define MOO_SIZEOF___INT64 8
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 8
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 8
#else
# error Define the size of various data types.
#endif

88
moo/lib/moo-os2.h Normal file
View File

@ -0,0 +1,88 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* OS/2 for other platforms than x86?
* If so, the endian should be defined selectively
*/
#define MOO_ENDIAN_LITTLE
#if defined(__WATCOMC__)
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 4
# define MOO_SIZEOF_LONG 4
# if (__WATCOMC__ < 1200)
# define MOO_SIZEOF_LONG_LONG 0
# else
# define MOO_SIZEOF_LONG_LONG 8
# endif
# define MOO_SIZEOF_VOID_P 4
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 8
# define MOO_SIZEOF_WCHAR_T 2
# define MOO_SIZEOF___INT8 1
# define MOO_SIZEOF___INT16 2
# define MOO_SIZEOF___INT32 4
# define MOO_SIZEOF___INT64 8
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 8
/* I don't know the exact mbstate size.
* but this should be large enough */
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
/* TODO: check the exact value */
# define MOO_MBLEN_MAX 8
#elif defined(__BORLANDC__)
# define MOO_SIZEOF_CHAR 1
# define MOO_SIZEOF_SHORT 2
# define MOO_SIZEOF_INT 4
# define MOO_SIZEOF_LONG 4
# define MOO_SIZEOF_LONG_LONG 0
# define MOO_SIZEOF_VOID_P 4
# define MOO_SIZEOF_FLOAT 4
# define MOO_SIZEOF_DOUBLE 8
# define MOO_SIZEOF_LONG_DOUBLE 8
# define MOO_SIZEOF_WCHAR_T 2
# define MOO_SIZEOF___INT8 0
# define MOO_SIZEOF___INT16 0
# define MOO_SIZEOF___INT32 0
# define MOO_SIZEOF___INT64 0
# define MOO_SIZEOF___INT128 0
# define MOO_SIZEOF_OFF64_T 0
# define MOO_SIZEOF_OFF_T 4
# define MOO_SIZEOF_MBSTATE_T MOO_SIZEOF_LONG
# define MOO_MBLEN_MAX 8
#else
# error Define the size of various data types.
#endif

1200
moo/lib/moo-prv.h Normal file

File diff suppressed because it is too large Load Diff

603
moo/lib/moo-rbt.h Normal file
View File

@ -0,0 +1,603 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MOO_RBT_H_
#define _MOO_RBT_H_
#include "moo-cmn.h"
/**@file
* This file provides a red-black tree encapsulated in the #moo_rbt_t type that
* implements a self-balancing binary search tree.Its interface is very close
* to #moo_htb_t.
*
* This sample code adds a series of keys and values and print them
* in descending key order.
* @code
* #include <moo/cmn/rbt.h>
* #include <moo/cmn/mem.h>
* #include <moo/cmn/sio.h>
*
* static moo_rbt_walk_t walk (moo_rbt_t* rbt, moo_rbt_pair_t* pair, void* ctx)
* {
* moo_printf (MOO_T("key = %d, value = %d\n"),
* *(int*)MOO_RBT_KPTR(pair), *(int*)MOO_RBT_VPTR(pair));
* return MOO_RBT_WALK_FORWARD;
* }
*
* int main ()
* {
* moo_rbt_t* s1;
* int i;
*
* s1 = moo_rbt_open (MOO_MMGR_GETDFL(), 0, 1, 1); // error handling skipped
* moo_rbt_setstyle (s1, moo_getrbtstyle(MOO_RBT_STYLE_INLINE_COPIERS));
*
* for (i = 0; i < 20; i++)
* {
* int x = i * 20;
* moo_rbt_insert (s1, &i, MOO_SIZEOF(i), &x, MOO_SIZEOF(x)); // eror handling skipped
* }
*
* moo_rbt_rwalk (s1, walk, MOO_NULL);
*
* moo_rbt_close (s1);
* return 0;
* }
* @endcode
*/
typedef struct moo_rbt_t moo_rbt_t;
typedef struct moo_rbt_pair_t moo_rbt_pair_t;
/**
* The moo_rbt_walk_t type defines values that the callback function can
* return to control moo_rbt_walk() and moo_rbt_rwalk().
*/
enum moo_rbt_walk_t
{
MOO_RBT_WALK_STOP = 0,
MOO_RBT_WALK_FORWARD = 1
};
typedef enum moo_rbt_walk_t moo_rbt_walk_t;
/**
* The moo_rbt_id_t type defines IDs to indicate a key or a value in various
* functions
*/
enum moo_rbt_id_t
{
MOO_RBT_KEY = 0, /**< indicate a key */
MOO_RBT_VAL = 1 /**< indicate a value */
};
typedef enum moo_rbt_id_t moo_rbt_id_t;
/**
* The moo_rbt_copier_t type defines a pair contruction callback.
*/
typedef void* (*moo_rbt_copier_t) (
moo_rbt_t* rbt /* red-black tree */,
void* dptr /* pointer to a key or a value */,
moo_oow_t dlen /* length of a key or a value */
);
/**
* The moo_rbt_freeer_t defines a key/value destruction callback.
*/
typedef void (*moo_rbt_freeer_t) (
moo_rbt_t* rbt, /**< red-black tree */
void* dptr, /**< pointer to a key or a value */
moo_oow_t dlen /**< length of a key or a value */
);
/**
* The moo_rbt_comper_t type defines a key comparator that is called when
* the rbt needs to compare keys. A red-black tree is created with a default
* comparator which performs bitwise comparison of two keys.
* The comparator should return 0 if the keys are the same, 1 if the first
* key is greater than the second key, -1 otherwise.
*/
typedef int (*moo_rbt_comper_t) (
const moo_rbt_t* rbt, /**< red-black tree */
const void* kptr1, /**< key pointer */
moo_oow_t klen1, /**< key length */
const void* kptr2, /**< key pointer */
moo_oow_t klen2 /**< key length */
);
/**
* The moo_rbt_keeper_t type defines a value keeper that is called when
* a value is retained in the context that it should be destroyed because
* it is identical to a new value. Two values are identical if their
* pointers and lengths are equal.
*/
typedef void (*moo_rbt_keeper_t) (
moo_rbt_t* rbt, /**< red-black tree */
void* vptr, /**< value pointer */
moo_oow_t vlen /**< value length */
);
/**
* The moo_rbt_walker_t defines a pair visitor.
*/
typedef moo_rbt_walk_t (*moo_rbt_walker_t) (
moo_rbt_t* rbt, /**< red-black tree */
moo_rbt_pair_t* pair, /**< pointer to a key/value pair */
void* ctx /**< pointer to user-defined data */
);
/**
* The moo_rbt_cbserter_t type defines a callback function for moo_rbt_cbsert().
* The moo_rbt_cbserter() function calls it to allocate a new pair for the
* key pointed to by @a kptr of the length @a klen and the callback context
* @a ctx. The second parameter @a pair is passed the pointer to the existing
* pair for the key or #MOO_NULL in case of no existing key. The callback
* must return a pointer to a new or a reallocated pair. When reallocating the
* existing pair, this callback must destroy the existing pair and return the
* newly reallocated pair. It must return #MOO_NULL for failure.
*/
typedef moo_rbt_pair_t* (*moo_rbt_cbserter_t) (
moo_rbt_t* rbt, /**< red-black tree */
moo_rbt_pair_t* pair, /**< pair pointer */
void* kptr, /**< key pointer */
moo_oow_t klen, /**< key length */
void* ctx /**< callback context */
);
/**
* The moo_rbt_pair_t type defines red-black tree pair. A pair is composed
* of a key and a value. It maintains pointers to the beginning of a key and
* a value plus their length. The length is scaled down with the scale factor
* specified in an owning tree. Use macros defined in the
*/
struct moo_rbt_pair_t
{
struct
{
void* ptr;
moo_oow_t len;
} key;
struct
{
void* ptr;
moo_oow_t len;
} val;
/* management information below */
enum
{
MOO_RBT_RED,
MOO_RBT_BLACK
} color;
moo_rbt_pair_t* parent;
moo_rbt_pair_t* child[2]; /* left and right */
};
typedef struct moo_rbt_style_t moo_rbt_style_t;
/**
* The moo_rbt_style_t type defines callback function sets for key/value
* pair manipulation.
*/
struct moo_rbt_style_t
{
moo_rbt_copier_t copier[2]; /**< key and value copier */
moo_rbt_freeer_t freeer[2]; /**< key and value freeer */
moo_rbt_comper_t comper; /**< key comparator */
moo_rbt_keeper_t keeper; /**< value keeper */
};
/**
* The moo_rbt_style_kind_t type defines the type of predefined
* callback set for pair manipulation.
*/
enum moo_rbt_style_kind_t
{
/** store the key and the value pointer */
MOO_RBT_STYLE_DEFAULT,
/** copy both key and value into the pair */
MOO_RBT_STYLE_INLINE_COPIERS,
/** copy the key into the pair but store the value pointer */
MOO_RBT_STYLE_INLINE_KEY_COPIER,
/** copy the value into the pair but store the key pointer */
MOO_RBT_STYLE_INLINE_VALUE_COPIER
};
typedef enum moo_rbt_style_kind_t moo_rbt_style_kind_t;
/**
* The moo_rbt_t type defines a red-black tree.
*/
struct moo_rbt_t
{
moo_t* moo;
const moo_rbt_style_t* style;
moo_oob_t scale[2]; /**< length scale */
moo_rbt_pair_t xnil; /**< internal nil node */
moo_oow_t size; /**< number of pairs */
moo_rbt_pair_t* root; /**< root pair */
};
/**
* The MOO_RBT_COPIER_SIMPLE macros defines a copier that remembers the
* pointer and length of data in a pair.
*/
#define MOO_RBT_COPIER_SIMPLE ((moo_rbt_copier_t)1)
/**
* The MOO_RBT_COPIER_INLINE macros defines a copier that copies data into
* a pair.
*/
#define MOO_RBT_COPIER_INLINE ((moo_rbt_copier_t)2)
#define MOO_RBT_COPIER_DEFAULT (MOO_RBT_COPIER_SIMPLE)
#define MOO_RBT_FREEER_DEFAULT (MOO_NULL)
#define MOO_RBT_COMPER_DEFAULT (moo_rbt_dflcomp)
#define MOO_RBT_KEEPER_DEFAULT (MOO_NULL)
/**
* The MOO_RBT_SIZE() macro returns the number of pairs in red-black tree.
*/
#define MOO_RBT_SIZE(m) ((const moo_oow_t)(m)->size)
#define MOO_RBT_KSCALE(m) ((const int)(m)->scale[MOO_RBT_KEY])
#define MOO_RBT_VSCALE(m) ((const int)(m)->scale[MOO_RBT_VAL])
#define MOO_RBT_KPTL(p) (&(p)->key)
#define MOO_RBT_VPTL(p) (&(p)->val)
#define MOO_RBT_KPTR(p) ((p)->key.ptr)
#define MOO_RBT_KLEN(p) ((p)->key.len)
#define MOO_RBT_VPTR(p) ((p)->val.ptr)
#define MOO_RBT_VLEN(p) ((p)->val.len)
#define MOO_RBT_NEXT(p) ((p)->next)
#if defined(__cplusplus)
extern "C" {
#endif
/**
* The moo_getrbtstyle() functions returns a predefined callback set for
* pair manipulation.
*/
MOO_EXPORT const moo_rbt_style_t* moo_getrbtstyle (
moo_rbt_style_kind_t kind
);
/**
* The moo_rbt_open() function creates a red-black tree.
* @return moo_rbt_t pointer on success, MOO_NULL on failure.
*/
MOO_EXPORT moo_rbt_t* moo_rbt_open (
moo_t* moo,
moo_oow_t xtnsize, /**< extension size in bytes */
int kscale, /**< key scale */
int vscale /**< value scale */
);
/**
* The moo_rbt_close() function destroys a red-black tree.
*/
MOO_EXPORT void moo_rbt_close (
moo_rbt_t* rbt /**< red-black tree */
);
/**
* The moo_rbt_init() function initializes a red-black tree
*/
MOO_EXPORT int moo_rbt_init (
moo_rbt_t* rbt, /**< red-black tree */
moo_t* moo,
int kscale, /**< key scale */
int vscale /**< value scale */
);
/**
* The moo_rbt_fini() funtion finalizes a red-black tree
*/
MOO_EXPORT void moo_rbt_fini (
moo_rbt_t* rbt /**< red-black tree */
);
MOO_EXPORT void* moo_rbt_getxtn (
moo_rbt_t* rbt
);
/**
* The moo_rbt_getstyle() function gets manipulation callback function set.
*/
MOO_EXPORT const moo_rbt_style_t* moo_rbt_getstyle (
const moo_rbt_t* rbt /**< red-black tree */
);
/**
* The moo_rbt_setstyle() function sets internal manipulation callback
* functions for data construction, destruction, comparison, etc.
* The callback structure pointed to by \a style must outlive the tree
* pointed to by \a htb as the tree doesn't copy the contents of the
* structure.
*/
MOO_EXPORT void moo_rbt_setstyle (
moo_rbt_t* rbt, /**< red-black tree */
const moo_rbt_style_t* style /**< callback function set */
);
/**
* The moo_rbt_getsize() function gets the number of pairs in red-black tree.
*/
MOO_EXPORT moo_oow_t moo_rbt_getsize (
const moo_rbt_t* rbt /**< red-black tree */
);
/**
* The moo_rbt_search() function searches red-black tree to find a pair with a
* matching key. It returns the pointer to the pair found. If it fails
* to find one, it returns MOO_NULL.
* @return pointer to the pair with a maching key,
* or MOO_NULL if no match is found.
*/
MOO_EXPORT moo_rbt_pair_t* moo_rbt_search (
const moo_rbt_t* rbt, /**< red-black tree */
const void* kptr, /**< key pointer */
moo_oow_t klen /**< the size of the key */
);
/**
* The moo_rbt_upsert() function searches red-black tree for the pair with a
* matching key. If one is found, it updates the pair. Otherwise, it inserts
* a new pair with the key and the value given. It returns the pointer to the
* pair updated or inserted.
* @return a pointer to the updated or inserted pair on success,
* MOO_NULL on failure.
*/
MOO_EXPORT moo_rbt_pair_t* moo_rbt_upsert (
moo_rbt_t* rbt, /**< red-black tree */
void* kptr, /**< key pointer */
moo_oow_t klen, /**< key length */
void* vptr, /**< value pointer */
moo_oow_t vlen /**< value length */
);
/**
* The moo_rbt_ensert() function inserts a new pair with the key and the value
* given. If there exists a pair with the key given, the function returns
* the pair containing the key.
* @return pointer to a pair on success, MOO_NULL on failure.
*/
MOO_EXPORT moo_rbt_pair_t* moo_rbt_ensert (
moo_rbt_t* rbt, /**< red-black tree */
void* kptr, /**< key pointer */
moo_oow_t klen, /**< key length */
void* vptr, /**< value pointer */
moo_oow_t vlen /**< value length */
);
/**
* The moo_rbt_insert() function inserts a new pair with the key and the value
* given. If there exists a pair with the key given, the function returns
* MOO_NULL without channging the value.
* @return pointer to the pair created on success, MOO_NULL on failure.
*/
MOO_EXPORT moo_rbt_pair_t* moo_rbt_insert (
moo_rbt_t* rbt, /**< red-black tree */
void* kptr, /**< key pointer */
moo_oow_t klen, /**< key length */
void* vptr, /**< value pointer */
moo_oow_t vlen /**< value length */
);
/**
* The moo_rbt_update() function updates the value of an existing pair
* with a matching key.
* @return pointer to the pair on success, MOO_NULL on no matching pair
*/
MOO_EXPORT moo_rbt_pair_t* moo_rbt_update (
moo_rbt_t* rbt, /**< red-black tree */
void* kptr, /**< key pointer */
moo_oow_t klen, /**< key length */
void* vptr, /**< value pointer */
moo_oow_t vlen /**< value length */
);
/**
* The moo_rbt_cbsert() function inserts a key/value pair by delegating pair
* allocation to a callback function. Depending on the callback function,
* it may behave like moo_rbt_insert(), moo_rbt_upsert(), moo_rbt_update(),
* moo_rbt_ensert(), or totally differently. The sample code below inserts
* a new pair if the key is not found and appends the new value to the
* existing value delimited by a comma if the key is found.
*
* @code
* moo_rbt_walk_t print_map_pair (moo_rbt_t* map, moo_rbt_pair_t* pair, void* ctx)
* {
* moo_printf (MOO_T("%.*s[%d] => %.*s[%d]\n"),
* (int)MOO_RBT_KLEN(pair), MOO_RBT_KPTR(pair), (int)MOO_RBT_KLEN(pair),
* (int)MOO_RBT_VLEN(pair), MOO_RBT_VPTR(pair), (int)MOO_RBT_VLEN(pair));
* return MOO_RBT_WALK_FORWARD;
* }
*
* moo_rbt_pair_t* cbserter (
* moo_rbt_t* rbt, moo_rbt_pair_t* pair,
* void* kptr, moo_oow_t klen, void* ctx)
* {
* moo_cstr_t* v = (moo_cstr_t*)ctx;
* if (pair == MOO_NULL)
* {
* // no existing key for the key
* return moo_rbt_allocpair (rbt, kptr, klen, v->ptr, v->len);
* }
* else
* {
* // a pair with the key exists.
* // in this sample, i will append the new value to the old value
* // separated by a comma
* moo_rbt_pair_t* new_pair;
* moo_char_t comma = MOO_T(',');
* moo_oob_t* vptr;
*
* // allocate a new pair, but without filling the actual value.
* // note vptr is given MOO_NULL for that purpose
* new_pair = moo_rbt_allocpair (
* rbt, kptr, klen, MOO_NULL, pair->vlen + 1 + v->len);
* if (new_pair == MOO_NULL) return MOO_NULL;
*
* // fill in the value space
* vptr = new_pair->vptr;
* moo_memcpy (vptr, pair->vptr, pair->vlen*MOO_SIZEOF(moo_char_t));
* vptr += pair->vlen*MOO_SIZEOF(moo_char_t);
* moo_memcpy (vptr, &comma, MOO_SIZEOF(moo_char_t));
* vptr += MOO_SIZEOF(moo_char_t);
* moo_memcpy (vptr, v->ptr, v->len*MOO_SIZEOF(moo_char_t));
*
* // this callback requires the old pair to be destroyed
* moo_rbt_freepair (rbt, pair);
*
* // return the new pair
* return new_pair;
* }
* }
*
* int main ()
* {
* moo_rbt_t* s1;
* int i;
* moo_char_t* keys[] = { MOO_T("one"), MOO_T("two"), MOO_T("three") };
* moo_char_t* vals[] = { MOO_T("1"), MOO_T("2"), MOO_T("3"), MOO_T("4"), MOO_T("5") };
*
* s1 = moo_rbt_open (
* MOO_MMGR_GETDFL(), 0,
* MOO_SIZEOF(moo_char_t), MOO_SIZEOF(moo_char_t)
* ); // note error check is skipped
* moo_rbt_setstyle (s1, &style1);
*
* for (i = 0; i < MOO_COUNTOF(vals); i++)
* {
* moo_cstr_t ctx;
* ctx.ptr = vals[i]; ctx.len = moo_strlen(vals[i]);
* moo_rbt_cbsert (s1,
* keys[i%MOO_COUNTOF(keys)], moo_strlen(keys[i%MOO_COUNTOF(keys)]),
* cbserter, &ctx
* ); // note error check is skipped
* }
* moo_rbt_walk (s1, print_map_pair, MOO_NULL);
*
* moo_rbt_close (s1);
* return 0;
* }
* @endcode
*/
MOO_EXPORT moo_rbt_pair_t* moo_rbt_cbsert (
moo_rbt_t* rbt, /**< red-black tree */
void* kptr, /**< key pointer */
moo_oow_t klen, /**< key length */
moo_rbt_cbserter_t cbserter, /**< callback function */
void* ctx /**< callback context */
);
/**
* The moo_rbt_delete() function deletes a pair with a matching key
* @return 0 on success, -1 on failure
*/
MOO_EXPORT int moo_rbt_delete (
moo_rbt_t* rbt, /**< red-black tree */
const void* kptr, /**< key pointer */
moo_oow_t klen /**< key size */
);
/**
* The moo_rbt_clear() function empties a red-black tree.
*/
MOO_EXPORT void moo_rbt_clear (
moo_rbt_t* rbt /**< red-black tree */
);
/**
* The moo_rbt_walk() function traverses a red-black tree in preorder
* from the leftmost child.
*/
MOO_EXPORT void moo_rbt_walk (
moo_rbt_t* rbt, /**< red-black tree */
moo_rbt_walker_t walker, /**< callback function for each pair */
void* ctx /**< pointer to user-specific data */
);
/**
* The moo_rbt_walk() function traverses a red-black tree in preorder
* from the rightmost child.
*/
MOO_EXPORT void moo_rbt_rwalk (
moo_rbt_t* rbt, /**< red-black tree */
moo_rbt_walker_t walker, /**< callback function for each pair */
void* ctx /**< pointer to user-specific data */
);
/**
* The moo_rbt_allocpair() function allocates a pair for a key and a value
* given. But it does not chain the pair allocated into the red-black tree @a rbt.
* Use this function at your own risk.
*
* Take note of he following special behavior when the copier is
* #MOO_RBT_COPIER_INLINE.
* - If @a kptr is #MOO_NULL, the key space of the size @a klen is reserved but
* not propagated with any data.
* - If @a vptr is #MOO_NULL, the value space of the size @a vlen is reserved
* but not propagated with any data.
*/
MOO_EXPORT moo_rbt_pair_t* moo_rbt_allocpair (
moo_rbt_t* rbt,
void* kptr,
moo_oow_t klen,
void* vptr,
moo_oow_t vlen
);
/**
* The moo_rbt_freepair() function destroys a pair. But it does not detach
* the pair destroyed from the red-black tree @a rbt. Use this function at your
* own risk.
*/
MOO_EXPORT void moo_rbt_freepair (
moo_rbt_t* rbt,
moo_rbt_pair_t* pair
);
/**
* The moo_rbt_dflcomp() function defines the default key comparator.
*/
MOO_EXPORT int moo_rbt_dflcomp (
const moo_rbt_t* rbt,
const void* kptr1,
moo_oow_t klen1,
const void* kptr2,
moo_oow_t klen2
);
#if defined(__cplusplus)
}
#endif
#endif

331
moo/lib/moo-utl.h Normal file
View File

@ -0,0 +1,331 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MOO_UTL_H_
#define _MOO_UTL_H_
#include "moo-cmn.h"
#if defined(__cplusplus)
extern "C" {
#endif
MOO_EXPORT moo_oow_t moo_hashbytes (
const moo_oob_t* ptr,
moo_oow_t len
);
#if defined(MOO_HAVE_INLINE)
static MOO_INLINE moo_oow_t moo_hashbchars (const moo_bch_t* ptr, moo_oow_t len)
{
return moo_hashbytes((const moo_oob_t*)ptr,len * MOO_SIZEOF(moo_bch_t));
}
static MOO_INLINE moo_oow_t moo_hashuchars (const moo_uch_t* ptr, moo_oow_t len)
{
return moo_hashbytes((const moo_oob_t*)ptr,len * MOO_SIZEOF(moo_uch_t));
}
static MOO_INLINE moo_oow_t moo_hashwords (const moo_oow_t* ptr, moo_oow_t len)
{
return moo_hashbytes((const moo_oob_t*)ptr, len * MOO_SIZEOF(moo_oow_t));
}
static MOO_INLINE moo_oow_t moo_hashhalfwords (const moo_oohw_t* ptr, moo_oow_t len)
{
return moo_hashbytes((const moo_oob_t*)ptr, len * MOO_SIZEOF(moo_oohw_t));
}
#else
# define moo_hashbchars(ptr,len) moo_hashbytes((const moo_oob_t*)ptr,len * MOO_SIZEOF(moo_bch_t))
# define moo_hashuchars(ptr,len) moo_hashbytes((const moo_oob_t*)ptr,len * MOO_SIZEOF(moo_uch_t))
# define moo_hashwords(ptr,len) moo_hashbytes((const moo_oob_t*)ptr, len * MOO_SIZEOF(moo_oow_t))
# define moo_hashhalfwords(ptr,len) moo_hashbytes((const moo_oob_t*)ptr, len * MOO_SIZEOF(moo_oohw_t))
#endif
#if defined(MOO_OOCH_IS_UCH)
# define moo_hashoochars(ptr,len) moo_hashuchars(ptr,len)
#else
# define moo_hashoochars(ptr,len) moo_hashbchars(ptr,len)
#endif
MOO_EXPORT moo_oow_t moo_hashwords (
const moo_oow_t* ptr,
moo_oow_t len
);
/**
* The moo_equaluchars() function determines equality of two strings
* of the same length \a len.
*/
MOO_EXPORT int moo_equaluchars (
const moo_uch_t* str1,
const moo_uch_t* str2,
moo_oow_t len
);
MOO_EXPORT int moo_equalbchars (
const moo_bch_t* str1,
const moo_bch_t* str2,
moo_oow_t len
);
MOO_EXPORT int moo_compucstr (
const moo_uch_t* str1,
const moo_uch_t* str2
);
MOO_EXPORT int moo_compbcstr (
const moo_bch_t* str1,
const moo_bch_t* str2
);
MOO_EXPORT int moo_compucbcstr (
const moo_uch_t* str1,
const moo_bch_t* str2
);
MOO_EXPORT int moo_compucharsbcstr (
const moo_uch_t* str1,
moo_oow_t len,
const moo_bch_t* str2
);
MOO_EXPORT int moo_compbcharsbcstr (
const moo_bch_t* str1,
moo_oow_t len,
const moo_bch_t* str2
);
MOO_EXPORT void moo_copyuchars (
moo_uch_t* dst,
const moo_uch_t* src,
moo_oow_t len
);
MOO_EXPORT void moo_copybchars (
moo_bch_t* dst,
const moo_bch_t* src,
moo_oow_t len
);
MOO_EXPORT void moo_copybtouchars (
moo_uch_t* dst,
const moo_bch_t* src,
moo_oow_t len
);
MOO_EXPORT moo_oow_t moo_copyucstr (
moo_uch_t* dst,
moo_oow_t len,
const moo_uch_t* src
);
MOO_EXPORT moo_oow_t moo_copybcstr (
moo_bch_t* dst,
moo_oow_t len,
const moo_bch_t* src
);
MOO_EXPORT moo_uch_t* moo_finduchar (
const moo_uch_t* ptr,
moo_oow_t len,
moo_uch_t c
);
MOO_EXPORT moo_bch_t* moo_findbchar (
const moo_bch_t* ptr,
moo_oow_t len,
moo_bch_t c
);
MOO_EXPORT moo_uch_t* moo_rfinduchar (
const moo_uch_t* ptr,
moo_oow_t len,
moo_uch_t c
);
MOO_EXPORT moo_bch_t* moo_rfindbchar (
const moo_bch_t* ptr,
moo_oow_t len,
moo_bch_t c
);
MOO_EXPORT moo_oow_t moo_countucstr (
const moo_uch_t* str
);
MOO_EXPORT moo_oow_t moo_countbcstr (
const moo_bch_t* str
);
#if defined(MOO_OOCH_IS_UCH)
# define moo_equaloochars(str1,str2,len) moo_equaluchars(str1,str2,len)
# define moo_compoocbcstr(str1,str2) moo_compucbcstr(str1,str2)
# define moo_compoocharsbcstr(str1,len1,str2) moo_compucharsbcstr(str1,len1,str2)
# define moo_compoocstr(str1,str2) moo_compucstr(str1,str2)
# define moo_copyoochars(dst,src,len) moo_copyuchars(dst,src,len)
# define moo_copybctooochars(dst,src,len) moo_copybtouchars(dst,src,len)
# define moo_copyoocstr(dst,len,src) moo_copyucstr(dst,len,src)
# define moo_findoochar(ptr,len,c) moo_finduchar(ptr,len,c)
# define moo_rfindoochar(ptr,len,c) moo_rfinduchar(ptr,len,c)
# define moo_countoocstr(str) moo_countucstr(str)
#else
# define moo_equaloochars(str1,str2,len) moo_equalbchars(str1,str2,len)
# define moo_compoocbcstr(str1,str2) moo_compbcstr(str1,str2)
# define moo_compoocharsbcstr(str1,len1,str2) moo_compbcharsbcstr(str1,len1,str2)
# define moo_compoocstr(str1,str2) moo_compbcstr(str1,str2)
# define moo_copyoochars(dst,src,len) moo_copybchars(dst,src,len)
# define moo_copybctooochars(dst,src,len) moo_copybchars(dst,src,len)
# define moo_copyoocstr(dst,len,src) moo_copybcstr(dst,len,src)
# define moo_findoochar(ptr,len,c) moo_findbchar(ptr,len,c)
# define moo_rfindoochar(ptr,len,c) moo_rfindbchar(ptr,len,c)
# define moo_countoocstr(str) moo_countbcstr(str)
#endif
MOO_EXPORT int moo_copyoocstrtosbuf (
moo_t* moo,
const moo_ooch_t* str,
int id
);
MOO_EXPORT int moo_concatoocstrtosbuf (
moo_t* moo,
const moo_ooch_t* str,
int id
);
MOO_EXPORT moo_cmgr_t* moo_getutf8cmgr (
void
);
/**
* The moo_convutoutf8chars() function converts a unicode character string \a ucs
* to a UTF8 string and writes it into the buffer pointed to by \a bcs, but
* not more than \a bcslen bytes including the terminating null.
*
* Upon return, \a bcslen is modified to the actual number of bytes written to
* \a bcs excluding the terminating null; \a ucslen is modified to the number of
* wide characters converted.
*
* You may pass #MOO_NULL for \a bcs to dry-run conversion or to get the
* required buffer size for conversion. -2 is never returned in this case.
*
* \return
* - 0 on full conversion,
* - -1 on no or partial conversion for an illegal character encountered,
* - -2 on no or partial conversion for a small buffer.
*
* \code
* const moo_uch_t ucs[] = { 'H', 'e', 'l', 'l', 'o' };
* moo_bch_t bcs[10];
* moo_oow_t ucslen = 5;
* moo_oow_t bcslen = MOO_COUNTOF(bcs);
* n = moo_convutoutf8chars (ucs, &ucslen, bcs, &bcslen);
* if (n <= -1)
* {
* // conversion error
* }
* \endcode
*/
MOO_EXPORT int moo_convutoutf8chars (
const moo_uch_t* ucs,
moo_oow_t* ucslen,
moo_bch_t* bcs,
moo_oow_t* bcslen
);
/**
* The moo_convutf8touchars() function converts a UTF8 string to a uncide string.
*
* It never returns -2 if \a ucs is #MOO_NULL.
*
* \code
* const moo_bch_t* bcs = "test string";
* moo_uch_t ucs[100];
* moo_oow_t ucslen = MOO_COUNTOF(buf), n;
* moo_oow_t bcslen = 11;
* int n;
* n = moo_convutf8touchars (bcs, &bcslen, ucs, &ucslen);
* if (n <= -1) { invalid/incomplenete sequence or buffer to small }
* \endcode
*
* The resulting \a ucslen can still be greater than 0 even if the return
* value is negative. The value indiates the number of characters converted
* before the error has occurred.
*
* \return 0 on success.
* -1 if \a bcs contains an illegal character.
* -2 if the wide-character string buffer is too small.
* -3 if \a bcs is not a complete sequence.
*/
MOO_EXPORT int moo_convutf8touchars (
const moo_bch_t* bcs,
moo_oow_t* bcslen,
moo_uch_t* ucs,
moo_oow_t* ucslen
);
MOO_EXPORT int moo_convutoutf8cstr (
const moo_uch_t* ucs,
moo_oow_t* ucslen,
moo_bch_t* bcs,
moo_oow_t* bcslen
);
MOO_EXPORT int moo_convutf8toucstr (
const moo_bch_t* bcs,
moo_oow_t* bcslen,
moo_uch_t* ucs,
moo_oow_t* ucslen
);
MOO_EXPORT moo_oow_t moo_uctoutf8 (
moo_uch_t uc,
moo_bch_t* utf8,
moo_oow_t size
);
MOO_EXPORT moo_oow_t moo_utf8touc (
const moo_bch_t* utf8,
moo_oow_t size,
moo_uch_t* uc
);
#if defined(__cplusplus)
}
#endif
#endif

740
moo/lib/moo.c Normal file
View File

@ -0,0 +1,740 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
moo_t* moo_open (moo_mmgr_t* mmgr, moo_oow_t xtnsize, moo_oow_t heapsize, const moo_vmprim_t* vmprim, moo_errnum_t* errnum)
{
moo_t* moo;
/* if this assertion fails, correct the type definition in moo.h */
MOO_ASSERT (moo, MOO_SIZEOF(moo_oow_t) == MOO_SIZEOF(moo_oop_t));
moo = MOO_MMGR_ALLOC (mmgr, MOO_SIZEOF(*moo) + xtnsize);
if (moo)
{
if (moo_init(moo, mmgr, heapsize, vmprim) <= -1)
{
if (errnum) *errnum = moo->errnum;
MOO_MMGR_FREE (mmgr, moo);
moo = MOO_NULL;
}
else MOO_MEMSET (moo + 1, 0, xtnsize);
}
else if (errnum) *errnum = MOO_ESYSMEM;
return moo;
}
void moo_close (moo_t* moo)
{
moo_fini (moo);
MOO_MMGR_FREE (moo->mmgr, moo);
}
static void fill_bigint_tables (moo_t* moo)
{
int radix, safe_ndigits;
moo_oow_t ub, w;
moo_oow_t multiplier;
for (radix = 2; radix <= 36; radix++)
{
w = 0;
ub = (moo_oow_t)MOO_TYPE_MAX(moo_liw_t) / radix - (radix - 1);
multiplier = 1;
safe_ndigits = 0;
while (w <= ub)
{
w = w * radix + (radix - 1);
multiplier *= radix;
safe_ndigits++;
}
/* safe_ndigits contains the number of digits that never
* cause overflow when computed normally with a native type. */
moo->bigint[radix].safe_ndigits = safe_ndigits;
moo->bigint[radix].multiplier = multiplier;
}
}
int moo_init (moo_t* moo, moo_mmgr_t* mmgr, moo_oow_t heapsz, const moo_vmprim_t* vmprim)
{
int modtab_inited = 0;
MOO_MEMSET (moo, 0, MOO_SIZEOF(*moo));
moo->mmgr = mmgr;
moo->cmgr = moo_getutf8cmgr ();
moo->vmprim = *vmprim;
moo->option.log_mask = ~0u;
moo->option.dfl_symtab_size = MOO_DFL_SYMTAB_SIZE;
moo->option.dfl_sysdic_size = MOO_DFL_SYSDIC_SIZE;
moo->option.dfl_procstk_size = MOO_DFL_PROCSTK_SIZE;
/* TODO: intoduct a permanent heap */
/*moo->permheap = moo_makeheap (moo, what is the best size???);
if (!moo->permheap) goto oops; */
moo->curheap = moo_makeheap (moo, heapsz);
if (!moo->curheap) goto oops;
moo->newheap = moo_makeheap (moo, heapsz);
if (!moo->newheap) goto oops;
if (moo_rbt_init (&moo->modtab, moo, MOO_SIZEOF(moo_ooch_t), 1) <= -1) goto oops;
modtab_inited = 1;
moo_rbt_setstyle (&moo->modtab, moo_getrbtstyle(MOO_RBT_STYLE_INLINE_COPIERS));
fill_bigint_tables (moo);
moo->tagged_classes[MOO_OOP_TAG_SMINT] = &moo->_small_integer;
moo->tagged_classes[MOO_OOP_TAG_CHAR] = &moo->_character;
moo->tagged_classes[MOO_OOP_TAG_ERROR] = &moo->_error_class;
return 0;
oops:
if (modtab_inited) moo_rbt_fini (&moo->modtab);
if (moo->newheap) moo_killheap (moo, moo->newheap);
if (moo->curheap) moo_killheap (moo, moo->curheap);
if (moo->permheap) moo_killheap (moo, moo->permheap);
return -1;
}
static moo_rbt_walk_t unload_module (moo_rbt_t* rbt, moo_rbt_pair_t* pair, void* ctx)
{
moo_t* moo = (moo_t*)ctx;
moo_mod_data_t* mdp;
mdp = MOO_RBT_VPTR(pair);
MOO_ASSERT (moo, mdp != MOO_NULL);
mdp->pair = MOO_NULL; /* to prevent moo_closemod() from calling moo_rbt_delete() */
moo_closemod (moo, mdp);
return MOO_RBT_WALK_FORWARD;
}
void moo_fini (moo_t* moo)
{
moo_cb_t* cb;
moo_oow_t i;
if (moo->sem_list)
{
moo_freemem (moo, moo->sem_list);
moo->sem_list_capa = 0;
moo->sem_list_count = 0;
}
if (moo->sem_heap)
{
moo_freemem (moo, moo->sem_heap);
moo->sem_heap_capa = 0;
moo->sem_heap_count = 0;
}
for (cb = moo->cblist; cb; cb = cb->next)
{
if (cb->fini) cb->fini (moo);
}
moo_rbt_walk (&moo->modtab, unload_module, moo); /* unload all modules */
moo_rbt_fini (&moo->modtab);
/* TOOD: persistency? storing objects to image file? */
moo_killheap (moo, moo->newheap);
moo_killheap (moo, moo->curheap);
moo_killheap (moo, moo->permheap);
/* deregister all callbacks */
while (moo->cblist) moo_deregcb (moo, moo->cblist);
for (i = 0; i < MOO_COUNTOF(moo->sbuf); i++)
{
if (moo->sbuf[i].ptr)
{
moo_freemem (moo, moo->sbuf[i].ptr);
moo->sbuf[i].ptr = MOO_NULL;
moo->sbuf[i].len = 0;
moo->sbuf[i].capa = 0;
}
}
if (moo->log.ptr)
{
/* make sure to flush your log message */
/* TODO: flush unwritten message */
moo_freemem (moo, moo->log.ptr);
moo->log.capa = 0;
moo->log.len = 0;
}
}
const moo_ooch_t* moo_geterrstr (moo_t* moo)
{
return moo_errnumtoerrstr (moo->errnum);
}
int moo_setoption (moo_t* moo, moo_option_t id, const void* value)
{
switch (id)
{
case MOO_TRAIT:
moo->option.trait = *(const unsigned int*)value;
return 0;
case MOO_LOG_MASK:
moo->option.log_mask = *(const unsigned int*)value;
return 0;
case MOO_SYMTAB_SIZE:
{
moo_oow_t w;
w = *(moo_oow_t*)value;
if (w <= 0 || w > MOO_SMOOI_MAX) goto einval;
moo->option.dfl_symtab_size = *(moo_oow_t*)value;
return 0;
}
case MOO_SYSDIC_SIZE:
{
moo_oow_t w;
w = *(moo_oow_t*)value;
if (w <= 0 || w > MOO_SMOOI_MAX) goto einval;
moo->option.dfl_sysdic_size = *(moo_oow_t*)value;
return 0;
}
case MOO_PROCSTK_SIZE:
{
moo_oow_t w;
w = *(moo_oow_t*)value;
if (w <= 0 || w > MOO_SMOOI_MAX) goto einval;
moo->option.dfl_procstk_size = *(moo_oow_t*)value;
return 0;
}
}
einval:
moo->errnum = MOO_EINVAL;
return -1;
}
int moo_getoption (moo_t* moo, moo_option_t id, void* value)
{
switch (id)
{
case MOO_TRAIT:
*(unsigned int*)value = moo->option.trait;
return 0;
case MOO_LOG_MASK:
*(unsigned int*)value = moo->option.log_mask;
return 0;
case MOO_SYMTAB_SIZE:
*(moo_oow_t*)value = moo->option.dfl_symtab_size;
return 0;
case MOO_SYSDIC_SIZE:
*(moo_oow_t*)value = moo->option.dfl_sysdic_size;
return 0;
case MOO_PROCSTK_SIZE:
*(moo_oow_t*)value = moo->option.dfl_procstk_size;
return 0;
};
moo->errnum = MOO_EINVAL;
return -1;
}
moo_cb_t* moo_regcb (moo_t* moo, moo_cb_t* tmpl)
{
moo_cb_t* actual;
actual = moo_allocmem (moo, MOO_SIZEOF(*actual));
if (!actual) return MOO_NULL;
*actual = *tmpl;
actual->next = moo->cblist;
actual->prev = MOO_NULL;
moo->cblist = actual;
return actual;
}
void moo_deregcb (moo_t* moo, moo_cb_t* cb)
{
if (cb == moo->cblist)
{
moo->cblist = moo->cblist->next;
if (moo->cblist) moo->cblist->prev = MOO_NULL;
}
else
{
if (cb->next) cb->next->prev = cb->prev;
if (cb->prev) cb->prev->next = cb->next;
}
moo_freemem (moo, cb);
}
void* moo_allocmem (moo_t* moo, moo_oow_t size)
{
void* ptr;
ptr = MOO_MMGR_ALLOC (moo->mmgr, size);
if (!ptr) moo->errnum = MOO_ESYSMEM;
return ptr;
}
void* moo_callocmem (moo_t* moo, moo_oow_t size)
{
void* ptr;
ptr = MOO_MMGR_ALLOC (moo->mmgr, size);
if (!ptr) moo->errnum = MOO_ESYSMEM;
else MOO_MEMSET (ptr, 0, size);
return ptr;
}
void* moo_reallocmem (moo_t* moo, void* ptr, moo_oow_t size)
{
ptr = MOO_MMGR_REALLOC (moo->mmgr, ptr, size);
if (!ptr) moo->errnum = MOO_ESYSMEM;
return ptr;
}
void moo_freemem (moo_t* moo, void* ptr)
{
MOO_MMGR_FREE (moo->mmgr, ptr);
}
/* -------------------------------------------------------------------------- */
#define MOD_PREFIX "moo_mod_"
#define MOD_PREFIX_LEN 9
#if defined(MOO_ENABLE_STATIC_MODULE)
#include "../mod/console.h"
#include "../mod/_stdio.h"
static struct
{
moo_bch_t* modname;
int (*modload) (moo_t* moo, moo_mod_t* mod);
}
static_modtab[] =
{
{ "console", moo_mod_console },
{ "stdio", moo_mod_stdio },
};
#endif
moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namelen)
{
moo_rbt_pair_t* pair;
moo_mod_data_t* mdp;
moo_mod_data_t md;
moo_mod_load_t load = MOO_NULL;
#if defined(MOO_ENABLE_STATIC_MODULE)
int n;
#endif
/* maximum module name length is MOO_MOD_NAME_LEN_MAX.
* MOD_PREFIX_LEN for MOD_PREFIX
* 1 for _ at the end when moo_mod_xxx_ is attempted.
* 1 for the terminating '\0'.
*/
moo_ooch_t buf[MOD_PREFIX_LEN + MOO_MOD_NAME_LEN_MAX + 1 + 1];
/* copy instead of encoding conversion. MOD_PREFIX must not
* include a character that requires encoding conversion.
* note the terminating null isn't needed in buf here. */
moo_copybctooochars (buf, MOD_PREFIX, MOD_PREFIX_LEN);
if (namelen > MOO_COUNTOF(buf) - (MOD_PREFIX_LEN + 1 + 1))
{
/* module name too long */
moo->errnum = MOO_EINVAL; /* TODO: change the error number to something more specific */
return MOO_NULL;
}
moo_copyoochars (&buf[MOD_PREFIX_LEN], name, namelen);
buf[MOD_PREFIX_LEN + namelen] = '\0';
#if defined(MOO_ENABLE_STATIC_MODULE)
/* attempt to find a statically linked module */
/*TODO: CHANGE THIS PART */
/* TODO: binary search ... */
for (n = 0; n < MOO_COUNTOF(static_modtab); n++)
{
if (moo_compoocharsbcstr (name, namelen, static_modtab[n].modname) == 0)
{
load = static_modtab[n].modload;
break;
}
}
if (n >= MOO_COUNTOF(static_modtab))
{
moo->errnum = MOO_ENOENT;
return MOO_NULL;
}
if (load)
{
/* found the module in the staic module table */
MOO_MEMSET (&md, 0, MOO_SIZEOF(md));
moo_copyoochars ((moo_ooch_t*)md.mod.name, name, namelen);
/* Note md.handle is MOO_NULL for a static module */
/* i copy-insert 'md' into the table before calling 'load'.
* to pass the same address to load(), query(), etc */
pair = moo_rbt_insert (&moo->modtab, (moo_ooch_t*)name, namelen, &md, MOO_SIZEOF(md));
if (pair == MOO_NULL)
{
moo->errnum = MOO_ESYSMEM;
return MOO_NULL;
}
mdp = (moo_mod_data_t*)MOO_RBT_VPTR(pair);
if (load (moo, &mdp->mod) <= -1)
{
moo_rbt_delete (&moo->modtab, (moo_ooch_t*)name, namelen);
return MOO_NULL;
}
return mdp;
}
#endif
/* attempt to find an external module */
MOO_MEMSET (&md, 0, MOO_SIZEOF(md));
moo_copyoochars ((moo_ooch_t*)md.mod.name, name, namelen);
if (moo->vmprim.dl_open && moo->vmprim.dl_getsym && moo->vmprim.dl_close)
{
md.handle = moo->vmprim.dl_open (moo, &buf[MOD_PREFIX_LEN]);
}
if (md.handle == MOO_NULL)
{
MOO_DEBUG2 (moo, "Cannot open a module [%.*js]\n", namelen, name);
moo->errnum = MOO_ENOENT; /* TODO: be more descriptive about the error */
return MOO_NULL;
}
/* attempt to get moo_mod_xxx where xxx is the module name*/
load = moo->vmprim.dl_getsym (moo, md.handle, buf);
if (!load)
{
MOO_DEBUG3 (moo, "Cannot get a module symbol [%js] in [%.*js]\n", buf, namelen, name);
moo->errnum = MOO_ENOENT; /* TODO: be more descriptive about the error */
moo->vmprim.dl_close (moo, md.handle);
return MOO_NULL;
}
/* i copy-insert 'md' into the table before calling 'load'.
* to pass the same address to load(), query(), etc */
pair = moo_rbt_insert (&moo->modtab, (void*)name, namelen, &md, MOO_SIZEOF(md));
if (pair == MOO_NULL)
{
MOO_DEBUG2 (moo, "Cannot register a module [%.*js]\n", namelen, name);
moo->errnum = MOO_ESYSMEM;
moo->vmprim.dl_close (moo, md.handle);
return MOO_NULL;
}
mdp = (moo_mod_data_t*)MOO_RBT_VPTR(pair);
if (load (moo, &mdp->mod) <= -1)
{
MOO_DEBUG3 (moo, "Module function [%js] returned failure in [%.*js]\n", buf, namelen, name);
moo->errnum = MOO_ENOENT; /* TODO: proper error code and handling */
moo_rbt_delete (&moo->modtab, name, namelen);
moo->vmprim.dl_close (moo, mdp->handle);
return MOO_NULL;
}
mdp->pair = pair;
MOO_DEBUG2 (moo, "Opened a module [%js] - %p\n", mdp->mod.name, mdp->handle);
/* the module loader must ensure to set a proper query handler */
MOO_ASSERT (moo, mdp->mod.query != MOO_NULL);
return mdp;
}
void moo_closemod (moo_t* moo, moo_mod_data_t* mdp)
{
if (mdp->mod.unload) mdp->mod.unload (moo, &mdp->mod);
if (mdp->handle)
{
moo->vmprim.dl_close (moo, mdp->handle);
MOO_DEBUG2 (moo, "Closed a module [%js] - %p\n", mdp->mod.name, mdp->handle);
mdp->handle = MOO_NULL;
}
if (mdp->pair)
{
/*mdp->pair = MOO_NULL;*/ /* this reset isn't needed as the area will get freed by moo_rbt_delete()) */
moo_rbt_delete (&moo->modtab, mdp->mod.name, moo_countoocstr(mdp->mod.name));
}
}
int moo_importmod (moo_t* moo, moo_oop_t _class, const moo_ooch_t* name, moo_oow_t len)
{
moo_rbt_pair_t* pair;
moo_mod_data_t* mdp;
int r = 0;
/* moo_openmod(), moo_closemod(), etc calls a user-defined callback.
* i need to protect _class in case the user-defined callback allocates
* a OOP memory chunk and GC occurs */
moo_pushtmp (moo, &_class);
pair = moo_rbt_search (&moo->modtab, name, len);
if (pair)
{
mdp = (moo_mod_data_t*)MOO_RBT_VPTR(pair);
MOO_ASSERT (moo, mdp != MOO_NULL);
}
else
{
mdp = moo_openmod (moo, name, len);
if (!mdp)
{
r = -1;
goto done2;
}
}
if (!mdp->mod.import)
{
MOO_DEBUG1 (moo, "Cannot import module [%js] - importing not supported by the module\n", mdp->mod.name);
moo->errnum = MOO_ENOIMPL;
r = -1;
goto done;
}
if (mdp->mod.import (moo, &mdp->mod, _class) <= -1)
{
MOO_DEBUG1 (moo, "Cannot import module [%js] - module's import() returned failure\n", mdp->mod.name);
r = -1;
goto done;
}
done:
if (!pair)
{
/* close the module if it has been opened in this function. */
moo_closemod (moo, mdp);
}
done2:
moo_poptmp (moo);
return r;
}
moo_pfimpl_t moo_querymod (moo_t* moo, const moo_ooch_t* pfid, moo_oow_t pfidlen)
{
/* primitive function identifier
* _funcname
* modname_funcname
*/
moo_rbt_pair_t* pair;
moo_mod_data_t* mdp;
const moo_ooch_t* sep;
moo_oow_t mod_name_len;
moo_pfimpl_t handler;
sep = moo_findoochar (pfid, pfidlen, '.');
if (!sep)
{
/* i'm writing a conservative code here. the compiler should
* guarantee that an underscore is included in an primitive identifer.
* what if the compiler is broken? imagine a buggy compiler rewritten
* in moo itself? */
MOO_DEBUG2 (moo, "Internal error - no period in a primitive function identifier [%.*js] - buggy compiler?\n", pfidlen, pfid);
moo->errnum = MOO_EINTERN;
return MOO_NULL;
}
mod_name_len = sep - pfid;
pair = moo_rbt_search (&moo->modtab, pfid, mod_name_len);
if (pair)
{
mdp = (moo_mod_data_t*)MOO_RBT_VPTR(pair);
MOO_ASSERT (moo, mdp != MOO_NULL);
}
else
{
mdp = moo_openmod (moo, pfid, mod_name_len);
if (!mdp) return MOO_NULL;
}
if ((handler = mdp->mod.query (moo, &mdp->mod, sep + 1)) == MOO_NULL)
{
/* the primitive function is not found. keep the module open */
MOO_DEBUG2 (moo, "Cannot find a primitive function [%js] in a module [%js]\n", sep + 1, mdp->mod.name);
moo->errnum = MOO_ENOENT; /* TODO: proper error code and handling */
return MOO_NULL;
}
MOO_DEBUG3 (moo, "Found a primitive function [%js] in a module [%js] - %p\n", sep + 1, mdp->mod.name, handler);
return handler;
}
/* -------------------------------------------------------------------------- */
/* add a new primitive method */
int moo_genpfmethod (moo_t* moo, moo_mod_t* mod, moo_oop_t _class, moo_method_type_t type, const moo_ooch_t* mthname, int variadic, const moo_ooch_t* pfname)
{
/* NOTE: this function is a subset of add_compiled_method() in comp.c */
moo_oop_char_t mnsym, pfidsym;
moo_oop_method_t mth;
moo_oop_class_t cls;
moo_oow_t tmp_count = 0, i;
moo_ooi_t arg_count = 0;
moo_oocs_t cs;
moo_ooi_t preamble_flags = 0;
static moo_ooch_t dot[] = { '.', '\0' };
MOO_ASSERT (moo, MOO_CLASSOF(moo, _class) == moo->_class);
if (!pfname) pfname = mthname;
cls = (moo_oop_class_t)_class;
moo_pushtmp (moo, (moo_oop_t*)&cls); tmp_count++;
MOO_ASSERT (moo, MOO_CLASSOF(moo, (moo_oop_t)cls->mthdic[type]) == moo->_method_dictionary);
for (i = 0; mthname[i]; i++)
{
if (mthname[i] == ':')
{
if (variadic) goto oops_inval;
arg_count++;
}
}
/* TODO: check if name is a valid method name - more checks... */
/* TOOD: if the method name is a binary selector, it can still have an argument.. so the check below is invalid... */
if (arg_count > 0 && mthname[i - 1] != ':')
{
oops_inval:
MOO_DEBUG2 (moo, "Cannot generate primitive function method [%js] in [%O] - invalid name\n", mthname, cls->name);
moo->errnum = MOO_EINVAL;
goto oops;
}
cs.ptr = (moo_ooch_t*)mthname;
cs.len = i;
if (moo_lookupdic (moo, cls->mthdic[type], &cs) != MOO_NULL)
{
MOO_DEBUG2 (moo, "Cannot generate primitive function method [%js] in [%O] - duplicate\n", mthname, cls->name);
moo->errnum = MOO_EEXIST;
goto oops;
}
mnsym = (moo_oop_char_t)moo_makesymbol (moo, mthname, i);
if (!mnsym) goto oops;
moo_pushtmp (moo, (moo_oop_t*)&mnsym); tmp_count++;
/* compose a full primitive function identifier to VM's string buffer.
* pfid => mod->name + '.' + pfname */
if (moo_copyoocstrtosbuf(moo, mod->name, 0) <= -1 ||
moo_concatoocstrtosbuf(moo, dot, 0) <= -1 ||
moo_concatoocstrtosbuf(moo, pfname, 0) <= -1)
{
MOO_DEBUG2 (moo, "Cannot generate primitive function method [%js] in [%O] - VM memory shortage\n", mthname, cls->name);
return -1;
}
pfidsym = (moo_oop_char_t)moo_makesymbol (moo, moo->sbuf[0].ptr, moo->sbuf[0].len);
if (!pfidsym)
{
MOO_DEBUG2 (moo, "Cannot generate primitive function method [%js] in [%O] - symbol instantiation failure\n", mthname, cls->name);
goto oops;
}
moo_pushtmp (moo, (moo_oop_t*)&pfidsym); tmp_count++;
#if defined(MOO_USE_OBJECT_TRAILER)
mth = (moo_oop_method_t)moo_instantiatewithtrailer (moo, moo->_method, 1, MOO_NULL, 0);
#else
mth = (moo_oop_method_t)moo_instantiate (moo, moo->_method, MOO_NULL, 1);
#endif
if (!mth)
{
MOO_DEBUG2 (moo, "Cannot generate primitive function method [%js] in [%O] - method instantiation failure\n", mthname, cls->name);
goto oops;
}
/* store the primitive function name symbol to the literal frame */
mth->slot[0] = (moo_oop_t)pfidsym;
/* premable should contain the index to the literal frame which is always 0 */
mth->owner = cls;
mth->name = mnsym;
if (variadic) preamble_flags |= MOO_METHOD_PREAMBLE_FLAG_VARIADIC;
mth->preamble = MOO_SMOOI_TO_OOP(MOO_METHOD_MAKE_PREAMBLE(MOO_METHOD_PREAMBLE_NAMED_PRIMITIVE, 0, preamble_flags));
mth->preamble_data[0] = MOO_SMOOI_TO_OOP(0);
mth->preamble_data[1] = MOO_SMOOI_TO_OOP(0);
mth->tmpr_count = MOO_SMOOI_TO_OOP(arg_count);
mth->tmpr_nargs = MOO_SMOOI_TO_OOP(arg_count);
/* TODO: emit BCODE_RETURN_NIL ? */
if (!moo_putatdic (moo, cls->mthdic[type], (moo_oop_t)mnsym, (moo_oop_t)mth))
{
MOO_DEBUG2 (moo, "Cannot generate primitive function method [%js] in [%O] - failed to add to method dictionary\n", mthname, cls->name);
goto oops;
}
MOO_DEBUG2 (moo, "Generated primitive function method [%js] in [%O]\n", mthname, cls->name);
moo_poptmps (moo, tmp_count); tmp_count = 0;
return 0;
oops:
moo_poptmps (moo, tmp_count);
return -1;
}

1463
moo/lib/moo.h Normal file

File diff suppressed because it is too large Load Diff

405
moo/lib/obj.c Normal file
View File

@ -0,0 +1,405 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
void* moo_allocbytes (moo_t* moo, moo_oow_t size)
{
moo_uint8_t* ptr;
#if defined(MOO_DEBUG_GC)
if (!(moo->option.trait & MOO_NOGC)) moo_gc (moo);
#endif
ptr = moo_allocheapmem (moo, moo->curheap, size);
if (!ptr && moo->errnum == MOO_EOOMEM && !(moo->option.trait & MOO_NOGC))
{
moo_gc (moo);
ptr = moo_allocheapmem (moo, moo->curheap, size);
/* TODO: grow heap if ptr is still null. */
}
return ptr;
}
moo_oop_t moo_allocoopobj (moo_t* moo, moo_oow_t size)
{
moo_oop_oop_t hdr;
moo_oow_t nbytes, nbytes_aligned;
nbytes = size * MOO_SIZEOF(moo_oop_t);
/* this isn't really necessary since nbytes must be
* aligned already. */
nbytes_aligned = MOO_ALIGN(nbytes, MOO_SIZEOF(moo_oop_t));
/* making the number of bytes to allocate a multiple of
* MOO_SIZEOF(moo_oop_t) will guarantee the starting address
* of the allocated space to be an even number.
* see MOO_OOP_IS_NUMERIC() and MOO_OOP_IS_POINTER() */
hdr = moo_allocbytes (moo, MOO_SIZEOF(moo_obj_t) + nbytes_aligned);
if (!hdr) return MOO_NULL;
hdr->_flags = MOO_OBJ_MAKE_FLAGS(MOO_OBJ_TYPE_OOP, MOO_SIZEOF(moo_oop_t), 0, 0, 0, 0, 0);
MOO_OBJ_SET_SIZE (hdr, size);
MOO_OBJ_SET_CLASS (hdr, moo->_nil);
while (size > 0) hdr->slot[--size] = moo->_nil;
return (moo_oop_t)hdr;
}
#if defined(MOO_USE_OBJECT_TRAILER)
moo_oop_t moo_allocoopobjwithtrailer (moo_t* moo, moo_oow_t size, const moo_oob_t* bptr, moo_oow_t blen)
{
moo_oop_oop_t hdr;
moo_oow_t nbytes, nbytes_aligned;
moo_oow_t i;
/* +1 for the trailer size of the moo_oow_t type */
nbytes = (size + 1) * MOO_SIZEOF(moo_oop_t) + blen;
nbytes_aligned = MOO_ALIGN(nbytes, MOO_SIZEOF(moo_oop_t));
hdr = moo_allocbytes (moo, MOO_SIZEOF(moo_obj_t) + nbytes_aligned);
if (!hdr) return MOO_NULL;
hdr->_flags = MOO_OBJ_MAKE_FLAGS(MOO_OBJ_TYPE_OOP, MOO_SIZEOF(moo_oop_t), 0, 0, 0, 0, 1);
MOO_OBJ_SET_SIZE (hdr, size);
MOO_OBJ_SET_CLASS (hdr, moo->_nil);
for (i = 0; i < size; i++) hdr->slot[i] = moo->_nil;
/* [NOTE] this is not converted to a SmallInteger object */
hdr->slot[size] = (moo_oop_t)blen;
if (bptr)
{
MOO_MEMCPY (&hdr->slot[size + 1], bptr, blen);
}
else
{
MOO_MEMSET (&hdr->slot[size + 1], 0, blen);
}
return (moo_oop_t)hdr;
}
#endif
static MOO_INLINE moo_oop_t alloc_numeric_array (moo_t* moo, const void* ptr, moo_oow_t len, moo_obj_type_t type, moo_oow_t unit, int extra)
{
/* allocate a variable object */
moo_oop_t hdr;
moo_oow_t xbytes, nbytes, nbytes_aligned;
xbytes = len * unit;
/* 'extra' indicates an extra unit to append at the end.
* it's useful to store a string with a terminating null */
nbytes = extra? xbytes + len: xbytes;
nbytes_aligned = MOO_ALIGN(nbytes, MOO_SIZEOF(moo_oop_t));
/* TODO: check overflow in size calculation*/
/* making the number of bytes to allocate a multiple of
* MOO_SIZEOF(moo_oop_t) will guarantee the starting address
* of the allocated space to be an even number.
* see MOO_OOP_IS_NUMERIC() and MOO_OOP_IS_POINTER() */
hdr = moo_allocbytes (moo, MOO_SIZEOF(moo_obj_t) + nbytes_aligned);
if (!hdr) return MOO_NULL;
hdr->_flags = MOO_OBJ_MAKE_FLAGS(type, unit, extra, 0, 0, 0, 0);
hdr->_size = len;
MOO_OBJ_SET_SIZE (hdr, len);
MOO_OBJ_SET_CLASS (hdr, moo->_nil);
if (ptr)
{
/* copy data */
MOO_MEMCPY (hdr + 1, ptr, xbytes);
MOO_MEMSET ((moo_uint8_t*)(hdr + 1) + xbytes, 0, nbytes_aligned - xbytes);
}
else
{
/* initialize with zeros when the string pointer is not given */
MOO_MEMSET ((hdr + 1), 0, nbytes_aligned);
}
return hdr;
}
moo_oop_t moo_alloccharobj (moo_t* moo, const moo_ooch_t* ptr, moo_oow_t len)
{
return alloc_numeric_array (moo, ptr, len, MOO_OBJ_TYPE_CHAR, MOO_SIZEOF(moo_ooch_t), 1);
}
moo_oop_t moo_allocbyteobj (moo_t* moo, const moo_oob_t* ptr, moo_oow_t len)
{
return alloc_numeric_array (moo, ptr, len, MOO_OBJ_TYPE_BYTE, MOO_SIZEOF(moo_oob_t), 0);
}
moo_oop_t moo_allochalfwordobj (moo_t* moo, const moo_oohw_t* ptr, moo_oow_t len)
{
return alloc_numeric_array (moo, ptr, len, MOO_OBJ_TYPE_HALFWORD, MOO_SIZEOF(moo_oohw_t), 0);
}
moo_oop_t moo_allocwordobj (moo_t* moo, const moo_oow_t* ptr, moo_oow_t len)
{
return alloc_numeric_array (moo, ptr, len, MOO_OBJ_TYPE_WORD, MOO_SIZEOF(moo_oow_t), 0);
}
static MOO_INLINE int decode_spec (moo_t* moo, moo_oop_t _class, moo_oow_t vlen, moo_obj_type_t* type, moo_oow_t* outlen)
{
moo_oow_t spec;
moo_oow_t named_instvar;
moo_obj_type_t indexed_type;
MOO_ASSERT (moo, MOO_OOP_IS_POINTER(_class));
MOO_ASSERT (moo, MOO_CLASSOF(moo, _class) == moo->_class);
MOO_ASSERT (moo, MOO_OOP_IS_SMOOI(((moo_oop_class_t)_class)->spec));
spec = MOO_OOP_TO_SMOOI(((moo_oop_class_t)_class)->spec);
named_instvar = MOO_CLASS_SPEC_NAMED_INSTVAR(spec); /* size of the named_instvar part */
if (MOO_CLASS_SPEC_IS_INDEXED(spec))
{
indexed_type = MOO_CLASS_SPEC_INDEXED_TYPE(spec);
if (indexed_type == MOO_OBJ_TYPE_OOP)
{
if (named_instvar > MOO_MAX_NAMED_INSTVARS)
{
MOO_DEBUG3 (moo, "Too many named instance variables for a variable-pointer class %O - %zu/%zu\n", _class, named_instvar, (moo_oow_t)MOO_MAX_NAMED_INSTVARS);
return -1;
}
if (vlen > MOO_MAX_INDEXED_INSTVARS(named_instvar))
{
MOO_DEBUG3 (moo, "Too many unnamed instance variables for a variable-pointer class %O - %zu/%zu\n", _class, vlen, (moo_oow_t)MOO_MAX_INDEXED_INSTVARS(named_instvar));
return -1;
}
MOO_ASSERT (moo, named_instvar + vlen <= MOO_OBJ_SIZE_MAX);
}
else
{
/* a non-pointer indexed class can't have named instance variables */
if (named_instvar > 0)
{
MOO_DEBUG1 (moo, "Named instance variables in a variable-nonpointer class %O\n", _class);
return -1;
}
if (vlen > MOO_OBJ_SIZE_MAX)
{
MOO_DEBUG3 (moo, "Too many unnamed instance variables for a variable-nonpointer class %O - %zu/%zu\n", _class, vlen, (moo_oow_t)MOO_OBJ_SIZE_MAX);
return -1;
}
}
}
else
{
/* named instance variables only. treat it as if it is an
* indexable class with no variable data */
indexed_type = MOO_OBJ_TYPE_OOP;
if (vlen > 0)
{
MOO_DEBUG2 (moo, "Unamed instance variables for a fixed class %O - %zu\n", _class, vlen);
return -1;
}
/*vlen = 0;*/ /* vlen is not used */
if (named_instvar > MOO_MAX_NAMED_INSTVARS)
{
MOO_DEBUG3 (moo, "Too many named instance variables for a fixed class %O - %zu/%zu\n", _class, named_instvar, (moo_oow_t)MOO_MAX_NAMED_INSTVARS);
return -1;
}
MOO_ASSERT (moo, named_instvar <= MOO_OBJ_SIZE_MAX);
}
*type = indexed_type;
*outlen = named_instvar + vlen;
return 0;
}
moo_oop_t moo_instantiate (moo_t* moo, moo_oop_t _class, const void* vptr, moo_oow_t vlen)
{
moo_oop_t oop;
moo_obj_type_t type;
moo_oow_t alloclen;
moo_oow_t tmp_count = 0;
MOO_ASSERT (moo, moo->_nil != MOO_NULL);
if (decode_spec (moo, _class, vlen, &type, &alloclen) <= -1)
{
moo->errnum = MOO_EINVAL;
return MOO_NULL;
}
moo_pushtmp (moo, &_class); tmp_count++;
switch (type)
{
case MOO_OBJ_TYPE_OOP:
/* both the fixed part(named instance variables) and
* the variable part(indexed instance variables) are allowed. */
oop = moo_allocoopobj (moo, alloclen);
MOO_ASSERT (moo, vptr == MOO_NULL);
/*
This function is not GC-safe. so i don't want to initialize
the payload of a pointer object. The caller can call this
function and initialize payloads then.
if (oop && vptr && vlen > 0)
{
moo_oop_oop_t hdr = (moo_oop_oop_t)oop;
MOO_MEMCPY (&hdr->slot[named_instvar], vptr, vlen * MOO_SIZEOF(moo_oop_t));
}
For the above code to work, it should protect the elements of
the vptr array with moo_pushtmp(). So it might be better
to disallow a non-NULL vptr when indexed_type is OOP. See
the assertion above this comment block.
*/
break;
case MOO_OBJ_TYPE_CHAR:
oop = moo_alloccharobj (moo, vptr, alloclen);
break;
case MOO_OBJ_TYPE_BYTE:
oop = moo_allocbyteobj (moo, vptr, alloclen);
break;
case MOO_OBJ_TYPE_HALFWORD:
oop = moo_allochalfwordobj (moo, vptr, alloclen);
break;
case MOO_OBJ_TYPE_WORD:
oop = moo_allocwordobj (moo, vptr, alloclen);
break;
default:
moo->errnum = MOO_EINTERN;
oop = MOO_NULL;
break;
}
if (oop) MOO_OBJ_SET_CLASS (oop, _class);
moo_poptmps (moo, tmp_count);
return oop;
}
moo_oop_t moo_instantiate2 (moo_t* moo, moo_oop_t _class, const void* vptr, moo_oow_t vlen, int ngc)
{
moo_oop_t oop;
moo_obj_type_t type;
moo_oow_t alloclen;
moo_oow_t tmp_count = 0;
MOO_ASSERT (moo, moo->_nil != MOO_NULL);
if (decode_spec (moo, _class, vlen, &type, &alloclen) <= -1)
{
moo->errnum = MOO_EINVAL;
return MOO_NULL;
}
moo_pushtmp (moo, &_class); tmp_count++;
/* TODO: support NGC */
switch (type)
{
case MOO_OBJ_TYPE_OOP:
/* NOTE: vptr is not used for GC unsafety */
oop = moo_allocoopobj (moo, alloclen);
break;
case MOO_OBJ_TYPE_CHAR:
oop = moo_alloccharobj (moo, vptr, alloclen);
break;
case MOO_OBJ_TYPE_BYTE:
oop = moo_allocbyteobj (moo, vptr, alloclen);
break;
case MOO_OBJ_TYPE_HALFWORD:
oop = moo_allochalfwordobj (moo, vptr, alloclen);
break;
case MOO_OBJ_TYPE_WORD:
oop = moo_allocwordobj (moo, vptr, alloclen);
break;
default:
moo->errnum = MOO_EINTERN;
oop = MOO_NULL;
break;
}
if (oop) MOO_OBJ_SET_CLASS (oop, _class);
moo_poptmps (moo, tmp_count);
return oop;
}
#if defined(MOO_USE_OBJECT_TRAILER)
moo_oop_t moo_instantiatewithtrailer (moo_t* moo, moo_oop_t _class, moo_oow_t vlen, const moo_oob_t* tptr, moo_oow_t tlen)
{
moo_oop_t oop;
moo_obj_type_t type;
moo_oow_t alloclen;
moo_oow_t tmp_count = 0;
MOO_ASSERT (moo, moo->_nil != MOO_NULL);
if (decode_spec (moo, _class, vlen, &type, &alloclen) <= -1)
{
moo->errnum = MOO_EINVAL;
return MOO_NULL;
}
moo_pushtmp (moo, &_class); tmp_count++;
switch (type)
{
case MOO_OBJ_TYPE_OOP:
/* NOTE: vptr is not used for GC unsafety */
oop = moo_allocoopobjwithtrailer(moo, alloclen, tptr, tlen);
break;
default:
moo->errnum = MOO_EINTERN;
oop = MOO_NULL;
break;
}
if (oop) MOO_OBJ_SET_CLASS (oop, _class);
moo_poptmps (moo, tmp_count);
return oop;
}
#endif

51
moo/lib/proc.c Normal file
View File

@ -0,0 +1,51 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
moo_oop_process_t moo_addnewproc (moo_t* moo)
{
moo_oop_process_t proc;
proc = (moo_oop_process_t)moo_instantiate (moo, moo->_process, MOO_NULL, moo->option.dfl_procstk_size);
if (!proc) return MOO_NULL;
proc->state = MOO_SMOOI_TO_OOP(0);
MOO_ASSERT (moo, MOO_OBJ_GET_SIZE(proc) == MOO_PROCESS_NAMED_INSTVARS + moo->option.dfl_procstk_size);
return proc;
}
void moo_schedproc (moo_t* moo, moo_oop_process_t proc)
{
/* TODO: if scheduled, don't add */
/*proc->next = moo->_active_process;
proc->_active_process = proc;*/
}
void moo_unschedproc (moo_t* moo, moo_oop_process_t proc)
{
}

997
moo/lib/rbt.c Normal file
View File

@ -0,0 +1,997 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-rbt.h"
#include "moo-prv.h"
#define copier_t moo_rbt_copier_t
#define freeer_t moo_rbt_freeer_t
#define comper_t moo_rbt_comper_t
#define keeper_t moo_rbt_keeper_t
#define walker_t moo_rbt_walker_t
#define cbserter_t moo_rbt_cbserter_t
#define KPTR(p) MOO_RBT_KPTR(p)
#define KLEN(p) MOO_RBT_KLEN(p)
#define VPTR(p) MOO_RBT_VPTR(p)
#define VLEN(p) MOO_RBT_VLEN(p)
#define KTOB(rbt,len) ((len)*(rbt)->scale[MOO_RBT_KEY])
#define VTOB(rbt,len) ((len)*(rbt)->scale[MOO_RBT_VAL])
#define UPSERT 1
#define UPDATE 2
#define ENSERT 3
#define INSERT 4
#define IS_NIL(rbt,x) ((x) == &((rbt)->xnil))
#define LEFT 0
#define RIGHT 1
#define left child[LEFT]
#define right child[RIGHT]
#define rotate_left(rbt,pivot) rotate(rbt,pivot,1);
#define rotate_right(rbt,pivot) rotate(rbt,pivot,0);
MOO_INLINE moo_rbt_pair_t* moo_rbt_allocpair (
moo_rbt_t* rbt, void* kptr, moo_oow_t klen, void* vptr, moo_oow_t vlen)
{
moo_rbt_pair_t* n;
copier_t kcop = rbt->style->copier[MOO_RBT_KEY];
copier_t vcop = rbt->style->copier[MOO_RBT_VAL];
moo_oow_t as = MOO_SIZEOF(moo_rbt_pair_t);
if (kcop == MOO_RBT_COPIER_INLINE) as += KTOB(rbt,klen);
if (vcop == MOO_RBT_COPIER_INLINE) as += VTOB(rbt,vlen);
n = (moo_rbt_pair_t*) MOO_MMGR_ALLOC (rbt->moo->mmgr, as);
if (n == MOO_NULL) return MOO_NULL;
n->color = MOO_RBT_RED;
n->parent = MOO_NULL;
n->child[LEFT] = &rbt->xnil;
n->child[RIGHT] = &rbt->xnil;
KLEN(n) = klen;
if (kcop == MOO_RBT_COPIER_SIMPLE)
{
KPTR(n) = kptr;
}
else if (kcop == MOO_RBT_COPIER_INLINE)
{
KPTR(n) = n + 1;
if (kptr) MOO_MEMCPY (KPTR(n), kptr, KTOB(rbt,klen));
}
else
{
KPTR(n) = kcop (rbt, kptr, klen);
if (KPTR(n) == MOO_NULL)
{
MOO_MMGR_FREE (rbt->moo->mmgr, n);
return MOO_NULL;
}
}
VLEN(n) = vlen;
if (vcop == MOO_RBT_COPIER_SIMPLE)
{
VPTR(n) = vptr;
}
else if (vcop == MOO_RBT_COPIER_INLINE)
{
VPTR(n) = n + 1;
if (kcop == MOO_RBT_COPIER_INLINE)
VPTR(n) = (moo_oob_t*)VPTR(n) + KTOB(rbt,klen);
if (vptr) MOO_MEMCPY (VPTR(n), vptr, VTOB(rbt,vlen));
}
else
{
VPTR(n) = vcop (rbt, vptr, vlen);
if (VPTR(n) != MOO_NULL)
{
if (rbt->style->freeer[MOO_RBT_KEY] != MOO_NULL)
rbt->style->freeer[MOO_RBT_KEY] (rbt, KPTR(n), KLEN(n));
MOO_MMGR_FREE (rbt->moo->mmgr, n);
return MOO_NULL;
}
}
return n;
}
MOO_INLINE void moo_rbt_freepair (moo_rbt_t* rbt, moo_rbt_pair_t* pair)
{
if (rbt->style->freeer[MOO_RBT_KEY] != MOO_NULL)
rbt->style->freeer[MOO_RBT_KEY] (rbt, KPTR(pair), KLEN(pair));
if (rbt->style->freeer[MOO_RBT_VAL] != MOO_NULL)
rbt->style->freeer[MOO_RBT_VAL] (rbt, VPTR(pair), VLEN(pair));
MOO_MMGR_FREE (rbt->moo->mmgr, pair);
}
static moo_rbt_style_t style[] =
{
{
{
MOO_RBT_COPIER_DEFAULT,
MOO_RBT_COPIER_DEFAULT
},
{
MOO_RBT_FREEER_DEFAULT,
MOO_RBT_FREEER_DEFAULT
},
MOO_RBT_COMPER_DEFAULT,
MOO_RBT_KEEPER_DEFAULT
},
{
{
MOO_RBT_COPIER_INLINE,
MOO_RBT_COPIER_INLINE
},
{
MOO_RBT_FREEER_DEFAULT,
MOO_RBT_FREEER_DEFAULT
},
MOO_RBT_COMPER_DEFAULT,
MOO_RBT_KEEPER_DEFAULT
},
{
{
MOO_RBT_COPIER_INLINE,
MOO_RBT_COPIER_DEFAULT
},
{
MOO_RBT_FREEER_DEFAULT,
MOO_RBT_FREEER_DEFAULT
},
MOO_RBT_COMPER_DEFAULT,
MOO_RBT_KEEPER_DEFAULT
},
{
{
MOO_RBT_COPIER_DEFAULT,
MOO_RBT_COPIER_INLINE
},
{
MOO_RBT_FREEER_DEFAULT,
MOO_RBT_FREEER_DEFAULT
},
MOO_RBT_COMPER_DEFAULT,
MOO_RBT_KEEPER_DEFAULT
}
};
const moo_rbt_style_t* moo_getrbtstyle (moo_rbt_style_kind_t kind)
{
return &style[kind];
}
moo_rbt_t* moo_rbt_open (moo_t* moo, moo_oow_t xtnsize, int kscale, int vscale)
{
moo_rbt_t* rbt;
rbt = (moo_rbt_t*) MOO_MMGR_ALLOC (moo->mmgr, MOO_SIZEOF(moo_rbt_t) + xtnsize);
if (rbt == MOO_NULL) return MOO_NULL;
if (moo_rbt_init (rbt, moo, kscale, vscale) <= -1)
{
MOO_MMGR_FREE (moo->mmgr, rbt);
return MOO_NULL;
}
MOO_MEMSET (rbt + 1, 0, xtnsize);
return rbt;
}
void moo_rbt_close (moo_rbt_t* rbt)
{
moo_rbt_fini (rbt);
MOO_MMGR_FREE (rbt->moo->mmgr, rbt);
}
int moo_rbt_init (moo_rbt_t* rbt, moo_t* moo, int kscale, int vscale)
{
/* do not zero out the extension */
MOO_MEMSET (rbt, 0, MOO_SIZEOF(*rbt));
rbt->moo = moo;
rbt->scale[MOO_RBT_KEY] = (kscale < 1)? 1: kscale;
rbt->scale[MOO_RBT_VAL] = (vscale < 1)? 1: vscale;
rbt->size = 0;
rbt->style = &style[0];
/* self-initializing nil */
MOO_MEMSET(&rbt->xnil, 0, MOO_SIZEOF(rbt->xnil));
rbt->xnil.color = MOO_RBT_BLACK;
rbt->xnil.left = &rbt->xnil;
rbt->xnil.right = &rbt->xnil;
/* root is set to nil initially */
rbt->root = &rbt->xnil;
return 0;
}
void moo_rbt_fini (moo_rbt_t* rbt)
{
moo_rbt_clear (rbt);
}
void* moo_rbt_getxtn (moo_rbt_t* rbt)
{
return (void*)(rbt + 1);
}
const moo_rbt_style_t* moo_rbt_getstyle (const moo_rbt_t* rbt)
{
return rbt->style;
}
void moo_rbt_setstyle (moo_rbt_t* rbt, const moo_rbt_style_t* style)
{
MOO_ASSERT (rbt->moo, style != MOO_NULL);
rbt->style = style;
}
moo_oow_t moo_rbt_getsize (const moo_rbt_t* rbt)
{
return rbt->size;
}
moo_rbt_pair_t* moo_rbt_search (const moo_rbt_t* rbt, const void* kptr, moo_oow_t klen)
{
moo_rbt_pair_t* pair = rbt->root;
while (!IS_NIL(rbt,pair))
{
int n = rbt->style->comper (rbt, kptr, klen, KPTR(pair), KLEN(pair));
if (n == 0) return pair;
if (n > 0) pair = pair->right;
else /* if (n < 0) */ pair = pair->left;
}
return MOO_NULL;
}
static void rotate (moo_rbt_t* rbt, moo_rbt_pair_t* pivot, int leftwise)
{
/*
* == leftwise rotation
* move the pivot pair down to the poistion of the pivot's original
* left child(x). move the pivot's right child(y) to the pivot's original
* position. as 'c1' is between 'y' and 'pivot', move it to the right
* of the new pivot position.
* parent parent
* | | (left or right?) | |
* pivot y
* / \ / \
* x y =====> pivot c2
* / \ / \
* c1 c2 x c1
*
* == rightwise rotation
* move the pivot pair down to the poistion of the pivot's original
* right child(y). move the pivot's left child(x) to the pivot's original
* position. as 'c2' is between 'x' and 'pivot', move it to the left
* of the new pivot position.
*
* parent parent
* | | (left or right?) | |
* pivot x
* / \ / \
* x y =====> c1 pivot
* / \ / \
* c1 c2 c2 y
*
*
* the actual implementation here resolves the pivot's relationship to
* its parent by comparaing pointers as it is not known if the pivot pair
* is the left child or the right child of its parent,
*/
moo_rbt_pair_t* parent, * z, * c;
int cid1, cid2;
MOO_ASSERT (rbt->moo, pivot != MOO_NULL);
if (leftwise)
{
cid1 = RIGHT;
cid2 = LEFT;
}
else
{
cid1 = LEFT;
cid2 = RIGHT;
}
parent = pivot->parent;
/* y for leftwise rotation, x for rightwise rotation */
z = pivot->child[cid1];
/* c1 for leftwise rotation, c2 for rightwise rotation */
c = z->child[cid2];
z->parent = parent;
if (parent)
{
if (parent->left == pivot)
{
parent->left = z;
}
else
{
MOO_ASSERT (rbt->moo, parent->right == pivot);
parent->right = z;
}
}
else
{
MOO_ASSERT (rbt->moo, rbt->root == pivot);
rbt->root = z;
}
z->child[cid2] = pivot;
if (!IS_NIL(rbt,pivot)) pivot->parent = z;
pivot->child[cid1] = c;
if (!IS_NIL(rbt,c)) c->parent = pivot;
}
static void adjust (moo_rbt_t* rbt, moo_rbt_pair_t* pair)
{
while (pair != rbt->root)
{
moo_rbt_pair_t* tmp, * tmp2, * x_par;
int leftwise;
x_par = pair->parent;
if (x_par->color == MOO_RBT_BLACK) break;
MOO_ASSERT (rbt->moo, x_par->parent != MOO_NULL);
if (x_par == x_par->parent->child[LEFT])
{
tmp = x_par->parent->child[RIGHT];
tmp2 = x_par->child[RIGHT];
leftwise = 1;
}
else
{
tmp = x_par->parent->child[LEFT];
tmp2 = x_par->child[LEFT];
leftwise = 0;
}
if (tmp->color == MOO_RBT_RED)
{
x_par->color = MOO_RBT_BLACK;
tmp->color = MOO_RBT_BLACK;
x_par->parent->color = MOO_RBT_RED;
pair = x_par->parent;
}
else
{
if (pair == tmp2)
{
pair = x_par;
rotate (rbt, pair, leftwise);
x_par = pair->parent;
}
x_par->color = MOO_RBT_BLACK;
x_par->parent->color = MOO_RBT_RED;
rotate (rbt, x_par->parent, !leftwise);
}
}
}
static moo_rbt_pair_t* change_pair_val (
moo_rbt_t* rbt, moo_rbt_pair_t* pair, void* vptr, moo_oow_t vlen)
{
if (VPTR(pair) == vptr && VLEN(pair) == vlen)
{
/* if the old value and the new value are the same,
* it just calls the handler for this condition.
* No value replacement occurs. */
if (rbt->style->keeper != MOO_NULL)
{
rbt->style->keeper (rbt, vptr, vlen);
}
}
else
{
copier_t vcop = rbt->style->copier[MOO_RBT_VAL];
void* ovptr = VPTR(pair);
moo_oow_t ovlen = VLEN(pair);
/* place the new value according to the copier */
if (vcop == MOO_RBT_COPIER_SIMPLE)
{
VPTR(pair) = vptr;
VLEN(pair) = vlen;
}
else if (vcop == MOO_RBT_COPIER_INLINE)
{
if (ovlen == vlen)
{
if (vptr) MOO_MEMCPY (VPTR(pair), vptr, VTOB(rbt,vlen));
}
else
{
/* need to reconstruct the pair */
moo_rbt_pair_t* p = moo_rbt_allocpair (rbt,
KPTR(pair), KLEN(pair),
vptr, vlen);
if (p == MOO_NULL) return MOO_NULL;
p->color = pair->color;
p->left = pair->left;
p->right = pair->right;
p->parent = pair->parent;
if (pair->parent)
{
if (pair->parent->left == pair)
{
pair->parent->left = p;
}
else
{
MOO_ASSERT (rbt->moo, pair->parent->right == pair);
pair->parent->right = p;
}
}
if (!IS_NIL(rbt,pair->left)) pair->left->parent = p;
if (!IS_NIL(rbt,pair->right)) pair->right->parent = p;
if (pair == rbt->root) rbt->root = p;
moo_rbt_freepair (rbt, pair);
return p;
}
}
else
{
void* nvptr = vcop (rbt, vptr, vlen);
if (nvptr == MOO_NULL) return MOO_NULL;
VPTR(pair) = nvptr;
VLEN(pair) = vlen;
}
/* free up the old value */
if (rbt->style->freeer[MOO_RBT_VAL] != MOO_NULL)
{
rbt->style->freeer[MOO_RBT_VAL] (rbt, ovptr, ovlen);
}
}
return pair;
}
static moo_rbt_pair_t* insert (
moo_rbt_t* rbt, void* kptr, moo_oow_t klen, void* vptr, moo_oow_t vlen, int opt)
{
moo_rbt_pair_t* x_cur = rbt->root;
moo_rbt_pair_t* x_par = MOO_NULL;
moo_rbt_pair_t* x_new;
while (!IS_NIL(rbt,x_cur))
{
int n = rbt->style->comper (rbt, kptr, klen, KPTR(x_cur), KLEN(x_cur));
if (n == 0)
{
switch (opt)
{
case UPSERT:
case UPDATE:
return change_pair_val (rbt, x_cur, vptr, vlen);
case ENSERT:
/* return existing pair */
return x_cur;
case INSERT:
/* return failure */
return MOO_NULL;
}
}
x_par = x_cur;
if (n > 0) x_cur = x_cur->right;
else /* if (n < 0) */ x_cur = x_cur->left;
}
if (opt == UPDATE) return MOO_NULL;
x_new = moo_rbt_allocpair (rbt, kptr, klen, vptr, vlen);
if (x_new == MOO_NULL) return MOO_NULL;
if (x_par == MOO_NULL)
{
/* the tree contains no pair */
MOO_ASSERT (rbt->moo, rbt->root == &rbt->xnil);
rbt->root = x_new;
}
else
{
/* perform normal binary insert */
int n = rbt->style->comper (rbt, kptr, klen, KPTR(x_par), KLEN(x_par));
if (n > 0)
{
MOO_ASSERT (rbt->moo, x_par->right == &rbt->xnil);
x_par->right = x_new;
}
else
{
MOO_ASSERT (rbt->moo, x_par->left == &rbt->xnil);
x_par->left = x_new;
}
x_new->parent = x_par;
adjust (rbt, x_new);
}
rbt->root->color = MOO_RBT_BLACK;
rbt->size++;
return x_new;
}
moo_rbt_pair_t* moo_rbt_upsert (
moo_rbt_t* rbt, void* kptr, moo_oow_t klen, void* vptr, moo_oow_t vlen)
{
return insert (rbt, kptr, klen, vptr, vlen, UPSERT);
}
moo_rbt_pair_t* moo_rbt_ensert (
moo_rbt_t* rbt, void* kptr, moo_oow_t klen, void* vptr, moo_oow_t vlen)
{
return insert (rbt, kptr, klen, vptr, vlen, ENSERT);
}
moo_rbt_pair_t* moo_rbt_insert (
moo_rbt_t* rbt, void* kptr, moo_oow_t klen, void* vptr, moo_oow_t vlen)
{
return insert (rbt, kptr, klen, vptr, vlen, INSERT);
}
moo_rbt_pair_t* moo_rbt_update (
moo_rbt_t* rbt, void* kptr, moo_oow_t klen, void* vptr, moo_oow_t vlen)
{
return insert (rbt, kptr, klen, vptr, vlen, UPDATE);
}
moo_rbt_pair_t* moo_rbt_cbsert (
moo_rbt_t* rbt, void* kptr, moo_oow_t klen, cbserter_t cbserter, void* ctx)
{
moo_rbt_pair_t* x_cur = rbt->root;
moo_rbt_pair_t* x_par = MOO_NULL;
moo_rbt_pair_t* x_new;
while (!IS_NIL(rbt,x_cur))
{
int n = rbt->style->comper (rbt, kptr, klen, KPTR(x_cur), KLEN(x_cur));
if (n == 0)
{
/* back up the contents of the current pair
* in case it is reallocated */
moo_rbt_pair_t tmp;
tmp = *x_cur;
/* call the callback function to manipulate the pair */
x_new = cbserter (rbt, x_cur, kptr, klen, ctx);
if (x_new == MOO_NULL)
{
/* error returned by the callback function */
return MOO_NULL;
}
if (x_new != x_cur)
{
/* the current pair has been reallocated, which implicitly
* means the previous contents were wiped out. so the contents
* backed up will be used for restoration/migration */
x_new->color = tmp.color;
x_new->left = tmp.left;
x_new->right = tmp.right;
x_new->parent = tmp.parent;
if (tmp.parent)
{
if (tmp.parent->left == x_cur)
{
tmp.parent->left = x_new;
}
else
{
MOO_ASSERT (rbt->moo, tmp.parent->right == x_cur);
tmp.parent->right = x_new;
}
}
if (!IS_NIL(rbt,tmp.left)) tmp.left->parent = x_new;
if (!IS_NIL(rbt,tmp.right)) tmp.right->parent = x_new;
if (x_cur == rbt->root) rbt->root = x_new;
}
return x_new;
}
x_par = x_cur;
if (n > 0) x_cur = x_cur->right;
else /* if (n < 0) */ x_cur = x_cur->left;
}
x_new = cbserter (rbt, MOO_NULL, kptr, klen, ctx);
if (x_new == MOO_NULL) return MOO_NULL;
if (x_par == MOO_NULL)
{
/* the tree contains no pair */
MOO_ASSERT (rbt->moo, rbt->root == &rbt->xnil);
rbt->root = x_new;
}
else
{
/* perform normal binary insert */
int n = rbt->style->comper (rbt, kptr, klen, KPTR(x_par), KLEN(x_par));
if (n > 0)
{
MOO_ASSERT (rbt->moo, x_par->right == &rbt->xnil);
x_par->right = x_new;
}
else
{
MOO_ASSERT (rbt->moo, x_par->left == &rbt->xnil);
x_par->left = x_new;
}
x_new->parent = x_par;
adjust (rbt, x_new);
}
rbt->root->color = MOO_RBT_BLACK;
rbt->size++;
return x_new;
}
static void adjust_for_delete (moo_rbt_t* rbt, moo_rbt_pair_t* pair, moo_rbt_pair_t* par)
{
while (pair != rbt->root && pair->color == MOO_RBT_BLACK)
{
moo_rbt_pair_t* tmp;
if (pair == par->left)
{
tmp = par->right;
if (tmp->color == MOO_RBT_RED)
{
tmp->color = MOO_RBT_BLACK;
par->color = MOO_RBT_RED;
rotate_left (rbt, par);
tmp = par->right;
}
if (tmp->left->color == MOO_RBT_BLACK &&
tmp->right->color == MOO_RBT_BLACK)
{
if (!IS_NIL(rbt,tmp)) tmp->color = MOO_RBT_RED;
pair = par;
par = pair->parent;
}
else
{
if (tmp->right->color == MOO_RBT_BLACK)
{
if (!IS_NIL(rbt,tmp->left))
tmp->left->color = MOO_RBT_BLACK;
tmp->color = MOO_RBT_RED;
rotate_right (rbt, tmp);
tmp = par->right;
}
tmp->color = par->color;
if (!IS_NIL(rbt,par)) par->color = MOO_RBT_BLACK;
if (tmp->right->color == MOO_RBT_RED)
tmp->right->color = MOO_RBT_BLACK;
rotate_left (rbt, par);
pair = rbt->root;
}
}
else
{
MOO_ASSERT (rbt->moo, pair == par->right);
tmp = par->left;
if (tmp->color == MOO_RBT_RED)
{
tmp->color = MOO_RBT_BLACK;
par->color = MOO_RBT_RED;
rotate_right (rbt, par);
tmp = par->left;
}
if (tmp->left->color == MOO_RBT_BLACK &&
tmp->right->color == MOO_RBT_BLACK)
{
if (!IS_NIL(rbt,tmp)) tmp->color = MOO_RBT_RED;
pair = par;
par = pair->parent;
}
else
{
if (tmp->left->color == MOO_RBT_BLACK)
{
if (!IS_NIL(rbt,tmp->right))
tmp->right->color = MOO_RBT_BLACK;
tmp->color = MOO_RBT_RED;
rotate_left (rbt, tmp);
tmp = par->left;
}
tmp->color = par->color;
if (!IS_NIL(rbt,par)) par->color = MOO_RBT_BLACK;
if (tmp->left->color == MOO_RBT_RED)
tmp->left->color = MOO_RBT_BLACK;
rotate_right (rbt, par);
pair = rbt->root;
}
}
}
pair->color = MOO_RBT_BLACK;
}
static void delete_pair (moo_rbt_t* rbt, moo_rbt_pair_t* pair)
{
moo_rbt_pair_t* x, * y, * par;
MOO_ASSERT (rbt->moo, pair && !IS_NIL(rbt,pair));
if (IS_NIL(rbt,pair->left) || IS_NIL(rbt,pair->right))
{
y = pair;
}
else
{
/* find a successor with NIL as a child */
y = pair->right;
while (!IS_NIL(rbt,y->left)) y = y->left;
}
x = IS_NIL(rbt,y->left)? y->right: y->left;
par = y->parent;
if (!IS_NIL(rbt,x)) x->parent = par;
if (par)
{
if (y == par->left)
par->left = x;
else
par->right = x;
}
else
{
rbt->root = x;
}
if (y == pair)
{
if (y->color == MOO_RBT_BLACK && !IS_NIL(rbt,x))
adjust_for_delete (rbt, x, par);
moo_rbt_freepair (rbt, y);
}
else
{
if (y->color == MOO_RBT_BLACK && !IS_NIL(rbt,x))
adjust_for_delete (rbt, x, par);
#if 1
if (pair->parent)
{
if (pair->parent->left == pair) pair->parent->left = y;
if (pair->parent->right == pair) pair->parent->right = y;
}
else
{
rbt->root = y;
}
y->parent = pair->parent;
y->left = pair->left;
y->right = pair->right;
y->color = pair->color;
if (pair->left->parent == pair) pair->left->parent = y;
if (pair->right->parent == pair) pair->right->parent = y;
#else
*y = *pair;
if (y->parent)
{
if (y->parent->left == pair) y->parent->left = y;
if (y->parent->right == pair) y->parent->right = y;
}
else
{
rbt->root = y;
}
if (y->left->parent == pair) y->left->parent = y;
if (y->right->parent == pair) y->right->parent = y;
#endif
moo_rbt_freepair (rbt, pair);
}
rbt->size--;
}
int moo_rbt_delete (moo_rbt_t* rbt, const void* kptr, moo_oow_t klen)
{
moo_rbt_pair_t* pair;
pair = moo_rbt_search (rbt, kptr, klen);
if (pair == MOO_NULL) return -1;
delete_pair (rbt, pair);
return 0;
}
void moo_rbt_clear (moo_rbt_t* rbt)
{
/* TODO: improve this */
while (!IS_NIL(rbt,rbt->root)) delete_pair (rbt, rbt->root);
}
#if 0
static MOO_INLINE moo_rbt_walk_t walk_recursively (
moo_rbt_t* rbt, walker_t walker, void* ctx, moo_rbt_pair_t* pair)
{
if (!IS_NIL(rbt,pair->left))
{
if (walk_recursively (rbt, walker, ctx, pair->left) == MOO_RBT_WALK_STOP)
return MOO_RBT_WALK_STOP;
}
if (walker (rbt, pair, ctx) == MOO_RBT_WALK_STOP) return MOO_RBT_WALK_STOP;
if (!IS_NIL(rbt,pair->right))
{
if (walk_recursively (rbt, walker, ctx, pair->right) == MOO_RBT_WALK_STOP)
return MOO_RBT_WALK_STOP;
}
return MOO_RBT_WALK_FORWARD;
}
#endif
static MOO_INLINE void walk (moo_rbt_t* rbt, walker_t walker, void* ctx, int l, int r)
{
moo_rbt_pair_t* x_cur = rbt->root;
moo_rbt_pair_t* prev = rbt->root->parent;
while (x_cur && !IS_NIL(rbt,x_cur))
{
if (prev == x_cur->parent)
{
/* the previous node is the parent of the current node.
* it indicates that we're going down to the child[l] */
if (!IS_NIL(rbt,x_cur->child[l]))
{
/* go to the child[l] child */
prev = x_cur;
x_cur = x_cur->child[l];
}
else
{
if (walker (rbt, x_cur, ctx) == MOO_RBT_WALK_STOP) break;
if (!IS_NIL(rbt,x_cur->child[r]))
{
/* go down to the right node if exists */
prev = x_cur;
x_cur = x_cur->child[r];
}
else
{
/* otherwise, move up to the parent */
prev = x_cur;
x_cur = x_cur->parent;
}
}
}
else if (prev == x_cur->child[l])
{
/* the left child has been already traversed */
if (walker (rbt, x_cur, ctx) == MOO_RBT_WALK_STOP) break;
if (!IS_NIL(rbt,x_cur->child[r]))
{
/* go down to the right node if it exists */
prev = x_cur;
x_cur = x_cur->child[r];
}
else
{
/* otherwise, move up to the parent */
prev = x_cur;
x_cur = x_cur->parent;
}
}
else
{
/* both the left child and the right child have been traversed */
MOO_ASSERT (rbt->moo, prev == x_cur->child[r]);
/* just move up to the parent */
prev = x_cur;
x_cur = x_cur->parent;
}
}
}
void moo_rbt_walk (moo_rbt_t* rbt, walker_t walker, void* ctx)
{
walk (rbt, walker, ctx, LEFT, RIGHT);
}
void moo_rbt_rwalk (moo_rbt_t* rbt, walker_t walker, void* ctx)
{
walk (rbt, walker, ctx, RIGHT, LEFT);
}
int moo_rbt_dflcomp (const moo_rbt_t* rbt, const void* kptr1, moo_oow_t klen1, const void* kptr2, moo_oow_t klen2)
{
moo_oow_t min;
int n, nn;
if (klen1 < klen2)
{
min = klen1;
nn = -1;
}
else
{
min = klen2;
nn = (klen1 == klen2)? 0: 1;
}
n = MOO_MEMCMP (kptr1, kptr2, KTOB(rbt,min));
if (n == 0) n = nn;
return n;
}

186
moo/lib/sym.c Normal file
View File

@ -0,0 +1,186 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
static moo_oop_oop_t expand_bucket (moo_t* moo, moo_oop_oop_t oldbuc)
{
moo_oop_oop_t newbuc;
moo_oow_t oldsz, newsz, index;
moo_oop_char_t symbol;
oldsz = MOO_OBJ_GET_SIZE(oldbuc);
/* TODO: better growth policy? */
if (oldsz < 5000) newsz = oldsz + oldsz;
else if (oldsz < 50000) newsz = oldsz + (oldsz / 2);
else if (oldsz < 100000) newsz = oldsz + (oldsz / 4);
else if (oldsz < 200000) newsz = oldsz + (oldsz / 8);
else if (oldsz < 400000) newsz = oldsz + (oldsz / 16);
else if (oldsz < 800000) newsz = oldsz + (oldsz / 32);
else if (oldsz < 1600000) newsz = oldsz + (oldsz / 64);
else
{
moo_oow_t inc, inc_max;
inc = oldsz / 128;
inc_max = MOO_OBJ_SIZE_MAX - oldsz;
if (inc > inc_max)
{
if (inc_max > 0) inc = inc_max;
else
{
moo->errnum = MOO_EOOMEM;
return MOO_NULL;
}
}
newsz = oldsz + inc;
}
moo_pushtmp (moo, (moo_oop_t*)&oldbuc);
newbuc = (moo_oop_oop_t)moo_instantiate (moo, moo->_array, MOO_NULL, newsz);
moo_poptmp (moo);
if (!newbuc) return MOO_NULL;
while (oldsz > 0)
{
symbol = (moo_oop_char_t)oldbuc->slot[--oldsz];
if ((moo_oop_t)symbol != moo->_nil)
{
MOO_ASSERT (moo, MOO_CLASSOF(moo,symbol) == moo->_symbol);
/*MOO_ASSERT (moo, sym->size > 0);*/
index = moo_hashoochars(symbol->slot, MOO_OBJ_GET_SIZE(symbol)) % newsz;
while (newbuc->slot[index] != moo->_nil) index = (index + 1) % newsz;
newbuc->slot[index] = (moo_oop_t)symbol;
}
}
return newbuc;
}
static moo_oop_t find_or_make_symbol (moo_t* moo, const moo_ooch_t* ptr, moo_oow_t len, int create)
{
moo_ooi_t tally;
moo_oow_t index;
moo_oop_char_t symbol;
MOO_ASSERT (moo, len > 0);
if (len <= 0)
{
/* i don't allow an empty symbol name */
moo->errnum = MOO_EINVAL;
return MOO_NULL;
}
MOO_ASSERT (moo, MOO_CLASSOF(moo,moo->symtab->bucket) == moo->_array);
index = moo_hashoochars(ptr, len) % MOO_OBJ_GET_SIZE(moo->symtab->bucket);
/* find a matching symbol in the open-addressed symbol table */
while (moo->symtab->bucket->slot[index] != moo->_nil)
{
symbol = (moo_oop_char_t)moo->symtab->bucket->slot[index];
MOO_ASSERT (moo, MOO_CLASSOF(moo,symbol) == (moo_oop_t)moo->_symbol);
if (len == MOO_OBJ_GET_SIZE(symbol) &&
moo_equaloochars (ptr, symbol->slot, len))
{
return (moo_oop_t)symbol;
}
index = (index + 1) % MOO_OBJ_GET_SIZE(moo->symtab->bucket);
}
if (!create)
{
moo->errnum = MOO_ENOENT;
return MOO_NULL;
}
/* make a new symbol and insert it */
MOO_ASSERT (moo, MOO_OOP_IS_SMOOI(moo->symtab->tally));
tally = MOO_OOP_TO_SMOOI(moo->symtab->tally);
if (tally >= MOO_SMOOI_MAX)
{
/* this built-in table is not allowed to hold more than
* MOO_SMOOI_MAX items for efficiency sake */
moo->errnum = MOO_EDFULL;
return MOO_NULL;
}
/* no conversion to moo_oow_t is necessary for tally + 1.
* the maximum value of tally is checked to be MOO_SMOOI_MAX - 1.
* tally + 1 can produce at most MOO_SMOOI_MAX. above all,
* MOO_SMOOI_MAX is way smaller than MOO_TYPE_MAX(moo_ooi_t). */
if (tally + 1 >= MOO_OBJ_GET_SIZE(moo->symtab->bucket))
{
moo_oop_oop_t bucket;
/* TODO: make the growth policy configurable instead of growing
it just before it gets full. The polcy can be grow it
if it's 70% full */
/* enlarge the symbol table before it gets full to
* make sure that it has at least one free slot left
* after having added a new symbol. this is to help
* traversal end at a _nil slot if no entry is found. */
bucket = expand_bucket(moo, moo->symtab->bucket);
if (!bucket) return MOO_NULL;
moo->symtab->bucket = bucket;
/* recalculate the index for the expanded bucket */
index = moo_hashoochars(ptr, len) % MOO_OBJ_GET_SIZE(moo->symtab->bucket);
while (moo->symtab->bucket->slot[index] != moo->_nil)
index = (index + 1) % MOO_OBJ_GET_SIZE(moo->symtab->bucket);
}
/* create a new symbol since it isn't found in the symbol table */
symbol = (moo_oop_char_t)moo_instantiate(moo, moo->_symbol, ptr, len);
if (symbol)
{
MOO_ASSERT (moo, tally < MOO_SMOOI_MAX);
moo->symtab->tally = MOO_SMOOI_TO_OOP(tally + 1);
moo->symtab->bucket->slot[index] = (moo_oop_t)symbol;
}
return (moo_oop_t)symbol;
}
moo_oop_t moo_makesymbol (moo_t* moo, const moo_ooch_t* ptr, moo_oow_t len)
{
return find_or_make_symbol (moo, ptr, len, 1);
}
moo_oop_t moo_findsymbol (moo_t* moo, const moo_ooch_t* ptr, moo_oow_t len)
{
return find_or_make_symbol (moo, ptr, len, 0);
}
moo_oop_t moo_makestring (moo_t* moo, const moo_ooch_t* ptr, moo_oow_t len)
{
return moo_instantiate (moo, moo->_string, ptr, len);
}

73
moo/lib/syntax.txt Normal file
View File

@ -0,0 +1,73 @@
literal := number-literal | string-literal | character-literal | symbol-literal
string-literal := single-quote string-character* single-quote
string-character := normal-character | (single-quote single-quote)
single-quote := "'"
normal-character := character-except-single-quote
character-literal := "$" character
character := normal-character | "'"
symbol-literal := "#" symbol-body
symbol-body := identifier | keyword+ | binary-selector | string
unary-selector := identifier
binary-selector := binary-selector-character+
binary-selector-character := "+" | "/" | "\" | ...
selector-argument := identifier
identifier := alpha-char (alpha-char | digit-char)*
keyword := identifier ":"
class-definition := #class class-modifier? "{" class-body "}"
class-modifier := "(" (#byte | #character | #word | #pointer)? ")"
class-body := variable-definition* method-definition*
variable-definition := (#dcl | #declare) variable-modifier? variable-list "."
variable-modifier := "(" (#class | #classinst)? ")"
variable-list := identifier*
method-definition := #method method-modifier? method-actual-definition
method-modifier := "(" (#class | #instance) ")"
method-actual-definition := method-name "{" method-tempraries? method-primitive? method-statements* "}"
method-name := unary-method-name | binary-method-name | keyword-method-name
unary-method-name := unary-selector
binary-method-name := binary-selector selector-argument
keyword-method-name := (keyword selector-argument)+
method-temporaries := "|" variable-list "|"
method-primitive := "<" "primitive:" integer ">"
method-statements := method-statement ("." | ("." method-statements))*
method-statement := method-return-statement | method-expression
method-return-statement := "^" method-expression
method-expression := method-assignment-expression | basic-expression
method-assignment-expression := identifier ":=" method-expression
basic-expression := expression-primary (message-expression cascaded-message-expression)?
expression-primary := identifier | literal | block-constructor | ( "(" method-expression ")" )
----------------------------------------------------------
message-expression := (unary-message-expression+ binary-message-expresson* keyword-message-expression?) |
(binary-message-expression+ keyword-message-expression?) |
keyword-message-expression
cascaded-message-expression := (";" message-expression)*
keyword-message-expression := (keyword keyword-argument)+
keyword-argument := expression-primary unary-selector* binary-message-expression*
binary-message-expression := binary-selector binary-argument
binary-argument := expression-primary unary-selector*
------------------------------------------------------------
#include '....'.
#class Test(Object)
{
}
#main

178
moo/lib/utf8.c Normal file
View File

@ -0,0 +1,178 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
/*
* from RFC 2279 UTF-8, a transformation format of ISO 10646
*
* UCS-4 range (hex.) UTF-8 octet sequence (binary)
* 1:2 00000000-0000007F 0xxxxxxx
* 2:2 00000080-000007FF 110xxxxx 10xxxxxx
* 3:2 00000800-0000FFFF 1110xxxx 10xxxxxx 10xxxxxx
* 4:4 00010000-001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
* inv 00200000-03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
* inv 04000000-7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
struct __utf8_t
{
moo_uint32_t lower;
moo_uint32_t upper;
moo_uint8_t fbyte; /* mask to the first utf8 byte */
moo_uint8_t mask;
moo_uint8_t fmask;
int length; /* number of bytes */
};
typedef struct __utf8_t __utf8_t;
static __utf8_t utf8_table[] =
{
{0x00000000ul, 0x0000007Ful, 0x00, 0x80, 0x7F, 1},
{0x00000080ul, 0x000007FFul, 0xC0, 0xE0, 0x1F, 2},
{0x00000800ul, 0x0000FFFFul, 0xE0, 0xF0, 0x0F, 3},
{0x00010000ul, 0x001FFFFFul, 0xF0, 0xF8, 0x07, 4},
{0x00200000ul, 0x03FFFFFFul, 0xF8, 0xFC, 0x03, 5},
{0x04000000ul, 0x7FFFFFFFul, 0xFC, 0xFE, 0x01, 6}
};
static MOO_INLINE __utf8_t* get_utf8_slot (moo_uch_t uc)
{
__utf8_t* cur, * end;
/*MOO_ASSERT (moo, MOO_SIZEOF(moo_bch_t) == 1);
MOO_ASSERT (moo, MOO_SIZEOF(moo_uch_t) >= 2);*/
end = utf8_table + MOO_COUNTOF(utf8_table);
cur = utf8_table;
while (cur < end)
{
if (uc >= cur->lower && uc <= cur->upper) return cur;
cur++;
}
return MOO_NULL; /* invalid character */
}
moo_oow_t moo_uctoutf8 (moo_uch_t uc, moo_bch_t* utf8, moo_oow_t size)
{
__utf8_t* cur = get_utf8_slot (uc);
if (cur == MOO_NULL) return 0; /* illegal character */
if (utf8 && cur->length <= size)
{
int index = cur->length;
while (index > 1)
{
/*
* 0x3F: 00111111
* 0x80: 10000000
*/
utf8[--index] = (uc & 0x3F) | 0x80;
uc >>= 6;
}
utf8[0] = uc | cur->fbyte;
}
/* small buffer is also indicated by this return value
* greater than 'size'. */
return (moo_oow_t)cur->length;
}
moo_oow_t moo_utf8touc (const moo_bch_t* utf8, moo_oow_t size, moo_uch_t* uc)
{
__utf8_t* cur, * end;
/*MOO_ASSERT (moo, utf8 != MOO_NULL);
MOO_ASSERT (moo, size > 0);
MOO_ASSERT (moo, MOO_SIZEOF(moo_bch_t) == 1);
MOO_ASSERT (moo, MOO_SIZEOF(moo_uch_t) >= 2);*/
end = utf8_table + MOO_COUNTOF(utf8_table);
cur = utf8_table;
while (cur < end)
{
if ((utf8[0] & cur->mask) == cur->fbyte)
{
/* if size is less that cur->length, the incomplete-seqeunce
* error is naturally indicated. so validate the string
* only if size is as large as cur->length. */
if (size >= cur->length)
{
int i;
if (uc)
{
moo_uch_t w;
w = utf8[0] & cur->fmask;
for (i = 1; i < cur->length; i++)
{
/* in utf8, trailing bytes are all
* set with 0x80.
*
* 10XXXXXX & 11000000 => 10000000
*
* if not, invalid. */
if ((utf8[i] & 0xC0) != 0x80) return 0;
w = (w << 6) | (utf8[i] & 0x3F);
}
*uc = w;
}
else
{
for (i = 1; i < cur->length; i++)
{
/* in utf8, trailing bytes are all
* set with 0x80.
*
* 10XXXXXX & 11000000 => 10000000
*
* if not, invalid. */
if ((utf8[i] & 0xC0) != 0x80) return 0;
}
}
}
/* this return value can indicate both
* the correct length (size >= cur->length)
* and
* the incomplete seqeunce error (size < cur->length).
*/
return (moo_oow_t)cur->length;
}
cur++;
}
return 0; /* error - invalid sequence */
}

647
moo/lib/utl.c Normal file
View File

@ -0,0 +1,647 @@
/*
* $Id$
*
Copyright (c) 2014-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "moo-prv.h"
#define MOO_BCLEN_MAX 6
/* some naming conventions
* bchars, uchars -> pointer and length
* bcstr, ucstr -> null-terminated string pointer
* btouchars -> bchars to uchars
* utobchars -> uchars to bchars
* btoucstr -> bcstr to ucstr
* utobcstr -> ucstr to bcstr
*/
moo_oow_t moo_hashbytes (const moo_oob_t* ptr, moo_oow_t len)
{
moo_oow_t h = 0;
const moo_uint8_t* bp, * be;
bp = ptr; be = bp + len;
while (bp < be) h = h * 31 + *bp++;
/* constrain the hash value to be representable in a small integer
* for convenience sake */
return h % ((moo_oow_t)MOO_SMOOI_MAX + 1);
}
int moo_equaluchars (const moo_uch_t* str1, const moo_uch_t* str2, moo_oow_t len)
{
moo_oow_t i;
for (i = 0; i < len; i++)
{
if (str1[i] != str2[i]) return 0;
}
return 1;
}
int moo_equalbchars (const moo_bch_t* str1, const moo_bch_t* str2, moo_oow_t len)
{
moo_oow_t i;
for (i = 0; i < len; i++)
{
if (str1[i] != str2[i]) return 0;
}
return 1;
}
int moo_compucstr (const moo_uch_t* str1, const moo_uch_t* str2)
{
while (*str1 == *str2)
{
if (*str1 == '\0') return 0;
str1++, str2++;
}
return (*str1 > *str2)? 1: -1;
}
int moo_compbcstr (const moo_bch_t* str1, const moo_bch_t* str2)
{
while (*str1 == *str2)
{
if (*str1 == '\0') return 0;
str1++, str2++;
}
return (*str1 > *str2)? 1: -1;
}
int moo_compucbcstr (const moo_uch_t* str1, const moo_bch_t* str2)
{
while (*str1 == *str2)
{
if (*str1 == '\0') return 0;
str1++, str2++;
}
return (*str1 > *str2)? 1: -1;
}
int moo_compucharsbcstr (const moo_uch_t* str1, moo_oow_t len, const moo_bch_t* str2)
{
const moo_uch_t* end = str1 + len;
while (str1 < end && *str2 != '\0' && *str1 == *str2) str1++, str2++;
if (str1 == end && *str2 == '\0') return 0;
if (*str1 == *str2) return (str1 < end)? 1: -1;
return (*str1 > *str2)? 1: -1;
}
int moo_compbcharsbcstr (const moo_bch_t* str1, moo_oow_t len, const moo_bch_t* str2)
{
const moo_bch_t* end = str1 + len;
while (str1 < end && *str2 != '\0' && *str1 == *str2) str1++, str2++;
if (str1 == end && *str2 == '\0') return 0;
if (*str1 == *str2) return (str1 < end)? 1: -1;
return (*str1 > *str2)? 1: -1;
}
void moo_copyuchars (moo_uch_t* dst, const moo_uch_t* src, moo_oow_t len)
{
moo_oow_t i;
for (i = 0; i < len; i++) dst[i] = src[i];
}
void moo_copybchars (moo_bch_t* dst, const moo_bch_t* src, moo_oow_t len)
{
moo_oow_t i;
for (i = 0; i < len; i++) dst[i] = src[i];
}
void moo_copybtouchars (moo_uch_t* dst, const moo_bch_t* src, moo_oow_t len)
{
/* copy without conversions.
* use moo_bctouchars() for conversion encoding */
moo_oow_t i;
for (i = 0; i < len; i++) dst[i] = src[i];
}
moo_oow_t moo_copyucstr (moo_uch_t* dst, moo_oow_t len, const moo_uch_t* src)
{
moo_uch_t* p, * p2;
p = dst; p2 = dst + len - 1;
while (p < p2)
{
if (*src == '\0') break;
*p++ = *src++;
}
if (len > 0) *p = '\0';
return p - dst;
}
moo_oow_t moo_copybcstr (moo_bch_t* dst, moo_oow_t len, const moo_bch_t* src)
{
moo_bch_t* p, * p2;
p = dst; p2 = dst + len - 1;
while (p < p2)
{
if (*src == '\0') break;
*p++ = *src++;
}
if (len > 0) *p = '\0';
return p - dst;
}
moo_oow_t moo_countucstr (const moo_uch_t* str)
{
const moo_uch_t* ptr = str;
while (*ptr != '\0') ptr++;
return ptr - str;
}
moo_oow_t moo_countbcstr (const moo_bch_t* str)
{
const moo_bch_t* ptr = str;
while (*ptr != '\0') ptr++;
return ptr - str;
}
moo_uch_t* moo_finduchar (const moo_uch_t* ptr, moo_oow_t len, moo_uch_t c)
{
const moo_uch_t* end;
end = ptr + len;
while (ptr < end)
{
if (*ptr == c) return (moo_uch_t*)ptr;
ptr++;
}
return MOO_NULL;
}
moo_bch_t* moo_findbchar (const moo_bch_t* ptr, moo_oow_t len, moo_bch_t c)
{
const moo_bch_t* end;
end = ptr + len;
while (ptr < end)
{
if (*ptr == c) return (moo_bch_t*)ptr;
ptr++;
}
return MOO_NULL;
}
moo_uch_t* moo_rfinduchar (const moo_uch_t* ptr, moo_oow_t len, moo_uch_t c)
{
const moo_uch_t* cur;
cur = ptr + len;
while (cur > ptr)
{
--cur;
if (*cur == c) return (moo_uch_t*)cur;
}
return MOO_NULL;
}
moo_bch_t* moo_rfindbchar (const moo_bch_t* ptr, moo_oow_t len, moo_bch_t c)
{
const moo_bch_t* cur;
cur = ptr + len;
while (cur > ptr)
{
--cur;
if (*cur == c) return (moo_bch_t*)cur;
}
return MOO_NULL;
}
/* ----------------------------------------------------------------------- */
int moo_concatoocstrtosbuf (moo_t* moo, const moo_ooch_t* str, int id)
{
moo_sbuf_t* p;
moo_oow_t len;
p = &moo->sbuf[id];
len = moo_countoocstr (str);
if (len > p->capa - p->len)
{
moo_oow_t newcapa;
moo_ooch_t* tmp;
newcapa = MOO_ALIGN(p->len + len, 512); /* TODO: adjust this capacity */
/* +1 to handle line ending injection more easily */
tmp = moo_reallocmem (moo, p->ptr, (newcapa + 1) * MOO_SIZEOF(*tmp));
if (!tmp) return -1;
p->ptr = tmp;
p->capa = newcapa;
}
moo_copyoochars (&p->ptr[p->len], str, len);
p->len += len;
p->ptr[p->len] = '\0';
return 0;
}
int moo_copyoocstrtosbuf (moo_t* moo, const moo_ooch_t* str, int id)
{
moo->sbuf[id].len = 0;;
return moo_concatoocstrtosbuf (moo, str, id);
}
/* ----------------------------------------------------------------------- */
static MOO_INLINE int bcsn_to_ucsn_with_cmgr (
const moo_bch_t* bcs, moo_oow_t* bcslen,
moo_uch_t* ucs, moo_oow_t* ucslen, moo_cmgr_t* cmgr, int all)
{
const moo_bch_t* p;
int ret = 0;
moo_oow_t mlen;
if (ucs)
{
/* destination buffer is specified.
* copy the conversion result to the buffer */
moo_uch_t* q, * qend;
p = bcs;
q = ucs;
qend = ucs + *ucslen;
mlen = *bcslen;
while (mlen > 0)
{
moo_oow_t n;
if (q >= qend)
{
/* buffer too small */
ret = -2;
break;
}
n = cmgr->bctouc (p, mlen, q);
if (n == 0)
{
/* invalid sequence */
if (all)
{
n = 1;
*q = '?';
}
else
{
ret = -1;
break;
}
}
if (n > mlen)
{
/* incomplete sequence */
if (all)
{
n = 1;
*q = '?';
}
else
{
ret = -3;
break;
}
}
q++;
p += n;
mlen -= n;
}
*ucslen = q - ucs;
*bcslen = p - bcs;
}
else
{
/* no destination buffer is specified. perform conversion
* but don't copy the result. the caller can call this function
* without a buffer to find the required buffer size, allocate
* a buffer with the size and call this function again with
* the buffer. */
moo_uch_t w;
moo_oow_t wlen = 0;
p = bcs;
mlen = *bcslen;
while (mlen > 0)
{
moo_oow_t n;
n = cmgr->bctouc (p, mlen, &w);
if (n == 0)
{
/* invalid sequence */
if (all) n = 1;
else
{
ret = -1;
break;
}
}
if (n > mlen)
{
/* incomplete sequence */
if (all) n = 1;
else
{
ret = -3;
break;
}
}
p += n;
mlen -= n;
wlen += 1;
}
*ucslen = wlen;
*bcslen = p - bcs;
}
return ret;
}
static MOO_INLINE int bcs_to_ucs_with_cmgr (
const moo_bch_t* bcs, moo_oow_t* bcslen,
moo_uch_t* ucs, moo_oow_t* ucslen, moo_cmgr_t* cmgr, int all)
{
const moo_bch_t* bp;
moo_oow_t mlen, wlen;
int n;
for (bp = bcs; *bp != '\0'; bp++) /* nothing */ ;
mlen = bp - bcs; wlen = *ucslen;
n = bcsn_to_ucsn_with_cmgr (bcs, &mlen, ucs, &wlen, cmgr, all);
if (ucs)
{
/* null-terminate the target buffer if it has room for it. */
if (wlen < *ucslen) ucs[wlen] = '\0';
else n = -2; /* buffer too small */
}
*bcslen = mlen; *ucslen = wlen;
return n;
}
static MOO_INLINE int ucsn_to_bcsn_with_cmgr (
const moo_uch_t* ucs, moo_oow_t* ucslen,
moo_bch_t* bcs, moo_oow_t* bcslen, moo_cmgr_t* cmgr)
{
const moo_uch_t* p = ucs;
const moo_uch_t* end = ucs + *ucslen;
int ret = 0;
if (bcs)
{
moo_oow_t rem = *bcslen;
while (p < end)
{
moo_oow_t n;
if (rem <= 0)
{
ret = -2; /* buffer too small */
break;
}
n = cmgr->uctobc (*p, bcs, rem);
if (n == 0)
{
ret = -1;
break; /* illegal character */
}
if (n > rem)
{
ret = -2; /* buffer too small */
break;
}
bcs += n; rem -= n; p++;
}
*bcslen -= rem;
}
else
{
moo_bch_t bcsbuf[MOO_BCLEN_MAX];
moo_oow_t mlen = 0;
while (p < end)
{
moo_oow_t n;
n = cmgr->uctobc (*p, bcsbuf, MOO_COUNTOF(bcsbuf));
if (n == 0)
{
ret = -1;
break; /* illegal character */
}
/* it assumes that bcsbuf is large enough to hold a character */
/*MOO_ASSERT (moo, n <= MOO_COUNTOF(bcsbuf));*/
p++; mlen += n;
}
/* this length excludes the terminating null character.
* this function doesn't even null-terminate the result. */
*bcslen = mlen;
}
*ucslen = p - ucs;
return ret;
}
static int ucs_to_bcs_with_cmgr (
const moo_uch_t* ucs, moo_oow_t* ucslen,
moo_bch_t* bcs, moo_oow_t* bcslen, moo_cmgr_t* cmgr)
{
const moo_uch_t* p = ucs;
int ret = 0;
if (bcs)
{
moo_oow_t rem = *bcslen;
while (*p != '\0')
{
moo_oow_t n;
if (rem <= 0)
{
ret = -2;
break;
}
n = cmgr->uctobc (*p, bcs, rem);
if (n == 0)
{
ret = -1;
break; /* illegal character */
}
if (n > rem)
{
ret = -2;
break; /* buffer too small */
}
bcs += n; rem -= n; p++;
}
/* update bcslen to the length of the bcs string converted excluding
* terminating null */
*bcslen -= rem;
/* null-terminate the multibyte sequence if it has sufficient space */
if (rem > 0) *bcs = '\0';
else
{
/* if ret is -2 and cs[cslen] == '\0',
* this means that the bcs buffer was lacking one
* slot for the terminating null */
ret = -2; /* buffer too small */
}
}
else
{
moo_bch_t bcsbuf[MOO_BCLEN_MAX];
moo_oow_t mlen = 0;
while (*p != '\0')
{
moo_oow_t n;
n = cmgr->uctobc (*p, bcsbuf, MOO_COUNTOF(bcsbuf));
if (n == 0)
{
ret = -1;
break; /* illegal character */
}
/* it assumes that bcs is large enough to hold a character */
/*MOO_ASSERT (moo, n <= MOO_COUNTOF(bcs));*/
p++; mlen += n;
}
/* this length holds the number of resulting multi-byte characters
* excluding the terminating null character */
*bcslen = mlen;
}
*ucslen = p - ucs; /* the number of wide characters handled. */
return ret;
}
/* ----------------------------------------------------------------------- */
static moo_cmgr_t utf8_cmgr =
{
moo_utf8touc,
moo_uctoutf8
};
moo_cmgr_t* moo_getutf8cmgr (void)
{
return &utf8_cmgr;
}
int moo_convutf8touchars (const moo_bch_t* bcs, moo_oow_t* bcslen, moo_uch_t* ucs, moo_oow_t* ucslen)
{
/* the source is length bound */
return bcsn_to_ucsn_with_cmgr (bcs, bcslen, ucs, ucslen, &utf8_cmgr, 0);
}
int moo_convutoutf8chars (const moo_uch_t* ucs, moo_oow_t* ucslen, moo_bch_t* bcs, moo_oow_t* bcslen)
{
/* length bound */
return ucsn_to_bcsn_with_cmgr (ucs, ucslen, bcs, bcslen, &utf8_cmgr);
}
int moo_convutf8toucstr (const moo_bch_t* bcs, moo_oow_t* bcslen, moo_uch_t* ucs, moo_oow_t* ucslen)
{
/* null-terminated. */
return bcs_to_ucs_with_cmgr (bcs, bcslen, ucs, ucslen, &utf8_cmgr, 0);
}
int moo_convutoutf8cstr (const moo_uch_t* ucs, moo_oow_t* ucslen, moo_bch_t* bcs, moo_oow_t* bcslen)
{
/* null-terminated */
return ucs_to_bcs_with_cmgr (ucs, ucslen, bcs, bcslen, &utf8_cmgr);
}
/* ----------------------------------------------------------------------- */
int moo_convbtouchars (moo_t* moo, const moo_bch_t* bcs, moo_oow_t* bcslen, moo_uch_t* ucs, moo_oow_t* ucslen)
{
/* length bound */
return bcsn_to_ucsn_with_cmgr (bcs, bcslen, ucs, ucslen, moo->cmgr, 0);
}
int moo_convutobchars (moo_t* moo, const moo_uch_t* ucs, moo_oow_t* ucslen, moo_bch_t* bcs, moo_oow_t* bcslen)
{
/* length bound */
return ucsn_to_bcsn_with_cmgr (ucs, ucslen, bcs, bcslen, moo->cmgr);
}
int moo_convbtoucstr (moo_t* moo, const moo_bch_t* bcs, moo_oow_t* bcslen, moo_uch_t* ucs, moo_oow_t* ucslen)
{
/* null-terminated. */
return bcs_to_ucs_with_cmgr (bcs, bcslen, ucs, ucslen, moo->cmgr, 0);
}
int moo_convutobcstr (moo_t* moo, const moo_uch_t* ucs, moo_oow_t* ucslen, moo_bch_t* bcs, moo_oow_t* bcslen)
{
/* null-terminated */
return ucs_to_bcs_with_cmgr (ucs, ucslen, bcs, bcslen, moo->cmgr);
}