Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
reader.h File Reference

A simple sexp reader to be used with textual IR. More...

#include <stdint.h>
#include "serene/rt/impl/array_list.h"
#include "serene/rt/source_manager.h"
#include "serene/rt/errors.h"
Include dependency graph for reader.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  srn_sexp_atom_t
struct  srn_sexp_str_t
struct  srn_sexp_num_t
 A number literal, kept as the raw text it was written with (e.g. More...
struct  srn_sexp_cons_t
struct  srn_sexp_list_t
struct  srn_sexp_node_t
struct  srn_sexp_parser_t
struct  srn_sexp_tree_t
struct  reader_fiber_arg_t

Typedefs

typedef struct srn_sexp_node_t srn_sexp_node_t
typedef struct srn_src_location_t srn_src_location_t
typedef struct srn_sexp_parser_t srn_sexp_parser_t
typedef struct array_list_t array_list_t
typedef enum srn_sexp_node_type_e srn_sexp_node_type_e
typedef struct srn_sexp_atom_t srn_sexp_atom_t
typedef struct srn_sexp_str_t srn_sexp_str_t
typedef struct srn_sexp_num_t srn_sexp_num_t
 A number literal, kept as the raw text it was written with (e.g.
typedef struct srn_sexp_cons_t srn_sexp_cons_t
typedef struct srn_sexp_list_t srn_sexp_list_t
typedef struct srn_sexp_tree_t srn_sexp_tree_t
typedef struct reader_fiber_arg_t reader_fiber_arg_t

Enumerations

enum  srn_sexp_node_type_e : uint8_t {
  SRN_SEXP_ATOM , SRN_SEXP_CONS , SRN_SEXP_LIST , SRN_SEXP_NUM ,
  SRN_SEXP_SEQ , SRN_SEXP_STR
}

Functions

srn_sexp_node_t * srn_sexp_make_atom (srn_context_t *ctx, const char *name)
srn_sexp_node_t * srn_sexp_make_str (srn_context_t *ctx, const char *data)
srn_sexp_node_t * srn_sexp_make_num (srn_context_t *ctx, const char *text)
srn_sexp_node_t * srn_sexp_make_cons (srn_context_t *ctx, srn_sexp_node_t *head, srn_sexp_node_t *tail)
srn_sexp_node_t * srn_sexp_make_list (srn_context_t *ctx)
srn_sexp_node_t * srn_sexp_make_node (srn_context_t *ctx, srn_sexp_node_type_e type)
srn_sexp_tree_t * srn_sexp_read_from_string (srn_context_t *ctx, void *reading_context, const char *buf)
 Read the symbolic expressions from a buffer.
srn_sexp_tree_t * srn_sexp_read_from_file (srn_context_t *ctx, void *reading_context, const char *path)
 Read the symbolic expressions from a file.
srn_sexp_node_t * read_expr (srn_sexp_parser_t *parser, srn_error_t **err)
srn_fiber_result_t read_from_buffer (srn_context_t *ctx, void *arg)
const char * srn_sexp_to_debug_string (srn_context_t *ctx, srn_sexp_tree_t *tree)
 Convert the given sexp to a string for debugging purposes.

Detailed Description

A simple sexp reader to be used with textual IR.

The IR types we use for the runtime have a lispy representation, and this reader will parse symbolic expressions in a basic form and different layers of IR can use this reader and transform the symbolic expressions to a format that they like.

I wrote this parser mostly to act as an inefficient way to parse different layers of IR without needing to have multiple parsers. Long in the future when we have everything in place, I should write efficient parsers for only the crucial layers of IR and avoid this generic one.

Definition in file reader.h.

Typedef Documentation

◆ array_list_t

typedef struct array_list_t array_list_t

Definition at line 49 of file reader.h.

◆ reader_fiber_arg_t

typedef struct reader_fiber_arg_t reader_fiber_arg_t

◆ srn_sexp_atom_t

typedef struct srn_sexp_atom_t srn_sexp_atom_t

◆ srn_sexp_cons_t

typedef struct srn_sexp_cons_t srn_sexp_cons_t

◆ srn_sexp_list_t

typedef struct srn_sexp_list_t srn_sexp_list_t

◆ srn_sexp_node_t

typedef struct srn_sexp_node_t srn_sexp_node_t

Definition at line 46 of file reader.h.

◆ srn_sexp_node_type_e

◆ srn_sexp_num_t

typedef struct srn_sexp_num_t srn_sexp_num_t

A number literal, kept as the raw text it was written with (e.g.

"42", "-3.14", "+1e10"). The reader only recognises the shape of a number, it does not parse it into an int/float value or fix its precision, that is a later phase's job.

◆ srn_sexp_parser_t

typedef struct srn_sexp_parser_t srn_sexp_parser_t

Definition at line 48 of file reader.h.

◆ srn_sexp_str_t

typedef struct srn_sexp_str_t srn_sexp_str_t

◆ srn_sexp_tree_t

typedef struct srn_sexp_tree_t srn_sexp_tree_t

◆ srn_src_location_t

typedef struct srn_src_location_t srn_src_location_t

Definition at line 47 of file reader.h.

Enumeration Type Documentation

◆ srn_sexp_node_type_e

enum srn_sexp_node_type_e : uint8_t
Enumerator
SRN_SEXP_ATOM 
SRN_SEXP_CONS 
SRN_SEXP_LIST 
SRN_SEXP_NUM 
SRN_SEXP_SEQ 
SRN_SEXP_STR 

Definition at line 51 of file reader.h.

51 : uint8_t {
56 SRN_SEXP_SEQ, // An array list of expressions
srn_sexp_node_type_e
Definition reader.h:51
@ SRN_SEXP_CONS
Definition reader.h:53
@ SRN_SEXP_ATOM
Definition reader.h:52
@ SRN_SEXP_NUM
Definition reader.h:55
@ SRN_SEXP_LIST
Definition reader.h:54
@ SRN_SEXP_STR
Definition reader.h:57
@ SRN_SEXP_SEQ
Definition reader.h:56

Function Documentation

◆ read_expr()

srn_sexp_node_t * read_expr ( srn_sexp_parser_t * parser,
srn_error_t ** err )

Definition at line 552 of file reader.c.

552 {
553 skip_whitespace(parser);
554
555 utf8_int32_t c = peek(parser);
556
557 if (c == '(') {
558 return read_list(parser, err);
559 }
560
561 // Checked before is_atom_start: a sign like '-' is itself a valid atom-start
562 // character (see is_atom_char), so "-5" would otherwise be read as the atom "-5"
563 // never reaching read_number at all.
564 if (is_number_start(c, peek_next(parser))) {
565 return read_number(parser, err);
566 }
567
568 if (is_atom_start(c)) {
569 return read_atom(parser, err);
570 }
571
572 if (c == '"') {
573 return read_string(parser, err);
574 }
575
576 if (c == '[') {
577 return read_seq(parser, err);
578 }
579
580 *err = parse_error(parser, c, nullptr);
581 return nullptr;
582}
static utf8_int32_t peek_next(srn_sexp_parser_t *p)
The codepoint one past the current one, without moving p.
Definition reader.c:65
static void skip_whitespace(srn_sexp_parser_t *p)
Definition reader.c:97
static srn_error_t * parse_error(srn_sexp_parser_t *parser, const utf8_int32_t c, const char *msg)
Definition reader.c:135
static srn_sexp_node_t * read_atom(srn_sexp_parser_t *parser, srn_error_t **err)
Definition reader.c:361
static srn_sexp_node_t * read_number(srn_sexp_parser_t *parser, srn_error_t **err)
A number literal: an optional leading sign, digits, an optional '.
Definition reader.c:399
static utf8_int32_t peek(srn_sexp_parser_t *p)
Definition reader.c:48
static srn_sexp_node_t * read_seq(srn_sexp_parser_t *parser, srn_error_t **err)
Definition reader.c:306
static bool is_atom_start(utf8_int32_t c)
Definition reader.c:109
static srn_sexp_node_t * read_list(srn_sexp_parser_t *parser, srn_error_t **err)
Definition reader.c:250
static bool is_number_start(utf8_int32_t c, utf8_int32_t next)
Definition reader.c:111
static srn_sexp_node_t * read_string(srn_sexp_parser_t *parser, srn_error_t **err)
Definition reader.c:466
Here is the call graph for this function:
Here is the caller graph for this function:

◆ read_from_buffer()

srn_fiber_result_t read_from_buffer ( srn_context_t * ctx,
void * arg )

Definition at line 584 of file reader.c.

584 {
585 UNUSED(ctx);
586 reader_fiber_arg_t *fiber_arg = arg;
587
588 srn_sexp_parser_t *parser = fiber_arg->parser;
589
590 auto sexps = array_list_empty(parser->ctx);
591 srn_error_t *err = nullptr;
592
593 // Every decode below trusts the lead byte of a sequence and reads the
594 // continuation bytes without looking for the terminator, so the whole buffer
595 // is checked once here. A sequence cut short by the end of the buffer, a
596 // continuation byte with no lead byte, and an overlong encoding are all
597 // rejected, which also guarantees that re-encoding a codepoint never needs
598 // more bytes than it was read from.
599 const utf8_int8_t *bad = utf8nvalid((const utf8_int8_t *)parser->buffer, parser->len);
600 if (bad != nullptr) {
601 parser->pos = (uint32_t)(bad - (const utf8_int8_t *)parser->buffer);
602 return parse_error(parser, '\0', "Malformed UTF-8 sequence");
603 }
604
605 // Whitespace and comments after the last expression are not an expression,
606 // so they are consumed here rather than handed to `read_expr`.
607 for (;;) {
608 skip_whitespace(parser);
609 if (is_at_end(parser)) {
610 break;
611 }
612
613 auto expr = read_expr(parser, &err);
614
615 if (err != nullptr) {
616 return err;
617 }
618
619 err = array_list_push(&sexps, expr);
620 if (err != nullptr) {
621 return err;
622 }
624 }
625
627 tree->maybe_error = nullptr;
628 tree->reading_context = parser->reading_context;
629 tree->exprs = sexps;
630 fiber_arg->tree = tree;
631
632 return nullptr;
633}
array_list_t array_list_empty(const srn_context_t *ctx)
Create an empty array list in the given context ctx.
Definition array_list.c:101
srn_error_t * array_list_push(array_list_t *al, array_list_elem_t x)
Push the given element x to the end of array_list al.
Definition array_list.c:114
#define ALLOC_OR_PANIC(ctx, T)
Definition context.h:98
srn_sexp_node_t * read_expr(srn_sexp_parser_t *parser, srn_error_t **err)
Definition reader.c:552
static bool is_at_end(srn_sexp_parser_t *p)
Definition reader.c:89
void srn_fiber_yield(void)
Yield cooperatively, re-enqueue the running fiber and run the next ready one.
Definition scheduler.c:1039
void * arg
srn_sexp_parser_t * parser
Definition reader.h:183
srn_sexp_tree_t * tree
Definition reader.h:184
A runtime error, a tag classifying the failure and a human-readable message.
Definition errors.h:173
const unsigned char * buffer
Definition reader.h:146
void * reading_context
We store whatever the caller passes as reading context to pass it back later on in the parsed tree.
Definition reader.h:143
uint32_t pos
Definition reader.h:150
srn_context_t * ctx
Definition reader.h:140
void * reading_context
Definition reader.h:158
array_list_t exprs
Definition reader.h:156
#define UNUSED(x)
Definition utils.h:45
Here is the call graph for this function:
Here is the caller graph for this function:

◆ srn_sexp_make_atom()

srn_sexp_node_t * srn_sexp_make_atom ( srn_context_t * ctx,
const char * name )

Definition at line 176 of file reader.c.

176 {
177 // NOTE: We assume name is allocated in an block, we just take it
178 PANIC_IF_NULL(name);
181
182 atom->name = (char *)name;
183 n->as.atom = atom;
184 return n;
185}
int n
Definition acutest.h:525
srn_sexp_node_t * srn_sexp_make_node(srn_context_t *ctx, srn_sexp_node_type_e type)
Definition reader.c:234
char * name
Definition reader.h:64
#define PANIC_IF_NULL(ptr)
Definition utils.h:66
Here is the call graph for this function:
Here is the caller graph for this function:

◆ srn_sexp_make_cons()

srn_sexp_node_t * srn_sexp_make_cons ( srn_context_t * ctx,
srn_sexp_node_t * head,
srn_sexp_node_t * tail )

Definition at line 211 of file reader.c.

211 {
212 PANIC_IF_NULL(head);
213
216
217 c->head = head;
218 c->tail = tail;
219 n->as.cons = c;
220
221 return n;
222}
srn_sexp_node_t * tail
Definition reader.h:98
srn_sexp_node_t * head
Definition reader.h:97
Here is the call graph for this function:
Here is the caller graph for this function:

◆ srn_sexp_make_list()

srn_sexp_node_t * srn_sexp_make_list ( srn_context_t * ctx)

Definition at line 224 of file reader.c.

224 {
227
228 l->head = nullptr;
229 l->len = 0;
230 n->as.list = l;
231
232 return n;
233}
srn_sexp_node_t * head
Definition reader.h:110
Here is the call graph for this function:
Here is the caller graph for this function:

◆ srn_sexp_make_node()

srn_sexp_node_t * srn_sexp_make_node ( srn_context_t * ctx,
srn_sexp_node_type_e type )

Definition at line 234 of file reader.c.

234 {
235 auto n = ALLOC_OR_PANIC(ctx, srn_sexp_node_t);
236 n->type = type;
237 n->metadata = nullptr;
238 return n;
239}
Here is the caller graph for this function:

◆ srn_sexp_make_num()

srn_sexp_node_t * srn_sexp_make_num ( srn_context_t * ctx,
const char * text )

Definition at line 198 of file reader.c.

198 {
199 // NOTE: We assume text is allocated in a block, we just take it
200 PANIC_IF_NULL(text);
203
204 num->text = (char *)text;
205 n->as.num = num;
206
207 return n;
208}
A number literal, kept as the raw text it was written with (e.g.
Definition reader.h:86
char * text
Definition reader.h:87
Here is the call graph for this function:
Here is the caller graph for this function:

◆ srn_sexp_make_str()

srn_sexp_node_t * srn_sexp_make_str ( srn_context_t * ctx,
const char * data )

Definition at line 187 of file reader.c.

187 {
188 // NOTE: We assume data is allocated in an block, we just take it
191
192 s->data = (char *)data;
193 n->as.string = s;
194
195 return n;
196}
char * data
Definition reader.h:74
Here is the call graph for this function:
Here is the caller graph for this function:

◆ srn_sexp_read_from_file()

srn_sexp_tree_t * srn_sexp_read_from_file ( srn_context_t * ctx,
void * reading_context,
const char * path )

Read the symbolic expressions from a file.

reading_context is a piece of data that the reader might provide as an identity or a piece of data that gives meaning to the result. For example a namespace key.

Definition at line 643 of file reader.c.

643 {
645
646 srn_sm_t *sm = ctx->engine->source_manager;
648
649 if (HAS_ERROR(maybe_id)) {
650 PUSH_AND_MOVE(sm->ctx, maybe_id, *result);
651 return result;
652 }
653
654 srn_sm_buffer_t *buf = srn_sm_get_buffer(sm, maybe_id.id);
655 PANIC_IF_NULL(buf);
656
657 if (buf->data == nullptr || buf->len == 0) {
658 result->maybe_error = nullptr;
659 result->exprs = array_list_empty(ctx);
660 result->reading_context = reading_context;
661 return result;
662 }
663
664 srn_sexp_parser_t parser = {
665 .ctx = ctx,
666 .reading_context = reading_context,
667 .buffer_id = maybe_id.id,
668 .buffer = srn_sm_buffer_data(buf),
669 .len = srn_sm_buffer_len(buf),
670 .pos = 0,
671 };
672
673 reader_fiber_arg_t fiber_arg = {
674 .parser = &parser,
675 // This will be the output
676 .tree = nullptr,
677 };
678
679 srn_fiber_t *fiber = srn_fiber_spawn(ctx, read_from_buffer, &fiber_arg);
680 srn_fiber_result_t fiber_result = srn_fiber_wait_for(fiber);
681
682 if (fiber_result != nullptr) {
683 result->maybe_error = (srn_error_t *)fiber_result;
684 PUSH_TRACE(sm->ctx, *result);
685 return result;
686 }
687
688 result = fiber_arg.tree;
689 return result;
690}
#define PUSH_AND_MOVE(ctx, from, to)
Definition errors.h:73
#define HAS_ERROR(x)
True when x – a value carrying an ERROR_HEADER – has an error attached.
Definition errors.h:70
#define PUSH_TRACE(ctx, x)
Definition errors.h:72
srn_fiber_t * srn_fiber_spawn(srn_context_t *ctx, srn_fiber_entry_t entry, void *arg)
Make and schedule a fiber with every default, the engine's scheduler, the configured stack size,...
Definition fiber.c:250
void * srn_fiber_result_t
What a fiber's entry produces, type-erased.
Definition fiber.h:171
srn_fiber_result_t read_from_buffer(srn_context_t *ctx, void *arg)
Definition reader.c:584
srn_fiber_result_t srn_fiber_wait_for(srn_fiber_t *target)
Block the calling fiber until target finishes, then return its result.
Definition scheduler.c:1130
srn_sm_buffer_t * srn_sm_get_buffer(srn_sm_t *sm, srn_sm_buffer_id_t id)
Return the buffer pointer of the given id, nullptr if the id does not exists.
srn_sm_maybe_id_t srn_sm_read_buffer_file(srn_sm_t *sm, const char *filepath, bool reread)
Read and buffer the given filepath into the source manager and return the buffer id.
static size_t srn_sm_buffer_len(srn_sm_buffer_t *buf)
static const unsigned char * srn_sm_buffer_data(srn_sm_buffer_t *buf)
srn_sm_t * sm
char path[PATH_MAX]
auto result
srn_engine_t * engine
Long term state of the compiler.
Definition context.h:49
unsigned char * data
nullptr when the source file was empty (no mapping exists)
srn_sm_buffer_id_t id
Here is the call graph for this function:

◆ srn_sexp_read_from_string()

srn_sexp_tree_t * srn_sexp_read_from_string ( srn_context_t * ctx,
void * reading_context,
const char * buf )

Read the symbolic expressions from a buffer.

reading_context is a piece of data that the reader might provide as an identity or a piece of data that gives meaning to the result. For example a namespace key.

Definition at line 636 of file reader.c.

636 {
637 // TODO(lxsameer): Extend the source manager to support sparse buffers and add the given
638 // buffer here as a sparse buffer for the given namespace i guess
639 return nullptr;
640}

◆ srn_sexp_to_debug_string()

const char * srn_sexp_to_debug_string ( srn_context_t * ctx,
srn_sexp_tree_t * tree )

Convert the given sexp to a string for debugging purposes.

The string will contain metadata info as well.

Definition at line 860 of file reader.c.

860 {
861 // Since this function is for debugging purposes we set a hard limit on the buffer
862 char *buf = srn_mm_malloc(ctx->engine->mm, sizeof(char) * DEBUG_BUF_MAX_SIZE);
863 PANIC_IF_NULL(buf);
864 buf[0] = '\0';
865
866 auto err = array_list_reduce(&tree->exprs, sexp_tree_reducer, buf);
867 PANIC_IF(err != nullptr, srn_error_to_string(ctx, err));
868
869 return buf;
870}
srn_error_t * array_list_reduce(array_list_t *al, array_list_reduce_f_t f, void *init)
Definition array_list.c:345
void * srn_mm_malloc(srn_mm_t *mm, size_t size)
Generic allocations that do not participate in the block based pools.
Definition default.c:155
char * srn_error_to_string(const srn_context_t *ctx, const srn_error_t *err)
Format err as a newly allocated string of the form [TAG]: msg, allocated in ctx.
Definition errors.c:133
static srn_error_t * sexp_tree_reducer(array_list_t *exprs_array, size_t n, void *expr, void *state)
Definition reader.c:853
#define DEBUG_BUF_MAX_SIZE
Definition reader.c:39
srn_mm_t * mm
Memory manager.
Definition engine.h:68
#define PANIC_IF(cond, msg)
Definition utils.h:59
Here is the call graph for this function:
Here is the caller graph for this function: