<commit_before>// hack for executing code on node.js
if(typeof module !== 'undefined') {
    fs = require('fs');
	var code = fs.readFileSync('js/parser/createjs.js', 'utf-8');
	eval(cdoe);
    var code = fs.readFileSync('js/parser/pixitiny.js', 'utf-8');
    eval(code);
}

// actual test-case
describe("PIXI_tiny Parser Test Suite", function() {

	var pixitiny = new Pixitiny();

	it("testParsePathItem", function () {
		pixitiny.cropBox = [0,0];
	    var pathItem = {
	        "typename" : "PathItem",
	        "closed" : true,
	        "filled" : false,
	        "fillColor" : {
	            "gray" : 0,
	            "typename" : "GrayColor"
	        },
	        "opacity" : 100,
	        "stroked" : true,
	        "strokeColor" : {
	            "cyan" : 0,
	            "magenta" : 0,
	            "yellow" : 0,
	            "black" : 100,
	            "typename" : "CMYKColor"
	        },
	        "strokeDashes" : [

	        ],
	        "strokeDashOffset" : 0,
	        "strokeCap" : {},
	        "strokeJoin" : {},
	        "strokeMiterLimit" : 10,
	        "strokeWidth" : 6,
	        "pathPoints" : [{
	                "anchor" : [
	                    0,
	                    0
	                ],
	                "leftDirection" : [
	                    0,
	                    0
	                ],
	                "rightDirection" : [
	                    0,
	                    0
	                ]
	            }, {
	                "anchor" : [
	                    10,
	                    0
	                ],
	                "leftDirection" : [
	                    10,
	                    0
	                ],
	                "rightDirection" : [
	                    10,
	                    0
	                ]
	            }, {
	                "anchor" : [
	                    10,
	                    10
	                ],
	                "leftDirection" : [
	                    10,
	                    10
	                ],
	                "rightDirection" : [
	                    10,
	                    10
	                ]
	            }, {
	                "anchor" : [
	                    0,
						10
	                ],
	                "leftDirection" : [
	                     0,
						10
	                ],
	                "rightDirection" : [
	                     0,
						10
	                ]
	            }
	        ]
	    }

		expect(pixitiny.parsePathItem(pathItem)).toBe(".ss(6).s(0x000000).p('" +
			pixitiny.convertPathItemToPathInstruction(pathItem) +"').es()");
	});

	it("testGetColor", function () {
	    var testColor = {
		    typename: 'RGBColor',
		    red: '0',
		    green: '0',
		    blue: '0'
	    };

	    var testOpactiy = 100;
	    expect(pixitiny.getColor(testColor, testOpactiy)).toBe("0x000000");

	    testColor = {
			    typename: 'RGBColor',
			    red: '255',
			    green: '255',
			    blue: '255'
	    };
	    expect(pixitiny.getColor(testColor, testOpactiy)).toBe("0xffffff");

	    testColor = {
			    typename: 'CMYKColor',
			    cyan: '0',
			    black: '100',
			    magenta: '0',
			    yellow: '0'
	    }
	    expect(pixitiny.getColor(testColor, testOpactiy)).toBe("0x000000");
    });

	it("testConvertToHex", function() {
		var number = [0,0.2,0.4,0.6,0.8,10.0,100.0,200000.0,-0.1,-2.0];
	    var bits12 = ["000000000000","000000000010","000000000100","000000000110","000000001000",
	                  "000001100100","001111101000","overflow","100000000001","100000010100"];
	    var bits18 = ["000000000000000000","000000000000000010","000000000000000100",
	                  "000000000000000110","000000000000001000","000000000001100100",
	                  "000000001111101000","overflow","100000000000000001","100000000000010100"];
	    for(var i = 0; i < number.length; i++) {
		    expect(pixitiny.convertNumberToBits(number[i],12)).toBe(bits12[i]);
		    expect(pixitiny.convertNumberToBits(number[i],18)).toBe(bits18[i]);
		}
	});

});<commit_msg>add nodejs support<commit_after>// hack for executing code on node.js
if(typeof module !== 'undefined') {
    fs = require('fs');
	var code = fs.readFileSync('js/parser/createjs.js', 'utf-8');
	eval(code);
    var code = fs.readFileSync('js/parser/pixitiny.js', 'utf-8');
    eval(code);
}

// actual test-case
describe("PIXI_tiny Parser Test Suite", function() {

	var pixitiny = new Pixitiny();

	it("testParsePathItem", function () {
		pixitiny.cropBox = [0,0];
	    var pathItem = {
	        "typename" : "PathItem",
	        "closed" : true,
	        "filled" : false,
	        "fillColor" : {
	            "gray" : 0,
	            "typename" : "GrayColor"
	        },
	        "opacity" : 100,
	        "stroked" : true,
	        "strokeColor" : {
	            "cyan" : 0,
	            "magenta" : 0,
	            "yellow" : 0,
	            "black" : 100,
	            "typename" : "CMYKColor"
	        },
	        "strokeDashes" : [

	        ],
	        "strokeDashOffset" : 0,
	        "strokeCap" : {},
	        "strokeJoin" : {},
	        "strokeMiterLimit" : 10,
	        "strokeWidth" : 6,
	        "pathPoints" : [{
	                "anchor" : [
	                    0,
	                    0
	                ],
	                "leftDirection" : [
	                    0,
	                    0
	                ],
	                "rightDirection" : [
	                    0,
	                    0
	                ]
	            }, {
	                "anchor" : [
	                    10,
	                    0
	                ],
	                "leftDirection" : [
	                    10,
	                    0
	                ],
	                "rightDirection" : [
	                    10,
	                    0
	                ]
	            }, {
	                "anchor" : [
	                    10,
	                    10
	                ],
	                "leftDirection" : [
	                    10,
	                    10
	                ],
	                "rightDirection" : [
	                    10,
	                    10
	                ]
	            }, {
	                "anchor" : [
	                    0,
						10
	                ],
	                "leftDirection" : [
	                     0,
						10
	                ],
	                "rightDirection" : [
	                     0,
						10
	                ]
	            }
	        ]
	    }

		expect(pixitiny.parsePathItem(pathItem)).toBe(".ss(6).s(0x000000).p('" +
			pixitiny.convertPathItemToPathInstruction(pathItem) +"').es()");
	});

	it("testGetColor", function () {
	    var testColor = {
		    typename: 'RGBColor',
		    red: '0',
		    green: '0',
		    blue: '0'
	    };

	    var testOpactiy = 100;
	    expect(pixitiny.getColor(testColor, testOpactiy)).toBe("0x000000");

	    testColor = {
			    typename: 'RGBColor',
			    red: '255',
			    green: '255',
			    blue: '255'
	    };
	    expect(pixitiny.getColor(testColor, testOpactiy)).toBe("0xffffff");

	    testColor = {
			    typename: 'CMYKColor',
			    cyan: '0',
			    black: '100',
			    magenta: '0',
			    yellow: '0'
	    }
	    expect(pixitiny.getColor(testColor, testOpactiy)).toBe("0x000000");
    });

	it("testConvertToHex", function() {
		var number = [0,0.2,0.4,0.6,0.8,10.0,100.0,200000.0,-0.1,-2.0];
	    var bits12 = ["000000000000","000000000010","000000000100","000000000110","000000001000",
	                  "000001100100","001111101000","overflow","100000000001","100000010100"];
	    var bits18 = ["000000000000000000","000000000000000010","000000000000000100",
	                  "000000000000000110","000000000000001000","000000000001100100",
	                  "000000001111101000","overflow","100000000000000001","100000000000010100"];
	    for(var i = 0; i < number.length; i++) {
		    expect(pixitiny.convertNumberToBits(number[i],12)).toBe(bits12[i]);
		    expect(pixitiny.convertNumberToBits(number[i],18)).toBe(bits18[i]);
		}
	});

});<|endoftext|>


<commit_before>/*
 * backend.js - backend for scratch86
 * entrypoint to the backend of scratch86 --
 * all code generation is done in this file or required files from here
 * HERE BE DRAGONS!
 */

// process a script
// this method actually hooks into code generation :)

function processScript(context, script) {
    console.log("Compiling script:");
    console.log(script);
}

// processes a child (basically a sprite)

function processChild(child) {
    // attach some metadata to tag the sprite

    child["86"] = {
        type: "sprite"
    };

    // sprites can have scripts
    // process those seperately

    if(typeof child.scripts !== 'undefined') {
        child.scripts.forEach(function(script) {
            processScript(child, script[2]);
        });
    }
}

module.exports = function(project, output) {
    project.children.forEach(function(child) {
        processChild(child);
    });

    console.log("Backend stub");
}
<commit_msg>Emit function stubs for scripts<commit_after>/*
 * backend.js - backend for scratch86
 * entrypoint to the backend of scratch86 --
 * all code generation is done in this file or required files from here
 * HERE BE DRAGONS!
 */

