1 /* 2 * Copyright (c) 2022 Nik Silver 3 * 4 * This source code is released for free distribution under the terms of the 5 * GNU General Public License version 2 or (at your option) any later version. 6 * 7 * This module contains macros, data decls and prototypes to generate tags for Elm. 8 */ 9 10 /* 11 * INCLUDE FILES 12 */ 13 14 #include "kind.h" 15 #include "peg_common.h" 16 17 /* 18 * This allows us to save and restore the module scope. 19 * We want to do this because it's unhelpful to say that an imported item 20 * is the scope of the importing module. 21 */ 22 23 // Remember the scope of the module tag. But at first there is none (CORK_NIL). 24 static int elm_module_scope_index; 25 26 #define ELM_INIT_MODULE_SCOPE \ 27 elm_module_scope_index = CORK_NIL 28 #define ELM_SAVE_MODULE_SCOPE \ 29 if (elm_module_scope_index != CORK_NIL) { \ 30 POP_SCOPE (auxil); \ 31 } 32 #define ELM_RESTORE_MODULE_SCOPE \ 33 if (elm_module_scope_index != CORK_NIL) { \ 34 SET_SCOPE (auxil, elm_module_scope_index); \ 35 } else { \ 36 POP_SCOPE (auxil); \ 37 } 38 39 /* 40 * DATA DECLARATIONS 41 */ 42 typedef enum { 43 K_MODULE, 44 K_NAMESPACE, 45 K_TYPE, 46 K_CONSTRUCTOR, 47 K_ALIAS, 48 K_PORT, 49 K_FUNCTION, 50 COUNT_KINDS, 51 } ElmKind; 52 53 /* We only define roles which aren't def(ined) 54 */ 55 typedef enum { 56 ELM_MODULE_IMPORTED, 57 } elmModuleRoles; 58 59 static roleDefinition ElmModuleRoles [] = { 60 { true, "imported", "module imported" }, 61 }; 62 63 #define define_elm_role(NAME,Name) \ 64 typedef enum { \ 65 ELM_##NAME##_EXPOSED, \ 66 } elm##Name##Roleds; \ 67 static roleDefinition Elm##Name##Roles [] = { \ 68 { true, "exposed", "item exposed from a module" }, \ 69 } 70 define_elm_role(TYPE,Type); 71 define_elm_role(CONSTRUCTOR,Constructor); 72 define_elm_role(FUNCTION,Function); 73 74 typedef enum { 75 F_MODULENAME, 76 COUNT_FIELDS, 77 } ElmField; 78 79 static fieldDefinition ElmFields [COUNT_FIELDS] = { 80 { .name = "moduleName", 81 .description = "actual name of renamed module", 82 .enabled = true }, 83 }; 84 85 /* Use referenceOnly = true when a tag must always appear 86 * as role that's not def(ined). 87 */ 88 static kindDefinition ElmKinds [COUNT_KINDS] = { 89 { true, 'm', "module", "modules", 90 .referenceOnly = false, ATTACH_ROLES (ElmModuleRoles) }, 91 { true, 'n', "namespace", "modules renamed", }, 92 { true, 't', "type", "types", 93 .referenceOnly = false, ATTACH_ROLES (ElmTypeRoles) }, 94 { true, 'c', "constructor", "constructors", 95 .referenceOnly = false, ATTACH_ROLES (ElmConstructorRoles) }, 96 { true, 'a', "alias", "aliases", }, 97 { true, 'p', "port", "ports", }, 98 { true, 'f', "function", "functions", 99 .referenceOnly = false, ATTACH_ROLES (ElmFunctionRoles) }, 100 }; 101 102 struct parserCtx { 103 struct parserBaseCtx base; 104 vString *customType; 105 vString *consSubtype; 106 }; 107 108 /* 109 * FUNCTION PROTOTYPES 110 */ 111 #define USE_KIND_STACK KIND_GHOST_INDEX 112 static int makeElmTag (struct parserCtx *auxil, const char *name, long offset, int kind, int role); 113 static int makeElmTagSettingScope (struct parserCtx *auxil, const char *name, long offset, int kind, int role); 114 static void addElmSignature(int scope_index, const char *sig); 115 static void addElmTypeRef(int scope_index, const char *str); 116 static void initElmConstructorFields (struct parserCtx *auxil, const char *name); 117 static void initElmConstructorSubtypeFields (struct parserCtx *auxil); 118 static void addElmConstructorSubtype (struct parserCtx *auxil, const char *name); 119 static void addElmConstructorTypeRef (struct parserCtx *auxil, int tag_index); 120 static void tidyElmConstructorFields (struct parserCtx *auxil); 121 static vString *collapseWhitespace (const char *sig); 122