all: add optional args
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
- Destructuring assignment
|
||||
- `maptable`
|
||||
- `coerce`
|
||||
- `o`
|
||||
- `len`
|
||||
- `mac`
|
||||
- `\``
|
||||
|
22
ast/ast.go
22
ast/ast.go
@@ -3,6 +3,8 @@ package ast
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cevaris/ordered_map"
|
||||
)
|
||||
|
||||
type AST struct {
|
||||
@@ -88,9 +90,10 @@ func (ast *AST) Pretty() string {
|
||||
agg = append(agg, elem)
|
||||
}
|
||||
opt := ""
|
||||
if val.HasOpt() {
|
||||
opt = " . " + *val.Opt
|
||||
if val.HasRest() {
|
||||
opt = " . " + *val.Rest
|
||||
}
|
||||
// TODO: opt
|
||||
body := val.Body.Pretty()
|
||||
return "(fn (" + strings.Join(agg, " ") + opt + ") " + body + ")"
|
||||
} else if ast.Tag == Char {
|
||||
@@ -121,12 +124,12 @@ type Primitive struct {
|
||||
Fn PrimFn
|
||||
}
|
||||
|
||||
func newEnv(parent *Env) Env {
|
||||
func NewEnv(parent *Env) Env {
|
||||
return Env{parent, make(map[string]*AST)}
|
||||
}
|
||||
|
||||
func ParentEnv() Env {
|
||||
return newEnv(nil)
|
||||
return NewEnv(nil)
|
||||
}
|
||||
|
||||
func (e *Env) Lookup(elem string) (*AST, error) {
|
||||
@@ -145,11 +148,16 @@ func (e *Env) Lookup(elem string) (*AST, error) {
|
||||
|
||||
type Func struct {
|
||||
Params []string
|
||||
Opt *string
|
||||
Rest *string
|
||||
Opt *ordered_map.OrderedMap
|
||||
Body *AST
|
||||
Env Env
|
||||
}
|
||||
|
||||
func (f *Func) HasOpt() bool {
|
||||
return f.Opt != nil
|
||||
func (f *Func) HasRest() bool {
|
||||
return f.Rest != nil
|
||||
}
|
||||
|
||||
func (f *Func) HasOpt() bool {
|
||||
return f.Opt.Len() != 0
|
||||
}
|
||||
|
45
eval/eval.go
45
eval/eval.go
@@ -6,6 +6,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cevaris/ordered_map"
|
||||
|
||||
"github.com/hellerve/argos/ast"
|
||||
)
|
||||
|
||||
@@ -264,18 +266,34 @@ func evalFn(input []*ast.AST, e ast.Env) (*ast.AST, error) {
|
||||
}
|
||||
|
||||
var argsStr []string
|
||||
var opt *string = nil
|
||||
var rest *string = nil
|
||||
opt := ordered_map.NewOrderedMap()
|
||||
|
||||
argslst := args.Val.([]*ast.AST)
|
||||
for i, a := range argslst {
|
||||
if a.Tag != ast.Symbol {
|
||||
if a.Tag != ast.Symbol && a.Tag != ast.List {
|
||||
return nil, fmt.Errorf("Argument list cannot contain %s", a.Pretty())
|
||||
}
|
||||
|
||||
if a.Tag == ast.List {
|
||||
argv := a.Val.([]*ast.AST)
|
||||
argvln := len(argv)
|
||||
if (argvln != 3 && argvln != 2) || argv[0].Tag != ast.Symbol || argv[0].Val.(string) != "o" || argv[0].Tag != ast.Symbol {
|
||||
return nil, fmt.Errorf("Argument list cannot contain %s", a.Pretty())
|
||||
}
|
||||
if argvln == 2 {
|
||||
opt.Set(argv[1].Val.(string), nil)
|
||||
} else if argvln == 3 {
|
||||
opt.Set(argv[1].Val.(string), argv[2])
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
val := a.Val.(string)
|
||||
// TODO: error handling
|
||||
if val == "." {
|
||||
str := argslst[i+1].Val.(string)
|
||||
opt = &str
|
||||
rest = &str
|
||||
break
|
||||
}
|
||||
|
||||
@@ -284,7 +302,9 @@ func evalFn(input []*ast.AST, e ast.Env) (*ast.AST, error) {
|
||||
|
||||
body := input[1]
|
||||
|
||||
res := ast.AST{ast.Fn, ast.Func{argsStr, opt, body, e}}
|
||||
fe := ast.NewEnv(&e)
|
||||
|
||||
res := ast.AST{ast.Fn, ast.Func{argsStr, rest, opt, body, fe}}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
@@ -292,7 +312,7 @@ func funcApply(f ast.Func, args []*ast.AST, e ast.Env) (*ast.AST, error) {
|
||||
plen := len(f.Params)
|
||||
alen := len(args)
|
||||
|
||||
if plen != alen && !f.HasOpt() {
|
||||
if plen != alen && !f.HasRest() && !f.HasOpt() {
|
||||
return nil, fmt.Errorf("Function expected %d arguments, was called with %d.", plen, alen)
|
||||
}
|
||||
|
||||
@@ -300,10 +320,21 @@ func funcApply(f ast.Func, args []*ast.AST, e ast.Env) (*ast.AST, error) {
|
||||
f.Env.Values[a] = args[i]
|
||||
}
|
||||
|
||||
if f.HasOpt() {
|
||||
if f.HasRest() {
|
||||
lst := ast.AST{ast.List, args[plen:]}
|
||||
quoted := ast.AST{ast.Quoted, &lst}
|
||||
f.Env.Values[*f.Opt] = "ed
|
||||
f.Env.Values[*f.Rest] = "ed
|
||||
} else {
|
||||
iter := f.Opt.IterFunc()
|
||||
i := plen
|
||||
for kv, ok := iter(); ok; kv, ok = iter() {
|
||||
if i < alen {
|
||||
f.Env.Values[kv.Key.(string)] = args[i]
|
||||
} else {
|
||||
f.Env.Values[kv.Key.(string)] = kv.Value.(*ast.AST)
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
return Eval(f.Body, f.Env)
|
||||
|
Reference in New Issue
Block a user