Compare commits
	
		
			10 Commits
		
	
	
		
			61df0ac26e
			...
			b44de0a4c0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b44de0a4c0 | |||
| 28c8a8a401 | |||
| bc55abc8f4 | |||
| e15cb4e3aa | |||
| edbd51b450 | |||
| 44853b0e1d | |||
| 5a0bcbefc6 | |||
| b39fea3fa7 | |||
| 1739809380 | |||
| 9db9305c06 | 
							
								
								
									
										52
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								README.md
									
									
									
									
									
								
							| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## About
 | 
					## About
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This is a Lisp written in C. It follows the outline in this [Build Your Own Lisp](https://buildyourownlisp.com/chapter11_variables) book, though it then adds some small tweaks and improvements and quality of life improvements:
 | 
					This is a Lisp written in C. It follows the outline in this [Build Your Own Lisp](https://buildyourownlisp.com) book, though it then adds tweaks and quality of life improvements:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- A makefile
 | 
					- A makefile
 | 
				
			||||||
- Configurable verbosity levels
 | 
					- Configurable verbosity levels
 | 
				
			||||||
| 
						 | 
					@ -57,38 +57,54 @@ Simply call the `./mumble` binary:
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
mumble> (1 2 3)
 | 
					mumble> (1 2 3)
 | 
				
			||||||
mumble> { 1 2 3 }
 | 
					mumble> { 1 2 3 }
 | 
				
			||||||
mumble> head (1 2 3)
 | 
					mumble> head {1 2 3}
 | 
				
			||||||
mumble> { head (1 2 3) }
 | 
					mumble> { head {1 2 3) }
 | 
				
			||||||
mumble> tail { 1 2 3 }
 | 
					mumble> tail { 1 2 3 }
 | 
				
			||||||
mumble> list ( 1 2 3 )
 | 
					mumble> list ( 1 2 3 )
 | 
				
			||||||
mumble> eval { head {1 2 3} } 
 | 
					mumble> eval { head {1 2 3} } 
 | 
				
			||||||
mumble> (eval { head {+ tail head } } ) 1 2 3 
 | 
					mumble> (eval { head {+ tail head } } ) 1 2 3 
 | 
				
			||||||
mumble> len {1 2 3}
 | 
					mumble> len {1 2 3}
 | 
				
			||||||
mumble> join { {1 2} {3 4} }
 | 
					mumble> join { {1 2} {3 4} }
 | 
				
			||||||
mumble> def { {x} { 100 } }
 | 
					mumble> def {x} { 100 }
 | 
				
			||||||
mumble> x
 | 
					mumble> def {y} 100
 | 
				
			||||||
mumble> def { { a b c } { 1 2 3} }
 | 
					mumble> (x y)
 | 
				
			||||||
mumble> * a b c
 | 
					 | 
				
			||||||
mumble> - a b c
 | 
					 | 
				
			||||||
mumble> / a b c
 | 
					 | 
				
			||||||
mumble> VERBOSITY=0
 | 
					 | 
				
			||||||
mumble> VERBOSITY=1
 | 
					 | 
				
			||||||
mumble> VERBOSITY=2
 | 
					mumble> VERBOSITY=2
 | 
				
			||||||
mumble> def {sq} (@ {x} {* x x})
 | 
					mumble> def {sq} (@ {x} {* x x})
 | 
				
			||||||
mumble> sq 44
 | 
					mumble> sq 44
 | 
				
			||||||
 | 
					mumble> VERBOSITY=1
 | 
				
			||||||
mumble> def {sqsum} (@ {x y} {(+ (sq x) (sq y))})
 | 
					mumble> def {sqsum} (@ {x y} {(+ (sq x) (sq y))})
 | 
				
			||||||
mumble> sqsum 2 3
 | 
					mumble> sqsum 2 3
 | 
				
			||||||
 | 
					mumble> VERBOSITY=0
 | 
				
			||||||
mumble> def {init} (@ {xs} { list((head xs)) } )
 | 
					mumble> def {init} (@ {xs} { list((head xs)) } )
 | 
				
			||||||
 | 
					mumble> def {kopf} (@ {xx} { head (list xx) } )
 | 
				
			||||||
mumble> init {1 2}
 | 
					mumble> init {1 2}
 | 
				
			||||||
 | 
					mumble> kopf (1 2)
 | 
				
			||||||
 | 
					mumble> ifelse 1 2 3
 | 
				
			||||||
 | 
					mumble> if 1 2 3
 | 
				
			||||||
 | 
					mumble> ifelse 0 1 2 
 | 
				
			||||||
 | 
					mumble> if 0 1 2 
 | 
				
			||||||
 | 
					mumble> if {1 2 3} (1) (1)
 | 
				
			||||||
 | 
					mumble> def {positive} (@ {x} {> x 0})
 | 
				
			||||||
 | 
					mumble> def {fibtest} (@ {x} {if (> x 0) {+ x 1} 0 })
 | 
				
			||||||
 | 
					mumble> fibtest 2
 | 
				
			||||||
 | 
					mumble> def {fibonacci} (@ {x} {if (> x 1) { + (fibonacci (- x 2)) ( fibonacci ( - x 1 ) ) } 1} )
 | 
				
			||||||
 | 
					mumble> fibonacci 4
 | 
				
			||||||
 | 
					mumble> def {!} (@ {x} { if ( > 1 x) 1 { * x (! (- x 1)) } })
 | 
				
			||||||
 | 
					mumble> ! 100
 | 
				
			||||||
 | 
					mumble> def {++} (@ {x} { if ( > 1 x) 0 { + x (++ (- x 1)) } })
 | 
				
			||||||
 | 
					mumble> ++ 10
 | 
				
			||||||
 | 
					mumble>  def {++2} (@ {x} { / (* x (+ x 1)) 2 })
 | 
				
			||||||
 | 
					mumble> ++2 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## To do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [x] Define functions
 | 
				
			||||||
 | 
					- [x] Define if, = and >
 | 
				
			||||||
 | 
					- [x] Build fibonacci function
 | 
				
			||||||
 | 
					- [x] Build factorial function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Gotchas
 | 
					## Gotchas
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This doesn't currently run on Windows. But it easily could, with [preprocessor statements from the book].
 | 
					This doesn't currently run on Windows. But it easily could, with the preprocessor staments from parsing.c [here](https://buildyourownlisp.com/chapter6_parsing).
 | 
				
			||||||
 | 
					 | 
				
			||||||
## Usage and licensing
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
I don't expect this project to be such that people might want to use it. If you want a
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
But for the eventuality, this code is licensed under the MIT license; see the license.txt file.
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
https://buildyourownlisp.com/chapter7_evaluation#trees
 | 
					https://buildyourownlisp.com/chapter7_evaluation#trees
 | 
				
			||||||
https://buildyourownlisp.com/chapter9_s_expressions
 | 
					https://buildyourownlisp.com/chapter9_s_expressions
 | 
				
			||||||
https://buildyourownlisp.com/chapter12_functions
 | 
					https://buildyourownlisp.com/chapter12_functions
 | 
				
			||||||
 | 
					https://buildyourownlisp.com/chapter13_conditionals
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										77
									
								
								src/mumble.c
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								src/mumble.c
									
									
									
									
									
								
							| 
						 | 
					@ -782,7 +782,6 @@ lispval* builtin_join(lispval* l, lispenv* e)
 | 
				
			||||||
// Define a variable
 | 
					// Define a variable
 | 
				
			||||||
lispval* builtin_def(lispval* v, lispenv* env)
 | 
					lispval* builtin_def(lispval* v, lispenv* env)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Takes one argument: def { { a b } { 1 2 } }
 | 
					 | 
				
			||||||
    // Takes two arguments: argument: def {a} 1; def {init} (@ {x y} {x})
 | 
					    // Takes two arguments: argument: def {a} 1; def {init} (@ {x y} {x})
 | 
				
			||||||
    lispval* symbol_wrapper = v->cell[0];
 | 
					    lispval* symbol_wrapper = v->cell[0];
 | 
				
			||||||
    lispval* value = v->cell[1];
 | 
					    lispval* value = v->cell[1];
 | 
				
			||||||
| 
						 | 
					@ -834,6 +833,77 @@ lispval* builtin_define_lambda(lispval* v, lispenv* env)
 | 
				
			||||||
    lispval* lambda = lispval_lambda_func(variables, manipulation, new_env);
 | 
					    lispval* lambda = lispval_lambda_func(variables, manipulation, new_env);
 | 
				
			||||||
    return lambda;
 | 
					    return lambda;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Conditionals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lispval* builtin_ifelse(lispval* v, lispenv* e)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // ifelse 1 {a} b
 | 
				
			||||||
 | 
					    LISPVAL_ASSERT(v->count == 3, "Error: function ifelse passed too many arguments. Try ifelse choice result alternative, e.g., if (1 (a) {b})");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lispval* choice = v->cell[0];
 | 
				
			||||||
 | 
					    lispval* result = v->cell[1];
 | 
				
			||||||
 | 
					    lispval* alternative = v->cell[2];
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if( choice->type == LISPVAL_NUM && choice->num == 0){
 | 
				
			||||||
 | 
								lispval* answer = clone_lispval(alternative);
 | 
				
			||||||
 | 
								if(answer->type == LISPVAL_QEXPR){
 | 
				
			||||||
 | 
									answer->type = LISPVAL_SEXPR;
 | 
				
			||||||
 | 
									answer = evaluate_lispval(answer, e);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return answer;
 | 
				
			||||||
 | 
							}else {
 | 
				
			||||||
 | 
								lispval* answer = clone_lispval(result);
 | 
				
			||||||
 | 
								if(answer->type == LISPVAL_QEXPR){
 | 
				
			||||||
 | 
									// answer = builtin_eval(answer, e);
 | 
				
			||||||
 | 
									answer->type = LISPVAL_SEXPR;
 | 
				
			||||||
 | 
									answer = evaluate_lispval(answer, e);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return answer;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Comparators: =, > (also potentially <, >=, <=, <=)
 | 
				
			||||||
 | 
					// For numbers. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lispval* builtin_equal(lispval* v, lispenv* e)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // ifelse 1 {a} b
 | 
				
			||||||
 | 
					    LISPVAL_ASSERT(v->count == 2, "Error: function = takes two numeric arguments. Try (= 1 2)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lispval* a = v->cell[0];
 | 
				
			||||||
 | 
					    lispval* b = v->cell[1];
 | 
				
			||||||
 | 
						  
 | 
				
			||||||
 | 
							LISPVAL_ASSERT(a->type == LISPVAL_NUM, "Error: Functio = only takes numeric arguments.");
 | 
				
			||||||
 | 
							LISPVAL_ASSERT(b->type == LISPVAL_NUM, "Error: Functio = only takes numeric arguments.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(a->num == b->num){
 | 
				
			||||||
 | 
								return lispval_num(1);
 | 
				
			||||||
 | 
							}else {
 | 
				
			||||||
 | 
								return lispval_num(0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lispval* builtin_greater_than(lispval* v, lispenv* e)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // ifelse 1 {a} b
 | 
				
			||||||
 | 
					    LISPVAL_ASSERT(v->count == 2, "Error: function = takes two numeric arguments. Try (= 1 2)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lispval* a = v->cell[0];
 | 
				
			||||||
 | 
					    lispval* b = v->cell[1];
 | 
				
			||||||
 | 
						  
 | 
				
			||||||
 | 
							LISPVAL_ASSERT(a->type == LISPVAL_NUM, "Error: Functio = only takes numeric arguments.");
 | 
				
			||||||
 | 
							LISPVAL_ASSERT(b->type == LISPVAL_NUM, "Error: Functio = only takes numeric arguments.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(a->num > b->num){
 | 
				
			||||||
 | 
								return lispval_num(1);
 | 
				
			||||||
 | 
							}else {
 | 
				
			||||||
 | 
								return lispval_num(0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Simple math ops
 | 
					// Simple math ops
 | 
				
			||||||
lispval* builtin_math_ops(char* op, lispval* v, lispenv* e)
 | 
					lispval* builtin_math_ops(char* op, lispval* v, lispenv* e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -931,8 +1001,13 @@ void lispenv_add_builtins(lispenv* env)
 | 
				
			||||||
    lispenv_add_builtin("tail", builtin_tail, env);
 | 
					    lispenv_add_builtin("tail", builtin_tail, env);
 | 
				
			||||||
    lispenv_add_builtin("eval", builtin_eval, env);
 | 
					    lispenv_add_builtin("eval", builtin_eval, env);
 | 
				
			||||||
    lispenv_add_builtin("join", builtin_join, env);
 | 
					    lispenv_add_builtin("join", builtin_join, env);
 | 
				
			||||||
 | 
					    lispenv_add_builtin("len", builtin_len, env);
 | 
				
			||||||
    lispenv_add_builtin("def", builtin_def, env);
 | 
					    lispenv_add_builtin("def", builtin_def, env);
 | 
				
			||||||
    lispenv_add_builtin("@", builtin_define_lambda, env);
 | 
					    lispenv_add_builtin("@", builtin_define_lambda, env);
 | 
				
			||||||
 | 
					    lispenv_add_builtin("ifelse", builtin_ifelse, env);
 | 
				
			||||||
 | 
					    lispenv_add_builtin("if", builtin_ifelse, env);
 | 
				
			||||||
 | 
					    lispenv_add_builtin("=", builtin_equal, env);
 | 
				
			||||||
 | 
					    lispenv_add_builtin(">", builtin_greater_than, env);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Evaluate the lispval
 | 
					// Evaluate the lispval
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user