<commit_before>var tokenizer = require("./tokenizer");

var tokenUtils = require("./util/tokenUtils");

var classHandlers = require("./handlers/classHandlers");
var functionHandlers = require("./handlers/functionHandlers");
var invocationHandlers = require("./handlers/invocationHandlers");
var moduleHandlers = require("./handlers/moduleHandlers");
var commentHandlers = require("./handlers/commentHandlers");
var propertyAccessorHandlers = require("./handlers/propertyAccessorHandlers");
var operatorHandlers = require("./handlers/operatorHandlers");
var statementHandlers = require("./handlers/statementHandlers");

var parserState = require("./parserState");
const StateEnum = parserState.StateEnum;

var validOperators = {
  is: " === ",
  not: " !== ",
  and: " && ",
  or: " || ",
  as: " = ",
  more: " += ",
  less: " -= ",
  lots: " *= ",
  few: " /= ",
  very: " var ",
  smaller: " < ",
  bigger: " > ",
  smallerish: " <= ",
  biggerish: " >= ",
  notrly: " ! ",
  bigify: "++",
  bigified: "++",
  smallify: "--",
  smallified: "--"
};

var valid = [
  "such",
  "wow",
  "wow&",
  "plz",
  ".plz",
  "dose",
  "very",
  "shh",
  "quiet",
  "loud",
  "rly",
  "notrly",
  "but",
  "many",
  "much",
  "so",
  "trained",
  "maybe",
  "debooger",
  "pawse",
  "woof",
  "obj", // can be handled as top-level token
  "giv",
  "levl",
  "next",
  "amaze",
  "classy",
  "maker",
  "grows",
  "git",
  "sit",
  "stay"
];

/**
 * Determines if the parsed tokens should be treated as dogescript source or not.
 */
function isDogescriptSource(parseContext) {
  var tokens = parseContext.tokens;

  // starts the statement with a valid token
  if (valid.indexOf(tokens[0]) !== -1) {
    return true;
  }

  // statement applying an assignment operator
  if (operatorHandlers.hasAssignmentOperator(parseContext)) {
    return true;
  }

  // applying a unary operator
  if (operatorHandlers.containsIncrementDecrement(parseContext)) {
    return true;
  }

  // calling function on Object
  if (tokens[1] === "dose") {
    return true;
  }

  // ending a multi comment block
  if (
    parserState.hasState(StateEnum.MULTILINE_COMMENT) &&
    tokens[0] === "loud"
  ) {
    return true;
  }

  // closing a multi-line object creation
  if (parserState.hasState(StateEnum.OBJECT) && tokens[0] === "wow") {
    return true;
  }

  // binary operation anywhere
  if (operatorHandlers.hasBinaryOperator(parseContext)) {
    return true;
  }

  // something uses a property accessor
  if (tokens.some(propertyAccessorHandlers.isPropertyAccessor)) {
    return true;
  }

  // check if next is anywhere in the stack
  if (
    tokens.some(function(token) {
      return token === "next";
    })
  ) {
    return true;
  }

  // not valid dogescript
  return false;
}

/**
 * Handles if statements:
 * rly [condition]
 */
function handleRly(parseContext) {
  tokenUtils.expectToken("rly", parseContext);

  var tokens = parseContext.tokens;

  // consume: rly
  tokens.shift();

  var statement = "if (";
  parserState.pushState(StateEnum.CONTROL_FLOW);
  statement += parseStatements(parseContext);
  parserState.popState();
  // close condition and open branch
  statement += ") {\n";
  return statement;
}

/**
 * Handles negated if statements:
 * notrly [condition]
 */
function handleNotrly(parseContext) {
  tokenUtils.expectToken("notrly", parseContext);

  var tokens = parseContext.tokens;

  // consume: notrly
  tokens.shift();

  var statement = "if (!";
  parserState.pushState(StateEnum.CONTROL_FLOW);
  statement += parseStatements(parseContext);
  parserState.popState();
  // close condition and open branch
  statement += ") {\n";
  return statement;
}

/**
 * Handles else statements:
 * but [condition]
 * but [rly|notrly] [condition]
 */
function handleBut(parseContext) {
  tokenUtils.expectToken("but", parseContext);

  var tokens = parseContext.tokens;

  // consume: but
  tokens.shift();

  var statement = "} else ";
  if (tokens[0] === "rly" || tokens[0] === "notrly") {
    if (tokens[0] === "rly") {
      statement += handleRly(parseContext);
    } else {
      statement += handleNotrly(parseContext);
    }
  } else {
    // open branch
    statement += "{\n";
  }
  return statement;
}

/**
 * Handles the ending of statements:
 * wow [return vals]
 * wow& [return vals]
 */
function handleWow(parseContext) {
  tokenUtils.expectAnyToken(["wow", "wow&"], parseContext);

  var tokens = parseContext.tokens;
  // turn off multiline declaration
  if (parserState.hasState(StateEnum.OBJECT)) {
    parserState.popState();
  }

  var chained = tokens[0] === "wow&";

  // consume: wow/wow&
  tokens.shift();

  var statement = "";

  // add tokens if there's a return value
  if (tokens.length > 0) {
    statement += "return";
    let arg;
    // ideally this will call parsetokens in the future to support return foo();
    while ((arg = tokens.shift())) {
      statement += " " + arg;
    }
    statement += ";\n";
  }

  if (chained) {
    // close chained call
    statement += "}) \n";
  } else {
    // close block
    statement += "} \n";
  }

  return statement;
}

/**
 * Handles the for loop construct:
 * much [startState] next [condition] next [nextState]
 *
 * Produces:
 * for(startState; condition; nextState) {
 */
function handleMuchLoop(parseContext) {
  tokenUtils.expectToken("much", parseContext);

  var tokens = parseContext.tokens;

  // consume: much
  tokens.shift();

  var statement = "for (";
  parserState.pushState(StateEnum.CONTROL_FLOW);
  statement += parseStatements(parseContext);
  parserState.popState();
  statement += ") {\n";
  return statement;
}

/**
 * Handles the while loop construct:
 * many [condition]
 *
 * Produces:
 * while(condition) {
 */
function handleMany(parseContext) {
  tokenUtils.expectToken("many", parseContext);

  var tokens = parseContext.tokens;

  // consume: many
  tokens.shift();

  var statement = "while (";
  parserState.pushState(StateEnum.CONTROL_FLOW);
  statement += parseStatements(parseContext);
  parserState.popState();
  statement += ") {\n";

  return statement;
}

/**
 * Handles variable declaration:
 *  very <variable> is <value>
 *
 * Produces:
 *  var <variable> = <value>;
 */
function handleVery(parseContext) {
  tokenUtils.expectToken("very", parseContext);

  var tokens = parseContext.tokens;

  // consume: very
  tokens.shift();

  var statement = "var " + tokens.shift() + " = ";

  // consume:is/as
  tokens.shift();

  if (tokens[0] === "new") {
    statement += invocationHandlers.handleNew(parseContext);
    return statement;
  }

  if (tokens[0] === "much") {
    var anonStatement = functionHandlers.handleLambda(parseContext);
    statement += anonStatement;
    return statement;
  }

  if (tokens[0] === "obj") {
    // consume obj
    tokens.shift();
    statement += "{\n";
    parserState.pushState(StateEnum.OBJECT);
    return statement;
  }

  // the condition check below needs fixing so we can resolve this with just parseStatement
  if (tokens[0] === "classy") {
    statement += classHandlers.handleClass(parseContext);
    return statement;
  }

  if (tokens.length > 1) {
    statement += parseStatement(parseContext);

    if (!statementHandlers.shouldCloseStatement(parseContext, statement)) {
      return statement;
    }
  } else {
    statement += tokens.shift();
  }

  statement += ";\n";
  return statement;
}

/**
 * Handles explicit return:
 *  amaze <expression>
 *
 * Produces:
 *  return <expression>;
 */
function handleAmaze(parseContext) {
  tokenUtils.expectToken("amaze", parseContext);

  // consume: amaze
  parseContext.tokens.shift();

  return "return " + returnStatements(parseContext);
}

/**
 * Appends statements from the parse context into a single line
 */
function returnStatements(parseContext) {
  var statement = parseStatements(parseContext);
  if (statementHandlers.shouldCloseStatement(parseContext, statement)) {
    statement += ";\n";
  }

  return statement;
}

