Skip to content

Commit

Permalink
Codegen basic destructuring of objects and tuples (#300)
Browse files Browse the repository at this point in the history
* Codegen basic destructuring of objects and tuples

* handle rest patterns in objects and tuples
  • Loading branch information
kevinbarabash committed Jul 21, 2024
1 parent 7aee8ae commit 37477a8
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 3 deletions.
80 changes: 80 additions & 0 deletions src/Escalier.Codegen.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,86 @@ let CodegenImmutableObjectLiteral () =
printfn "error = %A" error
failwith "ParseError"

[<Fact>]
let CodegenDestructureObjects () =
let res =
result {
let src =
"""
let object = {point: {x: 5, y: 10}, color: "red"};
let {point: {x, y}, color} = object;
"""

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) ->
printfn "error = %A" error
failwith "ParseError"

[<Fact>]
let CodegenDestructureObjectWithRest () =
let res =
result {
let src =
"""
let object = {foo: 5, bar: "hello", baz: true};
let {foo, ...rest} = object;
"""

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) ->
printfn "error = %A" error
failwith "ParseError"

[<Fact>]
let CodegenDestructureTuples () =
let res =
result {
let src =
"""
let tuple = ["hello", [5, true]];
let [msg, [num, flag]] = tuple;
"""

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) ->
printfn "error = %A" error
failwith "ParseError"

[<Fact>]
let CodegenDestructureTupleWithRest () =
let res =
result {
let src =
"""
let tuple = [5, "hello", true];
let [foo, ...rest] = tuple;
"""

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) ->
printfn "error = %A" error
failwith "ParseError"

[<Fact>]
let CodegenJsxElement () =
let res =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
input:
let object = {foo: 5, bar: "hello", baz: true};
let {foo, ...rest} = object;

output:
var object = {foo: 5, bar: "hello", baz: true};
var {foo, ...rest} = object;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
input:
let object = {point: {x: 5, y: 10}, color: "red"};
let {point: {x, y}, color} = object;

output:
var object = {point: {x: 5, y: 10}, color: "red"};
var {point: {x, y}, color} = object;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
input:
let tuple = [5, "hello", true];
let [foo, ...rest] = tuple;

output:
var tuple = [5, "hello", true];
var [foo, ...rest] = tuple;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
input:
let tuple = ["hello", [5, true]];
let [msg, [num, flag]] = tuple;

output:
var tuple = ["hello", [5, true]];
var [msg, [num, flag]] = tuple;
48 changes: 47 additions & 1 deletion src/Escalier.Codegen/Codegen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -795,13 +795,59 @@ module rec Codegen =
| Finalizer.Return -> [ Stmt.Return { Argument = None; Loc = None } ]
| Finalizer.Empty -> []

// TODO: also return boolean expressions that need to be checked when codegen'ing
// pattern matching and if-let
let buildPattern (ctx: Ctx) (pattern: Syntax.Pattern) : TS.Pat =
match pattern.Kind with
| PatternKind.Ident { Name = name } ->
Pat.Ident
{ Id = { Name = name; Loc = None }
Loc = None }
| _ -> failwith "TODO"
| PatternKind.Object { Elems = elems } ->
let props =
elems
|> List.map (fun elem ->
match elem with
| Syntax.ObjPatElem.KeyValuePat { Key = key
Value = value
Default = _ } ->
let pat = buildPattern ctx value

// TODO: add support for default values in ObjectPatProp.KeyValue
ObjectPatProp.KeyValue
{ Key = TS.PropName.Ident { Name = key; Loc = None }
Value = pat
Loc = None }
| Syntax.ObjPatElem.ShorthandPat { Name = name
Default = init
Assertion = _ } ->
ObjectPatProp.Assign
{ Key = { Name = name; Loc = None }
Value = None // TODO: handle default values
Loc = None }
| Syntax.ObjPatElem.RestPat { Target = target } ->
ObjectPatProp.Rest
{ Arg = buildPattern ctx target
Loc = None })

Pat.Object { Props = props; Loc = None }
| PatternKind.Tuple { Elems = elems } ->
let elems =
elems
|> List.map (fun elem ->
let pat = buildPattern ctx elem
Some pat)

Pat.Array { Elems = elems; Loc = None }
| PatternKind.Enum enumVariantPattern ->
failwith "TODO: buildPattern - Enum"
| PatternKind.Wildcard wildcardPattern ->
failwith "TODO: buildPattern - Wildcard"
| PatternKind.Literal literal -> failwith "TODO: buildPattern - Literal"
| PatternKind.Rest pattern ->
Pat.Rest
{ Arg = buildPattern ctx pattern
Loc = None }

// TODO: our ModuleItem enum should contain: Decl and Imports
// TODO: pass in `env: Env` so that we can look up the types of
Expand Down
41 changes: 39 additions & 2 deletions src/Escalier.Codegen/Printer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -501,10 +501,47 @@ module rec Printer =
| Stmt.ForOf(_) -> failwith "TODO: printStmt - ForOf"

let printPattern (ctx: PrintCtx) (p: Pat) : string =

match p with
| Pat.Ident { Id = id } -> id.Name
| _ -> failwith "TODO"
| Pat.Array { Elems = elems } ->
let elems =
elems
|> List.map (fun elem ->
match elem with
| None -> " "
| Some pat -> printPattern ctx pat)
|> String.concat ", "

$"[{elems}]"
| Pat.Rest { Arg = arg } ->
let arg = printPattern ctx arg
$"...{arg}"
| Pat.Object { Props = props } ->
let props =
props
|> List.map (fun prop ->
match prop with
| ObjectPatProp.Rest { Arg = arg } ->
let arg = printPattern ctx arg
$"...{arg}"
| ObjectPatProp.Assign { Key = key; Value = _ } -> key.Name
| ObjectPatProp.KeyValue { Key = key; Value = value } ->
let key =
match key with
| PropName.Ident id -> id.Name
| PropName.Str { Value = value } -> $"\"{value}\""
| PropName.Num { Value = value } -> $"{value}"
| Computed { Expr = expr } ->
let expr = printExpr ctx expr
$"[{expr}]"

let value = printPattern ctx value
$"{key}: {value}")
|> String.concat ", "

$"{{{props}}}"
| Pat.Assign assignPat -> failwith "TODO: printPattern - Assign"
| Pat.Invalid invalid -> failwith "TODO: printPattern - Invalid"

let printBlock (ctx: PrintCtx) (block: BlockStmt) =
let oldIdent = String.replicate ctx.Indent " "
Expand Down

0 comments on commit 37477a8

Please sign in to comment.