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
20 changes: 20 additions & 0 deletions examples/euler2.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Euler2

let main () =
let mutable first = 1
let mutable second = 2

let mutable sum = 2

while second <= 4_000_000 do
let temp = first + second
first <- second
second <- temp

sum <-
if second % 2 = 0 then
sum + second
else
sum

sum
21 changes: 20 additions & 1 deletion src/AstToWasm.fs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ let getBlockType (typ: Types option) =
| Bool
| Int32 -> i32_VAL_TYPE
| Int64 -> i64_VAL_TYPE
//| F32 -> f32_VAL_TYPE
| Float32 -> f32_VAL_TYPE
| Float64 -> f64_VAL_TYPE
| _ -> tinyfail (sprintf "Currently do not support a '%s' block type" (vall.ToString()))

Expand All @@ -103,6 +103,7 @@ let getResultType typ =
| Types.Int16
| Types.Int32 -> i32_VAL_TYPE
| Types.Int64 -> i64_VAL_TYPE
| Types.Float32 -> f32_VAL_TYPE
| Types.Float64 -> f64_VAL_TYPE
| _ -> tinyfail (sprintf "Currently does not support '%s' result type" (typ.ToString()))

Expand All @@ -113,6 +114,7 @@ let getType (strType) =
| FS_INT
| FS_INT32 -> Types.Int32
| FS_INT64 -> Types.Int64
| FS_FLOAT32 -> Types.Float32
| FS_FLOAT64 -> Types.Float64
| FS_BOOL -> Types.Bool
| FS_UNIT -> Types.Unit
Expand All @@ -125,6 +127,7 @@ let getOperatorType typ =
| Types.Int16
| Types.Int32 -> Types.Int32
| Types.Int64 -> Types.Int64
| Types.Float32 -> Types.Float32
| Types.Float64 -> Types.Float64
| _ -> tinyfail (sprintf "Currently does not support '%s' operator type" (typ.ToString()))

