diff --git a/src/struct.v b/src/struct.v index 4280368..6f9780c 100644 --- a/src/struct.v +++ b/src/struct.v @@ -4,194 +4,215 @@ import strings // |-RecordDecl 0x7fd7c302c560 line:3:8 struct User definition fn (mut c C2V) record_decl(node &Node) { - vprintln('record_decl("${node.name}")') - // Skip empty structs (extern or forward decls) - if node.kindof(.record_decl) && node.inner.len == 0 { - return - } - mut name := node.name - // Dont generate struct header if it was already generated by typedef - // Confusing, but typedefs in C AST are really messy. - // ... - // If the struct has no name, then it's `typedef struct { ... } name` - // AST: 1) RecordDecl struct definition 2) TypedefDecl struct name - if c.tree.inner.len > c.node_i + 1 { - next_node := c.tree.inner[c.node_i + 1] - if next_node.kind == .typedef_decl { - if c.is_verbose { - c.genln('// typedef struct') - } - name = next_node.name - if name.contains('apthing_t') { - vprintln(node.str()) - } - } - } + vprintln('record_decl("${node.name}")') + // Skip empty structs (extern or forward decls) + if node.kindof(.record_decl) && node.inner.len == 0 { + return + } + mut name := node.name + // Dont generate struct header if it was already generated by typedef + // Confusing, but typedefs in C AST are really messy. + // ... + // If the struct has no name, then it's `typedef struct { ... } name` + // AST: 1) RecordDecl struct definition 2) TypedefDecl struct name + if c.tree.inner.len > c.node_i + 1 { + next_node := c.tree.inner[c.node_i + 1] + if next_node.kind == .typedef_decl { + if c.is_verbose { + c.genln('// typedef struct') + } + name = next_node.name + if name.contains('apthing_t') { + vprintln(node.str()) + } + } + } - if name in builtin_type_names { - return - } - if c.is_verbose { - c.genln('// struct decl name="${name}"') - } - if name in c.types { - return - } - // Anonymous struct, most likely the next node is a vardecl with this anon struct type, so remember it - if name == '' { - name = 'AnonStruct_${node.location.line}' - c.last_declared_type_name = name - } - if name !in ['struct', 'union'] { - c.types << name - name = capitalize_type(name) - if node.tags.contains('union') { - c.genln('union ${name} { ') - } else { - c.genln('struct ${name} { ') - } - } - mut new_struct := Struct{} - // in V it's `field struct {...}`, but in C we get struct definition first, so save it and use it in the - // next child - mut anon_struct_definition := '' - for field in node.inner { - // Handle anon structs - if field.kind == .record_decl { - anon_struct_definition = c.anon_struct_field_type(field) - continue - } - // There may be comments, skip them - if field.kind != .field_decl { - continue - } - field_type := convert_type(field.ast_type.qualified) - field_name := filter_name(field.name).uncapitalize() - mut field_type_name := field_type.name + if name in builtin_type_names { + return + } + if c.is_verbose { + c.genln('// struct decl name="${name}"') + } + if name in c.types { + return + } + // Anonymous struct, most likely the next node is a vardecl with this anon struct type, so remember it + if name == '' { + name = 'AnonStruct_${node.location.line}' + c.last_declared_type_name = name + } + if name !in ['struct', 'union'] { + c.types << name + name = capitalize_type(name) + if node.tags.contains('union') { + c.genln('union ${name} { ') + } else { + c.genln('struct ${name} { ') + } + } + mut new_struct := Struct{} + // in V it's `field struct {...}`, but in C we get struct definition first, so save it and use it in the + // next child + mut anon_struct_definition := '' + mut ano_arr := []string{} + for field in node.inner { + len := ano_arr.len + i := '${name}${len}' + if field.kind == .record_decl && field.tags.contains('union') { + anon_struct_definition = c.anon_struct_field_type(field, i) + ano_arr << anon_struct_definition + c.genln('\n${i}\n') + continue + } + } + for field in node.inner { + // Handle anon structs + if field.kind == .record_decl && field.tags.contains('union') { + continue + } + if field.kind == .record_decl { + anon_struct_definition = c.anon_struct_field_type(field, '') + continue + } + // There may be comments, skip them + if field.kind != .field_decl { + continue + } + field_type := convert_type(field.ast_type.qualified) + field_name := filter_name(field.name).uncapitalize() + mut field_type_name := field_type.name - // Handle anon structs, the anonymous struct has just been defined above, use its definition - if field_type_name.contains('unnamed at') { - field_type_name = anon_struct_definition - } - if field_type_name.contains('anonymous at') { - continue - } - /* - if field_type.name.contains('union') { - continue // TODO - } - */ - new_struct.fields << field_name - if field_type.name.ends_with('_s') { // TODO doom _t _s hack, remove - n := field_type.name[..field_type.name.len - 2] + '_t' - c.genln('\t${field_name} ${n}') - } else { - c.genln('\t${field_name} ${field_type_name}') - } - } - c.structs[name] = new_struct - c.genln('}') + // Handle anon structs, the anonymous struct has just been defined above, use its definition + if field_type_name.contains('unnamed at') { + field_type_name = anon_struct_definition + } + if field_type_name.contains('anonymous at') { + continue + } + /* + if field_type.name.contains('union') { + continue // TODO + } + */ + new_struct.fields << field_name + if field_type.name.ends_with('_s') { // TODO doom _t _s hack, remove + n := field_type.name[..field_type.name.len - 2] + '_t' + c.genln('\t${field_name} ${n}') + } else { + c.genln('\t${field_name} ${field_type_name}') + } + } + c.structs[name] = new_struct + c.genln('}') + for anon in ano_arr { + c.genln(anon) + } } -fn (mut c C2V) anon_struct_field_type(node &Node) string { - mut sb := strings.new_builder(50) - sb.write_string(' struct {') - for field in node.inner { - if field.kind != .field_decl { - continue - } - field_type := convert_type(field.ast_type.qualified) - field_name := filter_name(field.name) - sb.write_string('\t${field_name} ${field_type.name}\n') - } - sb.write_string('}\n') - return sb.str() +fn (mut c C2V) anon_struct_field_type(node &Node, i string) string { + mut sb := strings.new_builder(50) + if node.tags.contains('union') { + sb.write_string('union ${i} {\n') + } else { + sb.write_string('struct ${i} {\n') + } + for field in node.inner { + if field.kind != .field_decl { + continue + } + field_type := convert_type(field.ast_type.qualified) + field_name := filter_name(field.name) + sb.write_string('\t${field_name} ${field_type.name}\n') + } + sb.write_string('}') + return sb.str() } // Typedef node goes after struct enum, but we need to parse it first, so that "type name { " is // generated first fn (mut c C2V) typedef_decl(node &Node) { - mut typ := node.ast_type.qualified - // just a single line typedef: (alias) - // typedef sha1_context_t sha1_context_s ; - // typedef after enum decl, just generate "enum NAME {" header - mut alias_name := node.name // get_val(-2) - vprintln('TYPEDEF "${node.name}" ${node.is_builtin_type} ${typ}') - if alias_name.contains('et_context_t') { - // TODO remove this - return - } - if node.name in builtin_type_names { - return - } + mut typ := node.ast_type.qualified + // just a single line typedef: (alias) + // typedef sha1_context_t sha1_context_s ; + // typedef after enum decl, just generate "enum NAME {" header + mut alias_name := node.name // get_val(-2) + vprintln('TYPEDEF "${node.name}" ${node.is_builtin_type} ${typ}') + if alias_name.contains('et_context_t') { + // TODO remove this + return + } + if node.name in builtin_type_names { + return + } - if alias_name in c.types || alias_name in c.enums { - // This means that this is a struct/enum typedef that has already been defined. - return - } + if alias_name in c.types || alias_name in c.enums { + // This means that this is a struct/enum typedef that has already been defined. + return + } - c.types << alias_name + c.types << alias_name - if typ.starts_with('struct ') && typ.ends_with(' *') { - // Opaque pointer, for example: typedef struct TSTexture_t *TSTexture; - c.genln('type ${alias_name} = voidptr') - return - } + if typ.starts_with('struct ') && typ.ends_with(' *') { + // Opaque pointer, for example: typedef struct TSTexture_t *TSTexture; + c.genln('type ${alias_name} = voidptr') + return + } - if !typ.contains(alias_name) { - if typ.contains('(*)') { - tt := convert_type(typ) - typ = tt.name - } - // Struct types have junk before spaces - else { - alias_name = alias_name.all_after(' ') - tt := convert_type(typ) - typ = tt.name - } - if alias_name.starts_with('__') { - // Skip internal stuff like __builtin_ms_va_list - return - } - if typ in c.enums { - return - } + if !typ.contains(alias_name) { + if typ.contains('(*)') { + tt := convert_type(typ) + typ = tt.name + } + // Struct types have junk before spaces + else { + alias_name = alias_name.all_after(' ') + tt := convert_type(typ) + typ = tt.name + } + if alias_name.starts_with('__') { + // Skip internal stuff like __builtin_ms_va_list + return + } + if typ in c.enums { + return + } - mut cgen_alias := typ - if cgen_alias.starts_with('_') { - cgen_alias = trim_underscores(typ) - } - if typ !in ['int', 'i8', 'i16', 'i64', 'u8', 'u16', 'u32', 'u64', 'f32', 'f64', 'usize', 'isize', 'bool', 'void', 'voidptr'] - && !typ.starts_with('fn (') { - // TODO handle this better - cgen_alias = cgen_alias.capitalize() - } - c.genln('type ${alias_name.capitalize()} = ${cgen_alias}') // typedef alias (SINGLE LINE)') - return - } - if typ.contains('enum ') { - // enums were alredy handled in enum_decl - return - } else if typ.contains('struct ') { - // structs were already handled in struct_decl - return - } else if typ.contains('union ') { - // unions were alredy handled in struct_decl - return - } + mut cgen_alias := typ + if cgen_alias.starts_with('_') { + cgen_alias = trim_underscores(typ) + } + if typ !in ['int', 'i8', 'i16', 'i64', 'u8', 'u16', 'u32', 'u64', 'f32', 'f64', 'usize', 'isize', 'bool', 'void', 'voidptr'] + && !typ.starts_with('fn (') { + // TODO handle this better + cgen_alias = cgen_alias.capitalize() + } + c.genln('type ${alias_name.capitalize()} = ${cgen_alias}') // typedef alias (SINGLE LINE)') + return + } + if typ.contains('enum ') { + // enums were alredy handled in enum_decl + return + } else if typ.contains('struct ') { + // structs were already handled in struct_decl + return + } else if typ.contains('union ') { + // unions were alredy handled in struct_decl + return + } } // this calls typedef_decl() above fn (mut c C2V) parse_next_typedef() bool { - // Hack: typedef with the actual enum name is next, parse it and generate "enum NAME {" first - /* - XTODO - next_line := c.lines[c.line_i + 1] - if next_line.contains('TypedefDecl') { - c.line_i++ - c.parse_next_node() - return true - } - */ - return false + // Hack: typedef with the actual enum name is next, parse it and generate "enum NAME {" first + /* + XTODO + next_line := c.lines[c.line_i + 1] + if next_line.contains('TypedefDecl') { + c.line_i++ + c.parse_next_node() + return true + } + */ + return false }