Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/bugc/src/evmgen/generation/module.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe("Module.generate", () => {
it("should generate runtime bytecode for module without constructor", () => {
const module: Ir.Module = {
name: "Test",
sourceId: "test",
functions: new Map(),
main: {
name: "main",
Expand Down Expand Up @@ -58,6 +59,7 @@ describe("Module.generate", () => {
it("should generate deployment bytecode with constructor", () => {
const module: Ir.Module = {
name: "Test",
sourceId: "test",
functions: new Map(),
create: {
name: "create",
Expand Down Expand Up @@ -142,6 +144,7 @@ describe("Module.generate", () => {
it("should use optimal PUSH opcodes based on value size", () => {
const module: Ir.Module = {
name: "Test",
sourceId: "test",
functions: new Map(),
main: {
name: "main",
Expand Down Expand Up @@ -228,6 +231,7 @@ describe("Module.generate", () => {

const module: Ir.Module = {
name: "LargeContract",
sourceId: "test",
functions: new Map(),
main: {
name: "main",
Expand Down Expand Up @@ -317,6 +321,7 @@ describe("Module.generate", () => {
it("should calculate deployment size correctly with optimal PUSH opcodes", () => {
const module: Ir.Module = {
name: "Test",
sourceId: "test",
functions: new Map(),
main: {
name: "main",
Expand Down Expand Up @@ -403,6 +408,7 @@ describe("Module.generate", () => {
for (const { value, expectedPushSize } of testCases) {
const module: Ir.Module = {
name: "Test",
sourceId: "test",
functions: new Map(),
main: {
name: "main",
Expand Down
2 changes: 1 addition & 1 deletion packages/bugc/src/evmgen/program-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export function buildProgram(
const contract: Format.Program.Contract = {
name: ir.name,
definition: {
source: { id: "0" }, // TODO: Get actual source ID
source: { id: ir.sourceId },
range: ir.loc ?? { offset: 0, length: 0 },
},
};
Expand Down
3 changes: 3 additions & 0 deletions packages/bugc/src/ir/analysis/formatter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ describe("IrFormatter", () => {
it("should format phi nodes with predecessor labels", () => {
const module: Ir.Module = {
name: "TestModule",
sourceId: "test",
functions: new Map(),
main: {
name: "main",
Expand Down Expand Up @@ -143,6 +144,7 @@ describe("IrFormatter", () => {
it("should format multiple phi nodes in a block", () => {
const module: Ir.Module = {
name: "TestModule",
sourceId: "test",
functions: new Map(),
main: {
name: "main",
Expand Down Expand Up @@ -229,6 +231,7 @@ describe("IrFormatter", () => {
it("should show block predecessors when there are phi nodes", () => {
const module: Ir.Module = {
name: "TestModule",
sourceId: "test",
functions: new Map(),
main: {
name: "main",
Expand Down
2 changes: 2 additions & 0 deletions packages/bugc/src/ir/spec/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import type { Function as IrFunction } from "./function.js";
export interface Module {
/** Program name from 'name' declaration */
name: string;
/** Source identifier for debug info */
sourceId: string;
/** User-defined functions */
functions: Map<string, IrFunction>;
/** Constructor function (optional, for contract creation) */
Expand Down
4 changes: 2 additions & 2 deletions packages/bugc/src/irgen/generate/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ export function* buildModule(

// Build program-level debug context with storage variables
const state: State = yield { type: "peek" };
const sourceId = "0"; // TODO: Get actual source ID
const variables = collectVariablesWithLocations(state, sourceId);
const variables = collectVariablesWithLocations(state, module_.sourceId);
const debugContext =
variables.length > 0
? { variables: variables.map(toVariableContextEntry) }
Expand All @@ -98,6 +97,7 @@ export function* buildModule(
// Return the module, ensuring main exists
const result: Ir.Module = {
name: module_.name,
sourceId: module_.sourceId,
functions: module_.functions,
main: module_.main || createEmptyFunction("main"),
debugContext,
Expand Down
2 changes: 1 addition & 1 deletion packages/bugc/src/irgen/generate/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1046,7 +1046,7 @@ export namespace Process {
}

const { offset, length } = node.loc;
const id = (yield* Process.Modules.current()).name;
const { sourceId: id } = yield* Process.Modules.current();

// Combine code and variables in a single context object
// No need for gather since the keys don't conflict
Expand Down
1 change: 1 addition & 0 deletions packages/bugc/src/irgen/generate/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export namespace State {
*/
export interface Module {
readonly name: string;
readonly sourceId: string;
readonly functions: Map<string, Ir.Function>;
readonly main?: Ir.Function;
readonly create?: Ir.Function;
Expand Down
30 changes: 30 additions & 0 deletions packages/bugc/src/irgen/generator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,36 @@ describe("generateModule", () => {
expect(ir.main.blocks.size).toBe(1);
expect(ir.main.blocks.get("entry")).toBeDefined();
});

it("should default sourceId to '0' when no sourcePath", () => {
const ir = buildIR(`
name Test;
storage {}
code {}
`);
expect(ir.sourceId).toBe("0");
});

it("should use sourcePath as sourceId when provided", () => {
const source = `
name Test;
storage {}
code {}
`;
const parseResult = parse(source);
if (!parseResult.success) throw new Error("Parse failed");
const typeCheckResult = TypeChecker.checkProgram(parseResult.value);
if (!typeCheckResult.success) {
throw new Error("Type check failed");
}
const result = generateModule(
parseResult.value,
typeCheckResult.value.types,
"contracts/Test.bug",
);
if (!result.success) throw new Error("IR gen failed");
expect(result.value.sourceId).toBe("contracts/Test.bug");
});
});

describe("expressions", () => {
Expand Down
10 changes: 8 additions & 2 deletions packages/bugc/src/irgen/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import { buildModule } from "#irgen/generate";
export function generateModule(
program: Ast.Program,
types: Types,
sourcePath?: string,
): Result<Ir.Module, IrgenError> {
// Create initial state
const initialState = createInitialState(program, types);
const initialState = createInitialState(program, types, sourcePath);

// Run the generator
const result = Process.run(buildModule(program, types), initialState);
Expand Down Expand Up @@ -55,13 +56,18 @@ export function generateModule(
/**
* Create the initial IR generation state
*/
function createInitialState(program: Ast.Program, types: Types): State {
function createInitialState(
program: Ast.Program,
types: Types,
sourcePath?: string,
): State {
// Create errors array to collect any type resolution errors
const errors: IrgenError[] = [];

// Create initial module
const module: State.Module = {
name: program.name,
sourceId: sourcePath ?? "0",
functions: new Map(),
storageDeclarations: program.storage ?? [],
};
Expand Down
5 changes: 3 additions & 2 deletions packages/bugc/src/irgen/pass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ const pass: Pass<{
needs: {
ast: Program;
types: Types;
sourcePath?: string;
};
adds: {
ir: Ir.Module;
};
error: IrgenError;
}> = {
async run({ ast, types }) {
return Result.map(generateModule(ast, types), (ir) => ({ ir }));
async run({ ast, types, sourcePath }) {
return Result.map(generateModule(ast, types, sourcePath), (ir) => ({ ir }));
},
};

Expand Down
5 changes: 5 additions & 0 deletions packages/bugc/src/optimizer/optimizer.property.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ describe("Optimizer Property Tests", () => {
function createModuleWithBinaryOp(a: bigint, b: bigint, op: string): Ir.Module {
return {
name: "Test",
sourceId: "test",
main: {
name: "main",
parameters: [],
Expand Down Expand Up @@ -336,6 +337,7 @@ function createModuleWithDeadCode(useFlags: boolean[]): Ir.Module {

return {
name: "Test",
sourceId: "test",
main: {
name: "main",
parameters: [],
Expand All @@ -361,6 +363,7 @@ function createModuleWithDeadCode(useFlags: boolean[]): Ir.Module {
function createModuleWithDuplicateExpressions(a: bigint, b: bigint): Ir.Module {
return {
name: "Test",
sourceId: "test",
main: {
name: "main",
parameters: [],
Expand Down Expand Up @@ -513,6 +516,7 @@ function createModuleWithMergeableBlocks(

return {
name: "Test",
sourceId: "test",
main: { name: "main", parameters: [], entry: "entry", blocks },
functions: new Map(),
};
Expand All @@ -522,6 +526,7 @@ function createModuleWithMergeableBlocks(
function generateRandomModule(): fc.Arbitrary<Ir.Module> {
return fc.record({
name: fc.constant("Test"),
sourceId: fc.constant("test"),
main: generateRandomFunction(),
functions: fc.constant(new Map()),
});
Expand Down
1 change: 1 addition & 0 deletions packages/bugc/src/optimizer/optimizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ export abstract class BaseOptimizationStep implements OptimizationStep {

return {
name: module.name,
sourceId: module.sourceId,
functions: clonedFunctions,
create: clonedCreate,
main: clonedMain,
Expand Down
1 change: 1 addition & 0 deletions packages/bugc/src/optimizer/steps/constant-folding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ describe("ConstantFoldingStep", () => {

return {
name: "test",
sourceId: "test",
functions: new Map(),
main: {
name: "main",
Expand Down
Loading