by Macoy Madson
A transpiling language with an emphasis on compile-time code generation.

This is a programming language where I can have my cake and eat it too.

The goal is a metaprogrammable, hot-reloadable, non-garbage-collected language ideal for high performance, iteratively-developed programs (especially games).

It is a transpiler which generates C/C++ from an S-expression syntax. Cakelisp takes some inspiration from Lisp, but is not compatible and does not aspire to become "a Lisp".

I was inspired by Naughty Dog's use of GOAL, GOOL, and Racket/Scheme (on their modern titles). I've also taken several ideas from Jonathan Blow's talks on Jai.

You can also read the introduction to Cakelisp.

The main repository is here.

(add-cakelisp-search-directory "runtime")
(import "ComptimeHelpers.cake" "CHelpers.cake")

(c-import "<stdio.h>" "<string.h>" "<stdbool.h>")

(defmacro hello-from-macro ()
  (tokenize-push output
    (fprintf stderr "Hello from macro land!\n"))
  (return true))

(defmacro defcommand (command-name symbol arguments array &rest body any)

  (get-or-create-comptime-var environment command-table (template (in std vector) (addr (const Token))))
  (call-on-ptr push_back command-table command-name)

  (tokenize-push output
    (defun (token-splice command-name) (token-splice arguments)
      (token-splice-rest body tokens)))
  (return true))

(defcommand say-your-name ()
  (fprintf stderr "your name.\n"))

(defun-comptime create-command-lookup-table (environment (ref EvaluatorEnvironment) &return bool)
  (get-or-create-comptime-var environment command-table-already-created bool false)
  (when (deref command-table-already-created)
    (return true))
  (set (deref command-table-already-created) true)

  (get-or-create-comptime-var environment command-table (template (in std vector) (addr (const Token))))

  (var command-data (addr (template std::vector Token)) (new (template std::vector Token)))
  (call-on push_back (field environment comptimeTokens) command-data)

  (for-in command-name (addr (const Token)) (deref command-table)
    (printFormattedToken stderr (deref command-name))
    (fprintf stderr "\n")

    (var command-name-string Token (deref command-name))
    (set (field command-name-string type) TokenType_String)

    (tokenize-push (deref command-data)
      (array (token-splice-addr command-name-string)
             (token-splice command-name))))

  (prettyPrintTokens (deref command-data))

  (var command-table-tokens (addr (template std::vector Token)) (new (template std::vector Token)))
  (call-on push_back (field environment comptimeTokens) command-table-tokens)
  (tokenize-push (deref command-table-tokens)
    (var command-table (array command-metadata)
      (array (token-splice-array (deref command-data)))))
  (prettyPrintTokens (deref command-table-tokens))

  (return (ClearAndEvaluateAtSplicePoint environment "command-lookup-table" command-table-tokens)))

(add-compile-time-hook post-references-resolved
                       create-command-lookup-table)

;; Our command functions take no arguments and return nothing
(def-function-signature command-function ())

(defstruct-local command-metadata
  name (addr (const char))
  command command-function)

(splice-point command-lookup-table)

(defun main (num-arguments int
             arguments (array (addr char))
             &return int)
  (fprintf stderr "Available commands:\n")
  (each-in-array command-table i
    (fprintf stderr "  %s\n"
             (field (at i command-table) name)))

  (unless (= 2 num-arguments)
    (fprintf stderr "Expected command argument\n")
    ;; Commented for easy integration in RunTests.cake only
    ;;(return 1))
    (return 0))

  (fprintf stderr "Hello, Cakelisp!\n")
  (hello-from-macro)

  (var found bool false)
  (each-in-array command-table i
    (when (= 0 (strcmp (field (at i command-table) name) (at 1 arguments)))
      (call (field (at i command-table) command))
      (set found true)
      (break)))
  (unless found
    (fprintf stderr "error: could not find command '%s'\n" (at 1 arguments))
    (return 1))
  (return 0))

(set-cakelisp-option executable-output "test/Tutoral_Basics")
Information updated 09/29/23
View Comments