gofront 1.7.0 → 1.9.0

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.
Files changed (194) hide show
  1. package/README.md +14 -14
  2. package/package.json +10 -38
  3. package/src/backend/js/expressions.js +2060 -389
  4. package/src/backend/js/index.js +586 -174
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +936 -1644
  7. package/src/backend/js/statements.js +1349 -132
  8. package/src/backend/js/stdlib/index.js +51 -94
  9. package/src/backend/js/templ.js +67 -118
  10. package/src/backend/js/type-info.js +436 -0
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +80 -0
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +753 -872
  15. package/src/backend/wasm/emit-builtins.js +914 -237
  16. package/src/backend/wasm/emit-exprs.js +1456 -195
  17. package/src/backend/wasm/emit-maps.js +78 -380
  18. package/src/backend/wasm/emit-stmts.js +1659 -214
  19. package/src/backend/wasm/emit.js +614 -88
  20. package/src/backend/wasm/encode.js +43 -13
  21. package/src/backend/wasm/globals.js +491 -0
  22. package/src/backend/wasm/glue.js +2 -4
  23. package/src/backend/wasm/index.js +406 -3195
  24. package/src/backend/wasm/method-expr.js +392 -0
  25. package/src/backend/wasm/module-emitter.js +1615 -0
  26. package/src/backend/wasm/monomorph.js +164 -9
  27. package/src/backend/wasm/natives.js +596 -0
  28. package/src/backend/wasm/prescan.js +249 -0
  29. package/src/backend/wasm/prune-funcs.js +89 -0
  30. package/src/backend/wasm/stdlib/index.js +2 -37
  31. package/src/backend/wasm/stdlib/simd.js +293 -28
  32. package/src/backend/wasm/types.js +260 -27
  33. package/src/backend/wasm/variadic.js +93 -0
  34. package/src/backend/wasm/wat.js +47 -20
  35. package/src/{cli-core.js → cli/cli-core.js} +241 -11
  36. package/src/{test-runner.js → cli/test-runner.js} +188 -122
  37. package/src/{vendor.js → cli/vendor.js} +3 -4
  38. package/src/compiler.js +202 -386
  39. package/src/index.js +15 -169
  40. package/src/{lexer.js → lexer/lexer.js} +203 -62
  41. package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
  42. package/src/{tokens.js → lexer/tokens.js} +2 -0
  43. package/src/link/sourcemap.js +97 -0
  44. package/src/link/stdlib.js +737 -0
  45. package/src/link/type-names.js +148 -0
  46. package/src/link/wasm.js +318 -0
  47. package/src/lower/bounds.js +547 -0
  48. package/src/lower/boxing.js +1 -1
  49. package/src/lower/captures.js +267 -64
  50. package/src/lower/embedding.js +32 -3
  51. package/src/lower/errors-as.js +196 -0
  52. package/src/lower/fmt-formatters.js +905 -0
  53. package/src/lower/functions.js +2 -0
  54. package/src/lower/gen-types.js +274 -0
  55. package/src/lower/index.js +33 -19
  56. package/src/lower/json-codecs.js +1379 -0
  57. package/src/lower/ownership.js +47 -8
  58. package/src/lower/range.js +86 -1
  59. package/src/lower/reachability.js +150 -0
  60. package/src/lower/walk.js +12 -0
  61. package/src/parser/declarations.js +83 -15
  62. package/src/parser/expressions.js +110 -18
  63. package/src/parser/index.js +2 -1
  64. package/src/parser/statements.js +38 -22
  65. package/src/{templ-parser.js → parser/templ.js} +179 -17
  66. package/src/parser/types.js +70 -9
  67. package/src/resolver.js +21 -1
  68. package/src/typechecker/assignability.js +291 -19
  69. package/src/typechecker/const-fold.js +399 -0
  70. package/src/typechecker/constants.js +282 -0
  71. package/src/typechecker/expressions.js +1220 -183
  72. package/src/typechecker/index.js +659 -92
  73. package/src/typechecker/init-order.js +426 -0
  74. package/src/typechecker/operand-text.js +40 -0
  75. package/src/typechecker/resolve.js +613 -62
  76. package/src/typechecker/statements.js +212 -20
  77. package/src/typechecker/stdlib/excluded.js +902 -0
  78. package/src/typechecker/stdlib/index.js +38 -0
  79. package/src/typechecker/stdlib/simd.js +65 -15
  80. package/src/typechecker/termination.js +11 -2
  81. package/src/typechecker/types.js +268 -514
  82. package/stdlib/bytes/buffer.go +479 -0
  83. package/stdlib/bytes/bytes.go +1010 -0
  84. package/stdlib/bytes/reader.go +161 -0
  85. package/stdlib/cmp/cmp.go +65 -0
  86. package/stdlib/context/context.go +115 -0
  87. package/stdlib/crypto/rand/rand.go +34 -0
  88. package/stdlib/crypto/sha256/sha256.go +249 -0
  89. package/stdlib/encoding/base64/base64.go +331 -0
  90. package/stdlib/encoding/binary/binary.go +332 -0
  91. package/stdlib/encoding/hex/hex.go +140 -0
  92. package/stdlib/encoding/json/errors.go +31 -0
  93. package/stdlib/encoding/json/indent.go +71 -0
  94. package/stdlib/encoding/json/json.go +62 -0
  95. package/stdlib/encoding/json/number.go +12 -0
  96. package/stdlib/encoding/json/stream.go +173 -0
  97. package/stdlib/errors/errors.go +174 -0
  98. package/stdlib/fmt/errors.go +110 -0
  99. package/stdlib/fmt/format.go +732 -0
  100. package/stdlib/fmt/print.go +1232 -0
  101. package/stdlib/gom/gom.go +293 -0
  102. package/stdlib/hash/hash.go +53 -0
  103. package/stdlib/html/html.go +251 -0
  104. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  105. package/stdlib/internal/jsonrt/dec.go +871 -0
  106. package/stdlib/internal/jsonrt/enc.go +516 -0
  107. package/stdlib/internal/jsonrt/indent.go +135 -0
  108. package/stdlib/internal/jsonrt/number.go +27 -0
  109. package/stdlib/internal/jsonrt/reader.go +73 -0
  110. package/stdlib/internal/jsonrt/scanner.go +658 -0
  111. package/stdlib/io/io.go +502 -0
  112. package/stdlib/iter/iter.go +18 -0
  113. package/stdlib/maps/maps.go +131 -0
  114. package/stdlib/math/bits/bits.go +507 -0
  115. package/stdlib/math/extra.go +272 -0
  116. package/stdlib/math/math.go +439 -0
  117. package/stdlib/math/rand/rand.go +297 -0
  118. package/stdlib/os/os.go +93 -0
  119. package/stdlib/path/filepath/filepath.go +47 -0
  120. package/stdlib/path/path.go +394 -0
  121. package/stdlib/regexp/regexp.go +231 -0
  122. package/stdlib/slices/slices.go +526 -0
  123. package/stdlib/slices/sort.go +209 -0
  124. package/stdlib/slices/zsort_cmp.go +480 -0
  125. package/stdlib/slices/zsort_ordered.go +482 -0
  126. package/stdlib/sort/sort.go +500 -0
  127. package/stdlib/sort/zsort_func.go +480 -0
  128. package/stdlib/sort/zsort_iface.go +480 -0
  129. package/stdlib/strconv/float.go +1699 -0
  130. package/stdlib/strconv/isprint.go +752 -0
  131. package/stdlib/strconv/quote.go +526 -0
  132. package/stdlib/strconv/strconv.go +616 -0
  133. package/stdlib/strings/builder.go +95 -0
  134. package/stdlib/strings/reader.go +163 -0
  135. package/stdlib/strings/replacer.go +102 -0
  136. package/stdlib/strings/strings.go +807 -0
  137. package/stdlib/sync/sync.go +268 -0
  138. package/stdlib/testing/async_js.go +61 -0
  139. package/stdlib/testing/benchmark.go +297 -0
  140. package/stdlib/testing/testing.go +523 -0
  141. package/stdlib/time/duration.go +233 -0
  142. package/stdlib/time/format.go +745 -0
  143. package/stdlib/time/parse.go +790 -0
  144. package/stdlib/time/sleep_js.go +63 -0
  145. package/stdlib/time/time.go +834 -0
  146. package/stdlib/unicode/unicode.go +250 -0
  147. package/stdlib/unicode/utf8/utf8.go +464 -0
  148. package/src/backend/js/stdlib/base64.js +0 -12
  149. package/src/backend/js/stdlib/binary.js +0 -102
  150. package/src/backend/js/stdlib/bits.js +0 -46
  151. package/src/backend/js/stdlib/builder.js +0 -63
  152. package/src/backend/js/stdlib/bytes.js +0 -122
  153. package/src/backend/js/stdlib/errors.js +0 -44
  154. package/src/backend/js/stdlib/fmt.js +0 -178
  155. package/src/backend/js/stdlib/gom.js +0 -155
  156. package/src/backend/js/stdlib/hex.js +0 -17
  157. package/src/backend/js/stdlib/html.js +0 -20
  158. package/src/backend/js/stdlib/io.js +0 -137
  159. package/src/backend/js/stdlib/json.js +0 -972
  160. package/src/backend/js/stdlib/maps.js +0 -45
  161. package/src/backend/js/stdlib/math.js +0 -69
  162. package/src/backend/js/stdlib/os.js +0 -13
  163. package/src/backend/js/stdlib/path.js +0 -48
  164. package/src/backend/js/stdlib/rand.js +0 -32
  165. package/src/backend/js/stdlib/regexp.js +0 -54
  166. package/src/backend/js/stdlib/sha256.js +0 -12
  167. package/src/backend/js/stdlib/shared.js +0 -17
  168. package/src/backend/js/stdlib/simd.js +0 -24
  169. package/src/backend/js/stdlib/slices.js +0 -77
  170. package/src/backend/js/stdlib/sort.js +0 -30
  171. package/src/backend/js/stdlib/strconv.js +0 -74
  172. package/src/backend/js/stdlib/strings.js +0 -222
  173. package/src/backend/js/stdlib/sync.js +0 -13
  174. package/src/backend/js/stdlib/testing.js +0 -34
  175. package/src/backend/js/stdlib/time.js +0 -128
  176. package/src/backend/js/stdlib/unicode.js +0 -25
  177. package/src/backend/js/stdlib/utf8.js +0 -26
  178. package/src/backend/wasm/const-fold.js +0 -205
  179. package/src/backend/wasm/emit-stdlib.js +0 -13
  180. package/src/backend/wasm/stdlib/bytes.js +0 -5039
  181. package/src/backend/wasm/stdlib/core.js +0 -8903
  182. package/src/backend/wasm/stdlib/io.js +0 -2161
  183. package/src/backend/wasm/stdlib/packages.js +0 -2400
  184. package/src/backend/wasm/stdlib/pure.js +0 -720
  185. package/src/backend/wasm/stdlib/time.js +0 -1200
  186. package/src/typechecker/stdlib/core.js +0 -801
  187. package/src/typechecker/stdlib/extended.js +0 -914
  188. package/src/typechecker/stdlib.js +0 -22
  189. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  190. /package/src/{colors.js → cli/colors.js} +0 -0
  191. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  192. /package/src/{minifier.js → cli/minifier.js} +0 -0
  193. /package/src/{project-config.js → cli/project-config.js} +0 -0
  194. /package/src/{pwa.js → cli/pwa.js} +0 -0
