even cuter comments

This commit is contained in:
cozis
2022-03-13 16:28:41 +01:00
parent 4f8aaa7eca
commit 3a49b82135
4 changed files with 105 additions and 141 deletions
+15 -17
View File
@@ -26,23 +26,21 @@
** | You should have received a copy of the GNU General Public License along |
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
** +--------------------------------------------------------------------------+
*/
/* 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. It's also possible that the compilation fails
** bacause of internal errors (which usually means "out of memory").
**
** | 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. It's also |
** | possible that the compilation fails bacause of internal errors (which |
** | usually means "out of memory"). |
** +--------------------------------------------------------------------------+
*/
#include <assert.h>
+24 -27
View File
@@ -26,33 +26,30 @@
** | You should have received a copy of the GNU General Public License along |
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
** +--------------------------------------------------------------------------+
*/
/* 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.
**
** | 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>
+47 -68
View File
@@ -26,74 +26,53 @@
** | You should have received a copy of the GNU General Public License along |
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
** +--------------------------------------------------------------------------+
*/
/* WHAT IS THIS FILE?
** This is the implementation of the "Heap", an
** object that provides the rest of the program
** with memory and manages it by claiming it back
** implicitly when it's not in use anymore. To
** determine which memory is used or not, the
** heap system must be aware of the object graph.
** This is the reason why the Heap is tightly
** coupled to the object model.
**
** HOW DOES IT WORK?
** The collection algorithm is move-and-compact.
** The allocator is a bump-pointer allocator.
** When the base pool of memory is filled up,
** further allocations are forwarded to the
** stdlib's malloc, but are kept track of by
** putting them in a linked list. When the parent
** system decides to free up some memory, a new
** heap is allocated and the live objects are
** moved to it, then the old heap is freed. The
** references between live objects are updated
** when moving them.
** Some objects implement destructors that must
** be called when a new heap is allocated and
** they're not moved to it. An auxiliary list
** of allocated objects with destructors is stored
** alongside the heap. When the live objects
** are moved and the ones to be destroyed are
** left in the old one, the list of objects with
** destructors is iterated over and the objects
** in it that weren't moved are destroied and
** removed from the list. This approach becomes
** linearly slower with the number of allocated
** objects with destructors, but it's assumed
** that not many of them implement them.
**
** HOW ARE POINTERS UPDATED?
** Basically, when an object is moved from the
** old to the new heap, the location of the object
** in the old heap is overwritten with a placeholder
** object that holds the new location. Then all
** of it's references are iterated over and if
** they refer to placeholders they're updated
** with the new location of the object. If the
** references don't refer to placeholder objects,
** then the referred objects are moved too. This
** is a recursive process that, when applied to
** the root object of the program, moves all reachable
** objects to the new heap and updates the pointers.
** The complexity of this algorithm is proportional
** to the number of live objects.
**
** WHAT IS A BUMP-POINTER ALLOCATOR?
** A bump-pointer allocator is a minimal memory
** management system. A contiguous pool of memory
** is allocated. On a higher level, allocations
** are stacked one after another until the pool is
** all used up. This is done by having a pointer
** that points to the first free buffer of the pool.
** Initially, it points to the first byte of the pool.
** When N bytes are requested, the value of the
** pointer is given to the caller and then it's
** incremented by the allocated amount. When the
** pool has less free memory than what is requested,
** the allocation fails.
**
** | |
** | WHAT IS THIS FILE? |
** | This is the implementation of the "Heap", an object that provides the |
** | rest of the program with memory and manages it by claiming it back |
** | implicitly when it's not in use anymore. To determine which memory is |
** | used or not, the heap system must be aware of the object graph. This is |
** | the reason why the Heap is tightly coupled to the object model. |
** | |
** | HOW DOES IT WORK? |
** | The collection algorithm is move-and-compact. The allocator is a |
** | bump-pointer allocator. When the base pool of memory is filled up, |
** | further allocations are forwarded to the stdlib's malloc, but are kept |
** | track of by putting them in a linked list. When the parent system decides|
** | to free up some memory, a new heap is allocated and the live objects are |
** | moved to it, then the old heap is freed. The references between live |
** | objects are updated when moving them.Some objects implement destructors |
** | that must be called when a new heap is allocated and they're not moved |
** | to it. An auxiliary list of allocated objects with destructors is stored |
** | alongside the heap. When the live objects are moved and the ones to be |
** | destroyed are left in the old one, the list of objects with destructors |
** | is iterated over and the objects in it that weren't moved are destroied |
** | and removed from the list. This approach becomes linearly slower with |
** | the number of allocated objects with destructors, but it's assumed that |
** | not many of them implement them. |
** | |
** | HOW ARE POINTERS UPDATED? |
** | Basically, when an object is moved from the old to the new heap, the |
** | location of the object in the old heap is overwritten with a placeholder |
** | object that holds the new location. Then all of it's references are |
** | iterated over and if they refer to placeholders they're updated with the |
** | new location of the object. If the references don't refer to placeholder |
** | objects, then the referred objects are moved too. This is a recursive |
** | process that, when applied to the root object of the program, moves all |
** | reachable objects to the new heap and updates the pointers. The |
** | complexity of this algorithm is proportional to the number of live |
** | objects. |
** | |
** | WHAT IS A BUMP-POINTER ALLOCATOR? |
** | A bump-pointer allocator is a minimal memory management system. A |
** | contiguous pool of memory is allocated. On a higher level, allocations |
** | are stacked one after another until the pool is all used up. This is done|
** | by having a pointer that points to the first free buffer of the pool. |
** | Initially, it points to the first byte of the pool. When N bytes are |
** | requested, the value of the pointer is given to the caller and then it's |
** | incremented by the allocated amount. When the pool has less free memory |
** | than what is requested, the allocation fails. |
** +--------------------------------------------------------------------------+
*/
#include <stdint.h>
#include <assert.h>
+18 -28
View File
@@ -26,35 +26,25 @@
** | You should have received a copy of the GNU General Public License along |
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
** +--------------------------------------------------------------------------+
** | WHAT IS THIS FILE? |
** | This file implements the "static map" object. The static map object |
** | behaves like a read-only "map". (Note that "implementing an object" means|
** | a very specific thing in this interpreter. If you didn't know, check the |
** | src/objects folder.) |
** | |
** | THE STATIC MAP OBJECT |
** | The statis map is a read-only collection of objects. You can see it as |
** | an interface for static arrays. You can define an array of |
** | `StaticMapSlot`s and then wrap it in this object. When the map is |
** | accessed, a lookup is performed into the array. Something to note is that|
** | the array is converted to noja objects lazily when they are accessed, |
** | which makes the start-up times lower than a general purpose map. |
** +--------------------------------------------------------------------------+
** | NOTES: |
** | - Only strings can be keys. There is no intrinsic reason why |
** | it should be like that, it's just simpler. |
** +--------------------------------------------------------------------------+
*/
/*
*
* -- WHAT IS THIS FILE? --------------------------------------------
* This file implements the "static map" object. The static map
* object behaves like a read-only "map". (Note that "implementing
* an object" means a very specific thing in this interpreter. If
* you didn't know, check the src/objects folder.)
* ------------------------------------------------------------------
*
* -- THE STATIC MAP OBJECT -----------------------------------------
* The statis map is a read-only collection of objects. You can see
* it as an interface for static arrays. You can define an array of
* `StaticMapSlot`s and then wrap it in this object. When the map is
* accessed, a lookup is performed into the array. Something to note
* is that the array is converted to noja objects lazily when they
* are accessed, which makes the start-up times lower than a general
* purpose map.
* ------------------------------------------------------------------
*
* NOTES:
* - This object, unlike the others implemented in src/objects,
* depends on the Runtime objects. This is because it needs
* to be able to create `NativeFuncObject`s.
*
* - Only strings can be keys. There is no intrinsic reason why
* it should be like that, it's just simpler.
*/
#include <string.h>
#include <assert.h>
#include "../runtime/runtime.h"