function parseStatement(parseContext) {
  var tokens = parseContext.tokens;

  // if processing multi-comment
  if (parserState.hasState(StateEnum.MULTILINE_COMMENT)) {
    // consume tokens until we encounter loud
    if (tokens[0] !== "loud") {
      // clear out tokens
      parseContext.tokens = [];
      return parseContext.input + "\n";
    }
    // else must be loud
    return commentHandlers.handleLoud(parseContext);
  }

  // not dogescript, such javascript
  if (!isDogescriptSource(parseContext)) {
    return tokenUtils.joinTokens(tokens) + "\n";
  }

  // trained use strict
  if (tokens[0] === "trained") {
    // consume: trained
    tokens.shift();
    return '"use strict";\n';
  }

  // such function
  if (tokens[0] === "such") {
    return functionHandlers.handleSuch(parseContext);
  }

  if (tokens[0] === "wow" || tokens[0] === "wow&") {
    return handleWow(parseContext);
  }

  // plz execute function
  if (tokens[0] === "plz" || tokens[0] === ".plz") {
    return invocationHandlers.handlePlz(parseContext);
  }
  // obj dose function
  if (tokens[0] === "dose" || tokens[1] === "dose") {
    return invocationHandlers.handleDose(parseContext);
  }

  // very new variable
  if (tokens[0] === "very") {
    return handleVery(parseContext);
  }

  // only applicable to disambiguate during control flow parsing
  if (parserState.hasState(StateEnum.CONTROL_FLOW)) {
    // convert to supported operator / otherwise fall thorugh
    // TODO remove operators as they become supported
    if (validOperators.hasOwnProperty(tokens[0])) {
      return validOperators[tokens.shift()];
    }
  }

  // support any kind of assignment operator
  if (operatorHandlers.isAssignmentOperator(tokens[0])) {
    var statement = operatorHandlers.handleAssignmentOperator(parseContext);

    if (tokens[0] === "new") {
      statement += invocationHandlers.handleNew(parseContext);
      return statement;
    }

    statement += parseStatement(parseContext);

    if (statementHandlers.shouldCloseStatement(parseContext, statement)) {
      statement += ";\n";
    }

    return statement;
  }

  // shh comment
  if (tokens[0] === "shh") {
    return commentHandlers.handleShh(parseContext);
  }

  // quiet start multi-line comment
  if (tokens[0] === "quiet") {
    return commentHandlers.handleQuiet(parseContext);
  }

  // rly if
  if (tokens[0] === "rly") {
    return handleRly(parseContext);
  }

  // ntrly if
  if (tokens[0] === "notrly") {
    return handleNotrly(parseContext);
  }

  // but else
  if (tokens[0] === "but") {
    return handleBut(parseContext);
  }

  // many while
  if (tokens[0] === "many") {
    return handleMany(parseContext);
  }

  // much for
  if (tokens[0] === "much") {
    return handleMuchLoop(parseContext);
  }

  // so require
  if (tokens[0] === "so") {
    return moduleHandlers.handleSo(parseContext);
  }

  // maybe boolean operator
  if (tokens[0] === "maybe") {
    // consume: maybe
    tokens.shift();
    return "(!!+Math.round(Math.random()))";
  }

  if (tokens[0] === "next") {
    // consume next
    tokens.shift();
    return ";";
  }

  // standalone increment/decrement
  if (operatorHandlers.containsIncrementDecrement(parseContext)) {
    return operatorHandlers.handleIncrementDecrementOperators(parseContext);
  }

  if (tokens[0] === "woof") {
    return moduleHandlers.handleWoof(parseContext);
  }

  if (tokens[0] === "debooger" || tokens[0] === "pawse") {
    return statementHandlers.handleDebugger(parseContext);
  }

  if (tokens[0] === "obj") {
    // consume obj
    tokens.shift();
    parserState.pushState(StateEnum.OBJECT);
    return "{\n";
  }

  if (operatorHandlers.isBinaryOperator(tokens[0])) {
    return operatorHandlers.handleBinaryOperator(parseContext);
  }

  if (tokens[0] === "giv") {
    return propertyAccessorHandlers.handleGiv(parseContext);
  }

  if (tokens[0] === "levl") {
    return propertyAccessorHandlers.handleLevl(parseContext);
  }

  if (tokens[0] === "amaze") {
    return handleAmaze(parseContext);
  }

  if (tokens[0] === "classy") {
    return classHandlers.handleClass(parseContext);
  }

  if (tokens[0] === "maker") {
    return classHandlers.handleMaker(parseContext);
  }

  if (tokens[0] === "git") {
    return classHandlers.handleGit(parseContext);
  }

  if (tokens[0] === "sit") {
    return classHandlers.handleSit(parseContext);
  }

  if (tokens[0] === "stay") {
    return classHandlers.handleStay(parseContext);
  }

  var statement = tokens.shift();
  // if there's more tokens, split them by a ' ' similar to how tokenUtils.joinTokens would work
  if (tokens.length > 0) {
    statement += " ";
  }
  return statement;
}

/**
 * Consumes every token in the parseContext, appending each found statement and returning all statements found.
 */
function parseStatements(parseContext) {
  var statements = "";

  while (parseContext.tokens.length > 0) {
    statements += parseStatement(parseContext);
  }

  return statements;
}

var replacements = {};
replacements["dogeument"] = "document";
replacements["windoge"] = "window";
replacements["dis"] = "this";
replacements["sooper"] = "super";

