119 lines
3.0 KiB
Go
119 lines
3.0 KiB
Go
package generator
|
|
|
|
import "fmt"
|
|
import "sort"
|
|
import "errors"
|
|
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
|
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
|
|
|
|
// 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
|
|
|
|
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,
|
|
}).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,
|
|
errors.New(fmt.Sprintln("type", typeName, "not found"))
|
|
}
|
|
return this.generateTypedef(def)
|
|
}
|
|
|
|
func (this *generator) method (typeName string, name string) (*llvm.Function, error) {
|
|
for _, function := range this.module.Functions {
|
|
if function.Name() == typeName + "." + name {
|
|
return function, nil
|
|
}
|
|
}
|
|
|
|
ty, exists := this.tree.Types[typeName]
|
|
if !exists {
|
|
return nil,
|
|
errors.New(fmt.Sprintln("type", typeName, "not found"))
|
|
}
|
|
method, exists := ty.Methods[name]
|
|
if !exists {
|
|
return nil, errors.New(fmt.Sprintln (
|
|
"method", typeName + "." + name, "not found"))
|
|
}
|
|
return this.generateMethod(method)
|
|
}
|
|
|
|
func (this *generator) function (name string) (*llvm.Function, error) {
|
|
for _, function := range this.module.Functions {
|
|
if function.Name() == name {
|
|
return function, nil
|
|
}
|
|
}
|
|
function, exists := this.tree.Functions[name]
|
|
if !exists {
|
|
return nil, errors.New(fmt.Sprintln (
|
|
"function", name, "not found"))
|
|
}
|
|
return this.generateFunction(function)
|
|
}
|
|
|
|
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
|
|
}
|