added slice function

This commit is contained in:
Aidan 2020-07-24 20:32:08 -07:00
parent 15e294085c
commit adff10b56a
No known key found for this signature in database
GPG key ID: 327711E983899316
2 changed files with 107 additions and 0 deletions

View file

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