macro: defining macros works
This commit is contained in:
@@ -9,6 +9,4 @@
|
|||||||
- Destructuring assignment
|
- Destructuring assignment
|
||||||
- `coerce`
|
- `coerce`
|
||||||
- `mac`
|
- `mac`
|
||||||
- `w/link`
|
|
||||||
- `aform`
|
|
||||||
- ...
|
- ...
|
||||||
|
72
macro/macro.go
Normal file
72
macro/macro.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package macro
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hellerve/argos/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Macro struct {
|
||||||
|
params []string
|
||||||
|
transformer *ast.AST
|
||||||
|
}
|
||||||
|
|
||||||
|
type MacroEnv map[string]Macro
|
||||||
|
|
||||||
|
func NewMacroEnv() MacroEnv {
|
||||||
|
return make(MacroEnv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleMac(l []*ast.AST, m MacroEnv) (*ast.AST, error) {
|
||||||
|
if len(l) != 4 {
|
||||||
|
return nil, fmt.Errorf("mac takes 3 arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
nameThunk := l[1]
|
||||||
|
|
||||||
|
if nameThunk.Tag != ast.Symbol {
|
||||||
|
return nil, fmt.Errorf("First argument to mac must be symbol, got %s", nameThunk.Pretty())
|
||||||
|
}
|
||||||
|
|
||||||
|
name := nameThunk.Val.(string)
|
||||||
|
|
||||||
|
paramsThunk := l[2]
|
||||||
|
|
||||||
|
if paramsThunk.Tag != ast.List {
|
||||||
|
return nil, fmt.Errorf("second argument to mac must be list, got %s", paramsThunk.Pretty())
|
||||||
|
}
|
||||||
|
|
||||||
|
var params []string
|
||||||
|
|
||||||
|
for _, elem := range paramsThunk.Val.([]*ast.AST) {
|
||||||
|
if elem.Tag != ast.Symbol {
|
||||||
|
return nil, fmt.Errorf("Invalid value in parameter list to mac: %s", elem.Pretty())
|
||||||
|
}
|
||||||
|
params = append(params, elem.Val.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
m[name] = Macro{params, l[2]}
|
||||||
|
|
||||||
|
nilVal := ast.AST{ast.Symbol, "nil"}
|
||||||
|
return &nilVal, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func traverse(l *ast.AST, m MacroEnv) (*ast.AST, error) {
|
||||||
|
vals := l.Val.([]*ast.AST)
|
||||||
|
if len(vals) == 0 {
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if vals[0].Tag == ast.Symbol && vals[0].Val.(string) == "mac" {
|
||||||
|
return handleMac(vals, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Expand(l *ast.AST, m MacroEnv) (*ast.AST, error) {
|
||||||
|
if l.Tag != ast.List {
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
return traverse(l, m)
|
||||||
|
}
|
21
main.go
21
main.go
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/chzyer/readline"
|
"github.com/chzyer/readline"
|
||||||
|
|
||||||
"github.com/hellerve/argos/eval"
|
"github.com/hellerve/argos/eval"
|
||||||
|
"github.com/hellerve/argos/macro"
|
||||||
"github.com/hellerve/argos/parser"
|
"github.com/hellerve/argos/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ func runRepl() {
|
|||||||
defer rl.Close()
|
defer rl.Close()
|
||||||
|
|
||||||
e := eval.RootEnv()
|
e := eval.RootEnv()
|
||||||
|
m := macro.NewMacroEnv()
|
||||||
for {
|
for {
|
||||||
input, err := rl.Readline()
|
input, err := rl.Readline()
|
||||||
|
|
||||||
@@ -46,8 +48,15 @@ func runRepl() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expanded, err := macro.Expand(parsed, m)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: how to avoid bindings on error?
|
// TODO: how to avoid bindings on error?
|
||||||
evald, err := eval.Eval(parsed, e)
|
evald, err := eval.Eval(expanded, e)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@@ -60,6 +69,7 @@ func runRepl() {
|
|||||||
|
|
||||||
func runFile(path string) {
|
func runFile(path string) {
|
||||||
e := eval.RootEnv()
|
e := eval.RootEnv()
|
||||||
|
m := macro.NewMacroEnv()
|
||||||
input, err := ioutil.ReadFile(path)
|
input, err := ioutil.ReadFile(path)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -79,7 +89,14 @@ func runFile(path string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
evald, err := eval.Eval(parsed, e)
|
expanded, err := macro.Expand(parsed, m)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
evald, err := eval.Eval(expanded, e)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
Reference in New Issue
Block a user