Clean up code and add support for multiple operations in expression
This commit is contained in:
parent
a95d054189
commit
291b7a906c
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"
|
Loading…
Reference in New Issue
Block a user