Guidedog Manual 0.2.0
Language
On this page
Guidedog / Documentation 0.2.0

odindoc

Package odindoc reads Odin packages by static analysis, with Odin’s own parser (core:odin/parser), and writes the reStructuredText of the Guidedoc odin domain that documents them, as sphinx.ext.autodoc writes the Python domain’s: packages, procedures, procedure groups, types and their fields or enumerators, constants, variables, and foreign imports, each with its doc comment turned into reST.

It never runs the compiler: types are shown as written. A package’s files are read the way Odin builds them for every target at once: file-name suffixes (_windows, _linux_arm64) and #+build tags choose the targets a file builds for, and file-scope when ODIN_OS == ... blocks are evaluated when their conditions are that simple. A declaration made for every target the package builds for is documented once; one made for some targets only says which (see platform.odin).

It is a host library: it reads files through a File_Reader and allocates with the context allocator, freeing nothing itself, so a host runs it in an arena: a Project, the packages it loads, and the lines document returns live until the arena is freed.

Types

odindoc.Arch :: runtime.Odin_Arch_Type
odindoc.Archs :: runtime.Odin_Arch_Types
odindoc.Config :: struct
default_options: []Option
member_order: string

“source” (the default), “alphabetical”, “groupwise”.

odindoc.Decl :: struct

Decl is a package-level declaration. signature is one line, without attributes, as the odin domain’s directive takes it (“clone :: proc(s: string) -> string”).

name: string
kind: Kind
signature: string
attributes: []string

as written, in order: “@(require_results)”.

docs: string
private: Private
members: []Member
foreign_lib: string

the library of a foreign block it is declared in.

targets: Targets
availability: string

its targets for people, when not the package’s all.

variant: int

0; 1, 2, … for later declarations of the name that differ.

file: string

base name.

line: int
order: int

in the package: files by name, then position.

odindoc.File_Read :: struct
path: string
text: string
odindoc.File_Reader :: struct

File_Reader reads the files the analysis needs. procedure reads a file; list names the entries of a folder (folders end with “/”). Either may be nil, which uses the file system; a host confines both to its readable roots.

reserve, when set, is asked for the memory parsing a file may take (parse_bound) before the file is parsed; a file it refuses is not parsed (Package.too_large). Odin’s parser does not survive a failed allocation, so a host whose allocator can refuse reserves the bound ahead, and its allocator then serves the parse from what was reserved.

procedure: proc(user: rawptr, path: string) -> (string, bool)
list: proc(user: rawptr, dir: string) -> ([]string, bool)
reserve: proc(user: rawptr, bytes: int) -> bool
user: rawptr
odindoc.Import :: struct

Import is a package another package imports: the name it is used by in the source (its alias) and the id of the package it names.

alias: string
id: string
odindoc.Kind :: enum u8
Proc
Proc_Group
Struct
Union
Enum
Bit_Set
Bit_Field
Type
Const
Var
Foreign_Import
odindoc.Member :: struct
name: string
kind: Member_Kind
signature: string
docs: string

the comment above it and the one after it on its line.

odindoc.Member_Kind :: enum u8
Field

of a struct: “[using ]name: T[ tag]”.

Enumerator

of an enum: “Name[ = value]”.

Bit_Field

of a bit_field: “name: T | bits”.

odindoc.Message :: struct
severity: Severity
code: string
title: string
text: string
hint: string
odindoc.OS :: runtime.Odin_OS_Type
odindoc.Option :: struct
name: string
value: string
odindoc.Package :: struct

Package is an analysed package. doc is its package comment (from doc.odin first, then the first file by name that has one) with comment markers stripped; synopsis is that comment’s first sentence.

id: string
name: string
dir: string
doc: string
synopsis: string
decls: []Decl
imports: []Import
targets: Targets

every target some file of the package builds for.

platform: string

targets shown for people; “” when it builds for all.

files: []string

the package’s files that were read, sorted.

errors: int

syntax errors the parser reported.

too_deep: [dynamic]string

files nested too deeply to parse (nesting.odin).

too_large: [dynamic]string

files whose parse_bound the reader refused.

odindoc.Package_Ref :: struct
id: string
dir: string
odindoc.Private :: enum u8
Public
Package

@(private), or a #+private file.

File

@(private=”file”), or a #+private file file.

odindoc.Project :: struct
roots: []Root
reader: File_Reader
files: [dynamic]File_Read

every file read, for the host’s dependencies.

packages: map[string]^Package

loaded packages by id; nil for one that failed.

odindoc.Request :: struct
directive: string

“odin:autopackage”, “odin:autoproc”, …

argument: string
options: []Option
current: string

the reader’s current odin package, or “”.

odindoc.Result :: struct
lines: [dynamic]string
messages: [dynamic]Message
odindoc.Root :: struct

Root is a folder holding packages. Without a collection, a package’s id is its path relative to dir (“readers/sphinx”), and dir’s own package is named by dir’s base name; with one, ids are import paths in that collection (“core:fmt”).

dir: string
collection: string
odindoc.Severity :: enum u8
Note
Warning
Error
odindoc.Targets :: [OS]Archs

Targets is a set of (os, arch) pairs: per system, its architectures.

Procedures

odindoc.document :: proc(p: ^Project, config: ^Config, request: Request) -> Result

document runs one autodoc directive (request.directive, “odin:autopackage” and the others, with its argument and options over config’s defaults) and returns the reStructuredText lines it generates, with any messages: an unknown directive, option, package, or name is an Error message and no lines, never a panic. Packages are loaded through p as needed. The result lives in the context arena.

odindoc.init :: proc(p: ^Project, roots: []Root, reader := File_Reader{})

init starts a project over roots, reading through reader (the file system when it is zero). The project and everything it loads live in the context arena.

odindoc.list_packages :: proc(p: ^Project) -> []Package_Ref

list_packages lists every folder below the roots that holds a package, by id.

odindoc.load :: proc(p: ^Project, id: string) -> (^Package, bool)

load analyses the package with an id, once; later calls return the same package, which the project keeps. It is false when no root holds a package with that id.

odindoc.parse_bound :: proc(n: int) -> int

parse_bound is the memory parsing a file of n bytes may take.

Constants

odindoc.PARSE_BASE_BYTES :: 256 << 10

PARSE_BASE_BYTES is what the parser allocates for any file, and an arena block’s room.

odindoc.PARSE_BYTES_PER_BYTE :: 256

PARSE_BYTES_PER_BYTE bounds what Odin’s parser allocates, with the build tags read after it, for each byte of a file it parses. Its tree takes 20 to 30 bytes for each byte of ordinary code, and up to about 170 for the densest input measured: long operator chains, runs of semicolons, and one-character list items (parse_bounds_hold). The bound counts every growth of a list as a new allocation, as an arena that cannot grow it in place makes it.