blob: bbd7cf4d8258a5a935a4328048c3454e51c4bb1b [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
2
Lev Walkina00d6b32006-03-21 03:40:38 +00003typedef struct resolver_arg {
4 asn1p_expr_t *(*resolver)(asn1p_expr_t *, void *arg);
5 arg_t *arg;
6 asn1p_expr_t *original_expr;
7 asn1p_paramlist_t *lhs_params;
8 asn1p_expr_t *rhs_pspecs;
9} resolver_arg_t;
Lev Walkind541c252004-09-05 10:36:22 +000010
Lev Walkina00d6b32006-03-21 03:40:38 +000011static asn1p_expr_t *resolve_expr(asn1p_expr_t *, void *resolver_arg);
12static int compare_specializations(arg_t *, asn1p_expr_t *a, asn1p_expr_t *b);
13static asn1p_expr_t *find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref);
14static asn1p_expr_t *find_target_specialization_bystr(resolver_arg_t *rarg, char *str);
Lev Walkinf15320b2004-06-03 03:38:44 +000015
Lev Walkina00d6b32006-03-21 03:40:38 +000016asn1p_expr_t *
17asn1f_parameterization_fork(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *rhs_pspecs) {
18 resolver_arg_t rarg; /* resolver argument */
19 asn1p_expr_t *exc; /* expr clone */
20 asn1p_expr_t *rpc; /* rhs_pspecs clone */
21 asn1p_expr_t *target;
Lev Walkinf15320b2004-06-03 03:38:44 +000022 void *p;
Lev Walkina00d6b32006-03-21 03:40:38 +000023 struct asn1p_pspec_s *pspec;
24 int npspecs;
25 int i;
Lev Walkinf15320b2004-06-03 03:38:44 +000026
Lev Walkina00d6b32006-03-21 03:40:38 +000027 assert(rhs_pspecs);
28 assert(expr->lhs_params);
29 assert(expr->parent_expr == 0);
30
31 DEBUG("Forking parameterization at %d for %s (%d alr)",
32 rhs_pspecs->_lineno, expr->Identifier,
33 expr->specializations.pspecs_count);
Lev Walkinf593f102005-02-22 07:59:59 +000034
Lev Walkinf15320b2004-06-03 03:38:44 +000035 /*
Lev Walkina00d6b32006-03-21 03:40:38 +000036 * Find if this exact specialization has been used already.
Lev Walkinf15320b2004-06-03 03:38:44 +000037 */
Lev Walkina00d6b32006-03-21 03:40:38 +000038 for(npspecs = 0;
39 npspecs < expr->specializations.pspecs_count;
40 npspecs++) {
41 if(compare_specializations(arg, rhs_pspecs,
42 expr->specializations.pspec[npspecs].rhs_pspecs) == 0) {
43 DEBUG("Reused parameterization for %s",
44 expr->Identifier);
45 return expr->specializations.pspec[npspecs].my_clone;
Lev Walkind5947712005-11-05 12:28:14 +000046 }
Lev Walkinf15320b2004-06-03 03:38:44 +000047 }
Lev Walkinf15320b2004-06-03 03:38:44 +000048
Lev Walkina00d6b32006-03-21 03:40:38 +000049 rarg.resolver = resolve_expr;
50 rarg.arg = arg;
51 rarg.original_expr = expr;
52 rarg.lhs_params = expr->lhs_params;
53 rarg.rhs_pspecs = rhs_pspecs;
54 exc = asn1p_expr_clone_with_resolver(expr, resolve_expr, &rarg);
55 rpc = asn1p_expr_clone(rhs_pspecs, 0);
56 assert(exc && rpc);
57
58 /*
59 * Create a new specialization.
60 */
61 npspecs = expr->specializations.pspecs_count;
62 p = realloc(expr->specializations.pspec,
63 (npspecs + 1) * sizeof(expr->specializations.pspec[0]));
64 assert(p);
65 expr->specializations.pspec = p;
66 pspec = &expr->specializations.pspec[npspecs];
67 memset(pspec, 0, sizeof *pspec);
68
69 pspec->rhs_pspecs = rpc;
70 pspec->my_clone = exc;
71 exc->spec_index = npspecs;
72
73 /* Update LHS->RHS specialization in target */
74 target = TQ_FIRST(&rpc->members);
75 for(i = 0; i < exc->lhs_params->params_count;
76 i++, target = TQ_NEXT(target, next)) {
77 if(!target) { target = (void *)0xdeadbeef; break; }
78
79 assert(exc->lhs_params->params[i].into_expr == 0);
80 exc->lhs_params->params[i].into_expr = target;
81 }
82 if(target) {
83 asn1p_expr_free(exc);
84 asn1p_expr_free(rpc);
85 FATAL("Parameterization of %s failed: "
86 "parameters number mismatch", expr->Identifier);
87 errno = EPERM;
88 return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +000089 }
90
Lev Walkina00d6b32006-03-21 03:40:38 +000091 DEBUG("Forked new parameterization for %s", expr->Identifier);
Lev Walkinf15320b2004-06-03 03:38:44 +000092
Lev Walkina00d6b32006-03-21 03:40:38 +000093 /* Commit */
94 expr->specializations.pspecs_count = npspecs + 1;
95 return exc;
Lev Walkinf15320b2004-06-03 03:38:44 +000096}
97
98static int
Lev Walkina00d6b32006-03-21 03:40:38 +000099compare_specializations(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
100 asn1p_expr_t *ac = TQ_FIRST(&a->members);
101 asn1p_expr_t *bc = TQ_FIRST(&b->members);
Lev Walkinf15320b2004-06-03 03:38:44 +0000102
Lev Walkina00d6b32006-03-21 03:40:38 +0000103 for(;ac && bc; ac = TQ_NEXT(ac, next), bc = TQ_NEXT(bc, next)) {
104 retry:
105 if(ac == bc) continue;
106 if(ac->meta_type != bc->meta_type) break;
107 if(ac->expr_type != bc->expr_type) break;
Lev Walkinf593f102005-02-22 07:59:59 +0000108
Lev Walkina00d6b32006-03-21 03:40:38 +0000109 if(!ac->reference && !bc->reference)
110 continue;
Lev Walkind541c252004-09-05 10:36:22 +0000111
Lev Walkina00d6b32006-03-21 03:40:38 +0000112 if(ac->reference) {
113 ac = asn1f_lookup_symbol(arg,
114 ac->module, ac->rhs_pspecs, ac->reference);
115 if(!ac) break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000116 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000117 if(bc->reference) {
118 bc = asn1f_lookup_symbol(arg,
119 bc->module, bc->rhs_pspecs, bc->reference);
120 if(!bc) break;
121 }
122 goto retry;
Lev Walkinf15320b2004-06-03 03:38:44 +0000123 }
124
Lev Walkina00d6b32006-03-21 03:40:38 +0000125 if(ac || bc)
126 /* Specializations do not match: different size option sets */
127 return -1;
128
Lev Walkinf15320b2004-06-03 03:38:44 +0000129 return 0;
130}
131
132static asn1p_expr_t *
Lev Walkina00d6b32006-03-21 03:40:38 +0000133resolve_expr(asn1p_expr_t *expr_to_resolve, void *resolver_arg) {
134 resolver_arg_t *rarg = resolver_arg;
135 arg_t *arg = rarg->arg;
136 asn1p_expr_t *expr;
137 asn1p_expr_t *nex;
Lev Walkinf15320b2004-06-03 03:38:44 +0000138
Lev Walkina00d6b32006-03-21 03:40:38 +0000139 DEBUG("Resolving %s (meta %d)",
140 expr_to_resolve->Identifier, expr_to_resolve->meta_type);
141
142 if(expr_to_resolve->meta_type == AMT_TYPEREF) {
143 expr = find_target_specialization_byref(rarg,
144 expr_to_resolve->reference);
145 if(!expr) return NULL;
146 } else if(expr_to_resolve->meta_type == AMT_VALUE) {
147 assert(expr_to_resolve->value);
148 expr = find_target_specialization_bystr(rarg,
149 expr_to_resolve->Identifier);
150 if(!expr) return NULL;
151 } else {
152 errno = ESRCH;
Lev Walkinf15320b2004-06-03 03:38:44 +0000153 return NULL;
Lev Walkina00d6b32006-03-21 03:40:38 +0000154 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000155
Lev Walkina00d6b32006-03-21 03:40:38 +0000156 DEBUG("Found target %s", expr->Identifier);
157 if(expr->meta_type == AMT_TYPE
158 || expr->meta_type == AMT_VALUE) {
159 DEBUG("Target is a simple type %s",
160 ASN_EXPR_TYPE2STR(expr->expr_type));
161 nex = asn1p_expr_clone(expr, 0);
162 free(nex->Identifier);
163 nex->Identifier = expr_to_resolve->Identifier
164 ? strdup(expr_to_resolve->Identifier) : 0;
165 return nex;
166 } else {
167 FATAL("Feature not implemented for %s",
168 rarg->original_expr->Identifier);
169 errno = EPERM;
170 return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000171 }
172
173 return NULL;
174}
Lev Walkind541c252004-09-05 10:36:22 +0000175
Lev Walkina00d6b32006-03-21 03:40:38 +0000176static asn1p_expr_t *
177find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref) {
178 char *refstr;
Lev Walkind541c252004-09-05 10:36:22 +0000179
Lev Walkina00d6b32006-03-21 03:40:38 +0000180 if(!ref || ref->comp_count != 1) {
181 errno = ESRCH;
182 return NULL;
Lev Walkind541c252004-09-05 10:36:22 +0000183 }
184
Lev Walkina00d6b32006-03-21 03:40:38 +0000185 refstr = ref->components[0].name; /* T */
186
187 return find_target_specialization_bystr(rarg, refstr);
Lev Walkind541c252004-09-05 10:36:22 +0000188}
189
Lev Walkina00d6b32006-03-21 03:40:38 +0000190static asn1p_expr_t *
191find_target_specialization_bystr(resolver_arg_t *rarg, char *refstr) {
192 arg_t *arg = rarg->arg;
193 asn1p_expr_t *target;
194 int i;
Lev Walkind541c252004-09-05 10:36:22 +0000195
Lev Walkina00d6b32006-03-21 03:40:38 +0000196 target = TQ_FIRST(&rarg->rhs_pspecs->members);
197 for(i = 0; i < rarg->lhs_params->params_count;
198 i++, target = TQ_NEXT(target, next)) {
199 struct asn1p_param_s *param = &rarg->lhs_params->params[i];
200 if(!target) break;
Lev Walkind541c252004-09-05 10:36:22 +0000201
Lev Walkina00d6b32006-03-21 03:40:38 +0000202 if(strcmp(param->argument, refstr))
203 continue;
Lev Walkind541c252004-09-05 10:36:22 +0000204
Lev Walkina00d6b32006-03-21 03:40:38 +0000205 return target;
206 }
207 if(i != rarg->lhs_params->params_count) {
208 FATAL("Parameterization of %s failed: "
209 "parameters number mismatch",
210 rarg->original_expr->Identifier);
211 errno = EPERM;
212 return NULL;
Lev Walkind541c252004-09-05 10:36:22 +0000213 }
214
Lev Walkina00d6b32006-03-21 03:40:38 +0000215 errno = ESRCH;
216 return NULL;
Lev Walkind541c252004-09-05 10:36:22 +0000217}