use super::{code::KtCode, slot::KtPropertyValue, types::KtType};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum KtVis {
#[default]
Default,
Public,
Internal,
Private,
}
impl KtVis {
pub(crate) fn prefix(self) -> &'static str {
match self {
KtVis::Default => "",
KtVis::Public => "public ",
KtVis::Internal => "internal ",
KtVis::Private => "private ",
}
}
}
#[derive(Clone, Debug)]
pub struct KtFile {
pub package: String,
pub decls: Vec<KtDecl>,
pub extra_imports: Vec<String>,
pub banner: Option<String>,
}
impl KtFile {
pub fn new(package: impl Into<String>) -> Self {
Self {
package: package.into(),
decls: Vec::new(),
extra_imports: Vec::new(),
banner: None,
}
}
pub fn banner(mut self, text: impl Into<String>) -> Self {
self.banner = Some(text.into());
self
}
pub fn decl(mut self, d: impl Into<KtDecl>) -> Self {
self.decls.push(d.into());
self
}
pub fn import(mut self, fqn: impl Into<String>) -> Self {
self.extra_imports.push(fqn.into());
self
}
pub fn imports(mut self, fqns: impl IntoIterator<Item = String>) -> Self {
self.extra_imports.extend(fqns);
self
}
}
#[derive(Clone, Debug)]
pub enum KtDecl {
Class(KtClass),
Fun(KtFun),
FunInterface(KtFunInterface),
Property(KtProperty),
TypeAlias {
vis: KtVis,
name: String,
target: KtType,
},
Raw {
name: String,
code: KtCode,
},
}
impl KtDecl {
pub fn name(&self) -> &str {
match self {
KtDecl::Class(c) => &c.name,
KtDecl::Fun(f) => &f.name,
KtDecl::FunInterface(i) => &i.name,
KtDecl::Property(p) => &p.name,
KtDecl::TypeAlias { name, .. } => name,
KtDecl::Raw { name, .. } => name,
}
}
}
impl From<KtClass> for KtDecl {
fn from(c: KtClass) -> Self {
KtDecl::Class(c)
}
}
impl From<KtFunInterface> for KtDecl {
fn from(i: KtFunInterface) -> Self {
KtDecl::FunInterface(i)
}
}
impl From<KtFun> for KtDecl {
fn from(f: KtFun) -> Self {
KtDecl::Fun(f)
}
}
impl From<KtProperty> for KtDecl {
fn from(p: KtProperty) -> Self {
KtDecl::Property(p)
}
}
#[derive(Clone, Debug)]
pub struct KtFunSig {
pub name: String,
pub vis: KtVis,
pub annotations: Vec<String>,
pub kdoc: Option<String>,
pub generics: Vec<String>,
pub receiver: Option<KtType>,
pub params: Vec<KtParam>,
pub ret: Option<KtType>,
}
impl KtFunSig {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
vis: KtVis::Default,
annotations: Vec::new(),
kdoc: None,
generics: Vec::new(),
receiver: None,
params: Vec::new(),
ret: None,
}
}
pub fn vis(mut self, v: KtVis) -> Self {
self.vis = v;
self
}
pub fn receiver(mut self, ty: KtType) -> Self {
self.receiver = Some(ty);
self
}
pub fn annotation(mut self, a: impl Into<String>) -> Self {
self.annotations.push(a.into());
self
}
pub fn kdoc(mut self, d: impl Into<String>) -> Self {
self.kdoc = Some(d.into());
self
}
pub fn generic(mut self, g: impl Into<String>) -> Self {
self.generics.push(g.into());
self
}
pub fn param(mut self, p: KtParam) -> Self {
self.params.push(p);
self
}
pub fn returns(mut self, ty: KtType) -> Self {
self.ret = Some(ty);
self
}
}
impl From<KtFunSig> for KtFun {
fn from(s: KtFunSig) -> Self {
KtFun {
name: s.name,
vis: s.vis,
modifiers: Vec::new(),
annotations: s.annotations,
kdoc: s.kdoc,
generics: s.generics,
receiver: s.receiver,
params: s.params,
ret: s.ret,
body: KtBody::None,
}
}
}
impl From<KtFunSig> for KtDecl {
fn from(s: KtFunSig) -> Self {
KtDecl::Fun(s.into())
}
}
#[derive(Clone, Debug)]
pub struct KtFunInterface {
pub vis: KtVis,
pub name: String,
pub type_params: Vec<String>,
pub kdoc: Option<String>,
pub method: KtFunSig,
}
impl KtFunInterface {
pub fn new(name: impl Into<String>, method: KtFunSig) -> Self {
Self {
vis: KtVis::Default,
name: name.into(),
type_params: Vec::new(),
kdoc: None,
method,
}
}
pub fn vis(mut self, v: KtVis) -> Self {
self.vis = v;
self
}
pub fn type_param(mut self, p: impl Into<String>) -> Self {
self.type_params.push(p.into());
self
}
pub fn kdoc(mut self, d: impl Into<String>) -> Self {
self.kdoc = Some(d.into());
self
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum KtClassModifier {
Abstract,
Open,
Sealed,
}
#[derive(Clone, Debug)]
pub enum KtClassKind {
Class {
modifier: Option<KtClassModifier>,
ctor: Vec<KtCtorParam>,
},
Data {
ctor: Vec<KtCtorParam>,
},
Value {
field: Box<KtCtorParam>,
},
Enum {
ctor: Vec<KtCtorParam>,
entries: Vec<KtEnumEntry>,
},
Object,
Interface,
SealedInterface,
DataObject,
}
impl KtClassKind {
pub fn ctor_params(&self) -> &[KtCtorParam] {
match self {
KtClassKind::Class { ctor, .. }
| KtClassKind::Data { ctor }
| KtClassKind::Enum { ctor, .. } => ctor,
KtClassKind::Value { field } => std::slice::from_ref(field),
KtClassKind::Object
| KtClassKind::Interface
| KtClassKind::SealedInterface
| KtClassKind::DataObject => &[],
}
}
pub fn entries(&self) -> &[KtEnumEntry] {
match self {
KtClassKind::Enum { entries, .. } => entries,
_ => &[],
}
}
pub(crate) fn keyword(&self) -> &'static str {
match self {
KtClassKind::Class { modifier: None, .. } => "class",
KtClassKind::Class {
modifier: Some(KtClassModifier::Abstract),
..
} => "abstract class",
KtClassKind::Class {
modifier: Some(KtClassModifier::Open),
..
} => "open class",
KtClassKind::Class {
modifier: Some(KtClassModifier::Sealed),
..
} => "sealed class",
KtClassKind::Data { .. } => "data class",
KtClassKind::Enum { .. } => "enum class",
KtClassKind::Value { .. } => "value class",
KtClassKind::Object => "object",
KtClassKind::Interface => "interface",
KtClassKind::SealedInterface => "sealed interface",
KtClassKind::DataObject => "data object",
}
}
}
#[derive(Clone, Debug)]
pub struct KtEnumEntry {
pub name: String,
pub args: Option<KtCode>,
}
impl KtEnumEntry {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
args: None,
}
}
pub fn with_args(name: impl Into<String>, args: impl Into<String>) -> Self {
Self {
name: name.into(),
args: Some(KtCode::new().line(args.into())),
}
}
}
#[derive(Clone, Debug)]
pub struct KtCtorParam {
pub name: String,
pub ty: KtType,
pub prop: Option<bool>,
pub overrides: bool,
pub vis: KtVis,
pub default: Option<KtCode>,
pub annotations: Vec<String>,
}
impl KtCtorParam {
pub fn new(name: impl Into<String>, ty: KtType) -> Self {
Self {
name: name.into(),
ty,
prop: None,
overrides: false,
vis: KtVis::Default,
default: None,
annotations: Vec::new(),
}
}
pub fn val(mut self) -> Self {
self.prop = Some(false);
self
}
pub fn overrides(mut self) -> Self {
self.overrides = true;
self
}
pub fn var(mut self) -> Self {
self.prop = Some(true);
self
}
pub fn vis(mut self, v: KtVis) -> Self {
self.vis = v;
self
}
pub fn default(mut self, d: impl Into<String>) -> Self {
self.default = Some(KtCode::new().line(d.into()));
self
}
pub fn annotation(mut self, a: impl Into<String>) -> Self {
self.annotations.push(a.into());
self
}
}
#[derive(Clone, Debug)]
pub struct KtSuperclass {
pub ty: KtType,
pub args: Option<KtCode>,
}
#[derive(Clone, Debug, Default)]
pub struct KtSupertypes {
pub superclass: Option<KtSuperclass>,
pub interfaces: Vec<KtType>,
}
impl KtSupertypes {
pub fn iter(&self) -> impl Iterator<Item = (&KtType, Option<&KtCode>)> {
self.superclass
.iter()
.map(|s| (&s.ty, s.args.as_ref()))
.chain(self.interfaces.iter().map(|t| (t, None)))
}
pub fn is_empty(&self) -> bool {
self.superclass.is_none() && self.interfaces.is_empty()
}
fn set_superclass(&mut self, ty: KtType, args: Option<&str>, what: &str) {
if let Some(existing) = &self.superclass {
panic!(
"{what} already extends `{}`; Kotlin allows only one superclass \
(use `implements` for interfaces)",
existing.ty
);
}
self.superclass = Some(KtSuperclass {
ty,
args: args.map(|s| KtCode::new().line(s.to_string())),
});
}
}
#[derive(Clone, Debug, Default)]
pub struct KtCompanion {
pub name: Option<String>,
pub vis: KtVis,
pub kdoc: Option<String>,
pub annotations: Vec<String>,
pub supertypes: KtSupertypes,
pub members: Vec<KtDecl>,
}
impl KtCompanion {
pub fn new() -> Self {
Self::default()
}
pub fn named(name: impl Into<String>) -> Self {
let name = name.into();
assert!(
!name.is_empty(),
"a companion object's name cannot be empty — use `KtCompanion::new()` \
for the anonymous form"
);
Self {
name: Some(name),
..Self::default()
}
}
pub fn vis(mut self, v: KtVis) -> Self {
self.vis = v;
self
}
pub fn kdoc(mut self, d: impl Into<String>) -> Self {
self.kdoc = Some(d.into());
self
}
pub fn annotation(mut self, a: impl Into<String>) -> Self {
self.annotations.push(a.into());
self
}
pub fn extends(mut self, ty: KtType, args: Option<&str>) -> Self {
self.supertypes.set_superclass(ty, args, "companion object");
self
}
pub fn implements(mut self, ty: KtType) -> Self {
self.supertypes.interfaces.push(ty);
self
}
pub fn member(mut self, d: impl Into<KtDecl>) -> Self {
self.members.push(d.into());
self
}
}
fn describe_prop(prop: Option<bool>) -> &'static str {
match prop {
None => "a plain constructor parameter",
Some(false) => "a `val`",
Some(true) => "a `var`",
}
}
fn assert_data_property(p: &KtCtorParam) {
assert!(
p.prop.is_some(),
"every `data class` constructor parameter must be a property, but `{}` is {} — \
call `.val()` or `.var()` on it",
p.name,
describe_prop(p.prop),
);
}
#[derive(Clone, Debug)]
pub struct KtClass {
pub kind: KtClassKind,
pub name: String,
pub vis: KtVis,
pub annotations: Vec<String>,
pub kdoc: Option<String>,
pub supertypes: KtSupertypes,
pub members: Vec<KtDecl>,
pub companion: Option<Box<KtCompanion>>,
}
impl KtClass {
pub fn new(kind: KtClassKind, name: impl Into<String>) -> Self {
Self {
kind,
name: name.into(),
vis: KtVis::Default,
annotations: Vec::new(),
kdoc: None,
supertypes: KtSupertypes::default(),
members: Vec::new(),
companion: None,
}
}
pub fn class_(name: impl Into<String>) -> Self {
Self::new(
KtClassKind::Class {
modifier: None,
ctor: Vec::new(),
},
name,
)
}
pub fn class_with(modifier: KtClassModifier, name: impl Into<String>) -> Self {
Self::new(
KtClassKind::Class {
modifier: Some(modifier),
ctor: Vec::new(),
},
name,
)
}
pub fn data(name: impl Into<String>, first: KtCtorParam) -> Self {
assert_data_property(&first);
Self::new(KtClassKind::Data { ctor: vec![first] }, name)
}
pub fn value(name: impl Into<String>, field: KtCtorParam) -> Self {
assert!(
field.prop == Some(false),
"`value class` wraps a single read-only property, but `{}` is {} — \
call `.val()` on it",
field.name,
describe_prop(field.prop),
);
Self::new(
KtClassKind::Value {
field: Box::new(field),
},
name,
)
}
pub fn enum_(name: impl Into<String>) -> Self {
Self::new(
KtClassKind::Enum {
ctor: Vec::new(),
entries: Vec::new(),
},
name,
)
}
pub fn object_(name: impl Into<String>) -> Self {
Self::new(KtClassKind::Object, name)
}
pub fn data_object(name: impl Into<String>) -> Self {
Self::new(KtClassKind::DataObject, name)
}
pub fn interface_(name: impl Into<String>) -> Self {
Self::new(KtClassKind::Interface, name)
}
pub fn sealed_interface(name: impl Into<String>) -> Self {
Self::new(KtClassKind::SealedInterface, name)
}
pub fn ctor_params(&self) -> &[KtCtorParam] {
self.kind.ctor_params()
}
pub fn vis(mut self, v: KtVis) -> Self {
self.vis = v;
self
}
pub fn annotation(mut self, a: impl Into<String>) -> Self {
self.annotations.push(a.into());
self
}
pub fn kdoc(mut self, d: impl Into<String>) -> Self {
self.kdoc = Some(d.into());
self
}
pub fn ctor_param(mut self, p: KtCtorParam) -> Self {
if matches!(self.kind, KtClassKind::Data { .. }) {
assert_data_property(&p);
}
match &mut self.kind {
KtClassKind::Class { ctor, .. }
| KtClassKind::Data { ctor }
| KtClassKind::Enum { ctor, .. } => ctor.push(p),
other => panic!(
"`{}` has no primary constructor to add parameter `{}` to",
other.keyword(),
p.name
),
}
self
}
pub fn entry(mut self, e: KtEnumEntry) -> Self {
match &mut self.kind {
KtClassKind::Enum { entries, .. } => entries.push(e),
other => panic!(
"`{}` is not an enum class; cannot add entry `{}`",
other.keyword(),
e.name
),
}
self
}
pub fn extends(mut self, ty: KtType, args: Option<&str>) -> Self {
let what = format!("class `{}`", self.name);
self.supertypes.set_superclass(ty, args, &what);
self
}
pub fn implements(mut self, ty: KtType) -> Self {
self.supertypes.interfaces.push(ty);
self
}
pub fn member(mut self, d: impl Into<KtDecl>) -> Self {
self.members.push(d.into());
self
}
pub fn companion(mut self, c: KtCompanion) -> Self {
self.companion = Some(Box::new(c));
self
}
}
#[derive(Clone, Debug, Default)]
pub enum KtBody {
#[default]
None,
Expr(KtCode),
Block(KtCode),
External,
}
#[derive(Clone, Debug)]
pub struct KtFun {
pub name: String,
pub vis: KtVis,
pub modifiers: Vec<String>,
pub annotations: Vec<String>,
pub kdoc: Option<String>,
pub generics: Vec<String>,
pub receiver: Option<KtType>,
pub params: Vec<KtParam>,
pub ret: Option<KtType>,
pub body: KtBody,
}
impl KtFun {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
vis: KtVis::Default,
modifiers: Vec::new(),
annotations: Vec::new(),
kdoc: None,
generics: Vec::new(),
receiver: None,
params: Vec::new(),
ret: None,
body: KtBody::None,
}
}
pub fn vis(mut self, v: KtVis) -> Self {
self.vis = v;
self
}
pub fn receiver(mut self, ty: KtType) -> Self {
self.receiver = Some(ty);
self
}
pub fn modifier(mut self, m: impl Into<String>) -> Self {
let m = m.into();
assert!(
!m.split_whitespace().any(|w| w == "external"),
"`external` is not a modifier here — use `KtFun::external()`, which \
also rules out giving the function a body"
);
self.modifiers.push(m);
self
}
pub fn annotation(mut self, a: impl Into<String>) -> Self {
self.annotations.push(a.into());
self
}
pub fn kdoc(mut self, d: impl Into<String>) -> Self {
self.kdoc = Some(d.into());
self
}
pub fn generic(mut self, g: impl Into<String>) -> Self {
self.generics.push(g.into());
self
}
pub fn param(mut self, p: KtParam) -> Self {
self.params.push(p);
self
}
pub fn returns(mut self, ty: KtType) -> Self {
self.ret = Some(ty);
self
}
pub fn body(mut self, c: KtCode) -> Self {
self.body = KtBody::Block(c);
self
}
pub fn expr_body(mut self, c: KtCode) -> Self {
self.body = KtBody::Expr(c);
self
}
pub fn external(mut self) -> Self {
self.body = KtBody::External;
self
}
pub fn signature(&self) -> KtFunSig {
KtFunSig {
name: self.name.clone(),
vis: self.vis,
annotations: self.annotations.clone(),
kdoc: self.kdoc.clone(),
generics: self.generics.clone(),
receiver: self.receiver.clone(),
params: self.params.clone(),
ret: self.ret.clone(),
}
}
}
#[derive(Clone, Debug)]
pub struct KtParam {
pub name: String,
pub ty: KtType,
pub default: Option<KtCode>,
}
impl KtParam {
pub fn new(name: impl Into<String>, ty: KtType) -> Self {
Self {
name: name.into(),
ty,
default: None,
}
}
pub fn default(mut self, d: impl Into<String>) -> Self {
self.default = Some(KtCode::new().line(d.into()));
self
}
}
#[derive(Clone, Debug)]
pub struct KtProperty {
pub name: String,
pub ty: Option<KtType>,
pub value: KtPropertyValue,
pub mutable: bool,
pub vis: KtVis,
pub annotations: Vec<String>,
pub modifiers: Vec<String>,
pub kdoc: Option<String>,
pub accessors: Option<KtCode>,
}
impl KtProperty {
pub fn val(name: impl Into<String>) -> Self {
Self {
name: name.into(),
ty: None,
value: KtPropertyValue::None,
mutable: false,
vis: KtVis::Default,
annotations: Vec::new(),
modifiers: Vec::new(),
kdoc: None,
accessors: None,
}
}
pub fn var(name: impl Into<String>) -> Self {
Self {
mutable: true,
..Self::val(name)
}
}
pub fn ty(mut self, t: KtType) -> Self {
self.ty = Some(t);
self
}
pub fn initializer(mut self, i: impl Into<String>) -> Self {
self.value = KtPropertyValue::Initializer(KtCode::new().line(i.into()));
self
}
pub fn delegate(mut self, d: impl Into<String>) -> Self {
self.value = KtPropertyValue::Delegate(KtCode::new().line(d.into()));
self
}
pub fn vis(mut self, v: KtVis) -> Self {
self.vis = v;
self
}
pub fn annotation(mut self, a: impl Into<String>) -> Self {
self.annotations.push(a.into());
self
}
pub fn modifier(mut self, m: impl Into<String>) -> Self {
self.modifiers.push(m.into());
self
}
pub fn kdoc(mut self, d: impl Into<String>) -> Self {
self.kdoc = Some(d.into());
self
}
pub fn accessors(mut self, c: KtCode) -> Self {
self.accessors = Some(c);
self
}
}