diff --git a/contributing/grammar.md b/contributing/grammar.md index 240f4ef..ee3e1a5 100644 --- a/contributing/grammar.md +++ b/contributing/grammar.md @@ -111,7 +111,7 @@ flag_long → "--" flag_name; short_flag → "-" SHORT_FLAGS ; spread → "..." expression ; -command_name → string | call_name | IDENTIFIER ; +command_name → string | IDENTIFIER_ALLOW_DASH ; flag_name → IDENTIFIER_ALLOW_DASH ; call_name → IDENTIFIER_ALLOW_DASH IDENTIFIER_ALLOW_DASH+ ; diff --git a/src/parser.rs b/src/parser.rs index 71046e3..e0abf5c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -308,12 +308,23 @@ pub enum AstNode { long: NodeId, short: Option, ty: Option, + // it can only exists if `ty` is not None + custom_completion: Option, default: Option, }, PosParam { name: NodeId, ty: Option, + // it can only exists if `ty` is not None + custom_completion: Option, default: Option, + is_optional: bool, + }, + RestParam { + name: NodeId, + ty: Option, + // it can only exists if `ty` is not None + custom_completion: Option, }, InOutTypes(InOutTypesId), /// Input/output type pair for a command @@ -1000,6 +1011,13 @@ impl Parser { ) } + pub fn command_name(&mut self) -> NodeId { + match self.tokens.peek_token() { + Token::DoubleQuotedString | Token::SingleQuotedString => self.string(), + _ => self.identifier_allow_dash(), + } + } + pub fn string(&mut self) -> NodeId { match self.tokens.peek() { (Token::DoubleQuotedString, span) => self.advance_node(AstNode::String, span), @@ -1218,8 +1236,16 @@ impl Parser { } let is_flag_param = self.is_dashdash(); + let is_rest_param = self.is_dotdotdot(); + let mut is_pos_param_optional = false; + let (name, short_name) = - if is_flag_param && matches!(params_context, ParamsContext::Squares) { + if is_rest_param && matches!(params_context, ParamsContext::Squares) { + // reset parameter + self.tokens.advance(); + (self.name(), None) + } else if is_flag_param && matches!(params_context, ParamsContext::Squares) { + // flag_parameter. let result = self.flag_long(); if self.is_lparen() { self.tokens.advance(); @@ -1230,16 +1256,30 @@ impl Parser { (result, None) } } else { - (self.name(), None) + // positional parameter + let result = (self.name(), None); + if self.is_question_mark() { + self.tokens.advance(); + is_pos_param_optional = true; + } + result }; - let ty = if self.is_colon() { + let (ty, custom_completion) = if self.is_colon() { // We have a type self.colon(); - Some(self.typename()) + let type_name = self.typename(); + // We have custom completer + let custom_completion = if self.is_at() { + self.tokens.advance(); + Some(self.command_name()) + } else { + None + }; + (Some(type_name), custom_completion) } else { - None + (None, None) }; let default_val = if self.is_equals() { @@ -1262,17 +1302,30 @@ impl Parser { long: name, short: short_name, ty, + custom_completion, default: default_val, }, name_span.start, param_span_end, ) + } else if is_rest_param { + self.create_node( + AstNode::RestParam { + name, + ty, + custom_completion, + }, + name_span.start, + param_span_end, + ) } else { self.create_node( AstNode::PosParam { name, ty, + custom_completion, default: default_val, + is_optional: is_pos_param_optional, }, name_span.start, param_span_end, @@ -1868,6 +1921,10 @@ impl Parser { self.tokens.peek_token() == Token::Equals } + pub fn is_at(&mut self) -> bool { + self.tokens.peek_token() == Token::At + } + pub fn is_comma(&mut self) -> bool { self.tokens.peek_token() == Token::Comma } @@ -1956,6 +2013,10 @@ impl Parser { self.tokens.peek_token() == Token::DotDot } + pub fn is_dotdotdot(&mut self) -> bool { + self.tokens.peek_token() == Token::DotDotDot + } + pub fn is_coloncolon(&mut self) -> bool { self.tokens.peek_token() == Token::ColonColon } diff --git a/src/resolver.rs b/src/resolver.rs index 57ef9c5..f64b92a 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -301,14 +301,18 @@ impl<'a> Resolver<'a> { AstNode::PosParam { name, ty, + custom_completion: _, default: _, + is_optional: _, } | AstNode::FlagParam { long: name, short: _, ty, + custom_completion: _, default: _, - } => { + } + | AstNode::RestParam { name, ty, .. } => { self.define_variable(name, false); if let Some(ty) = ty { self.resolve_node(ty); diff --git a/src/snapshots/new_nu_parser__test__node_output@calls.nu.snap b/src/snapshots/new_nu_parser__test__node_output@calls.nu.snap index 48e7a5a..8587cd0 100644 --- a/src/snapshots/new_nu_parser__test__node_output@calls.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@calls.nu.snap @@ -16,15 +16,15 @@ input_file: tests/calls.nu 9: Name (38 to 39) "a" 10: Name (41 to 47) "string" 11: Type { name: NodeId(10), args: None, optional: false } (41 to 47) -12: PosParam { name: NodeId(9), ty: Some(NodeId(11)), default: None } (38 to 47) +12: PosParam { name: NodeId(9), ty: Some(NodeId(11)), custom_completion: None, default: None, is_optional: false } (38 to 47) 13: Name (49 to 50) "b" 14: Name (52 to 58) "string" 15: Type { name: NodeId(14), args: None, optional: false } (52 to 58) -16: PosParam { name: NodeId(13), ty: Some(NodeId(15)), default: None } (49 to 58) +16: PosParam { name: NodeId(13), ty: Some(NodeId(15)), custom_completion: None, default: None, is_optional: false } (49 to 58) 17: Name (60 to 61) "c" 18: Name (63 to 66) "int" 19: Type { name: NodeId(18), args: None, optional: false } (63 to 66) -20: PosParam { name: NodeId(17), ty: Some(NodeId(19)), default: None } (60 to 66) +20: PosParam { name: NodeId(17), ty: Some(NodeId(19)), custom_completion: None, default: None, is_optional: false } (60 to 66) 21: Params(ParamsId(0)) (37 to 67) 22: Variable (72 to 74) "$a" 23: Variable (76 to 78) "$b" diff --git a/src/snapshots/new_nu_parser__test__node_output@calls_invalid.nu.snap b/src/snapshots/new_nu_parser__test__node_output@calls_invalid.nu.snap index 653d079..2b08a20 100644 --- a/src/snapshots/new_nu_parser__test__node_output@calls_invalid.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@calls_invalid.nu.snap @@ -8,7 +8,7 @@ input_file: tests/calls_invalid.nu 1: Name (10 to 11) "a" 2: Name (13 to 16) "int" 3: Type { name: NodeId(2), args: None, optional: false } (13 to 16) -4: PosParam { name: NodeId(1), ty: Some(NodeId(3)), default: None } (10 to 16) +4: PosParam { name: NodeId(1), ty: Some(NodeId(3)), custom_completion: None, default: None, is_optional: false } (10 to 16) 5: Params(ParamsId(0)) (8 to 18) 6: Block(BlockId(0)) (19 to 21) 7: Def { name: NodeId(0), type_params: None, params: NodeId(5), in_out_types: None, block: NodeId(6), env: false, wrapped: false } (0 to 21) diff --git a/src/snapshots/new_nu_parser__test__node_output@closure.nu.snap b/src/snapshots/new_nu_parser__test__node_output@closure.nu.snap index 3af804e..35e2139 100644 --- a/src/snapshots/new_nu_parser__test__node_output@closure.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@closure.nu.snap @@ -5,9 +5,9 @@ input_file: tests/closure.nu --- ==== COMPILER ==== 0: Name (3 to 4) "a" -1: PosParam { name: NodeId(0), ty: None, default: None } (3 to 4) +1: PosParam { name: NodeId(0), ty: None, custom_completion: None, default: None, is_optional: false } (3 to 4) 2: Name (6 to 7) "b" -3: PosParam { name: NodeId(2), ty: None, default: None } (6 to 7) +3: PosParam { name: NodeId(2), ty: None, custom_completion: None, default: None, is_optional: false } (6 to 7) 4: Params(ParamsId(0)) (2 to 8) 5: Variable (9 to 11) "$a" 6: Plus (12 to 13) diff --git a/src/snapshots/new_nu_parser__test__node_output@closure3.nu.snap b/src/snapshots/new_nu_parser__test__node_output@closure3.nu.snap index dfaafc0..595cd3a 100644 --- a/src/snapshots/new_nu_parser__test__node_output@closure3.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@closure3.nu.snap @@ -8,11 +8,11 @@ input_file: tests/closure3.nu 1: Name (16 to 17) "a" 2: Name (19 to 22) "int" 3: Type { name: NodeId(2), args: None, optional: false } (19 to 22) -4: PosParam { name: NodeId(1), ty: Some(NodeId(3)), default: None } (16 to 22) +4: PosParam { name: NodeId(1), ty: Some(NodeId(3)), custom_completion: None, default: None, is_optional: false } (16 to 22) 5: Name (24 to 25) "b" 6: Name (27 to 30) "int" 7: Type { name: NodeId(6), args: None, optional: false } (27 to 30) -8: PosParam { name: NodeId(5), ty: Some(NodeId(7)), default: None } (24 to 30) +8: PosParam { name: NodeId(5), ty: Some(NodeId(7)), custom_completion: None, default: None, is_optional: false } (24 to 30) 9: Params(ParamsId(0)) (15 to 31) 10: Variable (32 to 34) "$a" 11: Plus (35 to 36) diff --git a/src/snapshots/new_nu_parser__test__node_output@def.nu.snap b/src/snapshots/new_nu_parser__test__node_output@def.nu.snap index 55106c7..b750ca1 100644 --- a/src/snapshots/new_nu_parser__test__node_output@def.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@def.nu.snap @@ -6,11 +6,11 @@ input_file: tests/def.nu ==== COMPILER ==== 0: Name (4 to 7) "foo" 1: Name (9 to 10) "w" -2: PosParam { name: NodeId(1), ty: None, default: None } (9 to 10) +2: PosParam { name: NodeId(1), ty: None, custom_completion: None, default: None, is_optional: false } (9 to 10) 3: Name (11 to 12) "x" 4: Name (14 to 17) "int" 5: Type { name: NodeId(4), args: None, optional: false } (14 to 17) -6: PosParam { name: NodeId(3), ty: Some(NodeId(5)), default: None } (11 to 17) +6: PosParam { name: NodeId(3), ty: Some(NodeId(5)), custom_completion: None, default: None, is_optional: false } (11 to 17) 7: Name (19 to 20) "y" 8: Name (22 to 26) "list" 9: Name (27 to 31) "list" @@ -20,18 +20,18 @@ input_file: tests/def.nu 13: Type { name: NodeId(9), args: Some(NodeId(12)), optional: false } (27 to 31) 14: TypeArgs(TypeArgsId(1)) (26 to 37) 15: Type { name: NodeId(8), args: Some(NodeId(14)), optional: false } (22 to 26) -16: PosParam { name: NodeId(7), ty: Some(NodeId(15)), default: None } (19 to 26) +16: PosParam { name: NodeId(7), ty: Some(NodeId(15)), custom_completion: None, default: None, is_optional: false } (19 to 26) 17: Name (39 to 40) "z" 18: Name (42 to 48) "record" 19: Name (49 to 50) "a" -20: PosParam { name: NodeId(19), ty: None, default: None } (49 to 50) +20: PosParam { name: NodeId(19), ty: None, custom_completion: None, default: None, is_optional: false } (49 to 50) 21: Name (52 to 53) "b" 22: Name (55 to 58) "int" 23: Type { name: NodeId(22), args: None, optional: false } (55 to 58) -24: PosParam { name: NodeId(21), ty: Some(NodeId(23)), default: None } (52 to 58) +24: PosParam { name: NodeId(21), ty: Some(NodeId(23)), custom_completion: None, default: None, is_optional: false } (52 to 58) 25: Params(ParamsId(0)) (48 to 59) 26: RecordType { fields: NodeId(25), optional: false } (42 to 60) -27: PosParam { name: NodeId(17), ty: Some(NodeId(26)), default: None } (39 to 60) +27: PosParam { name: NodeId(17), ty: Some(NodeId(26)), custom_completion: None, default: None, is_optional: false } (39 to 60) 28: Params(ParamsId(1)) (8 to 61) 29: Variable (66 to 68) "$w" 30: Variable (69 to 71) "$x" @@ -46,18 +46,18 @@ input_file: tests/def.nu 39: Name (125 to 128) "int" 40: Type { name: NodeId(39), args: None, optional: false } (125 to 128) 41: Int (131 to 132) "3" -42: FlagParam { long: NodeId(38), short: None, ty: Some(NodeId(40)), default: Some(NodeId(41)) } (118 to 132) +42: FlagParam { long: NodeId(38), short: None, ty: Some(NodeId(40)), custom_completion: None, default: Some(NodeId(41)) } (118 to 132) 43: Name (136 to 139) "baz" 44: FlagLong(NodeId(43)) (134 to 139) 45: Name (141 to 142) "b" 46: FlagShort(NodeId(45)) (140 to 142) -47: FlagParam { long: NodeId(44), short: Some(NodeId(46)), ty: None, default: None } (134 to 139) +47: FlagParam { long: NodeId(44), short: Some(NodeId(46)), ty: None, custom_completion: None, default: None } (134 to 139) 48: Name (145 to 146) "x" -49: PosParam { name: NodeId(48), ty: None, default: None } (145 to 146) +49: PosParam { name: NodeId(48), ty: None, custom_completion: None, default: None, is_optional: false } (145 to 146) 50: Name (148 to 149) "y" 51: Name (151 to 154) "int" 52: Type { name: NodeId(51), args: None, optional: false } (151 to 154) -53: PosParam { name: NodeId(50), ty: Some(NodeId(52)), default: None } (148 to 154) +53: PosParam { name: NodeId(50), ty: Some(NodeId(52)), custom_completion: None, default: None, is_optional: false } (148 to 154) 54: Params(ParamsId(2)) (117 to 155) 55: Variable (159 to 163) "$bar" 56: Variable (165 to 169) "$baz" @@ -66,14 +66,76 @@ input_file: tests/def.nu 59: List(ListId(1)) (158 to 177) 60: Block(BlockId(1)) (156 to 180) 61: Def { name: NodeId(36), type_params: None, params: NodeId(54), in_out_types: None, block: NodeId(60), env: false, wrapped: false } (99 to 180) -62: Block(BlockId(2)) (0 to 181) +62: Name (213 to 223) "completion" +63: Params(ParamsId(3)) (224 to 226) +64: Int (230 to 231) "1" +65: Int (233 to 234) "2" +66: Int (236 to 237) "3" +67: List(ListId(2)) (229 to 237) +68: Block(BlockId(2)) (227 to 240) +69: Def { name: NodeId(62), type_params: None, params: NodeId(63), in_out_types: None, block: NodeId(68), env: false, wrapped: false } (209 to 240) +70: Name (245 to 264) "foo-with-completion" +71: Name (268 to 271) "bar" +72: FlagLong(NodeId(71)) (266 to 271) +73: Name (273 to 276) "int" +74: Type { name: NodeId(73), args: None, optional: false } (273 to 276) +75: Name (277 to 287) "completion" +76: FlagParam { long: NodeId(72), short: None, ty: Some(NodeId(74)), custom_completion: Some(NodeId(75)), default: None } (266 to 276) +77: Name (289 to 292) "baz" +78: Name (294 to 297) "int" +79: Type { name: NodeId(78), args: None, optional: false } (294 to 297) +80: Name (298 to 308) "completion" +81: PosParam { name: NodeId(77), ty: Some(NodeId(79)), custom_completion: Some(NodeId(80)), default: None, is_optional: false } (289 to 297) +82: Params(ParamsId(4)) (265 to 309) +83: Variable (313 to 317) "$bar" +84: Variable (319 to 323) "$baz" +85: List(ListId(3)) (312 to 323) +86: Block(BlockId(3)) (310 to 326) +87: Def { name: NodeId(70), type_params: None, params: NodeId(82), in_out_types: None, block: NodeId(86), env: false, wrapped: false } (241 to 326) +88: Name (332 to 344) "foo-optional" +89: Name (346 to 347) "x" +90: Name (349 to 352) "int" +91: Type { name: NodeId(90), args: None, optional: false } (349 to 352) +92: PosParam { name: NodeId(89), ty: Some(NodeId(91)), custom_completion: None, default: None, is_optional: false } (346 to 352) +93: Name (354 to 355) "y" +94: Name (358 to 361) "int" +95: Type { name: NodeId(94), args: None, optional: false } (358 to 361) +96: PosParam { name: NodeId(93), ty: Some(NodeId(95)), custom_completion: None, default: None, is_optional: true } (354 to 361) +97: Params(ParamsId(5)) (345 to 362) +98: Variable (366 to 368) "$x" +99: Variable (370 to 372) "$y" +100: List(ListId(4)) (365 to 372) +101: Block(BlockId(4)) (363 to 375) +102: Def { name: NodeId(88), type_params: None, params: NodeId(97), in_out_types: None, block: NodeId(101), env: false, wrapped: false } (328 to 375) +103: Name (380 to 388) "foo-rest" +104: Name (390 to 391) "x" +105: Name (393 to 396) "int" +106: Type { name: NodeId(105), args: None, optional: false } (393 to 396) +107: PosParam { name: NodeId(104), ty: Some(NodeId(106)), custom_completion: None, default: None, is_optional: false } (390 to 396) +108: Name (401 to 402) "y" +109: RestParam { name: NodeId(108), ty: None, custom_completion: None } (401 to 402) +110: Params(ParamsId(6)) (389 to 403) +111: Variable (407 to 409) "$x" +112: Variable (411 to 413) "$y" +113: List(ListId(5)) (406 to 413) +114: Block(BlockId(5)) (404 to 416) +115: Def { name: NodeId(103), type_params: None, params: NodeId(110), in_out_types: None, block: NodeId(114), env: false, wrapped: false } (376 to 416) +116: Block(BlockId(6)) (0 to 417) ==== SCOPE ==== -0: Frame Scope, node_id: NodeId(62) - decls: [ foo-with-flag: NodeId(36), foo: NodeId(0) ] +0: Frame Scope, node_id: NodeId(116) + decls: [ completion: NodeId(62), foo-optional: NodeId(88), foo-rest: NodeId(103), foo-with-completion: NodeId(70), foo-with-flag: NodeId(36), foo: NodeId(0) ] 1: Frame Scope, node_id: NodeId(34) variables: [ w: NodeId(1), x: NodeId(3), y: NodeId(7), z: NodeId(17) ] 2: Frame Scope, node_id: NodeId(60) variables: [ --bar: NodeId(38), --baz: NodeId(44), x: NodeId(48), y: NodeId(50) ] +3: Frame Scope, node_id: NodeId(68) (empty) +4: Frame Scope, node_id: NodeId(86) + variables: [ --bar: NodeId(72), baz: NodeId(77) ] +5: Frame Scope, node_id: NodeId(101) + variables: [ x: NodeId(89), y: NodeId(93) ] +6: Frame Scope, node_id: NodeId(114) + variables: [ x: NodeId(104), y: NodeId(108) ] ==== SCOPE ERRORS ==== Error (NodeId 55): variable `bar` not found Error (NodeId 56): variable `baz` not found +Error (NodeId 83): variable `bar` not found 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 index 2e8add0..c9d74b0 100644 --- a/src/snapshots/new_nu_parser__test__node_output@extern.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@extern.nu.snap @@ -8,7 +8,7 @@ input_file: tests/extern.nu 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: PosParam { name: NodeId(1), ty: Some(NodeId(3)), default: None } (13 to 25) +4: PosParam { name: NodeId(1), ty: Some(NodeId(3)), custom_completion: None, default: None, is_optional: false } (13 to 25) 5: Params(ParamsId(0)) (12 to 26) 6: Extern { name: NodeId(0), params: NodeId(5) } (0 to 26) 7: Block(BlockId(0)) (0 to 27) diff --git a/src/snapshots/new_nu_parser__test__node_output@infer_complex.nu.snap b/src/snapshots/new_nu_parser__test__node_output@infer_complex.nu.snap index 1c76b0f..8118357 100644 --- a/src/snapshots/new_nu_parser__test__node_output@infer_complex.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@infer_complex.nu.snap @@ -13,27 +13,27 @@ input_file: tests/infer_complex.nu 6: Name (24 to 25) "a" 7: Name (27 to 28) "A" 8: Type { name: NodeId(7), args: None, optional: false } (27 to 28) -9: PosParam { name: NodeId(6), ty: Some(NodeId(8)), default: None } (24 to 28) +9: PosParam { name: NodeId(6), ty: Some(NodeId(8)), custom_completion: None, default: None, is_optional: false } (24 to 28) 10: Name (30 to 31) "b" 11: Name (33 to 34) "B" 12: Type { name: NodeId(11), args: None, optional: false } (33 to 34) -13: PosParam { name: NodeId(10), ty: Some(NodeId(12)), default: None } (30 to 34) +13: PosParam { name: NodeId(10), ty: Some(NodeId(12)), custom_completion: None, default: None, is_optional: false } (30 to 34) 14: Params(ParamsId(1)) (23 to 35) 15: RecordType { fields: NodeId(14), optional: false } (17 to 35) -16: PosParam { name: NodeId(4), ty: Some(NodeId(15)), default: None } (14 to 35) +16: PosParam { name: NodeId(4), ty: Some(NodeId(15)), custom_completion: None, default: None, is_optional: false } (14 to 35) 17: Name (37 to 38) "y" 18: Name (40 to 46) "record" 19: Name (47 to 48) "a" 20: Name (50 to 51) "A" 21: Type { name: NodeId(20), args: None, optional: false } (50 to 51) -22: PosParam { name: NodeId(19), ty: Some(NodeId(21)), default: None } (47 to 51) +22: PosParam { name: NodeId(19), ty: Some(NodeId(21)), custom_completion: None, default: None, is_optional: false } (47 to 51) 23: Name (53 to 54) "b" 24: Name (56 to 57) "B" 25: Type { name: NodeId(24), args: None, optional: false } (56 to 57) -26: PosParam { name: NodeId(23), ty: Some(NodeId(25)), default: None } (53 to 57) +26: PosParam { name: NodeId(23), ty: Some(NodeId(25)), custom_completion: None, default: None, is_optional: false } (53 to 57) 27: Params(ParamsId(2)) (46 to 58) 28: RecordType { fields: NodeId(27), optional: false } (40 to 59) -29: PosParam { name: NodeId(17), ty: Some(NodeId(28)), default: None } (37 to 59) +29: PosParam { name: NodeId(17), ty: Some(NodeId(28)), custom_completion: None, default: None, is_optional: false } (37 to 59) 30: Params(ParamsId(3)) (12 to 60) 31: Name (63 to 70) "nothing" 32: Type { name: NodeId(31), args: None, optional: false } (63 to 70) @@ -41,11 +41,11 @@ input_file: tests/infer_complex.nu 34: Name (81 to 82) "a" 35: Name (84 to 85) "A" 36: Type { name: NodeId(35), args: None, optional: false } (84 to 85) -37: PosParam { name: NodeId(34), ty: Some(NodeId(36)), default: None } (81 to 85) +37: PosParam { name: NodeId(34), ty: Some(NodeId(36)), custom_completion: None, default: None, is_optional: false } (81 to 85) 38: Name (87 to 88) "b" 39: Name (90 to 91) "B" 40: Type { name: NodeId(39), args: None, optional: false } (90 to 91) -41: PosParam { name: NodeId(38), ty: Some(NodeId(40)), default: None } (87 to 91) +41: PosParam { name: NodeId(38), ty: Some(NodeId(40)), custom_completion: None, default: None, is_optional: false } (87 to 91) 42: Params(ParamsId(4)) (80 to 92) 43: RecordType { fields: NodeId(42), optional: false } (74 to 93) 44: InOutType(NodeId(32), NodeId(43)) (63 to 93) @@ -59,7 +59,7 @@ input_file: tests/infer_complex.nu 52: Name (122 to 123) "x" 53: Name (125 to 128) "int" 54: Type { name: NodeId(53), args: None, optional: false } (125 to 128) -55: PosParam { name: NodeId(52), ty: Some(NodeId(54)), default: None } (122 to 128) +55: PosParam { name: NodeId(52), ty: Some(NodeId(54)), custom_completion: None, default: None, is_optional: false } (122 to 128) 56: Params(ParamsId(6)) (120 to 130) 57: Name (133 to 140) "nothing" 58: Type { name: NodeId(57), args: None, optional: false } (133 to 140) @@ -79,7 +79,7 @@ input_file: tests/infer_complex.nu 72: Name (185 to 186) "a" 73: Name (188 to 194) "number" 74: Type { name: NodeId(73), args: None, optional: false } (188 to 194) -75: PosParam { name: NodeId(72), ty: Some(NodeId(74)), default: None } (185 to 194) +75: PosParam { name: NodeId(72), ty: Some(NodeId(74)), custom_completion: None, default: None, is_optional: false } (185 to 194) 76: Params(ParamsId(7)) (184 to 195) 77: RecordType { fields: NodeId(76), optional: false } (178 to 196) 78: Name (198 to 199) "f" diff --git a/src/snapshots/new_nu_parser__test__node_output@infer_generics.nu.snap b/src/snapshots/new_nu_parser__test__node_output@infer_generics.nu.snap index 70be49e..66edcd4 100644 --- a/src/snapshots/new_nu_parser__test__node_output@infer_generics.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@infer_generics.nu.snap @@ -10,7 +10,7 @@ input_file: tests/infer_generics.nu 3: Name (11 to 12) "x" 4: Name (14 to 15) "T" 5: Type { name: NodeId(4), args: None, optional: false } (14 to 15) -6: PosParam { name: NodeId(3), ty: Some(NodeId(5)), default: None } (11 to 15) +6: PosParam { name: NodeId(3), ty: Some(NodeId(5)), custom_completion: None, default: None, is_optional: false } (11 to 15) 7: Params(ParamsId(1)) (9 to 17) 8: Name (20 to 27) "nothing" 9: Type { name: NodeId(8), args: None, optional: false } (20 to 27) diff --git a/src/snapshots/new_nu_parser__test__node_output@infer_plus.nu.snap b/src/snapshots/new_nu_parser__test__node_output@infer_plus.nu.snap index 571b189..c2c4f2b 100644 --- a/src/snapshots/new_nu_parser__test__node_output@infer_plus.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@infer_plus.nu.snap @@ -10,7 +10,7 @@ input_file: tests/infer_plus.nu 3: Name (20 to 21) "x" 4: Name (23 to 26) "int" 5: Type { name: NodeId(4), args: None, optional: false } (23 to 26) -6: PosParam { name: NodeId(3), ty: Some(NodeId(5)), default: None } (20 to 26) +6: PosParam { name: NodeId(3), ty: Some(NodeId(5)), custom_completion: None, default: None, is_optional: false } (20 to 26) 7: Params(ParamsId(1)) (18 to 28) 8: Name (31 to 38) "nothing" 9: Type { name: NodeId(8), args: None, optional: false } (31 to 38) diff --git a/src/snapshots/new_nu_parser__test__node_output@invalid_types.nu.snap b/src/snapshots/new_nu_parser__test__node_output@invalid_types.nu.snap index 749dfe6..401a8fe 100644 --- a/src/snapshots/new_nu_parser__test__node_output@invalid_types.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@invalid_types.nu.snap @@ -13,7 +13,7 @@ input_file: tests/invalid_types.nu 6: Type { name: NodeId(5), args: None, optional: false } (22 to 28) 7: TypeArgs(TypeArgsId(0)) (16 to 29) 8: Type { name: NodeId(2), args: Some(NodeId(7)), optional: false } (12 to 16) -9: PosParam { name: NodeId(1), ty: Some(NodeId(8)), default: None } (9 to 16) +9: PosParam { name: NodeId(1), ty: Some(NodeId(8)), custom_completion: None, default: None, is_optional: false } (9 to 16) 10: Params(ParamsId(0)) (8 to 30) 11: Variable (33 to 35) "$x" 12: Block(BlockId(0)) (31 to 37) @@ -23,7 +23,7 @@ input_file: tests/invalid_types.nu 16: Name (50 to 54) "list" 17: TypeArgs(TypeArgsId(1)) (54 to 56) 18: Type { name: NodeId(16), args: Some(NodeId(17)), optional: false } (50 to 54) -19: PosParam { name: NodeId(15), ty: Some(NodeId(18)), default: None } (47 to 54) +19: PosParam { name: NodeId(15), ty: Some(NodeId(18)), custom_completion: None, default: None, is_optional: false } (47 to 54) 20: Params(ParamsId(1)) (46 to 57) 21: Variable (60 to 62) "$y" 22: Block(BlockId(1)) (58 to 64) diff --git a/src/snapshots/new_nu_parser__test__node_output@let_mismatch.nu.snap b/src/snapshots/new_nu_parser__test__node_output@let_mismatch.nu.snap index 7de8e98..2eb1b05 100644 --- a/src/snapshots/new_nu_parser__test__node_output@let_mismatch.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@let_mismatch.nu.snap @@ -37,7 +37,7 @@ input_file: tests/let_mismatch.nu 30: Name (138 to 139) "a" 31: Name (141 to 144) "int" 32: Type { name: NodeId(31), args: None, optional: false } (141 to 144) -33: PosParam { name: NodeId(30), ty: Some(NodeId(32)), default: None } (138 to 144) +33: PosParam { name: NodeId(30), ty: Some(NodeId(32)), custom_completion: None, default: None, is_optional: false } (138 to 144) 34: Params(ParamsId(0)) (137 to 145) 35: RecordType { fields: NodeId(34), optional: false } (131 to 146) 36: String (149 to 150) "a" diff --git a/src/snapshots/new_nu_parser__test__node_output@reparse.nu.snap b/src/snapshots/new_nu_parser__test__node_output@reparse.nu.snap index 308e7ee..8ec903f 100644 --- a/src/snapshots/new_nu_parser__test__node_output@reparse.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@reparse.nu.snap @@ -6,7 +6,7 @@ input_file: tests/reparse.nu ==== COMPILER ==== 0: Variable (4 to 5) "x" 1: Name (10 to 11) "a" -2: PosParam { name: NodeId(1), ty: None, default: None } (10 to 11) +2: PosParam { name: NodeId(1), ty: None, custom_completion: None, default: None, is_optional: false } (10 to 11) 3: Params(ParamsId(0)) (9 to 12) 4: Variable (13 to 15) "$a" 5: Block(BlockId(0)) (13 to 16) diff --git a/src/typechecker.rs b/src/typechecker.rs index f304978..b653bfa 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -259,7 +259,9 @@ impl<'a> Typechecker<'a> { AstNode::PosParam { name, ty, + custom_completion: _, default: _, + is_optional: _, } => { if let Some(ty) = ty { let ty_id = self.typecheck_type(ty); @@ -986,7 +988,9 @@ impl<'a> Typechecker<'a> { let AstNode::PosParam { name, ty, + custom_completion: _, default: _, + is_optional: _, } = self.compiler.get_node(*field) else { panic!("internal error: record field isn't Param"); diff --git a/tests/def.nu b/tests/def.nu index 3e7d9a8..522bd7f 100644 --- a/tests/def.nu +++ b/tests/def.nu @@ -2,3 +2,10 @@ def foo [w x: int, y: list>, z: record ] { [ $w $x, $y, $z # define flag def foo-with-flag [--bar: int = 3, --baz(-b), x, y: int] { [$bar, $baz, $x, $y] } + +# define custom completion +def completion [] { [1, 2, 3] } +def foo-with-completion [--bar: int@completion, baz: int@completion] { [$bar, $baz] } + +def foo-optional [x: int, y?: int] { [$x, $y] } +def foo-rest [x: int, ...y] { [$x, $y] }