(defpackage #:sarcasm.instr (:use #:cl) (:shadow cl:return cl:if cl:block cl:loop cl:t) (:local-nicknames (#:a #:alexandria-2))) (in-package #:sarcasm.instr) (defclass instr () ()) (eval-when (:compile-toplevel :load-toplevel :execute) (defun expand-instr-plist (plist) (destructuring-bind (&key instr code type) plist (let* ((class-name (intern (string-upcase (first instr)))) (immediates (cl:loop :for arg :in (rest instr) :for slot-name := (intern (string-upcase arg)) :for reader := (intern (format nil "~a-~a" class-name slot-name)) :for initarg := (a:make-keyword slot-name) :collect `(,slot-name :reader ,reader :initarg ,initarg :initform (error "~a required" ',slot-name))))) `(defclass ,class-name (instr) ((instr-name :allocation :class :type string :initform ,(first instr) :reader instr-name) (instr-code :allocation :class :type (vector (unsigned-byte 8) ,(length code)) :initform (make-array ,(length code) :element-type '(unsigned-byte 8) :initial-contents ',code)) (instr-type :allocation :class :type t :initform ',type) ,@immediates)))))) (macrolet ((create-instr-classes (raw) `(progn ,@(mapcar #'expand-instr-plist raw)))) (create-instr-classes #.sarcasm.raw-instrs:raw-instrs))