From f190f404028de7ee5b4b6cf9a6e531e50c3c397c Mon Sep 17 00:00:00 2001 From: FelixBrendel Date: Wed, 20 May 2020 23:20:47 +0200 Subject: [PATCH] Using ftb print and updated the doc generation --- .gitignore | 2 + 3rd/ftb | 2 +- bin/pre.slime | 25 +- build.bat | 12 +- manual/build.bat | 22 + manual/built-in-docs.tex | 1014 ------------ manual/manual.html | 3236 -------------------------------------- manual/manual.org | 1 + src/assert.hpp | 24 +- src/built_ins.cpp | 215 ++- src/docgeneration.cpp | 81 +- src/env.cpp | 60 +- src/error.cpp | 10 +- src/eval.cpp | 431 ++--- src/forward_decls.cpp | 14 +- src/io.cpp | 199 ++- src/libslime.cpp | 23 +- src/lisp_object.cpp | 20 - src/memory.cpp | 22 +- src/structs.cpp | 2 +- src/testing.cpp | 27 +- 21 files changed, 620 insertions(+), 4822 deletions(-) create mode 100644 manual/build.bat delete mode 100644 manual/built-in-docs.tex delete mode 100644 manual/manual.html diff --git a/.gitignore b/.gitignore index b4dd02a..d74393f 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ todo.html /bin/slime_d /bin/slime_p *.json +/bin/manual.pdf +/bin/manual.tex diff --git a/3rd/ftb b/3rd/ftb index a77b139..dc98c61 160000 --- a/3rd/ftb +++ b/3rd/ftb @@ -1 +1 @@ -Subproject commit a77b1393050001991382a9bac3f395cf9c463f32 +Subproject commit dc98c61901fe01da4e3f1df4325d3f2d041f3700 diff --git a/bin/pre.slime b/bin/pre.slime index 01aa06a..987240f 100644 --- a/bin/pre.slime +++ b/bin/pre.slime @@ -1,10 +1,3 @@ -;; (remove_when_double_free_is_fixed) -;; (remove_when_double_free_is_fixed_2) -;; (define (kk (:key ())) -;; ()) - -;; (kk) - (define pair cons) (define first car) (define rest cdr) @@ -117,7 +110,25 @@ condition is false." (define unzipped (unzip bindings)) `((,lambda ,(car unzipped) ,@body) ,@(car (cdr unzipped)))) +(define-macro (while cond . body) + (let ((gs (gensym))) + `(,let ((,gs ())) + (,set! ,gs + (,lambda () + (,when ,cond + ,@body + (,gs)))) + (,gs)))) + (define-macro (cond . clauses) + "Example usage: + (define (prime? x) + (define (rec i) + (cond ((> i (** x 0.5)) t) + ((= 0 (% x i)) ()) + (else (rec (+ 1 i)))) + ) + (rec 2))" (define (rec clauses) (if (= () clauses) () diff --git a/build.bat b/build.bat index 93a0e27..004f579 100644 --- a/build.bat +++ b/build.bat @@ -7,25 +7,31 @@ set exeName=slime.exe taskkill /F /IM %exeName% > NUL 2> NUL echo ---------- Compiling ---------- -call cl ^ +call ..\timecmd cl ^ ../src/main.cpp^ /I../3rd/ ^ /D_PROFILING /D_DEBUG /D_DONT_BREAK_ON_ERRORS ^ /Zi /std:c++latest /Fe%exeName% /W3 /wd4003 /wd4996 /nologo /EHsc + rem call ..\timecmd cl ^ rem ../src/main.cpp^ rem /I../3rd/ ^ rem /O2 /D_DONT_BREAK_ON_ERRORS ^ rem /std:c++latest /Fe%exeName% /W3 /wd4003 /nologo /EHsc -rem call ..\timecmd clang-cl ../src/main.cpp -o %exeName% /O2 /std:c++latest /W3 /Zi /EHsc +rem call ..\timecmd clang-cl ../src/main.cpp /I../3rd/ -o %exeName% /O2 /std:c++latest /W3 /Zi /EHsc if %errorlevel% == 0 ( echo. echo -------- Running Tests -------- echo. - call slime.exe --run-tests + call ..\timecmd slime.exe --run-tests + echo. + echo -------- Generatign Docs -------- + echo. + call ..\timecmd slime.exe --generate-docs-file + rem call ..\manual\build.bat ) else ( echo. echo Fuckin' ell diff --git a/manual/build.bat b/manual/build.bat new file mode 100644 index 0000000..80e9118 --- /dev/null +++ b/manual/build.bat @@ -0,0 +1,22 @@ +@echo off +@setlocal +pushd %~dp0\bin + +echo ================================================ +echo Starting Tex Export +echo ================================================ + +set FILENAME=manual + +emacsclient -c --frame-parameters="((visibility . nil))" -e "(progn (require 'org) (find-file-other-window \"%FILENAME%.org\") (org-latex-export-to-latex) (save-buffers-kill-terminal))" || exit 1 + + +echo ================================================ +echo Tex Export Finished +echo ================================================ + + +latexmk -Werror -pdf -shell-escape %FILENAME%.tex || exit 1 +latexmk -c %FILENAME%.tex + +popd diff --git a/manual/built-in-docs.tex b/manual/built-in-docs.tex deleted file mode 100644 index 8ad092a..0000000 --- a/manual/built-in-docs.tex +++ /dev/null @@ -1,1014 +0,0 @@ -% Created 2019-06-11 Di 00:15 -% Intended LaTeX compiler: pdflatex -\documentclass[11pt]{article} -\usepackage[utf8]{inputenc} -\usepackage[T1]{fontenc} -\usepackage{fixltx2e} -\usepackage{graphicx} -\usepackage{grffile} -\usepackage{longtable} -\usepackage{wrapfig} -\usepackage{rotating} -\usepackage[normalem]{ulem} -\usepackage{amsmath} -\usepackage{textcomp} -\usepackage{amssymb} -\usepackage{capt-of} -\author{Felix Brendel} -\date{\today} -\title{} -\begin{document} - -\tableofcontents - -\section*{\texttt{=}} -\label{sec:org31e3235} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:158:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] Takes 0 or more arguments and returns \texttt{t} if all arguments are equal and \texttt{()} otherwise. -\end{description} - -\section*{\texttt{>}} -\label{sec:org11b65ef} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:175:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{>=}} -\label{sec:org040fc2d} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:193:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{<}} -\label{sec:org495ac8d} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:211:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{<=}} -\label{sec:orgb3d6d87} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:231:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{+}} -\label{sec:org497d901} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:249:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{-}} -\label{sec:org04ab2bb} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:262:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{*}} -\label{sec:org42f3ed5} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:285:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{/}} -\label{sec:org60f7896} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:306:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{**}} -\label{sec:orgb860d63} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:327:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{\%}} -\label{sec:org7679821} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:343:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{assert}} -\label{sec:org81e23f7} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:359:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{define}} -\label{sec:org501614a} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:371:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{mutate}} -\label{sec:org6ba42c6} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:433:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{if}} -\label{sec:orga57c0cf} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:458:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{quote}} -\label{sec:org6ee47a1} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:480:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{quasiquote}} -\label{sec:org1573170} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:485:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{and}} -\label{sec:org9185975} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:583:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{or}} -\label{sec:org1e61c07} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:594:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{not}} -\label{sec:orgf60a5bd} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:605:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{while}} -\label{sec:orgfb64aca} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:615:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{lambda}} -\label{sec:orga60bbea} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:693:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{special-lambda}} -\label{sec:org3ea00e3} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:705:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{eval}} -\label{sec:orga586c08} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:713:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{begin}} -\label{sec:orgb188fed} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:725:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{list}} -\label{sec:org63b9132} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:741:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{pair}} -\label{sec:orge6d9e03} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:745:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{first}} -\label{sec:org6968e67} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:755:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{rest}} -\label{sec:org6f558af} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:766:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{set-type}} -\label{sec:org8ff89e6} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:777:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{delete-type}} -\label{sec:orgc4df119} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:789:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{type}} -\label{sec:orge39cac6} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:796:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{info}} -\label{sec:orgf3fb347} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:828:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{show}} -\label{sec:orgae18d02} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:910:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{addr-of}} -\label{sec:org09ce813} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:922:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{generate-docs}} -\label{sec:org055dade} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:928:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{print}} -\label{sec:org51e9ac8} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:937:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{read}} -\label{sec:org986a33f} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:945:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{exit}} -\label{sec:org3a6dddf} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:962:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{break}} -\label{sec:orga45e393} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:973:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{memstat}} -\label{sec:orgd8c6a3a} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:978:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{try}} -\label{sec:orgdf2db5f} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:982:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{load}} -\label{sec:org60ee1c1} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:997:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{import}} -\label{sec:org453c75e} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:1008:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{copy}} -\label{sec:orgd64bce6} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:1019:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{error}} -\label{sec:orgf6b91cf} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:1027:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{symbol->keyword}} -\label{sec:org0a52c4e} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:1034:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{string->symbol}} -\label{sec:org647cd24} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:1043:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{symbol->string}} -\label{sec:org47e14d5} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:1055:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{concat-strings}} -\label{sec:org8acbdc6} -\begin{description} -\item[{defined in}] \texttt{src/./built\_ins.cpp:1064:0} -\item[{type}] \texttt{:cfunction} -\item[{docu}] TODO -\end{description} - -\section*{\texttt{pe}} -\label{sec:org9e78e87} -\begin{description} -\item[{defined in}] \texttt{pre.slime:2:40} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{expr} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{when}} -\label{sec:org1fd6509} -\begin{description} -\item[{defined in}] \texttt{pre.slime:8:37} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{condition}: -\item[{rest}] \texttt{body} -\end{description} -\item[{docu}] Doc String for `when' -\end{description} - -\section*{\texttt{unless}} -\label{sec:org2bc243b} -\begin{description} -\item[{defined in}] \texttt{pre.slime:13:41} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{condition}: -\item[{rest}] \texttt{body} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{n-times}} -\label{sec:org320901c} -\begin{description} -\item[{defined in}] \texttt{pre.slime:20:35} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{times}, \texttt{action} -\end{description} -\item[{docu}] Executes action times times. -\end{description} - -\section*{\texttt{let}} -\label{sec:org211dd45} -\begin{description} -\item[{defined in}] \texttt{pre.slime:37:64} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{bindings}: -\item[{rest}] \texttt{body} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{cond}} -\label{sec:orgd892c8c} -\begin{description} -\item[{defined in}] \texttt{pre.slime:51:19} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{rest}] \texttt{clauses} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{define-special}} -\label{sec:orgaf0a045} -\begin{description} -\item[{defined in}] \texttt{pre.slime:54:81} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{name-and-args}: -\item[{rest}] \texttt{body} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{construct-list}} -\label{sec:orgf661769} -\begin{description} -\item[{defined in}] \texttt{pre.slime:94:14} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{rest}] \texttt{body} -\end{description} -\item[{docu}] (construct-list - i <- '(1 2 3 4 5) - yield (* i i)) - -(construct-list - i <- '(1 2 3 4) - j <- '(A B) - yield (pair i j)) - -(construct-list - i <- '(1 2 3 4 5 6 7 8) - when (evenp i) - yield i) -\end{description} - -\section*{\texttt{apply}} -\label{sec:org45b573a} -\begin{description} -\item[{defined in}] \texttt{pre.slime:99:28} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{fun}, \texttt{seq} -\end{description} -\item[{docu}] Applies the funciton to the sequence, as in calls the function with -ithe sequence as arguemens. -\end{description} - -\section*{\texttt{define-package}} -\label{sec:org0069822} -\begin{description} -\item[{defined in}] \texttt{pre.slime:113:24} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{name}: -\item[{rest}] \texttt{body} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{nil?}} -\label{sec:orgedf1fec} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Checks if the argument is \texttt{nil}. -\end{description} - -\section*{\texttt{number?}} -\label{sec:org2ecc887} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Checks if the argument is a number. -\end{description} - -\section*{\texttt{symbol?}} -\label{sec:org8eb8eb1} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Checks if the argument is a symbol. -\end{description} - -\section*{\texttt{keyword?}} -\label{sec:orga942423} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Checks if the argument is a keyword. -\end{description} - -\section*{\texttt{pair?}} -\label{sec:org49fa45c} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Checks if the argument is a pair. -\end{description} - -\section*{\texttt{string?}} -\label{sec:org1374465} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Checks if the argument is a string. -\end{description} - -\section*{\texttt{lambda?}} -\label{sec:orge205cdc} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Checks if the argument is a function. -\end{description} - -\section*{\texttt{macro?}} -\label{sec:org1a92381} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Checks if the argument is a macro. -\end{description} - -\section*{\texttt{special-lambda?}} -\label{sec:org732b556} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Checks if the argument is a special-lambda. -\end{description} - -\section*{\texttt{built-in-function?}} -\label{sec:org89e43c4} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Checks if the argument is a built-in function. -\end{description} - -\section*{\texttt{callable?}} -\label{sec:org936a11d} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{end}} -\label{sec:orgc976460} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{seq} -\end{description} -\item[{docu}] Returns the last pair in the sqeuence. -\end{description} - -\section*{\texttt{last}} -\label{sec:org82ec031} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{seq} -\end{description} -\item[{docu}] Returns the (first) of the last (pair) of the given sequence. -\end{description} - -\section*{\texttt{extend}} -\label{sec:orga3701e7} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{seq}, \texttt{elem} -\end{description} -\item[{docu}] Extends a list with the given element, by putting it in -the (rest) of the last element of the sequence. -\end{description} - -\section*{\texttt{extend2}} -\label{sec:orgf83752c} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{seq}, \texttt{elem} -\end{description} -\item[{docu}] Extends a list with the given element, by putting it in -the (rest) of the last element of the sequence. -\end{description} - -\section*{\texttt{append}} -\label{sec:orgc6bb2db} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{seq}, \texttt{elem} -\end{description} -\item[{docu}] Appends an element to a sequence, by extendeing the list -with (pair elem nil). -\end{description} - -\section*{\texttt{length}} -\label{sec:orgfc5c7db} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{seq} -\end{description} -\item[{docu}] Returns the length of the given sequence. -\end{description} - -\section*{\texttt{increment}} -\label{sec:org448fc7a} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{val} -\end{description} -\item[{docu}] Adds one to the argument. -\end{description} - -\section*{\texttt{decrement}} -\label{sec:orga45beaf} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{val} -\end{description} -\item[{docu}] Subtracts one from the argument. -\end{description} - -\section*{\texttt{range}} -\label{sec:org13c7545} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{keyword}] \texttt{from} \texttt{(0)}, \texttt{to} -\end{description} -\item[{docu}] Returns a sequence of numbers starting with the number defined by the -key \texttt{from} and ends with the number defined in \texttt{to}. -\end{description} - -\section*{\texttt{range-while}} -\label{sec:org0c5cb36} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{keyword}] \texttt{from} \texttt{(0)}, \texttt{to} -\end{description} -\item[{docu}] Returns a sequence of numbers starting with the number defined -by the key 'from' and ends with the number defined in 'to'. -\end{description} - -\section*{\texttt{map}} -\label{sec:orgacde49c} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{fun}, \texttt{seq} -\end{description} -\item[{docu}] Takes a function and a sequence as arguments and returns a new -sequence which contains the results of using the first sequences -elemens as argument to that function. -\end{description} - -\section*{\texttt{reduce}} -\label{sec:org22122b7} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{fun}, \texttt{seq} -\end{description} -\item[{docu}] Takes a function and a sequence as arguments and applies the -function to the argument sequence. This only works correctly if the -given function accepts a variable amount of parameters. If your -funciton is limited to two arguments, use \hyperref[sec:org1b2823b]{\texttt{reduce-binary}} -instead. -\end{description} - -\section*{\texttt{reduce-binary}} -\label{sec:org1b2823b} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{fun}, \texttt{seq} -\end{description} -\item[{docu}] Takes a function and a sequence as arguments and applies the -function to the argument sequence. reduce-binary applies the -arguments `pair-wise' which means it works with binary functions -as compared to `reduce'. -\end{description} - -\section*{\texttt{filter}} -\label{sec:orgb0f5f85} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{fun}, \texttt{seq} -\end{description} -\item[{docu}] Takes a function and a sequence as arguments and applies the -function to every value in the sequence. If the result of that -funciton application returns a truthy value, the original value is -added to a list, which in the end is returned. -\end{description} - -\section*{\texttt{zip}} -\label{sec:org5c4e4ae} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{l1}, \texttt{l2} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{unzip}} -\label{sec:orgd648a84} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{lists} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{enumerate}} -\label{sec:org3a95198} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{seq} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{printf}} -\label{sec:orgf5d6005} -\begin{description} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{keyword}] \texttt{sep} \texttt{(" ")}, \texttt{end} =(" -\end{description} -\end{description} -")=: -\begin{description} -\item[{rest}] \texttt{args} -\end{description} -\begin{description} -\item[{docu}] A wrapper for the built-in (print) that accepts a variable number -of arguments and also provides keywords for specifying the printed -separators between the arguments and what should be printed after the -las argument. -\end{description} - -\section*{\texttt{define-class}} -\label{sec:org8555bc8} -\begin{description} -\item[{defined in}] \texttt{oo.slime:22:22} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{name-and-members}: -\item[{rest}] \texttt{body} -\end{description} -\item[{docu}] Macro for creating simple classes. -\end{description} - -\section*{\texttt{->}} -\label{sec:orga95c900} -\begin{description} -\item[{defined in}] \texttt{oo.slime:25:24} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{obj}, \texttt{meth}: -\item[{rest}] \texttt{args} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{math->}} -\label{sec:org91bd4f1} -\begin{description} -\item[{type}] \texttt{:package} -\item[{arguments}] : -\begin{description} -\item[{rest}] \texttt{args} -\end{description} -\item[{docu}] none -\end{description} - -\section*{\texttt{math-> pi}} -\label{sec:org5df416d} -\begin{description} -\item[{defined in}] \texttt{math.slime:5:4} -\item[{type}] \texttt{:number} -\item[{value}] \texttt{3.141593} -\item[{docu}] Tha famous circle constant. -\end{description} - -\section*{\texttt{math-> abs}} -\label{sec:orgeae475d} -\begin{description} -\item[{defined in}] \texttt{math.slime:9:4} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Accepts one argument and returns the absoulte value of it -\end{description} - -\section*{\texttt{math-> sqrt}} -\label{sec:org85193e5} -\begin{description} -\item[{defined in}] \texttt{math.slime:13:4} -\item[{type}] \texttt{:lambda} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x} -\end{description} -\item[{docu}] Accepts one argument and returns the square root of it -\end{description} - -\section*{\texttt{math-> make-vector3}} -\label{sec:org5e39827} -\begin{description} -\item[{defined in}] \texttt{pre.slime:37:63} -\item[{type}] \texttt{:constructor} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{x}, \texttt{y}, \texttt{z} -\end{description} -\item[{docu}] This is the handle to an object of the class vector3 -\end{description} - -\section*{\texttt{math-> make-vector3 define-class}} -\label{sec:org8eebb62} -\begin{description} -\item[{defined in}] \texttt{oo.slime:22:22} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{name-and-members}: -\item[{rest}] \texttt{body} -\end{description} -\item[{docu}] Macro for creating simple classes. -\end{description} - -\section*{\texttt{math-> make-vector3 ->}} -\label{sec:org139666d} -\begin{description} -\item[{defined in}] \texttt{oo.slime:25:24} -\item[{type}] \texttt{:macro} -\item[{arguments}] : -\begin{description} -\item[{postitional}] \texttt{obj}, \texttt{meth}: -\item[{rest}] \texttt{args} -\end{description} -\item[{docu}] none -\end{description} -\end{document} \ No newline at end of file diff --git a/manual/manual.html b/manual/manual.html deleted file mode 100644 index cc08864..0000000 --- a/manual/manual.html +++ /dev/null @@ -1,3236 +0,0 @@ - - - -The Slime 1.0 Manual - - - - - - - - - - - - - - - - -
-

