A light lisp written in C++

Overview

wisp

A light lisp written in C++ Wisp

Why write a lisp?

Lisp is one of those niche, beautiful languages that people only really use to either

  1. Write a lisp interpreter
  2. Show off how "code is data!!!"

So why add to the list of infinite lisp interpreters?

The answer is simple: I'm bored out of my mind in quarantine. If you were looking to find out why this particular lisp is special, you're fresh out of luck.

But isn't the fact that it's a lisp enough?

Lisp

yes.

Syntax and Special Forms

Like every other lisp, this language uses s-expressions for code syntax and data syntax. So, for example, the s-expression (print 5) is both a valid code snippet, and a valid list containing the items print and 5.

When the data (print 5) is evaluated by the interpreter, it evaluates print and 5, and then applies print to 5.

Here's the result.

>>> (print 5)
5
 => 5

That's super cool! But what if we want to define our own functions? We can use the builtin function defun!

; define a function `fact` that takes an argument `n`
(defun fact (n)
  (if (<= n 1)
     1
     (* n (fact (- n 1)))
   ))

Thats awesome! But did you notice anything different about the defun function? It doesn't evaluate its arguments. If the atom fact were evaluated, it would throw an error like so:

>>> fact
error: the expression `fact` failed in scope { } with message "atom not defined"

This is known as a special form, where certain functions "quote" their arguments. We can quote things ourselves too, but the language automatically quotes arguments to special forms itself.

If you want to "quote" a value yourself, you can do it like this.

