diff --git a/examples/tests/valid/optionals.test.w b/examples/tests/valid/optionals.test.w index 511be164e9c..1c7772a72cb 100644 --- a/examples/tests/valid/optionals.test.w +++ b/examples/tests/valid/optionals.test.w @@ -16,13 +16,14 @@ class Super { class Sub extends Super { new() { this.name = "Sub"; } } -class Sub1 extends Super { - new() { this.name = "Sub"; } +class SubSub extends Sub { + new() { this.name = "SubSub"; } } let optionalSup: Super? = new Super(); let s = optionalSup ?? new Sub(); assert(s.name == "Super"); +let s2 = optionalSup ?? optionalSup ?? new SubSub(); struct Name { first: str; diff --git a/libs/tree-sitter-wing/grammar.js b/libs/tree-sitter-wing/grammar.js index 7bfe12e3485..4d48990e565 100644 --- a/libs/tree-sitter-wing/grammar.js +++ b/libs/tree-sitter-wing/grammar.js @@ -326,6 +326,7 @@ module.exports = grammar({ expression: ($) => choice( + $.unwrap_or, $.binary_expression, $.unary_expression, $.new_expression, @@ -568,6 +569,14 @@ module.exports = grammar({ _container_value_type: ($) => seq("<", field("type_parameter", $._type), ">"), + unwrap_or: ($) => prec.right(PREC.UNWRAP_OR, + seq( + field("left", $.expression), + field("op", "??"), + field("right", $.expression) + ) + ), + optional_unwrap: ($) => prec.right(PREC.OPTIONAL_UNWRAP, seq($.expression, "!")), @@ -614,7 +623,6 @@ module.exports = grammar({ //['<<', PREC.SHIFT], //['>>', PREC.SHIFT], //['>>>', PREC.SHIFT], - ["??", PREC.UNWRAP_OR], ]; return choice( diff --git a/libs/tree-sitter-wing/test/corpus/expressions.txt b/libs/tree-sitter-wing/test/corpus/expressions.txt index 3d2b9c650d3..925bdb0b9ab 100644 --- a/libs/tree-sitter-wing/test/corpus/expressions.txt +++ b/libs/tree-sitter-wing/test/corpus/expressions.txt @@ -298,17 +298,18 @@ Template string maybeVal ?? 2; maybeVal ?? 2 + 2; maybeVal ?? 2 == 2; +maybeVal ?? "hi" ?? 2; -------------------------------------------------------------------------------- (source (expression_statement - (binary_expression + (unwrap_or (reference (reference_identifier)) (number))) (expression_statement - (binary_expression + (unwrap_or (reference (reference_identifier)) (binary_expression @@ -316,11 +317,18 @@ maybeVal ?? 2 == 2; (number)))) (expression_statement (binary_expression - (binary_expression + (unwrap_or (reference (reference_identifier)) (number)) - (number)))) + (number))) + (expression_statement + (unwrap_or + (reference + (reference_identifier)) + (unwrap_or + (string) + (number))))) ================================================================================ Unwrap expression diff --git a/libs/wingc/src/parser.rs b/libs/wingc/src/parser.rs index 31945b6b531..e78dc59dd07 100644 --- a/libs/wingc/src/parser.rs +++ b/libs/wingc/src/parser.rs @@ -2021,7 +2021,7 @@ impl<'s> Parser<'s> { expression_span, )) } - "binary_expression" => Ok(Expr::new( + "binary_expression" | "unwrap_or" => Ok(Expr::new( ExprKind::Binary { left: Box::new(self.build_expression(&expression_node.child_by_field_name("left").unwrap(), phase)?), right: Box::new(self.build_expression(&expression_node.child_by_field_name("right").unwrap(), phase)?), diff --git a/tools/hangar/__snapshots__/test_corpus/valid/optionals.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/optionals.test.w_compile_tf-aws.md index ad5e1181cae..2a75aef7ff9 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/optionals.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/optionals.test.w_compile_tf-aws.md @@ -52,19 +52,19 @@ module.exports = function({ $Super }) { //# sourceMappingURL=inflight.Sub-1.js.map ``` -## inflight.Sub1-1.js +## inflight.SubSub-1.js ```js "use strict"; const $helpers = require("@winglang/sdk/lib/helpers"); -module.exports = function({ $Super }) { - class Sub1 extends $Super { +module.exports = function({ $Sub }) { + class SubSub extends $Sub { constructor({ }) { super({ }); } } - return Sub1; + return SubSub; } -//# sourceMappingURL=inflight.Sub1-1.js.map +//# sourceMappingURL=inflight.SubSub-1.js.map ``` ## inflight.Super-1.js @@ -187,23 +187,23 @@ class $Root extends $stdlib.std.Resource { }); } } - class Sub1 extends Super { + class SubSub extends Sub { constructor($scope, $id, ) { super($scope, $id); - this.name = "Sub"; + this.name = "SubSub"; } static _toInflightType() { return ` - require("${$helpers.normalPath(__dirname)}/inflight.Sub1-1.js")({ - $Super: ${$stdlib.core.liftObject(Super)}, + require("${$helpers.normalPath(__dirname)}/inflight.SubSub-1.js")({ + $Sub: ${$stdlib.core.liftObject(Sub)}, }) `; } _toInflight() { return ` (await (async () => { - const Sub1Client = ${Sub1._toInflightType()}; - const client = new Sub1Client({ + const SubSubClient = ${SubSub._toInflightType()}; + const client = new SubSubClient({ }); if (client.$inflight_init) { await client.$inflight_init(); } return client; @@ -298,6 +298,7 @@ class $Root extends $stdlib.std.Resource { const optionalSup = new Super(this, "Super"); const s = (optionalSup ?? new Sub(this, "Sub")); $helpers.assert($helpers.eq(s.name, "Super"), "s.name == \"Super\""); + const s2 = (optionalSup ?? (optionalSup ?? new SubSub(this, "SubSub"))); let name = ({"first": "John", "last": "Doe"}); { const $if_let_value = name;