Skip to content

Commit

Permalink
cargo: Do not convert cfg() to Meson AST
Browse files Browse the repository at this point in the history
We'll need to evaluate those expressions before generating the AST.
Instead take a config key-value dictionary and evaluate the expression
to return a boolean.
  • Loading branch information
xclaesse committed Oct 24, 2024
1 parent b6028a8 commit 8676322
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 107 deletions.
74 changes: 17 additions & 57 deletions mesonbuild/cargo/cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,9 @@
from __future__ import annotations
import dataclasses
import enum
import functools
import typing as T


from . import builder
from .. import mparser
from ..mesonlib import MesonBugException

if T.TYPE_CHECKING:
Expand Down Expand Up @@ -144,8 +141,8 @@ class Identifier(IR):
@dataclasses.dataclass
class Equal(IR):

lhs: IR
rhs: IR
lhs: Identifier
rhs: String


@dataclasses.dataclass
Expand Down Expand Up @@ -219,57 +216,20 @@ def parse(ast: _LEX_STREAM) -> IR:
return _parse(ast_i)


@functools.singledispatch
def ir_to_meson(ir: T.Any, build: builder.Builder) -> mparser.BaseNode:
raise NotImplementedError


@ir_to_meson.register
def _(ir: String, build: builder.Builder) -> mparser.BaseNode:
return build.string(ir.value)


@ir_to_meson.register
def _(ir: Identifier, build: builder.Builder) -> mparser.BaseNode:
host_machine = build.identifier('host_machine')
if ir.value == "target_arch":
return build.method('cpu_family', host_machine)
elif ir.value in {"target_os", "target_family"}:
return build.method('system', host_machine)
elif ir.value == "target_endian":
return build.method('endian', host_machine)
raise MesonBugException(f"Unhandled Cargo identifier: {ir.value}")


@ir_to_meson.register
def _(ir: Equal, build: builder.Builder) -> mparser.BaseNode:
return build.equal(ir_to_meson(ir.lhs, build), ir_to_meson(ir.rhs, build))


@ir_to_meson.register
def _(ir: Not, build: builder.Builder) -> mparser.BaseNode:
return build.not_(ir_to_meson(ir.value, build))


@ir_to_meson.register
def _(ir: Any, build: builder.Builder) -> mparser.BaseNode:
if not ir.args:
return build.bool(False)
args = iter(reversed(ir.args))
last = next(args)
cur = build.or_(ir_to_meson(next(args), build), ir_to_meson(last, build))
for a in args:
cur = build.or_(ir_to_meson(a, build), cur)
return cur
def _eval_cfg(ir: IR, cfgs: T.Dict[str, str]) -> bool:
if isinstance(ir, Identifier):
return ir.value in cfgs
elif isinstance(ir, Equal):
return cfgs.get(ir.lhs.value) == ir.rhs.value
elif isinstance(ir, Not):
return not _eval_cfg(ir.value, cfgs)
elif isinstance(ir, Any):
return any(_eval_cfg(i, cfgs) for i in ir.args)
elif isinstance(ir, All):
return all(_eval_cfg(i, cfgs) for i in ir.args)
else:
raise MesonBugException(f'Unhandled Cargo cfg IR: {ir}')


@ir_to_meson.register
def _(ir: All, build: builder.Builder) -> mparser.BaseNode:
if not ir.args:
return build.bool(True)
args = iter(reversed(ir.args))
last = next(args)
cur = build.and_(ir_to_meson(next(args), build), ir_to_meson(last, build))
for a in args:
cur = build.and_(ir_to_meson(a, build), cur)
return cur
def eval_cfg(raw: str, cfgs: T.Dict[str, str]) -> bool:
return _eval_cfg(parse(lexer(raw)), cfgs)
69 changes: 19 additions & 50 deletions unittests/cargotests.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,60 +151,29 @@ def test_parse(self) -> None:
with self.subTest():
self.assertEqual(cfg.parse(iter(cfg.lexer(data))), expected)

def test_ir_to_meson(self) -> None:
build = builder.Builder('')
HOST_MACHINE = build.identifier('host_machine')

def test_eval_ir(self) -> None:
d = {
'target_os': 'unix',
'unix': '',
}
cases = [
('target_os = "windows"',
build.equal(build.method('system', HOST_MACHINE),
build.string('windows'))),
('target_arch = "x86"',
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('x86'))),
('target_family = "unix"',
build.equal(build.method('system', HOST_MACHINE),
build.string('unix'))),
('not(target_arch = "x86")',
build.not_(build.equal(
build.method('cpu_family', HOST_MACHINE),
build.string('x86')))),
('any(target_arch = "x86", target_arch = "x86_64")',
build.or_(
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('x86')),
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('x86_64')))),
('any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")',
build.or_(
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('x86')),
build.or_(
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('x86_64')),
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('aarch64'))))),
('all(target_arch = "x86", target_arch = "x86_64")',
build.and_(
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('x86')),
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('x86_64')))),
('all(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")',
build.and_(
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('x86')),
build.and_(
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('x86_64')),
build.equal(build.method('cpu_family', HOST_MACHINE),
build.string('aarch64'))))),
('all()', build.bool(True)),
('any()', build.bool(False)),
('target_os = "windows"', False),
('target_os = "unix"', True),
('doesnotexist = "unix"', False),
('not(target_os = "windows")', True),
('any(target_os = "windows", target_arch = "x86_64")', False),
('any(target_os = "windows", target_os = "unix")', True),
('all(target_os = "windows", target_os = "unix")', False),
('all(not(target_os = "windows"), target_os = "unix")', True),
('any(unix, windows)', True),
('all()', True),
('any()', False),
('cfg(unix)', True),
('cfg(windows)', False),
]
for data, expected in cases:
with self.subTest():
value = cfg.ir_to_meson(cfg.parse(iter(cfg.lexer(data))), build)
value = cfg.eval_cfg(data, d)
self.assertEqual(value, expected)

class CargoLockTest(unittest.TestCase):
Expand Down

0 comments on commit 8676322

Please sign in to comment.