gofront 1.8.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 (177) hide show
  1. package/README.md +3 -3
  2. package/package.json +5 -4
  3. package/src/backend/js/expressions.js +849 -371
  4. package/src/backend/js/index.js +241 -147
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +512 -2547
  7. package/src/backend/js/statements.js +506 -103
  8. package/src/backend/js/stdlib/index.js +45 -93
  9. package/src/backend/js/templ.js +32 -45
  10. package/src/backend/js/type-info.js +177 -13
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +63 -171
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +490 -965
  15. package/src/backend/wasm/emit-builtins.js +643 -256
  16. package/src/backend/wasm/emit-exprs.js +124 -57
  17. package/src/backend/wasm/emit-maps.js +17 -367
  18. package/src/backend/wasm/emit-stmts.js +325 -75
  19. package/src/backend/wasm/emit.js +104 -13
  20. package/src/backend/wasm/globals.js +47 -8
  21. package/src/backend/wasm/glue.js +2 -4
  22. package/src/backend/wasm/index.js +36 -530
  23. package/src/backend/wasm/method-expr.js +12 -1
  24. package/src/backend/wasm/module-emitter.js +92 -717
  25. package/src/backend/wasm/monomorph.js +103 -6
  26. package/src/backend/wasm/natives.js +596 -0
  27. package/src/backend/wasm/prescan.js +5 -153
  28. package/src/backend/wasm/prune-funcs.js +89 -0
  29. package/src/backend/wasm/stdlib/index.js +2 -32
  30. package/src/backend/wasm/types.js +68 -20
  31. package/src/backend/wasm/variadic.js +3 -3
  32. package/src/cli/cli-core.js +5 -1
  33. package/src/cli/test-runner.js +115 -342
  34. package/src/compiler.js +108 -130
  35. package/src/lexer/lexer.js +105 -11
  36. package/src/lexer/templ-lexer.js +61 -18
  37. package/src/lexer/tokens.js +1 -0
  38. package/src/link/stdlib.js +354 -132
  39. package/src/link/type-names.js +148 -0
  40. package/src/link/wasm.js +30 -6
  41. package/src/lower/bounds.js +153 -0
  42. package/src/lower/captures.js +92 -33
  43. package/src/lower/embedding.js +32 -3
  44. package/src/lower/errors-as.js +196 -0
  45. package/src/lower/fmt-formatters.js +905 -0
  46. package/src/lower/functions.js +2 -0
  47. package/src/lower/gen-types.js +274 -0
  48. package/src/lower/index.js +7 -1
  49. package/src/lower/json-codecs.js +228 -247
  50. package/src/lower/ownership.js +25 -7
  51. package/src/lower/reachability.js +69 -51
  52. package/src/lower/walk.js +12 -0
  53. package/src/parser/declarations.js +28 -5
  54. package/src/parser/expressions.js +86 -16
  55. package/src/parser/statements.js +1 -0
  56. package/src/parser/templ.js +44 -5
  57. package/src/parser/types.js +1 -0
  58. package/src/resolver.js +1 -2
  59. package/src/typechecker/assignability.js +124 -11
  60. package/src/typechecker/const-fold.js +70 -27
  61. package/src/typechecker/constants.js +32 -6
  62. package/src/typechecker/expressions.js +326 -98
  63. package/src/typechecker/index.js +208 -33
  64. package/src/typechecker/init-order.js +136 -40
  65. package/src/typechecker/operand-text.js +40 -0
  66. package/src/typechecker/resolve.js +192 -36
  67. package/src/typechecker/statements.js +122 -11
  68. package/src/typechecker/stdlib/excluded.js +9 -5
  69. package/src/typechecker/stdlib/index.js +25 -9
  70. package/src/typechecker/termination.js +10 -1
  71. package/src/typechecker/types.js +203 -573
  72. package/stdlib/bytes/buffer.go +479 -0
  73. package/stdlib/bytes/bytes.go +1010 -0
  74. package/stdlib/bytes/reader.go +161 -0
  75. package/stdlib/context/context.go +115 -0
  76. package/stdlib/crypto/rand/rand.go +34 -0
  77. package/stdlib/crypto/sha256/sha256.go +249 -0
  78. package/stdlib/encoding/base64/base64.go +331 -0
  79. package/stdlib/encoding/binary/binary.go +332 -0
  80. package/stdlib/encoding/hex/hex.go +140 -0
  81. package/stdlib/encoding/json/json.go +62 -0
  82. package/stdlib/errors/errors.go +174 -0
  83. package/stdlib/fmt/errors.go +110 -0
  84. package/stdlib/fmt/format.go +732 -0
  85. package/stdlib/fmt/print.go +1232 -0
  86. package/stdlib/gom/gom.go +293 -0
  87. package/stdlib/html/html.go +251 -0
  88. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  89. package/stdlib/internal/jsonrt/dec.go +171 -38
  90. package/stdlib/internal/jsonrt/enc.go +186 -36
  91. package/stdlib/internal/jsonrt/scanner.go +17 -8
  92. package/stdlib/io/io.go +157 -1
  93. package/stdlib/maps/maps.go +131 -0
  94. package/stdlib/math/bits/bits.go +507 -0
  95. package/stdlib/math/extra.go +16 -14
  96. package/stdlib/math/math.go +439 -0
  97. package/stdlib/math/rand/rand.go +297 -0
  98. package/stdlib/os/os.go +93 -0
  99. package/stdlib/path/filepath/filepath.go +47 -0
  100. package/stdlib/path/path.go +394 -0
  101. package/stdlib/regexp/regexp.go +231 -0
  102. package/stdlib/slices/slices.go +526 -0
  103. package/stdlib/slices/sort.go +209 -0
  104. package/stdlib/slices/zsort_cmp.go +480 -0
  105. package/stdlib/slices/zsort_ordered.go +482 -0
  106. package/stdlib/sort/sort.go +391 -452
  107. package/stdlib/sort/zsort_func.go +480 -0
  108. package/stdlib/sort/zsort_iface.go +480 -0
  109. package/stdlib/strconv/float.go +1699 -0
  110. package/stdlib/strconv/isprint.go +752 -0
  111. package/stdlib/strconv/quote.go +235 -50
  112. package/stdlib/strconv/strconv.go +616 -0
  113. package/stdlib/strings/builder.go +95 -0
  114. package/stdlib/strings/reader.go +163 -0
  115. package/stdlib/strings/replacer.go +102 -0
  116. package/stdlib/strings/strings.go +807 -0
  117. package/stdlib/sync/sync.go +268 -0
  118. package/stdlib/testing/async_js.go +61 -0
  119. package/stdlib/testing/benchmark.go +297 -0
  120. package/stdlib/testing/testing.go +523 -0
  121. package/stdlib/time/duration.go +233 -0
  122. package/stdlib/time/format.go +745 -0
  123. package/stdlib/time/parse.go +790 -0
  124. package/stdlib/time/sleep_js.go +63 -0
  125. package/stdlib/time/time.go +834 -0
  126. package/stdlib/unicode/unicode.go +141 -3
  127. package/stdlib/unicode/utf8/utf8.go +464 -0
  128. package/src/backend/js/fmt-runtime.js +0 -573
  129. package/src/backend/js/stdlib/base64.js +0 -12
  130. package/src/backend/js/stdlib/binary.js +0 -102
  131. package/src/backend/js/stdlib/bits.js +0 -119
  132. package/src/backend/js/stdlib/builder.js +0 -98
  133. package/src/backend/js/stdlib/bytes.js +0 -368
  134. package/src/backend/js/stdlib/errors.js +0 -45
  135. package/src/backend/js/stdlib/fmt.js +0 -517
  136. package/src/backend/js/stdlib/gom.js +0 -155
  137. package/src/backend/js/stdlib/hex.js +0 -17
  138. package/src/backend/js/stdlib/html.js +0 -20
  139. package/src/backend/js/stdlib/io.js +0 -137
  140. package/src/backend/js/stdlib/json.js +0 -1167
  141. package/src/backend/js/stdlib/maps.js +0 -37
  142. package/src/backend/js/stdlib/math.js +0 -85
  143. package/src/backend/js/stdlib/os.js +0 -13
  144. package/src/backend/js/stdlib/path.js +0 -48
  145. package/src/backend/js/stdlib/rand.js +0 -32
  146. package/src/backend/js/stdlib/regexp.js +0 -54
  147. package/src/backend/js/stdlib/sha256.js +0 -12
  148. package/src/backend/js/stdlib/shared.js +0 -17
  149. package/src/backend/js/stdlib/simd.js +0 -34
  150. package/src/backend/js/stdlib/slices.js +0 -107
  151. package/src/backend/js/stdlib/sort.js +0 -30
  152. package/src/backend/js/stdlib/strconv.js +0 -79
  153. package/src/backend/js/stdlib/strings.js +0 -301
  154. package/src/backend/js/stdlib/sync.js +0 -13
  155. package/src/backend/js/stdlib/testing.js +0 -41
  156. package/src/backend/js/stdlib/time.js +0 -152
  157. package/src/backend/js/stdlib/unicode.js +0 -25
  158. package/src/backend/js/stdlib/utf8.js +0 -26
  159. package/src/backend/wasm/stdlib/bytes.js +0 -6716
  160. package/src/backend/wasm/stdlib/core.js +0 -10278
  161. package/src/backend/wasm/stdlib/io.js +0 -3578
  162. package/src/backend/wasm/stdlib/packages.js +0 -2402
  163. package/src/backend/wasm/stdlib/pure.js +0 -720
  164. package/src/backend/wasm/stdlib/time.js +0 -2229
  165. package/src/typechecker/stdlib/core.js +0 -1079
  166. package/src/typechecker/stdlib/extended.js +0 -1210
  167. package/stdlib/bytes/iter.go +0 -192
  168. package/stdlib/bytes/search.go +0 -240
  169. package/stdlib/bytes/split.go +0 -218
  170. package/stdlib/errors/overlay.go +0 -12
  171. package/stdlib/maps/iter.go +0 -65
  172. package/stdlib/slices/extra.go +0 -73
  173. package/stdlib/slices/iter.go +0 -113
  174. package/stdlib/strings/extra.go +0 -35
  175. package/stdlib/strings/iter.go +0 -122
  176. package/stdlib/sync/extra.go +0 -105
  177. package/stdlib/unicode/utf8/bytes.go +0 -239
