aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/shell/state.go
diff options
context:
space:
mode:
authorJP Appel <jeanpierre.appel01@gmail.com>2025-06-13 12:35:37 -0400
committerJP Appel <jeanpierre.appel01@gmail.com>2025-06-13 12:35:37 -0400
commitf85cfb2055551926ed4aeaa0550330d3e4da7569 (patch)
tree8ac67405b961c3609ab6fbd9488c826ab81b3e97 /pkg/shell/state.go
parentbf841d00967c3047bff88dbe070cb56319e1fe38 (diff)
Move debug shell into main binary as a command
Diffstat (limited to 'pkg/shell/state.go')
-rw-r--r--pkg/shell/state.go142
1 files changed, 142 insertions, 0 deletions
diff --git a/pkg/shell/state.go b/pkg/shell/state.go
new file mode 100644
index 0000000..ea62604
--- /dev/null
+++ b/pkg/shell/state.go
@@ -0,0 +1,142 @@
+package shell
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/jpappel/atlas/pkg/query"
+)
+
+type ValueType int
+
+const (
+ INVALID ValueType = iota
+ STRING
+ TOKENS
+ CLAUSE
+)
+
+type Value struct {
+ Type ValueType
+ Val any
+}
+
+type State map[string]Value
+
+func (v Value) String() string {
+ switch v.Type {
+ case STRING:
+ s, ok := v.Val.(string)
+ if !ok {
+ return "Corrupted Type (expected string)"
+ }
+ return s
+ case TOKENS:
+ ts, ok := v.Val.([]query.Token)
+ if !ok {
+ return "Corrupted Type (expected []query.Token)"
+ }
+ return query.TokensStringify(ts)
+ case CLAUSE:
+ rootClause, ok := v.Val.(*query.Clause)
+ if !ok {
+ return "Corrupted Type (expected query.Clause)"
+ }
+ return rootClause.String()
+ case INVALID:
+ return "Invalid"
+ }
+ return fmt.Sprintf("Unknown @ %p", v.Val)
+}
+
+func (s State) String() string {
+ b := strings.Builder{}
+
+ for k, v := range s {
+ b.WriteString(k)
+ b.WriteByte(':')
+ switch v.Type {
+ case INVALID:
+ b.WriteString(" Invalid")
+ case STRING:
+ b.WriteString(" String")
+ case TOKENS:
+ b.WriteString(" Tokens")
+ case CLAUSE:
+ b.WriteString(" Clause")
+ default:
+ fmt.Fprintf(&b, " Unknown (%d)", v.Val)
+ }
+ b.WriteByte('\n')
+ }
+
+ return b.String()
+}
+
+func (s State) CmdTokenize(input string) (Value, bool) {
+ if len(input) == 0 {
+ return Value{}, false
+ }
+
+ var rawQuery string
+ if input[0] == '`' {
+ rawQuery = input[1:]
+ } else {
+ variable, ok := s[input]
+ if !ok {
+ fmt.Fprintln(os.Stderr, "Cannot tokenize: no variable with name", input)
+ return Value{}, false
+ } else if variable.Type != STRING {
+ fmt.Fprintln(os.Stderr, "Cannot tokenize: variable is not a string")
+ return Value{}, false
+ }
+
+ rawQuery, ok = variable.Val.(string)
+ if !ok {
+ fmt.Fprintln(os.Stderr, "Cannot tokenize: type corruption")
+ fmt.Fprintln(os.Stderr, "Type corruption, expected string")
+ panic("Type corruption")
+ }
+ }
+ tokens := query.Lex(rawQuery)
+ return Value{TOKENS, tokens}, true
+}
+
+func (s State) CmdParse(args string) (Value, error) {
+ if len(args) == 0 {
+ return Value{}, errors.New("no arguments for parse")
+ }
+
+ var tokens []query.Token
+ if tokenizeArgs, found := strings.CutPrefix(args, "tokenize "); found {
+ val, ok := s.CmdTokenize(tokenizeArgs)
+ if !ok {
+ return Value{}, errors.New("error occured during tokenization")
+ }
+ tokens = val.Val.([]query.Token)
+ } else {
+ variable, ok := s[args]
+ if !ok {
+ fmt.Fprintln(os.Stderr, "Cannot parse: no variable with name", args)
+ return Value{}, errors.New("variable does not exist")
+ } else if variable.Type != TOKENS {
+ fmt.Fprintln(os.Stderr, "Cannot parse: variable is not []query.Tokens")
+ return Value{}, errors.New("bad variable type")
+ }
+
+ tokens, ok = variable.Val.([]query.Token)
+ if !ok {
+ fmt.Fprintln(os.Stderr, "Cannot parse: type corruption")
+ fmt.Fprintln(os.Stderr, "Type corruption, expected []query.Tokens")
+ panic("Type corruption")
+ }
+ }
+
+ clause, err := query.Parse(tokens)
+ if err != nil {
+ return Value{}, err
+ }
+ return Value{CLAUSE, *clause}, err
+}