<commit_before>var _ = require('lodash');
var astUtils = require('./ast-utils');

var buffer
  , print
  , indentationLevel
  , globalsContainerName = 'anglGlobals'
  ;

var initializeCompiler = function() {
    buffer = [];
    print = _.bind(buffer.push, buffer);
    indentationLevel = 0;
};

var indent = function() {
    indentationLevel++;
};

var outdent = function() {
    indentationLevel--;
    if(indentationLevel < 0) {
        throw new Error('Tried to outdent too far.');
    }
};

var printIndent = function() {
    // TODO create customizable indentation level
    // TODO make this faster?
    _.times(indentationLevel, function() {
        print('    ');
    });
};

// TODO properly translate all binops and unops:
//   ones that GML has that JS doesn't have
//   ones with different behavior that need to be implemented differently
//   DIV, MOD, ^^, bitwise ops
//   how does GML do type coercion (42 + "hello world")?  Do I need to emulate that behavior?
var generateExpression = function(astNode) {
    switch(astNode.type) {

        case 'identifier':
            var variable = astNode.variable;
            if(variable) {
                if(variable.getAccessType() === 'PROP_ACCESS') {
                    print(variable.getContainingObjectIdentifier() + '.');
                }
                print(variable.getJsIdentifier());
            } else {
                print(astNode.name);
            }
            // TODO will this ever need to be enclosed in parentheses?
            // How should I be handling this in the general case?
            break;

        case 'binop':
            print('(');
            // special-case the dot operator
            if(astNode.op === '.') {
                print('resolveObjectBeforeDot(');
                generateExpression(astNode.expr1);
                print(').');
                generateExpression(astNode.expr2);
            } else { // all other operators
                generateExpression(astNode.expr1);
                print(' ' + astNode.op + ' ');
                generateExpression(astNode.expr2);
            }
            print(')');
            break;

        case 'unop':
            print('(');
            print(astNode.op);
            generateExpression(astNode.expr);
            print(')');
            break;

        case 'number':
            print('(');
            print(astNode.val.toString());
            // TODO does toString always produce valid Javascript that will create the exact same number?
            print(')');
            break;

        case 'string':
            print('(');
            print(JSON.stringify(astNode.val));
            // TODO this fails in a select few corner cases.  Use something better,
            // perhaps stolen from the Jade source code
            print(')');
            break;

        case 'index':
            // TODO this needs a lot of work
            // What do we do when index values aren't numbers?  Aren't integers?
            // What about when the array isn't initialized or the target isn't an array?
            print('(');
            generateExpression(astNode.expr);
            print(')');
            _.each(astNode.indexes, function (index) {
                print('[');
                generateExpression(index);
                print(']');
            });
            break;

        case 'funccall':
            print('(');
            generateExpression(astNode.expr);
            print(')(');
            _.each(astNode.args, function(arg, i, args) {
                generateExpression(arg);
                if(i < args.length - 1) {
                    print(', ');
                }
            });
            print(')');
            break;

        default:
            throw new Error('Unknown expression type: "' + astNode.type + '"');
    }
};

var generateStatement = function(astNode, omitTerminator, omitIndentation) {<commit_msg>Added generation of anonymous Angl scripts<commit_after>var _ = require('lodash');
var astUtils = require('./ast-utils');

var buffer
  , print
  , indentationLevel
  , globalsContainerName = 'anglGlobals'
  ;

var initializeCompiler = function() {
    buffer = [];
    print = _.bind(buffer.push, buffer);
    indentationLevel = 0;
};

var indent = function() {
    indentationLevel++;
};

var outdent = function() {
    indentationLevel--;
    if(indentationLevel < 0) {
        throw new Error('Tried to outdent too far.');
    }
};

var printIndent = function() {
    // TODO create customizable indentation level
    // TODO make this faster?
    _.times(indentationLevel, function() {
        print('    ');
    });
};

// TODO properly translate all binops and unops:
//   ones that GML has that JS doesn't have
//   ones with different behavior that need to be implemented differently
//   DIV, MOD, ^^, bitwise ops
//   how does GML do type coercion (42 + "hello world")?  Do I need to emulate that behavior?
var generateExpression = function(astNode, omitIndentation) {
    switch(astNode.type) {

        case 'identifier':
            var variable = astNode.variable;
            if(variable) {
                if(variable.getAccessType() === 'PROP_ACCESS') {
                    print(variable.getContainingObjectIdentifier() + '.');
                }
                print(variable.getJsIdentifier());
            } else {
                print(astNode.name);
            }
            // TODO will this ever need to be enclosed in parentheses?
            // How should I be handling this in the general case?
            break;

        case 'binop':
            print('(');
            // special-case the dot operator
            if(astNode.op === '.') {
                print('resolveObjectBeforeDot(');
                generateExpression(astNode.expr1);
                print(').');
                generateExpression(astNode.expr2);
            } else { // all other operators
                generateExpression(astNode.expr1);
                print(' ' + astNode.op + ' ');
                generateExpression(astNode.expr2);
            }
            print(')');
            break;

        case 'unop':
            print('(');
            print(astNode.op);
            generateExpression(astNode.expr);
            print(')');
            break;

        case 'number':
            print('(');
            print(astNode.val.toString());
            // TODO does toString always produce valid Javascript that will create the exact same number?
            print(')');
            break;

        case 'string':
            print('(');
            print(JSON.stringify(astNode.val));
            // TODO this fails in a select few corner cases.  Use something better,
            // perhaps stolen from the Jade source code
            print(')');
            break;

        case 'index':
            // TODO this needs a lot of work
            // What do we do when index values aren't numbers?  Aren't integers?
            // What about when the array isn't initialized or the target isn't an array?
            print('(');
            generateExpression(astNode.expr);
            print(')');
            _.each(astNode.indexes, function (index) {
                print('[');
                generateExpression(index);
                print(']');
            });
            break;

        case 'funccall':
            print('(');
            generateExpression(astNode.expr);
            print(')(');
            _.each(astNode.args, function(arg, i, args) {
                generateExpression(arg);
                if(i < args.length - 1) {
                    print(', ');
                }
            });
            print(')');
            break;

        case 'script':
            print('function(');
            print(['other'].concat(astNode.args).join(', '));
            print(') {\n');
            indent();
            generateLocalVariableAllocation(astNode);
            // TODO this part of the AST doesn't seem quite right, suggesting there are
            // possibilities I'm not aware of.
            // These sanity checks will reject anything unexpected.
            /*if(!(_.isObject(astNode.stmts) && _(_.keys(astNode.stmts).sort()).isEqual(['list', 'type']) && astNode.stmts.type === 'statements' && _.isArray(astNode.stmts.list))) {
             throw new Error('Failed sanity checks on stmts!')
             }
             _.each(astNode.stmts.list, generateStatement)*/
            generateStatement(astNode.stmts);
            outdent();
            omitIndentation || printIndent();
            print('}');
            break;

        default:
            throw new Error('Unknown expression type: "' + astNode.type + '"');
    }
};

var generateStatement = function(astNode, omitTerminator, omitIndentation) {
{'fraction_non_alphanumeric': 0.12195676905574517, 'fraction_numerical': 0.0020477815699658703, 'mean_word_length': 1.669602186456119, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1112452', 'n_tokens_mistral': 2305, 'n_tokens_neox': 2198, 'n_words': 618}