elysium/main.go

126 lines
2.3 KiB
Go
Raw Normal View History

2024-03-10 22:48:57 +01:00
// The compiler
package main
import (
"log"
"os"
2024-03-21 20:37:21 +01:00
"strconv"
"strings"
2024-03-10 22:48:57 +01:00
)
2024-03-24 21:36:34 +01:00
const ERROR_LOG_LINES = 5
2024-03-21 20:37:21 +01:00
func countTabs(line string) int {
tabs := 0
for _, rune := range line {
if rune == '\t' {
tabs++
}
}
return tabs
}
func printCompilerError(file string, source string, err CompilerError) {
sourceRunes := []rune(source)
lines := strings.Split(source, "\n")
line := 0
col := 0
var i uint64
for i = 0; i < err.Position; i++ {
col++
if sourceRunes[i] == '\n' {
line++
col = 0
}
}
log.Println("Failed to compile: " + err.Message + " (at " + file + ":" + strconv.Itoa(line+1) + ":" + strconv.Itoa(col+1) + ")")
linesStart := max(0, line-ERROR_LOG_LINES)
linesEnd := min(len(lines), line+ERROR_LOG_LINES+1)
for _, line := range lines[linesStart:line] {
println(strings.Replace(line, "\t", " ", -1))
}
tabs := countTabs(lines[line])
println(strings.Repeat(" ", col+tabs*3) + "v--- error occurs here ---")
for _, line := range lines[line:linesEnd] {
println(strings.Replace(line, "\t", " ", -1))
}
}
2024-03-10 22:48:57 +01:00
func main() {
if len(os.Args) != 2 {
log.Fatalln("Usage: " + os.Args[0] + " <file>")
}
2024-03-21 20:37:21 +01:00
file := os.Args[1]
content, err := os.ReadFile(file)
2024-03-10 22:48:57 +01:00
if err != nil {
log.Fatalln("Cannot open input file.", err)
}
2024-03-21 20:37:21 +01:00
source := string(content)
tokens, err := lexer(source)
2024-03-10 22:48:57 +01:00
if err != nil {
2024-03-14 16:42:22 +01:00
if c, ok := err.(CompilerError); ok {
2024-03-21 20:37:21 +01:00
printCompilerError(file, source, c)
} else {
log.Println(err)
2024-03-14 16:42:22 +01:00
}
2024-03-21 20:37:21 +01:00
return
2024-03-10 22:48:57 +01:00
}
2024-03-11 22:05:36 +01:00
log.Printf("Tokens:\n%+#v\n\n", tokens)
2024-03-13 17:17:09 +01:00
parser := Parser{Tokens: tokens}
2024-03-12 22:47:45 +01:00
parsed, err := parser.parseFile()
2024-03-11 22:05:36 +01:00
if err != nil {
2024-03-13 23:26:20 +01:00
if c, ok := err.(CompilerError); ok {
2024-03-21 20:37:21 +01:00
printCompilerError(file, source, c)
} else {
log.Println(err)
2024-03-13 23:26:20 +01:00
}
2024-03-21 20:37:21 +01:00
return
2024-03-11 22:05:36 +01:00
}
log.Printf("Parsed:\n%+#v\n\n", parsed)
2024-03-16 20:12:00 +01:00
validator := Validator{file: parsed}
errors := validator.validate()
2024-03-16 20:12:00 +01:00
if len(errors) != 0 {
for _, err = range errors {
if c, ok := err.(CompilerError); ok {
2024-03-21 20:37:21 +01:00
printCompilerError(file, source, c)
} else {
log.Println(err)
2024-03-16 20:12:00 +01:00
}
2024-03-21 20:37:21 +01:00
}
2024-03-16 20:12:00 +01:00
2024-03-21 20:37:21 +01:00
if len(errors) != 0 {
return
2024-03-16 20:12:00 +01:00
}
}
2024-03-17 19:55:28 +01:00
log.Printf("Validated:\n%+#v\n\n", parsed)
2024-03-18 21:14:28 +01:00
wat, err := backendWAT(*parsed)
if err != nil {
if c, ok := err.(CompilerError); ok {
2024-03-21 20:37:21 +01:00
printCompilerError(file, source, c)
} else {
log.Println(err)
2024-03-18 21:14:28 +01:00
}
2024-03-21 20:37:21 +01:00
return
2024-03-18 21:14:28 +01:00
}
log.Println("WAT: " + wat)
os.WriteFile("out.wat", []byte(wat), 0o644)
2024-03-10 22:48:57 +01:00
}