Skip to content

Commit

Permalink
Add indexing for lists, strings, and literals
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchpaulus committed Sep 21, 2024
1 parent fafbd77 commit c9074fc
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 0 deletions.
36 changes: 36 additions & 0 deletions mshell-go/Evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,42 @@ func (state *EvalState) Evaluate(tokens []Token, stack *MShellStack, context Exe
}

stack.Push(&MShellString { obj.DebugString() })
} else if t.Type == INDEXER {
obj1, err := stack.Pop()
if err != nil {
return FailWithMessage(fmt.Sprintf("%d:%d: Cannot index an empty stack.\n", t.Line, t.Column))
}

// Indexer is a digit between ':' and ':'. Remove ends and parse the number
indexStr := t.Lexeme[1:len(t.Lexeme) - 1]
index, err := strconv.Atoi(indexStr)
if err != nil {
return FailWithMessage(fmt.Sprintf("%d:%d: Error parsing index: %s\n", t.Line, t.Column, err.Error()))
}

// Check if obj1 is a list, string, or literal
switch obj1.(type) {
case *MShellList:
if index < 0 || index >= len(obj1.(*MShellList).Items) {
return FailWithMessage(fmt.Sprintf("%d:%d: Index %d out of range for list of length %d.\n", t.Line, t.Column, index, len(obj1.(*MShellList).Items)))
} else {
stack.Push(obj1.(*MShellList).Items[index])
}
case *MShellString:
if index < 0 || index >= len(obj1.(*MShellString).Content) {
return FailWithMessage(fmt.Sprintf("%d:%d: Index %d out of range for string of length %d.\n", t.Line, t.Column, index, len(obj1.(*MShellString).Content)))
} else {
stack.Push(&MShellString { string(obj1.(*MShellString).Content[index]) })
}
case *MShellLiteral:
if index < 0 || index >= len(obj1.(*MShellLiteral).LiteralText) {
return FailWithMessage(fmt.Sprintf("%d:%d: Index %d out of range for literal of length %d.\n", t.Line, t.Column, index, len(obj1.(*MShellLiteral).LiteralText)))
} else {
stack.Push(&MShellString { string(obj1.(*MShellLiteral).LiteralText[index]) })
}
default:
return FailWithMessage(fmt.Sprintf("%d:%d: Cannot index a %s.\n", t.Line, t.Column, obj1.TypeName()))
}
} else {
return FailWithMessage(fmt.Sprintf("%d:%d: We haven't implemented the token type '%s' yet.\n", t.Line, t.Column, t.Type))
}
Expand Down
51 changes: 51 additions & 0 deletions mshell-go/Lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const (
INTEGER
DOUBLE
LITERAL
INDEXER
)

func (t TokenType) String() string {
Expand Down Expand Up @@ -117,6 +118,8 @@ func (t TokenType) String() string {
return "DOUBLE"
case LITERAL:
return "LITERAL"
case INDEXER:
return "INDEXER"
default:
return "UNKNOWN"
}
Expand Down Expand Up @@ -214,11 +217,59 @@ func (l *Lexer) scanToken() Token {
return l.parsePositional()
}
return l.parseLiteralOrNumber()
case ':':
return l.parseIndexerOrLiteral()
default:
return l.parseLiteralOrNumber()
}
}

func (l *Lexer) consumeLiteral() Token {
for {
if l.atEnd() {
break
}
c := l.peek()
if !unicode.IsSpace(c) && c != ']' && c != ')' && c != '<' && c != '>' && c != ';' && c != '?' {
l.advance()
} else {
break
}
}
return l.makeToken(LITERAL)
}

func (l *Lexer) parseIndexerOrLiteral() Token {
c := l.advance()

// Return literal if at end
if l.atEnd() {
return l.makeToken(LITERAL)
}

if unicode.IsDigit(c) {
// Read all the digits
for {
c = l.advance()

if l.atEnd() {
break
}
if !unicode.IsDigit(l.peek()) {
break
}
}
} else {
return l.consumeLiteral()
}

if c == ':' {
return l.makeToken(INDEXER)
} else {
return l.consumeLiteral()
}
}

func (l *Lexer) parsePositional() Token {
for {
if l.atEnd() {
Expand Down
6 changes: 6 additions & 0 deletions mshell/tests/indexing.msh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
echo
1 [1 2 3] :2: +
"My string" :3:
myliteral :4:
];
1 change: 1 addition & 0 deletions mshell/tests/indexing.msh.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4 s t

0 comments on commit c9074fc

Please sign in to comment.