<commit_before>/**
 * Copyright (c) 2013 <NAME>
 * See the file license.txt for copying permission.
 */

/**
 * AVS expression parse and code generator.
 * Generates JS and GLSL code from avs expressions
 * @param codeSrc
 * @param externalVars list of variables that will be supplied externally
 *                     these variables will be instance values of the generated
 *                     code instance
 * @constructor
 */
function ExprCodeGenerator(codeSrc, externalVars) {
    this.codeSrc = codeSrc;
    this.externalVars = externalVars?externalVars:[];
    this._parseSrc();
}
extend(ExprCodeGenerator, Object, {
    _parseSrc: function() {
        // Generate AST and find variables usages in all the expressions
        var codeAst = {};
        var variables = {};
        for(var name in this.codeSrc) {
            try {
                codeAst[name] = Webvs.PegExprParser.parse(this.codeSrc[name]);
                variables[name] = _.uniq(this._getVars(codeAst[name]));
            } catch(e) {
                throw new Error("Error parsing " + name + " : " + e);
            }
        }
        this.codeAst = codeAst;

        // find the variables shared between expressions
        var sharedVars = [];
        for(var vName in variables) {
            for(var vName2 in variables) {
                if(vName2 == vName) {
                    continue;
                }
                sharedVars = sharedVars.concat(_.intersection(variables[vName], variables[vName2]));
            }
        }

        this.instanceVars = _.uniq(this.externalVars.concat(sharedVars));

        // find local variables for each expression
        var localVars = {};
        for(var varName in variables) {
            localVars[varName] = _.difference(variables[varName], this.instanceVars);
        }
        this.localVars = localVars;
    },

    /**
     * Generates code and returns a code instance containing
     * executable functions for the avs expressions. Empty no-op
     * functions are inserted if the expression was not supplied
     * @param funcs functions to be generated.
     * @returns {CodeInstance}
     */
    generateJs: function(funcs) {
        var js = new CodeInstance();
        var that = this;

        // clear all instance variables
        _.each(this.instanceVars, function(ivar) {
            js[ivar] = 0;
        });

        // generate code and assign function
        _.each(this.codeAst, function(codeAst, name) {
            if(!_.contains(funcs, name)) {
                return;
            }
            var codeString = that._generateJs(codeAst, that.localVars[name]);
            js[name] = new Function(codeString);
        });

        // add noops for missing expressions
        _.each(_.difference(funcs, _.functions(js)), function(name) {
            js[name] = noop;
        });
        return js;
    },

    /**
     * Generates glsl code for avs expressions. Empty void-void functions
     * are generated for missing functions
     * @param funcs list of functions to be generated
     * @param treatAsNonUniform these instance variables will be treated as non uniforms
     * @returns {string} string containing generated glsl code
     */
    generateGlsl: function(funcs, treatAsNonUniform) {
        var code = [];
        var that = this;

        // generate uniform and global declarations
        _.each(this.instanceVars, function(ivar) {
            var prefix = "";
            if(!_.contains(treatAsNonUniform, ivar)) {
                prefix = "uniform ";
            }
            code.push(prefix + "float " + ivar + ";");
        });

        // generate functions
        _.each(this.codeAst, function(codeAst, name) {
            if(!_.contains(funcs, name)) {
                return;
            }
            var codeString = that._generateGlsl(codeAst, that.localVars[name]);
            code.push("void " + name + "() {");
            code.push(codeString);
            code.push("}");
        });

        // generate noops for missing functions
        _.each(_.difference(funcs, _.keys(this.codeAst)), function(name) {
            code.push("void " + name + "() {}");
        });

        return code.join("\n");
    },

    _generateGlsl: function(ast, localVars) {
        var that = this;

        if(ast instanceof AstBinaryExpr) {
            return "(" + this._generateGlsl(ast.leftOperand) + ast.operator + this._generateGlsl(ast.rightOperand) + ")";
        }
        if(ast instanceof AstUnaryExpr) {
            return "(" + ast.operator + this._generateGlsl(ast.operand) + ")";
        }
        if(ast instanceof AstFuncCall) {
            var args = _.map(ast.args, function(arg) {return that._generateGlsl(arg);}).join(",");
            return "(" + this._translateGlslFuncName(ast.funcName) + "(" + args + "))";
        }
        if(ast instanceof AstAssignment) {
            return ast.identifier + "=" + this._generateGlsl(ast.expr);
        }
        if(ast instanceof AstProgram) {
            var declarations = _.map(localVars, function(localVar){
                return "float " + localVar + "=0.0";
            });
            var stmts = _.map(ast.statements, function(stmt) {return that._generateGlsl(stmt);});
            return declarations.concat(stmts).join(";\n")+";";
        }
        if(ast instanceof AstPrimaryExpr) {
            var suffix = "";
            if(typeof ast.value === "number" && ast.value%1 === 0) {
                suffix = ".0";
            }
            return this._translateConstants(ast.value).toString() + suffix;
        }
    },

    _generateJs: function(ast, localVars) {
        var prefix;
        var that = this;

        if(ast instanceof AstBinaryExpr) {
            return "(" + this._generateJs(ast.leftOperand) + ast.operator + this._generateJs(ast.rightOperand) + ")";
        }
        if(ast instanceof AstUnaryExpr) {
            return "(" + ast.operator + this._generateJs(ast.operand) + ")";
        }
        if(ast instanceof AstFuncCall) {
            var args = _.map(ast.args, function(arg) {return that._generateJs(arg);}).join(",");
            return "(" + this._translateJsFuncName(ast.funcName) + "(" + args + "))";
        }
        if(ast instanceof AstAssignment) {
            prefix = "";
            if(_.contains(this.instanceVars, ast.identifier)) {
                prefix = "this.";
            }
            return prefix + ast.identifier + "=" + this._generateJs(ast.expr);
        }
        if(ast instanceof AstProgram) {
            var declarations = _.map(localVars, function(localVar){
                return "var " + localVar + "=0";
            });
            var stmts = _.map(ast.statements, function(stmt) {return that._generateJs(stmt);});
            return declarations.concat(stmts).join(";\n");
        }
        if(ast instanceof AstPrimaryExpr) {
            prefix = "";
            if(typeof ast.value === "string" && _.contains(this.instanceVars, ast.value)) {
                prefix = "this.";
            }
            return prefix + this._translateConstants(ast.value).toString();
        }
    },

    _getVars: function(ast) {
        var that = this;
        if(ast instanceof AstBinaryExpr) {
            var leftVars = this._getVars(ast.leftOperand);
            var rightVars = this._getVars(ast.rightOperand);
            return leftVars.concat(rightVars);
        }
        if(ast instanceof AstUnaryExpr) {
            return this._getVars(ast.operand);
        }
        if(ast instanceof AstFuncCall) {
            return _.map(ast.args, function(arg) {return that._getVars(arg);} );
        }
        if(ast instanceof AstAssignment) {
            var vars = this._getVars(ast.expr);
            return vars.concat(ast.identifier);
        }
        if(ast instanceof AstProgram) {
            return _.flatMap(ast.statements, function(stmt) {return that._getVars(stmt);});
        }
        if(ast instanceof AstPrimaryExpr) {
            if(typeof ast.value === "string" && ast.value[0] !== "$") {
                return [ast.value];
            } else {
                return [];
            }
        }
    },

    _translateGlslFuncName: function(name) {
        switch(name) {
            case "sin": return "sin";
            case "cos": return "cos";
            case "tan": return "tan";
            case "asin": return "asin";
            case "acos": return "acos";
            case "atan": return "atan";
            case "log": return "log";
            //case "rand": return "this.rand";
        }
    },

    _translateJsFuncName: function(name) {
        switch(name) {
            case "sin": return "Math.sin";
            case "cos": return "Math.cos";
            case "tan": return "Math.tan";
            case "asin": return "Math.asin";
            case "acos": return "Math.acos";
            case "atan": return "Math.atan";
            case "log": return "Math.log";
            case "rand": return "this.rand";
        }
    },

    _translateConstants: function(value) {
        switch(value) {<commit_msg>more expr stuff WIP<commit_after>/**
 * Copyright (c) 2013 <NAME>
 * See the file license.txt for copying permission.
 */

/**
 * AVS expression parse and code generator.
 * Generates JS and GLSL code from avs expressions
 * @param codeSrc
 * @param externalVars list of variables that will be supplied externally
 *                     these variables will be instance values of the generated
 *                     code instance
 * @constructor
 */
function ExprCodeGenerator(codeSrc, externalVars) {
    this.codeSrc = codeSrc;
    this.externalVars = externalVars?externalVars:[];
    this._parseSrc();
}
extend(ExprCodeGenerator, Object, {
    _parseSrc: function() {
        // Generate AST and find variables usages in all the expressions
        var codeAst = {};
        var variables = {};
        for(var name in this.codeSrc) {
            try {
                codeAst[name] = Webvs.PegExprParser.parse(this.codeSrc[name]);
                variables[name] = _.uniq(this._getVars(codeAst[name]));
            } catch(e) {
                throw new Error("Error parsing " + name + " : " + e);
            }
        }
        this.codeAst = codeAst;

        // find the variables shared between expressions
        var sharedVars = [];
        for(var vName in variables) {
            for(var vName2 in variables) {
                if(vName2 == vName) {
                    continue;
                }
                sharedVars = sharedVars.concat(_.intersection(variables[vName], variables[vName2]));
            }
        }

        this.instanceVars = _.uniq(this.externalVars.concat(sharedVars));

        // find local variables for each expression
        var localVars = {};
        for(var varName in variables) {
            localVars[varName] = _.difference(variables[varName], this.instanceVars);
        }
        this.localVars = localVars;
    },

    /**
     * Generates code and returns a code instance containing
     * executable functions for the avs expressions. Empty no-op
     * functions are inserted if the expression was not supplied
     * @param funcs functions to be generated.
     * @returns {CodeInstance}
     */
    generateJs: function(funcs) {
        var js = new CodeInstance();
        var that = this;

        // clear all instance variables
        _.each(this.instanceVars, function(ivar) {
            js[ivar] = 0;
        });

        // generate code and assign function
        _.each(this.codeAst, function(codeAst, name) {
            if(!_.contains(funcs, name)) {
                return;
            }
            var codeString = that._generateJs(codeAst, that.localVars[name]);
            js[name] = new Function(codeString);
        });

        // add noops for missing expressions
        _.each(_.difference(funcs, _.functions(js)), function(name) {
            js[name] = noop;
        });
        return js;
    },

    /**
     * Generates glsl code for avs expressions. Empty void-void functions
     * are generated for missing functions
     * @param funcs list of functions to be generated
     * @param treatAsNonUniform these instance variables will be treated as non uniforms
     * @returns {string} string containing generated glsl code
     */
    generateGlsl: function(funcs, treatAsNonUniform) {
        var code = [];
        var that = this;

        // generate uniform and global declarations
        _.each(this.instanceVars, function(ivar) {
            var prefix = "";
            if(!_.contains(treatAsNonUniform, ivar)) {
                prefix = "uniform ";
            }
            code.push(prefix + "float " + ivar + ";");
        });

        var functionUsages = [];
        // generate functions
        _.each(this.codeAst, function(codeAst, name) {
            if(!_.contains(funcs, name)) {
                return;
            }
            var codeString = that._generateGlsl(codeAst, that.localVars[name], functionUsages);
            code.push("void " + name + "() {");
            code.push(codeString);
            code.push("}");
        });

        functionUsages = _.uniq(functionUsages);
        _.each(functionUsages, function(funcName) {
            code.push(this.glslFuncs[funcName]);
        });

        // generate noops for missing functions
        _.each(_.difference(funcs, _.keys(this.codeAst)), function(name) {
            code.push("void " + name + "() {}");
        });

        return code.join("\n");
    },

    funcArgLengths: {
        "above": 2,
        "below": 2,
        "equal": 2,
        "loop": 2,
        "if": 3,
        "sin": 1,
        "cos": 1,
        "tan": 1,
        "asin": 1,
        "acos": 1,
        "atan": 1,
        "log": 1,
        "rand": 1
    },

    jsMathFuncs: ["sin", "cos", "tan", "asin", "acos", "atan", "log"],
    glslBultinFuncs: ["sin", "cos", "tan", "asin", "acos", "atan", "log"],

    glslFuncs: {
        "rand": [
            "uniform vec2 __randStep;",
            "vec2 __randSeed;",
            "float rand(float max) {",
            "   __randCur += __randStep;",
            "   float val = fract(sin(dot(__randSeed.xy ,vec2(12.9898,78.233))) * 43758.5453);",
            "   return (floor(val*max)+1);",
            "}"
        ].join("]n")
    },

    _checkFunc: function(ast) {
        var requiredArgLength = this.funcArgLengths[ast.funcName];
        if(requiredArgLength == undefined) {
            throw Error("Unknown function " + ast.funcName);
        }
        if(ast.args.length != requiredArgLength) {
            throw Error(ast.funcName + " accepts " + requiredArgLength + " arguments");
        }
    },

    _generateGlsl: function(ast, fu, localVars) {
        var that = this;

        if(ast instanceof AstBinaryExpr) {
            return "(" + this._generateGlsl(ast.leftOperand, fu) + ast.operator + this._generateGlsl(ast.rightOperand, fu) + ")";
        }
        if(ast instanceof AstUnaryExpr) {
            return "(" + ast.operator + this._generateGlsl(ast.operand, fu) + ")";
        }
        if(ast instanceof AstFuncCall) {
            this._checkFunc(ast);
            switch(ast.funcName) {
                case "above":
                    return [
                        "(",
                        this._generateGlsl(ast.args[0], fu),
                        ">",
                        this._generateGlsl(ast.args[1], fu),
                        "?1.0:0.0)"
                    ].join("");
                case "below":
                    return [
                        "(",
                        this._generateGlsl(ast.args[0], fu),
                        "<",
                        this._generateGlsl(ast.args[1], fu),
                        "?1.0:0.0)"
                    ].join("");
                case "equal":
                    return [
                        "(",
                        this._generateGlsl(ast.args[0], fu),
                        "==",
                        this._generateGlsl(ast.args[1], fu),
                        "?1.0:0.0)"
                    ].join("");
                case "if":
                    return [
                        "(",
                        this._generateGlsl(ast.args[0], fu),
                        "!=0.0?",
                        this._generateGlsl(ast.args[1], fu),
                        ":",
                        this._generateGlsl(ast.args[2], fu),
                        ")"
                    ].join("");
                default:
                    if(!_.contains(this.glslBultinFuncs, ast.funcName)) {
                        fu.push(ast.funcName);
                    }
                    var args = _.map(ast.args, function(arg) {return that._generateGlsl(arg, fu);}).join(",");
                    return "(" + ast.funcName + "(" + args + "))";
            }
        }
        if(ast instanceof AstAssignment) {
            return ast.identifier + "=" + this._generateGlsl(ast.expr, fu);
        }
        if(ast instanceof AstProgram) {
            var declarations = _.map(localVars, function(localVar){
                return "float " + localVar + "=0.0";
            });
            var stmts = _.map(ast.statements, function(stmt) {return that._generateGlsl(stmt, fu);});
            return declarations.concat(stmts).join(";\n")+";";
        }
        if(ast instanceof AstPrimaryExpr) {
            var suffix = "";
            if(typeof ast.value === "number" && ast.value%1 === 0) {
                suffix = ".0";
            }
            return this._translateConstants(ast.value).toString() + suffix;
        }
    },

    _generateJs: function(ast, localVars) {
        var prefix;
        var that = this;

        if(ast instanceof AstBinaryExpr) {
            return "(" + this._generateJs(ast.leftOperand) + ast.operator + this._generateJs(ast.rightOperand) + ")";
        }
        if(ast instanceof AstUnaryExpr) {
            return "(" + ast.operator + this._generateJs(ast.operand) + ")";
        }
        if(ast instanceof AstFuncCall) {
            this._checkFunc(ast);
            switch(ast.funcName) {
                case "above":
                    return [
                        "(",
                        this._generateJs(ast.args[0]),
                        ">",
                        this._generateJs(ast.args[1]),
                        "?1:0)"
                    ].join("");
                case "below":
                    return [
                        "(",
                        this._generateJs(ast.args[0]),
                        "<",
                        this._generateJs(ast.args[1]),
                        "?1:0)"
                    ].join("");
                case "equal":
                    return [
                        "(",
                        this._generateJs(ast.args[0]),
                        "==",
                        this._generateJs(ast.args[1]),
                        "?1:0)"
                    ].join("");
                case "if":
                    return [
                        "(",
                        this._generateJs(ast.args[0]),
                        "!==0?",
                        this._generateJs(ast.args[1]),
                        ":",
                        this._generateJs(ast.args[2]),
                        ")"
                    ].join("");
                default:
                    var args = _.map(ast.args, function(arg) {return that._generateJs(arg);}).join(",");
                    var prefix = "";
                    if(_.contains(this.jsMathFuncs, ast.funcName)) {
                        prefix = "Math.";
                    } else {
                        prefix = "this.";
                    }
                    return "(" + prefix + ast.funcName + "(" + args + "))";
            }
        }
        if(ast instanceof AstAssignment) {
            prefix = "";
            if(_.contains(this.instanceVars, ast.identifier)) {
                prefix = "this.";
            }
            return prefix + ast.identifier + "=" + this._generateJs(ast.expr);
        }
        if(ast instanceof AstProgram) {
            var declarations = _.map(localVars, function(localVar){
                return "var " + localVar + "=0";
            });
            var stmts = _.map(ast.statements, function(stmt) {return that._generateJs(stmt);});
            return declarations.concat(stmts).join(";\n");
        }
        if(ast instanceof AstPrimaryExpr) {
            prefix = "";
            if(typeof ast.value === "string" && _.contains(this.instanceVars, ast.value)) {
                prefix = "this.";
            }
            return prefix + this._translateConstants(ast.value).toString();
        }
    },

    _mergeVars: function(vars1, vars2) {
        return [vars1[0].concat(vars2[0]), vars1[1].concat(vars2[1])];
    },

    _getVars: function(ast) {
        var that = this;
        if(ast instanceof AstBinaryExpr) {
            var leftVars = this._getVars(ast.leftOperand);
            var rightVars = this._getVars(ast.rightOperand);
            return this._mergeVars(leftVars, rightVars);
        }
        if(ast instanceof AstUnaryExpr) {
            return this._getVars(ast.operand);
        }
        if(ast instanceof AstFuncCall) {
            var vars = [[],[ast.funcName]];
            _.each(ast.args, function(arg) {
               that._mergeVars(vars, that._getVars(arg));
            });
            return vars;
        }
        if(ast instanceof AstAssignment) {
            var vars = this._getVars(ast.expr);
            return this._mergeVars(this._getVars(ast.expr), [[ast.identifier],[]]);
        }
        if(ast instanceof AstProgram) {
            var vars = [[],[]];
            _.each(ast.args, function(stmt) {
                that._mergeVars(vars, that._getVars(stmt));
            });
            return vars;
        }
        if(ast instanceof AstPrimaryExpr) {
            if(typeof ast.value === "string" && ast.value[0] !== "$") {
                return [[ast.value], []];
            } else {
                return [[], []];
            }
        }
    },

    _translateConstants: function(value) {
        switch(value) {
{'fraction_non_alphanumeric': 0.1294821613353129, 'fraction_numerical': 0.005218877941242633, 'mean_word_length': 1.5614196819543673, 'pattern_counts': {'":': 40, '<': 7, '<?xml version=': 0, '>': 7, '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': '1316714', 'n_tokens_mistral': 6109, 'n_tokens_neox': 5940, 'n_words': 1300}