<commit_before>
// reuse-lang - a pure functional lisp-like language for writing
// reusable business-logic in an extremely portable way.
//
// Written in 2015 by Jesper Oskarsson jesosk@gmail.com
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain worldwide.
// This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.

var ast = require('../lib/ast-builder');

exports.parse = function (program) {
    var index = 0,
        root = null,
        current = null,
        openBraces = 0,
        value = null;

    if (program.length === 0) {
        return {error: null, value: null};
    }

    while (index < program.length) {
        if (program[index] === '(') {
            var list = ast([]);
            list.parent = current;

            if (current) {
                current.elements.push(list);
            }

            current = list;
            if (root === null) {
                root = list;
            }

            openBraces += 1;

            index += 1;

        } else if (program[index] === ')') {
            if (current === null) {
                return {error: new Error('unbalanced-parentheses')};
            }
            current = current.parent;
            openBraces -= 1;
            index += 1;

        } else if (program[index] === ' ' ||
                   program[index] === '\t' ||
                   program[index] === '\n' ||
                   program[index] === '\r') {
            index += 1;

        } else {
            var start = index;
            while (index < program.length &&
                   program[index] !== ' ' &&
                   program[index] !== '\t' &&
                   program[index] !== '\n' &&
                   program[index] !== '\r' &&
                   program[index] !== ')') {
                index += 1;
            }

            var atom = ast(program.slice(start, index));

            if (!current) {
                value = atom;
            } else {
                current.elements.push(atom);
                atom.parent = current;
            }
        }
    }

    if (openBraces !== 0) {
        return {error: new Error('unbalanced-parentheses')};
    }

    return {error: null, value: root || value};
};
<commit_msg>Refactored parser<commit_after>
// reuse-lang - a pure functional lisp-like language for writing
// reusable business-logic in an extremely portable way.
//
// Written in 2015 by Jesper Oskarsson jesosk@gmail.com
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain worldwide.
// This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.

var ast = require('../lib/ast-builder');

var UNBALANCED_PARENTHESES_ERROR = {error: new Error('unbalanced-parentheses')};

var isSpace = function (character) {
    return character === ' ' ||
           character === '\t' ||
           character === '\n' ||
           character === '\r';
};

var isPartOfAtom = function (character) {
    return !isSpace(character) && character !== ')';
};

var consume = function (predicate, program, state) {
    if (state.index < program.length && predicate(program[state.index])) {
        state.index++;
        return true;
    }
};

var consumeToken = function (token, program, state) {
    return consume(function (character) { return character === token; }, program, state);
}

var consumeSpace = function (program, state) {
    return consume(isSpace, program, state);
}

var consumePartOfAtom = function(program, state) {
    return consume(isPartOfAtom, program, state);
}

var parseAtom = function (program, state) {
    var start = state.index;
    while (consumePartOfAtom(program, state)) {}
    return ast(program.slice(start, state.index));
};

exports.parse = function (program) {
    var root = null,
        current = null,
        openBraces = 0,
        value = null;

    var state = {
        index: 0
    };

    if (program.length === 0) {
        return {error: null, value: null};
    }

    while (state.index < program.length) {
        if (consumeToken('(', program, state)) {
            var list = ast([]);
            list.parent = current;

            if (current) {
                current.elements.push(list);
            }

            current = list;
            if (root === null) {
                root = list;
            }

            openBraces += 1;

        } else if (consumeToken(')', program, state)) {
            if (current === null) {
                return UNBALANCED_PARENTHESES_ERROR;
            }
            current = current.parent;
            openBraces -= 1;

        } else if (consumeSpace(program, state)) {
        } else {
            var atom = parseAtom(program, state);

            if (!current) {
                value = atom;
            } else {
                current.elements.push(atom);
                atom.parent = current;
            }
        }
    }

    if (openBraces !== 0) {
        return UNBALANCED_PARENTHESES_ERROR;
    }

    return {error: null, value: root || value};
};
<|endoftext|>


<commit_before>/*
Copyright (c) 2011 Sam Decrock <sam.decrock@gmail.com>

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

var querystring = require('querystring');
var https = require('https');
var http = require('http');
var url = require('url');

exports.doRequest = function(o, callback){
	var responsebody = "";
	var params;

	var reqUrl = url.parse(o.url);
	var path = reqUrl.path;

	var port = 80;
	if(reqUrl.protocol == 'https:')
		port = 443;

	if(o.method == 'POST' && o.options){
		params = querystring.stringify(o.options);
	}else if(o.method == 'GET' && o.options){
		path += "?" + querystring.stringify(o.options);
	}

	var requestoptions = {
		host: reqUrl.hostname,
		port: port,
		path: path,
		method: o.method,
		headers: {}
	};

	if(params){
		requestoptions['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
		requestoptions['headers']['Content-Length'] = params.length;
	}

	if(o.cookies){
		requestoptions['headers']['Cookie'] = o.cookies.join("; ");
	}

	if(o.headers){
		for(var headerkey in o.headers){
			requestoptions['headers'][headerkey] = o.headers[headerkey];
		}
	}

	function requestResponse(res){
		res.setEncoding('utf8');

		res.on('data', function (chunk) {
			responsebody += chunk;
		});

		res.on('end', function (err) {
			callback(null, {headers: res.headers, body: responsebody});
		});

		res.on('close', function (err) {
			callback(err);
		});
	}

	var request;

	if(reqUrl.protocol == 'https:')
		request = https.request(requestoptions, requestResponse);
	else
		request = http.request(requestoptions, requestResponse);

	if(params)
		request.write(params);

	request.end();
};

exports.uploadFile = function(o, callback){
	var responsebody = "";

	var reqUrl = url.parse(o.url);

	var port = 80;
	if(reqUrl.protocol == 'https:')
		port = 443;

	var crlf = "\r\n";
	var boundary = '---------------------------10102754414578508781458777923';
	var separator = '--' + boundary;

	var bufferArray = new Array();

	for(var key in o.options){
		var optionsData = separator + crlf
			+ 'Content-Disposition: form-data; name="'+encodeURIComponent(key)+'"' + crlf
			+ crlf
			+ encodeURIComponent(o.options[key]) + crlf;

		bufferArray.push(new Buffer(optionsData));
	}

	for(var file in o.files){
		var filepath = o.files[file];
		var filename = filepath.replace(/\\/g,'/').replace( /.*\//, '' );

		var fileData = separator + crlf
			+ 'Content-Disposition: file; name="' + file + '"; filename="' + filename + '"' + crlf
			+ 'Content-Type: application/octet-stream' +  crlf
			+ crlf;

		bufferArray.push(new Buffer(fileData));
		bufferArray.push(require("fs").readFileSync(filepath));
	}

	var footer = crlf + separator + '--' + crlf;
	bufferArray.push(new Buffer(footer));

	var multipartBody = Buffer.concat(bufferArray);

	var requestoptions = {
		host: reqUrl.hostname,
		port: port,
		path: reqUrl.path,
		method: 'POST',
		headers: {}
	};

	requestoptions['headers']['Content-Type'] = 'multipart/form-data; boundary=' + boundary;
	requestoptions['headers']['Content-Length'] = multipartBody.length;

	if(o.cookies){
		requestoptions['headers']['Cookie'] = o.cookies.join("; ");
	}

	if(o.headers){
		for(var headerkey in o.headers){
			requestoptions['headers'][headerkey] = o.headers[headerkey];
		}
	}

	function requestResponse(res){
		res.setEncoding('utf8');

		res.on('data', function (chunk) {
			responsebody += chunk;
		});

		res.on('end', function (err) {
			callback(null, {headers: res.headers, body: responsebody});
		});

		res.on('close', function (err) {
			callback(err);
		});
	}

	var request;

	if(reqUrl.protocol == 'https:')
		request = https.request(requestoptions, requestResponse);
	else
		request = http.request(requestoptions, requestResponse);

	request.write(multipartBody);

	request.end();
}

<commit_msg>port fix + better error handling<commit_after>/*
Copyright (c) 2011 Sam Decrock <sam.decrock@gmail.com>

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

var querystring = require('querystring');
var https = require('https');
var http = require('http');
var url = require('url');

exports.doRequest = function(o, callback){
	var responsebody = "";
	var params;

	var reqUrl = url.parse(o.url);
	var path = reqUrl.path;

	var port;

	if(reqUrl.port){
		port = reqUrl.port;
	}else if(reqUrl.protocol == 'https:'){
		port = 443;
	}else{
		port = 80;
	}

	if(o.method == 'POST' && o.options){
		params = querystring.stringify(o.options);
	}else if(o.method == 'GET' && o.options){
		path += "?" + querystring.stringify(o.options);
	}

	var requestoptions = {
		host: reqUrl.hostname,
		port: port,
		path: path,
		method: o.method,
		headers: {}
	};

	if(params){
		requestoptions['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
		requestoptions['headers']['Content-Length'] = params.length;
	}

	if(o.cookies){
		requestoptions['headers']['Cookie'] = o.cookies.join("; ");
	}

	if(o.headers){
		for(var headerkey in o.headers){
			requestoptions['headers'][headerkey] = o.headers[headerkey];
		}
	}

	function requestResponse(res){
		res.setEncoding('utf8');

		res.on('data', function (chunk) {
			responsebody += chunk;
		});

		res.on('end', function (err) {
			callback(null, {headers: res.headers, body: responsebody});
		});

		res.on('close', function (err) {
			callback(err);
		});
	}

	var request;

	if(reqUrl.protocol == 'https:')
		request = https.request(requestoptions, requestResponse);
	else
		request = http.request(requestoptions, requestResponse);

	request.on('error', function (err) {
		callback(err);
	});

	if(params)
		request.write(params);

	request.end();
};

exports.uploadFile = function(o, callback){
	var responsebody = "";

	var reqUrl = url.parse(o.url);

	var port = 80;
	if(reqUrl.protocol == 'https:')
		port = 443;

	var crlf = "\r\n";
	var boundary = '---------------------------10102754414578508781458777923';
	var separator = '--' + boundary;

	var bufferArray = new Array();

	for(var key in o.options){
		var optionsData = separator + crlf
			+ 'Content-Disposition: form-data; name="'+encodeURIComponent(key)+'"' + crlf
			+ crlf
			+ encodeURIComponent(o.options[key]) + crlf;

		bufferArray.push(new Buffer(optionsData));
	}

	for(var file in o.files){
		var filepath = o.files[file];
		var filename = filepath.replace(/\\/g,'/').replace( /.*\//, '' );

		var fileData = separator + crlf
			+ 'Content-Disposition: file; name="' + file + '"; filename="' + filename + '"' + crlf
			+ 'Content-Type: application/octet-stream' +  crlf
			+ crlf;

		bufferArray.push(new Buffer(fileData));
		bufferArray.push(require("fs").readFileSync(filepath));
	}

	var footer = crlf + separator + '--' + crlf;
	bufferArray.push(new Buffer(footer));

	var multipartBody = Buffer.concat(bufferArray);

	var requestoptions = {
		host: reqUrl.hostname,
		port: port,
		path: reqUrl.path,
		method: 'POST',
		headers: {}
	};

	requestoptions['headers']['Content-Type'] = 'multipart/form-data; boundary=' + boundary;
	requestoptions['headers']['Content-Length'] = multipartBody.length;

	if(o.cookies){
		requestoptions['headers']['Cookie'] = o.cookies.join("; ");
	}

	if(o.headers){
		for(var headerkey in o.headers){
			requestoptions['headers'][headerkey] = o.headers[headerkey];
		}
	}

	function requestResponse(res){
		res.setEncoding('utf8');

		res.on('data', function (chunk) {
			responsebody += chunk;
		});

		res.on('end', function (err) {
			callback(null, {headers: res.headers, body: responsebody});
		});

		res.on('close', function (err) {
			callback(err);
		});
	}

	var request;

	if(reqUrl.protocol == 'https:')
		request = https.request(requestoptions, requestResponse);
	else
		request = http.request(requestoptions, requestResponse);

	request.on('error', function (err) {
		callback(err);
	});

	request.write(multipartBody);

	request.end();
}

<|endoftext|>


<commit_before>var _ = require('underscore');
var fs = require('fs');
var url = require('url');
var path = require('path');
var Promise = require('promise');
var request = require('request');
var cheerio = require('cheerio');
var cssParse = require('css-parse');

var util = require('./util');

/**
 * Get promised request
 * @param {Object} options
 * @returns {Promise}
 */
