mirror of
https://github.com/BorysLevytskyi/BitwiseCmd.git
synced 2025-12-13 08:22:11 +01:00
`Disable bitwise operations
This commit is contained in:
@@ -18,12 +18,13 @@ describe("calc", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('calculates expression', () => {
|
it('calculates expression', () => {
|
||||||
|
|
||||||
var result = calc.calcExpression(new BitwiseOperationExpression(
|
var result = calc.calcExpression(new BitwiseOperationExpression(
|
||||||
"1|2&3",
|
"1|2&3",
|
||||||
[
|
[
|
||||||
new ScalarExpression(1),
|
new ScalarExpression(1),
|
||||||
new OperatorExpression("|2", new ScalarExpression(2), "|"),
|
new OperatorExpression(new ScalarExpression(2), "|"),
|
||||||
new OperatorExpression("&3", new ScalarExpression(3), "&"),
|
new OperatorExpression(new ScalarExpression(3), "&"),
|
||||||
]
|
]
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
const INT_MAX_VALUE = 2147483647;
|
const INT_MAX_VALUE = 2147483647;
|
||||||
|
|
||||||
export {INT_MAX_VALUE};
|
export {INT_MAX_VALUE};
|
||||||
@@ -3,17 +3,17 @@ import ScalarExpression from "./ScalarExpression";
|
|||||||
import { ExpressionInput, Expression } from "./expression-interfaces";
|
import { ExpressionInput, Expression } from "./expression-interfaces";
|
||||||
|
|
||||||
export default class ListOfNumbersExpression implements ExpressionInput {
|
export default class ListOfNumbersExpression implements ExpressionInput {
|
||||||
numbers: ScalarExpression[];
|
children: ScalarExpression[];
|
||||||
expressionString: string;
|
expressionString: string;
|
||||||
maxBitsLength: number;
|
maxBitsLength: number;
|
||||||
|
|
||||||
constructor(expressionString: string, numbers: ScalarExpression[]) {
|
constructor(expressionString: string, numbers: ScalarExpression[]) {
|
||||||
this.expressionString = expressionString;
|
this.expressionString = expressionString;
|
||||||
this.numbers = numbers;
|
this.children = numbers;
|
||||||
this.maxBitsLength = numbers.map(n => calc.numberOfBitsDisplayed(n.value)).reduce((n , c) => n >= c ? n : c, 0);
|
this.maxBitsLength = numbers.map(n => calc.numberOfBitsDisplayed(n.value)).reduce((n , c) => n >= c ? n : c, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return this.numbers.map(n => n.value.toString()).join(' ');
|
return this.children.map(n => n.value.toString()).join(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import ScalarExpression from "./ScalarExpression";
|
import ScalarExpression from "./ScalarExpression";
|
||||||
import OperatorExpression from './OperatorExpression';
|
import OperatorExpression from './OperatorExpression';
|
||||||
|
import { INT_MAX_VALUE } from "../core/const";
|
||||||
|
|
||||||
it('can apply ~ operand', () => {
|
it('can apply ~ operand', () => {
|
||||||
var op = new ScalarExpression(10, 'dec');
|
var op = new ScalarExpression(10, 'dec');
|
||||||
var expr = new OperatorExpression("~10", op, "~");
|
var expr = new OperatorExpression(op, "~");
|
||||||
var result = expr.evaluate();
|
var result = expr.evaluate();
|
||||||
expect(result.value).toBe(-11);
|
expect(result.value).toBe(-11);
|
||||||
expect(result.base).toBe('dec');
|
expect(result.base).toBe('dec');
|
||||||
@@ -12,8 +13,13 @@ it('can apply ~ operand', () => {
|
|||||||
it('can apply & operand', () => {
|
it('can apply & operand', () => {
|
||||||
var op1 = new ScalarExpression(3, 'dec');
|
var op1 = new ScalarExpression(3, 'dec');
|
||||||
var op2 = new ScalarExpression(4, 'dec');
|
var op2 = new ScalarExpression(4, 'dec');
|
||||||
var expr = new OperatorExpression("|3", op1, "|");
|
var expr = new OperatorExpression(op1, "|");
|
||||||
var result = expr.evaluate(op2);
|
var result = expr.evaluate(op2);
|
||||||
expect(result.value).toBe(7);
|
expect(result.value).toBe(7);
|
||||||
expect(result.base).toBe('dec');
|
expect(result.base).toBe('dec');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("doesn't support opreations with numbers larger than 32-bit", () => {
|
||||||
|
expect(() => new OperatorExpression(new ScalarExpression(2147483648), "^"))
|
||||||
|
.toThrowError("2147483648 has more than 32 bits. JavaScript converts all numbers to 32-bit integers when applying bitwise operators. BitwiseCmd currently uses the JavaScript engine of your browser for results calculation and supports numbers in the range from -2147483647 to 2147483647");
|
||||||
|
});
|
||||||
@@ -1,21 +1,30 @@
|
|||||||
|
import { INT_MAX_VALUE } from '../core/const';
|
||||||
|
import formatter from '../core/formatter';
|
||||||
import ScalarExpression from './ScalarExpression';
|
import ScalarExpression from './ScalarExpression';
|
||||||
import { Expression } from './expression-interfaces';
|
import { Expression } from './expression-interfaces';
|
||||||
|
|
||||||
export default class OperatorExpression implements Expression {
|
export default class OperatorExpression implements Expression {
|
||||||
expressionString: string;
|
|
||||||
operand: Expression;
|
operand: Expression;
|
||||||
sign: string;
|
operator: string;
|
||||||
isOperator: boolean;
|
isOperator: boolean;
|
||||||
isShiftExpression: boolean;
|
isShiftExpression: boolean;
|
||||||
isNotExpression: boolean;
|
isNotExpression: boolean;
|
||||||
|
|
||||||
constructor(expressionString : string, operand : Expression, sign : string) {
|
constructor(operand : Expression, operator : string) {
|
||||||
this.expressionString = expressionString;
|
|
||||||
|
if(operand instanceof ScalarExpression) {
|
||||||
|
const o = operand.getUnderlyingScalarOperand();
|
||||||
|
if(Math.abs(o.value) > INT_MAX_VALUE) {
|
||||||
|
const n = formatter.numberToString(o.value, o.base);
|
||||||
|
throw new Error(`${n} has more than 32 bits. JavaScript converts all numbers to 32-bit integers when applying bitwise operators. BitwiseCmd currently uses the JavaScript engine of your browser for results calculation and supports numbers in the range from ${-INT_MAX_VALUE} to ${INT_MAX_VALUE}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.operand = operand;
|
this.operand = operand;
|
||||||
this.sign = sign;
|
this.operator = operator;
|
||||||
this.isOperator = true;
|
this.isOperator = true;
|
||||||
this.isShiftExpression = this.sign.indexOf('<') >= 0 || this.sign.indexOf('>')>= 0;
|
this.isShiftExpression = this.operator.indexOf('<') >= 0 || this.operator.indexOf('>')>= 0;
|
||||||
this.isNotExpression = this.sign === '~';
|
this.isNotExpression = this.operator === '~';
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluate(operand?: ScalarExpression) : ScalarExpression {
|
evaluate(operand?: ScalarExpression) : ScalarExpression {
|
||||||
@@ -26,13 +35,13 @@ export default class OperatorExpression implements Expression {
|
|||||||
var evaluatedOperand = this.operand.evaluate();
|
var evaluatedOperand = this.operand.evaluate();
|
||||||
|
|
||||||
var str = '';
|
var str = '';
|
||||||
if(this.sign == '~'){
|
if(this.operator == '~'){
|
||||||
str = '~' + evaluatedOperand.value;
|
str = '~' + evaluatedOperand.value;
|
||||||
} else {
|
} else {
|
||||||
if(operand == null)
|
if(operand == null)
|
||||||
throw new Error("Other is required for expression: " + this.expressionString)
|
throw new Error("Other is required for this expression");
|
||||||
|
|
||||||
str = operand.value + this.sign + evaluatedOperand.value;
|
str = operand.value + this.operator + evaluatedOperand.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ScalarExpression.create(eval(str), evaluatedOperand.base);
|
return ScalarExpression.create(eval(str), evaluatedOperand.base);
|
||||||
@@ -43,6 +52,6 @@ export default class OperatorExpression implements Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return this.sign + this.operand.toString();
|
return this.operator + this.operand.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import {numberParser} from './numberParser';
|
import {numberParser} from './numberParser';
|
||||||
import { Expression as Expression } from './expression-interfaces';
|
import { Expression as Expression } from './expression-interfaces';
|
||||||
import { NumberBase } from '../core/formatter';
|
import { NumberBase } from '../core/formatter';
|
||||||
|
import { INT_MAX_VALUE } from '../core/const';
|
||||||
|
|
||||||
var globalId : number = 1;
|
var globalId : number = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default class BitwiseExpressionViewModel {
|
|||||||
|
|
||||||
static buildListOfNumbers(expr : ListOfNumbersExpression, config : Config) {
|
static buildListOfNumbers(expr : ListOfNumbersExpression, config : Config) {
|
||||||
var model = new BitwiseExpressionViewModel(config);
|
var model = new BitwiseExpressionViewModel(config);
|
||||||
expr.numbers.forEach(op => model.addScalarRow(op));
|
expr.children.forEach(op => model.addScalarRow(op));
|
||||||
model.maxNumberOfBits = BitwiseExpressionViewModel.applyEmphasizeBytes(model.maxNumberOfBits, model.emphasizeBytes);
|
model.maxNumberOfBits = BitwiseExpressionViewModel.applyEmphasizeBytes(model.maxNumberOfBits, model.emphasizeBytes);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ export default class BitwiseExpressionViewModel {
|
|||||||
this.maxNumberOfBits = Math.max(bits, this.maxNumberOfBits);
|
this.maxNumberOfBits = Math.max(bits, this.maxNumberOfBits);
|
||||||
|
|
||||||
this.items.push({
|
this.items.push({
|
||||||
sign: expr.sign,
|
sign: expr.operator,
|
||||||
css: '',
|
css: '',
|
||||||
label: this.getLabel(resultNumber),
|
label: this.getLabel(resultNumber),
|
||||||
expression: expr.operand,
|
expression: expr.operand,
|
||||||
@@ -118,7 +118,7 @@ export default class BitwiseExpressionViewModel {
|
|||||||
this.maxNumberOfBits = Math.max(bits, this.maxNumberOfBits);
|
this.maxNumberOfBits = Math.max(bits, this.maxNumberOfBits);
|
||||||
const child = expr.operand.getUnderlyingScalarOperand();
|
const child = expr.operand.getUnderlyingScalarOperand();
|
||||||
this.items.push({
|
this.items.push({
|
||||||
sign: expr.sign + formatter.numberToString(child.value, child.base),
|
sign: expr.operator + formatter.numberToString(child.value, child.base),
|
||||||
css: 'expression-result',
|
css: 'expression-result',
|
||||||
expression: resultExpr,
|
expression: resultExpr,
|
||||||
allowFlipBits: false,
|
allowFlipBits: false,
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class ExpressionRow extends React.Component<ExpressionRowProps> {
|
|||||||
// TODO: find a better way...
|
// TODO: find a better way...
|
||||||
if(this.props.expressionItem.isOperator) {
|
if(this.props.expressionItem.isOperator) {
|
||||||
const ex = this.props.expressionItem as OperatorExpression;
|
const ex = this.props.expressionItem as OperatorExpression;
|
||||||
return ex.sign + this.getLabelString(ex.getUnderlyingScalarOperand());
|
return ex.operator + this.getLabelString(ex.getUnderlyingScalarOperand());
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getLabelString(this.props.expressionItem.getUnderlyingScalarOperand());
|
return this.getLabelString(this.props.expressionItem.getUnderlyingScalarOperand());
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { OperationCanceledException } from "typescript";
|
|
||||||
import { parser, ListOfNumbersExpression, BitwiseOperationExpression, ScalarExpression, OperatorExpression } from "./expression";
|
import { parser, ListOfNumbersExpression, BitwiseOperationExpression, ScalarExpression, OperatorExpression } from "./expression";
|
||||||
|
|
||||||
describe("expression parser", () => {
|
describe("expression parser", () => {
|
||||||
@@ -21,11 +20,11 @@ describe("expression parser", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("parses big binary bitwise expression", () => {
|
it("parses big binary bitwise expression", () => {
|
||||||
const input = "0b00010010001101000101011001111000 | 0b10101010101010101010101000000000";
|
const input = "0b00010010001101000101011001111000 0b10101010101010101010101000000000";
|
||||||
const actual = parser.parse(input);
|
const actual = parser.parse(input);
|
||||||
expect(actual).toBeInstanceOf(BitwiseOperationExpression);
|
expect(actual).toBeInstanceOf(ListOfNumbersExpression);
|
||||||
|
|
||||||
const expr = actual as BitwiseOperationExpression;
|
const expr = actual as ListOfNumbersExpression;
|
||||||
expect(expr.children[0].getUnderlyingScalarOperand().value).toBe(305419896);
|
expect(expr.children[0].getUnderlyingScalarOperand().value).toBe(305419896);
|
||||||
expect(expr.children[1].getUnderlyingScalarOperand().value).toBe(2863311360);
|
expect(expr.children[1].getUnderlyingScalarOperand().value).toBe(2863311360);
|
||||||
})
|
})
|
||||||
@@ -43,7 +42,7 @@ describe("expression parser", () => {
|
|||||||
|
|
||||||
expect(second).toBeInstanceOf(OperatorExpression);
|
expect(second).toBeInstanceOf(OperatorExpression);
|
||||||
var secondOp = second as OperatorExpression;
|
var secondOp = second as OperatorExpression;
|
||||||
expect(secondOp.sign).toBe("^");
|
expect(secondOp.operator).toBe("^");
|
||||||
|
|
||||||
expect(secondOp.operand).toBeInstanceOf(ScalarExpression);
|
expect(secondOp.operand).toBeInstanceOf(ScalarExpression);
|
||||||
var childOp = secondOp.operand as ScalarExpression;
|
var childOp = secondOp.operand as ScalarExpression;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import ListOfNumbersExpression from './ListOfNumbersExpression';
|
|||||||
import BitwiseOperationExpression from './BitwiseOperationExpression';
|
import BitwiseOperationExpression from './BitwiseOperationExpression';
|
||||||
import { ExpressionInput, Expression } from './expression-interfaces';
|
import { ExpressionInput, Expression } from './expression-interfaces';
|
||||||
import { NumberBase } from '../core/formatter';
|
import { NumberBase } from '../core/formatter';
|
||||||
|
import { Match } from '@testing-library/react';
|
||||||
|
|
||||||
export { default as ScalarExpression } from './ScalarExpression';
|
export { default as ScalarExpression } from './ScalarExpression';
|
||||||
export { default as OperatorExpression } from './OperatorExpression';
|
export { default as OperatorExpression } from './OperatorExpression';
|
||||||
@@ -100,8 +101,11 @@ class BitwiseOperationExpressionFactory implements IExpressionParserFactory {
|
|||||||
};
|
};
|
||||||
|
|
||||||
create (input: string) : ExpressionInput {
|
create (input: string) : ExpressionInput {
|
||||||
var m, operands : Expression[] = [],
|
var m : RegExpExecArray | null;
|
||||||
normalizedString = this.normalizeString(input);
|
const operands : Expression[] = [];
|
||||||
|
const normalizedString = this.normalizeString(input);
|
||||||
|
|
||||||
|
this.regex.lastIndex = 0;
|
||||||
|
|
||||||
while ((m = this.regex.exec(normalizedString)) != null) {
|
while ((m = this.regex.exec(normalizedString)) != null) {
|
||||||
operands.push(this.parseMatch(m));
|
operands.push(this.parseMatch(m));
|
||||||
@@ -112,21 +116,21 @@ class BitwiseOperationExpressionFactory implements IExpressionParserFactory {
|
|||||||
|
|
||||||
parseMatch (m:any): Expression {
|
parseMatch (m:any): Expression {
|
||||||
var input = m[0],
|
var input = m[0],
|
||||||
sign = m[1],
|
operator = m[1],
|
||||||
num = m[2];
|
num = m[2];
|
||||||
|
|
||||||
var parsed = null;
|
var parsed = null;
|
||||||
if(num.indexOf('~') == 0) {
|
if(num.indexOf('~') == 0) {
|
||||||
parsed = new OperatorExpression(num, ScalarExpression.parse(num.substring(1)), '~');
|
parsed = new OperatorExpression(ScalarExpression.parse(num.substring(1)), '~');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parsed = ScalarExpression.parse(num);
|
parsed = ScalarExpression.parse(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sign == null) {
|
if(operator == null) {
|
||||||
return parsed as OperatorExpression;
|
return parsed as OperatorExpression;
|
||||||
} else {
|
} else {
|
||||||
return new OperatorExpression(input, parsed as ScalarExpression, sign);
|
return new OperatorExpression(parsed as ScalarExpression, operator);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,16 +42,17 @@ export class CmdShell {
|
|||||||
var handler = this.findHandler(input);
|
var handler = this.findHandler(input);
|
||||||
|
|
||||||
if(handler != null) {
|
if(handler != null) {
|
||||||
if(this.debugMode) {
|
// if(this.debugMode) {
|
||||||
this.invokeHandler(input, handler, ops);
|
// this.invokeHandler(input, handler, ops);
|
||||||
} else {
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.invokeHandler(input, handler, ops);
|
this.invokeHandler(input, handler, ops);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.handleError(input, e as Error);
|
this.handleError(input, e as Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
log.debug(`Handled is not found for command: ${rawInput}`)
|
log.debug(`Handled is not found for command: ${rawInput}`)
|
||||||
this.handleError(input, new Error("Unsupported expression: " + input.trim()));
|
this.handleError(input, new Error("Unsupported expression: " + input.trim()));
|
||||||
@@ -107,6 +108,7 @@ export class CmdShell {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleError (input: string, err: Error) {
|
handleError (input: string, err: Error) {
|
||||||
|
|
||||||
if(this.debugMode)
|
if(this.debugMode)
|
||||||
console.error(input, err);
|
console.error(input, err);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user