@@ 71,24 71,32 @@ func Load(path string) (Block, error) {
func Read(r io.Reader) (Block, error) {
scanner := bufio.NewScanner(r)
- block, closingBrace, err := readBlock(scanner)
+ dec := decoder{scanner: scanner}
+ block, closingBrace, err := dec.readBlock()
if err != nil {
return nil, err
} else if closingBrace {
- return nil, fmt.Errorf("unexpected '}'")
+ return nil, fmt.Errorf("line %v: unexpected '}'", dec.lineno)
}
return block, scanner.Err()
}
+type decoder struct {
+ scanner *bufio.Scanner
+ lineno int
+}
+
// readBlock reads a block. closingBrace is true if parsing stopped on '}'
// (otherwise, it stopped on Scanner.Scan).
-func readBlock(scanner *bufio.Scanner) (block Block, closingBrace bool, err error) {
- for scanner.Scan() {
- l := scanner.Text()
+func (dec *decoder) readBlock() (block Block, closingBrace bool, err error) {
+ for dec.scanner.Scan() {
+ dec.lineno++
+
+ l := dec.scanner.Text()
words, err := splitWords(l)
if err != nil {
- return nil, false, fmt.Errorf("failed to parse configuration file: %v", err)
+ return nil, false, fmt.Errorf("line %v: %v", dec.lineno, err)
} else if len(words) == 0 {
continue
}
@@ 108,11 116,12 @@ func readBlock(scanner *bufio.Scanner) (block Block, closingBrace bool, err erro
name, params = words[0], words[1:]
}
- childBlock, childClosingBrace, err := readBlock(scanner)
+ startLineno := dec.lineno
+ childBlock, childClosingBrace, err := dec.readBlock()
if err != nil {
return nil, false, err
} else if !childClosingBrace {
- return nil, false, io.ErrUnexpectedEOF
+ return nil, false, fmt.Errorf("line %v: unterminated block", startLineno)
}
// Allows callers to tell apart "no block" and "empty block"