The Slime 1.0 Manual

-
-

-abstract -

- -
- -

-\tableofcontents -

- -
-

1 Lisp languages

-
-

-Lisp is not one language but rather a family of programming languages. The family is devided by some -characteristics. There are Lisp-1 and Lisp-2 dialects and there is a difference between a Lisp with -lexical scoping as opposed to dynamic scoping. These differences will be explained in later -sections. -

- -

-Like most Lisps, Slime is dynamically typed. That means that like in statically typed Languages -Slime has different data types, but they are associated not with variables but with the Lisp objects -themselves. Variables can be assigend Lisp objects of any internal type. -

- -

-The Lisp language family is known to be highly flexible and applicable in all areas by creating -domain specific languages in Lisp itself through a powerful macro system. The central data structure -in Lisp is the list. The reason why lisp is so powerful is because the program source code itself is -represented as lists. The nested lists make up the syntax tree of the lisp program. It is therfore -computationally easy to parse lisp programs as the source code itself is already structured in the -form of the syntax tree; allowing for parsing in linear time. -

- -

-The macro system in Slime works by recognizing macros at parse-time and running them, and replacing -the macro call in the program code with the return value of the macro and then checking if further -macros have to be expanded in the replaced code. Therefore the macros can be used to pre-compute -values or rewrite expressions (creating syntactic sugar) or themselves define macros. -

-
-
- -
-

2 Lists

-
-

-As mentioned in Lisp languages, the central data structure in all Lisps is the list. Lists are -implemented as singly linked lists, made up of pairs (historically called cons-cells), each pair -has two slots, the first and the rest (historically car and cdr). A linked lsit ist then -constructed by the convention that the first field of a pair points to the first element of the -list and the rest field points to the rest of the list. Following this description, the list is a -recursive data structure. For the end of the list a special value nil is used in the rest field. -

- -

-A helpful way to visualize lists made up of pairs is using box diagrams. A simple box diagram can be -seen in 1. Each rectangle is divided in two. The left part represents the first -field, the right part represents the rest. The arrows point to the values in these fields. -

- -

-The diagram in 1 shows a simple list containing the values 1, 2 and 3. The first pair -stores the number 1 its first field and the rest points to the rest of the list. The last pair -points to the special value nil in its rest to denote the end of the list. -

- -

-diagrams/list123.eps -

- - -

-However the rest of a pair needs not to be a pair or nil, it could also point to any other value. -By doing this the list is no longer "well formed" but rather "ill formed". Ill formed lsits can be -used as an optimization when using the list for storing data. In 2 an ill formed list -can be seen, that also contains the values 1, 2 and 3 but stores them using only two pairs instead -of 3. -

- -

-diagrams/list12.3.eps -

-
- -
-

2.1 representing lists in Lisp

-
-

-In Slime and in most Lisps, lists are represented using round parenthesis where ( denotes the -start of the list and ) denotes the end. Eeach element inside these parenthesis separated by one -or more spaces will be interpreted as an element of that list. For example the list from -1 would be represented as (1 2 3). During parse time, the Lisp parser transforms -the parenthesised list into the pairs that are in the end stored in memory. -

- -

-To also be able to represent ill formed lists in Lisp there is a special syntax using the . (dot -symbol). If the parser encounters a . inside of a list, it will treat the next element as the -rest. If there is no or more than one element after the . an parsing error will be thrown. Using -this syntax we can represent the ill formed list from 2 as (1 2 . 3). We can also -write well formed lists using the dot notation if we point the rest to another list. So the well -formed list from 1 can also be written as \[\texttt{(1 . (2 . (3)))}\] -

-
-
- -
-

2.2 representing function calls in Lisp

-
-

-If we tried to enter the Lisp representation of the lists like (1 2 3) discussed in representing lists in Lisp directly into an Lisp interpreter we would get an error. That doesn't mean that the -explanation given in the section is wrong, it is in fact correct: the lisp parser will transform the -lisp syntax into the pairs in memory. The reason we would get an error is, that when reading Lisp -code, the Lisp interpreter first parses the code and then tries to evaluate it and return the result -back to the user. -

- -

-In Lisp by default, a list corresponds to a function call. As mentioned in Lisp languages Lisp -represents lists and Lisp programms as lists. If a list is treated as a function call, the first -element will be treated as the function and the rest of the elements will be the arguments to that -function. If we would wnter (1 2 3) directly into the Lisp interpreter we would get an error -saying it cannot find the function 1. -

- -

-If we would want to compute the sum of the numbers 5 and 3 we could do this by invoking the + -function with 5 and 3 as its arguments. (+ 5 3) will evaluate to 8. We can also nest functions -calls and use the return values as parameters to other functions: (+ (- 12 4) (/ 24 4)) will -evaluate to 14. The box diagramm showing the internal structure of that computation can be seen in -3. -

- -

-diagrams/simpleMath.eps -

-
-
-
- -
-

3 Evaluation order

-
-

-As a first step of evaluation of a regular function, all its arguments are getting evaluated, and -then the function is applied to the evaluated arguments. For example when evaluating the nested -expression in 1 the outermost function is the + function with three arguments: (* -3 4), (- 100 (+ 12 13 14 15)) and 2. So before the outhermost + gets invoked, the three -arguments are getting evaluated recursively. -

- -
- -
(print (+ (* 3 4)
-          (- 100 (+ 12 13 14 15))
-          2))
-
-
- -
-evaluates to =>
-60
-
-
-
- -
-

3.1 Special forms

-
-

-The given evaluation rule – to evaluate all the arguments first and then allpying them to the -funciton – as described in Evaluation order is only valid for regular functions. There is a class -of functions that do not follow this evaluation rule called special forms. Special forms are -needed when you do not wish to evaluate all arguments. For example the built-in if function should -only evaluate the "then-expression" if the condition evaluates to a truthy value and not otherwise. -Consider the example in 2. The if expression only evaluates the then-expression. If -the if function would follow the evaluation order of regular functions, first all three arguments -(< 1 2), (print "I knew it!!\n") but also (print "Oh, it is not?!\n") could get evaluated and -so both messages would be printed. In the given if expression, the condition evaluates to a truthy -value and only I knew it!! will be printed. -

- -
- -
(if (< 1 2)
-    (print "I knew it!!\n")
-  (print "Oh, it is not?!\n"))
-
-
- -
-evaluates to =>
-I knew it!!
-
-
- -

-The programmer can also define their own special forms using special-lambda and macros, which will -be explained in Special lambdas and Macros. -

-
-
-
- -
-

4 Symbols and keywords

-
-
-

5 Truthyness

-
-
-

6 Lambdas

-
-

-Slime allows for creating anonymous functions called lambdas. We did not talk about binding -variables, we will do this in Define, but we can still use lambdas now. Remember that Lisp -interpretes the first argument of a list in the source code as a function and the rest as the -arguments. The lambda special form evaluates to a regular function object that can then stand in -the first position of the function call list. The basic syntax for the lambda special form is: -\[\texttt{(lambda (arg1 arg2 ...) (body1) ...)}\] the first arguemnt to lambda is a list of the -arguments. All the following arguments will be the body of the lambda. They will be executed when -the lambda is invoked. The return value of a lambda is the value of the last evaluated expression in -the body. -

- -

-Probably the simplest function to write as a lambda is the identity function. It takes one argument -and returns it. The identity lambda and a few other simple examples of lambdas can be seen in -3. -

- -
- -
(printf ((lambda (x) x) 1))
-(printf ((lambda (x y) (+ x y)) 3 5))
-(printf ((lambda (x y z) (list x y z)) 1 2 3))
-
-
- -
-evaluates to =>
-1
-8
-(1 2 3)
-
-
- -

-Additionally Slime lambdas have the possibility to take optional arguments in the form of keyword -arguemnts as well as a rest argument which allows for accepting any number of arguments. Since -these concepts are most useful when the function is actually bound to a variable, they will be -introduced when we learned how to do that in Define. -

