diff --git a/components/json/src/json.c b/components/json/src/json.c index 1dff56c5..2e195e3e 100644 --- a/components/json/src/json.c +++ b/components/json/src/json.c @@ -73,7 +73,7 @@ static cx_int16 serializePrimitive(cx_serializer s, cx_value *v, void *userData) CX_UNUSED(s); cx_type type = cx_valueType(v); cx_json_ser_t *data = userData; - cx_int16 result; + cx_int16 result = 0; cx_string valueString; switch (cx_primitive(type)->kind) { diff --git a/packages/corto/ast/src/ast_While.c b/packages/corto/ast/src/ast_While.c index 38b4e46c..43bb8d02 100644 --- a/packages/corto/ast/src/ast_While.c +++ b/packages/corto/ast/src/ast_While.c @@ -42,7 +42,7 @@ cx_int16 _ast_While_construct(ast_While this) { ic_node _ast_While_toIc_v(ast_While this, ic_program program, ic_storage storage, cx_bool stored) { /* $begin(::corto::ast::While::toIc) */ ic_storage accumulator; - ic_label labelEval, labelNeq; + ic_label labelEval, labelNeq = NULL; ast_Expression condition = NULL; cx_bool condResult = FALSE, inverse = FALSE; ic_node expr = NULL; diff --git a/packages/corto/lang/include/cx_rbtree.h b/packages/corto/lang/include/cx_rbtree.h index 0807714e..12c3ec69 100644 --- a/packages/corto/lang/include/cx_rbtree.h +++ b/packages/corto/lang/include/cx_rbtree.h @@ -22,8 +22,10 @@ void cx_rbtreeFree(cx_rbtree tree); void* cx_rbtreeGet(cx_rbtree tree, void* key); void* cx_rbtreeGetPtr(cx_rbtree tree, void* key); void cx_rbtreeSet(cx_rbtree tree, const void* key, void* value); +void* cx_rbtreeFindOrSet(cx_rbtree tree, const void* key, void* value); void cx_rbtreeRemove(cx_rbtree tree, void* key); cx_bool cx_rbtreeHasKey(cx_rbtree tree, const void* key, void** value); +cx_bool cx_rbtreeHasKey_w_cmp(cx_rbtree tree, const void* key, void** value, cx_equalsAction cmp); void* cx_rbtreeMin(cx_rbtree tree, void** key_out); void* cx_rbtreeMax(cx_rbtree tree, void** key_out); void* cx_rbtreeNext(cx_rbtree tree, void* key, void** key_out); diff --git a/packages/corto/lang/src/cx_copy_ser.c b/packages/corto/lang/src/cx_copy_ser.c index 53e5803b..25fe61f6 100644 --- a/packages/corto/lang/src/cx_copy_ser.c +++ b/packages/corto/lang/src/cx_copy_ser.c @@ -175,7 +175,7 @@ static void cx_collection_resizeArray(cx_collection t, void* sequence, cx_uint32 static cx_int16 cx_ser_collection(cx_serializer s, cx_value *info, void* userData) { cx_type t1, t2; void *v1, *v2; - cx_uint32 size1; + cx_uint32 size1 = 0; cx_copy_ser_t *data = userData; cx_uint32 result = 0; diff --git a/packages/corto/lang/src/cx_object.c b/packages/corto/lang/src/cx_object.c index 1d128aed..acf0f6a4 100644 --- a/packages/corto/lang/src/cx_object.c +++ b/packages/corto/lang/src/cx_object.c @@ -34,7 +34,7 @@ extern cx_mutex_s cx_adminLock; -static int cx_adopt(cx_object parent, cx_object child); +static cx_object cx_adopt(cx_object parent, cx_object child); static cx_int32 cx_notify(cx__observable *_o, cx_object observable, cx_uint32 mask); static void cx_notifyObserverDefault(cx__observer* data, cx_object this, cx_object observable, cx_object source, cx_uint32 mask); @@ -247,9 +247,10 @@ static void* cx__objectStartAddr(cx__object* o) { } /* Initialze scope-part of object */ -static cx_int16 cx__initScope(cx_object o, cx_string name, cx_object parent) { +static cx_object cx__initScope(cx_object o, cx_string name, cx_object parent) { cx__object* _o; cx__scope* scope; + cx_object result = NULL; _o = CX_OFFSET(o, -sizeof(cx__object)); scope = cx__objectScope(_o); @@ -260,13 +261,18 @@ static cx_int16 cx__initScope(cx_object o, cx_string name, cx_object parent) { cx_rwmutexNew(&scope->scopeLock); /* Add object to the scope of the parent-object */ - if (cx_adopt(parent, o)) { + if (!(result = cx_adopt(parent, o))) { goto error; } - return 0; + if (result != o) { + cx_dealloc(scope->name); + cx_rwmutexFree(&scope->scopeLock); + } + + return result; error: - return -1; + return NULL; } static void cx__deinitScope(cx_object o) { @@ -497,7 +503,7 @@ int cx__adoptSSO(cx_object sso) { /* Reset the parent to NULL, since cx_adopt will otherwise conclude that this object is adopted twice */ scope->parent = NULL; - return cx_adopt(parent, sso); + return !cx_adopt(parent, sso); } /* Find the right constructor to call */ @@ -554,7 +560,6 @@ int cx__destructor(cx_object o) { return -1; } -/* Set state on object */ void cx__setState(cx_object o, cx_uint8 state) { cx__object* _o; @@ -568,6 +573,44 @@ static cx_equalityKind cx_objectCompare(cx_type this, const void* o1, const void return ((r = stricmp(o1, o2)) < 0) ? CX_LT : (r > 0) ? CX_GT : CX_EQ; } +#include "ctype.h" +static cx_equalityKind cx_objectCompareLookup(cx_type this, const void* o1, const void* o2) { + CX_UNUSED(this); + int r; + const char *ptr1, *ptr2; + ptr1 = o1; + ptr2 = o2; + char ch1, ch2; + + ch2 = *ptr2; + while((ch1 = *ptr1) && ch2) { + if (ch1 == ch2) { + if (ch1 == '(') { + r = 0; + goto compare; + } + ptr1++; ptr2++; + ch2 = *ptr2; + continue; + } + if (ch1 < 97) ch1 = tolower(ch1); + + /* Query is always made lower case, for efficiency reasons */ + /* if (ch2 < 97) ch2 = tolower(ch2); */ + if (ch1 != ch2) { + r = ch1 - ch2; + goto compare; + } + ptr1++; + ptr2++; + ch2 = *ptr2; + } + + r = ch1 - ch2; +compare: + return (r < 0) ? CX_LT : (r > 0) ? CX_GT : CX_EQ; +} + /* Match a state exclusively: * CX_DECLARED - CX_DECLARED | CX_DEFINED * CX_DECLARED X @@ -590,7 +633,7 @@ static cx_bool cx__checkStateXOR(cx_object o, cx_uint8 state) { } /* Adopt an object */ -static int cx_adopt(cx_object parent, cx_object child) { +static cx_object cx_adopt(cx_object parent, cx_object child) { cx__object *_parent, *_child; cx__scope *p_scope, *c_scope; cx_type parentType; @@ -644,7 +687,15 @@ static int cx_adopt(cx_object parent, cx_object child) { if (!p_scope->scope) { p_scope->scope = cx_rbtreeNew_w_func(cx_objectCompare); } - cx_rbtreeSet(p_scope->scope, c_scope->name, child); + + cx_object existing = cx_rbtreeFindOrSet(p_scope->scope, c_scope->name, child); + if (existing) { + if (cx_typeof(existing) != cx_typeof(child)) { + goto err_type_mismatch; + } else { + child = existing; + } + } /* Parent must not be deleted before all childs are gone. */ cx_claim(parent); @@ -656,31 +707,37 @@ static int cx_adopt(cx_object parent, cx_object child) { goto err_no_parent_scope; } - return 0; + return child; err_child_mutex: cx_critical("cx_adopt: lock operation on scopeLock of child failed"); - return -1; + return NULL; err_parent_mutex: cx_critical("cx_adopt: lock operation on scopeLock of parent failed"); - return -1; + return NULL; err_already_adopted: cx_rwmutexUnlock(&c_scope->scopeLock); cx_seterr("cx_adopt: child-object is already adopted"); - return -1; + return NULL; + +err_type_mismatch: + cx_rwmutexUnlock(&p_scope->scopeLock); + cx_critical("'%s' is already declared with a different type", + c_scope->name); + return NULL; err_no_parent_scope: cx_critical("cx_adopt: parent-object is not scoped"); - return -1; + return NULL; err_no_child_scope: cx_critical("cx_adopt: child-object is not scoped"); - return -1; + return NULL; err_invalid_parent: - return -1; + return NULL; } void cx_attach(cx_object parent, cx_object child) { @@ -911,7 +968,7 @@ cx_object _cx_declare(cx_type type) { } else { cx_seterr("%s::init failed", cx_fullname(type, id)); } - goto error; + goto error_init; } /* Add object to anonymous cache */ @@ -925,6 +982,8 @@ cx_object _cx_declare(cx_type type) { } return CX_OFFSET(o, sizeof(cx__object)); +error_init: + cx_release(type); error: if (o) cx_dealloc(cx__objectObservable(o)); return NULL; @@ -938,26 +997,19 @@ cx_object _cx_declareChild(cx_object parent, cx_string name, cx_type type) { parent = root_o; } - /* Check if object already exists */ - if ((o = cx_lookup(parent, name))) { - if (cx_typeof(o) != type) { - cx_seterr("object already declared with different type"); - o = NULL; - goto error; - } - cx__scope *scope = cx__objectScope(CX_OFFSET(o, -sizeof(cx__object))); - cx_ainc(&scope->declared); - } else { - /* Create new object */ - cx_attr oldAttr = cx_setAttr(cx_getAttr()|CX_ATTR_SCOPED); - o = cx_declare(type); - cx_setAttr(oldAttr); + /* Create new object */ + cx_attr oldAttr = cx_setAttr(cx_getAttr()|CX_ATTR_SCOPED); + o = cx_declare(type); + cx_setAttr(oldAttr); + + if (o) { + cx_object o_ret = NULL; + cx__object *_o = CX_OFFSET(o, -sizeof(cx__object)); + /* Initialize object parameters. */ - if (o) { - cx__object *_o = CX_OFFSET(o, -sizeof(cx__object)); - /* Initialize object parameters. */ - if (!cx__initScope(o, name, parent)) { + if ((o_ret = cx__initScope(o, name, parent))) { + if (o_ret == o) { /* Observable administration needs to be initialized after the * scope administration because it needs to setup the correct * chain of parents to notify on an event. */ @@ -980,17 +1032,24 @@ cx_object _cx_declareChild(cx_object parent, cx_string name, cx_type type) { /* Initially, an object is valid and declared */ _o->attrs.state |= CX_VALID; } else { - cx__deinitScope(o); + cx_release(type); cx_dealloc(cx__objectStartAddr(CX_OFFSET(o,-sizeof(cx__object)))); - o = NULL; - goto error; + o = o_ret; + goto ok; } - - /* Notify parent of new object */ - cx_notify(cx__objectObservable(CX_OFFSET(parent,-sizeof(cx__object))), o, CX_ON_DECLARE); + } else { + cx__deinitScope(o); + cx_release(type); + cx_dealloc(cx__objectStartAddr(CX_OFFSET(o,-sizeof(cx__object)))); + o = NULL; + goto error; } + + /* Notify parent of new object */ + cx_notify(cx__objectObservable(CX_OFFSET(parent,-sizeof(cx__object))), o, CX_ON_DECLARE); } +ok: return o; error: if (o) { @@ -1844,7 +1903,7 @@ void cx_drop(cx_object o) { } } -cx_object cx_lookup(cx_object o, cx_string name) { +cx_object cx_lookupLowercase(cx_object o, cx_string name) { cx_object result; cx__object *_o, *_result; cx__scope* scope; @@ -1856,7 +1915,7 @@ cx_object cx_lookup(cx_object o, cx_string name) { if (scope) { cx_rwmutexRead(&scope->scopeLock); if ((tree = scope->scope)) { - if ((!cx_rbtreeHasKey(tree, name, (void**)&result))) { + if ((!cx_rbtreeHasKey_w_cmp(tree, name, (void**)&result, cx_objectCompareLookup))) { result = NULL; } else { /* Keep object. If the refcount was zero, this object will be deleted soon, so prevent the object from being referenced again. */ @@ -1889,6 +1948,15 @@ cx_object cx_lookup(cx_object o, cx_string name) { return NULL; } +cx_object cx_lookup(cx_object o, cx_string name) { + cx_id lower; + char *ptr = name, ch; + char *bptr = lower; + for(; (ch = *ptr); ptr++) *(bptr++) = tolower(ch); + *bptr = '\0'; + return cx_lookupLowercase(o, lower); +} + /* Event handling. */ static cx__observer* cx_observerFind(cx_ll on, cx_observer observer, cx_object this) { cx__observer* result; @@ -3182,7 +3250,7 @@ cx_int16 cx_overload(cx_object object, cx_string requested, cx_int32* distance) } /* Validate if names of request and offered match */ - if (strcmp(o_name, r_name)) { + if (stricmp(o_name, r_name)) { goto nomatch; } @@ -3279,7 +3347,7 @@ int cx_lookupFunctionWalk(cx_object o, void* userData) { } else { cx_id name; cx_signatureName(cx_nameof(o), name); /* Obtain function name */ - if (!strcmp(name, data->request)) { + if (!stricmp(name, data->request)) { d = INT_MAX-1; } } @@ -3763,3 +3831,4 @@ cx_int16 cx_copya(cx_any *dst, cx_any src) { dst->type = src.type; return result; } + diff --git a/packages/corto/lang/src/cx_rbtree.c b/packages/corto/lang/src/cx_rbtree.c index 196da462..50ea51e9 100644 --- a/packages/corto/lang/src/cx_rbtree.c +++ b/packages/corto/lang/src/cx_rbtree.c @@ -39,7 +39,13 @@ void* cx_rbtreeGetPtr(cx_rbtree tree, void* key) { } void cx_rbtreeSet(cx_rbtree tree, const void* key, void* value) { - jsw_rbinsert((jsw_rbtree_t*)tree, (void*)key, value); + jsw_rbinsert((jsw_rbtree_t*)tree, (void*)key, value, NULL, TRUE); +} + +void* cx_rbtreeFindOrSet(cx_rbtree tree, const void* key, void* value) { + void *old = NULL; + jsw_rbinsert((jsw_rbtree_t*)tree, (void*)key, value, &old, FALSE); + return old; } void cx_rbtreeRemove(cx_rbtree tree, void* key) { @@ -50,6 +56,10 @@ cx_bool cx_rbtreeHasKey(cx_rbtree tree, const void* key, void** value) { return jsw_rbhaskey((jsw_rbtree_t*)tree, key, value); } +cx_bool cx_rbtreeHasKey_w_cmp(cx_rbtree tree, const void* key, void** value, cx_equalsAction cmp) { + return jsw_rbhaskey_w_cmp((jsw_rbtree_t*)tree, key, value, cmp); +} + cx_uint32 cx_rbtreeSize(cx_rbtree tree) { return jsw_rbsize((jsw_rbtree_t*)tree); } diff --git a/packages/corto/lang/src/cx_resolver.c b/packages/corto/lang/src/cx_resolver.c index 93504a91..b2799a1d 100644 --- a/packages/corto/lang/src/cx_resolver.c +++ b/packages/corto/lang/src/cx_resolver.c @@ -35,6 +35,10 @@ static cx_object cx_resolveAddress(cx_string str) { return (cx_object)addr; } +/* Use private function to do a lookup with a string that is guaranteed lowercase */ +#include "ctype.h" +cx_object cx_lookupLowercase(cx_object o, cx_string name); + /* Resolve fully scoped name */ cx_object cx_resolve(cx_object _scope, cx_string str) { cx_object scope, _scope_start, o, lookup; @@ -99,13 +103,13 @@ cx_object cx_resolve(cx_object _scope, cx_string str) { bptr = buffer; while ((ch = *ptr) && (ch != ':') && (ch != '{') && (ch != '/')) { - *bptr = ch; + *bptr = tolower(ch); bptr++; ptr++; if (ch == '(') { overload = TRUE; while ((ch = *ptr) && (ch != ')')) { - *bptr = ch; + *bptr = tolower(ch); bptr++; ptr++; } @@ -118,10 +122,7 @@ cx_object cx_resolve(cx_object _scope, cx_string str) { cx_object prev = o; int i; for (i = 0; i < 2; i++) { - o = cx_lookup(o, buffer); - if (!o) { - o = cx_lookupFunction(prev, buffer, NULL); - } + o = cx_lookupLowercase(o, buffer); if (lookup) { cx_release(lookup); /* Free reference */ } diff --git a/packages/corto/lang/src/jsw_rbtree.c b/packages/corto/lang/src/jsw_rbtree.c index cb10bd45..9a9c516a 100644 --- a/packages/corto/lang/src/jsw_rbtree.c +++ b/packages/corto/lang/src/jsw_rbtree.c @@ -288,11 +288,16 @@ void *jsw_rbfindPtr ( jsw_rbtree_t *tree, void *key ) */ int jsw_rbhaskey ( jsw_rbtree_t *tree, const void *key, void** data ) +{ + return jsw_rbhaskey_w_cmp( tree, key, data, tree->cmp ); +} + +int jsw_rbhaskey_w_cmp ( jsw_rbtree_t *tree, const void *key, void** data, cx_equalsAction f_cmp ) { jsw_rbnode_t *it = tree->root; while ( it != NULL ) { - int cmp = tree->cmp ( tree->type, it->key, key ); + int cmp = f_cmp ( tree->type, it->key, key ); if ( cmp == 0 ) break; @@ -310,20 +315,29 @@ int jsw_rbhaskey ( jsw_rbtree_t *tree, const void *key, void** data ) return !(it == NULL); } + /** Insert a copy of the user-specified data into a red black tree + old_out and overwrite allow the function + to be used as a find-or-insert. The tree to insert into The data value to insert + The old value + Is overwriting allowed 1 if the value was inserted successfully, 0 if the insertion failed for any reason */ -int jsw_rbinsert ( jsw_rbtree_t *tree, void* key, void *data ) +int jsw_rbinsert ( jsw_rbtree_t *tree, void* key, void *data, void **old_out, cx_bool overwrite ) { + + if (old_out) + *old_out = NULL; + if ( tree->root == NULL ) { /* We have an empty tree; attach the @@ -371,16 +385,19 @@ int jsw_rbinsert ( jsw_rbtree_t *tree, void* key, void *data ) t->link[dir2] = jsw_double ( g, !last ); } - /* TODO: time is wasted here: reduce number of compare functions to 1 */ /* Stop working if we inserted a node. This check also disallows duplicates in the tree */ - if ( tree->cmp ( tree->type, q->key, key ) == 0 ) + cx_equalityKind eq = tree->cmp ( tree->type, q->key, key ); + if ( eq == 0 ) { + if (old_out) + *old_out = q->data; break; + } last = dir; - dir = tree->cmp ( tree->type, q->key, key ) < 0; + dir = eq < 0; /* Move the helpers down */ if ( g != NULL ) @@ -440,13 +457,14 @@ int jsw_rberase ( jsw_rbtree_t *tree, void *key ) /* Move the helpers down */ g = p, p = q; q = q->link[dir]; - dir = tree->cmp ( tree->type, q->key, key ) < 0; + cx_equalityKind eq = tree->cmp ( tree->type, q->key, key ); + dir = eq < 0; /* Save the node with matching data and keep going; we'll do removal tasks at the end */ - if ( tree->cmp ( tree->type, q->key, key ) == 0 ) + if ( eq == 0 ) f = q; /* Push the red node down with rotations and color flips */ diff --git a/packages/corto/lang/src/jsw_rbtree.h b/packages/corto/lang/src/jsw_rbtree.h index 5dcf6cd7..398d958e 100644 --- a/packages/corto/lang/src/jsw_rbtree.h +++ b/packages/corto/lang/src/jsw_rbtree.h @@ -62,7 +62,8 @@ cx_type jsw_rbtype( jsw_rbtree_t *tree); void *jsw_rbfind ( jsw_rbtree_t *tree, void *key ); void *jsw_rbfindPtr ( jsw_rbtree_t *tree, void *key ); int jsw_rbhaskey ( jsw_rbtree_t *tree, const void *key, void** data ); -int jsw_rbinsert ( jsw_rbtree_t *tree, void* key, void *data ); +int jsw_rbhaskey_w_cmp ( jsw_rbtree_t *tree, const void *key, void** data, cx_equalsAction f_cmp ); +int jsw_rbinsert ( jsw_rbtree_t *tree, void* key, void *data, void **old_out, cx_bool overwrite ); int jsw_rberase ( jsw_rbtree_t *tree, void *key ); size_t jsw_rbsize ( jsw_rbtree_t *tree );