//var processScript = require("./processScript");

var LLVMOut = [];
var indentStatus = 0;

function emit(line, indentation) {
    if(indentation < 0) indentStatus += indentation;

    var out = "";
    for(var i = 0; i < indentStatus; ++i) out += "    ";

    LLVMOut.push( out + line );

    if(indentation > 0) indentStatus += indentation;
}

var functionCounter = 0; // TODO: infer legitimate names for scripts

// process a script
// this method actually hooks into code generation :)

function processScript(context, script) {
    console.log("Compiling script:");
    console.log(script);

    // first element of the script block is the hat block
    // this determines when this function will be called
    // basically, this is used as a note to the runtime
    // and yes, scripts are functions :)

    var hatBlock = script[0];

    // TODO: implement hat blocks

    // emit a function definition

    emit("declare void @" + hatBlock[0] + (functionCounter++) + "() {", 1);

    emit("}", -1);
}

// processes a child (basically a sprite)

function processChild(child) {
    // attach some metadata to tag the sprite

    child["86"] = {
        type: "sprite"
    };

    // sprites can have scripts
    // process those seperately

    if(typeof child.scripts !== 'undefined') {
        child.scripts.forEach(function(script) {
            processScript(child, script[2]);
        });
    }
}

module.exports = function(project, output) {
    project.children.forEach(function(child) {
        processChild(child);
    });

    console.log("Backend stub");
}
<|endoftext|>


<commit_before>/*
 * angular-loading-bar
 *
 * intercepts XHR requests and creates a loading bar.
 * Based on the excellent nprogress work by rstacruz (more info in readme)
 *
 * (c) 2013 Wes Cruver
 * License: MIT
 */

