Exemple #1
0
 def _parse_target(tree, target):
     target.parse(tree, named_token='path')
     # Parse disable
     if not target.was_quoted:
         target.value = util.parse_bool(target.at, target.value)
         if target.value is not False:
             log.die_print_error_at(target.at, "You can only disable targets!")
Exemple #2
0
    def resolve_var(self, var, kconfig):
        # Remember if var was a special variable
        var_special = var.value.startswith('$')

        # Resolve symbols
        var_is_sym = (not var.was_quoted) and (not var_special) and (util.kernel_option_regex.match(var.value) is not None)
        sym = None
        if var_is_sym:
            if var.value.startswith('CONFIG_'):
                sym_name = var.value[len('CONFIG_'):]
            else:
                sym_name = var.value
            sym = self.get_sym(sym_name, kconfig)
            value = sym.str_value
            var_cmp_mode = Condition._sym_cmp_type.get(sym.orig_type, 'unknown')
            if var_cmp_mode == 'unknown':
                log.die_print_error_at(var.at, "cannot compare with symbol {} which is of unknown type".format(sym.name))
        elif var_special:
            value = resolve_special_variable(var.at, kconfig, var.value)
            var_cmp_mode = get_special_var_cmp_mode(var.at, var.value)
        else:
            value = var.value
            # Literal strings will always inherit the mode
            var_cmp_mode = None

        return VarInfo(var, value, var_special, var_is_sym, sym, var_cmp_mode)
Exemple #3
0
    def __init__(self, tree, compare_op, operands):
        super().__init__(tree)
        self.compare_op = compare_op
        self.vars = operands

        if self.compare_op not in _compare_op_to_str:
            log.die_print_error_at(self.at, "Invalid comparison op '{}'. This is a bug that should be reported.".format(_compare_op_to_str[self.compare_op]))
Exemple #4
0
def parse_bool(at, s):
    if s in ['true', '1', 'yes', 'y', 'on']:
        return True
    elif s in ['false', '0', 'no', 'n', 'off']:
        return False
    else:
        log.die_print_error_at(at, "invalid value for boolean")
Exemple #5
0
 def stmt_root_include_module_dir(tree):
     include_dir = os.path.join(os.path.dirname(currently_parsed_filenames[-1]), find_named_token(tree, 'path'))
     if os.path.isdir(include_dir):
         for filename in os.listdir(include_dir):
             if filename.endswith('.conf'):
                 _include_module_file(tree, os.path.join(include_dir, filename))
     else:
         log.die_print_error_at(def_at(tree), "'{}' is not a directory".format(include_dir))
Exemple #6
0
def resolve_env_variable(hint_at, var):
    tokens = var[len('$env['):-1].split(':', 1)
    envvar = tokens[0]
    default = None if len(tokens) == 1 else decode_quotes(tokens[1])
    value = os.environ.get(envvar, default)
    if value is None:
        log.die_print_error_at(
            hint_at, "unknown environment variable '{}'.".format(envvar))
    return value
Exemple #7
0
    def get_sym(self, sym_name, kconfig):
        try:
            sym = kconfig.syms[sym_name]
        except KeyError:
            log.die_print_error_at(self.at, "symbol {} does not exist".format(sym_name))

        # If the symbol hadn't been encountered before, pin the current value
        if sym not in autokernel.symbol_tracking.symbol_changes:
            autokernel.symbol_tracking.symbol_changes[sym] = autokernel.symbol_tracking.SymbolChange(sym.str_value, self.at, 'used in condition')

        return sym
Exemple #8
0
    def _evaluate(self, kconfig):
        resolved_var = self.resolve_var(self.var, kconfig)
        cmp_mode = resolved_var.cmp_mode

        if cmp_mode is 'tristate':
            implicit_var = self.resolve_var(TokenRawLiteral(self.var.at, '"n"', is_quoted=True), kconfig)
        elif cmp_mode is 'string' and (resolved_var.is_sym or (resolved_var.special and util.is_env_var(self.var.value))):
            implicit_var = self.resolve_var(TokenRawLiteral(self.var.at, '""', is_quoted=True), kconfig)
        else:
            log.die_print_error_at(self.at, "cannot implicitly convert '{}' to a truth value".format(self.var.value))

        return compare_variables([resolved_var, implicit_var], 'EXPR_CMP_NEQ', cmp_mode, self.at)
