diff --git a/src/__tests__/warnings.a.spec.ts b/src/__tests__/warnings.a.spec.ts index 5133c07..4478438 100644 --- a/src/__tests__/warnings.a.spec.ts +++ b/src/__tests__/warnings.a.spec.ts @@ -25,15 +25,34 @@ describe('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 warnings = "Warning! At line: 1:12. Unused variable 'lb'.\n |long la=0, lb; fixed fa, fb=0.0; fa = fb - (fixed)la;\n | ^" 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 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! At line: 7:21. Unused variable 'foundPlayer'. + | struct PLAYER * foundPlayer; + | ^` 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 cbfa47a..eff02dc 100644 --- a/src/codeGenerator/codeGenerator.ts +++ b/src/codeGenerator/codeGenerator.ts @@ -211,11 +211,8 @@ export default function codeGenerator (Program: CONTRACT) { function checkUnusedVariables () { Program.memory.forEach(Mem => { if (Mem.isSet === false) { - if (Mem.scope) { - Program.Context.warnings.push(`Warning! Unused variable '${Mem.name}' in function '${Mem.scope}'.`) - return - } - Program.Context.warnings.push(`Warning! Unused global variable '${Mem.name}'.`) + Program.Context.warnings.push('Warning! ' + Program.Context.formatError(Mem.line, + `Unused variable '${Mem.name}'.`)) } }) } diff --git a/src/codeGenerator/utils.ts b/src/codeGenerator/utils.ts index f449222..aa1024a 100644 --- a/src/codeGenerator/utils.ts +++ b/src/codeGenerator/utils.ts @@ -38,6 +38,7 @@ export default { asmName: '', type: 'constant', scope: '', + line: '0:0', size: param.length / 16, declaration: 'long', isDeclared: true, @@ -60,6 +61,7 @@ export default { asmName: '', type: 'void', scope: '', + line: '0:0', size: 0, declaration: 'void', isSet: true, diff --git a/src/shaper/memoryProcessor.ts b/src/shaper/memoryProcessor.ts index 2bd514c..8667a4e 100644 --- a/src/shaper/memoryProcessor.ts +++ b/src/shaper/memoryProcessor.ts @@ -116,6 +116,7 @@ export default function memoryProcessor ( header.isDeclared = Program.Context.ShaperContext.isFunctionArgument header.isSet = Program.Context.ShaperContext.isFunctionArgument header.toBeRegister = isRegister + header.line = phraseCode[tokenCounter].line // If is not an array, just send the header if (dimensions.length === 0) { return [header] @@ -146,6 +147,7 @@ export default function memoryProcessor ( Mem2.name = `${header.name}_${i - 1}` Mem2.asmName = `${header.asmName}_${i - 1}` Mem2.scope = Program.Context.ShaperContext.currentScopeName + Mem2.line = phraseCode[tokenCounter].line Mem2.declaration = header.ArrayItem.declaration Mem2.isSet = true // No way to track array items for using before initialized retArrMem.push(Mem2) @@ -291,6 +293,7 @@ export default function memoryProcessor ( StructMemHeader.name = phraseCode[startingTokenCounter].value StructMemHeader.asmName = Program.Context.ShaperContext.currentPrefix + phraseCode[startingTokenCounter].value StructMemHeader.scope = Program.Context.ShaperContext.currentScopeName + StructMemHeader.line = phraseCode[startingTokenCounter].line StructMemHeader.isDeclared = Program.Context.ShaperContext.isFunctionArgument StructMemHeader.isSet = Program.Context.ShaperContext.isFunctionArgument return [StructMemHeader] @@ -309,6 +312,7 @@ export default function memoryProcessor ( StructMemHeader.name = phraseCode[startingTokenCounter].value StructMemHeader.asmName = Program.Context.ShaperContext.currentPrefix + phraseCode[startingTokenCounter].value StructMemHeader.scope = Program.Context.ShaperContext.currentScopeName + StructMemHeader.line = phraseCode[startingTokenCounter].line StructMemHeader.isDeclared = Program.Context.ShaperContext.isFunctionArgument StructMemHeader.isSet = true // do not control using variables in array StructMemHeader.type = 'array' @@ -371,6 +375,7 @@ export default function memoryProcessor ( Mem.name = variableName + '_' + Mem.name } Mem.asmName = Program.Context.ShaperContext.currentPrefix + Mem.name + Mem.line = phraseCode[tokenCounter].line }) return newmemory } diff --git a/src/shaper/shaper.ts b/src/shaper/shaper.ts index dda6f33..9927944 100644 --- a/src/shaper/shaper.ts +++ b/src/shaper/shaper.ts @@ -371,6 +371,7 @@ export default function shaper (Program: CONTRACT, tokenAST: TOKEN[]): void { MemTempl.asmName = Sentence.id MemTempl.name = Sentence.id MemTempl.isDeclared = true + MemTempl.line = Sentence.line Program.memory.push(MemTempl) } } @@ -436,19 +437,14 @@ export default function shaper (Program: CONTRACT, tokenAST: TOKEN[]): void { for (i = 0; i < Program.memory.length - 1; i++) { for (j = i + 1; j < Program.memory.length; j++) { if (Program.memory[i].asmName === Program.memory[j].asmName) { - if (Program.memory[i].type !== Program.memory[j].type) { - throw new Error('At line: unknown.' + - ` Global check: it was found that variable '${Program.memory[i].name}' was declared more` + - ` one time with types '${Program.memory[i].type}' and '${Program.memory[j].type}'.`) + if (Program.memory[i].type === 'label' || Program.memory[j].type === 'label') { + throw new Error(Program.Context.formatError(Program.memory[j].line, + `Label '${Program.memory[i].name}' was declared more than one time, ` + + `first declaration at line ${Program.memory[i].line}.` + + 'Labels also cannot have same name from variables.')) } - if (Program.memory[i].type === 'label') { - throw new Error('At line: unknow.' + - ` Global check: it was found that label '${Program.memory[i].name}' was` + - ' declared more than one time.') - } - throw new Error('At line: unknow.' + - ` Global check: it was found that variable '${Program.memory[i].name}' was` + - ' declared more than one time.') + throw new Error(Program.Context.formatError(Program.memory[j].line, + `Variable '${Program.memory[i].name}' was first declared at line ${Program.memory[i].line}.`)) } } } diff --git a/src/shaper/templates.ts b/src/shaper/templates.ts index 3d3d535..f29229c 100644 --- a/src/shaper/templates.ts +++ b/src/shaper/templates.ts @@ -67,6 +67,7 @@ const longArg : MEMORY_SLOT = { asmName: 'dummy_dummy', type: 'long', scope: 'dummy', + line: '0:0', declaration: 'long', isSet: false, toBeRegister: false, @@ -80,6 +81,7 @@ const longPtrArg : MEMORY_SLOT = { asmName: 'dummy_dummy', type: 'long', scope: 'dummy', + line: '0:0', declaration: 'long_ptr', isSet: false, toBeRegister: false, @@ -93,6 +95,7 @@ const fixedArg : MEMORY_SLOT = { asmName: 'dummy_dummy', type: 'fixed', scope: 'dummy', + line: '0:0', declaration: 'fixed', isSet: false, toBeRegister: false, @@ -109,6 +112,7 @@ export const autoCounterTemplate : MEMORY_SLOT = { isSet: true, name: '_counterTimestamp', scope: '', + line: '0:0', size: 1, type: 'long' } @@ -150,6 +154,7 @@ export const BuiltInTemplate: SC_FUNCTION[] = [ asmName: 'memcopy_addr1', type: 'long', scope: 'memcopy', + line: '0:0', declaration: 'void_ptr', isSet: false, toBeRegister: false, @@ -162,6 +167,7 @@ export const BuiltInTemplate: SC_FUNCTION[] = [ asmName: 'memcopy_addr2', type: 'long', scope: 'memcopy', + line: '0:0', declaration: 'void_ptr', isSet: false, toBeRegister: false, @@ -632,6 +638,7 @@ export function getMemoryTemplate (memType: MEMORY_BASE_TYPES) : MEMORY_SLOT { address: -1, name: '', scope: '', + line: '0:0', size: -1 } } @@ -646,6 +653,7 @@ export const fixedBaseTemplate : MEMORY_SLOT = { name: 'f100000000', hexContent: '0000000005f5e100', scope: '', + line: '0:0', size: 1, type: 'fixed' } diff --git a/src/typings/syntaxTypes.ts b/src/typings/syntaxTypes.ts index c763d18..0a18bce 100644 --- a/src/typings/syntaxTypes.ts +++ b/src/typings/syntaxTypes.ts @@ -68,6 +68,8 @@ export type MEMORY_SLOT = { name: string /** Variable scope */ scope: string + /** Line of declaration */ + line: string /** Variable size in longs */ size: number /** struct type definition OR array type definition */