nfl/stdlib

Search:
Group by:

Embeds the NFL prelude source so it's available at compile time without a runtime file read — needed since compiler.nim auto-loads it inside Nim macros, where the compiler VM's file access is restricted.

Consts

coreSource = "(defmacro when (test &body body)\n  `(if ,test (block ,@body) nil))\n\n(defmacro unless (test &body body)\n  `(if ,test nil (block ,@body)))\n\n(defmacro progn (&body body)\n  `(block ,@body))\n\n; CL-style spellings of the Nim declaration forms — plain aliases, not the\n; canonical syntax (which stays Nim-focused); provided for readers who\'d\n; rather see a `def...` prefix.\n(defmacro defproc (name &rest args)\n  `(proc ,name ,@args))\n\n(defmacro defun (name &rest args)\n  `(proc ,name ,@args))\n\n(defmacro defvar (name &rest args)\n  `(var ,name ,@args))\n\n; `defvar`/`defparameter` are the same plain `var` alias at expansion time —\n; both compile down to nothing but `(var name args...)`. Their distinct CL\n; semantics (defvar sets only if unbound; defparameter always resets) are\n; not a macro-expansion-time property; they only become observable when the\n; same name is re-entered, which only happens in `nfl repl` (#14), so the\n; REPL — not this macro — is what tells the two apart, by checking a\n; re-entered name\'s *raw* head symbol before deciding whether to keep the\n; old value or replace it.\n(defmacro defparameter (name &rest args)\n  `(var ,name ,@args))\n\n(defmacro defconst (name &rest args)\n  `(const ,name ,@args))\n\n(defmacro defconstant (name &rest args)\n  `(const ,name ,@args))\n\n(defmacro deftype (name &rest args)\n  `(type ,name ,@args))\n\n(defmacro deftemplate (name &rest args)\n  `(template ,name ,@args))\n\n(defmacro defiterator (name &rest args)\n  `(iterator ,name ,@args))\n\n(defmacro defmethod (name &rest args)\n  `(method ,name ,@args))\n\n(defmacro deffunc (name &rest args)\n  `(func ,name ,@args))\n\n(defmacro defconverter (name &rest args)\n  `(converter ,name ,@args))\n\n(defmacro and (&rest args)\n  (if (nil? args)\n      true\n      (if (nil? (rest args))\n          (first args)\n          `(if ,(first args) (and ,@(rest args)) false))))\n\n(defmacro or (&rest args)\n  (if (nil? args)\n      false\n      (if (nil? (rest args))\n          (first args)\n          (let ((value (gensym \"or\")))\n            `(let ((,value ,(first args)))\n               (if ,value ,value (or ,@(rest args))))))))\n\n(defmacro cond (&rest clauses)\n  (if (nil? clauses)\n      nil\n      (let ((clause (first clauses)))\n        (if (symbol? clause)\n            (macro-error \"cond clause must be a list\")\n            (if (nil? (rest clause))\n                (macro-error \"cond clause expects test and body\")\n                (if (nil? (rest clauses))\n                    `(if ,(first clause) (block ,@(rest clause)) nil)\n                    `(if ,(first clause) (block ,@(rest clause)) (cond ,@(rest clauses)))))))))\n\n(defmacro let* (bindings &body body)\n  (if (nil? bindings)\n      `(block ,@body)\n      `(let (,(first bindings)) (let* ,(rest bindings) ,@body))))\n\n(defmacro first (items)\n  `(at ,items 0))\n\n(defmacro rest (items)\n  `(slice ,items 1 (- (. ,items len) 1)))\n\n(defmacro empty? (items)\n  `(== (. ,items len) 0))\n\n(defmacro append (left right)\n  `(& ,left ,right))\n\n(defmacro map (items op)\n  `(nflSeqMap ,items ,op))\n\n(defmacro filter (items pred)\n  `(nflSeqFilter ,items ,pred))\n\n(defmacro foldl (items initial op)\n  `(nflSeqFoldl ,items ,initial ,op))\n\n(defmacro foldr (items initial op)\n  `(nflSeqFoldr ,items ,initial ,op))\n\n; CL-style sequence functions. Argument order follows the rest of this\n; preamble (items first, like map/filter/foldl above) rather than CL\'s own\n; order (e.g. CL\'s `some`/`every` take the predicate first) — kept\n; consistent with NFL\'s own convention instead of literal CL. `position`\n; and `nflSeqPosition` return -1 when not found (Nim\'s own sentinel\n; convention), not CL\'s nil, since a generic element type has no nil-like\n; value to return instead.\n; unlike CL, `n` and `fill` are both required — Nim can only infer the\n; array\'s element type from an actual argument value, and NFL has no call-\n; site syntax for supplying a bare type argument instead.\n(defmacro make-array (n fill)\n  `(nflMakeArray ,n ,fill))\n\n(defmacro length (items)\n  `(. ,items len))\n\n(defmacro reverse (items)\n  `(nflReversed ,items))\n\n(defmacro sort (items)\n  `(nflSorted ,items))\n\n(defmacro mapcar (items op)\n  `(nflSeqMap ,items ,op))\n\n(defmacro reduce (items initial op)\n  `(nflSeqFoldl ,items ,initial ,op))\n\n(defmacro remove-if (items pred)\n  `(nflSeqRemoveIf ,items ,pred))\n\n(defmacro remove-if-not (items pred)\n  `(nflSeqFilter ,items ,pred))\n\n(defmacro count-if (items pred)\n  `(nflSeqCount ,items ,pred))\n\n(defmacro some (items pred)\n  `(nflSeqAny ,items ,pred))\n\n(defmacro every (items pred)\n  `(nflSeqEvery ,items ,pred))\n\n(defmacro position (items value)\n  `(nflSeqPosition ,items ,value))\n\n(defmacro elt (items i)\n  `(at ,items ,i))\n\n(defmacro aref (items i)\n  `(at ,items ,i))\n\n; CL\'s subseq takes an exclusive end (and an optional, sequence-length-\n; defaulted one) — unlike NFL\'s own `slice`, whose end is inclusive — so\n; this isn\'t a bare alias, it adjusts for that difference.\n(defmacro subseq (items start &rest rest)\n  (if (nil? rest)\n      `(slice ,items ,start (- (. ,items len) 1))\n      `(slice ,items ,start (- ,(first rest) 1))))\n\n(defmacro -> (value &rest forms)\n  (if (nil? forms)\n      value\n      (let ((form (first forms)))\n        (if (list? form)\n            `(-> (,(first form) ,value ,@(rest form)) ,@(rest forms))\n            `(-> (,form ,value) ,@(rest forms))))))\n\n(defmacro ->> (value &rest forms)\n  (if (nil? forms)\n      value\n      (let ((form (first forms)))\n        (if (list? form)\n            `(->> (,(first form) ,@(rest form) ,value) ,@(rest forms))\n            `(->> (,form ,value) ,@(rest forms))))))\n\n(defmacro as-> (value name &body forms)\n  (if (nil? forms)\n      value\n      `(let ((,name ,value)) (as-> ,(first forms) ,name ,@(rest forms)))))\n\n; CLOS-lite: a defclass/make-instance layer over the existing type/ref/\n; object/new/method forms, in the spirit of the def* aliases and CL sequence\n; functions above. Deliberate departures from real CLOS, tightened by what\n; NFL doesn\'t have yet (see the tracker for the follow-up tickets):\n;   - :initform is supported (a slot default used when make-instance omits\n;     it). :initarg (a distinct external initializer name for a slot,\n;     `(name Type :initarg :nom)`) is also supported, but not by a\n;     macro-expand-time class registry — defclass still has no visibility\n;     into an inherited superclass\'s slots at its own expansion time.\n;     Instead each :initarg is recorded as a Nim custom field pragma\n;     (`nflInitarg`, runtime.nim), and `make-instance` expands to the Nim\n;     macro `nflMakeInstance`, which walks the class\'s type definition —\n;     including its `of` inheritance chain — at Nim semcheck time, when\n;     every ancestor\'s fields and pragmas are visible. A slot\'s own field\n;     name and its :initarg are both accepted at the call site — an\n;     :initarg is an alias, not a rename: `(name Type :initarg :nom)` can\n;     be initialized as either `(name ...)` or `(nom ...)`.\n;   - :accessor generates both a getter and a setter (`animalName` and\n;     `animalName=`, callable as `(set! (animalName a) v)`); :reader\n;     generates a getter only.\n;   - single inheritance only — a defclass superclass list may name at most\n;     one parent; full CLOS multiple dispatch is tracked separately.\n;   - defmethod stays the plain `method` alias defined above; CLOS-lite adds\n;     no dispatch mechanism of its own.\n;   - every slot carries an explicit Nim type, because Nim object fields\n;     must be typed and NFL has no type-inference story for them.\n;   - :accessor/:reader names become real `proc` names, so — unlike a\n;     defclass/defmacro/defmacro-proc name itself, which only ever exists at\n;     expansion time — they must be plain Nim identifiers (no hyphens);\n;     `animalName`, not `animal-name`.\n;   - an :initform expression must be a compile-time-evaluable Nim\n;     expression — it lowers straight into a Nim object-field default (see\n;     `man/language-reference.md`), which carries that same restriction.\n;   - an :initarg value is conventionally keyword-shaped (`:nom`), matching\n;     :accessor/:reader/:initform\'s own keys, but any symbol works — it\n;     never becomes a proc name, only a Nim pragma string, so it carries\n;     none of :accessor/:reader\'s plain-Nim-identifier restriction.\n\n(defmacro-proc nfl-class-parent (supers)\n  (if (nil? supers)\n      \'RootObj\n      (if (nil? (rest supers))\n          (first supers)\n          (macro-error \"defclass supports a single superclass; see the multiple-dispatch ticket\"))))\n\n(defmacro-proc nfl-slot-option-key-ok? (key)\n  (if (= key \':accessor) true (if (= key \':reader) true (if (= key \':initform) true (= key \':initarg)))))\n\n(defmacro-proc nfl-validate-slot-options (opts)\n  (if (nil? opts)\n      nil\n      (if (nil? (rest opts))\n          (macro-error \"defclass slot option missing its value\")\n          (if (nfl-slot-option-key-ok? (first opts))\n              ; :initform\'s value is an arbitrary expression; :accessor/\n              ; :reader/:initarg still require a plain symbol (:accessor/\n              ; :reader turn it into a proc name; :initarg turns it into a\n              ; pragma string — see nfl-slot-initarg/nfl-slot-field).\n              (if (= (first opts) \':initform)\n                  (nfl-validate-slot-options (rest (rest opts)))\n                  (if (symbol? (nth opts 1))\n                      (nfl-validate-slot-options (rest (rest opts)))\n                      (macro-error \"defclass slot accessor/reader/initarg value must be a symbol\")))\n              (macro-error (string-append \"defclass: unknown slot option \" (symbol->string (first opts))))))))\n\n(defmacro-proc nfl-slot-names-for-key (opts key)\n  ; Collects the values paired with a given option key (`:accessor`,\n  ; `:reader`, or `:initform`), skipping every other key/value pair. Called\n  ; once per key so `:accessor` and `:reader` each generate their own set of\n  ; procs (see #75).\n  (if (nil? opts)\n      \'()\n      (if (= (first opts) key)\n          (cons (nth opts 1) (nfl-slot-names-for-key (rest (rest opts)) key))\n          (nfl-slot-names-for-key (rest (rest opts)) key))))\n\n(defmacro-proc nfl-slot-initform (slot)\n  ; Extracts a slot\'s :initform value, if any — the single value paired with\n  ; the :initform key, or nil if the option is absent. More than one\n  ; :initform on a slot is rejected here, since `nfl-validate-slot-options`\n  ; validates each key/value pair independently and never counts repeats.\n  (let ((initforms (nfl-slot-names-for-key (rest (rest slot)) \':initform)))\n    (if (nil? initforms)\n        nil\n        (if (nil? (rest initforms))\n            (first initforms)\n            (macro-error \"defclass slot has more than one :initform\")))))\n\n(defmacro-proc nfl-slot-initarg (slot)\n  ; Extracts a slot\'s :initarg value, if any — the single value paired with\n  ; the :initarg key, or nil if the option is absent. More than one\n  ; :initarg on a slot is rejected here, mirroring nfl-slot-initform.\n  (let ((initargs (nfl-slot-names-for-key (rest (rest slot)) \':initarg)))\n    (if (nil? initargs)\n        nil\n        (if (nil? (rest initargs))\n            (first initargs)\n            (macro-error \"defclass slot has more than one :initarg\")))))\n\n(defmacro-proc nfl-slot-field (slot)\n  ; Validated here, not only in nfl-slot-accessors: defclass computes\n  ; `fields` before `accessors` (see below), and an :initarg\'s value gets\n  ; converted with symbol->string right below — which needs it to already\n  ; be a symbol, not just eventually rejected as a non-symbol once\n  ; nfl-slot-accessors gets around to validating it.\n  (if (not (list? slot))\n      (macro-error \"defclass slot must be a list\")\n      (if (< (length slot) 2)\n          (macro-error \"defclass slot must be (name Type [options...])\")\n          (let ((validated (nfl-validate-slot-options (rest (rest slot))))\n                (initform (nfl-slot-initform slot))\n                (initarg (nfl-slot-initarg slot)))\n            (if (nil? initarg)\n                (if (nil? initform)\n                    (list (first slot) (nth slot 1))\n                    (list (first slot) (nth slot 1) initform))\n                ; An :initarg becomes a field pragma (`nflInitarg`,\n                ; runtime.nim) that `nflMakeInstance` reads back off the\n                ; class\'s Nim type definition at semcheck time — the\n                ; visibility a macro-expand-time defclass/make-instance\n                ; pair can\'t have across an inherited slot. The pragma\'s\n                ; string carries the keyword\'s own text (colon included);\n                ; nflMakeInstance strips it there, not here, since NFL\'s\n                ; macro-time builtins have no substring primitive.\n                (let ((pragmaClause `(pragma (: nflInitarg ,(symbol->string initarg)))))\n                  (if (nil? initform)\n                      (list (first slot) pragmaClause (nth slot 1))\n                      (list (first slot) pragmaClause (nth slot 1) initform))))))))\n\n(defmacro-proc nfl-slot-fields (slots)\n  (if (nil? slots)\n      \'()\n      (cons (nfl-slot-field (first slots)) (nfl-slot-fields (rest slots)))))\n\n(defmacro-proc nfl-make-getter (className fieldName fieldType getterName)\n  ; A literal `self`, not `(gensym \"self\")` — the automatic hygiene pass\n  ; auto-renames a proc\'s own literal param names, so this can\'t capture or\n  ; be captured by a caller symbol even without an explicit gensym. (A\n  ; literal name also keeps the golden-expansion fixture\'s output stable —\n  ; renderSyntax doesn\'t print hygieneId, but a gensym\'d name would embed\n  ; the macro env\'s running counter in its printed spelling, making the\n  ; fixture\'s exact text depend on unrelated preamble changes.)\n  `(proc ,getterName ((self ,className)) (: ,fieldType) (. self ,fieldName)))\n\n(defmacro-proc nfl-make-setter (className fieldName fieldType setterName)\n  `(proc ,setterName ((self ,className) (v ,fieldType)) (set! (. self ,fieldName) v)))\n\n(defmacro-proc nfl-make-getters-for-names (className fieldName fieldType names)\n  (if (nil? names)\n      \'()\n      (cons (nfl-make-getter className fieldName fieldType (first names))\n            (nfl-make-getters-for-names className fieldName fieldType (rest names)))))\n\n(defmacro-proc nfl-setter-name (accessorName)\n  (string->symbol (string-append (symbol->string accessorName) \"=\")))\n\n(defmacro-proc nfl-make-setters-for-names (className fieldName fieldType names)\n  (if (nil? names)\n      \'()\n      (cons (nfl-make-setter className fieldName fieldType (nfl-setter-name (first names)))\n            (nfl-make-setters-for-names className fieldName fieldType (rest names)))))\n\n(defmacro-proc nfl-slot-accessors (className slot)\n  (let ((fieldName (first slot))\n        (fieldType (nth slot 1))\n        (opts (rest (rest slot))))\n    (nfl-validate-slot-options opts)\n    (let ((accessorNames (nfl-slot-names-for-key opts \':accessor))\n          (readerNames (nfl-slot-names-for-key opts \':reader)))\n      (append (nfl-make-getters-for-names className fieldName fieldType accessorNames)\n              (append (nfl-make-setters-for-names className fieldName fieldType accessorNames)\n                      (nfl-make-getters-for-names className fieldName fieldType readerNames))))))\n\n(defmacro-proc nfl-class-accessors (className slots)\n  (if (nil? slots)\n      \'()\n      (append (nfl-slot-accessors className (first slots)) (nfl-class-accessors className (rest slots)))))\n\n(defmacro defclass (name supers slots)\n  (let ((fields (nfl-slot-fields slots))\n        (accessors (nfl-class-accessors name slots))\n        (parent (nfl-class-parent supers)))\n    `(block\n       (type ,name (ref (object (of ,parent) ,@fields)))\n       ,@accessors)))\n\n(defmacro make-instance (className &rest inits)\n  ; nflMakeInstance (runtime.nim) is a Nim macro, not plain sugar over `new`:\n  ; unlike this preamble macro, it runs at Nim semcheck time, when the\n  ; class\'s whole `of` inheritance chain — and every ancestor\'s :initarg\n  ; pragmas — is visible, so an initializer can name either a slot\'s own\n  ; field or its :initarg, inherited or not.\n  `(nflMakeInstance ,className ,@inits))\n"
The full source of preamble.nfl, auto-expanded before user code unless expandSource/expandModule is called with autoloadCore = false (e.g. the REPL's --no-core).