diff options
author | Charlie Stanton <charlie@shtanton.xyz> | 2022-09-21 21:05:34 +0100 |
---|---|---|
committer | Charlie Stanton <charlie@shtanton.xyz> | 2022-09-21 21:05:34 +0100 |
commit | 0a8690993d572a50b95dd4f1c1903ed00ddb9c2b (patch) | |
tree | 2ab207544c88ff19308e22c8b79c3ea349c97faa /main/main.go | |
download | subex-0a8690993d572a50b95dd4f1c1903ed00ddb9c2b.tar |
Initial commit
Parses and executes substitute expressions (subexes)
So far subex has the following operations:
- Concatenation of a and b with ab
- Or with |
- Repeat maximally with *
- Repeat minimally with -
- Copy a specific character 'a'
- Copy any character '.'
- Store text matching a regex into slot 's': `$s(regex)`
- Output text in "" including loading from slots with '$'
Regexes support all the same operations as subexes minus storing and outputting
This first implementation gives very little thought to efficiency
Example:
./main 'according to all known laws of aviation' '$1(.-)$m(( .* )| ).*"$m$1"'
This swaps the first and last words of the input string
Diffstat (limited to 'main/main.go')
-rw-r--r-- | main/main.go | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/main/main.go b/main/main.go new file mode 100644 index 0000000..be43d90 --- /dev/null +++ b/main/main.go @@ -0,0 +1,86 @@ +package main + +import ( + "os" + "fmt" +) + +type TransducerOutput interface { + build(Store) string +} + +type TransducerReplacementRune rune +func (replacement TransducerReplacementRune) build(store Store) string { + return string(replacement) +} + +type TransducerReplacementLoad rune +func (replacement TransducerReplacementLoad) build(store Store) string { + return store[rune(replacement)] +} + +type Store map[rune]string +func (store Store) clone() Store { + newStore := make(Store) + for key, val := range store { + newStore[key] = val + } + return newStore +} + +func compileTransducer(transducerAst SubexAST) SubexState { + return transducerAst.compileWith(SubexNoneState{}) +} + +type SubexBranch struct { + store Store + state SubexState + output string +} +func (pair SubexBranch) eat(char rune) []SubexBranch { + states := pair.state.eat(pair.store, char) + for i := range states { + states[i].output = pair.output + states[i].output + } + return states +} +func (pair SubexBranch) accepting() []string { + return pair.state.accepting(pair.store) +} + +func runTransducer(transducer SubexState, input string) (output string, err bool) { + states := []SubexBranch{{ + state: transducer, + output: "", + store: make(Store), + }} + for _, char := range input { + var newStates []SubexBranch + for _, state := range states { + newStates = append(newStates, state.eat(char)...) + } + states = newStates + } + for _, state := range states { + outputEnds := state.accepting() + for _, outputEnd := range outputEnds { + return state.output + outputEnd, false + } + } + return "", true +} + +func main() { + if len(os.Args) != 3 { + panic("Expected: program [input] [subex]") + } + input := os.Args[1] + program := os.Args[2] + ast := parse(program) + transducer := compileTransducer(ast) + output, err := runTransducer(transducer, input) + if err { + output = input + } + fmt.Println(output) +} |