diff --git a/src/parser.rs b/src/parser.rs index 79aa5a9..0bece02 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -186,6 +186,10 @@ pub enum AstNode { env: bool, wrapped: bool, }, + Extern { + name: NodeId, + params: NodeId, + }, Params(Vec), Param { name: NodeId, @@ -246,6 +250,11 @@ pub enum AstNode { then_block: NodeId, else_block: Option, }, + Try { + try_block: NodeId, + catch_block: Option, + finally_block: Option, + }, Match { target: NodeId, match_arms: Vec<(NodeId, NodeId)>, @@ -369,6 +378,8 @@ impl Parser { return AssignmentOrExpression::Expression(self.if_expression()); } else if self.is_keyword(b"match") { return AssignmentOrExpression::Expression(self.match_expression()); + } else if self.is_keyword(b"try") { + return AssignmentOrExpression::Expression(self.try_expression()); } // TODO // } else if self.is_keyword(b"where") { @@ -943,6 +954,52 @@ impl Parser { ) } + pub fn try_expression(&mut self) -> NodeId { + let _span = span!(); + let span_start = self.position(); + + self.keyword(b"try"); + + let try_block = self.block(BlockContext::Curlies); + let mut span_end = self.get_span_end(try_block); + self.skip_newlines(); + + // catch + let catch_block = if self.is_keyword(b"catch") { + self.tokens.advance(); + self.skip_newlines(); + + let block = self.block(BlockContext::Curlies); + span_end = self.get_span_end(block); + + Some(block) + } else { + None + }; + + // finally + let finally_block = if self.is_keyword(b"finally") { + self.tokens.advance(); + self.skip_newlines(); + + let block = self.block(BlockContext::Curlies); + span_end = self.get_span_end(block); + Some(block) + } else { + None + }; + + self.create_node( + AstNode::Try { + try_block, + catch_block, + finally_block, + }, + span_start, + span_end, + ) + } + // directly ripped from `type_params` just changed delimiters // FIXME: simplify if appropriate pub fn signature_params(&mut self, params_context: ParamsContext) -> NodeId { @@ -1247,6 +1304,26 @@ impl Parser { ) } + pub fn extern_statement(&mut self) -> NodeId { + let _span = span!(); + let span_start = self.position(); + + self.keyword(b"extern"); + + let name = match self.tokens.peek() { + (Token::Bareword, span) => self.advance_node(AstNode::Name, span), + (Token::DoubleQuotedString | Token::SingleQuotedString, span) => { + self.advance_node(AstNode::String, span) + } + _ => return self.error("expected def name"), + }; + + let params = self.signature_params(ParamsContext::Squares); + let span_end = self.position(); + + self.create_node(AstNode::Extern { name, params }, span_start, span_end) + } + // TODO: Deduplicate code between let/mut/const assignments pub fn let_statement(&mut self) -> NodeId { let _span = span!(); @@ -1372,6 +1449,8 @@ impl Parser { code_body.push(self.break_statement()); } else if self.is_keyword(b"alias") { code_body.push(self.alias_statement()); + } else if self.is_keyword(b"extern") { + code_body.push(self.extern_statement()); } else { let exp_span_start = self.position(); let pipeline = self.pipeline_or_expression_or_assignment(); diff --git a/src/snapshots/new_nu_parser__test__node_output@extern.nu.snap b/src/snapshots/new_nu_parser__test__node_output@extern.nu.snap new file mode 100644 index 0000000..3b79990 --- /dev/null +++ b/src/snapshots/new_nu_parser__test__node_output@extern.nu.snap @@ -0,0 +1,32 @@ +--- +source: src/test.rs +expression: evaluate_example(path) +input_file: tests/extern.nu +--- +==== COMPILER ==== +0: Name (7 to 11) "echo" +1: Name (13 to 17) "text" +2: Name (19 to 25) "string" +3: Type { name: NodeId(2), args: None, optional: false } (19 to 25) +4: Param { name: NodeId(1), ty: Some(NodeId(3)) } (13 to 25) +5: Params([NodeId(4)]) (12 to 26) +6: Extern { name: NodeId(0), params: NodeId(5) } (0 to 26) +7: Block(BlockId(0)) (0 to 27) +==== SCOPE ==== +0: Frame Scope, node_id: NodeId(7) (empty) +==== TYPES ==== +0: unknown +1: unknown +2: unknown +3: unknown +4: unknown +5: unknown +6: unknown +7: unknown +==== TYPE ERRORS ==== +Error (NodeId 6): Expected statement to typecheck, got 'Extern { name: NodeId(0), params: NodeId(5) }' +==== IR ==== +register_count: 0 +file_count: 0 +==== IR ERRORS ==== +Error (NodeId 6): node Extern { name: NodeId(0), params: NodeId(5) } not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@try.nu.snap b/src/snapshots/new_nu_parser__test__node_output@try.nu.snap new file mode 100644 index 0000000..ad495f0 --- /dev/null +++ b/src/snapshots/new_nu_parser__test__node_output@try.nu.snap @@ -0,0 +1,97 @@ +--- +source: src/test.rs +expression: evaluate_example(path) +input_file: tests/try.nu +--- +==== COMPILER ==== +0: Int (10 to 11) "1" +1: Divide (12 to 13) +2: Int (14 to 15) "0" +3: BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) } (10 to 15) +4: Block(BlockId(0)) (4 to 17) +5: Try { try_block: NodeId(4), catch_block: None, finally_block: None } (0 to 17) +6: Int (29 to 30) "1" +7: Divide (31 to 32) +8: Int (33 to 34) "0" +9: BinaryOp { lhs: NodeId(6), op: NodeId(7), rhs: NodeId(8) } (29 to 34) +10: Block(BlockId(1)) (23 to 37) +11: Name (49 to 54) "print" +12: String (55 to 59) ""aa"" +13: Call { parts: [NodeId(11), NodeId(12)] } (55 to 59) +14: Block(BlockId(2)) (43 to 61) +15: Try { try_block: NodeId(10), catch_block: Some(NodeId(14)), finally_block: None } (19 to 61) +16: Int (73 to 74) "1" +17: Divide (75 to 76) +18: Int (77 to 78) "0" +19: BinaryOp { lhs: NodeId(16), op: NodeId(17), rhs: NodeId(18) } (73 to 78) +20: Block(BlockId(3)) (67 to 81) +21: Name (95 to 100) "print" +22: String (101 to 105) ""bb"" +23: Call { parts: [NodeId(21), NodeId(22)] } (101 to 105) +24: Block(BlockId(4)) (89 to 107) +25: Try { try_block: NodeId(20), catch_block: None, finally_block: Some(NodeId(24)) } (63 to 107) +26: Int (119 to 120) "1" +27: Divide (121 to 122) +28: Int (123 to 124) "0" +29: BinaryOp { lhs: NodeId(26), op: NodeId(27), rhs: NodeId(28) } (119 to 124) +30: Block(BlockId(5)) (113 to 127) +31: Int (139 to 141) "22" +32: Block(BlockId(6)) (133 to 144) +33: Name (158 to 163) "print" +34: String (164 to 168) ""bb"" +35: Call { parts: [NodeId(33), NodeId(34)] } (164 to 168) +36: Block(BlockId(7)) (152 to 170) +37: Try { try_block: NodeId(30), catch_block: Some(NodeId(32)), finally_block: Some(NodeId(36)) } (109 to 170) +38: Block(BlockId(8)) (0 to 172) +==== SCOPE ==== +0: Frame Scope, node_id: NodeId(38) (empty) +==== TYPES ==== +0: unknown +1: unknown +2: unknown +3: unknown +4: unknown +5: unknown +6: unknown +7: unknown +8: unknown +9: unknown +10: unknown +11: unknown +12: unknown +13: unknown +14: unknown +15: unknown +16: unknown +17: unknown +18: unknown +19: unknown +20: unknown +21: unknown +22: unknown +23: unknown +24: unknown +25: unknown +26: unknown +27: unknown +28: unknown +29: unknown +30: unknown +31: unknown +32: unknown +33: unknown +34: unknown +35: unknown +36: unknown +37: unknown +38: unknown +==== TYPE ERRORS ==== +Error (NodeId 5): Expected statement to typecheck, got 'Try { try_block: NodeId(4), catch_block: None, finally_block: None }' +Error (NodeId 15): Expected statement to typecheck, got 'Try { try_block: NodeId(10), catch_block: Some(NodeId(14)), finally_block: None }' +Error (NodeId 25): Expected statement to typecheck, got 'Try { try_block: NodeId(20), catch_block: None, finally_block: Some(NodeId(24)) }' +Error (NodeId 37): Expected statement to typecheck, got 'Try { try_block: NodeId(30), catch_block: Some(NodeId(32)), finally_block: Some(NodeId(36)) }' +==== IR ==== +register_count: 0 +file_count: 0 +==== IR ERRORS ==== +Error (NodeId 5): node Try { try_block: NodeId(4), catch_block: None, finally_block: None } not suported yet diff --git a/tests/extern.nu b/tests/extern.nu new file mode 100644 index 0000000..f9aa500 --- /dev/null +++ b/tests/extern.nu @@ -0,0 +1 @@ +extern echo [text: string] diff --git a/tests/try.nu b/tests/try.nu new file mode 100644 index 0000000..b43e33d --- /dev/null +++ b/tests/try.nu @@ -0,0 +1,24 @@ +try { + 1 / 0 +} + +try { + 1 / 0 +} catch { + print "aa" +} + +try { + 1 / 0 +} finally { + print "bb" +} + +try { + 1 / 0 +} catch { + 22 +} finally { + print "bb" +} +