Przeglądaj źródła

cleanup and writing docs

master
FelixBrendel 7 lat temu
rodzic
commit
321ef46a84
4 zmienionych plików z 61 dodań i 1022 usunięć
  1. +46
    -30
      bin/pre.slime
  2. +15
    -15
      src/error.c
  3. +0
    -539
      todo.html
  4. +0
    -438
      todo.org

+ 46
- 30
bin/pre.slime Wyświetl plik

@@ -1,15 +1,13 @@
(define nil ())

(define defun
(macro (@name @params :rest @body)
(eval (pair 'define (pair @name (pair (pair 'lambda (pair @params @body)) nil))))))

(define defmacro
(macro (@name @params :rest @body)
(eval (pair 'define (pair @name (pair (pair 'macro (pair @params @body)) nil))))))
"Macro for creating macros with a more concise syntax."
(eval (pair 'define (pair @name (pair (pair 'macro (pair @params @body)) nil))))))

(defmacro pe (@expr)
(printf @expr "evaluates to" (eval @expr)))
(defmacro defun (@name @params :rest @body)
"Macro for creating functions with a more concise syntax."
(eval (pair 'define (pair @name (pair (pair 'lambda (pair @params @body)) nil)))))

(defun nil? (x)
"Checks if the argument is nil."
@@ -53,7 +51,7 @@ ithe sequence as arguemens."
(eval (pair fun seq)))

(defmacro when (@test :rest @body)
"Executes the code in :rest if test is true"
"Executes the code in :rest if test is true."
(if (eval @test)
(eval (pair prog @body))
nil))
@@ -83,25 +81,35 @@ the (rest) of the last element of the sequence."
seq)

(defun incr (val)
"Adds one to the argument."
(+ val 1))

(defun decr (val)
"Subtracts one from the argument."
(- val 1))

(defun append (seq elem)
"Appends an element to a sequence, by extendeing the list
with (pair elem nil)."
(extend seq (pair elem nil)))

(defun length (seq)
"Returns the length of the given sequence."
(if (nil? seq)
0
(incr (length (rest seq)))))

(defmacro n-times (@times @action)
"Executes @action @times times."
(unless (<= (eval @times) 0)
(eval @action)
(eval (list n-times (list - @times 1) @action))))
(apply n-times (list (list - @times 1) @action))))

(defmacro for (@symbol @from @to :rest @for-body)
"Designed to resemble a C style for loop. It takes a symbol as
well as its starting number and end number and executes the
@for-body with the defined symbol for all numbers between @from
to @to, where @to is exclusive."
(if (< (eval @from) (eval @to))
(macro-define @op incr)
(if (> (eval @from) (eval @to))
@@ -115,12 +123,11 @@ the (rest) of the last element of the sequence."
(defun range (:keys from :defaults-to 0 to)
"Returns a sequence of numbers starting with the number defined
by the key 'from' and ends with the number defined in 'to'."
(if (< from to)
(pair from (range :from (+ 1 from) :to to))
nil))
(when (< from to)
(pair from (range :from (+ 1 from) :to to))))

(defun map (fun seq)
"Takes a sequence and a function as arguments and returns a new
"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."
(if (nil? seq)
@@ -129,15 +136,15 @@ elemens as argument to that function."
(map fun (rest seq)))))

(defun reduce (fun seq)
"Takes a sequence and a function as arguments and applies the
"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."
(eval (pair fun seq)))
(apply fun seq))

