diff options
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | docs/src/cmdline.txt | 6 | ||||
-rw-r--r-- | pygments/lexers/_clbuiltins.py | 232 | ||||
-rw-r--r-- | pygments/lexers/_mapping.py | 4 | ||||
-rw-r--r-- | pygments/lexers/agile.py | 2 | ||||
-rw-r--r-- | pygments/lexers/functional.py | 182 | ||||
-rw-r--r-- | pygments/lexers/text.py | 62 | ||||
-rw-r--r-- | tests/examplefiles/type.lisp | 1202 |
8 files changed, 1683 insertions, 11 deletions
@@ -10,11 +10,13 @@ Version 0.9 * Erlang * ActionScript * Literate Haskell + * Common Lisp * Various assembly languages * Gettext catalogs * Squid configuration + * Debian control files + * MySQL-style SQL * MOOCode - * MySQL - Lexers improved: diff --git a/docs/src/cmdline.txt b/docs/src/cmdline.txt index 6cdec40e..5950d425 100644 --- a/docs/src/cmdline.txt +++ b/docs/src/cmdline.txt @@ -44,9 +44,9 @@ quote the option value in this case too, so that the shell doesn't split it). Since the ``-O`` option argument is split at commas and expects the split values to be of the form ``name=value``, you can't give an option value that contains -commas or equals signs. Therefore, an option ``-P`` is provided that works like -``-O`` but can only pass one option per ``-P``. Its value can then contain all -characters:: +commas or equals signs. Therefore, an option ``-P`` is provided (as of Pygments +0.9) that works like ``-O`` but can only pass one option per ``-P``. Its value +can then contain all characters:: $ pygmentize -P "heading=Pygments, the Python highlighter" ... diff --git a/pygments/lexers/_clbuiltins.py b/pygments/lexers/_clbuiltins.py new file mode 100644 index 00000000..0792798e --- /dev/null +++ b/pygments/lexers/_clbuiltins.py @@ -0,0 +1,232 @@ +# -*- coding: utf-8 -*- +""" + pygments.lexers._clbuiltins + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + ANSI Common Lisp builtins. + + :copyright: 2006-2007 by Matteo Sasso. + :license: BSD, see LICENSE for more details. +""" + +BUILTIN_FUNCTIONS = [ # 638 functions + '<', '<=', '=', '>', '>=', '-', '/', '/=', '*', '+', '1-', '1+', + 'abort', 'abs', 'acons', 'acos', 'acosh', 'add-method', 'adjoin', + 'adjustable-array-p', 'adjust-array', 'allocate-instance', + 'alpha-char-p', 'alphanumericp', 'append', 'apply', 'apropos', + 'apropos-list', 'aref', 'arithmetic-error-operands', + 'arithmetic-error-operation', 'array-dimension', 'array-dimensions', + 'array-displacement', 'array-element-type', 'array-has-fill-pointer-p', + 'array-in-bounds-p', 'arrayp', 'array-rank', 'array-row-major-index', + 'array-total-size', 'ash', 'asin', 'asinh', 'assoc', 'assoc-if', + 'assoc-if-not', 'atan', 'atanh', 'atom', 'bit', 'bit-and', 'bit-andc1', + 'bit-andc2', 'bit-eqv', 'bit-ior', 'bit-nand', 'bit-nor', 'bit-not', + 'bit-orc1', 'bit-orc2', 'bit-vector-p', 'bit-xor', 'boole', + 'both-case-p', 'boundp', 'break', 'broadcast-stream-streams', + 'butlast', 'byte', 'byte-position', 'byte-size', 'caaaar', 'caaadr', + 'caaar', 'caadar', 'caaddr', 'caadr', 'caar', 'cadaar', 'cadadr', + 'cadar', 'caddar', 'cadddr', 'caddr', 'cadr', 'call-next-method', 'car', + 'cdaaar', 'cdaadr', 'cdaar', 'cdadar', 'cdaddr', 'cdadr', 'cdar', + 'cddaar', 'cddadr', 'cddar', 'cdddar', 'cddddr', 'cdddr', 'cddr', 'cdr', + 'ceiling', 'cell-error-name', 'cerror', 'change-class', 'char', 'char<', + 'char<=', 'char=', 'char>', 'char>=', 'char/=', 'character', + 'characterp', 'char-code', 'char-downcase', 'char-equal', + 'char-greaterp', 'char-int', 'char-lessp', 'char-name', + 'char-not-equal', 'char-not-greaterp', 'char-not-lessp', 'char-upcase', + 'cis', 'class-name', 'class-of', 'clear-input', 'clear-output', + 'close', 'clrhash', 'code-char', 'coerce', 'compile', + 'compiled-function-p', 'compile-file', 'compile-file-pathname', + 'compiler-macro-function', 'complement', 'complex', 'complexp', + 'compute-applicable-methods', 'compute-restarts', 'concatenate', + 'concatenated-stream-streams', 'conjugate', 'cons', 'consp', + 'constantly', 'constantp', 'continue', 'copy-alist', 'copy-list', + 'copy-pprint-dispatch', 'copy-readtable', 'copy-seq', 'copy-structure', + 'copy-symbol', 'copy-tree', 'cos', 'cosh', 'count', 'count-if', + 'count-if-not', 'decode-float', 'decode-universal-time', 'delete', + 'delete-duplicates', 'delete-file', 'delete-if', 'delete-if-not', + 'delete-package', 'denominator', 'deposit-field', 'describe', + 'describe-object', 'digit-char', 'digit-char-p', 'directory', + 'directory-namestring', 'disassemble', 'documentation', 'dpb', + 'dribble', 'echo-stream-input-stream', 'echo-stream-output-stream', + 'ed', 'eighth', 'elt', 'encode-universal-time', 'endp', + 'enough-namestring', 'ensure-directories-exist', + 'ensure-generic-function', 'eq', 'eql', 'equal', 'equalp', 'error', + 'eval', 'evenp', 'every', 'exp', 'export', 'expt', 'fboundp', + 'fceiling', 'fdefinition', 'ffloor', 'fifth', 'file-author', + 'file-error-pathname', 'file-length', 'file-namestring', + 'file-position', 'file-string-length', 'file-write-date', + 'fill', 'fill-pointer', 'find', 'find-all-symbols', 'find-class', + 'find-if', 'find-if-not', 'find-method', 'find-package', 'find-restart', + 'find-symbol', 'finish-output', 'first', 'float', 'float-digits', + 'floatp', 'float-precision', 'float-radix', 'float-sign', 'floor', + 'fmakunbound', 'force-output', 'format', 'fourth', 'fresh-line', + 'fround', 'ftruncate', 'funcall', 'function-keywords', + 'function-lambda-expression', 'functionp', 'gcd', 'gensym', 'gentemp', + 'get', 'get-decoded-time', 'get-dispatch-macro-character', 'getf', + 'gethash', 'get-internal-real-time', 'get-internal-run-time', + 'get-macro-character', 'get-output-stream-string', 'get-properties', + 'get-setf-expansion', 'get-universal-time', 'graphic-char-p', + 'hash-table-count', 'hash-table-p', 'hash-table-rehash-size', + 'hash-table-rehash-threshold', 'hash-table-size', 'hash-table-test', + 'host-namestring', 'identity', 'imagpart', 'import', + 'initialize-instance', 'input-stream-p', 'inspect', + 'integer-decode-float', 'integer-length', 'integerp', + 'interactive-stream-p', 'intern', 'intersection', + 'invalid-method-error', 'invoke-debugger', 'invoke-restart', + 'invoke-restart-interactively', 'isqrt', 'keywordp', 'last', 'lcm', + 'ldb', 'ldb-test', 'ldiff', 'length', 'lisp-implementation-type', + 'lisp-implementation-version', 'list', 'list*', 'list-all-packages', + 'listen', 'list-length', 'listp', 'load', + 'load-logical-pathname-translations', 'log', 'logand', 'logandc1', + 'logandc2', 'logbitp', 'logcount', 'logeqv', 'logical-pathname', + 'logical-pathname-translations', 'logior', 'lognand', 'lognor', + 'lognot', 'logorc1', 'logorc2', 'logtest', 'logxor', 'long-site-name', + 'lower-case-p', 'machine-instance', 'machine-type', 'machine-version', + 'macroexpand', 'macroexpand-1', 'macro-function', 'make-array', + 'make-broadcast-stream', 'make-concatenated-stream', 'make-condition', + 'make-dispatch-macro-character', 'make-echo-stream', 'make-hash-table', + 'make-instance', 'make-instances-obsolete', 'make-list', + 'make-load-form', 'make-load-form-saving-slots', 'make-package', + 'make-pathname', 'make-random-state', 'make-sequence', 'make-string', + 'make-string-input-stream', 'make-string-output-stream', 'make-symbol', + 'make-synonym-stream', 'make-two-way-stream', 'makunbound', 'map', + 'mapc', 'mapcan', 'mapcar', 'mapcon', 'maphash', 'map-into', 'mapl', + 'maplist', 'mask-field', 'max', 'member', 'member-if', 'member-if-not', + 'merge', 'merge-pathnames', 'method-combination-error', + 'method-qualifiers', 'min', 'minusp', 'mismatch', 'mod', + 'muffle-warning', 'name-char', 'namestring', 'nbutlast', 'nconc', + 'next-method-p', 'nintersection', 'ninth', 'no-applicable-method', + 'no-next-method', 'not', 'notany', 'notevery', 'nreconc', 'nreverse', + 'nset-difference', 'nset-exclusive-or', 'nstring-capitalize', + 'nstring-downcase', 'nstring-upcase', 'nsublis', 'nsubst', 'nsubst-if', + 'nsubst-if-not', 'nsubstitute', 'nsubstitute-if', 'nsubstitute-if-not', + 'nth', 'nthcdr', 'null', 'numberp', 'numerator', 'nunion', 'oddp', + 'open', 'open-stream-p', 'output-stream-p', 'package-error-package', + 'package-name', 'package-nicknames', 'packagep', + 'package-shadowing-symbols', 'package-used-by-list', 'package-use-list', + 'pairlis', 'parse-integer', 'parse-namestring', 'pathname', + 'pathname-device', 'pathname-directory', 'pathname-host', + 'pathname-match-p', 'pathname-name', 'pathnamep', 'pathname-type', + 'pathname-version', 'peek-char', 'phase', 'plusp', 'position', + 'position-if', 'position-if-not', 'pprint', 'pprint-dispatch', + 'pprint-fill', 'pprint-indent', 'pprint-linear', 'pprint-newline', + 'pprint-tab', 'pprint-tabular', 'prin1', 'prin1-to-string', 'princ', + 'princ-to-string', 'print', 'print-object', 'probe-file', 'proclaim', + 'provide', 'random', 'random-state-p', 'rassoc', 'rassoc-if', + 'rassoc-if-not', 'rational', 'rationalize', 'rationalp', 'read', + 'read-byte', 'read-char', 'read-char-no-hang', 'read-delimited-list', + 'read-from-string', 'read-line', 'read-preserving-whitespace', + 'read-sequence', 'readtable-case', 'readtablep', 'realp', 'realpart', + 'reduce', 'reinitialize-instance', 'rem', 'remhash', 'remove', + 'remove-duplicates', 'remove-if', 'remove-if-not', 'remove-method', + 'remprop', 'rename-file', 'rename-package', 'replace', 'require', + 'rest', 'restart-name', 'revappend', 'reverse', 'room', 'round', + 'row-major-aref', 'rplaca', 'rplacd', 'sbit', 'scale-float', 'schar', + 'search', 'second', 'set', 'set-difference', + 'set-dispatch-macro-character', 'set-exclusive-or', + 'set-macro-character', 'set-pprint-dispatch', 'set-syntax-from-char', + 'seventh', 'shadow', 'shadowing-import', 'shared-initialize', + 'short-site-name', 'signal', 'signum', 'simple-bit-vector-p', + 'simple-condition-format-arguments', 'simple-condition-format-control', + 'simple-string-p', 'simple-vector-p', 'sin', 'sinh', 'sixth', 'sleep', + 'slot-boundp', 'slot-exists-p', 'slot-makunbound', 'slot-missing', + 'slot-unbound', 'slot-value', 'software-type', 'software-version', + 'some', 'sort', 'special-operator-p', 'sqrt', 'stable-sort', + 'standard-char-p', 'store-value', 'stream-element-type', + 'stream-error-stream', 'stream-external-format', 'streamp', 'string', + 'string<', 'string<=', 'string=', 'string>', 'string>=', 'string/=', + 'string-capitalize', 'string-downcase', 'string-equal', + 'string-greaterp', 'string-left-trim', 'string-lessp', + 'string-not-equal', 'string-not-greaterp', 'string-not-lessp', + 'stringp', 'string-right-trim', 'string-trim', 'string-upcase', + 'sublis', 'subseq', 'subsetp', 'subst', 'subst-if', 'subst-if-not', + 'substitute', 'substitute-if', 'substitute-if-not', 'subtypep','svref', + 'sxhash', 'symbol-function', 'symbol-name', 'symbolp', 'symbol-package', + 'symbol-plist', 'symbol-value', 'synonym-stream-symbol', 'syntax:', + 'tailp', 'tan', 'tanh', 'tenth', 'terpri', 'third', + 'translate-logical-pathname', 'translate-pathname', 'tree-equal', + 'truename', 'truncate', 'two-way-stream-input-stream', + 'two-way-stream-output-stream', 'type-error-datum', + 'type-error-expected-type', 'type-of', 'typep', 'unbound-slot-instance', + 'unexport', 'unintern', 'union', 'unread-char', 'unuse-package', + 'update-instance-for-different-class', + 'update-instance-for-redefined-class', 'upgraded-array-element-type', + 'upgraded-complex-part-type', 'upper-case-p', 'use-package', + 'user-homedir-pathname', 'use-value', 'values', 'values-list', 'vector', + 'vectorp', 'vector-pop', 'vector-push', 'vector-push-extend', 'warn', + 'wild-pathname-p', 'write', 'write-byte', 'write-char', 'write-line', + 'write-sequence', 'write-string', 'write-to-string', 'yes-or-no-p', + 'y-or-n-p', 'zerop', +] + +SPECIAL_FORMS = [ + 'block', 'catch', 'declare', 'eval-when', 'flet', 'function', 'go', 'if', + 'labels', 'lambda', 'let', 'let*', 'load-time-value', 'locally', 'macrolet', + 'multiple-value-call', 'multiple-value-prog1', 'progn', 'progv', 'quote', + 'return-from', 'setq', 'symbol-macrolet', 'tagbody', 'the', 'throw', + 'unwind-protect', +] + +MACROS = [ + 'and', 'assert', 'call-method', 'case', 'ccase', 'check-type', 'cond', + 'ctypecase', 'decf', 'declaim', 'defclass', 'defconstant', 'defgeneric', + 'define-compiler-macro', 'define-condition', 'define-method-combination', + 'define-modify-macro', 'define-setf-expander', 'define-symbol-macro', + 'defmacro', 'defmethod', 'defpackage', 'defparameter', 'defsetf', + 'defstruct', 'deftype', 'defun', 'defvar', 'destructuring-bind', 'do', + 'do*', 'do-all-symbols', 'do-external-symbols', 'dolist', 'do-symbols', + 'dotimes', 'ecase', 'etypecase', 'formatter', 'handler-bind', + 'handler-case', 'ignore-errors', 'incf', 'in-package', 'lambda', 'loop', + 'loop-finish', 'make-method', 'multiple-value-bind', 'multiple-value-list', + 'multiple-value-setq', 'nth-value', 'or', 'pop', + 'pprint-exit-if-list-exhausted', 'pprint-logical-block', 'pprint-pop', + 'print-unreadable-object', 'prog', 'prog*', 'prog1', 'prog2', 'psetf', + 'psetq', 'push', 'pushnew', 'remf', 'restart-bind', 'restart-case', + 'return', 'rotatef', 'setf', 'shiftf', 'step', 'time', 'trace', 'typecase', + 'unless', 'untrace', 'when', 'with-accessors', 'with-compilation-unit', + 'with-condition-restarts', 'with-hash-table-iterator', + 'with-input-from-string', 'with-open-file', 'with-open-stream', + 'with-output-to-string', 'with-package-iterator', 'with-simple-restart', + 'with-slots', 'with-standard-io-syntax', +] + +LAMBDA_LIST_KEYWORDS = [ + '&allow-other-keys', '&aux', '&body', '&environment', '&key', '&optional', + '&rest', '&whole', +] + +DECLARATIONS = [ + 'dynamic-extent', 'ignore', 'optimize', 'ftype', 'inline', 'special', + 'ignorable', 'notinline', 'type', +] + +BUILTIN_TYPES = [ + 'atom', 'boolean', 'base-char', 'base-string', 'bignum', 'bit', + 'compiled-function', 'extended-char', 'fixnum', 'keyword', 'nil', + 'signed-byte', 'short-float', 'single-float', 'double-float', 'long-float', + 'simple-array', 'simple-base-string', 'simple-bit-vector', 'simple-string', + 'simple-vector', 'standard-char', 'unsigned-byte', + + # Condition Types + 'arithmetic-error', 'cell-error', 'condition', 'control-error', + 'division-by-zero', 'end-of-file', 'error', 'file-error', + 'floating-point-inexact', 'floating-point-overflow', + 'floating-point-underflow', 'floating-point-invalid-operation', + 'parse-error', 'package-error', 'print-not-readable', 'program-error', + 'reader-error', 'serious-condition', 'simple-condition', 'simple-error', + 'simple-type-error', 'simple-warning', 'stream-error', 'storage-condition', + 'style-warning', 'type-error', 'unbound-variable', 'unbound-slot', + 'undefined-function', 'warning', +] + +BUILTIN_CLASSES = [ + 'array', 'broadcast-stream', 'bit-vector', 'built-in-class', 'character', + 'class', 'complex', 'concatenated-stream', 'cons', 'echo-stream', + 'file-stream', 'float', 'function', 'generic-function', 'hash-table', + 'integer', 'list', 'logical-pathname', 'method-combination', 'method', + 'null', 'number', 'package', 'pathname', 'ratio', 'rational', 'readtable', + 'real', 'random-state', 'restart', 'sequence', 'standard-class', + 'standard-generic-function', 'standard-method', 'standard-object', + 'string-stream', 'stream', 'string', 'structure-class', 'structure-object', + 'symbol', 'synonym-stream', 't', 'two-way-stream', 'vector', +] diff --git a/pygments/lexers/_mapping.py b/pygments/lexers/_mapping.py index 7a8eae3f..3691377c 100644 --- a/pygments/lexers/_mapping.py +++ b/pygments/lexers/_mapping.py @@ -25,6 +25,7 @@ LEXERS = { 'CLexer': ('pygments.lexers.compiled', 'C', ('c',), ('*.c', '*.h'), ('text/x-chdr', 'text/x-csrc')), 'CObjdumpLexer': ('pygments.lexers.asm', 'c-objdump', ('c-objdump',), ('*.c-objdump',), ('text/x-c-objdump',)), 'CSharpLexer': ('pygments.lexers.dotnet', 'C#', ('csharp', 'c#'), ('*.cs',), ('text/x-csharp',)), + 'CommonLispLexer': ('pygments.lexers.functional', 'Common Lisp', ('common-lisp', 'cl'), ('*.cl', '*.lisp', '*.el'), ('text/x-common-lisp',)), 'CppLexer': ('pygments.lexers.compiled', 'C++', ('cpp', 'c++'), ('*.cpp', '*.hpp', '*.c++', '*.h++'), ('text/x-c++hdr', 'text/x-c++src')), 'CppObjdumpLexer': ('pygments.lexers.asm', 'cpp-objdump', ('cpp-objdump', 'c++-objdumb', 'cxx-objdump'), ('*.cpp-objdump', '*.c++-objdump', '*.cxx-objdump'), ('text/x-cpp-objdump',)), 'CssDjangoLexer': ('pygments.lexers.templates', 'CSS+Django/Jinja', ('css+django', 'css+jinja'), (), ('text/css+django', 'text/css+jinja')), @@ -35,6 +36,7 @@ LEXERS = { 'CssSmartyLexer': ('pygments.lexers.templates', 'CSS+Smarty', ('css+smarty',), (), ('text/css+smarty',)), 'DLexer': ('pygments.lexers.compiled', 'D', ('d',), ('*.d', '*.di'), ('text/x-dsrc',)), 'DObjdumpLexer': ('pygments.lexers.asm', 'd-objdump', ('d-objdump',), ('*.d-objdump',), ('text/x-d-objdump',)), + 'DebianControlLexer': ('pygments.lexers.text', 'Debian Control file', ('control',), ('control',), ()), 'DelphiLexer': ('pygments.lexers.compiled', 'Delphi', ('delphi', 'pas', 'pascal', 'objectpascal'), ('*.pas',), ('text/x-pascal',)), 'DiffLexer': ('pygments.lexers.text', 'Diff', ('diff',), ('*.diff', '*.patch'), ('text/x-diff', 'text/x-patch')), 'DjangoLexer': ('pygments.lexers.templates', 'Django/Jinja', ('django', 'jinja'), (), ('application/x-django-templating', 'application/x-jinja')), @@ -88,7 +90,7 @@ LEXERS = { 'PerlLexer': ('pygments.lexers.agile', 'Perl', ('perl', 'pl'), ('*.pl', '*.pm'), ('text/x-perl', 'application/x-perl')), 'PhpLexer': ('pygments.lexers.web', 'PHP', ('php', 'php3', 'php4', 'php5'), ('*.php', '*.php[345]'), ('text/x-php',)), 'PythonConsoleLexer': ('pygments.lexers.agile', 'Python console session', ('pycon',), (), ('text/x-python-doctest',)), - 'PythonLexer': ('pygments.lexers.agile', 'Python', ('python', 'py'), ('*.py', '*.pyw', '*.sc'), ('text/x-python', 'application/x-python')), + 'PythonLexer': ('pygments.lexers.agile', 'Python', ('python', 'py'), ('*.py', '*.pyw', '*.sc', 'SConstruct', 'SConscript'), ('text/x-python', 'application/x-python')), 'PythonTracebackLexer': ('pygments.lexers.agile', 'Python Traceback', ('pytb',), ('*.pytb',), ('text/x-python-traceback',)), 'RawTokenLexer': ('pygments.lexers.special', 'Raw token data', ('raw',), ('*.raw',), ('application/x-pygments-tokens',)), 'RedcodeLexer': ('pygments.lexers.other', 'Redcode', ('redcode',), ('*.cw',), ()), diff --git a/pygments/lexers/agile.py b/pygments/lexers/agile.py index d1dc0d30..30adea9a 100644 --- a/pygments/lexers/agile.py +++ b/pygments/lexers/agile.py @@ -41,7 +41,7 @@ class PythonLexer(RegexLexer): name = 'Python' aliases = ['python', 'py'] - filenames = ['*.py', '*.pyw', '*.sc'] # .sc is for SCons + filenames = ['*.py', '*.pyw', '*.sc', 'SConstruct', 'SConscript'] mimetypes = ['text/x-python', 'application/x-python'] tokens = { diff --git a/pygments/lexers/functional.py b/pygments/lexers/functional.py index 626910a3..c2305f68 100644 --- a/pygments/lexers/functional.py +++ b/pygments/lexers/functional.py @@ -6,7 +6,7 @@ Lexers for functional languages. :copyright: 2006-2007 by Georg Brandl, Marek Kubica, - Adam Blinkinsop <blinks@acm.org>. + Adam Blinkinsop <blinks@acm.org>, Matteo Sasso. :license: BSD, see LICENSE for more details. """ @@ -19,10 +19,10 @@ except NameError: from pygments.lexer import Lexer, RegexLexer, bygroups, using, this, include, \ do_insertions from pygments.token import Text, Comment, Operator, Keyword, Name, \ - String, Number, Punctuation + String, Number, Punctuation, Literal -__all__ = ['SchemeLexer', 'HaskellLexer', 'LiterateHaskellLexer', +__all__ = ['SchemeLexer', 'CommonLispLexer', 'HaskellLexer', 'LiterateHaskellLexer', 'OcamlLexer', 'ErlangLexer'] @@ -154,6 +154,182 @@ class SchemeLexer(RegexLexer): } +class CommonLispLexer(RegexLexer): + """ + A Common Lisp lexer. + + *New in Pygments 0.9.* + """ + name = 'Common Lisp' + aliases = ['common-lisp', 'cl'] + filenames = ['*.cl', '*.lisp', '*.el'] # use for Elisp too + mimetypes = ['text/x-common-lisp'] + + flags = re.IGNORECASE | re.MULTILINE + + ### couple of useful regexes + + # characters that are not macro-characters and can be used to begin a symbol + nonmacro = r'\\.|[a-zA-Z0-9!$%&*+-/<=>?@\[\]^_{}~]' + constituent = nonmacro + '|[#.:]' + terminated = r'(?=[ "()\'\n,;`])' # whitespace or terminating macro characters + + ### symbol token, reverse-engineered from hyperspec + # Take a deep breath... + symbol = r'(\|[^|]+\||(?:%s)(?:%s)*)' % (nonmacro, constituent) + + def __init__(self, **options): + from pygments.lexers._clbuiltins import BUILTIN_FUNCTIONS, \ + SPECIAL_FORMS, MACROS, LAMBDA_LIST_KEYWORDS, DECLARATIONS, \ + BUILTIN_TYPES, BUILTIN_CLASSES + self.builtin_function = BUILTIN_FUNCTIONS + self.special_forms = SPECIAL_FORMS + self.macros = MACROS + self.lambda_list_keywords = LAMBDA_LIST_KEYWORDS + self.declarations = DECLARATIONS + self.builtin_types = BUILTIN_TYPES + self.builtin_classes = BUILTIN_CLASSES + RegexLexer.__init__(self, **options) + + def get_tokens_unprocessed(self, text): + stack = ['root'] + for index, token, value in RegexLexer.get_tokens_unprocessed(self, text, stack): + if token is Name.Variable: + if value in self.builtin_function: + yield index, Name.Builtin, value + continue + if value in self.special_forms: + yield index, Keyword, value + continue + if value in self.macros: + yield index, Name.Builtin, value + continue + if value in self.lambda_list_keywords: + yield index, Keyword, value + continue + if value in self.declarations: + yield index, Keyword, value + continue + if value in self.builtin_types: + yield index, Keyword.Type, value + continue + if value in self.builtin_classes: + yield index, Name.Class, value + continue + yield index, token, value + + tokens = { + 'root' : [ + ('', Text, 'body'), + ], + 'multiline-comment' : [ + (r'#\|', Comment.Multiline, '#push'), # (cf. Hyperspec 2.4.8.19) + (r'\|#', Comment.Multiline, '#pop'), + (r'[^|#]+', Comment.Multiline), + (r'[|#]', Comment.Multiline), + ], + 'commented-form' : [ + (r'\(', Comment.Preproc, '#push'), + (r'\)', Comment.Preproc, '#pop'), + (r'[^()]+', Comment.Preproc), + ], + 'body' : [ + # whitespace + (r'\s+', Text), + + # single-line comment + (r';.*$', Comment.Single), + + # multi-line comment + (r'#\|', Comment.Multiline, 'multiline-comment'), + + # encoding comment (?) + (r'#\d*Y.*$', Comment.Special), + + # strings and characters + (r'"(\\.|[^"])*"', String), + # quoting + (r":" + symbol, String.Symbol), + (r"'" + symbol, String.Symbol), + (r"'", Operator), + (r"`", Operator), + + # decimal numbers + (r'[-+]?\d+\.?' + terminated, Number.Integer), + (r'[-+]?\d+/\d+' + terminated, Number), + (r'[-+]?(\d*\.\d+([defls][-+]?\d+)?|\d+(\.\d*)?[defls][-+]?\d+)' \ + + terminated, Number.Float), + + # sharpsign strings and characters + (r"#\\." + terminated, String.Char), + (r"#\\" + symbol, String.Char), + + # vector + (r'#\(', Operator, 'body'), + + # bitstring + (r'#\d*\*[01]*', Literal.Other), + + # uninterned symbol + (r'#:' + symbol, String.Symbol), + + # read-time and load-time evaluation + (r'#[.,]', Operator), + + # function shorthand + (r'#\'', Name.Function), + + # binary rational + (r'#[bB][+-]?[01]+(/[01]+)?', Number), + + # octal rational + (r'#[oO][+-]?[0-7]+(/[0-7]+)?', Number.Oct), + + # hex rational + (r'#[xX][+-]?[0-9a-fA-F]+(/[0-9a-fA-F]+)?', Number.Hex), + + # radix rational + (r'#\d+[rR][+-]?[0-9a-zA-Z]+(/[0-9a-zA-Z]+)?', Number), + + # complex + (r'(#[cC])(\()', bygroups(Number, Punctuation), 'body'), + + # array + (r'(#\d+[aA])(\()', bygroups(Literal.Other, Punctuation), 'body'), + + # structure + (r'(#[sS])(\()', bygroups(Literal.Other, Punctuation), 'body'), + + # path + (r'#[pP]?"(\\.|[^"])*"', Literal.Other), + + # reference + (r'#\d+=', Operator), + (r'#\d+#', Operator), + + # read-time comment + (r'#+nil' + terminated + '\s*\(', Comment.Preproc, 'commented-form'), + + # read-time conditional + (r'#[+-]', Operator), + + # special operators that should have been parsed already + (r'(,@|,|\.)', Operator), + + # special constants + (r'(t|nil)' + terminated, Name.Constant), + + # functions and variables + (r'\*' + symbol + '\*', Name.Variable.Global), + (symbol, Name.Variable), + + # parentheses + (r'\(', Punctuation, 'body'), + (r'\)', Punctuation, '#pop'), + ], + } + + class HaskellLexer(RegexLexer): """ A Haskell lexer based on the lexemes defined in the Haskell 98 Report. diff --git a/pygments/lexers/text.py b/pygments/lexers/text.py index c4422a2f..2b18cf2d 100644 --- a/pygments/lexers/text.py +++ b/pygments/lexers/text.py @@ -8,7 +8,9 @@ :copyright: 2006-2007 by Armin Ronacher, Georg Brandl, Tim Hatch <tim@timhatch.com>, Ronny Pfannschmidt, - Dennis Kaarsemaker. + Dennis Kaarsemaker, + Kumar Appaiah <akumar@ee.iitm.ac.in>, + Varun Hiremath <varunhiremath@gmail.com>. :license: BSD, see LICENSE for more details. """ @@ -30,7 +32,7 @@ from pygments.util import get_bool_opt __all__ = ['IniLexer', 'SourcesListLexer', 'MakefileLexer', 'DiffLexer', 'IrcLogsLexer', 'TexLexer', 'GroffLexer', 'ApacheConfLexer', 'BBCodeLexer', 'MoinWikiLexer', 'RstLexer', 'VimLexer', - 'GettextLexer', 'SquidConfLexer'] + 'GettextLexer', 'SquidConfLexer', 'DebianControlLexer'] class IniLexer(RegexLexer): @@ -847,3 +849,59 @@ class SquidConfLexer(RegexLexer): (r'.*', Comment, '#pop'), ], } + + +class DebianControlLexer(RegexLexer): + """ + Lexer for Debian ``control`` files and ``apt-cache show <pkg>`` outputs. + + *New in Pygments 0.9.* + """ + name = 'Debian Control file' + aliases = ['control'] + filenames = ['control'] + + tokens = { + 'root': [ + (r'^(Description)', Keyword, 'description'), + (r'^(Maintainer)(:\s*)', bygroups(Keyword, Text), 'maintainer'), + (r'^((Build-)?Depends)', Keyword, 'depends'), + (r'^((?:Python-)?Version)(:\s*)([^\s]+)$', + bygroups(Keyword, Text, Number)), + (r'^((?:Installed-)?Size)(:\s*)([^\s]+)$', + bygroups(Keyword, Text, Number)), + (r'^(MD5Sum|SHA1|SHA256)(:\s*)([^\s]+)$', + bygroups(Keyword, Text, Number)), + (r'^([a-zA-Z\-0-9\.]*?)(:\s*)(.*?)$', + bygroups(Keyword, Whitespace, String)), + ], + 'maintainer': [ + (r'<[^>]+>', Generic.Strong), + (r'<[^>]+>$', Generic.Strong, '#pop'), + (r',\n?', Text), + (r'.', Text), + ], + 'description': [ + (r'(.*)(Homepage)(: )([^\s]+)', bygroups(Text, String, Name, Name.Class)), + (r':.*\n', Generic.Strong), + (r' .*\n', Text), + ('', Text, '#pop'), + ], + 'depends': [ + (r':\s*', Text), + (r'(\$)(\{)(\w+\s*:\s*\w+)', bygroups(Operator, Text, Name.Entity)), + (r'\(', Text, 'depend_vers'), + (r',', Text), + (r'\|', Operator), + (r'[\s]+', Text), + (r'[}\)]\s*$', Text, '#pop'), + (r'[}]', Text), + (r'[^,]$', Name.Function, '#pop'), + (r'([\+\.a-zA-Z0-9-][\s\n]*)', Name.Function), + ], + 'depend_vers': [ + (r'\),', Text, '#pop'), + (r'\)[^,]', Text, '#pop:2'), + (r'([><=]+)(\s*)([^\)]+)', bygroups(Operator, Text, Number)) + ] + } diff --git a/tests/examplefiles/type.lisp b/tests/examplefiles/type.lisp new file mode 100644 index 00000000..9c769379 --- /dev/null +++ b/tests/examplefiles/type.lisp @@ -0,0 +1,1202 @@ +;;;; TYPEP und Verwandtes +;;;; Michael Stoll, 21. 10. 1988 +;;;; Bruno Haible, 10.6.1989 +;;;; Sam Steingold 2000-2005 + +;;; Datenstrukturen für TYPEP: +;;; - Ein Type-Specifier-Symbol hat auf seiner Propertyliste unter dem +;;; Indikator SYS::TYPE-SYMBOL eine Funktion von einem Argument, die +;;; testet, ob ein Objekt vom richtigen Typ ist. +;;; - Ein Symbol, das eine Type-Specifier-Liste beginnen kann, hat auf seiner +;;; Propertyliste unter dem Indikator SYS::TYPE-LIST eine Funktion von +;;; einem Argument für das zu testende Objekt und zusätzlichen Argumenten +;;; für die Listenelemente. +;;; - Ein Symbol, das als Typmacro definiert wurde, hat auf seiner Property- +;;; liste unter dem Indikator SYSTEM::DEFTYPE-EXPANDER den zugehörigen +;;; Expander: eine Funktion, die den zu expandierenden Type-Specifier (eine +;;; mindestens einelementige Liste) als Argument bekommt. + +(in-package "EXT") +(export '(type-expand)) +(in-package "SYSTEM") + +; vorläufig, solange bis clos.lisp geladen wird: +(eval-when (eval) + (predefun clos::built-in-class-p (object) (declare (ignore object)) nil)) +(unless (fboundp 'clos::class-name) + (defun clos::class-name (c) (declare (ignore c)) nil) +) + +(defun typespec-error (fun type) + (error-of-type 'error + (TEXT "~S: invalid type specification ~S") + fun type +) ) + +;; ============================================================================ + +;; return the CLOS class named by TYPESPEC or NIL +(defun clos-class (typespec) + (let ((cc (get typespec 'CLOS::CLOSCLASS))) + (when (and cc (clos::defined-class-p cc) (eq (clos:class-name cc) typespec)) + cc))) + +;;; TYPEP, CLTL S. 72, S. 42-51 +(defun typep (x y &optional env &aux f) ; x = Objekt, y = Typ + (declare (ignore env)) + (setq y (expand-deftype y)) + (cond + ((symbolp y) + (cond ((setq f (get y 'TYPE-SYMBOL)) (funcall f x)) + ((setq f (get y 'TYPE-LIST)) (funcall f x)) + ((setq f (get y 'DEFSTRUCT-DESCRIPTION)) (ds-typep x y f)) + ((setq f (clos-class y)) + ; It's not worth handling structure classes specially here. + (clos::typep-class x f)) + (t (typespec-error 'typep y)) + ) ) + ((and (consp y) (symbolp (first y))) + (cond + ((and (eq (first y) 'SATISFIES) (eql (length y) 2)) + (unless (symbolp (second y)) + (error-of-type 'error + (TEXT "~S: argument to SATISFIES must be a symbol: ~S") + 'typep (second y) + ) ) + (if (funcall (symbol-function (second y)) x) t nil) + ) + ((eq (first y) 'MEMBER) + (if (member x (rest y)) t nil) + ) + ((and (eq (first y) 'EQL) (eql (length y) 2)) + (eql x (second y)) + ) + ((and (eq (first y) 'NOT) (eql (length y) 2)) + (not (typep x (second y))) + ) + ((eq (first y) 'AND) + (dolist (type (rest y) t) + (unless (typep x type) (return nil)) + ) ) + ((eq (first y) 'OR) + (dolist (type (rest y) nil) + (when (typep x type) (return t)) + ) ) + ((setq f (get (first y) 'TYPE-LIST)) (apply f x (rest y))) + (t (typespec-error 'typep y)) + ) ) + ((clos::defined-class-p y) (clos::typep-class x y)) + ((clos::eql-specializer-p y) (eql x (clos::eql-specializer-singleton y))) + ((encodingp y) (charset-typep x y)) + (t (typespec-error 'typep y)) +) ) + +;; ---------------------------------------------------------------------------- + +;; UPGRADED-ARRAY-ELEMENT-TYPE is a lattice homomorphism, see +;; ANSI CL 15.1.2.1. +(defun upgraded-array-element-type (type &optional environment) + (declare (ignore environment)) + ;; see array.d + (case type + ((BIT) 'BIT) + ((CHARACTER) 'CHARACTER) + ((T) 'T) + ((NIL) 'NIL) + (t (if (subtypep type 'NIL) + 'NIL + (multiple-value-bind (low high) (sys::subtype-integer type) + ; Es gilt (or (null low) (subtypep type `(INTEGER ,low ,high))) + (if (and (integerp low) (not (minusp low)) (integerp high)) + (let ((l (integer-length high))) + ; Es gilt (subtypep type `(UNSIGNED-BYTE ,l)) + (cond ((<= l 1) 'BIT) + ((<= l 2) '(UNSIGNED-BYTE 2)) + ((<= l 4) '(UNSIGNED-BYTE 4)) + ((<= l 8) '(UNSIGNED-BYTE 8)) + ((<= l 16) '(UNSIGNED-BYTE 16)) + ((<= l 32) '(UNSIGNED-BYTE 32)) + (t 'T))) + (if (subtypep type 'CHARACTER) + 'CHARACTER + 'T))))))) + +;; ---------------------------------------------------------------------------- + +;; UPGRADED-COMPLEX-PART-TYPE is a lattice homomorphism, see +;; HyperSpec/Body/fun_complex.html and HyperSpec/Body/syscla_complex.html, +;; and an idempotent. Therefore +;; (subtypep (upgraded-complex-part-type T1) (upgraded-complex-part-type T2)) +;; is equivalent to +;; (subtypep T1 (upgraded-complex-part-type T2)) +;; (Proof: Let U T be an abbreviation for (upgraded-complex-part-type T). +;; If U T1 <= U T2, then T1 <= U T1 <= U T2. +;; If T1 <= U T2, then by homomorphism U T1 <= U U T2 = U T2.) +;; +;; For _any_ CL implementation, you could define +;; (defun upgraded-complex-part-type (type) 'REAL) +;; Likewise for _any_ CL implementation, you could define +;; (defun upgraded-complex-part-type (type) type) +;; or - again for _any_ CL implementation: +;; (defun upgraded-complex-part-type (type) +;; (cond ((subtypep type 'NIL) 'NIL) +;; ((subtypep type 'SHORT-FLOAT) 'SHORT-FLOAT) +;; ((subtypep type 'SINGLE-FLOAT) 'SINGLE-FLOAT) +;; ((subtypep type 'DOUBLE-FLOAT) 'DOUBLE-FLOAT) +;; ((subtypep type 'LONG-FLOAT) 'LONG-FLOAT) +;; ((subtypep type 'RATIONAL) 'RATIONAL) +;; ((subtypep type 'REAL) 'REAL) +;; (t (error ...)))) +;; The reason is that a complex number is immutable: no setters for the +;; realpart and imagpart exist. +;; +;; We choose the second implementation because it allows the most precise +;; type inference. +(defun upgraded-complex-part-type (type &optional environment) + (declare (ignore environment)) + (if (subtypep type 'REAL) + type + (error-of-type 'error + (TEXT "~S: type ~S is not a subtype of ~S") + 'upgraded-complex-part-type type 'real))) + +;; ---------------------------------------------------------------------------- + +;; Macros for defining the various built-in "atomic type specifier"s and +;; "compound type specifier"s. The following macros add information for both +;; the TYPEP function above and the c-TYPEP in the compiler. + +; Alist symbol -> funname, used by the compiler. +(defparameter c-typep-alist1 '()) +; Alist symbol -> lambdabody, used by the compiler. +(defparameter c-typep-alist2 '()) +; Alist symbol -> expander function, used by the compiler. +(defparameter c-typep-alist3 '()) + +; (def-atomic-type symbol function-name) +; defines an atomic type. The function-name designates a function taking one +; argument and returning a generalized boolean value. It can be either a +; symbol or a lambda expression. +(defmacro def-atomic-type (symbol funname) + (let ((lambdap (and (consp funname) (eq (car funname) 'LAMBDA)))) + `(PROGN + (SETF (GET ',symbol 'TYPE-SYMBOL) + ,(if lambdap + `(FUNCTION ,(concat-pnames "TYPE-SYMBOL-" symbol) ,funname) + `(FUNCTION ,funname) + ) + ) + ,(if lambdap + `(SETQ C-TYPEP-ALIST2 + (NCONC C-TYPEP-ALIST2 (LIST (CONS ',symbol ',(cdr funname)))) + ) + `(SETQ C-TYPEP-ALIST1 + (NCONC C-TYPEP-ALIST1 (LIST (CONS ',symbol ',funname))) + ) + ) + ',symbol + ) +) ) + +; (def-compound-type symbol lambda-list (x) check-form typep-form c-typep-form) +; defines a compound type. The lambda-list is of the form (&optional ...) +; where the arguments come from the CDR of the type specifier. +; For typep-form, x is an object. +; For c-typep-form, x is a multiply evaluatable form (actually a gensym). +; check-form is a form performing error checking, may call `error'. +; typep-form should return a generalized boolean value. +; c-typep-form should produce a form returning a generalized boolean value. +(defmacro def-compound-type (symbol lambdalist (var) check-form typep-form c-typep-form) + `(PROGN + (SETF (GET ',symbol 'TYPE-LIST) + (FUNCTION ,(concat-pnames "TYPE-LIST-" symbol) + (LAMBDA (,var ,@lambdalist) + ,@(if check-form + `((MACROLET ((ERROR (&REST ERROR-ARGS) + (LIST* 'ERROR-OF-TYPE ''ERROR ERROR-ARGS) + )) + ,check-form + )) + ) + ,typep-form + ) ) ) + (SETQ C-TYPEP-ALIST3 + (NCONC C-TYPEP-ALIST3 + (LIST (CONS ',symbol + #'(LAMBDA (,var ,@lambdalist &REST ILLEGAL-ARGS) + (DECLARE (IGNORE ILLEGAL-ARGS)) + ,@(if check-form + `((MACROLET ((ERROR (&REST ERROR-ARGS) + (LIST 'PROGN + (LIST* 'C-WARN ERROR-ARGS) + '(THROW 'C-TYPEP NIL) + )) ) + ,check-form + )) + ) + ,c-typep-form + ) + ) ) ) ) + ',symbol + ) +) + +; CLtL1 p. 43 +(def-atomic-type ARRAY arrayp) +(def-atomic-type ATOM atom) +(def-atomic-type BASE-CHAR + #+BASE-CHAR=CHARACTER + characterp + #-BASE-CHAR=CHARACTER + (lambda (x) (and (characterp x) (base-char-p x))) +) +(def-atomic-type BASE-STRING + (lambda (x) + (and (stringp x) + (eq (array-element-type x) + #+BASE-CHAR=CHARACTER 'CHARACTER #-BASE-CHAR=CHARACTER 'BASE-CHAR +) ) ) ) +(def-atomic-type BIGNUM + (lambda (x) (and (integerp x) (not (fixnump x)))) +) +(def-atomic-type BIT + (lambda (x) (or (eql x 0) (eql x 1))) +) +(def-atomic-type BIT-VECTOR bit-vector-p) +(def-atomic-type BOOLEAN + (lambda (x) (or (eq x 'nil) (eq x 't))) +) +(def-atomic-type CHARACTER characterp) +(def-atomic-type COMPILED-FUNCTION compiled-function-p) +(def-atomic-type COMPLEX complexp) +(def-atomic-type CONS consp) +(def-atomic-type DOUBLE-FLOAT double-float-p) +(def-atomic-type ENCODING encodingp) +(def-atomic-type EXTENDED-CHAR + #+BASE-CHAR=CHARACTER + (lambda (x) (declare (ignore x)) nil) + #-BASE-CHAR=CHARACTER + (lambda (x) (and (characterp x) (not (base-char-p x)))) +) +(def-atomic-type FIXNUM fixnump) +(def-atomic-type FLOAT floatp) +(def-atomic-type FUNCTION functionp) +(def-atomic-type HASH-TABLE hash-table-p) +(def-atomic-type INTEGER integerp) +(def-atomic-type KEYWORD keywordp) +(def-atomic-type LIST listp) +#+LOGICAL-PATHNAMES +(def-atomic-type LOGICAL-PATHNAME logical-pathname-p) +(def-atomic-type LONG-FLOAT long-float-p) +(def-atomic-type NIL + (lambda (x) (declare (ignore x)) nil) +) +(def-atomic-type NULL null) +(def-atomic-type NUMBER numberp) +(def-atomic-type PACKAGE packagep) +(def-atomic-type PATHNAME pathnamep) +(def-atomic-type RANDOM-STATE random-state-p) +(def-atomic-type RATIO + (lambda (x) (and (rationalp x) (not (integerp x)))) +) +(def-atomic-type RATIONAL rationalp) +(def-atomic-type READTABLE readtablep) +(def-atomic-type REAL realp) +(def-atomic-type SEQUENCE sequencep) +(def-atomic-type SHORT-FLOAT short-float-p) +(def-atomic-type SIMPLE-ARRAY simple-array-p) +(def-atomic-type SIMPLE-BASE-STRING + (lambda (x) + (and (simple-string-p x) + (eq (array-element-type x) + #+BASE-CHAR=CHARACTER 'CHARACTER #-BASE-CHAR=CHARACTER 'BASE-CHAR +) ) ) ) +(def-atomic-type SIMPLE-BIT-VECTOR simple-bit-vector-p) +(def-atomic-type SIMPLE-STRING simple-string-p) +(def-atomic-type SIMPLE-VECTOR simple-vector-p) +(def-atomic-type SINGLE-FLOAT single-float-p) +(defun %standard-char-p (x) (and (characterp x) (standard-char-p x))) ; ABI +(def-atomic-type STANDARD-CHAR %standard-char-p) +(def-atomic-type CLOS:STANDARD-OBJECT clos::std-instance-p) +(def-atomic-type STREAM streamp) +(def-atomic-type FILE-STREAM file-stream-p) +(def-atomic-type SYNONYM-STREAM synonym-stream-p) +(def-atomic-type BROADCAST-STREAM broadcast-stream-p) +(def-atomic-type CONCATENATED-STREAM concatenated-stream-p) +(def-atomic-type TWO-WAY-STREAM two-way-stream-p) +(def-atomic-type ECHO-STREAM echo-stream-p) +(def-atomic-type STRING-STREAM string-stream-p) +(def-atomic-type STRING stringp) +(def-atomic-type STRING-CHAR characterp) +(def-atomic-type CLOS:STRUCTURE-OBJECT clos::structure-object-p) +(def-atomic-type SYMBOL symbolp) +(def-atomic-type T (lambda (x) (declare (ignore x)) t)) +;; foreign1.lisp is loaded after this file, +;; so these symbols are not external yet +#+ffi +(def-atomic-type ffi::foreign-function + (lambda (x) (eq 'ffi::foreign-function (type-of x)))) +#+ffi +(def-atomic-type ffi::foreign-variable + (lambda (x) (eq 'ffi::foreign-variable (type-of x)))) +#+ffi +(def-atomic-type ffi::foreign-address + (lambda (x) (eq 'ffi::foreign-address (type-of x)))) +;; see lispbibl.d (#define FOREIGN) and predtype.d (TYPE-OF): +#+(or unix ffi affi win32) +(def-atomic-type foreign-pointer + (lambda (x) (eq 'foreign-pointer (type-of x)))) +(def-atomic-type VECTOR vectorp) +(def-atomic-type PLIST + (lambda (x) (multiple-value-bind (length tail) (list-length-dotted x) + (and (null tail) (evenp length))))) + +(defmacro ensure-dim (type dim) + ;; make sure DIM is a valid dimension + `(unless (or (eq ,dim '*) (typep ,dim `(INTEGER 0 (,ARRAY-DIMENSION-LIMIT)))) + (error (TEXT "~S: dimension ~S is invalid") ',type ,dim))) + +(defmacro ensure-rank (type rank) + ;; make sure RANK is a valid rank + `(unless (typep ,rank `(INTEGER 0 (,ARRAY-RANK-LIMIT))) + (error (TEXT "~S: rank ~S is invalid") ',type ,rank))) + +; CLtL1 p. 46-50 +(defun c-typep-array (tester el-type dims x) + `(AND (,tester ,x) + ,@(if (eq el-type '*) + '() + `((EQUAL (ARRAY-ELEMENT-TYPE ,x) ',(upgraded-array-element-type el-type))) + ) + ,@(if (eq dims '*) + '() + (if (numberp dims) + `((EQL ,dims (ARRAY-RANK ,x))) + `((EQL ,(length dims) (ARRAY-RANK ,x)) + ,@(let ((i 0)) + (mapcap #'(lambda (dim) + (prog1 + (if (eq dim '*) + '() + `((EQL ',dim (ARRAY-DIMENSION ,x ,i))) + ) + (incf i) + ) ) + dims + ) ) + ) + ) ) + ) +) +(defun c-typep-vector (tester size x) + `(AND (,tester ,x) + ,@(if (eq size '*) + '() + `((EQL ',size (ARRAY-DIMENSION ,x 0))) + ) + ) +) +(defun typep-number-test (x low high test type) + (and (funcall test x) + (cond ((eq low '*)) + ((funcall test low) (<= low x)) + ((and (consp low) (null (rest low)) (funcall test (first low))) + (< (first low) x) + ) + (t (error-of-type 'error + #1=(TEXT "~S: argument to ~S must be *, ~S or a list of ~S: ~S") + 'typep type type type low + ) ) ) + (cond ((eq high '*)) + ((funcall test high) (>= high x)) + ((and (consp high) (null (rest high)) (funcall test (first high))) + (> (first high) x) + ) + (t (error-of-type 'error + #1# 'typep type type type high +) ) ) ) ) +(defun c-typep-number (caller tester low high x) + `(AND (,tester ,x) + ,@(cond ((eq low '*) '()) + ((funcall tester low) `((<= ,low ,x))) + ((and (consp low) (null (rest low)) (funcall tester (first low))) + `((< ,(first low) ,x)) + ) + (t (c-warn #1=(TEXT "~S: argument to ~S must be *, ~S or a list of ~S: ~S") + 'typep caller caller caller low + ) + (throw 'c-TYPEP nil) + ) ) + ,@(cond ((eq high '*) '()) + ((funcall tester high) `((>= ,high ,x))) + ((and (consp high) (null (rest high)) (funcall tester (first high))) + `((> ,(first high) ,x)) + ) + (t (c-warn #1# 'typep caller caller caller high) + (throw 'c-TYPEP nil) + ) ) + ) +) +(def-compound-type ARRAY (&optional (el-type '*) (dims '*)) (x) + (unless (eq dims '*) + (if (numberp dims) + (ensure-rank ARRAY dims) + (dolist (dim dims) (ensure-dim ARRAY dim)))) + (and (arrayp x) + (or (eq el-type '*) + (equal (array-element-type x) (upgraded-array-element-type el-type)) + ) + (or (eq dims '*) + (if (numberp dims) + (eql dims (array-rank x)) + (and (eql (length dims) (array-rank x)) + (every #'(lambda (a b) (or (eq a '*) (eql a b))) + dims (array-dimensions x) + ) ) ) ) ) + (c-typep-array 'ARRAYP el-type dims x) +) +(def-compound-type SIMPLE-ARRAY (&optional (el-type '*) (dims '*)) (x) + (unless (eq dims '*) + (if (numberp dims) + (ensure-rank SIMPLE-ARRAY dims) + (dolist (dim dims) (ensure-dim SIMPLE-ARRAY dim)))) + (and (simple-array-p x) + (or (eq el-type '*) + (equal (array-element-type x) (upgraded-array-element-type el-type)) + ) + (or (eq dims '*) + (if (numberp dims) + (eql dims (array-rank x)) + (and (eql (length dims) (array-rank x)) + (every #'(lambda (a b) (or (eq a '*) (eql a b))) + dims (array-dimensions x) + ) ) ) ) ) + (c-typep-array 'SIMPLE-ARRAY-P el-type dims x) +) +(def-compound-type VECTOR (&optional (el-type '*) (size '*)) (x) + (ensure-dim VECTOR size) + (and (vectorp x) + (or (eq el-type '*) + (equal (array-element-type x) (upgraded-array-element-type el-type)) + ) + (or (eq size '*) (eql (array-dimension x 0) size)) + ) + `(AND (VECTORP ,x) + ,@(if (eq el-type '*) + '() + `((EQUAL (ARRAY-ELEMENT-TYPE ,x) ',(upgraded-array-element-type el-type))) + ) + ,@(if (eq size '*) + '() + `((EQL (ARRAY-DIMENSION ,x 0) ',size)) + ) + ) +) +(def-compound-type SIMPLE-VECTOR (&optional (size '*)) (x) + (ensure-dim SIMLPE-VECTOR size) + (and (simple-vector-p x) + (or (eq size '*) (eql size (array-dimension x 0))) + ) + (c-typep-vector 'SIMPLE-VECTOR-P size x) +) +(def-compound-type COMPLEX (&optional (rtype '*) (itype rtype)) (x) + nil + (and (complexp x) + (or (eq rtype '*) + (typep (realpart x) (upgraded-complex-part-type rtype))) + (or (eq itype '*) + (typep (imagpart x) (upgraded-complex-part-type itype)))) + `(AND (COMPLEXP ,x) + ,@(if (eq rtype '*) + '() + `((TYPEP (REALPART ,x) ',(upgraded-complex-part-type rtype)))) + ,@(if (eq itype '*) + '() + `((TYPEP (IMAGPART ,x) ',(upgraded-complex-part-type itype)))))) +(def-compound-type INTEGER (&optional (low '*) (high '*)) (x) + nil + (typep-number-test x low high #'integerp 'INTEGER) + (c-typep-number 'INTEGER 'INTEGERP low high x) +) +(def-compound-type MOD (n) (x) + (unless (integerp n) + (error (TEXT "~S: argument to MOD must be an integer: ~S") + 'typep n + ) ) + (and (integerp x) (<= 0 x) (< x n)) + `(AND (INTEGERP ,x) (NOT (MINUSP ,x)) (< ,x ,n)) +) +(def-compound-type SIGNED-BYTE (&optional (n '*)) (x) + (unless (or (eq n '*) (integerp n)) + (error (TEXT "~S: argument to SIGNED-BYTE must be an integer or * : ~S") + 'typep n + ) ) + (and (integerp x) (or (eq n '*) (< (integer-length x) n))) + `(AND (INTEGERP ,x) + ,@(if (eq n '*) '() `((< (INTEGER-LENGTH ,x) ,n))) + ) +) +(def-compound-type UNSIGNED-BYTE (&optional (n '*)) (x) + (unless (or (eq n '*) (integerp n)) + (error (TEXT "~S: argument to UNSIGNED-BYTE must be an integer or * : ~S") + 'typep n + ) ) + (and (integerp x) + (not (minusp x)) + (or (eq n '*) (<= (integer-length x) n)) + ) + `(AND (INTEGERP ,x) (NOT (MINUSP ,x)) + ,@(if (eq n '*) '() `((<= (INTEGER-LENGTH ,x) ,n))) + ) +) +(def-compound-type REAL (&optional (low '*) (high '*)) (x) + nil + (typep-number-test x low high #'realp 'REAL) + (c-typep-number 'REAL 'REALP low high x) +) +(def-compound-type RATIONAL (&optional (low '*) (high '*)) (x) + nil + (typep-number-test x low high #'rationalp 'RATIONAL) + (c-typep-number 'RATIONAL 'RATIONALP low high x) +) +(def-compound-type FLOAT (&optional (low '*) (high '*)) (x) + nil + (typep-number-test x low high #'floatp 'FLOAT) + (c-typep-number 'FLOAT 'FLOATP low high x) +) +(def-compound-type SHORT-FLOAT (&optional (low '*) (high '*)) (x) + nil + (typep-number-test x low high #'short-float-p 'SHORT-FLOAT) + (c-typep-number 'SHORT-FLOAT 'SHORT-FLOAT-P low high x) +) +(def-compound-type SINGLE-FLOAT (&optional (low '*) (high '*)) (x) + nil + (typep-number-test x low high #'single-float-p 'SINGLE-FLOAT) + (c-typep-number 'SINGLE-FLOAT 'SINGLE-FLOAT-P low high x) +) +(def-compound-type DOUBLE-FLOAT (&optional (low '*) (high '*)) (x) + nil + (typep-number-test x low high #'double-float-p 'DOUBLE-FLOAT) + (c-typep-number 'DOUBLE-FLOAT 'DOUBLE-FLOAT-P low high x) +) +(def-compound-type LONG-FLOAT (&optional (low '*) (high '*)) (x) + nil + (typep-number-test x low high #'long-float-p 'LONG-FLOAT) + (c-typep-number 'LONG-FLOAT 'LONG-FLOAT-P low high x) +) +(def-compound-type STRING (&optional (size '*)) (x) + (ensure-dim STRING size) + (and (stringp x) + (or (eq size '*) (eql size (array-dimension x 0))) + ) + (c-typep-vector 'STRINGP size x) +) +(def-compound-type SIMPLE-STRING (&optional (size '*)) (x) + (ensure-dim SIMPLE-STRING size) + (and (simple-string-p x) + (or (eq size '*) (eql size (array-dimension x 0))) + ) + (c-typep-vector 'SIMPLE-STRING-P size x) +) +(def-compound-type BASE-STRING (&optional (size '*)) (x) + (ensure-dim BASE-STRING size) + (and (stringp x) + (or (eq size '*) (eql size (array-dimension x 0))) + ) + (c-typep-vector 'STRINGP size x) +) +(def-compound-type SIMPLE-BASE-STRING (&optional (size '*)) (x) + (ensure-dim SIMPLE-BASE-STRING size) + (and (simple-string-p x) + (or (eq size '*) (eql size (array-dimension x 0))) + ) + (c-typep-vector 'SIMPLE-STRING-P size x) +) +(def-compound-type BIT-VECTOR (&optional (size '*)) (x) + (ensure-dim BIT-VECTOR size) + (and (bit-vector-p x) + (or (eq size '*) (eql size (array-dimension x 0))) + ) + (c-typep-vector 'BIT-VECTOR-P size x) +) +(def-compound-type SIMPLE-BIT-VECTOR (&optional (size '*)) (x) + (ensure-dim SIMPLE-BIT-VECTOR size) + (and (simple-bit-vector-p x) + (or (eq size '*) (eql size (array-dimension x 0))) + ) + (c-typep-vector 'SIMPLE-BIT-VECTOR-P size x) +) +(def-compound-type CONS (&optional (car-type '*) (cdr-type '*)) (x) + nil + (and (consp x) + (or (eq car-type '*) (typep (car x) car-type)) + (or (eq cdr-type '*) (typep (cdr x) cdr-type)) + ) + `(AND (CONSP ,x) + ,@(if (eq car-type '*) '() `((TYPEP (CAR ,x) ',car-type))) + ,@(if (eq cdr-type '*) '() `((TYPEP (CDR ,x) ',cdr-type))) + ) +) + +(fmakunbound 'def-compound-type) + +;; ---------------------------------------------------------------------------- + +; Typtest ohne Gefahr einer Fehlermeldung. Für SIGNAL und HANDLER-BIND. +(defun safe-typep (x y &optional env) + (let ((*error-handler* + #'(lambda (&rest error-args) + (declare (ignore error-args)) + (return-from safe-typep (values nil nil)) + )) ) + (values (typep x y env) t) +) ) + +; Umwandlung eines "type for declaration" in einen "type for discrimination". +(defun type-for-discrimination (y &optional (notp nil) &aux f) + (cond ((symbolp y) + (cond ((get y 'TYPE-SYMBOL) y) + ((get y 'TYPE-LIST) y) + ((setq f (get y 'DEFTYPE-EXPANDER)) + (let* ((z (funcall f (list y))) + (zx (type-for-discrimination z notp))) + (if (eql zx z) y zx) + )) + (t y) + ) ) + ((and (consp y) (symbolp (first y))) + (case (first y) + ((SATISFIES MEMBER EQL) y) + (NOT + (let* ((z (second y)) + (zx (type-for-discrimination z (not notp)))) + (if (eql zx z) y `(NOT ,zx)) + )) + ((AND OR COMPLEX VALUES) + (let* ((z (rest y)) + (zx (mapcar #'(lambda (x) (type-for-discrimination x notp)) z))) + (if (every #'eql z zx) y (cons (first y) zx)) + )) + (FUNCTION + ;; (FUNCTION arg-types res-type) is somewhere between + ;; NIL and FUNCTION, but undecidable. + (if notp 'NIL 'FUNCTION) + ) + (t (cond ((get (first y) 'TYPE-LIST) y) + ((setq f (get (first y) 'DEFTYPE-EXPANDER)) + (let* ((z (funcall f y)) + (zx (type-for-discrimination z notp))) + (if (eql zx z) y zx) + )) + (t y) + ) ) ) ) + (t y) +) ) + +; Testet eine Liste von Werten auf Erfüllen eines Type-Specifiers. Für THE. +(defun %the (values type) ; ABI + (macrolet ((near-typep (objform typform) + ;; near-typep ist wie typep, nur dass das Objekt auch ein + ;; Read-Label sein darf. Das tritt z.B. auf bei + ;; (read-from-string "#1=#S(FOO :X #1#)") + ;; im Konstruktor MAKE-FOO. Die Implementation ist aber + ;; nicht gezwungen, bei fehlerhaftem THE zwingend einen + ;; Fehler zu melden, darum ist ein lascherer Typcheck hier + ;; erlaubt. + (let ((g (gensym))) + `(let ((,g ,objform)) + (or (typep ,g ,typform) (eq (type-of ,g) 'READ-LABEL)))))) + (if (and (consp type) (eq (car type) 'VALUES)) + ;; The VALUES type specifier is ill-defined in ANSI CL. + ;; + ;; There are two possibilities to define a VALUES type specifier in a + ;; sane way: + ;; - (EXACT-VALUES type1 ... [&optional ...]) describes the exact shape + ;; of the values list, as received by MULTIPLE-VALUE-LIST. + ;; For example, (EXACT-VALUES SYMBOL) is matched by (values 'a) but not + ;; by (values 'a 'b) or (values). + ;; - (ASSIGNABLE-VALUES type1 ... [&optional ...]) describes the values + ;; as received by a set of variables through MULTIPLE-VALUE-BIND or + ;; MULTIPLE-VALUE-SETQ. For example, (ASSIGNABLE-VALUES SYMBOL) is + ;; defined by whether + ;; (MULTIPLE-VALUE-BIND (var1) values (DECLARE (TYPE SYMBOL var1)) ...) + ;; is valid or not; therefore (ASSIGNABLE-VALUES SYMBOL) is matched by + ;; (values 'a) and (values 'a 'b) and (values). + ;; Note that &OPTIONAL is actually redundant here: + ;; (ASSIGNABLE-VALUES type1 ... &optional otype1 ...) + ;; is equivalent to + ;; (ASSIGNABLE-VALUES type1 ... (OR NULL otype1) ...) + ;; HyperSpec/Body/typspe_values.html indicates that VALUES means + ;; EXACT-VALUES; however, HyperSpec/Body/speope_the.html indicates that + ;; VALUES means ASSIGNABLE-VALUES. + ;; + ;; SBCL interprets the VALUES type specifier to mean EXACT-VALUES when + ;; it contains &OPTIONAL or &REST, but ASSIGNABLE-VALUES when it has + ;; only a tuple of type specifiers. This is utter nonsense, in particular + ;; because it makes (VALUES type1 ... typek &OPTIONAL) + ;; different from (VALUES type1 ... typek). + ;; + ;; Here we use the ASSIGNABLE-VALUES interpretation. + ;; In SUBTYPEP we just punt and don't assume any interpretation. + (let ((vals values) (types (cdr type))) + ;; required: + (loop + (when (or (atom types) (atom vals)) (return-from %the t)) + (when (memq (car types) lambda-list-keywords) (return)) + (unless (near-typep (pop vals) (pop types)) + (return-from %the nil))) + ;; &optional: + (when (and (consp types) (eq (car types) '&optional)) + (setq types (cdr types)) + (loop + (when (or (atom types) (atom vals)) (return-from %the t)) + (when (memq (car types) lambda-list-keywords) (return)) + (unless (near-typep (pop vals) (pop types)) + (return-from %the nil)))) + ;; &rest &key: + (case (car types) + (&rest + (setq types (cdr types)) + (when (atom types) (typespec-error 'the type)) + (unless (near-typep (pop vals) (pop types)) + (return-from %the nil))) + (&key) + (t (typespec-error 'the type))) + (if (eq (car types) '&key) + (progn + (setq types (cdr types)) + (when (oddp (length vals)) (return-from %the nil)) + (let ((keywords nil)) + (loop + (when (or (atom types) (atom vals)) (return-from %the t)) + (when (memq (car types) lambda-list-keywords) (return)) + (let ((item (pop types))) + (unless (and (listp item) (eql (length item) 2) + (symbolp (first item))) + (typespec-error 'the type)) + (let ((kw (symbol-to-keyword (first item)))) + (unless (near-typep (getf vals kw) (second item)) + (return-from %the nil)) + (push kw keywords)))) + (if (and (consp types) (eq (car types) '&allow-other-keys)) + (setq types (cdr types)) + (unless (getf vals ':allow-other-keys) + (do ((L vals (cddr L))) + ((atom L)) + (unless (memq (car L) keywords) + (return-from %the nil))))))) + (when (consp types) (typespec-error 'the type))) + t) + (near-typep (if (consp values) (car values) nil) type)))) + +;;; =========================================================================== + +;; SUBTYPEP +(load "subtypep") + + +;; Returns the number of bytes that are needed to represent #\Null in a +;; given encoding. +(defun encoding-zeroes (encoding) + #+UNICODE + ;; this should use min_bytes_per_char for cache, not the hash table + (let ((name (ext:encoding-charset encoding)) + (table #.(make-hash-table :key-type '(or string symbol) :value-type 'fixnum + :test 'stablehash-equal :warn-if-needs-rehash-after-gc t + :initial-contents '(("UTF-7" . 1)))) + (tester #.(make-string 2 :initial-element (code-char 0)))) + (or (gethash name table) + (setf (gethash name table) + (- (length (ext:convert-string-to-bytes tester encoding)) + (length (ext:convert-string-to-bytes tester encoding + :end 1)))))) + #-UNICODE 1) + +;; Determines two values low,high such that +;; (subtypep type `(INTEGER ,low ,high)) +;; holds and low is as large as possible and high is as small as possible. +;; low = * means -infinity, high = * means infinity. +;; When (subtypep type 'INTEGER) is false, the values NIL,NIL are returned. +;; We need this function only for MAKE-ARRAY, UPGRADED-ARRAY-ELEMENT-TYPE and +;; OPEN and can therefore w.l.o.g. replace +;; type with `(OR ,type (MEMBER 0)) +#| ;; The original implementation calls canonicalize-type and then applies + ;; a particular SUBTYPE variant: + (defun subtype-integer (type) + (macrolet ((yes () '(return-from subtype-integer (values low high))) + (no () '(return-from subtype-integer nil)) + (unknown () '(return-from subtype-integer nil))) + (setq type (canonicalize-type type)) + (if (consp type) + (case (first type) + (MEMBER ; (MEMBER &rest objects) + ;; All elements must be of type INTEGER. + (let ((low 0) (high 0)) ; wlog! + (dolist (x (rest type) (yes)) + (unless (typep x 'INTEGER) (return (no))) + (setq low (min low x) high (max high x))))) + (OR ; (OR type*) + ;; Every type must be subtype of INTEGER. + (let ((low 0) (high 0)) ; wlog! + (dolist (type1 (rest type) (yes)) + (multiple-value-bind (low1 high1) (subtype-integer type1) + (unless low1 (return (no))) + (setq low (if (or (eq low '*) (eq low1 '*)) '* (min low low1)) + high (if (or (eq high '*) (eq high1 '*)) + '* (max high high1))))))) + (AND ; (AND type*) + ;; If one of the types is subtype of INTEGER, then yes, + ;; otherwise unknown. + (let ((low nil) (high nil)) + (dolist (type1 (rest type)) + (multiple-value-bind (low1 high1) (subtype-integer type1) + (when low1 + (if low + (setq low (if (eq low '*) low1 (if (eq low1 '*) low (max low low1))) + high (if (eq high '*) high1 (if (eq high1 '*) high (min high high1)))) + (setq low low1 high high1))))) + (if low + (progn + (when (and (numberp low) (numberp high) (not (<= low high))) + (setq low 0 high 0) ; type equivalent to NIL) + (yes)) + (unknown))))) + (setq type (list type))) + (if (eq (first type) 'INTEGER) + (let ((low (if (rest type) (second type) '*)) + (high (if (cddr type) (third type) '*))) + (when (consp low) + (setq low (first low)) + (when (numberp low) (incf low))) + (when (consp high) + (setq high (first high)) + (when (numberp high) (decf high))) + (when (and (numberp low) (numberp high) (not (<= low high))) ; type leer? + (setq low 0 high 0)) + (yes)) + (if (and (eq (first type) 'INTERVALS) (eq (second type) 'INTEGER)) + (let ((low (third type)) + (high (car (last type)))) + (when (consp low) + (setq low (first low)) + (when (numberp low) (incf low))) + (when (consp high) + (setq high (first high)) + (when (numberp high) (decf high))) + (yes)) + (unknown))))) +|# ;; This implementation inlines the (tail-recursive) canonicalize-type + ;; function. Its advantage is that it doesn't cons as much. + ;; (For example, (subtype-integer '(UNSIGNED-BYTE 8)) doesn't cons.) +(defun subtype-integer (type) + (macrolet ((yes () '(return-from subtype-integer (values low high))) + (no () '(return-from subtype-integer nil)) + (unknown () '(return-from subtype-integer nil))) + (setq type (expand-deftype type)) + (cond ((symbolp type) + (case type + (BIT (let ((low 0) (high 1)) (yes))) + (FIXNUM + (let ((low '#,most-negative-fixnum) + (high '#,most-positive-fixnum)) + (yes))) + ((INTEGER BIGNUM SIGNED-BYTE) + (let ((low '*) (high '*)) (yes))) + (UNSIGNED-BYTE + (let ((low 0) (high '*)) (yes))) + ((NIL) + (let ((low 0) (high 0)) (yes))) ; wlog! + (t (no)))) + ((and (consp type) (symbolp (first type))) + (unless (and (list-length type) (null (cdr (last type)))) + (typespec-error 'subtypep type)) + (case (first type) + (MEMBER ; (MEMBER &rest objects) + ;; All elements must be of type INTEGER. + (let ((low 0) (high 0)) ; wlog! + (dolist (x (rest type) (yes)) + (unless (typep x 'INTEGER) (return (no))) + (setq low (min low x) high (max high x))))) + (EQL ; (EQL object) + (let ((x (second type))) + (if (typep x 'INTEGER) + (let ((low (min 0 x)) (high (max 0 x))) (yes)) + (no)))) + (OR ; (OR type*) + ;; Every type must be subtype of INTEGER. + (let ((low 0) (high 0)) ; wlog! + (dolist (type1 (rest type) (yes)) + (multiple-value-bind (low1 high1) (subtype-integer type1) + (unless low1 (return (no))) + (setq low (if (or (eq low '*) (eq low1 '*)) + '* (min low low1)) + high (if (or (eq high '*) (eq high1 '*)) + '* (max high high1))))))) + (AND ; (AND type*) + ;; If one of the types is subtype of INTEGER, then yes, + ;; otherwise unknown. + (let ((low nil) (high nil)) + (dolist (type1 (rest type)) + (multiple-value-bind (low1 high1) (subtype-integer type1) + (when low1 + (if low + (setq low (if (eq low '*) low1 + (if (eq low1 '*) low + (max low low1))) + high (if (eq high '*) high1 + (if (eq high1 '*) high + (min high high1)))) + (setq low low1 + high high1))))) + (if low + (progn + (when (and (numberp low) (numberp high) + (not (<= low high))) + (setq low 0 high 0)) ; type equivalent to NIL + (yes)) + (unknown)))) + (INTEGER + (let ((low (if (rest type) (second type) '*)) + (high (if (cddr type) (third type) '*))) + (when (consp low) + (setq low (first low)) + (when (numberp low) (incf low))) + (when (consp high) + (setq high (first high)) + (when (numberp high) (decf high))) + (when (and (numberp low) (numberp high) (not (<= low high))) + (setq low 0 high 0)) ; type equivalent to NIL + (yes))) + (INTERVALS + (if (eq (second type) 'INTEGER) + (let ((low (third type)) + (high (car (last type)))) + (when (consp low) + (setq low (first low)) + (when (numberp low) (incf low))) + (when (consp high) + (setq high (first high)) + (when (numberp high) (decf high))) + (yes)) + (unknown))) + (MOD ; (MOD n) + (let ((n (second type))) + (unless (and (integerp n) (>= n 0)) + (typespec-error 'subtypep type)) + (if (eql n 0) + (no) + (let ((low 0) (high (1- n))) + (yes))))) + (SIGNED-BYTE ; (SIGNED-BYTE &optional s) + (let ((s (if (cdr type) (second type) '*))) + (if (eq s '*) + (let ((low '*) (high '*)) (yes)) + (progn + (unless (and (integerp s) (plusp s)) + (typespec-error 'subtypep type)) + (let ((n (ash 1 (1- s)))) ; (ash 1 *) == (expt 2 *) + (let ((low (- n)) (high (1- n))) + (yes))))))) + (UNSIGNED-BYTE ; (UNSIGNED-BYTE &optional s) + (let ((s (if (cdr type) (second type) '*))) + (if (eq s '*) + (let ((low 0) (high '*)) (yes)) + (progn + (unless (and (integerp s) (>= s 0)) + (typespec-error 'subtypep type)) + (let ((n (ash 1 s))) ; (ash 1 *) == (expt 2 *) + (let ((low 0) (high (1- n))) + (yes))))))) + (t (no)))) + ((clos::defined-class-p type) + (if (and (clos::built-in-class-p type) + (eq (get (clos:class-name type) 'CLOS::CLOSCLASS) type)) + (return-from subtype-integer + (subtype-integer (clos:class-name type))) + (no))) + ((clos::eql-specializer-p type) + (let ((x (clos::eql-specializer-singleton type))) + (if (typep x 'INTEGER) + (let ((low (min 0 x)) (high (max 0 x))) (yes)) + (no)))) + ((encodingp type) (no)) + (t (typespec-error 'subtypep type))))) + +#| TODO: Fix subtype-integer such that this works. +Henry Baker: + (defun type-null (x) + (values (and (eq 'bit (upgraded-array-element-type `(or bit ,x))) + (not (typep 0 x)) + (not (typep 1 x))) + t)) + (type-null '(and symbol number)) + (type-null '(and integer symbol)) + (type-null '(and integer character)) +|# + +;; Determines a sequence kind (an atom, as defined in defseq.lisp: one of +;; LIST - stands for LIST +;; VECTOR - stands for (VECTOR T) +;; STRING - stands for (VECTOR CHARACTER) +;; 1, 2, 4, 8, 16, 32 - stands for (VECTOR (UNSIGNED-BYTE n)) +;; 0 - stands for (VECTOR NIL)) +;; that indicates the sequence type meant by the given type. Other possible +;; return values are +;; SEQUENCE - denoting a type whose intersection with (OR LIST VECTOR) is not +;; subtype of LIST or VECTOR, or +;; NIL - indicating a type whose intersection with (OR LIST VECTOR) is empty. +;; When the type is (OR (VECTOR eltype1) ... (VECTOR eltypeN)), the chosen +;; element type is the smallest element type that contains all of eltype1 ... +;; eltypeN. +;; +;; User-defined sequence types are not supported here. +;; +;; This implementation inlines the (tail-recursive) canonicalize-type +;; function. Its advantage is that it doesn't cons as much. Also it employs +;; some heuristics and does not have the full power of SUBTYPEP. +(defun subtype-sequence (type) + (setq type (expand-deftype type)) + (cond ((symbolp type) + (case type + ((LIST CONS NULL) 'LIST) + ((NIL) 'NIL) + ((BIT-VECTOR SIMPLE-BIT-VECTOR) '1) + ((STRING SIMPLE-STRING BASE-STRING SIMPLE-BASE-STRING) 'STRING) + ((VECTOR SIMPLE-VECTOR ARRAY SIMPLE-ARRAY) 'VECTOR) + ((SEQUENCE) 'SEQUENCE) + (t 'NIL))) + ((and (consp type) (symbolp (first type))) + (unless (and (list-length type) (null (cdr (last type)))) + (typespec-error 'subtypep type)) + (case (first type) + (MEMBER ; (MEMBER &rest objects) + (let ((kind 'NIL)) + (dolist (x (rest type)) + (setq kind (sequence-type-union kind (type-of-sequence x)))) + kind)) + (EQL ; (EQL object) + (unless (eql (length type) 2) + (typespec-error 'subtypep type)) + (type-of-sequence (second type))) + (OR ; (OR type*) + (let ((kind 'NIL)) + (dolist (x (rest type)) + (setq kind (sequence-type-union kind (subtype-sequence x)))) + kind)) + (AND ; (AND type*) + (let ((kind 'SEQUENCE)) + (dolist (x (rest type)) + (setq kind (sequence-type-intersection kind (subtype-sequence x)))) + kind)) + ((SIMPLE-BIT-VECTOR BIT-VECTOR) ; (SIMPLE-BIT-VECTOR &optional size) + (when (cddr type) + (typespec-error 'subtypep type)) + '1) + ((SIMPLE-STRING STRING SIMPLE-BASE-STRING BASE-STRING) ; (SIMPLE-STRING &optional size) + (when (cddr type) + (typespec-error 'subtypep type)) + 'STRING) + (SIMPLE-VECTOR ; (SIMPLE-VECTOR &optional size) + (when (cddr type) + (typespec-error 'subtypep type)) + 'VECTOR) + ((VECTOR ARRAY SIMPLE-ARRAY) ; (VECTOR &optional el-type size), (ARRAY &optional el-type dimensions) + (when (cdddr type) + (typespec-error 'subtypep type)) + (let ((el-type (if (cdr type) (second type) '*))) + (if (eq el-type '*) + 'VECTOR + (let ((eltype (upgraded-array-element-type el-type))) + (cond ((eq eltype 'T) 'VECTOR) + ((eq eltype 'CHARACTER) 'STRING) + ((eq eltype 'BIT) '1) + ((and (consp eltype) (eq (first eltype) 'UNSIGNED-BYTE)) (second eltype)) + ((eq eltype 'NIL) '0) + (t (error (TEXT "~S is not up-to-date with ~S for element type ~S") + 'subtypep-sequence 'upgraded-array-element-type eltype))))))) + ((CONS) ; (CONS &optional cartype cdrtype) + (when (cdddr type) + (typespec-error 'subtypep type)) + 'LIST) + (t 'NIL))) + ((clos::defined-class-p type) + (if (and (clos::built-in-class-p type) + (eq (get (clos:class-name type) 'CLOS::CLOSCLASS) type)) + (subtype-sequence (clos:class-name type)) + 'NIL)) + ((clos::eql-specializer-p type) + (type-of-sequence (clos::eql-specializer-singleton type))) + (t 'NIL))) +(defun type-of-sequence (x) + (cond ((listp x) 'LIST) + ((vectorp x) + (let ((eltype (array-element-type x))) + (cond ((eq eltype 'T) 'VECTOR) + ((eq eltype 'CHARACTER) 'STRING) + ((eq eltype 'BIT) '1) + ((and (consp eltype) (eq (first eltype) 'UNSIGNED-BYTE)) (second eltype)) + ((eq eltype 'NIL) '0) + (t (error (TEXT "~S is not up-to-date with ~S for element type ~S") + 'type-of-sequence 'array-element-type eltype))))) + (t 'NIL))) +(defun sequence-type-union (t1 t2) + (cond ; Simple general rules. + ((eql t1 t2) t1) + ((eq t1 'NIL) t2) + ((eq t2 'NIL) t1) + ; Now the union of two different types. + ((or (eq t1 'SEQUENCE) (eq t2 'SEQUENCE)) 'SEQUENCE) + ((or (eq t1 'LIST) (eq t2 'LIST)) + ; union of LIST and a vector type + 'SEQUENCE) + ((or (eq t1 'VECTOR) (eq t2 'VECTOR)) 'VECTOR) + ((eql t1 0) t2) + ((eql t2 0) t1) + ((or (eq t1 'STRING) (eq t2 'STRING)) + ; union of STRING and an integer-vector type + 'VECTOR) + (t (max t1 t2)))) +(defun sequence-type-intersection (t1 t2) + (cond ; Simple general rules. + ((eql t1 t2) t1) + ((or (eq t1 'NIL) (eq t2 'NIL)) 'NIL) + ; Now the intersection of two different types. + ((eq t1 'SEQUENCE) t2) + ((eq t2 'SEQUENCE) t1) + ((or (eq t1 'LIST) (eq t2 'LIST)) + ; intersection of LIST and a vector type + 'NIL) + ((eq t1 'VECTOR) t2) + ((eq t2 'VECTOR) t1) + ((or (eql t1 0) (eql t2 0)) '0) + ((or (eq t1 'STRING) (eq t2 'STRING)) + ; intersection of STRING and an integer-vector type + '0) + (t (min t1 t2)))) + +;; ============================================================================ + +(defun type-expand (typespec &optional once-p) + (multiple-value-bind (expanded user-defined-p) + (expand-deftype typespec once-p) + (if user-defined-p (values expanded user-defined-p) + (cond ((symbolp typespec) + (cond ((or (get typespec 'TYPE-SYMBOL) (get typespec 'TYPE-LIST)) + (values typespec nil)) + ((or (get typespec 'DEFSTRUCT-DESCRIPTION) + (clos-class typespec)) + (values typespec nil)) + (t (typespec-error 'type-expand typespec)))) + ((and (consp typespec) (symbolp (first typespec))) + (case (first typespec) + ((SATISFIES MEMBER EQL NOT AND OR) (values typespec nil)) + (t (cond ((get (first typespec) 'TYPE-LIST) + (values typespec nil)) + (t (typespec-error 'type-expand typespec)))))) + ((clos::defined-class-p typespec) (values typespec nil)) + (t (typespec-error 'type-expand typespec)))))) + +;; ============================================================================ + +(unless (clos::funcallable-instance-p #'clos::class-name) + (fmakunbound 'clos::class-name)) |