anchor.diff:  ;; (defun (setf object-data)    (new-value object))
   ;;
   ;;
  -;; Unfortunately:
  -;;
  -;; - asinine doesn't keep around type definitions for ASN.1 types,
  -;;   (they're immediately translated into encoder/decoder functions),
  -;;   so we cannot check that the alternative have different type tags:
  -;;   we can only test for different type names.
  -;;
  -;; - in general, we don't know for a given type a (valid) prototype
  -;;   value.  Therefore we cannot initialize a structure with default
  -;;   values: we have to let the slots initialized to NIL.  And we
  -;;   don't have a map of ASN.1 types to lisp types, so we cannot type
  -;;   the slots either.
  +;; In general, we don't know for a given type a (valid) prototype
  +;; value.  Therefore we cannot initialize a structure with default
  +;; values: we have to let the slots initialized to NIL.  And we
  +;; don't have a map of ASN.1 types to lisp types, so we cannot type
  +;; the slots either.
   ;;
   ;; So:
   ;; -->
   ;; (defstruct object
   ;;   %alternative
   ;;   %value)
  -
  -
  -;; (:choice ((null null :tag 0)
  -;;           (asinine::primitive :octet-string :tag 1)
  -;;           (cons asinine::bsx-cons :tag 2))))
  +;;
  +;; Regarding the encoding/decoding of CHOICE:
  +;;
  +;; * CHOICE with explicit tags generates contextual tag prefixes before
  +;;   the actual alternative data:
  +;;
  +;;     BSX { bsx(31337) } DEFINITIONS ::= BEGIN
  +;;     BsxPDU ::= SEQUENCE {
  +;;         version INTEGER(0..127),
  +;;         object BsxObject
  +;;     }
  +;;     BsxCons ::= SEQUENCE {
  +;;         head BsxObject,
  +;;         tail BsxObject
  +;;     }
  +;;     BsxObject ::= CHOICE {
  +;;         null      [0] NULL,
  +;;         primitive [1] OCTET STRING,
  +;;         cons      [2] BsxCons
  +;;     }
  +;;     END
  +;;
  +;;     (0 :-> bsx-object null null)
  +;;     (1 :-> bsx-object primitive :octet-string)
  +;;     (2 :-> bsx-object cons bsx-cons)
  +;;     30 1D 02 01 01 A2 18 30 16 A1 05 04 03 01 02 03 A2 0D 30 0B A1 05 04 03 04 05 06 A0 02 05 00
  +;;
  +;;
  +;; * CHOICE with implicit tags requires that each alternative has a
  +;;   distinct tag.  For this we need to keep all the type definitions
  +;;   specified (*TYPE* hashtable), so we may retrieve them and use their
  +;;   specific tags.  In this case, the alternatives can be generated in
  +;;   place of the CHOICE without overhead.
  +;;
  +;;     BSX { bsx(31337) } DEFINITIONS ::= BEGIN
  +;;     BsxPDU ::= SEQUENCE {
  +;;         version INTEGER(0..127),
  +;;         object BsxObject
  +;;     }
  +;;     BsxCons ::= SEQUENCE {
  +;;         head BsxObject,
  +;;         tail BsxObject
  +;;     }
  +;;     BsxObject ::= CHOICE {
  +;;         null       NULL,
  +;;         primitive  OCTET STRING,
  +;;         cons       BsxCons
  +;;     }
  +;;     END
  +;;
  +;;     (5 :-> bsx-object null null)
  +;;     (4 :-> bsx-object primitive :octet-string)
  +;;     (16 :-> bsx-object cons bsx-cons)
  +;;     30 13 02 01 01 30 0E 04 03 01 02 03 30 07 04 03 04 05 06 05 00
   
   
   (defun valid-alternatives-p (alternatives)
  
positive.code:                   `(encode-tagged-type stream #'enc (,(accessor-name name '%value) choice)
                                         :class ,class :tag ,tag)
                    `(enc stream)))))
         (defun ,(decoder-name name) (stream)
           (declare (type stream stream))
           (flet ((dec (stream)
                    (decode-identifier stream)
                    (let ((value (,(alexandria:symbolicate 'make- name))))
                      ,(if (some (lambda (alternative) (find :tag alternative)) alternatives)
                           `(let ((v (nibbles:make-octet-vector (decode-length stream))))
                              (read-sequence v stream)
                              (flexi-streams:with-input-from-sequence (stream v)
                                (do ()
                                    ((not (listen stream)))
                                  (let ((tag (decode-identifier stream)))
                                    (decode-length stream)
                                    (ecase tag
                                      ,@(mapcar (lambda (slot)
                                                  (destructuring-bind (s-name s-type &key tag optional) slot
                                                    (declare (ignore optional))
                                                    `(,tag
                                                      (flet ((dec (stream)
                                                               ,@(cond
                                                                   ((symbolp s-type)
                                                                    `((,(decoder-name s-type) stream)))
                                                                   ((eq (car s-type) :integer)
                                                                    `((decode-integer stream)))
                                                                   ((eq (car s-type) :sequence-of)
                                                                    `((decode-sequence-of stream
                                                                                          #',(decoder-name (cadr s-type))))))))
                                                        (setf (,(accessor-name name s-name) value)
                                                              (dec stream))))))
                                         alternatives))))))
                           `(progn
                              (decode-length stream)
                              ,@(mapcar (lambda (slot)
                                          (destructuring-bind (s-name s-type) slot
                                            `(flet ((dec (stream)
                                                      ,@(cond
                                                          ((symbolp s-type)
                                                           `((,(decoder-name s-type) stream)))
                                                          ((eq (car s-type) :integer)
                                                           `((decode-integer stream)))
                                                          ((eq (car s-type) :sequence-of)
                                                           `((decode-sequence-of stream
                                                                                 #',(decoder-name (cadr s-type))))))))
                                               (setf (,(accessor-name name s-name) value)
                                                     (dec stream)))))
                                        alternatives)))
                      value)))
             ,(if (and class tag)
                  `(decode-tagged-type stream #'dec)
                  `(dec stream)))))))
  
  
  ;; -----------------------------------
  
  (defun gen (asn1 &optional (stream *standard-output*))
    (destructuring-bind (module-name assignments &key explicit implicit oid) (cdr asn1)
      (declare (ignore explicit implicit))
      (let ((*print-case* :downcase))
        (pprint `(defpackage ,(string-upcase module-name)
                   (:use #:cl #:asinine #:asinine))
                stream)
        (terpri stream)
        (pprint `(in-package ,(string-upcase module-name))
  
negative.code: ;;;; Copyright (c) Frank James 2015 <frank.a.james@gmail.com>
  ;;;; CHOICE implementation: Copyright (c) Pascal J. Bourguignon 2016 <pjb@informatimago.com>
  ;;;; This code is licensed under the MIT license.
  
  (in-package #:asinine)
  