module.exports = function parse(line) {
  var tokens = tokenizer.tokenize(line);

  if (tokens.length == 0) {
    return line + "\n";
  }

  var parseContext = {
    input: line,
    // leave original tokens to throw better syntax errors
    inputTokens: tokens.slice(),
    tokens: tokens
  };

  // pre-process tokens and swap replacements
  for (let i = 0; i < tokens.length; i++) {
    var testToken = tokens[i];

    // if we see a shh, skip since everything should be preserved
    if (testToken === "shh") {
      break;
    }

    Object.keys(replacements).forEach(function(key) {
      if (testToken === key) {
        tokens[i] = replacements[key];
      }

      if (testToken.startsWith(key + ".")) {
        tokens[i] = testToken.replace(key + ".", replacements[key] + ".");
      }
    });
  }

  return parseStatements(parseContext);
};
<commit_msg>rename functions (#247)<commit_after>var tokenizer = require("./tokenizer");

var tokenUtils = require("./util/tokenUtils");

var classHandlers = require("./handlers/classHandlers");
var functionHandlers = require("./handlers/functionHandlers");
var invocationHandlers = require("./handlers/invocationHandlers");
var moduleHandlers = require("./handlers/moduleHandlers");
var commentHandlers = require("./handlers/commentHandlers");
var propertyAccessorHandlers = require("./handlers/propertyAccessorHandlers");
var operatorHandlers = require("./handlers/operatorHandlers");
var statementHandlers = require("./handlers/statementHandlers");

var parserState = require("./parserState");
const StateEnum = parserState.StateEnum;

var validOperators = {
  is: " === ",
  not: " !== ",
  and: " && ",
  or: " || ",
  as: " = ",
  more: " += ",
  less: " -= ",
  lots: " *= ",
  few: " /= ",
  very: " var ",
  smaller: " < ",
  bigger: " > ",
  smallerish: " <= ",
  biggerish: " >= ",
  notrly: " ! ",
  bigify: "++",
  bigified: "++",
  smallify: "--",
  smallified: "--"
};

var valid = [
  "such",
  "wow",
  "wow&",
  "plz",
  ".plz",
  "dose",
  "very",
  "shh",
  "quiet",
  "loud",
  "rly",
  "notrly",
  "but",
  "many",
  "much",
  "so",
  "trained",
  "maybe",
  "debooger",
  "pawse",
  "woof",
  "obj", // can be handled as top-level token
  "giv",
  "levl",
  "next",
  "amaze",
  "classy",
  "maker",
  "grows",
  "git",
  "sit",
  "stay"
];

/**
 * Determines if the parsed tokens should be treated as dogescript source or not.
 */
function isDogescriptSource(parseContext) {
  var tokens = parseContext.tokens;

  // starts the statement with a valid token
  if (valid.indexOf(tokens[0]) !== -1) {
    return true;
  }

  // statement applying an assignment operator
  if (operatorHandlers.hasAssignmentOperator(parseContext)) {
    return true;
  }

  // applying a unary operator
  if (operatorHandlers.containsIncrementDecrement(parseContext)) {
    return true;
  }

  // calling function on Object
  if (tokens[1] === "dose") {
    return true;
  }

  // ending a multi comment block
  if (
    parserState.hasState(StateEnum.MULTILINE_COMMENT) &&
    tokens[0] === "loud"
  ) {
    return true;
  }

  // closing a multi-line object creation
  if (parserState.hasState(StateEnum.OBJECT) && tokens[0] === "wow") {
    return true;
  }

  // binary operation anywhere
  if (operatorHandlers.hasBinaryOperator(parseContext)) {
    return true;
  }

  // something uses a property accessor
  if (tokens.some(propertyAccessorHandlers.isPropertyAccessor)) {
    return true;
  }

  // check if next is anywhere in the stack
  if (
    tokens.some(function(token) {
      return token === "next";
    })
  ) {
    return true;
  }

  // not valid dogescript
  return false;
}

/**
 * Handles if statements:
 * rly [condition]
 */
function handleRly(parseContext) {
  tokenUtils.expectToken("rly", parseContext);

  var tokens = parseContext.tokens;

  // consume: rly
  tokens.shift();

  var statement = "if (";
  parserState.pushState(StateEnum.CONTROL_FLOW);
  statement += handleStatements(parseContext);
  parserState.popState();
  // close condition and open branch
  statement += ") {\n";
  return statement;
}

/**
 * Handles negated if statements:
 * notrly [condition]
 */
function handleNotrly(parseContext) {
  tokenUtils.expectToken("notrly", parseContext);

  var tokens = parseContext.tokens;

  // consume: notrly
  tokens.shift();

  var statement = "if (!";
  parserState.pushState(StateEnum.CONTROL_FLOW);
  statement += handleStatements(parseContext);
  parserState.popState();
  // close condition and open branch
  statement += ") {\n";
  return statement;
}

/**
 * Handles else statements:
 * but [condition]
 * but [rly|notrly] [condition]
 */
function handleBut(parseContext) {
  tokenUtils.expectToken("but", parseContext);

  var tokens = parseContext.tokens;

  // consume: but
  tokens.shift();

  var statement = "} else ";
  if (tokens[0] === "rly" || tokens[0] === "notrly") {
    if (tokens[0] === "rly") {
      statement += handleRly(parseContext);
    } else {
      statement += handleNotrly(parseContext);
    }
  } else {
    // open branch
    statement += "{\n";
  }
  return statement;
}

/**
 * Handles the ending of statements:
 * wow [return vals]
 * wow& [return vals]
 */
function handleWow(parseContext) {
  tokenUtils.expectAnyToken(["wow", "wow&"], parseContext);

  var tokens = parseContext.tokens;
  // turn off multiline declaration
  if (parserState.hasState(StateEnum.OBJECT)) {
    parserState.popState();
  }

  var chained = tokens[0] === "wow&";

  // consume: wow/wow&
  tokens.shift();

  var statement = "";

  // add tokens if there's a return value
  if (tokens.length > 0) {
    statement += "return";
    let arg;
    // ideally this will call parsetokens in the future to support return foo();
    while ((arg = tokens.shift())) {
      statement += " " + arg;
    }
    statement += ";\n";
  }

  if (chained) {
    // close chained call
    statement += "}) \n";
  } else {
    // close block
    statement += "} \n";
  }

  return statement;
}

/**
 * Handles the for loop construct:
 * much [startState] next [condition] next [nextState]
 *
 * Produces:
 * for(startState; condition; nextState) {
 */
function handleMuchLoop(parseContext) {
  tokenUtils.expectToken("much", parseContext);

  var tokens = parseContext.tokens;

  // consume: much
  tokens.shift();

  var statement = "for (";
  parserState.pushState(StateEnum.CONTROL_FLOW);
  statement += handleStatements(parseContext);
  parserState.popState();
  statement += ") {\n";
  return statement;
}

/**
 * Handles the while loop construct:
 * many [condition]
 *
 * Produces:
 * while(condition) {
 */
function handleMany(parseContext) {
  tokenUtils.expectToken("many", parseContext);

  var tokens = parseContext.tokens;

  // consume: many
  tokens.shift();

  var statement = "while (";
  parserState.pushState(StateEnum.CONTROL_FLOW);
  statement += handleStatements(parseContext);
  parserState.popState();
  statement += ") {\n";

  return statement;
}

/**
 * Handles variable declaration:
 *  very <variable> is <value>
 *
 * Produces:
 *  var <variable> = <value>;
 */
function handleVery(parseContext) {
  tokenUtils.expectToken("very", parseContext);

  var tokens = parseContext.tokens;

  // consume: very
  tokens.shift();

  var statement = "var " + tokens.shift() + " = ";

  // consume:is/as
  tokens.shift();

  if (tokens[0] === "new") {
    statement += invocationHandlers.handleNew(parseContext);
    return statement;
  }

  if (tokens[0] === "much") {
    var anonStatement = functionHandlers.handleLambda(parseContext);
    statement += anonStatement;
    return statement;
  }

  if (tokens[0] === "obj") {
    // consume obj
    tokens.shift();
    statement += "{\n";
    parserState.pushState(StateEnum.OBJECT);
    return statement;
  }

  // the condition check below needs fixing so we can resolve this with just handleStatement
  if (tokens[0] === "classy") {
    statement += classHandlers.handleClass(parseContext);
    return statement;
  }

  if (tokens.length > 1) {
    statement += handleStatement(parseContext);

    if (!statementHandlers.shouldCloseStatement(parseContext, statement)) {
      return statement;
    }
  } else {
    statement += tokens.shift();
  }

  statement += ";\n";
  return statement;
}

/**
 * Handles explicit return:
 *  amaze <expression>
 *
 * Produces:
 *  return <expression>;
 */
function handleAmaze(parseContext) {
  tokenUtils.expectToken("amaze", parseContext);

  // consume: amaze
  parseContext.tokens.shift();

  return "return " + returnStatements(parseContext);
}

/**
 * Appends statements from the parse context into a single line
 */
function returnStatements(parseContext) {
  var statement = handleStatements(parseContext);
  if (statementHandlers.shouldCloseStatement(parseContext, statement)) {
    statement += ";\n";
  }

  return statement;
}

function handleStatement(parseContext) {
  var tokens = parseContext.tokens;

  // if processing multi-comment
  if (parserState.hasState(StateEnum.MULTILINE_COMMENT)) {
    // consume tokens until we encounter loud
    if (tokens[0] !== "loud") {
      // clear out tokens
      parseContext.tokens = [];
      return parseContext.input + "\n";
    }
    // else must be loud
    return commentHandlers.handleLoud(parseContext);
  }

  // not dogescript, such javascript
  if (!isDogescriptSource(parseContext)) {
    return tokenUtils.joinTokens(tokens) + "\n";
  }

  // trained use strict
  if (tokens[0] === "trained") {
    // consume: trained
    tokens.shift();
    return '"use strict";\n';
  }

  // such function
  if (tokens[0] === "such") {
    return functionHandlers.handleSuch(parseContext);
  }

  if (tokens[0] === "wow" || tokens[0] === "wow&") {
    return handleWow(parseContext);
  }

  // plz execute function
  if (tokens[0] === "plz" || tokens[0] === ".plz") {
    return invocationHandlers.handlePlz(parseContext);
  }
  // obj dose function
  if (tokens[0] === "dose" || tokens[1] === "dose") {
    return invocationHandlers.handleDose(parseContext);
  }

  // very new variable
  if (tokens[0] === "very") {
    return handleVery(parseContext);
  }

  // only applicable to disambiguate during control flow parsing
  if (parserState.hasState(StateEnum.CONTROL_FLOW)) {
    // convert to supported operator / otherwise fall thorugh
    // TODO remove operators as they become supported
    if (validOperators.hasOwnProperty(tokens[0])) {
      return validOperators[tokens.shift()];
    }
  }

  // support any kind of assignment operator
  if (operatorHandlers.isAssignmentOperator(tokens[0])) {
    var statement = operatorHandlers.handleAssignmentOperator(parseContext);

    if (tokens[0] === "new") {
      statement += invocationHandlers.handleNew(parseContext);
      return statement;
    }

    statement += handleStatement(parseContext);

    if (statementHandlers.shouldCloseStatement(parseContext, statement)) {
      statement += ";\n";
    }

    return statement;
  }

  // shh comment
  if (tokens[0] === "shh") {
    return commentHandlers.handleShh(parseContext);
  }

  // quiet start multi-line comment
  if (tokens[0] === "quiet") {
    return commentHandlers.handleQuiet(parseContext);
  }

  // rly if
  if (tokens[0] === "rly") {
    return handleRly(parseContext);
  }

  // ntrly if
  if (tokens[0] === "notrly") {
    return handleNotrly(parseContext);
  }

  // but else
  if (tokens[0] === "but") {
    return handleBut(parseContext);
  }

  // many while
  if (tokens[0] === "many") {
    return handleMany(parseContext);
  }

  // much for
  if (tokens[0] === "much") {
    return handleMuchLoop(parseContext);
  }

  // so require
  if (tokens[0] === "so") {
    return moduleHandlers.handleSo(parseContext);
  }

  // maybe boolean operator
  if (tokens[0] === "maybe") {
    // consume: maybe
    tokens.shift();
    return "(!!+Math.round(Math.random()))";
  }

  if (tokens[0] === "next") {
    // consume next
    tokens.shift();
    return ";";
  }

  // standalone increment/decrement
  if (operatorHandlers.containsIncrementDecrement(parseContext)) {
    return operatorHandlers.handleIncrementDecrementOperators(parseContext);
  }

  if (tokens[0] === "woof") {
    return moduleHandlers.handleWoof(parseContext);
  }

  if (tokens[0] === "debooger" || tokens[0] === "pawse") {
    return statementHandlers.handleDebugger(parseContext);
  }

  if (tokens[0] === "obj") {
    // consume obj
    tokens.shift();
    parserState.pushState(StateEnum.OBJECT);
    return "{\n";
  }

  if (operatorHandlers.isBinaryOperator(tokens[0])) {
    return operatorHandlers.handleBinaryOperator(parseContext);
  }

  if (tokens[0] === "giv") {
    return propertyAccessorHandlers.handleGiv(parseContext);
  }

  if (tokens[0] === "levl") {
    return propertyAccessorHandlers.handleLevl(parseContext);
  }

  if (tokens[0] === "amaze") {
    return handleAmaze(parseContext);
  }

  if (tokens[0] === "classy") {
    return classHandlers.handleClass(parseContext);
  }

  if (tokens[0] === "maker") {
    return classHandlers.handleMaker(parseContext);
  }

  if (tokens[0] === "git") {
    return classHandlers.handleGit(parseContext);
  }

  if (tokens[0] === "sit") {
    return classHandlers.handleSit(parseContext);
  }

  if (tokens[0] === "stay") {
    return classHandlers.handleStay(parseContext);
  }

  var statement = tokens.shift();
  // if there's more tokens, split them by a ' ' similar to how tokenUtils.joinTokens would work
  if (tokens.length > 0) {
    statement += " ";
  }
  return statement;
}

/**
 * Consumes every token in the parseContext, appending each found statement and returning all statements found.
 */
function handleStatements(parseContext) {
  var statements = "";

  while (parseContext.tokens.length > 0) {
    statements += handleStatement(parseContext);
  }

  return statements;
}

var replacements = {};
replacements["dogeument"] = "document";
replacements["windoge"] = "window";
replacements["dis"] = "this";
replacements["sooper"] = "super";

module.exports = function parse(line) {
  var tokens = tokenizer.tokenize(line);

  if (tokens.length == 0) {
    return line + "\n";
  }

  var parseContext = {
    input: line,
    // leave original tokens to throw better syntax errors
    inputTokens: tokens.slice(),
    tokens: tokens
  };

  // pre-process tokens and swap replacements
  for (let i = 0; i < tokens.length; i++) {
    var testToken = tokens[i];

    // if we see a shh, skip since everything should be preserved
    if (testToken === "shh") {
      break;
    }

    Object.keys(replacements).forEach(function(key) {
      if (testToken === key) {
        tokens[i] = replacements[key];
      }

      if (testToken.startsWith(key + ".")) {
        tokens[i] = testToken.replace(key + ".", replacements[key] + ".");
      }
    });
  }

  return handleStatements(parseContext);
};
<|endoftext|>


<commit_before>/*
  Parser
  Parses clean source. Generates clean AST.
*/
const biOps = require('./binaryOperators.js')
const estemplate = require('./template')
/*  Utility functions  */
const mayBe = (value, func) => value === null ? null : func(...value)
const precedence = operator => biOps[operator].prec
const associativity = operator => biOps[operator].assoc
const lookAhead = src => {
  let match = parser.all(spaceParser, binaryOperatorParser, spaceParser)(src)
  if (match !== null) {
    let [[, operator], remaining] = match
    return [operator, remaining]
  }
  return null
}
// Predifined regexes

/*  Predifined regexes */
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)*)$/
// var argsRegex = /^([^=]*)((.|\n)*)$/
const binaryOperatorRegex = /^(\+|\-|\/|\*|\<\<|\<\=|\<|\>\>\>|\>\>|\>\=|\>|\&\&|\&|\|\||\||\^|\=\=)(?=\s)((.|\n)*)$/
// var nullRegEx       = /^null\b/i

