-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalgo_base.typ
133 lines (118 loc) · 3.98 KB
/
algo_base.typ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#import "types.typ": *
#import "style_base.typ": eval_line
#let _ex_format(name, fn) = makeup => {
let format = if t_check(TMakeup, makeup) {
makeup.format
} else {
makeup
}
if name == none or name in format {
fn(format)
} else {
panic("formatter '" + repr(format) + "' is missing '" + name + "' field")
}
}
#let block(body, indent, makeup) = {
(body: body, indent: indent, makeup: makeup)
}
#let _choose_formatter(format, default, name) = {
if name in format {
format.at(name)
} else {
default
}
}
#let _line_format(line_part, format: none) = {
if type(line_part) == "array" {
line_part.flatten().map(part => if type(part) == "function" { part(format) } else { part })
} else if type(line_part) == "function" {
line_part(format)
} else {
line_part
}
}
#let constant(name) = _ex_format(name, format => format.at(name))
#let expr(name, ..values, format: none, format_name: "format") = _ex_format(name, _format => {
let values = values.pos()
let default_format = if format != none { format } else { (..v)=>v.pos().flatten().map(v => if t_check(TNumber, v) { str(v) } else {v}) }
let formatter = _choose_formatter(_format.at(name), default_format, format_name)
formatter(..values.map(_line_format.with(format: _format)))
})
#let control_flow(name, ..values, format_head: none, format_tail: none, format_head_name: "format_head", format_tail_name: "format_tail", indent: 1em, indent_name: "indent", with_body: d=>d) = (..body) => {
(
expr(name, ..values, format: format_head, format_name: format_head_name),
block(with_body(body.pos()), _ex_format(name, format => _choose_formatter(format.at(name), indent, indent_name)), _ex_format(name, format => if "makeup" in format.at(name) {format.at(name).makeup})),
expr(name, ..values, format: format_tail, format_name: format_tail_name),
)
}
#let _mk_array(e) = if type(e) == "array" {e} else {(e,)}
#let append_content(before: (), after: ()) = content => {
_mk_array(before) + _mk_array(content) + _mk_array(after)
}
#let algo_body(makeup) = (..content) => {
t_assert(TMakeup, makeup)
let resolve_groups(elem, start_idx) = {
let i = start_idx
let items = ()
while i < elem.len() {
let e = elem.at(i)
if t_check(TGroupStart, e) {
let (inner, next_idx) = resolve_groups(elem, i+1)
i = next_idx
let start_style = if "start_style" in e { e.start_style } else { v=>v }
let end_style = if "end_style" in e { e.end_style } else { v=>v }
let use_start = if "use_start" in e { e.use_start } else { v=>v }
let use_end = if "use_end" in e { e.use_end } else { v=>v }
let item = if use_start and use_end {
(e.group)(inner, start_style, end_style)
} else if use_start {
(e.group)(inner, start_style)
} else if use_end {
(e.group)(inner, end_style)
} else {
(e.group)(inner)
}
items.push(item)
} else if t_check(TGroupEnd, e) {
return (items.join(""), i+1)
} else {
items.push(e)
i = i+1
}
}
(items.join(""), i)
}
let indent(lines, level, makeup) = {
for l in lines {
if t_check(TBody, l) {
let m = (l.makeup)(makeup)
indent(l.body, level + (l.indent)(makeup), if m != none { m } else { makeup })
} else if type(l) == "array" {
indent(l, level, makeup)
} else {
let elem = l(makeup)
if elem == none { continue }
let elem = if type(elem) == "array" {
resolve_groups(eval_line(elem, makeup), 0).at(0)
} else {
elem
}
(h(level) + elem,)
}
}
}
indent(content.pos(), 0em, makeup)
}
#let algo(name, makeup) = (..content) => {
t_assert(TMakeup, makeup)
figure(align(
start,
[
#box(line(length: 100%))
#name
#box(line(length: 100%))
#enum(..algo_body(makeup)(..content), numbering: "1:")
#box(line(length: 100%))
]
))
}