<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/subex/subexast.go
diff options
context:
space:
mode:
Diffstat (limited to 'subex/subexast.go')
-rw-r--r--subex/subexast.go311
1 files changed, 234 insertions, 77 deletions
diff --git a/subex/subexast.go b/subex/subexast.go
index 655a783..89949ba 100644
--- a/subex/subexast.go
+++ b/subex/subexast.go
@@ -32,20 +32,60 @@ type SubexASTStoreValues struct {
Slot rune
}
func (ast SubexASTStoreValues) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState {
+ if inType != ValueType {
+ panic("Invalid inType storing to value slot")
+ }
id := slotMap.getId(ast.Slot)
- newNext := ast.Match.compileWith(&SubexStoreEndState {
+ var endState SubexState = &SubexStoreEndState {
slot: id,
next: next,
- }, slotMap, inType, ValueType)
+ }
+ switch ast.Slot {
+ case '+':
+ endState = &SubexCaptureBeginState {
+ next: ast.Match.compileWith(&SubexArithmeticEndState {
+ calculate: arithmeticSum,
+ next: endState,
+ }, slotMap, inType, outType),
+ }
+ case '*':
+ endState = &SubexCaptureBeginState {
+ next: ast.Match.compileWith(&SubexArithmeticEndState {
+ calculate: arithmeticProduct,
+ next: endState,
+ }, slotMap, inType, outType),
+ }
+ default:
+ endState = ast.Match.compileWith(endState, slotMap, inType, outType)
+ }
return &SubexCaptureBeginState {
- next: newNext,
+ next: endState,
}
}
func (ast SubexASTStoreValues) String() string {
return fmt.Sprintf("$%c(%v)", ast.Slot, ast.Match)
}
+type SubexASTAppendStoreValues struct {
+ Match SubexAST
+ Slot rune
+}
+func (ast SubexASTAppendStoreValues) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState {
+ id := slotMap.getId(ast.Slot)
+ newNext := ast.Match.compileWith(&SubexStoreEndState {
+ slot: id,
+ next: next,
+ }, slotMap, inType, ValueType)
+
+ return &SubexOutputValueLoadState {
+ slot: id,
+ next: &SubexCaptureBeginState {
+ next: newNext,
+ },
+ }
+}
+
type SubexASTStoreRunes struct {
Match SubexAST
Slot rune
@@ -66,6 +106,25 @@ func (ast SubexASTStoreRunes) String() string {
}
// Try to run the first subex, if it fails then backtrack and use the second
+type SubexASTAppendStoreRunes struct {
+ Match SubexAST
+ Slot rune
+}
+func (ast SubexASTAppendStoreRunes) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState {
+ id := slotMap.getId(ast.Slot)
+ newNext := ast.Match.compileWith(&SubexStoreEndState {
+ slot: id,
+ next: next,
+ }, slotMap, inType, RuneType)
+
+ return &SubexOutputRuneLoadState {
+ slot: id,
+ next: &SubexCaptureBeginState {
+ next: newNext,
+ },
+ }
+}
+
type SubexASTOr struct {
First, Second SubexAST
}
@@ -238,6 +297,158 @@ func (ast SubexASTCopyNumber) String() string {
return "%"
}
+type SubexASTNumberFilter interface {
+ compile() numberFilter
+ computable() bool
+ compute() float64
+}
+
+type SubexASTNumberFilterLiteral struct {
+ value float64
+}
+func (ast SubexASTNumberFilterLiteral) compile() numberFilter {
+ return equalNumberFilter {ast.value}
+}
+func (ast SubexASTNumberFilterLiteral) computable() bool {
+ return true
+}
+func (ast SubexASTNumberFilterLiteral) compute() float64 {
+ return ast.value
+}
+
+type NumberSubset int
+const (
+ NumberSubsetReal NumberSubset = iota
+ NumberSubsetInteger
+ NumberSubsetPositiveInteger
+ NumberSubsetZeroToOne
+ NumberSubsetPositiveReal
+ NumberSubsetNonNegativeReal
+)
+
+type SubexASTNumberFilterSubset struct {
+ subset NumberSubset
+}
+func (ast SubexASTNumberFilterSubset) compile() numberFilter {
+ switch ast.subset {
+ case NumberSubsetReal:
+ return anyNumberFilter{}
+ case NumberSubsetInteger:
+ return divisibleNumberFilter {
+ divisor: 1.0,
+ target: 0.0,
+ }
+ case NumberSubsetPositiveInteger:
+ return andNumberFilter {
+ lhs: divisibleNumberFilter {
+ divisor: 1.0,
+ target: 0.0,
+ },
+ rhs: greaterThanNumberFilter {0.0},
+ }
+ case NumberSubsetZeroToOne:
+ return andNumberFilter {
+ lhs: notNumberFilter {
+ lessThanNumberFilter {0},
+ },
+ rhs: notNumberFilter {
+ greaterThanNumberFilter {1},
+ },
+ }
+ case NumberSubsetPositiveReal:
+ return greaterThanNumberFilter {0}
+ case NumberSubsetNonNegativeReal:
+ return notNumberFilter {
+ lessThanNumberFilter {0},
+ }
+ default:
+ panic("Invalid NumberSubset")
+ }
+}
+func (ast SubexASTNumberFilterSubset) computable() bool {
+ return false
+}
+func (ast SubexASTNumberFilterSubset) compute() float64 {
+ panic("Tried to compute uncomputable")
+}
+
+type SubexASTNumberFilterCount struct {
+ count int
+}
+func (ast SubexASTNumberFilterCount) compile() numberFilter {
+ return andNumberFilter {
+ lhs: andNumberFilter {
+ lhs: notNumberFilter {
+ lessThanNumberFilter {0.0},
+ },
+ rhs: lessThanNumberFilter {float64(ast.count)},
+ },
+ rhs: divisibleNumberFilter {
+ divisor: 1.0,
+ target: 0.0,
+ },
+ }
+}
+func (ast SubexASTNumberFilterCount) computable() bool {
+ return false
+}
+func (ast SubexASTNumberFilterCount) compute() float64 {
+ panic("Tried to compute uncomputable")
+}
+
+type SubexASTNumberFilterAdd struct {
+ lhs, rhs SubexASTNumberFilter
+}
+func (ast SubexASTNumberFilterAdd) compile() numberFilter {
+ if ast.lhs.computable() {
+ return ast.rhs.compile().add(ast.lhs.compute())
+ } else {
+ return ast.lhs.compile().add(ast.rhs.compute())
+ }
+}
+func (ast SubexASTNumberFilterAdd) computable() bool {
+ return ast.lhs.computable() && ast.rhs.computable()
+}
+func (ast SubexASTNumberFilterAdd) compute() float64 {
+ return ast.lhs.compute() + ast.rhs.compute()
+}
+func (ast SubexASTNumberFilterAdd) String() string {
+ return fmt.Sprintf("(%v + %v)", ast.lhs, ast.rhs)
+}
+
+type SubexASTNumberFilterMultiply struct {
+ lhs, rhs SubexASTNumberFilter
+}
+func (ast SubexASTNumberFilterMultiply) compile() numberFilter {
+ if ast.lhs.computable() {
+ return ast.rhs.compile().multiply(ast.lhs.compute())
+ } else {
+ return ast.lhs.compile().multiply(ast.rhs.compute())
+ }
+}
+func (ast SubexASTNumberFilterMultiply) computable() bool {
+ return ast.lhs.computable() && ast.rhs.computable()
+}
+func (ast SubexASTNumberFilterMultiply) compute() float64 {
+ return ast.lhs.compute() * ast.rhs.compute()
+}
+func (ast SubexASTNumberFilterMultiply) String() string {
+ return fmt.Sprintf("(%v * %v)", ast.lhs, ast.rhs)
+}
+
+type SubexASTCopyNumberFilter struct {
+ filter SubexASTNumberFilter
+}
+func (ast SubexASTCopyNumberFilter) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState {
+ if inType != ValueType || outType != ValueType {
+ panic("Invalid types for SubexASTCopyNumberFilter")
+ }
+ return &SubexCopyNumberState {
+ next: next,
+ filter: ast.filter.compile(),
+ }
+}
+
// Read in a null, bool, number, string or empty array or map and output it unchanged
type SubexASTCopyAnySimpleValue struct {}
func (ast SubexASTCopyAnySimpleValue) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState {
@@ -377,85 +588,31 @@ func (ast SubexASTOutputRuneLoad) compileWith(next SubexState, slotMap *SlotMap,
// return fmt.Sprintf("[abc=xyz]")
// }
-// Run content, if content is a list of booleans, OR them, if all values are castable to numbers, sum them and output the total
-// Reject if neither of these cases match
-type SubexASTSum struct {
- Content SubexAST
-}
-func (ast SubexASTSum) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState {
- if inType != ValueType || outType != ValueType {
- panic("Invalid types for SubexASTSum")
- }
- return &SubexCaptureBeginState {
- next: ast.Content.compileWith(&SubexArithmeticEndState {
- next: next,
- calculate: sumValues,
- }, slotMap, inType, outType),
- }
+type SubexASTBinop struct {
+ op func ([]walk.Value) ([]walk.Value, error)
+ lhs, rhs SubexAST
}
-func (ast SubexASTSum) String() string {
- return fmt.Sprintf("(%v)+", ast.Content)
-}
-
-// Like sum but for AND and product
-type SubexASTProduct struct {
- Content SubexAST
-}
-func (ast SubexASTProduct) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState {
- if inType != ValueType || outType != ValueType {
- panic("Invalid types for SubexASTProduct")
- }
- return &SubexCaptureBeginState {
- next: ast.Content.compileWith(&SubexArithmeticEndState {
- next: next,
- calculate: multiplyValues,
- }, slotMap, inType, outType),
- }
-}
-func (ast SubexASTProduct) String() string {
- return fmt.Sprintf("(%v)*", ast.Content)
-}
-
-// Runs the content Subex, if all outputted atoms can be cast to numbers, outputs them all negated
-// Rejects if this fails
-type SubexASTNegate struct {
- Content SubexAST
-}
-func (ast SubexASTNegate) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState {
- if inType != ValueType || outType != ValueType {
- panic("Invalid types for SubexASTNegate")
- }
- return &SubexCaptureBeginState {
- next: ast.Content.compileWith(&SubexArithmeticEndState {
- next: next,
- calculate: negateValues,
- }, slotMap, inType, outType),
- }
-}
-func (ast SubexASTNegate) String() string {
- return fmt.Sprintf("(%v)-", ast.Content)
-}
-
-// Runs the content Subex and collects the output
-// Maps over the values in the output, casting each to a boolean, notting each and then outputs them
-// Rejects if it cannot cast to boolean
-type SubexASTNot struct {
- Content SubexAST
-}
-func (ast SubexASTNot) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState {
- if inType != ValueType || outType != ValueType {
- panic("Invalid types for SubexASTNot")
+func (ast SubexASTBinop) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState {
+ if outType != ValueType {
+ panic("Invalid types for SubexASTBinop")
}
return &SubexCaptureBeginState {
- next: ast.Content.compileWith(&SubexArithmeticEndState {
- next: next,
- calculate: notValues,
- }, slotMap, ValueType, ValueType),
+ next: ast.lhs.compileWith(
+ ast.rhs.compileWith(
+ &SubexArithmeticEndState {
+ next: next,
+ calculate: ast.op,
+ },
+ slotMap,
+ inType,
+ outType,
+ ),
+ slotMap,
+ inType,
+ outType,
+ ),
}
}
-func (ast SubexASTNot) String() string {
- return fmt.Sprintf("(%v)!", ast.Content)
-}
// Does nothing
type SubexASTEmpty struct {}