/*
  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),
  (m, val, rest) => [val, rest]
)

parser.bind = (mv, mf) => str => mayBe(
  mv(str),
  (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(/^(\s+)((.|\n)*)$/)

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 numberParser = str => mayBe(
  numRegex.exec(str),
  (a, num, rest) => [estemplate.literal(num, num), rest]
)

var identifierParser = str => mayBe(
  idRegex.exec(str),
  (a, name, rest) => [estemplate.identifier(name), rest]
)

var stringParser = str => mayBe(
  stringRegex.exec(str),
  (a, string, rest) => [estemplate.stringLiteral(string), rest]
)

var booleanParser = str => mayBe(
  boolRegex.exec(str),
  (a, bool, rest) => [estemplate.literal(bool), rest]
)

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

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

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

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

var binaryOperatorParser = parser.regex(binaryOperatorRegex)

var binaryExprParser = src => {
  var biExpr = estemplate.binaryExpression
  let result = parser.all(
                          expressionParser,
                          spaceParser,
                          binaryOperatorParser,
                          spaceParser,
                          parser.any(fnCallParser, expressionParser))(src)
  if (result === null) return null
  let [[leftOperand, , firstOperator, , rightOperand], rest] = result

  if (lookAhead(rest) === null) {
    return [biExpr(leftOperand, firstOperator, rightOperand), rest]
  }

  let [nextOperator, possibleExpr] = lookAhead(rest)

  let p = parser.any(binaryExprParser, expressionParser)(possibleExpr)
  if (p === null) return null
  let [nextExpr, remaining] = p

  if (precedence(nextOperator) < precedence(firstOperator)) {
    return [
      biExpr(
        biExpr(leftOperand, firstOperator, rightOperand),
        nextOperator,
        nextExpr),
      remaining]
  }

  if (precedence(nextOperator) > precedence(firstOperator)) {
    return (nextExpr.type === 'BinaryExpression') &&
           (precedence(nextExpr.operator) < precedence(nextOperator))
           ? [
             biExpr(
               biExpr(
                 leftOperand,
                 firstOperator,
                 biExpr(rightOperand, nextOperator, nextExpr.left)),
               nextExpr.operator,
               nextExpr.right),
             remaining]
             : [
               biExpr(
                 leftOperand,
                 firstOperator,
                 biExpr(rightOperand, nextOperator, nextExpr)),
               remaining]
  }

  if (precedence(nextOperator) === precedence(firstOperator)) {
    return associativity(firstOperator) === 'R'
            ? [
              biExpr(
                leftOperand,
                firstOperator,
                biExpr(rightOperand, nextOperator, nextExpr)),
              remaining]
              : [
                biExpr(
                  biExpr(leftOperand, firstOperator, rightOperand),
                  nextOperator,
                  nextExpr),
                remaining]
  }
}

var declParser = parser.bind(
  parser.bind(
    identifierParser,
    val => str => mayBe(
      equalSignParser(str),
      (v, rest) => [val, rest]
    )
  ),
  val => str => mayBe(
    parser.any(binaryExprParser, expressionParser)(str),
    (v, rest) => [estemplate.declaration(val, v), rest]
  )
)

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

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 => str => mayBe(
        lambdaParamsParser(str),
        (params, rest) => [estemplate.lambda(params), rest]
       )
      ),
    val => str => mayBe(
      thinArrowParser(str),
      (v, rest) => [val, rest]
    )
   ),
   val => str => mayBe(
     expressionParser(str),
     (v, rest) => {
       val.expression.body = v
       return [val, rest]
     }
   )
 )

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 => str => mayBe(
        letParamsParser(str),
        (val1, val2, rest) => [estemplate.letExpression(val1, val2), rest]
     )
    ),
    val => str => mayBe(
      inParser(str),
      (v, rest) => [val, rest]
    )
  ),
  val => str => mayBe(
    expressionParser(str),
    (v, rest) => {
      val.expression.callee.body = v
      return [val, rest]
    }
  )
)

var parenCheck = str => str[0] === ')' ? [')', str] : null

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

var fnCallParser = parser.bind(
  parser.all(identifierParser, spaceParser),
  val => str => mayBe(
    argsParser(str),
    (args, rest) => [estemplate.fnCall(val[0], args), rest]
  )
)

var statementParser = parser.any(spaceParser, letExpressionParser, declParser, fnDeclParser, fnCallParser, lambdaParser)

var programParser = (str, ast = estemplate.ast()) => {
  let result = statementParser(str)
  if (result === null) return ast
  if (typeof result[0] !== 'string') ast.body.push(result[0])
  return programParser(result[1], ast)
}

/*  Module Exports programParser  */
module.exports = programParser
<commit_msg>Refactor Binary Expression Parser<commit_after>/*
  Parser
  Parses clean source. Generates clean AST.
*/
const biOps = require('./binaryOperators.js')
const estemplate = require('./template')
/*  Utility functions  */
const mayBe = (value, func) => value === null ? null : func(...value)
const precedence = operator => biOps[operator].prec
const associativity = operator => biOps[operator].assoc
const lookAhead = src => {
  let match = parser.all(spaceParser, binaryOperatorParser, spaceParser)(src)
  if (match !== null) {
    let [[, operator], remaining] = match
    return [operator, remaining]
  }
  return null
}
// Predifined regexes

/*  Predifined regexes */
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)*)$/
// var argsRegex = /^([^=]*)((.|\n)*)$/
const binaryOperatorRegex = /^(\+|\-|\/|\*|\<\<|\<\=|\<|\>\>\>|\>\>|\>\=|\>|\&\&|\&|\|\||\||\^|\=\=)(?=\s)((.|\n)*)$/
// var nullRegEx       = /^null\b/i

