diff --git a/src/core/calc.test.ts b/src/core/calc.test.ts index b521467..48213cc 100644 --- a/src/core/calc.test.ts +++ b/src/core/calc.test.ts @@ -17,13 +17,14 @@ describe("calc", () => { expect(calc.maxNumberOfBitsDisplayed([1, 2, 3, 10])).toBe(4); }); - it('calculates expression', () => { + it('calculates expression', () => { + var result = calc.calcExpression(new BitwiseOperationExpression( "1|2&3", [ new ScalarExpression(1), - new OperatorExpression("|2", new ScalarExpression(2), "|"), - new OperatorExpression("&3", new ScalarExpression(3), "&"), + new OperatorExpression(new ScalarExpression(2), "|"), + new OperatorExpression(new ScalarExpression(3), "&"), ] )); diff --git a/src/core/const.ts b/src/core/const.ts index a5b1ef5..66095c6 100644 --- a/src/core/const.ts +++ b/src/core/const.ts @@ -1,4 +1,3 @@ const INT_MAX_VALUE = 2147483647; - export {INT_MAX_VALUE}; \ No newline at end of file diff --git a/src/expression/ListOfNumbersExpression.ts b/src/expression/ListOfNumbersExpression.ts index 5d90564..6cd5a9b 100644 --- a/src/expression/ListOfNumbersExpression.ts +++ b/src/expression/ListOfNumbersExpression.ts @@ -3,17 +3,17 @@ import ScalarExpression from "./ScalarExpression"; import { ExpressionInput, Expression } from "./expression-interfaces"; export default class ListOfNumbersExpression implements ExpressionInput { - numbers: ScalarExpression[]; + children: ScalarExpression[]; expressionString: string; maxBitsLength: number; constructor(expressionString: string, numbers: ScalarExpression[]) { 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); } toString() { - return this.numbers.map(n => n.value.toString()).join(' '); + return this.children.map(n => n.value.toString()).join(' '); } } \ No newline at end of file diff --git a/src/expression/OperatorExpression.test.ts b/src/expression/OperatorExpression.test.ts index 2dda211..a4decc2 100644 --- a/src/expression/OperatorExpression.test.ts +++ b/src/expression/OperatorExpression.test.ts @@ -1,9 +1,10 @@ import ScalarExpression from "./ScalarExpression"; import OperatorExpression from './OperatorExpression'; +import { INT_MAX_VALUE } from "../core/const"; it('can apply ~ operand', () => { var op = new ScalarExpression(10, 'dec'); - var expr = new OperatorExpression("~10", op, "~"); + var expr = new OperatorExpression(op, "~"); var result = expr.evaluate(); expect(result.value).toBe(-11); expect(result.base).toBe('dec'); @@ -12,8 +13,13 @@ it('can apply ~ operand', () => { it('can apply & operand', () => { var op1 = new ScalarExpression(3, 'dec'); var op2 = new ScalarExpression(4, 'dec'); - var expr = new OperatorExpression("|3", op1, "|"); + var expr = new OperatorExpression(op1, "|"); var result = expr.evaluate(op2); expect(result.value).toBe(7); 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"); }); \ No newline at end of file diff --git a/src/expression/OperatorExpression.ts b/src/expression/OperatorExpression.ts index 2df3bd8..7909508 100644 --- a/src/expression/OperatorExpression.ts +++ b/src/expression/OperatorExpression.ts @@ -1,21 +1,30 @@ +import { INT_MAX_VALUE } from '../core/const'; +import formatter from '../core/formatter'; import ScalarExpression from './ScalarExpression'; import { Expression } from './expression-interfaces'; export default class OperatorExpression implements Expression { - expressionString: string; operand: Expression; - sign: string; + operator: string; isOperator: boolean; isShiftExpression: boolean; isNotExpression: boolean; - constructor(expressionString : string, operand : Expression, sign : string) { - this.expressionString = expressionString; + constructor(operand : Expression, operator : string) { + + 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.sign = sign; + this.operator = operator; this.isOperator = true; - this.isShiftExpression = this.sign.indexOf('<') >= 0 || this.sign.indexOf('>')>= 0; - this.isNotExpression = this.sign === '~'; + this.isShiftExpression = this.operator.indexOf('<') >= 0 || this.operator.indexOf('>')>= 0; + this.isNotExpression = this.operator === '~'; } evaluate(operand?: ScalarExpression) : ScalarExpression { @@ -26,13 +35,13 @@ export default class OperatorExpression implements Expression { var evaluatedOperand = this.operand.evaluate(); var str = ''; - if(this.sign == '~'){ + if(this.operator == '~'){ str = '~' + evaluatedOperand.value; } else { 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); @@ -43,6 +52,6 @@ export default class OperatorExpression implements Expression { } toString(): string { - return this.sign + this.operand.toString(); + return this.operator + this.operand.toString(); } } \ No newline at end of file diff --git a/src/expression/ScalarExpression.ts b/src/expression/ScalarExpression.ts index 256c7ce..2aa9e59 100644 --- a/src/expression/ScalarExpression.ts +++ b/src/expression/ScalarExpression.ts @@ -1,6 +1,7 @@ import {numberParser} from './numberParser'; import { Expression as Expression } from './expression-interfaces'; import { NumberBase } from '../core/formatter'; +import { INT_MAX_VALUE } from '../core/const'; var globalId : number = 1; diff --git a/src/expression/components/BitwiseExpressionModel.ts b/src/expression/components/BitwiseExpressionModel.ts index 706fd1e..94cbe6c 100644 --- a/src/expression/components/BitwiseExpressionModel.ts +++ b/src/expression/components/BitwiseExpressionModel.ts @@ -32,7 +32,7 @@ export default class BitwiseExpressionViewModel { static buildListOfNumbers(expr : ListOfNumbersExpression, config : 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); return model; } @@ -105,7 +105,7 @@ export default class BitwiseExpressionViewModel { this.maxNumberOfBits = Math.max(bits, this.maxNumberOfBits); this.items.push({ - sign: expr.sign, + sign: expr.operator, css: '', label: this.getLabel(resultNumber), expression: expr.operand, @@ -118,7 +118,7 @@ export default class BitwiseExpressionViewModel { this.maxNumberOfBits = Math.max(bits, this.maxNumberOfBits); const child = expr.operand.getUnderlyingScalarOperand(); this.items.push({ - sign: expr.sign + formatter.numberToString(child.value, child.base), + sign: expr.operator + formatter.numberToString(child.value, child.base), css: 'expression-result', expression: resultExpr, allowFlipBits: false, diff --git a/src/expression/components/BitwiseOperationExpressionView.tsx b/src/expression/components/BitwiseOperationExpressionView.tsx index 173b309..3aa1629 100644 --- a/src/expression/components/BitwiseOperationExpressionView.tsx +++ b/src/expression/components/BitwiseOperationExpressionView.tsx @@ -96,7 +96,7 @@ class ExpressionRow extends React.Component { // TODO: find a better way... if(this.props.expressionItem.isOperator) { 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()); diff --git a/src/expression/expression.test.ts b/src/expression/expression.test.ts index 98c8781..bf7eb48 100644 --- a/src/expression/expression.test.ts +++ b/src/expression/expression.test.ts @@ -1,4 +1,3 @@ -import { OperationCanceledException } from "typescript"; import { parser, ListOfNumbersExpression, BitwiseOperationExpression, ScalarExpression, OperatorExpression } from "./expression"; describe("expression parser", () => { @@ -21,11 +20,11 @@ describe("expression parser", () => { }); it("parses big binary bitwise expression", () => { - const input = "0b00010010001101000101011001111000 | 0b10101010101010101010101000000000"; + const input = "0b00010010001101000101011001111000 0b10101010101010101010101000000000"; 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[1].getUnderlyingScalarOperand().value).toBe(2863311360); }) @@ -43,7 +42,7 @@ describe("expression parser", () => { expect(second).toBeInstanceOf(OperatorExpression); var secondOp = second as OperatorExpression; - expect(secondOp.sign).toBe("^"); + expect(secondOp.operator).toBe("^"); expect(secondOp.operand).toBeInstanceOf(ScalarExpression); var childOp = secondOp.operand as ScalarExpression; diff --git a/src/expression/expression.ts b/src/expression/expression.ts index 62080f4..fc087c1 100644 --- a/src/expression/expression.ts +++ b/src/expression/expression.ts @@ -4,6 +4,7 @@ import ListOfNumbersExpression from './ListOfNumbersExpression'; import BitwiseOperationExpression from './BitwiseOperationExpression'; import { ExpressionInput, Expression } from './expression-interfaces'; import { NumberBase } from '../core/formatter'; +import { Match } from '@testing-library/react'; export { default as ScalarExpression } from './ScalarExpression'; export { default as OperatorExpression } from './OperatorExpression'; @@ -100,33 +101,36 @@ class BitwiseOperationExpressionFactory implements IExpressionParserFactory { }; create (input: string) : ExpressionInput { - var m, operands : Expression[] = [], - normalizedString = this.normalizeString(input); + var m : RegExpExecArray | null; + const operands : Expression[] = []; + const normalizedString = this.normalizeString(input); + + this.regex.lastIndex = 0; while ((m = this.regex.exec(normalizedString)) != null) { operands.push(this.parseMatch(m)); } - + return new BitwiseOperationExpression(normalizedString, operands) }; parseMatch (m:any): Expression { var input = m[0], - sign = m[1], + operator = m[1], num = m[2]; var parsed = null; if(num.indexOf('~') == 0) { - parsed = new OperatorExpression(num, ScalarExpression.parse(num.substring(1)), '~'); + parsed = new OperatorExpression(ScalarExpression.parse(num.substring(1)), '~'); } else { parsed = ScalarExpression.parse(num); } - if(sign == null) { + if(operator == null) { return parsed as OperatorExpression; } else { - return new OperatorExpression(input, parsed as ScalarExpression, sign); + return new OperatorExpression(parsed as ScalarExpression, operator); } }; diff --git a/src/shell/cmd.ts b/src/shell/cmd.ts index 9868299..d4212d1 100644 --- a/src/shell/cmd.ts +++ b/src/shell/cmd.ts @@ -42,14 +42,15 @@ export class CmdShell { var handler = this.findHandler(input); if(handler != null) { - if(this.debugMode) { + // if(this.debugMode) { + // this.invokeHandler(input, handler, ops); + // return + // } + + try { this.invokeHandler(input, handler, ops); - } else { - try { - this.invokeHandler(input, handler, ops); - } catch (e) { - this.handleError(input, e as Error); - } + } catch (e) { + this.handleError(input, e as Error); } } else { @@ -107,6 +108,7 @@ export class CmdShell { }; handleError (input: string, err: Error) { + if(this.debugMode) console.error(input, err);