Skip to content

Instantly share code, notes, and snippets.

View spacebat's full-sized avatar

Andy Kirkpatrick spacebat

  • Adelaide, South Australia
View GitHub Profile
@spacebat
spacebat / with-output-to-stream.lisp
Created July 11, 2020 01:51
Flexible macro to output to a stream (default returns a string)
(defmacro with-output-to-stream ((var &optional stream &key (element-type 'character)) &body body)
(let ((gstream (gensym "STREAM"))
(gresult (gensym "RESULT")))
`(let* ((,gstream ,stream)
(,var (case ,gstream
((t) *standard-output*)
((nil) (make-string-output-stream :element-type ',element-type))
(otherwise ,gstream)))
(,gresult (multiple-value-list (progn ,@body))))
(if ,gstream
@spacebat
spacebat / ecl-build.lisp
Created April 8, 2020 23:27
Create and run a standalone exeutable in ECL
(with-open-file (f "print-args.lisp" :direction :output :if-does-not-exist :create :if-exists :overwrite)
(dolist (expr '((defun print-args ()
(princ (cdr (ext:command-args))))
(print-args)
(quit)))
(prin1 expr f)
(terpri f))
(force-output f))
(defparameter *object-file* (compile-file "print-args.lisp" :system-p t))
;; See https://tailrecursion.com/jlt/posts/collecting-macro-edition.html
;; Shared implementation of collector, providing a standalone collector
;; via MAKE-COLLECTOR and an flet-scoped collector via WITH-COLLECTOR
(defun %collector-impl (head tail)
(let* ((item (gensym "ITEM"))
(item-passed (gensym "ITEM-PASSED"))
(new-tail (gensym "NEW-TAIL")))
`((&optional (,item nil ,item-passed))
(ql:quickload :closer-mop)
(defclass foo ()
((bar :initarg :bar :initform nil :reader foo-bar)))
(defclass fuu (foo)
((baz :initarg :baz :initform nil :reader fuu-baz)))
(defmethod print-object ((f foo) stream)
(print-unreadable-object (f stream :type t)))
@spacebat
spacebat / condition-case+.el
Last active March 28, 2018 22:27
An extension to the syntax of condition-case to support else and finally cases
;; This gist licensed GPLv3
(cl-defmacro condition-case+ (var form (&rest handlers/else/finally))
"Like condition-case, only if the last handlers have matching
forms of :else or :finally. In that case, the body of an :else
handler is evaluated if no exception was thrown. The body of
a :finally clause is evaluated always as the last thing before
the form is exited whether normally or not. If both :else
and :finally appear among the handlers, :else must be second last
and :finally must be last."
(cl-flet ((maybe-split-last (symbol handlers)
@spacebat
spacebat / with-container-map.lisp
Created January 21, 2018 23:08
Generic container iteration
(defgeneric call-with-container-map (container func)
(:documentation "Iterate over the contents of CONTAINER, calling
FUNC with the current element of CONTAINER, followed by the index or
key that corresponds to it."))
(defmethod call-with-container-map ((container array) func)
(loop for index from 0
for value across container
do (funcall func value index)))
@spacebat
spacebat / moo.rb
Created October 31, 2017 02:02
Module, class and a default instance
#!/usr/bin/env ruby
# Attempt to make a module with methods that default to using state in
# a default instance of a class within the module, yet allow for
# specific instances of the class to be produced with their own state,
# that share these same module methods. It boils down to using the
# module method this in place of self.
module Moo
extend self
@spacebat
spacebat / truncated-compilation-mode.el
Created November 29, 2016 13:14
An Emacs global minor mode that prevents lines in compilation buffers from growing too long
(defvar truncated-compilation-line-limit 70)
(defvar truncated-compilation-line-trailer "…")
;; TODO: convert this from a post filter hook to advice on a
;; configured set of filter functions to prevent the insertion of text
;; constituting overlong lines in the first place
;;;###autoload
@spacebat
spacebat / sq.lisp
Last active November 10, 2016 23:46
(defmacro sq (variable value &optional (documentation nil documentation-p))
"REPL-friendly alternative-to/merger-of setq and defparameter."
(assert (and variable (symbolp variable)))
(alexandria:once-only (value)
`(cond
((boundp ',variable)
,@(when documentation-p
`((setf (documentation ',variable 'variable) ,documentation)))
(setf ,variable ,value))
(t
(defpackage :99-bottles
(:use :cl)
(:export #:print-song))
(in-package :99-bottles)
(defun wrap (number)
(if (minusp number)
(+ number 100)
number))