Skip to content
This repository was archived by the owner on Jul 31, 2025. It is now read-only.

Commit d474896

Browse files
committed
Adding number helper
1 parent 69ec501 commit d474896

19 files changed

+282
-147
lines changed

aws/session/internal/ini/ini.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ini
22

33
import (
4+
"io"
45
"os"
56
)
67

@@ -13,13 +14,13 @@ func OpenFile(path string) (Sections, error) {
1314
}
1415
defer f.Close()
1516

16-
return ParseFile(f)
17+
return Parse(f)
1718
}
1819

19-
// ParseFile will parse the given file using the shared config
20+
// Parse will parse the given file using the shared config
2021
// visitor.
21-
func ParseFile(f *os.File) (Sections, error) {
22-
tree, err := Parse(f)
22+
func Parse(f io.Reader) (Sections, error) {
23+
tree, err := ParseAST(f)
2324
if err != nil {
2425
return nil, err
2526
}

aws/session/internal/ini/ini_parser.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ func (s *skipper) Continue() {
110110
s.prevTok = nil
111111
}
112112

113-
// Parse will parse input from an io.Reader using
113+
// ParseAST will parse input from an io.Reader using
114114
// an LL(1) parser.
115-
func Parse(r io.Reader) ([]AST, error) {
115+
func ParseAST(r io.Reader) ([]AST, error) {
116116
lexer := iniLexer{}
117117
tokens, err := lexer.Tokenize(r)
118118
if err != nil {

aws/session/internal/ini/ini_parser_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ region = us-west-2
232232
}
233233

234234
for i, c := range cases {
235-
stack, err := Parse(c.r)
235+
stack, err := ParseAST(c.r)
236236

237237
if e, a := c.expectedError, err != nil; e != a {
238238
t.Errorf("%d: expected %t, but received %t with error %v", i+1, e, a, err)

aws/session/internal/ini/literal_tokens.go

Lines changed: 24 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -26,62 +26,50 @@ func isBoolValue(b []byte) bool {
2626
return false
2727
}
2828

29+
// isNumberValue will return whether not the leading characters in
30+
// a byte slice is a number. A number is delimited by whitespace or
31+
// the newline token.
32+
//
33+
// A number is defined to be in a binary, octal, decimal (int | float), hex format,
34+
// or in scientific notation.
2935
func isNumberValue(b []byte) bool {
30-
foundDecimal := false
31-
foundBinary := false
32-
foundOctal := false
33-
foundHex := false
34-
foundExponent := false
35-
foundNegative := false
3636
negativeIndex := 0
37+
helper := numberHelper{}
3738

3839
for i := 0; i < len(b); i++ {
3940
negativeIndex++
4041

4142
switch b[i] {
4243
case '-':
43-
if foundNegative || negativeIndex != 1 {
44+
if helper.IsNegative() || negativeIndex != 1 {
4445
return false
4546
}
46-
foundNegative = true
47-
continue
48-
case '.':
49-
if foundDecimal ||
50-
foundBinary ||
51-
foundOctal ||
52-
foundHex ||
53-
foundExponent {
54-
return false
55-
}
56-
foundDecimal = true
47+
helper.Determine(b[i])
5748
continue
5849
case 'e', 'E':
59-
if foundDecimal ||
60-
foundBinary ||
61-
foundOctal ||
62-
foundHex ||
63-
foundExponent {
50+
if helper.Exists() {
6451
return false
6552
}
6653

67-
foundExponent = true
68-
foundNegative = false
6954
negativeIndex = 0
55+
helper.Determine(b[i])
7056
continue
71-
case 'b', 'o', 'x':
57+
case 'b':
58+
if helper.hex {
59+
break
60+
}
61+
fallthrough
62+
case 'o', 'x':
7263
if i == 0 {
7364
return false
7465
}
75-
if foundDecimal ||
76-
foundBinary ||
77-
foundOctal ||
78-
foundHex ||
79-
foundExponent {
66+
67+
fallthrough
68+
case '.':
69+
if helper.Exists() {
8070
return false
8171
}
82-
foundBinary = foundBinary || b[i] == 'b'
83-
foundOctal = foundOctal || b[i] == 'o'
84-
foundHex = foundHex || b[i] == 'x'
72+
helper.Determine(b[i])
8573
continue
8674
}
8775

@@ -90,49 +78,14 @@ func isNumberValue(b []byte) bool {
9078
return true
9179
}
9280

93-
switch {
94-
case foundBinary:
95-
if b[i] != '0' && b[i] != '1' {
96-
return false
97-
}
98-
case foundOctal:
99-
switch b[i] {
100-
case '0', '1', '2', '3', '4', '5', '6', '7':
101-
default:
102-
return false
103-
}
104-
case foundHex:
105-
if !isHexByte(b[i]) {
106-
return false
107-
}
108-
case foundDecimal:
109-
if !isDigit(b[i]) {
110-
return false
111-
}
112-
case foundExponent:
113-
if !isDigit(b[i]) {
114-
return false
115-
}
116-
case foundNegative:
117-
if !isDigit(b[i]) {
118-
return false
119-
}
120-
default:
121-
if !isDigit(b[i]) {
122-
return false
123-
}
81+
if !helper.CorrectByte(b[i]) {
82+
return false
12483
}
125-
12684
}
12785

12886
return true
12987
}
13088

131-
// isDigit will return whether or not something is an integer
132-
func isDigit(b byte) bool {
133-
return b >= '0' && b <= '9'
134-
}
135-
13689
func isValid(b byte) bool {
13790
return utf8.ValidRune(rune(b)) && b != '=' && b != '[' && b != ']' && b != ' ' && b != '\n'
13891
}
@@ -286,7 +239,3 @@ func (token literalToken) String() string {
286239

287240
return "invalid token"
288241
}
289-
290-
func hasExponent(v string) bool {
291-
return strings.Contains(v, "e") || strings.Contains(v, "E")
292-
}

aws/session/internal/ini/literal_tokens_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ func TestIsNumberValue(t *testing.T) {
3030
[]byte("1E234"),
3131
true,
3232
},
33+
{
34+
[]byte("1ea4"),
35+
false,
36+
},
3337
{
3438
[]byte("1-23"),
3539
false,

aws/session/internal/ini/newline_token.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package ini
22

3+
// newlineToken acts as a delimeter in ini is will be used
4+
// primarily to handle nesting expressions.
35
type newlineToken struct {
46
emptyToken
57
raw string
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package ini
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
7+
"github.com/aws/aws-sdk-go/aws/awserr"
8+
)
9+
10+
// numberHelper is used to dictate what format a number is in
11+
// and what to do for negative values. Since -1e-4 is a valid
12+
// number, we cannot just simply check for duplicate negatives.
13+
type numberHelper struct {
14+
binary bool
15+
octal bool
16+
decimal bool
17+
hex bool
18+
19+
exponent bool
20+
negative bool
21+
}
22+
23+
func (b numberHelper) Exists() bool {
24+
return b.decimal || b.binary || b.octal || b.hex || b.exponent
25+
}
26+
27+
func (b numberHelper) IsNegative() bool {
28+
return b.negative
29+
}
30+
31+
func (b *numberHelper) Determine(c byte) error {
32+
switch c {
33+
case 'b':
34+
b.binary = true
35+
case 'o':
36+
b.octal = true
37+
case 'x':
38+
b.hex = true
39+
case 'e', 'E':
40+
b.exponent = true
41+
b.negative = false
42+
case '-':
43+
b.negative = true
44+
case '.':
45+
b.decimal = true
46+
default:
47+
return awserr.New(ErrCodeParseError, fmt.Sprintf("invalid number character: %v", string(c)), nil)
48+
}
49+
50+
return nil
51+
}
52+
53+
func (b numberHelper) CorrectByte(c byte) bool {
54+
switch {
55+
case b.binary:
56+
if !isBinaryByte(c) {
57+
return false
58+
}
59+
case b.octal:
60+
if !isOctalByte(c) {
61+
return false
62+
}
63+
case b.hex:
64+
if !isHexByte(c) {
65+
return false
66+
}
67+
case b.decimal:
68+
if !isDigit(c) {
69+
return false
70+
}
71+
case b.exponent:
72+
if !isDigit(c) {
73+
return false
74+
}
75+
case b.negative:
76+
if !isDigit(c) {
77+
return false
78+
}
79+
default:
80+
if !isDigit(c) {
81+
return false
82+
}
83+
}
84+
85+
return true
86+
}
87+
88+
func (b numberHelper) Base() int {
89+
switch {
90+
case b.binary:
91+
return 2
92+
case b.octal:
93+
return 8
94+
case b.hex:
95+
return 16
96+
default:
97+
return 10
98+
}
99+
}
100+
101+
func (b numberHelper) String() string {
102+
buf := bytes.Buffer{}
103+
i := 0
104+
105+
if b.binary {
106+
i++
107+
buf.WriteString(string(i+'0') + ": binary format\n")
108+
}
109+
110+
if b.octal {
111+
i++
112+
buf.WriteString(string(i+'0') + ": octal format\n")
113+
}
114+
115+
if b.hex {
116+
i++
117+
buf.WriteString(string(i+'0') + ": hex format\n")
118+
}
119+
120+
if b.exponent {
121+
i++
122+
buf.WriteString(string(i+'0') + ": exponent format\n")
123+
}
124+
125+
if b.negative {
126+
i++
127+
buf.WriteString(string(i+'0') + ": negative format\n")
128+
}
129+
130+
return buf.String()
131+
}

aws/session/internal/ini/op_tokens.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const (
2424
opTypeEqual
2525
)
2626

27+
// opToken is an operation token that signifies an expression.
2728
type opToken struct {
2829
emptyToken
2930

aws/session/internal/ini/parse_stack.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,34 @@ import (
55
"fmt"
66
)
77

8+
// ParseStack is a stack that contains a container, the stack portion,
9+
// and the list which is the list of ASTs that have been successfully
10+
// parsed.
811
type ParseStack struct {
912
container []AST
1013
list []AST
1114
}
1215

16+
// Pop will return and truncate the last container element.
1317
func (s *ParseStack) Pop() AST {
1418
temp := s.container[0]
1519
s.container = s.container[1:]
1620
return temp
1721
}
1822

23+
// Push will add the new AST to the container
1924
func (s *ParseStack) Push(ast AST) {
2025
s.container = append(s.container, ast)
2126
}
2227

28+
// Epsilon will push Start{} back to the stack and append the
29+
// AST to the list of completed statements
2330
func (s *ParseStack) Epsilon(ast AST) {
2431
s.Push(Start{})
2532
s.list = append(s.list, ast)
2633
}
2734

35+
// Len will return the length of the container
2836
func (s *ParseStack) Len() int {
2937
return len(s.container)
3038
}

aws/session/internal/ini/sep_tokens.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const (
2525
sepTypeCloseBrace
2626
)
2727

28+
// sepToken is a separator token which represents the concept of
29+
// scoping in ini files.
2830
type sepToken struct {
2931
emptyToken
3032

0 commit comments

Comments
 (0)