parser: add comments and [...]; main: add file mode
This commit is contained in:
@@ -27,7 +27,6 @@
|
|||||||
- `each`
|
- `each`
|
||||||
- `while`
|
- `while`
|
||||||
- `repeat`
|
- `repeat`
|
||||||
- `[...]`
|
|
||||||
- `:`
|
- `:`
|
||||||
- `~`
|
- `~`
|
||||||
- `keep`
|
- `keep`
|
||||||
|
48
main.go
48
main.go
@@ -2,7 +2,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/chzyer/readline"
|
"github.com/chzyer/readline"
|
||||||
@@ -11,7 +13,7 @@ import (
|
|||||||
"github.com/hellerve/argos/parser"
|
"github.com/hellerve/argos/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func runRepl() {
|
||||||
rl, err := readline.New("argos> ")
|
rl, err := readline.New("argos> ")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -22,13 +24,13 @@ func main() {
|
|||||||
|
|
||||||
e := eval.ParentEnv()
|
e := eval.ParentEnv()
|
||||||
for {
|
for {
|
||||||
prompt, err := rl.Readline()
|
input, err := rl.Readline()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parsed, err, unconsumed := parser.Parse(prompt)
|
parsed, err, unconsumed := parser.Parse(input)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@@ -52,3 +54,43 @@ func main() {
|
|||||||
fmt.Println(evald.Pretty())
|
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])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package parser
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -18,8 +19,18 @@ func withoutEmpty(input []string) []string {
|
|||||||
return r
|
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 {
|
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) {
|
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:]
|
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) {
|
func parseToken(input []string) (*ast.AST, error, []string) {
|
||||||
if len(input) == 0 {
|
if len(input) == 0 {
|
||||||
return nil, errors.New("Unmatched '('"), input
|
return nil, errors.New("Unmatched '(' or '['"), input
|
||||||
}
|
}
|
||||||
|
|
||||||
if input[0][0] == '\'' {
|
if input[0][0] == '\'' {
|
||||||
@@ -94,6 +112,25 @@ func parseToken(input []string) (*ast.AST, error, []string) {
|
|||||||
case ")": {
|
case ")": {
|
||||||
return nil, errors.New("Unmatched ')'"), input
|
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)
|
return parseValue(input)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user