package generator import "sort" import "git.tebibyte.media/fspl/fspl/llvm" import "git.tebibyte.media/fspl/fspl/entity" import "git.tebibyte.media/fspl/fspl/analyzer" type errNotFound string func (err errNotFound) Error () string { return string(err) + " 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. Values must correspond // directly to those recognized by LLVM in a target triple. Arch string // OS specifies the machine operating system. Values must correspond // directly to those recognized by LLVM in a target triple. OS string } type generator struct { target Target tree analyzer.Tree module *llvm.Module types map[entity.Key] llvm.Type functions map[entity.Key] *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, types: make(map[entity.Key] llvm.Type), functions: make(map[entity.Key] *llvm.Function), }).generate() } func (this *generator) generate () (*llvm.Module, error) { // generate functions functions := sortKeyedMapKeys(this.tree.Functions) for _, key := range functions { _, err := this.function(key) if err != nil { return nil, err } } // generate methods types := sortKeyedMapKeys(this.tree.Types) for _, key := range types { ty := this.tree.Types[key] methods := sortMapKeys(ty.Methods) for _, methodName := range methods { methodKey := key methodKey.Method = methodName _, err := this.method(methodKey) if err != nil { return nil, err } } } return this.module, nil } func (this *generator) typedef (key entity.Key) (llvm.Type, error) { ty, exists := this.types[key] if exists { return ty, nil } def, exists := this.tree.Types[key] if !exists { return nil, errNotFound("typedef " + key.String()) } return this.generateTypedef(def) } func (this *generator) method (key entity.Key) (*llvm.Function, error) { method, exists := this.functions[key] if exists { return method, nil } ty, exists := this.tree.Types[key.StripMethod()] if !exists { return nil, errNotFound("owner of method " + key.String()) } if method, exists := ty.Methods[key.Method]; exists { return this.generateMethod(method) } return nil, errNotFound("method " + key.String()) } func (this *generator) function (key entity.Key) (*llvm.Function, error) { function, exists := this.functions[key] if exists { return function, nil } if function, exists := this.tree.Functions[key]; exists { return this.generateFunction(function) } return nil, errNotFound("function " + key.String()) } 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 } type keySlice []entity.Key func (keys keySlice) Len () int { return len(keys) } func (keys keySlice) Less (lefti, righti int) bool { left := keys[lefti] right := keys[righti] return left.String() < right.String() } func (keys keySlice) Swap (lefti, righti int) { keys[lefti], keys[righti] = keys[righti], keys[lefti] } func sortKeyedMapKeys[T any] (unsorted map[entity.Key] T) keySlice { keys := make(keySlice, len(unsorted)) index := 0 for key := range unsorted { keys[index] = key index ++ } sort.Sort(keys) return keys }