<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--subex/main.go6
-rw-r--r--subex/subexstate.go43
-rw-r--r--walk/walk.go91
3 files changed, 109 insertions, 31 deletions
diff --git a/subex/main.go b/subex/main.go
index 593dbbd..2a5f5ad 100644
--- a/subex/main.go
+++ b/subex/main.go
@@ -118,7 +118,11 @@ func Main() {
return
}
- valueOut := walk.MemoryCompound(output)
+ valueOut, error := walk.MemoryCompound(output)
+ if error != nil {
+ fmt.Println(error.Error())
+ return
+ }
for _, value := range valueOut {
fmt.Println(value)
}
diff --git a/subex/subexstate.go b/subex/subexstate.go
index 62e9d1a..855d44a 100644
--- a/subex/subexstate.go
+++ b/subex/subexstate.go
@@ -2,6 +2,8 @@ package subex
import (
"main/walk"
+ "strconv"
+ "errors"
)
// A state of execution for the transducer
@@ -236,41 +238,54 @@ func (state SubexRangeState) accepting(store Store) [][]walk.Atom {
return nil
}
-func sumValues(values []walk.Atom) walk.ValueNumber {
+func sumValues(atoms []walk.Atom) (walk.ValueNumber, error) {
var sum float64 = 0
+ values, err := walk.MemoryCompound(atoms)
+ if err != nil {
+ return 0, err
+ }
for _, value := range values {
switch v := value.(type) {
+ case walk.ValueNull:
case walk.ValueBool:
if (bool(v)) {
sum += 1
}
case walk.ValueNumber:
sum += float64(v)
- case rune:
- if '0' <= v && v <= '9' {
- sum += float64(v - '0')
+ case walk.ValueString:
+ num, err := strconv.ParseFloat(string(v), 64)
+ if err == nil {
+ sum += num
+ } else {
+ return 0, errors.New("Tried to sum non-castable string")
}
default:
+ return 0, errors.New("Tried to sum non-number")
}
}
- return walk.ValueNumber(sum)
+ return walk.ValueNumber(sum), nil
}
// Run the inputState machine and sum any values output, output the sum
-// Cast non numbers into numbers, ignore anything uncastable
+// Cast non numbers into numbers, branch dies if it is not castable
type SubexSumState struct {
inputState SubexState
next SubexState
- sum walk.ValueNumber
+ acc []walk.Atom
}
func (state SubexSumState) child() SubexState {
return state.inputState
}
func (state SubexSumState) nextAcc(output []walk.Atom) interface{} {
- return sumValues(append(output, state.sum))
+ return walk.ConcatData(state.acc, output)
}
func (state SubexSumState) feedNext(acc interface{}, store Store, char walk.Atom) []SubexBranch {
- total := acc.(walk.ValueNumber)
+ childOutput := acc.([]walk.Atom)
+ total, err := sumValues(childOutput)
+ if err != nil {
+ return nil
+ }
output := []walk.Atom{total}
nextStates := state.next.eat(store.clone(), char)
for i := range nextStates {
@@ -279,7 +294,11 @@ func (state SubexSumState) feedNext(acc interface{}, store Store, char walk.Atom
return nextStates
}
func (state SubexSumState) acceptNext(acc interface{}, store Store) [][]walk.Atom {
- total := acc.(walk.ValueNumber)
+ childOutput := acc.([]walk.Atom)
+ total, err := sumValues(childOutput)
+ if err != nil {
+ return nil
+ }
output := []walk.Atom{total}
outputs := state.next.accepting(store.clone())
for i := range outputs {
@@ -288,11 +307,11 @@ func (state SubexSumState) acceptNext(acc interface{}, store Store) [][]walk.Ato
return outputs
}
func (state SubexSumState) nextParent(child SubexState, acc interface{}) SubexState {
- sum := acc.(walk.ValueNumber)
+ childOutput := acc.([]walk.Atom)
return &SubexSumState {
inputState: child,
next: state.next,
- sum: sum,
+ acc: childOutput,
}
}
func (state SubexSumState) eat(store Store, char walk.Atom) (nextStates []SubexBranch) {
diff --git a/walk/walk.go b/walk/walk.go
index 4da8040..36e9805 100644
--- a/walk/walk.go
+++ b/walk/walk.go
@@ -390,41 +390,92 @@ func Atomise(in <-chan WalkValue) <-chan Atom {
return out
}
-func Compound(in <-chan Atom) <-chan WalkValue {
- out := make(chan WalkValue)
- go func(out chan<- WalkValue, in <-chan Atom) {
- for {
+func MemoryAtomise(in []WalkValue) (out []Atom) {
+ inChan := make(chan WalkValue)
+ go func(in []WalkValue, out chan<- WalkValue) {
+ for _, value := range in {
+ out<-value
+ }
+ close(out)
+ }(in, inChan)
+ outChan := Atomise(inChan)
+ for atom := range outChan {
+ out = append(out, atom)
+ }
+ return out
+}
+
+type CompoundError int
+
+const (
+ CompoundRuneOutsideString CompoundError = iota
+ CompoundEndStringOutsideString
+ CompoundUnknownAtom
+ CompoundMissingEnd
+ CompoundInvalidStringAtom
+)
+
+func (err CompoundError) Error() string {
+ switch err {
+ case CompoundRuneOutsideString:
+ return "Compound Error: Rune Outside String"
+ case CompoundEndStringOutsideString:
+ return "Compound Error: End String Outside String"
+ case CompoundUnknownAtom:
+ return "Compound Error: Unknown Atom"
+ case CompoundMissingEnd:
+ return "Compound Error: Missing End"
+ case CompoundInvalidStringAtom:
+ return "Compound Error: Invalid String Atom"
+ default:
+ panic("Invalid CompoundError")
+ }
+}
+
+type CompoundResult struct {
+ value WalkValue
+ error error
+}
+
+func Compound(in <-chan Atom) <-chan CompoundResult {
+ out := make(chan CompoundResult)
+ go func(out chan<- CompoundResult, in <-chan Atom) {
+ outer: for {
atom, hasAtom := <-in
if !hasAtom {
break
}
switch v := atom.(type) {
case TerminalValue:
- out<-v
+ out<-CompoundResult{v, nil}
continue
case ValueNull:
- out<-v
+ out<-CompoundResult{v, nil}
continue
case ValueBool:
- out<-v
+ out<-CompoundResult{v, nil}
continue
case ValueNumber:
- out<-v
+ out<-CompoundResult{v, nil}
continue
case rune:
- panic("Error! Rune output by subex but not in a string")
+ out<-CompoundResult{nil, CompoundRuneOutsideString}
+ break outer
case EndString:
- panic("Error! subex output an EndString before BeginString")
+ out<-CompoundResult{nil, CompoundEndStringOutsideString}
+ break outer
case StartString:
default:
- panic("Unknown atom type")
+ out<-CompoundResult{nil, CompoundUnknownAtom}
+ break outer
}
// Handle string start
var builder strings.Builder
loop: for {
atom, hasAtom := <-in
if !hasAtom {
- panic("Missing EndString")
+ out<-CompoundResult{nil, CompoundMissingEnd}
+ break outer
}
switch v := atom.(type) {
case EndString:
@@ -432,17 +483,18 @@ func Compound(in <-chan Atom) <-chan WalkValue {
case rune:
builder.WriteRune(v)
default:
- panic("Invalid atom in string")
+ out<-CompoundResult{nil, CompoundInvalidStringAtom}
+ break outer
}
}
- out<-ValueString(builder.String())
+ out<-CompoundResult{ValueString(builder.String()), nil}
}
close(out)
}(out, in)
return out
}
-func MemoryCompound(in []Atom) (out []WalkValue) {
+func MemoryCompound(in []Atom) (out []WalkValue, err error) {
inChan := make(chan Atom)
go func(in []Atom, out chan<- Atom) {
for _, atom := range in {
@@ -451,8 +503,11 @@ func MemoryCompound(in []Atom) (out []WalkValue) {
close(out)
}(in, inChan)
outChan := Compound(inChan)
- for value := range outChan {
- out = append(out, value)
+ for result := range outChan {
+ if result.error != nil {
+ return out, result.error
+ }
+ out = append(out, result.value)
}
- return out
+ return out, nil
} \ No newline at end of file