@@ -0,0 +1,790 @@
1
+ //go:build gofront
2
+
3
+ //gofront:target both
4
+
5
+ // Copyright 2010 The Go Authors. All rights reserved.
6
+ // Use of this source code is governed by a BSD-style
7
+ // license that can be found in the LICENSE file.
8
+
9
+ package time
10
+
11
+ import "errors"
12
+
13
+ var errLeadingInt = errors.New("time: bad [0-9]*") // never printed
14
+
15
+ var shortDayNames = []string{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}
16
+
17
+ // lookup returns the index of the entry of tab that value starts with, case
18
+ // insensitively, and the rest of value.
19
+ func lookup(tab []string, val string) (int, string, error) {
20
+ for i, v := range tab {
21
+ if len(val) >= len(v) && match(val[0:len(v)], v) {
22
+ return i, val[len(v):], nil
23
+ }
24
+ }
25
+ return -1, val, errBad
26
+ }
27
+
28
+ // match reports whether s1 and s2 match ignoring case.
29
+ // It is assumed s1 and s2 are the same length.
30
+ func match(s1, s2 string) bool {
31
+ for i := 0; i < len(s1); i++ {
32
+ c1 := s1[i]
33
+ c2 := s2[i]
34
+ if c1 != c2 {
35
+ // Switch to lower-case; 'a'-'A' is known to be a single bit.
36
+ c1 |= 32
37
+ c2 |= 32
38
+ if c1 != c2 || c1 < 'a' || c1 > 'z' {
39
+ return false
40
+ }
41
+ }
42
+ }
43
+ return true
44
+ }
45
+
46
+ func commaOrPeriod(b byte) bool {
47
+ return b == '.' || b == ','
48
+ }
49
+
50
+ func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) {
51
+ if !commaOrPeriod(value[0]) {
52
+ err = errBad
53
+ return
54
+ }
55
+ if nbytes > 10 {
56
+ value = value[:10]
57
+ nbytes = 10
58
+ }
59
+ ns, err = atoi(value[1:nbytes])
60
+ if err != nil {
61
+ return
62
+ }
63
+ if ns < 0 {
64
+ rangeErrString = "fractional second"
65
+ return
66
+ }
67
+ // We need nanoseconds, which means scaling by the number
68
+ // of digits in the format string.
69
+ scaleDigits := 10 - nbytes
70
+ for i := 0; i < scaleDigits; i++ {
71
+ ns *= 10
72
+ }
73
+ return
74
+ }
75
+
76
+ // atoi parses a decimal integer with an optional sign.
77
+ func atoi(s string) (x int, err error) {
78
+ neg := false
79
+ if s != "" && (s[0] == '-' || s[0] == '+') {
80
+ neg = s[0] == '-'
81
+ s = s[1:]
82
+ }
83
+ q, rem, err := leadingInt(s)
84
+ x = int(q)
85
+ if err != nil || rem != "" {
86
+ return 0, errBad
87
+ }
88
+ if neg {
89
+ x = -x
90
+ }
91
+ return x, nil
92
+ }
93
+
94
+ // leadingInt consumes the leading [0-9]* from s.
95
+ func leadingInt(s string) (x uint64, rem string, err error) {
96
+ var limit uint64 = 1 << 63
97
+ i := 0
98
+ for ; i < len(s); i++ {
99
+ c := s[i]
100
+ if c < '0' || c > '9' {
101
+ break
102
+ }
103
+ if x > limit/10 {
104
+ // overflow
105
+ return 0, "", errLeadingInt
106
+ }
107
+ x = x*10 + uint64(c) - '0'
108
+ if x > limit {
109
+ // overflow
110
+ return 0, "", errLeadingInt
111
+ }
112
+ }
113
+ return x, s[i:], nil
114
+ }
115
+
116
+ // leadingFraction consumes the leading [0-9]* from s.
117
+ // It is used only for fractions, so does not return an error on overflow,
118
+ // it just stops accumulating precision.
119
+ func leadingFraction(s string) (x uint64, scale float64, rem string) {
120
+ var limit uint64 = 1 << 63
121
+ i := 0
122
+ scale = 1
123
+ overflow := false
124
+ for ; i < len(s); i++ {
125
+ c := s[i]
126
+ if c < '0' || c > '9' {
127
+ break
128
+ }
129
+ if overflow {
130
+ continue
131
+ }
132
+ if x > (limit-1)/10 {
133
+ // It's possible for overflow to give a positive number, so take care.
134
+ overflow = true
135
+ continue
136
+ }
137
+ y := x*10 + uint64(c) - '0'
138
+ if y > limit {
139
+ overflow = true
140
+ continue
141
+ }
142
+ x = y
143
+ scale *= 10
144
+ }
145
+ return x, scale, s[i:]
146
+ }
147
+
148
+ func unitValue(u string) (uint64, bool) {
149
+ switch u {
150
+ case "ns":
151
+ return uint64(Nanosecond), true
152
+ case "us", "µs", "μs": // U+00B5 = micro symbol, U+03BC = Greek letter mu
153
+ return uint64(Microsecond), true
154
+ case "ms":
155
+ return uint64(Millisecond), true
156
+ case "s":
157
+ return uint64(Second), true
158
+ case "m":
159
+ return uint64(Minute), true
160
+ case "h":
161
+ return uint64(Hour), true
162
+ }
163
+ return 0, false
164
+ }
165
+
166
+ // ParseDuration parses a duration string.
167
+ // A duration string is a possibly signed sequence of
168
+ // decimal numbers, each with optional fraction and a unit suffix,
169
+ // such as "300ms", "-1.5h" or "2h45m".
170
+ // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
171
+ func ParseDuration(s string) (Duration, error) {
172
+ // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
173
+ orig := s
174
+ var d uint64
175
+ var limit uint64 = 1 << 63
176
+ neg := false
177
+
178
+ // Consume [-+]?
179
+ if s != "" {
180
+ c := s[0]
181
+ if c == '-' || c == '+' {
182
+ neg = c == '-'
183
+ s = s[1:]
184
+ }
185
+ }
186
+ // Special case: if all that is left is "0", this is zero.
187
+ if s == "0" {
188
+ return 0, nil
189
+ }
190
+ if s == "" {
191
+ return 0, errors.New("time: invalid duration " + quote(orig))
192
+ }
193
+ for s != "" {
194
+ var (
195
+ v, f uint64 // integers before, after decimal point
196
+ scale float64 = 1 // value = v + f/scale
197
+ )
198
+
199
+ var err error
200
+
201
+ // The next character must be [0-9.]
202
+ if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') {
203
+ return 0, errors.New("time: invalid duration " + quote(orig))
204
+ }
205
+ // Consume [0-9]*
206
+ pl := len(s)
207
+ v, s, err = leadingInt(s)
208
+ if err != nil {
209
+ return 0, errors.New("time: invalid duration " + quote(orig))
210
+ }
211
+ pre := pl != len(s) // whether we consumed anything before a period
212
+
213
+ // Consume (\.[0-9]*)?
214
+ post := false
215
+ if s != "" && s[0] == '.' {
216
+ s = s[1:]
217
+ pl := len(s)
218
+ f, scale, s = leadingFraction(s)
219
+ post = pl != len(s)
220
+ }
221
+ if !pre && !post {
222
+ // no digits (e.g. ".s" or "-.s")
223
+ return 0, errors.New("time: invalid duration " + quote(orig))
224
+ }
225
+
226
+ // Consume unit.
227
+ i := 0
228
+ for ; i < len(s); i++ {
229
+ c := s[i]
230
+ if c == '.' || '0' <= c && c <= '9' {
231
+ break
232
+ }
233
+ }
234
+ if i == 0 {
235
+ return 0, errors.New("time: missing unit in duration " + quote(orig))
236
+ }
237
+ u := s[:i]
238
+ s = s[i:]
239
+ unit, ok := unitValue(u)
240
+ if !ok {
241
+ return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig))
242
+ }
243
+ if v > limit/unit {
244
+ // overflow
245
+ return 0, errors.New("time: invalid duration " + quote(orig))
246
+ }
247
+ v *= unit
248
+ if f > 0 {
249
+ // float64 is needed to be nanosecond accurate for fractions of hours.
250
+ // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
251
+ v += uint64(float64(f) * (float64(unit) / scale))
252
+ if v > limit {
253
+ // overflow
254
+ return 0, errors.New("time: invalid duration " + quote(orig))
255
+ }
256
+ }
257
+ d += v
258
+ if d > limit {
259
+ return 0, errors.New("time: invalid duration " + quote(orig))
260
+ }
261
+ }
262
+ if neg {
263
+ return -Duration(d), nil
264
+ }
265
+ if d > limit-1 {
266
+ return 0, errors.New("time: invalid duration " + quote(orig))
267
+ }
268
+ return Duration(d), nil
269
+ }
270
+
271
+ // skip removes the given prefix from value,
272
+ // treating runs of space characters as equivalent.
273
+ func skip(value, prefix string) (string, error) {
274
+ for len(prefix) > 0 {
275
+ if prefix[0] == ' ' {
276
+ if len(value) > 0 && value[0] != ' ' {
277
+ return value, errBad
278
+ }
279
+ prefix = cutspace(prefix)
280
+ value = cutspace(value)
281
+ continue
282
+ }
283
+ if len(value) == 0 || value[0] != prefix[0] {
284
+ return value, errBad
285
+ }
286
+ prefix = prefix[1:]
287
+ value = value[1:]
288
+ }
289
+ return value, nil
290
+ }
291
+
292
+ func cutspace(s string) string {
293
+ for len(s) > 0 && s[0] == ' ' {
294
+ s = s[1:]
295
+ }
296
+ return s
297
+ }
298
+
299
+ // daysIn returns the number of days in a month for a given year.
300
+ func daysIn(m Month, year int) int {
301
+ if m == February && isLeap(year) {
302
+ return 29
303
+ }
304
+ return daysBefore[m] - daysBefore[m-1]
305
+ }
306
+
307
+ func newParseError(layout, value, layoutElem, valueElem, message string) *ParseError {
308
+ return &ParseError{layout, value, layoutElem, valueElem, message}
309
+ }
310
+
311
+ // Parse parses a formatted string and returns the time value it represents.
312
+ // See the documentation for the constant called Layout to see how to
313
+ // represent the format.
314
+ //
315
+ // In the absence of a time zone indicator, Parse returns a time in UTC.
316
+ //
317
+ // When parsing a time with a zone offset like -0700, if the offset
318
+ // corresponds to a time zone used by the current location (Local), then Parse
319
+ // uses that location and zone in the returned time. Otherwise it records the
320
+ // time as being in a fabricated location with time fixed at the given zone
321
+ // offset.
322
+ func Parse(layout, value string) (Time, error) {
323
+ return parse(layout, value, UTC, Local)
324
+ }
325
+
326
+ // ParseInLocation is like Parse but differs in two important ways. First, in
327
+ // the absence of time zone information, Parse interprets a time as UTC;
328
+ // ParseInLocation interprets the time as in the given location. Second, when
329
+ // given a zone offset or abbreviation, Parse tries to match it against the
330
+ // Local location; ParseInLocation uses the given location.
331
+ func ParseInLocation(layout, value string, loc *Location) (Time, error) {
332
+ return parse(layout, value, loc, loc)
333
+ }
334
+
335
+ func parseTimeZone(value string) (length int, ok bool) {
336
+ if len(value) < 3 {
337
+ return 0, false
338
+ }
339
+ // Special case 1: ChST and MeST.
340
+ if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") {
341
+ return 4, true
342
+ }
343
+ // Special case 2: GMT may have an hour offset; treat it specially.
344
+ if value[:3] == "GMT" {
345
+ length = parseGMT(value)
346
+ return length, true
347
+ }
348
+ // Special Case 3: Some time zones are not named, but have +/-00 format
349
+ if value[0] == '+' || value[0] == '-' {
350
+ length = parseSignedOffset(value)
351
+ ok := length > 0 // parseSignedOffset returns 0 in case of bad input
352
+ return length, ok
353
+ }
354
+ // How many upper-case letters are there? Need at least three, at most five.
355
+ var nUpper int
356
+ for nUpper = 0; nUpper < 6; nUpper++ {
357
+ if nUpper >= len(value) {
358
+ break
359
+ }
360
+ if c := value[nUpper]; c < 'A' || 'Z' < c {
361
+ break
362
+ }
363
+ }
364
+ switch nUpper {
365
+ case 0, 1, 2, 6:
366
+ return 0, false
367
+ case 5: // Must end in T to match.
368
+ if value[4] == 'T' {
369
+ return 5, true
370
+ }
371
+ case 4:
372
+ // Must end in T, except one special case.
373
+ if value[3] == 'T' || value[:4] == "WITA" {
374
+ return 4, true
375
+ }
376
+ case 3:
377
+ return 3, true
378
+ }
379
+ return 0, false
380
+ }
381
+
382
+ // parseGMT parses a GMT time zone. The input string is known to start "GMT".
383
+ // The function checks whether that is followed by a sign and a number in the
384
+ // range -23 through +23 excluding zero.
385
+ func parseGMT(value string) int {
386
+ value = value[3:]
387
+ if len(value) == 0 {
388
+ return 3
389
+ }
390
+
391
+ return 3 + parseSignedOffset(value)
392
+ }
393
+
394
+ // parseSignedOffset parses a signed timezone offset (e.g. "+03" or "-04").
395
+ // The function checks for a signed number in the range -23 through +23
396
+ // excluding zero. Returns length of the found offset string or 0 otherwise.
397
+ func parseSignedOffset(value string) int {
398
+ sign := value[0]
399
+ if sign != '-' && sign != '+' {
400
+ return 0
401
+ }
402
+ x, rem, err := leadingInt(value[1:])
403
+
404
+ // fail if nothing consumed by leadingInt
405
+ if err != nil || value[1:] == rem {
406
+ return 0
407
+ }
408
+ if x > 23 {
409
+ return 0
410
+ }
411
+ return len(value) - len(rem)
412
+ }
413
+
414
+ func parse(layout, value string, defaultLocation, local *Location) (Time, error) {
415
+ alayout, avalue := layout, value
416
+ rangeErrString := "" // set if a value is out of range
417
+ amSet := false // do we need to subtract 12 from the hour for midnight?
418
+ pmSet := false // do we need to add 12 to the hour?
419
+
420
+ // Time being constructed.
421
+ var (
422
+ year int
423
+ month int = -1
424
+ day int = -1
425
+ yday int = -1
426
+ hour int
427
+ min int
428
+ sec int
429
+ nsec int
430
+ z *Location
431
+ zoneOffset int = -1
432
+ zoneName string
433
+ )
434
+
435
+ // Each iteration processes one std value.
436
+ for {
437
+ var err error
438
+ prefix, std, suffix := nextStdChunk(layout)
439
+ stdstr := layout[len(prefix) : len(layout)-len(suffix)]
440
+ value, err = skip(value, prefix)
441
+ if err != nil {
442
+ return Time{}, newParseError(alayout, avalue, prefix, value, "")
443
+ }
444
+ if std == 0 {
445
+ if len(value) != 0 {
446
+ return Time{}, newParseError(alayout, avalue, "", value, ": extra text: "+quote(value))
447
+ }
448
+ break
449
+ }
450
+ layout = suffix
451
+ var p string
452
+ hold := value
453
+ switch std & stdMask {
454
+ case stdYear:
455
+ if len(value) < 2 {
456
+ err = errBad
457
+ break
458
+ }
459
+ hold = value
460
+ p, value = value[0:2], value[2:]
461
+ year, err = atoi(p)
462
+ if err != nil {
463
+ value = hold
464
+ } else if year >= 69 { // Unix time starts Dec 31 1969 in some time zones
465
+ year += 1900
466
+ } else {
467
+ year += 2000
468
+ }
469
+ case stdLongYear:
470
+ if len(value) < 4 || !isDigit(value, 0) {
471
+ err = errBad
472
+ break
473
+ }
474
+ p, value = value[0:4], value[4:]
475
+ year, err = atoi(p)
476
+ case stdMonth:
477
+ month, value, err = lookup(shortMonthNames, value)
478
+ month++
479
+ case stdLongMonth:
480
+ month, value, err = lookup(longMonthNames, value)
481
+ month++
482
+ case stdNumMonth, stdZeroMonth:
483
+ month, value, err = getnum(value, std == stdZeroMonth)
484
+ if err == nil && (month <= 0 || 12 < month) {
485
+ rangeErrString = "month"
486
+ }
487
+ case stdWeekDay:
488
+ // Ignore weekday except for error checking.
489
+ _, value, err = lookup(shortDayNames, value)
490
+ case stdLongWeekDay:
491
+ _, value, err = lookup(longDayNames, value)
492
+ case stdDay, stdUnderDay, stdZeroDay:
493
+ if std == stdUnderDay && len(value) > 0 && value[0] == ' ' {
494
+ value = value[1:]
495
+ }
496
+ day, value, err = getnum(value, std == stdZeroDay)
497
+ // Note that we allow any one- or two-digit day here.
498
+ // The month, day, year combination is validated after we've completed parsing.
499
+ case stdUnderYearDay, stdZeroYearDay:
500
+ for i := 0; i < 2; i++ {
501
+ if std == stdUnderYearDay && len(value) > 0 && value[0] == ' ' {
502
+ value = value[1:]
503
+ }
504
+ }
505
+ yday, value, err = getnum3(value, std == stdZeroYearDay)
506
+ // Note that we allow any one-, two-, or three-digit year-day here.
507
+ // The year-day, year combination is validated after we've completed parsing.
508
+ case stdHour:
509
+ hour, value, err = getnum(value, false)
510
+ if hour < 0 || 24 <= hour {
511
+ rangeErrString = "hour"
512
+ }
513
+ case stdHour12, stdZeroHour12:
514
+ hour, value, err = getnum(value, std == stdZeroHour12)
515
+ if hour < 0 || 12 < hour {
516
+ rangeErrString = "hour"
517
+ }
518
+ case stdMinute, stdZeroMinute:
519
+ min, value, err = getnum(value, std == stdZeroMinute)
520
+ if min < 0 || 60 <= min {
521
+ rangeErrString = "minute"
522
+ }
523
+ case stdSecond, stdZeroSecond:
524
+ sec, value, err = getnum(value, std == stdZeroSecond)
525
+ if err != nil {
526
+ break
527
+ }
528
+ if sec < 0 || 60 <= sec {
529
+ rangeErrString = "second"
530
+ break
531
+ }
532
+ // Special case: do we have a fractional second but no
533
+ // fractional second in the format?
534
+ if len(value) >= 2 && commaOrPeriod(value[0]) && isDigit(value, 1) {
535
+ _, nextStd, _ := nextStdChunk(layout)
536
+ nextStd &= stdMask
537
+ if nextStd == stdFracSecond0 || nextStd == stdFracSecond9 {
538
+ // Fractional second in the layout; proceed normally
539
+ break
540
+ }
541
+ // No fractional second in the layout but we have one in the input.
542
+ n := 2
543
+ for ; n < len(value) && isDigit(value, n); n++ {
544
+ }
545
+ nsec, rangeErrString, err = parseNanoseconds(value, n)
546
+ value = value[n:]
547
+ }
548
+ case stdPM:
549
+ if len(value) < 2 {
550
+ err = errBad
551
+ break
552
+ }
553
+ p, value = value[0:2], value[2:]
554
+ switch p {
555
+ case "PM":
556
+ pmSet = true
557
+ case "AM":
558
+ amSet = true
559
+ default:
560
+ err = errBad
561
+ }
562
+ case stdpm:
563
+ if len(value) < 2 {
564
+ err = errBad
565
+ break
566
+ }
567
+ p, value = value[0:2], value[2:]
568
+ switch p {
569
+ case "pm":
570
+ pmSet = true
571
+ case "am":
572
+ amSet = true
573
+ default:
574
+ err = errBad
575
+ }
576
+ case stdISO8601TZ, stdISO8601ShortTZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
577
+ if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ColonSecondsTZ) && len(value) >= 1 && value[0] == 'Z' {
578
+ value = value[1:]
579
+ z = UTC
580
+ break
581
+ }
582
+ var sign, hour, min, seconds string
583
+ if std == stdISO8601ColonTZ || std == stdNumColonTZ {
584
+ if len(value) < 6 {
585
+ err = errBad
586
+ break
587
+ }
588
+ if value[3] != ':' {
589
+ err = errBad
590
+ break
591
+ }
592
+ sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:]
593
+ } else if std == stdNumShortTZ || std == stdISO8601ShortTZ {
594
+ if len(value) < 3 {
595
+ err = errBad
596
+ break
597
+ }
598
+ sign, hour, min, seconds, value = value[0:1], value[1:3], "00", "00", value[3:]
599
+ } else if std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
600
+ if len(value) < 9 {
601
+ err = errBad
602
+ break
603
+ }
604
+ if value[3] != ':' || value[6] != ':' {
605
+ err = errBad
606
+ break
607
+ }
608
+ sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], value[7:9], value[9:]
609
+ } else if std == stdISO8601SecondsTZ || std == stdNumSecondsTz {
610
+ if len(value) < 7 {
611
+ err = errBad
612
+ break
613
+ }
614
+ sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], value[5:7], value[7:]
615
+ } else {
616
+ if len(value) < 5 {
617
+ err = errBad
618
+ break
619
+ }
620
+ sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], "00", value[5:]
621
+ }
622
+ var hr, mm, ss int
623
+ hr, _, err = getnum(hour, true)
624
+ if err == nil {
625
+ mm, _, err = getnum(min, true)
626
+ }
627
+ if err == nil {
628
+ ss, _, err = getnum(seconds, true)
629
+ }
630
+
631
+ // The range test use > rather than >=,
632
+ // as some people do write offsets of 24 hours
633
+ // or 60 minutes or 60 seconds.
634
+ if hr > 24 {
635
+ rangeErrString = "time zone offset hour"
636
+ }
637
+ if mm > 60 {
638
+ rangeErrString = "time zone offset minute"
639
+ }
640
+ if ss > 60 {
641
+ rangeErrString = "time zone offset second"
642
+ }
643
+
644
+ zoneOffset = (hr*60+mm)*60 + ss // offset is in seconds
645
+ switch sign[0] {
646
+ case '+':
647
+ case '-':
648
+ zoneOffset = -zoneOffset
649
+ default:
650
+ err = errBad
651
+ }
652
+ case stdTZ:
653
+ // Does it look like a time zone?
654
+ if len(value) >= 3 && value[0:3] == "UTC" {
655
+ z = UTC
656
+ value = value[3:]
657
+ break
658
+ }
659
+ n, ok := parseTimeZone(value)
660
+ if !ok {
661
+ err = errBad
662
+ break
663
+ }
664
+ zoneName, value = value[:n], value[n:]
665
+
666
+ case stdFracSecond0:
667
+ // stdFracSecond0 requires the exact number of digits as specified in
668
+ // the layout.
669
+ ndigit := 1 + digitsLen(std)
670
+ if len(value) < ndigit {
671
+ err = errBad
672
+ break
673
+ }
674
+ nsec, rangeErrString, err = parseNanoseconds(value, ndigit)
675
+ value = value[ndigit:]
676
+
677
+ case stdFracSecond9:
678
+ if len(value) < 2 || !commaOrPeriod(value[0]) || value[1] < '0' || '9' < value[1] {
679
+ // Fractional second omitted.
680
+ break
681
+ }
682
+ // Take any number of digits, even more than asked for,
683
+ // because it is what the stdSecond case would do.
684
+ i := 0
685
+ for i+1 < len(value) && '0' <= value[i+1] && value[i+1] <= '9' {
686
+ i++
687
+ }
688
+ nsec, rangeErrString, err = parseNanoseconds(value, 1+i)
689
+ value = value[1+i:]
690
+ }
691
+ if rangeErrString != "" {
692
+ return Time{}, newParseError(alayout, avalue, stdstr, value, ": "+rangeErrString+" out of range")
693
+ }
694
+ if err != nil {
695
+ return Time{}, newParseError(alayout, avalue, stdstr, hold, "")
696
+ }
697
+ }
698
+ if pmSet && hour < 12 {
699
+ hour += 12
700
+ } else if amSet && hour == 12 {
701
+ hour = 0
702
+ }
703
+
704
+ // Convert yday to day, month.
705
+ if yday >= 0 {
706
+ var d int
707
+ var m int
708
+ if isLeap(year) {
709
+ if yday == 31+29 {
710
+ m = int(February)
711
+ d = 29
712
+ } else if yday > 31+29 {
713
+ yday--
714
+ }
715
+ }
716
+ if yday < 1 || yday > 365 {
717
+ // Argh, ParseError's Message field has to be a string.
718
+ return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year out of range")
719
+ }
720
+ if m == 0 {
721
+ m = (yday-1)/31 + 1
722
+ if daysBefore[m] < yday {
723
+ m++
724
+ }
725
+ d = yday - daysBefore[m-1]
726
+ }
727
+ // If month, day already seen, yday's m, d must match.
728
+ // Otherwise, set them from m, d.
729
+ if month >= 0 && month != m {
730
+ return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year does not match month")
731
+ }
732
+ month = m
733
+ if day >= 0 && day != d {
734
+ return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year does not match day")
735
+ }
736
+ day = d
737
+ } else {
738
+ if month < 0 {
739
+ month = int(January)
740
+ }
741
+ if day < 0 {
742
+ day = 1
743
+ }
744
+ }
745
+
746
+ // Validate the day of the month.
747
+ if day < 1 || day > daysIn(Month(month), year) {
748
+ return Time{}, newParseError(alayout, avalue, "", value, ": day out of range")
749
+ }
750
+
751
+ if z != nil {
752
+ return Date(year, Month(month), day, hour, min, sec, nsec, z), nil
753
+ }
754
+
755
+ if zoneOffset != -1 {
756
+ t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
757
+ t.sec -= int64(zoneOffset)
758
+
759
+ // Look for local zone with the given offset.
760
+ // If that zone was in effect at the given time, use it.
761
+ name, offset := lookupZone(local, t.unixSec())
762
+ if offset == zoneOffset && (zoneName == "" || name == zoneName) {
763
+ return t.setLoc(local), nil
764
+ }
765
+
766
+ // Otherwise create fake zone with unknown name.
767
+ return t.setLoc(FixedZone(zoneName, zoneOffset)), nil
768
+ }
769
+
770
+ if zoneName != "" {
771
+ t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
772
+ // Look for local zone with the given name.
773
+ name, offset := lookupZone(local, t.unixSec())
774
+ if name == zoneName {
775
+ t.sec -= int64(offset)
776
+ return t.setLoc(local), nil
777
+ }
778
+
779
+ // Otherwise, create fake zone with unknown offset.
780
+ offset = 0
781
+ if len(zoneName) > 3 && zoneName[:3] == "GMT" {
782
+ offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT.
783
+ offset *= 3600
784
+ }
785
+ return t.setLoc(FixedZone(zoneName, offset)), nil
786
+ }
787
+
788
+ // Otherwise, fall back to default.
789
+ return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil
790
+ }