More doc comments

This commit is contained in:
K. Lange 2021-02-18 21:00:27 +09:00
parent 076b702afa
commit c567204f65
5 changed files with 183 additions and 9 deletions

View File

@ -4,11 +4,21 @@
#include "value.h"
/**
* Opcodes
* @brief Instruction opcode values
*
* These are pretty much entirely based on the clox opcodes from the book.
* There's not really much else to add here, since the VM is sufficient for
* our needs. Most of the interesting changes happen in the compiler.
* The instruction opcode table is divided in four parts. The high two bits of each
* opcode encodes the number of operands to pull from the codeobject and thus the
* size (generally) of the instruction (note that OP_CLOSURE(_LONG) has additional
* arguments depending on the function it points to).
*
* 0-operand opcodes are "simple" instructions that generally only deal with stack
* values and require no additional arguments.
*
* 1- and 3- operand opcodes are paired as 'short' and 'long'. While the VM does not
* currently depend on these instructions having the same values in the lower 6 bits,
* it is recommended that this property remain true.
*
* 2-operand opcodes are generally jump instructions.
*/
typedef enum {
OP_ADD = 1,
@ -111,13 +121,32 @@ typedef enum {
OP_UNPACK_LONG,
} KrkOpCode;
/**
* @brief Map entry of instruction offsets to line numbers.
*
* Each code object contains an array of line mappings, indicating
* the start offset of each line. Since a line typically maps to
* multiple opcodes, and spans of many lines may map to no opcodes
* in the case of blank lines or docstrings, this array is stored
* as a sequence of <starOffset, line> pairs rather than a simple
* array of one or the other.
*/
typedef struct {
size_t startOffset;
size_t line;
} KrkLineMap;
/**
* Bytecode chunks
* @brief Opcode chunk of a code object.
*
* Opcode chunks are internal to code objects and I'm not really
* sure why we're still separating them from the KrkFunction objects.
*
* Stores four flexible arrays using three different formats:
* - Code, representing opcodes and operands.
* - Lines, representing offset-to-line mappings.
* - Filename, the string name of the source file.
* - Constants, an array of values referenced by the code object.
*/
typedef struct {
size_t count;
@ -132,9 +161,32 @@ typedef struct {
KrkValueArray constants;
} KrkChunk;
/**
* @brief Initialize an opcode chunk.
*/
extern void krk_initChunk(KrkChunk * chunk);
/**
* @brief Append a byte to an opcode chunk.
*/
extern void krk_writeChunk(KrkChunk * chunk, uint8_t byte, size_t line);
/**
* @brief Release the resources allocated to an opcode chunk.
*/
extern void krk_freeChunk(KrkChunk * chunk);
/**
* @brief Add a new constant value to an opcode chunk.
*/
extern size_t krk_addConstant(KrkChunk * chunk, KrkValue value);
/**
* @brief Write an OP_CONSTANT(_LONG) instruction.
*/
extern void krk_emitConstant(KrkChunk * chunk, size_t ind, size_t line);
/**
* @brief Add a new constant and write an instruction for it.
*/
extern size_t krk_writeConstant(KrkChunk * chunk, KrkValue value, size_t line);

View File

@ -2,5 +2,19 @@
#include "object.h"
/**
* @brief Compile a string to a code object.
*
* Compiles the source string 'src' into a code object.
*
* @param src Source code string to compile.
* @param newScope Whether the compiler should treat the source as a new module.
* @param fileName Path name of the source file or a representative string like "<stdin>"
* @return The code object resulting from the compilation, or NULL if compilation failed.
*/
extern KrkFunction * krk_compile(const char * src, int newScope, char * fileName);
/**
* @brief Mark objects owned by the compiler as in use.
*/
extern void krk_markCompilerRoots(void);

View File

@ -239,7 +239,7 @@ void krk_markTable(KrkTable * table) {
}
}
void krk_tableRemoveWhite(KrkTable * table) {
static void tableRemoveWhite(KrkTable * table) {
for (size_t i = 0; i < table->capacity; ++i) {
KrkTableEntry * entry = &table->entries[i];
if (IS_OBJECT(entry->key) && !(AS_OBJECT(entry->key))->isMarked) {
@ -287,7 +287,7 @@ static void markRoots() {
size_t krk_collectGarbage(void) {
markRoots();
traceReferences();
krk_tableRemoveWhite(&vm.strings);
tableRemoveWhite(&vm.strings);
size_t out = sweep();
vm.nextGC = vm.bytesAllocated * 2;
return out;

View File

@ -12,10 +12,66 @@
#define ALLOCATE(type, count) (type*)krk_reallocate(NULL,0,sizeof(type)*(count))
extern void * krk_reallocate(void *, size_t, size_t);
/**
* @brief Resize an allocated heap object.
*
* Allocates or reallocates the heap object 'ptr', tracking changes
* in sizes from 'old' to 'new'. If 'ptr' is NULL, 'old' should be 0,
* and a new pointer will be allocated of size 'new'.
*
* @param ptr Heap object to resize.
* @param old Current size of the object.
* @param new New size of the object.
* @return New pointer for heap object.
*/
extern void * krk_reallocate(void * ptr, size_t old, size_t new);
/**
* @brief Release all objects.
*
* Generally called automatically by krk_freeVM(); releases all of
* the GC-tracked heap objects.
*/
extern void krk_freeObjects(void);
/**
* @brief Run a cycle of the garbage collector.
*
* Runs one scan-sweep cycle of the garbage collector, potentially
* freeing unused resources and advancing potentially-unused
* resources to the next stage of removal.
*
* @return The number of bytes released by this collection cycle.
*/
extern size_t krk_collectGarbage(void);
/**
* @brief During a GC scan cycle, mark a value as used.
*
* When defining a new type in a C extension, this function should
* be used by the type's _ongcscan callback to mark any values not
* already tracked by the garbage collector.
*
* @param value The value to mark.
*/
extern void krk_markValue(KrkValue value);
/**
* @brief During a GC scan cycle, mark an object as used.
*
* Equivalent to krk_markValue but operates directly on an object.
*
* @param object The object to mark.
*/
extern void krk_markObject(KrkObj * object);
/**
* @brief During a GC scan cycle, mark the contents of a table as used.
*
* Marks all keys and values in a table as used. Generally applied
* to the internal storage of mapping types.
*
* @param table The table to mark.
*/
extern void krk_markTable(KrkTable * table);
extern void krk_tableRemoveWhite(KrkTable * table);

View File

@ -99,6 +99,12 @@ typedef enum {
TOKEN_EOF,
} KrkTokenType;
/**
* @brief A token from the scanner.
*
* Represents a single scanned item from the scanner, such as a keyword,
* string literal, numeric literal, identifier, etc.
*/
typedef struct {
KrkTokenType type;
const char * start;
@ -109,6 +115,12 @@ typedef struct {
size_t literalWidth;
} KrkToken;
/**
* @brief Token scanner state.
*
* Stores the state of the compiler's scanner, reading from a source
* character string and tracking the current line.
*/
typedef struct {
const char * start;
const char * cur;
@ -119,8 +131,48 @@ typedef struct {
KrkToken unget;
} KrkScanner;
/**
* @brief Initialize the compiler to scan tokens from 'src'.
*
* FIXME: There is currently only a single static scanner state;
* along with making the compiler re-entrant, the scanner
* needs to also be re-entrant; there's really no reason
* these can't all just take a KrkScanner* argument.
*/
extern void krk_initScanner(const char * src);
/**
* @brief Read the next token from the scanner.
*
* FIXME: Or, maybe the scanner shouldn't even be available outside
* of the compiler, that would make some sense as well, as it's
* a low-level detail, but we use it for tab completion in the
* main repl, so I'm not sure that's feasible right now.
*/
extern KrkToken krk_scanToken(void);
/**
* @brief Push a token back to the scanner to be reprocessed.
*
* Pushes a previously-scanned token back to the scanner.
* Used to implement small backtracking operations at the
* end of block constructs like 'if' and 'try'.
*/
extern void krk_ungetToken(KrkToken token);
/**
* @brief Rewind the scanner to a previous state.
*
* Resets the current scanner to the state in 'to'. Used by
* the compiler to implement comprehensions, which would otherwise
* not be possible in a single-pass compiler.
*/
extern void krk_rewindScanner(KrkScanner to);
/**
* @brief Retreive a copy of the current scanner state.
*
* Used with krk_rewindScanner() to implement rescanning
* for comprehensions.
*/
extern KrkScanner krk_tellScanner(void);