build: Don't include <config.h> in native programs when cross-compiling.
[bpt/guile.git] / libguile / memoize.c
index 2604be9..dfbeea7 100644 (file)
@@ -1,6 +1,7 @@
-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010
- * Free Software Foundation, Inc.
- * 
+/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+ *   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+ *   Free Software Foundation, Inc.
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
  * as published by the Free Software Foundation; either version 3 of
@@ -64,7 +65,8 @@ SCM_SYMBOL (sym_case_lambda_star, "case-lambda*");
 
 scm_t_bits scm_tc16_memoized;
 
-#define MAKMEMO(n, args)       (scm_cell (scm_tc16_memoized | ((n) << 16), (scm_t_bits)(args)))
+#define MAKMEMO(n, args)                                                \
+  (scm_cell (scm_tc16_memoized | ((n) << 16), SCM_UNPACK (args)))
 
 #define MAKMEMO_BEGIN(exps) \
   MAKMEMO (SCM_M_BEGIN, exps)
@@ -77,8 +79,9 @@ scm_t_bits scm_tc16_memoized;
 #define FULL_ARITY(nreq, rest, nopt, kw, inits, alt) \
   scm_list_n (SCM_I_MAKINUM (nreq), rest, SCM_I_MAKINUM (nopt), kw, inits, \
               alt, SCM_UNDEFINED)
-#define MAKMEMO_LAMBDA(body, arity) \
-  MAKMEMO (SCM_M_LAMBDA, (scm_cons (body, arity)))
+#define MAKMEMO_LAMBDA(body, arity, docstring)                 \
+  MAKMEMO (SCM_M_LAMBDA,                                       \
+          scm_cons (body, scm_cons (docstring, arity)))
 #define MAKMEMO_LET(inits, body) \
   MAKMEMO (SCM_M_LET, scm_cons (inits, body))
 #define MAKMEMO_QUOTE(exp) \
@@ -266,17 +269,50 @@ memoize (SCM exp, SCM env)
       return MAKMEMO_BEGIN (memoize_exps (REF (exp, SEQUENCE, EXPS), env));
 
     case SCM_EXPANDED_LAMBDA:
-      /* The body will be a lambda-case. */
-      return memoize (REF (exp, LAMBDA, BODY), env);
+      /* The body will be a lambda-case or #f. */
+      {
+       SCM meta, docstring, body, proc;
+
+       meta = REF (exp, LAMBDA, META);
+       docstring = scm_assoc_ref (meta, scm_sym_documentation);
+
+        body = REF (exp, LAMBDA, BODY);
+        if (scm_is_false (body))
+          /* Give a body to case-lambda with no clauses.  */
+          proc = MAKMEMO_LAMBDA
+            (MAKMEMO_CALL
+             (MAKMEMO_MOD_REF (list_of_guile,
+                               scm_from_latin1_symbol ("throw"),
+                               SCM_BOOL_F),
+              5,
+              scm_list_5 (MAKMEMO_QUOTE (scm_args_number_key),
+                          MAKMEMO_QUOTE (SCM_BOOL_F),
+                          MAKMEMO_QUOTE (scm_from_latin1_string
+                                         ("Wrong number of arguments")),
+                          MAKMEMO_QUOTE (SCM_EOL),
+                          MAKMEMO_QUOTE (SCM_BOOL_F))),
+             FIXED_ARITY (0),
+             SCM_BOOL_F /* docstring */);
+        else
+          proc = memoize (body, env);
+
+       if (scm_is_string (docstring))
+         {
+           SCM args = SCM_MEMOIZED_ARGS (proc);
+           SCM_SETCAR (SCM_CDR (args), docstring);
+         }
+
+       return proc;
+      }
 
     case SCM_EXPANDED_LAMBDA_CASE:
       {
         SCM req, rest, opt, kw, inits, vars, body, alt;
         SCM walk, minits, arity, new_env;
-        int nreq, nopt;
+        int nreq, nopt, ntotal;
 
         req = REF (exp, LAMBDA_CASE, REQ);
-        rest = REF (exp, LAMBDA_CASE, REST);
+        rest = scm_not (scm_not (REF (exp, LAMBDA_CASE, REST)));
         opt = REF (exp, LAMBDA_CASE, OPT);
         kw = REF (exp, LAMBDA_CASE, KW);
         inits = REF (exp, LAMBDA_CASE, INITS);
@@ -286,6 +322,7 @@ memoize (SCM exp, SCM env)
 
         nreq = scm_ilength (req);
         nopt = scm_is_pair (opt) ? scm_ilength (opt) : 0;
+        ntotal = scm_ilength (vars);
 
         /* The vars are the gensyms, according to the divine plan. But we need
            to memoize the inits within their appropriate environment,
@@ -319,6 +356,22 @@ memoize (SCM exp, SCM env)
 
         minits = scm_reverse_x (minits, SCM_UNDEFINED);
 
+        if (scm_is_true (kw))
+          {
+            /* (aok? (kw name sym) ...) -> (aok? (kw . index) ...) */
+            SCM aok = CAR (kw), indices = SCM_EOL;
+            for (kw = CDR (kw); scm_is_pair (kw); kw = CDR (kw))
+              {
+                SCM k;
+                int idx;
+
+                k = CAR (CAR (kw));
+                idx = ntotal - 1 - lookup (CADDR (CAR (kw)), new_env);
+                indices = scm_acons (k, SCM_I_MAKINUM (idx), indices);
+              }
+            kw = scm_cons (aok, scm_reverse_x (indices, SCM_UNDEFINED));
+          }
+
         if (scm_is_false (alt) && scm_is_false (kw) && scm_is_false (opt))
           {
             if (scm_is_false (rest))
@@ -332,7 +385,8 @@ memoize (SCM exp, SCM env)
         else
           arity = FULL_ARITY (nreq, rest, nopt, kw, minits, SCM_BOOL_F);
 
-        return MAKMEMO_LAMBDA (memoize (body, new_env), arity);
+        return MAKMEMO_LAMBDA (memoize (body, new_env), arity,
+                              SCM_BOOL_F /* docstring */);
       }
 
     case SCM_EXPANDED_LET:
