---
warning: DO NOT CHANGE THIS MANUALLY, THIS IS GENERATED BY https://github.com/duckdb/community-extensions repository, check README there
title: sitting_duck
excerpt: |
DuckDB Community Extensions
Parse and analyze source code ASTs from 28 programming languages with tree-sitter grammars, pattern matching, and structural search
extension:
name: sitting_duck
description: Parse and analyze source code ASTs from 28 programming languages with tree-sitter grammars, pattern matching, and structural search
version: 1.18.1
language: C++
build: cmake
license: Apache-2.0
maintainers:
- teaguesterling
repo:
github: teaguesterling/sitting_duck
# v1.18 REQUIRES DUCKDB 2.0, so `ref` and `variegata` are no longer the same
# commit. sitting_duck's duckdb submodule pin moved to the v2.0.0 tag and the
# v1.5 build leg was removed from its own CI.
#
# ref, ref_next -> v1.18.1, for the 2.0 line
# variegata -> held at v1.17.0, so DuckDB v1.5.6 keeps the artifact it
# has today
#
# `variegata` is unchanged on purpose: the v1.5.6 leg then skips and its
# existing artifact stays in place. Stated plainly, so nobody is surprised:
# under this entry's `version: 1.18.1`, v1.5.6 continues to serve
# sitting_duck v1.17.0. Only the 2.0 line moves.
#
# WHY v1.5.6 IS STILL OFFERED: ast_select is about 28x slower per call on the
# 2.0 line. Measured with one variable changed, 0.448 s against 12.537 s. The
# cost is planning, not execution, and PREPARE does not amortize it. It is an
# upstream planner regression, duckdb/duckdb#26036. It no longer reproduces on
# duckdb main, but that fix is not in any release.
ref: 30704be97ef09c416ea97bfd2071e2894fabec2a
variegata: cee95ef6eeb33aa6c25527769d3ebf97898aa994
#
# v1.18.0 CHANGED OUTPUT, so re-measure if you pin values. ast_type_map()
# gained a `native_strategy` column at index 8, which moves `flags` from 8 to
# 9. Four native-extraction paths that returned populated but WRONG values now
# return correct ones: python type annotations, swift call arguments, and lua
# local visibility and modifier scope. v1.18.1 adds an opt-in `peek :=`
# parameter to ast_select and corrects the ast_unparse documentation.
# Notes: https://github.com/teaguesterling/sitting_duck/blob/main/docs/releases/v1.18.1.md
#
# EVIDENCE: run 41990901070 on the extension repo, at the commit `ref` names, is
# completed/success with no job outside success and skipped, over 17 platform
# legs. https://github.com/teaguesterling/sitting_duck/actions/runs/41990901070
#
# The suite RUNS against DuckDB v2.0.0 -- the version this registry builds --
# on all four platforms where the harness runs it, with identical counts:
#
# linux_amd64 ran tests: 168 passed, 5 skipped in 1310s
# osx_arm64 ran tests: 168 passed, 5 skipped in 3264s
# windows_amd64 ran tests: 168 passed, 5 skipped in 3820s
# windows_amd64_mingw ran tests: 168 passed, 5 skipped in 3899s
#
# A fifth leg pins the same v2.0.0 tag with ci-tools `main` and reports
# ran tests: 168 passed, 5 skipped in 1325s on linux_amd64.
#
# The rest is COMPILE evidence, stated so a green "Test" step is not over-read.
# On `linux_arm64` the harness itself declines: "Tests are not supported for
# linux_arm64." The three wasm targets have no test step. A separate leg
# builds the moving `v2.0-cyanoptera` branch with `skip_tests: true`, whose
# Test step prints "Tests skipped by workflow input."
ref_next: 30704be97ef09c416ea97bfd2071e2894fabec2a
docs:
hello_world: |
-- Parse Python code and find function definitions
SELECT name, start_line, peek
FROM parse_ast('
def hello():
return "hello world"
def greet(name):
print(f"Hello, {name}!")
return name
', 'python')
WHERE is_function_definition(semantic_type);
-- Pattern matching: find eval() calls and capture arguments
SELECT captures['X'].peek as dangerous_input, file_path, start_line
FROM ast_match('code', 'eval(__X__)', 'python');
-- Pattern matching with variadic wildcards
SELECT captures['F'].name as func_name, captures['Y'].peek as return_value
FROM ast_match('code',
'def __F__(__):
%__
__%
return __Y__', 'python');
-- Security audit: find dangerous function calls
SELECT * FROM ast_security_audit('code')
WHERE risk_level = 'high';
-- Function complexity metrics
SELECT name, cyclomatic, max_depth, lines
FROM ast_function_metrics('code')
WHERE cyclomatic > 10;
-- Cross-language analysis with semantic types
SELECT language, COUNT(*) as functions
FROM read_ast(['src/**/*.py', 'src/**/*.js', 'src/**/*.go'])
WHERE is_function_definition(semantic_type)
GROUP BY language;
extended_description: |
Sitting Duck is a DuckDB extension for parsing source code into Abstract Syntax Trees (ASTs)
using tree-sitter grammars. It provides a powerful SQL interface to analyze, search, and
understand code structure across 25+ programming languages.
**Documentation:** https://sitting-duck.readthedocs.io/
## Core Features
**Pattern Matching:**
Find code structures using pattern-by-example matching with wildcards:
```sql
-- Recursive wildcards for deep matching
SELECT * FROM ast_match('code', 'class __C__: %__<**>__% def __M__(self): %____%', 'python');
-- Optional and negation wildcards
SELECT * FROM ast_match('code', 'def __F__(____): %____%', 'python');
```
See: https://sitting-duck.readthedocs.io/en/latest/guide/pattern-matching/
**CSS Selector Queries (v1.6.0, enhanced in v1.7.0+):**
Query AST nodes using CSS selector syntax — bootstrapped with sitting duck's own CSS grammar:
```sql
SELECT name FROM ast_select('src/*.py', '.func:has(.call#execute):not(:has(try_statement))');
-- v1.7.0: :match (current-node) vs :contains (subtree) structural patterns
SELECT name FROM ast_select('src/*.py', '.func:contains("db.execute()")');
SELECT name FROM ast_select('src/*.py', 'call:match("db.execute()")');
-- v1.7.2: parse once, query many — orders of magnitude faster for interactive use
CREATE TABLE my_ast AS SELECT * FROM read_ast('src/**/*.py');
SELECT * FROM ast_select_from('my_ast', '.class:named');
SELECT * FROM ast_select_from('my_ast', '.func:has(return_statement)');
```
Supports type selectors, `#name`, `.semantic` (~80 aliases), combinators, `:has()`, `:not()`,
`:match()` / `:contains()` structural patterns, scope/call-graph pseudo-classes, and pseudo-element navigation.
Bare type matching: `if` matches `if` + `if_statement` + `if_clause`.
v1.10.0 adds runtime-loadable tree-sitter grammars (`register_language()`, off by
default behind `sitting_duck_enable_runtime_grammars`), `ast_to_blocks` (render code
structure as duck_blocks documents), and `ast_patch`/`ast_replace` (AST-anchored
source patching and selector-driven rewriting in SQL).
v1.9.0 hardens the selector engine: no more silent-empty results (selectors the engine
can't honor now raise a clear error instead of returning 0 rows), `#name` on call nodes
binds uniformly across all 27 grammars, and NULL columns no longer over- or under-match.
**Parse-time filtering (v1.8.0):**
`max_depth :=` and `prune :=` shrink the AST at parse time, with automatic tree healing:
```sql
SELECT * FROM read_ast('file.py', max_depth := 2);
SELECT * FROM read_ast('src/**/*.py', prune := ['syntax', 'comments', 'punctuation']);
```
Prune policies: `syntax`, `comments`, `literals`, `imports`, `types`, `punctuation`,
`unnamed`, `leaves`, `internal`.
**Call-graph macros (v1.8.0):**
- `ast_get_calls(source)` - calls with caller attribution and type classification
- `ast_call_graph(source)` - aggregated caller→callee graph with call counts
- `ast_find_references(source, name)` - scope-chain-aware symbol reference resolution
**Table Functions:**
- `read_ast(file_pattern, language := NULL)` - Parse source files into AST rows (parallel)
- `parse_ast(content, language)` - Parse source code strings (table function)
- `parse_ast_list(content, language)` - Parse source code strings (scalar, returns LIST; v1.7.0)
- `ast_match(source, pattern, lang)` - Pattern matching for code search
- `ast_select(source, css_selector)` - CSS selector queries
- `ast_select_from(table_name, selector)` - CSS selectors on pre-parsed tables (v1.7.2)
- `ast_type_map(language)` - Node type discovery across languages
**v1.7.0 extraction suffix:**
Any extraction parameter (`context`, `source`, `structure`, `peek`) can take a `+schema`
suffix that keeps the full column set in the output schema as NULLs without computing them:
```sql
-- Keep peek column in schema but skip its computation
SELECT name, peek FROM read_ast('file.py', peek := 'none+schema');
```
Enables SQL macros to declare stable schemas regardless of which columns they populate.
**Relational Predicates (v1.5.0):**
- `ast_has(source, parent_type, child_type)` - Check containment relationships
- `ast_inside(source, child_type, parent_type, parent_name)` - Find nodes inside specific parents
- `ast_precedes(source, before_type, after_type)` - Ordering predicates
- `ast_follows(source, after_type, before_type)` - Ordering predicates
- `ast_not_has(source, parent_type, child_type)` - Negated containment
**Analysis Macros (file-path based):**
- `ast_definitions(source)` - All named definitions with categories
- `ast_function_metrics(source)` - Cyclomatic complexity, nesting depth, line counts
- `ast_security_audit(source)` - Detect dangerous function call patterns
- `ast_dead_code(source)` - Find potentially unused functions/classes
- `ast_nesting_analysis(source)` - Identify deeply nested code
- `ast_definition_parent(table)` - Resolve nearest definition ancestor per node
**Tree Navigation:**
- `ast_descendants(table, node_id)` - Get subtree (O(1) using descendant_count)
- `ast_ancestors(table, node_id)` - Path from node to root
- `ast_children(table, node_id)` - Immediate children
- `ast_function_scope(table, node_id)` - Function body excluding nested functions
**Semantic Predicates:**
Cross-language filtering with normalized types:
- `is_function_definition(st)`, `is_class_definition(st)`, `is_variable_definition(st)`
- `is_function_call(st)`, `is_literal(st)`, `is_conditional(st)`, `is_loop(st)`
## Supported Languages (27)
| Category | Languages |
|----------|-----------|
| **Web** | JavaScript, TypeScript, HTML, CSS |
| **Systems** | C, C++, Go, Rust, Zig |
| **Scripting** | Python, Ruby, PHP, Lua, R, Bash |
| **Enterprise** | Java, C#, Kotlin, Swift |
| **Mobile** | Dart |
| **Data** | SQL, JSON, TOML, GraphQL, HCL |
| **Documentation** | Markdown |
## AST Schema
Each parsed node includes:
- `type`, `name` - Node type and extracted identifier
- `semantic_type` - Normalized type for cross-language queries
- `file_path`, `language` - Source location
- `start_line`, `end_line`, `depth` - Position and nesting
- `descendant_count` - For O(1) subtree queries
- `peek` - Configurable source preview
- `qualified_name` - Scope-based path unique within a file (`C[User] F[__init__]` format; v1.7.0)
- `signature_type`, `parameters`, `modifiers`, `annotations` - Native extraction
(v1.8.0: `modifiers[]` populated across Python, JS, TS, Rust, Kotlin, Swift, Dart, C#;
`IS_EXPORTED` flag for file-level visibility)
- `scope` - STRUCT (v1.7.4); replaces
the v1.7.2 `scope_id` / `scope_stack` columns. `scope.function` lets you
answer "what function is this in?" as a single column read.
Full schema: https://sitting-duck.readthedocs.io/en/latest/api/output-schema/
## Use Cases
- **Security auditing** - Find dangerous patterns (eval, exec, SQL injection)
- **Code quality** - Complexity metrics, dead code detection, nesting analysis
- **Refactoring** - Pattern-based code search across large codebases
- **Documentation** - Extract function signatures and structure
- **AI workflows** - Structured code understanding for LLM tools
**GitHub:** https://github.com/teaguesterling/sitting_duck
extension_star_count: 36
extension_star_count_pretty: 36
extension_download_count: 1132
extension_download_count_pretty: 1.1k
image: '/images/community_extensions/social_preview/preview_community_extension_sitting_duck.png'
layout: community_extension_doc
---
### Compatibility Matrix
This table covers all DuckDB releases that have not reached [end-of-life](https://duckdb.org/release_calendar), including LTS releases, and shows the 2 most recent patch releases of each. Older patch releases are not listed, but the extension may be available for them as well.
| Platform | 1.4.4 | 1.4.5 | 1.5.5 | 1.5.6 | 2.0.0 |
| :--- | :---: | :---: | :---: | :---: | :---: |
| Linux AMD64 | ✅ | ❌ | ✅ | ✅ | ✅ |
| Linux ARM64 | ✅ | ❌ | ✅ | ✅ | ✅ |
| macOS AMD64 | ✅ | ❌ | ✅ | ✅ | ✅ |
| macOS ARM64 | ✅ | ❌ | ✅ | ✅ | ✅ |
| Windows AMD64 | ✅ | ❌ | ✅ | ✅ | ✅ |
| Windows ARM64 | ❌ | ❌ | ❌ | ❌ | ❌ |
| WebAssembly | ✅ | ❌ | ✅ | ✅ | ✅ |
### Installing and Loading
```sql
INSTALL {{ page.extension.name }} FROM community;
LOAD {{ page.extension.name }};
```
{% if page.docs.hello_world %}
### Example
```sql
{{ page.docs.hello_world }}```
{% endif %}
{% if page.docs.extended_description %}
### About {{ page.extension.name }}
{{ page.docs.extended_description }}
{% endif %}
### Added Functions
| function_name | function_type | description | comment | examples |
|----------------------------------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ast_ancestors | table_macro | The ancestor chain from a node up to the root | NULL | |
| ast_call_arguments | table_macro | Argument nodes of a call, from its argument_list child | NULL | |
| ast_call_graph | table_macro | Caller to callee edges derived from the call sites | NULL | |
| ast_callees | table_macro | What does each function call? | NULL | [SELECT * FROM ast_callees('src/**/*.py');, SELECT caller, callee FROM ast_callees('src/*.py') WHERE caller = 'main';] |
| ast_callers | table_macro | Who calls a given function? | NULL | [SELECT * FROM ast_callers('src/**/*.py');, SELECT caller, callee FROM ast_callers('src/*.py') WHERE callee = 'execute';] |
| ast_capture | macro | Pull one named capture out of a match captures map | NULL | |
| ast_children | table_macro | Direct children of a node in a parsed AST table | NULL | |
| ast_class_members | table_macro | Members declared directly inside one class | NULL | |
| ast_containing_line | table_macro | Nodes whose source span covers a given line number | NULL | |
| ast_dead_code | table_macro | Definitions with no reference elsewhere in the source, with the reason | NULL | |
| ast_definition_parent | table_macro | The nearest enclosing definition for every node in an AST table | NULL | |
| ast_definitions | table_macro | Every definition (function, class, variable, module) in the source | NULL | |
| ast_descendants | table_macro | Every node beneath an ancestor, via its descendant_count range | NULL | |
| ast_dispatch_predicate | macro | NULL | NULL | |
| ast_exports | table_macro | Module-level definitions visible outside the file | NULL | [SELECT * FROM ast_exports('src/**/*.py');, SELECT name, type FROM ast_exports('src/*.go') WHERE name = upper(left(name, 1)) \|\| right(name, -1);] |
| ast_find_references | table_macro | Find all uses of a symbol via scope-chain resolution | NULL | [SELECT * FROM ast_find_references('src/**/*.py', 'process');, SELECT * FROM ast_find_references('src/main.py', 'x') WHERE ref_kind = 'call';, SELECT * FROM ast_find_references('src/*.py', 'Service', language := 'python');] |
| ast_follows | table_macro | Nodes of one type that appear after a node of another type | NULL | |
| ast_function_metrics | table_macro | Per-function size and complexity: lines, return_count, conditionals, loops, cyclomatic | NULL | |
| ast_function_scope | table_macro | Every node inside one function definition | NULL | |
| ast_functions_containing | table_macro | Functions that contain at least one node of a given type | NULL | |
| ast_get_calls | table_macro | Call sites in the source, with the enclosing function | NULL | |
| ast_get_source | macro | Raw source text for a line range of a file | NULL | |
| ast_get_source_line | macro | A single line of source text from a file | NULL | |
| ast_get_source_numbered | macro | Source text for a line range, each line prefixed with its number | NULL | |
| ast_has | table_macro | Nodes of one type that contain a node of another type | NULL | |
| ast_imports | table_macro | Import statements with source module and imported names | NULL | [SELECT * FROM ast_imports('src/**/*.py');, SELECT source_module, imported_name FROM ast_imports('src/*.js');] |
| ast_in_range | table_macro | Nodes whose source span falls inside a line range | NULL | |
| ast_inside | table_macro | Nodes of one type that sit inside a node of another type | NULL | |
| ast_match | table_macro | Find nodes matching a structural pattern, with wildcard captures | NULL | [SELECT * FROM ast_match('src/**/*.py', 'my_func(__X__)');, SELECT * FROM ast_match('src/main.py', 'my_func(__X__)', match_syntax := true);, SELECT * FROM ast_match('src/**/*.py', '__F__(__X__)', match_by := 'semantic_type');] |
| ast_nesting_analysis | table_macro | Per-function nesting depth: max_depth, avg_depth, deep_nodes, total_nodes | NULL | |
| ast_node_edit | macro | build a well-formed edit STRUCT from an AST row's location columns. `node` is any STRUCT/row with file_path, start_line, start_column, end_line, end_column — pass the table alias of a read_ast(...) scan directly. Expand to columns with unnest(...): | NULL | [SELECT unnest(ast_node_edit(r, 'replace', 'renamed_fn')), SELECT unnest(ast_node_edit(r, 'replace', 'new_text'))] |
| ast_not_has | table_macro | Nodes of one type that do NOT contain a node of another type | NULL | |
| ast_patch | table_macro | apply edit rows to their files, returning patched text | NULL | [SELECT * FROM ast_patch('edits', 'src/main.py');] |
| ast_pattern | table_macro | Parse a pattern string into its node sequence | NULL | |
| ast_pattern_list | macro | Parse a pattern string into a list of pattern tokens | NULL | |
| ast_peek_contains_any | scalar | Case-sensitive search checking if peek string contains any pattern in the list (alias of string_contains_any). | NULL | [ast_peek_contains_any(peek, ['import', 'require'])] |
| ast_precedes | table_macro | Nodes of one type that appear before a node of another type | NULL | |
| ast_qualified_name_as_string | macro | NULL | NULL | |
| ast_replace | table_macro | one-shot selector-driven replacement — match nodes with a CSS selector (the ast_select engine), replace each match's exact byte range with new_text, return the patched text per file | NULL | |
| ast_resolve | table_macro | Resolve references to their definitions via scope chain | NULL | [SELECT * FROM ast_resolve('src/main.py');, SELECT r.ref_name, r.def_line, r.scope_hops FROM ast_resolve('src/*.py') r;] |
| ast_resolve_entity | table_macro | Find a named entity by name and optional kind, within one file | NULL | [SELECT * FROM ast_resolve_entity('src/app.py', 'run', kind := 'function');] |
| ast_security_audit | table_macro | Risk-pattern findings per function: risk_category, risk_level, finding, matched_pattern | NULL | |
| ast_select | table_macro | convenience wrapper that parses source files and then runs the selector engine. For one-off queries this is the simplest API. For repeated queries, use ast_select_from with a pre-parsed table | NULL | |
| ast_select_from | table_macro | the selector engine, operates on a pre-parsed AST table. The `source` parameter is a table name (string) resolved via query_table(). This separates parsing (expensive) from querying (cheap), enabling callers to parse once and query many times with different selectors | NULL | [SELECT * FROM ast_select_from('my_ast', '.class:named');, SELECT * FROM ast_select_from('my_ast', '.func:has(return_statement)');] |
| ast_select_list | table_macro | nested form, one row per rule with matches packed as LIST | NULL | |
| ast_select_rules | table_macro | Run several CSS selector rules at once, one row per match | NULL | |
| ast_selector_for | table_macro | node -> selector ("Copy selector", as in browser devtools) | NULL | [SELECT * FROM ast_selector_for('my_ast', 'src/app.py', 42);] |
| ast_semantic_aliases | table | Return every semantic class usable in an ast_select selector (e.g. .fn, .call, .def), what it resolves to, and how broadly it matches. | NULL | [SELECT selector, resolves_to FROM ast_semantic_aliases() ORDER BY selector] |
| ast_siblings | table_macro | Nodes sharing a parent with the target node | NULL | |
| ast_source_bytes | scalar | Read a file's pristine bytes as a BLOB, one row at a time. NULL when the path does not exist (including the '' pseudo-path of parse_ast()). This is the per-row substrate byte-exact unparse needs, which read_blob() cannot provide because table functions take only constant arguments. | NULL | [SELECT ast_source_bytes('src/main.py'), SELECT fp, ast_source_bytes(fp) AS cblob FROM (SELECT DISTINCT file_path AS fp FROM nodes)] |
| ast_source_of | table_macro | Source text for matched nodes, keyed by file pattern | NULL | [SELECT * FROM ast_source_of('src/**/*.py', 'process_payment');, SELECT * FROM ast_source_of('src/**/*.py', 'MyClass', kind := 'class');, SELECT * FROM ast_source_of('src/**/*.py', 'handler', language := 'python', kind := 'function');] |
| ast_supported_languages | table | Return list of supported programming and markup languages and their registered grammar metadata. | NULL | [SELECT * FROM ast_supported_languages()] |
| ast_to_blocks | table_macro | convenience wrapper that parses source files (with the peek := 'full' that complete bodies require) and delegates to the converter engine. Same CTE-delegation pattern as ast_select -> ast_select_from | NULL | |
| ast_to_blocks_from | table_macro | the converter engine, operates on a pre-parsed AST table (name resolved via query_table). Parse once with read_ast(..., peek := 'full'), convert many times with different styles | NULL | |
| ast_to_blocks_list | table_macro | one row per file with the blocks pre-aggregated into a LIST(duck_block) ready for consumers that take a whole document, e.g. duck_block_utils rendering: | NULL | |
| ast_type_map | table | Return mapping of AST node types to semantic types and extraction strategies. | NULL | [SELECT * FROM ast_type_map(), SELECT * FROM ast_type_map('python')] |
| ast_unparse | table_macro | Reconstruct source text from a file path, using a formatting preset | NULL | |
| ast_unparse_code | table_macro | Reconstruct source text from a code string, using a formatting preset | NULL | |
| ast_unparse_custom | table_macro | Reconstruct source text using caller-supplied formatting rules | NULL | |
| ast_unparse_exact | table_macro | Reproduce a file byte-for-byte from its AST, or refuse — no normalising | NULL | |
| ast_unparse_exact_code | table_macro | Reproduce a code string byte-for-byte through a parse round-trip | NULL | |
| ast_unparse_exact_from | table_macro | Reproduce files byte-for-byte from an existing AST table | NULL | |
| ast_unparse_exact_splice | table_macro | the shared core. You normally want `ast_unparse_exact(path)`; this is exposed because it is the one place the splice lives, and because it is useful on its own | NULL | |
| ast_unparse_from | table_macro | Reconstruct source text from an AST table, using a formatting preset | NULL | |
| ast_unparse_rules | table | Return active unparse layout and spacing rules. | NULL | [SELECT * FROM ast_unparse_rules(), SELECT * FROM ast_unparse_rules('python'), SELECT * FROM ast_unparse_rules('python', 'black'), SELECT * FROM ast_unparse_rules('go', 'gofmt')] |
| binds_name | scalar | Returns true if node binds a name in lexical scope (definition or declaration). | NULL | [binds_name(flags)] |
| clean_pattern | macro | NULL | NULL | |
| detect_language | scalar | Detect tree-sitter language name from file extension, or return NULL if unknown. | NULL | [detect_language('src/main.rs')] |
| get_kind | scalar | Get the primary kind name (FUNCTION, CLASS, VARIABLE, etc.) for a semantic type. | NULL | [get_kind(semantic_type)] |
| get_searchable_types | scalar | Get list of all searchable semantic type codes. | NULL | [get_searchable_types()] |
| get_super_kind | scalar | Get the super-kind category name (DEFINITION, EXECUTION, STRUCTURE, LITERAL, etc.) for a semantic type. | NULL | [get_super_kind(semantic_type)] |
| has_body | scalar | Returns true if node has an embodied implementation body. | NULL | [has_body(flags)] |
| is_annotation | macro | NULL | NULL | |
| is_arithmetic | macro | NULL | NULL | |
| is_assignment | macro | NULL | NULL | |
| is_block | macro | NULL | NULL | |
| is_boolean_literal | macro | NULL | NULL | |
| is_call | scalar | Check if a semantic type represents a function/method call expression. | NULL | [is_call(semantic_type)] |
| is_class_definition | macro | NULL | NULL | |
| is_comment | macro | NULL | NULL | |
| is_comparison | macro | NULL | NULL | |
| is_conditional | macro | NULL | NULL | |
| is_constituent | scalar | Returns true if node is an internal constituent part of a compound construct. | NULL | [is_constituent(flags)] |
| is_construct | scalar | Returns true if node is a meaningful semantic construct (inverse of is_syntax_only). | NULL | [is_construct(flags)] |
| is_control_flow | scalar | Check if a semantic type represents a control flow construct (if, loop, switch, return, etc.). | NULL | [is_control_flow(semantic_type)] |
| is_declaration_only | scalar | Returns true if node is a declaration without an accompanying implementation body. | NULL | [is_declaration_only(flags)] |
| is_definition | scalar | Check if a semantic type represents a definition (function, class, variable, etc.). | NULL | [is_definition(semantic_type)] |
| is_directive | macro | NULL | NULL | |
| is_embodied | scalar | Returns true if node is an embodied definition (has implementation body). | NULL | [is_embodied(flags)] |
| is_export | macro | NULL | NULL | |
| is_exported | scalar | Returns true if node is exported from its containing module/package. | NULL | [is_exported(flags)] |
| is_foreign | macro | NULL | NULL | |
| is_function_call | macro | NULL | NULL | |
| is_function_definition | macro | NULL | NULL | |
| is_identifier | scalar | Check if a semantic type represents an identifier (variable name, function name, etc.). | NULL | [is_identifier(semantic_type)] |
| is_import | macro | NULL | NULL | |
| is_jump | macro | NULL | NULL | |
| is_kind | scalar | Check if a semantic type code belongs to the specified kind. | NULL | [is_kind(semantic_type, 'FUNCTION')] |
| is_list | macro | NULL | NULL | |
| is_literal | macro | NULL | NULL | |
| is_logical | macro | NULL | NULL | |
| is_loop | macro | NULL | NULL | |
| is_member_access | macro | NULL | NULL | |
| is_module_definition | macro | NULL | NULL | |
| is_name_declaration | scalar | Returns true if node represents a name declaration. | NULL | [is_name_declaration(flags)] |
| is_name_definition | scalar | Returns true if node represents a name definition. | NULL | [is_name_definition(flags)] |
| is_name_reference | scalar | Returns true if node represents a name reference. | NULL | [is_name_reference(flags)] |
| is_number_literal | macro | NULL | NULL | |
| is_parser_specific | scalar | Check if a semantic type is parser-specific/unclassified in the universal taxonomy. | NULL | [is_parser_specific(semantic_type)] |
| is_pattern_wildcard | macro | NULL | NULL | |
| is_punctuation | scalar | Check if a semantic type represents punctuation or syntax delimiter. | NULL | [is_punctuation(semantic_type)] |
| is_scope | scalar | Returns true if node establishes a lexical scope boundary (function, class, block, module). | NULL | [is_scope(flags)] |
| is_semantic_type | scalar | Check if a semantic type bitmask matches a taxonomy pattern string. | NULL | [is_semantic_type(semantic_type, 'DEFINITION_%')] |
| is_string_literal | macro | NULL | NULL | |
| is_syntax_only | scalar | Returns true if node is a pure syntax token (keyword, punctuation) with no semantic payload. | NULL | [is_syntax_only(flags)] |
| is_type_composite | macro | NULL | NULL | |
| is_type_definition | macro | NULL | NULL | |
| is_type_generic | macro | NULL | NULL | |
| is_type_primitive | macro | NULL | NULL | |
| is_type_reference | macro | NULL | NULL | |
| is_variable_definition | macro | NULL | NULL | |
| kind_code | scalar | Get the numeric code for a taxonomy kind name. | NULL | [kind_code('FUNCTION')] |
| name_role | scalar | Get the numeric NameRole code (0=NONE, 1=DECLARATION, 2=DEFINITION, 3=REFERENCE) from flags. | NULL | [name_role(flags)] |
| parse_ast | table | Parse source code string into an AST table representation. | NULL | [SELECT * FROM parse_ast('def add(a, b): return a + b', 'python')] |
| parse_ast_flat | table | Parse source code string into a flat AST table representation (alias of parse_ast). | NULL | [SELECT * FROM parse_ast_flat('def add(a, b): return a + b', 'python')] |
| parse_ast_hierarchical | table | Parse source code string into a hierarchical AST table representation. | NULL | [SELECT * FROM parse_ast_hierarchical('def add(a, b): return a + b', 'python')] |
| parse_ast_list | scalar | Parse source code string into a list of AST node structs (scalar function for column-valued inputs). | NULL | [parse_ast_list('x = 1', 'python')] |
| parse_ast_list_table | table_macro | Table-macro wrapper for parse_ast_list | NULL | |
| parse_html_wildcard | macro | NULL | NULL | |
| pattern_has_recursive | macro | NULL | NULL | |
| pattern_has_variadic | macro | NULL | NULL | |
| read_ast | table | Parse source code from file(s) into an AST table representation. | NULL | [SELECT * FROM read_ast('src/main.cpp'), SELECT * FROM read_ast('src/main.cpp', 'cpp')] |
| read_ast | table | NULL | NULL | |
| read_ast_flat | table | Parse source code from file(s) into flat AST table representation (alias of read_ast). | NULL | [SELECT * FROM read_ast_flat('src/main.cpp'), SELECT * FROM read_ast_flat('src/main.cpp', 'cpp')] |
| read_ast_flat | table | NULL | NULL | |
| read_ast_hierarchical | table | Parse source code from file(s) into legacy hierarchical AST table representation. | NULL | [SELECT * FROM read_ast_hierarchical('src/main.cpp'), SELECT * FROM read_ast_hierarchical('src/main.cpp', 'cpp')] |
| read_ast_hierarchical | table | NULL | NULL | |
| read_ast_hierarchical_new | table | Parse source code from file(s) into hierarchical AST table representation. | NULL | [SELECT * FROM read_ast_hierarchical_new('src/main.cpp'), SELECT * FROM read_ast_hierarchical_new('src/main.cpp', 'cpp')] |
| read_ast_hierarchical_new | table | NULL | NULL | |
| register_language | table | Dynamically register a tree-sitter language grammar from a shared library. | NULL | [SELECT * FROM register_language('mylang', '/path/to/libtree-sitter-mylang.so')] |
| semantic_type_base | macro | NULL | NULL | |
| semantic_type_code | scalar | Convert a semantic type name string to its numeric bitmask code. | NULL | [semantic_type_code('DEFINITION_FUNCTION')] |
| semantic_type_to_string | scalar | Convert a numeric semantic type bitmask to its human-readable name string. | NULL | [semantic_type_to_string(1::UTINYINT)] |
| sitting_duck_enable_dynamic_predicates | pragma | NULL | NULL | |
| string_contains_any | scalar | Case-sensitive search checking if string contains any pattern in the list. | NULL | [string_contains_any('hello world', ['world', 'foo'])] |
| string_contains_any_i | scalar | Case-insensitive search checking if string contains any pattern in the list. | NULL | [string_contains_any_i('Hello World', ['world', 'foo'])] |
| wildcard_capture_name | macro | NULL | NULL | |
### Overloaded Functions
This extension does not add any function overloads.
### Added Types
| type_name | type_size | logical_type | type_category | internal |
|---------------|----------:|--------------|---------------|----------|
| SEMANTIC_TYPE | 1 | UTINYINT | NUMERIC | true |
### Added Settings
| name | description | input_type | scope | aliases | typed_value |
|--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|------------|--------|---------|-------------|
| sitting_duck_enable_runtime_grammars | Allow register_language() to load native tree-sitter grammar libraries, which executes arbitrary native code in-process. Disabled by default. | BOOLEAN | GLOBAL | [] | false |
| temp_directory | Set the directory to which temporary files are written. | VARCHAR | GLOBAL | [] | post.db.tmp |