Skip to content

Commit

Permalink
implement format strings with string interpolations (ref: #2)
Browse files Browse the repository at this point in the history
  • Loading branch information
itchyny committed Jan 5, 2020
1 parent 5cf8228 commit cfc6c53
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 18 deletions.
39 changes: 39 additions & 0 deletions cli/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3207,6 +3207,13 @@
expected: |
"{\"a\":42}"
- name: format strings @json with string interpolation
args:
- '@json "0\(.)1\(. + .)2\([2])3"'
input: '[1]'
expected: |
"0[1]1[1,1]2[2]3"
- name: format strings @html
args:
- '@html'
Expand All @@ -3215,6 +3222,14 @@
expected: |
"{"foo":"<div>&'\\"</div>"}"
- name: format strings @html with string interpolation
args:
- '@html "x\(.)x\(.+.)x"'
input: |
["<>"]
expected: |
"x[&quot;&lt;&gt;&quot;]x[&quot;&lt;&gt;&quot;,&quot;&lt;&gt;&quot;]x"
- name: format strings @csv
args:
- '@csv'
Expand All @@ -3223,6 +3238,14 @@
expected: |
"1,\"foo\",,\"foo,\n\"\"bar\"\"\tbaz\""
- name: format strings @csv with string interpolation
args:
- '@csv "\(.),\(. + .)"'
input: |
[1, "foo", null, 2]
expected: |
"1,\"foo\",,2,1,\"foo\",,2,1,\"foo\",,2"
- name: format strings @csv error
args:
- '@csv'
Expand All @@ -3239,6 +3262,14 @@
expected: |
"1\tfoo\t\tfoo,\\n\"bar\"\\tba\\\\z"
- name: format strings @csv with string interpolation
args:
- '@tsv "\(.),\(. + .)"'
input: |
[1, "foo", null, 2]
expected: |
"1\tfoo\t\t2,1\tfoo\t\t2\t1\tfoo\t\t2"
- name: format strings @tsv error
args:
- '@tsv'
Expand All @@ -3255,6 +3286,14 @@
expected: |
"eyJmb28iOiJiYXIifQ=="
- name: format strings @base64 with string interpolation
args:
- '@base64 "\(.),\(. + .),\(. + . + .)"'
input: |
[1,2]
expected: |
"WzEsMl0=,WzEsMiwxLDJd,WzEsMiwxLDIsMSwyXQ=="
- name: format strings @base64d
args:
- -R
Expand Down
48 changes: 31 additions & 17 deletions compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ func (c *compiler) compileTerm(e *Term) (err error) {
} else if e.Unary != nil {
return c.compileUnary(e.Unary)
} else if e.Format != "" {
return c.compileFormat(e.Format)
return c.compileFormat(e.Format, e.FormatStr)
} else if e.Str != "" {
return c.compileString(e.Str)
} else if e.RawStr != "" {
Expand Down Expand Up @@ -710,7 +710,7 @@ func (c *compiler) compileIndex(e *Term, x *Index) error {
return c.compileCall("_index", []*Query{e.toQuery(), (&Term{RawStr: x.Name}).toQuery()})
}
if x.Str != "" {
q, err := c.stringToQuery(x.Str)
q, err := c.stringToQuery(x.Str, nil)
if err != nil {
return err
}
Expand Down Expand Up @@ -902,24 +902,38 @@ func (c *compiler) compileUnary(e *Unary) error {
}
}

func (c *compiler) compileFormat(fmt string) error {
func (c *compiler) compileFormat(fmt, str string) error {
if f := formatToFunc(fmt); f != nil {
if str == "" {
return c.compileFunc(f)
}
q, err := c.stringToQuery(str, f)
if err != nil {
return err
}
return c.compileQuery(q)
}
return &formatNotFoundError{fmt}
}

func formatToFunc(fmt string) *Func {
switch fmt {
case "@text":
return c.compileFunc(&Func{Name: "tostring"})
return &Func{Name: "tostring"}
case "@json":
return c.compileFunc(&Func{Name: "tojson"})
return &Func{Name: "tojson"}
case "@html":
return c.compileFunc(&Func{Name: "_tohtml"})
return &Func{Name: "_tohtml"}
case "@csv":
return c.compileFunc(&Func{Name: "_tocsv"})
return &Func{Name: "_tocsv"}
case "@tsv":
return c.compileFunc(&Func{Name: "_totsv"})
return &Func{Name: "_totsv"}
case "@base64":
return c.compileFunc(&Func{Name: "_tobase64"})
return &Func{Name: "_tobase64"}
case "@base64d":
return c.compileFunc(&Func{Name: "_tobase64d"})
return &Func{Name: "_tobase64d"}
default:
return &formatNotFoundError{fmt}
return nil
}
}

Expand All @@ -931,14 +945,17 @@ func (c *compiler) compileString(s string) error {
return nil
}
}
q, err := c.stringToQuery(s)
q, err := c.stringToQuery(s, nil)
if err != nil {
return err
}
return c.compileQuery(q)
}

func (c *compiler) stringToQuery(s string) (*Query, error) {
func (c *compiler) stringToQuery(s string, f *Func) (*Query, error) {
if f == nil {
f = &Func{Name: "tostring"}
}
// ref: strconv.Unquote
x := s[1 : len(s)-1]
var runeTmp [utf8.UTFMax]byte
Expand Down Expand Up @@ -975,10 +992,7 @@ func (c *compiler) stringToQuery(s string) (*Query, error) {
xs = append(xs, (&Term{RawStr: string(buf)}).toFilter())
buf = buf[:0]
}
q.Commas = append(
q.Commas,
(&Term{Func: &Func{Name: "tostring"}}).toQuery().Commas...,
)
q.Commas = append(q.Commas, (&Term{Func: f}).toQuery().Commas...)
name := fmt.Sprintf("$%%%d", cnt)
es = append(es, &Expr{
Logic: (&Term{Query: q}).toLogic(),
Expand Down
3 changes: 2 additions & 1 deletion query.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,8 @@ type Term struct {
Array *Array `| @@`
Number string `| @Number`
Unary *Unary `| @@`
Format string `| @Format`
Format string `| ( @Format`
FormatStr string ` @String? )`
Str string `| @String`
RawStr string `| @" "` // never matches, used in compiler
Null bool `| @"null"`
Expand Down

0 comments on commit cfc6c53

Please sign in to comment.