157 lines
6.0 KiB
TypeScript
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);
|
|
}; |