mirror of
https://github.com/golang/go.git
synced 2024-09-30 14:57:10 +00:00
remove goroutines from template parsing.
fix up one usage to take advantage. R=rsc CC=go-dev http://go/go-review/1018023
This commit is contained in:
parent
f32cde88b6
commit
236a9de93f
@ -12,7 +12,6 @@ package rpc
|
|||||||
import (
|
import (
|
||||||
"fmt";
|
"fmt";
|
||||||
"http";
|
"http";
|
||||||
"os";
|
|
||||||
"sort";
|
"sort";
|
||||||
"template";
|
"template";
|
||||||
)
|
)
|
||||||
@ -37,7 +36,7 @@ const debugText = `<html>
|
|||||||
</body>
|
</body>
|
||||||
</html>`
|
</html>`
|
||||||
|
|
||||||
var debug *template.Template
|
var debug = template.MustParse(debugText, nil)
|
||||||
|
|
||||||
type debugMethod struct {
|
type debugMethod struct {
|
||||||
m *methodType;
|
m *methodType;
|
||||||
@ -76,14 +75,6 @@ func (m methodArray) Swap(i, j int) {
|
|||||||
|
|
||||||
// Runs at /debug/rpc
|
// Runs at /debug/rpc
|
||||||
func debugHTTP(c *http.Conn, req *http.Request) {
|
func debugHTTP(c *http.Conn, req *http.Request) {
|
||||||
var err os.Error;
|
|
||||||
if debug == nil {
|
|
||||||
debug, err = template.Parse(debugText, nil);
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(c, "rpc can't create debug HTML template:", err.String());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Build a sorted version of the data.
|
// Build a sorted version of the data.
|
||||||
var services = make(serviceArray, len(server.serviceMap));
|
var services = make(serviceArray, len(server.serviceMap));
|
||||||
i := 0;
|
i := 0;
|
||||||
@ -100,7 +91,7 @@ func debugHTTP(c *http.Conn, req *http.Request) {
|
|||||||
}
|
}
|
||||||
server.Unlock();
|
server.Unlock();
|
||||||
sort.Sort(services);
|
sort.Sort(services);
|
||||||
err = debug.Execute(services, c);
|
err := debug.Execute(services, c);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(c, "rpc: error executing template:", err.String());
|
fmt.Fprintln(c, "rpc: error executing template:", err.String());
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ type Template struct {
|
|||||||
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
|
||||||
errors chan os.Error; // for error reporting during parsing (only)
|
error os.Error; // error during parsing (only)
|
||||||
// Parsed results:
|
// Parsed results:
|
||||||
elems *vector.Vector;
|
elems *vector.Vector;
|
||||||
}
|
}
|
||||||
@ -177,25 +177,20 @@ func New(fmap FormatterMap) *Template {
|
|||||||
t.fmap = fmap;
|
t.fmap = fmap;
|
||||||
t.ldelim = lbrace;
|
t.ldelim = lbrace;
|
||||||
t.rdelim = rbrace;
|
t.rdelim = rbrace;
|
||||||
t.errors = make(chan os.Error);
|
|
||||||
t.elems = vector.New(0);
|
t.elems = vector.New(0);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic error handler, called only from execError or parseError.
|
// Report error and stop executing. The line number must be provided explicitly.
|
||||||
func error(errors chan os.Error, line int, err string, args ...) {
|
func (t *Template) execError(st *state, line int, err string, args ...) {
|
||||||
errors <- &Error{line, fmt.Sprintf(err, args)};
|
st.errors <- &Error{line, fmt.Sprintf(err, args)};
|
||||||
runtime.Goexit();
|
runtime.Goexit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report error and stop executing. The line number must be provided explicitly.
|
// Report error, save in Template to terminate parsing.
|
||||||
func (t *Template) execError(st *state, line int, err string, args ...) {
|
// The line number comes from the template state.
|
||||||
error(st.errors, line, err, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Report error and stop parsing. The line number comes from the template state.
|
|
||||||
func (t *Template) parseError(err string, args ...) {
|
func (t *Template) parseError(err string, args ...) {
|
||||||
error(t.errors, t.linenum, err, args)
|
t.error = &Error{t.linenum, fmt.Sprintf(err, args)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Lexical analysis
|
// -- Lexical analysis
|
||||||
@ -261,7 +256,8 @@ Loop:
|
|||||||
i = j - 1;
|
i = j - 1;
|
||||||
case equal(t.buf, i, t.rdelim):
|
case equal(t.buf, i, t.rdelim):
|
||||||
if !sawLeft {
|
if !sawLeft {
|
||||||
t.parseError("unmatched closing delimiter")
|
t.parseError("unmatched closing delimiter");
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
sawLeft = false;
|
sawLeft = false;
|
||||||
i += len(t.rdelim);
|
i += len(t.rdelim);
|
||||||
@ -271,7 +267,8 @@ Loop:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sawLeft {
|
if sawLeft {
|
||||||
t.parseError("unmatched opening delimiter")
|
t.parseError("unmatched opening delimiter");
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
item := t.buf[start:i];
|
item := t.buf[start:i];
|
||||||
if special && trim_white {
|
if special && trim_white {
|
||||||
@ -322,13 +319,15 @@ func (t *Template) analyze(item []byte) (tok int, w []string) {
|
|||||||
// item is known to be non-empty
|
// item is known to be non-empty
|
||||||
if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
|
if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
|
||||||
tok = tokText;
|
tok = tokText;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
|
if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
|
||||||
t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
|
t.parseError("internal error: unmatched opening delimiter"); // lexing should prevent this
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
|
if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
|
||||||
t.parseError("empty directive")
|
t.parseError("empty directive");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// Comment
|
// Comment
|
||||||
if item[len(t.ldelim)] == '#' {
|
if item[len(t.ldelim)] == '#' {
|
||||||
@ -338,7 +337,8 @@ func (t *Template) analyze(item []byte) (tok int, w []string) {
|
|||||||
// Split into words
|
// Split into words
|
||||||
w = words(item[len(t.ldelim): len(item)-len(t.rdelim)]); // drop final delimiter
|
w = words(item[len(t.ldelim): len(item)-len(t.rdelim)]); // drop final delimiter
|
||||||
if len(w) == 0 {
|
if len(w) == 0 {
|
||||||
t.parseError("empty directive")
|
t.parseError("empty directive");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if len(w) == 1 && w[0][0] != '.' {
|
if len(w) == 1 && w[0][0] != '.' {
|
||||||
tok = tokVariable;
|
tok = tokVariable;
|
||||||
@ -356,19 +356,22 @@ func (t *Template) analyze(item []byte) (tok int, w []string) {
|
|||||||
return;
|
return;
|
||||||
case ".section":
|
case ".section":
|
||||||
if len(w) != 2 {
|
if len(w) != 2 {
|
||||||
t.parseError("incorrect fields for .section: %s", item)
|
t.parseError("incorrect fields for .section: %s", item);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
tok = tokSection;
|
tok = tokSection;
|
||||||
return;
|
return;
|
||||||
case ".repeated":
|
case ".repeated":
|
||||||
if len(w) != 3 || w[1] != "section" {
|
if len(w) != 3 || w[1] != "section" {
|
||||||
t.parseError("incorrect fields for .repeated: %s", item)
|
t.parseError("incorrect fields for .repeated: %s", item);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
tok = tokRepeated;
|
tok = tokRepeated;
|
||||||
return;
|
return;
|
||||||
case ".alternates":
|
case ".alternates":
|
||||||
if len(w) != 2 || w[1] != "with" {
|
if len(w) != 2 || w[1] != "with" {
|
||||||
t.parseError("incorrect fields for .alternates: %s", item)
|
t.parseError("incorrect fields for .alternates: %s", item);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
tok = tokAlternates;
|
tok = tokAlternates;
|
||||||
return;
|
return;
|
||||||
@ -413,6 +416,9 @@ func (t *Template) newVariable(name_formatter string) (v *variableElement) {
|
|||||||
// Otherwise return its details.
|
// Otherwise return its details.
|
||||||
func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
|
func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
|
||||||
tok, w = t.analyze(item);
|
tok, w = t.analyze(item);
|
||||||
|
if t.error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
done = true; // assume for simplicity
|
done = true; // assume for simplicity
|
||||||
switch tok {
|
switch tok {
|
||||||
case tokComment:
|
case tokComment:
|
||||||
@ -432,6 +438,7 @@ func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
|
|||||||
t.elems.Push(&literalElement{tab});
|
t.elems.Push(&literalElement{tab});
|
||||||
default:
|
default:
|
||||||
t.parseError("internal error: unknown literal: %s", w[0]);
|
t.parseError("internal error: unknown literal: %s", w[0]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case tokVariable:
|
case tokVariable:
|
||||||
@ -454,12 +461,19 @@ func (t *Template) parseRepeated(words []string) *repeatedElement {
|
|||||||
r.altstart = -1;
|
r.altstart = -1;
|
||||||
r.altend = -1;
|
r.altend = -1;
|
||||||
Loop:
|
Loop:
|
||||||
for {
|
for t.error == nil {
|
||||||
item := t.nextItem();
|
item := t.nextItem();
|
||||||
|
if t.error != nil {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if len(item) == 0 {
|
if len(item) == 0 {
|
||||||
t.parseError("missing .end for .repeated section")
|
t.parseError("missing .end for .repeated section");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
done, tok, w := t.parseSimple(item);
|
done, tok, w := t.parseSimple(item);
|
||||||
|
if t.error != nil {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if done {
|
if done {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -469,6 +483,7 @@ Loop:
|
|||||||
case tokOr:
|
case tokOr:
|
||||||
if r.or >= 0 {
|
if r.or >= 0 {
|
||||||
t.parseError("extra .or in .repeated section");
|
t.parseError("extra .or in .repeated section");
|
||||||
|
break Loop;
|
||||||
}
|
}
|
||||||
r.altend = t.elems.Len();
|
r.altend = t.elems.Len();
|
||||||
r.or = t.elems.Len();
|
r.or = t.elems.Len();
|
||||||
@ -479,15 +494,21 @@ Loop:
|
|||||||
case tokAlternates:
|
case tokAlternates:
|
||||||
if r.altstart >= 0 {
|
if r.altstart >= 0 {
|
||||||
t.parseError("extra .alternates in .repeated section");
|
t.parseError("extra .alternates in .repeated section");
|
||||||
|
break Loop;
|
||||||
}
|
}
|
||||||
if r.or >= 0 {
|
if r.or >= 0 {
|
||||||
t.parseError(".alternates inside .or block in .repeated section");
|
t.parseError(".alternates inside .or block in .repeated section");
|
||||||
|
break Loop;
|
||||||
}
|
}
|
||||||
r.altstart = t.elems.Len();
|
r.altstart = t.elems.Len();
|
||||||
default:
|
default:
|
||||||
t.parseError("internal error: unknown repeated section item: %s", item);
|
t.parseError("internal error: unknown repeated section item: %s", item);
|
||||||
|
break Loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if t.error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if r.altend < 0 {
|
if r.altend < 0 {
|
||||||
r.altend = t.elems.Len()
|
r.altend = t.elems.Len()
|
||||||
}
|
}
|
||||||
@ -504,12 +525,19 @@ func (t *Template) parseSection(words []string) *sectionElement {
|
|||||||
s.start = t.elems.Len();
|
s.start = t.elems.Len();
|
||||||
s.or = -1;
|
s.or = -1;
|
||||||
Loop:
|
Loop:
|
||||||
for {
|
for t.error == nil {
|
||||||
item := t.nextItem();
|
item := t.nextItem();
|
||||||
|
if t.error != nil {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if len(item) == 0 {
|
if len(item) == 0 {
|
||||||
t.parseError("missing .end for .section")
|
t.parseError("missing .end for .section");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
done, tok, w := t.parseSimple(item);
|
done, tok, w := t.parseSimple(item);
|
||||||
|
if t.error != nil {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if done {
|
if done {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -519,6 +547,7 @@ Loop:
|
|||||||
case tokOr:
|
case tokOr:
|
||||||
if s.or >= 0 {
|
if s.or >= 0 {
|
||||||
t.parseError("extra .or in .section");
|
t.parseError("extra .or in .section");
|
||||||
|
break Loop;
|
||||||
}
|
}
|
||||||
s.or = t.elems.Len();
|
s.or = t.elems.Len();
|
||||||
case tokSection:
|
case tokSection:
|
||||||
@ -531,13 +560,19 @@ Loop:
|
|||||||
t.parseError("internal error: unknown section item: %s", item);
|
t.parseError("internal error: unknown section item: %s", item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if t.error != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
s.end = t.elems.Len();
|
s.end = t.elems.Len();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Template) parse() {
|
func (t *Template) parse() {
|
||||||
for {
|
for t.error == nil {
|
||||||
item := t.nextItem();
|
item := t.nextItem();
|
||||||
|
if t.error != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
if len(item) == 0 {
|
if len(item) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -816,11 +851,8 @@ func (t *Template) Parse(s string) os.Error {
|
|||||||
t.buf = strings.Bytes(s);
|
t.buf = strings.Bytes(s);
|
||||||
t.p = 0;
|
t.p = 0;
|
||||||
t.linenum = 0;
|
t.linenum = 0;
|
||||||
go func() {
|
t.parse();
|
||||||
t.parse();
|
return t.error;
|
||||||
t.errors <- nil; // clean return;
|
|
||||||
}();
|
|
||||||
return <-t.errors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute applies a parsed template to the specified data object,
|
// Execute applies a parsed template to the specified data object,
|
||||||
@ -855,5 +887,17 @@ func (t *Template) SetDelims(left, right string) {
|
|||||||
func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
|
func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
|
||||||
t = New(fmap);
|
t = New(fmap);
|
||||||
err = t.Parse(s);
|
err = t.Parse(s);
|
||||||
|
if err != nil {
|
||||||
|
t = nil
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustParse is like Parse but panics if the template cannot be parsed.
|
||||||
|
func MustParse(s string, fmap FormatterMap) *Template {
|
||||||
|
t , err := Parse(s, fmap);
|
||||||
|
if err != nil {
|
||||||
|
panic("template parse error: ", err);
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user