Skip to content

Commit

Permalink
feat(compiler): adding reassignable to if let (if let var) (#3840)
Browse files Browse the repository at this point in the history
I found the 'TODO: support if let var' in tree-sitter-wing and had some free time 🤷‍♂️

## Checklist

- [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [x] Description explains motivation and solution
- [x] Tests added (always)
- [ ] Docs updated (only required for features)
- [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
marciocadev authored Aug 17, 2023
1 parent 37f65dc commit 7c9bfe4
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 3 deletions.
7 changes: 7 additions & 0 deletions examples/tests/valid/optionals.w
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ let tryParseName = (fullName: str): Name? => {
};
};

// if lets reassignable
let a: num? = 1;
if let var z = a {
assert(z == 1);
z = 2;
assert(z == 2);
}

// Nested if lets
if let parsedName = tryParseName("Good Name") {
Expand Down
2 changes: 1 addition & 1 deletion libs/tree-sitter-wing/grammar.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,8 @@ module.exports = grammar({

if_let_statement: ($) =>
seq(
// TODO: support "if let var"
"if let",
optional(field("reassignable", $.reassignable)),
field("name", $.identifier),
"=",
field("value", $.expression),
Expand Down
16 changes: 16 additions & 0 deletions libs/tree-sitter-wing/test/corpus/statements/statements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,22 @@ if let x = y {} else {}
block: (block)
else_block: (block)))

================================================================================
If Let Var
================================================================================

if let var x = y {}

--------------------------------------------------------------------------------

(source
(if_let_statement
reassignable: (reassignable)
name: (identifier)
value: (reference
(reference_identifier))
block: (block)))

================================================================================
Debug symbol env
================================================================================
Expand Down
1 change: 1 addition & 0 deletions libs/wingc/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ pub enum StmtKind {
statements: Scope,
},
IfLet {
reassignable: bool,
var_name: Symbol,
value: Expr,
statements: Scope,
Expand Down
2 changes: 2 additions & 0 deletions libs/wingc/src/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,13 @@ where
StmtKind::IfLet {
value,
statements,
reassignable,
var_name,
else_statements,
} => StmtKind::IfLet {
value: f.fold_expr(value),
statements: f.fold_scope(statements),
reassignable,
var_name: f.fold_symbol(var_name),
else_statements: else_statements.map(|statements| f.fold_scope(statements)),
},
Expand Down
7 changes: 6 additions & 1 deletion libs/wingc/src/jsify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,7 @@ impl<'a> JSifier<'a> {
StmtKind::Break => CodeMaker::one_line("break;"),
StmtKind::Continue => CodeMaker::one_line("continue;"),
StmtKind::IfLet {
reassignable,
value,
statements,
var_name,
Expand Down Expand Up @@ -894,7 +895,11 @@ impl<'a> JSifier<'a> {
self.jsify_expression(value, ctx)
));
code.open(format!("if ({if_let_value} != undefined) {{"));
code.line(format!("const {} = {};", var_name, if_let_value));
if *reassignable {
code.line(format!("let {} = {};", var_name, if_let_value));
} else {
code.line(format!("const {} = {};", var_name, if_let_value));
}
code.add_code(self.jsify_scope_body(statements, ctx));
code.close("}");

Expand Down
2 changes: 2 additions & 0 deletions libs/wingc/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ impl<'s> Parser<'s> {

fn build_if_let_statement(&self, statement_node: &Node, phase: Phase) -> DiagnosticResult<StmtKind> {
let if_block = self.build_scope(&statement_node.child_by_field_name("block").unwrap(), phase);
let reassignable = statement_node.child_by_field_name("reassignable").is_some();
let value = self.build_expression(&statement_node.child_by_field_name("value").unwrap(), phase)?;
let name = self.check_reserved_symbol(&statement_node.child_by_field_name("name").unwrap())?;
let else_block = if let Some(else_block) = statement_node.child_by_field_name("else_block") {
Expand All @@ -577,6 +578,7 @@ impl<'s> Parser<'s> {
};
Ok(StmtKind::IfLet {
var_name: name,
reassignable,
value,
statements: if_block,
else_statements: else_block,
Expand Down
3 changes: 2 additions & 1 deletion libs/wingc/src/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2808,6 +2808,7 @@ impl<'a> TypeChecker<'a> {
StmtKind::IfLet {
value,
statements,
reassignable,
var_name,
else_statements,
} => {
Expand Down Expand Up @@ -2838,7 +2839,7 @@ impl<'a> TypeChecker<'a> {
// Add the variable to if block scope
match stmt_env.define(
var_name,
SymbolKind::make_free_variable(var_name.clone(), var_type, false, env.phase),
SymbolKind::make_free_variable(var_name.clone(), var_type, *reassignable, env.phase),
StatementIdx::Top,
) {
Err(type_error) => {
Expand Down
1 change: 1 addition & 0 deletions libs/wingc/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ where
StmtKind::IfLet {
value,
statements,
reassignable: _,
var_name,
else_statements,
} => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,16 @@ class $Root extends $stdlib.std.Resource {
}
return ({"first": (parts.at(0)),"last": (parts.at(1))});
});
const a = 1;
{
const $IF_LET_VALUE = a;
if ($IF_LET_VALUE != undefined) {
let z = $IF_LET_VALUE;
{((cond) => {if (!cond) throw new Error("assertion failed: z == 1")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(z,1)))};
z = 2;
{((cond) => {if (!cond) throw new Error("assertion failed: z == 2")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(z,2)))};
}
}
{
const $IF_LET_VALUE = (tryParseName("Good Name"));
if ($IF_LET_VALUE != undefined) {
Expand Down

0 comments on commit 7c9bfe4

Please sign in to comment.