Expand All @@ -143,36 +146,46 @@ let operatorToWasm (op: string) (typ: Types) =
//arithmetic
| FS_OP_ADDITION, Int32 -> INSTR_i32_ADD
| FS_OP_ADDITION, Int64 -> INSTR_i64_ADD
| FS_OP_ADDITION, Float32 -> INSTR_f32_ADD
| FS_OP_ADDITION, Float64 -> INSTR_f64_ADD
| FS_OP_SUBTRACTION, Int32 -> INSTR_i32_SUB
| FS_OP_SUBTRACTION, Int64 -> INSTR_i64_SUB
| FS_OP_SUBTRACTION, Float32 -> INSTR_f32_SUB
| FS_OP_SUBTRACTION, Float64 -> INSTR_f64_SUB
| FS_OP_MULTIPLY, Int32 -> INSTR_i32_MUL
| FS_OP_MULTIPLY, Int64 -> INSTR_i64_MUL
| FS_OP_MULTIPLY, Float32 -> INSTR_f32_MUL
| FS_OP_MULTIPLY, Float64 -> INSTR_f64_MUL
| FS_OP_DIVISION, Int32 -> INSTR_i32_DIV_S
| FS_OP_DIVISION, Int64 -> INSTR_i64_DIV_S
| FS_OP_DIVISION, Float32 -> INSTR_f32_DIV
| FS_OP_DIVISION, Float64 -> INSTR_f64_DIV
| FS_OP_MODULUS, Int32 -> INSTR_i32_MOD_S
| FS_OP_MODULUS, Int64 -> INSTR_i64_MOD_S
//comparison
| FS_OP_EQUALITY, Int32 -> INSTR_i32_EQ
| FS_OP_EQUALITY, Int64 -> INSTR_i64_EQ
| FS_OP_EQUALITY, Float32 -> INSTR_f32_EQ
| FS_OP_EQUALITY, Float64 -> INSTR_f64_EQ
| FS_OP_INEQUALITY, Int32 -> INSTR_i32_NE
| FS_OP_INEQUALITY, Int64 -> INSTR_i64_NE
| FS_OP_INEQUALITY, Float32 -> INSTR_f32_NE
| FS_OP_INEQUALITY, Float64 -> INSTR_f64_NE
| FS_OP_LESSTHAN, Int32 -> INSTR_i32_LT_S
| FS_OP_LESSTHAN, Int64 -> INSTR_i64_LT_S
| FS_OP_LESSTHAN, Float32 -> INSTR_f32_LT
| FS_OP_LESSTHAN, Float64 -> INSTR_f64_LT
| FS_OP_LESSTHANOREQUAL, Int32 -> INSTR_i32_LE_S
| FS_OP_LESSTHANOREQUAL, Int64 -> INSTR_i64_LE_S
| FS_OP_LESSTHANOREQUAL, Float32 -> INSTR_f32_LE
| FS_OP_LESSTHANOREQUAL, Float64 -> INSTR_f64_LE
| FS_OP_GREATERTHAN, Int32 -> INSTR_i32_GT_S
| FS_OP_GREATERTHAN, Int64 -> INSTR_i64_GT_S
| FS_OP_GREATERTHAN, Float32 -> INSTR_f32_GT
| FS_OP_GREATERTHAN, Float64 -> INSTR_f64_GT
| FS_OP_GREATERTHANOREQUAL, Int32 -> INSTR_i32_GE_S
| FS_OP_GREATERTHANOREQUAL, Int64 -> INSTR_i64_GE_S
| FS_OP_GREATERTHANOREQUAL, Float32 -> INSTR_f32_GE
| FS_OP_GREATERTHANOREQUAL, Float64 -> INSTR_f64_GE
////logic
//| "and" -> INSTR_i32_AND
Expand Down Expand Up @@ -334,6 +347,12 @@ let rec exprToWasm
match convertInt64 value with
| Some vall -> (Types.Int64, (appendSinList i64_CONST (i64 vall)))
| None -> tinyfail (sprintf "Cannot convert '%s' to Int64" (value.ToString()))
| Types.Float32 ->
match convertFloat32 value with
| Some vall ->
let floatBytes = BitConverter.GetBytes(vall) |> Array.toList
(Types.Float32, (appendSinList f32_CONST floatBytes))
| None -> tinyfail (sprintf "Cannot convert '%s' to Float32" (value.ToString()))
| Types.Float64 ->
match convertFloat64 value with
| Some vall ->
Expand Down
3 changes: 3 additions & 0 deletions src/TypeInfos.fs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ let FS_INT = "Microsoft.FSharp.Core.int"
[<Literal>]
let FS_BOOL = "Microsoft.FSharp.Core.bool"

[<Literal>]
let FS_FLOAT32 = "Microsoft.FSharp.Core.float32"

[<Literal>]
let FS_FLOAT64 = "Microsoft.FSharp.Core.float"

Expand Down
5 changes: 5 additions & 0 deletions src/Utils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ let convertInt64 (o: obj) =
| true, int -> Some int
| _ -> None

let convertFloat32 (o: obj) =
match System.Single.TryParse(o.ToString()) with
| true, flt -> Some flt
| _ -> None

let convertFloat64 (o: obj) =
match System.Double.TryParse(o.ToString()) with
| true, flt -> Some flt
Expand Down
13 changes: 13 additions & 0 deletions src/WasmLiterals.fs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module TinyFS.Core.WasmLiterals

//https://webassembly.github.io/spec/core/appendix/index-instructions.html
module Section =
[<Literal>]
let SECTION_ID_TYPE = 0x1uy
Expand Down Expand Up @@ -221,6 +222,18 @@ module Instructions =
[<Literal>]
let INSTR_i64_MOD_U = 0x82uy

[<Literal>]
let INSTR_f32_ADD = 0x92uy

[<Literal>]
let INSTR_f32_SUB = 0x93uy

[<Literal>]
let INSTR_f32_MUL = 0x94uy

[<Literal>]
let INSTR_f32_DIV = 0x95uy

