elysium/main.go

126 lines
2.3 KiB
Go

// The compiler
package main
import (
"log"
"os"
"strconv"
"strings"
)
const ERROR_LOG_LINES = 5
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))
}
}
func main() {
if len(os.Args) != 2 {
log.Fatalln("Usage: " + os.Args[0] + " <file>")
}
file := os.Args[1]
content, err := os.ReadFile(file)
if err != nil {
log.Fatalln("Cannot open input file.", err)
}
source := string(content)
tokens, err := lexer(source)
if err != nil {
if c, ok := err.(CompilerError); ok {
printCompilerError(file, source, c)
} else {
log.Println(err)
}
return
}
log.Printf("Tokens:\n%+#v\n\n", tokens)
parser := Parser{Tokens: tokens}
parsed, err := parser.parseFile()
if err != nil {
if c, ok := err.(CompilerError); ok {
printCompilerError(file, source, c)
} else {
log.Println(err)
}
return
}
log.Printf("Parsed:\n%+#v\n\n", parsed)
validator := Validator{file: parsed}
errors := validator.validate()
if len(errors) != 0 {
for _, err = range errors {
if c, ok := err.(CompilerError); ok {
printCompilerError(file, source, c)
} else {
log.Println(err)
}
}
if len(errors) != 0 {
return
}
}
log.Printf("Validated:\n%+#v\n\n", parsed)
wat, err := backendWAT(*parsed)
if err != nil {
if c, ok := err.(CompilerError); ok {
printCompilerError(file, source, c)
} else {
log.Println(err)
}
return
}
log.Println("WAT: " + wat)
os.WriteFile("out.wat", []byte(wat), 0o644)
}