all: add quasiquoting

This commit is contained in:
2018-05-14 23:25:39 +02:00
parent a3a84dcb98
commit c873602cfd
3 changed files with 75 additions and 1 deletions

View File

@@ -9,7 +9,6 @@
- Destructuring assignment
- `coerce`
- `mac`
- `````
- `w/link`
- `aform`
- ...

View File

@@ -524,6 +524,49 @@ func evalMapTable(l []*ast.AST, e ast.Env) (*ast.AST, error) {
return &quoted, nil
}
func evalQuasiquote(l []*ast.AST, e ast.Env) (*ast.AST, error) {
err := checkArity(l, 1, "quasiquote")
if err != nil {
return nil, err
}
arg := l[0]
if arg.Tag != ast.List {
return nil, fmt.Errorf("Argument to quasiquote needs to be list, got %s", arg.Pretty())
}
var res []*ast.AST
for _, elem := range arg.Val.([]*ast.AST) {
if elem.Tag != ast.List {
res = append(res, elem)
continue
}
lst := elem.Val.([]*ast.AST)
if lst[0].Tag != ast.Symbol && lst[0].Val.(string) == "unquote" {
res = append(res, elem)
continue
}
if len(lst) != 2 {
return nil, fmt.Errorf("Unquote takes one argument.")
}
value, err := Eval(lst[1], e)
if err != nil {
return nil, err
}
res = append(res, value)
}
lst := ast.AST{ast.List, res}
quotedLst := ast.AST{ast.Quoted, &lst}
return &quotedLst, nil
}
func evalSymbolList(l []*ast.AST, e ast.Env) (*ast.AST, error) {
sym := l[0].Val.(string)
@@ -540,6 +583,8 @@ func evalSymbolList(l []*ast.AST, e ast.Env) (*ast.AST, error) {
lst := l[0]
res := ast.AST{ast.Quoted, lst}
return &res, nil
case "quasiquote":
return evalQuasiquote(l, e)
case "fn":
return evalFn(l, e)
case "if":

View File

@@ -145,6 +145,36 @@ func parseToken(input []string) (*ast.AST, error, []string) {
return &res, nil, input
}
if input[0] == "`" {
input = input[1:]
tmp, err, input := parseToken(input)
if err != nil {
return nil, err, input
}
quote := ast.AST{ast.Symbol, "quasiquote"}
res := ast.AST{ast.List, []*ast.AST{&quote, tmp}}
return &res, nil, input
}
if input[0][0] == '@' {
if input[0] == "@" {
input = input[1:]
} else {
input = append([]string{input[0][1:]}, input[1:]...)
}
tmp, err, input := parseToken(input)
if err != nil {
return nil, err, input
}
unquote := ast.AST{ast.Symbol, "unqote"}
res := ast.AST{ast.List, []*ast.AST{&unquote, tmp}}
return &res, nil, input
}
switch input[0] {
case "(":
{