<- Back to shtanton's homepage
summaryrefslogtreecommitdiff
path: root/main/main.go
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2022-09-21 21:05:34 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2022-09-21 21:05:34 +0100
commit0a8690993d572a50b95dd4f1c1903ed00ddb9c2b (patch)
tree2ab207544c88ff19308e22c8b79c3ea349c97faa /main/main.go
downloadsubex-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.go86
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)
+}