GithubHelp home page GithubHelp logo

ariane-emory / tiny-lisp Goto Github PK

View Code? Open in Web Editor NEW

This project forked from matp/tiny-lisp

0.0 0.0 0.0 67 KB

A small implementation of LISP, written in standard C11.

License: The Unlicense

C 98.53% Makefile 1.47%

tiny-lisp's Introduction

tiny-lisp

tiny-lisp is a small implementation of LISP, written in standard C11. It is intended to show how features such as macros, tail recursion and a copying garbage collector can be implemented in C.

Language features

  • read-eval-print loop
  • numbers, strings, symbols and lists
  • functions and macros
  • lexical scoping
  • scheme-style dotted parameter lists
  • scheme-style tail recursion
  • copying garbage collector

Numeric operations

tiny-lisp supports the four arithmetic operations +, -, *, / as well as the relational operations =, <, <=, >, >=:

(- 5)                  ; -5
(- 5 3.2 .6)           ; 1.2
(< 2 4 6.8)            ; t
(> 4 8)                ; nil

List operations

(list ...) returns a list containing the supplied arguments:

(list)                 ; nil
(list 1 2 3)           ; (1 2 3)
(list 1 2 (+ 1 2))     ; (1 2 3)

(cons x y) creates a new cons cell, the car of which is x and the cdr of which is y:

(cons 1 2)             ; (1 . 2)
(cons 1 '(2))          ; (1 2)

(car x), (cdr x) return the car and cdr of a list respectively:

(car '(1 2 3))         ; 1
(cdr '(1 2 3))         ; (2 3)

Predicates

(eq x y) returns t if x and y refer to the same object, or if they are numbers with the same value, or if they are string objects with identical content:

(eq 1 1)               ; t
(eq 1 2)               ; nil
(eq 'a 'a)             ; t
(eq 'a 'b)             ; nil
(eq "hello" "hello")   ; t
(eq "hello" "world")   ; nil
(eq '(1 2) '(1 2))     ; nil

(equal x y) returns t if x and y are objects of identical structure and each of their elements satisfy the eq predicate, otherwise nil:

(equal '(1 2) '(1))    ; nil
(equal '(1 2) '(1 2))  ; t

(null x) returns t if x is nil, otherwise nil:

(null nil)             ; t
(null 1)               ; nil
(null "hello")         ; nil
(null '(1 2))          ; nil

(atom x) returns t if x is not a cons cell, otherwise nil:

(atom nil)             ; t
(atom 1)               ; t
(atom "hello")         ; t
(atom '(1 2))          ; nil

(consp x) returns t if x is a cons cell, otherwise nil:

(consp nil)            ; nil
(consp 1)              ; nil
(consp "hello")        ; nil
(consp '(1 2))         ; t

(listp x) returns t if x is a cons cell or nil, otherwise nil:

(listp nil)            ; t
(listp 1)              ; nil
(listp "hello")        ; nil
(listp '(1 2))         ; t

(zerop x) returns t if x is the number zero, otherwise nil:

(zerop 0)              ; t
(zerop 1)              ; nil
(zerop "hello")        ; error: "hello" is not a number

Logical operations

(not x) returns t if x is nil, otherwise nil (not is therefore identical to null, but is usually used in conjunction with boolean logic).

(and ...) evaluates its arguments one at a time from left to right. As soon as any argument evaluates to nil, and returns nil without evaluating the remaining arguments. Otherwise, it returns the value produced by evaluating its last argument. If no arguments are supplied, and returns t:

(and)                  ; t
(and 1 2 3)            ; 3
(and 1 nil 3)          ; nil

(or ...) evaluates its arguments one at a time from left to right. As soon as any argument does not evaluate to nil, or returns its value without evaluating the remaining arguments. Otherwise, it returns nil:

(or)                   ; nil
(or 1 2 3)             ; 1
(or nil nil 3)         ; 3

Output operations

(princ x) prints x to the standard output:

(princ "Hello!\n")     ; prints Hello! followed by a newline

(print x) is similar to princ but its output is preceded by a newline and followed by a space. In addition, print differs in its handling of strings which it outputs exactly the way they were entered, including reproducing escape sequences:

(print "\"a\\b\"\n")   ; prints "\"a\\b\"\n"

Conditionals

(if test then [else]) returns the result of evaluating then if test does not evaluate to nil, otherwise returns the result of evaluating else or nil:

(if 1 2 3)             ; 2
(if nil 2 3)           ; 3
(if nil 2)             ; nil

(cond ...) takes zero or more clauses, each of the form (test [expr...]). cond returns the result of evaluating expr... of the first clause for which test does not evaluate to nil without evaluating the remaining clauses. If a clause does not supply expr..., the result of evaluating test is returned instead. If every test evaluates to nil, or no clauses are given, cond returns nil:

(cond)                 ; nil
(cond (nil "hello")
      (t   "world"))   ; "world"
(cond (nil "hello")
      ("world"))       ; "world"

Defining variables

(setq name expr ...) binds the result of evaluating expr to the symbol name. More than one name-expr pair can be given. setq returns the value bound to the last symbol:

(setq a 1
      b 2)             ; 2
a                      ; 1
b                      ; 2

Defining functions

(lambda params expr...) creates an anonymous function with parameters params and body expr.... params can be nil, a symbol, or a list of symbols. If params is a symbol or a dotted list of symbols, the function will accept a variable number of arguments:

((lambda nil
   "hello"))           ; "hello"
((lambda (a b)
   (+ a b)) 1 2)       ; 3
((lambda (a b . c)
   c) 1 2 3 4 5)       ; (3 4 5)
((lambda args
   args) 1 2 3 4 5)    ; (1 2 3 4 5)

(defun name params expr...) creates a function and binds it to the symbol name:

(defun plus1 (x)
  (+ x 1))             ; #<Lambda (x)>
(plus1 2)              ; 3

Defining macros

(macro params expr...) creates an anonymous macro with parameters params and body expr....

(defmacro name params expr...) creates a macro and binds it to the symbol name.

Macros are different from functions in that they do not evaluate their arguments when called. Instead, we can think of them as taking expressions as input and returning a new expression as output.

Imagine we want to implement (when test expr...):

(setq x '(1 2 3))      ; (1 2 3)
(when (consp x)
      (car x))         ; 1
(setq x "hello")
(when (consp x)
      (car x))         ; nil

when, if implemented as a function, would not work correctly, since expr... would be evaluated as soon as when is called:

(setq x "hello")
(when (consp x)
      (car x))         ; error: "hello" is not a list

However, we can implement when as a macro that wraps expr... in a call to if:

(defmacro when (test . expr)
  (list 'if test (cons 'progn expr)))

(when (consp x) (car x)) would then produce the expression (if (consp x) (progn (car x))) which yields the expected behaviour.

tiny-lisp's People

Contributors

ariane-emory avatar matp avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.