const { getDataType, normalizeGroup } = require('../../domain/parameter-groups/model.js') const { parseStructCatalog, parseStructDefinition: parseStructDefinitionSource } = require('../../domain/parameter-groups/struct-parser.js') function getRegisterByteLengthFromConfig(register) { const dataType = getDataType(register.dataType).key if (dataType === 'ascii' || dataType === 'utf8') return Math.max(1, Number(register.textByteLength) || 1) if (dataType === 'float' || dataType === 'int32_t' || dataType === 'uint32_t') return 4 if (dataType === 'int8_t' || dataType === 'uint8_t') return 1 return 2 } function getRegistersByteLength(registers = []) { const explicitByteEnds = registers.map((register) => { const byteStart = Number(register && register.byteStart) if (!Number.isFinite(byteStart)) return null if (register.isBitField) { const bitOffset = Math.min(Math.max(Math.floor(Number(register.bitOffset) || 0), 0), 7) const bitWidth = Math.max(1, Math.round(Number(register.bitWidth) || 1)) return Math.max(0, Math.floor(byteStart)) + Math.max(1, Math.ceil((bitOffset + bitWidth) / 8)) } return Math.max(0, Math.floor(byteStart)) + getRegisterByteLengthFromConfig(register) }).filter((value) => Number.isFinite(value)) if (explicitByteEnds.length) return Math.max.apply(null, explicitByteEnds) return registers.reduce((total, register) => total + getRegisterByteLengthFromConfig(register), 0) } function normalizeSymbolText(value) { return String(value || '') .replace(/^(?:IDATA|XDATA|DATA|CODE)[\s:_-]+/i, '') .replace(/^_+/, '') .replace(/[^A-Za-z0-9]/g, '') .toLowerCase() } function findStructCompletion(group, catalog) { const symbolName = group.sourceSymbolName || group.name const direct = catalog.variablesByName[normalizeSymbolText(symbolName)] || catalog.variablesByName[symbolName] if (direct) return direct const normalizedSymbol = normalizeSymbolText(symbolName) const normalizedType = normalizeSymbolText(group.sourceSymbolType) const expectedBytes = Number(group.sourceByteLength || group.byteLength || 0) const matchedStruct = catalog.structs.find((structInfo) => { const normalizedStructName = normalizeSymbolText(structInfo.name) if (normalizedType && normalizedType === normalizedStructName) { return true } if (normalizedSymbol && ( normalizedSymbol === normalizedStructName || normalizedSymbol.indexOf(normalizedStructName) >= 0 || normalizedStructName.indexOf(normalizedSymbol) >= 0 )) { return true } return expectedBytes > 0 && getRegistersByteLength(structInfo.registers) === expectedBytes }) return matchedStruct ? { name: symbolName, registers: matchedStruct.registers, structName: matchedStruct.name } : null } function createCompletedRegisters(group, completion) { const existingRemarksByByteStart = (Array.isArray(group.registers) ? group.registers : []).reduce((remarks, register) => { const byteStart = Number(register && register.byteStart) const remark = String(register && register.remark ? register.remark : '').trim() if (Number.isFinite(byteStart) && remark) remarks[Math.floor(byteStart)] = remark return remarks }, {}) return completion.registers.map((register) => ({ ...register, isStructField: true, remark: register.remark || existingRemarksByByteStart[Math.floor(Number(register.byteStart) || 0)] || '', sourceMemoryArea: group.sourceMemoryArea, sourceMemoryClass: group.sourceMemoryClass, sourceSymbolName: group.sourceSymbolName, sourceSymbolType: completion.structName || register.sourceSymbolType })) } function completeStructInstanceGroups(groups, sourceText, options = {}) { const catalog = parseStructCatalog(sourceText) let completedCount = 0 let skippedCount = 0 const nextGroups = groups.map((group) => { if (!group.sourceSymbolName || !group.sourceMemoryArea) return group const completion = findStructCompletion(group, catalog) if (!completion || !completion.registers || !completion.registers.length) { skippedCount += 1 return group } const expectedBytes = Number(group.sourceByteLength || group.byteLength || 0) const actualBytes = getRegistersByteLength(completion.registers) if (expectedBytes > 0 && actualBytes !== expectedBytes && options.strictLength !== false) { skippedCount += 1 return group } completedCount += 1 return normalizeGroup({ ...group, layout: 'struct', quantity: completion.registers.length, registers: createCompletedRegisters(group, completion) }) }) return { completedCount, groups: nextGroups, skippedCount, structCount: catalog.structs.length, variableCount: Object.keys(catalog.variablesByName).length } } function parseStructDefinition(sourceText) { return parseStructDefinitionSource(sourceText) } module.exports = { completeStructInstanceGroups, getRegistersByteLength, parseStructDefinition }