Browse Source

Implement repeat loops

master
Arsen Musayelyan 1 year ago
parent
commit
877f85ef78
  1. 48
      ast.go
  2. 8
      defaults.go
  3. 4
      lexer.go
  4. 3
      scpt.go
  5. 5
      test.scpt

48
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.

8
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
}

4
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},
}))
}))

3
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
}

5
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)}
}
Loading…
Cancel
Save