nodes: 0, module; 1, function_definition; 2, function_name:sort_canonical; 3, parameters; 4, block; 5, identifier:keyword; 6, identifier:stmts; 7, expression_statement; 8, try_statement; 9, expression_statement; 10, comment:# keep the order of data definition statements and case; 11, expression_statement; 12, for_statement; 13, comment:# then copy all other statements (extensions); 14, expression_statement; 15, return_statement; 16, comment:"""Sort all `stmts` in the canonical order defined by `keyword`.
      Return the sorted list.  The `stmt` list is not modified.
      If `keyword` does not have a canonical order, the list is returned
      as is.
      """; 17, block; 18, except_clause; 19, assignment; 20, assignment; 21, tuple_pattern; 22, call; 23, comment:# keep comments before a statement together with that statement; 24, block; 25, call; 26, identifier:res; 27, expression_statement; 28, identifier:KeyError; 29, block; 30, identifier:res; 31, list; 32, identifier:keep; 33, binary_operator:[s[0] for s in data_def_stmts] + ['case']; 34, identifier:kw; 35, identifier:_spec; 36, identifier:flatten_spec; 37, argument_list; 38, expression_statement; 39, for_statement; 40, attribute; 41, argument_list; 42, assignment; 43, return_statement; 44, list_comprehension; 45, list; 46, identifier:subspec; 47, assignment; 48, identifier:s; 49, identifier:stmts; 50, block; 51, identifier:res; 52, identifier:extend; 53, list_comprehension; 54, tuple_pattern; 55, subscript; 56, identifier:stmts; 57, subscript; 58, for_in_clause; 59, string; 60, identifier:comments; 61, list; 62, if_statement; 63, identifier:stmt; 64, for_in_clause; 65, if_clause; 66, identifier:_arg_type; 67, identifier:subspec; 68, identifier:stmt_map; 69, identifier:keyword; 70, identifier:s; 71, integer:0; 72, identifier:s; 73, identifier:data_def_stmts; 74, string_content:case; 75, comparison_operator:s.keyword == '_comment'; 76, block; 77, elif_clause; 78, else_clause; 79, identifier:stmt; 80, identifier:stmts; 81, comparison_operator:stmt not in res; 82, attribute; 83, string; 84, expression_statement; 85, boolean_operator; 86, block; 87, block; 88, identifier:stmt; 89, identifier:res; 90, identifier:s; 91, identifier:keyword; 92, string_content:_comment; 93, call; 94, comparison_operator:s.keyword == kw; 95, comparison_operator:kw not in keep; 96, expression_statement; 97, expression_statement; 98, expression_statement; 99, expression_statement; 100, attribute; 101, argument_list; 102, attribute; 103, identifier:kw; 104, identifier:kw; 105, identifier:keep; 106, call; 107, assignment; 108, call; 109, assignment; 110, identifier:comments; 111, identifier:append; 112, identifier:s; 113, identifier:s; 114, identifier:keyword; 115, attribute; 116, argument_list; 117, identifier:comments; 118, list; 119, attribute; 120, argument_list; 121, identifier:comments; 122, list; 123, identifier:res; 124, identifier:extend; 125, identifier:comments; 126, identifier:res; 127, identifier:append; 128, identifier:s
code: def sort_canonical(keyword, stmts):
      """Sort all `stmts` in the canonical order defined by `keyword`.
      Return the sorted list.  The `stmt` list is not modified.
      If `keyword` does not have a canonical order, the list is returned
      as is.
      """
  
      try:
          (_arg_type, subspec) = stmt_map[keyword]
      except KeyError:
          return stmts
      res = []
      # keep the order of data definition statements and case
      keep = [s[0] for s in data_def_stmts] + ['case']
      for (kw, _spec) in flatten_spec(subspec):
          # keep comments before a statement together with that statement
          comments = []
          for s in stmts:
              if s.keyword == '_comment':
                  comments.append(s)
              elif s.keyword == kw and kw not in keep:
                  res.extend(comments)
                  comments = []
                  res.append(s)
              else:
                  comments = []
  
      # then copy all other statements (extensions)
      res.extend([stmt for stmt in stmts if stmt not in res])
      return res