Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions doc/build/dts/macros.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,9 @@ property-macro = %s"DT_N" path-id %s"_P_" prop-id [prop-suf]
; };
; };
;
; has path-id "_S_foo_123_S_bar_baz".
path-id = 1*( %s"_S_" dt-name )
; has path-id "_S_foo_123_S_bar_baz". The root node "/" has an empty
; path-id, which results in a bare "DT_N" identifier.
path-id = *( %s"_S_" dt-name )

; ----------------------------------------------------------------------
; prop-id: a property identifier
Expand Down
123 changes: 123 additions & 0 deletions doc/tools/check_dt_macros.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
# Copyright (c) 2024 The Zephyr Project Developers
# SPDX-License-Identifier: Apache-2.0
"""Lightweight sanity checks for devicetree macro identifiers.

This script operates on a small, curated fixture that mimics the generated
``devicetree_generated.h`` header. The goal is to exercise the grammar
documented in ``doc/build/dts/macros.bnf`` and make sure common patterns –
including identifiers for the devicetree root node – are accepted.

The fixture does not need to contain exhaustive data; it only needs to cover
typical shapes so regressions are caught quickly. In particular, the root
node macros such as ``DT_N_PATH`` and ``DT_N_FOREACH_CHILD(fn)`` are included
so the optional nature of the ``path-id`` production is validated.
"""

from __future__ import annotations

import re
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import Iterable, Iterator

Check failure on line 23 in doc/tools/check_dt_macros.py

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

Python lint error (UP035) see https://docs.astral.sh/ruff/rules/deprecated-import

doc/tools/check_dt_macros.py:23 Import from `collections.abc` instead: `Iterable`, `Iterator`

FIXTURE_DIR = Path(__file__).with_name("fixtures")
FIXTURE = FIXTURE_DIR / "sample_devicetree_macros.h"

PATH_SEGMENT_RE = re.compile(r"_S_([a-z0-9]+(?:_[a-z0-9]+)*)")


@dataclass(frozen=True)
class Macro:
name: str
params: str


MACRO_RE = re.compile(r"#define\s+(DT_[A-Za-z0-9_]+)(\([^)]*\))?")


def parse_fixture(path: Path) -> Iterator[Macro]:
"""Yield ``Macro`` objects from a fixture header."""

for raw_line in path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
match = MACRO_RE.match(line)
if match is None:
continue

macro_name, params = match.groups()
yield Macro(name=macro_name, params=params or "")


def consume_path_id(text: str) -> int:
"""Return the index directly after the ``path-id`` portion of ``text``."""

index = 0
while True:
match = PATH_SEGMENT_RE.match(text, index)
if match is None:
break
index = match.end()

return index


def validate_node_macro(macro: Macro) -> None:
"""Validate macros that start with the ``DT_N`` prefix."""

suffix_params = {
"_PATH": "",
"_FOREACH_CHILD": "(fn)",
"_FOREACH_CHILD_SEP": "(fn, sep)",
"_FOREACH_CHILD_VARGS": "(fn, ...)",
"_FOREACH_CHILD_SEP_VARGS": "(fn, sep, ...)",
}

name_without_prefix = macro.name[len("DT_") :]
if not name_without_prefix.startswith("N"):
return

tail = name_without_prefix[1:]
try:
path_id_end = consume_path_id(tail)
except ValueError as exc:
raise AssertionError(f"invalid path-id in '{macro.name}'") from exc

suffix = tail[path_id_end:]
for candidate, expected_params in suffix_params.items():
if suffix == candidate:
if macro.params != expected_params:
raise AssertionError(
f"macro '{macro.name}' expects parameters {expected_params!r},"
f" found {macro.params!r}"
)
return

raise AssertionError(f"unrecognised node macro suffix in '{macro.name}'")


def validate_macros(macros: Iterable[Macro]) -> None:
for macro in macros:
if macro.name.startswith("DT_N"):
validate_node_macro(macro)


def main() -> int:
if not FIXTURE.exists():
print(f"Fixture '{FIXTURE}' not found", file=sys.stderr)
return 1

macros = list(parse_fixture(FIXTURE))
try:
validate_macros(macros)
except AssertionError as exc:
print(exc, file=sys.stderr)
return 1

print(f"Validated {len(macros)} macros from {FIXTURE.relative_to(Path.cwd())}")
return 0


