Esempio n. 1
0
def parse_add_custom_command(tokens, breakstack):
  """
  There are two forms of `add_custom_command`. This is the dispatcher between
  the two forms.
  """
  descriminator_token = get_first_semantic_token(tokens)
  descriminator_word = get_normalized_kwarg(descriminator_token)
  if descriminator_word == "TARGET":
    return parse_add_custom_command_events(tokens, breakstack)
  if descriminator_word == "OUTPUT":
    return parse_add_custom_command_standard(tokens, breakstack)

  logger.warning(
      "Indeterminate form of add_custom_command at %s",
      descriminator_token.location)
  return parse_add_custom_command_standard(tokens, breakstack)
Esempio n. 2
0
def parse_install(tokens, breakstack):
  """
  The ``install()`` command has multiple different forms, implemented
  by different functions. The forms are indicated by the first token
  and are:

  * TARGETS
  * FILES
  * DIRECTORY
  * SCRIPT
  * CODE
  * EXPORT

  :see: https://cmake.org/cmake/help/v3.0/command/install.html
  """

  descriminator_token = get_first_semantic_token(tokens)
  if descriminator_token is None:
    logger.warning("Invalid install() command at %s", tokens[0].get_location())
    return parse_standard(tokens, npargs='*', kwargs={}, flags=[],
                          breakstack=breakstack)

  descriminator = descriminator_token.spelling.upper()
  parsemap = {
      "TARGETS": parse_install_targets,
      "FILES": parse_install_files,
      "PROGRAMS": parse_install_files,
      "DIRECTORY": parse_install_directory,
      "SCRIPT": parse_install_script,
      "CODE": parse_install_script,
      "EXPORT": parse_install_export
  }
  if descriminator not in parsemap:
    logger.warning("Invalid install form \"%s\" at %s", descriminator,
                   tokens[0].location())
    return parse_standard(tokens, npargs='*', kwargs={}, flags=[],
                          breakstack=breakstack)

  return parsemap[descriminator](tokens, breakstack)
Esempio n. 3
0
def parse_file(tokens, breakstack):
    """
  The ``file()`` command has a lot of different forms, depending on the first
  argument. This function just dispatches the correct parse implementation for
  the given form::

    Reading
      file(READ <filename> <out-var> [...])
      file(STRINGS <filename> <out-var> [...])
      file(<HASH> <filename> <out-var>)
      file(TIMESTAMP <filename> <out-var> [...])

    Writing
      file({WRITE | APPEND} <filename> <content>...)
      file({TOUCH | TOUCH_NOCREATE} [<file>...])
      file(GENERATE OUTPUT <output-file> [...])

    Filesystem
      file({GLOB | GLOB_RECURSE} <out-var> [...] [<globbing-expr>...])
      file(RENAME <oldname> <newname>)
      file({REMOVE | REMOVE_RECURSE } [<files>...])
      file(MAKE_DIRECTORY [<dir>...])
      file({COPY | INSTALL} <file>... DESTINATION <dir> [...])
      file(SIZE <filename> <out-var>)
      file(READ_SYMLINK <linkname> <out-var>)
      file(CREATE_LINK <original> <linkname> [...])

    Path Conversion
      file(RELATIVE_PATH <out-var> <directory> <file>)
      file({TO_CMAKE_PATH | TO_NATIVE_PATH} <path> <out-var>)

    Transfer
      file(DOWNLOAD <url> <file> [...])
      file(UPLOAD <file> <url> [...])

    Locking
      file(LOCK <path> [...])

  :see: https://cmake.org/cmake/help/v3.14/command/file.html
  """

    descriminator_token = get_first_semantic_token(tokens)
    if descriminator_token is None:
        logger.warning("Invalid empty file() command at %s",
                       tokens[0].get_location())
        return parse_standard(tokens,
                              npargs='*',
                              kwargs={},
                              flags=[],
                              breakstack=breakstack)

    descriminator = descriminator_token.spelling.upper()
    parsemap = {
        "READ": parse_file_read,
        "STRINGS": parse_file_strings,
        "TIMESTAMP": parse_file_timestamp,
        "WRITE": parse_file_write,
        "APPEND": parse_file_write,
        "TOUCH": StandardParser('+', flags=["TOUCH"]),
        "TOUCH_NO_CREATE": StandardParser('+', flags=["TOUCH_NO_CREATE"]),
        "GENERATE": parse_file_generate_output,
        "GLOB": parse_file_glob,
        "GLOB_RECURSE": parse_file_glob,
        "RENAME": StandardParser(3, flags=["RENAME"]),
        "REMOVE": StandardParser('+', flags=["REMOVE"]),
        "REMOVE_RECURSE": StandardParser('+', flags=["REMOVE_RECURSE"]),
        "MAKE_DIRECTORY": StandardParser('+', flags=["MAKE_DIRECTORY"]),
        "COPY": parse_file_copy,
        "INSTALL": parse_file_copy,
        "SIZE": StandardParser(3, flags=["SIZE"]),
        "READ_SYMLINK": StandardParser(3, flags=["READ_SYMLINK"]),
        "CREATE_LINK": parse_file_create_link,
        "RELATIVE_PATH": StandardParser(4, flags=["RELATIVE_PATH"]),
        "TO_CMAKE_PATH": StandardParser(3, flags=["TO_CMAKE_PATH"]),
        "TO_NATIVE_PATH": StandardParser(3, flags=["TO_NATIVE_PATH"]),
        "DOWNLOAD": parse_file_xfer,
        "UPLOAD": parse_file_xfer,
        "LOCK": parse_file_lock
    }
    for hashname in HASH_STRINGS:
        parsemap[hashname] = parse_file_hash

    if descriminator not in parsemap:
        logger.warning("Invalid file() form \"%s\" at %s", descriminator,
                       tokens[0].location())
        return parse_standard(tokens,
                              npargs='*',
                              kwargs={},
                              flags=[],
                              breakstack=breakstack)

    return parsemap[descriminator](tokens, breakstack)
