Shells in OCaml
at wip 923 lines 28 kB view raw
1(* Our AST is essentially Morbig's CST without linebreaks, newlines 2 etc. *) 3open Morbig 4open Import 5include Sast 6 7type t = complete_commands 8 9let rec program : CST.program -> complete_commands = 10 fun x -> 11 match x with 12 | Program_LineBreak_CompleteCommands_LineBreak (_, b, _) -> 13 complete_commands b.value 14 | Program_LineBreak _ -> [] 15 16and complete_commands : CST.complete_commands -> complete_commands = 17 fun x -> 18 match x with 19 | CompleteCommands_CompleteCommands_NewlineList_CompleteCommand (a, _, c) -> 20 let a = complete_commands a.value in 21 let c = complete_command c.value in 22 a @ [ c ] 23 | CompleteCommands_CompleteCommand a -> 24 let a = complete_command a.value in 25 [ a ] 26 27and complete_command : CST.complete_command -> complete_command = 28 fun x -> 29 match x with 30 | CompleteCommand_CList_SeparatorOp (a, b) -> 31 (clist a.value, Some (separator_op b.value)) 32 | CompleteCommand_CList a -> 33 let a = clist a.value in 34 (a, None) 35 36and separator_op : CST.separator_op -> separator = function 37 | CST.SeparatorOp_Uppersand -> Ampersand 38 | CST.SeparatorOp_Semicolon -> Semicolon 39 40and clist : ?sep:separator -> CST.clist -> clist = 41 fun ?(sep = Semicolon) x -> 42 match x with 43 | CList_CList_SeparatorOp_AndOr (a, b, c) -> 44 let next_sep = separator_op b.value in 45 let rest = clist ~sep:next_sep a.value in 46 let command = and_or c.value in 47 Nslist.append rest (Nlist.Singleton (command, sep)) 48 | CList_AndOr a -> 49 let a = and_or a.value in 50 Nslist.singleton sep a 51 52and and_or : ?sep:and_or -> CST.and_or -> pipeline and_or_list = 53 fun ?(sep = Noand_or) x -> 54 match x with 55 | AndOr_Pipeline a -> 56 let a = pipeline a.value in 57 Nslist.singleton sep a 58 | AndOr_AndOr_AndIf_LineBreak_Pipeline (a, _, c) -> 59 let rest = and_or ~sep:And a.value in 60 let c = pipeline c.value in 61 Nslist.append rest (Nlist.Singleton (c, sep)) 62 | AndOr_AndOr_OrIf_LineBreak_Pipeline (a, _, c) -> 63 let rest = and_or ~sep:Or a.value in 64 let c = pipeline c.value in 65 Nslist.append rest (Nlist.Singleton (c, sep)) 66 67and pipeline : CST.pipeline -> pipeline = 68 fun x -> 69 match x with 70 | Pipeline_PipeSequence a -> 71 let a = pipe_sequence a.value in 72 Pipeline a 73 | Pipeline_Bang_PipeSequence a -> 74 let a = pipe_sequence a.value in 75 Pipeline_Bang a 76 77and pipe_sequence : CST.pipe_sequence -> pipe_sequence = 78 fun x -> 79 match x with 80 | PipeSequence_Command a -> 81 let a = command a.value in 82 [ a ] 83 | PipeSequence_PipeSequence_Pipe_LineBreak_Command (a, _, c) -> 84 let rest = pipe_sequence a.value in 85 let c = command c.value in 86 rest @ [ c ] 87 88and command : CST.command -> command = 89 fun x -> 90 match x with 91 | Command_SimpleCommand a -> 92 let a = simple_command a.value in 93 SimpleCommand a 94 | Command_CompoundCommand a -> 95 let a = compound_command a.value in 96 CompoundCommand (a, []) 97 | Command_CompoundCommand_RedirectList (a, rdrs) -> 98 let a = compound_command a.value in 99 let b = redirect_list rdrs.value in 100 CompoundCommand (a, b) 101 | Command_FunctionDefinition a -> 102 let a = function_definition a.value in 103 FunctionDefinition a 104 105and compound_command : CST.compound_command -> compound_command = 106 fun x -> 107 match x with 108 | CompoundCommand_BraceGroup a -> 109 let a = brace_group a.value in 110 BraceGroup a 111 | CompoundCommand_Subshell a -> 112 let a = subshell a.value in 113 Subshell a 114 | CompoundCommand_ForClause a -> 115 let a = for_clause a.value in 116 ForClause a 117 | CompoundCommand_CaseClause a -> 118 let a = case_clause a.value in 119 CaseClause a 120 | CompoundCommand_IfClause a -> 121 let a = if_clause a.value in 122 IfClause a 123 | CompoundCommand_WhileClause a -> 124 let a = while_clause a.value in 125 WhileClause a 126 | CompoundCommand_UntilClause a -> 127 let a = until_clause a.value in 128 UntilClause a 129 130and subshell : CST.subshell -> subshell = 131 fun x -> 132 match x with Subshell_Lparen_CompoundList_Rparen a -> compound_list a.value 133 134and compound_list : CST.compound_list -> compound_list = 135 fun x -> 136 match x with 137 | CompoundList_LineBreak_Term (_, b) -> 138 let b = term b.value in 139 (b, Semicolon) 140 | CompoundList_LineBreak_Term_Separator (_, b, c) -> 141 let b = term b.value in 142 let c = separator c.value in 143 (b, c) 144 145and term : CST.term -> term = 146 fun x -> 147 match x with 148 | Term_Term_Separator_AndOr (a, b, c) -> 149 let rest = term a.value in 150 let b = separator b.value in 151 let c = and_or c.value in 152 Nslist.append rest (Nslist.singleton b c) 153 | Term_AndOr a -> 154 let a = and_or a.value in 155 Nslist.singleton Semicolon a 156 157and for_clause : CST.for_clause -> for_clause = 158 fun x -> 159 match x with 160 | ForClause_For_Name_DoGroup (a, b) -> 161 let a = name a.value in 162 let b = do_group b.value in 163 For_Name_DoGroup (a, b) 164 | ForClause_For_Name_SequentialSep_DoGroup (a, _, c) -> 165 let a = name a.value in 166 let c = do_group c.value in 167 For_Name_DoGroup (a, c) 168 | ForClause_For_Name_LineBreak_In_SequentialSep_DoGroup (a, _, _, d) -> 169 let a = name a.value in 170 let d = do_group d.value in 171 For_Name_DoGroup (a, d) 172 | ForClause_For_Name_LineBreak_In_WordList_SequentialSep_DoGroup 173 (a, _, c, _, e) -> 174 let a = name a.value in 175 let c = wordlist c.value in 176 let e = do_group e.value in 177 For_Name_In_WordList_DoGroup (a, c, e) 178 179and wordlist : CST.wordlist -> wordlist = 180 fun x -> 181 match x with 182 | WordList_WordList_Word (a, b) -> 183 let a = wordlist a.value in 184 let b = word b.value in 185 Nlist.append a (Nlist.Singleton b) 186 | WordList_Word a -> 187 let a = word a.value in 188 Nlist.Singleton a 189 190and case_clause : CST.case_clause -> case_clause = 191 fun x -> 192 match x with 193 | CaseClause_Case_Word_LineBreak_In_LineBreak_CaseList_Esac (a, _, _, d) -> 194 let a = word a.value in 195 let d = case_list d.value in 196 Cases (a, d) 197 | CaseClause_Case_Word_LineBreak_In_LineBreak_CaseListNS_Esac (a, _, _, d) -> 198 let a = word a.value in 199 let d = case_list_ns d.value in 200 Cases (a, d) 201 | CaseClause_Case_Word_LineBreak_In_LineBreak_Esac (a, _, _) -> 202 let a = word a.value in 203 Case a 204 205and case_list_ns : CST.case_list_ns -> case_list = 206 fun x -> 207 match x with 208 | CaseListNS_CaseList_CaseItemNS (a, b) -> 209 let a = case_list a.value in 210 let b = case_item_ns b.value in 211 Nlist.(a @ Singleton b) 212 | CaseListNS_CaseItemNS a -> 213 let a = case_item_ns a.value in 214 Nlist.Singleton a 215 216and case_list : CST.case_list -> case_list = 217 fun x -> 218 match x with 219 | CaseList_CaseList_CaseItem (a, b) -> 220 let a = case_list a.value in 221 let b = case_item b.value in 222 Nlist.(a @ Singleton b) 223 | CaseList_CaseItem a -> 224 let a = case_item a.value in 225 Nlist.Singleton a 226 227and case_item_ns : CST.case_item_ns -> case_item = 228 fun x -> 229 match x with 230 | CaseItemNS_Pattern_Rparen_LineBreak (a, _) -> 231 let a = pattern a.value in 232 Case_pattern (a, None) 233 | CaseItemNS_Pattern_Rparen_CompoundList (a, b) -> 234 let a = pattern a.value in 235 let b = compound_list b.value in 236 Case_pattern (a, Some b) 237 | CaseItemNS_Lparen_Pattern_Rparen_LineBreak (a, _) -> 238 let a = pattern a.value in 239 Case_pattern (a, None) 240 | CaseItemNS_Lparen_Pattern_Rparen_CompoundList (a, b) -> 241 let a = pattern a.value in 242 let b = compound_list b.value in 243 Case_pattern (a, Some b) 244 245and case_item : CST.case_item -> case_item = 246 fun x -> 247 match x with 248 | CaseItem_Pattern_Rparen_LineBreak_Dsemi_LineBreak (a, _, _) -> 249 let a = pattern a.value in 250 Case_pattern (a, None) 251 | CaseItem_Pattern_Rparen_CompoundList_Dsemi_LineBreak (a, b, _) -> 252 let a = pattern a.value in 253 let b = compound_list b.value in 254 Case_pattern (a, Some b) 255 | CaseItem_Lparen_Pattern_Rparen_LineBreak_Dsemi_LineBreak (a, _, _) -> 256 let a = pattern a.value in 257 Case_pattern (a, None) 258 | CaseItem_Lparen_Pattern_Rparen_CompoundList_Dsemi_LineBreak (a, b, _) -> 259 let a = pattern a.value in 260 let b = compound_list b.value in 261 Case_pattern (a, Some b) 262 263and pattern : CST.pattern -> pattern = 264 fun x -> 265 match x with 266 | Pattern_Word a -> 267 let a = word a.value in 268 Nlist.Singleton a 269 | Pattern_Pattern_Pipe_Word (a, b) -> 270 let a = pattern a.value in 271 let b = word b.value in 272 Nlist.(a @ Singleton b) 273 274and if_clause : CST.if_clause -> if_clause = 275 fun x -> 276 match x with 277 | IfClause_If_CompoundList_Then_CompoundList_ElsePart_Fi (a, b, c) -> 278 let a = compound_list a.value in 279 let b = compound_list b.value in 280 let c = else_part c.value in 281 If_then_else (a, b, c) 282 | IfClause_If_CompoundList_Then_CompoundList_Fi (a, b) -> 283 let a = compound_list a.value in 284 let b = compound_list b.value in 285 If_then (a, b) 286 287and else_part : CST.else_part -> else_part = 288 fun x -> 289 match x with 290 | ElsePart_Elif_CompoundList_Then_CompoundList (a, b) -> 291 let a = compound_list a.value in 292 let b = compound_list b.value in 293 Elif_then (a, b) 294 | ElsePart_Elif_CompoundList_Then_CompoundList_ElsePart (a, b, c) -> 295 let a = compound_list a.value in 296 let b = compound_list b.value in 297 let c = else_part c.value in 298 Elif_then_else (a, b, c) 299 | ElsePart_Else_CompoundList a -> 300 let a = compound_list a.value in 301 Else a 302 303and while_clause : CST.while_clause -> while_clause = 304 fun x -> 305 match x with 306 | WhileClause_While_CompoundList_DoGroup (a, b) -> 307 let a = compound_list a.value in 308 let b = do_group b.value in 309 While (a, b) 310 311and until_clause : CST.until_clause -> until_clause = 312 fun x -> 313 match x with 314 | UntilClause_Until_CompoundList_DoGroup (a, b) -> 315 let a = compound_list a.value in 316 let b = do_group b.value in 317 Until (a, b) 318 319and function_definition : CST.function_definition -> function_definition = 320 fun x -> 321 match x with 322 | FunctionDefinition_Fname_Lparen_Rparen_LineBreak_FunctionBody (a, _, c) -> 323 let CST.(Fname_Name (Name a)) = a.value in 324 let c = function_body c.value in 325 (a, c) 326 327and function_body : CST.function_body -> function_body = 328 fun x -> 329 match x with 330 | FunctionBody_CompoundCommand a -> 331 let a = compound_command a.value in 332 (a, []) 333 | FunctionBody_CompoundCommand_RedirectList (a, b) -> 334 let a = compound_command a.value in 335 let b = redirect_list b.value in 336 (a, b) 337 338and brace_group : CST.brace_group -> brace_group = 339 fun x -> 340 match x with 341 | BraceGroup_LBrace_CompoundList_RBrace a -> 342 let a = compound_list a.value in 343 a 344 345and do_group : CST.do_group -> do_group = 346 fun x -> 347 match x with 348 | DoGroup_Do_CompoundList_Done a -> 349 let a = compound_list a.value in 350 a 351 352and simple_command : CST.simple_command -> simple_command = 353 fun x -> 354 match x with 355 | SimpleCommand_CmdPrefix_CmdWord_CmdSuffix (a, b, c) -> 356 let a = cmd_prefix a.value in 357 let b = cmd_word b.value in 358 let c = cmd_suffix c.value in 359 Prefixed (a, Some b, Some c) 360 | SimpleCommand_CmdPrefix_CmdWord (a, b) -> 361 let a = cmd_prefix a.value in 362 let b = cmd_word b.value in 363 Prefixed (a, Some b, None) 364 | SimpleCommand_CmdPrefix a -> 365 let a = cmd_prefix a.value in 366 Prefixed (a, None, None) 367 | SimpleCommand_CmdName_CmdSuffix (a, b) -> 368 let a = cmd_name a.value in 369 let b = cmd_suffix b.value in 370 Named (a, Some b) 371 | SimpleCommand_CmdName a -> 372 let a = cmd_name a.value in 373 Named (a, None) 374 375and cmd_name : CST.cmd_name -> cmd_name = 376 fun x -> 377 match x with 378 | CmdName_Word a -> 379 let a = word a.value in 380 a 381 382and cmd_word : CST.cmd_word -> cmd_word = 383 fun x -> 384 match x with 385 | CmdWord_Word a -> 386 let a = word a.value in 387 a 388 389and cmd_prefix : CST.cmd_prefix -> cmd_prefix = 390 fun x -> 391 match x with 392 | CmdPrefix_IoRedirect a -> 393 let a = io_redirect a.value in 394 [ Prefix_redirect a ] 395 | CmdPrefix_CmdPrefix_IoRedirect (a, b) -> 396 let a = cmd_prefix a.value in 397 let b = io_redirect b.value in 398 a @ [ Prefix_redirect b ] 399 | CmdPrefix_AssignmentWord a -> 400 let a = assignment_word a.value in 401 [ Prefix_assignment a ] 402 | CmdPrefix_CmdPrefix_AssignmentWord (a, b) -> 403 let a = cmd_prefix a.value in 404 let b = assignment_word b.value in 405 a @ [ Prefix_assignment b ] 406 407and cmd_suffix : CST.cmd_suffix -> cmd_suffix = 408 fun x -> 409 match x with 410 | CmdSuffix_IoRedirect a -> 411 let a = io_redirect a.value in 412 [ Suffix_redirect a ] 413 | CmdSuffix_CmdSuffix_IoRedirect (a, b) -> 414 let a = cmd_suffix a.value in 415 let b = io_redirect b.value in 416 a @ [ Suffix_redirect b ] 417 | CmdSuffix_Word a -> 418 let a = word a.value in 419 [ Suffix_word a ] 420 | CmdSuffix_CmdSuffix_Word (a, b) -> 421 let a = cmd_suffix a.value in 422 let b = word b.value in 423 a @ [ Suffix_word b ] 424 425and redirect_list : CST.redirect_list -> redirects = 426 fun x -> 427 match x with 428 | RedirectList_IoRedirect a -> 429 let a = io_redirect a.value in 430 [ a ] 431 | RedirectList_RedirectList_IoRedirect (a, b) -> 432 let a = redirect_list a.value in 433 let b = io_redirect b.value in 434 a @ [ b ] 435 436and io_op_default_fd : io_op -> io_number = function 437 | Io_op_less -> 0 438 | Io_op_lessand -> 0 439 | _ -> 1 440 441and io_redirect : CST.io_redirect -> io_redirect = 442 fun x -> 443 match x with 444 | IoRedirect_IoFile a -> 445 let a = io_file a.value in 446 IoRedirect_IoFile (io_op_default_fd (fst a), a) 447 | IoRedirect_IoNumber_IoFile (a, b) -> 448 let a = io_number a in 449 let b = io_file b.value in 450 IoRedirect_IoFile (a, b) 451 | IoRedirect_IoHere a -> 452 let a = io_here a.value in 453 IoRedirect_IoHere (0, a) 454 | IoRedirect_IoNumber_IoHere (a, b) -> 455 let a = io_number a in 456 let b = io_here b.value in 457 IoRedirect_IoHere (a, b) 458 459and io_file : CST.io_file -> io_file = 460 fun x -> 461 match x with 462 | IoFile_Less_FileName a -> 463 let a = filename a.value in 464 (Io_op_less, a) 465 | IoFile_LessAnd_FileName a -> 466 let a = filename a.value in 467 (Io_op_lessand, a) 468 | IoFile_Great_FileName a -> 469 let a = filename a.value in 470 (Io_op_great, a) 471 | IoFile_GreatAnd_FileName a -> 472 let a = filename a.value in 473 (Io_op_greatand, a) 474 | IoFile_DGreat_FileName a -> 475 let a = filename a.value in 476 (Io_op_dgreat, a) 477 | IoFile_LessGreat_FileName a -> 478 let a = filename a.value in 479 (Io_op_lessgreat, a) 480 | IoFile_AndGreat_FileName a -> 481 let a = filename a.value in 482 (Io_op_andgreat, a) 483 | IoFile_Clobber_FileName a -> 484 let a = filename a.value in 485 (Io_op_clobber, a) 486 487and filename : CST.filename -> filename = 488 fun x -> 489 match x with 490 | Filename_Word a -> 491 let a = word a.value in 492 a 493 494and io_here : CST.io_here -> io_here = 495 fun x -> 496 match x with 497 | IoHere_DLess_HereEnd (a, b) -> 498 let a = here_end a.value in 499 IoHere (a, word !b.value) 500 | IoHere_DLessDash_HereEnd (a, b) -> 501 let a = here_end a.value in 502 IoHere_Dash (a, word !b.value) 503 504and here_end : CST.here_end -> here_end = 505 fun x -> 506 match x with 507 | HereEnd_Word a -> 508 let a = word a.value in 509 a 510 511and separator : CST.separator -> separator = 512 fun x -> 513 match x with 514 | Separator_SeparatorOp_LineBreak (a, _) -> separator_op a.value 515 | Separator_NewLineList _ -> Semicolon 516 517and word : CST.word -> word = fun x -> match x with Word (_, b) -> word_cst b 518and word_cst : CST.word_cst -> word_cst = fun v -> List.map word_component v 519 520and need_escaped = function 521 | '(' | '`' | '$' | ')' | '0' .. '9' -> true 522 | _ -> false 523 524and remove_double_escape s = 525 let len = String.length s in 526 let i = ref 0 in 527 let r = ref "" in 528 while !i <= len - 1 do 529 if 530 Char.equal (String.unsafe_get s !i) '\\' 531 && need_escaped (String.unsafe_get s (!i + 1)) 532 then begin 533 r := !r ^ String.make 1 @@ String.unsafe_get s (!i + 1); 534 i := !i + 2 535 end 536 else begin 537 r := !r ^ String.make 1 @@ String.unsafe_get s !i; 538 incr i 539 end 540 done; 541 !r 542 543and word_component : CST.word_component -> word_component = 544 fun x -> 545 match x with 546 | WordSubshell (_a, b) -> 547 let b = program b.value in 548 WordSubshell b 549 | WordName a -> WordName (remove_double_escape a) 550 | WordAssignmentWord a -> 551 let a = assignment_word a in 552 WordAssignmentWord a 553 | WordDoubleQuoted a -> 554 let a = word a in 555 WordDoubleQuoted a 556 | WordSingleQuoted a -> 557 let a = word a in 558 WordSingleQuoted a 559 | WordTildePrefix a -> WordTildePrefix a 560 | WordLiteral a -> WordLiteral (remove_double_escape a) 561 | WordVariable a -> 562 let a = variable a in 563 WordVariable a 564 | WordGlobAll -> WordGlobAll 565 | WordGlobAny -> WordGlobAny 566 | WordArithmeticExpression s -> WordArithmeticExpression (word s) 567 | WordReBracketExpression a -> 568 let a = bracket_expression a in 569 WordReBracketExpression a 570 | WordEmpty -> WordEmpty 571 572and bracket_expression : CST.bracket_expression -> bracket_expression = 573 fun x -> 574 match x with 575 | BracketExpression_LBRACKET_MatchingList_RBRACKET a -> 576 let a = matching_list a in 577 BracketExpression_LBRACKET_MatchingList_RBRACKET a 578 | BracketExpression_LBRACKET_NonMatchingList_RBRACKET a -> 579 let a = nonmatching_list a in 580 BracketExpression_LBRACKET_NonMatchingList_RBRACKET a 581 582and matching_list : CST.matching_list -> matching_list = 583 fun x -> 584 match x with 585 | MatchingList_BracketList a -> 586 let a = bracket_list a in 587 MatchingList_BracketList a 588 589and nonmatching_list : CST.nonmatching_list -> nonmatching_list = 590 fun x -> 591 match x with 592 | NonMatchingList_BracketList a -> 593 let a = bracket_list a in 594 NonMatchingList_BracketList a 595 596and bracket_list : CST.bracket_list -> bracket_list = 597 fun x -> 598 match x with 599 | BracketList_FollowList a -> 600 let a = follow_list a in 601 BracketList_FollowList a 602 | BracketList_FollowList_MINUS a -> 603 let a = follow_list a in 604 BracketList_FollowList_MINUS a 605 606and follow_list : CST.follow_list -> follow_list = 607 fun x -> 608 match x with 609 | FollowList_ExpressionTerm a -> 610 let a = expression_term a in 611 FollowList_ExpressionTerm a 612 | FollowList_FollowList_ExpressionTerm (a, b) -> 613 let a = follow_list a in 614 let b = expression_term b in 615 FollowList_FollowList_ExpressionTerm (a, b) 616 617and expression_term : CST.expression_term -> expression_term = 618 fun x -> 619 match x with 620 | ExpressionTerm_SingleExpression a -> 621 let a = single_expression a in 622 ExpressionTerm_SingleExpression a 623 | ExpressionTerm_RangeExpression a -> 624 let a = range_expression a in 625 ExpressionTerm_RangeExpression a 626 627and single_expression : CST.single_expression -> single_expression = 628 fun x -> 629 match x with 630 | SingleExpression_EndRange a -> 631 let a = end_range a in 632 SingleExpression_EndRange a 633 | SingleExpression_CharacterClass a -> 634 let a = character_class a in 635 SingleExpression_CharacterClass a 636 | SingleExpression_EquivalenceClass a -> 637 let a = equivalence_class a in 638 SingleExpression_EquivalenceClass a 639 640and range_expression : CST.range_expression -> range_expression = 641 fun x -> 642 match x with 643 | RangeExpression_StartRange_EndRange (a, b) -> 644 let a = start_range a in 645 let b = end_range b in 646 RangeExpression_StartRange_EndRange (a, b) 647 | RangeExpression_StartRange_MINUS a -> 648 let a = start_range a in 649 RangeExpression_StartRange_MINUS a 650 651and start_range : CST.start_range -> start_range = 652 fun x -> 653 match x with 654 | StartRange_EndRange_MINUS a -> 655 let a = end_range a in 656 StartRange_EndRange_MINUS a 657 658and end_range : CST.end_range -> end_range = 659 fun x -> 660 match x with 661 | EndRange_COLLELEMSINGLE a -> EndRange_COLLELEMSINGLE a 662 | EndRangeCollatingSymbol a -> 663 let a = collating_symbol a in 664 EndRangeCollatingSymbol a 665 666and collating_symbol : CST.collating_symbol -> collating_symbol = 667 fun x -> 668 match x with 669 | CollatingSymbol_OpenDot_COLLELEMSINGLE_DotClose a -> 670 CollatingSymbol_OpenDot_COLLELEMSINGLE_DotClose a 671 | CollatingSymbol_OpenDot_COLLELEMMULTI_DotClose a -> 672 CollatingSymbol_OpenDot_COLLELEMMULTI_DotClose a 673 | CollatingSymbol_OpenDot_METACHAR_DotClose a -> 674 CollatingSymbol_OpenDot_METACHAR_DotClose a 675 676and equivalence_class : CST.equivalence_class -> equivalence_class = 677 fun x -> 678 match x with 679 | EquivalenceClass_OpenEqual_COLLELEMSINGLE_EqualClose a -> 680 EquivalenceClass_OpenEqual_COLLELEMSINGLE_EqualClose a 681 | EquivalenceClass_OpenEqual_COLLELEMMULTI_EqualClose a -> 682 EquivalenceClass_OpenEqual_COLLELEMMULTI_EqualClose a 683 684and character_class : CST.character_class -> character_class = 685 fun x -> 686 match x with 687 | CharacterClass_OpenColon_CLASSNAME_ColonClose a -> 688 let a = class_name a in 689 CharacterClass_OpenColon_CLASSNAME_ColonClose a 690 691and class_name : CST.class_name -> class_name = 692 fun x -> match x with ClassName a -> ClassName a 693 694and variable : CST.variable -> variable = 695 fun x -> 696 match x with 697 | VariableAtom (a, b) -> 698 let b = variable_attribute b in 699 VariableAtom (a, b) 700 701and variable_attribute : CST.variable_attribute -> variable_attribute = 702 fun x -> 703 match x with 704 | NoAttribute -> NoAttribute 705 | ParameterLength -> ParameterLength 706 | UseDefaultValues (a, b) -> 707 let b = word b in 708 UseDefaultValues (a, b) 709 | AssignDefaultValues (a, b) -> 710 let b = word b in 711 AssignDefaultValues (a, b) 712 | IndicateErrorifNullorUnset (a, b) -> 713 let b = word b in 714 IndicateErrorifNullorUnset (a, b) 715 | UseAlternativeValue (a, b) -> 716 let b = word b in 717 UseAlternativeValue (a, b) 718 | RemoveSmallestSuffixPattern a -> 719 let a = word a in 720 RemoveSmallestSuffixPattern a 721 | RemoveLargestSuffixPattern a -> 722 let a = word a in 723 RemoveLargestSuffixPattern a 724 | RemoveSmallestPrefixPattern a -> 725 let a = word a in 726 RemoveSmallestPrefixPattern a 727 | RemoveLargestPrefixPattern a -> 728 let a = word a in 729 RemoveLargestPrefixPattern a 730 731and name : CST.name -> name = fun x -> match x with Name a -> Name a 732 733and assignment_word : CST.assignment_word -> assignment_word = 734 fun (a, b) -> 735 let a = name a in 736 let b = word b in 737 (a, b) 738 739and io_number : CST.io_number -> io_number = 740 fun x -> match x with IONumber a -> int_of_string a 741 742let of_program = program 743 744module Dump = struct 745 let pp ppf v = 746 let yjs = complete_commands_to_yojson v in 747 Yojson.Safe.pretty_print ppf yjs 748end 749 750let () = 751 Printexc.register_printer (function 752 | Morbig.Errors.DuringParsing pos -> 753 Some 754 (Fmt.str "Error during parsing (potentially non-POSIX): %s" 755 (Morbig.string_of_lexing_position pos)) 756 | Morbig.Errors.DuringLexing (pos, s) -> 757 Some 758 (Fmt.str "Error during lexing of \"%s\": %s" s 759 (Morbig.string_of_lexing_position pos)) 760 | Morbig.Errors.DuringAliasing (pos, s) -> 761 Some 762 (Fmt.str "Error during aliasing of \"%s\": %s" s 763 (Morbig.string_of_lexing_position pos)) 764 | _ -> None) 765 766let of_string ?(filename = "-") s = 767 let f = Morbig.parse_string filename s in 768 of_program f 769 770let of_file path = 771 let fname = Eio.Path.native_exn path in 772 Eio.Path.load path |> of_string ~filename:fname 773 774let rec word_component_to_string : 775 ?field_splitting:bool -> word_component -> string list = 776 fun ?(field_splitting = true) -> function 777 | WordName s -> [ s ] 778 | WordLiteral s -> [ s ] 779 | WordDoubleQuoted s -> word_components_to_strings ~field_splitting:false s 780 | WordSingleQuoted s -> word_components_to_strings ~field_splitting:false s 781 | WordGlobAll -> [ "*" ] 782 | WordGlobAny -> [ "?" ] 783 | WordEmpty -> [ "" ] 784 | WordAssignmentWord (Name p, v) -> 785 p :: "=" :: word_components_to_strings ~field_splitting v 786 | WordSubshell _ -> 787 Fmt.failwith 788 "This is an error in Merry, subshells should already have been \ 789 expanded by now!" 790 | v -> 791 Fmt.failwith "conversion of %a" Yojson.Safe.pp 792 (word_component_to_yojson v) 793 794and word_components_to_strings ?(field_splitting = true) ws = 795 if field_splitting then 796 List.concat_map (word_component_to_string ~field_splitting) ws 797 else 798 [ 799 String.concat "" 800 (List.concat_map (word_component_to_string ~field_splitting) ws); 801 ] 802 803class check_ast = 804 object (_) 805 inherit [bool] Sast.fold 806 method int _ ctx = ctx 807 method bool _ ctx = ctx 808 method string _ ctx = ctx 809 method char _ ctx = ctx 810 method option f v ctx = Option.fold ~none:ctx ~some:(fun i -> f i ctx) v 811 method nlist__t f v ctx = Nlist.fold_left (fun acc i -> f i acc) ctx v 812 813 method nslist__t f g v ctx = 814 Nslist.fold_left (fun acc a b -> f a acc |> g b) ctx v 815 816 method list f v ctx = List.fold_left (fun acc i -> f i acc) ctx v 817 end 818 819let has_async ast = 820 let o = 821 object 822 inherit check_ast as super 823 824 method! complete_command v ctx = 825 match v with 826 | _, Some Ampersand -> true 827 | _ -> super#complete_command v ctx 828 829 method! clist l ctx = 830 let v = 831 Nlist.to_list l 832 |> List.exists (function _, Ampersand -> true | _ -> false) 833 in 834 if v then v else super#clist l ctx 835 836 method! term t ctx = 837 let v = 838 Nlist.to_list t 839 |> List.exists (function _, Ampersand -> true | _ -> false) 840 in 841 if v then v else super#term t ctx 842 end 843 in 844 o#complete_command ast false 845 846let has_glob ast = 847 let o = 848 object 849 inherit check_ast as super 850 851 method! word_component v ctx = 852 match v with 853 | WordGlobAll | WordGlobAny -> true 854 | _ -> super#word_component v ctx 855 end 856 in 857 o#word_cst ast false 858 859module Fragment = struct 860 let make ?(splittable = false) ?(globbable = false) ?(tilde_expansion = false) 861 ?(join = `No) txt = 862 { txt; splittable; join; globbable; tilde_expansion } 863 864 let empty = make "" 865 let to_string { txt; _ } = txt 866 867 let join ~sep f1 f2 = 868 { 869 f1 with 870 txt = f1.txt ^ sep ^ f2.txt; 871 globbable = f1.globbable || f2.globbable; 872 } 873 874 let join_list ~sep fs = List.fold_left (join ~sep) empty fs |> to_string 875 876 let pp_join ppf = function 877 | `No -> Fmt.pf ppf "no" 878 | `With_previous -> Fmt.pf ppf "with-previous" 879 | `With_next -> Fmt.pf ppf "with-next" 880 881 let pp ppf { txt; join; splittable; globbable; tilde_expansion } = 882 Fmt.pf ppf 883 "{ txt = %s; join = %a; splittable = %b; globbable = %b; tilde_expansion \ 884 = %b }" 885 txt pp_join join splittable globbable tilde_expansion 886 887 let handle_joins cst = 888 let rec loop = function 889 | [] -> [] 890 | [ x ] -> [ { x with join = `No } ] 891 | x :: { txt; join = `With_previous; globbable; _ } :: rest -> 892 loop 893 ({ 894 x with 895 join = `No; 896 txt = x.txt ^ txt; 897 globbable = x.globbable || globbable; 898 } 899 :: rest) 900 | { txt; join = `With_next; globbable; _ } :: y :: rest -> 901 { y with txt = txt ^ y.txt; globbable = globbable || y.globbable } 902 :: loop rest 903 | x :: xs -> x :: loop xs 904 in 905 let v = loop cst in 906 let has_a_tilde = List.exists (fun f -> f.tilde_expansion) v in 907 let v = 908 if has_a_tilde then [ List.fold_left (join ~sep:"") empty v ] else v 909 in 910 (* TODO: Blergh, this is horrible, surely there is a better way? Maybe morbig 911 should not parse these separately... *) 912 let rec recombine_equals = function 913 | [] -> [] 914 | [ x ] -> [ x ] 915 | ({ txt; _ } as x) :: y :: rest -> ( 916 let s = String.length txt in 917 match String.get txt (s - 1) with 918 | '=' -> { y with txt = txt ^ y.txt } :: recombine_equals rest 919 | (exception Invalid_argument _) | _ -> 920 x :: recombine_equals (y :: rest)) 921 in 922 recombine_equals v 923end