1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2021 Tobias Kortkamp <tobik@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 #pragma once 29 30 enum ASTType { 31 AST_ROOT, 32 AST_DELETED, 33 AST_COMMENT, 34 AST_EXPR, 35 AST_IF, 36 AST_FOR, 37 AST_INCLUDE, 38 AST_TARGET, 39 AST_TARGET_COMMAND, 40 AST_VARIABLE, 41 }; 42 43 const char *ASTType_tostring(enum ASTType); 44 45 enum ASTCommentType { 46 AST_COMMENT_LINE, 47 }; 48 49 const char *ASTCommentType_tostring(enum ASTCommentType); 50 51 enum ASTExprType { 52 AST_EXPR_ERROR, // identifier:".error" 53 AST_EXPR_EXPORT_ENV, // identifier:".export-env" 54 AST_EXPR_EXPORT_LITERAL, // identifier:".export-literal" 55 AST_EXPR_EXPORT, // identifier:".export" 56 AST_EXPR_INFO, // identifier:".info" 57 AST_EXPR_UNDEF, // identifier:".undef" 58 AST_EXPR_UNEXPORT_ENV, // identifier:".unexport-env" 59 AST_EXPR_UNEXPORT, // identifier:".unexport" 60 AST_EXPR_WARNING, // identifier:".warning" 61 }; 62 63 const char *ASTExprType_identifier(enum ASTExprType); 64 const char *ASTExprType_tostring(enum ASTExprType); 65 66 enum ASTIfType { 67 AST_IF_IF, // human:"if" 68 AST_IF_DEF, // human:"ifdef" 69 AST_IF_ELSE, // human:"else" 70 AST_IF_MAKE, // human:"ifmake" 71 AST_IF_NDEF, // human:"ifndef" 72 AST_IF_NMAKE, // human:"ifnmake" 73 }; 74 75 const char *ASTIfType_human(enum ASTIfType); 76 const char *ASTIfType_tostring(enum ASTIfType); 77 78 enum ASTIncludeType { 79 AST_INCLUDE_BMAKE, // identifier:".include" 80 AST_INCLUDE_POSIX, // identifier:"include" 81 AST_INCLUDE_POSIX_OPTIONAL, // identifier:"-include" 82 AST_INCLUDE_POSIX_OPTIONAL_S, // identifier:"sinclude" 83 AST_INCLUDE_OPTIONAL, // identifier:".-include" 84 AST_INCLUDE_OPTIONAL_D, // identifier:".dinclude" 85 AST_INCLUDE_OPTIONAL_S, // identifier:".sinclude" 86 }; 87 88 const char *ASTIncludeType_identifier(enum ASTIncludeType); 89 const char *ASTIncludeType_tostring(enum ASTIncludeType); 90 91 enum ASTTargetType { 92 AST_TARGET_NAMED, 93 AST_TARGET_UNASSOCIATED, 94 }; 95 96 const char *ASTTargetType_tostring(enum ASTTargetType); 97 98 enum ASTTargetCommandFlag { 99 AST_TARGET_COMMAND_FLAG_NONE = 0, // human:"<none>" 100 AST_TARGET_COMMAND_FLAG_ALWAYS_EXECUTE = 1 << 0, // human:"+" 101 AST_TARGET_COMMAND_FLAG_IGNORE_ERROR = 1 << 1, // human:"-" 102 AST_TARGET_COMMAND_FLAG_SILENT = 1 << 2, // human:"@" 103 }; 104 105 const char *ASTTargetCommandFlag_human(enum ASTTargetCommandFlag); 106 const char *ASTTargetCommandFlag_tostring(enum ASTTargetCommandFlag); 107 108 enum ASTVariableModifier { 109 AST_VARIABLE_MODIFIER_APPEND, // human:"+=" 110 AST_VARIABLE_MODIFIER_ASSIGN, // human:"=" 111 AST_VARIABLE_MODIFIER_EXPAND, // human:":=" 112 AST_VARIABLE_MODIFIER_OPTIONAL, // human:"?=" 113 AST_VARIABLE_MODIFIER_SHELL, // human:"!=" 114 }; 115 116 const char *ASTVariableModifier_human(enum ASTVariableModifier); 117 const char *ASTVariableModifier_tostring(enum ASTVariableModifier); 118 119 enum ASTWalkState { 120 AST_WALK_CONTINUE, 121 AST_WALK_STOP, 122 }; 123 124 const char *ASTWalkState_tostring(enum ASTWalkState); 125 126 struct ASTComment { 127 enum ASTCommentType type; 128 struct Array *lines; 129 }; 130 131 struct ASTFor { 132 // .for $bindings in $words 133 // $body 134 // .endfor 135 struct Array *bindings; 136 struct Array *words; 137 struct Array *body; 138 const char *comment; 139 const char *end_comment; 140 size_t indent; 141 }; 142 143 struct ASTIf { 144 // .if $test 145 // $body 146 // .else 147 // $orelse 148 // .endif 149 // 150 // Elif: 151 // 152 // .if $test1 153 // $body1 154 // .elif $test2 155 // $body2 156 // .else 157 // $orelse 158 // .endif 159 // 160 // => 161 // 162 // .if $test1 163 // $body1 164 // .else 165 // .if $test2 166 // $body2 167 // .else 168 // $orelse 169 // .endif 170 // .endif 171 enum ASTIfType type; 172 struct Array *test; 173 struct Array *body; 174 struct Array *orelse; 175 const char *comment; 176 const char *end_comment; 177 size_t indent; 178 struct AST *ifparent; 179 }; 180 181 struct ASTExpr { 182 enum ASTExprType type; 183 struct Array *words; 184 const char *comment; 185 size_t indent; 186 }; 187 188 struct ASTInclude { 189 enum ASTIncludeType type; 190 struct Array *body; 191 const char *comment; 192 size_t indent; 193 const char *path; 194 bool sys; 195 bool loaded; 196 }; 197 198 struct ASTTarget { 199 enum ASTTargetType type; 200 struct Array *sources; 201 struct Array *dependencies; 202 struct Array *body; 203 const char *comment; 204 }; 205 206 struct ASTTargetCommand { 207 struct ASTTarget *target; 208 struct Array *words; 209 const char *comment; 210 enum ASTTargetCommandFlag flags; 211 }; 212 213 struct ASTVariable { 214 const char *name; 215 enum ASTVariableModifier modifier; 216 struct Array *words; 217 const char *comment; 218 }; 219 220 struct ASTRoot { 221 struct Array *body; 222 }; 223 224 struct ASTLineRange { // [a,b) 225 size_t a; 226 size_t b; 227 }; 228 229 struct AST { 230 enum ASTType type; 231 struct AST *parent; 232 struct Mempool *pool; 233 struct ASTLineRange line_start; 234 struct ASTLineRange line_end; 235 bool edited; 236 struct { 237 size_t goalcol; 238 } meta; 239 union { 240 struct ASTRoot root; 241 struct ASTComment comment; 242 struct ASTExpr expr; 243 struct ASTIf ifexpr; 244 struct ASTInclude include; 245 struct ASTFor forexpr; 246 struct ASTTarget target; 247 struct ASTTargetCommand targetcommand; 248 struct ASTVariable variable; 249 }; 250 }; 251 252 void ast_free(struct AST *); 253 struct AST *ast_new(struct Mempool *, enum ASTType, struct ASTLineRange *, void *); 254 struct AST *ast_clone(struct Mempool *, struct AST *); 255 struct Array *ast_siblings(struct Mempool *, struct AST *); 256 void ast_parent_append_sibling(struct AST *, struct AST *, bool); 257 void ast_parent_insert_before_sibling(struct AST *, struct AST *); 258 void ast_print(struct AST *, FILE *); 259 void ast_balance(struct AST *); 260 261 char *ast_line_range_tostring(struct ASTLineRange *, bool, struct Mempool *); 262 263 #define AST_WALK_RECUR(x) \ 264 if ((x) == AST_WALK_STOP) { \ 265 return AST_WALK_STOP; \ 266 } 267 268 #define AST_WALK_DEFAULT(f, node, ...) \ 269 switch (node->type) { \ 270 case AST_ROOT: \ 271 ARRAY_FOREACH(node->root.body, struct AST *, child) { \ 272 AST_WALK_RECUR(f(child, ##__VA_ARGS__)); \ 273 } \ 274 break; \ 275 case AST_FOR: \ 276 ARRAY_FOREACH(node->forexpr.body, struct AST *, child) { \ 277 AST_WALK_RECUR(f(child, ##__VA_ARGS__)); \ 278 } \ 279 break; \ 280 case AST_IF: \ 281 ARRAY_FOREACH(node->ifexpr.body, struct AST *, child) { \ 282 AST_WALK_RECUR(f(child, ##__VA_ARGS__)); \ 283 } \ 284 ARRAY_FOREACH(node->ifexpr.orelse, struct AST *, child) { \ 285 AST_WALK_RECUR(f(child, ##__VA_ARGS__)); \ 286 } \ 287 break; \ 288 case AST_INCLUDE: \ 289 ARRAY_FOREACH(node->include.body, struct AST *, child) { \ 290 AST_WALK_RECUR(f(child, ##__VA_ARGS__)); \ 291 } \ 292 break; \ 293 case AST_TARGET: \ 294 ARRAY_FOREACH(node->target.body, struct AST *, child) { \ 295 AST_WALK_RECUR(f(child, ##__VA_ARGS__)); \ 296 } \ 297 break; \ 298 case AST_DELETED: \ 299 case AST_COMMENT: \ 300 case AST_EXPR: \ 301 case AST_TARGET_COMMAND: \ 302 case AST_VARIABLE: \ 303 break; \ 304 } 305