/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-â
âvi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viâ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ¡
â Copyright 2022 Justine Alexandra Roberts Tunney                              â
â                                                                              â
â Copying of this file is authorized only if (1) you are Justine Tunney, or    â
â (2) you make absolutely no changes to your copy.                             â
â                                                                              â
â THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES     â
â WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF             â
â MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR      â
â ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES       â
â WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN        â
â ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF      â
â OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.               â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ*/
#include "libc/log/check.h"
#include "tool/plinko/lib/cons.h"
#include "tool/plinko/lib/gc.h"
#include "tool/plinko/lib/index.h"
#include "tool/plinko/lib/plinko.h"
#include "tool/plinko/lib/print.h"
#include "tool/plinko/lib/printf.h"
#include "tool/plinko/lib/tree.h"

void GetName(int *x) {
  int t;
  if (*x < 0) {
    if ((t = GetTree(*x, revglob))) {
      *x = Val(Ent(t));
    }
  }
}

int Define(int e, int a) {
  struct Gc *G;
  int k, v, x, r, o;
  DCHECK_EQ(kDefine, Car(e));
  if (Cdr(e) >= 0) Error("bad define: %S", e);
  if (Cadr(e) <= 0) Error("scheme define: %S", e);
  if (Cddr(e) >= 0 || Caddr(e) == kLambda) {
    /*
     * compatibility with sectorlisp friendly branch, e.g.
     *
     *   (DEFINE ð . ð£)
     *   (DEFINE ð . (LAMBDA â¯))
     *
     * are equivalent to the following
     *
     *   (DEFINE ð (QUOTE ð£))
     *   (DEFINE ð (QUOTE (LAMBDA â¯)))
     */
    e = Cdr(e);
    k = Car(e);
  } else if (!Cdddr(e)) {
    k = Cadr(e);
    v = Caddr(e);
    x = eval(v, a);
    e = Cons(k, x);
  } else {
    Error("too many args: %S", e);
  }
  a = Cons(PutTree(e, Car(a), 0), 0);
  r = PutTree(Cons(Cdr(e), Car(e)), revglob, 0);
  o = Cons(k, ordglob);
  G = NewGc(cFrost);
  Mark(G, a);
  Mark(G, r);
  Mark(G, o);
  Census(G);
  a = Relocate(G, a);
  r = Relocate(G, r);
  o = Relocate(G, o);
  Sweep(G);
  revglob = r;
  ordglob = o;
  return a;
}

/**
 * Prints stuff declared by Define().
 *
 * The output is primarily intended for describing the internal machine
 * state, with a focus on readability. If closures are printed, with -c
 * then each nugget can be copied back into the machine on its own, b/c
 * each definition is a transitive closure that totally defines all its
 * dependencies. However it's quite verbose, so the normal mode is just
 * readable and can be finessed back into a good program with some work
 * although one thing that's really cool is it peels away macros in the
 * hope it can help demystify amazingly dense recreational abstractions
 *
 * @param t is symbol to use for DEFINE
 * @param a is an association list and/or red-black tree
 * @param o is ordering of names
 * @see Assoc() for documentation on structure of ð
 */
int DumpDefines(int t, int a, int o) {
  int e;
  bool nn;
  nn = noname;
  noname = true;
  for (; o; o = Cdr(o)) {
    e = Assoc(Car(o), a);
    Printf("%n%p%n", Cons(t, Cons(Car(e), Cons(Cdr(e), -0))));
  }
  noname = nn;
  return 0;
}
