From 2546b2bb48f45a819ffbfec92bf4ae111854678b Mon Sep 17 00:00:00 2001 From: Mitchell Paulus Date: Wed, 18 Sep 2024 21:53:38 -0500 Subject: [PATCH] Add first translation of Evaluator --- mshell-go/Evaluator.go | 119 ++++++++++++++++++++++++++++++++++++++ mshell-go/Lexer.go | 6 +- mshell-go/MShellObject.go | 1 - mshell-go/Main.go | 2 +- 4 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 mshell-go/Evaluator.go diff --git a/mshell-go/Evaluator.go b/mshell-go/Evaluator.go new file mode 100644 index 0000000..6305c9e --- /dev/null +++ b/mshell-go/Evaluator.go @@ -0,0 +1,119 @@ +package main + +import ( + "io" + "fmt" + "os" +) + +type MShellStack []MShellObject + +func (objList MShellStack) Peek() (MShellObject, error) { + if len(objList) == 0 { + return nil, fmt.Errorf("Empty stack") + } + return objList[len(objList) - 1], nil +} + +func (objList MShellStack) Pop() (MShellObject, error) { + if len(objList) == 0 { + return nil, fmt.Errorf("Empty stack") + } + popped := objList[len(objList) - 1] + objList = objList[:len(objList) - 1] + return popped, nil +} + +func (objList MShellStack) Push(obj MShellObject) { + objList = append(objList, obj) +} + +type EvalState struct { + PositionalArgs[] string + LoopDepth int32 + + // private Dictionary _variables = new(); + Variables map[string]MShellObject +} + +type EvalResult struct { + Success bool + BreakNum int32 +} + +type ExecuteContext struct { + StandardInput io.Reader + StandardOutput io.Writer +} + +func SimpleSuccess() EvalResult { + return EvalResult { true, -1 } +} + +func FailWithMessage(message string) EvalResult { + // Log message to stderr + fmt.Fprintf(os.Stderr, message) + return EvalResult { false, -1 } +} + +func (state EvalState) Evaluate(tokens []Token, stack MShellStack, context ExecuteContext) EvalResult { + index := 0 + + // Need a stack of integers + // quotationStack := []int32{} + leftSquareBracketStack := []int{} + + for index < len(tokens) { + t := tokens[index] + index++ + + if t.Type == EOF { + return SimpleSuccess() + } else if t.Type == LITERAL { + stack.Push(&MShellLiteral { t.Lexeme }) + } else if t.Type == LEFT_SQUARE_BRACKET { + leftSquareBracketStack = append(leftSquareBracketStack, index) + + for { + currentToken := tokens[index] + index++ + + if index >= len(tokens) || tokens[index].Type == EOF { + return FailWithMessage(fmt.Sprintf("%d:%d: Found unbalanced bracket.\n", currentToken.Line, currentToken.Column)) + } + + if tokens[index].Type == LEFT_SQUARE_BRACKET { + leftSquareBracketStack = append(leftSquareBracketStack, index) + } else if tokens[index].Type == RIGHT_SQUARE_BRACKET { + if len(leftSquareBracketStack) > 0 { + leftIndex := leftSquareBracketStack[len(leftSquareBracketStack)-1] + + if len(leftSquareBracketStack) == 0 { + listStack := []MShellObject{} + tokensWithinList := tokens[leftIndex + 1:index - leftIndex - 1] + result := state.Evaluate(tokensWithinList, listStack, context) + if !result.Success { + return result + } + + if result.BreakNum > 0 { + return FailWithMessage("Encountered break within list.\n") + } + + l := &MShellList { listStack, nil, nil } + stack.Push(l) + break + } + + } else { + return FailWithMessage(fmt.Sprintf("%d:%d: Found unbalanced square bracket.\n", currentToken.Line, currentToken.Column)) + } + } + } + } else { + return FailWithMessage(fmt.Sprintf("%d:%d: We haven't implemented the token type '%s' yet.\n", t.Line, t.Column, t.Type)) + } + } + + return EvalResult { true, -1 } +} diff --git a/mshell-go/Lexer.go b/mshell-go/Lexer.go index 89f8c66..44bc7e9 100644 --- a/mshell-go/Lexer.go +++ b/mshell-go/Lexer.go @@ -127,7 +127,7 @@ type Token struct { Column int Start int Lexeme string - TokenType TokenType + Type TokenType } type Lexer struct { @@ -156,7 +156,7 @@ func (l *Lexer) makeToken(tokenType TokenType) Token { Column: l.col, Start: l.start, Lexeme: lexeme, - TokenType: tokenType, + Type: tokenType, } } @@ -333,7 +333,7 @@ func (l *Lexer) Tokenize() []Token { for { t := l.scanToken() tokens = append(tokens, t) - if t.TokenType == ERROR || t.TokenType == EOF { + if t.Type == ERROR || t.Type == EOF { break } } diff --git a/mshell-go/MShellObject.go b/mshell-go/MShellObject.go index 7fc045f..a879b84 100644 --- a/mshell-go/MShellObject.go +++ b/mshell-go/MShellObject.go @@ -236,4 +236,3 @@ func (obj *MShellPipe) DebugString() string { // Join each item with a ' | ' return strings.Join(DebugStrs(obj.List.Items), " | ") } - diff --git a/mshell-go/Main.go b/mshell-go/Main.go index e2ad1fe..7e1d1c0 100644 --- a/mshell-go/Main.go +++ b/mshell-go/Main.go @@ -60,7 +60,7 @@ func main() { fmt.Println("Tokens:") for _, t := range tokens { // Console.Write($"{t.Line}:{t.Column}:{t.TokenType} {t.RawText}\n"); - fmt.Printf("%d:%d:%s %s\n", t.Line, t.Column, t.TokenType, t.Lexeme) + fmt.Printf("%d:%d:%s %s\n", t.Line, t.Column, t.Type, t.Lexeme) } return }