1#![allow(dead_code)]
2use super::constant;
3use super::objects::{ObjKey, PackageKey, ScopeKey, TCObjects, TypeKey};
4use super::package::Package;
5use super::typ;
6use super::universe;
7use super::universe::Universe;
8use goscript_parser::ast;
9use goscript_parser::position;
10use std::borrow::Cow;
11use std::collections::HashMap;
12use std::fmt;
13use std::fmt::Write;
14
15#[derive(Clone, Debug, PartialEq)]
16pub struct VarProperty {
17 pub embedded: bool,
18 pub is_field: bool,
19 pub used: bool,
20}
21
22impl VarProperty {
23 pub fn new(embedded: bool, field: bool, used: bool) -> VarProperty {
24 VarProperty {
25 embedded: embedded,
26 is_field: field,
27 used: used,
28 }
29 }
30}
31
32#[derive(Clone, Debug, PartialEq)]
35pub enum EntityType {
36 PkgName(PackageKey, bool), Const(constant::Value),
40 TypeName,
42 Var(VarProperty),
45 Func(bool), Label(bool), Builtin(universe::Builtin),
55 Nil,
57}
58
59impl EntityType {
60 pub fn is_pkg_name(&self) -> bool {
61 match self {
62 EntityType::PkgName(_, _) => true,
63 _ => false,
64 }
65 }
66
67 pub fn is_const(&self) -> bool {
68 match self {
69 EntityType::Const(_) => true,
70 _ => false,
71 }
72 }
73
74 pub fn is_type_name(&self) -> bool {
75 match self {
76 EntityType::TypeName => true,
77 _ => false,
78 }
79 }
80
81 pub fn is_var(&self) -> bool {
82 match self {
83 EntityType::Var(_) => true,
84 _ => false,
85 }
86 }
87
88 pub fn is_func(&self) -> bool {
89 match self {
90 EntityType::Func(_) => true,
91 _ => false,
92 }
93 }
94
95 pub fn is_label(&self) -> bool {
96 match self {
97 EntityType::Label(_) => true,
98 _ => false,
99 }
100 }
101
102 pub fn is_builtin(&self) -> bool {
103 match self {
104 EntityType::Builtin(_) => true,
105 _ => false,
106 }
107 }
108
109 pub fn is_nil(&self) -> bool {
110 match self {
111 EntityType::Nil => true,
112 _ => false,
113 }
114 }
115
116 pub fn is_dependency(&self) -> bool {
117 match self {
118 EntityType::Const(_) | EntityType::Var(_) | EntityType::Func(_) => true,
119 _ => false,
120 }
121 }
122
123 pub fn func_has_ptr_recv(&self) -> bool {
124 match self {
125 EntityType::Func(h) => *h,
126 _ => unreachable!(),
127 }
128 }
129
130 pub fn func_set_has_ptr_recv(&mut self, has: bool) {
131 match self {
132 EntityType::Func(h) => {
133 *h = has;
134 }
135 _ => unreachable!(),
136 }
137 }
138
139 pub fn var_property_mut(&mut self) -> &mut VarProperty {
140 match self {
141 EntityType::Var(prop) => prop,
142 _ => unreachable!(),
143 }
144 }
145
146 pub fn label_used(&self) -> bool {
147 match self {
148 EntityType::Label(u) => *u,
149 _ => unreachable!(),
150 }
151 }
152
153 pub fn label_set_used(&mut self, used: bool) {
154 match self {
155 EntityType::Label(u) => {
156 *u = used;
157 }
158 _ => unreachable!(),
159 }
160 }
161}
162
163#[derive(Copy, Clone, Debug, PartialEq, Eq)]
164pub enum ObjColor {
165 White,
166 Black,
167 Gray(usize),
168}
169
170impl fmt::Display for ObjColor {
171 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
172 match self {
173 ObjColor::White => f.write_str("white"),
174 ObjColor::Black => f.write_str("black"),
175 ObjColor::Gray(_) => f.write_str("gray"),
176 }
177 }
178}
179
180#[derive(Clone, Debug)]
187pub struct LangObj {
188 entity_type: EntityType,
189 parent: Option<ScopeKey>,
190 pos: position::Pos,
191 pkg: Option<PackageKey>,
192 name: String,
193 typ: Option<TypeKey>,
194 order: u32,
195 color: ObjColor,
196 scope_pos: position::Pos,
197}
198
199impl LangObj {
200 pub fn new_pkg_name(
201 pos: position::Pos,
202 pkg: Option<PackageKey>,
203 name: String,
204 imported: PackageKey,
205 univ: &Universe,
206 ) -> LangObj {
207 let t = univ.types()[&typ::BasicType::Invalid];
208 LangObj::new(
209 EntityType::PkgName(imported, false),
210 pos,
211 pkg,
212 name,
213 Some(t),
214 )
215 }
216
217 pub fn new_const(
218 pos: position::Pos,
219 pkg: Option<PackageKey>,
220 name: String,
221 typ: Option<TypeKey>,
222 val: constant::Value,
223 ) -> LangObj {
224 LangObj::new(EntityType::Const(val), pos, pkg, name, typ)
225 }
226
227 pub fn new_type_name(
228 pos: position::Pos,
229 pkg: Option<PackageKey>,
230 name: String,
231 typ: Option<TypeKey>,
232 ) -> LangObj {
233 LangObj::new(EntityType::TypeName, pos, pkg, name, typ)
234 }
235
236 pub fn new_var(
237 pos: position::Pos,
238 pkg: Option<PackageKey>,
239 name: String,
240 typ: Option<TypeKey>,
241 ) -> LangObj {
242 LangObj::new(
243 EntityType::Var(VarProperty::new(false, false, false)),
244 pos,
245 pkg,
246 name,
247 typ,
248 )
249 }
250
251 pub fn new_param_var(
252 pos: position::Pos,
253 pkg: Option<PackageKey>,
254 name: String,
255 typ: Option<TypeKey>,
256 ) -> LangObj {
257 LangObj::new(
258 EntityType::Var(VarProperty::new(false, false, true)),
259 pos,
260 pkg,
261 name,
262 typ,
263 )
264 }
265
266 pub fn new_field(
267 pos: position::Pos,
268 pkg: Option<PackageKey>,
269 name: String,
270 typ: Option<TypeKey>,
271 embedded: bool,
272 ) -> LangObj {
273 LangObj::new(
274 EntityType::Var(VarProperty::new(embedded, true, false)),
275 pos,
276 pkg,
277 name,
278 typ,
279 )
280 }
281
282 pub fn new_func(
283 pos: position::Pos,
284 pkg: Option<PackageKey>,
285 name: String,
286 typ: Option<TypeKey>,
287 ) -> LangObj {
288 LangObj::new(EntityType::Func(false), pos, pkg, name, typ)
289 }
290
291 pub fn new_label(
292 pos: position::Pos,
293 pkg: Option<PackageKey>,
294 name: String,
295 univ: &Universe,
296 ) -> LangObj {
297 let t = univ.types()[&typ::BasicType::Invalid];
298 LangObj::new(EntityType::Label(false), pos, pkg, name, Some(t))
299 }
300
301 pub fn new_builtin(f: universe::Builtin, name: String, typ: TypeKey) -> LangObj {
302 LangObj::new(EntityType::Builtin(f), 0, None, name, Some(typ))
303 }
304
305 pub fn new_nil(typ: TypeKey) -> LangObj {
306 LangObj::new(EntityType::Nil, 0, None, "nil".to_owned(), Some(typ))
307 }
308
309 pub fn entity_type(&self) -> &EntityType {
310 &self.entity_type
311 }
312
313 pub fn entity_type_mut(&mut self) -> &mut EntityType {
314 &mut self.entity_type
315 }
316
317 pub fn parent(&self) -> Option<ScopeKey> {
318 self.parent
319 }
320
321 pub fn pos(&self) -> position::Pos {
322 self.pos
323 }
324
325 pub fn name(&self) -> &String {
326 &self.name
327 }
328
329 pub fn typ(&self) -> Option<TypeKey> {
330 self.typ
331 }
332
333 pub fn pkg(&self) -> Option<PackageKey> {
334 self.pkg
335 }
336
337 pub fn exported(&self) -> bool {
338 ast::is_exported(&self.name)
339 }
340
341 pub fn id(&self, objs: &TCObjects) -> Cow<str> {
342 let pkg = self.pkg.map(|x| &objs.pkgs[x]);
343 get_id(pkg, &self.name)
344 }
345
346 pub fn order(&self) -> u32 {
347 self.order
348 }
349
350 pub fn color(&self) -> ObjColor {
351 self.color
352 }
353
354 pub fn set_type(&mut self, typ: Option<TypeKey>) {
355 self.typ = typ
356 }
357
358 pub fn set_pkg(&mut self, pkg: Option<PackageKey>) {
359 self.pkg = pkg;
360 }
361
362 pub fn set_parent(&mut self, parent: Option<ScopeKey>) {
363 self.parent = parent
364 }
365
366 pub fn scope_pos(&self) -> &position::Pos {
367 &self.scope_pos
368 }
369
370 pub fn set_order(&mut self, order: u32) {
371 assert!(order > 0);
372 self.order = order;
373 }
374
375 pub fn set_color(&mut self, color: ObjColor) {
376 assert!(color != ObjColor::White);
377 self.color = color
378 }
379
380 pub fn set_scope_pos(&mut self, pos: position::Pos) {
381 self.scope_pos = pos
382 }
383
384 pub fn same_id(&self, pkg: Option<PackageKey>, name: &str, objs: &TCObjects) -> bool {
385 if name != self.name {
390 false
391 } else if self.exported() {
392 true
393 } else if pkg.is_none() || self.pkg.is_none() {
394 pkg == self.pkg
395 } else {
396 let a = &objs.pkgs[pkg.unwrap()];
397 let b = &objs.pkgs[self.pkg.unwrap()];
398 a.path() == b.path()
399 }
400 }
401
402 pub fn pkg_name_imported(&self) -> PackageKey {
403 match &self.entity_type {
404 EntityType::PkgName(imported, _) => *imported,
405 _ => unreachable!(),
406 }
407 }
408
409 pub fn const_val(&self) -> &constant::Value {
410 match &self.entity_type {
411 EntityType::Const(val) => val,
412 _ => unreachable!(),
413 }
414 }
415
416 pub fn set_const_val(&mut self, v: constant::Value) {
417 match &mut self.entity_type {
418 EntityType::Const(val) => *val = v,
419 _ => unreachable!(),
420 }
421 }
422
423 pub fn var_embedded(&self) -> bool {
424 match &self.entity_type {
425 EntityType::Var(prop) => prop.embedded,
426 _ => unreachable!(),
427 }
428 }
429
430 pub fn var_is_field(&self) -> bool {
431 match &self.entity_type {
432 EntityType::Var(prop) => prop.is_field,
433 _ => unreachable!(),
434 }
435 }
436
437 pub fn func_fmt_name(&self, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
438 match &self.entity_type {
439 EntityType::Func(_) => fmt_func_name(self, f, objs),
440 _ => unreachable!(),
441 }
442 }
443
444 pub fn func_scope(&self) -> &ScopeKey {
445 unimplemented!()
446 }
447
448 fn new(
449 entity_type: EntityType,
450 pos: position::Pos,
451 pkg: Option<PackageKey>,
452 name: String,
453 typ: Option<TypeKey>,
454 ) -> LangObj {
455 LangObj {
456 entity_type: entity_type,
457 parent: None,
458 pos: pos,
459 pkg: pkg,
460 name: name,
461 typ: typ,
462 order: 0,
463 color: color_for_typ(typ),
464 scope_pos: 0,
465 }
466 }
467}
468
469pub fn type_name_is_alias(okey: ObjKey, objs: &TCObjects) -> bool {
470 let lobj = &objs.lobjs[okey];
471 match lobj.entity_type {
472 EntityType::TypeName => match lobj.typ {
473 Some(t) => {
474 let ty = &objs.types[t];
475 match ty {
476 typ::Type::Basic(detail) => {
477 let universe = objs.universe();
478 if lobj.pkg() == Some(*universe.unsafe_pkg()) {
480 false
481 } else {
482 lobj.pkg().is_some()
489 || detail.name() != lobj.name()
490 || t == *universe.byte()
491 || t == *universe.rune()
492 }
493 }
494 typ::Type::Named(detail) => *detail.obj() != Some(okey),
495 _ => true,
496 }
497 }
498 None => false,
499 },
500 _ => unreachable!(),
501 }
502}
503
504pub struct ObjSet(HashMap<String, ObjKey>);
509
510impl ObjSet {
511 pub fn new() -> ObjSet {
512 ObjSet(HashMap::new())
513 }
514
515 pub fn insert(&self, okey: ObjKey, objs: &TCObjects) -> Option<&ObjKey> {
516 let obj = &objs.lobjs[okey];
517 let id = obj.id(objs);
518 self.0.get(id.as_ref())
519 }
520}
521
522pub fn get_id<'a>(pkg: Option<&Package>, name: &'a str) -> Cow<'a, str> {
526 if ast::is_exported(name) {
527 return Cow::Borrowed(name);
528 }
529 let path = if let Some(p) = pkg {
530 if !p.path().is_empty() {
531 p.path()
532 } else {
533 "_"
534 }
535 } else {
536 "_"
537 };
538 Cow::Owned(format!("{}.{}", path, name))
539}
540
541pub fn fmt_obj(okey: ObjKey, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
542 let obj = &objs.lobjs[okey];
543 match obj.entity_type() {
544 EntityType::PkgName(imported, _) => {
545 write!(f, "package {}", obj.name())?;
546 let path = objs.pkgs[*imported].path();
547 if path != obj.name() {
548 write!(f, " ('{}')", path)?;
549 }
550 }
551 EntityType::Const(_) => {
552 f.write_str("const")?;
553 fmt_obj_name(okey, f, objs)?;
554 fmt_obj_type(okey, f, objs)?;
555 }
556 EntityType::TypeName => {
557 f.write_str("type")?;
558 fmt_obj_name(okey, f, objs)?;
559 fmt_obj_type(okey, f, objs)?;
560 }
561 EntityType::Var(prop) => {
562 f.write_str(if prop.is_field { "field" } else { "var" })?;
563 fmt_obj_name(okey, f, objs)?;
564 fmt_obj_type(okey, f, objs)?;
565 }
566 EntityType::Func(_) => {
567 f.write_str("func ")?;
568 fmt_func_name(obj, f, objs)?;
569 if let Some(t) = obj.typ() {
570 typ::fmt_signature(t, f, objs)?;
571 }
572 }
573 EntityType::Label(_) => {
574 f.write_str("label")?;
575 fmt_obj_name(okey, f, objs)?;
576 }
577 EntityType::Builtin(_) => {
578 f.write_str("builtin")?;
579 fmt_obj_name(okey, f, objs)?;
580 }
581 EntityType::Nil => f.write_str("nil")?,
582 }
583 Ok(())
584}
585
586fn fmt_obj_name(okey: ObjKey, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
587 f.write_char(' ')?;
588 let obj = &objs.lobjs[okey];
589 if let Some(p) = obj.pkg {
590 let pkg_val = &objs.pkgs[p];
591 if let Some(k) = objs.scopes[*pkg_val.scope()].lookup(obj.name()) {
592 if *k == okey {
593 pkg_val.fmt_with_qualifier(f, objs.fmt_qualifier.as_ref())?;
594 }
595 }
596 }
597 f.write_str(obj.name())
598}
599
600fn fmt_obj_type(okey: ObjKey, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
601 let obj = &objs.lobjs[okey];
602 if obj.typ().is_none() {
603 return Ok(());
604 }
605 let mut obj_typ = obj.typ().unwrap();
606 if obj.entity_type().is_type_name() {
607 let typ_val = &objs.types[obj.typ().unwrap()];
608 if typ_val.try_as_basic().is_some() {
609 return Ok(());
610 }
611 if type_name_is_alias(okey, objs) {
612 f.write_str(" =")?;
613 } else {
614 obj_typ = typ::underlying_type(obj_typ, objs);
615 }
616 }
617 f.write_char(' ')?;
618 typ::fmt_type(Some(obj_typ), f, objs)
619}
620
621fn fmt_func_name(func: &LangObj, f: &mut fmt::Formatter<'_>, objs: &TCObjects) -> fmt::Result {
622 if let Some(t) = func.typ() {
623 let sig = objs.types[t].try_as_signature().unwrap();
624 if let Some(r) = sig.recv() {
625 f.write_char('(')?;
626 typ::fmt_type(objs.lobjs[*r].typ(), f, objs)?;
627 f.write_str(").")?;
628 } else {
629 if let Some(p) = func.pkg() {
630 objs.pkgs[p].fmt_with_qualifier(f, objs.fmt_qualifier.as_ref())?;
631 }
632 }
633 }
634 f.write_str(func.name())
635}
636
637fn color_for_typ(typ: Option<TypeKey>) -> ObjColor {
638 match typ {
639 Some(_) => ObjColor::Black,
640 None => ObjColor::White,
641 }
642}