<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/subex/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'subex/parse.go')
-rw-r--r--subex/parse.go162
1 files changed, 87 insertions, 75 deletions
diff --git a/subex/parse.go b/subex/parse.go
index 35baaa2..fa98ecc 100644
--- a/subex/parse.go
+++ b/subex/parse.go
@@ -6,6 +6,12 @@ import (
"strings"
)
+type Type int
+const (
+ ValueType Type = iota
+ RuneType
+)
+
type RuneReader interface {
Next() rune
Rewind()
@@ -45,24 +51,24 @@ func parseScalarLiteral(l RuneReader) (walk.Scalar, bool) {
if err != nil {
panic("Invalid number literal")
}
- return walk.NumberScalar(number), true
+ return walk.NumberValue(number), true
}
switch r {
case 'n':
if accept(l, "u") && accept(l, "l") && accept(l, "l") {
- return walk.NullScalar{}, true
+ return walk.NullValue{}, true
} else {
panic("Invalid literal")
}
case 't':
if accept(l, "r") && accept(l, "u") && accept(l, "e") {
- return walk.BoolScalar(true), true
+ return walk.BoolValue(true), true
} else {
panic("Invalid literal")
}
case 'f':
if accept(l, "a") && accept(l, "l") && accept(l, "s") && accept(l, "e") {
- return walk.BoolScalar(false), true
+ return walk.BoolValue(false), true
} else {
panic("Invalid literal")
}
@@ -133,34 +139,53 @@ func parseRepeatRange(l RuneReader) (output []ConvexRange) {
return output
}
-// TODO: Consider if it's worth making better use of the go type system to enforce output being all runes or all values
-func parseReplacement(l RuneReader, runic bool) (output []OutputContentAST) {
+func parseValueReplacement(l RuneReader) (output []OutputValueAST) {
// TODO escaping
// TODO add arrays, maps and strings
loop: for {
r := l.Next()
switch r {
- case eof:
- panic("Missing closing `")
- case '`':
- break loop
- case '$':
- slot := l.Next()
- if slot == eof {
- panic("Missing slot character")
- }
- output = append(output, OutputLoadAST{slot: slot})
- default:
- if runic {
- output = append(output, OutputRuneLiteralAST {walk.StringRuneAtom(r)})
- } else {
- l.Rewind()
- scalar, ok := parseScalarLiteral(l)
- if !ok {
- panic("Invalid scalar literal")
- }
- output = append(output, OutputValueLiteralAST {scalar})
- }
+ case eof:
+ panic("Missing closing `")
+ case ' ':
+ case '`':
+ break loop
+ case '$':
+ slot := l.Next()
+ if slot == eof {
+ panic("Missing slot character")
+ }
+ output = append(output, OutputValueLoadAST {slot: slot})
+ default:
+ l.Rewind()
+ scalar, ok := parseScalarLiteral(l)
+ if !ok {
+ panic("Invalid scalar literal")
+ }
+ output = append(output, OutputValueLiteralAST {scalar})
+ }
+ }
+ return output
+}
+
+func parseRuneReplacement(l RuneReader) (output []OutputRuneAST) {
+ // TODO escaping
+ // TODO add arrays, maps and strings
+ loop: for {
+ r := l.Next()
+ switch r {
+ case eof:
+ panic("Missing closing `")
+ case '`':
+ break loop
+ case '$':
+ slot := l.Next()
+ if slot == eof {
+ panic("Missing slot character")
+ }
+ output = append(output, OutputRuneLoadAST {slot: slot})
+ default:
+ output = append(output, OutputRuneLiteralAST {r})
}
}
return output
@@ -245,17 +270,29 @@ func parseReplacement(l RuneReader, runic bool) (output []OutputContentAST) {
// return parts
// }
-func parseSubex(l RuneReader, minPower int, runic bool) SubexAST {
+func parseSubex(l RuneReader, minPower int, inType Type, outType Type) SubexAST {
var lhs SubexAST
r := l.Next()
switch r {
case eof:
return nil
case '(':
- lhs = parseSubex(l, 0, runic)
+ lhs = parseSubex(l, 0, inType, outType)
if !accept(l, ")") {
panic("Missing matching )")
}
+ case '~':
+ if !accept(l, "(") {
+ panic("Missing ( after ~")
+ }
+ lhs = parseSubex(l, 0, RuneType, RuneType)
+ if !accept(l, ")") {
+ panic("Missing matching )")
+ }
+ if !accept(l, "~") {
+ panic("Missing matching ~")
+ }
+ lhs = SubexASTEnterString {lhs}
// TODO
// case '[':
// rangeParts := parseRangeSubex(l)
@@ -278,7 +315,10 @@ func parseSubex(l RuneReader, minPower int, runic bool) SubexAST {
// )
// lhs = SubexASTOutput {replacement}
case '.':
- if runic {
+ if inType != outType {
+ panic("Copying value changes type!")
+ }
+ if inType == RuneType {
lhs = SubexASTCopyAnyRune{}
} else {
lhs = SubexASTCopyAnyValue{}
@@ -287,32 +327,8 @@ func parseSubex(l RuneReader, minPower int, runic bool) SubexAST {
lhs = SubexASTCopyBool{}
case '%':
lhs = SubexASTCopyNumber{}
- case ':':
- if runic {
- lhs = SubexASTCopyRune {':'}
- } else {
- if !accept(l, "[") {
- panic("Missing [ after :")
- }
- lhs = SubexASTEnterArray {parseSubex(l, 0, runic)}
- if !accept(l, "]") {
- panic("Missing matching ]")
- }
- }
case '`':
- lhs = SubexASTOutput {parseReplacement(l, runic)}
- case '~':
- if runic {
- lhs = SubexASTCopyRune {'~'}
- } else {
- if !accept(l, "\"") {
- panic("Missing \" after ~")
- }
- lhs = SubexASTEnterString {parseSubex(l, 0, true)}
- if !accept(l, "\"") {
- panic("Missing matching \"")
- }
- }
+ lhs = SubexASTOutputValues {parseValueReplacement(l)}
// TODO
// case '_':
// lhs = SubexASTCopyStringAtom{}
@@ -322,15 +338,11 @@ func parseSubex(l RuneReader, minPower int, runic bool) SubexAST {
// lhs = SubexASTCopyValue{}
// case '"':
// lhs = SubexASTCopyScalar {walk.NewAtomStringTerminal()}
- // case '~':
- // literals := parseNonStringLiteral(l)
- // var replacement []OutputContentAST
- // for _, literal := range literals {
- // replacement = append(replacement, OutputValueLiteralAST {literal})
- // }
- // lhs = SubexASTOutput {replacement}
default:
- if runic {
+ if inType != outType {
+ panic("inType and outType don't match in copy")
+ }
+ if inType == RuneType {
lhs = SubexASTCopyRune {r}
} else {
l.Rewind()
@@ -343,7 +355,7 @@ func parseSubex(l RuneReader, minPower int, runic bool) SubexAST {
}
loop: for {
if minPower <= 20 {
- next := parseSubex(l, 21, runic)
+ next := parseSubex(l, 21, inType, outType)
if next != nil && (next != SubexASTEmpty{}) {
lhs = SubexASTConcat{lhs, next}
continue loop
@@ -362,12 +374,12 @@ func parseSubex(l RuneReader, minPower int, runic bool) SubexAST {
lhs = SubexASTProduct {lhs}
case r == '-' && minPower <= 4:
lhs = SubexASTNegate {lhs}
- case r == '/' && minPower <= 4:
- lhs = SubexASTReciprocal {lhs}
+ // case r == '/' && minPower <= 4:
+ // lhs = SubexASTReciprocal {lhs}
case r == '!' && minPower <= 4:
lhs = SubexASTNot {lhs}
- case r == '=' && minPower <= 4:
- lhs = SubexASTEqual {lhs}
+ // case r == '=' && minPower <= 4:
+ // lhs = SubexASTEqual {lhs}
case r == '$' && minPower <= 4:
slot := l.Next()
if slot == eof {
@@ -376,26 +388,26 @@ func parseSubex(l RuneReader, minPower int, runic bool) SubexAST {
if slot == '_' {
lhs = SubexASTDiscard {lhs}
} else {
- lhs = SubexASTStore{
+ lhs = SubexASTStoreValues {
Match: lhs,
Slot: slot,
}
}
case r == '|' && minPower <= 8:
- rhs := parseSubex(l, 9, runic)
+ rhs := parseSubex(l, 9, inType, outType)
if rhs == nil {
panic("Missing subex after |")
}
lhs = SubexASTOr{lhs, rhs}
- case r == ';' && minPower <= 10:
- rhs := parseSubex(l, 11, runic)
+ /*case r == ';' && minPower <= 10:
+ rhs := parseSubex(l, 11, inType, outType)
if rhs == nil {
panic("Missing subex after ;")
}
- lhs = SubexASTJoin{
+ lhs = SubexASTJoin {
Content: lhs,
Delimiter: rhs,
- }
+ }*/
default:
l.Rewind()
break loop
@@ -405,7 +417,7 @@ func parseSubex(l RuneReader, minPower int, runic bool) SubexAST {
}
func Parse(l RuneReader) SubexAST {
- ast := parseSubex(l, 0, false)
+ ast := parseSubex(l, 0, ValueType, ValueType)
if ast == nil {
return SubexASTEmpty{}
}