Skip to main content

yog_script_analyze/
words.rs

1//! The words of Yog Script. Each word is one file under `words/`: how it's
2//! written, what it means (shown by editors) and how it parses. The parser
3//! core only hands each word its turn; this file only lists them.
4
5use std::fmt;
6
7use crate::ast::{DeclKind, Expr, Modifier, PatchItem, Point, Stmt};
8use crate::parser::{PResult, Parser};
9
10/// One word of the language.
11pub struct Word {
12    /// How it's written.
13    pub text: &'static str,
14    /// What it means, for editors (hover, completion).
15    pub doc: &'static str,
16    /// Reserved everywhere (a keyword); otherwise a name where its forms
17    /// don't apply.
18    pub reserved: bool,
19    /// What it does where it stands.
20    pub roles: &'static [Role],
21}
22
23/// Whether a form starts here, beyond the word itself being here.
24pub type Starts = Option<fn(&Parser) -> bool>;
25
26/// What a word does where the parser meets it.
27#[derive(Clone, Copy)]
28pub enum Role {
29    /// Starts a declaration.
30    Decl {
31        starts: Starts,
32        parse: fn(&mut Parser) -> PResult<DeclKind>,
33    },
34    /// Starts a statement.
35    Stmt {
36        parse: fn(&mut Parser) -> PResult<Stmt>,
37    },
38    /// Starts an expression (a literal, a prefix, `new`).
39    Prefix {
40        starts: Starts,
41        parse: fn(&mut Parser) -> PResult<Expr>,
42    },
43    /// Joins the expression before it with what follows.
44    Infix {
45        level: Level,
46        parse: fn(&mut Parser, Expr) -> PResult<Expr>,
47    },
48    /// Marks the declaration after it.
49    Modifier(Modifier),
50    /// A built-in type (`i32`, `string`, `void`).
51    BuiltinType,
52    /// Starts an item of a patch (`before`, `add`, …).
53    PatchItem {
54        parse: fn(&mut Parser) -> PResult<PatchItem>,
55    },
56    /// Starts a point inside a patched method (`around`, `at`, …).
57    Point {
58        parse: fn(&mut Parser) -> PResult<Point>,
59    },
60    /// Only part of another word's form (`else`, `was`, `when`).
61    Part,
62}
63
64/// Binding strength of infix forms, loosest first (`ys-grammar.md` §3.2).
65/// Lambdas and `c ? a : b` are looser still; prefixes and postfixes tighter.
66#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
67pub enum Level {
68    Coalesce,
69    Or,
70    And,
71    Equality,
72    Compare,
73    Range,
74    Sum,
75    Product,
76    Switch,
77}
78
79impl Word {
80    /// Its role of the kind `pick` finds.
81    pub fn role<T>(&self, pick: impl Fn(&Role) -> Option<T>) -> Option<T> {
82        self.roles.iter().find_map(pick)
83    }
84
85    /// Whether it names a built-in type.
86    pub fn is_type(&self) -> bool {
87        self.roles.iter().any(|r| matches!(r, Role::BuiltinType))
88    }
89}
90
91impl PartialEq for Word {
92    fn eq(&self, other: &Word) -> bool {
93        self.text == other.text
94    }
95}
96
97impl fmt::Debug for Word {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        write!(f, "`{}`", self.text)
100    }
101}
102
103/// The reserved word written `text`.
104pub fn reserved(text: &str) -> Option<&'static Word> {
105    ALL.iter().copied().find(|w| w.reserved && w.text == text)
106}
107
108/// The word written `text`, reserved or not.
109pub fn named(text: &str) -> Option<&'static Word> {
110    ALL.iter().copied().find(|w| w.text == text)
111}
112
113macro_rules! words {
114    ($($file:ident $(= $path:literal)?),* $(,)?) => {
115        $($(#[path = $path])? pub mod $file;)*
116
117        /// Every word, in the order the parser offers them a turn.
118        pub static ALL: &[&Word] = &[$(&$file::WORD),*];
119    };
120}
121
122words! {
123    // Files and declarations. `mod.rs` can't name a module file: its says `_word`.
124    using, global, namespace, module = "words/mod_word.rs", r#macro, class, r#struct, record, interface, r#enum, unit,
125    component, system, extend, event, test, screen, command, patch, targets,
126    // Parts of declarations.
127    was, requires, every, has, r#where, when, get, set, init, value, field, mc, out,
128    // Modifiers.
129    public, private, internal, protected, r#static, r#const, readonly, r#async,
130    r#abstract, r#virtual, r#override, sealed, r#extern,
131    server, client, shared, saved, synced, tune,
132    // Built-in types.
133    void, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, decimal, bool, char, string, object,
134    dynamic,
135    // Statements.
136    r#let, r#mut, r#if, r#else, foreach, r#for, r#while, r#do, r#break, r#continue, r#return, skip,
137    // Expressions.
138    new, this, base, r#ref, r#move, r#typeof, nameof, default, r#true, r#false, null, r#await, r#try, is, r#as, r#in, switch, and, or, not,
139    // Patches: items, points, selectors.
140    add, before, after, inside, replace, read, write, priority, uses, local,
141    around, at, call, constant, first, last,
142}