mirror of
https://github.com/golang/go
synced 2024-11-21 17:54:39 -07:00
exp/template: allow complex numbers, add 'with', 'define', and 'template' keywords.
Also simplify the handling of keywords. R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/4639096
This commit is contained in:
parent
db0e358022
commit
72efdea20e
@ -18,60 +18,71 @@ type item struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i item) String() string {
|
func (i item) String() string {
|
||||||
switch i.typ {
|
switch {
|
||||||
case itemEOF:
|
case i.typ == itemEOF:
|
||||||
return "EOF"
|
return "EOF"
|
||||||
case itemError:
|
case i.typ == itemError:
|
||||||
return i.val
|
return i.val
|
||||||
}
|
case i.typ > itemKeyword:
|
||||||
if len(i.val) > 10 {
|
return fmt.Sprintf("<%s>", i.val)
|
||||||
|
case len(i.val) > 10:
|
||||||
return fmt.Sprintf("%.10q...", i.val)
|
return fmt.Sprintf("%.10q...", i.val)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%q", i.val)
|
return fmt.Sprintf("%q", i.val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// itemType identifies the type of lex item.
|
// itemType identifies the type of lex items.
|
||||||
type itemType int
|
type itemType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
itemError itemType = iota // error occurred; value is text of error
|
itemError itemType = iota // error occurred; value is text of error
|
||||||
itemBool // boolean constant
|
itemBool // boolean constant
|
||||||
itemDot // the cursor, spelled '.'.
|
itemComplex // complex constant (1+2i); imaginary is just a number
|
||||||
itemEOF
|
itemEOF
|
||||||
itemElse // else keyword
|
|
||||||
itemEnd // end keyword
|
|
||||||
itemField // alphanumeric identifier, starting with '.', possibly chained ('.x.y')
|
itemField // alphanumeric identifier, starting with '.', possibly chained ('.x.y')
|
||||||
itemIdentifier // alphanumeric identifier
|
itemIdentifier // alphanumeric identifier
|
||||||
itemIf // if keyword
|
|
||||||
itemLeftMeta // left meta-string
|
itemLeftMeta // left meta-string
|
||||||
itemNumber // number
|
itemNumber // simple number, including imaginary
|
||||||
itemPipe // pipe symbol
|
itemPipe // pipe symbol
|
||||||
itemRange // range keyword
|
|
||||||
itemRawString // raw quoted string (includes quotes)
|
itemRawString // raw quoted string (includes quotes)
|
||||||
itemRightMeta // right meta-string
|
itemRightMeta // right meta-string
|
||||||
itemString // quoted string (includes quotes)
|
itemString // quoted string (includes quotes)
|
||||||
itemText // plain text
|
itemText // plain text
|
||||||
|
// Keywords appear after all the rest.
|
||||||
|
itemKeyword // used only to delimit the keywords
|
||||||
|
itemDot // the cursor, spelled '.'.
|
||||||
|
itemDefine // define keyword
|
||||||
|
itemElse // else keyword
|
||||||
|
itemEnd // end keyword
|
||||||
|
itemIf // if keyword
|
||||||
|
itemRange // range keyword
|
||||||
|
itemTemplate // template keyword
|
||||||
|
itemWith // with keyword
|
||||||
)
|
)
|
||||||
|
|
||||||
// Make the types prettyprint.
|
// Make the types prettyprint.
|
||||||
var itemName = map[itemType]string{
|
var itemName = map[itemType]string{
|
||||||
itemError: "error",
|
itemError: "error",
|
||||||
itemBool: "bool",
|
itemBool: "bool",
|
||||||
itemDot: ".",
|
itemComplex: "complex",
|
||||||
itemEOF: "EOF",
|
itemEOF: "EOF",
|
||||||
itemElse: "else",
|
|
||||||
itemEnd: "end",
|
|
||||||
itemField: "field",
|
itemField: "field",
|
||||||
itemIdentifier: "identifier",
|
itemIdentifier: "identifier",
|
||||||
itemIf: "if",
|
|
||||||
itemLeftMeta: "left meta",
|
itemLeftMeta: "left meta",
|
||||||
itemNumber: "number",
|
itemNumber: "number",
|
||||||
itemPipe: "pipe",
|
itemPipe: "pipe",
|
||||||
itemRange: "range",
|
|
||||||
itemRawString: "raw string",
|
itemRawString: "raw string",
|
||||||
itemRightMeta: "rightMeta",
|
itemRightMeta: "rightMeta",
|
||||||
itemString: "string",
|
itemString: "string",
|
||||||
itemText: "text",
|
// keywords
|
||||||
|
itemDot: ".",
|
||||||
|
itemDefine: "define",
|
||||||
|
itemElse: "else",
|
||||||
|
itemIf: "if",
|
||||||
|
itemEnd: "end",
|
||||||
|
itemRange: "range",
|
||||||
|
itemTemplate: "template",
|
||||||
|
itemWith: "with",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i itemType) String() string {
|
func (i itemType) String() string {
|
||||||
@ -83,11 +94,14 @@ func (i itemType) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var key = map[string]itemType{
|
var key = map[string]itemType{
|
||||||
".": itemDot,
|
".": itemDot,
|
||||||
"else": itemElse,
|
"define": itemDefine,
|
||||||
"end": itemEnd,
|
"else": itemElse,
|
||||||
"if": itemIf,
|
"end": itemEnd,
|
||||||
"range": itemRange,
|
"if": itemIf,
|
||||||
|
"range": itemRange,
|
||||||
|
"template": itemTemplate,
|
||||||
|
"with": itemWith,
|
||||||
}
|
}
|
||||||
|
|
||||||
const eof = -1
|
const eof = -1
|
||||||
@ -282,7 +296,7 @@ Loop:
|
|||||||
l.backup()
|
l.backup()
|
||||||
word := l.input[l.start:l.pos]
|
word := l.input[l.start:l.pos]
|
||||||
switch {
|
switch {
|
||||||
case key[word] != itemError:
|
case key[word] > itemKeyword:
|
||||||
l.emit(key[word])
|
l.emit(key[word])
|
||||||
case word[0] == '.':
|
case word[0] == '.':
|
||||||
l.emit(itemField)
|
l.emit(itemField)
|
||||||
@ -301,8 +315,23 @@ Loop:
|
|||||||
// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
|
// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
|
||||||
// and "089" - but when it's wrong the input is invalid and the parser (via
|
// and "089" - but when it's wrong the input is invalid and the parser (via
|
||||||
// strconv) will notice.
|
// strconv) will notice.
|
||||||
// TODO: without expressions you can do imaginary but not complex.
|
|
||||||
func lexNumber(l *lexer) stateFn {
|
func lexNumber(l *lexer) stateFn {
|
||||||
|
if !l.scanNumber() {
|
||||||
|
return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
|
||||||
|
}
|
||||||
|
if sign := l.peek(); sign == '+' || sign == '-' {
|
||||||
|
// Complex: 1+2i. No spaces, must end in 'i'.
|
||||||
|
if !l.scanNumber() || l.input[l.pos-1] != 'i' {
|
||||||
|
return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
|
||||||
|
}
|
||||||
|
l.emit(itemComplex)
|
||||||
|
} else {
|
||||||
|
l.emit(itemNumber)
|
||||||
|
}
|
||||||
|
return lexInsideAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *lexer) scanNumber() bool {
|
||||||
// Optional leading sign.
|
// Optional leading sign.
|
||||||
l.accept("+-")
|
l.accept("+-")
|
||||||
// Is it hex?
|
// Is it hex?
|
||||||
@ -323,10 +352,9 @@ func lexNumber(l *lexer) stateFn {
|
|||||||
// Next thing mustn't be alphanumeric.
|
// Next thing mustn't be alphanumeric.
|
||||||
if isAlphaNumeric(l.peek()) {
|
if isAlphaNumeric(l.peek()) {
|
||||||
l.next()
|
l.next()
|
||||||
return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
|
return false
|
||||||
}
|
}
|
||||||
l.emit(itemNumber)
|
return true
|
||||||
return lexInsideAction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// lexQuote scans a quoted string.
|
// lexQuote scans a quoted string.
|
||||||
|
@ -35,7 +35,7 @@ var lexTests = []lexTest{
|
|||||||
{"for", `{{for }}`, []item{tLeft, tFor, tRight, tEOF}},
|
{"for", `{{for }}`, []item{tLeft, tFor, tRight, tEOF}},
|
||||||
{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
|
{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
|
||||||
{"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
|
{"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
|
||||||
{"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4}}", []item{
|
{"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{
|
||||||
tLeft,
|
tLeft,
|
||||||
{itemNumber, "1"},
|
{itemNumber, "1"},
|
||||||
{itemNumber, "02"},
|
{itemNumber, "02"},
|
||||||
@ -43,6 +43,8 @@ var lexTests = []lexTest{
|
|||||||
{itemNumber, "-7.2i"},
|
{itemNumber, "-7.2i"},
|
||||||
{itemNumber, "1e3"},
|
{itemNumber, "1e3"},
|
||||||
{itemNumber, "+1.2e-4"},
|
{itemNumber, "+1.2e-4"},
|
||||||
|
{itemNumber, "4.2i"},
|
||||||
|
{itemComplex, "1+2i"},
|
||||||
tRight,
|
tRight,
|
||||||
tEOF,
|
tEOF,
|
||||||
}},
|
}},
|
||||||
@ -68,12 +70,13 @@ var lexTests = []lexTest{
|
|||||||
tRight,
|
tRight,
|
||||||
tEOF,
|
tEOF,
|
||||||
}},
|
}},
|
||||||
{"keywords", "{{range if else end}}", []item{
|
{"keywords", "{{range if else end with}}", []item{
|
||||||
tLeft,
|
tLeft,
|
||||||
{itemRange, "range"},
|
{itemRange, "range"},
|
||||||
{itemIf, "if"},
|
{itemIf, "if"},
|
||||||
{itemElse, "else"},
|
{itemElse, "else"},
|
||||||
{itemEnd, "end"},
|
{itemEnd, "end"},
|
||||||
|
{itemWith, "with"},
|
||||||
tRight,
|
tRight,
|
||||||
tEOF,
|
tEOF,
|
||||||
}},
|
}},
|
||||||
|
Loading…
Reference in New Issue
Block a user