@@ -0,0 +1,293 @@
1
+ //go:build gofront
2
+
3
+ //gofront:target js
4
+
5
+ // Package gom builds DOM trees from Go values. A Node mounts itself into a
6
+ // parent element; templ components are Nodes too. It is only available to js
7
+ // packages and needs no import.
8
+ package gom
9
+
10
+ // A Node adds itself to the DOM element parent. refs, when not nil, is the
11
+ // map that `ref="key"` attributes of templ components fill with elements.
12
+ type Node interface {
13
+ Mount(parent any, refs any)
14
+ }
15
+
16
+ // NodeFunc adapts a function that mounts into an element to a Node.
17
+ type NodeFunc func(parent any)
18
+
19
+ func (f NodeFunc) Mount(parent any, refs any) {
20
+ f(parent)
21
+ }
22
+
23
+ // Group mounts its nodes one after another into the same parent.
24
+ type Group []Node
25
+
26
+ func (g Group) Mount(parent any, refs any) {
27
+ for _, n := range g {
28
+ if n != nil {
29
+ n.Mount(parent, refs)
30
+ }
31
+ }
32
+ }
33
+
34
+ type element struct {
35
+ tag string
36
+ children []Node
37
+ }
38
+
39
+ func (e *element) Mount(parent any, refs any) {
40
+ el := document.createElement(e.tag)
41
+ for _, c := range e.children {
42
+ if c != nil {
43
+ c.Mount(el, refs)
44
+ }
45
+ }
46
+ parent.appendChild(el)
47
+ }
48
+
49
+ type text struct{ s string }
50
+
51
+ func (t *text) Mount(parent any, refs any) {
52
+ parent.appendChild(document.createTextNode(t.s))
53
+ }
54
+
55
+ type attr struct{ name, value string }
56
+
57
+ func (a *attr) Mount(el any, refs any) {
58
+ el.setAttribute(a.name, a.value)
59
+ }
60
+
61
+ type prop struct{ name, value string }
62
+
63
+ func (p *prop) Mount(el any, refs any) {
64
+ el[p.name] = p.value
65
+ }
66
+
67
+ type style struct{ css string }
68
+
69
+ func (s *style) Mount(parent any, refs any) {
70
+ el := document.createElement("style")
71
+ el.textContent = s.css
72
+ parent.appendChild(el)
73
+ }
74
+
75
+ // El is an element with the given tag, attributes and children.
76
+ func El(tag string, children ...Node) Node {
77
+ return &element{tag: tag, children: children}
78
+ }
79
+
80
+ // Text is a text node.
81
+ func Text(s string) Node {
82
+ return &text{s: s}
83
+ }
84
+
85
+ // Attr sets an attribute.
86
+ func Attr(name, value string) Node {
87
+ return &attr{name: name, value: value}
88
+ }
89
+
90
+ // DataAttr sets the attribute data-<key>.
91
+ func DataAttr(key, value string) Node {
92
+ return &attr{name: "data-" + key, value: value}
93
+ }
94
+
95
+ // If is n when cond holds, and an empty node otherwise.
96
+ func If(cond bool, n Node) Node {
97
+ if cond {
98
+ return n
99
+ }
100
+ return Group{}
101
+ }
102
+
103
+ // Map applies f to every element of s; the nodes mount in order.
104
+ func Map[T any](s []T, f func(T) Node) Node {
105
+ g := make(Group, 0, len(s))
106
+ for _, v := range s {
107
+ g = append(g, f(v))
108
+ }
109
+ return g
110
+ }
111
+
112
+ // Style is a <style> element with the given CSS text.
113
+ func Style(css string) Node {
114
+ return &style{css: css}
115
+ }
116
+
117
+ func refOf(refs []any) any {
118
+ if len(refs) > 0 {
119
+ return refs[0]
120
+ }
121
+ return nil
122
+ }
123
+
124
+ // Mount replaces the content of the element matching the selector with node.
125
+ // The optional refs map receives the elements of templ `ref` attributes.
126
+ func Mount(sel string, node Node, refs ...any) {
127
+ el := document.querySelector(sel)
128
+ el.innerHTML = ""
129
+ node.Mount(el, refOf(refs))
130
+ }
131
+
132
+ // MountTo is like Mount but keeps the existing content.
133
+ func MountTo(sel string, node Node, refs ...any) {
134
+ node.Mount(document.querySelector(sel), refOf(refs))
135
+ }
136
+
137
+ // Elements.
138
+
139
+ func Div(children ...Node) Node { return El("div", children...) }
140
+
141
+ func Section(children ...Node) Node { return El("section", children...) }
142
+
143
+ func Article(children ...Node) Node { return El("article", children...) }
144
+
145
+ func Aside(children ...Node) Node { return El("aside", children...) }
146
+
147
+ func Header(children ...Node) Node { return El("header", children...) }
148
+
149
+ func Footer(children ...Node) Node { return El("footer", children...) }
150
+
151
+ func Main(children ...Node) Node { return El("main", children...) }
152
+
153
+ func Nav(children ...Node) Node { return El("nav", children...) }
154
+
155
+ func Figure(children ...Node) Node { return El("figure", children...) }
156
+
157
+ func H1(children ...Node) Node { return El("h1", children...) }
158
+
159
+ func H2(children ...Node) Node { return El("h2", children...) }
160
+
161
+ func H3(children ...Node) Node { return El("h3", children...) }
162
+
163
+ func H4(children ...Node) Node { return El("h4", children...) }
164
+
165
+ func H5(children ...Node) Node { return El("h5", children...) }
166
+
167
+ func H6(children ...Node) Node { return El("h6", children...) }
168
+
169
+ func Span(children ...Node) Node { return El("span", children...) }
170
+
171
+ func A(children ...Node) Node { return El("a", children...) }
172
+
173
+ func Strong(children ...Node) Node { return El("strong", children...) }
174
+
175
+ func Em(children ...Node) Node { return El("em", children...) }
176
+
177
+ func Code(children ...Node) Node { return El("code", children...) }
178
+
179
+ func Pre(children ...Node) Node { return El("pre", children...) }
180
+
181
+ func Small(children ...Node) Node { return El("small", children...) }
182
+
183
+ func Mark(children ...Node) Node { return El("mark", children...) }
184
+
185
+ func P(children ...Node) Node { return El("p", children...) }
186
+
187
+ func Br(children ...Node) Node { return El("br", children...) }
188
+
189
+ func Hr(children ...Node) Node { return El("hr", children...) }
190
+
191
+ func Ul(children ...Node) Node { return El("ul", children...) }
192
+
193
+ func Ol(children ...Node) Node { return El("ol", children...) }
194
+
195
+ func Li(children ...Node) Node { return El("li", children...) }
196
+
197
+ func Dl(children ...Node) Node { return El("dl", children...) }
198
+
199
+ func Dt(children ...Node) Node { return El("dt", children...) }
200
+
201
+ func Dd(children ...Node) Node { return El("dd", children...) }
202
+
203
+ func Form(children ...Node) Node { return El("form", children...) }
204
+
205
+ func Input(children ...Node) Node { return El("input", children...) }
206
+
207
+ func Button(children ...Node) Node { return El("button", children...) }
208
+
209
+ func Textarea(children ...Node) Node { return El("textarea", children...) }
210
+
211
+ func Select(children ...Node) Node { return El("select", children...) }
212
+
213
+ func Option(children ...Node) Node { return El("option", children...) }
214
+
215
+ func Label(children ...Node) Node { return El("label", children...) }
216
+
217
+ func Fieldset(children ...Node) Node { return El("fieldset", children...) }
218
+
219
+ func Legend(children ...Node) Node { return El("legend", children...) }
220
+
221
+ func Img(children ...Node) Node { return El("img", children...) }
222
+
223
+ func Video(children ...Node) Node { return El("video", children...) }
224
+
225
+ func Audio(children ...Node) Node { return El("audio", children...) }
226
+
227
+ func Canvas(children ...Node) Node { return El("canvas", children...) }
228
+
229
+ func Table(children ...Node) Node { return El("table", children...) }
230
+
231
+ func Thead(children ...Node) Node { return El("thead", children...) }
232
+
233
+ func Tbody(children ...Node) Node { return El("tbody", children...) }
234
+
235
+ func Tfoot(children ...Node) Node { return El("tfoot", children...) }
236
+
237
+ func Tr(children ...Node) Node { return El("tr", children...) }
238
+
239
+ func Th(children ...Node) Node { return El("th", children...) }
240
+
241
+ func Td(children ...Node) Node { return El("td", children...) }
242
+
243
+ // Attributes.
244
+
245
+ func For(v string) Node { return Attr("for", v) }
246
+
247
+ func Name(v string) Node { return Attr("name", v) }
248
+
249
+ func Value(v string) Node { return Attr("value", v) }
250
+
251
+ func Target(v string) Node { return Attr("target", v) }
252
+
253
+ func Rel(v string) Node { return Attr("rel", v) }
254
+
255
+ func Alt(v string) Node { return Attr("alt", v) }
256
+
257
+ func Title(v string) Node { return Attr("title", v) }
258
+
259
+ func Lang(v string) Node { return Attr("lang", v) }
260
+
261
+ func Action(v string) Node { return Attr("action", v) }
262
+
263
+ func Method(v string) Node { return Attr("method", v) }
264
+
265
+ func AutoComplete(v string) Node { return Attr("autocomplete", v) }
266
+
267
+ func Draggable(v string) Node { return Attr("draggable", v) }
268
+
269
+ func Role(v string) Node { return Attr("role", v) }
270
+
271
+ func StyleAttr(v string) Node { return Attr("style", v) }
272
+
273
+ func AriaLabel(v string) Node { return Attr("aria-label", v) }
274
+
275
+ func Disabled() Node { return Attr("disabled", "") }
276
+
277
+ func Checked() Node { return Attr("checked", "") }
278
+
279
+ func Selected() Node { return Attr("selected", "") }
280
+
281
+ func Readonly() Node { return Attr("readonly", "") }
282
+
283
+ // Properties.
284
+
285
+ func Class(v string) Node { return &prop{name: "className", value: v} }
286
+
287
+ func Type(v string) Node { return &prop{name: "type", value: v} }
288
+
289
+ func Href(v string) Node { return &prop{name: "href", value: v} }
290
+
291
+ func Src(v string) Node { return &prop{name: "src", value: v} }
292
+
293
+ func Placeholder(v string) Node { return &prop{name: "placeholder", value: v} }
@@ -0,0 +1,251 @@
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 html provides functions for escaping and unescaping HTML text.
10
+ //
11
+ // UnescapeString follows Go's algorithm for numeric references (including the
12
+ // Windows-1252 replacement table) and for named references without a
13
+ // semicolon, but knows a subset of Go's 2,231 entity names: the five that
14
+ // EscapeString produces and apos, the 96 HTML 4 Latin-1 names (nbsp through
15
+ // yuml) and these others: euro, hellip, mdash, ndash, lsquo, rsquo, sbquo,
16
+ // ldquo, rdquo, bdquo, bull, trade, larr, rarr, uarr, darr, harr, hearts,
17
+ // spades, clubs and diams. An unknown name is left as it is.
18
+ package html
19
+
20
+ var replacementTable = [...]rune{
21
+ '\u20AC', // First entry is what 0x80 should be replaced with.
22
+ '\u0081',
23
+ '\u201A',
24
+ '\u0192',
25
+ '\u201E',
26
+ '\u2026',
27
+ '\u2020',
28
+ '\u2021',
29
+ '\u02C6',
30
+ '\u2030',
31
+ '\u0160',
32
+ '\u2039',
33
+ '\u0152',
34
+ '\u008D',
35
+ '\u017D',
36
+ '\u008F',
37
+ '\u0090',
38
+ '\u2018',
39
+ '\u2019',
40
+ '\u201C',
41
+ '\u201D',
42
+ '\u2022',
43
+ '\u2013',
44
+ '\u2014',
45
+ '\u02DC',
46
+ '\u2122',
47
+ '\u0161',
48
+ '\u203A',
49
+ '\u0153',
50
+ '\u009D',
51
+ '\u017E',
52
+ '\u0178', // Last entry is 0x9F.
53
+ // 0x00->'\uFFFD' is handled programmatically.
54
+ // 0x0D->'\u000D' is a no-op.
55
+ }
56
+
57
+ // latin1 holds the HTML 4 names of the runes U+00A0 through U+00FF, in order.
58
+ var latin1 = [...]string{
59
+ "nbsp", "iexcl", "cent", "pound", "curren", "yen", "brvbar", "sect",
60
+ "uml", "copy", "ordf", "laquo", "not", "shy", "reg", "macr",
61
+ "deg", "plusmn", "sup2", "sup3", "acute", "micro", "para", "middot",
62
+ "cedil", "sup1", "ordm", "raquo", "frac14", "frac12", "frac34", "iquest",
63
+ "Agrave", "Aacute", "Acirc", "Atilde", "Auml", "Aring", "AElig", "Ccedil",
64
+ "Egrave", "Eacute", "Ecirc", "Euml", "Igrave", "Iacute", "Icirc", "Iuml",
65
+ "ETH", "Ntilde", "Ograve", "Oacute", "Ocirc", "Otilde", "Ouml", "times",
66
+ "Oslash", "Ugrave", "Uacute", "Ucirc", "Uuml", "Yacute", "THORN", "szlig",
67
+ "agrave", "aacute", "acirc", "atilde", "auml", "aring", "aelig", "ccedil",
68
+ "egrave", "eacute", "ecirc", "euml", "igrave", "iacute", "icirc", "iuml",
69
+ "eth", "ntilde", "ograve", "oacute", "ocirc", "otilde", "ouml", "divide",
70
+ "oslash", "ugrave", "uacute", "ucirc", "uuml", "yacute", "thorn", "yuml",
71
+ }
72
+
73
+ // longestEntityWithoutSemicolon is the length of the longest name that may
74
+ // appear without its closing semicolon.
75
+ const longestEntityWithoutSemicolon = 6
76
+
77
+ // entities is the entity table: every name with its semicolon, and the
78
+ // legacy names (the Latin-1 ones, amp, lt, gt and quot) without it too.
79
+ var entities = makeEntities()
80
+
81
+ func makeEntities() map[string]rune {
82
+ m := make(map[string]rune)
83
+ for i, name := range latin1 {
84
+ m[name+";"] = rune(0xA0 + i)
85
+ m[name] = rune(0xA0 + i)
86
+ }
87
+ for name, r := range map[string]rune{"amp": '&', "lt": '<', "gt": '>', "quot": '"'} {
88
+ m[name+";"] = r
89
+ m[name] = r
90
+ }
91
+ for name, r := range map[string]rune{
92
+ "apos": '\'', "euro": 0x20AC, "hellip": 0x2026, "mdash": 0x2014,
93
+ "ndash": 0x2013, "lsquo": 0x2018, "rsquo": 0x2019, "sbquo": 0x201A,
94
+ "ldquo": 0x201C, "rdquo": 0x201D, "bdquo": 0x201E, "bull": 0x2022,
95
+ "trade": 0x2122, "larr": 0x2190, "uarr": 0x2191, "rarr": 0x2192,
96
+ "darr": 0x2193, "harr": 0x2194, "spades": 0x2660, "clubs": 0x2663,
97
+ "hearts": 0x2665, "diams": 0x2666,
98
+ } {
99
+ m[name+";"] = r
100
+ }
101
+ return m
102
+ }
103
+
104
+ // unescapeEntity reads an entity like "&lt;" at the start of s (s[0] is '&')
105
+ // and returns the text it stands for and how many code units it spans. A
106
+ // reference it does not know stands for itself, one unit long.
107
+ func unescapeEntity(s string) (text string, n int) {
108
+ if len(s) <= 1 {
109
+ return "&", 1
110
+ }
111
+ i := 1
112
+ if s[i] == '#' {
113
+ if len(s) <= 3 { // We need to have at least "&#.".
114
+ return "&", 1
115
+ }
116
+ i++
117
+ c := s[i]
118
+ hex := false
119
+ if c == 'x' || c == 'X' {
120
+ hex = true
121
+ i++
122
+ }
123
+
124
+ var x rune
125
+ for i < len(s) {
126
+ c = s[i]
127
+ i++
128
+ if hex {
129
+ if '0' <= c && c <= '9' {
130
+ x = 16*x + rune(c) - '0'
131
+ continue
132
+ } else if 'a' <= c && c <= 'f' {
133
+ x = 16*x + rune(c) - 'a' + 10
134
+ continue
135
+ } else if 'A' <= c && c <= 'F' {
136
+ x = 16*x + rune(c) - 'A' + 10
137
+ continue
138
+ }
139
+ } else if '0' <= c && c <= '9' {
140
+ x = 10*x + rune(c) - '0'
141
+ continue
142
+ }
143
+ if c != ';' {
144
+ i--
145
+ }
146
+ break
147
+ }
148
+
149
+ if i <= 3 { // No characters matched.
150
+ return "&", 1
151
+ }
152
+
153
+ if 0x80 <= x && x <= 0x9F {
154
+ // Replace characters from Windows-1252 with UTF-8 equivalents.
155
+ x = replacementTable[x-0x80]
156
+ } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x < 0 || x > 0x10FFFF {
157
+ // Replace invalid characters with the replacement character.
158
+ x = '\uFFFD'
159
+ }
160
+ return string(x), i
161
+ }
162
+
163
+ // Consume the maximum number of characters possible, with the
164
+ // consumed characters matching one of the named references.
165
+ for i < len(s) {
166
+ c := s[i]
167
+ i++
168
+ if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
169
+ continue
170
+ }
171
+ if c != ';' {
172
+ i--
173
+ }
174
+ break
175
+ }
176
+
177
+ entityName := s[1:i]
178
+ if len(entityName) == 0 {
179
+ return "&", 1
180
+ }
181
+ entity := entities
182
+ if x := entity[entityName]; x != 0 {
183
+ return string(x), i
184
+ }
185
+ maxLen := len(entityName) - 1
186
+ if maxLen > longestEntityWithoutSemicolon {
187
+ maxLen = longestEntityWithoutSemicolon
188
+ }
189
+ for j := maxLen; j > 1; j-- {
190
+ if x := entity[entityName[:j]]; x != 0 {
191
+ return string(x), j + 1
192
+ }
193
+ }
194
+ return s[:i], i
195
+ }
196
+
197
+ // EscapeString escapes special characters like "<" to become "&lt;". It
198
+ // escapes only five such characters: <, >, &, ' and ".
199
+ // [UnescapeString](EscapeString(s)) == s always holds, but the converse isn't
200
+ // always true.
201
+ func EscapeString(s string) string {
202
+ out := ""
203
+ last := 0
204
+ for i := 0; i < len(s); i++ {
205
+ var rep string
206
+ switch s[i] {
207
+ case '&':
208
+ rep = "&amp;"
209
+ case '\'':
210
+ rep = "&#39;" // "&#39;" is shorter than "&apos;" and apos was not in HTML until HTML5.
211
+ case '<':
212
+ rep = "&lt;"
213
+ case '>':
214
+ rep = "&gt;"
215
+ case '"':
216
+ rep = "&#34;" // "&#34;" is shorter than "&quot;".
217
+ default:
218
+ continue
219
+ }
220
+ out += s[last:i] + rep
221
+ last = i + 1
222
+ }
223
+ if last == 0 {
224
+ return s
225
+ }
226
+ return out + s[last:]
227
+ }
228
+
229
+ // UnescapeString unescapes entities like "&lt;" to become "<". It unescapes a
230
+ // larger range of entities than [EscapeString] escapes. For example, "&aacute;"
231
+ // unescapes to "á", as does "&#225;" and "&#xE1;".
232
+ // UnescapeString([EscapeString](s)) == s always holds, but the converse isn't
233
+ // always true.
234
+ func UnescapeString(s string) string {
235
+ out := ""
236
+ last := 0
237
+ for i := 0; i < len(s); {
238
+ if s[i] != '&' {
239
+ i++
240
+ continue
241
+ }
242
+ text, n := unescapeEntity(s[i:])
243
+ out += s[last:i] + text
244
+ i += n
245
+ last = i
246
+ }
247
+ if last == 0 {
248
+ return s
249
+ }
250
+ return out + s[last:]
251
+ }
@@ -0,0 +1,163 @@
1
+ //go:build gofront
2
+
3
+ //gofront:target both
4
+
5
+ // Package fmtrt is the contract between package fmt and the code the
6
+ // compiler generates for each package that formats values.
7
+ //
8
+ // Go's fmt learns the type of every operand by reflection. Here the compiler
9
+ // knows it statically: it describes an operand as an Arg (a kind, the value
10
+ // in a field of that kind, and closures that reach the parts of a composite)
11
+ // and fmt only reads the description. An operand that arrives through an
12
+ // interface is described by the lookups packages register with Register.
13
+ package fmtrt
14
+
15
+ // The kinds of an Arg.
16
+ const (
17
+ KNone = iota // not described: format the value in V
18
+ KBool // B
19
+ KInt // I, any signed integer type
20
+ KUint // U, any unsigned integer type
21
+ KFloat // R, any float type
22
+ KComplex // R and Im, any complex type
23
+ KString // S
24
+ KStruct // N fields, Field
25
+ KPtr // Nil, Ptr, Inner
26
+ KSlice // Nil, N elements, Elem
27
+ KArray // N elements, Elem
28
+ KMap // Nil, N entries, Entries
29
+ KFunc // Nil, Ptr
30
+ KInterface // V holds the operand, formatted by its dynamic type
31
+ KChan // Nil, Ptr
32
+ KUnsafePtr // Nil, Ptr
33
+ )
34
+
35
+ // Stringer, GoStringer and Error-only views of a value, kept apart from
36
+ // package fmt so that the generated code needs only this package.
37
+ type Stringer interface {
38
+ String() string
39
+ }
40
+
41
+ type GoStringer interface {
42
+ GoString() string
43
+ }
44
+
45
+ // Arg describes one operand.
46
+ type Arg struct {
47
+ K int // the kind, one of the K constants
48
+ Size int // the bit size of a number (8, 16, 32, 64 or 0 for int, uint and uintptr)
49
+ T string // the Go type, as %T prints it
50
+ B bool
51
+ I int64
52
+ U uint64
53
+ R float64
54
+ Im float64
55
+ S string
56
+ V any // the operand itself, when K is KNone or KInterface
57
+
58
+ // The methods of the static type that fmt calls. They are set only
59
+ // where Go would call them: the type's method set holds the method and,
60
+ // for a struct field, the field is exported.
61
+ Err error
62
+ Str Stringer
63
+ GoStr GoStringer
64
+
65
+ Nil bool
66
+ N int
67
+ Ptr any
68
+ Boxed bool // Ptr is a pointer to a scalar, boxed anew each time it is put in an Arg
69
+ IsBytes bool // a []byte or [N]byte, whose elements are in Bytes
70
+ Bytes []byte
71
+ Field func(i int) (string, Arg) // the name and value of field i
72
+ Elem func(i int) Arg // element i
73
+ Entries func() []Entry // the entries of a map
74
+ Inner func() Arg // what a non-nil pointer points to
75
+ }
76
+
77
+ // Entry is one key and value of a map.
78
+ type Entry struct {
79
+ Key Arg
80
+ Val Arg
81
+ }
82
+
83
+ type registry struct {
84
+ keys []string
85
+ lookups []func(v any) (Arg, bool)
86
+ scalars []numbered
87
+ }
88
+
89
+ // numbered is a pointer to a scalar that has been given an id; same reports
90
+ // whether a value is that pointer.
91
+ type numbered struct {
92
+ same func(v any) bool
93
+ id uint64
94
+ }
95
+
96
+ var reg = &registry{}
97
+
98
+ func (r *registry) add(key string, f func(v any) (Arg, bool)) {
99
+ for _, k := range r.keys {
100
+ if k == key {
101
+ return
102
+ }
103
+ }
104
+ r.keys = append(r.keys, key)
105
+ r.lookups = append(r.lookups, f)
106
+ }
107
+
108
+ // Register adds a package's lookup, which describes the values of that
109
+ // package's types held in an interface. A key registers once, so a call may
110
+ // be repeated: it identifies the lookup, and it returns true so that it can
111
+ // initialise a package-level variable.
112
+ func Register(key string, f func(v any) (Arg, bool)) bool {
113
+ reg.add(key, f)
114
+ return true
115
+ }
116
+
117
+ // Lookup describes a value held in an interface by asking each registered
118
+ // lookup in turn.
119
+ func Lookup(v any) (Arg, bool) {
120
+ for _, f := range reg.lookups {
121
+ if a, ok := f(v); ok {
122
+ return a, true
123
+ }
124
+ }
125
+ return Arg{}, false
126
+ }
127
+
128
+ // PtrID returns a number that identifies the pointer, function or other
129
+ // reference v; 0 for nil.
130
+ func PtrID(v any) uint64 {
131
+ if v == nil {
132
+ return 0
133
+ }
134
+ return ptrID(v)
135
+ }
136
+
137
+ // ArgPtrID returns the identity number of the pointer, function or channel
138
+ // that a holds. A pointer to a scalar is boxed anew each time it is put in an
139
+ // Arg and the host would see a different object, so those are matched by
140
+ // equality against the ones already numbered.
141
+ func ArgPtrID(a Arg) uint64 {
142
+ if !a.Boxed {
143
+ return PtrID(a.Ptr)
144
+ }
145
+ p := a.Ptr
146
+ for _, n := range reg.scalars {
147
+ if n.same(p) {
148
+ return n.id
149
+ }
150
+ }
151
+ id := PtrID(p)
152
+ reg.remember(p, id)
153
+ return id
154
+ }
155
+
156
+ func (r *registry) remember(p any, id uint64) {
157
+ r.scalars = append(r.scalars, numbered{func(v any) bool { return v == p }, id})
158
+ }
159
+
160
+ // ptrID is the host's stable identity number for an object.
161
+ //
162
+ //gofront:intrinsic fmt_ptr_id
163
+ func ptrID(v any) uint64