<commit_before>/**
  This is a primitive asynchronous class, used as a base class for Promise and
  Signal.
 **/


package promhx.base;

#if macro
import haxe.macro.Expr;
import haxe.macro.Type;
import haxe.macro.Context;
#end
import promhx.base.EventLoop;
import promhx.Thenable;

typedef AsyncLink<T> = {
    async : AsyncBase<Dynamic>,
    linkf : T->Void
}


class AsyncBase<T>{
#if debug
    // add ids to the async instances so they are easier to track
    static var id_ctr  = 0;
    var id          : Int;
#end
    var _val        : T;
    var _resolved   : Bool;
    var _fulfilled  : Bool;
    var _pending    : Bool;
    var _update     : Array<AsyncLink<T>>;
    var _error      : Array<Dynamic->Void>;
    var _errorMap   : Dynamic->T;

    /**
      Constructor argument can take optional function argument, which adds
      a callback to the error handler chain.
     **/
    public function new(?d:Deferred<T>) {
#if debug id = id_ctr +=1; #end
        if (d != null){ 
            d.then(handleResolve, handleError ); 
        }

        _resolved   = false;
        _pending = false;
        _fulfilled  = false;
        _update     = [];
        _error      = [];

    }

    /**
      Catch error, effectively halting the current update chain.
      This will prevent downstream async objects from receiving 
      the error message.
     **/
    public function catchError(f : Dynamic->Void) : AsyncBase<T> {
        _error.push(f);
        return this;
    }

    /**
      Map errors back to the expected type, and continue as normal.
     **/
    public function errorThen( f : Dynamic -> T){
        _errorMap = f;
        return this;
    }

    /**
      Utility function to determine if a Promise value has been resolved.
     **/
    public inline function isResolved() : Bool
        return _resolved;


    /**
      Utility function to determine if a Promise value has been rejected.
     **/
    public inline function isFulfilled(): Bool
        return _fulfilled;

    /**
      Utility function to determine if a Promise value is pending operations
      on the next loop.
     **/
    public inline function isPending() : Bool
        return _pending;


    function handleResolve(val:T) : Void {
        _resolve(val);
    }
    /**
      Resolves the given value for processing on any waiting functions.
     **/
    function _resolve(val : T) : Void {

        // this async is pending an update on the next loop, move the
        // resolve to the loop after that.
        if (_pending){
            EventLoop.enqueue(_resolve.bind(val));
        } else {

            // point of no return, this async has now been resolved at least once.
            _resolved = true;

            // we are now in the act of fulfilling the async... which
            // involves waiting for the next enqueued loop
            _pending = true;

            // the loop handler, which may not even be used
            EventLoop.enqueue(function(){
                _val = val; // save the value
                for (up in _update){
#if PromhxExposeErrors
                    up.linkf(val);
#else
                    try up.linkf(val)
                catch (e:Dynamic) up.async.handleError(e);
#end
                }
                _fulfilled = true; // we're in a fulfilled state
                _pending = false; // we're done fulfilling for this resolve
            });
        }

    }

    /**
      Handle errors
     **/
    function handleError(error : Dynamic) : Void {
        var update_errors = function(e:Dynamic){
            if (_error.length > 0) for (ef in _error) ef(e);
            else if (_update.length > 0) for (up in _update) up.async.handleError(e);
            else {
#if (js && nodejs)
                // Node sometimes doesn't produce helpful stack information on thrown errors.
                trace('Call Stack: ' + haxe.CallStack.toString(haxe.CallStack.callStack()));
#end
                throw e;
            }
        }
        EventLoop.enqueue(function(){
            if (_errorMap != null){
#if PromhxExposeErrors
                this._resolve(_errorMap(error));
            resolve(_errorMap(error));
#else
                try this._resolve(_errorMap(error))
                catch (e : Dynamic) update_errors(e);
#end
            } else {
                update_errors(error);
            }
        });
    }

    /**
      This function returns a new AsyncBase.  When this instance resolves,
      it will resolve the new AsyncBase with the function callback argument.
     **/
    public function then<A>(f : T->A) : AsyncBase<A> {
        var ret = new AsyncBase<A>();
        link(this, ret, f);
        return ret;
    }

