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 {} | 
