/// <summary> /// Post a commute on a ref in this transaction. /// </summary> /// <param name="r">The ref.</param> /// <param name="fn">The commuting function.</param> /// <param name="args">Additional arguments to the function.</param> /// <returns>The computed value.</returns> internal object DoCommute(Ref r, IFn fn, ISeq args) { if (!_info.IsRunning) { throw _retryex; } if (!_vals.ContainsKey(r)) { object val = null; try { r.EnterReadLock(); val = r.TryGetVal(); } finally { r.ExitReadLock(); } _vals[r] = val; } List <CFn> fns; if (!_commutes.TryGetValue(r, out fns)) { _commutes[r] = fns = new List <CFn>(); } fns.Add(new CFn(fn, args)); object ret = fn.applyTo(RT.cons(_vals[r], args)); _vals[r] = ret; return(ret); }
static ISeq push(Node t, ISeq stack, bool asc) { while (t != null) { stack = RT.cons(t, stack); t = asc ? t.Left : t.Right; } return(stack); }
public object alterRoot(IFn fn, ISeq args) { object newRoot = fn.applyTo(RT.cons(_root, args)); Validate(getValidator(), newRoot); object oldroot = getRoot(); _root = newRoot; notifyWatches(oldroot, newRoot); return(newRoot); }
/// <summary> /// Worker method to execute the action on a thread. /// </summary> /// <param name="state">(not used)</param> /// <remarks>corresponds to doRun in Java version</remarks> void ExecuteAction(object state) { try { Var.pushThreadBindings(RT.map(RT.AGENT, _agent)); Agent.Nested = PersistentVector.EMPTY; bool hadError = false; try { object oldval = _agent.State; object newval = _fn.applyTo(RT.cons(_agent.State, _args)); _agent.SetState(newval); _agent.notifyWatches(oldval, newval); } catch (Exception e) { // TODO: report/callback (Java TODO) _agent.AddError(e); hadError = true; } if (!hadError) { releasePendingSends(); } bool popped = false; IPersistentStack next = null; while (!popped) { IPersistentStack prior = _agent._q.Get(); next = prior.pop(); popped = _agent._q.CompareAndSet(prior, next); } if (next.count() > 0) { ((Action)next.peek()).execute(); } } finally { Nested = null; Var.popThreadBindings(); } }
/// <summary> /// Returns an <see cref="ISeq">ISeq</see> to iterate through the collection in the designated direction starting from a particular key. /// </summary> /// <param name="key">The key at which to start the iteration.</param> /// <param name="ascending">A flag indicating if the iteration is ascending or descending.</param> /// <returns>A sequence for first/rest iteration.</returns> /// <remarks>The key need not be in the collection. If not present, the iteration will start with /// the first element with a key greater than (if asscending) or less than (if descending) the given key.</remarks> public ISeq seqFrom(object key, bool ascending) { if (_count > 0) { ISeq stack = null; Node t = _tree; while (t != null) { int c = DoCompare(key, t.Key); if (c == 0) { stack = RT.cons(t, stack); return(new Seq(stack, ascending)); } else if (ascending) { if (c < 0) { stack = RT.cons(t, stack); t = t.Left; } else { t = t.Right; } } else { if (c > 0) { stack = RT.cons(t, stack); t = t.Right; } else { t = t.Left; } } } if (stack != null) { return(new Seq(stack, ascending)); } } return(null); }
public void step(LazyTransformer lt) { while (lt._stepper != null && MoveNext()) { if (RT.isReduced(_xform.applyTo(RT.cons(lt, Current())))) { if (lt._rest != null) { lt._rest._stepper = null; } break; } } if (lt._stepper != null) { _xform.invoke(lt); } }
private bool Step() { _next = NONE; while (_next == NONE) { if (_buffer.IsEmpty()) { if (_completed) { return(false); } else if (_sourceEnum.MoveNext()) { object iter; if (_multi) { iter = _xf.applyTo(RT.cons(null, _sourceEnum.Current)); } else { iter = _xf.invoke(null, _sourceEnum.Current); } if (RT.isReduced(iter)) { _xf.invoke(null); _completed = true; } } else { _xf.invoke(null); _completed = true; } } else { _next = _buffer.Remove(); } } return(true); }
public void step(LazyTransformer lt) { while (lt._stepper != null && MoveNext()) { if (RT.isReduced(_xform.applyTo(RT.cons(lt, Current())))) { lt._stepper = null; LazyTransformer et = lt; while (et._rest != null) { et = et._rest; et._stepper = null; } _xform.invoke(et); return; } } if (lt._stepper != null) { _xform.invoke(lt); } }
/// <summary> /// Start a transaction and invoke a function. /// </summary> /// <param name="fn">The function to invoke.</param> /// <returns>The value computed by the function.</returns> object Run(IFn fn) { // TODO: Define an overload called on ThreadStartDelegate or something equivalent. bool done = false; object ret = null; List <Ref> locked = new List <Ref>(); List <Notify> notify = new List <Notify>(); for (int i = 0; !done && i < RetryLimit; i++) { try { GetReadPoint(); if (i == 0) { _startPoint = _readPoint; _startTime = Environment.TickCount; } _info = new Info(RUNNING, _startPoint); ret = fn.invoke(); // make sure no one has killed us before this point, // and can't from now on if (_info.Status.compareAndSet(RUNNING, COMMITTING)) { foreach (KeyValuePair <Ref, List <CFn> > pair in _commutes) { Ref r = pair.Key; if (_sets.Contains(r)) { continue; } bool wasEnsured = _ensures.Contains(r); // can't upgrade read lock, so release ReleaseIfEnsured(r); TryWriteLock(r); locked.Add(r); if (wasEnsured && r.CurrentValPoint() > _readPoint) { throw _retryex; } Info refinfo = r.TInfo; if (refinfo != null && refinfo != _info && refinfo.IsRunning) { if (!Barge(refinfo)) { throw _retryex; } } object val = r.TryGetVal(); _vals[r] = val; foreach (CFn f in pair.Value) { _vals[r] = f.Fn.applyTo(RT.cons(_vals[r], f.Args)); } } foreach (Ref r in _sets) { TryWriteLock(r); locked.Add(r); } // validate and enqueue notifications foreach (KeyValuePair <Ref, object> pair in _vals) { Ref r = pair.Key; r.Validate(pair.Value); } // at this point, all values calced, all refs to be written locked // no more client code to be called int msecs = System.Environment.TickCount; long commitPoint = GetCommitPoint(); foreach (KeyValuePair <Ref, object> pair in _vals) { Ref r = pair.Key; object oldval = r.TryGetVal(); object newval = pair.Value; r.SetValue(newval, commitPoint, msecs); if (r.getWatches().count() > 0) { notify.Add(new Notify(r, oldval, newval)); } } done = true; _info.Status.set(COMMITTED); } } catch (RetryEx) { // eat this so we retry rather than fall out } catch (Exception ex) { if (ContainsNestedRetryEx(ex)) { // Wrapped exception, eat it. } else { throw; } } finally { for (int k = locked.Count - 1; k >= 0; --k) { locked[k].ExitWriteLock(); } locked.Clear(); foreach (Ref r in _ensures) { r.ExitReadLock(); } _ensures.Clear(); Stop(done ? COMMITTED : RETRY); try { if (done) // re-dispatch out of transaction { foreach (Notify n in notify) { n._ref.NotifyWatches(n._oldval, n._newval); } foreach (Agent.Action action in _actions) { Agent.DispatchAction(action); } } } finally { notify.Clear(); _actions.Clear(); } } } if (!done) { throw new InvalidOperationException("Transaction failed after reaching retry limit"); } return(ret); }
public static Expr Parse(ParserContext pcon, ISeq form, string name) { ISeq origForm = form; FnExpr fn = new FnExpr(Compiler.TagOf(form)); fn._src = form; if (((IMeta)form.first()).meta() != null) { fn._onceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), KW_ONCE)); } fn.ComputeNames(form, name); List <string> prims = new List <string>(); //arglist might be preceded by symbol naming this fn if (RT.second(form) is Symbol) { Symbol nm = (Symbol)RT.second(form); fn._thisName = nm.Name; fn._isStatic = false; // RT.booleanCast(RT.get(nm.meta(), Compiler.STATIC_KEY)); form = RT.cons(Compiler.FnSym, RT.next(RT.next(form))); } // Normalize body //now (fn [args] body...) or (fn ([args] body...) ([args2] body2...) ...) //turn former into latter if (RT.second(form) is IPersistentVector) { form = RT.list(Compiler.FnSym, RT.next(form)); } fn.SpanMap = (IPersistentMap)Compiler.SourceSpanVar.deref(); GenContext newContext = null; GenContext context = Compiler.CompilerContextVar.deref() as GenContext ?? Compiler.EvalContext; newContext = context.WithNewDynInitHelper(fn.InternalName + "__dynInitHelper_" + RT.nextID().ToString()); Var.pushThreadBindings(RT.map(Compiler.CompilerContextVar, newContext)); try { try { Var.pushThreadBindings(RT.mapUniqueKeys( Compiler.ConstantsVar, PersistentVector.EMPTY, Compiler.ConstantIdsVar, new IdentityHashMap(), Compiler.KeywordsVar, PersistentHashMap.EMPTY, Compiler.VarsVar, PersistentHashMap.EMPTY, Compiler.KeywordCallsitesVar, PersistentVector.EMPTY, Compiler.ProtocolCallsitesVar, PersistentVector.EMPTY, Compiler.VarCallsitesVar, Compiler.EmptyVarCallSites(), Compiler.NoRecurVar, null)); SortedDictionary <int, FnMethod> methods = new SortedDictionary <int, FnMethod>(); FnMethod variadicMethod = null; for (ISeq s = RT.next(form); s != null; s = RT.next(s)) { FnMethod f = FnMethod.Parse(fn, (ISeq)RT.first(s), fn._isStatic); if (f.IsVariadic) { if (variadicMethod == null) { variadicMethod = f; } else { throw new ParseException("Can't have more than 1 variadic overload"); } } else if (!methods.ContainsKey(f.RequiredArity)) { methods[f.RequiredArity] = f; } else { throw new ParseException("Can't have 2 overloads with the same arity."); } if (f.Prim != null) { prims.Add(f.Prim); } } if (variadicMethod != null && methods.Count > 0 && methods.Keys.Max() >= variadicMethod.NumParams) { throw new ParseException("Can't have fixed arity methods with more params than the variadic method."); } if (fn._isStatic && fn.Closes.count() > 0) { throw new ParseException("static fns can't be closures"); } IPersistentCollection allMethods = null; foreach (FnMethod method in methods.Values) { allMethods = RT.conj(allMethods, method); } if (variadicMethod != null) { allMethods = RT.conj(allMethods, variadicMethod); } fn._methods = allMethods; fn._variadicMethod = variadicMethod; fn.Keywords = (IPersistentMap)Compiler.KeywordsVar.deref(); fn.Vars = (IPersistentMap)Compiler.VarsVar.deref(); fn.Constants = (PersistentVector)Compiler.ConstantsVar.deref(); fn.KeywordCallsites = (IPersistentVector)Compiler.KeywordCallsitesVar.deref(); fn.ProtocolCallsites = (IPersistentVector)Compiler.ProtocolCallsitesVar.deref(); fn.VarCallsites = (IPersistentSet)Compiler.VarCallsitesVar.deref(); fn._constantsID = RT.nextID(); } finally { Var.popThreadBindings(); } IPersistentMap fmeta = RT.meta(origForm); if (fmeta != null) { fmeta = fmeta.without(RT.LineKey).without(RT.ColumnKey).without(RT.SourceSpanKey).without(RT.FileKey); } fn._hasMeta = RT.count(fmeta) > 0; IPersistentVector primTypes = PersistentVector.EMPTY; foreach (string typename in prims) { primTypes = primTypes.cons(Type.GetType(typename)); } fn.Compile( fn.IsVariadic ? typeof(RestFn) : typeof(AFunction), null, primTypes, fn._onceOnly, newContext); if (fn.SupportsMeta) { return(new MetaExpr(fn, MapExpr.Parse(pcon.EvalOrExpr(), fmeta))); } else { return(fn); } } finally { if (newContext != null) { Var.popThreadBindings(); } } }
static object syntaxQuote(object form) { object ret; if (Compiler.isSpecial(form)) { ret = RT.list(Compiler.QUOTE, form); } else if (form is Symbol) { Symbol sym = (Symbol)form; if (sym.Namespace == null && sym.Name.EndsWith("#")) { IPersistentMap gmap = (IPersistentMap)GENSYM_ENV.deref(); if (gmap == null) { throw new InvalidDataException("Gensym literal not in syntax-quote"); } Symbol gs = (Symbol)gmap.valAt(sym); if (gs == null) { GENSYM_ENV.set(gmap.assoc(sym, gs = Symbol.intern(null, sym.Name.Substring(0, sym.Name.Length - 1) + "__" + RT.nextID() + "__auto__"))); } sym = gs; } else if (sym.Namespace == null && sym.Name.EndsWith(".")) { Symbol csym = Symbol.intern(null, sym.Name.Substring(0, sym.Name.Length - 1)); csym = Compiler.resolveSymbol(csym); sym = Symbol.intern(null, csym.Name + "."); } else if (sym.Namespace == null && sym.Name.StartsWith(".")) { // simply quote method names } else { sym = Compiler.resolveSymbol(sym); } ret = RT.list(Compiler.QUOTE, sym); } //else if (form is Unquote) // return ((Unquote)form).Obj; // Rev 1184 else if (isUnquote(form)) { return(RT.second(form)); } else if (isUnquoteSplicing(form)) { throw new ArgumentException("splice not in list"); } else if (form is IPersistentCollection) { if (form is IPersistentMap) { IPersistentVector keyvals = flattenMap(form); ret = RT.list(APPLY, HASHMAP, RT.list(SEQ, RT.cons(CONCAT, sqExpandList(keyvals.seq())))); } else if (form is IPersistentVector) { ret = RT.list(APPLY, VECTOR, RT.list(SEQ, RT.cons(CONCAT, sqExpandList(((IPersistentVector)form).seq())))); } else if (form is IPersistentSet) { ret = RT.list(APPLY, HASHSET, RT.list(SEQ, RT.cons(CONCAT, sqExpandList(((IPersistentSet)form).seq())))); } else if (form is ISeq || form is IPersistentList) { ISeq seq = RT.seq(form); if (seq == null) { ret = RT.cons(LIST, null); } else { ret = RT.list(SEQ, RT.cons(CONCAT, sqExpandList(seq))); } } else { throw new InvalidOperationException("Unknown Collection type"); } } else if (form is Keyword || Util.IsNumeric(form) || form is Char || form is String) { ret = form; } else { ret = RT.list(Compiler.QUOTE, form); } if (form is IObj && RT.meta(form) != null) { //filter line numbers IPersistentMap newMeta = ((IObj)form).meta().without(RT.LINE_KEY); if (newMeta.count() > 0) { return(RT.list(WITH_META, ret, syntaxQuote(((IObj)form).meta()))); } } return(ret); }
public object alter(IFn fn, ISeq args) { LockingTransaction t = LockingTransaction.GetEx(); return(t.DoSet(this, fn.applyTo(RT.cons(t.DoGet(this), args)))); }
/// <summary> /// Add an error. /// </summary> /// <param name="e">The exception to add.</param> public void AddError(Exception e) { _errors = RT.cons(e, _errors); }
public ISeq nodeSeq() { return((ISeq)RT.cons(this, null)); }
void ExecuteAction(object state) { try { Agent.Nested = PersistentVector.EMPTY; Exception error = null; try { object oldval = _agent.State; object newval = _fn.applyTo(RT.cons(_agent.State, _args)); _agent.SetState(newval); _agent.NotifyWatches(oldval, newval); } catch (Exception e) { error = e; } if (error == null) { releasePendingSends(); } else { Nested = null; // allow errorHandler to send if (_agent._errorHandler != null) { try { _agent._errorHandler.invoke(_agent, error); } catch (Exception) { // ignore error handler errors } } if (_agent._errorMode == ContinueKeyword) { error = null; } } bool popped = false; ActionQueue next = null; while (!popped) { ActionQueue prior = _agent._aq.Get(); next = new ActionQueue(prior._q.pop(), error); popped = _agent._aq.CompareAndSet(prior, next); } if (error == null && next._q.count() > 0) { ((Action)next._q.peek()).execute(); } } finally { Nested = null; } }
public object alter(IFn fn, ISeq args) { set(fn.applyTo(RT.cons(deref(), args))); return(this); }
public ISeq cons(object o) { return(RT.cons(o, seq())); }
public static Expr Parse(object frm, string name) { ISeq form = (ISeq)frm; FnExpr fn = new FnExpr(Compiler.TagOf(form)); if (((IMeta)form.first()).meta() != null) { fn._onceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), KW_ONCE)); fn._superName = (string)RT.get(RT.meta(form.first()), KW_SUPER_NAME); } fn.ComputeNames(form, name); try { Var.pushThreadBindings(RT.map( Compiler.CONSTANTS, PersistentVector.EMPTY, Compiler.KEYWORDS, PersistentHashMap.EMPTY, Compiler.VARS, PersistentHashMap.EMPTY)); //arglist might be preceded by symbol naming this fn if (RT.second(form) is Symbol) { fn._thisName = ((Symbol)RT.second(form)).Name; form = RT.cons(Compiler.FN, RT.next(RT.next(form))); } // Normalize body // If it is (fn [arg...] body ...), turn it into // (fn ([arg...] body...)) // so that we can treat uniformly as (fn ([arg...] body...) ([arg...] body...) ... ) if (RT.second(form) is IPersistentVector) { form = RT.list(Compiler.FN, RT.next(form)); } FnMethod variadicMethod = null; SortedDictionary <int, FnMethod> methods = new SortedDictionary <int, FnMethod>(); for (ISeq s = RT.next(form); s != null; s = RT.next(s)) { FnMethod f = FnMethod.Parse(fn, (ISeq)RT.first(s)); if (f.IsVariadic) { if (variadicMethod == null) { variadicMethod = f; } else { throw new Exception("Can't have more than 1 variadic overload"); } } else if (!methods.ContainsKey(f.RequiredArity)) { methods[f.RequiredArity] = f; } else { throw new Exception("Can't have 2 overloads with the same arity."); } } if (variadicMethod != null && methods.Count > 0 && methods.Keys.Max() >= variadicMethod.NumParams) { throw new Exception("Can't have fixed arity methods with more params than the variadic method."); } IPersistentCollection allMethods = null; foreach (FnMethod method in methods.Values) { allMethods = RT.conj(allMethods, method); } if (variadicMethod != null) { allMethods = RT.conj(allMethods, variadicMethod); } fn._methods = allMethods; fn._variadicMethod = variadicMethod; fn._keywords = (IPersistentMap)Compiler.KEYWORDS.deref(); fn._vars = (IPersistentMap)Compiler.VARS.deref(); fn._constants = (PersistentVector)Compiler.CONSTANTS.deref(); fn._constantsID = RT.nextID(); } finally { Var.popThreadBindings(); } // JAVA: fn.compile(); return(fn); }