Linx.NFT.RuntimeCompiler (Linx v0.1.0)

Copy Markdown View Source

AST → Elixir AST (quoted code) translation for ~NFT sigil bodies that contain #{...} interpolations.

This is the runtime-emit sibling of Linx.NFT.Compiler. Where the static compiler walks the AST and calls the validator-setter functions on Linx.Netfilter.Ruleset directly to produce a ready-made %Ruleset{} value at compile time, the runtime compiler walks the same AST and produces an Elixir AST that, when evaluated at runtime, calls the same validator-setter functions to produce the %Ruleset{}. The two paths are semantically identical for static sigils; the runtime emit path exists so the sigil can splice the values of interpolated Elixir expressions into the right positions.

The macro picks which path to use based on whether any :elixir_expr tokens were produced by the tokenizer.

Static portions vs runtime portions

AST nodes outside the value-position of a match (i.e. table family, chain name, hook, priority, …) must be static — the parser produces the same AST for them, and the runtime compiler emits them as literal values via Macro.escape/1.

AST nodes at value positions inside matches CAN be :elixir_expr. When they are, the runtime compiler:

  1. Parses the raw Elixir source of the interpolation with Code.string_to_quoted!/1 to recover the original AST.
  2. Emits a call to Linx.NFT.Runtime.cmp!/3 (or one of the other encoders) passing the parsed Elixir AST + the field kind the surrounding nft syntax expects.

Result: at runtime, the Elixir expression is evaluated in the caller's scope, encoded per the typed field, and spliced into the rule's expression list.

Scope

Mirrors Linx.NFT.Compiler's scope. Anything the static compiler rejects (limit / meta-set / named objects / flowtables / concat keys / includes) the runtime compiler also rejects, with the same error message. Interpolation is supported at:

  • Match RHS where the field kind is {:int, _} / :ipv4 / :ipv6 / :ifname.

Interpolations in keyword positions (table name, chain name, family, hook, etc.) raise a clear ParseError — they'd require case-by-case wiring through each validator-setter.

Summary

Functions

Emits Elixir AST that, when evaluated, returns a %Linx.Netfilter.Ruleset{}. Returns {:ok, quoted} or {:error, %ParseError{}}.

Functions

emit(ast_items, opts \\ [])

@spec emit(
  [tuple()],
  keyword()
) :: {:ok, Macro.t()} | {:error, Linx.NFT.ParseError.t()}

Emits Elixir AST that, when evaluated, returns a %Linx.Netfilter.Ruleset{}. Returns {:ok, quoted} or {:error, %ParseError{}}.