type declarations

This commit is contained in:
Greg Shuflin 2021-11-07 01:30:26 -08:00
parent 02fc76c8fc
commit d46f40bc0f
2 changed files with 67 additions and 17 deletions

View File

@ -2,6 +2,10 @@ use std::rc::Rc;
use crate::ast::*;
fn rc_string(s: &str) -> Rc<String> {
Rc::new(s.to_string())
}
peg::parser! {
pub grammar schala_parser() for str {
@ -14,11 +18,6 @@ peg::parser! {
rule delimiter() = (";" / "\n")+
rule statement() -> Statement =
_ expr:expression() { Statement {
id: Default::default(), location: Default::default(), kind: StatementKind::Expression(expr) }
}
//Note - this is a hack, ideally the rule `rule block() -> Block = "{" _ items:(statement() **
//delimiter()) _ "}" { items.into() }` would've worked, but it doesn't.
pub rule block() -> Block = "{" _ items:block_item()* _ "}" { items.into() } /
@ -27,10 +26,61 @@ peg::parser! {
rule block_item() -> Statement =
stmt:statement() delimiter()+ { stmt }
rule statement() -> Statement =
_ decl:declaration() { Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Declaration(decl) } } /
_ expr:expression() { Statement { id: Default::default(), location: Default::default(), kind: StatementKind::Expression(expr) } }
rule declaration() -> Declaration =
binding() / type_decl()
rule binding() -> Declaration =
"let" _ mutable:"mut"? _ ident:identifier() _ type_anno:type_anno()? _ "=" _ expr:expression() {
Declaration::Binding { name: Rc::new(ident.to_string()), constant: mutable.is_none(),
type_anno, expr }
}
rule type_decl() -> Declaration =
"type" _ "alias" _ alias:type_alias() { alias } /
"type" _ mutable:"mut"? _ name:type_singleton_name() _ "=" _ body:type_body() {
Declaration::TypeDecl { name, body, mutable: mutable.is_some() }
}
rule type_singleton_name() -> TypeSingletonName =
name:identifier() params:type_params()? { TypeSingletonName { name: rc_string(name), params: if let Some(params) = params { params } else { vec![] } } }
rule type_params() -> Vec<TypeIdentifier> =
"<" _ idents:(type_identifier() ** (_ "," _)) _ ">" { idents }
rule type_identifier() -> TypeIdentifier =
"(" _ items:(type_identifier() ** (_ "," _)) _ ")" { TypeIdentifier::Tuple(items) } /
singleton:type_singleton_name() { TypeIdentifier::Singleton(singleton) }
rule type_body() -> TypeBody =
"{" _ items:(record_variant_item() ++ (_ "," _)) _ "}" { TypeBody::ImmediateRecord(Default::default(), items) } /
variants:(variant_spec() ** (_ "|" _)) { TypeBody::Variants(variants) }
rule variant_spec() -> Variant =
name:identifier() _ "{" _ typed_identifier_list:(record_variant_item() ++ (_ "," _)) _ "}" { Variant {
id: Default::default(), name: rc_string(name), kind: VariantKind::Record(typed_identifier_list)
} } /
name:identifier() "(" tuple_members:(type_identifier() ++ (_ "," _)) ")" { Variant {
id: Default::default(), name: rc_string(name), kind: VariantKind::TupleStruct(tuple_members) } } /
name:identifier() { Variant { id: Default::default(), name: rc_string(name), kind: VariantKind::UnitStruct } }
rule record_variant_item() -> (Rc<String>, TypeIdentifier) =
name:identifier() _ ":" _ ty:type_identifier() { (rc_string(name), ty) }
rule type_alias() -> Declaration =
alias:identifier() _ "=" _ name:identifier() { Declaration::TypeAlias { alias: rc_string(alias), original: rc_string(name), } }
rule type_anno() -> TypeIdentifier =
":" _ ident:identifier() { TypeIdentifier::Singleton(TypeSingletonName { name: Rc::new(ident.to_string()), params: vec![] }) }
pub rule expression() -> Expression =
_ kind:expression_kind() { Expression { id: Default::default(), type_anno: None, kind: kind } }
pub rule expression_no_struct() -> Expression =
rule expression_no_struct() -> Expression =
_ kind:expression_kind_no_struct() { Expression { id: Default::default(), type_anno: None, kind: kind } }
rule expression_kind() -> ExpressionKind =

View File

@ -597,7 +597,7 @@ fn type_annotations() {
#[test]
fn type_declarations() {
use Declaration::TypeDecl;
assert_ast! {
assert_ast2! {
"type Alpha = Alpha", vec![
decl(TypeDecl {
name: TypeSingletonName { name: rc("Alpha"), params: vec![] },
@ -613,7 +613,7 @@ fn type_declarations() {
]
};
assert_ast!(
assert_ast2!(
"type mut Kuah = Kuah",
decl(TypeDecl {
name: TypeSingletonName { name: rc("Kuah"), params: vec![] },
@ -626,7 +626,7 @@ fn type_declarations() {
})
);
assert_ast! {
assert_ast2! {
"type Alpha = Alpha { a: Int, b: Int }",
vec![decl(TypeDecl {
name: TypeSingletonName { name: rc("Alpha"), params: vec![] },
@ -644,7 +644,7 @@ fn type_declarations() {
})]
};
assert_ast! {
assert_ast2! {
"type Alpha = { a: Int, b: Int }",
vec![decl(TypeDecl {
name: TypeSingletonName { name: rc("Alpha"), params: vec![] },
@ -657,7 +657,7 @@ fn type_declarations() {
})]
};
assert_ast!(
assert_ast2!(
"type Option<T> = None | Some(T)",
vec![decl(TypeDecl {
name: TypeSingletonName {
@ -679,12 +679,12 @@ fn type_declarations() {
})]
);
assert_ast!(
assert_ast2!(
"type alias Alpha = Beta",
decl(Declaration::TypeAlias { alias: rc("Alpha"), original: rc("Beta") })
);
assert_ast!("type Complex<T, U> = Unit | Record { field: AnotherType<Bool>, field2: (Nat, Int), field3: T } | Tuple(Int, (String, T))",
assert_ast2!("type Complex<T, U> = Unit | Record { field: AnotherType<Bool>, field2: (Nat, Int), field3: T } | Tuple(Int, (String, T))",
decl(TypeDecl {
name: TypeSingletonName { name: rc("Complex"), params: vec![
TypeIdentifier::Singleton(TypeSingletonName { name: rc("T"), params: vec![] }),
@ -721,7 +721,7 @@ fn type_declarations() {
fn declarations() {
use ExpressionKind::*;
assert_ast!(
assert_ast2!(
"let q_q = Yolo::Swaggins",
vec![decl(Declaration::Binding {
name: rc("q_q"),
@ -736,7 +736,7 @@ fn declarations() {
fn bindings() {
use ExpressionKind::*;
assert_ast!(
assert_ast2!(
"let mut a = 10",
vec![decl(Declaration::Binding {
name: rc("a"),
@ -746,7 +746,7 @@ fn bindings() {
})]
);
assert_ast!(
assert_ast2!(
"let a = 2 + a",
vec![stmt(StatementKind::Declaration(Declaration::Binding {
name: rc("a"),
@ -756,7 +756,7 @@ fn bindings() {
}))]
);
assert_ast!(
assert_ast2!(
"let a: Nat = 2",
vec![stmt(StatementKind::Declaration(Declaration::Binding {
name: rc("a"),