feat: field access

This commit is contained in:
rvcas 2022-10-02 18:16:19 -04:00 committed by Lucas
parent 34492f600c
commit 1b61f4b25b
2 changed files with 98 additions and 2 deletions

View File

@ -2,12 +2,22 @@ use chumsky::prelude::*;
use vec1::Vec1; use vec1::Vec1;
use crate::{ use crate::{
ast::{self, BinOp, TodoKind}, ast::{self, BinOp, Span, TodoKind},
error::ParseError, error::ParseError,
expr, expr,
token::Token, token::Token,
}; };
// Parsing a function call into the appropriate structure
#[derive(Debug)]
pub enum ParserArg {
Arg(Box<ast::CallArg<expr::UntypedExpr>>),
Hole {
location: Span,
label: Option<String>,
},
}
pub fn module_parser( pub fn module_parser(
kind: ast::ModuleKind, kind: ast::ModuleKind,
) -> impl Parser<Token, ast::UntypedModule, Error = ParseError> { ) -> impl Parser<Token, ast::UntypedModule, Error = ParseError> {
@ -453,13 +463,65 @@ pub fn expr_parser(
assert_parser, assert_parser,
)); ));
enum Chain {
FieldAccess(String, Span),
RecordUpdate,
Call(Vec<ParserArg>, Span),
}
let field_access_parser = just(Token::Dot)
.ignore_then(select! {
Token::Name { name } => name,
Token::UpName { name } => name
})
.map_with_span(Chain::FieldAccess);
let call_parser = choice((
select! { Token::Name { name } => name }
.then_ignore(just(Token::Colon))
.or_not()
.then(r.clone())
.map_with_span(|(label, value), span| {
ParserArg::Arg(Box::new(ast::CallArg {
label,
location: span,
value,
}))
}),
select! { Token::Name { name } => name }
.then_ignore(just(Token::Colon))
.or_not()
.then_ignore(select! {Token::DiscardName {name} => name })
.map_with_span(|label, span| ParserArg::Hole {
location: span,
label,
}),
))
.separated_by(just(Token::Comma))
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
.map_with_span(Chain::Call);
let chain = choice((field_access_parser, call_parser));
let chained = expr_unit_parser
.then(chain.repeated())
.foldl(|e, chain| match chain {
Chain::FieldAccess(label, span) => expr::UntypedExpr::FieldAccess {
location: e.location().union(span),
label,
container: Box::new(e),
},
_ => todo!(),
});
// Negate
let op = just(Token::Bang); let op = just(Token::Bang);
let unary = op let unary = op
.ignored() .ignored()
.map_with_span(|_, span| span) .map_with_span(|_, span| span)
.repeated() .repeated()
.then(expr_unit_parser) .then(chained)
.foldr(|span, value| expr::UntypedExpr::Negate { .foldr(|span, value| expr::UntypedExpr::Negate {
location: span.union(value.location()), location: span.union(value.location()),
value: Box::new(value), value: Box::new(value),

View File

@ -77,6 +77,10 @@ fn module() {
} }
fn run() {} fn run() {}
fn name(user: User) {
user.name
}
"#; "#;
let len = code.chars().count(); let len = code.chars().count();
@ -725,6 +729,36 @@ 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(), 1425..1429),
},
location: Span::new(SrcId::empty(), 1425..1435),
annotation: Some(ast::Annotation::Constructor {
location: Span::new(SrcId::empty(), 1431..1435),
module: None,
name: "User".to_string(),
arguments: vec![],
},),
tipo: (),
},],
body: expr::UntypedExpr::FieldAccess {
location: Span::new(SrcId::empty(), 1455..1464),
label: "name".to_string(),
container: Box::new(expr::UntypedExpr::Var {
location: Span::new(SrcId::empty(), 1455..1459),
name: "user".to_string(),
}),
},
doc: None,
location: Span::new(SrcId::empty(), 1417..1478),
name: "name".to_string(),
public: false,
return_annotation: None,
return_type: (),
},
] ]
}, },
); );