text string
}
-func newNumber(text string, isComplex bool) (*numberNode, os.Error) {
+func newNumber(text string, typ itemType) (*numberNode, os.Error) {
n := &numberNode{nodeType: nodeNumber, text: text}
- if isComplex {
+ switch typ {
+ case itemChar:
+ if len(text) < 3 {
+ return nil, fmt.Errorf("illegal character constant: %s", text)
+ }
+ rune, _, tail, err := strconv.UnquoteChar(text[1:len(text)-1], text[0])
+ if err != nil {
+ return nil, err
+ }
+ if len(tail) > 0 {
+ return nil, fmt.Errorf("extra bytes in character constant: %s", text)
+ }
+ n.int64 = int64(rune)
+ n.isInt = true
+ n.uint64 = uint64(rune)
+ n.isUint = true
+ n.float64 = float64(rune) // odd but those are the rules.
+ n.isFloat = true
+ return n, nil
+ case itemComplex:
// fmt.Sscan can parse the pair, so let it do the work.
if _, err := fmt.Sscan(text, &n.complex128); err != nil {
return nil, err
t.errorf("missing value for %s", context)
}
return
- case itemBool, itemComplex, itemDot, itemField, itemIdentifier, itemVariable, itemNumber, itemRawString, itemString:
+ case itemBool, itemChar, itemComplex, itemDot, itemField, itemIdentifier, itemVariable, itemNumber, itemRawString, itemString:
t.backup()
pipe.append(t.command())
default:
cmd.append(newField(token.val))
case itemBool:
cmd.append(newBool(token.val == "true"))
- case itemComplex, itemNumber:
- number, err := newNumber(token.val, token.typ == itemComplex)
+ case itemChar, itemComplex, itemNumber:
+ number, err := newNumber(token.val, token.typ)
if err != nil {
t.error(err)
}
{"0", true, true, true, false, 0, 0, 0, 0},
{"-0", true, true, true, false, 0, 0, 0, 0}, // check that -0 is a uint.
{"73", true, true, true, false, 73, 73, 73, 0},
+ {"073", true, true, true, false, 073, 073, 073, 0},
+ {"0x73", true, true, true, false, 0x73, 0x73, 0x73, 0},
{"-73", true, false, true, false, -73, 0, -73, 0},
{"+73", true, false, true, false, 73, 0, 73, 0},
{"100", true, true, true, false, 100, 100, 100, 0},
{"-1e19", false, false, true, false, 0, 0, -1e19, 0},
{"4i", false, false, false, true, 0, 0, 0, 4i},
{"-1.2+4.2i", false, false, false, true, 0, 0, 0, -1.2 + 4.2i},
+ {"073i", false, false, false, true, 0, 0, 0, 73i}, // not octal!
// complex with 0 imaginary are float (and maybe integer)
{"0i", true, true, true, true, 0, 0, 0, 0},
{"-1.2+0i", false, false, true, true, 0, 0, -1.2, -1.2},
{"0123", true, true, true, false, 0123, 0123, 0123, 0},
{"-0x0", true, true, true, false, 0, 0, 0, 0},
{"0xdeadbeef", true, true, true, false, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0},
+ // character constants
+ {`'a'`, true, true, true, false, 'a', 'a', 'a', 0},
+ {`'\n'`, true, true, true, false, '\n', '\n', '\n', 0},
+ {`'\\'`, true, true, true, false, '\\', '\\', '\\', 0},
+ {`'\''`, true, true, true, false, '\'', '\'', '\'', 0},
+ {`'\xFF'`, true, true, true, false, 0xFF, 0xFF, 0xFF, 0},
+ {`'パ'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
+ {`'\u30d1'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
+ {`'\U000030d1'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
// some broken syntax
{text: "+-2"},
{text: "0x123."},
{text: "1e."},
{text: "0xi."},
{text: "1+2."},
+ {text: "'x"},
+ {text: "'xx'"},
}
func TestNumberParse(t *testing.T) {
// If fmt.Sscan thinks it's complex, it's complex. We can't trust the output
// because imaginary comes out as a number.
var c complex128
- _, err := fmt.Sscan(test.text, &c)
- n, err := newNumber(test.text, err == nil)
+ typ := itemNumber
+ if test.text[0] == '\'' {
+ typ = itemChar
+ } else {
+ _, err := fmt.Sscan(test.text, &c)
+ if err == nil {
+ typ = itemComplex
+ }
+ }
+ n, err := newNumber(test.text, typ)
ok := test.isInt || test.isUint || test.isFloat || test.isComplex
if ok && err != nil {
- t.Errorf("unexpected error for %q", test.text)
+ t.Errorf("unexpected error for %q: %s", test.text, err)
continue
}
if !ok && err == nil {
continue
}
if !ok {
+ if *debug {
+ fmt.Printf("%s\n\t%s\n", test.text, err)
+ }
continue
}
if n.isComplex != test.isComplex {
`[({{range [(command: [F=[X]]) (command: [F=[M]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
{"range []int", "{{range .SI}}{{.}}{{end}}", noError,
`[({{range [(command: [F=[SI]])]}} [(action: [(command: [{{<.>}}])])])]`},
- {"constants", "{{range .SI 1 -3.2i true false }}{{end}}", noError,
- `[({{range [(command: [F=[SI] N=1 N=-3.2i B=true B=false])]}} [])]`},
+ {"constants", "{{range .SI 1 -3.2i true false 'a'}}{{end}}", noError,
+ `[({{range [(command: [F=[SI] N=1 N=-3.2i B=true B=false N='a'])]}} [])]`},
{"template", "{{template `x`}}", noError,
"[{{template S=`x`}}]"},
{"template", "{{template `x` .Y}}", noError,