nfl/macros

Macro definitions and the environment (MacroEnv) they're registered in, shared by the macro expander (expand.nim) — parameter shapes for &optional/&rest/&body/&key, gensym/hygiene id allocation, and the import-cycle tracking used while inlining .nfl files.

Types

MacroDef = object
  name*: string
  params*: seq[Syntax]
  optParams*: seq[MacroOptParam]
  restParam*: string
  bodyParam*: string
  keyParams*: seq[MacroKeyParam]
  body*: seq[Syntax]
  span*: Span
A single macro's parameter shape and body.
MacroEnv = ref object
  macros*: Table[string, MacroDef]
  macroProcs*: Table[string, MacroDef] ## `defmacro-proc` definitions (#70)
  macroProcDepth*: int       ## current `defmacro-proc` call nesting — guards
                             ## against unbounded evaluator recursion, since
                             ## `maxExpansionDepth` only counts expansions
  gensymCounter*: int
  includedFiles*: HashSet[string] ## resolved paths of .nfl files already
                                  ## inlined (#10) — a second `(import
                                  ## ...)` of the same file is a no-op so
                                  ## diamond imports don't duplicate decls
  includingStack*: seq[string] ## resolved paths currently being
                               ## inlined, in inclusion order — used to
                               ## detect and report circular imports
Expansion-time state: registered macros, gensym counter, and import-cycle tracking.
MacroKeyParam = object
  keyword*: string
  local*: string
  default*: Option[Syntax]
A &key macro parameter.
MacroOptParam = object
  name*: string
  default*: Option[Syntax]
An &optional macro parameter.

Consts

macroReservedNames = ["quote", "quasiquote", "if", "block", "let", "break-from",
                      "symbol?", "list?", "vector?", "string?", "int?",
                      "float?", "bool?", "nil?", "first", "rest", "cons",
                      "list", "append", "syntax->datum", "datum->syntax",
                      "gensym", "macro-error", "+", "-", "*", "/", "div", "mod",
                      "<", "<=", ">", ">=", "=", "/=", "not", "nth", "length",
                      "reverse", "member", "symbol->string", "string->symbol",
                      "string-append"]

Procs

proc defineMacro(env: MacroEnv; def: MacroDef) {....raises: [CompilerError],
    tags: [], forbids: [].}
Registers def in env; raises CompilerError if a macro with the same name is already defined.
proc defineMacroProc(env: MacroEnv; def: MacroDef) {....raises: [CompilerError],
    tags: [], forbids: [].}
Registers def in env; raises CompilerError if a macro-proc with the same name is already defined, or if def.name shadows a macro-time special form or builtin (macroReservedNames) — both would otherwise be silently unreachable behind the reserved name's own dispatch.
proc gensym(env: MacroEnv; hint: string; span: Span): Syntax {....raises: [],
    tags: [], forbids: [].}
Allocates a fresh, guaranteed-unique symbol prefixed with hint (or "g" if empty), for use in macro-generated code.
proc getMacro(env: MacroEnv; name: string): MacroDef {....raises: [KeyError],
    tags: [], forbids: [].}
proc getMacroProc(env: MacroEnv; name: string): MacroDef {....raises: [KeyError],
    tags: [], forbids: [].}
proc hasMacro(env: MacroEnv; name: string): bool {....raises: [], tags: [],
    forbids: [].}
True if a macro named name is registered in env.
proc hasMacroProc(env: MacroEnv; name: string): bool {....raises: [], tags: [],
    forbids: [].}
True if a defmacro-proc named name is registered in env.
proc newHygienicId(env: MacroEnv): int {....raises: [], tags: [], forbids: [].}
Allocates a fresh hygieneId for the automatic template-hygiene rename pass (#11) — shares gensymCounter with explicit gensym calls so both mechanisms draw from the same id space; backend.nim's hygienicSymbols table treats an id as opaque regardless of which produced it.
proc newMacroEnv(): MacroEnv {....raises: [], tags: [], forbids: [].}
Creates an empty MacroEnv ready for expansion.