10.12. Position-based AST queries

Position-based AST queries. Given a file, line, and column, finds all expression nodes at that cursor position with innermost-first ordering and enclosing function context. Used for implementing IDE features like goto-definition, type-of, and find-references.

10.12.1. Enumerations

DeclarationKind

What find_declaration_at_cursor or declaration_of found: which of DeclarationHit’s pointers is set.

Values:
  • none = 0 - no declaration

  • func = 1 - a function or generic: func

  • structure = 2 - a struct or class: structure

  • enumeration = 3 - an enumeration: enumeration

  • alias = 4 - a typedef: name and alias_type

  • variable = 5 - a global variable: variable

  • handled = 6 - a C++-bound type: annotation

  • field = 7 - a struct or class field: structure owns it, name and field_type describe it

10.12.2. Structures

CursorHit

A single hit at the cursor position: an expression node, or when asked for a variable declaration or a type name. Innermost hits come first.

Fields:
  • expr : Expression? - Raw pointer to the expression node (valid while the program lives); null for a variable or type hit.

  • variable : Variable? - The variable whose declaration the cursor is on (for/let variable, function, lambda or block argument) when declarations were asked for; else null.

  • type_decl : TypeDecl? - The type the cursor’s type name denotes (a struct, enum or alias spelled in the source) when declarations were asked for; else null.

  • func : Function? - Enclosing function, or null for expressions in global scope.

  • name : string - Extracted name for named nodes (variable name, call name, field name, operator); the type’s name for a type hit.

  • rtti : string - Expression RTTI type string: “ExprVar”, “ExprCall”, “ExprField”, etc.; “Variable” or “TypeDecl” for the other hits.

DeclarationHit

A declaration - the one whose name the cursor is on, or the one a type denotes: at most one of the pointers is set, by kind.

Fields:
  • kind : DeclarationKind - which pointer below is set; none when there is no declaration

  • func : Function? - the function or generic, for func

  • structure : Structure? - the structure or class, for structure; the owner, for field

  • field_type : TypeDecl? - the field’s type, for field

  • enumeration : Enumeration? - the enumeration, for enumeration

  • variable : Variable? - the global variable, for variable

  • alias_type : TypeDecl? - the aliased type, for alias; null when no module of the program declares the typedef

  • annotation : TypeAnnotation? - the C++-bound type’s annotation, for handled

  • name : string - the declared name

  • at : LineInfo - the declaration’s own position; zero for handled and for an alias no module declares

  • word_column : int = -1 - 0-based byte column where the cursor’s word starts on the cursor line; -1 when no cursor word named it

10.12.3. Classes

CursorVisitor : AstVisitor

class CursorVisitor

CursorVisitor.preVisitTypeDecl(typ: TypeDeclPtr )

def preVisitTypeDecl : function<(var self:ast::AstVisitor;typ:ast_core::TypeDecl? aka TypeDeclPtr const):void>

Arguments:
CursorVisitor.preVisitStructureField(str: StructurePtr; decl: FieldDeclaration; last: bool )

def preVisitStructureField : function<(var self:ast::AstVisitor;str:ast_core::Structure? aka StructurePtr const;decl:ast_core::FieldDeclaration const;last:bool const):void>

Arguments:
CursorVisitor.visitStructureField(str: StructurePtr; decl: FieldDeclaration; last: bool )

def visitStructureField : function<(var self:ast::AstVisitor;str:ast_core::Structure? aka StructurePtr const;decl:ast_core::FieldDeclaration const;last:bool const):void>

Arguments:
CursorVisitor.preVisitFunction(fun: FunctionPtr )

def preVisitFunction : function<(var self:ast::AstVisitor;fun:ast_core::Function? aka FunctionPtr const):void>

Arguments:
CursorVisitor.visitFunction(fun: FunctionPtr ): FunctionPtr

def visitFunction : function<(var self:ast::AstVisitor;fun:ast_core::Function? aka FunctionPtr const):ast_core::Function? aka FunctionPtr>

Arguments:
CursorVisitor.preVisitFunctionArgument(fun: FunctionPtr; arg: VariablePtr; lastArg: bool )

def preVisitFunctionArgument : function<(var self:ast::AstVisitor;fun:ast_core::Function? aka FunctionPtr const;arg:ast_core::Variable? aka VariablePtr const;lastArg:bool const):void>

Arguments:
CursorVisitor.preVisitExpression(expr: ExpressionPtr )

def preVisitExpression : function<(var self:ast::AstVisitor;expr:ast_core::Expression? aka ExpressionPtr const):void>

Arguments:
CursorVisitor.preVisitExprBlockArgument(blk: ExprBlock?; arg: VariablePtr; lastArg: bool )

def preVisitExprBlockArgument : function<(var self:ast::AstVisitor;blk:ast_core::ExprBlock? const;arg:ast_core::Variable? aka VariablePtr const;lastArg:bool const):void>

Arguments:
CursorVisitor.preVisitExprLetVariable(expr: ExprLet?; arg: VariablePtr; lastArg: bool )

def preVisitExprLetVariable : function<(var self:ast::AstVisitor;expr:ast_core::ExprLet? const;arg:ast_core::Variable? aka VariablePtr const;lastArg:bool const):void>

Arguments:
CursorVisitor.preVisitExprForVariable(expr: ExprFor?; svar: VariablePtr; last: bool )

def preVisitExprForVariable : function<(var self:ast::AstVisitor;expr:ast_core::ExprFor? const;svar:ast_core::Variable? aka VariablePtr const;last:bool const):void>

Arguments:
CursorVisitor.in_target_file(at: LineInfo ): bool

def in_target_file : function<(var self:ast_cursor::CursorVisitor;at:rtti_core::LineInfo const):bool const>

