-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add some parser bits from text/template
- Loading branch information
Showing
2 changed files
with
108 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,120 @@ | ||
package jigo | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
// Tree is the representation of a single parsed template. | ||
type Tree struct { | ||
Name string // name of the template represented by the tree. | ||
ParseName string // name of the top-level template during parsing, for error messages. | ||
Root *ListNode // top-level root of the tree. | ||
text string // text parsed to create the template (or its parent) | ||
// Parsing only; cleared after parse. | ||
funcs []map[string]interface{} | ||
lex *lexer | ||
funcs []map[string]interface{} | ||
lex *lexer | ||
// FIXME: how much do we need? | ||
token [3]item // three-token lookahead for parser. | ||
peekCount int | ||
vars []string // variables defined at the moment. | ||
} | ||
|
||
// next returns the next token. | ||
func (t *Tree) next() item { | ||
if t.peekCount > 0 { | ||
t.peekCount-- | ||
} else { | ||
t.token[0] = t.lex.nextItem() | ||
} | ||
return t.token[t.peekCount] | ||
} | ||
|
||
// backup backs the input stream up one token. | ||
func (t *Tree) backup() { | ||
t.peekCount++ | ||
} | ||
|
||
// backup2 backs the input stream up two tokens. | ||
// The zeroth token is already there. | ||
func (t *Tree) backup2(t1 item) { | ||
t.token[1] = t1 | ||
t.peekCount = 2 | ||
} | ||
|
||
// backup3 backs the input stream up three tokens | ||
// The zeroth token is already there. | ||
func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back. | ||
t.token[1] = t1 | ||
t.token[2] = t2 | ||
t.peekCount = 3 | ||
} | ||
|
||
// peek returns but does not consume the next token. | ||
func (t *Tree) peek() item { | ||
if t.peekCount > 0 { | ||
return t.token[t.peekCount-1] | ||
} | ||
t.peekCount = 1 | ||
t.token[0] = t.lex.nextItem() | ||
return t.token[0] | ||
} | ||
|
||
// nextNonSpace returns the next non-space token. | ||
func (t *Tree) nextNonSpace() (token item) { | ||
for { | ||
token = t.next() | ||
if token.typ != tokenWhitespace { | ||
break | ||
} | ||
} | ||
return token | ||
} | ||
|
||
// peekNonSpace returns but does not consume the next non-space token. | ||
func (t *Tree) peekNonSpace() (token item) { | ||
for { | ||
token = t.next() | ||
if token.typ != tokenWhitespace { | ||
break | ||
} | ||
} | ||
t.backup() | ||
return token | ||
} | ||
|
||
// Parsing. | ||
|
||
// New allocates a new parse tree with the given name. | ||
func New(name string, funcs ...map[string]interface{}) *Tree { | ||
return &Tree{ | ||
Name: name, | ||
funcs: funcs, | ||
} | ||
} | ||
|
||
// ErrorContext returns a textual representation of the location of the node in the input text. | ||
func (t *Tree) ErrorContext(n Node) (location, context string) { | ||
pos := int(n.Position()) | ||
text := t.text[:pos] | ||
byteNum := strings.LastIndex(text, "\n") | ||
if byteNum == -1 { | ||
byteNum = pos // On first line. | ||
} else { | ||
byteNum++ // After the newline. | ||
byteNum = pos - byteNum | ||
} | ||
lineNum := 1 + strings.Count(text, "\n") | ||
context = n.String() | ||
if len(context) > 20 { | ||
context = fmt.Sprintf("%.20s...", context) | ||
} | ||
return fmt.Sprintf("%s:%d:%d", t.ParseName, lineNum, byteNum), context | ||
} | ||
|
||
// errorf formats the error and terminates processing. | ||
func (t *Tree) errorf(format string, args ...interface{}) { | ||
t.Root = nil | ||
format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format) | ||
panic(fmt.Errorf(format, args...)) | ||
} |