(function() {

'use strict';

// Alias the loading bar for various backwards compatibilities since the project has matured:
angular.module('angular-loading-bar', ['cfp.loadingBarInterceptor']);
angular.module('chieffancypants.loadingBar', ['cfp.loadingBarInterceptor']);

/**
 * loadingBarInterceptor service
 *
 * Registers itself as an Angular interceptor and listens for XHR requests.
 */
angular.module('cfp.loadingBarInterceptor', ['cfp.loadingBar'])
  .config(['$httpProvider', function ($httpProvider) {

    var interceptor = ['$q', '$cacheFactory', '$timeout', '$rootScope', 'cfpLoadingBar', function ($q, $cacheFactory, $timeout, $rootScope, cfpLoadingBar) {

      /**
       * The total number of requests made
       */
      var reqsTotal = 0;

      /**
       * The number of requests completed (either successfully or not)
       */
      var reqsCompleted = 0;

      /**
       * The amount of time spent fetching before showing the loading bar
       */
      var latencyThreshold = cfpLoadingBar.latencyThreshold;

      /**
       * $timeout handle for latencyThreshold
       */
      var startTimeout;

      /**
       * calls cfpLoadingBar.complete() which removes the
       * loading bar from the DOM.
       */
      function setComplete() {
        $timeout.cancel(startTimeout);
        cfpLoadingBar.complete();
        reqsCompleted = 0;
        reqsTotal = 0;
      }

      /**
       * Determine if the response has already been cached
       * @param  {Object}  config the config option from the request
       * @return {Boolean} retrns true if cached, otherwise false
       */
      function isCached(config) {
        var cache;
        var defaults = $httpProvider.defaults;

        if (config.method !== 'GET' || config.cache === false) {
          config.cached = false;
          return false;
        }

        if (config.cache === true && defaults.cache === undefined) {
          cache = $cacheFactory.get('$http');
        } else if (defaults.cache !== undefined) {
          cache = defaults.cache;
        } else {
          cache = config.cache;
        }

        var cached = cache !== undefined ?
          cache.get(config.url) !== undefined : false;

        if (config.cached !== undefined && cached !== config.cached) {
          return config.cached;
        }
        config.cached = cached;
        return cached;
      }

      return {
        'request': function(config) {
          // Check to make sure this request hasn't already been cached and that
          // the requester didn't explicitly ask us to ignore this request:
          if (!config.ignoreLoadingBar && !isCached(config)) {
            $rootScope.$broadcast('cfpLoadingBar:loading', {url: config.url});
            if (reqsTotal === 0) {
              startTimeout = $timeout(function() {
                cfpLoadingBar.start();
              }, latencyThreshold);
            }
            reqsTotal++;
            cfpLoadingBar.set(reqsCompleted / reqsTotal);
          }
          return config;
        },

        'response': function(response) {
          if (!isCached(response.config)) {
            reqsCompleted++;
            $rootScope.$broadcast('cfpLoadingBar:loaded', {url: response.config.url});
            if (reqsCompleted >= reqsTotal) {
              setComplete();
            } else {
              cfpLoadingBar.set(reqsCompleted / reqsTotal);
            }
          }
          return response;
        },

        'responseError': function(rejection) {
          if (!isCached(rejection.config)) {
            reqsCompleted++;
            $rootScope.$broadcast('cfpLoadingBar:loaded', {url: rejection.config.url});
            if (reqsCompleted >= reqsTotal) {
              setComplete();
            } else {
              cfpLoadingBar.set(reqsCompleted / reqsTotal);
            }
          }
          return $q.reject(rejection);
        }
      };
    }];

    $httpProvider.interceptors.push(interceptor);
  }]);

/**
 * Loading Bar
 *
 * This service handles adding and removing the actual element in the DOM.
 * Generally, best practices for DOM manipulation is to take place in a
 * directive, but because the element itself is injected in the DOM only upon
 * XHR requests, and it's likely needed on every view, the best option is to
 * use a service.
 */
angular.module('cfp.loadingBar', [])
  .provider('cfpLoadingBar', function() {

    this.includeSpinner = true;
    this.includeBar = true;
    this.latencyThreshold = 100;
    this.startSize = 0.02;
    this.parentSelector = 'body';

    this.$get = ['$document', '$timeout', '$animate', '$rootScope', function ($document, $timeout, $animate, $rootScope) {

      var $parentSelector = this.parentSelector,
        loadingBarContainer = angular.element('

'),
        loadingBar = loadingBarContainer.find('div').eq(0),
        spinner = angular.element('

');

      var incTimeout,
        completeTimeout,
        started = false,
        status = 0;

      var includeSpinner = this.includeSpinner;
      var includeBar = this.includeBar;
      var startSize = this.startSize;

      /**
       * Inserts the loading bar element into the dom, and sets it to 2%
       */
      function _start() {
        var $parent = $document.find($parentSelector);
        $timeout.cancel(completeTimeout);

        // do not continually broadcast the started event:
        if (started) {
          return;
        }

        $rootScope.$broadcast('cfpLoadingBar:started');
        started = true;

        if (includeBar) {
          $animate.enter(loadingBarContainer, $parent);
        }

        if (includeSpinner) {
          $animate.enter(spinner, $parent);
        }

        _set(startSize);
      }

      /**
       * Set the loading bar's width to a certain percent.
       *
       * @param n any value between 0 and 1
       */
      function _set(n) {
        if (!started) {
          return;
        }
        var pct = (n * 100) + '%';
        loadingBar.css('width', pct);
        status = n;

        // increment loadingbar to give the illusion that there is always
        // progress but make sure to cancel the previous timeouts so we don't
        // have multiple incs running at the same time.
        $timeout.cancel(incTimeout);
        incTimeout = $timeout(function() {
          _inc();
        }, 250);
      }

      /**
       * Increments the loading bar by a random amount
       * but slows down as it progresses
       */
      function _inc() {
        if (_status() >= 1) {
          return;
        }

        var rnd = 0;

        // TODO: do this mathmatically instead of through conditions

        var stat = _status();
        if (stat >= 0 && stat < 0.25) {
          // Start out between 3 - 6% increments
          rnd = (Math.random() * (5 - 3 + 1) + 3) / 100;
        } else if (stat >= 0.25 && stat < 0.65) {
          // increment between 0 - 3%
          rnd = (Math.random() * 3) / 100;
        } else if (stat >= 0.65 && stat < 0.9) {
          // increment between 0 - 2%
          rnd = (Math.random() * 2) / 100;
        } else if (stat >= 0.9 && stat < 0.99) {
          // finally, increment it .5 %
          rnd = 0.005;
        } else {
          // after 99%, don't increment:
          rnd = 0;
        }

        var pct = _status() + rnd;
        _set(pct);
      }

      function _status() {
        return status;
      }

      function _complete() {
        $rootScope.$broadcast('cfpLoadingBar:completed');
        _set(1);

        // Attempt to aggregate any start/complete calls within 500ms:
        completeTimeout = $timeout(function() {
          $animate.leave(loadingBarContainer, function() {
            status = 0;
            started = false;
          });
          $animate.leave(spinner);
        }, 500);
      }

      return {
        start            : _start,
        set              : _set,
        status           : _status,
        inc              : _inc,
        complete         : _complete,
        includeSpinner   : this.includeSpinner,
        latencyThreshold : this.latencyThreshold,
        parentSelector   : this.parentSelector,
        startSize        : this.startSize
      };

    }];     //
  });       // wtf javascript. srsly
})();       //
<commit_msg>ignoreLoadingBar parameter fix<commit_after>/*
 * angular-loading-bar
 *
 * intercepts XHR requests and creates a loading bar.
 * Based on the excellent nprogress work by rstacruz (more info in readme)
 *
 * (c) 2013 Wes Cruver
 * License: MIT
 */

(function() {

'use strict';

// Alias the loading bar for various backwards compatibilities since the project has matured:
angular.module('angular-loading-bar', ['cfp.loadingBarInterceptor']);
angular.module('chieffancypants.loadingBar', ['cfp.loadingBarInterceptor']);

/**
 * loadingBarInterceptor service
 *
 * Registers itself as an Angular interceptor and listens for XHR requests.
 */
angular.module('cfp.loadingBarInterceptor', ['cfp.loadingBar'])
  .config(['$httpProvider', function ($httpProvider) {

    var interceptor = ['$q', '$cacheFactory', '$timeout', '$rootScope', 'cfpLoadingBar', function ($q, $cacheFactory, $timeout, $rootScope, cfpLoadingBar) {

      /**
       * The total number of requests made
       */
      var reqsTotal = 0;

      /**
       * The number of requests completed (either successfully or not)
       */
      var reqsCompleted = 0;

      /**
       * The amount of time spent fetching before showing the loading bar
       */
      var latencyThreshold = cfpLoadingBar.latencyThreshold;

      /**
       * $timeout handle for latencyThreshold
       */
      var startTimeout;

      /**
       * calls cfpLoadingBar.complete() which removes the
       * loading bar from the DOM.
       */
      function setComplete() {
        $timeout.cancel(startTimeout);
        cfpLoadingBar.complete();
        reqsCompleted = 0;
        reqsTotal = 0;
      }

      /**
       * Determine if the response has already been cached
       * @param  {Object}  config the config option from the request
       * @return {Boolean} retrns true if cached, otherwise false
       */
      function isCached(config) {
        var cache;
        var defaults = $httpProvider.defaults;

        if (config.method !== 'GET' || config.cache === false) {
          config.cached = false;
          return false;
        }

        if (config.cache === true && defaults.cache === undefined) {
          cache = $cacheFactory.get('$http');
        } else if (defaults.cache !== undefined) {
          cache = defaults.cache;
        } else {
          cache = config.cache;
        }

        var cached = cache !== undefined ?
          cache.get(config.url) !== undefined : false;

        if (config.cached !== undefined && cached !== config.cached) {
          return config.cached;
        }
        config.cached = cached;
        return cached;
      }

      return {
        'request': function(config) {
          // Check to make sure this request hasn't already been cached and that
          // the requester didn't explicitly ask us to ignore this request:
          if (!config.ignoreLoadingBar && !isCached(config)) {
            $rootScope.$broadcast('cfpLoadingBar:loading', {url: config.url});
            if (reqsTotal === 0) {
              startTimeout = $timeout(function() {
                cfpLoadingBar.start();
              }, latencyThreshold);
            }
            reqsTotal++;
            cfpLoadingBar.set(reqsCompleted / reqsTotal);
          }
          return config;
        },

        'response': function(response) {
          if (!response.config.ignoreLoadingBar && !isCached(response.config)) {
            reqsCompleted++;
            $rootScope.$broadcast('cfpLoadingBar:loaded', {url: response.config.url});
            if (reqsCompleted >= reqsTotal) {
              setComplete();
            } else {
              cfpLoadingBar.set(reqsCompleted / reqsTotal);
            }
          }
          return response;
        },

        'responseError': function(rejection) {
          if (!rejection.config.ignoreLoadingBar && !isCached(rejection.config)) {
            reqsCompleted++;
            $rootScope.$broadcast('cfpLoadingBar:loaded', {url: rejection.config.url});
            if (reqsCompleted >= reqsTotal) {
              setComplete();
            } else {
              cfpLoadingBar.set(reqsCompleted / reqsTotal);
            }
          }
          return $q.reject(rejection);
        }
      };
    }];

    $httpProvider.interceptors.push(interceptor);
  }]);

/**
 * Loading Bar
 *
 * This service handles adding and removing the actual element in the DOM.
 * Generally, best practices for DOM manipulation is to take place in a
 * directive, but because the element itself is injected in the DOM only upon
 * XHR requests, and it's likely needed on every view, the best option is to
 * use a service.
 */
angular.module('cfp.loadingBar', [])
  .provider('cfpLoadingBar', function() {

    this.includeSpinner = true;
    this.includeBar = true;
    this.latencyThreshold = 100;
    this.startSize = 0.02;
    this.parentSelector = 'body';

    this.$get = ['$document', '$timeout', '$animate', '$rootScope', function ($document, $timeout, $animate, $rootScope) {

      var $parentSelector = this.parentSelector,
        loadingBarContainer = angular.element('

'),
        loadingBar = loadingBarContainer.find('div').eq(0),
        spinner = angular.element('

');

      var incTimeout,
        completeTimeout,
        started = false,
        status = 0;

      var includeSpinner = this.includeSpinner;
      var includeBar = this.includeBar;
      var startSize = this.startSize;

      /**
       * Inserts the loading bar element into the dom, and sets it to 2%
       */
      function _start() {
        var $parent = $document.find($parentSelector);
        $timeout.cancel(completeTimeout);

        // do not continually broadcast the started event:
        if (started) {
          return;
        }

        $rootScope.$broadcast('cfpLoadingBar:started');
        started = true;

        if (includeBar) {
          $animate.enter(loadingBarContainer, $parent);
        }

        if (includeSpinner) {
          $animate.enter(spinner, $parent);
        }

        _set(startSize);
      }

      /**
       * Set the loading bar's width to a certain percent.
       *
       * @param n any value between 0 and 1
       */
      function _set(n) {
        if (!started) {
          return;
        }
        var pct = (n * 100) + '%';
        loadingBar.css('width', pct);
        status = n;

        // increment loadingbar to give the illusion that there is always
        // progress but make sure to cancel the previous timeouts so we don't
        // have multiple incs running at the same time.
        $timeout.cancel(incTimeout);
        incTimeout = $timeout(function() {
          _inc();
        }, 250);
      }

      /**
       * Increments the loading bar by a random amount
       * but slows down as it progresses
       */
      function _inc() {
        if (_status() >= 1) {
          return;
        }

        var rnd = 0;

        // TODO: do this mathmatically instead of through conditions

        var stat = _status();
        if (stat >= 0 && stat < 0.25) {
          // Start out between 3 - 6% increments
          rnd = (Math.random() * (5 - 3 + 1) + 3) / 100;
        } else if (stat >= 0.25 && stat < 0.65) {
          // increment between 0 - 3%
          rnd = (Math.random() * 3) / 100;
        } else if (stat >= 0.65 && stat < 0.9) {
          // increment between 0 - 2%
          rnd = (Math.random() * 2) / 100;
        } else if (stat >= 0.9 && stat < 0.99) {
          // finally, increment it .5 %
          rnd = 0.005;
        } else {
          // after 99%, don't increment:
          rnd = 0;
        }

        var pct = _status() + rnd;
        _set(pct);
      }

      function _status() {
        return status;
      }

      function _complete() {
        $rootScope.$broadcast('cfpLoadingBar:completed');
        _set(1);

        // Attempt to aggregate any start/complete calls within 500ms:
        completeTimeout = $timeout(function() {
          $animate.leave(loadingBarContainer, function() {
            status = 0;
            started = false;
          });
          $animate.leave(spinner);
        }, 500);
      }

      return {
        start            : _start,
        set              : _set,
        status           : _status,
        inc              : _inc,
        complete         : _complete,
        includeSpinner   : this.includeSpinner,
        latencyThreshold : this.latencyThreshold,
        parentSelector   : this.parentSelector,
        startSize        : this.startSize
      };

    }];     //
  });       // wtf javascript. srsly
})();       //
<|endoftext|>


<commit_before>/*
 * backend.js - backend for scratch86
 * entrypoint to the backend of scratch86 --
 * all code generation is done in this file or required files from here
 * HERE BE DRAGONS!
 */

var fs = require("fs");

//var processScript = require("./processScript");

var LLVMOut = [];
var indentStatus = 0;

function emit(line, indentation) {
    if(indentation < 0) indentStatus += indentation;

    var out = "";
    for(var i = 0; i < indentStatus; ++i) out += "    ";

    LLVMOut.push( out + line );

    if(indentation > 0) indentStatus += indentation;
}

var functionCounter = 0; // TODO: infer legitimate names for scripts

// compileBlock is the meat of the compiler
// it recursively emits IR to make stuff happen
// this is the real "HERE BE DRAGONS" <3

function compileBlock(block, expectedType) {
    if(block[0] == "playSound:") {
        // heh, so sound isn't actually supported atm
        // TODO: actually implement sound
        // but, this block is used as a putchar ABI for testing scratch->LLVM until a graphics runtime is setup :)

        var argument = compileBlock(block[1], "i32");

        // just call putchar

        emit("call void @putchar(i32 " + argument + ")");
    } else {
        console.error("Unknown block:");
        console.error(block);

        // return a stub value if needed

        if(expectedType == 'i8' || expectedType == 'i16' || expectedType == 'i32') {
            return "0";
        }
    }
}

// process a script
// this method actually hooks into code generation :)

function processScript(context, script) {
    console.log("Compiling script:");
    console.log(script);

    // first element of the script block is the hat block
    // this determines when this function will be called
    // basically, this is used as a note to the runtime
    // and yes, scripts are functions :)

    var hatBlock = script[0];

    // TODO: implement hat blocks

    // emit a function definition

    emit("define void @" + hatBlock[0] + (functionCounter++) + "() {", 1);

    // for each block in the script, compile it!

    script.forEach(compileBlock);

    emit("}", -1);
}

// processes a child (basically a sprite)

function processChild(child) {
    // attach some metadata to tag the sprite

    child["86"] = {
        type: "sprite"
    };

    // sprites can have scripts
    // process those seperately

    if(typeof child.scripts !== 'undefined') {
        child.scripts.forEach(function(script) {
            processScript(child, script[2]);
        });
    }
}

module.exports = function(project, output) {
    project.children.forEach(function(child) {
        processChild(child);
    });

    fs.writeFile(output, LLVMOut.join("\n") + "\n");

    console.log("Backend stub");
}
<commit_msg>Type tracking through compile block<commit_after>/*
 * backend.js - backend for scratch86
 * entrypoint to the backend of scratch86 --
 * all code generation is done in this file or required files from here
 * HERE BE DRAGONS!
 */

var fs = require("fs");

//var processScript = require("./processScript");

var LLVMOut = [];
var indentStatus = 0;

function emit(line, indentation) {
    if(indentation < 0) indentStatus += indentation;

    var out = "";
    for(var i = 0; i < indentStatus; ++i) out += "    ";

    LLVMOut.push( out + line );

    if(indentation > 0) indentStatus += indentation;
}

var functionCounter = 0; // TODO: infer legitimate names for scripts

// compileBlock is the meat of the compiler
// it recursively emits IR to make stuff happen
// this is the real "HERE BE DRAGONS" <3
// its return type is a reference to the output of its operation
// (typically an IR register, a getelementptr, a constant, etc.),
// but in an array, where the second element is the type.
// type tracking is implemented this way to optimize the IR for Scratch's weird type rules.

function compileBlock(block, expectedType) {
    if(block[0] == "playSound:") {
        // heh, so sound isn't actually supported atm
        // TODO: actually implement sound
        // but, this block is used as a putchar ABI for testing scratch->LLVM until a graphics runtime is setup :)

        var argument = compileBlock(block[1], "i32");

        // just call putchar

        emit("call void @putchar(i32 " + argument[0] + ")");
    } else {
        console.error("Unknown block:");
        console.error(block);

        // return a stub value if needed

        if(expectedType == 'i8' || expectedType == 'i16' || expectedType == 'i32') {
            return ["0", expectedType];
        }
    }

    // if we're still here, it's probably a void block and not part of a chain :)
    // for good measure, just in case, we return type void (I know, wat?)

    return [null, "void"];
}

// process a script
// this method actually hooks into code generation :)

function processScript(context, script) {
    console.log("Compiling script:");
    console.log(script);

    // first element of the script block is the hat block
    // this determines when this function will be called
    // basically, this is used as a note to the runtime
    // and yes, scripts are functions :)

    var hatBlock = script[0];

    // TODO: implement hat blocks

    // emit a function definition

    emit("define void @" + hatBlock[0] + (functionCounter++) + "() {", 1);

    // for each block in the script, compile it!

    script.forEach(compileBlock);

    emit("}", -1);
}

// processes a child (basically a sprite)

function processChild(child) {
    // attach some metadata to tag the sprite

    child["86"] = {
        type: "sprite"
    };

    // sprites can have scripts
    // process those seperately

    if(typeof child.scripts !== 'undefined') {
        child.scripts.forEach(function(script) {
            processScript(child, script[2]);
        });
    }
}

module.exports = function(project, output) {
    project.children.forEach(function(child) {
        processChild(child);
    });

    fs.writeFile(output, LLVMOut.join("\n") + "\n");

    console.log("Backend stub");
}
<|endoftext|>


<commit_before>import nock from 'nock';
import * as reservice from '../src';

const { ReserviceError, createService, isBadService,
        isService, setupServiceEndpoint, createMiddlewareByServiceList,
        serviceMiddleware, handleServiceActions } = reservice;

describe('reservice', () => {
  const mockServerHOST = 'http://test';
  const mockServerPATH = '/here';
  const mockServerURL = mockServerHOST + mockServerPATH;

  const doneService = (name) => {
    const act = createService(name)();
    act.meta.serviceState = 'END';
    return act;
  };

  const mockStore = () => ({
    req: 123,
    dispatch: jasmine.createSpy('dispatch'),
  });

  const serviceList = {
    foo: param1 => param1,
    bar: (p1, p2) => ({ p1, p2 }),
    err: () => { throw new ReserviceError('bad'); },
  };

  let middleware;

  beforeAll(() => {
    nock(mockServerHOST)
    .persist()
    .post(mockServerPATH)
    .reply(200, { foo: 'OK' });
  });

  afterAll(() => {
    nock.cleanAll();
  });

  describe('ReserviceError', () => {
    it('should be a standard Error', () => {
      expect(new ReserviceError('test') instanceof Error).toBe(true);
    });

    it('should be a extended Error', () => {
      expect(new ReserviceError('test') instanceof ReserviceError).toBe(true);
    });

    it('should keep action when proviced', () => {
      const action = { type: 'test', payload: 'haha' };
      const err = new ReserviceError('test', action);
      expect(err.action).toBe(action);
    });
  });

  describe('createService()', () => {
    it('should return action creator', () => {
      expect(typeof createService()).toBe('function');
    });

    it('should keep service name in .toString()', () => {
      expect(createService('SERVICE_NAME').toString()).toBe('SERVICE_NAME');
    });

    it('should keep service name in action.meta.serviceName', () => {
      expect(createService('SERVICE_NAME')().meta.serviceName).toBe('SERVICE_NAME');
    });

    it('should provide default payload logic', () => {
      expect(createService('thisIsService')('yo', 'ya')).toEqual({
        type: 'CALL_SERVICE',
        payload: 'yo',
        meta: {
          serviceName: 'thisIsService',
          serviceState: 'CREATED',
        },
      });
    });

    it('should handle payload creator correctly', () => {
      const payloadCreator = (arg1, arg2) => ({ foo: arg1, bar: arg2 });

      expect(createService('SERVICE_NAME', payloadCreator)('yo', 'ya')).toEqual({
        type: 'CALL_SERVICE',
        payload: {
          foo: 'yo',
          bar: 'ya',
        },
        meta: {
          serviceName: 'SERVICE_NAME',
          serviceState: 'CREATED',
        },
      });
    });
  });

  describe('isBadService()', () => {
    it('should detect no meta issue', () => {
      expect(isBadService({ type: 'CALL_SERVICE' })).toEqual({
        type: 'CALL_SERVICE',
        payload: new ReserviceError('no action.meta', { type: 'CALL_SERVICE' }),
        error: true,
        meta: {
          serviceState: 'END',
          previous_action: {
            type: 'CALL_SERVICE',
          },
        },
      });
    });

    it('should detect no meta.serviceName issue', () => {
      expect(isBadService({ type: 'CALL_SERVICE', meta: {} })).toEqual({
        type: 'CALL_SERVICE',
        payload: new ReserviceError('no action.meta.serviceName'),
        error: true,
        meta: {
          serviceState: 'END',
          previous_action: {
            type: 'CALL_SERVICE',
            meta: {},
          },
        },
      });
    });

    it('should detect no meta.serviceState issue', () => {
      expect(isBadService({ type: 'CALL_SERVICE', meta: { serviceName: 'OK' } })).toEqual({
        type: 'CALL_SERVICE',
        payload: new ReserviceError('no action.meta.serviceState'),
        error: true,
        meta: {
          serviceName: 'OK',
          serviceState: 'END',
          previous_action: {
            type: 'CALL_SERVICE',
            meta: {
              serviceName: 'OK',
            },
          },
        },
      });
    });
  });

  describe('isService()', () => {
    it('should return true when service is valid', () => {
      expect(isService(createService('TEST')())).toEqual(true);
    });

    it('should return false when no input', () => {
      expect(isService()).toEqual(false);
    });

    it('should return false when is not service action', () => {
      expect(isService({ type: 'any' })).toEqual(false);
    });

    it('should return false when is not a valid service action', () => {
      expect(isService({ type: 'CALL_SERVICE' })).toEqual(null);
    });

    it('should return error action when required', () => {
      expect(isService({ type: 'CALL_SERVICE' }, true)).toEqual({
        type: 'CALL_SERVICE',
        payload: new ReserviceError('no action.meta'),
        error: true,
        meta: {
          serviceState: 'END',
          previous_action: {
            type: 'CALL_SERVICE',
          },
        },
      });
    });
  });

  describe('createMiddlewareByServiceList() error', () => {
    let oldWindow;

    beforeAll(() => {
      oldWindow = global.window;
    });
    afterAll(() => {
      global.window = oldWindow;
    });

    it('should error when no serviceList', () => {
      expect(createMiddlewareByServiceList).toThrow(new ReserviceError('No serviceList for service middleware! Check the serviceList in your createMiddlewareByServiceList(serviceList)'));
    });

    it('should error when at client side', () => {
      global.window = true;
      expect(() => createMiddlewareByServiceList({})).toThrow(new ReserviceError('createMiddlewareByServiceList() should not be executed at client side!'));
    });
  });

  describe('serviceMiddleware() error', () => {
    it('should throw when service_list is not provided', () => {
      expect(() => serviceMiddleware(mockStore())(() => 0)(createService('test')())).toThrow(new ReserviceError('Wrong serviceMiddleware() at server side! You should create service middleware by serviceMiddleware(serviceList) !'));
    });
  });

  describe('setupServiceEndpoint()', () => {
    it('should be ok', () => setupServiceEndpoint(mockServerURL, 'POST'));
  });

  describe('serviceMiddleware() at client', () => {
    let oldWindow;

    beforeAll(() => {
      oldWindow = global.window;
      global.window = 1;
    });
    afterAll(() => {
      global.window = oldWindow;
    });

    it('should transportServiceToServer()', () => {
      const store = mockStore();
      return serviceMiddleware(store)(() => 0)(createService('foo')()).then(() => {
        expect(store.dispatch).toHaveBeenCalledWith({
          type: 'CALL_SERVICE',
          payload: { foo: 'OK' },
          error: false,
          meta: {
            serviceName: 'foo',
            serviceState: 'END',
            previous_action: {
              type: 'CALL_SERVICE',
              meta: {
                serviceName: 'foo',
                serviceState: 'CREATED',
              },
            },
          },
        });
      });
    });
  });

  describe('setupServiceEndpoint() error', () => {
    it('should be ok', () => setupServiceEndpoint(mockServerURL, 'POST'));
    it('should throw when executed after createMiddlewareByServiceList()', () => {
      middleware = createMiddlewareByServiceList(serviceList);
      expect(setupServiceEndpoint).toThrow(new ReserviceError('Wrong setupServiceEndpoint() ! You should to it before serviceMiddleware(serviceList) !'));
    });
  });

  describe('createMiddlewareByServiceList()', () => {
    it('should error when executed twice', () => {
      expect(() => createMiddlewareByServiceList({})).toThrow(new ReserviceError('createMiddlewareByServiceList() should be executed once only!'));
    });

    it('should call next when url is not matched', () => {
      const next = jasmine.createSpy('next');
      middleware({ originalUrl: 'ooxx' }, undefined, next);
      expect(next).toHaveBeenCalled();
    });

    it('should call next when method is not matched', () => {
      const next = jasmine.createSpy('next');
      middleware({ originalUrl: mockServerURL }, undefined, next);
      expect(next).toHaveBeenCalled();
    });

    it('should call next when no req.body', () => {
      const next = jasmine.createSpy('next');
      middleware({ originalUrl: mockServerURL, method: 'POST' }, undefined, next);
      expect(next).toHaveBeenCalled();
    });

    it('should call next when action is not service action', () => {
      const next = jasmine.createSpy('next');
      middleware({ originalUrl: mockServerURL, method: 'POST', body: {} }, undefined, next);
      expect(next).toHaveBeenCalled();
    });

    it('should call next with error when action is not a valid service action', () => {
      const next = jasmine.createSpy('next');
      middleware({ originalUrl: mockServerURL, method: 'POST', body: { type: 'CALL_SERVICE' } }, undefined, next);
      expect(next).toHaveBeenCalledWith(new ReserviceError('no action.meta'));
    });

    it('should execute service', (done) => {
      const req = {
        originalUrl: mockServerURL,
        method: 'POST',
        body: {
          type: 'CALL_SERVICE',
          meta: {
            serviceName: 'foo',
            serviceState: 'CREATED',
          },
        },
      };
      middleware(req, {
        send: (act) => {
          expect(act).toEqual(req);
          done();
        },
      });
    });

    it('should report error when service not found', (done) => {
      const req = {
        originalUrl: mockServerURL,
        method: 'POST',
        body: {
          type: 'CALL_SERVICE',
          meta: {
            serviceName: 'not_found',
            serviceState: 'CREATED',
          },
        },
      };
      middleware(req, {
        send: (err) => {
          expect(err).toEqual(new ReserviceError('can not find service named as "not_found" in serviceList'));
          done();
        },
      });
    });

    it('should report error in service', (done) => {
      const req = {
        originalUrl: mockServerURL,
        method: 'POST',
        body: {
          type: 'CALL_SERVICE',
          meta: {
            serviceName: 'err',
            serviceState: 'CREATED',
          },
        },
      };
      middleware(req, {
        send: (err) => {
          expect(err).toEqual(new ReserviceError('bad'));
          done();
        },
      });
    });
  });

  describe('serviceMiddleware()', () => {
    it('should bypass when action is not service action', () => {
      const next = jasmine.createSpy('next');
      serviceMiddleware()(next)({ foo: 'bar' });
      expect(next).toHaveBeenCalledWith({ foo: 'bar' });
    });

    it('should return next() result when action is not service action', () => {
      expect(serviceMiddleware()(() => ({ foo: 'bar' }))({})).toEqual({ foo: 'bar' });
    });

    it('should next() error action when action is bad service action', () => {
      const next = jasmine.createSpy('next');
      serviceMiddleware()(next)({ type: 'CALL_SERVICE' });
      expect(next).toHaveBeenCalledWith({
        type: 'CALL_SERVICE',
        payload: new ReserviceError('no action.meta'),
        error: true,
        meta: {
          previous_action: {
            type: 'CALL_SERVICE',
          },
          serviceState: 'END',
        },
      });
    });

    it('should return promise when input bad service action', () => {
      expect(serviceMiddleware()(() => 0)({ type: 'CALL_SERVICE' }).then).toEqual(jasmine.any(Function));
    });

    it('should bypass when action is done', () => {
      const next = jasmine.createSpy('next');
      const act = doneService('test');
      serviceMiddleware()(next)(act);
      expect(next).toHaveBeenCalledWith(act);
    });

    it('should return next() result when action is done', () => {
      expect(serviceMiddleware()(() => ({ foo: 'bar' }))(doneService('test'))).toEqual({ foo: 'bar' });
    });

    it('should executeServiceAtServer()', () => {
      const store = mockStore();
      return serviceMiddleware(store)(() => 0)(createService('foo')()).then(() => {
        expect(store.dispatch).toHaveBeenCalledWith({
          type: 'CALL_SERVICE',
          payload: 123,
          error: false,
          meta: {
            serviceName: 'foo',
            serviceState: 'END',
            previous_action: {
              type: 'CALL_SERVICE',
              meta: {
                serviceName: 'foo',
                serviceState: 'BEGIN',
              },
            },
          },
        });
      });
    });
  });

  describe('handleServiceActions()', () => {
    it('should create default reducer when no input', () => {
      expect(handleServiceActions()()).toEqual({});
    });

    it('should create reducer to handle default state', () => {
      expect(handleServiceActions(undefined, { foo: 'bar' })()).toEqual({ foo: 'bar' });
    });

    it('should lookup service list then bypass not matched action', () => {
      expect(handleServiceActions({}, { foo: 'bar' })(undefined, doneService('TEST'))).toEqual({ foo: 'bar' });
    });

    it('should execute matched reducer', () => {
      const reducer = jasmine.createSpy('reducer');
      handleServiceActions({ foo: reducer })(3, doneService('foo'));
      expect(reducer).toHaveBeenCalledWith(3, doneService('foo'));
    });

    it('should execute .next when success', () => {
      const reducer = jasmine.createSpy('reducer');
      handleServiceActions({ foo: { next: reducer } })(3, doneService('foo'));
      expect(reducer).toHaveBeenCalledWith(3, doneService('foo'));
    });

    it('should execute .throw when failed', () => {
      const reducer = jasmine.createSpy('reducer');
      const failService = { ...doneService('foo'), error: true };
      handleServiceActions({ foo: { throw: reducer } })(3, failService);
      expect(reducer).toHaveBeenCalledWith(3, failService);
    });
  });
});
<commit_msg>fix tests (move to new interface)<commit_after>import nock from 'nock';
import * as reservice from '../src';

const { ReserviceError, createService, isBadService,
        isService, setupServiceEndpoint, createMiddlewareByServiceList,
        serviceMiddleware, handleServiceActions } = reservice;

describe('reservice', () => {
  const mockServerHOST = 'http://test';
  const mockServerPATH = '/here';
  const mockServerURL = mockServerHOST + mockServerPATH;

  const doneService = (name) => {
    const act = createService(name)();
    act.meta.serviceState = 'END';
    return act;
  };

  const mockStore = () => ({
    req: 123,
    dispatch: jasmine.createSpy('dispatch'),
  });

  const serviceList = {
    foo: param1 => param1,
    bar: (p1, p2) => ({ p1, p2 }),
    err: () => { throw new ReserviceError('bad'); },
  };

  let middleware;

  beforeAll(() => {
    nock(mockServerHOST)
    .persist()
    .post(mockServerPATH)
    .reply(200, { foo: 'OK' });
  });

  afterAll(() => {
    nock.cleanAll();
  });

  describe('ReserviceError', () => {
    it('should be a standard Error', () => {
      expect(new ReserviceError('test') instanceof Error).toBe(true);
    });

    it('should be a extended Error', () => {
      expect(new ReserviceError('test') instanceof ReserviceError).toBe(true);
    });

    it('should keep action when proviced', () => {
      const action = { type: 'test', payload: 'haha' };
      const err = new ReserviceError('test', action);
      expect(err.action).toBe(action);
    });
  });

  describe('createService()', () => {
    it('should return action creator', () => {
      expect(typeof createService()).toBe('function');
    });

    it('should keep service name in .toString()', () => {
      expect(createService('SERVICE_NAME').toString()).toBe('SERVICE_NAME');
    });

    it('should keep service name in action.meta.serviceName', () => {
      expect(createService('SERVICE_NAME')().meta.serviceName).toBe('SERVICE_NAME');
    });

    it('should provide default payload logic', () => {
      expect(createService('thisIsService')('yo', 'ya')).toEqual({
        type: 'CALL_SERVICE',
        payload: 'yo',
        meta: {
          serviceName: 'thisIsService',
          serviceState: 'CREATED',
        },
      });
    });

    it('should handle payload creator correctly', () => {
      const payloadCreator = (arg1, arg2) => ({ foo: arg1, bar: arg2 });

      expect(createService('SERVICE_NAME', payloadCreator)('yo', 'ya')).toEqual({
        type: 'CALL_SERVICE',
        payload: {
          foo: 'yo',
          bar: 'ya',
        },
        meta: {
          serviceName: 'SERVICE_NAME',
          serviceState: 'CREATED',
        },
      });
    });
  });

  describe('isBadService()', () => {
    it('should detect no meta issue', () => {
      expect(isBadService({ type: 'CALL_SERVICE' })).toEqual({
        type: 'CALL_SERVICE',
        payload: new ReserviceError('no action.meta', { type: 'CALL_SERVICE' }),
        error: true,
        meta: {
          serviceState: 'END',
          previous_action: {
            type: 'CALL_SERVICE',
          },
        },
      });
    });

    it('should detect no meta.serviceName issue', () => {
      expect(isBadService({ type: 'CALL_SERVICE', meta: {} })).toEqual({
        type: 'CALL_SERVICE',
        payload: new ReserviceError('no action.meta.serviceName'),
        error: true,
        meta: {
          serviceState: 'END',
          previous_action: {
            type: 'CALL_SERVICE',
            meta: {},
          },
        },
      });
    });

    it('should detect no meta.serviceState issue', () => {
      expect(isBadService({ type: 'CALL_SERVICE', meta: { serviceName: 'OK' } })).toEqual({
        type: 'CALL_SERVICE',
        payload: new ReserviceError('no action.meta.serviceState'),
        error: true,
        meta: {
          serviceName: 'OK',
          serviceState: 'END',
          previous_action: {
            type: 'CALL_SERVICE',
            meta: {
              serviceName: 'OK',
            },
          },
        },
      });
    });
  });

  describe('isService()', () => {
    it('should return true when service is valid', () => {
      expect(isService(createService('TEST')())).toEqual(true);
    });

    it('should return false when no input', () => {
      expect(isService()).toEqual(false);
    });

    it('should return false when is not service action', () => {
      expect(isService({ type: 'any' })).toEqual(false);
    });

    it('should return false when is not a valid service action', () => {
      expect(isService({ type: 'CALL_SERVICE' })).toEqual(null);
    });

    it('should return error action when required', () => {
      expect(isService({ type: 'CALL_SERVICE' }, true)).toEqual({
        type: 'CALL_SERVICE',
        payload: new ReserviceError('no action.meta'),
        error: true,
        meta: {
          serviceState: 'END',
          previous_action: {
            type: 'CALL_SERVICE',
          },
        },
      });
    });
  });

  describe('createMiddlewareByServiceList() error', () => {
    let oldWindow;

    beforeAll(() => {
      oldWindow = global.window;
    });
    afterAll(() => {
      global.window = oldWindow;
    });

    it('should error when no serviceList', () => {
      expect(createMiddlewareByServiceList).toThrow(new ReserviceError('No serviceList for service middleware! Check the serviceList in your createMiddlewareByServiceList(serviceList)'));
    });

    it('should error when at client side', () => {
      global.window = true;
      expect(() => createMiddlewareByServiceList({})).toThrow(new ReserviceError('createMiddlewareByServiceList() should not be executed at client side!'));
    });
  });

  describe('serviceMiddleware() error', () => {
    it('should throw when service_list is not provided', () => {
      expect(() => serviceMiddleware(mockStore())(() => 0)(createService('test')())).toThrow(new ReserviceError('Wrong serviceMiddleware() at server side! You should create service middleware by serviceMiddleware(serviceList) !'));
    });
  });

  describe('setupServiceEndpoint()', () => {
    it('should be ok', () => setupServiceEndpoint(mockServerURL, 'POST'));
  });

  describe('serviceMiddleware() at client', () => {
    let oldWindow;

    beforeAll(() => {
      oldWindow = global.window;
      global.window = 1;
    });
    afterAll(() => {
      global.window = oldWindow;
    });

    it('should transportServiceToServer()', () => {
      const store = mockStore();
      return serviceMiddleware(store)(() => 0)(createService('foo')()).then(() => {
        expect(store.dispatch).toHaveBeenCalledWith({
          type: 'CALL_SERVICE',
          payload: { foo: 'OK' },
          error: false,
          meta: {
            serviceName: 'foo',
            serviceState: 'END',
            previous_action: {
              type: 'CALL_SERVICE',
              meta: {
                serviceName: 'foo',
                serviceState: 'CREATED',
              },
            },
          },
        });
      });
    });
  });

  describe('setupServiceEndpoint() error', () => {
    it('should be ok', () => setupServiceEndpoint(mockServerURL, 'POST'));
    it('should throw when executed after createMiddlewareByServiceList()', () => {
      middleware = createMiddlewareByServiceList(serviceList);
      expect(setupServiceEndpoint).toThrow(new ReserviceError('Wrong setupServiceEndpoint() ! You should to it before serviceMiddleware(serviceList) !'));
    });
  });

  describe('createMiddlewareByServiceList()', () => {
    it('should error when executed twice', () => {
      expect(() => createMiddlewareByServiceList({})).toThrow(new ReserviceError('createMiddlewareByServiceList() should be executed once only!'));
    });

    it('should call next when url is not matched', () => {
      const next = jasmine.createSpy('next');
      middleware({ originalUrl: 'ooxx' }, undefined, next);
      expect(next).toHaveBeenCalled();
    });

    it('should call next when method is not matched', () => {
      const next = jasmine.createSpy('next');
      middleware({ originalUrl: mockServerURL }, undefined, next);
      expect(next).toHaveBeenCalled();
    });

    it('should call next when no req.body', () => {
      const next = jasmine.createSpy('next');
      middleware({ originalUrl: mockServerURL, method: 'POST' }, undefined, next);
      expect(next).toHaveBeenCalled();
    });

    it('should call next when action is not service action', () => {
      const next = jasmine.createSpy('next');
      middleware({ originalUrl: mockServerURL, method: 'POST', body: {} }, undefined, next);
      expect(next).toHaveBeenCalled();
    });

    it('should call next with error when action is not a valid service action', () => {
      const next = jasmine.createSpy('next');
      middleware({ originalUrl: mockServerURL, method: 'POST', body: { type: 'CALL_SERVICE' } }, undefined, next);
      expect(next).toHaveBeenCalledWith(new ReserviceError('no action.meta'));
    });

    it('should execute service', (done) => {
      const req = {
        originalUrl: mockServerURL,
        method: 'POST',
        body: {
          type: 'CALL_SERVICE',
          payload: { good: 'morning' },
          meta: {
            serviceName: 'bar',
            serviceState: 'CREATED',
          },
        },
      };
      middleware(req, {
        send: (act) => {
          expect(act).toEqual({
            p1: { good: 'morning' },
            p2: req,
          });
          done();
        },
      });
    });

    it('should report error when service not found', (done) => {
      const req = {
        originalUrl: mockServerURL,
        method: 'POST',
        body: {
          type: 'CALL_SERVICE',
          meta: {
            serviceName: 'not_found',
            serviceState: 'CREATED',
          },
        },
      };
      middleware(req, {
        send: (err) => {
          expect(err).toEqual(new ReserviceError('can not find service named as "not_found" in serviceList'));
          done();
        },
      });
    });

    it('should report error in service', (done) => {
      const req = {
        originalUrl: mockServerURL,
        method: 'POST',
        body: {
          type: 'CALL_SERVICE',
          meta: {
            serviceName: 'err',
            serviceState: 'CREATED',
          },
        },
      };
      middleware(req, {
        send: (err) => {
          expect(err).toEqual(new ReserviceError('bad'));
          done();
        },
      });
    });
  });

  describe('serviceMiddleware()', () => {
    it('should bypass when action is not service action', () => {
      const next = jasmine.createSpy('next');
      serviceMiddleware()(next)({ foo: 'bar' });
      expect(next).toHaveBeenCalledWith({ foo: 'bar' });
    });

    it('should return next() result when action is not service action', () => {
      expect(serviceMiddleware()(() => ({ foo: 'bar' }))({})).toEqual({ foo: 'bar' });
    });

    it('should next() error action when action is bad service action', () => {
      const next = jasmine.createSpy('next');
      serviceMiddleware()(next)({ type: 'CALL_SERVICE' });
      expect(next).toHaveBeenCalledWith({
        type: 'CALL_SERVICE',
        payload: new ReserviceError('no action.meta'),
        error: true,
        meta: {
          previous_action: {
            type: 'CALL_SERVICE',
          },
          serviceState: 'END',
        },
      });
    });

    it('should return promise when input bad service action', () => {
      expect(serviceMiddleware()(() => 0)({ type: 'CALL_SERVICE' }).then).toEqual(jasmine.any(Function));
    });

    it('should bypass when action is done', () => {
      const next = jasmine.createSpy('next');
      const act = doneService('test');
      serviceMiddleware()(next)(act);
      expect(next).toHaveBeenCalledWith(act);
    });

    it('should return next() result when action is done', () => {
      expect(serviceMiddleware()(() => ({ foo: 'bar' }))(doneService('test'))).toEqual({ foo: 'bar' });
    });

    it('should executeServiceAtServer()', () => {
      const store = mockStore();
      return serviceMiddleware(store)(() => 0)(createService('foo')(456)).then(() => {
        expect(store.dispatch).toHaveBeenCalledWith({
          type: 'CALL_SERVICE',
          payload: 456,
          error: false,
          meta: {
            serviceName: 'foo',
            serviceState: 'END',
            previous_action: {
              type: 'CALL_SERVICE',
              payload: 456,
              meta: {
                serviceName: 'foo',
                serviceState: 'BEGIN',
              },
            },
          },
        });
      });
    });
  });

  describe('handleServiceActions()', () => {
    it('should create default reducer when no input', () => {
      expect(handleServiceActions()()).toEqual({});
    });

    it('should create reducer to handle default state', () => {
      expect(handleServiceActions(undefined, { foo: 'bar' })()).toEqual({ foo: 'bar' });
    });

    it('should lookup service list then bypass not matched action', () => {
      expect(handleServiceActions({}, { foo: 'bar' })(undefined, doneService('TEST'))).toEqual({ foo: 'bar' });
    });

    it('should execute matched reducer', () => {
      const reducer = jasmine.createSpy('reducer');
      handleServiceActions({ foo: reducer })(3, doneService('foo'));
      expect(reducer).toHaveBeenCalledWith(3, doneService('foo'));
    });

    it('should execute .next when success', () => {
      const reducer = jasmine.createSpy('reducer');
      handleServiceActions({ foo: { next: reducer } })(3, doneService('foo'));
      expect(reducer).toHaveBeenCalledWith(3, doneService('foo'));
    });

    it('should execute .throw when failed', () => {
      const reducer = jasmine.createSpy('reducer');
      const failService = { ...doneService('foo'), error: true };
      handleServiceActions({ foo: { throw: reducer } })(3, failService);
      expect(reducer).toHaveBeenCalledWith(3, failService);
    });
  });
});
<|endoftext|>


<commit_before>/*
 * backend.js - backend for scratch86
 * entrypoint to the backend of scratch86 --
 * all code generation is done in this file or required files from here
 * HERE BE DRAGONS!
 */

var fs = require("fs");

//var processScript = require("./processScript");

var LLVMOut = [];
var indentStatus = 0;

function emit(line, indentation) {
    if(indentation < 0) indentStatus += indentation;

    var out = "";
    for(var i = 0; i < indentStatus; ++i) out += "    ";

    LLVMOut.push( out + line );

    if(indentation > 0) indentStatus += indentation;
}

var functionCounter = 0; // TODO: infer legitimate names for scripts

// compileBlock is the meat of the compiler
// it recursively emits IR to make stuff happen
// this is the real "HERE BE DRAGONS" <3
// its return type is a reference to the output of its operation
// (typically an IR register, a getelementptr, a constant, etc.),
// but in an array, where the second element is the type.
// type tracking is implemented this way to optimize the IR for Scratch's weird type rules.

function compileBlock(block, expectedType) {
    if(block[0] == "playSound:") {
        // heh, so sound isn't actually supported atm
        // TODO: actually implement sound
        // but, this block is used as a putchar ABI for testing scratch->LLVM until a graphics runtime is setup :)

        var argument = compileBlock(block[1], "i32");

        // just call putchar

        emit("call void @putchar(i32 " + argument[0] + ")");
    } else {
        console.error("Unknown block:");
        console.error(block);

        // return a stub value if needed

        if(expectedType == 'i8' || expectedType == 'i16' || expectedType == 'i32') {
            return ["0", expectedType];
        }
    }

    // if we're still here, it's probably a void block and not part of a chain :)
    // for good measure, just in case, we return type void (I know, wat?)

    return [null, "void"];
}

// process a script
// this method actually hooks into code generation :)

function processScript(context, script) {
    console.log("Compiling script:");
    console.log(script);

    // first element of the script block is the hat block
    // this determines when this function will be called
    // basically, this is used as a note to the runtime
    // and yes, scripts are functions :)

    var hatBlock = script[0];

    // TODO: implement hat blocks

    // emit a function definition

    emit("define void @" + hatBlock[0] + (functionCounter++) + "() {", 1);

    // for each block in the script, compile it!

    script.forEach(compileBlock);

    emit("}", -1);
}

// processes a child (basically a sprite)

function processChild(child) {
    // attach some metadata to tag the sprite

    child["86"] = {
        type: "sprite"
    };

    // sprites can have scripts
    // process those seperately

    if(typeof child.scripts !== 'undefined') {
        child.scripts.forEach(function(script) {
            processScript(child, script[2]);
        });
    }
}

module.exports = function(project, output) {
    project.children.forEach(function(child) {
        processChild(child);
    });

    fs.writeFile(output, LLVMOut.join("\n") + "\n");

    console.log("Backend stub");
}
<commit_msg>Implementation of addition + register tracking + constants :D<commit_after>/*
 * backend.js - backend for scratch86
 * entrypoint to the backend of scratch86 --
 * all code generation is done in this file or required files from here
 * HERE BE DRAGONS!
 */

var fs = require("fs");

//var processScript = require("./processScript");

var LLVMOut = [];
var indentStatus = 0;

function emit(line, indentation) {
    if(indentation < 0) indentStatus += indentation;

    var out = "";
    for(var i = 0; i < indentStatus; ++i) out += "    ";

    LLVMOut.push( out + line );

    if(indentation > 0) indentStatus += indentation;
}

var functionCounter = 0; // TODO: infer legitimate names for scripts

var functionContext = {
    registerCount: 0
};

function newRegister() {
    return "%" + (++functionContext.registerCount);
}

// compileBlock is the meat of the compiler
// it recursively emits IR to make stuff happen
// this is the real "HERE BE DRAGONS" <3
// its return type is a reference to the output of its operation
// (typically an IR register, a getelementptr, a constant, etc.),
// but in an array, where the second element is the type.
// type tracking is implemented this way to optimize the IR for Scratch's weird type rules.

function compileBlock(block, expectedType) {
    if(block[0] == "playSound:") {
        // heh, so sound isn't actually supported atm
        // TODO: actually implement sound
        // but, this block is used as a putchar ABI for testing scratch->LLVM until a graphics runtime is setup :)

        var argument = compileBlock(block[1], "i32");

        // just call putchar

        emit("call void @putchar(i32 " + argument[0] + ")");
    } else if(block[0] == '+') { // addition
        // recursively get arguments

        var argument0 = compileBlock(block[1], "i32");
        var argument1 = compileBlock(block[2], "i32");

        // TODO: typecheck the arguments to ensure we don't need to demote anything
        // in the future, compileBlock can refuse our type request and return a double instead
        // this is bad, because doubles are slow, but also necessary in some cases
        // the logic here would be to cast both arguments to doubles and then return as a double
        // yes, this causes a chain reaction. I'm sad too :(

        var register = newRegister();
        emit(register + " = add " + "i32" + " " + argument0[0] + ", " + argument1[0]);

        return [register, "i32"];
    } else if(!isNaN(block)) {
        // if the block is a number, we can probably just return it as is :)
        // TODO: infer type of whether it's an integer or a float

        return [block, "i32"];
    } else {
        console.error("Unknown block:");
        console.error(block);

        // return a stub value if needed

        if(expectedType == 'i8' || expectedType == 'i16' || expectedType == 'i32') {
            return ["0", expectedType];
        }
    }

    // if we're still here, it's probably a void block and not part of a chain :)
    // for good measure, just in case, we return type void (I know, wat?)

    return [null, "void"];
}

// process a script
// this method actually hooks into code generation :)

function processScript(context, script) {
    console.log("Compiling script:");
    console.log(script);

    // first element of the script block is the hat block
    // this determines when this function will be called
    // basically, this is used as a note to the runtime
    // and yes, scripts are functions :)

    var hatBlock = script[0];

    // TODO: implement hat blocks

    // emit a function definition

    emit("define void @" + hatBlock[0] + (functionCounter++) + "() {", 1);

    // for each block in the script, compile it!

    script.forEach(compileBlock);

    emit("}", -1);
}

// processes a child (basically a sprite)

function processChild(child) {
    // attach some metadata to tag the sprite

    child["86"] = {
        type: "sprite"
    };

    // sprites can have scripts
    // process those seperately

    if(typeof child.scripts !== 'undefined') {
        child.scripts.forEach(function(script) {
            processScript(child, script[2]);
        });
    }
}

module.exports = function(project, output) {
    project.children.forEach(function(child) {
        processChild(child);
    });

    fs.writeFile(output, LLVMOut.join("\n") + "\n");

    console.log("Backend stub");
}
<|endoftext|>


<commit_before>// import LogWatcher from 'hearthstone-log-watcher';

import {setWinCondition, setMatchId, setFor, setAgainst, setPlayerId, resetData, setStartTime, setEndTime} from './match-data-manipulation';
import {parseFriendlyPlayer, parseFriendlyPlayerById} from './parse-friendly-player';
import {isMyHero, isHeroCard} from './is-my-hero';
import findClass from './find-class';
import hasWon from './win-condition';

import debug from 'debug';

// TODO: case to be made whereby we turn the for and against values into object
// { playerName: 'foo', playerId: 1}
let dataStructure = {
  _id: "",
  playerId: "",
  startTime: "",
  endTime: "",
  for: "",
  against: "",
  log: [],
  hasWon: ""
};
let database = [];

// Define some debug logging functions for easy and readable debug messages.
let log = {
  main: debug('HT:LV')
};

//TODO: should live somewhere else;
const setHeroValues = (data) => {
  //TODO: write a test to cover the issue resolved in commit 8fcc506
  if (isHeroCard(data)) {
    if (isMyHero(data)) {
      dataStructure = setFor(dataStructure, findClass(data.cardName));
      dataStructure = setPlayerId(dataStructure, data.playerId);
    } else {
      dataStructure = setAgainst(dataStructure, findClass(data.cardName));
    }
  }
  return dataStructure;
};

const fixStartTime = (dataStructure) => {
  dataStructure.startTime = dataStructure.log[0].id;

  return dataStructure;
}

export function dataLogger (logWatcher, db) {

  logWatcher.on('game-start', () => {
    dataStructure = setMatchId(dataStructure);
    dataStructure = setStartTime(dataStructure);
    log.main('game start: %s', dataStructure._id);
  });

  logWatcher.on('game-over', (data) => {
    var winCondition;
    if(!dataStructure._id) {
      log.main('no game start event');
      log.main(data);
      log.main(parseFriendlyPlayerById(data, dataStructure.playerId));
      log.main(hasWon(parseFriendlyPlayerById(data, dataStructure.playerId)));
      dataStructure = setMatchId(dataStructure);
      dataStructure = fixStartTime(dataStructure);
      winCondition = hasWon(parseFriendlyPlayerById(data, dataStructure.playerId));
    } else {
      log.main('game started event');
      log.main(parseFriendlyPlayer(data));
      log.main(hasWon(parseFriendlyPlayer(data)));
      winCondition = hasWon(parseFriendlyPlayer(data));
    }
    dataStructure = setWinCondition(dataStructure, winCondition);
    dataStructure = setEndTime(dataStructure);
    log.main(dataStructure);
    db.put(dataStructure)
      .then(() => {
        // TODO: switch to immutable data and renable this
        dataStructure = resetData();
      }).catch((error) => {
        log.main(error);
      });
  });

  logWatcher.on('zone-change', (data) => {
    dataStructure = setHeroValues(data);
    data.id = Date.now();
    dataStructure.log.push(data);
  });

  return logWatcher;
}

export function getDatabase () {
  return database;
}
<commit_msg>Fix linitng issue<commit_after>// import LogWatcher from 'hearthstone-log-watcher';

import {setWinCondition, setMatchId, setFor, setAgainst, setPlayerId, resetData, setStartTime, setEndTime} from './match-data-manipulation';
import {parseFriendlyPlayer, parseFriendlyPlayerById} from './parse-friendly-player';
import {isMyHero, isHeroCard} from './is-my-hero';
import findClass from './find-class';
import hasWon from './win-condition';

import debug from 'debug';

// TODO: case to be made whereby we turn the for and against values into object
// { playerName: 'foo', playerId: 1}
let dataStructure = {
  _id: "",
  playerId: "",
  startTime: "",
  endTime: "",
  for: "",
  against: "",
  log: [],
  hasWon: ""
};
let database = [];

// Define some debug logging functions for easy and readable debug messages.
let log = {
  main: debug('HT:LV')
};

//TODO: should live somewhere else;
const setHeroValues = (data) => {
  //TODO: write a test to cover the issue resolved in commit 8fcc506
  if (isHeroCard(data)) {
    if (isMyHero(data)) {
      dataStructure = setFor(dataStructure, findClass(data.cardName));
      dataStructure = setPlayerId(dataStructure, data.playerId);
    } else {
      dataStructure = setAgainst(dataStructure, findClass(data.cardName));
    }
  }
  return dataStructure;
};

const fixStartTime = (dataStructure) => {
  dataStructure.startTime = dataStructure.log[0].id;

  return dataStructure;
};

export function dataLogger (logWatcher, db) {

  logWatcher.on('game-start', () => {
    dataStructure = setMatchId(dataStructure);
    dataStructure = setStartTime(dataStructure);
    log.main('game start: %s', dataStructure._id);
  });

  logWatcher.on('game-over', (data) => {
    var winCondition;
    if(!dataStructure._id) {
      log.main('no game start event');
      log.main(data);
      log.main(parseFriendlyPlayerById(data, dataStructure.playerId));
      log.main(hasWon(parseFriendlyPlayerById(data, dataStructure.playerId)));
      dataStructure = setMatchId(dataStructure);
      dataStructure = fixStartTime(dataStructure);
      winCondition = hasWon(parseFriendlyPlayerById(data, dataStructure.playerId));
    } else {
      log.main('game started event');
      log.main(parseFriendlyPlayer(data));
      log.main(hasWon(parseFriendlyPlayer(data)));
      winCondition = hasWon(parseFriendlyPlayer(data));
    }
    dataStructure = setWinCondition(dataStructure, winCondition);
    dataStructure = setEndTime(dataStructure);
    log.main(dataStructure);
    db.put(dataStructure)
      .then(() => {
        // TODO: switch to immutable data and renable this
        dataStructure = resetData();
      }).catch((error) => {
        log.main(error);
      });
  });

  logWatcher.on('zone-change', (data) => {
    dataStructure = setHeroValues(data);
    data.id = Date.now();
    dataStructure.log.push(data);
  });

  return logWatcher;
}

export function getDatabase () {
  return database;
}
<|endoftext|>