gitstack

grindlemire/go-tui code browser

5.2 KB Go 202 lines 2026-06-03 · d15bb9f raw
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Package tuigen provides a DSL compiler that transforms .gsx files into Go source code.
// The DSL provides a templ-inspired syntax for building go-tui element trees.
package tuigen

import "fmt"

// TokenType represents the type of a lexical token.
type TokenType int

const (
	// Special tokens
	TokenEOF        TokenType = iota // end of file
	TokenError                       // lexer error
	TokenNewline                     // newline
	TokenWhitespace                  // spaces/tabs (usually skipped)

	// Keywords
	TokenPackage // package
	TokenImport  // import
	TokenFunc    // func
	TokenTempl   // templ
	TokenReturn  // return
	TokenIf      // if
	TokenElse    // else
	TokenFor     // for
	TokenRange   // range
	TokenTypeKw  // type
	TokenConst   // const
	TokenVar     // var

	// DSL keywords (@ prefixed)
	TokenAtCall // @ComponentName (uppercase, component call)
	TokenAtExpr // @expr (lowercase, renders a Component field/variable)

	// Literals
	TokenIdent     // identifier
	TokenInt       // integer literal: 123
	TokenFloat     // float literal: 1.23
	TokenString    // string literal: "..."
	TokenRawString // raw string literal: `...`
	TokenRune      // rune literal: 'x'
	TokenSymbol    // arbitrary Unicode symbol/character (for text content)

	// Operators and Punctuation
	TokenLParen      // (
	TokenRParen      // )
	TokenLBrace      // {
	TokenRBrace      // }
	TokenLAngle      // <
	TokenRAngle      // >
	TokenLBracket    // [
	TokenRBracket    // ]
	TokenSlash       // /
	TokenEquals      // =
	TokenComma       // ,
	TokenDot         // .
	TokenColon       // :
	TokenSemicolon   // ;
	TokenColonEquals // :=
	TokenAmpersand   // &
	TokenPipe        // |
	TokenStar        // *
	TokenPlus        // +
	TokenMinus       // -
	TokenBang        // !
	TokenUnderscore  // _

	// Composite tokens
	TokenGoExpr      // Go expression inside {}
	TokenSlashAngle  // />  (self-closing tag end)
	TokenLAngleSlash // </ (closing tag start)

	// Comment tokens (collected but not emitted by lexer)
	TokenLineComment  // // comment
	TokenBlockComment // /* comment */
)

// tokenNames maps token types to their string names for debugging.
var tokenNames = map[TokenType]string{
	TokenEOF:          "EOF",
	TokenError:        "Error",
	TokenNewline:      "Newline",
	TokenWhitespace:   "Whitespace",
	TokenPackage:      "package",
	TokenImport:       "import",
	TokenFunc:         "func",
	TokenTempl:        "templ",
	TokenReturn:       "return",
	TokenIf:           "if",
	TokenElse:         "else",
	TokenFor:          "for",
	TokenRange:        "range",
	TokenTypeKw:       "type",
	TokenConst:        "const",
	TokenVar:          "var",
	TokenAtCall:       "@Call",
	TokenAtExpr:       "@Expr",
	TokenIdent:        "Ident",
	TokenInt:          "Int",
	TokenFloat:        "Float",
	TokenString:       "String",
	TokenRawString:    "RawString",
	TokenRune:         "Rune",
	TokenSymbol:       "Symbol",
	TokenLParen:       "(",
	TokenRParen:       ")",
	TokenLBrace:       "{",
	TokenRBrace:       "}",
	TokenLAngle:       "<",
	TokenRAngle:       ">",
	TokenLBracket:     "[",
	TokenRBracket:     "]",
	TokenSlash:        "/",
	TokenEquals:       "=",
	TokenComma:        ",",
	TokenDot:          ".",
	TokenColon:        ":",
	TokenSemicolon:    ";",
	TokenColonEquals:  ":=",
	TokenAmpersand:    "&",
	TokenPipe:         "|",
	TokenStar:         "*",
	TokenPlus:         "+",
	TokenMinus:        "-",
	TokenBang:         "!",
	TokenUnderscore:   "_",
	TokenGoExpr:       "GoExpr",
	TokenSlashAngle:   "/>",
	TokenLAngleSlash:  "</",
	TokenLineComment:  "LineComment",
	TokenBlockComment: "BlockComment",
}

// String returns a human-readable name for the token type.
func (t TokenType) String() string {
	if name, ok := tokenNames[t]; ok {
		return name
	}
	return fmt.Sprintf("TokenType(%d)", t)
}

// Token represents a lexical token with its type, literal value, and source position.
type Token struct {
	Type     TokenType
	Literal  string
	Line     int
	Column   int
	StartPos int // byte offset in source where token starts
}

// String returns a debug representation of the token.
func (t Token) String() string {
	if t.Literal == "" {
		return fmt.Sprintf("%s at %d:%d", t.Type, t.Line, t.Column)
	}
	// Truncate long literals for readability
	lit := t.Literal
	if len(lit) > 20 {
		lit = lit[:17] + "..."
	}
	return fmt.Sprintf("%s(%q) at %d:%d", t.Type, lit, t.Line, t.Column)
}

// Position represents a source code location for error reporting.
type Position struct {
	File   string
	Line   int
	Column int
}

// String returns a formatted position string.
func (p Position) String() string {
	if p.File == "" {
		return fmt.Sprintf("%d:%d", p.Line, p.Column)
	}
	return fmt.Sprintf("%s:%d:%d", p.File, p.Line, p.Column)
}

// keywords maps keyword strings to their token types.
var keywords = map[string]TokenType{
	"package": TokenPackage,
	"import":  TokenImport,
	"func":    TokenFunc,
	"templ":   TokenTempl,
	"return":  TokenReturn,
	"if":      TokenIf,
	"else":    TokenElse,
	"for":     TokenFor,
	"range":   TokenRange,
	"type":    TokenTypeKw,
	"const":   TokenConst,
	"var":     TokenVar,
}

// LookupIdent returns the token type for an identifier,
// checking if it's a keyword first.
func LookupIdent(ident string) TokenType {
	if tok, ok := keywords[ident]; ok {
		return tok
	}
	return TokenIdent
}