Exemple #9
0
def find_token(tree, token_name, ignore_missing=False, strip_quotes=False):
    """
    Finds a token by literal name in the children of the given tree. Raises
    an exception if the token is not found and ignore_missing is not set.
    """
    for c in tree.children:
        if c.__class__ == lark.Token and c.type == token_name:
            return util.decode_quotes(str(c)) if strip_quotes else str(c)

    if not ignore_missing:
        log.die_print_error_at(def_at(tree), "missing token '{}'".format(token_name))
    return None
Exemple #10
0
def find_condition(tree, ignore_missing=True):
    conditions = find_conditions(tree)

    if len(conditions) == 0:
        if ignore_missing:
            return None
        else:
            log.die_print_error_at(def_at(tree), "missing expression")

    if len(conditions) == 1:
        return conditions[0]

    log.die_print_error_at(def_at(tree), "expected exactly one expression, but got {}".format(len(conditions)))
Exemple #11
0
def resolve_special_variable(hint_at, kconfig, var):
    if var == '$kernel_version':
        return autokernel.kconfig.get_kernel_version(kconfig.srctree)
    elif var == '$uname_arch':
        return autokernel.kconfig.get_uname_arch()
    elif var == '$arch':
        return autokernel.kconfig.get_arch()
    elif var == '$true':
        return 'y'
    elif var == '$false':
        return 'n'
    elif util.is_env_var(var):
        return util.resolve_env_variable(hint_at, var)
    else:
        log.die_print_error_at(hint_at, "unknown special variable '{}'".format(var))
Exemple #12
0
    def _evaluate(self, kconfig):
        resolved_vars = [self.resolve_var(v, kconfig) for v in self.vars]

        # The comparison mode is determined by the following schema:
        # 1. Filter out None, as variables with mode None will inherit any other comparison type.
        # 2. All other variables force a comparison mode. It is an error to use two variables
        #    of different type in the same expression

        resolved_vars_with_type = [v for v in resolved_vars if v.cmp_mode is not None]
        if len(resolved_vars_with_type) == 0:
            cmp_mode = 'string' # compare with string mode as fallback (e.g. when two literals were given)
        elif len(resolved_vars_with_type) == 1:
            cmp_mode = resolved_vars_with_type[0].cmp_mode
        else:
            log.die_print_error_at(self.at, "cannot compare variables of different types: [{}]".format(', '.join(["{} ({})".format(v.var.value, v.cmp_mode) for v in resolved_vars_with_type])))

        return compare_variables(resolved_vars, self.compare_op, cmp_mode, self.at)
Exemple #13
0
        def stmt_module_if(tree):
            conditions = find_conditions(tree)
            subcontexts = find_subtrees(tree, 'ctxt_module')
            if len(subcontexts) - len(conditions) not in [0, 1]:
                log.die_print_error_at(def_at(tree), "invalid amount of subcontexts(={}) and conditions(={}) for if block; this is a bug that should be reported.".format(len(subcontexts), len(conditions)))

            not_previous_conditions = []
            for c, s in zip(conditions, subcontexts):
                # The condition for an else if block is the combined negation of all previous conditions,
                # and its own condition
                conds = preconditions + not_previous_conditions + [c]
                self.parse_context(s, preconditions=conds)
                not_previous_conditions.append(c.negate())

            if len(subcontexts) > len(conditions):
                # The condition for the else block is the combined negation of all previous conditions
                conds = preconditions + not_previous_conditions
                self.parse_context(subcontexts[-1], preconditions=conds)
