Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
+2
-2
@@ -40,8 +40,8 @@ type Generator struct {
|
|||||||
structs map[reflect.Type]structResult
|
structs map[reflect.Type]structResult
|
||||||
}
|
}
|
||||||
|
|
||||||
// generatorState is one generator's state across its renders: the seeded rng plus the {seq()}
|
// generatorState is one generator's draw state, kept across its renders: the seeded rng plus
|
||||||
// counters.
|
// the {seq()} counters.
|
||||||
type generatorState struct {
|
type generatorState struct {
|
||||||
*rand.Rand
|
*rand.Rand
|
||||||
counters map[string]uint64
|
counters map[string]uint64
|
||||||
|
|||||||
@@ -13,17 +13,17 @@ type scanUnit struct {
|
|||||||
body string
|
body string
|
||||||
}
|
}
|
||||||
|
|
||||||
// eachToken scans a format string once and calls fn for each unit, the single
|
// eachScanUnit scans a format string once and calls fn for each unit, the single
|
||||||
// source of truth for how braces are read: "{{" and "}}" are literal braces, a "{"
|
// source of truth for how braces are read: "{{" and "}}" are literal braces, a "{"
|
||||||
// opens a token that must reach its "}", and a lone "}" is an error.
|
// opens a token that must reach its "}", and a lone "}" is an error.
|
||||||
func eachToken(format string, fn func(scanUnit) error) error {
|
func eachScanUnit(format string, fn func(scanUnit) error) error {
|
||||||
rs := []rune(format)
|
rs := []rune(format)
|
||||||
for i := 0; i < len(rs); i++ {
|
for i := 0; i < len(rs); i++ {
|
||||||
var t scanUnit
|
var u scanUnit
|
||||||
switch c := rs[i]; c {
|
switch c := rs[i]; c {
|
||||||
case '{':
|
case '{':
|
||||||
if i+1 < len(rs) && rs[i+1] == '{' {
|
if i+1 < len(rs) && rs[i+1] == '{' {
|
||||||
t.char = '{'
|
u.char = '{'
|
||||||
i++
|
i++
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -37,19 +37,19 @@ func eachToken(format string, fn func(scanUnit) error) error {
|
|||||||
if end >= len(rs) {
|
if end >= len(rs) {
|
||||||
return fmt.Errorf("unterminated '{' in %q", format)
|
return fmt.Errorf("unterminated '{' in %q", format)
|
||||||
}
|
}
|
||||||
t.isToken, t.body = true, string(rs[i+1:end])
|
u.isToken, u.body = true, string(rs[i+1:end])
|
||||||
i = end
|
i = end
|
||||||
case '}':
|
case '}':
|
||||||
if i+1 < len(rs) && rs[i+1] == '}' {
|
if i+1 < len(rs) && rs[i+1] == '}' {
|
||||||
t.char = '}'
|
u.char = '}'
|
||||||
i++
|
i++
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return fmt.Errorf("lone '}' in %q; a literal brace is written }}", format)
|
return fmt.Errorf("lone '}' in %q; a literal brace is written }}", format)
|
||||||
default:
|
default:
|
||||||
t.char = c
|
u.char = c
|
||||||
}
|
}
|
||||||
if err := fn(t); err != nil {
|
if err := fn(u); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,21 +85,21 @@ func parseFormat(format string) ([]formatToken, error) {
|
|||||||
lit.Reset()
|
lit.Reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := eachToken(format, func(t scanUnit) error {
|
err := eachScanUnit(format, func(u scanUnit) error {
|
||||||
if !t.isToken {
|
if !u.isToken {
|
||||||
lit.WriteRune(t.char)
|
lit.WriteRune(u.char)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
flush()
|
flush()
|
||||||
if indexOutside(t.body, '(') < 0 {
|
if indexOutside(u.body, '(') < 0 {
|
||||||
toks = append(toks, formatToken{kind: nameRead, body: t.body, names: splitOutside(t.body, '|')})
|
toks = append(toks, formatToken{kind: nameRead, body: u.body, names: splitOutside(u.body, '|')})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
name, args, ok := funcCall(t.body)
|
name, args, ok := funcCall(u.body)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("malformed function token {%s}", t.body)
|
return fmt.Errorf("malformed function token {%s}", u.body)
|
||||||
}
|
}
|
||||||
toks = append(toks, formatToken{kind: builtinCall, body: t.body, fn: name, args: args, names: builtinOperands(name, args)})
|
toks = append(toks, formatToken{kind: builtinCall, body: u.body, fn: name, args: args, names: builtinOperands(name, args)})
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -110,12 +110,12 @@ func parseFormat(format string) ([]formatToken, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// builtin is a format-string function invoked as {name(args)}. It receives the
|
// builtin is a format-string function invoked as {name(args)}. It receives the
|
||||||
// generatorState (its rng, and the {seq()} counters), the output emitted so far in the
|
// generatorState, the output emitted so far in the current expansion (for derivations
|
||||||
// current expansion (for derivations such as a checksum over preceding digits), and
|
// such as a checksum over preceding digits), and the values of the operands it named
|
||||||
// the values of the operands it named (calc and the transforms name them). All must
|
// (calc and the transforms name them). All must stay pure over (rng, emitted, args) so
|
||||||
// stay pure over (rng, emitted, args) so seeded output is reproducible; seq advances
|
// seeded output is reproducible; seq advances per-generator counter state, which is
|
||||||
// per-generator counter state, which is itself deterministic. arity is the exact arg
|
// itself deterministic. arity is the exact arg count, or -1 for variadic (then
|
||||||
// count, or -1 for variadic (then checkArgs does all the validation).
|
// checkArgs does all the validation).
|
||||||
type builtin struct {
|
type builtin struct {
|
||||||
arity int
|
arity int
|
||||||
// prep parses validated args once, at compile time, into the closure expand calls.
|
// prep parses validated args once, at compile time, into the closure expand calls.
|
||||||
|
|||||||
Reference in New Issue
Block a user