Esempio n. 4
0
def parse_add_custom_target(tokens, breakstack):
  """
  ::
    add_custom_target(Name [ALL] [command1 [args1...]]
                      [COMMAND command2 [args2...] ...]
                      [DEPENDS depend depend depend ... ]
                      [BYPRODUCTS [files...]]
                      [WORKING_DIRECTORY dir]
                      [COMMENT comment]
                      [JOB_POOL job_pool]
                      [VERBATIM] [USES_TERMINAL]
                      [COMMAND_EXPAND_LISTS]
                      [SOURCES src1 [src2...]])

  :see: https://cmake.org/cmake/help/latest/command/add_custom_target.html
  """
  kwargs = {
      "BYPRODUCTS": PositionalParser("+"),
      "COMMAND": parse_shell_command,
      "COMMENT": PositionalParser(1),
      "DEPENDS": PositionalParser("+"),
      "JOB_POOL": PositionalParser(1),
      "SOURCES": PositionalParser("+"),
      "WORKING_DIRECTORY": PositionalParser(1),
  }
  flags = ("VERBATIM", "USES_TERMINAL", "COMMAND_EXPAND_LISTS")
  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

  breaker = KwargBreaker(list(kwargs.keys()) + list(flags))
  child_breakstack = breakstack + [breaker]

  nametree = None
  state = "name"

  while tokens:
    # 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

    # 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, then add it at the current depth
    if tokens[0].type in (lexer.TokenType.COMMENT,
                          lexer.TokenType.BRACKET_COMMENT):
      child = TreeNode(NodeType.COMMENT)
      tree.children.append(child)
      child.children.append(tokens.pop(0))
      continue

    ntokens = len(tokens)
    if state == "name":
      next_semantic = get_first_semantic_token(tokens[1:])
      if (next_semantic is not None and
          get_normalized_kwarg(next_semantic) == "ALL"):
        npargs = 2
      else:
        npargs = 1

      nametree = parse_positionals(tokens, npargs, ["ALL"], child_breakstack)
      assert len(tokens) < ntokens
      tree.children.append(nametree)
      state = "first-command"
      continue

    word = get_normalized_kwarg(tokens[0])
    if state == "first-command":
      if not(word in kwargs or word in flags):
        subtree = parse_positionals(tokens, '+', [], child_breakstack)
        tree.children.append(subtree)
        assert len(tokens) < ntokens
      state = "kwargs"
      continue

    if word in flags:
      subtree = parse_flags(
          tokens, flags, breakstack + [KwargBreaker(list(kwargs.keys()))])
      assert len(tokens) < ntokens
      tree.children.append(subtree)
      continue

    if word in kwargs:
      subtree = parse_kwarg(tokens, word, kwargs[word], child_breakstack)
      assert len(tokens) < ntokens
      tree.children.append(subtree)
      continue

    logger.warning(
        "Unexpected positional argument %s at %s",
        tokens[0].spelling, tokens[0].location())
    subtree = parse_positionals(tokens, '+', [], child_breakstack)
    assert len(tokens) < ntokens
    tree.children.append(subtree)
    continue
  return tree