Commits

Armin Rigo  committed 6445e33 Merge

merge the non-STM transaction module to 'base'

  • Participants
  • Parent commits c1edea6, 5564627
  • Branches base

Comments (0)

Files changed (8)

File consobject.c

 
 DuObject *cons_eval(DuConsObject *ob, DuObject *locals)
 {
-    return _DuFrame_EvalCall(locals, ob->car, ob->cdr);
+    return _DuFrame_EvalCall(locals, ob->car, ob->cdr, 1);
 }
 
 DuTypeObject DuCons_Type = {

File demo/simple_transaction.duh

+
+
+(defun do_stuff (i)
+  (if (> (* i i) 10)
+    (print i)))
+
+(setq i 0)
+(while (< i 10)
+  (transaction do_stuff i)
+  (setq i (+ i 1)))
         }
         Du_DECREF(res);
         Du_DECREF(code);
+        Du_TransactionRun();
         if (!interactive)
             break;
     }
 DuObject *Du_Eval(DuObject *ob, DuObject *locals);
 DuObject *Du_Progn(DuObject *cons, DuObject *locals);
 
-DuObject *DuFrame_New(void);
+DuObject *DuFrame_New(DuObject *code);
+DuObject *DuFrame_Execute(DuObject *frame);
 DuObject *DuFrame_GetSymbol(DuObject *frame, DuObject *symbol);
 void DuFrame_SetSymbol(DuObject *frame, DuObject *symbol, DuObject *value);
 void DuFrame_SetSymbolStr(DuObject *frame, char *name, DuObject *value);
 void DuFrame_SetBuiltinMacro(DuObject *frame, char *name, eval_fn func);
 void DuFrame_SetUserFunction(DuObject *frame, DuObject *symbol,
                              DuObject *arglist, DuObject *progn);
-DuObject *_DuFrame_EvalCall(DuObject *frame, DuObject *symbol, DuObject *rest);
+DuObject *_DuFrame_EvalCall(DuObject *frame, DuObject *symbol,
+                            DuObject *rest, int execute_now);
 
 void Du_Initialize(void);
 void Du_Finalize(void);
 extern DuObject *Du_Globals;
+
+void Du_TransactionAdd(DuObject *frame);
+void Du_TransactionRun(void);
 
 typedef struct {
     DuOBJECT_HEAD
+    DuObject *f_code;
     int entry_count;
     struct dictentry *entries;
 } DuFrameObject;
 
-DuObject *DuFrame_New()
+DuObject *DuFrame_New(DuObject *code)
 {
     DuFrameObject *ob = (DuFrameObject *)DuObject_New(&DuFrame_Type);
+    ob->f_code = code; Du_INCREF(code);
     ob->entry_count = 0;
     ob->entries = NULL;
     return (DuObject *)ob;
         if (e->func_progn   != NULL) Du_DECREF(e->func_progn  );
     }
     free(ob->entries);
+    Du_DECREF(ob->f_code);
     free(ob);
 }
 
                       DuSymbol_AsString(symbol));
 }
 
-DuObject *_DuFrame_EvalCall(DuObject *frame, DuObject *symbol, DuObject *rest)
+DuObject *DuFrame_Execute(DuObject *frame)
+{
+    DuFrame_Ensure("DuFrame_Execute", frame);
+    DuObject* code = ((DuFrameObject *)frame)->f_code;
+    return Du_Progn(code, frame);
+}
+
+DuObject *_DuFrame_EvalCall(DuObject *frame, DuObject *symbol,
+                            DuObject *rest, int execute_now)
 {
     struct dictentry *e;
     DuFrame_Ensure("_DuFrame_EvalCall", frame);
         }
     }
     if (e->func_progn) {
-        DuObject *callee_frame = DuFrame_New();
+        DuObject *callee_frame = DuFrame_New(e->func_progn);
         _parse_arguments(symbol, rest, e->func_arglist, frame, callee_frame);
-        DuObject *res = Du_Progn(e->func_progn, callee_frame);
-        Du_DECREF(callee_frame);
-        return res;
+        if (execute_now) {
+            DuObject *res = Du_Progn(e->func_progn, callee_frame);
+            Du_DECREF(callee_frame);
+            return res;
+        }
+        else
+            return callee_frame;
     }
     if (e->builtin_macro) {
+        if (!execute_now)
+            Du_FatalError("symbol refers to a macro: '%s'",
+                          DuSymbol_AsString(symbol));
         return e->builtin_macro(rest, frame);
     }
  not_defined:
     return DuInt_FromInt(res);
 }
 
+DuObject *du_transaction(DuObject *cons, DuObject *locals)
+{
+    if (cons == Du_None)
+        Du_FatalError("transaction: expected at least one argument");
+    DuObject *sym = _DuCons_CAR(cons);
+    DuObject *rest = _DuCons_NEXT(cons);
+    DuObject *frame = _DuFrame_EvalCall(locals, sym, rest, 0);
+    Du_TransactionAdd(frame);
+    Du_DECREF(frame);
+    Du_INCREF(Du_None);
+    return Du_None;
+}
+
 
 DuObject *Du_Globals;
 
     chainedlist.ob_debug_next = &chainedlist;
 #endif
 
-    Du_Globals = DuFrame_New();
+    Du_Globals = DuFrame_New(Du_None);
     DuFrame_SetBuiltinMacro(Du_Globals, "progn", Du_Progn);
     DuFrame_SetBuiltinMacro(Du_Globals, "setq", du_setq);
     DuFrame_SetBuiltinMacro(Du_Globals, "print", du_print);
     DuFrame_SetBuiltinMacro(Du_Globals, "car", du_car);
     DuFrame_SetBuiltinMacro(Du_Globals, "cdr", du_cdr);
     DuFrame_SetBuiltinMacro(Du_Globals, "not", du_not);
+    DuFrame_SetBuiltinMacro(Du_Globals, "transaction", du_transaction);
     DuFrame_SetSymbolStr(Du_Globals, "None", Du_None);
 }
 

File test/test_transaction.py

+from support import run
+
+
+def test_simple():
+    assert run("(defun f (n) (print n)) "
+               "(transaction f (+ 40 2)) "
+               "(print (quote hello))") == "'hello'\n42\n"
+    assert run("(defun f(x) (if (< x 20) (transaction f (+ x 1)) (print x))) "
+               "(print (f 0))") == "None\n20\n"

File transaction.c

+#include "duhton.h"
+
+
+static DuObject *list_transactions = NULL;
+
+void Du_TransactionAdd(DuObject *frame)
+{
+    if (list_transactions == NULL) {
+        list_transactions = DuList_New();
+        _Du_ForgetReference(list_transactions);
+    }
+    DuList_Append(list_transactions, frame);
+}
+
+void Du_TransactionRun(void)
+{
+    if (list_transactions == NULL)
+        return;
+    while (DuList_Size(list_transactions) > 0) {
+        DuObject *frame = DuList_Pop(list_transactions, 0);
+        DuObject *res = DuFrame_Execute(frame);
+        Du_DECREF(res);
+        Du_DECREF(frame);
+    }
+}