Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 24 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -21,24 +33,29 @@ 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.
* Run `tinyfs compile <.fs file>` to generate a wasm file
* 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

⚠️⚠️⚠️⚠️⚠️⚠️

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.

Expand All @@ -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
Expand Down
89 changes: 54 additions & 35 deletions cli/Arguments.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,28 @@ type Filename = string

type CompileArgs =
| [<MainCommand>] Filename of file: string
| [<AltCommandLine("-r")>] 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 =
| [<MainCommand>] 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 =
| [<CliPrefix(CliPrefix.None)>] Compile of ParseResults<CompileArgs>
| [<CliPrefix(CliPrefix.None)>] Run of ParseResults<RunArgs>
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
Expand All @@ -41,48 +43,65 @@ let runPrint print =
printfn "%s" print
Ok()

let compile (parseResults: ParseResults<CompileArgs>) =
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<RunArgs>) =
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<int32>(funcName)
let result = main.Invoke()
printfn "%d" result

let instance = linker.Instantiate(store, modd)
let compile (parseResults: ParseResults<CompileArgs>) =
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<int32>(funcName)
let result = main.Invoke()
printfn "%d" result
Ok()
| _ -> Error ArgumentsNotSpecified

let run (parseResults: ParseResults<RunArgs>) =
match parseResults with
| f when f.Contains(RunArgs.Filename) ->
f.GetResult(RunArgs.Filename) |> runFile

Ok()
| _ -> Error ArgumentsNotSpecified
2 changes: 1 addition & 1 deletion cli/TinyFS.Cli.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageId>TinyFS.Cli</PackageId>
<Title>TinyFS.Cli</Title>
<Version>0.0.2-beta</Version>
<Version>0.0.2</Version>
<Authors>Morgan Kenyon</Authors>
<Description>A Cli for compiling and running F# files into WebAssembly.</Description>
<Summary>A Cli for compiling and running F# files into WebAssembly.</Summary>
Expand Down
5 changes: 5 additions & 0 deletions examples/functions.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Functions

let addThree x y = x + y

let main () = addThree 3 3
2 changes: 1 addition & 1 deletion src/TinyFS.Core.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageId>TinyFS.Core</PackageId>
<Title>TinyFS.Core</Title>
<Version>0.0.2-beta</Version>
<Version>0.0.2</Version>
<Authors>Morgan Kenyon</Authors>
<Description>A F# to Wasm Compiler.</Description>
<Summary>A F# to Wasm Compiler.</Summary>
Expand Down