    /**
      Remove an Async that is updated from this Async.  This action is
      performed on the next event loop.
     **/
    public function unlink( to : AsyncBase<Dynamic>) {
        EventLoop.enqueue(function(){
            _update =  _update.filter(function(x) return x.async != to);
        });
    }<commit_msg>fix issue #33 with -D PromhxExposeErrors<commit_after>/**
  This is a primitive asynchronous class, used as a base class for Promise and
  Signal.
 **/


package promhx.base;

#if macro
import haxe.macro.Expr;
import haxe.macro.Type;
import haxe.macro.Context;
#end
import promhx.base.EventLoop;
import promhx.Thenable;

typedef AsyncLink<T> = {
    async : AsyncBase<Dynamic>,
    linkf : T->Void
}


class AsyncBase<T>{
#if debug
    // add ids to the async instances so they are easier to track
    static var id_ctr  = 0;
    var id          : Int;
#end
    var _val        : T;
    var _resolved   : Bool;
    var _fulfilled  : Bool;
    var _pending    : Bool;
    var _update     : Array<AsyncLink<T>>;
    var _error      : Array<Dynamic->Void>;
    var _errorMap   : Dynamic->T;

    /**
      Constructor argument can take optional function argument, which adds
      a callback to the error handler chain.
     **/
    public function new(?d:Deferred<T>) {
#if debug id = id_ctr +=1; #end
        if (d != null){ 
            d.then(handleResolve, handleError ); 
        }

        _resolved   = false;
        _pending = false;
        _fulfilled  = false;
        _update     = [];
        _error      = [];

    }

    /**
      Catch error, effectively halting the current update chain.
      This will prevent downstream async objects from receiving 
      the error message.
     **/
    public function catchError(f : Dynamic->Void) : AsyncBase<T> {
        _error.push(f);
        return this;
    }

    /**
      Map errors back to the expected type, and continue as normal.
     **/
    public function errorThen( f : Dynamic -> T){
        _errorMap = f;
        return this;
    }

    /**
      Utility function to determine if a Promise value has been resolved.
     **/
    public inline function isResolved() : Bool
        return _resolved;


    /**
      Utility function to determine if a Promise value has been rejected.
     **/
    public inline function isFulfilled(): Bool
        return _fulfilled;

    /**
      Utility function to determine if a Promise value is pending operations
      on the next loop.
     **/
    public inline function isPending() : Bool
        return _pending;


    function handleResolve(val:T) : Void {
        _resolve(val);
    }
    /**
      Resolves the given value for processing on any waiting functions.
     **/
    function _resolve(val : T) : Void {

        // this async is pending an update on the next loop, move the
        // resolve to the loop after that.
        if (_pending){
            EventLoop.enqueue(_resolve.bind(val));
        } else {

            // point of no return, this async has now been resolved at least once.
            _resolved = true;

            // we are now in the act of fulfilling the async... which
            // involves waiting for the next enqueued loop
            _pending = true;

            // the loop handler, which may not even be used
            EventLoop.enqueue(function(){
                _val = val; // save the value
                for (up in _update){
#if PromhxExposeErrors
                    up.linkf(val);
#else
                    try up.linkf(val)
                catch (e:Dynamic) up.async.handleError(e);
#end
                }
                _fulfilled = true; // we're in a fulfilled state
                _pending = false; // we're done fulfilling for this resolve
            });
        }

    }

    /**
      Handle errors
     **/
    function handleError(error : Dynamic) : Void {
        var update_errors = function(e:Dynamic){
            if (_error.length > 0) for (ef in _error) ef(e);
            else if (_update.length > 0) for (up in _update) up.async.handleError(e);
            else {
#if (js && nodejs)
                // Node sometimes doesn't produce helpful stack information on thrown errors.
                trace('Call Stack: ' + haxe.CallStack.toString(haxe.CallStack.callStack()));
#end
                throw e;
            }
        }
        EventLoop.enqueue(function(){
            if (_errorMap != null){
#if PromhxExposeErrors
                this._resolve(_errorMap(error));
            _resolve(_errorMap(error));
#else
                try this._resolve(_errorMap(error))
                catch (e : Dynamic) update_errors(e);
#end
            } else {
                update_errors(error);
            }
        });
    }

    /**
      This function returns a new AsyncBase.  When this instance resolves,
      it will resolve the new AsyncBase with the function callback argument.
     **/
    public function then<A>(f : T->A) : AsyncBase<A> {
        var ret = new AsyncBase<A>();
        link(this, ret, f);
        return ret;
    }

    /**
      Remove an Async that is updated from this Async.  This action is
      performed on the next event loop.
     **/
    public function unlink( to : AsyncBase<Dynamic>) {
        EventLoop.enqueue(function(){
            _update =  _update.filter(function(x) return x.async != to);
        });
    }
{'fraction_non_alphanumeric': 0.09510545165141265, 'fraction_numerical': 0.0009948269001193793, 'mean_word_length': 1.802620574296069, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4991161', 'n_tokens_mistral': 2879, 'n_tokens_neox': 2738, 'n_words': 951}