Clean up code and add support for multiple operations in expression
This commit is contained in:
		
							
								
								
									
										27
									
								
								ast.go
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								ast.go
									
									
									
									
									
								
							@@ -1,6 +1,7 @@
 | 
				
			|||||||
package scpt
 | 
					package scpt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/alecthomas/participle/lexer"
 | 
						"github.com/alecthomas/participle/lexer"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -50,6 +51,21 @@ func (ast *AST) Execute() error {
 | 
				
			|||||||
					return fmt.Errorf("%s: %s", Call.Pos, err)
 | 
										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
 | 
						return nil
 | 
				
			||||||
@@ -59,9 +75,16 @@ func (ast *AST) Execute() error {
 | 
				
			|||||||
type Command struct {
 | 
					type Command struct {
 | 
				
			||||||
	Pos   lexer.Position
 | 
						Pos   lexer.Position
 | 
				
			||||||
	Vars  []*Var      `( @@`
 | 
						Vars  []*Var      `( @@`
 | 
				
			||||||
 | 
						Ifs   []*If       `| @@`
 | 
				
			||||||
	Calls []*FuncCall `| @@ )`
 | 
						Calls []*FuncCall `| @@ )`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type If struct {
 | 
				
			||||||
 | 
						Pos       lexer.Position
 | 
				
			||||||
 | 
						Condition *Value    `"if" @@`
 | 
				
			||||||
 | 
						Action    *FuncCall `"then" @@`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FuncCall stores any function calls encountered while parsing a script
 | 
					// FuncCall stores any function calls encountered while parsing a script
 | 
				
			||||||
type FuncCall struct {
 | 
					type FuncCall struct {
 | 
				
			||||||
	Pos  lexer.Position
 | 
						Pos  lexer.Position
 | 
				
			||||||
@@ -112,6 +135,10 @@ func (b *Bool) Capture(values []string) error {
 | 
				
			|||||||
type Expression struct {
 | 
					type Expression struct {
 | 
				
			||||||
	Pos       lexer.Position
 | 
						Pos       lexer.Position
 | 
				
			||||||
	Left      *Value          `@@`
 | 
						Left      *Value          `@@`
 | 
				
			||||||
 | 
						RightSegs []*ExprRightSeg `@@*`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ExprRightSeg struct {
 | 
				
			||||||
	Op    string `@( ">" | ">" "=" | "<" | "<" "=" | "!" "=" | "=" "=" | "+" | "-" | "*" | "/" | "^" | "%")`
 | 
						Op    string `@( ">" | ">" "=" | "<" | "<" "=" | "!" "=" | "=" "=" | "+" | "-" | "*" | "/" | "^" | "%")`
 | 
				
			||||||
	Right *Value `@@`
 | 
						Right *Value `@@`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@@ -6,6 +6,4 @@ require (
 | 
				
			|||||||
	github.com/alecthomas/participle v0.7.1
 | 
						github.com/alecthomas/participle v0.7.1
 | 
				
			||||||
	github.com/antonmedv/expr v1.8.9
 | 
						github.com/antonmedv/expr v1.8.9
 | 
				
			||||||
	github.com/gen2brain/dlgs v0.0.0-20210222160047-2f436553172f
 | 
						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
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										48
									
								
								scpt.go
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								scpt.go
									
									
									
									
									
								
							@@ -67,8 +67,8 @@ func ParseValue(val *Value) (interface{}, error) {
 | 
				
			|||||||
		// Return unquoted string
 | 
							// Return unquoted string
 | 
				
			||||||
		return strings.Trim(*val.String, `"`), nil
 | 
							return strings.Trim(*val.String, `"`), nil
 | 
				
			||||||
	} else if val.Bool != nil {
 | 
						} else if val.Bool != nil {
 | 
				
			||||||
		// Return dereferenced boolean
 | 
							// Return dereferenced Bool converted to bool
 | 
				
			||||||
		return *val.Bool, nil
 | 
							return bool(*val.Bool), nil
 | 
				
			||||||
	} else if val.Float != nil {
 | 
						} else if val.Float != nil {
 | 
				
			||||||
		// Return dereferenced float
 | 
							// Return dereferenced float
 | 
				
			||||||
		return *val.Float, nil
 | 
							return *val.Float, nil
 | 
				
			||||||
@@ -83,22 +83,32 @@ func ParseValue(val *Value) (interface{}, error) {
 | 
				
			|||||||
		return Vars[*val.VarVal], nil
 | 
							return Vars[*val.VarVal], nil
 | 
				
			||||||
	} else if val.Expr != nil {
 | 
						} else if val.Expr != nil {
 | 
				
			||||||
		// Parse value of left side of expression
 | 
							// Parse value of left side of expression
 | 
				
			||||||
		left, _ := ParseValue(val.Expr.Left)
 | 
							left, _ := callIfFunc(ParseValue(val.Expr.Left))
 | 
				
			||||||
		// If value is string, requote
 | 
							// If value is string, requote
 | 
				
			||||||
		if isStr(left) {
 | 
							if isStr(left) {
 | 
				
			||||||
			left = requoteStr(left.(string))
 | 
								left = requoteStr(left.(string))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Parse value of right side of expression
 | 
							// Create new nil string
 | 
				
			||||||
		right, _ := ParseValue(val.Expr.Right)
 | 
							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 value is string, requote
 | 
				
			||||||
		if isStr(right) {
 | 
								if isStr(rVal) {
 | 
				
			||||||
			right = requoteStr(right.(string))
 | 
									rVal = requoteStr(rVal.(string))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		// Create string expression from halves and operator
 | 
								// Append right segment to right string
 | 
				
			||||||
 | 
								right = right + fmt.Sprintf(
 | 
				
			||||||
 | 
									" %s %v",
 | 
				
			||||||
 | 
									segment.Op,
 | 
				
			||||||
 | 
									rVal,
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Create string expression from segments and operator
 | 
				
			||||||
		exp := fmt.Sprintf(
 | 
							exp := fmt.Sprintf(
 | 
				
			||||||
			"%v %s %v",
 | 
								"%v %s",
 | 
				
			||||||
			left,
 | 
								left,
 | 
				
			||||||
			val.Expr.Op,
 | 
					 | 
				
			||||||
			right,
 | 
								right,
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		// Compile string expression
 | 
							// Compile string expression
 | 
				
			||||||
@@ -132,6 +142,20 @@ func isStr(i interface{}) bool {
 | 
				
			|||||||
	return false
 | 
						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
 | 
					// UnwrapArgs takes a slice of Arg structs and returns a map
 | 
				
			||||||
// storing the argument name and its value. If the argument has
 | 
					// storing the argument name and its value. If the argument has
 | 
				
			||||||
// no name, its key will be an empty string
 | 
					// 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
 | 
					// IsFuncCall checks if val is a FuncCall struct
 | 
				
			||||||
func IsFuncCall(val interface{}) bool {
 | 
					func IsFuncCall(val interface{}) bool {
 | 
				
			||||||
	// If type of val contains .FuncCall, return true
 | 
						// If type of val is a pointer to FuncCall, return true
 | 
				
			||||||
	if strings.Contains(reflect.TypeOf(val).String(), ".FuncCall") {
 | 
						if reflect.TypeOf(val) == reflect.TypeOf(&FuncCall{}) {
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
set y to (display-dialog "Hello" with title 12 with type "yesno")
 | 
					set y to (display-dialog "Hello" with title 12 with type "yesno")
 | 
				
			||||||
display-dialog "Goodbye" with title 21 with type "error"
 | 
					display-dialog "Goodbye" with title 21 with type "error"
 | 
				
			||||||
do-shell-script "notify-send Test Notification"
 | 
					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
 | 
					set x to $y
 | 
				
			||||||
print { 3+4 }
 | 
					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"
 | 
				
			||||||
		Reference in New Issue
	
	Block a user