X-Git-Url: http://ecere.com/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ecere%2Fsrc%2Fsys%2FJSON.ec;h=cc793b75192246efb3b66c5e7c7a95c64f7ec59c;hb=7a5018319e9cc4cf293d9128c0fb0095c39c901e;hp=eec1a04cba88ba8503aa38d59c893edc128d474c;hpb=0a3fdc707751ee1e97307810e55eeb1a5f33349f;p=sdk diff --git a/ecere/src/sys/JSON.ec b/ecere/src/sys/JSON.ec index eec1a04..cc793b7 100644 --- a/ecere/src/sys/JSON.ec +++ b/ecere/src/sys/JSON.ec @@ -1,10 +1,11 @@ namespace sys; +import "instance" import "System" import "Array" default: -static void UnusedFunction() +__attribute__((unused)) static void UnusedFunction() { int a; a.OnGetDataFromString(null); @@ -20,7 +21,7 @@ public enum JSONResult { syntaxError, success, typeMismatch, noItem }; public enum SetBool : uint { - unset, false, true /*; // Syntax error! */ + unset, false, true; /*public property bool // NOT WORKING! { @@ -30,15 +31,55 @@ public enum SetBool : uint }; +public class ECONParser : JSONParser +{ + eCON = true; +} + public class JSONParser { public: File f; +private: char ch; + bool eCON; void SkipEmpty() { - while(!f.Eof() && (!ch || ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')) + if(eCON) + { + char pch; + bool lineComment = false; + bool comment = false; + while(!f.Eof() && (!ch || lineComment || comment || ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '/')) + { + pch = ch; + f.Getc(&ch); + if(!lineComment && !comment && pch == '/') + { + if(ch == '/') + lineComment = true; + else if(ch == '*') + comment = true; + } + else if(lineComment && ch == '\n') + lineComment = false; + else if(comment && pch == '*' && ch == '/') + comment = false; + } + } + else + { + while(!f.Eof() && (!ch || ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '/')) + { + f.Getc(&ch); + } + } + } + + void SkipExtraSemicolon() + { + while(!f.Eof() && (!ch || ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == ';')) { f.Getc(&ch); } @@ -60,9 +101,9 @@ public: { value.p = string; } - else if(type && type.type == enumClass) + else if(type && (type.type == enumClass || type.type == unitClass)) { - if(type._vTbl[__ecereVMethodID_class_OnGetDataFromString](type, &value.i, string)) + if(((bool (*)(void *, void *, const char *))(void *)type._vTbl[__ecereVMethodID_class_OnGetDataFromString])(type, &value.i, string)) result = success; else result = typeMismatch; @@ -75,9 +116,14 @@ public: result = success; delete string; } + else if(type && eClass_IsDerived(type, class(ColorAlpha))) + { + result = GetColorAlpha(string, value); + delete string; + } else if(type && (type.type == structClass)) { - if(type._vTbl[__ecereVMethodID_class_OnGetDataFromString](type, value.p, string)) + if(((bool (*)(void *, void *, const char *))(void *)type._vTbl[__ecereVMethodID_class_OnGetDataFromString])(type, value.p, string)) result = success; else result = typeMismatch; @@ -93,9 +139,14 @@ public: else if(ch == '[') { Container array; - result = GetArray(type, &array); - - if(type && eClass_IsDerived(type, class(Container))) + if(type && eClass_IsDerived(type, class(Map))) + { + result = GetMap(type, (Map *)&array); + } + else + result = GetArray(type, &array); + + if(result == success && type && eClass_IsDerived(type, class(Container))) { value.p = array; } @@ -104,7 +155,6 @@ public: if(array) array.Free(); delete array; - result = typeMismatch; } } else if(ch == '-' || isdigit(ch)) @@ -113,61 +163,141 @@ public: } else if(ch == '{') { - void * object; - result = GetObject(type, &object); - if(result) + if(type.type == structClass || type.type == normalClass || type.type == noHeadClass) { - if(type && (type.type == normalClass || type.type == structClass || type.type == noHeadClass || type.type == bitClass)) + void * object = value.p; + result = GetObject(type, &object); + if(result) { - value.p = object; + if(type && type.type == structClass); + else + value.p = object; } - else + } + else if(type.type == bitClass) + { + uint64 object = 0; + result = GetObject(type, (void **)&object); + if(result) + value.ui64 = object; + } + else + { + void * object = value.p; + result = GetObject(type, &object); + if(result) { result = typeMismatch; - type._vTbl[__ecereVMethodID_class_OnFree](object); + if(type) + ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, object); } } } - else if(isalpha(ch)) + else if(isalpha(ch) || ch == '_') { - char buffer[256]; - int c = 0; - while(c < sizeof(buffer)-1 && isalpha(ch)) + if(eCON) { - buffer[c++] = ch; - if(!f.Getc(&ch)) break; - } - buffer[c] = 0; - result = success; - - if(type) - { - if(!strcmp(type.name, "bool")) + String string; + if(GetIdentifier(&string, null)) { - if(!strcmpi(buffer, "false")) value.i = 0; - else if(!strcmpi(buffer, "true")) value.i = 1; + result = success; + if(eCON && type && (type.type == enumClass || type.type == unitClass)) + { + // should this be set by calling __ecereVMethodID_class_OnGetDataFromString ? + if(((bool (*)(void *, void *, const char *))(void *)type._vTbl[__ecereVMethodID_class_OnGetDataFromString])(type, &value.i, string)) + result = success; + else + result = typeMismatch; + } + else if(type && !strcmp(type.name, "bool")) + { + if(!strcmpi(string, "false")) value.i = 0; + else if(!strcmpi(string, "true")) value.i = 1; + else + result = typeMismatch; + } + else if(type && !strcmp(type.name, "SetBool")) + { + if(!strcmpi(string, "false")) value.i = SetBool::false; + else if(!strcmpi(string, "true")) value.i = SetBool::true; + else + result = typeMismatch; + } + else if(type && !strcmpi(string, "null")) + { + if(type.type != structClass) + value.p = 0; + } + else if(isSubclass(type, string)) + { + void * object = value.p; + Class subtype = superFindClass(string, type.module); + SkipEmpty(); + result = GetObject(subtype, &object); + if(result) + { + if(subtype && subtype.type == structClass); + else if(subtype && (subtype.type == normalClass || subtype.type == noHeadClass || subtype.type == bitClass)) + { + value.p = object; + } + else + { + result = typeMismatch; + if(subtype) + ((void (*)(void *, void *))(void *)subtype._vTbl[__ecereVMethodID_class_OnFree])(subtype, object); + } + } + } else result = typeMismatch; } - else if(!strcmp(type.name, "SetBool")) + delete string; + } + else + { + char buffer[256]; + int c = 0; + while(c < sizeof(buffer)-1 && (isalpha(ch) || isdigit(ch) || ch == '_')) { - if(!strcmpi(buffer, "false")) value.i = SetBool::false; - else if(!strcmpi(buffer, "true")) value.i = SetBool::true; - else - result = typeMismatch; + buffer[c++] = ch; + if(!f.Getc(&ch)) break; } - else if(!strcmpi(buffer, "null")) + buffer[c] = 0; + result = success; + + if(type) { - value.p = 0; + if(!strcmp(type.name, "bool")) + { + if(!strcmpi(buffer, "false")) value.i = 0; + else if(!strcmpi(buffer, "true")) value.i = 1; + else + result = typeMismatch; + } + else if(!strcmp(type.name, "SetBool")) + { + if(!strcmpi(buffer, "false")) value.i = SetBool::false; + else if(!strcmpi(buffer, "true")) value.i = SetBool::true; + else + result = typeMismatch; + } + else if(!strcmpi(buffer, "null")) + { + if(type.type != structClass) + value.p = 0; + } + else + result = typeMismatch; } else result = typeMismatch; } - else - result = typeMismatch; } else if(ch == '}' || ch == ']') result = noItem; + if(result == typeMismatch) + PrintLn("Warning: Value type mismatch"); return result; } @@ -178,7 +308,6 @@ public: *array = null; if(ch == '[') { - int count = 0; *array = eInstance_New(type); result = success; while(result) @@ -192,6 +321,8 @@ public: arrayType = type.templateArgs[0].dataTypeClass; } + if(arrayType && arrayType.type == structClass) + value.p = new0 byte[arrayType.structSize]; itemResult = GetValue(arrayType, value); if(itemResult == success) { @@ -199,48 +330,115 @@ public: uint64 t; if(arrayType.type == structClass) { - t = (uint64) value.p; + t = (uint64)(uintptr)value.p; } else if(arrayType == class(double) || !strcmp(arrayType.dataTypeString, "double")) { - t = *(uint64 *)&value.d; + t = value.ui64; //*(uint64 *)&value.d; } else if(arrayType == class(float) || !strcmp(arrayType.dataTypeString, "float")) { - t = *(uint *)&value.f; + t = value.ui; //f*(uint *)&value.f; } - else if(arrayType.typeSize == sizeof(int64) || !strcmp(arrayType.dataTypeString, "int64") + else if(arrayType.typeSize == sizeof(int64) || !strcmp(arrayType.dataTypeString, "int64") || !strcmp(arrayType.dataTypeString, "unsigned int64") || !strcmp(arrayType.dataTypeString, "uint64")) { t = value.ui64; } - else if(arrayType.typeSize == sizeof(int) || !strcmp(arrayType.dataTypeString, "int") || + else if(arrayType.typeSize == sizeof(int) || !strcmp(arrayType.dataTypeString, "int") || !strcmp(arrayType.dataTypeString, "unsigned int") || !strcmp(arrayType.dataTypeString, "uint")) { t = value.i; } - else if(arrayType.typeSize == sizeof(short int) || !strcmp(arrayType.dataTypeString, "short") || - !strcmp(arrayType.dataTypeString, "unsigned short") || !strcmp(arrayType.dataTypeString, "uint16") || + else if(arrayType.typeSize == sizeof(short int) || !strcmp(arrayType.dataTypeString, "short") || + !strcmp(arrayType.dataTypeString, "unsigned short") || !strcmp(arrayType.dataTypeString, "uint16") || !strcmp(arrayType.dataTypeString, "int16")) { t = value.s; } - else if(arrayType.typeSize == sizeof(byte) || !strcmp(arrayType.dataTypeString, "char") || + else if(arrayType.typeSize == sizeof(byte) || !strcmp(arrayType.dataTypeString, "char") || !strcmp(arrayType.dataTypeString, "unsigned char") || !strcmp(arrayType.dataTypeString, "byte")) { t = value.c; } else { - t = (uint64)value.p; + t = (uint64)(uintptr)value.p; } ((void *(*)(void *, uint64))(void *)array->Add)(*array, t); + + if(arrayType && arrayType.type == structClass) + delete value.p; + } + else + { + if(itemResult == typeMismatch) + { + if(arrayType) + PrintLn("Warning: Incompatible value for array value, expected ", (String)arrayType.name); + } + else if(itemResult == noItem) + result = success; + else + result = itemResult; + } + + if(result != syntaxError) + { + if(ch != ']' && ch != ',') + { + ch = 0; + SkipEmpty(); + } + if(ch == ']') + { + break; + } + else if(ch != ',') + result = syntaxError; + } + } + } + ch = 0; + return result; + } + + JSONResult GetMap(Class type, Map * map) + { + JSONResult result = syntaxError; + SkipEmpty(); + *map = null; + if(ch == '[') + { + Class mapNodeType = type.templateArgs[0].dataTypeClass; + Class keyType = mapNodeType.templateArgs[0].dataTypeClass; + Property keyProp = null; + if(keyType && !strcmp(keyType.dataTypeString, "char *")) + keyProp = eClass_FindProperty(mapNodeType, "key", mapNodeType.module); + + *map = eInstance_New(type); + result = success; + + while(result) + { + DataValue value { }; + + JSONResult itemResult; + + itemResult = GetValue(mapNodeType, value); + if(itemResult == success) + { + String s = keyProp ? ((void * (*)(void *))(void *)keyProp.Get)(value.p) : null; + ((void *(*)(void *, uint64))(void *)map->Add)(*map, (uint64)(uintptr)value.p); + // Must free String keys here + delete s; } else { if(itemResult == typeMismatch) { - PrintLn("Warning: Incompatible value for array value, expected ", (String)arrayType.name); + if(mapNodeType) + PrintLn("Warning: Incompatible value for array value, expected ", (String)mapNodeType.name); } else if(itemResult == noItem) result = success; @@ -264,7 +462,83 @@ public: } } } - ch = 0; + ch = 0; + return result; + } + + JSONResult GetIdentifier(String * string, bool * wasQuoted) + { + JSONResult result = syntaxError; + Array buffer { minAllocSize = 256 }; + bool comment = false; + bool quoted = false; + + *string = null; + SkipEmpty(); + if(ch == '\"') + quoted = true; + else + buffer.Add(ch); + result = success; + while(f.Getc(&ch)) + { + if(!comment && ch == '/') + { + if(f.Getc(&ch)) + { + if(ch == '/') + break; + else if(ch == '*') + comment = true; + else + { + result = syntaxError; + break; + } + } + else + { + result = syntaxError; + break; + } + } + else if(comment && ch == '*') + { + if(f.Getc(&ch)) + { + if(ch == '/') + { + comment = false; + ch = 0; + } + } + else + { + result = syntaxError; + break; + } + } + else if(ch == '\"' || (!quoted && !comment && ch && !isalpha(ch) && !isdigit(ch) && ch != '_')) + { + if(quoted && ch == '\"' && wasQuoted) + *wasQuoted = true; + break; + } + else if(!comment && ch) + { + buffer.Add(ch); + if(buffer.minAllocSize < buffer.count) + buffer.minAllocSize *= 2; + } + } + if(result != syntaxError) + { + buffer.Add(0); + *string = CopyString(buffer.array); + } + delete buffer; + if(ch != ',' && ch != '}' && ch != ';' && ch != '/' && ch != '=' && ch != ':') + ch = 0; return result; } @@ -276,7 +550,7 @@ public: *string = null; SkipEmpty(); - if(ch == '\"') + if(ch == '\"' || eCON) { while(f.Getc(&ch)) { @@ -298,17 +572,61 @@ public: f.Getc(&unicode[0]); f.Getc(&unicode[1]); f.Getc(&unicode[2]); - f.Getc(&unicode[3]); + f.Getc(&unicode[3]); } escaped = false; } - else if(ch == '\"') + else if(eCON && ch == '\"') + { + int seekback = 0; + char pch; + bool lineComment = false; + bool comment = false; + while(!f.Eof()) + { + pch = ch; + f.Getc(&ch); + seekback--; + if(!lineComment && !comment && pch == '/') + { + if(ch == '/') + lineComment = true; + else if(ch == '*') + comment = true; + } + else if(lineComment && ch == '\n') + lineComment = false; + else if(comment && pch == '*' && ch == '/') + comment = false; + else if(ch == '=' || ch == ':' || ch == ';' || ch == ',' || ch == ']' || ch == '}') + { + ch = 0; + seekback = -1; + break; + } + else if(ch == '\"') + { + seekback = 0; + ch = 0; + break; + } + } + if(seekback != 0) + { + f.Seek(seekback, current); + break; + } + } + else if((!eCON && ch == '\"')) { break; } - buffer.Add(ch); - if(buffer.minAllocSize < buffer.count) - buffer.minAllocSize *= 2; + if(ch) + { + buffer.Add(ch); + if(buffer.minAllocSize < buffer.count) + buffer.minAllocSize *= 2; + } } } buffer.Add(0); @@ -316,72 +634,199 @@ public: result = success; } delete buffer; - ch = 0; + if(ch != ',' && ch != '}' && (!eCON || (ch != ';' && ch != '/'))) + ch = 0; return result; } public JSONResult GetObject(Class objectType, void ** object) { JSONResult result = syntaxError; - *object = null; + if(!objectType || objectType.type != structClass) + { + if(objectType && objectType.type == bitClass) + *(uint64 *)object = 0; + else + *object = null; + } SkipEmpty(); if(ch == '{') { - result = success; - if(objectType && objectType.type == noHeadClass || objectType.type == normalClass) + Class mapKeyClass = null, mapDataClass = null; + Class curClass = null; + DataMember curMember = null; + DataMember subMemberStack[256]; + int subMemberStackPos = 0; + uint64 bits = 0; + + if(objectType.type == bitClass) { - *object = eInstance_New(objectType); + switch(objectType.typeSize) + { + case 1: bits = (byte )*(uint64 *)object; break; + case 2: bits = (uint16)*(uint64 *)object; break; + case 4: bits = (uint32)*(uint64 *)object; break; + case 8: bits = (uint64)*(uint64 *)object; break; + } } - else if(objectType) + + if(objectType && objectType.templateClass && eClass_IsDerived(objectType.templateClass, class(MapNode))) { - *object = eSystem_New(objectType.typeSize); + mapKeyClass = objectType.templateArgs[0].dataTypeClass; + mapDataClass = objectType.templateArgs[2].dataTypeClass; } + result = success; + if(objectType && (objectType.type == noHeadClass || objectType.type == normalClass)) + *object = eInstance_New(objectType); + while(result) { String string; + bool wasQuoted = false; + int seek; ch = 0; - if(GetString(&string)) + if(eCON) + { + SkipExtraSemicolon(); + if(ch == '}') + break; + } + SkipEmpty(); + seek = f.Tell(); + if(eCON ? GetIdentifier(&string, &wasQuoted) : GetString(&string)) { - bool found = true; DataMember member = null; Property prop = null; Class type = null; + bool isKey = false; + bool isTemplateArg = false; + uint offset = 0; + if(eCON) + { + SkipEmpty(); + prop = null; member = null; + if(ch == '=' || ch == ':') + { + if(wasQuoted) + string[0] = (char)tolower(string[0]); + while(1) + { + eClass_FindNextMember(objectType, &curClass, &curMember, subMemberStack, &subMemberStackPos); + if(!curMember) break; + if(!strcmp(curMember.name, string)) + break; + } + } + else + eClass_FindNextMember(objectType, &curClass, &curMember, subMemberStack, &subMemberStackPos); + if(curMember) + { + prop = curMember.isProperty ? (Property)curMember : null; + member = curMember.isProperty ? null : curMember; - if(objectType) + if(mapKeyClass && !strcmp(prop ? prop.name : member.name, "key")) + { + type = mapKeyClass; + isTemplateArg = true; + isKey = true; + } + else if(mapDataClass && !strcmp(prop ? prop.name : member.name, "value")) + { + type = mapDataClass; + isTemplateArg = true; + if(member) + offset = member._class.offset + member.offset; + } + else if(prop) + type = superFindClass(prop.dataTypeString, objectType.module); + else if(member) + { + type = superFindClass(member.dataTypeString, objectType.module); + offset = member._class.offset + member.offset; + } + } + else + { + if(ch == '=' || ch == ':') + PrintLn("Warning: member ", string, " not found in class ", (String)objectType.name); + else + PrintLn("Warning: default member assignment: no more members"); + } + } + if(objectType && !eCON) { string[0] = (char)tolower(string[0]); - member = eClass_FindDataMember(objectType, string, objectType.module, null, null); - if(member) + if(mapKeyClass && !strcmp(string, "key")) { - type = eSystem_FindClass(__thisModule, member.dataTypeString); - if(!type) - type = eSystem_FindClass(__thisModule.application, member.dataTypeString); + prop = eClass_FindProperty(objectType, "key", objectType.module); + type = mapKeyClass; + isTemplateArg = true; + isKey = true; + } + else if(mapDataClass && !strcmp(string, "value")) + { + prop = eClass_FindProperty(objectType, "value", objectType.module); + type = mapDataClass; + isTemplateArg = true; } - else if(!member) + else { - prop = eClass_FindProperty(objectType, string, objectType.module); - if(prop) + member = eClass_FindDataMember(objectType, string, objectType.module, null, null); + if(member) { - type = eSystem_FindClass(__thisModule, prop.dataTypeString); - if(!type) - type = eSystem_FindClass(__thisModule.application, prop.dataTypeString); + type = superFindClass(member.dataTypeString, objectType.module); + offset = member._class.offset + member.offset; } - else - PrintLn("Warning: member ", string, " not found in class ", (String)objectType.name); - } + else if(!member) + { + prop = eClass_FindProperty(objectType, string, objectType.module); + if(prop) + type = superFindClass(prop.dataTypeString, objectType.module); + else + PrintLn("Warning: member ", string, " not found in class ", (String)objectType.name); + } + } + } + if(type && type.templateClass && type.templateClass == class(Container)) + { + char * br = strchr(type.fullName, '<'); + if(br) + { + char className[1024]; + strcpy(className, "Array"); + strcat(className, br); + type = superFindClass(className, objectType.module); + } } + // Find Member in Object Class { DataValue value { }; if(type && type.type == structClass) { - value.p = (byte *)*object + member._class.offset + member.offset; + if(member) + { + value.p = (byte *)*object + offset; + memset(value.p, 0, type.structSize); + } + else if(prop) + { + value.p = new0 byte[type.structSize]; + } + } + if(!eCON) + { + ch = 0; + SkipEmpty(); } - ch = 0; - SkipEmpty(); - if(ch == ':') + if(eCON && ch != '=' && ch != ':') + { + f.Seek(seek-1, start); + ch = 0; + } + if((ch == ':' || (eCON && ch == '=')) || (eCON && type && (prop || member))) { JSONResult itemResult = GetValue(type, value); if(itemResult != syntaxError) @@ -389,97 +834,198 @@ public: if(prop || member) { if(!type) - { PrintLn("warning: Unresolved data type ", member ? (String)member.dataTypeString : (String)prop.dataTypeString); - } else if(itemResult == success) { + BitMember bitMember = objectType.type == bitClass ? (BitMember) member : null; // Set value if(member) { // TOFIX: How to swiftly handle classes with base data type? - if(type == class(double) || !strcmp(type.dataTypeString, "double")) + if(type.type == structClass) + ; + else if(type.type == normalClass || type.type == noHeadClass) { - *(double *)((byte *)*object + member._class.offset + member.offset) = value.d; + void ** ptr = (void**)((byte *)*object + offset); + if(eClass_IsDerived(type, class(Container)) && *ptr) + { + Container container = (Container)*ptr; + container.Free(); + delete container; + } + *ptr = value.p; + } + else if(type == class(double) || !strcmp(type.dataTypeString, "double")) + { + if(objectType.type != bitClass) + { + *(double *)((byte *)*object + offset) = value.d; + } } else if(type == class(float) || !strcmp(type.dataTypeString, "float")) { - *(float *)((byte *)*object + member._class.offset + member.offset) = value.f; + if(objectType.type != bitClass) + { + *(float *)((byte *)*object + offset) = value.f; + } } - else if(type.typeSize == sizeof(int64) || !strcmp(type.dataTypeString, "int64") + else if(type.typeSize == sizeof(int64) || !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64")) { - *(uint64 *)((byte *)*object + member._class.offset + member.offset) = value.ui64; + if(objectType.type == bitClass) + { + bits &= ~bitMember.mask; + bits |= (value.ui64 << bitMember.pos) & bitMember.mask; + } + else + { + *(uint64 *)((byte *)*object + offset) = value.ui64; + } } - else if(type.typeSize == sizeof(int) || !strcmp(type.dataTypeString, "int") || + else if(type.typeSize == sizeof(int) || !strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint")) { - int * ptr = (int *)((byte *)*object + member._class.offset + member.offset); - // TODO: Fix Me Up 64 bit pointer here - if(eClass_IsDerived(type, class(Container)) && *ptr) + if(objectType.type == bitClass) { - Container container = (Container)*ptr; - container.Free(); - delete container; + bits &= ~bitMember.mask; + bits |= (value.ui << bitMember.pos) & bitMember.mask; + } + else + { + *(int *)((byte *)*object + offset) = value.i; } - *ptr = value.i; } - else if(type.typeSize == sizeof(short int) || !strcmp(type.dataTypeString, "short") || - !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") || + else if(type.typeSize == sizeof(short int) || !strcmp(type.dataTypeString, "short") || + !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") || !strcmp(type.dataTypeString, "int16")) { - *(short *)((byte *)*object + member._class.offset + member.offset) = value.s; + if(objectType.type == bitClass) + { + bits &= ~bitMember.mask; + bits |= (value.us << bitMember.pos) & bitMember.mask; + } + else + { + *(short *)((byte *)*object + offset) = value.s; + } } - else if(type.typeSize == sizeof(byte) || !strcmp(type.dataTypeString, "char") || + else if(type.typeSize == sizeof(byte) || !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte")) { - *(char *)((byte *)*object + member._class.offset + member.offset) = value.c; + if(objectType.type == bitClass) + { + bits &= ~bitMember.mask; + bits |= (value.uc << bitMember.pos) & bitMember.mask; + } + else + { + *(char *)((byte *)*object + offset) = value.c; + } } - else if(type.type != structClass) + else { - *(void **)((byte *)*object + member._class.offset + member.offset) = value.p; + if(objectType.type != bitClass) + *(void **)((byte *)*object + offset) = value.p; } } else if(prop && prop.Set) { - if(!strcmp(type.dataTypeString, "char *")) - { - ((void (*)(void *, int))(void *)prop.Set)(*object, value.i); - delete value.p; - } - // TOFIX: How to swiftly handle classes with base data type? - else if(type == class(double) || !strcmp(type.dataTypeString, "double")) - { - ((void (*)(void *, double))(void *)prop.Set)(*object, value.d); - } - else if(type == class(float) || !strcmp(type.dataTypeString, "float")) - { - ((void (*)(void *, float))(void *)prop.Set)(*object, value.f); - } - else if(type.typeSize == sizeof(int64) || !strcmp(type.dataTypeString, "int64") - !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64")) - { - ((void (*)(void *, uint64))(void *)prop.Set)(*object, value.ui64); - } - else if(type.typeSize == sizeof(int) || !strcmp(type.dataTypeString, "int") || - !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint")) + if(objectType.type == bitClass) { - ((void (*)(void *, int))(void *)prop.Set)(*object, value.i); + if(type.type == enumClass || type.type == bitClass || type.type == unitClass || type.type == systemClass) + { + switch(objectType.typeSize) + { + case 1: + switch(type.typeSize) + { + case 1: ((byte (*)(byte, byte)) (void *)prop.Set)((byte)bits, value.uc); break; + case 2: ((byte (*)(byte, uint16))(void *)prop.Set)((byte)bits, value.us); break; + case 4: ((byte (*)(byte, uint32))(void *)prop.Set)((byte)bits, value.ui); break; + case 8: ((byte (*)(byte, uint64))(void *)prop.Set)((byte)bits, value.ui64); break; + } + break; + case 2: + switch(type.typeSize) + { + case 1: ((uint16 (*)(uint16, byte)) (void *)prop.Set)((uint16)bits, value.uc); break; + case 2: ((uint16 (*)(uint16, uint16))(void *)prop.Set)((uint16)bits, value.us); break; + case 4: ((uint16 (*)(uint16, uint32))(void *)prop.Set)((uint16)bits, value.ui); break; + case 8: ((uint16 (*)(uint16, uint64))(void *)prop.Set)((uint16)bits, value.ui64); break; + } + break; + case 4: + switch(type.typeSize) + { + case 1: ((uint32 (*)(uint32, byte)) (void *)prop.Set)((uint32)bits, value.uc); break; + case 2: ((uint32 (*)(uint32, uint16))(void *)prop.Set)((uint32)bits, value.us); break; + case 4: ((uint32 (*)(uint32, uint32))(void *)prop.Set)((uint32)bits, value.ui); break; + case 8: ((uint32 (*)(uint32, uint64))(void *)prop.Set)((uint32)bits, value.ui64); break; + } + break; + case 8: + switch(type.typeSize) + { + case 1: ((uint64 (*)(uint64, byte)) (void *)prop.Set)((uint64)bits, value.uc); break; + case 2: ((uint64 (*)(uint64, uint16))(void *)prop.Set)((uint64)bits, value.us); break; + case 4: ((uint64 (*)(uint64, uint32))(void *)prop.Set)((uint64)bits, value.ui); break; + case 8: ((uint64 (*)(uint64, uint64))(void *)prop.Set)((uint64)bits, value.ui64); break; + } + break; + } + } + else + ; // TODO: Generate error } - else if(type.typeSize == sizeof(short int) || !strcmp(type.dataTypeString, "short") || - !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") || - !strcmp(type.dataTypeString, "int16")) + else if(!strcmp(type.dataTypeString, "char *")) { - ((void (*)(void *, short))(void *)prop.Set)(*object, value.s); + ((void (*)(void *, void *))(void *)prop.Set)(*object, value.p); + if(!isKey) + delete value.p; } - else if(type.typeSize == sizeof(byte) || !strcmp(type.dataTypeString, "char") || - !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte")) + else if(type.type == enumClass || type.type == bitClass || type.type == unitClass || type.type == systemClass) { - ((void (*)(void *, char))(void *)prop.Set)(*object, value.c); + // TOFIX: How to swiftly handle classes with base data type? + if(type == class(double) || !strcmp(type.dataTypeString, "double")) + { + ((void (*)(void *, double))(void *)prop.Set)(*object, value.d); + } + else if(type == class(float) || !strcmp(type.dataTypeString, "float")) + { + ((void (*)(void *, float))(void *)prop.Set)(*object, value.f); + } + else if(type.typeSize == sizeof(int64) || !strcmp(type.dataTypeString, "int64") || + !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64")) + { + ((void (*)(void *, uint64))(void *)prop.Set)(*object, value.ui64); + } + else if(type.typeSize == sizeof(int) || !strcmp(type.dataTypeString, "int") || + !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint")) + { + ((void (*)(void *, int))(void *)prop.Set)(*object, value.i); + } + else if(type.typeSize == sizeof(short int) || !strcmp(type.dataTypeString, "short") || + !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") || + !strcmp(type.dataTypeString, "int16")) + { + ((void (*)(void *, short))(void *)prop.Set)(*object, value.s); + } + else if(type.typeSize == sizeof(byte) || !strcmp(type.dataTypeString, "char") || + !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte")) + { + ((void (*)(void *, char))(void *)prop.Set)(*object, value.c); + } + else + { + ((void (*)(void *, int))(void *)prop.Set)(*object, value.i); + } } else { - ((void (*)(void *, void *))(void *)prop.Set)(*object, value.p); + if(isTemplateArg) + ((void (*)(void *, uint64))(void *)prop.Set)(*object, (uint64)(uintptr)value.p); + else + ((void (*)(void *, void *))(void *)prop.Set)(*object, value.p); } } } @@ -493,9 +1039,14 @@ public: } else result = syntaxError; + + if(prop && type && type.type == structClass) + { + delete value.p; + } } } - else + else if(ch && ch != '}' && ch != ',' && (!eCON || ch != ';')) result = syntaxError; delete string; @@ -506,10 +1057,21 @@ public: { break; } - else if(ch != ',') + else if(ch != ',' && (!eCON || ch != ';')) result = syntaxError; } } + + if(objectType.type == bitClass) + { + switch(objectType.typeSize) + { + case 1: *(uint64 *)object = (byte) bits; break; + case 2: *(uint64 *)object = (uint16) bits; break; + case 4: *(uint64 *)object = (uint32) bits; break; + case 8: *(uint64 *)object = (uint64) bits; break; + } + } } ch = 0; return result; @@ -517,16 +1079,66 @@ public: JSONResult GetNumber(Class type, DataValue value) { - JSONResult result = syntaxError; + JSONResult result = success; char buffer[256]; int c = 0; - while(c < sizeof(buffer)-1 && (ch == '-' || ch == '.' || tolower(ch) == 'e' || ch == '+' || isdigit(ch))) + bool comment = false; + bool hexMode = false; + if(eCON) { - buffer[c++] = ch; - if(!f.Getc(&ch)) break; + while(c < sizeof(buffer)-1 && (comment || ch == '-' || ch == '.' || tolower(ch) == 'f' || + (c == 1 && tolower(ch) == 'x' && buffer[0] == '0') || tolower(ch) == 'e' || ch == '+' || isdigit(ch) || ch == '/' || + (hexMode && ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))))) + { + if(!comment && ch == '/') + { + if(f.Getc(&ch)) + { + if(ch == '*') + comment = true; + } + else + { + result = syntaxError; + break; + } + } + else if(comment && ch == '*') + { + if(f.Getc(&ch)) + { + if(ch == '/') + comment = false; + } + else + { + result = syntaxError; + break; + } + } + else if(!comment) + { + if(c == 1 && ch == 'x' && buffer[0] == '0') + hexMode = true; + buffer[c++] = ch; + } + if(!f.Getc(&ch)) break; + } + } + else + { + while(c < sizeof(buffer)-1 && (ch == '-' || ch == '.' || tolower(ch) == 'e' || ch == '+' || isdigit(ch))) + { + buffer[c++] = ch; + if(!f.Getc(&ch)) break; + } } buffer[c] = 0; //if(strchr(buffer, '.')) + if(result == syntaxError) + return result; + if(!type) return success; + result = syntaxError; // TOFIX: How to swiftly handle classes with base data type? if(type == class(double) || !strcmp(type.dataTypeString, "double")) @@ -543,170 +1155,403 @@ public: //else if(type == class(int64) || !strcmp(type.dataTypeString, "int64")) else if(!strcmp(type.dataTypeString, "int64")) { - value.i64 = strtol(buffer, null, 10); // TOFIX: 64 bit support + value.i64 = strtol(buffer, null, eCON ? 0 : 10); // TOFIX: 64 bit support result = success; } else if(type == class(uint64) || !strcmp(type.dataTypeString, "uint64")) { - value.ui64 = strtol(buffer, null, 10); // TOFIX: 64 bit support + value.ui64 = strtoul(buffer, null, eCON ? 0 : 10); // TOFIX: 64 bit support + result = success; + } + else if(type == class(uint) || !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint")) + { + value.ui = (uint)strtoul(buffer, null, eCON ? 0 : 10); // TOFIX: 64 bit support result = success; } else { - value.i = strtol(buffer, null, 10); + value.i = (int)strtol(buffer, null, eCON ? 0 : 10); result = success; } + + if(result == success && type.type == unitClass) + { + // Convert to reference unit + Property prop; + for(prop = type.conversions.first; prop; prop = prop.next) + { + bool refProp = false; + if(!strcmp(prop.name, type.base.fullName)) + refProp = true; + else + { + Class c = eSystem_FindClass(type.module, prop.name); + if(!c) + c = eSystem_FindClass(type.module.application, prop.name); + if(c) + { + Property p; + for(p = c.conversions.first; p; p = p.next) + { + if(!strcmp(p.name, type.base.fullName) && !p.Set && !p.Get) + { + refProp = true; + break; + } + } + } + } + if(refProp) + { + if(prop.Set && prop.Get) + { + const String dts = type.base.dataTypeString; + if(!strcmp(dts, "double")) + value.d = ((double(*)(double))(void *)prop.Get)(value.d); + else if(!strcmp(dts, "float")) + value.f = ((float(*)(float))(void *)prop.Get)(value.f); + else if(!strcmp(dts, "int")) + value.i = ((int(*)(int))(void *)prop.Get)(value.i); + else if(!strcmp(dts, "int64")) + value.i64 = ((int64(*)(int64))(void *)prop.Get)(value.i64); + else if(!strcmp(dts, "unsigned int")) + value.ui = ((uint(*)(uint))(void *)prop.Get)(value.ui); + else if(!strcmp(dts, "uint64")) + value.ui64 = ((uint64(*)(uint64))(void *)prop.Get)(value.ui64); + } + else + break; + } + } + } return result; } + + JSONResult GetColorAlpha(String string, DataValue value) + { + ColorAlpha color = 0; + DefinedColor c = 0; + if(string) + { + if(string[0] == '0' && string[1] == 'x') + color = (uint)strtoul(string, null, 0); + else + { + char *d; + byte a = 255; + if((d = strchr(string, ','))) + { + a = (byte)atoi(string); + d += 2; + } + else + d = string; + if(c.class::OnGetDataFromString(d)) + { + color.a = a; + color.color = c; + } + else + color = (uint)strtoul(string, null, 16); + } + } + value.i = color; + return success; + } +} + +static bool WriteMap(File f, Class type, Map map, int indent, bool eCON) +{ + if(map) + { + int i; + bool isFirst = true; + MapIterator it { map = map }; + Class mapNodeClass = map._class.templateArgs[0].dataTypeClass; + f.Puts("[\n"); + indent++; + + while(it.Next()) + { + MapNode n = (MapNode)it.pointer; + if(!isFirst) + f.Puts(",\n"); + else + isFirst = false; + for(i = 0; i= 4 && ch == '>' && string[c-2] == 'r' && string[c-3] == 'b' && string[c-4] == '<') + { + // Add an automatic newline for
as this is how we imported documentor data... + int i; + buffer[b] = 0; + f.Puts(buffer); + f.Puts(">\"\n"); + for(i = 0; i bases { }; + + if(objectType.templateClass && eClass_IsDerived(objectType.templateClass, class(MapNode))) + { + mapKeyClass = objectType.templateArgs[0].dataTypeClass; + mapDataClass = objectType.templateArgs[2].dataTypeClass; + } + + if(eCON && _class != objectType && eClass_IsDerived(_class, objectType)) + { + f.Puts(_class.name); + f.Puts(" "); + } + f.Puts("{\n"); indent++; - for(prop = objectType.membersAndProperties.first; prop; prop = prop.next) + for(baseClass = _class; baseClass; baseClass = baseClass.base) + { + if(baseClass.isInstanceClass || !baseClass.base) + break; + bases.Insert(null, baseClass); + } + + for(baseClass : bases) { - if(prop.memberAccess != publicAccess || (prop.isProperty && (!prop.Set || !prop.Get))) continue; - if(prop.isProperty) + for(prop = baseClass.membersAndProperties.first; prop; prop = prop.next) { - if(!prop.conversion && (!prop.IsSet || prop.IsSet(object))) + if(prop.memberAccess != publicAccess || (prop.isProperty && (!prop.Set || !prop.Get))) continue; + if(prop.isProperty) { - DataValue value { }; - Class type = eSystem_FindClass(__thisModule, prop.dataTypeString); - if(!type) - type = eSystem_FindClass(__thisModule.application, prop.dataTypeString); - - // TOFIX: How to swiftly handle classes with base data type? - if(type == class(double) || !strcmp(type.dataTypeString, "double")) - { - value.d = ((double (*)(void *))(void *)prop.Get)(object); - } - else if(type == class(float) || !strcmp(type.dataTypeString, "float")) - { - value.f = ((float (*)(void *))(void *)prop.Get)(object); - } - else if(type.typeSize == sizeof(int64) || !strcmp(type.dataTypeString, "int64") - !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64")) + if(!prop.conversion && (!prop.IsSet || prop.IsSet(object))) { - value.ui64 = ((uint64 (*)(void *))(void *)prop.Get)(object); - } - else if(type.typeSize == sizeof(int) || !strcmp(type.dataTypeString, "int") || - !strcmp(type.dataTypeString, "unsigned int") || !strcmp(type.dataTypeString, "uint")) - { - value.i = ((int (*)(void *))(void *)prop.Get)(object); - } - else if(type.typeSize == sizeof(short int) || !strcmp(type.dataTypeString, "short") || - !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") || - !strcmp(type.dataTypeString, "int16")) - { - value.s = ((short (*)(void *))(void *)prop.Get)(object); - } - else if(type.typeSize == sizeof(byte) || !strcmp(type.dataTypeString, "char") || - !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte")) - { - value.c = ((char (*)(void *))(void *)prop.Get)(object); - } - else - { - value.p = ((void *(*)(void *))(void *)prop.Get)(object); - } - - if(!isFirst) f.Puts(",\n"); - for(c = 0; c