From 15e294085c1f6a5873cde6d0ec028a959f54c82a Mon Sep 17 00:00:00 2001 From: Aidan Date: Fri, 24 Jul 2020 19:58:09 -0700 Subject: [PATCH] some rudimentary list operations --- stdlib/list.go | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ stdlib/stdlib.go | 22 ++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/stdlib/list.go b/stdlib/list.go index 748414b..863718e 100644 --- a/stdlib/list.go +++ b/stdlib/list.go @@ -18,6 +18,7 @@ package stdlib import ( + "fmt" "gitlab.com/whom/shs/ast" "gitlab.com/whom/shs/log" ) @@ -28,6 +29,7 @@ import ( * in event a not-list is passed in, returns the arg. */ func Expand(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token { + input = input.Eval(funcs, vars, false) if input.Tag != ast.LIST { log.Log(log.INFO, "expand called on not a list", "expand") return input @@ -42,6 +44,7 @@ func Expand(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token * if no args are a list, a list is made from all args */ func L_append(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token { + input = input.Eval(funcs, vars, false) src := input if input.Tag != ast.LIST { @@ -68,3 +71,76 @@ func L_append(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Tok return src } + +/* Len + * Returns length of list as a number + * Returns nil if not a list + * + * Example: () -> 0 + * Example: (1 2 3) -> 3 + */ +func Len(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token { + input = input.Eval(funcs, vars, false) + if input.Tag != ast.LIST { + log.Log(log.ERR, + "non-list as parameter to head", + "head") + return nil + } + + length := 0 + for iter := input.Expand(); iter != nil; iter = iter.Next { + length += 1 + } + + ret := &ast.Token{Tag: ast.NUMBER} + ret.Set(fmt.Sprintf("%d", length)) + return ret +} + +/* Head + * Returns first element in the list + * Returns nil if input is not a list or if list is empty + * + * Example: (head (2 3 4)) -> 2 + */ +func Head(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token { + input = input.Eval(funcs, vars, false) + if input.Tag != ast.LIST { + log.Log(log.ERR, + "non-list as parameter to head", + "head") + return nil + } + + li := input.Expand().Copy() + if li != nil { + li.Next = nil + } + + return li +} + +/* Tail + * Returns last element in a list + * Returns nil if not a list + * + * Example: (tail (2 3 4)) -> 4 + */ +func Tail(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token { + input = input.Eval(funcs, vars, false) + if input.Tag != ast.LIST { + log.Log(log.ERR, + "non-list as parameter to head", + "head") + return nil + } + + + iter := input.Expand() + for iter != nil && iter.Next != nil { + iter = iter.Next + } + + return iter.Copy() +} diff --git a/stdlib/stdlib.go b/stdlib/stdlib.go index 292b7da..2479249 100644 --- a/stdlib/stdlib.go +++ b/stdlib/stdlib.go @@ -59,6 +59,28 @@ func GenFuncTable() ast.FuncTable { Args: 3, }, + "len": &ast.Function{ + Function: Len, + Name: "len", + TimesCalled: 0, + Args: 1, + }, + + "head": &ast.Function{ + Function: Head, + Name: "head", + TimesCalled: 0, + Args: 1, + }, + + "tail": &ast.Function{ + Function: Tail, + Name: "tail", + TimesCalled: 0, + Args: 1, + }, + + "export": &ast.Function{ Function: Export, Name: "export",