macro: macros seem to work
This commit is contained in:
@@ -45,12 +45,73 @@ func handleMac(l []*ast.AST, m MacroEnv) (*ast.AST, error) {
|
|||||||
params = append(params, elem.Val.(string))
|
params = append(params, elem.Val.(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
m[name] = Macro{params, l[2]}
|
m[name] = Macro{params, l[3]}
|
||||||
|
|
||||||
nilVal := ast.AST{ast.Symbol, "nil"}
|
nilVal := ast.AST{ast.Symbol, "nil"}
|
||||||
return &nilVal, 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) {
|
func traverse(l *ast.AST, m MacroEnv) (*ast.AST, error) {
|
||||||
vals := l.Val.([]*ast.AST)
|
vals := l.Val.([]*ast.AST)
|
||||||
if len(vals) == 0 {
|
if len(vals) == 0 {
|
||||||
@@ -61,6 +122,16 @@ func traverse(l *ast.AST, m MacroEnv) (*ast.AST, error) {
|
|||||||
return handleMac(vals, m)
|
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
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user