trackler 2.0.6.36 → 2.0.6.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,238 @@
1
+ // Package forth implements a tiny subset of the Forth language.
2
+ package forth
3
+
4
+ import (
5
+ "errors"
6
+ "strconv"
7
+ "strings"
8
+ "unicode"
9
+ )
10
+
11
+ type operatorFn func(stack *[]int) error
12
+
13
+ type operatorId byte
14
+
15
+ const (
16
+ addOp operatorId = iota
17
+ subOp
18
+ mulOp
19
+ divOp
20
+ dropOp
21
+ dupOp
22
+ swapOp
23
+ overOp
24
+ constOp
25
+ userDefOp
26
+ endDefOp
27
+ )
28
+
29
+ type operatorTyp struct {
30
+ fn operatorFn
31
+ id operatorId
32
+ }
33
+
34
+ func Forth(input []string) (result []int, err error) {
35
+ if len(input) == 0 {
36
+ return []int{}, nil
37
+ }
38
+
39
+ // Allocate an initially empty stack, with arbitrary starting capacity of 8.
40
+ stack := make([]int, 0, 8)
41
+ // Allocate a map for user defined words.
42
+ userDefs := make(map[string][]operatorTyp, 8)
43
+ for _, phrase := range input {
44
+ // Parse one phrase of input, building up an operator list.
45
+ opList, err := parse(phrase, userDefs)
46
+ if err != nil {
47
+ return nil, err
48
+ }
49
+ // Perform any operators from that phrase, updating stack.
50
+ for _, opr := range opList {
51
+ err = opr.fn(&stack)
52
+ if err != nil {
53
+ return nil, err
54
+ }
55
+ }
56
+ }
57
+
58
+ return stack[:len(stack)], nil
59
+ }
60
+
61
+ // parse given phrase, returning an operator list, and updating
62
+ // a userDefs map for any user definifion of words in phrase.
63
+ func parse(phrase string, userDefs map[string][]operatorTyp) (oplist []operatorTyp, err error) {
64
+ words := strings.FieldsFunc(phrase,
65
+ func(r rune) bool {
66
+ return unicode.IsSpace(r) || unicode.IsControl(r)
67
+ })
68
+
69
+ // t is token index into words[]
70
+ for t := 0; t < len(words); t++ {
71
+ w := strings.ToUpper(words[t])
72
+ // Handle reference to user defined word.
73
+ if udef, ok := userDefs[w]; ok {
74
+ oplist = append(oplist, udef...)
75
+ } else if op, ok := builtinOps[w]; ok {
76
+ if op.id == userDefOp {
77
+ // Handle user defined word definition.
78
+ t++
79
+ if t >= len(words)-2 {
80
+ return nil, emptyUserDefErr
81
+ }
82
+ userword := strings.ToUpper(words[t])
83
+ if _, numerr := strconv.Atoi(userword); numerr == nil {
84
+ return nil, invalidUserDefErr
85
+ }
86
+ t++
87
+ var userops []operatorTyp
88
+ for t < len(words) {
89
+ oneOp, err := parse(words[t], userDefs)
90
+ if err != nil {
91
+ return nil, err
92
+ }
93
+ if oneOp[0].id == endDefOp {
94
+ break
95
+ }
96
+ userops = append(userops, oneOp...)
97
+ t++
98
+ }
99
+ if len(userops) == 0 {
100
+ return nil, emptyUserDefErr
101
+ } else {
102
+ userDefs[userword] = userops
103
+ }
104
+ } else {
105
+ // Normal builtin operator.
106
+ oplist = append(oplist, op)
107
+ }
108
+ } else {
109
+ // Handle constant literal.
110
+ var x int
111
+ x, err = strconv.Atoi(w)
112
+ if err != nil {
113
+ return nil, err
114
+ }
115
+ oplist = append(oplist,
116
+ operatorTyp{id: constOp,
117
+ fn: func(stack *[]int) error {
118
+ push(stack, x)
119
+ return nil
120
+ },
121
+ })
122
+ }
123
+ }
124
+ return oplist, nil
125
+ }
126
+
127
+ // builtinOps are the pre-defined operators to support.
128
+ var builtinOps = map[string]operatorTyp{
129
+ "+": {add, addOp},
130
+ "-": {subtract, subOp},
131
+ "*": {multiply, mulOp},
132
+ "/": {divide, divOp},
133
+ "DUP": {dup, dropOp},
134
+ "DROP": {drop, dupOp},
135
+ "SWAP": {swap, swapOp},
136
+ "OVER": {over, overOp},
137
+ ":": {nil, userDefOp},
138
+ ";": {nil, endDefOp},
139
+ }
140
+
141
+ func pop(stack *[]int) (v int, err error) {
142
+ slen := len(*stack)
143
+ if slen >= 1 {
144
+ v = (*stack)[slen-1]
145
+ *stack = (*stack)[:slen-1]
146
+ return v, nil
147
+ }
148
+ return 0, notEnoughOperands
149
+ }
150
+
151
+ func pop2(stack *[]int) (v1, v2 int, err error) {
152
+ v1, err = pop(stack)
153
+ if err != nil {
154
+ return 0, 0, err
155
+ }
156
+ v2, err = pop(stack)
157
+ return v1, v2, err
158
+ }
159
+
160
+ func push(stack *[]int, v int) {
161
+ *stack = append(*stack, v)
162
+ }
163
+
164
+ func binaryOp(stack *[]int, op func(a, b int) int) error {
165
+ v1, v2, err := pop2(stack)
166
+ if err != nil {
167
+ return err
168
+ }
169
+ push(stack, op(v2, v1))
170
+ return nil
171
+ }
172
+
173
+ func add(stack *[]int) (err error) {
174
+ return binaryOp(stack, func(a, b int) int { return a + b })
175
+ }
176
+
177
+ func subtract(stack *[]int) (err error) {
178
+ return binaryOp(stack, func(a, b int) int { return a - b })
179
+ }
180
+
181
+ func multiply(stack *[]int) error {
182
+ return binaryOp(stack, func(a, b int) int { return a * b })
183
+ }
184
+
185
+ func divide(stack *[]int) error {
186
+ v1, v2, err := pop2(stack)
187
+ if err != nil {
188
+ return err
189
+ }
190
+ if v1 == 0 {
191
+ return divideByZero
192
+ }
193
+ push(stack, v2/v1)
194
+ return nil
195
+ }
196
+
197
+ func dup(stack *[]int) error {
198
+ v1, err := pop(stack)
199
+ if err != nil {
200
+ return err
201
+ }
202
+ push(stack, v1)
203
+ push(stack, v1)
204
+ return nil
205
+ }
206
+
207
+ func drop(stack *[]int) error {
208
+ _, err := pop(stack)
209
+ return err
210
+ }
211
+
212
+ func over(stack *[]int) error {
213
+ v1, v2, err := pop2(stack)
214
+ if err != nil {
215
+ return err
216
+ }
217
+ push(stack, v2)
218
+ push(stack, v1)
219
+ push(stack, v2)
220
+ return nil
221
+ }
222
+
223
+ func swap(stack *[]int) error {
224
+ v1, v2, err := pop2(stack)
225
+ if err != nil {
226
+ return err
227
+ }
228
+ push(stack, v1)
229
+ push(stack, v2)
230
+ return nil
231
+ }
232
+
233
+ var notEnoughOperands error = errors.New("not enough operands")
234
+ var divideByZero error = errors.New("attempt to divide by zero")
235
+ var emptyUserDefErr error = errors.New("empty user definition")
236
+ var invalidUserDefErr error = errors.New("invalid user def word")
237
+
238
+ const testVersion = 1
@@ -0,0 +1,99 @@
1
+ // +build ignore
2
+
3
+ package main
4
+
5
+ import (
6
+ "log"
7
+ "text/template"
8
+
9
+ "../../gen"
10
+ )
11
+
12
+ func main() {
13
+ t, err := template.New("").Parse(tmpl)
14
+ if err != nil {
15
+ log.Fatal(err)
16
+ }
17
+ var j js
18
+ if err := gen.Gen("forth", &j, t); err != nil {
19
+ log.Fatal(err)
20
+ }
21
+ }
22
+
23
+ // The JSON structure we expect to be able to unmarshal into
24
+ type js struct {
25
+ ParsingAndNumbers section `json:"parsing and numbers"`
26
+ Addition section
27
+ Subtraction section
28
+ Multiplication section
29
+ Division section
30
+ CombinedArithmetic section `json:"combined arithmetic"`
31
+ Dup section
32
+ Drop section
33
+ Swap section
34
+ Over section
35
+ UserDefinedWords section `json:"user-defined words"`
36
+ }
37
+
38
+ // A grouped section of test cases.
39
+ type section struct {
40
+ Cases []struct {
41
+ Description string
42
+ Input []string
43
+ Expected []int
44
+ }
45
+ }
46
+
47
+ // template applied to above data structure generates the Go test cases
48
+ var tmpl = `package forth
49
+
50
+ // Source: {{.Ori}}
51
+ {{if .Commit}}// Commit: {{.Commit}}
52
+ {{end}}
53
+
54
+ {{/* template for repeated caseSection */}}
55
+
56
+ {{define "caseSection"}} = []testCase{
57
+ {{range $y, $c := .}}{
58
+ {{printf "%q" $c.Description}},
59
+ {{printf "%#v" $c.Input}},
60
+ {{printf "%#v" $c.Expected}},
61
+ },
62
+ {{end}}}{{end}}
63
+
64
+ var parsingGroup{{template "caseSection" .J.ParsingAndNumbers.Cases}}
65
+
66
+ var additionGroup{{template "caseSection" .J.Addition.Cases}}
67
+
68
+ var subtractionGroup{{template "caseSection" .J.Subtraction.Cases}}
69
+
70
+ var multiplicationGroup{{template "caseSection" .J.Multiplication.Cases}}
71
+
72
+ var divisionGroup{{template "caseSection" .J.Division.Cases}}
73
+
74
+ var arithmeticGroup{{template "caseSection" .J.CombinedArithmetic.Cases}}
75
+
76
+ var dupGroup{{template "caseSection" .J.Dup.Cases}}
77
+
78
+ var dropGroup{{template "caseSection" .J.Drop.Cases}}
79
+
80
+ var swapGroup{{template "caseSection" .J.Swap.Cases}}
81
+
82
+ var overGroup{{template "caseSection" .J.Over.Cases}}
83
+
84
+ var userdefinedGroup{{template "caseSection" .J.UserDefinedWords.Cases}}
85
+
86
+ var testSections = []testcaseSection{
87
+ {"parsing", parsingGroup},
88
+ {"addition(+)", additionGroup},
89
+ {"subtraction(-)", subtractionGroup},
90
+ {"multiplication(*)", multiplicationGroup},
91
+ {"division(/)", divisionGroup},
92
+ {"arithmetic", arithmeticGroup},
93
+ {"dup", dupGroup},
94
+ {"drop", dropGroup},
95
+ {"swap", swapGroup},
96
+ {"over", overGroup},
97
+ {"user-defined", userdefinedGroup},
98
+ }
99
+ `
@@ -0,0 +1,64 @@
1
+ package forth
2
+
3
+ // API:
4
+ // func Forth([]string) ([]int, error)
5
+ //
6
+
7
+ import (
8
+ "reflect"
9
+ "testing"
10
+ )
11
+
12
+ const targetTestVersion = 1
13
+
14
+ type testCase struct {
15
+ description string
16
+ input []string
17
+ expected []int // nil slice indicates error expected.
18
+ }
19
+
20
+ type testcaseSection struct {
21
+ name string
22
+ tests []testCase
23
+ }
24
+
25
+ func TestTestVersion(t *testing.T) {
26
+ if testVersion != targetTestVersion {
27
+ t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
28
+ }
29
+ }
30
+
31
+ func runTestCases(t *testing.T, sectionName string, testCases []testCase) {
32
+ for _, tc := range testCases {
33
+ description := sectionName + " - " + tc.description
34
+ if v, err := Forth(tc.input); err == nil {
35
+ var _ error = err
36
+ if tc.expected == nil {
37
+ t.Fatalf("%s\n\tForth(%#v) expected an error, got %v",
38
+ description, tc.input, v)
39
+ } else if !reflect.DeepEqual(v, tc.expected) {
40
+ t.Fatalf("%s\n\tForth(%#v) expected %v, got %v",
41
+ description, tc.input, tc.expected, v)
42
+ }
43
+ } else if tc.expected != nil {
44
+ t.Fatalf("%s\n\tForth(%#v) expected %v, got an error: %q",
45
+ description, tc.input, tc.expected, err)
46
+ }
47
+ }
48
+ }
49
+
50
+ func TestForth(t *testing.T) {
51
+ for _, testSection := range testSections {
52
+ runTestCases(t, testSection.name, testSection.tests)
53
+ }
54
+ }
55
+
56
+ func BenchmarkForth(b *testing.B) {
57
+ for i := 0; i < b.N; i++ {
58
+ for _, testSection := range testSections {
59
+ for _, test := range testSection.tests {
60
+ Forth(test.input)
61
+ }
62
+ }
63
+ }
64
+ }
@@ -7,44 +7,38 @@ public class PhoneNumber {
7
7
  }