function requestSync(options) {
    return new Promise(function(resolve, reject) {
        request(options, function(error, response) {
            if (!error && response.statusCode === 200) {
                resolve(response);
            } else if (!error) {
                reject('Status code is ' + response.statusCode);
            } else {
                reject(error);
            }
        });
    });
}

/**
 * Parser class
 * @param {Array} urls
 * @param {Array} files
 * @param {Array} styles
 * @constructor
 */
function Parser(urls, files, styles, options) {
    this.urls = urls;
    this.files = files;
    this.styles = styles;
    this.options = options;

    this.cssFiles = [];
    this.sassFiles = [];
    this.lessFiles = [];
    this.stylusFiles = [];

    this.files.forEach(function(file) {
        var extname = path.extname(file);
        switch (extname) {
            case '.css':
                this.cssFiles.push(file);
                break;
            case '.less':
                this.lessFiles.push(file);
                break;
            case '.styl':
            case '.stylus':
                this.stylusFiles.push(file);
                break;
        }
    }, this);
}

/**
 * Parse css data
 * @param {Function} callback
 */
Parser.prototype.parse = function(callback) {

    // object to return
    var result = {
        cssString: '',
        cssSize: 0,
        styleElements: 0,
        mediaQueries: 0,
        cssFiles: 0,
        rules: [],
        selectors: [],
        declarations: []
    };

    var that = this;

    // remote file requests
    var requestPromises = [];
    this.urls.forEach(function(url) {
        var options = that.options.customHttpHeaders;
        options.url = url;
        requestPromises.push(requestSync(options));
    });

    // css string array from arguments
    // they will be joined into css string
    this.cssFiles.forEach(function(cssFile) {
        // push local css data
        that.styles.push(fs.readFileSync(cssFile, {
            encoding: 'utf8'
        }));
    });
    // LESS compile
    if (this.lessFiles.length !== 0) {
        var less = require('less');
        this.lessFiles.forEach(function(lessFile) {
            var parser = new(less.Parser)({
                filename: lessFile
            });
            var promise = new Promise(function(resolve, reject) {
                var string = fs.readFileSync(lessFile, 'utf8');
                parser.parse(string, function(error, tree) {
                    if (error) {
                        reject(error);
                    }
                    resolve(tree.toCSS());
                });
            });
            requestPromises.push(promise);
        });
    }
    // Stylus compile
    if (this.stylusFiles.length !== 0) {
        var stylus = require('stylus');
        this.stylusFiles.forEach(function(stylusFile) {
            var promise = new Promise(function(resolve, reject) {
                var string = fs.readFileSync(stylusFile, 'utf8');
                stylus(string)
                    .set('filename', stylusFile)
                    .render(function(error, css) {
                        if (error) {
                            reject(error);
                        }
                        resolve(css);
                    });
            });
            requestPromises.push(promise);
        });
    }

    // get remote files
    Promise.all(requestPromises).then(function onFulfilled(results) {

        // requests to stylesheet defined in html
        var requestPromisesInner = [];

        results.forEach(function(result) {
            if (util.isCSS(result)) {
                that.styles.push(result);
            } else {
                // push remote css data
                var type = result.headers['content-type'];
                if (type.indexOf('html') > -1) {
                    // parse result body
                    var $ = cheerio.load(result.body);
                    var $link = $('link[rel=stylesheet]');
                    var $style = $('style');

                    // add css file count
                    result.cssFiles += $link.length;
                    result.styleElements += $style.length;

                    // request link[href]
                    $link.each(function() {
                        var relPath = $(this).attr('href');
                        var absPath = url.resolve(result.request.href, relPath);
                        var options = that.options.customHttpHeaders;
                        options.url = absPath;
                        requestPromisesInner.push(requestSync(options));
                    });

                    // add text in style tags
                    $style.each(function() {
                        that.styles.push($(this).text());
                    });
                } else if (type.indexOf('css') > -1) {
                    that.styles.push(result.body);
                } else {
                    throw new Error('Content type is not HTML or CSS!');
                }
            }
        });

        if (requestPromisesInner.length > 0) {
            return Promise.all(requestPromisesInner);
        } else {
            return true;
        }
    }).done(function onFulfilled(results) {
        if (Array.isArray(results)) {
            results.forEach(function(result) {
                that.styles.push(result.body);
            });
        }

        // join all css string
        result.cssString = that.styles.join('');
        result.cssSize = Buffer.byteLength(result.cssString, 'utf8');

        // parse css string
        var rawRules = [];

        try {
            rawRules = cssParse(result.cssString).stylesheet.rules;
        } catch (error) {
            throw error;
        }

        // add rules into result
        rawRules.forEach(function(rule) {
            if (rule.type === 'rule') {
                result.rules.push(rule);
            } else if (rule.type === 'media') {
                result.mediaQueries += 1;
                rule.rules.forEach(function(rule) {
                    if (rule.type === 'rule') {
                        result.rules.push(rule);
                    }
                });
            }
        });

        // add selectors and declarations into result
        result.rules.forEach(function(rule) {
            rule.selectors.forEach(function(selector) {
                result.selectors.push(selector);
            });
            rule.declarations.forEach(function(declaration) {
                if (declaration.type === 'declaration') {
                    result.declarations.push(declaration);
                }
            });
        });
        if (_.isFunction(callback)) {
            callback(null, result);
        }
    }, function onRejected(error) {
        if (_.isFunction(callback)) {
            callback(error, null);
        }
    });
};

// export
module.exports = Parser;<commit_msg>Fix bug no count stylesheets<commit_after>var _ = require('underscore');
var fs = require('fs');
var url = require('url');
var path = require('path');
var Promise = require('promise');
var request = require('request');
var cheerio = require('cheerio');
var cssParse = require('css-parse');

var util = require('./util');

/**
 * Get promised request
 * @param {Object} options
 * @returns {Promise}
 */
function requestSync(options) {
    return new Promise(function(resolve, reject) {
        request(options, function(error, response) {
            if (!error && response.statusCode === 200) {
                resolve(response);
            } else if (!error) {
                reject('Status code is ' + response.statusCode);
            } else {
                reject(error);
            }
        });
    });
}

/**
 * Parser class
 * @param {Array} urls
 * @param {Array} files
 * @param {Array} styles
 * @constructor
 */
function Parser(urls, files, styles, options) {
    this.urls = urls;
    this.files = files;
    this.styles = styles;
    this.options = options;

    this.cssFiles = [];
    this.sassFiles = [];
    this.lessFiles = [];
    this.stylusFiles = [];

    this.files.forEach(function(file) {
        var extname = path.extname(file);
        switch (extname) {
            case '.css':
                this.cssFiles.push(file);
                break;
            case '.less':
                this.lessFiles.push(file);
                break;
            case '.styl':
            case '.stylus':
                this.stylusFiles.push(file);
                break;
        }
    }, this);
}

/**
 * Parse css data
 * @param {Function} callback
 */
