Improve printing for record types

This commit is contained in:
gingerBill
2022-01-17 18:23:30 +00:00
parent 76ccce2942
commit 97922406fe
+200 -53
View File
@@ -32,6 +32,17 @@ errorf :: proc(format: string, args: ..any) -> ! {
os.exit(1) os.exit(1)
} }
base_type :: proc(t: doc.Type) -> doc.Type {
t := t
for {
if t.kind != .Named {
break
}
t = types[array(t.types)[0]]
}
return t
}
common_prefix :: proc(strs: []string) -> string { common_prefix :: proc(strs: []string) -> string {
if len(strs) == 0 { if len(strs) == 0 {
return "" return ""
@@ -270,10 +281,74 @@ is_entity_blank :: proc(e: doc.Entity_Index) -> bool {
Write_Type_Flag :: enum { Write_Type_Flag :: enum {
Is_Results, Is_Results,
Variadic, Variadic,
Allow_Indent,
} }
Write_Type_Flags :: distinct bit_set[Write_Type_Flag] Write_Type_Flags :: distinct bit_set[Write_Type_Flag]
Type_Writer :: struct {
w: io.Writer,
pkg: doc.Pkg_Index,
indent: int,
}
write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type_Flags) {
write_param_entity :: proc(using writer: ^Type_Writer, e: ^doc.Entity, flags: Write_Type_Flags, name_width := 0) {
name := str(e.name)
if .Param_Using in e.flags { io.write_string(w, "using ") }
if .Param_Const in e.flags { io.write_string(w, "#const ") }
if .Param_Auto_Cast in e.flags { io.write_string(w, "#auto_cast ") }
if .Param_CVararg in e.flags { io.write_string(w, "#c_vararg ") }
if .Param_No_Alias in e.flags { io.write_string(w, "#no_alias ") }
if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") }
if name != "" {
io.write_string(w, name)
io.write_string(w, ": ")
}
padding := max(name_width-len(name), 0)
for _ in 0..<padding {
io.write_byte(w, ' ')
}
param_flags := flags - {.Is_Results}
if .Param_Ellipsis in e.flags {
param_flags += {.Variadic}
}
write_type(writer, types[e.type], param_flags)
}
write_poly_params :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type_Flags) {
type_entites := array(type.entities)
for entity_index, i in type_entites {
if i > 0 {
io.write_string(w, ", ")
}
write_param_entity(writer, &entities[entity_index], flags)
}
io.write_byte(w, ')')
}
do_indent :: proc(using writer: ^Type_Writer, flags: Write_Type_Flags) {
if .Allow_Indent not_in flags {
return
}
for _ in 0..<indent {
io.write_byte(w, '\t')
}
}
do_newline :: proc(using writer: ^Type_Writer, flags: Write_Type_Flags) {
if .Allow_Indent in flags {
io.write_byte(w, '\n')
}
}
calc_name_width :: proc(type_entites: []doc.Entity_Index) -> (name_width: int) {
for entity_index in type_entites {
e := &entities[entity_index]
name := str(e.name)
name_width = max(len(name), name_width)
}
return
}
write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Write_Type_Flags) {
type_entites := array(type.entities) type_entites := array(type.entities)
type_types := array(type.types) type_types := array(type.types)
switch type.kind { switch type.kind {
@@ -301,75 +376,128 @@ write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Writ
io.write_string(w, name) io.write_string(w, name)
if len(array(type.types)) == 1 { if len(array(type.types)) == 1 {
io.write_byte(w, '/') io.write_byte(w, '/')
write_type(w, pkg, types[type_types[0]], flags) write_type(writer, types[type_types[0]], flags)
} }
case .Pointer: case .Pointer:
io.write_byte(w, '^') io.write_byte(w, '^')
write_type(w, pkg, types[type_types[0]], flags) write_type(writer, types[type_types[0]], flags)
case .Array: case .Array:
assert(type.elem_count_len == 1) assert(type.elem_count_len == 1)
io.write_byte(w, '[') io.write_byte(w, '[')
io.write_uint(w, uint(type.elem_counts[0])) io.write_uint(w, uint(type.elem_counts[0]))
io.write_byte(w, ']') io.write_byte(w, ']')
write_type(w, pkg, types[type_types[0]], flags) write_type(writer, types[type_types[0]], flags)
case .Enumerated_Array: case .Enumerated_Array:
io.write_byte(w, '[') io.write_byte(w, '[')
write_type(w, pkg, types[type_types[0]], flags) write_type(writer, types[type_types[0]], flags)
io.write_byte(w, ']') io.write_byte(w, ']')
write_type(w, pkg, types[type_types[1]], flags) write_type(writer, types[type_types[1]], flags)
case .Slice: case .Slice:
if .Variadic in flags { if .Variadic in flags {
io.write_string(w, "..") io.write_string(w, "..")
} else { } else {
io.write_string(w, "[]") io.write_string(w, "[]")
} }
write_type(w, pkg, types[type_types[0]], flags - {.Variadic}) write_type(writer, types[type_types[0]], flags - {.Variadic})
case .Dynamic_Array: case .Dynamic_Array:
io.write_string(w, "[dynamic]") io.write_string(w, "[dynamic]")
write_type(w, pkg, types[type_types[0]], flags) write_type(writer, types[type_types[0]], flags)
case .Map: case .Map:
io.write_string(w, "map[") io.write_string(w, "map[")
write_type(w, pkg, types[type_types[0]], flags) write_type(writer, types[type_types[0]], flags)
io.write_byte(w, ']') io.write_byte(w, ']')
write_type(w, pkg, types[type_types[1]], flags) write_type(writer, types[type_types[1]], flags)
case .Struct: case .Struct:
type_flags := transmute(doc.Type_Flags_Struct)type.flags type_flags := transmute(doc.Type_Flags_Struct)type.flags
io.write_string(w, "struct {}") io.write_string(w, "struct")
if .Polymorphic in type_flags {
write_poly_params(writer, type, flags)
}
if .Packed in type_flags { io.write_string(w, " #packed") }
if .Raw_Union in type_flags { io.write_string(w, " #raw_union") }
if custom_align := str(type.custom_align); custom_align != "" {
io.write_string(w, " #align")
io.write_string(w, custom_align)
}
io.write_string(w, " {")
do_newline(writer, flags)
indent += 1
name_width := calc_name_width(type_entites)
for entity_index in type_entites {
e := &entities[entity_index]
do_indent(writer, flags)
write_param_entity(writer, e, flags, name_width)
io.write_byte(w, ',')
do_newline(writer, flags)
}
indent -= 1
do_indent(writer, flags)
io.write_string(w, "}")
case .Union: case .Union:
type_flags := transmute(doc.Type_Flags_Union)type.flags type_flags := transmute(doc.Type_Flags_Union)type.flags
io.write_string(w, "union {}") io.write_string(w, "union")
if .Polymorphic in type_flags {
write_poly_params(writer, type, flags)
}
if .No_Nil in type_flags { io.write_string(w, " #no_nil") }
if .Maybe in type_flags { io.write_string(w, " #maybe") }
if custom_align := str(type.custom_align); custom_align != "" {
io.write_string(w, " #align")
io.write_string(w, custom_align)
}
io.write_string(w, " {")
if len(type_types) > 1 {
do_newline(writer, flags)
indent += 1
for type_index in type_types {
do_indent(writer, flags)
write_type(writer, types[type_index], flags)
io.write_string(w, ", ")
do_newline(writer, flags)
}
indent -= 1
do_indent(writer, flags)
}
io.write_string(w, "}")
case .Enum: case .Enum:
io.write_string(w, "enum {}") io.write_string(w, "enum")
io.write_string(w, " {")
do_newline(writer, flags)
indent += 1
name_width := calc_name_width(type_entites)
for entity_index in type_entites {
e := &entities[entity_index]
do_indent(writer, flags)
io.write_string(w, str(e.name))
if init_string := str(e.init_string); init_string != "" {
for _ in 0..<name_width {
io.write_byte(w, ' ')
}
io.write_string(w, " = ")
io.write_string(w, init_string)
}
io.write_string(w, ", ")
do_newline(writer, flags)
}
indent -= 1
do_indent(writer, flags)
io.write_string(w, "}")
case .Tuple: case .Tuple:
entity_indices := type_entites if len(type_entites) == 0 {
if len(entity_indices) == 0 {
return return
} }
require_parens := (.Is_Results in flags) && (len(entity_indices) > 1 || !is_entity_blank(entity_indices[0])) require_parens := (.Is_Results in flags) && (len(type_entites) > 1 || !is_entity_blank(type_entites[0]))
if require_parens { io.write_byte(w, '(') } if require_parens { io.write_byte(w, '(') }
for entity_index, i in entity_indices { for entity_index, i in type_entites {
e := &entities[entity_index]
name := str(e.name)
if i > 0 { if i > 0 {
io.write_string(w, ", ") io.write_string(w, ", ")
} }
if .Param_Using in e.flags { io.write_string(w, "using ") } write_param_entity(writer, &entities[entity_index], flags)
if .Param_Const in e.flags { io.write_string(w, "#const ") }
if .Param_Auto_Cast in e.flags { io.write_string(w, "#auto_cast ") }
if .Param_CVararg in e.flags { io.write_string(w, "#c_vararg ") }
if .Param_No_Alias in e.flags { io.write_string(w, "#no_alias ") }
if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") }
if name != "" {
io.write_string(w, name)
io.write_string(w, ": ")
}
param_flags := flags - {.Is_Results}
if .Param_Ellipsis in e.flags {
param_flags += {.Variadic}
}
write_type(w, pkg, types[e.type], param_flags)
} }
if require_parens { io.write_byte(w, ')') } if require_parens { io.write_byte(w, ')') }
@@ -385,12 +513,12 @@ write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Writ
params := array(type.types)[0] params := array(type.types)[0]
results := array(type.types)[1] results := array(type.types)[1]
io.write_byte(w, '(') io.write_byte(w, '(')
write_type(w, pkg, types[params], flags) write_type(writer, types[params], flags)
io.write_byte(w, ')') io.write_byte(w, ')')
if results != 0 { if results != 0 {
assert(.Diverging not_in type_flags) assert(.Diverging not_in type_flags)
io.write_string(w, " -> ") io.write_string(w, " -> ")
write_type(w, pkg, types[results], flags+{.Is_Results}) write_type(writer, types[results], flags+{.Is_Results})
} }
if .Diverging in type_flags { if .Diverging in type_flags {
io.write_string(w, " -> !") io.write_string(w, " -> !")
@@ -415,24 +543,24 @@ write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Writ
io.write_string(w, "#soa[dynamic]") io.write_string(w, "#soa[dynamic]")
case .Relative_Pointer: case .Relative_Pointer:
io.write_string(w, "#relative(") io.write_string(w, "#relative(")
write_type(w, pkg, types[type_types[1]], flags) write_type(writer, types[type_types[1]], flags)
io.write_string(w, ") ") io.write_string(w, ") ")
write_type(w, pkg, types[type_types[0]], flags) write_type(writer, types[type_types[0]], flags)
case .Relative_Slice: case .Relative_Slice:
io.write_string(w, "#relative(") io.write_string(w, "#relative(")
write_type(w, pkg, types[type_types[1]], flags) write_type(writer, types[type_types[1]], flags)
io.write_string(w, ") ") io.write_string(w, ") ")
write_type(w, pkg, types[type_types[0]], flags) write_type(writer, types[type_types[0]], flags)
case .Multi_Pointer: case .Multi_Pointer:
io.write_string(w, "[^]") io.write_string(w, "[^]")
write_type(w, pkg, types[type_types[0]], flags) write_type(writer, types[type_types[0]], flags)
case .Matrix: case .Matrix:
io.write_string(w, "matrix[") io.write_string(w, "matrix[")
io.write_uint(w, uint(type.elem_counts[0])) io.write_uint(w, uint(type.elem_counts[0]))
io.write_string(w, ", ") io.write_string(w, ", ")
io.write_uint(w, uint(type.elem_counts[1])) io.write_uint(w, uint(type.elem_counts[1]))
io.write_string(w, "]") io.write_string(w, "]")
write_type(w, pkg, types[type_types[0]], flags) write_type(writer, types[type_types[0]], flags)
} }
} }
@@ -529,12 +657,16 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
print_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { print_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) {
fmt.wprintf(w, "<h4>%s</h4>\n", name) fmt.wprintf(w, "<h4>%s</h4>\n", name)
fmt.wprintln(w, `<section class="documentation-index">`) fmt.wprintln(w, `<section class="documentation-index">`)
fmt.wprintln(w, "<ul>") if len(entities) == 0 {
for e in entities { io.write_string(w, "<p>This section is empty.</p>\n")
name := str(e.name) } else {
fmt.wprintf(w, "<li><a href=\"#{0:s}\">{0:s}</a></li>\n", name) fmt.wprintln(w, "<ul>")
for e in entities {
name := str(e.name)
fmt.wprintf(w, "<li><a href=\"#{0:s}\">{0:s}</a></li>\n", name)
}
fmt.wprintln(w, "</ul>")
} }
fmt.wprintln(w, "</ul>")
fmt.wprintln(w, "</section>") fmt.wprintln(w, "</section>")
} }
@@ -549,7 +681,13 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
print_entity :: proc(w: io.Writer, e: ^doc.Entity) { print_entity :: proc(w: io.Writer, e: ^doc.Entity) {
pkg := &pkgs[files[e.pos.file].pkg] pkg_index := files[e.pos.file].pkg
pkg := &pkgs[pkg_index]
writer := &Type_Writer{
w = w,
pkg = pkg_index,
}
name := str(e.name) name := str(e.name)
fmt.wprintf(w, "<h4 id=\"{0:s}\"><a href=\"#{0:s}\">{0:s}</a></h3>\n", name) fmt.wprintf(w, "<h4 id=\"{0:s}\"><a href=\"#{0:s}\">{0:s}</a></h3>\n", name)
switch e.kind { switch e.kind {
@@ -558,10 +696,15 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
case .Constant: case .Constant:
case .Variable: case .Variable:
case .Type_Name: case .Type_Name:
fmt.wprint(w, "<pre>")
fmt.wprintf(w, "%s :: ", name)
tn := base_type(types[e.type])
write_type(writer, tn, {.Allow_Indent})
fmt.wprintln(w, "</pre>")
case .Procedure: case .Procedure:
fmt.wprint(w, "<pre>") fmt.wprint(w, "<pre>")
fmt.wprintf(w, "%s :: ", name) fmt.wprintf(w, "%s :: ", name)
write_type(w, files[e.pos.file].pkg, types[e.type], nil) write_type(writer, types[e.type], nil)
where_clauses := array(e.where_clauses) where_clauses := array(e.where_clauses)
if len(where_clauses) != 0 { if len(where_clauses) != 0 {
io.write_string(w, " where ") io.write_string(w, " where ")
@@ -583,8 +726,12 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
print_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) { print_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) {
fmt.wprintf(w, "<h3>%s</h3>\n", title) fmt.wprintf(w, "<h3>%s</h3>\n", title)
fmt.wprintln(w, `<section class="documentation">`) fmt.wprintln(w, `<section class="documentation">`)
for e in entities { if len(entities) == 0 {
print_entity(w, e) io.write_string(w, "<p>This section is empty.</p>\n")
} else {
for e in entities {
print_entity(w, e)
}
} }
fmt.wprintln(w, "</section>") fmt.wprintln(w, "</section>")
} }