From 8193e5c590177b91b51acd818e8a365ab6845988 Mon Sep 17 00:00:00 2001 From: Mel Date: Thu, 11 Aug 2022 01:26:09 +0000 Subject: Add compmod tool to compile built-in modules --- Taskfile.yml | 7 ++++ cmd/compmod/compiled.tmpl | 22 +++++++++++ cmd/compmod/main.go | 94 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 cmd/compmod/compiled.tmpl create mode 100644 cmd/compmod/main.go 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) +} -- cgit 1.4.1