diff --git a/ast.go b/ast.go index 3c278c5..85a6982 100644 --- a/ast.go +++ b/ast.go @@ -100,24 +100,48 @@ func executeCmd(cmd *Command) error { } } } + } else if cmd.RptLoops != nil { + // For each repeat loop + for _, RptLoop := range cmd.RptLoops { + for i:=0;i<*RptLoop.Times;i++ { + if RptLoop.IndexVar != nil { + Vars[*RptLoop.IndexVar] = i + } + for _, InnerCmd := range RptLoop.InnerCmds { + // Execute command recursively + err := executeCmd(InnerCmd) + if err != nil { + return fmt.Errorf("%s: %s", InnerCmd.Pos, err) + } + } + } + } } return nil } // Command stores any commands encountered while parsing a script type Command struct { - Pos lexer.Position + Pos lexer.Position Tokens []lexer.Token - Vars []*Var `( @@` - Ifs []*If `| @@` - Calls []*FuncCall `| @@)` + Vars []*Var `( @@` + Ifs []*If `| @@` + RptLoops []*RptLoop`| @@` + Calls []*FuncCall `| @@)` } // If stores any if statements encountered while parsing a script type If struct { Pos lexer.Position Condition *Value `"if" @@ "{"` - InnerCmds []*Command `@@*"}"` + InnerCmds []*Command `@@* "}"` +} + +type RptLoop struct { + Pos lexer.Position + Times *int `"repeat" @Number "times" "{"` + IndexVar *string `(@Ident "in")?` + InnerCmds []*Command `@@* "}"` } // FuncCall stores any function calls encountered while parsing a script @@ -143,13 +167,13 @@ type Var struct { // Value stores any literal values encountered while parsing a script type Value struct { - Pos lexer.Position - String *string ` @String` - Number *float64 `| @Number` - Bool *Bool `| @("true" | "false")` - SubCmd *FuncCall `| "(" @@ ")"` - VarVal *string `| "$" @Ident` - Expr *Expression `| "{" @@ "}"` + Pos lexer.Position + String *string ` @String` + Number *float64 `| @Number` + Bool *Bool `| @("true" | "false")` + SubCmd *FuncCall `| "(" @@ ")"` + VarVal *string `| "$" @Ident` + Expr *Expression `| "{" @@ "}"` } // Bool stores boolean values encountered while parsing a script. diff --git a/defaults.go b/defaults.go index 34ff3bb..016ed1f 100644 --- a/defaults.go +++ b/defaults.go @@ -81,3 +81,11 @@ func doShellScript(args map[string]interface{}) (interface{}, error) { return nil, errors.New("script not provided") } } + +func toString(args map[string]interface{}) (interface{}, error) { + val, ok := args[""] + if !ok { + return nil, errors.New("no value provided") + } + return fmt.Sprint(val), nil +} \ No newline at end of file diff --git a/lexer.go b/lexer.go index 7346e68..ca62611 100644 --- a/lexer.go +++ b/lexer.go @@ -10,8 +10,8 @@ var scptLexer = lexer.Must(stateful.NewSimple([]stateful.Rule{ {"Ident", `[a-zA-Z]\w*`, nil}, {"String", `"[^"]*"`, nil}, {"Number", `(?:\d*\.)?\d+`, nil}, - {"Punct", `[-[!@#$&()_{}\|:;"',.?/]|]`, nil}, + {"Punct", `[-[!@$&()_{}\|:;"',.?/]|]`, nil}, {"Whitespace", `[ \t\r\n]+`, nil}, {"Comment", `#[^\n]+`, nil}, {"Operator", `(>=|<=|>|<|==|!=)|[-+*/^%]`, nil}, -})) \ No newline at end of file +})) diff --git a/scpt.go b/scpt.go index 6d0380b..c88fbef 100644 --- a/scpt.go +++ b/scpt.go @@ -36,6 +36,7 @@ type FuncMap map[string]func(map[string]interface{}) (interface{}, error) var Funcs = FuncMap{ "display-dialog": displayDialog, "do-shell-script": doShellScript, + "string": toString, } // AddFuncs adds all functions from the provided FuncMap into @@ -63,7 +64,7 @@ func Parse(r io.Reader) (*AST, error) { &AST{}, participle.Lexer(scptLexer), participle.Elide("Whitespace", "Comment"), - ) + ) if err != nil { return nil, err } diff --git a/test.scpt b/test.scpt index c132aba..bfe231b 100644 --- a/test.scpt +++ b/test.scpt @@ -14,3 +14,8 @@ if {3 == 3} { } } +do-shell-script "echo rpt" + +repeat 5 times { z in + do-shell-script {"echo " + (string $z)} +} \ No newline at end of file