[<Literal>]
let INSTR_f64_ADD = 0xA0uy

Expand Down
16 changes: 14 additions & 2 deletions test/Helpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,22 @@ let runFuncInt32Return (funcName: string) (wasmBytes: byte list) =
let func = instance.GetFunction<int32>(funcName)
func.Invoke()

let runFuncInt64Return (funcName: string) (wasmBytes: byte list) =
let instance = buildInstance wasmBytes

let func = instance.GetFunction<int64>(funcName)
func.Invoke()

let runFuncFloat64Return (funcName: string) (wasmBytes: byte list) =
let instance = buildInstance wasmBytes

let func = instance.GetFunction<float>(funcName)
func.Invoke()

let runFuncInt64Return (funcName: string) (wasmBytes: byte list) =
let runFuncFloat32Return (funcName: string) (wasmBytes: byte list) =
let instance = buildInstance wasmBytes

let func = instance.GetFunction<int64>(funcName)
let func = instance.GetFunction<float32>(funcName)
func.Invoke()

let runInt32FuncInt32 (funcName: string) (param1: int32) (wasmBytes: byte list) =
Expand All @@ -52,6 +58,12 @@ let runInt64FuncInt64 (funcName: string) (param1: int64) (wasmBytes: byte list)
let func = instance.GetFunction<int64, int64>(funcName)
func.Invoke(param1)

let runFloat32FuncFloat32 (funcName: string) (param1: float32) (wasmBytes: byte list) =
let instance = buildInstance wasmBytes

let func = instance.GetFunction<float32, float32>(funcName)
func.Invoke(param1)

let runFloat64FuncFloat64 (funcName: string) (param1: float) (wasmBytes: byte list) =
let instance = buildInstance wasmBytes

Expand Down
152 changes: 152 additions & 0 deletions test/WasmBoolOperatorTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,46 @@ let main () = 0
let response = wasmBytes |> runInt64FuncInt64 "x" param
response.Should().Be(expected)

[<Theory>]
[<InlineData("y > 0.0f", 3.0f, 10.0f)>]
[<InlineData("y > 0.0f", -3.0f, -10.0f)>]
[<InlineData("y < 0.0f", 3.0f, -10.0f)>]
[<InlineData("y < 0.0f", -3.0f, 10.0f)>]
[<InlineData("y = 3.0f", 3.0f, 10.0f)>]
[<InlineData("y = 3.0f", -3.0f, -10.0f)>]
[<InlineData("y = 3.0f", 6.0f, -10.0f)>]
[<InlineData("y <> 3.0f", 3.0f, -10.0f)>]
[<InlineData("y <> 3.0f", -3.0f, 10.0f)>]
[<InlineData("y <> 3.0f", 6.0f, 10.0f)>]
[<InlineData("y <= 3.0f", 3.0f, 10.0f)>]
[<InlineData("y <= 3.0f", -3.0f, 10.0f)>]
[<InlineData("y <= 3.0f", 6.0f, -10.0f)>]
[<InlineData("y >= 3.0f", 3.0f, 10.0f)>]
[<InlineData("y >= 3.0f", -3.0f, -10.0f)>]
[<InlineData("y >= 3.0f", 6.0f, 10.0f)>]
let ``Can support float32 boolean operator expressions`` expr param expected =
let input =
$"""module Test

let x (y: float32) =
let z =
if {expr} then
10.0f
else
-10.0f
z

let main () = 0
"""

let declarations = getDeclarations checker input
let wasmBytes = astToWasm declarations

//printWasm wasmBytes

let response = wasmBytes |> runFloat32FuncFloat32 "x" param
response.Should().Be(expected)

[<Theory>]
[<InlineData("y > 0.0", 3.0, 10.0)>]
[<InlineData("y > 0.0", -3.0, -10.0)>]
Expand Down Expand Up @@ -458,6 +498,118 @@ let main () =
let response = wasmBytes |> runFuncInt64Return "main"
response.Should().Be(10L)

