2021-03-01 17:11:22 +00:00
|
|
|
package scpt
|
|
|
|
|
2021-03-01 17:22:00 +00:00
|
|
|
import (
|
2021-03-02 00:44:33 +00:00
|
|
|
"errors"
|
2021-03-01 21:43:10 +00:00
|
|
|
"fmt"
|
|
|
|
"github.com/alecthomas/participle/lexer"
|
2021-03-01 17:22:00 +00:00
|
|
|
)
|
|
|
|
|
2021-03-01 21:43:10 +00:00
|
|
|
// AST stores the root of the Abstract Syntax Tree for scpt
|
2021-03-01 17:11:22 +00:00
|
|
|
type AST struct {
|
2021-03-01 21:43:10 +00:00
|
|
|
Pos lexer.Position
|
2021-03-01 17:11:22 +00:00
|
|
|
Commands []*Command `@@*`
|
|
|
|
}
|
|
|
|
|
2021-03-01 21:43:10 +00:00
|
|
|
// 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 {
|
2021-03-01 23:01:21 +00:00
|
|
|
// For each command in AST
|
2021-03-01 17:22:00 +00:00
|
|
|
for _, cmd := range ast.Commands {
|
2021-03-01 23:01:21 +00:00
|
|
|
// If parsing variables
|
2021-03-01 17:22:00 +00:00
|
|
|
if cmd.Vars != nil {
|
2021-03-01 23:01:21 +00:00
|
|
|
// For each variable
|
2021-03-01 17:22:00 +00:00
|
|
|
for _, Var := range cmd.Vars {
|
2021-03-01 23:01:21 +00:00
|
|
|
// Parse value of variable
|
2021-03-01 21:43:10 +00:00
|
|
|
val, err := ParseValue(Var.Value)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("%s: %s", Var.Value.Pos, err)
|
|
|
|
}
|
2021-03-01 23:01:21 +00:00
|
|
|
// If value of variable is a function call
|
2021-03-01 21:43:10 +00:00
|
|
|
if IsFuncCall(val) {
|
2021-03-01 23:01:21 +00:00
|
|
|
// Assert type of val as *FuncCall
|
2021-03-01 17:22:00 +00:00
|
|
|
Call := val.(*FuncCall)
|
2021-03-01 23:01:21 +00:00
|
|
|
// Set variable value to function return value
|
2021-03-01 21:43:10 +00:00
|
|
|
Vars[Var.Key], err = CallFunction(Call)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("%s: %s", Var.Value.Pos, err)
|
|
|
|
}
|
2021-03-01 17:22:00 +00:00
|
|
|
} else {
|
2021-03-01 23:01:21 +00:00
|
|
|
// If value is not a function call, set variable value to parsed value
|
2021-03-01 17:22:00 +00:00
|
|
|
Vars[Var.Key] = val
|
|
|
|
}
|
|
|
|
}
|
2021-03-02 00:44:33 +00:00
|
|
|
// If parsing function calls
|
2021-03-01 17:22:00 +00:00
|
|
|
} else if cmd.Calls != nil {
|
2021-03-01 23:01:21 +00:00
|
|
|
// For each function call
|
2021-03-01 17:22:00 +00:00
|
|
|
for _, Call := range cmd.Calls {
|
2021-03-01 23:01:21 +00:00
|
|
|
// Attempt to call function
|
2021-03-01 21:43:10 +00:00
|
|
|
_, err := CallFunction(Call)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("%s: %s", Call.Pos, err)
|
|
|
|
}
|
2021-03-01 17:22:00 +00:00
|
|
|
}
|
2021-03-02 00:44:33 +00:00
|
|
|
} else if cmd.Ifs != nil {
|
|
|
|
for _, If := range cmd.Ifs {
|
|
|
|
condVal, err := callIfFunc(ParseValue(If.Condition))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
condBool, ok := condVal.(bool)
|
|
|
|
if !ok {
|
|
|
|
return errors.New("condition must be a boolean")
|
|
|
|
}
|
|
|
|
if condBool {
|
|
|
|
_, err := CallFunction(If.Action)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2021-03-01 17:22:00 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-01 21:43:10 +00:00
|
|
|
return nil
|
2021-03-01 17:22:00 +00:00
|
|
|
}
|
|
|
|
|
2021-03-01 21:43:10 +00:00
|
|
|
// Command stores any commands encountered while parsing a script
|
2021-03-01 17:11:22 +00:00
|
|
|
type Command struct {
|
2021-03-01 21:43:10 +00:00
|
|
|
Pos lexer.Position
|
2021-03-01 17:11:22 +00:00
|
|
|
Vars []*Var `( @@`
|
2021-03-02 00:44:33 +00:00
|
|
|
Ifs []*If `| @@`
|
2021-03-01 17:11:22 +00:00
|
|
|
Calls []*FuncCall `| @@ )`
|
|
|
|
}
|
|
|
|
|
2021-03-02 00:44:33 +00:00
|
|
|
type If struct {
|
|
|
|
Pos lexer.Position
|
|
|
|
Condition *Value `"if" @@`
|
|
|
|
Action *FuncCall `"then" @@`
|
|
|
|
}
|
|
|
|
|
2021-03-01 21:43:10 +00:00
|
|
|
// FuncCall stores any function calls encountered while parsing a script
|
2021-03-01 17:11:22 +00:00
|
|
|
type FuncCall struct {
|
2021-03-01 21:43:10 +00:00
|
|
|
Pos lexer.Position
|
|
|
|
Name string `@Ident @("-" Ident)*`
|
|
|
|
Args []*Arg `@@*`
|
2021-03-01 17:11:22 +00:00
|
|
|
}
|
|
|
|
|
2021-03-01 21:43:10 +00:00
|
|
|
// Arg stores arguments for function calls
|
2021-03-01 17:11:22 +00:00
|
|
|
type Arg struct {
|
2021-03-01 21:43:10 +00:00
|
|
|
Pos lexer.Position
|
|
|
|
Key string `("with" @Ident)?`
|
|
|
|
Value *Value `@@`
|
2021-03-01 17:11:22 +00:00
|
|
|
}
|
|
|
|
|
2021-03-01 21:43:10 +00:00
|
|
|
// Var stores any variables encountered while parsing a script
|
2021-03-01 17:11:22 +00:00
|
|
|
type Var struct {
|
2021-03-01 21:43:10 +00:00
|
|
|
Pos lexer.Position
|
|
|
|
Key string `"set" @Ident "to"`
|
|
|
|
Value *Value `@@`
|
2021-03-01 17:11:22 +00:00
|
|
|
}
|
|
|
|
|
2021-03-01 21:43:10 +00:00
|
|
|
// Value stores any literal values encountered while parsing a script
|
2021-03-01 17:11:22 +00:00
|
|
|
type Value struct {
|
2021-03-01 21:43:10 +00:00
|
|
|
Pos lexer.Position
|
|
|
|
String *string ` @String`
|
|
|
|
Float *float64 `| @Float`
|
|
|
|
Integer *int64 `| @Int`
|
|
|
|
Bool *Bool `| @("true" | "false")`
|
|
|
|
SubCmd *FuncCall `| "(" @@ ")"`
|
|
|
|
VarVal *string `| "$" @Ident`
|
|
|
|
Expr *Expression `| "{" @@ "}"`
|
2021-03-01 17:11:22 +00:00
|
|
|
}
|
|
|
|
|
2021-03-01 21:43:10 +00:00
|
|
|
// Bool stores boolean values encountered while parsing a script.
|
|
|
|
// It is required for the Capture method
|
2021-03-01 17:11:22 +00:00
|
|
|
type Bool bool
|
|
|
|
|
2021-03-01 21:43:10 +00:00
|
|
|
// Capture parses a boolean literal encountered in the script into
|
|
|
|
// a Go boolean value
|
2021-03-01 17:11:22 +00:00
|
|
|
func (b *Bool) Capture(values []string) error {
|
2021-03-01 23:01:21 +00:00
|
|
|
// Convert string to boolean
|
2021-03-01 17:11:22 +00:00
|
|
|
*b = values[0] == "true"
|
|
|
|
return nil
|
|
|
|
}
|
2021-03-01 21:43:10 +00:00
|
|
|
|
|
|
|
// Expression stores any expressions encountered while parsing a
|
|
|
|
// script for later evaluation
|
|
|
|
type Expression struct {
|
2021-03-02 00:44:33 +00:00
|
|
|
Pos lexer.Position
|
|
|
|
Left *Value `@@`
|
|
|
|
RightSegs []*ExprRightSeg `@@*`
|
|
|
|
}
|
|
|
|
|
|
|
|
type ExprRightSeg struct {
|
2021-03-01 21:43:10 +00:00
|
|
|
Op string `@( ">" | ">" "=" | "<" | "<" "=" | "!" "=" | "=" "=" | "+" | "-" | "*" | "/" | "^" | "%")`
|
|
|
|
Right *Value `@@`
|
|
|
|
}
|