2014年7月15日火曜日

JavaScript で書いてみた。これをもっと簡単に、手っ取り早く書けるようなプログラミング言語を作るってことかなぁ〜

コード(BBEdit, Emacs)

var pre = document.querySelector('#pre0'),
    select = document.querySelector('#select0'),
    num = document.querySelector('#n0'),
    button = document.querySelector('#b0'),
    select1 = document.querySelector('#select1'),
    button1 = document.querySelector('#b1'),
    has_value = function (connector) {
        return connector('has_value');
    },
    get_value = function (connector) {
        return connector('value');
    },
    set_value = function (connector, new_value, informant) {
        return connector('set_value')(new_value, informant);
    },
    forget_value = function (connector, retractor) {
        return connector('forget')(retractor);
    },
    connect = function (connector, new_constraint) {
        return connector('connect')(new_constraint);
    },
    inform_about_value = function (constraint) {
        return constraint('I have a value');
    },
    inform_about_no_value = function (constraint) {
        return constraint('I lost my value');
    },
    multiplier = function (m1, m2, product) {
        var process_new_value = function () {
                if ((has_value(m1) && (get_value(m2) === 0)) ||
                        (has_value(m2) && (get_value(m1) === 0))) {
                    return set_value(product, 0, me);
                }
                if (has_value(m1) && has_value(m2)) {
                    return set_value(product, get_value(m1) * get_value(m2), me);
                }
                if (has_value(product) && has_value(m1)) {
                    return set_value(m2, get_value(product) / get_value(m1), me);
                }
                if (has_value(product) && has_value(m2)) {
                    return set_value(m1, get_value(product) / get_value(m2), me);
                }
            },
            process_forget_value = function () {
                forget_value(product, me);
                forget_value(m1, me);
                forget_value(m2, me);
                return process_new_value();
            },
            me = function (request) {
                switch (request) {
                    case 'I have a value':
                        return process_new_value();
                    case 'I lost my value':
                        return process_forget_value();
                    default:
                        throw 'Unknown request -- MULTIPLIER ' + request;
                }
            };
        connect(m1, me);
        connect(m2, me);
        connect(product, me);
        return me;
    },
    probe = function (name, connector) {
        var print_probe = function (value) {
                pre.textContent += name + ' = ' + value + '\n';
            },
            process_new_value = function () {
                return print_probe(get_value(connector));
            },
            process_forget_value = function () {
                return print_probe('?');
            },
            me = function (request) {
                switch (request) {
                    case 'I have a value':
                        return process_new_value();
                    case 'I lost my value':
                        return process_forget_value();
                    default:
                        throw 'Unknown request -- PROBE ' + request;
                }
            };
        connect(connector, me);
        return me;
    },
    make_connector = function () {
        var value = false,
            informant = false,
            constraints = [],
            set_my_value = function (newval, setter) {
                if (!has_value(me)) {
                    value = newval;
                    informant = setter;
                    return for_each_except(setter, inform_about_value,
                                           constraints);
                }
                if (value !== newval) {
                    throw '設定済み: ' + [value, newval];
                }
                return 'ignored';
            },
            forget_my_value = function (retractor) {
                var ary = constraints.slice();
                if (retractor === informant) {
                    informant = false;
                    return for_each_except(retractor, inform_about_no_value,
                                           ary);
                }
                return 'ignored';
            },
            connect = function (new_constraint) {
                if (constraints.indexOf(new_constraint) === -1) {
                    constraints.unshift(new_constraint);
                }
                if (has_value(me)) {
                    inform_about_value(new_constraint);
                }
                return 'done';
            },
            me = function (request) {
                switch (request) {
                    case 'has_value':
                        return informant ? true : false;
                    case 'value':
                        return value;
                    case 'set_value':
                        return set_my_value;
                    case 'forget':
                        return forget_my_value;
                    case 'connect':
                        return connect;
                    default:
                        throw 'Unknown operation -- CONNECTOR ' + request;
                }
            };
        return me;
    },
    for_each_except = function (exception, procedure, ary) {
        var i = 1;
        var loop = function (ary) {
                var ary1 = ary.slice();
                if (ary1.length === 0) {
                    return 'done';
                }
                if (ary1[0] === exception) {
                    ary1.shift();
                    return loop(ary1);
                }
                procedure(ary.shift());
                return loop(ary);
            },
            ary1 = ary.slice();
        
        return loop(ary1);
    },
    n = make_connector(),
    price = make_connector(),
    total = make_connector(),
    value;

multiplier(n, price, total);
probe('個数', n);
probe('単価', price);
probe('代金', total);

button.onclick = function () {
    if (num.value.match(/\D/) || num.value === '') {
        pre.textContent += '数値を設定する必要があります\n';
    } else {
        value = parseInt(num.value, 10);
        try {
            switch (select.value) {
                case 'n':
                    return set_value(n, value, 'kamimura');
                case 'price':
                    return set_value(price, value, 'kamimura');
                case 'total':
                    return set_value(total, value, 'kamimura');
            }
        } catch (e) {
            pre.textContent += e + '\n';
        }
    }
};
button1.onclick = function () {
    try {
        switch (select1.value) {
            case 'n':
                return forget_value(n,'kamimura');
            case 'price':
                return forget_value(price, 'kamimura');
            case 'total':
                return forget_value(total, 'kamimura');
        }
    } catch (e) {
        pre.textContent += e + '\n';
    }
};

出力結果


個数 × 単価 = 代金

0 コメント:

コメントを投稿