@@ -159,7 +159,7 @@ pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) {
159159 working_set. error ( ParseError :: DuplicateCommandDef ( spans[ 1 ] ) ) ;
160160 }
161161 }
162- } else if name == b"extern" && spans. len ( ) = = 3 {
162+ } else if name == b"extern" && spans. len ( ) > = 3 {
163163 let name_expr = parse_string ( working_set, spans[ 1 ] ) ;
164164 let name = name_expr. as_string ( ) ;
165165
@@ -430,40 +430,7 @@ pub fn parse_def(
430430 * declaration = signature. clone ( ) . into_block_command ( block_id) ;
431431
432432 let mut block = working_set. get_block_mut ( block_id) ;
433- let calls_itself = block. pipelines . iter ( ) . any ( |pipeline| {
434- pipeline
435- . elements
436- . iter ( )
437- . any ( |pipe_element| match pipe_element {
438- PipelineElement :: Expression (
439- _,
440- Expression {
441- expr : Expr :: Call ( call_expr) ,
442- ..
443- } ,
444- ) => {
445- if call_expr. decl_id == decl_id {
446- return true ;
447- }
448- call_expr. arguments . iter ( ) . any ( |arg| match arg {
449- Argument :: Positional ( Expression { expr, .. } ) => match expr {
450- Expr :: Keyword ( .., expr) => {
451- let expr = expr. as_ref ( ) ;
452- let Expression { expr, .. } = expr;
453- match expr {
454- Expr :: Call ( call_expr2) => call_expr2. decl_id == decl_id,
455- _ => false ,
456- }
457- }
458- Expr :: Call ( call_expr2) => call_expr2. decl_id == decl_id,
459- _ => false ,
460- } ,
461- _ => false ,
462- } )
463- }
464- _ => false ,
465- } )
466- } ) ;
433+ let calls_itself = block_calls_itself ( block, decl_id) ;
467434 block. recursive = Some ( calls_itself) ;
468435 block. signature = signature;
469436 block. redirect_env = def_call == b"def-env" ;
@@ -543,6 +510,7 @@ pub fn parse_extern(
543510 } ;
544511 let name_expr = call. positional_nth ( 0 ) ;
545512 let sig = call. positional_nth ( 1 ) ;
513+ let body = call. positional_nth ( 2 ) ;
546514
547515 if let ( Some ( name_expr) , Some ( sig) ) = ( name_expr, sig) {
548516 if let ( Some ( name) , Some ( mut signature) ) = ( & name_expr. as_string ( ) , sig. as_signature ( ) ) {
@@ -581,13 +549,29 @@ pub fn parse_extern(
581549 signature. extra_usage = extra_usage. clone ( ) ;
582550 signature. allows_unknown_args = true ;
583551
584- let decl = KnownExternal {
585- name : external_name,
586- usage : [ usage, extra_usage] . join ( "\n " ) ,
587- signature,
588- } ;
552+ if let Some ( block_id) = body. and_then ( |x| x. as_block ( ) ) {
553+ if signature. rest_positional . is_none ( ) {
554+ working_set. error ( ParseError :: InternalError (
555+ "Extern block must have a rest positional argument" . into ( ) ,
556+ name_expr. span ,
557+ ) ) ;
558+ } else {
559+ * declaration = signature. clone ( ) . into_block_command ( block_id) ;
560+
561+ let block = working_set. get_block_mut ( block_id) ;
562+ let calls_itself = block_calls_itself ( block, decl_id) ;
563+ block. recursive = Some ( calls_itself) ;
564+ block. signature = signature;
565+ }
566+ } else {
567+ let decl = KnownExternal {
568+ name : external_name,
569+ usage : [ usage, extra_usage] . join ( "\n " ) ,
570+ signature,
571+ } ;
589572
590- * declaration = Box :: new ( decl) ;
573+ * declaration = Box :: new ( decl) ;
574+ }
591575 } else {
592576 working_set. error ( ParseError :: InternalError (
593577 "Predeclaration failed to add declaration" . into ( ) ,
@@ -614,6 +598,43 @@ pub fn parse_extern(
614598 } ] )
615599}
616600
601+ fn block_calls_itself ( block : & Block , decl_id : usize ) -> bool {
602+ block. pipelines . iter ( ) . any ( |pipeline| {
603+ pipeline
604+ . elements
605+ . iter ( )
606+ . any ( |pipe_element| match pipe_element {
607+ PipelineElement :: Expression (
608+ _,
609+ Expression {
610+ expr : Expr :: Call ( call_expr) ,
611+ ..
612+ } ,
613+ ) => {
614+ if call_expr. decl_id == decl_id {
615+ return true ;
616+ }
617+ call_expr. arguments . iter ( ) . any ( |arg| match arg {
618+ Argument :: Positional ( Expression { expr, .. } ) => match expr {
619+ Expr :: Keyword ( .., expr) => {
620+ let expr = expr. as_ref ( ) ;
621+ let Expression { expr, .. } = expr;
622+ match expr {
623+ Expr :: Call ( call_expr2) => call_expr2. decl_id == decl_id,
624+ _ => false ,
625+ }
626+ }
627+ Expr :: Call ( call_expr2) => call_expr2. decl_id == decl_id,
628+ _ => false ,
629+ } ,
630+ _ => false ,
631+ } )
632+ }
633+ _ => false ,
634+ } )
635+ } )
636+ }
637+
617638pub fn parse_alias (
618639 working_set : & mut StateWorkingSet ,
619640 lite_command : & LiteCommand ,
0 commit comments