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#[derive(Clone)]
70pub struct ValkyrieBuilder<'config> {
71 config: &'config ValkyrieLanguage,
73}
74
75impl<'config> ValkyrieBuilder<'config> {
76 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 mut parse_cache = oak_core::parser::ParseSession::<ValkyrieLanguage>::default();
89 let parse_result = parser.parse(source, edits, &mut parse_cache);
90
91 match parse_result.result {
93 Ok(green_tree) => {
94 let source_text = SourceText::new(source.get_text_in((0..source.length()).into()).into_owned());
96 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 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 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(); }
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 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(); }
335 }
336
337 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 if let Some(RedTree::Leaf(t)) = children_iter.peek() {
350 if t.kind == ValkyrieSyntaxKind::Eq {
351 children_iter.next(); 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 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 }
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 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 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 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 receiver = Some(self.build_expr(n, source)?);
512 }
513 }
514 RedTree::Leaf(t) => {
515 if idx == 2 && t.kind == ValkyrieSyntaxKind::Identifier {
516 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 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 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}