1use derive_more::{From};
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4
5use kodept_core::structure::rlt;
6use kodept_core::structure::span::CodeHolder;
7
8use crate::graph::NodeId;
9use crate::graph::{SyntaxTreeBuilder};
10use crate::traits::Linker;
11use crate::traits::PopulateTree;
12use crate::{node, node_sub_enum};
13
14node_sub_enum! {
15 #[derive(Debug, PartialEq)]
16 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17 pub enum Term {
18 Ref(Ref)
19 }
20}
21
22#[derive(Debug, PartialEq, Default)]
23#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
24pub struct ReferenceContext {
25 global: bool,
26 items: Vec<String>
27}
28
29node! {
30 #[derive(Debug, PartialEq)]
31 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
32 pub struct Ref {
33 pub context: ReferenceContext,
34 pub ident: Identifier,;
35 }
36}
37
38#[derive(Debug, PartialEq, From)]
39#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
40pub enum Identifier {
41 #[from(ignore)]
42 TypeReference { name: String },
43 #[from(ignore)]
44 Reference { name: String },
45}
46
47impl ReferenceContext {
48 pub fn global(items: impl IntoIterator<Item: Into<String>>) -> Self {
49 Self {
50 global: true,
51 items: items.into_iter().map(|it| it.into()).collect(),
52 }
53 }
54
55 pub fn local(items: impl IntoIterator<Item: Into<String>>) -> Self {
56 Self {
57 global: false,
58 items: items.into_iter().map(|it| it.into()).collect(),
59 }
60 }
61}
62
63impl PopulateTree for rlt::Term {
64 type Output = Term;
65
66 fn convert(
67 &self,
68 builder: &mut SyntaxTreeBuilder,
69 context: &mut (impl Linker + CodeHolder),
70 ) -> NodeId<Self::Output> {
71 match self {
72 rlt::Term::Reference(x) => x.convert(builder, context).cast(),
73 rlt::Term::Contextual(x) => x.inner.convert(builder, context).cast()
74 }
75 }
76}
77
78impl PopulateTree for rlt::ContextualReference {
79 type Output = Ref;
80
81 fn convert(&self, builder: &mut SyntaxTreeBuilder, context: &mut (impl Linker + CodeHolder)) -> NodeId<Self::Output> {
82 let ident = match &self.inner {
83 rlt::Reference::Type(x) => Identifier::TypeReference {
84 name: context.get_chunk_located(x).to_string(),
85 },
86 rlt::Reference::Identifier(x) => Identifier::Reference {
87 name: context.get_chunk_located(x).to_string(),
88 },
89 };
90 let (from_root, refs) = self.context.clone().unfold();
91 let ctx = ReferenceContext {
92 global: from_root.is_some(),
93 items: refs.into_iter().map(|it| match it {
94 rlt::Reference::Type(x) => context.get_chunk_located(&x).to_string(),
95 rlt::Reference::Identifier(_) => panic!("Context built with ordinary references is unsupported")
96 }).collect(),
97 };
98 builder.add_node(Ref::uninit(ctx, ident))
99 .with_rlt(context, self)
100 .id()
101 }
102}
103
104impl PopulateTree for rlt::Reference {
105 type Output = Ref;
106
107 fn convert(
108 &self,
109 builder: &mut SyntaxTreeBuilder,
110 context: &mut (impl Linker + CodeHolder),
111 ) -> NodeId<Self::Output> {
112 let ident = match self {
113 rlt::Reference::Type(x) => Identifier::TypeReference {
114 name: context.get_chunk_located(x).to_string(),
115 },
116 rlt::Reference::Identifier(x) => Identifier::Reference {
117 name: context.get_chunk_located(x).to_string(),
118 },
119 };
120 builder
121 .add_node(Ref::uninit(Default::default(), ident))
122 .with_rlt(context, self)
123 .id()
124 }
125}