aboutsummaryrefslogtreecommitdiff
path: root/src/parse.c
blob: 84cfcfd68d60e2451916d219c2455ee0f2e7e990 (plain) (blame)
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
// Copyright (c) 2024, Marvin Borner <dev@marvinborner.de>
// SPDX-License-Identifier: MIT

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <term.h>
#include <spec.h>
#include <parse.h>
#include <log.h>

#define BIT_AT(i) ((term[(i) / 8] & (1 << (7 - ((i) % 8)))) >> (7 - ((i) % 8)))

// parses bloc's bit-encoded blc
// 010M -> abstraction of M
// 00MN -> application of M and N
// 1X0 -> bruijn index, amount of 1s in X
// 011I -> 2B index to entry
static struct term *parse_bloc_bblc(const char *term, size_t *bit)
{
	struct term *res = 0;
	if (!BIT_AT(*bit) && BIT_AT(*bit + 1) && !BIT_AT(*bit + 2)) {
		(*bit) += 3;
		res = new_term(ABS);
		res->u.abs.term = parse_bloc_bblc(term, bit);
	} else if (!BIT_AT(*bit) && !BIT_AT(*bit + 1)) {
		(*bit) += 2;
		res = new_term(APP);
		res->u.app.lhs = parse_bloc_bblc(term, bit);
		res->u.app.rhs = parse_bloc_bblc(term, bit);
	} else if (BIT_AT(*bit)) {
		const size_t cur = *bit;
		while (BIT_AT(*bit))
			(*bit)++;
		res = new_term(VAR);
		res->u.var.index = *bit - cur - 1;
		(*bit)++;
	} else if (!BIT_AT(*bit) && BIT_AT(*bit + 1) && BIT_AT(*bit + 2)) {
		(*bit) += 3;

		// selected bit pattern, see readme
		int sel = (2 << (BIT_AT(*bit) * 2 + BIT_AT(*bit + 1) + 2));
		(*bit) += 2;

		res = new_term(REF);
		size_t index = 0;
		for (int i = 0; i < sel; i++) {
			index |= BIT_AT(*bit) << i;
			(*bit) += 1;
		}
		res->u.ref.index = index;
	} else {
		(*bit)++;
		res = parse_bloc_bblc(term, bit);
	}
	return res;
}

struct bloc_parsed *parse_bloc(const void *bloc)
{
	const struct bloc_header *header = bloc;
	if (memcmp(header->identifier, BLOC_IDENTIFIER,
		   (size_t)BLOC_IDENTIFIER_LENGTH)) {
		fatal("invalid BLoC identifier!\n");
		return 0;
	}

	struct bloc_parsed *parsed = malloc(sizeof(*parsed));
	parsed->length = header->length;
	parsed->entries = malloc(header->length * sizeof(struct term *));

	const struct bloc_entry *current = (const void *)&header->entries;
	for (size_t i = 0; i < parsed->length; i++) {
		size_t len = 0;
		parsed->entries[i] =
			parse_bloc_bblc((const char *)current, &len);
		current =
			(const struct bloc_entry *)(((const char *)current) +
						    (len / 8) + (len % 8 != 0));
	}

	return parsed;
}

void free_bloc(struct bloc_parsed *bloc)
{
	for (size_t i = 0; i < bloc->length; i++) {
		free_term(bloc->entries[i]);
	}

	free(bloc->entries);
	free(bloc);
}