Parser.prototype.parse = function(callback) {

    // object to return
    var parseData = {
        cssString: '',
        cssSize: 0,
        styleElements: 0,
        mediaQueries: 0,
        cssFiles: 0,
        rules: [],
        selectors: [],
        declarations: []
    };

    var that = this;

    // remote file requests
    var requestPromises = [];
    this.urls.forEach(function(url) {
        var options = that.options.customHttpHeaders;
        options.url = url;
        requestPromises.push(requestSync(options));
    });

    // css string array from arguments
    // they will be joined into css string
    this.cssFiles.forEach(function(cssFile) {
        // push local css data
        that.styles.push(fs.readFileSync(cssFile, {
            encoding: 'utf8'
        }));
    });
    // LESS compile
    if (this.lessFiles.length !== 0) {
        var less = require('less');
        this.lessFiles.forEach(function(lessFile) {
            var parser = new(less.Parser)({
                filename: lessFile
            });
            var promise = new Promise(function(resolve, reject) {
                var string = fs.readFileSync(lessFile, 'utf8');
                parser.parse(string, function(error, tree) {
                    if (error) {
                        reject(error);
                    }
                    resolve(tree.toCSS());
                });
            });
            requestPromises.push(promise);
        });
    }
    // Stylus compile
    if (this.stylusFiles.length !== 0) {
        var stylus = require('stylus');
        this.stylusFiles.forEach(function(stylusFile) {
            var promise = new Promise(function(resolve, reject) {
                var string = fs.readFileSync(stylusFile, 'utf8');
                stylus(string)
                    .set('filename', stylusFile)
                    .render(function(error, css) {
                        if (error) {
                            reject(error);
                        }
                        resolve(css);
                    });
            });
            requestPromises.push(promise);
        });
    }

    // get remote files
    Promise.all(requestPromises).then(function onFulfilled(results) {

        // requests to stylesheet defined in html
        var requestPromisesInner = [];

        results.forEach(function(result) {
            if (util.isCSS(result)) {
                that.styles.push(result);
            } else {
                // push remote css data
                var type = result.headers['content-type'];
                if (type.indexOf('html') > -1) {
                    // parse result body
                    var $ = cheerio.load(result.body);
                    var $link = $('link[rel=stylesheet]');
                    var $style = $('style');

                    // add css file count
                    parseData.cssFiles += $link.length;
                    parseData.styleElements += $style.length;

                    // request link[href]
                    $link.each(function() {
                        var relPath = $(this).attr('href');
                        var absPath = url.resolve(result.request.href, relPath);
                        var options = that.options.customHttpHeaders;
                        options.url = absPath;
                        requestPromisesInner.push(requestSync(options));
                    });

                    // add text in style tags
                    $style.each(function() {
                        that.styles.push($(this).text());
                    });
                } else if (type.indexOf('css') > -1) {
                    that.styles.push(result.body);
                } else {
                    throw new Error('Content type is not HTML or CSS!');
                }
            }
        });

        if (requestPromisesInner.length > 0) {
            return Promise.all(requestPromisesInner);
        } else {
            return true;
        }
    }).done(function onFulfilled(results) {
        if (Array.isArray(results)) {
            results.forEach(function(result) {
                that.styles.push(result.body);
            });
        }

        // join all css string
        parseData.cssString = that.styles.join('');
        parseData.cssSize = Buffer.byteLength(parseData.cssString, 'utf8');

        // parse css string
        var rawRules = [];

        try {
            rawRules = cssParse(parseData.cssString).stylesheet.rules;
        } catch (error) {
            throw error;
        }

        // add rules into result
        rawRules.forEach(function(rule) {
            if (rule.type === 'rule') {
                parseData.rules.push(rule);
            } else if (rule.type === 'media') {
                parseData.mediaQueries += 1;
                rule.rules.forEach(function(rule) {
                    if (rule.type === 'rule') {
                        parseData.rules.push(rule);
                    }
                });
            }
        });

        // add selectors and declarations into result
        parseData.rules.forEach(function(rule) {
            rule.selectors.forEach(function(selector) {
                parseData.selectors.push(selector);
            });
            rule.declarations.forEach(function(declaration) {
                if (declaration.type === 'declaration') {
                    parseData.declarations.push(declaration);
                }
            });
        });
        if (_.isFunction(callback)) {
            callback(null, parseData);
        }
    }, function onRejected(error) {
        if (_.isFunction(callback)) {
            callback(error, null);
        }
    });
};

// export
module.exports = Parser;<|endoftext|>


<commit_before>/*
  Parser
  Parses clean source. Generates clean AST.
*/
const opPrec = require('./operatorPrecedence')
const estemplate = require('./estemplate')
const updateAst = require('./astupdate')

/*  Utility functions  */
const mayBe = (value, func) => value === null ? null : func(...value)
const parenCheck = src => mayBe(parser.regex(/^(\))((.|\n)*)$/)(src),
                              (m, val, rest) => returnRest(val, src, src.str))

const returnRest = (val, input, rest, field) => {
  const output = JSON.parse(JSON.stringify(input))
  if (field) {
    let value = field.value
    switch (field.name) {
      case 'indent':
        output.indent = value
        output.column = value
        break
      case 'return':
        output.column = 1
        output.line += value
        break
      case 'column':
        output.column += value
        break
    }
  }
  output.str = rest
  return [val, output]
}

/*  Predefined regexes */
const spaceRegex = /^([ \t]+)((.|\n)*)$/
const returnRegex = /^(\n)((.|\n)*)$/
const idRegex = /^([a-zA-Z]+[a-zA-Z0-9_]*)((.|\n)*)$/
const numRegex = /^((?:\d+(?:\.\d*)?|\.\d+)(?:[e][+-]?\d+)?)((.|\n)*)$/
const boolRegex = /^(true|false)((.|\n)*)$/i
const stringRegex = /^('[^\\']*(?:\\.[^\\']*)*')((.|\n)*)$/
const binaryOperatorRegex = /^(\+\+|\+|-|\/|\*|<<|<=|<|>>>|>>|>=|>|&&|&|\|\||\||\^|==)((.|\n)*)$/
const unaryOperatorRegex = /^(:type|-|!)((.|\n)*)$/

/*
  Parser factory. Used to create parsers
  parser.regex - creates parser for given regex
  parser.bind - applies monadic bind on parsers
  parser.all - All parsers supplied MUST match
  parser.any - ANY ONE of the parsers need match
*/

const parser = {}

parser.regex = regex => src => mayBe(
  regex.exec(src.str),
  (m, val, rest) => returnRest(val, src, rest, {'name': 'column', 'value': val.length})
)

parser.bind = (mv, mf) => input => mayBe(
  mv(input),
  (val, rest) => mf(val)(rest)
)

parser.all = (...parsers) => src => {
  var rest = src
  var values = []
  for (let parser of parsers) {
    let result = parser(rest)
    if (result === null) return null
    values.push(result[0])
    rest = result[1]
  }
  return [values, rest]
}

parser.any = (...parsers) => src => {
  for (let parser of parsers) {
    let result = parser(src)
    if (result !== null) return result
  }
  return null
}

/*
  All required parsers are created below
*/
var spaceParser = parser.regex(spaceRegex)

var equalSignParser = parser.regex(/^(\s+=\s+)((.|\n)*)$/)

var thinArrowParser = parser.regex(/^(\s*->\s+)((.|\n)*)$/)

var slashParser = parser.regex(/^(\s*\\)((.|\n)*)$/)

var letParser = parser.regex(/^(\s*let\s+)((.|\n)*)$/)

var inParser = parser.regex(/^(\s*in\s+)((.|\n)*)$/)

var dotParser = parser.regex(/^(\.)((.|\n)*)$/)

var ifParser = parser.regex(/^(if\s+)((.|\n)*)$/)
var thenParser = parser.regex(/^(then\s+)((.|\n)*)$/)
var elseParser = parser.regex(/^(else\s+)((.|\n)*)$/)

var indentParser = input => mayBe(
  spaceRegex.exec(input),
  (a, space, rest) => [space, rest]
)

var returnParser = input => mayBe(
  returnRegex.exec(input.str),
  (a, newLine, rest) => returnRest(newLine, input, rest, {'name': 'return', 'value': newLine.length})
)

var numberParser = input => mayBe(
  numRegex.exec(input.str),
  (a, num, rest) => returnRest(estemplate.literal(num, num), input, rest, {'name': 'column', 'value': num.length})
)

var identifierParser = input => mayBe(
  idRegex.exec(input.str),
  (a, name, rest) => returnRest(estemplate.identifier(name), input, rest, {'name': 'column', 'value': name.length})
)

var stringParser = input => mayBe(
  stringRegex.exec(input.str),
  (a, string, rest) => returnRest(estemplate.stringLiteral(string.replace(/(^')/, '').replace(/('$)/, '')),
                                    input, rest, {'name': 'column', 'value': string.length})
)

var booleanParser = input => mayBe(
    boolRegex.exec(input.str),
    (a, bool, rest) => returnRest(estemplate.boolLiteral(bool), input, rest, {'name': 'column', 'value': bool.length})
  )

var parenthesisParser = parser.bind(
  parser.bind(
  parser.bind(
  parser.bind(
    input => input.str.startsWith('(')
      ? returnRest('(', input, input.str.substr(1), {'name': 'column', 'value': 1})
      : null,
    val => input => {
      const space = spaceParser(input)
      return space ? [space[0], space[1]] : [null, input]
    }),
    val => input => mayBe(
      parser.any(ifExprParser, binaryExprParser, fnCallParser, expressionParser)(input),
      (v, rest) => returnRest(v, input, rest.str)
    )),
    val => input => {
      var space = spaceParser(input)
      return space ? [val, space[1]] : [val, input]
    }),
    val => input => input.str.startsWith(')')
      ? returnRest(val, input, input.str.substr(1), {'name': 'column', 'value': 1})
      : null
)

var expressionParser = parser.any(parenthesisParser, booleanParser, identifierParser, numberParser, stringParser)

var unaryOperatorParser = input => mayBe(
    unaryOperatorRegex.exec(input.str),
    (m, operator, rest) => returnRest(operator, input, rest, {'name': 'column', 'value': operator.length})
  )

var unaryExprParser = parser.bind(
  parser.bind(
    unaryOperatorParser,
    operator => rest => operator === ':type'
      ? spaceParser(rest) !== null ? ['typeof', spaceParser(rest)[1]] : null
      : [operator, rest]),
  operator => rest => mayBe(expressionParser(rest),
    (argument, rest) => [estemplate.unaryExpression(operator, argument), rest])
)

var binaryOperatorParser = parser.regex(binaryOperatorRegex)

var declParser = parser.bind(
  parser.bind(
    identifierParser,
    val => input => mayBe(
        equalSignParser(input),
        (v, rest) => [val, rest]
      )
  ),
  val => input => mayBe(
    parser.any(unaryExprParser, letExpressionParser, ifExprParser, binaryExprParser, fnCallParser, expressionParser)(input),
        (v, rest) => {
          return returnRest(estemplate.declaration(val, v), input, rest.str)
        }
      )
)

var paramParser = parser.all(spaceParser, parser.any(identifierParser, numberParser))

var paramsParser = (str, paramArray = []) => {
  var param = paramParser(str)
  return (param !== null) ? paramsParser(param[1], paramArray.concat(param[0][1]))
                          : [paramArray, str]
}

var fnDeclParser = parser.bind(
  parser.bind(
    parser.bind(
      identifierParser,
      val => input => mayBe(
        paramsParser(input),
        (params, rest) => returnRest(estemplate.funcDeclaration(val, params), input, rest.str)
      )
    ),
    val => input => mayBe(
        equalSignParser(input),
        (v, rest) => [val, rest]
      )
  ),
  val => input => mayBe(
    parser.any(unaryExprParser, letExpressionParser, ifExprParser, binaryExprParser, fnCallParser, expressionParser)(input),
      (v, rest) => {
        val.declarations[0].init.body = v
        return returnRest(val, input, rest.str)
      }
    )
)

var lambdaParamParser = parser.all(identifierParser, spaceParser)

var lambdaParamsParser = (str, lambdaparamArray = []) => {
  var arg = lambdaParamParser(str)
  if (arg !== null) return lambdaParamsParser(arg[1], lambdaparamArray.concat(arg[0][0]))
  return [lambdaparamArray, str]
}

var lambdaParser = parser.bind(
  parser.bind(
    parser.bind(
      slashParser,
      val => input => mayBe(
        lambdaParamsParser(input),
        (params, rest) => returnRest(estemplate.lambda(params), input, rest.str)
       )
      ),
    val => input => mayBe(
      thinArrowParser(input),
      (v, rest) => returnRest(val, input, rest.str)
    )
   ),
   val => input => mayBe(
     expressionParser(input),
     (v, rest) => {
       val.expression.body = v
       return returnRest(val, input, rest.str)
     }
   )
 )

var letParamParser = parser.all(expressionParser, equalSignParser, expressionParser, spaceParser)

var letParamsParser = (str, letIdArray = [], letLiteralArray = []) => {
  var param = letParamParser(str)
  if (param !== null) return letParamsParser(param[1], letIdArray.concat(param[0][0]), letLiteralArray.concat(param[0][2]))
  return [letIdArray, letLiteralArray, str]
}

var letExpressionParser = parser.bind(
  parser.bind(
    parser.bind(
      letParser,
      val => input => mayBe(
          letParamsParser(input),
          (val1, val2, rest) => returnRest(estemplate.letExpression(val1, val2), input, rest.str)
       )
    ),
    val => input => mayBe(
        inParser(input),
        (v, rest) => returnRest(val, input, rest.str)
      )
  ),
  val => input => mayBe(
      parser.any(binaryExprParser, fnCallParser, expressionParser)(input),
      (v, rest) => {
        val.expression.callee.body = v
        return returnRest(val, input, rest.str)
      }
    )
  )

var memberPropParser = parser.all(identifierParser, dotParser)

var memberPropsParser = (str, memberArray = []) => {
  var result = memberPropParser(str)
  if (result !== null) return memberPropsParser(result[1], memberArray.concat(result[0][0]))
  if (result === null && memberArray.length === 0) return null
  var property = identifierParser(str)
  if (property === null) return null
  let tree = memberExprParser(memberArray.concat(property[0]))
  return [tree, property[1]]
}

var memberExprParser = (str, tree = {}) => {
  let memExpr = estemplate.memberExpression
  tree = memExpr(str[0], str[1])
  for (let i = 2; i < str.length; i++) {
    tree = memExpr(tree.expression, str[i])
  }
  return tree
}

var argsParser = (input, argArray = []) => {
  var arg = parser.all(
              parser.any(unaryExprParser, expressionParser),
              parser.any(returnParser, parenCheck, spaceParser))(input)
  if (arg === null) return argArray.length === 0 ? null : [argArray, input]
  let [[argument, nextChar], rest] = arg
  if (nextChar === '\n' || nextChar === ')') {
    rest.str = nextChar === '\n' ? '\n' + rest.str : rest.str
    return [argArray.concat(argument), rest]
  }
  return argsParser(rest, argArray.concat(argument))
}

var fnCallParser = parser.bind(
  parser.all(parser.any(memberPropsParser, identifierParser), spaceParser),
  val => input => mayBe(
      argsParser(input),
      (args, rest) => val[1] === 'n' ? null : returnRest(estemplate.fnCall(val[0], args), input, rest.str)
    )
)

var ifExprParser = input => mayBe(
  parser.all(
    ifParser, expressionParser,
    spaceParser, thenParser, expressionParser,
    spaceParser, elseParser, expressionParser)(input),
    (val, rest) => {
      let [, condition, , , consequent, , , alternate] = val
      return returnRest(estemplate.ifthenelse(condition, consequent, alternate), input, rest.str)
    }
)
var multiLineParser = src => {
  if (src.length < 2) return src
  if (!indentParser(src[1])) return src
  const lead = src.splice(0, 1)
  const follow = src.splice(0, 1)
  src.unshift(lead + follow)
  return multiLineParser(src)
}

var statementParser = parser.any(returnParser, declParser, ifExprParser, fnDeclParser, fnCallParser, lambdaParser)

var programParser = (input, ast = estemplate.ast()) => {
  let result = statementParser(returnRest('', input, multiLineParser(input.str.split('\n')).join('\n'))[1])
  if (result === null) return updateAst(ast)
  if (typeof result[0] !== 'string') ast.body.push(result[0])
  return programParser(result[1], ast)
}

/* helper functions for binaryExprParser */
const precedence = operator => opPrec[operator].prec
const associativity = operator => opPrec[operator].assoc
const current = parser.any(unaryExprParser, binaryOperatorParser, spaceParser, fnCallParser, expressionParser)
const isBinaryOperator = token => opPrec[token] !== undefined
const isExpression = token => token.type !== undefined

var binaryExprParser = src => {
  let opStack = ['$']
  let operandStack = []
  let biExpr = estemplate.binaryExpression
  var descender = s => {
    let currentToken = current(s)
    let [token, rest] = currentToken === null ? [null, s] : currentToken
    let topOfOpStack = opStack[opStack.length - 1]

    if (token === null) {
      if (topOfOpStack !== '$') {
        let [rightOperand, operator, leftOperand] = [operandStack.pop(), opStack.pop(), operandStack.pop()]
        operandStack.push(biExpr(leftOperand, operator, rightOperand))
        return descender(rest)
      }
      return operandStack.length === 0 && opStack.length === 1 ? null : [operandStack.pop(), rest]
    }

    if (isExpression(token)) {
      operandStack.push(token)
      return descender(rest)
    }
    if (isBinaryOperator(token)) { // check operator stack
      if (precedence(token) > precedence(topOfOpStack)) {
        opStack.push(token)
        return descender(rest)
      }

      if (precedence(token) < precedence(topOfOpStack)) {
        let [rightOperand, operator, leftOperand] = [operandStack.pop(), opStack.pop(), operandStack.pop()]
        operandStack.push(biExpr(leftOperand, operator, rightOperand))
        opStack.push(token)
        return descender(rest)
      }
      if (associativity(token) === associativity(topOfOpStack)) {
        if (associativity(token) === 'R') {
          opStack.push(token)
          return descender(rest)
        }
        let [rightOperand, operator, leftOperand] = [operandStack.pop(), opStack.pop(), operandStack.pop()]
        operandStack.push(biExpr(leftOperand, operator, rightOperand))
        opStack.push(token)
        return descender(rest)
      }
    }
    return descender(rest)
  }
  let [val, rest] = descender(src)
  return val === null ? null : [val, rest]
}
/*  Module Exports programParser  */
module.exports = programParser
<commit_msg>Add `stringParser` to `paramParser` [pattern matching]<commit_after>/*
  Parser
  Parses clean source. Generates clean AST.
*/
const opPrec = require('./operatorPrecedence')
const estemplate = require('./estemplate')
const updateAst = require('./astupdate')

/*  Utility functions  */
const mayBe = (value, func) => value === null ? null : func(...value)
const parenCheck = src => mayBe(parser.regex(/^(\))((.|\n)*)$/)(src),
                              (m, val, rest) => returnRest(val, src, src.str))

