diff options
Diffstat (limited to 'waftools')
27 files changed, 0 insertions, 1694 deletions
diff --git a/waftools/__init__.py b/waftools/__init__.py deleted file mode 100644 index 6f804bce35..0000000000 --- a/waftools/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 diff --git a/waftools/checks/__init__.py b/waftools/checks/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/waftools/checks/__init__.py +++ /dev/null diff --git a/waftools/checks/custom.py b/waftools/checks/custom.py deleted file mode 100644 index 964546977b..0000000000 --- a/waftools/checks/custom.py +++ /dev/null @@ -1,155 +0,0 @@ -from waftools import inflector -from waftools.checks.generic import * -from waflib import Utils -from distutils.version import StrictVersion -import os - -__all__ = ["check_pthreads", "check_iconv", "check_lua", - "check_cocoa", "check_wl_protocols", "check_swift", - "check_egl_provider"] - -pthreads_program = load_fragment('pthreads.c') - -def check_pthread_flag(ctx, dependency_identifier): - checks = [ - check_cc(fragment = pthreads_program, cflags = '-pthread'), - check_cc(fragment = pthreads_program, cflags = '-pthread', - linkflags = '-pthread') ] - - for fn in checks: - if fn(ctx, dependency_identifier): - return True - return False - -def check_pthreads(ctx, dependency_identifier): - if ctx.dependency_satisfied('win32-internal-pthreads'): - h = ctx.path.find_node('osdep/win32/include').abspath() - # define IN_WINPTHREAD to workaround mingw stupidity (we never want it - # to define features specific to its own pthread stuff) - ctx.env.CFLAGS += ['-isystem', h, '-I', h, '-DIN_WINPTHREAD'] - return True - if check_pthread_flag(ctx, dependency_identifier): - return True - platform_cflags = { - 'linux': '-D_REENTRANT', - 'freebsd': '-D_THREAD_SAFE', - 'netbsd': '-D_THREAD_SAFE', - 'openbsd': '-D_THREAD_SAFE', - }.get(ctx.env.DEST_OS, '') - libs = ['pthreadGC2', 'pthread'] - checkfn = check_cc(fragment=pthreads_program, cflags=platform_cflags) - checkfn_nocflags = check_cc(fragment=pthreads_program) - for fn in [checkfn, checkfn_nocflags]: - if check_libs(libs, fn)(ctx, dependency_identifier): - return True - return False - -def check_iconv(ctx, dependency_identifier): - iconv_program = load_fragment('iconv.c') - libdliconv = " ".join(ctx.env.LIB_LIBDL + ['iconv']) - libs = ['iconv', libdliconv] - args = {'fragment': iconv_program} - if ctx.env.DEST_OS == 'openbsd' or ctx.env.DEST_OS == 'freebsd': - args['cflags'] = '-I/usr/local/include' - args['linkflags'] = '-L/usr/local/lib' - elif ctx.env.DEST_OS == 'win32': - args['linkflags'] = " ".join(['-L' + x for x in ctx.env.LIBRARY_PATH]) - checkfn = check_cc(**args) - return check_libs(libs, checkfn)(ctx, dependency_identifier) - -def check_lua(ctx, dependency_identifier): - lua_versions = [ - ( '52', 'lua >= 5.2.0 lua < 5.3.0' ), - ( '52arch', 'lua52 >= 5.2.0'), # Arch - ( '52deb', 'lua5.2 >= 5.2.0'), # debian - ( '52fbsd', 'lua-5.2 >= 5.2.0'), # FreeBSD - ( 'luajit', 'luajit >= 2.0.0' ), - ( '51', 'lua >= 5.1.0 lua < 5.2.0'), - ( '51obsd', 'lua51 >= 5.1.0'), # OpenBSD - ( '51deb', 'lua5.1 >= 5.1.0'), # debian - ( '51fbsd', 'lua-5.1 >= 5.1.0'), # FreeBSD - ] - - if ctx.options.LUA_VER: - lua_versions = \ - [lv for lv in lua_versions if lv[0] == ctx.options.LUA_VER] - - for lua_version, pkgconfig_query in lua_versions: - if check_pkg_config(pkgconfig_query, uselib_store=lua_version) \ - (ctx, dependency_identifier): - # XXX: this is a bit of a hack, ask waf developers if I can copy - # the uselib_store to 'lua' - ctx.mark_satisfied(lua_version) - ctx.add_optional_message(dependency_identifier, - 'version found: ' + lua_version) - return True - return False - -def check_wl_protocols(ctx, dependency_identifier): - def fn(ctx, dependency_identifier): - ret = check_pkg_config_datadir("wayland-protocols", ">= 1.15") - ret = ret(ctx, dependency_identifier) - if ret != None: - ctx.env.WL_PROTO_DIR = ret.split()[0] - return ret - return fn(ctx, dependency_identifier) - -def check_cocoa(ctx, dependency_identifier): - fn = check_cc( - fragment = load_fragment('cocoa.m'), - compile_filename = 'test.m', - framework_name = ['Cocoa', 'IOKit', 'OpenGL', 'QuartzCore'], - includes = [ctx.srcnode.abspath()], - linkflags = '-fobjc-arc') - - res = fn(ctx, dependency_identifier) - if res and ctx.env.MACOS_SDK: - # on macOS we explicitly need to set the SDK path, otherwise it can lead - # to linking warnings or errors - ctx.env.append_value('LAST_LINKFLAGS', [ - '-isysroot', ctx.env.MACOS_SDK, - '-L/usr/lib', - '-L/usr/local/lib' - ]) - - return res - -def check_swift(version): - def fn(ctx, dependency_identifier): - minVer = StrictVersion(version) - if ctx.env.SWIFT_VERSION: - if StrictVersion(ctx.env.SWIFT_VERSION) >= minVer: - ctx.add_optional_message(dependency_identifier, - 'version found: ' + str(ctx.env.SWIFT_VERSION)) - return True - ctx.add_optional_message(dependency_identifier, - "'swift >= " + str(minVer) + "' not found, found " + - str(ctx.env.SWIFT_VERSION or None)) - return False - return fn - -def check_egl_provider(minVersion=None, name='egl', check=None): - def fn(ctx, dependency_identifier, **kw): - if not hasattr(ctx, 'egl_provider'): - egl_provider_check = check or check_pkg_config(name) - if egl_provider_check(ctx, dependency_identifier): - ctx.egl_provider = name - for ver in ['1.5', '1.4', '1.3', '1.2', '1.1', '1.0']: - stmt = 'int x[EGL_VERSION_{0}]'.format(ver.replace('.','_')) - check_stmt = check_statement(['EGL/egl.h'], stmt) - if check_stmt(ctx, dependency_identifier): - ctx.egl_provider_version = StrictVersion(ver) - break - return True - else: - return False - else: - minVersionSV = minVersion and StrictVersion(minVersion) - if not minVersionSV or ctx.egl_provider_version and \ - ctx.egl_provider_version >= minVersionSV: - defkey = inflector.define_key(dependency_identifier) - ctx.define(defkey, 1) - return True - else: - return False - return fn diff --git a/waftools/checks/generic.py b/waftools/checks/generic.py deleted file mode 100644 index 4e27f5114a..0000000000 --- a/waftools/checks/generic.py +++ /dev/null @@ -1,204 +0,0 @@ -import os -import inflector -from distutils.version import StrictVersion -from waflib.ConfigSet import ConfigSet -from waflib import Utils - -__all__ = [ - "check_pkg_config", "check_pkg_config_mixed", "check_pkg_config_mixed_all", - "check_pkg_config_cflags", "check_cc", "check_statement", "check_libs", - "check_headers", "compose_checks", "any_check", "check_true", "any_version", - "load_fragment", "check_stub", "check_ctx_vars", "check_program", - "check_pkg_config_datadir", "check_macos_sdk"] - -any_version = None - -def even(n): - return n % 2 == 0 - -def __define_options__(dependency_identifier): - return inflector.define_dict(dependency_identifier) - -def __merge_options__(dependency_identifier, *args): - options_accu = inflector.storage_dict(dependency_identifier) - options_accu['mandatory'] = False - [options_accu.update(arg) for arg in args if arg] - return options_accu - -def _filter_cc_arguments(ctx, opts): - if ctx.env.DEST_OS != Utils.unversioned_sys_platform(): - # cross compiling, remove execute=True if present - if opts.get('execute'): - opts['execute'] = False - return opts - -def check_program(name, var): - def fn(ctx, dependency_identifier): - return ctx.find_program(name, var=var, mandatory=False) - return fn - -def check_libs(libs, function): - libs = [None] + libs - def fn(ctx, dependency_identifier): - for lib in libs: - kwargs = lib and {'lib': lib} or {} - if function(ctx, dependency_identifier, **kwargs): - return True - return False - return fn - -def check_statement(header, statement, **kw_ext): - def fn(ctx, dependency_identifier, **kw): - headers = header - if not isinstance(headers, list): - headers = [header] - hs = "\n".join(["#include <{0}>".format(h) for h in headers]) - fragment = ("{0}\n" - "int main(int argc, char **argv)\n" - "{{ {1}; return 0; }}").format(hs, statement) - opts = __merge_options__(dependency_identifier, - {'fragment':fragment}, - __define_options__(dependency_identifier), - kw_ext, kw) - return ctx.check_cc(**_filter_cc_arguments(ctx, opts)) - return fn - -def check_cc(**kw_ext): - def fn(ctx, dependency_identifier, **kw): - options = __merge_options__(dependency_identifier, - __define_options__(dependency_identifier), - kw_ext, kw) - return ctx.check_cc(**_filter_cc_arguments(ctx, options)) - return fn - -def check_pkg_config(*args, **kw_ext): - return _check_pkg_config([], ["--libs", "--cflags"], *args, **kw_ext) - -def check_pkg_config_mixed(_dyn_libs, *args, **kw_ext): - return _check_pkg_config([_dyn_libs], ["--libs", "--cflags"], *args, **kw_ext) - -def check_pkg_config_mixed_all(*all_args, **kw_ext): - args = [all_args[i] for i in [n for n in range(0, len(all_args)) if n % 3]] - return _check_pkg_config(all_args[::3], ["--libs", "--cflags"], *args, **kw_ext) - -def check_pkg_config_cflags(*args, **kw_ext): - return _check_pkg_config([], ["--cflags"], *args, **kw_ext) - -def check_pkg_config_datadir(*args, **kw_ext): - return _check_pkg_config([], ["--variable=pkgdatadir"], *args, **kw_ext) - -def _check_pkg_config(_dyn_libs, _pkgc_args, *args, **kw_ext): - def fn(ctx, dependency_identifier, **kw): - argsl = list(args) - packages = args[::2] - verchecks = args[1::2] - sargs = [] - pkgc_args = _pkgc_args - dyn_libs = {} - for i in range(0, len(packages)): - if i < len(verchecks): - sargs.append(packages[i] + ' ' + verchecks[i]) - else: - sargs.append(packages[i]) - if _dyn_libs and _dyn_libs[i]: - dyn_libs[packages[i]] = _dyn_libs[i] - if ctx.dependency_satisfied('static-build') and not dyn_libs: - pkgc_args += ["--static"] - - defaults = { - 'path': ctx.env.PKG_CONFIG, - 'package': " ".join(packages), - 'args': sargs + pkgc_args } - opts = __merge_options__(dependency_identifier, defaults, kw_ext, kw) - - # Warning! Megahack incoming: when parsing flags in `parse_flags` waf - # uses append_unique. This appends the flags only if they aren't - # already present in the list. This causes breakage if one checks for - # multiple pkg-config packages in a single call as stuff like -lm is - # added only at its first occurrence. - original_append_unique = ConfigSet.append_unique - ConfigSet.append_unique = ConfigSet.append_value - result = ctx.check_cfg(**opts) - ConfigSet.append_unique = original_append_unique - - defkey = inflector.define_key(dependency_identifier) - if result: - ctx.define(defkey, 1) - for x in dyn_libs.keys(): - ctx.env['LIB_'+x] += dyn_libs[x] - else: - ctx.add_optional_message(dependency_identifier, - "'{0}' not found".format(" ".join(sargs))) - ctx.undefine(defkey) - return result - return fn - -def check_headers(*headers, **kw_ext): - def undef_others(ctx, headers, found): - not_found_hs = set(headers) - {found} - for not_found_h in not_found_hs: - ctx.undefine(inflector.define_key(not_found_h)) - - def fn(ctx, dependency_identifier): - for header in headers: - defaults = {'header_name': header, 'features': 'c cprogram'} - options = __merge_options__(dependency_identifier, defaults, kw_ext) - if ctx.check(**options): - undef_others(ctx, headers, header) - ctx.define(inflector.define_key(dependency_identifier), 1) - return True - undef_others(ctx, headers, None) - return False - return fn - -def check_true(ctx, dependency_identifier): - ctx.define(inflector.define_key(dependency_identifier), 1) - return True - -def check_ctx_vars(*variables): - def fn(ctx, dependency_identifier): - missing = [] - for variable in variables: - if variable not in ctx.env: - missing.append(variable) - - if any(missing): - ctx.add_optional_message(dependency_identifier, - 'missing {0}'.format(', '.join(missing))) - return False - else: - return True - - return fn - -def check_stub(ctx, dependency_identifier): - ctx.undefine(inflector.define_key(dependency_identifier)) - return False - -def compose_checks(*checks): - def fn(ctx, dependency_identifier): - return all([check(ctx, dependency_identifier) for check in checks]) - return fn - -def any_check(*checks): - def fn(ctx, dependency_identifier): - return any(check(ctx, dependency_identifier) for check in checks) - return fn - -def load_fragment(fragment): - file_path = os.path.join(os.path.dirname(__file__), '..', 'fragments', - fragment) - fp = open(file_path,"r") - fragment_code = fp.read() - fp.close() - return fragment_code - -def check_macos_sdk(version): - def fn(ctx, dependency_identifier): - if ctx.env.MACOS_SDK_VERSION: - if StrictVersion(ctx.env.MACOS_SDK_VERSION) >= StrictVersion(version): - ctx.define(inflector.define_key(dependency_identifier), 1) - return True - return False - - return fn diff --git a/waftools/clang_compilation_database.py b/waftools/clang_compilation_database.py deleted file mode 100644 index 666471f07e..0000000000 --- a/waftools/clang_compilation_database.py +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# Christoph Koke, 2013 -# Original source: waflib/extras/clang_compilation_database.py from -# waf git 5e4b86b81df3 (New BSD License) - -""" -Writes the c and cpp compile commands into build/compile_commands.json -see http://clang.llvm.org/docs/JSONCompilationDatabase.html - -Usage: - - def configure(conf): - conf.load('compiler_cxx') - ... - conf.load('clang_compilation_database') -""" - -import sys, os, json, shlex, pipes -from waflib import Logs, TaskGen, Task - -Task.Task.keep_last_cmd = True - -@TaskGen.feature('c', 'cxx') -@TaskGen.after_method('process_use') -def collect_compilation_db_tasks(self): - "Add a compilation database entry for compiled tasks" - try: - clang_db = self.bld.clang_compilation_database_tasks - except AttributeError: - clang_db = self.bld.clang_compilation_database_tasks = [] - self.bld.add_post_fun(write_compilation_database) - - tup = tuple(y for y in [Task.classes.get(x) for x in ('c', 'cxx')] if y) - for task in getattr(self, 'compiled_tasks', []): - if isinstance(task, tup): - clang_db.append(task) - -def write_compilation_database(ctx): - "Write the clang compilation database as JSON" - database_file = ctx.bldnode.make_node('compile_commands.json') - Logs.info('Build commands will be stored in %s', database_file.path_from(ctx.path)) - try: - root = json.load(database_file) - except IOError: - root = [] - clang_db = {x['file']: x for x in root} - for task in getattr(ctx, 'clang_compilation_database_tasks', []): - try: - cmd = task.last_cmd - except AttributeError: - continue - directory = getattr(task, 'cwd', ctx.variant_dir) - f_node = task.inputs[0] - filename = os.path.relpath(f_node.abspath(), directory) - entry = { - "directory": directory, - "arguments": cmd, - "file": filename, - } - clang_db[filename] = entry - root = list(clang_db.values()) - database_file.write(json.dumps(root, indent=2)) - -# Override the runnable_status function to do a dummy/dry run when the file doesn't need to be compiled. -# This will make sure compile_commands.json is always fully up to date. -# Previously you could end up with a partial compile_commands.json if the build failed. -for x in ('c', 'cxx'): - if x not in Task.classes: - continue - - t = Task.classes[x] - - def runnable_status(self): - def exec_command(cmd, **kw): - pass - - run_status = self.old_runnable_status() - if run_status == Task.SKIP_ME: - setattr(self, 'old_exec_command', getattr(self, 'exec_command', None)) - setattr(self, 'exec_command', exec_command) - self.run() - setattr(self, 'exec_command', getattr(self, 'old_exec_command', None)) - return run_status - - setattr(t, 'old_runnable_status', getattr(t, 'runnable_status', None)) - setattr(t, 'runnable_status', runnable_status) diff --git a/waftools/dependencies.py b/waftools/dependencies.py deleted file mode 100644 index cbe4555cae..0000000000 --- a/waftools/dependencies.py +++ /dev/null @@ -1,224 +0,0 @@ -from waflib.Errors import ConfigurationError, WafError -from waflib.Configure import conf -from waflib.Build import BuildContext -from waflib.Logs import pprint -import deps_parser -import inflector - -class DependencyError(Exception): - pass - -class Dependency(object): - def __init__(self, ctx, known_deps, satisfied_deps, dependency): - self.ctx = ctx - self.known_deps = known_deps - self.satisfied_deps = satisfied_deps - self.identifier, self.desc = dependency['name'], dependency['desc'] - self.attributes = self.__parse_attributes__(dependency) - - known_deps.add(self.identifier) - - if 'deps' in self.attributes: - self.ctx.ensure_dependency_is_known(self.attributes['deps']) - - def __parse_attributes__(self, dependency): - if 'os_specific_checks' in dependency: - all_chks = dependency['os_specific_checks'] - chks = [check for check in all_chks if check in self.satisfied_deps] - if any(chks): - return all_chks[chks[0]] - return dependency - - def check(self): - self.ctx.start_msg('Checking for {0}'.format(self.desc)) - - try: - self.check_group_disabled() - self.check_disabled() - self.check_dependencies() - except DependencyError: - # No check was run, since the prerequisites of the dependency are - # not satisfied. Make sure the define is 'undefined' so that we - # get a `#define YYY 0` in `config.h`. - self.ctx.undefine(inflector.define_key(self.identifier)) - self.fatal_if_needed() - return - - self.check_autodetect_func() - - def check_group_disabled(self): - if 'groups' in self.attributes: - groups = self.attributes['groups'] - disabled = (self.enabled_option(g) == False for g in groups) - if any(disabled): - self.skip() - raise DependencyError - - def check_disabled(self): - if self.enabled_option() == False: - self.skip() - raise DependencyError - - if self.enabled_option() == True: - self.attributes['req'] = True - self.attributes['fmsg'] = "You manually enabled the feature '{0}', but \ -the autodetection check failed.".format(self.identifier) - - def check_dependencies(self): - if 'deps' in self.attributes: - ok, why = deps_parser.check_dependency_expr(self.attributes['deps'], - self.satisfied_deps) - if not ok: - self.skip(why) - raise DependencyError - - def check_autodetect_func(self): - if self.attributes['func'](self.ctx, self.identifier): - self.success(self.identifier) - else: - self.fail() - self.ctx.undefine(inflector.define_key(self.identifier)) - self.fatal_if_needed() - - def enabled_option(self, identifier=None): - try: - return getattr(self.ctx.options, self.enabled_option_repr(identifier)) - except AttributeError: - pass - return None - - def enabled_option_repr(self, identifier): - return "enable_{0}".format(identifier or self.identifier) - - def success(self, depname): - self.ctx.mark_satisfied(depname) - self.ctx.end_msg(self.__message__('yes')) - - def fail(self, reason='no'): - self.ctx.end_msg(self.__message__(reason), 'RED') - - def fatal_if_needed(self): - if self.enabled_option() == False: - return - if self.attributes.get('req', False): - raise ConfigurationError(self.attributes.get('fmsg', 'Unsatisfied requirement')) - - def skip(self, reason='disabled', color='YELLOW'): - self.ctx.end_msg(self.__message__(reason), color) - - def __message__(self, message): - optional_message = self.ctx.deps_msg.get(self.identifier) - if optional_message: - return "{0} ({1})".format(message, optional_message) - else: - return message - -def configure(ctx): - def __detect_target_os_dependency__(ctx): - target = "os-{0}".format(ctx.env.DEST_OS) - ctx.start_msg('Detected target OS:') - ctx.end_msg(target) - ctx.known_deps.add(target) - ctx.satisfied_deps.add(target) - - ctx.deps_msg = {} - ctx.known_deps = set() - ctx.satisfied_deps = set() - __detect_target_os_dependency__(ctx) - -@conf -def ensure_dependency_is_known(ctx, depnames): - def check(ast): - if isinstance(ast, deps_parser.AstSym): - if (not ast.name.startswith('os-')) and ast.name not in ctx.known_deps: - raise ConfigurationError( - "error in dependencies definition: dependency {0} in" - " {1} is unknown.".format(ast.name, depnames)) - elif isinstance(ast, deps_parser.AstOp): - for sub in ast.sub: - check(sub) - else: - assert False - check(deps_parser.parse_expr(depnames)) - -@conf -def mark_satisfied(ctx, dependency_identifier): - ctx.satisfied_deps.add(dependency_identifier) - -@conf -def add_optional_message(ctx, dependency_identifier, message): - ctx.deps_msg[dependency_identifier] = message - -@conf -def parse_dependencies(ctx, dependencies): - def __check_dependency__(ctx, dependency): - Dependency(ctx, - ctx.known_deps, - ctx.satisfied_deps, - dependency).check() - - [__check_dependency__(ctx, dependency) for dependency in dependencies] - -@conf -def dependency_satisfied(ctx, dependency_identifier): - ctx.ensure_dependency_is_known(dependency_identifier) - ok, _ = deps_parser.check_dependency_expr(dependency_identifier, - ctx.satisfied_deps) - return ok - -@conf -def store_dependencies_lists(ctx): - ctx.env.known_deps = list(ctx.known_deps) - ctx.env.satisfied_deps = list(ctx.satisfied_deps) - -@conf -def unpack_dependencies_lists(ctx): - ctx.known_deps = set(ctx.env.known_deps) - ctx.satisfied_deps = set(ctx.env.satisfied_deps) - -def filtered_sources(ctx, sources): - def __source_file__(source): - if isinstance(source, tuple): - return source[0] - else: - return source - - def __check_filter__(dependency): - return dependency_satisfied(ctx, dependency) - - def __unpack_and_check_filter__(source): - try: - _, dependency = source - return __check_filter__(dependency) - except ValueError: - return True - - return [__source_file__(source) for source in sources \ - if __unpack_and_check_filter__(source)] - -""" -Like filtered_sources(), but pick only the first entry that matches, and -return its filename. -""" -def pick_first_matching_dep(ctx, deps): - files = filtered_sources(ctx, deps) - if len(files) > 0: - return files[0] - else: - raise DependencyError - -def env_fetch(tx): - def fn(ctx): - deps = ctx.env.satisfied_deps - lists = [ctx.env[tx(dep)] for dep in deps if (tx(dep) in ctx.env)] - return [item for sublist in lists for item in sublist] - return fn - -def dependencies_use(ctx): - return [inflector.storage_key(dep) for dep in sorted(ctx.env.satisfied_deps)] - -BuildContext.filtered_sources = filtered_sources -BuildContext.pick_first_matching_dep = pick_first_matching_dep -BuildContext.dependencies_use = dependencies_use -BuildContext.dependencies_includes = env_fetch(lambda x: "INCLUDES_{0}".format(x)) -BuildContext.dependency_satisfied = dependency_satisfied diff --git a/waftools/deps_parser.py b/waftools/deps_parser.py deleted file mode 100644 index eef3b6f9e8..0000000000 --- a/waftools/deps_parser.py +++ /dev/null @@ -1,211 +0,0 @@ - -class ParseError(Exception): - pass - -class AstOp(object): - def __init__(self, op, sub): - self.op = op - self.sub = sub - - def __repr__(self): - if len(self.sub) == 1: - return self.op + str(self.sub[0]) - return "(" + (" " + self.op + " ").join([str(x) for x in self.sub]) + ")" - -class AstSym(object): - def __init__(self, name): - assert type(name) is type("") - self.name = name - - def __repr__(self): - return self.name - -Arity = { "!": 1, "&&": 2, "||": 2 } -Precedence = { "!": 3, "&&": 2, "||": 1 } -Tokens = list(Arity.keys()) + ["(", ")"] - -# return (token, rest), or (None, "") if nothing left -def read_tok(expr): - expr = expr.strip() - for t in Tokens: - if expr.startswith(t): - return (t, expr[len(t):]) - if expr == "": - return (None, "") - sym = "" - while len(expr) and ((expr[0].lower() >= 'a' and expr[0].lower() <= 'z') or - (expr[0] >= '0' and expr[0] <= '9') or - (expr[0] in ["_", "-", "."])): - sym += expr[0] - expr = expr[1:] - if len(sym): - return sym, expr - raise ParseError("unknown token in '%s'" % expr) - -def parse_expr(expr): - opstack = [] - outstack = [] - def out(sym): - if sym in Arity: - sub = [] - for i in range(Arity[sym]): - if len(outstack) == 0: - raise ParseError("missing operator argument") - sub.insert(0, outstack.pop()) - outstack.append(AstOp(sym, sub)) - elif sym == "(": - raise ParseError("missing closing ')'") - elif not isinstance(sym, AstSym): - raise ParseError("bogus symbol '%s'" % sym) - else: - outstack.append(sym) - while True: - tok, expr = read_tok(expr) - if tok is None: - break - if tok in Arity: - while len(opstack) and opstack[-1] != '(' and \ - Precedence[opstack[-1]] > Precedence[tok]: - out(opstack.pop()) - opstack.append(tok) - elif tok == "(": - opstack.append(tok) - elif tok == ")": - while True: - if not len(opstack): - raise ParseError("missing '(' for ')'") - sym = opstack.pop() - if sym == "(": - break - out(sym) - else: - out(AstSym(tok)) # Assume a terminal - while len(opstack): - out(opstack.pop()) - if len(outstack) != 1: - raise ParseError("empty expression or extra symbols (%s)" % outstack) - return outstack.pop() - -def convert_dnf(ast): - - # no nested ! (negation normal form) - def simplify_negation(ast): - if isinstance(ast, AstOp): - if ast.op == "!": - sub = ast.sub[0] - if isinstance(sub, AstOp): - if sub.op == "!": - return sub.sub[0] - elif sub.op in ["&&", "||"]: - sub.op = "||" if sub.op == "&&" else "&&" - sub.sub = [AstOp("!", [x]) for x in sub.sub] - |