<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2024-04-27 09:29:46 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2024-04-27 09:29:46 +0100
commit8ac12c99fc59b01da40c2939cb4a7b72d32d2153 (patch)
treea60859e7614f35a8158fdd7614b2e3c196460b61
parent7084f5e1ceb61eab199512410048ad53e3ea08d7 (diff)
downloadstred-go-8ac12c99fc59b01da40c2939cb4a7b72d32d2153.tar
Add iterating destructures
-rw-r--r--main/main_test.go7
-rw-r--r--subex/parse.go61
-rw-r--r--subex/subexstate.go78
3 files changed, 37 insertions, 109 deletions
diff --git a/main/main_test.go b/main/main_test.go
index b745202..8512b62 100644
--- a/main/main_test.go
+++ b/main/main_test.go
@@ -87,6 +87,13 @@ func TestMain(t *testing.T) {
expected: `["Charlie Johnson","Tom Johnson","Charlie Chaplin","John Johnson"]`,
},
{
+ name: "Get full names with merge full command",
+ program: "s/#(\"people\"$_ :(): )-/p M/#( \"people\" @( . #()# )@ )#/{ s/#( \"people\"$_ @( . #[ \"first_name\" \".{-0}$a\" | \"last_name\" \".{-0}$b\" | .. $_]- `\"$a $b\"` )@ )-/p }",
+ quiet: true,
+ input: miscInput,
+ expected: `["Charlie Johnson","Tom Johnson","Charlie Chaplin","John Johnson"]`,
+ },
+ {
name: "Verbose concat array values",
program: "as/#( \"array\"$_ :(): )-/{ :s N/#( .$_ . )-/{ es/.{-0}:():/be mbs } :em s/:( -( ~(.{-0}` `)-{-0} ~(.{-0})- )~ )-/p }",
quiet: true,
diff --git a/subex/parse.go b/subex/parse.go
index b6bf2f6..9a7a75c 100644
--- a/subex/parse.go
+++ b/subex/parse.go
@@ -55,6 +55,12 @@ func (s Structure) String() string {
}
}
+type DestructureMethod int
+const (
+ Normal DestructureMethod = iota
+ Iterate
+)
+
type RuneReader interface {
Next() rune
Rewind()
@@ -361,8 +367,14 @@ func parseRuneReplacement(l RuneReader, end rune) (output SubexAST) {
// }
func parseDestructure(l RuneReader, destructure Structure, inType Type) (lhs SubexAST, outType Type) {
- if !accept(l, "(") {
- panic("Missing ( after destructure start")
+ var method rune
+ switch l.Next() {
+ case '(':
+ method = ')'
+ case '[':
+ method = ']'
+ default:
+ panic("Missing ( or [ after destructure start")
}
var innerInType Type
@@ -390,8 +402,22 @@ func parseDestructure(l RuneReader, destructure Structure, inType Type) (lhs Sub
resolveTypes(inType, expectedInType)
lhs, innerOutType := parseSubex(l, 0, innerInType)
- if !accept(l, ")") {
- panic("Missing matching )")
+ if !accept(l, string(method)) {
+ panic("Missing matching ) or ]")
+ }
+
+ switch method {
+ case ')':
+ case ']':
+ lhs = SubexASTRepeat {
+ Content: lhs,
+ Acceptable: []ConvexRange{{
+ Start: -1,
+ End: 0,
+ }},
+ }
+ default:
+ panic("Invalid method")
}
var structure Structure
@@ -487,20 +513,6 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType
case ')', ']', '|', ';', '{', '+', '*', '/', '!', '=', '$':
l.Rewind()
return SubexASTEmpty{}, inType
- // case '=':
- // replacement := parseReplacement(l)
- // lhs = SubexASTOutput{replacement}
- // case '^':
- // replacement := parseReplacement(l)
- // replacement = append(
- // []OutputContentAST{OutputValueLiteralAST {walk.NewAtomStringTerminal()}},
- // replacement...
- // )
- // replacement = append(
- // replacement,
- // OutputValueLiteralAST {walk.NewAtomStringTerminal()},
- // )
- // lhs = SubexASTOutput {replacement}
case '.':
outType = inType
if inType == RuneType {
@@ -569,14 +581,10 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType
lhs = SubexASTProduct {lhs}
resolveTypes(inType, ValueType)
outType = resolveTypes(outType, ValueType)
- // case r == '/' && minPower <= 4:
- // lhs = SubexASTReciprocal {lhs}
case r == '!' && minPower <= 4:
lhs = SubexASTNot {lhs}
resolveTypes(inType, ValueType)
outType = resolveTypes(outType, ValueType)
- // case r == '=' && minPower <= 4:
- // lhs = SubexASTEqual {lhs}
case r == '$' && minPower <= 4:
slot := l.Next()
if slot == eof {
@@ -608,15 +616,6 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType
panic("Missing subex after |")
}
lhs = SubexASTOr{lhs, rhs}
- /*case r == ';' && minPower <= 10:
- rhs := parseSubex(l, 11, inType, outType)
- if rhs == nil {
- panic("Missing subex after ;")
- }
- lhs = SubexASTJoin {
- Content: lhs,
- Delimiter: rhs,
- }*/
default:
l.Rewind()
break loop
diff --git a/subex/subexstate.go b/subex/subexstate.go
index 1e1e94e..8f27a10 100644
--- a/subex/subexstate.go
+++ b/subex/subexstate.go
@@ -146,84 +146,6 @@ func (state SubexStoreRunesEndState) epsilon(aux auxiliaryState) []SubexBranch {
}}
}
-/*
-// A part of an output literal, either an Atom or a slot from which to load
-type OutputContent interface {
- // Given the current store, return the ValueList produced by the TransducerOutput
- buildValues(Store) walk.ValueList
- // Given the current store, return the RuneList produced by the TransducerOutput
- buildRunes(Store) walk.RuneList
-}
-
-// An OutputContent which is just a Value literal
-type OutputValueLiteral struct {
- value walk.Value
-}
-func (replacement OutputValueLiteral) buildValues(store Store) walk.ValueList {
- return walk.ValueList{replacement.value}
-}
-func (replacement OutputValueLiteral) buildRunes(store Store) walk.RuneList {
- // TODO: serialise to JSON
- panic("Unimplemented!")
-}
-
-// An OutputContent which is just a rune literal
-type OutputRuneLiteral struct {
- rune walk.StringRuneAtom
-}
-func (replacement OutputRuneLiteral) buildValues(store Store) walk.ValueList {
- // TODO: Try to deserialise
- panic("Unimplemented!")
-}
-func (replacement OutputRuneLiteral) buildRunes(store Store) walk.RuneList {
- return walk.RuneList {replacement.rune}
-}
-
-// An OutputContent which is a slot that is loaded from
-type OutputLoad struct {
- slot int
-}
-func (replacement OutputLoad) buildValues(store Store) walk.ValueList {
- values, isValues := store[replacement.slot].(walk.ValueList)
- if !isValues {
- panic("Tried to output non-values list")
- }
- return values
-}
-func (replacement OutputLoad) buildRunes(store Store) walk.RuneList {
- runes, isRunes := store[replacement.slot].(walk.RuneList)
- if !isRunes {
- panic("Tried to output non-runes as runes")
- }
- return runes
-}
-
-// Don't read in anything, just output the series of data and slots specified
-type SubexOutputState struct {
- content []OutputContent
- next SubexState
-}
-// Given a store, return what is outputted by an epsilon transition from this state
-// TODO: separate into buildValues and buildRunes
-func (state SubexOutputState) build(store Store) walk.ValueList {
- var result walk.ValueList
- for _, part := range state.content {
- result = append(result, part.buildValues(store)...)
- }
- return result
-}
-func (state SubexOutputState) eat(aux auxiliaryState, char walk.Value) []SubexBranch {
- content := state.build(aux.store)
- nextStates := state.next.eat(aux.topAppend(content), char)
- return nextStates
-}
-func (state SubexOutputState) accepting(aux auxiliaryState) []OutputStack {
- content := state.build(aux.store)
- outputStacks := state.next.accepting(aux.topAppend(content))
- return outputStacks
-}
-*/
-
type SubexOutputValueLiteralState struct {
literal walk.Scalar
next SubexState