1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use super::problems;
use crate::ast::structure as i;
use crate::high_level::compiler::{PerformanceCounters, SourceSet};
use crate::high_level::problem::{CompileProblem, FilePosition};
use crate::vague::structure as o;
use std::collections::HashSet;
#[derive(Clone, Default)]
pub(super) struct AuxScopeData {
pub(super) included_files: HashSet<usize>,
}
pub(super) struct VagueIngester<'a> {
pub(super) target: o::Program,
pub(super) current_scope: o::ScopeId,
pub(super) current_file_id: usize,
pub(super) source_set: &'a SourceSet,
pub(super) perf_counters: &'a mut PerformanceCounters,
pub(super) aux_scope_data: AuxScopeData,
aux_scope_stack: Vec<AuxScopeData>,
}
impl<'a> VagueIngester<'a> {
pub(super) fn make_position(&self, node: &i::Node) -> FilePosition {
FilePosition::from_pair(node, self.current_file_id)
}
pub(super) fn lookup_identifier(
&self,
node: &i::Node,
) -> Result<o::VariableId, CompileProblem> {
debug_assert!(node.as_rule() == i::Rule::identifier);
match self.target.lookup_symbol(self.current_scope, node.as_str()) {
Option::Some(entity) => Result::Ok(entity),
Option::None => {
let position = self.make_position(node);
Result::Err(problems::no_entity_with_name(position))
}
}
}
pub(super) fn lookup_identifier_without_error(&self, name: &str) -> Option<o::VariableId> {
self.target.lookup_symbol(self.current_scope, name)
}
pub(super) fn add_statement(&mut self, statement: o::Statement) {
self.target[self.current_scope].add_statement(statement);
}
pub(super) fn create_variable_in_scope(
&mut self,
scope: o::ScopeId,
data_type: o::VPExpression,
name: &str,
decl_pos: FilePosition,
) -> o::VariableId {
let var = o::Variable::variable(decl_pos.clone(), None);
let var_id = self.target.adopt_and_define_symbol(scope, name, var);
self.target[scope].add_statement(o::Statement::CreationPoint {
var: var_id,
var_type: Box::new(data_type),
position: decl_pos,
});
var_id
}
pub(super) fn create_variable(
&mut self,
data_type: o::VPExpression,
name: &str,
decl_pos: FilePosition,
) -> o::VariableId {
self.create_variable_in_scope(self.current_scope, data_type, name, decl_pos)
}
pub(super) fn enter_scope(&mut self) {
self.aux_scope_stack.push(self.aux_scope_data.clone());
}
pub(super) fn exit_scope(&mut self) {
self.aux_scope_data = self
.aux_scope_stack
.pop()
.expect("exit_scope called without a matching enter_scope.");
}
pub(super) fn execute(&mut self, source: &mut i::Program) -> Result<(), CompileProblem> {
let root_node = source.next().expect("illegal grammar");
debug_assert!(root_node.as_rule() == i::Rule::root);
for child in root_node.into_inner() {
if child.as_rule() == i::Rule::EOI {
break;
}
self.convert_statement(child)?;
}
Ok(())
}
}
pub fn ingest(
source: &mut i::Program,
source_set: &SourceSet,
perf_counters: &mut PerformanceCounters,
) -> Result<o::Program, CompileProblem> {
let target = o::Program::new();
let init_scope = target.get_entry_point();
let mut ingester = VagueIngester {
target,
current_scope: init_scope,
current_file_id: 1,
source_set,
perf_counters,
aux_scope_data: Default::default(),
aux_scope_stack: Vec::new(),
};
ingester.execute(source)?;
Ok(ingester.target)
}