-
- -
-

6.1 Special lambdas

-
-

-The lambda special form creates a function object that represents a regular function. So the basic -evaluation rules count: when the lambda is invoked all it's arguments are evaluated and then the -lambda is applied to the evaluated arguments. If this is not wanted in some rare cases, the -programmer also has the possibility to define a special form using special-lambda, which, when -invoked does not evaluare any argument. The programmer has to evaluate the arguments in the body -themselves using eval. The rest of the syntax between lambda and special-lambda are the same. -

- -
- -
((lambda         (x) (printf x)) (+ 1 2))
-((special-lambda (x) (printf x)) (+ 1 2))
-
-;; Special lambdas make it possible to write
-;; code that inspects code
-((special-lambda (expr)
-     (printf "The function to be called is"
-             (first expr)
-             "and the result is"
-             (eval expr)))
- (+ 1 2))
-
-
- -
-evaluates to =>
-3
-(+ 1 2)
-The function to be called is + and the result is 3.
-
-
-
-
-
- -
-

7 Define

-
-

-To assign a value to a symbol you can use the define built-in special form. The syntax for -define is: \[\texttt{(define symbol value)}\] and some usages can be seen in -5. -

- -
- -
(define var1 1)
-(define var2 "Hello World")
-(define var3 (+ 1 2))
-
-(printf var1 var2 var3)
-
-
- -
-evaluates to =>
-1 Hello World 3
-
-
-
- -
-

7.1 Defining functions

-
-

-In Lambdas we learned how to create function objects using the lambda built-in form. Using -define every Lisp Object can be assigned to a symbol making no exception for the function objects. -In 6 you can see what that would look like. -

- -
- -
(define hypothenuse
-  (lambda (a b)
-    (** (+ (* a a) (* b b)) 0.5)))
-
-(printf (hypothenuse 3 4))
-
-
- -
-evaluates to =>
-5
-
-
- -

-Since defining functions is so common, there is a syntactic shorthand that does not require to write -out the whole lambda definition. In this case the first argument to the call to define is a -list. The frist element of the list is the name of the function to define and the other elemens are -the arguments to that function. An example can be seen in 7. Note that the -definition looks like a call to the function we are constructing, making it easier to see what a -call to that function will look like. -

- -
- -
(define (hypothenuse a b)
-  (** (+ (* a a) (* b b)) 0.5))
-
-(printf (hypothenuse 3 4))
-
-
- -
-evaluates to =>
-5
-
-
-
-
- -
-

7.2 Functions with keyword arguments

-
-

-A sometimes more convenient way of passing arguments to a function is using keyword arguments. Using -keyword arguments a function call could look like this: \[\texttt{(function :arg1 value1 :arg2 -value2)}\] here the function accepts two arguments named arg1 and arg2. The user of this -function can see more clearly excatly which argument will be assigned wich value. This notation also -allows for switching the argument order. The following function call is equivalent to the call -above. \[\texttt{(function :arg2 value2 :arg1 value1)}\]. -

- -

-For this to work however, the function must be defined to accept these keyword arguments. To do this -the special marker :keys has to be inserted into the argument list of a lambda or a function -define. All following arguments must be supplied as keyword arguments, unless they are also -supplied with a default value, in which case they do not need to be supplied. To attach a default -value to a keyword argument, insert :defaults-to <value> after the keyword argument name. An -example of all of this can be seen in 8. Important note: keyword arguments must be -defined and supplied after all the regular arguments. -

- -
- -
(define (complex required1 required2 :keys
-                 key1
-                 key2 :defaults-to 3
-                 key3)
-  (* (+ required1 required2)
-     key1
-     key2
-     key3))
-
-(printf (complex 1 2 :key1 2 :key2 2 :key3 3))
-(printf (complex 1 2 :key1 2 :key3 3))
-(printf (complex 1 2 :key3 3 :key1 2))
-
-
- -
-evaluates to =>
-36
-54
-54
-
-
-
-
- -
-

7.3 Functions with rest arguments

-
-

-If the programmer wants to create a function that can accept any number of arguments, they can use -the rest argument. It is defined after the special marker :rest and after the rest argument, no -other arguments can be defined. In the execution of the fuction, the rest arguent will be assigned -to a list containing all the supplied values. The rest argument can be used in conjunction with the -other argument types, regular arguments and keyword arguments. -