const returnRest = (val, input, rest, field) => {
  const output = JSON.parse(JSON.stringify(input))
  if (field) {
    let value = field.value
    switch (field.name) {
      case 'indent':
        output.indent = value
        output.column = value
        break
      case 'return':
        output.column = 1
        output.line += value
        break
      case 'column':
        output.column += value
        break
    }
  }
  output.str = rest
  return [val, output]
}

/*  Predefined regexes */
const spaceRegex = /^([ \t]+)((.|\n)*)$/
const returnRegex = /^(\n)((.|\n)*)$/
const idRegex = /^([a-zA-Z]+[a-zA-Z0-9_]*)((.|\n)*)$/
const numRegex = /^((?:\d+(?:\.\d*)?|\.\d+)(?:[e][+-]?\d+)?)((.|\n)*)$/
const boolRegex = /^(true|false)((.|\n)*)$/i
const stringRegex = /^('[^\\']*(?:\\.[^\\']*)*')((.|\n)*)$/
const binaryOperatorRegex = /^(\+\+|\+|-|\/|\*|<<|<=|<|>>>|>>|>=|>|&&|&|\|\||\||\^|==)((.|\n)*)$/
const unaryOperatorRegex = /^(:type|-|!)((.|\n)*)$/

/*
  Parser factory. Used to create parsers
  parser.regex - creates parser for given regex
  parser.bind - applies monadic bind on parsers
  parser.all - All parsers supplied MUST match
  parser.any - ANY ONE of the parsers need match
*/

const parser = {}

parser.regex = regex => src => mayBe(
  regex.exec(src.str),
  (m, val, rest) => returnRest(val, src, rest, {'name': 'column', 'value': val.length})
)

parser.bind = (mv, mf) => input => mayBe(
  mv(input),
  (val, rest) => mf(val)(rest)
)

parser.all = (...parsers) => src => {
  var rest = src
  var values = []
  for (let parser of parsers) {
    let result = parser(rest)
    if (result === null) return null
    values.push(result[0])
    rest = result[1]
  }
  return [values, rest]
}

parser.any = (...parsers) => src => {
  for (let parser of parsers) {
    let result = parser(src)
    if (result !== null) return result
  }
  return null
}

/*
  All required parsers are created below
*/
var spaceParser = parser.regex(spaceRegex)

var equalSignParser = parser.regex(/^(\s+=\s+)((.|\n)*)$/)

var thinArrowParser = parser.regex(/^(\s*->\s+)((.|\n)*)$/)

var slashParser = parser.regex(/^(\s*\\)((.|\n)*)$/)

var letParser = parser.regex(/^(\s*let\s+)((.|\n)*)$/)

var inParser = parser.regex(/^(\s*in\s+)((.|\n)*)$/)

var dotParser = parser.regex(/^(\.)((.|\n)*)$/)

var ifParser = parser.regex(/^(if\s+)((.|\n)*)$/)
var thenParser = parser.regex(/^(then\s+)((.|\n)*)$/)
var elseParser = parser.regex(/^(else\s+)((.|\n)*)$/)

var indentParser = input => mayBe(
  spaceRegex.exec(input),
  (a, space, rest) => [space, rest]
)

var returnParser = input => mayBe(
  returnRegex.exec(input.str),
  (a, newLine, rest) => returnRest(newLine, input, rest, {'name': 'return', 'value': newLine.length})
)

var numberParser = input => mayBe(
  numRegex.exec(input.str),
  (a, num, rest) => returnRest(estemplate.literal(num, num), input, rest, {'name': 'column', 'value': num.length})
)

var identifierParser = input => mayBe(
  idRegex.exec(input.str),
  (a, name, rest) => returnRest(estemplate.identifier(name), input, rest, {'name': 'column', 'value': name.length})
)

var stringParser = input => mayBe(
  stringRegex.exec(input.str),
  (a, string, rest) => returnRest(estemplate.stringLiteral(string.replace(/(^')/, '').replace(/('$)/, '')),
                                    input, rest, {'name': 'column', 'value': string.length})
)

var booleanParser = input => mayBe(
    boolRegex.exec(input.str),
    (a, bool, rest) => returnRest(estemplate.boolLiteral(bool), input, rest, {'name': 'column', 'value': bool.length})
  )

var parenthesisParser = parser.bind(
  parser.bind(
  parser.bind(
  parser.bind(
    input => input.str.startsWith('(')
      ? returnRest('(', input, input.str.substr(1), {'name': 'column', 'value': 1})
      : null,
    val => input => {
      const space = spaceParser(input)
      return space ? [space[0], space[1]] : [null, input]
    }),
    val => input => mayBe(
      parser.any(ifExprParser, binaryExprParser, fnCallParser, expressionParser)(input),
      (v, rest) => returnRest(v, input, rest.str)
    )),
    val => input => {
      var space = spaceParser(input)
      return space ? [val, space[1]] : [val, input]
    }),
    val => input => input.str.startsWith(')')
      ? returnRest(val, input, input.str.substr(1), {'name': 'column', 'value': 1})
      : null
)

var expressionParser = parser.any(parenthesisParser, booleanParser, identifierParser, numberParser, stringParser)

var unaryOperatorParser = input => mayBe(
    unaryOperatorRegex.exec(input.str),
    (m, operator, rest) => returnRest(operator, input, rest, {'name': 'column', 'value': operator.length})
  )

var unaryExprParser = parser.bind(
  parser.bind(
    unaryOperatorParser,
    operator => rest => operator === ':type'
      ? spaceParser(rest) !== null ? ['typeof', spaceParser(rest)[1]] : null
      : [operator, rest]),
  operator => rest => mayBe(expressionParser(rest),
    (argument, rest) => [estemplate.unaryExpression(operator, argument), rest])
)

var binaryOperatorParser = parser.regex(binaryOperatorRegex)

var declParser = parser.bind(
  parser.bind(
    identifierParser,
    val => input => mayBe(
        equalSignParser(input),
        (v, rest) => [val, rest]
      )
  ),
  val => input => mayBe(
    parser.any(unaryExprParser, letExpressionParser, ifExprParser, binaryExprParser, fnCallParser, expressionParser)(input),
        (v, rest) => {
          return returnRest(estemplate.declaration(val, v), input, rest.str)
        }
      )
)

var paramParser = parser.all(spaceParser, parser.any(identifierParser, numberParser, stringParser))

var paramsParser = (str, paramArray = []) => {
  var param = paramParser(str)
  return (param !== null) ? paramsParser(param[1], paramArray.concat(param[0][1]))
                          : [paramArray, str]
}

var fnDeclParser = parser.bind(
  parser.bind(
    parser.bind(
      identifierParser,
      val => input => mayBe(
        paramsParser(input),
        (params, rest) => returnRest(estemplate.funcDeclaration(val, params), input, rest.str)
      )
    ),
    val => input => mayBe(
        equalSignParser(input),
        (v, rest) => [val, rest]
      )
  ),
  val => input => mayBe(
    parser.any(unaryExprParser, letExpressionParser, ifExprParser, binaryExprParser, fnCallParser, expressionParser)(input),
      (v, rest) => {
        val.declarations[0].init.body = v
        return returnRest(val, input, rest.str)
      }
    )
)

var lambdaParamParser = parser.all(identifierParser, spaceParser)

var lambdaParamsParser = (str, lambdaparamArray = []) => {
  var arg = lambdaParamParser(str)
  if (arg !== null) return lambdaParamsParser(arg[1], lambdaparamArray.concat(arg[0][0]))
  return [lambdaparamArray, str]
}

var lambdaParser = parser.bind(
  parser.bind(
    parser.bind(
      slashParser,
      val => input => mayBe(
        lambdaParamsParser(input),
        (params, rest) => returnRest(estemplate.lambda(params), input, rest.str)
       )
      ),
    val => input => mayBe(
      thinArrowParser(input),
      (v, rest) => returnRest(val, input, rest.str)
    )
   ),
   val => input => mayBe(
     expressionParser(input),
     (v, rest) => {
       val.expression.body = v
       return returnRest(val, input, rest.str)
     }
   )
 )

var letParamParser = parser.all(expressionParser, equalSignParser, expressionParser, spaceParser)

var letParamsParser = (str, letIdArray = [], letLiteralArray = []) => {
  var param = letParamParser(str)
  if (param !== null) return letParamsParser(param[1], letIdArray.concat(param[0][0]), letLiteralArray.concat(param[0][2]))
  return [letIdArray, letLiteralArray, str]
}

var letExpressionParser = parser.bind(
  parser.bind(
    parser.bind(
      letParser,
      val => input => mayBe(
          letParamsParser(input),
          (val1, val2, rest) => returnRest(estemplate.letExpression(val1, val2), input, rest.str)
       )
    ),
    val => input => mayBe(
        inParser(input),
        (v, rest) => returnRest(val, input, rest.str)
      )
  ),
  val => input => mayBe(
      parser.any(binaryExprParser, fnCallParser, expressionParser)(input),
      (v, rest) => {
        val.expression.callee.body = v
        return returnRest(val, input, rest.str)
      }
    )
  )

var memberPropParser = parser.all(identifierParser, dotParser)

var memberPropsParser = (str, memberArray = []) => {
  var result = memberPropParser(str)
  if (result !== null) return memberPropsParser(result[1], memberArray.concat(result[0][0]))
  if (result === null && memberArray.length === 0) return null
  var property = identifierParser(str)
  if (property === null) return null
  let tree = memberExprParser(memberArray.concat(property[0]))
  return [tree, property[1]]
}

var memberExprParser = (str, tree = {}) => {
  let memExpr = estemplate.memberExpression
  tree = memExpr(str[0], str[1])
  for (let i = 2; i < str.length; i++) {
    tree = memExpr(tree.expression, str[i])
  }
  return tree
}

var argsParser = (input, argArray = []) => {
  var arg = parser.all(
              parser.any(unaryExprParser, expressionParser),
              parser.any(returnParser, parenCheck, spaceParser))(input)
  if (arg === null) return argArray.length === 0 ? null : [argArray, input]
  let [[argument, nextChar], rest] = arg
  if (nextChar === '\n' || nextChar === ')') {
    rest.str = nextChar === '\n' ? '\n' + rest.str : rest.str
    return [argArray.concat(argument), rest]
  }
  return argsParser(rest, argArray.concat(argument))
}

var fnCallParser = parser.bind(
  parser.all(parser.any(memberPropsParser, identifierParser), spaceParser),
  val => input => mayBe(
      argsParser(input),
      (args, rest) => val[1] === 'n' ? null : returnRest(estemplate.fnCall(val[0], args), input, rest.str)
    )
)

var ifExprParser = input => mayBe(
  parser.all(
    ifParser, expressionParser,
    spaceParser, thenParser, expressionParser,
    spaceParser, elseParser, expressionParser)(input),
    (val, rest) => {
      let [, condition, , , consequent, , , alternate] = val
      return returnRest(estemplate.ifthenelse(condition, consequent, alternate), input, rest.str)
    }
)
var multiLineParser = src => {
  if (src.length < 2) return src
  if (!indentParser(src[1])) return src
  const lead = src.splice(0, 1)
  const follow = src.splice(0, 1)
  src.unshift(lead + follow)
  return multiLineParser(src)
}

var statementParser = parser.any(returnParser, declParser, ifExprParser, fnDeclParser, fnCallParser, lambdaParser)

var programParser = (input, ast = estemplate.ast()) => {
  let result = statementParser(returnRest('', input, multiLineParser(input.str.split('\n')).join('\n'))[1])
  if (result === null) return updateAst(ast)
  if (typeof result[0] !== 'string') ast.body.push(result[0])
  return programParser(result[1], ast)
}

/* helper functions for binaryExprParser */
const precedence = operator => opPrec[operator].prec
const associativity = operator => opPrec[operator].assoc
const current = parser.any(unaryExprParser, binaryOperatorParser, spaceParser, fnCallParser, expressionParser)
const isBinaryOperator = token => opPrec[token] !== undefined
const isExpression = token => token.type !== undefined

var binaryExprParser = src => {
  let opStack = ['$']
  let operandStack = []
  let biExpr = estemplate.binaryExpression
  var descender = s => {
    let currentToken = current(s)
    let [token, rest] = currentToken === null ? [null, s] : currentToken
    let topOfOpStack = opStack[opStack.length - 1]

    if (token === null) {
      if (topOfOpStack !== '$') {
        let [rightOperand, operator, leftOperand] = [operandStack.pop(), opStack.pop(), operandStack.pop()]
        operandStack.push(biExpr(leftOperand, operator, rightOperand))
        return descender(rest)
      }
      return operandStack.length === 0 && opStack.length === 1 ? null : [operandStack.pop(), rest]
    }

    if (isExpression(token)) {
      operandStack.push(token)
      return descender(rest)
    }
    if (isBinaryOperator(token)) { // check operator stack
      if (precedence(token) > precedence(topOfOpStack)) {
        opStack.push(token)
        return descender(rest)
      }

      if (precedence(token) < precedence(topOfOpStack)) {
        let [rightOperand, operator, leftOperand] = [operandStack.pop(), opStack.pop(), operandStack.pop()]
        operandStack.push(biExpr(leftOperand, operator, rightOperand))
        opStack.push(token)
        return descender(rest)
      }
      if (associativity(token) === associativity(topOfOpStack)) {
        if (associativity(token) === 'R') {
          opStack.push(token)
          return descender(rest)
        }
        let [rightOperand, operator, leftOperand] = [operandStack.pop(), opStack.pop(), operandStack.pop()]
        operandStack.push(biExpr(leftOperand, operator, rightOperand))
        opStack.push(token)
        return descender(rest)
      }
    }
    return descender(rest)
  }
  let [val, rest] = descender(src)
  return val === null ? null : [val, rest]
}
/*  Module Exports programParser  */
module.exports = programParser
<|endoftext|>


<commit_before>'use strict'

const EventEmitter = require('events')
const espree = require('espree')
const HtmlParser = require('htmlparser2').Parser
const path = require('path')
const utils = require('./utils')

const DEFAULT_OPTIONS = {
  range: false,
//   comment: true,
  attachComment: true,

  // create a top-level tokens array containing all tokens
  tokens: true,

  // set to 3, 5 (default), 6, 7, or 8 to specify the version of ECMAScript syntax you want to use.
  // You can also set to 2015 (same as 6), 2016 (same as 7), or 2017 (same as 8) to use the year-based naming.
  ecmaVersion: 7,

  // specify which type of script you're parsing (script or module, default is script)
  sourceType: 'module'
}

const SUPPORTED_FEATURES = [
  'name', 'description', 'keywords', 'slots',
  'props', 'data', 'computed', 'events', 'methods'
]

class Parser extends EventEmitter {
  constructor (options) {
    options = Object.assign({}, DEFAULT_OPTIONS, options)

    Parser.validateOptions(options)

    super()

    this.source = options.source
    this.features = options.features || SUPPORTED_FEATURES

    if (options.source.hasOwnProperty('script') && options.source.script) {
      this.ast = espree.parse(options.source.script, options)
    } else {
      this.ast = null
    }

    this.componentName = null
    this.template = options.source.template
    this.filename = options.filename
    this.eventsEmmited = {}
    this.defaultMethodVisibility = options.defaultMethodVisibility
  }

  static validateOptions (options) {
    if (!options.source) {
      throw new Error('options.source is required')
    }

    if (options.features) {
      if (!Array.isArray(options.features)) {
        throw new TypeError('options.features must be an array')
      }

      options.features.forEach((feature) => {
        if (!SUPPORTED_FEATURES.includes(feature)) {
          throw new Error(`Unknow '${feature}' feature. Supported features: ` + JSON.stringify(SUPPORTED_FEATURES))
        }
      })
    }
  }

  static getEventName (feature) {
    return feature.endsWith('s')
      ? feature.substring(0, feature.length - 1) : feature
  }

  parseObjectExpression (property) {
    if (!this.features.includes(property.key.name)) {
      return
    }

    const eventName = Parser.getEventName(property.key.name)

    property.value.properties.forEach((p) => {
      let defaultVisibility = utils.DEFAULT_VISIBILITY

      if (property.key.name === 'methods' && this.defaultMethodVisibility) {
        defaultVisibility = this.defaultMethodVisibility
      }

      const entry = utils.getComment(p, defaultVisibility)

      entry.value = utils.value(p)
      entry.name = Object.keys(entry.value)[0]
      entry.value = entry.value[entry.name]

      if (property.key.name === 'computed') {
        if (entry.value instanceof utils.NodeFunction) {
          entry.dependencies = utils.getDependencies(entry.value, this.source.script)
        } else if (entry.value instanceof Object && entry.value.get instanceof utils.NodeFunction) {
          entry.dependencies = utils.getDependencies(entry.value.get, this.source.script)
        } else {
          entry.dependencies = []
        }
      } else if (entry.value instanceof utils.NodeFunction) {
        entry.params = entry.value.params
      } else if (property.key.name === 'props') {
        if (entry.describeModel) {
          entry.name = 'v-model'
        } else {
          entry.name = utils.unCamelcase(entry.name)
        }
      }

      delete entry.describeModel

      this.emit(eventName, entry)
      this.subWalk(entry.value)
    })
  }

  parseProperty (property) {
    const propertyValue = utils.value(property)

    if (propertyValue.hasOwnProperty('name') && !this.componentName) {
      this.componentName = propertyValue.name
      return
    }

    const entryValue = propertyValue[Object.keys(propertyValue)[0]]

    this.subWalk(entryValue)
  }

  extractProperties (property) {
    switch (property.value.type) {
      case 'FunctionExpression':
        const expression = property.value.body.body.find((p) => {
          return p.type === 'ReturnStatement'
        })

        if (expression) {
          if (expression.argument.type === 'ObjectExpression') {
            return this.parseObjectExpression({
              key: property.key,
              value: expression.argument
            })
          }
        }
        this.parseProperty(property)
        break

      case 'ArrowFunctionExpression':
        if (property.value.body.type === 'ObjectExpression') {
          this.parseObjectExpression({
            key: property.key,
            value: property.value.body
          })
        } else {
          this.parseProperty(property)
        }
        break

      case 'ObjectExpression':
        this.parseObjectExpression(property)
        break

      default:
        this.parseProperty(property)
    }
  }

  parseComponentName () {
    if (this.componentName === null) {
      if (this.filename) {
        this.componentName = path.parse(this.filename).name
      }
    }

    if (this.componentName) {
      this.emit('name', utils.unCamelcase(this.componentName))
    }
  }

  walk () {
    process.nextTick(() => {
      if (this.features.length === 0) {
        return this.emit('end')
      }

      if (this.template) {
        if (this.features.includes('slots')) {
          this.parseTemplate()
        }
      }

      if (this.ast === null) {
        if (this.features.includes('name')) {
          this.parseComponentName()
        }

        return this.emit('end')
      }

      const identifiers = {}

      this.ast.body.forEach((body) => {
        const entry = utils.getComment(body, this.defaultMethodVisibility, this.features)

        if (entry.description) {
          this.emit('description', entry.description)
        }

        if (entry.keywords.length) {
          this.emit('keywords', entry.keywords)
        }

        if (body.type !== 'ExportDefaultDeclaration' && body.type !== 'ExpressionStatement') {
          if (body.type === 'VariableDeclaration') {
            identifiers[body.declarations[0].id.name] = body.declarations[0].init
          }
          return
        }

        if (body.declaration) {
          switch (body.declaration.type) {
            case 'ObjectExpression':
              body.declaration.properties.forEach((property) => this.extractProperties(property))
              break

            case 'Identifier':
              if (identifiers.hasOwnProperty(body.declaration.name)) {
                identifiers[body.declaration.name].properties.forEach((property) => this.extractProperties(property))
              }
              break
          }
        } else if (body.expression !== null && body.expression.right && body.expression.right.properties) {
          body.expression.right.properties.forEach((property) => this.extractProperties(property))
        }

        if (this.features.includes('name')) {
          this.parseComponentName()
        }
      })

      this.emit('end')
    })

    return this
  }

  subWalk (entry) {
    if (entry instanceof utils.NodeFunction) {
      const tokens = utils.tokensInterval(this.ast.tokens, entry.range)

      for (let i = 0; i < tokens.length; i++) {
        const token = tokens[i]

        if (token.type === 'Identifier' && token.value === '$emit') {
          if (!tokens[i + 2]) {
            break
          }

          if (!this.features.includes('events')) {
            continue
          }

          const next = tokens[i + 2]
          const event = {
            name: null,
            description: null,
            visibility: utils.DEFAULT_VISIBILITY,
            keywords: []
          }

          const range = [
            tokens[i - 3].range[1],
            tokens[i - 2].range[0]
          ]

          event.description = this.ast.comments.reverse().find((c) => {
            return c.range[0] > range[0] && c.range[1] < range[1]
          })

          if (event.description) {
            const comment = utils.parseComment(
              event.description.value)

            event.visibility = comment.visibility
            event.description = comment.description
            event.keywords = comment.keywords

            const keyword = comment.keywords.find((keyword) => keyword.name === 'event')

            if (keyword) {
              if (!keyword.description) {
                const error = new Error('Missing keyword value for @event')

                this.emit('error', error)

                continue
              }

              event.name = keyword.description
            }
          }

          if (event.name === null) {
            switch (next.type) {
              case 'String':
                event.name = next.value.replace(/['"]/g, '')
                break

              case 'Identifier':
                event.name = utils.getIdentifierValue(tokens, next.value, next.range[0])

                if (typeof event.name === 'object') {
                  event.name = utils.getIdentifierValueFromStart(this.ast.tokens, event.name.notFoundIdentifier)
                }
                break
            }
          }

          if (!event.name) {
            event.name = '****unhandled-event-name****'
          } else {
            if (this.eventsEmmited.hasOwnProperty(event.name)) {
              continue
            }

            this.eventsEmmited[event.name] = true
          }

          this.emit('event', event)

          i += 2
        }
      }
    }
  }

  parseTemplate () {
    let lastComment = null

    const parser = new HtmlParser({
      oncomment: (data) => {
        lastComment = data.trim()
      },
      ontext: (text) => {
        if (text.trim()) {
          lastComment = null
        }
      },
      onopentag: (name, attrs) => {
        if (name === 'slot') {
          this.emit('slot', {
            name: attrs.name || 'default',
            description: lastComment
          })

          lastComment = null
        }
      }
    })

    parser.write(this.template)
    parser.end()
  }
}

module.exports = Parser
module.exports.SUPPORTED_FEATURES = SUPPORTED_FEATURES
<commit_msg>Use ECMA v8 on espree<commit_after>'use strict'

const EventEmitter = require('events')
const espree = require('espree')
const HtmlParser = require('htmlparser2').Parser
const path = require('path')
const utils = require('./utils')

const DEFAULT_OPTIONS = {
  range: false,
//   comment: true,
  attachComment: true,

  // create a top-level tokens array containing all tokens
  tokens: true,

  // set to 3, 5 (default), 6, 7, or 8 to specify the version of ECMAScript syntax you want to use.
  // You can also set to 2015 (same as 6), 2016 (same as 7), or 2017 (same as 8) to use the year-based naming.
  ecmaVersion: 8,

  // specify which type of script you're parsing (script or module, default is script)
  sourceType: 'module'
}

const SUPPORTED_FEATURES = [
  'name', 'description', 'keywords', 'slots',
  'props', 'data', 'computed', 'events', 'methods'
]

class Parser extends EventEmitter {
  constructor (options) {
    options = Object.assign({}, DEFAULT_OPTIONS, options)

    Parser.validateOptions(options)

    super()

    this.source = options.source
    this.features = options.features || SUPPORTED_FEATURES

    if (options.source.hasOwnProperty('script') && options.source.script) {
      this.ast = espree.parse(options.source.script, options)
    } else {
      this.ast = null
    }

    this.componentName = null
    this.template = options.source.template
    this.filename = options.filename
    this.eventsEmmited = {}
    this.defaultMethodVisibility = options.defaultMethodVisibility
  }

  static validateOptions (options) {
    if (!options.source) {
      throw new Error('options.source is required')
    }

    if (options.features) {
      if (!Array.isArray(options.features)) {
        throw new TypeError('options.features must be an array')
      }

      options.features.forEach((feature) => {
        if (!SUPPORTED_FEATURES.includes(feature)) {
          throw new Error(`Unknow '${feature}' feature. Supported features: ` + JSON.stringify(SUPPORTED_FEATURES))
        }
      })
    }
  }

  static getEventName (feature) {
    return feature.endsWith('s')
      ? feature.substring(0, feature.length - 1) : feature
  }

  parseObjectExpression (property) {
    if (!this.features.includes(property.key.name)) {
      return
    }

    const eventName = Parser.getEventName(property.key.name)

    property.value.properties.forEach((p) => {
      let defaultVisibility = utils.DEFAULT_VISIBILITY

      if (property.key.name === 'methods' && this.defaultMethodVisibility) {
        defaultVisibility = this.defaultMethodVisibility
      }

      const entry = utils.getComment(p, defaultVisibility)

      entry.value = utils.value(p)
      entry.name = Object.keys(entry.value)[0]
      entry.value = entry.value[entry.name]

      if (property.key.name === 'computed') {
        if (entry.value instanceof utils.NodeFunction) {
          entry.dependencies = utils.getDependencies(entry.value, this.source.script)
        } else if (entry.value instanceof Object && entry.value.get instanceof utils.NodeFunction) {
          entry.dependencies = utils.getDependencies(entry.value.get, this.source.script)
        } else {
          entry.dependencies = []
        }
      } else if (entry.value instanceof utils.NodeFunction) {
        entry.params = entry.value.params
      } else if (property.key.name === 'props') {
        if (entry.describeModel) {
          entry.name = 'v-model'
        } else {
          entry.name = utils.unCamelcase(entry.name)
        }
      }

      delete entry.describeModel

      this.emit(eventName, entry)
      this.subWalk(entry.value)
    })
  }

  parseProperty (property) {
    const propertyValue = utils.value(property)

    if (propertyValue.hasOwnProperty('name') && !this.componentName) {
      this.componentName = propertyValue.name
      return
    }

    const entryValue = propertyValue[Object.keys(propertyValue)[0]]

    this.subWalk(entryValue)
  }

  extractProperties (property) {
    switch (property.value.type) {
      case 'FunctionExpression':
        const expression = property.value.body.body.find((p) => {
          return p.type === 'ReturnStatement'
        })

        if (expression) {
          if (expression.argument.type === 'ObjectExpression') {
            return this.parseObjectExpression({
              key: property.key,
              value: expression.argument
            })
          }
        }
        this.parseProperty(property)
        break

      case 'ArrowFunctionExpression':
        if (property.value.body.type === 'ObjectExpression') {
          this.parseObjectExpression({
            key: property.key,
            value: property.value.body
          })
        } else {
          this.parseProperty(property)
        }
        break

      case 'ObjectExpression':
        this.parseObjectExpression(property)
        break

      default:
        this.parseProperty(property)
    }
  }

  parseComponentName () {
    if (this.componentName === null) {
      if (this.filename) {
        this.componentName = path.parse(this.filename).name
      }
    }

    if (this.componentName) {
      this.emit('name', utils.unCamelcase(this.componentName))
    }
  }

  walk () {
    process.nextTick(() => {
      if (this.features.length === 0) {
        return this.emit('end')
      }

      if (this.template) {
        if (this.features.includes('slots')) {
          this.parseTemplate()
        }
      }

      if (this.ast === null) {
        if (this.features.includes('name')) {
          this.parseComponentName()
        }

        return this.emit('end')
      }

      const identifiers = {}

      this.ast.body.forEach((body) => {
        const entry = utils.getComment(body, this.defaultMethodVisibility, this.features)

        if (entry.description) {
          this.emit('description', entry.description)
        }

        if (entry.keywords.length) {
          this.emit('keywords', entry.keywords)
        }

        if (body.type !== 'ExportDefaultDeclaration' && body.type !== 'ExpressionStatement') {
          if (body.type === 'VariableDeclaration') {
            identifiers[body.declarations[0].id.name] = body.declarations[0].init
          }
          return
        }

        if (body.declaration) {
          switch (body.declaration.type) {
            case 'ObjectExpression':
              body.declaration.properties.forEach((property) => this.extractProperties(property))
              break

            case 'Identifier':
              if (identifiers.hasOwnProperty(body.declaration.name)) {
                identifiers[body.declaration.name].properties.forEach((property) => this.extractProperties(property))
              }
              break
          }
        } else if (body.expression !== null && body.expression.right && body.expression.right.properties) {
          body.expression.right.properties.forEach((property) => this.extractProperties(property))
        }

        if (this.features.includes('name')) {
          this.parseComponentName()
        }
      })

      this.emit('end')
    })

    return this
  }

  subWalk (entry) {
    if (entry instanceof utils.NodeFunction) {
      const tokens = utils.tokensInterval(this.ast.tokens, entry.range)

      for (let i = 0; i < tokens.length; i++) {
        const token = tokens[i]

        if (token.type === 'Identifier' && token.value === '$emit') {
          if (!tokens[i + 2]) {
            break
          }

          if (!this.features.includes('events')) {
            continue
          }

          const next = tokens[i + 2]
          const event = {
            name: null,
            description: null,
            visibility: utils.DEFAULT_VISIBILITY,
            keywords: []
          }

          const range = [
            tokens[i - 3].range[1],
            tokens[i - 2].range[0]
          ]

          event.description = this.ast.comments.reverse().find((c) => {
            return c.range[0] > range[0] && c.range[1] < range[1]
          })

          if (event.description) {
            const comment = utils.parseComment(
              event.description.value)

            event.visibility = comment.visibility
            event.description = comment.description
            event.keywords = comment.keywords

            const keyword = comment.keywords.find((keyword) => keyword.name === 'event')

            if (keyword) {
              if (!keyword.description) {
                const error = new Error('Missing keyword value for @event')

                this.emit('error', error)

                continue
              }

              event.name = keyword.description
            }
          }

          if (event.name === null) {
            switch (next.type) {
              case 'String':
                event.name = next.value.replace(/['"]/g, '')
                break

              case 'Identifier':
                event.name = utils.getIdentifierValue(tokens, next.value, next.range[0])

                if (typeof event.name === 'object') {
                  event.name = utils.getIdentifierValueFromStart(this.ast.tokens, event.name.notFoundIdentifier)
                }
                break
            }
          }

          if (!event.name) {
            event.name = '****unhandled-event-name****'
          } else {
            if (this.eventsEmmited.hasOwnProperty(event.name)) {
              continue
            }

            this.eventsEmmited[event.name] = true
          }

          this.emit('event', event)

          i += 2
        }
      }
    }
  }

  parseTemplate () {
    let lastComment = null

    const parser = new HtmlParser({
      oncomment: (data) => {
        lastComment = data.trim()
      },
      ontext: (text) => {
        if (text.trim()) {
          lastComment = null
        }
      },
      onopentag: (name, attrs) => {
        if (name === 'slot') {
          this.emit('slot', {
            name: attrs.name || 'default',
            description: lastComment
          })

          lastComment = null
        }
      }
    })

    parser.write(this.template)
    parser.end()
  }
}

module.exports = Parser
module.exports.SUPPORTED_FEATURES = SUPPORTED_FEATURES
<|endoftext|>


<commit_before>var PLR_SHADOW = -5
var PLR_FORCE = 0.8;
var PLR_RADIUS = 20

class Player {
    constructor(menu, image) {
        var shape = new planck.Circle(PLR_RADIUS / PHY_SCALE)
        var body = menu.world.createBody({
            'type': 'dynamic'
        })
        this.world = menu.world
        body.createFixture({
            'shape': shape,
            'restitution': 0.9,
            'm_radius': PLR_RADIUS / PHY_SCALE
        }).setUserData(this)
        body.setLinearDamping(0.3);
        body.setAwake(true);
        body.setActive(true);
        this.body = body;
        this.image = image;
        this.pawn = makeImage('img/pawn.png')
        this.ball = false
        this.actions = {
            'boost': new TimedAction({duration:20}),
            'shoot': new TimedAction({duration:10}),
            'pusher':new TimedAction({duration:10}),
        }
    }
    update(dt, delta) {
        for (let action in this.actions) {
            this.actions[action].update(delta)
        }
    }
    take_ball(ball) {
        if (ball.owned) {
            ball.owned.ball = false;
        }
        ball.body.setActive(false);
        this.ball = ball
        ball.owned = this
    }
    distance_from(coords) {
        return Math.sqrt(Math.pow(coords.x - this.pos.x, 2) + Math.pow(coords.y - this.pos.y, 2))
    }
    set_position(x, y, randomicity = 0, rotation = 0) {
        let temp = new planck.Vec2(x / PHY_SCALE + (Math.random() * randomicity - randomicity / 2), -y / PHY_SCALE + (Math.random() * randomicity - randomicity / 2))
        this.body.setLinearVelocity({
            x: 0,
            y: 0
        }, 0.0);
        this.body.setTransform(temp, rotation);
    }
    destroy() {
        this.world.destroyBody(this.body)
        this.body = null
        this.image = null
        this.world = null
    }
    targets(coords, delta) {
        var x = coords.x - this.pos.x
        var y = coords.y - this.pos.y
        var angle = Math.atan(y / x)
        if (this.pos.x > coords.x) {
            var myangle = (Math.PI / 2 + (this.body.getAngle() - Math.PI)) % (2 * Math.PI);
        } else {
            var myangle = (Math.PI / 2 + (this.body.getAngle() )) % (2 * Math.PI);
        }
        let dangle = angle - myangle
        var sync = Math.abs(dangle) < (delta / 360 * (2 * Math.PI))

        return [sync, dangle]
    }
    push(dt) {
        if (!!this.ball) {
            // shooting ball
            this.ball.shot(dt)
            let angle = this.body.getAngle()
            let [x, y] = [Math.sin(-angle), Math.cos(-angle)]
            let temp = new planck.Vec2(this.pos.x + x, this.pos.y + y)
            this.ball.body.setTransform(temp, angle)
            this.ball.body.setActive(true)
            temp = this.body.getLinearVelocity()
            this.ball.body.setLinearVelocity(temp)
            this.ball.body.applyLinearImpulse(this.ball.body.getWorldVector(new planck.Vec2(0, 3 * PLR_FORCE)), this.ball.pos, true)
            this.ball = false
            this.actions.shoot.start()
        } else {
            if (this.actions.boost.running) // disable boost if already running
                return
            this.body.applyLinearImpulse(this.body.getWorldVector(new planck.Vec2(0, 5 * PLR_FORCE)), this.pos, true)
            this.actions.boost.start()
            this.actions.pusher.start()
        }
    }
    forward(delta) {
        let force = PLR_FORCE * delta
        this.body.applyLinearImpulse(this.body.getWorldVector(new planck.Vec2(0, force)), this.pos, true)
    }
    backward(delta) {
        let force = PLR_FORCE * delta
        this.body.applyLinearImpulse(this.body.getWorldVector(new planck.Vec2(0, -force / 1.25)), this.pos, true)
    }
    left(delta) {
        let angle = 0.37 * delta
        this.body.setTransform(this.pos, this.body.getAngle() + angle)

    }
    right(delta) {
        let angle = 0.37 * delta
        this.body.setTransform(this.pos, this.body.getAngle() - angle)
    }
    draw(dt, delta) {
        this.pos = this.body.getPosition();
        app.display.context.save()
        let x = PHY_SCALE * (this.pos.x)
        let y = -PHY_SCALE * (this.pos.y)
        app.display.context.translate(x, y)
        app.display.blit(this.image, -PLR_RADIUS, -PLR_RADIUS)
        app.display.context.rotate(-this.body.getAngle())
        app.display.context.translate(0, -PLR_RADIUS / 2)
        if (this.ball) {
            app.display.blit(this.ball.image, -this.ball.image.width / 2, -this.ball.image.height / 2)
            let angle = this.body.getAngle()
            let [x, y] = [Math.sin(-angle), Math.cos(-angle)]
            this.ball.pos = new planck.Vec2(this.pos.x + x, this.pos.y + y)
        }
        app.display.context.translate(0, -PLR_RADIUS / 2)
        app.display.blit(this.pawn, -this.pawn.width / 2, -this.pawn.height / 2)
        app.display.context.restore()
    }
}
<commit_msg>minor refactor<commit_after>var PLR_SHADOW = -5
var PLR_FORCE = 0.8;
var PLR_RADIUS = 20

class Player {
    constructor(menu, image) {
        var shape = new planck.Circle(PLR_RADIUS / PHY_SCALE)
        var body = menu.world.createBody({
            'type': 'dynamic'
        })
        this.world = menu.world
        body.createFixture({
            'shape': shape,
            'restitution': 0.9,
            'm_radius': PLR_RADIUS / PHY_SCALE
        }).setUserData(this)
        body.setLinearDamping(0.3);
        body.setAwake(true);
        body.setActive(true);
        this.body = body;
        this.image = image;
        this.pawn = makeImage('img/pawn.png')
        this.ball = false
        this.actions = {
            'boost': new TimedAction({duration:20}),
            'shoot': new TimedAction({duration:10}),
            'pusher':new TimedAction({duration:10}),
        }
    }
    update(dt, delta) {
        for (let action in this.actions) {
            this.actions[action].update(delta)
        }
    }
    take_ball(ball) {
        if (ball.owned) {
            ball.owned.ball = false;
        }
        ball.body.setActive(false);
        this.ball = ball
        ball.owned = this
    }
    distance_from(coords) {
        return Math.sqrt(Math.pow(coords.x - this.pos.x, 2) + Math.pow(coords.y - this.pos.y, 2))
    }
    set_position(x, y, randomicity = 0, rotation = 0) {
        let temp = new planck.Vec2(x / PHY_SCALE + (Math.random() * randomicity - randomicity / 2), -y / PHY_SCALE + (Math.random() * randomicity - randomicity / 2))
        this.body.setLinearVelocity({
            x: 0,
            y: 0
        }, 0.0);
        this.body.setTransform(temp, rotation);
    }
    destroy() {
        this.world.destroyBody(this.body)
        this.body = null
        this.image = null
        this.world = null
    }
    targets(coords, delta) {
        var x = coords.x - this.pos.x
        var y = coords.y - this.pos.y
        var angle = Math.atan(y / x)
        var angle_correction = (this.pos.x > coords.x)? Math.PI:0
        var myangle = (Math.PI / 2 + (this.body.getAngle() - angle_correction)) % (2 * Math.PI);
        let dangle = angle - myangle
        var sync = Math.abs(dangle) < (delta / 360 * (2 * Math.PI))

        return [sync, dangle]
    }
    push(dt) {
        if (!!this.ball) {
            // shooting ball
            this.ball.shot(dt)
            let angle = this.body.getAngle()
            let [x, y] = [Math.sin(-angle), Math.cos(-angle)]
            let temp = new planck.Vec2(this.pos.x + x, this.pos.y + y)
            this.ball.body.setTransform(temp, angle)
            this.ball.body.setActive(true)
            temp = this.body.getLinearVelocity()
            this.ball.body.setLinearVelocity(temp)
            this.ball.body.applyLinearImpulse(this.ball.body.getWorldVector(new planck.Vec2(0, 3 * PLR_FORCE)), this.ball.pos, true)
            this.ball = false
            this.actions.shoot.start()
        } else {
            if (this.actions.boost.running) // disable boost if already running
                return
            this.body.applyLinearImpulse(this.body.getWorldVector(new planck.Vec2(0, 5 * PLR_FORCE)), this.pos, true)
            this.actions.boost.start()
            this.actions.pusher.start()
        }
    }
    forward(delta) {
        let force = PLR_FORCE * delta
        this.body.applyLinearImpulse(this.body.getWorldVector(new planck.Vec2(0, force)), this.pos, true)
    }
    backward(delta) {
        let force = PLR_FORCE * delta
        this.body.applyLinearImpulse(this.body.getWorldVector(new planck.Vec2(0, -force / 1.25)), this.pos, true)
    }
    left(delta) {
        let angle = 0.37 * delta
        this.body.setTransform(this.pos, this.body.getAngle() + angle)

    }
    right(delta) {
        let angle = 0.37 * delta
        this.body.setTransform(this.pos, this.body.getAngle() - angle)
    }
    draw(dt, delta) {
        this.pos = this.body.getPosition();
        app.display.context.save()
        let x = PHY_SCALE * (this.pos.x)
        let y = -PHY_SCALE * (this.pos.y)
        app.display.context.translate(x, y)
        app.display.blit(this.image, -PLR_RADIUS, -PLR_RADIUS)
        app.display.context.rotate(-this.body.getAngle())
        app.display.context.translate(0, -PLR_RADIUS / 2)
        if (this.ball) {
            app.display.blit(this.ball.image, -this.ball.image.width / 2, -this.ball.image.height / 2)
            let angle = this.body.getAngle()
            let [x, y] = [Math.sin(-angle), Math.cos(-angle)]
            this.ball.pos = new planck.Vec2(this.pos.x + x, this.pos.y + y)
        }
        app.display.context.translate(0, -PLR_RADIUS / 2)
        app.display.blit(this.pawn, -this.pawn.width / 2, -this.pawn.height / 2)
        app.display.context.restore()
    }
}
<|endoftext|>


<commit_before>exports.canRun = function (ast, userAgent) {

};

exports.whoCanRun = function (ast, userAgent) {

};
<commit_msg>comment out detection file<commit_after>//exports.canRun = function (ast, userAgent) {

//};

//exports.whoCanRun = function (ast, userAgent) {

//};
<|endoftext|>


<commit_before>var _   = require('lodash');
var fs  = require('fs');
var jsf = require('jsonfile');

/**
 * Object Definition
 */

var Player = function (username) {
  this.username = username;
  this.data     = null;
  this.settings = null;
};

/**
 * Prototypes
 */

Player.prototype.load = function (data) {
  if (fs.existsSync(__dirname + '/../data/save/' + this.username)) {
    this.data = jsf.readFileSync(__dirname + '/../data/save/' + this.username + '/player-data.json');
    this.settings = jsf.readFileSync(__dirname + '/../data/save/' + this.username + '/player-settings.json');
    this.update(data);
  } else {
    this.data = data;
    this.settings = {
      spreadsheet: {
        color:  {
          iv:   false,
          move: false
        },
        display: {
          move_1:       true,
          move_2:       false,
          move_energy:  false,
          move_dps:     false,
          level:        true,
          cp:           true,
          hp:           true,
          atk:          false,
          def:          false,
          iva:          true,
          ivd:          true,
          ivs:          true,
          dps:          false,
          piv:          true,
          pcp:          true
        }
      }
    };
  }
};

Player.prototype.save = function () {
  if (!fs.existsSync(__dirname + '/../data/save/' + this.username)) fs.mkdirSync(__dirname + '/../data/save/' + this.username);
  jsf.writeFileSync(__dirname + '/../data/save/' + this.username + '/player-data.json', this.data, {spaces: 2});
  jsf.writeFileSync(__dirname + '/../data/save/' + this.username + '/player-settings.json', this.settings, {spaces: 2});
};

Player.prototype.update = function (data) {
  this.data = data;
};

Player.prototype.toJSON = function () {
  return {
    data: this.data,
    settings: this.settings
  };
};

module.exports = Player;<commit_msg>Fixed the undefined settings message<commit_after>var _   = require('lodash');
var fs  = require('fs');
var jsf = require('jsonfile');

/**
 * Object Definition
 */

var Player = function (username) {
  this.username = username;
  this.data     = null;
  this.settings = null;
};

/**
 * Prototypes
 */

Player.prototype.load = function (data) {
  if (fs.existsSync(__dirname + '/../data/save/' + this.username)) {
    this.data = jsf.readFileSync(__dirname + '/../data/save/' + this.username + '/player-data.json');
    this.settings = jsf.readFileSync(__dirname + '/../data/save/' + this.username + '/player-settings.json');
    if (this.settings === undefined) {
      this.settings = {
        spreadsheet: {
          color:  {
            iv:   false,
            move: false
          },
          display: {
            move_1:       true,
            move_2:       false,
            move_energy:  false,
            move_dps:     false,
            level:        true,
            cp:           true,
            hp:           true,
            atk:          false,
            def:          false,
            iva:          true,
            ivd:          true,
            ivs:          true,
            dps:          false,
            piv:          true,
            pcp:          true
          }
        }
      };
    }
    this.update(data);
  } else {
    this.data = data;
    this.settings = {
      spreadsheet: {
        color:  {
          iv:   false,
          move: false
        },
        display: {
          move_1:       true,
          move_2:       false,
          move_energy:  false,
          move_dps:     false,
          level:        true,
          cp:           true,
          hp:           true,
          atk:          false,
          def:          false,
          iva:          true,
          ivd:          true,
          ivs:          true,
          dps:          false,
          piv:          true,
          pcp:          true
        }
      }
    };
  }
};

Player.prototype.save = function () {
  if (!fs.existsSync(__dirname + '/../data/save/' + this.username)) fs.mkdirSync(__dirname + '/../data/save/' + this.username);
  jsf.writeFileSync(__dirname + '/../data/save/' + this.username + '/player-data.json', this.data, {spaces: 2});
  jsf.writeFileSync(__dirname + '/../data/save/' + this.username + '/player-settings.json', this.settings, {spaces: 2});
};

Player.prototype.update = function (data) {
  this.data = data;
};

Player.prototype.toJSON = function () {
  return {
    data: this.data,
    settings: this.settings
  };
};

module.exports = Player;<|endoftext|>