all: add optional args

This commit is contained in:
2018-05-14 21:48:44 +02:00
parent fae99aedd8
commit ac880c26a6
4 changed files with 139 additions and 101 deletions

View File

@@ -9,7 +9,6 @@
- Destructuring assignment
- `maptable`
- `coerce`
- `o`
- `len`
- `mac`
- `\``

View File

@@ -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
}

View File

@@ -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] = &quoted
f.Env.Values[*f.Rest] = &quoted
} 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)