From 7f39d04ca837304128298dcdc4755d5aad778b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lker=20G=2E=20=C3=96zt=C3=BCrk?= Date: Wed, 2 Oct 2024 18:09:40 +0300 Subject: [PATCH 01/20] chore(codeowners): add codeowners for boardsv2 (#2883) Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> Co-authored-by: Morgan --- .github/CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f13ce49ef45..3870ff30539 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -26,6 +26,7 @@ /examples/gno.land/p/demo/avl/ @jaekwon /examples/gno.land/p/demo/bf/ @moul /examples/gno.land/p/demo/blog/ @gnolang/devrels +/examples/gno.land/p/demo/boardsv2/ @ilgooz @jeronimoalbi @moul /examples/gno.land/p/demo/cford32/ @thehowl /examples/gno.land/p/demo/memeland/ @leohhhn /examples/gno.land/p/demo/seqid/ @thehowl @@ -36,6 +37,7 @@ /examples/gno.land/p/demo/ui/ @moul /examples/gno.land/r/demo/ @gnolang/tech-staff @gnolang/devrels /examples/gno.land/r/demo/art/ @moul +/examples/gno.land/r/demo/boardsv2/ @ilgooz @jeronimoalbi @moul /examples/gno.land/r/demo/memeland/ @leohhhn /examples/gno.land/r/demo/tamagotchi/ @moul /examples/gno.land/r/demo/userbook/ @leohhhn From ee2b1fa13189e728e410cbe42809caae8ec57efa Mon Sep 17 00:00:00 2001 From: SunSpirit <48086732+sunspirit99@users.noreply.github.com> Date: Thu, 3 Oct 2024 00:03:27 +0700 Subject: [PATCH 02/20] test(gno.land/sdk/vm): add unit tests for `Msg*.ValidateBasic` (#2855) The `vm Msg` is not yet covered by unit tests
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--------- Co-authored-by: Morgan --- gno.land/pkg/sdk/vm/msg_test.go | 271 ++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 gno.land/pkg/sdk/vm/msg_test.go diff --git a/gno.land/pkg/sdk/vm/msg_test.go b/gno.land/pkg/sdk/vm/msg_test.go new file mode 100644 index 00000000000..eaaaa0f0ab2 --- /dev/null +++ b/gno.land/pkg/sdk/vm/msg_test.go @@ -0,0 +1,271 @@ +package vm + +import ( + "testing" + + "github.com/gnolang/gno/tm2/pkg/crypto" + "github.com/gnolang/gno/tm2/pkg/std" + "github.com/stretchr/testify/assert" +) + +func TestMsgAddPackage_ValidateBasic(t *testing.T) { + t.Parallel() + + creator := crypto.AddressFromPreimage([]byte("addr1")) + pkgName := "test" + pkgPath := "gno.land/r/namespace/test" + files := []*std.MemFile{ + { + Name: "test.gno", + Body: `package test + func Echo() string {return "hello world"}`, + }, + } + + tests := []struct { + name string + msg MsgAddPackage + expectSignBytes string + expectErr error + }{ + { + name: "valid message", + msg: NewMsgAddPackage(creator, pkgPath, files), + expectSignBytes: `{"creator":"g14ch5q26mhx3jk5cxl88t278nper264ces4m8nt","deposit":"",` + + `"package":{"files":[{"body":"package test\n\t\tfunc Echo() string {return \"hello world\"}",` + + `"name":"test.gno"}],"name":"test","path":"gno.land/r/namespace/test"}}`, + expectErr: nil, + }, + { + name: "missing creator address", + msg: MsgAddPackage{ + Creator: crypto.Address{}, + Package: &std.MemPackage{ + Name: pkgName, + Path: pkgPath, + Files: files, + }, + Deposit: std.Coins{std.Coin{ + Denom: "ugnot", + Amount: 1000, + }}, + }, + expectErr: std.InvalidAddressError{}, + }, + { + name: "missing package path", + msg: MsgAddPackage{ + Creator: creator, + Package: &std.MemPackage{ + Name: pkgName, + Path: "", + Files: files, + }, + Deposit: std.Coins{std.Coin{ + Denom: "ugnot", + Amount: 1000, + }}, + }, + expectErr: InvalidPkgPathError{}, + }, + { + name: "invalid deposit coins", + msg: MsgAddPackage{ + Creator: creator, + Package: &std.MemPackage{ + Name: pkgName, + Path: pkgPath, + Files: files, + }, + Deposit: std.Coins{std.Coin{ + Denom: "ugnot", + Amount: -1000, // invalid amount + }}, + }, + expectErr: std.InvalidCoinsError{}, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + if err := tc.msg.ValidateBasic(); err != nil { + assert.ErrorIs(t, err, tc.expectErr) + } else { + assert.Equal(t, tc.expectSignBytes, string(tc.msg.GetSignBytes())) + } + }) + } +} + +func TestMsgCall_ValidateBasic(t *testing.T) { + t.Parallel() + + caller := crypto.AddressFromPreimage([]byte("addr1")) + pkgPath := "gno.land/r/namespace/test" + funcName := "MyFunction" + args := []string{"arg1", "arg2"} + + tests := []struct { + name string + msg MsgCall + expectSignBytes string + expectErr error + }{ + { + name: "valid message", + msg: NewMsgCall(caller, std.NewCoins(std.NewCoin("ugnot", 1000)), pkgPath, funcName, args), + expectSignBytes: `{"args":["arg1","arg2"],"caller":"g14ch5q26mhx3jk5cxl88t278nper264ces4m8nt",` + + `"func":"MyFunction","pkg_path":"gno.land/r/namespace/test","send":"1000ugnot"}`, + expectErr: nil, + }, + { + name: "invalid caller address", + msg: MsgCall{ + Caller: crypto.Address{}, + PkgPath: pkgPath, + Func: funcName, + Args: args, + Send: std.Coins{std.Coin{ + Denom: "ugnot", + Amount: 1000, + }}, + }, + expectErr: std.InvalidAddressError{}, + }, + { + name: "missing package path", + msg: MsgCall{ + Caller: caller, + PkgPath: "", + Func: funcName, + Args: args, + Send: std.Coins{std.Coin{ + Denom: "ugnot", + Amount: 1000, + }}, + }, + expectErr: InvalidPkgPathError{}, + }, + { + name: "pkgPath should not be a realm path", + msg: MsgCall{ + Caller: caller, + PkgPath: "gno.land/p/namespace/test", // this is not a valid realm path + Func: funcName, + Args: args, + Send: std.Coins{std.Coin{ + Denom: "ugnot", + Amount: 1000, + }}, + }, + expectErr: InvalidPkgPathError{}, + }, + { + name: "missing function name to call", + msg: MsgCall{ + Caller: caller, + PkgPath: pkgPath, + Func: "", + Args: args, + Send: std.Coins{std.Coin{ + Denom: "ugnot", + Amount: 1000, + }}, + }, + expectErr: InvalidExprError{}, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + if err := tc.msg.ValidateBasic(); err != nil { + assert.ErrorIs(t, err, tc.expectErr) + } else { + assert.Equal(t, tc.expectSignBytes, string(tc.msg.GetSignBytes())) + } + }) + } +} + +func TestMsgRun_ValidateBasic(t *testing.T) { + t.Parallel() + + caller := crypto.AddressFromPreimage([]byte("addr1")) + pkgName := "main" + pkgPath := "gno.land/r/" + caller.String() + "/run" + pkgFiles := []*std.MemFile{ + { + Name: "main.gno", + Body: `package main + func Echo() string {return "hello world"}`, + }, + } + + tests := []struct { + name string + msg MsgRun + expectSignBytes string + expectErr error + }{ + { + name: "valid message", + msg: NewMsgRun(caller, std.NewCoins(std.NewCoin("ugnot", 1000)), pkgFiles), + expectSignBytes: `{"caller":"g14ch5q26mhx3jk5cxl88t278nper264ces4m8nt",` + + `"package":{"files":[{"body":"package main\n\t\tfunc Echo() string {return \"hello world\"}",` + + `"name":"main.gno"}],"name":"main","path":""},` + + `"send":"1000ugnot"}`, + expectErr: nil, + }, + { + name: "invalid caller address", + msg: MsgRun{ + Caller: crypto.Address{}, + Package: &std.MemPackage{ + Name: pkgName, + Path: pkgPath, + Files: pkgFiles, + }, + Send: std.Coins{std.Coin{ + Denom: "ugnot", + Amount: 1000, + }}, + }, + expectErr: std.InvalidAddressError{}, + }, + { + name: "invalid package path", + msg: MsgRun{ + Caller: caller, + Package: &std.MemPackage{ + Name: pkgName, + Path: "gno.land/r/namespace/test", // this is not a valid run path + Files: pkgFiles, + }, + Send: std.Coins{std.Coin{ + Denom: "ugnot", + Amount: 1000, + }}, + }, + expectErr: InvalidPkgPathError{}, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + if err := tc.msg.ValidateBasic(); err != nil { + assert.ErrorIs(t, err, tc.expectErr) + } else { + assert.Equal(t, tc.expectSignBytes, string(tc.msg.GetSignBytes())) + } + }) + } +} From a2b4d4b39349474b5d1b61be018aa820d644a009 Mon Sep 17 00:00:00 2001 From: Miguel Victoria Villaquiran Date: Wed, 2 Oct 2024 23:31:31 +0200 Subject: [PATCH 03/20] feat(stdlibs): add strings.Replacer (#2816) prerequisite of #2802 This pull request ports the files: - replace.go - replace_test.go from the Golang standard library. I added some tags on the code with the hope it will help to review the code and to launch discussion if neccessary. I could after remove these changes ```go // Custom code: XXX_Some_Explanation ( code not present on the original go file) . . . // End of custom code ```
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- gnovm/stdlibs/strings/printtrie_test.gno | 102 ++++ gnovm/stdlibs/strings/replace.gno | 587 +++++++++++++++++++++++ gnovm/stdlibs/strings/replace_test.gno | 511 ++++++++++++++++++++ 3 files changed, 1200 insertions(+) create mode 100644 gnovm/stdlibs/strings/printtrie_test.gno create mode 100644 gnovm/stdlibs/strings/replace.gno create mode 100644 gnovm/stdlibs/strings/replace_test.gno diff --git a/gnovm/stdlibs/strings/printtrie_test.gno b/gnovm/stdlibs/strings/printtrie_test.gno new file mode 100644 index 00000000000..b5b387b9bca --- /dev/null +++ b/gnovm/stdlibs/strings/printtrie_test.gno @@ -0,0 +1,102 @@ +package strings + +import ( + "testing" +) + +func (r *Replacer) PrintTrie() string { + r.buildOnce() + gen := r.r.(*genericReplacer) + return gen.printNode(&gen.root, 0) +} + +func (r *genericReplacer) printNode(t *trieNode, depth int) (s string) { + if t.priority > 0 { + s += "+" + } else { + s += "-" + } + s += "\n" + + if t.prefix != "" { + s += Repeat(".", depth) + t.prefix + s += r.printNode(t.next, depth+len(t.prefix)) + } else if t.table != nil { + for b, m := range r.mapping { + if int(m) != r.tableSize && t.table[m] != nil { + s += Repeat(".", depth) + string([]byte{byte(b)}) + s += r.printNode(t.table[m], depth+1) + } + } + } + return +} + +func TestGenericTrieBuilding(t *testing.T) { + testCases := []struct{ in, out string }{ + {"abc;abdef;abdefgh;xx;xy;z", `- + a- + .b- + ..c+ + ..d- + ...ef+ + .....gh+ + x- + .x+ + .y+ + z+ + `}, + {"abracadabra;abracadabrakazam;abraham;abrasion", `- + a- + .bra- + ....c- + .....adabra+ + ...........kazam+ + ....h- + .....am+ + ....s- + .....ion+ + `}, + {"aaa;aa;a;i;longerst;longer;long;xx;x;X;Y", `- + X+ + Y+ + a+ + .a+ + ..a+ + i+ + l- + .ong+ + ....er+ + ......st+ + x+ + .x+ + `}, + {"foo;;foo;foo1", `+ + f- + .oo+ + ...1+ + `}, + } + + for _, tc := range testCases { + keys := Split(tc.in, ";") + args := make([]string, len(keys)*2) + for i, key := range keys { + args[i*2] = key + } + + got := NewReplacer(args...).PrintTrie() + // Remove tabs from tc.out + wantbuf := make([]byte, 0, len(tc.out)) + for i := 0; i < len(tc.out); i++ { + if tc.out[i] != '\t' { + wantbuf = append(wantbuf, tc.out[i]) + } + } + want := string(wantbuf) + + if got != want { + t.Errorf("PrintTrie(%q)\ngot\n%swant\n%s", tc.in, got, want) + } + } +} diff --git a/gnovm/stdlibs/strings/replace.gno b/gnovm/stdlibs/strings/replace.gno new file mode 100644 index 00000000000..98a47ad3f81 --- /dev/null +++ b/gnovm/stdlibs/strings/replace.gno @@ -0,0 +1,587 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings + +import ( + "io" +) + +// Replacer replaces a list of strings with replacements. +// It is safe for concurrent use by multiple goroutines. +type Replacer struct { + // Custom code: remove variable once of type sync.Once on golang package + // End of custom code + r replacer + oldnew []string +} + +// replacer is the interface that a replacement algorithm needs to implement. +type replacer interface { + Replace(s string) string + WriteString(w io.Writer, s string) (n int, err error) +} + +// NewReplacer returns a new [Replacer] from a list of old, new string +// pairs. Replacements are performed in the order they appear in the +// target string, without overlapping matches. The old string +// comparisons are done in argument order. +// +// NewReplacer panics if given an odd number of arguments. +func NewReplacer(oldnew ...string) *Replacer { + if len(oldnew)%2 == 1 { + panic("strings.NewReplacer: odd argument count") + } + return &Replacer{oldnew: append([]string(nil), oldnew...)} +} + +func (r *Replacer) buildOnce() { + // Custom code: check replacer is null instead of call sync.Once + if r.r != nil { + return + } + // End of custom code + r.r = r.build() + r.oldnew = nil +} + +func (b *Replacer) build() replacer { + oldnew := b.oldnew + if len(oldnew) == 2 && len(oldnew[0]) > 1 { + return makeSingleStringReplacer(oldnew[0], oldnew[1]) + } + + allNewBytes := true + for i := 0; i < len(oldnew); i += 2 { + if len(oldnew[i]) != 1 { + return makeGenericReplacer(oldnew) + } + if len(oldnew[i+1]) != 1 { + allNewBytes = false + } + } + + if allNewBytes { + r := byteReplacer{} + for i := range r { + r[i] = byte(i) + } + // The first occurrence of old->new map takes precedence + // over the others with the same old string. + for i := len(oldnew) - 2; i >= 0; i -= 2 { + o := oldnew[i][0] + n := oldnew[i+1][0] + r[o] = n + } + return &r + } + + r := byteStringReplacer{toReplace: make([]string, 0, len(oldnew)/2)} + // The first occurrence of old->new map takes precedence + // over the others with the same old string. + for i := len(oldnew) - 2; i >= 0; i -= 2 { + o := oldnew[i][0] + n := oldnew[i+1] + // To avoid counting repetitions multiple times. + if r.replacements[o] == nil { + // We need to use string([]byte{o}) instead of string(o), + // to avoid utf8 encoding of o. + // E. g. byte(150) produces string of length 2. + r.toReplace = append(r.toReplace, string([]byte{o})) + } + r.replacements[o] = []byte(n) + + } + return &r +} + +// Replace returns a copy of s with all replacements performed. +func (r *Replacer) Replace(s string) string { + // Custom code: adaptation without sync.Once + r.buildOnce() + // End of custom code + return r.r.Replace(s) +} + +// WriteString writes s to w with all replacements performed. +func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error) { + // Custom code: adaptation without sync.Once + r.buildOnce() + // End of custom code + return r.r.WriteString(w, s) +} + +// trieNode is a node in a lookup trie for prioritized key/value pairs. Keys +// and values may be empty. For example, the trie containing keys "ax", "ay", +// "bcbc", "x" and "xy" could have eight nodes: +// +// n0 - +// n1 a- +// n2 .x+ +// n3 .y+ +// n4 b- +// n5 .cbc+ +// n6 x+ +// n7 .y+ +// +// n0 is the root node, and its children are n1, n4 and n6; n1's children are +// n2 and n3; n4's child is n5; n6's child is n7. Nodes n0, n1 and n4 (marked +// with a trailing "-") are partial keys, and nodes n2, n3, n5, n6 and n7 +// (marked with a trailing "+") are complete keys. +type trieNode struct { + // value is the value of the trie node's key/value pair. It is empty if + // this node is not a complete key. + value string + // priority is the priority (higher is more important) of the trie node's + // key/value pair; keys are not necessarily matched shortest- or longest- + // first. Priority is positive if this node is a complete key, and zero + // otherwise. In the example above, positive/zero priorities are marked + // with a trailing "+" or "-". + priority int + + // A trie node may have zero, one or more child nodes: + // * if the remaining fields are zero, there are no children. + // * if prefix and next are non-zero, there is one child in next. + // * if table is non-zero, it defines all the children. + // + // Prefixes are preferred over tables when there is one child, but the + // root node always uses a table for lookup efficiency. + + // prefix is the difference in keys between this trie node and the next. + // In the example above, node n4 has prefix "cbc" and n4's next node is n5. + // Node n5 has no children and so has zero prefix, next and table fields. + prefix string + next *trieNode + + // table is a lookup table indexed by the next byte in the key, after + // remapping that byte through genericReplacer.mapping to create a dense + // index. In the example above, the keys only use 'a', 'b', 'c', 'x' and + // 'y', which remap to 0, 1, 2, 3 and 4. All other bytes remap to 5, and + // genericReplacer.tableSize will be 5. Node n0's table will be + // []*trieNode{ 0:n1, 1:n4, 3:n6 }, where the 0, 1 and 3 are the remapped + // 'a', 'b' and 'x'. + table []*trieNode +} + +func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { + if key == "" { + if t.priority == 0 { + t.value = val + t.priority = priority + } + return + } + + if t.prefix != "" { + // Need to split the prefix among multiple nodes. + var n int // length of the longest common prefix + for ; n < len(t.prefix) && n < len(key); n++ { + if t.prefix[n] != key[n] { + break + } + } + if n == len(t.prefix) { + t.next.add(key[n:], val, priority, r) + } else if n == 0 { + // First byte differs, start a new lookup table here. Looking up + // what is currently t.prefix[0] will lead to prefixNode, and + // looking up key[0] will lead to keyNode. + var prefixNode *trieNode + if len(t.prefix) == 1 { + prefixNode = t.next + } else { + prefixNode = &trieNode{ + prefix: t.prefix[1:], + next: t.next, + } + } + keyNode := new(trieNode) + t.table = make([]*trieNode, r.tableSize) + t.table[r.mapping[t.prefix[0]]] = prefixNode + t.table[r.mapping[key[0]]] = keyNode + t.prefix = "" + t.next = nil + keyNode.add(key[1:], val, priority, r) + } else { + // Insert new node after the common section of the prefix. + next := &trieNode{ + prefix: t.prefix[n:], + next: t.next, + } + t.prefix = t.prefix[:n] + t.next = next + next.add(key[n:], val, priority, r) + } + } else if t.table != nil { + // Insert into existing table. + m := r.mapping[key[0]] + if t.table[m] == nil { + t.table[m] = new(trieNode) + } + t.table[m].add(key[1:], val, priority, r) + } else { + t.prefix = key + t.next = new(trieNode) + t.next.add("", val, priority, r) + } +} + +func (r *genericReplacer) lookup(s string, ignoreRoot bool) (val string, keylen int, found bool) { + // Iterate down the trie to the end, and grab the value and keylen with + // the highest priority. + bestPriority := 0 + node := &r.root + n := 0 + for node != nil { + if node.priority > bestPriority && !(ignoreRoot && node == &r.root) { + bestPriority = node.priority + val = node.value + keylen = n + found = true + } + + if s == "" { + break + } + if node.table != nil { + index := r.mapping[s[0]] + if int(index) == r.tableSize { + break + } + node = node.table[index] + s = s[1:] + n++ + } else if node.prefix != "" && HasPrefix(s, node.prefix) { + n += len(node.prefix) + s = s[len(node.prefix):] + node = node.next + } else { + break + } + } + return +} + +// genericReplacer is the fully generic algorithm. +// It's used as a fallback when nothing faster can be used. +type genericReplacer struct { + root trieNode + // tableSize is the size of a trie node's lookup table. It is the number + // of unique key bytes. + tableSize int + // mapping maps from key bytes to a dense index for trieNode.table. + mapping [256]byte +} + +func makeGenericReplacer(oldnew []string) *genericReplacer { + r := new(genericReplacer) + // Find each byte used, then assign them each an index. + for i := 0; i < len(oldnew); i += 2 { + key := oldnew[i] + for j := 0; j < len(key); j++ { + r.mapping[key[j]] = 1 + } + } + + for _, b := range r.mapping { + r.tableSize += int(b) + } + + var index byte + for i, b := range r.mapping { + if b == 0 { + r.mapping[i] = byte(r.tableSize) + } else { + r.mapping[i] = index + index++ + } + } + // Ensure root node uses a lookup table (for performance). + r.root.table = make([]*trieNode, r.tableSize) + + for i := 0; i < len(oldnew); i += 2 { + r.root.add(oldnew[i], oldnew[i+1], len(oldnew)-i, r) + } + return r +} + +type appendSliceWriter []byte + +// Write writes to the buffer to satisfy [io.Writer]. +func (w *appendSliceWriter) Write(p []byte) (int, error) { + *w = append(*w, p...) + return len(p), nil +} + +// WriteString writes to the buffer without string->[]byte->string allocations. +func (w *appendSliceWriter) WriteString(s string) (int, error) { + *w = append(*w, s...) + return len(s), nil +} + +type stringWriter struct { + w io.Writer +} + +func (w stringWriter) WriteString(s string) (int, error) { + return w.w.Write([]byte(s)) +} + +func getStringWriter(w io.Writer) io.StringWriter { + sw, ok := w.(io.StringWriter) + if !ok { + sw = stringWriter{w} + } + return sw +} + +func (r *genericReplacer) Replace(s string) string { + buf := make(appendSliceWriter, 0, len(s)) + r.WriteString(&buf, s) + return string(buf) +} + +func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) { + sw := getStringWriter(w) + var last, wn int + var prevMatchEmpty bool + for i := 0; i <= len(s); { + // Fast path: s[i] is not a prefix of any pattern. + if i != len(s) && r.root.priority == 0 { + index := int(r.mapping[s[i]]) + if index == r.tableSize || r.root.table[index] == nil { + i++ + continue + } + } + + // Ignore the empty match iff the previous loop found the empty match. + val, keylen, match := r.lookup(s[i:], prevMatchEmpty) + prevMatchEmpty = match && keylen == 0 + if match { + wn, err = sw.WriteString(s[last:i]) + n += wn + if err != nil { + return + } + wn, err = sw.WriteString(val) + n += wn + if err != nil { + return + } + i += keylen + last = i + continue + } + i++ + } + if last != len(s) { + wn, err = sw.WriteString(s[last:]) + n += wn + } + return +} + +// singleStringReplacer is the implementation that's used when there is only +// one string to replace (and that string has more than one byte). +type singleStringReplacer struct { + finder *stringFinder + // value is the new string that replaces that pattern when it's found. + value string +} + +func makeSingleStringReplacer(pattern string, value string) *singleStringReplacer { + return &singleStringReplacer{finder: makeStringFinder(pattern), value: value} +} + +func (r *singleStringReplacer) Replace(s string) string { + var buf Builder + i, matched := 0, false + for { + match := r.finder.next(s[i:]) + if match == -1 { + break + } + matched = true + buf.Grow(match + len(r.value)) + buf.WriteString(s[i : i+match]) + buf.WriteString(r.value) + i += match + len(r.finder.pattern) + } + if !matched { + return s + } + buf.WriteString(s[i:]) + return buf.String() +} + +func (r *singleStringReplacer) WriteString(w io.Writer, s string) (n int, err error) { + sw := getStringWriter(w) + var i, wn int + for { + match := r.finder.next(s[i:]) + if match == -1 { + break + } + wn, err = sw.WriteString(s[i : i+match]) + n += wn + if err != nil { + return + } + wn, err = sw.WriteString(r.value) + n += wn + if err != nil { + return + } + i += match + len(r.finder.pattern) + } + wn, err = sw.WriteString(s[i:]) + n += wn + return +} + +// byteReplacer is the implementation that's used when all the "old" +// and "new" values are single ASCII bytes. +// The array contains replacement bytes indexed by old byte. +type byteReplacer [256]byte + +func (r *byteReplacer) Replace(s string) string { + var buf []byte // lazily allocated + for i := 0; i < len(s); i++ { + b := s[i] + if r[b] != b { + if buf == nil { + buf = []byte(s) + } + buf[i] = r[b] + } + } + if buf == nil { + return s + } + return string(buf) +} + +func (r *byteReplacer) WriteString(w io.Writer, s string) (n int, err error) { + sw := getStringWriter(w) + last := 0 + for i := 0; i < len(s); i++ { + b := s[i] + if r[b] == b { + continue + } + if last != i { + wn, err := sw.WriteString(s[last:i]) + n += wn + if err != nil { + return n, err + } + } + last = i + 1 + nw, err := w.Write(r[b : int(b)+1]) + n += nw + if err != nil { + return n, err + } + } + if last != len(s) { + nw, err := sw.WriteString(s[last:]) + n += nw + if err != nil { + return n, err + } + } + return n, nil +} + +// byteStringReplacer is the implementation that's used when all the +// "old" values are single ASCII bytes but the "new" values vary in size. +type byteStringReplacer struct { + // replacements contains replacement byte slices indexed by old byte. + // A nil []byte means that the old byte should not be replaced. + replacements [256][]byte + // toReplace keeps a list of bytes to replace. Depending on length of toReplace + // and length of target string it may be faster to use Count, or a plain loop. + // We store single byte as a string, because Count takes a string. + toReplace []string +} + +// countCutOff controls the ratio of a string length to a number of replacements +// at which (*byteStringReplacer).Replace switches algorithms. +// For strings with higher ration of length to replacements than that value, +// we call Count, for each replacement from toReplace. +// For strings, with a lower ratio we use simple loop, because of Count overhead. +// countCutOff is an empirically determined overhead multiplier. +// TODO(tocarip) revisit once we have register-based abi/mid-stack inlining. +const countCutOff = 8 + +func (r *byteStringReplacer) Replace(s string) string { + newSize := len(s) + anyChanges := false + // Is it faster to use Count? + if len(r.toReplace)*countCutOff <= len(s) { + for _, x := range r.toReplace { + if c := Count(s, x); c != 0 { + // The -1 is because we are replacing 1 byte with len(replacements[b]) bytes. + newSize += c * (len(r.replacements[x[0]]) - 1) + anyChanges = true + } + + } + } else { + for i := 0; i < len(s); i++ { + b := s[i] + if r.replacements[b] != nil { + // See above for explanation of -1 + newSize += len(r.replacements[b]) - 1 + anyChanges = true + } + } + } + if !anyChanges { + return s + } + buf := make([]byte, newSize) + j := 0 + for i := 0; i < len(s); i++ { + b := s[i] + if r.replacements[b] != nil { + j += copy(buf[j:], r.replacements[b]) + } else { + buf[j] = b + j++ + } + } + return string(buf) +} + +func (r *byteStringReplacer) WriteString(w io.Writer, s string) (n int, err error) { + sw := getStringWriter(w) + last := 0 + for i := 0; i < len(s); i++ { + b := s[i] + if r.replacements[b] == nil { + continue + } + if last != i { + nw, err := sw.WriteString(s[last:i]) + n += nw + if err != nil { + return n, err + } + } + last = i + 1 + nw, err := w.Write(r.replacements[b]) + n += nw + if err != nil { + return n, err + } + } + if last != len(s) { + var nw int + nw, err = sw.WriteString(s[last:]) + n += nw + } + return +} diff --git a/gnovm/stdlibs/strings/replace_test.gno b/gnovm/stdlibs/strings/replace_test.gno new file mode 100644 index 00000000000..dc4858dcc5c --- /dev/null +++ b/gnovm/stdlibs/strings/replace_test.gno @@ -0,0 +1,511 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings_test + +import ( + "bytes" + "fmt" + "strings" + "testing" +) + +var htmlEscaper = strings.NewReplacer( + "&", "&", + "<", "<", + ">", ">", + `"`, """, + "'", "'", +) + +var htmlUnescaper = strings.NewReplacer( + "&", "&", + "<", "<", + ">", ">", + """, `"`, + "'", "'", +) + +// The http package's old HTML escaping function. +func oldHTMLEscape(s string) string { + s = strings.Replace(s, "&", "&", -1) + s = strings.Replace(s, "<", "<", -1) + s = strings.Replace(s, ">", ">", -1) + s = strings.Replace(s, `"`, """, -1) + s = strings.Replace(s, "'", "'", -1) + return s +} + +var capitalLetters = strings.NewReplacer("a", "A", "b", "B") + +// TestReplacer tests the replacer implementations. +func TestReplacer(t *testing.T) { + type testCase struct { + r *strings.Replacer + in, out string + } + var testCases []testCase + + // str converts 0xff to "\xff". This isn't just string(b) since that converts to UTF-8. + str := func(b byte) string { + return string([]byte{b}) + } + var s []string + + // inc maps "\x00"->"\x01", ..., "a"->"b", "b"->"c", ..., "\xff"->"\x00". + s = nil + for i := 0; i < 256; i++ { + s = append(s, str(byte(i)), str(byte(i+1))) + } + inc := strings.NewReplacer(s...) + + // Test cases with 1-byte old strings, 1-byte new strings. + testCases = append(testCases, + testCase{capitalLetters, "brad", "BrAd"}, + testCase{capitalLetters, strings.Repeat("a", (32<<10)+123), strings.Repeat("A", (32<<10)+123)}, + testCase{capitalLetters, "", ""}, + + testCase{inc, "brad", "csbe"}, + testCase{inc, "\x00\xff", "\x01\x00"}, + testCase{inc, "", ""}, + + testCase{strings.NewReplacer("a", "1", "a", "2"), "brad", "br1d"}, + ) + + // repeat maps "a"->"a", "b"->"bb", "c"->"ccc", ... + s = nil + for i := 0; i < 256; i++ { + n := i + 1 - 'a' + if n < 1 { + n = 1 + } + s = append(s, str(byte(i)), strings.Repeat(str(byte(i)), n)) + } + repeat := strings.NewReplacer(s...) + + // Test cases with 1-byte old strings, variable length new strings. + testCases = append(testCases, + testCase{htmlEscaper, "No changes", "No changes"}, + testCase{htmlEscaper, "I <3 escaping & stuff", "I <3 escaping & stuff"}, + testCase{htmlEscaper, "&&&", "&&&"}, + testCase{htmlEscaper, "", ""}, + + testCase{repeat, "brad", "bbrrrrrrrrrrrrrrrrrradddd"}, + testCase{repeat, "abba", "abbbba"}, + testCase{repeat, "", ""}, + + testCase{strings.NewReplacer("a", "11", "a", "22"), "brad", "br11d"}, + ) + + // The remaining test cases have variable length old strings. + + testCases = append(testCases, + testCase{htmlUnescaper, "&amp;", "&"}, + testCase{htmlUnescaper, "<b>HTML's neat</b>", "HTML's neat"}, + testCase{htmlUnescaper, "", ""}, + + testCase{strings.NewReplacer("a", "1", "a", "2", "xxx", "xxx"), "brad", "br1d"}, + + testCase{strings.NewReplacer("a", "1", "aa", "2", "aaa", "3"), "aaaa", "1111"}, + + testCase{strings.NewReplacer("aaa", "3", "aa", "2", "a", "1"), "aaaa", "31"}, + ) + + // gen1 has multiple old strings of variable length. There is no + // overall non-empty common prefix, but some pairwise common prefixes. + gen1 := strings.NewReplacer( + "aaa", "3[aaa]", + "aa", "2[aa]", + "a", "1[a]", + "i", "i", + "longerst", "most long", + "longer", "medium", + "long", "short", + "xx", "xx", + "x", "X", + "X", "Y", + "Y", "Z", + ) + testCases = append(testCases, + testCase{gen1, "fooaaabar", "foo3[aaa]b1[a]r"}, + testCase{gen1, "long, longerst, longer", "short, most long, medium"}, + testCase{gen1, "xxxxx", "xxxxX"}, + testCase{gen1, "XiX", "YiY"}, + testCase{gen1, "", ""}, + ) + + // gen2 has multiple old strings with no pairwise common prefix. + gen2 := strings.NewReplacer( + "roses", "red", + "violets", "blue", + "sugar", "sweet", + ) + testCases = append(testCases, + testCase{gen2, "roses are red, violets are blue...", "red are red, blue are blue..."}, + testCase{gen2, "", ""}, + ) + + // gen3 has multiple old strings with an overall common prefix. + gen3 := strings.NewReplacer( + "abracadabra", "poof", + "abracadabrakazam", "splat", + "abraham", "lincoln", + "abrasion", "scrape", + "abraham", "isaac", + ) + testCases = append(testCases, + testCase{gen3, "abracadabrakazam abraham", "poofkazam lincoln"}, + testCase{gen3, "abrasion abracad", "scrape abracad"}, + testCase{gen3, "abba abram abrasive", "abba abram abrasive"}, + testCase{gen3, "", ""}, + ) + + // foo{1,2,3,4} have multiple old strings with an overall common prefix + // and 1- or 2- byte extensions from the common prefix. + foo1 := strings.NewReplacer( + "foo1", "A", + "foo2", "B", + "foo3", "C", + ) + foo2 := strings.NewReplacer( + "foo1", "A", + "foo2", "B", + "foo31", "C", + "foo32", "D", + ) + foo3 := strings.NewReplacer( + "foo11", "A", + "foo12", "B", + "foo31", "C", + "foo32", "D", + ) + foo4 := strings.NewReplacer( + "foo12", "B", + "foo32", "D", + ) + testCases = append(testCases, + testCase{foo1, "fofoofoo12foo32oo", "fofooA2C2oo"}, + testCase{foo1, "", ""}, + + testCase{foo2, "fofoofoo12foo32oo", "fofooA2Doo"}, + testCase{foo2, "", ""}, + + testCase{foo3, "fofoofoo12foo32oo", "fofooBDoo"}, + testCase{foo3, "", ""}, + + testCase{foo4, "fofoofoo12foo32oo", "fofooBDoo"}, + testCase{foo4, "", ""}, + ) + + // genAll maps "\x00\x01\x02...\xfe\xff" to "[all]", amongst other things. + allBytes := make([]byte, 256) + for i := range allBytes { + allBytes[i] = byte(i) + } + allString := string(allBytes) + genAll := strings.NewReplacer( + allString, "[all]", + "\xff", "[ff]", + "\x00", "[00]", + ) + testCases = append(testCases, + testCase{genAll, allString, "[all]"}, + testCase{genAll, "a\xff" + allString + "\x00", "a[ff][all][00]"}, + testCase{genAll, "", ""}, + ) + + // Test cases with empty old strings. + + blankToX1 := strings.NewReplacer("", "X") + blankToX2 := strings.NewReplacer("", "X", "", "") + blankHighPriority := strings.NewReplacer("", "X", "o", "O") + blankLowPriority := strings.NewReplacer("o", "O", "", "X") + blankNoOp1 := strings.NewReplacer("", "") + blankNoOp2 := strings.NewReplacer("", "", "", "A") + blankFoo := strings.NewReplacer("", "X", "foobar", "R", "foobaz", "Z") + testCases = append(testCases, + testCase{blankToX1, "foo", "XfXoXoX"}, + testCase{blankToX1, "", "X"}, + + testCase{blankToX2, "foo", "XfXoXoX"}, + testCase{blankToX2, "", "X"}, + + testCase{blankHighPriority, "oo", "XOXOX"}, + testCase{blankHighPriority, "ii", "XiXiX"}, + testCase{blankHighPriority, "oiio", "XOXiXiXOX"}, + testCase{blankHighPriority, "iooi", "XiXOXOXiX"}, + testCase{blankHighPriority, "", "X"}, + + testCase{blankLowPriority, "oo", "OOX"}, + testCase{blankLowPriority, "ii", "XiXiX"}, + testCase{blankLowPriority, "oiio", "OXiXiOX"}, + testCase{blankLowPriority, "iooi", "XiOOXiX"}, + testCase{blankLowPriority, "", "X"}, + + testCase{blankNoOp1, "foo", "foo"}, + testCase{blankNoOp1, "", ""}, + + testCase{blankNoOp2, "foo", "foo"}, + testCase{blankNoOp2, "", ""}, + + testCase{blankFoo, "foobarfoobaz", "XRXZX"}, + testCase{blankFoo, "foobar-foobaz", "XRX-XZX"}, + testCase{blankFoo, "", "X"}, + ) + + // single string replacer + + abcMatcher := strings.NewReplacer("abc", "[match]") + + testCases = append(testCases, + testCase{abcMatcher, "", ""}, + testCase{abcMatcher, "ab", "ab"}, + testCase{abcMatcher, "abc", "[match]"}, + testCase{abcMatcher, "abcd", "[match]d"}, + testCase{abcMatcher, "cabcabcdabca", "c[match][match]d[match]a"}, + ) + + // Issue 6659 cases (more single string replacer) + + noHello := strings.NewReplacer("Hello", "") + testCases = append(testCases, + testCase{noHello, "Hello", ""}, + testCase{noHello, "Hellox", "x"}, + testCase{noHello, "xHello", "x"}, + testCase{noHello, "xHellox", "xx"}, + ) + + // No-arg test cases. + + nop := strings.NewReplacer() + testCases = append(testCases, + testCase{nop, "abc", "abc"}, + testCase{nop, "", ""}, + ) + + // Run the test cases. + + for i, tc := range testCases { + if s := tc.r.Replace(tc.in); s != tc.out { + t.Errorf("%d. Replace(%q) = %q, want %q", i, tc.in, s, tc.out) + } + var buf bytes.Buffer + n, err := tc.r.WriteString(&buf, tc.in) + if err != nil { + t.Errorf("%d. WriteString: %v", i, err) + continue + } + got := buf.String() + if got != tc.out { + t.Errorf("%d. WriteString(%q) wrote %q, want %q", i, tc.in, got, tc.out) + continue + } + if n != len(tc.out) { + t.Errorf("%d. WriteString(%q) wrote correct string but reported %d bytes; want %d (%q)", + i, tc.in, n, len(tc.out), tc.out) + } + } +} + +var algorithmTestCases = []struct { + r *strings.Replacer + want string +}{ + {capitalLetters, "*strings.byteReplacer"}, + {htmlEscaper, "*strings.byteStringReplacer"}, + {strings.NewReplacer("12", "123"), "*strings.singleStringReplacer"}, + {strings.NewReplacer("1", "12"), "*strings.byteStringReplacer"}, + {strings.NewReplacer("", "X"), "*strings.genericReplacer"}, + {strings.NewReplacer("a", "1", "b", "12", "cde", "123"), "*strings.genericReplacer"}, +} + +//// TestPickAlgorithm tests that strings.NewReplacer picks the correct algorithm. +//func TestPickAlgorithm(t *testing.T) { +// for i, tc := range algorithmTestCases { +// got := fmt.Sprintf("%T", tc.r.Replacer()) +// if got != tc.want { +// t.Errorf("%d. algorithm = %s, want %s", i, got, tc.want) +// } +// } +//} + +type errWriter struct{} + +func (errWriter) Write(p []byte) (n int, err error) { + return 0, fmt.Errorf("unwritable") +} + +// TestWriteStringError tests that WriteString returns an error +// received from the underlying io.Writer. +func TestWriteStringError(t *testing.T) { + for i, tc := range algorithmTestCases { + n, err := tc.r.WriteString(errWriter{}, "abc") + if n != 0 || err == nil || err.Error() != "unwritable" { + t.Errorf("%d. WriteStringError = %d, %v, want 0, unwritable", i, n, err) + } + } +} + +func BenchmarkGenericNoMatch(b *testing.B) { + str := strings.Repeat("A", 100) + strings.Repeat("B", 100) + generic := strings.NewReplacer("a", "A", "b", "B", "12", "123") // varying lengths forces generic + for i := 0; i < b.N; i++ { + generic.Replace(str) + } +} + +func BenchmarkGenericMatch1(b *testing.B) { + str := strings.Repeat("a", 100) + strings.Repeat("b", 100) + generic := strings.NewReplacer("a", "A", "b", "B", "12", "123") + for i := 0; i < b.N; i++ { + generic.Replace(str) + } +} + +func BenchmarkGenericMatch2(b *testing.B) { + str := strings.Repeat("It's <b>HTML</b>!", 100) + for i := 0; i < b.N; i++ { + htmlUnescaper.Replace(str) + } +} + +func benchmarkSingleString(b *testing.B, pattern, text string) { + r := strings.NewReplacer(pattern, "[match]") + b.SetBytes(int64(len(text))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + r.Replace(text) + } +} + +func BenchmarkSingleMaxSkipping(b *testing.B) { + benchmarkSingleString(b, strings.Repeat("b", 25), strings.Repeat("a", 10000)) +} + +func BenchmarkSingleLongSuffixFail(b *testing.B) { + benchmarkSingleString(b, "b"+strings.Repeat("a", 500), strings.Repeat("a", 1002)) +} + +func BenchmarkSingleMatch(b *testing.B) { + benchmarkSingleString(b, "abcdef", strings.Repeat("abcdefghijklmno", 1000)) +} + +func BenchmarkByteByteNoMatch(b *testing.B) { + str := strings.Repeat("A", 100) + strings.Repeat("B", 100) + for i := 0; i < b.N; i++ { + capitalLetters.Replace(str) + } +} + +func BenchmarkByteByteMatch(b *testing.B) { + str := strings.Repeat("a", 100) + strings.Repeat("b", 100) + for i := 0; i < b.N; i++ { + capitalLetters.Replace(str) + } +} + +func BenchmarkByteStringMatch(b *testing.B) { + str := "<" + strings.Repeat("a", 99) + strings.Repeat("b", 99) + ">" + for i := 0; i < b.N; i++ { + htmlEscaper.Replace(str) + } +} + +func BenchmarkHTMLEscapeNew(b *testing.B) { + str := "I <3 to escape HTML & other text too." + for i := 0; i < b.N; i++ { + htmlEscaper.Replace(str) + } +} + +func BenchmarkHTMLEscapeOld(b *testing.B) { + str := "I <3 to escape HTML & other text too." + for i := 0; i < b.N; i++ { + oldHTMLEscape(str) + } +} + +func BenchmarkByteStringReplacerWriteString(b *testing.B) { + str := strings.Repeat("I <3 to escape HTML & other text too.", 100) + buf := new(bytes.Buffer) + for i := 0; i < b.N; i++ { + htmlEscaper.WriteString(buf, str) + buf.Reset() + } +} + +func BenchmarkByteReplacerWriteString(b *testing.B) { + str := strings.Repeat("abcdefghijklmnopqrstuvwxyz", 100) + buf := new(bytes.Buffer) + for i := 0; i < b.N; i++ { + capitalLetters.WriteString(buf, str) + buf.Reset() + } +} + +// BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces. +func BenchmarkByteByteReplaces(b *testing.B) { + str := strings.Repeat("a", 100) + strings.Repeat("b", 100) + for i := 0; i < b.N; i++ { + strings.Replace(strings.Replace(str, "a", "A", -1), "b", "B", -1) + } +} + +// BenchmarkByteByteMap compares byteByteImpl against Map. +func BenchmarkByteByteMap(b *testing.B) { + str := strings.Repeat("a", 100) + strings.Repeat("b", 100) + fn := func(r rune) rune { + switch r { + case 'a': + return 'A' + case 'b': + return 'B' + } + return r + } + for i := 0; i < b.N; i++ { + strings.Map(fn, str) + } +} + +var mapdata = []struct{ name, data string }{ + {"ASCII", "a b c d e f g h i j k l m n o p q r s t u v w x y z"}, + {"Greek", "α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ ς σ τ υ φ χ ψ ω"}, +} + +func BenchmarkMap(b *testing.B) { + mapidentity := func(r rune) rune { + return r + } + + b.Run("identity", func(b *testing.B) { + for _, md := range mapdata { + b.Run(md.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + strings.Map(mapidentity, md.data) + } + }) + } + }) + + mapchange := func(r rune) rune { + if 'a' <= r && r <= 'z' { + return r + 'A' - 'a' + } + if 'α' <= r && r <= 'ω' { + return r + 'Α' - 'α' + } + return r + } + + b.Run("change", func(b *testing.B) { + for _, md := range mapdata { + b.Run(md.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + strings.Map(mapchange, md.data) + } + }) + } + }) +} From 47118efc66853e1b892ef02508b9cb0843161123 Mon Sep 17 00:00:00 2001 From: Miguel Victoria Villaquiran Date: Thu, 3 Oct 2024 11:20:03 +0200 Subject: [PATCH 04/20] feat(stdlibs): add package `html` (#2802) related to #1267 - Implement html golang package. - Added a silly implementation of strings.Replacer: Maybe we should optimize it ? I did not wanted to do something complex as this is not the main point of this pull request
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- docs/reference/go-gno-compatibility.md | 2 +- gnovm/stdlibs/generated.go | 1 + gnovm/stdlibs/html/entity.gno | 2253 ++++++++++++++++++++++++ gnovm/stdlibs/html/entity_test.gno | 37 + gnovm/stdlibs/html/escape.gno | 213 +++ gnovm/stdlibs/html/escape_test.gno | 169 ++ 6 files changed, 2674 insertions(+), 1 deletion(-) create mode 100644 gnovm/stdlibs/html/entity.gno create mode 100644 gnovm/stdlibs/html/entity_test.gno create mode 100644 gnovm/stdlibs/html/escape.gno create mode 100644 gnovm/stdlibs/html/escape_test.gno diff --git a/docs/reference/go-gno-compatibility.md b/docs/reference/go-gno-compatibility.md index a2f83f2bbc6..bad19860655 100644 --- a/docs/reference/go-gno-compatibility.md +++ b/docs/reference/go-gno-compatibility.md @@ -184,7 +184,7 @@ Legend: | hash/crc64 | `todo` | | hash/fnv | `todo` | | hash/maphash | `todo` | -| html | `todo` | +| html | `full` | | html/template | `todo` | | image | `tbd` | | image/color | `tbd` | diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index 37e1b1a4cce..4c460e220b7 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -1077,6 +1077,7 @@ var initOrder = [...]string{ "encoding/hex", "hash", "hash/adler32", + "html", "math/overflow", "math/rand", "path", diff --git a/gnovm/stdlibs/html/entity.gno b/gnovm/stdlibs/html/entity.gno new file mode 100644 index 00000000000..d123794335c --- /dev/null +++ b/gnovm/stdlibs/html/entity.gno @@ -0,0 +1,2253 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +// All entities that do not end with ';' are 6 or fewer bytes long. +const longestEntityWithoutSemicolon = 6 + +// entity is a map from HTML entity names to their values. The semicolon matters: +// https://html.spec.whatwg.org/multipage/named-characters.html +// lists both "amp" and "amp;" as two separate entries. +// +// Note that the HTML5 list is larger than the HTML4 list at +// http://www.w3.org/TR/html4/sgml/entities.html +var entity = map[string]rune{ + "AElig;": '\U000000C6', + "AMP;": '\U00000026', + "Aacute;": '\U000000C1', + "Abreve;": '\U00000102', + "Acirc;": '\U000000C2', + "Acy;": '\U00000410', + "Afr;": '\U0001D504', + "Agrave;": '\U000000C0', + "Alpha;": '\U00000391', + "Amacr;": '\U00000100', + "And;": '\U00002A53', + "Aogon;": '\U00000104', + "Aopf;": '\U0001D538', + "ApplyFunction;": '\U00002061', + "Aring;": '\U000000C5', + "Ascr;": '\U0001D49C', + "Assign;": '\U00002254', + "Atilde;": '\U000000C3', + "Auml;": '\U000000C4', + "Backslash;": '\U00002216', + "Barv;": '\U00002AE7', + "Barwed;": '\U00002306', + "Bcy;": '\U00000411', + "Because;": '\U00002235', + "Bernoullis;": '\U0000212C', + "Beta;": '\U00000392', + "Bfr;": '\U0001D505', + "Bopf;": '\U0001D539', + "Breve;": '\U000002D8', + "Bscr;": '\U0000212C', + "Bumpeq;": '\U0000224E', + "CHcy;": '\U00000427', + "COPY;": '\U000000A9', + "Cacute;": '\U00000106', + "Cap;": '\U000022D2', + "CapitalDifferentialD;": '\U00002145', + "Cayleys;": '\U0000212D', + "Ccaron;": '\U0000010C', + "Ccedil;": '\U000000C7', + "Ccirc;": '\U00000108', + "Cconint;": '\U00002230', + "Cdot;": '\U0000010A', + "Cedilla;": '\U000000B8', + "CenterDot;": '\U000000B7', + "Cfr;": '\U0000212D', + "Chi;": '\U000003A7', + "CircleDot;": '\U00002299', + "CircleMinus;": '\U00002296', + "CirclePlus;": '\U00002295', + "CircleTimes;": '\U00002297', + "ClockwiseContourIntegral;": '\U00002232', + "CloseCurlyDoubleQuote;": '\U0000201D', + "CloseCurlyQuote;": '\U00002019', + "Colon;": '\U00002237', + "Colone;": '\U00002A74', + "Congruent;": '\U00002261', + "Conint;": '\U0000222F', + "ContourIntegral;": '\U0000222E', + "Copf;": '\U00002102', + "Coproduct;": '\U00002210', + "CounterClockwiseContourIntegral;": '\U00002233', + "Cross;": '\U00002A2F', + "Cscr;": '\U0001D49E', + "Cup;": '\U000022D3', + "CupCap;": '\U0000224D', + "DD;": '\U00002145', + "DDotrahd;": '\U00002911', + "DJcy;": '\U00000402', + "DScy;": '\U00000405', + "DZcy;": '\U0000040F', + "Dagger;": '\U00002021', + "Darr;": '\U000021A1', + "Dashv;": '\U00002AE4', + "Dcaron;": '\U0000010E', + "Dcy;": '\U00000414', + "Del;": '\U00002207', + "Delta;": '\U00000394', + "Dfr;": '\U0001D507', + "DiacriticalAcute;": '\U000000B4', + "DiacriticalDot;": '\U000002D9', + "DiacriticalDoubleAcute;": '\U000002DD', + "DiacriticalGrave;": '\U00000060', + "DiacriticalTilde;": '\U000002DC', + "Diamond;": '\U000022C4', + "DifferentialD;": '\U00002146', + "Dopf;": '\U0001D53B', + "Dot;": '\U000000A8', + "DotDot;": '\U000020DC', + "DotEqual;": '\U00002250', + "DoubleContourIntegral;": '\U0000222F', + "DoubleDot;": '\U000000A8', + "DoubleDownArrow;": '\U000021D3', + "DoubleLeftArrow;": '\U000021D0', + "DoubleLeftRightArrow;": '\U000021D4', + "DoubleLeftTee;": '\U00002AE4', + "DoubleLongLeftArrow;": '\U000027F8', + "DoubleLongLeftRightArrow;": '\U000027FA', + "DoubleLongRightArrow;": '\U000027F9', + "DoubleRightArrow;": '\U000021D2', + "DoubleRightTee;": '\U000022A8', + "DoubleUpArrow;": '\U000021D1', + "DoubleUpDownArrow;": '\U000021D5', + "DoubleVerticalBar;": '\U00002225', + "DownArrow;": '\U00002193', + "DownArrowBar;": '\U00002913', + "DownArrowUpArrow;": '\U000021F5', + "DownBreve;": '\U00000311', + "DownLeftRightVector;": '\U00002950', + "DownLeftTeeVector;": '\U0000295E', + "DownLeftVector;": '\U000021BD', + "DownLeftVectorBar;": '\U00002956', + "DownRightTeeVector;": '\U0000295F', + "DownRightVector;": '\U000021C1', + "DownRightVectorBar;": '\U00002957', + "DownTee;": '\U000022A4', + "DownTeeArrow;": '\U000021A7', + "Downarrow;": '\U000021D3', + "Dscr;": '\U0001D49F', + "Dstrok;": '\U00000110', + "ENG;": '\U0000014A', + "ETH;": '\U000000D0', + "Eacute;": '\U000000C9', + "Ecaron;": '\U0000011A', + "Ecirc;": '\U000000CA', + "Ecy;": '\U0000042D', + "Edot;": '\U00000116', + "Efr;": '\U0001D508', + "Egrave;": '\U000000C8', + "Element;": '\U00002208', + "Emacr;": '\U00000112', + "EmptySmallSquare;": '\U000025FB', + "EmptyVerySmallSquare;": '\U000025AB', + "Eogon;": '\U00000118', + "Eopf;": '\U0001D53C', + "Epsilon;": '\U00000395', + "Equal;": '\U00002A75', + "EqualTilde;": '\U00002242', + "Equilibrium;": '\U000021CC', + "Escr;": '\U00002130', + "Esim;": '\U00002A73', + "Eta;": '\U00000397', + "Euml;": '\U000000CB', + "Exists;": '\U00002203', + "ExponentialE;": '\U00002147', + "Fcy;": '\U00000424', + "Ffr;": '\U0001D509', + "FilledSmallSquare;": '\U000025FC', + "FilledVerySmallSquare;": '\U000025AA', + "Fopf;": '\U0001D53D', + "ForAll;": '\U00002200', + "Fouriertrf;": '\U00002131', + "Fscr;": '\U00002131', + "GJcy;": '\U00000403', + "GT;": '\U0000003E', + "Gamma;": '\U00000393', + "Gammad;": '\U000003DC', + "Gbreve;": '\U0000011E', + "Gcedil;": '\U00000122', + "Gcirc;": '\U0000011C', + "Gcy;": '\U00000413', + "Gdot;": '\U00000120', + "Gfr;": '\U0001D50A', + "Gg;": '\U000022D9', + "Gopf;": '\U0001D53E', + "GreaterEqual;": '\U00002265', + "GreaterEqualLess;": '\U000022DB', + "GreaterFullEqual;": '\U00002267', + "GreaterGreater;": '\U00002AA2', + "GreaterLess;": '\U00002277', + "GreaterSlantEqual;": '\U00002A7E', + "GreaterTilde;": '\U00002273', + "Gscr;": '\U0001D4A2', + "Gt;": '\U0000226B', + "HARDcy;": '\U0000042A', + "Hacek;": '\U000002C7', + "Hat;": '\U0000005E', + "Hcirc;": '\U00000124', + "Hfr;": '\U0000210C', + "HilbertSpace;": '\U0000210B', + "Hopf;": '\U0000210D', + "HorizontalLine;": '\U00002500', + "Hscr;": '\U0000210B', + "Hstrok;": '\U00000126', + "HumpDownHump;": '\U0000224E', + "HumpEqual;": '\U0000224F', + "IEcy;": '\U00000415', + "IJlig;": '\U00000132', + "IOcy;": '\U00000401', + "Iacute;": '\U000000CD', + "Icirc;": '\U000000CE', + "Icy;": '\U00000418', + "Idot;": '\U00000130', + "Ifr;": '\U00002111', + "Igrave;": '\U000000CC', + "Im;": '\U00002111', + "Imacr;": '\U0000012A', + "ImaginaryI;": '\U00002148', + "Implies;": '\U000021D2', + "Int;": '\U0000222C', + "Integral;": '\U0000222B', + "Intersection;": '\U000022C2', + "InvisibleComma;": '\U00002063', + "InvisibleTimes;": '\U00002062', + "Iogon;": '\U0000012E', + "Iopf;": '\U0001D540', + "Iota;": '\U00000399', + "Iscr;": '\U00002110', + "Itilde;": '\U00000128', + "Iukcy;": '\U00000406', + "Iuml;": '\U000000CF', + "Jcirc;": '\U00000134', + "Jcy;": '\U00000419', + "Jfr;": '\U0001D50D', + "Jopf;": '\U0001D541', + "Jscr;": '\U0001D4A5', + "Jsercy;": '\U00000408', + "Jukcy;": '\U00000404', + "KHcy;": '\U00000425', + "KJcy;": '\U0000040C', + "Kappa;": '\U0000039A', + "Kcedil;": '\U00000136', + "Kcy;": '\U0000041A', + "Kfr;": '\U0001D50E', + "Kopf;": '\U0001D542', + "Kscr;": '\U0001D4A6', + "LJcy;": '\U00000409', + "LT;": '\U0000003C', + "Lacute;": '\U00000139', + "Lambda;": '\U0000039B', + "Lang;": '\U000027EA', + "Laplacetrf;": '\U00002112', + "Larr;": '\U0000219E', + "Lcaron;": '\U0000013D', + "Lcedil;": '\U0000013B', + "Lcy;": '\U0000041B', + "LeftAngleBracket;": '\U000027E8', + "LeftArrow;": '\U00002190', + "LeftArrowBar;": '\U000021E4', + "LeftArrowRightArrow;": '\U000021C6', + "LeftCeiling;": '\U00002308', + "LeftDoubleBracket;": '\U000027E6', + "LeftDownTeeVector;": '\U00002961', + "LeftDownVector;": '\U000021C3', + "LeftDownVectorBar;": '\U00002959', + "LeftFloor;": '\U0000230A', + "LeftRightArrow;": '\U00002194', + "LeftRightVector;": '\U0000294E', + "LeftTee;": '\U000022A3', + "LeftTeeArrow;": '\U000021A4', + "LeftTeeVector;": '\U0000295A', + "LeftTriangle;": '\U000022B2', + "LeftTriangleBar;": '\U000029CF', + "LeftTriangleEqual;": '\U000022B4', + "LeftUpDownVector;": '\U00002951', + "LeftUpTeeVector;": '\U00002960', + "LeftUpVector;": '\U000021BF', + "LeftUpVectorBar;": '\U00002958', + "LeftVector;": '\U000021BC', + "LeftVectorBar;": '\U00002952', + "Leftarrow;": '\U000021D0', + "Leftrightarrow;": '\U000021D4', + "LessEqualGreater;": '\U000022DA', + "LessFullEqual;": '\U00002266', + "LessGreater;": '\U00002276', + "LessLess;": '\U00002AA1', + "LessSlantEqual;": '\U00002A7D', + "LessTilde;": '\U00002272', + "Lfr;": '\U0001D50F', + "Ll;": '\U000022D8', + "Lleftarrow;": '\U000021DA', + "Lmidot;": '\U0000013F', + "LongLeftArrow;": '\U000027F5', + "LongLeftRightArrow;": '\U000027F7', + "LongRightArrow;": '\U000027F6', + "Longleftarrow;": '\U000027F8', + "Longleftrightarrow;": '\U000027FA', + "Longrightarrow;": '\U000027F9', + "Lopf;": '\U0001D543', + "LowerLeftArrow;": '\U00002199', + "LowerRightArrow;": '\U00002198', + "Lscr;": '\U00002112', + "Lsh;": '\U000021B0', + "Lstrok;": '\U00000141', + "Lt;": '\U0000226A', + "Map;": '\U00002905', + "Mcy;": '\U0000041C', + "MediumSpace;": '\U0000205F', + "Mellintrf;": '\U00002133', + "Mfr;": '\U0001D510', + "MinusPlus;": '\U00002213', + "Mopf;": '\U0001D544', + "Mscr;": '\U00002133', + "Mu;": '\U0000039C', + "NJcy;": '\U0000040A', + "Nacute;": '\U00000143', + "Ncaron;": '\U00000147', + "Ncedil;": '\U00000145', + "Ncy;": '\U0000041D', + "NegativeMediumSpace;": '\U0000200B', + "NegativeThickSpace;": '\U0000200B', + "NegativeThinSpace;": '\U0000200B', + "NegativeVeryThinSpace;": '\U0000200B', + "NestedGreaterGreater;": '\U0000226B', + "NestedLessLess;": '\U0000226A', + "NewLine;": '\U0000000A', + "Nfr;": '\U0001D511', + "NoBreak;": '\U00002060', + "NonBreakingSpace;": '\U000000A0', + "Nopf;": '\U00002115', + "Not;": '\U00002AEC', + "NotCongruent;": '\U00002262', + "NotCupCap;": '\U0000226D', + "NotDoubleVerticalBar;": '\U00002226', + "NotElement;": '\U00002209', + "NotEqual;": '\U00002260', + "NotExists;": '\U00002204', + "NotGreater;": '\U0000226F', + "NotGreaterEqual;": '\U00002271', + "NotGreaterLess;": '\U00002279', + "NotGreaterTilde;": '\U00002275', + "NotLeftTriangle;": '\U000022EA', + "NotLeftTriangleEqual;": '\U000022EC', + "NotLess;": '\U0000226E', + "NotLessEqual;": '\U00002270', + "NotLessGreater;": '\U00002278', + "NotLessTilde;": '\U00002274', + "NotPrecedes;": '\U00002280', + "NotPrecedesSlantEqual;": '\U000022E0', + "NotReverseElement;": '\U0000220C', + "NotRightTriangle;": '\U000022EB', + "NotRightTriangleEqual;": '\U000022ED', + "NotSquareSubsetEqual;": '\U000022E2', + "NotSquareSupersetEqual;": '\U000022E3', + "NotSubsetEqual;": '\U00002288', + "NotSucceeds;": '\U00002281', + "NotSucceedsSlantEqual;": '\U000022E1', + "NotSupersetEqual;": '\U00002289', + "NotTilde;": '\U00002241', + "NotTildeEqual;": '\U00002244', + "NotTildeFullEqual;": '\U00002247', + "NotTildeTilde;": '\U00002249', + "NotVerticalBar;": '\U00002224', + "Nscr;": '\U0001D4A9', + "Ntilde;": '\U000000D1', + "Nu;": '\U0000039D', + "OElig;": '\U00000152', + "Oacute;": '\U000000D3', + "Ocirc;": '\U000000D4', + "Ocy;": '\U0000041E', + "Odblac;": '\U00000150', + "Ofr;": '\U0001D512', + "Ograve;": '\U000000D2', + "Omacr;": '\U0000014C', + "Omega;": '\U000003A9', + "Omicron;": '\U0000039F', + "Oopf;": '\U0001D546', + "OpenCurlyDoubleQuote;": '\U0000201C', + "OpenCurlyQuote;": '\U00002018', + "Or;": '\U00002A54', + "Oscr;": '\U0001D4AA', + "Oslash;": '\U000000D8', + "Otilde;": '\U000000D5', + "Otimes;": '\U00002A37', + "Ouml;": '\U000000D6', + "OverBar;": '\U0000203E', + "OverBrace;": '\U000023DE', + "OverBracket;": '\U000023B4', + "OverParenthesis;": '\U000023DC', + "PartialD;": '\U00002202', + "Pcy;": '\U0000041F', + "Pfr;": '\U0001D513', + "Phi;": '\U000003A6', + "Pi;": '\U000003A0', + "PlusMinus;": '\U000000B1', + "Poincareplane;": '\U0000210C', + "Popf;": '\U00002119', + "Pr;": '\U00002ABB', + "Precedes;": '\U0000227A', + "PrecedesEqual;": '\U00002AAF', + "PrecedesSlantEqual;": '\U0000227C', + "PrecedesTilde;": '\U0000227E', + "Prime;": '\U00002033', + "Product;": '\U0000220F', + "Proportion;": '\U00002237', + "Proportional;": '\U0000221D', + "Pscr;": '\U0001D4AB', + "Psi;": '\U000003A8', + "QUOT;": '\U00000022', + "Qfr;": '\U0001D514', + "Qopf;": '\U0000211A', + "Qscr;": '\U0001D4AC', + "RBarr;": '\U00002910', + "REG;": '\U000000AE', + "Racute;": '\U00000154', + "Rang;": '\U000027EB', + "Rarr;": '\U000021A0', + "Rarrtl;": '\U00002916', + "Rcaron;": '\U00000158', + "Rcedil;": '\U00000156', + "Rcy;": '\U00000420', + "Re;": '\U0000211C', + "ReverseElement;": '\U0000220B', + "ReverseEquilibrium;": '\U000021CB', + "ReverseUpEquilibrium;": '\U0000296F', + "Rfr;": '\U0000211C', + "Rho;": '\U000003A1', + "RightAngleBracket;": '\U000027E9', + "RightArrow;": '\U00002192', + "RightArrowBar;": '\U000021E5', + "RightArrowLeftArrow;": '\U000021C4', + "RightCeiling;": '\U00002309', + "RightDoubleBracket;": '\U000027E7', + "RightDownTeeVector;": '\U0000295D', + "RightDownVector;": '\U000021C2', + "RightDownVectorBar;": '\U00002955', + "RightFloor;": '\U0000230B', + "RightTee;": '\U000022A2', + "RightTeeArrow;": '\U000021A6', + "RightTeeVector;": '\U0000295B', + "RightTriangle;": '\U000022B3', + "RightTriangleBar;": '\U000029D0', + "RightTriangleEqual;": '\U000022B5', + "RightUpDownVector;": '\U0000294F', + "RightUpTeeVector;": '\U0000295C', + "RightUpVector;": '\U000021BE', + "RightUpVectorBar;": '\U00002954', + "RightVector;": '\U000021C0', + "RightVectorBar;": '\U00002953', + "Rightarrow;": '\U000021D2', + "Ropf;": '\U0000211D', + "RoundImplies;": '\U00002970', + "Rrightarrow;": '\U000021DB', + "Rscr;": '\U0000211B', + "Rsh;": '\U000021B1', + "RuleDelayed;": '\U000029F4', + "SHCHcy;": '\U00000429', + "SHcy;": '\U00000428', + "SOFTcy;": '\U0000042C', + "Sacute;": '\U0000015A', + "Sc;": '\U00002ABC', + "Scaron;": '\U00000160', + "Scedil;": '\U0000015E', + "Scirc;": '\U0000015C', + "Scy;": '\U00000421', + "Sfr;": '\U0001D516', + "ShortDownArrow;": '\U00002193', + "ShortLeftArrow;": '\U00002190', + "ShortRightArrow;": '\U00002192', + "ShortUpArrow;": '\U00002191', + "Sigma;": '\U000003A3', + "SmallCircle;": '\U00002218', + "Sopf;": '\U0001D54A', + "Sqrt;": '\U0000221A', + "Square;": '\U000025A1', + "SquareIntersection;": '\U00002293', + "SquareSubset;": '\U0000228F', + "SquareSubsetEqual;": '\U00002291', + "SquareSuperset;": '\U00002290', + "SquareSupersetEqual;": '\U00002292', + "SquareUnion;": '\U00002294', + "Sscr;": '\U0001D4AE', + "Star;": '\U000022C6', + "Sub;": '\U000022D0', + "Subset;": '\U000022D0', + "SubsetEqual;": '\U00002286', + "Succeeds;": '\U0000227B', + "SucceedsEqual;": '\U00002AB0', + "SucceedsSlantEqual;": '\U0000227D', + "SucceedsTilde;": '\U0000227F', + "SuchThat;": '\U0000220B', + "Sum;": '\U00002211', + "Sup;": '\U000022D1', + "Superset;": '\U00002283', + "SupersetEqual;": '\U00002287', + "Supset;": '\U000022D1', + "THORN;": '\U000000DE', + "TRADE;": '\U00002122', + "TSHcy;": '\U0000040B', + "TScy;": '\U00000426', + "Tab;": '\U00000009', + "Tau;": '\U000003A4', + "Tcaron;": '\U00000164', + "Tcedil;": '\U00000162', + "Tcy;": '\U00000422', + "Tfr;": '\U0001D517', + "Therefore;": '\U00002234', + "Theta;": '\U00000398', + "ThinSpace;": '\U00002009', + "Tilde;": '\U0000223C', + "TildeEqual;": '\U00002243', + "TildeFullEqual;": '\U00002245', + "TildeTilde;": '\U00002248', + "Topf;": '\U0001D54B', + "TripleDot;": '\U000020DB', + "Tscr;": '\U0001D4AF', + "Tstrok;": '\U00000166', + "Uacute;": '\U000000DA', + "Uarr;": '\U0000219F', + "Uarrocir;": '\U00002949', + "Ubrcy;": '\U0000040E', + "Ubreve;": '\U0000016C', + "Ucirc;": '\U000000DB', + "Ucy;": '\U00000423', + "Udblac;": '\U00000170', + "Ufr;": '\U0001D518', + "Ugrave;": '\U000000D9', + "Umacr;": '\U0000016A', + "UnderBar;": '\U0000005F', + "UnderBrace;": '\U000023DF', + "UnderBracket;": '\U000023B5', + "UnderParenthesis;": '\U000023DD', + "Union;": '\U000022C3', + "UnionPlus;": '\U0000228E', + "Uogon;": '\U00000172', + "Uopf;": '\U0001D54C', + "UpArrow;": '\U00002191', + "UpArrowBar;": '\U00002912', + "UpArrowDownArrow;": '\U000021C5', + "UpDownArrow;": '\U00002195', + "UpEquilibrium;": '\U0000296E', + "UpTee;": '\U000022A5', + "UpTeeArrow;": '\U000021A5', + "Uparrow;": '\U000021D1', + "Updownarrow;": '\U000021D5', + "UpperLeftArrow;": '\U00002196', + "UpperRightArrow;": '\U00002197', + "Upsi;": '\U000003D2', + "Upsilon;": '\U000003A5', + "Uring;": '\U0000016E', + "Uscr;": '\U0001D4B0', + "Utilde;": '\U00000168', + "Uuml;": '\U000000DC', + "VDash;": '\U000022AB', + "Vbar;": '\U00002AEB', + "Vcy;": '\U00000412', + "Vdash;": '\U000022A9', + "Vdashl;": '\U00002AE6', + "Vee;": '\U000022C1', + "Verbar;": '\U00002016', + "Vert;": '\U00002016', + "VerticalBar;": '\U00002223', + "VerticalLine;": '\U0000007C', + "VerticalSeparator;": '\U00002758', + "VerticalTilde;": '\U00002240', + "VeryThinSpace;": '\U0000200A', + "Vfr;": '\U0001D519', + "Vopf;": '\U0001D54D', + "Vscr;": '\U0001D4B1', + "Vvdash;": '\U000022AA', + "Wcirc;": '\U00000174', + "Wedge;": '\U000022C0', + "Wfr;": '\U0001D51A', + "Wopf;": '\U0001D54E', + "Wscr;": '\U0001D4B2', + "Xfr;": '\U0001D51B', + "Xi;": '\U0000039E', + "Xopf;": '\U0001D54F', + "Xscr;": '\U0001D4B3', + "YAcy;": '\U0000042F', + "YIcy;": '\U00000407', + "YUcy;": '\U0000042E', + "Yacute;": '\U000000DD', + "Ycirc;": '\U00000176', + "Ycy;": '\U0000042B', + "Yfr;": '\U0001D51C', + "Yopf;": '\U0001D550', + "Yscr;": '\U0001D4B4', + "Yuml;": '\U00000178', + "ZHcy;": '\U00000416', + "Zacute;": '\U00000179', + "Zcaron;": '\U0000017D', + "Zcy;": '\U00000417', + "Zdot;": '\U0000017B', + "ZeroWidthSpace;": '\U0000200B', + "Zeta;": '\U00000396', + "Zfr;": '\U00002128', + "Zopf;": '\U00002124', + "Zscr;": '\U0001D4B5', + "aacute;": '\U000000E1', + "abreve;": '\U00000103', + "ac;": '\U0000223E', + "acd;": '\U0000223F', + "acirc;": '\U000000E2', + "acute;": '\U000000B4', + "acy;": '\U00000430', + "aelig;": '\U000000E6', + "af;": '\U00002061', + "afr;": '\U0001D51E', + "agrave;": '\U000000E0', + "alefsym;": '\U00002135', + "aleph;": '\U00002135', + "alpha;": '\U000003B1', + "amacr;": '\U00000101', + "amalg;": '\U00002A3F', + "amp;": '\U00000026', + "and;": '\U00002227', + "andand;": '\U00002A55', + "andd;": '\U00002A5C', + "andslope;": '\U00002A58', + "andv;": '\U00002A5A', + "ang;": '\U00002220', + "ange;": '\U000029A4', + "angle;": '\U00002220', + "angmsd;": '\U00002221', + "angmsdaa;": '\U000029A8', + "angmsdab;": '\U000029A9', + "angmsdac;": '\U000029AA', + "angmsdad;": '\U000029AB', + "angmsdae;": '\U000029AC', + "angmsdaf;": '\U000029AD', + "angmsdag;": '\U000029AE', + "angmsdah;": '\U000029AF', + "angrt;": '\U0000221F', + "angrtvb;": '\U000022BE', + "angrtvbd;": '\U0000299D', + "angsph;": '\U00002222', + "angst;": '\U000000C5', + "angzarr;": '\U0000237C', + "aogon;": '\U00000105', + "aopf;": '\U0001D552', + "ap;": '\U00002248', + "apE;": '\U00002A70', + "apacir;": '\U00002A6F', + "ape;": '\U0000224A', + "apid;": '\U0000224B', + "apos;": '\U00000027', + "approx;": '\U00002248', + "approxeq;": '\U0000224A', + "aring;": '\U000000E5', + "ascr;": '\U0001D4B6', + "ast;": '\U0000002A', + "asymp;": '\U00002248', + "asympeq;": '\U0000224D', + "atilde;": '\U000000E3', + "auml;": '\U000000E4', + "awconint;": '\U00002233', + "awint;": '\U00002A11', + "bNot;": '\U00002AED', + "backcong;": '\U0000224C', + "backepsilon;": '\U000003F6', + "backprime;": '\U00002035', + "backsim;": '\U0000223D', + "backsimeq;": '\U000022CD', + "barvee;": '\U000022BD', + "barwed;": '\U00002305', + "barwedge;": '\U00002305', + "bbrk;": '\U000023B5', + "bbrktbrk;": '\U000023B6', + "bcong;": '\U0000224C', + "bcy;": '\U00000431', + "bdquo;": '\U0000201E', + "becaus;": '\U00002235', + "because;": '\U00002235', + "bemptyv;": '\U000029B0', + "bepsi;": '\U000003F6', + "bernou;": '\U0000212C', + "beta;": '\U000003B2', + "beth;": '\U00002136', + "between;": '\U0000226C', + "bfr;": '\U0001D51F', + "bigcap;": '\U000022C2', + "bigcirc;": '\U000025EF', + "bigcup;": '\U000022C3', + "bigodot;": '\U00002A00', + "bigoplus;": '\U00002A01', + "bigotimes;": '\U00002A02', + "bigsqcup;": '\U00002A06', + "bigstar;": '\U00002605', + "bigtriangledown;": '\U000025BD', + "bigtriangleup;": '\U000025B3', + "biguplus;": '\U00002A04', + "bigvee;": '\U000022C1', + "bigwedge;": '\U000022C0', + "bkarow;": '\U0000290D', + "blacklozenge;": '\U000029EB', + "blacksquare;": '\U000025AA', + "blacktriangle;": '\U000025B4', + "blacktriangledown;": '\U000025BE', + "blacktriangleleft;": '\U000025C2', + "blacktriangleright;": '\U000025B8', + "blank;": '\U00002423', + "blk12;": '\U00002592', + "blk14;": '\U00002591', + "blk34;": '\U00002593', + "block;": '\U00002588', + "bnot;": '\U00002310', + "bopf;": '\U0001D553', + "bot;": '\U000022A5', + "bottom;": '\U000022A5', + "bowtie;": '\U000022C8', + "boxDL;": '\U00002557', + "boxDR;": '\U00002554', + "boxDl;": '\U00002556', + "boxDr;": '\U00002553', + "boxH;": '\U00002550', + "boxHD;": '\U00002566', + "boxHU;": '\U00002569', + "boxHd;": '\U00002564', + "boxHu;": '\U00002567', + "boxUL;": '\U0000255D', + "boxUR;": '\U0000255A', + "boxUl;": '\U0000255C', + "boxUr;": '\U00002559', + "boxV;": '\U00002551', + "boxVH;": '\U0000256C', + "boxVL;": '\U00002563', + "boxVR;": '\U00002560', + "boxVh;": '\U0000256B', + "boxVl;": '\U00002562', + "boxVr;": '\U0000255F', + "boxbox;": '\U000029C9', + "boxdL;": '\U00002555', + "boxdR;": '\U00002552', + "boxdl;": '\U00002510', + "boxdr;": '\U0000250C', + "boxh;": '\U00002500', + "boxhD;": '\U00002565', + "boxhU;": '\U00002568', + "boxhd;": '\U0000252C', + "boxhu;": '\U00002534', + "boxminus;": '\U0000229F', + "boxplus;": '\U0000229E', + "boxtimes;": '\U000022A0', + "boxuL;": '\U0000255B', + "boxuR;": '\U00002558', + "boxul;": '\U00002518', + "boxur;": '\U00002514', + "boxv;": '\U00002502', + "boxvH;": '\U0000256A', + "boxvL;": '\U00002561', + "boxvR;": '\U0000255E', + "boxvh;": '\U0000253C', + "boxvl;": '\U00002524', + "boxvr;": '\U0000251C', + "bprime;": '\U00002035', + "breve;": '\U000002D8', + "brvbar;": '\U000000A6', + "bscr;": '\U0001D4B7', + "bsemi;": '\U0000204F', + "bsim;": '\U0000223D', + "bsime;": '\U000022CD', + "bsol;": '\U0000005C', + "bsolb;": '\U000029C5', + "bsolhsub;": '\U000027C8', + "bull;": '\U00002022', + "bullet;": '\U00002022', + "bump;": '\U0000224E', + "bumpE;": '\U00002AAE', + "bumpe;": '\U0000224F', + "bumpeq;": '\U0000224F', + "cacute;": '\U00000107', + "cap;": '\U00002229', + "capand;": '\U00002A44', + "capbrcup;": '\U00002A49', + "capcap;": '\U00002A4B', + "capcup;": '\U00002A47', + "capdot;": '\U00002A40', + "caret;": '\U00002041', + "caron;": '\U000002C7', + "ccaps;": '\U00002A4D', + "ccaron;": '\U0000010D', + "ccedil;": '\U000000E7', + "ccirc;": '\U00000109', + "ccups;": '\U00002A4C', + "ccupssm;": '\U00002A50', + "cdot;": '\U0000010B', + "cedil;": '\U000000B8', + "cemptyv;": '\U000029B2', + "cent;": '\U000000A2', + "centerdot;": '\U000000B7', + "cfr;": '\U0001D520', + "chcy;": '\U00000447', + "check;": '\U00002713', + "checkmark;": '\U00002713', + "chi;": '\U000003C7', + "cir;": '\U000025CB', + "cirE;": '\U000029C3', + "circ;": '\U000002C6', + "circeq;": '\U00002257', + "circlearrowleft;": '\U000021BA', + "circlearrowright;": '\U000021BB', + "circledR;": '\U000000AE', + "circledS;": '\U000024C8', + "circledast;": '\U0000229B', + "circledcirc;": '\U0000229A', + "circleddash;": '\U0000229D', + "cire;": '\U00002257', + "cirfnint;": '\U00002A10', + "cirmid;": '\U00002AEF', + "cirscir;": '\U000029C2', + "clubs;": '\U00002663', + "clubsuit;": '\U00002663', + "colon;": '\U0000003A', + "colone;": '\U00002254', + "coloneq;": '\U00002254', + "comma;": '\U0000002C', + "commat;": '\U00000040', + "comp;": '\U00002201', + "compfn;": '\U00002218', + "complement;": '\U00002201', + "complexes;": '\U00002102', + "cong;": '\U00002245', + "congdot;": '\U00002A6D', + "conint;": '\U0000222E', + "copf;": '\U0001D554', + "coprod;": '\U00002210', + "copy;": '\U000000A9', + "copysr;": '\U00002117', + "crarr;": '\U000021B5', + "cross;": '\U00002717', + "cscr;": '\U0001D4B8', + "csub;": '\U00002ACF', + "csube;": '\U00002AD1', + "csup;": '\U00002AD0', + "csupe;": '\U00002AD2', + "ctdot;": '\U000022EF', + "cudarrl;": '\U00002938', + "cudarrr;": '\U00002935', + "cuepr;": '\U000022DE', + "cuesc;": '\U000022DF', + "cularr;": '\U000021B6', + "cularrp;": '\U0000293D', + "cup;": '\U0000222A', + "cupbrcap;": '\U00002A48', + "cupcap;": '\U00002A46', + "cupcup;": '\U00002A4A', + "cupdot;": '\U0000228D', + "cupor;": '\U00002A45', + "curarr;": '\U000021B7', + "curarrm;": '\U0000293C', + "curlyeqprec;": '\U000022DE', + "curlyeqsucc;": '\U000022DF', + "curlyvee;": '\U000022CE', + "curlywedge;": '\U000022CF', + "curren;": '\U000000A4', + "curvearrowleft;": '\U000021B6', + "curvearrowright;": '\U000021B7', + "cuvee;": '\U000022CE', + "cuwed;": '\U000022CF', + "cwconint;": '\U00002232', + "cwint;": '\U00002231', + "cylcty;": '\U0000232D', + "dArr;": '\U000021D3', + "dHar;": '\U00002965', + "dagger;": '\U00002020', + "daleth;": '\U00002138', + "darr;": '\U00002193', + "dash;": '\U00002010', + "dashv;": '\U000022A3', + "dbkarow;": '\U0000290F', + "dblac;": '\U000002DD', + "dcaron;": '\U0000010F', + "dcy;": '\U00000434', + "dd;": '\U00002146', + "ddagger;": '\U00002021', + "ddarr;": '\U000021CA', + "ddotseq;": '\U00002A77', + "deg;": '\U000000B0', + "delta;": '\U000003B4', + "demptyv;": '\U000029B1', + "dfisht;": '\U0000297F', + "dfr;": '\U0001D521', + "dharl;": '\U000021C3', + "dharr;": '\U000021C2', + "diam;": '\U000022C4', + "diamond;": '\U000022C4', + "diamondsuit;": '\U00002666', + "diams;": '\U00002666', + "die;": '\U000000A8', + "digamma;": '\U000003DD', + "disin;": '\U000022F2', + "div;": '\U000000F7', + "divide;": '\U000000F7', + "divideontimes;": '\U000022C7', + "divonx;": '\U000022C7', + "djcy;": '\U00000452', + "dlcorn;": '\U0000231E', + "dlcrop;": '\U0000230D', + "dollar;": '\U00000024', + "dopf;": '\U0001D555', + "dot;": '\U000002D9', + "doteq;": '\U00002250', + "doteqdot;": '\U00002251', + "dotminus;": '\U00002238', + "dotplus;": '\U00002214', + "dotsquare;": '\U000022A1', + "doublebarwedge;": '\U00002306', + "downarrow;": '\U00002193', + "downdownarrows;": '\U000021CA', + "downharpoonleft;": '\U000021C3', + "downharpoonright;": '\U000021C2', + "drbkarow;": '\U00002910', + "drcorn;": '\U0000231F', + "drcrop;": '\U0000230C', + "dscr;": '\U0001D4B9', + "dscy;": '\U00000455', + "dsol;": '\U000029F6', + "dstrok;": '\U00000111', + "dtdot;": '\U000022F1', + "dtri;": '\U000025BF', + "dtrif;": '\U000025BE', + "duarr;": '\U000021F5', + "duhar;": '\U0000296F', + "dwangle;": '\U000029A6', + "dzcy;": '\U0000045F', + "dzigrarr;": '\U000027FF', + "eDDot;": '\U00002A77', + "eDot;": '\U00002251', + "eacute;": '\U000000E9', + "easter;": '\U00002A6E', + "ecaron;": '\U0000011B', + "ecir;": '\U00002256', + "ecirc;": '\U000000EA', + "ecolon;": '\U00002255', + "ecy;": '\U0000044D', + "edot;": '\U00000117', + "ee;": '\U00002147', + "efDot;": '\U00002252', + "efr;": '\U0001D522', + "eg;": '\U00002A9A', + "egrave;": '\U000000E8', + "egs;": '\U00002A96', + "egsdot;": '\U00002A98', + "el;": '\U00002A99', + "elinters;": '\U000023E7', + "ell;": '\U00002113', + "els;": '\U00002A95', + "elsdot;": '\U00002A97', + "emacr;": '\U00000113', + "empty;": '\U00002205', + "emptyset;": '\U00002205', + "emptyv;": '\U00002205', + "emsp;": '\U00002003', + "emsp13;": '\U00002004', + "emsp14;": '\U00002005', + "eng;": '\U0000014B', + "ensp;": '\U00002002', + "eogon;": '\U00000119', + "eopf;": '\U0001D556', + "epar;": '\U000022D5', + "eparsl;": '\U000029E3', + "eplus;": '\U00002A71', + "epsi;": '\U000003B5', + "epsilon;": '\U000003B5', + "epsiv;": '\U000003F5', + "eqcirc;": '\U00002256', + "eqcolon;": '\U00002255', + "eqsim;": '\U00002242', + "eqslantgtr;": '\U00002A96', + "eqslantless;": '\U00002A95', + "equals;": '\U0000003D', + "equest;": '\U0000225F', + "equiv;": '\U00002261', + "equivDD;": '\U00002A78', + "eqvparsl;": '\U000029E5', + "erDot;": '\U00002253', + "erarr;": '\U00002971', + "escr;": '\U0000212F', + "esdot;": '\U00002250', + "esim;": '\U00002242', + "eta;": '\U000003B7', + "eth;": '\U000000F0', + "euml;": '\U000000EB', + "euro;": '\U000020AC', + "excl;": '\U00000021', + "exist;": '\U00002203', + "expectation;": '\U00002130', + "exponentiale;": '\U00002147', + "fallingdotseq;": '\U00002252', + "fcy;": '\U00000444', + "female;": '\U00002640', + "ffilig;": '\U0000FB03', + "fflig;": '\U0000FB00', + "ffllig;": '\U0000FB04', + "ffr;": '\U0001D523', + "filig;": '\U0000FB01', + "flat;": '\U0000266D', + "fllig;": '\U0000FB02', + "fltns;": '\U000025B1', + "fnof;": '\U00000192', + "fopf;": '\U0001D557', + "forall;": '\U00002200', + "fork;": '\U000022D4', + "forkv;": '\U00002AD9', + "fpartint;": '\U00002A0D', + "frac12;": '\U000000BD', + "frac13;": '\U00002153', + "frac14;": '\U000000BC', + "frac15;": '\U00002155', + "frac16;": '\U00002159', + "frac18;": '\U0000215B', + "frac23;": '\U00002154', + "frac25;": '\U00002156', + "frac34;": '\U000000BE', + "frac35;": '\U00002157', + "frac38;": '\U0000215C', + "frac45;": '\U00002158', + "frac56;": '\U0000215A', + "frac58;": '\U0000215D', + "frac78;": '\U0000215E', + "frasl;": '\U00002044', + "frown;": '\U00002322', + "fscr;": '\U0001D4BB', + "gE;": '\U00002267', + "gEl;": '\U00002A8C', + "gacute;": '\U000001F5', + "gamma;": '\U000003B3', + "gammad;": '\U000003DD', + "gap;": '\U00002A86', + "gbreve;": '\U0000011F', + "gcirc;": '\U0000011D', + "gcy;": '\U00000433', + "gdot;": '\U00000121', + "ge;": '\U00002265', + "gel;": '\U000022DB', + "geq;": '\U00002265', + "geqq;": '\U00002267', + "geqslant;": '\U00002A7E', + "ges;": '\U00002A7E', + "gescc;": '\U00002AA9', + "gesdot;": '\U00002A80', + "gesdoto;": '\U00002A82', + "gesdotol;": '\U00002A84', + "gesles;": '\U00002A94', + "gfr;": '\U0001D524', + "gg;": '\U0000226B', + "ggg;": '\U000022D9', + "gimel;": '\U00002137', + "gjcy;": '\U00000453', + "gl;": '\U00002277', + "glE;": '\U00002A92', + "gla;": '\U00002AA5', + "glj;": '\U00002AA4', + "gnE;": '\U00002269', + "gnap;": '\U00002A8A', + "gnapprox;": '\U00002A8A', + "gne;": '\U00002A88', + "gneq;": '\U00002A88', + "gneqq;": '\U00002269', + "gnsim;": '\U000022E7', + "gopf;": '\U0001D558', + "grave;": '\U00000060', + "gscr;": '\U0000210A', + "gsim;": '\U00002273', + "gsime;": '\U00002A8E', + "gsiml;": '\U00002A90', + "gt;": '\U0000003E', + "gtcc;": '\U00002AA7', + "gtcir;": '\U00002A7A', + "gtdot;": '\U000022D7', + "gtlPar;": '\U00002995', + "gtquest;": '\U00002A7C', + "gtrapprox;": '\U00002A86', + "gtrarr;": '\U00002978', + "gtrdot;": '\U000022D7', + "gtreqless;": '\U000022DB', + "gtreqqless;": '\U00002A8C', + "gtrless;": '\U00002277', + "gtrsim;": '\U00002273', + "hArr;": '\U000021D4', + "hairsp;": '\U0000200A', + "half;": '\U000000BD', + "hamilt;": '\U0000210B', + "hardcy;": '\U0000044A', + "harr;": '\U00002194', + "harrcir;": '\U00002948', + "harrw;": '\U000021AD', + "hbar;": '\U0000210F', + "hcirc;": '\U00000125', + "hearts;": '\U00002665', + "heartsuit;": '\U00002665', + "hellip;": '\U00002026', + "hercon;": '\U000022B9', + "hfr;": '\U0001D525', + "hksearow;": '\U00002925', + "hkswarow;": '\U00002926', + "hoarr;": '\U000021FF', + "homtht;": '\U0000223B', + "hookleftarrow;": '\U000021A9', + "hookrightarrow;": '\U000021AA', + "hopf;": '\U0001D559', + "horbar;": '\U00002015', + "hscr;": '\U0001D4BD', + "hslash;": '\U0000210F', + "hstrok;": '\U00000127', + "hybull;": '\U00002043', + "hyphen;": '\U00002010', + "iacute;": '\U000000ED', + "ic;": '\U00002063', + "icirc;": '\U000000EE', + "icy;": '\U00000438', + "iecy;": '\U00000435', + "iexcl;": '\U000000A1', + "iff;": '\U000021D4', + "ifr;": '\U0001D526', + "igrave;": '\U000000EC', + "ii;": '\U00002148', + "iiiint;": '\U00002A0C', + "iiint;": '\U0000222D', + "iinfin;": '\U000029DC', + "iiota;": '\U00002129', + "ijlig;": '\U00000133', + "imacr;": '\U0000012B', + "image;": '\U00002111', + "imagline;": '\U00002110', + "imagpart;": '\U00002111', + "imath;": '\U00000131', + "imof;": '\U000022B7', + "imped;": '\U000001B5', + "in;": '\U00002208', + "incare;": '\U00002105', + "infin;": '\U0000221E', + "infintie;": '\U000029DD', + "inodot;": '\U00000131', + "int;": '\U0000222B', + "intcal;": '\U000022BA', + "integers;": '\U00002124', + "intercal;": '\U000022BA', + "intlarhk;": '\U00002A17', + "intprod;": '\U00002A3C', + "iocy;": '\U00000451', + "iogon;": '\U0000012F', + "iopf;": '\U0001D55A', + "iota;": '\U000003B9', + "iprod;": '\U00002A3C', + "iquest;": '\U000000BF', + "iscr;": '\U0001D4BE', + "isin;": '\U00002208', + "isinE;": '\U000022F9', + "isindot;": '\U000022F5', + "isins;": '\U000022F4', + "isinsv;": '\U000022F3', + "isinv;": '\U00002208', + "it;": '\U00002062', + "itilde;": '\U00000129', + "iukcy;": '\U00000456', + "iuml;": '\U000000EF', + "jcirc;": '\U00000135', + "jcy;": '\U00000439', + "jfr;": '\U0001D527', + "jmath;": '\U00000237', + "jopf;": '\U0001D55B', + "jscr;": '\U0001D4BF', + "jsercy;": '\U00000458', + "jukcy;": '\U00000454', + "kappa;": '\U000003BA', + "kappav;": '\U000003F0', + "kcedil;": '\U00000137', + "kcy;": '\U0000043A', + "kfr;": '\U0001D528', + "kgreen;": '\U00000138', + "khcy;": '\U00000445', + "kjcy;": '\U0000045C', + "kopf;": '\U0001D55C', + "kscr;": '\U0001D4C0', + "lAarr;": '\U000021DA', + "lArr;": '\U000021D0', + "lAtail;": '\U0000291B', + "lBarr;": '\U0000290E', + "lE;": '\U00002266', + "lEg;": '\U00002A8B', + "lHar;": '\U00002962', + "lacute;": '\U0000013A', + "laemptyv;": '\U000029B4', + "lagran;": '\U00002112', + "lambda;": '\U000003BB', + "lang;": '\U000027E8', + "langd;": '\U00002991', + "langle;": '\U000027E8', + "lap;": '\U00002A85', + "laquo;": '\U000000AB', + "larr;": '\U00002190', + "larrb;": '\U000021E4', + "larrbfs;": '\U0000291F', + "larrfs;": '\U0000291D', + "larrhk;": '\U000021A9', + "larrlp;": '\U000021AB', + "larrpl;": '\U00002939', + "larrsim;": '\U00002973', + "larrtl;": '\U000021A2', + "lat;": '\U00002AAB', + "latail;": '\U00002919', + "late;": '\U00002AAD', + "lbarr;": '\U0000290C', + "lbbrk;": '\U00002772', + "lbrace;": '\U0000007B', + "lbrack;": '\U0000005B', + "lbrke;": '\U0000298B', + "lbrksld;": '\U0000298F', + "lbrkslu;": '\U0000298D', + "lcaron;": '\U0000013E', + "lcedil;": '\U0000013C', + "lceil;": '\U00002308', + "lcub;": '\U0000007B', + "lcy;": '\U0000043B', + "ldca;": '\U00002936', + "ldquo;": '\U0000201C', + "ldquor;": '\U0000201E', + "ldrdhar;": '\U00002967', + "ldrushar;": '\U0000294B', + "ldsh;": '\U000021B2', + "le;": '\U00002264', + "leftarrow;": '\U00002190', + "leftarrowtail;": '\U000021A2', + "leftharpoondown;": '\U000021BD', + "leftharpoonup;": '\U000021BC', + "leftleftarrows;": '\U000021C7', + "leftrightarrow;": '\U00002194', + "leftrightarrows;": '\U000021C6', + "leftrightharpoons;": '\U000021CB', + "leftrightsquigarrow;": '\U000021AD', + "leftthreetimes;": '\U000022CB', + "leg;": '\U000022DA', + "leq;": '\U00002264', + "leqq;": '\U00002266', + "leqslant;": '\U00002A7D', + "les;": '\U00002A7D', + "lescc;": '\U00002AA8', + "lesdot;": '\U00002A7F', + "lesdoto;": '\U00002A81', + "lesdotor;": '\U00002A83', + "lesges;": '\U00002A93', + "lessapprox;": '\U00002A85', + "lessdot;": '\U000022D6', + "lesseqgtr;": '\U000022DA', + "lesseqqgtr;": '\U00002A8B', + "lessgtr;": '\U00002276', + "lesssim;": '\U00002272', + "lfisht;": '\U0000297C', + "lfloor;": '\U0000230A', + "lfr;": '\U0001D529', + "lg;": '\U00002276', + "lgE;": '\U00002A91', + "lhard;": '\U000021BD', + "lharu;": '\U000021BC', + "lharul;": '\U0000296A', + "lhblk;": '\U00002584', + "ljcy;": '\U00000459', + "ll;": '\U0000226A', + "llarr;": '\U000021C7', + "llcorner;": '\U0000231E', + "llhard;": '\U0000296B', + "lltri;": '\U000025FA', + "lmidot;": '\U00000140', + "lmoust;": '\U000023B0', + "lmoustache;": '\U000023B0', + "lnE;": '\U00002268', + "lnap;": '\U00002A89', + "lnapprox;": '\U00002A89', + "lne;": '\U00002A87', + "lneq;": '\U00002A87', + "lneqq;": '\U00002268', + "lnsim;": '\U000022E6', + "loang;": '\U000027EC', + "loarr;": '\U000021FD', + "lobrk;": '\U000027E6', + "longleftarrow;": '\U000027F5', + "longleftrightarrow;": '\U000027F7', + "longmapsto;": '\U000027FC', + "longrightarrow;": '\U000027F6', + "looparrowleft;": '\U000021AB', + "looparrowright;": '\U000021AC', + "lopar;": '\U00002985', + "lopf;": '\U0001D55D', + "loplus;": '\U00002A2D', + "lotimes;": '\U00002A34', + "lowast;": '\U00002217', + "lowbar;": '\U0000005F', + "loz;": '\U000025CA', + "lozenge;": '\U000025CA', + "lozf;": '\U000029EB', + "lpar;": '\U00000028', + "lparlt;": '\U00002993', + "lrarr;": '\U000021C6', + "lrcorner;": '\U0000231F', + "lrhar;": '\U000021CB', + "lrhard;": '\U0000296D', + "lrm;": '\U0000200E', + "lrtri;": '\U000022BF', + "lsaquo;": '\U00002039', + "lscr;": '\U0001D4C1', + "lsh;": '\U000021B0', + "lsim;": '\U00002272', + "lsime;": '\U00002A8D', + "lsimg;": '\U00002A8F', + "lsqb;": '\U0000005B', + "lsquo;": '\U00002018', + "lsquor;": '\U0000201A', + "lstrok;": '\U00000142', + "lt;": '\U0000003C', + "ltcc;": '\U00002AA6', + "ltcir;": '\U00002A79', + "ltdot;": '\U000022D6', + "lthree;": '\U000022CB', + "ltimes;": '\U000022C9', + "ltlarr;": '\U00002976', + "ltquest;": '\U00002A7B', + "ltrPar;": '\U00002996', + "ltri;": '\U000025C3', + "ltrie;": '\U000022B4', + "ltrif;": '\U000025C2', + "lurdshar;": '\U0000294A', + "luruhar;": '\U00002966', + "mDDot;": '\U0000223A', + "macr;": '\U000000AF', + "male;": '\U00002642', + "malt;": '\U00002720', + "maltese;": '\U00002720', + "map;": '\U000021A6', + "mapsto;": '\U000021A6', + "mapstodown;": '\U000021A7', + "mapstoleft;": '\U000021A4', + "mapstoup;": '\U000021A5', + "marker;": '\U000025AE', + "mcomma;": '\U00002A29', + "mcy;": '\U0000043C', + "mdash;": '\U00002014', + "measuredangle;": '\U00002221', + "mfr;": '\U0001D52A', + "mho;": '\U00002127', + "micro;": '\U000000B5', + "mid;": '\U00002223', + "midast;": '\U0000002A', + "midcir;": '\U00002AF0', + "middot;": '\U000000B7', + "minus;": '\U00002212', + "minusb;": '\U0000229F', + "minusd;": '\U00002238', + "minusdu;": '\U00002A2A', + "mlcp;": '\U00002ADB', + "mldr;": '\U00002026', + "mnplus;": '\U00002213', + "models;": '\U000022A7', + "mopf;": '\U0001D55E', + "mp;": '\U00002213', + "mscr;": '\U0001D4C2', + "mstpos;": '\U0000223E', + "mu;": '\U000003BC', + "multimap;": '\U000022B8', + "mumap;": '\U000022B8', + "nLeftarrow;": '\U000021CD', + "nLeftrightarrow;": '\U000021CE', + "nRightarrow;": '\U000021CF', + "nVDash;": '\U000022AF', + "nVdash;": '\U000022AE', + "nabla;": '\U00002207', + "nacute;": '\U00000144', + "nap;": '\U00002249', + "napos;": '\U00000149', + "napprox;": '\U00002249', + "natur;": '\U0000266E', + "natural;": '\U0000266E', + "naturals;": '\U00002115', + "nbsp;": '\U000000A0', + "ncap;": '\U00002A43', + "ncaron;": '\U00000148', + "ncedil;": '\U00000146', + "ncong;": '\U00002247', + "ncup;": '\U00002A42', + "ncy;": '\U0000043D', + "ndash;": '\U00002013', + "ne;": '\U00002260', + "neArr;": '\U000021D7', + "nearhk;": '\U00002924', + "nearr;": '\U00002197', + "nearrow;": '\U00002197', + "nequiv;": '\U00002262', + "nesear;": '\U00002928', + "nexist;": '\U00002204', + "nexists;": '\U00002204', + "nfr;": '\U0001D52B', + "nge;": '\U00002271', + "ngeq;": '\U00002271', + "ngsim;": '\U00002275', + "ngt;": '\U0000226F', + "ngtr;": '\U0000226F', + "nhArr;": '\U000021CE', + "nharr;": '\U000021AE', + "nhpar;": '\U00002AF2', + "ni;": '\U0000220B', + "nis;": '\U000022FC', + "nisd;": '\U000022FA', + "niv;": '\U0000220B', + "njcy;": '\U0000045A', + "nlArr;": '\U000021CD', + "nlarr;": '\U0000219A', + "nldr;": '\U00002025', + "nle;": '\U00002270', + "nleftarrow;": '\U0000219A', + "nleftrightarrow;": '\U000021AE', + "nleq;": '\U00002270', + "nless;": '\U0000226E', + "nlsim;": '\U00002274', + "nlt;": '\U0000226E', + "nltri;": '\U000022EA', + "nltrie;": '\U000022EC', + "nmid;": '\U00002224', + "nopf;": '\U0001D55F', + "not;": '\U000000AC', + "notin;": '\U00002209', + "notinva;": '\U00002209', + "notinvb;": '\U000022F7', + "notinvc;": '\U000022F6', + "notni;": '\U0000220C', + "notniva;": '\U0000220C', + "notnivb;": '\U000022FE', + "notnivc;": '\U000022FD', + "npar;": '\U00002226', + "nparallel;": '\U00002226', + "npolint;": '\U00002A14', + "npr;": '\U00002280', + "nprcue;": '\U000022E0', + "nprec;": '\U00002280', + "nrArr;": '\U000021CF', + "nrarr;": '\U0000219B', + "nrightarrow;": '\U0000219B', + "nrtri;": '\U000022EB', + "nrtrie;": '\U000022ED', + "nsc;": '\U00002281', + "nsccue;": '\U000022E1', + "nscr;": '\U0001D4C3', + "nshortmid;": '\U00002224', + "nshortparallel;": '\U00002226', + "nsim;": '\U00002241', + "nsime;": '\U00002244', + "nsimeq;": '\U00002244', + "nsmid;": '\U00002224', + "nspar;": '\U00002226', + "nsqsube;": '\U000022E2', + "nsqsupe;": '\U000022E3', + "nsub;": '\U00002284', + "nsube;": '\U00002288', + "nsubseteq;": '\U00002288', + "nsucc;": '\U00002281', + "nsup;": '\U00002285', + "nsupe;": '\U00002289', + "nsupseteq;": '\U00002289', + "ntgl;": '\U00002279', + "ntilde;": '\U000000F1', + "ntlg;": '\U00002278', + "ntriangleleft;": '\U000022EA', + "ntrianglelefteq;": '\U000022EC', + "ntriangleright;": '\U000022EB', + "ntrianglerighteq;": '\U000022ED', + "nu;": '\U000003BD', + "num;": '\U00000023', + "numero;": '\U00002116', + "numsp;": '\U00002007', + "nvDash;": '\U000022AD', + "nvHarr;": '\U00002904', + "nvdash;": '\U000022AC', + "nvinfin;": '\U000029DE', + "nvlArr;": '\U00002902', + "nvrArr;": '\U00002903', + "nwArr;": '\U000021D6', + "nwarhk;": '\U00002923', + "nwarr;": '\U00002196', + "nwarrow;": '\U00002196', + "nwnear;": '\U00002927', + "oS;": '\U000024C8', + "oacute;": '\U000000F3', + "oast;": '\U0000229B', + "ocir;": '\U0000229A', + "ocirc;": '\U000000F4', + "ocy;": '\U0000043E', + "odash;": '\U0000229D', + "odblac;": '\U00000151', + "odiv;": '\U00002A38', + "odot;": '\U00002299', + "odsold;": '\U000029BC', + "oelig;": '\U00000153', + "ofcir;": '\U000029BF', + "ofr;": '\U0001D52C', + "ogon;": '\U000002DB', + "ograve;": '\U000000F2', + "ogt;": '\U000029C1', + "ohbar;": '\U000029B5', + "ohm;": '\U000003A9', + "oint;": '\U0000222E', + "olarr;": '\U000021BA', + "olcir;": '\U000029BE', + "olcross;": '\U000029BB', + "oline;": '\U0000203E', + "olt;": '\U000029C0', + "omacr;": '\U0000014D', + "omega;": '\U000003C9', + "omicron;": '\U000003BF', + "omid;": '\U000029B6', + "ominus;": '\U00002296', + "oopf;": '\U0001D560', + "opar;": '\U000029B7', + "operp;": '\U000029B9', + "oplus;": '\U00002295', + "or;": '\U00002228', + "orarr;": '\U000021BB', + "ord;": '\U00002A5D', + "order;": '\U00002134', + "orderof;": '\U00002134', + "ordf;": '\U000000AA', + "ordm;": '\U000000BA', + "origof;": '\U000022B6', + "oror;": '\U00002A56', + "orslope;": '\U00002A57', + "orv;": '\U00002A5B', + "oscr;": '\U00002134', + "oslash;": '\U000000F8', + "osol;": '\U00002298', + "otilde;": '\U000000F5', + "otimes;": '\U00002297', + "otimesas;": '\U00002A36', + "ouml;": '\U000000F6', + "ovbar;": '\U0000233D', + "par;": '\U00002225', + "para;": '\U000000B6', + "parallel;": '\U00002225', + "parsim;": '\U00002AF3', + "parsl;": '\U00002AFD', + "part;": '\U00002202', + "pcy;": '\U0000043F', + "percnt;": '\U00000025', + "period;": '\U0000002E', + "permil;": '\U00002030', + "perp;": '\U000022A5', + "pertenk;": '\U00002031', + "pfr;": '\U0001D52D', + "phi;": '\U000003C6', + "phiv;": '\U000003D5', + "phmmat;": '\U00002133', + "phone;": '\U0000260E', + "pi;": '\U000003C0', + "pitchfork;": '\U000022D4', + "piv;": '\U000003D6', + "planck;": '\U0000210F', + "planckh;": '\U0000210E', + "plankv;": '\U0000210F', + "plus;": '\U0000002B', + "plusacir;": '\U00002A23', + "plusb;": '\U0000229E', + "pluscir;": '\U00002A22', + "plusdo;": '\U00002214', + "plusdu;": '\U00002A25', + "pluse;": '\U00002A72', + "plusmn;": '\U000000B1', + "plussim;": '\U00002A26', + "plustwo;": '\U00002A27', + "pm;": '\U000000B1', + "pointint;": '\U00002A15', + "popf;": '\U0001D561', + "pound;": '\U000000A3', + "pr;": '\U0000227A', + "prE;": '\U00002AB3', + "prap;": '\U00002AB7', + "prcue;": '\U0000227C', + "pre;": '\U00002AAF', + "prec;": '\U0000227A', + "precapprox;": '\U00002AB7', + "preccurlyeq;": '\U0000227C', + "preceq;": '\U00002AAF', + "precnapprox;": '\U00002AB9', + "precneqq;": '\U00002AB5', + "precnsim;": '\U000022E8', + "precsim;": '\U0000227E', + "prime;": '\U00002032', + "primes;": '\U00002119', + "prnE;": '\U00002AB5', + "prnap;": '\U00002AB9', + "prnsim;": '\U000022E8', + "prod;": '\U0000220F', + "profalar;": '\U0000232E', + "profline;": '\U00002312', + "profsurf;": '\U00002313', + "prop;": '\U0000221D', + "propto;": '\U0000221D', + "prsim;": '\U0000227E', + "prurel;": '\U000022B0', + "pscr;": '\U0001D4C5', + "psi;": '\U000003C8', + "puncsp;": '\U00002008', + "qfr;": '\U0001D52E', + "qint;": '\U00002A0C', + "qopf;": '\U0001D562', + "qprime;": '\U00002057', + "qscr;": '\U0001D4C6', + "quaternions;": '\U0000210D', + "quatint;": '\U00002A16', + "quest;": '\U0000003F', + "questeq;": '\U0000225F', + "quot;": '\U00000022', + "rAarr;": '\U000021DB', + "rArr;": '\U000021D2', + "rAtail;": '\U0000291C', + "rBarr;": '\U0000290F', + "rHar;": '\U00002964', + "racute;": '\U00000155', + "radic;": '\U0000221A', + "raemptyv;": '\U000029B3', + "rang;": '\U000027E9', + "rangd;": '\U00002992', + "range;": '\U000029A5', + "rangle;": '\U000027E9', + "raquo;": '\U000000BB', + "rarr;": '\U00002192', + "rarrap;": '\U00002975', + "rarrb;": '\U000021E5', + "rarrbfs;": '\U00002920', + "rarrc;": '\U00002933', + "rarrfs;": '\U0000291E', + "rarrhk;": '\U000021AA', + "rarrlp;": '\U000021AC', + "rarrpl;": '\U00002945', + "rarrsim;": '\U00002974', + "rarrtl;": '\U000021A3', + "rarrw;": '\U0000219D', + "ratail;": '\U0000291A', + "ratio;": '\U00002236', + "rationals;": '\U0000211A', + "rbarr;": '\U0000290D', + "rbbrk;": '\U00002773', + "rbrace;": '\U0000007D', + "rbrack;": '\U0000005D', + "rbrke;": '\U0000298C', + "rbrksld;": '\U0000298E', + "rbrkslu;": '\U00002990', + "rcaron;": '\U00000159', + "rcedil;": '\U00000157', + "rceil;": '\U00002309', + "rcub;": '\U0000007D', + "rcy;": '\U00000440', + "rdca;": '\U00002937', + "rdldhar;": '\U00002969', + "rdquo;": '\U0000201D', + "rdquor;": '\U0000201D', + "rdsh;": '\U000021B3', + "real;": '\U0000211C', + "realine;": '\U0000211B', + "realpart;": '\U0000211C', + "reals;": '\U0000211D', + "rect;": '\U000025AD', + "reg;": '\U000000AE', + "rfisht;": '\U0000297D', + "rfloor;": '\U0000230B', + "rfr;": '\U0001D52F', + "rhard;": '\U000021C1', + "rharu;": '\U000021C0', + "rharul;": '\U0000296C', + "rho;": '\U000003C1', + "rhov;": '\U000003F1', + "rightarrow;": '\U00002192', + "rightarrowtail;": '\U000021A3', + "rightharpoondown;": '\U000021C1', + "rightharpoonup;": '\U000021C0', + "rightleftarrows;": '\U000021C4', + "rightleftharpoons;": '\U000021CC', + "rightrightarrows;": '\U000021C9', + "rightsquigarrow;": '\U0000219D', + "rightthreetimes;": '\U000022CC', + "ring;": '\U000002DA', + "risingdotseq;": '\U00002253', + "rlarr;": '\U000021C4', + "rlhar;": '\U000021CC', + "rlm;": '\U0000200F', + "rmoust;": '\U000023B1', + "rmoustache;": '\U000023B1', + "rnmid;": '\U00002AEE', + "roang;": '\U000027ED', + "roarr;": '\U000021FE', + "robrk;": '\U000027E7', + "ropar;": '\U00002986', + "ropf;": '\U0001D563', + "roplus;": '\U00002A2E', + "rotimes;": '\U00002A35', + "rpar;": '\U00000029', + "rpargt;": '\U00002994', + "rppolint;": '\U00002A12', + "rrarr;": '\U000021C9', + "rsaquo;": '\U0000203A', + "rscr;": '\U0001D4C7', + "rsh;": '\U000021B1', + "rsqb;": '\U0000005D', + "rsquo;": '\U00002019', + "rsquor;": '\U00002019', + "rthree;": '\U000022CC', + "rtimes;": '\U000022CA', + "rtri;": '\U000025B9', + "rtrie;": '\U000022B5', + "rtrif;": '\U000025B8', + "rtriltri;": '\U000029CE', + "ruluhar;": '\U00002968', + "rx;": '\U0000211E', + "sacute;": '\U0000015B', + "sbquo;": '\U0000201A', + "sc;": '\U0000227B', + "scE;": '\U00002AB4', + "scap;": '\U00002AB8', + "scaron;": '\U00000161', + "sccue;": '\U0000227D', + "sce;": '\U00002AB0', + "scedil;": '\U0000015F', + "scirc;": '\U0000015D', + "scnE;": '\U00002AB6', + "scnap;": '\U00002ABA', + "scnsim;": '\U000022E9', + "scpolint;": '\U00002A13', + "scsim;": '\U0000227F', + "scy;": '\U00000441', + "sdot;": '\U000022C5', + "sdotb;": '\U000022A1', + "sdote;": '\U00002A66', + "seArr;": '\U000021D8', + "searhk;": '\U00002925', + "searr;": '\U00002198', + "searrow;": '\U00002198', + "sect;": '\U000000A7', + "semi;": '\U0000003B', + "seswar;": '\U00002929', + "setminus;": '\U00002216', + "setmn;": '\U00002216', + "sext;": '\U00002736', + "sfr;": '\U0001D530', + "sfrown;": '\U00002322', + "sharp;": '\U0000266F', + "shchcy;": '\U00000449', + "shcy;": '\U00000448', + "shortmid;": '\U00002223', + "shortparallel;": '\U00002225', + "shy;": '\U000000AD', + "sigma;": '\U000003C3', + "sigmaf;": '\U000003C2', + "sigmav;": '\U000003C2', + "sim;": '\U0000223C', + "simdot;": '\U00002A6A', + "sime;": '\U00002243', + "simeq;": '\U00002243', + "simg;": '\U00002A9E', + "simgE;": '\U00002AA0', + "siml;": '\U00002A9D', + "simlE;": '\U00002A9F', + "simne;": '\U00002246', + "simplus;": '\U00002A24', + "simrarr;": '\U00002972', + "slarr;": '\U00002190', + "smallsetminus;": '\U00002216', + "smashp;": '\U00002A33', + "smeparsl;": '\U000029E4', + "smid;": '\U00002223', + "smile;": '\U00002323', + "smt;": '\U00002AAA', + "smte;": '\U00002AAC', + "softcy;": '\U0000044C', + "sol;": '\U0000002F', + "solb;": '\U000029C4', + "solbar;": '\U0000233F', + "sopf;": '\U0001D564', + "spades;": '\U00002660', + "spadesuit;": '\U00002660', + "spar;": '\U00002225', + "sqcap;": '\U00002293', + "sqcup;": '\U00002294', + "sqsub;": '\U0000228F', + "sqsube;": '\U00002291', + "sqsubset;": '\U0000228F', + "sqsubseteq;": '\U00002291', + "sqsup;": '\U00002290', + "sqsupe;": '\U00002292', + "sqsupset;": '\U00002290', + "sqsupseteq;": '\U00002292', + "squ;": '\U000025A1', + "square;": '\U000025A1', + "squarf;": '\U000025AA', + "squf;": '\U000025AA', + "srarr;": '\U00002192', + "sscr;": '\U0001D4C8', + "ssetmn;": '\U00002216', + "ssmile;": '\U00002323', + "sstarf;": '\U000022C6', + "star;": '\U00002606', + "starf;": '\U00002605', + "straightepsilon;": '\U000003F5', + "straightphi;": '\U000003D5', + "strns;": '\U000000AF', + "sub;": '\U00002282', + "subE;": '\U00002AC5', + "subdot;": '\U00002ABD', + "sube;": '\U00002286', + "subedot;": '\U00002AC3', + "submult;": '\U00002AC1', + "subnE;": '\U00002ACB', + "subne;": '\U0000228A', + "subplus;": '\U00002ABF', + "subrarr;": '\U00002979', + "subset;": '\U00002282', + "subseteq;": '\U00002286', + "subseteqq;": '\U00002AC5', + "subsetneq;": '\U0000228A', + "subsetneqq;": '\U00002ACB', + "subsim;": '\U00002AC7', + "subsub;": '\U00002AD5', + "subsup;": '\U00002AD3', + "succ;": '\U0000227B', + "succapprox;": '\U00002AB8', + "succcurlyeq;": '\U0000227D', + "succeq;": '\U00002AB0', + "succnapprox;": '\U00002ABA', + "succneqq;": '\U00002AB6', + "succnsim;": '\U000022E9', + "succsim;": '\U0000227F', + "sum;": '\U00002211', + "sung;": '\U0000266A', + "sup;": '\U00002283', + "sup1;": '\U000000B9', + "sup2;": '\U000000B2', + "sup3;": '\U000000B3', + "supE;": '\U00002AC6', + "supdot;": '\U00002ABE', + "supdsub;": '\U00002AD8', + "supe;": '\U00002287', + "supedot;": '\U00002AC4', + "suphsol;": '\U000027C9', + "suphsub;": '\U00002AD7', + "suplarr;": '\U0000297B', + "supmult;": '\U00002AC2', + "supnE;": '\U00002ACC', + "supne;": '\U0000228B', + "supplus;": '\U00002AC0', + "supset;": '\U00002283', + "supseteq;": '\U00002287', + "supseteqq;": '\U00002AC6', + "supsetneq;": '\U0000228B', + "supsetneqq;": '\U00002ACC', + "supsim;": '\U00002AC8', + "supsub;": '\U00002AD4', + "supsup;": '\U00002AD6', + "swArr;": '\U000021D9', + "swarhk;": '\U00002926', + "swarr;": '\U00002199', + "swarrow;": '\U00002199', + "swnwar;": '\U0000292A', + "szlig;": '\U000000DF', + "target;": '\U00002316', + "tau;": '\U000003C4', + "tbrk;": '\U000023B4', + "tcaron;": '\U00000165', + "tcedil;": '\U00000163', + "tcy;": '\U00000442', + "tdot;": '\U000020DB', + "telrec;": '\U00002315', + "tfr;": '\U0001D531', + "there4;": '\U00002234', + "therefore;": '\U00002234', + "theta;": '\U000003B8', + "thetasym;": '\U000003D1', + "thetav;": '\U000003D1', + "thickapprox;": '\U00002248', + "thicksim;": '\U0000223C', + "thinsp;": '\U00002009', + "thkap;": '\U00002248', + "thksim;": '\U0000223C', + "thorn;": '\U000000FE', + "tilde;": '\U000002DC', + "times;": '\U000000D7', + "timesb;": '\U000022A0', + "timesbar;": '\U00002A31', + "timesd;": '\U00002A30', + "tint;": '\U0000222D', + "toea;": '\U00002928', + "top;": '\U000022A4', + "topbot;": '\U00002336', + "topcir;": '\U00002AF1', + "topf;": '\U0001D565', + "topfork;": '\U00002ADA', + "tosa;": '\U00002929', + "tprime;": '\U00002034', + "trade;": '\U00002122', + "triangle;": '\U000025B5', + "triangledown;": '\U000025BF', + "triangleleft;": '\U000025C3', + "trianglelefteq;": '\U000022B4', + "triangleq;": '\U0000225C', + "triangleright;": '\U000025B9', + "trianglerighteq;": '\U000022B5', + "tridot;": '\U000025EC', + "trie;": '\U0000225C', + "triminus;": '\U00002A3A', + "triplus;": '\U00002A39', + "trisb;": '\U000029CD', + "tritime;": '\U00002A3B', + "trpezium;": '\U000023E2', + "tscr;": '\U0001D4C9', + "tscy;": '\U00000446', + "tshcy;": '\U0000045B', + "tstrok;": '\U00000167', + "twixt;": '\U0000226C', + "twoheadleftarrow;": '\U0000219E', + "twoheadrightarrow;": '\U000021A0', + "uArr;": '\U000021D1', + "uHar;": '\U00002963', + "uacute;": '\U000000FA', + "uarr;": '\U00002191', + "ubrcy;": '\U0000045E', + "ubreve;": '\U0000016D', + "ucirc;": '\U000000FB', + "ucy;": '\U00000443', + "udarr;": '\U000021C5', + "udblac;": '\U00000171', + "udhar;": '\U0000296E', + "ufisht;": '\U0000297E', + "ufr;": '\U0001D532', + "ugrave;": '\U000000F9', + "uharl;": '\U000021BF', + "uharr;": '\U000021BE', + "uhblk;": '\U00002580', + "ulcorn;": '\U0000231C', + "ulcorner;": '\U0000231C', + "ulcrop;": '\U0000230F', + "ultri;": '\U000025F8', + "umacr;": '\U0000016B', + "uml;": '\U000000A8', + "uogon;": '\U00000173', + "uopf;": '\U0001D566', + "uparrow;": '\U00002191', + "updownarrow;": '\U00002195', + "upharpoonleft;": '\U000021BF', + "upharpoonright;": '\U000021BE', + "uplus;": '\U0000228E', + "upsi;": '\U000003C5', + "upsih;": '\U000003D2', + "upsilon;": '\U000003C5', + "upuparrows;": '\U000021C8', + "urcorn;": '\U0000231D', + "urcorner;": '\U0000231D', + "urcrop;": '\U0000230E', + "uring;": '\U0000016F', + "urtri;": '\U000025F9', + "uscr;": '\U0001D4CA', + "utdot;": '\U000022F0', + "utilde;": '\U00000169', + "utri;": '\U000025B5', + "utrif;": '\U000025B4', + "uuarr;": '\U000021C8', + "uuml;": '\U000000FC', + "uwangle;": '\U000029A7', + "vArr;": '\U000021D5', + "vBar;": '\U00002AE8', + "vBarv;": '\U00002AE9', + "vDash;": '\U000022A8', + "vangrt;": '\U0000299C', + "varepsilon;": '\U000003F5', + "varkappa;": '\U000003F0', + "varnothing;": '\U00002205', + "varphi;": '\U000003D5', + "varpi;": '\U000003D6', + "varpropto;": '\U0000221D', + "varr;": '\U00002195', + "varrho;": '\U000003F1', + "varsigma;": '\U000003C2', + "vartheta;": '\U000003D1', + "vartriangleleft;": '\U000022B2', + "vartriangleright;": '\U000022B3', + "vcy;": '\U00000432', + "vdash;": '\U000022A2', + "vee;": '\U00002228', + "veebar;": '\U000022BB', + "veeeq;": '\U0000225A', + "vellip;": '\U000022EE', + "verbar;": '\U0000007C', + "vert;": '\U0000007C', + "vfr;": '\U0001D533', + "vltri;": '\U000022B2', + "vopf;": '\U0001D567', + "vprop;": '\U0000221D', + "vrtri;": '\U000022B3', + "vscr;": '\U0001D4CB', + "vzigzag;": '\U0000299A', + "wcirc;": '\U00000175', + "wedbar;": '\U00002A5F', + "wedge;": '\U00002227', + "wedgeq;": '\U00002259', + "weierp;": '\U00002118', + "wfr;": '\U0001D534', + "wopf;": '\U0001D568', + "wp;": '\U00002118', + "wr;": '\U00002240', + "wreath;": '\U00002240', + "wscr;": '\U0001D4CC', + "xcap;": '\U000022C2', + "xcirc;": '\U000025EF', + "xcup;": '\U000022C3', + "xdtri;": '\U000025BD', + "xfr;": '\U0001D535', + "xhArr;": '\U000027FA', + "xharr;": '\U000027F7', + "xi;": '\U000003BE', + "xlArr;": '\U000027F8', + "xlarr;": '\U000027F5', + "xmap;": '\U000027FC', + "xnis;": '\U000022FB', + "xodot;": '\U00002A00', + "xopf;": '\U0001D569', + "xoplus;": '\U00002A01', + "xotime;": '\U00002A02', + "xrArr;": '\U000027F9', + "xrarr;": '\U000027F6', + "xscr;": '\U0001D4CD', + "xsqcup;": '\U00002A06', + "xuplus;": '\U00002A04', + "xutri;": '\U000025B3', + "xvee;": '\U000022C1', + "xwedge;": '\U000022C0', + "yacute;": '\U000000FD', + "yacy;": '\U0000044F', + "ycirc;": '\U00000177', + "ycy;": '\U0000044B', + "yen;": '\U000000A5', + "yfr;": '\U0001D536', + "yicy;": '\U00000457', + "yopf;": '\U0001D56A', + "yscr;": '\U0001D4CE', + "yucy;": '\U0000044E', + "yuml;": '\U000000FF', + "zacute;": '\U0000017A', + "zcaron;": '\U0000017E', + "zcy;": '\U00000437', + "zdot;": '\U0000017C', + "zeetrf;": '\U00002128', + "zeta;": '\U000003B6', + "zfr;": '\U0001D537', + "zhcy;": '\U00000436', + "zigrarr;": '\U000021DD', + "zopf;": '\U0001D56B', + "zscr;": '\U0001D4CF', + "zwj;": '\U0000200D', + "zwnj;": '\U0000200C', + "AElig": '\U000000C6', + "AMP": '\U00000026', + "Aacute": '\U000000C1', + "Acirc": '\U000000C2', + "Agrave": '\U000000C0', + "Aring": '\U000000C5', + "Atilde": '\U000000C3', + "Auml": '\U000000C4', + "COPY": '\U000000A9', + "Ccedil": '\U000000C7', + "ETH": '\U000000D0', + "Eacute": '\U000000C9', + "Ecirc": '\U000000CA', + "Egrave": '\U000000C8', + "Euml": '\U000000CB', + "GT": '\U0000003E', + "Iacute": '\U000000CD', + "Icirc": '\U000000CE', + "Igrave": '\U000000CC', + "Iuml": '\U000000CF', + "LT": '\U0000003C', + "Ntilde": '\U000000D1', + "Oacute": '\U000000D3', + "Ocirc": '\U000000D4', + "Ograve": '\U000000D2', + "Oslash": '\U000000D8', + "Otilde": '\U000000D5', + "Ouml": '\U000000D6', + "QUOT": '\U00000022', + "REG": '\U000000AE', + "THORN": '\U000000DE', + "Uacute": '\U000000DA', + "Ucirc": '\U000000DB', + "Ugrave": '\U000000D9', + "Uuml": '\U000000DC', + "Yacute": '\U000000DD', + "aacute": '\U000000E1', + "acirc": '\U000000E2', + "acute": '\U000000B4', + "aelig": '\U000000E6', + "agrave": '\U000000E0', + "amp": '\U00000026', + "aring": '\U000000E5', + "atilde": '\U000000E3', + "auml": '\U000000E4', + "brvbar": '\U000000A6', + "ccedil": '\U000000E7', + "cedil": '\U000000B8', + "cent": '\U000000A2', + "copy": '\U000000A9', + "curren": '\U000000A4', + "deg": '\U000000B0', + "divide": '\U000000F7', + "eacute": '\U000000E9', + "ecirc": '\U000000EA', + "egrave": '\U000000E8', + "eth": '\U000000F0', + "euml": '\U000000EB', + "frac12": '\U000000BD', + "frac14": '\U000000BC', + "frac34": '\U000000BE', + "gt": '\U0000003E', + "iacute": '\U000000ED', + "icirc": '\U000000EE', + "iexcl": '\U000000A1', + "igrave": '\U000000EC', + "iquest": '\U000000BF', + "iuml": '\U000000EF', + "laquo": '\U000000AB', + "lt": '\U0000003C', + "macr": '\U000000AF', + "micro": '\U000000B5', + "middot": '\U000000B7', + "nbsp": '\U000000A0', + "not": '\U000000AC', + "ntilde": '\U000000F1', + "oacute": '\U000000F3', + "ocirc": '\U000000F4', + "ograve": '\U000000F2', + "ordf": '\U000000AA', + "ordm": '\U000000BA', + "oslash": '\U000000F8', + "otilde": '\U000000F5', + "ouml": '\U000000F6', + "para": '\U000000B6', + "plusmn": '\U000000B1', + "pound": '\U000000A3', + "quot": '\U00000022', + "raquo": '\U000000BB', + "reg": '\U000000AE', + "sect": '\U000000A7', + "shy": '\U000000AD', + "sup1": '\U000000B9', + "sup2": '\U000000B2', + "sup3": '\U000000B3', + "szlig": '\U000000DF', + "thorn": '\U000000FE', + "times": '\U000000D7', + "uacute": '\U000000FA', + "ucirc": '\U000000FB', + "ugrave": '\U000000F9', + "uml": '\U000000A8', + "uuml": '\U000000FC', + "yacute": '\U000000FD', + "yen": '\U000000A5', + "yuml": '\U000000FF', +} + +// HTML entities that are two unicode codepoints. +var entity2 = map[string][2]rune{ + // TODO(nigeltao): Handle replacements that are wider than their names. + // "nLt;": {'\u226A', '\u20D2'}, + // "nGt;": {'\u226B', '\u20D2'}, + "NotEqualTilde;": {'\u2242', '\u0338'}, + "NotGreaterFullEqual;": {'\u2267', '\u0338'}, + "NotGreaterGreater;": {'\u226B', '\u0338'}, + "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'}, + "NotHumpDownHump;": {'\u224E', '\u0338'}, + "NotHumpEqual;": {'\u224F', '\u0338'}, + "NotLeftTriangleBar;": {'\u29CF', '\u0338'}, + "NotLessLess;": {'\u226A', '\u0338'}, + "NotLessSlantEqual;": {'\u2A7D', '\u0338'}, + "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'}, + "NotNestedLessLess;": {'\u2AA1', '\u0338'}, + "NotPrecedesEqual;": {'\u2AAF', '\u0338'}, + "NotRightTriangleBar;": {'\u29D0', '\u0338'}, + "NotSquareSubset;": {'\u228F', '\u0338'}, + "NotSquareSuperset;": {'\u2290', '\u0338'}, + "NotSubset;": {'\u2282', '\u20D2'}, + "NotSucceedsEqual;": {'\u2AB0', '\u0338'}, + "NotSucceedsTilde;": {'\u227F', '\u0338'}, + "NotSuperset;": {'\u2283', '\u20D2'}, + "ThickSpace;": {'\u205F', '\u200A'}, + "acE;": {'\u223E', '\u0333'}, + "bne;": {'\u003D', '\u20E5'}, + "bnequiv;": {'\u2261', '\u20E5'}, + "caps;": {'\u2229', '\uFE00'}, + "cups;": {'\u222A', '\uFE00'}, + "fjlig;": {'\u0066', '\u006A'}, + "gesl;": {'\u22DB', '\uFE00'}, + "gvertneqq;": {'\u2269', '\uFE00'}, + "gvnE;": {'\u2269', '\uFE00'}, + "lates;": {'\u2AAD', '\uFE00'}, + "lesg;": {'\u22DA', '\uFE00'}, + "lvertneqq;": {'\u2268', '\uFE00'}, + "lvnE;": {'\u2268', '\uFE00'}, + "nGg;": {'\u22D9', '\u0338'}, + "nGtv;": {'\u226B', '\u0338'}, + "nLl;": {'\u22D8', '\u0338'}, + "nLtv;": {'\u226A', '\u0338'}, + "nang;": {'\u2220', '\u20D2'}, + "napE;": {'\u2A70', '\u0338'}, + "napid;": {'\u224B', '\u0338'}, + "nbump;": {'\u224E', '\u0338'}, + "nbumpe;": {'\u224F', '\u0338'}, + "ncongdot;": {'\u2A6D', '\u0338'}, + "nedot;": {'\u2250', '\u0338'}, + "nesim;": {'\u2242', '\u0338'}, + "ngE;": {'\u2267', '\u0338'}, + "ngeqq;": {'\u2267', '\u0338'}, + "ngeqslant;": {'\u2A7E', '\u0338'}, + "nges;": {'\u2A7E', '\u0338'}, + "nlE;": {'\u2266', '\u0338'}, + "nleqq;": {'\u2266', '\u0338'}, + "nleqslant;": {'\u2A7D', '\u0338'}, + "nles;": {'\u2A7D', '\u0338'}, + "notinE;": {'\u22F9', '\u0338'}, + "notindot;": {'\u22F5', '\u0338'}, + "nparsl;": {'\u2AFD', '\u20E5'}, + "npart;": {'\u2202', '\u0338'}, + "npre;": {'\u2AAF', '\u0338'}, + "npreceq;": {'\u2AAF', '\u0338'}, + "nrarrc;": {'\u2933', '\u0338'}, + "nrarrw;": {'\u219D', '\u0338'}, + "nsce;": {'\u2AB0', '\u0338'}, + "nsubE;": {'\u2AC5', '\u0338'}, + "nsubset;": {'\u2282', '\u20D2'}, + "nsubseteqq;": {'\u2AC5', '\u0338'}, + "nsucceq;": {'\u2AB0', '\u0338'}, + "nsupE;": {'\u2AC6', '\u0338'}, + "nsupset;": {'\u2283', '\u20D2'}, + "nsupseteqq;": {'\u2AC6', '\u0338'}, + "nvap;": {'\u224D', '\u20D2'}, + "nvge;": {'\u2265', '\u20D2'}, + "nvgt;": {'\u003E', '\u20D2'}, + "nvle;": {'\u2264', '\u20D2'}, + "nvlt;": {'\u003C', '\u20D2'}, + "nvltrie;": {'\u22B4', '\u20D2'}, + "nvrtrie;": {'\u22B5', '\u20D2'}, + "nvsim;": {'\u223C', '\u20D2'}, + "race;": {'\u223D', '\u0331'}, + "smtes;": {'\u2AAC', '\uFE00'}, + "sqcaps;": {'\u2293', '\uFE00'}, + "sqcups;": {'\u2294', '\uFE00'}, + "varsubsetneq;": {'\u228A', '\uFE00'}, + "varsubsetneqq;": {'\u2ACB', '\uFE00'}, + "varsupsetneq;": {'\u228B', '\uFE00'}, + "varsupsetneqq;": {'\u2ACC', '\uFE00'}, + "vnsub;": {'\u2282', '\u20D2'}, + "vnsup;": {'\u2283', '\u20D2'}, + "vsubnE;": {'\u2ACB', '\uFE00'}, + "vsubne;": {'\u228A', '\uFE00'}, + "vsupnE;": {'\u2ACC', '\uFE00'}, + "vsupne;": {'\u228B', '\uFE00'}, +} diff --git a/gnovm/stdlibs/html/entity_test.gno b/gnovm/stdlibs/html/entity_test.gno new file mode 100644 index 00000000000..6688ed2c43a --- /dev/null +++ b/gnovm/stdlibs/html/entity_test.gno @@ -0,0 +1,37 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "testing" + "unicode/utf8" +) + +func init() { + UnescapeString("") // force load of entity maps +} + +func TestEntityLength(t *testing.T) { + if len(entity) == 0 || len(entity2) == 0 { + t.Fatal("maps not loaded") + } + + // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key). + // The +1 comes from the leading "&". This property implies that the length of + // unescaped text is <= the length of escaped text. + for k, v := range entity { + if 1+len(k) < utf8.RuneLen(v) { + t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v)) + } + if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' { + t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon) + } + } + for k, v := range entity2 { + if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) { + t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1])) + } + } +} diff --git a/gnovm/stdlibs/html/escape.gno b/gnovm/stdlibs/html/escape.gno new file mode 100644 index 00000000000..6d911239852 --- /dev/null +++ b/gnovm/stdlibs/html/escape.gno @@ -0,0 +1,213 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package html provides functions for escaping and unescaping HTML text. +package html + +import ( + "strings" + "unicode/utf8" +) + +// These replacements permit compatibility with old numeric entities that +// assumed Windows-1252 encoding. +// https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state +var replacementTable = [...]rune{ + '\u20AC', // First entry is what 0x80 should be replaced with. + '\u0081', + '\u201A', + '\u0192', + '\u201E', + '\u2026', + '\u2020', + '\u2021', + '\u02C6', + '\u2030', + '\u0160', + '\u2039', + '\u0152', + '\u008D', + '\u017D', + '\u008F', + '\u0090', + '\u2018', + '\u2019', + '\u201C', + '\u201D', + '\u2022', + '\u2013', + '\u2014', + '\u02DC', + '\u2122', + '\u0161', + '\u203A', + '\u0153', + '\u009D', + '\u017E', + '\u0178', // Last entry is 0x9F. + // 0x00->'\uFFFD' is handled programmatically. + // 0x0D->'\u000D' is a no-op. +} + +// unescapeEntity reads an entity like "<" from b[src:] and writes the +// corresponding "<" to b[dst:], returning the incremented dst and src cursors. +// Precondition: b[src] == '&' && dst <= src. +func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) { + const attribute = false + + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference + + // i starts at 1 because we already know that s[0] == '&'. + i, s := 1, b[src:] + + if len(s) <= 1 { + b[dst] = b[src] + return dst + 1, src + 1 + } + + if s[i] == '#' { + if len(s) <= 3 { // We need to have at least "&#.". + b[dst] = b[src] + return dst + 1, src + 1 + } + i++ + c := s[i] + hex := false + if c == 'x' || c == 'X' { + hex = true + i++ + } + + x := '\x00' + for i < len(s) { + c = s[i] + i++ + if hex { + if '0' <= c && c <= '9' { + x = 16*x + rune(c) - '0' + continue + } else if 'a' <= c && c <= 'f' { + x = 16*x + rune(c) - 'a' + 10 + continue + } else if 'A' <= c && c <= 'F' { + x = 16*x + rune(c) - 'A' + 10 + continue + } + } else if '0' <= c && c <= '9' { + x = 10*x + rune(c) - '0' + continue + } + if c != ';' { + i-- + } + break + } + + if i <= 3 { // No characters matched. + b[dst] = b[src] + return dst + 1, src + 1 + } + + if 0x80 <= x && x <= 0x9F { + // Replace characters from Windows-1252 with UTF-8 equivalents. + x = replacementTable[x-0x80] + } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF { + // Replace invalid characters with the replacement character. + x = '\uFFFD' + } + + return dst + utf8.EncodeRune(b[dst:], x), src + i + } + + // Consume the maximum number of characters possible, with the + // consumed characters matching one of the named references. + + for i < len(s) { + c := s[i] + i++ + // Lower-cased characters are more common in entities, so we check for them first. + if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { + continue + } + if c != ';' { + i-- + } + break + } + + entityName := s[1:i] + if len(entityName) == 0 { + // No-op. + } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { + // No-op. + } else if x := entity[string(entityName)]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + i + } else if x := entity2[string(entityName)]; x[0] != 0 { + dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) + return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i + } else if !attribute { + maxLen := len(entityName) - 1 + if maxLen > longestEntityWithoutSemicolon { + maxLen = longestEntityWithoutSemicolon + } + for j := maxLen; j > 1; j-- { + if x := entity[string(entityName[:j])]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 + } + } + } + + dst1, src1 = dst+i, src+i + copy(b[dst:dst1], b[src:src1]) + return dst1, src1 +} + +var htmlEscaper = strings.NewReplacer( + `&`, "&", + `'`, "'", // "'" is shorter than "'" and apos was not in HTML until HTML5. + `<`, "<", + `>`, ">", + `"`, """, // """ is shorter than """. +) + +// EscapeString escapes special characters like "<" to become "<". It +// escapes only five such characters: <, >, &, ' and ". +// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't +// always true. +func EscapeString(s string) string { + return htmlEscaper.Replace(s) +} + +// UnescapeString unescapes entities like "<" to become "<". It unescapes a +// larger range of entities than EscapeString escapes. For example, "á" +// unescapes to "á", as does "á" and "á". +// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't +// always true. +func UnescapeString(s string) string { + i := strings.IndexByte(s, '&') + + if i < 0 { + return s + } + + b := []byte(s) + dst, src := unescapeEntity(b, i, i) + for len(s[src:]) > 0 { + if s[src] == '&' { + i = 0 + } else { + i = strings.IndexByte(s[src:], '&') + } + if i < 0 { + dst += copy(b[dst:], s[src:]) + break + } + + if i > 0 { + copy(b[dst:], s[src:src+i]) + } + dst, src = unescapeEntity(b, dst+i, src+i) + } + return string(b[:dst]) +} diff --git a/gnovm/stdlibs/html/escape_test.gno b/gnovm/stdlibs/html/escape_test.gno new file mode 100644 index 00000000000..8b51a55409f --- /dev/null +++ b/gnovm/stdlibs/html/escape_test.gno @@ -0,0 +1,169 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "strings" + "testing" +) + +type unescapeTest struct { + // A short description of the test case. + desc string + // The HTML text. + html string + // The unescaped text. + unescaped string +} + +var unescapeTests = []unescapeTest{ + // Handle no entities. + { + "copy", + "A\ttext\nstring", + "A\ttext\nstring", + }, + // Handle simple named entities. + { + "simple", + "& > <", + "& > <", + }, + // Handle hitting the end of the string. + { + "stringEnd", + "& &", + "& &", + }, + // Handle entities with two codepoints. + { + "multiCodepoint", + "text ⋛︀ blah", + "text \u22db\ufe00 blah", + }, + // Handle decimal numeric entities. + { + "decimalEntity", + "Delta = Δ ", + "Delta = Δ ", + }, + // Handle hexadecimal numeric entities. + { + "hexadecimalEntity", + "Lambda = λ = λ ", + "Lambda = λ = λ ", + }, + // Handle numeric early termination. + { + "numericEnds", + "&# &#x €43 © = ©f = ©", + "&# &#x €43 © = ©f = ©", + }, + // Handle numeric ISO-8859-1 entity replacements. + { + "numericReplacements", + "Footnote‡", + "Footnote‡", + }, + // Handle single ampersand. + { + "copySingleAmpersand", + "&", + "&", + }, + // Handle ampersand followed by non-entity. + { + "copyAmpersandNonEntity", + "text &test", + "text &test", + }, + // Handle "&#". + { + "copyAmpersandHash", + "text &#", + "text &#", + }, +} + +func TestUnescape(t *testing.T) { + for _, tt := range unescapeTests { + unescaped := UnescapeString(tt.html) + if unescaped != tt.unescaped { + t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped) + } + } +} + +func TestUnescapeEscape(t *testing.T) { + ss := []string{ + ``, + `abc def`, + `a & b`, + `a&b`, + `a & b`, + `"`, + `"`, + `"<&>"`, + `"<&>"`, + `3&5==1 && 0<1, "0<1", a+acute=á`, + `The special characters are: <, >, &, ' and "`, + } + for _, s := range ss { + if got := UnescapeString(EscapeString(s)); got != s { + t.Errorf("got %q want %q", got, s) + } + } +} + +var ( + benchEscapeData = strings.Repeat("AAAAA < BBBBB > CCCCC & DDDDD ' EEEEE \" ", 100) + benchEscapeNone = strings.Repeat("AAAAA x BBBBB x CCCCC x DDDDD x EEEEE x ", 100) + benchUnescapeSparse = strings.Repeat(strings.Repeat("AAAAA x BBBBB x CCCCC x DDDDD x EEEEE x ", 10)+"&", 10) + benchUnescapeDense = strings.Repeat("&< & <", 100) +) + +func BenchmarkEscape(b *testing.B) { + n := 0 + for i := 0; i < b.N; i++ { + n += len(EscapeString(benchEscapeData)) + } +} + +func BenchmarkEscapeNone(b *testing.B) { + n := 0 + for i := 0; i < b.N; i++ { + n += len(EscapeString(benchEscapeNone)) + } +} + +func BenchmarkUnescape(b *testing.B) { + s := EscapeString(benchEscapeData) + n := 0 + for i := 0; i < b.N; i++ { + n += len(UnescapeString(s)) + } +} + +func BenchmarkUnescapeNone(b *testing.B) { + s := EscapeString(benchEscapeNone) + n := 0 + for i := 0; i < b.N; i++ { + n += len(UnescapeString(s)) + } +} + +func BenchmarkUnescapeSparse(b *testing.B) { + n := 0 + for i := 0; i < b.N; i++ { + n += len(UnescapeString(benchUnescapeSparse)) + } +} + +func BenchmarkUnescapeDense(b *testing.B) { + n := 0 + for i := 0; i < b.N; i++ { + n += len(UnescapeString(benchUnescapeDense)) + } +} From 41881ece1e3f148187912f9c38738b3e8ba49889 Mon Sep 17 00:00:00 2001 From: Sergio Maria Matone Date: Thu, 3 Oct 2024 11:20:46 +0200 Subject: [PATCH 05/20] chore: ci(benchmarks) Feat/benchmarks master push (#2891) Restructuring Benchmarks workflow in the following way * Reducing workflows for benchmarks to a single one (instead of two different ones) * Workflow is triggered only when PR is finally merged with master branch * There is a single flow of benchmarks performance to verify * Benchmarks do not impact PR * An Alert is automatically added as comment to each commit when regressions are introduced respect to previous results --- .github/workflows/benchmark-check.yml | 13 ------- ...template.yml => benchmark-master-push.yml} | 34 ++++++++----------- .github/workflows/benchmark-publish.yml | 15 -------- 3 files changed, 14 insertions(+), 48 deletions(-) delete mode 100644 .github/workflows/benchmark-check.yml rename .github/workflows/{benchmark_template.yml => benchmark-master-push.yml} (74%) delete mode 100644 .github/workflows/benchmark-publish.yml diff --git a/.github/workflows/benchmark-check.yml b/.github/workflows/benchmark-check.yml deleted file mode 100644 index 8f763d1ec11..00000000000 --- a/.github/workflows/benchmark-check.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: run benchmarks on every PR - -on: - pull_request: - -jobs: - check: - uses: ./.github/workflows/benchmark_template.yml - secrets: inherit - with: - publish: false - test-flags: "-short" - external-data-json-path: "./cache/benchmark-data.json" \ No newline at end of file diff --git a/.github/workflows/benchmark_template.yml b/.github/workflows/benchmark-master-push.yml similarity index 74% rename from .github/workflows/benchmark_template.yml rename to .github/workflows/benchmark-master-push.yml index f7988a463c6..7067395bc59 100644 --- a/.github/workflows/benchmark_template.yml +++ b/.github/workflows/benchmark-master-push.yml @@ -1,18 +1,11 @@ -name: benchmarks +name: run benchmarks when pushing on main branch + on: - workflow_call: - inputs: - publish: - required: true - type: boolean - test-flags: - required: true - type: string - runner-additional-tag: - type: string - default: benchmarks - external-data-json-path: - type: string + push: + branches: + - master + + # publish: true permissions: # deployments permission to deploy GitHub pages website @@ -26,7 +19,7 @@ env: jobs: benchmarks: if: ${{ github.repository == 'gnolang/gno' }} - runs-on: [self-hosted, Linux, X64, "${{ inputs.runner-additional-tag }}"] + runs-on: [self-hosted, Linux, X64, benchmarks] steps: - name: Checkout uses: actions/checkout@v4 @@ -40,7 +33,7 @@ jobs: - name: Run benchmark run: | go test -benchmem -bench=. ./... -run=^$ \ - -cpu 1,2 ${{ inputs.test-flags }} | tee benchmarks.txt + -cpu 1,2 -timeout 50m | tee benchmarks.txt - name: Download previous benchmark data uses: actions/cache@v4 @@ -56,11 +49,13 @@ jobs: tool: 'go' output-file-path: benchmarks.txt # Where the previous data file is stored - external-data-json-path: ${{ inputs.external-data-json-path }} + external-data-json-path: ./cache/benchmark-data.json + max-items-in-chart: 100 # Show alert with commit comment on detecting possible performance regression - alert-threshold: '20%' + alert-threshold: '100%' fail-on-alert: true comment-on-alert: true + alert-comment-cc-users: '@ajnavarro,@thehowl,@zivkovicmilos' # Enable Job Summary for PRs summary-always: true github-token: ${{ secrets.GITHUB_TOKEN }} @@ -68,5 +63,4 @@ jobs: # gh-repository: 'github.com/gnolang/benchmarks' # on gh-pages branch gh-pages-branch: gh-benchmarks benchmark-data-dir-path: . - auto-push: ${{ inputs.publish }} - alert-comment-cc-users: '@ajnavarro,@thehowl,@zivkovicmilos' + auto-push: true diff --git a/.github/workflows/benchmark-publish.yml b/.github/workflows/benchmark-publish.yml deleted file mode 100644 index 37fd452a163..00000000000 --- a/.github/workflows/benchmark-publish.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: run benchmarks on main branch every day - -on: - workflow_dispatch: - schedule: - - cron: '0 0 * * *' # run on default branch every day - -jobs: - publish: - uses: ./.github/workflows/benchmark_template.yml - secrets: inherit - with: - publish: true - test-flags: "-timeout 50m" - runner-additional-tag: "benchmarks-large" \ No newline at end of file From e4d7528b26a64e392b799325535fb7dcd267a9a5 Mon Sep 17 00:00:00 2001 From: Morgan Date: Thu, 3 Oct 2024 11:30:16 +0200 Subject: [PATCH 06/20] ci: change alert-threshold to 120% (#2880) Apologies for the whitespace changes; if you disable them, you'll see it's a one-line change. See [alert threshold](https://github.com/benchmark-action/github-action-benchmark?tab=readme-ov-file#alert-threshold-optional) on the documentation of the action.
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- .github/workflows/benchmark-master-push.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/benchmark-master-push.yml b/.github/workflows/benchmark-master-push.yml index 7067395bc59..49acab52076 100644 --- a/.github/workflows/benchmark-master-push.yml +++ b/.github/workflows/benchmark-master-push.yml @@ -21,11 +21,11 @@ jobs: if: ${{ github.repository == 'gnolang/gno' }} runs-on: [self-hosted, Linux, X64, benchmarks] steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 1 - + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + - uses: actions/setup-go@v5 with: go-version: "1.22.x" @@ -40,7 +40,7 @@ jobs: with: path: ./cache key: ${{ runner.os }}-benchmark - + - name: Store benchmark results into `gh-benchmarks` branch uses: benchmark-action/github-action-benchmark@v1 # see https://github.com/benchmark-action/github-action-benchmark?tab=readme-ov-file#action-inputs @@ -52,7 +52,7 @@ jobs: external-data-json-path: ./cache/benchmark-data.json max-items-in-chart: 100 # Show alert with commit comment on detecting possible performance regression - alert-threshold: '100%' + alert-threshold: '120%' fail-on-alert: true comment-on-alert: true alert-comment-cc-users: '@ajnavarro,@thehowl,@zivkovicmilos' From 14acb901fef22e78b1eb3192dc34b6157fc3daf9 Mon Sep 17 00:00:00 2001 From: Morgan Date: Thu, 3 Oct 2024 11:48:56 +0200 Subject: [PATCH 07/20] ci(hotfix): yaml whitespace (#2892)
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- .github/workflows/benchmark-master-push.yml | 72 ++++++++++----------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/.github/workflows/benchmark-master-push.yml b/.github/workflows/benchmark-master-push.yml index 49acab52076..fe8d1613b0d 100644 --- a/.github/workflows/benchmark-master-push.yml +++ b/.github/workflows/benchmark-master-push.yml @@ -5,8 +5,6 @@ on: branches: - master - # publish: true - permissions: # deployments permission to deploy GitHub pages website deployments: write @@ -26,41 +24,41 @@ jobs: with: fetch-depth: 1 - - uses: actions/setup-go@v5 - with: - go-version: "1.22.x" + - uses: actions/setup-go@v5 + with: + go-version: "1.22.x" - - name: Run benchmark - run: | - go test -benchmem -bench=. ./... -run=^$ \ - -cpu 1,2 -timeout 50m | tee benchmarks.txt + - name: Run benchmark + run: | + go test -benchmem -bench=. ./... -run=^$ \ + -cpu 1,2 -timeout 50m | tee benchmarks.txt - - name: Download previous benchmark data - uses: actions/cache@v4 - with: - path: ./cache - key: ${{ runner.os }}-benchmark + - name: Download previous benchmark data + uses: actions/cache@v4 + with: + path: ./cache + key: ${{ runner.os }}-benchmark - - name: Store benchmark results into `gh-benchmarks` branch - uses: benchmark-action/github-action-benchmark@v1 - # see https://github.com/benchmark-action/github-action-benchmark?tab=readme-ov-file#action-inputs - with: - name: Go Benchmarks - tool: 'go' - output-file-path: benchmarks.txt - # Where the previous data file is stored - external-data-json-path: ./cache/benchmark-data.json - max-items-in-chart: 100 - # Show alert with commit comment on detecting possible performance regression - alert-threshold: '120%' - fail-on-alert: true - comment-on-alert: true - alert-comment-cc-users: '@ajnavarro,@thehowl,@zivkovicmilos' - # Enable Job Summary for PRs - summary-always: true - github-token: ${{ secrets.GITHUB_TOKEN }} - # NOTE you need to use a separate GITHUB PAT token that has a write access to the specified repository. - # gh-repository: 'github.com/gnolang/benchmarks' # on gh-pages branch - gh-pages-branch: gh-benchmarks - benchmark-data-dir-path: . - auto-push: true + - name: Store benchmark results into `gh-benchmarks` branch + uses: benchmark-action/github-action-benchmark@v1 + # see https://github.com/benchmark-action/github-action-benchmark?tab=readme-ov-file#action-inputs + with: + name: Go Benchmarks + tool: "go" + output-file-path: benchmarks.txt + # Where the previous data file is stored + external-data-json-path: ./cache/benchmark-data.json + max-items-in-chart: 100 + # Show alert with commit comment on detecting possible performance regression + alert-threshold: "120%" + fail-on-alert: true + comment-on-alert: true + alert-comment-cc-users: "@ajnavarro,@thehowl,@zivkovicmilos" + # Enable Job Summary for PRs + summary-always: true + github-token: ${{ secrets.GITHUB_TOKEN }} + # NOTE you need to use a separate GITHUB PAT token that has a write access to the specified repository. + # gh-repository: 'github.com/gnolang/benchmarks' # on gh-pages branch + gh-pages-branch: gh-benchmarks + benchmark-data-dir-path: . + auto-push: true From 4b3b419cf81cc04021f1990da774e9c4605e01f0 Mon Sep 17 00:00:00 2001 From: grepsuzette <350354+grepsuzette@users.noreply.github.com> Date: Thu, 3 Oct 2024 20:11:01 +0800 Subject: [PATCH 08/20] chore(docs): fix broken link in tm2/pkg/amino/README.md (#2322) This is a broken link: https://github.com/gnolang/gno/blob/3f5a6ad90600fef16a04675d79e4ef8f0e19bf4d/tm2/pkg/amino/README.md?plain=1#L46-L50 PR replaces it with the updated link.
Details

File was move there: https://github.com/tendermint/tendermint/blob/main/spec/blockchain/encoding.md which says it's been moved there: https://github.com/tendermint/tendermint/blob/main/spec/core/encoding.md

--- For the future, since we have a version in the monorepo and gnolang/tendermint2, where is the best place to post PR? Because gnolang/tendermint2 of course has the same issue (https://github.com/gnolang/tendermint2/blob/master/pkgs/amino/README.md) Co-authored-by: grepsuzette --- tm2/pkg/amino/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tm2/pkg/amino/README.md b/tm2/pkg/amino/README.md index 1a69cc7426c..b0e0d8baa30 100644 --- a/tm2/pkg/amino/README.md +++ b/tm2/pkg/amino/README.md @@ -45,8 +45,7 @@ This is experimental and subject to change. ## Amino in the Wild -* Amino:binary spec in [Tendermint]( -https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md) +* Amino:binary spec in [Tendermint](https://github.com/tendermint/tendermint/blob/main/spec/core/encoding.md) # Amino Spec From 8a62a28f672d3311163bee75f5e8f10ba3d4d52b Mon Sep 17 00:00:00 2001 From: Sergio Maria Matone Date: Thu, 3 Oct 2024 15:17:04 +0200 Subject: [PATCH 09/20] ci: remove conflicting option to push benchmark on github pages (#2895) Just a small fix to allow publication of benchmark on the repository --- .github/workflows/benchmark-master-push.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/benchmark-master-push.yml b/.github/workflows/benchmark-master-push.yml index fe8d1613b0d..ba8c11b2007 100644 --- a/.github/workflows/benchmark-master-push.yml +++ b/.github/workflows/benchmark-master-push.yml @@ -46,8 +46,6 @@ jobs: name: Go Benchmarks tool: "go" output-file-path: benchmarks.txt - # Where the previous data file is stored - external-data-json-path: ./cache/benchmark-data.json max-items-in-chart: 100 # Show alert with commit comment on detecting possible performance regression alert-threshold: "120%" From d3049ae4227493993f3cd01594a84e9449add591 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Fri, 4 Oct 2024 22:45:04 +0200 Subject: [PATCH 10/20] docs: test3 -> portal loop (#2897) Update links from test3 to portal loop where appropriate. --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> --- README.md | 6 +++--- docs/concepts/gnovm.md | 2 +- examples/gno.land/r/demo/boards/README.md | 12 ++++++------ examples/gno.land/r/gnoland/home/home.gno | 4 +--- examples/gno.land/r/gnoland/home/home_filetest.gno | 4 +--- examples/gno.land/r/gnoland/pages/page_testnets.gno | 5 +---- gno.land/cmd/gnoweb/README.md | 2 +- gnovm/README.md | 2 +- gnovm/cmd/gno/mod.go | 2 +- gnovm/pkg/gnomod/file_test.go | 6 +++--- 10 files changed, 19 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 19ac161e790..eeffc9adefc 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ If you haven't already, take a moment to check out our [website](https://gno.lan > The website is a deployment of our [gnoweb](./gno.land/cmd/gnoweb) frontend; you > can use it to check out -> [some](https://test3.gno.land/r/demo/boards) -> [example](https://test3.gno.land/r/gnoland/blog) -> [contracts](https://test3.gno.land/r/demo/users). +> [some](https://gno.land/r/demo/boards) +> [example](https://gno.land/r/gnoland/blog) +> [contracts](https://gno.land/r/demo/users). > > Use the `[source]` button in the header to inspect the program's source; use > the `[help]` button to view how you can use [`gnokey`](./gno.land/cmd/gnokey) diff --git a/docs/concepts/gnovm.md b/docs/concepts/gnovm.md index 16e43cb0d42..13e55defb71 100644 --- a/docs/concepts/gnovm.md +++ b/docs/concepts/gnovm.md @@ -8,7 +8,7 @@ GnoVM is a virtual machine that interprets Gno, a custom version of Go optimized It works with Tendermint2 and enables smarter, more modular, and transparent appchains with embedded smart-contracts. It can be adapted for use in TendermintCore, forks, and non-Cosmos blockchains. -Read the ["Intro to Gnoland"](https://test3.gno.land/r/gnoland/blog:p/intro) blogpost. +Read the ["Intro to Gnoland"](https://gno.land/r/gnoland/blog:p/intro) blogpost. This folder focuses on the VM, language, stdlibs, tests, and tools, independent of the blockchain. This enables non-web3 developers to contribute without requiring an understanding of the broader context. diff --git a/examples/gno.land/r/demo/boards/README.md b/examples/gno.land/r/demo/boards/README.md index 628bc9aa349..3aa765df25a 100644 --- a/examples/gno.land/r/demo/boards/README.md +++ b/examples/gno.land/r/demo/boards/README.md @@ -8,8 +8,8 @@ name ["gno.land/r/demo/boards"](https://gno.land/r/demo/boards/) ## Build `gnokey`, create your account, and interact with Gno. NOTE: Where you see `-remote localhost:26657` here, that flag can be replaced -with `-remote test3.gno.land:26657` if you have $GNOT on the testnet. -(To use the testnet, also replace `-chainid dev` with `-chainid test3` .) +with `-remote gno.land:26657` if you have $GNOT on the testnet. +(To use the testnet, also replace `-chainid dev` with `-chainid portal-loop` .) ### Build `gnokey` (and other tools). @@ -85,7 +85,7 @@ The `USERNAME` for posting can different than your `KEYNAME`. It is internally l ./build/gnokey maketx call -pkgpath "gno.land/r/demo/users" -func "Register" -args "" -args "USERNAME" -args "Profile description" -gas-fee "10000000ugnot" -gas-wanted "2000000" -send "200000000ugnot" -broadcast -chainid dev -remote 127.0.0.1:26657 KEYNAME ``` -Interactive documentation: https://test3.gno.land/r/demo/users?help&__func=Register +Interactive documentation: https://gno.land/r/demo/users?help&__func=Register ### Create a board with a smart contract call. @@ -93,7 +93,7 @@ Interactive documentation: https://test3.gno.land/r/demo/users?help&__func=Regis ./build/gnokey maketx call -pkgpath "gno.land/r/demo/boards" -func "CreateBoard" -args "BOARDNAME" -gas-fee "1000000ugnot" -gas-wanted "10000000" -broadcast -chainid dev -remote localhost:26657 KEYNAME ``` -Interactive documentation: https://test3.gno.land/r/demo/boards?help&__func=CreateBoard +Interactive documentation: https://gno.land/r/demo/boards?help&__func=CreateBoard Next, query for the permanent board ID by querying (you need this to create a new post): @@ -109,7 +109,7 @@ NOTE: If a board was created successfully, your SEQUENCE_NUMBER would have incre ./build/gnokey maketx call -pkgpath "gno.land/r/demo/boards" -func "CreateThread" -args BOARD_ID -args "Hello gno.land" -args "Text of the post" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid dev -remote localhost:26657 KEYNAME ``` -Interactive documentation: https://test3.gno.land/r/demo/boards?help&__func=CreateThread +Interactive documentation: https://gno.land/r/demo/boards?help&__func=CreateThread ### Create a comment to a post. @@ -117,7 +117,7 @@ Interactive documentation: https://test3.gno.land/r/demo/boards?help&__func=Crea ./build/gnokey maketx call -pkgpath "gno.land/r/demo/boards" -func "CreateReply" -args BOARD_ID -args "1" -args "1" -args "Nice to meet you too." -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid dev -remote localhost:26657 KEYNAME ``` -Interactive documentation: https://test3.gno.land/r/demo/boards?help&__func=CreateReply +Interactive documentation: https://gno.land/r/demo/boards?help&__func=CreateReply ```bash ./build/gnokey query "vm/qrender" -data "gno.land/r/demo/boards:BOARDNAME/1" -remote localhost:26657 diff --git a/examples/gno.land/r/gnoland/home/home.gno b/examples/gno.land/r/gnoland/home/home.gno index 921492d81b4..93f9a68f39a 100644 --- a/examples/gno.land/r/gnoland/home/home.gno +++ b/examples/gno.land/r/gnoland/home/home.gno @@ -269,9 +269,7 @@ func discoverLinks() ui.Element { - [Discover demo packages](https://github.com/gnolang/gno/tree/master/examples) - [Gnoscan](https://gnoscan.io) - [Portal Loop](https://docs.gno.land/concepts/portal-loop) -- [Testnet 4](https://test4.gno.land/) (Launched July 2024!) -- [Testnet 3](https://test3.gno.land/) (archive) -- [Testnet 2](https://test2.gno.land/) (archive) +- [Testnet 4](https://test4.gno.land/) - Testnet Faucet Hub (soon) diff --git a/examples/gno.land/r/gnoland/home/home_filetest.gno b/examples/gno.land/r/gnoland/home/home_filetest.gno index b70b22c80af..2260dc3a409 100644 --- a/examples/gno.land/r/gnoland/home/home_filetest.gno +++ b/examples/gno.land/r/gnoland/home/home_filetest.gno @@ -56,9 +56,7 @@ func main() { // - [Discover demo packages](https://github.com/gnolang/gno/tree/master/examples) // - [Gnoscan](https://gnoscan.io) // - [Portal Loop](https://docs.gno.land/concepts/portal-loop) -// - [Testnet 4](https://test4.gno.land/) (Launched July 2024!) -// - [Testnet 3](https://test3.gno.land/) (archive) -// - [Testnet 2](https://test2.gno.land/) (archive) +// - [Testnet 4](https://test4.gno.land/) // - Testnet Faucet Hub (soon) // // diff --git a/examples/gno.land/r/gnoland/pages/page_testnets.gno b/examples/gno.land/r/gnoland/pages/page_testnets.gno index 05f29a8e0f4..900ee2e3bf7 100644 --- a/examples/gno.land/r/gnoland/pages/page_testnets.gno +++ b/examples/gno.land/r/gnoland/pages/page_testnets.gno @@ -6,10 +6,7 @@ func init() { body := ` - [Portal Loop](https://docs.gno.land/concepts/portal-loop) - a rolling testnet - [staging.gno.land](https://staging.gno.land) - wiped every commit to monorepo master -- test4.gno.land (upcoming) -- _[test3.gno.land](https://test3.gno.land) (latest)_ -- _[test2.gno.land](https://test2.gno.land) (archive)_ -- _[test1.gno.land](https://test1.gno.land) (archive)_ +- _[test4.gno.land](https://test4.gno.land) (latest)_ For a list of RPC endpoints, see the [reference documentation](https://docs.gno.land/reference/rpc-endpoints). diff --git a/gno.land/cmd/gnoweb/README.md b/gno.land/cmd/gnoweb/README.md index 941d5e4f67e..6379d3f6c43 100644 --- a/gno.land/cmd/gnoweb/README.md +++ b/gno.land/cmd/gnoweb/README.md @@ -2,7 +2,7 @@ The gno.land web interface. -Live demo: https://test3.gno.land/ +Live demo: https://gno.land/ ## Install `gnoweb` diff --git a/gnovm/README.md b/gnovm/README.md index 91419746cfa..2fe4345c367 100644 --- a/gnovm/README.md +++ b/gnovm/README.md @@ -4,7 +4,7 @@ GnoVM is a virtual machine that interprets Gnolang, a custom version of Golang o It works with Tendermint2 and enables smarter, more modular, and transparent appchains with embedded smart-contracts. It can be used in TendermintCore, forks, and non-Cosmos blockchains. -Read the ["Intro to Gnoland"](https://test3.gno.land/r/gnoland/blog:p/intro) blogpost. +Read the ["Intro to Gnoland"](https://gno.land/r/gnoland/blog:p/intro) blogpost. This folder focuses on the VM, language, stdlibs, tests, and tools, independent of the blockchain. This enables non-web3 developers to contribute without requiring an understanding of the broader context. diff --git a/gnovm/cmd/gno/mod.go b/gnovm/cmd/gno/mod.go index fec1b0ab2c1..03b2bb348a8 100644 --- a/gnovm/cmd/gno/mod.go +++ b/gnovm/cmd/gno/mod.go @@ -131,7 +131,7 @@ func (c *modDownloadCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( &c.remote, "remote", - "test3.gno.land:26657", + "gno.land:26657", "remote for fetching gno modules", ) diff --git a/gnovm/pkg/gnomod/file_test.go b/gnovm/pkg/gnomod/file_test.go index 7abfe16f340..a64c2794a65 100644 --- a/gnovm/pkg/gnomod/file_test.go +++ b/gnovm/pkg/gnomod/file_test.go @@ -14,7 +14,7 @@ import ( "golang.org/x/mod/module" ) -const testRemote string = "test3.gno.land:26657" +const testRemote string = "gno.land:26657" // XXX(race condition): test with a local node so that this test is consistent with git and not with a deploy func TestFetchDeps(t *testing.T) { for _, tc := range []struct { @@ -68,7 +68,7 @@ func TestFetchDeps(t *testing.T) { "cached gno.land/p/demo/avl", }, }, { - desc: "fetch_gno.land/p/demo/blog", + desc: "fetch_gno.land/p/demo/blog6", modFile: File{ Module: &modfile.Module{ Mod: module.Version{ @@ -84,7 +84,7 @@ func TestFetchDeps(t *testing.T) { }, }, }, - requirements: []string{"avl", "blog", "ufmt"}, + requirements: []string{"avl", "blog", "ufmt", "mux"}, stdOutContains: []string{ "fetching gno.land/p/demo/blog", "fetching gno.land/p/demo/avl // indirect", From 628f965a1983697cf9b197a053e31878409924f0 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Sat, 5 Oct 2024 22:47:58 +0200 Subject: [PATCH 11/20] chore(ci): do not mark master as failing due to benchmark (#2913) --- .github/workflows/benchmark-master-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmark-master-push.yml b/.github/workflows/benchmark-master-push.yml index ba8c11b2007..a219a49305a 100644 --- a/.github/workflows/benchmark-master-push.yml +++ b/.github/workflows/benchmark-master-push.yml @@ -49,7 +49,7 @@ jobs: max-items-in-chart: 100 # Show alert with commit comment on detecting possible performance regression alert-threshold: "120%" - fail-on-alert: true + fail-on-alert: false comment-on-alert: true alert-comment-cc-users: "@ajnavarro,@thehowl,@zivkovicmilos" # Enable Job Summary for PRs From e5840e2aa2ed0e0fdf2d4c43c1d3d277f0cbd47b Mon Sep 17 00:00:00 2001 From: Leon Hudak <33522493+leohhhn@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:35:31 +0200 Subject: [PATCH 12/20] fix(gnoweb): fix broken link (#2926) ## Description Fixes a broken link. Closes: #2925
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests - [x] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- gno.land/pkg/gnoweb/views/realm_help.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gno.land/pkg/gnoweb/views/realm_help.html b/gno.land/pkg/gnoweb/views/realm_help.html index b9c8e119e7a..0a93f786c0d 100644 --- a/gno.land/pkg/gnoweb/views/realm_help.html +++ b/gno.land/pkg/gnoweb/views/realm_help.html @@ -17,7 +17,7 @@
These are the realm's exposed functions ("public smart contracts").

- My address: (see `gnokey list`)
+ My address: (see `gnokey list`)


{{ template "func_specs" . }} From 2f605805efee5b48f26fe8cef2ac69b936845ea3 Mon Sep 17 00:00:00 2001 From: Michelle <117160070+michelleellen@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:09:38 +0200 Subject: [PATCH 13/20] chore(gnoweb): update page_contribute.gno (#2922) Added the gno.land grants GH repository link to the page --- examples/gno.land/r/gnoland/pages/page_contribute.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/gnoland/pages/page_contribute.gno b/examples/gno.land/r/gnoland/pages/page_contribute.gno index 3cdef10d9dc..a4bdfabb6ef 100644 --- a/examples/gno.land/r/gnoland/pages/page_contribute.gno +++ b/examples/gno.land/r/gnoland/pages/page_contribute.gno @@ -80,7 +80,7 @@ _[3XL]_ \* | $ 32000 The gno.land grants program is to encourage and support the growth of the gno.land contributor community, and build out the usability of the platform and smart contract library. The program provides financial resources to contributors to explore the Gno tech stack, and build dApps, tooling, infrastructure, products, and smart contract libraries in gno.land. - +For more details on gno.land grants, suggested topics, and how to apply, visit our grants [repository](https://github.com/gnolang/grants). ## Join Game of Realms From 912a5dbf5c1d7118472a4f46b26bfcd7f4072856 Mon Sep 17 00:00:00 2001 From: Malek Lahbib <111009238+MalekLahbib@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:20:04 +0200 Subject: [PATCH 14/20] docs(/p/demo/json): update json package README.md (#2921) in the three examples provided in the README.md file, there's a useless import of "fmt" package.
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- examples/gno.land/p/demo/json/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/gno.land/p/demo/json/README.md b/examples/gno.land/p/demo/json/README.md index 86bc9928194..d983333d246 100644 --- a/examples/gno.land/p/demo/json/README.md +++ b/examples/gno.land/p/demo/json/README.md @@ -75,7 +75,6 @@ The converted `Node` type allows you to modify the JSON data or search and extra package main import ( - "fmt" "gno.land/p/demo/json" "gno.land/p/demo/ufmt" ) @@ -100,7 +99,6 @@ Encoding (or Marshaling) is the functionality that converts JSON data represente package main import ( - "fmt" "gno.land/p/demo/json" "gno.land/p/demo/ufmt" ) @@ -133,7 +131,6 @@ Here is an example of finding data with a specific key. For more examples, pleas package main import ( - "fmt" "gno.land/p/demo/json" "gno.land/p/demo/ufmt" ) From d63918fe42e578bae037fa7a4987ed445804fa89 Mon Sep 17 00:00:00 2001 From: ltzmaxwell Date: Tue, 15 Oct 2024 20:59:39 +0800 Subject: [PATCH 15/20] fix(gnovm): correct type for shift expression (#1775) [shift operator where first operand is an untyped bigint always results in a bigint](https://github.com/gnolang/gno/issues/1462) is not resolved by #1426, it's fixed by this one. ================================================================= 1. This is a fix to gnolang/gno/issues/1462; 3. **NOTE**: This PR should be reviewed following the potential merger of #1426, from which it is both decoupled and dependent. #1426 serves as base branch of this one. 4. **NOTE**: Currently, this PR displays all code including that from #1426, because it is being compared to the master branch instead of differing against #1426 directly. --------- Co-authored-by: Morgan Co-authored-by: Marc Vertes --- gnovm/pkg/gnolang/eval_test.go | 4 +- gnovm/pkg/gnolang/nodes.go | 1 + gnovm/pkg/gnolang/op_binary.go | 2 + gnovm/pkg/gnolang/op_call.go | 5 + gnovm/pkg/gnolang/preprocess.go | 194 ++++++++++++++---- gnovm/pkg/gnolang/type_check.go | 121 ++++++++--- gnovm/pkg/gnolang/values.go | 106 ++++------ gnovm/pkg/gnolang/values_conversions.go | 1 + gnovm/tests/files/types/cmp_slice.gno | 14 ++ .../files/types/explicit_conversion_0.gno | 13 ++ .../files/types/explicit_conversion_1.gno | 13 ++ .../files/types/explicit_conversion_2.gno | 14 ++ .../files/types/explicit_conversion_4.gno | 9 + .../files/types/explicit_conversion_5.gno | 9 + gnovm/tests/files/types/shift_a11.gno | 2 +- gnovm/tests/files/types/shift_a2.gno | 1 - gnovm/tests/files/types/shift_a4.gno | 1 - gnovm/tests/files/types/shift_a5.gno | 6 +- gnovm/tests/files/types/shift_a7.gno | 2 +- gnovm/tests/files/types/shift_b0.gno | 14 ++ gnovm/tests/files/types/shift_b1.gno | 14 ++ gnovm/tests/files/types/shift_b10.gno | 14 ++ gnovm/tests/files/types/shift_b11.gno | 14 ++ gnovm/tests/files/types/shift_b2.gno | 14 ++ gnovm/tests/files/types/shift_b3.gno | 32 +++ gnovm/tests/files/types/shift_b4.gno | 32 +++ gnovm/tests/files/types/shift_b5.gno | 31 +++ gnovm/tests/files/types/shift_b6.gno | 30 +++ gnovm/tests/files/types/shift_b6a.gno | 31 +++ gnovm/tests/files/types/shift_b7.gno | 13 ++ gnovm/tests/files/types/shift_b8.gno | 14 ++ gnovm/tests/files/types/shift_b9.gno | 14 ++ gnovm/tests/files/types/shift_c10.gno | 12 ++ gnovm/tests/files/types/shift_c3.gno | 14 ++ gnovm/tests/files/types/shift_c4.gno | 14 ++ gnovm/tests/files/types/shift_c5.gno | 10 + gnovm/tests/files/types/shift_c6.gno | 14 ++ gnovm/tests/files/types/shift_c7.gno | 14 ++ gnovm/tests/files/types/shift_c8.gno | 14 ++ gnovm/tests/files/types/shift_c9.gno | 14 ++ gnovm/tests/files/types/shift_d11.gno | 21 ++ gnovm/tests/files/types/shift_d12.gno | 16 ++ gnovm/tests/files/types/shift_d13.gno | 17 ++ gnovm/tests/files/types/shift_d14.gno | 18 ++ gnovm/tests/files/types/shift_d15.gno | 10 + gnovm/tests/files/types/shift_d16.gno | 10 + gnovm/tests/files/types/shift_d21.gno | 10 + gnovm/tests/files/types/shift_d24.gno | 10 + gnovm/tests/files/types/shift_d25.gno | 10 + gnovm/tests/files/types/shift_d26.gno | 11 + gnovm/tests/files/types/shift_d27.gno | 11 + gnovm/tests/files/types/shift_d28.gno | 11 + gnovm/tests/files/types/shift_d29.gno | 14 ++ gnovm/tests/files/types/shift_d3.gno | 9 + gnovm/tests/files/types/shift_d30.gno | 14 ++ gnovm/tests/files/types/shift_d32.gno | 14 ++ gnovm/tests/files/types/shift_d32a.gno | 13 ++ gnovm/tests/files/types/shift_d33.gno | 14 ++ gnovm/tests/files/types/shift_d34.gno | 13 ++ gnovm/tests/files/types/shift_d35.gno | 14 ++ gnovm/tests/files/types/shift_d36.gno | 14 ++ gnovm/tests/files/types/shift_d37.gno | 9 + gnovm/tests/files/types/shift_d38.gno | 8 + gnovm/tests/files/types/shift_d39.gno | 16 ++ gnovm/tests/files/types/shift_d4.gno | 9 + gnovm/tests/files/types/shift_d40.gno | 10 + gnovm/tests/files/types/shift_d41.gno | 10 + gnovm/tests/files/types/shift_d42.gno | 14 ++ gnovm/tests/files/types/shift_d43.gno | 10 + gnovm/tests/files/types/shift_d44.gno | 10 + gnovm/tests/files/types/shift_d45.gno | 10 + gnovm/tests/files/types/shift_d46.gno | 10 + gnovm/tests/files/types/shift_d47.gno | 26 +++ gnovm/tests/files/types/shift_d48.gno | 23 +++ gnovm/tests/files/types/shift_d4a.gno | 9 + gnovm/tests/files/types/shift_d5.gno | 10 + gnovm/tests/files/types/shift_d50.gno | 13 ++ gnovm/tests/files/types/shift_d51.gno | 10 + gnovm/tests/files/types/shift_d52.gno | 10 + gnovm/tests/files/types/shift_d53.gno | 12 ++ gnovm/tests/files/types/shift_d54.gno | 14 ++ gnovm/tests/files/types/shift_d55.gno | 16 ++ gnovm/tests/files/types/shift_d56.gno | 16 ++ gnovm/tests/files/types/shift_d5a.gno | 10 + gnovm/tests/files/types/shift_d5b.gno | 10 + gnovm/tests/files/types/shift_d6.gno | 18 ++ gnovm/tests/files/types/shift_d9.gno | 9 + gnovm/tests/files/types/shift_e0.gno | 8 + gnovm/tests/files/types/shift_e1.gno | 8 + gnovm/tests/files/types/shift_e1a.gno | 8 + gnovm/tests/files/types/shift_e2.gno | 8 + gnovm/tests/files/types/shift_e3.gno | 9 + gnovm/tests/files/types/shift_e4.gno | 9 + gnovm/tests/files/types/shift_e5.gno | 9 + gnovm/tests/files/types/shift_e6.gno | 9 + gnovm/tests/files/types/shift_e7.gno | 9 + gnovm/tests/files/types/shift_e7a.gno | 9 + gnovm/tests/files/types/shift_e7b.gno | 8 + gnovm/tests/files/types/shift_e8.gno | 9 + gnovm/tests/files/types/shift_e9.gno | 11 + gnovm/tests/files/types/shift_e9a.gno | 11 + gnovm/tests/files/types/shift_f1a.gno | 12 ++ gnovm/tests/files/types/shift_f1b.gno | 12 ++ gnovm/tests/files/types/shift_f2.gno | 10 + gnovm/tests/files/types/shift_f2a.gno | 10 + gnovm/tests/files/types/shift_f2b.gno | 10 + gnovm/tests/files/types/shift_f2c.gno | 10 + gnovm/tests/files/types/shift_f2d.gno | 10 + gnovm/tests/files/types/shift_f2e.gno | 10 + gnovm/tests/files/types/shift_f3.gno | 10 + gnovm/tests/files/types/shift_f3a.gno | 10 + gnovm/tests/files/types/shift_f3b.gno | 10 + gnovm/tests/files/types/shift_f3c.gno | 10 + gnovm/tests/files/types/shift_f3d.gno | 10 + gnovm/tests/files/types/shift_f4.gno | 10 + gnovm/tests/files/types/shift_f5.gno | 10 + gnovm/tests/files/types/shift_g.gno | 18 ++ 117 files changed, 1640 insertions(+), 144 deletions(-) create mode 100644 gnovm/tests/files/types/cmp_slice.gno create mode 100644 gnovm/tests/files/types/explicit_conversion_0.gno create mode 100644 gnovm/tests/files/types/explicit_conversion_1.gno create mode 100644 gnovm/tests/files/types/explicit_conversion_2.gno create mode 100644 gnovm/tests/files/types/explicit_conversion_4.gno create mode 100644 gnovm/tests/files/types/explicit_conversion_5.gno create mode 100644 gnovm/tests/files/types/shift_b0.gno create mode 100644 gnovm/tests/files/types/shift_b1.gno create mode 100644 gnovm/tests/files/types/shift_b10.gno create mode 100644 gnovm/tests/files/types/shift_b11.gno create mode 100644 gnovm/tests/files/types/shift_b2.gno create mode 100644 gnovm/tests/files/types/shift_b3.gno create mode 100644 gnovm/tests/files/types/shift_b4.gno create mode 100644 gnovm/tests/files/types/shift_b5.gno create mode 100644 gnovm/tests/files/types/shift_b6.gno create mode 100644 gnovm/tests/files/types/shift_b6a.gno create mode 100644 gnovm/tests/files/types/shift_b7.gno create mode 100644 gnovm/tests/files/types/shift_b8.gno create mode 100644 gnovm/tests/files/types/shift_b9.gno create mode 100644 gnovm/tests/files/types/shift_c10.gno create mode 100644 gnovm/tests/files/types/shift_c3.gno create mode 100644 gnovm/tests/files/types/shift_c4.gno create mode 100644 gnovm/tests/files/types/shift_c5.gno create mode 100644 gnovm/tests/files/types/shift_c6.gno create mode 100644 gnovm/tests/files/types/shift_c7.gno create mode 100644 gnovm/tests/files/types/shift_c8.gno create mode 100644 gnovm/tests/files/types/shift_c9.gno create mode 100644 gnovm/tests/files/types/shift_d11.gno create mode 100644 gnovm/tests/files/types/shift_d12.gno create mode 100644 gnovm/tests/files/types/shift_d13.gno create mode 100644 gnovm/tests/files/types/shift_d14.gno create mode 100644 gnovm/tests/files/types/shift_d15.gno create mode 100644 gnovm/tests/files/types/shift_d16.gno create mode 100644 gnovm/tests/files/types/shift_d21.gno create mode 100644 gnovm/tests/files/types/shift_d24.gno create mode 100644 gnovm/tests/files/types/shift_d25.gno create mode 100644 gnovm/tests/files/types/shift_d26.gno create mode 100644 gnovm/tests/files/types/shift_d27.gno create mode 100644 gnovm/tests/files/types/shift_d28.gno create mode 100644 gnovm/tests/files/types/shift_d29.gno create mode 100644 gnovm/tests/files/types/shift_d3.gno create mode 100644 gnovm/tests/files/types/shift_d30.gno create mode 100644 gnovm/tests/files/types/shift_d32.gno create mode 100644 gnovm/tests/files/types/shift_d32a.gno create mode 100644 gnovm/tests/files/types/shift_d33.gno create mode 100644 gnovm/tests/files/types/shift_d34.gno create mode 100644 gnovm/tests/files/types/shift_d35.gno create mode 100644 gnovm/tests/files/types/shift_d36.gno create mode 100644 gnovm/tests/files/types/shift_d37.gno create mode 100644 gnovm/tests/files/types/shift_d38.gno create mode 100644 gnovm/tests/files/types/shift_d39.gno create mode 100644 gnovm/tests/files/types/shift_d4.gno create mode 100644 gnovm/tests/files/types/shift_d40.gno create mode 100644 gnovm/tests/files/types/shift_d41.gno create mode 100644 gnovm/tests/files/types/shift_d42.gno create mode 100644 gnovm/tests/files/types/shift_d43.gno create mode 100644 gnovm/tests/files/types/shift_d44.gno create mode 100644 gnovm/tests/files/types/shift_d45.gno create mode 100644 gnovm/tests/files/types/shift_d46.gno create mode 100644 gnovm/tests/files/types/shift_d47.gno create mode 100644 gnovm/tests/files/types/shift_d48.gno create mode 100644 gnovm/tests/files/types/shift_d4a.gno create mode 100644 gnovm/tests/files/types/shift_d5.gno create mode 100644 gnovm/tests/files/types/shift_d50.gno create mode 100644 gnovm/tests/files/types/shift_d51.gno create mode 100644 gnovm/tests/files/types/shift_d52.gno create mode 100644 gnovm/tests/files/types/shift_d53.gno create mode 100644 gnovm/tests/files/types/shift_d54.gno create mode 100644 gnovm/tests/files/types/shift_d55.gno create mode 100644 gnovm/tests/files/types/shift_d56.gno create mode 100644 gnovm/tests/files/types/shift_d5a.gno create mode 100644 gnovm/tests/files/types/shift_d5b.gno create mode 100644 gnovm/tests/files/types/shift_d6.gno create mode 100644 gnovm/tests/files/types/shift_d9.gno create mode 100644 gnovm/tests/files/types/shift_e0.gno create mode 100644 gnovm/tests/files/types/shift_e1.gno create mode 100644 gnovm/tests/files/types/shift_e1a.gno create mode 100644 gnovm/tests/files/types/shift_e2.gno create mode 100644 gnovm/tests/files/types/shift_e3.gno create mode 100644 gnovm/tests/files/types/shift_e4.gno create mode 100644 gnovm/tests/files/types/shift_e5.gno create mode 100644 gnovm/tests/files/types/shift_e6.gno create mode 100644 gnovm/tests/files/types/shift_e7.gno create mode 100644 gnovm/tests/files/types/shift_e7a.gno create mode 100644 gnovm/tests/files/types/shift_e7b.gno create mode 100644 gnovm/tests/files/types/shift_e8.gno create mode 100644 gnovm/tests/files/types/shift_e9.gno create mode 100644 gnovm/tests/files/types/shift_e9a.gno create mode 100644 gnovm/tests/files/types/shift_f1a.gno create mode 100644 gnovm/tests/files/types/shift_f1b.gno create mode 100644 gnovm/tests/files/types/shift_f2.gno create mode 100644 gnovm/tests/files/types/shift_f2a.gno create mode 100644 gnovm/tests/files/types/shift_f2b.gno create mode 100644 gnovm/tests/files/types/shift_f2c.gno create mode 100644 gnovm/tests/files/types/shift_f2d.gno create mode 100644 gnovm/tests/files/types/shift_f2e.gno create mode 100644 gnovm/tests/files/types/shift_f3.gno create mode 100644 gnovm/tests/files/types/shift_f3a.gno create mode 100644 gnovm/tests/files/types/shift_f3b.gno create mode 100644 gnovm/tests/files/types/shift_f3c.gno create mode 100644 gnovm/tests/files/types/shift_f3d.gno create mode 100644 gnovm/tests/files/types/shift_f4.gno create mode 100644 gnovm/tests/files/types/shift_f5.gno create mode 100644 gnovm/tests/files/types/shift_g.gno diff --git a/gnovm/pkg/gnolang/eval_test.go b/gnovm/pkg/gnolang/eval_test.go index 9acf4cc89f0..9b83d673767 100644 --- a/gnovm/pkg/gnolang/eval_test.go +++ b/gnovm/pkg/gnolang/eval_test.go @@ -40,8 +40,8 @@ func TestEvalFiles(t *testing.T) { if wantStacktrace != "" && !strings.Contains(stacktrace, wantStacktrace) { t.Fatalf("unexpected stacktrace\nWant: %s\n Got: %s", wantStacktrace, stacktrace) } - if wantOut != "" && out != wantOut { - t.Fatalf("unexpected output\nWant: %s\n Got: %s", wantOut, out) + if wantOut != "" && strings.TrimSpace(out) != strings.TrimSpace(wantOut) { + t.Fatalf("unexpected output\nWant: \"%s\"\n Got: \"%s\"", wantOut, out) } }) diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index b18ed157ca6..8927eafcfb2 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -2119,6 +2119,7 @@ const ( ATTR_IOTA GnoAttribute = "ATTR_IOTA" ATTR_LOCATIONED GnoAttribute = "ATTR_LOCATIONED" ATTR_INJECTED GnoAttribute = "ATTR_INJECTED" + ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS" ) var rePkgName = regexp.MustCompile(`^[a-z][a-z0-9_]+$`) diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index db3c1e5695c..24123d285ad 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -1097,6 +1097,7 @@ func xorAssign(lv, rv *TypedValue) { // for doOpShl and doOpShlAssign. func shlAssign(lv, rv *TypedValue) { + rv.AssertNonNegative("runtime error: negative shift amount") // set the result in lv. // NOTE: baseOf(rv.T) is always UintType. switch baseOf(lv.T) { @@ -1136,6 +1137,7 @@ func shlAssign(lv, rv *TypedValue) { // for doOpShr and doOpShrAssign. func shrAssign(lv, rv *TypedValue) { + rv.AssertNonNegative("runtime error: negative shift amount") // set the result in lv. // NOTE: baseOf(rv.T) is always UintType. switch baseOf(lv.T) { diff --git a/gnovm/pkg/gnolang/op_call.go b/gnovm/pkg/gnolang/op_call.go index 15531ec610d..510c308a86a 100644 --- a/gnovm/pkg/gnolang/op_call.go +++ b/gnovm/pkg/gnolang/op_call.go @@ -27,6 +27,11 @@ func (m *Machine) doOpPrecall() { case TypeValue: // Do not pop type yet. // No need for frames. + xv := m.PeekValue(1) + if cx.GetAttribute(ATTR_SHIFT_RHS) == true { + xv.AssertNonNegative("runtime error: negative shift amount") + } + m.PushOp(OpConvert) if debug { if len(cx.Args) != 1 { diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 9168fc6f7c1..df1f7bab498 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -1025,7 +1025,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { isShift := n.Op == SHL || n.Op == SHR if isShift { // check LHS type compatibility - n.checkShiftLhs(lt) + n.assertShiftExprCompatible1(store, last, lt, rt) // checkOrConvert RHS if baseOf(rt) != UintType { // convert n.Right to (gno) uint type, @@ -1036,6 +1036,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { Op: n.Op, Right: rn, } + n2.Right.SetAttribute(ATTR_SHIFT_RHS, true) resn := Preprocess(store, last, n2) return resn, TRANS_CONTINUE } @@ -1097,12 +1098,34 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // NOTE: binary operations are always computed in // gno, never with reflect. } else { - // convert n.Left to right type. - checkOrConvertType(store, last, &n.Left, rt, false) + // right is untyped const, left is not const, typed/untyped + checkUntypedShiftExpr := func(x Expr) { + if bx, ok := x.(*BinaryExpr); ok { + slt := evalStaticTypeOf(store, last, bx.Left) + if bx.Op == SHL || bx.Op == SHR { + srt := evalStaticTypeOf(store, last, bx.Right) + bx.assertShiftExprCompatible1(store, last, slt, srt) + } + } + } + + if !isUntyped(rt) { // right is typed + checkOrConvertType(store, last, &n.Left, rt, false) + } else { + if shouldSwapOnSpecificity(lt, rt) { + checkUntypedShiftExpr(n.Right) + } else { + checkUntypedShiftExpr(n.Left) + } + } } } else if lcx.T == nil { // LHS is nil. // convert n.Left to typed-nil type. checkOrConvertType(store, last, &n.Left, rt, false) + } else { + if isUntyped(rt) { + checkOrConvertType(store, last, &n.Right, lt, false) + } } } else if ric { // right is const, left is not if isUntyped(rcx.T) { @@ -1134,12 +1157,33 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // NOTE: binary operations are always computed in // gno, never with reflect. } else { - // convert n.Right to left type. - checkOrConvertType(store, last, &n.Right, lt, false) + // right is untyped const, left is not const, typed or untyped + checkUntypedShiftExpr := func(x Expr) { + if bx, ok := x.(*BinaryExpr); ok { + if bx.Op == SHL || bx.Op == SHR { + srt := evalStaticTypeOf(store, last, bx.Right) + bx.assertShiftExprCompatible1(store, last, rt, srt) + } + } + } + // both untyped, e.g. 1<>=. convertType(store, last, &n.Rhs[0], UintType) } else if n.Op == ADD_ASSIGN || n.Op == SUB_ASSIGN || n.Op == MUL_ASSIGN || n.Op == QUO_ASSIGN || n.Op == REM_ASSIGN { @@ -2281,10 +2343,15 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { vt := evalStaticTypeOf(store, last, vx) sts[i] = vt } - } else { + } else { // T is nil, n not const // convert n.Value to default type. for i, vx := range n.Values { - convertIfConst(store, last, vx) + if cx, ok := vx.(*ConstExpr); ok { + convertConst(store, last, cx, nil) + // convertIfConst(store, last, vx) + } else { + checkOrConvertType(store, last, &vx, nil, false) + } vt := evalStaticTypeOf(store, last, vx) sts[i] = vt } @@ -2840,9 +2907,25 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative assertAssignableTo(cx.T, t, autoNative) } } else if bx, ok := (*x).(*BinaryExpr); ok && (bx.Op == SHL || bx.Op == SHR) { - // "push" expected type into shift binary's left operand. recursively. - checkOrConvertType(store, last, &bx.Left, t, autoNative) - } else if *x != nil { // XXX if x != nil && t != nil { + xt := evalStaticTypeOf(store, last, *x) + if debug { + debug.Printf("shift, xt: %v, Op: %v, t: %v \n", xt, bx.Op, t) + } + if isUntyped(xt) { + // check assignable first, see: types/shift_b6.gno + assertAssignableTo(xt, t, autoNative) + + if t == nil || t.Kind() == InterfaceKind { + t = defaultTypeOf(xt) + } + + bx.assertShiftExprCompatible2(t) + checkOrConvertType(store, last, &bx.Left, t, autoNative) + } else { + assertAssignableTo(xt, t, autoNative) + } + return + } else if *x != nil { xt := evalStaticTypeOf(store, last, *x) if t != nil { assertAssignableTo(xt, t, autoNative) @@ -2853,19 +2936,53 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative switch bx.Op { case ADD, SUB, MUL, QUO, REM, BAND, BOR, XOR, BAND_NOT, LAND, LOR: - // push t into bx.Left and bx.Right - checkOrConvertType(store, last, &bx.Left, t, autoNative) - checkOrConvertType(store, last, &bx.Right, t, autoNative) - return - case SHL, SHR: - // push t into bx.Left - checkOrConvertType(store, last, &bx.Left, t, autoNative) + lt := evalStaticTypeOf(store, last, bx.Left) + rt := evalStaticTypeOf(store, last, bx.Right) + if t != nil { + // push t into bx.Left and bx.Right + checkOrConvertType(store, last, &bx.Left, t, autoNative) + checkOrConvertType(store, last, &bx.Right, t, autoNative) + return + } else { + if shouldSwapOnSpecificity(lt, rt) { + // e.g. 1.0< string)) to type uint diff --git a/gnovm/tests/files/types/shift_a2.gno b/gnovm/tests/files/types/shift_a2.gno index 91072929306..726d5415b15 100644 --- a/gnovm/tests/files/types/shift_a2.gno +++ b/gnovm/tests/files/types/shift_a2.gno @@ -1,6 +1,5 @@ package main -// both typed(different) const func main() { println(1 << int(1)) println(1 >> int(1)) diff --git a/gnovm/tests/files/types/shift_a4.gno b/gnovm/tests/files/types/shift_a4.gno index 3561929b672..694d771f190 100644 --- a/gnovm/tests/files/types/shift_a4.gno +++ b/gnovm/tests/files/types/shift_a4.gno @@ -1,6 +1,5 @@ package main -// both typed(different) const func main() { println(1 << 1.0) println(1 >> 1.0) diff --git a/gnovm/tests/files/types/shift_a5.gno b/gnovm/tests/files/types/shift_a5.gno index a0b7652c6d1..5d2c4304732 100644 --- a/gnovm/tests/files/types/shift_a5.gno +++ b/gnovm/tests/files/types/shift_a5.gno @@ -1,10 +1,10 @@ package main -// TODO: support this? func main() { println(1.0 << 1) println(1.0 >> 1) } -// Error: -// main/files/types/shift_a5.gno:5:10: operator << not defined on: BigdecKind +// Output: +// 2 +// 0 diff --git a/gnovm/tests/files/types/shift_a7.gno b/gnovm/tests/files/types/shift_a7.gno index 62151c5cfc5..cd1b3d95ec7 100644 --- a/gnovm/tests/files/types/shift_a7.gno +++ b/gnovm/tests/files/types/shift_a7.gno @@ -6,4 +6,4 @@ func main() { } // Error: -// main/files/types/shift_a7.gno:3:1: cannot convert StringKind to UintKind +// main/files/types/shift_a7.gno:5:10: cannot convert (const ("a" string)) to type uint diff --git a/gnovm/tests/files/types/shift_b0.gno b/gnovm/tests/files/types/shift_b0.gno new file mode 100644 index 00000000000..fa9ee4ed2a0 --- /dev/null +++ b/gnovm/tests/files/types/shift_b0.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + x := 2 + r := uint64(1 << x) + println(r) + fmt.Printf("%T \n", r) +} + +// Output: +// 4 +// uint64 diff --git a/gnovm/tests/files/types/shift_b1.gno b/gnovm/tests/files/types/shift_b1.gno new file mode 100644 index 00000000000..403887269c0 --- /dev/null +++ b/gnovm/tests/files/types/shift_b1.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + x := 2 + r := uint64(1< bigint does not implement main.R (missing method foo) diff --git a/gnovm/tests/files/types/shift_b6a.gno b/gnovm/tests/files/types/shift_b6a.gno new file mode 100644 index 00000000000..26b7f1b2ea1 --- /dev/null +++ b/gnovm/tests/files/types/shift_b6a.gno @@ -0,0 +1,31 @@ +package main + +import "fmt" + +type R interface { + foo() +} + +type U64 uint64 + +func (u64 U64) foo() { + println("bar") +} + +func bar(r R) { + r.foo() +} + +func main() { + x := 2 + var r R + r = U64(1) << x + + r.foo() + + fmt.Printf("%T \n", r) // TODO: should output main.U64 rather than the underlying type +} + +// Output: +// bar +// uint64 diff --git a/gnovm/tests/files/types/shift_b7.gno b/gnovm/tests/files/types/shift_b7.gno new file mode 100644 index 00000000000..ccc6cd41b7f --- /dev/null +++ b/gnovm/tests/files/types/shift_b7.gno @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + x := 2 + r := float32(1<>2) +} + +// Output: +// 4 0 diff --git a/gnovm/tests/files/types/shift_c3.gno b/gnovm/tests/files/types/shift_c3.gno new file mode 100644 index 00000000000..6ca9a8b7cc2 --- /dev/null +++ b/gnovm/tests/files/types/shift_c3.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + x := 1 + r := uint(+(1 << x)) + println(r) + fmt.Printf("%T \n", r) +} + +// Output: +// 2 +// uint diff --git a/gnovm/tests/files/types/shift_c4.gno b/gnovm/tests/files/types/shift_c4.gno new file mode 100644 index 00000000000..55b5fa782d7 --- /dev/null +++ b/gnovm/tests/files/types/shift_c4.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + x := 63 + r := int32(+(1<>x) +} + +// Output: +// uint64 +// int64 +// 2048 +// 0 diff --git a/gnovm/tests/files/types/shift_d12.gno b/gnovm/tests/files/types/shift_d12.gno new file mode 100644 index 00000000000..3d8c6e3de16 --- /dev/null +++ b/gnovm/tests/files/types/shift_d12.gno @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func foo(a uint64, b float32) { + fmt.Printf("%T \n", a) + println(a) +} + +func main() { + x := 11 + foo(1<>x) +} + +// Error: +// main/files/types/shift_d12.gno:12:2: operator >> not defined on: Float32Kind diff --git a/gnovm/tests/files/types/shift_d13.gno b/gnovm/tests/files/types/shift_d13.gno new file mode 100644 index 00000000000..0ab495c1a26 --- /dev/null +++ b/gnovm/tests/files/types/shift_d13.gno @@ -0,0 +1,17 @@ +package main + +import "fmt" + +// it's like assign +func foo(a uint64, b float32) { + fmt.Printf("%T \n", a) + println(a) +} + +func main() { + x := 11 + foo(1<>x) +} + +// Error: +// main/files/types/shift_d13.gno:13:2: cannot use int as float32 diff --git a/gnovm/tests/files/types/shift_d14.gno b/gnovm/tests/files/types/shift_d14.gno new file mode 100644 index 00000000000..8458cf94ffb --- /dev/null +++ b/gnovm/tests/files/types/shift_d14.gno @@ -0,0 +1,18 @@ +package main + +import "fmt" + +// it's like assign +func foo(a uint64, b int64) { + fmt.Printf("%T\n", a) + println(a) +} + +func main() { + x := 11 + foo(1<>x) +} + +// Output: +// uint64 +// 2048 diff --git a/gnovm/tests/files/types/shift_d15.gno b/gnovm/tests/files/types/shift_d15.gno new file mode 100644 index 00000000000..a29108aef5a --- /dev/null +++ b/gnovm/tests/files/types/shift_d15.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 64 + y := uint64(1 << x) + println(y) +} + +// Output: +// 0 diff --git a/gnovm/tests/files/types/shift_d16.gno b/gnovm/tests/files/types/shift_d16.gno new file mode 100644 index 00000000000..3b7fb0aec50 --- /dev/null +++ b/gnovm/tests/files/types/shift_d16.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 64 + y := uint64(1<>2) //special case with == !=, untyped bool + println(r) +} + +// Error: +// main/files/types/shift_d4.gno:4:7: cannot convert BoolKind to Uint64Kind diff --git a/gnovm/tests/files/types/shift_d40.gno b/gnovm/tests/files/types/shift_d40.gno new file mode 100644 index 00000000000..8840f8b7322 --- /dev/null +++ b/gnovm/tests/files/types/shift_d40.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 2 + s := []float32{1 << a} + println(s[0]) +} + +// Error: +// main/files/types/shift_d40.gno:5:7: operator << not defined on: Float32Kind diff --git a/gnovm/tests/files/types/shift_d41.gno b/gnovm/tests/files/types/shift_d41.gno new file mode 100644 index 00000000000..bf46da524f7 --- /dev/null +++ b/gnovm/tests/files/types/shift_d41.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 2 + s := map[string]float32{"k": 1 << a} + println(s["k"]) +} + +// Error: +// main/files/types/shift_d41.gno:5:7: operator << not defined on: Float32Kind diff --git a/gnovm/tests/files/types/shift_d42.gno b/gnovm/tests/files/types/shift_d42.gno new file mode 100644 index 00000000000..c2bbfe94e2b --- /dev/null +++ b/gnovm/tests/files/types/shift_d42.gno @@ -0,0 +1,14 @@ +package main + +func main() { + type S struct { + a float32 + } + s := S{ + a: 1 << 2, + } + println(s.a) +} + +// Output: +// 4 diff --git a/gnovm/tests/files/types/shift_d43.gno b/gnovm/tests/files/types/shift_d43.gno new file mode 100644 index 00000000000..e9b0032ac9a --- /dev/null +++ b/gnovm/tests/files/types/shift_d43.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 2 + s := map[string]interface{}{"k": 1 << a} + println(s["k"]) +} + +// Output: +// 4 diff --git a/gnovm/tests/files/types/shift_d44.gno b/gnovm/tests/files/types/shift_d44.gno new file mode 100644 index 00000000000..0ef024f1e6b --- /dev/null +++ b/gnovm/tests/files/types/shift_d44.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1 + b := 1 + (a == b)++ // LHS is untyped bool, determined in preprocess +} + +// Error: +// main/files/types/shift_d44.gno:6:2: operator ++ not defined on: BoolKind diff --git a/gnovm/tests/files/types/shift_d45.gno b/gnovm/tests/files/types/shift_d45.gno new file mode 100644 index 00000000000..5c504d7d616 --- /dev/null +++ b/gnovm/tests/files/types/shift_d45.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 11 + y := uint64(1 << x) + println(y) +} + +// Output: +// 2048 diff --git a/gnovm/tests/files/types/shift_d46.gno b/gnovm/tests/files/types/shift_d46.gno new file mode 100644 index 00000000000..8490c751c88 --- /dev/null +++ b/gnovm/tests/files/types/shift_d46.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 11 + y := uint64(1.0 << x) + println(y) +} + +// Output: +// 2048 diff --git a/gnovm/tests/files/types/shift_d47.gno b/gnovm/tests/files/types/shift_d47.gno new file mode 100644 index 00000000000..d50c3944e90 --- /dev/null +++ b/gnovm/tests/files/types/shift_d47.gno @@ -0,0 +1,26 @@ +package main + +var specialBytes [16]byte + +func main() { + for i, b := range []byte(`\.+*?()|[]{}^$`) { + specialBytes[b%16] |= 1 << (b / 16) + println(i, (1 << (b / 16)), specialBytes[b%16]) + } +} + +// Output: +// 0 32 32 +// 1 4 4 +// 2 4 4 +// 3 4 4 +// 4 8 8 +// 5 4 4 +// 6 4 4 +// 7 128 160 +// 8 32 36 +// 9 32 32 +// 10 128 164 +// 11 128 160 +// 12 32 36 +// 13 4 4 diff --git a/gnovm/tests/files/types/shift_d48.gno b/gnovm/tests/files/types/shift_d48.gno new file mode 100644 index 00000000000..2ec6782c7f0 --- /dev/null +++ b/gnovm/tests/files/types/shift_d48.gno @@ -0,0 +1,23 @@ +package main + +import ( + "github.com/gnolang/gno/_test/net/http" +) + +type extendedRequest struct { + Request http.Request + + Data string +} + +func main() { + r := extendedRequest{} + // req := &r.Request + + println(r) + // XXX removed temporarily until recursion detection implemented for sprintString(). + // println(req) +} + +// Output: +// (struct{(struct{( string),( string),(0 int),(0 int),(nil github.com/gnolang/gno/_test/net/http.Header),(undefined),(0 int64),(nil []string),(false bool),( string),(nil github.com/gnolang/gno/_test/net/http.Values),(nil github.com/gnolang/gno/_test/net/http.Values),(nil github.com/gnolang/gno/_test/net/http.Header),( string),( string),(nil *github.com/gnolang/gno/_test/net/http.Response)} github.com/gnolang/gno/_test/net/http.Request),( string)} main.extendedRequest) diff --git a/gnovm/tests/files/types/shift_d4a.gno b/gnovm/tests/files/types/shift_d4a.gno new file mode 100644 index 00000000000..803da33ea64 --- /dev/null +++ b/gnovm/tests/files/types/shift_d4a.gno @@ -0,0 +1,9 @@ +package main + +func main() { + r := string(1<<2 == 1>>2) //special case with == !=, untyped bool + println(r) +} + +// Error: +// main/files/types/shift_d4a.gno:4:7: cannot convert BoolKind to StringKind diff --git a/gnovm/tests/files/types/shift_d5.gno b/gnovm/tests/files/types/shift_d5.gno new file mode 100644 index 00000000000..43c0e117f5e --- /dev/null +++ b/gnovm/tests/files/types/shift_d5.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 11 + y := 1.0 << x // no const + println(y) +} + +// Error: +// main/files/types/shift_d5.gno:5:2: operator << not defined on: Float64Kind diff --git a/gnovm/tests/files/types/shift_d50.gno b/gnovm/tests/files/types/shift_d50.gno new file mode 100644 index 00000000000..fec552e48d7 --- /dev/null +++ b/gnovm/tests/files/types/shift_d50.gno @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + x := 11 + y := uint64(-(1.0 << 2) << x) + println(y) + fmt.Printf("%T \n", y) +} + +// Error: +// main/files/types/shift_d50.gno:7:7: bigint underflows target kind diff --git a/gnovm/tests/files/types/shift_d51.gno b/gnovm/tests/files/types/shift_d51.gno new file mode 100644 index 00000000000..bd2b432479f --- /dev/null +++ b/gnovm/tests/files/types/shift_d51.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1.0 + a <<= 1 + println(a) +} + +// Error: +// main/files/types/shift_d51.gno:5:2: operator <<= not defined on: Float64Kind diff --git a/gnovm/tests/files/types/shift_d52.gno b/gnovm/tests/files/types/shift_d52.gno new file mode 100644 index 00000000000..f998381ef1c --- /dev/null +++ b/gnovm/tests/files/types/shift_d52.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1 + a <<= 1 + println(a) +} + +// Output: +// 2 diff --git a/gnovm/tests/files/types/shift_d53.gno b/gnovm/tests/files/types/shift_d53.gno new file mode 100644 index 00000000000..575dc1e146b --- /dev/null +++ b/gnovm/tests/files/types/shift_d53.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + a := 1 // a is inferred as int + b := a << 3 // b is also int + fmt.Printf("%T, %T, %d, %d \n", a, b, a, b) +} + +// Output: +// int, int, 1, 8 diff --git a/gnovm/tests/files/types/shift_d54.gno b/gnovm/tests/files/types/shift_d54.gno new file mode 100644 index 00000000000..13266f44379 --- /dev/null +++ b/gnovm/tests/files/types/shift_d54.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + a := 5 // infer type int + var b int32 = 10 + c := b + a<<2 + + fmt.Printf("%T, %d \n", c, c) +} + +// Error: +// main/files/types/shift_d54.gno:8:7: invalid operation: mismatched types int32 and int diff --git a/gnovm/tests/files/types/shift_d55.gno b/gnovm/tests/files/types/shift_d55.gno new file mode 100644 index 00000000000..58628376421 --- /dev/null +++ b/gnovm/tests/files/types/shift_d55.gno @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func shiftReturn() int64 { + return 1 << 4 // The shift result is cast to int64 +} + +func main() { + r := shiftReturn() + + fmt.Printf("%T, %d \n", r, r) +} + +// Output: +// int64, 16 diff --git a/gnovm/tests/files/types/shift_d56.gno b/gnovm/tests/files/types/shift_d56.gno new file mode 100644 index 00000000000..3f734bb993e --- /dev/null +++ b/gnovm/tests/files/types/shift_d56.gno @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func shiftReturn() int64 { + return 1<<4 + int(1) // The shift result is cast to int64 +} + +func main() { + r := shiftReturn() + + fmt.Printf("%T, %d \n", r, r) +} + +// Error: +// main/files/types/shift_d56.gno:6:2: cannot use int as int64 diff --git a/gnovm/tests/files/types/shift_d5a.gno b/gnovm/tests/files/types/shift_d5a.gno new file mode 100644 index 00000000000..8490c751c88 --- /dev/null +++ b/gnovm/tests/files/types/shift_d5a.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 11 + y := uint64(1.0 << x) + println(y) +} + +// Output: +// 2048 diff --git a/gnovm/tests/files/types/shift_d5b.gno b/gnovm/tests/files/types/shift_d5b.gno new file mode 100644 index 00000000000..8c04105a450 --- /dev/null +++ b/gnovm/tests/files/types/shift_d5b.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 11 + y := float32(1.0 << x) + println(y) +} + +// Error: +// main/files/types/shift_d5b.gno:5:7: operator << not defined on: Float32Kind diff --git a/gnovm/tests/files/types/shift_d6.gno b/gnovm/tests/files/types/shift_d6.gno new file mode 100644 index 00000000000..e2ce1d02157 --- /dev/null +++ b/gnovm/tests/files/types/shift_d6.gno @@ -0,0 +1,18 @@ +package main + +import "fmt" + +func main() { + x := 11 + y := 1 << x + println(y) + fmt.Printf("%T\n", y) + fmt.Printf("%T\n", 1) + fmt.Printf("%T\n", x) +} + +// Output: +// 2048 +// int +// int +// int diff --git a/gnovm/tests/files/types/shift_d9.gno b/gnovm/tests/files/types/shift_d9.gno new file mode 100644 index 00000000000..e766e5e218d --- /dev/null +++ b/gnovm/tests/files/types/shift_d9.gno @@ -0,0 +1,9 @@ +package main + +func main() { + r := bool(1<<2+1 == 1>>2) + println(r) +} + +// Output: +// false diff --git a/gnovm/tests/files/types/shift_e0.gno b/gnovm/tests/files/types/shift_e0.gno new file mode 100644 index 00000000000..d5b75063d3e --- /dev/null +++ b/gnovm/tests/files/types/shift_e0.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1 << -1) +} + +// Error: +// main/files/types/shift_e0.gno:4:10: invalid operation: negative shift count: (const (-1 bigint)) diff --git a/gnovm/tests/files/types/shift_e1.gno b/gnovm/tests/files/types/shift_e1.gno new file mode 100644 index 00000000000..343dee1f933 --- /dev/null +++ b/gnovm/tests/files/types/shift_e1.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1.0 << float32(2.58485848)) +} + +// Error: +// main/files/types/shift_e1.gno:4:10: invalid operation: invalid shift count: (const (2.5848584 float32)) diff --git a/gnovm/tests/files/types/shift_e1a.gno b/gnovm/tests/files/types/shift_e1a.gno new file mode 100644 index 00000000000..bb6bedd2016 --- /dev/null +++ b/gnovm/tests/files/types/shift_e1a.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1.0 << 2.0) +} + +// Output: +// 4 diff --git a/gnovm/tests/files/types/shift_e2.gno b/gnovm/tests/files/types/shift_e2.gno new file mode 100644 index 00000000000..192d5c1b3e9 --- /dev/null +++ b/gnovm/tests/files/types/shift_e2.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1 << 1.25) +} + +// Error: +// main/files/types/shift_e2.gno:4:10: invalid operation: invalid shift count: (const (1.25 bigdec)) diff --git a/gnovm/tests/files/types/shift_e3.gno b/gnovm/tests/files/types/shift_e3.gno new file mode 100644 index 00000000000..81c803897c7 --- /dev/null +++ b/gnovm/tests/files/types/shift_e3.gno @@ -0,0 +1,9 @@ +package main + +func main() { + x := 1.25 + println(1 << x) +} + +// Error: +// main/files/types/shift_e3.gno:5:10: invalid operation: invalid shift count: x diff --git a/gnovm/tests/files/types/shift_e4.gno b/gnovm/tests/files/types/shift_e4.gno new file mode 100644 index 00000000000..02746eb04fe --- /dev/null +++ b/gnovm/tests/files/types/shift_e4.gno @@ -0,0 +1,9 @@ +package main + +func main() { + x := 1.25 + println(1 << x) +} + +// Error: +// main/files/types/shift_e4.gno:5:10: invalid operation: invalid shift count: x \ No newline at end of file diff --git a/gnovm/tests/files/types/shift_e5.gno b/gnovm/tests/files/types/shift_e5.gno new file mode 100644 index 00000000000..acd351bd50d --- /dev/null +++ b/gnovm/tests/files/types/shift_e5.gno @@ -0,0 +1,9 @@ +package main + +func main() { + x := -1 + println(1 << x) +} + +// Error: +// runtime error: negative shift amount: (-1 int) diff --git a/gnovm/tests/files/types/shift_e6.gno b/gnovm/tests/files/types/shift_e6.gno new file mode 100644 index 00000000000..43cb2464132 --- /dev/null +++ b/gnovm/tests/files/types/shift_e6.gno @@ -0,0 +1,9 @@ +package main + +func main() { + x := -1 + println(1 >> x) +} + +// Error: +// runtime error: negative shift amount: (-1 int) diff --git a/gnovm/tests/files/types/shift_e7.gno b/gnovm/tests/files/types/shift_e7.gno new file mode 100644 index 00000000000..c7d8aded350 --- /dev/null +++ b/gnovm/tests/files/types/shift_e7.gno @@ -0,0 +1,9 @@ +package main + +func main() { + y := 1 + y <<= -1 +} + +// Error: +// main/files/types/shift_e7.gno:5:2: invalid operation: negative shift count: (-1 bigint) diff --git a/gnovm/tests/files/types/shift_e7a.gno b/gnovm/tests/files/types/shift_e7a.gno new file mode 100644 index 00000000000..2e81fc102bc --- /dev/null +++ b/gnovm/tests/files/types/shift_e7a.gno @@ -0,0 +1,9 @@ +package main + +func main() { + a := float64(-100) + println(1 << a) +} + +// Error: +// main/files/types/shift_e7a.gno:5:10: invalid operation: invalid shift count: a diff --git a/gnovm/tests/files/types/shift_e7b.gno b/gnovm/tests/files/types/shift_e7b.gno new file mode 100644 index 00000000000..80766d2928e --- /dev/null +++ b/gnovm/tests/files/types/shift_e7b.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1 << float64(-1)) +} + +// Error: +// main/files/types/shift_e7b.gno:4:10: invalid operation: invalid shift count: (const (-1 float64)) diff --git a/gnovm/tests/files/types/shift_e8.gno b/gnovm/tests/files/types/shift_e8.gno new file mode 100644 index 00000000000..1940dd9b8fb --- /dev/null +++ b/gnovm/tests/files/types/shift_e8.gno @@ -0,0 +1,9 @@ +package main + +func main() { + y := 1 + y <<= 1.25 +} + +// Error: +// main/files/types/shift_e8.gno:5:2: invalid operation: invalid shift count: (const (1.25 bigdec)) diff --git a/gnovm/tests/files/types/shift_e9.gno b/gnovm/tests/files/types/shift_e9.gno new file mode 100644 index 00000000000..2bd408860f2 --- /dev/null +++ b/gnovm/tests/files/types/shift_e9.gno @@ -0,0 +1,11 @@ +package main + +func main() { + x := -1 + y := 1 + y <<= x + println(y) +} + +// Error: +// runtime error: negative shift amount: (-1 int) diff --git a/gnovm/tests/files/types/shift_e9a.gno b/gnovm/tests/files/types/shift_e9a.gno new file mode 100644 index 00000000000..03ce9343948 --- /dev/null +++ b/gnovm/tests/files/types/shift_e9a.gno @@ -0,0 +1,11 @@ +package main + +func main() { + x := -1 + y := 1 + y >>= x + println(y) +} + +// Error: +// runtime error: negative shift amount: (-1 int) diff --git a/gnovm/tests/files/types/shift_f1a.gno b/gnovm/tests/files/types/shift_f1a.gno new file mode 100644 index 00000000000..ca35144bacc --- /dev/null +++ b/gnovm/tests/files/types/shift_f1a.gno @@ -0,0 +1,12 @@ +package main + +func main() { + var s uint = 33 + + var u1 bool + u1 = 1< bigint NEQ bigdec diff --git a/gnovm/tests/files/types/shift_f2e.gno b/gnovm/tests/files/types/shift_f2e.gno new file mode 100644 index 00000000000..dec0a2a6626 --- /dev/null +++ b/gnovm/tests/files/types/shift_f2e.gno @@ -0,0 +1,10 @@ +package main + +func main() { + var s uint = 33 + var u2 = 1.0< Date: Tue, 15 Oct 2024 16:26:16 +0200 Subject: [PATCH 16/20] =?UTF-8?q?chore:=20farewell=20Dylan=20=F0=9F=91=8B?= =?UTF-8?q?=20(#2951)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3870ff30539..8566e861db9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -64,9 +64,9 @@ # GnoVM/Gnolang. /gnovm/ @jaekwon @moul @piux2 @thehowl /gnovm/stdlibs/ @thehowl -/gnovm/tests/ @jaekwon @deelawn @thehowl @mvertes +/gnovm/tests/ @jaekwon @thehowl @mvertes /gnovm/cmd/gno/ @moul @thehowl -/gnovm/pkg/gnolang/ @jaekwon @moul @piux2 @deelawn +/gnovm/pkg/gnolang/ @jaekwon @moul @piux2 /gnovm/pkg/doc/ @thehowl /gnovm/pkg/repl/ @mvertes @ajnavarro /gnovm/pkg/gnomod/ @thehowl From d741140c099f427e568ecd5f8ca82b983c94ac82 Mon Sep 17 00:00:00 2001 From: Malek Lahbib <111009238+MalekLahbib@users.noreply.github.com> Date: Tue, 15 Oct 2024 19:25:45 +0200 Subject: [PATCH 17/20] fix(p/demo/uassert): amend ineffective assignment (#2936)
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- examples/gno.land/p/demo/uassert/uassert.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index 2776e93dca9..f9c0ab3efc8 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -266,7 +266,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgs ...string) bool { if av, ok := actual.(string); ok { notEqual = ev != av ok_ = true - es, as = ev, as + es, as = ev, av } case std.Address: if av, ok := actual.(std.Address); ok { From 679301ab829ee576246b03c8381bab2212baa82d Mon Sep 17 00:00:00 2001 From: Leon Hudak <33522493+leohhhn@users.noreply.github.com> Date: Tue, 15 Oct 2024 19:52:43 +0200 Subject: [PATCH 18/20] fix(r/leon/config): fix config bug (#2934) ## Description Fixes a bug in `r/leon/config`.
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests - [x] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- examples/gno.land/r/leon/config/config.gno | 20 +++++++++----------- examples/gno.land/r/leon/home/home.gno | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/examples/gno.land/r/leon/config/config.gno b/examples/gno.land/r/leon/config/config.gno index cbc1e537e3f..bc800ec8263 100644 --- a/examples/gno.land/r/leon/config/config.gno +++ b/examples/gno.land/r/leon/config/config.gno @@ -8,6 +8,9 @@ import ( var ( main std.Address // leon's main address backup std.Address // backup address + + ErrInvalidAddr = errors.New("leon's config: invalid address") + ErrUnauthorized = errors.New("leon's config: unauthorized") ) func init() { @@ -24,7 +27,7 @@ func Backup() std.Address { func SetAddress(a std.Address) error { if !a.IsValid() { - return errors.New("config: invalid address") + return ErrInvalidAddr } if err := checkAuthorized(); err != nil { @@ -37,7 +40,7 @@ func SetAddress(a std.Address) error { func SetBackup(a std.Address) error { if !a.IsValid() { - return errors.New("config: invalid address") + return ErrInvalidAddr } if err := checkAuthorized(); err != nil { @@ -50,16 +53,11 @@ func SetBackup(a std.Address) error { func checkAuthorized() error { caller := std.PrevRealm().Addr() - if caller != main || caller != backup { - return errors.New("config: unauthorized") + isAuthorized := caller == main || caller == backup + + if !isAuthorized { + return ErrUnauthorized } return nil } - -func AssertAuthorized() { - caller := std.PrevRealm().Addr() - if caller != main || caller != backup { - panic("config: unauthorized") - } -} diff --git a/examples/gno.land/r/leon/home/home.gno b/examples/gno.land/r/leon/home/home.gno index 1f6a07e8959..ba688792a4c 100644 --- a/examples/gno.land/r/leon/home/home.gno +++ b/examples/gno.land/r/leon/home/home.gno @@ -34,13 +34,19 @@ TODO import r/gh } func UpdatePFP(url, caption string) { - config.AssertAuthorized() + if !isAuthorized(std.PrevRealm().Addr()) { + panic(config.ErrUnauthorized) + } + pfp = url pfpCaption = caption } func UpdateAboutMe(col1, col2 string) { - config.AssertAuthorized() + if !isAuthorized(std.PrevRealm().Addr()) { + panic(config.ErrUnauthorized) + } + abtMe[0] = col1 abtMe[1] = col2 } @@ -119,3 +125,7 @@ func renderMillipede() string { return out } + +func isAuthorized(addr std.Address) bool { + return addr == config.Address() || addr == config.Backup() +} From a73cb22e58d8b81413c35aa0b5b4dfece2dfecd3 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Tue, 15 Oct 2024 22:54:09 +0200 Subject: [PATCH 19/20] chore: fix issues reported by `go vet` (#2952) Passing `go vet` is the minimum level of code quality for a go project. This is addressed here for the full mono-repo. Mainly trivial changes, except for a few `copy lock` issues which could be more meaningful (kept for a separate pull request). Addresses #2954 (but not sufficient to close it yet). Hint for reviewers: it's easier to review each commit individually.
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- gno.land/pkg/gnoweb/gnoweb.go | 4 ++-- gno.land/pkg/sdk/vm/builtins.go | 4 ++-- gno.land/pkg/sdk/vm/keeper_test.go | 18 +++++++-------- gnovm/pkg/gnomod/read.go | 2 +- gnovm/tests/file.go | 4 ++-- misc/logos/cmd/logos.go | 2 +- tm2/pkg/amino/wellknown.go | 1 - tm2/pkg/bft/abci/example/kvstore/helpers.go | 2 +- .../example/kvstore/persistent_kvstore.go | 2 +- tm2/pkg/bft/consensus/state.go | 22 +++++++++---------- tm2/pkg/bft/consensus/wal_generator.go | 2 +- tm2/pkg/bft/types/params.go | 6 ++--- tm2/pkg/crypto/hd/hdpath_test.go | 4 ++-- tm2/pkg/db/boltdb/boltdb.go | 4 ++-- tm2/pkg/db/memdb/mem_db.go | 2 +- tm2/pkg/p2p/switch.go | 2 +- tm2/pkg/sdk/bank/keeper_test.go | 2 +- tm2/pkg/sdk/baseapp.go | 4 ---- tm2/pkg/sdk/baseapp_test.go | 14 ++++++------ tm2/pkg/store/cache/store_test.go | 8 +++---- tm2/pkg/store/gas/store_test.go | 8 +++---- tm2/pkg/store/iavl/store_test.go | 4 ++-- tm2/pkg/store/prefix/store_test.go | 12 +++++----- 23 files changed, 64 insertions(+), 69 deletions(-) diff --git a/gno.land/pkg/gnoweb/gnoweb.go b/gno.land/pkg/gnoweb/gnoweb.go index 5377ae6a420..3e6249cf126 100644 --- a/gno.land/pkg/gnoweb/gnoweb.go +++ b/gno.land/pkg/gnoweb/gnoweb.go @@ -476,7 +476,7 @@ func handleNotFound(logger *slog.Logger, app gotuna.App, cfg *Config, path strin // decode path for non-ascii characters decodedPath, err := url.PathUnescape(path) if err != nil { - logger.Error("failed to decode path", err) + logger.Error("failed to decode path", "error", err) decodedPath = path } w.WriteHeader(http.StatusNotFound) @@ -491,7 +491,7 @@ func writeError(logger *slog.Logger, w http.ResponseWriter, err error) { if details := errors.Unwrap(err); details != nil { logger.Error("handler", "error", err, "details", details) } else { - logger.Error("handler", "error:", err) + logger.Error("handler", "error", err) } // XXX: writeError should return an error page template. diff --git a/gno.land/pkg/sdk/vm/builtins.go b/gno.land/pkg/sdk/vm/builtins.go index de58cd3e8ae..d4d6b6032b2 100644 --- a/gno.land/pkg/sdk/vm/builtins.go +++ b/gno.land/pkg/sdk/vm/builtins.go @@ -42,7 +42,7 @@ func (bnk *SDKBanker) TotalCoin(denom string) int64 { func (bnk *SDKBanker) IssueCoin(b32addr crypto.Bech32Address, denom string, amount int64) { addr := crypto.MustAddressFromString(string(b32addr)) - _, err := bnk.vmk.bank.AddCoins(bnk.ctx, addr, std.Coins{std.Coin{denom, amount}}) + _, err := bnk.vmk.bank.AddCoins(bnk.ctx, addr, std.Coins{std.Coin{Denom: denom, Amount: amount}}) if err != nil { panic(err) } @@ -50,7 +50,7 @@ func (bnk *SDKBanker) IssueCoin(b32addr crypto.Bech32Address, denom string, amou func (bnk *SDKBanker) RemoveCoin(b32addr crypto.Bech32Address, denom string, amount int64) { addr := crypto.MustAddressFromString(string(b32addr)) - _, err := bnk.vmk.bank.SubtractCoins(bnk.ctx, addr, std.Coins{std.Coin{denom, amount}}) + _, err := bnk.vmk.bank.SubtractCoins(bnk.ctx, addr, std.Coins{std.Coin{Denom: denom, Amount: amount}}) if err != nil { panic(err) } diff --git a/gno.land/pkg/sdk/vm/keeper_test.go b/gno.land/pkg/sdk/vm/keeper_test.go index 9257da2ddaf..f6c6b87419d 100644 --- a/gno.land/pkg/sdk/vm/keeper_test.go +++ b/gno.land/pkg/sdk/vm/keeper_test.go @@ -81,7 +81,7 @@ func TestVMKeeperOrigSend1(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -126,7 +126,7 @@ func TestVMKeeperOrigSend2(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -180,7 +180,7 @@ func TestVMKeeperOrigSend3(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -224,7 +224,7 @@ func TestVMKeeperRealmSend1(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -268,7 +268,7 @@ func TestVMKeeperRealmSend2(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -312,7 +312,7 @@ func TestVMKeeperOrigCallerInit(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -363,7 +363,7 @@ func TestVMKeeperRunSimple(t *testing.T) { env.acck.SetAccount(ctx, acc) files := []*std.MemFile{ - {"script.gno", ` + {Name: "script.gno", Body: ` package main func main() { @@ -402,7 +402,7 @@ func testVMKeeperRunImportStdlibs(t *testing.T, env testEnv) { env.acck.SetAccount(ctx, acc) files := []*std.MemFile{ - {"script.gno", ` + {Name: "script.gno", Body: ` package main import "std" @@ -474,7 +474,7 @@ func TestVMKeeperReinitialize(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test func Echo(msg string) string { diff --git a/gnovm/pkg/gnomod/read.go b/gnovm/pkg/gnomod/read.go index a7a600f8826..d6d771429d3 100644 --- a/gnovm/pkg/gnomod/read.go +++ b/gnovm/pkg/gnomod/read.go @@ -249,7 +249,7 @@ func (in *input) readToken() { // Otherwise, save comment for later attachment to syntax tree. in.endToken(_EOLCOMMENT) - in.comments = append(in.comments, modfile.Comment{in.token.pos, in.token.text, suffix}) + in.comments = append(in.comments, modfile.Comment{Start: in.token.pos, Token: in.token.text, Suffix: suffix}) return } diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go index f6bd789f1bf..1be2a0516f9 100644 --- a/gnovm/tests/file.go +++ b/gnovm/tests/file.go @@ -597,12 +597,12 @@ func (tb *testBanker) TotalCoin(denom string) int64 { func (tb *testBanker) IssueCoin(addr crypto.Bech32Address, denom string, amt int64) { coins, _ := tb.coinTable[addr] - sum := coins.Add(std.Coins{{denom, amt}}) + sum := coins.Add(std.Coins{{Denom: denom, Amount: amt}}) tb.coinTable[addr] = sum } func (tb *testBanker) RemoveCoin(addr crypto.Bech32Address, denom string, amt int64) { coins, _ := tb.coinTable[addr] - rest := coins.Sub(std.Coins{{denom, amt}}) + rest := coins.Sub(std.Coins{{Denom: denom, Amount: amt}}) tb.coinTable[addr] = rest } diff --git a/misc/logos/cmd/logos.go b/misc/logos/cmd/logos.go index 3a374fecba2..ddb979111fb 100644 --- a/misc/logos/cmd/logos.go +++ b/misc/logos/cmd/logos.go @@ -162,7 +162,7 @@ func makeTestPage() *logos.BufferedElemView { // make a buffered page. ts := makeTestString() style := logos.DefaultStyle() - style.Padding = logos.Padding{2, 2, 2, 2} + style.Padding = logos.Padding{Left: 2, Top: 2, Right: 2, Bottom: 2} style.Border = logos.DefaultBorder() // TODO width shouldn't matter. page := logos.NewPage(ts, 84, true, style) diff --git a/tm2/pkg/amino/wellknown.go b/tm2/pkg/amino/wellknown.go index 8c8ff79695d..9dbafcbecec 100644 --- a/tm2/pkg/amino/wellknown.go +++ b/tm2/pkg/amino/wellknown.go @@ -210,7 +210,6 @@ func isJSONWellKnownType(rt reflect.Type) (wellKnown bool) { default: return false } - return false } // Returns ok=false if nothing was done because the default behavior is fine (or if err). diff --git a/tm2/pkg/bft/abci/example/kvstore/helpers.go b/tm2/pkg/bft/abci/example/kvstore/helpers.go index b72b4da4778..c2a89fa20b3 100644 --- a/tm2/pkg/bft/abci/example/kvstore/helpers.go +++ b/tm2/pkg/bft/abci/example/kvstore/helpers.go @@ -11,7 +11,7 @@ import ( func RandVal(i int) abci.ValidatorUpdate { pubkey := ed25519.GenPrivKey().PubKey() power := random.RandUint16() + 1 - v := abci.ValidatorUpdate{pubkey.Address(), pubkey, int64(power)} + v := abci.ValidatorUpdate{Address: pubkey.Address(), PubKey: pubkey, Power: int64(power)} return v } diff --git a/tm2/pkg/bft/abci/example/kvstore/persistent_kvstore.go b/tm2/pkg/bft/abci/example/kvstore/persistent_kvstore.go index 01a8a3a8b8c..b6d096667ac 100644 --- a/tm2/pkg/bft/abci/example/kvstore/persistent_kvstore.go +++ b/tm2/pkg/bft/abci/example/kvstore/persistent_kvstore.go @@ -211,7 +211,7 @@ func (app *PersistentKVStoreApplication) execValidatorTx(tx []byte) (res abci.Re } // update - return app.updateValidator(abci.ValidatorUpdate{pubkey.Address(), pubkey, power}) + return app.updateValidator(abci.ValidatorUpdate{Address: pubkey.Address(), PubKey: pubkey, Power: power}) } // add, update, or remove a validator diff --git a/tm2/pkg/bft/consensus/state.go b/tm2/pkg/bft/consensus/state.go index 3f71dac368c..6faa40be20b 100644 --- a/tm2/pkg/bft/consensus/state.go +++ b/tm2/pkg/bft/consensus/state.go @@ -73,7 +73,7 @@ func (ti *timeoutInfo) GetHRS() cstypes.HRS { if ti == nil { return cstypes.HRS{} } else { - return cstypes.HRS{ti.Height, ti.Round, ti.Step} + return cstypes.HRS{Height: ti.Height, Round: ti.Round, Step: ti.Step} } } @@ -746,13 +746,13 @@ func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs cstypes.RoundState) { case cstypes.RoundStepNewRound: cs.enterPropose(ti.Height, 0) case cstypes.RoundStepPropose: - cs.evsw.FireEvent(cstypes.EventTimeoutPropose{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventTimeoutPropose{HRS: cs.RoundState.GetHRS()}) cs.enterPrevote(ti.Height, ti.Round) case cstypes.RoundStepPrevoteWait: - cs.evsw.FireEvent(cstypes.EventTimeoutWait{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventTimeoutWait{HRS: cs.RoundState.GetHRS()}) cs.enterPrecommit(ti.Height, ti.Round) case cstypes.RoundStepPrecommitWait: - cs.evsw.FireEvent(cstypes.EventTimeoutWait{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventTimeoutWait{HRS: cs.RoundState.GetHRS()}) cs.enterPrecommit(ti.Height, ti.Round) cs.enterNewRound(ti.Height, ti.Round+1) default: @@ -1126,7 +1126,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { } // At this point +2/3 prevoted for a particular block or nil. - cs.evsw.FireEvent(cstypes.EventPolka{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventPolka{HRS: cs.RoundState.GetHRS()}) // the latest POLRound should be this round. polRound, _ := cs.Votes.POLInfo() @@ -1143,7 +1143,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { cs.LockedRound = -1 cs.LockedBlock = nil cs.LockedBlockParts = nil - cs.evsw.FireEvent(cstypes.EventUnlock{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventUnlock{HRS: cs.RoundState.GetHRS()}) } cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{}) return @@ -1155,7 +1155,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { if cs.LockedBlock.HashesTo(blockID.Hash) { logger.Info("enterPrecommit: +2/3 prevoted locked block. Relocking") cs.LockedRound = round - cs.evsw.FireEvent(cstypes.EventRelock{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventRelock{HRS: cs.RoundState.GetHRS()}) cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader) return } @@ -1170,7 +1170,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { cs.LockedRound = round cs.LockedBlock = cs.ProposalBlock cs.LockedBlockParts = cs.ProposalBlockParts - cs.evsw.FireEvent(cstypes.EventLock{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventLock{HRS: cs.RoundState.GetHRS()}) cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader) return } @@ -1186,7 +1186,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { cs.ProposalBlock = nil cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader) } - cs.evsw.FireEvent(cstypes.EventUnlock{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventUnlock{HRS: cs.RoundState.GetHRS()}) cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{}) } @@ -1591,7 +1591,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool, return } - cs.evsw.FireEvent(types.EventVote{vote}) + cs.evsw.FireEvent(types.EventVote{Vote: vote}) switch vote.Type { case types.PrevoteType: @@ -1620,7 +1620,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool, cs.LockedRound = -1 cs.LockedBlock = nil cs.LockedBlockParts = nil - cs.evsw.FireEvent(cstypes.EventUnlock{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventUnlock{HRS: cs.RoundState.GetHRS()}) } // Update Valid* if we can. diff --git a/tm2/pkg/bft/consensus/wal_generator.go b/tm2/pkg/bft/consensus/wal_generator.go index fddcb4231e5..79c6e63c6a1 100644 --- a/tm2/pkg/bft/consensus/wal_generator.go +++ b/tm2/pkg/bft/consensus/wal_generator.go @@ -77,7 +77,7 @@ func (w *heightStopWAL) Write(m walm.WALMessage) error { } w.logger.Debug("WAL Write Message", "msg", m) - err := w.enc.Write(walm.TimedWALMessage{fixedTime, m}) + err := w.enc.Write(walm.TimedWALMessage{Time: fixedTime, Msg: m}) if err != nil { panic(fmt.Sprintf("failed to encode the msg %v", m)) } diff --git a/tm2/pkg/bft/types/params.go b/tm2/pkg/bft/types/params.go index 0b48da9329e..c2e8f304698 100644 --- a/tm2/pkg/bft/types/params.go +++ b/tm2/pkg/bft/types/params.go @@ -36,8 +36,8 @@ var validatorPubKeyTypeURLs = map[string]struct{}{ func DefaultConsensusParams() abci.ConsensusParams { return abci.ConsensusParams{ - DefaultBlockParams(), - DefaultValidatorParams(), + Block: DefaultBlockParams(), + Validator: DefaultValidatorParams(), } } @@ -51,7 +51,7 @@ func DefaultBlockParams() *abci.BlockParams { } func DefaultValidatorParams() *abci.ValidatorParams { - return &abci.ValidatorParams{[]string{ + return &abci.ValidatorParams{PubKeyTypeURLs: []string{ amino.GetTypeURL(ed25519.PubKeyEd25519{}), }} } diff --git a/tm2/pkg/crypto/hd/hdpath_test.go b/tm2/pkg/crypto/hd/hdpath_test.go index 31e806b2b1a..f79ee1151f7 100644 --- a/tm2/pkg/crypto/hd/hdpath_test.go +++ b/tm2/pkg/crypto/hd/hdpath_test.go @@ -17,7 +17,7 @@ func mnemonicToSeed(mnemonic string) []byte { return bip39.NewSeed(mnemonic, defaultBIP39Passphrase) } -func ExampleStringifyPathParams() { +func ExampleNewParams() { path := NewParams(44, 0, 0, false, 0) fmt.Println(path.String()) path = NewParams(44, 33, 7, true, 9) @@ -109,7 +109,7 @@ func TestParamsFromPath(t *testing.T) { } } -func ExampleSomeBIP32TestVecs() { +func ExampleDerivePrivateKeyForPath() { seed := mnemonicToSeed("barrel original fuel morning among eternal " + "filter ball stove pluck matrix mechanic") master, ch := ComputeMastersFromSeed(seed) diff --git a/tm2/pkg/db/boltdb/boltdb.go b/tm2/pkg/db/boltdb/boltdb.go index c35e3bb00e1..12aa20b8ce2 100644 --- a/tm2/pkg/db/boltdb/boltdb.go +++ b/tm2/pkg/db/boltdb/boltdb.go @@ -170,13 +170,13 @@ func (bdb *BoltDB) NewBatch() db.Batch { // It is safe to modify the contents of the argument after Set returns but not // before. func (bdb *boltDBBatch) Set(key, value []byte) { - bdb.ops = append(bdb.ops, internal.Operation{internal.OpTypeSet, key, value}) + bdb.ops = append(bdb.ops, internal.Operation{OpType: internal.OpTypeSet, Key: key, Value: value}) } // It is safe to modify the contents of the argument after Delete returns but // not before. func (bdb *boltDBBatch) Delete(key []byte) { - bdb.ops = append(bdb.ops, internal.Operation{internal.OpTypeDelete, key, nil}) + bdb.ops = append(bdb.ops, internal.Operation{OpType: internal.OpTypeDelete, Key: key}) } // NOTE: the operation is synchronous (see BoltDB for reasons) diff --git a/tm2/pkg/db/memdb/mem_db.go b/tm2/pkg/db/memdb/mem_db.go index 09b90b6be44..d39a9838cef 100644 --- a/tm2/pkg/db/memdb/mem_db.go +++ b/tm2/pkg/db/memdb/mem_db.go @@ -150,7 +150,7 @@ func (db *MemDB) NewBatch() dbm.Batch { db.mtx.Lock() defer db.mtx.Unlock() - return &internal.MemBatch{db, nil} + return &internal.MemBatch{DB: db} } // ---------------------------------------- diff --git a/tm2/pkg/p2p/switch.go b/tm2/pkg/p2p/switch.go index cecfc21f3ef..b2de68e1ae3 100644 --- a/tm2/pkg/p2p/switch.go +++ b/tm2/pkg/p2p/switch.go @@ -219,7 +219,7 @@ func (sw *Switch) OnStop() { if t, ok := sw.transport.(TransportLifecycle); ok { err := t.Close() if err != nil { - sw.Logger.Error("Error stopping transport on stop: ", err) + sw.Logger.Error("Error stopping transport on stop: ", "error", err) } } diff --git a/tm2/pkg/sdk/bank/keeper_test.go b/tm2/pkg/sdk/bank/keeper_test.go index 59b4c12689c..df2039a682c 100644 --- a/tm2/pkg/sdk/bank/keeper_test.go +++ b/tm2/pkg/sdk/bank/keeper_test.go @@ -133,7 +133,7 @@ func TestBankKeeper(t *testing.T) { // validate coins with invalid denoms or negative values cannot be sent // NOTE: We must use the Coin literal as the constructor does not allow // negative values. - err = bank.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.Coin{"FOOCOIN", -5}}) + err = bank.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.Coin{Denom: "FOOCOIN", Amount: -5}}) require.Error(t, err) } diff --git a/tm2/pkg/sdk/baseapp.go b/tm2/pkg/sdk/baseapp.go index 671f18cf058..3cabc9df336 100644 --- a/tm2/pkg/sdk/baseapp.go +++ b/tm2/pkg/sdk/baseapp.go @@ -392,10 +392,6 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { default: return handleQueryCustom(app, path, req) } - - msg := "unknown query path " + req.Path - res.Error = ABCIError(std.ErrUnknownRequest(msg)) - return } func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { diff --git a/tm2/pkg/sdk/baseapp_test.go b/tm2/pkg/sdk/baseapp_test.go index c8884533b30..08e8191170a 100644 --- a/tm2/pkg/sdk/baseapp_test.go +++ b/tm2/pkg/sdk/baseapp_test.go @@ -47,7 +47,7 @@ func newTxCounter(txInt int64, msgInts ...int64) std.Tx { msgs := make([]std.Msg, len(msgInts)) for i, msgInt := range msgInts { - msgs[i] = msgCounter{msgInt, false} + msgs[i] = msgCounter{Counter: msgInt, FailOnHandler: false} } tx := std.Tx{Msgs: msgs} @@ -120,13 +120,13 @@ func TestLoadVersion(t *testing.T) { header := &bft.Header{ChainID: "test-chain", Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res := app.Commit() - commitID1 := store.CommitID{1, res.Data} + commitID1 := store.CommitID{Version: 1, Hash: res.Data} // execute a block, collect commit ID header = &bft.Header{ChainID: "test-chain", Height: 2} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res = app.Commit() - commitID2 := store.CommitID{2, res.Data} + commitID2 := store.CommitID{Version: 2, Hash: res.Data} // reload with LoadLatestVersion app = newBaseApp(name, db, pruningOpt) @@ -184,7 +184,7 @@ func TestLoadVersionInvalid(t *testing.T) { header := &bft.Header{ChainID: "test-chain", Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res := app.Commit() - commitID1 := store.CommitID{1, res.Data} + commitID1 := store.CommitID{Version: 1, Hash: res.Data} // create a new app with the stores mounted under the same cap key app = newBaseApp(name, db, pruningOpt) @@ -439,7 +439,7 @@ func setCounter(tx *Tx, counter int64) { func setFailOnHandler(tx *Tx, fail bool) { for i, msg := range tx.Msgs { - tx.Msgs[i] = msgCounter{msg.(msgCounter).Counter, fail} + tx.Msgs[i] = msgCounter{Counter: msg.(msgCounter).Counter, FailOnHandler: fail} } } @@ -676,8 +676,8 @@ func TestMultiMsgDeliverTx(t *testing.T) { // replace the second message with a msgCounter2 tx = newTxCounter(1, 3) - tx.Msgs = append(tx.Msgs, msgCounter2{0}) - tx.Msgs = append(tx.Msgs, msgCounter2{1}) + tx.Msgs = append(tx.Msgs, msgCounter2{Counter: 0}) + tx.Msgs = append(tx.Msgs, msgCounter2{Counter: 1}) txBytes, err = amino.Marshal(tx) require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) diff --git a/tm2/pkg/store/cache/store_test.go b/tm2/pkg/store/cache/store_test.go index 4ac8cc64de9..1caf51ea52c 100644 --- a/tm2/pkg/store/cache/store_test.go +++ b/tm2/pkg/store/cache/store_test.go @@ -15,7 +15,7 @@ import ( ) func newCacheStore() types.Store { - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} return cache.New(mem) } @@ -25,7 +25,7 @@ func valFmt(i int) []byte { return bz(fmt.Sprintf("value%0.8d", i)) } func TestCacheStore(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} st := cache.New(mem) require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") @@ -70,7 +70,7 @@ func TestCacheStore(t *testing.T) { func TestCacheStoreNoNilSet(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} st := cache.New(mem) require.Panics(t, func() { st.Set([]byte("key"), nil) }, "setting a nil value should panic") } @@ -78,7 +78,7 @@ func TestCacheStoreNoNilSet(t *testing.T) { func TestCacheStoreNested(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} st := cache.New(mem) // set. check its there on st and not on mem. diff --git a/tm2/pkg/store/gas/store_test.go b/tm2/pkg/store/gas/store_test.go index 5b8cc7c656c..52c8dbf08e8 100644 --- a/tm2/pkg/store/gas/store_test.go +++ b/tm2/pkg/store/gas/store_test.go @@ -20,7 +20,7 @@ func valFmt(i int) []byte { return bz(fmt.Sprintf("value%0.8d", i)) } func TestGasKVStoreBasic(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} meter := types.NewGasMeter(10000) st := gas.New(mem, meter, types.DefaultGasConfig()) require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") @@ -34,7 +34,7 @@ func TestGasKVStoreBasic(t *testing.T) { func TestGasKVStoreIterator(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} meter := types.NewGasMeter(10000) st := gas.New(mem, meter, types.DefaultGasConfig()) require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") @@ -60,7 +60,7 @@ func TestGasKVStoreIterator(t *testing.T) { func TestGasKVStoreOutOfGasSet(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} meter := types.NewGasMeter(0) st := gas.New(mem, meter, types.DefaultGasConfig()) require.Panics(t, func() { st.Set(keyFmt(1), valFmt(1)) }, "Expected out-of-gas") @@ -69,7 +69,7 @@ func TestGasKVStoreOutOfGasSet(t *testing.T) { func TestGasKVStoreOutOfGasIterator(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} meter := types.NewGasMeter(20000) st := gas.New(mem, meter, types.DefaultGasConfig()) st.Set(keyFmt(1), valFmt(1)) diff --git a/tm2/pkg/store/iavl/store_test.go b/tm2/pkg/store/iavl/store_test.go index 6959e9172dc..9157394cb08 100644 --- a/tm2/pkg/store/iavl/store_test.go +++ b/tm2/pkg/store/iavl/store_test.go @@ -46,7 +46,7 @@ func newAlohaTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, types.CommitID) { } hash, ver, err := tree.SaveVersion() require.Nil(t, err) - return tree, types.CommitID{ver, hash} + return tree, types.CommitID{Version: ver, Hash: hash} } func TestGetImmutable(t *testing.T) { @@ -58,7 +58,7 @@ func TestGetImmutable(t *testing.T) { require.True(t, tree.Set([]byte("hello"), []byte("adios"))) hash, ver, err := tree.SaveVersion() - cID = types.CommitID{ver, hash} + cID = types.CommitID{Version: ver, Hash: hash} require.Nil(t, err) _, err = store.GetImmutable(cID.Version + 1) diff --git a/tm2/pkg/store/prefix/store_test.go b/tm2/pkg/store/prefix/store_test.go index 701ceda17d5..d61b67462e8 100644 --- a/tm2/pkg/store/prefix/store_test.go +++ b/tm2/pkg/store/prefix/store_test.go @@ -106,7 +106,7 @@ func TestPrefixStoreNoNilSet(t *testing.T) { t.Parallel() meter := types.NewGasMeter(100000000) - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} gasStore := gas.New(mem, meter, types.DefaultGasConfig()) require.Panics(t, func() { gasStore.Set([]byte("key"), nil) }, "setting a nil value should panic") } @@ -115,7 +115,7 @@ func TestPrefixStoreIterate(t *testing.T) { t.Parallel() db := memdb.NewMemDB() - baseStore := dbadapter.Store{db} + baseStore := dbadapter.Store{DB: db} prefix := []byte("test") prefixStore := New(baseStore, prefix) @@ -165,7 +165,7 @@ func TestPrefixStoreIteratorEdgeCase(t *testing.T) { t.Parallel() db := memdb.NewMemDB() - baseStore := dbadapter.Store{db} + baseStore := dbadapter.Store{DB: db} // overflow in cpIncr prefix := []byte{0xAA, 0xFF, 0xFF} @@ -197,7 +197,7 @@ func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) { t.Parallel() db := memdb.NewMemDB() - baseStore := dbadapter.Store{db} + baseStore := dbadapter.Store{DB: db} // overflow in cpIncr prefix := []byte{0xAA, 0xFF, 0xFF} @@ -225,7 +225,7 @@ func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) { iter.Close() db = memdb.NewMemDB() - baseStore = dbadapter.Store{db} + baseStore = dbadapter.Store{DB: db} // underflow in cpDecr prefix = []byte{0xAA, 0x00, 0x00} @@ -256,7 +256,7 @@ func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) { func mockStoreWithStuff() types.Store { db := memdb.NewMemDB() - store := dbadapter.Store{db} + store := dbadapter.Store{DB: db} // Under "key" prefix store.Set(bz("key"), bz("value")) store.Set(bz("key1"), bz("value1")) From 5444859b159b40927f7771e20cc7386582a87332 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Wed, 16 Oct 2024 11:46:26 +0200 Subject: [PATCH 20/20] chore: Remove checkbox with the reminder of adding more Benchmarks. (#2927) --- .github/pull_request_template.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d76f68cba5d..12e07a9cde6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -8,5 +8,4 @@ - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests -- [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).