feat: record update syntax

This commit is contained in:
rvcas 2022-10-03 17:00:58 -04:00 committed by Lucas
parent 3ad915cafd
commit dba82d544d
3 changed files with 123 additions and 10 deletions

View File

@ -447,7 +447,7 @@ pub struct TypedRecordUpdateArg {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct UntypedRecordUpdateArg { pub struct UntypedRecordUpdateArg {
pub label: String, pub label: String,
// pub location: SrcSpan, pub location: Span,
pub value: UntypedExpr, pub value: UntypedExpr,
} }

View File

@ -467,9 +467,12 @@ pub fn expr_parser(
} }
enum Chain { enum Chain {
FieldAccess(String, Span),
RecordUpdate,
Call(Vec<ParserArg>, Span), Call(Vec<ParserArg>, Span),
FieldAccess(String, Span),
RecordUpdate(
Box<(expr::UntypedExpr, Vec<ast::UntypedRecordUpdateArg>)>,
Span,
),
} }
let field_access_parser = just(Token::Dot) let field_access_parser = just(Token::Dot)
@ -479,6 +482,29 @@ pub fn expr_parser(
}) })
.map_with_span(Chain::FieldAccess); .map_with_span(Chain::FieldAccess);
let record_update_parser = just(Token::DotDot)
.ignore_then(r.clone())
.then(
just(Token::Comma)
.ignore_then(
select! { Token::Name {name} => name }
.then_ignore(just(Token::Colon))
.then(r.clone())
.map_with_span(|(label, value), span| ast::UntypedRecordUpdateArg {
label,
value,
location: span,
})
.separated_by(just(Token::Comma))
.allow_trailing(),
)
.or_not(),
)
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace))
.map_with_span(|(spread, args_opt), span| {
Chain::RecordUpdate(Box::new((spread, args_opt.unwrap_or_default())), span)
});
let call_parser = choice(( let call_parser = choice((
select! { Token::Name { name } => name } select! { Token::Name { name } => name }
.then_ignore(just(Token::Colon)) .then_ignore(just(Token::Colon))
@ -504,16 +530,11 @@ pub fn expr_parser(
.delimited_by(just(Token::LeftParen), just(Token::RightParen)) .delimited_by(just(Token::LeftParen), just(Token::RightParen))
.map_with_span(Chain::Call); .map_with_span(Chain::Call);
let chain = choice((field_access_parser, call_parser)); let chain = choice((field_access_parser, record_update_parser, call_parser));
let chained = expr_unit_parser let chained = expr_unit_parser
.then(chain.repeated()) .then(chain.repeated())
.foldl(|e, chain| match chain { .foldl(|e, chain| match chain {
Chain::FieldAccess(label, span) => expr::UntypedExpr::FieldAccess {
location: e.location().union(span),
label,
container: Box::new(e),
},
Chain::Call(args, span) => { Chain::Call(args, span) => {
let mut holes = Vec::new(); let mut holes = Vec::new();
@ -563,7 +584,30 @@ pub fn expr_parser(
} }
} }
} }
_ => todo!(),
Chain::FieldAccess(label, span) => expr::UntypedExpr::FieldAccess {
location: e.location().union(span),
label,
container: Box::new(e),
},
Chain::RecordUpdate(data, span) => {
let (spread, arguments) = *data;
let location = span.union(spread.location());
let spread = ast::RecordUpdateSpread {
base: Box::new(spread),
location,
};
expr::UntypedExpr::RecordUpdate {
location: e.location().union(span),
constructor: Box::new(e),
spread,
arguments,
}
}
}); });
// Negate // Negate

View File

@ -89,6 +89,10 @@ fn module() {
map_add_x([ 1, 2, 3 ]) map_add_x([ 1, 2, 3 ])
} }
fn update_name(user: User, name: String) -> User {
User { ..user, name: "Aiken", }
}
"#; "#;
let len = code.chars().count(); let len = code.chars().count();
@ -923,6 +927,71 @@ fn module() {
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
}, },
ast::UntypedDefinition::Fn {
arguments: vec![
ast::Arg {
arg_name: ast::ArgName::Named {
name: "user".to_string(),
location: Span::new(SrcId::empty(), 1685..1689),
},
location: Span::new(SrcId::empty(), 1685..1695),
annotation: Some(ast::Annotation::Constructor {
location: Span::new(SrcId::empty(), 1691..1695),
module: None,
name: "User".to_string(),
arguments: vec![],
},),
tipo: (),
},
ast::Arg {
arg_name: ast::ArgName::Named {
name: "name".to_string(),
location: Span::new(SrcId::empty(), 1697..1701),
},
location: Span::new(SrcId::empty(), 1697..1709),
annotation: Some(ast::Annotation::Constructor {
location: Span::new(SrcId::empty(), 1703..1709),
module: None,
name: "String".to_string(),
arguments: vec![],
},),
tipo: (),
},
],
body: expr::UntypedExpr::RecordUpdate {
location: Span::new(SrcId::empty(), 1737..1768),
constructor: Box::new(expr::UntypedExpr::Var {
location: Span::new(SrcId::empty(), 1737..1741),
name: "User".to_string(),
}),
spread: ast::RecordUpdateSpread {
base: Box::new(expr::UntypedExpr::Var {
location: Span::new(SrcId::empty(), 1746..1750),
name: "user".to_string(),
}),
location: Span::new(SrcId::empty(), 1742..1768),
},
arguments: vec![ast::UntypedRecordUpdateArg {
label: "name".to_string(),
location: Span::new(SrcId::empty(), 1752..1765),
value: expr::UntypedExpr::String {
location: Span::new(SrcId::empty(), 1758..1765),
value: "Aiken".to_string(),
},
},],
},
doc: None,
location: Span::new(SrcId::empty(), 1670..1782),
name: "update_name".to_string(),
public: false,
return_annotation: Some(ast::Annotation::Constructor {
location: Span::new(SrcId::empty(), 1714..1718),
module: None,
name: "User".to_string(),
arguments: vec![],
},),
return_type: (),
},
] ]
}, },
); );