...
This commit is contained in:
212
pkg2/heroscript/playbook/parser.go
Normal file
212
pkg2/heroscript/playbook/parser.go
Normal file
@@ -0,0 +1,212 @@
|
||||
package playbook
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
|
||||
"git.ourworld.tf/herocode/heroagent/pkg/tools"
|
||||
)
|
||||
|
||||
// State represents the parser state
|
||||
type State int
|
||||
|
||||
const (
|
||||
StateStart State = iota
|
||||
StateCommentForActionMaybe
|
||||
StateAction
|
||||
StateOtherText
|
||||
)
|
||||
|
||||
// PlayBookOptions contains options for creating a new PlayBook
|
||||
type PlayBookOptions struct {
|
||||
Text string
|
||||
Path string
|
||||
GitURL string
|
||||
GitPull bool
|
||||
GitBranch string
|
||||
GitReset bool
|
||||
Priority int
|
||||
}
|
||||
|
||||
// AddText adds heroscript text to the playbook
|
||||
func (p *PlayBook) AddText(text string, priority int) error {
|
||||
// Normalize text
|
||||
text = strings.ReplaceAll(text, "\t", " ")
|
||||
|
||||
var state State = StateStart
|
||||
var action *Action
|
||||
var comments []string
|
||||
var paramsData []string
|
||||
|
||||
// Process each line
|
||||
lines := strings.Split(text, "\n")
|
||||
for _, line := range lines {
|
||||
lineStrip := strings.TrimSpace(line)
|
||||
|
||||
if lineStrip == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle action state
|
||||
if state == StateAction {
|
||||
if !strings.HasPrefix(line, " ") || lineStrip == "" || strings.HasPrefix(lineStrip, "!") {
|
||||
state = StateStart
|
||||
// End of action, parse params
|
||||
if len(paramsData) > 0 {
|
||||
params := strings.Join(paramsData, "\n")
|
||||
err := action.Params.Parse(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Remove ID from params if present
|
||||
delete(action.Params.GetAll(), "id")
|
||||
}
|
||||
comments = []string{}
|
||||
paramsData = []string{}
|
||||
action = nil
|
||||
} else {
|
||||
paramsData = append(paramsData, line)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle comment state
|
||||
if state == StateCommentForActionMaybe {
|
||||
if strings.HasPrefix(lineStrip, "//") {
|
||||
comments = append(comments, strings.TrimLeft(lineStrip, "/ "))
|
||||
} else {
|
||||
if strings.HasPrefix(lineStrip, "!") {
|
||||
state = StateStart
|
||||
} else {
|
||||
state = StateStart
|
||||
p.OtherText += strings.Join(comments, "\n")
|
||||
if !strings.HasSuffix(p.OtherText, "\n") {
|
||||
p.OtherText += "\n"
|
||||
}
|
||||
comments = []string{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle start state
|
||||
if state == StateStart {
|
||||
if strings.HasPrefix(lineStrip, "!") && !strings.HasPrefix(lineStrip, "![") {
|
||||
// Start a new action
|
||||
state = StateAction
|
||||
|
||||
// Create new action
|
||||
action = &Action{
|
||||
ID: p.NrActions + 1,
|
||||
Priority: priority,
|
||||
Params: paramsparser.New(),
|
||||
Result: paramsparser.New(),
|
||||
}
|
||||
p.NrActions++
|
||||
|
||||
// Set comments
|
||||
action.Comments = strings.Join(comments, "\n")
|
||||
comments = []string{}
|
||||
paramsData = []string{}
|
||||
|
||||
// Parse action name
|
||||
actionName := lineStrip
|
||||
if strings.Contains(lineStrip, " ") {
|
||||
actionName = strings.TrimSpace(strings.Split(lineStrip, " ")[0])
|
||||
params := strings.TrimSpace(strings.Join(strings.Split(lineStrip, " ")[1:], " "))
|
||||
if params != "" {
|
||||
paramsData = append(paramsData, params)
|
||||
}
|
||||
}
|
||||
|
||||
// Determine action type
|
||||
if strings.HasPrefix(actionName, "!!!!!") {
|
||||
return ErrInvalidActionPrefix
|
||||
} else if strings.HasPrefix(actionName, "!!!!") {
|
||||
action.ActionType = ActionTypeWAL
|
||||
} else if strings.HasPrefix(actionName, "!!!") {
|
||||
action.ActionType = ActionTypeMacro
|
||||
} else if strings.HasPrefix(actionName, "!!") {
|
||||
action.ActionType = ActionTypeSAL
|
||||
} else if strings.HasPrefix(actionName, "!") {
|
||||
action.ActionType = ActionTypeDAL
|
||||
}
|
||||
|
||||
// Remove prefix
|
||||
actionName = strings.TrimLeft(actionName, "!")
|
||||
|
||||
// Split into actor and action name
|
||||
parts := strings.Split(actionName, ".")
|
||||
if len(parts) == 1 {
|
||||
action.Actor = "core"
|
||||
action.Name = tools.NameFix(parts[0])
|
||||
} else if len(parts) == 2 {
|
||||
action.Actor = tools.NameFix(parts[0])
|
||||
action.Name = tools.NameFix(parts[1])
|
||||
} else {
|
||||
return ErrInvalidActionName
|
||||
}
|
||||
|
||||
// Add action to playbook
|
||||
p.Actions = append(p.Actions, action)
|
||||
|
||||
continue
|
||||
} else if strings.HasPrefix(lineStrip, "//") {
|
||||
state = StateCommentForActionMaybe
|
||||
comments = append(comments, strings.TrimLeft(lineStrip, "/ "))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process the last action if needed
|
||||
if state == StateAction && action != nil && action.ID != 0 {
|
||||
if len(paramsData) > 0 {
|
||||
params := strings.Join(paramsData, "\n")
|
||||
err := action.Params.Parse(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Remove ID from params if present
|
||||
delete(action.Params.GetAll(), "id")
|
||||
}
|
||||
}
|
||||
|
||||
// Process the last comment if needed
|
||||
if state == StateCommentForActionMaybe && len(comments) > 0 {
|
||||
p.OtherText += strings.Join(comments, "\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewFromFile creates a new PlayBook from a file
|
||||
func NewFromFile(path string, priority int) (*PlayBook, error) {
|
||||
// This is a simplified version - in a real implementation, you'd read the file
|
||||
// and handle different file types (md, hero, etc.)
|
||||
|
||||
// For now, we'll just create an empty playbook
|
||||
pb := New()
|
||||
|
||||
// TODO: Implement file reading and parsing
|
||||
|
||||
return pb, nil
|
||||
}
|
||||
|
||||
// Errors
|
||||
var (
|
||||
ErrInvalidActionPrefix = NewError("invalid action prefix")
|
||||
ErrInvalidActionName = NewError("invalid action name")
|
||||
)
|
||||
|
||||
// NewError creates a new error
|
||||
func NewError(msg string) error {
|
||||
return &PlayBookError{msg}
|
||||
}
|
||||
|
||||
// PlayBookError represents a playbook error
|
||||
type PlayBookError struct {
|
||||
Msg string
|
||||
}
|
||||
|
||||
// Error returns the error message
|
||||
func (e *PlayBookError) Error() string {
|
||||
return e.Msg
|
||||
}
|
Reference in New Issue
Block a user