/*
  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),
  (m, val, rest) => [val, rest]
)

parser.bind = (mv, mf) => str => mayBe(
  mv(str),
  (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(/^(\s+)((.|\n)*)$/)

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 numberParser = str => mayBe(
  numRegex.exec(str),
  (a, num, rest) => [estemplate.literal(num, num), rest]
)

var identifierParser = str => mayBe(
  idRegex.exec(str),
  (a, name, rest) => [estemplate.identifier(name), rest]
)

var stringParser = str => mayBe(
  stringRegex.exec(str),
  (a, string, rest) => [estemplate.stringLiteral(string), rest]
)

var booleanParser = str => mayBe(
  boolRegex.exec(str),
  (a, bool, rest) => [estemplate.literal(bool), rest]
)

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

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

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

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

var binaryOperatorParser = parser.regex(binaryOperatorRegex)

var binaryExprParser = src => {
  var biExpr = estemplate.binaryExpression
  let result = parser.all(
                          parser.any(fnCallParser, expressionParser),
                          spaceParser,
                          binaryOperatorParser,
                          spaceParser,
                          parser.any(fnCallParser, expressionParser))(src)
  if (result === null) return null
  let [[leftOperand, , firstOperator, , rightOperand], rest] = result

  if (lookAhead(rest) === null) {
    return [biExpr(leftOperand, firstOperator, rightOperand), rest]
  }

  let [nextOperator, possibleExpr] = lookAhead(rest)

  let p = parser.any(binaryExprParser, expressionParser)(possibleExpr)
  if (p === null) return null
  let [nextExpr, remaining] = p

  if (precedence(nextOperator) < precedence(firstOperator)) {
    return [
      biExpr(
        biExpr(leftOperand, firstOperator, rightOperand),
        nextOperator,
        nextExpr),
      remaining]
  }

  if (precedence(nextOperator) > precedence(firstOperator)) {
    return (nextExpr.type === 'BinaryExpression') &&
           (precedence(nextExpr.operator) < precedence(nextOperator))
           ? [
             biExpr(
               biExpr(
                 leftOperand,
                 firstOperator,
                 biExpr(rightOperand, nextOperator, nextExpr.left)),
               nextExpr.operator,
               nextExpr.right),
             remaining]
             : [
               biExpr(
                 leftOperand,
                 firstOperator,
                 biExpr(rightOperand, nextOperator, nextExpr)),
               remaining]
  }

  return associativity(firstOperator) === 'R'
          ? [
            biExpr(
              leftOperand,
              firstOperator,
              biExpr(rightOperand, nextOperator, nextExpr)),
            remaining]
            : [
              biExpr(
                biExpr(leftOperand, firstOperator, rightOperand),
                nextOperator,
                nextExpr),
              remaining]
}

var declParser = parser.bind(
  parser.bind(
    identifierParser,
    val => str => mayBe(
      equalSignParser(str),
      (v, rest) => [val, rest]
    )
  ),
  val => str => mayBe(
    parser.any(binaryExprParser, expressionParser)(str),
    (v, rest) => [estemplate.declaration(val, v), rest]
  )
)

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

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 => str => mayBe(
        lambdaParamsParser(str),
        (params, rest) => [estemplate.lambda(params), rest]
       )
      ),
    val => str => mayBe(
      thinArrowParser(str),
      (v, rest) => [val, rest]
    )
   ),
   val => str => mayBe(
     expressionParser(str),
     (v, rest) => {
       val.expression.body = v
       return [val, rest]
     }
   )
 )

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 => str => mayBe(
        letParamsParser(str),
        (val1, val2, rest) => [estemplate.letExpression(val1, val2), rest]
     )
    ),
    val => str => mayBe(
      inParser(str),
      (v, rest) => [val, rest]
    )
  ),
  val => str => mayBe(
    expressionParser(str),
    (v, rest) => {
      val.expression.callee.body = v
      return [val, rest]
    }
  )
)

var parenCheck = str => str[0] === ')' ? [')', str] : null

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

var fnCallParser = parser.bind(
  parser.all(identifierParser, spaceParser),
  val => str => mayBe(
    argsParser(str),
    (args, rest) => [estemplate.fnCall(val[0], args), rest]
  )
)

var statementParser = parser.any(spaceParser, letExpressionParser, declParser, fnDeclParser, fnCallParser, lambdaParser)

var programParser = (str, ast = estemplate.ast()) => {
  let result = statementParser(str)
  if (result === null) return ast
  if (typeof result[0] !== 'string') ast.body.push(result[0])
  return programParser(result[1], ast)
}

/*  Module Exports programParser  */
module.exports = programParser
<|endoftext|>


<commit_before>/**
 * # Game stages definition file
 * Copyright(c) {YEAR} {AUTHOR} <{AUTHOR_EMAIL}>
 * MIT Licensed
 *
 * Stages are defined using the stager API
 *
 * http://www.nodegame.org
 * ---
 */

module.exports = function(stager, settings) {

     stager
        .next('instructions')
        .repeat('game', settings.REPEAT)
        .next('end')
        .gameover();

    // Modify the stager to skip one stage.
    // stager.skip('instructions');

    return stager.getState();
};
<commit_msg>minor<commit_after>/**
 * # Game stages definition file
 * Copyright(c) {YEAR} {AUTHOR} <{AUTHOR_EMAIL}>
 * MIT Licensed
 *
 * Stages are defined using the stager API
 *
 * http://www.nodegame.org
 * ---
 */

module.exports = function(stager, settings) {

     stager
        .next('instructions')
        .repeat('game', settings.REPEAT)
        .next('end')
        .gameover();

    // Modify the stager to skip one stage.
    // stager.skip('instructions');
};
<|endoftext|>


<commit_before>
var fs = require("fs");
var path = require("path");
var utilities = require("./utilities");

/**
 * This is used as the display text for the build phase block in XCode as well as the
 * inline comments inside of the .pbxproj file for the build script phase block.
 */
var comment = "\"Fabric.io: Crashlytics\"";

module.exports = {

    /**
     * This helper is used to add a build phase to the XCode project which runs a shell
     * script during the build process. The script executes Crashlytics run command line
     * tool with the API and Secret keys. This tool is used to upload the debug symbols
     * (dSYMs) so that Crashlytics can display stack trace information in it's web console.
     */
    addShellScriptBuildPhase: function(context, xcodeProjectPath) {

        var pluginConfig = utilities.getPluginConfig("ios");
        var xcode = context.requireCordovaModule("xcode");

        // Read and parse the XCode project (.pxbproj) from disk.
        // File format information: http://www.monobjc.net/xcode-project-file-format.html
        var xcodeProject = xcode.project(xcodeProjectPath);
        xcodeProject.parseSync();

        xcodeProject.updateBuildProperty('ENABLE_BITCODE', 'NO');
        xcodeProject.updateBuildProperty('ENABLE_TESTABILITY', 'NO');

        // Build the body of the script to be executed during the build phase.
        // ../../plugins/plugin-id/lib/ios/Crashlytics.framework/run API_KEY SECRET_KEY
        var script = [
            "\"",
            utilities.getAppName(context),
            "/Plugins/",
            utilities.getPluginId(),
            "/Crashlytics.framework/run ",
            pluginConfig.apiKey,
            " ",
            pluginConfig.apiSecret,
            "\""
        ].join("");

        // Generate a unique ID for our new build phase.
        var id = xcodeProject.generateUuid();

        // Create the build phase.
        xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id] = {
            isa: "PBXShellScriptBuildPhase",
            buildActionMask: 2147483647,
            files: [],
            inputPaths: [],
            name: comment,
            outputPaths: [],
            runOnlyForDeploymentPostprocessing: 0,
            shellPath: "/bin/sh",
            shellScript: script,
            showEnvVarsInLog: 0
        };

        // Add a comment to the block (viewable in the source of the pbxproj file).
        xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id + "_comment"] = comment;

        // Add this new shell script build phase block to the targets.
        for (var nativeTargetId in xcodeProject.hash.project.objects.PBXNativeTarget) {

            // Skip over the comment blocks.
            if (nativeTargetId.indexOf("_comment") !== -1) {
                continue;
            }

            var nativeTarget = xcodeProject.hash.project.objects.PBXNativeTarget[nativeTargetId];

            nativeTarget.buildPhases.push({
                value: id,
                comment: comment
            });
        }

        // Finally, write the .pbxproj back out to disk.
        fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync());
    },

    /**
     * This helper is used to remove the build phase from the XCode project that was added
     * by the addShellScriptBuildPhase() helper method.
     */
    removeShellScriptBuildPhase: function(context, xcodeProjectPath) {

        var xcode = context.requireCordovaModule("xcode");

        // Read and parse the XCode project (.pxbproj) from disk.
        // File format information: http://www.monobjc.net/xcode-project-file-format.html
        var xcodeProject = xcode.project(xcodeProjectPath);
        xcodeProject.parseSync();

        // First, we want to delete the build phase block itself.

        var buildPhases = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase;

        for (var buildPhaseId in buildPhases) {

            var buildPhase = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[buildPhaseId];
            var shouldDelete = false;

            if (buildPhaseId.indexOf("_comment") === -1) {
                // Dealing with a build phase block.

                // If the name of this block matches ours, then we want to delete it.
                shouldDelete = buildPhase.name && buildPhase.name.indexOf(comment) !== -1;
            }
            else {
                // Dealing with a comment block.

                // If this is a comment block that matches ours, then we want to delete it.
                shouldDelete = buildPhaseId === comment;
            }

            if (shouldDelete) {
                delete buildPhases[buildPhaseId];
            }
        }

        // Second, we want to delete the native target reference to the block.

        var nativeTargets = xcodeProject.hash.project.objects.PBXNativeTarget;

        for (var nativeTargetId in nativeTargets) {

            // Skip over the comment blocks.
            if (nativeTargetId.indexOf("_comment") !== -1) {
                continue;
            }

            var nativeTarget = nativeTargets[nativeTargetId];

            // We remove the reference to the block by filtering out the the ones that match.
            nativeTarget.buildPhases = nativeTarget.buildPhases.filter(function (buildPhase) {
                return buildPhase.comment !== comment;
            });
        }

        // Finally, write the .pbxproj back out to disk.
        fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync());
    }
};
<commit_msg>update<commit_after>
var fs = require("fs");
var path = require("path");
var utilities = require("./utilities");

/**
 * This is used as the display text for the build phase block in XCode as well as the
 * inline comments inside of the .pbxproj file for the build script phase block.
 */
var comment = "\"Fabric.io: Crashlytics\"";

