use crate::{
ValkyrieLanguage,
ast::{Class, EnumVariant, Enums, EnumsKind, Field, Flags, Identifier, Item, Parent, Singleton, StructureKind, Trait, Variant, VariantCase, Widget},
builder::{ValkyrieBuilder, text},
lexer::{ValkyrieKeywords, token_type::ValkyrieTokenType},
parser::element_type::ValkyrieElementType,
};
use oak_core::{OakError, RedNode, RedTree, Source};
impl<'config> ValkyrieBuilder<'config> {
pub(crate) fn build_class<S: Source + ?Sized>(&self, node: RedNode<ValkyrieLanguage>, source: &S) -> Result<Class, OakError> {
let span = node.span();
let mut kind = StructureKind::default();
let mut name = Identifier { name: String::new(), span: Default::default() };
let mut generics = Vec::new();
let mut annotations = Vec::new();
let mut parents = Vec::new();
let mut items = Vec::new();
let mut is_abstract = false;
let mut is_sealed = false;
let mut is_final = false;
for child in node.children() {
match child {
RedTree::Leaf(t) => match t.kind {
ValkyrieTokenType::Whitespace | ValkyrieTokenType::Newline | ValkyrieTokenType::LineComment | ValkyrieTokenType::BlockComment => continue,
ValkyrieTokenType::Identifier => {
let t_text = text(source, t.span);
name = Identifier { name: t_text, span: t.span };
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Class) => {
kind = StructureKind::Class;
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Abstract) => {
is_abstract = true;
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Sealed) => {
is_sealed = true;
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Final) => {
is_final = true;
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Struct) => {
kind = StructureKind::Struct;
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Structure) => {
kind = StructureKind::Structure;
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Widget) => {
kind = StructureKind::Widget;
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Trait) => {
kind = StructureKind::Trait;
}
_ => {}
},
RedTree::Node(n) => match n.green.kind {
ValkyrieElementType::Attribute => {
annotations.push(self.build_attribute(n, source)?);
}
ValkyrieElementType::GenericParameterList => {
generics = self.build_generic_params(n, source)?;
}
ValkyrieElementType::NamePath => {
let parent = Parent { alias: None, name: self.build_name_path(n, source)?, span: n.span() };
parents.push(parent);
}
ValkyrieElementType::Type => {
for child in n.children() {
if let RedTree::Node(inner) = child {
if inner.green.kind == ValkyrieElementType::NamePath {
let parent = Parent { alias: None, name: self.build_name_path(inner, source)?, span: inner.span() };
parents.push(parent);
}
}
}
}
ValkyrieElementType::Namespace => {
let ns = self.build_namespace(n, source)?;
items.push(Item::Namespace(ns));
}
ValkyrieElementType::Class => {
let class = self.build_class(n, source)?;
items.push(Item::Class(class));
}
ValkyrieElementType::Flags => {
let flags = self.build_flags(n, source)?;
items.push(Item::Flags(flags));
}
ValkyrieElementType::Enums => {
let enums = self.build_enums(n, source)?;
items.push(Item::Enums(enums));
}
ValkyrieElementType::Trait => {
let trait_node = self.build_trait(n, source)?;
items.push(Item::Trait(trait_node));
}
ValkyrieElementType::Widget => {
let widget = self.build_widget(n, source)?;
items.push(Item::Widget(widget));
}
ValkyrieElementType::UsingStatement => {
let us = self.build_using(n, source)?;
items.push(Item::Using(us));
}
ValkyrieElementType::Micro => {
let micro = self.build_micro(n, source)?;
items.push(Item::Micro(micro));
}
ValkyrieElementType::LetStatement => {
let stmt = self.build_let(n, source)?;
items.push(Item::Statement(stmt));
}
ValkyrieElementType::ExprStatement => {
let stmt = self.build_expr_stmt(n, source)?;
items.push(Item::Statement(stmt));
}
ValkyrieElementType::Variant => {
let variant = self.build_variant_decl(n, source)?;
items.push(Item::Variant(variant));
}
ValkyrieElementType::BlockExpression => {
for inner_child in n.children() {
if let RedTree::Node(inner_n) = inner_child {
if let Ok(item) = self.build_item(inner_n, source) {
items.push(item);
}
}
}
}
_ => {}
},
}
}
Ok(Class { kind, name, generics, annotations, parents, items, span, is_abstract, is_sealed, is_final })
}
pub(crate) fn build_flags<S: Source + ?Sized>(&self, node: RedNode<ValkyrieLanguage>, source: &S) -> Result<Flags, OakError> {
let span = node.span();
let mut name = Identifier { name: String::new(), span: Default::default() };
let mut annotations = Vec::new();
let mut variants = Vec::new();
for child in node.children() {
match child {
RedTree::Leaf(t) => match t.kind {
ValkyrieTokenType::Whitespace | ValkyrieTokenType::Newline | ValkyrieTokenType::LineComment | ValkyrieTokenType::BlockComment => continue,
ValkyrieTokenType::Identifier => {
let t_text = text(source, t.span);
name = Identifier { name: t_text, span: t.span };
}
_ => {}
},
RedTree::Node(n) => match n.green.kind {
ValkyrieElementType::Attribute => annotations.push(self.build_attribute(n, source)?),
ValkyrieElementType::Variant => {
let variant = self.build_enum_variant(n, source)?;
variants.push(variant);
}
ValkyrieElementType::BlockExpression => {
for inner_child in n.children() {
if let RedTree::Node(inner_n) = inner_child {
if inner_n.green.kind == ValkyrieElementType::Variant {
if let Ok(v) = self.build_enum_variant(inner_n, source) {
variants.push(v);
}
}
}
}
}
_ => {}
},
}
}
Ok(Flags { name, variants, annotations, span })
}
pub(crate) fn build_enums<S: Source + ?Sized>(&self, node: RedNode<ValkyrieLanguage>, source: &S) -> Result<Enums, OakError> {
let span = node.span();
let mut kind = EnumsKind::default();
let mut name = Identifier { name: String::new(), span: Default::default() };
let mut generics = Vec::new();
let mut annotations = Vec::new();
let mut variants = Vec::new();
for child in node.children() {
match child {
RedTree::Leaf(t) => match t.kind {
ValkyrieTokenType::Whitespace | ValkyrieTokenType::Newline | ValkyrieTokenType::LineComment | ValkyrieTokenType::BlockComment => continue,
ValkyrieTokenType::Identifier => {
let t_text = text(source, t.span);
name = Identifier { name: t_text, span: t.span }
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Enums) => {
kind = EnumsKind::Enums;
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Enum) => {
kind = EnumsKind::Enum;
}
ValkyrieTokenType::Keyword(ValkyrieKeywords::Unity) => {
kind = EnumsKind::Unity;
}
_ => {}
},
RedTree::Node(n) => match n.green.kind {
ValkyrieElementType::Attribute => annotations.push(self.build_attribute(n, source)?),
ValkyrieElementType::GenericParameterList => {
generics = self.build_generic_params(n, source)?;
}
ValkyrieElementType::Variant => {
let variant = self.build_enum_variant(n, source)?;
variants.push(variant)
}
ValkyrieElementType::BlockExpression => {
for inner_child in n.children() {
if let RedTree::Node(inner_n) = inner_child {
if inner_n.green.kind == ValkyrieElementType::Variant {
if let Ok(v) = self.build_enum_variant(inner_n, source) {
variants.push(v)
}
}
}
}
}
_ => {}
},
}
}
Ok(Enums { kind, name, generics, variants, annotations, span })
}
pub(crate) fn build_enum_variant<S: Source + ?Sized>(&self, node: RedNode<ValkyrieLanguage>, source: &S) -> Result<EnumVariant, OakError> {
let span = node.span();
let mut name = Identifier { name: String::new(), span: Default::default() };
let mut fields = Vec::new();
let mut annotations = Vec::new();
let mut value = None;
for child in node.children() {
match child {
RedTree::Leaf(t) => match t.kind {
ValkyrieTokenType::Whitespace | ValkyrieTokenType::Newline | ValkyrieTokenType::LineComment | ValkyrieTokenType::BlockComment => continue,
ValkyrieTokenType::Identifier => {
let t_text = text(source, t.span);
name = Identifier { name: t_text, span: t.span };
}
_ => {}
},
RedTree::Node(n) => match n.green.kind {
ValkyrieElementType::Attribute => annotations.push(self.build_attribute(n, source)?),
ValkyrieElementType::Field => {
if let Ok(field) = self.build_field(n, source) {
fields.push(field);
}
}
_ => {
if value.is_none() {
if let Ok(expr) = self.build_expr(n, source) {
value = Some(expr);
}
}
}
},
}
}
Ok(EnumVariant { name, fields, annotations, span, value })
}
pub(crate) fn build_field<S: Source + ?Sized>(&self, node: RedNode<ValkyrieLanguage>, source: &S) -> Result<Field, OakError> {
let span = node.span();
let mut name = Identifier { name: String::new(), span: Default::default() };
let mut ty = None;
let mut default = None;
let mut annotations = Vec::new();
for child in node.children() {
match child {
RedTree::Leaf(t) => match t.kind {
ValkyrieTokenType::Whitespace | ValkyrieTokenType::Newline | ValkyrieTokenType::LineComment | ValkyrieTokenType::BlockComment => continue,
ValkyrieTokenType::Identifier => {
if name.name.is_empty() {
name = Identifier { name: text(source, t.span), span: t.span };
}
}
_ => {}
},
RedTree::Node(n) => match n.green.kind {
ValkyrieElementType::Attribute => annotations.push(self.build_attribute(n, source)?),
ValkyrieElementType::Type => ty = Some(self.build_type(n, source)?),
_ => {
if default.is_none() {
default = Some(self.build_expr(n, source)?);
}
}
},
}
}
let ty = ty.ok_or_else(|| source.syntax_error("Missing type for field".to_string(), span.start))?;
Ok(Field { name, ty, default, annotations, span })
}
pub(crate) fn build_variant_decl<S: Source + ?Sized>(&self, node: RedNode<ValkyrieLanguage>, source: &S) -> Result<Variant, OakError> {
let span = node.span();
let mut name = Identifier { name: String::new(), span: Default::default() };
let mut generics = Vec::new();
let mut annotations = Vec::new();
let mut cases = Vec::new();
for child in node.children() {
match child {
RedTree::Leaf(t) => match t.kind {
ValkyrieTokenType::Whitespace | ValkyrieTokenType::Newline | ValkyrieTokenType::LineComment | ValkyrieTokenType::BlockComment => continue,
ValkyrieTokenType::Identifier => {
let t_text = text(source, t.span);
name = Identifier { name: t_text, span: t.span };
}
_ => {}
},
RedTree::Node(n) => match n.green.kind {
ValkyrieElementType::Attribute => annotations.push(self.build_attribute(n, source)?),
ValkyrieElementType::GenericParameterList => {
generics = self.build_generic_params(n, source)?;
}
ValkyrieElementType::MatchArm => {
if let Ok(case) = self.build_variant_case(n, source) {
cases.push(case);
}
}
_ => {}
},
}
}
Ok(Variant { name, generics, cases, annotations, span })
}
pub(crate) fn build_variant_case<S: Source + ?Sized>(&self, node: RedNode<ValkyrieLanguage>, source: &S) -> Result<VariantCase, OakError> {
let span = node.span();
let mut pattern = None;
let mut body = None;
for child in node.children() {
match child {
RedTree::Leaf(t) => match t.kind {
ValkyrieTokenType::Whitespace | ValkyrieTokenType::Newline | ValkyrieTokenType::LineComment | ValkyrieTokenType::BlockComment => continue,
_ => {}
},
RedTree::Node(n) => match n.green.kind {
ValkyrieElementType::Whitespace | ValkyrieElementType::Newline | ValkyrieElementType::LineComment | ValkyrieElementType::BlockComment => continue,
ValkyrieElementType::Pattern => {
pattern = Some(self.build_pattern(n, source)?);
}
_ => {
if body.is_none() {
body = Some(self.build_expr(n, source)?);
}
}
},
}
}
let pattern = pattern.ok_or_else(|| source.syntax_error("Missing pattern in variant case".to_string(), span.start))?;
let body = body.ok_or_else(|| source.syntax_error("Missing body in variant case".to_string(), span.start))?;
Ok(VariantCase { pattern, body, span })
}
pub(crate) fn build_trait<S: Source + ?Sized>(&self, node: RedNode<ValkyrieLanguage>, source: &S) -> Result<Trait, OakError> {
let span = node.span();
let mut name = Identifier { name: String::new(), span: Default::default() };
let mut generics = Vec::new();
let mut annotations = Vec::new();
let mut methods = Vec::new();
let mut associated_types = Vec::new();
for child in node.children() {
match child {
RedTree::Leaf(t) => match t.kind {
ValkyrieTokenType::Whitespace | ValkyrieTokenType::Newline | ValkyrieTokenType::LineComment | ValkyrieTokenType::BlockComment => continue,
ValkyrieTokenType::Identifier => {
let t_text = text(source, t.span);
name = Identifier { name: t_text, span: t.span };
}
_ => {}
},
RedTree::Node(n) => match n.green.kind {
ValkyrieElementType::Attribute => annotations.push(self.build_attribute(n, source)?),
ValkyrieElementType::GenericParameterList => {
generics = self.build_generic_params(n, source)?;
}
ValkyrieElementType::NamePath => {}
ValkyrieElementType::Type => {}
ValkyrieElementType::Micro => {
if let Ok(func) = self.build_function(n, source) {
methods.push(func);
}
}
ValkyrieElementType::BlockExpression => {
for inner_child in n.children() {
if let RedTree::Node(inner_n) = inner_child {
if inner_n.green.kind == ValkyrieElementType::Micro {
if let Ok(func) = self.build_function(inner_n, source) {
methods.push(func);
}
}
}
}
}
_ => {}
},
}
}
Ok(Trait { name, generics, methods, associated_types, annotations, span })
}
pub(crate) fn build_widget<S: Source + ?Sized>(&self, node: RedNode<ValkyrieLanguage>, source: &S) -> Result<Widget, OakError> {
let span = node.span();
let mut name = Identifier { name: String::new(), span: Default::default() };
let mut generics = Vec::new();
let mut annotations = Vec::new();
let mut items = Vec::new();
for child in node.children() {
match child {
RedTree::Leaf(t) => match t.kind {
ValkyrieTokenType::Whitespace | ValkyrieTokenType::Newline | ValkyrieTokenType::LineComment | ValkyrieTokenType::BlockComment => continue,
ValkyrieTokenType::Identifier => {
name = Identifier { name: text(source, t.span), span: t.span };
}
_ => {}
},
RedTree::Node(n) => match n.green.kind {
ValkyrieElementType::Attribute => annotations.push(self.build_attribute(n, source)?),
ValkyrieElementType::GenericParameterList => {
generics = self.build_generic_params(n, source)?;
}
ValkyrieElementType::Namespace => {
let ns = self.build_namespace(n, source)?;
items.push(Item::Namespace(ns))
}
ValkyrieElementType::Class => {
let class = self.build_class(n, source)?;
items.push(Item::Class(class))
}
ValkyrieElementType::Flags => {
let flags = self.build_flags(n, source)?;
items.push(Item::Flags(flags))
}
ValkyrieElementType::Trait => {
let trait_node = self.build_trait(n, source)?;
items.push(Item::Trait(trait_node))
}
ValkyrieElementType::Widget => {
let widget = self.build_widget(n, source)?;
items.push(Item::Widget(widget))
}
ValkyrieElementType::UsingStatement => {
let us = self.build_using(n, source)?;
items.push(Item::Using(us))
}
ValkyrieElementType::Micro => {
let micro = self.build_micro(n, source)?;
items.push(Item::Micro(micro))
}
ValkyrieElementType::LetStatement => {
let stmt = self.build_let(n, source)?;
items.push(Item::Statement(stmt))
}
ValkyrieElementType::ExprStatement => {
let stmt = self.build_expr_stmt(n, source)?;
items.push(Item::Statement(stmt))
}
_ => {}
},
}
}
Ok(Widget { name, generics, items, annotations, span })
}
pub(crate) fn build_singleton<S: Source + ?Sized>(&self, node: RedNode<ValkyrieLanguage>, source: &S) -> Result<Singleton, OakError> {
let span = node.span();
let mut name = Identifier { name: String::new(), span: Default::default() };
let mut generics = Vec::new();
let mut parents = Vec::new();
let mut annotations = Vec::new();
let mut items = Vec::new();
for child in node.children() {
match child {
RedTree::Leaf(t) => match t.kind {
ValkyrieTokenType::Whitespace | ValkyrieTokenType::Newline | ValkyrieTokenType::LineComment | ValkyrieTokenType::BlockComment => continue,
ValkyrieTokenType::Identifier => {
name = Identifier { name: text(source, t.span), span: t.span };
}
_ => {}
},
RedTree::Node(n) => match n.green.kind {
ValkyrieElementType::Attribute => annotations.push(self.build_attribute(n, source)?),
ValkyrieElementType::GenericParameterList => {
generics = self.build_generic_params(n, source)?;
}
ValkyrieElementType::NamePath => {
let parent = Parent { alias: None, name: self.build_name_path(n, source)?, span: n.span() };
parents.push(parent);
}
ValkyrieElementType::Type => {
for child in n.children() {
if let RedTree::Node(inner) = child {
if inner.green.kind == ValkyrieElementType::NamePath {
let parent = Parent { alias: None, name: self.build_name_path(inner, source)?, span: inner.span() };
parents.push(parent);
}
}
}
}
ValkyrieElementType::Namespace => {
let ns = self.build_namespace(n, source)?;
items.push(Item::Namespace(ns))
}
ValkyrieElementType::Class => {
let class = self.build_class(n, source)?;
items.push(Item::Class(class))
}
ValkyrieElementType::Micro => {
let micro = self.build_micro(n, source)?;
items.push(Item::Micro(micro))
}
ValkyrieElementType::LetStatement => {
let stmt = self.build_let(n, source)?;
items.push(Item::Statement(stmt))
}
ValkyrieElementType::ExprStatement => {
let stmt = self.build_expr_stmt(n, source)?;
items.push(Item::Statement(stmt))
}
_ => {}
},
}
}
Ok(Singleton { name, generics, parents, items, annotations, span })
}
}