all: add optional args
This commit is contained in:
@@ -9,7 +9,6 @@
|
|||||||
- Destructuring assignment
|
- Destructuring assignment
|
||||||
- `maptable`
|
- `maptable`
|
||||||
- `coerce`
|
- `coerce`
|
||||||
- `o`
|
|
||||||
- `len`
|
- `len`
|
||||||
- `mac`
|
- `mac`
|
||||||
- `\``
|
- `\``
|
||||||
|
22
ast/ast.go
22
ast/ast.go
@@ -3,6 +3,8 @@ package ast
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cevaris/ordered_map"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AST struct {
|
type AST struct {
|
||||||
@@ -88,9 +90,10 @@ func (ast *AST) Pretty() string {
|
|||||||
agg = append(agg, elem)
|
agg = append(agg, elem)
|
||||||
}
|
}
|
||||||
opt := ""
|
opt := ""
|
||||||
if val.HasOpt() {
|
if val.HasRest() {
|
||||||
opt = " . " + *val.Opt
|
opt = " . " + *val.Rest
|
||||||
}
|
}
|
||||||
|
// TODO: opt
|
||||||
body := val.Body.Pretty()
|
body := val.Body.Pretty()
|
||||||
return "(fn (" + strings.Join(agg, " ") + opt + ") " + body + ")"
|
return "(fn (" + strings.Join(agg, " ") + opt + ") " + body + ")"
|
||||||
} else if ast.Tag == Char {
|
} else if ast.Tag == Char {
|
||||||
@@ -121,12 +124,12 @@ type Primitive struct {
|
|||||||
Fn PrimFn
|
Fn PrimFn
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEnv(parent *Env) Env {
|
func NewEnv(parent *Env) Env {
|
||||||
return Env{parent, make(map[string]*AST)}
|
return Env{parent, make(map[string]*AST)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParentEnv() Env {
|
func ParentEnv() Env {
|
||||||
return newEnv(nil)
|
return NewEnv(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Env) Lookup(elem string) (*AST, error) {
|
func (e *Env) Lookup(elem string) (*AST, error) {
|
||||||
@@ -145,11 +148,16 @@ func (e *Env) Lookup(elem string) (*AST, error) {
|
|||||||
|
|
||||||
type Func struct {
|
type Func struct {
|
||||||
Params []string
|
Params []string
|
||||||
Opt *string
|
Rest *string
|
||||||
|
Opt *ordered_map.OrderedMap
|
||||||
Body *AST
|
Body *AST
|
||||||
Env Env
|
Env Env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Func) HasOpt() bool {
|
func (f *Func) HasRest() bool {
|
||||||
return f.Opt != nil
|
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"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cevaris/ordered_map"
|
||||||
|
|
||||||
"github.com/hellerve/argos/ast"
|
"github.com/hellerve/argos/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -264,18 +266,34 @@ func evalFn(input []*ast.AST, e ast.Env) (*ast.AST, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var argsStr []string
|
var argsStr []string
|
||||||
var opt *string = nil
|
var rest *string = nil
|
||||||
|
opt := ordered_map.NewOrderedMap()
|
||||||
|
|
||||||
argslst := args.Val.([]*ast.AST)
|
argslst := args.Val.([]*ast.AST)
|
||||||
for i, a := range argslst {
|
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())
|
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)
|
val := a.Val.(string)
|
||||||
// TODO: error handling
|
// TODO: error handling
|
||||||
if val == "." {
|
if val == "." {
|
||||||
str := argslst[i+1].Val.(string)
|
str := argslst[i+1].Val.(string)
|
||||||
opt = &str
|
rest = &str
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +302,9 @@ func evalFn(input []*ast.AST, e ast.Env) (*ast.AST, error) {
|
|||||||
|
|
||||||
body := input[1]
|
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
|
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)
|
plen := len(f.Params)
|
||||||
alen := len(args)
|
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)
|
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]
|
f.Env.Values[a] = args[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.HasOpt() {
|
if f.HasRest() {
|
||||||
lst := ast.AST{ast.List, args[plen:]}
|
lst := ast.AST{ast.List, args[plen:]}
|
||||||
quoted := ast.AST{ast.Quoted, &lst}
|
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)
|
return Eval(f.Body, f.Env)
|
||||||
|
Reference in New Issue
Block a user