<commit_before>var isProblem = require( '../utils/isProblem' );
var Problem = require( '../models/Problem' );
var functionName = require( '../utils/fnName' );
var namedFn = require( '../utils/namedFn' );
var betterThrow = require( '../utils/betterThrow' );
var stringifyWithFnName = require( '../utils/stringifyWithFnName' );

function fclauseWalker( clause, walkFn ) {
  var { args: argsClause, ret: retClause, fn: validateFn } = clause.opts;

  return {
    trailblaze: fclauseTrailblaze,
    reconstruct: fclauseReconstruct,
  };

  function fclauseTrailblaze( fn ) {
    return fn;
  }

  function fclauseReconstruct( fn, walkOpts ) {
    if ( fn ) {
      var { conform, instrument } = walkOpts;

      if ( conform && instrument ) {
        return instrumentConformed( fn, walkOpts );
      } else if ( instrument ) {
        return _instrument( fn, walkOpts );
      }
    } else {
      throw new Error( 'A function must be clauseified for instrumentation.' );
    }
  }

  function _instrument( fn, walkOpts ) {
    var fnName = functionName( fn );
    var instrumentedFn = getInstrumentedFn( fnName, fn, walkOpts );
    var namedClauseedFn = namedFn( fnName, instrumentedFn, '__instrumented' );
    return namedClauseedFn;
  }

  function instrumentConformed( fn, walkOpts ) {
    var fnName = functionName( fn );
    var argConformedFn = getArgConformedInstrumentedFn( fnName, fn, walkOpts );
    var namedArgConformedFn = namedFn( fnName, argConformedFn, '__conformed' );

    return namedArgConformedFn;
  }

  function getInstrumentedFn( fnName, fn ) {
    return function __instrumented() {
      var args = Array.prototype.slice.call( arguments );
      var instrumentedArgs = checkArgs( fn, fnName, args );
      var retVal = fn.apply( this, instrumentedArgs );
      var instrumentedRetVal = checkRet( fn, fnName, retVal );

      // TODO optimize
      var conformedArgs =
      argsClause ?
        walkFn( argsClause, args, { conform: true, instrument: true } ) :
        args;
      let conformedRetVal;
      if ( retClause ) {
        conformedRetVal = walkFn( retClause, retVal, { conform: true, instrument: true } );
      } else {
        conformedRetVal = retVal;
      }

      checkFnRelation( fnName, fn, validateFn, conformedArgs, conformedRetVal );
      return instrumentedRetVal;
    };
  }

  function checkFnRelation( fnName, fn, validateFn, conformedArgs, retVal ) {
    if ( validateFn ) {
      var r = validateFn.call( null, conformedArgs, retVal );
      if ( !r ) {
        var p = new Problem( fn, clause, [],
          `Function ${fnName} failed valiation on argument-return value relation` );
        betterThrow( p );
      }
    }
  }

  function checkArgs( fn, fnName, args ) {
    if ( argsClause ) {
      var instrumentedArgs = walkFn( argsClause, args, { phase: 'trailblaze' } );
      if ( isProblem( instrumentedArgs ) ) {
        var p = new Problem( args, clause, [ instrumentedArgs ], `Arguments ${stringifyWithFnName( args )} for function ${fnName} failed validation` );
        betterThrow( p );
      } else {
        return walkFn( argsClause, instrumentedArgs, { phase: 'reconstruct', conform: false, instrument: true } );
      }
    } else {
      return args;
    }
  }

  function checkRet( fn, fnName, retVal ) {
    if ( retClause ) {
      var instrumentedRetVal = walkFn( retClause, retVal, { phase: 'trailblaze' } );
      if ( isProblem( instrumentedRetVal ) ) {
        var p = new Problem( retVal, clause, [ instrumentedRetVal ], 'Return value ' + retVal + ' for function ' + fnName + ' is not valid.' );
        betterThrow( p );
      } else {
        var r = walkFn( retClause, instrumentedRetVal, { phase: 'reconstruct', instrument: true, conform: false } );
        return r;
      }
    } else {<commit_msg>remove extra period in fclase error message<commit_after>var isProblem = require( '../utils/isProblem' );
var Problem = require( '../models/Problem' );
var functionName = require( '../utils/fnName' );
var namedFn = require( '../utils/namedFn' );
var betterThrow = require( '../utils/betterThrow' );
var stringifyWithFnName = require( '../utils/stringifyWithFnName' );

function fclauseWalker( clause, walkFn ) {
  var { args: argsClause, ret: retClause, fn: validateFn } = clause.opts;

  return {
    trailblaze: fclauseTrailblaze,
    reconstruct: fclauseReconstruct,
  };

  function fclauseTrailblaze( fn ) {
    return fn;
  }

  function fclauseReconstruct( fn, walkOpts ) {
    if ( fn ) {
      var { conform, instrument } = walkOpts;

      if ( conform && instrument ) {
        return instrumentConformed( fn, walkOpts );
      } else if ( instrument ) {
        return _instrument( fn, walkOpts );
      }
    } else {
      throw new Error( 'A function must be clauseified for instrumentation.' );
    }
  }

  function _instrument( fn, walkOpts ) {
    var fnName = functionName( fn );
    var instrumentedFn = getInstrumentedFn( fnName, fn, walkOpts );
    var namedClauseedFn = namedFn( fnName, instrumentedFn, '__instrumented' );
    return namedClauseedFn;
  }

  function instrumentConformed( fn, walkOpts ) {
    var fnName = functionName( fn );
    var argConformedFn = getArgConformedInstrumentedFn( fnName, fn, walkOpts );
    var namedArgConformedFn = namedFn( fnName, argConformedFn, '__conformed' );

    return namedArgConformedFn;
  }

  function getInstrumentedFn( fnName, fn ) {
    return function __instrumented() {
      var args = Array.prototype.slice.call( arguments );
      var instrumentedArgs = checkArgs( fn, fnName, args );
      var retVal = fn.apply( this, instrumentedArgs );
      var instrumentedRetVal = checkRet( fn, fnName, retVal );

      // TODO optimize
      var conformedArgs =
      argsClause ?
        walkFn( argsClause, args, { conform: true, instrument: true } ) :
        args;
      let conformedRetVal;
      if ( retClause ) {
        conformedRetVal = walkFn( retClause, retVal, { conform: true, instrument: true } );
      } else {
        conformedRetVal = retVal;
      }

      checkFnRelation( fnName, fn, validateFn, conformedArgs, conformedRetVal );
      return instrumentedRetVal;
    };
  }

  function checkFnRelation( fnName, fn, validateFn, conformedArgs, retVal ) {
    if ( validateFn ) {
      var r = validateFn.call( null, conformedArgs, retVal );
      if ( !r ) {
        var p = new Problem( fn, clause, [],
          `Function ${fnName} failed valiation on argument-return value relation` );
        betterThrow( p );
      }
    }
  }

  function checkArgs( fn, fnName, args ) {
    if ( argsClause ) {
      var instrumentedArgs = walkFn( argsClause, args, { phase: 'trailblaze' } );
      if ( isProblem( instrumentedArgs ) ) {
        var p = new Problem( args, clause, [ instrumentedArgs ], `Arguments ${stringifyWithFnName( args )} for function ${fnName} is not valid` );
        betterThrow( p );
      } else {
        return walkFn( argsClause, instrumentedArgs, { phase: 'reconstruct', conform: false, instrument: true } );
      }
    } else {
      return args;
    }
  }

  function checkRet( fn, fnName, retVal ) {
    if ( retClause ) {
      var instrumentedRetVal = walkFn( retClause, retVal, { phase: 'trailblaze' } );
      if ( isProblem( instrumentedRetVal ) ) {
        var p = new Problem( retVal, clause, [ instrumentedRetVal ], 'Return value for function ' + ( fnName || '<anonymous>' ) + '() is not valid' );
        betterThrow( p );
      } else {
        var r = walkFn( retClause, instrumentedRetVal, { phase: 'reconstruct', instrument: true, conform: false } );
        return r;
      }
    } else {
{'fraction_non_alphanumeric': 0.11448475289169295, 'fraction_numerical': 0.0, 'mean_word_length': 2.858519269776876, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, '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': '4007345', 'n_tokens_mistral': 2300, 'n_tokens_neox': 2301, 'n_words': 647}