fixing pass-by-reference handling bugs
This commit is contained in:
		| @ -306,13 +306,19 @@ struct qse_awk_chain_t | ||||
| }; | ||||
|  | ||||
| #define RTX_STACK_AT(rtx,n) ((rtx)->stack[(rtx)->stack_base+(n)]) | ||||
| #define RTX_STACK_NARGS(rtx) (RTX_STACK_AT(rtx,3)) | ||||
| #define RTX_STACK_NARGS(rtx) RTX_STACK_AT(rtx,3) | ||||
| #define RTX_STACK_ARG(rtx,n) RTX_STACK_AT(rtx,3+1+(n)) | ||||
| #define RTX_STACK_LCL(rtx,n) RTX_STACK_AT(rtx,3+(qse_size_t)RTX_STACK_NARGS(rtx)+1+(n)) | ||||
| #define RTX_STACK_RETVAL(rtx) RTX_STACK_AT(rtx,2) | ||||
| #define RTX_STACK_GBL(rtx,n) ((rtx)->stack[(n)]) | ||||
| #define RTX_STACK_RETVAL_GBL(rtx) ((rtx)->stack[(rtx)->awk->tree.ngbls+2]) | ||||
|  | ||||
| #define RTX_STACK_AT_OVER_BASE(rtx,_base,n) ((rtx)->stack[(_base)+(n)]) | ||||
| #define RTX_STACK_NARGS_OVER_BASE(rtx,_base) RTX_STACK_AT_OVER_BASE(rtx,_base,3) | ||||
| #define RTX_STACK_ARG_OVER_BASE(rtx,_base,n) RTX_STACK_AT_OVER_BASE(rtx,_base,3+1+(n)) | ||||
| #define RTX_STACK_LCL_OVER_BASE(rtx,_base,n) RTX_STACK_AT_OVER_BASE(rtx,_base,3+(qse_size_t)RTX_STACK_NARGS(rtx)+1+(n)) | ||||
| #define RTX_STACK_RETVAL_OVER_BASE(rtx,_base) RTX_STACK_AT_OVER_BASE(rtx,_base,2) | ||||
|  | ||||
| struct qse_awk_rtx_t | ||||
| { | ||||
| 	QSE_AWK_RTX_HDR; | ||||
|  | ||||
| @ -1553,9 +1553,9 @@ qse_awk_val_t* qse_awk_rtx_callfun (qse_awk_rtx_t* rtx, qse_awk_fun_t* fun, qse_ | ||||
|  | ||||
| 	if (fun->argspec) | ||||
| 	{ | ||||
| 		/* this function contains call-by-reference parameters. | ||||
| 		/* this function contains pass-by-reference parameters. | ||||
| 		 * i don't support the call here as it requires variables */ | ||||
| 		qse_awk_rtx_seterrfmt (rtx, QSE_AWK_EPERM, QSE_NULL, QSE_T("not allowed to call '%.*js' with call-by-reference parameters"), (int)fun->name.len, fun->name.ptr); | ||||
| 		qse_awk_rtx_seterrfmt (rtx, QSE_AWK_EPERM, QSE_NULL, QSE_T("not allowed to call '%.*js' with pass-by-reference parameters"), (int)fun->name.len, fun->name.ptr); | ||||
| 		return QSE_NULL; | ||||
| 	} | ||||
|  | ||||
| @ -5949,16 +5949,19 @@ static qse_awk_val_t* __eval_call ( | ||||
| 	{ | ||||
| 		/* extra step for normal awk functions */ | ||||
|  | ||||
| 		 | ||||
| 		if (fun->argspec) | ||||
| 		{ | ||||
| 			/* sanity check for call-by-reference parameters of a normal awk function. | ||||
| 			 * it tests if each call-by-reference argument is referenceable. */ | ||||
| 			/* sanity check for pass-by-reference parameters of a normal awk function. | ||||
| 			 * it tests if each pass-by-reference argument is referenceable. */ | ||||
| 			 | ||||
| 			qse_awk_nde_t* p = call->args; | ||||
| 			for (i = 0; i < nargs; i++) | ||||
| 			{ | ||||
| 				if (fun->argspec[i] == QSE_T('r')) | ||||
| 				{ | ||||
| 					qse_awk_val_t** ref; | ||||
|  | ||||
| 					if (get_reference(rtx, p, &ref) <= -1) | ||||
| 					{ | ||||
| 						UNWIND_RTX_STACK (rtx, nargs); | ||||
| @ -6039,12 +6042,21 @@ static qse_awk_val_t* __eval_call ( | ||||
| 	qse_errputstrf (QSE_T("block rtx complete nargs = %d\n"), (int)nargs);  | ||||
| #endif | ||||
|  | ||||
| 	if (fun && fun->argspec) | ||||
| 	if (fun && fun->argspec && nargs > 0) | ||||
| 	{ | ||||
| 		/* set back the values for call-by-reference parameters of normal functions. | ||||
| 		/* set back the values for pass-by-reference parameters of normal functions. | ||||
| 		 * the intrinsic functions are not handled here but their implementation would | ||||
| 		 * call qse_awk_rtx_setrefval() */ | ||||
|  | ||||
| 		/* even if fun->argspec exists, nargs may still be 0. so i test if nargs > 0. | ||||
| 		 *   function x(a1, &a2) {} | ||||
| 		 *   BEGIN { x(); } | ||||
| 		 * all parameters are nils in this case. fun->nargs is 2 but call->nargs or  nargs is 0. | ||||
| 		 */ | ||||
|  | ||||
| 		qse_size_t cur_stack_base = rtx->stack_base; | ||||
| 		qse_size_t prev_stack_base = (qse_size_t)rtx->stack[rtx->stack_base+0]; | ||||
|  | ||||
| 		qse_awk_nde_t* p = call->args; | ||||
| 		for (i = 0; i < nargs; i++) | ||||
| 		{ | ||||
| @ -6052,8 +6064,14 @@ static qse_awk_val_t* __eval_call ( | ||||
| 			{ | ||||
| 				qse_awk_val_t** ref; | ||||
| 				qse_awk_val_ref_t refv; | ||||
|  | ||||
| 				/* UGLY */ | ||||
| 				rtx->stack_base = prev_stack_base; | ||||
| 				get_reference (rtx, p, &ref); /* no failure check as it must succeed here for the check done above */ | ||||
| 				QSE_AWK_RTX_INIT_REF_VAL (&refv, p->type - QSE_AWK_NDE_NAMED, ref, 5); /* initialize a fake reference variable */ | ||||
| 				rtx->stack_base = cur_stack_base; | ||||
| 				/* UGLY */ | ||||
|  | ||||
| 				QSE_AWK_RTX_INIT_REF_VAL (&refv, p->type - QSE_AWK_NDE_NAMED, ref, 9); /* initialize a fake reference variable. 9 chosen randomly */ | ||||
| 				qse_awk_rtx_setrefval (rtx, &refv, RTX_STACK_ARG(rtx, i)); | ||||
| 			} | ||||
|  | ||||
| @ -6067,6 +6085,9 @@ static qse_awk_val_t* __eval_call ( | ||||
| 		{ | ||||
| 			qse_awk_rtx_refdownval (rtx, RTX_STACK_ARG(rtx,i)); | ||||
| 		} | ||||
|  | ||||
| 		/* no refdown on arguments at position between nargs and fun->nargs  | ||||
| 		 * even if they were reference, there is no effect(no copy back). */ | ||||
| 	} | ||||
|  | ||||
| #ifdef DEBUG_RUN | ||||
| @ -6217,6 +6238,7 @@ static qse_size_t push_arg_from_nde (qse_awk_rtx_t* rtx, qse_awk_nde_fncall_t* c | ||||
| 		qse_awk_rtx_refupval (rtx, v); | ||||
| 	} | ||||
|  | ||||
| 	QSE_ASSERT (call->nargs == nargs); | ||||
| 	return nargs; | ||||
| } | ||||
|  | ||||
| @ -6236,11 +6258,10 @@ static int get_reference (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, qse_awk_val_t* | ||||
| 			pair = qse_htb_search(rtx->named, tgt->id.name.ptr, tgt->id.name.len); | ||||
| 			if (pair == QSE_NULL) | ||||
| 			{ | ||||
| 				/* it is bad that the named variable has to be | ||||
| 				 * created in the function named "__get_refernce". | ||||
| 				/* it is bad that the named variable has to be created here. | ||||
| 				 * would there be any better ways to avoid this? */ | ||||
| 				pair = qse_htb_upsert(rtx->named, tgt->id.name.ptr, tgt->id.name.len, qse_awk_val_nil, 0); | ||||
| 				if (pair == QSE_NULL)  | ||||
| 				if (!pair)  | ||||
| 				{ | ||||
| 					SETERR_LOC (rtx, QSE_AWK_ENOMEM, &nde->loc); | ||||
| 					return -1; | ||||
| @ -6773,7 +6794,7 @@ static int __raw_push (qse_awk_rtx_t* rtx, void* val) | ||||
| 		n = rtx->stack_limit + RTX_STACK_INCREMENT; | ||||
|  | ||||
| 		tmp = (void**)qse_awk_rtx_reallocmem(rtx, rtx->stack, n * QSE_SIZEOF(void*));  | ||||
| 		if (tmp == QSE_NULL) return -1; | ||||
| 		if (!tmp) return -1; | ||||
|  | ||||
| 		rtx->stack = tmp; | ||||
| 		rtx->stack_limit = n; | ||||
| @ -6897,7 +6918,7 @@ static int shorten_record (qse_awk_rtx_t* rtx, qse_size_t nflds) | ||||
| 	if (nflds > 1) qse_awk_rtx_refdownval (rtx, v); | ||||
|  | ||||
| 	v = (qse_awk_val_t*)qse_awk_rtx_makestrvalwithxstr(rtx, QSE_STR_XSTR(&tmp)); | ||||
| 	if (v == QSE_NULL)  | ||||
| 	if (!v)  | ||||
| 	{ | ||||
| 		qse_str_fini (&tmp); | ||||
| 		return -1; | ||||
| @ -6926,19 +6947,19 @@ static qse_char_t* idxnde_to_str (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, qse_ch | ||||
|  | ||||
| 	QSE_ASSERT (nde != QSE_NULL); | ||||
|  | ||||
| 	if (nde->next == QSE_NULL) | ||||
| 	if (!nde->next) | ||||
| 	{ | ||||
| 		qse_awk_rtx_valtostr_out_t out; | ||||
|  | ||||
| 		/* single node index */ | ||||
| 		idx = eval_expression (rtx, nde); | ||||
| 		if (idx == QSE_NULL) return QSE_NULL; | ||||
| 		if (!idx) return QSE_NULL; | ||||
|  | ||||
| 		qse_awk_rtx_refupval (rtx, idx); | ||||
|  | ||||
| 		str = QSE_NULL; | ||||
|  | ||||
| 		if (buf != QSE_NULL) | ||||
| 		if (buf) | ||||
| 		{ | ||||
| 			/* try with a fixed-size buffer if given */ | ||||
| 			out.type = QSE_AWK_RTX_VALTOSTR_CPLCPY; | ||||
| @ -6953,7 +6974,7 @@ static qse_char_t* idxnde_to_str (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, qse_ch | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (str == QSE_NULL) | ||||
| 		if (!str) | ||||
| 		{ | ||||
| 			/* if no fixed-size buffer was given or the fixed-size  | ||||
| 			 * conversion failed, switch to the dynamic mode */ | ||||
| @ -6987,10 +7008,10 @@ static qse_char_t* idxnde_to_str (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, qse_ch | ||||
| 			return QSE_NULL; | ||||
| 		} | ||||
|  | ||||
| 		while (nde != QSE_NULL) | ||||
| 		while (nde) | ||||
| 		{ | ||||
| 			idx = eval_expression(rtx, nde); | ||||
| 			if (idx == QSE_NULL)  | ||||
| 			if (!idx)  | ||||
| 			{ | ||||
| 				qse_str_fini (&idxstr); | ||||
| 				return QSE_NULL; | ||||
| @ -6998,10 +7019,7 @@ static qse_char_t* idxnde_to_str (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, qse_ch | ||||
|  | ||||
| 			qse_awk_rtx_refupval (rtx, idx); | ||||
|  | ||||
| 			if (QSE_STR_LEN(&idxstr) > 0 && | ||||
| 			    qse_str_ncat (&idxstr,  | ||||
| 			    	rtx->gbl.subsep.ptr,  | ||||
| 			    	rtx->gbl.subsep.len) == (qse_size_t)-1) | ||||
| 			if (QSE_STR_LEN(&idxstr) > 0 && qse_str_ncat(&idxstr, rtx->gbl.subsep.ptr, rtx->gbl.subsep.len) == (qse_size_t)-1) | ||||
| 			{ | ||||
| 				qse_awk_rtx_refdownval (rtx, idx); | ||||
| 				qse_str_fini (&idxstr); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user