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:
typ : TypeDeclPtr
- 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:
str : StructurePtr
decl : FieldDeclaration
last : bool
- 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:
str : StructurePtr
decl : FieldDeclaration
last : bool
- CursorVisitor.preVisitFunction(fun: FunctionPtr )
def preVisitFunction : function<(var self:ast::AstVisitor;fun:ast_core::Function? aka FunctionPtr const):void>
- Arguments:
fun : FunctionPtr
- 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:
fun : FunctionPtr
- 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:
fun : FunctionPtr
arg : VariablePtr
lastArg : bool
- CursorVisitor.preVisitExpression(expr: ExpressionPtr )
def preVisitExpression : function<(var self:ast::AstVisitor;expr:ast_core::Expression? aka ExpressionPtr const):void>
- Arguments:
expr : ExpressionPtr
- 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:
blk : ExprBlock?
arg : VariablePtr
lastArg : bool
- 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:
expr : ExprLet?
arg : VariablePtr
lastArg : bool
- 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:
expr : ExprFor?
svar : VariablePtr
last : bool
- 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:
at : LineInfo
- 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:
v : Variable?
- 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:
v : Variable?
- 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:
e : Expression?
- 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:
e : Expression?
- 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:
at : LineInfo
name : string
- 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:
line : int
col : int
at : LineInfo
- 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.
- 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.
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:
at : LineInfo
name : string
- 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:
st : Structure?
name : string
- 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:
expr : Expression?
- 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:
fld : FieldDeclaration
- 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:
value : Expression?
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 : CursorHit
- hit_at(hit: CursorHit ): LineInfo
The position of the node the hit holds: its expression, variable or type.
- Arguments:
hit : CursorHit
- 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:
func : Function?