diff options
Diffstat (limited to 'pkg/shell/state.go')
| -rw-r--r-- | pkg/shell/state.go | 142 |
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 +} |