module.exports = {

    /**
     * This helper is used to add a build phase to the XCode project which runs a shell
     * script during the build process. The script executes Crashlytics run command line
     * tool with the API and Secret keys. This tool is used to upload the debug symbols
     * (dSYMs) so that Crashlytics can display stack trace information in it's web console.
     */
    addShellScriptBuildPhase: function(context, xcodeProjectPath) {

        var pluginConfig = utilities.getPluginConfig("ios");
        var xcode = context.requireCordovaModule("xcode");

        // Read and parse the XCode project (.pxbproj) from disk.
        // File format information: http://www.monobjc.net/xcode-project-file-format.html
        var xcodeProject = xcode.project(xcodeProjectPath);
        xcodeProject.parseSync();

        xcodeProject.updateBuildProperty('ENABLE_BITCODE', 'NO');
        xcodeProject.updateBuildProperty('ENABLE_TESTABILITY', 'NO');
        xcodeProject.updateBuildProperty('DEBUG_INFORMATION_FORMAT', 'dwarf-with-dsym');

        // Build the body of the script to be executed during the build phase.
        // ../../plugins/plugin-id/lib/ios/Crashlytics.framework/run API_KEY SECRET_KEY
        var script = [
            "\"",
            utilities.getAppName(context),
            "/Plugins/",
            utilities.getPluginId(),
            "/Crashlytics.framework/run ",
            pluginConfig.apiKey,
            " ",
            pluginConfig.apiSecret,
            "\""
        ].join("");

        // Generate a unique ID for our new build phase.
        var id = xcodeProject.generateUuid();

        // Create the build phase.
        xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id] = {
            isa: "PBXShellScriptBuildPhase",
            buildActionMask: 2147483647,
            files: [],
            inputPaths: [],
            name: comment,
            outputPaths: [],
            runOnlyForDeploymentPostprocessing: 0,
            shellPath: "/bin/sh",
            shellScript: script,
            showEnvVarsInLog: 0
        };

        // Add a comment to the block (viewable in the source of the pbxproj file).
        xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id + "_comment"] = comment;

        // Add this new shell script build phase block to the targets.
        for (var nativeTargetId in xcodeProject.hash.project.objects.PBXNativeTarget) {

            // Skip over the comment blocks.
            if (nativeTargetId.indexOf("_comment") !== -1) {
                continue;
            }

            var nativeTarget = xcodeProject.hash.project.objects.PBXNativeTarget[nativeTargetId];

            nativeTarget.buildPhases.push({
                value: id,
                comment: comment
            });
        }

        // Finally, write the .pbxproj back out to disk.
        fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync());
    },

    /**
     * This helper is used to remove the build phase from the XCode project that was added
     * by the addShellScriptBuildPhase() helper method.
     */
    removeShellScriptBuildPhase: function(context, xcodeProjectPath) {

        var xcode = context.requireCordovaModule("xcode");

        // Read and parse the XCode project (.pxbproj) from disk.
        // File format information: http://www.monobjc.net/xcode-project-file-format.html
        var xcodeProject = xcode.project(xcodeProjectPath);
        xcodeProject.parseSync();

        // First, we want to delete the build phase block itself.

        var buildPhases = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase;

        for (var buildPhaseId in buildPhases) {

            var buildPhase = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[buildPhaseId];
            var shouldDelete = false;

            if (buildPhaseId.indexOf("_comment") === -1) {
                // Dealing with a build phase block.

                // If the name of this block matches ours, then we want to delete it.
                shouldDelete = buildPhase.name && buildPhase.name.indexOf(comment) !== -1;
            }
            else {
                // Dealing with a comment block.

                // If this is a comment block that matches ours, then we want to delete it.
                shouldDelete = buildPhaseId === comment;
            }

            if (shouldDelete) {
                delete buildPhases[buildPhaseId];
            }
        }

        // Second, we want to delete the native target reference to the block.

        var nativeTargets = xcodeProject.hash.project.objects.PBXNativeTarget;

        for (var nativeTargetId in nativeTargets) {

            // Skip over the comment blocks.
            if (nativeTargetId.indexOf("_comment") !== -1) {
                continue;
            }

            var nativeTarget = nativeTargets[nativeTargetId];

            // We remove the reference to the block by filtering out the the ones that match.
            nativeTarget.buildPhases = nativeTarget.buildPhases.filter(function (buildPhase) {
                return buildPhase.comment !== comment;
            });
        }

        // Finally, write the .pbxproj back out to disk.
        fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync());
    }
};
<|endoftext|>


<commit_before>var serializer = require("./serializer");
var errors = require("./errors");
var Class = require(__basedir + "/utilities/class");
var Server = require("./server");
var constants = require("./constants");
var moment = require('moment');
var fs = require('fs');
var log = require("./log");

/**
 * @class Session: the server that handles of communications between a game and its clients, on a seperate thread than the lobby.
 */
var Session = Class(Server, {
    init: function(args) {
        Server.init.call(this, args);

        this._needToSendStart = true;
        this._sentOver = false;
        this._deltas = []; // A record of all deltas generated and sent, to store in the gamelog

        this.game = new args.gameClass({
            session: args.gameSession,
        });

        this._profiler = args.profiler;

        this.name = this.game.name + " - " + this.game.session + " @ " + process.pid;
    },

    /**
     * Overrides from the base Server class to start the game once all Clients have been constructed
     *
     * @override
     */
    addSocket: function(socket, clientInfo) {
        Server.addSocket.call(this, socket, clientInfo);

        if(this.getClientsPlaying().length === this.game.numberOfPlayers) {
            this.start();
        }
    },

    /**
     * Overridden to give a reason why it timed out (or more accurately, when)
     *
     * @override
     */
    clientTimedOut: function(client) {
        Server.clientTimedOut.call(this, client, "Timed out during gameplay.")
    },

    /**
     * Overridden so that when a client disconnects we can check if the game needs to end.
     *
     * @override
     */
    clientDisconnected: function(client, reason) {
        Server.clientDisconnected.call(this, client);

        this.game.playerDisconnected(client.player, reason);

        this._updateDeltas("disconnect", {
            player: client.player,
        });

        if(this.game.isOver() && this.clients.length === 0) {
            this.end();
        }
    },

    /**
     * Starts the game in this session
     */
    start: function() {
        log("Game is starting.");
        this.game.start(this.getClientsPlaying()); // note: the game only knows about clients playing, the session will care about spectators sending them deltas a such, so the game never needs to know of their existance

        if(this._profiler) {
            this._profiler.startProfiling();
        }

        this._updateDeltas("start");
    },

    /**
     * Called when the game ends, so that this thread "ends"
     */
    end: function() {
        if(this._profiler) {
            var profile = this._profiler.stopProfiling();
            profile.export(function(error, result) {
                fs.writeFileSync('output/profiles/profile-' + this.game.name + '-' + this.game.session + '-' + moment().format("YYYY.MM.DD.HH.mm.ss.SSS") + '.cpuprofile', result);
                profile.delete();
                process.exit(0); // "returns" to the lobby that this Session thread ended successfully. All players connected, played, then disconnected. So this session is over
            });
        }
        else {
            process.exit(0);
        }
    },

    /**
     * when the game state changes the clients need to know, and we need to check if that game ended when its state changed.
     *
     * @param {string} type - the type of delta that occured
     * @param {Object} [data] - any additional data about what caused the delta
     */
    _updateDeltas: function(type, data) {
        for(var i = 0; i < this.clients.length; i++) {
            var client = this.clients[i];
            client.send("delta", this.game.getDeltaFor(client.player));
        }

        if(data && data.player) {
            data.player = serializer.serialize(data.player, this.game);
        }

        var delta = this.game.getTrueDelta();
        this._deltas.push({
            type: type,
            data: data,
            game: delta,
        });

        this.game.flushDelta();

        if(this._needToSendStart) {
            this._needToSendStart = false;
            for(var i = 0; i < this.clients.length; i++) {
                var client = this.clients[i];

                client.send("start", {
                    playerID: client.player && client.player.id,
                });
            }
        }

        if(this.game.isOver() && !this._sentOver) {
            this._gameOver();
        }
        else { // game is still in progress, so send requests to players. Note we always do that after sending delta states so they have updated state info
            this._sendGameOrders();
        }
    },

    /**
     * Called when the game has ended (is over) and the clients need to know, and the gamelog needs to be generated
     */
    _gameOver: function() {
        this._sentOver = true;
        log("Game is over.");

        this._updateDeltas("over");

        for(var i = 0; i < this.clients.length; i++) {
            this.clients[i].send("over"); // TODO: send link to gamelog, or something like that.
        }

        process.send({
            gamelog: this.generateGamelog(),
        });
    },

    /**
     * Sends to all the clients in the game, that the game has orders they need to execute, depleating the orders stack
     */
    _sendGameOrders: function() {
        var orders = this.game.getNewOrders();

        for(var i = 0; i < orders.length; i++) {
            var order = orders[i];
            order.player.client.send("order", {
                name: order.name,
                index: order.index,
                args: order.args,
            });

            order.player.client.startTicking();
        }
    },

    /**
     * Checks if the client should be ignored because it is in a game ending condition
     *
     * @param {Client} client - client to check if it should be ignored
     * @returns {boolean} true if the client should be ignored, false otherwise
     */
    _checkToIgnoreClient: function(client) {
        if(this.game.isOver() || client.player.lost || client.player.won) {
            client.send("over");
            return true;
        }

        return false;
    },

    /////////////////////////////////////////////////////////////////////////////////////////////////
    /// Client functions. These should be invoked when a client sends something back to the server //
    /////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * A client sent a 'run' command, which is a request for the game to run game logic
     *
     * @param {Client} client - the client that sent this run event
     * @param {Object} run - data about what they want the game server to run
     */
    _clientSentRun: function(client, run) {
        client.pauseTicking();

        if(this._checkToIgnoreClient(client)) {
            return; // because they can't run anything right now
        }

        var self = this;
        this.game.aiRun(client.player, run) // this is a Promise, the game server is promising that eventually it will run the logic, we do this because the game server may need to get info asyncronously (such as from other AIs) before it can resolve this run command
            .then(function(returned) {
                var serializedReturned = serializer.serialize(returned, self.game);
                self._updateDeltas("ran", {
                    player: client.player,
                    data: run,
                    returned: serializedReturned,
                });

                client.send("ran", serializedReturned);
            })
            .catch(function(error) {
                if(!Class.isInstance(error, errors.CerveauError)) {
                    throw error;
                }
                client.send("invalid", error);
            });
    },

    /**
     * A client sent a 'finished' command, which is what happens when it finished an order
     *
     * @param {Client} client - the client that sent this finished event
     * @param {Object} data - finished data
     */
    _clientSentFinished: function(client, data) {
        client.pauseTicking();

        if(this._checkToIgnoreClient(client)) {
            return;
        }

        var finished = null;
        try {
            finished = this.game.aiFinished(client.player, data.orderIndex, data.returned);
        }
        catch(error)
        {
            if(!Class.isInstance(error, errors.CerveauError)) {
                throw error;
            }
            client.send("invalid", error);
        }

        this._updateDeltas("finished", {
            player: client.player,
            order: finished,
            returned: data.returned,
        });
    },

    /**
     * Generates the game log from all the events that happened in this game.
     *
     * @returns {Object} the gamelog to store somewhere and somehow (GameLogger handles that)
     */
    generateGamelog: function() {
        var winners = [];
        var losers = [];

        for(var i = 0; i < this.game.players.length; i++) {
            var player = this.game.players[i];

            (player.won ? winners : losers).push({
                index: i,
                id: player.id,
                name: player.name,
            });
        }

        return {
            gameName: this.game.name,
            gameSession: this.game.session,
            deltas: this._deltas,
            constants: constants.shared,
            epoch: moment().valueOf(),
            winners: winners,
            losers: losers,
        };
    },
});

