feat: display structures and their fields properly

main
Henrik Böving 2022-01-04 08:23:39 +01:00
parent 3adb8e71d1
commit 8a58752c56
5 changed files with 61 additions and 37 deletions

View File

@ -5,7 +5,6 @@ namespace Output
open scoped DocGen4.Jsx open scoped DocGen4.Jsx
def ctorToHtml (i : NameInfo) : HtmlM Html := do def ctorToHtml (i : NameInfo) : HtmlM Html := do
let name := i.name.components'.head!.toString let name := i.name.components'.head!.toString
return <li «class»="constructor" id={name}>{name} : [←infoFormatToHtml i.type]</li> return <li «class»="constructor" id={name}>{name} : [←infoFormatToHtml i.type]</li>

View File

@ -5,6 +5,7 @@ Authors: Henrik Böving
-/ -/
import DocGen4.Output.Template import DocGen4.Output.Template
import DocGen4.Output.Inductive import DocGen4.Output.Inductive
import DocGen4.Output.Structure
namespace DocGen4 namespace DocGen4
namespace Output namespace Output
@ -30,6 +31,19 @@ def argToHtml (arg : Arg) : HtmlM Html := do
else else
html html
def structureInfoHeader (s : StructureInfo) : HtmlM (Array Html) := do
let mut nodes := #[]
if s.parents.size > 0 then
nodes := nodes.push <span «class»="decl_extends">extends</span>
let mut parents := #[]
for parent in s.parents do
let link := <a «class»="break_within" href={←declNameToLink parent}>{parent.toString}</a>
let inner := Html.element "span" true #[("class", "fn")] #[link]
let html:= Html.element "span" false #[("class", "decl_parent")] #[inner]
parents := parents.push html
nodes := nodes.append (parents.toList.intersperse (Html.text ", ")).toArray
nodes
def docInfoHeader (doc : DocInfo) : HtmlM Html := do def docInfoHeader (doc : DocInfo) : HtmlM Html := do
let mut nodes := #[] let mut nodes := #[]
-- TODO: noncomputable, partial -- TODO: noncomputable, partial
@ -44,14 +58,19 @@ def docInfoHeader (doc : DocInfo) : HtmlM Html := do
</span> </span>
for arg in doc.getArgs do for arg in doc.getArgs do
nodes := nodes.push (←argToHtml arg) nodes := nodes.push (←argToHtml arg)
if let DocInfo.structureInfo i := doc then
nodes := nodes.append (←structureInfoHeader i)
nodes := nodes.push <span «class»="decl_args">:</span> nodes := nodes.push <span «class»="decl_args">:</span>
nodes := nodes.push $ Html.element "div" true #[("class", "decl_type")] (←infoFormatToHtml doc.getType) nodes := nodes.push $ Html.element "div" true #[("class", "decl_type")] (←infoFormatToHtml doc.getType)
-- TODO: The final type of the declaration -- TODO: The final type of the declaration
return <div «class»="decl_header"> [nodes] </div> return <div «class»="decl_header"> [nodes] </div>
def docInfoToHtml (doc : DocInfo) : HtmlM Html := do def docInfoToHtml (doc : DocInfo) : HtmlM Html := do
let doc_html := match doc with let doc_html match doc with
| DocInfo.inductiveInfo i => inductiveToHtml i | DocInfo.inductiveInfo i => inductiveToHtml i
| DocInfo.structureInfo i => structureToHtml i
| _ => #[] | _ => #[]
return <div «class»="decl" id={doc.getName.toString}> return <div «class»="decl" id={doc.getName.toString}>

View File

@ -0,0 +1,15 @@
import DocGen4.Output.Template
namespace DocGen4
namespace Output
open scoped DocGen4.Jsx
def fieldToHtml (f : NameInfo) : HtmlM Html := do
return <li «class»="structure_field" id={f.name.toString}>{s!"{f.name} : "} [←infoFormatToHtml f.type]</li>
def structureToHtml (i : StructureInfo) : HtmlM (Array Html) := do
#[Html.element "ul" false #[("class", "structure_fields"), ("id", s!"{i.name.toString}.mk")] (←i.fieldInfo.mapM fieldToHtml)]
end Output
end DocGen4

View File

