refactored parameterization support


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@1102 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/libasn1parser/asn1p_expr.c b/libasn1parser/asn1p_expr.c
index f5626a7..266f2d7 100644
--- a/libasn1parser/asn1p_expr.c
+++ b/libasn1parser/asn1p_expr.c
@@ -6,6 +6,9 @@
 
 #include "asn1parser.h"
 
+static asn1p_expr_t *asn1p_expr_clone_impl(asn1p_expr_t *expr, int skip_extensions, asn1p_expr_t *(*)(asn1p_expr_t *, void *), void *);
+static asn1p_value_t *value_resolver(asn1p_value_t *, void *arg);
+
 /*
  * Construct a new empty types collection.
  */
@@ -16,6 +19,7 @@
 	expr = calloc(1, sizeof *expr);
 	if(expr) {
 		TQ_INIT(&(expr->members));
+		expr->spec_index = -1;
 		expr->_lineno = _lineno;
 	}
 
@@ -24,21 +28,62 @@
 
 asn1p_expr_t *
 asn1p_expr_clone(asn1p_expr_t *expr, int skip_extensions) {
-	asn1p_expr_t *clone;
+	return asn1p_expr_clone_impl(expr, skip_extensions, 0, 0);
+}
+
+asn1p_expr_t *
+asn1p_expr_clone_with_resolver(asn1p_expr_t *expr, asn1p_expr_t *(*r)(asn1p_expr_t *, void *), void *rarg) {
+	return asn1p_expr_clone_impl(expr, 0, r, rarg);
+}
+
+static asn1p_expr_t *
+asn1p_expr_clone_impl(asn1p_expr_t *expr, int skip_extensions, asn1p_expr_t *(*r)(asn1p_expr_t *, void *), void *rarg) {
+	asn1p_value_t *(*vr)(asn1p_value_t *, void *) = 0;
+	asn1p_expr_t *clone = 0;
 	asn1p_expr_t *tcmemb;	/* Child of tc */
 	int hit_ext = 0;
 
-	clone = asn1p_expr_new(expr->_lineno);
-	if(clone == NULL) return NULL;
-
 #define	CLCOPY(field)	do { clone->field = expr->field; } while(0)
-#define	CLCLONE(field, func)	do { if(expr->field) {		\
-			clone->field = func(expr->field);	\
-			if(clone->field == NULL) {		\
-				asn1p_expr_free(clone);		\
-				return NULL;			\
-			}					\
+#define	CLCLONE(field, func)	do { if(expr->field) {			\
+			clone->field = func(expr->field);		\
+			if(clone->field == NULL) {			\
+				asn1p_expr_free(clone);			\
+				return NULL;				\
+			}						\
 		} } while(0)
+#define	CLVRCLONE(field, func)	do { if(expr->field) {			\
+			clone->field = func(expr->field, vr, rarg);	\
+			if(clone->field == NULL) {			\
+				asn1p_expr_free(clone);			\
+				return NULL;				\
+			}						\
+		} } while(0)
+
+	if(r) {
+		vr = value_resolver;
+		clone = r(expr, rarg);
+		if(clone) {
+			/* Merge constraints */
+			if(expr->constraints) {
+				asn1p_constraint_t *tmpct = asn1p_constraint_clone_with_resolver(expr->constraints, vr, rarg);
+				if(clone->constraints) {
+					if(asn1p_constraint_insert(clone->constraints, tmpct)) {
+						asn1p_constraint_free(tmpct);
+						asn1p_expr_free(clone);
+						return NULL;
+					}
+				} else {
+					clone->constraints = tmpct;
+				}
+			}
+			assert(expr->combined_constraints == 0);
+			return clone;
+		} else if(errno != ESRCH) {
+			return NULL;	/* Hard error */
+		}
+	}
+	if(!clone) clone = asn1p_expr_new(expr->_lineno);
+	if(!clone) return NULL;
 
 	/*
 	 * Copy simple fields.
@@ -58,10 +103,10 @@
 	 */
 	CLCLONE(Identifier, strdup);
 	CLCLONE(reference, asn1p_ref_clone);
-	CLCLONE(constraints, asn1p_constraint_clone);
-	CLCLONE(combined_constraints, asn1p_constraint_clone);
-	CLCLONE(params, asn1p_paramlist_clone);
-	CLCLONE(value, asn1p_value_clone);
+	CLVRCLONE(constraints, asn1p_constraint_clone_with_resolver);
+	CLVRCLONE(combined_constraints, asn1p_constraint_clone_with_resolver);
+	CLCLONE(lhs_params, asn1p_paramlist_clone);
+	CLVRCLONE(value, asn1p_value_clone_with_resolver);
 	CLCLONE(marker.default_value, asn1p_value_clone);
 	CLCLONE(with_syntax, asn1p_wsyntx_clone);
 
@@ -78,7 +123,7 @@
 		}
 		if(hit_ext == 1) continue;	/* Skip between ...'s */
 
-		cmemb = asn1p_expr_clone(tcmemb, skip_extensions);
+		cmemb = asn1p_expr_clone_impl(tcmemb, skip_extensions, r, rarg);
 		if(cmemb == NULL) {
 			asn1p_expr_free(clone);
 			return NULL;
@@ -89,6 +134,48 @@
 	return clone;
 }
 
+
+static asn1p_value_t *
+value_resolver(asn1p_value_t *value, void *rarg) {
+	asn1p_value_t *cval;
+	asn1p_expr_t *tmpexpr;
+	asn1p_expr_t *target;
+	asn1p_ref_t *ref;
+	struct {
+		asn1p_expr_t *(*expr_resolve)(asn1p_expr_t *, void *arg);
+	} *varg = rarg;
+
+	if(!value || value->type != ATV_REFERENCED) {
+		errno = ESRCH;
+		return NULL;
+	}
+
+	ref = value->value.reference;
+	tmpexpr = asn1p_expr_new(ref->_lineno);
+	tmpexpr->meta_type = AMT_TYPEREF;
+	tmpexpr->expr_type = A1TC_REFERENCE;
+	tmpexpr->reference = ref;
+	target = varg->expr_resolve(tmpexpr, rarg);
+	tmpexpr->reference = 0;
+	asn1p_expr_free(tmpexpr);
+
+	if(!target)
+		return NULL;	/* errno's are compatible */
+
+	if(!target->value) {
+		fprintf(stderr,
+		"FATAL: Parameterization did not resolve value reference "
+		"at line %d", ref->_lineno);
+		asn1p_expr_free(target);
+		errno = EPERM;
+		return NULL;
+	}
+
+	cval = asn1p_value_clone(target->value);
+	asn1p_expr_free(target);
+	return cval;
+}
+
 /*
  * Add expression as a member of another.
  */
@@ -125,8 +212,8 @@
 			asn1p_constraint_free(expr->constraints);
 		if(expr->combined_constraints)
 			asn1p_constraint_free(expr->combined_constraints);
-		if(expr->params)
-			asn1p_paramlist_free(expr->params);
+		if(expr->lhs_params)
+			asn1p_paramlist_free(expr->lhs_params);
 		if(expr->value)
 			asn1p_value_free(expr->value);
 		if(expr->marker.default_value)