module.exports = Session;
<commit_msg>gamelogs will now contain deltas as players see them, if they differ<commit_after>var serializer = require("./serializer");
var errors = require("./errors");
var Class = require(__basedir + "/utilities/class");
var Server = require("./server");
var constants = require("./constants");
var moment = require('moment');
var fs = require('fs');
var log = require("./log");

/**
 * @class Session: the server that handles of communications between a game and its clients, on a seperate thread than the lobby.
 */
var Session = Class(Server, {
    init: function(args) {
        Server.init.call(this, args);

        this._needToSendStart = true;
        this._sentOver = false;
        this._deltas = []; // A record of all deltas generated and sent, to store in the gamelog

        this.game = new args.gameClass({
            session: args.gameSession,
        });

        this._profiler = args.profiler;

        this.name = this.game.name + " - " + this.game.session + " @ " + process.pid;
    },

    /**
     * Overrides from the base Server class to start the game once all Clients have been constructed
     *
     * @override
     */
    addSocket: function(socket, clientInfo) {
        Server.addSocket.call(this, socket, clientInfo);

        if(this.getClientsPlaying().length === this.game.numberOfPlayers) {
            this.start();
        }
    },

    /**
     * Overridden to give a reason why it timed out (or more accurately, when)
     *
     * @override
     */
    clientTimedOut: function(client) {
        Server.clientTimedOut.call(this, client, "Timed out during gameplay.")
    },

    /**
     * Overridden so that when a client disconnects we can check if the game needs to end.
     *
     * @override
     */
    clientDisconnected: function(client, reason) {
        Server.clientDisconnected.call(this, client);

        this.game.playerDisconnected(client.player, reason);

        this._updateDeltas("disconnect", {
            player: client.player,
        });

        if(this.game.isOver() && this.clients.length === 0) {
            this.end();
        }
    },

    /**
     * Starts the game in this session
     */
    start: function() {
        log("Game is starting.");
        this.game.start(this.getClientsPlaying()); // note: the game only knows about clients playing, the session will care about spectators sending them deltas a such, so the game never needs to know of their existance

        if(this._profiler) {
            this._profiler.startProfiling();
        }

        this._updateDeltas("start");
    },

    /**
     * Called when the game ends, so that this thread "ends"
     */
    end: function() {
        if(this._profiler) {
            var profile = this._profiler.stopProfiling();
            profile.export(function(error, result) {
                fs.writeFileSync('output/profiles/profile-' + this.game.name + '-' + this.game.session + '-' + moment().format("YYYY.MM.DD.HH.mm.ss.SSS") + '.cpuprofile', result);
                profile.delete();
                process.exit(0); // "returns" to the lobby that this Session thread ended successfully. All players connected, played, then disconnected. So this session is over
            });
        }
        else {
            process.exit(0);
        }
    },

    /**
     * when the game state changes the clients need to know, and we need to check if that game ended when its state changed.
     *
     * @param {string} type - the type of delta that occured
     * @param {Object} [data] - any additional data about what caused the delta
     */
    _updateDeltas: function(type, data) {
        var trueDelta = this.game.getTrueDelta();
        var playerDeltas = {};

        if(data && data.player) {
            data.player = serializer.serialize(data.player, this.game); // because so many datas include a player sending them, it's easier to serialize them all here
        }

        var delta = {
            type: type,
            data: data,
            game: trueDelta,
        };

        for(var i = 0; i < this.clients.length; i++) {
            var client = this.clients[i];
            var deltaToSend = client.player ? this.game.getDeltaFor(client.player) : trueDelta;

            if(client.player && deltaToSend !== trueDelta) { // then this player got a different game state that the "true" one (it was probably obscured), so record that in the gamelog too
                delta.gameToPlayer = delta.gameToPlayer || {};
                delta.gameToPlayer[client.player.id] = deltaToSend;
            }

            client.send("delta", deltaToSend);
        }

        this._deltas.push(delta);
        this.game.flushDelta();

        if(this._needToSendStart) {
            this._needToSendStart = false;
            for(var i = 0; i < this.clients.length; i++) {
                var client = this.clients[i];

                client.send("start", {
                    playerID: client.player && client.player.id,
                });
            }
        }

        if(this.game.isOver() && !this._sentOver) {
            this._gameOver();
        }
        else { // game is still in progress, so send requests to players. Note we always do that after sending delta states so they have updated state info
            this._sendGameOrders();
        }
    },

    /**
     * Called when the game has ended (is over) and the clients need to know, and the gamelog needs to be generated
     */
    _gameOver: function() {
        this._sentOver = true;
        log("Game is over.");

        this._updateDeltas("over");

        for(var i = 0; i < this.clients.length; i++) {
            this.clients[i].send("over"); // TODO: send link to gamelog, or something like that.
        }

        process.send({
            gamelog: this.generateGamelog(),
        });
    },

    /**
     * Sends to all the clients in the game, that the game has orders they need to execute, depleating the orders stack
     */
    _sendGameOrders: function() {
        var orders = this.game.getNewOrders();

        for(var i = 0; i < orders.length; i++) {
            var order = orders[i];
            order.player.client.send("order", {
                name: order.name,
                index: order.index,
                args: order.args,
            });

            order.player.client.startTicking();
        }
    },

    /**
     * Checks if the client should be ignored because it is in a game ending condition
     *
     * @param {Client} client - client to check if it should be ignored
     * @returns {boolean} true if the client should be ignored, false otherwise
     */
    _checkToIgnoreClient: function(client) {
        if(this.game.isOver() || client.player.lost || client.player.won) {
            client.send("over");
            return true;
        }

        return false;
    },

    /////////////////////////////////////////////////////////////////////////////////////////////////
    /// Client functions. These should be invoked when a client sends something back to the server //
    /////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * A client sent a 'run' command, which is a request for the game to run game logic
     *
     * @param {Client} client - the client that sent this run event
     * @param {Object} run - data about what they want the game server to run
     */
    _clientSentRun: function(client, run) {
        client.pauseTicking();

        if(this._checkToIgnoreClient(client)) {
            return; // because they can't run anything right now
        }

        var self = this;
        this.game.aiRun(client.player, run) // this is a Promise, the game server is promising that eventually it will run the logic, we do this because the game server may need to get info asyncronously (such as from other AIs) before it can resolve this run command
            .then(function(returned) {
                var serializedReturned = serializer.serialize(returned, self.game);
                self._updateDeltas("ran", {
                    player: client.player,
                    data: run,
                    returned: serializedReturned,
                });

                client.send("ran", serializedReturned);
            })
            .catch(function(error) {
                if(!Class.isInstance(error, errors.CerveauError)) {
                    throw error;
                }
                client.send("invalid", error);
            });
    },

    /**
     * A client sent a 'finished' command, which is what happens when it finished an order
     *
     * @param {Client} client - the client that sent this finished event
     * @param {Object} data - finished data
     */
    _clientSentFinished: function(client, data) {
        client.pauseTicking();

        if(this._checkToIgnoreClient(client)) {
            return;
        }

        var finished = null;
        try {
            finished = this.game.aiFinished(client.player, data.orderIndex, data.returned);
        }
        catch(error)
        {
            if(!Class.isInstance(error, errors.CerveauError)) {
                throw error;
            }
            client.send("invalid", error);
        }

        this._updateDeltas("finished", {
            player: client.player,
            order: finished,
            returned: data.returned,
        });
    },

    /**
     * Generates the game log from all the events that happened in this game.
     *
     * @returns {Object} the gamelog to store somewhere and somehow (GameLogger handles that)
     */
    generateGamelog: function() {
        var winners = [];
        var losers = [];

        for(var i = 0; i < this.game.players.length; i++) {
            var player = this.game.players[i];

            (player.won ? winners : losers).push({
                index: i,
                id: player.id,
                name: player.name,
            });
        }

        return {
            gameName: this.game.name,
            gameSession: this.game.session,
            deltas: this._deltas,
            constants: constants.shared,
            epoch: moment().valueOf(),
            winners: winners,
            losers: losers,
        };
    },
});

