4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
35 #define ALLOW_NOTHING 0
36 #define ALLOW_VARSIZE 1
39 #define ALLOW_NO_UNIONS 8 /* for topmost structures */
40 #define ALLOW_NO_SWITCH 16
47 static void type_ident_decl(ndr_typeinfo_t
*, char *, size_t, char *);
48 static void type_ident_decl1(struct tup
*, char *, size_t, char *);
49 static void analyze_typeinfo_list(void);
50 static void analyze_typeinfo_typedef(ndr_typeinfo_t
*);
51 static void analyze_typeinfo_struct(ndr_typeinfo_t
*);
52 static void analyze_typeinfo_union(ndr_typeinfo_t
*);
53 static void analyze_typeinfo_aggregate_finish(ndr_typeinfo_t
*);
54 static void analyze_member(ndr_node_t
*, ndr_member_t
*, unsigned long *, int);
55 static void seed_basic_types(void);
56 static void seed_construct_types(void);
57 static void append_typeinfo(ndr_typeinfo_t
*);
58 static ndr_typeinfo_t
*bind_typeinfo(ndr_typeinfo_t
*);
59 static ndr_typeinfo_t
*find_typeinfo_by_name(ndr_node_t
*);
60 static void determine_advice(ndr_advice_t
*, ndr_node_t
*);
61 static ndr_node_t
*find_advice(ndr_node_t
*advice_list
, int label
);
68 seed_construct_types();
70 analyze_typeinfo_list();
74 show_typeinfo_list(void)
81 char fname_type
[NDLBUFSZ
];
83 for (ti
= typeinfo_list
; ti
; ti
= ti
->next
) {
84 switch (ti
->type_op
) {
101 type_extern_suffix(ti
, fname_type
, NDLBUFSZ
);
103 (void) printf("extern ndr_%s()\n",
105 } else if (!ti
->is_referenced
) {
106 (void) printf("implied ndr_%s\n", fname_type
);
111 (void) printf("show_typeinfo skipping %d\n",
116 (void) printf("\n\n");
117 show_advice(&ti
->advice
, 0);
118 (void) printf("%s %s {\n", p
, ti
->type_name
->n_sym
->name
);
120 for (i
= 0; i
< ti
->n_member
; i
++) {
121 mem
= &ti
->member
[i
];
122 show_advice(&mem
->advice
, 2);
123 type_extern_suffix(mem
->type
, fname_type
, NDLBUFSZ
);
124 (void) printf(" %-16s ndr_%-13s",
125 mem
->name
, fname_type
);
128 (void) printf(" fsiz=%d vsiz=%d algn=%d off=%d\n",
129 tdti
->size_fixed_part
,
130 tdti
->size_variable_part
,
135 (void) printf("} fsiz=%d vsiz=%d algn=%d comp=%d ptrs=%d\n",
137 ti
->size_variable_part
,
145 type_extern_suffix(ndr_typeinfo_t
*tsti
, char *funcbuf
, size_t buflen
)
148 char *p_fb
= funcbuf
;
152 for (ti
= tsti
; ti
; ti
= ti
->type_down
) {
153 switch (ti
->type_op
) {
158 (void) snprintf(p_fb
, buflen
, "_%s",
159 ti
->type_name
->n_sym
->name
);
163 (void) strlcpy(p_fb
, "p", buflen
);
168 (void) snprintf(p_fb
, buflen
, "a%ld",
169 ti
->type_dim
->n_int
);
171 (void) snprintf(p_fb
, buflen
, "ac");
176 (void) strlcpy(p_fb
, "s", buflen
);
180 (void) snprintf(p_fb
, buflen
, "?<%d>", ti
->type_op
);
189 type_ident_decl1(struct tup
*tup
, char *funcbuf
, size_t buflen
, char *ident
)
196 (void) strlcpy(funcbuf
, ident
, buflen
);
201 switch (ti
->type_op
) {
204 type_ident_decl1(tup
->up
, fb
, NDLBUFSZ
, ident
);
205 (void) snprintf(funcbuf
, buflen
, "%s%s%s%s",
206 "", ti
->type_name
->n_sym
->name
, *fb
? " " : "", fb
);
210 type_ident_decl1(tup
->up
, fb
, NDLBUFSZ
, ident
);
211 (void) snprintf(funcbuf
, buflen
, "%s%s%s%s",
212 "struct ", ti
->type_name
->n_sym
->name
, *fb
? " " : "", fb
);
216 type_ident_decl1(tup
->up
, fb
, NDLBUFSZ
, ident
);
217 (void) snprintf(funcbuf
, buflen
, "%s%s%s%s",
218 "union ", ti
->type_name
->n_sym
->name
, *fb
? " " : "", fb
);
223 type_ident_decl1(tup
->up
, funcbuf
+1, buflen
- 1, ident
);
229 type_ident_decl1(tup
->up
, p
, NDLBUFSZ
- 1, ident
);
232 (void) strlcat(p
, ")", NDLBUFSZ
);
235 (void) snprintf(funcbuf
, buflen
, "%s[%ld]",
236 p
, ti
->type_dim
->n_int
);
238 (void) snprintf(funcbuf
, buflen
,
239 "%s[NDR_ANYSIZE_DIM]", p
);
246 type_ident_decl1(tup
->up
, p
, NDLBUFSZ
- 1, ident
);
249 (void) strlcat(p
, ")", NDLBUFSZ
);
251 (void) snprintf(funcbuf
, buflen
, "%s[NDR_STRING_DIM]", p
);
255 compile_error("unknown type or keyword <%d>", ti
->type_op
);
261 type_ident_decl(ndr_typeinfo_t
*tsti
, char *funcbuf
, size_t buflen
, char *ident
)
264 struct tup tup_tab
[40];
269 for (ti
= tsti
; ti
; ti
= ti
->type_down
, n_tt
++) {
270 tup
= &tup_tab
[n_tt
];
276 type_ident_decl1(up
, funcbuf
, buflen
, ident
);
280 type_null_decl(ndr_typeinfo_t
*tsti
, char *funcbuf
, size_t buflen
)
283 type_ident_decl(tsti
, funcbuf
+1, buflen
, "");
284 (void) strlcat(funcbuf
, ")", buflen
);
288 type_name_decl(ndr_typeinfo_t
*tsti
, char *funcbuf
, size_t buflen
, char *name
)
290 type_ident_decl(tsti
, funcbuf
, buflen
, name
);
294 show_advice(ndr_advice_t
*adv
, int indent
)
299 for (i
= 0; i
< N_ADVICE
; i
++) {
300 if (!adv
->a_nodes
[i
])
304 (void) printf("%-*s[", indent
, "");
308 print_node(adv
->a_nodes
[i
]);
312 (void) printf("]\n");
316 analyze_typeinfo_list(void)
320 for (ti
= typeinfo_list
; ti
; ti
= ti
->next
) {
321 switch (ti
->type_op
) {
323 analyze_typeinfo_struct(ti
);
327 analyze_typeinfo_union(ti
);
331 analyze_typeinfo_typedef(ti
);
338 analyze_typeinfo_typedef(ndr_typeinfo_t
*ti
)
344 unsigned long offset
;
346 assert(ti
->type_op
== TYPEDEF_KW
);
351 determine_advice(&ti
->advice
, ti
->definition
->n_c_advice
);
354 * Convert the members to table.
355 * Determine layout metrics along the way.
357 mem_np
= ti
->definition
->n_c_members
;
360 assert(i
< ti
->n_member
);
361 mem
= &ti
->member
[i
];
363 allow
= ALLOW_NO_SWITCH
;
365 analyze_member(mem_np
, mem
,
366 &offset
, /* progress offset */
367 allow
); /* see above */
369 assert(1 == ti
->n_member
);
371 analyze_typeinfo_aggregate_finish(ti
);
373 /* Align offset to determine overall size */
374 while (offset
& ti
->alignment
)
377 ti
->size_fixed_part
= offset
;
381 analyze_typeinfo_struct(ndr_typeinfo_t
*ti
)
387 unsigned long offset
;
389 assert(ti
->type_op
== STRUCT_KW
);
392 * Snarf the advice. Only recognize [operation()] for
393 * struct definitions.
395 determine_advice(&ti
->advice
, ti
->definition
->n_c_advice
);
398 * Convert the members from list to table.
399 * Determine layout metrics along the way.
401 mem_np
= ti
->definition
->n_c_members
;
404 for (; mem_np
; i
++, mem_np
= mem_np
->n_next
) {
405 assert(i
< ti
->n_member
);
406 mem
= &ti
->member
[i
];
408 if (!ti
->advice
.a_operation
/* no var-size in op param */ &&
409 i
== ti
->n_member
-1) /* only last mem may be var-size */
410 allow
= ALLOW_VARSIZE
;
414 analyze_member(mem_np
, mem
, &offset
, allow
);
416 assert(i
== ti
->n_member
);
418 analyze_typeinfo_aggregate_finish(ti
); /* align,complete,ptrs,etc */
420 /* Align offset to determine overall size */
421 while (offset
& ti
->alignment
)
424 ti
->size_fixed_part
= offset
;
426 /* If last member is var-sized, so is this struct */
427 mem
= &ti
->member
[ti
->n_member
-1];
428 ti
->size_variable_part
= mem
->type
->size_variable_part
;
430 if (ti
->size_variable_part
)
431 ti
->is_conformant
= 1;
435 analyze_typeinfo_union(ndr_typeinfo_t
*ti
)
440 unsigned long offset
;
443 assert(ti
->type_op
== UNION_KW
);
446 * Snarf the advice. None supported for union definitions.
447 * Only [switch_is()] supported for union instances.
449 determine_advice(&ti
->advice
, ti
->definition
->n_c_advice
);
452 * Convert the members from list to table.
453 * Determine layout metrics along the way.
455 mem_np
= ti
->definition
->n_c_members
;
458 for (; mem_np
; i
++, mem_np
= mem_np
->n_next
) {
459 assert(i
< ti
->n_member
);
460 mem
= &ti
->member
[i
];
462 offset
= 0; /* all members offset=0 */
463 analyze_member(mem_np
, mem
,
465 ALLOW_CASE
+ALLOW_NO_UNIONS
); /* var-size disallowed */
467 if (size
< mem
->type
->size_fixed_part
)
468 size
= mem
->type
->size_fixed_part
;
470 assert(i
== ti
->n_member
);
472 analyze_typeinfo_aggregate_finish(ti
); /* align,complete,ptrs,etc */
474 /* align size to determine overall size */
475 while (size
& ti
->alignment
)
478 ti
->size_fixed_part
= size
;
482 analyze_typeinfo_aggregate_finish(ndr_typeinfo_t
*ti
)
487 int has_pointers
= 0;
489 for (i
= 0; i
< ti
->n_member
; i
++) {
490 mem
= &ti
->member
[i
];
492 complete
&= mem
->type
->complete
;
493 has_pointers
|= mem
->type
->has_pointers
;
494 ti
->alignment
|= mem
->type
->alignment
;
497 ti
->complete
= complete
;
498 ti
->has_pointers
= has_pointers
;
502 analyze_member(ndr_node_t
*mem_np
, ndr_member_t
*mem
,
503 unsigned long *offsetp
, int allow
)
506 ndr_node_t
*decl_ops
[NDLBUFSZ
];
507 ndr_typeinfo_t
*type_down
;
508 ndr_typeinfo_t proto_ti
;
512 * Set line_number for error reporting (so we know where to look)
514 line_number
= mem_np
->line_number
;
517 * Simple parts of member
519 mem
->definition
= mem_np
;
520 determine_advice(&mem
->advice
, mem_np
->n_m_advice
);
523 * The node list for the declarator is in outside-to-inside
524 * order. It is also decorated with the LP nodes for
525 * precedence, which are in our way at this point.
527 * These two loops reverse the list, which is easier
528 * to analyze. For example, the declaration:
532 * will have the node list (=> indicates n_d_descend):
534 * ulong => STAR => LP => LB[100] => id
536 * and the conversion will result in type info (=> indicates
539 * id => LB[100] => STAR => ulong
541 * which is closer to how you would pronounce the declaration:
543 * id is an array size 100 of pointers to ulong.
546 /* first pass -- turn the list into a table */
548 for (np
= mem_np
->n_m_decl
; np
; np
= np
->n_d_descend
) {
549 if (np
->label
== IDENTIFIER
) {
554 continue; /* ignore precedence nodes */
556 decl_ops
[n_decl_ops
++] = np
;
559 compile_error("declaration error");
560 print_node(mem_np
->n_m_decl
);
563 mem
->name
= np
->n_sym
->name
;
566 /* second pass -- turn the table into push-back list */
567 type_down
= find_typeinfo_by_name(mem_np
->n_m_type
);
569 if (type_down
->type_op
== TYPEDEF_KW
)
570 type_down
= type_down
->member
[0].type
;
572 if (mem
->advice
.a_string
) {
573 bzero(&proto_ti
, sizeof (proto_ti
));
574 proto_ti
.type_op
= STRING_KW
;
575 proto_ti
.type_down
= type_down
;
576 type_down
= bind_typeinfo(&proto_ti
);
579 for (i
= n_decl_ops
; i
-- > 0; ) {
582 bzero(&proto_ti
, sizeof (proto_ti
));
584 proto_ti
.type_op
= np
->label
;
585 proto_ti
.type_down
= type_down
;
589 proto_ti
.type_dim
= np
->n_d_dim
;
594 * bind_typeinfo() reuses (interns) typeinfo's to
595 * make later code generation easier. It will report
598 type_down
= bind_typeinfo(&proto_ti
);
601 /* bind the member to its type info */
602 mem
->type
= type_down
;
603 type_down
->is_referenced
= 1; /* we handle first-level indirection */
606 * Now, apply the type info to the member layout metrics.
610 while (*offsetp
& type_down
->alignment
)
613 mem
->pdu_offset
= *offsetp
;
615 *offsetp
+= type_down
->size_fixed_part
;
617 if (mem
->advice
.a_length_is
)
618 compile_error("[length_is()] is not supported");
620 if (mem
->advice
.a_transmit_as
)
621 compile_error("[transmit_as()] is not supported");
623 if (mem
->advice
.a_arg_is
)
624 compile_error("[arg_is()] is not supported");
628 * [case(x)] TYPE xxx;
629 * [default] TYPE xxx;
631 * These only make sense within unions.
633 if (allow
& ALLOW_CASE
) {
636 if (mem
->advice
.a_case
)
638 if (mem
->advice
.a_default
)
642 compile_error("no [case/default] advice");
644 compile_error("too many [case/default] advice");
646 if (mem
->advice
.a_case
&& mem
->advice
.a_default
)
647 compile_error("[case/default] advice not allowed");
652 * [operation(x)] TYPE foo;
653 * [interface(x)] TYPE foo;
654 * [uuid(x)] TYPE foo;
656 * The [operation()] advice may only appear on a struct to
657 * indicate that the structure is a top-most (parameter)
658 * structure, and the opcode associated with the parameters.
660 if (mem
->advice
.a_operation
)
661 compile_error("[operation()] advice not allowed");
663 if (mem
->advice
.a_interface
)
664 compile_error("[interface()] advice not allowed");
666 if (mem
->advice
.a_uuid
)
667 compile_error("[uuid()] advice not allowed");
671 * [switch_is(x)] union foo xxx;
673 * Disallow [switch_is] on anything which is not a union.
675 if (mem
->advice
.a_switch_is
&& type_down
->type_op
!= UNION_KW
) {
676 compile_error("[switch_is()] advice not allowed");
681 * [size_is(x)] TYPE * ptr;
682 * [size_is(x)] TYPE arr[];
684 * Disallow [size_is()] on anything other than pointer and
685 * variable length array.
687 if (mem
->advice
.a_size_is
&&
688 type_down
->type_op
!= STAR
&&
689 !(type_down
->type_op
== LB
&&
690 type_down
->type_dim
== 0)) {
691 compile_error("[size_is()] advice not allowed");
696 * [string] char * ptr_string;
698 * Disallow [string] on anything else. The determination
699 * of size (for the outer header) on anything else is
702 if (mem
->advice
.a_string
&& type_down
->type_op
!= STAR
) {
703 compile_error("[string] advice not allowed");
706 if (type_down
->type_op
== LB
&&
707 type_down
->type_dim
== 0) { /* var-length array of some sort */
712 * Requires [size_is()] directive
713 * [size_is(x)] TYPE array[]
716 if (mem
->advice
.a_size_is
)
720 compile_error("var-size missing sizing directive");
722 compile_error("var-size too many sizing directives");
726 * Nested unions and struct members, other than the last one,
727 * cannot contain variable sized members.
729 if (type_down
->size_variable_part
&& !(allow
& ALLOW_VARSIZE
)) {
730 compile_error("var-size member not allowed");
734 * Disallow unions in operations (i.e. [operation()] struct ...),
735 * The switch_is() value is not reliably available. DCE/RPC
736 * automatically synthesizes an encapsulated union for
737 * these situations, which we have to do by hand:
739 * struct { long switch_value; union foo x; } synth;
741 * We also can not allow unions within unions because
742 * there is no way to pass the separate [switch_is(x)] selector.
744 if (type_down
->type_op
== UNION_KW
) {
745 if (allow
& ALLOW_NO_UNIONS
) {
746 compile_error("unencapsulated union not allowed");
747 } else if (!mem
->advice
.a_switch_is
&&
748 !(allow
& ALLOW_NO_SWITCH
)) {
749 compile_error("union instance without selector");
755 seed_basic_types(void)
759 ndr_typeinfo_t proto_ti
;
761 for (sym
= symbol_list
; sym
; sym
= sym
->next
) {
765 if (sym
->kw
->token
!= BASIC_TYPE
)
768 ti
= ndr_alloc(1, sizeof (ndr_typeinfo_t
));
770 ti
->type_op
= BASIC_TYPE
;
771 ti
->definition
= &sym
->s_node
;
772 ti
->type_name
= &sym
->s_node
;
773 ti
->size_fixed_part
= sym
->kw
->value
;
774 ti
->alignment
= ti
->size_fixed_part
- 1;
780 bzero(&proto_ti
, sizeof (proto_ti
));
781 proto_ti
.type_op
= STRING_KW
;
782 proto_ti
.type_down
= ti
;
784 ti
= bind_typeinfo(&proto_ti
);
790 seed_construct_types(void)
792 ndr_node_t
*construct
;
797 construct
= construct_list
;
798 for (; construct
; construct
= construct
->n_next
) {
799 ti
= ndr_alloc(1, sizeof (ndr_typeinfo_t
));
801 ti
->type_op
= construct
->label
;
802 ti
->definition
= construct
;
804 switch (ti
->type_op
) {
808 ti
->type_name
= construct
->n_c_typename
;
810 np
= construct
->n_c_members
;
812 for (; np
; np
= np
->n_next
)
815 ti
->n_member
= n_member
;
817 ti
->member
= ndr_alloc(n_member
,
818 sizeof (ndr_member_t
));
822 fatal_error("seed_construct unknown %d\n", ti
->type_op
);
826 determine_advice(&ti
->advice
, construct
->n_c_advice
);
828 ti
->is_referenced
= 1; /* always generate */
835 append_typeinfo(ndr_typeinfo_t
*ti
)
839 for (pp
= &typeinfo_list
; *pp
; pp
= &(*pp
)->next
)
846 static ndr_typeinfo_t
*
847 bind_typeinfo(ndr_typeinfo_t
*proto_ti
)
850 ndr_typeinfo_t
*tdti
= proto_ti
->type_down
;
852 for (ti
= typeinfo_list
; ti
; ti
= ti
->next
) {
853 if (ti
->type_op
!= proto_ti
->type_op
)
856 switch (ti
->type_op
) {
858 if (ti
->type_down
!= proto_ti
->type_down
)
863 if (ti
->type_down
!= proto_ti
->type_down
)
868 if (ti
->type_down
!= proto_ti
->type_down
)
870 if (ti
->type_dim
!= proto_ti
->type_dim
)
878 if (ti
->type_name
!= proto_ti
->type_name
)
883 fatal_error("bind_typeinfo unknown %d\n", ti
->type_op
);
890 ti
= ndr_alloc(1, sizeof (ndr_typeinfo_t
));
895 switch (ti
->type_op
) {
897 ti
->size_fixed_part
= 4;
900 ti
->has_pointers
= 1;
905 if (tdti
->complete
) {
906 ti
->alignment
= tdti
->alignment
;
907 if (tdti
->size_variable_part
) {
908 compile_error("array of var-size type");
909 } else if (ti
->type_dim
) {
910 ti
->size_fixed_part
= tdti
->size_fixed_part
*
913 ti
->size_variable_part
= tdti
->size_fixed_part
;
914 ti
->is_conformant
= 1;
917 compile_error("array of incomplete type");
920 ti
->has_pointers
= tdti
->has_pointers
;
925 compile_error("bind_type internal error op=%d", ti
->type_op
);
932 * There is no way to pass the selector (switch_is)in
934 if (ti
->type_op
== STAR
&& ti
->type_down
->type_op
== UNION_KW
) {
935 compile_error("pointers to unions not allowed");
940 * union foo fooarr[n];
941 * Each element needs a distinct selector
943 if (ti
->type_op
== LB
&& ti
->type_down
->type_op
== UNION_KW
) {
944 compile_error("arrays of unions not allowed");
950 static ndr_typeinfo_t
*
951 find_typeinfo_by_name(ndr_node_t
*typename
)
955 for (ti
= typeinfo_list
; ti
; ti
= ti
->next
) {
956 if (ti
->type_name
== typename
)
960 compile_error("unknown type %s", typename
->n_sym
->name
);
962 /* fake BASIC_TYPE */
963 ti
= ndr_alloc(1, sizeof (ndr_typeinfo_t
));
964 ti
->type_op
= BASIC_TYPE
;
965 ti
->definition
= typename
;
966 ti
->type_name
= typename
;
967 ti
->size_fixed_part
= 0;
975 determine_advice(ndr_advice_t
*advice
, ndr_node_t
*advice_list
)
977 /* alias for basic types */
978 advice
->a_transmit_as
= find_advice(advice_list
, TRANSMIT_AS_KW
);
980 /* arg used for size, union, or generic purpose */
981 advice
->a_arg_is
= find_advice(advice_list
, ARG_IS_KW
);
983 /* operation parameter in/out stuff */
984 advice
->a_operation
= find_advice(advice_list
, OPERATION_KW
);
985 advice
->a_in
= find_advice(advice_list
, IN_KW
);
986 advice
->a_out
= find_advice(advice_list
, OUT_KW
);
989 advice
->a_string
= find_advice(advice_list
, STRING_KW
);
990 advice
->a_size_is
= find_advice(advice_list
, SIZE_IS_KW
);
991 advice
->a_length_is
= find_advice(advice_list
, LENGTH_IS_KW
);
994 advice
->a_case
= find_advice(advice_list
, CASE_KW
);
995 advice
->a_default
= find_advice(advice_list
, DEFAULT_KW
);
996 advice
->a_switch_is
= find_advice(advice_list
, SWITCH_IS_KW
);
998 /* interface stuff */
999 advice
->a_interface
= find_advice(advice_list
, INTERFACE_KW
);
1000 advice
->a_uuid
= find_advice(advice_list
, UUID_KW
);
1001 advice
->a_no_reorder
= find_advice(advice_list
, _NO_REORDER_KW
);
1002 advice
->a_extern
= find_advice(advice_list
, EXTERN_KW
);
1004 advice
->a_reference
= find_advice(advice_list
, REFERENCE_KW
);
1005 advice
->a_align
= find_advice(advice_list
, ALIGN_KW
);
1009 find_advice(ndr_node_t
*advice_list
, int label
)
1013 for (np
= advice_list
; np
; np
= np
->n_next
)
1014 if (np
->label
== label
)
1021 member_fixup(ndr_node_t
*member_np
)
1025 for (np
= member_np
->n_m_decl
; np
; np
= np
->n_d_descend
)
1026 if (np
->label
== IDENTIFIER
)
1029 member_np
->n_m_name
= np
;
1033 construct_fixup(ndr_node_t
*construct_np
)
1035 construct_np
->n_c_typename
->n_sym
->typedefn
= construct_np
;