diff --git a/README.md b/README.md index 12e2bca..13fd935 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,24 @@ # TinyFS +[![NuGet version](https://badge.fury.io/nu/TinyFS.Core.svg)](https://badge.fury.io/nu/TinyFS.Core) [![NuGet version](https://badge.fury.io/nu/TinyFS.Cli.svg)](https://badge.fury.io/nu/TinyFS.Cli) + > Taking inspiration from the [tinygo](https://tinygo.org/) project. F# for WebAssembly. TinyFS is a F# to Wasm Compiler. -Current status: Basic int32 arithmetic operators work. +Leveraging the [FSharp.Compiler.Service](https://www.nuget.org/packages/FSharp.Compiler.Service) nuget package to generate an Abstract Syntax Tree (AST). Then walking the AST to generate Wasm bytes. + +Current feature status: +* Support for `int32`, `int64`, `float32`, `float64` and `bool` primitives +* The basic mathematical operators (`+`, `-`, `*`, `/`, `%`) are supported + * `%` - modulo not supported by floating point primitives +* The basic boolean operators (`=`, `<>`, `>`, `>=`, `<`, `<=`) are supported +* Local parameters are supported, as well as mutable parameters. +* `if/else` expression is supported + * No `elif` yet +* `while...do` ## Installing as Nuget Tool @@ -21,7 +33,7 @@ The fastest way to get started is to install via nuget tool. How to compile and use. -* Write a valid .fs program containing the supported fs syntax listed below +* Write a valid .fs program containing the supported fs syntax listed above/below * See examples to get started * Currently every *.fs file requires main function with a single unit parameter to exist * All code must be in a single .fs file, TinyFS does not currently support importing across files. @@ -29,6 +41,7 @@ How to compile and use. * Run `tinyfs run <.wasm file>` to run the generated wasm * Can also run in any other wasm compliant runtime. * This leverages the [wasmtime nuget](https://www.nuget.org/packages/Wasmtime) package. +* You can also use `tinyfs compile -r <.fs file>` to compile and run in one command. ## Alpha Notice @@ -36,9 +49,13 @@ How to compile and use. This is still alpha software, bugs are to be expected. The more complex the code, the more likely it will break. +By day I mainly program in C#, so I won't claim this library is optimized or error free. I mainly undertook this as a learning opportunity. There are currently no longer term plans for what this project will look like moving forward. + +Feel free to raise an issue if you see something could be improved. + ## Supported Syntax -I don't think my overal goal is to get to 100%, but probably target the 20% of language features that cover 80% of use cases. The easier a language construct is able to be mapped into WebAssembly the more likely it is to be implemented. +The easier a language construct is able to be mapped into WebAssembly the more likely it is to be implemented. I don't currently have any long term plans on what I'm planning on doing with this project. Below lists the following language features that are supported. @@ -60,15 +77,14 @@ Below lists the following language features that are supported. - [ ] `nativeint` - probably never - [ ] `unativeint` - probably never - [ ] `decimal` -- [ ] `float32/single` (32 bit) -- [ ] `float/double` (64 bit) +- [x] `float32/single` (32 bit) +- [x] `float/double` (64 bit) - [ ] `char` - [ ] `string` - [ ] `unit` -* The next values to be supported will be: - * `float32`, `float64` and `bool` - * WebAssembly provides builtin support for `int32`, `int64`, `float32` and `float64`. Everything else comes extra. + +* WebAssembly provides builtin support for `int32`, `int64`, `float32` and `float64`. Everything else comes extra. ### Language Constructs diff --git a/cli/Arguments.fs b/cli/Arguments.fs index 0dd4069..a85ad4d 100644 --- a/cli/Arguments.fs +++ b/cli/Arguments.fs @@ -9,17 +9,19 @@ type Filename = string type CompileArgs = | [] Filename of file: string + | [] Run interface IArgParserTemplate with member this.Usage = match this with - | Filename _ -> "The .fs file to compile" + | Filename _ -> "The *.fs file to compile" + | Run -> "Runs the *.wasm file that was just compiled." type RunArgs = | [] Filename of file: string interface IArgParserTemplate with member this.Usage = match this with - | Filename _ -> "The .wasm file to run" + | Filename _ -> "The *.wasm file to run" type CmdArgs = | [] Compile of ParseResults @@ -27,8 +29,8 @@ type CmdArgs = interface IArgParserTemplate with member this.Usage = match this with - | Run _ -> "Runs a .wasm file" - | Compile _ -> "Compile a .fs file to .wasm" + | Run _ -> "Runs a *.wasm file" + | Compile _ -> "Compile a *.fs file to *.wasm" let getExitCode result = match result with @@ -41,48 +43,65 @@ let runPrint print = printfn "%s" print Ok() -let compile (parseResults: ParseResults) = - match parseResults with - | f when f.Contains(CompileArgs.Filename) -> - let filename = f.GetResult(CompileArgs.Filename) - printfn "Compiling: %s" filename +let compileFile (filename: string) = + printfn "Compiling: %s" filename - let fileText = System.IO.File.ReadAllText filename + let fileText = System.IO.File.ReadAllText filename - //printfn "%s" fileText - let name = System.IO.Path.GetFileNameWithoutExtension filename - let fileInfo = new System.IO.FileInfo(filename) - let directory = fileInfo.DirectoryName - let wasmFilename = $"{directory}\{name}.wasm" + let name = System.IO.Path.GetFileNameWithoutExtension filename + let fileInfo = new System.IO.FileInfo(filename) + let directory = fileInfo.DirectoryName + let wasmFilename = $"{directory}\{name}.wasm" - let wasmBytes = EndToEnd.compile fileText |> List.toArray + let wasmBytes = EndToEnd.compile fileText |> List.toArray - System.IO.File.WriteAllBytes(wasmFilename, wasmBytes) - printfn "Compiled to: %s" wasmFilename - Ok() - | _ -> Error ArgumentsNotSpecified + System.IO.File.WriteAllBytes(wasmFilename, wasmBytes) + printfn "Compiled to: %s" wasmFilename -let run (parseResults: ParseResults) = - match parseResults with - | f when f.Contains(RunArgs.Filename) -> - let filename = f.GetResult(RunArgs.Filename) - printfn "Running: %s" filename - let funcName = "main" + wasmFilename + +let runFile (filename: string) = + printfn "Running: %s" filename + let funcName = "main" + + let wasmBytes = System.IO.File.ReadAllBytes filename + + let engine = new Engine() - let wasmBytes = System.IO.File.ReadAllBytes filename + let modd = Module.FromBytes(engine, "tinyfs", wasmBytes) - let engine = new Engine() + let linker = new Linker(engine) + let store = new Store(engine) - let modd = Module.FromBytes(engine, "tinyfs", wasmBytes) + let instance = linker.Instantiate(store, modd) - let linker = new Linker(engine) - let store = new Store(engine) + let main = instance.GetFunction(funcName) + let result = main.Invoke() + printfn "%d" result - let instance = linker.Instantiate(store, modd) +let compile (parseResults: ParseResults) = + match parseResults with + | f when + f.Contains(CompileArgs.Filename) + && f.Contains(CompileArgs.Run) + -> + f.GetResult(CompileArgs.Filename) + |> compileFile + |> runFile + + Ok() + | f when f.Contains(CompileArgs.Filename) -> + f.GetResult(CompileArgs.Filename) + |> compileFile + |> ignore - let main = instance.GetFunction(funcName) - let result = main.Invoke() - printfn "%d" result + Ok() + | _ -> Error ArgumentsNotSpecified + +let run (parseResults: ParseResults) = + match parseResults with + | f when f.Contains(RunArgs.Filename) -> + f.GetResult(RunArgs.Filename) |> runFile Ok() | _ -> Error ArgumentsNotSpecified diff --git a/cli/TinyFS.Cli.fsproj b/cli/TinyFS.Cli.fsproj index 64f7510..cded51c 100644 --- a/cli/TinyFS.Cli.fsproj +++ b/cli/TinyFS.Cli.fsproj @@ -8,7 +8,7 @@ true TinyFS.Cli TinyFS.Cli - 0.0.2-beta + 0.0.2 Morgan Kenyon A Cli for compiling and running F# files into WebAssembly. A Cli for compiling and running F# files into WebAssembly. diff --git a/examples/functions.fs b/examples/functions.fs new file mode 100644 index 0000000..edb011c --- /dev/null +++ b/examples/functions.fs @@ -0,0 +1,5 @@ +module Functions + +let addThree x y = x + y + +let main () = addThree 3 3 diff --git a/src/TinyFS.Core.fsproj b/src/TinyFS.Core.fsproj index c8bb9eb..7fba502 100644 --- a/src/TinyFS.Core.fsproj +++ b/src/TinyFS.Core.fsproj @@ -5,7 +5,7 @@ true TinyFS.Core TinyFS.Core - 0.0.2-beta + 0.0.2 Morgan Kenyon A F# to Wasm Compiler. A F# to Wasm Compiler.