111 lines
2.2 KiB
Go
Raw Normal View History

2023-10-17 13:10:35 +00:00
package build
2023-10-17 18:29:36 +00:00
import (
"bufio"
2023-10-20 11:22:06 +00:00
"bytes"
2023-10-17 18:29:36 +00:00
"os"
"path/filepath"
2023-10-20 13:29:40 +00:00
"strings"
2023-10-17 18:29:36 +00:00
2023-10-20 13:29:40 +00:00
"git.akyoto.dev/cli/q/directory"
"git.akyoto.dev/cli/q/elf"
"git.akyoto.dev/cli/q/errors"
"git.akyoto.dev/cli/q/log"
2023-10-17 18:29:36 +00:00
)
2023-10-17 13:10:35 +00:00
// Build describes a compiler build.
type Build struct {
2023-10-20 11:22:06 +00:00
Name string
Directory string
Code bytes.Buffer
Data bytes.Buffer
2023-10-17 13:10:35 +00:00
WriteExecutable bool
}
// New creates a new build.
2023-10-20 11:22:06 +00:00
func New(directory string) *Build {
return &Build{
Name: filepath.Base(directory),
Directory: directory,
WriteExecutable: true,
}
}
// Run parses the input files and generates an executable file.
func (build *Build) Run() error {
err := build.Compile()
2023-10-17 13:10:35 +00:00
if err != nil {
2023-10-20 11:22:06 +00:00
return err
}
if build.WriteExecutable {
return writeToDisk(build.Executable(), build.Code.Bytes(), build.Data.Bytes())
2023-10-17 13:10:35 +00:00
}
2023-10-20 11:22:06 +00:00
return nil
}
// Compile compiles all the functions.
func (build *Build) Compile() error {
2023-10-20 13:29:40 +00:00
stat, err := os.Stat(build.Directory)
2023-10-19 08:14:52 +00:00
if err != nil {
2023-10-20 11:22:06 +00:00
return err
2023-10-19 08:14:52 +00:00
}
2023-10-20 13:29:40 +00:00
if !stat.IsDir() {
return &errors.InvalidDirectory{Path: build.Directory}
2023-10-19 08:14:52 +00:00
}
2023-10-20 13:29:40 +00:00
directory.Walk(build.Directory, func(file string) {
if !strings.HasSuffix(file, ".q") {
return
}
log.Info.Println(file)
})
2023-10-19 08:14:52 +00:00
2023-10-20 11:22:06 +00:00
build.Code.Write([]byte{
2023-10-19 08:14:52 +00:00
0xb8, 0x01, 0x00, 0x00, 0x00, // mov eax, 1
0xbf, 0x01, 0x00, 0x00, 0x00, // mov edi, 1
0xbe, 0xa2, 0x00, 0x40, 0x00, // mov esi, 0x4000a2
0xba, 0x06, 0x00, 0x00, 0x00, // mov edx, 6
0x0f, 0x05, // syscall
2023-10-17 18:29:36 +00:00
2023-10-19 08:14:52 +00:00
0xb8, 0x3c, 0x00, 0x00, 0x00, // mov eax, 60
0xbf, 0x00, 0x00, 0x00, 0x00, // mov edi, 0
0x0f, 0x05, // syscall
2023-10-20 11:22:06 +00:00
})
2023-10-17 18:29:36 +00:00
2023-10-20 11:22:06 +00:00
build.Data.Write([]byte{'H', 'e', 'l', 'l', 'o', '\n'})
return nil
2023-10-17 13:10:35 +00:00
}
2023-10-17 18:29:36 +00:00
2023-10-20 13:29:40 +00:00
// Executable returns the path to the executable.
func (build *Build) Executable() string {
return filepath.Join(build.Directory, build.Name)
}
2023-10-17 18:29:36 +00:00
// writeToDisk writes the executable file to disk.
2023-10-20 11:22:06 +00:00
func writeToDisk(filePath string, code []byte, data []byte) error {
2023-10-17 18:29:36 +00:00
file, err := os.Create(filePath)
if err != nil {
return err
}
buffer := bufio.NewWriter(file)
2023-10-20 11:22:06 +00:00
executable := elf.New(code, data)
2023-10-17 18:29:36 +00:00
executable.Write(buffer)
buffer.Flush()
err = file.Close()
if err != nil {
return err
}
return os.Chmod(filePath, 0755)
}