Commit 0c3a43e7 authored by Rob Pike's avatar Rob Pike

error handling had a bug in execute: the error channel was being shared.

fix that and clean up state handling a little.

R=rsc
DELTA=44  (18 added, 8 deleted, 18 changed)
OCL=28359
CL=28359
parent 876c637e
...@@ -142,13 +142,13 @@ type repeatedElement struct { ...@@ -142,13 +142,13 @@ type repeatedElement struct {
// It is unchanged after parsing. // It is unchanged after parsing.
type Template struct { type Template struct {
fmap FormatterMap; // formatters for variables fmap FormatterMap; // formatters for variables
errorchan chan os.Error; // for reporting errors during parse and execute
// Used during parsing: // Used during parsing:
ldelim, rdelim []byte; // delimiters; default {} ldelim, rdelim []byte; // delimiters; default {}
buf []byte; // input text to process buf []byte; // input text to process
p int; // position in buf p int; // position in buf
linenum int; // position in input linenum int; // position in input
// Parsed state: errors chan os.Error; // for error reporting during parsing (only)
// Parsed results:
elems *vector.Vector; elems *vector.Vector;
} }
...@@ -159,6 +159,11 @@ type state struct { ...@@ -159,6 +159,11 @@ type state struct {
parent *state; // parent in hierarchy parent *state; // parent in hierarchy
data reflect.Value; // the driver data for this section etc. data reflect.Value; // the driver data for this section etc.
wr io.Write; // where to send output wr io.Write; // where to send output
errors chan os.Error; // for reporting errors during execute
}
func (parent *state) clone(data reflect.Value) *state {
return &state{parent, data, parent.wr, parent.errors}
} }
// New creates a new template with the specified formatter map (which // New creates a new template with the specified formatter map (which
...@@ -168,21 +173,25 @@ func New(fmap FormatterMap) *Template { ...@@ -168,21 +173,25 @@ func New(fmap FormatterMap) *Template {
t.fmap = fmap; t.fmap = fmap;
t.ldelim = lbrace; t.ldelim = lbrace;
t.rdelim = rbrace; t.rdelim = rbrace;
t.errorchan = make(chan os.Error); t.errors = make(chan os.Error);
t.elems = vector.New(0); t.elems = vector.New(0);
return t; return t;
} }
// Report error and stop parsing. The line number comes from the template state. // Generic error handler, called only from execError or parseError.
func (t *Template) parseError(err string, args ...) { func error(errors chan os.Error, line int, err string, args ...) {
t.errorchan <- ParseError{fmt.Sprintf("line %d: %s", t.linenum, fmt.Sprintf(err, args))}; errors <- ParseError{fmt.Sprintf("line %d: %s", line, fmt.Sprintf(err, args))};
sys.Goexit(); sys.Goexit();
} }
// Report error and stop executing. The line number must be provided explicitly. // Report error and stop executing. The line number must be provided explicitly.
func (t *Template) execError(line int, err string, args ...) { func (t *Template) execError(st *state, line int, err string, args ...) {
t.errorchan <- ParseError{fmt.Sprintf("line %d: %s", line, fmt.Sprintf(err, args))}; error(st.errors, line, err, args);
sys.Goexit(); }
// Report error and stop parsing. The line number comes from the template state.
func (t *Template) parseError(err string, args ...) {
error(t.errors, t.linenum, err, args)
} }
// -- Lexical analysis // -- Lexical analysis
...@@ -589,7 +598,7 @@ func (t *Template) varValue(v *variableElement, st *state) reflect.Value { ...@@ -589,7 +598,7 @@ func (t *Template) varValue(v *variableElement, st *state) reflect.Value {
field := st.findVar(v.name); field := st.findVar(v.name);
if field == nil { if field == nil {
if st.parent == nil { if st.parent == nil {
t.execError(t.linenum, "name not found: %s", v.name) t.execError(st, t.linenum, "name not found: %s", v.name)
} }
return t.varValue(v, st.parent); return t.varValue(v, st.parent);
} }
...@@ -613,7 +622,7 @@ func (t *Template) writeVariable(v *variableElement, st *state) { ...@@ -613,7 +622,7 @@ func (t *Template) writeVariable(v *variableElement, st *state) {
fn(st.wr, val, v.formatter); fn(st.wr, val, v.formatter);
return; return;
} }
t.execError(v.linenum, "missing formatter %s for variable %s", v.formatter, v.name) t.execError(st, v.linenum, "missing formatter %s for variable %s", v.formatter, v.name)
} }
// execute{|Element|Section|Repeated} are mutually recursive // execute{|Element|Section|Repeated} are mutually recursive
...@@ -640,7 +649,7 @@ func (t *Template) executeElement(i int, st *state) int { ...@@ -640,7 +649,7 @@ func (t *Template) executeElement(i int, st *state) int {
return elem.end; return elem.end;
} }
e := t.elems.At(i); e := t.elems.At(i);
t.execError(0, "internal error: bad directive in execute: %v %T\n", reflect.NewValue(e).Interface(), e); t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.NewValue(e).Interface(), e);
return 0 return 0
} }
...@@ -656,9 +665,9 @@ func (t *Template) executeSection(s *sectionElement, st *state) { ...@@ -656,9 +665,9 @@ func (t *Template) executeSection(s *sectionElement, st *state) {
// Find driver data for this section. It must be in the current struct. // Find driver data for this section. It must be in the current struct.
field := st.findVar(s.field); field := st.findVar(s.field);
if field == nil { if field == nil {
t.execError(s.linenum, ".section: cannot find field %s in %s", s.field, reflect.Indirect(st.data).Type()); t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, reflect.Indirect(st.data).Type());
} }
st = &state{st, field, st.wr}; st = st.clone(field);
start, end := s.start, s.or; start, end := s.start, s.or;
if !empty(field, true) { if !empty(field, true) {
// Execute the normal block. // Execute the normal block.
...@@ -682,19 +691,19 @@ func (t *Template) executeRepeated(r *repeatedElement, st *state) { ...@@ -682,19 +691,19 @@ func (t *Template) executeRepeated(r *repeatedElement, st *state) {
// Find driver data for this section. It must be in the current struct. // Find driver data for this section. It must be in the current struct.
field := st.findVar(r.field); field := st.findVar(r.field);
if field == nil { if field == nil {
t.execError(r.linenum, ".repeated: cannot find field %s in %s", r.field, reflect.Indirect(st.data).Type()); t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, reflect.Indirect(st.data).Type());
} }
field = reflect.Indirect(field); field = reflect.Indirect(field);
// Must be an array/slice // Must be an array/slice
if field != nil && field.Kind() != reflect.ArrayKind { if field != nil && field.Kind() != reflect.ArrayKind {
t.execError(r.linenum, ".repeated: %s has bad type %s", r.field, field.Type()); t.execError(st, r.linenum, ".repeated: %s has bad type %s", r.field, field.Type());
} }
if empty(field, true) { if empty(field, true) {
// Execute the .or block, once. If it's missing, do nothing. // Execute the .or block, once. If it's missing, do nothing.
start, end := r.or, r.end; start, end := r.or, r.end;
if start >= 0 { if start >= 0 {
newst := &state{st, field, st.wr}; newst := st.clone(field);
for i := start; i < end; { for i := start; i < end; {
i = t.executeElement(i, newst) i = t.executeElement(i, newst)
} }
...@@ -712,7 +721,7 @@ func (t *Template) executeRepeated(r *repeatedElement, st *state) { ...@@ -712,7 +721,7 @@ func (t *Template) executeRepeated(r *repeatedElement, st *state) {
if field != nil { if field != nil {
array := field.(reflect.ArrayValue); array := field.(reflect.ArrayValue);
for j := 0; j < array.Len(); j++ { for j := 0; j < array.Len(); j++ {
newst := &state{st, array.Elem(j), st.wr}; newst := st.clone(array.Elem(j));
for i := start; i < end; { for i := start; i < end; {
i = t.executeElement(i, newst) i = t.executeElement(i, newst)
} }
...@@ -753,9 +762,9 @@ func (t *Template) Parse(s string) os.Error { ...@@ -753,9 +762,9 @@ func (t *Template) Parse(s string) os.Error {
t.linenum = 0; t.linenum = 0;
go func() { go func() {
t.parse(); t.parse();
t.errorchan <- nil; // clean return; t.errors <- nil; // clean return;
}(); }();
return <-t.errorchan; return <-t.errors;
} }
// Execute applies a parsed template to the specified data object, // Execute applies a parsed template to the specified data object,
...@@ -763,12 +772,13 @@ func (t *Template) Parse(s string) os.Error { ...@@ -763,12 +772,13 @@ func (t *Template) Parse(s string) os.Error {
func (t *Template) Execute(data interface{}, wr io.Write) os.Error { func (t *Template) Execute(data interface{}, wr io.Write) os.Error {
// Extract the driver data. // Extract the driver data.
val := reflect.NewValue(data); val := reflect.NewValue(data);
errors := make(chan os.Error);
go func() { go func() {
t.p = 0; t.p = 0;
t.execute(0, t.elems.Len(), &state{nil, val, wr}); t.execute(0, t.elems.Len(), &state{nil, val, wr, errors});
t.errorchan <- nil; // clean return; errors <- nil; // clean return;
}(); }();
return <-t.errorchan; return <-errors;
} }
// SetDelims sets the left and right delimiters for operations in the // SetDelims sets the left and right delimiters for operations in the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment