@@ -18,6 +18,7 @@ import {
1818 type StatementHandlers ,
1919} from "./generic-cfg-builder" ;
2020import { treeSitterNoNullNodes } from "./hacks.ts" ;
21+ import { extractCapturedTextsByCaptureName } from "./query-utils.ts" ;
2122import { type SwitchOptions , buildSwitch , collectCases } from "./switch-utils" ;
2223
2324export const goLanguageDefinition = {
@@ -28,6 +29,7 @@ export const goLanguageDefinition = {
2829 "method_declaration" ,
2930 "func_literal" ,
3031 ] ,
32+ extractFunctionName : extractGoFunctionName ,
3133} ;
3234
3335const processBreakStatement = labeledBreakProcessor ( `
@@ -419,3 +421,118 @@ function processSwitchlike(
419421
420422 return blockHandler . update ( { entry : headNode , exit : mergeNode } ) ;
421423}
424+
425+ const functionQuery = {
426+ functionDeclaration : `(function_declaration
427+ name :(identifier) @name)` ,
428+
429+ methodDeclaration : `(method_declaration
430+ name: (field_identifier) @name)` ,
431+
432+ shortVarDeclaration : `(short_var_declaration
433+ left: (expression_list (identifier) @name))` ,
434+
435+ varSpec : `(var_spec
436+ name: (identifier) @name)` ,
437+
438+ assignmentStatement : `(assignment_statement
439+ left: (expression_list
440+ [
441+ (identifier) @name
442+ (selector_expression) @name
443+ ]))` ,
444+
445+ captureName : "name" ,
446+ } ;
447+
448+ // Find the variable or field name bound to a function literal
449+ function findVariableBinding ( func : SyntaxNode ) : string | undefined {
450+ const parent = func . parent ;
451+ if ( ! parent ) return undefined ;
452+
453+ // Walk the right-hand expression list and find the index of *this* func literal.
454+ // I compare by node id to be safe - same node, same id.
455+ const findFuncIndex = (
456+ funcNode : SyntaxNode ,
457+ right : SyntaxNode ,
458+ ) : number | null => {
459+ const index = right . namedChildren . findIndex (
460+ ( child ) => child ?. type === "func_literal" && child . id === funcNode . id ,
461+ ) ;
462+
463+ if ( index !== - 1 ) {
464+ return index ;
465+ }
466+ return null ;
467+ } ;
468+
469+ // We run the left query -> get names[], locate our func literal on the right -> get index,
470+ // then names[index] is the binding.
471+ // If nothing matches, return undefined.
472+ const bindFromPair = (
473+ node : SyntaxNode ,
474+ leftPattern : string ,
475+ rightField : "right" | "value" = "right" ,
476+ ) : string | undefined => {
477+ const left = extractCapturedTextsByCaptureName (
478+ node ,
479+ leftPattern ,
480+ functionQuery . captureName ,
481+ ) ;
482+ const right = node . childForFieldName ( rightField ) ;
483+ if ( ! right ) return undefined ;
484+
485+ const bindingIndex = findFuncIndex ( func , right ) ;
486+ if ( bindingIndex !== null ) {
487+ return left [ bindingIndex ] ?? undefined ;
488+ }
489+ return undefined ;
490+ } ;
491+
492+ switch ( parent . parent ?. type ) {
493+ // := short var declaration
494+ case "short_var_declaration" :
495+ return bindFromPair (
496+ parent . parent ,
497+ functionQuery . shortVarDeclaration ,
498+ "right" ,
499+ ) ;
500+
501+ // = plain assignment ...
502+ case "assignment_statement" :
503+ return bindFromPair (
504+ parent . parent ,
505+ functionQuery . assignmentStatement ,
506+ "right" ,
507+ ) ;
508+
509+ // var x, y = ..., func(){}, ...
510+ // Same idea, but Go’s var spec uses "value".
511+ case "var_spec" :
512+ return bindFromPair ( parent . parent , functionQuery . varSpec , "value" ) ;
513+
514+ default :
515+ return undefined ;
516+ }
517+ }
518+
519+ function extractGoFunctionName ( func : SyntaxNode ) : string | undefined {
520+ switch ( func . type ) {
521+ case "function_declaration" :
522+ return extractCapturedTextsByCaptureName (
523+ func ,
524+ functionQuery . functionDeclaration ,
525+ functionQuery . captureName ,
526+ ) [ 0 ] ;
527+ case "method_declaration" :
528+ return extractCapturedTextsByCaptureName (
529+ func ,
530+ functionQuery . methodDeclaration ,
531+ functionQuery . captureName ,
532+ ) [ 0 ] ;
533+ case "func_literal" :
534+ return findVariableBinding ( func ) ;
535+ default :
536+ return undefined ;
537+ }
538+ }
0 commit comments