/*-*-macsyma-*-*/

/* macros to define functions which take their arguments
   via keywords. */

EVAL_WHEN([TRANSLATE,BATCH,DEMO],
          IF GET('SHAREM,'VERSION) = FALSE
             THEN LOADFILE(AUTOLO,FASL,DSK,SHAREM))$



/* The idea is to be able to say:

  FOO(X_ZONE=3.3, LOGLIN, FOOSWITCH, BAR=0)

  Specify the arguments/options to a function in terms of
  keywords.

And have unspecified arguments default. */


DEF_KEYARG(HEADER,BODY)::=
 BUILDQ([MNAME:PART(HEADER,0), BODY,
         SNAME:CONCAT(PART(HEADER,0),"-internal"),
         SARGS:MAPLIST(LAMBDA([U],IF ATOM(U) THEN U ELSE PART(U,1)),
	               ARGS(HEADER)),
         DISPATCH:MAPLIST(LAMBDA([U],IF ATOM(U) THEN ['KEY_ATOM,[U]]
	                                ELSE ['KEY_PAIR,[PART(U,1),PART(U,2)]]),
			  ARGS(HEADER))],
	(EVAL_WHEN(LOADFILE,
	           SETUP_AUTOLOAD([KEYARG,FASL,DSK,SHAREM],TRANSLATE_KEYARG)),
         PUT('MNAME,'DISPATCH,'TRANSLATE_KEYARG),
         MNAME([MACRO_ARGL])::=TRANSLATE_KEYARG(MACRO_ARGL,'MNAME,'SNAME),
	 SNAME(SPLICE(SARGS)):=BODY))$

/* This routine must be around during the macro-expansion */

TRANSLATE_KEYARG(MACRO_ARGL,MNAME,SNAME):=
 /* for now I am not going to do the order-of-evaluation guarantee */
 BLOCK([SARGL:[],TEMP,DISPATCH:GET(MNAME,'TRANSLATE_KEYARG)],
       FOR D IN DISPATCH
       DO(TEMP:APPLY(D[1],CONS(MACRO_ARGL,D[2])),
          PUSH(TEMP[1],SARGL),
	  MACRO_ARGL:TEMP[2]),
       IF NOT MACRO_ARGL=[] THEN ERROR("Unknown arguments to",MNAME,":",MACRO_ARGL),
       FUNMAKE(SNAME,REVERSE(SARGL)))$

KEY_INDICATOR(ARGL,ATOM,VALUE):=
 (FOR A IN ARGL
  DO(IF ATOM(A) THEN(IF A=ATOM THEN(VALUE:TRUE,ARGL:DELETE(A,ARGL),RETURN(DONE)))
     ELSE IF PART(A,1)=ATOM THEN(VALUE:PART(A,2),ARGL:DELETE(A,ARGL),RETURN(DONE))),
  [VALUE,ARGL])$     

/* I am thinking of having KEY_ATOM and KEY_PAIR do different things. */

KEY_ATOM(ARGL,ATOM):=KEY_INDICATOR(ARGL,ATOM,FALSE)$

KEY_PAIR(ARGL,ATOM,VALUE):=KEY_INDICATOR(ARGL,ATOM,VALUE)$

