#![allow(unused_macros)]
#![allow(dead_code)]
use super::check::DeclInfo;
use super::constant;
use super::obj::LangObj;
use super::package::Package;
use super::scope::Scope;
use super::typ::*;
use super::universe::Universe;
use goscript_parser::position;
use std::borrow::Cow;
use slotmap::{new_key_type, DenseSlotMap};
const DEFAULT_CAPACITY: usize = 16;
macro_rules! null_key {
() => {
slotmap::Key::null()
};
}
macro_rules! new_objects {
() => {
DenseSlotMap::with_capacity_and_key(DEFAULT_CAPACITY)
};
}
new_key_type! { pub struct ObjKey; }
new_key_type! { pub struct TypeKey; }
new_key_type! { pub struct PackageKey; }
new_key_type! { pub struct DeclInfoKey; }
new_key_type! { pub struct ScopeKey; }
pub type LangObjs = DenseSlotMap<ObjKey, LangObj>;
pub type Types = DenseSlotMap<TypeKey, Type>;
pub type Packages = DenseSlotMap<PackageKey, Package>;
pub type Decls = DenseSlotMap<DeclInfoKey, DeclInfo>;
pub type Scopes = DenseSlotMap<ScopeKey, Scope>;
pub struct TCObjects {
pub lobjs: LangObjs,
pub types: Types,
pub pkgs: Packages,
pub decls: Decls,
pub scopes: Scopes,
pub universe: Option<Universe>,
pub fmt_qualifier: Box<dyn Fn(&Package) -> Cow<str>>,
}
fn default_fmt_qualifier(p: &Package) -> Cow<str> {
p.path().into()
}
impl TCObjects {
pub fn new() -> TCObjects {
let fmtq = Box::new(default_fmt_qualifier);
let mut objs = TCObjects {
lobjs: new_objects!(),
types: new_objects!(),
pkgs: new_objects!(),
decls: new_objects!(),
scopes: new_objects!(),
universe: None,
fmt_qualifier: fmtq,
};
objs.universe = Some(Universe::new(&mut objs));
objs
}
pub fn universe(&self) -> &Universe {
self.universe.as_ref().unwrap()
}
pub fn new_scope(
&mut self,
parent: Option<ScopeKey>,
pos: position::Pos,
end: position::Pos,
comment: String,
is_func: bool,
) -> ScopeKey {
let scope = Scope::new(parent, pos, end, comment, is_func);
let skey = self.scopes.insert(scope);
if let Some(s) = parent {
if s != *self.universe().scope() {
self.scopes[s].add_child(skey);
}
}
skey
}
pub fn new_package(&mut self, path: String) -> PackageKey {
let skey = self.new_scope(
Some(*self.universe().scope()),
0,
0,
format!("package {}", path),
false,
);
let pkg = Package::new(path, None, skey);
self.pkgs.insert(pkg)
}
pub fn new_pkg_name(
&mut self,
pos: position::Pos,
pkg: Option<PackageKey>,
name: String,
imported: PackageKey,
) -> ObjKey {
let lobj = LangObj::new_pkg_name(pos, pkg, name, imported, self.universe());
self.lobjs.insert(lobj)
}
pub fn new_const(
&mut self,
pos: position::Pos,
pkg: Option<PackageKey>,
name: String,
typ: Option<TypeKey>,
val: constant::Value,
) -> ObjKey {
let lobj = LangObj::new_const(pos, pkg, name, typ, val);
self.lobjs.insert(lobj)
}
pub fn new_type_name(
&mut self,
pos: position::Pos,
pkg: Option<PackageKey>,
name: String,
typ: Option<TypeKey>,
) -> ObjKey {
let lobj = LangObj::new_type_name(pos, pkg, name, typ);
self.lobjs.insert(lobj)
}
pub fn new_var(
&mut self,
pos: position::Pos,
pkg: Option<PackageKey>,
name: String,
typ: Option<TypeKey>,
) -> ObjKey {
let lobj = LangObj::new_var(pos, pkg, name, typ);
self.lobjs.insert(lobj)
}
pub fn new_param_var(
&mut self,
pos: position::Pos,
pkg: Option<PackageKey>,
name: String,
typ: Option<TypeKey>,
) -> ObjKey {
let lobj = LangObj::new_param_var(pos, pkg, name, typ);
self.lobjs.insert(lobj)
}
pub fn new_field(
&mut self,
pos: position::Pos,
pkg: Option<PackageKey>,
name: String,
typ: Option<TypeKey>,
embedded: bool,
) -> ObjKey {
let lobj = LangObj::new_field(pos, pkg, name, typ, embedded);
self.lobjs.insert(lobj)
}
pub fn new_func(
&mut self,
pos: position::Pos,
pkg: Option<PackageKey>,
name: String,
typ: Option<TypeKey>,
) -> ObjKey {
let lobj = LangObj::new_func(pos, pkg, name, typ);
self.lobjs.insert(lobj)
}
pub fn new_label(
&mut self,
pos: position::Pos,
pkg: Option<PackageKey>,
name: String,
) -> ObjKey {
let lobj = LangObj::new_label(pos, pkg, name, self.universe());
self.lobjs.insert(lobj)
}
pub fn new_t_basic(&mut self, typ: BasicType, info: BasicInfo, name: &'static str) -> TypeKey {
self.types
.insert(Type::Basic(BasicDetail::new(typ, info, name)))
}
pub fn new_t_array(&mut self, elem: TypeKey, len: Option<u64>) -> TypeKey {
self.types.insert(Type::Array(ArrayDetail::new(elem, len)))
}
pub fn new_t_slice(&mut self, elem: TypeKey) -> TypeKey {
self.types.insert(Type::Slice(SliceDetail::new(elem)))
}
pub fn new_t_struct(
&mut self,
fields: Vec<ObjKey>,
tags: Option<Vec<Option<String>>>,
) -> TypeKey {
self.types
.insert(Type::Struct(StructDetail::new(fields, tags, self)))
}
pub fn new_t_pointer(&mut self, base: TypeKey) -> TypeKey {
self.types.insert(Type::Pointer(PointerDetail::new(base)))
}
pub fn new_t_tuple(&mut self, vars: Vec<ObjKey>) -> TypeKey {
self.types.insert(Type::Tuple(TupleDetail::new(vars)))
}
pub fn new_t_signature(
&mut self,
scope: Option<ScopeKey>,
recv: Option<ObjKey>,
params: TypeKey,
results: TypeKey,
variadic: bool,
) -> TypeKey {
self.types.insert(Type::Signature(SignatureDetail::new(
scope, recv, params, results, variadic, self,
)))
}
pub fn new_t_interface(&mut self, methods: Vec<ObjKey>, embeddeds: Vec<TypeKey>) -> TypeKey {
let iface = Type::Interface(InterfaceDetail::new(methods, embeddeds, self));
self.types.insert(iface)
}
pub fn new_t_empty_interface(&mut self) -> TypeKey {
self.types
.insert(Type::Interface(InterfaceDetail::new_empty()))
}
pub fn new_t_map(&mut self, key: TypeKey, elem: TypeKey) -> TypeKey {
self.types.insert(Type::Map(MapDetail::new(key, elem)))
}
pub fn new_t_chan(&mut self, dir: ChanDir, elem: TypeKey) -> TypeKey {
self.types.insert(Type::Chan(ChanDetail::new(dir, elem)))
}
pub fn new_t_named(
&mut self,
obj: Option<ObjKey>,
underlying: Option<TypeKey>,
methods: Vec<ObjKey>,
) -> TypeKey {
self.types.insert(Type::Named(NamedDetail::new(
obj, underlying, methods, self,
)))
}
}