Implement immediate records

This commit is contained in:
Greg Shuflin 2021-10-31 02:30:38 -07:00
parent 663e99df23
commit 803a836887
5 changed files with 64 additions and 37 deletions

View File

@ -135,7 +135,10 @@ pub struct Signature {
//TODO I can probably get rid of TypeBody //TODO I can probably get rid of TypeBody
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct TypeBody(pub Vec<Variant>); pub enum TypeBody {
Variants(Vec<Variant>),
ImmediateRecord(ItemId, Vec<(Rc<String>, TypeIdentifier)>),
}
#[derive(Debug, Derivative, Clone)] #[derive(Debug, Derivative, Clone)]
#[derivative(PartialEq)] #[derivative(PartialEq)]

View File

@ -26,7 +26,8 @@
//! type_declaration := "type" type_declaration_body //! type_declaration := "type" type_declaration_body
//! type_declaration_body := "alias" type_alias | "mut"? type_singleton_name "=" type_body //! type_declaration_body := "alias" type_alias | "mut"? type_singleton_name "=" type_body
//! type_alias := IDENTIFIER "=" type_name //! type_alias := IDENTIFIER "=" type_name
//! type_body := variant_specifier ("|" variant_specifier)* //! type_body := immediate_record | (variant_specifier ("|" variant_specifier)*)
//! immediate_record := "{" typed_identifier_list "}"
//! variant_specifier := IDENTIFIER | IDENTIFIER "{" typed_identifier_list "}" | IDENTIFIER "(" type_name* ")" //! variant_specifier := IDENTIFIER | IDENTIFIER "{" typed_identifier_list "}" | IDENTIFIER "(" type_name* ")"
//! typed_identifier_list := typed_identifier* //! typed_identifier_list := typed_identifier*
//! typed_identifier := IDENTIFIER type_anno //! typed_identifier := IDENTIFIER type_anno
@ -454,12 +455,17 @@ impl Parser {
#[recursive_descent_method] #[recursive_descent_method]
fn type_body(&mut self) -> ParseResult<TypeBody> { fn type_body(&mut self) -> ParseResult<TypeBody> {
let mut variants = vec![self.variant_specifier()?]; Ok(if let LCurlyBrace = self.token_handler.peek_kind() {
while let Pipe = self.token_handler.peek_kind() { let typed_identifier_list = delimited!(self, LCurlyBrace, typed_identifier, Comma, RCurlyBrace);
self.token_handler.next(); TypeBody::ImmediateRecord(self.id_store.fresh(), typed_identifier_list)
variants.push(self.variant_specifier()?); } else {
} let mut variants = vec![self.variant_specifier()?];
Ok(TypeBody(variants)) while let Pipe = self.token_handler.peek_kind() {
self.token_handler.next();
variants.push(self.variant_specifier()?);
}
TypeBody::Variants(variants)
})
} }
#[recursive_descent_method] #[recursive_descent_method]
@ -471,7 +477,6 @@ impl Parser {
VariantKind::TupleStruct(tuple_members) VariantKind::TupleStruct(tuple_members)
} }
LCurlyBrace => { LCurlyBrace => {
println!("ARAH");
let typed_identifier_list = let typed_identifier_list =
delimited!(self, LCurlyBrace, typed_identifier, Comma, RCurlyBrace); delimited!(self, LCurlyBrace, typed_identifier, Comma, RCurlyBrace);
VariantKind::Record(typed_identifier_list) VariantKind::Record(typed_identifier_list)
@ -690,7 +695,9 @@ impl Parser {
fn prefix_expr(&mut self) -> ParseResult<Expression> { fn prefix_expr(&mut self) -> ParseResult<Expression> {
loop { loop {
match self.token_handler.peek_kind() { match self.token_handler.peek_kind() {
Semicolon | Newline => { self.token_handler.next(); }, Semicolon | Newline => {
self.token_handler.next();
}
_ => break, _ => break,
} }
} }

View File

@ -572,7 +572,7 @@ fn type_declarations() {
decl(TypeDecl { decl(TypeDecl {
name: TypeSingletonName { name: rc("Alpha"), params: vec![] }, name: TypeSingletonName { name: rc("Alpha"), params: vec![] },
mutable: false, mutable: false,
body: TypeBody(vec![ body: TypeBody::Variants(vec![
Variant { Variant {
id: Default::default(), id: Default::default(),
name: rc("Alpha"), name: rc("Alpha"),
@ -588,7 +588,7 @@ fn type_declarations() {
decl(TypeDecl { decl(TypeDecl {
name: TypeSingletonName { name: rc("Kuah"), params: vec![] }, name: TypeSingletonName { name: rc("Kuah"), params: vec![] },
mutable: true, mutable: true,
body: TypeBody(vec![Variant { body: TypeBody::Variants(vec![Variant {
id: Default::default(), id: Default::default(),
name: rc("Kuah"), name: rc("Kuah"),
kind: VariantKind::UnitStruct kind: VariantKind::UnitStruct
@ -596,26 +596,36 @@ fn type_declarations() {
}) })
); );
//TODO support this assert_ast! {
let specs = ["type Alpha = Alpha { a: Int, b: Int }" /* "type Alpha = { a: Int, b: Int }"*/]; "type Alpha = Alpha { a: Int, b: Int }",
for spec in specs { vec![decl(TypeDecl {
assert_ast! { name: TypeSingletonName { name: rc("Alpha"), params: vec![] },
spec, vec![decl(TypeDecl { mutable: false,
name: TypeSingletonName { name: rc("Alpha"), params: vec![] }, body: TypeBody::Variants(vec![
mutable: false, Variant {
body: TypeBody(vec![ id: Default::default(),
Variant { name: rc("Alpha"),
id: Default::default(), kind: VariantKind::Record(vec![
name: rc("Alpha"), (rc("a"), ty_simple("Int")),
kind: VariantKind::Record(vec![ (rc("b"), ty_simple("Int"))
(rc("a"), ty_simple("Int")), ])
(rc("b"), ty_simple("Int")) }
]) ])
} })]
]) };
})]
}; assert_ast! {
} "type Alpha = { a: Int, b: Int }",
vec![decl(TypeDecl {
name: TypeSingletonName { name: rc("Alpha"), params: vec![] },
mutable: false,
body: TypeBody::ImmediateRecord(Default::default(), vec![
(rc("a"), ty_simple("Int")),
(rc("b"), ty_simple("Int"))
])
})]
};
assert_ast!( assert_ast!(
"type Option<T> = None | Some(T)", "type Option<T> = None | Some(T)",
@ -625,7 +635,7 @@ fn type_declarations() {
params: vec![TypeIdentifier::Singleton(TypeSingletonName { name: rc("T"), params: vec![] })] params: vec![TypeIdentifier::Singleton(TypeSingletonName { name: rc("T"), params: vec![] })]
}, },
mutable: false, mutable: false,
body: TypeBody(vec![ body: TypeBody::Variants(vec![
Variant { id: Default::default(), name: rc("None"), kind: VariantKind::UnitStruct }, Variant { id: Default::default(), name: rc("None"), kind: VariantKind::UnitStruct },
Variant { Variant {
id: Default::default(), id: Default::default(),
@ -651,7 +661,7 @@ fn type_declarations() {
TypeIdentifier::Singleton(TypeSingletonName { name: rc("U"), params: vec![] }), TypeIdentifier::Singleton(TypeSingletonName { name: rc("U"), params: vec![] }),
] }, ] },
mutable: false, mutable: false,
body: TypeBody(vec![ body: TypeBody::Variants(vec![
Variant { id: Default::default(), name: rc("Unit"), kind: VariantKind::UnitStruct }, Variant { id: Default::default(), name: rc("Unit"), kind: VariantKind::UnitStruct },
Variant { id: Default::default(), name: rc("Record"), kind: VariantKind::Record( Variant { id: Default::default(), name: rc("Record"), kind: VariantKind::Record(
vec![ vec![

View File

@ -404,7 +404,14 @@ impl<'a> SymbolTableRunner<'a> {
location: Location, location: Location,
scope_stack: &mut Vec<Scope>, scope_stack: &mut Vec<Scope>,
) -> Vec<SymbolError> { ) -> Vec<SymbolError> {
let TypeBody(variants) = type_body; let variants = match type_body {
TypeBody::Variants(variants) => variants.clone(),
TypeBody::ImmediateRecord(id, fields) => vec![Variant {
id: *id,
name: type_name.name.clone(),
kind: VariantKind::Record(fields.clone()),
}],
};
let type_fqsn = Fqsn::from_scope_stack(scope_stack, type_name.name.clone()); let type_fqsn = Fqsn::from_scope_stack(scope_stack, type_name.name.clone());
let new_scope = Scope::Name(type_name.name.clone()); let new_scope = Scope::Name(type_name.name.clone());
@ -414,7 +421,7 @@ impl<'a> SymbolTableRunner<'a> {
let mut seen_variants = HashSet::new(); let mut seen_variants = HashSet::new();
let mut errors = vec![]; let mut errors = vec![];
for variant in variants { for variant in variants.iter() {
if seen_variants.contains(&variant.name) { if seen_variants.contains(&variant.name) {
errors.push(SymbolError::DuplicateVariant { errors.push(SymbolError::DuplicateVariant {
type_fqsn: type_fqsn.clone(), type_fqsn: type_fqsn.clone(),

View File

@ -371,7 +371,7 @@ let x = Some(9); if x is Some(q) then { q } else { 0 }"#;
#[test] #[test]
fn accessors() { fn accessors() {
let source = r#" let source = r#"
type Klewos = Klewos { a: Int, b: String } type Klewos = { a: Int, b: String }
let value = Klewos::Klewos { a: 50, b: "nah" } let value = Klewos::Klewos { a: 50, b: "nah" }
(value.a, value.b) (value.a, value.b)
"#; "#;