From 46ba3bb3f5ff7596833e83a4c212d76d2ebd8ef3 Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Sun, 19 Mar 2017 14:18:37 +0000 Subject: [PATCH] added respondsTo: and perform:with: fixed a bug in Dictionary>>__remove_at: added gc callback to external modules --- moo/configure | 34 +++++- moo/configure.ac | 17 ++- moo/kernel/Apex.moo | 81 +++++++++++++- moo/kernel/Collect.moo | 64 ++++++----- moo/lib/exec.c | 77 ++++++++++++- moo/lib/gc.c | 15 +++ moo/lib/main.c | 6 +- moo/lib/moo-cfg.h.in | 5 +- moo/lib/moo-prv.h | 14 +-- moo/lib/moo.c | 94 +++++++++++----- moo/lib/moo.h | 33 +++++- moo/mod/x11.c | 246 ++++++++++++++++++++++++++++++++--------- 12 files changed, 550 insertions(+), 136 deletions(-) diff --git a/moo/configure b/moo/configure index 85d27a1..097af93 100755 --- a/moo/configure +++ b/moo/configure @@ -660,6 +660,8 @@ ENABLE_LIBLTDL_FALSE ENABLE_LIBLTDL_TRUE ENABLE_STATIC_MODULE_FALSE ENABLE_STATIC_MODULE_TRUE +ENABLE_DYNAMIC_MODULE_FALSE +ENABLE_DYNAMIC_MODULE_TRUE ENABLE_CXX_FALSE ENABLE_CXX_TRUE BUILD_MODE @@ -832,6 +834,7 @@ with_ltdl_lib enable_ltdl_install enable_debug enable_cxx +enable_dynamic_module enable_static_module enable_libltdl ' @@ -1482,6 +1485,7 @@ Optional Features: --enable-debug build the library in the debug mode (default. no) --enable-cxx build the library for C++ if a C++ compiler is available (default. yes) + --enable-dynamic-module enable dynamic module capability(default. yes) --enable-static-module build modules statically into the main library(default. no) --enable-libltdl use libltdl(default. yes) @@ -20588,6 +20592,31 @@ else fi +# Check whether --enable-dynamic-module was given. +if test "${enable_dynamic_module+set}" = set; then : + enableval=$enable_dynamic_module; enable_dynamic_module_is=$enableval +else + enable_dynamic_module_is=yes + +fi + +test "${enable_shared}" = "no" && enable_dynamic_module_is="no" + +if test "${enable_dynamic_module_is}" = "yes" +then + +$as_echo "#define MOO_ENABLE_DYNAMIC_MODULE /**/" >>confdefs.h + +fi + if test "${enable_dynamic_module_is}" = "yes"; then + ENABLE_DYNAMIC_MODULE_TRUE= + ENABLE_DYNAMIC_MODULE_FALSE='#' +else + ENABLE_DYNAMIC_MODULE_TRUE='#' + ENABLE_DYNAMIC_MODULE_FALSE= +fi + + # Check whether --enable-static-module was given. if test "${enable_static_module+set}" = set; then : enableval=$enable_static_module; enable_static_module_is=$enableval @@ -20613,7 +20642,6 @@ else fi - # Check whether --enable-libltdl was given. if test "${enable_libltdl+set}" = set; then : enableval=$enable_libltdl; enable_libltdl_is=$enableval @@ -20844,6 +20872,10 @@ if test -z "${ENABLE_CXX_TRUE}" && test -z "${ENABLE_CXX_FALSE}"; then as_fn_error $? "conditional \"ENABLE_CXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${ENABLE_DYNAMIC_MODULE_TRUE}" && test -z "${ENABLE_DYNAMIC_MODULE_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_DYNAMIC_MODULE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${ENABLE_STATIC_MODULE_TRUE}" && test -z "${ENABLE_STATIC_MODULE_FALSE}"; then as_fn_error $? "conditional \"ENABLE_STATIC_MODULE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 diff --git a/moo/configure.ac b/moo/configure.ac index e35b1cf..2322ffa 100644 --- a/moo/configure.ac +++ b/moo/configure.ac @@ -420,6 +420,20 @@ test "${ax_cv_cxx_have_std_namespace}" = "yes" || enable_cxx_is="no" AM_CONDITIONAL(ENABLE_CXX, test "${enable_cxx_is}" = "yes" ) +dnl ===== enable-dynamic-module ===== +AC_ARG_ENABLE([dynamic-module], + [AS_HELP_STRING([--enable-dynamic-module],[enable dynamic module capability(default. yes)])], + enable_dynamic_module_is=$enableval, + enable_dynamic_module_is=yes +) +test "${enable_shared}" = "no" && enable_dynamic_module_is="no" + +if test "${enable_dynamic_module_is}" = "yes" +then + AC_DEFINE([MOO_ENABLE_DYNAMIC_MODULE],[],[enable dynamic module capability]) +fi +AM_CONDITIONAL(ENABLE_DYNAMIC_MODULE, test "${enable_dynamic_module_is}" = "yes") + dnl ===== enable-static-module ===== AC_ARG_ENABLE([static-module], [AS_HELP_STRING([--enable-static-module],[build modules statically into the main library(default. no)])], @@ -434,7 +448,6 @@ then fi AM_CONDITIONAL(ENABLE_STATIC_MODULE, test "${enable_static_module_is}" = "yes") - dnl ===== enable-libltdl ===== AC_ARG_ENABLE([libltdl], [AS_HELP_STRING([--enable-libltdl],[use libltdl(default. yes)])], @@ -443,7 +456,7 @@ AC_ARG_ENABLE([libltdl], ) if test "${enable_libltdl_is}" = "yes" then - AC_DEFINE([MOO_ENABLE_LIBLTDL],[],[use libltdl]) + AC_DEFINE([MOO_ENABLE_LIBLTDL],[],[use libltdl when loading a dynamic module]) fi AM_CONDITIONAL(ENABLE_LIBLTDL, test "${enable_libltdl_is}" = "yes") diff --git a/moo/kernel/Apex.moo b/moo/kernel/Apex.moo index cd4936b..962e1d0 100644 --- a/moo/kernel/Apex.moo +++ b/moo/kernel/Apex.moo @@ -312,17 +312,86 @@ class Apex(nil) ^(self isMemberOf: aClass) or: [self class inheritsFrom: aClass]. } - (* ----------------- - method(#class) respondsTo: selectorSymbol + ## ------------------------------------------------------- + ## ------------------------------------------------------- + + method(#class) respondsTo: selector { - TODO: find selectorSymbol in the class method dictionary... + + self primitiveFailed } - method respondsTo: selectorSymbol + method respondsTo: selector { - TODO: find selectorSymbol in the method dictionary... + + self primitiveFailed } - ------------ *) + + ## ------------------------------------------------------- + ## ------------------------------------------------------- + + method(#class) perform() + { + + self primitiveFailed + } + + method perform() + { + + self primitiveFailed + } + + method(#class) perform: selector + { + + self primitiveFailed + } + + method perform: selector + { + + self primitiveFailed + } + + method(#class) perform: selector with: arg1 + { + + self primitiveFailed + } + + method perform: selector with: arg1 + { + + self primitiveFailed + } + + method(#class) perform: selector with: arg1 with: arg2 + { + + self primitiveFailed + } + + method perform: selector with: arg1 with: arg2 + { + + self primitiveFailed + } + + method(#class) perform: selector with: arg1 with: arg2 with: arg3 + { + + self primitiveFailed + } + + method perform: selector with: arg1 with: arg2 with: arg3 + { + + self primitiveFailed + } + + ## ------------------------------------------------------- + ## ------------------------------------------------------- method exceptionizeError: trueOrFalse { diff --git a/moo/kernel/Collect.moo b/moo/kernel/Collect.moo index 2c040d1..4573f43 100644 --- a/moo/kernel/Collect.moo +++ b/moo/kernel/Collect.moo @@ -321,40 +321,33 @@ class Set(Collection) method __remove_at: index { - | bs x y i v | + | bs x y i v ass z | bs := self.bucket size. - v := self.bucket basicAt: index. + v := self.bucket at: index. x := index. y := index. i := 0. - [i < self.tally] whileTrue: [ - | ass z | - + while (i < self.tally) + { y := (y + 1) rem: bs. - ass := self.bucket at: i. - if (ass isNil) - { - (* done. the slot at the current index is nil *) - i := self.tally - } - else - { - (* get the natural hash index *) - z := (ass key hash) rem: bs. + ass := self.bucket at: y. + if (ass isNil) { (* done. the slot at the current index is nil *) break }. + + (* get the natural hash index *) + z := (ass key hash) rem: bs. - (* move an element if necessary *) - if ((y > x and: [(z <= x) or: [z > y]]) or: [(y < x) and: [(z <= x) and: [z > y]]]) - { - self.bucket at: x put: (self.bucket at: y). - x := y. - }. - - i := i + 1 + (* move an element if necessary *) + if ((y > x and: [(z <= x) or: [z > y]]) or: [(y < x) and: [(z <= x) and: [z > y]]]) + { + self.bucket at: x put: (self.bucket at: y). + x := y. }. - ]. + + i := i + 1. + }. self.bucket at: x put: nil. self.tally := self.tally - 1. @@ -744,14 +737,15 @@ class LinkedList(Collection) else { self.first := link next }. self.tally := self.tally - 1. + ^link. } - method removeFirst + method removeFirstLink { ^self removeLink: self.first } - method removeLast + method removeLastLink { ^self removeLink: self.last } @@ -767,4 +761,22 @@ class LinkedList(Collection) link := next. } } + + method doOverLink: block + { + | link next | + link := self.first. + while (link notNil) + { + next := link next. + block value: link. + link := next. + } + } + + method findLink: value + { + self doOverLink: [:el | if (el value = value) { ^el }]. + ^Error.Code.ENOENT + } } diff --git a/moo/lib/exec.c b/moo/lib/exec.c index 9ecd72a..f32a1bd 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -108,6 +108,7 @@ #endif static void signal_io_semaphore (moo_t* moo, int mask, void* ctx); +static int send_message (moo_t* moo, moo_oop_char_t selector, int to_super, moo_ooi_t nargs); /* ------------------------------------------------------------------------- */ static MOO_INLINE int vm_startup (moo_t* moo) @@ -1521,6 +1522,7 @@ static moo_pfrc_t pf_basic_at (moo_t* moo, moo_ooi_t nargs) if (!MOO_OOP_IS_POINTER(rcv)) { /* the receiver is a special numeric object, not a normal pointer */ + moo->errnum = MOO_EINVAL; return MOO_PF_FAILURE; } @@ -1528,11 +1530,13 @@ static moo_pfrc_t pf_basic_at (moo_t* moo, moo_ooi_t nargs) if (moo_inttooow (moo, pos, &idx) <= 0) { /* negative integer or not integer */ + moo->errnum = MOO_EINVAL; return MOO_PF_FAILURE; } if (idx >= MOO_OBJ_GET_SIZE(rcv)) { /* index out of range */ + moo->errnum = MOO_ERANGE; return MOO_PF_FAILURE; } @@ -1580,6 +1584,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs) if (!MOO_OOP_IS_POINTER(rcv)) { /* the receiver is a special numeric object, not a normal pointer */ + moo->errnum = MOO_EINVAL; return MOO_PF_FAILURE; } pos = MOO_STACK_GETARG(moo, nargs, 0); @@ -1588,11 +1593,13 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs) if (moo_inttooow (moo, pos, &idx) <= 0) { /* negative integer or not integer */ + moo->errnum = MOO_EINVAL; return MOO_PF_FAILURE; } if (idx >= MOO_OBJ_GET_SIZE(rcv)) { /* index out of range */ + moo->errnum = MOO_ERANGE; return MOO_PF_FAILURE; } @@ -1601,6 +1608,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs) /* TODO: disallow change of some key kernel objects???? */ /* TODO: is it better to introduct a read-only mark in the object header instead of this class check??? */ /* read-only object */ /* TODO: DEVISE A WAY TO PASS a proper error from the primitive handler to MOO */ + moo->errnum = MOO_EINVAL; return MOO_PF_FAILURE; } @@ -1610,6 +1618,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs) if (!MOO_OOP_IS_SMOOI(val)) { /* the value is not a character */ + moo->errnum = MOO_EINVAL; return MOO_PF_FAILURE; } /* TOOD: must I check the range of the value? */ @@ -1620,6 +1629,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs) if (!MOO_OOP_IS_CHAR(val)) { /* the value is not a character */ + moo->errnum = MOO_EINVAL; return MOO_PF_FAILURE; } ((moo_oop_char_t)rcv)->slot[idx] = MOO_OOP_TO_CHAR(val); @@ -1629,6 +1639,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs) if (!MOO_OOP_IS_SMOOI(val)) { /* the value is not a number */ + moo->errnum = MOO_EINVAL; return MOO_PF_FAILURE; } @@ -1643,6 +1654,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs) if (moo_inttooow (moo, val, &w) <= 0) { /* the value is not a number, out of range, or negative */ + moo->errnum = MOO_EINVAL; return MOO_PF_FAILURE; } ((moo_oop_word_t)rcv)->slot[idx] = w; @@ -1712,6 +1724,7 @@ static moo_pfrc_t pf_hash (moo_t* moo, moo_ooi_t nargs) default: /* MOO_OBJ_TYPE_OOP, ... */ MOO_DEBUG1 (moo, " Cannot hash an object of type %d\n", type); + moo->errnum = MOO_EINVAL; return MOO_PF_FAILURE; } break; @@ -1726,6 +1739,65 @@ static moo_pfrc_t pf_hash (moo_t* moo, moo_ooi_t nargs) return MOO_PF_SUCCESS; } +static moo_pfrc_t pf_responds_to (moo_t* moo, moo_ooi_t nargs) +{ + moo_oop_t rcv, selector; + moo_oocs_t mthname; + + rcv = MOO_STACK_GETRCV(moo, nargs); + selector = MOO_STACK_GETARG(moo, nargs, 0); + + if (MOO_CLASSOF(moo,selector) != moo->_symbol) + { + moo->errnum = MOO_EINVAL; + return MOO_PF_FAILURE; + } + + mthname.ptr = MOO_OBJ_GET_CHAR_SLOT(selector); + mthname.len = MOO_OBJ_GET_SIZE(selector); + if (find_method (moo, rcv, &mthname, 0)) + { + MOO_STACK_SETRET (moo, nargs, moo->_true); + } + else + { + MOO_STACK_SETRET (moo, nargs, moo->_false); + } + + return MOO_PF_SUCCESS; +} + +static moo_pfrc_t pf_perform (moo_t* moo, moo_ooi_t nargs) +{ + moo_oop_t /*rcv,*/ selector; + moo_oow_t ssp, esp, i; + + /*rcv = MOO_STACK_GETRCV(moo, nargs);*/ + selector = MOO_STACK_GETARG(moo, nargs, 0); + + if (MOO_CLASSOF(moo,selector) != moo->_symbol) + { + moo->errnum = MOO_EINVAL; + return MOO_PF_FAILURE; + } + + /* remove the selector from the stack */ + ssp = MOO_STACK_GETARGSP (moo, nargs, 0); + esp = MOO_STACK_GETARGSP (moo, nargs, nargs - 1); + for (i = ssp; i < esp;) + { + moo_oop_t t; + t = MOO_STACK_GET (moo, i); + i++; + MOO_STACK_SET(moo, i, t); + } + MOO_STACK_POP (moo); + + /* emulate message sending */ + if (send_message (moo, (moo_oop_char_t)selector, 0, nargs - 1) <= -1) return MOO_PF_HARD_FAILURE; + return MOO_PF_SUCCESS; +} + static moo_pfrc_t pf_exceptionize_error (moo_t* moo, moo_ooi_t nargs) { moo_oop_t rcv; @@ -2719,12 +2791,15 @@ static pf_t pftab[] = { 0, 0, pf_hash, "_hash" }, + { 1, 1, pf_responds_to, "_responds_to" }, + { 1, MAX_NARGS, pf_perform, "_perform" }, { 1, 1, pf_exceptionize_error, "_exceptionize_error" }, { 1, 1, pf_context_goto, "_context_goto" }, { 0, MAX_NARGS, pf_block_value, "_block_value" }, { 0, MAX_NARGS, pf_block_new_process, "_block_new_process" }, + { 0, 0, pf_process_resume, "_process_resume" }, { 0, 0, pf_process_terminate, "_process_terminate" }, { 0, 0, pf_process_yield, "_process_yield" }, @@ -3043,7 +3118,7 @@ static int send_message (moo_t* moo, moo_oop_char_t selector, int to_super, moo_ receiver = MOO_STACK_GET(moo, moo->sp - nargs); - mthname.ptr = selector->slot; + mthname.ptr = MOO_OBJ_GET_CHAR_SLOT(selector); mthname.len = MOO_OBJ_GET_SIZE(selector); method = find_method (moo, receiver, &mthname, to_super); if (!method) diff --git a/moo/lib/gc.c b/moo/lib/gc.c index 8ff5cab..e95b0b7 100644 --- a/moo/lib/gc.c +++ b/moo/lib/gc.c @@ -562,6 +562,19 @@ static moo_uint8_t* scan_new_heap (moo_t* moo, moo_uint8_t* ptr) return ptr; } +static moo_rbt_walk_t call_module_gc (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); + + if (mdp->mod.gc) mdp->mod.gc (moo, &mdp->mod); + + return MOO_RBT_WALK_FORWARD; +} + void moo_gc (moo_t* moo) { /* @@ -643,6 +656,8 @@ void moo_gc (moo_t* moo) if (moo->active_method) moo->active_method = (moo_oop_method_t)moo_moveoop (moo, (moo_oop_t)moo->active_method); + moo_rbt_walk (&moo->modtab, call_module_gc, moo); + for (cb = moo->cblist; cb; cb = cb->next) { if (cb->gc) cb->gc (moo); diff --git a/moo/lib/main.c b/moo/lib/main.c index 884c261..3736742 100644 --- a/moo/lib/main.c +++ b/moo/lib/main.c @@ -462,6 +462,9 @@ static void* dl_open (moo_t* moo, const moo_ooch_t* name, int flags) return handle; #else + + + /* TODO: support various platforms */ /* TODO: implemenent this */ MOO_DEBUG1 (moo, "Dynamic loading not implemented - cannot open %js\n", name); @@ -1320,11 +1323,12 @@ int main (int argc, char* argv[]) } #endif + + memset (&vmprim, 0, MOO_SIZEOF(vmprim)); vmprim.dl_open = dl_open; vmprim.dl_close = dl_close; vmprim.dl_getsym = dl_getsym; vmprim.log_write = log_write; - vmprim.vm_startup = vm_startup; vmprim.vm_cleanup = vm_cleanup; vmprim.vm_gettime = vm_gettime; diff --git a/moo/lib/moo-cfg.h.in b/moo/lib/moo-cfg.h.in index 533ebe5..6c075e3 100644 --- a/moo/lib/moo-cfg.h.in +++ b/moo/lib/moo-cfg.h.in @@ -326,7 +326,10 @@ /* Define to the shared archive member specification, say "(shr.o)". */ #undef LT_SHARED_LIB_MEMBER -/* use libltdl */ +/* enable dynamic module capability */ +#undef MOO_ENABLE_DYNAMIC_MODULE + +/* use libltdl when loading a dynamic module */ #undef MOO_ENABLE_LIBLTDL /* link modules statically into the main library */ diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index 7fddb05..c79dd38 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -925,15 +925,6 @@ void* moo_allocheapmem ( moo_oow_t size ); - -/* ========================================================================= */ -/* gc.c */ -/* ========================================================================= */ -moo_oop_t moo_moveoop ( - moo_t* moo, - moo_oop_t oop -); - /* ========================================================================= */ /* obj.c */ /* ========================================================================= */ @@ -1185,13 +1176,14 @@ int moo_getpfnum ( /* ========================================================================= */ -/* moo.c */ +/* moo.c */ /* ========================================================================= */ moo_mod_data_t* moo_openmod ( moo_t* moo, const moo_ooch_t* name, - moo_oow_t namelen + moo_oow_t namelen, + int hints /* 0 or bitwise-ORed of moo_mod_hint_t enumerators */ ); void moo_closemod ( diff --git a/moo/lib/moo.c b/moo/lib/moo.c index d44efb8..cd2c185 100644 --- a/moo/lib/moo.c +++ b/moo/lib/moo.c @@ -378,7 +378,7 @@ static_modtab[] = }; #endif -moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namelen) +moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namelen, int hints) { moo_rbt_pair_t* pair; moo_mod_data_t* mdp; @@ -423,14 +423,6 @@ moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namel } } - if (n >= MOO_COUNTOF(static_modtab)) - { - MOO_DEBUG2 (moo, "Cannot find a static module [%.*js]\n", namelen, name); - moo->errnum = MOO_ENOENT; - return MOO_NULL; -/* TODO: fall back to find dynamic module further on supported platforms instead of returning error here... */ - } - if (load) { /* found the module in the staic module table */ @@ -449,17 +441,36 @@ moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namel } mdp = (moo_mod_data_t*)MOO_RBT_VPTR(pair); + MOO_ASSERT (moo, MOO_SIZEOF(mdp->mod.hints) == MOO_SIZEOF(int)); + *(int*)&mdp->mod.hints = hints; if (load (moo, &mdp->mod) <= -1) { moo_rbt_delete (&moo->modtab, (moo_ooch_t*)name, namelen); return MOO_NULL; } + mdp->pair = pair; + + MOO_DEBUG1 (moo, "Opened a static module [%js]\n", mdp->mod.name); return mdp; } + else + { + #if !defined(MOO_ENABLE_DYNAMIC_MODULE) + MOO_DEBUG2 (moo, "Cannot find a static module [%.*js]\n", namelen, name); + moo->errnum = MOO_ENOENT; + return MOO_NULL; + #endif + } #endif - /* attempt to find an external module */ +#if !defined(MOO_ENABLE_DYNAMIC_MODULE) + MOO_DEBUG2 (moo, "Cannot open module [%.*js] - module loading disabled\n", namelen, name); + moo->errnum = MOO_ENOIMPL; /* TODO: is it a good error number for disabled module loading? */ + return MOO_NULL; +#endif + + /* attempt to find a dynamic 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) @@ -496,6 +507,8 @@ moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namel } mdp = (moo_mod_data_t*)MOO_RBT_VPTR(pair); + MOO_ASSERT (moo, MOO_SIZEOF(mdp->mod.hints) == MOO_SIZEOF(int)); + *(int*)&mdp->mod.hints = hints; if (load (moo, &mdp->mod) <= -1) { MOO_DEBUG3 (moo, "Module function [%js] returned failure in [%.*js]\n", buf, namelen, name); @@ -525,6 +538,10 @@ void moo_closemod (moo_t* moo, moo_mod_data_t* mdp) MOO_DEBUG2 (moo, "Closed a module [%js] - %p\n", mdp->mod.name, mdp->handle); mdp->handle = MOO_NULL; } + else + { + MOO_DEBUG1 (moo, "Closed a static module [%js] - %p\n", mdp->mod.name); + } if (mdp->pair) { @@ -537,7 +554,7 @@ int moo_importmod (moo_t* moo, moo_oop_class_t _class, const moo_ooch_t* name, m { moo_rbt_pair_t* pair; moo_mod_data_t* mdp; - int r = 0; + int r = -1; /* moo_openmod(), moo_closemod(), etc call a user-defined callback. * i need to protect _class in case the user-defined callback allocates @@ -550,38 +567,36 @@ int moo_importmod (moo_t* moo, moo_oop_class_t _class, const moo_ooch_t* name, m { mdp = (moo_mod_data_t*)MOO_RBT_VPTR(pair); MOO_ASSERT (moo, mdp != MOO_NULL); + + MOO_DEBUG1 (moo, "Cannot import module [%js] - already active\n", mdp->mod.name); + moo->errnum = MOO_EPERM; + goto done2; } - else - { - mdp = moo_openmod (moo, name, len); - if (!mdp) - { - r = -1; - goto done2; - } - } + + mdp = moo_openmod (moo, name, len, MOO_MOD_LOAD_FOR_IMPORT); + if (!mdp) 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; } + r = 0; /* everything successful */ + done: - if (!pair) - { - /* close the module if it has been opened in this function. */ - moo_closemod (moo, mdp); - } + /* close the module opened above. + * [NOTE] if the import callback calls the moo_querymod(), the returned + * function pointers will get all invalidated here. so never do + * anything like that */ + moo_closemod (moo, mdp); done2: moo_poptmp (moo); @@ -615,8 +630,8 @@ moo_pfimpl_t moo_querymod (moo_t* moo, const moo_ooch_t* pfid, moo_oow_t pfidlen mod_name_len = sep - pfid; - /* the first through the segment before the last compose a module id. - * the last segment is the primitive function name. + /* the first segment through the segment before the last compose a + * module id. the last segment is the primitive function name. * for instance, in con.window.open, con.window is a module id and * open is the primitive function name. */ pair = moo_rbt_search (&moo->modtab, pfid, mod_name_len); @@ -628,7 +643,7 @@ moo_pfimpl_t moo_querymod (moo_t* moo, const moo_ooch_t* pfid, moo_oow_t pfidlen else { /* open a module using the part before the last period */ - mdp = moo_openmod (moo, pfid, mod_name_len); + mdp = moo_openmod (moo, pfid, mod_name_len, 0); if (!mdp) return MOO_NULL; } @@ -873,3 +888,22 @@ void* moo_getobjtrailer (moo_t* moo, moo_oop_t obj, moo_oow_t* size) if (size) *size = MOO_OBJ_GET_TRAILER_SIZE(obj); return MOO_OBJ_GET_TRAILER_BYTE(obj); } + + +moo_oop_t moo_findclass (moo_t* moo, moo_oop_set_t nsdic, const moo_ooch_t* name) +{ + moo_oop_association_t ass; + moo_oocs_t n; + + n.ptr = (moo_ooch_t*)name; + n.len = moo_countoocstr(name); + + ass = moo_lookupdic (moo, nsdic, &n); + if (!ass || MOO_CLASSOF(moo,ass->value) != moo->_class) + { + moo->errnum = MOO_ENOENT; + return MOO_NULL; + } + + return ass->value; +} diff --git a/moo/lib/moo.h b/moo/lib/moo.h index 6f90e3c..52eda50 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -840,9 +840,14 @@ struct moo_pfinfo_t moo_pfimpl_t handler; }; - typedef struct moo_mod_t moo_mod_t; +enum moo_mod_hint_t +{ + MOO_MOD_LOAD_FOR_IMPORT = (1 << 0) +}; +typedef enum moo_mod_hint_t moo_mod_hint_t; + typedef int (*moo_mod_load_t) ( moo_t* moo, moo_mod_t* mod @@ -865,12 +870,22 @@ typedef void (*moo_mod_unload_t) ( moo_mod_t* mod ); +typedef void (*moo_mod_gc_t) ( + moo_t* moo, + moo_mod_t* mod +); + struct moo_mod_t { + /* input */ const moo_ooch_t name[MOO_MOD_NAME_LEN_MAX + 1]; + const int hints; /* bitwised-ORed of moo_mod_hint_t enumerators */ + + /* user-defined data */ moo_mod_import_t import; moo_mod_query_t query; moo_mod_unload_t unload; + moo_mod_gc_t gc; void* ctx; }; @@ -883,7 +898,6 @@ struct moo_mod_data_t typedef struct moo_mod_data_t moo_mod_data_t; - struct moo_sbuf_t { moo_ooch_t* ptr; @@ -1065,6 +1079,7 @@ struct moo_t #define MOO_STACK_POPS(moo,count) ((moo)->sp = (moo)->sp - (count)) #define MOO_STACK_ISEMPTY(moo) ((moo)->sp <= -1) +#define MOO_STACK_GETARGSP(moo,nargs,idx) ((moo)->sp - ((nargs) - (idx) - 1)) #define MOO_STACK_GETARG(moo,nargs,idx) MOO_STACK_GET(moo, (moo)->sp - ((nargs) - (idx) - 1)) #define MOO_STACK_GETRCV(moo,nargs) MOO_STACK_GET(moo, (moo)->sp - nargs) @@ -1348,6 +1363,15 @@ MOO_EXPORT void moo_gc ( ); +/** + * The moo_moveoop() function moves an object and returns an updated pointer + * after having moved. it must be called in the GC callback context only. + */ +MOO_EXPORT moo_oop_t moo_moveoop ( + moo_t* moo, + moo_oop_t oop +); + /** * The moo_instantiate() function creates a new object instance of the class * \a _class. The size of the fixed part is taken from the information @@ -1457,6 +1481,11 @@ MOO_EXPORT int moo_inttoooi ( moo_ooi_t* i ); +MOO_EXPORT moo_oop_t moo_findclass ( + moo_t* moo, + moo_oop_set_t nsdic, + const moo_ooch_t* name +); /* ========================================================================= * TRAILER MANAGEMENT diff --git a/moo/mod/x11.c b/moo/mod/x11.c index 6971aea..58ba5fd 100644 --- a/moo/mod/x11.c +++ b/moo/mod/x11.c @@ -34,12 +34,21 @@ #define C MOO_METHOD_CLASS #define I MOO_METHOD_INSTANCE +typedef struct x11_modctx_t x11_modctx_t; +struct x11_modctx_t +{ + moo_oop_class_t x11_class; + moo_oop_class_t mouse_event_class; + moo_oop_class_t key_event_class; +}; typedef struct x11_t x11_t; struct x11_t { xcb_connection_t* c; xcb_screen_t* screen; + + xcb_generic_event_t* curevt; /* most recent event received */ }; typedef struct x11_win_t x11_win_t; @@ -49,6 +58,7 @@ struct x11_win_t xcb_intern_atom_reply_t* dwcr; }; + /* ------------------------------------------------------------------------ */ static moo_pfrc_t pf_connect (moo_t* moo, moo_ooi_t nargs) @@ -56,6 +66,8 @@ static moo_pfrc_t pf_connect (moo_t* moo, moo_ooi_t nargs) x11_t* x11; xcb_connection_t* c; + x11 = (x11_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); + /* TODO: accept display target as a parameter */ if (nargs != 0) { @@ -63,8 +75,6 @@ static moo_pfrc_t pf_connect (moo_t* moo, moo_ooi_t nargs) goto softfail; } - x11 = (x11_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); - if (x11->c) { MOO_DEBUG0 (moo, " Unable to connect multiple times\n"); @@ -108,6 +118,11 @@ static moo_pfrc_t pf_disconnect (moo_t* moo, moo_ooi_t nargs) MOO_DEBUG1 (moo, " %p\n", x11->c); + if (x11->curevt) + { + free (x11->curevt); + x11->curevt = MOO_NULL; + } if (x11->c) { xcb_disconnect (x11->c); @@ -116,18 +131,14 @@ static moo_pfrc_t pf_disconnect (moo_t* moo, moo_ooi_t nargs) MOO_STACK_SETRETTORCV (moo, nargs); return MOO_PF_SUCCESS; - -softfail: - MOO_STACK_SETRETTOERROR (moo, nargs); - return MOO_PF_SUCCESS; } -static moo_pfrc_t pf_getfd (moo_t* moo, moo_ooi_t nargs) +static moo_pfrc_t pf_get_fd (moo_t* moo, moo_ooi_t nargs) { x11_t* x11; x11 = (x11_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); - MOO_DEBUG1 (moo, " %p\n", x11->c); + MOO_DEBUG1 (moo, " %p\n", x11->c); if (x11->c) { @@ -146,38 +157,73 @@ static moo_pfrc_t pf_getfd (moo_t* moo, moo_ooi_t nargs) return MOO_PF_SUCCESS; } - static moo_pfrc_t pf_getevent (moo_t* moo, moo_ooi_t nargs) { x11_t* x11; xcb_generic_event_t* evt; x11 = (x11_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); - MOO_DEBUG1 (moo, " %p\n", x11->c); + MOO_DEBUG1 (moo, " %p\n", x11->c); evt = xcb_poll_for_event(x11->c); + if (x11->curevt) free (x11->curevt); + x11->curevt = evt; + if (evt) { - uint8_t evttype = evt->response_type & ~0x80; + uint8_t evttype = evt->response_type & 0x7F; + x11->curevt = evt; if (evttype == XCB_CLIENT_MESSAGE) -#if 0 -&& - ((xcb_client_message_event_t*)evt)->data.data32[0] == x11->dwcr->atom) -#endif { -#if 0 - xcb_unmap_window (x11->c, x11->w); - xcb_destroy_window (x11->c, x11->w); - xcb_flush (x11->c); -#endif MOO_STACK_SETRET (moo, nargs, MOO_SMOOI_TO_OOP(9999)); /* TODO: translate evt to the event object */ } else { MOO_STACK_SETRET (moo, nargs, MOO_SMOOI_TO_OOP(evttype)); /* TODO: translate evt to the event object */ } + +#if 0 + switch (evttype) + { + case XCB_CLIENT_MESSAGE: + #if 0 + if (((xcb_client_message_event_t*)evt)->data.data32[0] == x11->dwcr->atom) + { + xcb_unmap_window (x11->c, x11->w); + xcb_destroy_window (x11->c, x11->w); + xcb_flush (x11->c); + } + #endif + MOO_STACK_SETRET (moo, nargs, MOO_SMOOI_TO_OOP(9999)); /* TODO: translate evt to the event object */ + + break; + + + case XCB_BUTTON_PRESS: + case XCB_BUTTON_RELEASE: + { + xcb_button_press_event_t* bpe = (xcb_button_press_event_t*)evt; + + + MOO_STACK_SETRET (moo, nargs, e); + break; + } + + default: + MOO_STACK_SETRET (moo, nargs, MOO_SMOOI_TO_OOP(evttype)); /* TODO: translate evt to the event object */ + break; + } + + free (evt); +#endif + + } + else if (xcb_connection_has_error(x11->c)) + { + /* TODO: to be specific about the error */ + MOO_STACK_SETRETTOERROR (moo, nargs); } else { @@ -189,23 +235,72 @@ static moo_pfrc_t pf_getevent (moo_t* moo, moo_ooi_t nargs) /* ------------------------------------------------------------------------ */ +static moo_pfrc_t pf_win_get_id (moo_t* moo, moo_ooi_t nargs) +{ + x11_win_t* win; + moo_oop_t x; + + win = (x11_win_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); + + x = moo_oowtoint (moo, win->id); + if (!x) return MOO_PF_HARD_FAILURE; + + MOO_STACK_SETRET (moo, nargs, x); + return MOO_PF_SUCCESS; + +} + +static moo_pfrc_t pf_win_kill_on (moo_t* moo, moo_ooi_t nargs) +{ + x11_t* x11; + x11_win_t* win; + + x11 = (x11_t*)moo_getobjtrailer(moo, MOO_STACK_GETARG(moo, nargs, 0), MOO_NULL); + win = (x11_win_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); + + if (!x11->c) + { + MOO_STACK_SETRETTOERROR (moo, nargs); /* More specific error code*/ + return MOO_PF_SUCCESS; + } + +/* TODO: check on windows id */ + + xcb_unmap_window (x11->c, win->id); /* TODO: check error code */ + xcb_destroy_window (x11->c, win->id); + xcb_flush (x11->c); + + MOO_STACK_SETRETTORCV (moo, nargs); + return MOO_PF_SUCCESS; +} + static moo_pfrc_t pf_win_make_on (moo_t* moo, moo_ooi_t nargs) { x11_t* x11; x11_win_t* win; + moo_oop_t id; uint32_t mask; uint32_t values[2]; xcb_intern_atom_cookie_t cookie; xcb_intern_atom_reply_t* reply; -MOO_DEBUG0 (moo, " %p\n"); +MOO_DEBUG0 (moo, " %p\n"); x11 = (x11_t*)moo_getobjtrailer(moo, MOO_STACK_GETARG(moo, nargs, 0), MOO_NULL); win = (x11_win_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); + if (!x11->c) + { + MOO_STACK_SETRETTOERROR (moo, nargs); /* TODO: be more specific about error */ + return MOO_PF_SUCCESS; + } + win->id = xcb_generate_id (x11->c); + id = moo_oowtoint (moo, win->id); + if (!id) return MOO_PF_HARD_FAILURE; + mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; values[0] = x11->screen->white_pixel; values[1] = XCB_EVENT_MASK_KEY_RELEASE | @@ -237,44 +332,20 @@ MOO_DEBUG0 (moo, " %p\n"); xcb_map_window (x11->c, win->id); xcb_flush (x11->c); - MOO_STACK_SETRETTORCV (moo, nargs); + MOO_STACK_SETRET (moo, nargs, id); return MOO_PF_SUCCESS; } -static moo_pfrc_t pf_win_kill_on (moo_t* moo, moo_ooi_t nargs) -{ - x11_t* x11; - x11_win_t* win; - - x11 = (x11_t*)moo_getobjtrailer(moo, MOO_STACK_GETARG(moo, nargs, 0), MOO_NULL); - win = (x11_win_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL); - - if (!x11->c) - { - MOO_STACK_SETRETTOERROR (moo, nargs); /* More specific error code*/ - return MOO_PF_SUCCESS; - } - -/* TODO: check on windows id */ - - xcb_unmap_window (x11->c, win->id); /* TODO: check error code */ - xcb_destroy_window (x11->c, win->id); - xcb_flush (x11->c); - - MOO_STACK_SETRETTORCV (moo, nargs); - return MOO_PF_SUCCESS; -} /* ------------------------------------------------------------------------ */ static moo_pfinfo_t x11_pfinfo[] = { - { I, { '_','g','e','t','e','v','e','n','t','\0'}, 0, pf_getevent }, - { I, { 'c','o','n','n','e','c','t','\0' }, 0, pf_connect }, - { I, { 'd','i','s','c','o','n','n','e','c','t','\0' }, 0, pf_disconnect }, - { I, { 'g','e','t','f','d','\0' }, 0, pf_getfd } - + { I, { '_','c','o','n','n','e','c','t','\0' }, 0, pf_connect }, + { I, { '_','d','i','s','c','o','n','n','e','c','t','\0' }, 0, pf_disconnect }, + { I, { '_','g','e','t','_','e','v','e','n','t','\0'}, 0, pf_getevent }, + { I, { '_','g','e','t','_','f','d','\0' }, 0, pf_get_fd } }; static int x11_import (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class) @@ -291,15 +362,77 @@ static moo_pfimpl_t x11_query (moo_t* moo, moo_mod_t* mod, const moo_ooch_t* nam static void x11_unload (moo_t* moo, moo_mod_t* mod) { - /* TODO: anything? close open open dll handles? For that, pf_open must store the value it returns to mod->ctx or somewhere..*/ + /* TODO: anything else? close all open dll handles? For that, pf_open must store the value it returns to mod->ctx or somewhere..*/ + moo_freemem (moo, mod->ctx); +} + +static void x11_gc (moo_t* moo, moo_mod_t* mod) +{ + x11_modctx_t* ctx = mod->ctx; + + MOO_ASSERT (moo, ctx != MOO_NULL); + ctx->mouse_event_class = (moo_oop_class_t)moo_moveoop (moo, (moo_oop_t)ctx->mouse_event_class); + ctx->key_event_class = (moo_oop_class_t)moo_moveoop (moo, (moo_oop_t)ctx->key_event_class); } int moo_mod_x11 (moo_t* moo, moo_mod_t* mod) { + if (mod->hints & MOO_MOD_LOAD_FOR_IMPORT) + { + mod->gc = MOO_NULL; + mod->ctx = MOO_NULL; + } + else + { + x11_modctx_t* ctx; + + static moo_ooch_t name_x11[] = { 'X','1','1','\0' }; + static moo_ooch_t name_mouse_event[] = { 'M','o','u','s','e','E','v','e','n','t','\0' }; + static moo_ooch_t name_key_event[] = { 'K','e','y','E','v','e','n','t','\0' }; + + ctx = moo_callocmem (moo, MOO_SIZEOF(*ctx)); + if (!ctx) return -1; + + ctx->x11_class = (moo_oop_class_t)moo_findclass (moo, moo->sysdic, name_x11); + if (!ctx->x11_class) + { + /* Not a single X11.XXX has been defined. */ + MOO_DEBUG0 (moo, "X11 class not found\n"); + oops: + moo_freemem (moo, ctx); + return -1; + } + + if ((moo_oop_t)ctx->x11_class->nsdic == moo->_nil) + { + MOO_DEBUG0 (moo, "No class defined in X11\n"); + goto oops; + } + +/* TODO: check on instance size... etc */ +/* TODO: tabulate key event classes */ + ctx->mouse_event_class = (moo_oop_class_t)moo_findclass (moo, ctx->x11_class->nsdic, name_mouse_event); + if (!ctx->mouse_event_class) + { + MOO_DEBUG0 (moo, "X11.MouseEvent class not found\n"); + goto oops; + } + ctx->key_event_class = (moo_oop_class_t)moo_findclass (moo, ctx->x11_class->nsdic, name_key_event); + + if (!ctx->key_event_class) + { + MOO_DEBUG0 (moo, "X11.KeyEvent class not found\n"); + goto oops; + } + + mod->gc = x11_gc; + mod->ctx = ctx; + } + mod->import = x11_import; mod->query = x11_query; mod->unload = x11_unload; - mod->ctx = MOO_NULL; + return 0; } @@ -307,8 +440,9 @@ int moo_mod_x11 (moo_t* moo, moo_mod_t* mod) static moo_pfinfo_t x11_win_pfinfo[] = { - { I, { '_','m','a','k','e','_','o','n',':','\0' }, 0, pf_win_make_on }, - { I, { '_','k','i','l','l','_','o','n',':','\0' }, 0, pf_win_kill_on } + { I, { '_','g','e','t','_','i','d','\0' }, 0, pf_win_get_id }, + { I, { '_','k','i','l','l','_','o','n',':','\0' }, 0, pf_win_kill_on }, + { I, { '_','m','a','k','e','_','o','n',':','\0' }, 0, pf_win_make_on } }; static int x11_win_import (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class) @@ -325,7 +459,7 @@ static moo_pfimpl_t x11_win_query (moo_t* moo, moo_mod_t* mod, const moo_ooch_t* static void x11_win_unload (moo_t* moo, moo_mod_t* mod) { - /* TODO: anything? */ + /* anything? */ } int moo_mod_x11_win (moo_t* moo, moo_mod_t* mod) @@ -333,6 +467,8 @@ int moo_mod_x11_win (moo_t* moo, moo_mod_t* mod) mod->import = x11_win_import; mod->query = x11_win_query; mod->unload = x11_win_unload; + mod->gc = MOO_NULL; mod->ctx = MOO_NULL; + return 0; }