diff options
Diffstat (limited to 'subex/subexast.go')
-rw-r--r-- | subex/subexast.go | 311 |
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 {} |