diff --git a/mshell/Lexer.go b/mshell/Lexer.go index 8657e22..318e1cf 100644 --- a/mshell/Lexer.go +++ b/mshell/Lexer.go @@ -321,6 +321,16 @@ func (l *Lexer) scanToken() Token { } else { return l.makeToken(STDOUTLINES) } + case '-': + if unicode.IsDigit(l.peek()) { + // Consume the hyphen and parse the number + l.advance() + return l.parseNumberOrStartIndexer() + } else if unicode.IsSpace(l.peek()) { + return l.makeToken(MINUS) + } else { + return l.consumeLiteral() + } default: return l.parseLiteralOrNumber() } @@ -376,7 +386,20 @@ func (l *Lexer) parseNumberOrStartIndexer() Token { l.advance() c := l.peek() - if unicode.IsDigit(c) { + if c == '-' { + if unicode.IsDigit(l.peekNext()) { + l.advance() // Consume the hyphen + for { + if !unicode.IsDigit(l.peek()) { + break + } + l.advance() + } + return l.makeToken(SLICEINDEXER) + } else { + return l.makeToken(STARTINDEXER) + } + } else if unicode.IsDigit(c) { // Read all the digits for { if l.atEnd() { @@ -411,7 +434,7 @@ func (l *Lexer) parseIndexerOrLiteral() Token { return l.makeToken(LITERAL) } - if unicode.IsDigit(c) { + if unicode.IsDigit(c) || c == '-' { // Read all the digits for { if l.atEnd() { @@ -539,6 +562,12 @@ func (l *Lexer) parseLiteralOrNumber() Token { if strings.HasPrefix(literal, "@") { return l.makeToken(VARRETRIEVE) } + // Currently here to handle the negative start indexer case. '-3:' + if strings.HasSuffix(literal, ":") { + if _, err := strconv.Atoi(literal[:len(literal)-1]); err == nil { + return l.makeToken(STARTINDEXER) + } + } if _, err := strconv.Atoi(literal); err == nil { return l.makeToken(INTEGER) } @@ -568,7 +597,7 @@ func (l *Lexer) eatWhitespace() { } c := l.peek() switch c { - case ' ', '\t', '\r': + case ' ', '\t', '\r', '\v', '\f': l.advance() case '#': for !l.atEnd() && l.peek() != '\n' { diff --git a/mshell/MShellObject.go b/mshell/MShellObject.go index de3a63c..587da50 100644 --- a/mshell/MShellObject.go +++ b/mshell/MShellObject.go @@ -387,6 +387,10 @@ func IndexCheckExc(index int, length int, obj MShellObject) error { // Index func (obj *MShellLiteral) Index(index int) (MShellObject, error) { + if index < 0 { + index = len(obj.LiteralText) + index + } + if err := IndexCheck(index, len(obj.LiteralText), obj); err != nil { return nil, err } @@ -398,6 +402,9 @@ func (obj *MShellBool) Index(index int) (MShellObject, error) { } func (obj *MShellQuotation) Index(index int) (MShellObject, error) { + if index < 0 { + index = len(obj.Tokens) + index + } if err := IndexCheck(index, len(obj.Tokens), obj); err != nil { return nil, err } @@ -405,6 +412,10 @@ func (obj *MShellQuotation) Index(index int) (MShellObject, error) { } func (obj *MShellList) Index(index int) (MShellObject, error) { + if index < 0 { + index = len(obj.Items) + index + } + if err := IndexCheck(index, len(obj.Items), obj); err != nil { return nil, err } @@ -412,6 +423,10 @@ func (obj *MShellList) Index(index int) (MShellObject, error) { } func (obj *MShellString) Index(index int) (MShellObject, error) { + if index < 0 { + index = len(obj.Content) + index + } + if err := IndexCheck(index, len(obj.Content), obj); err != nil { return nil, err } @@ -419,6 +434,10 @@ func (obj *MShellString) Index(index int) (MShellObject, error) { } func (obj *MShellPipe) Index(index int) (MShellObject, error) { + if index < 0 { + index = len(obj.List.Items) + index + } + if err := IndexCheck(index, len(obj.List.Items), obj); err != nil { return nil, err } @@ -435,6 +454,10 @@ func (obj *MShellSimple) Index(index int) (MShellObject, error) { // SliceStart func (obj *MShellLiteral) SliceStart(start int) (MShellObject, error) { + if start < 0 { + start = len(obj.LiteralText) + start + } + if err := IndexCheck(start, len(obj.LiteralText), obj); err != nil { return nil, err } @@ -446,6 +469,9 @@ func (obj *MShellBool) SliceStart(start int) (MShellObject, error) { } func (obj *MShellQuotation) SliceStart(start int) (MShellObject, error) { + if start < 0 { + start = len(obj.Tokens) + start + } if err := IndexCheck(start, len(obj.Tokens), obj); err != nil { return nil, err } @@ -453,6 +479,9 @@ func (obj *MShellQuotation) SliceStart(start int) (MShellObject, error) { } func (obj *MShellList) SliceStart(start int) (MShellObject, error) { + if start < 0 { + start = len(obj.Items) + start + } if err := IndexCheck(start, len(obj.Items), obj); err != nil { return nil, err } @@ -460,6 +489,9 @@ func (obj *MShellList) SliceStart(start int) (MShellObject, error) { } func (obj *MShellString) SliceStart(start int) (MShellObject, error) { + if start < 0 { + start = len(obj.Content) + start + } if err := IndexCheck(start, len(obj.Content), obj); err != nil { return nil, err } @@ -467,6 +499,9 @@ func (obj *MShellString) SliceStart(start int) (MShellObject, error) { } func (obj *MShellPipe) SliceStart(start int) (MShellObject, error) { + if start < 0 { + start = len(obj.List.Items) + start + } if err := IndexCheck(start, len(obj.List.Items), obj); err != nil { return nil, err } @@ -483,6 +518,10 @@ func (obj *MShellSimple) SliceStart(start int) (MShellObject, error) { // SliceEnd func (obj *MShellLiteral) SliceEnd(end int) (MShellObject, error) { + if end < 0 { + end = len(obj.LiteralText) + end + } + if err := IndexCheckExc(end, len(obj.LiteralText), obj); err != nil { return nil, err } @@ -494,6 +533,9 @@ func (obj *MShellBool) SliceEnd(end int) (MShellObject, error) { } func (obj *MShellQuotation) SliceEnd(end int) (MShellObject, error) { + if end < 0 { + end = len(obj.Tokens) + end + } if err := IndexCheckExc(end, len(obj.Tokens), obj); err != nil { return nil, err } @@ -501,6 +543,9 @@ func (obj *MShellQuotation) SliceEnd(end int) (MShellObject, error) { } func (obj *MShellList) SliceEnd(end int) (MShellObject, error) { + if end < 0 { + end = len(obj.Items) + end + } if err := IndexCheckExc(end, len(obj.Items), obj); err != nil { return nil, err } @@ -508,6 +553,9 @@ func (obj *MShellList) SliceEnd(end int) (MShellObject, error) { } func (obj *MShellString) SliceEnd(end int) (MShellObject, error) { + if end < 0 { + end = len(obj.Content) + end + } if err := IndexCheckExc(end, len(obj.Content), obj); err != nil { return nil, err } @@ -515,6 +563,9 @@ func (obj *MShellString) SliceEnd(end int) (MShellObject, error) { } func (obj *MShellPipe) SliceEnd(end int) (MShellObject, error) { + if end < 0 { + end = len(obj.List.Items) + end + } if err := IndexCheckExc(end, len(obj.List.Items), obj); err != nil { return nil, err } @@ -530,8 +581,15 @@ func (obj *MShellSimple) SliceEnd(end int) (MShellObject, error) { } // Slice - func SliceIndexCheck(startInc int, endExc int, length int, obj MShellObject) error { + if startInc < 0 { + startInc = length + startInc + } + + if endExc < 0 { + endExc = length + endExc + } + if startInc < 0 || startInc > endExc || endExc > length { return fmt.Errorf("Invalid slice range [%d:%d) for %s with length %d.\n", startInc, endExc, obj.TypeName(), length) } else { @@ -540,6 +598,14 @@ func SliceIndexCheck(startInc int, endExc int, length int, obj MShellObject) err } func (obj *MShellLiteral) Slice(startInc int, endExc int) (MShellObject, error) { + if startInc < 0 { + startInc = len(obj.LiteralText) + startInc + } + + if endExc < 0 { + endExc = len(obj.LiteralText) + endExc + } + if err := SliceIndexCheck(startInc, endExc, len(obj.LiteralText), obj); err != nil { return nil, err } @@ -551,6 +617,14 @@ func (obj *MShellBool) Slice(startInc int, endExc int) (MShellObject, error) { } func (obj *MShellQuotation) Slice(startInc int, endExc int) (MShellObject, error) { + if startInc < 0 { + startInc = len(obj.Tokens) + startInc + } + + if endExc < 0 { + endExc = len(obj.Tokens) + endExc + } + if err := SliceIndexCheck(startInc, endExc, len(obj.Tokens), obj); err != nil { return nil, err } @@ -558,6 +632,14 @@ func (obj *MShellQuotation) Slice(startInc int, endExc int) (MShellObject, error } func (obj *MShellList) Slice(startInc int, endExc int) (MShellObject, error) { + if startInc < 0 { + startInc = len(obj.Items) + startInc + } + + if endExc < 0 { + endExc = len(obj.Items) + endExc + } + if err := SliceIndexCheck(startInc, endExc, len(obj.Items), obj); err != nil { return nil, err } @@ -565,6 +647,14 @@ func (obj *MShellList) Slice(startInc int, endExc int) (MShellObject, error) { } func (obj *MShellString) Slice(startInc int, endExc int) (MShellObject, error) { + if startInc < 0 { + startInc = len(obj.Content) + startInc + } + + if endExc < 0 { + endExc = len(obj.Content) + endExc + } + if err := SliceIndexCheck(startInc, endExc, len(obj.Content), obj); err != nil { return nil, err } @@ -572,6 +662,14 @@ func (obj *MShellString) Slice(startInc int, endExc int) (MShellObject, error) { } func (obj *MShellPipe) Slice(startInc int, endExc int) (MShellObject, error) { + if startInc < 0 { + startInc = len(obj.List.Items) + startInc + } + + if endExc < 0 { + endExc = len(obj.List.Items) + endExc + } + if err := SliceIndexCheck(startInc, endExc, len(obj.List.Items), obj); err != nil { return nil, err } diff --git a/mshell/mshell b/mshell/mshell index 033d5e4..201033f 100755 Binary files a/mshell/mshell and b/mshell/mshell differ diff --git a/tests/indexing.msh b/tests/indexing.msh index aaaa985..ef41eb7 100644 --- a/tests/indexing.msh +++ b/tests/indexing.msh @@ -13,3 +13,9 @@ echo [ echo "Another" 3: ]; [ echo "Full Range" 1:3]; + +# Negative indexing +"12345" :-1: wl # 5 +"12345" -3: wl # 345 +"12345" :-4 wl # 1 +"12345" -4:-2 wl # 23 diff --git a/tests/indexing.msh.stdout b/tests/indexing.msh.stdout index aacfaa1..b574bda 100644 --- a/tests/indexing.msh.stdout +++ b/tests/indexing.msh.stdout @@ -2,3 +2,7 @@ My st ther ul +5 +345 +1 +23