Skip to content

Commit

Permalink
Add negative indexing
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchpaulus committed Nov 17, 2024
1 parent 90bc339 commit 8a73668
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 4 deletions.
35 changes: 32 additions & 3 deletions mshell/Lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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' {
Expand Down
100 changes: 99 additions & 1 deletion mshell/MShellObject.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -398,27 +402,42 @@ 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
}
return &MShellQuotation{Tokens: []MShellParseItem{obj.Tokens[index]}}, nil
}

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
}
return obj.Items[index], nil
}

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
}
return &MShellString{Content: string(obj.Content[index])}, nil
}

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
}
Expand All @@ -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
}
Expand All @@ -446,27 +469,39 @@ 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
}
return &MShellQuotation{Tokens: obj.Tokens[start:]}, nil
}

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
}
return &MShellList{Items: obj.Items[start:]}, nil
}

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
}
return &MShellString{Content: obj.Content[start:]}, nil
}

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
}
Expand All @@ -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
}
Expand All @@ -494,27 +533,39 @@ 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
}
return &MShellQuotation{Tokens: obj.Tokens[:end]}, nil
}

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
}
return &MShellList{Items: obj.Items[:end]}, nil
}

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
}
return &MShellString{Content: obj.Content[:end]}, nil
}

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
}
Expand All @@ -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 {
Expand All @@ -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
}
Expand All @@ -551,27 +617,59 @@ 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
}
return &MShellQuotation{Tokens: obj.Tokens[startInc:endExc]}, nil
}

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
}
return &MShellList{Items: obj.Items[startInc:endExc]}, nil
}

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
}
return &MShellString{Content: obj.Content[startInc:endExc]}, nil
}

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
}
Expand Down
Binary file modified mshell/mshell
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/indexing.msh
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 4 additions & 0 deletions tests/indexing.msh.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
My st
ther
ul
5
345
1
23

0 comments on commit 8a73668

Please sign in to comment.