about summary refs log tree commit diff
path: root/cmd
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-05-20 01:43:55 +0200
committerMel <einebeere@gmail.com>2022-05-20 01:43:55 +0200
commit20d84ae7ffd8a8e4c9397470e5b0459fec9a86ba (patch)
tree426a72eb7f78d70945f450f1756ee6bb72c2bfaa /cmd
parentabebfa047e3ef9bc8fb06d73d0d39d393e51c92c (diff)
downloadjinx-20d84ae7ffd8a8e4c9397470e5b0459fec9a86ba.tar.zst
jinx-20d84ae7ffd8a8e4c9397470e5b0459fec9a86ba.zip
Add VM cli tool
Diffstat (limited to 'cmd')
-rw-r--r--cmd/vm/main.go91
1 files changed, 91 insertions, 0 deletions
diff --git a/cmd/vm/main.go b/cmd/vm/main.go
new file mode 100644
index 0000000..b844dbc
--- /dev/null
+++ b/cmd/vm/main.go
@@ -0,0 +1,91 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"io"
+	"jinx/pkg/lang/vm"
+	"jinx/pkg/lang/vm/code"
+	"jinx/pkg/lang/vm/text"
+	"os"
+)
+
+func main() {
+	// Take the first argument as the path to the file to be parsed.
+	compile := flag.String("c", "", "compile to file (if not bytecode)")
+	run := flag.Bool("r", false, "run")
+	bytecode := flag.Bool("b", false, "interpret bytecode, without this flag the program will be interpreted in Lang VM text format.")
+
+	flag.Parse()
+
+	if *compile != "" && *bytecode {
+		exit("-c and -b are mutually exclusive")
+	}
+
+	if *bytecode && !*run {
+		exit("-b requires -r")
+	}
+
+	if *compile == "" && !*run {
+		exit("nothing to do, either -c or -r is required")
+	}
+
+	path := flag.Arg(0)
+	if path == "" {
+		exit("no file specified")
+	}
+
+	file, err := os.Open(path)
+	if err != nil {
+		exit("could not open file: %v", err)
+	}
+	defer file.Close()
+
+	var bc code.Code
+	if !*bytecode {
+		comp := text.NewCompiler(file)
+		bc, err = comp.Compile()
+		if err != nil {
+			exit("compilation failed: %v", err)
+		}
+
+		if *compile != "" {
+			output, err := os.Create(*compile)
+			if err != nil {
+				exit("could not create file: %v", err)
+			}
+			defer output.Close()
+
+			if _, err := output.Write(bc.Code()); err != nil {
+				exit("could not write to file: %v", err)
+			}
+		}
+	} else {
+		content, err := io.ReadAll(file)
+		if err != nil {
+			exit("could not read file: %v", err)
+		}
+
+		bc = code.New(content)
+	}
+
+	if *run {
+		vm := vm.New(&bc)
+		if err := vm.Run(); err != nil {
+			exit("execution failed: %v", err)
+		}
+
+		res, err := vm.GetResult()
+		if err != nil {
+			exit("could not get result: %v", err)
+		}
+
+		fmt.Println(res)
+	}
+}
+
+func exit(format string, args ...any) {
+	message := fmt.Sprintf(format, args...)
+	fmt.Printf("error: %s\n", message)
+	os.Exit(1)
+}