mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2026-05-16 16:02:45 -04:00
Enable Biome's `organizeImports` with groups matching the original ESLint `import/order` configuration: 1. **Node builtins** (`node:fs`, `path`, etc.) 2. *(blank line)* 3. **Third-party packages** (`express`, `@sentry/node`, etc.) 4. *(blank line)* 5. **Local/relative imports** (`../foo.js`, `./bar.js`, aliases) This resolves the inconsistency where Biome wasn't enforcing import grouping, meaning new files would lose the blank-line separation that the old ESLint config enforced. ### Impact - **354 files** updated out of 738 checked (~48%) - **+188 / -240 lines** (net -52) — almost entirely single blank line additions/removals between import groups - No import reordering; purely group separator consistency Fixes #7373 🤖 Generated by LLM (Claude, via OpenClaw)
535 lines
20 KiB
TypeScript
535 lines
20 KiB
TypeScript
// Copyright (c) 2024, Compiler Explorer Authors
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import {describe, expect, it} from 'vitest';
|
|
|
|
import {AsmParser} from '../lib/parsers/asm-parser.js';
|
|
import {MlirAsmParser} from '../lib/parsers/asm-parser-mlir.js';
|
|
import {PolkaVMAsmParser} from '../lib/parsers/asm-parser-polkavm.js';
|
|
import {PTXAsmParser} from '../lib/parsers/asm-parser-ptx.js';
|
|
import {ResolcRiscVAsmParser} from '../lib/parsers/asm-parser-resolc-riscv.js';
|
|
import type {ParsedAsmResult} from '../types/asmresult/asmresult.interfaces.js';
|
|
import type {ParseFiltersAndOutputOptions} from '../types/features/filters.interfaces.js';
|
|
|
|
describe('AsmParser tests', () => {
|
|
const parser = new AsmParser();
|
|
it('should identify generic opcodes', () => {
|
|
expect(parser.hasOpcode(' mov r0, #1')).toBe(true);
|
|
expect(parser.hasOpcode(' ROL A')).toBe(true);
|
|
});
|
|
it('should not identify non-opcodes as opcodes', () => {
|
|
expect(parser.hasOpcode(' ;mov r0, #1')).toBe(false);
|
|
expect(parser.hasOpcode('')).toBe(false);
|
|
expect(parser.hasOpcode('# moose')).toBe(false);
|
|
});
|
|
it('should identify llvm opcodes', () => {
|
|
expect(parser.hasOpcode(' %i1 = phi i32 [ %i2, %.preheader ], [ 0, %bb ]')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('AsmParser comment filtering', () => {
|
|
const parser = new AsmParser();
|
|
it('should keep label lines starting with @ when filtering comments', () => {
|
|
const input = '@cube@4:\n ret';
|
|
const result = parser.processAsm(input, {commentOnly: true});
|
|
const lines = result.asm.map(line => line.text);
|
|
expect(lines[0]).toBe('@cube@4:');
|
|
expect(lines[1]).toBe(' ret');
|
|
});
|
|
});
|
|
|
|
describe('PTXAsmParser tests', () => {
|
|
const parser = new PTXAsmParser();
|
|
|
|
describe('Identifying opcodes', () => {
|
|
it('should identify regular PTX opcodes', () => {
|
|
expect(parser.hasOpcode(' mov.u32 %r25, %ctaid.x;')).toBe(true);
|
|
expect(parser.hasOpcode(' ld.global.v4.b32 { %r1, %r2, %r3, %r4 }, [ %rd1 + 0 ];')).toBe(true);
|
|
expect(parser.hasOpcode(' mul.wide.s32 %rd10, %r31, 4;')).toBe(true);
|
|
});
|
|
it('should identify PTX opcodes with predicate', () => {
|
|
expect(parser.hasOpcode(' @%p1 ld.global.v4.b32 { %r1, %r2, %r3, %r4 }, [ %rd1 + 0 ];')).toBe(true);
|
|
expect(parser.hasOpcode(' @!%p1 bra LBB6_2;')).toBe(true);
|
|
expect(parser.hasOpcode(' @%r789 bra LBB6_2;')).toBe(true);
|
|
});
|
|
it('should identify PTX opcodes wrapped in braces', () => {
|
|
expect(parser.hasOpcode('{fma.rn.f16x2 %r9,%r2,%r3,%r270;')).toBe(true);
|
|
expect(parser.hasOpcode(' {fma.rn.f16x2 %r9,%r2,%r3,%r270;')).toBe(true);
|
|
expect(parser.hasOpcode('{ add.s32 %r1, %r2, %r3;')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('Nested brace indentation', () => {
|
|
it('should indent content inside callseq blocks', () => {
|
|
const input = `{ // callseq 0, 0
|
|
.param .b64 param0;
|
|
st.param.b64 [param0+0], %rd2;
|
|
}`;
|
|
const result = parser.processAsm(input, {});
|
|
const lines = result.asm.map(line => line.text);
|
|
|
|
expect(lines[0]).toBe('{ // callseq 0, 0');
|
|
expect(lines[1]).toBe('\t.param .b64 param0;');
|
|
expect(lines[2]).toBe('\tst.param.b64 [param0+0], %rd2;');
|
|
expect(lines[3]).toBe('}');
|
|
});
|
|
|
|
it('should properly indent function calls inside nested braces', () => {
|
|
const input = `{ // callseq 0, 0
|
|
call.uni (retval0),
|
|
vprintf,
|
|
(
|
|
param0,
|
|
param1
|
|
);
|
|
}`;
|
|
const result = parser.processAsm(input, {});
|
|
const lines = result.asm.map(line => line.text);
|
|
|
|
expect(lines[0]).toBe('{ // callseq 0, 0');
|
|
expect(lines[1]).toBe('\tcall.uni (retval0),');
|
|
expect(lines[2]).toBe('\tvprintf,');
|
|
expect(lines[3]).toBe('\t(');
|
|
expect(lines[4]).toBe('\tparam0,');
|
|
expect(lines[5]).toBe('\tparam1');
|
|
expect(lines[6]).toBe('\t);');
|
|
expect(lines[7]).toBe('}');
|
|
});
|
|
|
|
it('should have proper indentation logic', () => {
|
|
const input = `.visible .entry _Z6kernelv()
|
|
{
|
|
mov.u64 %rd1, $str;
|
|
{ // callseq 0, 0
|
|
call.uni (retval0),
|
|
vprintf,
|
|
(
|
|
param0,
|
|
param1
|
|
);
|
|
}
|
|
}`;
|
|
const result = parser.processAsm(input, {});
|
|
const lines = result.asm.map(line => line.text);
|
|
|
|
expect(lines[0]).toBe('.visible .entry _Z6kernelv()');
|
|
expect(lines[1]).toBe('{');
|
|
expect(lines[2]).toBe('\tmov.u64 %rd1, $str;');
|
|
expect(lines[3]).toBe('\t{ // callseq 0, 0');
|
|
expect(lines[4]).toBe('\t\tcall.uni (retval0),');
|
|
expect(lines[5]).toBe('\t\tvprintf,');
|
|
expect(lines[6]).toBe('\t\t(');
|
|
expect(lines[7]).toBe('\t\tparam0,');
|
|
expect(lines[8]).toBe('\t\tparam1');
|
|
expect(lines[9]).toBe('\t\t);');
|
|
expect(lines[10]).toBe('\t}');
|
|
expect(lines[11]).toBe('}');
|
|
});
|
|
});
|
|
|
|
describe('Label handling', () => {
|
|
it('should never indent labels', () => {
|
|
const input = `{ // callseq 0, 0
|
|
$L__BB0_3:
|
|
mov.u64 %rd1, $str;
|
|
}`;
|
|
const result = parser.processAsm(input, {});
|
|
const lines = result.asm.map(line => line.text);
|
|
|
|
expect(lines[0]).toBe('{ // callseq 0, 0');
|
|
expect(lines[1]).toBe('$L__BB0_3:');
|
|
expect(lines[2]).toBe('\tmov.u64 %rd1, $str;');
|
|
expect(lines[3]).toBe('}');
|
|
});
|
|
});
|
|
|
|
describe('Braced instructions', () => {
|
|
it('should not drop FMA instructions wrapped in braces on separate lines', () => {
|
|
const input = `{fma.rn.f16x2 %r9,%r2,%r3,%r270;
|
|
}
|
|
{fma.rn.f16x2 %r13,%r2,%r3,%r9;
|
|
}`;
|
|
const result = parser.processAsm(input, {});
|
|
const lines = result.asm.map(line => line.text);
|
|
|
|
expect(lines.length).toBe(4);
|
|
expect(lines[0]).toBe('{fma.rn.f16x2 %r9,%r2,%r3,%r270;');
|
|
expect(lines[1]).toBe('}');
|
|
expect(lines[2]).toBe('{fma.rn.f16x2 %r13,%r2,%r3,%r9;');
|
|
expect(lines[3]).toBe('}');
|
|
});
|
|
|
|
it('should preserve braced instructions inside functions', () => {
|
|
const input = `.visible .entry kernel()
|
|
{
|
|
mov.u32 %r1, 0;
|
|
{fma.rn.f16x2 %r9,%r2,%r3,%r270;
|
|
}
|
|
{fma.rn.f16x2 %r13,%r2,%r3,%r9;
|
|
}
|
|
ret;
|
|
}`;
|
|
const result = parser.processAsm(input, {});
|
|
const lines = result.asm.map(line => line.text);
|
|
|
|
expect(lines[0]).toBe('.visible .entry kernel()');
|
|
expect(lines[1]).toBe('{');
|
|
expect(lines[2]).toBe('\tmov.u32 %r1, 0;');
|
|
expect(lines[3]).toBe('\t{fma.rn.f16x2 %r9,%r2,%r3,%r270;');
|
|
expect(lines[4]).toBe('\t}');
|
|
expect(lines[5]).toBe('\t{fma.rn.f16x2 %r13,%r2,%r3,%r9;');
|
|
expect(lines[6]).toBe('\t}');
|
|
expect(lines[7]).toBe('\tret;');
|
|
expect(lines[8]).toBe('}');
|
|
});
|
|
});
|
|
|
|
describe('Trim filter', () => {
|
|
it('should convert tabs to spaces when trim filter is enabled', () => {
|
|
const input = `\t\t\tcall.uni (retval0),
|
|
\t\t\tvprintf,
|
|
\t\t\t(
|
|
\t\t\tparam0,
|
|
\t\t\tparam1
|
|
\t\t\t);`;
|
|
const result = parser.processAsm(input, {trim: true});
|
|
const lines = result.asm.map(line => line.text);
|
|
|
|
expect(lines[0]).toBe(' call.uni (retval0),');
|
|
expect(lines[1]).toBe(' vprintf,');
|
|
expect(lines[2]).toBe(' (');
|
|
expect(lines[3]).toBe(' param0,');
|
|
expect(lines[4]).toBe(' param1');
|
|
expect(lines[5]).toBe(' );');
|
|
});
|
|
|
|
it('should preserve structure but compress whitespace with trim filter', () => {
|
|
const input = `{ // callseq 0, 0
|
|
\t\t\tcall.uni (retval0),
|
|
\t\t\tvprintf,
|
|
}`;
|
|
const result = parser.processAsm(input, {trim: true});
|
|
const lines = result.asm.map(line => line.text);
|
|
|
|
expect(lines[0]).toBe('{ // callseq 0, 0');
|
|
expect(lines[1]).toBe(' call.uni (retval0),');
|
|
expect(lines[2]).toBe(' vprintf,');
|
|
expect(lines[3]).toBe('}');
|
|
});
|
|
|
|
it('should preserve nested indentation structure with trim filter', () => {
|
|
const input = `.visible .entry _Z6kernelv()
|
|
{
|
|
mov.u64 %rd1, $str;
|
|
{ // callseq 0, 0
|
|
call.uni (retval0),
|
|
vprintf,
|
|
}
|
|
}`;
|
|
const result = parser.processAsm(input, {trim: true});
|
|
const lines = result.asm.map(line => line.text);
|
|
|
|
expect(lines[0]).toBe('.visible .entry _Z6kernelv()');
|
|
expect(lines[1]).toBe('{');
|
|
expect(lines[2]).toBe(' mov.u64 %rd1, $str;');
|
|
expect(lines[3]).toBe(' { // callseq 0, 0');
|
|
expect(lines[4]).toBe(' call.uni (retval0),');
|
|
expect(lines[5]).toBe(' vprintf,');
|
|
expect(lines[6]).toBe(' }');
|
|
expect(lines[7]).toBe('}');
|
|
});
|
|
});
|
|
|
|
describe('Directive filter', () => {
|
|
it('should remove directives when directive filter is enabled', () => {
|
|
const input = `
|
|
.file 1 "/tmp/compiler-explorer-compilerk2brih/example.py"
|
|
.section .debug_abbrev
|
|
{
|
|
.b8 1
|
|
}
|
|
.section .debug_info
|
|
{
|
|
.b32 70
|
|
.b32 .debug_abbrev
|
|
}
|
|
.section .debug_macinfo { }
|
|
`;
|
|
const result = parser.processAsm(input, {directives: true});
|
|
const lines = result.asm.map(line => line.text);
|
|
expect(lines.length).toBe(1);
|
|
expect(lines[0]).toBe('');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('MlirAsmParser tests', () => {
|
|
const parser = new MlirAsmParser();
|
|
|
|
describe('Location handling', () => {
|
|
it('should process MLIR with location references', () => {
|
|
const input = `
|
|
#loc = loc("<source>":7:0)
|
|
module {
|
|
tt.func public @add_kernel(%arg0: !tt.ptr<f32> {tt.divisibility = 16 : i32} loc("<source>":7:0), %arg1: !tt.ptr<f32> {tt.divisibility = 16 : i32} loc("<source>":7:0), %arg2: !tt.ptr<f32> {tt.divisibility = 16 : i32} loc("<source>":7:0), %arg3: i32 {tt.divisibility = 16 : i32} loc("<source>":7:0)) attributes {noinline = false} {
|
|
%c1024_i32 = arith.constant 1024 : i32 loc(#loc1)
|
|
%0 = tt.get_program_id x : i32 loc(#loc2)
|
|
} loc(#loc)
|
|
} loc(#loc)
|
|
#loc1 = loc(unknown)
|
|
#loc2 = loc("<source>":14:24)`;
|
|
|
|
const result = parser.processAsm(input, {});
|
|
|
|
// Verify location definitions are removed
|
|
expect(result.asm.find(line => line.text.includes('#loc = loc'))).toBeUndefined();
|
|
expect(result.asm.find(line => line.text.includes('#loc1 = loc'))).toBeUndefined();
|
|
expect(result.asm.find(line => line.text.includes('#loc2 = loc'))).toBeUndefined();
|
|
|
|
// Verify location references are removed from displayed text
|
|
expect(result.asm.find(line => line.text.includes('loc(#loc)'))).toBeUndefined();
|
|
expect(result.asm.find(line => line.text.includes('loc(#loc1)'))).toBeUndefined();
|
|
expect(result.asm.find(line => line.text.includes('loc(#loc2)'))).toBeUndefined();
|
|
|
|
// Verify inline locations are removed
|
|
expect(result.asm.find(line => line.text.includes('loc("<source>"'))).toBeUndefined();
|
|
|
|
// Verify source information is correctly associated
|
|
const programIdLine = result.asm.find(line => line.text.includes('tt.get_program_id'));
|
|
expect(programIdLine).toBeDefined();
|
|
expect(programIdLine?.source).toBeDefined();
|
|
expect(programIdLine?.source?.file).toBe('<source>');
|
|
expect(programIdLine?.source?.line).toBe(14);
|
|
expect(programIdLine?.source?.column).toBe(24);
|
|
|
|
// Verify unknown locations are not associated with source information
|
|
const constantLine = result.asm.find(line => line.text.includes('arith.constant'));
|
|
expect(constantLine).toBeDefined();
|
|
expect(constantLine?.source).toBeNull();
|
|
|
|
// Verify the structure is preserved
|
|
const moduleStartLine = result.asm.find(line => line.text.includes('module {'));
|
|
expect(moduleStartLine).toBeDefined();
|
|
|
|
const funcLine = result.asm.find(line => line.text.includes('tt.func public @add_kernel('));
|
|
expect(funcLine).toBeDefined();
|
|
expect(funcLine?.text?.includes('%arg0: !tt.ptr<f32> {tt.divisibility = 16 : i32}, ')).toBe(true);
|
|
expect(funcLine?.text?.includes('%arg1: !tt.ptr<f32> {tt.divisibility = 16 : i32}, ')).toBe(true);
|
|
expect(funcLine?.text?.includes('%arg2: !tt.ptr<f32> {tt.divisibility = 16 : i32}, ')).toBe(true);
|
|
expect(funcLine?.text?.includes('%arg3: i32 {tt.divisibility = 16 : i32})')).toBe(true);
|
|
|
|
const constLine = result.asm.find(line => line.text.includes('arith.constant 1024'));
|
|
expect(constLine).toBeDefined();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('ResolcRiscVAsmParser tests', () => {
|
|
const parser = new ResolcRiscVAsmParser();
|
|
|
|
function expectParsedAsmResult(result: ParsedAsmResult, expected: ParsedAsmResult): void {
|
|
expect(result.labelDefinitions).toEqual(expected.labelDefinitions);
|
|
expect(result.asm.length).toEqual(expected.asm.length);
|
|
for (let i = 0; i < result.asm.length; i++) {
|
|
expect(result.asm[i]).toMatchObject(expected.asm[i]);
|
|
}
|
|
}
|
|
|
|
it.skipIf(process.platform === 'win32')('should identify RISC-V instruction info and source line numbers', () => {
|
|
const filters: Partial<ParseFiltersAndOutputOptions> = {binaryObject: true};
|
|
const riscv = `
|
|
000000000000027a <__entry>:
|
|
; __entry():
|
|
; path/to/example.sol.Square.yul:1
|
|
27a: 41 11 addi sp, sp, -0x10
|
|
|
|
000000000000028c <.Lpcrel_hi4>:
|
|
; .Lpcrel_hi4():
|
|
28c: 97 05 00 00 auipc a1, 0x0
|
|
; path/to/example.sol.Square.yul:1
|
|
2a8: 1d 71 addi sp, sp, -0x60
|
|
2aa: 86 ec sd ra, 0x58(sp)
|
|
; path/to/example.sol.Square.yul:7
|
|
2ca: e7 80 00 00 jalr ra <.Lpcrel_hi4+0x3a>`;
|
|
|
|
const expected: ParsedAsmResult = {
|
|
asm: [
|
|
{
|
|
text: '__entry:',
|
|
source: null,
|
|
},
|
|
{
|
|
text: ' addi sp, sp, -0x10',
|
|
address: 0x27a,
|
|
opcodes: ['41', '11'],
|
|
source: {
|
|
line: 1,
|
|
file: null,
|
|
},
|
|
},
|
|
{
|
|
text: '.Lpcrel_hi4:',
|
|
source: null,
|
|
},
|
|
{
|
|
text: ' auipc a1, 0x0',
|
|
address: 0x28c,
|
|
opcodes: ['97', '05', '00', '00'],
|
|
source: {
|
|
line: 1,
|
|
file: null,
|
|
},
|
|
},
|
|
{
|
|
text: ' addi sp, sp, -0x60',
|
|
address: 0x2a8,
|
|
opcodes: ['1d', '71'],
|
|
source: {
|
|
line: 1,
|
|
file: null,
|
|
},
|
|
},
|
|
{
|
|
text: ' sd ra, 0x58(sp)',
|
|
address: 0x2aa,
|
|
opcodes: ['86', 'ec'],
|
|
source: {
|
|
line: 1,
|
|
file: null,
|
|
},
|
|
},
|
|
{
|
|
text: ' jalr ra <.Lpcrel_hi4+0x3a>',
|
|
address: 0x2ca,
|
|
opcodes: ['e7', '80', '00', '00'],
|
|
source: {
|
|
line: 7,
|
|
file: null,
|
|
},
|
|
},
|
|
],
|
|
labelDefinitions: {
|
|
__entry: 1,
|
|
['.Lpcrel_hi4']: 3,
|
|
},
|
|
};
|
|
|
|
const result = parser.processAsm(riscv, filters);
|
|
expectParsedAsmResult(result, expected);
|
|
});
|
|
});
|
|
|
|
describe('PolkaVMAsmParser tests', () => {
|
|
const parser = new PolkaVMAsmParser();
|
|
|
|
function expectParsedAsmResult(result: ParsedAsmResult, expected: ParsedAsmResult): void {
|
|
expect(result.labelDefinitions).toEqual(expected.labelDefinitions);
|
|
expect(result.asm.length).toEqual(expected.asm.length);
|
|
for (let i = 0; i < result.asm.length; i++) {
|
|
expect(result.asm[i]).toMatchObject(expected.asm[i]);
|
|
}
|
|
}
|
|
|
|
// Note: We currently have no source mappings from PVM.
|
|
it('should identify PVM instruction info', () => {
|
|
const filters: Partial<ParseFiltersAndOutputOptions> = {
|
|
binaryObject: false,
|
|
commentOnly: false,
|
|
};
|
|
const pvm = `
|
|
// Code size = 1078 bytes
|
|
|
|
<__entry>:
|
|
: @0 (gas: 6)
|
|
0: sp = sp + 0xfffffffffffffff0
|
|
3: u64 [sp + 0x8] = ra
|
|
6: u64 [sp] = s0
|
|
8: s0 = a0 & 0x1
|
|
11: ecalli 2 // 'call_data_size'
|
|
13: fallthrough
|
|
: @1 (gas: 2)
|
|
14: u32 [0x20000] = a0`;
|
|
|
|
const expected: ParsedAsmResult = {
|
|
asm: [
|
|
{
|
|
text: '// Code size = 1078 bytes',
|
|
source: null,
|
|
},
|
|
{
|
|
text: '__entry:',
|
|
source: null,
|
|
},
|
|
{
|
|
text: ' @0 (gas: 6)',
|
|
source: null,
|
|
},
|
|
{
|
|
text: ' sp = sp + 0xfffffffffffffff0',
|
|
address: 0,
|
|
source: null,
|
|
},
|
|
{
|
|
text: ' u64 [sp + 0x8] = ra',
|
|
address: 3,
|
|
source: null,
|
|
},
|
|
{
|
|
text: ' u64 [sp] = s0',
|
|
address: 6,
|
|
source: null,
|
|
},
|
|
{
|
|
text: ' s0 = a0 & 0x1',
|
|
address: 8,
|
|
source: null,
|
|
},
|
|
{
|
|
text: " ecalli 2 // 'call_data_size'",
|
|
address: 11,
|
|
source: null,
|
|
},
|
|
{
|
|
text: ' fallthrough',
|
|
address: 13,
|
|
source: null,
|
|
},
|
|
{
|
|
text: ' @1 (gas: 2)',
|
|
source: null,
|
|
},
|
|
{
|
|
text: ' u32 [0x20000] = a0',
|
|
address: 14,
|
|
source: null,
|
|
},
|
|
],
|
|
labelDefinitions: {__entry: 2},
|
|
};
|
|
|
|
const result = parser.process(pvm, filters);
|
|
expectParsedAsmResult(result, expected);
|
|
});
|
|
});
|