Exemple #14
0
        def _include_module_file(tree, filename):
            rpath = os.path.realpath(filename)
            if rpath in self._include_module_files:
                log.verbose("Skipping duplicate inclusion of '{}'".format(rpath))
                return
            else:
                self._include_module_files.add(rpath)

            if os.path.isfile(filename):
                try:
                    subtree = load_config_tree(filename)
                except IOError as e:
                    log.die_print_error_at(def_at(tree), str(e))

                currently_parsed_filenames.append(filename)
                self.parse_tree(subtree, restrict_to_modules=True)
                currently_parsed_filenames.pop()
            else:
                log.die_print_error_at(def_at(tree), "'{}' does not exist or is not a file".format(filename))
Exemple #15
0
def apply_tree_nodes(nodes, callbacks, on_additional=None, ignore_additional=False):
    """
    For each node calls the callback matching its name.
    Raises an exception for unmatched nodes if ignore_additional is not set.
    """
    if type(callbacks) == list:
        callback_dict = {}
        for c in callbacks:
            callback_dict[c.__name__] = c
        callbacks = callback_dict

    for n in nodes:
        if n.__class__ == lark.Tree:
            if n.data in callbacks:
                callbacks[n.data](n)
            elif n.data == "extra_semicolon":
                log.verbose("Extra semicolon at {}:{}:{}".format(currently_parsed_filenames[-1], n.line, n.column))
            elif on_additional:
                on_additional(n)
            elif not ignore_additional:
                log.die_print_error_at(def_at(n), "unprocessed rule '{}'; this is a bug that should be reported.".format(n.data))
Exemple #16
0
def parse_expr_condition(tree):
    if tree.data == 'expr':
        return ConditionOr(tree, *[parse_expr_condition(c) for c in tree.children if c.__class__ == lark.Tree and c.data == 'expr_term'])
    if tree.data == 'expr_term':
        return ConditionAnd(tree, *[parse_expr_condition(c) for c in tree.children if c.__class__ == lark.Tree and c.data == 'expr_factor'])
    elif tree.data == 'expr_factor':
        negated = find_first_child(tree, 'expr_op_neg') is not None
        expr_cmp = find_first_child(tree, 'expr_cmp')
        if expr_cmp:
            operands = find_all_named_tokens_raw(expr_cmp, 'expr_param')
            operation = None
            # Find operation type and assert all operation types are equal
            for c in expr_cmp.children:
                if c.data == 'expr_op_cmp':
                    op = c.children[0].type
                    if operation is None:
                        operation = op
                    elif operation != op:
                        log.die_print_error_at(def_at(expr_cmp), "all expression operands must be the same for n-ary comparisons")
            return ConditionVarComparison(expr_cmp, operation, operands).negate(negated)

        expr_id = find_named_token(tree, 'expr_id')
        if expr_id:
            # Implicit truth value is the same as writing 'var != "n"' for tristate symbols
            # and 'var != ""' for others.
            operand = TokenRawInfo(tree, str(expr_id), is_quoted=False)
            return ConditionVarTruth(tree, operand).negate(negated)

        expr = find_first_child(tree, 'expr')
        if expr:
            return parse_expr_condition(expr).negate(negated)

        log.die_print_error_at(def_at(tree), "invalid expression subtree '{}' in 'expr_factor'".format(tree.data))
    else:
        log.die_print_error_at(def_at(tree), "invalid expression subtree '{}'".format(tree.data))
Exemple #17
0
def compare_variables(resolved_vars, op, cmp_mode, hint_at):
    # Assert that the comparison mode is supported for the given type
    if cmp_mode == 'string':
        if op not in ['EXPR_CMP_NEQ', 'EXPR_CMP_EQ']:
            log.die_print_error_at(hint_at, "invalid comparison '{}' for type string".format(_compare_op_to_str[op]))
    elif cmp_mode == 'tristate':
        if op not in ['EXPR_CMP_NEQ', 'EXPR_CMP_EQ']:
            log.die_print_error_at(hint_at, "invalid comparison operator '{}' for type tristate".format(_compare_op_to_str[op]))

    # Parse variables to comparable types
    parse_functor = _variable_parse_functors[cmp_mode]
    parsed_variables = []
    for i, var in enumerate(resolved_vars, start=1):
        try:
            parsed_variables.append(parse_functor(var))
        except ValueError as e:
            log.die_print_error_at(var.var.at, "could not convert operand #{} '{}' to {}: {}".format(i, var.var.value, cmp_mode, str(e)))

    # Compare all variables in order
    for i, rhs in enumerate(parsed_variables[1:], start=1):
        if not _compare_op_to_functor[op](parsed_variables[i - 1], rhs):
            return False
    return True
