namespace eval st {

# Autogenerated with DRAKON Editor 1.27

proc access_decl { field_name user } {
    #item 748
    set result {}
    #item 724
    unpack $user fields snippets name
    #item 725
    set field [ get_value $fields $field_name ]
    set type     [ get_value $field "type" ]
    set class    [ get_value $field "class" ]
    set generate [ get_value $field "generate" ]
    #item 7260001
    if {$type == "value"} {
        #item 745
        if {[ str_contains $generate "getter" ]} {
            #item 750
            if {[ str_contains $class "*" ]} {
                #item 752
                lappend result [ snip $snippets \
                  VALUE_GETTER_PTR NAME $name \
                  ITEM $class PROP $field_name]
            } else {
                #item 749
                lappend result [ snip $snippets \
                  VALUE_GETTER_NORMAL NAME $name \
                  ITEM $class PROP $field_name]
            }
        } else {
            
        }
        #item 753
        if {[ str_contains $generate "setter" ]} {
            #item 756
            lappend result [ snip $snippets \
              VALUE_SETTER NAME $name \
              ITEM $class PROP $field_name]
        } else {
            
        }
    } else {
        #item 7260002
        if {$type == "own"} {
            #item 757
            if {[ str_contains $generate "getter" ]} {
                #item 760
                lappend result [ snip $snippets \
                  OWN_GETTER NAME $name \
                  ITEM $class PROP $field_name]
            } else {
                
            }
            #item 761
            if {[ str_contains $generate "setter" ]} {
                #item 764
                lappend result [ snip $snippets \
                  OWN_SETTER NAME $name \
                  ITEM $class PROP $field_name]
            } else {
                
            }
            #item 765
            if {[ str_contains $generate "taker" ]} {
                #item 768
                lappend result [ snip $snippets \
                  OWN_TAKER NAME $name \
                  ITEM $class PROP $field_name]
            } else {
                
            }
        } else {
            #item 7260003
            if {$type == "inline"} {
                #item 770
                if {[ str_contains $generate "getter" ]} {
                    #item 773
                    lappend result [ snip $snippets \
                      INLINE_GETTER NAME $name \
                      ITEM $class PROP $field_name]
                } else {
                    
                }
            } else {
                #item 744
                error "$name: unknown type $type of field $field_name"
            }
        }
    }
    #item 774
    return [ join $result "\n" ]
}

proc add_comma { line } {
    #item 681
    if {[ str_contains $line " //" ]} {
        #item 685
        set result [ string map { " //" ", //" } $line ]
    } else {
        #item 684
        set result "$line,"
    }
    #item 686
    return $result
}

proc add_index_info { field_names fields indices name } {
    #item 1053
    set state [ list {} $fields $name ]
    unpack [ lfold $indices st::check_index_fields $state ] indexed_fields
    #item 1054
    set unique_indexed [ lsort -unique $indexed_fields ]
    #item 1051
    set user_data [ list $fields $unique_indexed $name ]
    set enriched_fields [ lmap_user $field_names st::add_index_info_to_field $user_data ]
    #item 1055
    return $enriched_fields
}

proc add_index_info_to_field { field_name user_data } {
    #item 1061
    unpack $user_data fields unique_indexed name
    #item 1062
    set field [ get_value $fields $field_name ]
    #item 1063
    set fname    [ get_value $field "name" ]
    set generate [ get_value $field "generate" ]
    #item 1064
    set methods [ make_list $generate ]
    #item 1065
    if {[ contains $unique_indexed $fname ]} {
        #item 1828
        put_value field "indexed" "yes"
        #item 1068
        if {([ contains $methods "setter" ]) || ([ contains $methods "taker" ])} {
            #item 1073
            error "Field $fname of table $name is indexed and therefore read only."
        } else {
            #item 1076
            if {[ contains $methods "ctr" ]} {
                
            } else {
                #item 1075
                lappend methods "ctr"
            }
            #item 1074
            put_value field "generate" $methods
            #item 1078
            return $field
        }
    } else {
        #item 1074
        put_value field "generate" $methods
        #item 1078
        return $field
    }
}

proc add_structures { structures struct_h_name struct_c_name } {
    #item 3587
    upvar $struct_h_name struct_h
    upvar $struct_c_name struct_c
    #item 3652
    if {$struct_c == ""} {
        
    } else {
        #item 3655
        set includes "#include <stdlib.h>\n#include <string.h>\n"
        set struct_c "$includes$struct_c"
    }
    foreach str $structures {
        #item 3609
        set forward [ inl_make_forward $str ]
        set struct_h "$forward\n$struct_h"
    }
    #item 3606
    set impl_lines {}
    foreach str $structures {
        #item 3612
        print_class_impl $str impl_lines
    }
    #item 3613
    set impl [ join $impl_lines "\n" ]
    #item 3614
    set struct_c "$impl\n$struct_c"
}

proc build_arg_list { lines } {
    #item 667
    if {$lines == {}} {
        #item 670
        return "    void"
    } else {
        #item 673
        set leading [ lrange $lines 0 end-1 ]
        set last [ lindex $lines end ]
        #item 674
        set leading2 [ lmap $leading st::add_comma ]
        #item 675
        lappend leading2 $last
        #item 671
        return [ join $leading2 "\n" ]
    }
}

proc build_ctr_start { fields field_names snippets name } {
    #item 693
    set user [ list $fields $snippets $name ]
    #item 694
    set ctr_args [ lfilter_user $field_names \
    	st::in_ctr $fields ]
    #item 695
    set arg_lines [ lmap_user $ctr_args \
      st::make_arg $user ]
    #item 697
    set arg_lines [ build_arg_list $arg_lines ]
    #item 699
    set result ""
    #item 692
    append result [ snip $snippets CTR_START \
     NAME $name ]
    #item 701
    append result "\n"
    #item 696
    append result $arg_lines
    #item 698
    return $result
}

proc check_index_fields { index state } {
    #item 1033
    unpack $state indexed fields name
    #item 1008
    set iname       [ get_value $index "name" ]
    set fields_cell [ get_value $index "fields" ]
    #item 1009
    set ifields [ make_list $fields_cell ]
    #item 1010
    if {$ifields == {}} {
        #item 1013
        set msg \
        "Index $iname of table $name does not have fields."
        #item 1040
        error $msg
    } else {
        #item 1014
        if {[ is_unique $ifields ]} {
            foreach ifield $ifields {
                #item 1017
                set field_key [ find_key $fields $ifield ]
                #item 1020
                if {$field_key == -1} {
                    #item 1022
                    set msg \
                    "Index $iname of table $name: field $ifield not found."
                    #item 1040
                    error $msg
                    break
                } else {
                    
                }
                #item 1023
                incr field_key
                set field [ lindex $fields $field_key ]
                set type [ get_value $field "type" ]
                #item 10360001
                if {($type == "value") || ($type == "own")} {
                    
                } else {
                    #item 1030
                    set msg [ concat \
                    "Index $iname of table $name: " \
                    "fields of type $type cannot be indexed." ]
                    #item 1040
                    error $msg
                    break
                }
            }
        } else {
            #item 1016
            set msg \
            "Index $iname of table $name has repeating fields."
            #item 1040
            error $msg
        }
    }
    #item 1038
    set indexed2 [ concat $indexed $ifields ]
    #item 1039
    return [ list $indexed2 $fields $name ]
}

proc class_cast { name } {
    #item 3641
    set dname "${name}_FromObject"
    #item 3640
    set returns [ list "$name*" "" ]
    #item 3638
    set obj [ sfield "void*" "obj" "" ]
    set args [ list $obj ]
    #item 3639
    set comment "Casts Object to $name."
    #item 3637
    set signature [ ssignature $dname $returns $args $comment ]
    #item 3643
    set lines {}
    #item 3649
    lappend lines "${name}* tObj;"
    lappend lines "if \(!obj\) abort\(\);"
    lappend lines "tObj = \(${name}*\)obj;"
    lappend lines "if \(tObj->Super.Type != &g${name}\) abort\(\);"
    lappend lines "return tObj;"
    #item 3650
    return [ smethod $signature {} $lines ]
}

proc class_category { class } {
    #item 2483
    set char {
     char
     byte
     int8
     int8_t
    }
    #item 2484
    set uchar {
     "unsigned char"
     uchar
     ubyte
     uint8
     uint8_t
    }
    #item 2485
    set short {
     short
     int16
     int16_t
    }
    #item 2488
    set ushort {
     "unsigned short"
     ushort
     uint16
     uint16_t
    }
    #item 2486
    set int {
     int
     int32
     int32_t
    }
    #item 2489
    set uint {
     uint
     "unsigned int"
     uint32
     uint32_t
    }
    #item 2487
    set int64 {
     "long long"
     int64
     int64_t
    }
    #item 2490
    set uint64 {
     "unsigned long long"
     uint64
     uint64_t
    }
    #item 2491
    if {[ contains $char $class ]} {
        #item 2552
        set pre Char
        set type char
    } else {
        #item 2495
        if {[ contains $uchar $class ]} {
            #item 2553
            set pre UChar
            set type "unsigned char"
        } else {
            #item 2498
            if {[ contains $short $class ]} {
                #item 2554
                set pre Short
                set type "short"
            } else {
                #item 2502
                if {[ contains $ushort $class ]} {
                    #item 2555
                    set pre UShort
                    set type "unsigned short"
                } else {
                    #item 2505
                    if {[ contains $int $class ]} {
                        #item 2556
                        set pre Int
                        set type "int"
                    } else {
                        #item 2508
                        if {[ contains $uint $class ]} {
                            #item 2557
                            set pre UInt
                            set type "unsigned int"
                        } else {
                            #item 2510
                            if {[ contains $int64 $class ]} {
                                #item 2558
                                set pre Int64
                                set type "long long"
                            } else {
                                #item 2513
                                if {[ contains $uint64 $class ]} {
                                    #item 2559
                                    set pre UInt64
                                    set type "unsigned long long"
                                } else {
                                    #item 2516
                                    if {$class == "double"} {
                                        #item 2560
                                        set pre Double
                                        set type "double"
                                    } else {
                                        #item 2519
                                        if {$class == "float"} {
                                            #item 2561
                                            set pre Float
                                            set type "float"
                                        } else {
                                            #item 2522
                                            set pre $class
                                            set type ""
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    #item 2562
    return [ list $pre $type ]
}

proc class_clone { name fields } {
    #item 2953
    set fnames [ get_keys $fields ]
    #item 2959
    set own_names [ lfilter_user \
     $fnames st::is_own $fields ]
    #item 2958
    set dname "${name}_Clone"
    #item 2957
    set returns [ list "$name*" "Returns ownership. Can be null." ]
    #item 2955
    set obj [ sfield "const $name*" "obj" "Can be null." ]
    #item 2956
    set comment "Clones $name."
    #item 2954
    set signature [ ssignature $dname $returns [ list $obj ] $comment ]
    #item 2973
    set lines {}
    lappend lines "$name* newItem;"
    lappend lines "if \(!obj\) return 0;"
    #item 2966
    lappend lines \
     "newItem = Allocator_Allocate\(sizeof\($name\), 1\);"
    #item 2967
    lappend lines "*newItem = *obj;"
    #item 2961
    add_range lines [ lmap_user $own_names st::field_clone $fields ]
    #item 2963
    lappend lines "return newItem;"
    #item 2962
    return [ smethod $signature {} $lines ]
}

proc class_create { name fields smachine } {
    #item 2865
    set dname "${name}_Create"
    #item 2864
    set returns [ list "$name*" "Returns ownership." ]
    #item 2885
    set fnames [ get_keys $fields ]
    #item 3660
    set own_names [ lfilter_user \
     $fnames st::is_own $fields ]
    #item 3661
    set ctr_fields [ lfilter_user \
      $fnames st::ctr_field $fields ]
    #item 2886
    set args [ lmap_user $ctr_fields st::ctr_arg $fields ]
    #item 2863
    set comment "Creates a new instance of $name."
    #item 2861
    set signature [ ssignature $dname $returns $args $comment ]
    #item 2898
    set lines [ new_obj $name ]
    #item 3488
    if {$smachine == {}} {
        
    } else {
        #item 3491
        set states [ get_value $smachine states ]
        set first_state [ lindex $states 0 ]
        #item 3492
        lappend lines "obj->State = &${name}_${first_state}_State;"
    }
    foreach fname $ctr_fields {
        #item 2893
        lappend lines "obj->$fname = $fname;"
    }
    foreach fname $own_names {
        #item 3664
        if {[ contains $ctr_fields $fname ]} {
            
        } else {
            #item 3674
            lappend lines [ field_ctr $fname $fields "obj" ]
        }
    }
    #item 2882
    lappend lines "return obj;"
    #item 2884
    return [ smethod $signature {} $lines ]
}

proc class_destroy { name fields dtr } {
    #item 2913
    set fnames [ get_keys $fields ]
    #item 2919
    set own_names [ lfilter_user \
     $fnames st::is_own $fields ]
    #item 2918
    set dname "${name}_Destroy"
    #item 2917
    set returns { "void" "" }
    #item 2915
    set obj [ sfield "$name*" "obj" "" ]
    set args [ list $obj ]
    #item 2916
    set comment "Destroys $name."
    #item 2914
    set signature [ ssignature $dname $returns $args $comment ]
    #item 2920
    set lines {}
    lappend lines "if \(!obj\) return; "
    #item 2923
    if {$dtr} {
        #item 2926
        lappend lines "${name}_Destructor\(obj\);"
    } else {
        
    }
    #item 2921
    add_range lines [ lmap_user $own_names st::field_dtr $fields ]
    #item 2922
    lappend lines "Allocator_Free\(obj\);"
    #item 2927
    return [ smethod $signature {} $lines ]
}

proc class_load { item fields smachine } {
    #item 3151
    set fnames [ get_keys $fields ]
    #item 3167
    set ser_fields [ select_ser_fields $fields ]
    #item 3156
    set dname "${item}_Load"
    #item 3155
    set returns { "int" "Returns non-zero on success." }
    #item 3153
    set dst [ sfield "$item**" "dst" "" ]
    set str [ sfield "ReadStream*" "stream" "" ]
    set args [ list $dst $str ]
    #item 3154
    set comment "Loads $item."
    #item 3152
    set signature [ ssignature $dname $returns $args $comment ]
    #item 3185
    set fcount [ count_serializable $fields ]
    #item 3157
    set lines {}
    lappend lines "$item* item;"
    lappend lines "short fcount;"
    #item 3515
    if {$smachine == {}} {
        
    } else {
        #item 3518
        lappend lines "short state;"
    }
    #item 3186
    lappend lines "if \(!Short_Read\(stream, &fcount\)\) return 0;"
    #item 3187
    lappend lines "if \(fcount == 0\) \{"
    lappend lines "    *dst = 0;"
    lappend lines "    return 1;"
    lappend lines "\}"
    lappend lines "if \(fcount > $fcount\) return 0;"
    #item 3161
    lappend lines \
     "item = Allocator_Allocate\(sizeof\($item\), 1\);"
    #item 3188
    lappend lines "item->Super.Type = &g$item;"
    #item 3519
    if {$smachine == {}} {
        
    } else {
        #item 3525
        set states [ get_value $smachine states ]
        #item 3526
        set state_count [ llength $states ]
        #item 3522
        lappend lines "if \(!Short_Read\(stream, &state\)\) goto delete_item;"
        #item 3523
        lappend lines "switch \(state\) \{"
        lappend lines "    case 0:"
        lappend lines "        item->State = 0;"
        lappend lines "        break;"
        #item 35270001
        set i 0
        while { 1 } {
            #item 35270002
            if {$i < $state_count} {
                
            } else {
                break
            }
            #item 3529
            set state [ lindex $states $i ]
            set id [ expr { $i + 1 } ]
            #item 3530
            lappend lines "    case $id:"
            lappend lines "        item->State = &${item}_${state}_State;"
            lappend lines "        break;"
            #item 35270003
            incr i
        }
        #item 3524
        lappend lines "    default:"
        lappend lines "        goto delete_item;"
        lappend lines "\}"
    }
    #item 31680001
    set i 0
    while { 1 } {
        #item 31680002
        if {$i < [ llength $ser_fields ]} {
            
        } else {
            break
        }
        #item 3170
        set fname [ lindex $ser_fields $i ]
        #item 3171
        add_range lines [ field_load $fname $fields $i ]
        #item 31680003
        incr i
    }
    #item 3172
    lappend lines "*dst = item;"
    lappend lines "return 1;"
    #item 3504
    lappend lines "delete_item:"
    foreach fname $ser_fields {
        #item 3507
        set field [ get_value $fields $fname ]
        set type [ get_value $field type ]
        set class [ get_value $field class ]
        #item 3508
        if {$type == "own"} {
            #item 3511
            lappend lines "${class}_Destroy\(item->$fname\);"
        } else {
            
        }
    }
    #item 3503
    lappend lines "Allocator_Free\(item\);"
    lappend lines "return 0;"
    #item 3158
    return [ smethod $signature {} $lines ]
}

proc class_save { item fields smachine } {
    #item 3115
    set fnames [ get_keys $fields ]
    #item 3127
    set ser_fields [ select_ser_fields $fields ]
    #item 3120
    set dname "${item}_Save"
    #item 3119
    set returns { "int" "Returns non-zero on success." }
    #item 3117
    set obj [ sfield "const $item*" "item" "Can be null." ]
    set ign [ sfield "WriteStream*" "stream" "" ]
    #item 3118
    set comment "Saves $item."
    #item 3116
    set signature [ ssignature $dname $returns [ list $obj $ign ] $comment ]
    #item 3129
    set fcount [ count_serializable $fields ]
    #item 3132
    if {$fcount == 0} {
        #item 3135
        error "$item does not have serializable fields."
    } else {
        
    }
    #item 3121
    set lines {}
    #item 3130
    lappend lines "if \(!item\) \{"
    lappend lines "    return Short_Write\(stream, 0\);"
    lappend lines "\}"
    #item 3131
    lappend lines "if \(!Short_Write\(stream, $fcount\)\) return 0;"
    #item 3493
    if {$smachine == {}} {
        
    } else {
        #item 3496
        lappend lines "if \(!item->State\) \{"
        lappend lines "    if \(!Short_Write\(stream, 0\)\) return 0;"
        lappend lines "\} else \{"
        lappend lines "    if \(!Short_Write\(stream, \(short\)item->State->Id\)\) return 0;"
        lappend lines "\}"
    }
    #item 3137
    set user_data [ list $fields 0 ]
    add_range lines [ lmap_user $ser_fields st::field_save $user_data ]
    #item 3124
    lappend lines "return 1;"
    #item 3123
    return [ smethod $signature {} $lines ]
}

proc clone_item { name item fields indices } {
    #item 2342
    set fnames [ get_keys $fields ]
    #item 2348
    set own_names [ lfilter_user \
     $fnames st::is_own $fields ]
    #item 2347
    set dname "${item}_CloneItem"
    #item 2346
    set returns { "int" "" }
    #item 2344
    set obj [ sfield "$item*" "obj" "" ]
    set ign [ sfield "void*" "userData" "" ]
    #item 2345
    set comment "Clones $item."
    #item 2343
    set signature [ ssignature $dname $returns [ list $obj $ign ] $comment ]
    #item 2349
    set lines {}
    lappend lines "$name* table;"
    lappend lines "$item* newItem;"
    #item 2359
    lappend lines "table = userData;"
    #item 2360
    lappend lines \
     "newItem = Allocator_Allocate\(sizeof\($item\), 1\);"
    #item 2361
    lappend lines \
     "*newItem = *obj;"
    #item 2362
    lappend lines \
     "newItem->_parent_ = table;"
    #item 2350
    add_range lines [ lmap_user $own_names st::field_clone $fields ]
    foreach index $indices {
        #item 2372
        set iname [ get_value $index name ]
        #item 2373
        lappend lines \
         "Hashtable_Put\(table->$iname, newItem\);"
    }
    #item 2357
    lappend lines "return 0;"
    #item 2356
    return [ smethod $signature {static} $lines ]
}

proc count_serializable { fields } {
    #item 2405
    set ser_fields [ select_ser_fields $fields ]
    #item 2406
    return [ llength $ser_fields ]
}

proc create_clone { name item fields indices } {
    #item 2298
    set dname "${name}_Clone"
    #item 2297
    set returns [ list "$name*" "Returns ownership." ]
    #item 2295
    set obj [ sfield "const $name*" "old" "" ]
    #item 2296
    set comment "Creates a deep copy of $name."
    #item 2294
    set signature [ ssignature $dname $returns [ list $obj ] $comment ]
    #item 2317
    set first [ lindex $indices 0 ]
    set iname [ get_value $first name ]
    #item 2320
    set lines {}
    lappend lines "$name* obj;"
    lappend lines "assert\(old\);"
    #item 2322
    lappend lines "obj = ${name}_Create\(\);"
    #item 2316
    lappend lines \
     "Hashtable_Foreach\(old->$iname, \(VisitorFun\)${item}_CloneItem, obj\);"
    #item 2321
    lappend lines "return obj;"
    #item 2318
    return [ smethod $signature {} $lines ]
}

proc create_count { name indices } {
    #item 1874
    set dname "${name}_Count"
    #item 1873
    set returns { int ">= 0" }
    #item 1871
    set obj [ sfield "const $name*" "obj" "" ]
    #item 1872
    set comment "Gets the number of records in the table."
    #item 1870
    set signature [ ssignature $dname $returns [ list $obj ] $comment ]
    #item 1893
    set first [ lindex $indices 0 ]
    set iname [ get_value $first name ]
    #item 1886
    set lines {}
    #item 1895
    lappend lines "assert\(obj\);"
    #item 1892
    lappend lines \
     "return Hashtable_Count\(obj->$iname\);"
    #item 1894
    return [ smethod $signature {} $lines ]
}

proc create_ctr { name item indices } {
    #item 1396
    set dname "${name}_Create"
    #item 1395
    set returns [ list "$name*" "Returns ownership." ]
    #item 1394
    set comment "Creates a new $name."
    #item 1392
    set signature [ ssignature $dname $returns {} $comment ]
    #item 1422
    set lines [ new_obj $name ]
    foreach index $indices {
        #item 1420
        set iname [ get_value $index name ]
        #item 1425
        set eq "${item}_${iname}_Equal"
        set hash "${item}_${iname}_Hash"
        #item 1421
        lappend lines "obj->$iname = Hashtable_Create\(\(GetHashCodeFun\)$hash, \(EqualsFun\)$eq\);"
    }
    #item 1424
    lappend lines "return obj;"
    #item 1416
    return [ smethod $signature {} $lines ]
}

proc create_delete { name item indices } {
    #item 1904
    set dname "${name}_Delete"
    #item 1903
    set returns { "void" "" }
    #item 1901
    set obj [ sfield "$name*" "table" "" ]
    set rec [ sfield "$item*" "item" "" ]
    set args [ list $obj $rec ]
    #item 1902
    set comment "Removes a record from the table $name. "
    append comment "Also destroys the record."
    #item 1900
    set signature [ ssignature $dname $returns $args $comment ]
    #item 1916
    set lines {}
    lappend lines "assert\(table\);"
    lappend lines "assert\(item\);"
    lappend lines "assert\(item->_parent_ == table\);"
    foreach index $indices {
        #item 1919
        set iname [ get_value $index name ]
        #item 1920
        lappend lines \
         "Hashtable_Remove\(table->$iname, item\);"
    }
    #item 1937
    lappend lines "${item}_DeleteItem\(item, 0\);"
    #item 1923
    return [ smethod $signature {} $lines ]
}

proc create_dtr { name item indices } {
    #item 1354
    set dname "${name}_Destroy"
    #item 1353
    set returns { void "" }
    #item 1351
    set obj [ sfield "$name*" "obj" "Can be null. Takes ownership." ]
    #item 1352
    set comment "Destroys an instance of $name."
    #item 1350
    set signature [ ssignature $dname $returns [ list $obj ] $comment ]
    #item 1387
    set first [ lindex $indices 0 ]
    set iname [ get_value $first name ]
    #item 1380
    set lines [ dtr_null_check ]
    #item 1386
    lappend lines \
     "Hashtable_Foreach\(obj->$iname, \(VisitorFun\)${item}_DeleteItem\, 0\);"
    foreach index $indices {
        #item 1383
        set iname [ get_value $index name ]
        #item 1384
        lappend lines "Hashtable_Destroy\(obj->$iname\);"
    }
    #item 1385
    lappend lines [ delete_me ]
    #item 1388
    return [ smethod $signature {} $lines ]
}

proc create_find { name item iname fields ifields } {
    #item 2009
    set dname "${name}_${iname}"
    #item 2008
    set returns [ list "$item*" "Can be null \(if not found\)" ]
    #item 2006
    set obj [ sfield "$name*" "_table_" "" ]
    #item 2030
    set args [ list $obj ]
    add_range args \
     [ lmap_user $ifields st::find_arg $fields ]
    #item 2007
    set comment "Finds an $item by index $iname."
    #item 2005
    set signature [ ssignature $dname $returns $args $comment ]
    #item 2021
    set lines {}
    lappend lines "$item _key_;"
    foreach ifield $ifields {
        #item 2049
        set field [ get_value $fields $ifield ]
        set type [ get_value $field type ]
        set class [ get_value $field class ]
        #item 2050
        if {$type == "own"} {
            #item 2025
            lappend lines "_key_.$ifield = ($class*)$ifield;"
        } else {
            #item 2053
            lappend lines "_key_.$ifield = $ifield;"
        }
    }
    #item 2026
    lappend lines "return Hashtable_Get\(_table_->$iname, &_key_\);"
    #item 2029
    return [ smethod $signature {} $lines ]
}

proc create_foreach { name item indices } {
    #item 1945
    set dname "${name}_Foreach"
    #item 1944
    set returns { int "Returns non-zero if iteration was interrupted." }
    #item 1942
    set obj [ sfield "$name*" "obj" "" ]
    set fun [ sfield "${item}Visitor" "visitor" "" ]
    set use [ sfield "void*" "userData" "A pointer to user data" ]
    set args [ list $obj $fun $use ]
    #item 1943
    set comment "Applies an operation to each record."
    #item 1941
    set signature [ ssignature $dname $returns $args $comment ]
    #item 1959
    set first [ lindex $indices 0 ]
    set iname [ get_value $first name ]
    #item 1957
    set lines {}
    #item 1961
    lappend lines "assert\(obj\);"
    lappend lines "assert\(visitor\);"
    #item 1958
    lappend lines \
     "return Hashtable_Foreach\(obj->$iname, \(VisitorFun\)visitor, userData\);"
    #item 1960
    return [ smethod $signature {} $lines ]
}

proc create_insert { name item fields indices } {
    #item 1799
    set dname "${name}_Insert"
    #item 1798
    set returns [ list "$item*" "Can be null." ]
    #item 1796
    set obj [ sfield "$name*" "_table_" "" ]
    #item 1837
    set fnames [ get_keys $fields ]
    set ctr_fields [ lfilter_user $fnames st::ctr_field $fields ]
    #item 3675
    set own_names [ lfilter_user \
     $fnames st::is_own $fields ]
    #item 1818
    set indexed [ lfilter_user $fnames st::indexed_field $fields ]
    #item 1855
    set args [ list $obj ]
    add_range args \
     [ lmap_user $ctr_fields st::ctr_arg $fields ]
    #item 1797
    set comment "Creates a new record in the table $name. "
    append comment \
      "Returns null if unique constraints are violated"
    #item 1795
    set signature [ ssignature $dname $returns $args $comment ]
    #item 1811
    set lines {}
    lappend lines "$item _key_;"
    lappend lines "$item* _new_;"
    lappend lines "assert\(_table_\);"
    foreach fname $indexed {
        #item 1858
        lappend lines "_key_.$fname = $fname;"
    }
    foreach index $indices {
        #item 1814
        set iname [ get_value $index name ]
        #item 1815
        lappend lines \
         "if \(Hashtable_Get\(_table_->$iname, &_key_\)\) \{ return 0; \}"
    }
    #item 1861
    lappend lines \
     "_new_ = Allocator_Allocate\(sizeof\($item\), 1\);"
    lappend lines \
     "_new_->_parent_ = _table_;"
    foreach fname $ctr_fields {
        #item 1862
        lappend lines "_new_->$fname = $fname;"
    }
    foreach fname $own_names {
        #item 3677
        if {[ contains $ctr_fields $fname ]} {
            
        } else {
            #item 3680
            lappend lines [ field_ctr $fname $fields "_new_" ]
        }
    }
    foreach index $indices {
        #item 1865
        set iname [ get_value $index name ]
        #item 1866
        lappend lines \
         "Hashtable_Put\(_table_->$iname, _new_\);"
    }
    #item 1816
    lappend lines "return _new_;"
    #item 1819
    return [ smethod $signature {} $lines ]
}

proc create_load { name item fields } {
    #item 2657
    set dname "${name}_Load"
    #item 2656
    set returns [ list "int" "Returns non-zero on success." ]
    #item 2654
    set obj [ sfield "$name**" "obj" "Pointer to output." ]
    set str [ sfield "ReadStream*" "stream" "" ]
    set args [ list $obj $str ]
    #item 2655
    set comment "Loads $name from the binary stream."
    #item 2653
    set signature [ ssignature $dname $returns $args $comment ]
    #item 2673
    set lines {}
    lappend lines "short fcount;"
    lappend lines "int count, i;"
    lappend lines "$name* table;"
    #item 2676
    set fcount [ count_serializable $fields ]
    #item 2683
    lappend lines "if \(!Short_Read\(stream, &fcount\)\) return 0;"
    lappend lines "if \(fcount < 0 || fcount > $fcount\) return 0;"
    lappend lines "if \(fcount == 0\) \{"
    lappend lines "    *obj = 0;"
    lappend lines "    return 1;"
    lappend lines "\}"
    #item 2684
    lappend lines "if \(!Int_Read\(stream, &count\)\) return 0;"
    lappend lines "if \(count < 0\) return 0;"
    #item 2685
    lappend lines "table = ${name}_Create\(\);"
    lappend lines "for \(i = 0; i < count; i++\) \{"
    lappend lines "    if \(!${item}_LoadItem\(table, stream, fcount\)\) \{"
    lappend lines "        ${name}_Destroy\(table\);"
    lappend lines "        return 0;"
    lappend lines "    \}"
    lappend lines "\}"
    #item 2675
    lappend lines "*obj = table;"
    lappend lines "return 1;"
    #item 2671
    return [ smethod $signature {} $lines ]
}

proc create_save { name item fields indices } {
    #item 2381
    set dname "${name}_Save"
    #item 2380
    set returns [ list "int" "Returns non-zero on success." ]
    #item 2378
    set obj [ sfield "const $name*" "obj" "" ]
    set str [ sfield "WriteStream*" "stream" "" ]
    set args [ list $obj $str ]
    #item 2379
    set comment "Saves $name to the binary stream."
    #item 2377
    set signature [ ssignature $dname $returns $args $comment ]
    #item 2394
    set first [ lindex $indices 0 ]
    set iname [ get_value $first name ]
    #item 2397
    set lines {}
    lappend lines "int count, interrupted;"
    lappend lines "if \(!obj\) \{"
    lappend lines "    return Short_Write\(stream, 0\);"
    lappend lines "\}"
    #item 2424
    set fcount [ count_serializable $fields ]
    #item 2426
    if {$fcount == 0} {
        #item 2428
        error "$name does not have serialisable fields"
    } else {
        
    }
    #item 2425
    lappend lines \
     "if \(!Short_Write\(stream, $fcount\)\) return 0;"
    #item 2422
    lappend lines "count = Hashtable_Count\(obj->$iname\);"
    lappend lines \
     "if \(!Int_Write\(stream, count\)\) return 0;"
    #item 2393
    lappend lines "interrupted = "
    
    lappend lines \
     "Hashtable_Foreach\(obj->$iname, \(VisitorFun\)${item}_SaveItem, stream\);"
    #item 2430
    lappend lines "if \(interrupted\) return 0;"
    #item 2423
    lappend lines "return 1;"
    #item 2395
    return [ smethod $signature {} $lines ]
}

proc create_table_fields { indices } {
    #item 1298
    set result {}
    #item 1307
    lappend result [ sfield "Object" "Super" "" ]
    #item 1306
    set comment "The number of records in the table."
    foreach index $indices {
        #item 1301
        set name [ get_value $index name ]
        #item 1302
        set comment "The $name index"
        #item 1300
        lappend result [ sfield "Hashtable*" $name $comment ]
    }
    #item 1299
    return $result
}

proc ctr_arg { fname fields } {
    #item 1843
    set field [ get_value $fields $fname ]
    #item 1844
    set type [ get_value $field type ]
    set class [ get_value $field class ]
    #item 1853
    set comment ""
    #item 1846
    if {$type == "own"} {
        #item 1896
        append comment "Ownership. "
        #item 1849
        set class "$class*"
    } else {
        
    }
    #item 1850
    if {[ str_contains $class "*" ]} {
        #item 1854
        append comment "Can be null."
    } else {
        
    }
    #item 1845
    return [ sfield $class $fname $comment ]
}

proc ctr_field { fname fields } {
    #item 1825
    set field [ get_value $fields $fname ]
    #item 1826
    set generate [ get_value $field generate ]
    #item 1827
    return [ contains $generate ctr ]
}

proc delete_item { item fields dtr } {
    #item 1768
    set fnames [ get_keys $fields ]
    #item 1775
    set own_names [ lfilter_user \
     $fnames st::is_own $fields ]
    #item 1773
    set dname "${item}_DeleteItem"
    #item 1772
    set returns { "int" "" }
    #item 1770
    set obj [ sfield "$item*" "obj" "" ]
    set ign [ sfield "void*" "ignored" "" ]
    #item 1771
    set comment "Deletes $item."
    #item 1769
    set signature [ ssignature $dname $returns [ list $obj $ign ] $comment ]
    #item 1776
    set lines {}
    #item 1786
    if {$dtr} {
        #item 1789
        lappend lines "${item}_Destructor\(obj\);"
    } else {
        
    }
    #item 1777
    add_range lines [ lmap_user $own_names st::field_dtr $fields ]
    #item 1785
    lappend lines "Allocator_Free\(obj\);"
    #item 2290
    lappend lines "return 0;"
    #item 1790
    return [ smethod $signature {static} $lines ]
}

proc delete_me { } {
    #item 1325
    return "Allocator_Free\(obj\);"
}

proc diff_arrays { left right } {
    #item 252
    set left_unmatched {}
    set right_unmatched {}
    foreach item $left {
        #item 248
        if {[ contains $right $item ]} {
            
        } else {
            #item 251
            lappend left_unmatched $item
        }
    }
    foreach item $right {
        #item 255
        if {[ contains $left $item ]} {
            
        } else {
            #item 258
            lappend right_unmatched $item
        }
    }
    #item 261
    if {($left_unmatched == {}) && ($right_unmatched == {})} {
        #item 259
        set equal 1
    } else {
        #item 260
        set equal 0
    }
    #item 265
    return [ list $equal \
     $left_unmatched     \
     $right_unmatched ]
}

proc dtr_null_check { } {
    #item 1320
    return { "if \(!obj\) return;" }
}

proc extract_arguments { text name } {
    #item 3281
    set length [ string length $text ]
    set last [ expr { $length - 1 } ]
    #item 3285
    if {$length == 0} {
        #item 3288
        set msg "$name: empty message signature"
        #item 3307
        error $msg
    } else {
        #item 3301
        set fname ""
        #item 33190001
        set i 0
        while { 1 } {
            #item 33190002
            if {$i < $length} {
                
            } else {
                #item 3311
                set msg "$name: expected \( in signature: $text"
                #item 3307
                error $msg
                break
            }
            #item 3321
            set c [ string index $text $i ]
            #item 3299
            if {$c == "\)"} {
                #item 3310
                set msg "$name: unexpected \) in signature: $text"
                #item 3307
                error $msg
                break
            } else {
                
            }
            #item 3322
            if {$c == "\("} {
                #item 3323
                if {$i == 0} {
                    #item 3324
                    set msg "$name: unexpected \( in signature: $text"
                    #item 3307
                    error $msg
                } else {
                    #item 3333
                    set args ""
                    #item 33290001
                    incr i
                    while { 1 } {
                        #item 33290002
                        if {$i < $length} {
                            
                        } else {
                            #item 3348
                            set msg "$name: expected \) in signature: $text"
                            #item 3307
                            error $msg
                            break
                        }
                        #item 3331
                        set c [ string index $text $i ]
                        #item 3334
                        if {$c == "\("} {
                            #item 3335
                            set msg "$name: unexpected \( in signature: $text"
                            #item 3307
                            error $msg
                            break
                        } else {
                            
                        }
                        #item 3332
                        if {$c == "\)"} {
                            #item 3341
                            if {$i == $last} {
                                
                            } else {
                                #item 3345
                                set msg "$name: symbols after \) in signature: $text"
                                #item 3307
                                error $msg
                            }
                            break
                        } else {
                            
                        }
                        #item 3338
                        append args $c
                        #item 33290003
                        incr i
                    }
                }
                break
            } else {
                
            }
            #item 3302
            append fname $c
            #item 33190003
            incr i
        }
    }
    #item 3350
    return [ list $fname $args ]
}

proc extract_tables { filename } {
    #item 6
    set content [ read_all_text $filename ]
    #item 7
    set raw_lines [ split $content "\n" ]
    #item 8
    set trimmed [ lmap $raw_lines st::trim_line ]
    lappend trimmed ""
    #item 24
    set i 0
    set count [ llength $trimmed ]
    #item 35
    set state idle
    #item 46
    set table {}
    set result {}
    while { 1 } {
        #item 26
        if {$i == $count} {
            break
        } else {
            
        }
        #item 25
        set line [ lindex $trimmed $i ]
        incr i
        #item 575
        set line [ remove_formatting $line ]
        #item 290001
        if {$state == "idle"} {
            #item 38
            if {[ is_table_row $line ]} {
                #item 39
                set row [ make_row $line ]
                lappend table $row
                #item 40
                set state table
            } else {
                
            }
        } else {
            #item 290002
            if {$state == "table"} {
                
            } else {
                #item 290003
                error "Unexpected switch value: $state"
            }
            #item 43
            if {[ is_table_row $line ]} {
                #item 44
                set row [ make_row $line ]
                lappend table $row
            } else {
                #item 47
                lappend result $table
                set table {}
                #item 45
                set state idle
            }
        }
    }
    #item 48
    return $result
}

proc field_accessors { fname item fields } {
    #item 2065
    set field [ get_value $fields $fname ]
    #item 2066
    set type [ get_value $field type ]
    set class [ get_value $field class ]
    set generate [ get_value $field generate ]
    set indexed [ get_opt_value $field indexed "no" ]
    #item 2067
    set result {}
    #item 2069
    if {[ contains $generate getter ]} {
        #item 22560001
        if {$type == "value"} {
            #item 2076
            set class2 $class
            #item 2074
            lappend result [ field_getter $item $fname $class2 ]
        } else {
            #item 22560002
            if {$type == "own"} {
                #item 2077
                set class2 "const $class*"
                #item 2074
                lappend result [ field_getter $item $fname $class2 ]
            } else {
                #item 22560003
                if {$type == "inline"} {
                    #item 2263
                    lappend result [ field_getter_inl $item $fname $class ]
                } else {
                    #item 3658
                    error "Unexpected field type $type for field $fname"
                }
            }
        }
    } else {
        
    }
    #item 2985
    if {[ contains $generate wgetter ]} {
        #item 2986
        if {$type == "own"} {
            #item 3020
            if {$indexed == "yes"} {
                #item 3023
                set msg    "$fname field of $item: "
                append msg "wgetters are not allowed for "
                append msg "indexed fields"
                #item 2277
                error $msg
            } else {
                #item 2991
                lappend result [ field_wgetter $item $fname $class ]
                #item 2098
                if {[ contains $generate setter ]} {
                    #item 2266
                    if {$type == "inline"} {
                        #item 2267
                        set msg    "$fname field of $item: "
                        append msg "setters are not allowed for "
                        append msg "inline fields"
                        #item 2277
                        error $msg
                    } else {
                        #item 2268
                        if {$indexed == "yes"} {
                            #item 2271
                            set msg    "$fname field of $item: "
                            append msg "setters are not allowed for "
                            append msg "indexed fields"
                            #item 2277
                            error $msg
                        } else {
                            #item 2273
                            if {$type == "own"} {
                                #item 2276
                                lappend result \
                                 [ field_setter_own $item $fname $class ]
                            } else {
                                #item 2272
                                lappend result \
                                 [ field_setter $item $fname $class ]
                            }
                            #item 2279
                            if {[ contains $generate taker ]} {
                                #item 2278
                                if {$type == "own"} {
                                    #item 2280
                                    if {$indexed == "yes"} {
                                        #item 2283
                                        set msg    "$fname field of $item: "
                                        append msg "takers are not allowed for "
                                        append msg "indexed fields"
                                        #item 2277
                                        error $msg
                                    } else {
                                        #item 2289
                                        lappend result \
                                         [ field_taker $item $fname $class ]
                                    }
                                } else {
                                    #item 2284
                                    set msg    "$fname field of $item: "
                                    append msg "takers are allowed only for "
                                    append msg "own fields"
                                    #item 2277
                                    error $msg
                                }
                            } else {
                                
                            }
                        }
                    }
                } else {
                    #item 2279
                    if {[ contains $generate taker ]} {
                        #item 2278
                        if {$type == "own"} {
                            #item 2280
                            if {$indexed == "yes"} {
                                #item 2283
                                set msg    "$fname field of $item: "
                                append msg "takers are not allowed for "
                                append msg "indexed fields"
                                #item 2277
                                error $msg
                            } else {
                                #item 2289
                                lappend result \
                                 [ field_taker $item $fname $class ]
                            }
                        } else {
                            #item 2284
                            set msg    "$fname field of $item: "
                            append msg "takers are allowed only for "
                            append msg "own fields"
                            #item 2277
                            error $msg
                        }
                    } else {
                        
                    }
                }
            }
        } else {
            #item 2989
            set msg    "$fname field of $item: "
            append msg "wgetters are only allowed for "
            append msg "own fields"
            #item 2277
            error $msg
        }
    } else {
        #item 2098
        if {[ contains $generate setter ]} {
            #item 2266
            if {$type == "inline"} {
                #item 2267
                set msg    "$fname field of $item: "
                append msg "setters are not allowed for "
                append msg "inline fields"
                #item 2277
                error $msg
            } else {
                #item 2268
                if {$indexed == "yes"} {
                    #item 2271
                    set msg    "$fname field of $item: "
                    append msg "setters are not allowed for "
                    append msg "indexed fields"
                    #item 2277
                    error $msg
                } else {
                    #item 2273
                    if {$type == "own"} {
                        #item 2276
                        lappend result \
                         [ field_setter_own $item $fname $class ]
                    } else {
                        #item 2272
                        lappend result \
                         [ field_setter $item $fname $class ]
                    }
                    #item 2279
                    if {[ contains $generate taker ]} {
                        #item 2278
                        if {$type == "own"} {
                            #item 2280
                            if {$indexed == "yes"} {
                                #item 2283
                                set msg    "$fname field of $item: "
                                append msg "takers are not allowed for "
                                append msg "indexed fields"
                                #item 2277
                                error $msg
                            } else {
                                #item 2289
                                lappend result \
                                 [ field_taker $item $fname $class ]
                            }
                        } else {
                            #item 2284
                            set msg    "$fname field of $item: "
                            append msg "takers are allowed only for "
                            append msg "own fields"
                            #item 2277
                            error $msg
                        }
                    } else {
                        
                    }
                }
            }
        } else {
            #item 2279
            if {[ contains $generate taker ]} {
                #item 2278
                if {$type == "own"} {
                    #item 2280
                    if {$indexed == "yes"} {
                        #item 2283
                        set msg    "$fname field of $item: "
                        append msg "takers are not allowed for "
                        append msg "indexed fields"
                        #item 2277
                        error $msg
                    } else {
                        #item 2289
                        lappend result \
                         [ field_taker $item $fname $class ]
                    }
                } else {
                    #item 2284
                    set msg    "$fname field of $item: "
                    append msg "takers are allowed only for "
                    append msg "own fields"
                    #item 2277
                    error $msg
                }
            } else {
                
            }
        }
    }
    #item 2087
    return $result
}

proc field_clone { fname fields } {
    #item 2368
    set field [ get_value $fields $fname ]
    set class [ get_value $field class ]
    #item 2369
    return "if \(obj->$fname\) newItem->$fname = ${class}_Clone\(obj->$fname\);"
}

proc field_ctr { fname fields self_name } {
    #item 3672
    set field [ get_value $fields $fname ]
    set class [ get_value $field class ]
    #item 3673
    return "$self_name->$fname = ${class}_Create\(\);"
}

proc field_dtr { fname fields } {
    #item 1783
    set field [ get_value $fields $fname ]
    set class [ get_value $field class ]
    #item 1784
    return "${class}_Destroy\(obj->$fname\);"
}

proc field_eq { fname udata } {
    #item 1662
    lassign $udata item fields indices
    #item 1664
    set field [ get_value $fields $fname ]
    #item 1663
    set type [ get_value $field type ]
    set class [ get_value $field class ]
    #item 1677
    if {$type == "own"} {
        #item 1679
        return "${class}_Equal\(left->$fname, right->$fname\)"
    } else {
        #item 1665
        if {([ is_integral $class ]) || ([ is_pointer $class ])} {
            #item 1668
            return "\(left->$fname == right->$fname\)"
        } else {
            #item 1673
            return "\(memcmp\(&left->$fname, &right->$fname, sizeof\($class\)\) == 0\)"
        }
    }
}

proc field_getter { item field_name class } {
    #item 2135
    set dname "${item}_Get${field_name}"
    #item 2138
    if {[ str_contains $class "*" ]} {
        #item 2141
        set rcomment "Can be null."
    } else {
        #item 2137
        set rcomment ""
    }
    #item 2134
    set returns [ list $class $rcomment ]
    #item 2132
    set obj [ sfield "const $item*" "obj" "" ]
    #item 2133
    set comment "Gets the $field_name property of $item."
    #item 2131
    set signature [ ssignature $dname $returns [ list $obj ] $comment ]
    #item 2127
    set lines {}
    lappend lines "assert\(obj\);"
    #item 2142
    lappend lines "return obj->$field_name;"
    #item 2136
    return [ smethod $signature {} $lines ]
}

proc field_getter_inl { item field_name class } {
    #item 2190
    set dname "${item}_Get${field_name}"
    #item 2192
    set rcomment ""
    #item 2189
    set returns [ list "$class*" $rcomment ]
    #item 2187
    set obj [ sfield "$item*" "obj" "" ]
    #item 2188
    set comment "Gets the address of the $field_name property of $item."
    #item 2186
    set signature [ ssignature $dname $returns [ list $obj ] $comment ]
    #item 2185
    set lines {}
    lappend lines "assert\(obj\);"
    #item 2197
    lappend lines "return &obj->$field_name;"
    #item 2191
    return [ smethod $signature {} $lines ]
}

proc field_hash { fname udata } {
    #item 1644
    lassign $udata item fields indices
    #item 1647
    set field [ get_value $fields $fname ]
    #item 1646
    set type [ get_value $field type ]
    set class [ get_value $field class ]
    #item 1674
    if {$type == "own"} {
        #item 1676
        return "${class}_Hash\(obj->$fname\)"
    } else {
        #item 1648
        if {[ is_integral $class ]} {
            #item 1651
            return "\(unsigned int\)obj->$fname"
        } else {
            #item 1652
            if {[ is_pointer $class ]} {
                #item 1655
                return "\(*\(unsigned int*\)&obj->$fname\)"
            } else {
                #item 1656
                return "qhashmurmur3_32\(&obj->$fname, sizeof\($class\)\)"
            }
        }
    }
}

proc field_load { fname fields ordinal } {
    #item 2474
    set field [ get_value $fields $fname ]
    set class [ get_value $field class ]
    set type [ get_value $field type ]
    #item 2569
    if {$type == "inline"} {
        #item 2572
        set fun "${class}_Load\(&item->$fname, stream\)"
    } else {
        #item 2563
        lassign [ class_category $class ] pre ttype
        #item 2564
        if {$ttype == ""} {
            #item 2568
            set fun "${pre}_Load\(&item->$fname\, stream)"
        } else {
            #item 2567
            set fun "${pre}_Read\(stream, &item->$fname\)"
        }
    }
    #item 2475
    set load "if \(!$fun\) goto delete_item;"
    #item 2630
    if {$ordinal == 0} {
        #item 2629
        return [ list $load ]
    } else {
        #item 2633
        incr ordinal
        #item 2634
        set result {}
        #item 2636
        lappend result "if \(fcount >= $ordinal\) \{"
        lappend result "    $load"
        lappend result "\}"
        #item 2635
        return $result
    }
}

proc field_save { fname user_data } {
    #item 3136
    lassign $user_data fields error_code
    #item 2650
    set field [ get_value $fields $fname ]
    set class [ get_value $field class ]
    set type [ get_value $field type ]
    #item 2625
    if {$type == "inline"} {
        #item 2628
        set fun "${class}_Save\(&item->$fname, stream\)"
    } else {
        #item 2619
        lassign [ class_category $class ] pre ttype
        #item 2620
        if {$ttype == ""} {
            #item 2624
            set fun "${pre}_Save\(item->$fname, stream\)"
        } else {
            #item 2623
            set fun "${pre}_Write\(stream, item->$fname\)"
        }
    }
    #item 2618
    return "if \(!$fun\) return $error_code;"
}

proc field_setter { item field_name class } {
    #item 2162
    set dname "${item}_Set${field_name}"
    #item 2165
    if {[ str_contains $class "*" ]} {
        #item 2168
        set rcomment "Can be null."
    } else {
        #item 2164
        set rcomment ""
    }
    #item 2161
    set returns { void "" }
    #item 2159
    set obj [ sfield "$item*" "obj" "" ]
    set value [ sfield $class "value" $rcomment ]
    #item 2170
    set args [ list $obj $value ]
    #item 2160
    set comment "Sets the $field_name property of $item."
    #item 2158
    set signature [ ssignature $dname $returns $args $comment ]
    #item 2157
    set lines {}
    lappend lines "assert\(obj\);"
    #item 2169
    lappend lines "obj->$field_name = value;"
    #item 2163
    return [ smethod $signature {} $lines ]
}

proc field_setter_own { item field_name class } {
    #item 2217
    set dname "${item}_Set${field_name}"
    #item 2223
    set rcomment "Can be null. Takes ownership."
    #item 2216
    set returns { void "" }
    #item 2214
    set obj [ sfield "$item*" "obj" "" ]
    set value [ sfield "$class*" "value" $rcomment ]
    #item 2225
    set args [ list $obj $value ]
    #item 2215
    set comment "Replaces the $field_name property of $item."
    #item 2213
    set signature [ ssignature $dname $returns $args $comment ]
    #item 2212
    set lines {}
    lappend lines "assert\(obj\);"
    #item 2224
    lappend lines "if \(obj->$field_name != value\) \{"
    #item 2226
    lappend lines "    ${class}_Destroy\(obj->$field_name\);"
    #item 2228
    lappend lines "    obj->$field_name = value;"
    #item 2227
    lappend lines "\}"
    #item 2218
    return [ smethod $signature {} $lines ]
}

proc field_taker { item field_name class } {
    #item 2248
    set dname "${item}_Take${field_name}"
    #item 2254
    set rcomment "Can be null. Returns ownership."
    #item 2247
    set returns [ list "$class*" $rcomment ]
    #item 2245
    set obj [ sfield "$item*" "obj" "" ]
    #item 2246
    set comment "Removes ownership for the $field_name property of $item."
    #item 2244
    set signature [ ssignature $dname $returns [ list $obj ] $comment ]
    #item 2243
    set lines {}
    lappend lines "$class* old;"
    lappend lines "assert\(obj\);"
    #item 2255
    lappend lines "old = obj->$field_name;"
    lappend lines "obj->$field_name = 0;"
    lappend lines "return old;"
    #item 2249
    return [ smethod $signature {} $lines ]
}

proc field_wgetter { item field_name class } {
    #item 3012
    set dname "${item}_${field_name}"
    #item 3018
    set rcomment "Can be null."
    #item 3011
    set returns [ list "$class*" $rcomment ]
    #item 3009
    set obj [ sfield "$item*" "obj" "" ]
    #item 3010
    set comment "Gets the $field_name property of $item."
    #item 3008
    set signature [ ssignature $dname $returns [ list $obj ] $comment ]
    #item 3007
    set lines {}
    lappend lines "assert\(obj\);"
    #item 3019
    lappend lines "return obj->$field_name;"
    #item 3013
    return [ smethod $signature {} $lines ]
}

proc find_arg { fname fields } {
    #item 2036
    set field [ get_value $fields $fname ]
    #item 2037
    set type [ get_value $field type ]
    set class [ get_value $field class ]
    #item 2046
    set comment ""
    #item 2039
    if {$type == "own"} {
        #item 2042
        set class "const $class*"
    } else {
        
    }
    #item 2038
    return [ sfield $class $fname $comment ]
}

proc generate_class { obj print_fun } {
    #item 2781
    set class [ make_class_for_class $obj ]
    #item 2777
    set lines {}
    #item 2778
    $print_fun $class lines
    #item 2779
    set result [ join $lines "\n" ]
    #item 2780
    return $result
}

proc generate_classes { twiki_folder } {
    #item 307
    set all_objects [ read_model_pages $twiki_folder ]
    #item 318
    set obj_infos [ lfilter $all_objects st::not_empty ]
    #item 319
    lassign [ lpartition $obj_infos st::is_public ] \
     publics privates
    #item 782
    set pub_forwards [ lmap $publics st::make_forward ]
    set pri_forwards [ lmap $privates st::make_forward ]
    #item 337
    set pub_declares [ lmap $publics st::make_declare ]
    set pri_declares [ lmap $privates st::make_declare ]
    #item 338
    set impls [ lmap $obj_infos st::make_impl ]
    #item 784
    set h_file_items [ concat \
      $pub_forwards \
      $pub_declares ]
    set c_file_items [ concat \
      $pri_forwards \
      $pri_declares $impls ]
    #item 340
    set h_file [ join $h_file_items "\n" ]
    set c_file [ join $c_file_items "\n" ]
    #item 341
    return [ list $h_file $c_file ]
}

proc generate_table { obj print_fun } {
    #item 1143
    set classes [ make_classes_for_table $obj ]
    #item 1139
    set lines {}
    foreach class $classes {
        #item 1140
        $print_fun $class lines
    }
    #item 1141
    set result [ join $lines "\n" ]
    #item 1142
    return $result
}

proc get_name { obj } {
    #item 398
    return [ get_value $obj "name" ]
}

proc get_prop { obj key } {
    #item 420
    set props [ get_value $obj "props" ]
    #item 386
    set index [ find_key $props $key ]
    #item 387
    if {$index == -1} {
        #item 390
        set name [ get_name $obj ]
        #item 391
        error "Property '$key' not found in $name"
    } else {
        #item 422
        incr index
        #item 392
        return [ lindex $props $index ]
    }
}

proc get_table_header { table } {
    #item 283
    
    set first_line [ lindex $table 0 ]
    set first_cell [ lindex $first_line 0 ]
    #item 284
    return $first_cell
}

proc in_ctr { field_name fields } {
    #item 623
    set field [ get_value $fields $field_name ]
    #item 624
    set generate [ get_value $field "generate" ]
    #item 628
    return [ str_contains $generate "ctr" ]
}

proc indexed_field { fname fields } {
    #item 1834
    set field [ get_value $fields $fname ]
    #item 1835
    set indexed [ get_opt_value $field indexed "no" ]
    #item 1836
    return [ expr { $indexed == "yes" } ]
}

proc inl_make_Impl { } {
    
}

proc inl_make_forward { struct } {
    #item 3603
    set name [ get_value $struct name ]
    #item 3604
    set result "\ntypedef struct $name $name;\n"
    append result "typedef struct ${name}_State ${name}_State;\n"
    #item 3605
    return $result
}

proc is_empty { line } {
    #item 62
    if {$line == ""} {
        #item 60
        return 1
    } else {
        #item 61
        return 0
    }
}

proc is_integral { class } {
    #item 2482
    set known_integrals {
      char uchar "unsigned char"
      short ushort "unsigned short"
      int uint "unsigned int"
      int8 int16 int32 int64
      uint8 uint16 uint32 uint64
      "long long" "unsigned long long"
      byte ubyte
     int8_t
     int16_t
     int32_t
     uint8_t
     uint16_t
     uint32_t
     int64_t
     uint64_t
    }
    #item 1629
    return [ expr { [ contains $known_integrals $class ] } ]
}

proc is_own { field_name fields } {
    #item 898
    set field [ get_value $fields $field_name ]
    #item 899
    set type [ get_value $field "type" ]
    #item 900
    return [ expr { $type == "own" } ]
}

proc is_pointer { class } {
    #item 1635
    set last [ string index $class end ]
    #item 1636
    return [ expr { $last == "*" } ]
}

proc is_public { obj } {
    #item 325
    set props [ get_value $obj "props" ]
    set access [ get_opt_value $props "access" "private" ]
    #item 1212
    return [ expr { $access == "public" } ]
}

proc is_table_row { line } {
    #item 70
    return [ string match "|*" $line ]
}

proc load_item { name item fields indices } {
    #item 2587
    set fnames [ get_keys $fields ]
    #item 2607
    set ser_fields [ select_ser_fields $fields ]
    #item 2592
    set dname "${item}_LoadItem"
    #item 2591
    set returns { "int" "" }
    #item 2589
    set tab [ sfield "$name*" "table" "" ]
    set str [ sfield "ReadStream*" "stream" "" ]
    set fcn [ sfield "int" "fcount" "" ]
    set args [ list $tab $str $fcn ]
    #item 2590
    set comment "Loads $item."
    #item 2588
    set signature [ ssignature $dname $returns $args $comment ]
    #item 2594
    set lines {}
    lappend lines "$item* item;"
    #item 2600
    lappend lines \
     "item = Allocator_Allocate\(sizeof\($item\), 1\);"
    #item 2602
    lappend lines \
     "item->_parent_ = table;"
    #item 26080001
    set i 0
    while { 1 } {
        #item 26080002
        if {$i < [ llength $ser_fields ]} {
            
        } else {
            break
        }
        #item 2610
        set fname [ lindex $ser_fields $i ]
        #item 2611
        add_range lines [ field_load $fname $fields $i ]
        #item 26080003
        incr i
    }
    foreach index $indices {
        #item 2605
        set iname [ get_value $index name ]
        #item 2606
        lappend lines \
         "if \(!Hashtable_Put\(table->$iname, item\)\) goto full_undo;"
    }
    #item 2637
    lappend lines "return 1;"
    lappend lines "full_undo:"
    foreach index $indices {
        #item 2640
        set iname [ get_value $index name ]
        #item 2641
        lappend lines \
         "Hashtable_Remove\(table->$iname, item\);"
    }
    #item 2642
    lappend lines "delete_item:"
    foreach fname $ser_fields {
        #item 2645
        set field [ get_value $fields $fname ]
        set type [ get_value $field type ]
        set class [ get_value $field class ]
        #item 2646
        if {$type == "own"} {
            #item 2649
            lappend lines "${class}_Destroy\(item->$fname\);"
        } else {
            
        }
    }
    #item 2597
    lappend lines "Allocator_Free\(item\);"
    lappend lines "return 0;"
    #item 2596
    return [ smethod $signature {static} $lines ]
}

proc make_arg { field_name user } {
    #item 649
    unpack $user fields snippets name
    #item 635
    set field [ get_value $fields $field_name ]
    #item 636
    set type [ get_value $field "type" ]
    #item 658
    set class [ get_value $field "class" ]
    #item 653
    set lower [ string tolower $field_name ]
    set arg "${lower}_"
    #item 6420001
    if {$type == "value"} {
        #item 654
        if {[ str_contains $class "*" ]} {
            #item 657
            set block [ snip $snippets PTR_ARG \
             ITEM $class ARG $arg ]
        } else {
            #item 652
            set block [ snip $snippets VALUE_ARG \
             ITEM $class ARG $arg ]
        }
    } else {
        #item 6420002
        if {$type == "own"} {
            #item 659
            set block [ snip $snippets OWN_ARG \
             ITEM $class ARG $arg ]
        } else {
            #item 651
            error "$name: field $field_name has type $type and cannot be in constructor"
        }
    }
    #item 660
    return $block
}

proc make_array { obj place } {
    #item 413
    set name [ get_name $obj ]
    #item 415
    set type [ get_prop $obj "type" ]
    set item [ get_prop $obj "item" ]
    #item 416
    set filename "array.$place"
    #item 414
    set template [ read_template $filename $type ]
    #item 423
    if {$type == "own"} {
        #item 426
        set map [ list \
        	"ITEM " "$item* " \
        	"ITEM_" "${item}_"  \
        	"ITEM"  "${item}*" \
        	"NAME" $name ]
    } else {
        #item 417
        set map [ list \
        	"ITEM" $item \
        	"NAME" $name ]
    }
    #item 418
    set result [ string map $map $template ]
    #item 2978
    set props [ get_value $obj "props" ]
    set clone [ get_opt_value $props clone no ]
    set ser   [ get_opt_value $props serialize no ]
    #item 2974
    if {$clone == "yes"} {
        #item 2980
        set filename "array.clone.$place"
        #item 2979
        set template [ read_template $filename $type ]
        #item 2981
        append result [ string map $map $template ]
    } else {
        
    }
    #item 3024
    if {$ser == "yes"} {
        #item 3029
        append result [ make_array_load $name $item $type $place ]
        #item 3101
        append result [ make_array_save $name $item $type $place ]
    } else {
        
    }
    #item 2977
    return $result
}

proc make_array_load { name item type place } {
    #item 3080
    set r {}
    #item 3081
    lappend r ""
    lappend r "int // Returns non-zero on success."
    lappend r "${name}_Load\("
    lappend r "    $name** dst,"
    lappend r "    ReadStream* stream"
    #item 3083
    if {$place == "decl"} {
        #item 3085
        lappend r "\);"
    } else {
        #item 3087
        lappend r "\) \{"
        #item 3097
        if {$type == "inline"} {
            #item 3100
            set fun "${item}_Load\(&obj->Items\[i\], stream\)"
        } else {
            #item 3091
            lassign [ class_category $item ] pre ttype
            #item 3092
            if {$ttype == ""} {
                #item 3096
                set fun "${pre}_Load\(&obj->Items\[i\], stream)"
            } else {
                #item 3095
                set fun "${pre}_Read\(stream, &obj->Items\[i\]\)"
            }
        }
        #item 3089
        lappend r "    $name* obj;"
        lappend r "    int i;"
        lappend r "    char present;"
        lappend r "    int count;"
        lappend r "    if \(!Char_Read\(stream, &present\)\) return 0;"
        lappend r "    if \(present == 0\) \{"
        lappend r "        *dst = 0;"
        lappend r "        return 1;"
        lappend r "    \}"
        lappend r "    if \(!Int_Read\(stream, &count\)\) return 0;"
        lappend r "    if \(count < 0 || count > 200000\) return 0;"
        lappend r "    obj = ${name}_Create\(\);"
        lappend r "    ${name}_Resize\(obj, count\);"
        lappend r "    for \(i = 0; i < count; i++\) \{"
        lappend r "        if \(!$fun\) \{"
        lappend r "            ${name}_Destroy\(obj\);"
        lappend r "            return 0;"
        lappend r "        \}"
        lappend r "    \}"
        lappend r "    *dst = obj;"
        lappend r "    return 1;"
        lappend r "\}"
    }
    #item 3082
    return [ join $r "\n" ]
}

proc make_array_save { name item type place } {
    #item 3044
    set r {}
    #item 3045
    lappend r ""
    lappend r "int // Returns non-zero on success."
    lappend r "${name}_Save\("
    lappend r "    const $name* obj,"
    lappend r "    WriteStream* stream"
    #item 3047
    if {$place == "decl"} {
        #item 3049
        lappend r "\);"
    } else {
        #item 3051
        lappend r "\) \{"
        #item 3053
        lappend r "    int i;"
        lappend r "    if \(!obj\) \{"
        lappend r "        return Char_Write\(stream, 0\);"
        lappend r "    \}"
        lappend r "    if \(!Char_Write\(stream, 1\)\) return 0;"
        lappend r "    if \(!Int_Write\(stream, obj->Size\)) return 0;"
        #item 3054
        lappend r "    for \(i = 0; i < obj->Size; i++\) \{"
        #item 3061
        if {$type == "inline"} {
            #item 3064
            set fun "${item}_Save\(&obj->Items\[i\], stream\)"
        } else {
            #item 3055
            lassign [ class_category $item ] pre ttype
            #item 3056
            if {$ttype == ""} {
                #item 3060
                set fun "${pre}_Save\(obj->Items\[i\], stream)"
            } else {
                #item 3059
                set fun "${pre}_Write\(stream, obj->Items\[i\]\)"
            }
        }
        #item 3065
        lappend r "        if \(!$fun\) return 0;"
        lappend r "    \}"
        lappend r "    return 1;"
        lappend r "\}"
    }
    #item 3046
    return [ join $r "\n" ]
}

proc make_assign { field_name user } {
    #item 873
    unpack $user fields snippets name
    #item 864
    set field [ get_value $fields $field_name ]
    #item 882
    set class [ get_value $field "class" ]
    #item 877
    set lower [ string tolower $field_name ]
    set arg "${lower}_"
    #item 876
    return [ snip $snippets FIELD_ASSIGN \
     PROP $field_name ARG $arg ]
}

proc make_class_class { name props fields smachine } {
    #item 2823
    set gen_clone     [ get_opt_value $props clone     no ]
    set gen_serialize [ get_opt_value $props serialize no ]
    #item 2815
    set has_dtr [ get_opt_value $props destructor no ]
    #item 2806
    set fnames [ get_keys $fields ]
    #item 2796
    set methods {}
    #item 2807
    set sfields {}
    #item 2851
    lappend sfields [ sfield "Object" "Super" "" ]
    #item 3484
    if {$smachine == {}} {
        
    } else {
        #item 3487
        lappend sfields [ sfield "${name}_funs*" "State" \
         "The pointer to the current state." ]
    }
    #item 2938
    set field_values [ add_index_info $fnames $fields {} $name ]
    #item 2939
    set fields [ make_fields_map $name $field_values ]
    #item 2801
    add_range sfields [ lmap_user $fnames st::record_field $fields ]
    foreach fname $fnames {
        #item 2822
        add_range methods [ field_accessors $fname $name $fields ]
    }
    #item 3376
    set ptypedefs {}
    set code {}
    #item 3373
    if {$smachine == ""} {
        
    } else {
        #item 3378
        set messages [ get_value $smachine messages ]
        set defaults [ get_value $smachine defaults ]
        #item 3379
        set ptypedefs [ lmap_user $messages st::make_sm_typedef $name ]
        #item 3402
        set code [ make_code_for_sm $smachine $name ]
        #item 3456
        add_range methods [ lmap_user $defaults st::make_default $name ]
        #item 3531
        add_range methods [ lmap_user $messages st::make_mwrapper $name ]
    }
    #item 2852
    lappend methods [ class_create $name $fields $smachine ]
    #item 2816
    set dtr [ expr { $has_dtr == "yes" } ]
    #item 2808
    lappend methods [ class_destroy $name $fields $dtr ]
    #item 3621
    lappend methods [ class_cast $name ]
    #item 2824
    if {$gen_serialize == "yes"} {
        #item 2827
        lappend methods [ class_save $name $fields $smachine ]
        #item 2853
        lappend methods [ class_load $name $fields $smachine ]
    } else {
        
    }
    #item 2854
    if {$gen_clone} {
        #item 2857
        lappend methods [ class_clone $name $fields ]
    } else {
        
    }
    #item 2804
    set comment "$name class."
    #item 2803
    set result [ sstruct \
     $name $sfields $methods {} 1 $comment $ptypedefs $code ]
    #item 2802
    return $result
}

proc make_class_decl { obj } {
    #item 2782
    return [ generate_class $obj st::print_class_decl ]
}

proc make_class_for_class { obj } {
    #item 2838
    set name   [ get_name $obj ]
    set props  [ get_value $obj "props" ]
    set fields [ get_value $obj "fields" ]
    #item 3377
    set smachine [ get_value $obj "state machine" ]
    #item 2850
    return [ make_class_class $name $props $fields $smachine ]
}

proc make_class_impl { obj } {
    #item 2783
    return [ generate_class $obj st::print_class_impl ]
}

proc make_classes_for_table { obj } {
    #item 1105
    set name [ get_name $obj ]
    set props         [ get_value $obj "props" ]
    set field_records [ get_value $obj "fields" ]
    set index_records [ get_value $obj "indices" ]
    #item 1106
    set field_names [ get_keys $field_records ]
    set indices [ get_values $index_records ]
    #item 1111
    set fields [ add_index_info $field_names $field_records $indices $name ]
    #item 1288
    set field_map [ make_fields_map $name $fields ]
    #item 1116
    if {$indices == {}} {
        #item 1118
        error "Table $name does not have indexes."
    } else {
        
    }
    #item 1119
    set table [ make_table_class $name $props $field_map $indices ]
    #item 1120
    set record [ make_record_class $name $props $field_map $indices ]
    #item 1121
    return [ list $record $table ]
}

proc make_code_for_sm { smachine name } {
    #item 3417
    set states [ get_value $smachine states ]
    set messages [ get_value $smachine messages ]
    set cells [ get_value $smachine cells ]
    #item 3418
    set lines {}
    #item 3419
    lappend lines ""
    lappend lines "// Virtual functions table for $name state machine."
    lappend lines "struct ${name}_funs \{"
    lappend lines "    int Id;"
    lappend lines "    const char* Name;"
    foreach message $messages {
        #item 3423
        set m [ parse_message_signature $message $name ]
        set mname [ get_value $m name ]
        #item 3424
        lappend lines "    ${name}_${mname}_fun $mname;"
    }
    #item 3422
    lappend lines "\};"
    lappend lines ""
    #item 3438
    set id 1
    foreach state $states {
        #item 3431
        lappend lines ""
        lappend lines "// $state state of $name."
        lappend lines "${name}_funs ${name}_${state}_State = \{"
        lappend lines "    $id,"
        lappend lines "    \"$state\","
        #item 3439
        incr id
        #item 3440
        set i 1
        foreach message $messages {
            #item 3448
            set m [ parse_message_signature $message $name ]
            set mname [ get_value $m name ]
            #item 3429
            set key "$state|$message"
            #item 3433
            set cell [ get_value $cells $key ]
            #item 3434
            if {$cell == ""} {
                #item 3447
                set method "${name}_${mname}_default"
            } else {
                #item 3446
                set method "${name}_$cell"
            }
            #item 3441
            if {$i == [ llength $messages ]} {
                
            } else {
                #item 3437
                append method ","
            }
            #item 3444
            incr i
            #item 3445
            lappend lines "    $method"
        }
        #item 3432
        lappend lines "\};"
        lappend lines ""
    }
    #item 3425
    return [ join $lines "\n" ]
}

proc make_declare { obj } {
    #item 347
    set type [ get_value $obj "type" ]
    #item 3480001
    if {$type == "array"} {
        #item 356
        return [ make_array $obj "decl" ]
    } else {
        #item 3480002
        if {$type == "class"} {
            #item 357
            return [ make_class_decl $obj ]
        } else {
            #item 3480003
            if {$type == "table"} {
                
            } else {
                #item 3480004
                error "Unexpected switch value: $type"
            }
            #item 358
            return [ make_table_decl $obj ]
        }
    }
}

proc make_default { message name } {
    #item 3481
    set mobj [ parse_message_signature $message $name ]
    #item 3482
    set margs [ get_value $mobj args ]
    set mname [ get_value $mobj name ]
    #item 3464
    set dname "${name}_${mname}_default"
    #item 3463
    set returns [ list "${name}_funs*" "Returns old state." ]
    #item 3461
    set obj [ sfield "$name*" "obj" "" ]
    set old [ sfield "${name}_funs*" "old_state" "" ]
    #item 3462
    set comment ""
    #item 3483
    set args [ list $obj $old ]
    add_range args $margs
    #item 3460
    set signature [ ssignature $dname $returns $args $comment ]
    #item 3476
    set lines {}
    #item 3480
    lappend lines "return old_state;"
    #item 3479
    return [ smethod $signature {} $lines ]
}

proc make_destroy { field_name user } {
    #item 889
    unpack $user fields snippets name
    #item 888
    set field [ get_value $fields $field_name ]
    #item 892
    set class [ get_value $field "class" ]
    #item 890
    return [ snip $snippets OWN_DESTROY \
     PROP $field_name ITEM $class ]
}

proc make_eq { index udata } {
    #item 1717
    lassign $udata item fields indices
    #item 1742
    set iname [ get_value $index name ]
    #item 1719
    set ifields_raw [ get_value $index fields ]
    set ifields [ make_list $ifields_raw ]
    #item 1733
    set dname "${item}_${iname}_Equal"
    #item 1732
    set returns { "int" "0 if two objects are NOT equal" }
    #item 1730
    set left [ sfield "const $item*" "left" "" ]
    set right [ sfield "const $item*" "right" "" ]
    #item 1731
    set comment "Calculates equality for $item for index $iname."
    #item 1729
    set signature [ ssignature $dname $returns [ list $left $right ] $comment ]
    #item 1725
    set lines {}
    #item 1721
    if {[ llength $ifields ] == 1} {
        #item 1720
        set field_name [ lindex $ifields 0 ]
        set single_value [ field_eq $field_name $udata ]
        #item 1724
        lappend lines "return $single_value;"
    } else {
        #item 1728
        add_range lines [ lmap_user \
         $ifields st::many_field_eq $udata ]
        #item 1727
        lappend lines "return 1;"
    }
    #item 1734
    return [ smethod $signature {static} $lines ]
}

proc make_field { field_name user } {
    #item 834
    unpack $user fields snippets name
    #item 832
    set field [ get_value $fields $field_name ]
    #item 833
    set type [ get_value $field "type" ]
    #item 835
    set class [ get_value $field "class" ]
    #item 8370001
    if {$type == "value"} {
        #item 848
        if {[ str_contains $class "*" ]} {
            #item 851
            set section PTR_FIELD
        } else {
            #item 850
            set section VALUE_FIELD
        }
    } else {
        #item 8370002
        if {$type == "own"} {
            #item 852
            set section OWN_FIELD
        } else {
            #item 8370003
            if {$type == "inline"} {
                #item 853
                set section VALUE_FIELD
            } else {
                #item 847
                error "$name: unsupported field type in field $field_name: $type"
            }
        }
    }
    #item 854
    return [ snip $snippets $section \
     ITEM $class PROP $field_name ]
}

proc make_fields_map { name fields } {
    #item 290
    set result {}
    #item 295
    set names {}
    foreach field $fields {
        #item 291
        array set fprops $field
        set fname $fprops(name)
        #item 297
        if {[ contains $names $fname ]} {
            #item 300
            error "Non-unique name '$fname' in $name"
        } else {
            #item 296
            lappend names $fname
            #item 294
            lappend result $fname $field
        }
    }
    #item 301
    return $result
}

proc make_foreach_td { item } {
    #item 1969
    set dname "${item}Visitor"
    #item 1970
    set returns { "int" "Returns non-zero to interrupt iteration." }
    #item 1971
    set item [ sfield "$item*" "item" "Current item." ]
    set user [ sfield "void*" "userData" "A pointer to user data." ]
    set args [ list $item $user ]
    #item 1972
    set comment "The procedure to apply to each item."
    #item 1968
    set signature [ ssignature $dname $returns $args $comment ]
}

proc make_forward { obj } {
    #item 1150
    set type [ get_value $obj "type" ]
    #item 1162
    set name [ get_name $obj ]
    set props [ get_value $obj "props" ]
    #item 11510001
    if {$type == "array"} {
        #item 3399
        set result ""
        #item 781
        append result "typedef struct $name $name;"
    } else {
        #item 11510002
        if {$type == "class"} {
            #item 3365
            set sm [ get_value $obj "state machine" ]
            #item 3366
            if {$sm == ""} {
                #item 3401
                set result ""
            } else {
                #item 3369
                set result "typedef struct ${name}_funs ${name}_funs;\n"
            }
            #item 781
            append result "typedef struct $name $name;"
        } else {
            #item 11510003
            if {$type == "table"} {
                
            } else {
                #item 11510004
                error "Unexpected switch value: $type"
            }
            #item 1164
            set item_index [ find_key $props "item" ]
            #item 1165
            if {$item_index == -1} {
                #item 1169
                error "No item type defined for table $name."
            } else {
                #item 1211
                incr item_index
                #item 1168
                set item [ lindex $props $item_index ]
            }
            #item 1170
            set rec "typedef struct $item $item;"
            set tab "typedef struct $name $name;"
            #item 1159
            set result "$rec\n$tab"
        }
    }
    #item 3400
    return $result
}

proc make_hash { index udata } {
    #item 1622
    lassign $udata item fields indices
    #item 1637
    set iname [ get_value $index name ]
    #item 1743
    set ifields_raw [ get_value $index fields ]
    set ifields [ make_list $ifields_raw ]
    #item 1701
    set dname "${item}_${iname}_Hash"
    #item 1700
    set returns { "unsigned int" "" }
    #item 1698
    set obj [ sfield "const $item*" "obj" "" ]
    #item 1699
    set comment "Calculates the hash code of $item for index $iname."
    #item 1697
    set signature [ ssignature $dname $returns [ list $obj ] $comment ]
    #item 1686
    set lines {}
    #item 1682
    if {[ llength $ifields ] == 1} {
        #item 1681
        set field_name [ lindex $ifields 0 ]
        set single_value [ field_hash $field_name $udata ]
        #item 1685
        lappend lines "return $single_value;"
    } else {
        #item 1687
        lappend lines "unsigned int hash = 17;"
        #item 1696
        add_range lines [ lmap_user \
         $ifields st::many_field_hash $udata ]
        #item 1688
        lappend lines "return hash;"
    }
    #item 1702
    return [ smethod $signature {static} $lines ]
}

proc make_impl { obj } {
    #item 1213
    set type [ get_value $obj "type" ]
    #item 3650001
    if {$type == "array"} {
        #item 419
        return [ make_array $obj "impl" ]
    } else {
        #item 3650002
        if {$type == "class"} {
            #item 374
            return [ make_class_impl $obj ]
        } else {
            #item 3650003
            if {$type == "table"} {
                
            } else {
                #item 3650004
                error "Unexpected switch value: $type"
            }
            #item 375
            return [ make_table_impl $obj ]
        }
    }
}

proc make_list { text } {
    #item 971
    set items [ split $text "," ]
    #item 972
    set trimmed [ lmap $items st::trim_line ]
    #item 973
    return [ lfilter $trimmed st::not_empty ]
}

proc make_mwrapper { message name } {
    #item 3554
    set mobj [ parse_message_signature $message $name ]
    #item 3555
    set margs [ get_value $mobj args ]
    set mname [ get_value $mobj name ]
    #item 3539
    set dname "${name}_${mname}"
    #item 3538
    set returns { int "Returns zero on error." }
    #item 3536
    set obj [ sfield "$name*" "obj" "" ]
    set args {}
    lappend args $obj
    add_range args $margs
    #item 3537
    set comment "$mname message handler for $name state machine."
    #item 3535
    set signature [ ssignature $dname $returns $args $comment ]
    #item 3551
    set lines {}
    #item 3556
    lappend lines "${name}_funs* old_state;"
    lappend lines "${name}_funs* new_state;"
    #item 3557
    lappend lines "assert\(obj\);"
    #item 3558
    lappend lines "old_state = obj->State;"
    lappend lines "obj->State = 0;"
    #item 3559
    set names [ lmap $margs st::get_name ]
    #item 3560
    set arg_list [ join $names ", " ]
    #item 3562
    if {$arg_list == {}} {
        #item 3565
        lappend lines "new_state = old_state->${mname}\(obj, old_state\);"
    } else {
        #item 3561
        lappend lines "new_state = old_state->${mname}\(obj, old_state, $arg_list\);"
    }
    #item 3566
    lappend lines "obj->State = new_state;"
    lappend lines "if \(!new_state\) return 0;"
    lappend lines "return 1;"
    #item 3552
    return [ smethod $signature {} $lines ]
}

proc make_record_class { name props fields indices } {
    #item 1594
    set item [ get_value $props item ]
    #item 2323
    set gen_clone     [ get_opt_value $props clone     no ]
    set gen_serialize [ get_opt_value $props serialize no ]
    #item 1276
    set methods {}
    #item 1595
    set fnames [ get_keys $fields ]
    #item 1598
    set sfields {}
    #item 1277
    lappend sfields [ sfield "$name*" "_parent_" \
     "Pointer to the collection that owns this record" ]
    #item 1590
    add_range sfields [ lmap_user $fnames st::record_field $fields ]
    foreach fname $fnames {
        #item 2059
        add_range methods [ field_accessors $fname $item $fields ]
    }
    #item 1748
    set udata [ list $item $fields $indices ]
    #item 1747
    add_range methods [ lmap_user $indices st::make_hash $udata ]
    #item 1749
    add_range methods [ lmap_user $indices st::make_eq $udata ]
    #item 1750
    set has_dtr [ get_opt_value $props destructor no ]
    #item 1791
    set dtr [ expr { $has_dtr == "yes" } ]
    #item 1605
    lappend methods [ delete_item $item $fields $dtr ]
    #item 2431
    if {$gen_serialize == "yes"} {
        #item 2434
        lappend methods [ save_item $item $fields ]
    } else {
        
    }
    #item 1593
    set comment "Record class for table $name"
    #item 1592
    set result [ sstruct \
     $item $sfields $methods {} 0 $comment {} {} ]
    #item 1591
    return $result
}

proc make_row { line } {
    #item 76
    set cells [ split $line "|" ]
    #item 77
    set trimmed [ lmap $cells st::trim_line ]
    #item 78
    return [ lrange $trimmed 1 end-1 ]
}

proc make_sm_typedef { message name } {
    #item 3385
    set msig [ parse_message_signature $message $name ] 
    set mname [ get_value $msig name ]
    set args [ get_value $msig args ]
    #item 3387
    set fun_name "${name}_${mname}_fun"
    #item 3388
    set return_value [ list "${name}_funs*" "Returns a pointer to the next state." ]
    #item 3389
    set me [ sfield "$name*" "obj" "" ]
    set old [ sfield "${name}_funs*" "old_state" "Pointer to the previous state." ]
    set arg_list [ list $me $old ]
    #item 3390
    add_range arg_list $args
    #item 3391
    set comment "Function prototype for $mname message to $name."
    #item 3392
    return [ ssignature $fun_name $return_value $arg_list $comment ]
}

proc make_table_class { name props fields indices } {
    #item 1251
    set item [ get_opt_value $props item "" ]
    #item 1278
    if {$item == ""} {
        #item 1281
        error "No 'item' property specified for table $name"
    } else {
        
    }
    #item 1252
    set gen_foreach   [ get_opt_value $props foreach   no ]
    set gen_delete    [ get_opt_value $props delete    no ]
    set gen_serialize [ get_opt_value $props serialize no ]
    set gen_clone     [ get_opt_value $props clone     no ]
    #item 1271
    set tfields [ create_table_fields $indices ]
    #item 1247
    set methods {}
    set typedefs {}
    #item 1248
    lappend methods [ create_ctr $name $item $indices ]
    #item 1249
    lappend methods [ create_dtr $name $item $indices ]
    #item 1250
    lappend methods [ create_insert $name $item $fields $indices ]
    #item 1265
    lappend methods [ create_count $name $indices ]
    #item 3651
    lappend methods [ class_cast $name ]
    #item 1254
    if {$gen_delete == "yes"} {
        #item 1253
        lappend methods [ create_delete $name $item $indices ]
    } else {
        
    }
    #item 1258
    if {$gen_foreach == "yes"} {
        #item 1257
        lappend methods [ create_foreach $name $item $indices ]
        #item 1962
        lappend typedefs [ make_foreach_td $item ]
    } else {
        
    }
    #item 1290
    if {$gen_clone == "yes"} {
        #item 2374
        lappend methods [ clone_item $name $item $fields $indices ]
        #item 1289
        lappend methods [ create_clone $name $item $fields $indices ]
    } else {
        
    }
    #item 1262
    if {$gen_serialize == "yes"} {
        #item 2573
        lappend methods [ load_item $name $item $fields $indices ]
        #item 1261
        lappend methods [ create_save $name $item $fields $indices ]
        lappend methods [ create_load $name $item $fields ]
    } else {
        
    }
    foreach index $indices {
        #item 1268
        lassign $index iname ifields_raw
        #item 2048
        set iname [ get_value $index name ]
        set ifields_raw [ get_value $index fields ]
        #item 1269
        set ifields [ make_list $ifields_raw ]
        #item 1270
        lappend methods [ create_find \
         $name $item $iname $fields $ifields ]
    }
    #item 1274
    set comment "Collection class for table $name"
    #item 1273
    set result [ sstruct \
     $name $tfields $methods $typedefs 1 $comment {} {} ]
    #item 1195
    return $result
}

proc make_table_decl { obj } {
    #item 1122
    return [ generate_table $obj st::print_class_decl ]
}

proc make_table_impl { obj } {
    #item 1146
    return [ generate_table $obj st::print_class_impl ]
}

proc many_field_eq { field_name udata } {
    #item 1740
    set value [ field_eq $field_name $udata ]
    #item 1741
    return "if \(!$value\) \{ return 0; \}"
}

proc many_field_hash { field_name udata } {
    #item 1694
    set value [ field_hash $field_name $udata ]
    #item 1695
    return "hash = hash * 31 + $value;"
}

proc method_is_public { method } {
    #item 1567
    set modifiers [ get_value $method modifiers ]
    #item 1569
    if {[ contains $modifiers static ]} {
        #item 1572
        return 0
    } else {
        #item 1568
        return 1
    }
}

proc new_obj { name } {
    #item 1560
    set result {}
    #item 1344
    lappend result \
     "$name* obj = Allocator_Allocate\(sizeof\($name\), 1\);"
    #item 1345
    lappend result \
     "obj->Super.Type = &g$name;"
    #item 1561
    return $result
}

proc not_empty { line } {
    #item 315
    if {$line == ""} {
        #item 314
        return 0
    } else {
        #item 313
        return 1
    }
}

proc parse_arg { text object } {
    #item 3356
    set trimmed [ string trim $text ]
    #item 3361
    if {[ llength $trimmed ] < 2} {
        #item 3360
        error "Error in signature argument: '$trimmed' in $object"
    } else {
        #item 3362
        set name [ lindex $trimmed end ]
        set type [ lrange $trimmed 0 end-1 ]
        #item 3363
        set type_trimmed [ string trim $type ]
        #item 3364
        return [ sfield $type_trimmed $name "" ]
    }
}

proc parse_message_signature { text name } {
    #item 3276
    lassign [ extract_arguments $text $name ] mname args
    #item 3277
    set arg_list [ split $args "," ]
    #item 3278
    set arguments [ lmap_user $arg_list st::parse_arg "$name: $text" ]
    #item 3279
    return [ list args $arguments name $mname ]
}

proc prepend { text before } {
    #item 1520
    return $before$text
}

proc print_class_decl { class lines_var } {
    #item 1438
    upvar $lines_var lines
    #item 1436
    set name    [ get_value $class name ]
    set comment [ get_value $class comment ]
    set methods [ get_value $class methods ]
    set typedefs [ get_value $class typedefs ]
    #item 1573
    set pmethods [ lfilter $methods st::method_is_public ]
    #item 1439
    lappend lines ""
    lappend lines "///////////////////////////////"
    lappend lines "// $name"
    lappend lines "// $comment"
    foreach typedef $typedefs {
        #item 2001
        typedef_decl $typedef lines
    }
    foreach method $pmethods {
        #item 1442
        smethod_decl $method lines
        #item 1506
        lappend lines "\);"
    }
}

proc print_class_impl { class lines_var } {
    #item 1508
    upvar $lines_var lines
    #item 1507
    set name      [ get_value $class name ]
    set comment   [ get_value $class comment ]
    set methods   [ get_value $class methods ]
    set dtr       [ get_value $class dtr ]
    set fields    [ get_value $class fields ]
    set ptypedefs [ get_value $class ptypedefs ]
    set code      [ get_value $class code ]
    set on_message [ get_value $class on_message ]
    #item 1509
    lappend lines ""
    lappend lines "///////////////////////////////"
    lappend lines "// $name"
    lappend lines "// $comment"
    foreach typedef $ptypedefs {
        #item 3398
        typedef_decl $typedef lines
    }
    #item 3426
    lappend lines $code
    #item 1539
    lappend lines "struct $name \{"
    foreach field $fields {
        #item 1541
        set fname [ get_value $field name ]
        set ftype [ get_value $field type ]
        set fcomm [ get_value $field comment ]
        #item 1547
        lappend lines ""
        #item 1544
        if {$fcomm == {}} {
            
        } else {
            #item 1548
            lappend lines "    // $fcomm"
        }
        #item 1549
        lappend lines "    $ftype $fname;"
    }
    #item 1540
    lappend lines "\};"
    #item 1536
    if {$dtr} {
        #item 1553
        set dtr_value "\(ObjectDestructorFun\)${name}_Destroy"
    } else {
        #item 1554
        set dtr_value 0
    }
    #item 3615
    if {$on_message} {
        #item 3619
        set msg_value "\(ObjectOnMessageFun\)${name}_OnMessage"
    } else {
        #item 3620
        set msg_value 0
    }
    #item 3618
    lappend lines \
    "TypeInfo g$name = \{ \"$name\", $dtr_value, $msg_value \};"
    #item 1577
    lassign [ lpartition $methods st::method_is_public ] \
     _ prmethods
    foreach method $prmethods {
        #item 1580
        smethod_decl $method lines
        #item 1581
        lappend lines "\);"
    }
    foreach method $methods {
        #item 1559
        set body [ get_value $method body ]
        #item 1512
        smethod_decl $method lines
        #item 1513
        lappend lines "\) \{"
        #item 1521
        set indented [ lmap_user $body st::prepend "    " ]
        set body_block [ join $indented "\n" ]
        #item 1522
        lappend lines $body_block
        #item 1514
        lappend lines "\}"
    }
}

proc read_array { tables name } {
    #item 130
    set table [ lindex $tables 0 ]
    #item 131
    set properties [ read_properties_table $table ]
    #item 132
    return [ list "type" "array" "name" $name "props" $properties ]
}

proc read_class { tables name type } {
    #item 170
    set count [ llength $tables ]
    #item 148
    if {$count < 2} {
        #item 146
        error "Too few tables in $name"
    } else {
        #item 151
        set prop_table [ lindex $tables 0 ]
        set fields_table [ lindex $tables 1 ]
        #item 152
        set fields_header [ get_table_header $fields_table ]
        #item 153
        if {$fields_header == "fields"} {
            #item 176
            set indices {}
            #item 157
            set props [ read_properties_table $prop_table ]
            #item 158
            set columns {name type class generate}
            #item 159
            set fields [ read_columns_table \
              $name $fields_table $columns ]
            #item 161
            set fmap [ make_fields_map $name $fields ]
            #item 3192
            set smachine {}
            #item 165
            if {$type == "table"} {
                #item 1680001
                set i 2
                while { 1 } {
                    #item 1680002
                    if {$i < $count} {
                        
                    } else {
                        break
                    }
                    #item 171
                    set table [ lindex $tables $i ]
                    set table_name [ get_table_header $table ]
                    #item 172
                    if {$table_name == "index"} {
                        #item 175
                        set index [ read_properties_table $table ]
                        #item 177
                        lappend indices $index
                    } else {
                        
                    }
                    #item 1680003
                    incr i
                }
                #item 178
                set imap [ make_fields_map $name $indices ]
            } else {
                #item 576
                set imap {}
                #item 3193
                if {$count > 2} {
                    #item 3196
                    set sm_table [ lindex $tables 2 ]
                    set sm_table_name [ get_table_header $sm_table ]
                    #item 3197
                    if {$sm_table_name == "state machine"} {
                        #item 3198
                        set smachine [ read_matrix $sm_table $name ]
                    } else {
                        
                    }
                } else {
                    
                }
            }
        } else {
            #item 156
            error "$name: the second table must be 'fields'"
        }
    }
    #item 160
    return [ list \
    	"type"    $type \
    	"name"    $name \
    	"props"   $props \
    	"fields"  $fmap \
    	"indices" $imap \
            "state machine" $smachine ]
}

proc read_columns_table { name table columns } {
    #item 211
    set count [ llength $table ]
    #item 212
    if {$count < 3} {
        #item 228
        error "$name: table too short"
    } else {
        #item 215
        set headers [ lindex $table 1 ]
        #item 216
        unpack [ diff_arrays $headers $columns ] \
          equal actual expected
        #item 217
        if {$expected == {}} {
            #item 226
            set result {}
            #item 2210001
            set i 2
            while { 1 } {
                #item 2210002
                if {$i < $count} {
                    
                } else {
                    break
                }
                #item 223
                set row [ lindex $table $i ]
                #item 224
                set tagged [ read_row $row $headers ]
                #item 225
                lappend result $tagged
                #item 2210003
                incr i
            }
            #item 227
            return $result
        } else {
            #item 220
            error "$name: missing fields: $expected"
        }
    }
}

proc read_matrix { table name } {
    #item 3214
    set count [ llength $table ]
    #item 3215
    if {$count < 3} {
        #item 3218
        error "$name: table 'state machine' too short"
    } else {
        #item 3219
        set headers [ lindex $table 1 ]
        set column_count [ llength $headers ]
        #item 3220
        if {$column_count >= 2} {
            #item 3233
            set cells {}
            #item 3235
            set message_list [ lrange $headers 1 end ]
            set state_list {}
            #item 3450
            set defaults {}
            #item 3224
            set rows [ lrange $table 2 end ]
            foreach row $rows {
                #item 3227
                set state [ lindex $row 0 ]
                #item 32280001
                set i 1
                while { 1 } {
                    #item 32280002
                    if {$i < $column_count} {
                        
                    } else {
                        break
                    }
                    #item 3230
                    set message [ lindex $headers $i ]
                    #item 3231
                    set key "$state|$message"
                    #item 3232
                    set cell [ lindex $row $i ]
                    #item 3234
                    lappend cells $key $cell
                    #item 3451
                    if {$cell == ""} {
                        #item 3454
                        lappend defaults $message
                    } else {
                        
                    }
                    #item 32280003
                    incr i
                }
                #item 3236
                lappend state_list $state
            }
        } else {
            #item 3223
            error "$name: table 'state machine' too narrow"
        }
    }
    #item 3455
    set defaults [ lsort -unique $defaults ]
    #item 3243
    return [ ssmachine $message_list $state_list $cells $defaults ]
}

proc read_model_page { folder } {
    #item 91
    set name [ file tail $folder ]
    #item 92
    set page_file $folder/content.txt
    #item 93
    if {[ file exists $page_file ]} {
        #item 96
        set tables [ extract_tables $page_file ]
        #item 97
        if {[ llength $tables ] == 0} {
            #item 95
            set result ""
        } else {
            #item 107
            set first_table [ lindex $tables 0 ]
            set first_cell [ \
              get_table_header $first_table ]
            #item 1110001
            if {$first_cell == "array"} {
                #item 98
                set result [ \
                  read_array $tables $name ]
            } else {
                #item 1110002
                if {($first_cell == "class") || ($first_cell == "table")} {
                    #item 123
                    set result [ \
                      read_class $tables $name $first_cell ]
                } else {
                    #item 118
                    error "Unknown model type in $page_file"
                }
            }
        }
    } else {
        #item 95
        set result ""
    }
    #item 110
    return $result
}

proc read_model_pages { path } {
    #item 84
    set folders [ glob -type d -nocomplain $path/* ]
    #item 85
    return [ lmap $folders st::read_model_page ]
}

proc read_properties_table { table } {
    #item 186
    set count [ llength $table ]
    #item 189
    set properties {}
    #item 1840001
    set i 1
    while { 1 } {
        #item 1840002
        if {$i < $count} {
            
        } else {
            break
        }
        #item 187
        set row [ lindex $table $i ]
        #item 188
        set first [ lindex $row 0 ]
        set second [ lindex $row 1 ]
        #item 193
        if {($first == "") || ($second == "")} {
            
        } else {
            #item 190
            lappend properties $first $second
        }
        #item 1840003
        incr i
    }
    #item 191
    return $properties
}

proc read_row { cells headers } {
    #item 274
    set result {}
    #item 273
    set count [ llength $headers ]
    #item 2710001
    set i 0
    while { 1 } {
        #item 2710002
        if {$i < $count} {
            
        } else {
            break
        }
        #item 275
        set header [ lindex $headers $i ]
        set cell   [ lindex $cells $i ]
        #item 276
        lappend result $header $cell
        #item 2710003
        incr i
    }
    #item 277
    return $result
}

proc read_snippets { filename } {
    #item 528
    set content [ read_all_text $filename ]
    #item 529
    set lines [ split $content "\n" ]
    lappend lines "\n\n\n"
    #item 530
    set acc { "idle" {} {} {}}
    #item 533
    set result [ lfold $lines st::snippet_line $acc ]
    #item 531
    unpack $result state map
    #item 532
    return $map
}

proc read_template { filename type } {
    #item 410
    global script_path
    #item 411
    set path [ file join $script_path structure $filename ]
    #item 412
    set content [ read_all_text $path.c ]
    #item 427
    set lines [ split $content "\n" ]
    #item 487
    set init_acc [ list \
    	"normal"    \
    	{}          \
    	$type       \
    	$filename ]
    #item 488
    set final_acc [ lfold         \
    	$lines                 \
    	st::read_template_line \
    	$init_acc	]
    #item 494
    unpack $final_acc  \
    	state      \
    	proc_lines \
    	type2      \
    	filename2
    #item 489
    return [ join $proc_lines "\n" ]
}

proc read_template_line { line acc } {
    #item 454
    unpack $acc    \
    	state  \
    	result \
    	type   \
    	filename
    #item 493
    set tr_line \
      [ string trim $line ]
    #item 4570001
    if {$state == "normal"} {
        #item 464
        if {[ string match "IF *" $tr_line ]} {
            #item 468
            if {[ contains $line $type ]} {
                #item 473
                set new_state "if"
            } else {
                #item 474
                set new_state "skip"
            }
        } else {
            #item 475
            if {$tr_line == "END"} {
                #item 477
                error "Unexpected END in $filename"
            } else {
                #item 467
                lappend result $line
                #item 483
                set new_state $state
            }
        }
    } else {
        #item 4570002
        if {$state == "if"} {
            #item 479
            if {$tr_line == "END"} {
                #item 482
                set new_state "normal"
            } else {
                #item 478
                lappend result $line
                #item 481
                set new_state $state
            }
        } else {
            #item 4570003
            if {$state == "skip"} {
                
            } else {
                #item 4570004
                error "Unexpected switch value: $state"
            }
            #item 490
            if {$tr_line == "END"} {
                #item 492
                set new_state "normal"
            } else {
                #item 484
                set new_state $state
            }
        }
    }
    #item 485
    set new_acc [ list \
    	$new_state \
    	$result    \
    	$type      \
    	$filename ]
    #item 486
    return $new_acc
}

proc record_field { fname fields } {
    #item 1597
    set field [ get_value $fields $fname ]
    #item 1588
    set name [ get_value $field name ]
    set type [ get_value $field type ]
    set comment [ get_opt_value $field comment "" ]
    set class [ get_value $field class ]
    #item 1599
    if {$type == "own"} {
        #item 1602
        set comment "Ownership. $comment"
        #item 1604
        set ftype "$class*"
    } else {
        #item 1603
        set ftype $class
    }
    #item 1589
    return [ sfield $ftype $name $comment ]
}

proc remove_formatting { line } {
    #item 573
    set mapping { "'''" "" "!-" "" "-!" "" }
    #item 574
    return [ string map $mapping $line ]
}

proc save_item { item fields } {
    #item 2448
    set fnames [ get_keys $fields ]
    #item 2468
    set ser_fields [ select_ser_fields $fields ]
    #item 2453
    set dname "${item}_SaveItem"
    #item 2452
    set returns { "int" "" }
    #item 2450
    set obj [ sfield "$item*" "item" "" ]
    set ign [ sfield "void*" "userData" "" ]
    #item 2451
    set comment "Saves $item."
    #item 2449
    set signature [ ssignature $dname $returns [ list $obj $ign ] $comment ]
    #item 2455
    set lines {}
    lappend lines "WriteStream* stream;"
    #item 2460
    lappend lines "stream = userData;"
    #item 2456
    set user_data [ list $fields 1 ]
    add_range lines [ lmap_user $ser_fields st::field_save $user_data ]
    #item 2458
    lappend lines "return 0;"
    #item 2457
    return [ smethod $signature {static} $lines ]
}

proc select_ser_fields { fields } {
    #item 2412
    set fnames [ get_keys $fields ]
    #item 2413
    set result {}
    foreach fname $fnames {
        #item 2417
        set field [ get_value $fields $fname ]
        set class [ get_value $field class ]
        #item 2418
        if {[ is_pointer $class ]} {
            
        } else {
            #item 2421
            lappend result $fname
        }
    }
    #item 2414
    return $result
}

proc sfield { type name comment } {
    #item 1228
    return [ list type $type name $name comment $comment ]
}

proc smethod { signature modifiers body } {
    #item 1246
    return [ list \
    signature $signature \
    modifiers $modifiers \
    body      $body ]
}

proc smethod_args { arguments lines_var } {
    #item 1486
    upvar $lines_var lines
    #item 1555
    if {[ llength $arguments ] == 0} {
        #item 1558
        lappend lines "    void"
    } else {
        #item 1487
        set first_args [ lrange $arguments 0 end-1 ]
        set last_arg [ lindex $arguments end ]
        foreach arg $first_args {
            #item 1490
            set atype [ get_value $arg type ]
            set aname [ get_value $arg name ]
            set acomm [ get_value $arg comment ]
            #item 1491
            if {$acomm == ""} {
                #item 1495
                lappend lines "    $atype $aname,"
            } else {
                #item 1494
                lappend lines "    $atype $aname, // $acomm"
            }
        }
        #item 1496
        set atype [ get_value $last_arg type ]
        set aname [ get_value $last_arg name ]
        set acomm [ get_value $last_arg comment ]
        #item 1497
        if {$acomm == ""} {
            #item 1501
            lappend lines "    $atype $aname"
        } else {
            #item 1500
            lappend lines "    $atype $aname // $acomm"
        }
    }
}

proc smethod_decl { method lines_var } {
    #item 1450
    upvar $lines_var lines
    #item 1451
    set signature [ get_value $method signature ]
    set modifiers [ get_value $method modifiers ]
    set comment      [ get_value $signature comment ]
    set name         [ get_value $signature name ]
    set return_value [ get_value $signature return_value ]
    set arguments    [ get_value $signature arguments ]
    #item 1454
    lassign $return_value ret_type ret_comment
    #item 1452
    lappend lines ""
    #item 1503
    if {$comment == {}} {
        
    } else {
        #item 1453
        lappend lines "// $comment"
    }
    #item 1455
    if {[ contains $modifiers static ]} {
        #item 1458
        lappend lines static
    } else {
        
    }
    #item 1459
    if {$ret_comment == ""} {
        #item 1463
        lappend lines $ret_type
    } else {
        #item 1462
        lappend lines "$ret_type // $ret_comment"
    }
    #item 1464
    lappend lines "$name\("
    #item 1502
    smethod_args $arguments lines
}

proc snip { snippets section args } {
    #item 616
    set block [ get_value $snippets $section ]
    #item 617
    set replaced [ string map $args $block ]
    #item 661
    return [ string trimright $replaced ]
}

proc snippet_line { line acc } {
    #item 539
    unpack $acc state map snippet current
    #item 548
    set stripped [ string trim $line ]
    #item 5410001
    if {$state == "idle"} {
        #item 549
        if {$stripped == ""} {
            
        } else {
            #item 552
            set snippet $stripped
            #item 553
            set state "snippet"
            #item 564
            set current {}
        }
    } else {
        #item 5410002
        if {$state == "snippet"} {
            #item 556
            lappend current $line
            #item 554
            if {$stripped == ""} {
                #item 557
                set state "empty"
            } else {
                
            }
        } else {
            #item 5410003
            if {$state == "empty"} {
                
            } else {
                #item 5410004
                error "Unexpected switch value: $state"
            }
            #item 558
            if {$stripped == ""} {
                #item 561
                set state "idle"
                #item 577
                set block [ join $current "\n" ]
                #item 565
                lappend map $snippet $block
            } else {
                #item 563
                lappend current $line
                #item 562
                set state "snippet"
            }
        }
    }
    #item 540
    return [ list $state $map \
      $snippet $current ]
}

proc ssignature { name return_value arguments comment } {
    #item 1240
    return [ list \
    name         $name \
    return_value $return_value \
    arguments    $arguments \
    comment      $comment ]
}

proc ssmachine { messages states cells defaults } {
    #item 3242
    return [ list \
     messages $messages \
     states   $states \
     cells    $cells \
     defaults $defaults ]
}

proc sstruct { name fields methods typedefs dtr comment ptypedefs code } {
    #item 1234
    return [ list \
     name      $name \
     fields    $fields \
     methods   $methods \
     typedefs  $typedefs \
     dtr       $dtr \
     comment   $comment \
     ptypedefs $ptypedefs \
     on_message 0 \
     code      $code]
}

proc trim_line { line } {
    #item 54
    return [ string trim $line ]
}

proc typedef_decl { signature lines_var } {
    #item 1978
    upvar $lines_var lines
    #item 1979
    set comment      [ get_value $signature comment ]
    set name         [ get_value $signature name ]
    set return_value [ get_value $signature return_value ]
    set arguments    [ get_value $signature arguments ]
    #item 1982
    lassign $return_value ret_type ret_comment
    #item 1980
    lappend lines ""
    #item 1994
    if {$comment == {}} {
        
    } else {
        #item 1981
        lappend lines "// $comment"
    }
    #item 1998
    lappend lines "typedef"
    #item 1987
    if {$ret_comment == ""} {
        #item 1991
        lappend lines $ret_type
    } else {
        #item 1990
        lappend lines "$ret_type // $ret_comment"
    }
    #item 1992
    lappend lines "\(*$name\)\("
    #item 1993
    smethod_args $arguments lines
    #item 1997
    lappend lines "\);"
}

}
