<- Back to shtanton's homepage
summaryrefslogtreecommitdiff
path: root/main/subexstate.go
blob: 880be380172b92092f6b2d9919c8be367707f4b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package main

import (
	"strings"
)

type SubexState interface {
	eat(store Store, char rune) []SubexBranch
	accepting(store Store) []string
}

type SubexGroupState struct {
	first, second SubexState
}
func (state SubexGroupState) eat(store Store, char rune) []SubexBranch {
	otherStore := store.clone()
	return append(state.first.eat(store, char), state.second.eat(otherStore, char)...)
}
func (state SubexGroupState) accepting(store Store) []string {
	return append(state.first.accepting(store), state.second.accepting(store)...)
}

type SubexStoreState struct {
	match SubexState
	slot rune
	next SubexState
	toStore string
}
func (state SubexStoreState) eat(store Store, char rune) (nextStates []SubexBranch) {
	acceptedOutputs := state.match.accepting(store)
	for _, acceptedOutput := range acceptedOutputs {
		nextStore := store.withValue(state.slot, state.toStore + acceptedOutput)
		nextStates = append(nextStates, state.next.eat(nextStore.clone(), char)...)
	}
	nextMatchStates := state.match.eat(store.clone(), char)
	for _, matchState := range nextMatchStates {
		nextStates = append(nextStates, SubexBranch {
			state: SubexStoreState {
				match: matchState.state,
				slot: state.slot,
				next: state.next,
				toStore: state.toStore + matchState.output,
			},
			output: "",
			store: store.clone(),
		})
	}
	return nextStates
}
func (state SubexStoreState) accepting(store Store) (outputs []string) {
	acceptedOutputs := state.match.accepting(store)
	for _, acceptedOutput := range acceptedOutputs {
		nextStore := store.withValue(state.slot, state.toStore + acceptedOutput)
		outputs = append(outputs, state.next.accepting(nextStore)...)
	}
	return outputs
}

type SubexOutputState struct {
	content []TransducerOutput
	next SubexState
}
func (state SubexOutputState) build(store Store) string {
	var builder strings.Builder
	for _, part := range state.content {
		builder.WriteString(part.build(store))
	}
	return builder.String()
}
func (state SubexOutputState) eat(store Store, char rune) []SubexBranch {
	content := state.build(store)
	nextStates := state.next.eat(store, char)
	for i := range nextStates {
		nextStates[i].output = content + nextStates[i].output
	}
	return nextStates
}
func (state SubexOutputState) accepting(store Store) []string {
	content := state.build(store)
	outputs := state.next.accepting(store)
	for i := range outputs {
		outputs[i] = content + outputs[i]
	}
	return outputs
}

type SubexNoneState struct {}
func (state SubexNoneState) eat(store Store, char rune) []SubexBranch {
	return nil
}
func (state SubexNoneState) accepting(store Store) []string {
	return []string{""}
}

type SubexCopyRuneState struct {
	rune rune
	next SubexState
}
func (state SubexCopyRuneState) eat(store Store, char rune) []SubexBranch {
	if char == state.rune {
		return []SubexBranch{{
			state: state.next,
			output: string(char),
			store: store,
		}}
	}
	return nil
}
func (state SubexCopyRuneState) accepting(store Store) []string {
	return nil
}

type SubexCopyAnyState struct {
	next SubexState
}
func (state SubexCopyAnyState) eat(store Store, char rune) []SubexBranch {
	return []SubexBranch{{
		state: state.next,
		output: string(char),
		store: store,
	}}
}
func (state SubexCopyAnyState) accepting(store Store) []string {
	return nil
}

type SubexRangeState struct {
	parts map[rune]rune
	next SubexState
}
func (state SubexRangeState) eat(store Store, char rune) []SubexBranch {
	out, exists := state.parts[char]
	if !exists {
		return nil
	} else {
		return []SubexBranch{{
			state: state.next,
			output: string(out),
			store: store,
		}}
	}
}
func (state SubexRangeState) accepting(store Store) []string {
	return nil
}