From 291b7a906c2cd4688df6614e0fa33d9d4e2c5500 Mon Sep 17 00:00:00 2001 From: Arsen Musayelyan Date: Mon, 1 Mar 2021 16:44:33 -0800 Subject: [PATCH] Clean up code and add support for multiple operations in expression --- ast.go | 33 ++++++++++++++++++++++++++++++--- defaults.go | 2 +- go.mod | 2 -- scpt.go | 50 +++++++++++++++++++++++++++++++++++++------------- test.scpt | 5 +++-- 5 files changed, 71 insertions(+), 21 deletions(-) diff --git a/ast.go b/ast.go index 2d035e0..8be99b6 100644 --- a/ast.go +++ b/ast.go @@ -1,6 +1,7 @@ package scpt import ( + "errors" "fmt" "github.com/alecthomas/participle/lexer" ) @@ -40,7 +41,7 @@ func (ast *AST) Execute() error { Vars[Var.Key] = val } } - // If parsing function calls + // If parsing function calls } else if cmd.Calls != nil { // For each function call for _, Call := range cmd.Calls { @@ -50,6 +51,21 @@ func (ast *AST) Execute() error { return fmt.Errorf("%s: %s", Call.Pos, err) } } + } 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 + } + } } } return nil @@ -59,9 +75,16 @@ func (ast *AST) Execute() error { type Command struct { Pos lexer.Position Vars []*Var `( @@` + Ifs []*If `| @@` Calls []*FuncCall `| @@ )` } +type If struct { + Pos lexer.Position + Condition *Value `"if" @@` + Action *FuncCall `"then" @@` +} + // FuncCall stores any function calls encountered while parsing a script type FuncCall struct { Pos lexer.Position @@ -110,8 +133,12 @@ func (b *Bool) Capture(values []string) error { // Expression stores any expressions encountered while parsing a // script for later evaluation type Expression struct { - Pos lexer.Position - Left *Value `@@` + Pos lexer.Position + Left *Value `@@` + RightSegs []*ExprRightSeg `@@*` +} + +type ExprRightSeg struct { Op string `@( ">" | ">" "=" | "<" | "<" "=" | "!" "=" | "=" "=" | "+" | "-" | "*" | "/" | "^" | "%")` Right *Value `@@` } diff --git a/defaults.go b/defaults.go index 908cd9e..65ceadb 100644 --- a/defaults.go +++ b/defaults.go @@ -66,4 +66,4 @@ func doShellScript(args map[string]interface{}) (interface{}, error) { } else { return nil, errors.New("script not provided") } -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index e6cb23a..bef766c 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,4 @@ require ( github.com/alecthomas/participle v0.7.1 github.com/antonmedv/expr v1.8.9 github.com/gen2brain/dlgs v0.0.0-20210222160047-2f436553172f - github.com/gopherjs/gopherjs v0.0.0-20210202160940-bed99a852dfe // indirect - github.com/rs/zerolog v1.20.0 ) diff --git a/scpt.go b/scpt.go index 0c0937e..cb47af2 100644 --- a/scpt.go +++ b/scpt.go @@ -67,8 +67,8 @@ func ParseValue(val *Value) (interface{}, error) { // Return unquoted string return strings.Trim(*val.String, `"`), nil } else if val.Bool != nil { - // Return dereferenced boolean - return *val.Bool, nil + // Return dereferenced Bool converted to bool + return bool(*val.Bool), nil } else if val.Float != nil { // Return dereferenced float return *val.Float, nil @@ -83,22 +83,32 @@ func ParseValue(val *Value) (interface{}, error) { return Vars[*val.VarVal], nil } else if val.Expr != nil { // Parse value of left side of expression - left, _ := ParseValue(val.Expr.Left) + left, _ := callIfFunc(ParseValue(val.Expr.Left)) // If value is string, requote if isStr(left) { left = requoteStr(left.(string)) } - // Parse value of right side of expression - right, _ := ParseValue(val.Expr.Right) - // If value is string, requote - if isStr(right) { - right = requoteStr(right.(string)) + // Create new nil string + var right string + // For every right segment + for _, segment := range val.Expr.RightSegs { + // Parse value of right segment, calling it if it is a function + rVal, _ := callIfFunc(ParseValue(segment.Right)) + // If value is string, requote + if isStr(rVal) { + rVal = requoteStr(rVal.(string)) + } + // Append right segment to right string + right = right + fmt.Sprintf( + " %s %v", + segment.Op, + rVal, + ) } - // Create string expression from halves and operator + // Create string expression from segments and operator exp := fmt.Sprintf( - "%v %s %v", + "%v %s", left, - val.Expr.Op, right, ) // Compile string expression @@ -132,6 +142,20 @@ func isStr(i interface{}) bool { return false } +// Call val if it is a function, otherwise pass through return values +func callIfFunc(val interface{}, err error) (interface{}, error) { + if err != nil { + return nil, err + } + // If val is a pointer to a FuncCall + if IsFuncCall(val) { + // Pass through return values of function call + return CallFunction(val.(*FuncCall)) + } + // Return given value + return val, nil +} + // UnwrapArgs takes a slice of Arg structs and returns a map // storing the argument name and its value. If the argument has // no name, its key will be an empty string @@ -164,8 +188,8 @@ func UnwrapArgs(args []*Arg) (map[string]interface{}, error) { // IsFuncCall checks if val is a FuncCall struct func IsFuncCall(val interface{}) bool { - // If type of val contains .FuncCall, return true - if strings.Contains(reflect.TypeOf(val).String(), ".FuncCall") { + // If type of val is a pointer to FuncCall, return true + if reflect.TypeOf(val) == reflect.TypeOf(&FuncCall{}) { return true } return false diff --git a/test.scpt b/test.scpt index 6886c2b..e31a8a5 100644 --- a/test.scpt +++ b/test.scpt @@ -1,6 +1,7 @@ set y to (display-dialog "Hello" with title 12 with type "yesno") display-dialog "Goodbye" with title 21 with type "error" do-shell-script "notify-send Test Notification" -print (display-dialog {"Test " + "2"} with title 30 with type "entry" with default "text") +do-shell-script {"echo " + (display-dialog {"Test " + "2"} with title 30 with type "entry" with default "text")} set x to $y -print { 3+4 } \ No newline at end of file +if {3 == 4} then display-dialog "What? Why is 3 equal to 4?" with title "What?!" with type "info" +if {3 == 3} then display-dialog "3 is equal to 3!" with title "New Discovery" with type "info" \ No newline at end of file