2025-11-23 13:37:08 +11:00
# include "types.h"
2025-11-23 18:34:30 +11:00
# include <inttypes.h>
2025-11-28 09:23:43 +11:00
# include <stdlib.h>
2025-11-23 13:37:08 +11:00
GroundValue createIntGroundValue ( int64_t in ) {
GroundValue gv ;
gv . data . intVal = in ;
gv . type = INT ;
return gv ;
}
GroundValue createDoubleGroundValue ( double in ) {
GroundValue gv ;
gv . data . doubleVal = in ;
gv . type = DOUBLE ;
return gv ;
}
GroundValue createStringGroundValue ( const char * in ) {
GroundValue gv ;
gv . data . stringVal = strdup ( in ) ;
gv . type = STRING ;
return gv ;
}
GroundValue createCharGroundValue ( char in ) {
GroundValue gv ;
gv . data . charVal = in ;
gv . type = CHAR ;
return gv ;
}
GroundValue createBoolGroundValue ( bool in ) {
GroundValue gv ;
gv . data . boolVal = in ;
gv . type = BOOL ;
return gv ;
}
2025-12-01 10:15:37 +11:00
GroundValue createListGroundValue ( List in ) {
GroundValue gv ;
gv . data . listVal = in ;
gv . type = LIST ;
return gv ;
}
2025-12-06 11:50:42 +11:00
GroundValue createFunctionGroundValue ( GroundFunction * in ) {
GroundValue gv ;
gv . data . fnVal = in ;
gv . type = FUNCTION ;
return gv ;
}
2025-12-01 10:36:09 +11:00
2026-01-18 20:49:50 +11:00
GroundValue createErrorGroundValue ( GroundError in ) {
GroundValue gv ;
gv . data . errorVal = in ;
gv . type = ERROR ;
return gv ;
}
2025-12-06 14:35:13 +11:00
GroundValue createNoneGroundValue ( ) {
GroundValue gv ;
gv . type = NONE ;
return gv ;
}
2025-12-01 10:36:09 +11:00
GroundValue copyGroundValue ( const GroundValue * gv ) {
GroundValue newGv ;
newGv . type = gv - > type ;
switch ( gv - > type ) {
case INT : newGv . data . intVal = gv - > data . intVal ; break ;
case DOUBLE : newGv . data . doubleVal = gv - > data . doubleVal ; break ;
case CHAR : newGv . data . charVal = gv - > data . charVal ; break ;
case BOOL : newGv . data . boolVal = gv - > data . boolVal ; break ;
case STRING :
if ( gv - > data . stringVal ! = NULL ) {
newGv . data . stringVal = strdup ( gv - > data . stringVal ) ;
} else {
newGv . data . stringVal = NULL ;
}
break ;
case LIST : {
List newList = createList ( ) ;
2026-01-17 12:21:43 +11:00
for ( size_t i = 0 ; i < gv - > data . listVal . size ; i + + ) {
2025-12-01 10:36:09 +11:00
// Recursive call to handle nested lists and other types
appendToList ( & newList , copyGroundValue ( & gv - > data . listVal . values [ i ] ) ) ;
}
newGv . data . listVal = newList ;
break ;
}
2025-12-06 11:50:42 +11:00
case FUNCTION : newGv . data . fnVal = gv - > data . fnVal ; break ;
2026-01-15 12:44:09 +11:00
case STRUCTVAL : {
2026-01-27 14:10:12 +11:00
newGv . data . structVal = malloc ( sizeof ( GroundStruct ) ) ;
if ( newGv . data . structVal = = NULL ) {
printf ( " Couldn't allocate memory for GroundStruct copy \n " ) ;
exit ( 1 ) ;
}
newGv . data . structVal - > size = gv - > data . structVal - > size ;
newGv . data . structVal - > fields = malloc ( gv - > data . structVal - > size * sizeof ( GroundStructField ) ) ;
if ( newGv . data . structVal - > fields = = NULL & & gv - > data . structVal - > size > 0 ) {
printf ( " Couldn't allocate memory for GroundStruct fields copy \n " ) ;
exit ( 1 ) ;
}
for ( size_t i = 0 ; i < gv - > data . structVal - > size ; i + + ) {
strncpy ( newGv . data . structVal - > fields [ i ] . id ,
gv - > data . structVal - > fields [ i ] . id ,
sizeof ( newGv . data . structVal - > fields [ i ] . id ) - 1 ) ;
newGv . data . structVal - > fields [ i ] . id [ sizeof ( newGv . data . structVal - > fields [ i ] . id ) - 1 ] = ' \0 ' ;
newGv . data . structVal - > fields [ i ] . value = copyGroundValue ( & gv - > data . structVal - > fields [ i ] . value ) ;
}
2026-01-15 12:44:09 +11:00
break ;
}
2026-01-27 14:10:12 +11:00
case CUSTOM : {
newGv . customType = gv - > customType ;
newGv . data . customVal = malloc ( sizeof ( GroundObject ) ) ;
if ( newGv . data . customVal = = NULL ) {
printf ( " Couldn't allocate memory for GroundObject copy \n " ) ;
exit ( 1 ) ;
}
newGv . data . customVal - > fields = NULL ;
GroundObjectField * field , * tmp ;
HASH_ITER ( hh , gv - > data . customVal - > fields , field , tmp ) {
GroundObjectField * newField = malloc ( sizeof ( GroundObjectField ) ) ;
if ( newField = = NULL ) {
printf ( " Couldn't allocate memory for GroundObjectField copy \n " ) ;
exit ( 1 ) ;
}
strncpy ( newField - > id , field - > id , sizeof ( newField - > id ) - 1 ) ;
newField - > id [ sizeof ( newField - > id ) - 1 ] = ' \0 ' ;
newField - > value = copyGroundValue ( & field - > value ) ;
HASH_ADD_STR ( newGv . data . customVal - > fields , id , newField ) ;
}
2025-12-01 10:36:09 +11:00
break ;
2026-01-27 14:10:12 +11:00
}
2026-01-17 12:21:43 +11:00
case NONE :
default : {
}
2025-12-01 10:36:09 +11:00
}
return newGv ;
}
2025-11-23 18:34:30 +11:00
void printGroundValue ( GroundValue * gv ) {
switch ( gv - > type ) {
case INT : {
printf ( " % " PRId64 " " , gv - > data . intVal ) ;
break ;
}
case DOUBLE : {
printf ( " %f " , gv - > data . doubleVal ) ;
break ;
}
case STRING : {
printf ( " %s " , gv - > data . stringVal ) ;
break ;
}
case CHAR : {
printf ( " %c " , gv - > data . charVal ) ;
break ;
}
case BOOL : {
if ( gv - > data . boolVal ) {
printf ( " true " ) ;
} else {
printf ( " false " ) ;
}
break ;
}
2025-12-01 10:36:09 +11:00
case LIST : {
printf ( " [ " ) ;
2026-01-17 12:21:43 +11:00
for ( size_t i = 0 ; i < gv - > data . listVal . size ; i + + ) {
2025-12-01 10:36:09 +11:00
printGroundValue ( & gv - > data . listVal . values [ i ] ) ;
if ( i < gv - > data . listVal . size - 1 ) {
printf ( " , " ) ;
}
}
printf ( " ] " ) ;
break ;
}
2025-12-08 11:08:08 +11:00
case FUNCTION : {
printf ( " <function> " ) ;
break ;
}
2026-01-24 16:23:01 +11:00
case STRUCTVAL : {
printf ( " <struct fields: { " ) ;
for ( size_t i = 0 ; i < gv - > data . structVal - > size ; i + + ) {
if ( i ! = 0 ) {
printf ( " , " ) ;
}
printf ( " %s: " , gv - > data . structVal - > fields [ i ] . id ) ;
if ( gv - > data . structVal - > fields [ i ] . value . type = = STRING ) {
printf ( " \" " ) ;
printGroundValue ( & gv - > data . structVal - > fields [ i ] . value ) ;
printf ( " \" " ) ;
} else {
printGroundValue ( & gv - > data . structVal - > fields [ i ] . value ) ;
}
}
printf ( " }> " ) ;
break ;
}
case CUSTOM : {
printf ( " <object fields: { " ) ;
for ( size_t i = 0 ; i < gv - > customType - > size ; i + + ) {
if ( i ! = 0 ) {
printf ( " , " ) ;
}
printf ( " %s: " , gv - > customType - > fields [ i ] . id ) ;
GroundObjectField * field = findField ( * gv - > data . customVal , gv - > customType - > fields [ i ] . id ) ;
if ( field = = NULL ) {
printf ( " <missing> " ) ;
} else {
printGroundValue ( & field - > value ) ;
}
}
printf ( " }> " ) ;
break ;
}
case ERROR : {
printf ( " <error type: %s, what: %s> " , gv - > data . errorVal . type , gv - > data . errorVal . what ) ;
break ;
}
case NONE : {
printf ( " <none> " ) ;
2025-11-23 18:34:30 +11:00
break ;
}
}
}
2025-11-23 13:37:08 +11:00
void freeGroundValue ( GroundValue * gv ) {
if ( gv - > type = = STRING & & gv - > data . stringVal ! = NULL ) {
free ( gv - > data . stringVal ) ;
2025-12-01 10:36:09 +11:00
gv - > data . stringVal = NULL ;
2025-11-23 13:37:08 +11:00
}
2025-12-01 10:15:37 +11:00
if ( gv - > type = = LIST & & gv - > data . listVal . values ! = NULL ) {
List * list = & gv - > data . listVal ;
2026-01-17 12:21:43 +11:00
for ( size_t i = 0 ; i < list - > size ; i + + ) {
2025-12-01 10:15:37 +11:00
freeGroundValue ( & list - > values [ i ] ) ;
}
free ( list - > values ) ;
2025-12-01 10:36:09 +11:00
list - > values = NULL ;
gv - > data . listVal = createList ( ) ;
2025-12-01 10:15:37 +11:00
}
2026-01-15 12:44:09 +11:00
if ( gv - > type = = STRUCTVAL & & gv - > data . structVal - > fields ! = NULL ) {
GroundStruct * gstruct = gv - > data . structVal ;
freeGroundStruct ( gstruct ) ;
free ( gstruct ) ;
}
2026-01-18 20:49:50 +11:00
if ( gv - > type = = ERROR ) {
GroundError * error = & gv - > data . errorVal ;
if ( error - > type ! = NULL ) {
free ( error - > type ) ;
}
if ( error - > what ! = NULL ) {
free ( error - > what ) ;
}
if ( error - > where ! = NULL ) {
freeGroundInstruction ( error - > where ) ;
}
}
2025-11-23 13:37:08 +11:00
}
GroundArg createValueGroundArg ( GroundValue value ) {
GroundArg ga ;
ga . value . value = value ;
ga . type = VALUE ;
return ga ;
}
GroundArg createRefGroundArg ( GroundArgType type , const char * refname ) {
GroundArg ga ;
ga . value . refName = strdup ( refname ) ;
ga . type = type ;
return ga ;
}
void freeGroundArg ( GroundArg * ga ) {
if ( ga - > type = = VALUE ) {
freeGroundValue ( & ga - > value . value ) ;
} else {
free ( ga - > value . refName ) ;
}
}
2025-11-23 18:34:30 +11:00
void printGroundArg ( GroundArg * ga ) {
switch ( ga - > type ) {
case VALUE : {
printGroundValue ( & ga - > value . value ) ;
break ;
}
case DIRREF : {
printf ( " &%s " , ga - > value . refName ) ;
break ;
}
case VALREF : {
printf ( " $%s " , ga - > value . refName ) ;
break ;
}
case LINEREF : {
printf ( " %%%s " , ga - > value . refName ) ;
break ;
}
case LABEL : {
printf ( " @%s " , ga - > value . refName ) ;
break ;
}
case FNREF : {
printf ( " !%s " , ga - > value . refName ) ;
break ;
}
case TYPEREF : {
printf ( " -%s " , ga - > value . refName ) ;
break ;
}
}
}
2025-11-23 13:37:08 +11:00
GroundInstruction createGroundInstruction ( GroundInstType type ) {
GroundInstruction gi ;
gi . type = type ;
gi . args . args = NULL ;
gi . args . length = 0 ;
return gi ;
}
void freeGroundInstruction ( GroundInstruction * gi ) {
for ( size_t i = 0 ; i < gi - > args . length ; i + + ) {
freeGroundArg ( & gi - > args . args [ i ] ) ;
}
2025-11-24 10:15:53 +11:00
free ( gi - > args . args ) ;
2025-11-23 13:37:08 +11:00
}
2025-11-24 10:15:53 +11:00
GroundInstruction copyGroundInstruction ( const GroundInstruction * inst ) {
GroundInstruction newInst ;
newInst . type = inst - > type ;
newInst . args . length = inst - > args . length ;
if ( inst - > args . length > 0 ) {
newInst . args . args = malloc ( inst - > args . length * sizeof ( GroundArg ) ) ;
for ( size_t i = 0 ; i < inst - > args . length ; i + + ) {
newInst . args . args [ i ] . type = inst - > args . args [ i ] . type ;
if ( inst - > args . args [ i ] . type = = VALUE ) {
2025-12-01 10:36:09 +11:00
newInst . args . args [ i ] . value . value = copyGroundValue ( & inst - > args . args [ i ] . value . value ) ;
2025-11-24 10:15:53 +11:00
} else {
newInst . args . args [ i ] . value . refName = strdup ( inst - > args . args [ i ] . value . refName ) ;
}
}
} else {
newInst . args . args = NULL ;
}
return newInst ;
}
2025-11-23 13:37:08 +11:00
void addArgToInstruction ( GroundInstruction * gi , GroundArg arg ) {
gi - > args . length + + ;
GroundArg * newArgs = realloc ( gi - > args . args , gi - > args . length * sizeof ( GroundArg ) ) ;
if ( newArgs = = NULL ) {
perror ( " Failed to allocate memory for instruction argument " ) ;
exit ( EXIT_FAILURE ) ;
}
gi - > args . args = newArgs ;
gi - > args . args [ gi - > args . length - 1 ] = arg ;
}
2025-11-23 18:34:30 +11:00
void printGroundInstruction ( GroundInstruction * gi ) {
switch ( gi - > type ) {
case IF :
printf ( " if " ) ;
break ;
case JUMP :
printf ( " jump " ) ;
break ;
case END :
printf ( " end " ) ;
break ;
case INPUT :
printf ( " input " ) ;
break ;
case PRINT :
printf ( " print " ) ;
break ;
case PRINTLN :
printf ( " println " ) ;
break ;
case SET :
printf ( " set " ) ;
break ;
case GETTYPE :
printf ( " gettype " ) ;
break ;
case EXISTS :
printf ( " exists " ) ;
break ;
case SETLIST :
printf ( " setlist " ) ;
break ;
case SETLISTAT :
printf ( " setlistat " ) ;
break ;
case GETLISTAT :
printf ( " getlistat " ) ;
break ;
case GETLISTSIZE :
printf ( " getlistsize " ) ;
break ;
case LISTAPPEND :
printf ( " listappend " ) ;
break ;
case GETSTRSIZE :
printf ( " getstrsize " ) ;
break ;
case GETSTRCHARAT :
printf ( " getstrcharat " ) ;
break ;
case ADD :
printf ( " add " ) ;
break ;
case SUBTRACT :
printf ( " subtract " ) ;
break ;
case MULTIPLY :
printf ( " multiply " ) ;
break ;
case DIVIDE :
printf ( " divide " ) ;
break ;
case EQUAL :
printf ( " equal " ) ;
break ;
case INEQUAL :
printf ( " inequal " ) ;
break ;
case NOT :
printf ( " not " ) ;
break ;
case GREATER :
printf ( " greater " ) ;
break ;
case LESSER :
printf ( " lesser " ) ;
break ;
case STOI :
printf ( " stoi " ) ;
break ;
case STOD :
printf ( " stod " ) ;
break ;
2026-01-24 18:18:52 +11:00
case CTOI :
printf ( " ctoi " ) ;
break ;
case ITOC :
printf ( " itoc " ) ;
break ;
2025-11-23 18:34:30 +11:00
case TOSTRING :
printf ( " tostring " ) ;
break ;
case FUN :
printf ( " fun " ) ;
break ;
case RETURN :
printf ( " return " ) ;
break ;
case ENDFUN :
printf ( " endfun " ) ;
break ;
case PUSHARG :
printf ( " pusharg " ) ;
break ;
case CALL :
printf ( " call " ) ;
break ;
case STRUCT :
printf ( " struct " ) ;
break ;
case ENDSTRUCT :
printf ( " endstruct " ) ;
break ;
case INIT :
printf ( " init " ) ;
break ;
case USE :
printf ( " use " ) ;
break ;
case EXTERN :
printf ( " extern " ) ;
break ;
2025-12-22 14:05:40 +11:00
case DROP :
printf ( " drop " ) ;
break ;
2025-11-23 18:34:30 +11:00
case CREATELABEL :
break ;
2026-01-19 21:14:48 +11:00
case ERRORCMD :
printf ( " error " ) ;
break ;
2025-11-23 18:34:30 +11:00
default :
printf ( " FIXME " ) ;
break ;
}
2025-12-21 11:41:14 +11:00
if ( gi - > type ! = CREATELABEL ) printf ( " " ) ;
2026-01-17 12:21:43 +11:00
for ( size_t i = 0 ; i < gi - > args . length ; i + + ) {
2025-12-21 11:41:14 +11:00
if ( gi - > args . args [ i ] . type = = VALUE & & gi - > args . args [ i ] . value . value . type = = STRING ) {
printf ( " \" " ) ;
printGroundArg ( & gi - > args . args [ i ] ) ;
printf ( " \" " ) ;
} else {
printGroundArg ( & gi - > args . args [ i ] ) ;
}
2025-11-23 18:34:30 +11:00
printf ( " " ) ;
}
}
2025-11-28 09:23:43 +11:00
List createList ( ) {
List list ;
list . size = 0 ;
list . values = malloc ( sizeof ( GroundValue ) ) ;
return list ;
}
void appendToList ( List * list , GroundValue value ) {
if ( list = = NULL ) {
printf ( " Expecting a List ptr, got a null pointer instead. \n This is likely not an error with your Ground program. \n Please report this issue to https://chsp.au/ground/cground \n " ) ;
exit ( EXIT_FAILURE ) ;
}
2025-12-01 10:15:37 +11:00
GroundValue * ptr = realloc ( list - > values , ( list - > size + 1 ) * sizeof ( GroundValue ) ) ;
2025-11-28 09:23:43 +11:00
if ( ptr = = NULL ) {
printf ( " There was an error allocating memory for a list. \n This is likely not an error with your Ground program. \n Please report this issue to https://chsp.au/ground/cground \n " ) ;
exit ( EXIT_FAILURE ) ;
}
list - > size + + ;
list - > values = ptr ;
list - > values [ list - > size - 1 ] = value ;
}
2026-01-17 12:21:43 +11:00
ListAccess getListAt ( List * list , size_t idx ) {
2025-11-28 09:23:43 +11:00
if ( list = = NULL ) {
printf ( " Expecting a List ptr, got a null pointer instead. \n This is likely not an error with your Ground program. \n Please report this issue to https://chsp.au/ground/cground \n " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( idx < list - > size ) {
ListAccess retval ;
retval . value = & list - > values [ idx ] ;
retval . status = LIST_OKAY ;
return retval ;
} else {
ListAccess retval ;
retval . value = NULL ;
retval . status = LIST_OUT_OF_BOUNDS ;
return retval ;
}
}
2026-01-17 12:21:43 +11:00
ListAccessStatus setListAt ( List * list , size_t idx , GroundValue value ) {
2025-11-28 09:23:43 +11:00
if ( list = = NULL ) {
printf ( " Expecting a List ptr, got a null pointer instead. \n This is likely not an error with your Ground program. \n Please report this issue to https://chsp.au/ground/cground \n " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( idx < list - > size ) {
list - > values [ idx ] = value ;
return LIST_OKAY ;
} else {
return LIST_OUT_OF_BOUNDS ;
}
}
2026-01-15 12:44:09 +11:00
GroundStruct createStruct ( ) {
return ( GroundStruct ) {
. fields = malloc ( sizeof ( GroundStructField ) ) ,
. size = 0
} ;
}
void addFieldToStruct ( GroundStruct * gstruct , char * name , GroundValue field ) {
GroundStructField * tmpPointer = realloc ( gstruct - > fields , ( gstruct - > size + 1 ) * sizeof ( GroundStructField ) ) ;
if ( tmpPointer = = NULL ) {
printf ( " Couldn't allocate memory for GroundStruct \n " ) ;
exit ( 1 ) ;
}
gstruct - > size + + ;
gstruct - > fields = tmpPointer ;
gstruct - > fields [ gstruct - > size - 1 ] . value = field ;
strncpy ( gstruct - > fields [ gstruct - > size - 1 ] . id , name , sizeof ( gstruct - > fields - > id ) - 1 ) ;
gstruct - > fields [ gstruct - > size - 1 ] . id [ sizeof ( gstruct - > fields [ gstruct - > size - 1 ] . id ) - 1 ] = ' \0 ' ;
}
void freeGroundStruct ( GroundStruct * gstruct ) {
for ( size_t i = 0 ; i < gstruct - > size ; i + + ) {
freeGroundValue ( & gstruct - > fields [ i ] . value ) ;
}
}
void addFieldToObject ( GroundObject * object , const char * id , GroundValue data ) {
GroundObjectField * field = malloc ( sizeof ( GroundObjectField ) ) ;
if ( field = = NULL ) {
printf ( " Couldnt allocate stuff lmao \n " ) ;
exit ( 1 ) ;
}
strncpy ( field - > id , id , sizeof ( field - > id ) - 1 ) ;
field - > id [ sizeof ( field - > id ) - 1 ] = ' \0 ' ;
field - > value = copyGroundValue ( & data ) ;
HASH_ADD_STR ( object - > fields , id , field ) ;
}
GroundObject createObject ( GroundStruct gstruct ) {
GroundObject object ;
object . fields = NULL ;
for ( size_t i = 0 ; i < gstruct . size ; i + + ) {
addFieldToObject ( & object , gstruct . fields [ i ] . id , gstruct . fields [ i ] . value ) ;
}
return object ;
}
GroundObjectField * findField ( GroundObject head , const char * id ) {
GroundObjectField * s ;
HASH_FIND_STR ( head . fields , id , s ) ;
return s ;
}
void freeGroundObject ( GroundObject * object ) {
GroundObjectField * current_field , * tmp ;
HASH_ITER ( hh , object - > fields , current_field , tmp ) {
HASH_DEL ( object - > fields , current_field ) ;
freeGroundValue ( & current_field - > value ) ;
free ( current_field ) ;
}
object - > fields = NULL ;
}
2026-01-18 20:49:50 +11:00
GroundError createGroundError ( char * what , char * type , GroundInstruction * where , size_t * line ) {
GroundError ge ;
if ( what ! = NULL ) {
ge . what = malloc ( strlen ( what ) + 1 ) ;
strcpy ( ge . what , what ) ;
} else {
ge . what = NULL ;
}
if ( type ! = NULL ) {
ge . type = malloc ( strlen ( type ) + 1 ) ;
strcpy ( ge . type , type ) ;
} else {
2026-01-18 21:37:46 +11:00
ge . type = malloc ( strlen ( " GenericError " ) + 1 ) ;
strcpy ( ge . type , " GenericError " ) ;
2026-01-18 20:49:50 +11:00
}
if ( where ! = NULL ) {
ge . where = malloc ( sizeof ( GroundInstruction ) ) ;
* ge . where = copyGroundInstruction ( where ) ;
} else {
ge . where = NULL ;
}
if ( line ! = NULL ) {
ge . line = * line ;
} else {
2026-01-18 21:37:46 +11:00
ge . line = 0 ;
ge . hasLine = false ;
2026-01-18 20:49:50 +11:00
}
return ge ;
}
2026-01-20 19:55:38 +11:00
bool checkFnTypes ( GroundValue * left , GroundFunctionArgs * right ) {
if ( left - > type ! = right - > type ) {
return false ;
}
if ( left - > type = = CUSTOM ) {
if ( left - > customType - > size ! = right - > customType - > size ) {
return false ;
}
for ( size_t i = 0 ; i < left - > customType - > size ; i + + ) {
if ( strcmp ( left - > customType - > fields [ i ] . id , right - > customType - > fields [ i ] . id ) ! = 0 ) {
return false ;
}
if ( ! checkTypes ( & left - > customType - > fields [ i ] . value , & right - > customType - > fields [ i ] . value ) ) {
return false ;
}
}
}
return true ;
}
bool checkTypes ( GroundValue * left , GroundValue * right ) {
if ( left - > type ! = right - > type ) {
return false ;
}
if ( left - > type = = CUSTOM ) {
if ( left - > customType - > size ! = right - > customType - > size ) {
return false ;
}
for ( size_t i = 0 ; i < left - > customType - > size ; i + + ) {
if ( strcmp ( left - > customType - > fields [ i ] . id , right - > customType - > fields [ i ] . id ) ! = 0 ) {
return false ;
}
if ( ! checkTypes ( & left - > customType - > fields [ i ] . value , & right - > customType - > fields [ i ] . value ) ) {
return false ;
}
}
}
return true ;
}