package build import ( "bufio" "bytes" "os" "path/filepath" "git.akyoto.dev/cli/q/build/elf" "git.akyoto.dev/cli/q/cli/log" ) // Build describes a compiler build. type Build struct { Name string Directory string Code bytes.Buffer Data bytes.Buffer WriteExecutable bool } // New creates a new build. 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() if err != nil { return err } if build.WriteExecutable { return writeToDisk(build.Executable(), build.Code.Bytes(), build.Data.Bytes()) } return nil } // Executable returns the path to the executable. func (build *Build) Executable() string { return filepath.Join(build.Directory, build.Name) } // Compile compiles all the functions. func (build *Build) Compile() error { file, err := os.Open(build.Directory) if err != nil { return err } defer file.Close() files, err := file.Readdirnames(0) if err != nil { return err } for _, name := range files { log.Info.Println(name) } build.Code.Write([]byte{ 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 0xb8, 0x3c, 0x00, 0x00, 0x00, // mov eax, 60 0xbf, 0x00, 0x00, 0x00, 0x00, // mov edi, 0 0x0f, 0x05, // syscall }) build.Data.Write([]byte{'H', 'e', 'l', 'l', 'o', '\n'}) return nil } // writeToDisk writes the executable file to disk. func writeToDisk(filePath string, code []byte, data []byte) error { file, err := os.Create(filePath) if err != nil { return err } buffer := bufio.NewWriter(file) executable := elf.New(code, data) executable.Write(buffer) buffer.Flush() err = file.Close() if err != nil { return err } return os.Chmod(filePath, 0755) }