about summary refs log tree commit diff
path: root/cmd
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-08-11 01:26:09 +0000
committerMel <einebeere@gmail.com>2022-08-11 01:26:09 +0000
commit8193e5c590177b91b51acd818e8a365ab6845988 (patch)
tree24716cf6ff5fbc9b34dca416350f93da90a6ed21 /cmd
parent86f31acf6789be116dcc54ed85b069a37c0f7aa8 (diff)
downloadjinx-8193e5c590177b91b51acd818e8a365ab6845988.tar.zst
jinx-8193e5c590177b91b51acd818e8a365ab6845988.zip
Add compmod tool to compile built-in modules
Diffstat (limited to 'cmd')
-rw-r--r--cmd/compmod/compiled.tmpl22
-rw-r--r--cmd/compmod/main.go94
2 files changed, 116 insertions, 0 deletions
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)
+}