c-next 0.1.68 → 0.1.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +240 -204
- package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +693 -0
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +86 -5
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/AssignmentTargetExtractor.ts +1 -1
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/ChildStatementCollector.ts +1 -1
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/StatementExpressionCollector.ts +1 -1
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/AssignmentTargetExtractor.test.ts +2 -2
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/ChildStatementCollector.test.ts +2 -2
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/StatementExpressionCollector.test.ts +2 -2
- package/src/transpiler/output/codegen/CodeGenerator.ts +160 -742
- package/src/transpiler/output/codegen/TypeRegistrationUtils.ts +4 -6
- package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
- package/src/transpiler/output/codegen/TypeValidator.ts +7 -7
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +2 -2
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +29 -1
- package/src/transpiler/output/codegen/__tests__/TypeRegistrationUtils.test.ts +36 -51
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +20 -17
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +4 -6
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +4 -2
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +9 -9
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +12 -12
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +11 -11
- package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +49 -0
- package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +15 -0
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +30 -17
- package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +25 -18
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +19 -8
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +3 -3
- package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +4 -4
- package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +5 -5
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +9 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +41 -26
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +29 -37
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +27 -19
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +10 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +51 -33
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +9 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +5 -4
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +14 -6
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +19 -16
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +21 -4
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +15 -2
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +2 -1
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +2 -2
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +3 -3
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +6 -1
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +2 -2
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +7 -7
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +7 -7
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +2 -2
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +4 -4
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +2 -2
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +5 -5
- package/src/transpiler/state/CodeGenState.ts +157 -5
- package/src/transpiler/state/__tests__/CodeGenState.test.ts +274 -6
- /package/src/transpiler/{output/codegen → logic/analysis}/helpers/TransitiveModificationPropagator.ts +0 -0
- /package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/TransitiveModificationPropagator.test.ts +0 -0
|
@@ -6,6 +6,27 @@ import { describe, it, expect, beforeEach } from "vitest";
|
|
|
6
6
|
import CodeGenState from "../CodeGenState";
|
|
7
7
|
import TTypeInfo from "../../output/codegen/types/TTypeInfo";
|
|
8
8
|
import ICodeGenSymbols from "../../types/ICodeGenSymbols";
|
|
9
|
+
import ESymbolKind from "../../../utils/types/ESymbolKind";
|
|
10
|
+
import ESourceLanguage from "../../../utils/types/ESourceLanguage";
|
|
11
|
+
import ISymbol from "../../../utils/types/ISymbol";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a minimal ISymbol for testing with required fields.
|
|
15
|
+
*/
|
|
16
|
+
function createTestSymbol(
|
|
17
|
+
overrides: Partial<ISymbol> & {
|
|
18
|
+
name: string;
|
|
19
|
+
kind: ESymbolKind;
|
|
20
|
+
sourceLanguage: ESourceLanguage;
|
|
21
|
+
},
|
|
22
|
+
): ISymbol {
|
|
23
|
+
return {
|
|
24
|
+
sourceFile: "test.cnx",
|
|
25
|
+
sourceLine: 1,
|
|
26
|
+
isExported: false,
|
|
27
|
+
...overrides,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
9
30
|
|
|
10
31
|
/**
|
|
11
32
|
* Create a minimal mock ICodeGenSymbols with default empty collections.
|
|
@@ -110,7 +131,7 @@ describe("CodeGenState", () => {
|
|
|
110
131
|
|
|
111
132
|
it("getScopeMembers returns members for known scope", () => {
|
|
112
133
|
const members = new Set(["member1", "member2"]);
|
|
113
|
-
CodeGenState.
|
|
134
|
+
CodeGenState.setScopeMembers("TestScope", members);
|
|
114
135
|
|
|
115
136
|
expect(CodeGenState.getScopeMembers("TestScope")).toBe(members);
|
|
116
137
|
});
|
|
@@ -122,14 +143,14 @@ describe("CodeGenState", () => {
|
|
|
122
143
|
|
|
123
144
|
it("isCurrentScopeMember returns false for non-member", () => {
|
|
124
145
|
CodeGenState.currentScope = "TestScope";
|
|
125
|
-
CodeGenState.
|
|
146
|
+
CodeGenState.setScopeMembers("TestScope", new Set(["member1"]));
|
|
126
147
|
|
|
127
148
|
expect(CodeGenState.isCurrentScopeMember("nonMember")).toBe(false);
|
|
128
149
|
});
|
|
129
150
|
|
|
130
151
|
it("isCurrentScopeMember returns true for member", () => {
|
|
131
152
|
CodeGenState.currentScope = "TestScope";
|
|
132
|
-
CodeGenState.
|
|
153
|
+
CodeGenState.setScopeMembers("TestScope", new Set(["member1"]));
|
|
133
154
|
|
|
134
155
|
expect(CodeGenState.isCurrentScopeMember("member1")).toBe(true);
|
|
135
156
|
});
|
|
@@ -143,14 +164,14 @@ describe("CodeGenState", () => {
|
|
|
143
164
|
|
|
144
165
|
it("returns identifier unchanged when not a scope member", () => {
|
|
145
166
|
CodeGenState.currentScope = "TestScope";
|
|
146
|
-
CodeGenState.
|
|
167
|
+
CodeGenState.setScopeMembers("TestScope", new Set(["member1"]));
|
|
147
168
|
|
|
148
169
|
expect(CodeGenState.resolveIdentifier("varName")).toBe("varName");
|
|
149
170
|
});
|
|
150
171
|
|
|
151
172
|
it("returns scoped name for scope member", () => {
|
|
152
173
|
CodeGenState.currentScope = "TestScope";
|
|
153
|
-
CodeGenState.
|
|
174
|
+
CodeGenState.setScopeMembers("TestScope", new Set(["member1"]));
|
|
154
175
|
|
|
155
176
|
expect(CodeGenState.resolveIdentifier("member1")).toBe(
|
|
156
177
|
"TestScope_member1",
|
|
@@ -281,7 +302,7 @@ describe("CodeGenState", () => {
|
|
|
281
302
|
|
|
282
303
|
CodeGenState.registerType("myVar", typeInfo);
|
|
283
304
|
|
|
284
|
-
expect(CodeGenState.
|
|
305
|
+
expect(CodeGenState.getVariableTypeInfo("myVar")).toBe(typeInfo);
|
|
285
306
|
});
|
|
286
307
|
|
|
287
308
|
it("registerConstValue adds to constValues", () => {
|
|
@@ -348,6 +369,253 @@ describe("CodeGenState", () => {
|
|
|
348
369
|
});
|
|
349
370
|
});
|
|
350
371
|
|
|
372
|
+
describe("Variable Type Info API (Issue #786)", () => {
|
|
373
|
+
it("getVariableTypeInfo returns local type info from registry", () => {
|
|
374
|
+
const typeInfo: TTypeInfo = {
|
|
375
|
+
baseType: "u32",
|
|
376
|
+
bitWidth: 32,
|
|
377
|
+
isArray: false,
|
|
378
|
+
isConst: false,
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
CodeGenState.setVariableTypeInfo("localVar", typeInfo);
|
|
382
|
+
|
|
383
|
+
expect(CodeGenState.getVariableTypeInfo("localVar")).toBe(typeInfo);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it("getVariableTypeInfo returns undefined for unknown variable", () => {
|
|
387
|
+
expect(CodeGenState.getVariableTypeInfo("unknownVar")).toBeUndefined();
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("getVariableTypeInfo falls back to SymbolTable for C-Next variables", () => {
|
|
391
|
+
// Add a C-Next variable to SymbolTable (simulating cross-file include)
|
|
392
|
+
CodeGenState.symbolTable.addSymbol(
|
|
393
|
+
createTestSymbol({
|
|
394
|
+
name: "crossFileVar",
|
|
395
|
+
kind: ESymbolKind.Variable,
|
|
396
|
+
type: "u16",
|
|
397
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
398
|
+
isArray: true,
|
|
399
|
+
arrayDimensions: ["10"],
|
|
400
|
+
}),
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
const result = CodeGenState.getVariableTypeInfo("crossFileVar");
|
|
404
|
+
|
|
405
|
+
expect(result).toBeDefined();
|
|
406
|
+
expect(result?.baseType).toBe("u16");
|
|
407
|
+
expect(result?.bitWidth).toBe(16);
|
|
408
|
+
expect(result?.isArray).toBe(true);
|
|
409
|
+
expect(result?.arrayDimensions).toEqual([10]);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
it("getVariableTypeInfo does not use C header symbols", () => {
|
|
413
|
+
// Add a C header variable (should NOT be used)
|
|
414
|
+
CodeGenState.symbolTable.addSymbol(
|
|
415
|
+
createTestSymbol({
|
|
416
|
+
name: "cHeaderVar",
|
|
417
|
+
kind: ESymbolKind.Variable,
|
|
418
|
+
type: "uint32_t",
|
|
419
|
+
sourceLanguage: ESourceLanguage.C,
|
|
420
|
+
}),
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
expect(CodeGenState.getVariableTypeInfo("cHeaderVar")).toBeUndefined();
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it("getVariableTypeInfo prefers local registry over SymbolTable", () => {
|
|
427
|
+
// Add both local and SymbolTable version
|
|
428
|
+
const localInfo: TTypeInfo = {
|
|
429
|
+
baseType: "i32",
|
|
430
|
+
bitWidth: 32,
|
|
431
|
+
isArray: false,
|
|
432
|
+
isConst: true,
|
|
433
|
+
};
|
|
434
|
+
CodeGenState.setVariableTypeInfo("mixedVar", localInfo);
|
|
435
|
+
|
|
436
|
+
CodeGenState.symbolTable.addSymbol(
|
|
437
|
+
createTestSymbol({
|
|
438
|
+
name: "mixedVar",
|
|
439
|
+
kind: ESymbolKind.Variable,
|
|
440
|
+
type: "u8",
|
|
441
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
442
|
+
}),
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
// Should return local info, not SymbolTable info
|
|
446
|
+
const result = CodeGenState.getVariableTypeInfo("mixedVar");
|
|
447
|
+
expect(result?.baseType).toBe("i32");
|
|
448
|
+
expect(result?.isConst).toBe(true);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
it("hasVariableTypeInfo returns true for local registry", () => {
|
|
452
|
+
CodeGenState.setVariableTypeInfo("localVar", {
|
|
453
|
+
baseType: "u8",
|
|
454
|
+
bitWidth: 8,
|
|
455
|
+
isArray: false,
|
|
456
|
+
isConst: false,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
expect(CodeGenState.hasVariableTypeInfo("localVar")).toBe(true);
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
it("hasVariableTypeInfo returns true for C-Next SymbolTable variable", () => {
|
|
463
|
+
CodeGenState.symbolTable.addSymbol(
|
|
464
|
+
createTestSymbol({
|
|
465
|
+
name: "crossFileVar",
|
|
466
|
+
kind: ESymbolKind.Variable,
|
|
467
|
+
type: "u32",
|
|
468
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
469
|
+
}),
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
expect(CodeGenState.hasVariableTypeInfo("crossFileVar")).toBe(true);
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
it("hasVariableTypeInfo returns false for unknown variable", () => {
|
|
476
|
+
expect(CodeGenState.hasVariableTypeInfo("unknownVar")).toBe(false);
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
it("hasVariableTypeInfo returns false for C header variable", () => {
|
|
480
|
+
CodeGenState.symbolTable.addSymbol(
|
|
481
|
+
createTestSymbol({
|
|
482
|
+
name: "cVar",
|
|
483
|
+
kind: ESymbolKind.Variable,
|
|
484
|
+
type: "int",
|
|
485
|
+
sourceLanguage: ESourceLanguage.C,
|
|
486
|
+
}),
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
expect(CodeGenState.hasVariableTypeInfo("cVar")).toBe(false);
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it("setVariableTypeInfo and deleteVariableTypeInfo work correctly", () => {
|
|
493
|
+
const typeInfo: TTypeInfo = {
|
|
494
|
+
baseType: "f32",
|
|
495
|
+
bitWidth: 32,
|
|
496
|
+
isArray: false,
|
|
497
|
+
isConst: false,
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
CodeGenState.setVariableTypeInfo("tempVar", typeInfo);
|
|
501
|
+
expect(CodeGenState.getVariableTypeInfo("tempVar")).toBe(typeInfo);
|
|
502
|
+
|
|
503
|
+
CodeGenState.deleteVariableTypeInfo("tempVar");
|
|
504
|
+
expect(CodeGenState.getVariableTypeInfo("tempVar")).toBeUndefined();
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
it("getTypeRegistryView returns readonly view", () => {
|
|
508
|
+
CodeGenState.setVariableTypeInfo("var1", {
|
|
509
|
+
baseType: "u8",
|
|
510
|
+
bitWidth: 8,
|
|
511
|
+
isArray: false,
|
|
512
|
+
isConst: false,
|
|
513
|
+
});
|
|
514
|
+
CodeGenState.setVariableTypeInfo("var2", {
|
|
515
|
+
baseType: "u16",
|
|
516
|
+
bitWidth: 16,
|
|
517
|
+
isArray: false,
|
|
518
|
+
isConst: false,
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
const view = CodeGenState.getTypeRegistryView();
|
|
522
|
+
|
|
523
|
+
expect(view.size).toBe(2);
|
|
524
|
+
expect(view.has("var1")).toBe(true);
|
|
525
|
+
expect(view.has("var2")).toBe(true);
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
it("getTypeInfo is deprecated alias for getVariableTypeInfo", () => {
|
|
529
|
+
const typeInfo: TTypeInfo = {
|
|
530
|
+
baseType: "u64",
|
|
531
|
+
bitWidth: 64,
|
|
532
|
+
isArray: false,
|
|
533
|
+
isConst: false,
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
CodeGenState.setVariableTypeInfo("aliasVar", typeInfo);
|
|
537
|
+
|
|
538
|
+
// getTypeInfo should return same result
|
|
539
|
+
expect(CodeGenState.getTypeInfo("aliasVar")).toBe(typeInfo);
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
it("convertSymbolToTypeInfo handles string<N> types", () => {
|
|
543
|
+
CodeGenState.symbolTable.addSymbol(
|
|
544
|
+
createTestSymbol({
|
|
545
|
+
name: "myString",
|
|
546
|
+
kind: ESymbolKind.Variable,
|
|
547
|
+
type: "string<32>",
|
|
548
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
549
|
+
}),
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
const result = CodeGenState.getVariableTypeInfo("myString");
|
|
553
|
+
|
|
554
|
+
expect(result?.baseType).toBe("char");
|
|
555
|
+
expect(result?.bitWidth).toBe(8);
|
|
556
|
+
expect(result?.isString).toBe(true);
|
|
557
|
+
expect(result?.stringCapacity).toBe(32);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
it("convertSymbolToTypeInfo handles enum types", () => {
|
|
561
|
+
// Register an enum
|
|
562
|
+
CodeGenState.symbols = createMockSymbols({
|
|
563
|
+
knownEnums: new Set(["EColor"]),
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
CodeGenState.symbolTable.addSymbol(
|
|
567
|
+
createTestSymbol({
|
|
568
|
+
name: "color",
|
|
569
|
+
kind: ESymbolKind.Variable,
|
|
570
|
+
type: "EColor",
|
|
571
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
572
|
+
}),
|
|
573
|
+
);
|
|
574
|
+
|
|
575
|
+
const result = CodeGenState.getVariableTypeInfo("color");
|
|
576
|
+
|
|
577
|
+
expect(result?.baseType).toBe("EColor");
|
|
578
|
+
expect(result?.isEnum).toBe(true);
|
|
579
|
+
expect(result?.enumTypeName).toBe("EColor");
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
it("convertSymbolToTypeInfo handles const and atomic", () => {
|
|
583
|
+
CodeGenState.symbolTable.addSymbol(
|
|
584
|
+
createTestSymbol({
|
|
585
|
+
name: "constAtomicVar",
|
|
586
|
+
kind: ESymbolKind.Variable,
|
|
587
|
+
type: "u32",
|
|
588
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
589
|
+
isConst: true,
|
|
590
|
+
isAtomic: true,
|
|
591
|
+
}),
|
|
592
|
+
);
|
|
593
|
+
|
|
594
|
+
const result = CodeGenState.getVariableTypeInfo("constAtomicVar");
|
|
595
|
+
|
|
596
|
+
expect(result?.isConst).toBe(true);
|
|
597
|
+
expect(result?.isAtomic).toBe(true);
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
it("convertSymbolToTypeInfo filters invalid array dimensions", () => {
|
|
601
|
+
CodeGenState.symbolTable.addSymbol(
|
|
602
|
+
createTestSymbol({
|
|
603
|
+
name: "arrayVar",
|
|
604
|
+
kind: ESymbolKind.Variable,
|
|
605
|
+
type: "u8",
|
|
606
|
+
sourceLanguage: ESourceLanguage.CNext,
|
|
607
|
+
isArray: true,
|
|
608
|
+
arrayDimensions: ["10", "invalid", "20"],
|
|
609
|
+
}),
|
|
610
|
+
);
|
|
611
|
+
|
|
612
|
+
const result = CodeGenState.getVariableTypeInfo("arrayVar");
|
|
613
|
+
|
|
614
|
+
// Should only include valid numeric dimensions
|
|
615
|
+
expect(result?.arrayDimensions).toEqual([10, 20]);
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
|
|
351
619
|
describe("Overflow Operation Helpers", () => {
|
|
352
620
|
it("markClampOpUsed adds to usedClampOps", () => {
|
|
353
621
|
CodeGenState.markClampOpUsed("add", "u8");
|
|
File without changes
|
|
File without changes
|