1#![warn(clippy::todo)]
2
3pub mod ast;
6mod cmd_ext;
7mod expr_ext;
8mod parse;
9pub mod smt;
10mod span;
11pub mod tc;
12
13use std::sync::{Arc, RwLock};
14
15use ast::{DomainRef, FunctionRef, MethodRef, Ref};
16use indexmap::IndexMap;
17pub use parse::ParseResult;
18pub use span::{Position, Span};
19
20#[derive(Debug)]
22pub struct SourceFile {
23 items: Arc<Items>,
24 pub parse_errors: Vec<parse::ParseError>,
26 pub tc_errors: Vec<tc::Error>,
28}
29impl SourceFile {
30 pub fn methods(&self) -> Vec<Arc<ast::Method>> {
32 self.items.methods()
33 }
34 pub fn functions(&self) -> Vec<Arc<ast::Function>> {
36 self.items.functions()
37 }
38 pub fn domains(&self) -> Vec<Arc<ast::Domain>> {
40 self.items.domains()
41 }
42 pub fn globals(&self) -> Vec<Arc<ast::Global>> {
44 self.items.globals()
45 }
46
47 pub fn get_method_ref(&self, ident: String) -> MethodRef {
51 MethodRef(self.items.new_ref(ident))
52 }
53 pub fn get_function_ref(&self, ident: String) -> FunctionRef {
58 FunctionRef(self.items.new_ref(ident))
59 }
60 pub fn get_domain_ref(&self, ident: String) -> DomainRef {
64 DomainRef(self.items.new_ref(ident))
65 }
66
67 pub fn contains_error(&self) -> bool {
69 !self.parse_errors.is_empty() || !self.tc_errors.is_empty()
70 }
71}
72
73#[non_exhaustive]
75#[derive(Debug, Default)]
76pub struct Items {
77 methods: RwLock<IndexMap<String, Arc<ast::Method>>>,
78 functions: RwLock<IndexMap<String, (bool, Arc<ast::Function>)>>,
79 domains: RwLock<IndexMap<String, Arc<ast::Domain>>>,
80 globals: RwLock<IndexMap<String, Arc<ast::Global>>>,
81}
82
83impl Items {
84 fn new_ref(self: &Arc<Self>, ident: String) -> Ref {
85 Ref::Resolved(ident, Arc::downgrade(self))
86 }
87 pub fn methods(&self) -> Vec<Arc<ast::Method>> {
89 self.methods.read().unwrap().values().cloned().collect()
90 }
91 pub fn method(&self, id: &str) -> Option<Arc<ast::Method>> {
93 self.methods.read().ok()?.get(id).cloned()
94 }
95 fn insert_method(&self, id: String, ast: Arc<ast::Method>) {
96 self.methods.write().unwrap().insert(id, ast);
97 }
98 pub fn functions(&self) -> Vec<Arc<ast::Function>> {
100 self.functions
101 .read()
102 .unwrap()
103 .values()
104 .filter_map(|(is_domain, f)| if *is_domain { None } else { Some(f.clone()) })
105 .collect()
106 }
107 pub fn function(&self, id: &str) -> Option<Arc<ast::Function>> {
109 Some(self.functions.read().ok()?.get(id).cloned()?.1)
110 }
111 fn insert_function(&self, id: String, is_domain: bool, ast: Arc<ast::Function>) {
112 self.functions.write().unwrap().insert(id, (is_domain, ast));
113 }
114 pub fn domains(&self) -> Vec<Arc<ast::Domain>> {
116 self.domains.read().unwrap().values().cloned().collect()
117 }
118 pub fn domain(&self, id: &str) -> Option<Arc<ast::Domain>> {
120 self.domains.read().ok()?.get(id).cloned()
121 }
122 fn insert_domain(&self, id: String, ast: Arc<ast::Domain>) {
123 self.domains.write().unwrap().insert(id, ast);
124 }
125 pub fn globals(&self) -> Vec<Arc<ast::Global>> {
127 self.globals.read().unwrap().values().cloned().collect()
128 }
129 pub fn global(&self, id: &str) -> Option<Arc<ast::Global>> {
131 self.globals.read().ok()?.get(id).cloned()
132 }
133 fn insert_global(&self, id: String, ast: Arc<ast::Global>) {
134 self.globals.write().unwrap().insert(id, ast);
135 }
136}
137
138pub fn parse_file(src: &str) -> SourceFile {
139 let ParseResult {
140 ast,
141 errors: parse_errors,
142 } = parse::file(src);
143
144 if let Some((items, tc_errors)) = ast.map(|file| file.tc()) {
145 SourceFile {
146 items,
147 parse_errors,
148 tc_errors,
149 }
150 } else {
151 SourceFile {
152 items: Default::default(),
153 parse_errors,
154 tc_errors: Vec::new(),
155 }
156 }
157}