Skip to content

Commit

Permalink
Codegen overloaded function declarations (#352)
Browse files Browse the repository at this point in the history
* Codegen overloaded function declarations

* extract helper methods, handle 'declare fn'

* Add ticket numbers to TODOs
  • Loading branch information
kevinbarabash committed Aug 25, 2024
1 parent 2dba351 commit 685f22a
Show file tree
Hide file tree
Showing 19 changed files with 457 additions and 67 deletions.
117 changes: 90 additions & 27 deletions src/Escalier.Codegen.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,33 @@ open Escalier.Codegen.Printer
open Escalier.Codegen.Codegen
open Escalier.Parser
open Escalier.TypeChecker
open Escalier.TypeChecker.Infer

type CompileError = Prelude.CompileError


let settings = VerifySettings()
settings.UseDirectory("snapshots")
settings.DisableDiff()

let projectRoot = __SOURCE_DIRECTORY__

let printCtx: PrintCtx = { Indent = 0; Precedence = 0 }

let parseAndCodegenJS (src: string) =
result {
let! escAst = Parser.parseModule src
let! ast = Parser.parseModule src |> Result.mapError CompileError.ParseError

let! ctx, env = Prelude.getEnvAndCtx projectRoot

let! env =
Infer.inferModule ctx env ast |> Result.mapError CompileError.TypeError

let ctx: Ctx =
{ NextTempId = 0
AutoImports = Set.empty }

let mod' = buildModule ctx escAst
let mod' = buildModule ctx ast
let js = printModule printCtx mod'

return js
Expand Down Expand Up @@ -197,6 +208,8 @@ let CodegenTaggedTemplateLiteral () =
result {
let src =
"""
declare fn gql(strings: string[], ...values: unknown[]) -> string;
let id = "foo123";
let query = gql`query {
user(id: ${id}) {
username
Expand Down Expand Up @@ -264,6 +277,8 @@ let CodegenMemberAccess () =
result {
let src =
"""
declare let mut foo: {bar: string};
declare let a: {b?: {c: string}} | undefined;
foo.bar = "baz";
let c = a?.b?.c;
"""
Expand Down Expand Up @@ -386,7 +401,12 @@ let CodegenFunction () =
printfn "error = %A" error
failwith "ParseError"

[<Fact>]
// TODO(#349): Make function params that are primitive types immutable when migrating
// the types from .d.ts files.
// TODO(#350): Fix optional function params in functions migrated from .d.ts files.
// TODO(#351): Update getPropType to check for properties on the Extends type of an
// object type.
[<Fact(Skip = "TODO")>]
let CodegenAsyncFunction () =
let res =
result {
Expand All @@ -404,16 +424,15 @@ let CodegenAsyncFunction () =

match res with
| Ok(res) -> Verifier.Verify(res, settings).ToTask() |> Async.AwaitTask
| Error(error) ->
printfn "error = %A" error
failwith "ParseError"
| Error(error) -> failwith $"error = %A{error}"

[<Fact>]
let CodegenCalls () =
let res =
result {
let src =
"""
declare fn parseInt(input: string) -> number;
let num = parseInt("123");
let array = new Array(1, 2, 3);
"""
Expand All @@ -435,6 +454,9 @@ let CodegenChainedIfElse () =
result {
let src =
"""
let cond1 = Math.random() > 0.5;
let cond2 = Math.random() > 0.5;
let [foo, bar, baz] = ["foo", "bar", "baz"];
let result = if (cond1) {
foo
} else if (cond2) {
Expand All @@ -460,6 +482,8 @@ let CodegenLogicalOperators () =
result {
let src =
"""
let [a, b, c] = [true, false, true];
let [x, y, z] = [true, true, false];
let foo = a || b || c;
let bar = x && y && z;
"""
Expand Down Expand Up @@ -664,7 +688,7 @@ let CodegenIfLetObject () =
let src =
"""
let object = {point: {x: 5, y: 10}, color: "red"};
let mag = if let {point: {x, y}} = object {
let mag = if let {point: {x, y}, color: _} = object {
Math.sqrt(x * x + y * y)
} else {
0
Expand All @@ -677,9 +701,7 @@ let CodegenIfLetObject () =

match res with
| Ok(res) -> Verifier.Verify(res, settings).ToTask() |> Async.AwaitTask
| Error(error) ->
printfn "error = %A" error
failwith "ParseError"
| Error(error) -> failwith $"error = %A{error}"

[<Fact>]
let CodegenMatchArray () =
Expand Down Expand Up @@ -744,9 +766,11 @@ let CodegenTryCatch () =
result {
let src =
"""
declare fn parseJSON(input: string) -> unknown throws "SyntaxError" | "RangeError";
let input = "{\"x\": 5, \"y\": 10}";
let result =
try {
JSON.parse(input);
parseJSON(input);
} catch {
"SyntaxError" => null,
"RangeError" => null,
Expand All @@ -759,21 +783,21 @@ let CodegenTryCatch () =

match res with
| Ok(res) -> Verifier.Verify(res, settings).ToTask() |> Async.AwaitTask
| Error(error) ->
printfn "error = %A" error
failwith "ParseError"
| Error(error) -> failwith $"error = %A{error}"

[<Fact>]
let CodegenTryFinally () =
let res =
result {
let src =
"""
declare fn parseJSON(input: string) -> unknown throws "SyntaxError" | "RangeError";
let input = "{\"x\": 5, \"y\": 10}";
let result =
try {
JSON.parse(input);
parseJSON(input);
} finally {
cleanup();
console.log("cleaning up");
};
"""

Expand All @@ -783,24 +807,24 @@ let CodegenTryFinally () =

match res with
| Ok(res) -> Verifier.Verify(res, settings).ToTask() |> Async.AwaitTask
| Error(error) ->
printfn "error = %A" error
failwith "ParseError"
| Error(error) -> failwith $"error = %A{error}"

[<Fact>]
let CodegenTryCatchFinally () =
let res =
result {
let src =
"""
declare fn parseJSON(input: string) -> unknown throws "SyntaxError" | "RangeError";
let input = "{\"x\": 5, \"y\": 10}";
let result =
try {
JSON.parse(input);
parseJSON(input);
} catch {
"SyntaxError" => null,
"RangeError" => null,
} finally {
cleanup();
console.log("cleaning up");
};
"""

Expand All @@ -810,9 +834,7 @@ let CodegenTryCatchFinally () =

match res with
| Ok(res) -> Verifier.Verify(res, settings).ToTask() |> Async.AwaitTask
| Error(error) ->
printfn "error = %A" error
failwith "ParseError"
| Error(error) -> failwith $"error = %A{error}"

[<Fact>]
let CodegenJsxElement () =
Expand Down Expand Up @@ -859,9 +881,6 @@ let CodegenJsxFragment () =
printfn "error = %A" error
failwith "ParseError"


type CompileError = Prelude.CompileError

[<Fact>]
let CodegenDtsBasics () =
let res =
Expand Down Expand Up @@ -936,3 +955,47 @@ let CodegenDtsGeneric () =
| Error(error) ->
printfn "error = %A" error
failwith "ParseError"

[<Fact>]
let CodegenFunctionDeclaration () =
let res =
result {
let src =
"""
fn add(a: number, b: number) -> number {
return a + b;
}
let sum = add(5, 10);
"""

let! js = parseAndCodegenJS src
return $"input: %s{src}\noutput:\n{js}"
}

match res with
| Ok(res) -> Verifier.Verify(res, settings).ToTask() |> Async.AwaitTask
| Error(error) -> failwith $"error = %A{error}"

[<Fact>]
let CodegenFunctionOverloads () =
let res =
result {
let src =
"""
fn add(a: number, b: number) -> number {
return a + b;
}
fn add(a: string, b: string) -> string {
return a ++ b;
}
let sum = add(5, 10);
let msg = add("hello, ", "world");
"""

let! js = parseAndCodegenJS src
return $"input: %s{src}\noutput:\n{js}"
}

match res with
| Ok(res) -> Verifier.Verify(res, settings).ToTask() |> Async.AwaitTask
| Error(error) -> failwith $"error = %A{error}"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
input:
declare fn parseInt(input: string) -> number;
let num = parseInt("123");
let array = new Array(1, 2, 3);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
input:
let cond1 = Math.random() > 0.5;
let cond2 = Math.random() > 0.5;
let [foo, bar, baz] = ["foo", "bar", "baz"];
let result = if (cond1) {
foo
} else if (cond2) {
Expand All @@ -8,6 +11,9 @@
};

output:
var cond1 = Math.random() > 0.5;
var cond2 = Math.random() > 0.5;
var [foo, bar, baz] = ["foo", "bar", "baz"];
var temp0;
if (cond1) {
temp0 = foo;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
input:
fn add(a: number, b: number) -> number {
return a + b;
}
let sum = add(5, 10);

output:
function add(a, b) {
return a + b;
}
var sum = add(5, 10);
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
input:
fn add(a: number, b: number) -> number {
return a + b;
}
fn add(a: string, b: string) -> string {
return a ++ b;
}
let sum = add(5, 10);
let msg = add("hello, ", "world");

output:
function add(a, b) {
if (typeof a == "number" && typeof b == "number") {
return a + b;
} else if (typeof a == "string" && typeof b == "string") {
return a + b;
} else {
throw TypeError();
}
}
var sum = add(5, 10);
var msg = add("hello, ", "world");
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
input:
let object = {point: {x: 5, y: 10}, color: "red"};
let mag = if let {point: {x, y}} = object {
let mag = if let {point: {x, y}, color: _} = object {
Math.sqrt(x * x + y * y)
} else {
0
Expand All @@ -9,8 +9,8 @@
output:
var object = {point: {x: 5, y: 10}, color: "red"};
var temp0;
if (typeof object == "object" && "point" in object && typeof object["point"] == "object" && "x" in object["point"] && "y" in object["point"]) {
var {point: {x, y}} = object;
if (typeof object == "object" && "point" in object && typeof object["point"] == "object" && "x" in object["point"] && "y" in object["point"] && "color" in object) {
var {point: {x, y}, color: _} = object;
temp0 = Math.sqrt((x * x + y * y));
} else {
temp0 = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
input:
let [a, b, c] = [true, false, true];
let [x, y, z] = [true, true, false];
let foo = a || b || c;
let bar = x && y && z;

output:
var [a, b, c] = [true, false, true];
var [x, y, z] = [true, true, false];
var temp0;
if (a) {
temp0 = a;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
input:
declare let mut foo: {bar: string};
declare let a: {b?: {c: string}} | undefined;
foo.bar = "baz";
let c = a?.b?.c;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
input:
declare fn gql(strings: string[], ...values: unknown[]) -> string;
let id = "foo123";
let query = gql`query {
user(id: ${id}) {
username
Expand All @@ -7,6 +9,7 @@
}`;

output:
var id = "foo123";
var query = gql`query {
user(id: ${id}) {
username
Expand Down
Loading

0 comments on commit 685f22a

Please sign in to comment.