(defun reduce-binary (fun seq)
"Takes a sequence and a function as arguments and applies the
"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'."
@@ -147,23 +154,32 @@ as compared to `reduce'."
(reduce-binary fun (rest seq)))))

(defun filter (fun seq)
(if (nil? seq)
nil
"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."
(when seq
(if (fun (first seq))
(pair (first seq)
(filter fun (rest seq)))
(filter fun (rest seq)))))

(defmacro printf-quoted (:keys @sep :defaults-to " " @end :defaults-to "\n" :rest @args)
(if (nil? @args)
(prog (print (eval @end)) nil)
(prog
(print (first @args))
(when (not (nil? (rest @args))) (print (eval @sep)))
(eval
(pair printf-quoted
(extend (list :@sep (eval @sep) :@end (eval @end)) (rest @args)))))))

(defun printf (:keys sep :defaults-to " " end :defaults-to "\n" :rest args)
(define command-args (extend (list :@sep (eval sep) :@end (eval end)) args))
(eval (pair printf-quoted command-args)))
"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."
(defmacro printf-quoted (:keys @sep @end :rest @args)
(if (nil? @args)
(prog (print (eval @end)) nil)
(prog
(print (first @args))
(unless (nil? (rest @args))
(print (eval @sep)))
(eval (pair printf-quoted
(extend (list :@sep (eval @sep) :@end (eval @end)) (rest @args)))))))

(eval (pair printf-quoted (extend (list :@sep (eval sep) :@end (eval end)) args))))

(defmacro pe (@expr)
(printf @expr "evaluates to" (eval @expr)))

+ 15
- 15
src/error.c Wyświetl plik

@@ -1,18 +1,18 @@
typedef enum {
Error_Type_Ill_Formed_List,
Error_Type_Ill_Formed_Arguments,
Error_Type_Ill_Formed_Lambda_List,
Error_Type_Wrong_Number_Of_Arguments,
Error_Type_Unknown_Keyword_Argument,
Error_Type_Type_Missmatch,
Error_Type_Symbol_Not_Defined,
Error_Type_Ill_Formed_List,
Error_Type_Not_A_Function,
Error_Type_Not_Yet_Implemented,
Error_Type_Symbol_Not_Defined,
Error_Type_Syntax_Error,
Error_Type_Unexpected_Eof,
Error_Type_Unbalanced_Parenthesis,
Error_Type_Trailing_Garbage,
Error_Type_Type_Missmatch,
Error_Type_Unbalanced_Parenthesis,
Error_Type_Unexpected_Eof,
Error_Type_Unknown_Error,
Error_Type_Unknown_Keyword_Argument,
Error_Type_Wrong_Number_Of_Arguments,
} Error_Type;

typedef struct {
@@ -31,7 +31,7 @@ void delete_error() {

void create_error(Error_Type type, Ast_Node* location) {
delete_error();
error = new(Error);
error->type = type;
error->location = location;
@@ -39,19 +39,19 @@ void create_error(Error_Type type, Ast_Node* location) {

char* Error_Type_to_string(Error_Type type) {
switch (type) {
case Error_Type_Ill_Formed_List: return "Evaluation-error: Ill formed list";
case Error_Type_Ill_Formed_Arguments: return "Evaluation-error: Ill formed arguments";
case Error_Type_Ill_Formed_Lambda_List: return "Evaluation-error: Ill formed lambda list";
case Error_Type_Unknown_Keyword_Argument: return "Evaluation-error: Unknown keyword argument";
case Error_Type_Ill_Formed_List: return "Evaluation-error: Ill formed list";
case Error_Type_Not_A_Function: return "Evaluation-error: Not a function";
case Error_Type_Symbol_Not_Defined: return "Evaluation-error: Symbol not defined";
case Error_Type_Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments";
case Error_Type_Type_Missmatch: return "Evaluation-error: Type Missmatch";
case Error_Type_Not_Yet_Implemented: return "Evaluation-error: Not yet implemented";
case Error_Type_Trailing_Garbage: return "Evaluation-error: Trailing garbage following expression";
case Error_Type_Symbol_Not_Defined: return "Evaluation-error: Symbol not defined";
case Error_Type_Syntax_Error: return "Syntax Error";
case Error_Type_Unexpected_Eof: return "Parsing-error: Unexpected EOF";
case Error_Type_Trailing_Garbage: return "Evaluation-error: Trailing garbage following expression";
case Error_Type_Type_Missmatch: return "Evaluation-error: Type Missmatch";
case Error_Type_Unbalanced_Parenthesis: return "Parsing-error: Unbalanced parenthesis";
case Error_Type_Unexpected_Eof: return "Parsing-error: Unexpected EOF";
case Error_Type_Unknown_Keyword_Argument: return "Evaluation-error: Unknown keyword argument";
case Error_Type_Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments";
default: return "Unknown Error";
}
}

+ 0
- 539
todo.html Wyświetl plik

@@ -1,539 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<title></title>
<!-- 2018-10-14 So 16:55 -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="Org-mode">
<meta name="author" content="Felix Brendel">

<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.min.js"></script>
<style type="text/css">
/* org mode styles on top of twbs */

html {
position: relative;
min-height: 100%;
}

body {
font-size: 18px;
margin-bottom: 105px;
}

footer {
position: absolute;
bottom: 0;
width: 100%;
height: 101px;
background-color: #f5f5f5;
}

footer > div {
padding: 10px;
}

footer p {
margin: 0 0 5px;
text-align: center;
font-size: 16px;
}

#table-of-contents {
margin-top: 20px;
margin-bottom: 20px;
}

blockquote p {
font-size: 18px;
}

pre {
font-size: 16px;
}

.footpara {
display: inline-block;
}

figcaption {
font-size: 16px;
color: #666;
font-style: italic;
padding-bottom: 15px;
}

/* from twbs docs */

.bs-docs-sidebar.affix {
position: static;
}
@media (min-width: 768px) {
.bs-docs-sidebar {
padding-left: 20px;
}
}

/* All levels of nav */
.bs-docs-sidebar .nav > li > a {
display: block;
padding: 4px 20px;
font-size: 14px;
font-weight: 500;
color: #999;
}
.bs-docs-sidebar .nav > li > a:hover,
.bs-docs-sidebar .nav > li > a:focus {
padding-left: 19px;
color: #A1283B;
text-decoration: none;
background-color: transparent;
border-left: 1px solid #A1283B;
}
.bs-docs-sidebar .nav > .active > a,
.bs-docs-sidebar .nav > .active:hover > a,
.bs-docs-sidebar .nav > .active:focus > a {
padding-left: 18px;
font-weight: bold;
color: #A1283B;
background-color: transparent;
border-left: 2px solid #A1283B;
}

/* Nav: second level (shown on .active) */
.bs-docs-sidebar .nav .nav {
display: none; /* Hide by default, but at >768px, show it */
padding-bottom: 10px;
}
.bs-docs-sidebar .nav .nav > li > a {
padding-top: 1px;
padding-bottom: 1px;
padding-left: 30px;
font-size: 12px;
font-weight: normal;
}
.bs-docs-sidebar .nav .nav > li > a:hover,
.bs-docs-sidebar .nav .nav > li > a:focus {
padding-left: 29px;
}
.bs-docs-sidebar .nav .nav > .active > a,
.bs-docs-sidebar .nav .nav > .active:hover > a,
.bs-docs-sidebar .nav .nav > .active:focus > a {
padding-left: 28px;
font-weight: 500;
}

/* Nav: third level (shown on .active) */
.bs-docs-sidebar .nav .nav .nav {
padding-bottom: 10px;
}
.bs-docs-sidebar .nav .nav .nav > li > a {
padding-top: 1px;
padding-bottom: 1px;
padding-left: 40px;
font-size: 12px;
font-weight: normal;
}
.bs-docs-sidebar .nav .nav .nav > li > a:hover,
.bs-docs-sidebar .nav .nav .nav > li > a:focus {
padding-left: 39px;
}
.bs-docs-sidebar .nav .nav .nav > .active > a,
.bs-docs-sidebar .nav .nav .nav > .active:hover > a,
.bs-docs-sidebar .nav .nav .nav > .active:focus > a {
padding-left: 38px;
font-weight: 500;
}

/* Show and affix the side nav when space allows it */
@media (min-width: 992px) {
.bs-docs-sidebar .nav > .active > ul {
display: block;
}
/* Widen the fixed sidebar */
.bs-docs-sidebar.affix,
.bs-docs-sidebar.affix-bottom {
width: 213px;
}
.bs-docs-sidebar.affix {
position: fixed; /* Undo the static from mobile first approach */
top: 20px;
}
.bs-docs-sidebar.affix-bottom {
position: absolute; /* Undo the static from mobile first approach */
}
.bs-docs-sidebar.affix .bs-docs-sidenav,.bs-docs-sidebar.affix-bottom .bs-docs-sidenav {
margin-top: 0;
margin-bottom: 0
}
}
@media (min-width: 1200px) {
/* Widen the fixed sidebar again */
.bs-docs-sidebar.affix-bottom,
.bs-docs-sidebar.affix {
width: 263px;
}
}
</style>
<script type="text/javascript">
$(function() {
'use strict';

$('.bs-docs-sidebar li').first().addClass('active');

$(document.body).scrollspy({target: '.bs-docs-sidebar'});

$('.bs-docs-sidebar').affix();
});
</script>
</head>
<body>
<div id="content" class="container">
<div class="row"><div class="col-md-9"><h1 class="title"></h1>
<div id="outline-container-sec-1" class="outline-2">
<h2 id="sec-1"><span class="section-number-2">1</span> Arguments</h2>
<div class="outline-text-2" id="text-1">
<p>
In Emacs lisp, keyword arguments must be passed in the same order as they were
defined in, so <code>((lambda (a &amp;key b c) (+ a b c)) 1 3 :b 2)</code> will preduce an
error, because <code>b</code> was passed as last argument but was defined as second argument.
</p>
<div class="org-src-container">

<pre class="src src-emacs-lisp"><span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a b<span style="color: #b58900;">)</span> <span style="color: #b58900;">(</span>+ a b<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 2<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">3</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a <span style="color: #268bd2;">&amp;key</span> b<span style="color: #b58900;">)</span> <span style="color: #b58900;">(</span>+ a b<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 <span style="color: #6c71c4;">:b</span> 2<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">3</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a <span style="color: #268bd2;">&amp;key</span> b<span style="color: #b58900;">)</span> <span style="color: #b58900;">(</span>+ a b<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> <span style="color: #6c71c4;">:b</span> 2 1<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">error</span>
</pre>
</div>


<p>
But if mulitiple keyword arguments are defined, their ordering does not matter.
</p>
<div class="org-src-container">

<pre class="src src-emacs-lisp"><span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a <span style="color: #268bd2;">&amp;key</span> b <span style="color: #268bd2;">&amp;key</span> c <span style="color: #268bd2;">&amp;key</span> d<span style="color: #b58900;">)</span> <span style="color: #b58900;">(</span>+ a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 <span style="color: #6c71c4;">:d</span> 4 <span style="color: #6c71c4;">:c</span> 3 <span style="color: #6c71c4;">:b</span> 2<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">10</span>
</pre>
</div>

<p>
It is even possible to have a non keyword argument bewtween keyword arguments
and when calling, switch the order.
</p>
<div class="org-src-container">

<pre class="src src-emacs-lisp"><span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a <span style="color: #268bd2;">&amp;key</span> b c <span style="color: #268bd2;">&amp;key</span> d<span style="color: #b58900;">)</span> <span style="color: #b58900;">(</span>+ a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 <span style="color: #6c71c4;">:d</span> 4 3 <span style="color: #6c71c4;">:b</span> 2<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">10</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a <span style="color: #268bd2;">&amp;key</span> b c <span style="color: #268bd2;">&amp;key</span> d<span style="color: #b58900;">)</span> <span style="color: #b58900;">(</span>+ a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 <span style="color: #6c71c4;">:d</span> 4 <span style="color: #6c71c4;">:b</span> 2 3<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">error</span>
</pre>
</div>

<p>
However somehow it is not possible to flip the ordering at the first argument
</p>
<div class="org-src-container">

<pre class="src src-emacs-lisp"><span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a <span style="color: #268bd2;">&amp;key</span> b<span style="color: #b58900;">)</span> <span style="color: #b58900;">(</span>+ a b<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 2 <span style="color: #6c71c4;">:b</span> 1<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">3</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a <span style="color: #268bd2;">&amp;key</span> b<span style="color: #b58900;">)</span> <span style="color: #b58900;">(</span>+ a b<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> <span style="color: #6c71c4;">:b</span> 2 1<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">error</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span><span style="color: #268bd2;">&amp;key</span> a b<span style="color: #b58900;">)</span> <span style="color: #b58900;">(</span>+ a b<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> <span style="color: #6c71c4;">:a</span> 2 1<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">3</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span><span style="color: #268bd2;">&amp;key</span> a b<span style="color: #b58900;">)</span> <span style="color: #b58900;">(</span>+ a b<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 <span style="color: #6c71c4;">:a</span> 2<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">error</span>
</pre>
</div>

<p>
So it seems, positional arguments have to be at the exact position they were
defined in, but keyword arguments can appear in any order, but at the places
where keyword arguments have been defined.
</p>
</div>

<div id="outline-container-sec-1-1" class="outline-3">
<h3 id="sec-1-1"><span class="section-number-3">1.1</span> Idea</h3>
<div class="outline-text-3" id="text-1-1">
<p>
Every argument can be set using keys, but keyword arguments always come strictly
after positional arguments
</p>

<div class="org-src-container">

<pre class="src src-emacs-lisp"><span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 2 3 4<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">ok</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 2 <span style="color: #6c71c4;">:c</span> 2 <span style="color: #6c71c4;">:d</span> 1<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">ok</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 2 <span style="color: #6c71c4;">:d</span> 1 <span style="color: #6c71c4;">:c</span> 2<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">ok</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> <span style="color: #6c71c4;">:d</span> 1 1 2 <span style="color: #6c71c4;">:c</span> 2<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">error, keyword arguments must come last</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 2 <span style="color: #6c71c4;">:c</span> 2 <span style="color: #6c71c4;">:d</span> 1 <span style="color: #6c71c4;">:a</span> 2<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">error, 'a' was passed two times</span>

<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 2 <span style="color: #6c71c4;">:d</span> 1<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">error, c was not passed, but does not have a default value</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a b c <span style="color: #6c71c4;">:default</span> 10 d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> 1 2 <span style="color: #6c71c4;">:d</span> 1<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">okay again</span>
</pre>
</div>

<p>
The drawback then is that you can never pass a keyword as a positional argument,
because it will always try to assign the next argument to the variable defined
by the keyword. You could still pass it as a keyword argument though. This is
especially annoying because we want to use keywords as type identifiers.
</p>

<div class="org-src-container">

<pre class="src src-emacs-lisp"><span style="color: #839496;">(</span>= <span style="color: #2aa198;">(</span>type <span style="color: #2aa198;">"hello"</span><span style="color: #2aa198;">)</span> <span style="color: #6c71c4;">:string</span><span style="color: #839496;">)</span>
</pre>
</div>


<div class="org-src-container">

<pre class="src src-emacs-lisp"><span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>i-wanna-get-a-kw<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> <span style="color: #6c71c4;">:hey</span><span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">error, unmatched value for keyword argument</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>i-wanna-get-a-kw<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> <span style="color: #6c71c4;">:i-wanna-get-a-kw</span> <span style="color: #6c71c4;">:hey</span><span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">this would work again</span>
</pre>
</div>

<p>
Other Idea is to mark the place in the parameter list where keyword argumetns
start and arguments before that are positional and will not be stuffed into
key-value pairs and arguments after that will be keyword arguments
</p>

<div class="org-src-container">

<pre class="src src-ebnf">&lt;lambda list&gt; -&gt; &lt;positional argument&gt;*
[:keys ( &lt;keyword arguments&gt; [:defaults-to &lt;value&gt;])*]
[(:rest &lt;rest argument&gt;)|(:body &lt;body argument&gt;)]
</pre>
</div>

<div class="org-src-container">

<pre class="src src-emacs-lisp"> <span style="color: #839496;">(</span>= <span style="color: #2aa198;">(</span>type <span style="color: #2aa198;">"hello"</span><span style="color: #2aa198;">)</span> <span style="color: #6c71c4;">:string</span><span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">this will work again because (=) does</span>
<span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">not use keyword arguments</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>i-wanna-get-a-kw<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span> <span style="color: #6c71c4;">:hey</span><span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">would work because of the same reason</span>

<span style="color: #839496;">(</span>define fun
<span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span><span style="color: #6c71c4;">:keys</span> a b c d<span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span>+ a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span><span style="color: #839496;">)</span>

<span style="color: #839496;">(</span>fun 1 2 3 4<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">okay</span>
<span style="color: #839496;">(</span>fun 1 2 <span style="color: #6c71c4;">:d</span> 3 <span style="color: #6c71c4;">:c</span> 4<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">okay</span>
<span style="color: #839496;">(</span>fun 1 2 <span style="color: #6c71c4;">:d</span> 3 <span style="color: #6c71c4;">:c</span> 4 <span style="color: #6c71c4;">:a</span> 2<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">error, 'a' was passed two times</span>
<span style="color: #839496;">(</span>fun <span style="color: #6c71c4;">:c</span> 1 <span style="color: #6c71c4;">:b</span> 2 <span style="color: #6c71c4;">:d</span> 3 <span style="color: #6c71c4;">:a</span> 4<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">okay</span>
<span style="color: #839496;">(</span>fun <span style="color: #6c71c4;">:c</span> 1 <span style="color: #6c71c4;">:b</span> 2 <span style="color: #6c71c4;">:d</span> 3 4<span style="color: #839496;">)</span> <span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">error, positional argument after keyword</span>
<span style="color: #49974A; font-style: italic;">;; </span><span style="color: #49974A; font-style: italic;">and fun does not accept rest parameter</span>

<span style="color: #839496;">(</span>define fun2
<span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span><span style="color: #6c71c4;">:quoted</span> op a b <span style="color: #6c71c4;">:keys</span> c d <span style="color: #6c71c4;">:rest</span> r<span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span>print r<span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span>op a b c d<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span><span style="color: #839496;">)</span>

&gt;&gt; <span style="color: #839496;">(</span>fun2 * 1 2 <span style="color: #6c71c4;">:c</span> 3 <span style="color: #6c71c4;">:d</span> 4 <span style="color: #2aa198;">"this"</span> <span style="color: #2aa198;">"can"</span> <span style="color: #6c71c4;">:be</span> <span style="color: #2aa198;">"whatever"</span><span style="color: #839496;">)</span>
<span style="color: #839496;">(</span><span style="color: #2aa198;">"this"</span> <span style="color: #2aa198;">"can"</span> <span style="color: #6c71c4;">:be</span> <span style="color: #2aa198;">"whatever"</span><span style="color: #839496;">)</span>
24


&gt;&gt; <span style="color: #839496;">(</span>define print-before-eval <span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span><span style="color: #6c71c4;">:body</span> expr<span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span>print expr<span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span>eval expr<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span><span style="color: #839496;">)</span>
&gt;&gt; <span style="color: #839496;">(</span>define r <span style="color: #2aa198;">(</span>print-before-eval <span style="color: #b58900;">(</span>+ 1 2 3<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span><span style="color: #839496;">)</span>
<span style="color: #839496;">(</span>+ 1 2 3<span style="color: #839496;">)</span>
&gt;&gt; r
6

</pre>
</div>

<p>
Wait this does not work either because you won't be able to pass keywords into
rest.
</p>

<p>
<b>Unrealated Idea: Distinguish between functions and macros</b>
</p>

<p>
The difference is really simple:
</p>
<dl class="org-dl">
<dt> Function </dt><dd>like a lambda, but no argument is automatically quoted
</dd>
<dt> Macro </dt><dd>like a lambda, but every argument is automatically quoted
</dd>
</dl>

<p>
This is important, because a macro should not introduce a new environment, but
use the one it lives in.
</p>

<div class="org-src-container">

<pre class="src src-emacs-lisp">&gt;&gt; <span style="color: #839496;">(</span>define print-before-eval <span style="color: #2aa198;">(</span>macro <span style="color: #b58900;">(</span><span style="color: #6c71c4;">:rest</span> expr<span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span>print expr<span style="color: #b58900;">)</span>
<span style="color: #b58900;">(</span>eval expr<span style="color: #b58900;">)</span><span style="color: #2aa198;">)</span>

</pre>
</div>
</div>
</div>

<div id="outline-container-sec-1-2" class="outline-3">
<h3 id="sec-1-2"><span class="section-number-3">1.2</span> the actual problem</h3>
<div class="outline-text-3" id="text-1-2">
<p>
We have some requirements to the arguments:
</p>
<ul class="org-ul">
<li>positional arguments (always required, no default value)
</li>
<li>keyword arguments (always come after positionals), can be not passed if there
is a default value
</li>
<li>We want to be able to have a rest paramter, where everything is dumped in to
that exceeds the other parameters
</li>
</ul>

<p>
<b>The problem is, we have no way of knowing if the current keyword we are
reading is still part of the keyword block or part of the rest paramter.</b>
</p>

<p>
Consider:
</p>

<div class="org-src-container">

<pre class="src src-emacs-lisp">&gt;&gt; <span style="color: #839496;">(</span>define fun <span style="color: #2aa198;">(</span><span style="color: #859900;">lambda</span> <span style="color: #b58900;">(</span>a b <span style="color: #6c71c4;">:key</span> c d <span style="color: #6c71c4;">:defaults-to</span> 4 <span style="color: #6c71c4;">:rest</span><span style="color: #b58900;">)</span> nil<span style="color: #2aa198;">)</span><span style="color: #839496;">)</span>
&gt;&gt; <span style="color: #839496;">(</span>fun 1 2 <span style="color: #6c71c4;">:c</span> 3 <span style="color: #6c71c4;">:d</span> 5<span style="color: #839496;">)</span>
</pre>
</div>
<p>
What should this be evaluated to?
</p>

<table class="table table-striped table-bordered table-hover table-condensed">


<colgroup>
<col class="left">

<col class="right">

<col class="right">

<col class="right">

<col class="right">

<col class="left">
</colgroup>
<thead>
<tr>
<th scope="col" class="text-left">&#xa0;</th>
<th scope="col" class="text-right">a</th>
<th scope="col" class="text-right">b</th>
<th scope="col" class="text-right">c</th>
<th scope="col" class="text-right">d</th>
<th scope="col" class="text-left">rest</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-left">v1</td>
<td class="text-right">1</td>
<td class="text-right">2</td>
<td class="text-right">3</td>
<td class="text-right">5</td>
<td class="text-left">nil</td>
</tr>

<tr>
<td class="text-left">v2</td>
<td class="text-right">1</td>
<td class="text-right">2</td>
<td class="text-right">3</td>
<td class="text-right">4</td>
<td class="text-left">(:d 5)</td>
</tr>
</tbody>
</table>

<p>
It is ambiguous. It is however important to note that this can only happen when
there are optinal keyword arguments (keyword arguments with default values).
Otherwise we could always know which variables are set and wich have not been
set to see if we are in an errornious state.
</p>
</div>
</div>

<div id="outline-container-sec-1-3" class="outline-3">
<h3 id="sec-1-3"><span class="section-number-3">1.3</span> Solution</h3>
<div class="outline-text-3" id="text-1-3">
<p>
We can resolve that problem by always making the the decision of chosing <code>v1</code>
between <code>v1</code> and <code>v1</code>. This means, when we are expecting to read kwargs, and we
encounter an kwarg, try to apply it (this can fail, for two reasons:
</p>

<ol class="org-ol">
<li>The keyword has no following value
</li>
<li>The keyword is not a keyword argument in the funciton
</li>
</ol>

<p>
), if it fails treat it as part of the rest arguments, and read all the
following arguments into the rest arguments, or if it works, use it as the
keyword argument.
</p>
</div>
</div>

<div id="outline-container-sec-1-4" class="outline-3">
<h3 id="sec-1-4"><span class="section-number-3">1.4</span> Implementation</h3>
<div class="outline-text-3" id="text-1-4">
<div class="org-src-container">

<pre class="src src-c"><span style="color: #859900;">typedef</span> <span style="color: #859900;">struct</span> <span style="color: #839496;">{</span>
<span style="color: #268bd2;">char</span>* <span style="color: #6c71c4;">docstring</span>;
<span style="color: #268bd2;">char</span>** <span style="color: #6c71c4;">positional_arguments</span>;
<span style="color: #859900;">struct</span> <span style="color: #2aa198;">{</span>
<span style="color: #268bd2;">char</span>* <span style="color: #6c71c4;">identifier</span>;
<span style="color: #268bd2;">Ast_node</span>* <span style="color: #6c71c4;">default_value</span>; <span style="color: #49974A; font-style: italic;">// </span><span style="color: #49974A; font-style: italic;">will be nullptr if no defalut value was declared</span>
<span style="color: #2aa198;">}</span>* <span style="color: #6c71c4;">keyword_arguments</span>;
<span style="color: #268bd2;">char</span>* <span style="color: #6c71c4;">rest_argument</span>; <span style="color: #49974A; font-style: italic;">// </span><span style="color: #49974A; font-style: italic;">will be nullptr if no rest argument is declared</span>
<span style="color: #268bd2;">Ast_Node_array_list</span> <span style="color: #6c71c4;">body</span>;
<span style="color: #839496;">}</span> <span style="color: #268bd2;">lambda</span>;
</pre>
</div>
</div>
</div>
</div>
</div><div class="col-md-3"><nav id="table-of-contents">
<div id="text-table-of-contents" class="bs-docs-sidebar">
<ul class="nav">
<li><a href="#sec-1">1. Arguments</a>
<ul class="nav">
<li><a href="#sec-1-1">1.1. Idea</a></li>
<li><a href="#sec-1-2">1.2. the actual problem</a></li>
<li><a href="#sec-1-3">1.3. Solution</a></li>
<li><a href="#sec-1-4">1.4. Implementation</a></li>
</ul>
</li>
</ul>
</div>
</nav>
</div></div></div>
<footer id="postamble" class="">
<div><p class="author">Author: Felix Brendel</p>
<p class="date">Created: 2018-10-14 So 16:55</p>
<p class="creator"><a href="http://www.gnu.org/software/emacs/">Emacs</a> 26.0.91 (<a href="http://orgmode.org">Org-mode</a> 9.1.13)</p>
</div>
</footer>
</body>
</html>

+ 0
- 438
todo.org Wyświetl plik

@@ -1,438 +0,0 @@
* Issues
** DONE #001
CLOSED: [2018-10-26 Fr 22:36]

#+begin_src lisp
(define seq (list 1 2 3))
(when 1 (printf seq))
#+end_src

The problem is, that =when= calls =apply= and the params of =apply= are named =fun= and =seq=. So
when we refer to seq in =printf= then we are refering to the =apply='s argument names. Maybe a good
solution to that is, that a child environment can never look up something in a parent macro
environment, but will always pass through

| stack depth | is macro environment | defined symbols | scope |
|-------------+----------------------+--------------------------+---------------------|
| 0 | no | seq nil printf apply etc | |
| 1 | yes | test body | (when 1 printf seq) |
| 2 | yes | fun seq | (apply prog body) |
| 3 | no | | (printf seq) |

** DONE #002
CLOSED: [2018-10-27 Sa 13:50]
#+begin_src lisp
(define l (list 1 2 3))
(extend l 4)

;; === Environment ===
;; current: in (apply)
;; fun -> prog
;; seq -> body
;; parent (hidden): in (when)
;; test -> (pair? seq)
;; body -> ((define e (end seq)) (mutate e (pair (first e) elem)))
;; parent: in (extend)
;; seq -> (1.000000 2.000000 3.000000)
;; elem -> 4.000000
;; parent: (top level)
;; nil -> nil
;; defun -> [macro]
;; defmacro -> [macro]
;; pe -> [macro]
;; nil? -> [lambda]
;; number? -> [lambda]
;; symbol? -> [lambda]
;; keyword? -> [lambda]
;; pair? -> [lambda]
;; string? -> [lambda]
;; dynamic-function? -> [lambda]
;; dynamic-macro? -> [lambda]
;; built-in-function? -> [lambda]
;; apply -> [macro]
;; when -> [macro]
;; unless -> [macro]
;; end -> [lambda]
;; last -> [lambda]
;; extend -> [lambda]
;; append -> [lambda]
;; n-times -> [macro]
;; range -> [lambda]
;; map -> [lambda]
;; reduce -> [lambda]
;; reduce-binary -> [lambda]
;; filter -> [lambda]
;; printf-quoted -> [macro]
;; printf -> [lambda]
;; l -> (1.000000 2.000000 3.000000)

;; M (apply fun -> prog seq -> body)
;; M (when test -> (pair? seq) body -> ((define e (end seq)) (mutate e (pair (first e) elem))))
;; (extend seq -> (1.000000 2.000000 3.000000) elem -> 4.000000)
#+end_src

The problem is that a funciton g called by a function f has access to the environment of f. This is
a real problem.

#+begin_src lisp
(defun f () 1)
(defun g () (f))
(defun h (f) (g))
(h 4)
#+end_src

What *should* happen:
- (h 1) calls (g)
- (g) calls (f)
- (f) retunrs 1

What *actually* happens:
- (h 1) calls (g)
- (g) tries to call (f) but f is not a funciton but =4=

** DONE #003
CLOSED: [2018-10-27 Sa 15:22]
#+begin_src lisp
(defmacro n-times (times action)
(unless (<= (eval times) 0)
(breakpoint)
(eval action)
(macro-define args (pair (pair - (pair (eval times) (pair 1 nil))) (pair action nil)))
;; [o|o] --------------------------> [o|o] -> nil
;; | |
;; V V
;; [o|o] -> [o|o] -> [o|o]-> nil action
;; | | |
;; V V V
;; - times 1
(eval (pair n-times args))))
#+end_src

- *let* should never have access to parenting macro because =(while 2 test) -> 2.00000=
- Should it have access to the grandad macro?
- no, =(when 2 (when 3 test)) -> 2=

- in the example, =n-times= is a macro, that calls =unless=, that itself is a macro that calls the
content of =n-times= in a let. So of course the contents of =n-times= wont have acess to the
parameters to =n-times=, which is bad.

So right now the only way I see to fix this is to make maco environments accessable again, but pay
attention on how to name macro parameters, to avoid collision, maybe a naming convention would help,
maybe prefix with =@=
*** Solutions:

First instinct to prevent that, is that if a parent environment is a function then just pass it and
go for their parent etc. Then we need =let= of a way to create environments that are neither macro-
nor funciton environmetns. They will be still different though.

*** Defining
In a macro environment define will still behave differently than in a function environment. If you
use =define= in a macro environment, it will actually be defined in the closest non-macro
environment. If you actually want to define something in a macro environment, then use
=macro-define=. However =define= will do the same if you are in a function or let environment.

*** Looking up
If the symbol is found on the active environment then use it. If not: Go up the environments untily
ou find a let-environment and recurse on that.
* Arguments

In Emacs lisp, keyword arguments must be passed in the same order as they were
defined in, so =((lambda (a &key b c) (+ a b c)) 1 3 :b 2)= will preduce an
error, because =b= was passed as last argument but was defined as second argument.
#+begin_src emacs-lisp
((lambda (a b) (+ a b)) 1 2) ;; 3
((lambda (a &key b) (+ a b)) 1 :b 2) ;; 3
((lambda (a &key b) (+ a b)) :b 2 1) ;; error
#+end_src


But if mulitiple keyword arguments are defined, their ordering does not matter.
#+begin_src emacs-lisp
((lambda (a &key b &key c &key d) (+ a b c d)) 1 :d 4 :c 3 :b 2) ;; 10
#+end_src

It is even possible to have a non keyword argument bewtween keyword arguments
and when calling, switch the order.
#+begin_src emacs-lisp
((lambda (a &key b c &key d) (+ a b c d)) 1 :d 4 3 :b 2) ;; 10
((lambda (a &key b c &key d) (+ a b c d)) 1 :d 4 :b 2 3) ;; error
#+end_src

However somehow it is not possible to flip the ordering at the first argument
#+begin_src emacs-lisp
((lambda (a &key b) (+ a b)) 2 :b 1) ;; 3
((lambda (a &key b) (+ a b)) :b 2 1) ;; error
((lambda (&key a b) (+ a b)) :a 2 1) ;; 3
((lambda (&key a b) (+ a b)) 1 :a 2) ;; error
#+end_src

So it seems, positional arguments have to be at the exact position they were
defined in, but keyword arguments can appear in any order, but at the places
where keyword arguments have been defined.

** Idea

Every argument can be set using keys, but keyword arguments always come strictly
after positional arguments

#+begin_src emacs-lisp
((lambda (a b c d)) 1 2 3 4) ;; ok
((lambda (a b c d)) 1 2 :c 2 :d 1) ;; ok
((lambda (a b c d)) 1 2 :d 1 :c 2) ;; ok
((lambda (a b c d)) :d 1 1 2 :c 2) ;; error, keyword arguments must come last
((lambda (a b c d)) 1 2 :c 2 :d 1 :a 2) ;; error, 'a' was passed two times

((lambda (a b c d)) 1 2 :d 1) ;; error, c was not passed, but does not have a default value
((lambda (a b c :default 10 d)) 1 2 :d 1) ;; okay again
#+end_src

The drawback then is that you can never pass a keyword as a positional argument,
because it will always try to assign the next argument to the variable defined
by the keyword. You could still pass it as a keyword argument though. This is
especially annoying because we want to use keywords as type identifiers.

#+begin_src emacs-lisp
(= (type "hello") :string)
#+end_src


#+begin_src emacs-lisp
((lambda (i-wanna-get-a-kw)) :hey) ;; error, unmatched value for keyword argument
((lambda (i-wanna-get-a-kw)) :i-wanna-get-a-kw :hey) ;; this would work again
#+end_src

Other Idea is to mark the place in the parameter list where keyword argumetns
start and arguments before that are positional and will not be stuffed into
key-value pairs and arguments after that will be keyword arguments

#+begin_src ebnf
<lambda list> -> <positional argument>*
[:keys ( <keyword arguments> [:defaults-to <value>])*]
[(:rest <rest argument>)|(:body <body argument>)]
#+end_src

#+begin_src emacs-lisp
(= (type "hello") :string) ;; this will work again because (=) does
;; not use keyword arguments
((lambda (i-wanna-get-a-kw)) :hey) ;; would work because of the same reason

(define fun
(lambda (:keys a b c d)
(+ a b c d)))

(fun 1 2 3 4) ;; okay
(fun 1 2 :d 3 :c 4) ;; okay
(fun 1 2 :d 3 :c 4 :a 2) ;; error, 'a' was passed two times
(fun :c 1 :b 2 :d 3 :a 4) ;; okay
(fun :c 1 :b 2 :d 3 4) ;; error, positional argument after keyword
;; and fun does not accept rest parameter

(define fun2
(lambda (:quoted op a b :keys c d :rest r)
(print r)
(op a b c d)))

>> (fun2 * 1 2 :c 3 :d 4 "this" "can" :be "whatever")
("this" "can" :be "whatever")
24


>> (define print-before-eval (lambda (:body expr)
(print expr)
(eval expr)))
>> (define r (print-before-eval (+ 1 2 3)))
(+ 1 2 3)
>> r
6

#+end_src

Wait this does not work either because you won't be able to pass keywords into
rest.

*Unrealated Idea: Distinguish between functions and macros*

The difference is really simple:
- Function :: like a lambda, but no argument is automatically quoted
- Macro :: like a lambda, but every argument is automatically quoted

This is important, because a macro should not introduce a new environment, but
use the one it lives in.

#+begin_src emacs-lisp

>> (define print-before-eval (macro (:rest expr)
(print expr)
(eval expr))

#+end_src

** the actual problem

We have some requirements to the arguments:
- positional arguments (always required, no default value)
- keyword arguments (always come after positionals), can be not passed if there
is a default value
- We want to be able to have a rest paramter, where everything is dumped in to
that exceeds the other parameters

*The problem is, we have no way of knowing if the current keyword we are
reading is still part of the keyword block or part of the rest paramter.*

Consider:

#+begin_src emacs-lisp
>> (define fun (lambda (a b :key c d :defaults-to 4 :rest) nil))
>> (fun 1 2 :c 3 :d 5)


(defun haha (par1 par2)
(+ 1 2))
#+end_src
What should this be evaluated to?

| | a | b | c | d | rest |
|----+---+---+---+---+--------|
| v1 | 1 | 2 | 3 | 5 | nil |
| v2 | 1 | 2 | 3 | 4 | (:d 5) |

It is ambiguous. It is however important to note that this can only happen when
there are optinal keyword arguments (keyword arguments with default values).
Otherwise we could always know which variables are set and wich have not been
set to see if we are in an errornious state.

** Solution
We can resolve that problem by always making the the decision of chosing =v1=
between =v1= and =v1=. This means, when we are expecting to read kwargs, and we
encounter an kwarg, try to apply it (this can fail, for two reasons:

1. The keyword has no following value
2. The keyword is not a keyword argument in the funciton

), if it fails treat it as part of the rest arguments, and read all the
following arguments into the rest arguments, or if it works, use it as the
keyword argument.

** Implementation

#+begin_src c
typedef struct {
char* docstring;
char** positional_arguments;
struct {
char* identifier;
Ast_node* default_value; // will be nullptr if no defalut value was declared
}* keyword_arguments;
char* rest_argument; // will be nullptr if no rest argument is declared
Ast_Node_array_list body;
} lambda;
#+end_src
* DONE use an enum for builtin identifiers
CLOSED: [2018-10-11 Do 17:15]

* DONE Print escaped chracters correctly
CLOSED: [2018-10-27 Sa 18:16]
* TODO [#A] =t= ast node type, universal source of truth
* TODO [#A] source code locations for errors
* TODO [#A] String error messages
* TODO [#A] Rename macro to =special= or something
* TODO [#B] =assert_equal_type= macro in testing
* TODO [#B] dont create new nils or builtins, but store one of each globally
* TODO [#B] make keywords unique (binary tree)
* TODO [#B] store all ast nodes in a huge arena
* TODO [#B] Auto doc generation
* TODO [#C] backquoting
* Build-in forms [29/30]
** TODO info

** DONE let
CLOSED: [2018-10-27 Sa 15:30]
** DONE +
CLOSED: [2018-09-18 Di 12:14]
** DONE -
CLOSED: [2018-09-18 Di 12:14]
** DONE *
CLOSED: [2018-09-18 Di 12:14]
** DONE /
CLOSED: [2018-09-18 Di 12:14]
** DONE >
CLOSED: [2018-10-26 Fr 23:30]
** DONE >=
CLOSED: [2018-10-26 Fr 23:30]
** DONE <
CLOSED: [2018-10-26 Fr 23:30]
** DONE >=
CLOSED: [2018-10-26 Fr 23:30]
** DONE =
CLOSED: [2018-10-21 So 00:25]
** DONE if
CLOSED: [2018-09-18 Di 12:14]
** DONE and (short circuiting)
CLOSED: [2018-10-05 Fr 22:21]
** DONE or
CLOSED: [2018-10-05 Fr 22:21]
** DONE not
CLOSED: [2018-10-05 Fr 22:21]
#+begin_src
(not 1) ;; == (not . (1 . nil))
(not (expression 1 3)) ;; == (not . ((expression . (1 . (3 . nil))) . nil) . nil)
(not) ;; == (not . nil)
(not 1 2) ;; == (not . (1 . (2 . nil)))
#+end_src

#+RESULTS:
: t

** DONE first (car)
CLOSED: [2018-10-08 Mo 20:28]
** DONE rest (cdr)
CLOSED: [2018-10-08 Mo 20:28]
** DONE pair (cons)
CLOSED: [2018-10-08 Mo 20:28]

** DONE load (import)
CLOSED: [2018-10-21 So 00:25]
** DONE define
CLOSED: [2018-10-08 Mo 20:28]
** DONE mutate
CLOSED: [2018-10-25 Do 19:40]
** DONE lambda
CLOSED: [2018-10-21 So 00:25]
** DONE macro
CLOSED: [2018-10-25 Do 19:40]
** DONE prog
CLOSED: [2018-10-21 So 00:25]
** DONE eval
CLOSED: [2018-10-08 Mo 20:28]

(setq condition (quote (= a 10)))
(setq a 10)
(eval condition)
(setq a 11)
(eval condition)

** DONE quote
CLOSED: [2018-10-08 Mo 20:28]

** DONE list
CLOSED: [2018-10-08 Mo 21:06]

#+begin_src
(quote (cons 2 (cons 3 (cons 4 ()))))
;; (cons 2 (cons 3 (cons 4 nil)))
(quote (2 . (3 . (4 . ()))))
;; (2 3 4)
#+end_src

#+begin_src
(list (cons 2 (cons 3 (cons 4 ()))))
;; ((2 3 4))
(list (quote(2 . (3 . (4 . ())))))
#+end_src

** DONE print
CLOSED: [2018-10-08 Mo 20:28]
** DONE read
CLOSED: [2018-10-08 Mo 20:28]
** DONE type
CLOSED: [2018-10-08 Mo 21:30]

Ładowanie…
Anuluj
Zapisz