package scpt import ( "fmt" "github.com/alecthomas/participle/lexer" ) // AST stores the root of the Abstract Syntax Tree for scpt type AST struct { Pos lexer.Position Commands []*Command `@@*` } // Execute traverses the AST and executes any commands, it returns an error // containing the position at which the error was encountered and the error // itself func (ast *AST) Execute() error { // For each command in AST for _, cmd := range ast.Commands { // If parsing variables if cmd.Vars != nil { // For each variable for _, Var := range cmd.Vars { // Parse value of variable val, err := ParseValue(Var.Value) if err != nil { return fmt.Errorf("%s: %s", Var.Value.Pos, err) } // If value of variable is a function call if IsFuncCall(val) { // Assert type of val as *FuncCall Call := val.(*FuncCall) // Set variable value to function return value Vars[Var.Key], err = CallFunction(Call) if err != nil { return fmt.Errorf("%s: %s", Var.Value.Pos, err) } } else { // If value is not a function call, set variable value to parsed value Vars[Var.Key] = val } } // If parsing function calls } else if cmd.Calls != nil { // For each function call for _, Call := range cmd.Calls { // Attempt to call function _, err := CallFunction(Call) if err != nil { return fmt.Errorf("%s: %s", Call.Pos, err) } } } } return nil } // Command stores any commands encountered while parsing a script type Command struct { Pos lexer.Position Vars []*Var `( @@` Calls []*FuncCall `| @@ )` } // FuncCall stores any function calls encountered while parsing a script type FuncCall struct { Pos lexer.Position Name string `@Ident @("-" Ident)*` Args []*Arg `@@*` } // Arg stores arguments for function calls type Arg struct { Pos lexer.Position Key string `("with" @Ident)?` Value *Value `@@` } // Var stores any variables encountered while parsing a script type Var struct { Pos lexer.Position Key string `"set" @Ident "to"` Value *Value `@@` } // Value stores any literal values encountered while parsing a script type Value struct { Pos lexer.Position String *string ` @String` Float *float64 `| @Float` Integer *int64 `| @Int` Bool *Bool `| @("true" | "false")` SubCmd *FuncCall `| "(" @@ ")"` VarVal *string `| "$" @Ident` Expr *Expression `| "{" @@ "}"` } // Bool stores boolean values encountered while parsing a script. // It is required for the Capture method type Bool bool // Capture parses a boolean literal encountered in the script into // a Go boolean value func (b *Bool) Capture(values []string) error { // Convert string to boolean *b = values[0] == "true" return nil } // Expression stores any expressions encountered while parsing a // script for later evaluation type Expression struct { Pos lexer.Position Left *Value `@@` Op string `@( ">" | ">" "=" | "<" | "<" "=" | "!" "=" | "=" "=" | "+" | "-" | "*" | "/" | "^" | "%")` Right *Value `@@` }