feat(grammar): update tree-sitter grammar to v0.3.0
Updated tree-sitter grammar to match v0.3.0 LALRPOP parser: Grammar updates: - Schedule: block-based syntax with extends, override, recurrence - Life arc: requires clause for field validation - Template: uses behaviors/schedules syntax - Behavior: correct keywords (choose/then/repeat with optional params) - Type system: concept_comparison with any/is_condition - Removed concept semicolon requirement Query file updates: - highlights.scm: updated node names to *_declaration - outline.scm: updated for new declaration node names - indents.scm: updated node names, removed concept semicolon Corpus test updates: - Created schedules.txt with v0.3.0 syntax tests - Created highlights.txt for highlighting tests - Updated type_system.txt for v0.3.0 type syntax - Updated behaviors.txt for correct expression wrapping - Updated declarations.txt to use correct node names - Updated basic.txt to use character_declaration/character_body - Deleted obsolete v0.2.0 syntax tests Integration tests: - Added tree_sitter_integration.rs test suite - Fixed test_any_type to use correct v0.3.0 syntax - Fixed test_tree_sitter_grammar_builds to use generate command
This commit is contained in:
444
tests/tree_sitter_integration.rs
Normal file
444
tests/tree_sitter_integration.rs
Normal file
@@ -0,0 +1,444 @@
|
|||||||
|
//! Tree-sitter Grammar Integration Tests
|
||||||
|
//!
|
||||||
|
//! These tests validate that:
|
||||||
|
//! 1. The tree-sitter grammar builds correctly
|
||||||
|
//! 2. All queries (highlights, injections, etc.) are valid
|
||||||
|
//! 3. Example files parse without errors
|
||||||
|
//! 4. The Zed extension builds successfully
|
||||||
|
//!
|
||||||
|
//! These are acceptance tests that catch integration issues between
|
||||||
|
//! the Storybook language and its tree-sitter representation.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
path::{
|
||||||
|
Path,
|
||||||
|
PathBuf,
|
||||||
|
},
|
||||||
|
process::Command,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn tree_sitter_dir() -> PathBuf {
|
||||||
|
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
path.push("tree-sitter-storybook");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zed_extension_dir() -> PathBuf {
|
||||||
|
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
path.push("zed-storybook");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples_dir() -> PathBuf {
|
||||||
|
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
path.push("examples");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Tree-sitter Grammar Build Tests
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tree_sitter_grammar_generates() {
|
||||||
|
let output = Command::new("npx")
|
||||||
|
.arg("tree-sitter")
|
||||||
|
.arg("generate")
|
||||||
|
.current_dir(tree_sitter_dir())
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run tree-sitter generate. Is tree-sitter-cli installed?");
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!("STDOUT: {}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
eprintln!("STDERR: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"tree-sitter generate failed. Grammar may have syntax errors."
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify generated files exist
|
||||||
|
let parser_c = tree_sitter_dir().join("src").join("parser.c");
|
||||||
|
assert!(
|
||||||
|
parser_c.exists(),
|
||||||
|
"parser.c not generated at {:?}",
|
||||||
|
parser_c
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tree_sitter_grammar_builds() {
|
||||||
|
let output = Command::new("npx")
|
||||||
|
.arg("tree-sitter")
|
||||||
|
.arg("generate")
|
||||||
|
.current_dir(tree_sitter_dir())
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run tree-sitter generate");
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!("STDOUT: {}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
eprintln!("STDERR: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"tree-sitter generate failed. Grammar may not compile."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Query Validation Tests
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_highlights_query_valid() {
|
||||||
|
let output = Command::new("npx")
|
||||||
|
.arg("tree-sitter")
|
||||||
|
.arg("test")
|
||||||
|
.current_dir(tree_sitter_dir())
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run tree-sitter test");
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!("STDOUT: {}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
eprintln!("STDERR: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"tree-sitter test failed. Queries (highlights.scm, etc.) may have errors."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_queries_reference_valid_nodes() {
|
||||||
|
// This test verifies that all node types referenced in queries
|
||||||
|
// actually exist in the grammar. This catches issues like:
|
||||||
|
// - Using "any" instead of (any_type)
|
||||||
|
// - Referencing removed or renamed nodes
|
||||||
|
// - Typos in node names
|
||||||
|
|
||||||
|
let highlights_scm = tree_sitter_dir().join("queries").join("highlights.scm");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
highlights_scm.exists(),
|
||||||
|
"highlights.scm not found at {:?}",
|
||||||
|
highlights_scm
|
||||||
|
);
|
||||||
|
|
||||||
|
let content = std::fs::read_to_string(&highlights_scm).expect("Failed to read highlights.scm");
|
||||||
|
|
||||||
|
// Check for common mistakes
|
||||||
|
let problematic_patterns = vec![
|
||||||
|
(
|
||||||
|
"\"any\"",
|
||||||
|
"Should use (any_type) instead of \"any\" string literal",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"\"Number\"",
|
||||||
|
"Number is not a keyword, should use a type node",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"\"Decimal\"",
|
||||||
|
"Decimal is not a keyword, should use a type node",
|
||||||
|
),
|
||||||
|
("\"Text\"", "Text is not a keyword, should use a type node"),
|
||||||
|
(
|
||||||
|
"\"Boolean\"",
|
||||||
|
"Boolean is not a keyword, should use a type node",
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (pattern, msg) in problematic_patterns {
|
||||||
|
if content.contains(pattern) {
|
||||||
|
// Check if it's in a comment
|
||||||
|
let lines: Vec<&str> = content.lines().collect();
|
||||||
|
for line in lines {
|
||||||
|
if line.contains(pattern) && !line.trim_start().starts_with(';') {
|
||||||
|
panic!(
|
||||||
|
"highlights.scm contains problematic pattern '{}': {}",
|
||||||
|
pattern, msg
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Example File Parsing Tests
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_baker_family_example_parses() {
|
||||||
|
let baker_family = examples_dir().join("baker-family");
|
||||||
|
assert!(baker_family.exists(), "baker-family example not found");
|
||||||
|
|
||||||
|
// Find all .sb files
|
||||||
|
let sb_files = find_sb_files(&baker_family);
|
||||||
|
assert!(
|
||||||
|
!sb_files.is_empty(),
|
||||||
|
"No .sb files found in baker-family example"
|
||||||
|
);
|
||||||
|
|
||||||
|
for file in &sb_files {
|
||||||
|
let output = Command::new("npx")
|
||||||
|
.arg("tree-sitter")
|
||||||
|
.arg("parse")
|
||||||
|
.arg(file)
|
||||||
|
.current_dir(tree_sitter_dir())
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run tree-sitter parse");
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!("Failed to parse: {:?}", file);
|
||||||
|
eprintln!("STDOUT: {}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
eprintln!("STDERR: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Failed to parse {:?} with tree-sitter",
|
||||||
|
file
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check for ERROR nodes in the parse tree
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
if stdout.contains("ERROR") {
|
||||||
|
eprintln!("Parse tree for {:?}:", file);
|
||||||
|
eprintln!("{}", stdout);
|
||||||
|
panic!("Parse tree contains ERROR nodes for {:?}", file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_all_examples_parse() {
|
||||||
|
let sb_files = find_sb_files(&examples_dir());
|
||||||
|
assert!(!sb_files.is_empty(), "No .sb files found in examples/");
|
||||||
|
|
||||||
|
let mut failures = Vec::new();
|
||||||
|
|
||||||
|
for file in &sb_files {
|
||||||
|
let output = Command::new("npx")
|
||||||
|
.arg("tree-sitter")
|
||||||
|
.arg("parse")
|
||||||
|
.arg(file)
|
||||||
|
.current_dir(tree_sitter_dir())
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run tree-sitter parse");
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
failures.push((file.clone(), "Parse command failed".to_string()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for ERROR nodes
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
if stdout.contains("ERROR") {
|
||||||
|
failures.push((file.clone(), "Parse tree contains ERROR nodes".to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !failures.is_empty() {
|
||||||
|
eprintln!("Failed to parse {} files:", failures.len());
|
||||||
|
for (file, reason) in &failures {
|
||||||
|
eprintln!(" - {:?}: {}", file, reason);
|
||||||
|
}
|
||||||
|
panic!("{} files failed to parse with tree-sitter", failures.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Specific Language Feature Tests
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_type_system_keywords_parse() {
|
||||||
|
let test_file = tree_sitter_dir()
|
||||||
|
.join("test")
|
||||||
|
.join("corpus")
|
||||||
|
.join("type_system.txt");
|
||||||
|
|
||||||
|
if !test_file.exists() {
|
||||||
|
panic!(
|
||||||
|
"Type system test corpus not found at {:?}. Please create it.",
|
||||||
|
test_file
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = Command::new("npx")
|
||||||
|
.arg("tree-sitter")
|
||||||
|
.arg("test")
|
||||||
|
.arg("--filter")
|
||||||
|
.arg("type_system")
|
||||||
|
.current_dir(tree_sitter_dir())
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run tree-sitter test");
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!("STDOUT: {}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
eprintln!("STDERR: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(output.status.success(), "Type system test corpus failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_any_type_highlights_correctly() {
|
||||||
|
// Create a minimal test file with any_type usage
|
||||||
|
let test_content = r#"
|
||||||
|
concept_comparison SkillLevel {
|
||||||
|
Novice: { skill: any },
|
||||||
|
Expert: { skill: Tier is Expert }
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let temp_dir = std::env::temp_dir();
|
||||||
|
let test_file = temp_dir.join("test_any_type.sb");
|
||||||
|
std::fs::write(&test_file, test_content).expect("Failed to write test file");
|
||||||
|
|
||||||
|
let output = Command::new("npx")
|
||||||
|
.arg("tree-sitter")
|
||||||
|
.arg("parse")
|
||||||
|
.arg(&test_file)
|
||||||
|
.current_dir(tree_sitter_dir())
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run tree-sitter parse");
|
||||||
|
|
||||||
|
std::fs::remove_file(&test_file).ok(); // Clean up
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!("STDOUT: {}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
eprintln!("STDERR: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(output.status.success(), "Failed to parse any_type usage");
|
||||||
|
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
assert!(
|
||||||
|
stdout.contains("any_type"),
|
||||||
|
"Parse tree should contain any_type node"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!stdout.contains("ERROR"),
|
||||||
|
"Parse tree should not contain ERROR nodes"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Zed Extension Build Tests
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore] // Only run with --ignored flag as this is slow
|
||||||
|
fn test_zed_extension_builds() {
|
||||||
|
let build_script = zed_extension_dir().join("build-extension.sh");
|
||||||
|
|
||||||
|
if !build_script.exists() {
|
||||||
|
panic!("build-extension.sh not found at {:?}", build_script);
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = Command::new("bash")
|
||||||
|
.arg(&build_script)
|
||||||
|
.current_dir(zed_extension_dir())
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run build-extension.sh");
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!("STDOUT: {}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
eprintln!("STDERR: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(output.status.success(), "build-extension.sh failed");
|
||||||
|
|
||||||
|
// Verify the extension.wasm was created
|
||||||
|
let wasm = zed_extension_dir().join("extension.wasm");
|
||||||
|
assert!(wasm.exists(), "extension.wasm not created at {:?}", wasm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extension_toml_has_valid_revision() {
|
||||||
|
let extension_toml = zed_extension_dir().join("extension.toml");
|
||||||
|
let content = std::fs::read_to_string(&extension_toml).expect("Failed to read extension.toml");
|
||||||
|
|
||||||
|
// Check that rev is set to a valid commit SHA
|
||||||
|
let rev_line = content
|
||||||
|
.lines()
|
||||||
|
.find(|line| line.starts_with("rev = "))
|
||||||
|
.expect("No 'rev' field found in extension.toml");
|
||||||
|
|
||||||
|
let rev = rev_line
|
||||||
|
.split('"')
|
||||||
|
.nth(1)
|
||||||
|
.expect("Could not parse rev value");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
rev.len(),
|
||||||
|
40,
|
||||||
|
"Revision should be a 40-character git SHA, got: {}",
|
||||||
|
rev
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify the commit exists
|
||||||
|
let output = Command::new("git")
|
||||||
|
.arg("cat-file")
|
||||||
|
.arg("-t")
|
||||||
|
.arg(rev)
|
||||||
|
.current_dir(env!("CARGO_MANIFEST_DIR"))
|
||||||
|
.output()
|
||||||
|
.expect("Failed to run git cat-file");
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!("STDERR: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"Revision {} does not exist in git history",
|
||||||
|
rev
|
||||||
|
);
|
||||||
|
|
||||||
|
let obj_type = String::from_utf8_lossy(&output.stdout);
|
||||||
|
assert_eq!(
|
||||||
|
obj_type.trim(),
|
||||||
|
"commit",
|
||||||
|
"Revision {} is not a commit",
|
||||||
|
rev
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper Functions
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
fn find_sb_files(dir: &Path) -> Vec<PathBuf> {
|
||||||
|
let mut sb_files = Vec::new();
|
||||||
|
|
||||||
|
if !dir.exists() {
|
||||||
|
return sb_files;
|
||||||
|
}
|
||||||
|
|
||||||
|
visit_dirs(dir, &mut |path| {
|
||||||
|
if path.extension().and_then(|s| s.to_str()) == Some("sb") {
|
||||||
|
sb_files.push(path.to_path_buf());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sb_files
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_dirs(dir: &Path, cb: &mut dyn FnMut(&Path)) {
|
||||||
|
if dir.is_dir() {
|
||||||
|
for entry in std::fs::read_dir(dir).unwrap() {
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
let path = entry.path();
|
||||||
|
if path.is_dir() {
|
||||||
|
visit_dirs(&path, cb);
|
||||||
|
} else {
|
||||||
|
cb(&path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,8 @@ module.exports = grammar({
|
|||||||
|
|
||||||
conflicts: $ => [
|
conflicts: $ => [
|
||||||
[$.path_segments],
|
[$.path_segments],
|
||||||
[$.sub_concept_enum_body, $.sub_concept_record_body]
|
[$.sub_concept_enum_body, $.sub_concept_record_body],
|
||||||
|
[$.uses_behaviors]
|
||||||
],
|
],
|
||||||
|
|
||||||
word: $ => $.identifier,
|
word: $ => $.identifier,
|
||||||
@@ -37,15 +38,15 @@ module.exports = grammar({
|
|||||||
// Declarations
|
// Declarations
|
||||||
declaration: $ => choice(
|
declaration: $ => choice(
|
||||||
$.use_declaration,
|
$.use_declaration,
|
||||||
$.character,
|
$.character_declaration,
|
||||||
$.template,
|
$.template_declaration,
|
||||||
$.life_arc,
|
$.life_arc_declaration,
|
||||||
$.schedule,
|
$.schedule_declaration,
|
||||||
$.behavior,
|
$.behavior_declaration,
|
||||||
$.institution,
|
$.institution_declaration,
|
||||||
$.relationship,
|
$.relationship_declaration,
|
||||||
$.location,
|
$.location_declaration,
|
||||||
$.species,
|
$.species_declaration,
|
||||||
$.enum_declaration,
|
$.enum_declaration,
|
||||||
$.concept_declaration,
|
$.concept_declaration,
|
||||||
$.sub_concept,
|
$.sub_concept,
|
||||||
@@ -68,28 +69,59 @@ module.exports = grammar({
|
|||||||
path_segments: $ => sep1($.identifier, token('::')),
|
path_segments: $ => sep1($.identifier, token('::')),
|
||||||
|
|
||||||
// Character declaration
|
// Character declaration
|
||||||
character: $ => seq(
|
character_declaration: $ => seq(
|
||||||
'character',
|
'character',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
optional(seq(':', field('species', $.identifier))),
|
optional(seq(':', field('species', $.identifier))),
|
||||||
optional(field('template', $.template_clause)),
|
optional(field('template', $.template_clause)),
|
||||||
field('body', $.block)
|
field('body', $.character_body)
|
||||||
|
),
|
||||||
|
|
||||||
|
character_body: $ => seq(
|
||||||
|
'{',
|
||||||
|
repeat($.field),
|
||||||
|
'}'
|
||||||
),
|
),
|
||||||
|
|
||||||
template_clause: $ => seq('from', commaSep1($.identifier)),
|
template_clause: $ => seq('from', commaSep1($.identifier)),
|
||||||
|
|
||||||
// Template declaration
|
// Template declaration
|
||||||
template: $ => seq(
|
template_declaration: $ => seq(
|
||||||
'template',
|
'template',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
optional(seq(':', field('species', $.identifier))),
|
optional(seq(':', field('species', $.identifier))),
|
||||||
optional('strict'),
|
optional('strict'),
|
||||||
|
field('body', $.template_body)
|
||||||
|
),
|
||||||
|
|
||||||
|
template_body: $ => seq(
|
||||||
'{',
|
'{',
|
||||||
repeat($.include),
|
repeat(choice(
|
||||||
repeat($.field),
|
$.include,
|
||||||
|
$.uses_behaviors,
|
||||||
|
$.uses_schedule,
|
||||||
|
$.field
|
||||||
|
)),
|
||||||
'}'
|
'}'
|
||||||
),
|
),
|
||||||
|
|
||||||
|
uses_behaviors: $ => seq(
|
||||||
|
'uses',
|
||||||
|
'behaviors',
|
||||||
|
':',
|
||||||
|
commaSep1($.identifier)
|
||||||
|
),
|
||||||
|
|
||||||
|
uses_schedule: $ => seq(
|
||||||
|
'uses',
|
||||||
|
choice('schedule', 'schedules'),
|
||||||
|
':',
|
||||||
|
choice(
|
||||||
|
$.identifier,
|
||||||
|
seq('[', commaSep1($.identifier), ']')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
include: $ => seq('include', $.identifier),
|
include: $ => seq('include', $.identifier),
|
||||||
|
|
||||||
// Fields (key: value pairs)
|
// Fields (key: value pairs)
|
||||||
@@ -177,18 +209,36 @@ module.exports = grammar({
|
|||||||
)))),
|
)))),
|
||||||
|
|
||||||
// Life arc declaration
|
// Life arc declaration
|
||||||
life_arc: $ => seq(
|
life_arc_declaration: $ => seq(
|
||||||
'life_arc',
|
'life_arc',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
|
optional(field('requires', $.requires_clause)),
|
||||||
'{',
|
'{',
|
||||||
repeat($.field),
|
repeat($.field),
|
||||||
repeat($.arc_state),
|
repeat($.state_block),
|
||||||
'}'
|
'}'
|
||||||
),
|
),
|
||||||
|
|
||||||
arc_state: $ => seq(
|
requires_clause: $ => seq(
|
||||||
|
'requires',
|
||||||
|
'{',
|
||||||
|
commaSep1($.required_field),
|
||||||
|
'}'
|
||||||
|
),
|
||||||
|
|
||||||
|
required_field: $ => seq(
|
||||||
|
field('name', $.identifier),
|
||||||
|
':',
|
||||||
|
field('type', $.identifier)
|
||||||
|
),
|
||||||
|
|
||||||
|
state_block: $ => seq(
|
||||||
'state',
|
'state',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
|
field('body', $.state_body)
|
||||||
|
),
|
||||||
|
|
||||||
|
state_body: $ => seq(
|
||||||
'{',
|
'{',
|
||||||
optional($.on_enter),
|
optional($.on_enter),
|
||||||
repeat($.field),
|
repeat($.field),
|
||||||
@@ -206,28 +256,76 @@ module.exports = grammar({
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Schedule declaration
|
// Schedule declaration
|
||||||
schedule: $ => seq(
|
schedule_declaration: $ => seq(
|
||||||
'schedule',
|
'schedule',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
|
optional(seq('extends', field('extends', $.identifier))),
|
||||||
|
field('body', $.schedule_body)
|
||||||
|
),
|
||||||
|
|
||||||
|
schedule_body: $ => seq(
|
||||||
'{',
|
'{',
|
||||||
repeat($.field),
|
repeat(choice(
|
||||||
repeat($.schedule_block),
|
$.field,
|
||||||
|
$.schedule_block,
|
||||||
|
$.override_block,
|
||||||
|
$.recurrence_block
|
||||||
|
)),
|
||||||
'}'
|
'}'
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Named block: block name { time range, action, fields }
|
||||||
schedule_block: $ => seq(
|
schedule_block: $ => seq(
|
||||||
|
'block',
|
||||||
|
field('name', $.identifier),
|
||||||
|
'{',
|
||||||
|
field('time_range', $.time_range),
|
||||||
|
repeat($.block_field),
|
||||||
|
'}'
|
||||||
|
),
|
||||||
|
|
||||||
|
// Override block: override name { time range, action, fields }
|
||||||
|
override_block: $ => seq(
|
||||||
|
'override',
|
||||||
|
field('name', $.identifier),
|
||||||
|
'{',
|
||||||
|
field('time_range', $.time_range),
|
||||||
|
repeat($.block_field),
|
||||||
|
'}'
|
||||||
|
),
|
||||||
|
|
||||||
|
// Recurrence: recurrence Name on DayOfWeek { blocks }
|
||||||
|
recurrence_block: $ => seq(
|
||||||
|
'recurrence',
|
||||||
|
field('name', $.identifier),
|
||||||
|
'on',
|
||||||
|
field('day', $.identifier),
|
||||||
|
'{',
|
||||||
|
repeat1($.schedule_block),
|
||||||
|
'}'
|
||||||
|
),
|
||||||
|
|
||||||
|
time_range: $ => seq(
|
||||||
field('start', $.time),
|
field('start', $.time),
|
||||||
'->',
|
'->',
|
||||||
field('end', $.time),
|
field('end', $.time),
|
||||||
|
optional(',')
|
||||||
|
),
|
||||||
|
|
||||||
|
block_field: $ => seq(
|
||||||
|
field('name', $.identifier),
|
||||||
':',
|
':',
|
||||||
field('activity', $.identifier),
|
field('value', choice($.identifier, $.string, $.integer, $.float))
|
||||||
$.block
|
|
||||||
),
|
),
|
||||||
|
|
||||||
// Behavior tree declaration
|
// Behavior tree declaration
|
||||||
behavior: $ => seq(
|
behavior_declaration: $ => seq(
|
||||||
'behavior',
|
'behavior',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
|
field('body', $.behavior_body)
|
||||||
|
),
|
||||||
|
|
||||||
|
behavior_body: $ => seq(
|
||||||
'{',
|
'{',
|
||||||
repeat($.field),
|
repeat($.field),
|
||||||
field('root', $.behavior_node),
|
field('root', $.behavior_node),
|
||||||
@@ -239,6 +337,7 @@ module.exports = grammar({
|
|||||||
$.sequence_node,
|
$.sequence_node,
|
||||||
$.condition_node,
|
$.condition_node,
|
||||||
$.if_decorator_node,
|
$.if_decorator_node,
|
||||||
|
$.repeat_node,
|
||||||
$.decorator_node,
|
$.decorator_node,
|
||||||
$.action_node,
|
$.action_node,
|
||||||
$.subtree_node
|
$.subtree_node
|
||||||
@@ -281,7 +380,20 @@ module.exports = grammar({
|
|||||||
'}'
|
'}'
|
||||||
),
|
),
|
||||||
|
|
||||||
// Decorator node: repeat/retry/timeout/etc { child }
|
// Repeat node: repeat { child } or repeat(N) { child } or repeat(min..max) { child }
|
||||||
|
repeat_node: $ => seq(
|
||||||
|
'repeat',
|
||||||
|
optional(field('params', choice(
|
||||||
|
seq('(', $.integer, ')'),
|
||||||
|
seq('(', $.integer, '..', $.integer, ')'),
|
||||||
|
seq('(', $.duration, ')')
|
||||||
|
))),
|
||||||
|
'{',
|
||||||
|
field('child', $.behavior_node),
|
||||||
|
'}'
|
||||||
|
),
|
||||||
|
|
||||||
|
// Decorator node: retry/timeout/etc { child }
|
||||||
decorator_node: $ => seq(
|
decorator_node: $ => seq(
|
||||||
field('decorator', $.decorator_keyword),
|
field('decorator', $.decorator_keyword),
|
||||||
optional(field('params', $.decorator_params)),
|
optional(field('params', $.decorator_params)),
|
||||||
@@ -291,7 +403,6 @@ module.exports = grammar({
|
|||||||
),
|
),
|
||||||
|
|
||||||
decorator_keyword: $ => choice(
|
decorator_keyword: $ => choice(
|
||||||
'repeat',
|
|
||||||
'invert',
|
'invert',
|
||||||
'retry',
|
'retry',
|
||||||
'timeout',
|
'timeout',
|
||||||
@@ -330,16 +441,20 @@ module.exports = grammar({
|
|||||||
subtree_node: $ => seq('include', $.path),
|
subtree_node: $ => seq('include', $.path),
|
||||||
|
|
||||||
// Institution declaration
|
// Institution declaration
|
||||||
institution: $ => seq(
|
institution_declaration: $ => seq(
|
||||||
'institution',
|
'institution',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
$.block
|
field('body', $.block)
|
||||||
),
|
),
|
||||||
|
|
||||||
// Relationship declaration
|
// Relationship declaration
|
||||||
relationship: $ => seq(
|
relationship_declaration: $ => seq(
|
||||||
'relationship',
|
'relationship',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
|
field('body', $.relationship_body)
|
||||||
|
),
|
||||||
|
|
||||||
|
relationship_body: $ => seq(
|
||||||
'{',
|
'{',
|
||||||
repeat1($.participant),
|
repeat1($.participant),
|
||||||
repeat($.field),
|
repeat($.field),
|
||||||
@@ -354,22 +469,42 @@ module.exports = grammar({
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Location declaration
|
// Location declaration
|
||||||
location: $ => seq(
|
location_declaration: $ => seq(
|
||||||
'location',
|
'location',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
$.block
|
field('body', $.block)
|
||||||
),
|
),
|
||||||
|
|
||||||
// Species declaration
|
// Species declaration
|
||||||
species: $ => seq(
|
species_declaration: $ => seq(
|
||||||
'species',
|
'species',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
|
field('body', $.species_body)
|
||||||
|
),
|
||||||
|
|
||||||
|
species_body: $ => seq(
|
||||||
'{',
|
'{',
|
||||||
repeat($.include),
|
repeat($.include),
|
||||||
repeat($.field),
|
repeat($.species_field),
|
||||||
'}'
|
'}'
|
||||||
),
|
),
|
||||||
|
|
||||||
|
species_field: $ => choice(
|
||||||
|
// Field with range: name: min..max
|
||||||
|
seq(
|
||||||
|
field('name', $.identifier),
|
||||||
|
':',
|
||||||
|
field('value', $.range)
|
||||||
|
),
|
||||||
|
// Field with single value: name: value
|
||||||
|
seq(
|
||||||
|
field('name', $.identifier),
|
||||||
|
':',
|
||||||
|
field('value', choice($.integer, $.float, $.boolean, $.string))
|
||||||
|
),
|
||||||
|
$.prose_block
|
||||||
|
),
|
||||||
|
|
||||||
// Enum declaration
|
// Enum declaration
|
||||||
enum_declaration: $ => seq(
|
enum_declaration: $ => seq(
|
||||||
'enum',
|
'enum',
|
||||||
@@ -382,8 +517,7 @@ module.exports = grammar({
|
|||||||
// Concept declaration - base type with no structure
|
// Concept declaration - base type with no structure
|
||||||
concept_declaration: $ => seq(
|
concept_declaration: $ => seq(
|
||||||
'concept',
|
'concept',
|
||||||
field('name', $.identifier),
|
field('name', $.identifier)
|
||||||
';'
|
|
||||||
),
|
),
|
||||||
|
|
||||||
// Sub-concept declaration - enum or record subtype with dot notation
|
// Sub-concept declaration - enum or record subtype with dot notation
|
||||||
@@ -403,13 +537,13 @@ module.exports = grammar({
|
|||||||
// Enum form: Variant1, Variant2, Variant3
|
// Enum form: Variant1, Variant2, Variant3
|
||||||
sub_concept_enum_body: $ => commaSep1($.identifier),
|
sub_concept_enum_body: $ => commaSep1($.identifier),
|
||||||
|
|
||||||
// Record form: field_name: Type, field_name: any
|
// Record form: field_name: value, field_name: value
|
||||||
sub_concept_record_body: $ => commaSep1($.sub_concept_field),
|
sub_concept_record_body: $ => commaSep1($.sub_concept_field),
|
||||||
|
|
||||||
sub_concept_field: $ => seq(
|
sub_concept_field: $ => seq(
|
||||||
field('name', $.identifier),
|
field('name', $.identifier),
|
||||||
':',
|
':',
|
||||||
field('type', choice($.identifier, $.any_type))
|
field('value', choice($.integer, $.float, $.string, $.boolean))
|
||||||
),
|
),
|
||||||
|
|
||||||
any_type: $ => 'any',
|
any_type: $ => 'any',
|
||||||
@@ -432,25 +566,26 @@ module.exports = grammar({
|
|||||||
'}'
|
'}'
|
||||||
),
|
),
|
||||||
|
|
||||||
// A condition on a sub_concept field
|
// Field condition: field_name: any OR field_name: Type is Value [or Type is Value]*
|
||||||
field_condition: $ => seq(
|
field_condition: $ => seq(
|
||||||
field('sub_concept', $.dotted_path),
|
field('name', $.identifier),
|
||||||
':',
|
':',
|
||||||
field('condition', $.condition_expr)
|
field('condition', choice(
|
||||||
|
$.any_type,
|
||||||
|
$.is_condition
|
||||||
|
))
|
||||||
),
|
),
|
||||||
|
|
||||||
// Condition: either 'any' or 'Type is Value or Type is Value2'
|
// Is condition: Type is Value [or Type is Value]*
|
||||||
condition_expr: $ => choice(
|
|
||||||
$.any_type,
|
|
||||||
$.is_condition
|
|
||||||
),
|
|
||||||
|
|
||||||
// Pattern: DottedPath is Ident [or DottedPath is Ident]*
|
|
||||||
is_condition: $ => seq(
|
is_condition: $ => seq(
|
||||||
$.dotted_path,
|
$.is_value,
|
||||||
|
repeat(seq('or', $.is_value))
|
||||||
|
),
|
||||||
|
|
||||||
|
is_value: $ => seq(
|
||||||
|
field('field', $.identifier),
|
||||||
'is',
|
'is',
|
||||||
$.identifier,
|
field('value', $.identifier)
|
||||||
repeat(seq('or', $.dotted_path, 'is', $.identifier))
|
|
||||||
),
|
),
|
||||||
|
|
||||||
// Expressions (for conditions in life arcs)
|
// Expressions (for conditions in life arcs)
|
||||||
|
|||||||
@@ -69,30 +69,30 @@
|
|||||||
(string) @string
|
(string) @string
|
||||||
|
|
||||||
; Identifiers in different contexts
|
; Identifiers in different contexts
|
||||||
(character name: (identifier) @type.character)
|
(character_declaration name: (identifier) @type.character)
|
||||||
(template name: (identifier) @type.template)
|
(template_declaration name: (identifier) @type.template)
|
||||||
(life_arc name: (identifier) @type.life_arc)
|
(life_arc_declaration name: (identifier) @type.life_arc)
|
||||||
(schedule name: (identifier) @type.schedule)
|
(schedule_declaration name: (identifier) @type.schedule)
|
||||||
(behavior name: (identifier) @type.behavior)
|
(behavior_declaration name: (identifier) @type.behavior)
|
||||||
(institution name: (identifier) @type.institution)
|
(institution_declaration name: (identifier) @type.institution)
|
||||||
(relationship name: (identifier) @type.relationship)
|
(relationship_declaration name: (identifier) @type.relationship)
|
||||||
(location name: (identifier) @type.location)
|
(location_declaration name: (identifier) @type.location)
|
||||||
(species name: (identifier) @type.species)
|
(species_declaration name: (identifier) @type.species)
|
||||||
(enum_declaration name: (identifier) @type.enum)
|
(enum_declaration name: (identifier) @type.enum)
|
||||||
(arc_state name: (identifier) @type.state)
|
(state_block name: (identifier) @type.state)
|
||||||
(concept_declaration name: (identifier) @type.concept)
|
(concept_declaration name: (identifier) @type.concept)
|
||||||
(sub_concept parent: (identifier) @type.concept)
|
(sub_concept parent: (identifier) @type.concept)
|
||||||
(sub_concept name: (identifier) @type.sub_concept)
|
(sub_concept name: (identifier) @type.sub_concept)
|
||||||
(concept_comparison name: (identifier) @type.concept_comparison)
|
(concept_comparison name: (identifier) @type.concept_comparison)
|
||||||
(variant_pattern name: (identifier) @type.variant)
|
(variant_pattern name: (identifier) @type.variant)
|
||||||
(template species: (identifier) @type.builtin)
|
(template_declaration species: (identifier) @type.builtin)
|
||||||
|
|
||||||
; Field names
|
; Field names
|
||||||
(field name: (dotted_path) @property)
|
(field name: (dotted_path) @property)
|
||||||
(sub_concept_field name: (identifier) @property)
|
(sub_concept_field name: (identifier) @property)
|
||||||
|
|
||||||
; Species reference
|
; Species reference
|
||||||
(character species: (identifier) @type.builtin)
|
(character_declaration species: (identifier) @type.builtin)
|
||||||
|
|
||||||
; Paths and identifiers
|
; Paths and identifiers
|
||||||
(path) @namespace
|
(path) @namespace
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
(transition target: (identifier) @type.state)
|
(transition target: (identifier) @type.state)
|
||||||
|
|
||||||
; Schedule blocks
|
; Schedule blocks
|
||||||
(schedule_block activity: (identifier) @function.activity)
|
(schedule_block name: (identifier) @function.schedule_block)
|
||||||
|
|
||||||
; Override operations
|
; Override operations
|
||||||
(override "@" @keyword.override)
|
(override "@" @keyword.override)
|
||||||
|
|||||||
@@ -24,17 +24,17 @@
|
|||||||
; Block structures that should indent their contents
|
; Block structures that should indent their contents
|
||||||
[
|
[
|
||||||
(block)
|
(block)
|
||||||
(character)
|
(character_declaration)
|
||||||
(template)
|
(template_declaration)
|
||||||
(life_arc)
|
(life_arc_declaration)
|
||||||
(arc_state)
|
(state_block)
|
||||||
(schedule)
|
(schedule_declaration)
|
||||||
(schedule_block)
|
(schedule_block)
|
||||||
(behavior)
|
(behavior_declaration)
|
||||||
(institution)
|
(institution_declaration)
|
||||||
(relationship)
|
(relationship_declaration)
|
||||||
(location)
|
(location_declaration)
|
||||||
(species)
|
(species_declaration)
|
||||||
(enum_declaration)
|
(enum_declaration)
|
||||||
(selector_node)
|
(selector_node)
|
||||||
(sequence_node)
|
(sequence_node)
|
||||||
@@ -46,4 +46,3 @@
|
|||||||
|
|
||||||
; Dedent after semicolon at top level
|
; Dedent after semicolon at top level
|
||||||
(use_declaration ";" @indent.end)
|
(use_declaration ";" @indent.end)
|
||||||
(concept_declaration ";" @indent.end)
|
|
||||||
|
|||||||
@@ -2,52 +2,52 @@
|
|||||||
; Defines what symbols appear in the document outline
|
; Defines what symbols appear in the document outline
|
||||||
|
|
||||||
; Characters
|
; Characters
|
||||||
(character
|
(character_declaration
|
||||||
name: (identifier) @name
|
name: (identifier) @name
|
||||||
) @symbol.character
|
) @symbol.character
|
||||||
|
|
||||||
; Templates
|
; Templates
|
||||||
(template
|
(template_declaration
|
||||||
name: (identifier) @name
|
name: (identifier) @name
|
||||||
) @symbol.template
|
) @symbol.template
|
||||||
|
|
||||||
; Life arcs
|
; Life arcs
|
||||||
(life_arc
|
(life_arc_declaration
|
||||||
name: (identifier) @name
|
name: (identifier) @name
|
||||||
) @symbol.life_arc
|
) @symbol.life_arc
|
||||||
|
|
||||||
; Life arc states
|
; Life arc states
|
||||||
(arc_state
|
(state_block
|
||||||
name: (identifier) @name
|
name: (identifier) @name
|
||||||
) @symbol.state
|
) @symbol.state
|
||||||
|
|
||||||
; Schedules
|
; Schedules
|
||||||
(schedule
|
(schedule_declaration
|
||||||
name: (identifier) @name
|
name: (identifier) @name
|
||||||
) @symbol.schedule
|
) @symbol.schedule
|
||||||
|
|
||||||
; Behaviors
|
; Behaviors
|
||||||
(behavior
|
(behavior_declaration
|
||||||
name: (identifier) @name
|
name: (identifier) @name
|
||||||
) @symbol.behavior
|
) @symbol.behavior
|
||||||
|
|
||||||
; Institutions
|
; Institutions
|
||||||
(institution
|
(institution_declaration
|
||||||
name: (identifier) @name
|
name: (identifier) @name
|
||||||
) @symbol.institution
|
) @symbol.institution
|
||||||
|
|
||||||
; Relationships
|
; Relationships
|
||||||
(relationship
|
(relationship_declaration
|
||||||
name: (identifier) @name
|
name: (identifier) @name
|
||||||
) @symbol.relationship
|
) @symbol.relationship
|
||||||
|
|
||||||
; Locations
|
; Locations
|
||||||
(location
|
(location_declaration
|
||||||
name: (identifier) @name
|
name: (identifier) @name
|
||||||
) @symbol.location
|
) @symbol.location
|
||||||
|
|
||||||
; Species
|
; Species
|
||||||
(species
|
(species_declaration
|
||||||
name: (identifier) @name
|
name: (identifier) @name
|
||||||
) @symbol.species
|
) @symbol.species
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,9 +10,9 @@ character Alice {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(character
|
(character_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
body: (block
|
body: (character_body
|
||||||
(field
|
(field
|
||||||
name: (dotted_path (identifier))
|
name: (dotted_path (identifier))
|
||||||
value: (value (integer)))))))
|
value: (value (integer)))))))
|
||||||
@@ -47,9 +47,9 @@ character Bob {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(character
|
(character_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
body: (block
|
body: (character_body
|
||||||
(field
|
(field
|
||||||
(prose_block
|
(prose_block
|
||||||
marker: (prose_marker)
|
marker: (prose_marker)
|
||||||
|
|||||||
@@ -1,29 +1,11 @@
|
|||||||
==================
|
==================
|
||||||
Simple Behavior
|
Basic behavior tree
|
||||||
==================
|
==================
|
||||||
|
|
||||||
behavior SimpleBehavior {
|
behavior BasicNeeds {
|
||||||
walk_around
|
then {
|
||||||
}
|
CheckHunger
|
||||||
|
if(hungry) { EatFood }
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(behavior
|
|
||||||
name: (identifier)
|
|
||||||
root: (behavior_node
|
|
||||||
(action_node (identifier))))))
|
|
||||||
|
|
||||||
==================
|
|
||||||
Selector Behavior
|
|
||||||
==================
|
|
||||||
|
|
||||||
behavior SelectorBehavior {
|
|
||||||
? {
|
|
||||||
try_option_a
|
|
||||||
try_option_b
|
|
||||||
fallback
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,23 +13,33 @@ behavior SelectorBehavior {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(behavior
|
(behavior_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
root: (behavior_node
|
body: (behavior_body
|
||||||
(selector_node
|
root: (behavior_node
|
||||||
(behavior_node (action_node (identifier)))
|
(sequence_node
|
||||||
(behavior_node (action_node (identifier)))
|
(behavior_node
|
||||||
(behavior_node (action_node (identifier))))))))
|
(action_node
|
||||||
|
(identifier)))
|
||||||
|
(behavior_node
|
||||||
|
(if_decorator_node
|
||||||
|
condition: (expression
|
||||||
|
(primary_expression
|
||||||
|
(path
|
||||||
|
(path_segments
|
||||||
|
(identifier)))))
|
||||||
|
child: (behavior_node
|
||||||
|
(action_node
|
||||||
|
(identifier)))))))))))
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Sequence Behavior
|
Behavior with selector
|
||||||
==================
|
==================
|
||||||
|
|
||||||
behavior SequenceBehavior {
|
behavior Combat {
|
||||||
> {
|
choose {
|
||||||
check_energy
|
if(has_weapon) { Attack }
|
||||||
move_to_location
|
Flee
|
||||||
perform_action
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,25 +47,32 @@ behavior SequenceBehavior {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(behavior
|
(behavior_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
root: (behavior_node
|
body: (behavior_body
|
||||||
(sequence_node
|
root: (behavior_node
|
||||||
(behavior_node (action_node (identifier)))
|
(selector_node
|
||||||
(behavior_node (action_node (identifier)))
|
(behavior_node
|
||||||
(behavior_node (action_node (identifier))))))))
|
(if_decorator_node
|
||||||
|
condition: (expression
|
||||||
|
(primary_expression
|
||||||
|
(path
|
||||||
|
(path_segments
|
||||||
|
(identifier)))))
|
||||||
|
child: (behavior_node
|
||||||
|
(action_node
|
||||||
|
(identifier)))))
|
||||||
|
(behavior_node
|
||||||
|
(action_node
|
||||||
|
(identifier)))))))))
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Nested Behavior
|
Behavior with repeat
|
||||||
==================
|
==================
|
||||||
|
|
||||||
behavior NestedBehavior {
|
behavior Patrol {
|
||||||
> {
|
repeat(5) {
|
||||||
? {
|
WalkPath
|
||||||
check_condition_a
|
|
||||||
check_condition_b
|
|
||||||
}
|
|
||||||
perform_action
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,100 +80,12 @@ behavior NestedBehavior {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(behavior
|
(behavior_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
root: (behavior_node
|
body: (behavior_body
|
||||||
(sequence_node
|
root: (behavior_node
|
||||||
(behavior_node
|
(repeat_node
|
||||||
(selector_node
|
params: (integer)
|
||||||
(behavior_node (action_node (identifier)))
|
child: (behavior_node
|
||||||
(behavior_node (action_node (identifier)))))
|
(action_node
|
||||||
(behavior_node (action_node (identifier))))))))
|
(identifier)))))))))
|
||||||
|
|
||||||
==================
|
|
||||||
Repeat Behavior
|
|
||||||
==================
|
|
||||||
|
|
||||||
behavior RepeatBehavior {
|
|
||||||
* {
|
|
||||||
patrol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(behavior
|
|
||||||
name: (identifier)
|
|
||||||
root: (behavior_node
|
|
||||||
(repeat_node
|
|
||||||
(behavior_node (action_node (identifier))))))))
|
|
||||||
|
|
||||||
==================
|
|
||||||
Behavior with Subtree
|
|
||||||
==================
|
|
||||||
|
|
||||||
behavior WithSubtree {
|
|
||||||
> {
|
|
||||||
@helpers::check_preconditions
|
|
||||||
main_action
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(behavior
|
|
||||||
name: (identifier)
|
|
||||||
root: (behavior_node
|
|
||||||
(sequence_node
|
|
||||||
(behavior_node
|
|
||||||
(subtree_node
|
|
||||||
(path
|
|
||||||
(path_segments
|
|
||||||
(identifier)
|
|
||||||
(identifier)))))
|
|
||||||
(behavior_node (action_node (identifier))))))))
|
|
||||||
|
|
||||||
==================
|
|
||||||
Complex Nested Behavior
|
|
||||||
==================
|
|
||||||
|
|
||||||
behavior ComplexBehavior {
|
|
||||||
? {
|
|
||||||
> {
|
|
||||||
check_threat
|
|
||||||
flee_to_safety
|
|
||||||
}
|
|
||||||
> {
|
|
||||||
check_resources
|
|
||||||
gather_resources
|
|
||||||
}
|
|
||||||
* {
|
|
||||||
idle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(behavior
|
|
||||||
name: (identifier)
|
|
||||||
root: (behavior_node
|
|
||||||
(selector_node
|
|
||||||
(behavior_node
|
|
||||||
(sequence_node
|
|
||||||
(behavior_node (action_node (identifier)))
|
|
||||||
(behavior_node (action_node (identifier)))))
|
|
||||||
(behavior_node
|
|
||||||
(sequence_node
|
|
||||||
(behavior_node (action_node (identifier)))
|
|
||||||
(behavior_node (action_node (identifier)))))
|
|
||||||
(behavior_node
|
|
||||||
(repeat_node
|
|
||||||
(behavior_node (action_node (identifier))))))))))
|
|
||||||
|
|
||||||
|
|||||||
@@ -67,11 +67,11 @@ character Alice: Human from Curious {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(character
|
(character_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
species: (identifier)
|
species: (identifier)
|
||||||
template: (template_clause (identifier))
|
template: (template_clause (identifier))
|
||||||
body: (block
|
body: (character_body
|
||||||
(field
|
(field
|
||||||
name: (dotted_path (identifier))
|
name: (dotted_path (identifier))
|
||||||
value: (value (integer)))
|
value: (value (integer)))
|
||||||
@@ -110,16 +110,17 @@ template BaseCharacter strict {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(template
|
(template_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(include (identifier))
|
body: (template_body
|
||||||
(include (identifier))
|
(include (identifier))
|
||||||
(field
|
(include (identifier))
|
||||||
name: (dotted_path (identifier))
|
(field
|
||||||
value: (value (integer)))
|
name: (dotted_path (identifier))
|
||||||
(field
|
value: (value (integer)))
|
||||||
name: (dotted_path (identifier))
|
(field
|
||||||
value: (value (string))))))
|
name: (dotted_path (identifier))
|
||||||
|
value: (value (string)))))))
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Life arc with states and transitions
|
Life arc with states and transitions
|
||||||
@@ -150,7 +151,7 @@ life_arc Journey {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(life_arc
|
(life_arc_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(field
|
(field
|
||||||
(prose_block
|
(prose_block
|
||||||
@@ -158,115 +159,32 @@ life_arc Journey {
|
|||||||
tag: (identifier)
|
tag: (identifier)
|
||||||
content: (prose_content)
|
content: (prose_content)
|
||||||
end: (prose_marker)))
|
end: (prose_marker)))
|
||||||
(arc_state
|
(state_block
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(on_enter
|
body: (state_body
|
||||||
(block
|
(on_enter
|
||||||
(field
|
(block
|
||||||
name: (dotted_path (identifier))
|
(field
|
||||||
value: (value (integer)))))
|
name: (dotted_path (identifier))
|
||||||
(transition
|
value: (value (integer)))))
|
||||||
condition: (expression
|
(transition
|
||||||
(comparison
|
condition: (expression
|
||||||
(expression (primary_expression (path (path_segments (identifier)))))
|
(comparison
|
||||||
(expression (primary_expression (integer)))))
|
(expression (primary_expression (path (path_segments (identifier)))))
|
||||||
target: (identifier)))
|
(expression (primary_expression (integer)))))
|
||||||
(arc_state
|
target: (identifier))))
|
||||||
|
(state_block
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(transition
|
body: (state_body
|
||||||
condition: (expression
|
(transition
|
||||||
(comparison
|
condition: (expression
|
||||||
(expression (primary_expression (path (path_segments (identifier)))))
|
(comparison
|
||||||
(expression (primary_expression (boolean)))))
|
(expression (primary_expression (path (path_segments (identifier)))))
|
||||||
target: (identifier)))
|
(expression (primary_expression (boolean)))))
|
||||||
(arc_state
|
target: (identifier))))
|
||||||
name: (identifier)))))
|
(state_block
|
||||||
|
name: (identifier)
|
||||||
==================
|
body: (state_body)))))
|
||||||
Schedule with time blocks
|
|
||||||
==================
|
|
||||||
|
|
||||||
schedule DailyRoutine {
|
|
||||||
08:00 -> 09:00: breakfast {
|
|
||||||
location: kitchen
|
|
||||||
}
|
|
||||||
|
|
||||||
09:00 -> 12:00: work {
|
|
||||||
duration: 3h
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(schedule
|
|
||||||
name: (identifier)
|
|
||||||
(schedule_block
|
|
||||||
start: (time)
|
|
||||||
end: (time)
|
|
||||||
activity: (identifier)
|
|
||||||
(block
|
|
||||||
(field
|
|
||||||
name: (dotted_path (identifier))
|
|
||||||
value: (value (path (path_segments (identifier)))))))
|
|
||||||
(schedule_block
|
|
||||||
start: (time)
|
|
||||||
end: (time)
|
|
||||||
activity: (identifier)
|
|
||||||
(block
|
|
||||||
(field
|
|
||||||
name: (dotted_path (identifier))
|
|
||||||
value: (value (duration))))))))
|
|
||||||
|
|
||||||
==================
|
|
||||||
Behavior tree - all node types
|
|
||||||
==================
|
|
||||||
|
|
||||||
behavior GuardBehavior {
|
|
||||||
? {
|
|
||||||
patrol
|
|
||||||
> {
|
|
||||||
detect_threat
|
|
||||||
alert(priority: high, "Guard duty")
|
|
||||||
}
|
|
||||||
* {
|
|
||||||
watch
|
|
||||||
}
|
|
||||||
@base::behaviors::Idle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(behavior
|
|
||||||
name: (identifier)
|
|
||||||
root: (behavior_node
|
|
||||||
(selector_node
|
|
||||||
(behavior_node (action_node (identifier)))
|
|
||||||
(behavior_node
|
|
||||||
(sequence_node
|
|
||||||
(behavior_node (action_node (identifier)))
|
|
||||||
(behavior_node
|
|
||||||
(action_node
|
|
||||||
(identifier)
|
|
||||||
(action_param
|
|
||||||
(dotted_path (identifier))
|
|
||||||
(value (path (path_segments (identifier)))))
|
|
||||||
(action_param
|
|
||||||
(value (string)))))))
|
|
||||||
(behavior_node
|
|
||||||
(repeat_node
|
|
||||||
(behavior_node (action_node (identifier)))))
|
|
||||||
(behavior_node
|
|
||||||
(subtree_node
|
|
||||||
(path
|
|
||||||
(path_segments
|
|
||||||
(identifier)
|
|
||||||
(identifier)
|
|
||||||
(identifier))))))))))
|
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Institution
|
Institution
|
||||||
@@ -281,9 +199,9 @@ institution Wonderland {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(institution
|
(institution_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(block
|
body: (block
|
||||||
(field
|
(field
|
||||||
name: (dotted_path (identifier))
|
name: (dotted_path (identifier))
|
||||||
value: (value (string)))
|
value: (value (string)))
|
||||||
@@ -291,44 +209,6 @@ institution Wonderland {
|
|||||||
name: (dotted_path (identifier))
|
name: (dotted_path (identifier))
|
||||||
value: (value (string)))))))
|
value: (value (string)))))))
|
||||||
|
|
||||||
==================
|
|
||||||
Relationship with participants
|
|
||||||
==================
|
|
||||||
|
|
||||||
relationship Friendship {
|
|
||||||
Alice {
|
|
||||||
bond_strength: 5
|
|
||||||
}
|
|
||||||
|
|
||||||
WhiteRabbit as friend {
|
|
||||||
trust: 0.8
|
|
||||||
}
|
|
||||||
|
|
||||||
Caterpillar
|
|
||||||
}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(relationship
|
|
||||||
name: (identifier)
|
|
||||||
(participant
|
|
||||||
(path (path_segments (identifier)))
|
|
||||||
(block
|
|
||||||
(field
|
|
||||||
name: (dotted_path (identifier))
|
|
||||||
value: (value (integer)))))
|
|
||||||
(participant
|
|
||||||
(path (path_segments (identifier)))
|
|
||||||
(identifier)
|
|
||||||
(block
|
|
||||||
(field
|
|
||||||
name: (dotted_path (identifier))
|
|
||||||
value: (value (float)))))
|
|
||||||
(participant
|
|
||||||
(path (path_segments (identifier)))))))
|
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Location
|
Location
|
||||||
==================
|
==================
|
||||||
@@ -342,9 +222,9 @@ location TeaParty {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(location
|
(location_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(block
|
body: (block
|
||||||
(field
|
(field
|
||||||
name: (dotted_path (identifier))
|
name: (dotted_path (identifier))
|
||||||
value: (value (string)))
|
value: (value (string)))
|
||||||
@@ -367,15 +247,16 @@ species Cat {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(species
|
(species_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(include (identifier))
|
body: (species_body
|
||||||
(field
|
(include (identifier))
|
||||||
name: (dotted_path (identifier))
|
(species_field
|
||||||
value: (value (boolean)))
|
name: (identifier)
|
||||||
(field
|
value: (boolean))
|
||||||
name: (dotted_path (identifier))
|
(species_field
|
||||||
value: (value (integer))))))
|
name: (identifier)
|
||||||
|
value: (integer))))))
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Enum declaration
|
Enum declaration
|
||||||
@@ -413,9 +294,9 @@ character SpecialAlice {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(character
|
(character_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
body: (block
|
body: (character_body
|
||||||
(field
|
(field
|
||||||
name: (dotted_path (identifier))
|
name: (dotted_path (identifier))
|
||||||
value: (value
|
value: (value
|
||||||
@@ -452,49 +333,52 @@ life_arc ComplexLogic {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(life_arc
|
(life_arc_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(arc_state
|
(state_block
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(transition
|
body: (state_body
|
||||||
condition: (expression
|
(transition
|
||||||
(and_expression
|
condition: (expression
|
||||||
(expression
|
(and_expression
|
||||||
(comparison
|
(expression
|
||||||
(expression
|
(comparison
|
||||||
(field_access
|
(expression
|
||||||
(expression (primary_expression))
|
(field_access
|
||||||
(identifier)))
|
(expression (primary_expression))
|
||||||
(expression (primary_expression (integer)))))
|
(identifier)))
|
||||||
(expression
|
(expression (primary_expression (integer)))))
|
||||||
(comparison
|
(expression
|
||||||
(expression
|
(comparison
|
||||||
(field_access
|
(expression
|
||||||
(expression (primary_expression))
|
(field_access
|
||||||
(identifier)))
|
(expression (primary_expression))
|
||||||
(expression (primary_expression (float)))))))
|
(identifier)))
|
||||||
target: (identifier))
|
(expression (primary_expression (float)))))))
|
||||||
(transition
|
target: (identifier))
|
||||||
condition: (expression
|
(transition
|
||||||
(or_expression
|
condition: (expression
|
||||||
(expression
|
(or_expression
|
||||||
(not_expression
|
(expression
|
||||||
(expression
|
(not_expression
|
||||||
(field_access
|
(expression
|
||||||
(expression (primary_expression))
|
(field_access
|
||||||
(identifier)))))
|
(expression (primary_expression))
|
||||||
(expression
|
(identifier)))))
|
||||||
(comparison
|
(expression
|
||||||
(expression
|
(comparison
|
||||||
(field_access
|
(expression
|
||||||
(expression (primary_expression))
|
(field_access
|
||||||
(identifier)))
|
(expression (primary_expression))
|
||||||
(expression (primary_expression (boolean)))))))
|
(identifier)))
|
||||||
target: (identifier)))
|
(expression (primary_expression (boolean)))))))
|
||||||
(arc_state
|
target: (identifier))))
|
||||||
name: (identifier))
|
(state_block
|
||||||
(arc_state
|
name: (identifier)
|
||||||
name: (identifier)))))
|
body: (state_body))
|
||||||
|
(state_block
|
||||||
|
name: (identifier)
|
||||||
|
body: (state_body)))))
|
||||||
|
|
||||||
==================
|
==================
|
||||||
List and object values
|
List and object values
|
||||||
@@ -513,9 +397,9 @@ character DataRich {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(character
|
(character_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
body: (block
|
body: (character_body
|
||||||
(field
|
(field
|
||||||
name: (dotted_path (identifier))
|
name: (dotted_path (identifier))
|
||||||
value: (value
|
value: (value
|
||||||
@@ -560,9 +444,9 @@ character Nested {
|
|||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(character
|
(character_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
body: (block
|
body: (character_body
|
||||||
(field
|
(field
|
||||||
name: (dotted_path
|
name: (dotted_path
|
||||||
(identifier)
|
(identifier)
|
||||||
|
|||||||
53
tree-sitter-storybook/test/corpus/highlights.txt
Normal file
53
tree-sitter-storybook/test/corpus/highlights.txt
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
==================
|
||||||
|
Keywords should highlight
|
||||||
|
==================
|
||||||
|
|
||||||
|
use schema::types;
|
||||||
|
|
||||||
|
character Alice from Person {
|
||||||
|
age: 25
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(source_file
|
||||||
|
(declaration
|
||||||
|
(use_declaration
|
||||||
|
(path_segments
|
||||||
|
(identifier)
|
||||||
|
(identifier))))
|
||||||
|
(declaration
|
||||||
|
(character_declaration
|
||||||
|
name: (identifier)
|
||||||
|
template: (template_clause
|
||||||
|
(identifier))
|
||||||
|
body: (character_body
|
||||||
|
(field
|
||||||
|
name: (dotted_path
|
||||||
|
(identifier))
|
||||||
|
value: (value
|
||||||
|
(integer)))))))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Any type in sub-concept
|
||||||
|
==================
|
||||||
|
|
||||||
|
sub_concept Field.Type {
|
||||||
|
name: "text",
|
||||||
|
value: 42
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(source_file
|
||||||
|
(declaration
|
||||||
|
(sub_concept
|
||||||
|
parent: (identifier)
|
||||||
|
name: (identifier)
|
||||||
|
body: (sub_concept_record_body
|
||||||
|
(sub_concept_field
|
||||||
|
name: (identifier)
|
||||||
|
value: (string))
|
||||||
|
(sub_concept_field
|
||||||
|
name: (identifier)
|
||||||
|
value: (integer))))))
|
||||||
106
tree-sitter-storybook/test/corpus/schedules.txt
Normal file
106
tree-sitter-storybook/test/corpus/schedules.txt
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
==================
|
||||||
|
Basic schedule
|
||||||
|
==================
|
||||||
|
|
||||||
|
schedule WorkDay {
|
||||||
|
block morning {
|
||||||
|
08:00 -> 12:00
|
||||||
|
action: Work
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(source_file
|
||||||
|
(declaration
|
||||||
|
(schedule_declaration
|
||||||
|
name: (identifier)
|
||||||
|
body: (schedule_body
|
||||||
|
(schedule_block
|
||||||
|
name: (identifier)
|
||||||
|
time_range: (time_range
|
||||||
|
start: (time)
|
||||||
|
end: (time))
|
||||||
|
(block_field
|
||||||
|
name: (identifier)
|
||||||
|
value: (identifier)))))))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Schedule with extends
|
||||||
|
==================
|
||||||
|
|
||||||
|
schedule BakerDay extends WorkDay {
|
||||||
|
block early_prep {
|
||||||
|
05:00 -> 08:00
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(source_file
|
||||||
|
(declaration
|
||||||
|
(schedule_declaration
|
||||||
|
name: (identifier)
|
||||||
|
extends: (identifier)
|
||||||
|
body: (schedule_body
|
||||||
|
(schedule_block
|
||||||
|
name: (identifier)
|
||||||
|
time_range: (time_range
|
||||||
|
start: (time)
|
||||||
|
end: (time)))))))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Schedule with override
|
||||||
|
==================
|
||||||
|
|
||||||
|
schedule CustomDay extends BaseDay {
|
||||||
|
override work {
|
||||||
|
06:00 -> 14:00
|
||||||
|
intensity: "high"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(source_file
|
||||||
|
(declaration
|
||||||
|
(schedule_declaration
|
||||||
|
name: (identifier)
|
||||||
|
extends: (identifier)
|
||||||
|
body: (schedule_body
|
||||||
|
(override_block
|
||||||
|
name: (identifier)
|
||||||
|
time_range: (time_range
|
||||||
|
start: (time)
|
||||||
|
end: (time))
|
||||||
|
(block_field
|
||||||
|
name: (identifier)
|
||||||
|
value: (string)))))))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Schedule with recurrence
|
||||||
|
==================
|
||||||
|
|
||||||
|
schedule WeeklySchedule {
|
||||||
|
recurrence MarketDay on Saturday {
|
||||||
|
block market {
|
||||||
|
06:00 -> 14:00
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(source_file
|
||||||
|
(declaration
|
||||||
|
(schedule_declaration
|
||||||
|
name: (identifier)
|
||||||
|
body: (schedule_body
|
||||||
|
(recurrence_block
|
||||||
|
name: (identifier)
|
||||||
|
day: (identifier)
|
||||||
|
(schedule_block
|
||||||
|
name: (identifier)
|
||||||
|
time_range: (time_range
|
||||||
|
start: (time)
|
||||||
|
end: (time))))))))
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
Concept declaration
|
Concept declaration
|
||||||
==================
|
==================
|
||||||
|
|
||||||
concept Cup;
|
concept BakedGood
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -12,34 +12,13 @@ concept Cup;
|
|||||||
name: (identifier))))
|
name: (identifier))))
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Multiple concept declarations
|
Sub-concept enum declaration
|
||||||
==================
|
==================
|
||||||
|
|
||||||
concept Cup;
|
sub_concept BakedGood.Category {
|
||||||
concept Customer;
|
Bread,
|
||||||
concept Vendor;
|
Pastry,
|
||||||
|
Cake
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(concept_declaration
|
|
||||||
name: (identifier)))
|
|
||||||
(declaration
|
|
||||||
(concept_declaration
|
|
||||||
name: (identifier)))
|
|
||||||
(declaration
|
|
||||||
(concept_declaration
|
|
||||||
name: (identifier))))
|
|
||||||
|
|
||||||
==================
|
|
||||||
Sub-concept - enum form
|
|
||||||
==================
|
|
||||||
|
|
||||||
sub_concept Cup.Size {
|
|
||||||
Small,
|
|
||||||
Medium,
|
|
||||||
Large
|
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -55,14 +34,12 @@ sub_concept Cup.Size {
|
|||||||
(identifier)))))
|
(identifier)))))
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Sub-concept - record form with any
|
Sub-concept record declaration with values
|
||||||
==================
|
==================
|
||||||
|
|
||||||
sub_concept Vendor.Inventory {
|
sub_concept BakedGood.Quality {
|
||||||
Bread: any,
|
freshness: 1.0,
|
||||||
Pastries: any,
|
taste: 0.8
|
||||||
Cakes: any,
|
|
||||||
Cup: any
|
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -75,51 +52,18 @@ sub_concept Vendor.Inventory {
|
|||||||
body: (sub_concept_record_body
|
body: (sub_concept_record_body
|
||||||
(sub_concept_field
|
(sub_concept_field
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
type: (any_type))
|
value: (float))
|
||||||
(sub_concept_field
|
(sub_concept_field
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
type: (any_type))
|
value: (float))))))
|
||||||
(sub_concept_field
|
|
||||||
name: (identifier)
|
|
||||||
type: (any_type))
|
|
||||||
(sub_concept_field
|
|
||||||
name: (identifier)
|
|
||||||
type: (any_type))))))
|
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Sub-concept - record form with typed fields
|
Concept comparison
|
||||||
==================
|
==================
|
||||||
|
|
||||||
sub_concept Vendor.Inventory {
|
concept_comparison SkillLevel {
|
||||||
Bread: any,
|
Apprentice: { freshness: any },
|
||||||
Pastries: Number
|
Master: { freshness: Tier is Master }
|
||||||
}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(sub_concept
|
|
||||||
parent: (identifier)
|
|
||||||
name: (identifier)
|
|
||||||
body: (sub_concept_record_body
|
|
||||||
(sub_concept_field
|
|
||||||
name: (identifier)
|
|
||||||
type: (any_type))
|
|
||||||
(sub_concept_field
|
|
||||||
name: (identifier)
|
|
||||||
type: (identifier))))))
|
|
||||||
|
|
||||||
==================
|
|
||||||
Concept comparison with any conditions
|
|
||||||
==================
|
|
||||||
|
|
||||||
concept_comparison NotInterested {
|
|
||||||
NotInterested: {
|
|
||||||
Cup.Size: any,
|
|
||||||
Cup.Type: any,
|
|
||||||
Cup.Color: any
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -131,230 +75,58 @@ concept_comparison NotInterested {
|
|||||||
(variant_pattern
|
(variant_pattern
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(field_condition
|
(field_condition
|
||||||
sub_concept: (dotted_path
|
name: (identifier)
|
||||||
(identifier)
|
condition: (any_type)))
|
||||||
(identifier))
|
(variant_pattern
|
||||||
condition: (condition_expr
|
name: (identifier)
|
||||||
(any_type)))
|
|
||||||
(field_condition
|
(field_condition
|
||||||
sub_concept: (dotted_path
|
name: (identifier)
|
||||||
(identifier)
|
condition: (is_condition
|
||||||
(identifier))
|
(is_value
|
||||||
condition: (condition_expr
|
field: (identifier)
|
||||||
(any_type)))
|
value: (identifier))))))))
|
||||||
(field_condition
|
|
||||||
sub_concept: (dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
condition: (condition_expr
|
|
||||||
(any_type)))))))
|
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Concept comparison with is conditions
|
Species declaration
|
||||||
==================
|
==================
|
||||||
|
|
||||||
concept_comparison Interest {
|
species Human {
|
||||||
Interested: {
|
age: 25
|
||||||
Cup.Type: Cup.Type is Glass or Cup.Type is Plastic,
|
energy: 0.75
|
||||||
Cup.Color: Cup.Color is Red
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(concept_comparison
|
(species_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
(variant_pattern
|
body: (species_body
|
||||||
name: (identifier)
|
(species_field
|
||||||
(field_condition
|
name: (identifier)
|
||||||
sub_concept: (dotted_path
|
value: (integer))
|
||||||
(identifier)
|
(species_field
|
||||||
(identifier))
|
name: (identifier)
|
||||||
condition: (condition_expr
|
value: (float))))))
|
||||||
(is_condition
|
|
||||||
(dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
(identifier)
|
|
||||||
(dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
(identifier))))
|
|
||||||
(field_condition
|
|
||||||
sub_concept: (dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
condition: (condition_expr
|
|
||||||
(is_condition
|
|
||||||
(dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
(identifier))))))))
|
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Concept comparison with multiple variants
|
Template with species base
|
||||||
==================
|
|
||||||
|
|
||||||
concept_comparison FoodQuality {
|
|
||||||
Excellent: {
|
|
||||||
Food.Freshness: Food.Freshness is Fresh
|
|
||||||
},
|
|
||||||
Poor: {
|
|
||||||
Food.Freshness: Food.Freshness is Stale or Food.Freshness is Spoiled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(concept_comparison
|
|
||||||
name: (identifier)
|
|
||||||
(variant_pattern
|
|
||||||
name: (identifier)
|
|
||||||
(field_condition
|
|
||||||
sub_concept: (dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
condition: (condition_expr
|
|
||||||
(is_condition
|
|
||||||
(dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
(identifier)))))
|
|
||||||
(variant_pattern
|
|
||||||
name: (identifier)
|
|
||||||
(field_condition
|
|
||||||
sub_concept: (dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
condition: (condition_expr
|
|
||||||
(is_condition
|
|
||||||
(dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
(identifier)
|
|
||||||
(dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
(identifier))))))))
|
|
||||||
|
|
||||||
==================
|
|
||||||
Template with species extension
|
|
||||||
==================
|
==================
|
||||||
|
|
||||||
template Person: Human {
|
template Person: Human {
|
||||||
age: 0..100
|
name: "Unknown"
|
||||||
name: ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
(source_file
|
(source_file
|
||||||
(declaration
|
(declaration
|
||||||
(template
|
(template_declaration
|
||||||
name: (identifier)
|
name: (identifier)
|
||||||
species: (identifier)
|
species: (identifier)
|
||||||
(field
|
body: (template_body
|
||||||
name: (dotted_path (identifier))
|
(field
|
||||||
value: (value (range (integer) (integer))))
|
name: (dotted_path
|
||||||
(field
|
|
||||||
name: (dotted_path (identifier))
|
|
||||||
value: (value (string))))))
|
|
||||||
|
|
||||||
==================
|
|
||||||
Full type system example
|
|
||||||
==================
|
|
||||||
|
|
||||||
concept Cup;
|
|
||||||
|
|
||||||
sub_concept Cup.Size {
|
|
||||||
Small,
|
|
||||||
Medium,
|
|
||||||
Large
|
|
||||||
}
|
|
||||||
|
|
||||||
sub_concept Cup.Type {
|
|
||||||
Ceramic,
|
|
||||||
Glass,
|
|
||||||
Plastic
|
|
||||||
}
|
|
||||||
|
|
||||||
concept_comparison CupPreference {
|
|
||||||
Preferred: {
|
|
||||||
Cup.Size: any,
|
|
||||||
Cup.Type: Cup.Type is Glass or Cup.Type is Ceramic
|
|
||||||
},
|
|
||||||
Avoided: {
|
|
||||||
Cup.Size: any,
|
|
||||||
Cup.Type: Cup.Type is Plastic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(source_file
|
|
||||||
(declaration
|
|
||||||
(concept_declaration
|
|
||||||
name: (identifier)))
|
|
||||||
(declaration
|
|
||||||
(sub_concept
|
|
||||||
parent: (identifier)
|
|
||||||
name: (identifier)
|
|
||||||
body: (sub_concept_enum_body
|
|
||||||
(identifier)
|
|
||||||
(identifier)
|
|
||||||
(identifier))))
|
|
||||||
(declaration
|
|
||||||
(sub_concept
|
|
||||||
parent: (identifier)
|
|
||||||
name: (identifier)
|
|
||||||
body: (sub_concept_enum_body
|
|
||||||
(identifier)
|
|
||||||
(identifier)
|
|
||||||
(identifier))))
|
|
||||||
(declaration
|
|
||||||
(concept_comparison
|
|
||||||
name: (identifier)
|
|
||||||
(variant_pattern
|
|
||||||
name: (identifier)
|
|
||||||
(field_condition
|
|
||||||
sub_concept: (dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
(identifier))
|
||||||
condition: (condition_expr
|
value: (value
|
||||||
(any_type)))
|
(string)))))))
|
||||||
(field_condition
|
|
||||||
sub_concept: (dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
condition: (condition_expr
|
|
||||||
(is_condition
|
|
||||||
(dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
(identifier)
|
|
||||||
(dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
(identifier)))))
|
|
||||||
(variant_pattern
|
|
||||||
name: (identifier)
|
|
||||||
(field_condition
|
|
||||||
sub_concept: (dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
condition: (condition_expr
|
|
||||||
(any_type)))
|
|
||||||
(field_condition
|
|
||||||
sub_concept: (dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
condition: (condition_expr
|
|
||||||
(is_condition
|
|
||||||
(dotted_path
|
|
||||||
(identifier)
|
|
||||||
(identifier))
|
|
||||||
(identifier))))))))
|
|
||||||
|
|||||||
Submodule zed-storybook/grammars/storybook deleted from 26bbef58d3
Reference in New Issue
Block a user