Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/subex/parse.go
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2025-10-18 09:41:50 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2025-10-18 09:41:50 +0100
commitb2ce005d227a10a9b8a6f5362c87a0e34ee07acc (patch)
tree454c7dcafc02759b90d083ab1d72c0bbfb65f578 /subex/parse.go
parent62aa738be03845f96c40edde087ea39693b27e4e (diff)
downloadstred-go-b2ce005d227a10a9b8a6f5362c87a0e34ee07acc.tar
Implement numbers properlyHEADnumbersmain
Diffstat (limited to 'subex/parse.go')
-rw-r--r--subex/parse.go203
1 files changed, 140 insertions, 63 deletions
diff --git a/subex/parse.go b/subex/parse.go
index 179cc01..01a747b 100644
--- a/subex/parse.go
+++ b/subex/parse.go
@@ -144,62 +144,128 @@ func parseInt(l RuneReader) (output int) {
return output
}
-func parseNumberFilter(l RuneReader, minPower int) SubexASTNumberFilter {
- var lhs SubexASTNumberFilter
- r := l.Next()
- switch r {
- case eof:
- panic("Missing matching ]")
- case 'c':
- count := parseInt(l)
- lhs = SubexASTNumberFilterCount {count}
- case 'p':
- var subset NumberSubset
- if l.Next() == 'i' {
- subset = NumberSubsetPositiveInteger
- } else {
- subset = NumberSubsetPositiveReal
- l.Rewind()
- }
- lhs = SubexASTNumberFilterSubset {
- subset: subset,
- }
- default:
+// Parse a number literal in a number expression
+func parseNumberLiteral(l RuneReader) NumberExprLiteral {
+ var builder strings.Builder
+ for {
+ r := l.Next()
if !isNumericRune(r) {
- panic("Invalid character in numeric []")
+ l.Rewind()
+ break
}
-
- var builder strings.Builder
builder.WriteRune(r)
- for {
- r := l.Next()
- if !isNumericRune(r) {
- l.Rewind()
- break
- }
- builder.WriteRune(r)
+ }
+ numberString := builder.String()
+ number, err := strconv.ParseFloat(numberString, 64)
+ if err != nil {
+ panic("Invalid number literal")
+ }
+ return NumberExprLiteral {
+ Value: number,
+ }
+}
+
+// Parse a numeric expression
+func parseNumberExpression(l RuneReader, minPower int) NumberExpr {
+ var lhs NumberExpr
+ switch l.Next() {
+ case '(':
+ lhs = parseNumberExpression(l, 0)
+ if !accept(l, ")") {
+ panic("Missing closing )")
}
- numberString := builder.String()
- number, err := strconv.ParseFloat(numberString, 64)
- if err != nil {
- panic("Invalid number literal")
+ case 'n':
+ lhs = NumberExprVariable{}
+ case '-':
+ lhs = NumberExprLiteral{0}
+ l.Rewind()
+ case '!':
+ lhs = NumberExprNot {
+ Right: parseNumberExpression(l, 13),
}
-
- lhs = SubexASTNumberFilterLiteral {number}
+ default:
+ l.Rewind()
+ lhs = parseNumberLiteral(l)
}
loop: for {
r := l.Next()
switch {
- case r == '+' && minPower <= 10:
- lhs = SubexASTNumberFilterAdd {
- lhs: lhs,
- rhs: parseNumberFilter(l, 11),
+ case r == '|' && minPower <= 8:
+ lhs = NumberExprOr {
+ Left: lhs,
+ Right: parseNumberExpression(l, 9),
}
- case r == '*' && minPower <= 20:
- lhs = SubexASTNumberFilterMultiply {
- lhs: lhs,
- rhs: parseNumberFilter(l, 21),
+ case r == '&' && minPower <= 10:
+ lhs = NumberExprAnd {
+ Left: lhs,
+ Right: parseNumberExpression(l, 11),
+ }
+ case r == '<' && minPower <= 20:
+ if accept(l, "=") {
+ lhs = NumberExprAtMost {
+ Left: lhs,
+ Right: parseNumberExpression(l, 21),
+ }
+ } else {
+ lhs = NumberExprLessThan {
+ Left: lhs,
+ Right: parseNumberExpression(l, 21),
+ }
+ }
+ case r == '>' && minPower <= 20:
+ if accept(l, "=") {
+ lhs = NumberExprAtLeast {
+ Left: lhs,
+ Right: parseNumberExpression(l, 21),
+ }
+ } else {
+ lhs = NumberExprGreaterThan {
+ Left: lhs,
+ Right: parseNumberExpression(l, 21),
+ }
+ }
+ case r == '=' && minPower <= 20:
+ lhs = NumberExprEqual {
+ Left: lhs,
+ Right: parseNumberExpression(l, 21),
+ }
+ case r == '~' && minPower <= 20:
+ lhs = NumberExprNot {
+ Right: NumberExprEqual {
+ Left: lhs,
+ Right: parseNumberExpression(l, 21),
+ },
+ }
+ case r == '+' && minPower <= 30:
+ lhs = NumberExprAdd {
+ Left: lhs,
+ Right: parseNumberExpression(l, 31),
+ }
+ case r == '-' && minPower <= 30:
+ lhs = NumberExprSubtract {
+ Left: lhs,
+ Right: parseNumberExpression(l, 31),
+ }
+ case r == '*' && minPower <= 36:
+ lhs = NumberExprMultiply {
+ Left: lhs,
+ Right: parseNumberExpression(l, 37),
+ }
+ case r == '/' && minPower <= 36:
+ lhs = NumberExprDivide {
+ Left: lhs,
+ Right: parseNumberExpression(l, 37),
+ }
+ case r == '%' && minPower <= 36:
+ lhs = NumberExprMod {
+ Left: lhs,
+ Right: parseNumberExpression(l, 37),
+ }
+ case r == '^' && minPower <= 40:
+ lhs = NumberExprExponent {
+ Left: lhs,
+ Right: parseNumberExpression(l, 41),
}
default:
l.Rewind()
@@ -210,6 +276,34 @@ func parseNumberFilter(l RuneReader, minPower int) SubexASTNumberFilter {
return lhs
}
+// Having just read a [ in a value subex, parse the number mapping contents up
+// to but not including the closing ]
+func parseNumberMapping(l RuneReader) SubexAST {
+ numRange := parseNumberExpression(l, 0)
+ var numReplace []NumberExpr
+ if accept(l, ":") {
+ if !accept(l, "]") {
+ for {
+ numReplace = append(
+ numReplace,
+ parseNumberExpression(l, 0),
+ )
+ if !accept(l, ",") {
+ break
+ }
+ }
+ } else {
+ l.Rewind()
+ }
+ } else {
+ numReplace = []NumberExpr{NumberExprVariable{}}
+ }
+ return SubexASTNumberMapping {
+ Range: numRange,
+ Replace: numReplace,
+ }
+}
+
// Having just read {, read in and parse the range contents
func parseRepeatRange(l RuneReader) (output []ConvexRange) {
loop: for {
@@ -717,9 +811,7 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType
case '[':
switch inType {
case ValueType:
- lhs = SubexASTCopyNumberFilter {
- filter: parseNumberFilter(l, 0),
- }
+ lhs = parseNumberMapping(l)
if !accept(l, "]") {
panic("Missing matching ]")
}
@@ -748,21 +840,6 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType
default:
panic("Invalid inType")
}
- case 'r':
- switch inType {
- case ValueType:
- outType = inType
- lhs = SubexASTCopyNumberFilter {
- filter: SubexASTNumberFilterSubset {
- subset: NumberSubsetReal,
- },
- }
- case RuneType:
- outType = inType
- lhs = SubexASTCopyRune {'r'}
- default:
- panic("Invalid inType")
- }
case '?':
outType = inType
lhs = SubexASTCopyBool{}