module.exports = Session;
<|endoftext|>


<commit_before>
// Formulas for pentatonic scales
exports.MINOR_PENTATONIC = [3, 2, 2, 3, 2];  // minor pentatonic
exports.MAJOR_PENTATONIC = [2, 2, 3, 2, 3];  // major pentatonic

// Formulas for hexatonic scales
exports.MINOR_BLUES          = [3, 2, 1, 1, 3, 2];  // minor blues
exports.MAJOR_BLUES          = [2, 1, 1, 3, 2, 3];  // major blues
exports.PROMETHEUS           = [2, 2, 2, 3, 1, 2];  // prometheus - mystic
exports.ISTRIAN              = [1, 2, 1, 2, 1, 5];  // istrian
exports.WHOLE_TONE           = [2, 2, 2, 2, 2, 2];  // whole tone
exports.AUGMENTED            = [3, 1, 3, 1, 3, 1];  // augmented - symmetrical augmented
exports.TRITONE              = [1, 3, 2, 1, 3, 2];  // tritone
exports.TWO_SEMITONE_TRITONE = [1, 1, 4, 1, 1, 4];  // two semitone tritone

// Major derived formulas
exports.LYDIAN     = [2, 2, 2, 1, 2, 2, 1];  // lydian
exports.IONIAN     = [2, 2, 1, 2, 2, 2, 1];  // ionian - major
exports.MIXOLYDIAN = [2, 2, 1, 2, 2, 1, 2];  // mixolydian
exports.DORIAN     = [2, 1, 2, 2, 2, 1, 2];  // dorian
exports.AEOLIAN    = [2, 1, 2, 2, 1, 2, 2];  // aeolian - minor
exports.PHRYGIAN   = [1, 2, 2, 2, 1, 2, 2];  // phrygian
exports.LOCRIAN    = [1, 2, 2, 1, 2, 2, 2];  // locrian
exports.MAJOR      = [2, 2, 1, 2, 2, 2, 1];  // ionian alias
exports.MINOR      = [2, 1, 2, 2, 1, 2, 2];  // aeolian alias

// Melodic minor derived formulas
exports.MELODIC_MINOR     = [2, 1, 2, 2, 2, 2, 1]; // melodic minor
exports.DORIAN_FLAT9      = [1, 2, 2, 2, 2, 1, 2]; // dorian flat 9
exports.LYDIAN_AUGMENTED  = [2, 2, 2, 2, 1, 2, 1]; // lydian augmented
exports.LYDIAN_FLAT7      = [2, 2, 2, 1, 2, 1, 2]; // lydian flat 7
exports.MIXOLYDIAN_FLAT13 = [2, 2, 1, 2, 1, 2, 2]; // mixolydian flat 13
exports.SEMI_LOCRIAN      = [2, 1, 2, 1, 2, 2, 2]; // semilocrian
exports.SUPER_LOCRIAN     = [1, 2, 1, 2, 2, 2, 2]; // superlocrian

// Harmonic minor derived formulas
exports.HARMONIC_MINOR   = [2, 1, 2, 2, 1, 3, 1]; // harmonic minor
exports.LOCRIAN_SHARP7   = [1, 2, 2, 1, 3, 1, 2]; // locrian sharp 7
exports.IONIAN_AUGMENTED = [2, 2, 1, 3, 1, 2, 1]; // ionian augmented

<commit_msg>added triadFormulas<commit_after>// ===========================================
//              Scale Formulas
// ===========================================

// Formulas for pentatonic scales
exports.MINOR_PENTATONIC = [3, 2, 2, 3, 2];  // minor pentatonic
exports.MAJOR_PENTATONIC = [2, 2, 3, 2, 3];  // major pentatonic

// Formulas for hexatonic scales
exports.MINOR_BLUES          = [3, 2, 1, 1, 3, 2];  // minor blues
exports.MAJOR_BLUES          = [2, 1, 1, 3, 2, 3];  // major blues
exports.PROMETHEUS           = [2, 2, 2, 3, 1, 2];  // prometheus - mystic
exports.ISTRIAN              = [1, 2, 1, 2, 1, 5];  // istrian
exports.WHOLE_TONE           = [2, 2, 2, 2, 2, 2];  // whole tone
exports.AUGMENTED            = [3, 1, 3, 1, 3, 1];  // augmented - symmetrical augmented
exports.TRITONE              = [1, 3, 2, 1, 3, 2];  // tritone
exports.TWO_SEMITONE_TRITONE = [1, 1, 4, 1, 1, 4];  // two semitone tritone

// Major derived formulas
exports.LYDIAN     = [2, 2, 2, 1, 2, 2, 1];  // lydian
exports.IONIAN     = [2, 2, 1, 2, 2, 2, 1];  // ionian - major
exports.MIXOLYDIAN = [2, 2, 1, 2, 2, 1, 2];  // mixolydian
exports.DORIAN     = [2, 1, 2, 2, 2, 1, 2];  // dorian
exports.AEOLIAN    = [2, 1, 2, 2, 1, 2, 2];  // aeolian - minor
exports.PHRYGIAN   = [1, 2, 2, 2, 1, 2, 2];  // phrygian
exports.LOCRIAN    = [1, 2, 2, 1, 2, 2, 2];  // locrian
exports.MAJOR      = [2, 2, 1, 2, 2, 2, 1];  // ionian alias
exports.MINOR      = [2, 1, 2, 2, 1, 2, 2];  // aeolian alias

// Melodic minor derived formulas
exports.MELODIC_MINOR     = [2, 1, 2, 2, 2, 2, 1]; // melodic minor
exports.DORIAN_FLAT9      = [1, 2, 2, 2, 2, 1, 2]; // dorian flat 9
exports.LYDIAN_AUGMENTED  = [2, 2, 2, 2, 1, 2, 1]; // lydian augmented
exports.LYDIAN_FLAT7      = [2, 2, 2, 1, 2, 1, 2]; // lydian flat 7
exports.MIXOLYDIAN_FLAT13 = [2, 2, 1, 2, 1, 2, 2]; // mixolydian flat 13
exports.SEMI_LOCRIAN      = [2, 1, 2, 1, 2, 2, 2]; // semilocrian
exports.SUPER_LOCRIAN     = [1, 2, 1, 2, 2, 2, 2]; // superlocrian

// Harmonic minor derived formulas
exports.HARMONIC_MINOR   = [2, 1, 2, 2, 1, 3, 1]; // harmonic minor
exports.LOCRIAN_SHARP7   = [1, 2, 2, 1, 3, 1, 2]; // locrian sharp 7
exports.IONIAN_AUGMENTED = [2, 2, 1, 3, 1, 2, 1]; // ionian augmented

// ===========================================
//              Chord Formulas
// ===========================================

// Chord formulas:
var triadFormulas = {
    "major triad":      [4, 3],
    "minor triad":      [3, 4],
    "augmented triad":  [4, 4],
    "diminished triad": [3, 3],
    "suspended fourth": [5, 2],
    "suspended second": [2, 5]
};

exports.triadFormulas = triadFormulas;<|endoftext|>


<commit_before>const packer = require('./packer');

const terminator = "\0\0\0\0\0\0";
var processedTerminator = [];
terminator.split('').forEach(function (item) {
	processedTerminator.push(0);
});
processedTerminator = processedTerminator.join('||');

module.exports = function (socket, callback, data) {
	data = Array.prototype.slice.call(data);
	if (!Array.isArray(socket.data)) {
		socket.data = [];
	}
	if (data.join('||').indexOf(processedTerminator) < 0) {
		socket.data = socket.data.concat(data);
		return;
	}
	var splitted = data.join('||').split(processedTerminator);
	splitted.pop();
	splitted.forEach(function (chunk) {
		chunk = chunk.split('||');
		if (chunk[0] === '') {
			chunk.shift();
		} else {
			chunk.pop();
		}
		chunk.forEach(function (item, i) {
			chunk[i] = parseInt(item);
		});
		if (socket.data && socket.data.length > 0 && chunk.length === 0) {
			callback(packer.unpack(socket.data.concat(data)));
			socket.data = [];
			return;
		}
		callback(packer.unpack(chunk));
	});
};

module.exports.terminator = terminator;
<commit_msg>Fixed parser bug<commit_after>const packer = require('./packer');

const terminator = "\0\0\0\0\0\0";
const processedTerminator = '0||0||0||0||0||0';

module.exports = function (socket, callback, data) {
	data = Array.prototype.slice.call(data);
	if (!Array.isArray(socket.data)) {
		socket.data = [];
	}
	if (data.join('||').indexOf(processedTerminator) < 0) {
		socket.data = socket.data.concat(data);
		return;
	}
	if (socket.data && socket.data.length > 0) {
		data = socket.data.concat(data);
		socket.data = [];
	}
	var splitted = data.join('||').split(processedTerminator);
	splitted.forEach(function (chunk, i) {
		chunk = chunk.split('||');
		if (chunk[0] === '') {
			chunk.shift();
		} else {
			chunk.pop();
		}
		chunk.forEach(function (item, i) {
			chunk[i] = parseInt(item);
		});
		if (splitted.length - 1 === i) {
			socket.data = socket.data.concat(data);
			return;
		}
		callback(packer.unpack(chunk));
	});
};

module.exports.terminator = terminator;
<|endoftext|>