diff --git a/doc/runtime.md b/doc/runtime.md new file mode 100644 index 0000000..f920a5e --- /dev/null +++ b/doc/runtime.md @@ -0,0 +1,111 @@ +# Runtime + +Any ginger data-structure can be put into a ginger file. The data itself has no executional meaning on its own, but if +the data is properly formed it can be parsed by the ginger interpreter and a thread of execution can be started. For +example, if I put the following in a file called `test.gng`: +``` +(1 2 3) +``` + +It doesn't have any meaning, it's just a list. However, if you put the following: +``` +(add 1 2 3) +``` + +and run `ginger test.gng` then a program can be interpreted from the given data. This file describes how given data can +be formed into a valid program. + +## Eval + +Ginger evaluation is done the same was as other lisp languages: the first item in a list is the function name, the rest +of the items in the list are arguments to the function. In the example above, `add` is the function name, and `1`, `2`, +and `3` are arguments to the function. + +Arguments to a function can be functions to be eval'd themselves. An equivalent to the example above would have been: +``` +(add 1 2 (add 1 2)) +``` + +## Doing multiple things + +It's not very useful to only be able to do one thing. A vector of lists is interpreted into sequentially eval'ing each +item in the vector. For (a trivial) example: +``` +[ (add 1 2) + (sub 4 (add 1 2)) + (mul 8 0) ] +``` + +## Variables/Scope + +The above example does a few things, but it repeats itself in the second part (with the `sub`). If we could save the +result of the addition to a variable that would be awesomesauce. The `=` function does this! It makes it so that the +first argument is equivalent to the evaluation of the second argument. Variables' first letters must be upper-case, this +is how they're differentiated from raw string literals. The above could be re-written as: +``` +[ (= AdditionResult (add 1 2)) + (sub 4 AdditionResult) + (mul 8 0) ] +``` + +In the above example `AdditionResult` is a valid variable inside of the vector that contains its declaration, and any +vectors contained within that vector. For example: +``` +[ (= AdditionResult (add 1 2)) + [ (sub 4 AdditionResult) ;This works + (mul 8 0) ] ] + +[ (add 4 AdditionResult) ] ;This does not work! +``` + +## Literals + +We've determined that a list is interpreted as a function/arguments set, and an upper-case string is interpreted as a +variable name which will be de-referenced. What if we want to actually use these structures without eval'ing them? For +these cases we have the literal function `l`: +``` +[ (concat (l (1 2 3)) (l (4 5 6))) ; => (1 2 3 4 5 6) + (println (l "I start with a capital letter and I DONT CARE!!!")) ] +``` + +## Functions + +### Anonymous + +Anonymous functions are declared using the `fn` function. The first argument is a vector of argument names (remember, +all upper-case!) and the second is a list/vector to be eval'd. Examples: +``` +[ (= Add3 (fn [Num] (add Num 3))) + (Add3 4) ; => 7 + + (= Add3Sub1 + (fn [Num] [ + (= Added (add Num 3)) + (sub Added 1) + ])) + (Add3Sub1 4) ] ; => 6 +``` + +`fn` returns a function, which can be passed around and assigned like any other value. In the above examples the +functions are assigned to the `Add3` and `Add3Sub1` variables. Functions can also be passed into other functions as +arguments: +``` +;DoTwice takes a function Fun and a number Num. it will call Fun twice on Num and return the result. +[ (= DoTwice + (fn [Fun Num] + (Fun (Fun Num)))) + + (DoTwice (fn [Num] (add Num 1)) 3) ] ; => 5 +``` + +### Defined + +Defined functions attach the function definition to a string literal (lower-case) in the current scope. They are useful +as they support more features then an anonymous function, such as inline documentation. These extra features will be +documented elsewhere. To create a defined function use the `dfn` function: +``` +[ (dfn add-four-sub-three [Num] [ + (= A (add Num 4)) + (sub A 3) ]) + (add-four-sub-three 4) ] ; => 5 +```