File: parseNumber.go

package info (click to toggle)
hjson-go 4.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,384 kB
  • sloc: sh: 51; makefile: 4
file content (116 lines) | stat: -rw-r--r-- 2,063 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package hjson

import (
	"encoding/json"
	"errors"
	"math"
	"strconv"
)

type parseNumber struct {
	data []byte
	at   int  // The index of the current character
	ch   byte // The current character
}

func (p *parseNumber) next() bool {
	// get the next character.
	len := len(p.data)
	if p.at < len {
		p.ch = p.data[p.at]
		p.at++
		return true
	}
	if p.at == len {
		p.at++
		p.ch = 0
	}
	return false
}

func (p *parseNumber) peek(offs int) byte {
	pos := p.at + offs
	if pos >= 0 && pos < len(p.data) {
		return p.data[pos]
	}
	return 0
}

func startsWithNumber(text []byte) bool {
	if _, err := tryParseNumber(text, true, false); err == nil {
		return true
	}
	return false
}

func tryParseNumber(text []byte, stopAtNext, useJSONNumber bool) (interface{}, error) {
	// Parse a number value.

	p := parseNumber{
		data: text,
		at:   0,
		ch:   ' ',
	}
	leadingZeros := 0
	testLeading := true
	p.next()
	if p.ch == '-' {
		p.next()
	}
	for p.ch >= '0' && p.ch <= '9' {
		if testLeading {
			if p.ch == '0' {
				leadingZeros++
			} else {
				testLeading = false
			}
		}
		p.next()
	}
	if testLeading {
		leadingZeros--
	} // single 0 is allowed
	if p.ch == '.' {
		for p.next() && p.ch >= '0' && p.ch <= '9' {
		}
	}
	if p.ch == 'e' || p.ch == 'E' {
		p.next()
		if p.ch == '-' || p.ch == '+' {
			p.next()
		}
		for p.ch >= '0' && p.ch <= '9' {
			p.next()
		}
	}

	end := p.at

	// skip white/to (newline)
	for p.ch > 0 && p.ch <= ' ' {
		p.next()
	}

	if stopAtNext {
		// end scan if we find a punctuator character like ,}] or a comment
		if p.ch == ',' || p.ch == '}' || p.ch == ']' ||
			p.ch == '#' || p.ch == '/' && (p.peek(0) == '/' || p.peek(0) == '*') {
			p.ch = 0
		}
	}

	if p.ch > 0 || leadingZeros != 0 {
		return 0, errors.New("Invalid number")
	}
	if useJSONNumber {
		return json.Number(string(p.data[0 : end-1])), nil
	}
	number, err := strconv.ParseFloat(string(p.data[0:end-1]), 64)
	if err != nil {
		return 0, err
	}
	if math.IsInf(number, 0) || math.IsNaN(number) {
		return 0, errors.New("Invalid number")
	}
	return number, nil
}