Merge pull request 'os-native-filepaths' (#75) from os-native-filepaths into main
Reviewed-on: #75
This commit is contained in:
commit
08eedaf74d
|
@ -3,30 +3,23 @@ package main
|
|||
import "os"
|
||||
import "io"
|
||||
import "fmt"
|
||||
import "path/filepath"
|
||||
import "git.tebibyte.media/fspl/fspl/cli"
|
||||
import "git.tebibyte.media/fspl/fspl/entity"
|
||||
import "git.tebibyte.media/fspl/fspl/compiler"
|
||||
import ferrors "git.tebibyte.media/fspl/fspl/errors"
|
||||
import "git.tebibyte.media/fspl/fspl/compiler/native"
|
||||
|
||||
func main () {
|
||||
// instantiate the compiler
|
||||
// FIXME: perhaps we want different paths on Windows?
|
||||
comp := new(compiler.Compiler)
|
||||
comp.Writer = os.Stderr
|
||||
comp.Resolver = compiler.NewResolver (
|
||||
"/usr/local/src/fspl",
|
||||
"/usr/src/fspl",
|
||||
"/usr/local/incude/fspl",
|
||||
"/usr/include/fspl")
|
||||
homeDir, err := os.UserHomeDir()
|
||||
|
||||
resolver, err := native.NativeResolver()
|
||||
if err != nil {
|
||||
comp.Errorln(err)
|
||||
os.Exit(2)
|
||||
}
|
||||
comp.Resolver.AddPathFront (
|
||||
filepath.Join(homeDir, ".local/src/fspl"),
|
||||
filepath.Join(homeDir, ".local/include/fspl"))
|
||||
comp.Resolver = resolver
|
||||
|
||||
// take in CLI flags
|
||||
debug := cli.NewFlag (
|
||||
|
@ -54,6 +47,13 @@ func main () {
|
|||
'O', "optimization",
|
||||
"Optimization level (0-3)", "0",
|
||||
cli.NewValSet("0", "1", "2", "3"))
|
||||
includePath := cli.NewInputFlag (
|
||||
'u', "unit-directory",
|
||||
"Extra directory(s) to search for units in", "",
|
||||
cli.ValString)
|
||||
includePath.Found = func (application *cli.Cli, value string) {
|
||||
comp.Resolver.AddPathFront(value)
|
||||
}
|
||||
|
||||
application := cli.New (
|
||||
"Compile FSPL source files",
|
||||
|
@ -62,7 +62,8 @@ func main () {
|
|||
quiet,
|
||||
filetype,
|
||||
output,
|
||||
optimization)
|
||||
optimization,
|
||||
includePath)
|
||||
|
||||
application.Syntax = "[OPTION]... ADDRESS"
|
||||
application.ParseOrExit(os.Args)
|
||||
|
|
|
@ -11,6 +11,7 @@ import "path/filepath"
|
|||
import "git.tebibyte.media/fspl/fspl/entity"
|
||||
import "git.tebibyte.media/fspl/fspl/errors"
|
||||
import "git.tebibyte.media/fspl/fspl/testcommon"
|
||||
import "git.tebibyte.media/fspl/fspl/generator/native"
|
||||
|
||||
//go:embed all:test-data/*
|
||||
var testData embed.FS
|
||||
|
@ -27,6 +28,8 @@ func defaultCompiler () *Compiler {
|
|||
comp.Resolver.FS = testData
|
||||
comp.Filetype = FiletypeObject
|
||||
comp.Debug = true
|
||||
nativeTarget := native.NativeTarget()
|
||||
comp.Target = &nativeTarget
|
||||
return comp
|
||||
}
|
||||
|
||||
|
@ -50,7 +53,7 @@ func compileDependency (
|
|||
if !ok {
|
||||
test.Fatal("could not generate nickname for", address)
|
||||
}
|
||||
comp.Output = filepath.Join(temp, nickname)
|
||||
comp.Output = filepath.Join(temp, FiletypeObject.Extend(*comp.Target, nickname))
|
||||
|
||||
// compile to object file
|
||||
err := comp.CompileUnit(address)
|
||||
|
@ -79,8 +82,7 @@ func testUnit (
|
|||
test.Log("COMPILER LOG (main unit):\n" + compOutputBuilder.String())
|
||||
}
|
||||
comp.Writer = compOutputBuilder
|
||||
comp.Output = filepath.Join(temp, "output.o")
|
||||
|
||||
comp.Output = filepath.Join(temp, FiletypeObject.Extend(*comp.Target, "output"))
|
||||
|
||||
// compile to object file
|
||||
err := comp.CompileUnit(address)
|
||||
|
@ -91,22 +93,25 @@ func testUnit (
|
|||
outputCompilerLog()
|
||||
|
||||
// link the object file into an executable
|
||||
executablePath := filepath.Join(temp, "output")
|
||||
linkOutputBuilder := new(strings.Builder)
|
||||
executablePath := FiletypeExecutable.Extend(*comp.Target, filepath.Join(temp, "output"))
|
||||
linkCommand := exec.Command("clang", append (
|
||||
clangArgs,
|
||||
comp.Output,
|
||||
"-v",
|
||||
"-o",
|
||||
executablePath)...)
|
||||
linkCommand.Stdout = compOutputBuilder
|
||||
linkCommand.Stderr = compOutputBuilder
|
||||
linkCommand.Stdout = linkOutputBuilder
|
||||
linkCommand.Stderr = linkOutputBuilder
|
||||
test.Log("running link command: ", linkCommand)
|
||||
err = linkCommand.Run()
|
||||
test.Log("LINKER LOG (main unit):\n" + linkOutputBuilder.String())
|
||||
if err != nil {
|
||||
test.Fatal("error linking executable:", err)
|
||||
}
|
||||
|
||||
// run the executable file (with timeout) and check its output
|
||||
timeoutDuration := 10 * time.Millisecond
|
||||
timeoutDuration := 4000 * time.Millisecond
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeoutDuration)
|
||||
defer cancel()
|
||||
executableCommand := exec.CommandContext(ctx, executablePath, args...)
|
||||
|
|
|
@ -22,7 +22,11 @@ func (this *Compiler) CompileUnit (address entity.Address) error {
|
|||
_, err = this.AnalyzeUnit(&semanticTree, path, false)
|
||||
if err != nil { return err }
|
||||
|
||||
irModule, err := native.NativeTarget().Generate(semanticTree)
|
||||
if this.Target == nil {
|
||||
target := native.NativeTarget()
|
||||
this.Target = &target
|
||||
}
|
||||
irModule, err := this.Target.Generate(semanticTree)
|
||||
if err != nil {
|
||||
return this.bug(err)
|
||||
}
|
||||
|
@ -30,10 +34,17 @@ func (this *Compiler) CompileUnit (address entity.Address) error {
|
|||
// if the format isn't specified, try to get it from the filename
|
||||
// extension of the input. if that isn't specified, default to .o
|
||||
if this.Filetype == FiletypeUnknown {
|
||||
var ok bool
|
||||
this.Filetype, ok = FiletypeFromExt(filepath.Ext(this.Output))
|
||||
if !ok {
|
||||
this.Debugln("filetype was not specified")
|
||||
if this.Output == "" {
|
||||
this.Filetype = FiletypeObject
|
||||
} else {
|
||||
var ok bool
|
||||
this.Filetype, ok = FiletypeFromExt (
|
||||
*this.Target,
|
||||
filepath.Ext(this.Output))
|
||||
if !ok {
|
||||
this.Filetype = FiletypeObject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +53,7 @@ func (this *Compiler) CompileUnit (address entity.Address) error {
|
|||
if this.Output == "" {
|
||||
nickname, ok := entity.Address(path).Nickname()
|
||||
if !ok { nickname = "output" }
|
||||
this.Output = this.Filetype.Extend(nickname)
|
||||
this.Output = this.Filetype.Extend(*this.Target, nickname)
|
||||
}
|
||||
|
||||
// do something based on the output extension
|
||||
|
|
|
@ -10,14 +10,16 @@ import "git.tebibyte.media/fspl/fspl/cli"
|
|||
import "git.tebibyte.media/fspl/fspl/lexer"
|
||||
import "git.tebibyte.media/fspl/fspl/entity"
|
||||
import "git.tebibyte.media/fspl/fspl/analyzer"
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
import "git.tebibyte.media/fspl/fspl/parser/fspl"
|
||||
import "git.tebibyte.media/fspl/fspl/parser/meta"
|
||||
import ferrors "git.tebibyte.media/fspl/fspl/errors"
|
||||
|
||||
type Compiler struct {
|
||||
Resolver
|
||||
*Resolver
|
||||
cli.Logger
|
||||
|
||||
Target *generator.Target
|
||||
Output string
|
||||
Optimization string
|
||||
Filetype Filetype
|
||||
|
|
|
@ -1,18 +1,26 @@
|
|||
package compiler
|
||||
|
||||
import "testing"
|
||||
import "runtime"
|
||||
|
||||
var nativeLineBreak = "\n"
|
||||
func init () {
|
||||
if runtime.GOOS == "windows" {
|
||||
nativeLineBreak = "\r\n"
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelloWorld (test *testing.T) {
|
||||
testUnit (test,
|
||||
"/test-data/data/hello", nil,
|
||||
"", "Hello, world!\n",
|
||||
"", "Hello, world!" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
||||
func TestPuts (test *testing.T) {
|
||||
testUnit (test,
|
||||
"/test-data/data/puts", nil,
|
||||
"", "hello\n",
|
||||
"", "hello" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
||||
|
@ -26,7 +34,7 @@ testUnit (test,
|
|||
func TestSystemInclude (test *testing.T) {
|
||||
testUnit (test,
|
||||
"/test-data/data/system-include", nil,
|
||||
"", "Hello, /usr/include!\n",
|
||||
"", "Hello, /usr/include!" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
||||
|
@ -36,7 +44,7 @@ dependencies := []string {
|
|||
}
|
||||
testUnit (test,
|
||||
"/test-data/data/system-src", dependencies,
|
||||
"", "Hello, /usr/src!\n",
|
||||
"", "Hello, /usr/src!" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
||||
|
@ -68,7 +76,7 @@ dependencies := []string {
|
|||
}
|
||||
testUnit (test,
|
||||
"/test-data/data/writer", dependencies,
|
||||
"", "well hello their\n",
|
||||
"", "well hello their" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
||||
|
@ -85,7 +93,7 @@ dependencies := []string {
|
|||
}
|
||||
testUnit (test,
|
||||
"/test-data/data/match-print", dependencies,
|
||||
"", "F64\n",
|
||||
"", "F64" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
||||
|
@ -95,7 +103,7 @@ dependencies := []string {
|
|||
}
|
||||
testUnit (test,
|
||||
"/test-data/data/match-default-print", dependencies,
|
||||
"", "something else\n",
|
||||
"", "something else" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
||||
|
@ -112,7 +120,7 @@ dependencies := []string {
|
|||
}
|
||||
testUnit (test,
|
||||
"/test-data/data/return-assign", dependencies,
|
||||
"", "false\n",
|
||||
"", "false" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
||||
|
@ -143,7 +151,8 @@ dependencies := []string {
|
|||
}
|
||||
testUnit (test,
|
||||
"/test-data/data/for-string-array", dependencies,
|
||||
"", "a\nb\nc\na\nb\nc\n",
|
||||
"", "a" + nativeLineBreak + "b" + nativeLineBreak + "c" + nativeLineBreak +
|
||||
"a" + nativeLineBreak + "b" + nativeLineBreak + "c" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
||||
|
@ -153,7 +162,7 @@ dependencies := []string {
|
|||
}
|
||||
testUnit (test,
|
||||
"/test-data/data/for-string-array-once", dependencies,
|
||||
"", "abc\n",
|
||||
"", "abc" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
||||
|
@ -163,6 +172,6 @@ dependencies := []string {
|
|||
}
|
||||
testUnit (test,
|
||||
"/test-data/data/for-break-branch", dependencies,
|
||||
"", "iter\niter\n",
|
||||
"", "iter" + nativeLineBreak + "iter" + nativeLineBreak,
|
||||
0,
|
||||
)}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package compiler
|
||||
|
||||
import "fmt"
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
// Filetype represents an output filetype.
|
||||
type Filetype int; const (
|
||||
|
@ -9,59 +10,86 @@ type Filetype int; const (
|
|||
FiletypeLibrary
|
||||
FiletypeAssembly
|
||||
FiletypeIR
|
||||
FiletypeExecutable
|
||||
)
|
||||
|
||||
// FiletypeFromString returns a filetype based on the given name.
|
||||
func FiletypeFromString (ext string) (Filetype, bool) {
|
||||
switch ext {
|
||||
case "": return FiletypeUnknown, true
|
||||
case "obj": return FiletypeObject, true
|
||||
case "lib": return FiletypeLibrary, true
|
||||
case "asm": return FiletypeAssembly, true
|
||||
case "ir": return FiletypeIR, true
|
||||
default: return FiletypeUnknown, false
|
||||
case "": return FiletypeUnknown, true
|
||||
case "obj": return FiletypeObject, true
|
||||
case "lib": return FiletypeLibrary, true
|
||||
case "asm": return FiletypeAssembly, true
|
||||
case "ir": return FiletypeIR, true
|
||||
case "exe": return FiletypeExecutable, true
|
||||
default: return FiletypeUnknown, false
|
||||
}
|
||||
}
|
||||
|
||||
// FiletypeFromExt returns a filetype based on the given filename extension.
|
||||
func FiletypeFromExt (ext string) (Filetype, bool) {
|
||||
// FIXME some of these are platform dependent, for example on windows
|
||||
// FiletypeLib would be .dll
|
||||
func FiletypeFromExt (target generator.Target, ext string) (Filetype, bool) {
|
||||
switch ext {
|
||||
case ".o": return FiletypeObject, true
|
||||
case ".so": return FiletypeLibrary, true
|
||||
case ".s": return FiletypeAssembly, true
|
||||
case ".ll": return FiletypeIR, true
|
||||
default: return FiletypeUnknown, false
|
||||
case targetObjExt(target): return FiletypeObject, true
|
||||
case targetSoExt(target): return FiletypeLibrary, true
|
||||
case ".s": return FiletypeAssembly, true
|
||||
case ".ll": return FiletypeIR, true
|
||||
case targetExeExt(target): return FiletypeExecutable, true
|
||||
default: return FiletypeUnknown, false
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a string representation of the filetype.
|
||||
func (filetype Filetype) String () string {
|
||||
switch filetype {
|
||||
case FiletypeUnknown: return ""
|
||||
case FiletypeObject: return "obj"
|
||||
case FiletypeLibrary: return "lib"
|
||||
case FiletypeAssembly: return "asm"
|
||||
case FiletypeIR: return "ir"
|
||||
default: return fmt.Sprintf("Filetype(%d)", filetype)
|
||||
case FiletypeUnknown: return ""
|
||||
case FiletypeObject: return "obj"
|
||||
case FiletypeLibrary: return "lib"
|
||||
case FiletypeAssembly: return "asm"
|
||||
case FiletypeIR: return "ir"
|
||||
case FiletypeExecutable: return "exe"
|
||||
default: return fmt.Sprintf("Filetype(%d)", filetype)
|
||||
}
|
||||
}
|
||||
|
||||
// Ext returns the standard filename extension of the filetype.
|
||||
func (filetype Filetype) Ext () string {
|
||||
// FIXME again, some of these are platform dependent
|
||||
func (filetype Filetype) Ext (target generator.Target) string {
|
||||
switch filetype {
|
||||
case FiletypeUnknown: return ""
|
||||
case FiletypeObject: return ".o"
|
||||
case FiletypeLibrary: return ".so"
|
||||
case FiletypeAssembly: return ".s"
|
||||
case FiletypeIR: return ".ll"
|
||||
case FiletypeUnknown: return ""
|
||||
case FiletypeObject: return targetObjExt(target)
|
||||
case FiletypeLibrary: return targetSoExt(target)
|
||||
case FiletypeAssembly: return ".s"
|
||||
case FiletypeIR: return ".ll"
|
||||
case FiletypeExecutable: return targetExeExt(target)
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
||||
// Extend adds the extension of the filetype onto the specified path.
|
||||
func (filetype Filetype) Extend (path string) string {
|
||||
return path + filetype.Ext()
|
||||
func (filetype Filetype) Extend (target generator.Target, path string) string {
|
||||
return path + filetype.Ext(target)
|
||||
}
|
||||
|
||||
func targetSoExt (target generator.Target) string {
|
||||
// TODO: more research is required here
|
||||
switch target.OS {
|
||||
case "win32": return ".dll"
|
||||
default: return ".so"
|
||||
}
|
||||
}
|
||||
|
||||
func targetObjExt (target generator.Target) string {
|
||||
// TODO: more research is required here
|
||||
switch target.OS {
|
||||
case "win32": return ".obj"
|
||||
default: return ".o"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func targetExeExt (target generator.Target) string {
|
||||
// TODO: more research is required here
|
||||
switch target.OS {
|
||||
case "win32": return ".exe"
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package compiler
|
||||
|
||||
import "os"
|
||||
import "io/fs"
|
||||
import "runtime"
|
||||
import "strings"
|
||||
import "path/filepath"
|
||||
|
||||
// OsFS returns an fs.FS that represents the operating system's filesystem. In
|
||||
// Windows, volume names (A:, B:, C:, etc.) are treated as subdirectories within
|
||||
// the root.
|
||||
type OsFS struct { }
|
||||
|
||||
// win
|
||||
// C:/Something -> C:\Something
|
||||
// "" -> ""
|
||||
|
||||
// unix
|
||||
// C:/Something -> /C:/Something
|
||||
// "" -> /
|
||||
|
||||
func (this OsFS) Open (name string) (fs.File, error) {
|
||||
fullname, err := this.nativize(name)
|
||||
if err != nil {
|
||||
return nil, this.err("open", name, err)
|
||||
}
|
||||
file, err := os.Open(fullname)
|
||||
if err != nil {
|
||||
return nil, this.err("open", name, err.(*os.PathError).Err)
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func (this OsFS) nativize (name string) (string, error) {
|
||||
if !fs.ValidPath(name) {
|
||||
return "", fs.ErrInvalid
|
||||
}
|
||||
if filepath.Separator != '/' {
|
||||
if strings.Contains(name, string(filepath.Separator)) {
|
||||
return "", fs.ErrInvalid
|
||||
}
|
||||
}
|
||||
if runtime.GOOS != "windows" {
|
||||
// TODO is this correct for all non-windows systems?
|
||||
name = "/" + name
|
||||
}
|
||||
name = filepath.FromSlash(name)
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (this OsFS) err (op, path string, err error) error {
|
||||
return &fs.PathError {
|
||||
Op: "open",
|
||||
Path: path,
|
||||
Err: err,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// Package native provides OS native parameters for the compilation process.
|
||||
package native
|
||||
|
||||
import "os"
|
||||
import "errors"
|
||||
import "runtime"
|
||||
import "path/filepath"
|
||||
import "git.tebibyte.media/fspl/fspl/compiler"
|
||||
|
||||
// NativeResolver returns a resolver that resolves paths native to the operating
|
||||
// system.
|
||||
func NativeResolver () (*compiler.Resolver, error) {
|
||||
switch runtime.GOOS {
|
||||
case "windows": return windowsNativeResolver()
|
||||
default: return unixNativeResolver()
|
||||
}
|
||||
}
|
||||
|
||||
func unixNativeResolver () (*compiler.Resolver, error) {
|
||||
resolver := compiler.NewResolver (
|
||||
"/usr/local/src/fspl",
|
||||
"/usr/src/fspl",
|
||||
"/usr/local/incude/fspl",
|
||||
"/usr/include/fspl")
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil { return nil, err }
|
||||
resolver.AddPathFront (
|
||||
filepath.Join(homeDir, ".local/src/fspl"),
|
||||
filepath.Join(homeDir, ".local/include/fspl"))
|
||||
return resolver, nil
|
||||
}
|
||||
|
||||
func windowsNativeResolver () (*compiler.Resolver, error) {
|
||||
localAppData := os.Getenv("LOCALAPPDATA")
|
||||
if localAppData == "" {
|
||||
return nil, errors.New("could not get %LOCALAPPDATA%")
|
||||
}
|
||||
allUsersProfile := os.Getenv("ALLUSERSPROFILE")
|
||||
if allUsersProfile == "" {
|
||||
return nil, errors.New("could not get %ALLUSERSPROFILE%")
|
||||
}
|
||||
programFiles := os.Getenv("ProgramFiles")
|
||||
if programFiles == "" {
|
||||
return nil, errors.New("could not get %ProgramFiles%")
|
||||
}
|
||||
|
||||
resolver := compiler.NewResolver (
|
||||
filepath.Join(localAppData, "fspl\\src"),
|
||||
filepath.Join(localAppData, "fspl\\include"),
|
||||
filepath.Join(allUsersProfile, "fspl\\src"),
|
||||
filepath.Join(allUsersProfile, "fspl\\include"),
|
||||
filepath.Join(programFiles, "fspl\\src"),
|
||||
filepath.Join(programFiles, "fspl\\include"))
|
||||
return resolver, nil
|
||||
}
|
|
@ -20,10 +20,10 @@ type Resolver struct {
|
|||
Path []string
|
||||
}
|
||||
|
||||
// NewResolver creates a new resolver with os.DirFS("/").
|
||||
func NewResolver (path ...string) Resolver {
|
||||
return Resolver {
|
||||
FS: os.DirFS("/"),
|
||||
// NewResolver creates a new resolver with OsFS.
|
||||
func NewResolver (path ...string) *Resolver {
|
||||
return &Resolver {
|
||||
FS: OsFS { },
|
||||
Path: path,
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ func (resolver *Resolver) AddPathFront (path ...string) {
|
|||
// - If the address starts with '/', it is treated as an absolute path from
|
||||
// the fs root
|
||||
// - Else, the address is searched for in the resolver's paths
|
||||
func (resolver Resolver) Resolve (context string, address entity.Address) (string, error) {
|
||||
func (resolver *Resolver) Resolve (context string, address entity.Address) (string, error) {
|
||||
strAddr := string(address)
|
||||
switch {
|
||||
case strings.HasPrefix(strAddr, "."):
|
||||
|
@ -71,7 +71,7 @@ func (resolver Resolver) Resolve (context string, address entity.Address) (strin
|
|||
}
|
||||
}
|
||||
|
||||
func (resolver Resolver) search (needle string) (string, error) {
|
||||
func (resolver *Resolver) search (needle string) (string, error) {
|
||||
for _, dirPath := range resolver.Path {
|
||||
// attempt to open the file as dir.
|
||||
// if we can't open the dir, just skip it, because it is
|
||||
|
@ -98,7 +98,7 @@ func (resolver Resolver) search (needle string) (string, error) {
|
|||
|
||||
// ResolveCwd resolves the address within the context of the current working
|
||||
// directory.
|
||||
func (resolver Resolver) ResolveCwd (address entity.Address) (string, error) {
|
||||
func (resolver *Resolver) ResolveCwd (address entity.Address) (string, error) {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil { return "", err }
|
||||
return resolver.Resolve(wd, address)
|
||||
|
@ -106,9 +106,8 @@ func (resolver Resolver) ResolveCwd (address entity.Address) (string, error) {
|
|||
|
||||
// openAbsolute exists because fs.FS implementations do not understand absolute
|
||||
// paths, which the FSPL compiler runs on. It converts an absolute path to a
|
||||
// path relative to "/" and opens the file.
|
||||
// slash path relative to "/" and opens the file.
|
||||
func openAbsolute (filesystem fs.FS, path string) (fs.File, error) {
|
||||
path, err := filepath.Rel("/", path)
|
||||
if err != nil { return nil, err }
|
||||
path = strings.TrimPrefix(filepath.ToSlash(path), "/")
|
||||
return filesystem.Open(path)
|
||||
}
|
||||
|
|
|
@ -38,7 +38,15 @@ in order of preference:
|
|||
- `/usr/src/fspl`
|
||||
- `/usr/include/fspl`
|
||||
|
||||
Files in `include` directories should *not* include program code, and should
|
||||
On windows, these are used instead:
|
||||
- `%LOCALAPPDATA%\fspl\src`
|
||||
- `%LOCALAPPDATA%\fspl\include`
|
||||
- `%ALLUSERSPROFILE%\fspl\src`
|
||||
- `%ALLUSERSPROFILE%\fspl\include`
|
||||
- `%ProgramFiles%\fspl\src`
|
||||
- `%ProgramFiles%\fspl\include`
|
||||
|
||||
Files in `include` directories *should not* include program code, and should
|
||||
only define types and external functions and methods, similar to header files in
|
||||
C. They may have a corresponding shared object file that programs can
|
||||
dynamically link against.
|
||||
|
|
|
@ -16,8 +16,13 @@ type Target struct {
|
|||
// of the Word type.
|
||||
WordSize uint64
|
||||
|
||||
// Arch specifies the machine architecture
|
||||
// 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 {
|
||||
|
|
|
@ -2,9 +2,60 @@
|
|||
// This is accomplished using several conditionally compiled source files.
|
||||
package native
|
||||
|
||||
import "runtime"
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
// LLVM supported operating systems (note: capitalization is wrong)
|
||||
// https://llvm.org/doxygen/Triple_8h_source.html
|
||||
// GOOS and GOARCH values:
|
||||
// https://go.dev/doc/install/source#environment
|
||||
|
||||
// NativeTarget returns a target describing the current system.
|
||||
func NativeTarget () generator.Target {
|
||||
return nativeTarget()
|
||||
target := generator.Target { }
|
||||
switch runtime.GOARCH {
|
||||
case "386": target.WordSize = 32; target.Arch = "i386"
|
||||
case "amd64": target.WordSize = 64; target.Arch = "x86_64"
|
||||
case "amd64p32": target.WordSize = 32; target.Arch = "x86" // might be inaccurate
|
||||
case "arm": target.WordSize = 32; target.Arch = "arm"
|
||||
case "arm64": target.WordSize = 64; target.Arch = "aarch64"
|
||||
case "arm64be": target.WordSize = 64; target.Arch = "aarch64_be"
|
||||
case "armbe": target.WordSize = 32; target.Arch = "armeb"
|
||||
case "loong": target.WordSize = 32; target.Arch = "loongarch32"
|
||||
case "loong64": target.WordSize = 64; target.Arch = "loongarch64"
|
||||
case "mips": target.WordSize = 32; target.Arch = "mips"
|
||||
case "mips64": target.WordSize = 64; target.Arch = "mips64"
|
||||
case "mips64le": target.WordSize = 64; target.Arch = "mips64el"
|
||||
case "mipsle": target.WordSize = 32; target.Arch = "mipsel"
|
||||
case "ppc": target.WordSize = 32; target.Arch = "ppc32"
|
||||
case "ppc64": target.WordSize = 64; target.Arch = "ppc64"
|
||||
case "ppc64le": target.WordSize = 64; target.Arch = "ppc64le"
|
||||
case "riscv": target.WordSize = 32; target.Arch = "riscv32"
|
||||
case "riscv64": target.WordSize = 64; target.Arch = "riscv64"
|
||||
case "sparc": target.WordSize = 32; target.Arch = "sparc"
|
||||
case "sparc64": target.WordSize = 64; target.Arch = "sparcv9"
|
||||
case "wasm": target.WordSize = 64; target.Arch = "wasm64"
|
||||
default: target.WordSize = 64; target.Arch = "unknown"
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "aix": target.OS = "aix"
|
||||
case "android": target.OS = "linux"
|
||||
case "darwin": target.OS = "darwin"
|
||||
case "dragonfly": target.OS = "dragonfly"
|
||||
case "freebsd": target.OS = "freebsd"
|
||||
case "illumos": target.OS = "illumos"
|
||||
case "ios": target.OS = "ios"
|
||||
case "js": target.OS = "unknown"
|
||||
case "linux": target.OS = "linux"
|
||||
case "nacl": target.OS = "nacl"
|
||||
case "netbsd": target.OS = "netbsd"
|
||||
case "openbsd": target.OS = "openbsd"
|
||||
case "plan9": target.OS = "plan9" // does not seem to be supported by LLVM at the moment
|
||||
case "solaris": target.OS = "solaris"
|
||||
case "wasip1": target.OS = "wasi"
|
||||
case "windows": target.OS = "win32"
|
||||
default: target.OS = "unknown"
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 32,
|
||||
Arch: "i386",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 64,
|
||||
Arch: "x86_64",
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
// this may not be accurate, can't find info online about amd64p32
|
||||
return generator.Target {
|
||||
WordSize: 32,
|
||||
Arch: "x86",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 32,
|
||||
Arch: "arm",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 64,
|
||||
Arch: "aarch64",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 64,
|
||||
Arch: "aarch64_be",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 32,
|
||||
Arch: "armeb",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 32,
|
||||
Arch: "mips",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 64,
|
||||
Arch: "mips64",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 64,
|
||||
Arch: "mips64el",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 32,
|
||||
Arch: "mipsel",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 32,
|
||||
Arch: "ppc32",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 64,
|
||||
Arch: "ppc64",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 64,
|
||||
Arch: "ppc64le",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 32,
|
||||
Arch: "riscv32",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 32,
|
||||
Arch: "sparc",
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
return generator.Target {
|
||||
WordSize: 64,
|
||||
Arch: "sparcv9",
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package native
|
||||
|
||||
import "git.tebibyte.media/fspl/fspl/generator"
|
||||
|
||||
func nativeTarget () generator.Target {
|
||||
// FIXME: golang doesn't discern between 32/64 bit wasm so we assume 64
|
||||
// bit here
|
||||
return generator.Target {
|
||||
WordSize: 64,
|
||||
Arch: "wasm64",
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue