schema.c (2961B)
1 #include <assert.h> 2 #include <stdio.h> 3 4 #include "schema.h" 5 6 #include "assoc.h" 7 8 struct schema { 9 assoc *constructors; 10 bool (*checker)(tree*); 11 symbol name; 12 }; 13 14 struct schema _LEAF = { NULL }; 15 struct schema *LEAF = &_LEAF; 16 17 struct constructor { 18 assoc *subschemas; 19 }; 20 21 typedef struct constructor constructor; 22 23 /* CONSTRUCTORS */ 24 25 schema* 26 new_schema(symbol name) 27 { 28 schema *s = malloc(sizeof(schema)); 29 s->constructors = new_assoc(); 30 s->checker = NULL; 31 s->name = name; 32 return s; 33 } 34 35 constructor* 36 new_constructor() 37 { 38 constructor *c = malloc(sizeof(constructor)); 39 c->subschemas = new_assoc(); 40 return c; 41 } 42 43 44 /* GETTERS AND SETTERS */ 45 46 symbol 47 get_name(schema*s) 48 { 49 return s->name; 50 } 51 52 bool 53 is_constructor(schema* s, symbol c) 54 { 55 return assoc_get(s->constructors, c) != NULL; 56 } 57 58 constructor* 59 get_constructor(schema* s, symbol c) 60 { 61 assert(is_constructor(s, c)); 62 return (constructor*) assoc_get(s->constructors, c); 63 } 64 65 schema* 66 get_subschema(schema* s, symbol c, symbol k) 67 { 68 assert(is_constructor(s, c)); 69 return (schema*) assoc_get(get_constructor(s, c)->subschemas, k); 70 } 71 72 bool 73 has_key(schema *s, symbol c, symbol k) 74 { 75 assert(is_constructor(s, c)); 76 return (assoc_get(get_constructor(s, c)->subschemas, k) != NULL); 77 } 78 79 bool 80 takes_leaf(schema *s, symbol c, symbol k) 81 { 82 assert(is_constructor(s, c)); 83 return (assoc_get(get_constructor(s, c)->subschemas, k) == LEAF); 84 } 85 86 void 87 set_check_function(schema* s, bool (*f)(tree*)) 88 { 89 s->checker = f; 90 } 91 92 bool (*get_check_function(schema* s))(tree*) 93 { 94 return s->checker; 95 } 96 97 size_t 98 get_amount_of_required_keys(schema *s, symbol c) 99 { 100 return get_amount_of_keys(get_constructor(s, c)->subschemas); 101 } 102 103 symbol* 104 get_required_keys(schema *s, symbol c) 105 { 106 return get_keys(get_constructor(s, c)->subschemas); 107 } 108 109 /* REST OF INTERFACE */ 110 111 void 112 add_constructor(schema* s, symbol c) 113 { 114 assert(s); 115 assert(!is_constructor(s, c)); 116 constructor *sub = new_constructor(); 117 assoc_set(s->constructors, c, sub); 118 } 119 120 void 121 assign_subschema(schema* s, symbol c, symbol k, schema* sub) 122 { 123 assert(is_constructor(s, c)); 124 assoc_set(get_constructor(s, c)->subschemas, k, sub); 125 } 126 127 void 128 mark_as_leaf(schema* s, symbol c, symbol k) 129 { 130 assert(is_constructor(s, c)); 131 assoc_set(get_constructor(s, c)->subschemas, k, LEAF); 132 } 133 134 bool 135 check(schema* s, tree* t) 136 { 137 if (!s) return true; 138 if (!t) return false; 139 if (s == LEAF && is_leaf(t)) return true; 140 141 symbol head = get_head(t); 142 if (!is_constructor(s, head)) return false; 143 144 bool good = true; 145 146 size_t lim = get_amount_of_keys(get_constructor(s, head)->subschemas); 147 symbol *keys = get_keys(get_constructor(s, head)->subschemas); 148 149 for (size_t i = 0; i < lim && good; i++) { 150 tree *subtree = get_subtree(t, keys[i]); 151 schema *subschema = get_subschema(s, head, keys[i]); 152 assert(subschema != NULL); 153 154 if (subtree) 155 good &= (check(subschema, get_subtree(t, keys[i]))); 156 else 157 return false; 158 } 159 160 bool (*checker)(tree*) = get_check_function(s); 161 if (checker) good &= checker(t); 162 163 return good; 164 } 165 166