import type { LogQLSection } from '../types'; export enum TokenKind { Ident = 'Ident', Number = 'Number', /** 字符串字面量(含起止引号)。引号种类记录在 quote 字段。 */ String = 'String', /** 比较 / 赋值运算符:`:` `=` `>` `<` `>=` `<=` `!=` `<>`。 */ Operator = 'Operator', /** 大小写无关识别后的关键词,value 统一规范为大写。 */ Keyword = 'Keyword', /** 顶层 `|`(非字符串、括号内)。 */ Pipe = 'Pipe', LParen = 'LParen', RParen = 'RParen', LBracket = 'LBracket', RBracket = 'RBracket', Wildcard = 'Wildcard', /** 已闭合的 `${name}`。 */ Variable = 'Variable', /** 孤立的 `$`(如 `${...}` 未闭合或仅有 `$`),用于触发变量补全。 */ Dollar = 'Dollar', Comma = 'Comma', Whitespace = 'Whitespace', EOF = 'EOF', /** Lexer 无法消化的字符,留给上层容错。 */ Error = 'Error', } export interface Token { kind: TokenKind; value: string; start: number; end: number; /** Variable 的名字(不含 `${}` 包裹)。 */ name?: string; /** String token 的引号字符,如 `"` 、 `'` 、`` ` ``。 */ quote?: string; /** String token 是否未闭合。 */ unterminated?: boolean; } export type SearchExpr = FilterNode | BinaryNode | UnaryNode | GroupNode | TermNode | ErrorNode; export interface FilterNode { type: 'Filter'; field?: Token; op?: Token; value?: ValueNode; range: [number, number]; } export interface BinaryNode { type: 'Binary'; op: 'AND' | 'OR'; opToken: Token; left: SearchExpr; right: SearchExpr; range: [number, number]; } export interface UnaryNode { type: 'Unary'; op: 'NOT'; opToken: Token; expr: SearchExpr; range: [number, number]; } export interface GroupNode { type: 'Group'; expr?: SearchExpr; range: [number, number]; } export interface TermNode { type: 'Term'; value: ValueNode; range: [number, number]; } export interface ErrorNode { type: 'Error'; range: [number, number]; } export type ValueNode = | { type: 'Literal'; token: Token } | { type: 'Variable'; token: Token; name: string } | { type: 'Range'; from?: Token; to?: Token; range: [number, number] }; export interface AnalyzeSegment { type: 'Analyze'; tokens: Token[]; range: [number, number]; } export interface LogQLAST { type: 'Query'; search?: SearchExpr; pipe?: Token; analyze?: AnalyzeSegment; range: [number, number]; } export interface Situation { section: LogQLSection; kind: | 'FIELD_NAME' | 'FIELD_VALUE' | 'VARIABLE' | 'ANALYZE_KEYWORD' | 'ANALYZE_FUNCTION' | 'ANALYZE_FIELD' | 'IN_STRING' | 'NONE'; prefix: string; fieldName?: string; replaceRange: { start: number; end: number }; } export const SEARCH_KEYWORDS_SET = new Set(['AND', 'OR', 'NOT', 'TO', 'IN']);