Files
sointu/compiler/compiler.go
Veikko Sariola 7f049acf88 feat(cli): Re-engineer CLIs, split play & compile
Play depends on bridge and compile on compiler package. Before, the compiler depended on bridge, but we could not use the compiler to build the library, as the bridge depends on the library. Also, play can now start having slightly more options e.g. wav out etc.
2020-12-18 20:25:49 +02:00

85 lines
2.8 KiB
Go

package compiler
import (
"bytes"
"fmt"
"path"
"path/filepath"
"runtime"
"text/template"
"github.com/Masterminds/sprig"
"github.com/vsariola/sointu"
)
type Compiler struct {
Template *template.Template
OS string
Arch string
}
// New returns a new compiler using the default .asm templates
func New(os string, arch string) (*Compiler, error) {
_, myname, _, _ := runtime.Caller(0)
templateDir := filepath.Join(path.Dir(myname), "..", "templates")
compiler, err := NewFromTemplates(os, arch, templateDir)
return compiler, err
}
func NewFromTemplates(os string, arch string, templateDirectory string) (*Compiler, error) {
globPtrn := filepath.Join(templateDirectory, "*.*")
tmpl, err := template.New("base").Funcs(sprig.TxtFuncMap()).ParseGlob(globPtrn)
if err != nil {
return nil, fmt.Errorf(`could not create template based on directory "%v": %v`, templateDirectory, err)
}
return &Compiler{Template: tmpl, OS: os, Arch: arch}, nil
}
func (com *Compiler) Library() (map[string]string, error) {
if com.Arch != "386" && com.Arch != "amd64" {
return nil, fmt.Errorf(`compiling as a library is supported only on 386 and amd64 architectures (targeted architecture was %v)`, com.Arch)
}
templates := []string{"library.asm", "library.h"}
features := AllFeatures{}
retmap := map[string]string{}
for _, templateName := range templates {
macros := NewMacros(*com, features)
macros.Library = true
populatedTemplate, extension, err := com.compile(templateName, macros)
if err != nil {
return nil, fmt.Errorf(`could not execute template "%v": %v`, templateName, err)
}
retmap[extension] = populatedTemplate
}
return retmap, nil
}
func (com *Compiler) Song(song *sointu.Song) (map[string]string, error) {
if com.Arch != "386" && com.Arch != "amd64" {
return nil, fmt.Errorf(`compiling a song player is supported only on 386 and amd64 architectures (targeted architecture was %v)`, com.Arch)
}
templates := []string{"player.asm", "player.h"}
features := NecessaryFeaturesFor(song.Patch)
retmap := map[string]string{}
encodedPatch, err := Encode(&song.Patch, features)
if err != nil {
return nil, fmt.Errorf(`could not encode patch: %v`, err)
}
for _, templateName := range templates {
macros := NewPlayerMacros(*com, features, song, encodedPatch)
populatedTemplate, extension, err := com.compile(templateName, macros)
if err != nil {
return nil, fmt.Errorf(`could not execute template "%v": %v`, templateName, err)
}
retmap[extension] = populatedTemplate
}
return retmap, nil
}
func (com *Compiler) compile(templateName string, data interface{}) (string, string, error) {
result := bytes.NewBufferString("")
err := com.Template.ExecuteTemplate(result, templateName, data)
extension := filepath.Ext(templateName)
return result.String(), extension, err
}