1/* BEGIN LICENSE BLOCK
2 * Version: CMPL 1.1
3 *
4 * The contents of this file are subject to the Cisco-style Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file except
6 * in compliance with the License.  You may obtain a copy of the License
7 * at www.eclipse-clp.org/license.
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11 * the License for the specific language governing rights and limitations
12 * under the License.
13 *
14 * The Original Code is  The ECLiPSe Constraint Logic Programming System.
15 * The Initial Developer of the Original Code is  Cisco Systems, Inc.
16 * Portions created by the Initial Developer are
17 * Copyright (C) 1989-2006 Cisco Systems, Inc.  All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * END LICENSE BLOCK */
22
23
24/*
25 * SEPIA C SOURCE MODULE
26 *
27 * VERSION	$Id: operator.c,v 1.6 2012/09/23 18:52:39 jschimpf Exp $
28 */
29
30/*
31 * IDENTIFICATION		operator.c
32 *
33 * DESCRIPTION			implemetation of the operator using
34 *				the property list
35 *
36 * CONTENTS:
37 *
38 * AUTHOR		VERSION	 DATE	REASON
39 * Emmanuel van Rossum		900315	created the file
40 *
41 */
42
43#include	"config.h"
44#include	"sepia.h"
45#include	"types.h"
46#include	"embed.h"
47#include	"error.h"
48#include	"mem.h"
49#include	"dict.h"
50#include 	"emu_export.h"
51#include	"property.h"
52#include	"module.h"
53#include	"lex.h"
54
55
56
57/* flags in the isop field of atoms, not set means no operator,
58   set means may be an operator						*/
59#define	IS_PREFIX_OP	1
60#define	IS_INFIX_OP	2
61#define	IS_POSTFIX_OP	4
62
63#define FixToProp(fixity) ((fixity) == IS_PREFIX_OP ? PREFIX_PROP : (fixity) == IS_INFIX_OP ? INFIX_PROP : POSTFIX_PROP)
64
65#define PropToFix(prop) ((prop) == PREFIX_PROP ? IS_PREFIX_OP : (prop) == INFIX_PROP ? IS_INFIX_OP : IS_POSTFIX_OP)
66
67/* 2 followings get or create a property prop (can be PREFIX_PROP or
68   INFIX_PROP or POSTFIX_PROP) for did did in module mod with visibility vis */
69#define OperatorItem(did, mod, mod_tag, vis, prop, perr) \
70    get_modular_property(did, prop, mod, mod_tag, vis, perr)
71#define NewOperatorItem(did, mod, mod_tag, vis, prop, perr) \
72    set_modular_property(did, prop, mod, mod_tag, vis, perr)
73
74
75static dident	didassoc[MAX_ASSOC+1];
76static dident	d_comma0_, d_bar0_;
77
78static int
79    _get_assoc(dident assoc),
80    _insert_op(int scope, word preced, word assoc, dident oper, dident module, type mod_tag),
81    _erase_op(dident oper, word assoc, int scope, dident module, type mod_tag),
82    p_op_(value vi, type ti, value vprec, type tprec, value vassoc, type tassoc, value v_op, type t_op, value vm, type tm),
83    p_is_prefix_op(value vp, type tp, value assoc, type ta, value name, type tn, value vv, type tv, value module, type tm),
84    p_is_postfix_op(value vp, type tp, value assoc, type ta, value name, type tn, value vv, type tv, value module, type tm),
85    p_is_infix_op(value vp, type tp, value assoc, type ta, value name, type tn, value vv, type tv, value module, type tm),
86    p_abolish_op_(value v_op, type t_op, value v_assoc, type t_assoc, value v_mod, type t_mod),
87    p_legal_current_op(value v_prec, type t_prec, value v_assoc, type t_assoc, value v_op, type t_op, value v_mod, type t_mod);
88
89static opi	*_visible_anyfix_op(int fixity, dident atom, dident module, type mod_tag, int *res);
90
91
92/*
93 * Operator Initialization
94 */
95/*ARGSUSED*/
96void
97op_init(int flags)
98{
99    if (!(flags & INIT_PRIVATE))
100	return;
101    /* initialize the associativity table */
102    didassoc[FX] = in_dict("fx", 0);
103    didassoc[FY] = in_dict("fy", 0);
104    didassoc[XF] = in_dict("xf", 0);
105    didassoc[YF] = in_dict("yf", 0);
106    didassoc[XFX] = in_dict("xfx", 0);
107    didassoc[XFY] = in_dict("xfy", 0);
108    didassoc[YFX] = in_dict("yfx", 0);
109    didassoc[FXX] = in_dict("fxx", 0);
110    didassoc[FXY] = in_dict("fxy", 0);
111
112    d_comma0_ = in_dict(",", 0);
113    d_bar0_ = in_dict("|", 0);
114}
115
116void
117bip_op_init(int flags)
118{
119    if (!(flags & INIT_SHARED))
120	return;
121    (void) local_built_in(in_dict("op_", 5),	p_op_, B_SAFE);
122    (void) local_built_in(in_dict("is_prefix_op", 5), p_is_prefix_op, B_SAFE);
123    (void) local_built_in(in_dict("is_postfix_op", 5), p_is_postfix_op, B_SAFE);
124    (void) local_built_in(in_dict("is_infix_op", 5), p_is_infix_op, B_SAFE);
125    (void) local_built_in(in_dict("abolish_op_", 3),p_abolish_op_, B_SAFE);
126    (void) local_built_in(in_dict("legal_current_op", 4),
127		   p_legal_current_op, B_SAFE);
128}
129
130/*
131 *	returns the (unsigned) associativity associated to the
132 *	Prolog one (did).
133 *	return NIL_OP if 'assoc' is not in the table.
134 */
135static int
136_get_assoc(dident assoc)
137{
138    word iassoc = MAX_ASSOC;
139
140    while (iassoc > NIL_OP && didassoc[iassoc] != assoc)
141	iassoc--;
142    return (iassoc);
143}
144
145/*
146 * The locking done here is rather useless:
147 * We are not allowed to return a pointer to a (shared heap) opi
148 * without holding the lock. But this would be just too much to fix...
149 * Most of the other properties have the same bug.
150 */
151static opi *
152_visible_anyfix_op(int fixity, dident atom, dident module, type mod_tag, int *res)
153{
154    opi		*operator_prop;
155
156    if (atom == D_UNKNOWN
157	|| !(DidIsOp(atom) & fixity))
158    {
159	*res = PERROR;
160	return 0;
161    }
162
163    a_mutex_lock(&PropertyLock);
164
165    operator_prop = OperatorItem(atom, module, mod_tag,
166				 VISIBLE_PROP, FixToProp(fixity), res);
167    if (!operator_prop)
168    {
169	a_mutex_unlock(&PropertyLock);
170	*res = PERROR;
171	return 0;
172    }
173    if (operator_prop->tag.kernel != TEND)
174    {
175	a_mutex_unlock(&PropertyLock);	/* THIS IS WRONG! */
176	return operator_prop;
177    }
178    else
179    {
180	a_mutex_unlock(&PropertyLock);
181	*res = PERROR;
182	return 0;
183    }
184}
185
186
187/*
188 * Return nonzero if any operator property is attached to atom.
189 * Needed to implement ISO-Prolog restrictions.
190 */
191int
192visible_operator(dident atom, dident module, type mod_tag)
193{
194    int res;
195    opi *desc;
196    desc = OperatorItem(atom, module, mod_tag, VISIBLE_PROP, INFIX_PROP, &res);
197    if (desc && GetOpiPreced(desc)) return 1;
198    desc = OperatorItem(atom, module, mod_tag, VISIBLE_PROP, PREFIX_PROP, &res);
199    if (desc && GetOpiPreced(desc)) return 1;
200    desc = OperatorItem(atom, module, mod_tag, VISIBLE_PROP, POSTFIX_PROP, &res);
201    if (desc && GetOpiPreced(desc)) return 1;
202    return 0;
203}
204
205
206/*
207 * visible_prefix_op(atom, module) return a pointer to the visible
208 * prefix operator desriptor defined under atom and visible from module
209 * if there is such an operator; return 0 otherwise.
210 */
211opi*
212visible_prefix_op(dident atom, dident module, type mod_tag, int *res)
213{
214    opi		*desc;
215
216    desc = _visible_anyfix_op(IS_PREFIX_OP, atom, module, mod_tag, res);
217    if (desc && !GetOpiPreced(desc)) {
218	*res = PERROR;
219	return (opi *) 0;
220    } else
221	return desc;
222}
223
224/*
225 * visible_infix_op(atom, module) return a pointer to the visible
226 * infix operator desriptor defined under atom and visible from module
227 * if there is such an operator; return 0 otherwise.
228 */
229opi*
230visible_infix_op(dident atom, dident module, type mod_tag, int *res)
231{
232    opi		*desc;
233
234    desc = _visible_anyfix_op(IS_INFIX_OP, atom, module, mod_tag, res);
235    if (desc && !GetOpiPreced(desc)) {
236	*res = PERROR;
237	return (opi *) 0;
238    } else
239	return desc;
240}
241
242/*
243 * visible_postfix_op(atom, module) return a pointer to the visible
244 * postfix operator desriptor defined under atom and visible from module
245 * if there is such an operator; return 0 otherwise.
246 */
247opi*
248visible_postfix_op(dident atom, dident module, type mod_tag, int *res)
249{
250    opi		*desc;
251
252    desc = _visible_anyfix_op(IS_POSTFIX_OP, atom, module, mod_tag, res);
253    if (desc && !GetOpiPreced(desc)) {
254	*res = PERROR;
255	return (opi *) 0;
256    } else
257	return desc;
258}
259
260/*
261 * visible_op(functor, module) return a pointer to the visible operator
262 * under functor (an infix operator if functor is arity 2, an unary operator
263 * if functor is of arity 1 (if a prefix and a postfix are visible,
264 * the prefix is returned).
265 * return 0 if no operator is visible from module under functor.
266 * NOTE : when there is a prefix/postfix conflict, a local declaration
267 * should be return when there is one (e.g. local postfix and global prefix).
268 */
269opi*
270visible_op(dident functor, dident module, type mod_tag, int *res)
271{
272    opi		*operator_prop;
273    int		arity;
274    dident	atom = add_dict(functor, 0);
275
276    if ((arity = DidArity(functor)) == 1)
277    {
278	/* look for a unary operator: first try FX,FY then XF,YF */
279	operator_prop = visible_prefix_op(atom, module, mod_tag, res);
280	/* visible_prefix_op() also finds FXX and FXY: ignore them here */
281	if (!operator_prop || IsPrefix2(operator_prop))
282	{
283	    /* no unary prefix, look for postfix */
284	    operator_prop = visible_postfix_op(atom, module, mod_tag, res);
285	}
286    }
287    else if (arity == 2)
288    {
289	/* look for a binary operator, first try XFX,XFY,YFX then FXX,FXY */
290	operator_prop = visible_infix_op(atom, module, mod_tag, res);
291	if (!operator_prop)
292	{
293	    /* no infix, look for binary prefix */
294	    operator_prop = visible_prefix_op(atom, module, mod_tag, res);
295	    if (operator_prop && !IsPrefix2(operator_prop))
296	    	operator_prop = (opi *) 0;
297	}
298    }
299    else /* arity != 1 && arity != 2 so it is not an operator		*/
300    {
301	*res = PERROR; /* means no operator */
302	return 0;
303    }
304    return operator_prop;
305}
306
307/*
308 * is_visible_op(atom, module, mod_tag) returns 1 iff there is an
309 * operator attached to 'atom', returns 0 otherwise.
310 *
311 * Must be called in an interrupt protected area.
312 */
313int
314is_visible_op(dident atom, dident module, type mod_tag)
315{
316    opi		*operator_prop;
317    int		err = PERROR;
318    int		res;
319
320    if (atom == D_UNKNOWN || !DidIsOp(atom))
321    {
322	Set_Bip_Error(PERROR);
323	return 0;
324    }
325
326    a_mutex_lock(&PropertyLock);
327
328    /* DidIsOp may be out of date, ie. it may be set even when there
329     * is no longer such an operator. That's why we have to check.	*/
330    if ((DidIsOp(atom) & IS_PREFIX_OP)
331	&& (operator_prop = OperatorItem(atom, module, mod_tag,
332					 VISIBLE_PROP, PREFIX_PROP, &res))
333	&& operator_prop->tag.kernel != TEND
334	&& GetOpiPreced(operator_prop))
335    {
336	a_mutex_unlock(&PropertyLock);
337	return 1;
338    }
339    else if ((DidIsOp(atom) & IS_INFIX_OP)
340	     && (operator_prop = OperatorItem(atom, module, mod_tag,
341					      VISIBLE_PROP, INFIX_PROP,&res))
342	     && operator_prop->tag.kernel != TEND
343	    && GetOpiPreced(operator_prop))
344    {
345	a_mutex_unlock(&PropertyLock);
346	return 1;
347    }
348    else if ((DidIsOp(atom) & IS_POSTFIX_OP)
349	     && (operator_prop = OperatorItem(atom, module, mod_tag,
350					      VISIBLE_PROP, POSTFIX_PROP,&res))
351	     && operator_prop->tag.kernel != TEND
352	    && GetOpiPreced(operator_prop))
353    {
354	a_mutex_unlock(&PropertyLock);
355	return 1;
356    }
357    else
358    {
359	Set_Bip_Error(err);
360	a_mutex_unlock(&PropertyLock);
361	return 0;
362    }
363}
364
365
366/* The following builtins use the global error variable ! */
367#undef Bip_Error
368#define Bip_Error(N) Bip_Error_Fail(N)
369
370/*
371  op_(Visibility, Precedence, Associativity, Operator, Module)
372  It inserts in the operator table an operator, whose name is
373  Operator of precedence Precedence and of associativity Associativity.
374  Visibility can only be global or local. Module is significant
375  only for a local operator.
376  A null precedence will erase/hide a previous/global declaration.
377  */
378/*ARGSUSED*/
379static int
380p_op_(value vi, type ti, value vprec, type tprec, value vassoc, type tassoc, value v_op, type t_op, value vm, type tm)
381{
382    word	iassoc;
383    int		scope = (vi.did == d_.local0 ? LOCAL_PROP : GLOBAL_PROP);
384
385    /* vi is supplied by the system so no need to test it.		*/
386    Check_Module(tm, vm);
387    Check_Atom_Or_Nil(v_op, t_op);
388    Check_Atom_Or_Nil(vassoc, tassoc);
389    Check_Integer(tprec);
390
391    if ((vprec.nint > 1200) || (vprec.nint < 0))
392    {
393        Bip_Error(RANGE_ERROR);
394    }
395    iassoc = _get_assoc(vassoc.did);
396    if (iassoc == NIL_OP)
397    {
398	Bip_Error(RANGE_ERROR);
399    }
400    if (ModuleSyntax(vm.did)->options & ISO_RESTRICTIONS)
401    {
402	if (iassoc >= FXX)
403	{
404	    Bip_Error(RANGE_ERROR)
405	}
406	else if (v_op.did == d_comma0_
407	      || v_op.did == d_.nil
408	      || v_op.did == d_.nilcurbr
409	      || v_op.did == d_bar0_ && (
410		    !(iassoc==XFY || iassoc==XFX || iassoc==YFX)
411		    || vprec.nint > 0 && vprec.nint <= 1000))
412	{
413	    Bip_Error(ILLEGAL_OP_DEF)
414	}
415    }
416
417    if (vprec.nint == 0 && scope == GLOBAL_PROP)
418	/* precedence 0 is used to erase the operator but if it is
419	   local, the descriptor is kept to hide a global operator	*/
420	return _erase_op(v_op.did, iassoc, scope, vm.did, tm);
421    else
422	return _insert_op(scope, vprec.nint, iassoc, v_op.did, vm.did, tm);
423}
424
425/*
426  abolish_op_(atom, assoc, module)
427  abolish the declaration of the operator 'atom' of associativity
428  'assoc' visible from 'module'.
429 */
430static int
431p_abolish_op_(value v_op, type t_op, value v_assoc, type t_assoc, value v_mod, type t_mod)
432{
433    word	iassoc;
434
435    Check_Atom_Or_Nil(v_op, t_op);
436    Check_Atom_Or_Nil(v_assoc, t_assoc);
437    Check_Module(t_mod, v_mod);
438
439    iassoc = _get_assoc(v_assoc.did);
440    if (iassoc == NIL_OP)
441    {
442	Bip_Error(RANGE_ERROR);
443    }
444
445    return _erase_op(v_op.did, iassoc, VISIBLE_PROP, v_mod.did,t_mod);
446}
447
448/*
449  _insert_op( scope, preced, assoc, oper, module, mod_tag)
450  An insertion is made in the operator property list if there are
451  no conflict of associativity (postfix and infix).
452  However a local postfix/infix hide a global one so that
453  the conflict is impossible between a local and a global.
454  A local operator can not be modified in a locked module if the
455  module tag is not signed.
456  The precedence 0 is used to hide a global operator.
457*/
458static int
459_insert_op(int scope, word preced, word assoc, dident oper, dident module, type mod_tag)
460{
461    opi		*operator_prop;
462    int		prop_type;
463    int		arity;
464    int		res;
465
466    switch (assoc)
467    {
468    case XF:
469    case YF:
470	prop_type = POSTFIX_PROP;
471	arity = 1;
472	break;
473    case FX:
474    case FY:
475	prop_type = PREFIX_PROP;
476	arity = 1;
477	break;
478    case FXX:
479    case FXY:
480	prop_type = PREFIX_PROP;
481	arity = 2;
482	break;
483    case XFX:
484    case XFY:
485    case YFX:
486	prop_type = INFIX_PROP;
487	arity = 2;
488	break;
489    }
490
491    /* Disallow infix/postfix, if required by the module syntax */
492    if (prop_type != PREFIX_PROP  &&  ModuleSyntax(module)->options & ISO_RESTRICTIONS)
493    {
494        if (OperatorItem(oper, module, mod_tag, VISIBLE_PROP,
495                (prop_type==INFIX_PROP? POSTFIX_PROP : INFIX_PROP), &res))
496        {
497	    Bip_Error(ILLEGAL_OP_DEF);
498        }
499    }
500
501    a_mutex_lock(&PropertyLock);
502
503    res = PERROR;
504    operator_prop = OperatorItem(oper, module, mod_tag, scope, prop_type, &res);
505
506    if (operator_prop)		/* same scope operator exists already */
507    {
508	if (preced && (GetOpiAssoc(operator_prop) != assoc ||
509			GetOpiPreced(operator_prop) != preced)) {
510	    res = REDEF_OPERATOR;
511	} else {
512	    res = PSUCCEED;
513	}
514    }
515    else
516    {
517	if (res != PERROR)
518	{
519	    a_mutex_unlock(&PropertyLock);
520	    Bip_Error(res);
521	}
522	/* No proper scope operator exists yet */
523	/* For locals, check hiding */
524	if (scope == LOCAL_PROP &&
525	    OperatorItem(oper, module, mod_tag, GLOBAL_PROP, prop_type, &res))
526	    res = HIDING_OPERATOR;
527	else
528	    res = PSUCCEED;
529
530	operator_prop = NewOperatorItem(oper, module, mod_tag,
531					scope, prop_type, &res);
532	if (!operator_prop)
533	{
534	    a_mutex_unlock(&PropertyLock);
535	    Bip_Error(res);
536	}
537    }
538
539    /* now update the descriptor					*/
540    operator_prop->tag.kernel = TDICT;
541    Set_Opi_Assoc(operator_prop, assoc);
542    Set_Opi_Preced(operator_prop, preced);
543    OpiDid(operator_prop) = add_dict(oper, arity);
544    DidIsOp(oper) |= PropToFix(prop_type);
545
546    a_mutex_unlock(&PropertyLock);
547    if (res < 0)
548	{Bip_Error(res)}
549    return res;
550}
551
552/*
553 * _erase_op(oper, module) erase the definition of an operator
554 */
555static int
556_erase_op(dident oper, word assoc, int scope, dident module, type mod_tag)
557{
558    opi		*operator_prop;
559    int		prop_type;
560    int		res;
561
562    switch (assoc)
563    {
564    case XF:
565    case YF:
566	prop_type = POSTFIX_PROP;
567	break;
568    case FX:
569    case FY:
570    case FXX:
571    case FXY:
572	prop_type = PREFIX_PROP;
573	break;
574    case XFX:
575    case XFY:
576    case YFX:
577	prop_type = INFIX_PROP;
578	break;
579    }
580
581    a_mutex_lock(&PropertyLock);
582    operator_prop = OperatorItem(oper, module, mod_tag, scope, prop_type,&res);
583    if (!operator_prop)
584    {
585	if (res == PERROR)
586	    res = UNDEF_OPERATOR;
587	a_mutex_unlock(&PropertyLock);
588	Bip_Error(res);
589    }
590    else if (operator_prop->tag.kernel == TEND)
591    {
592	a_mutex_unlock(&PropertyLock);
593	Bip_Error(UNDEF_OPERATOR);
594    }
595    if (erase_modular_property(oper, prop_type, module, mod_tag, scope)
596	== PFAIL) /* the property is completely erased for that atom	*/
597    {
598	DidIsOp(oper) &= ~PropToFix(prop_type);
599    }
600    a_mutex_unlock(&PropertyLock);
601    Succeed_;
602}
603
604/*
605  legal_current_op(?Precedence, ?Assoc, +Operator_atom, +Module)
606  checks that all arguments are valid for current_op_body/4.
607  */
608static int
609p_legal_current_op(value v_prec, type t_prec, value v_assoc, type t_assoc, value v_op, type t_op, value v_mod, type t_mod)
610{
611    if (!IsRef(t_op))			/* Operator name		*/
612    {
613	Check_Atom_Or_Nil(v_op, t_op);
614#ifdef lint
615	/* v_op is set in Check_Atom_Or_Nil but not used		*/
616	if (v_op.nint) return v_op.nint;
617#endif /* lint */
618    }
619    Check_Module(t_mod, v_mod);		/* module			*/
620    Check_Module_Access(v_mod, t_mod);
621
622    if (IsAtom(t_assoc))		/* Associativity		*/
623    {
624	word iassoc = _get_assoc(v_assoc.did);
625	if (iassoc == NIL_OP ||
626	   (iassoc > FXX && (ModuleSyntax(v_mod.did)->options & ISO_RESTRICTIONS)))
627	{
628	    Bip_Error(RANGE_ERROR);
629	}
630    }
631    else if (!IsRef(t_assoc))
632    {
633	Bip_Error(TYPE_ERROR);
634    }
635
636    if (IsInteger(t_prec))		/* Precedence			*/
637    {
638	if (v_prec.nint < 0 || v_prec.nint > 1200)
639	{
640	    Bip_Error(RANGE_ERROR);
641	}
642    }
643    else if (!IsRef(t_prec))
644    {
645	Bip_Error(TYPE_ERROR);
646    }
647    Succeed_;
648}
649
650/*
651	is_prefix_op(Precedence, Associativity, Name, Visib, Module)
652	Name and Module must be instantiated.
653	Associativity and Precedence are either instantiated or a variable.
654	If there is an operator of this type in the operator table,
655	It succeeds and instantiates the precedence.
656*/
657/*ARGSUSED*/ /* check is already made in p_illegal_current_op		*/
658static int
659p_is_prefix_op(value vp, type tp, value assoc, type ta, value name, type tn, value vv, type tv, value module, type tm)
660{
661    opi    	*desc;
662    int		res;
663    Prepare_Requests;
664
665    if (IsNil(tn))
666    {
667	name.did = d_.nil;
668	tn = tdict;
669    }
670
671    if (desc = _visible_anyfix_op(IS_PREFIX_OP, name.did, module.did, tm, &res))
672    {
673        Request_Unify_Integer(vp, tp, GetOpiPreced(desc));
674	Request_Unify_Atom(assoc, ta, didassoc[GetOpiAssoc(desc)]);
675	Request_Unify_Atom(vv, tv,
676			    (res == LOCAL_PROP ? d_.local0 : d_.global0));
677	Return_Unify;
678    }
679    Fail_;
680}
681
682/*
683	is_postfix_op(Precedence, Associativity, Name, Visib, Module)
684	Name and Module must be instantiated.
685	Associativity and Precedence are either instantiated or a variable.
686	If there is an operator of this type in the operator table,
687	It succeeds and instantiates the precedence.
688*/
689/*ARGSUSED*/ /* check is already made in p_illegal_current_op		*/
690static int
691p_is_postfix_op(value vp, type tp, value assoc, type ta, value name, type tn, value vv, type tv, value module, type tm)
692{
693    opi    	*desc;
694    int		res;
695    Prepare_Requests
696
697    if (IsNil(tn))
698    {
699	name.did = d_.nil;
700	tn = tdict;
701    }
702    if (desc = _visible_anyfix_op(IS_POSTFIX_OP, name.did, module.did, tm, &res))
703    {
704        Request_Unify_Integer(vp, tp, GetOpiPreced(desc));
705	Request_Unify_Atom(assoc, ta, didassoc[GetOpiAssoc(desc)]);
706	Request_Unify_Atom(vv, tv,
707			    (res == LOCAL_PROP ? d_.local0 : d_.global0));
708	Return_Unify;
709    }
710    Fail_;
711}
712
713/*
714	is_infix_op(Precedence, Associativity, Name, Visib, Module)
715	Name and Module must be instantiated.
716	Associativity and Precedence are either instantiated or a variable.
717	If there is an operator of this type in the operator table,
718	It succeeds and instantiates the precedence.
719*/
720/*ARGSUSED*/ /* check is already made in p_illegal_current_op		*/
721static int
722p_is_infix_op(value vp, type tp, value assoc, type ta, value name, type tn, value vv, type tv, value module, type tm)
723{
724    opi    	*desc;
725    int		res;
726    Prepare_Requests
727
728    if (IsNil(tn))
729    {
730	name.did = d_.nil;
731	tn = tdict;
732    }
733    if (desc = _visible_anyfix_op(IS_INFIX_OP, name.did, module.did, tm, &res))
734    {
735        Request_Unify_Integer(vp, tp, GetOpiPreced(desc));
736	Request_Unify_Atom(assoc, ta, didassoc[GetOpiAssoc(desc)]);
737	Request_Unify_Atom(vv, tv,
738			    (res == LOCAL_PROP ? d_.local0 : d_.global0));
739	Return_Unify;
740    }
741    Fail_;
742}
743