use crate::item::{Item, ItemKind, Span};
use crate::token::{Token, TokenKind};
use std::backtrace::Backtrace;
#[derive(Debug)]
pub struct ParseError {
pub span: Span,
pub reason: String,
pub backtrace: Backtrace,
}
impl ParseError {
pub fn new<T>(span: Span, reason: T) -> Self
where
T: Into<String>,
{
Self {
span,
reason: reason.into(),
backtrace: Backtrace::force_capture(), }
}
}
impl std::fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Parse Error: {} ({:?})\nBacktrace:\n{}",
self.reason, self.span, self.backtrace
)
}
}
impl std::error::Error for ParseError {}
pub type ParseResult<T = ()> = Result<T, ParseError>;
#[derive(Debug)]
pub struct Parser<'text> {
pub text: &'text str,
pub items: Vec<Item>,
pub comments: Vec<Item>,
pub tokens: Vec<Token>,
pub token_i: usize,
}
impl<'text> Parser<'text> {
pub fn new(text: &'text str, mut tokens: Vec<Token>) -> Self {
let mut comments = Vec::new();
for t in tokens.iter().filter(|t| t.kind == TokenKind::Comment) {
comments.push(Item::new(ItemKind::Comment, t.span));
}
tokens.retain(|t| t.kind != TokenKind::Comment);
Self {
items: Vec::new(),
comments,
text,
tokens,
token_i: 0,
}
}
pub fn last_span(&self) -> Span {
if let Some(t) = self.token_i.checked_sub(1).and_then(|i| self.tokens.get(i)) {
t.span
} else {
Span { start: 0, end: 0 }
}
}
pub fn next_span(&self) -> Span {
if let Some(t) = self.tokens.get(self.token_i) {
t.span
} else {
let n = self.text.len();
Span { start: n, end: n }
}
}
fn next_empty_span(&self) -> Span {
let start = self.next_span().start;
Span::new(start, start)
}
pub fn next_token(&mut self) -> ParseResult<Token> {
let t = self.token()?;
self.token_i += 1;
Ok(t)
}
pub fn peek_token(&self) -> Option<Token> {
self.tokens.get(self.token_i).copied()
}
pub fn token(&self) -> ParseResult<Token> {
if let Some(token) = self.tokens.get(self.token_i).copied() {
Ok(token)
} else {
let n = self.text.len();
let span = Span { start: n, end: n };
Err(ParseError::new(span, "unexpected EOF"))
}
}
pub fn is_eof(&self) -> bool {
self.token_i == self.tokens.len()
}
pub fn parse_module(&mut self) -> ParseResult {
while !self.is_eof() {
if self.is_next_symbol("-") {
self.parse_attr()?;
} else {
self.parse_fun_decl()?;
}
}
let span = Span::new(0, self.text.len());
self.insert_item(0, ItemKind::Module, span);
Ok(())
}
pub fn parse_attr(&mut self) -> ParseResult {
let (_i, start) = self.span_start();
self.expect_symbol("-")?;
let mut paren_level = 0;
loop {
if self.is_next_symbol("(") {
paren_level += 1;
self.next_token()?;
} else if self.is_next_symbol(")") {
paren_level -= 1;
self.next_token()?;
} else if self.is_next_symbol(".") && paren_level == 0 {
self.expect_symbol(".")?;
break;
} else {
self.next_token()?;
}
}
let span = self.span_finish(start);
self.push_item(ItemKind::Attr, span);
Ok(())
}
pub fn parse_fun_decl(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.parse_fun_clause()?;
while self.is_next_symbol(";") {
self.expect_symbol(";")?;
self.parse_fun_clause()?;
}
let end = self.expect_symbol(".")?.end;
let span = Span::new(start, end);
self.insert_item(i, ItemKind::FunDecl, span);
Ok(())
}
fn span_start(&self) -> (usize, usize) {
(self.items.len(), self.next_span().start)
}
fn span_finish(&self, start: usize) -> Span {
Span::new(start, self.last_span().end)
}
pub fn parse_body(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
self.parse_expr()?;
while self.is_next_symbol(",") {
let _ = self.next_token();
self.parse_expr()?;
}
let span = self.span_finish(start);
self.insert_item(i, ItemKind::Body, span);
Ok(())
}
pub fn parse_guard(&mut self) -> ParseResult {
let (i, start) = self.span_start();
if !self.expect_optional_keyword("when") {
self.push_item(ItemKind::Guard, self.next_empty_span());
return Ok(());
}
self.parse_expr()?;
while self.is_next_symbol(",") || self.is_next_symbol(";") {
let _ = self.next_token();
self.parse_expr()?;
}
let span = self.span_finish(start);
self.insert_item(i, ItemKind::Guard, span);
Ok(())
}
pub fn parse_fun_clause(&mut self) -> ParseResult<()> {
let i = self.items.len();
let start = self.parse_atom()?.start;
self.parse_args()?;
self.parse_guard()?;
self.expect_symbol("->")?;
self.parse_body()?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::FunClause, span);
Ok(())
}
pub fn parse_atom(&mut self) -> ParseResult<Span> {
let t = self.next_token()?;
if t.kind != TokenKind::Atom {
return Err(ParseError::new(t.span, "not an atom token"));
}
self.push_item(ItemKind::Atom, t.span);
Ok(t.span)
}
fn parse_strings(&mut self, i: usize) -> ParseResult {
while self.is_nth_token_kind(0, TokenKind::String) {
self.next_token()?; self.push_item(ItemKind::String, self.last_span());
}
self.insert_item2(i, ItemKind::Strings);
Ok(())
}
pub fn parse_expr(&mut self) -> ParseResult<()> {
let i = self.items.len();
self.parse_expr_item()?;
let mut has_binary_op = false;
while let Some(t) = self.peek_token()
&& t.is_binary_op(self.text)
{
self.parse_binary_op_item()?;
self.parse_expr_item()?;
has_binary_op = true;
}
if has_binary_op {
let start = self.items[i].span.start;
let end = self.last_span().end;
self.insert_item(i, ItemKind::BinaryOpExprs, Span::new(start, end));
}
Ok(())
}
fn push_item(&mut self, kind: ItemKind, span: Span) {
self.items.push(Item::new(kind, span));
}
fn insert_item(&mut self, i: usize, kind: ItemKind, span: Span) {
self.items.insert(i, Item::new(kind, span));
}
fn insert_item2(&mut self, i: usize, kind: ItemKind) {
let start = self.items[i].span.start;
let span = self.span_finish(start);
self.items.insert(i, Item::new(kind, span));
}
fn parse_binary_op_item(&mut self) -> ParseResult<()> {
let t = self.next_token()?;
if !t.is_binary_op(self.text) {
return Err(ParseError::new(t.span, "expected binary operator"));
}
self.push_item(ItemKind::BinaryOp, t.span);
Ok(())
}
fn parse_expr_item(&mut self) -> ParseResult<()> {
let i = self.items.len();
self.parse_compound_expr()?;
loop {
if self.is_next_symbol("?=") {
self.parse_maybe_match(i)?;
} else if self.is_next_symbol("=") {
self.parse_match(i)?;
} else if self.is_next_symbol("#")
&& self.is_nth_token_kind(1, TokenKind::Atom)
&& self.is_nth_token(2, TokenKind::Symbol, ".")
{
self.parse_record_field_access(i)?;
} else if self.is_next_symbol("#") && self.is_nth_token_kind(1, TokenKind::Atom) {
self.parse_record_update(i)?;
} else if self.is_next_symbol("#") && self.is_nth_token(1, TokenKind::Symbol, "{") {
self.parse_map_update(i)?;
} else {
return Ok(());
}
}
}
fn parse_compound_expr(&mut self) -> ParseResult<()> {
let i = self.items.len();
self.parse_base_expr_item()?;
if self.is_next_symbol(":") {
self.parse_module_fun_call(i)
} else if self.is_next_symbol("(") {
self.parse_fun_call(i)
} else if self.items[i].kind == ItemKind::String
&& self.is_nth_token_kind(0, TokenKind::String)
{
self.parse_strings(i)
} else {
Ok(())
}
}
fn parse_map_update(&mut self, i: usize) -> ParseResult {
let _ = self.next_token()?; self.expect_symbol("{")?;
if !self.is_next_symbol("}") {
loop {
self.parse_expr()?; self.expect_symbol_any(&["=>", ":="])?;
self.parse_expr()?; if !self.expect_optional_symbol(",") {
break;
}
}
}
self.expect_symbol("}")?;
self.insert_item2(i, ItemKind::MapUpdate);
Ok(())
}
fn parse_record_field_access(&mut self, i: usize) -> ParseResult {
let _ = self.next_token()?; self.parse_atom()?; self.expect_symbol(".")?;
self.parse_atom()?;
self.insert_item2(i, ItemKind::RecordFieldAccess);
Ok(())
}
fn parse_record_update(&mut self, i: usize) -> ParseResult {
let _ = self.next_token()?; self.parse_atom()?; self.expect_symbol("{")?;
if !self.is_next_symbol("}") {
loop {
self.parse_atom()?; self.expect_symbol("=")?;
self.parse_expr()?; if !self.expect_optional_symbol(",") {
break;
}
}
}
self.expect_symbol("}")?;
self.insert_item2(i, ItemKind::RecordUpdate);
Ok(())
}
fn parse_args(&mut self) -> ParseResult<Span> {
let (i, start) = self.span_start();
self.expect_symbol("(")?;
if !self.is_next_symbol(")") {
loop {
self.parse_expr()?;
if !self.is_next_symbol(",") {
break;
}
let _ = self.next_token()?;
}
}
let last = self.expect_symbol(")")?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::Args, span);
Ok(last)
}
fn parse_record_create(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_symbol("#")?;
self.parse_atom()?; self.expect_symbol("{")?;
if !self.is_next_symbol("}") {
loop {
self.parse_atom()?; self.expect_symbol("=")?;
self.parse_expr()?; if !self.expect_optional_symbol(",") {
break;
}
}
}
self.expect_symbol("}")?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::RecordCreate, span);
Ok(())
}
fn expect_symbol_any(&mut self, names: &[&str]) -> ParseResult<Span> {
let t = self.next_token()?;
if t.kind == TokenKind::Symbol && names.contains(&t.text(self.text)) {
Ok(t.span)
} else {
Err(ParseError::new(
t.span,
format!(
"expected one of symbols {}, got '{}'",
names.join(", "),
t.text(self.text)
),
))
}
}
fn parse_map_create(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_symbol("#")?;
self.expect_symbol("{")?;
let mut kind = ItemKind::MapCreate;
let mut is_first = true;
if !self.is_next_symbol("}") {
loop {
self.parse_expr()?;
self.expect_symbol_any(&["=>", ":="])?;
self.parse_expr()?;
if is_first && self.is_next_symbol("||") {
kind = ItemKind::MapComprehension;
self.parse_comprehension_right()?;
break;
}
is_first = false;
if !self.expect_optional_symbol(",") {
break;
}
}
}
self.expect_symbol("}")?;
let span = self.span_finish(start);
self.insert_item(i, kind, span);
Ok(())
}
fn parse_binary(&mut self) -> ParseResult {
let (_i, start) = self.span_start();
self.expect_symbol("<<")?;
let mut level = 1; while level > 0 {
if self.is_next_symbol("<<") {
level += 1;
} else if self.is_next_symbol(">>") {
level -= 1;
}
self.next_token()?;
}
let span = self.span_finish(start);
self.push_item(ItemKind::Binary, span);
Ok(())
}
fn parse_paren(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_symbol("(")?;
if !self.is_next_symbol(")") {
self.parse_expr()?;
}
self.expect_symbol(")")?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::Paren, span);
Ok(())
}
fn parse_comprehension_right(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
self.expect_symbol("||")?;
loop {
let mut kind = ItemKind::ComprehensionFilter;
let (i, start) = self.span_start();
self.parse_expr()?;
if self.is_next_symbol(":=") {
self.next_token()?;
self.parse_expr()?;
self.expect_symbol_any(&["<-", "<:-"])?;
self.parse_expr()?;
kind = ItemKind::ComprehensionGenerator;
} else if self.peek_token().is_some_and(|t| {
t.kind == TokenKind::Symbol
&& matches!(t.text(&self.text), "<-" | "<=" | "<:-" | "<:=")
}) {
self.next_token()?;
self.parse_expr()?;
kind = ItemKind::ComprehensionGenerator;
}
let span = self.span_finish(start);
self.insert_item(i, kind, span);
if !self.expect_optional_symbol(",") {
break;
}
}
let span = self.span_finish(start);
self.insert_item(i, ItemKind::ComprehensionRight, span);
Ok(())
}
fn parse_list(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_symbol("[")?;
let mut kind = ItemKind::List;
let mut is_first = true;
if !self.is_next_symbol("]") {
loop {
self.parse_expr()?;
if is_first && self.is_next_symbol("||") {
kind = ItemKind::ListComprehension;
self.parse_comprehension_right()?;
break;
}
is_first = false;
if !self.expect_optional_symbol(",") {
break;
}
}
}
self.expect_symbol("]")?;
let span = self.span_finish(start);
self.insert_item(i, kind, span);
Ok(())
}
fn parse_tuple<F>(&mut self, f: F) -> ParseResult
where
F: Fn(&mut Self) -> ParseResult,
{
let (i, start) = self.span_start();
self.expect_symbol("{")?;
while !self.is_next_symbol("}") {
f(self)?;
if !self.expect_optional_symbol(",") {
break;
}
}
self.expect_symbol("}")?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::Tuple, span);
Ok(())
}
fn parse_module_fun_call(&mut self, module_item_i: usize) -> ParseResult {
let _ = self.next_token()?; self.parse_base_expr_item()?; let last = self.parse_args()?;
let start = self.items[module_item_i].span.start;
let span = Span::new(start, last.end);
self.insert_item(module_item_i, ItemKind::ModuleFunCall, span);
Ok(())
}
fn parse_fun_call(&mut self, i: usize) -> ParseResult {
self.parse_args()?; self.insert_item2(i, ItemKind::FunCall);
Ok(())
}
fn parse_maybe_match(&mut self, i: usize) -> ParseResult {
let _ = self.next_token()?; self.parse_expr()?;
self.insert_item2(i, ItemKind::MaybeMatch);
Ok(())
}
fn parse_match(&mut self, i: usize) -> ParseResult {
let _ = self.next_token()?; self.parse_expr()?;
self.insert_item2(i, ItemKind::Match);
Ok(())
}
fn expect_optional_symbol(&mut self, name: &str) -> bool {
if self.is_next_symbol(name) {
self.token_i += 1;
true
} else {
false
}
}
fn expect_optional_keyword(&mut self, name: &str) -> bool {
if self.is_next_keyword(name) {
self.token_i += 1;
true
} else {
false
}
}
fn expect_symbol(&mut self, name: &str) -> ParseResult<Span> {
let t = self.next_token()?;
if t.kind == TokenKind::Symbol && t.text(self.text) == name {
Ok(t.span)
} else {
Err(ParseError::new(
t.span,
format!("expected symbol '{}', got '{}'", name, t.text(self.text)),
))
}
}
fn expect_keyword(&mut self, name: &str) -> ParseResult<Span> {
let t = self.next_token()?;
if t.kind == TokenKind::Keyword && t.text(self.text) == name {
Ok(t.span)
} else {
Err(ParseError::new(
t.span,
format!("expected keyword '{}', got '{}'", name, t.text(self.text)),
))
}
}
fn is_next_symbol(&self, name: &str) -> bool {
self.peek_token()
.is_some_and(|t| t.kind == TokenKind::Symbol && t.text(self.text) == name)
}
fn is_nth_token(&self, n: usize, kind: TokenKind, name: &str) -> bool {
self.tokens
.get(self.token_i + n)
.is_some_and(|t| t.kind == kind && t.text(self.text) == name)
}
fn is_nth_token_kind(&self, n: usize, kind: TokenKind) -> bool {
self.tokens
.get(self.token_i + n)
.is_some_and(|t| t.kind == kind)
}
fn is_next_keyword(&self, name: &str) -> bool {
self.peek_token()
.is_some_and(|t| t.kind == TokenKind::Keyword && t.text(self.text) == name)
}
fn parse_maybe_expr(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_keyword("maybe")?;
self.parse_body()?;
if !self.is_next_keyword("end") {
self.expect_keyword("else")?;
self.parse_else_clauses()?;
}
self.expect_keyword("end")?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::MaybeExpr, span);
Ok(())
}
fn parse_else_clauses(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
loop {
self.parse_else_clause()?;
if !self.is_next_symbol(";") {
break;
}
let _ = self.next_token()?; }
let span = self.span_finish(start);
self.insert_item(i, ItemKind::Clauses, span);
Ok(())
}
fn parse_else_clause(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
self.parse_pattern()?; self.parse_guard()?;
self.expect_symbol("->")?;
self.parse_body()?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::ElseClause, span);
Ok(())
}
fn parse_case(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_keyword("case")?;
self.parse_expr()?;
self.expect_keyword("of")?;
self.parse_case_clauses()?;
self.expect_keyword("end")?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::Case, span);
Ok(())
}
fn parse_case_clauses(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
loop {
self.parse_case_clause()?;
if !self.is_next_symbol(";") {
break;
}
let _ = self.next_token()?; }
let span = self.span_finish(start);
self.insert_item(i, ItemKind::CaseClauses, span);
Ok(())
}
fn parse_pattern(&mut self) -> ParseResult {
let i = self.items.len();
self.parse_base_expr_item()?;
loop {
if self.is_next_symbol("?=") {
self.parse_maybe_match(i)?;
} else if self.is_next_symbol("=") {
self.parse_match(i)?;
} else if self.is_next_symbol("#")
&& self.is_nth_token_kind(1, TokenKind::Atom)
&& self.is_nth_token(2, TokenKind::Symbol, ".")
{
self.parse_record_field_access(i)?;
} else if self.is_next_symbol("#") && self.is_nth_token_kind(1, TokenKind::Atom) {
self.parse_record_update(i)?;
} else if self.is_next_symbol("#") && self.is_nth_token(1, TokenKind::Symbol, "{") {
self.parse_map_update(i)?;
} else {
return Ok(());
}
}
}
fn parse_case_clause(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
self.parse_pattern()?; self.parse_guard()?;
self.expect_symbol("->")?;
self.parse_body()?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::CaseClause, span);
Ok(())
}
fn parse_base_expr_item(&mut self) -> ParseResult<()> {
let t = self.next_token()?;
match t.kind {
TokenKind::Comment => panic!("bug"),
TokenKind::Integer => self.push_item(ItemKind::Integer, t.span),
TokenKind::Atom => self.push_item(ItemKind::Atom, t.span),
TokenKind::Variable => self.push_item(ItemKind::Variable, t.span),
TokenKind::Float => self.push_item(ItemKind::Float, t.span),
TokenKind::Char => self.push_item(ItemKind::Char, t.span),
TokenKind::String => self.push_item(ItemKind::String, t.span),
TokenKind::SigilString => self.push_item(ItemKind::SigilString, t.span),
TokenKind::Keyword => {
self.token_i -= 1;
match t.text(self.text) {
"case" => self.parse_case()?,
"try" => self.parse_try()?,
"receive" => self.parse_receive()?,
"begin" => self.parse_begin()?,
"maybe" => self.parse_maybe_expr()?,
"fun" if self.is_nth_token(1, TokenKind::Symbol, "(") => {
self.parse_anonymous_fun()?
}
"fun"
if self.is_nth_token_kind(1, TokenKind::Variable)
&& self.is_nth_token(2, TokenKind::Symbol, "(") =>
{
self.parse_named_fun()?
}
"fun" => self.parse_fun_ref()?,
"not" => self.parse_unary_op_expr()?,
t => return Err(ParseError::new(self.next_span(), format!("TODO: {t:?}"))),
}
}
TokenKind::Symbol => {
self.token_i -= 1;
match t.text(self.text) {
"(" => self.parse_paren()?,
"{" => self.parse_tuple(|p| p.parse_expr())?,
"[" => self.parse_list()?,
"<<" => self.parse_binary()?,
"#" if self.is_nth_token(1, TokenKind::Symbol, "{") => {
self.parse_map_create()?
}
"#" if self.is_nth_token_kind(1, TokenKind::Atom)
&& self.is_nth_token(2, TokenKind::Symbol, ".") =>
{
self.parse_record_field_index()?
}
"#" if self.is_nth_token_kind(1, TokenKind::Atom) => {
self.parse_record_create()?
}
"-" => self.parse_unary_op_expr()?,
t => return Err(ParseError::new(self.next_span(), format!("TODO: {t:?}"))),
}
}
}
Ok(())
}
fn parse_named_fun(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_keyword("fun")?;
loop {
self.parse_named_fun_clause()?;
if !self.is_next_symbol(";") {
break;
}
let _ = self.next_token()?; }
self.expect_keyword("end")?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::NamedFun, span);
Ok(())
}
fn parse_named_fun_clause(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
let t = self.next_token()?;
if t.kind != TokenKind::Variable {
return Err(ParseError::new(t.span, "expected variable in named fun"));
}
self.push_item(ItemKind::Variable, t.span);
self.parse_args()?;
self.parse_guard()?;
self.expect_symbol("->")?;
self.parse_body()?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::NamedFunClause, span);
Ok(())
}
fn parse_record_field_index(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_symbol("#")?;
self.parse_atom()?; self.expect_symbol(".")?;
self.parse_atom()?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::RecordFieldIndex, span);
Ok(())
}
fn parse_fun_ref(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_keyword("fun")?;
self.parse_base_expr_item()?;
if self.is_next_symbol(":") {
self.expect_symbol(":")?;
self.parse_base_expr_item()?; self.expect_symbol("/")?;
let t = self.next_token()?;
if t.kind != TokenKind::Integer {
return Err(ParseError::new(t.span, "expected integer arity"));
}
self.push_item(ItemKind::Integer, t.span);
let span = self.span_finish(start);
self.insert_item(i, ItemKind::ModuleFunRef, span);
} else {
self.expect_symbol("/")?;
let t = self.next_token()?;
if t.kind != TokenKind::Integer {
return Err(ParseError::new(t.span, "expected integer arity"));
}
self.push_item(ItemKind::Integer, t.span);
let span = self.span_finish(start);
self.insert_item(i, ItemKind::FunRef, span);
}
Ok(())
}
fn parse_receive(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_keyword("receive")?;
if self.is_next_keyword("after") {
self.push_none();
} else {
self.parse_case_clauses()?;
}
if self.expect_optional_keyword("after") {
self.parse_expr()?; self.expect_symbol("->")?;
self.parse_body()?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::ReceiveAfter, span);
} else {
self.push_none();
}
self.expect_keyword("end")?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::Receive, span);
Ok(())
}
fn parse_begin(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_keyword("begin")?;
self.parse_body()?;
self.expect_keyword("end")?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::Begin, span);
Ok(())
}
fn parse_try(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_keyword("try")?;
self.parse_body()?;
let kind = if self.expect_optional_keyword("of") {
self.parse_case_clauses()?;
ItemKind::TryOf
} else {
ItemKind::Try
};
if self.expect_optional_keyword("catch") {
self.parse_try_catch_clauses()?;
} else {
self.push_none();
}
if self.expect_optional_keyword("after") {
let (i, start) = self.span_start();
self.parse_body()?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::TryAfter, span);
} else {
self.push_none();
}
self.expect_keyword("end")?;
let span = self.span_finish(start);
self.insert_item(i, kind, span);
Ok(())
}
fn push_none(&mut self) {
let p = self.next_span().start;
let span = Span::new(p, p);
self.push_item(ItemKind::None, span);
}
fn parse_try_catch_clauses(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
loop {
self.parse_try_catch_clause()?;
if !self.is_next_symbol(";") {
break;
}
let _ = self.next_token()?; }
let span = self.span_finish(start);
self.insert_item(i, ItemKind::Clauses, span);
Ok(())
}
fn parse_try_catch_clause(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
self.parse_base_expr_item()?; if self.expect_optional_symbol(":") {
self.parse_pattern()?;
}
if self.expect_optional_symbol(":") {
self.parse_base_expr_item()?; }
self.parse_guard()?;
self.expect_symbol("->")?;
self.parse_body()?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::TryCatchClause, span);
Ok(())
}
fn parse_anonymous_fun(&mut self) -> ParseResult {
let (i, start) = self.span_start();
self.expect_keyword("fun")?;
loop {
self.parse_anonymous_fun_clause()?;
if !self.is_next_symbol(";") {
break;
}
let _ = self.next_token()?; }
self.expect_keyword("end")?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::AnonymousFun, span);
Ok(())
}
fn parse_anonymous_fun_clause(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
self.parse_args()?;
self.parse_guard()?;
self.expect_symbol("->")?;
self.parse_body()?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::AnonymousFunClause, span);
Ok(())
}
fn parse_unary_op_expr(&mut self) -> ParseResult<()> {
let (i, start) = self.span_start();
let t = self.next_token()?;
self.push_item(ItemKind::UnaryOp, t.span);
self.parse_expr_item()?;
let span = self.span_finish(start);
self.insert_item(i, ItemKind::UnaryOpExpr, span);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::item::ItemView;
fn parse(text: &str) -> ParseResult<Vec<Item>> {
let tokens = crate::token::tokenize(text).expect("tokenization failed");
let mut parser = Parser::new(text, tokens);
while !parser.is_eof() {
parser.parse_expr()?;
}
Ok(parser.items)
}
#[test]
fn parse_integers() {
let input = " 42 ";
let items = parse(input).expect("parse failed");
assert_eq!(items.len(), 1);
assert_eq!(items[0].kind, ItemKind::Integer);
assert_eq!(items[0].text(input), "42");
}
#[test]
fn parse_binary_op_exprs() {
let input = "1 + 2 * 3";
let items = parse(input).expect("parse failed");
assert_eq!(items.len(), 6);
assert_eq!(items[0].kind, ItemKind::BinaryOpExprs);
assert_eq!(items[0].text(input), input);
assert_eq!(items[1].kind, ItemKind::Integer);
assert_eq!(items[1].text(input), "1");
assert_eq!(items[2].kind, ItemKind::BinaryOp);
assert_eq!(items[2].text(input), "+");
assert_eq!(items[3].kind, ItemKind::Integer);
assert_eq!(items[3].text(input), "2");
assert_eq!(items[4].kind, ItemKind::BinaryOp);
assert_eq!(items[4].text(input), "*");
assert_eq!(items[5].kind, ItemKind::Integer);
assert_eq!(items[5].text(input), "3");
let view = crate::item::BinaryOpExprsView::new(ItemView::new(&items, 0)).expect("bug");
assert_eq!(view.exprs().count(), 3);
assert_eq!(view.ops().count(), 2);
}
#[test]
fn parse_module_fun_call() {
let input = "foo:bar()";
let items = parse(input).expect("parse failed");
assert_eq!(items.len(), 4);
assert_eq!(items[0].kind, ItemKind::ModuleFunCall);
assert_eq!(items[0].text(input), "foo:bar()");
assert_eq!(items[1].kind, ItemKind::Atom);
assert_eq!(items[1].text(input), "foo");
assert_eq!(items[2].kind, ItemKind::Atom);
assert_eq!(items[2].text(input), "bar");
assert_eq!(items[3].kind, ItemKind::Args);
assert_eq!(items[3].text(input), "()");
let view = crate::item::ModuleFunCallView::new(ItemView::new(&items, 0)).expect("bug");
assert_eq!(view.module_name().kind(), ItemKind::Atom);
assert_eq!(view.module_name().text(input), "foo");
assert_eq!(view.function_name().kind(), ItemKind::Atom);
assert_eq!(view.function_name().text(input), "bar");
assert_eq!(view.args().count(), 0);
let input = "foo:bar(42, X)";
let items = parse(input).expect("parse failed");
let view = crate::item::ModuleFunCallView::new(ItemView::new(&items, 0)).expect("bug");
assert_eq!(view.module_name().text(input), "foo");
assert_eq!(view.function_name().text(input), "bar");
let args: Vec<_> = view.args().collect();
assert_eq!(args.len(), 2);
assert_eq!(args[0].kind(), ItemKind::Integer);
assert_eq!(args[0].text(input), "42");
assert_eq!(args[1].kind(), ItemKind::Variable);
assert_eq!(args[1].text(input), "X");
}
#[test]
fn parse_fun_decl() {
let input = "foo(X) -> X.";
let tokens = crate::token::tokenize(input).expect("tokenization failed");
let mut parser = Parser::new(input, tokens);
parser.parse_fun_decl().expect("parse failed");
let items = &parser.items;
assert!(!items.is_empty());
assert_eq!(items[0].kind, ItemKind::FunDecl);
assert_eq!(items[0].text(input), input);
let view = crate::item::FunDeclView::new(ItemView::new(items, 0)).expect("bug");
let clauses: Vec<_> = view.clauses().collect();
assert_eq!(clauses.len(), 1);
assert_eq!(clauses[0].name().text(input), "foo");
assert_eq!(clauses[0].args().count(), 1);
assert_eq!(clauses[0].body().count(), 1);
}
#[test]
fn parse_case_expr() {
let input = "case X of 42 -> ok; _ -> error end";
let items = parse(input).expect("parse failed");
assert!(!items.is_empty());
assert_eq!(items[0].kind, ItemKind::Case);
assert_eq!(items[0].text(input), input);
let view = crate::item::CaseView::new(ItemView::new(&items, 0)).expect("bug");
assert_eq!(view.expr().kind(), ItemKind::Variable);
assert_eq!(view.expr().text(input), "X");
let clauses: Vec<_> = view.clauses().collect();
assert_eq!(clauses.len(), 2);
assert_eq!(clauses[0].pattern().kind(), ItemKind::Integer);
assert_eq!(clauses[0].pattern().text(input), "42");
assert_eq!(clauses[0].body().count(), 1);
assert_eq!(clauses[1].pattern().kind(), ItemKind::Variable);
assert_eq!(clauses[1].pattern().text(input), "_");
assert_eq!(clauses[1].body().count(), 1);
}
#[test]
fn parse_maybe_expr() {
let input = "maybe X else _ -> error end";
let items = parse(input).expect("parse failed");
assert!(!items.is_empty());
assert_eq!(items[0].kind, ItemKind::MaybeExpr);
assert_eq!(items[0].text(input), input);
let view = crate::item::MaybeExprView::new(ItemView::new(&items, 0)).expect("bug");
let body_items: Vec<_> = view.body().collect();
assert_eq!(body_items.len(), 1);
assert_eq!(body_items[0].kind(), ItemKind::Variable);
assert_eq!(body_items[0].text(input), "X");
let clauses: Vec<_> = view.clauses().collect();
assert_eq!(clauses.len(), 1);
assert_eq!(clauses[0].pattern().kind(), ItemKind::Variable);
assert_eq!(clauses[0].pattern().text(input), "_");
assert_eq!(clauses[0].body().count(), 1);
}
#[test]
fn parse_tuple() {
let input = "{42, X, ok}";
let items = parse(input).expect("parse failed");
assert!(!items.is_empty());
assert_eq!(items[0].kind, ItemKind::Tuple);
assert_eq!(items[0].text(input), input);
let view = crate::item::ItemView::new(&items, 0);
let tuple_items: Vec<_> = view.children().collect();
assert_eq!(tuple_items.len(), 3);
assert_eq!(tuple_items[0].kind(), ItemKind::Integer);
assert_eq!(tuple_items[0].text(input), "42");
assert_eq!(tuple_items[1].kind(), ItemKind::Variable);
assert_eq!(tuple_items[1].text(input), "X");
assert_eq!(tuple_items[2].kind(), ItemKind::Atom);
assert_eq!(tuple_items[2].text(input), "ok");
}
}