Skip to main content

oak_valkyrie/builder/
mod.rs

1#[doc = include_str!("readme.md")]
2use crate::{
3    ValkyrieLanguage, ValkyrieParser,
4    ast::{ValkyrieRoot, *},
5    kind::ValkyrieSyntaxKind,
6    lexer::ValkyrieKeywords,
7};
8use core::range::Range;
9use oak_core::{
10    Builder, GreenNode, OakDiagnostics, OakError, Parser, RedNode, RedTree, SourceText,
11    builder::{BuildOutput, BuilderCache},
12    source::{Source, TextEdit},
13};
14
15/// A builder for the Valkyrie programming language.
16///
17/// The `ValkyrieParser` is responsible for parsing Valkyrie source code and building an Abstract Syntax Tree (AST).
18/// It uses a Pratt parser for handling operator precedence in expressions and supports all Valkyrie syntax features.
19///
20/// # Examples
21///
22/// Basic usage:
23///
24/// ```
25/// use oak_core::{Parser, parser::ParseSession, source::SourceText};
26/// use oak_valkyrie::{ValkyrieLanguage, ValkyrieParser};
27///
28/// let language = ValkyrieLanguage::default();
29/// let parser = ValkyrieParser::new(language);
30/// let source = SourceText::new("namespace Main { micro main() { let x = 42; } }");
31/// let mut cache = ParseSession::default();
32/// let result = parser.parse(&source, &[], &mut cache);
33///
34/// // The result contains the parsed AST
35/// assert!(result.result.is_ok());
36/// ```
37///
38/// Parsing a more complex Valkyrie structure:
39///
40/// ```
41/// use oak_core::{Parser, parser::ParseSession, source::SourceText};
42/// use oak_valkyrie::{ValkyrieLanguage, ValkyrieParser};
43///
44/// let language = ValkyrieLanguage::default();
45/// let parser = ValkyrieParser::new(language);
46/// let mut cache = ParseSession::default();
47///
48/// let source = SourceText::new(
49///     r#"
50/// namespace Math {
51///     micro add(x: i32, y: i32) -> i32 {
52///         x + y
53///     }
54///
55///     class Calculator {
56///         micro multiply(a: f64, b: f64) -> f64 {
57///             a * b
58///         }
59///     }
60/// }
61/// "#,
62/// );
63/// let result = parser.parse(&source, &[], &mut cache);
64///
65/// // Verify that parsing succeeded
66/// assert!(result.result.is_ok());
67/// ```
68/// A builder for the Valkyrie programming language.
69#[derive(Clone)]
70pub struct ValkyrieBuilder<'config> {
71    /// Language configuration
72    config: &'config ValkyrieLanguage,
73}
74
75impl<'config> ValkyrieBuilder<'config> {
76    /// Creates a new Valkyrie builder.
77    pub fn new(config: &'config ValkyrieLanguage) -> Self {
78        Self { config }
79    }
80}
81
82impl<'config> Builder<ValkyrieLanguage> for ValkyrieBuilder<'config> {
83    fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<ValkyrieLanguage>) -> BuildOutput<ValkyrieLanguage> {
84        let parser = ValkyrieParser::new(self.config);
85        // let lexer = ValkyrieLexer::new(&self.config);
86
87        // 使用解析器获取绿树
88        let mut parse_cache = oak_core::parser::ParseSession::<ValkyrieLanguage>::default();
89        let parse_result = parser.parse(source, edits, &mut parse_cache);
90
91        // 检查解析是否成功
92        match parse_result.result {
93            Ok(green_tree) => {
94                // 提前构造 SourceText 引用以便后续 AST 构建
95                let source_text = SourceText::new(source.get_text_in((0..source.length()).into()).into_owned());
96                // 构建 AST
97                match parser.build_root(green_tree, &source_text) {
98                    Ok(ast_root) => OakDiagnostics { result: Ok(ast_root), diagnostics: parse_result.diagnostics },
99                    Err(build_error) => {
100                        let mut diagnostics = parse_result.diagnostics;
101                        diagnostics.push(build_error);
102                        OakDiagnostics { result: Err(OakError::custom_error("Failed to build AST")), diagnostics }
103                    }
104                }
105            }
106            Err(parse_error) => OakDiagnostics { result: Err(parse_error), diagnostics: parse_result.diagnostics },
107        }
108    }
109}
110
111impl<'config> ValkyrieParser<'config> {
112    pub fn build_root(&self, green_tree: &GreenNode<ValkyrieLanguage>, source: &SourceText) -> Result<ValkyrieRoot, OakError> {
113        let red_root = RedNode::<ValkyrieLanguage>::new(green_tree, 0);
114        let mut items = Vec::new();
115        for child in red_root.children() {
116            match child {
117                RedTree::Node(n) => match n.green.kind {
118                    ValkyrieSyntaxKind::Namespace => {
119                        let ns = self.build_namespace(n, source)?;
120                        items.push(Item::Namespace(ns));
121                    }
122                    ValkyrieSyntaxKind::Micro => {
123                        let micro = self.build_micro(n, source)?;
124                        items.push(Item::Micro(micro));
125                    }
126                    ValkyrieSyntaxKind::LetStatement => {
127                        let stmt = self.build_let(n, source)?;
128                        items.push(Item::Statement(stmt));
129                    }
130                    ValkyrieSyntaxKind::ExpressionStatement => {
131                        let stmt = self.build_expr_stmt(n, source)?;
132                        items.push(Item::Statement(stmt));
133                    }
134                    _ => {
135                        return Err(source.syntax_error("Unexpected item in root".to_string(), n.span().start));
136                    }
137                },
138                RedTree::Leaf(t) => {
139                    return Err(source.syntax_error("Unexpected token in root".to_string(), t.span.start));
140                }
141            }
142        }
143        Ok(ValkyrieRoot { items })
144    }
145
146    /// 从红绿树提取强类型 AST
147
148    pub(crate) fn build_namespace(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Namespace, OakError> {
149        let span = node.span();
150        let mut name = Identifier { name: String::new(), span: Default::default() };
151        let mut items = Vec::new();
152
153        for child in node.children() {
154            match child {
155                RedTree::Leaf(t) => {
156                    if t.kind == ValkyrieSyntaxKind::Identifier {
157                        name.name = text(source, t.span.clone().into());
158                        name.span = t.span.clone();
159                    }
160                }
161                RedTree::Node(n) => match n.green.kind {
162                    ValkyrieSyntaxKind::Namespace => {
163                        let ns = self.build_namespace(n, source)?;
164                        items.push(Item::Namespace(ns));
165                    }
166                    ValkyrieSyntaxKind::Micro => {
167                        let micro = self.build_micro(n, source)?;
168                        items.push(Item::Micro(micro));
169                    }
170                    ValkyrieSyntaxKind::LetStatement => {
171                        let stmt = self.build_let(n, source)?;
172                        items.push(Item::Statement(stmt));
173                    }
174                    ValkyrieSyntaxKind::ExpressionStatement => {
175                        let stmt = self.build_expr_stmt(n, source)?;
176                        items.push(Item::Statement(stmt));
177                    }
178                    _ => {
179                        return Err(source.syntax_error("Unexpected item in namespace".to_string(), n.span().start));
180                    }
181                },
182            }
183        }
184        Ok(Namespace { name, items, span })
185    }
186
187    pub(crate) fn build_micro(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<MicroDefinition, OakError> {
188        let span = node.span();
189        let mut name = Identifier { name: String::new(), span: Default::default() };
190        let mut params = Vec::new();
191        let mut return_type = None;
192        let mut body = None;
193
194        for child in node.children() {
195            match child {
196                RedTree::Leaf(t) => {
197                    if t.kind == ValkyrieSyntaxKind::Identifier {
198                        name.name = text(source, t.span.clone().into());
199                        name.span = t.span.clone();
200                    }
201                }
202                RedTree::Node(n) => match n.green.kind {
203                    ValkyrieSyntaxKind::ParameterList => {
204                        params = self.build_params(n, source)?;
205                    }
206                    ValkyrieSyntaxKind::Type => {
207                        return_type = Some(text(source, n.span().into()));
208                    }
209                    ValkyrieSyntaxKind::BlockExpression => {
210                        body = Some(self.build_block(n, source)?);
211                    }
212                    _ => {
213                        return Err(source.syntax_error("Unexpected item in micro definition".to_string(), n.span().start));
214                    }
215                },
216            }
217        }
218
219        let body = body.ok_or_else(|| source.syntax_error(format!("Missing micro body at {:?}", span), span.start))?;
220
221        Ok(MicroDefinition { name, params, return_type, body, span })
222    }
223
224    fn build_params(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Vec<Param>, OakError> {
225        let mut params = Vec::new();
226        for child in node.children() {
227            if let RedTree::Node(n) = child {
228                if n.green.kind == ValkyrieSyntaxKind::Parameter {
229                    params.push(self.build_param(n, source)?);
230                }
231            }
232        }
233        Ok(params)
234    }
235
236    fn build_param(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Param, OakError> {
237        let span = node.span();
238        let mut name: Option<Identifier> = None;
239        let mut ty = None;
240        // children: IDENT ':' IDENT
241        for child in node.children() {
242            match child {
243                RedTree::Leaf(t) => {
244                    if t.kind == ValkyrieSyntaxKind::Identifier {
245                        if name.is_none() {
246                            name = Some(Identifier { name: text(source, t.span.clone().into()), span: t.span.clone() });
247                        }
248                        else {
249                            ty = Some(text(source, t.span.clone().into()));
250                        }
251                    }
252                    else if t.kind != ValkyrieSyntaxKind::Colon {
253                        return Err(source.syntax_error("Unexpected token in parameter definition", t.span.start));
254                    }
255                }
256                _ => {
257                    return Err(source.syntax_error("Unexpected token in parameter definition", child.span().start));
258                }
259            }
260        }
261        return if let (Some(name), Some(ty)) = (name, ty) { Ok(Param { name, ty, span }) } else { Err(source.syntax_error(format!("Missing name or type in parameter at {:?}", span), span.start)) };
262    }
263
264    fn build_block(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Block, OakError> {
265        let span = node.span();
266        let mut statements = Vec::new();
267        for child in node.children() {
268            match child {
269                RedTree::Node(n) => match n.green.kind {
270                    ValkyrieSyntaxKind::LetStatement => statements.push(self.build_let(n, source)?),
271                    ValkyrieSyntaxKind::ExpressionStatement => statements.push(self.build_expr_stmt(n, source)?),
272                    _ => {
273                        return Err(source.syntax_error("Unexpected statement in block", n.span().start));
274                    }
275                },
276                RedTree::Leaf(t) => {
277                    if t.kind != ValkyrieSyntaxKind::LeftBrace 
278                        && t.kind != ValkyrieSyntaxKind::RightBrace 
279                        && t.kind != ValkyrieSyntaxKind::Comma {
280                        return Err(source.syntax_error("Unexpected token in block", t.span.start));
281                    }
282                }
283            }
284        }
285        Ok(Block { statements, span })
286    }
287
288    fn build_expr_stmt(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Statement, OakError> {
289        let span = node.span();
290        let mut children_iter = node.children().peekable();
291
292        let expr_node = children_iter.next().ok_or_else(|| source.syntax_error("Missing expression in expression statement", span.start))?;
293
294        let expr = match expr_node {
295            RedTree::Node(n) => self.build_expr(n, source)?,
296            RedTree::Leaf(t) => {
297                return Err(source.syntax_error("Expected an expression, found a token", t.span.start));
298            }
299        };
300
301        let mut semi = false;
302        if let Some(RedTree::Leaf(t)) = children_iter.peek() {
303            if t.kind == ValkyrieSyntaxKind::Semicolon {
304                semi = true;
305                children_iter.next(); // Consume the semicolon
306            }
307        }
308
309        if let Some(unexpected_child) = children_iter.next() {
310            return Err(source.syntax_error("Unexpected token or expression after semicolon", unexpected_child.span().start));
311        }
312
313        Ok(Statement::ExprStmt { expr, semi, span })
314    }
315
316    fn build_let(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Statement, OakError> {
317        let span = node.span();
318        let mut children_iter = node.children().peekable();
319
320        // Expect 'let' keyword
321        let let_keyword = children_iter.next().ok_or_else(|| source.syntax_error("Missing 'let' keyword", span.start))?;
322        match let_keyword {
323            RedTree::Leaf(t) if t.kind == ValkyrieSyntaxKind::Keyword(ValkyrieKeywords::Let) => {}
324            _ => {
325                return Err(source.syntax_error("Expected 'let' keyword", let_keyword.span().start));
326            }
327        }
328
329        let mut is_mutable = false;
330        if let Some(RedTree::Leaf(t)) = children_iter.peek() {
331            if t.kind == ValkyrieSyntaxKind::Keyword(ValkyrieKeywords::Mut) {
332                is_mutable = true;
333                children_iter.next(); // Consume 'mut' keyword
334            }
335        }
336
337        // Expect identifier
338        let name_node = children_iter.next().ok_or_else(|| source.syntax_error("Missing identifier in let statement", span.start))?;
339        let name = match name_node {
340            RedTree::Leaf(t) if t.kind == ValkyrieSyntaxKind::Identifier => Identifier { name: text(source, t.span.clone().into()), span: t.span.clone() },
341            _ => {
342                return Err(source.syntax_error("Expected identifier in let statement", name_node.span().start));
343            }
344        };
345
346        let mut expr: Option<Expr> = None;
347
348        // Check for optional '=' and expression
349        if let Some(RedTree::Leaf(t)) = children_iter.peek() {
350            if t.kind == ValkyrieSyntaxKind::Eq {
351                children_iter.next(); // Consume '=' token
352
353                let expr_node = children_iter.next().ok_or_else(|| source.syntax_error("Missing expression after '=' in let statement", span.end))?;
354
355                expr = Some(match expr_node {
356                    RedTree::Node(n) => self.build_expr(n, source)?,
357                    RedTree::Leaf(t) => {
358                        return Err(source.syntax_error("Expected an expression, found a token after '=' in let statement", t.span.start));
359                    }
360                });
361            }
362        }
363
364        if let Some(unexpected_child) = children_iter.next() {
365            match unexpected_child {
366                RedTree::Leaf(t) if t.kind == ValkyrieSyntaxKind::Semicolon => {}
367                _ => return Err(source.syntax_error("Unexpected token or expression in let statement", unexpected_child.span().start)),
368            }
369        }
370
371        let expr = expr.ok_or_else(|| source.syntax_error("Missing expression in let statement", span.start))?;
372
373        Ok(Statement::Let { is_mutable, name, expr, span })
374    }
375
376    pub(crate) fn build_expr(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Expr, OakError> {
377        let node_kind = node.green.kind;
378        let node_span = node.span();
379        let node_text = text(source, node_span.clone().into());
380        println!("Building expr: kind={:?}, span={:?}, text={:?}", node_kind, node_span, node_text);
381        match node_kind {
382            ValkyrieSyntaxKind::IdentifierExpression => {
383                let span = node.span();
384                // child: IDENT
385                for child in node.children() {
386                    match child {
387                        RedTree::Leaf(t) => {
388                            if t.kind == ValkyrieSyntaxKind::Identifier {
389                                return Ok(Expr::Ident(Identifier { name: text(source, t.span.clone().into()), span: t.span.clone() }));
390                            }
391                        }
392                        RedTree::Node(n) if n.green.kind == ValkyrieSyntaxKind::Error => {
393                            // If we have an error node here, it might be due to a mis-parsed token
394                        }
395                        _ => {}
396                    }
397                }
398                Err(source.syntax_error(format!("Missing identifier in identifier expression at {:?}", span), span.start))
399            }
400            ValkyrieSyntaxKind::LiteralExpression => {
401                let span = node.span();
402                for child in node.children() {
403                    if let RedTree::Leaf(t) = child {
404                        return Ok(Expr::Literal { value: text(source, t.span.into()), span });
405                    }
406                }
407                Err(source.syntax_error(format!("Missing literal in literal expression at {:?}", span), span.start))
408            }
409            ValkyrieSyntaxKind::BooleanLiteral => {
410                let span = node.span();
411                for child in node.children() {
412                    if let RedTree::Leaf(t) = child {
413                        return Ok(Expr::Bool { value: t.kind == ValkyrieSyntaxKind::Keyword(ValkyrieKeywords::True), span });
414                    }
415                }
416                Err(source.syntax_error(format!("Missing boolean literal in boolean literal expression at {:?}", span), span.start))
417            }
418            ValkyrieSyntaxKind::ParenthesizedExpression => {
419                let span = node.span();
420                for child in node.children() {
421                    if let RedTree::Node(n) = child {
422                        return Ok(Expr::Paren { expr: Box::new(self.build_expr(n, source)?), span });
423                    }
424                }
425                Err(source.syntax_error(format!("Missing expression in parenthesized expression at {:?}", span), span.start))
426            }
427            ValkyrieSyntaxKind::UnaryExpression => {
428                let span = node.span();
429                // children: operator expression
430                let mut op: Option<ValkyrieSyntaxKind> = None;
431                let mut expr: Option<Expr> = None;
432                for child in node.children() {
433                    match child {
434                        RedTree::Node(n) => {
435                            expr = Some(self.build_expr(n, source)?);
436                        }
437                        RedTree::Leaf(t) => {
438                            if let oak_core::UniversalTokenRole::Operator = t.kind.into() {
439                                op = Some(t.kind);
440                            }
441                        }
442                    }
443                }
444                if let (Some(op_kind), Some(expr_val)) = (op, expr) { Ok(Expr::Unary { op: op_kind, expr: Box::new(expr_val), span }) } else { Err(source.syntax_error(format!("Missing operand in unary expression at {:?}", span), span.start)) }
445            }
446            ValkyrieSyntaxKind::BinaryExpression => {
447                let span = node.span();
448                // children: left operator right
449                let mut left: Option<Expr> = None;
450                let mut op: Option<ValkyrieSyntaxKind> = None;
451                let mut right: Option<Expr> = None;
452                for child in node.children() {
453                    match child {
454                        RedTree::Node(n) => {
455                            if left.is_none() {
456                                left = Some(self.build_expr(n, source)?);
457                            }
458                            else {
459                                right = Some(self.build_expr(n, source)?);
460                            }
461                        }
462                        RedTree::Leaf(t) => {
463                            if let oak_core::UniversalTokenRole::Operator = t.kind.into() {
464                                op = Some(t.kind);
465                            }
466                        }
467                    }
468                }
469                if let (Some(left_expr), Some(op_kind), Some(right_expr)) = (left, op, right) {
470                    Ok(Expr::Binary { left: Box::new(left_expr), op: op_kind, right: Box::new(right_expr), span })
471                }
472                else {
473                    Err(source.syntax_error(format!("Missing operands in binary expression at {:?}", span), span.start))
474                }
475            }
476            ValkyrieSyntaxKind::CallExpression => {
477                let span = node.span();
478                // children: callee '(' args... ')' with commas
479                let mut callee: Option<Expr> = None;
480                let mut args: Vec<Expr> = Vec::new();
481                let mut seen_paren = false;
482                for child in node.children() {
483                    match child {
484                        RedTree::Node(n) => {
485                            if !seen_paren && callee.is_none() {
486                                callee = Some(self.build_expr(n, source)?);
487                            }
488                            else {
489                                args.push(self.build_expr(n, source)?);
490                            }
491                        }
492                        RedTree::Leaf(t) => {
493                            if t.kind == ValkyrieSyntaxKind::LeftParen {
494                                seen_paren = true;
495                            }
496                        }
497                    }
498                }
499                if let Some(callee_expr) = callee { Ok(Expr::Call { callee: Box::new(callee_expr), args, span }) } else { Err(source.syntax_error(format!("Missing callee in call expression at {:?}", span), span.start)) }
500            }
501            ValkyrieSyntaxKind::FieldExpression => {
502                let span = node.span();
503                let mut receiver: Option<Expr> = None;
504                let mut field: Option<Identifier> = None;
505                let mut idx = 0;
506                for child in node.children() {
507                    match child {
508                        RedTree::Node(n) => {
509                            if idx == 0 {
510                                // The first node is the receiver
511                                receiver = Some(self.build_expr(n, source)?);
512                            }
513                        }
514                        RedTree::Leaf(t) => {
515                            if idx == 2 && t.kind == ValkyrieSyntaxKind::Identifier {
516                                // The third child (leaf) is the identifier
517                                field = Some(Identifier { name: text(source, t.span.clone().into()), span: t.span.clone() });
518                            }
519                        }
520                    }
521                    idx += 1;
522                }
523                if let (Some(receiver_val), Some(field_val)) = (receiver, field) {
524                    Ok(Expr::Field { receiver: Box::new(receiver_val), field: field_val, span })
525                }
526                else {
527                    Err(source.syntax_error(format!("Missing receiver or field in field expression at {:?}", span), span.start))
528                }
529            }
530            ValkyrieSyntaxKind::IndexExpression => {
531                let span = node.span();
532                // children: base '[' index ']'
533                let mut base: Option<Expr> = None;
534                let mut index: Option<Expr> = None;
535                let mut idx = 0;
536                for child in node.children() {
537                    match child {
538                        RedTree::Node(n) => {
539                            if idx == 0 {
540                                base = Some(self.build_expr(n, source)?);
541                            }
542                            else {
543                                index = Some(self.build_expr(n, source)?);
544                            }
545                        }
546                        _ => {}
547                    }
548                    idx += 1;
549                }
550                if let (Some(base_expr), Some(index_expr)) = (base, index) {
551                    Ok(Expr::Index { receiver: Box::new(base_expr), index: Box::new(index_expr), span })
552                }
553                else {
554                    Err(source.syntax_error(format!("Missing base or index in index expression at {:?}", span), span.start))
555                }
556            }
557            ValkyrieSyntaxKind::IfExpression => self.build_if(node, source),
558            ValkyrieSyntaxKind::MatchExpression => self.build_match(node, source),
559            ValkyrieSyntaxKind::LoopExpression => self.build_loop(node, source),
560            ValkyrieSyntaxKind::ReturnExpression => self.build_return(node, source),
561            ValkyrieSyntaxKind::ApplyBlock | ValkyrieSyntaxKind::ObjectExpression => {
562                let span = node.span();
563                let mut callee = None;
564                let mut block = None;
565                for child in node.children() {
566                    match child {
567                        RedTree::Node(n) => match n.green.kind {
568                            ValkyrieSyntaxKind::BlockExpression => {
569                                block = Some(self.build_block(n, source)?);
570                            }
571                            _ => {
572                                if callee.is_none() {
573                                    callee = Some(self.build_expr(n, source)?);
574                                }
575                            }
576                        },
577                        RedTree::Leaf(_) => {}
578                    }
579                }
580                let callee = callee.ok_or_else(|| source.syntax_error("Missing callee in apply block", span.start))?;
581                let block = block.ok_or_else(|| source.syntax_error("Missing block in apply block", span.end))?;
582                Ok(Expr::Object { callee: Box::new(callee), block, span })
583            }
584            ValkyrieSyntaxKind::BlockExpression => {
585                let block = self.build_block(node, source)?;
586                Ok(Expr::Block(block))
587            }
588            ValkyrieSyntaxKind::BreakExpression => self.build_break(node, source),
589            ValkyrieSyntaxKind::ContinueExpression => self.build_continue(node, source),
590            ValkyrieSyntaxKind::YieldExpression => self.build_yield(node, source),
591            ValkyrieSyntaxKind::RaiseExpression => self.build_raise(node, source),
592            ValkyrieSyntaxKind::CatchExpression => self.build_catch(node, source),
593            ValkyrieSyntaxKind::Error => Err(source.syntax_error(format!("Syntax error at {:?}", node.span()), node.span().start)),
594            _ => Err(source.syntax_error(format!("Unknown expression type {:?} at {:?}", node.green.kind, node.span()), node.span().start)),
595        }
596    }
597
598    fn build_if(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Expr, OakError> {
599        let span = node.span();
600        let mut condition = None;
601        let mut then_branch = None;
602        let mut else_branch = None;
603        let mut is_else = false;
604
605        for child in node.children() {
606            match child {
607                RedTree::Node(n) => match n.green.kind {
608                    ValkyrieSyntaxKind::BlockExpression => {
609                        if is_else {
610                            else_branch = Some(self.build_block(n, source)?);
611                        }
612                        else {
613                            then_branch = Some(self.build_block(n, source)?);
614                        }
615                    }
616                    ValkyrieSyntaxKind::IfExpression => {
617                        // else if
618                        if is_else {
619                            let nested_if = self.build_if(n, source)?;
620                            let n_span = n.span();
621                            else_branch = Some(Block { statements: vec![Statement::ExprStmt { expr: nested_if, semi: false, span: n_span.clone() }], span: n_span });
622                        }
623                    }
624                    _ => {
625                        if condition.is_none() {
626                            condition = Some(Box::new(self.build_expr(n, source)?));
627                        }
628                    }
629                },
630                RedTree::Leaf(t) => {
631                    if t.kind == ValkyrieSyntaxKind::Keyword(ValkyrieKeywords::Else) {
632                        is_else = true;
633                    }
634                }
635            }
636        }
637
638        Ok(Expr::If {
639            condition: condition.ok_or_else(|| source.syntax_error("Missing if condition".to_string(), span.start))?,
640            then_branch: then_branch.ok_or_else(|| source.syntax_error("Missing if then branch".to_string(), span.start))?,
641            else_branch,
642            span,
643        })
644    }
645
646    fn build_match(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Expr, OakError> {
647        let span = node.span();
648        let mut scrutinee = None;
649        let mut arms = Vec::new();
650
651        for child in node.children() {
652            match child {
653                RedTree::Node(n) => match n.green.kind {
654                    ValkyrieSyntaxKind::MatchArm => {
655                        arms.push(self.build_match_arm(n, source)?);
656                    }
657                    _ => {
658                        if scrutinee.is_none() {
659                            scrutinee = Some(Box::new(self.build_expr(n, source)?));
660                        }
661                    }
662                },
663                _ => {}
664            }
665        }
666
667        Ok(Expr::Match { scrutinee: scrutinee.ok_or_else(|| source.syntax_error("Missing match scrutinee".to_string(), span.start))?, arms, span })
668    }
669
670    fn build_match_arm(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<MatchArm, OakError> {
671        let span = node.span();
672        let mut pattern = None;
673        let mut guard = None;
674        let mut body = None;
675        let mut is_guard = false;
676
677        for child in node.children() {
678            match child {
679                RedTree::Node(n) => {
680                    if pattern.is_none() {
681                        pattern = Some(self.build_pattern(n, source)?);
682                    }
683                    else if is_guard && guard.is_none() {
684                        guard = Some(self.build_expr(n, source)?);
685                    }
686                    else {
687                        body = Some(self.build_expr(n, source)?);
688                    }
689                }
690                RedTree::Leaf(t) => {
691                    if t.kind == ValkyrieSyntaxKind::Keyword(ValkyrieKeywords::When) {
692                        is_guard = true;
693                    }
694                }
695            }
696        }
697
698        Ok(MatchArm { pattern: pattern.ok_or_else(|| source.syntax_error("Missing match arm pattern".to_string(), span.start))?, guard, body: body.ok_or_else(|| source.syntax_error("Missing match arm body".to_string(), span.start))?, span })
699    }
700
701    fn build_pattern(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Pattern, OakError> {
702        let span = node.span();
703        for child in node.children() {
704            if let RedTree::Leaf(t) = child {
705                match t.kind {
706                    ValkyrieSyntaxKind::Identifier => {
707                        return Ok(Pattern::Variable { name: Identifier { name: text(source, t.span.clone().into()), span: t.span.clone() }, span });
708                    }
709                    ValkyrieSyntaxKind::IntegerLiteral | ValkyrieSyntaxKind::StringLiteral => {
710                        return Ok(Pattern::Literal { value: text(source, t.span.clone().into()), span });
711                    }
712                    _ => {}
713                }
714            }
715        }
716        Ok(Pattern::Wildcard { span })
717    }
718
719    fn build_loop(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Expr, OakError> {
720        let span = node.span();
721        let mut body = None;
722        for child in node.children() {
723            if let RedTree::Node(n) = child {
724                if n.green.kind == ValkyrieSyntaxKind::BlockExpression {
725                    body = Some(self.build_block(n, source)?);
726                }
727            }
728        }
729        Ok(Expr::Loop { label: None, body: body.ok_or_else(|| source.syntax_error("Missing loop body".to_string(), span.start))?, span })
730    }
731
732    fn build_return(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Expr, OakError> {
733        let span = node.span();
734        let mut expr = None;
735        for child in node.children() {
736            if let RedTree::Node(n) = child {
737                expr = Some(Box::new(self.build_expr(n, source)?));
738            }
739        }
740        Ok(Expr::Return { expr, span })
741    }
742
743    fn build_break(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Expr, OakError> {
744        let span = node.span();
745        let mut label = None;
746        let mut expr = None;
747        for child in node.children() {
748            match child {
749                RedTree::Leaf(t) if t.kind == ValkyrieSyntaxKind::Identifier => {
750                    label = Some(text(source, t.span.into()));
751                }
752                RedTree::Node(n) => {
753                    expr = Some(Box::new(self.build_expr(n, source)?));
754                }
755                _ => {}
756            }
757        }
758        Ok(Expr::Break { label, expr, span })
759    }
760
761    fn build_continue(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Expr, OakError> {
762        let span = node.span();
763        let mut label = None;
764        for child in node.children() {
765            if let RedTree::Leaf(t) = child {
766                if t.kind == ValkyrieSyntaxKind::Identifier {
767                    label = Some(text(source, t.span.into()));
768                }
769            }
770        }
771        Ok(Expr::Continue { label, span })
772    }
773
774    fn build_yield(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Expr, OakError> {
775        let span = node.span();
776        let mut expr = None;
777        let mut yield_from = false;
778        for child in node.children() {
779            match child {
780                RedTree::Leaf(t) if t.kind == ValkyrieSyntaxKind::Star => {
781                    yield_from = true;
782                }
783                RedTree::Node(n) => {
784                    expr = Some(Box::new(self.build_expr(n, source)?));
785                }
786                _ => {}
787            }
788        }
789        Ok(Expr::Yield { expr, yield_from, span })
790    }
791
792    fn build_raise(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Expr, OakError> {
793        let span = node.span();
794        let mut expr = None;
795        for child in node.children() {
796            if let RedTree::Node(n) = child {
797                expr = Some(Box::new(self.build_expr(n, source)?));
798            }
799        }
800        Ok(Expr::Raise { expr: expr.ok_or_else(|| source.syntax_error("Missing raise expression".to_string(), span.start))?, span })
801    }
802
803    fn build_catch(&self, node: RedNode<ValkyrieLanguage>, source: &SourceText) -> Result<Expr, OakError> {
804        let span = node.span();
805        let mut expr = None;
806        let mut arms = Vec::new();
807        for child in node.children() {
808            if let RedTree::Node(n) = child {
809                match n.green.kind {
810                    ValkyrieSyntaxKind::MatchArm => {
811                        arms.push(self.build_match_arm(n, source)?);
812                    }
813                    _ => {
814                        if expr.is_none() {
815                            expr = Some(Box::new(self.build_expr(n, source)?));
816                        }
817                    }
818                }
819            }
820        }
821        Ok(Expr::Catch { expr: expr.ok_or_else(|| source.syntax_error("Missing catch expression".to_string(), span.start))?, arms, span })
822    }
823}
824
825#[inline]
826fn text(source: &SourceText, span: Range<usize>) -> String {
827    source.get_text_in(span.into()).to_string()
828}