|
4 | 4 | "errors" |
5 | 5 | "fmt" |
6 | 6 | "sort" |
7 | | - "strings" |
8 | 7 |
|
9 | 8 | "github.com/philandstuff/dhall-golang/v5/term" |
10 | 9 | ) |
@@ -64,6 +63,8 @@ func evalWith(t term.Term, e env) Value { |
64 | 63 | return Text |
65 | 64 | case term.TextShow: |
66 | 65 | return TextShow |
| 66 | + case term.TextReplace: |
| 67 | + return TextReplace |
67 | 68 | case term.List: |
68 | 69 | return List |
69 | 70 | case term.ListBuild: |
@@ -135,41 +136,15 @@ func evalWith(t term.Term, e env) Value { |
135 | 136 | case term.DoubleLit: |
136 | 137 | return DoubleLit(t) |
137 | 138 | case term.TextLit: |
138 | | - var str strings.Builder |
139 | | - var newChunks chunks |
| 139 | + text := &textValBuilder{} |
140 | 140 | for _, chk := range t.Chunks { |
141 | | - str.WriteString(chk.Prefix) |
| 141 | + text.appendStr(chk.Prefix) |
142 | 142 | normExpr := evalWith(chk.Expr, e) |
143 | | - if text, ok := normExpr.(PlainTextLit); ok { |
144 | | - str.WriteString(string(text)) |
145 | | - } else if text, ok := normExpr.(interpolatedText); ok { |
146 | | - // first chunk gets the rest of str |
147 | | - str.WriteString(text.Chunks[0].Prefix) |
148 | | - newChunks = append(newChunks, |
149 | | - chunk{Prefix: str.String(), Expr: text.Chunks[0].Expr}) |
150 | | - newChunks = append(newChunks, |
151 | | - text.Chunks[1:]...) |
152 | | - str.Reset() |
153 | | - str.WriteString(text.Suffix) |
154 | | - } else { |
155 | | - newChunks = append(newChunks, chunk{Prefix: str.String(), Expr: normExpr}) |
156 | | - str.Reset() |
157 | | - } |
158 | | - } |
159 | | - str.WriteString(t.Suffix) |
160 | | - newSuffix := str.String() |
161 | | - |
162 | | - // Special case: "${<expr>}" → <expr> |
163 | | - if len(newChunks) == 1 && newChunks[0].Prefix == "" && newSuffix == "" { |
164 | | - return newChunks[0].Expr |
165 | | - } |
166 | | - |
167 | | - // Special case: no chunks -> PlainTextLit |
168 | | - if len(newChunks) == 0 { |
169 | | - return PlainTextLit(newSuffix) |
| 143 | + text.appendValue(normExpr) |
170 | 144 | } |
| 145 | + text.appendStr(t.Suffix) |
171 | 146 |
|
172 | | - return interpolatedText{Chunks: newChunks, Suffix: newSuffix} |
| 147 | + return text.value() |
173 | 148 | case term.BoolLit: |
174 | 149 | return BoolLit(t) |
175 | 150 | case term.If: |
@@ -615,46 +590,33 @@ func evalWith(t term.Term, e env) Value { |
615 | 590 | case term.With: |
616 | 591 | record := evalWith(t.Record, e) |
617 | 592 | value := evalWith(t.Value, e) |
618 | | - output := record |
619 | | - here := record |
620 | | - var recordLit RecordLit |
621 | | - depth := 0 |
622 | | - for _, component := range t.Path { |
623 | | - var ok bool |
624 | | - recordLit, ok = here.(RecordLit) |
625 | | - if !ok { |
626 | | - break |
627 | | - } |
628 | | - here = recordLit[component] |
629 | | - depth = depth + 1 |
630 | | - } |
631 | | - desugared := desugarWith(here, t.Path[depth:], value) |
632 | | - if depth == 0 { |
633 | | - return desugared |
634 | | - } |
635 | | - recordLit[t.Path[depth-1]] = desugared |
636 | | - return output |
| 593 | + |
| 594 | + return withRule(record, t.Path, value) |
637 | 595 | default: |
638 | 596 | panic(fmt.Sprint("unknown term type", t)) |
639 | 597 | } |
640 | 598 | } |
641 | 599 |
|
642 | | -// desugarWith converts a `r with a.b...c = v` term to the equivalent, |
643 | | -// defined by desugar-with() in the Dhall standard. Note that path |
644 | | -// may be of length 0, in which case value is returned. |
645 | | -func desugarWith(abstractRecord Value, path []string, value Value) Value { |
646 | | - if len(path) == 0 { |
647 | | - return value |
| 600 | +// withRule implements evaluation of `with` expressions. It was too |
| 601 | +// hard to express using for loops, so I finally did actual functional |
| 602 | +// style |
| 603 | +// |
| 604 | +// withRule may modify its parameters, you have been warned |
| 605 | +func withRule(record Value, path []string, value Value) Value { |
| 606 | + recordLit, ok := record.(RecordLit) |
| 607 | + if !ok { |
| 608 | + return with{Record: record, Path: path, Value: value} |
| 609 | + } |
| 610 | + if len(path) == 1 { |
| 611 | + recordLit[path[0]] = value |
| 612 | + return recordLit |
648 | 613 | } |
649 | | - return oper{ |
650 | | - OpCode: term.RightBiasedRecordMergeOp, |
651 | | - L: abstractRecord, |
652 | | - R: RecordLit{path[0]: desugarWith( |
653 | | - field{abstractRecord, path[0]}, |
654 | | - path[1:], |
655 | | - value, |
656 | | - )}, |
| 614 | + var subrecord Value = RecordLit{} |
| 615 | + if recordLit[path[0]] != nil { |
| 616 | + subrecord = recordLit[path[0]] |
657 | 617 | } |
| 618 | + recordLit[path[0]] = withRule(subrecord, path[1:], value) |
| 619 | + return recordLit |
658 | 620 | } |
659 | 621 |
|
660 | 622 | func apply(fn Value, args ...Value) Value { |
|
0 commit comments