YakshaLisp and macros in Yaksha
Bhathiya Perera
YakshaLisp is the builtin macro processing system in the Yaksha language. In this tutorial we will go through YakshaLisp basics, some builtin functions and how you can use those.
What makes YakshaLisp different from Yaksha
From the point of view of Yaksha language. YakshaLisp exist only during the compilation phase. Most of the programming languages consist of a DSL that acts as the meta programming layer. Think YakshaLisp as such DSL that exist to generate code.
YakshaLisp basics
Before we take a look at how to write macros, we need to understand how YakshaLisp works.
You can execute YakshaLisp REPL by running yaksha lisp command. (This is a very simple REPL)
Defining and setting a value
(def a 1) # <--- a is initialized to 1
(setq a 2) # <--- a value is changed to 2
# a is now set to 2
Shortcut.
(= a 1) # <--- def or setq
S-expressions
(def a 1) # <--- this is an S-expression
Q-expressions
(def a (quote 1 2 3))
(def b {1 2 3})
(== a b) # <---- truthy
Q-expressions are inspired by the make your own lisp. (However, we also do have special forms).
Difference between list, quote and Q-Expressions
(def a (list 1 2 3)) # <--- a is created with `list`
(def b {1 2 3}) # <--- b created with `{}`
(def c (quote 1 2 3))# <--- c is created with `quote`
(== a b) # <--- ==/!= type mismatch
(== b c) # <--- truthy
(== (map eval b) a) # <--- truthy
Individual elements in Q-expressions are not evaluated. However, if you want to evaluate them, you can use eval function with map function.
(quote ...) is same as {...}. However, quote is a function with a special form.
(map eval {(+ 0 1) (+ 1 1) (+ 1 2)}) # <---- {1 2 3}
Builtin values
nil- falsey value, it is same as{}true- truthy value, it is same as1false- falsey value, it is same as0newline- newline character, either"\r\n"or"\n"
Simple builtins
(def a (+ 1 2)) # <----- a is 3
(def b (- 2 1)) # <----- b is 1
(def c (* 2 3)) # <----- c is 6
(def d (/ 6 2)) # <----- d is 3
Comparison builtins
(def a (== 1 1)) # <----- a is true
(def b (!= 1 1)) # <----- b is false
(def c (< 1 2)) # <----- c is true
(def d (> 1 2)) # <----- d is false
(def e (<= 1 2)) # <----- e is true
(def f (>= 1 2)) # <----- f is false
Logical builtins
(def a (and true true)) # <----- a is true
(def b (and true false)) # <----- b is false
(def c (or true false)) # <----- c is true
(def d (or false false)) # <----- d is false
(def e (not true)) # <----- e is false
(def f (not false)) # <----- f is true
If builtin
(def a (if true 1 2)) # <----- a is 1
(def b (if false 1 2))# <----- b is 2
(def c (if true 1)) # <----- c is 1
(def d (if false 1)) # <----- d is nil (same as {})
DSL macros
Currently YakshaLisp can be used to write DSL macros. In this tutorial we will go through how to write a simple DSL macro.
macros! {
# Get an integer_decimal token 7
(defun ymacro_get () (list (ykt_integer_decimal 7)))
# create a DSL macro named get! that executes above (defun ymacro_get...) function
(yk_register {dsl get ymacro_get})
}
def main() -> int:
e1 = array("int", 4, 5, 6, get!{})
for i: int in e1:
println(i)
del e1
return 0
This should print 4, 5, 6, 7 in individual lines. yk_register is a builtin function that registers a DSL macro. dsl is the type of the macro. get is the name of the macro. ymacro_get is the YakshaLisp function that executes when the macro is called.