add documentation generation for type signatures

This commit is contained in:
2025-11-11 12:05:03 +01:00
parent 7a2290c00e
commit 071696a786

View File

@@ -3,15 +3,15 @@
inner
}
#let type_primitive(id, name) = {
(type: "primitive", type_id: id, type_name: name)
#let type_primitive(id, name, cs_name) = {
(type: "primitive", type_id: id, type_name: name, type_name_cs: cs_name)
}
#let int = type_primitive("integer", "an 'integer'");
#let float = type_primitive("float", "a 'float'");
#let bool = type_primitive("boolean", "a 'boolean'");
#let string = type_primitive("string", "a 'string'");
#let content = type_primitive("content", "a 'content'");
#let int = type_primitive("integer", "an 'integer'", "celé číslo");
#let float = type_primitive("float", "a 'float'", "desetinné číslo");
#let bool = type_primitive("boolean", "a 'boolean'", "pravdivostní hodnota");
#let string = type_primitive("string", "a 'string'", "textový řetězec");
#let content = type_primitive("content", "a 'content'", "obsah generovaný Typst syntaxí");
#let literal(value) = {
(type: "literal", value: value)
@@ -21,8 +21,8 @@
(type: "variants", variants: variants.pos())
}
#let list(items) = {
(type: "list", items: items)
#let slice(items) = {
(type: "slice", items: items)
}
#let tuple(..items) = {
@@ -38,13 +38,23 @@
}
#let struct(..keyvals) = {
let copy_doc(from, to) = {
if "doc" in from {
let to = to;
to.doc = from.doc;
to
} else {
to
}
}
let keyvals = keyvals.pos();
let res = ().to-dict();
for keyval in keyvals {
if keyval.key.type != "literal" {
panic("invalid type signature, struct keys must be literals");
}
res.insert(keyval.key.value, keyval.val);
res.insert(keyval.key.value, copy_doc(keyval, keyval.val));
}
(type: "struct", pairs: res)
}
@@ -80,7 +90,7 @@
} else {
res
}
} else if target.type == "list" or target.type == "tuple" {
} else if target.type == "slice" or target.type == "tuple" {
"an array"
} else if target.type == "dictionary" or target.type == "struct" {
"a dictionary/hashmap"
@@ -93,8 +103,12 @@
}
}
let error(target, name_prefix, value, is_value: false) = {
error_target_name(target, name_prefix) + " " + if is_value {
let error(target, name_prefix, value, is_value: false, target_doc: none) = {
if type(target_doc) != type(none) {
error_target_name(target_doc)
} else {
error_target_name(target, name_prefix)
} + " " + if is_value {
"is unexpected"
} else {
"has an unexpected type '" + error_value_name(value) + "'"
@@ -128,7 +142,11 @@
if target.type == "struct" {
for key in target.pairs.keys() {
if key not in value {
return (false, name_prefix + " is missing an entry for key " + dbg_literal(key));
return (false, (
error_target_name(target, name_prefix) +
" is missing an entry for key " +
dbg_literal(key)
));
}
}
for (key, val) in value.pairs() {
@@ -137,7 +155,9 @@
false, name_prefix + " contains an unexpected key " + dbg_literal(key)
);
}
matches_type(val, target.pairs.at(key), name_prefix: name_prefix + " " + str(key))
matches_type(
val, target.pairs.at(key), name_prefix: name_prefix + " " + str(key)
)
}
} else if target.type == "dictionary" {
for (key, val) in value.pairs() {
@@ -145,7 +165,9 @@
if not cur.at(0) {
return cur;
}
let cur = matches_type(val, target.val, name_prefix: name_prefix + " value");
let cur = matches_type(
val, target.val, name_prefix: name_prefix + " value"
);
if not cur.at(0) {
return cur;
}
@@ -155,7 +177,7 @@
(false, error(target, name_prefix, value))
}
} else if type(value) == array {
if target.type == "list" {
if target.type == "slice" {
for (idx, val) in value.enumerate() {
let cur = matches_type(
val, target.items, name_prefix: name_prefix + " item at index " + str(idx)
@@ -192,3 +214,85 @@
matches_type(value, signature, name_prefix: name_prefix)
}
#let signature_docs(target, is_nested: false) = {
let typeinfo(target, flatten: false, disable_doc: false) = {
let try_doc(target, mapper: (v) => { v }) = {
if "doc" in target and not disable_doc {
mapper(target.doc.expl);
} else {
""
}
}
if target.type == "struct" {
if not flatten {
[slovník s přesnými atributy (_dictionary_)];
try_doc(target, mapper: (v) => { [ -- ]; v; });
":";
}
list(
..target.pairs.pairs().map(((key, val)) => {
raw(key);
try_doc(val, mapper: (v) => { [ -- ]; text(v); });
": "
typeinfo(val, disable_doc: true);
})
);
} else if target.type == "dictionary" {
[slovník (_dictionary_)];
try_doc(target, mapper: (v) => { [ -- ]; v; });
":";
list(
{
"S klíči typu ";
typeinfo(target.val);
},
{
"S hodnotami typu ";
typeinfo(target.key);
},
);
} else if target.type == "slice" {
} else if target.type == "tuple" {
} else if target.type == "primitive" {
text(target.type_name_cs + " (");
text(target.type_id, style: "italic");
text(")");
try_doc(target, mapper: (v) => { [ -- ]; text(v); });
} else if target.type == "variants" {
list(
..target.variants.map((v) => {
list.item({
typeinfo(v);
});
})
);
} else {
panic();
}
}
let args = ();
if target.type == "struct" {
for val in target.pairs.values() {
args.push(signature_docs(val, is_nested: true));
}
} else {
if "doc" in target and type(target.doc.argname) != type(none) {
args.push({
raw(target.doc.argname);
[: ]
typeinfo(target, flatten: true)
});
}
}
if not is_nested {
list(..args.flatten());
} else {
args.flatten()
}
}