Arguments:
CursorVisitor.cursor_on_variable(v: Variable const? ): bool

def cursor_on_variable : function<(var self:ast_cursor::CursorVisitor;v:ast_core::Variable const? const):bool const>

Arguments:
CursorVisitor.add_variable_at_cursor(v: Variable const? )

def add_variable_at_cursor : function<(var self:ast_cursor::CursorVisitor;v:ast_core::Variable const? const):void>

Arguments:
CursorVisitor.generated_variable(e: Expression const? ): bool

def generated_variable : function<(var self:ast_cursor::CursorVisitor;e:ast_core::Expression const? const):bool const>

Arguments:
CursorVisitor.on_field_name(e: Expression const? ): bool

def on_field_name : function<(var self:ast_cursor::CursorVisitor;e:ast_core::Expression const? const):bool const>

Arguments:
CursorVisitor.cursor_on_token(at: LineInfo; name: string ): bool

def cursor_on_token : function<(var self:ast_cursor::CursorVisitor;at:rtti_core::LineInfo const;name:string const):bool const>

Arguments:
CursorVisitor(file: string; line: int; col: int; declarations: bool; line_text: string ): CursorVisitor

def CursorVisitor (file: string; line: int; col: int; declarations: bool; line_text: string) : CursorVisitor

Arguments:
  • file : string

  • line : int

  • col : int

  • declarations : bool

  • line_text : string

10.12.4. Cursor queries

cursor_inside(line: int; col: int; at: LineInfo ): bool

Check whether a point (line, col) is inside the span described by at. Follows the same logic as C++ LineInfo::inside.

Arguments:
declaration_of(program: smart_ptr<Program>; td: TypeDecl const? ): DeclarationHit

The declaration a type denotes - its typedef, structure, enumeration or C++-bound annotation; none for a bare type.

Arguments:
find_at_cursor(program: smart_ptr<Program>; file: string; line: int; col: int; declarations: bool = false; line_text: string = "" ): array<CursorHit>

Find all expression nodes at the given cursor position, innermost first; file is a substring of FileInfo.name (”” matches any); nodes inside a synthesized member and compiler-made variables are never hits. With declarations, a cursor on a for/let variable’s or an argument’s name is a variable hit and, given the line’s source as line_text, on a type name a type_decl hit.

Arguments:
  • program : smart_ptr< Program>

  • file : string

  • line : int

  • col : int

  • declarations : bool

  • line_text : string

find_at_cursor_in_function(func: FunctionPtr; file: string; line: int; col: int; declarations: bool = false; line_text: string = "" ): array<CursorHit>

Find all expression nodes at the given cursor position within a single function body. file, declarations and line_text mean what they mean for find_at_cursor.

Arguments:
  • func : FunctionPtr

  • file : string

  • line : int

  • col : int

  • declarations : bool

  • line_text : string

find_declaration_at_cursor(program: smart_ptr<Program>; file: string; line: int; col: int; line_text: string ): DeclarationHit

The declaration whose name is at the cursor, the parent a class line names included; line_text “” makes it a line-only lookup, file is a substring of FileInfo.name.

Arguments:
  • program : smart_ptr< Program>

  • file : string

  • line : int

  • col : int

  • line_text : string

typedef_named(program: smart_ptr<Program>; name: string; mod: Module? = null ): TypeDecl const?

The type declared under the typedef name - in mod when given, else in the program’s own module, else in any module it requires; null when none declares it.

Arguments:

10.12.5. Source text

bare_name(name: string ): string

“Animal`speak” -> “speak”: the token the source spells at a method’s declaration and call sites.

Arguments:
  • name : string

declared_name_column(at: LineInfo; name: string ): int

Where the line a declaration starts on spells its name; at.column when it does not.

Arguments:
name_column(line_text: string; name: string; hint: int ): int

Where line_text spells name as a whole word (0-based byte column), else hint.

Arguments:
  • line_text : string

  • name : string

  • hint : int

source_name(name: string ): string

The name the source spells for a compiler-renamed variable (a generator’s loop variable); any other name unchanged.

Arguments:
  • name : string

spells_name(line_text: string; col: int; name: string ): bool

True when line_text spells name as a whole word starting exactly at col.

Arguments:
  • line_text : string

  • col : int

  • name : string

word_at(line_text: string; col: int ): tuple<word:string;start:int>

The identifier the 0-based byte column col is on in line_text, with its start column; a caret right after a word is on it, as in an editor, and the word is empty when col is on none.

Arguments:
  • line_text : string

  • col : int

10.12.6. Class members

field_at(st: Structure const?; name: string ): LineInfo

Where the field name of st is declared - the parent’s line for an inherited field; a zero position when there is no such field.

Arguments:
field_name_at(expr: Expression const? ): LineInfo

Where a field access spells its field name - a method call’s name sits past the -> its node spans; a zero position for any other node.

Arguments:
is_own_field(fld: FieldDeclaration ): bool

True for a field the source declares in its struct’s or class’s own body - an override included - not one the compiler made (__rtti, __finalize) or a parent’s copy.

Arguments:
value_struct(value: Expression const? ): Structure const?

The struct a field access reads its field from - through a pointer when value is one; null for any other value.

Arguments:

10.12.7. Result inspection

describe(hit: CursorHit ): string

Pretty-print a CursorHit for debugging. Includes RTTI type, name, resolved type, source location, and enclosing function.

Arguments:
hit_at(hit: CursorHit ): LineInfo

The position of the node the hit holds: its expression, variable or type.

Arguments:
is_synthesized(func: Function const? ): bool

True for a member the compiler made on the class line (Foo’__finalize), never for a lambda or generator body or a generic instance.

Arguments: