Implement parser & type-checker for tuple indexes.

```aiken
  fn foo() {
    let tuple = #(1, 2, 3, 4)
    tuple.1st + tuple.2nd + tuple.3rd + tuple.4th
  }
  ```
This commit is contained in:
KtorZ
2022-12-21 19:24:27 +01:00
parent 7867793bcd
commit bf7cdfba73
13 changed files with 287 additions and 42 deletions

View File

@@ -24,6 +24,17 @@ impl ParseError {
}
self
}
pub fn invalid_tuple_index(span: Span, index: u32, suffix: Option<String>) -> Self {
let hint = suffix.map(|suffix| format!("{index}{suffix}"));
Self {
kind: ErrorKind::InvalidTupleIndex { hint },
span,
while_parsing: None,
expected: HashSet::new(),
label: None,
}
}
}
impl PartialEq for ParseError {
@@ -69,20 +80,22 @@ impl<T: Into<Pattern>> chumsky::Error<T> for ParseError {
#[derive(Debug, PartialEq, Eq, Diagnostic, thiserror::Error)]
pub enum ErrorKind {
#[error("unexpected end")]
#[error("Unexpected end")]
UnexpectedEnd,
#[error("{0}")]
#[diagnostic(help("{}", .0.help().unwrap_or_else(|| Box::new(""))))]
Unexpected(Pattern),
#[error("unclosed {start}")]
#[error("Unclosed {start}")]
Unclosed {
start: Pattern,
#[label]
before_span: Span,
before: Option<Pattern>,
},
#[error("no end branch")]
#[error("No end branch")]
NoEndBranch,
#[error("Invalid tuple index{}", hint.as_ref().map(|s| format!("; did you mean '{s}' ?")).unwrap_or_default())]
InvalidTupleIndex { hint: Option<String> },
}
#[derive(Debug, PartialEq, Eq, Hash, Diagnostic, thiserror::Error)]

View File

@@ -2,6 +2,8 @@ use chumsky::prelude::*;
use crate::ast::Span;
use ordinal::Ordinal;
use super::{error::ParseError, token::Token};
pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
@@ -17,6 +19,25 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
))
.map(|value| Token::Int { value });
let ordinal = text::int(10)
.from_str()
.unwrapped()
.then_with(|index: u32| {
choice((just("st"), just("nd"), just("rd"), just("th")))
.map(move |suffix| (index, suffix))
})
.validate(|(index, suffix), span, emit| {
let expected_suffix = Ordinal(index).suffix();
if expected_suffix != suffix {
emit(ParseError::invalid_tuple_index(
span,
index,
Some(expected_suffix.to_string()),
))
}
Token::Ordinal { index }
});
let op = choice((
just("==").to(Token::EqualEqual),
just('=').to(Token::Equal),
@@ -132,7 +153,7 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
module_comments,
doc_comments,
comments,
choice((keyword, int, op, grouping, string))
choice((ordinal, keyword, int, op, grouping, string))
.or(any().map(Token::Error).validate(|t, span, emit| {
emit(ParseError::expected_input_found(
span,

View File

@@ -4,6 +4,7 @@ use std::fmt;
pub enum Token {
Error(char),
Name { name: String },
Ordinal { index: u32 },
UpName { name: String },
DiscardName { name: String },
Int { value: String },
@@ -78,12 +79,17 @@ pub enum Token {
impl fmt::Display for Token {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let index_str;
let s = match self {
Token::Error(c) => {
write!(f, "\"{}\"", c)?;
return Ok(());
}
Token::Name { name } => name,
Token::Ordinal { index } => {
index_str = index.to_string();
&index_str[..]
}
Token::UpName { name } => name,
Token::DiscardName { name } => name,
Token::Int { value } => value,