all: add quasiquoting
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
- Destructuring assignment
|
||||
- `coerce`
|
||||
- `mac`
|
||||
- `````
|
||||
- `w/link`
|
||||
- `aform`
|
||||
- ...
|
||||
|
45
eval/eval.go
45
eval/eval.go
@@ -524,6 +524,49 @@ func evalMapTable(l []*ast.AST, e ast.Env) (*ast.AST, error) {
|
||||
return "ed, 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 "edLst, 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":
|
||||
|
@@ -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{"e, 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 "(":
|
||||
{
|
||||
|
Reference in New Issue
Block a user