if __name__ == "__main__":
sys.exit(main())
17 changes: 17 additions & 0 deletions doc/tools/fixtures/sample_devicetree_macros.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Minimal fixture containing a subset of generated devicetree macros.
* Values are intentionally simple; only macro identifiers are relevant
* for the documentation grammar check.
*/

#define DT_N_PATH "\/"
#define DT_N_FOREACH_CHILD(fn) fn(DT_N)
#define DT_N_FOREACH_CHILD_SEP(fn, sep) fn(DT_N)
#define DT_N_FOREACH_CHILD_VARGS(fn, ...) fn(DT_N, __VA_ARGS__)
#define DT_N_FOREACH_CHILD_SEP_VARGS(fn, sep, ...) fn(DT_N, sep, __VA_ARGS__)

#define DT_N_S_soc_PATH "\/soc"
#define DT_N_S_soc_FOREACH_CHILD(fn) fn(DT_N_S_soc)
#define DT_N_S_soc_FOREACH_CHILD_SEP(fn, sep) fn(DT_N_S_soc)
#define DT_N_S_soc_FOREACH_CHILD_VARGS(fn, ...) fn(DT_N_S_soc, __VA_ARGS__)
#define DT_N_S_soc_FOREACH_CHILD_SEP_VARGS(fn, sep, ...) fn(DT_N_S_soc, sep, __VA_ARGS__)
18 changes: 1 addition & 17 deletions dts/bindings/adc/arduino,uno-adc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,4 @@ description: |

compatible: "arduino,uno-adc"

include: base.yaml

properties:
io-channel-map:
type: compound
required: true

io-channel-map-mask:
type: compound

io-channel-map-pass-thru:
type: compound

"#io-channel-cells":
type: int
required: true
description: Number of items to expect in an ADC specifier
include: [base.yaml, io-channel-nexus.yaml]
4 changes: 2 additions & 2 deletions dts/bindings/gpio/gpio-nexus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ properties:
required: true

gpio-map-mask:
type: compound
type: array

gpio-map-pass-thru:
type: compound
type: array

"#gpio-cells":
type: int
Expand Down
20 changes: 20 additions & 0 deletions dts/bindings/iio/io-channel-nexus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright (c) 2025 TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0

# Common fields for io-channel nexus

properties:
io-channel-map:
type: compound
required: true

io-channel-map-mask:
type: array

io-channel-map-pass-thru:
type: array

"#io-channel-cells":
type: int
required: true
description: Number of items to expect in the io-channel specifier, such as ADC channels.
20 changes: 20 additions & 0 deletions dts/bindings/interrupt-controller/interrupt-nexus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright (c) 2025 TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0

# Common fields for interrupt nexus nodes

properties:
interrupt-map:
type: compound
required: true

interrupt-map-mask:
type: array

interrupt-map-pass-thru:
type: array

"#interrupt-cells":
type: int
required: true
description: Number of items to expect in a interrupt specifier
8 changes: 1 addition & 7 deletions dts/bindings/pcie/host/pci-host-ecam-generic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: PCIe Controller in ECAM mode

compatible: "pci-host-ecam-generic"

include: pcie-controller.yaml
include: [pcie-controller.yaml, interrupt-nexus.yaml]

properties:
reg:
Expand All @@ -22,11 +22,5 @@ properties:
definition of non-prefetchable memory. One or both of prefetchable Memory
and IO Space may also be provided.

interrupt-map-mask:
type: array

interrupt-map:
type: compound

bus-range:
type: array
8 changes: 8 additions & 0 deletions dts/bindings/test/vnd,gpio-nexus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2025, TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0

description: VND GPIO nexus

include: [gpio-nexus.yaml]

compatible: "vnd,gpio-nexus"
8 changes: 8 additions & 0 deletions dts/bindings/test/vnd,intr-nexus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2025, TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0

description: VND interrupt nexus

include: [interrupt-nexus.yaml]

compatible: "vnd,intr-nexus"
1 change: 1 addition & 0 deletions include/zephyr/devicetree.h
Original file line number Diff line number Diff line change
Expand Up @@ -5570,5 +5570,6 @@
#include <zephyr/devicetree/mbox.h>
#include <zephyr/devicetree/port-endpoint.h>
#include <zephyr/devicetree/display.h>
#include <zephyr/devicetree/map.h>

#endif /* ZEPHYR_INCLUDE_DEVICETREE_H_ */
Loading
Loading