Files
ragflow/internal/cli/parser.go
Jin Hai 70e9743ef1 RAGFlow go API server (#13240)
# RAGFlow Go Implementation Plan 🚀

This repository tracks the progress of porting RAGFlow to Go. We'll
implement core features and provide performance comparisons between
Python and Go versions.

## Implementation Checklist

- [x] User Management APIs
- [x] Dataset Management Operations
- [x] Retrieval Test
- [x] Chat Management Operations
- [x] Infinity Go SDK

---------

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
Co-authored-by: Yingfeng Zhang <yingfeng.zhang@gmail.com>
2026-03-04 19:17:16 +08:00

1569 lines
32 KiB
Go

//
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package cli
import (
"fmt"
"strconv"
"strings"
)
// Parser implements a recursive descent parser for RAGFlow CLI commands
type Parser struct {
lexer *Lexer
curToken Token
peekToken Token
}
// NewParser creates a new parser
func NewParser(input string) *Parser {
l := NewLexer(input)
p := &Parser{lexer: l}
// Read two tokens to initialize curToken and peekToken
p.nextToken()
p.nextToken()
return p
}
func (p *Parser) nextToken() {
p.curToken = p.peekToken
p.peekToken = p.lexer.NextToken()
}
// Parse parses the input and returns a Command
func (p *Parser) Parse() (*Command, error) {
if p.curToken.Type == TokenEOF {
return nil, nil
}
// Check for meta commands (backslash commands)
if p.curToken.Type == TokenIdentifier && strings.HasPrefix(p.curToken.Value, "\\") {
return p.parseMetaCommand()
}
// Parse SQL-like command
return p.parseSQLCommand()
}
func (p *Parser) parseMetaCommand() (*Command, error) {
cmd := NewCommand("meta")
cmdName := strings.TrimPrefix(p.curToken.Value, "\\")
cmd.Params["command"] = strings.ToLower(cmdName)
// Parse arguments
var args []string
p.nextToken()
for p.curToken.Type != TokenEOF {
args = append(args, p.curToken.Value)
p.nextToken()
}
cmd.Params["args"] = args
return cmd, nil
}
func (p *Parser) parseSQLCommand() (*Command, error) {
if p.curToken.Type != TokenIdentifier && !isKeyword(p.curToken.Type) {
return nil, fmt.Errorf("expected command, got %s", p.curToken.Value)
}
switch p.curToken.Type {
case TokenLogin:
return p.parseLoginUser()
case TokenPing:
return p.parsePingServer()
case TokenList:
return p.parseListCommand()
case TokenShow:
return p.parseShowCommand()
case TokenCreate:
return p.parseCreateCommand()
case TokenDrop:
return p.parseDropCommand()
case TokenAlter:
return p.parseAlterCommand()
case TokenGrant:
return p.parseGrantCommand()
case TokenRevoke:
return p.parseRevokeCommand()
case TokenSet:
return p.parseSetCommand()
case TokenReset:
return p.parseResetCommand()
case TokenGenerate:
return p.parseGenerateCommand()
case TokenImport:
return p.parseImportCommand()
case TokenSearch:
return p.parseSearchCommand()
case TokenParse:
return p.parseParseCommand()
case TokenBenchmark:
return p.parseBenchmarkCommand()
case TokenRegister:
return p.parseRegisterCommand()
case TokenStartup:
return p.parseStartupCommand()
case TokenShutdown:
return p.parseShutdownCommand()
case TokenRestart:
return p.parseRestartCommand()
default:
return nil, fmt.Errorf("unknown command: %s", p.curToken.Value)
}
}
func (p *Parser) expectPeek(tokenType int) error {
if p.peekToken.Type != tokenType {
return fmt.Errorf("expected %s, got %s", tokenTypeToString(tokenType), p.peekToken.Value)
}
p.nextToken()
return nil
}
func (p *Parser) expectSemicolon() error {
if p.curToken.Type == TokenSemicolon {
return nil
}
if p.peekToken.Type == TokenSemicolon {
p.nextToken()
return nil
}
return fmt.Errorf("expected semicolon")
}
func isKeyword(tokenType int) bool {
return tokenType >= TokenLogin && tokenType <= TokenPing
}
// Helper functions for parsing
func (p *Parser) parseQuotedString() (string, error) {
if p.curToken.Type != TokenQuotedString {
return "", fmt.Errorf("expected quoted string, got %s", p.curToken.Value)
}
return p.curToken.Value, nil
}
func (p *Parser) parseIdentifier() (string, error) {
if p.curToken.Type != TokenIdentifier {
return "", fmt.Errorf("expected identifier, got %s", p.curToken.Value)
}
return p.curToken.Value, nil
}
func (p *Parser) parseNumber() (int, error) {
if p.curToken.Type != TokenNumber {
return 0, fmt.Errorf("expected number, got %s", p.curToken.Value)
}
return strconv.Atoi(p.curToken.Value)
}
// Command parsers
func (p *Parser) parseLoginUser() (*Command, error) {
cmd := NewCommand("login_user")
p.nextToken() // consume LOGIN
if p.curToken.Type != TokenUser {
return nil, fmt.Errorf("expected USER after LOGIN")
}
p.nextToken()
email, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd.Params["email"] = email
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parsePingServer() (*Command, error) {
cmd := NewCommand("ping_server")
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseRegisterCommand() (*Command, error) {
cmd := NewCommand("register_user")
p.nextToken() // consume REGISTER
if err := p.expectPeek(TokenUser); err != nil {
return nil, err
}
p.nextToken()
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd.Params["user_name"] = userName
p.nextToken()
if p.curToken.Type != TokenAs {
return nil, fmt.Errorf("expected AS")
}
p.nextToken()
nickname, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd.Params["nickname"] = nickname
p.nextToken()
if p.curToken.Type != TokenPassword {
return nil, fmt.Errorf("expected PASSWORD")
}
p.nextToken()
password, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd.Params["password"] = password
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseListCommand() (*Command, error) {
p.nextToken() // consume LIST
switch p.curToken.Type {
case TokenServices:
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("list_services"), nil
case TokenUsers:
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("list_users"), nil
case TokenRoles:
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("list_roles"), nil
case TokenVars:
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("list_variables"), nil
case TokenConfigs:
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("list_configs"), nil
case TokenEnvs:
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("list_environments"), nil
case TokenDatasets:
return p.parseListDatasets()
case TokenAgents:
return p.parseListAgents()
case TokenKeys:
return p.parseListKeys()
case TokenModel:
return p.parseListModelProviders()
case TokenDefault:
return p.parseListDefaultModels()
case TokenChats:
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("list_user_chats"), nil
case TokenFiles:
return p.parseListFiles()
default:
return nil, fmt.Errorf("unknown LIST target: %s", p.curToken.Value)
}
}
func (p *Parser) parseListDatasets() (*Command, error) {
cmd := NewCommand("list_user_datasets")
p.nextToken() // consume DATASETS
if p.curToken.Type == TokenSemicolon {
return cmd, nil
}
if p.curToken.Type == TokenOf {
p.nextToken()
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd = NewCommand("list_datasets")
cmd.Params["user_name"] = userName
p.nextToken()
}
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseListAgents() (*Command, error) {
p.nextToken() // consume AGENTS
if p.curToken.Type == TokenSemicolon {
return NewCommand("list_user_agents"), nil
}
if p.curToken.Type != TokenOf {
return nil, fmt.Errorf("expected OF")
}
p.nextToken()
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("list_agents")
cmd.Params["user_name"] = userName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseListKeys() (*Command, error) {
p.nextToken() // consume KEYS
if p.curToken.Type != TokenOf {
return nil, fmt.Errorf("expected OF")
}
p.nextToken()
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("list_keys")
cmd.Params["user_name"] = userName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseListModelProviders() (*Command, error) {
p.nextToken() // consume MODEL
if p.curToken.Type != TokenProviders {
return nil, fmt.Errorf("expected PROVIDERS")
}
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("list_user_model_providers"), nil
}
func (p *Parser) parseListDefaultModels() (*Command, error) {
p.nextToken() // consume DEFAULT
if p.curToken.Type != TokenModels {
return nil, fmt.Errorf("expected MODELS")
}
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("list_user_default_models"), nil
}
func (p *Parser) parseListFiles() (*Command, error) {
p.nextToken() // consume FILES
if p.curToken.Type != TokenOf {
return nil, fmt.Errorf("expected OF")
}
p.nextToken()
if p.curToken.Type != TokenDataset {
return nil, fmt.Errorf("expected DATASET")
}
p.nextToken()
datasetName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("list_user_dataset_files")
cmd.Params["dataset_name"] = datasetName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseShowCommand() (*Command, error) {
p.nextToken() // consume SHOW
switch p.curToken.Type {
case TokenVersion:
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("show_version"), nil
case TokenCurrent:
p.nextToken()
if p.curToken.Type != TokenUser {
return nil, fmt.Errorf("expected USER after CURRENT")
}
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return NewCommand("show_current_user"), nil
case TokenUser:
return p.parseShowUser()
case TokenRole:
return p.parseShowRole()
case TokenVar:
return p.parseShowVariable()
case TokenService:
return p.parseShowService()
default:
return nil, fmt.Errorf("unknown SHOW target: %s", p.curToken.Value)
}
}
func (p *Parser) parseShowUser() (*Command, error) {
p.nextToken() // consume USER
// Check for PERMISSION
if p.curToken.Type == TokenPermission {
p.nextToken()
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("show_user_permission")
cmd.Params["user_name"] = userName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("show_user")
cmd.Params["user_name"] = userName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseShowRole() (*Command, error) {
p.nextToken() // consume ROLE
roleName, err := p.parseIdentifier()
if err != nil {
return nil, err
}
cmd := NewCommand("show_role")
cmd.Params["role_name"] = roleName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseShowVariable() (*Command, error) {
p.nextToken() // consume VAR
varName, err := p.parseIdentifier()
if err != nil {
return nil, err
}
cmd := NewCommand("show_variable")
cmd.Params["var_name"] = varName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseShowService() (*Command, error) {
p.nextToken() // consume SERVICE
serviceNum, err := p.parseNumber()
if err != nil {
return nil, err
}
cmd := NewCommand("show_service")
cmd.Params["number"] = serviceNum
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseCreateCommand() (*Command, error) {
p.nextToken() // consume CREATE
switch p.curToken.Type {
case TokenUser:
return p.parseCreateUser()
case TokenRole:
return p.parseCreateRole()
case TokenModel:
return p.parseCreateModelProvider()
case TokenDataset:
return p.parseCreateDataset()
case TokenChat:
return p.parseCreateChat()
default:
return nil, fmt.Errorf("unknown CREATE target: %s", p.curToken.Value)
}
}
func (p *Parser) parseCreateUser() (*Command, error) {
p.nextToken() // consume USER
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
password, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("create_user")
cmd.Params["user_name"] = userName
cmd.Params["password"] = password
cmd.Params["role"] = "user"
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseCreateRole() (*Command, error) {
p.nextToken() // consume ROLE
roleName, err := p.parseIdentifier()
if err != nil {
return nil, err
}
cmd := NewCommand("create_role")
cmd.Params["role_name"] = roleName
p.nextToken()
if p.curToken.Type == TokenDescription {
p.nextToken()
description, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd.Params["description"] = description
p.nextToken()
}
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseCreateModelProvider() (*Command, error) {
p.nextToken() // consume MODEL
if p.curToken.Type != TokenProvider {
return nil, fmt.Errorf("expected PROVIDER")
}
p.nextToken()
providerName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
providerKey, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("create_model_provider")
cmd.Params["provider_name"] = providerName
cmd.Params["provider_key"] = providerKey
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseCreateDataset() (*Command, error) {
p.nextToken() // consume DATASET
datasetName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenWith {
return nil, fmt.Errorf("expected WITH")
}
p.nextToken()
if p.curToken.Type != TokenEmbedding {
return nil, fmt.Errorf("expected EMBEDDING")
}
p.nextToken()
embedding, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
cmd := NewCommand("create_user_dataset")
cmd.Params["dataset_name"] = datasetName
cmd.Params["embedding"] = embedding
if p.curToken.Type == TokenParser {
p.nextToken()
parserType, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd.Params["parser_type"] = parserType
p.nextToken()
} else if p.curToken.Type == TokenPipeline {
p.nextToken()
pipeline, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd.Params["pipeline"] = pipeline
p.nextToken()
} else {
return nil, fmt.Errorf("expected PARSER or PIPELINE")
}
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseCreateChat() (*Command, error) {
p.nextToken() // consume CHAT
chatName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("create_user_chat")
cmd.Params["chat_name"] = chatName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseDropCommand() (*Command, error) {
p.nextToken() // consume DROP
switch p.curToken.Type {
case TokenUser:
return p.parseDropUser()
case TokenRole:
return p.parseDropRole()
case TokenModel:
return p.parseDropModelProvider()
case TokenDataset:
return p.parseDropDataset()
case TokenChat:
return p.parseDropChat()
case TokenKey:
return p.parseDropKey()
default:
return nil, fmt.Errorf("unknown DROP target: %s", p.curToken.Value)
}
}
func (p *Parser) parseDropUser() (*Command, error) {
p.nextToken() // consume USER
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("drop_user")
cmd.Params["user_name"] = userName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseDropRole() (*Command, error) {
p.nextToken() // consume ROLE
roleName, err := p.parseIdentifier()
if err != nil {
return nil, err
}
cmd := NewCommand("drop_role")
cmd.Params["role_name"] = roleName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseDropModelProvider() (*Command, error) {
p.nextToken() // consume MODEL
if p.curToken.Type != TokenProvider {
return nil, fmt.Errorf("expected PROVIDER")
}
p.nextToken()
providerName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("drop_model_provider")
cmd.Params["provider_name"] = providerName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseDropDataset() (*Command, error) {
p.nextToken() // consume DATASET
datasetName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("drop_user_dataset")
cmd.Params["dataset_name"] = datasetName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseDropChat() (*Command, error) {
p.nextToken() // consume CHAT
chatName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("drop_user_chat")
cmd.Params["chat_name"] = chatName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseDropKey() (*Command, error) {
p.nextToken() // consume KEY
key, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenOf {
return nil, fmt.Errorf("expected OF")
}
p.nextToken()
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("drop_key")
cmd.Params["key"] = key
cmd.Params["user_name"] = userName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseAlterCommand() (*Command, error) {
p.nextToken() // consume ALTER
switch p.curToken.Type {
case TokenUser:
return p.parseAlterUser()
case TokenRole:
return p.parseAlterRole()
default:
return nil, fmt.Errorf("unknown ALTER target: %s", p.curToken.Value)
}
}
func (p *Parser) parseAlterUser() (*Command, error) {
p.nextToken() // consume USER
if p.curToken.Type == TokenActive {
return p.parseActivateUser()
}
if p.curToken.Type == TokenPassword {
p.nextToken()
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
password, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("alter_user")
cmd.Params["user_name"] = userName
cmd.Params["password"] = password
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenSet {
return nil, fmt.Errorf("expected SET")
}
p.nextToken()
if p.curToken.Type != TokenRole {
return nil, fmt.Errorf("expected ROLE")
}
p.nextToken()
roleName, err := p.parseIdentifier()
if err != nil {
return nil, err
}
cmd := NewCommand("alter_user_role")
cmd.Params["user_name"] = userName
cmd.Params["role_name"] = roleName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseActivateUser() (*Command, error) {
p.nextToken() // consume ACTIVE
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
status, err := p.parseIdentifier()
if err != nil {
return nil, err
}
cmd := NewCommand("activate_user")
cmd.Params["user_name"] = userName
cmd.Params["activate_status"] = status
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseAlterRole() (*Command, error) {
p.nextToken() // consume ROLE
roleName, err := p.parseIdentifier()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenSet {
return nil, fmt.Errorf("expected SET")
}
p.nextToken()
if p.curToken.Type != TokenDescription {
return nil, fmt.Errorf("expected DESCRIPTION")
}
p.nextToken()
description, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("alter_role")
cmd.Params["role_name"] = roleName
cmd.Params["description"] = description
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseGrantCommand() (*Command, error) {
p.nextToken() // consume GRANT
if p.curToken.Type == TokenAdmin {
return p.parseGrantAdmin()
}
return p.parseGrantPermission()
}
func (p *Parser) parseGrantAdmin() (*Command, error) {
p.nextToken() // consume ADMIN
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("grant_admin")
cmd.Params["user_name"] = userName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseGrantPermission() (*Command, error) {
actions, err := p.parseIdentifierList()
if err != nil {
return nil, err
}
if p.curToken.Type != TokenOn {
return nil, fmt.Errorf("expected ON")
}
p.nextToken()
resource, err := p.parseIdentifier()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenTo {
return nil, fmt.Errorf("expected TO")
}
p.nextToken()
if p.curToken.Type != TokenRole {
return nil, fmt.Errorf("expected ROLE")
}
p.nextToken()
roleName, err := p.parseIdentifier()
if err != nil {
return nil, err
}
cmd := NewCommand("grant_permission")
cmd.Params["actions"] = actions
cmd.Params["resource"] = resource
cmd.Params["role_name"] = roleName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseRevokeCommand() (*Command, error) {
p.nextToken() // consume REVOKE
if p.curToken.Type == TokenAdmin {
return p.parseRevokeAdmin()
}
return p.parseRevokePermission()
}
func (p *Parser) parseRevokeAdmin() (*Command, error) {
p.nextToken() // consume ADMIN
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("revoke_admin")
cmd.Params["user_name"] = userName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseRevokePermission() (*Command, error) {
actions, err := p.parseIdentifierList()
if err != nil {
return nil, err
}
if p.curToken.Type != TokenOn {
return nil, fmt.Errorf("expected ON")
}
p.nextToken()
resource, err := p.parseIdentifier()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenFrom {
return nil, fmt.Errorf("expected FROM")
}
p.nextToken()
if p.curToken.Type != TokenRole {
return nil, fmt.Errorf("expected ROLE")
}
p.nextToken()
roleName, err := p.parseIdentifier()
if err != nil {
return nil, err
}
cmd := NewCommand("revoke_permission")
cmd.Params["actions"] = actions
cmd.Params["resource"] = resource
cmd.Params["role_name"] = roleName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseIdentifierList() ([]string, error) {
var list []string
ident, err := p.parseIdentifier()
if err != nil {
return nil, err
}
list = append(list, ident)
p.nextToken()
for p.curToken.Type == TokenComma {
p.nextToken()
ident, err := p.parseIdentifier()
if err != nil {
return nil, err
}
list = append(list, ident)
p.nextToken()
}
return list, nil
}
func (p *Parser) parseSetCommand() (*Command, error) {
p.nextToken() // consume SET
if p.curToken.Type == TokenVar {
return p.parseSetVariable()
}
if p.curToken.Type == TokenDefault {
return p.parseSetDefault()
}
return nil, fmt.Errorf("unknown SET target: %s", p.curToken.Value)
}
func (p *Parser) parseSetVariable() (*Command, error) {
p.nextToken() // consume VAR
varName, err := p.parseIdentifier()
if err != nil {
return nil, err
}
p.nextToken()
varValue, err := p.parseIdentifier()
if err != nil {
return nil, err
}
cmd := NewCommand("set_variable")
cmd.Params["var_name"] = varName
cmd.Params["var_value"] = varValue
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseSetDefault() (*Command, error) {
p.nextToken() // consume DEFAULT
var modelType, modelID string
switch p.curToken.Type {
case TokenLLM:
modelType = "llm_id"
case TokenVLM:
modelType = "img2txt_id"
case TokenEmbedding:
modelType = "embd_id"
case TokenReranker:
modelType = "reranker_id"
case TokenASR:
modelType = "asr_id"
case TokenTTS:
modelType = "tts_id"
default:
return nil, fmt.Errorf("unknown model type: %s", p.curToken.Value)
}
p.nextToken()
id, err := p.parseQuotedString()
if err != nil {
return nil, err
}
modelID = id
cmd := NewCommand("set_default_model")
cmd.Params["model_type"] = modelType
cmd.Params["model_id"] = modelID
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseResetCommand() (*Command, error) {
p.nextToken() // consume RESET
if p.curToken.Type != TokenDefault {
return nil, fmt.Errorf("expected DEFAULT")
}
p.nextToken()
var modelType string
switch p.curToken.Type {
case TokenLLM:
modelType = "llm_id"
case TokenVLM:
modelType = "img2txt_id"
case TokenEmbedding:
modelType = "embd_id"
case TokenReranker:
modelType = "reranker_id"
case TokenASR:
modelType = "asr_id"
case TokenTTS:
modelType = "tts_id"
default:
return nil, fmt.Errorf("unknown model type: %s", p.curToken.Value)
}
cmd := NewCommand("reset_default_model")
cmd.Params["model_type"] = modelType
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseGenerateCommand() (*Command, error) {
p.nextToken() // consume GENERATE
if p.curToken.Type != TokenKey {
return nil, fmt.Errorf("expected KEY")
}
p.nextToken()
if p.curToken.Type != TokenFor {
return nil, fmt.Errorf("expected FOR")
}
p.nextToken()
if p.curToken.Type != TokenUser {
return nil, fmt.Errorf("expected USER")
}
p.nextToken()
userName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("generate_key")
cmd.Params["user_name"] = userName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseImportCommand() (*Command, error) {
p.nextToken() // consume IMPORT
documentPaths, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenInto {
return nil, fmt.Errorf("expected INTO")
}
p.nextToken()
if p.curToken.Type != TokenDataset {
return nil, fmt.Errorf("expected DATASET")
}
p.nextToken()
datasetName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("import_docs_into_dataset")
cmd.Params["document_paths"] = documentPaths
cmd.Params["dataset_name"] = datasetName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseSearchCommand() (*Command, error) {
p.nextToken() // consume SEARCH
question, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenOn {
return nil, fmt.Errorf("expected ON")
}
p.nextToken()
if p.curToken.Type != TokenDatasets {
return nil, fmt.Errorf("expected DATASETS")
}
p.nextToken()
datasets, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("search_on_datasets")
cmd.Params["question"] = question
cmd.Params["datasets"] = datasets
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseParseCommand() (*Command, error) {
p.nextToken() // consume PARSE
if p.curToken.Type == TokenDataset {
return p.parseParseDataset()
}
return p.parseParseDocs()
}
func (p *Parser) parseParseDataset() (*Command, error) {
p.nextToken() // consume DATASET
datasetName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
var method string
if p.curToken.Type == TokenSync {
method = "sync"
} else if p.curToken.Type == TokenAsync {
method = "async"
} else {
return nil, fmt.Errorf("expected SYNC or ASYNC")
}
cmd := NewCommand("parse_dataset")
cmd.Params["dataset_name"] = datasetName
cmd.Params["method"] = method
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseParseDocs() (*Command, error) {
documentNames, err := p.parseQuotedString()
if err != nil {
return nil, err
}
p.nextToken()
if p.curToken.Type != TokenOf {
return nil, fmt.Errorf("expected OF")
}
p.nextToken()
if p.curToken.Type != TokenDataset {
return nil, fmt.Errorf("expected DATASET")
}
p.nextToken()
datasetName, err := p.parseQuotedString()
if err != nil {
return nil, err
}
cmd := NewCommand("parse_dataset_docs")
cmd.Params["document_names"] = documentNames
cmd.Params["dataset_name"] = datasetName
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseBenchmarkCommand() (*Command, error) {
cmd := NewCommand("benchmark")
p.nextToken() // consume BENCHMARK
concurrency, err := p.parseNumber()
if err != nil {
return nil, err
}
cmd.Params["concurrency"] = concurrency
p.nextToken()
iterations, err := p.parseNumber()
if err != nil {
return nil, err
}
cmd.Params["iterations"] = iterations
p.nextToken()
// Parse user_statement
nestedCmd, err := p.parseUserStatement()
if err != nil {
return nil, err
}
cmd.Params["command"] = nestedCmd
return cmd, nil
}
func (p *Parser) parseUserStatement() (*Command, error) {
switch p.curToken.Type {
case TokenPing:
return p.parsePingServer()
case TokenShow:
return p.parseShowCommand()
case TokenCreate:
return p.parseCreateCommand()
case TokenDrop:
return p.parseDropCommand()
case TokenSet:
return p.parseSetCommand()
case TokenReset:
return p.parseResetCommand()
case TokenList:
return p.parseListCommand()
case TokenParse:
return p.parseParseCommand()
case TokenImport:
return p.parseImportCommand()
case TokenSearch:
return p.parseSearchCommand()
default:
return nil, fmt.Errorf("invalid user statement: %s", p.curToken.Value)
}
}
func (p *Parser) parseStartupCommand() (*Command, error) {
p.nextToken() // consume STARTUP
if p.curToken.Type != TokenService {
return nil, fmt.Errorf("expected SERVICE")
}
p.nextToken()
serviceNum, err := p.parseNumber()
if err != nil {
return nil, err
}
cmd := NewCommand("startup_service")
cmd.Params["number"] = serviceNum
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseShutdownCommand() (*Command, error) {
p.nextToken() // consume SHUTDOWN
if p.curToken.Type != TokenService {
return nil, fmt.Errorf("expected SERVICE")
}
p.nextToken()
serviceNum, err := p.parseNumber()
if err != nil {
return nil, err
}
cmd := NewCommand("shutdown_service")
cmd.Params["number"] = serviceNum
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func (p *Parser) parseRestartCommand() (*Command, error) {
p.nextToken() // consume RESTART
if p.curToken.Type != TokenService {
return nil, fmt.Errorf("expected SERVICE")
}
p.nextToken()
serviceNum, err := p.parseNumber()
if err != nil {
return nil, err
}
cmd := NewCommand("restart_service")
cmd.Params["number"] = serviceNum
p.nextToken()
if err := p.expectSemicolon(); err != nil {
return nil, err
}
return cmd, nil
}
func tokenTypeToString(t int) string {
// Simplified for error messages
return fmt.Sprintf("token(%d)", t)
}