From 90284f2d06da32be013fef5f427a4be194b48c76 Mon Sep 17 00:00:00 2001 From: Aidan Date: Fri, 21 Aug 2020 00:14:31 -0700 Subject: [PATCH] negative number parsing --- ast/lex.go | 5 ++++ stdlib/stdlib.go | 7 +++++ stdlib/string.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/ast/lex.go b/ast/lex.go index d7db581..aa677f5 100644 --- a/ast/lex.go +++ b/ast/lex.go @@ -215,6 +215,11 @@ error: func StrIsNumber(arg string) bool { dotCount := 0 + // negative nums + if len(arg) > 0 && arg[0] == '-' { + arg = arg[1:] + } + for _, char := range arg { if !unicode.IsDigit(char) { if char == '.' && dotCount == 0 { diff --git a/stdlib/stdlib.go b/stdlib/stdlib.go index fcd0b30..699bbfb 100644 --- a/stdlib/stdlib.go +++ b/stdlib/stdlib.go @@ -157,6 +157,13 @@ func GenFuncTable() ast.FuncTable { Args: 2, }, + "substr": &ast.Function{ + Function: Substr, + Name: "substr", + TimesCalled: 0, + Args: 3, + }, + "exit": &ast.Function{ Function: ExitShell, Name: "exit", diff --git a/stdlib/string.go b/stdlib/string.go index 0cfe9f0..140600a 100644 --- a/stdlib/string.go +++ b/stdlib/string.go @@ -145,6 +145,80 @@ func Join(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { return ret } +/* takes three arguments: + * 1. start index + * 2. end index + * 3. source + * Returns a substring from source delimited by args 1 and 2. + * First two args must be integers (4 or 4.0 but not 4.3) + * + * Example: (substr 1 5 "Linus Torvalds") -> "inus " + */ +func Substr(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { + start := in.Eval(ft, vt, false) + if start == nil || start.Next == nil || start.Next.Next == nil { + log.Log(log.ERR, + "an argument evaluated to nil", + "substr") + return nil + } + + end := start.Next + str := end.Next + + if start.Tag != ast.NUMBER || end.Tag != ast.NUMBER || str.Tag != ast.STRING { + log.Log(log.ERR, + "incorrect types of args", + "substr") + return nil + } + + ed_idx := 0 + st_idx, err := strconv.Atoi(start.Value()) + ed_idx, err = strconv.Atoi(end.Value()) + if err != nil { + log.Log(log.ERR, + "error parsing args: " + err.Error(), + "substr") + return nil + } + + strlen := len(str.Value()) + if st_idx < 0 { + st_idx += strlen + } + + if ed_idx < 0 { + ed_idx += strlen + } + + if st_idx < 0 || st_idx >= strlen { + log.Log(log.ERR, + "first index out of bounds", + "substr") + return nil + } + + if ed_idx < 0 || ed_idx >= strlen { + log.Log(log.ERR, + "last index out of bounds", + "substr") + return nil + } + + if st_idx > ed_idx { + log.Log(log.ERR, + "start must be less than end", + "substr") + return nil + } + + res := str.Value()[st_idx:ed_idx] + ret := &ast.Token{Tag: ast.STRING} + ret.Set(res) + return ret +} + /* Takes one arg, returns nil * Prints a string to stdout * Unquotes string so user can add escaped chars like \n, \t, etc