def parse(cls, ctx, tokens, npargs, flags, breakstack, sortable=False): """ Parse a continuous sequence of `npargs` positional arguments. If npargs is an integer we will consume exactly that many arguments. If it is not an integer then it is a string meaning: * "?": zero or one * "*": zero or more * "+": one or more """ tree = cls(sortable=sortable) tree.spec = PositionalSpec(npargs, flags) nconsumed = 0 # Strip off any preceeding whitespace (note that in most cases this has # already been done but in some cases (such ask kwarg subparser) where # it hasn't while tokens and tokens[0].type in WHITESPACE_TOKENS: tree.children.append(tokens.pop(0)) # If the first non-whitespace token is a cmake-format tag annotating # sortability, then parse it out here and record the annotation if tokens and get_tag(tokens[0]) in ("sortable", "sort"): tree.sortable = True elif tokens and get_tag(tokens[0]) in ("unsortable", "unsort"): tree.sortable = False while tokens: # Break if we have consumed enough positional arguments if pargs_are_full(npargs, nconsumed): break # Break if the next token belongs to a parent parser, i.e. if it # matches a keyword argument of something higher in the stack, or if # it closes a parent group. if should_break(tokens[0], breakstack): # NOTE(josh): if npargs is an exact number of arguments, then we # shouldn't break on kwarg match from a parent parser. Instead, we # should consume the token. This is a hack to deal with # ```install(RUNTIME COMPONENT runtime)``. In this case the second # occurance of "runtime" should not match the ``RUNTIME`` keyword # and should not break the positional parser. # TODO(josh): this is kind of hacky because it will force the positional # parser to consume a right parenthesis and will lead to parse errors # in the event of a missing positional argument. Such errors will be # difficult to debug for the user. if not npargs_is_exact(npargs): break if tokens[0].type == lexer.TokenType.RIGHT_PAREN: break # If this is the start of a parenthetical group, then parse the group # NOTE(josh): syntatically this probably shouldn't be allowed here, but # cmake seems to accept it so we probably should too. if tokens[0].type == lexer.TokenType.LEFT_PAREN: subtree = ParenGroupNode.parse(ctx, tokens, breakstack) tree.children.append(subtree) continue # If it is a whitespace token then put it directly in the parse tree at # the current depth if tokens[0].type in WHITESPACE_TOKENS: tree.children.append(tokens.pop(0)) continue # If it's a comment token not associated with an argument, then put it # directly into the parse tree at the current depth if tokens[0].type in (lexer.TokenType.COMMENT, lexer.TokenType.BRACKET_COMMENT): before = len(tokens) child = CommentNode.consume(ctx, tokens) assert len(tokens) < before, \ "consume_comment didn't consume any tokens" tree.children.append(child) continue # Otherwise is it is a positional argument, so add it to the tree as such if get_normalized_kwarg(tokens[0]) in flags: child = TreeNode(NodeType.FLAG) else: child = TreeNode(NodeType.ARGUMENT) child.children.append(tokens.pop(0)) CommentNode.consume_trailing(ctx, tokens, child) tree.children.append(child) nconsumed += 1 return tree
def parse(cls, ctx, tokens, npargs, ntup, flags, breakstack): """Parse a continuous sequence of `npargs` positional argument pairs. If npargs is an integer we will consume exactly that many arguments. If it is not an integer then it is a string meaning: * "?": zero or one * "*": zero or more * "+": one or more """ tree = cls() subtree = None active_depth = tree npargs_consumed = 0 ntup_consumed = 0 while tokens: # Break if we have consumed enough positional arguments if pargs_are_full(npargs, npargs_consumed): break # Break if the next token belongs to a parent parser, i.e. if it # matches a keyword argument of something higher in the stack, or if # it closes a parent group. if should_break(tokens[0], breakstack): break # Otherwise we will consume the token token = tokens.pop(0) # If it is a whitespace token then put it directly in the parse tree at # the current depth if token.type in WHITESPACE_TOKENS: active_depth.children.append(token) continue # If it's a comment token not associated with an argument, then put it # directly into the parse tree at the current depth if token.type in (lexer.TokenType.COMMENT, lexer.TokenType.BRACKET_COMMENT): child = CommentNode() tree.children.append(child) child.children.append(token) continue if subtree is None: subtree = PositionalGroupNode() tree.children.append(subtree) ntup_consumed = 0 # Otherwise is it is a positional argument, so add it to the tree as such if get_normalized_kwarg(token) in flags: child = TreeNode(NodeType.FLAG) else: child = TreeNode(NodeType.ARGUMENT) child.children.append(token) CommentNode.consume_trailing(ctx, tokens, child) subtree.children.append(child) ntup_consumed += 1 if ntup_consumed >= ntup: npargs_consumed += 1 subtree = None return tree