- -
- -
(define (execute-operation operation
-                           :keys
-                           do-logging :defaults-to ()
-                           :rest values)
-  (define result (apply operation values))
-  (when do-logging
-    (printf "Executing operation"
-            operation
-            "agains the values"
-            values
-            "yielded:"
-            result))
-  result)
-
-(printf (execute-operation '+ 1 2 3))
-(printf (execute-operation '*
-                           :do-logging t
-                           10 11))
-
-
- -
-evaluates to =>
-6
-Executing operation * agains values (10 11) yielded: 110
-110
-
-
-
-
-
- -
-

8 Environments

-
-
-

9 Macros

-
-
-

Built-in functions

-
-
-
-
-

continuation?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is a continuation. -

-
-
-
-
-
-
-

=

-
-
-
type
:cfunction -
-
docu

-Takes 0 or more arguments and returns t if all arguments are equal and () otherwise. -

-
-
-
-
-
-
-

+

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

get-random-between

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

lambda

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

info

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

addr-of

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

type?=

-
-
-
type
:lambda -
-
arguments
-
postitional
obj, typ -
-
-
-
docu

-Checks if the argument obj is of type typ -

-
-
-
-
-
-
-

symbol?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is a symbol. -

-
-
-
-
-
-
-

macro?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is a macro. -

-
-
-
-
-
-
-

procedure?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu
none -
-
-
-
-
-
-

rest

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

type

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

print

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

import

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

symbol->keyword

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

pe

-
-
-
type
:macro -
-
arguments
-
postitional
expr -
-
-
-
docu
none -
-
-
-
-
-
-

stream-null?

-
-
-
type
:lambda -
-
arguments
-
postitional
s -
-
-
-
docu
none -
-
-
-
-
-
-

construct-list

-
-
-
type
:macro -
-
arguments
-
rest
body -
-
-
-
docu
- -
(construct-list
-  i <- '(1 2 3 4 5)
-  yield (* i i))
-
-
- -

-(construct-list - i <- '(1 2 3 4) - j <- '(A B) - yield (pair i j)) -

- -

-(construct-list - i <- '(1 2 3 4 5 6 7 8) - if (= 0 (% i 2)) - yield i) -

-
-
-
-
-
-
-

define

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

vector-length

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

/

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

quasiquote

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

or

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

list

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

zip

-
-
-
type
:lambda -
-
arguments
-
postitional
l1, l2 -
-
-
-
docu
none -
-
-
-
-
-
-

generic-extend

-
-
-
type
:macro -
-
arguments
-
postitional
args -
-
rest
body -
-
-
-
docu
none -
-
-
-
-
-
-

pair?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is a pair. -

-
-
-
-
-
-
-

end

-
-
-
type
:lambda -
-
arguments
-
postitional
seq -
-
-
-
docu

-Returns the last pair in the sqeuence. -

- -
- -
(define a (list 1 2 3 4))
-(print (end a))
-
-
-
-
-
-
-
-
-

decrement

-
-
-
type
:lambda -
-
arguments
-
postitional
val -
-
-
-
docu

-Subtracts one from the argument. -

-
-
-
-
-
-
-

range-while

-
-
-
type
:lambda -
-
arguments
-
keyword
from (0), to -
-
-
-
docu

-Returns a sequence of numbers starting with the number defined -by the key 'from' and ends with the number defined in 'to'. -

-
-
-
-
-
-
-

mutate

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

<

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

assert

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

set-car!

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

eval

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

vector

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

memstat

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

symbol->string

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

cond

-
-
-
type
:macro -
-
arguments
-
rest
clauses -
-
-
-
docu
none -
-
-
-
-
-
-

reduce

-
-
-
type
:lambda -
-
arguments
-
postitional
fun, seq -
-
-
-
docu

-Takes a function and a sequence as arguments and applies the -function to the argument sequence. This only works correctly if the -given function accepts a variable amount of parameters. If your -funciton is limited to two arguments, use reduce-binary -instead. -

-
-
-
-
-
-
-

define-module

-
-
-
type
:macro -
-
arguments
-
postitional
module-name -
-
keyword
imports (()), exports -
-
rest
body -
-
-
-
docu
none -
-
-
-
-
-
-

null?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is nil. -

-
-
-
-
-
-
-

built-in-function?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is a built-in function. -

-
-
-
-
-
-
-

list-without-index

-
-
-
type
:lambda -
-
arguments
-
postitional
seq, index -
-
-
-
docu
none -
-
-
-
-
-
-

error

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

hm/set!

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

case

-
-
-
type
:macro -
-
arguments
-
postitional
var -
-
rest
clauses -
-
-
-
docu
none -
-
-
-
-
-
-

-

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

%

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

extend

-
-
-
type
:lambda -
-
arguments
-
postitional
seq, elem -
-
-
-
docu

-Extends a list with the given element, by putting it in -the (rest) of the last element of the sequence. -

-
-
-
-
-
-
-

lambda?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is a function. -

-
-
-
-
-
-
-

extend2

-
-
-
type
:lambda -
-
arguments
-
postitional
seq, elem -
-
-
-
docu

-Extends a list with the given element, by putting it in -the (rest) of the last element of the sequence. -

-
-
-
-
-
-
-

length

-
-
-
type
:lambda -
-
arguments
-
postitional
seq -
-
-
-
docu

-Returns the length of the given sequence. -

-
-
-
-
-
-
-

helper

-
-
-
type
:cfunction -
-
docu
-
-
-
-
-
-

>

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

**

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

set!

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

if

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

quote

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

not

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

apply

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

create-hash-map

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

first

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

delete-type!

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

show

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

generate-docs

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

load

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

hm/get-or-nil

-
-
-
type
:lambda -
-
arguments
-
postitional
hm, key -
-
-
-
docu
none -
-
-
-
-
-
-

the-empty-stream

-
-
-
type
:constructor -
-
value
() -
-
docu
none -
-
-
-
-
-
-

force

-
-
-
type
:lambda -
-
arguments
-
postitional
promise -
-
-
-
docu
none -
-
-
-
-
-
-

when

-
-
-
type
:macro -
-
arguments
-
postitional
condition -
-
rest
body -
-
-
-
docu

-Special form for when multiple actions should be done if a -condition is true. -

- -
- -
(when (not ())
-  (print "Hello ")
-  (print "from ")
-  (print "when!"))
-
-(when ()
-  (print "Goodbye ")
-  (print "World!"))
-
-
-
-
-
-
-
-
-

member?

-
-
-
type
:lambda -
-
arguments
-
postitional
elem, seq -
-
-
-
docu
none -
-
-
-
-
-
-

number?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is a number. -

-
-
-
-
-
-
-

sublist-starting-at-index

-
-
-
type
:lambda -
-
arguments
-
postitional
seq, index -
-
-
-
docu
none -
-
-
-
-
-
-

increment

-
-
-
type
:lambda -
-
arguments
-
postitional
val -
-
-
-
docu

-Adds one to the argument. -

-
-
-
-
-
-
-

pair

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

set-type!

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

mem-reset

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

mytry

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

string->symbol

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

delay

-
-
-
type
:macro -
-
arguments
-
postitional
expr -
-
-
-
docu
none -
-
-
-
-
-
-

define-typed

-
-
-
type
:macro -
-
arguments
-
postitional
args -
-
rest
body -
-
-
-
docu
none -
-
-
-
-
-
-

vector-set!

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

<=

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

bound?

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

hash-map-delete!

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

filter

-
-
-
type
:lambda -
-
arguments
-
postitional
fun, seq -
-
-
-
docu

-Takes a function and a sequence as arguments and applies the -function to every value in the sequence. If the result of that -funciton application returns a truthy value, the original value is -added to a list, which in the end is returned. -

-
-
-
-
-
-
-

unzip

-
-
-
type
:lambda -
-
arguments
-
postitional
lists -
-
-
-
docu
none -
-
-
-
-
-
-

types?=

-
-
-
type
:lambda -
-
arguments
-
rest
objs -
-
-
-
docu
none -
-
-
-
-
-
-

special-lambda?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is a special-lambda. -

-
-
-
-
-
-
-

last

-
-
-
type
:lambda -
-
arguments
-
postitional
seq -
-
-
-
docu

-Returns the (first) of the last (pair) of the given sequence. -

- -
- -
(define a (list 1 2 3 4))
-(print (last a))
-
-
-
-
-
-
-
-
-

append

-
-
-
type
:lambda -
-
arguments
-
postitional
seq, elem -
-
-
-
docu

-Appends an element to a sequence, by extendeing the list -with (pair elem nil). -

-
-
-
-
-
-
-

define-syntax

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

vector-ref

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

*

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

and

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

begin

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

hash-map-set!

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

copy

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

concat-strings

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

let

-
-
-
type
:macro -
-
arguments
-
postitional
bindings -
-
rest
body -
-
-
-
docu
none -
-
-
-
-
-
-

enumerate

-
-
-
type
:lambda -
-
arguments
-
postitional
seq -
-
-
-
docu
none -
-
-
-
-
-
-

assert-types=

-
-
-
type
:lambda -
-
arguments
-
rest
objs -
-
-
-
docu
none -
-
-
-
-
-
-

keyword?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is a keyword. -

-
-
-
-
-
-
-

string?

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Checks if the argument is a string. -

-
-
-
-
-
-
-

range

-
-
-
type
:lambda -
-
arguments
-
keyword
from (0), to -
-
-
-
docu

-Returns a sequence of numbers starting with the number defined -by the key from and ends with the number defined in to. -

-
-
-
-
-
-
-

map

-
-
-
type
:lambda -
-
arguments
-
postitional
fun, seq -
-
-
-
docu

-Takes a function and a sequence as arguments and returns a new -sequence which contains the results of using the first sequences -elemens as argument to that function. -

-
-
-
-
-
-
-

read

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

exit

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

break

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

hm/get

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

unless

-
-
-
type
:macro -
-
arguments
-
postitional
condition -
-
rest
body -
-
-
-
docu

-Special form for when multiple actions should be done if a -condition is false. -

-
-
-
-
-
-
-

n-times

-
-
-
type
:macro -
-
arguments
-
postitional
times, action -
-
-
-
docu

-Executes action times times. -

-
-
-
-
-
-
-

test

-
-
-
type
:cfunction -
-
docu
-
-
-
-
-
-

>=

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

set-cdr!

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

hash-map-get

-
-
-
type
:cfunction -
-
docu

-TODO -

-
-
-
-
-
-
-

reduce-binary

-
-
-
type
:lambda -
-
arguments
-
postitional
fun, seq -
-
-
-
docu

-Takes a function and a sequence as arguments and applies the -function to the argument sequence. reduce-binary applies the arguments -pair-wise which means it works with binary functions as compared to -reduce. -

-
-
-
-
-
-
-

ds::alist::make

-
-
-
type
:lambda -
-
arguments
none. -
-
docu
none -
-
-
-
-
-
-

ds::alist::print

-
-
-
type
:lambda -
-
arguments
-
postitional
alist -
-
-
-
docu
none -
-
-
-
-
-
-

ds::alist::get

-
-
-
type
:lambda -
-
arguments
-
postitional
alist, key -
-
-
-
docu
none -
-
-
-
-
-
-

ds::alist::find

-
-
-
type
:lambda -
-
arguments
-
postitional
alist, key -
-
-
-
docu
none -
-
-
-
-
-
-

ds::alist::key-exists?

-
-
-
type
:lambda -
-
arguments
-
postitional
alist, key -
-
-
-
docu
none -
-
-
-
-
-
-

ds::alist::remove!

-
-
-
type
:lambda -
-
arguments
-
postitional
alist, key -
-
-
-
docu
none -
-
-
-
-
-
-

ds::alist::set!

-
-
-
type
:lambda -
-
arguments
-
postitional
alist, key, value -
-
-
-
docu
none -
-
-
-
-
-
-

ds::alist::set-overwrite!

-
-
-
type
:lambda -
-
arguments
-
postitional
alist, key, value -
-
-
-
docu
none -
-
-
-
-
-
-

ds::plist::make

-
-
-
type
:lambda -
-
arguments
none. -
-
docu
none -
-
-
-
-
-
-

ds::plist::print

-
-
-
type
:lambda -
-
arguments
-
postitional
plist -
-
-
-
docu
none -
-
-
-
-
-
-

ds::plist::get

-
-
-
type
:lambda -
-
arguments
-
postitional
plist, prop -
-
-
-
docu
none -
-
-
-
-
-
-

ds::plist::find

-
-
-
type
:lambda -
-
arguments
-
postitional
plist, prop -
-
-
-
docu
none -
-
-
-
-
-
-

ds::plist::prop-exists?

-
-
-
type
:lambda -
-
arguments
-
postitional
plist, prop -
-
-
-
docu
none -
-
-
-
-
-
-

ds::plist::remove!

-
-
-
type
:lambda -
-
arguments
-
postitional
plist, prop -
-
-
-
docu
none -
-
-
-
-
-
-

ds::plist::set!

-
-
-
type
:lambda -
-
arguments
-
postitional
plist, prop, value -
-
-
-
docu
none -
-
-
-
-
-
-

ds::plist::set-overwrite!

-
-
-
type
:lambda -
-
arguments
-
postitional
plist, prop, value -
-
-
-
docu
none -
-
-
-
-
-
-

automata::make-dfa

-
-
-
type
:lambda -
-
arguments
-
postitional
Q, S, delta, q0, F -
-
-
-
docu
none -
-
-
-
-
-
-

interpolation::lerp

-
-
-
type
:lambda -
-
arguments
-
postitional
a, b, t -
-
-
-
docu
none -
-
-
-
-
-
-

interpolation::lerper

-
-
-
type
:lambda -
-
arguments
-
postitional
a, b -
-
-
-
docu
none -
-
-
-
-
-
-

interpolation::stepped-lerper

-
-
-
type
:lambda -
-
arguments
-
postitional
a, b, #steps -
-
-
-
docu
none -
-
-
-
-
-
-

interpolation::point-lerp

-
-
-
type
:lambda -
-
arguments
-
postitional
p1, p2, t -
-
-
-
docu
none -
-
-
-
-
-
-

interpolation::point-lerper

-
-
-
type
:lambda -
-
arguments
-
postitional
p1, p2 -
-
-
-
docu
none -
-
-
-
-
-
-

interpolation::bezier2

-
-
-
type
:lambda -
-
arguments
-
postitional
p1, p2, p3, t -
-
-
-
docu
none -
-
-
-
-
-
-

interpolation::bezierer2

-
-
-
type
:lambda -
-
arguments
-
postitional
p1, p2, p3 -
-
-
-
docu
none -
-
-
-
-
-
-

define-class

-
-
-
type
:macro -
-
arguments
-
postitional
name-and-members -
-
rest
body -
-
-
-
docu
none -
-
-
-
-
-
-

->

-
-
-
type
:macro -
-
arguments
-
postitional
obj, meth -
-
rest
args -
-
-
-
docu
none -
-
-
-
-
-
-

math::pi

-
-
-
type
:number -
-
value
3.141593 -
-
docu
none -
-
-
-
-
-
-

math::abs

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Accepts one argument and returns the absoulte value of it -

-
-
-
-
-
-
-

math::sqrt

-
-
-
type
:lambda -
-
arguments
-
postitional
x -
-
-
-
docu

-Accepts one argument and returns the square root of it -

-
-
-
-
-
-
-

math::make-vector3

-
-
-
type
:lambda -
-
arguments
-
postitional
x, y, z -
-
-
-
docu
none -
-
-
-
-
-
-

set::make

-
-
-
type
:lambda -
-
arguments
-
rest
vals -
-
-
-
docu
none -
-
-
-
-
-
-

set::find

-
-
-
type
:lambda -
-
arguments
-
postitional
set, val -
-
-
-
docu
none -
-
-
-
-
-
-

set::contains?

-
-
-
type
:lambda -
-
arguments
-
postitional
set, val -
-
-
-
docu
none -
-
-
-
-
-
-

set::insert!

-
-
-
type
:lambda -
-
arguments
-
postitional
set, value -
-
-
-
docu
none -
-
-
-
-
-
- - - diff --git a/manual/manual.org b/manual/manual.org index 52cf6d0..c8d67c0 100644 --- a/manual/manual.org +++ b/manual/manual.org @@ -956,6 +956,7 @@ embedded scripting language. #+latex_header: \usepackage[german]{babel} #+latex_header: \usepackage{xcolor} #+latex_header: \usepackage{listings} +#+latex_header: \usepackage{inconsolata} #+latex_header: \usepackage[pageanchor=false]{hyperref} #+latex_header: \definecolor{slimeKeyword}{HTML}{B58900} diff --git a/src/assert.hpp b/src/assert.hpp index 6cef360..ba08e2d 100644 --- a/src/assert.hpp +++ b/src/assert.hpp @@ -22,23 +22,21 @@ #define create_symbol_undefined_error(...) \ __create_error("symbol-undefined", __VA_ARGS__) -#define create_type_missmatch_error(expected, actual, exp) \ - __create_error("type-missmatch", \ - "Type missmatch: expected %s, got %s in %s", \ +#define create_type_missmatch_error(expected, actual, exp) \ + __create_error("type-missmatch", \ + "Type missmatch: expected %{l_o_t}, got %{l_o_t} in %{l_o_r}", \ expected, actual, exp) #ifdef _DEBUG -#define assert_type(_node, _type) \ - do { \ - if (_node->type != _type) { \ - char* t = lisp_object_to_string(_node); \ - defer_free(t); \ - create_type_missmatch_error( \ - lisp_object_type_to_string(_type), \ - lisp_object_type_to_string(_node->type), \ - t); \ - } \ +#define assert_type(_node, _type) \ + do { \ + if (_node->type != _type) { \ + create_type_missmatch_error( \ + _type, \ + _node->type, \ + _node); \ + } \ } while(0) #define assert_list_length(_node, _len) assert("List length assertion", list_length(_node) == _len) diff --git a/src/built_ins.cpp b/src/built_ins.cpp index 670a426..d8711f4 100644 --- a/src/built_ins.cpp +++ b/src/built_ins.cpp @@ -203,7 +203,11 @@ namespace Slime { (Current_Execution.nass.end()-1)->append(NasAction::Eval); }; - define_macro((set! sym val), "TODO") { + define_macro((set! sym val), + "If ='sym= is bound in a lexical parent environment " + "it will be bound to =val=. If no binding is found, " + "then ='sym= will be bound to =val= in the global environment." + ) { // NOTE(Felix): This COULD be a define_special in theory, // but because of call/cc, it cannot be anymore because // the define_symbol would not be a part of the @@ -240,8 +244,8 @@ namespace Slime { Lisp_Object* sym = Current_Execution.cs.data[Current_Execution.cs.next_index-1]; Environment* target_env = find_binding_environment(sym, get_current_environment()); - if (!target_env) - target_env = get_root_environment(); + if (!target_env) + target_env = get_root_environment(); define_symbol(sym, val, target_env); }); (Current_Execution.nass.end()-1)->append(NasAction::And_Then_Action); @@ -354,7 +358,8 @@ namespace Slime { { profile_with_name("(if)"); using Globals::Current_Execution; - /* | | | | + /* +| | | | | | -> | | | | | | | .... | | ...... | */ @@ -397,51 +402,51 @@ namespace Slime { form = form->value.pair.rest; Lisp_Object_Type type = definee->type; switch (type) { - case Lisp_Object_Type::Symbol: { - if (form != Memory::nil) { - Lisp_Object* doc = thing; - try_void assert_type(doc, Lisp_Object_Type::String); - try_void assert_type(form, Lisp_Object_Type::Pair); - thing = form->value.pair.first; - try_void assert("list must end here.", form->value.pair.rest == Memory::nil); - // TODO docs (maybe with hooks) we have to attach - // the docs to the result of evaluating - } - Current_Execution.cs.append(definee); - Current_Execution.cs.append(thing); - (Current_Execution.nass.end()-1)->append(NasAction::Define_Var); - (Current_Execution.nass.end()-1)->append(NasAction::Eval); - } break; - case Lisp_Object_Type::Pair: { - try_void assert_type(definee->value.pair.first, Lisp_Object_Type::Symbol); - Lisp_Object* func; - try_void func = Memory::create_lisp_object_function(Lisp_Function_Type::Lambda); - func->value.function->parent_environment = get_current_environment(); - create_arguments_from_lambda_list_and_inject(definee->value.pair.rest, func); - - if (thing_cons->type == Lisp_Object_Type::Pair && - // if there is stuff in the function body - thing_cons->value.pair.first->type == Lisp_Object_Type::String && - // if the first is a string - thing_cons->value.pair.rest != Memory::nil - // if it is not the last - ) { - // we found docs - Globals::docs.set_object( - func, - Memory::duplicate_string( - thing_cons->value.pair.first->value.string).data); - thing_cons = thing_cons->value.pair.rest; + case Lisp_Object_Type::Symbol: { + if (form != Memory::nil) { + Lisp_Object* doc = thing; + try_void assert_type(doc, Lisp_Object_Type::String); + try_void assert_type(form, Lisp_Object_Type::Pair); + thing = form->value.pair.first; + try_void assert("list must end here.", form->value.pair.rest == Memory::nil); + // TODO docs (maybe with hooks) we have to attach + // the docs to the result of evaluating + } + Current_Execution.cs.append(definee); + Current_Execution.cs.append(thing); + (Current_Execution.nass.end()-1)->append(NasAction::Define_Var); + (Current_Execution.nass.end()-1)->append(NasAction::Eval); + } break; + case Lisp_Object_Type::Pair: { + try_void assert_type(definee->value.pair.first, Lisp_Object_Type::Symbol); + Lisp_Object* func; + try_void func = Memory::create_lisp_object_function(Lisp_Function_Type::Lambda); + func->value.function->parent_environment = get_current_environment(); + create_arguments_from_lambda_list_and_inject(definee->value.pair.rest, func); + + if (thing_cons->type == Lisp_Object_Type::Pair && + // if there is stuff in the function body + thing_cons->value.pair.first->type == Lisp_Object_Type::String && + // if the first is a string + thing_cons->value.pair.rest != Memory::nil + // if it is not the last + ) { + // we found docs + Globals::docs.set_object( + func, + Memory::duplicate_string( + thing_cons->value.pair.first->value.string).data); + thing_cons = thing_cons->value.pair.rest; + } + func->value.function->body.lisp_body = maybe_wrap_body_in_begin(thing_cons); + + define_symbol(definee->value.pair.first, func); + Current_Execution.cs.append(definee->value.pair.first); + } break; + default: { + create_generic_error("you can only define symbols"); + return; } - func->value.function->body.lisp_body = maybe_wrap_body_in_begin(thing_cons); - - define_symbol(definee->value.pair.first, func); - Current_Execution.cs.append(definee->value.pair.first); - } break; - default: { - create_generic_error("you can only define symbols"); - return; - } } }; define((helper), "") { @@ -458,7 +463,7 @@ namespace Slime { Globals::debug_log = false; return Memory::t; }; - define_special((with-debug-log . rest), "") { + define_special((with-debug-log . rest), "TODO") { profile_with_name("(enable-debug-log)"); fetch(rest); Lisp_Object* result = Memory::nil; @@ -694,10 +699,8 @@ namespace Slime { if (is_truthy(res)) return Memory::t; } + create_generic_error("Userland assertion. (%{l_o_r})", test); - char* string = lisp_object_to_string(test, true); - create_generic_error("Userland assertion. (%s)", string); - free(string); return nullptr; }; define_special((define-macro form . body), "TODO") { @@ -748,6 +751,24 @@ namespace Slime { *target = *source; return target; }; + define((vector . args), "TODO") { + profile_with_name("(vector)"); + fetch(args); + Lisp_Object* ret; + u32 length = list_length(args); + try ret = Memory::create_lisp_object_vector(length, args); + return ret; + }; + define((alloc-vector len), "TODO") { + profile_with_name("(alloc-vector )"); + fetch(len); + try assert_type(len, Lisp_Object_Type::Number); + u32 i_len = (u32)len->value.number; + + Lisp_Object* res; + try res = Memory::create_lisp_object_vector(i_len, Memory::nil); + return res; + }; define((vector-length v), "TODO") { profile_with_name("(vector-length)"); fetch(v); @@ -768,6 +789,39 @@ namespace Slime { return vec->value.vector.data+int_idx; }; + define((vector-range (:from 0) :to), "TODO") { + profile_with_name("(vector-range)"); + fetch(from, to); + try assert_type(from, Lisp_Object_Type::Number); + try assert_type(to, Lisp_Object_Type::Number); + + s64 i_from = (s64)from->value.number; + s64 i_to = (s64)to->value.number; + + try assert("to should be bigger then from", i_to > i_from); + + Lisp_Object* data; + try data = Memory::allocate_vector((u32)(i_to - i_from + 1)); + + if (i_from == 0) { + for (s64 i = 0; i <= i_to; ++i) { + data[i].type = Lisp_Object_Type::Number; + data[i].value.number = (f64)i; + } + } else { + f64 num = (f64)i_from; + for (s64 i = 0; num <= to->value.number; ++num, ++i) { + data[i].type = Lisp_Object_Type::Number; + data[i].value.number = num; + } + } + Lisp_Object* node; + try node = Memory::create_lisp_object(); + node->type = Lisp_Object_Type::Vector; + node->value.vector.data = data; + node->value.vector.length = (u32)(i_to - i_from + 1); + return node; + }; define((vector-set! vec idx val), "TODO") { profile_with_name("(vector-set!)"); fetch(vec, idx, val); @@ -998,14 +1052,6 @@ namespace Slime { hm->value.hashMap->delete_object(key); return Memory::nil; }; - define((vector . args), "TODO") { - profile_with_name("(vector)"); - fetch(args); - Lisp_Object* ret; - u32 length = list_length(args); - try ret = Memory::create_lisp_object_vector(length, args); - return ret; - }; define((cons car cdr), "TODO") { profile_with_name("(cons)"); fetch(car, cdr); @@ -1097,7 +1143,7 @@ namespace Slime { // // the global keyword profile_with_name("(info)"); fetch(n); - print(n); + print("%{l_o}", n); Lisp_Object* type; Lisp_Object* val; @@ -1106,11 +1152,9 @@ namespace Slime { try val = eval_expr(n); } - printf(" is of type "); - print(type); - printf(" (internal: %s)", lisp_object_type_to_string(val->type)); - printf("\nand is printed as: "); - print(val); + print(" is of type %{l_o}", n); + print(" (internal: %{l_o_t})",val->type); + print("\nand is printed as: %{l_o_r}", val); printf("\n\ndocs:\n=====\n %s\n\n", (Globals::docs.get_object(val)) ? Globals::docs.get_object(val) @@ -1137,17 +1181,13 @@ namespace Slime { printf("%s", Memory::get_c_str(args->keyword.keywords.data[0]->value.symbol)); if (args->keyword.values.data[0]) { - printf(" ("); - print(args->keyword.values.data[0], true); - printf(")"); + print(" (%{l_o_r})", args->keyword.values.data[0]); } for (u32 i = 1; i < args->keyword.values.next_index; ++i) { printf(", %s", Memory::get_c_str(args->keyword.keywords.data[i]->value.symbol)); if (args->keyword.values.data[i]) { - printf(" ("); - print(args->keyword.values.data[i], true); - printf(")"); + print(" (%{l_o_r})", args->keyword.values.data[i]); } } } @@ -1166,10 +1206,8 @@ namespace Slime { fetch(n); try assert_type(n, Lisp_Object_Type::Function); try assert("c-functoins cannot be shown", !n->value.function->is_c); - puts("body:\n"); - print(n->value.function->body.lisp_body); - puts("\n"); - printf("parent_env: %p\n", + print("body:\n%{l_o}\n", n->value.function->body.lisp_body); + print("parent_env: %{ptr}\n", n->value.function->parent_environment); return Memory::nil; @@ -1194,21 +1232,28 @@ namespace Slime { if (things != Memory::nil) { bool print_repr = (repr != Memory::nil); - print(things->value.pair.first, print_repr); + if (print_repr) { + print("%{l_o_r}",things->value.pair.first, print_repr); + } else { + print("%{l_o}",things->value.pair.first, print_repr); + } for_lisp_list(things->value.pair.rest) { - print(sep); - print(it, print_repr); + if (print_repr) { + print("%{l_o}%{l_o_r}", sep, it); + } else { + print("%{l_o}%{l_o}", sep, it); + } } } - print(end); + print("%{l_o}", end); return Memory::nil; }; define((read (:prompt ">")), "TODO") { profile_with_name("(read)"); fetch(prompt); - print(prompt); + print("%{l_o}", prompt); // TODO(Felix): make read_line return a String* char* line = read_line(); @@ -1227,7 +1272,7 @@ namespace Slime { define((show-environment), "TODO") { profile_with_name("(show-environment)"); in_caller_env { - print_environment(get_current_environment()); + print("%{env}", get_current_environment()); } return Memory::nil; }; @@ -1293,9 +1338,9 @@ namespace Slime { using Globals::error; error = new(Error); error->type = type; - error->message = message->value.string; + error->message = duplicate_c_string(message->value.string.data); - create_generic_error("Userlanderror"); + create_generic_error("Userlanderror %s", message->value.string.data); return nullptr; }; define((symbol->keyword sym), "TODO") { @@ -1310,7 +1355,7 @@ namespace Slime { try assert_type(sym, Lisp_Object_Type::Symbol); return Memory::create_lisp_object( - Memory::duplicate_string(sym->value.symbol)); + Memory::duplicate_string(sym->value.symbol)); }; define((string->symbol str), "TODO") { profile_with_name("(string->symbol)"); diff --git a/src/docgeneration.cpp b/src/docgeneration.cpp index 70d04f0..07288f5 100644 --- a/src/docgeneration.cpp +++ b/src/docgeneration.cpp @@ -1,5 +1,6 @@ namespace Slime { proc generate_docs(String path) -> void { + print("Generating Docs..."); FILE *f = fopen(Memory::get_c_str(path), "w"); if (!f) { create_generic_error("The file for writing the documentation (%s) " @@ -11,6 +12,10 @@ namespace Slime { }; Array_List visited; + visited.alloc(); + defer { + visited.dealloc(); + }; const auto print_this_env = [&](const auto& rec, Environment* env, char* prefix) -> void { bool we_already_printed = false; @@ -22,8 +27,7 @@ namespace Slime { } } if (!we_already_printed) { - // printf("Working on env::::"); - // print_environment(env); + // print("Working on env::::%{env}",env); // printf("\n--------------------------------\n"); visited.append(env); @@ -34,7 +38,9 @@ namespace Slime { for_hash_map(env->hm) { try_void fprintf(f, + "#+latex: \\vspace{0.5cm}\n" "#+latex: \\hrule\n" + // "#+latex: \\hspace{0.5cm}\n" "#+html:
\n" "* =%s%s= \n" " :PROPERTIES:\n" @@ -60,10 +66,8 @@ namespace Slime { Lisp_Object* type_expr = Memory::create_list(Memory::get_symbol("type"), value); try_void LOtype = eval_expr(type_expr); - fprintf(f, "\n - type :: ="); - print(LOtype, true, f); - fprintf(f, "="); - + fprintf(f, "\n*type*\\newline\\indent\n"); + print_to_file(f, "=%{l_o_r}=\\newline\\noindent", LOtype); /* * if printable value -> print it @@ -76,9 +80,7 @@ namespace Slime { case(Lisp_Object_Type::Pair): case(Lisp_Object_Type::Symbol): case(Lisp_Object_Type::Keyword): { - fprintf(f, "\n - value :: ="); - print(value, true, f); - fprintf(f, "="); + print_to_file(f, "\n*value*\\newline\\indent =%{l_o_r}=\\newline\\noindent", value); } break; default: break; } @@ -88,50 +90,48 @@ namespace Slime { if (type == Lisp_Object_Type::Function) { Arguments* args = &value->value.function->args; - fprintf(f, "\n - arguments :: "); - // if no args at all - if (args->positional.symbols.next_index == 0 && - args->keyword.values.next_index == 0 && - !args->rest) + fprintf(f, "\n*signature*\n"); + + fprintf(f, + "#+BEGIN:\n" + "#+BEGIN_SRC slime\n" + "(%s%s", prefix, Memory::get_c_str(((Lisp_Object*)key)->value.symbol)); + + // if some args at all + if (args->positional.symbols.next_index != 0 || + args->keyword.values.next_index != 0 || + args->rest) { - fprintf(f, "none."); - } else { if (args->positional.symbols.next_index != 0) { - fprintf(f, "\n - postitional :: "); - fprintf(f, "=%s=", Memory::get_c_str(args->positional.symbols.data[0]->value.symbol)); - for (u32 i = 1; i < args->positional.symbols.next_index; ++i) { - fprintf(f, ", =%s=", Memory::get_c_str(args->positional.symbols.data[i]->value.symbol)); + for (auto lo: args->positional.symbols) { + fprintf(f, " %s", lo->value.symbol.data); } } if (args->keyword.values.next_index != 0) { - fprintf(f, "\n - keyword :: "); - fprintf(f, "=%s=", Memory::get_c_str(args->keyword.keywords.data[0]->value.symbol)); - if (args->keyword.values.data[0]) { - fprintf(f, " =("); - print(args->keyword.values.data[0], true, f); - fprintf(f, ")="); - } - for (u32 i = 1; i < args->keyword.values.next_index; ++i) { - fprintf(f, ", =%s=", Memory::get_c_str(args->keyword.keywords.data[i]->value.symbol)); + for (u32 i = 0; i < args->keyword.values.next_index; ++i) { + // if has default value if (args->keyword.values.data[i]) { - fprintf(f, " =("); - print(args->keyword.values.data[i], true, f); - fprintf(f, ")="); + print_to_file(f, " (:%s %{l_o})", + args->keyword.keywords.data[i]->value.symbol.data, + args->keyword.values.data[i]); + } else { + fprintf(f, " :%s", args->keyword.keywords.data[i]->value.symbol.data); } } } if (args->rest) { - fprintf(f, "\n - rest :: =%s=", Memory::get_c_str(args->rest->value.symbol)); + fprintf(f, " . %s", Memory::get_c_str(args->rest->value.symbol)); } } + fprintf(f, + ")\n" + "#+END_SRC\n" + "#+END:\n"); } - fprintf(f, "\n - docu :: "); - // TODO(Felix): make docsting a hashmap lookup - // if (value->docstring) - // fprintf(f, "\n #+BEGIN:\n%s\n #+END:\n", - // Memory::get_c_str(value->docstring)); - // else - fprintf(f, "none\n"); + fprintf(f, "\n\\noindent\n*docu*\n"); + char* docs = Globals::docs.get_object(value); + fprintf(f, "\n #+BEGIN:\n%s\n #+END:\n", + docs ? docs : "none"); } } @@ -141,5 +141,6 @@ namespace Slime { }; print_this_env(print_this_env, get_current_environment(), (char*)""); + print("Done!\n"); } } diff --git a/src/env.cpp b/src/env.cpp index 2707c05..fcd821c 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -84,44 +84,44 @@ namespace Slime { return result; String identifier = node->value.symbol; - print_environment(env); - printf("\n"); + print("%{env}\n", env); create_symbol_undefined_error("The symbol '%s' is not defined.", identifier.data); return nullptr; } - proc print_environment_indent(Environment* env, u32 indent) -> void { - proc print_indent = [indent]() { - for (u32 i = 0; i < indent; ++i) { - printf(" "); + proc print_environment(FILE* file, Environment* env) -> int { + int written; + + const proc print_environment_indent = [&](const auto & self, Environment* env, u32 indent) -> void { + proc print_indent = [&]() -> int{ + for (u32 i = 0; i < indent; ++i) { + print_to_file(file, " "); + } + return indent; + }; + + if(env == get_root_environment()) { + written += print_indent(); + written += print_to_file(file, "[built-ins]-Environment (0x%p)\n", env); + return; } - }; - // if(env == get_root_environment()) { - // print_indent(); - // printf("[built-ins]-Environment (0x%p)\n", env); - // return; - // } - - for_hash_map (env->hm) { - print_indent(); - printf("-> %s :: ", (((Lisp_Object*)key)->value.symbol.data)); - print((Lisp_Object*)value); - printf(" (0x%p)", value); - puts(""); - } - for (u32 i = 0; i < env->parents.next_index; ++i) { - print_indent(); - printf("parent (0x%p)", env->parents.data[i]); - puts(":"); - print_environment_indent(env->parents.data[i], indent+4); - } - } + for_hash_map (env->hm) { + written += print_indent(); + written += print_to_file(file, "-> %{str} :: %{L_O} (%{ptr})\n", + ((Lisp_Object*)key)->value.symbol.data, value, value); + } + for (u32 i = 0; i < env->parents.next_index; ++i) { + written += print_indent(); + written += print_to_file(file,"parent (%{ptr}):", env->parents.data[i]); + self(self, env->parents.data[i], indent+4); + } + }; - proc print_environment(Environment* env) -> void { - printf("\n=== Environment === (0x%p)\n", env); - print_environment_indent(env, 0); + written = print_to_file(file, "\n=== Environment === %{ptr}\n", env); + print_environment_indent(print_environment_indent, env, 0); + return written; } } diff --git a/src/error.cpp b/src/error.cpp index 0ef4469..6a0bde3 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -8,7 +8,7 @@ namespace Slime { } proc create_error(const char* c_func_name, const char* c_file_name, - u32 c_file_line, Lisp_Object* type, String message) -> void + u32 c_file_line, Lisp_Object* type, char* message) -> void { using Globals::error; delete_error(); @@ -42,14 +42,14 @@ namespace Slime { error = new(Error); error->type = type; } - // contents will be filled in - String formatted_string = Memory::create_string("", 0); + + char* msg; va_list args; va_start(args, format); - formatted_string.length = vasprintf(&formatted_string.data, format, args); + print_va_args_to_string(&msg, format, &args); va_end(args); - create_error(c_func_name, c_file_name, c_file_line, type, formatted_string); + create_error(c_func_name, c_file_name, c_file_line, type, msg); } } diff --git a/src/eval.cpp b/src/eval.cpp index 37e19a5..e8adef7 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -1,9 +1,9 @@ + namespace Slime { - proc create_extended_environment_for_function_application_nrc( - Lisp_Object* function, - u32 arg_start, - u32 arg_end) -> Environment* + proc create_extended_environment_for_function_application_nrc(Lisp_Object* function, + u32 arg_start, + u32 arg_end) -> Environment* { profile_this(); using Globals::Current_Execution; @@ -20,18 +20,15 @@ namespace Slime { }; u32 obligatory_keywords_count = 0; u32 read_obligatory_keywords_count = 0; - Lisp_Object* sym; Lisp_Object* val; - // read positionals for (u32 i = 0; i < arg_spec->positional.symbols.next_index; ++i) { if (index_of_next_arg == arg_end) { - create_parsing_error( - "Not enough positional args supplied. Needed: %d suppied, %d.\n" - "Next missing arg is '%s'", - arg_spec->positional.symbols.next_index, arg_end-index_of_next_arg, - arg_spec->positional.symbols.data[i]->value.symbol.data); + create_parsing_error("Not enough positional args supplied. Needed: %d suppied, %d.\n" + "Next missing arg is '%s'", + arg_spec->positional.symbols.next_index, arg_end-index_of_next_arg, + arg_spec->positional.symbols.data[i]->value.symbol.data); return nullptr; } // NOTE(Felix): We have to copy all the arguments, @@ -72,10 +69,10 @@ namespace Slime { // otherwise we would have to read more but there // was a not accepted kwarg, so signal the error create_generic_error( - "The function does not take the keyword argument ':%s'\n" - "and not all required keyword arguments have been read\n" - "in to potentially count it as the rest argument.", - Current_Execution.cs.data[index_of_next_arg]->value.symbol.data); + "The function does not take the keyword argument ':%s'\n" + "and not all required keyword arguments have been read\n" + "in to potentially count it as the rest argument.", + Current_Execution.cs.data[index_of_next_arg]->value.symbol.data); return nullptr; } // This is an accepted kwarg; check if it was already @@ -91,8 +88,8 @@ namespace Slime { // If there are some kwargs left to be read // in, it is an error create_generic_error( - "The function already read the keyword argument ':%s'", - Current_Execution.cs.data[index_of_next_arg]->value.symbol.data); + "The function already read the keyword argument ':%s'", + Current_Execution.cs.data[index_of_next_arg]->value.symbol.data); return nullptr; } } @@ -101,8 +98,8 @@ namespace Slime { // set it to? if (index_of_next_arg+1 == arg_end) { create_generic_error( - "Attempting to set the keyword argument ':%s', but no value was supplied.", - Current_Execution.cs.data[index_of_next_arg]->value.symbol.data); + "Attempting to set the keyword argument ':%s', but no value was supplied.", + Current_Execution.cs.data[index_of_next_arg]->value.symbol.data); return nullptr; } @@ -128,7 +125,15 @@ namespace Slime { } } - kw_done: + + /*c +plot_title('Sine Wave') +plot_function_samples(1000) +plot_xaxis(0,30) +plot_yaxis(-1.5,1.5) +plot(sin(t)) +*/ + kw_done: // check keywords for completeness for (u32 i = 0; i < arg_spec->keyword.values.next_index; ++i) { auto defined_keyword = arg_spec->keyword.keywords.data[i]; @@ -143,9 +148,9 @@ namespace Slime { // if this one does not have a default value if (!was_set) { create_generic_error( - "There was no value supplied for the required " - "keyword argument ':%s'.", - defined_keyword->value.symbol.data); + "There was no value supplied for the required " + "keyword argument ':%s'.", + defined_keyword->value.symbol.data); return nullptr; } } else { @@ -180,9 +185,8 @@ namespace Slime { define_symbol(arg_spec->rest, list, env); } else { // rest was not declared but additional arguments were found - create_generic_error( - "A rest argument was not declared " - "but the function was called with additional arguments."); + create_generic_error("A rest argument was not declared " + "but the function was called with additional arguments."); return nullptr; } } @@ -215,8 +219,8 @@ namespace Slime { if (arguments->value.pair.first->type != Lisp_Object_Type::Symbol) { create_parsing_error("Only symbols and keywords " "(with or without default args) " - "can be parsed here, but found '%s'", - lisp_object_type_to_string(arguments->value.pair.first->type)); + "can be parsed here, but found '%{l_o_t}'", + arguments->value.pair.first->type); return; } @@ -349,208 +353,205 @@ namespace Slime { current_action = nas->data[--nas->next_index]; switch (current_action) { - case NasAction::Pop: { - --Current_Execution.cs.next_index; - } break; - case NasAction::And_Then_Action: { - Current_Execution.ats.data[--Current_Execution.ats.next_index](); - } break; - case NasAction::Pop_Environment: { - pop_environment(); - } break; - case NasAction::Eval: { - pc = Current_Execution.cs.data[Current_Execution.cs.next_index-1]; - Lisp_Object_Type type = pc->type; - switch (type) { - case Lisp_Object_Type::Symbol: { - Current_Execution.cs.data[Current_Execution.cs.next_index-1] - = lookup_symbol(pc, get_current_environment()); + case NasAction::Pop: { + --Current_Execution.cs.next_index; } break; - case Lisp_Object_Type::Pair: { - Current_Execution.cs.data[Current_Execution.cs.next_index-1] = pc->value.pair.first; - Current_Execution.ams.append(Current_Execution.cs.next_index-1); - - if_debug { - if (Current_Execution.ams.next_index >= 2) { - assert("invalid ams state", - Current_Execution.ams.data[Current_Execution.ams.next_index-2] <= - Current_Execution.ams.data[Current_Execution.ams.next_index-1]); - } - } - - Current_Execution.pcs.append(pc->value.pair.rest); - Current_Execution.mes.append(pc); - nas->append(NasAction::TM); - nas->append(NasAction::Eval); + case NasAction::And_Then_Action: { + Current_Execution.ats.data[--Current_Execution.ats.next_index](); } break; - default: { - // NOTE(Felix): others are self evaluating - // so do nothing - } - } - } break; - case NasAction::Macro_Write_Back: { - *(Current_Execution.mes.data[--Current_Execution.mes.next_index]) - = *Current_Execution.cs[Current_Execution.cs.next_index-1]; - } break; - case NasAction::TM: { - pc = Current_Execution.cs.data[Current_Execution.cs.next_index-1]; - - Lisp_Object_Type type = pc->type; - switch (type) { - case Lisp_Object_Type::Function: { - if(pc->value.function->is_c) { - if (pc->value.function->type.c_function_type == C_Function_Type::cMacro) { - --Current_Execution.cs.next_index; // remove the macro call from cs - --Current_Execution.ams.next_index; // remove the apply marker for the macro - try pc->value.function->body.c_macro_body(); - } else if (pc->value.function->type.c_function_type == C_Function_Type::cSpecial) - { - // QUESTION(Felix): Why not call the - // function right away, and instead push - // step, so that step calls it? - push_pc_on_cs(); - nas->append(NasAction::Step); - } else { - nas->append(NasAction::Step); - } - --Current_Execution.mes.next_index; - } else { - if (pc->value.function->type.lisp_function_type == - Lisp_Function_Type::Macro) - { - push_pc_on_cs(); + case NasAction::Pop_Environment: { + pop_environment(); + } break; + case NasAction::Eval: { + pc = Current_Execution.cs.data[Current_Execution.cs.next_index-1]; + Lisp_Object_Type type = pc->type; + switch (type) { + case Lisp_Object_Type::Symbol: { + Current_Execution.cs.data[Current_Execution.cs.next_index-1] + = lookup_symbol(pc, get_current_environment()); + } break; + case Lisp_Object_Type::Pair: { + Current_Execution.cs.data[Current_Execution.cs.next_index-1] = pc->value.pair.first; + Current_Execution.ams.append(Current_Execution.cs.next_index-1); + + if_debug { + if (Current_Execution.ams.next_index >= 2) { + assert("invalid ams state", + Current_Execution.ams.data[Current_Execution.ams.next_index-2] <= + Current_Execution.ams.data[Current_Execution.ams.next_index-1]); + } + } + + Current_Execution.pcs.append(pc->value.pair.rest); + Current_Execution.mes.append(pc); + nas->append(NasAction::TM); nas->append(NasAction::Eval); - nas->append(NasAction::Macro_Write_Back); - nas->append(NasAction::Step); - } else { - --Current_Execution.mes.next_index; - nas->append(NasAction::Step); + } break; + default: { + // NOTE(Felix): others are self evaluating + // so do nothing } } } break; - case Lisp_Object_Type::Continuation: { - --Current_Execution.mes.next_index; - --Current_Execution.ams.next_index; - Lisp_Object* param = Current_Execution.pcs.data[--Current_Execution.pcs.next_index]; - try assert_list_length(param, 1); - param = param->value.pair.first; - // NOTE(Felix): we could first get value and eval - // it and restore the cont on an and_then_action - // OR we could restore the cont now and push the - // new unevaluated val on the stack and leave a - // NAS_Actoin::Eval behind. So that's what we - // gonna do. - - Globals::Current_Execution.cs.clear(); - Globals::Current_Execution.ams.clear(); - Globals::Current_Execution.pcs.clear(); - Globals::Current_Execution.nass.clear(); - Globals::Current_Execution.envi_stack.clear(); - Globals::Current_Execution.ats.clear(); - Globals::Current_Execution.mes.clear(); - - // TODO(Felix): This seems super inefficient - for (auto it: pc->value.continuation->cs) { - Globals::Current_Execution.cs.append(it); - } - for (auto it: pc->value.continuation->ams) { - Globals::Current_Execution.ams.append(it); - } - for (auto it: pc->value.continuation->pcs) { - Globals::Current_Execution.pcs.append(it); - } - for (auto it: pc->value.continuation->envi_stack) { - Globals::Current_Execution.envi_stack.append(it); - } - for (auto it: pc->value.continuation->ats) { - Globals::Current_Execution.ats.append(it); - } - for (auto it: pc->value.continuation->mes) { - Globals::Current_Execution.mes.append(it); - } - { - Globals::Current_Execution.nass.reserve(pc->value.continuation->nass.next_index); - Globals::Current_Execution.nass.next_index = pc->value.continuation->nass.next_index; - - for (u32 i = 0; i < pc->value.continuation->nass.next_index; ++i) { - Globals::Current_Execution.nass.data[i].alloc(); - for (Globals::Current_Execution.nass.data[i].next_index = 0; - Globals::Current_Execution.nass.data[i].next_index < pc->value.continuation->nass.data[i].next_index;) + case NasAction::Macro_Write_Back: { + *(Current_Execution.mes.data[--Current_Execution.mes.next_index]) + = *Current_Execution.cs[Current_Execution.cs.next_index-1]; + } break; + case NasAction::TM: { + pc = Current_Execution.cs.data[Current_Execution.cs.next_index-1]; + + Lisp_Object_Type type = pc->type; + switch (type) { + case Lisp_Object_Type::Function: { + if(pc->value.function->is_c) { + if (pc->value.function->type.c_function_type == C_Function_Type::cMacro) { + --Current_Execution.cs.next_index; // remove the macro call from cs + --Current_Execution.ams.next_index; // remove the apply marker for the macro + try pc->value.function->body.c_macro_body(); + } else if (pc->value.function->type.c_function_type == C_Function_Type::cSpecial) + { + // QUESTION(Felix): Why not call the + // function right away, and instead push + // step, so that step calls it? + push_pc_on_cs(); + nas->append(NasAction::Step); + } else { + nas->append(NasAction::Step); + } + --Current_Execution.mes.next_index; + } else { + if (pc->value.function->type.lisp_function_type == + Lisp_Function_Type::Macro) + { + push_pc_on_cs(); + nas->append(NasAction::Eval); + nas->append(NasAction::Macro_Write_Back); + nas->append(NasAction::Step); + } else { + --Current_Execution.mes.next_index; + nas->append(NasAction::Step); + } + } + } break; + case Lisp_Object_Type::Continuation: { + --Current_Execution.mes.next_index; + --Current_Execution.ams.next_index; + Lisp_Object* param = Current_Execution.pcs.data[--Current_Execution.pcs.next_index]; + try assert_list_length(param, 1); + param = param->value.pair.first; + // NOTE(Felix): we could first get value and eval + // it and restore the cont on an and_then_action + // OR we could restore the cont now and push the + // new unevaluated val on the stack and leave a + // NAS_Actoin::Eval behind. So that's what we + // gonna do. + + Globals::Current_Execution.cs.clear(); + Globals::Current_Execution.ams.clear(); + Globals::Current_Execution.pcs.clear(); + Globals::Current_Execution.nass.clear(); + Globals::Current_Execution.envi_stack.clear(); + Globals::Current_Execution.ats.clear(); + Globals::Current_Execution.mes.clear(); + + // TODO(Felix): This seems super inefficient + for (auto it: pc->value.continuation->cs) { + Globals::Current_Execution.cs.append(it); + } + for (auto it: pc->value.continuation->ams) { + Globals::Current_Execution.ams.append(it); + } + for (auto it: pc->value.continuation->pcs) { + Globals::Current_Execution.pcs.append(it); + } + for (auto it: pc->value.continuation->envi_stack) { + Globals::Current_Execution.envi_stack.append(it); + } + for (auto it: pc->value.continuation->ats) { + Globals::Current_Execution.ats.append(it); + } + for (auto it: pc->value.continuation->mes) { + Globals::Current_Execution.mes.append(it); + } { - Globals::Current_Execution.nass.data[i].append( - pc->value.continuation->nass.data[i].data[Globals::Current_Execution.nass.data[i].next_index]); + Globals::Current_Execution.nass.reserve(pc->value.continuation->nass.next_index); + Globals::Current_Execution.nass.next_index = pc->value.continuation->nass.next_index; + + for (u32 i = 0; i < pc->value.continuation->nass.next_index; ++i) { + Globals::Current_Execution.nass.data[i].alloc(); + for (Globals::Current_Execution.nass.data[i].next_index = 0; + Globals::Current_Execution.nass.data[i].next_index < pc->value.continuation->nass.data[i].next_index;) + { + Globals::Current_Execution.nass.data[i].append( + pc->value.continuation->nass.data[i].data[Globals::Current_Execution.nass.data[i].next_index]); + } + } } + + Globals::Current_Execution.cs.append(param); + (Current_Execution.nass.end()-1)->append(NasAction::Eval); + // debug_break(); + } break; + default: { + create_generic_error("The first element of the pair was not a function but: %{l_o_t} in %{l_o}", + type, pc); + return nullptr; } } - Globals::Current_Execution.cs.append(param); - (Current_Execution.nass.end()-1)->append(NasAction::Eval); - // debug_break(); } break; - default: { - char* t = lisp_object_to_string(pc); - defer_free(t); - - create_generic_error("The first element of the pair was not a function but: %s in %s", - lisp_object_type_to_string(type), t); - return nullptr; - } - } - - } break; - case NasAction::Step: { - if (Current_Execution.pcs.data[Current_Execution.pcs.next_index-1] == Memory::nil) { - --Current_Execution.pcs.next_index; - u32 am = Current_Execution.ams.data[--Current_Execution.ams.next_index]; - Lisp_Object* function = Current_Execution.cs.data[am]; - try assert_type(function, Lisp_Object_Type::Function); - - Environment* extended_env; - try extended_env = create_extended_environment_for_function_application_nrc( - function, am+1, Current_Execution.cs.next_index); - Current_Execution.cs.next_index = am; - push_environment(extended_env); - if (function->value.function->is_c) { - if (function->value.function->type.c_function_type == C_Function_Type::cMacro) - try function->value.function->body.c_macro_body(); - else - try Current_Execution.cs.append(function->value.function->body.c_body()); - pop_environment(); + case NasAction::Step: { + if (Current_Execution.pcs.data[Current_Execution.pcs.next_index-1] == Memory::nil) { + --Current_Execution.pcs.next_index; + u32 am = Current_Execution.ams.data[--Current_Execution.ams.next_index]; + Lisp_Object* function = Current_Execution.cs.data[am]; + try assert_type(function, Lisp_Object_Type::Function); + + Environment* extended_env; + try extended_env = create_extended_environment_for_function_application_nrc( + function, am+1, Current_Execution.cs.next_index); + Current_Execution.cs.next_index = am; + push_environment(extended_env); + if (function->value.function->is_c) { + if (function->value.function->type.c_function_type == C_Function_Type::cMacro) + try function->value.function->body.c_macro_body(); + else + try Current_Execution.cs.append(function->value.function->body.c_body()); + pop_environment(); + } else { + nas->append(NasAction::Pop_Environment); + nas->append(NasAction::Eval); + Current_Execution.cs.append(function->value.function->body.lisp_body); + } } else { - nas->append(NasAction::Pop_Environment); + Current_Execution.cs.append(Current_Execution.pcs.data[Current_Execution.pcs.next_index-1]->value.pair.first); + Current_Execution.pcs.data[Current_Execution.pcs.next_index-1] = Current_Execution.pcs.data[Current_Execution.pcs.next_index-1]->value.pair.rest; + nas->append(NasAction::Step); nas->append(NasAction::Eval); - Current_Execution.cs.append(function->value.function->body.lisp_body); } - } else { - Current_Execution.cs.append(Current_Execution.pcs.data[Current_Execution.pcs.next_index-1]->value.pair.first); - Current_Execution.pcs.data[Current_Execution.pcs.next_index-1] = Current_Execution.pcs.data[Current_Execution.pcs.next_index-1]->value.pair.rest; - nas->append(NasAction::Step); - nas->append(NasAction::Eval); - } - } break; - case NasAction::If: { - /* | | - | | - | | - | .... | */ - Current_Execution.cs.next_index -= 2; - // NOTE(Felix): for false it is sufficent to pop 2 for - // true we have to copy the then part to the new top - // of the stack - if (Current_Execution.cs.data[Current_Execution.cs.next_index+1] != Memory::nil) { - Current_Execution.cs.data[Current_Execution.cs.next_index-1] = Current_Execution.cs.data[Current_Execution.cs.next_index]; + } break; + case NasAction::If: { + /* | | + | | + | | + | .... | */ + Current_Execution.cs.next_index -= 2; + // NOTE(Felix): for false it is sufficent to pop 2 for + // true we have to copy the then part to the new top + // of the stack + if (Current_Execution.cs.data[Current_Execution.cs.next_index+1] != Memory::nil) { + Current_Execution.cs.data[Current_Execution.cs.next_index-1] = Current_Execution.cs.data[Current_Execution.cs.next_index]; + } + } break; + case NasAction::Define_Var: { + /* | | + | | + | .... | */ + Current_Execution.cs.next_index -= 1; + try assert_type(Current_Execution.cs.data[Current_Execution.cs.next_index-1], Lisp_Object_Type::Symbol); + try define_symbol(Current_Execution.cs.data[Current_Execution.cs.next_index-1], Current_Execution.cs.data[Current_Execution.cs.next_index]); + Current_Execution.cs.data[Current_Execution.cs.next_index-1] = Memory::t; } - } break; - case NasAction::Define_Var: { - /* | | - | | - | .... | */ - Current_Execution.cs.next_index -= 1; - try assert_type(Current_Execution.cs.data[Current_Execution.cs.next_index-1], Lisp_Object_Type::Symbol); - try define_symbol(Current_Execution.cs.data[Current_Execution.cs.next_index-1], Current_Execution.cs.data[Current_Execution.cs.next_index]); - Current_Execution.cs.data[Current_Execution.cs.next_index-1] = Memory::t; - } } } @@ -612,7 +613,7 @@ namespace Slime { continue; } if (evaluated && evaluated != Memory::nil) { - print(evaluated); + print("%{l_o}", evaluated); } fputs("\n", stdout); } diff --git a/src/forward_decls.cpp b/src/forward_decls.cpp index 29e49f1..cd159b7 100644 --- a/src/forward_decls.cpp +++ b/src/forward_decls.cpp @@ -17,9 +17,15 @@ namespace Slime { Lisp_Object* lookup_symbol(Lisp_Object* symbol, Environment*); void define_symbol(Lisp_Object* symbol, Lisp_Object* value); void define_symbol(Lisp_Object* symbol, Lisp_Object* value, Environment* env); - char* lisp_object_to_string(Lisp_Object* node, bool print_repr = true); - void print(Lisp_Object* node, bool print_repr = false, FILE* file = stdout); - void print_environment(Environment*); + // char* lisp_object_to_string(Lisp_Object* node, bool print_repr = true); + + // void print_lisp_object(Lisp_Object* node, bool print_repr = false, FILE* file = stdout); + int print_lisp_object(FILE*, Lisp_Object*); + int print_lisp_object_repr(FILE*, Lisp_Object*); + int print_lisp_object_type(FILE*, Lisp_Object_Type); + int print_environment(FILE*, Environment*); + + inline char* duplicate_c_string(const char* str); char* char_to_wchar(const wchar_t* c); wchar_t* char_to_wchar(const char* c); @@ -35,8 +41,6 @@ namespace Slime { inline void push_environment(Environment*); inline void pop_environment(); - const char* lisp_object_type_to_string(Lisp_Object_Type type); - void visualize_lisp_machine(); void generate_docs(String path); void log_error(); diff --git a/src/io.cpp b/src/io.cpp index 31ccd2b..bea9e7b 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -337,84 +337,59 @@ namespace Slime { return res; } - proc lisp_object_to_string(Lisp_Object* node, bool print_repr) -> char* { - char* temp; - Array_List string_builder; - string_builder.alloc(); - defer { - string_builder.dealloc(); - }; + proc print_lisp_object_optional(FILE* f, Lisp_Object* node, bool print_repr) -> int { + int written = 0; - if (!node) return duplicate_c_string(""); + if (!node) + return print_to_file(f, ""); switch (node->type) { - case (Lisp_Object_Type::Nil): return duplicate_c_string("()"); - case (Lisp_Object_Type::T): return duplicate_c_string("t"); - case (Lisp_Object_Type::Continuation): return duplicate_c_string("[continuation]"); - case (Lisp_Object_Type::Pointer): return duplicate_c_string("[pointer]"); + case (Lisp_Object_Type::Nil): return print_to_file(f, "()"); + case (Lisp_Object_Type::T): return print_to_file(f, "t"); + case (Lisp_Object_Type::Continuation): return print_to_file(f, "[continuation]"); + case (Lisp_Object_Type::Pointer): return print_to_file(f, "[pointer]"); + case (Lisp_Object_Type::Keyword): return print_to_file(f, ":%s", Memory::get_c_str(node->value.symbol)); + case (Lisp_Object_Type::Symbol): return print_to_file(f, ":%s", Memory::get_c_str(node->value.symbol)); + case (Lisp_Object_Type::Number): { if (abs(node->value.number - (s32)node->value.number) < 0.000001f) - asprintf(&temp, "%d", (s32)node->value.number); + return print_to_file(f, "%d", (s32)node->value.number); else - asprintf(&temp, "%f", node->value.number); - return temp; - } - case (Lisp_Object_Type::Keyword): { - asprintf(&temp, ":%s", Memory::get_c_str(node->value.symbol)); - return temp; - } - case (Lisp_Object_Type::Symbol): { - asprintf(&temp, "%s", Memory::get_c_str(node->value.symbol)); - return temp; + return print_to_file(f, "%f", node->value.number); } case (Lisp_Object_Type::HashMap): { for_hash_map (*(node->value.hashMap)) { - char* k = lisp_object_to_string(key, true); - char* v = lisp_object_to_string((Lisp_Object*)value, true); - asprintf(&temp, " %s -> %s\n", k, v); - string_builder.append(temp); - free(v); - free(k); - } - - temp = string_buider_to_string(string_builder); - // free all asprintfs - for (auto str : string_builder) { - free(str); + written += fprintf(f, " "); + written += print_lisp_object_optional(f, key, true); + written += fprintf(f, " -> "); + written += print_lisp_object_optional(f, (Lisp_Object*)value, true); + written += fprintf(f, "\n"); } - return temp; + return written; } case (Lisp_Object_Type::String): { if (print_repr) { char* escaped = escape_string(Memory::get_c_str(node->value.string)); - asprintf(&temp, "\"%s\"", escaped); + written = fprintf(f, "\"%s\"", escaped); free(escaped); - return temp; + return written; } else - return duplicate_c_string(Memory::get_c_str(node->value.string)); + return print_to_file(f, "%s", Memory::get_c_str(node->value.string)); } break; case (Lisp_Object_Type::Vector): { - - string_builder.append(duplicate_c_string("[")); + written += print_to_file(f, "["); if (node->value.vector.length > 0) - string_builder.append(lisp_object_to_string(node->value.vector.data, print_repr)); + written += print_lisp_object_optional(f, node->value.vector.data, print_repr); for (u32 i = 1; i < node->value.vector.length; ++i) { - string_builder.append(duplicate_c_string(" ")); - string_builder.append(lisp_object_to_string(node->value.vector.data+i, print_repr)); + written += print_to_file(f, " "); + written += print_lisp_object_optional(f, node->value.vector.data+i, print_repr); } - string_builder.append(duplicate_c_string("]")); - temp = string_buider_to_string(string_builder); - for (auto str : string_builder) { - free(str); - } - return temp; + written += print_to_file(f, "]"); + return written; } break; case (Lisp_Object_Type::Function): { if (Globals::user_types.key_exists(node)) { - asprintf(&temp, "[%s]", - ((Lisp_Object*)Globals::user_types.key_exists(node)) - ->value.symbol.data); - return temp; + return print_to_file(f, "[%s]", ((Lisp_Object*)Globals::user_types.key_exists(node)) ->value.symbol.data); } if (node->value.function->is_c) { @@ -423,36 +398,35 @@ namespace Slime { Lisp_Object* name = (Lisp_Object*)(get_root_environment()->hm.search_key_to_object(node)); if (name) { switch (node->value.function->type.c_function_type) { - case C_Function_Type::cFunction: asprintf(&temp, "[c-function %s]",name->value.symbol.data); break; - case C_Function_Type::cSpecial: asprintf(&temp, "[c-special %s]", name->value.symbol.data); break; - case C_Function_Type::cMacro: asprintf(&temp, "[c-macro %s]", name->value.symbol.data); break; - default: return duplicate_c_string("[c-??]"); + case C_Function_Type::cFunction: return print_to_file(f, "[c-function %s]",name->value.symbol.data); + case C_Function_Type::cSpecial: return print_to_file(f, "[c-special %s]", name->value.symbol.data); + case C_Function_Type::cMacro: return print_to_file(f, "[c-macro %s]", name->value.symbol.data); + default: return print_to_file(f, "[c-??]"); } } else { switch (node->value.function->type.c_function_type) { - case C_Function_Type::cFunction: asprintf(&temp, "[c-function]"); break; - case C_Function_Type::cSpecial: asprintf(&temp, "[c-special]"); break; - case C_Function_Type::cMacro: asprintf(&temp, "[c-macro]"); break; - default: return duplicate_c_string("[c-??]"); + case C_Function_Type::cFunction: return print_to_file(f, "[c-function]"); + case C_Function_Type::cSpecial: return print_to_file(f, "[c-special]"); + case C_Function_Type::cMacro: return print_to_file(f, "[c-macro]"); + default: return print_to_file(f, "[c-??]"); } } - return temp; } else { switch (node->value.function->type.lisp_function_type) { - case Lisp_Function_Type::Lambda: return duplicate_c_string("[lambda]"); - case Lisp_Function_Type::Macro: return duplicate_c_string("[macro]"); - default: return duplicate_c_string("[??]"); + case Lisp_Function_Type::Lambda: return print_to_file(f, "[lambda]"); + case Lisp_Function_Type::Macro: return print_to_file(f, "[macro]"); + default: return print_to_file(f, "[??]"); } } } break; case (Lisp_Object_Type::Pair): { Lisp_Object* head = node; - defer { - for (auto str : string_builder) { - free(str); - } - }; + // defer { + // for (auto str : string_builder) { + // free(str); + // } + // }; // first check if it is a quotation form, in that case we want // to print it prettier if (head->value.pair.first->type == Lisp_Object_Type::Symbol) { @@ -464,73 +438,91 @@ namespace Slime { auto unquote_sym = Memory::get_symbol("unquote"); auto quasiquote_sym = Memory::get_symbol("quasiquote"); auto unquote_splicing_sym = Memory::get_symbol("unquote-splicing"); + // TODO(Felix): Maybe combine if and else? They look kinda the same if (symbol == quote_sym || symbol == unquote_sym || symbol == unquote_splicing_sym) { if (symbol == quote_sym) - string_builder.append(duplicate_c_string("\'")); + written += print_to_file(f, "\'"); else if (symbol == unquote_sym) - string_builder.append(duplicate_c_string(",")); + written += print_to_file(f, ","); else if (symbol == unquote_splicing_sym) - string_builder.append(duplicate_c_string(",@")); + written += print_to_file(f, ",@"); assert_type(head->value.pair.rest, Lisp_Object_Type::Pair); assert("The list must end here.", head->value.pair.rest->value.pair.rest == Memory::nil); - string_builder.append(lisp_object_to_string(head->value.pair.rest->value.pair.first, print_repr)); - return string_buider_to_string(string_builder); + written += print_lisp_object_optional(f, head->value.pair.rest->value.pair.first, print_repr); + return written; } else if (symbol == quasiquote_sym) { - string_builder.append(duplicate_c_string("`")); + written += print_to_file(f, "`"); assert_type(head->value.pair.rest, Lisp_Object_Type::Pair); - string_builder.append(lisp_object_to_string(head->value.pair.rest->value.pair.first, print_repr)); - return string_buider_to_string(string_builder); + written += print_lisp_object_optional(f, head->value.pair.rest->value.pair.first, print_repr); + return written; } } - string_builder.append(duplicate_c_string("(")); + written += print_to_file(f, "("); // NOTE(Felix): We could do a while true here, however in case // we want to print a broken list (for logging the error) we // should do more checks. while (head) { - string_builder.append(lisp_object_to_string(head->value.pair.first, print_repr)); + written += print_lisp_object_optional(f, head->value.pair.first, print_repr); head = head->value.pair.rest; - if (!head) break; + if (!head) break; if (head->type != Lisp_Object_Type::Pair) break; - string_builder.append(duplicate_c_string(" ")); + written += print_to_file(f, " "); } if (head && head != Memory::nil) { - string_builder.append(duplicate_c_string(" . ")); - string_builder.append(lisp_object_to_string(head, print_repr)); + written += print_to_file(f, " . "); + written += print_lisp_object_optional(f, head, print_repr); } - string_builder.append(duplicate_c_string(")")); + written += print_to_file(f, ")"); - return string_buider_to_string(string_builder); + return written; } default: create_generic_error("A Lisp_Object of type-id %d cannot be converted to a string", (u8)(node->type)); - return nullptr; + return 0; } } - proc print(Lisp_Object* node, bool print_repr, FILE* file) -> void { - char* string = nullptr; - defer { - free(string); - }; - string = lisp_object_to_string(node, print_repr); - fputs(string, file); + proc print_lisp_object(FILE* file, Lisp_Object* node) -> int { + return print_lisp_object_optional(file, node, false); + } + + proc print_lisp_object_repr(FILE* file, Lisp_Object* node) -> int { + return print_lisp_object_optional(file, node, true); + } + + proc print_lisp_object_type(FILE* file, Lisp_Object_Type type) -> int { + switch (type) { + case(Lisp_Object_Type::Nil): return print_to_file(file, "nil"); + case(Lisp_Object_Type::T): return print_to_file(file, "t"); + case(Lisp_Object_Type::Number): return print_to_file(file, "number"); + case(Lisp_Object_Type::String): return print_to_file(file, "string"); + case(Lisp_Object_Type::Symbol): return print_to_file(file, "symbol"); + case(Lisp_Object_Type::Keyword): return print_to_file(file, "keyword"); + case(Lisp_Object_Type::Function): return print_to_file(file, "function"); + case(Lisp_Object_Type::Continuation): return print_to_file(file, "continuation"); + case(Lisp_Object_Type::Pair): return print_to_file(file, "pair"); + case(Lisp_Object_Type::Vector): return print_to_file(file, "vector"); + case(Lisp_Object_Type::Pointer): return print_to_file(file, "pointer"); + case(Lisp_Object_Type::HashMap): return print_to_file(file, "hashmap"); + case(Lisp_Object_Type::Invalid_Garbage_Collected): return print_to_file(file, "Invalid: Garbage Collected"); + case(Lisp_Object_Type::Invalid_Under_Construction): return print_to_file(file, "Invalid: Under Construction"); + } + return print_to_file(file, "unknown"); } + proc print_single_call(Lisp_Object* obj) -> void { - printf(console_cyan); - print(obj, true); - printf(console_normal); - printf("\n at "); + print("%{cyan}%{l_o_r}%{normal}\n at ", obj); // TODO(Felix): Enable again when we have a source code // location again @@ -550,14 +542,11 @@ namespace Slime { printf("cs:\n "); for (u32 i = 0; i < Current_Execution.cs.next_index; ++i) { - char* t = lisp_object_to_string(Current_Execution.cs.data[i], true); - defer_free(t); - printf(" %d: %s\n ", i, t); + print(" %d: %{l_o_r}\n ", i, Current_Execution.cs.data[i]); } printf("\npcs:\n "); for (auto lo : Current_Execution.pcs) { - print(lo, true); - printf("\n "); + print("%{l_o_r}\n",lo); } printf("\nnnas:\n "); for (auto nas: Current_Execution.nass) { @@ -589,7 +578,7 @@ namespace Slime { proc log_error() -> void { fputs("\n", stdout); fputs(console_red, stdout); - fputs(Memory::get_c_str(Globals::error->message), stdout); + fputs(Globals::error->message, stdout); puts(console_normal); fputs(" in: ", stdout); diff --git a/src/libslime.cpp b/src/libslime.cpp index bbabed4..5fcb843 100644 --- a/src/libslime.cpp +++ b/src/libslime.cpp @@ -38,6 +38,7 @@ u32 hm_hash(Slime::Lisp_Object* obj); #include "ftb/macros.hpp" #include "ftb/profiler.hpp" #include "ftb/hooks.hpp" +#include "ftb/print.hpp" # include "defines.cpp" # include "assert.hpp" @@ -46,32 +47,10 @@ u32 hm_hash(Slime::Lisp_Object* obj); # include "structs.cpp" # include "forward_decls.cpp" - -inline bool hm_objects_match(char* a, char* b) { - return strcmp(a, b) == 0; -} - -inline bool hm_objects_match(void* a, void* b) { - return a == b; -} - inline bool hm_objects_match(Slime::Lisp_Object* a, Slime::Lisp_Object* b) { return Slime::lisp_object_equal(a, b); } -u32 hm_hash(char* str) { - u32 value = str[0] << 7; - s32 i = 0; - while (str[i]) { - value = (10000003 * value) ^ str[i++]; - } - return value ^ i; -} - -u32 hm_hash(void* ptr) { - return ((u64)ptr * 2654435761) % 4294967296; -} - u32 hm_hash(Slime::Lisp_Object* obj) { using namespace Slime; switch (obj->type) { diff --git a/src/lisp_object.cpp b/src/lisp_object.cpp index 9ea0353..67f7df8 100644 --- a/src/lisp_object.cpp +++ b/src/lisp_object.cpp @@ -10,24 +10,4 @@ namespace Slime { return ret; } - proc lisp_object_type_to_string(Lisp_Object_Type type) -> const char* { - switch (type) { - case(Lisp_Object_Type::Nil): return "nil"; - case(Lisp_Object_Type::T): return "t"; - case(Lisp_Object_Type::Number): return "number"; - case(Lisp_Object_Type::String): return "string"; - case(Lisp_Object_Type::Symbol): return "symbol"; - case(Lisp_Object_Type::Keyword): return "keyword"; - case(Lisp_Object_Type::Function): return "function"; - case(Lisp_Object_Type::Continuation): return "continuation"; - case(Lisp_Object_Type::Pair): return "pair"; - case(Lisp_Object_Type::Vector): return "vector"; - case(Lisp_Object_Type::Pointer): return "pointer"; - case(Lisp_Object_Type::HashMap): return "hashmap"; - case(Lisp_Object_Type::Invalid_Garbage_Collected): return "Invalid: Garbage Collected"; - case(Lisp_Object_Type::Invalid_Under_Construction): return "Invalid: Under Construction"; - } - return "unknown"; - } - } diff --git a/src/memory.cpp b/src/memory.cpp index 54a7b8e..f3eb28e 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -190,6 +190,12 @@ namespace Slime::Memory { proc init() -> void { profile_this(); + init_printer(); + register_printer("env", print_environment, Printer_Function_Type::_ptr); + register_printer("l_o", print_lisp_object, Printer_Function_Type::_ptr); + register_printer("l_o_r", print_lisp_object_repr, Printer_Function_Type::_ptr); + register_printer("l_o_t", print_lisp_object_type, Printer_Function_Type::_32b); + object_memory.alloc(1024, 8); environment_memory.alloc(1024, 8); hashmap_memory.alloc(256, 8); @@ -297,16 +303,19 @@ namespace Slime::Memory { proc allocate_vector(u32 size) -> Lisp_Object* { - Lisp_Object* ret = object_memory.allocate(size); - if (!ret) { - create_out_of_memory_error("The vector is too big to fit in a memory bucket."); - return nullptr; - } + // Lisp_Object* ret = object_memory.allocate(size); + // if (!ret) { + // create_out_of_memory_error("The vector is too big to fit in a memory bucket."); + // return nullptr; + // } + Lisp_Object* ret = (Lisp_Object*)malloc(size * sizeof(Lisp_Object)); return ret; } proc create_lisp_object_vector(u32 length, Lisp_Object* element_list) -> Lisp_Object* { - try assert_type(element_list, Lisp_Object_Type::Pair); + try assert("element_list must be either a pair or nil", + (element_list->type == Lisp_Object_Type::Pair) || + (element_list == Memory::nil)); Lisp_Object* node; try node = create_lisp_object(); @@ -319,6 +328,7 @@ namespace Slime::Memory { u32 i = 0; while (head != Memory::nil) { + // BUG(Felix): We copy symbols here... node->value.vector.data[i] = *head->value.pair.first; head = head->value.pair.rest; ++i; diff --git a/src/structs.cpp b/src/structs.cpp index 70d0b94..135e35e 100644 --- a/src/structs.cpp +++ b/src/structs.cpp @@ -150,6 +150,6 @@ namespace Slime { Lisp_Object* position; // type has to be a keyword Lisp_Object* type; - String message; + char* message; }; } diff --git a/src/testing.cpp b/src/testing.cpp index a98868d..9ededf9 100644 --- a/src/testing.cpp +++ b/src/testing.cpp @@ -6,15 +6,15 @@ namespace Slime { #define fail 0 #define print_assert_equal_fail(variable, value, type, format) \ - printf("\n%s:%d: Assertion failed\n\tfor '" #variable "'" \ - "\n\texpected: " format \ - "\n\tgot: " format "\n", \ + print("\n%s:%d: Assertion failed\n\tfor '" #variable "'" \ + "\n\texpected: " format \ + "\n\tgot: " format "\n", \ __FILE__, __LINE__, (type)value, (type)variable) #define print_assert_not_equal_fail(variable, value, type, format) \ - printf("\n%s:%d: Assertion failed\n\tfor '" #variable "'" \ - "\n\texpected not: " format \ - "\n\tgot anyways: " format "\n", \ + print("\n%s:%d: Assertion failed\n\tfor '" #variable "'" \ + "\n\texpected not: " format \ + "\n\tgot anyways: " format "\n", \ __FILE__, __LINE__, (type)value, (type)variable) #define assert_equal_int(variable, value) \ @@ -59,17 +59,16 @@ namespace Slime { #define assert_equal_string(variable, value) \ if (!string_equal(variable, value)) { \ - print_assert_equal_fail(variable.data, value, char*, "%s"); \ + print_assert_equal_fail(variable.data, value, char*, "%s"); \ return fail; \ } -#define assert_equal_type(node, _type) \ - if (node->type != _type) { \ - print_assert_equal_fail( \ - lisp_object_type_to_string(node->type), \ - lisp_object_type_to_string(_type), char*, "%s"); \ - return fail; \ - } \ +#define assert_equal_type(node, _type) \ + if (node->type != _type) { \ + print_assert_equal_fail(node->type, _type, Lisp_Object_Type, \ + "%{l_o_t}"); \ + return fail; \ + } \ #define assert_null(variable) \ assert_equal_int(variable, nullptr)