fspl/generator/generator.go

113 lines
2.8 KiB
Go

package generator
import "sort"
import "errors"
import "git.tebibyte.media/sashakoshka/fspl/llvm"
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
var errNotFound = errors.New("entity not found")
// Target contains information about the machine the code is being written for.
type Target struct {
// WordSize is the size of the machine word. This determines the width
// of the Word type.
WordSize uint64
// Arch specifies the machine architecture
Arch string
}
type generator struct {
target Target
tree analyzer.Tree
module *llvm.Module
functions map[string] *llvm.Function
managerStack []*blockManager
blockManager *blockManager
}
// Generate takes in a semantic tree and writes corresponding LLVM IR to the
// given io.Writer. It returns an error in case there is something wrong with
// the semantic tree that prevents the code generation process from occurring.
func (this Target) Generate (tree analyzer.Tree) (*llvm.Module, error) {
return (&generator {
module: new(llvm.Module),
target: this,
tree: tree,
functions: make(map[string] *llvm.Function),
}).generate()
}
func (this *generator) generate () (*llvm.Module, error) {
// generate functions
functions := sortMapKeys(this.tree.Functions)
for _, functionName := range functions {
_, err := this.function(functionName)
if err != nil { return nil, err }
}
// generate methods
types := sortMapKeys(this.tree.Types)
for _, typeName := range types {
ty := this.tree.Types[typeName]
methods := sortMapKeys(ty.Methods)
for _, methodName := range methods {
_, err := this.method(typeName, methodName)
if err != nil { return nil, err }
}
}
return this.module, nil
}
func (this *generator) typedef (typeName string) (llvm.Type, error) {
for _, ty := range this.module.Types {
if ty.Name() == typeName {
return ty, nil
}
}
def, exists := this.tree.Types[typeName]
if !exists {
return nil, errNotFound
}
return this.generateTypedef(def)
}
func (this *generator) method (typeName string, name string) (*llvm.Function, error) {
method, exists := this.functions[typeName + "." + name]
if exists { return method, nil }
ty, exists := this.tree.Types[typeName]
if !exists {
return nil, errNotFound
}
if method, exists := ty.Methods[name]; exists {
return this.generateMethod(method)
}
return nil, errNotFound
}
func (this *generator) function (name string) (*llvm.Function, error) {
function, exists := this.functions[name]
if exists { return function, nil }
if function, exists := this.tree.Functions[name]; exists {
return this.generateFunction(function)
}
return nil, errNotFound
}
func sortMapKeys[T any] (unsorted map[string] T) []string {
keys := make([]string, len(unsorted))
index := 0
for key := range unsorted {
keys[index] = key
index ++
}
sort.Strings(keys)
return keys
}