@ -56,13 +56,8 @@ structure InductiveInfo extends Info where
isUnsafe : Bool isUnsafe : Bool
deriving Inhabited deriving Inhabited
structure FieldInfo extends NameInfo where
projFn : Name
subobject? : Option Name
deriving Inhabited
structure StructureInfo extends Info where structure StructureInfo extends Info where
fieldInfo : Array FieldInfo fieldInfo : Array NameInfo
parents : Array Name parents : Array Name
ctor : NameInfo ctor : NameInfo
deriving Inhabited deriving Inhabited
@ -162,33 +157,36 @@ def InductiveInfo.ofInductiveVal (v : InductiveVal) : MetaM InductiveInfo := do
let ctors ← v.ctors.mapM (λ name => do NameInfo.mk name (←getConstructorType name)) let ctors ← v.ctors.mapM (λ name => do NameInfo.mk name (←getConstructorType name))
return InductiveInfo.mk info ctors v.isUnsafe return InductiveInfo.mk info ctors v.isUnsafe
def getFieldTypeAux (type : Expr) (vars : List Name) : (Expr × List Name) := def dropArgs (type : Expr) (n : Nat) : (Expr × List (Name × Expr)) :=
match type with match type, n with
| Expr.forallE `self _ b .. => (b, (`self :: vars)) | e, 0 => (e, [])
| Expr.forallE n _ b .. => getFieldTypeAux b (n :: vars) | Expr.forallE name type body _, x + 1 =>
| _ => (type, vars) let body := body.instantiate1 $ mkFVar ⟨name⟩
let next := dropArgs body x
{ next with snd := (name, type) :: next.snd}
| e, x + 1 => panic! s!"No forallE left"
def getFieldType (projFn : Name) : MetaM Expr := do def getFieldTypes (ctor : ConstructorVal) (parents : Nat) : MetaM (Array NameInfo) := do
let fn ← mkConstWithFreshMVarLevels projFn let type := ctor.type
let type ← inferType fn let (field_function, params) := dropArgs type (ctor.numParams + parents)
let (type, vars) := getFieldTypeAux type [] let (_, fields) := dropArgs field_function (ctor.numFields - parents)
type.instantiate $ vars.toArray.map mkConst let mut field_infos := #[]
for (name, type) in fields do
def FieldInfo.ofStructureFieldInfo (i : StructureFieldInfo) : MetaM FieldInfo := do field_infos := field_infos.push { name := name, type := ←prettyPrintTerm type}
let type ← getFieldType i.projFn field_infos
let ni := NameInfo.mk i.fieldName (←prettyPrintTerm type)
FieldInfo.mk ni i.projFn i.subobject?
def StructureInfo.ofInductiveVal (v : InductiveVal) : MetaM StructureInfo := do def StructureInfo.ofInductiveVal (v : InductiveVal) : MetaM StructureInfo := do
let info ← Info.ofConstantVal v.toConstantVal let info ← Info.ofConstantVal v.toConstantVal
let env ← getEnv let env ← getEnv
let parents := getParentStructures env v.name let parents := getParentStructures env v.name
let ctor := getStructureCtor env v.name |>.name let ctor := getStructureCtor env v.name
let ctorType ← getConstructorType ctor let ctorType ← prettyPrintTerm ctor.type
match getStructureInfo? env v.name with match getStructureInfo? env v.name with
| some i => | some i =>
let fieldInfos ← i.fieldInfo.mapM FieldInfo.ofStructureFieldInfo if i.fieldNames.size - parents.size > 0 then
return StructureInfo.mk info fieldInfos parents ⟨ctor, ctorType⟩ return StructureInfo.mk info (←getFieldTypes ctor parents.size) parents ⟨ctor.name, ctorType⟩
else
return StructureInfo.mk info #[] parents ⟨ctor.name, ctorType⟩
| none => panic! s!"{v.name} is not a structure" | none => panic! s!"{v.name} is not a structure"
def ClassInfo.ofInductiveVal (v : InductiveVal) : MetaM ClassInfo := do def ClassInfo.ofInductiveVal (v : InductiveVal) : MetaM ClassInfo := do

View File

@ -421,7 +421,7 @@ main h2, main h3, main h4, main h5, main h6 {
border-radius: 5px; border-radius: 5px;
} }
.decl_args, .decl_type { .decl_args, .decl_type .decl_parent {
font-weight: normal; font-weight: normal;
} }
@ -430,7 +430,7 @@ main h2, main h3, main h4, main h5, main h6 {
white-space: nowrap; white-space: nowrap;
} }
.decl_kind, .decl_name { .decl_kind, .decl_name, .decl_extends {
font-weight: bold; font-weight: bold;
} }
@ -480,14 +480,7 @@ pre code { padding: 0 0; }
.structure_field { .structure_field {
display: block; display: block;
} margin-left: 2ex;
.structure_field:before {
content: '(';
color: gray;
}
.structure_field:after {
content: ')';
color: gray;
} }
.constructor { .constructor {