aboutsummaryrefslogtreecommitdiff
path: root/src/formatter/utils.c
blob: 472829d9e555668b153edc76d472e7773c061eac (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
// This file defines utility functions for autoformatting code

#include <stdbool.h>
#include <stdint.h>

#include "../ast.h"
#include "../parse/context.h"
#include "../stdlib/datatypes.h"
#include "../stdlib/optionals.h"
#include "../stdlib/tables.h"
#include "../stdlib/text.h"

const Text_t single_indent = Text("    ");

void add_line(Text_t *code, Text_t line, Text_t indent) {
    if (code->length == 0) {
        *code = line;
    } else {
        if (line.length > 0) *code = Texts(*code, "\n", indent, line);
        else *code = Texts(*code, "\n");
    }
}

OptionalText_t next_comment(Table_t comments, const char **pos, const char *end) {
    for (const char *p = *pos; p < end; p++) {
        const char **comment_end = Table$get(comments, &p, parse_comments_info);
        if (comment_end) {
            *pos = *comment_end;
            return Text$from_strn(p, (int64_t)(*comment_end - p));
        }
    }
    return NONE_TEXT;
}

bool range_has_comment(const char *start, const char *end, Table_t comments) {
    OptionalText_t comment = next_comment(comments, &start, end);
    return (comment.length >= 0);
}

CONSTFUNC bool should_have_blank_line(ast_t *ast) {
    switch (ast->tag) {
    case If:
    case When:
    case Repeat:
    case While:
    case For:
    case Block:
    case FunctionDef:
    case StructDef:
    case EnumDef:
    case LangDef:
    case ConvertDef:
    case Extend: return true;
    default: return false;
    }
}

Text_t indent_code(Text_t code) {
    if (code.length <= 0) return code;
    return Texts(single_indent, Text$replace(code, Text("\n"), Texts("\n", single_indent)));
}

Text_t parenthesize(Text_t code, Text_t indent) {
    if (Text$has(code, Text("\n"))) return Texts("(\n", indent, indent_code(code), "\n", indent, ")");
    else return Texts("(", code, ")");
}

CONSTFUNC ast_t *unwrap_block(ast_t *ast) {
    if (ast == NULL) return NULL;
    while (ast->tag == Block && Match(ast, Block)->statements && Match(ast, Block)->statements->next == NULL) {
        ast = Match(ast, Block)->statements->ast;
    }
    return ast;
}

CONSTFUNC const char *binop_tomo_operator(ast_e tag) {
    switch (tag) {
    case Power: return "^";
    case PowerUpdate: return "^=";
    case Concat: return "++";
    case ConcatUpdate: return "++=";
    case Multiply: return "*";
    case MultiplyUpdate: return "*=";
    case Divide: return "/";
    case DivideUpdate: return "/=";
    case Mod: return "mod";
    case ModUpdate: return "mod=";
    case Mod1: return "mod1";
    case Mod1Update: return "mod1=";
    case Plus: return "+";
    case PlusUpdate: return "+=";
    case Minus: return "-";
    case MinusUpdate: return "-=";
    case LeftShift: return "<<";
    case LeftShiftUpdate: return "<<=";
    case RightShift: return ">>";
    case RightShiftUpdate: return ">>=";
    case And: return "and";
    case AndUpdate: return "and=";
    case Or: return "or";
    case OrUpdate: return "or=";
    case Xor: return "xor";
    case XorUpdate: return "xor=";
    case Equals: return "==";
    case NotEquals: return "!=";
    case LessThan: return "<";
    case LessThanOrEquals: return "<=";
    case GreaterThan: return ">";
    case GreaterThanOrEquals: return ">=";
    default: return NULL;
    }
}