<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/subex/subexstate.go
diff options
context:
space:
mode:
Diffstat (limited to 'subex/subexstate.go')
-rw-r--r--subex/subexstate.go351
1 files changed, 191 insertions, 160 deletions
diff --git a/subex/subexstate.go b/subex/subexstate.go
index 0b21c93..8f27a10 100644
--- a/subex/subexstate.go
+++ b/subex/subexstate.go
@@ -4,13 +4,24 @@ package subex
// e.g. Combine all of the copy states into a single type that has a filter function
import (
+ "fmt"
"main/walk"
+ "strings"
)
-// A state of execution for the transducer
type SubexState interface {
+}
+
+type SubexEpsilonState interface {
+ SubexState
+ epsilon(aux auxiliaryState) []SubexBranch
+}
+
+// A state of execution for the transducer
+type SubexEatState interface {
+ SubexState
// Eat a Atom and transition to any number of new states
- eat(aux auxiliaryState, char walk.Edible) []SubexBranch
+ eat(aux auxiliaryState, edible walk.Edible) []SubexBranch
// Find accepting states reachable through epsilon transitions and return their outputs
accepting(aux auxiliaryState) []OutputStack
}
@@ -19,13 +30,18 @@ type SubexState interface {
type SubexGroupState struct {
first, second SubexState
}
-func (state SubexGroupState) eat(aux auxiliaryState, char walk.Edible) []SubexBranch {
+func (state SubexGroupState) epsilon(aux auxiliaryState) []SubexBranch {
otherAux := aux.cloneStore()
- return append(state.first.eat(aux, char), state.second.eat(otherAux, char)...)
-}
-func (state SubexGroupState) accepting(aux auxiliaryState) []OutputStack {
- otherAux := aux.cloneStore()
- return append(state.first.accepting(aux), state.second.accepting(otherAux)...)
+ return []SubexBranch {
+ {
+ state: state.first,
+ aux: aux,
+ },
+ {
+ state: state.second,
+ aux: otherAux,
+ },
+ }
}
type SubexCopyState struct {
@@ -39,7 +55,7 @@ func (state SubexCopyState) eat(aux auxiliaryState, edible walk.Edible) []SubexB
}
return []SubexBranch{{
state: state.next,
- aux: aux.topAppend(walk.ValueList{value}),
+ aux: aux.topAppend([]walk.Value{value}),
}}
}
func (state SubexCopyState) accepting(aux auxiliaryState) []OutputStack {
@@ -51,29 +67,32 @@ type SubexCopyRuneState struct {
filter runeFilter
}
func (state SubexCopyRuneState) eat(aux auxiliaryState, edible walk.Edible) []SubexBranch {
- r, isRune := edible.(walk.StringRuneAtom)
- if !isRune || !state.filter.runeFilter(r) {
+ r, isRune := edible.(walk.RuneEdible)
+ if !isRune || !state.filter.runeFilter(rune(r)) {
return nil
}
return []SubexBranch{{
state: state.next,
- aux: aux.topAppend(walk.RuneList{r}),
+ aux: aux.topAppendRune([]rune{rune(r)}),
}}
}
func (state SubexCopyRuneState) accepting(aux auxiliaryState) []OutputStack {
return nil
}
+func (state SubexCopyRuneState) String() string {
+ return fmt.Sprintf("SubexCopyRuneState[%v]", state.filter)
+}
// Just pushes to the OutputStack and hands over to the next state
// Used to capture the output of the state being handed over to
type SubexCaptureBeginState struct {
next SubexState
}
-func (state SubexCaptureBeginState) eat(aux auxiliaryState, char walk.Edible) []SubexBranch {
- return state.next.eat(aux.pushOutput(walk.ValueList{}), char)
-}
-func (state SubexCaptureBeginState) accepting(aux auxiliaryState) []OutputStack {
- return state.next.accepting(aux.pushOutput(walk.ValueList{}))
+func (state SubexCaptureBeginState) epsilon(aux auxiliaryState) []SubexBranch {
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.pushOutput(nil),
+ }}
}
func (state SubexCaptureBeginState) String() string {
return "CaptureBeginState"
@@ -82,24 +101,22 @@ func (state SubexCaptureBeginState) String() string {
type SubexCaptureRunesBeginState struct {
next SubexState
}
-func (state SubexCaptureRunesBeginState) eat(aux auxiliaryState, char walk.Edible) []SubexBranch {
- return state.next.eat(aux.pushOutput(walk.RuneList{}), char)
-}
-func (state SubexCaptureRunesBeginState) accepting(aux auxiliaryState) []OutputStack {
- return state.next.accepting(aux.pushOutput(walk.RuneList{}))
+func (state SubexCaptureRunesBeginState) epsilon(aux auxiliaryState) []SubexBranch {
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.pushOutputRunes(nil),
+ }}
}
// Discard the top of the OutputStack
type SubexDiscardState struct {
next SubexState
}
-func (state SubexDiscardState) eat(aux auxiliaryState, char walk.Edible) []SubexBranch {
- _, newAux := aux.popOutput()
- return state.next.eat(newAux, char)
-}
-func (state SubexDiscardState) accepting(aux auxiliaryState) []OutputStack {
- _, newAux := aux.popOutput()
- return state.next.accepting(newAux)
+func (state SubexDiscardState) epsilon(aux auxiliaryState) []SubexBranch {
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.popDiscardOutput(),
+ }}
}
// Pop the top of the OutputStack which contains the stuff outputted since the start of the store
@@ -108,96 +125,74 @@ type SubexStoreEndState struct {
slot int
next SubexState
}
-func (state SubexStoreEndState) eat(aux auxiliaryState, char walk.Edible) []SubexBranch {
+func (state SubexStoreEndState) epsilon(aux auxiliaryState) []SubexBranch {
toStore, aux := aux.popOutput()
- aux = aux.withValue(state.slot, toStore)
- return state.next.eat(aux, char)
-}
-func (state SubexStoreEndState) accepting(aux auxiliaryState) []OutputStack {
- toStore, aux := aux.popOutput()
- aux = aux.withValue(state.slot, toStore)
- return state.next.accepting(aux)
-}
-
-// A part of an output literal, either an Atom or a slot from which to load
-type OutputContent interface {
- // Given the current store, return the ValueList produced by the TransducerOutput
- buildValues(Store) walk.ValueList
- // Given the current store, return the RuneList produced by the TransducerOutput
- buildRunes(Store) walk.RuneList
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.withValue(state.slot, toStore),
+ }}
}
-// An OutputContent which is just a Value literal
-type OutputValueLiteral struct {
- value walk.Value
-}
-func (replacement OutputValueLiteral) buildValues(store Store) walk.ValueList {
- return walk.ValueList{replacement.value}
+type SubexStoreRunesEndState struct {
+ slot int
+ next SubexState
}
-func (replacement OutputValueLiteral) buildRunes(store Store) walk.RuneList {
- // TODO: serialise to JSON
- panic("Unimplemented!")
+func (state SubexStoreRunesEndState) epsilon(aux auxiliaryState) []SubexBranch {
+ toStore, aux := aux.popOutputRunes()
+ aux.store = aux.store.withRunes(state.slot, toStore)
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux,
+ }}
}
-// An OutputContent which is just a rune literal
-type OutputRuneLiteral struct {
- rune walk.StringRuneAtom
-}
-func (replacement OutputRuneLiteral) buildValues(store Store) walk.ValueList {
- // TODO: Try to deserialise
- panic("Unimplemented!")
+type SubexOutputValueLiteralState struct {
+ literal walk.Scalar
+ next SubexState
}
-func (replacement OutputRuneLiteral) buildRunes(store Store) walk.RuneList {
- return walk.RuneList {replacement.rune}
+func (state SubexOutputValueLiteralState) epsilon(aux auxiliaryState) []SubexBranch {
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.topAppend([]walk.Value {state.literal}),
+ }}
}
-// An OutputContent which is a slot that is loaded from
-type OutputLoad struct {
+type SubexOutputValueLoadState struct {
slot int
+ next SubexState
}
-func (replacement OutputLoad) buildValues(store Store) walk.ValueList {
- values, isValues := store[replacement.slot].(walk.ValueList)
- if !isValues {
- panic("Tried to output non-values list")
- }
- return values
-}
-func (replacement OutputLoad) buildRunes(store Store) walk.RuneList {
- runes, isRunes := store[replacement.slot].(walk.RuneList)
- if !isRunes {
- panic("Tried to output non-runes as runes")
- }
- return runes
+func (state SubexOutputValueLoadState) epsilon(aux auxiliaryState) []SubexBranch {
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.topAppend(aux.store.values[state.slot]),
+ }}
}
-// Don't read in anything, just output the series of data and slots specified
-type SubexOutputState struct {
- content []OutputContent
+type SubexOutputRuneLiteralState struct {
+ literal rune
next SubexState
}
-// Given a store, return what is outputted by an epsilon transition from this state
-// TODO: separate into buildValues and buildRunes
-func (state SubexOutputState) build(store Store) walk.ValueList {
- var result walk.ValueList
- for _, part := range state.content {
- result = append(result, part.buildValues(store)...)
- }
- return result
+func (state SubexOutputRuneLiteralState) epsilon(aux auxiliaryState) []SubexBranch {
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.topAppendRune([]rune {state.literal}),
+ }}
}
-func (state SubexOutputState) eat(aux auxiliaryState, char walk.Edible) []SubexBranch {
- content := state.build(aux.store)
- nextStates := state.next.eat(aux.topAppend(content), char)
- return nextStates
+
+type SubexOutputRuneLoadState struct {
+ slot int
+ next SubexState
}
-func (state SubexOutputState) accepting(aux auxiliaryState) []OutputStack {
- content := state.build(aux.store)
- outputStacks := state.next.accepting(aux.topAppend(content))
- return outputStacks
+func (state SubexOutputRuneLoadState) epsilon(aux auxiliaryState) []SubexBranch {
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.topAppendRune(aux.store.runes[state.slot]),
+ }}
}
// A final state, transitions to nothing but is accepting
type SubexNoneState struct {}
-func (state SubexNoneState) eat(aux auxiliaryState, char walk.Edible) []SubexBranch {
+func (state SubexNoneState) eat(aux auxiliaryState, edible walk.Edible) []SubexBranch {
return nil
}
func (state SubexNoneState) accepting(aux auxiliaryState) []OutputStack {
@@ -206,7 +201,7 @@ func (state SubexNoneState) accepting(aux auxiliaryState) []OutputStack {
// A dead end state, handy for making internals work nicer but technically redundant
type SubexDeadState struct {}
-func (state SubexDeadState) eat(aux auxiliaryState, char walk.Edible) []SubexBranch {
+func (state SubexDeadState) eat(aux auxiliaryState, edible walk.Edible) []SubexBranch {
return nil
}
func (state SubexDeadState) accepting (aux auxiliaryState) []OutputStack {
@@ -239,31 +234,18 @@ func (state SubexDeadState) accepting (aux auxiliaryState) []OutputStack {
type SubexArithmeticEndState struct {
next SubexState
- calculate func(walk.ValueList) (walk.ValueList, error)
-}
-func (state SubexArithmeticEndState) eat(aux auxiliaryState, char walk.Edible) []SubexBranch {
- toCompute, aux := aux.popOutput()
- values, isValues := toCompute.(walk.ValueList)
- if !isValues {
- panic("Tried to do arithmetic on non-values")
- }
- result, err := state.calculate(values)
- if err != nil {
- return nil
- }
- return state.next.eat(aux.topAppend(result), char)
+ calculate func([]walk.Value) ([]walk.Value, error)
}
-func (state SubexArithmeticEndState) accepting(aux auxiliaryState) []OutputStack {
- toCompute, aux := aux.popOutput()
- values, isValues := toCompute.(walk.ValueList)
- if !isValues {
- panic("Tried to do arithmetic on non-values")
- }
+func (state SubexArithmeticEndState) epsilon(aux auxiliaryState) []SubexBranch {
+ values, aux := aux.popOutput()
result, err := state.calculate(values)
if err != nil {
return nil
}
- return state.next.accepting(aux.topAppend(result))
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.topAppend(result),
+ }}
}
type SubexDiscardTerminalState struct {
@@ -286,55 +268,102 @@ func (state SubexDiscardTerminalState) accepting(aux auxiliaryState) []OutputSta
type SubexConstructArrayState struct {
next SubexState
}
-func (state SubexConstructArrayState) eat(aux auxiliaryState, edible walk.Edible) []SubexBranch {
- outputs, aux := aux.popOutput()
- values, isValues := outputs.(walk.ValueList)
- if !isValues {
- panic("Tried to create an array from non-values")
+func (state SubexConstructArrayState) epsilon(aux auxiliaryState) []SubexBranch {
+ values, aux := aux.popOutput()
+ var array walk.ArrayValue
+ if len(values) % 2 != 0 {
+ panic("Tried to construct array with odd length input")
}
- array := walk.ArrayStructure(values)
- return state.next.eat(aux.topAppend(walk.ValueList{array}), edible)
-}
-func (state SubexConstructArrayState) accepting(aux auxiliaryState) []OutputStack {
- outputs, aux := aux.popOutput()
- values, isValues := outputs.(walk.ValueList)
- if !isValues {
- panic("Tried to create an array from non-values")
+ for i := 0; i < len(values); i += 2 {
+ index, isNum := values[i].(walk.NumberValue)
+ if !isNum {
+ panic("Tried to construct array with non-numeric index")
+ }
+ array = append(array, walk.ArrayElement {
+ Index: int(index),
+ Value: values[i + 1],
+ })
}
- array := walk.ArrayStructure(values)
- return state.next.accepting(aux.topAppend(walk.ValueList{array}))
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.topAppend([]walk.Value {array}),
+ }}
}
-type SubexConstructStringState struct {
+type SubexConstructArrayValuesState struct {
+ next SubexState
+}
+func (state SubexConstructArrayValuesState) epsilon(aux auxiliaryState) []SubexBranch {
+ values, aux := aux.popOutput()
+ var array walk.ArrayValue
+ for _, v := range values {
+ array = append(array, walk.ArrayElement {
+ Index: 0,
+ Value: v,
+ })
+ }
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.topAppend([]walk.Value {array}),
+ }}
+}
+
+type SubexConstructMapState struct {
next SubexState
}
-func (state SubexConstructStringState) eat(aux auxiliaryState, edible walk.Edible) []SubexBranch {
- outputs, aux := aux.popOutput()
- runes, isRunes := outputs.(walk.RuneList)
- if !isRunes {
- panic("Tried to create a string from non-runes")
+func (state SubexConstructMapState) epsilon(aux auxiliaryState) []SubexBranch {
+ values, aux := aux.popOutput()
+ var m walk.MapValue
+ if len(values) % 2 != 0 {
+ panic("Tried to construct array with odd length input")
}
- s := walk.StringStructure(runes)
- return state.next.eat(aux.topAppend(walk.ValueList{s}), edible)
-}
-func (state SubexConstructStringState) accepting(aux auxiliaryState) []OutputStack {
- outputs, aux := aux.popOutput()
- runes, isRunes := outputs.(walk.RuneList)
- if !isRunes {
- panic("Tried to create a string from non-runes")
+ for i := 0; i < len(values); i += 2 {
+ key, isNum := values[i].(walk.StringValue)
+ if !isNum {
+ panic("Tried to construct array with non-numeric index")
+ }
+ m = append(m, walk.MapElement {
+ Key: string(key),
+ Value: values[i + 1],
+ })
}
- s := walk.StringStructure(runes)
- return state.next.accepting(aux.topAppend(walk.ValueList{s}))
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.topAppend([]walk.Value {m}),
+ }}
}
-type SubexIncrementNestState struct {
+type SubexConstructStringState struct {
next SubexState
}
-func (state SubexIncrementNestState) eat(aux auxiliaryState, edible walk.Edible) []SubexBranch {
- return state.next.eat(aux.incNest(), edible)
+func (state SubexConstructStringState) construct(runes []rune) []walk.Value {
+ var builder strings.Builder
+ for _, r := range runes {
+ builder.WriteRune(r)
+ }
+ return []walk.Value{walk.StringValue(builder.String())}
+}
+func (state SubexConstructStringState) epsilon(aux auxiliaryState) []SubexBranch {
+ runes, aux := aux.popOutputRunes()
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux.topAppend(state.construct(runes)),
+ }}
+}
+func (state SubexConstructStringState) String() string {
+ return "SubexConstructStringState"
}
-func (state SubexIncrementNestState) accepting(aux auxiliaryState) []OutputStack {
- return state.next.accepting(aux.incNest())
+
+type SubexIncrementNestState struct {
+ keys bool
+ next SubexState
+}
+func (state SubexIncrementNestState) epsilon(aux auxiliaryState) []SubexBranch {
+ aux.nesting = append(aux.nesting, state.keys)
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux,
+ }}
}
func (state SubexIncrementNestState) String() string {
return "IncrementNestState"
@@ -343,9 +372,11 @@ func (state SubexIncrementNestState) String() string {
type SubexDecrementNestState struct {
next SubexState
}
-func (state SubexDecrementNestState) eat(aux auxiliaryState, edible walk.Edible) []SubexBranch {
- return state.next.eat(aux.decNest(), edible)
-}
-func (state SubexDecrementNestState) accepting(aux auxiliaryState) []OutputStack {
- return state.next.accepting(aux.decNest())
+func (state SubexDecrementNestState) epsilon(aux auxiliaryState) []SubexBranch {
+ aux.nesting = aux.nesting[:len(aux.nesting) - 1]
+ // aux.nestingValue will be set in addStates
+ return []SubexBranch {{
+ state: state.next,
+ aux: aux,
+ }}
}