PPysolate SpineREAD THE CODE · UNDERSTAND THE SYSTEM
课程与章节
源码索引 / CURRENT IMPLEMENTATION

site/scripts/symbols.mjs

30 行 · 点击行号可定位;函数链接随声明位置更新,不手填行号。

// Declaration navigation for this small source set; not a semantic call graph.
export function symbolsFor(name, code) {
  const found = [], scopes = [];
  function add(label, line) {
    const id = 'fn-' + label.replace(/[^a-z0-9]+/gi, '-').replace(/^-|-$/g, '');
    if (found.some(s => s.id === id)) throw new Error(`Duplicate symbol ${name}:${label}`);
    found.push({ label, id, line });
  }
  for (const [index, line] of code.split('\n').entries()) {
    let m;
    if (name.endsWith('.go')) {
      m = line.match(/^func\s+(?:\(\w+\s+\*?(\w+)\)\s*)?(\w+)\s*\(/);
      if (m) add(m[1] ? `${m[1]}.${m[2]}` : m[2], index + 1);
    } else if (name.endsWith('.py')) {
      if (!line.trim() || line.trimStart().startsWith('#')) continue;
      const indent = line.match(/^\s*/)[0].replaceAll('\t', '    ').length;
      while (scopes.length && scopes.at(-1).indent >= indent) scopes.pop();
      m = line.match(/^\s*(?:async\s+)?(def|class)\s+(\w+)/);
      if (m) {
        const label = [...scopes.map(s => s.name), m[2]].join('.');
        add(label, index + 1);
        scopes.push({ name: m[2], indent });
      }
    } else if (name.endsWith('.c')) {
      m = line.match(/^(?:EXPORT\([^)]+\)\s*)?(?:static\s+)?(?:PyObject\s*\*|int32_t|uint64_t|void\s*\*|void)\s*(\w+)\s*\([^;]*\)\s*\{/);
      if (m) add(m[1], index + 1);
    }
  }
  return found;
}