Add single-quoted strings
diff --git a/doc/changelog.md b/doc/changelog.md
index c6190d6..b6a3061 100644
--- a/doc/changelog.md
+++ b/doc/changelog.md
@@ -16,6 +16,7 @@
- Added `WUFFS_BASE__PIXEL_FORMAT__BGR_565`.
- Added interfaces.
- Added preprocessor.
+- Added single-quoted strings.
- Added tokens.
- Changed `gif.decoder_workbuf_len_max_incl_worst_case` from 1 to 0.
- Made `wuffs_base__pixel_format` a struct.
diff --git a/doc/wuffs-the-language.md b/doc/wuffs-the-language.md
index 54c7cb3..1c081b4 100644
--- a/doc/wuffs-the-language.md
+++ b/doc/wuffs-the-language.md
@@ -22,9 +22,6 @@
- [Iterate loops](/doc/note/iterate-loops.md).
- Public vs private API is marked with the `pub` and `pri` keywords. Visibility
boundaries are at the package level, unlike C++ or Java's type level.
-- No string type, only [slices](/doc/note/slices-arrays-and-tables.md) of
- `base.u8`. Literals like `"#bad checksum"` are actually
- [statuses](/doc/note/statuses.md).
- No variable shadowing. All local variables must be declared before any other
statements in a function body.
- Like Go, semi-colons can be omitted. Similarly, the `()` parentheses around
@@ -88,6 +85,34 @@
The `as` operator, e.g. `x as T`, converts an expression `x` to the type `T`.
+## Strings
+
+There is no string type. There are [arrays and
+slices](/doc/note/slices-arrays-and-tables.md) of bytes (`base.u8`s), but bear
+in mind that Wuffs code cannot [allocate or free
+memory](/doc/note/memory-safety.md).
+
+Double-quoted literals like `"#bad checksum"` are actually
+[statuses](/doc/note/statuses.md), [axiom names](/doc/note/assertions.md) or a
+`use "std/foo"` package name.
+
+Single-quoted literals are actually numerical constants. For example, `'A'` and
+`'\t'` are equivalent to `0x41` and `0x09`. These literals are not restricted
+to a single ASCII byte or even a single Unicode code point, and can decode to
+multiple bytes when finished with a `be` or `le` endianness suffix. For
+example, `'\x01\x02'be` is equivalent to `0x0102`. Similarly, `'\u0394?'le`
+(which can also be written `'Δ?'le`) is equivalent to `0x3F94CE`, because the
+UTF-8 encodings of U+0394 GREEK CAPITAL LETTER DELTA and U+003F QUESTION MARK
+(the ASCII `?`) is `(0xCE, 0x94)` and `(0x3F)`.
+
+Double-quoted literals cannot contain backslashes, as they'd be an unnecessary
+complication. Single-quoted literals can contain backslash-escapes, as they are
+often compared with arbitrary binary data. For example, where other programming
+languages would check if JPEG data starts with the magic _string_ `"\xFF\xD8"`,
+Wuffs would check if its opening 2 bytes, read as a little-endian `base.u16`,
+is a _number_ that equals `'\xFF\xD8'le`.
+
+
## Introductory Example
A simple Wuffs the Language program, unrelated to Wuffs the Library, is
diff --git a/internal/cgen/expr.go b/internal/cgen/expr.go
index 7c2874d..3dd3898 100644
--- a/internal/cgen/expr.go
+++ b/internal/cgen/expr.go
@@ -70,7 +70,7 @@
b.writes("false")
}
- } else if ident.IsStrLiteral(g.tm) {
+ } else if ident.IsDQStrLiteral(g.tm) {
if z := g.statusMap[n.StatusQID()]; z.cName != "" {
b.writes("wuffs_base__make_status(")
b.writes(z.cName)
diff --git a/internal/cgen/statement.go b/internal/cgen/statement.go
index b141b64..fd19ad3 100644
--- a/internal/cgen/statement.go
+++ b/internal/cgen/statement.go
@@ -441,7 +441,7 @@
b.writes("wuffs_base__make_status(NULL)")
isComplete = true
} else {
- if retExpr.Ident().IsStrLiteral(g.tm) {
+ if retExpr.Ident().IsDQStrLiteral(g.tm) {
msg, _ := t.Unescape(retExpr.Ident().Str(g.tm))
isComplete = statusMsgIsNote(msg)
}
diff --git a/lang/ast/ast.go b/lang/ast/ast.go
index 7779f6e..d31ed6a 100644
--- a/lang/ast/ast.go
+++ b/lang/ast/ast.go
@@ -379,7 +379,7 @@
// Assert is "assert RHS via ID2(args)", "pre etc", "inv etc" or "post etc":
// - ID0: <IDAssert|IDPre|IDInv|IDPost>
-// - ID2: <string literal> reason
+// - ID2: <"-string literal> reason
// - RHS: <Expr>
// - List0: <Arg> reason arguments
type Assert Node
@@ -948,7 +948,7 @@
}
// Use is "use ID2":
-// - ID2: <string literal> package path
+// - ID2: <"-string literal> package path
type Use Node
func (n *Use) AsNode() *Node { return (*Node)(n) }
diff --git a/lang/check/type.go b/lang/check/type.go
index 50da53a..7a0da26 100644
--- a/lang/check/type.go
+++ b/lang/check/type.go
@@ -364,7 +364,28 @@
n.SetMType(typeExprIdeal)
return nil
- } else if id1.IsStrLiteral(q.tm) {
+ } else if id1.IsSQStrLiteral(q.tm) {
+ s := id1.Str(q.tm)
+ unescaped, ok := t.Unescape(id1.Str(q.tm))
+ if !ok {
+ return fmt.Errorf("check: invalid '-string literal %q", s)
+ }
+
+ z := big.NewInt(0)
+ i, iEnd, iDelta := 0, len(unescaped), +1 // Big-endian.
+ if (len(s) > 2) && (s[len(s)-2] == 'l') {
+ i, iEnd, iDelta = len(unescaped)-1, -1, -1 // Little-endian.
+ }
+ for ; i != iEnd; i += iDelta {
+ z.Lsh(z, 8)
+ z.Or(z, big.NewInt(int64(unescaped[i])))
+ }
+
+ n.SetConstValue(z)
+ n.SetMType(typeExprIdeal)
+ return nil
+
+ } else if id1.IsDQStrLiteral(q.tm) {
if _, ok := q.c.statuses[n.StatusQID()]; !ok {
return fmt.Errorf("check: unrecognized status %s", n.StatusQID().Str(q.tm))
}
diff --git a/lang/parse/parse.go b/lang/parse/parse.go
index ab54a69..93a3eea 100644
--- a/lang/parse/parse.go
+++ b/lang/parse/parse.go
@@ -113,9 +113,9 @@
case t.IDUse:
p.src = p.src[1:]
path := p.peek1()
- if !path.IsStrLiteral(p.tm) {
+ if !path.IsDQStrLiteral(p.tm) {
got := p.tm.ByID(path)
- return nil, fmt.Errorf(`parse: expected string literal, got %q at %s:%d`, got, p.filename, p.line())
+ return nil, fmt.Errorf(`parse: expected "-string literal, got %q at %s:%d`, got, p.filename, p.line())
}
p.src = p.src[1:]
if x := p.peek1(); x != t.IDSemicolon {
@@ -224,9 +224,9 @@
p.src = p.src[1:]
message := p.peek1()
- if !message.IsStrLiteral(p.tm) {
+ if !message.IsDQStrLiteral(p.tm) {
got := p.tm.ByID(message)
- return nil, fmt.Errorf(`parse: expected string literal, got %q at %s:%d`, got, p.filename, p.line())
+ return nil, fmt.Errorf(`parse: expected "-string literal, got %q at %s:%d`, got, p.filename, p.line())
}
if s, _ := t.Unescape(p.tm.ByID(message)); !isStatusMessage(s) {
return nil, fmt.Errorf(`parse: status message %q does not start with `+
@@ -604,9 +604,9 @@
if p.peek1() == t.IDVia {
p.src = p.src[1:]
reason = p.peek1()
- if !reason.IsStrLiteral(p.tm) {
+ if !reason.IsDQStrLiteral(p.tm) {
got := p.tm.ByID(reason)
- return nil, fmt.Errorf(`parse: expected string literal, got %q at %s:%d`, got, p.filename, p.line())
+ return nil, fmt.Errorf(`parse: expected "-string literal, got %q at %s:%d`, got, p.filename, p.line())
}
p.src = p.src[1:]
args, err = p.parseList(t.IDCloseParen, (*parser).parseArgNode)
@@ -1254,11 +1254,11 @@
p.src = p.src[1:]
if x := p.peek1(); x.IsLiteral(p.tm) {
- if x.IsNumLiteral(p.tm) {
- return nil, fmt.Errorf(`parse: dot followed by numeric literal at %s:%d`, p.filename, p.line())
+ if !x.IsDQStrLiteral(p.tm) {
+ return nil, fmt.Errorf(`parse: dot followed by non-"-string literal at %s:%d`, p.filename, p.line())
}
if !first {
- return nil, fmt.Errorf(`parse: string literal %s has too many package qualifiers at %s:%d`,
+ return nil, fmt.Errorf(`parse: "-string literal %s has too many package qualifiers at %s:%d`,
x.Str(p.tm), p.filename, p.line())
}
p.src = p.src[1:]
diff --git a/lang/render/render.go b/lang/render/render.go
index a42ec18..2efa21b 100644
--- a/lang/render/render.go
+++ b/lang/render/render.go
@@ -291,7 +291,8 @@
}
func isCloseIdentStrLiteralQuestion(tm *t.Map, x t.ID) bool {
- return x.IsClose() || x.IsIdent(tm) || x.IsStrLiteral(tm) || (x == t.IDQuestion)
+ return x.IsClose() || x.IsIdent(tm) || x.IsDQStrLiteral(tm) ||
+ x.IsSQStrLiteral(tm) || (x == t.IDQuestion)
}
func measureVarNameLength(tm *t.Map, lineTokens []t.Token, remaining []t.Token) uint32 {
diff --git a/lang/token/list.go b/lang/token/list.go
index 94e7767..d585c60 100644
--- a/lang/token/list.go
+++ b/lang/token/list.go
@@ -81,7 +81,8 @@
return false
}
-func (x ID) IsStrLiteral(m *Map) bool {
+// IsDQStrLiteral returns whether x is a double-quote string literal.
+func (x ID) IsDQStrLiteral(m *Map) bool {
if x < nBuiltInIDs {
return false
} else if s := m.ByID(x); s != "" {
@@ -90,6 +91,16 @@
return false
}
+// IsSQStrLiteral returns whether x is a single-quote string literal.
+func (x ID) IsSQStrLiteral(m *Map) bool {
+ if x < nBuiltInIDs {
+ return false
+ } else if s := m.ByID(x); s != "" {
+ return s[0] == '\''
+ }
+ return false
+}
+
func (x ID) IsIdent(m *Map) bool {
if x < nBuiltInIDs {
return minBuiltInIdent <= x && x <= maxBuiltInIdent
diff --git a/lang/token/token.go b/lang/token/token.go
index b46e4dc..0d821e9 100644
--- a/lang/token/token.go
+++ b/lang/token/token.go
@@ -17,6 +17,7 @@
import (
"errors"
"fmt"
+ "unicode/utf8"
)
const (
@@ -25,11 +26,115 @@
maxTokenSize = 1023
)
+var backslashes = [256]byte{
+ '"': 0x22 | 0x80,
+ '\'': 0x27 | 0x80,
+ '/': 0x2F | 0x80,
+ '0': 0x00 | 0x80,
+ '?': 0x3F | 0x80,
+ '\\': 0x5C | 0x80,
+ 'a': 0x07 | 0x80,
+ 'b': 0x08 | 0x80,
+ 'e': 0x1B | 0x80,
+ 'f': 0x0C | 0x80,
+ 'n': 0x0A | 0x80,
+ 'r': 0x0D | 0x80,
+ 't': 0x09 | 0x80,
+ 'v': 0x0B | 0x80,
+}
+
func Unescape(s string) (unescaped string, ok bool) {
- if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
+ if len(s) < 2 {
return "", false
}
- return s[1 : len(s)-1], true
+ switch s[0] {
+ case '"':
+ if s[len(s)-1] == '"' {
+ s = s[1 : len(s)-1]
+ } else {
+ return "", false
+ }
+ case '\'':
+ if s[len(s)-1] == '\'' {
+ s = s[1 : len(s)-1]
+ } else if (len(s) >= 4) && (s[len(s)-3] == '\'') &&
+ ((s[len(s)-2] == 'b') || (s[len(s)-2] == 'l')) &&
+ (s[len(s)-1] == 'e') { // "be" or "le" suffix.
+ s = s[1 : len(s)-3]
+ } else {
+ return "", false
+ }
+ default:
+ return "", false
+ }
+
+ for i := 0; ; i++ {
+ if i == len(s) {
+ // There were no backslashes.
+ return s, true
+ }
+ if s[i] == '\\' {
+ break
+ }
+ }
+
+ // There were backslashes.
+ b := make([]byte, 0, len(s))
+ for i := 0; i < len(s); {
+ if s[i] != '\\' {
+ b = append(b, s[i])
+ i += 1
+ continue
+ } else if i >= (len(s) - 1) {
+ // No-op.
+ } else if x := backslashes[s[i+1]]; x != 0 {
+ b = append(b, x&0x7F)
+ i += 2
+ continue
+ } else if (s[i+1] == 'x') && (i < (len(s) - 3)) {
+ u0 := unhex(s[i+2])
+ u1 := unhex(s[i+3])
+ u := (u0 << 4) | u1
+ if 0 <= u {
+ b = append(b, uint8(u))
+ i += 4
+ continue
+ }
+ } else if (s[i+1] == 'u') && (i < (len(s) - 5)) {
+ u0 := unhex(s[i+2])
+ u1 := unhex(s[i+3])
+ u2 := unhex(s[i+4])
+ u3 := unhex(s[i+5])
+ u := (u0 << 12) | (u1 << 8) | (u2 << 4) | u3
+ if (u >= 0) && utf8.ValidRune(u) {
+ e := [utf8.UTFMax]byte{}
+ n := utf8.EncodeRune(e[:], u)
+ b = append(b, e[:n]...)
+ i += 6
+ continue
+ }
+ } else if (s[i+1] == 'U') && (i < (len(s) - 9)) {
+ u0 := unhex(s[i+2])
+ u1 := unhex(s[i+3])
+ u2 := unhex(s[i+4])
+ u3 := unhex(s[i+5])
+ u4 := unhex(s[i+6])
+ u5 := unhex(s[i+7])
+ u6 := unhex(s[i+8])
+ u7 := unhex(s[i+9])
+ u := (u0 << 28) | (u1 << 24) | (u2 << 20) | (u3 << 16) |
+ (u4 << 12) | (u5 << 8) | (u6 << 4) | u7
+ if (u >= 0) && utf8.ValidRune(u) {
+ e := [utf8.UTFMax]byte{}
+ n := utf8.EncodeRune(e[:], u)
+ b = append(b, e[:n]...)
+ i += 10
+ continue
+ }
+ }
+ return "", false
+ }
+ return string(b), true
}
type Map struct {
@@ -81,6 +186,18 @@
return ""
}
+func unhex(c byte) int32 {
+ switch {
+ case 'A' <= c && c <= 'F':
+ return int32(c) - ('A' - 10)
+ case 'a' <= c && c <= 'f':
+ return int32(c) - ('a' - 10)
+ case '0' <= c && c <= '9':
+ return int32(c) - '0'
+ }
+ return -1
+}
+
func alpha(c byte) bool {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || (c == '_')
}
@@ -150,32 +267,45 @@
continue
}
- // TODO: recognize escapes such as `\t`, `\"` and `\\`. For now, we
- // assume that strings don't contain control bytes or backslashes.
- // Neither should be necessary to parse `use "foo/bar"` lines.
- if c == '"' {
+ if (c == '"') || (c == '\'') {
+ quote := c
j := i + 1
- for ; j < len(src); j++ {
+ for j < len(src) {
c = src[j]
- if c == '"' {
- j++
+ j++
+ if c == quote {
break
- }
- if c == '\\' {
- return nil, nil, fmt.Errorf("token: backslash in string at %s:%d", filename, line)
- }
- if c == '\n' {
- return nil, nil, fmt.Errorf("token: expected final '\"' in string at %s:%d", filename, line)
- }
- if c < ' ' {
+ } else if c == '\\' {
+ if quote == '"' {
+ return nil, nil, fmt.Errorf("token: backslash in \"-string at %s:%d", filename, line)
+ }
+ } else if c == '\n' {
+ return nil, nil, fmt.Errorf("token: expected final %c in string at %s:%d", quote, filename, line)
+ } else if c < ' ' {
return nil, nil, fmt.Errorf("token: control character in string at %s:%d", filename, line)
}
- // The -1 is because we still haven't seen the final '"'.
- if j-i == maxTokenSize-1 {
- return nil, nil, fmt.Errorf("token: string too long at %s:%d", filename, line)
+ }
+
+ hasEndian := (quote == '\'') && (j < (len(src) - 2)) &&
+ ((src[j] == 'b') || (src[j] == 'l')) &&
+ (src[j+1] == 'e')
+ if hasEndian {
+ j += 2
+ }
+
+ if j-i > maxTokenSize {
+ return nil, nil, fmt.Errorf("token: string too long at %s:%d", filename, line)
+ }
+ s := string(src[i:j])
+ if quote == '\'' {
+ if unescaped, ok := Unescape(s); !ok {
+ return nil, nil, fmt.Errorf("token: invalid '-string at %s:%d", filename, line)
+ } else if (len(unescaped) > 1) && !hasEndian {
+ return nil, nil, fmt.Errorf("token: multi-byte '-string needs be or le suffix at %s:%d", filename, line)
}
}
- id, err := m.Insert(string(src[i:j]))
+
+ id, err := m.Insert(s)
if err != nil {
return nil, nil, err
}
diff --git a/std/bmp/decode_bmp.wuffs b/std/bmp/decode_bmp.wuffs
index 032f798..5cbe82a 100644
--- a/std/bmp/decode_bmp.wuffs
+++ b/std/bmp/decode_bmp.wuffs
@@ -70,7 +70,7 @@
// Read the BITMAPFILEHEADER (14 bytes).
magic = args.src.read_u16le_as_u32?()
- if magic <> 0x4D42 { // "BM" little-endian.
+ if magic <> 'BM'le {
return "#bad header"
}
diff --git a/std/gif/decode_config.wuffs b/std/gif/decode_config.wuffs
index 235bdf8..67d8f5b 100644
--- a/std/gif/decode_config.wuffs
+++ b/std/gif/decode_config.wuffs
@@ -180,9 +180,9 @@
}
pub func config_decoder.set_report_metadata!(fourcc: base.u32, report: base.bool) {
- if args.fourcc == 0x4943_4350 { // "ICCP"
+ if args.fourcc == 'ICCP'be {
this.report_metadata_iccp = args.report
- } else if args.fourcc == 0x584D_5020 { // "XMP "
+ } else if args.fourcc == 'XMP 'be {
this.report_metadata_xmp = args.report
}
}
@@ -204,7 +204,7 @@
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
if this.metadata_chunk_length_value > 0 {
- if this.metadata_fourcc_value == 0x584D_5020 { // "XMP "
+ if this.metadata_fourcc_value == 'XMP 'be {
// The +1 is because XMP metadata's encoding includes each
// block's leading byte (the block size) as part of the
// metadata passed to the caller.
@@ -427,8 +427,8 @@
c[i] = args.src.read_u8?()
i += 1
}
- if (c[0] <> 0x47) or (c[1] <> 0x49) or (c[2] <> 0x46) or (c[3] <> 0x38) or
- ((c[4] <> 0x37) and (c[4] <> 0x39)) or (c[5] <> 0x61) {
+ if (c[0] <> 'G') or (c[1] <> 'I') or (c[2] <> 'F') or (c[3] <> '8') or
+ ((c[4] <> '7') and (c[4] <> '9')) or (c[5] <> 'a') {
return "#bad header"
}
}
@@ -617,7 +617,7 @@
}
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
args.src.skip32_fast!(actual: 1, worst_case: 1)
- this.metadata_fourcc_value = 0x4943_4350 // "ICCP"
+ this.metadata_fourcc_value = 'ICCP'be
this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
this.call_sequence = 1
return base."@metadata reported"
@@ -637,7 +637,7 @@
} else {
args.src.skip32_fast!(actual: 1, worst_case: 1)
}
- this.metadata_fourcc_value = 0x584D_5020 // "XMP "
+ this.metadata_fourcc_value = 'XMP 'be
this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
this.call_sequence = 1
return base."@metadata reported"
diff --git a/std/gif/decode_gif.wuffs b/std/gif/decode_gif.wuffs
index 4f98771..56c23da 100644
--- a/std/gif/decode_gif.wuffs
+++ b/std/gif/decode_gif.wuffs
@@ -219,9 +219,9 @@
}
pub func decoder.set_report_metadata!(fourcc: base.u32, report: base.bool) {
- if args.fourcc == 0x4943_4350 { // "ICCP"
+ if args.fourcc == 'ICCP'be {
this.report_metadata_iccp = args.report
- } else if args.fourcc == 0x584D_5020 { // "XMP "
+ } else if args.fourcc == 'XMP 'be {
this.report_metadata_xmp = args.report
}
}
@@ -243,7 +243,7 @@
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
if this.metadata_chunk_length_value > 0 {
- if this.metadata_fourcc_value == 0x584D_5020 { // "XMP "
+ if this.metadata_fourcc_value == 'XMP 'be {
// The +1 is because XMP metadata's encoding includes each
// block's leading byte (the block size) as part of the
// metadata passed to the caller.
@@ -502,8 +502,8 @@
c[i] = args.src.read_u8?()
i += 1
}
- if (c[0] <> 0x47) or (c[1] <> 0x49) or (c[2] <> 0x46) or (c[3] <> 0x38) or
- ((c[4] <> 0x37) and (c[4] <> 0x39)) or (c[5] <> 0x61) {
+ if (c[0] <> 'G') or (c[1] <> 'I') or (c[2] <> 'F') or (c[3] <> '8') or
+ ((c[4] <> '7') and (c[4] <> '9')) or (c[5] <> 'a') {
return "#bad header"
}
}
@@ -692,7 +692,7 @@
}
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
args.src.skip32_fast!(actual: 1, worst_case: 1)
- this.metadata_fourcc_value = 0x4943_4350 // "ICCP"
+ this.metadata_fourcc_value = 'ICCP'be
this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
this.call_sequence = 1
return base."@metadata reported"
@@ -712,7 +712,7 @@
} else {
args.src.skip32_fast!(actual: 1, worst_case: 1)
}
- this.metadata_fourcc_value = 0x584D_5020 // "XMP "
+ this.metadata_fourcc_value = 'XMP 'be
this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
this.call_sequence = 1
return base."@metadata reported"
diff --git a/std/json/decode_json.wuffs b/std/json/decode_json.wuffs
index 7748504..9062909 100644
--- a/std/json/decode_json.wuffs
+++ b/std/json/decode_json.wuffs
@@ -361,7 +361,7 @@
continue.string_loop_outer
}
- } else if c == 0x75 { // 0x75 is 'u'.
+ } else if c == 'u' {
// -------- BEGIN backslash-u.
if args.src.available() < 6 {
if args.src.is_closed() {
@@ -437,8 +437,8 @@
uni4_string = args.src.peek_u64le_at(offset: 4) >> 16
// Look for the low surrogate's "\\u".
- if ((0xFF & (uni4_string >> 0)) <> 0x5C) or
- ((0xFF & (uni4_string >> 8)) <> 0x75) {
+ if ((0xFF & (uni4_string >> 0)) <> '\\') or
+ ((0xFF & (uni4_string >> 8)) <> 'u') {
uni4_high_surrogate = 0
uni4_value = 0
uni4_ok = 0
@@ -492,8 +492,8 @@
}
// -------- END backslash-u.
- } else if (c == 0x55) and
- this.quirk_enabled_allow_backslash_capital_u { // 0x55 is 'U'.
+ } else if (c == 'U') and
+ this.quirk_enabled_allow_backslash_capital_u {
// -------- BEGIN backslash-capital-u.
if args.src.available() < 10 {
if args.src.is_closed() {
@@ -559,8 +559,8 @@
}
// -------- END backslash-capital-u.
- } else if (c == 0x78) and
- this.quirk_enabled_allow_backslash_x { // 0x78 is 'x'.
+ } else if (c == 'x') and
+ this.quirk_enabled_allow_backslash_x {
// -------- BEGIN backslash-x
if args.src.available() < 4 {
if args.src.is_closed() {
@@ -1030,7 +1030,7 @@
continue.outer
} else if class == 0x09 { // 0x09 is CLASS_FALSE.
- match = args.src.match7(a: 0x6573_6C61_6605) // 5 bytes "false".
+ match = args.src.match7(a: '\x05false'le)
if match == 0 {
args.dst.write_fast_token!(
value_major: 0,
@@ -1048,7 +1048,7 @@
}
} else if class == 0x0A { // 0x0A is CLASS_TRUE.
- match = args.src.match7(a: 0x65_7572_7404) // 4 bytes "true".
+ match = args.src.match7(a: '\x04true'le)
if match == 0 {
args.dst.write_fast_token!(
value_major: 0,
@@ -1066,7 +1066,7 @@
}
} else if class == 0x0B { // 0x0B is CLASS_NULL_NAN_INF.
- match = args.src.match7(a: 0x6C_6C75_6E04) // 4 bytes "null".
+ match = args.src.match7(a: '\x04null'le)
if match == 0 {
args.dst.write_fast_token!(
value_major: 0,
@@ -1131,7 +1131,7 @@
c = args.src.peek_u8()
// Scan the optional minus sign.
- if c <> 0x2D { // 0x2D is '-'.
+ if c <> '-' {
assert args.src.available() > 0
assert n <= 1
} else {
@@ -1153,7 +1153,7 @@
}
// Scan the opening digits.
- if c == 0x30 { // 0x30 is '0'.
+ if c == '0' {
n += 1
args.src.skip32_fast!(actual: 1, worst_case: 1)
assert n <= 99
@@ -1175,7 +1175,7 @@
c = args.src.peek_u8()
// Scan the optional fraction.
- if c <> 0x2E { // 0x2E is '.'.
+ if c <> '.' {
assert args.src.available() > 0
assert n <= 99
} else {
@@ -1206,7 +1206,7 @@
}
// Scan the optional 'E' or 'e'.
- if (c <> 0x45) and (c <> 0x65) { // 0x45 and 0x65 are 'E' and 'e'.
+ if (c <> 'E') and (c <> 'e') {
break.goto_done
}
if n >= 99 {
@@ -1229,7 +1229,7 @@
c = args.src.peek_u8()
// Scan the optional '+' or '-'.
- if (c <> 0x2B) and (c <> 0x2D) { // 0x2B and 0x2D are '+' and '-'.
+ if (c <> '+') and (c <> '-') {
assert n <= 99
} else {
if n >= 99 {
@@ -1354,7 +1354,7 @@
}
c2 = args.src.peek_u16le()
- if (c2 == 0x2A2F) and this.quirk_enabled_allow_comment_block {
+ if (c2 == '/*'le) and this.quirk_enabled_allow_comment_block {
args.src.skip32_fast!(actual: 2, worst_case: 2)
length = 2
@@ -1386,7 +1386,7 @@
}
c2 = args.src.peek_u16le()
- if c2 == 0x2F2A { // 0x2F2A is "*/" little-endian.
+ if c2 == '*/'le {
args.src.skip32_fast!(actual: 2, worst_case: 2)
args.dst.write_fast_token!(
value_major: 0,
@@ -1411,7 +1411,7 @@
}
} endwhile.comment_block
- } else if (c2 == 0x2F2F) and this.quirk_enabled_allow_comment_line {
+ } else if (c2 == '//'le) and this.quirk_enabled_allow_comment_line {
args.src.skip32_fast!(actual: 2, worst_case: 2)
length = 2
@@ -1443,7 +1443,7 @@
}
c = args.src.peek_u8()
- if c == 0x0A { // 0x0A is '\n'.
+ if c == '\n' {
args.src.skip32_fast!(actual: 1, worst_case: 1)
args.dst.write_fast_token!(
value_major: 0,
@@ -1492,9 +1492,9 @@
// Bitwise or'ing with 0x20 converts upper case ASCII to lower case.
c4 = args.src.peek_u24le_as_u32()
- if (c4 | 0x20_2020) == 0x66_6E69 {
+ if (c4 | 0x20_2020) == 'inf'le {
if args.src.available() > 7 {
- if (args.src.peek_u64le() | 0x2020_2020_2020_2020) == 0x7974_696E_6966_6E69 {
+ if (args.src.peek_u64le() | 0x2020_2020_2020_2020) == 'infinity'le {
args.dst.write_fast_token!(
value_major: 0,
value_minor: 0xA0_0020,
@@ -1515,7 +1515,7 @@
args.src.skip32_fast!(actual: 3, worst_case: 3)
return ok
- } else if (c4 | 0x20_2020) == 0x6E_616E {
+ } else if (c4 | 0x20_2020) == 'nan'le {
args.dst.write_fast_token!(
value_major: 0,
value_minor: 0xA0_0080,
@@ -1523,9 +1523,9 @@
length: 3)
args.src.skip32_fast!(actual: 3, worst_case: 3)
return ok
- } else if (c4 & 0xFF) == 0x2B { // 0x2B is '+'.
+ } else if (c4 & 0xFF) == '+' {
neg = 0
- } else if (c4 & 0xFF) == 0x2D { // 0x2D is '-'.
+ } else if (c4 & 0xFF) == '-' {
neg = 1
} else {
return "#bad input"
@@ -1540,9 +1540,9 @@
}
c4 = args.src.peek_u32le() >> 8
- if (c4 | 0x20_2020) == 0x66_6E69 {
+ if (c4 | 0x20_2020) == 'inf'le {
if args.src.available() > 8 {
- if (args.src.peek_u64le_at(offset: 1) | 0x2020_2020_2020_2020) == 0x7974_696E_6966_6E69 {
+ if (args.src.peek_u64le_at(offset: 1) | 0x2020_2020_2020_2020) == 'infinity'le {
args.dst.write_fast_token!(
value_major: 0,
value_minor: 0xA0_0000 | ((0x20 as base.u32) >> neg),
@@ -1563,7 +1563,7 @@
args.src.skip32_fast!(actual: 4, worst_case: 4)
return ok
- } else if (c4 | 0x20_2020) == 0x6E_616E {
+ } else if (c4 | 0x20_2020) == 'nan'le {
args.dst.write_fast_token!(
value_major: 0,
value_minor: 0xA0_0000 | ((0x80 as base.u32) >> neg),
@@ -1616,11 +1616,11 @@
}
args.src.skip32_fast!(actual: 1, worst_case: 1)
- if (whitespace_length >= 0xFFFE) or (c == 0x0A) {
+ if (whitespace_length >= 0xFFFE) or (c == '\n') {
args.dst.write_fast_token!(
value_major: 0, value_minor: 0, link: 0x0, length: whitespace_length + 1)
whitespace_length = 0
- if c == 0x0A {
+ if c == '\n' {
break.outer
}
continue.outer