From ce0bc8d547b0b4d4fb8d833d46bb82bf28adabf3 Mon Sep 17 00:00:00 2001 From: deleterium Date: Sun, 18 Feb 2024 10:34:08 -0300 Subject: [PATCH] Feat: Waning unused variables --- src/__tests__/misc.a.spec.ts | 16 ++++++++-------- src/__tests__/warnings.a.spec.ts | 22 +++++++++++++++++++--- src/codeGenerator/codeGenerator.ts | 13 +++++++++++++ src/shaper/memoryProcessor.ts | 12 ++++++++---- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/__tests__/misc.a.spec.ts b/src/__tests__/misc.a.spec.ts index 39692e3..d3304a3 100644 --- a/src/__tests__/misc.a.spec.ts +++ b/src/__tests__/misc.a.spec.ts @@ -213,8 +213,8 @@ describe('Wrong code to check error safeguards', () => { describe('Warnings', () => { it('should compile with warning: right side of operator', () => { - const code = 'long la=0, lb; fixed fa, fb=0.0; fa = fb - la;' - const assembly = '^declare r0\n^declare r1\n^declare r2\n^declare f100000000\n^const SET @f100000000 #0000000005f5e100\n^declare la\n^declare lb\n^declare fa\n^declare fb\n\nCLR @la\nCLR @fb\nSET @fa $fb\nSET @r0 $la\nMUL @r0 $f100000000\nSUB @fa $r0\nFIN\n' + const code = 'long la=0 ; fixed fa, fb=0.0; fa = fb - la;' + const assembly = '^declare r0\n^declare r1\n^declare r2\n^declare f100000000\n^const SET @f100000000 #0000000005f5e100\n^declare la\n^declare fa\n^declare fb\n\nCLR @la\nCLR @fb\nSET @fa $fb\nSET @r0 $la\nMUL @r0 $f100000000\nSUB @fa $r0\nFIN\n' const warnings = "Warning: at line 1:42. Implicit type casting conversion on right side of operator '-'." const compiler = new SmartC({ language: 'C', sourceCode: code }) compiler.compile() @@ -222,8 +222,8 @@ describe('Warnings', () => { expect(compiler.getMachineCode().Warnings).toBe(warnings) }) it('should compile with warning: left side of operator', () => { - const code = 'long la=2, lb; fixed fa, fb=0.0; fa = la - fb;\n#pragma optimizationLevel 0' - const assembly = '^declare r0\n^declare r1\n^declare r2\n^declare f100000000\n^const SET @f100000000 #0000000005f5e100\n^declare la\n^declare lb\n^declare fa\n^declare fb\n\nSET @la #0000000000000002\nCLR @fb\nSET @fa $la\nMUL @fa $f100000000\nSUB @fa $fb\nFIN\n' + const code = 'long la=2 ; fixed fa, fb=0.0; fa = la - fb;\n#pragma optimizationLevel 0' + const assembly = '^declare r0\n^declare r1\n^declare r2\n^declare f100000000\n^const SET @f100000000 #0000000005f5e100\n^declare la\n^declare fa\n^declare fb\n\nSET @la #0000000000000002\nCLR @fb\nSET @fa $la\nMUL @fa $f100000000\nSUB @fa $fb\nFIN\n' const warnings = "Warning: at line 1:42. Implicit type casting conversion on left side of operator '-'." const compiler = new SmartC({ language: 'C', sourceCode: code }) compiler.compile() @@ -240,8 +240,8 @@ describe('Warnings', () => { expect(compiler.getMachineCode().Warnings).toBe(warnings) }) it('should compile with warning: left side of comparision', () => { - const code = 'long la=1, lb; fixed fa, fb=1.1; if(la < fb) la++;\n#pragma optimizationLevel 0\n' - const assembly = '^declare r0\n^declare r1\n^declare r2\n^declare f100000000\n^const SET @f100000000 #0000000005f5e100\n^declare la\n^declare lb\n^declare fa\n^declare fb\n\nSET @la #0000000000000001\nSET @fb #00000000068e7780\nSET @r0 $la\nMUL @r0 $f100000000\nBGE $r0 $fb :__if1_endif\n__if1_start:\nINC @la\n__if1_endif:\nFIN\n' + const code = 'long la=1 ; fixed fb=1.1; if(la < fb) la++;\n#pragma optimizationLevel 0\n' + const assembly = '^declare r0\n^declare r1\n^declare r2\n^declare f100000000\n^const SET @f100000000 #0000000005f5e100\n^declare la\n^declare fb\n\nSET @la #0000000000000001\nSET @fb #00000000068e7780\nSET @r0 $la\nMUL @r0 $f100000000\nBGE $r0 $fb :__if1_endif\n__if1_start:\nINC @la\n__if1_endif:\nFIN\n' const warnings = "Warning: at line 1:40. Implicit type casting conversion on left side of comparision '<'." const compiler = new SmartC({ language: 'C', sourceCode: code }) compiler.compile() @@ -249,8 +249,8 @@ describe('Warnings', () => { expect(compiler.getMachineCode().Warnings).toBe(warnings) }) it('should compile with warning: right side of assignment', () => { - const code = 'long la, lb; fixed fa, fb=0.0; la = fb;' - const assembly = '^declare r0\n^declare r1\n^declare r2\n^declare f100000000\n^const SET @f100000000 #0000000005f5e100\n^declare la\n^declare lb\n^declare fa\n^declare fb\n\nCLR @fb\nSET @la $fb\nDIV @la $f100000000\nFIN\n' + const code = 'long la ; fixed fb=0.0; la = fb;' + const assembly = '^declare r0\n^declare r1\n^declare r2\n^declare f100000000\n^const SET @f100000000 #0000000005f5e100\n^declare la\n^declare fb\n\nCLR @fb\nSET @la $fb\nDIV @la $f100000000\nFIN\n' const warnings = "Warning: at line 1:35. Implicit type casting conversion on right side of assignment '='." const compiler = new SmartC({ language: 'C', sourceCode: code }) compiler.compile() diff --git a/src/__tests__/warnings.a.spec.ts b/src/__tests__/warnings.a.spec.ts index 126e279..6d1ab5e 100644 --- a/src/__tests__/warnings.a.spec.ts +++ b/src/__tests__/warnings.a.spec.ts @@ -2,24 +2,40 @@ import { SmartC } from '../smartc' describe('Warnings', () => { it('should not warn: add or sub pointers with longs values (struct_ptr)', () => { - const code = 'search(2);\nstruct PLAYER { long address, balance, VDLS; } *playerPtr, players[2];\nstruct PLAYER * search(long playerAddress) {\nlong nPlayers=0;\n struct PLAYER * foundPlayer;\n foundPlayer = &players[0];\n for (long auxI = 0; auxI < nPlayers; auxI++) {\n if (foundPlayer->address == playerAddress) {\n return foundPlayer;\n }\n foundPlayer += (sizeof(struct PLAYER));\n foundPlayer = foundPlayer + (sizeof(struct PLAYER));\n foundPlayer++;\n }\n return NULL;\n}' + const code = 'search(2);\nstruct PLAYER { long address, balance, VDLS; } players[2];\nstruct PLAYER * search(long playerAddress) {\nlong nPlayers=0;\n struct PLAYER * foundPlayer;\n foundPlayer = &players[0];\n for (long auxI = 0; auxI < nPlayers; auxI++) {\n if (foundPlayer->address == playerAddress) {\n return foundPlayer;\n }\n foundPlayer += (sizeof(struct PLAYER));\n foundPlayer = foundPlayer + (sizeof(struct PLAYER));\n foundPlayer++;\n }\n return NULL;\n}' const warnings = '' const compiler = new SmartC({ language: 'C', sourceCode: code }) compiler.compile() expect(compiler.getMachineCode().Warnings).toBe(warnings) }) it('should warn: longs used before initialization', () => { - const code = 'struct PLAYER { long sa, sb; } player;\nlong a, b;\nlong message[4];\n\na+=1;\na = message[b];\na = player.sb;\n' + const code = 'struct PLAYER { long sb; } player;\nlong a, b;\nlong message[4];\n\na+=1;\na = message[b];\na = player.sb;\n' const warnings = "Warning: at line 5:1. Variable 'a' is used but not initialized.\nWarning: at line 6:13. Variable 'b' is used but not initialized.\nWarning: at line 7:12. Variable 'player_sb' is used but not initialized." const compiler = new SmartC({ language: 'C', sourceCode: code }) compiler.compile() expect(compiler.getMachineCode().Warnings).toBe(warnings) }) it('should not warn: same as before but initialized', () => { - const code = 'struct PLAYER { long sa, sb; } player;\nlong a, b;\nlong message[4];\n\na=b=1;\na = message[b];\nplayer.sb=message[2];\na = player.sb;\n' + const code = 'struct PLAYER { long sb; } player;\nlong a, b;\nlong message[4];\n\na=b=1;\na = message[b];\nplayer.sb=message[2];\na = player.sb;\n' const warnings = '' const compiler = new SmartC({ language: 'C', sourceCode: code }) compiler.compile() expect(compiler.getMachineCode().Warnings).toBe(warnings) }) + it('should compile with warning: unused global variable', () => { + const code = 'long la=0, lb; fixed fa, fb=0.0; fa = fb - (fixed)la;' + const assembly = '^declare r0\n^declare r1\n^declare r2\n^declare f100000000\n^const SET @f100000000 #0000000005f5e100\n^declare la\n^declare lb\n^declare fa\n^declare fb\n\nCLR @la\nCLR @fb\nSET @r0 $la\nMUL @r0 $f100000000\nSET @fa $fb\nSUB @fa $r0\nFIN\n' + const warnings = "Warning: Unused global variable 'lb'." + const compiler = new SmartC({ language: 'C', sourceCode: code }) + compiler.compile() + expect(compiler.getAssemblyCode()).toBe(assembly) + expect(compiler.getMachineCode().Warnings).toBe(warnings) + }) + it('should warn: Variable not used inside a function', () => { + const code = 'search(2); struct PLAYER { long address, balance, VDLS; } *playerPtr, players[2]; struct PLAYER * search(long playerAddress) { long nPlayers=0; struct PLAYER * foundPlayer; playerPtr = &players[0]; for (long auxI = 0; auxI < nPlayers; auxI++) { if (playerPtr->address == playerAddress) { return playerPtr; } playerPtr += (sizeof(struct PLAYER)); playerPtr = playerPtr + (sizeof(struct PLAYER)); playerPtr++; } return NULL;}' + const warnings = "Warning: Unused variable 'foundPlayer' in function 'search'." + const compiler = new SmartC({ language: 'C', sourceCode: code }) + compiler.compile() + expect(compiler.getMachineCode().Warnings).toBe(warnings) + }) }) diff --git a/src/codeGenerator/codeGenerator.ts b/src/codeGenerator/codeGenerator.ts index f7f335b..21acdfc 100644 --- a/src/codeGenerator/codeGenerator.ts +++ b/src/codeGenerator/codeGenerator.ts @@ -125,6 +125,7 @@ export default function codeGenerator (Program: CONTRACT) { 'Inline cannot be used in recursive functions neither have circular dependency of each other.') } } + checkUnusedVariables() // Inspect if there were errros and throw now if (GlobalCodeVars.errors.length !== 0) { throw new Error(GlobalCodeVars.errors + Program.warnings) @@ -252,6 +253,18 @@ export default function codeGenerator (Program: CONTRACT) { } } + function checkUnusedVariables () { + Program.memory.forEach(Mem => { + if (Mem.isSet === false) { + if (Mem.scope) { + Program.warnings.push(`Warning: Unused variable '${Mem.name}' in function '${Mem.scope}'.`) + return + } + Program.warnings.push(`Warning: Unused global variable '${Mem.name}'.`) + } + }) + } + /** Hot stuff!!! Assemble sentences!! */ function compileSentence (Sentence: SENTENCES) { let sentenceID: string diff --git a/src/shaper/memoryProcessor.ts b/src/shaper/memoryProcessor.ts index 85f7c8b..5aac555 100644 --- a/src/shaper/memoryProcessor.ts +++ b/src/shaper/memoryProcessor.ts @@ -270,7 +270,7 @@ export default function memoryProcessor ( throw new Error(`At line: ${startingLine}.` + ` Could not find type definition for 'struct' '${currentStructNameDef}'.`) } - return createMemoryObjectFromSTD(currentStructNameDef, phraseCode[tokenCounter].value, isStructPointer) + return createMemoryObjectFromSTD(currentStructNameDef, phraseCode[tokenCounter].value, isStructPointer, false) } // isStructPointer is true if (StructTD === undefined) { @@ -308,7 +308,7 @@ export default function memoryProcessor ( StructMemHeader.asmName = AuxVars.currentPrefix + phraseCode[startingTokenCounter].value StructMemHeader.scope = AuxVars.currentScopeName StructMemHeader.isDeclared = AuxVars.isFunctionArgument - StructMemHeader.isSet = AuxVars.isFunctionArgument + StructMemHeader.isSet = true // do not control using variables in array StructMemHeader.type = 'array' StructMemHeader.typeDefinition = StructMemHeader.asmName StructMemHeader.ArrayItem = { @@ -326,7 +326,8 @@ export default function memoryProcessor ( retStructMemory.push(...createMemoryObjectFromSTD( currentStructNameDef, phraseCode[tokenCounter - structArrDimensions.length].value + '_' + ((i - 1) / StructMemHeader.size).toString(), - isStructPointer + isStructPointer, + true )) } // create array type definition @@ -350,7 +351,7 @@ export default function memoryProcessor ( /** Create an array of memory objects from a given structTypeName. * The memory objects will be named variableName. */ function createMemoryObjectFromSTD ( - structTypeName: string, variableName: string, ispointer: boolean + structTypeName: string, variableName: string, ispointer: boolean, isArray: boolean ) : MEMORY_SLOT[] { const StructTD = assertNotUndefined(findSTD(structTypeName), 'Internal error.') @@ -359,6 +360,9 @@ export default function memoryProcessor ( newmemory.push(...deepCopy(StructTD.structMembers)) } newmemory.forEach(Mem => { + if (isArray) { + Mem.isSet = true + } if (Mem.name === '') { Mem.name = variableName } else {