Clean up code and add support for multiple operations in expression
This commit is contained in:
		
							
								
								
									
										33
									
								
								ast.go
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								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" | ||||||
| ) | ) | ||||||
| @@ -40,7 +41,7 @@ func (ast *AST) Execute() error { | |||||||
| 					Vars[Var.Key] = val | 					Vars[Var.Key] = val | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		// If parsing function calls | 			// If parsing function calls | ||||||
| 		} else if cmd.Calls != nil { | 		} else if cmd.Calls != nil { | ||||||
| 			// For each function call | 			// For each function call | ||||||
| 			for _, Call := range cmd.Calls { | 			for _, Call := range cmd.Calls { | ||||||
| @@ -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 | ||||||
| @@ -110,8 +133,12 @@ func (b *Bool) Capture(values []string) error { | |||||||
| // Expression stores any expressions encountered while parsing a | // Expression stores any expressions encountered while parsing a | ||||||
| // script for later evaluation | // script for later evaluation | ||||||
| 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 |  | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										50
									
								
								scpt.go
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								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 | ||||||
| 		// If value is string, requote | 		// For every right segment | ||||||
| 		if isStr(right) { | 		for _, segment := range val.Expr.RightSegs { | ||||||
| 			right = requoteStr(right.(string)) | 			// 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( | 		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