mirror of
https://github.com/BorysLevytskyi/BitwiseCmd.git
synced 2026-01-16 00:42:46 +01:00
new features wip
This commit is contained in:
@@ -6,6 +6,10 @@ import BitwiseExpressionViewModel from './models/BitwiseExpressionViewModel';
|
||||
import log from 'loglevel';
|
||||
|
||||
export default class BitwiseOperationEpxressionView extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {};
|
||||
}
|
||||
render() {
|
||||
var rows = this.getRows();
|
||||
if(!rows) {
|
||||
@@ -26,19 +30,31 @@ export default class BitwiseOperationEpxressionView extends React.Component {
|
||||
if(expr instanceof ListOfNumbersExpression) {
|
||||
model = BitwiseExpressionViewModel.buildListOfNumbers(expr, {
|
||||
emphasizeBytes: this.props.emphasizeBytes,
|
||||
allowFlipBits: true });
|
||||
}
|
||||
|
||||
if(expr instanceof SingleOperandExpression) {
|
||||
model = BitwiseExpressionViewModel.buildNot(expr, { emphasizeBytes: this.props.emphasizeBytes });
|
||||
allowFlipBits: true
|
||||
});
|
||||
}
|
||||
|
||||
if(expr instanceof MultipleOperandsExpression) {
|
||||
model = BitwiseExpressionViewModel.buildMultiple(expr, { emphasizeBytes: this.props.emphasizeBytes });
|
||||
model = BitwiseExpressionViewModel.buildMultiple(expr, {
|
||||
emphasizeBytes: this.props.emphasizeBytes,
|
||||
allowFlipBits: false
|
||||
});
|
||||
}
|
||||
|
||||
log.info('Render model', model);
|
||||
return model.items.map((itm, i) => <ExpressionRow key={i} {...itm} emphasizeBytes={this.props.emphasizeBytes} maxNumberOfBits={model.maxNumberOfBits} allowFlipBits={model.allowFlipBits} />);
|
||||
|
||||
return model.items.map((itm, i) =>
|
||||
<ExpressionRow
|
||||
key={i}
|
||||
{...itm}
|
||||
emphasizeBytes={this.props.emphasizeBytes}
|
||||
maxNumberOfBits={model.maxNumberOfBits}
|
||||
onBitFlipped={() => this.onBitFlipped()} />);
|
||||
}
|
||||
|
||||
onBitFlipped() {
|
||||
console.log('bit flipped');
|
||||
this.setState({d:new Date()});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +72,7 @@ class ExpressionRow extends React.Component {
|
||||
<td className="bin">
|
||||
<BinaryStringView
|
||||
emphasizeBytes={emphasizeBytes}
|
||||
binaryString={formatter.padLeft(operand.toBinaryString(), maxNumberOfBits, '0')}
|
||||
binaryString={formatter.padLeft(operand.apply().toBinaryString(), maxNumberOfBits, '0')}
|
||||
allowFlipBits={allowFlipBits}
|
||||
onFlipBit={idx => this.flipBit(idx)}/>
|
||||
</td>
|
||||
@@ -65,10 +81,16 @@ class ExpressionRow extends React.Component {
|
||||
}
|
||||
|
||||
getLabel(op) {
|
||||
if(op.isExpression) {
|
||||
return op.toString();
|
||||
}
|
||||
return op.toString(op.kind == 'bin' ? 'dec' : op.kind);
|
||||
}
|
||||
|
||||
getOther(op) {
|
||||
if(op.isExpression) {
|
||||
return op.apply().toString();
|
||||
}
|
||||
return op.toString(op.getOtherKind());
|
||||
}
|
||||
|
||||
@@ -76,13 +98,15 @@ class ExpressionRow extends React.Component {
|
||||
|
||||
const op = this.props.operand;
|
||||
const { index, binaryString } = args;
|
||||
|
||||
|
||||
var arr = binaryString.split('');
|
||||
arr[index] = arr[index] == '0' ? '1' : '0';
|
||||
var bin = arr.join('');
|
||||
|
||||
op.setValue(parseInt(bin, 2));
|
||||
var newValue = parseInt(bin, 2);
|
||||
console.log('flipped \n%s to \n%s from \n%s to \n%s', binaryString, bin, op.value, newValue);
|
||||
op.setValue(newValue);
|
||||
|
||||
this.setState({ operand: op });
|
||||
this.props.onBitFlipped();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Operand, SingleOperandExpression } from '../../../expression';
|
||||
|
||||
export default class BitwiseExpressionViewModel {
|
||||
|
||||
constructor({ emphasizeBytes = false, allowFlipBits = false } = {}) {
|
||||
@@ -15,22 +17,36 @@ export default class BitwiseExpressionViewModel {
|
||||
}
|
||||
|
||||
static buildMultiple (expr, config) {
|
||||
|
||||
console.log('build: ', expr);
|
||||
var op = expr.expressions[0],
|
||||
i = 1, l = expr.expressions.length,
|
||||
i = 0, l = expr.expressions.length,
|
||||
ex, m = new BitwiseExpressionViewModel(config);
|
||||
|
||||
m.addOperand(op);
|
||||
|
||||
var cur = null;
|
||||
for (;i<l;i++) {
|
||||
ex = expr.expressions[i];
|
||||
op = ex.apply(op.value);
|
||||
var ex = expr.expressions[i];
|
||||
if(ex instanceof Operand) {
|
||||
m.addOperand(ex);
|
||||
cur = ex;
|
||||
console.log('cur is ', cur)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ex.isShiftExpression()){
|
||||
m.addShiftExpressionResult(ex, op);
|
||||
} else {
|
||||
if(ex.isNotExpression) {
|
||||
m.addExpression(ex);
|
||||
m.addExpressionResult(op);
|
||||
var notResult = ex.apply();
|
||||
m.addExpressionResult(notResult);
|
||||
cur = notResult;
|
||||
}
|
||||
else if(ex.isShiftExpression){
|
||||
console.log('cur is ', cur)
|
||||
cur = ex.apply(cur);
|
||||
m.addShiftExpressionResult(ex, cur);
|
||||
} else {
|
||||
|
||||
cur = ex.apply(cur);
|
||||
m.addExpression(ex);
|
||||
m.addExpressionResult(cur);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,16 +68,19 @@ export default class BitwiseExpressionViewModel {
|
||||
this.items.push({
|
||||
sign:'',
|
||||
css: '',
|
||||
operand: operand
|
||||
operand: operand,
|
||||
allowFlipBits: this.allowFlipBits
|
||||
});
|
||||
};
|
||||
|
||||
addExpression(expression) {
|
||||
this.maxNumberOfBits = Math.max(expression.operand1.getLengthInBits(), this.maxNumberOfBits);
|
||||
this.maxNumberOfBits = Math.max(expression.operand1.apply().getLengthInBits(), this.maxNumberOfBits);
|
||||
|
||||
this.items.push({
|
||||
sign: expression.sign,
|
||||
label: this.getLabel(expression.operand1),
|
||||
operand: expression.operand1
|
||||
operand: expression.operand1,
|
||||
allowFlipBits: this.allowFlipBits
|
||||
});
|
||||
};
|
||||
|
||||
@@ -70,7 +89,8 @@ export default class BitwiseExpressionViewModel {
|
||||
this.items.push({
|
||||
sign: expression.sign + expression.operand1.toString(),
|
||||
css: 'expression-result',
|
||||
operand: resultOperand
|
||||
operand: resultOperand,
|
||||
allowFlipBits: false
|
||||
});
|
||||
};
|
||||
|
||||
@@ -79,7 +99,8 @@ export default class BitwiseExpressionViewModel {
|
||||
this.items.push({
|
||||
sign:'=',
|
||||
css: 'expression-result',
|
||||
operand: operand
|
||||
operand: operand,
|
||||
allowFlipBits: false
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import Operand from './expression/operand';
|
||||
export { default as Operand } from './expression/operand';
|
||||
import Operand from './expression/Operand';
|
||||
import SingleOperandExpression from './expression/SingleOperandExpression'
|
||||
|
||||
export { default as Operand } from './expression/Operand';
|
||||
export { default as ExpressionError } from './expression/ExpressionError';
|
||||
export { default as SingleOperandExpression } from './expression/SingleOperandExpression';
|
||||
|
||||
var expression = {
|
||||
factories:[],
|
||||
@@ -60,24 +63,10 @@ var expression = {
|
||||
}
|
||||
});
|
||||
|
||||
// Not Expression
|
||||
expression.addFactory({
|
||||
regex: /^(~)(-?[b,x,a-f,0-9]+)$/,
|
||||
canCreate: function(string) {
|
||||
return this.regex.test(string);
|
||||
},
|
||||
create: function (string) {
|
||||
var matches = this.regex.exec(string),
|
||||
operand = Operand.parse(matches[2]);
|
||||
|
||||
return new SingleOperandExpression(matches.input, operand, matches[1]);
|
||||
}
|
||||
});
|
||||
|
||||
// Multiple operands expression
|
||||
expression.addFactory({
|
||||
fullRegex: /^((<<|>>|>>>|\||\&|\^)?(-?([b,x,a-f,0-9]+)))+$/,
|
||||
regex: /(<<|>>|>>>|\||\&|\^)?(-?([b,x,a-f,0-9]+))/g,
|
||||
fullRegex: /^((<<|>>|>>>|\||\&|\^)?(~?-?([b,x,a-f,0-9]+)))+$/,
|
||||
regex: /(<<|>>|>>>|\||\&|\^)?(~?-?(?:[b,x,a-f,0-9]+))/g,
|
||||
canCreate: function(string) {
|
||||
this.fullRegex.lastIndex = 0;
|
||||
return this.fullRegex.test(this.normalizeString(string));
|
||||
@@ -93,11 +82,20 @@ var expression = {
|
||||
return new MultipleOperandsExpression(normalizedString, operands)
|
||||
},
|
||||
parseMatch: function (m) {
|
||||
console.log('match');
|
||||
console.log(m);
|
||||
var input = m[0],
|
||||
sign = m[1],
|
||||
num = m[2];
|
||||
|
||||
var op = Operand.parse(num);
|
||||
var op = null;
|
||||
if(num.indexOf('~') == '0') {
|
||||
op = new SingleOperandExpression(input, Operand.parse(num.substring(1)), '~');
|
||||
}
|
||||
else {
|
||||
op = Operand.parse(num);
|
||||
}
|
||||
|
||||
if(sign == null) {
|
||||
return op;
|
||||
} else {
|
||||
@@ -110,45 +108,9 @@ var expression = {
|
||||
});
|
||||
|
||||
// Expressions like ~1
|
||||
export class SingleOperandExpression {
|
||||
constructor(expressionString, operand, sign) {
|
||||
this.expressionString = expressionString;
|
||||
this.operand1 = operand;
|
||||
this.sign = sign;
|
||||
}
|
||||
|
||||
apply(value) {
|
||||
var str = '';
|
||||
if(this.sign == '~'){
|
||||
str = '~' + this.operand1.value;
|
||||
} else {
|
||||
str = value + this.sign + this.operand1.value
|
||||
}
|
||||
|
||||
console.log('eval:' + str + " = " + eval(str), Operand.create(eval(str), this.operand1.kind));
|
||||
|
||||
const resultValue = eval(str);
|
||||
return Operand.create(resultValue, this.operand1.kind);
|
||||
};
|
||||
|
||||
isShiftExpression() {
|
||||
return this.sign.indexOf('<') >= 0 || this.sign.indexOf('>')>= 0;
|
||||
};
|
||||
|
||||
toString() {
|
||||
return this.sign + this.operand1.toString();
|
||||
}
|
||||
}
|
||||
|
||||
// Expression like 1|2 or 4^5
|
||||
export class TwoOperandExpression {
|
||||
constructor(expressionString, operand1, operand2, sign) {
|
||||
this.expressionString = expressionString;
|
||||
this.operand1 = operand1;
|
||||
this.operand2 = operand2;
|
||||
this.sign = sign;
|
||||
}
|
||||
}
|
||||
|
||||
export class MultipleOperandsExpression {
|
||||
constructor(expressionString, expressions) {
|
||||
@@ -168,12 +130,6 @@ export class ListOfNumbersExpression {
|
||||
return this.numbers.map(n => n.value.toString()).join(' ');
|
||||
}
|
||||
}
|
||||
|
||||
export class Expression {
|
||||
toString() {
|
||||
return this.expressionString ? "Expression: " + this.expressionString : this.toString();
|
||||
};
|
||||
}
|
||||
|
||||
export var parser = expression;
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import numberParser from './numberParser';
|
||||
import ExpressionError from './ExpressionError';
|
||||
|
||||
var id = 1;
|
||||
|
||||
// Represents numeric value
|
||||
export default class Operand {
|
||||
constructor(cfg) {
|
||||
this.id = id++;
|
||||
this.value = cfg.value;
|
||||
this.kind = cfg.kind;
|
||||
this.lengthInBits = Operand.getBitLength(this.value);
|
||||
this.isExpression = false;
|
||||
}
|
||||
|
||||
getLengthInBits() {
|
||||
@@ -47,11 +51,16 @@ export default class Operand {
|
||||
}
|
||||
|
||||
setValue(value) {
|
||||
console.log('Operand:%s.setValue: %s', this.id, this.value);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
apply() {
|
||||
return this;
|
||||
}
|
||||
|
||||
static getBitLength(num) {
|
||||
return Math.floor(Math.log(num) / Math.log(2)) + 1
|
||||
return Math.floor(Math.log(num) / Math.log(2)) + 1;
|
||||
}
|
||||
|
||||
static getBase(kind){
|
||||
|
||||
40
src/app/expression/SingleOperandExpression.js
Normal file
40
src/app/expression/SingleOperandExpression.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import Operand from './Operand';
|
||||
|
||||
export default class SingleOperandExpression {
|
||||
constructor(expressionString, operand, sign) {
|
||||
this.expressionString = expressionString;
|
||||
this.operand1 = operand;
|
||||
this.sign = sign;
|
||||
this.isExpression = true;
|
||||
this.isShiftExpression = this.sign.indexOf('<') >= 0 || this.sign.indexOf('>')>= 0;
|
||||
this.isNotExpression = this.sign == '~';
|
||||
}
|
||||
|
||||
apply(operand) {
|
||||
if (operand instanceof SingleOperandExpression) {
|
||||
console.error("value shouldnt be expression", value);
|
||||
throw new Error('value shouldnt be expression');
|
||||
}
|
||||
|
||||
console.log('operand', operand);
|
||||
|
||||
var str = '';
|
||||
if(this.sign == '~'){
|
||||
str = '~' + this.operand1.apply().value;
|
||||
} else {
|
||||
str = operand.value + this.sign + this.operand1.apply().value;
|
||||
}
|
||||
|
||||
console.log('eval:' + str, this);
|
||||
const resultValue = eval(str);
|
||||
|
||||
var resultOp = Operand.create(eval(str), this.operand1.kind || this.operand1.operand1.kind);
|
||||
console.log(resultValue, resultOp);
|
||||
|
||||
return resultOp;
|
||||
};
|
||||
|
||||
toString() {
|
||||
return this.sign + this.operand1.toString();
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ ExpressionResultObject.prototype.shouldBe = function(expectedResult) {
|
||||
for(var i=0;i<expectedResult.length; i++) {
|
||||
var actual = actualResult[i],
|
||||
expected = convertToExpected(expectedResult[i]);
|
||||
|
||||
//console.log("actual.bin.length=" + actual.bin.length)
|
||||
expect(actual).toEqual(jasmine.objectContaining(expected));
|
||||
}
|
||||
});
|
||||
@@ -109,7 +109,7 @@ function convertExpectedFromArray(arg) {
|
||||
other: arg[start++]
|
||||
}
|
||||
|
||||
console.log('convert: ' + JSON.stringify(arg) + " to " + JSON.stringify(obj));
|
||||
// console.log('convert: ' + JSON.stringify(arg) + " to " + JSON.stringify(obj));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -98,19 +98,38 @@ describe('when application starts', function() {
|
||||
});
|
||||
|
||||
it('should do multiple operand expression', function() {
|
||||
|
||||
// actual { sign: '', label: '1', bin: '00000000000000000000000000000001', other: '0x1' }
|
||||
// expected { sign: '', label: '1', bin: '0000000000000000000000000000001', other: '0x1' }
|
||||
return assertOperation(
|
||||
'1|2|4<<0x1',
|
||||
'1|2|4<<0x1|~2',
|
||||
[
|
||||
[ '1', '00000001', '0x1'],
|
||||
[ '|', '2', '00000010', '0x2'],
|
||||
[ '=', '3', '00000011', '0x3'],
|
||||
[ '|', '4', '00000100', '0x4'],
|
||||
[ '=', '7', '00000111', '0x7'],
|
||||
[ '<<0x1','0xe','00001110', '14' ],
|
||||
[ '1', '00000000000000000000000000000001', '0x1'],
|
||||
[ '|', '2', '00000000000000000000000000000010', '0x2'],
|
||||
[ '=', '3', '00000000000000000000000000000011', '0x3'],
|
||||
[ '|', '4', '00000000000000000000000000000100', '0x4'],
|
||||
[ '=', '7', '00000000000000000000000000000111', '0x7'],
|
||||
[ '<<0x1','0xe', '00000000000000000000000000001110', '14' ],
|
||||
[ '|', '~2', '11111111111111111111111111111101', '-3'],
|
||||
[ '=', '-1', '11111111111111111111111111111111', '-0x1']
|
||||
]);
|
||||
});
|
||||
|
||||
it('should support nested not operations', function() {
|
||||
return assertOperation(
|
||||
'~3|~213&~12^~223',
|
||||
[
|
||||
['~', '3', '00000000000000000000000000000011', '0x3'],
|
||||
['=', '-4', '11111111111111111111111111111100', '-0x4'],
|
||||
['|', '~213', '11111111111111111111111100101010', '-214'],
|
||||
['=', '-2', '11111111111111111111111111111110', '-0x2'],
|
||||
['&', '~12', '11111111111111111111111111110011', '-13'],
|
||||
['=', '-14', '11111111111111111111111111110010', '-0xe'],
|
||||
['^', '~223', '11111111111111111111111100100000', '-224'],
|
||||
['=', '210', '00000000000000000000000011010010', '0xd2']
|
||||
]
|
||||
)
|
||||
})
|
||||
|
||||
it('should do or for binary numbers', function() {
|
||||
return assertOperation('0b10|0b11',
|
||||
[[ "2", "00000010", "0x2"],
|
||||
|
||||
Reference in New Issue
Block a user