JSFiddle - React, Tailwind, and code Playground

by francisfortier

HTML

<ul>
    <li expected="2" func="evaluateAsNumber">1 + 1</li>
    <li expected="6" func="evaluateAsNumber">1 + 2 + 3</li>
    <li expected="7" func="evaluateAsNumber">1 + 2 * 3</li>
    <li expected="9" func="evaluateAsNumber">(1 + 2) * 3</li>
    <li expected="6" func="evaluateAsNumber">sqrt(9) * 2</li>
    <li expected="2" func="evaluateAsNumber">3 + (-1)</li>
    <li expected="4" define="a=2" func="evaluateAsNumber">a^2</li>
    <li expected="5" define="a=2" func="evaluateAsNumber">3 + max(a, 1)</li>
    <li expected="coco" func="evaluateAsString">"co" "co"</li>
    <li expected="1 + 1 = 2" func="evaluateAsString">"1 + 1 = " 1 + 1</li>
    <li expected="1 + 1 = 2" func="evaluateAsString">3 - 2 " + 1 = " 1 + 1</li>
    <li expected="Bonjour Francis" define="ab$=Francis" func="evaluateAsString">"Bonjour " ab$</li>
    <li expected="true" func="evaluateAsBoolean">1 &lt;= 3</li>
</ul>

JavaScript

variables = {};

functions = {
    sqrt: function(expr) {
        return Math.sqrt(expr.evaluateAsNumber());
    },
    max: function(exprA, exprB) {
        var a = exprA.evaluateAsNumber();
        var b = exprB.evaluateAsNumber();
        
        return a > b ? a : b;
    }
};

Delimiter = function() {
    var delimiters = [];
    var t = this;
    
    for (var i = 0; i < arguments.length; i++)
    {
        delimiters.push(arguments[i]);
    }
    
    this.check = function(token) {
        for (var i = 0; i < delimiters.length; i++)
        {
            if (delimiters[i] === token)
            {
                t.found = token;
                t.expectationFilled = true;
                
                return true;
            }
        }
        
        return false;
    };
    
    this.toString = function() {
        return '[' + delimiters.toString() + ']';
    };
    
    this.expectationFilled = arguments.length === 0;
};

Delimiter.defaultDelimiter = new Delimiter();

Expression = function() { };

Expression.operatorPrecedences = [
    ['<', '>', '<=', '>=', '=', '<>'],
    ['+', '-'],
    ['*', '/', '^']
];

Expression.build = function(exprs, operators) {
    if (exprs.length === 1)
        return exprs[0];
    
    // On parcourt les opérateurs dans l'ordre de précéance
    for (var precedenceIndex = 0; precedenceIndex < Expression.operatorPrecedences.length; precedenceIndex++)
    {
        for (var operatorIndex = 0; operatorIndex < Expression.operatorPrecedences[precedenceIndex].length; operatorIndex++)
        {
            var op = Expression.operatorPrecedences[precedenceIndex][operatorIndex];
            
            for (var i = 0; i < operators.length; i++)
            {
                if (operators[i] === op)
                {
                    var leftExpr = arguments.callee(exprs.slice(0, i + 1), operators.slice(0, i));
                    var rightExpr = arguments.callee(exprs.slice(i + 1), operators.slice(i + 1));
             ...