Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
+3
-3
@@ -188,12 +188,12 @@ func ibanValid(s string) bool {
|
|||||||
return rem == 1
|
return rem == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRegistryShapes pins the builtin contract compileOps relies on: every entry
|
// TestRegistryShapes pins the builtin contract compileFormat relies on: every entry
|
||||||
// supplies prep, and args parsed at compile only behind a check.
|
// supplies prep, and args parsed at compile only behind a check.
|
||||||
func TestRegistryShapes(t *testing.T) {
|
func TestRegistryShapes(t *testing.T) {
|
||||||
for name, b := range builtins {
|
for name, b := range builtins {
|
||||||
if b.prep == nil {
|
if b.prep == nil {
|
||||||
t.Errorf("builtin %q has no prep: compileOps would call a nil func", name)
|
t.Errorf("builtin %q has no prep: compileFormat would call a nil func", name)
|
||||||
}
|
}
|
||||||
if b.arity != 0 && b.checkArgs == nil {
|
if b.arity != 0 && b.checkArgs == nil {
|
||||||
t.Errorf("builtin %q parses args in prep with no check", name)
|
t.Errorf("builtin %q parses args in prep with no check", name)
|
||||||
@@ -203,7 +203,7 @@ func TestRegistryShapes(t *testing.T) {
|
|||||||
|
|
||||||
// TestArgGuardsPanic pins the guards that report a builtin arg its check should
|
// TestArgGuardsPanic pins the guards that report a builtin arg its check should
|
||||||
// have rejected. No data reaches them — checkFunc runs a builtin's check before
|
// have rejected. No data reaches them — checkFunc runs a builtin's check before
|
||||||
// compileOps ever calls prep — so they are exercised directly.
|
// compileFormat ever calls prep — so they are exercised directly.
|
||||||
func TestArgGuardsPanic(t *testing.T) {
|
func TestArgGuardsPanic(t *testing.T) {
|
||||||
for name, call := range map[string]func(){
|
for name, call := range map[string]func(){
|
||||||
"atoi on an unvalidated arg": func() { atoi("nope") },
|
"atoi on an unvalidated arg": func() { atoi("nope") },
|
||||||
|
|||||||
@@ -441,19 +441,9 @@ func (c *formatOps) field(tok formatToken, refs map[string]refBinding) {
|
|||||||
c.ops = append(c.ops, op{formatToken: tok, arms: arms})
|
c.ops = append(c.ops, op{formatToken: tok, arms: arms})
|
||||||
}
|
}
|
||||||
|
|
||||||
// compileFormat compiles a format into ops, and applies the fences that need the
|
// compileFormat compiles a parsed format. Call checkTokens first: it is what proves
|
||||||
// compiled reads.
|
|
||||||
func compileFormat(toks []formatToken, refs map[string]refBinding) (formatOps, error) {
|
|
||||||
c := compileOps(toks, refs)
|
|
||||||
if err := checkNoOverlap(c); err != nil {
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
return c, checkNoRepeatedRead(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// compileOps compiles a parsed format. Call checkTokens first: it is what proves
|
|
||||||
// every token valid.
|
// every token valid.
|
||||||
func compileOps(toks []formatToken, refs map[string]refBinding) formatOps {
|
func compileFormat(toks []formatToken, refs map[string]refBinding) formatOps {
|
||||||
var c formatOps
|
var c formatOps
|
||||||
for _, tok := range toks {
|
for _, tok := range toks {
|
||||||
switch tok.kind {
|
switch tok.kind {
|
||||||
|
|||||||
+14
-1
@@ -15,10 +15,23 @@ func heldCheck(path string, n node) error {
|
|||||||
if !ok || len(t.compiled.held) == 0 {
|
if !ok || len(t.compiled.held) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if err := checkHeld(t); err != nil {
|
||||||
|
return fmt.Errorf("%s: %w", t.site.label(path), err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkHeld(t *template) error {
|
||||||
|
if err := checkNoOverlap(t.compiled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := checkNoRepeatedRead(t.compiled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
readers := pathHeadReaders(t.compiled)
|
readers := pathHeadReaders(t.compiled)
|
||||||
for _, name := range heldNames(t) {
|
for _, name := range heldNames(t) {
|
||||||
if err := checkNameHeld(t, name, readers); err != nil {
|
if err := checkNameHeld(t, name, readers); err != nil {
|
||||||
return fmt.Errorf("%s: %w", path, err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -73,6 +73,14 @@ func (s tableSite) isCell() bool {
|
|||||||
return s.table != nil && s.row != formatRow
|
return s.table != nil && s.row != formatRow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// label names the template at path in an error, a cell by its line in the rows file.
|
||||||
|
func (s tableSite) label(path string) string {
|
||||||
|
if s.isCell() {
|
||||||
|
return fmt.Sprintf("%s, line %d", path, s.row+2)
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
// templateLink is what a template resolves to in the assembled tree.
|
// templateLink is what a template resolves to in the assembled tree.
|
||||||
type templateLink struct {
|
type templateLink struct {
|
||||||
refs map[string]refBinding // each reference the format reads -> what it resolves to
|
refs map[string]refBinding // each reference the format reads -> what it resolves to
|
||||||
|
|||||||
+2
-9
@@ -81,18 +81,11 @@ func linkRefs(root map[string]node) error {
|
|||||||
// linkTemplate resolves t's references in category, "" for an inline template, and
|
// linkTemplate resolves t's references in category, "" for an inline template, and
|
||||||
// compiles its format against them.
|
// compiles its format against them.
|
||||||
func linkTemplate(folder []string, path, category string, t *template, root map[string]node) error {
|
func linkTemplate(folder []string, path, category string, t *template, root map[string]node) error {
|
||||||
if t.site.isCell() {
|
link, err := t.resolveLink(folder, t.site.label(path), category, root)
|
||||||
path = fmt.Sprintf("%s, line %d", path, t.site.row+2)
|
|
||||||
}
|
|
||||||
link, err := t.resolveLink(folder, path, category, root)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
compiled, err := compileFormat(t.tokens, link.refs)
|
t.link, t.compiled = link, compileFormat(t.tokens, link.refs)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s: %w", path, err)
|
|
||||||
}
|
|
||||||
t.link, t.compiled = link, compiled
|
|
||||||
compileArms(t)
|
compileArms(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user