aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/parsespec.c
blob: dfd3fe5a6a28b967ede0590cea6f9814b0b15757 (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
129
130
131
132
133
134
135

/*
 * Routines for parsing special module sections: giveme, svctype, usetype
 *
 * Copyright © 2025-2026 Samuel Lidén Borell <samuel@kodafritt.se>
 *
 * SPDX-License-Identifier: EUPL-1.2+ OR LGPL-2.1-or-later
 */
#include <assert.h>
#include "compiler.h"
#include "token.h"


void parse_svctype_spec(const char *classname, size_t cnlen)
{
    struct TreeNode *treenode;
    struct ServiceTypeSpec *svcspec;
    struct LexemeInfo li;
    enum Token t;

    assert(current_type != NULL);

    if (is_library) {
        error("The bootstrap compiler doesn't support service type "
              "specifications inside libraries.");
    }

    svcspec = malloc(sizeof(struct ServiceTypeSpec));
    NO_NULL(svcspec);
    svcspec->name = NULL;
    svcspec->namelen = 0;
    svcspec->next = current_type->svcspecs_list;
    current_type->svcspecs_list = svcspec;

    /* Detect duplicates */
    treenode = tree_insert_str(&current_type->svcspecs, classname, cnlen,
                               &svcspec->class_ident.node,
                               sizeof(struct ServiceTypeSpec));
    if (!treenode->is_new) {
        error_len("Duplicate service type specification", classname, cnlen);
    }

    /* Map class */
    svcspec->class_ = reference_type(classname, cnlen);
    if (svcspec->class_ != builtin_commandmain_class) {
        error_len("Service type specification must be `CommandMain` "
                  "in the bootstrap compiler. Was", classname, cnlen);
    }

    /* Parse name, if any */
    t = tokenize(&li);
    if (t == T_String) {
        svcspec->name = dupmemz(li.string, li.len);
        svcspec->namelen = li.len;
        t = tokenize(&li);
    }

    /* Parse parameters, if any */
    /* TODO */
    /*if (t == T_KW_with) {
        ...
    }*/

    if (t != T_EOL) {
        error("Expected end of line");
    }
}

static void parse_giveme_line(void)
{
    struct Var *var = parse_var(&current_type->vars, VAR_ALLOW_INITVAL);
    var->is_giveme = 1;
    toplevel_var_add(var);
}

void parse_giveme_section(void)
{
    for (;;) {
        struct LexemeInfo li;
        enum Token t = tokenize(&li);
        switch ((int)t) {
        case T_UpperIdent:
        case T_KW_bool:
        case T_KW_byte:
        case T_KW_int:
        case T_KW_long:
        TOKEN_CASES_QUALIFIERS
            unread_token();
            parse_giveme_line();
            expect_next_line();
            break;
        case T_KW_end:
            return;
        case T_EOL:
            tokenizer_next_line();
            break;
        default:
            error("Unexpected token at start of `giveme` line");
        }
    }
}

static void add_version(const char *s, size_t len)
{
    /* TODO */
    (void)s;
    (void)len;
    fprintf(stderr, "add version >%.*s<\n", (int)len, s);
}

void parse_versions_section(void)
{
    assert(!tokenize_numbers_as_versions);
    tokenize_numbers_as_versions = true;
    for (;;) {
        struct LexemeInfo li;
        enum Token t = tokenize(&li);
        if (t == T_EOL) {
            if (!tokenizer_next_line()) {
                break; /* EOF */
            }
            continue; /* Blank line */
        } else if (t != T_Version) {
            if (tokenizer_line_is_indented()) {
                error("Unexpected token in `versions` section "
                      "(or unexpected identation before symbol)");
            }
            unread_line(); /* End of version section */
            break;
        }

        add_version(li.string, li.len);
        expect_next_line_or_eof();
    }
    tokenize_numbers_as_versions = false;
}