From e8e6e4697a26be0ca0b3a4af28e5dc711f56e67c Mon Sep 17 00:00:00 2001 From: BorysLevytskyi Date: Sat, 6 May 2023 18:43:37 +0200 Subject: [PATCH] Refactor and enable bits flipping in bitwise expression --- src/core/calc.test.ts | 8 ++-- src/core/calc.ts | 4 +- src/expression/BitwiseOperationExpression.ts | 8 ++-- src/expression/ExpressionParser.test.ts | 6 +-- .../ListOfNumbersExpression.test.ts | 4 +- src/expression/ListOfNumbersExpression.ts | 10 ++--- src/expression/OperatorExpression.test.ts | 16 +++---- ...OperatorExpression.ts => OperatorToken.ts} | 20 ++++----- src/expression/ScalarExpression.test.ts | 8 ++-- .../{ScalarExpression.ts => ScalarToken.ts} | 18 ++++---- .../components/BitwiseResultView.tsx | 16 +++---- .../components/BitwiseResultViewModel.ts | 34 +++++++-------- src/expression/expression-interfaces.ts | 10 ++--- src/expression/expression.test.ts | 14 +++---- src/expression/expression.ts | 42 +++++++++---------- src/networking/components/IpAddressView.tsx | 2 +- 16 files changed, 110 insertions(+), 110 deletions(-) rename src/expression/{OperatorExpression.ts => OperatorToken.ts} (74%) rename src/expression/{ScalarExpression.ts => ScalarToken.ts} (65%) diff --git a/src/core/calc.test.ts b/src/core/calc.test.ts index 3ae6dbd..a62a2ed 100644 --- a/src/core/calc.test.ts +++ b/src/core/calc.test.ts @@ -1,5 +1,5 @@ import calc from './calc'; -import { BitwiseOperationExpression, ScalarExpression, OperatorExpression } from '../expression/expression'; +import { BitwiseOperationExpression, ScalarToken, OperatorToken } from '../expression/expression'; import exp from 'constants'; import { INT_MAX_VALUE } from './const'; import formatter from './formatter'; @@ -23,9 +23,9 @@ describe("calc", () => { var result = calc.calcExpression(new BitwiseOperationExpression( "1|2&3", [ - new ScalarExpression(1), - new OperatorExpression(new ScalarExpression(2), "|"), - new OperatorExpression(new ScalarExpression(3), "&"), + new ScalarToken(1), + new OperatorToken(new ScalarToken(2), "|"), + new OperatorToken(new ScalarToken(3), "&"), ] )); diff --git a/src/core/calc.ts b/src/core/calc.ts index edf4f3d..3a47dda 100644 --- a/src/core/calc.ts +++ b/src/core/calc.ts @@ -1,5 +1,5 @@ import { dblClick } from "@testing-library/user-event/dist/click"; -import { ExpressionInput } from "../expression/expression-interfaces"; +import { Expression } from "../expression/expression-interfaces"; import { INT_MAX_VALUE } from "./const"; import { start } from "repl"; @@ -23,7 +23,7 @@ export default { return Math.max.apply(null, counts); }, - calcExpression: function (expr: ExpressionInput) { + calcExpression: function (expr: Expression) { return eval(expr.expressionString); }, diff --git a/src/expression/BitwiseOperationExpression.ts b/src/expression/BitwiseOperationExpression.ts index 95b0785..64a9805 100644 --- a/src/expression/BitwiseOperationExpression.ts +++ b/src/expression/BitwiseOperationExpression.ts @@ -1,11 +1,11 @@ -import { ExpressionInput, Expression } from "./expression-interfaces"; +import { Expression, ExpressionToken } from "./expression-interfaces"; -export default class BitwiseOperationExpression implements ExpressionInput { +export default class BitwiseOperationExpression implements Expression { expressionString: string; - children: Expression[]; + children: ExpressionToken[]; - constructor(expressionString: string, children: Expression[]) { + constructor(expressionString: string, children: ExpressionToken[]) { this.expressionString = expressionString; this.children = children; } diff --git a/src/expression/ExpressionParser.test.ts b/src/expression/ExpressionParser.test.ts index 851cacf..1f04934 100644 --- a/src/expression/ExpressionParser.test.ts +++ b/src/expression/ExpressionParser.test.ts @@ -1,6 +1,6 @@ -import OperatorExpression from "./OperatorExpression"; -import { ScalarExpression } from "./expression"; -import { Expression } from "./expression-interfaces"; +import OperatorToken from "./OperatorToken"; +import { ScalarToken } from "./expression"; +import { ExpressionToken } from "./expression-interfaces"; import { type } from "os"; import { InputType } from "zlib"; import exp from "constants"; diff --git a/src/expression/ListOfNumbersExpression.test.ts b/src/expression/ListOfNumbersExpression.test.ts index 71c0a2a..5cb1d09 100644 --- a/src/expression/ListOfNumbersExpression.test.ts +++ b/src/expression/ListOfNumbersExpression.test.ts @@ -1,7 +1,7 @@ -import ScalarExpression from "./ScalarExpression"; +import ScalarToken from "./ScalarToken"; import ListOfNumbersExpression from "./ListOfNumbersExpression"; it('calculates max bits length', () => { - var expr = new ListOfNumbersExpression("10 0xabef 0b01010", [ScalarExpression.parse("10"), ScalarExpression.parse("0xabef"), ScalarExpression.parse("0b01010")]) + var expr = new ListOfNumbersExpression("10 0xabef 0b01010", [ScalarToken.parse("10"), ScalarToken.parse("0xabef"), ScalarToken.parse("0b01010")]) expect(expr.maxBitsLength).toBe(16); }); diff --git a/src/expression/ListOfNumbersExpression.ts b/src/expression/ListOfNumbersExpression.ts index 6cd5a9b..064492d 100644 --- a/src/expression/ListOfNumbersExpression.ts +++ b/src/expression/ListOfNumbersExpression.ts @@ -1,13 +1,13 @@ import calc from "../core/calc"; -import ScalarExpression from "./ScalarExpression"; -import { ExpressionInput, Expression } from "./expression-interfaces"; +import ScalarToken from "./ScalarToken"; +import { Expression, ExpressionToken } from "./expression-interfaces"; -export default class ListOfNumbersExpression implements ExpressionInput { - children: ScalarExpression[]; +export default class ListOfNumbersExpression implements Expression { + children: ScalarToken[]; expressionString: string; maxBitsLength: number; - constructor(expressionString: string, numbers: ScalarExpression[]) { + constructor(expressionString: string, numbers: ScalarToken[]) { this.expressionString = expressionString; this.children = numbers; this.maxBitsLength = numbers.map(n => calc.numberOfBitsDisplayed(n.value)).reduce((n , c) => n >= c ? n : c, 0); diff --git a/src/expression/OperatorExpression.test.ts b/src/expression/OperatorExpression.test.ts index a4decc2..ea30f6e 100644 --- a/src/expression/OperatorExpression.test.ts +++ b/src/expression/OperatorExpression.test.ts @@ -1,25 +1,25 @@ -import ScalarExpression from "./ScalarExpression"; -import OperatorExpression from './OperatorExpression'; +import ScalarToken from "./ScalarToken"; +import OperatorToken from './OperatorToken'; import { INT_MAX_VALUE } from "../core/const"; it('can apply ~ operand', () => { - var op = new ScalarExpression(10, 'dec'); - var expr = new OperatorExpression(op, "~"); + var op = new ScalarToken(10, 'dec'); + var expr = new OperatorToken(op, "~"); var result = expr.evaluate(); expect(result.value).toBe(-11); expect(result.base).toBe('dec'); }); it('can apply & operand', () => { - var op1 = new ScalarExpression(3, 'dec'); - var op2 = new ScalarExpression(4, 'dec'); - var expr = new OperatorExpression(op1, "|"); + var op1 = new ScalarToken(3, 'dec'); + var op2 = new ScalarToken(4, 'dec'); + var expr = new OperatorToken(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), "^")) + expect(() => new OperatorToken(new ScalarToken(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/OperatorToken.ts similarity index 74% rename from src/expression/OperatorExpression.ts rename to src/expression/OperatorToken.ts index 7909508..093e2e0 100644 --- a/src/expression/OperatorExpression.ts +++ b/src/expression/OperatorToken.ts @@ -1,18 +1,18 @@ import { INT_MAX_VALUE } from '../core/const'; import formatter from '../core/formatter'; -import ScalarExpression from './ScalarExpression'; -import { Expression } from './expression-interfaces'; +import ScalarToken from './ScalarToken'; +import { ExpressionToken } from './expression-interfaces'; -export default class OperatorExpression implements Expression { - operand: Expression; +export default class OperatorToken implements ExpressionToken { + operand: ExpressionToken; operator: string; isOperator: boolean; isShiftExpression: boolean; isNotExpression: boolean; - constructor(operand : Expression, operator : string) { + constructor(operand : ExpressionToken, operator : string) { - if(operand instanceof ScalarExpression) { + if(operand instanceof ScalarToken) { const o = operand.getUnderlyingScalarOperand(); if(Math.abs(o.value) > INT_MAX_VALUE) { const n = formatter.numberToString(o.value, o.base); @@ -27,8 +27,8 @@ export default class OperatorExpression implements Expression { this.isNotExpression = this.operator === '~'; } - evaluate(operand?: ScalarExpression) : ScalarExpression { - if (operand instanceof OperatorExpression) { + evaluate(operand?: ScalarToken) : ScalarToken { + if (operand instanceof OperatorToken) { throw new Error('value shouldnt be expression'); } @@ -44,10 +44,10 @@ export default class OperatorExpression implements Expression { str = operand.value + this.operator + evaluatedOperand.value; } - return ScalarExpression.create(eval(str), evaluatedOperand.base); + return ScalarToken.create(eval(str), evaluatedOperand.base); } - getUnderlyingScalarOperand() : ScalarExpression { + getUnderlyingScalarOperand() : ScalarToken { return this.operand.getUnderlyingScalarOperand(); } diff --git a/src/expression/ScalarExpression.test.ts b/src/expression/ScalarExpression.test.ts index d8b2f12..c4b0a44 100644 --- a/src/expression/ScalarExpression.test.ts +++ b/src/expression/ScalarExpression.test.ts @@ -1,19 +1,19 @@ -import ScalarExpression from './ScalarExpression'; +import ScalarToken from './ScalarToken'; it('parsed from dec string', () => { - var op = ScalarExpression.parse('123'); + var op = ScalarToken.parse('123'); expect(op.base).toBe('dec'); expect(op.value).toBe(123); }); it('parsed from bin string', () => { - var op = ScalarExpression.parse('0b10'); + var op = ScalarToken.parse('0b10'); expect(op.base).toBe('bin'); expect(op.value).toBe(2); }); it('parsed from hex string', () => { - var op = ScalarExpression.parse('0x10'); + var op = ScalarToken.parse('0x10'); expect(op.base).toBe('hex'); expect(op.value).toBe(16); }); diff --git a/src/expression/ScalarExpression.ts b/src/expression/ScalarToken.ts similarity index 65% rename from src/expression/ScalarExpression.ts rename to src/expression/ScalarToken.ts index 2aa9e59..07cdb87 100644 --- a/src/expression/ScalarExpression.ts +++ b/src/expression/ScalarToken.ts @@ -1,5 +1,5 @@ import {numberParser} from './numberParser'; -import { Expression as Expression } from './expression-interfaces'; +import { ExpressionToken as ExpressionToken } from './expression-interfaces'; import { NumberBase } from '../core/formatter'; import { INT_MAX_VALUE } from '../core/const'; @@ -7,7 +7,7 @@ var globalId : number = 1; // Represents scalar numeric value -export default class ScalarExpression implements Expression { +export default class ScalarToken implements ExpressionToken { id: number; value: number; base: NumberBase; @@ -25,21 +25,21 @@ export default class ScalarExpression implements Expression { this.value = value; } - evaluate() : ScalarExpression { + evaluate() : ScalarToken { return this; } - getUnderlyingScalarOperand() : ScalarExpression { + getUnderlyingScalarOperand() : ScalarToken { return this } static create(value : number, base? : NumberBase) { - return new ScalarExpression(value, base || "dec"); + return new ScalarToken(value, base || "dec"); }; - static parse(input: string) : ScalarExpression { + static parse(input: string) : ScalarToken { - var parsed = ScalarExpression.tryParse(input); + var parsed = ScalarToken.tryParse(input); if(parsed == null) { throw new Error(input + " is not a valid number"); @@ -48,7 +48,7 @@ export default class ScalarExpression implements Expression { return parsed; } - static tryParse(input: string) : ScalarExpression | null { + static tryParse(input: string) : ScalarToken | null { var parsed = numberParser.parse(input); @@ -56,7 +56,7 @@ export default class ScalarExpression implements Expression { return null; } - return new ScalarExpression(parsed.value, parsed.base); + return new ScalarToken(parsed.value, parsed.base); } } \ No newline at end of file diff --git a/src/expression/components/BitwiseResultView.tsx b/src/expression/components/BitwiseResultView.tsx index 1b5f3ec..c24d99c 100644 --- a/src/expression/components/BitwiseResultView.tsx +++ b/src/expression/components/BitwiseResultView.tsx @@ -2,11 +2,11 @@ import React from 'react'; import formatter from '../../core/formatter'; import BinaryStringView, { FlipBitEventArg } from '../../core/components/BinaryString'; import BitwiseResultViewModel from './BitwiseResultViewModel'; -import { ExpressionInput, Expression } from '../expression-interfaces'; -import { OperatorExpression, ScalarExpression } from '../expression'; +import { Expression, ExpressionToken } from '../expression-interfaces'; +import { OperatorToken, ScalarToken } from '../expression'; type BitwiseOperationExpressionViewProps = { - expression: ExpressionInput; + expression: Expression; emphasizeBytes: boolean; } @@ -59,7 +59,7 @@ type ExpressionRowProps = { maxNumberOfBits: number, emphasizeBytes: boolean, allowFlipBits: boolean, - expressionItem: Expression, + expressionItem: ExpressionToken, onBitFlipped: any } @@ -71,7 +71,7 @@ class ExpressionRow extends React.Component { render() { const { sign, css, maxNumberOfBits, emphasizeBytes, allowFlipBits } = this.props; - return + return {sign} {this.getLabel()} @@ -95,7 +95,7 @@ class ExpressionRow extends React.Component { // For expressions like |~2 // TODO: find a better way... if(this.props.expressionItem.isOperator) { - const ex = this.props.expressionItem as OperatorExpression; + const ex = this.props.expressionItem as OperatorToken; return ex.operator + this.getLabelString(ex.getUnderlyingScalarOperand()); } @@ -105,7 +105,7 @@ class ExpressionRow extends React.Component { getAlternative() { if(this.props.expressionItem.isOperator) { - const ex = this.props.expressionItem as OperatorExpression; + const ex = this.props.expressionItem as OperatorToken; const res = ex.evaluate(); return formatter.numberToString(res.value, res.base); @@ -116,7 +116,7 @@ class ExpressionRow extends React.Component { return formatter.numberToString(v.value, altBase); } - getLabelString (op: ScalarExpression) : string { + getLabelString (op: ScalarToken) : string { return formatter.numberToString(op.value, op.base == 'bin' ? 'dec' : op.base); } diff --git a/src/expression/components/BitwiseResultViewModel.ts b/src/expression/components/BitwiseResultViewModel.ts index 720ce44..82830c3 100644 --- a/src/expression/components/BitwiseResultViewModel.ts +++ b/src/expression/components/BitwiseResultViewModel.ts @@ -1,5 +1,5 @@ -import { ScalarExpression, ListOfNumbersExpression, BitwiseOperationExpression, OperatorExpression } from '../expression'; -import { Expression, ExpressionInput } from '../expression-interfaces'; +import { ScalarToken, ListOfNumbersExpression, BitwiseOperationExpression, OperatorToken } from '../expression'; +import { ExpressionToken, Expression } from '../expression-interfaces'; import calc from '../../core/calc'; import formatter from '../../core/formatter'; @@ -8,10 +8,10 @@ type Config = { allowFlipBits: boolean; } -type ExpressionItemModel = { +type ExpressionRowModel = { sign: string; css: string; - expression: Expression; + expression: ExpressionToken; allowFlipBits: boolean; label: string; } @@ -19,7 +19,7 @@ type ExpressionItemModel = { export default class BitwiseResultViewModel { emphasizeBytes: boolean; - items: ExpressionItemModel[]; + items: ExpressionRowModel[]; maxNumberOfBits: number; allowFlipBits: boolean; @@ -43,17 +43,17 @@ export default class BitwiseResultViewModel { i = 0, len = expr.children.length, ex, m = new BitwiseResultViewModel(config); - var prev : ScalarExpression | null = null; + var prev : ScalarToken | null = null; for (;i ScalarExpression; - evaluate(operand? : ScalarExpression): ScalarExpression; + getUnderlyingScalarOperand: () => ScalarToken; + evaluate(operand? : ScalarToken): ScalarToken; } diff --git a/src/expression/expression.test.ts b/src/expression/expression.test.ts index bf7eb48..59cb084 100644 --- a/src/expression/expression.test.ts +++ b/src/expression/expression.test.ts @@ -1,4 +1,4 @@ -import { parser, ListOfNumbersExpression, BitwiseOperationExpression, ScalarExpression, OperatorExpression } from "./expression"; +import { parser, ListOfNumbersExpression, BitwiseOperationExpression, ScalarToken, OperatorToken } from "./expression"; describe("expression parser", () => { @@ -36,16 +36,16 @@ describe("expression parser", () => { const first = result.children[0]; const second = result.children[1]; - expect(first).toBeInstanceOf(ScalarExpression); + expect(first).toBeInstanceOf(ScalarToken); - expect((first as ScalarExpression).value).toBe(1); + expect((first as ScalarToken).value).toBe(1); - expect(second).toBeInstanceOf(OperatorExpression); - var secondOp = second as OperatorExpression; + expect(second).toBeInstanceOf(OperatorToken); + var secondOp = second as OperatorToken; expect(secondOp.operator).toBe("^"); - expect(secondOp.operand).toBeInstanceOf(ScalarExpression); - var childOp = secondOp.operand as ScalarExpression; + expect(secondOp.operand).toBeInstanceOf(ScalarToken); + var childOp = secondOp.operand as ScalarToken; expect(childOp.value).toBe(2); }); diff --git a/src/expression/expression.ts b/src/expression/expression.ts index 9153692..9f0bd59 100644 --- a/src/expression/expression.ts +++ b/src/expression/expression.ts @@ -1,18 +1,18 @@ -import ScalarExpression from './ScalarExpression'; -import OperatorExpression from './OperatorExpression' +import ScalarToken from './ScalarToken'; +import OperatorToken from './OperatorToken' import ListOfNumbersExpression from './ListOfNumbersExpression'; import BitwiseOperationExpression from './BitwiseOperationExpression'; -import { ExpressionInput, Expression } from './expression-interfaces'; +import { Expression, ExpressionToken } from './expression-interfaces'; import { NumberBase } from '../core/formatter'; -export { default as ScalarExpression } from './ScalarExpression'; -export { default as OperatorExpression } from './OperatorExpression'; +export { default as ScalarToken } from './ScalarToken'; +export { default as OperatorToken } from './OperatorToken'; export { default as ListOfNumbersExpression } from './ListOfNumbersExpression'; export { default as BitwiseOperationExpression } from './BitwiseOperationExpression'; interface IExpressionParserFactory { canCreate: (input: string) => boolean; - create: (input: string) => ExpressionInput; + create: (input: string) => Expression; }; class ExpressionParser { @@ -32,7 +32,7 @@ class ExpressionParser { return false; }; - parse (input: string) : ExpressionInput | null { + parse (input: string) : Expression | null { var trimmed = input.replace(/^\s+|\s+$/, ''); var i = 0, l = this.factories.length, factory; @@ -47,12 +47,12 @@ class ExpressionParser { return null; }; - parseOperand (input : string) : ScalarExpression { - return ScalarExpression.parse(input); + parseOperand (input : string) : ScalarToken { + return ScalarToken.parse(input); }; - createOperand (number : number, base : NumberBase) : ScalarExpression { - return ScalarExpression.create(number, base); + createOperand (number : number, base : NumberBase) : ScalarToken { + return ScalarToken.create(number, base); }; addFactory (factory: IExpressionParserFactory) { @@ -70,16 +70,16 @@ class ListOfNumbersExpressionFactory implements IExpressionParserFactory return input.split(' ') .filter(p => p.length > 0) - .map(p => ScalarExpression.tryParse(p)) + .map(p => ScalarToken.tryParse(p)) .filter(n => n == null) .length == 0; }; - create (input : string) : ExpressionInput { + create (input : string) : Expression { const numbers = input.split(' ') .filter(p => p.length > 0) - .map(m => ScalarExpression.parse(m)); + .map(m => ScalarToken.parse(m)); return new ListOfNumbersExpression(input, numbers); } @@ -99,9 +99,9 @@ class BitwiseOperationExpressionFactory implements IExpressionParserFactory { return this.fullRegex.test(this.normalizeString(input)); }; - create (input: string) : ExpressionInput { + create (input: string) : Expression { var m : RegExpExecArray | null; - const operands : Expression[] = []; + const operands : ExpressionToken[] = []; const normalizedString = this.normalizeString(input); this.regex.lastIndex = 0; @@ -113,23 +113,23 @@ class BitwiseOperationExpressionFactory implements IExpressionParserFactory { return new BitwiseOperationExpression(normalizedString, operands) }; - parseMatch (m:any): Expression { + parseMatch (m:any): ExpressionToken { var input = m[0], operator = m[1], num = m[2]; var parsed = null; if(num.indexOf('~') == 0) { - parsed = new OperatorExpression(ScalarExpression.parse(num.substring(1)), '~'); + parsed = new OperatorToken(ScalarToken.parse(num.substring(1)), '~'); } else { - parsed = ScalarExpression.parse(num); + parsed = ScalarToken.parse(num); } if(operator == null) { - return parsed as OperatorExpression; + return parsed as OperatorToken; } else { - return new OperatorExpression(parsed as ScalarExpression, operator); + return new OperatorToken(parsed as ScalarToken, operator); } }; diff --git a/src/networking/components/IpAddressView.tsx b/src/networking/components/IpAddressView.tsx index 68df2c3..71cd176 100644 --- a/src/networking/components/IpAddressView.tsx +++ b/src/networking/components/IpAddressView.tsx @@ -14,7 +14,7 @@ export class IpAddressView extends React.Component render() { return - {this.props.ipAddresses.map((ip, i) => + {this.props.ipAddresses.map((ip, i) =>
{ip.toString()} {this.bin(ip.firstByte, 1, ip)}.