From 9e3d37ae016936f206bf0de59a9a115685e2b220 Mon Sep 17 00:00:00 2001 From: jesperkha Date: Thu, 25 Nov 2021 22:16:33 +0100 Subject: [PATCH] Moved run to main and fixed binary parsing bug --- README.md | 2 +- expr/parse.go | 8 +++ go.mod | 2 + go.sum | 7 +++ run/interp.go => interp.go | 2 +- main.go | 4 +- run.go | 114 +++++++++++++++++++++++++++++++++++++ run/file.go | 26 --------- run/run.go | 52 ----------------- run/terminal.go | 44 -------------- stmt/parse.go | 7 ++- todo.txt | 6 -- 12 files changed, 138 insertions(+), 136 deletions(-) create mode 100644 go.sum rename run/interp.go => interp.go (99%) create mode 100644 run.go delete mode 100644 run/file.go delete mode 100644 run/run.go delete mode 100644 run/terminal.go delete mode 100644 todo.txt diff --git a/README.md b/README.md index 30fa04f..261d129 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This roadmap highlights progress for Fizz's development: - ✔️ Expression parsing - ✔️ Conditional statements - ✔️ Loops -- ❌ Functions +- ✔️ Functions - ❌ Classes - ❌ Arrays - ❌ File import diff --git a/expr/parse.go b/expr/parse.go index 33e60f2..2588f51 100644 --- a/expr/parse.go +++ b/expr/parse.go @@ -181,6 +181,14 @@ func parsePTokens(tokens []ParseToken) *Expression { } } + // Invalid expression might have lowest as end token + // Move to middle and let evaluation handle error + if lowestIdx == len(tokens) - 1 { + newIdx := int(len(tokens)/2) + lowestIdx = newIdx + lowest = tokens[lowestIdx].Token + } + right, left := parsePTokens(tokens[lowestIdx+1:]), parsePTokens(tokens[:lowestIdx]) return &Expression{Type: Binary, Line: line, Operand: lowest, Left: left, Right: right} } diff --git a/go.mod b/go.mod index 9364c57..40ee8ba 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/jesperkha/Fizz go 1.16 + +require github.com/daviddengcn/go-colortext v1.0.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..861c058 --- /dev/null +++ b/go.sum @@ -0,0 +1,7 @@ +github.com/daviddengcn/go-colortext v1.0.0 h1:ANqDyC0ys6qCSvuEK7l3g5RaehL/Xck9EX8ATG8oKsE= +github.com/daviddengcn/go-colortext v1.0.0/go.mod h1:zDqEI5NVUop5QPpVJUxE9UO10hRnmkD5G4Pmri9+m4c= +github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= +github.com/golangplus/bytes v1.0.0/go.mod h1:AdRaCFwmc/00ZzELMWb01soso6W1R/++O1XL80yAn+A= +github.com/golangplus/fmt v1.0.0/go.mod h1:zpM0OfbMCjPtd2qkTD/jX2MgiFCqklhSUFyDW44gVQE= +github.com/golangplus/testing v1.0.0 h1:+ZeeiKZENNOMkTTELoSySazi+XaEhVO0mb+eanrSEUQ= +github.com/golangplus/testing v1.0.0/go.mod h1:ZDreixUV3YzhoVraIDyOzHrr76p6NUh6k/pPg/Q3gYA= diff --git a/run/interp.go b/interp.go similarity index 99% rename from run/interp.go rename to interp.go index 20d8694..0d24df4 100644 --- a/run/interp.go +++ b/interp.go @@ -1,4 +1,4 @@ -package run +package main import ( "github.com/jesperkha/Fizz/lexer" diff --git a/main.go b/main.go index 68d991e..c69604c 100644 --- a/main.go +++ b/main.go @@ -2,10 +2,8 @@ package main import ( "os" - - "github.com/jesperkha/Fizz/run" ) func main() { - run.RunInterpeter(os.Args) + RunInterpeter(os.Args) } diff --git a/run.go b/run.go new file mode 100644 index 0000000..a375ecf --- /dev/null +++ b/run.go @@ -0,0 +1,114 @@ +package main + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "os" + "strings" + + ct "github.com/daviddengcn/go-colortext" +) + +var ( + ErrFileNotFound = errors.New("cannot find file with name: '%s'") + ErrNonFizzFile = errors.New("cannot run non-Fizz file") +) + +var cmdOptions = map[string]func(){ + "help": func() { + fmt.Println("use: fizz [filename.fizz | --option]") + }, +} + +func RunInterpeter(args []string) { + if len(args) == 2 { + arg := args[1] + + // Run option commands + if strings.HasPrefix(arg, "--") { + option, ok := cmdOptions[strings.TrimLeft(arg, "-")] + if !ok { + formatError(fmt.Errorf("unknown option: '%s'", arg)) + return + } + + option() + } + + // Run fizz file + filename := args[1] + if !strings.HasSuffix(filename, ".fizz") { + filename += ".fizz" + } + + if err := runFile(filename); err != nil { + formatError(err) + } + + return + } + + // Run terminal mode + runTerminal() +} + +// Prints errors with red color to terminal +func formatError(err error) { + ct.Foreground(ct.Red, true) + fmt.Println(err.Error()) + ct.ResetColor() +} + +// Leaves the interpreter running as the user inputs code to the terminal. +// Prints out errors but does not terminate until ^C or 'exit'. +func runTerminal() { + scanner := bufio.NewScanner(os.Stdin) + totalString := "" + numBlocks := 0 + indent := " " + + fmt.Println("type 'exit' to terminate session") + for { + fmt.Print("::: " + strings.Repeat(indent, numBlocks)) + scanner.Scan() + input := scanner.Text() + + if input == "exit" { + break + } + + // Continue with indent after braces + numBlocks += strings.Count(input, "{") - strings.Count(input, "}") + totalString += input + "\n" // Better error handling + + if numBlocks <= 0 { + err := Interperate(totalString) + if err != nil { + formatError(err) + } + + totalString = "" + numBlocks = 0 + } + } + + fmt.Println("session ended") +} + +// Interperates code found in file specified in commandline arguments +func runFile(filename string) (err error) { + if !strings.HasSuffix(filename, ".fizz") { + return ErrNonFizzFile + } + + if file, err := os.Open(filename); err == nil { + var buf bytes.Buffer + bufio.NewReader(file).WriteTo(&buf) + return Interperate(buf.String()) + } + + // Assumes path error + return fmt.Errorf(ErrFileNotFound.Error(), filename) +} diff --git a/run/file.go b/run/file.go deleted file mode 100644 index a95a30c..0000000 --- a/run/file.go +++ /dev/null @@ -1,26 +0,0 @@ -package run - -import ( - "bufio" - "bytes" - "fmt" - "os" - "strings" -) - -// Interperates code found in file specified in commandline arguments -func RunFile(filename string) (err error) { - if !strings.HasSuffix(filename, ".fizz") { - return ErrNonFizzFile - } - - if file, err := os.Open(filename); err == nil { - var buf bytes.Buffer - bufio.NewReader(file).WriteTo(&buf) - - return Interperate(buf.String()) - } - - // Assumes path error - return fmt.Errorf(ErrFileNotFound.Error(), filename) -} diff --git a/run/run.go b/run/run.go deleted file mode 100644 index 633f1f3..0000000 --- a/run/run.go +++ /dev/null @@ -1,52 +0,0 @@ -package run - -import ( - "errors" - "fmt" - "strings" -) - -// Todo: Move this to main - -var ( - ErrFileNotFound = errors.New("cannot find file with name: '%s'") - ErrNonFizzFile = errors.New("cannot run non-Fizz file") -) - -var cmdOptions = map[string]func(){ - "help": func() { - fmt.Println("use: fizz [filename.fizz | --option]") - }, -} - -func RunInterpeter(args []string) { - if len(args) == 2 { - arg := args[1] - - // Run option commands - if strings.HasPrefix(arg, "--") { - if opt, ok := cmdOptions[strings.TrimLeft(arg, "-")]; ok { - opt() - return - } - - fmt.Printf("unknown option: '%s'\n", arg) - return - } - - // Run fizz file - filename := args[1] - if !strings.HasSuffix(filename, ".fizz") { - filename += ".fizz" - } - - if err := RunFile(filename); err != nil { - fmt.Println(err) - } - - return - } - - // Run terminal mode - RunTerminal() -} diff --git a/run/terminal.go b/run/terminal.go deleted file mode 100644 index cc5ff69..0000000 --- a/run/terminal.go +++ /dev/null @@ -1,44 +0,0 @@ -package run - -import ( - "bufio" - "fmt" - "os" - "strings" -) - -// Leaves the interpreter running as the user inputs code to the terminal. -// Prints out errors but does not terminate until ^C or 'exit'. -func RunTerminal() { - scanner := bufio.NewScanner(os.Stdin) - totalString := "" - numBlocks := 0 - indent := " " - - fmt.Println("type 'exit' to terminate session") - for { - fmt.Print("::: " + strings.Repeat(indent, numBlocks)) - scanner.Scan() - input := scanner.Text() - - if input == "exit" { - break - } - - // Continue with indent after braces - numBlocks += strings.Count(input, "{") - strings.Count(input, "}") - totalString += input + "\n" // Better error handling - - if numBlocks <= 0 { - err := Interperate(totalString) - if err != nil { - fmt.Println(err.Error() + "\n") - } - - totalString = "" - numBlocks = 0 - } - } - - fmt.Println("session ended") -} diff --git a/stmt/parse.go b/stmt/parse.go index 9200ec3..2238deb 100644 --- a/stmt/parse.go +++ b/stmt/parse.go @@ -191,21 +191,22 @@ func parseFunc(tokens []lexer.Token, idx *int) (stmt Statement, err error) { if len(tokens) < 6 { return stmt, ErrInvalidStatement } - + nameToken := tokens[*idx+1] if nameToken.Type != lexer.IDENTIFIER || tokens[*idx+2].Type != lexer.LEFT_PAREN { return stmt, ErrInvalidStatement // Missing identifier or block } - + *idx += 3 // Skip to start of param list endIdx, eof := seekToken(tokens, *idx, lexer.RIGHT_PAREN) if eof { return stmt, ErrInvalidStatement } - + // Get param names params := []string{} for _, p := range tokens[*idx:endIdx] { + // Todo: Add actual comma separation for function declarations switch p.Type { case lexer.COMMA: continue diff --git a/todo.txt b/todo.txt deleted file mode 100644 index ba3a2d7..0000000 --- a/todo.txt +++ /dev/null @@ -1,6 +0,0 @@ -Fix int to float64 conversion issue for function return values -Add actual comma separation for function declarations - -Rework -stmt/exec + stmt errors -expr/* \ No newline at end of file