From adff10b56a77cd39463f24abd0d1bdd42a93fff4 Mon Sep 17 00:00:00 2001 From: Aidan Date: Fri, 24 Jul 2020 20:32:08 -0700 Subject: [PATCH] added slice function --- stdlib/list.go | 101 +++++++++++++++++++++++++++++++++++++++++++++++ stdlib/stdlib.go | 6 +++ 2 files changed, 107 insertions(+) diff --git a/stdlib/list.go b/stdlib/list.go index 863718e..8f5d35e 100644 --- a/stdlib/list.go +++ b/stdlib/list.go @@ -19,6 +19,7 @@ package stdlib import ( "fmt" + "strconv" "gitlab.com/whom/shs/ast" "gitlab.com/whom/shs/log" ) @@ -144,3 +145,103 @@ func Tail(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token { return iter.Copy() } + +/* Slice + * Takes 3 args and returns a list + * Arg 1: starting index of sublist + * Arg 2: end index of sublist + * Arg 3: source list + * returns sublist, or nil if non list applied, or nil if start or end arent INTEGERS + * first index in a list is 0 + * + * Example: (slice 1 2 (1 2 3)) -> (2 3) + * Example: (slice 0 0 (1 2 3)) -> (1) + */ +func Slice(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token { + input = input.Eval(funcs, vars, false) + start := input + end := input.Next + source := end.Next + + if start.Tag != ast.NUMBER || end.Tag != ast.NUMBER { + log.Log(log.ERR, + "start and end must both be integers", + "slice") + return nil + } + + if source.Tag != ast.LIST { + log.Log(log.ERR, + "non-list as parameter to head", + "head") + return nil + } + + st, err := strconv.ParseInt(start.Value(), 10, 64) + en, errr := strconv.ParseInt(end.Value(), 10, 64) + + if err != nil { + log.Log(log.ERR, + "couldnt parse integer from start value: " + err.Error(), + "slice") + return nil + } + + if errr != nil { + log.Log(log.ERR, + "couldnt parse integer from end value: " + errr.Error(), + "slice") + return nil + } + + if st < 0 || en < 0 { + log.Log(log.ERR, + "both indices must be positive", + "slice") + return nil + } + + if st > en { + log.Log(log.ERR, + "end index must be greater than start index", + "slice") + return nil + } + + en = en - st + var inner *ast.Token + buildIter := &inner + sourceIter := source.Expand() + + for st > 0 { + if sourceIter == nil { + log.Log(log.ERR, + "start index out of bounds", + "slice") + return nil + } + + sourceIter = sourceIter.Next + st -= 1 + } + + for en >= 0 { + if sourceIter == nil { + log.Log(log.ERR, + "end index out of bounds", + "slice") + return nil + } + + *buildIter = sourceIter.Copy() + (*buildIter).Next = nil + + buildIter = &((*buildIter).Next) + sourceIter = sourceIter.Next + en -= 1 + } + + ret := &ast.Token{Tag: ast.LIST} + ret.Direct(inner) + return ret +} diff --git a/stdlib/stdlib.go b/stdlib/stdlib.go index 2479249..9080b15 100644 --- a/stdlib/stdlib.go +++ b/stdlib/stdlib.go @@ -80,6 +80,12 @@ func GenFuncTable() ast.FuncTable { Args: 1, }, + "slice": &ast.Function{ + Function: Slice, + Name: "slice", + TimesCalled: 0, + Args: 3, + }, "export": &ast.Function{ Function: Export,