better parsing information object class sets
diff --git a/libasn1parser/asn1p_expr.c b/libasn1parser/asn1p_expr.c
index 7a24d06..4383ea1 100644
--- a/libasn1parser/asn1p_expr.c
+++ b/libasn1parser/asn1p_expr.c
@@ -9,6 +9,82 @@
 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);
 
+void
+asn1p_expr_set_source(asn1p_expr_t *expr, asn1p_module_t *module, int lineno) {
+    if(expr) {
+        expr->module = module;
+        expr->_lineno = lineno;
+        asn1p_ref_set_source(expr->reference, module, lineno);
+        asn1p_value_set_source(expr->value, module, lineno);
+        asn1p_constraint_set_source(expr->constraints, module, lineno);
+        asn1p_constraint_set_source(expr->combined_constraints, module, lineno);
+        asn1p_expr_set_source(expr->rhs_pspecs, module, lineno);
+
+        asn1p_expr_t *memb;
+
+        TQ_FOR(memb, &(expr->members), next) {
+            asn1p_expr_set_source(memb, module, lineno);
+        }
+    }
+}
+
+int
+asn1p_expr_compare(const asn1p_expr_t *a, const asn1p_expr_t *b) {
+    if(a->meta_type != b->meta_type || a->expr_type != b->expr_type) {
+        return -1;
+    }
+
+    if((!a->Identifier && b->Identifier) || (a->Identifier && !b->Identifier)) {
+        return -1;
+    } else if(a->Identifier && strcmp(a->Identifier, b->Identifier)) {
+        return -1;
+    }
+
+    if((!a->reference && b->reference) || (a->reference && !b->reference)) {
+        return -1;
+    } else if(a->reference
+              && asn1p_ref_compare(a->reference, b->reference) != 0) {
+        return -1;
+    }
+
+    if((!a->value && b->value) || (a->value && !b->value)) {
+        return -1;
+    } else if(a->value && asn1p_value_compare(a->value, b->value)) {
+        return -1;
+    }
+
+    if((a->tag.tag_class != b->tag.tag_class)
+       || (a->tag.tag_mode != b->tag.tag_mode)
+       || (a->tag.tag_value != b->tag.tag_value)) {
+        return -1;
+    }
+
+    if((a->marker.flags != b->marker.flags)
+       || (a->marker.default_value && !b->marker.default_value)
+       || (!a->marker.default_value && b->marker.default_value)
+       || (a->marker.default_value
+           && asn1p_value_compare(a->marker.default_value,
+                                  b->marker.default_value))) {
+        return -1;
+    }
+
+    if(a->unique != b->unique) {
+        return -1;
+    }
+
+    const asn1p_expr_t *am = TQ_FIRST(&a->members);
+    const asn1p_expr_t *bm = TQ_FIRST(&b->members);
+    for(; am || bm; am = TQ_NEXT(am, next), bm = TQ_NEXT(bm, next)) {
+        if((am && !bm) || (!am && bm)) {
+            return -1;
+        } else if(asn1p_expr_compare(am, bm) != 0) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
 /*
  * Construct a new empty types collection.
  */