diff --git a/src/css/styles.css b/src/css/styles.css index 4416e83..2694168 100644 --- a/src/css/styles.css +++ b/src/css/styles.css @@ -16,6 +16,7 @@ code { font-size: 1.2em; font-weight: bold; } .expression .result td { border-top: dotted 1px gray; } .expression { font-size: 1.5em; font-family: monospace } .expression .prefix { font-weight: normal; display: none; font-size: 0.9em } +.expression .other { font-size: 0.9em} .hex .prefix { display: inline; } @@ -36,6 +37,7 @@ code { font-size: 1.2em; font-weight: bold; } .light .indicator { color: #ddd; } .light .on { color: #121212; } .light .prefix { color: #888} +.light .other { font-size: 0.9em} /* Dark */ .dark { background: #121212; color: white;} @@ -45,5 +47,6 @@ code { font-size: 1.2em; font-weight: bold; } .dark .on { color: white; } .dark .zero { color: #999;} .dark .prefix { color: #999} +.dark .other { color: #444;} diff --git a/src/index.html b/src/index.html index ea64e91..5646263 100644 --- a/src/index.html +++ b/src/index.html @@ -115,40 +115,40 @@ - - @@ -170,6 +170,7 @@ else { cmd.execute('1|2'); + cmd.execute('1<<0x2a'); cmd.execute('2 4 8 16 32'); } diff --git a/src/js/app/bitwise/expression.js b/src/js/app/bitwise/expression.js index 5276338..79be83c 100644 --- a/src/js/app/bitwise/expression.js +++ b/src/js/app/bitwise/expression.js @@ -1,51 +1,48 @@ app.set('expression', function() { "use strict"; - var decNumber = "\d+"; - var hexNumber = "(?:\d|a|b|c|d|e|f)"; - var modes = { - 'dec': { - expr: /^(\d+)\s*(<<|>>|\||\&|\^)\s*(\d+)$/, - list: /^((\d*)+\s?)+$/ - }, - 'hex': { - expr: /^([\d,a-f]+)\s*(<<|>>|\||\&|\^)\s*([\d,a-f]+)$/, - list: /^(([\d,a-f]*)+\s?)+$/ - } - }; + var exprRegex = /^(\d+|0x[\d,a-f]+)\s*(<<|>>|\||\&|\^)\s*(\d+|0x[\d,a-f]+)$/; + var listRegex = /^((\d+|0x[\d,a-f]+)\s?)+$/ return { canParse: function(string, mode) { - var regex = modes[mode || 'dec']; - return regex.expr.test(string) || regex.list.test(string); + return exprRegex.test(string) || listRegex.test(string); }, parse: function(string, mode) { mode = (mode || 'dec'); var trimmed = string.replace(/^\s+|\s+$/, ''); - var regex = modes[mode]; var base = getBase(mode); - var matches = regex.expr.exec(trimmed); + var matches = exprRegex.exec(trimmed); if(matches != null) { return createCalculableExpression(matches, base); } - matches = regex.list.exec(string); + matches = listRegex.exec(string); if(matches != null) { return createListOfNumbersExpression(string, base) } + }, + parseOperand: function(input) { + return new Operand(input); + }, + createOperand: function(number, kind) { + var str = number.toString(getBase(kind)); + if(kind == 'hex') { + str = "0x" + str; + } + + return new Operand(str); } + }; function createCalculableExpression(matches, base) { - var o1 = parseInt(matches[1], base); - var o2 = parseInt(matches[3], base); - var m = new app.models.BitwiseOperation(); - m.operand1 = new Operand(o1); - m.operand2 = new Operand(o2); + m.operand1 = new Operand(matches[1]); + m.operand2 = new Operand(matches[3]); m.sign = matches[2]; m.string = matches.input; //m.result = eval(matches.input); @@ -54,15 +51,15 @@ app.set('expression', function() { } function createListOfNumbersExpression(input, base) { - var numbers = []; + var operands = []; input.split(' ').forEach(function(n){ if(n.trim().length > 0) { - numbers.push(parseInt(n, base)); + operands.push(new Operand(n.trim())); } }); - return new app.models.BitwiseNumbers(numbers); + return new app.models.BitwiseNumbers(operands); } function getBase(mode) { @@ -73,11 +70,16 @@ app.set('expression', function() { } } - function Operand(n) { - this.value = n; - this.hex = n.toString(16); - this.dec = n.toString(10); - this.bin = n.toString(2); + function Operand(input) { + // console.log('input: ' + input); + this.input = input; + this.value = parseInt(input); + // console.log('value: ' + this.value); + this.hex = '0x' + this.value.toString(16); + this.dec = this.value.toString(10); + this.bin = this.value.toString(2); + this.kind = this.input.indexOf('0x') == 0 ? 'hex' : 'dec'; + this.other = this.kind == 'dec' ? this.hex : this.dec; } Operand.prototype.valueOf = function () { diff --git a/src/js/app/modelViews.js b/src/js/app/modelViews.js index 1767aff..799d795 100644 --- a/src/js/app/modelViews.js +++ b/src/js/app/modelViews.js @@ -6,32 +6,18 @@ app.compose(function () { var calc = app.get('calc'); var html = app.get('html'); var cmdConfig = app.get('cmdConfig'); + var expression = app.get('expression'); app.modelView(app.models.BitwiseOperation, { renderView: function(expr) { - var result = calc.calcExpression(expr); - var maxLen = getBinaryLength([expr.operand1.value, expr.operand2.value, result]); + var result = expression.createOperand(calc.calcExpression(expr), getResultMode([expr.operand1, expr.operand2])); + var maxLen = getBinaryLength([expr.operand1.value, expr.operand2.value, result.value]); var model = Object.create(expr); - - var otherMode = cmdConfig.mode == 'dec' ? 'hex' : 'dec'; - - model.mode = cmdConfig.mode; - model.otherMode = otherMode; - - model.operand1Str = expr.operand1[cmdConfig.mode]; + model.result = result; model.operand1Binary = formatter.padLeft(expr.operand1.bin, maxLen); - model.operand1Other = formatter.padLeft(expr.operand1[otherMode]); - - model.operand2Str = expr.operand2[cmdConfig.mode]; model.operand2Binary = formatter.padLeft(expr.operand2.bin, maxLen); - model.operand2Other = expr.operand2[otherMode]; - - model.resultStr = formatter.formatString(result, cmdConfig.mode); - model.resultBinary = formatter.padLeft(formatter.formatString(result, cmdConfig.mode), maxLen); - model.resultOther = formatter.formatString(result, otherMode); - - console.log(model); + model.resultBinary = formatter.padLeft(model.result.bin, maxLen); var templateId = /<<|>>/.test(model.sign) ? 'shiftExpressionView' : 'binaryExpressionView'; var template = app.template(templateId); @@ -48,7 +34,7 @@ app.compose(function () { var table = html.element('
'); var otherMode = cmdConfig.mode == 'dec' ? 'hex' : 'dec'; - model.numbers.forEach(function(n){ + model.operands.forEach(function(n){ var row = table.insertRow(); var decCell = row.insertCell(); @@ -59,12 +45,12 @@ app.compose(function () { var binCell = row.insertCell(); binCell.className = 'bin'; - decCell.innerHTML = html.template('0x{n}', { n: formatter.formatString(n, cmdConfig.mode) }); - binCell.textContent = formatter.padLeft(formatter.formatString(n), maxLen); + decCell.textContent = n.input; + binCell.textContent = formatter.padLeft(n.bin, maxLen); var otherCell = row.insertCell(); - otherCell.className = 'other ' + otherMode; - otherCell.innerHTML = html.template('0x{n}', { n: formatter.formatString(n, otherMode) }); + otherCell.className = 'other'; + otherCell.textContent = n.other; }); colorizeBits(table); @@ -118,5 +104,15 @@ app.compose(function () { .replace(/1/g, '1'); }); } + + function getResultMode(operands) { + for(var i=0; i index) { - sb.push("\t\thtml.push('" + normalize(template.substr(index, m.index - index)) + "');"); - } - sb.push('\t\thtml.push(' + m[1] + ');'); - index = m.index + m[0].length; - } - - if(index < template.length - 1) { - sb.push("\t\thtml.push('" + normalize(template.substr(index, template.length - index)) + "');"); - } - sb.push('\t}'); - sb.push("\treturn html.join('');"); - sb.push('}'); - sb.push('})()') - console.log(sb.join('\r\n')); - return eval(sb.join('\r\n')); - } - }; - - function normalize(str) { - return str.replace(/(\r|\n)+/g, '').replace("'", "\\\'"); - } - */ })(window.app, window.core); \ No newline at end of file diff --git a/src/js/components/templatesFeature.js b/src/js/components/templatesFeature.js index bccf5c5..e2f0405 100644 --- a/src/js/components/templatesFeature.js +++ b/src/js/components/templatesFeature.js @@ -1,11 +1,16 @@ (function(app) { "use strict"; - function Template(html) { + function Template(html, isCompiled) { this.html = html; + this.isCompiled = isCompiled === true; } Template.prototype.render = function (model) { + if(this.isCompiled) { + return app.get('html').element(this.process(model)); + } + return app.get('html').element(this.html, model); }; @@ -16,11 +21,11 @@ throw new Error(key + ' template is not found'); } return tpl; - } + }; app.run(function() { readTemplates(app.get('rootView')); - }) + }); function readTemplates(containerEl) { var els = containerEl.querySelectorAll('[data-template]'); @@ -34,9 +39,49 @@ return; } - store[key] = new Template(element.innerHTML); + + var template = new Template(element.innerHTML); + store[key] = template; + + if(element.hasAttribute('data-compiled')) { + template.process = compile(template.html); + template.isCompiled = true; + } }); - } + + + function compile (template) { + var regex = /(?:{([^}]+)})/g; + + var sb = []; + + sb.push('(function() {') + sb.push('return function (m) { ') + sb.push('\tvar html = [];') + sb.push('console.log(m)'); + var m, index = 0; + while ((m = regex.exec(template)) !== null) { + if(m.index > index) { + sb.push("\t\thtml.push('" + normalize(template.substr(index, m.index - index)) + "');"); + } + sb.push('\t\thtml.push(' + m[1] + ');'); + index = m.index + m[0].length; + } + + if(index < template.length - 1) { + sb.push("\t\thtml.push('" + normalize(template.substr(index, template.length - index)) + "');"); + } + sb.push("\treturn html.join('');"); + sb.push('}'); + sb.push('})()'); + console.log(sb.join('\r\n')); + return eval(sb.join('\r\n')); + } + }; + + function normalize(str) { + return str.replace(/(\r|\n)+/g, '').replace("'", "\\\'"); + } })(window.app); diff --git a/tests/domain/expressionSpec.js b/tests/domain/expressionSpec.js index f119430..ef42fef 100644 --- a/tests/domain/expressionSpec.js +++ b/tests/domain/expressionSpec.js @@ -1,38 +1,86 @@ +var app = window.app; +var expression = app.get('expression'); + describe("expression parse", function() { - var app = window.app; - var expression = app.get('expression'); - var decCases = { - "1 2 3": { numbers: [1,2,3] }, - "1": { numbers: [1] }, - "2>>1": { operand1: 2, operand2:1, "sign":">>", string:"2>>1" }, + var shouldParse = ['0x2>>1', '1 2 3', '0x1 1 2 3 5', '0x1>>0x2', '1|2']; + + it("should be able to parse", function() { + shouldParse.forEach(function(expr) { + console.log(expr); + expect(expression.canParse(expr)).toBe(true); + }) + }); + + var expressionCases = { + "0x2>>1": { operand1: 2, operand2:1, "sign":">>", string:"0x2>>1" }, "123|111": { operand1: 123, operand2:111, "sign":"|", string: "123|111" }, - "23^1": { operand1: 23, operand2:1, "sign":"^", string: "23^1" } + "23^0x1": { operand1: 23, operand2:1, "sign":"^", string: "23^0x1" }, + "0xf>>0xa": { operand1: 15, operand2:10, "sign":">>", string:"0xf>>0xa" }, + "0x10&0x11": { operand1: 0x10, operand2:0x11, "sign":"&", string:"0x10&0x11" }, + "0x1a^11": { operand1: 0x1a, operand2:11, "sign":"^", string:"0x1a^11" } }; - var hexCases = { - "1 10 f" : { numbers: [1, 16, 15] }, - "f>>a": { operand1: 15, operand2:10, "sign":">>", string:"f>>a" }, - "10&11": { operand1: 16, operand2:17, "sign":"&", string:"10&11" }, - "10^11": { operand1: 16, operand2:17, "sign":"^", string:"10^11" } - }; - - it("should parse decimal expressions", function() { + it("should parse expressions", function() { var input, expr; - for(input in decCases) { - expect(expression.canParse(input)).toBe(true); - expr = expression.parse(input); - expect(JSON.stringify(expr)).toEqual(JSON.stringify(decCases[input])); + for(input in expressionCases) { + var actual = expression.parse(input); + var expected = expressionCases[input]; + expect(actual).toBeDefined(); + expect(actual).not.toBe(null); + expect(actual.sign).toBe(expected.sign); + expect(actual.operand1.value).toBe(expected.operand1); + expect(actual.operand2.value).toBe(expected.operand2); + expect(actual.string).toBe(expected.string); } }); + var listCases = { + '1 2 3': [1, 2, 3], + '0x1 2 0xa6b': [0x1, 2, 0xa6b], + '0x11a': [0x11a] + }; + it("should parse hexadecimal expressions", function() { - var input, expr; - for(input in hexCases) { - console.log('input: ' + input) - expect(expression.canParse(input, 'hex')).toBe(true); - expr = expression.parse(input, 'hex'); - expect(JSON.stringify(expr)).toEqual(JSON.stringify(hexCases[input])); + var input, expr, i; + for(input in listCases) { + var actual = expression.parse(input); + var expected = listCases[input]; + + for(i =0; i