mirror of
https://github.com/BorysLevytskyi/BitwiseCmd.git
synced 2026-01-24 20:54:10 +01:00
Add support of binary numbers
This commit is contained in:
@@ -66,6 +66,7 @@ var cmd = {
|
||||
}
|
||||
|
||||
function invokeHandler (input, handler) {
|
||||
|
||||
var cmdResult = handler.handle({ input: input});
|
||||
if(cmdResult != null) {
|
||||
console.log(cmdResult);
|
||||
|
||||
@@ -11,14 +11,6 @@ var cmdConfig = {};
|
||||
export default {
|
||||
initialize (cmd, appState) {
|
||||
|
||||
cmd.command({
|
||||
canHandle: (input) => expression.parser.canParse(input),
|
||||
handle: function(c) {
|
||||
var expr = expression.parser.parse(c.input);
|
||||
appState.addCommandResult(new ExpressionResult(c.input, expr));
|
||||
}
|
||||
})
|
||||
|
||||
cmd.commands({
|
||||
'help': function(c) {
|
||||
appState.addCommandResult(new HelpResult(c.input));
|
||||
@@ -44,9 +36,21 @@ export default {
|
||||
'whatsnew': function(c) {
|
||||
appState.addCommandResult(new WahtsnewResult(c.input));
|
||||
},
|
||||
'-notrack': function () {}
|
||||
'-notrack': function () {},
|
||||
'-debug': function() {
|
||||
console.log('Debug mode on')
|
||||
cmd.debugMode = true;
|
||||
}
|
||||
});
|
||||
|
||||
cmd.command({
|
||||
canHandle: (input) => expression.parser.canParse(input),
|
||||
handle: function(c) {
|
||||
var expr = expression.parser.parse(c.input);
|
||||
appState.addCommandResult(new ExpressionResult(c.input, expr));
|
||||
}
|
||||
})
|
||||
|
||||
// Last command handler reports that input is unknown
|
||||
cmd.command({
|
||||
canHandle: () => true,
|
||||
|
||||
@@ -33,7 +33,6 @@ export default class InputBox extends React.Component {
|
||||
|
||||
input.value = '';
|
||||
cmd.execute(value);
|
||||
console.log(this.history);
|
||||
}
|
||||
|
||||
onKeyDown(args) {
|
||||
|
||||
@@ -19,8 +19,6 @@ export default class ExpressionResultView extends React.Component {
|
||||
</div>
|
||||
}
|
||||
|
||||
console.log('[BitwiseOperationExpressionView] render()', expr);
|
||||
|
||||
return <b>Expression: {expr.expressionString}</b>;
|
||||
}
|
||||
}
|
||||
@@ -27,12 +27,16 @@ class OperandView extends React.Component {
|
||||
const binaryString = formatter.padLeft(op.bin, this.props.maxBitsLegnth, '0');
|
||||
|
||||
return <tr data-kind={op.kind}>
|
||||
<td className="label">{op.input}</td>
|
||||
<td className="label">{this.getLabel(op)}</td>
|
||||
<td className="bin"><BinaryStringView emphasizeBytes={this.props.emphasizeBytes} binaryString={binaryString} allowFlipBits={true} onFlipBit={e => this.flipBit(e)} /></td>
|
||||
<td className="other">{op.other}</td>
|
||||
</tr>;
|
||||
};
|
||||
|
||||
getLabel(op) {
|
||||
return op.kind == 'bin' ? op.dec : op.input;
|
||||
}
|
||||
|
||||
flipBit(index) {
|
||||
var op = this.props.operand;
|
||||
const binaryString = formatter.padLeft(op.bin, this.props.maxBitsLegnth, '0');
|
||||
|
||||
@@ -41,19 +41,30 @@ export default class BitwiseExpressionViewModel {
|
||||
|
||||
addOperand(operand) {
|
||||
this.maxNumberOfBits = Math.max(operand.getLengthInBits(), this.maxNumberOfBits);
|
||||
this.items.push({ sign:'', label: operand.toString(), bin: operand.bin, other: operand.other, css: ''});
|
||||
this.items.push({
|
||||
sign:'',
|
||||
label: this.getLabel(operand),
|
||||
bin: operand.bin,
|
||||
other: operand.other,
|
||||
css: ''});
|
||||
};
|
||||
|
||||
addExpression(expression) {
|
||||
this.maxNumberOfBits = Math.max(expression.operand1.getLengthInBits(), this.maxNumberOfBits);
|
||||
this.items.push({ sign: expression.sign, label: expression.operand1.toString(), bin: expression.operand1.bin, other: expression.operand1.other, css: ''});
|
||||
this.items.push({
|
||||
sign: expression.sign,
|
||||
label: this.getLabel(expression.operand1),
|
||||
bin: expression.operand1.bin,
|
||||
other: expression.operand1.other,
|
||||
css: ''
|
||||
});
|
||||
};
|
||||
|
||||
addShiftExpressionResult(expression, resultOperand) {
|
||||
this.maxNumberOfBits = Math.max(resultOperand.getLengthInBits(), this.maxNumberOfBits);
|
||||
this.items.push({
|
||||
sign: expression.sign + expression.operand1.input,
|
||||
label: resultOperand.toString(),
|
||||
label: this.getLabel(resultOperand),
|
||||
bin: resultOperand.bin,
|
||||
other: resultOperand.other,
|
||||
css: 'expression-result'});
|
||||
@@ -61,9 +72,23 @@ export default class BitwiseExpressionViewModel {
|
||||
|
||||
addExpressionResult(operand) {
|
||||
this.maxNumberOfBits = Math.max(operand.getLengthInBits(), this.maxNumberOfBits);
|
||||
this.items.push({ sign:'=', label: operand.toString(), bin: operand.bin, other: operand.other, css: 'expression-result'});
|
||||
this.items.push({
|
||||
sign:'=',
|
||||
label: this.getLabel(operand),
|
||||
bin: operand.bin,
|
||||
other: operand.other,
|
||||
css: 'expression-result'});
|
||||
};
|
||||
|
||||
getLabel (op) {
|
||||
|
||||
if(op.kind == 'bin') {
|
||||
return op.dec;
|
||||
}
|
||||
|
||||
return op.toString();
|
||||
}
|
||||
|
||||
// TODO: move this method elsewhere. It is also used in LisOfNumbersExpressionView.js
|
||||
static getNumberOfBits = function (bits, emphasizeBytes) {
|
||||
if(emphasizeBytes && bits % 8 != 0) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import Operand from './expression/operand';
|
||||
|
||||
var expression = {
|
||||
factories:[],
|
||||
canParse: function(string) {
|
||||
@@ -25,7 +27,7 @@ var expression = {
|
||||
return null;
|
||||
},
|
||||
parseOperand: function(input) {
|
||||
return new Operand(input);
|
||||
return Operand.parse(input);
|
||||
},
|
||||
createOperand: function(number, kind) {
|
||||
return Operand.create(number, kind);
|
||||
@@ -37,7 +39,7 @@ var expression = {
|
||||
|
||||
// List of numbers
|
||||
expression.addFactory({
|
||||
regex: /^(-?(?:\d+|0x[\d,a-f]+)\s?)+$/,
|
||||
regex: /^(-?(?:\d+|0x[\d,a-f]+|0b[0-1])\s?)+$/,
|
||||
canCreate: function(string) {
|
||||
return this.regex.test(string);
|
||||
},
|
||||
@@ -48,7 +50,7 @@ var expression = {
|
||||
|
||||
input.split(' ').forEach(function(n){
|
||||
if(n.trim().length > 0) {
|
||||
numbers.push(new Operand(n.trim()));
|
||||
numbers.push(Operand.parse(n.trim()));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -58,13 +60,13 @@ var expression = {
|
||||
|
||||
// Not Expression
|
||||
expression.addFactory({
|
||||
regex: /^(~)(-?(?:\d+|0x[\d,a-f]+))$/,
|
||||
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 = new Operand(matches[2]);
|
||||
operand = Operand.parse(matches[2]);
|
||||
|
||||
return new SingleOperandExpression(matches.input, operand, matches[1]);
|
||||
}
|
||||
@@ -72,8 +74,8 @@ var expression = {
|
||||
|
||||
// Multiple operands expression
|
||||
expression.addFactory({
|
||||
fullRegex: /^((<<|>>|>>>|\||\&|\^)?(-?((?:\d+(?!x))|(?:0x[\d,a-f]+))))+$/,
|
||||
regex: /(<<|>>|>>>|\||\&|\^)?(-?((?:\d+(?!x))|(?:0x[\d,a-f]+)))/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,10 +95,11 @@ var expression = {
|
||||
sign = m[1],
|
||||
num = m[2];
|
||||
|
||||
var op = Operand.parse(num);
|
||||
if(sign == null) {
|
||||
return new Operand(num);
|
||||
return op;
|
||||
} else {
|
||||
return new SingleOperandExpression(input, new Operand(num), sign);
|
||||
return new SingleOperandExpression(input, op, sign);
|
||||
}
|
||||
},
|
||||
normalizeString: function (string) {
|
||||
@@ -104,91 +107,6 @@ var expression = {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Represents numeric value
|
||||
export class Operand {
|
||||
constructor(input) {
|
||||
this.input = input;
|
||||
this.value = parseInt(input);
|
||||
this.hex = Operand.toHexString(this.value.toString(16));
|
||||
this.dec = this.value.toString(10);
|
||||
// >>> 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.kind = this.input.indexOf('0x') > -1 ? 'hex' : 'dec';
|
||||
this.other = this.kind == 'dec' ? this.hex : this.dec;
|
||||
this.lengthInBits = Operand.getBitLength(this.value);
|
||||
}
|
||||
|
||||
getLengthInBits() {
|
||||
if(this.value < 0) {
|
||||
return 32;
|
||||
}
|
||||
return Math.floor(Math.log(this.value) / Math.log(2)) + 1;
|
||||
};
|
||||
|
||||
getOtherKind(kind) {
|
||||
switch(kind || this.kind) {
|
||||
case 'dec': return 'hex';
|
||||
case 'hex': return 'dec';
|
||||
default : throw new Error(kind + " kind doesn't have opposite kind")
|
||||
}
|
||||
};
|
||||
|
||||
toString() {
|
||||
return this.input;
|
||||
}
|
||||
|
||||
setValue(value) {
|
||||
console.log('Before ' + value, this);
|
||||
this.value = value;
|
||||
this.bin = Operand.toKindString(this.value, 'bin');
|
||||
this.dec = Operand.toKindString(this.value, 'dec');
|
||||
this.hex = Operand.toKindString(this.value, 'hex');
|
||||
this.other = Operand.toKindString(this.value, this.getOtherKind());
|
||||
this.input = Operand.toKindString(this.value, this.kind);
|
||||
console.log('After ' + value, this);
|
||||
}
|
||||
|
||||
static getBitLength(num) {
|
||||
return Math.floor(Math.log(num) / Math.log(2)) + 1
|
||||
}
|
||||
|
||||
static getBase(kind){
|
||||
switch (kind){
|
||||
case 'bin': return 2;
|
||||
case 'hex': return 16;
|
||||
case 'dec': return 10;
|
||||
}
|
||||
};
|
||||
|
||||
static create(number, kind) {
|
||||
var str = number.toString(Operand.getBase(kind));
|
||||
if(kind == 'hex') {
|
||||
str = Operand.toHexString(str);
|
||||
}
|
||||
|
||||
return new Operand(str);
|
||||
};
|
||||
|
||||
static toKindString(value, kind) {
|
||||
switch(kind) {
|
||||
case 'hex':
|
||||
var hexVal = Math.abs(value).toString(16);
|
||||
return value >= 0 ? '0x' + hexVal : '-0x' + hexVal;
|
||||
case 'bin':
|
||||
return (value>>>0).toString(2);
|
||||
case 'dec':
|
||||
return value.toString(10);
|
||||
default:
|
||||
throw new Error("Unexpected kind: " + kind)
|
||||
}
|
||||
};
|
||||
|
||||
static toHexString (hex) {
|
||||
return hex.indexOf('-') == 0 ? '-0x' + hex.substr(1) : '0x' + hex;
|
||||
};
|
||||
}
|
||||
|
||||
// Expressions like ~1
|
||||
export class SingleOperandExpression {
|
||||
constructor(expressionString, operand, sign) {
|
||||
@@ -205,7 +123,10 @@ export class SingleOperandExpression {
|
||||
str = value + this.sign + this.operand1.value
|
||||
}
|
||||
|
||||
return Operand.create(eval(str), this.operand1.kind);
|
||||
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() {
|
||||
|
||||
5
src/app/expression/ExpressionError.js
Normal file
5
src/app/expression/ExpressionError.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export default class ExpressionError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
98
src/app/expression/Operand.js
Normal file
98
src/app/expression/Operand.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import numberParser from './numberParser';
|
||||
import ExpressionError from './ExpressionError';
|
||||
|
||||
// Represents numeric value
|
||||
export default class Operand {
|
||||
constructor(cfg) {
|
||||
|
||||
this.input = cfg.input;
|
||||
this.value = cfg.value;
|
||||
this.kind = cfg.kind;
|
||||
|
||||
this.hex = Operand.toHexString(this.value.toString(16));
|
||||
this.dec = this.value.toString(10);
|
||||
// >>> 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.other = this.kind == 'hex' ? this.dec : this.hex;
|
||||
|
||||
this.lengthInBits = Operand.getBitLength(this.value);
|
||||
}
|
||||
|
||||
getLengthInBits() {
|
||||
if(this.value < 0) {
|
||||
return 32;
|
||||
}
|
||||
return Math.floor(Math.log(this.value) / Math.log(2)) + 1;
|
||||
};
|
||||
|
||||
getOtherKind(kind) {
|
||||
switch(kind || this.kind) {
|
||||
case 'dec': return 'hex';
|
||||
case 'hex': return 'dec';
|
||||
default : throw new Error(kind + " kind doesn't have opposite kind")
|
||||
}
|
||||
};
|
||||
|
||||
toString() {
|
||||
return this.input;
|
||||
}
|
||||
|
||||
setValue(value) {
|
||||
this.value = value;
|
||||
this.bin = Operand.toKindString(this.value, 'bin');
|
||||
this.dec = Operand.toKindString(this.value, 'dec');
|
||||
this.hex = Operand.toKindString(this.value, 'hex');
|
||||
this.other = Operand.toKindString(this.value, this.getOtherKind());
|
||||
this.input = Operand.toKindString(this.value, this.kind);
|
||||
}
|
||||
|
||||
static getBitLength(num) {
|
||||
return Math.floor(Math.log(num) / Math.log(2)) + 1
|
||||
}
|
||||
|
||||
static getBase(kind){
|
||||
switch (kind){
|
||||
case 'bin': return 2;
|
||||
case 'hex': return 16;
|
||||
case 'dec': return 10;
|
||||
}
|
||||
};
|
||||
|
||||
static create(value, kind) {
|
||||
|
||||
return new Operand({
|
||||
value: value,
|
||||
kind: kind,
|
||||
input: Operand.toKindString(value, kind),
|
||||
});
|
||||
};
|
||||
|
||||
static parse(input) {
|
||||
|
||||
var parsed = numberParser.parse(input);
|
||||
|
||||
if(!parsed) {
|
||||
throw new ExpressionError("Unknown number: " + input);
|
||||
}
|
||||
|
||||
return new Operand(parsed);
|
||||
}
|
||||
|
||||
static toKindString(value, kind) {
|
||||
switch(kind) {
|
||||
case 'hex':
|
||||
var hexVal = Math.abs(value).toString(16);
|
||||
return value >= 0 ? '0x' + hexVal : '-0x' + hexVal;
|
||||
case 'bin':
|
||||
return (value>>>0).toString(2);
|
||||
case 'dec':
|
||||
return value.toString(10);
|
||||
default:
|
||||
throw new Error("Unexpected kind: " + kind)
|
||||
}
|
||||
};
|
||||
|
||||
static toHexString (hex) {
|
||||
return hex.indexOf('-') == 0 ? '-0x' + hex.substr(1) : '0x' + hex;
|
||||
};
|
||||
}
|
||||
31
src/app/expression/numberParser.js
Normal file
31
src/app/expression/numberParser.js
Normal file
@@ -0,0 +1,31 @@
|
||||
var decimalRegex = /^-?\d+$/;
|
||||
var hexRegex = /^-?0x[0-9,a-f]+$/i;
|
||||
var binRegex = /^-?0b[0-1]+$/i;
|
||||
|
||||
var parsers = [
|
||||
{ regex: decimalRegex, radix: 10, kind: 'dec', prefix: '^$' },
|
||||
{ regex: hexRegex, radix: 16, kind: 'hex', prefix:/0x/i },
|
||||
{ regex: binRegex, radix: 2, kind: 'bin', prefix:/0b/i }];
|
||||
|
||||
function applyParser(parser, rawInput) {
|
||||
|
||||
if(!parser.regex.test(rawInput)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var value = parseInt(rawInput.replace(parser.prefix, ''), parser.radix);
|
||||
|
||||
return {
|
||||
value: value,
|
||||
kind: parser.kind,
|
||||
input: rawInput
|
||||
}
|
||||
}
|
||||
|
||||
var parser = {
|
||||
parse: function(input) {
|
||||
return parsers.map(p => applyParser(p, input)).reduce((c, n) => c || n);
|
||||
}
|
||||
}
|
||||
|
||||
export default parser;
|
||||
@@ -11,12 +11,6 @@ export default {
|
||||
args = { commands: [] };
|
||||
|
||||
splitHashList(decodedHash).forEach(function(value) {
|
||||
// Support for -debur or -notrack properties
|
||||
if(/^\-[a-zA-Z]+$/.test(value)) {
|
||||
args[value.substr(1)] = true;
|
||||
return;
|
||||
}
|
||||
|
||||
args.commands.push(value);
|
||||
});
|
||||
|
||||
|
||||
@@ -51,5 +51,7 @@ function executeStartupCommands() {
|
||||
startupCommands = hashArgs.commands;
|
||||
}
|
||||
|
||||
log.info('starup commands', startupCommands);
|
||||
|
||||
startupCommands.forEach(cmd.execute.bind(cmd));
|
||||
}
|
||||
@@ -108,8 +108,8 @@ code { font-size: 1.2em; font-weight: bold; }
|
||||
.midnight .zero { color: #85a0ad;}
|
||||
.midnight .prefix { color: #85a0ad}
|
||||
.midnight .other { color: #9FBAC7;}
|
||||
.midnight .hashLink, .dark .hashLink:visited { color: #333 }
|
||||
.midnight .hashLink:hover { color: #85a0ad }
|
||||
.midnight .hashLink, .dark .hashLink:visited { color: #85a0ad }
|
||||
.midnight .hashLink:hover { color: #9FBAC7 }
|
||||
.midnight ul.top-links li:hover { background: #132537 }
|
||||
.midnight .error { color:#da586d}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user