Files
explorer/src/utils/register_parsers/reg_default.ts
2025-12-17 20:10:00 +00:00

157 lines
6.0 KiB
TypeScript

import {Register, RegisterAccess, RegisterDetail, Note} from "@/utils/register_parser";
export const parseDescriptionDefault = (reg: Register, description: string) => {
const descriptionLines = description.split('\n');
let currentAccess: 'read' | 'write' | 'common' | null = null;
let accessData: RegisterAccess = { operations: [], notes: [] };
// Prepare a new RegisterDetail for this description block
const detail: RegisterDetail = { read: undefined, write: undefined, common: undefined, text: ''};
// Footnote multiline state
let inFootnote = false;
let footnoteBaseIndent = 0;
// let footnoteTarget: 'global' | 'access' | null = null;
let currentFootnote: Note | null = null;
const endFootnoteIfActive = () => {
inFootnote = false;
footnoteBaseIndent = 0;
// footnoteTarget = null;
currentFootnote = null;
};
for (let idx = 0; idx < descriptionLines.length; idx++) {
const line = descriptionLines[idx];
reg.source.push(line);
const trimmedLine = line.trim();
if (trimmedLine.startsWith('//')) continue;
reg.search += line.toLowerCase() + " ";
const spaces_at_start = line.match(/^(\s*)/)?.[0].length || 0;
if (line.includes('Issue 4 Only')) reg.issue_4_only = true;
// Handle multiline footnote continuation
if (inFootnote) {
if (spaces_at_start > footnoteBaseIndent && trimmedLine.length > 0) {
// continuation line; append preserving original line (trim left to the base indent)
const continuation = line.substring(footnoteBaseIndent + 1); // +1 to skip at least one extra indent
if (currentFootnote) {
currentFootnote.text += `\n${continuation.trimEnd()}`;
}
continue;
} else {
// indentation returned -> end footnote, and fall through to process this line normally
endFootnoteIfActive();
}
}
// Access state markers
if (trimmedLine.startsWith('(R)')) {
if (currentAccess) {
// finalize previous access block into detail
detail[currentAccess] = accessData;
}
accessData = { operations: [], notes: [] };
currentAccess = 'read';
continue;
}
if (trimmedLine.startsWith('(W)')) {
if (currentAccess) {
detail[currentAccess] = accessData;
}
accessData = { operations: [], notes: [] };
currentAccess = 'write';
continue;
}
if (trimmedLine.startsWith('(R/W')) {
if (currentAccess) {
detail[currentAccess] = accessData;
}
accessData = { operations: [], notes: [] };
currentAccess = 'common';
continue;
}
// New top-level text block (no leading spaces)
if (line.startsWith(trimmedLine)) {
if (currentAccess) {
detail[currentAccess] = accessData;
}
accessData = { operations: [], notes: [] };
currentAccess = null;
}
// Start of a footnote (works both inside and outside an access block)
if (trimmedLine.startsWith('*')) {
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
if (noteMatch) {
const note: Note = { ref: noteMatch[1], text: noteMatch[2] };
if (currentAccess) {
accessData.notes.push(note);
// footnoteTarget = 'access';
} else {
reg.notes.push(note);
// footnoteTarget = 'global';
}
currentFootnote = note;
inFootnote = true;
footnoteBaseIndent = spaces_at_start;
continue;
}
}
if (currentAccess) {
const bitMatch = trimmedLine.match(/^(bits?|bit)\s+([\d:-]+)\s*=\s*(.*)/);
// const valueMatch = !line.match(/^\s+/) && trimmedLine.match(/^([01\s]+)\s*=\s*(.*)/);
if (bitMatch) {
let bitDescription = bitMatch[3];
const footnoteMatch = bitDescription.match(/(\*+)$/);
let footnoteRef: string | undefined = undefined;
if (footnoteMatch) {
footnoteRef = footnoteMatch[1];
bitDescription = bitDescription.substring(0, bitDescription.length - footnoteRef.length).trim();
}
accessData.operations.push({
bits: bitMatch[2],
description: bitDescription,
footnoteRef: footnoteRef,
});
// } else if (valueMatch) {
// console.error("VALUE MATCH",valueMatch);
// accessData.operations.push({
// bits: valueMatch[1].trim().replace(/\s/g, ''),
// description: valueMatch[2].trim(),
// });
} else if (trimmedLine) {
if(spaces_at_start == 2) {
reg.text += `${line}\n`;
continue;
}
if (line.match(/^\s+/) && accessData.operations.length > 0) {
accessData.operations[accessData.operations.length - 1].description += `\n${line}`;
} else {
if (!accessData.description) {
accessData.description = '';
}
accessData.description += `\n${trimmedLine}`;
}
}
} else {
if (trimmedLine) {
detail.text += `${line}\n`;
}
}
}
// close any dangling footnote
if (inFootnote) {
endFootnoteIfActive();
}
if (currentAccess) {
detail[currentAccess] = accessData;
}
// Push the parsed detail into modes
reg.modes = reg.modes || [];
reg.modes.push(detail);
};