Skip to content

Grammar Reference

This page contains the complete tree-sitter grammar for Vanya. This is the authoritative syntax specification.

Tree-sitter Grammar

// tree-sitter-vanya grammar definition
// See docs/DESIGN.md for the full grammar specification
module.exports = grammar({
name: 'vanya',
externals: $ => [
$._indent,
$._dedent,
$._newline,
],
extras: $ => [/[ \t]/],
word: $ => $.identifier,
conflicts: $ => [
[$.action_tokens],
[$.statement_block],
],
rules: {
source_file: $ => seq(
repeat($._newline),
$.file_header,
repeat($._newline),
$.script_header,
repeat($._newline),
$.statement_block,
repeat($._newline)
),
file_header: $ => seq(
'Vanya', 'test', 'scenario',
'(', $.domain, '/', $.version, ')'
),
domain: $ => /[a-zA-Z0-9.-]+/,
version: $ => /v\d+\.\d+(\.\d+)?/,
script_header: $ => seq('Script', 'title:', $.string),
statement_block: $ => seq(
$._statement,
repeat(seq($._newline, optional($._statement)))
),
_statement: $ => choice(
$.within_stmt,
$.define_stmt,
$.capture_stmt,
$.export_stmt,
$.action_stmt,
$.comment
),
within_stmt: $ => seq(
'Within', 'the', $.context_name,
$._modifiers,
$._indent,
$.statement_block,
$._dedent
),
context_name: $ => /[^(\n]+/,
define_stmt: $ => prec(2, seq(
'Define', $.alias_name, '(', $.selector_list, ')'
)),
export_stmt: $ => prec(2, seq('Export', $.identifier)),
capture_stmt: $ => prec(2, seq('Capture', $.string, 'as', $.identifier)),
action_stmt: $ => seq(
$.action_tokens,
optional($._modifiers),
optional($.action_block)
),
// action_tokens can include hyphenated names (for alias references) and numbers
action_tokens: $ => repeat1(choice($.identifier, $.hyphenated_identifier, $.string, $.number)),
number: $ => /\d+/,
// Hyphenated identifier like submit-button
hyphenated_identifier: $ => /[a-zA-Z][a-zA-Z0-9_]*(-[a-zA-Z][a-zA-Z0-9_]*)+/,
action_block: $ => seq(
$._indent,
$._action_block_item,
repeat(seq($._newline, optional($._action_block_item))),
$._dedent
),
_action_block_item: $ => choice(
$.capture_stmt,
$.action_stmt
),
_modifiers: $ => choice(
$.parens_modifiers,
$.with_modifiers
),
parens_modifiers: $ => seq('(', $.key_value_list, ')'),
with_modifiers: $ => seq('with', $.key_value_list),
key_value_list: $ => seq($.key_value, repeat(seq(',', $.key_value))),
key_value: $ => seq($.identifier, ':', $._value),
_value: $ => choice($.string, $.unquoted_value),
selector_list: $ => seq($.key_value, repeat(seq(',', $.key_value))),
alias_name: $ => /[a-zA-Z][a-zA-Z0-9_-]*/,
identifier: $ => /[a-zA-Z][a-zA-Z0-9_]*/,
unquoted_value: $ => /[a-zA-Z][a-zA-Z0-9_-]*/,
string: $ => choice(
seq("'", /[^']*/, "'"),
seq('"', /[^"]*/, '"')
),
comment: $ => seq('#', /.*/),
}
});

Quick Reference

Top-Level Rules

RuleDescription
source_fileEntry point: file_header + script_header + statement_block
file_headerVanya test scenario (<domain>/<version>)
script_headerScript title: <string>
statement_blockOne or more statements separated by newlines

Statement Rules

RuleDescription
_statementChoice of: within_stmt, define_stmt, capture_stmt, export_stmt, action_stmt, comment
within_stmtWithin the <context_name> <modifiers> <indent> <statement_block> <dedent>
define_stmtDefine <alias_name> (<selector_list>)
capture_stmtCapture <string> as <identifier>
export_stmtExport <identifier>
action_stmt<action_tokens> + optional <modifiers> + optional <action_block>
comment# <text>

Action Rules

RuleDescription
action_tokensOne or more: identifier, hyphenated_identifier, string, or number
action_blockIndented block containing capture_stmt or action_stmt items

Modifier Rules

RuleDescription
_modifiersChoice of: parens_modifiers or with_modifiers
parens_modifiers(<key_value_list>)
with_modifierswith <key_value_list>
key_value_listComma-separated <key_value> pairs
key_value<identifier>: <value>
selector_listComma-separated <key_value> pairs (used in define_stmt)

Identifier and Literal Rules

RuleDescription
identifier[a-zA-Z][a-zA-Z0-9_]*
alias_name[a-zA-Z][a-zA-Z0-9_-]* (allows hyphens)
hyphenated_identifier[a-zA-Z][a-zA-Z0-9_]*(-[a-zA-Z][a-zA-Z0-9_]*)+ (e.g., submit-button)
context_name[^(\n]+ (any text until ( or newline)
domain[a-zA-Z0-9.-]+
versionv\d+\.\d+(\.\d+)? (e.g., v1.0, v2.1.3)
stringSingle or double quoted: '...' or "..."
number\d+
unquoted_value[a-zA-Z][a-zA-Z0-9_-]*

Keywords

All keywords are case-sensitive and fall into two categories:

Capitalized keywords (statement/structure beginnings):

  • Vanya, Script, Within, Define, Capture, Export

Lowercase connectors:

  • test, scenario (file header: Vanya test scenario (...))
  • title: (script header: Script title: "...")
  • the (within block: Within the <context>)
  • as (capture statement: Capture "..." as <name>)
  • with (modifier syntax: <action> with <key>: <value>)

Indentation

Vanya uses significant indentation (like Python). The external scanner handles _indent, _dedent, and _newline tokens.