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    BitOr,
72    BitXor,
73    BitAnd,
74    Equality,
75    Compare,
76    Range,
77    Shift,
78    Sum,
79    Product,
80    Switch,
81}
82
83impl Word {
84    /// Its role of the kind `pick` finds.
85    pub fn role<T>(&self, pick: impl Fn(&Role) -> Option<T>) -> Option<T> {
86        self.roles.iter().find_map(pick)
87    }
88
89    /// Whether it names a built-in type.
90    pub fn is_type(&self) -> bool {
91        self.roles.iter().any(|r| matches!(r, Role::BuiltinType))
92    }
93}
94
95impl PartialEq for Word {
96    fn eq(&self, other: &Word) -> bool {
97        self.text == other.text
98    }
99}
100
101impl fmt::Debug for Word {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        write!(f, "`{}`", self.text)
104    }
105}
106
107/// The reserved word written `text`.
108pub fn reserved(text: &str) -> Option<&'static Word> {
109    ALL.iter().copied().find(|w| w.reserved && w.text == text)
110}
111
112/// The word written `text`, reserved or not.
113pub fn named(text: &str) -> Option<&'static Word> {
114    ALL.iter().copied().find(|w| w.text == text)
115}
116
117macro_rules! words {
118    ($($file:ident $(= $path:literal)?),* $(,)?) => {
119        $($(#[path = $path])? pub mod $file;)*
120
121        /// Every word, in the order the parser offers them a turn.
122        pub static ALL: &[&Word] = &[$(&$file::WORD),*];
123    };
124}
125
126words! {
127    // Files and declarations. `mod.rs` can't name a module file: its says `_word`.
128    using, global, namespace, module = "words/mod_word.rs", r#macro, class, r#struct, record, interface, r#enum, unit,
129    component, system, extend, event, delegate, test, screen, command, patch, targets,
130    // Parts of declarations.
131    was, requires, every, has, params, r#where, when, get, set, init, value, field, operator, implicit, explicit, mc, out,
132    // Modifiers.
133    public, private, internal, protected, r#static, r#const, readonly, r#async,
134    r#abstract, r#virtual, r#override, sealed, r#extern, partial, required,
135    server, client, shared, saved, synced, tune,
136    // Built-in types.
137    void, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, decimal, bool, char, string, object,
138    dynamic,
139    // Statements.
140    r#let, r#mut, r#if, r#else, foreach, r#for, r#while, r#do, r#break, r#continue, goto, r#return, skip, r#yield, lock, r#unsafe, case, checked, unchecked,
141    // Expressions.
142    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, with, and, or, not,
143    // Patches: items, points, selectors.
144    add, before, after, inside, replace, read, write, priority, uses, local,
145    around, at, call, constant, first, last,
146    // Queries.
147    from, select, group, by, orderby, ascending, descending, into, join, on, equals,
148}