@@ -357,33 +411,50 @@ memoize (SCM exp, SCM env)
 
     case SCM_EXPANDED_LETREC:
       {
-        SCM vars, exps, body, undefs, inits, sets, new_env;
-        int i, nvars;
+        SCM vars, exps, body, undefs, new_env;
+        int i, nvars, in_order_p;
         
-        vars = REF (exp, LET, GENSYMS);
-        exps = REF (exp, LET, VALS);
-        body = REF (exp, LET, BODY);
+        vars = REF (exp, LETREC, GENSYMS);
+        exps = REF (exp, LETREC, VALS);
+        body = REF (exp, LETREC, BODY);
+        in_order_p = scm_is_true (REF (exp, LETREC, IN_ORDER_P));
         nvars = i = scm_ilength (vars);
-        inits = undefs = sets = SCM_EOL;
+        undefs = SCM_EOL;
         new_env = env;
 
-        for (; scm_is_pair (vars); vars = CDR (vars), i--)
+        for (; scm_is_pair (vars); vars = CDR (vars))
           {
             new_env = scm_cons (CAR (vars), new_env);
             undefs = scm_cons (MAKMEMO_QUOTE (SCM_UNDEFINED), undefs);
-            sets = scm_cons (MAKMEMO_LEX_SET ((i-1) + nvars,
-                                              MAKMEMO_LEX_REF (i-1)),
-                             sets);
           }
 
-        for (; scm_is_pair (exps); exps = CDR (exps))
-          inits = scm_cons (memoize (CAR (exps), new_env), inits);
-        inits = scm_reverse_x (inits, SCM_UNDEFINED);
-
-        return MAKMEMO_LET
-          (undefs,
-           MAKMEMO_BEGIN (scm_list_2 (MAKMEMO_LET (inits, MAKMEMO_BEGIN (sets)),
-                                      memoize (body, new_env))));
+        if (in_order_p)
+          {
+            SCM body_exps = SCM_EOL;
+            for (; scm_is_pair (exps); exps = CDR (exps), i--)
+              body_exps = scm_cons (MAKMEMO_LEX_SET (i-1,
+                                                     memoize (CAR (exps), new_env)),
+                                    body_exps);
+            body_exps = scm_cons (memoize (body, new_env), body_exps);
+            body_exps = scm_reverse_x (body_exps, SCM_UNDEFINED);
+            return MAKMEMO_LET (undefs, MAKMEMO_BEGIN (body_exps));
+          }
+        else
+          {
+            SCM sets = SCM_EOL, inits = SCM_EOL;
+            for (; scm_is_pair (exps); exps = CDR (exps), i--)
+              {
+                sets = scm_cons (MAKMEMO_LEX_SET ((i-1) + nvars,
+                                                  MAKMEMO_LEX_REF (i-1)),
+                                 sets);
+                inits = scm_cons (memoize (CAR (exps), new_env), inits);
+              }
+            inits = scm_reverse_x (inits, SCM_UNDEFINED);
+            return MAKMEMO_LET
+              (undefs,
+               MAKMEMO_BEGIN (scm_list_2 (MAKMEMO_LET (inits, MAKMEMO_BEGIN (sets)),
+                                          memoize (body, new_env))));
+          }
       }
 
     case SCM_EXPANDED_DYNLET:
