ref: 52eca667bbd1cf5a929d3f2352c3c1ee8e91625d
parent: 68a437bb6d370781e18ad1b794cc34c21dd5b361
author: Ori Bernstein <[email protected]>
date: Mon Dec 25 11:14:38 EST 2017
Formatting as a state machine.
--- a/lib/date/fmt.myr
+++ b/lib/date/fmt.myr
@@ -10,12 +10,7 @@
const __init__ = {
var d : instant
- std.fmtinstall(std.typeof(d), sbfmt, [
- ("D", false),
- ("d", false),
- ("t", false),
- ("f", true),
- ][:])
+ std.fmtinstall(std.typeof(d), sbfmt)
}
/* Always formats : proleptic Gregorian format */
--- a/lib/date/parse.myr
+++ b/lib/date/parse.myr
@@ -38,7 +38,7 @@
const __init__ = {
var fail : parsefail
- std.fmtinstall(std.typeof(fail), failfmt, [][:])
+ std.fmtinstall(std.typeof(fail), failfmt)
}
const strparse = {f, s, tz, replace
--- a/lib/escfmt/eschtml.myr
+++ b/lib/escfmt/eschtml.myr
@@ -8,7 +8,7 @@
const __init__ = {
var s = ("" : eschtml)
- std.fmtinstall(std.typeof(s), htmlfmt, [][:])
+ std.fmtinstall(std.typeof(s), htmlfmt)
}
const html = {s
--- a/lib/escfmt/escre.myr
+++ b/lib/escfmt/escre.myr
@@ -8,7 +8,7 @@
const __init__ = {
var s = ("" : escre)
- std.fmtinstall(std.typeof(s), refmt, [][:])
+ std.fmtinstall(std.typeof(s), refmt)
}
const re = {s
--- a/lib/escfmt/escsh.myr
+++ b/lib/escfmt/escsh.myr
@@ -8,7 +8,7 @@
const __init__ = {
var s = ("" : escsh)
- std.fmtinstall(std.typeof(s), shfmt, [][:])
+ std.fmtinstall(std.typeof(s), shfmt)
}
const sh = {s
--- a/lib/escfmt/escurl.myr
+++ b/lib/escfmt/escurl.myr
@@ -8,7 +8,7 @@
const __init__ = {
var s = ("" : escurl)
- std.fmtinstall(std.typeof(s), urlfmt, [][:])
+ std.fmtinstall(std.typeof(s), urlfmt)
}
const url = {s
--- a/lib/http/client.myr
+++ b/lib/http/client.myr
@@ -196,7 +196,7 @@
var m
m = `Get
- std.fmtinstall(std.typeof(m), fmtmethod, [][:])
+ std.fmtinstall(std.typeof(m), fmtmethod)
}
const readchunkedbody = {s, r
--- a/lib/http/url.myr
+++ b/lib/http/url.myr
@@ -12,9 +12,7 @@
var u : url#
u = u
- std.fmtinstall(std.typeof(u), urlfmt, [
- ("p", false)
- ][:])
+ std.fmtinstall(std.typeof(u), urlfmt)
}
const urlfmt = {sb, ap, opts
--- a/lib/json/fmt.myr
+++ b/lib/json/fmt.myr
@@ -8,7 +8,7 @@
const __init__ = {
var j : elt
- std.fmtinstall(std.typeof(&j), jsonfmt, [][:])
+ std.fmtinstall(std.typeof(&j), jsonfmt)
}
const jsonfmt = {sb, ap, opts
--- a/lib/regex/compile.myr
+++ b/lib/regex/compile.myr
@@ -879,7 +879,7 @@
match std.vanext(ap)
| `Noimpl: std.sbfmt(sb, "no implementation")
| `Incomplete: std.sbfmt(sb, "regex ended before input fully parsed")
- | `Unbalanced c: std.sbfmt(sb, "unbalanced {}", c)
+ | `Unbalanced c:std.sbfmt(sb, "unbalanced {}", c)
| `Emptyparen: std.sbfmt(sb, "empty parentheses")
| `Badrep c: std.sbfmt(sb, "invalid repetition {}", c)
| `Badrange s: std.sbfmt(sb, "invalid range name {}", s)
@@ -899,6 +899,6 @@
const __init__ = {
var e : status
- std.fmtinstall(std.typeof(e), fmtfail, [][:])
+ std.fmtinstall(std.typeof(e), fmtfail)
}
--- a/lib/std/fmt.myr
+++ b/lib/std/fmt.myr
@@ -47,8 +47,7 @@
/* add a formatter function */
const fmtinstall : (ty : byte[:], \
- fn : (sb : strbuf#, ap : valist#, opts : (byte[:],byte[:])[:] -> void), \
- optdesc : (byte[:], bool)[:] \
+ fn : (sb : strbuf#, ap : valist#, opts : (byte[:],byte[:])[:] -> void) \
-> void)
$noret const fatal : (fmt : byte[:], args : ... -> void)
@@ -55,6 +54,12 @@
$noret const fatalv : (fmt : byte[:], ap : valist# -> void)
;;
+type parsestate = union
+ `Copy
+ `ParamOpt
+ `ParamArg
+;;
+
const __init__ = {
fmtmap = mkht()
}
@@ -61,7 +66,6 @@
type fmtdesc = struct
fn : (sb : strbuf#, ap : valist#, opts : (byte[:],byte[:])[:] -> void)
- optdesc : (byte[:], bool)[:]
;;
/* same as 'put', but exits the program after printing */
@@ -81,10 +85,10 @@
var fmtmap : htab(byte[:], fmtdesc)#
-const fmtinstall = {ty, fn, optdesc
+const fmtinstall = {ty, fn
match std.htget(fmtmap, ty)
| `std.Some _: std.fatal("doubly installed format\n")
- | `std.None: htput(fmtmap, ty, [.fn=fn, .optdesc=sldup(optdesc)])
+ | `std.None: htput(fmtmap, ty, [.fn=fn])
;;
}
@@ -157,39 +161,85 @@
}
const sbfmtv = {sb, fmt, ap -> size
- var nfmt, nparams, orig
- var c, params
+ var buf : byte[256], param : (byte[:], byte[:])[8]
+ var state, startp, endp, starta, nbuf
+ var nfmt, nvarargs, nparam
+ var c
- orig = fmt
- nparams = ap.tc.nelt
+ nvarargs = ap.tc.nelt
nfmt = 0
+ startp = 0
+ starta = 0
+ nparam = 0
+ nbuf = 0
+ endp = 0
+ state = `Copy
while fmt.len != 0
(c, fmt) = charstep(fmt)
- match c
- | '{':
+ match (state, c)
+ /* raw bytes */
+ | (`Copy, '{'):
if decode(fmt) == '{'
(c, fmt) = charstep(fmt)
sbputc(sb, '{')
else
- (params, fmt) = getparams(fmt)
- nfmt++
- if nfmt > nparams
- die("too few params for fmt\n")
- ;;
-
- fmtval(sb, vatype(ap), ap, params)
+ state = `ParamOpt
+ nparam = 0
+ startp = 0
+ starta = 0
+ nbuf = 0
;;
- | '}':
+ | (`Copy, '}'):
if decode(fmt) == '}'
sbputc(sb, '}')
;;
- | chr:
+ | (`Copy, chr):
sbputc(sb, chr)
+
+ /* {param */
+ | (`ParamOpt, '='):
+ state = `ParamArg
+ endp = nbuf
+ starta = nbuf
+ | (`ParamOpt, ','):
+ if startp != nbuf
+ param[nparam++] = (buf[startp:nbuf], "")
+ ;;
+ | (`ParamOpt, '}'):
+ state = `Copy
+ if startp != nbuf
+ param[nparam++] = (buf[startp:nbuf], "")
+ ;;
+ fmtval(sb, vatype(ap), ap, param[:nparam])
+ nfmt++
+ | (`ParamOpt, '\\'):
+ (c, fmt) = charstep(fmt)
+ nbuf += std.encode(buf[nbuf:], c)
+ | (`ParamOpt, chr):
+ nbuf += std.encode(buf[nbuf:], chr)
+
+ /* {param=arg} */
+ | (`ParamArg, ','):
+ state = `ParamOpt
+ param[nparam++] = (buf[startp:endp], buf[starta:nbuf])
+ startp = nbuf
+ endp = nbuf
+ | (`ParamArg, '}'):
+ state = `Copy
+ if startp != nbuf
+ param[nparam++] = (buf[startp:endp], buf[starta:nbuf])
+ ;;
+ fmtval(sb, vatype(ap), ap, param[:nparam])
+ nfmt++
+ | (`ParamArg, '\\'):
+ (c, fmt) = charstep(fmt)
+ nbuf += std.encode(buf[nbuf:], c)
+ | (`ParamArg, chr):
+ nbuf += std.encode(buf[nbuf:], chr)
;;
:fmtdone
;;
- if nfmt != nparams
- write(1, orig)
+ if nfmt != nvarargs
die("too many params for fmt\n")
;;
-> sb.len
@@ -196,68 +246,14 @@
}
const fmtval = {sb, ty, ap, params
- var pl
-
match htget(fmtmap, ty)
| `Some f:
- pl = parseparams(params, f.optdesc)
- f.fn(sb, ap, pl)
- std.slfree(pl)
+ f.fn(sb, ap, params)
| `None:
fallbackfmt(sb, params, ty, ap)
;;
}
-const parseparams = {paramstr, optdesc
- var params, opts
- var o, a, ha, gotarg, found
-
- opts = [][:]
- if optdesc.len == 0 && paramstr.len > 0
- std.fatal("invalid format options {}\n")
- ;;
- params = strsplit(paramstr, ",")
- for p : params
- /* parse out the key/value pair */
- match std.strfind(p, "=")
- | `std.Some idx:
- o = p[:idx]
- a = p[idx+1:]
- gotarg = true
- | `std.None:
- o = p
- a = ""
- gotarg = false
- ;;
-
- found = false
- /* verify and add the arg */
- for (opt, hasarg) : optdesc
- if !std.sleq(opt, o)
- continue
- ;;
- found = true
- ha = hasarg
- if ha == gotarg
- std.slpush(&opts, (o, a))
- else
- std.fatal("invalid arg {} for option {}", a, o)
- ;;
- ;;
- if !found
- std.put("options: \n")
- for (opt, hasarg) : optdesc
- std.put("\t'{}', hasarg={}\n", opt, hasarg)
- ;;
- std.put("invalid option '{}' ", o)
- std.die("dying")
- ;;
- ;;
- slfree(params)
- -> opts
-}
-
-
const fallbackfmt = {sb, params, tyenc, ap : valist# -> void
/* value types */
var t_val : bool
@@ -369,7 +365,7 @@
subap = vaenter(ap)
sbputs(sb, "[")
while subap.tc.nelt != 0
- fmtval(sb, vatype(&subap), &subap, "")
+ fmtval(sb, vatype(&subap), &subap, [][:])
if subap.tc.nelt > 0
sbfmt(sb, ", ")
;;
@@ -381,7 +377,7 @@
subap = vaenter(ap)
sbfmt(sb, "(")
for var i = 0; i < subap.tc.nelt; i++
- fmtval(sb, vatype(&subap), &subap, "")
+ fmtval(sb, vatype(&subap), &subap, [][:])
if subap.tc.nelt == 1
sbfmt(sb, ",")
elif i != subap.tc.nelt -1
@@ -396,7 +392,7 @@
for var i = 0; i < subap.tc.nelt; i++
(subname, subenc) = ncpeek(&subap.tc)
sbfmt(sb, ".{}=", subname)
- fmtval(sb, vatype(&subap), &subap, "")
+ fmtval(sb, vatype(&subap), &subap, [][:])
if subap.tc.nelt == 1
sbfmt(sb, ",")
elif i != subap.tc.nelt -1
@@ -420,7 +416,7 @@
| `Tynone:
| _:
sbputc(sb, ' ')
- fmtval(sb, subenc, &subap, "")
+ fmtval(sb, subenc, &subap, [][:])
;;
vabytes(ap)
| `Tyname (name, desc):
@@ -431,28 +427,28 @@
}
const fmtslice = {sb, subap, params
- var opts, join, joined
+ var join, joined
- opts = parseparams(params, [
- ("j", true),
- ][:])
join = ", "
joined = false
- for o : opts
- match o
+ for p : params
+ match p
| ("j", j):
joined = true
join = j
- | _: std.die("unreacahable")
+ | (opt, arg):
+ std.write(2, "fmt: \0")
+ std.write(2, opt)
+ std.write(2, "\0arg: ")
+ std.write(2, arg)
+ std.die("unreacahable")
;;
;;
- std.slfree(opts)
-
if !joined
sbputs(sb, "[")
;;
while subap.tc.nelt != 0
- fmtval(sb, vatype(&subap), &subap, "")
+ fmtval(sb, vatype(&subap), &subap, [][:])
if subap.tc.nelt > 0
sbfmt(sb, join)
;;
@@ -462,19 +458,6 @@
;;
}
-const getparams = {fmt
- var i
-
- for i = 0; i < fmt.len; i++
- if fmt[i] == ('}' : byte)
- goto foundparams
- ;;
- ;;
- die("invalid format string")
-:foundparams
- -> (fmt[:i], fmt[i+1:])
-}
-
type intparams = struct
base : size
padto : size
@@ -483,7 +466,6 @@
const intparams = {params
var ip : intparams
- var opts
ip = [
.base = 10,
@@ -491,27 +473,25 @@
.padto = 0
]
- opts = parseparams(params, [
- ("b", true),
- ("x", false),
- ("w", true),
- ("p", true)][:])
- for o : opts
- match o
+ for p : params
+ match p
| ("b", bas): ip.base = getint(bas, "fmt: base must be integer")
| ("x", ""): ip.base = 16
| ("w", wid): ip.padto = getint(wid, "fmt: width must be integer")
| ("p", pad): ip.padfill = decode(pad)
- | _: std.die("unreachable")
+ | (opt, arg):
+ std.write(2, "fmt: ")
+ std.write(2, opt)
+ std.write(2, "arg: ")
+ std.write(2, arg)
+ std.die("\nunreachable\n")
;;
;;
iassert(ip.padto >= 0, "pad must be >= 0")
- std.slfree(opts)
-> ip
}
const strfmt = {sb, str, params
- var opts
var w, p, i, raw, esc
p = ' '
@@ -518,24 +498,17 @@
w = 0
raw = false
esc = false
- opts = parseparams(params, [
- ("w", true),
- ("p", true),
- ("r", false),
- ("e", false),
- ][:])
- for o : opts
- match o
+ for pp : params
+ match pp
| ("w", wid): w = getint(wid, "fmt: width must be integer")
| ("p", pad): p = decode(pad)
| ("r", ""): raw = true
| ("e", ""): esc = true
- | _: std.die("unreachable")
+ | _: std.die("unreachable\n")
;;
;;
iassert(p >= 0, "pad must be >= 0")
- std.slfree(opts)
if raw
for b : str
if esc
--- a/lib/std/fmtfuncs.myr
+++ b/lib/std/fmtfuncs.myr
@@ -17,9 +17,9 @@
bigint = mkbigint(0)
bitset = mkbs()
- fmtinstall(typeof(bigint), bigfmt, [][:])
- fmtinstall(typeof(bitset), bsfmt, [][:])
- fmtinstall(typeof(ipaddr), ipfmt, [][:])
+ fmtinstall(typeof(bigint), bigfmt)
+ fmtinstall(typeof(bitset), bsfmt)
+ fmtinstall(typeof(ipaddr), ipfmt)
bigfree(bigint)
bsfree(bitset)
}
--- a/lib/std/test/fmt.myr
+++ b/lib/std/test/fmt.myr
@@ -109,11 +109,8 @@
x = 0
p = [.x=0, .y=0]
- std.fmtinstall(std.typeof(x), intfmt, [][:])
- std.fmtinstall(std.typeof(p), pairfmt, [
- ("x", true),
- ("y", false)
- ][:])
+ std.fmtinstall(std.typeof(x), intfmt)
+ std.fmtinstall(std.typeof(p), pairfmt)
/* single value */
check("formatted an int: 0", "{}", 0)