parser: add comments and [...]; main: add file mode

This commit is contained in:
2018-05-14 00:37:14 +02:00
parent 3386ec0c4b
commit 8cb7c37096
3 changed files with 84 additions and 6 deletions

View File

@@ -27,7 +27,6 @@
- `each`
- `while`
- `repeat`
- `[...]`
- `:`
- `~`
- `keep`

48
main.go
View File

@@ -2,7 +2,9 @@ package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"github.com/chzyer/readline"
@@ -11,7 +13,7 @@ import (
"github.com/hellerve/argos/parser"
)
func main() {
func runRepl() {
rl, err := readline.New("argos> ")
if err != nil {
@@ -22,13 +24,13 @@ func main() {
e := eval.ParentEnv()
for {
prompt, err := rl.Readline()
input, err := rl.Readline()
if err != nil {
return
}
parsed, err, unconsumed := parser.Parse(prompt)
parsed, err, unconsumed := parser.Parse(input)
if err != nil {
fmt.Println(err)
@@ -52,3 +54,43 @@ func main() {
fmt.Println(evald.Pretty())
}
}
func runFile(path string) {
e := eval.ParentEnv()
input, err := ioutil.ReadFile(path)
if err != nil {
fmt.Println(err)
return
}
parsed, err, unconsumed := parser.Parse(string(input))
if err != nil {
fmt.Println(err)
return
}
if len(unconsumed) != 0 {
fmt.Println("Unconsumed input:", strings.Join(unconsumed, " "))
return
}
evald, err := eval.Eval(parsed, e)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(evald.Pretty())
}
func main() {
args := os.Args
if len(args) == 1 {
runRepl()
} else {
runFile(os.Args[1])
}
}

View File

@@ -2,6 +2,7 @@ package parser
import (
"errors"
"regexp"
"strconv"
"strings"
@@ -18,8 +19,18 @@ func withoutEmpty(input []string) []string {
return r
}
var comments = regexp.MustCompile(";.*")
var whitespace = regexp.MustCompile("\\s")
func explode(s string, start string, end string) string {
return strings.Replace(strings.Replace(s, start, " "+start+" ", -1), end, " "+end+" ", -1)
}
func tokenize(input string) []string {
return withoutEmpty(strings.Split(strings.Replace(strings.Replace(input, "(", " ( ", -1), ")", " ) ", -1), " "))
withoutComments := string(comments.ReplaceAll([]byte(input), []byte("")))
explodedParens := explode(withoutComments, "(", ")")
explodedBrackets := explode(explodedParens, "[", "]")
return withoutEmpty(whitespace.Split(explodedBrackets, -1))
}
func parseValue(input []string) (*ast.AST, error, []string) {
@@ -53,9 +64,16 @@ func parseValue(input []string) (*ast.AST, error, []string) {
return &res, nil, input[1:]
}
func makeFn(bodyStatements []ast.AST) ast.AST {
body := ast.AST{ast.List, bodyStatements}
args := ast.AST{ast.List, []ast.AST{ast.AST{ast.Symbol, "_"}}}
return ast.AST{ast.List, []ast.AST{ast.AST{ast.Symbol, "fn"}, args, body}}
}
func parseToken(input []string) (*ast.AST, error, []string) {
if len(input) == 0 {
return nil, errors.New("Unmatched '('"), input
return nil, errors.New("Unmatched '(' or '['"), input
}
if input[0][0] == '\'' {
@@ -94,6 +112,25 @@ func parseToken(input []string) (*ast.AST, error, []string) {
case ")": {
return nil, errors.New("Unmatched ')'"), input
}
case "[": {
var l []ast.AST
input = input[1:]
for input[0] != "]" {
elem, err, newInput := parseToken(input)
if err != nil {
return nil, err, input
}
l = append(l, *elem)
input = newInput
}
res := makeFn(l)
return &res, nil, input[1:]
}
case "]": {
return nil, errors.New("Unmatched ']'"), input
}
}
return parseValue(input)
}