# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. from pyparsing import (CharsNotIn, Group, Forward, Literal, Suppress, Word,
QuotedString, ZeroOrMore, alphas, alphanums) from string import Template import re
def extract_arguments(parsed): """Extract the command arguments skipping the parentheses""" return parsed[2:len(parsed) - 1]
def match_block(command, parsed, start): """Find the end of block starting with the command"""
depth = 0
end = start + 1
endcommand = 'end' + command while parsed[end][0] != endcommand or depth > 0: if parsed[end][0] == command:
depth += 1 elif parsed[end][0] == endcommand:
depth -= 1
end = end + 1 if end == len(parsed):
print('error: eof when trying to match block statement: %s'
% parsed[start]) return end
def parse_if(parsed, start): """Parse if/elseif/else/endif into a list of conditions and commands"""
depth = 0
conditions = []
condition = [extract_arguments(parsed[start])]
start = start + 1
end = start
while parsed[end][0] != 'endif'or depth > 0:
command = parsed[end][0] if command == 'if':
depth += 1 elif command == 'else'and depth == 0:
condition.append(parsed[start:end])
conditions.append(condition)
start = end + 1
condition = [['TRUE']] elif command == 'elseif'and depth == 0:
condition.append(parsed[start:end])
conditions.append(condition)
condition = [extract_arguments(parsed[end])]
start = end + 1 elif command == 'endif':
depth -= 1
end = end + 1 if end == len(parsed):
print('error: eof when trying to match if statement: %s'
% parsed[start])
condition.append(parsed[start:end])
conditions.append(condition) return end, conditions
def substs(variables, values): """Substitute variables into values"""
new_values = [] for value in values:
t = Template(value)
new_value = t.safe_substitute(variables)
# Safe substitute leaves unrecognized variables in place. # We replace them with the empty string.
new_values.append(re.sub(r'\$\{\w+\}', '', new_value)) return new_values
def evaluate(variables, cache_variables, parsed): """Evaluate a list of parsed commands, returning sources to build"""
i = 0
sources = [] while i < len(parsed):
command = parsed[i][0]
arguments = substs(variables, extract_arguments(parsed[i]))
if command == 'foreach':
end = match_block(command, parsed, i) for argument in arguments[1:]: # ; is also a valid divider, why have one when you can have two?
argument = argument.replace(';', ' ') for value in argument.split():
variables[arguments[0]] = value
cont_eval, new_sources = evaluate(variables, cache_variables,
parsed[i+1:end])
sources.extend(new_sources) ifnot cont_eval: return cont_eval, sources elif command == 'function': # for now we just execute functions inline at point of declaration # as this is sufficient to build libaom pass elif command == 'if':
i, conditions = parse_if(parsed, i) for condition in conditions: if evaluate_boolean(variables, condition[0]):
cont_eval, new_sources = evaluate(variables,
cache_variables,
condition[1])
sources.extend(new_sources) ifnot cont_eval: return cont_eval, sources break elif command == 'include': if arguments: try:
print('including: %s' % arguments[0])
sources.extend(parse(variables, cache_variables, arguments[0])) except IOError:
print('warning: could not include: %s' % arguments[0]) elif command == 'list': try:
action = arguments[0]
variable = arguments[1]
values = arguments[2:] if action == 'APPEND': if variable notin variables:
variables[variable] = ' '.join(values) else:
variables[variable] += ' ' + ' '.join(values) except (IndexError, KeyError): pass elif command == 'option':
variable = arguments[0]
value = arguments[2] # Allow options to be override without changing CMake files if variable notin variables:
variables[variable] = value elif command == 'return': returnFalse, sources elif command == 'set':
variable = arguments[0]
values = arguments[1:] # CACHE variables are not set if already present try:
cache = values.index('CACHE')
values = values[0:cache] if variable notin variables:
variables[variable] = ' '.join(values)
cache_variables.append(variable) except ValueError:
variables[variable] = ' '.join(values) # we need to emulate the behavior of these function calls # because we don't support interpreting them directly # see bug 1492292 elif command in ['set_aom_config_var', 'set_aom_detect_var']:
variable = arguments[0]
value = arguments[1] if variable notin variables:
variables[variable] = value
cache_variables.append(variable) elif command == 'set_aom_option_var': # option vars cannot go into cache_variables
variable = arguments[0]
value = arguments[2] if variable notin variables:
variables[variable] = value elif command == 'add_asm_library': try:
sources.extend(variables[arguments[1]].split(' ')) except (IndexError, KeyError): pass elif command == 'add_intrinsics_object_library': try:
sources.extend(variables[arguments[3]].split(' ')) except (IndexError, KeyError): pass elif command == 'add_library': for source in arguments[1:]:
sources.extend(source.split(' ')) elif command == 'target_sources': for source in arguments[1:]:
sources.extend(source.split(' ')) elif command == 'MOZDEBUG':
print('>>>> MOZDEBUG: %s' % ' '.join(arguments))
i += 1 returnTrue, sources
def evaluate_boolean(variables, arguments): """Evaluate a boolean expression""" ifnot arguments: returnFalse
argument = arguments[0]
if argument == 'NOT': returnnot evaluate_boolean(variables, arguments[1:])
if argument == '(':
i = 0
depth = 1 while depth > 0 and i < len(arguments):
i += 1 if arguments[i] == '(':
depth += 1 if arguments[i] == ')':
depth -= 1 return evaluate_boolean(variables, arguments[1:i])
def lookup_variable(argument): # If statements can have old-style variables which are not demarcated # like ${VARIABLE}. Attempt to look up the variable both ways. try: if re.search(r'\$\{\w+\}', argument): try:
t = Template(argument)
value = t.substitute(variables) try: # Attempt an old-style variable lookup with the # substituted value. return variables[value] except KeyError: return value except ValueError: # TODO: CMake supports nesting, e.g. ${${foo}} returnNone else: return variables[argument] except KeyError: returnNone
lhs = lookup_variable(argument) if lhs isNone: # variable resolution failed, treat as string
lhs = argument
if len(arguments) > 1:
op = arguments[1] if op == 'AND': return evaluate_constant(lhs) and evaluate_boolean(variables, arguments[2:]) elif op == 'MATCHES':
rhs = lookup_variable(arguments[2]) ifnot rhs:
rhs = arguments[2] returnnot re.match(rhs, lhs) isNone elif op == 'OR': return evaluate_constant(lhs) or evaluate_boolean(variables, arguments[2:]) elif op == 'STREQUAL':
rhs = lookup_variable(arguments[2]) ifnot rhs:
rhs = arguments[2] return lhs == rhs else:
lhs = evaluate_constant(lhs) if lhs isNone:
lhs = lookup_variable(argument)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.