aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Taskfile.yml7
-rw-r--r--cmd/compmod/compiled.tmpl22
-rw-r--r--cmd/compmod/main.go94
3 files changed, 123 insertions, 0 deletions
diff --git a/Taskfile.yml b/Taskfile.yml
index 56e26f3..a8fc876 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -9,6 +9,7 @@ tasks:
- go build -o build/bot jinx/cmd/bot
- go build -o build/vm jinx/cmd/vm
- go build -o build/lang jinx/cmd/lang
+ - go build -o build/compmod jinx/cmd/compmod
run:
desc: "Runs Jinx bot binary."
@@ -28,6 +29,12 @@ tasks:
cmds:
- build/lang {{.CLI_ARGS}}
+ run-compmod:
+ desc: "Runs built-in module compiler."
+ deps: [build]
+ cmds:
+ - build/compmod {{.CLI_ARGS}}
+
test:
desc: "Tests all packages."
cmds:
diff --git a/cmd/compmod/compiled.tmpl b/cmd/compmod/compiled.tmpl
new file mode 100644
index 0000000..2070749
--- /dev/null
+++ b/cmd/compmod/compiled.tmpl
@@ -0,0 +1,22 @@
+package {{.Module}}
+
+import (
+ "jinx/pkg/lang/modules"
+ "jinx/pkg/lang/vm/code"
+)
+
+var moduleCompiled = []byte{
+ {{.Bytes}}
+}
+
+var moduleCode = code.New(code.Raw(moduleCompiled), code.NewDebugInfo("{{.Module}}"))
+
+var Module = modules.NewModule(
+ "",
+ "{{.Module}}",
+ &moduleCode,
+ []modules.ModuleRef{},
+ []string{
+ {{range .Globals}}"{{.}}", {{end}}
+ },
+)
diff --git a/cmd/compmod/main.go b/cmd/compmod/main.go
new file mode 100644
index 0000000..7cea8ce
--- /dev/null
+++ b/cmd/compmod/main.go
@@ -0,0 +1,94 @@
+package main
+
+import (
+ _ "embed"
+ "flag"
+ "fmt"
+ "html/template"
+ "jinx/pkg/lang/compiler"
+ "jinx/pkg/lang/parser"
+ "jinx/pkg/lang/scanner"
+ "jinx/pkg/lang/vm/code"
+ "os"
+)
+
+//go:embed compiled.tmpl
+var compiledTemplateString string
+
+type compiledTemplateInfo struct {
+ Module string
+ Globals []string
+ Bytes string
+}
+
+func main() {
+ flag.Parse()
+
+ moduleName := flag.Arg(0)
+ if moduleName == "" {
+ exit("no module specified")
+ }
+
+ moduleSourcePath := fmt.Sprintf("pkg/lang/modules/%s/%s.lang", moduleName, moduleName)
+ moduleOutputPath := fmt.Sprintf("pkg/lang/modules/%s/compiled.go", moduleName)
+
+ sourceFile, err := os.Open(moduleSourcePath)
+ if err != nil {
+ exit("could not open file: %v", err)
+ }
+ defer sourceFile.Close()
+
+ scanner := scanner.New(sourceFile)
+ tokens, err := scanner.Scan()
+ if err != nil {
+ exit("error during scanning: %v", err)
+ }
+
+ parser := parser.New(tokens)
+ program, err := parser.Parse()
+ if err != nil {
+ exit("error during parsing: %v", err)
+ }
+
+ comp := compiler.New(moduleName, "", program)
+ module, err := comp.Compile()
+ if err != nil {
+ exit("compilation failed: %v", err)
+ }
+
+ code := turnCodeIntoBytes(module.Code().Code())
+
+ info := compiledTemplateInfo{
+ Module: module.Name(),
+ Globals: module.Globals(),
+ Bytes: code,
+ }
+
+ compiledTemplate, err := template.New("compiled").Parse(compiledTemplateString)
+ if err != nil {
+ exit("could not parse template: %v", err)
+ }
+
+ outputFile, err := os.Create(moduleOutputPath)
+ if err != nil {
+ exit("could not create file: %v", err)
+ }
+
+ if err := compiledTemplate.Execute(outputFile, info); err != nil {
+ exit("could not write to file: %v", err)
+ }
+}
+
+func turnCodeIntoBytes(code code.Raw) string {
+ var result string
+ for _, b := range []byte(code) {
+ result += fmt.Sprintf("0x%x, ", b)
+ }
+ return result
+}
+
+func exit(format string, args ...any) {
+ message := fmt.Sprintf(format, args...)
+ fmt.Printf("error: %s\n", message)
+ os.Exit(1)
+}