/*
 * $Id: eden.eden,v 1.2 2002/03/01 23:52:06 cssbz Exp $
 */

/*---------------------------------------------------------------------------
function macro(macro_str, para_str1, para_str2, .., para_strN)
  Expands 'macro_str' by substituting 'para_strI' for "?I" and returns the 
  resultant string (ref.: Edward Yung, M.Sc. thesis, `89, vol.2).
---------------------------------------------------------------------------*/

func macro {
  auto i, j, l, m, n, c, s;
  s = "";
  l = (m = $1)#;
  shift;
  i = 1;
  while (i <= l) {
    for (j = i; j <= l && m[j] != '?'; j++);
    if (i != j) s = s // substr(m, i, j - 1);
    if (j <= l) {
      j++;
      n = (c = (j > l) ? '?' : m[j]) - '0';
      s = s // ((1 <= n && n <= $#) ? $[n] : c);
    }
    i = j + 1;
  }
  return s;
}

proc installeddi {
  include(getenv("TKEDEN_LIB")//"/eddi.eden");
}

/* symboldefinition returns the Eden definition of a symbol s in a form
   that can be given to the Eden parser (via execute(), todo() etc),
   whatever the type of symbol s.  It will return a blank string when asked
   for the definition of a builtin function (since there is no meaningful
   Eden code representation of the function).  This function is intended to
   fix problems with the data returned by symboldetail() etc.  Pass
   symboldefinition a string naming the symbol or a pointer to the
   symbol. */
func symboldefinition {
  para s;
  auto sd, ret;

  /* convert s to a pointer if it is not already */
  if (type(s) == "string")
    s = &`s`;
  else if (type(s) != "pointer")
    error("address or symbol name needed (got "//type(s)//")");

  sd = symboldetail(s);

  switch (sd[2]) {
  case "var":
    if (type(*s) == "string")
      ret = nameof(s) // "=\"" // str(*s) // "\";";
    else
      ret = nameof(s) // "=" // str(*s) // ";";
    break;
  case "formula":
    ret = nameof(s) // " is" // sd[3];
    break;
  case "proc":
    ret = "proc " // nameof(s) // " " // sd[3] // ";";
    break;
  case "procmacro":
    ret = "procmacro " // nameof(s) // " " // sd[3] // ";";
    break;
  case "func":
    ret = "func " // nameof(s) // " " // sd[3] // ";";
    break;
  case "builtin":
  case "Real-func":
  case "C-func":
    ret = "";
    break;
  }

  return ret;
}

/* this copies a proc to a new name.  copy("rot", "rotnew"); copies
   the definition of proc rot to proc rotnew. */
proc copyproc {
  para old, new;
  execute("proc " // new // " " // symboltext(old) // ";");
}

/* this adjusts the definition of a proc so that, when called, the
   parameters and, optionally, return result are printed.
   showpara("rot", 1) causes proc rot to show its parameters when
   called. */
proc showpara {
  para p, showret;
  copy(p, p // "_preshowpara");
  execute(macro("
proc ?1 {
  auto ret;
  write(\"?1: \", $, \"...\");
  ret=apply(?1_preshowpara, $);
  if (?2) writeln(ret);
  return ret;
};
", str(p), str(showret)));
}

/* Make a real value into an integer with rounding.  (by Chris Roe) */
func round {
  para r;
  if (r-int(r)>=0.5) return int(r)+1;
  else return int(r);
}