@@ -414,17 +485,23 @@ SCM_DEFINE (scm_memoize_expression, "memoize-expression", 1, 0, 0,
 
 #define SCM_MAKE_MEMOIZER(STR, MEMOIZER, N)                             \
   (scm_cell (scm_tc16_memoizer,                                         \
-             (scm_t_bits)(scm_c_make_gsubr (STR, N, 0, 0, MEMOIZER))))
+             SCM_UNPACK (scm_c_make_gsubr (STR, N, 0, 0, MEMOIZER))))
 #define SCM_DEFINE_MEMOIZER(STR, MEMOIZER, N)                           \
 SCM_SNARF_INIT(scm_c_define (STR, SCM_MAKE_MEMOIZER (STR, MEMOIZER, N)))
 
-static SCM m_apply (SCM proc, SCM args);
+#define SCM_MAKE_REST_MEMOIZER(STR, MEMOIZER, N)                        \
+  (scm_cell (scm_tc16_memoizer,                                         \
+             SCM_UNPACK ((scm_c_make_gsubr (STR, N, 0, 1, MEMOIZER)))))
+#define SCM_DEFINE_REST_MEMOIZER(STR, MEMOIZER, N)                      \
+SCM_SNARF_INIT(scm_c_define (STR, SCM_MAKE_REST_MEMOIZER (STR, MEMOIZER, N)))
+
+static SCM m_apply (SCM proc, SCM arg, SCM rest);
 static SCM m_call_cc (SCM proc);
 static SCM m_call_values (SCM prod, SCM cons);
 static SCM m_dynamic_wind (SCM pre, SCM exp, SCM post);
 static SCM m_prompt (SCM tag, SCM exp, SCM handler);
 
-SCM_DEFINE_MEMOIZER ("@apply", m_apply, 2);
+SCM_DEFINE_REST_MEMOIZER ("@apply", m_apply, 2);
 SCM_DEFINE_MEMOIZER ("@call-with-current-continuation", m_call_cc, 1);
 SCM_DEFINE_MEMOIZER ("@call-with-values", m_call_values, 2);
 SCM_DEFINE_MEMOIZER ("@dynamic-wind", m_dynamic_wind, 3);
@@ -433,12 +510,38 @@ SCM_DEFINE_MEMOIZER ("@prompt", m_prompt, 3);
 
 \f
 
-static SCM m_apply (SCM proc, SCM args)
+static SCM m_apply (SCM proc, SCM arg, SCM rest)
 #define FUNC_NAME "@apply"
 {
+  long len;
+  
   SCM_VALIDATE_MEMOIZED (1, proc);
-  SCM_VALIDATE_MEMOIZED (2, args);
-  return MAKMEMO_APPLY (proc, args);
+  SCM_VALIDATE_MEMOIZED (2, arg);
+  len = scm_ilength (rest);
+  if (len < 0)
+    abort ();
+  else if (len == 0)
+    return MAKMEMO_APPLY (proc, arg);
+  else
+    {
+      SCM tail;
+
+      rest = scm_reverse (rest);
+      tail = scm_car (rest);
+      rest = scm_cdr (rest);
+      len--;
+      
+      while (scm_is_pair (rest))
+        {
+          tail = MAKMEMO_CALL (MAKMEMO_MOD_REF (scm_list_1 (scm_from_latin1_symbol ("guile")),
+                                                scm_from_latin1_symbol ("cons"),
+                                                SCM_BOOL_F),
+                               2,
+                               scm_list_2 (scm_car (rest), tail));
+          rest = scm_cdr (rest);
+        }
+      return MAKMEMO_APPLY (proc, tail);
+    }
 }
 #undef FUNC_NAME
 
