1#![allow(dead_code)]
2use super::super::constant::Value;
3use super::super::importer::{Config, ImportKey, Importer};
4use super::super::objects::{DeclInfoKey, ObjKey, PackageKey, ScopeKey, TCObjects, TypeKey};
5use super::super::operand::OperandMode;
6use super::super::selection::Selection;
7use super::interface::IfaceInfo;
8use goscript_parser::ast;
9use goscript_parser::ast::Node;
10use goscript_parser::ast::{Expr, NodeId};
11use goscript_parser::errors::{ErrorList, FilePosErrors};
12use goscript_parser::objects::{IdentKey, Objects as AstObjects};
13use goscript_parser::position::Pos;
14use goscript_parser::FileSet;
15use std::cell::RefCell;
16use std::collections::{HashMap, HashSet};
17use std::rc::Rc;
18
19#[derive(Debug, Clone)]
22pub struct TypeAndValue {
23 pub mode: OperandMode,
24 pub typ: TypeKey,
25}
26
27impl TypeAndValue {
28 pub fn get_const_val(&self) -> Option<&Value> {
29 match &self.mode {
30 OperandMode::Constant(v) => Some(v),
31 _ => None,
32 }
33 }
34}
35
36#[derive(Debug)]
40pub struct Initializer {
41 pub lhs: Vec<ObjKey>,
42 pub rhs: Expr,
43}
44
45#[derive(Debug)]
47pub struct TypeInfo {
48 pub types: HashMap<NodeId, TypeAndValue>,
66 pub defs: HashMap<IdentKey, Option<ObjKey>>,
76 pub uses: HashMap<IdentKey, ObjKey>,
82 pub implicits: HashMap<NodeId, ObjKey>,
89 pub selections: HashMap<NodeId, Selection>,
92 pub scopes: HashMap<NodeId, ScopeKey>,
114 pub init_order: Vec<Initializer>,
120 pub ast_files: Vec<ast::File>,
122}
123
124impl TypeInfo {
125 pub fn new() -> TypeInfo {
126 TypeInfo {
127 types: HashMap::new(),
128 defs: HashMap::new(),
129 uses: HashMap::new(),
130 implicits: HashMap::new(),
131 selections: HashMap::new(),
132 scopes: HashMap::new(),
133 init_order: Vec::new(),
134 ast_files: Vec::new(),
135 }
136 }
137}
138
139#[derive(Debug)]
141pub struct ExprInfo {
142 pub is_lhs: bool,
143 pub mode: OperandMode,
144 pub typ: Option<TypeKey>,
145}
146
147#[derive(Clone)]
150pub struct ObjContext {
151 pub decl: Option<DeclInfoKey>,
153 pub scope: Option<ScopeKey>,
155 pub pos: Option<Pos>,
157 pub iota: Option<Value>,
159 pub sig: Option<TypeKey>,
161 pub panics: Option<HashSet<NodeId>>,
163 pub has_label: bool,
165 pub has_call_or_recv: bool,
167}
168
169type DelayedAction = Box<dyn FnOnce(&mut Checker, &mut FilesContext)>;
170
171pub type RcIfaceInfo = Rc<IfaceInfo>;
172
173pub struct FilesContext<'a> {
176 pub files: &'a Vec<ast::File>,
178 pub unused_dot_imports: HashMap<ScopeKey, HashMap<PackageKey, Pos>>,
180 pub methods: HashMap<ObjKey, Vec<ObjKey>>,
183 pub ifaces: HashMap<ObjKey, Option<RcIfaceInfo>>,
186 pub untyped: HashMap<NodeId, ExprInfo>,
188 pub delayed: Vec<DelayedAction>,
190 pub obj_path: Vec<ObjKey>,
192}
193
194pub struct Checker<'a> {
195 pub tc_objs: &'a mut TCObjects,
197 pub ast_objs: &'a mut AstObjects,
199 errors: &'a ErrorList,
201 pub fset: &'a mut FileSet,
203 pub all_pkgs: &'a mut HashMap<String, PackageKey>,
205 all_results: &'a mut HashMap<PackageKey, TypeInfo>,
208 pub pkg: PackageKey,
210 pub obj_map: HashMap<ObjKey, DeclInfoKey>,
212 pub imp_map: HashMap<ImportKey, PackageKey>,
214 pub octx: ObjContext,
216 config: &'a Config,
218 pub result: TypeInfo,
220 pub indent: Rc<RefCell<usize>>,
222}
223
224impl ObjContext {
225 pub fn new() -> ObjContext {
226 ObjContext {
227 decl: None,
228 scope: None,
229 pos: None,
230 iota: None,
231 sig: None,
232 panics: None,
233 has_label: false,
234 has_call_or_recv: false,
235 }
236 }
237}
238
239impl FilesContext<'_> {
240 pub fn new(files: &Vec<ast::File>) -> FilesContext<'_> {
241 FilesContext {
242 files: files,
243 unused_dot_imports: HashMap::new(),
244 methods: HashMap::new(),
245 ifaces: HashMap::new(),
246 untyped: HashMap::new(),
247 delayed: Vec::new(),
248 obj_path: Vec::new(),
249 }
250 }
251
252 pub fn file_name(&self, index: usize, checker: &Checker) -> String {
254 let file = &self.files[index];
255 let pos = file.pos(checker.ast_objs);
256 if pos > 0 {
257 checker.fset.file(pos).unwrap().name().to_owned()
258 } else {
259 format!("file[{}]", index)
260 }
261 }
262
263 pub fn add_unused_dot_import(&mut self, scope: &ScopeKey, pkg: &PackageKey, pos: Pos) {
264 if !self.unused_dot_imports.contains_key(scope) {
265 self.unused_dot_imports.insert(*scope, HashMap::new());
266 }
267 self.unused_dot_imports
268 .get_mut(scope)
269 .unwrap()
270 .insert(*pkg, pos);
271 }
272
273 pub fn remember_untyped(&mut self, e: &Expr, ex_info: ExprInfo) {
274 self.untyped.insert(e.id(), ex_info);
275 }
276
277 pub fn later(&mut self, action: DelayedAction) {
282 self.delayed.push(action);
283 }
284
285 pub fn delayed_count(&self) -> usize {
286 self.delayed.len()
287 }
288
289 pub fn process_delayed(&mut self, top: usize, checker: &mut Checker) {
290 let fs: Vec<DelayedAction> = self.delayed.drain(top..).into_iter().collect();
291 for f in fs {
292 f(checker, self);
293 }
294 }
295
296 pub fn push(&mut self, obj: ObjKey) -> usize {
298 self.obj_path.push(obj);
299 self.obj_path.len() - 1
300 }
301
302 pub fn pop(&mut self) -> ObjKey {
303 self.obj_path.pop().unwrap()
304 }
305}
306
307impl TypeAndValue {
308 fn new(mode: OperandMode, typ: TypeKey) -> TypeAndValue {
309 TypeAndValue {
310 mode: mode,
311 typ: typ,
312 }
313 }
314}
315
316impl TypeInfo {
317 pub fn record_type_and_value(&mut self, e: &Expr, mode: OperandMode, typ: TypeKey) {
318 self.record_type_and_value_with_id(e.id(), mode, typ);
319 }
320
321 pub fn record_type_and_value_with_id(&mut self, id: NodeId, mode: OperandMode, typ: TypeKey) {
322 if let OperandMode::Invalid = mode {
323 return;
324 }
325 self.types.insert(id, TypeAndValue::new(mode, typ));
326 }
327
328 pub fn record_builtin_type(&mut self, mode: &OperandMode, e: &Expr, sig: TypeKey) {
329 let mut expr = e;
330 loop {
335 self.record_type_and_value(expr, mode.clone(), sig);
336 match expr {
337 Expr::Ident(_) => break,
338 Expr::Paren(p) => expr = &(*p).expr,
339 _ => unreachable!(),
340 }
341 }
342 }
343
344 pub fn record_comma_ok_types(
345 &mut self,
346 e: &Expr,
347 t: &[TypeKey; 2],
348 tc_objs: &mut TCObjects,
349 ast_objs: &AstObjects,
350 pkg: PackageKey,
351 ) {
352 let pos = e.pos(ast_objs);
353 let mut expr = e;
354 loop {
355 let tv = self.types.get_mut(&expr.id()).unwrap();
356 tv.typ = Checker::comma_ok_type(tc_objs, pos, pkg, t);
357 match expr {
358 Expr::Paren(p) => expr = &(*p).expr,
359 _ => break,
360 }
361 }
362 }
363
364 pub fn record_def(&mut self, id: IdentKey, obj: Option<ObjKey>) {
365 self.defs.insert(id, obj);
366 }
367
368 pub fn record_use(&mut self, id: IdentKey, obj: ObjKey) {
369 self.uses.insert(id, obj);
370 }
371
372 pub fn record_implicit(&mut self, node: &impl Node, obj: ObjKey) {
373 self.implicits.insert(node.id(), obj);
374 }
375
376 pub fn record_selection(&mut self, expr: &ast::SelectorExpr, sel: Selection) {
377 self.record_use(expr.sel, sel.obj());
378 self.selections.insert(expr.id(), sel);
379 }
380
381 pub fn record_scope(&mut self, node: &impl Node, scope: ScopeKey) {
382 self.scopes.insert(node.id(), scope);
383 }
384
385 pub fn record_init_order(&mut self, init_order: Vec<Initializer>) {
386 self.init_order = init_order;
387 }
388}
389
390impl<'a> Checker<'a> {
391 pub fn new(
392 tc_objs: &'a mut TCObjects,
393 ast_objs: &'a mut AstObjects,
394 fset: &'a mut FileSet,
395 errors: &'a ErrorList,
396 pkgs: &'a mut HashMap<String, PackageKey>,
397 all_results: &'a mut HashMap<PackageKey, TypeInfo>,
398 pkg: PackageKey,
399 cfg: &'a Config,
400 ) -> Checker<'a> {
401 Checker {
402 tc_objs: tc_objs,
403 ast_objs: ast_objs,
404 fset: fset,
405 errors: errors,
406 all_pkgs: pkgs,
407 all_results: all_results,
408 pkg: pkg,
409 obj_map: HashMap::new(),
410 imp_map: HashMap::new(),
411 octx: ObjContext::new(),
412 config: cfg,
413 result: TypeInfo::new(),
414 indent: Rc::new(RefCell::new(0)),
415 }
416 }
417
418 pub fn check(mut self, mut files: Vec<ast::File>) -> Result<PackageKey, ()> {
419 self.check_files_pkg_name(&files)?;
420 let fctx = &mut FilesContext::new(&files);
421 self.collect_objects(fctx);
422 self.package_objects(fctx);
423 fctx.process_delayed(0, &mut self);
424 self.init_order();
425 self.unused_imports(fctx);
426 self.record_untyped(fctx);
427
428 std::mem::swap(&mut self.result.ast_files, &mut files);
429 self.all_results.insert(self.pkg, self.result);
430 Ok(self.pkg)
431 }
432
433 fn record_untyped(&mut self, fctx: &mut FilesContext) {
434 for (id, info) in fctx.untyped.drain().into_iter() {
435 if info.mode != OperandMode::Invalid {
436 self.result
437 .record_type_and_value_with_id(id.clone(), info.mode, info.typ.unwrap());
438 }
439 }
440 }
441
442 pub fn errors(&self) -> &ErrorList {
443 self.errors
444 }
445
446 pub fn config(&self) -> &Config {
447 &self.config
448 }
449
450 pub fn new_importer(&mut self, pos: Pos) -> Importer {
451 Importer::new(
452 self.config,
453 self.fset,
454 self.all_pkgs,
455 self.all_results,
456 self.ast_objs,
457 self.tc_objs,
458 self.errors,
459 pos,
460 )
461 }
462
463 fn check_files_pkg_name(&mut self, files: &Vec<ast::File>) -> Result<(), ()> {
465 let mut pkg_name: Option<String> = None;
466 for f in files.iter() {
467 let ident = &self.ast_objs.idents[f.name];
468 if pkg_name.is_none() {
469 if ident.name == "_" {
470 self.error(ident.pos, "invalid package name _".to_string());
471 return Err(());
472 } else {
473 pkg_name = Some(ident.name.clone());
474 }
475 } else if &ident.name != pkg_name.as_ref().unwrap() {
476 self.error(
477 f.package,
478 format!(
479 "package {}; expected {}",
480 ident.name,
481 pkg_name.as_ref().unwrap()
482 ),
483 );
484 return Err(());
485 }
486 }
487 self.tc_objs.pkgs[self.pkg].set_name(pkg_name.unwrap());
488 Ok(())
489 }
490
491 pub fn error(&self, pos: Pos, err: String) {
492 self.error_impl(pos, err, false);
493 }
494
495 pub fn error_str(&self, pos: Pos, err: &str) {
496 self.error_impl(pos, err.to_string(), false);
497 }
498
499 pub fn soft_error(&self, pos: Pos, err: String) {
500 self.error_impl(pos, err, true);
501 }
502
503 pub fn soft_error_str(&self, pos: Pos, err: &str) {
504 self.error_impl(pos, err.to_string(), true);
505 }
506
507 fn error_impl(&self, pos: Pos, err: String, soft: bool) {
508 let file = self.fset.file(pos).unwrap();
509 FilePosErrors::new(file, self.errors).add(pos, err, soft);
510 }
511}