aboutsummaryrefslogtreecommitdiffstats
path: root/debug_shell/state.go
blob: 17d0474c3bd379f688f4d759fb4d1fe49bf2fc80 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package main

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
}