<- Back to shtanton's homepage
summaryrefslogtreecommitdiff
path: root/main/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'main/parse.go')
-rw-r--r--main/parse.go141
1 files changed, 141 insertions, 0 deletions
diff --git a/main/parse.go b/main/parse.go
new file mode 100644
index 0000000..a9bd4b5
--- /dev/null
+++ b/main/parse.go
@@ -0,0 +1,141 @@
+package main
+
+func parseReplacement(l *RuneReader) (output []TransducerOutput) {
+ 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, TransducerReplacementLoad(slot))
+ default:
+ output = append(output, TransducerReplacementRune(r))
+ }
+ }
+ return output
+}
+
+func parseRegex(l *RuneReader, minPower int) RegexAST {
+ var lhs RegexAST
+ r := l.next()
+ switch r {
+ case eof:
+ return nil
+ case ')', '*', '-', '|':
+ l.rewind()
+ return nil
+ case '(':
+ lhs = parseRegex(l, 0)
+ if !l.accept(")") {
+ panic("Missing matching )")
+ }
+ case '.':
+ lhs = RegexASTAny{}
+ default:
+ lhs = RegexASTRune(r)
+ }
+ loop: for {
+ if minPower <= 0 {
+ next := parseRegex(l, 1)
+ if next != nil {
+ lhs = RegexASTConcat{lhs, next}
+ continue loop
+ }
+ }
+ r := l.next()
+ switch {
+ case r == '*' && minPower <= 4:
+ lhs = RegexASTMaximise{lhs}
+ case r == '-' && minPower <= 4:
+ lhs = RegexASTMinimise{lhs}
+ case r == '|' && minPower <= 2:
+ rhs := parseRegex(l, 3)
+ if rhs == nil {
+ panic("Missing regex after |")
+ }
+ lhs = RegexASTOr{lhs, rhs}
+ default:
+ l.rewind()
+ break loop
+ }
+ }
+ return lhs
+}
+
+func parseSubex(l *RuneReader, minPower int) SubexAST {
+ var lhs SubexAST
+ r := l.next()
+ switch r {
+ case eof:
+ return nil
+ case '(':
+ lhs = parseSubex(l, 0)
+ if !l.accept(")") {
+ panic("Missing matching )")
+ }
+ case ')', '*', '-', '|':
+ l.rewind()
+ return nil
+ case '$':
+ slot := l.next()
+ if slot == eof {
+ panic("Missing slot character")
+ }
+ match := parseRegex(l, 100)
+ if match == nil {
+ panic("Missing regex for store")
+ }
+ lhs = SubexASTStore{
+ match: match,
+ slot: slot,
+ }
+ case '"':
+ replacement := parseReplacement(l)
+ lhs = SubexASTOutput{replacement}
+ case '.':
+ lhs = SubexASTCopyAny{}
+ default:
+ lhs = SubexASTCopyRune(r)
+ }
+ loop: for {
+ if minPower <= 0 {
+ next := parseSubex(l, 1)
+ if next != nil {
+ lhs = SubexASTConcat{lhs, next}
+ continue loop
+ }
+ }
+ r := l.next()
+ switch {
+ case r == '*' && minPower <= 4:
+ lhs = SubexASTMaximise{lhs}
+ case r == '-' && minPower <= 4:
+ lhs = SubexASTMinimise{lhs}
+ case r == '|' && minPower <= 2:
+ rhs := parseSubex(l, 3)
+ if rhs == nil {
+ panic("Missing subex after |")
+ }
+ lhs = SubexASTOr{lhs, rhs}
+ default:
+ l.rewind()
+ break loop
+ }
+ }
+ return lhs
+}
+
+func parse(input string) SubexAST {
+ l := RuneReader {
+ input: input,
+ pos: 0,
+ width: 0,
+ }
+ return parseSubex(&l, 0)
+}