[<Theory>]
[<InlineData("0.0f", "1.0f", "n = 0.0f && m = 1f", 10.0f)>]
[<InlineData("0.0f", "1.0f", "n = 1.0f && m = 1f", 20.0f)>]
[<InlineData("0.0f", "1.0f", "n = 0.0f && m = 0f", 20.0f)>]
[<InlineData("0.0f", "1.0f", "n = 1.0f && m = 0f", 20.0f)>]
[<InlineData("0.0f", "1.0f", "n = 0.0f || m = 1f", 10.0f)>]
[<InlineData("0.0f", "1.0f", "n = 1.0f || m = 1f", 10.0f)>]
[<InlineData("0.0f", "1.0f", "n = 0.0f || m = 0f", 10.0f)>]
[<InlineData("0.0f", "1.0f", "n = 1.0f || m = 0f", 20.0f)>]
let ``Can support float32 boolean expressions`` nValue mValue expr expected =
let input =
$"""module Test

let main () =
let n: float32 = {nValue}
let m: float32 = {mValue}
if {expr} then
10.0f
else
20.0f
"""

let declarations = getDeclarations checker input
let wasmBytes = astToWasm declarations

//printWasm wasmBytes

let response = wasmBytes |> runFuncFloat32Return "main"
response.Should().Be(expected)

[<Fact>]
let ``Can support complicated float32 boolean expression`` () =
let input =
$"""module Test

let main () =
let num1 = 1.0f
let num2 = 2.0f
let num3 = 3.0f
let num4 = 4.0f
let num5 = 5.0f
let num6 = 6.0f
if num1 = 1.0f && num2 = 2.0f && num3 = 3.0f && num4 > 2.0f && (num5 < 10.0f || num6 <= 6.0f) then
10.0f
else
20.0f
"""

let declarations = getDeclarations checker input
let wasmBytes = astToWasm declarations

//printWasm wasmBytes

let response = wasmBytes |> runFuncFloat32Return "main"
response.Should().Be(10.0f)

[<Theory>]
[<InlineData("0.0", "1.0", "n = 0.0 && m = 1.0", 10.0)>]
[<InlineData("0.0", "1.0", "n = 1.0 && m = 1.0", 20.0)>]
[<InlineData("0.0", "1.0", "n = 0.0 && m = 0.0", 20.0)>]
[<InlineData("0.0", "1.0", "n = 1.0 && m = 0.0", 20.0)>]
[<InlineData("0.0", "1.0", "n = 0.0 || m = 1.0", 10.0)>]
[<InlineData("0.0", "1.0", "n = 1.0 || m = 1.0", 10.0)>]
[<InlineData("0.0", "1.0", "n = 0.0 || m = 0.0", 10.0)>]
[<InlineData("0.0", "1.0", "n = 1.0 || m = 0.0", 20.0)>]
let ``Can support float64 boolean expressions`` nValue mValue expr expected =
let input =
$"""module Test

let main () =
let n: float = {nValue}
let m: float = {mValue}
if {expr} then
10.0
else
20.0
"""

let declarations = getDeclarations checker input
let wasmBytes = astToWasm declarations

//printWasm wasmBytes

let response = wasmBytes |> runFuncFloat64Return "main"
response.Should().Be(expected)

[<Fact>]
let ``Can support complicated float64 boolean expression`` () =
let input =
$"""module Test

let main () =
let num1 = 1.0
let num2 = 2.0
let num3 = 3.0
let num4 = 4.0
let num5 = 5.0
let num6 = 6.0
if num1 = 1.0 && num2 = 2.0 && num3 = 3.0 && num4 > 2.0 && (num5 < 10.0 || num6 <= 6.0) then
10.0
else
20.0
"""

let declarations = getDeclarations checker input
let wasmBytes = astToWasm declarations

//printWasm wasmBytes

let response = wasmBytes |> runFuncFloat64Return "main"
response.Should().Be(10.0)

[<Fact>]
let ``Can support boolean types`` () =
let input =
Expand Down
Loading