def parse(cls, ctx, tokens, npargs, kwargs, flags, breakstack): """ Standard parser for the commands in the form of:: command_name(parg1 parg2 parg3... KEYWORD1 kwarg1 kwarg2... KEYWORD2 kwarg3 kwarg4... FLAG1 FLAG2 FLAG3) The parser starts off as a positional parser. If a keyword or flag is encountered the positional parser is popped off the parse stack. If it was a keyword then the keyword parser is pushed on the parse stack. If it was a flag than a new flag parser is pushed onto the stack. """ if isinstance(npargs, IMPLICIT_PARG_TYPES): pargspecs = [PositionalSpec(npargs, flags=flags, legacy=True)] else: assert isinstance(npargs, (list, tuple)), ( "Invalid positional group specification of type {}".format( type(npargs).__name__)) assert flags is None, ( "Invalid usage of old-style 'flags' parameter with new style" " positional group specifications") pargspecs = npargs return cls.parse2(ctx, tokens, CommandSpec("<none>", pargspecs), kwargs, breakstack)
def parse_pspec(pargs, flags): """ Parse a positional argument specification. """ out = [] # Default pargs is "*" if pargs is None: pargs = ZERO_OR_MORE # If we only have one scalar specification, return a legacy specification if isinstance(pargs, STRING_TYPES + (int, )): return [PositionalSpec(pargs, flags=flags, legacy=True)] if flags: raise UserError( "Illegal use of top-level 'flags' keyword with new-style positional" " argument declaration") # If we only have one dictionary specification, then put it in a dictionary # so that we can do the rest consistently if isinstance(pargs, dict): pargs = [pargs] for pargdecl in pargs: if isinstance(pargdecl, STRING_TYPES + (int, )): # A scalar declaration is interpreted as npargs out.append(PositionalSpec(pargdecl)) continue if isinstance(pargdecl, dict): # A dictionary is interpreted as init kwargs if "npargs" not in pargdecl: pargdecl = dict(pargdecl) pargdecl["nargs"] = ZERO_OR_MORE out.append(PositionalSpec(**pargdecl)) continue if isinstance(pargdecl, (list, tuple)): # A list or tuple is interpreted as (*args, [kwargs]) args = list(pargdecl) kwargs = {} if isinstance(args[-1], dict): kwargs = args.pop(-1) out.append(PositionalSpec(*args, **kwargs)) return out
def __init__(self, pspec=None, kwargs=None, doc=None): if pspec is None: pspec = PositionalSpec("*") if kwargs is None: kwargs = {} self.pspec = pspec self.kwargs = kwargs self.doc = doc
def parse(cls, ctx, tokens, npargs, flags, breakstack, sortable=False, tags=None): """ 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 """ spec = PositionalSpec(npargs, sortable, tags, flags) return cls.parse2(ctx, tokens, spec, breakstack)
get_tag, npargs_is_exact, pargs_are_full, IMPLICIT_PARG_TYPES, CommandSpec, PositionalSpec, WHITESPACE_TOKENS, should_break, ) from cmake_format.parse.common import (NodeType, ParenBreaker, KwargBreaker, TreeNode) from cmake_format.parse.simple_nodes import CommentNode, OnOffNode logger = logging.getLogger(__name__) DEFAULT_PSPEC = PositionalSpec("*") class ArgGroupNode(TreeNode): """A group-of-groups. Top-level for the argument subtree of a statement, as well as the argument subtree of a keyword.""" def __init__(self): super(ArgGroupNode, self).__init__(NodeType.ARGGROUP) class StandardArgTree(ArgGroupNode): """Argument tree for most cmake-statement commands. Generically arguments are composed of a positional argument list, followed by one or more keyword arguments, followed by one or more flags:: command_name(parg1 parg2 parg3...
def parse_add_library_standard(ctx, tokens, breakstack, sortable): """ :: add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 [source2 ...]) :see: https://cmake.org/cmake/help/v3.0/command/add_library.html """ # pylint: disable=too-many-statements parsing_name = 1 parsing_type = 2 parsing_flag = 3 parsing_sources = 4 tree = TreeNode(NodeType.ARGGROUP) # If it is a whitespace token then put it directly in the parse tree at # the current depth while tokens and tokens[0].type in WHITESPACE_TOKENS: tree.children.append(tokens.pop(0)) continue state_ = parsing_name parg_group = None src_group = None active_depth = tree flags = ("STATIC", "SHARED", "MODULE", "OBJECT") while tokens: # This parse function breakson the first right paren, since parenthetical # groups are not allowed. A parenthesis might exist in a filename, but # if so that filename should be quoted so it wont show up as a RIGHT_PAREN # token. if tokens[0].type is TokenType.RIGHT_PAREN: break # 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: active_depth.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 (TokenType.COMMENT, TokenType.BRACKET_COMMENT): if state_ > parsing_name: if get_tag(tokens[0]) in ("unsort", "unsortable"): sortable = False elif get_tag(tokens[0]) in ("sort", "sortable"): sortable = True child = TreeNode(NodeType.COMMENT) active_depth.children.append(child) child.children.append(tokens.pop(0)) continue if state_ is parsing_name: token = tokens.pop(0) parg_group = PositionalGroupNode() parg_group.spec = PositionalSpec("+") active_depth = parg_group tree.children.append(parg_group) child = TreeNode(NodeType.ARGUMENT) child.children.append(token) CommentNode.consume_trailing(ctx, tokens, child) parg_group.children.append(child) state_ += 1 elif state_ is parsing_type: if get_normalized_kwarg(tokens[0]) in flags: token = tokens.pop(0) child = TreeNode(NodeType.FLAG) child.children.append(token) CommentNode.consume_trailing(ctx, tokens, child) parg_group.children.append(child) state_ += 1 elif state_ is parsing_flag: if get_normalized_kwarg(tokens[0]) == "EXCLUDE_FROM_ALL": token = tokens.pop(0) child = TreeNode(NodeType.FLAG) child.children.append(token) CommentNode.consume_trailing(ctx, tokens, child) parg_group.children.append(child) state_ += 1 src_group = PositionalGroupNode(sortable=sortable, tags=["file-list"]) src_group.spec = PositionalSpec("+") active_depth = src_group tree.children.append(src_group) elif state_ is parsing_sources: token = tokens.pop(0) child = TreeNode(NodeType.ARGUMENT) child.children.append(token) CommentNode.consume_trailing(ctx, tokens, child) src_group.children.append(child) if only_comments_and_whitespace_remain(tokens, breakstack): active_depth = tree return tree