mirror of
https://github.com/BorysLevytskyi/BitwiseCmd.git
synced 2025-12-10 06:52:05 +01:00
Complete of support of multi-operand expressions
This commit is contained in:
@@ -25,6 +25,7 @@ code { font-size: 1.2em; font-weight: bold; }
|
||||
.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}
|
||||
.expression .sign { text-align: right}
|
||||
|
||||
.hex .prefix { display: inline; }
|
||||
|
||||
|
||||
@@ -150,6 +150,7 @@
|
||||
<table class="expression">
|
||||
{each itm in m.items}
|
||||
<tr class="{itm.css}">
|
||||
<td class="sign">{itm.sign}</td>
|
||||
<td class="label">{itm.label}</td>
|
||||
<td class="bin">{itm.bin.padLeft(m.maxNumberOfBits, '0')}</td>
|
||||
<td class="other">{itm.other}</td>
|
||||
@@ -161,12 +162,14 @@
|
||||
<script data-template="notExpressionView" data-compiled="" type="text/template">
|
||||
<table class="expression">
|
||||
<tr>
|
||||
<td class="sign"></td>
|
||||
<td class="label">{m.operand1.input}</td>
|
||||
<td class="bin">{m.operand1.bin.padLeft(m.bitsSize, '0')}</td>
|
||||
<td class="other">{m.operand1.other}</td>
|
||||
</tr>
|
||||
<tr class="expression-result">
|
||||
<td class="label">{m.sign}{m.operand1.input}={m.result.input}</td>
|
||||
<td class="sign">{m.sign}</td>
|
||||
<td class="label">{m.result.input}</td>
|
||||
<td class="bin">{m.result.bin.padLeft(m.bitsSize, '0')}</td>
|
||||
<td class="other">{m.result.other}</td>
|
||||
</tr>
|
||||
@@ -176,19 +179,19 @@
|
||||
<script data-template="binaryExpressionView" data-compiled="" type="text/template">
|
||||
<table class="expression">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="sign"></td>
|
||||
<td class="label">{m.operand1.input}</td>
|
||||
<td class="bin">{m.operand1.bin.padLeft(m.bitsSize, '0')}</td>
|
||||
<td class="other">{m.operand1.other}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{m.sign}</td>
|
||||
<td class="sign">{m.sign}</td>
|
||||
<td class="label">{m.operand2.input}</td>
|
||||
<td class="bin">{m.operand2.bin.padLeft(m.bitsSize, '0')}</td>
|
||||
<td class="other">{m.operand2.other}</td>
|
||||
</tr>
|
||||
<tr class="expression-result">
|
||||
<td>=</td>
|
||||
<td class="sign">=</td>
|
||||
<td class="label">{m.result.input}</td>
|
||||
<td class="bin">{m.result.bin.padLeft(m.bitsSize, '0')}</td>
|
||||
<td class="other">{m.result.other}</td>
|
||||
|
||||
@@ -15,7 +15,7 @@ app.set('expression', function() {
|
||||
},
|
||||
parse: function(string) {
|
||||
var trimmed = string.replace(/^\s+|\s+$/, '');
|
||||
var i = 0, l = this.factories.length, factory, matches;
|
||||
var i = 0, l = this.factories.length, factory;
|
||||
|
||||
for(;i<l;i++) {
|
||||
factory = this.factories[i];
|
||||
@@ -77,48 +77,23 @@ app.set('expression', function() {
|
||||
}
|
||||
});
|
||||
|
||||
// Two operands expression
|
||||
expression.addFactory({
|
||||
regex: /^(-?(?:\d+|0x[\d,a-f]+))\s*(<<|>>|>>>|\||\&|\^)\s*(-?(?:\d+|0x[\d,a-f]+))$/,
|
||||
canCreate: function(string) {
|
||||
return this.regex.test(string);
|
||||
},
|
||||
create: function (string) {
|
||||
var matches = this.regex.exec(string),
|
||||
operand1 = new Operand(matches[1]),
|
||||
operand2 = new Operand(matches[3]),
|
||||
sign = matches[2],
|
||||
expressionString = matches.input;
|
||||
|
||||
return new TwoOperandExpression(expressionString, operand1, operand2, sign);
|
||||
}
|
||||
});
|
||||
|
||||
// Multiple operands expression
|
||||
expression.addFactory({
|
||||
fullRegex: /^((?:\s*)(<<|>>|>>>|\||\&|\^)?(?:\s*)(-?(?:\d+|0x[\d,a-f]+)))+$/,
|
||||
regex: /(?:\s*)(<<|>>|>>>|\||\&|\^)?(?:\s*)(-?(?:\d+|0x[\d,a-f]+))/g,
|
||||
fullRegex: /^((<<|>>|>>>|\||\&|\^)?(-?((?:\d+(?!x))|(?:0x[\d,a-f]+))))+$/,
|
||||
regex: /(<<|>>|>>>|\||\&|\^)?(-?((?:\d+(?!x))|(?:0x[\d,a-f]+)))/g,
|
||||
canCreate: function(string) {
|
||||
this.fullRegex.lastIndex = 0;
|
||||
return this.fullRegex.test(string);
|
||||
return this.fullRegex.test(this.normalizeString(string));
|
||||
},
|
||||
create: function (string) {
|
||||
var m = null, operands = [];
|
||||
var m, operands = [],
|
||||
normalizedString = this.normalizeString(string);
|
||||
|
||||
while ((m = this.regex.exec(string)) != null) {
|
||||
while ((m = this.regex.exec(normalizedString)) != null) {
|
||||
operands.push(this.parseMatch(m));
|
||||
}
|
||||
|
||||
//matches.input.replace(this.regex, function(inpt, sign, num) {
|
||||
// if(sign == null) {
|
||||
// operands.push(new Operand(num));
|
||||
// } else {
|
||||
// operands.push(new SingleOperandExpression(inpt, new Operand(num), sign))
|
||||
// }
|
||||
//
|
||||
//});
|
||||
|
||||
return new MultipleOperandsExpression(string, operands)
|
||||
return new MultipleOperandsExpression(normalizedString, operands)
|
||||
},
|
||||
parseMatch: function (m) {
|
||||
var input = m[0],
|
||||
@@ -130,6 +105,9 @@ app.set('expression', function() {
|
||||
} else {
|
||||
return new SingleOperandExpression(input, new Operand(num), sign);
|
||||
}
|
||||
},
|
||||
normalizeString: function (string) {
|
||||
return string.replace(/\s+/g,'');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -189,6 +167,10 @@ app.set('expression', function() {
|
||||
return Operand.create(eval(str), this.operand1.kind);
|
||||
};
|
||||
|
||||
SingleOperandExpression.prototype.isShiftExpression = function () {
|
||||
return this.sign.indexOf('<') >= 0 || this.sign.indexOf('>')>= 0;
|
||||
};
|
||||
|
||||
function TwoOperandExpression(expressionString, operand1, operand2, sign) {
|
||||
this.expressionString = expressionString;
|
||||
this.operand1 = operand1;
|
||||
|
||||
@@ -50,16 +50,16 @@ app.run(function() {
|
||||
return this.locateModel(expr);
|
||||
},
|
||||
locateModel: function (expr) {
|
||||
if(expr instanceof expression.SingleOperandExpression || expr instanceof expression.TwoOperandExpression){
|
||||
return new app.models.BitwiseOperation(expr);
|
||||
}
|
||||
|
||||
if(expr instanceof expression.ListOfNumbersExpression) {
|
||||
return new app.models.BitwiseNumbers(expr);
|
||||
}
|
||||
|
||||
if(expr instanceof expression.SingleOperandExpression ){
|
||||
return new app.models.BitwiseExpression.buildNot(expr);
|
||||
}
|
||||
|
||||
if(expr instanceof expression.MultipleOperandsExpression) {
|
||||
return new app.models.BitwiseExpression(expr);
|
||||
return new app.models.BitwiseExpression.buildMultiple(expr);
|
||||
}
|
||||
|
||||
return new app.models.ErrorResult('Cannot create model for expression: ' + expr.toString());
|
||||
|
||||
@@ -1,59 +1,84 @@
|
||||
(function(app) {
|
||||
"use strict";
|
||||
|
||||
|
||||
function BitwiseOperation (expression) {
|
||||
this.expression = expression;
|
||||
this.operand1 = expression.operand1;
|
||||
this.operand2 = expression.operand2;
|
||||
this.sign = expression.sign;
|
||||
this.string = expression.expressionString;
|
||||
function BitwiseOperation (expr) {
|
||||
this.expression = expr;
|
||||
this.operand1 = expr.operand1;
|
||||
this.operand2 = expr.operand2;
|
||||
this.sign = expr.sign;
|
||||
this.string = expr.expressionString;
|
||||
}
|
||||
|
||||
function BitwiseNumbers(expression) {
|
||||
this.expression = expression;
|
||||
this.operands = expression.numbers;
|
||||
function BitwiseNumbers(expr) {
|
||||
this.expression = expr;
|
||||
this.operands = expr.numbers;
|
||||
|
||||
var numbers = this.numbers = [];
|
||||
|
||||
expression.numbers.forEach(function (o) {
|
||||
expr.numbers.forEach(function (o) {
|
||||
numbers.push(o.value);
|
||||
});
|
||||
}
|
||||
|
||||
function BitwiseExpression(expression) {
|
||||
function BitwiseExpression() {
|
||||
this.items = [];
|
||||
this.maxNumberOfBits = 0;
|
||||
}
|
||||
|
||||
var op = expression.expressions[0],
|
||||
i = 1, l = expression.expressions.length,
|
||||
ex;
|
||||
BitwiseExpression.buildMultiple = function (expr) {
|
||||
var op = expr.expressions[0],
|
||||
i = 1, l = expr.expressions.length,
|
||||
ex, m = new BitwiseExpression();
|
||||
|
||||
this.addOperand(op);
|
||||
m.addOperand(op);
|
||||
|
||||
for (;i<l;i++) {
|
||||
ex = expression.expressions[i];
|
||||
this.addExpression(ex);
|
||||
ex = expr.expressions[i];
|
||||
op = ex.apply(op.value);
|
||||
this.addResult(op);
|
||||
|
||||
if(ex.isShiftExpression()){
|
||||
m.addShiftExpressionResult(ex, op);
|
||||
} else {
|
||||
m.addExpression(ex);
|
||||
m.addExpressionResult(op);
|
||||
}
|
||||
}
|
||||
|
||||
this.maxNumberOfBits = this.emphasizeBytes(this.maxNumberOfBits);
|
||||
}
|
||||
m.maxNumberOfBits = m.emphasizeBytes(m.maxNumberOfBits);
|
||||
return m;
|
||||
};
|
||||
|
||||
BitwiseExpression.buildNot = function (expression) {
|
||||
var m = new BitwiseExpression();
|
||||
m.addExpression(expression);
|
||||
m.addExpressionResult(expression.apply());
|
||||
m.maxNumberOfBits = m.emphasizeBytes(m.maxNumberOfBits);
|
||||
return m;
|
||||
};
|
||||
|
||||
BitwiseExpression.prototype.addOperand = function(operand) {
|
||||
this.maxNumberOfBits = Math.max(operand.getLengthInBits(), this.maxNumberOfBits);
|
||||
this.items.push({ label: operand.toString(), bin: operand.bin, other: operand.other, css: ''});
|
||||
this.items.push({ sign:'', label: operand.toString(), bin: operand.bin, other: operand.other, css: ''});
|
||||
};
|
||||
|
||||
BitwiseExpression.prototype.addExpression = function(expression) {
|
||||
this.maxNumberOfBits = Math.max(expression.operand1.getLengthInBits(), this.maxNumberOfBits);
|
||||
this.items.push({ label: expression.toString(), bin: expression.operand1.bin, other: expression.operand1.other, css: ''});
|
||||
this.items.push({ sign: expression.sign, label: expression.operand1.input, bin: expression.operand1.bin, other: expression.operand1.other, css: ''});
|
||||
};
|
||||
|
||||
BitwiseExpression.prototype.addResult = function(operand) {
|
||||
BitwiseExpression.prototype.addShiftExpressionResult = function(expression, resultOperand) {
|
||||
this.maxNumberOfBits = Math.max(resultOperand.getLengthInBits(), this.maxNumberOfBits);
|
||||
this.items.push({
|
||||
sign: expression.sign + expression.operand1.input,
|
||||
label: resultOperand,
|
||||
bin: resultOperand.bin,
|
||||
other: resultOperand.other,
|
||||
css: 'expression-result'});
|
||||
};
|
||||
|
||||
BitwiseExpression.prototype.addExpressionResult = function(operand) {
|
||||
this.maxNumberOfBits = Math.max(operand.getLengthInBits(), this.maxNumberOfBits);
|
||||
this.items.push({ label: "=" + operand.toString(), bin: operand.bin, other: operand.other, css: 'expression-result'});
|
||||
this.items.push({ sign:'=', label: operand.toString(), bin: operand.bin, other: operand.other, css: 'expression-result'});
|
||||
};
|
||||
|
||||
BitwiseExpression.prototype.emphasizeBytes = function (bits) {
|
||||
|
||||
@@ -41,6 +41,7 @@ describe('launch of application', function() {
|
||||
.then(function() { return sendCommand('0x1 0xf')})
|
||||
.then(function() { return sendCommand('0x1 | 0xf')})
|
||||
.then(function() { return sendCommand('0x1 ^ 123')})
|
||||
.then(function() { return sendCommand('1|2&3|5 |5')})
|
||||
.then(function() { return sendCommand('dark')})
|
||||
.then(function() { return sendCommand('light')})
|
||||
.then(assertNoErrors);
|
||||
@@ -63,21 +64,21 @@ describe('launch of application', function() {
|
||||
|
||||
return assertOperation('1<<1',
|
||||
[{ label: '1', bin:'00000001', other: '0x1'},
|
||||
{ label: '1<<1=2', bin:'00000010', other: '0x2'}])
|
||||
{ sign:'<<1', label: '2', bin:'00000010', other: '0x2'}])
|
||||
});
|
||||
|
||||
it('should do a ignroe sign RIGHT shift operation', function() {
|
||||
it('should do a ignore sign RIGHT shift operation', function() {
|
||||
|
||||
return assertOperation('-1>>>1',
|
||||
[{ label: '-1', bin:'11111111111111111111111111111111', other: '-0x1'},
|
||||
{ label: '-1>>>1=2147483647', bin:'01111111111111111111111111111111', other: '0x7fffffff'}])
|
||||
{ sign: '>>>1', label: '2147483647', bin:'01111111111111111111111111111111', other: '0x7fffffff'}])
|
||||
});
|
||||
|
||||
it('should do NOT operation', function() {
|
||||
|
||||
return assertOperation('~1',
|
||||
[{ label: '1', bin:'00000000000000000000000000000001', other: '0x1'},
|
||||
{ label: '~1=-2', bin:'11111111111111111111111111111110', other: '-0x2'}])
|
||||
[{ sing: '~', label: '1', bin:'00000000000000000000000000000001', other: '0x1'},
|
||||
{ sign: '=', label: '-2', bin:'11111111111111111111111111111110', other: '-0x2'}])
|
||||
});
|
||||
|
||||
it('should execute multiple expressions from hash arguments', function() {
|
||||
@@ -88,8 +89,8 @@ describe('launch of application', function() {
|
||||
return assertMultipleExpressionResults(driver, [
|
||||
//16&15
|
||||
[{ label: '16', bin:'00010000', other: '0x10'},
|
||||
{ label: '15', bin:'00001111', other: '0xf'},
|
||||
{ label: '0', bin:'00000000', other: '0x0'}],
|
||||
{ sign:'&', label: '15', bin:'00001111', other: '0xf'},
|
||||
{ sign:'=', label: '0', bin:'00000000', other: '0x0'}],
|
||||
|
||||
//16 15
|
||||
[{ label: '16', bin:'00010000', other: '0x10'},
|
||||
@@ -101,34 +102,47 @@ describe('launch of application', function() {
|
||||
it('should do OR operation', function() {
|
||||
|
||||
return assertOperation('1|2',
|
||||
[{ label: '1', bin:'00000001', other: '0x1'},
|
||||
{ sign: '|', label: '2', bin:'00000010', other: '0x2'},
|
||||
{ sign: '=', label: '3', bin:'00000011', other: '0x3'}])
|
||||
});
|
||||
|
||||
it('should do multiple operand expression', function() {
|
||||
|
||||
return assertOperation('1|2|4<<0x1',
|
||||
[{ label: '1', bin:'00000001', other: '0x1'},
|
||||
{ label: '2', bin:'00000010', other: '0x2'},
|
||||
{ label: '3', bin:'00000011', other: '0x3'}])
|
||||
{ sign:'|', label: '2', bin:'00000010', other: '0x2'},
|
||||
{ sign: '=', label: '3', bin:'00000011', other: '0x3'},
|
||||
{ sign: '|', label: '4', bin:'00000100', other: '0x4'},
|
||||
{ sign: '=', label: '7', bin:'00000111', other: '0x7'},
|
||||
{ sign: '<<0x1', label: '0xe', bin:'00001110', other: '14'}
|
||||
])
|
||||
});
|
||||
|
||||
it('should do XOR or large numbers', function() {
|
||||
|
||||
return assertOperation('0x0001000000003003^0x3001800400000fc1',
|
||||
[{ label: '0x0001000000003003', bin:'0000000000000001000000000000000000000000000000000011000000000011', other: '281474976722947'},
|
||||
{ label: '0x3001800400000fc1', bin:'0011000000000001100000000000010000000000000000000001000000000000', other: '3459186743465480000'},
|
||||
{ label: '0x2003', bin:'0000000000000000000000000000000000000000000000000010000000000011', other: '8195'}])
|
||||
[{ label: '0x0001000000003003', bin:'0000000000000001000000000000000000000000000000000011000000000011', other: '281474976722947'},
|
||||
{ sign:'^', label: '0x3001800400000fc1', bin:'0011000000000001100000000000010000000000000000000001000000000000', other: '3459186743465480000'},
|
||||
{ sign:'=', label: '0x2003', bin:'0000000000000000000000000000000000000000000000000010000000000011', other: '8195'}])
|
||||
});
|
||||
|
||||
it('should do prefer hex result', function() {
|
||||
|
||||
return assertOperation('1|0x2',
|
||||
[{ label: '1', bin:'00000001', other: '0x1'},
|
||||
{ label: '0x2', bin:'00000010', other: '2'},
|
||||
{ label: '0x3', bin:'00000011', other: '3'}])
|
||||
{ sign: '|', label: '0x2', bin:'00000010', other: '2'},
|
||||
{ sign: '=', label: '0x3', bin:'00000011', other: '3'}])
|
||||
});
|
||||
|
||||
|
||||
it('should create hashlink', function() {
|
||||
var expression = '1|0x2';
|
||||
var expected = [{ label: '1', bin:'00000001', other: '0x1'},
|
||||
{ label: '0x2', bin:'00000010', other: '2'},
|
||||
{ label: '0x3', bin:'00000011', other: '3'}];
|
||||
{ sign: '|', label: '0x2', bin:'00000010', other: '2'},
|
||||
{ sign: '=', label: '0x3', bin:'00000011', other: '3'}];
|
||||
|
||||
return assertOperation('1|0x2', expected).then(function(){
|
||||
return assertOperation(expression, expected).then(function(){
|
||||
return driver.findElement(By.css('.hashLink'));
|
||||
}).then(function(el) {
|
||||
return el.getAttribute('href');
|
||||
@@ -162,6 +176,7 @@ describe('launch of application', function() {
|
||||
});
|
||||
|
||||
function sendCommand(cmd) {
|
||||
console.log('\r\nSend command: ' + cmd + "\r\n");
|
||||
return driver.findElement(By.id('in')).then(function (el) {
|
||||
return el.sendKeys(cmd + Key.ENTER);
|
||||
});
|
||||
@@ -198,16 +213,15 @@ function assertExpressionResult(contaier, array) {
|
||||
var all= null, cur;
|
||||
for(var i=0; i<rows.length;i++) {
|
||||
var expected = array[i];
|
||||
cur = assertSingleRowResult(rows[i], expected.label, expected.bin, expected.other);
|
||||
cur = assertSingleRowResult(rows[i], expected.label, expected.bin, expected.other, expected.sign);
|
||||
all = all == null ? cur : all.then(cur);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function assertSingleRowResult(row, label, bin, other) {
|
||||
|
||||
return row.findElement(by.css('.label')).then(function (tbLabel) {
|
||||
function assertSingleRowResult(row, label, bin, other, sign) {
|
||||
var p = row.findElement(by.css('.label')).then(function (tbLabel) {
|
||||
expect(tbLabel.getText()).toBe(label);
|
||||
}).then(function () {
|
||||
return row.findElement(by.css('.bin'));
|
||||
@@ -218,7 +232,17 @@ function assertSingleRowResult(row, label, bin, other) {
|
||||
}).then(function (tdOther) {
|
||||
expect(tdOther.getText()).toBe(other);
|
||||
});
|
||||
}
|
||||
|
||||
if(sign != null) {
|
||||
p = p.then(function () {
|
||||
return row.findElement(by.css('.sign'));
|
||||
}).then(function (tdSign) {
|
||||
expect(tdSign.getText()).toBe(sign);
|
||||
});
|
||||
}
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
function assertOperation(op, expected) {
|
||||
return goToApp().then(function() {
|
||||
@@ -245,7 +269,5 @@ function goToApp(hashValue) {
|
||||
url += "||" + hash;
|
||||
}
|
||||
|
||||
console.log('---------- accessing url: ' + url);
|
||||
|
||||
return driver.get(url);
|
||||
}
|
||||
Reference in New Issue
Block a user