; quote the s-expression (1 2 3) so it's not evaluated
>>> (print '(1 2 3))
(1 2 3)
 => (1 2 3)

As you can see, quote negates an evaluation. For example, whenever the expression ''a is evaluated, it becomes 'a. This can be useful for when you want to write long lists of data or variable names without wanting to evaluate them as code.

Special Form Argument Evaluations Purpose
(if cond a b) if only evaluates its cond argument. If cond is truthy (non-zero), then a is evaluated. Otherwise, b is evaluated. This special form is the main method of control flow.
(do a b c ...) do takes a list of s-expressions and evaluates them in the order they were given (in the current scope), and then returns the result of the last s-expression. This special form allows lambda functions to have multi-step bodies.
(scope a b c ...) scope takes a list of s-expressions and evaluates them in the order they were given in a new scope, and then returns the result of the last s-expression. This special form allows the user to evaluate blocks of code in new scopes.
(defun name params body) defun evaluates none of its arguments. This special form allows the user to conveniently define functions.
(define name value) define evaluates the value argument, which is then assigned to name in the current scope. This special form allows the user to bind atoms to values in a scope.
(lambda params body) lambda evaluates none of its arguments. This special form allows the user to define anonymous functions.
(quote x) quote evaluates none of its arguments. This is equivalent to the 'expr syntactic sugar.
(for x list ...) for evaluates only its list argument. for iterates through the list storing each element in x, and then evaluating all of the rest of the values in the for body. It then returns the last value evaluated.
(while cond ...) while evaluates only its cond argument. while evaluates its condition expression every iteration before running. If it is true, it continues to evaluate every expression in the while body. It then returns the last value evaluated.

Examples

Here are some example math-y functions to wrap your head around.

; quicksort
(defun qs (l)
    (if (<= (len l) 1)
        l
        (do
            (define pivot (first l))
            (+
                (qs (filter (lambda (n) (> pivot n)) l))
                (list pivot)
                (qs (tail (filter (lambda (n) (<= pivot n)) l)))
            ))
    ))

; decrement a number
(defun dec (n) (- n 1))
; increment a number
(defun inc (n) (+ n 1))
; not a bool
(defun not (x) (if x 0 1))

; negate a number
(defun neg (n) (- 0 n))

; is a number positive?
(defun is-pos? (n) (> n 0))
; is a number negative?
(defun is-neg? (n) (< n 0))

Usage

Using and compiling wisp

Dependencies

Compile with your C++ compiler of choice. This is compatible with all standard versions of C++ since ANSI C++.

$ git clone https://github.com/adam-mcdaniel/wisp
$ cd wisp
$ g++ wisp.cpp -o wisp

Using the binary

Run wisp in interactive mode:

$ ./wisp
>>> (print "Hello world!")
Hello world!
 => "Hello world!"

Interpret a file:

$ ./wisp -f "examples/hello_world.lisp"
Hello world!

Interpret from command line argument:

$ ./wisp -c '(print "Hello world!")'
Hello world!
Comments
  • Sorry but, Wisp already exists, twice! It's Lisp without parentheses

    Sorry but, Wisp already exists, twice! It's Lisp without parentheses

    Sorry but, Wisp already exists, twice! It's Lisp without parentheses: http://dustycloud.org/blog/wisp-lisp-alternative/

    https://github.com/Gozala/wisp

    opened by madnight 1
  • tidy-related fixes

    tidy-related fixes

    • parameters copied for each invocation but used as const references; refactored into const references
    • use nullptr
    • use range-based for loops
    • use empty method whenever possible
    opened by 0x00b1 0
  • Lambdas only capture atoms that are used in their bodies

    Lambdas only capture atoms that are used in their bodies

    Before, lambda expressions would capture all items in scope. This allows for code like this to work:

    (defun true (x)
        (lambda (y) (eval (first (parse "x")))))
    

    When (lambda (y) (eval (first (parse "x")))) is evaluated when true is called, it captures the value of x even though the atom x is not used. With this pull request, this will not be true anymore.

    To be captured, the atom x must be used in the body of the returned lambda like so.

    (defun true (x)
        (lambda (y) x))
    ;; or
    (defun true (x)
        (lambda (y) (eval 'x)))
    

    Although this removes some functionality, it provides an utterly massive speed boost. Instead of each function being extremely heavy and carrying the environment of the entire program, they only store as many values as they need.

    enhancement 
    opened by adam-mcdaniel 0
  • parsing numbers, wrong code

    parsing numbers, wrong code

    I think there is error in parsing numbers on line std::string n = s.substr(save_ptr, ptr); which sometimes evaluates int as float (when somewhere later in string there is a ".".. I think there should be (ptr - save_ptr) as a second parameter to substr.

    opened by vaclavt 0
  • Problem with parsing comments

    Problem with parsing comments

    There is problem (exception malformed program) when trying to run this program.

    (print "ahoj" ; this comment is problem ) (print "lisp")

    The important thing is comment before closing bracket.

    opened by vaclavt 0
  • avoid the binary name clash with wisp

    avoid the binary name clash with wisp

    Currently there’s a name clash with the wisp binary from the Whitespace to Lisp project: https://www.draketo.de/english/wisp

    wisp 1.0.3 provides a wisp binary, so that wisp and this project cannot be installed on the same system without deduplicating names.

    opened by ArneBab 0
Owner
adam mcdaniel
Programmer and Musician
adam mcdaniel
Decoding light morse code with a light dependent resistor and Arduino board

Morse decoder The project's idea is very simple, the Arduino program has the responsibility to upload the sensor's data to the USB serial port.

null 15 Mar 12, 2022
Common Lisp and CXX interoperation with JIT

CL-CXX-JIT - Common Lisp C++ JIT for exposing C++ functions This library provides an interface to C++ from lisp. It compiles C++ code, then loads it i

Islam Omar 38 Aug 24, 2022
tree-sitter grammar for emacs lisp

Tree-sitter Grammar for Emacs Lisp A simple tree-sitter grammar for elisp. Syntax supported: Atoms (integers, floats, strings, characters, symbols) Li

Wilfred Hughes 21 Sep 12, 2022
aLisp - a custom Lisp in C

aLisp aims to become a hackable, embeddable, reasonably fast interpreted custom Lisp implemented in portable C.

Andreas Nilsson 7 Jan 10, 2022
Clio is an embryonic experiment in UI for Common Lisp programs.

Clio Clio is an embryonic experiment in UI for Common Lisp programs. Building and running Clio Make sure you have the prerequisites: Visual Studio 201

mikel evins 0 Feb 26, 2022
Common Lisp editor/IDE with high expansibility

Lem is the editor/IDE well-tuned for Common Lisp. After installing lem, you can start developing in Common Lisp at once. You can skip over writing tid

null 1.3k Oct 2, 2022
CAAR is an attempt at writing a modern Lisp machine.

CAAR - The modern lisp machine CAAR is an attempt at writing a modern Lisp machine. The goal of this project is to be able to run a somewhat functiona

Abbix 10 Jun 19, 2022
Pandex is a light but FAST programming language written in C . Pandex goal is that be hard & it's good for eductional goals

The Pandex programming language version 1.0.0.3 Pandex versions release type The Pandex version has four numbers. the first number holds 1 ( or 0 in s

null 8 May 23, 2022
Poseidon OS (POS) is a light-weight storage OS

Poseidon OS Poseidon OS (POS) is a light-weight storage OS that offers the best performance and valuable features over storage network. POS exploits t

null 48 Sep 23, 2022
A light-weight Flutter Engine Embedder based on HADK ,which for Android devices that runs without any java code

flutter-hadk A light-weight Flutter Engine Embedder based on HADK ,which for Android devices that runs without any java code 1.Build by android-ndk-to

null 12 Jun 15, 2022
Home automation light switch controller

Home Automation Light Switch Controller Copyright 2019-2021 SuperHouse Automation Pty Ltd www.superhouse.tv A modular Light Switch Controller for DIY

SuperHouse Automation 11 Mar 27, 2022
Analytics In Real-time (AIR) is a light-weight system profiling tool

Analytics In Real-time Analytics In Real-time (AIR) is a light-weight system profiling tool that provides a set of APIs for profiling performance, lat

null 2 Mar 3, 2022
DIY Zigbee CC2530 Motion sensor (AM312/ AM412/ BS312/ BS412), Temperature /Humidity /Pressure sensor (BME280), Ambient Light sensor (BH1750), 2.9inch e-Paper Module

How to join: If device in FN(factory new) state: Press and hold button (1) for 2-3 seconds, until device start flashing led Wait, in case of successfu

Sergey Koptyakov 5 Feb 13, 2022
DIY Zigbee CC2530 Motion sensor (AM312/ AM412/ BS312/ BS412), Temperature /Humidity /Pressure sensor (BME280), Ambient Light sensor (BH1750), 2.9/2.13/1.54 inch e-Paper Module

How to join: If device in FN(factory new) state: Press and hold button (1) for 2-3 seconds, until device start flashing led Wait, in case of successfu

Sergey Koptyakov 29 Sep 11, 2022
TinyTouchLight - Dimmable USB Night Light with Capacitive Touch Control

TinyTouchLight - Dimmable USB Night Light with Capacitive Touch Control

Stefan Wagner 9 Jun 13, 2022
Windows 10 interface adjustment tool supports automatic switching of light and dark modes, automatic switching of themes and transparent setting of taskbar

win10_tools Windows 10 interface adjustment tool supports automatic switching of light and dark modes, automatic switching of themes and transparent s

Simon 1 Dec 3, 2021
Fast and Light-weight path smoothing methods for vehicles

path_smoother About Fast and Light-weight path smoothing methods for vehicles Denpendencies This project has been tested on Ubuntu 18.04. sudo apt-get

MingwangZhao 4 Dec 1, 2021
Simple, Fast, Light weight

Welcome To PradoshOS Github! Index Main heading Setup Step 1 Step 2 Step 3 Step 4 Compilation of Bootloader Compilation of Kernel Compilation of Userl

S Pradosh 10 Aug 5, 2022
Visual-inertial-wheel fusion odometry, better performance in scenes with drastic changes in light

VIW-Fusion An visual-inertial-wheel fusion odometry VIW-Fusion is an optimization-based viusla-inertial-wheel fusion odometry, which is developed as a

庄庭达 213 Sep 28, 2022