8
8
 
9
9
  private String extractDigits(String dirtyNumber) {
10
- return dirtyNumber.replaceAll("[^\\d]", "");
10
+ StringBuilder stringBuilder = new StringBuilder();
11
+ for (char c : dirtyNumber.toCharArray()) {
12
+ if (c == ' ' || c == '.' || c == '(' || c == ')' || c == '-') {
13
+ // Remove spaces, dots, parentheses and hyphens
14
+ continue;
15
+ }
16
+ if (!Character.isDigit(c)) {
17
+ throw new IllegalArgumentException("Illegal character in phone number. "
18
+ + "Only digits, spaces, parentheses, hyphens or dots accepted.");
19
+ }
20
+ stringBuilder.append(c);
21
+ }
22
+ return stringBuilder.toString();
11
23
  }
12
24
 
13
25
  private String normalize(String number) {
14
- if(number.length() > 11 || number.length() < 10){
26
+ if (number.length() > 11 || number.length() < 10) {
15
27
  throw new IllegalArgumentException("Number must be 10 or 11 digits");
16
28
  }
17
29
 
18
- if(number.length() == 11){
19
- if(number.startsWith("1")){
30
+ if (number.length() == 11) {
31
+ if (number.startsWith("1")) {
20
32
  number = number.substring(1, number.length());
21
- }
22
- else{
33
+ } else {
23
34
  throw new IllegalArgumentException("Can only have 11 digits if number starts with '1'");
24
35
  }
25
- }
26
-
36
+ }
37
+
27
38
  return number;
28
39
  }
29
40
 
30
41
  public String getNumber() {
31
42
  return number;
32
43
  }
33
-
34
- public String getAreaCode() {
35
- return number.substring(0, 3);
36
- }
37
-
38
- public String getExchangeCode() {
39
- return number.substring(3, 6);
40
- }
41
-
42
- public String getSubscriberNumber() {
43
- return number.substring(6, 10);
44
- }
45
-
46
- public String pretty() {
47
- return "(" + getAreaCode() + ") " + getExchangeCode() + "-" + getSubscriberNumber();
48
- }
49
-
50
44
  }