Skip to content

Commit

Permalink
WIP: support inline types
Browse files Browse the repository at this point in the history
  • Loading branch information
yorickpeterse committed Nov 9, 2024
1 parent 35c338c commit b7778a5
Show file tree
Hide file tree
Showing 28 changed files with 1,261 additions and 472 deletions.
1 change: 1 addition & 0 deletions ast/src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,7 @@ pub enum ClassKind {
#[derive(Debug, PartialEq, Eq)]
pub struct DefineClass {
pub public: bool,
pub inline: bool,
pub kind: ClassKind,
pub name: Constant,
pub type_parameters: Option<TypeParameters>,
Expand Down
49 changes: 49 additions & 0 deletions ast/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,12 @@ impl Parser {
start: Token,
) -> Result<TopLevelExpression, ParseError> {
let public = self.next_is_public();
let inline = if self.peek().kind == TokenKind::Inline {
self.next();
true
} else {
false
};
let kind = match self.peek().kind {
TokenKind::Async => {
self.next();
Expand Down Expand Up @@ -1064,6 +1070,7 @@ impl Parser {

Ok(TopLevelExpression::DefineClass(Box::new(DefineClass {
public,
inline,
kind,
name,
type_parameters,
Expand Down Expand Up @@ -4604,6 +4611,7 @@ mod tests {
top(parse("class A {}")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand All @@ -4623,6 +4631,7 @@ mod tests {
top(parse("class pub A {}")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: true,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand All @@ -4645,6 +4654,7 @@ mod tests {
top(parse("class extern A {}")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand All @@ -4661,12 +4671,36 @@ mod tests {
);
}

#[test]
fn test_inline_class() {
assert_eq!(
top(parse("class inline A {}")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: true,
name: Constant {
source: None,
name: "A".to_string(),
location: cols(14, 14)
},
kind: ClassKind::Regular,
type_parameters: None,
body: ClassExpressions {
values: Vec::new(),
location: cols(16, 17)
},
location: cols(1, 17)
}))
);
}

#[test]
fn test_async_class() {
assert_eq!(
top(parse("class async A {}")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand All @@ -4689,6 +4723,7 @@ mod tests {
top(parse("class A { fn async foo {} }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -4727,6 +4762,7 @@ mod tests {
top(parse("class A { fn async mut foo {} }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -4768,6 +4804,7 @@ mod tests {
top(parse("class A[B: X, C] {}")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -4820,6 +4857,7 @@ mod tests {
top(parse("class A[B: a.X] {}")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -4867,6 +4905,7 @@ mod tests {
top(parse("class A { fn foo {} }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -4905,6 +4944,7 @@ mod tests {
top(parse("class A { fn pub foo {} }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -4946,6 +4986,7 @@ mod tests {
top(parse("class A { fn move foo {} }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -4987,6 +5028,7 @@ mod tests {
top(parse("class A { fn inline foo {} }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -5028,6 +5070,7 @@ mod tests {
top(parse("class A { fn mut foo {} }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -5069,6 +5112,7 @@ mod tests {
top(parse("class A { fn static foo {} }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -5110,6 +5154,7 @@ mod tests {
top(parse("class A { let @foo: A }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -5147,6 +5192,7 @@ mod tests {
top(parse("class A { let pub @foo: A }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
name: Constant {
source: None,
name: "A".to_string(),
Expand Down Expand Up @@ -6166,6 +6212,7 @@ mod tests {
top(parse("class builtin A {}")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
kind: ClassKind::Builtin,
name: Constant {
source: None,
Expand Down Expand Up @@ -9600,6 +9647,7 @@ mod tests {
top(parse("class enum Option[T] { case Some(T) case None }")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
kind: ClassKind::Enum,
name: Constant {
source: None,
Expand Down Expand Up @@ -9699,6 +9747,7 @@ mod tests {
top(parse_with_comments("class A {\n# foo\n}")),
TopLevelExpression::DefineClass(Box::new(DefineClass {
public: false,
inline: false,
kind: ClassKind::Regular,
name: Constant {
source: None,
Expand Down
18 changes: 18 additions & 0 deletions compiler/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,24 @@ impl Diagnostics {
);
}

pub(crate) fn not_a_stack_type(
&mut self,
name: &str,
file: PathBuf,
location: Location,
) {
self.error(
DiagnosticId::InvalidType,
format!(
"an 'inline' or 'extern' type is expected, \
but '{}' is a heap type",
name
),
file,
location,
);
}

pub(crate) fn fields_not_allowed(
&mut self,
name: &str,
Expand Down
22 changes: 12 additions & 10 deletions compiler/src/docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use location::Location;
use std::fs::{read_to_string, write};
use std::mem::take;
use std::path::Path;
use types::format::format_type;
use types::format::{format_type, type_parameter_capabilities};
use types::{
ClassId, ClassKind, Database, MethodId, ModuleId, TraitId, TypeBounds,
};
Expand All @@ -30,8 +30,7 @@ fn class_kind(kind: ClassKind) -> i64 {
ClassKind::Enum => 1,
ClassKind::Async => 2,
ClassKind::Extern => 3,
ClassKind::ValueType => 4,
ClassKind::Atomic => 5,
ClassKind::Atomic => 4,
_ => 0,
}
}
Expand All @@ -44,19 +43,19 @@ fn format_bounds(db: &Database, bounds: &TypeBounds) -> String {
pairs.sort_by(|(a, _), (b, _)| a.cmp(b));
buf.push_str("\nif\n");

for (idx, (param, req)) in pairs.into_iter().enumerate() {
let is_mut = req.is_mutable(db);
for (idx, (param, &req)) in pairs.into_iter().enumerate() {
let reqs = req.requirements(db);
let capa = type_parameter_capabilities(db, req);

buf.push_str(&format!(
"{} {}: {}",
if idx > 0 { ",\n" } else { "" },
param,
if is_mut { "mut" } else { "" }
capa.unwrap_or("")
));

if !reqs.is_empty() {
if is_mut {
if capa.is_some() {
buf.push_str(" + ");
}

Expand Down Expand Up @@ -391,15 +390,18 @@ impl<'a> GenerateDocumentation<'a> {

let name = id.name(self.db()).clone();
let docs = id.documentation(self.db()).clone();
let is_stack = id.is_stack_allocated(self.db());
let mut obj = Object::new();
let typ = format!(
"class{}{} {}",
if public { " pub" } else { "" },
match kind {
ClassKind::Enum if is_stack => " inline enum",
ClassKind::Enum => " enum",
ClassKind::Async => " async",
ClassKind::Extern => " extern",
_ if id.is_builtin() => " builtin",
_ if is_stack => " inline",
_ => "",
},
format_type(self.db(), id)
Expand Down Expand Up @@ -574,9 +576,9 @@ impl<'a> GenerateDocumentation<'a> {
let mut obj = Object::new();
let name = con.name(self.db()).clone();
let args: Vec<String> = con
.members(self.db())
.into_iter()
.map(|t| format_type(self.db(), t))
.arguments(self.db())
.iter()
.map(|&t| format_type(self.db(), t))
.collect();

let typ = format!("{}({})", name, args.join(", "));
Expand Down
4 changes: 4 additions & 0 deletions compiler/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,10 @@ impl Document {
header.push(Node::text("pub "));
}

if node.inline {
header.push(Node::text("inline "));
}

match node.kind {
nodes::ClassKind::Async => header.push(Node::text("async ")),
nodes::ClassKind::Builtin => header.push(Node::text("builtin ")),
Expand Down
Loading

0 comments on commit b7778a5

Please sign in to comment.