aboutsummaryrefslogtreecommitdiff
path: root/src/ls.h
blob: 38a2b38b39e4cada157b1b79a0c5ccc3d9ce2dfe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// This software disclaims copyright. Do what you want with it. Be gay, do
// crime. Originally written by Alexis Lockwood in 2021. Ⓐ

#ifndef LS_H
#define LS_H

// --- DEPENDENCIES ------------------------------------------------------------

// Supporting modules
#include "ls_types.h"

// Standard headers
#include <stdbool.h>
#include <stddef.h>
#include <inttypes.h>
#include <setjmp.h>
#include <stdio.h>

// --- PUBLIC MACROS -----------------------------------------------------------

// TODO make user definable
#define LS_LABEL_CACHE_SIZE 4

// --- PRIVATE DATATYPES -------------------------------------------------------
// --- PUBLIC DATATYPES --------------------------------------------------------

/// Fetcher. This function accepts a void* argument and a byte address, and
/// returns the byte at that location.
///
/// Fetchers not reading out of fast memory (for example, ones reading from a
/// stream) are advised to perform caching.
///
/// If an error occurs when trying to fetch data, return a negated error code
/// from ls_error_t. If no more characters are present, return
/// -LS_NO_MORE_PROGRAM, but do not perform cleanup operations --- the parser
/// must be allowed to read off the end.
typedef int (*ls_fetcher_t)(void * arg, uint16_t loc);

// fw decl
struct ls_s;

/// Main LS execution struct.
typedef struct ls_s {
	// --------- begin user-controlled fields ---------

	/// Fetcher to retrieve data. See ls_run(). User-controlled.
	ls_fetcher_t fetcher;

	/// Argument for fetcher. User-controlled.
	void * fetcher_arg;

	/// Line trace hook. If not null, this will be called for each line.
	/// User-controlled.
	void (*line_trace_hook)(struct ls_s * ctx);

	/// Set true to stop execution on the next line. The interpreter will
	/// exit with error LS_STOPPED. Note that LS_STOPPED is also given if
	/// the interpreter encounters the END statement. User-controlled.
	bool stop;

	// --------- end user-controlled fields ---------

	/// Execution stack.
	ls_value_t * callstack;

	/// User functions defined by DEF FN.
	ls_value_t * funcs;

	/// Named labels
	ls_value_t * labels;

	/// Data pool. All runtime values are allocated from here.
	ls_value_t * pool;

	/// Program counter
	ls_addr_t pc;

	/// Top error-handling jmpbuf. When the interpreter encounters an error,
	/// it should store the error code in .error and jump here.
	jmp_buf error_jmp_buf;

	ls_error_t error;

	/// Label cache
	ls_label_cache_t label_cache[LS_LABEL_CACHE_SIZE];

	/// Next label cache entry. This rotates so that the oldest entry is
	/// always overwritten.
	uint8_t label_cache_i;
} ls_t;

// --- PUBLIC CONSTANTS --------------------------------------------------------
// --- PUBLIC VARIABLES --------------------------------------------------------
// --- PUBLIC FUNCTIONS --------------------------------------------------------

/// Execute a script, returning any unhandled errors. The user-controlled
/// fields in the ls_t should be initialized first (these are between
/// begin/end "user-controlled fields", and documented as such in their
/// doc comments).
///
/// @param self
/// @param pool - an array of ls_value_t to use as the allocation pool
/// @param szpool - number of elements in @a pool
ls_error_t ls_run(ls_t * self, ls_value_t * pool, size_t szpool);

/// Convert a program counter value to a line and column number. This is
/// expensive and should only be called in rare cases (for example, printing
/// out a line number in an error message).
///
/// @param self
/// @param pc - program counter to look up
/// @param[out] line - 1-based line number
/// @param[out] col - 1-based column number
/// @retval true - success
/// @retval false - the PC doesn't exist
///
/// If the PC doesn't exist, @a line and @a col are unchanged.
bool ls_translate_pc(ls_t * self, ls_addr_t pc, uint16_t * line,
	uint16_t * col);

/// Print out a ls_value_t. For diagnostics.
///
/// @param stream - stream to print it into
/// @param value - value to print
/// @param first - first value in the pool, for computing pool offsets
void ls_print_value(FILE * stream, ls_value_t * value, ls_value_t * first);

#endif // !defined(LS_H)