mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-08-16 14:11:33 +00:00
initial plugin setup for syntax highlighting in vscode...
This commit is contained in:
+195
@@ -0,0 +1,195 @@
|
||||
"use strict";
|
||||
|
||||
const { nearestCall } = require("./lexer");
|
||||
const { mergeIndexes, scanSource } = require("./source-index");
|
||||
|
||||
const TOKEN_TYPES = [
|
||||
"tapeAtomKeyword",
|
||||
"tapeAtomName",
|
||||
"tapeComponentKeyword",
|
||||
"tapeComponentName",
|
||||
"tapeAnnotation",
|
||||
"tapeBindType",
|
||||
"tapePhase",
|
||||
"tapeLabel",
|
||||
"tapeCpuInstruction",
|
||||
"tapeControlFlow",
|
||||
"tapeGteInstruction",
|
||||
"tapeGpuInstruction",
|
||||
"tapeComponentInstruction",
|
||||
"tapeDelaySlot",
|
||||
"tapeGprRegister",
|
||||
"tapeCop2Register",
|
||||
"tapeDuffleType",
|
||||
"tapeAttribute",
|
||||
];
|
||||
|
||||
const TOKEN_MODIFIERS = ["declaration", "tapeRead", "tapeWrite", "tapeAuto"];
|
||||
const TOKEN_TYPE_INDEX = new Map(TOKEN_TYPES.map((name, index) => [name, index]));
|
||||
const TOKEN_MODIFIER_INDEX = new Map(TOKEN_MODIFIERS.map((name, index) => [name, index]));
|
||||
|
||||
const ATOM_KEYWORDS = new Set(["MipsAtom_", "MipsAtom_Proc_"]);
|
||||
const COMPONENT_KEYWORDS = new Set(["MipsAtomComp_", "MipsAtomComp_Proc_"]);
|
||||
const ANNOTATIONS = new Set([
|
||||
"atom_info", "atom_bind", "atom_reads", "atom_writes", "atom_label",
|
||||
"atom_offset", "atom_reg", "atom_type", "atom_ctx", "atom_phase",
|
||||
"atom_auto_reg", "phase_auto_reg", "atom_dbg_skip",
|
||||
]);
|
||||
|
||||
const DELAY_SLOT_KEYWORDS = new Set(["LdSlot_", "BdSlot_"]);
|
||||
|
||||
const CONTROL_FLOW_PREFIXES = /^(?:branch_|jump_|call_)/;
|
||||
|
||||
const ROLE_TO_TYPE = {
|
||||
atomName: "tapeAtomName",
|
||||
componentName: "tapeComponentName",
|
||||
bindType: "tapeBindType",
|
||||
duffleType: "tapeDuffleType",
|
||||
gprRegister: "tapeGprRegister",
|
||||
cop2Register: "tapeCop2Register",
|
||||
};
|
||||
|
||||
function registerType(name, index) {
|
||||
const kind = index.registers.get(name);
|
||||
if (kind === "gpr" || /^R_[A-Za-z0-9_]+$/.test(name)) return "tapeGprRegister";
|
||||
if (kind === "cop2" || /^(?:C2_|gte_cr_)[A-Za-z0-9_]+$/.test(name)) return "tapeCop2Register";
|
||||
return null;
|
||||
}
|
||||
|
||||
function instructionType(name, index) {
|
||||
const domain = index.macros.get(name);
|
||||
if (domain === "cpu") return "tapeCpuInstruction";
|
||||
if (domain === "gte") return "tapeGteInstruction";
|
||||
if (domain === "gpu") return "tapeGpuInstruction";
|
||||
if (domain === "component") return "tapeComponentInstruction";
|
||||
if (/^gte_(?!cr_)/.test(name)) return "tapeGteInstruction";
|
||||
if (/^gp[01]_/.test(name)) return "tapeGpuInstruction";
|
||||
if (/^mac_/.test(name)) return "tapeComponentInstruction";
|
||||
return null;
|
||||
}
|
||||
|
||||
function modifierMask(modifiers) {
|
||||
let mask = 0;
|
||||
for (const modifier of modifiers) {
|
||||
const index = TOKEN_MODIFIER_INDEX.get(modifier);
|
||||
if (index !== undefined) mask |= (1 << index);
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
function isRegUseAccess(tokens, tokenIndex) {
|
||||
const prev = tokens[tokenIndex - 1];
|
||||
if (!prev || prev.text !== ".") return false;
|
||||
const prevPrev = tokens[tokenIndex - 2];
|
||||
if (!prevPrev || prevPrev.kind !== "identifier") return false;
|
||||
if (prevPrev.text === "r") return true;
|
||||
const prev3 = tokens[tokenIndex - 3];
|
||||
const prev4 = tokens[tokenIndex - 4];
|
||||
if (prev3 && prev3.text === "." && prev4 && prev4.kind === "identifier" && prev4.text === "r") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function classifyDocument(source, filePath, workspaceIndex, shouldCancel = () => false) {
|
||||
const scanned = scanSource(source, filePath);
|
||||
const index = mergeIndexes(workspaceIndex, scanned.index);
|
||||
const spans = [];
|
||||
|
||||
for (let tokenIndex = 0; tokenIndex < scanned.tokens.length; tokenIndex += 1) {
|
||||
if (shouldCancel()) break;
|
||||
const token = scanned.tokens[tokenIndex];
|
||||
if (token.kind !== "identifier") continue;
|
||||
|
||||
let type = null;
|
||||
let modifiers = [];
|
||||
const declaration = scanned.declarations.get(token.start);
|
||||
const context = nearestCall(scanned.contexts, tokenIndex);
|
||||
|
||||
if (declaration) {
|
||||
type = ROLE_TO_TYPE[declaration.role] || null;
|
||||
modifiers = declaration.modifiers.slice();
|
||||
} else if (ATOM_KEYWORDS.has(token.text)) {
|
||||
type = "tapeAtomKeyword";
|
||||
} else if (COMPONENT_KEYWORDS.has(token.text)) {
|
||||
type = "tapeComponentKeyword";
|
||||
} else if (ANNOTATIONS.has(token.text)) {
|
||||
type = "tapeAnnotation";
|
||||
} else if (context && context.callee === "atom_bind" && context.argIndex === 0) {
|
||||
type = "tapeBindType";
|
||||
} else if (context && context.callee === "atom_phase" && context.argIndex === 0) {
|
||||
type = "tapePhase";
|
||||
modifiers = ["declaration"];
|
||||
} else if (context && context.callee === "atom_ctx" && context.argIndex === 0) {
|
||||
type = "tapeAtomName";
|
||||
} else if (context && context.callee === "atom_label" && context.argIndex === 0) {
|
||||
type = "tapeLabel";
|
||||
modifiers = ["declaration"];
|
||||
} else if (context && context.callee === "atom_offset" && context.argIndex <= 1) {
|
||||
type = "tapeLabel";
|
||||
} else if (context && context.callee === "atom_reads") {
|
||||
type = registerType(token.text, index);
|
||||
if (type) modifiers = ["tapeRead"];
|
||||
} else if (context && context.callee === "atom_writes") {
|
||||
type = registerType(token.text, index);
|
||||
if (type) modifiers = ["tapeWrite"];
|
||||
} else if (context && context.callee === "atom_auto_reg") {
|
||||
if (context.argIndex === 0) type = "tapeAtomName";
|
||||
if (context.argIndex === 1) {
|
||||
type = "tapeGprRegister";
|
||||
modifiers = ["declaration", "tapeAuto"];
|
||||
}
|
||||
} else if (context && context.callee === "phase_auto_reg") {
|
||||
if (context.argIndex === 0) type = "tapePhase";
|
||||
if (context.argIndex === 1) {
|
||||
type = "tapeGprRegister";
|
||||
modifiers = ["declaration", "tapeAuto"];
|
||||
}
|
||||
}
|
||||
|
||||
if (!type && index.bindTypes.has(token.text)) type = "tapeBindType";
|
||||
if (!type && index.types.has(token.text)) type = "tapeDuffleType";
|
||||
if (!type && index.attributes.has(token.text)) type = "tapeAttribute";
|
||||
if (!type) type = registerType(token.text, index);
|
||||
if (!type && DELAY_SLOT_KEYWORDS.has(token.text)) type = "tapeDelaySlot";
|
||||
if (!type) {
|
||||
const domain = index.macros.get(token.text);
|
||||
if (domain && CONTROL_FLOW_PREFIXES.test(token.text)) {
|
||||
type = "tapeControlFlow";
|
||||
}
|
||||
}
|
||||
if (!type && isRegUseAccess(scanned.tokens, tokenIndex)) type = "tapeGprRegister";
|
||||
if (!type) type = instructionType(token.text, index);
|
||||
if (!type && index.atoms.has(token.text)) type = "tapeAtomName";
|
||||
if (!type && index.components.has(token.text)) type = "tapeComponentName";
|
||||
if (!type && index.phases.has(token.text)) type = "tapePhase";
|
||||
if (!type && index.labels.has(token.text)) type = "tapeLabel";
|
||||
if (!type) continue;
|
||||
|
||||
spans.push({
|
||||
text: token.text,
|
||||
type,
|
||||
typeIndex: TOKEN_TYPE_INDEX.get(type),
|
||||
modifiers,
|
||||
modifierMask: modifierMask(modifiers),
|
||||
start: token.start,
|
||||
length: token.end - token.start,
|
||||
line: token.line,
|
||||
character: token.character,
|
||||
});
|
||||
}
|
||||
|
||||
spans.sort((left, right) => left.start - right.start || left.length - right.length);
|
||||
const nonOverlapping = [];
|
||||
for (const span of spans) {
|
||||
const previous = nonOverlapping[nonOverlapping.length - 1];
|
||||
if (!previous || previous.start + previous.length <= span.start) nonOverlapping.push(span);
|
||||
}
|
||||
|
||||
return { spans: nonOverlapping, errors: scanned.errors };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
TOKEN_MODIFIERS,
|
||||
TOKEN_TYPES,
|
||||
classifyDocument,
|
||||
modifierMask,
|
||||
};
|
||||
Reference in New Issue
Block a user