✨ feat(vscode): 代码阅读把推导式换成按读的顺序重排的遍历小框
This commit is contained in:
1 parent
677fb7da1f
commit
6416cdf714
16 files changed
+641
-91
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import type { Access, BlockShape, ClassFacts, CodeBlock, EntryFacts, FunctionFacts, ImportFacts, ImportItem, LanguageAdapter, Node, ParameterFacts, TextKind, TokenRole } from '../contract'
|
||||
import type { Access, BlockShape, ClassFacts, CodeBlock, EntryFacts, FunctionFacts, ImportFacts, ImportItem, IterationClause, IterationFacts, IterationResult, LanguageAdapter, Node, ParameterFacts, TextKind, TokenRole } from '../contract'
|
||||
import type { CommentRules } from './shared'
|
||||
import * as path from 'node:path'
|
||||
import { children, compoundShape, leafBlock, leafShape, listBlocks, named, sameNode, syntaxChildren } from './shared'
|
||||
@@ -258,6 +258,54 @@ function dictionaryEntries(value: Node | null): EntryFacts[] | undefined {
|
||||
})
|
||||
}
|
||||
|
||||
const ITERATION_RESULTS: Record<string, IterationResult> = {
|
||||
generator_expression: 'generator',
|
||||
list_comprehension: 'list',
|
||||
set_comprehension: 'set',
|
||||
dictionary_comprehension: 'dict',
|
||||
}
|
||||
|
||||
/**
|
||||
* 推导式、生成器表达式的结构,别的节点没有。几种读不成遍历的写法也没有,照常翻:
|
||||
* `for x in a, b`(语法树认、Python 3 不认的多个来源),以及缺了变量、来源、条件或每一项的值(写到一半的代码)。
|
||||
*/
|
||||
export function pythonIteration(node: Node): IterationFacts | undefined {
|
||||
const result = ITERATION_RESULTS[node.type]
|
||||
const body = node.childForFieldName('body')
|
||||
if (!result || !body)
|
||||
return undefined
|
||||
const clauses: IterationClause[] = []
|
||||
for (const child of syntaxChildren(node)) {
|
||||
if (child.type === 'for_in_clause') {
|
||||
const variables = child.childForFieldName('left')
|
||||
const sources = child.childrenForFieldName('right').filter(source => source !== null)
|
||||
if (!variables || sources.length !== 1)
|
||||
return undefined
|
||||
clauses.push({ kind: 'for', variables, source: sources[0], async: child.children.some(token => token?.type === 'async') })
|
||||
}
|
||||
else if (child.type === 'if_clause') {
|
||||
const [condition] = syntaxChildren(child)
|
||||
if (!condition)
|
||||
return undefined
|
||||
clauses.push({ kind: 'if', condition })
|
||||
}
|
||||
}
|
||||
if (clauses[0]?.kind !== 'for')
|
||||
return undefined
|
||||
const key = result === 'dict' ? body.childForFieldName('key') : undefined
|
||||
const value = result === 'dict' ? body.childForFieldName('value') : body
|
||||
if (!value || key === null)
|
||||
return undefined
|
||||
const facts: IterationFacts = { result, clauses, value, ...(key && { key }) }
|
||||
// 调用唯一的参数是生成器表达式时只写一对括号(f(x for x in y)),语法树把这对括号算给生成器
|
||||
const call = node.parent
|
||||
const open = node.child(0)
|
||||
const close = node.child(node.childCount - 1)
|
||||
if (result === 'generator' && call?.type === 'call' && sameNode(call.childForFieldName('arguments'), node) && open && close)
|
||||
facts.sharedParentheses = { open, close }
|
||||
return facts
|
||||
}
|
||||
|
||||
/** elif / else 展平成紧跟 if 的兄弟块。 */
|
||||
function ifBlocks(node: Node): CodeBlock[] {
|
||||
const blocks = [bodyBlock('if', node, bodyOf(node), 'other')]
|
||||
|
||||
Reference in new issue
Block a user