@@ -573,39 +676,43 @@ unmemoize (const SCM expr)
       return scm_list_4 (scm_sym_if, unmemoize (scm_car (args)),
                          unmemoize (scm_cadr (args)), unmemoize (scm_cddr (args)));
     case SCM_M_LAMBDA:
-      if (scm_is_null (CDDR (args)))
-        return scm_list_3 (scm_sym_lambda,
-                           scm_make_list (CADR (args), sym_placeholder),
-                           unmemoize (CAR (args)));
-      else if (scm_is_null (CDDDR (args)))
-        {
-          SCM formals = scm_make_list (CADR (args), sym_placeholder);
-          return scm_list_3 (scm_sym_lambda,
-                             scm_is_true (CADDR (args))
-                             ? scm_cons_star (sym_placeholder, formals)
-                             : formals,
-                             unmemoize (CAR (args)));
-        }
-      else
-        {
-          SCM body = CAR (args), spec = CDR (args), alt, tail;
-          
-          alt = CADDR (CDDDR (spec));
-          if (scm_is_true (alt))
-            tail = CDR (unmemoize (alt));
-          else
-            tail = SCM_EOL;
-          
-          return scm_cons
-            (sym_case_lambda_star,
-             scm_cons (scm_list_2 (scm_list_5 (CAR (spec),
-                                               CADR (spec),
-                                               CADDR (spec),
-                                               CADDDR (spec),
-                                               unmemoize_exprs (CADR (CDDDR (spec)))),
-                                   unmemoize (body)),
-                       tail));
-        }
+      {
+       SCM body = CAR (args), spec = CDDR (args);
+
+       if (scm_is_null (CDR (spec)))
+         return scm_list_3 (scm_sym_lambda,
+                            scm_make_list (CAR (spec), sym_placeholder),
+                            unmemoize (CAR (args)));
+       else if (scm_is_null (SCM_CDDR (spec)))
+         {
+           SCM formals = scm_make_list (CAR (spec), sym_placeholder);
+           return scm_list_3 (scm_sym_lambda,
+                              scm_is_true (CADR (spec))
+                              ? scm_cons_star (sym_placeholder, formals)
+                              : formals,
+                              unmemoize (CAR (args)));
+         }
+       else
+         {
+           SCM alt, tail;
+
+           alt = CADDR (CDDDR (spec));
+           if (scm_is_true (alt))
+             tail = CDR (unmemoize (alt));
+           else
+             tail = SCM_EOL;
+
+           return scm_cons
+             (sym_case_lambda_star,
+              scm_cons (scm_list_2 (scm_list_5 (CAR (spec),
+                                                CADR (spec),
+                                                CADDR (spec),
+                                                CADDDR (spec),
+                                                unmemoize_exprs (CADR (CDDDR (spec)))),
+                                    unmemoize (body)),
+                        tail));
+         }
+      }
     case SCM_M_LET:
       return scm_list_3 (scm_sym_let,
                          unmemoize_bindings (CAR (args)),
@@ -795,14 +902,13 @@ void
 scm_init_memoize ()
 {
   scm_tc16_memoized = scm_make_smob_type ("%memoized", 0);
-  scm_set_smob_mark (scm_tc16_memoized, scm_markcdr);
   scm_set_smob_print (scm_tc16_memoized, scm_print_memoized);
 
   scm_tc16_memoizer = scm_make_smob_type ("memoizer", 0);
 
 #include "libguile/memoize.x"
 
-  list_of_guile = scm_list_1 (scm_from_locale_symbol ("guile"));
+  list_of_guile = scm_list_1 (scm_from_latin1_symbol ("guile"));
 }
 
 /*