added some docs

This commit is contained in:
cozis
2021-11-05 17:01:34 +01:00
parent 795dfbcb54
commit fdc7e112c6
4 changed files with 151 additions and 20 deletions
+18 -9
View File
@@ -341,6 +341,13 @@ r = multiply(p, q);
print(p, ' * ', q, ' = ', r, '\n');
```
If the function doesn't return any values, then the `none` value is returned.
As an example, the `print` function always returns `none`
```py
print(print()); # none
```
Functions are always "pure", in the sense that the only values that the
function body can access are the ones provided as arguments. Usually in
other languages, functions can access the global scope and the parent
@@ -354,24 +361,26 @@ these variables but the effect only lasts for the lifetame of the
context local to the assignment.
```py
# Overwrite the print variable inside the global scope..
# Overwrite the print variable inside the global
# scope..
print = 5;
# The reference to the print function is lost
# withing this scope.
fun test()
{
# Now call print from inside the function.
# If the previous assignment were to overwrite the
# print function globally, the next statement would
# fail because the value 5 isn't a function. But
# it doesn't fail!
print('Not overwritten here!\n');
# If the previous assignment were to overwrite the print function
# globally, the previous statement would fail because the value 5
# isn't a function.
}
test();
# Now that i think about it, we lost the reference to the print function
# inside this scope. But we can take it back by returning it from a
# function!
# We can take the reference to the print function
# by taking it from a function!
fun get_print_back()
return print;
+15
View File
@@ -1,3 +1,18 @@
/* -- WHAT IS THIS FILE? --
*
* This file implements the routines that transform the AST
* into a list of bytecodes. The functionalities of this file
* are exposed through the `compile` function, that takes as
* input an `AST` and outputs an `Executable`.
* The function that does the heavy lifting is `emit_instr_for_node`
* which walks the tree and writes instructions to the `ExeBuilder`.
* Some semantic errors are catched at this phase, in which
* case, they are reported by filling out the `error` structure
* and aborting.
*
*/
#include <assert.h>
#include <setjmp.h>
#include <stdlib.h>
+101 -11
View File
@@ -1,3 +1,29 @@
/* -- WHAT IS THIS FILE? --
*
* This file implements the parser of the language, that transforms
* `Source` objects into `AST` objects. The functionalities of this
* file are exposed throigh the `parse` function.
*
* It's mainly composed by routines that can each parse specific
* parts of a noja source string. For example, `parse_expression`
* parses expressions and `parse_while_statement` parses while statements.
* These functions call each other recursively to parse the source
* and build the abstract syntax tree (AST) that can be then compiled
* into bytecode. If at any point the parsing fails because of an
* external or internal error, then the error is reported and the parsing
* is aborted.
* Since the nodes of the AST always have the same lifetime (they're
* allocated at the same time and die all together), the allocator
* scheme of choise is a bump-pointer allocator. This way each of the
* parsing routines can allocate memory if it need it but doesn't need
* to free it if an error occurres.
* The parsing routines don't operate directly on the source text, but
* on the tokenized version of it. Before parsing a linked list of
* tokens is produced through the `tokenize` function.
*
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@@ -81,21 +107,36 @@ static inline _Bool isoper(char c)
c == '=';
}
AST *parse(Source *src, BPAlloc *alloc, Error *error)
/* Symbol: tokenize
*
* Build a list of tokens that represents the
* provided source code.
*
*
* Arguments:
*
* src: The source code to be tokenized.
* alloc: The allocator that will contain all of the
* generated tokens.
* error: Error information structure that is filled out if
* an error occurres.
*
* None of the arguments are optional.
*
*
* Returns:
* A pointer to the first node of a linked list of tokens.
* If an error occurres, NULL is returned and the `error`
* structure is filled out.
*
*/
static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
{
assert(src != NULL);
assert(alloc != NULL);
const char *str = Source_GetBody(src);
int len = Source_GetSize(src);
assert(str != NULL);
assert(len >= 0);
AST *ast = BPAlloc_Malloc(alloc, sizeof(AST));
if(ast == NULL)
return NULL;
Token *head = NULL,
*tail = NULL;
int i = 0;
@@ -343,9 +384,58 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error)
tail = tok;
}
return head;
}
/* Symbol: parse
*
* Build an AST that represents the provided source code.
*
*
* Arguments:
*
* src: The source code to be parsed.
* alloc: The allocator that will contain all of the garbage
* the function needs and the final AST.
* error: Error information structure that is filled out if
* an error occurres.
*
* None of the arguments are optional.
*
*
* Returns:
*
* A pointer to the generated AST object. The AST object and
* all of the stuff that's referenced by it will be stored
* onto the provided allocator, therefore the AST will have
* the same lifetime of the allocator. If an error occurres,
* NULL is returned and the `error` structure is filled out.
*
* Notes:
* The AST structure holds a weak reference to the source
* object, therefore it will be invalidated if the source
* is freed before the AST.
*
*/
AST *parse(Source *src, BPAlloc *alloc, Error *error)
{
assert(src != NULL);
assert(alloc != NULL);
assert(error != NULL);
AST *ast = BPAlloc_Malloc(alloc, sizeof(AST));
if(ast == NULL)
return NULL;
Token *tokens = tokenize(src, alloc, error);
if(tokens == NULL)
return NULL;
Context ctx;
ctx.src = str;
ctx.token = head;
ctx.src = Source_GetBody(src);
ctx.token = tokens;
ctx.alloc = alloc;
ctx.error = error;
+17
View File
@@ -1,3 +1,20 @@
/* -- WHAT IS THIS FILE? --
*
* This file implements the routines that serialize the AST
* into JSON format. The JSON manipulation is handled by the
* third party library xJSON (written by me, still).
* The serialization functionality is exposed through the
* `serialize` function, that takes as an `AST` as argument
* and outputs a string of valid JSON. Therefore the xJSON
* dependency isn't exposed to the caller and can be regarded
* as an implementation detail.
* The way the serialization occurres is by converting the
* AST's representation native to the compiler to one native
* to xJSON, an then calling xj_encode on the converted AST.
*
*/
#include <assert.h>
#include <xjson.h>
#include "serialize.h"