Lisps are a family of programming languages based on lambda calculus and symbolic metaprogramming. The main appeal of Lisp is being able to edit itself and extend its own syntax. This allows Lisp users to implement abstractions such as OOP themselves instead of waiting for the language implementation to evolve.
Metaprogramming means writing programs that write programs. This is what Lisp users do when they extend the language. In the case of Antilisp, this also refers to being a cross-transpiled code generation and building language.
(for (i (range 10))
(print i))
; -> 0 1 2 3 4 5 6 7 8 9
Antilisp is based on modern abstractions from modern languages. This makes the language easy to learn even for non-lispers.
(print (list 1 2 3)) ; -> (1 2 3)
Lisp is a high level dynamically typed language, like Python or Javascript. Everything is an expression, and every syntax element or function call is delimited by parenthesis.
(defmacro (let name value . body)
`((fn (,name)
,@body)
,value))
; JS equivalent:
; (function(x) {
; f(x);
; g(x);
; })(preload_stuff())
(let x (preload-stuff)
(f x)
(g x))
Lisp has a powerful syntax expansion system. Define your own abstractions to match your needs.
; example from https://docs.github.com/en/actions/writing-workflows/quickstart
(load "modules/github-actions.lisp")
(def (echo text)
; (sum) uses the object-oriented (+) and supports any type for which (+) is defined
(sum
(list
"echo "
(yaml-quote text))))
;(print (echo "message"))
; -> echo "message"
(save-workflow ".github/workflows/github-actions-demo.yml"
(workflow "GitHub Actions Demo" "push"
;; the run-name field is not implemented in the library:
;'run-name "${{ github.actor }} is testing out GitHub Actions 🚀"
; declare the jobs
(job "Explore-GitHub-Actions" "ubuntu-latest"
; as you can see, the syntax is very easy to understand
(run "echo \"🎉 The job was automatically triggered by a ${{ github.event_name }} event.\"")
; but escaping quotes to nest the echo parameter is annoying
(run "echo \"🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!\"")
; let's abstract it:
(run (echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."))
(use
; optional fields can be set with keyword (named) arguments
'name "Check out repository code"
"actions/checkout@v4")
(run (echo "💡 The ${{ github.repository }} repository has been cloned to the runner."))
(run (echo "🖥️ The workflow is now ready to test your code on the runner."))
(run
'name "List files in the repository"
"ls ${{ github.workspace }}")
(run (echo "🍏 This job's status is ${{ job.status }}.")))))
Antilisp is designed for cross-language code manipulation. Apply the power of Lisp metaprogramming to any other language to get the job done.
cat .github/workflows/github-actions-demo.yml
name: GitHub Actions Demo
on: [push]
jobs:
Explore-GitHub-Actions:
runs-on: ubuntu-latest
steps:
- run: "echo \"🎉 The job was automatically triggered by a ${{ github.event_name }} event.\""
- run: "echo \"🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!\""
- run: "echo \"🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}.\""
- uses: "actions/checkout@v4"
name: "Check out repository code"
- run: "echo \"💡 The ${{ github.repository }} repository has been cloned to the runner.\""
- run: "echo \"🖥️ The workflow is now ready to test your code on the runner.\""
- run: "ls ${{ github.workspace }}"
- run: "echo \"🍏 This job's status is ${{ job.status }}.\""
Once your source code is generated, you can stop using Antilisp and forget about it, since you still have the code you generated.
; (char-parser "my source code" index) -> (new-index . char) | nil
(def char-parser (source position)
(if (is-eof source position)
nil
(cons (+ 1 position) (get-char source position))))
; add the parser to the set of value readers used by the langage
(set value-readers (cons char-parser value-readers))
"All the language available all the time" is one of the main philosophies of Lisp. Rewrite the Antilisp code parser from within Antilisp, or just override builtins if you want to. Adapt the language to your requirements.
Note: custom readers are not finished implementing yet
(print (repr current-scope))
-> (dict
:parent-scope nil
:true true
:false false
:nil nil
:type <type type>
:integer <type int>
:string <type str>
...
:to-string (fn (x) ...)
:repr (fn (x) ...)
...
:get-doc <native function get_doc>
:set-doc <native function set_doc>
...
:method-store (dict
:repr ...
:+ ...
:length ...
:at ...
:iter ...
:to-symbol ...
:to-string ...)
...)
(print (get-doc method-store))
-> internal dictionary used by generics to store and retrieve methods
Another tenet of Lisp is that everything is a first-class citizen. This means functions, classes, code, documentation and even the state of the program are represented as values.
In Antilisp, you can also just print the literal representation of a value with (repr) to get its definiton, or get the documentation of something with (get-doc).
Want to check examples ?
Start with the documentation
Or,
Download and start hacking