Exemple #18
0
    def parse_tree(self, tree, *args, **kwargs):
        """
        Parses the given block tree node, and class parse_block_params and parse_context.
        """
        if self.first_definition is None:
            self.first_definition = def_at(tree)

        if tree.data != ('blck_' + self.node_name):
            log.die_print_error_at(def_at(tree), "{} cannot parse '{}'".format(self.__class__.__name__, tree.data))

        self.parse_block_params(tree, *args, **kwargs)

        ctxt = None
        for c in tree.children:
            if c.__class__ == lark.Tree:
                if c.data == 'ctxt_' + self.node_name:
                    if ctxt:
                        log.die_print_error_at(def_at(c), "'{}' must not have multiple children of type '{}'".format("blck_" + self.node_name, "ctxt_" + self.node_name))
                    ctxt = c

        if not ctxt:
            log.die_print_error_at(def_at(tree), "'{}' must have exactly one child '{}'".format("blck_" + self.node_name, "ctxt_" + self.node_name))

        self.parse_context(ctxt, *args, **kwargs)
Exemple #19
0
 def other(tree):
     log.die_print_error_at(def_at(tree), "'{}' must not be used in a module config".format(tree.data))
Exemple #20
0
 def get_module(stmt):
     if stmt.module_name not in config.modules:
         log.die_print_error_at(stmt.at, "module '{}' is never defined".format(stmt.module_name))
     return config.modules[stmt.module_name]
Exemple #21
0
def find_named_token_raw(tree, token_name, ignore_missing=False):
    """
    Finds a token by subrule name in the children of the given tree. Raises
    an exception if the token is not found.
    """
    for c in tree.children:
        if c.__class__ == lark.Tree and c.data == token_name:
            if len(c.children) != 1:
                log.die_print_error_at(def_at(c), "subrule token '{}' has too many children".format(token_name))

            if c.children[0].data not in ['string', 'string_quoted']:
                log.die_print_error_at(def_at(c), "subrule token '{}.{}' has an invalid name (must be either 'string' or 'string_quoted')".format(token_name, c.children[0].data))

            if c.children[0].__class__ != lark.Tree:
                log.die_print_error_at(def_at(c), "subrule token '{}.{}' has no children tree".format(token_name, c.children[0].data))

            if len(c.children[0].children) != 1:
                log.die_print_error_at(def_at(c.children[0]), "subrule token '{}.{}' has too many children".format(token_name, c.children[0].data))

            if c.children[0].children[0].__class__ != lark.Token:
                log.die_print_error_at(def_at(c.children[0]), "subrule token '{}.{}' has no children literal".format(token_name, c.children[0].data))

            return TokenRawInfo(c.children[0], str(c.children[0].children[0]), is_quoted=(c.children[0].data == 'string_quoted'))

    if not ignore_missing:
        log.die_print_error_at(def_at(tree), "missing token '{}'".format(token_name))
    return TokenRawInfo(None, None, False)
Exemple #22
0
def _parse_umask_property(prop):
    try:
        prop.value = int(prop.value, 8)
    except ValueError as e:
        log.die_print_error_at(prop.at, "Invalid value for umask: {}".format(str(e)))
Exemple #23
0
def _parse_int_property(prop):
    try:
        prop.value = int(prop.value)
    except ValueError as e:
        log.die_print_error_at(prop.at, "Invalid value for integer: {}".format(str(e)))
Exemple #24
0
def get_special_var_cmp_mode(hint_at, var):
    if util.is_env_var(var):
        return 'string'
    if var in special_var_cmp_mode:
        return special_var_cmp_mode[var]
    log.die_print_error_at(hint_at, "unknown special variable '{}'".format(var))