stred

Stred: Streaming Tree Editor. Like sed but for JSON
git clone http://shtanton.xyz/git/repo/stred
Log | Files | Refs

commit 184118c1522ee4e78a0588fcac8eb235f512b599
parent 80e7fd0626bfb98f8c1b7f69726d88f8cfa3e4fc
Author: Charlie Stanton <charlie@shtanton.xyz>
Date:   Fri, 21 Apr 2023 11:19:18 +0100

Add :xyz: replacement syntax that removes whatever is before it and inserts whatever is inside it

Diffstat:
Msubex/parse.go | 20+++++++++++++++-----
Msubex/subexast.go | 13+++++++++++++
Msubex/subexstate.go | 13+++++++++++++
3 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/subex/parse.go b/subex/parse.go @@ -166,7 +166,7 @@ func parseReplacement(l RuneReader) (output []OutputContent) { switch r { case eof: panic("Missing closing \"") - case '=', '^': + case '=', '^', ':': break loop case '$': slot := l.Next() @@ -281,7 +281,7 @@ func parseSubex(l RuneReader, minPower int) SubexAST { case '[': rangeParts := parseRangeSubex(l) lhs = SubexASTRange {rangeParts} - case ')', '|', ';', '{', '+', '-', '*', '/', '!', '$': + case ')', '|', ';', '{', '+', '-', '*', '/', '!', '$', ':': l.Rewind() return nil case '=': @@ -358,9 +358,19 @@ func parseSubex(l RuneReader, minPower int) SubexAST { if slot == eof { panic("Missing slot character") } - lhs = SubexASTStore{ - Match: lhs, - Slot: slot, + if slot == '_' { + lhs = SubexASTDiscard {lhs} + } else { + lhs = SubexASTStore{ + Match: lhs, + Slot: slot, + } + } + case r == ':' && minPower <= 4: + replacement := parseReplacement(l) + lhs = SubexASTConcat { + SubexASTDiscard {lhs}, + SubexASTOutput {replacement}, } case r == '|' && minPower <= 8: rhs := parseSubex(l, 9) diff --git a/subex/subexast.go b/subex/subexast.go @@ -359,3 +359,16 @@ func (ast SubexASTEmpty) compileWith(next SubexState) SubexState { func (ast SubexASTEmpty) String() string { return "()" } + +// Discards the output from the content subex +type SubexASTDiscard struct { + Content SubexAST +} +func (ast SubexASTDiscard) compileWith(next SubexState) SubexState { + return &SubexCaptureBeginState { + next: ast.Content.compileWith(&SubexDiscardState {next}), + } +} +func (ast SubexASTDiscard) String() string { + return fmt.Sprintf("(%v)$_", ast.Content) +} diff --git a/subex/subexstate.go b/subex/subexstate.go @@ -36,6 +36,19 @@ func (state SubexCaptureBeginState) accepting(store Store, outputStack OutputSta return state.next.accepting(store, outputStack.push(nil)) } +// Discard the top of the OutputStack +type SubexDiscardState struct { + next SubexState +} +func (state SubexDiscardState) eat(store Store, outputStack OutputStack, char walk.Atom) []SubexBranch { + _, newStack := outputStack.pop() + return state.next.eat(store, newStack, char) +} +func (state SubexDiscardState) accepting(store Store, outputStack OutputStack) []OutputStack { + _, newStack := outputStack.pop() + return state.next.accepting(store, newStack) +} + // Pop the top of the OutputStack which contains the stuff outputted since the start of the store // This outputted data gets stored in a slot type SubexStoreEndState struct {