xee_interpreter/interpreter/
program.rs

1use crate::context;
2use crate::declaration::Declarations;
3use crate::function;
4use xee_name::Name;
5use xee_xpath_ast::ast::Span;
6
7use super::Runnable;
8
9#[derive(Debug)]
10pub struct Program {
11    span: Span,
12    pub functions: Vec<function::InlineFunction>,
13    pub declarations: Declarations,
14    static_context: context::StaticContext,
15    map_signature: function::Signature,
16    array_signature: function::Signature,
17}
18
19impl Program {
20    pub fn new(static_context: context::StaticContext, span: Span) -> Self {
21        Program {
22            span,
23            functions: Vec::new(),
24            declarations: Declarations::new(),
25            static_context,
26            map_signature: function::Signature::map_signature(),
27            array_signature: function::Signature::array_signature(),
28        }
29    }
30
31    pub fn static_context(&self) -> &context::StaticContext {
32        &self.static_context
33    }
34
35    pub fn dynamic_context_builder(&self) -> context::DynamicContextBuilder {
36        context::DynamicContextBuilder::new(self)
37    }
38
39    pub fn span(&self) -> Span {
40        self.span
41    }
42
43    pub(crate) fn inline_function(
44        &self,
45        function_id: function::InlineFunctionId,
46    ) -> &function::InlineFunction {
47        &self.functions[function_id.0]
48    }
49
50    pub(crate) fn static_function(
51        &self,
52        function_id: function::StaticFunctionId,
53    ) -> &function::StaticFunction {
54        self.static_context.function_by_id(function_id)
55    }
56
57    pub fn function_info<'a, 'b>(
58        &'a self,
59        function: &'b function::Function,
60    ) -> FunctionInfo<'a, 'b> {
61        FunctionInfo::new(function, self)
62    }
63
64    /// Obtain a runnable version of this program, with a particular dynamic context.
65    pub fn runnable<'a>(&'a self, dynamic_context: &'a context::DynamicContext) -> Runnable<'a> {
66        Runnable::new(self, dynamic_context)
67    }
68
69    pub fn add_function(
70        &mut self,
71        function: function::InlineFunction,
72    ) -> function::InlineFunctionId {
73        let id = self.functions.len();
74        if id > u16::MAX as usize {
75            panic!("too many functions");
76        }
77        self.functions.push(function);
78
79        function::InlineFunctionId(id)
80    }
81
82    pub(crate) fn get_function(&self, index: usize) -> &function::InlineFunction {
83        &self.functions[index]
84    }
85
86    pub(crate) fn get_function_by_id(
87        &self,
88        id: function::InlineFunctionId,
89    ) -> &function::InlineFunction {
90        self.get_function(id.0)
91    }
92
93    pub(crate) fn main_id(&self) -> function::InlineFunctionId {
94        function::InlineFunctionId(self.functions.len() - 1)
95    }
96}
97
98/// Given a function provide information about it.
99pub struct FunctionInfo<'a, 'b> {
100    function: &'b function::Function,
101    program: &'a Program,
102}
103
104impl<'a, 'b> FunctionInfo<'a, 'b> {
105    pub(crate) fn new(
106        function: &'b function::Function,
107        program: &'a Program,
108    ) -> FunctionInfo<'a, 'b> {
109        FunctionInfo { function, program }
110    }
111
112    /// Return the arity of the function.
113    pub fn arity(&self) -> usize {
114        match self.function {
115            function::Function::Inline(data) => self.program.inline_function(data.id).arity(),
116            function::Function::Static(data) => self.program.static_function(data.id).arity(),
117            function::Function::Array(_) => 1,
118            function::Function::Map(_) => 1,
119        }
120    }
121
122    /// Return the name of the function.
123    ///
124    /// Note that only static functions have names.
125    pub fn name(&self) -> Option<Name> {
126        match self.function {
127            function::Function::Static(data) => {
128                let static_function = self.program.static_function(data.id);
129                static_function.name().cloned()
130            }
131            _ => None,
132        }
133    }
134
135    /// Return the signature of the function.
136    pub fn signature(&self) -> &'a function::Signature {
137        match &self.function {
138            function::Function::Static(data) => {
139                let static_function = self.program.static_function(data.id);
140                static_function.signature()
141            }
142            function::Function::Inline(data) => {
143                let inline_function = self.program.inline_function(data.id);
144                inline_function.signature()
145            }
146            function::Function::Map(_map) => &self.program.map_signature,
147            function::Function::Array(_array) => &self.program.array_signature,
148        }
149    }
150}