#include #include "cwCommon.h" #include "cwLog.h" #include "cwCommonImpl.h" #include "cwMem.h" #include "cwFile.h" #include "cwLex.h" #include "cwText.h" #include "cwNumericConvert.h" #include "cwObject.h" #include "cwObjectTemplate.h" namespace cw { enum { kLCurlyLexTId = cw::lex::kUserLexTId+1, kRCurlyLexTId, kLHardLexTId, kRHardLexTId, kColonLexTId, kCommaLexTId, kTrueLexTId, kFalseLexTId, kNullLexTId }; idLabelPair_t _objTokenArray[] = { { kLCurlyLexTId, "{" }, { kRCurlyLexTId, "}" }, { kLHardLexTId, "[" }, { kRHardLexTId, "]" }, { kColonLexTId, ":" }, { kCommaLexTId, "," }, { kTrueLexTId, "true"}, { kFalseLexTId, "false"}, { kNullLexTId, "null" }, { lex::kErrorLexTId,""} }; void _objTypeFree( object_t* o ) { memRelease(o); } void _objTypeFreeString( object_t* o ) { memRelease( o->u.str ); _objTypeFree(o); } const char* _objTypeIdToLabel( objTypeId_t tid ); void _objTypeNullToString( object_t* o, char* buf, unsigned bufN ) { snprintf(buf,bufN,"%s","NULL"); } void _objTypeCharToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.c,"%c",buf,bufN); } void _objTypeInt8ToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.i8,"%i",buf,bufN); } void _objTypeUInt8ToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.u8,"%i",buf,bufN); } void _objTypeInt16ToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.i16,"%i",buf,bufN); } void _objTypeUInt16ToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.u16,"%i",buf,bufN); } void _objTypeInt32ToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.i32,"%i",buf,bufN); } void _objTypeUInt32ToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.u32,"%i",buf,bufN); } void _objTypeInt64ToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.i64,"%i",buf,bufN); } void _objTypeUInt64ToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.u64,"%i",buf,bufN); } void _objTypeBoolToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.b,"%i",buf,bufN); } void _objTypeFloatToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.f,"%f",buf,bufN); } void _objTypeDoubleToString( object_t* o, char* buf, unsigned bufN ) { number_to_string(o->u.d,"%f",buf,bufN); } void _objTypeStringToString( object_t* o, char* buf, unsigned bufN ) { snprintf(buf,bufN,"%s",o->u.str); } rc_t _objTypeValueFromChar( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.c,tid, dst,o->type->label); } rc_t _objTypeValueFromInt8( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.i8,tid, dst,o->type->label); } rc_t _objTypeValueFromUInt8( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.u8,tid, dst,o->type->label); } rc_t _objTypeValueFromInt16( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.i16,tid,dst,o->type->label); } rc_t _objTypeValueFromUInt16( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.u16,tid,dst,o->type->label); } rc_t _objTypeValueFromInt32( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.i32,tid,dst,o->type->label); } rc_t _objTypeValueFromUInt32( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.u32,tid,dst,o->type->label); } rc_t _objTypeValueFromInt64( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.i64,tid,dst,o->type->label); } rc_t _objTypeValueFromUInt64( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.u64,tid,dst,o->type->label); } rc_t _objTypeValueFromFloat( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.f,tid, dst,o->type->label); } rc_t _objTypeValueFromDouble( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.d,tid, dst,o->type->label); } rc_t _objTypeValueFromBool( const object_t* o, unsigned tid, void* dst ) { return getObjectValue(o->u.b,tid,dst,o->type->label); } rc_t _objTypeValueFromNonValue( const object_t* o, unsigned tid, void* dst ) { return cwLogError(kInvalidArgRC, "There is no conversion from '%s' to '%s'.", _objTypeIdToLabel(tid), o->type->label); } rc_t _objTypeValueFromString( const object_t* o, unsigned tid, void* dst ) { return _objTypeValueFromNonValue(o,tid,dst); } rc_t _objTypeValueFromVect( const object_t* o, unsigned tid, void* dst ) { return _objTypeValueFromNonValue(o,tid,dst); } void _objTypePrintIndent( const char* text, unsigned indent, const char* indentStr=" " ) { for(unsigned i=0; itype->print(o,c); printf(eolStr); } void _objTypePrintNull( const object_t* o, print_ctx_t& c ) { printf("NULL "); } void _objTypePrintError( const object_t* o, print_ctx_t& c ) { printf("Error "); } void _objTypePrintChar( const object_t* o, print_ctx_t& c ) { printf("%c",o->u.c); } void _objTypePrintInt8( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.i8); } void _objTypePrintUInt8( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.u8); } void _objTypePrintInt16( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.i16); } void _objTypePrintUInt16( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.u16); } void _objTypePrintInt32( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.i32); } void _objTypePrintUInt32( const object_t* o, print_ctx_t& c ) { printf("%i",o->u.u32); } void _objTypePrintInt64( const object_t* o, print_ctx_t& c ) { printf("%li",o->u.i64); } void _objTypePrintUInt64( const object_t* o, print_ctx_t& c ) { printf("%li",o->u.u64); } void _objTypePrintBool( const object_t* o, print_ctx_t& c ) { printf("%s",o->u.b ? "true" : "false"); } void _objTypePrintFloat( const object_t* o, print_ctx_t& c ) { printf("%f",o->u.f); } void _objTypePrintDouble( const object_t* o, print_ctx_t& c ) { printf("%f",o->u.d); } void _objTypePrintString( const object_t* o, print_ctx_t& c ) { printf("%s",o->u.str); } void _objTypePrintVect( const object_t* o, print_ctx_t& c ) { printf(""); } void _objTypePrintPair( const object_t* o, print_ctx_t& c ) { o->u.children->type->print(o->u.children,c); printf(": "); o->u.children->sibling->type->print(o->u.children->sibling,c); } void _objTypePrintList( const object_t* o, print_ctx_t& c ) { const char* indentStr = c.listOnOneLineFl ? "" : " "; char bracketStr[] = { '[','\0','\0' }; char eoValStr[] = { ',','\0','\0' }; if(!c.listOnOneLineFl) { bracketStr[1] = '\n'; eoValStr[1] = '\n'; } _objTypePrintIndent(bracketStr,0); c.indent += 2; for(const object_t* ch=o->u.children; ch!=nullptr; ch=ch->sibling) { if( ch->sibling == nullptr ) eoValStr[0] = ' '; _objTypePrintChild(ch,c,eoValStr,indentStr); } c.indent -= 2; _objTypePrintIndent("]",c.listOnOneLineFl ? 0 : c.indent); } void _objTypePrintDict( const object_t* o, print_ctx_t& c ) { _objTypePrintIndent("{\n",0); c.indent += 2; for(const object_t* ch=o->u.children; ch!=nullptr; ch=ch->sibling) _objTypePrintChild(ch,c); c.indent -= 2; _objTypePrintIndent("}",c.indent); } void _objTypePrintRoot( const object_t* o, print_ctx_t& c ) { _objTypePrintDict(o,c); } objType_t _objTypeArray[] = { { kNullTId, "null", 0, _objTypeFree, _objTypeValueFromNonValue, _objTypePrintNull }, { kErrorTId, "error", 0, _objTypeFree, _objTypeValueFromNonValue, _objTypePrintError }, { kCharTId, "char", 0, _objTypeFree, _objTypeValueFromChar, _objTypePrintChar }, { kInt8TId, "int8", 0, _objTypeFree, _objTypeValueFromInt8, _objTypePrintInt8 }, { kUInt8TId, "uint8", 0, _objTypeFree, _objTypeValueFromUInt8, _objTypePrintUInt8 }, { kInt16TId, "int16", 0, _objTypeFree, _objTypeValueFromInt16, _objTypePrintInt16 }, { kUInt16TId, "uint16", 0, _objTypeFree, _objTypeValueFromUInt16, _objTypePrintUInt16 }, { kInt32TId, "int32", 0, _objTypeFree, _objTypeValueFromInt32, _objTypePrintInt32 }, { kUInt32TId, "uint32", 0, _objTypeFree, _objTypeValueFromUInt32, _objTypePrintUInt32 }, { kInt64TId, "int64", 0, _objTypeFree, _objTypeValueFromInt64, _objTypePrintInt64 }, { kUInt64TId, "uint64", 0, _objTypeFree, _objTypeValueFromUInt64, _objTypePrintUInt64 }, { kBoolTId, "bool", 0, _objTypeFree, _objTypeValueFromBool, _objTypePrintBool }, { kFloatTId, "float", 0, _objTypeFree, _objTypeValueFromFloat, _objTypePrintFloat }, { kDoubleTId, "double", 0, _objTypeFree, _objTypeValueFromDouble, _objTypePrintDouble }, { kStringTId, "string", 0, _objTypeFreeString, _objTypeValueFromString, _objTypePrintString }, { kVectTId, "vect", 0, _objTypeFree, _objTypeValueFromVect, _objTypePrintVect }, { kPairTId, "pair", kContainerFl | kValueContainerFl, _objTypeFree, _objTypeValueFromNonValue, _objTypePrintPair }, { kListTId, "list", kContainerFl | kValueContainerFl, _objTypeFree, _objTypeValueFromNonValue, _objTypePrintList }, { kDictTId, "dict", kContainerFl, _objTypeFree, _objTypeValueFromNonValue, _objTypePrintDict }, { kRootTId, "root", kContainerFl | kValueContainerFl, _objTypeFree, _objTypeValueFromNonValue, _objTypePrintRoot }, { kInvalidTId, "", 0, nullptr } }; objType_t* _objIdToType( objTypeId_t tid ) { unsigned i; for(i=0; _objTypeArray[i].id != kInvalidTId; ++i) if( _objTypeArray[i].id == tid ) return _objTypeArray + i; cwLogError(kInvalidIdRC,"The object type id %i is not valid.",tid); return nullptr; } const char* _objTypeIdToLabel( objTypeId_t tid ) { const objType_t* type; if((type = _objIdToType(tid)) == nullptr ) return ""; return type->label; } object_t* _objAllocate( objTypeId_t tid, object_t* parent ) { objType_t* type = nullptr; if( tid != kInvalidTId ) { if((type = _objIdToType(tid)) == nullptr ) { cwLogError(kObjAllocFailRC,"Object allocation failed."); return nullptr; } } object_t* o = memAllocZ(); o->type = type; o->parent = parent; return o; } rc_t _objSyntaxError( lex::handle_t lexH, const char* fmt, ... ) { va_list vl; va_start(vl,fmt); cwLogVError( kSyntaxErrorRC, fmt, vl ); cwLogError( kSyntaxErrorRC, "Error on line: %i.", lex::currentLineNumber(lexH)); va_end(vl); return kSyntaxErrorRC; } rc_t _objVerifyParentIsValueContainer( lex::handle_t lexH, const object_t* parent, const char* msg ) { if( parent == nullptr ) return _objSyntaxError(lexH,"The parent node must always be valid."); // it is legal for a parent of a value to be null when the value is the root element. if( !(parent->is_value_container())) return _objSyntaxError(lexH,"Value nodes of type '%s' must be contained by 'root', 'pair' or 'array' node.",msg); return kOkRC; } object_t* _objAppendLeftMostNode( object_t* parent, object_t* newNode ) { if( newNode == nullptr ) return nullptr; object_t* child = parent->u.children; if( parent->u.children == nullptr ) parent->u.children = newNode; else { while( child->sibling != nullptr ) child = child->sibling; child->sibling = newNode; } newNode->parent = parent; return newNode; } object_t* _objCreateConainerNode( lex::handle_t lexH, object_t* parent, objTypeId_t tid ) { if( _objVerifyParentIsValueContainer(lexH,parent,_objTypeIdToLabel(tid)) == kOkRC ) return _objAppendLeftMostNode( parent, _objAllocate( tid, parent )); return nullptr; } } void cw::object_t::free() { if( is_container() ) { object_t* o1 = nullptr; for(object_t* o = u.children; o != nullptr; o=o1 ) { o1 = o->sibling; o->free(); } } type->free(this); } unsigned cw::object_t::child_count() const { unsigned n = 0; if( is_container() && u.children != nullptr) { object_t* o = u.children; for(n=1; o->sibling != nullptr; o=o->sibling) ++n; } return n; } cw::rc_t cw::object_t::value( void* dst, unsigned dstTypeId ) { return type->value(this,dstTypeId,dst); } cw::rc_t cw::object_t::value( char& v ) const { return type->value(this,kCharTId,&v); } cw::rc_t cw::object_t::value( int8_t& v ) const { return type->value(this,kInt8TId,&v); } cw::rc_t cw::object_t::value( uint8_t& v ) const { return type->value(this,kUInt8TId,&v); } cw::rc_t cw::object_t::value( int16_t& v ) const { return type->value(this,kInt16TId,&v); } cw::rc_t cw::object_t::value( uint16_t& v ) const { return type->value(this,kUInt16TId,&v); } cw::rc_t cw::object_t::value( int32_t& v ) const { return type->value(this,kInt32TId,&v); } cw::rc_t cw::object_t::value( uint32_t& v ) const { return type->value(this,kUInt32TId,&v); } cw::rc_t cw::object_t::value( int64_t& v ) const { return type->value(this,kInt64TId,&v); } cw::rc_t cw::object_t::value( uint64_t& v ) const { return type->value(this,kUInt64TId,&v); } cw::rc_t cw::object_t::value( float& v ) const { return type->value(this,kFloatTId,&v); } cw::rc_t cw::object_t::value( double& v ) const { return type->value(this,kDoubleTId,&v); } cw::rc_t cw::object_t::value( char*& v ) const { return type->value(this,kStringTId,&v); } const char* cw::object_t::pair_label() const { cwAssert( is_pair() ); if( is_pair() ) return u.children->u.str; return nullptr; } const struct cw::object_str* cw::object_t::pair_value() const { cwAssert( is_pair() ); if( is_pair() ) return u.children->sibling; return nullptr; } const struct cw::object_str* cw::object_t::find( const char* label ) const { if( is_container() ) { for(object_t* o=u.children; o!=nullptr; o=o->sibling) { if( o->is_pair() && textCompare(o->pair_label(),label) == 0 ) return o->pair_value(); const object_t* ch; if((ch = o->find(label)) != nullptr ) return ch; } } return nullptr; } void cw::object_t::print(const print_ctx_t* c) const { print_ctx_t ctx; if( c != nullptr ) ctx = *c; type->print(this,ctx); } cw::rc_t cw::objectFromString( const char* s, object_t*& objRef ) { lex::handle_t lexH; rc_t rc; unsigned lexFlags = 0; unsigned lexId = lex::kErrorLexTId; object_t* cnp = _objAllocate(kRootTId,nullptr); object_t* root = cnp; objRef = nullptr; if((rc = lex::create(lexH,s,textLength(s), lexFlags )) != kOkRC ) return rc; // setup the lexer with additional tokens for(unsigned i=0; _objTokenArray[i].id != lex::kErrorLexTId; ++i) if((rc = lex::registerToken( lexH, _objTokenArray[i].id, _objTokenArray[i].label )) != kOkRC ) { rc = cwLogError(rc,"Object lexer token registration failed on token id:%i : '%s'",_objTokenArray[i].id, _objTokenArray[i].label); goto errLabel; } // main parser loop while((lexId = lex::getNextToken(lexH)) != lex::kErrorLexTId && (lexId != lex::kEofLexTId) && (rc == kOkRC)) { //printf("Lex:%s\n",lexIdToLabel(lexH,lexId)); switch( lexId ) { case kLCurlyLexTId: cnp = _objCreateConainerNode( lexH, cnp, kDictTId ); break; case kRCurlyLexTId: if( cnp == nullptr ) _objSyntaxError(lexH,"An end of 'object' was encountered without an associated 'object' start."); else cnp = cnp->parent; break; case kLHardLexTId: cnp = _objCreateConainerNode( lexH, cnp, kListTId ); break; case kRHardLexTId: if( cnp == nullptr ) rc = _objSyntaxError(lexH,"An end of 'array' was encountered without an associated 'array' start."); else cnp = cnp->parent; break; case kColonLexTId: if( cnp == nullptr || !cnp->is_pair() ) rc = _objSyntaxError(lexH,"A colon was encountered outside a 'pair' node."); break; case kCommaLexTId: if( cnp == nullptr || (!cnp->is_list() && !cnp->is_dict()) ) rc = _objSyntaxError(lexH,"Unexpected comma outside of 'array' or 'object'."); break; case lex::kRealLexTId: _objCreateValueNode( cnp, lex::tokenDouble(lexH), "real" ); break; case lex::kIntLexTId: _objCreateValueNode( cnp, lex::tokenInt(lexH), "int" ); break; case lex::kHexLexTId: _objCreateValueNode( cnp, lex::tokenInt(lexH), "int", kHexFl ); break; case kTrueLexTId: _objCreateValueNode( cnp, true, "true" ); break; case kFalseLexTId: _objCreateValueNode( cnp, false, "false" ); break; case kNullLexTId: _objAppendLeftMostNode( cnp, _objAllocate( kNullTId, cnp )); break; case lex::kIdentLexTId: case lex::kQStrLexTId: { // if the parent is an object then this string must be a pair label if( cnp->is_dict() ) cnp = _objAppendLeftMostNode( cnp, _objAllocate( kPairTId, cnp )); char* v = memDuplStr(lex::tokenText(lexH),lex::tokenCharCount(lexH)); unsigned identFl = lexId == lex::kIdentLexTId ? kIdentFl : 0; _objCreateValueNode( cnp, v, "string", identFl ); } break; case lex::kEofLexTId: break; default: _objSyntaxError(lexH,"Unknown token type (%i) in text.", int(lexId) ); } // if this is a pair node and it now has both values // then make the parent 'object' the current node if( cnp->is_pair() && cnp->child_count()==2 ) cnp = cnp->parent; } objRef = root; errLabel: rc_t rc0 = lex::destroy(lexH); return rc != kOkRC ? rc : rc0; } cw::rc_t cw::objectFromFile( const char* fn, object_t*& objRef ) { rc_t rc = kOkRC; unsigned bufByteCnt = 0; char* buf = NULL; if(( buf = file::fnToStr(fn, &bufByteCnt)) != NULL ) { rc = objectFromString( buf, objRef ); memRelease(buf); } return rc; } void cw::objectPrintTypes( object_t* o0 ) { if( o0->is_container() ) for(object_t* o = o0->u.children; o!=nullptr; o=o->sibling) objectPrintTypes(o); printf("%s ",o0->type->label); }