corto_int16 corto_value_memberExpr(corto_value *val, corto_string member, corto_value *out) { corto_type t = corto_value_typeof(val); corto_object o = corto_value_objectof(val); void *ptr = corto_value_ptrof(val); corto_id tokens; strncpy(tokens, member, sizeof(corto_id)); char *cur = tokens, *prev = tokens; do { if (cur && (cur = strchr(cur + 1, '.'))) *cur = '\0'; if (!corto_instanceof(corto_interface_o, t)) { corto_seterr( "cannot get member from a non-composite value (type is '%s')", corto_fullpath(NULL, t)); goto error; } if (!strcmp(prev, "super")) { if (!(t = (corto_type)corto_interface(t)->base)) { corto_seterr("super unpexpected: interface '%s' does not have a base", corto_fullpath(NULL, t)); goto error; } else { *out = corto_value_base(ptr, t); } } else { corto_member m = corto_interface_resolveMember(t, prev); if (!m) { corto_seterr( "unresolved member '%s' in type '%s'", prev, corto_fullpath(NULL, t)); goto error; } ptr = CORTO_OFFSET(ptr, m->offset); t = m->type; *out = corto_value_member(o, m, ptr); } prev = cur + 1; } while (cur); return 0; error: return -1; }
bool _corto_delegate_compatible( corto_delegate _this, corto_type type) { static corto_uint32 _methodId; corto_method _method; bool _result; corto_interface _abstract; _abstract = corto_interface(corto_typeof(_this)); /* Determine methodId once, then cache it for subsequent calls. */ if (!_methodId) { _methodId = corto_interface_resolveMethodId(_abstract, "compatible(type type)"); } corto_assert(_methodId, "virtual 'compatible(type type)' not found in '%s'%s%s", corto_fullpath(NULL, _abstract), corto_lasterr() ? ": " : "", corto_lasterr() ? corto_lasterr() : ""); /* Lookup method-object. */ _method = corto_interface_resolveMethodById(_abstract, _methodId); corto_assert(_method != NULL, "unresolved method '%s::compatible(type type)@%d'", corto_idof(_this), _methodId); if (corto_function(_method)->kind == CORTO_PROCEDURE_CDECL) { _result = ((bool ___ (*)(corto_object, corto_type))((corto_function)_method)->fptr)(_this, type); } else { corto_call(corto_function(_method), &_result, _this, type); } return _result; }
corto_int16 corto_ptr_binaryOp(corto_type type, corto_operatorKind operator, void *operand1, void *operand2, void *result) { if (type->kind == CORTO_PRIMITIVE) { corto__binaryOperator impl = corto_binaryOps[corto_primitive(type)->convertId][operator]; if (impl) { impl(operand1, operand2, result); } else { corto_seterr("binary operator '%s' is not implemented for type '%s'", corto_idof(corto_enum_constant(corto_operatorKind_o, operator)), corto_fullpath(NULL, type)); goto error; } } else if (operator == CORTO_ASSIGN) { corto_ptr_copy(operand1, type, operand2); if (result && result != operand1) { corto_ptr_copy(result, type, operand1); } } else { corto_seterr("invalid operand for non-scalar type"); goto error; } return 0; error: return -1; }
static corto_type corto_valueExpr_getType(corto_type src, corto_type target, corto_bool targetIsRef) { corto_type result = src; if (!src) { if (target) { if (target->reference) { result = target; } else if ((target->kind == CORTO_PRIMITIVE) && (corto_primitive(target)->kind == CORTO_TEXT)) { result = corto_type(corto_string_o); } else { if (targetIsRef) { result = target; } else { corto_seterr( "invalid usage of null with non-string and non-reference type '%s'", corto_fullpath(NULL, target)); goto error; } } } else { result = corto_void_o; } } else if ((target && (target->kind == CORTO_VOID) && target->reference)) { result = corto_object_o; } return result; error: return NULL; }
void* _dDDS_getEntity(corto_object o, corto_type type) { void* result = NULL; if (o && corto_instanceof(type, o)) { result = corto_olsGet(o, DDDS_ENTITY_HANDLE); if (!result) { corto_seterr("%s contains an invalid handle", corto_fullpath(NULL, o)); } } else { corto_seterr("%s is not of type %s", corto_fullpath(NULL, o), corto_fullpath(NULL, type)); } return result; }
corto_bool corto_authorized(corto_object object, corto_secure_actionKind access) { if (corto_checkAttr(object, CORTO_ATTR_NAMED)) { corto_id objectId; corto_fullpath(objectId, object); return corto_authorizedId(objectId, access); } else { return TRUE; } }
void printAttr(corto_object o) { printf("attributes of %s: ", corto_fullpath(NULL, o)); if (corto_checkAttr(o, CORTO_ATTR_SCOPED)) printf("S"); if (corto_checkAttr(o, CORTO_ATTR_WRITABLE)) printf("W"); if (corto_checkAttr(o, CORTO_ATTR_OBSERVABLE)) printf("O"); if (corto_checkAttr(o, CORTO_ATTR_PERSISTENT)) printf("P"); if (corto_attrof(o) == 0) { printf("none"); } printf("\n"); }
corto_int16 corto_binaryOperator(corto_type type, corto_operatorKind operator, void *operand1, void *operand2, void *result) { if (type->kind == CORTO_PRIMITIVE) { corto__binaryOperator impl = corto_binaryOps[corto_primitive(type)->convertId][operator]; if (impl) { impl(operand1, operand2, result); } else { corto_seterr("binary operator '%s' is not implemented for type '%s'", corto_idof(corto_enum_constant(corto_operatorKind_o, operator)), corto_fullpath(NULL, type)); goto error; } } return 0; error: return -1; }
corto_function corto_valueFunction(corto_value* val) { corto_function result; switch(val->kind) { case CORTO_OBJECT: if (corto_class_instanceof(corto_procedure_o, corto_typeof(val->is.object.o))) { result = val->is.object.o; } else { corto_seterr("object '%s' in value is not a function", corto_fullpath(NULL, val->is.object.o)); result = NULL; } break; default: corto_seterr("value does not represent a function"); result = NULL; break; } return result; }
* * This example shows basic usage of core API functions to create, update * and delete objects. */ /* Callback for observer */ void onUpdate( corto_object this, corto_eventMask event, corto_object o, corto_observer observer) { /* Show information about the object that triggered the observer */ printf("update received for id='%s' parent='%s' type='%s' value='%d'\n", corto_idof(o), corto_fullpath(NULL, corto_parentof(o)), corto_fullpath(NULL, corto_typeof(o)), *corto_int32(o)); } int objectsMain(int argc, char *argv[]) { /* Create a signed integer object in the global object hierarchy */ corto_int32 *i = corto_createChild(root_o, "i", corto_int32_o); if (!i) { goto error; } /* Observe the object for updates */ corto_observer observer = corto_observe(CORTO_ON_UPDATE, i).callback(onUpdate);
/* Deserialize string in object */ corto_string corto_string_deser(corto_string str, corto_string_deser_t* data) { corto_char *ptr; corto_bool createdNew = FALSE; { corto_id buffer; corto_char *bptr, ch; /* Parse typename that potentially precedes string */ bptr = buffer; ptr = str; while((ch = *ptr) && (ch != '{')) { if (!((ch == ' ') || (ch == '\n') || (ch == '\t'))) { *bptr = ch; bptr++; } ptr++; } *bptr = '\0'; /* If no type is found, reset ptr */ if ((ch != '{') || (ptr == str)) { ptr = str; } else { corto_object type; /* If no out is provided create an object of the specified type */ if ((bptr != buffer)) { type = corto_resolve(NULL, buffer); if (type) { if (data->type && (type != data->type)) { corto_seterr( "type of object ('%s') does not match string ('%s')", corto_fullpath(NULL, data->type), corto_fullpath(NULL, type)); corto_release(type); goto error; } if (corto_instanceof(corto_type(corto_type_o), type)) { if (!data->out) { data->out = corto_declare(type); createdNew = TRUE; } data->type = type; } else { corto_seterr("'%s' is not a type", buffer); corto_release(type); goto error; } corto_release(type); } else { corto_seterr("unknown type '%s'", buffer); goto error; } } else { type = data->type; } if (type && (corto_type(type)->kind == CORTO_PRIMITIVE)) { ptr++; } } } data->current = 0; data->index = NULL; data->ptr = data->out; data->anonymousObjects = NULL; data->allocValue = NULL; data->allocUdata = NULL; if (data->out && data->isObject) { if (!data->type) { data->type = corto_typeof(data->out); } else if (!corto_instanceofType(corto_typeof(data->out), data->type)) { corto_seterr("object '%s' of type '%s' is not an instance of type '%s'", corto_fullpath(NULL, data->out), corto_fullpath(NULL, corto_typeof(data->out)), corto_fullpath(NULL, data->type)); goto error; } } if (!data->type) { corto_seterr("no type provided for '%s'", str); goto error; } if (data->type->kind == CORTO_PRIMITIVE) { ptr = corto_string_deserParse(ptr, NULL, data); } else { ptr = corto_string_deserParseScope(ptr, NULL, data); if (ptr) { ptr ++; } } if (!ptr) { if (!corto_lasterr()) { corto_seterr("failed to deserialize '%s'", str); } else { corto_seterr("failed to deserialize '%s': %s", str, corto_lasterr()); } goto error; } if (data->anonymousObjects) { corto_ll_free(data->anonymousObjects); } return ptr; error: if (data->out) { if (createdNew) { corto_release(data->out); } data->out = NULL; } return NULL; }
/* Parse string */ static corto_string corto_string_deserParse( corto_string str, struct corto_string_deserIndexInfo* info, corto_string_deser_t* data) { corto_char ch; corto_char *ptr, *bptr, *nonWs; corto_char buffer[CORTO_STRING_DESER_TOKEN_MAX]; /* TODO: dangerous in a recursive function */ corto_bool proceed, excess; struct corto_string_deserIndexInfo* memberInfo; CORTO_UNUSED(info); ptr = str; bptr = buffer; nonWs = bptr; proceed = TRUE; excess = FALSE; memberInfo = NULL; if (info) { memberInfo = corto_string_deserIndexNext(data); } /* If ptr == NULL, an error has occurred. If proceed == FALSE, this function * has finished processing the current value. */ while(ptr && (ch = *ptr) && proceed) { switch(ch) { case '=': /* Explicit member assignment */ excess = FALSE; if (buffer == bptr) { corto_seterr("missing member identifier"); goto error; } else { *nonWs = '\0'; memberInfo = corto_string_deserIndexLookup(buffer, data); bptr = buffer; nonWs = bptr; if (!memberInfo) { corto_seterr("member '%s' not found in type '%s'", buffer, corto_fullpath(NULL, data->type)); goto error; } break; } case '{': /* Scope open */ if (bptr == buffer) { if (!(ptr = corto_string_deserParseScope( ptr, memberInfo, data))) { goto error; } } else { *bptr = '\0'; if (!(ptr = corto_string_parseAnonymous( ptr, buffer, memberInfo, data))) { goto error; } bptr = buffer; } break; case '}': /* Scope close and end of value */ if (buffer != bptr) { *nonWs = '\0'; if (memberInfo && (data->type->kind != CORTO_PRIMITIVE)) { if (corto_string_deserParseValue(buffer, memberInfo, data)) { goto error; } bptr = buffer; nonWs = bptr; } } proceed = FALSE; ptr--; break; case '(': /* If a value is being parsed, the '(' is part of an argument list. * Parse up until the matching ')' */ if (bptr != buffer) { char *start = ptr; /* Parse until matching '} */ do { *bptr = ch; bptr++; ptr++; } while((ch = *ptr) && (ch == ')')); ptr--; nonWs = bptr; /* ptr must always end with a '}' */ if (*ptr != ')') { corto_seterr("missing ')' at '%s' (%s)", start, ptr); goto error; } } case '"': if (!(ptr = corto_string_deserParseString(ptr, buffer, &bptr))) { goto error; } nonWs = bptr; ptr--; break; case '\'': if (!(ptr = corto_string_deserParseCharacter(ptr+1, buffer))) { goto error; } *(++bptr) = '\0'; nonWs = bptr; break; case '\n': case '\t': case ' ': if (bptr != buffer) { *bptr = ch; bptr++; } break; case ',': /* End of value */ if (buffer != bptr) { *nonWs = '\0'; if (corto_string_deserParseValue(buffer, memberInfo ? memberInfo : info, data)) { goto error; } bptr = buffer; nonWs = bptr; } /* If memberInfo contains a member, get next member, otherwise it contains * an element. The same information applies to each element therefore it is only present * once in the index. */ if (memberInfo) { if (memberInfo->m) { memberInfo = corto_string_deserIndexNext(data); if (!memberInfo) { excess = TRUE; } } data->current++; } else { /* A comma without memberInfo means that a discriminator of a * union was parsed */ proceed = FALSE; } break; default: *bptr = ch; bptr++; nonWs = bptr; break; } if (ptr && *ptr) ptr++; } if (bptr != buffer) { struct corto_string_deserIndexInfo info; *nonWs = '\0'; info.type = data->type; info.parsed = FALSE; info.m = NULL; if (corto_string_deserParseValue(buffer, &info, data)) { goto error; } } if (excess) { corto_seterr("excess elements in string"); goto error; } return ptr; error: return NULL; }
static corto_string corto_string_parseAnonymous( corto_string str, corto_string value, struct corto_string_deserIndexInfo *info, corto_string_deser_t *data) { corto_object o = NULL; char *ptr = str; char *valuePtr = value; corto_uint32 index = 0; void *offset; if (corto_string_getDestinationPtr(info, data, &offset)) { corto_seterr("%s: %s", str, corto_lasterr()); goto error; } /* Check if this is a 'named' anonymous object in which case it is * prefixed with <[id]> */ if ((valuePtr = corto_string_deserParseAnonymousId(valuePtr, &index))) { if (data->anonymousObjects && (index <= corto_ll_size(data->anonymousObjects))) { if (!*valuePtr) { o = corto_ll_get(data->anonymousObjects, index - 1); corto_claim(o); } else { /* If the <n> is followed up with more data, a new anonymous * object is being created while one existed already with the * specified number */ corto_seterr("identifier <%d> is already defined (%s)", index, value); goto error; } } } else { valuePtr = value; } /* If no object has been referenced, create an anonymous object */ if (!o && *valuePtr) { corto_object type = corto_resolve(NULL, valuePtr); if (!type) { corto_seterr("unresolved type '%s'", valuePtr); goto error; } if (offset) { o = *(corto_object*)offset; if (!o || (type != corto_typeof(o))) { if (!corto_instanceof(corto_type_o, type)) { corto_seterr("'%s' is not a type", corto_fullpath(NULL, type)); goto error; } o = corto_declare(type); if (!o) { corto_seterr("failed to declare %s: %s", value, corto_lasterr()); goto error; } } else { corto_claim(o); } } corto_string_deser_t privateData = { .out = data->out, // Preserve original out to determine ownership .ptr = o, .type = type, .anonymousObjects = data->anonymousObjects, .scope = data->scope, .isObject = data->isObject }; if (corto_type(type)->kind == CORTO_PRIMITIVE) { ptr ++; if (!(ptr = corto_string_deserParse(ptr, NULL, &privateData))) { goto error; } } else { if (!(ptr = corto_string_deserParseScope(ptr, NULL, &privateData))) { goto error; } } if (o) { if (corto_define(o)) { goto error; } data->anonymousObjects = privateData.anonymousObjects; if (!data->anonymousObjects) { data->anonymousObjects = corto_ll_new(); } corto_ll_append(data->anonymousObjects, o); } } if (offset) corto_ptr_setref(offset, o); if (o) corto_release(o); return ptr; error: if (o) corto_release(o); return NULL; }
/* Parse value */ static corto_int16 corto_string_deserParseValue( corto_string value, struct corto_string_deserIndexInfo* info, corto_string_deser_t* data) { void *offset; if (corto_string_getDestinationPtr(info, data, &offset)) { corto_seterr("%s: %s", value, corto_lasterr()); goto error; } /* No more elements where available in the index, meaning an excess element */ if (!info) { corto_seterr("excess elements in scope @ '%s'", value); goto error; } /* Can typically occur when mixing short with default notation. */ if (info->parsed) { corto_seterr("member '%s' is already parsed", corto_idof(info->m)); goto error; } /* Only parse references and primitives */ if (info->type->reference) { corto_object o = NULL; corto_uint32 index = 0; /* Resolve object */ if (corto_string_deserParseAnonymousId(value, &index)) { if (!index) { if (data->isObject) { o = data->out; corto_claim(o); } else { corto_seterr("cannot refer to self (<0>), not deserializing an object"); goto error; } } else if (data->anonymousObjects && (index <= corto_ll_size(data->anonymousObjects))) { o = corto_ll_get(data->anonymousObjects, index - 1); corto_claim(o); } else { corto_seterr("undefined anonymous identifier '%s'", value); goto error; } } else { o = corto_resolve(data->scope, value); } if (o || !strcmp(value, "null")) { if (offset) corto_ptr_setref(offset, o); if (o) corto_release(o); } else { corto_seterr("unresolved reference to '%s' for member '%s'", value, corto_fullpath(NULL, info->m)); goto error; } } else /* Convert string to primitive value */ if (offset && (info->type->kind == CORTO_PRIMITIVE)) { if (corto_primitive(info->type)->kind != CORTO_TEXT) { if (corto_ptr_cast(corto_primitive(corto_string_o), &value, corto_primitive(info->type), offset)) { goto error; } } else { corto_uint32 length; corto_string deserialized; if (strcmp(value, "null")) { length = strlen(value); deserialized = corto_alloc(length+1); memcpy(deserialized, value, length); deserialized[length] = '\0'; } else { deserialized = NULL; } corto_ptr_setstr(offset, deserialized); } } /* Members are only parsed once */ if (info->m) { info->parsed = TRUE; } return 0; error: return -1; }
static void mqtt_onMessage( struct mosquitto *client, void *data, const struct mosquitto_message *msg) { corto_id nameBuffer; char *name = nameBuffer; corto_object o = NULL; mqtt_Connector this = data; corto_bool isDelete = FALSE; /* If the payload has been serialized as a corto string, the typename is * potentially prefixed to the value */ char *valueStr = strchr(msg->payload, '{'); /* mqtt is the owner of this thread. This ensures that all subsequent create * update / delete actions are performed with the right owner. Ownership * ensures to not trigger on own updates, and to only forward data from * other connectors (or the application). */ corto_object prevOwner = corto_setOwner(this); /* Remove topic from name, so that name is relative to mount point. */ strcpy(name, msg->topic); if (this->topic) { name += strlen(this->topic) + 1; } char *lastElem = strrchr(name, '/'); if (lastElem && !strcmp(lastElem, "/_d")) { *lastElem = '\0'; isDelete = TRUE; } corto_debug("mqtt: %s: received '%s'", msg->topic, msg->payload); /* If object doesn't yet exist in the store, create it */ if (!(o = corto_lookup(corto_mount(this)->mount, name)) && !isDelete) { corto_id buffer; corto_debug("mqtt: creating new object for '%s'", name); /* If the mount has been configured with a fixed type, use that type to * create a new object. Otherwise, look for type in payload. */ if (corto_observer(this)->type) { strcpy(buffer, corto_observer(this)->type); } else { char *typeStr = strchr(msg->payload, '{'); memcpy(buffer, msg->payload, typeStr - (char*)msg->payload); buffer[typeStr - (char*)msg->payload] = '\0'; } /* Resolve type. If type wasn't yet loaded in corto, corto_resolve will * do a lookup on the package repository. If it doesn't exist there * either throw an error. Currently, the MQTT connector does not align * types. */ corto_type type = corto_resolve(NULL, buffer); if (!type) { corto_error("mqtt: type '%s' not found", buffer); goto error; } corto_debug("mqtt: creating '%s' with type '%s'", name, buffer); /* Create a new object under the mountpoint. The name is derived from * the MQTT topic name. */ o = corto_declareChild(corto_mount(this)->mount, name, type); if (!o) { corto_error("mqtt: failed to create object '%s'", name); goto error; } } else { corto_debug("mqtt: found '%s' for '%s'", corto_fullpath(NULL, o), name); } /* Only continue updating object when it is owned by mqtt */ if (o && corto_owned(o)) { if (isDelete) { if (corto_delete(o)) { corto_error("mqtt: failed to delete '%s': %s", name, corto_lasterr()); } corto_release(o); } else { /* Start updating object (takes a writelock) */ if (!corto_updateBegin(o)) { /* Serialize value from JSON string */ if (corto_fromcontent(o, "text/json", valueStr)) { corto_error("mqtt: failed to deserialize for %s: %s (%s)\n", name, corto_lasterr(), msg->payload); /* If deserialization fails, cancel the update. No notification * will be sent. */ corto_updateCancel(o); goto error; } /* Successful update. Send notification and unlock object */ if (corto_updateEnd(o)) { corto_error("mqtt: failed to update '%s': %s", name, corto_lasterr()); goto error; } } else { /* For some reason, couldn't start updating object */ corto_error("mqtt: failed to start updating '%s': %s", name, corto_lasterr()); goto error; } } } else if (o) { corto_debug("mqtt: '%s' not owned by me (%s, defined = %d), ignoring", corto_fullpath(NULL, o), corto_ownerof(o) ? corto_fullpath(NULL, o) : "local", corto_checkState(o, CORTO_DEFINED)); } error: /* Restore previous owner */ corto_setOwner(prevOwner); }
static corto_int16 json_deserComposite(void* p, corto_type t, JSON_Value *v) { corto_assert(t->kind == CORTO_COMPOSITE, "not deserializing composite"); if (json_value_get_type(v) != JSONObject) { corto_seterr("expected object, got %s", json_valueTypeToString(v)); goto error; } JSON_Object* o = json_value_get_object(v); size_t count = json_object_get_count(o); size_t i; corto_bool isUnion = corto_interface(t)->kind == CORTO_UNION; corto_int32 discriminator = 0; corto_member unionMember = NULL; for (i = 0; i < count; i++) { const char* memberName = json_object_get_name(o, i); corto_member member_o; if (!strcmp(memberName, "super")) { JSON_Value* value = json_object_get_value(o, memberName); if (json_deserItem(p, corto_type(corto_interface(t)->base), value)) { goto error; } } else if (!strcmp(memberName, "_d") && isUnion) { JSON_Value* value = json_object_get_value(o, memberName); if (json_deserPrimitive(&discriminator, corto_union(t)->discriminator, value)) { goto error; } unionMember = corto_union_findCase(t, discriminator); if (!unionMember) { corto_seterr("discriminator '%d' invalid for union '%s'", discriminator, corto_fullpath(NULL, t)); } } else { member_o = corto_interface_resolveMember(t, (char*)memberName); /* Ensure that we're not resolving members from a base type */ if (!member_o || (corto_parentof(member_o) != t)) { corto_seterr( "cannot find member '%s' in type '%s'", memberName, corto_fullpath(NULL, t)); goto error; } if (isUnion && (unionMember != member_o)) { corto_seterr( "member '%s' does not match discriminator '%d' (expected member '%s')", memberName, discriminator, corto_idof(unionMember)); goto error; } else if (isUnion) { corto_int32 prev = *(corto_int32*)p; if (prev != discriminator) { corto_member prevMember = corto_union_findCase(t, prev); corto_deinitp(CORTO_OFFSET(p, prevMember->offset), prevMember->type); memset(CORTO_OFFSET(p, member_o->offset), 0, member_o->type->size); } *(corto_int32*)p = discriminator; } if (!json_deserMustSkip(member_o, p)) { JSON_Value* value = json_object_get_value(o, memberName); void *offset = CORTO_OFFSET(p, member_o->offset); if (member_o->modifiers & CORTO_OBSERVABLE) { offset = *(void**)offset; if (json_deserType(offset, member_o->type, value)) { goto error; } } else { if (member_o->modifiers & CORTO_OPTIONAL) { if (*(void**)offset) { corto_deinitp(*(void**)offset, member_o->type); memset(*(void**)offset, 0, member_o->type->size); } else { *(void**)offset = corto_calloc(member_o->type->size); } offset = *(void**)offset; } if (json_deserItem(offset, member_o->type, value)) { goto error; } } } } } return 0; error: return -1; }
void printInfo(corto_object o) { printf("object '%s' created with parent=%s, type=%s\n", corto_fullpath(NULL, o), corto_fullpath(NULL, corto_parentof(o)), corto_fullpath(NULL, corto_typeof(o))); }
/* This is a managed file. Do not delete this comment. */ #include <corto/corto.h> #include "interface.h" int16_t corto_member_construct( corto_member this) { if (!this->type) { corto_seterr("member '%s' has no type", corto_fullpath(NULL, this)); goto error; } if (corto_instanceof(corto_native_type_o, this->type) && !(this->modifiers & CORTO_LOCAL)) { corto_seterr("member '%s' of native type '%s' is not local", corto_fullpath(NULL, this), corto_fullpath(NULL, this->type)); goto error; } if (this->type->flags & CORTO_TYPE_HAS_TARGET) { ((corto_type)corto_parentof(this))->flags |= CORTO_TYPE_HAS_TARGET; } if (corto_typeof(this->type) == (corto_type)corto_target_o) { this->modifiers |= CORTO_OBSERVABLE; }
corto_int16 corto_valueExpr_getTypeForBinary( corto_type leftType, corto_bool t1ByRef, corto_type rightType, corto_bool t2ByRef, corto_operatorKind _operator, corto_type *operandType, corto_type *resultType) { corto_type castType = NULL; corto_bool equal = FALSE; corto_assert(operandType != NULL, "NULL provided for out-parameter operandType"); corto_assert(resultType != NULL, "NULL provided for out-parameter resultType"); /* If operator is condition result type is a boolean */ if (corto_valueExpr_isOperatorConditional(_operator)) { *resultType = corto_type(corto_bool_o); } /* Get leftType and rightType */ if (!(leftType = corto_valueExpr_getType(leftType, NULL, FALSE))) { goto error; } if (!(rightType = corto_valueExpr_getType(rightType, leftType, t1ByRef))) { goto error; } if (!leftType) { leftType = rightType; } /* If objects are not scoped, verify whether they're equal */ if (!corto_checkAttr(leftType, CORTO_ATTR_NAMED) && !corto_checkAttr(rightType, CORTO_ATTR_NAMED)) { if (corto_compare(leftType, rightType) == CORTO_EQ) { equal = TRUE; } } else { equal = leftType == rightType; } if (_operator == CORTO_DIV) { castType = corto_type(corto_float64_o); } else if (!equal) { /* Can only cast between primitive types */ if ((leftType->kind == CORTO_PRIMITIVE ) && (rightType->kind == CORTO_PRIMITIVE)) { corto_primitive ltype = corto_primitive(leftType), rtype = corto_primitive(rightType); corto_int8 lscore, rscore; corto_int8 lCastScore, rCastScore; lscore = corto_valueExpr_getTypeScore(ltype); rscore = corto_valueExpr_getTypeScore(rtype); lCastScore = corto_valueExpr_getCastScore(ltype); rCastScore = corto_valueExpr_getCastScore(rtype); /* If expression is an assignment, always take type of lvalue. * Otherwise determine based on expressibility score which type to * cast to. */ if (corto_valueExpr_isOperatorAssignment(_operator)) { if (lCastScore == rCastScore) { if (ltype->width != rtype->width) { castType = leftType; } } else { castType = leftType; } } else { if (lCastScore == rCastScore) { if (ltype->width == rtype->width) { /* If width and kind are equal, no conversion is required. */ if (lscore > rscore) { *operandType = leftType; } else if (lscore < rscore) { *operandType = rightType; } } else { /* If lvalue has a larger width than rvalue, cast rvalue to leftType (and vice versa) */ if (ltype->width > rtype->width) { castType = leftType; } else { castType = rightType; } } /* If kinds do not match figure a cast is potentially needed. Figure out which type to cast to */ } else { if (lscore > rscore) { castType = leftType; } else { castType = rightType; } } } } else if (leftType->reference && rightType->reference) { castType = NULL; /* Check if types are compatible */ } else if ((rightType->reference || (t2ByRef)) && !leftType->reference) { if (corto_type_castable(leftType, corto_object_o)) { castType = leftType; } } else { corto_seterr("cannot cast from '%s' to '%s'", corto_fullpath(NULL, leftType), corto_fullpath(NULL, rightType)); goto error; } } else if ((rightType->reference || (t2ByRef)) && !leftType->reference) { if (corto_type_castable(leftType, corto_object_o)) { castType = leftType; } } if (!castType) { castType = leftType; } if (castType) { *operandType = castType; } if (!*resultType) { *resultType = *operandType; } return 0; error: return -1; }
/* Parse scope */ static corto_string corto_string_deserParseScope(corto_string str, struct corto_string_deserIndexInfo* info, corto_string_deser_t* data) { struct corto_string_deserIndexInfo rootInfo; corto_typeKind kind; void *ptr = data->ptr; if (data->allocValue) { ptr = data->allocValue(ptr, data); } /* Prepare privateData */ corto_string_deser_t privateData = { .out = data->out, .scope = data->scope, .anonymousObjects = data->anonymousObjects, .type = data->type, .isObject = data->isObject, .members = {0, NULL} }; /* Offset the scope-members with the current offset */ if (info && info->m) { ptr = corto_getMemberPtr(data->isObject ? data->out : NULL, ptr, info->m); } privateData.ptr = ptr; /* Open scope of type */ if (!info) { if (!data->type) { rootInfo.type = corto_typeof(data->out); } else { rootInfo.type = data->type; } rootInfo.m = NULL; rootInfo.parsed = FALSE; info = &rootInfo; } /* Check if type is any, composite or collection */ kind = info->type->kind; if ((kind != CORTO_COMPOSITE) && (kind != CORTO_COLLECTION) && (kind != CORTO_ANY)) { corto_seterr("'{' unexpected for type '%s'", corto_fullpath(NULL, info->type)); goto error; } /* Build index for type */ if (info->type->kind == CORTO_COMPOSITE) { if (corto_interface(info->type)->kind == CORTO_UNION) { /* Parse discriminator */ struct corto_string_deserIndexInfo dInfo; dInfo.type = (corto_type)corto_int32_o; dInfo.parsed = FALSE; dInfo.m = NULL; str = corto_string_deserParse(str + 1, &dInfo, &privateData); if (!str) { goto error; } /* Find corresponding union case */ corto_int32 d = *(corto_int32*)ptr; corto_member m = safe_corto_union_findCase(info->type, d); if (!m) { corto_seterr("discriminator '%d' invalid for union '%s'", d, corto_fullpath(NULL, info->type)); goto error; } /* Build index for one member */ struct corto_string_deserIndexInfo *caseInfo = corto_alloc(sizeof(struct corto_string_deserIndexInfo)); caseInfo->type = m->type; caseInfo->parsed = FALSE; caseInfo->m = m; corto_string_deserIndexInsert(&privateData, caseInfo); } else { corto_walk_opt s = corto_string_deserBuildIndex(); s.members = data->members; if (s.members.length) { s.access = 0; } if (corto_metawalk(&s, info->type, &privateData)) { goto error; } } /* Create iterator for index */ if (privateData.index) { privateData.currentIter = _corto_ll_iter(privateData.index, &privateData.iterData); } /* If type is a collection, build index with one node for element */ } else if (info->type->kind == CORTO_COLLECTION) { struct corto_string_deserIndexInfo *elementNode; elementNode = corto_alloc(sizeof(struct corto_string_deserIndexInfo)); elementNode->m = NULL; elementNode->parsed = FALSE; elementNode->type = corto_collection(info->type)->elementType; corto_string_deserIndexInsert(&privateData, elementNode); /* Create iterator for index */ privateData.currentIter = _corto_ll_iter(privateData.index, &privateData.iterData); privateData.allocValue = corto_string_deserAllocElem; privateData.allocUdata = info->type; if (ptr) { switch(corto_collection(info->type)->kind) { case CORTO_ARRAY: case CORTO_SEQUENCE: break; case CORTO_LIST: if (!*(corto_ll*)ptr) { *(corto_ll*)ptr = corto_ll_new(); } else { corto_ll_clear(*(corto_ll*)ptr); } privateData.ptr = ptr; break; default: break; } } } else if (info->type->kind == CORTO_ANY) { struct corto_string_deserIndexInfo *anyNode; anyNode = corto_alloc(sizeof(struct corto_string_deserIndexInfo)); anyNode->m = NULL; anyNode->parsed = FALSE; anyNode->type = corto_type(corto_type_o); corto_string_deserIndexInsert(&privateData, anyNode); privateData.currentIter = _corto_ll_iter(privateData.index, &privateData.iterData); privateData.allocValue = corto_string_deserAllocAny; privateData.allocUdata = anyNode; } /* Parse scope */ if (!(str = corto_string_deserParse(str+1, info, &privateData))) { goto error; } corto_string_deserFreeIndex(&privateData); data->anonymousObjects = privateData.anonymousObjects; return str; error: return NULL; } /* Get pointer to current destination value */ corto_int16 corto_string_getDestinationPtr( struct corto_string_deserIndexInfo* info, corto_string_deser_t* data, void **ptr_out) { void *result = data->ptr; *ptr_out = NULL; if (!info) { corto_seterr("excess elements in string"); goto error; } if (data->allocValue) { result = data->allocValue(result, data); } if (info->m) { result = corto_getMemberPtr(data->isObject ? data->out : NULL, data->ptr, info->m); } *ptr_out = result; return 0; error: return -1; }