Next: Introduction, Previous: (dir), Up: (dir) [Contents][Index]
This is the check-bnf Reference Manual, version 8.1.30, generated automatically by Declt version 4.0 beta 2 "William Riker" on Mon Aug 15 03:24:25 2022 GMT+0.
Next: Systems, Previous: The check-bnf Reference Manual, Up: The check-bnf Reference Manual [Contents][Index]
Macro arguments checker.
Common Lisp has a true macro. Writing macro means extending the compiler i.e. creating a new language.
Lack of documentation. Do you want to use LANGUAGE which has no documentation nor BNF?
Check-bnf provides a bnf like syntax checker.
It allows you to write macro arguments definition.
It helps the third person to understand your macro.
* (defmacro mydefun (&whole whole name lambda-list &body body)
(check-bnf (:whole whole)
((name (or symbol setf-name))
(setf-name ((eql setf) symbol)))
((lambda-list list)))
(list* name lambda-list body))
MYDEFUN
* (mydefun "name" () :dummy)
debugger invoked on a SYNTAX-ERROR in thread
#<THREAD "main thread" RUNNING {10016C0073}>:
NAME : "name" comes.
Last failed at SETF-NAME.
Detail: SETF-NAME require CONS but "name".
Definition
NAME := [ SYMBOL | SETF-NAME ]
SETF-NAME := ((EQL SETF) SYMBOL)
For detail, see spec file.
You may emb bnf as documentation.
Macro DOC
allows you to do it by read time evaluation and read time labeling.
(defmacro your-macro (&whole w a)
#.(check-bnf:doc "Header for your-macro"
#0=(check-bnf:check-bnf (:whole w)
((a symbol))))
#0#
`',a)
=> YOUR-MACRO
(documentation 'your-macro 'function)
=> "Header for your-macro
A := SYMBOL
"
Your macro may have similar syntax e.g. CASE, CCASE, and ECASE.
In such cases, you can define global BNF by DEFBNF
.
DEFBNF
has almost the same syntax as CHECK-BNF
but except accepts only one definition and alias is invalid.
Currently <LAMBDA-LIST>
, <FUNCTION-TYPE>
and <DECLARATION>
is provided.
MIT
SBCL
Due to its own issue, ccl signals warnings. But the check-bnf features are works fine. In the test, we just muffled it.
The Lisp Pretty Printer implementation is not perfect yet.
CHECK-BNF works fine but the printed message is a little bit strange in clisp. For details see spec file.
CHECK-BNF works fine but the printed message is a little bit strange in abcl due to the abcl pretty printing issue.
Currently tests about pretty printings are ignored.
Allegro insert pprint logical block automatically for condition. Consequently, error message format becomes different from other implementations. Two tests about error message format are skipped.
(simple-condition-format-control (make-condition 'simple-condition :format-control ""))
=> "~1@<~:@>"
quicklisp supported.
* (ql:quickload :check-bnf)
Next: Files, Previous: Introduction, Up: The check-bnf Reference Manual [Contents][Index]
The main system appears first, followed by any subsystem dependency.
Macro arguments checker.
SATO Shinichi
(GIT git@github.com:hyotang666/check-bnf)
MIT
8.1.30
Next: Packages, Previous: Systems, Up: The check-bnf Reference Manual [Contents][Index]
Files are sorted by type and then listed depth-first from the systems components trees.
Next: check-bnf/check-bnf.lisp, Previous: Lisp, Up: Lisp [Contents][Index]
check-bnf (system).
Next: check-bnf/defbnf.lisp, Previous: check-bnf/check-bnf.asd, Up: Lisp [Contents][Index]
check-bnf (system).
Previous: check-bnf/check-bnf.lisp, Up: Lisp [Contents][Index]
check-bnf.lisp (file).
check-bnf (system).
Next: Definitions, Previous: Files, Up: The check-bnf Reference Manual [Contents][Index]
Packages are listed by definition order.
common-lisp.
Next: Indexes, Previous: Packages, Up: The check-bnf Reference Manual [Contents][Index]
Definitions are sorted by export status, category, package, and then by lexicographic order.
Next: Internals, Previous: Definitions, Up: Definitions [Contents][Index]
Next: Ordinary functions, Previous: Public Interface, Up: Public Interface [Contents][Index]
# CHECK-BNF
## Description:
Macro argument checker like CL:CHECK-TYPE.
In most simple case, its like CL:CHECK-TYPE.
“‘lisp
#?(let ((var ’symbol))
(check-bnf ()
((var symbol))))
=> NIL
“‘
“‘lisp
#?(let ((var "string"))
(check-bnf ()
((var symbol))))
:invokes-debugger syntax-error
, :test
“‘
You can check some place at once.
“‘lisp
#?(let ((a ’symbol)
(b "string"))
(check-bnf ()
((a symbol))
((b string))))
=> NIL
“‘
When type-specifier is expanded to T,
Efficient code is generated.
“‘lisp
#?(check-bnf ()
((a t)))
:expanded-to NIL
“‘
“‘lisp
#?(check-bnf ()
((a* t)))
:expanded-to (let ((check-bnf::*whole* nil)
(check-bnf::*bnf* ’((a* t))))
(labels ((a* (a*)
(if (typep a* ’(and atom (not null)))
(let ((check-bnf::*default-condition* ’check-bnf::violate-list))
(syntax-error ’a* "~A require LIST but ~S." ’a* a*))
nil)))
(a* a*)))
“‘
Also it occur in OR form.
“‘lisp
#?(check-bnf ()
((a (or symbol t string))))
:expanded-to NIL
“‘
“‘lisp
#?(check-bnf ()
((a (or symbol b string))
(b t)))
:expanded-to NIL
“‘
“‘lisp
#?(check-bnf ()
((a (or b c))
(b integer)
(c t)))
:expanded-to NIL
“‘
When you know VAR is list, and it has 0 or more elt. (a.k.a. *)
You can write like below.
“‘lisp
#?(let ((var* nil))
(check-bnf ()
((var* symbol))))
=> NIL
“‘
“‘lisp
#?(let ((var* ’(symbol)))
(check-bnf ()
((var* symbol))))
=> NIL
“‘
“‘lisp
#?(let ((var* ’("string")))
(check-bnf ()
((var* symbol))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((var* :not-list))
(check-bnf ()
((var* symbol))))
:invokes-debugger syntax-error
, :test
“‘
When expected T, efficient code is generated.
“‘lisp
#?(CHECK-BNF () ((OPTION* KEYWORD T)))
:expanded-to (LET ((check-bnf::*WHOLE* NIL) (check-bnf::*BNF* ’((OPTION* KEYWORD T))))
(LABELS ((OPTION* (OPTION*)
(IF (TYPEP OPTION* ’(AND ATOM (NOT NULL)))
(let ((check-bnf::*default-condition* ’check-bnf::violate-list))
(SYNTAX-ERROR ’OPTION* "~A require LIST but ~S."
’option*
OPTION*))
(LOOP :FOR args :ON OPTION* :BY #’CDDR
:for (G11516 G11517)
:= (if (typep args ’(cons * (cons * *)))
args
(let ((check-bnf::*default-condition*
’check-bnf::may-syntax-error))
(syntax-error ’option*
"~A : Length mismatch. Lack last ~{~S~^ ~} of ~S~:@_in ~S"
’option*
(subseq ’(keyword t)
(mod (length args) 2))
’(keyword t)
args)))
:DO (FUNCALL
(check-bnf::RESIGNALER ’OPTION* args)
(check-bnf::CAPTURE-SYNTAX-ERROR
(UNLESS (TYPEP G11516 ’KEYWORD)
(SYNTAX-ERROR ’OPTION*
"~A : ~S comes. It is type-of ~S."
’option*
G11516
(TYPE-OF
G11516))))
(check-bnf::IGNORED G11517))))))
(OPTION* OPTION*)))
“‘
If you do not like names var as XXX*, you can specify alias.
“‘lisp
#?(let ((vars ’(symbol)))
(check-bnf ()
(((var* vars) symbol))))
=> NIL
“‘
e.g. specify for plist.
“‘lisp
#?(let ((var* ’(:key "value" :key2 "value2")))
(check-bnf ()
((var* keyword string))))
=> NIL
“‘
“‘lisp
#?(let ((var* ’(:key 2 :key2 "not integer")))
(check-bnf ()
((var* keyword integer))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((var* ’(:key 1 "not-key" 2)))
(check-bnf ()
((var* keyword integer))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((var* ’(:not "ballanced" :plist)))
(check-bnf ()
((var* keyword string))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((var* ’(0 1)))
(check-bnf ()
((var* keyword string))))
:invokes-debugger syntax-error
, :test
“‘
e.g. specify for alist.
“‘lisp
#?(let ((var* ’((:key "value") (:key2 "value2"))))
(check-bnf ()
((var* (keyword string)))))
=> nil
“‘
“‘lisp
#?(let ((var* ’((:key "value") (:key2 :not-string))))
(check-bnf ()
((var* (keyword string)))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((var* ’((:key "value") (:not "ballanced" clause))))
(check-bnf ()
((var* (keyword string)))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((var* ’((:key "value") (:not-ballanced))))
(check-bnf ()
((var* (keyword string)))))
:invokes-debugger syntax-error
, :test
“‘
of course dotted are valid.
“‘lisp
#?(let ((var* ’((:key . "value"))))
(check-bnf ()
((var* (keyword . string)))))
=> nil
“‘
when you know var is list, and it has 1 or more elt, (a.k.a. +)
you can write like below.
“‘lisp
#?(let ((var+ ’(1)))
(check-bnf ()
((var+ integer))))
=> nil
“‘
“‘lisp
#?(let ((var+ ’()))
(check-bnf ()
((var+ integer))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((var+ ’("not-integer")))
(check-bnf ()
((var+ integer))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((var+ :not-cons))
(check-bnf ()
((var+ integer))))
:invokes-debugger syntax-error
, :test
“‘
### syntax
(check-bnf (&key ((:whole whole?))) &rest def+)
=> result
## arguments and values:
whole := form, evaluated.
“‘lisp
#?(check-bnf (:whole no-such-var)
((dummy dummy)))
:signals (or error
warning ; for ccl
)
“‘
expects var for &whole.
when specified, header and footer is generated in error message.
“‘lisp
#?(let ((a "not-symbol"))
(check-bnf ()
((a symbol))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((a "not-symbol"))
(check-bnf (:whole ’(whole ("not-symbol")))
((a symbol))))
:invokes-debugger syntax-error
, :test
“‘
def := (clause+)+
clause := (var-spec spec+)
var-spec := [ name | (name name) ]
name := symbol, otherwise error.
“‘lisp
#?(check-bnf ()
(("not-symbol" dummy)))
:signals syntax-error
, :lazy
“‘
not evaluated.
“‘lisp
#?(check-bnf ()
(((intern "not evaluated") dummy)))
:signals syntax-error
, :lazy
“‘
NAME must not be a type name.
“‘lisp
#?(deftype type-name () ’symbol)
=> TYPE-NAME
“‘
“‘lisp
#?(check-bnf ()
((type-name ’symbol)))
:signals syntax-error
, :lazy
“‘
clause require one or more, otherwise syntax error.
“‘lisp
#?(check-bnf ())
:signals syntax-error
, :lazy
“‘
spec := [ type-specifier | bnf ]
bnf := [ name | list-bnf | or-form ]
list-bnf := (spec+)
or-form := (or spec+)
spec require one or more, otherwise error.
“‘lisp
#?(check-bnf ()
((dummy)))
:signals syntax-error
, :lazy
“‘
“‘lisp
#?(check-bnf ()
((dummy+ nil)))
:signals syntax-error
, :lazy
“‘
result := null
## affected by:
none
## side-effects:
none
## notes:
to check optional argument (e.g. &optional or &key), you can write like below.
“‘lisp
#?(let ((option))
(check-bnf ()
((option (or null symbol)))))
=> nil
“‘
“‘lisp
#?(let ((option ’symbol))
(check-bnf ()
((option (or null symbol)))))
=> nil
“‘
“‘lisp
#?(let ((function-name "not function-name"))
(check-bnf ()
((function-name (or name setf-name))
(name symbol)
(setf-name ((eql setf) name)))))
:invokes-debugger syntax-error
, :test
“‘
to check optional value in list, you can write like below.
“‘lisp
#?(let ((args ’(option and others)))
(check-bnf ()
((args (option? other*))
(option? (eql option))
(other* symbol))))
=> nil
“‘
“‘lisp
#?(let ((args ’(and others)))
(check-bnf ()
((args (option? other*))
(option? (eql option))
(other* symbol))))
=> nil
“‘
“‘lisp
#?(let ((args ’("not option nor other*" and others)))
(check-bnf ()
((args (option? other*))
(option? (eql option))
(other* symbol))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(LET (VAR)
(CHECK-BNF ()
((VAR (A* B*))
(A SYMBOL)
(B INTEGER))))
=> NIL
“‘
“‘lisp
#?(LET ((VAR ’(SYM)))
(CHECK-BNF ()
((VAR (A* B*))
(A SYMBOL)
(B INTEGER))))
=> NIL
“‘
“‘lisp
#?(LET ((VAR ’(SYM SYM)))
(CHECK-BNF ()
((VAR (A* B*))
(A SYMBOL)
(B INTEGER))))
=> NIL
“‘
“‘lisp
#?(LET ((VAR ’(SYM SYM 1)))
(CHECK-BNF ()
((VAR (A* B*))
(A SYMBOL)
(B INTEGER))))
=> NIL
“‘
“‘lisp
#?(LET ((VAR ’(SYM SYM 1 2)))
(CHECK-BNF ()
((VAR (A* B*))
(A SYMBOL)
(B INTEGER))))
=> NIL
“‘
“‘lisp
#?(LET ((VAR ’(SYM SYM "string")))
(CHECK-BNF ()
((VAR (A* B*))
(A SYMBOL)
(B INTEGER))))
:invokes-debugger SYNTAX-ERROR
, :test
“‘
Key value pair in heads.
“‘lisp
#?(LET ((ARGS ’(:KEY 1 :KEY 2 "doc")))
(CHECK-BNF ()
((ARGS (OPTION* DOC?))
(OPTION* KEYWORD INTEGER)
(DOC? STRING))))
=> NIL
“‘
“‘lisp
#?(LET ((ARGS ’(:KEY 1 :KEY 2)))
(CHECK-BNF ()
((ARGS (OPTION* DOC?))
(OPTION* KEYWORD INTEGER)
(DOC? STRING))))
=> NIL
“‘
“‘lisp
#?(LET ((ARGS ’(:KEY 1 :KEY 2 not-string)))
(CHECK-BNF ()
((ARGS (OPTION* DOC?))
(OPTION* KEYWORD INTEGER)
(DOC? STRING))))
:invokes-debugger syntax-error
, :test
“‘
## exceptional-situations:
every name should not conflicts cl symbol.
“‘lisp
#?(let ((list nil))
(check-bnf ()
((list list))))
=> unspecified
“‘
## example.
“‘lisp
#?(let ((var ’(symbol symbol)))
(check-bnf ()
((var (symbol symbol option*))
(option* keyword string))))
=> nil
“‘
“‘lisp
#?(let ((var ’(symbol symbol)))
(check-bnf ()
((var (symbol symbol option?))
(option? keyword))))
=> nil
“‘
“‘lisp
#?(let ((var ’(symbol symbol)))
(check-bnf ()
((var (symbol symbol required))
(required keyword))))
:invokes-debugger syntax-error
, :test
“‘
#### right side xxx*
“‘lisp
#?(let ((var ’(symbol)))
(check-bnf ()
((var (or string name*))
(name symbol))))
=> nil
“‘
“‘lisp
#?(let ((var "string"))
(check-bnf ()
((var (or string name*))
(name symbol))))
=> nil
“‘
“‘lisp
#?(let ((var ()))
(check-bnf ()
((var (or string name*))
(name symbol))))
=> nil
“‘
“‘lisp
#?(let ((var :not-list))
(check-bnf ()
((var (or string name*))
(name symbol))))
:invokes-debugger syntax-error
, :test
“‘
#### right side xxx?
“‘lisp
#?(let ((ll nil))
(check-bnf ()
((ll (var?))
(var symbol))))
=> nil
“‘
“‘lisp
#?(let ((ll ’(var)))
(check-bnf ()
((ll (var?))
(var symbol))))
=> nil
“‘
“‘lisp
#?(let ((ll ’(var too much)))
(check-bnf ()
((ll (var?))
(var symbol))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((ll "not list"))
(check-bnf ()
((ll (var?))
(var symbol))))
:invokes-debugger syntax-error
, :test
“‘
“‘lisp
#?(let ((ll ’("not symbol")))
(check-bnf ()
((ll (var?))
(var symbol))))
:invokes-debugger syntax-error
, :test
“‘
## Practical case examples.
#### deftype.
“‘lisp
#?(let ((name ’name)
(lambda-list ’())
(body ’("doc" t)))
(check-bnf ()
((name (and symbol (not (or keyword boolean)))))
((lambda-list list))
((body (doc? declaration* expression*))
(doc? string)
(declaration* ((eql declare) t*)))))
=> NIL
“‘
“‘lisp
#?(let ((body ’("doc" t)))
(check-bnf ()
((body (string? declaration* expression*))
(declaration* ((eql declare) t*)))))
=> NIL
“‘
## Tests
“‘lisp
#?(let ((ll "not-list"))
(check-bnf ()
((ll <lambda-list>))))
:invokes-debugger syntax-error
, :test
“‘
#### Support compound type specifier.
#### ISSUE: Right side expression may be type specifier accidentally?
#### e.g. (vector spec)
“‘lisp
#?(let ((index 3))
(check-bnf ()
((index (mod #.array-total-size-limit)))))
=> NIL
“‘
Next: Standalone methods, Previous: Macros, Up: Public Interface [Contents][Index]
Next: Conditions, Previous: Ordinary functions, Up: Public Interface [Contents][Index]
Next: Types, Previous: Standalone methods, Up: Public Interface [Contents][Index]
Initarg | Value |
---|---|
:format-control |
(quote nil)
:whole
This slot is read-only.
(quote nil)
:definitions
This slot is read-only.
Previous: Conditions, Up: Public Interface [Contents][Index]
# EXPRESSION
## description:
## compound type specifier kind:
## compound type specifier syntax:
## compound type specifier arguments:
## compound type specifier description:
Previous: Public Interface, Up: Definitions [Contents][Index]
Next: Ordinary functions, Previous: Special variables, Up: Internals [Contents][Index]
Next: Generic functions, Previous: Macros, Up: Internals [Contents][Index]
Collect definitions that related to THING from BNF
Return extended-marker if NAME has, otherwirse nil.
# PPRINT-CHECK-BNF
## description:
### syntax
(pprint-check-bnf stream exp)
=> result
## arguments and values:
stream :=
exp :=
result :=
## affected by:
## side-effects:
## notes:
## exceptional-situations:
## tests:
“‘lisp
#?(pprint-check-bnf nil ’(check-bnf))
:outputs "(CHECK-BNF)"
“‘
“‘lisp
#?(pprint-check-bnf nil ’(check-bnf nil))
:outputs "(CHECK-BNF ())"
“‘
“‘lisp
#?(pprint-check-bnf nil ’(check-bnf nil nil))
:outputs "(CHECK-BNF () ())"
“‘
“‘lisp
#?(pprint-check-bnf nil ’(check-bnf nil not-list))
=> unspecified
“‘
depending on implementation.
CLISP specific guard #2.
“‘lisp
#?(pprint-check-bnf nil ’(check-bnf ()
((a symbol))
((b string))))
:outputs "(CHECK-BNF ()
((A SYMBOL))
((B STRING)))"
“‘
“‘lisp
#?(pprint-check-bnf nil ’(check-bnf ()
((a symbol))
((b string))))
:outputs "(CHECK-BNF ()
((A SYMBOL))
((B STRING)))"
“‘
CLISP specific guard #3.
“‘lisp
#?(format nil "~<~:@_~:>" nil)
=> ""
, :test
“‘
“‘lisp
#?(pprint-check-bnf nil ’(check-bnf ()
((function-name (or name setf-name))
(name symbol)
(setf-name ((eql setf) name)))))
:outputs "(CHECK-BNF ()
((FUNCTION-NAME (OR NAME SETF-NAME))
(NAME SYMBOL)
(SETF-NAME ((EQL SETF) NAME))))"
“‘
“‘lisp
#?(PPRINT-CHECK-BNF NIL
’(CHECK-BNF ()
(A
B)))
:outputs "(CHECK-BNF ()
(A
B))"
“‘
Next: Conditions, Previous: Ordinary functions, Up: Internals [Contents][Index]
automatically generated reader method
Next: Structures, Previous: Generic functions, Up: Internals [Contents][Index]
Next: Classes, Previous: Conditions, Up: Internals [Contents][Index]
Next: Types, Previous: Structures, Up: Internals [Contents][Index]
funcallable-standard-object.
:definitions
This slot is read-only.
Previous: Definitions, Up: The check-bnf Reference Manual [Contents][Index]
Jump to: | *
+
<
A B C D E F G I L M P R S T W |
---|
Jump to: | *
+
<
A B C D E F G I L M P R S T W |
---|
Next: Data types, Previous: Functions, Up: Indexes [Contents][Index]
Jump to: | *
C D N S W |
---|
Jump to: | *
C D N S W |
---|
Jump to: | C D E F L M P S T V |
---|
Jump to: | C D E F L M P S T V |
---|