mirror of
https://github.com/BorysLevytskyi/BitwiseCmd.git
synced 2025-12-23 21:22:48 +01:00
Initial support of multi-operand expressions
This commit is contained in:
@@ -146,6 +146,18 @@
|
|||||||
</table>
|
</table>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script data-template="bitwiseExpressionView" data-compiled="" type="text/template">
|
||||||
|
<table class="expression">
|
||||||
|
{each itm in m.items}
|
||||||
|
<tr class="{itm.css}">
|
||||||
|
<td class="label">{itm.label}</td>
|
||||||
|
<td class="bin">{itm.bin.padLeft(m.maxNumberOfBits, '0')}</td>
|
||||||
|
<td class="other">{itm.other}</td>
|
||||||
|
</tr>
|
||||||
|
{/}
|
||||||
|
</table>
|
||||||
|
</script>
|
||||||
|
|
||||||
<script data-template="notExpressionView" data-compiled="" type="text/template">
|
<script data-template="notExpressionView" data-compiled="" type="text/template">
|
||||||
<table class="expression">
|
<table class="expression">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -4,28 +4,25 @@ app.set('expression', function() {
|
|||||||
var expression = {
|
var expression = {
|
||||||
factories:[],
|
factories:[],
|
||||||
canParse: function(string) {
|
canParse: function(string) {
|
||||||
|
var trimmed = string.replace(/^\s+|\s+$/, '');
|
||||||
var i = this.factories.length-1;
|
var i = this.factories.length-1;
|
||||||
for(;i>=0;i--) {
|
for(;i>=0;i--) {
|
||||||
if(this.factories[i].regex.test(string)){
|
if(this.factories[i].canCreate(trimmed) === true){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
parse: function(string) {
|
parse: function(string) {
|
||||||
|
|
||||||
var trimmed = string.replace(/^\s+|\s+$/, '');
|
var trimmed = string.replace(/^\s+|\s+$/, '');
|
||||||
var i = 0, l = this.factories.length, factory, matches;
|
var i = 0, l = this.factories.length, factory, matches;
|
||||||
|
|
||||||
for(;i<l;i++) {
|
for(;i<l;i++) {
|
||||||
factory = this.factories[i];
|
factory = this.factories[i];
|
||||||
matches = factory.regex.exec(trimmed);
|
|
||||||
|
|
||||||
if(matches == null){
|
if(factory.canCreate(trimmed) == true){
|
||||||
continue;
|
return factory.create(trimmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return factory.create(matches);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -34,26 +31,26 @@ app.set('expression', function() {
|
|||||||
return new Operand(input);
|
return new Operand(input);
|
||||||
},
|
},
|
||||||
createOperand: function(number, kind) {
|
createOperand: function(number, kind) {
|
||||||
var str = number.toString(getBase(kind));
|
return Operand.create(number, kind);
|
||||||
if(kind == 'hex') {
|
|
||||||
str = toHex(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Operand(str);
|
|
||||||
},
|
},
|
||||||
addFactory: function(factory) {
|
addFactory: function(factory) {
|
||||||
this.factories.push(factory);
|
this.factories.push(factory);
|
||||||
},
|
},
|
||||||
TwoOperandExpression: TwoOperandExpression,
|
TwoOperandExpression: TwoOperandExpression,
|
||||||
SingleOperandExpression: SingleOperandExpression,
|
SingleOperandExpression: SingleOperandExpression,
|
||||||
ListOfNumbersExpression: ListOfNumbersExpression
|
ListOfNumbersExpression: ListOfNumbersExpression,
|
||||||
|
MultipleOperandsExpression: MultipleOperandsExpression
|
||||||
};
|
};
|
||||||
|
|
||||||
// List of numbers
|
// List of numbers
|
||||||
expression.addFactory({
|
expression.addFactory({
|
||||||
regex: /^(-?(?:\d+|0x[\d,a-f]+)\s?)+$/,
|
regex: /^(-?(?:\d+|0x[\d,a-f]+)\s?)+$/,
|
||||||
create: function (matches) {
|
canCreate: function(string) {
|
||||||
var numbers = [],
|
return this.regex.test(string);
|
||||||
|
},
|
||||||
|
create: function (string) {
|
||||||
|
var matches = this.regex.exec(string),
|
||||||
|
numbers = [],
|
||||||
input = matches.input;
|
input = matches.input;
|
||||||
|
|
||||||
input.split(' ').forEach(function(n){
|
input.split(' ').forEach(function(n){
|
||||||
@@ -69,8 +66,13 @@ app.set('expression', function() {
|
|||||||
// Not Expression
|
// Not Expression
|
||||||
expression.addFactory({
|
expression.addFactory({
|
||||||
regex: /^(~)(-?(?:\d+|0x[\d,a-f]+))$/,
|
regex: /^(~)(-?(?:\d+|0x[\d,a-f]+))$/,
|
||||||
create: function (matches) {
|
canCreate: function(string) {
|
||||||
var operand = new Operand(matches[2])
|
return this.regex.test(string);
|
||||||
|
},
|
||||||
|
create: function (string) {
|
||||||
|
var matches = this.regex.exec(string),
|
||||||
|
operand = new Operand(matches[2]);
|
||||||
|
|
||||||
return new SingleOperandExpression(matches.input, operand, matches[1]);
|
return new SingleOperandExpression(matches.input, operand, matches[1]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -78,9 +80,12 @@ app.set('expression', function() {
|
|||||||
// Two operands expression
|
// Two operands expression
|
||||||
expression.addFactory({
|
expression.addFactory({
|
||||||
regex: /^(-?(?:\d+|0x[\d,a-f]+))\s*(<<|>>|>>>|\||\&|\^)\s*(-?(?:\d+|0x[\d,a-f]+))$/,
|
regex: /^(-?(?:\d+|0x[\d,a-f]+))\s*(<<|>>|>>>|\||\&|\^)\s*(-?(?:\d+|0x[\d,a-f]+))$/,
|
||||||
create: function (matches) {
|
canCreate: function(string) {
|
||||||
|
return this.regex.test(string);
|
||||||
var operand1 = new Operand(matches[1]),
|
},
|
||||||
|
create: function (string) {
|
||||||
|
var matches = this.regex.exec(string),
|
||||||
|
operand1 = new Operand(matches[1]),
|
||||||
operand2 = new Operand(matches[3]),
|
operand2 = new Operand(matches[3]),
|
||||||
sign = matches[2],
|
sign = matches[2],
|
||||||
expressionString = matches.input;
|
expressionString = matches.input;
|
||||||
@@ -89,22 +94,49 @@ app.set('expression', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function getBase(kind) {
|
// Multiple operands expression
|
||||||
switch (kind){
|
expression.addFactory({
|
||||||
case 'bin': return 2;
|
fullRegex: /^((?:\s*)(<<|>>|>>>|\||\&|\^)?(?:\s*)(-?(?:\d+|0x[\d,a-f]+)))+$/,
|
||||||
case 'hex': return 16;
|
regex: /(?:\s*)(<<|>>|>>>|\||\&|\^)?(?:\s*)(-?(?:\d+|0x[\d,a-f]+))/g,
|
||||||
case 'dec': return 10;
|
canCreate: function(string) {
|
||||||
}
|
this.fullRegex.lastIndex = 0;
|
||||||
|
return this.fullRegex.test(string);
|
||||||
|
},
|
||||||
|
create: function (string) {
|
||||||
|
var m = null, operands = [];
|
||||||
|
|
||||||
|
while ((m = this.regex.exec(string)) != null) {
|
||||||
|
operands.push(this.parseMatch(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
function toHex(hex) {
|
//matches.input.replace(this.regex, function(inpt, sign, num) {
|
||||||
return hex.indexOf('-') == 0 ? '-0x' + hex.substr(1) : '0x' + hex;
|
// if(sign == null) {
|
||||||
|
// operands.push(new Operand(num));
|
||||||
|
// } else {
|
||||||
|
// operands.push(new SingleOperandExpression(inpt, new Operand(num), sign))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//});
|
||||||
|
|
||||||
|
return new MultipleOperandsExpression(string, operands)
|
||||||
|
},
|
||||||
|
parseMatch: function (m) {
|
||||||
|
var input = m[0],
|
||||||
|
sign = m[1],
|
||||||
|
num = m[2];
|
||||||
|
|
||||||
|
if(sign == null) {
|
||||||
|
return new Operand(num);
|
||||||
|
} else {
|
||||||
|
return new SingleOperandExpression(input, new Operand(num), sign);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function Operand(input) {
|
function Operand(input) {
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.value = parseInt(input);
|
this.value = parseInt(input);
|
||||||
this.hex = toHex(this.value.toString(16));
|
this.hex = Operand.toHexString(this.value.toString(16));
|
||||||
this.dec = this.value.toString(10);
|
this.dec = this.value.toString(10);
|
||||||
// >>> 0 makes negative numbers like -1 to be displayed as '11111111111111111111111111111111' in binary instead of -1
|
// >>> 0 makes negative numbers like -1 to be displayed as '11111111111111111111111111111111' in binary instead of -1
|
||||||
this.bin = this.value < 0 ? (this.value >>> 0).toString(2) : this.value.toString(2);
|
this.bin = this.value < 0 ? (this.value >>> 0).toString(2) : this.value.toString(2);
|
||||||
@@ -112,12 +144,51 @@ app.set('expression', function() {
|
|||||||
this.other = this.kind == 'dec' ? this.hex : this.dec;
|
this.other = this.kind == 'dec' ? this.hex : this.dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Operand.toHexString = function (hex) {
|
||||||
|
return hex.indexOf('-') == 0 ? '-0x' + hex.substr(1) : '0x' + hex;
|
||||||
|
};
|
||||||
|
|
||||||
|
Operand.create = function(number, kind) {
|
||||||
|
var str = number.toString(Operand.getBase(kind));
|
||||||
|
if(kind == 'hex') {
|
||||||
|
str = Operand.toHexString(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Operand(str);
|
||||||
|
};
|
||||||
|
|
||||||
|
Operand.prototype.getLengthInBits = function() {
|
||||||
|
if(this.value < 0) {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
return Math.floor(Math.log(this.value) / Math.log(2)) + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
Operand.getBase = function(kind){
|
||||||
|
switch (kind){
|
||||||
|
case 'bin': return 2;
|
||||||
|
case 'hex': return 16;
|
||||||
|
case 'dec': return 10;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function SingleOperandExpression(expressionString, operand, sign) {
|
function SingleOperandExpression(expressionString, operand, sign) {
|
||||||
this.expressionString = expressionString;
|
this.expressionString = expressionString;
|
||||||
this.operand1 = operand;
|
this.operand1 = operand;
|
||||||
this.sign = sign;
|
this.sign = sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SingleOperandExpression.prototype.apply = function (value) {
|
||||||
|
var str = '';
|
||||||
|
if(this.sign == '~'){
|
||||||
|
str = '~' + this.operand1.value;
|
||||||
|
} else {
|
||||||
|
str = value + this.sign + this.operand1.value
|
||||||
|
}
|
||||||
|
|
||||||
|
return Operand.create(eval(str), this.operand1.kind);
|
||||||
|
};
|
||||||
|
|
||||||
function TwoOperandExpression(expressionString, operand1, operand2, sign) {
|
function TwoOperandExpression(expressionString, operand1, operand2, sign) {
|
||||||
this.expressionString = expressionString;
|
this.expressionString = expressionString;
|
||||||
this.operand1 = operand1;
|
this.operand1 = operand1;
|
||||||
@@ -125,6 +196,11 @@ app.set('expression', function() {
|
|||||||
this.sign = sign;
|
this.sign = sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function MultipleOperandsExpression(expressionString, expressions) {
|
||||||
|
this.expressionString = expressionString;
|
||||||
|
this.expressions = expressions;
|
||||||
|
}
|
||||||
|
|
||||||
function ListOfNumbersExpression(expressionString, numbers) {
|
function ListOfNumbersExpression(expressionString, numbers) {
|
||||||
this.expressionString = expressionString;
|
this.expressionString = expressionString;
|
||||||
this.numbers = numbers;
|
this.numbers = numbers;
|
||||||
@@ -141,5 +217,13 @@ app.set('expression', function() {
|
|||||||
//SingleOperandExpression.prototype = Expression.prototype;
|
//SingleOperandExpression.prototype = Expression.prototype;
|
||||||
//ListOfNumbersExpression.prototype = Expression.prototype;
|
//ListOfNumbersExpression.prototype = Expression.prototype;
|
||||||
|
|
||||||
|
Operand.prototype.toString = function () {
|
||||||
|
return this.input;
|
||||||
|
};
|
||||||
|
|
||||||
|
SingleOperandExpression.prototype.toString = function() {
|
||||||
|
return this.sign + this.operand1.toString();
|
||||||
|
};
|
||||||
|
|
||||||
return expression;
|
return expression;
|
||||||
});
|
});
|
||||||
@@ -6,11 +6,7 @@ app.set("formatter", function() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
formatString: function(num, kind) {
|
formatString: function(num, kind) {
|
||||||
kind = kind || "bin";
|
return num.toString(getBase(kind || "bin"));
|
||||||
|
|
||||||
var convertedString = num.toString(getBase(kind));
|
|
||||||
return convertedString;
|
|
||||||
|
|
||||||
},
|
},
|
||||||
padLeft: function (str, length, symbol) {
|
padLeft: function (str, length, symbol) {
|
||||||
var sb = Array.prototype.slice.call(str), symbol = symbol || "0";
|
var sb = Array.prototype.slice.call(str), symbol = symbol || "0";
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ app.run(function() {
|
|||||||
return new app.models.BitwiseNumbers(expr);
|
return new app.models.BitwiseNumbers(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(expr instanceof expression.MultipleOperandsExpression) {
|
||||||
|
return new app.models.BitwiseExpression(expr);
|
||||||
|
}
|
||||||
|
|
||||||
return new app.models.ErrorResult('Cannot create model for expression: ' + expr.toString());
|
return new app.models.ErrorResult('Cannot create model for expression: ' + expr.toString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ app.compose(function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.modelView(app.models.BitwiseExpression, {
|
||||||
|
renderView: function(model) {
|
||||||
|
var template = app.template('bitwiseExpressionView');
|
||||||
|
return colorizeBits(template.render(model));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.modelView(app.models.BitwiseNumbers, {
|
app.modelView(app.models.BitwiseNumbers, {
|
||||||
renderView: function(model) {
|
renderView: function(model) {
|
||||||
model.bitsSize = getBinaryLength(model.numbers);
|
model.bitsSize = getBinaryLength(model.numbers);
|
||||||
@@ -88,6 +95,9 @@ app.compose(function () {
|
|||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function colorizeBits(container) {
|
function colorizeBits(container) {
|
||||||
var list = container.querySelectorAll('.bin');
|
var list = container.querySelectorAll('.bin');
|
||||||
Array.prototype.forEach.call(list, function(el){
|
Array.prototype.forEach.call(list, function(el){
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
(function(app) {
|
(function(app) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
|
||||||
function BitwiseOperation (expression) {
|
function BitwiseOperation (expression) {
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
this.operand1 = expression.operand1;
|
this.operand1 = expression.operand1;
|
||||||
@@ -20,6 +21,54 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function BitwiseExpression(expression) {
|
||||||
|
this.items = [];
|
||||||
|
this.maxNumberOfBits = 0;
|
||||||
|
|
||||||
|
var op = expression.expressions[0],
|
||||||
|
i = 1, l = expression.expressions.length,
|
||||||
|
ex;
|
||||||
|
|
||||||
|
this.addOperand(op);
|
||||||
|
|
||||||
|
for (;i<l;i++) {
|
||||||
|
ex = expression.expressions[i];
|
||||||
|
this.addExpression(ex);
|
||||||
|
op = ex.apply(op.value);
|
||||||
|
this.addResult(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maxNumberOfBits = this.emphasizeBytes(this.maxNumberOfBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
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: ''});
|
||||||
|
};
|
||||||
|
|
||||||
|
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: ''});
|
||||||
|
};
|
||||||
|
|
||||||
|
BitwiseExpression.prototype.addResult = 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'});
|
||||||
|
};
|
||||||
|
|
||||||
|
BitwiseExpression.prototype.emphasizeBytes = function (bits) {
|
||||||
|
var cmdConfig = app.get('cmdConfig');
|
||||||
|
if(cmdConfig.emphasizeBytes && bits % 8 != 0) {
|
||||||
|
if(bits < 8) {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
var n = bits - (bits % 8);
|
||||||
|
return n + 8;
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
};
|
||||||
|
|
||||||
function ErrorResult(message) {
|
function ErrorResult(message) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
@@ -39,5 +88,6 @@
|
|||||||
app.models.ErrorResult = ErrorResult;
|
app.models.ErrorResult = ErrorResult;
|
||||||
app.models.ViewResult = ViewResult;
|
app.models.ViewResult = ViewResult;
|
||||||
app.models.DisplayResult = DisplayResult;
|
app.models.DisplayResult = DisplayResult;
|
||||||
|
app.models.BitwiseExpression = BitwiseExpression;
|
||||||
|
|
||||||
})(window.app);
|
})(window.app);
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ describe("expression parse", function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it ("should parse multiple operands expression", function () {
|
||||||
|
var actual = expression.parse("1|2&3");
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('parse operands', function() {
|
describe('parse operands', function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user