code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(152 lines)
1 // This file defines utility functions for autoformatting code
3 #include <stdbool.h>
4 #include <stdint.h>
6 #include "../ast.h"
7 #include "../parse/context.h"
8 #include "../stdlib/datatypes.h"
9 #include "../stdlib/optionals.h"
10 #include "../stdlib/tables.h"
11 #include "../stdlib/text.h"
12 #include "formatter.h"
14 const Text_t single_indent = Text(" ");
16 void add_line(Text_t *code, Text_t line, Text_t indent) {
17 if (code->length == 0) {
18 *code = line;
19 } else {
20 if (line.length > 0) *code = Texts(*code, "\n", indent, line);
21 else *code = Texts(*code, "\n");
25 OptionalText_t next_comment(Table_t comments, const char **pos, const char *end) {
26 for (const char *p = *pos; p < end; p++) {
27 const char **comment_end = Table$get(comments, &p, parse_comments_info);
28 if (comment_end) {
29 *pos = *comment_end;
30 return Text$from_strn(p, (size_t)(*comment_end - p));
33 return NONE_TEXT;
36 bool range_has_comment(const char *start, const char *end, Table_t comments) {
37 OptionalText_t comment = next_comment(comments, &start, end);
38 return (comment.tag != TEXT_NONE);
41 CONSTFUNC int suggested_blank_lines(ast_t *first, ast_t *second) {
42 if (second == NULL) return 0;
44 for (;;) {
45 if (first->tag == Declare && Match(first, Declare)->value) {
46 first = Match(first, Declare)->value;
47 } else if (first->tag == DebugLog) {
48 return 1;
49 } else break;
52 for (;;) {
53 if (second->tag == Declare && Match(second, Declare)->value) {
54 second = Match(second, Declare)->value;
55 } else if (second->tag == DebugLog) {
56 return 1;
57 } else break;
60 switch (first->tag) {
61 case If:
62 case When:
63 case Repeat:
64 case While:
65 case For:
66 case Block:
67 case Defer:
68 case ConvertDef:
69 case FunctionDef:
70 case Lambda:
71 case StructDef:
72 case EnumDef:
73 case LangDef: return 1;
74 case Use: {
75 if (second->tag != Use) return 1;
76 break;
78 case Declare: {
79 DeclareMatch(decl, first, Declare);
80 if (decl->value) return suggested_blank_lines(decl->value, second);
81 break;
83 case Assign: {
84 DeclareMatch(assign, first, Assign);
85 for (ast_list_t *val = assign->values; val; val = val->next) {
86 if (suggested_blank_lines(val->ast, second) > 0) return 1;
88 break;
90 default: break;
93 switch (second->tag) {
94 case If:
95 case When:
96 case Repeat:
97 case While:
98 case For:
99 case Block:
100 case Defer:
101 case ConvertDef:
102 case FunctionDef:
103 case Lambda:
104 case StructDef:
105 case EnumDef:
106 case LangDef: return 1;
107 default: break;
109 return 0;
112 Text_t indent_code(Text_t code) {
113 if (code.length <= 0) return code;
114 return Texts(single_indent, Text$replace(code, Text("\n"), Texts("\n", single_indent)));
117 Text_t parenthesize(Text_t code, Text_t indent) {
118 if (Text$has(code, Text("\n"))) return Texts("(\n", indent, indent_code(code), "\n", indent, ")");
119 else return Texts("(", code, ")");
122 CONSTFUNC ast_t *unwrap_block(ast_t *ast) {
123 if (ast == NULL) return NULL;
124 while (ast->tag == Block && Match(ast, Block)->statements && Match(ast, Block)->statements->next == NULL) {
125 ast = Match(ast, Block)->statements->ast;
127 if (ast->tag == Block && Match(ast, Block)->statements == NULL) return NULL;
128 return ast;
131 OptionalText_t termify_inline(ast_t *ast, Table_t comments) {
132 if (range_has_comment(ast->start, ast->end, comments)) return NONE_TEXT;
133 switch (ast->tag) {
134 case BINOP_CASES:
135 case Not:
136 case Negative:
137 case HeapAllocate:
138 case StackReference: return parenthesize(format_inline_code(ast, comments), EMPTY_TEXT);
139 default: return format_inline_code(ast, comments);
143 Text_t termify(ast_t *ast, Table_t comments, Text_t indent) {
144 switch (ast->tag) {
145 case BINOP_CASES:
146 case Not:
147 case Negative:
148 case HeapAllocate:
149 case StackReference: return parenthesize(format_code(ast, comments, indent), indent);
150 default: return format_inline_code(ast, comments);