From a1369594233b97974c820be3b646873291ad8441 Mon Sep 17 00:00:00 2001 From: hellerve Date: Tue, 15 May 2018 00:51:03 +0200 Subject: [PATCH] macro: macros seem to work --- macro/macro.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/macro/macro.go b/macro/macro.go index f3a8901..e1f6a45 100644 --- a/macro/macro.go +++ b/macro/macro.go @@ -45,12 +45,73 @@ func handleMac(l []*ast.AST, m MacroEnv) (*ast.AST, error) { params = append(params, elem.Val.(string)) } - m[name] = Macro{params, l[2]} + m[name] = Macro{params, l[3]} nilVal := ast.AST{ast.Symbol, "nil"} return &nilVal, nil } +func transformList(l []*ast.AST, args map[string]*ast.AST) (*ast.AST, error) { + var res []*ast.AST + + for _, elem := range l { + transformed, err := doTransform(elem, args) + + if err != nil { + return nil, err + } + + res = append(res, transformed) + } + + lst := ast.AST{ast.List, res} + + return &lst, nil +} + +func doTransform(transformer *ast.AST, args map[string]*ast.AST) (*ast.AST, error) { + switch transformer.Tag { + case ast.List: + lst := transformer.Val.([]*ast.AST) + if len(lst) > 0 && lst[0].Tag == ast.Symbol && lst[0].Val.(string) == "list" { + return transformList(lst[1:], args) + } + if len(lst) > 0 && lst[0].Tag == ast.Symbol && lst[0].Val.(string) == "quote" { + return lst[1], nil + } + return transformer, nil + case ast.Quoted: + return transformer.Val.(*ast.AST), nil + case ast.Symbol: + key := transformer.Val.(string) + val, ok := args[key] + if !ok { + return nil, fmt.Errorf("Unbound symbol %s", key) + } + return val, nil + } + return transformer, nil +} + +func transform(l *ast.AST, macro Macro, m MacroEnv) (*ast.AST, error) { + args := make(map[string]*ast.AST) + vals := l.Val.([]*ast.AST)[1:] + + if len(vals) != len(macro.params) { + return nil, fmt.Errorf("Wrong number of arguments to macro") + } + + for i, arg := range vals { + expanded, err := Expand(arg, m) + if err != nil { + return nil, err + } + args[macro.params[i]] = expanded + } + + return doTransform(macro.transformer, args) +} + func traverse(l *ast.AST, m MacroEnv) (*ast.AST, error) { vals := l.Val.([]*ast.AST) if len(vals) == 0 { @@ -61,6 +122,16 @@ func traverse(l *ast.AST, m MacroEnv) (*ast.AST, error) { return handleMac(vals, m) } + if vals[0].Tag == ast.Symbol { + sym := vals[0].Val.(string) + + macro, ok := m[sym] + + if ok { + return transform(l, macro, m) + } + } + return l, nil }