Add opposite values and README.md

This commit is contained in:
Elara 2021-03-08 11:21:50 -08:00
parent 36d1eee759
commit bb89c93344
4 changed files with 93 additions and 2 deletions

80
README.md Normal file
View File

@ -0,0 +1,80 @@
# scpt
scpt is an applescript-inspired scripting language written for fun and to see if I could.
[![Go Reference](https://pkg.go.dev/badge/gitea.arsenm.dev/Arsen6331/scpt.svg)](https://pkg.go.dev/gitea.arsenm.dev/Arsen6331/scpt)
---
### Usage
scpt is to be used as a library imported into Go. A basic interpreter with no extra functionality would look like this:
```go
package main
import (
"gitea.arsenm.dev/Arsen6331/scpt"
"log"
"os"
"path/filepath"
)
func main() {
filename := os.Args[1]
file, err := os.Open(filepath.Clean(filename))
if err != nil {
log.Fatalln(err)
}
ast, err := scpt.Parse(file)
if err != nil {
log.Fatalln(err)
}
err = ast.Execute()
if err != nil {
log.Fatalln(err)
}
}
```
---
### Basic Syntax
The basic syntax of scpt can be learned from the test.scpt file.
---
### Default Functions
scpt comes with the following default functions:
- `str`: Convert value to string
- `num`: Parse string to number (`float64`)
- `bool`: Parse string to boolean
- `break`: Break out of loop (Errors if not in loop)
- `append`: Return an array with given items appended
- `exit`: Exit with given exit code
- `return`: Return value in function (Errors if not within function)
- `print`: Print using `fmt.Println()`
---
### Adding functionality:
Adding functionality is simple and requires a call to `scpt.AddFuncs()` or `scpt.AddVars()`. Here are some examples:
```go
scpt.AddFuncs(scpt.FuncMap{
"my-function": myFunction
})
```
Where `myFunction` is:
```go
func myFunction(args map[string]interface{}) (interface{}, error) {
fmt.Println(args)
return nil, nil
}
```
After the call to `scpt.AddFuncs()`, `my-function` can be used to run the function from within an scpt script. Variables work similarly.

1
ast.go
View File

@ -344,6 +344,7 @@ type Value struct {
Expr *Expression `| "{" @@ "}"` Expr *Expression `| "{" @@ "}"`
Map []*MapKVPair `| "[" (@@ ("," @@)* )? "]"` Map []*MapKVPair `| "[" (@@ ("," @@)* )? "]"`
Array []*Value `| "[" (@@ ("," @@)* )? "]"` Array []*Value `| "[" (@@ ("," @@)* )? "]"`
Opposite *Value `| "!" @@`
} }
// Bool stores boolean values encountered while parsing a script. // Bool stores boolean values encountered while parsing a script.

View File

@ -24,8 +24,8 @@ var scptLexer = lexer.Must(stateful.NewSimple([]stateful.Rule{
{"Ident", `[a-zA-Z_]\w*`, nil}, {"Ident", `[a-zA-Z_]\w*`, nil},
{"String", `"[^"]*"`, nil}, {"String", `"[^"]*"`, nil},
{"Number", `(?:\d*\.)?\d+`, nil}, {"Number", `(?:\d*\.)?\d+`, nil},
{"Punct", `[-[!@$&(){}\|:;"',.?/]|]`, nil}, {"Punct", `[![@$&(){}\|:;"',.?]|]`, nil},
{"Whitespace", `[ \t\r\n]+`, nil}, {"Whitespace", `[ \t\r\n]+`, nil},
{"Comment", `(###(.|\n)+###|#[^\n]+)`, nil}, {"Comment", `(###(.|\n)+###|#[^\n]+)`, nil},
{"Operator", `(>=|<=|>|<|==|!=)|[-+*/^%]`, nil}, {"Operator", `(>=|<=|>|<|==|!=)|[-+*%/^]`, nil},
})) }))

10
scpt.go
View File

@ -165,6 +165,16 @@ func ParseValue(val *Value) (interface{}, error) {
} }
// Return map[interface{}]interface{} // Return map[interface{}]interface{}
return iMap, nil return iMap, nil
} else if val.Opposite != nil {
value, err := callIfFunc(ParseValue(val.Opposite))
if err != nil {
return nil, err
}
boolean, ok := value.(bool)
if !ok {
return nil, errors.New("cannot take opposite of a non-boolean value")
}
return !boolean, nil
} }
return nil, nil return nil, nil
} }