Rewrote the parser
This commit is contained in:
parent
96d1311e09
commit
88912bfa39
@ -59,6 +59,12 @@ impl<'lexer> Lexer<'lexer> {
|
|||||||
Span::new(self.byte..self.byte, self.source.clone())
|
Span::new(self.byte..self.byte, self.source.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` when at the end of the input.
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn eof(&self) -> bool {
|
||||||
|
self.peek(0).is_none()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the current character.
|
/// Get the current character.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn current(&self) -> Option<char> {
|
fn current(&self) -> Option<char> {
|
||||||
|
@ -4,9 +4,123 @@ use crate::{
|
|||||||
span::Span,
|
span::Span,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Abstract Syntax Tree (AST).
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq)]
|
||||||
|
pub(crate) struct Ast {
|
||||||
|
root: Vec<Node>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ast {
|
||||||
|
/// Construct a new instance of `Ast`.
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn new(root: Vec<Node>) -> Self {
|
||||||
|
Self { root }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<Node>> for Ast {
|
||||||
|
fn from(root: Vec<Node>) -> Self {
|
||||||
|
Self { root }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(tarpaulin_include))]
|
||||||
|
impl std::fmt::Display for Ast {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for node in &self.root {
|
||||||
|
write!(f, "{node}\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A node in the Abstract Syntax Tree (AST).
|
||||||
|
///
|
||||||
|
/// `Nodes`s contain the kind of node which was found, as well as a [Span]
|
||||||
|
/// specifying the [Source] and [Location] of the node.
|
||||||
|
///
|
||||||
|
/// [Source]: crate::span::Source
|
||||||
|
/// [Location]: crate::span::Location
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub(crate) struct Node {
|
||||||
|
/// The kind of node.
|
||||||
|
pub kind: Expr,
|
||||||
|
/// The span in which the node occurs.
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
/// Construct a new instance of `Node`.
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn new(kind: Expr, span: Span) -> Self {
|
||||||
|
Self { kind, span }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Push a child node onto a list node.
|
||||||
|
pub(crate) fn push_node(&mut self, child: Self) -> Result<(), ParserError> {
|
||||||
|
match &mut self.kind {
|
||||||
|
Expr::List(vec) | Expr::Map(vec) | Expr::Set(vec) | Expr::Vector(vec) => {
|
||||||
|
vec.push(child);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// FIXME
|
||||||
|
// return Err(ParserError::new(
|
||||||
|
// ParserErrorKind::UnexpectedState,
|
||||||
|
// child.span,
|
||||||
|
// ))
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(tarpaulin_include))]
|
||||||
|
#[must_use]
|
||||||
|
fn display(&self, indent: usize) -> String {
|
||||||
|
let mut text = format!(
|
||||||
|
"{}{}@{}..{}\n",
|
||||||
|
" ".repeat(indent),
|
||||||
|
self.kind,
|
||||||
|
self.span.bytes().start,
|
||||||
|
self.span.bytes().end
|
||||||
|
);
|
||||||
|
|
||||||
|
match &self.kind {
|
||||||
|
Expr::Atom(_) => {}
|
||||||
|
Expr::List(vec) | Expr::Map(vec) | Expr::Set(vec) | Expr::Vector(vec) => {
|
||||||
|
for node in vec {
|
||||||
|
text.push_str(&format!("{}\n", node.display(indent + 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text.trim_end().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Token> for Node {
|
||||||
|
type Error = ParserError;
|
||||||
|
|
||||||
|
fn try_from(token: Token) -> Result<Self, Self::Error> {
|
||||||
|
let span = token.span.clone();
|
||||||
|
let kind = Expr::try_from(token)?;
|
||||||
|
|
||||||
|
Ok(Self::new(kind, span))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(tarpaulin_include))]
|
||||||
|
impl std::fmt::Display for Node {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.display(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An atomic value.
|
/// An atomic value.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Atom {
|
pub(crate) enum Atom {
|
||||||
/// Boolean, e.g. `true`, `false`
|
/// Boolean, e.g. `true`, `false`
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
/// Character, e.g. `'c'`, `'\n'`
|
/// Character, e.g. `'c'`, `'\n'`
|
||||||
@ -45,7 +159,7 @@ impl std::fmt::Display for Atom {
|
|||||||
|
|
||||||
/// An expression.
|
/// An expression.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum NodeKind {
|
pub(crate) enum Expr {
|
||||||
/// An atomic value.
|
/// An atomic value.
|
||||||
Atom(Atom),
|
Atom(Atom),
|
||||||
/// A list of nodes.
|
/// A list of nodes.
|
||||||
@ -58,13 +172,25 @@ pub enum NodeKind {
|
|||||||
Vector(Vec<Node>),
|
Vector(Vec<Node>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Atom> for NodeKind {
|
impl Expr {
|
||||||
|
/// Which closing delimiter is associated with the expression kind?
|
||||||
|
pub(crate) fn closing_delimiter(&self) -> Option<TokenKind> {
|
||||||
|
match self {
|
||||||
|
Expr::List(_) => Some(TokenKind::CloseParen),
|
||||||
|
Expr::Map(_) | Expr::Set(_) => Some(TokenKind::CloseBrace),
|
||||||
|
Expr::Vector(_) => Some(TokenKind::CloseBracket),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Atom> for Expr {
|
||||||
fn from(atom: Atom) -> Self {
|
fn from(atom: Atom) -> Self {
|
||||||
Self::Atom(atom)
|
Self::Atom(atom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Token> for NodeKind {
|
impl TryFrom<Token> for Expr {
|
||||||
type Error = ParserError;
|
type Error = ParserError;
|
||||||
|
|
||||||
fn try_from(token: Token) -> Result<Self, Self::Error> {
|
fn try_from(token: Token) -> Result<Self, Self::Error> {
|
||||||
@ -78,10 +204,12 @@ impl TryFrom<Token> for NodeKind {
|
|||||||
TokenKind::Symbol(s) => Atom::Symbol(s),
|
TokenKind::Symbol(s) => Atom::Symbol(s),
|
||||||
TokenKind::Nil => Atom::Nil,
|
TokenKind::Nil => Atom::Nil,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ParserError::new(
|
// FIXME
|
||||||
ParserErrorKind::UnexpectedState,
|
// return Err(ParserError::new(
|
||||||
token.span,
|
// ParserErrorKind::UnexpectedState,
|
||||||
))
|
// token.span,
|
||||||
|
// ))
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -90,9 +218,9 @@ impl TryFrom<Token> for NodeKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
impl std::fmt::Display for NodeKind {
|
impl std::fmt::Display for Expr {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
use NodeKind::*;
|
use Expr::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Atom(atom) => write!(f, "{atom}"),
|
Atom(atom) => write!(f, "{atom}"),
|
||||||
@ -103,89 +231,3 @@ impl std::fmt::Display for NodeKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A node in the Abstract Syntax Tree (AST).
|
|
||||||
///
|
|
||||||
/// `Nodes`s contain the kind of node which was found, as well as a [Span]
|
|
||||||
/// specifying the [Source] and [Location] of the node.
|
|
||||||
///
|
|
||||||
/// [Source]: crate::span::Source
|
|
||||||
/// [Location]: crate::span::Location
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct Node {
|
|
||||||
/// The kind of node.
|
|
||||||
pub kind: NodeKind,
|
|
||||||
/// The span in which the node occurs.
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node {
|
|
||||||
/// Construct a new instance of `Node`.
|
|
||||||
#[must_use]
|
|
||||||
pub const fn new(kind: NodeKind, span: Span) -> Self {
|
|
||||||
Self { kind, span }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Push a child node onto a list node.
|
|
||||||
pub fn push_node(&mut self, child: Self) -> Result<(), ParserError> {
|
|
||||||
match &mut self.kind {
|
|
||||||
NodeKind::List(vec)
|
|
||||||
| NodeKind::Map(vec)
|
|
||||||
| NodeKind::Set(vec)
|
|
||||||
| NodeKind::Vector(vec) => {
|
|
||||||
vec.push(child);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(ParserError::new(
|
|
||||||
ParserErrorKind::UnexpectedState,
|
|
||||||
child.span,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
|
||||||
fn display(&self, indent: usize) -> String {
|
|
||||||
let mut text = format!(
|
|
||||||
"{}{}@{}..{}\n",
|
|
||||||
" ".repeat(indent),
|
|
||||||
self.kind,
|
|
||||||
self.span.bytes().start,
|
|
||||||
self.span.bytes().end
|
|
||||||
);
|
|
||||||
|
|
||||||
match &self.kind {
|
|
||||||
NodeKind::Atom(_) => {}
|
|
||||||
NodeKind::List(vec)
|
|
||||||
| NodeKind::Map(vec)
|
|
||||||
| NodeKind::Set(vec)
|
|
||||||
| NodeKind::Vector(vec) => {
|
|
||||||
for node in vec {
|
|
||||||
text.push_str(&format!("{}\n", node.display(indent + 1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
text.trim_end().to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Token> for Node {
|
|
||||||
type Error = ParserError;
|
|
||||||
|
|
||||||
fn try_from(token: Token) -> Result<Self, Self::Error> {
|
|
||||||
let span = token.span.clone();
|
|
||||||
let kind = NodeKind::try_from(token)?;
|
|
||||||
|
|
||||||
Ok(Self::new(kind, span))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
|
||||||
impl std::fmt::Display for Node {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{}", self.display(0))
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,19 +5,16 @@ use crate::{lexer::LexerError, span::Span};
|
|||||||
pub enum ParserErrorKind {
|
pub enum ParserErrorKind {
|
||||||
/// An error which ocurred during lexical analysis.
|
/// An error which ocurred during lexical analysis.
|
||||||
Lexer(LexerError),
|
Lexer(LexerError),
|
||||||
/// Expected a value for key in map, but no value was found.
|
/// Key in map is missing its corresponding value.
|
||||||
MissingValueInMap,
|
MissingValueInMap,
|
||||||
/// An unexpecting closing parenthesis/brace/bracket was encountered.
|
/// Opening delimiter does not have a matching closing delimiter.
|
||||||
UnexpectedCloseBracket,
|
UnclosedSequence,
|
||||||
/// Unexpectedly reached the end of the input.
|
/// An unexpected closing delimiter was found.
|
||||||
|
UnexpectedClosingDelimiter,
|
||||||
|
/// Unexpectedly reached end of input.
|
||||||
UnexpectedEof,
|
UnexpectedEof,
|
||||||
/// Unexpected parser state reached.
|
/// An unmatched closing delimiter was found.
|
||||||
UnexpectedState,
|
UnmatchedClosingDelimiter,
|
||||||
/// Opening parenthesis/brace/bracket does not have a matching closing
|
|
||||||
/// parenthesis/brace/bracket.
|
|
||||||
UnclosedBracket,
|
|
||||||
/// An unmatched parenthesis/brace/bracket was encountered.
|
|
||||||
UnmatchedBracket,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parser error, with a start and end location.
|
/// Parser error, with a start and end location.
|
||||||
@ -30,13 +27,20 @@ pub struct ParserError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ParserError {
|
impl ParserError {
|
||||||
/// Construct a new instance of `ParserErorr`.
|
/// Construct a new instance of `ParserError`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn new(kind: ParserErrorKind, span: Span) -> Self {
|
pub const fn new(kind: ParserErrorKind, span: Span) -> Self {
|
||||||
Self { kind, span }
|
Self { kind, span }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<LexerError> for ParserError {
|
||||||
|
fn from(err: LexerError) -> Self {
|
||||||
|
let span = err.span.clone();
|
||||||
|
Self::new(ParserErrorKind::Lexer(err), span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::error::Error for ParserError {}
|
impl std::error::Error for ParserError {}
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
@ -46,19 +50,14 @@ impl std::fmt::Display for ParserError {
|
|||||||
|
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
Lexer(err) => write!(f, "{err}"),
|
Lexer(err) => write!(f, "{err}"),
|
||||||
MissingValueInMap => write!(f, "Key in map is missing its value"),
|
MissingValueInMap => write!(f, "Key in map is missing its corresponding value"),
|
||||||
UnexpectedCloseBracket => write!(f, "Unexpected closing bracket"),
|
UnclosedSequence => write!(
|
||||||
UnexpectedEof => write!(f, "Unexpected reached end of input"),
|
f,
|
||||||
UnexpectedState => write!(f, "Unexpected parsing state reached"),
|
"Opening delimiter does not have a matching closing delimiter"
|
||||||
UnclosedBracket => write!(f, "Unclosed bracket"),
|
),
|
||||||
UnmatchedBracket => write!(f, "Unmatched bracket"),
|
UnexpectedClosingDelimiter => write!(f, "An unexpected closing delimiter was found"),
|
||||||
|
UnexpectedEof => write!(f, "Unexpectedly reached end of input"),
|
||||||
|
UnmatchedClosingDelimiter => write!(f, "An unmatched closing delimiter was found"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<LexerError> for ParserError {
|
|
||||||
fn from(err: LexerError) -> Self {
|
|
||||||
let span = err.span.clone();
|
|
||||||
Self::new(ParserErrorKind::Lexer(err), span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,154 +1,154 @@
|
|||||||
pub use self::{
|
use self::{
|
||||||
|
ast::{Ast, Expr, Node},
|
||||||
error::{ParserError, ParserErrorKind},
|
error::{ParserError, ParserErrorKind},
|
||||||
node::{Node, NodeKind},
|
|
||||||
};
|
};
|
||||||
use crate::lexer::{Lexer, TokenKind};
|
use crate::{
|
||||||
|
lexer::{Lexer, TokenKind},
|
||||||
|
span::Span,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod ast;
|
||||||
mod error;
|
mod error;
|
||||||
mod node;
|
|
||||||
|
|
||||||
/// Parser for converting Onihime source code into an Abstract Syntax Tree
|
pub(crate) struct Parser<'parser> {
|
||||||
/// (AST).
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Parser<'parser> {
|
|
||||||
lexer: Lexer<'parser>,
|
lexer: Lexer<'parser>,
|
||||||
|
parents: Vec<Node>,
|
||||||
|
current: Node,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'parser> Parser<'parser> {
|
impl<'parser> Parser<'parser> {
|
||||||
/// Create a new parser instance from a string.
|
/// Create a new parser instance from a string.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(input: &'parser str) -> Self {
|
pub(crate) fn new(input: &'parser str) -> Self {
|
||||||
|
let lexer = Lexer::new(input);
|
||||||
|
let current = Node::new(Expr::List(Vec::new()), lexer.span());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
lexer: Lexer::new(input),
|
lexer,
|
||||||
|
parents: Vec::new(),
|
||||||
|
current,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the name of the lexer's source.
|
/// Set the name of the lexer's source.
|
||||||
pub fn set_name(&mut self, name: String) {
|
pub(crate) fn set_name(&mut self, name: String) {
|
||||||
self.lexer.set_name(name);
|
self.lexer.set_name(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the input string into an AST.
|
/// Produce an Abstract Syntax Tree (AST) from the source input.
|
||||||
pub fn parse(&mut self) -> Result<Vec<Node>, ParserError> {
|
#[must_use]
|
||||||
let mut parents = Vec::new();
|
pub(crate) fn parse(mut self) -> Result<Ast, ParserError> {
|
||||||
let mut cur_node = Node::new(NodeKind::List(Vec::new()), self.lexer.span());
|
// This parser is actually quite simple!Recursively parse expressions until we
|
||||||
|
// run out of tokens, or an error occurs:
|
||||||
while let Some(token) = self.lexer.read()? {
|
while !self.lexer.eof() {
|
||||||
match token.kind {
|
if let Some(node) = self.expr()? {
|
||||||
TokenKind::BlockComment(_) | TokenKind::LineComment(_) => {}
|
self.current.push_node(node);
|
||||||
|
|
||||||
TokenKind::OpenParen => {
|
|
||||||
let child = Node::new(NodeKind::List(Vec::new()), token.span);
|
|
||||||
parents.push(cur_node);
|
|
||||||
cur_node = child;
|
|
||||||
}
|
|
||||||
TokenKind::CloseParen => {
|
|
||||||
let mut parent = parents.pop().ok_or_else(|| {
|
|
||||||
ParserError::new(
|
|
||||||
ParserErrorKind::UnexpectedCloseBracket,
|
|
||||||
token.span.clone(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
cur_node.span.extend(&token.span);
|
|
||||||
|
|
||||||
if !matches!(cur_node.kind, NodeKind::List(_)) {
|
|
||||||
return Err(ParserError::new(
|
|
||||||
ParserErrorKind::UnmatchedBracket,
|
|
||||||
token.span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.push_node(cur_node)?;
|
|
||||||
cur_node = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
TokenKind::OpenBrace => {
|
|
||||||
let child = Node::new(NodeKind::Set(Vec::new()), token.span);
|
|
||||||
parents.push(cur_node);
|
|
||||||
cur_node = child;
|
|
||||||
}
|
|
||||||
TokenKind::OpenHashBrace => {
|
|
||||||
let child = Node::new(NodeKind::Map(Vec::new()), token.span);
|
|
||||||
parents.push(cur_node);
|
|
||||||
cur_node = child;
|
|
||||||
}
|
|
||||||
TokenKind::CloseBrace => {
|
|
||||||
let mut parent = parents.pop().ok_or_else(|| {
|
|
||||||
ParserError::new(
|
|
||||||
ParserErrorKind::UnexpectedCloseBracket,
|
|
||||||
token.span.clone(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
cur_node.span.extend(&token.span);
|
|
||||||
|
|
||||||
if !matches!(cur_node.kind, NodeKind::Map(_) | NodeKind::Set(_)) {
|
|
||||||
return Err(ParserError::new(
|
|
||||||
ParserErrorKind::UnmatchedBracket,
|
|
||||||
token.span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let NodeKind::Map(ref vec) = cur_node.kind {
|
|
||||||
if vec.len() % 2 != 0 {
|
|
||||||
return Err(ParserError::new(
|
|
||||||
ParserErrorKind::MissingValueInMap,
|
|
||||||
token.span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.push_node(cur_node)?;
|
|
||||||
cur_node = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
TokenKind::OpenBracket => {
|
|
||||||
let child = Node::new(NodeKind::Vector(Vec::new()), token.span);
|
|
||||||
parents.push(cur_node);
|
|
||||||
cur_node = child;
|
|
||||||
}
|
|
||||||
TokenKind::CloseBracket => {
|
|
||||||
let mut parent = parents.pop().ok_or_else(|| {
|
|
||||||
ParserError::new(
|
|
||||||
ParserErrorKind::UnexpectedCloseBracket,
|
|
||||||
token.span.clone(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
cur_node.span.extend(&token.span);
|
|
||||||
|
|
||||||
if !matches!(cur_node.kind, NodeKind::Vector(_)) {
|
|
||||||
return Err(ParserError::new(
|
|
||||||
ParserErrorKind::UnmatchedBracket,
|
|
||||||
token.span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.push_node(cur_node)?;
|
|
||||||
cur_node = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
let node = Node::try_from(token)?;
|
|
||||||
cur_node.push_node(node)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !parents.is_empty() {
|
// When we reach the end of input, there should be no remaining parent nodes; if
|
||||||
|
// there are, that means that there is a missing closing delimiter somewhere:
|
||||||
|
if !self.parents.is_empty() {
|
||||||
return Err(ParserError::new(
|
return Err(ParserError::new(
|
||||||
ParserErrorKind::UnclosedBracket,
|
ParserErrorKind::UnclosedSequence,
|
||||||
cur_node.span,
|
self.current.span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let NodeKind::List(body) = cur_node.kind {
|
// Since we created an initial `Expr::List` node to hold the parsed contents
|
||||||
Ok(body)
|
// (i.e. so that we had something to push nodes to), we can now rip out its guts
|
||||||
|
// and return the newly constructed AST:
|
||||||
|
if let Expr::List(root) = self.current.kind {
|
||||||
|
Ok(Ast::new(root))
|
||||||
} else {
|
} else {
|
||||||
unreachable!() // In theory, at least...
|
unreachable!() // TODO: Is this really true? It should be... right?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn expr(&mut self) -> Result<Option<Node>, ParserError> {
|
||||||
|
if let Some(token) = self.lexer.read()? {
|
||||||
|
match token.kind {
|
||||||
|
// Comments are simply ignored by the parser:
|
||||||
|
TokenKind::BlockComment(_) | TokenKind::LineComment(_) => Ok(None),
|
||||||
|
|
||||||
|
// Any valid opening delimiters begins a new sequence:
|
||||||
|
TokenKind::OpenParen => self.begin_sequence(Expr::List, token.span),
|
||||||
|
TokenKind::OpenHashBrace => self.begin_sequence(Expr::Map, token.span),
|
||||||
|
TokenKind::OpenBrace => self.begin_sequence(Expr::Set, token.span),
|
||||||
|
TokenKind::OpenBracket => self.begin_sequence(Expr::Vector, token.span),
|
||||||
|
|
||||||
|
// Any valid closing delimiters end the current sequence:
|
||||||
|
kind
|
||||||
|
@ (TokenKind::CloseParen | TokenKind::CloseBrace | TokenKind::CloseBracket) => {
|
||||||
|
self.end_sequence(kind, token.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atoms are pushed to the current sequence:
|
||||||
|
_ => {
|
||||||
|
let node = Node::try_from(token)?;
|
||||||
|
let span = node.span.clone();
|
||||||
|
|
||||||
|
self.current.push_node(node);
|
||||||
|
self.current.span.extend(&span);
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(ParserError::new(
|
||||||
|
ParserErrorKind::UnexpectedEof,
|
||||||
|
self.lexer.span(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn begin_sequence(
|
||||||
|
&mut self,
|
||||||
|
init: impl FnOnce(Vec<Node>) -> Expr,
|
||||||
|
span: Span,
|
||||||
|
) -> Result<Option<Node>, ParserError> {
|
||||||
|
self.current.span.extend(&span);
|
||||||
|
self.parents.push(self.current.clone());
|
||||||
|
|
||||||
|
self.current = Node::new(init(Vec::new()), span.clone());
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn end_sequence(&mut self, kind: TokenKind, span: Span) -> Result<Option<Node>, ParserError> {
|
||||||
|
// We will ultimately return the current expression, so clone it and update its
|
||||||
|
// span first:
|
||||||
|
let mut current = self.current.clone();
|
||||||
|
current.span.extend(&span);
|
||||||
|
|
||||||
|
// Update the parser's current node to the previous parent, or return an error
|
||||||
|
// if no parents exist:
|
||||||
|
self.current = self.parents.pop().ok_or_else(|| {
|
||||||
|
ParserError::new(ParserErrorKind::UnexpectedClosingDelimiter, span.clone())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Ensure that the appropriate closing delimiter was found for our current node:
|
||||||
|
if current.kind.closing_delimiter() != Some(kind) {
|
||||||
|
return Err(ParserError::new(
|
||||||
|
ParserErrorKind::UnmatchedClosingDelimiter,
|
||||||
|
span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For maps, ensure that each key has a corresponding value:
|
||||||
|
match current.kind {
|
||||||
|
Expr::Map(ref vec) if vec.len() % 2 != 0 => {
|
||||||
|
return Err(ParserError::new(ParserErrorKind::MissingValueInMap, span));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, return the current node so it can be added to the AST:
|
||||||
|
Ok(Some(current))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -156,8 +156,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
lexer::{LexerError, LexerErrorKind, Symbol},
|
lexer::{LexerError, LexerErrorKind, Symbol},
|
||||||
parser::node::Atom,
|
parser::ast::Atom,
|
||||||
span::Span,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! test {
|
macro_rules! test {
|
||||||
@ -171,7 +170,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test!(empty: "", _src => Ok(vec![]));
|
test!(empty: "", _src => Ok(Ast::default()));
|
||||||
|
|
||||||
test!(error_invalid_number: "(+ 1.2.3)", src => Err(ParserError::new(
|
test!(error_invalid_number: "(+ 1.2.3)", src => Err(ParserError::new(
|
||||||
ParserErrorKind::Lexer(LexerError::new(
|
ParserErrorKind::Lexer(LexerError::new(
|
||||||
@ -181,35 +180,35 @@ mod tests {
|
|||||||
Span::new(3..8, src)
|
Span::new(3..8, src)
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(list: "(+ 1 2) ; sneaky comment :)", src => Ok(vec![
|
test!(list: "(+ 1 2) ; sneaky comment :)", src => Ok(Ast::from(vec![
|
||||||
Node::new(
|
Node::new(
|
||||||
NodeKind::List(vec![
|
Expr::List(vec![
|
||||||
Node::new(Atom::Symbol(Symbol::from("+")).into(), Span::new(1..2, src.clone())),
|
Node::new(Atom::Symbol(Symbol::from("+")).into(), Span::new(1..2, src.clone())),
|
||||||
Node::new(Atom::Integer(1).into(), Span::new(3..4, src.clone())),
|
Node::new(Atom::Integer(1).into(), Span::new(3..4, src.clone())),
|
||||||
Node::new(Atom::Integer(2).into(), Span::new(5..6, src.clone())),
|
Node::new(Atom::Integer(2).into(), Span::new(5..6, src.clone())),
|
||||||
]),
|
]),
|
||||||
Span::new(0..7, src)
|
Span::new(0..7, src)
|
||||||
)
|
)
|
||||||
]));
|
])));
|
||||||
|
|
||||||
test!(error_list_unmatched_bracket: "(]", src => Err(ParserError::new(
|
test!(error_list_unmatched_bracket: "(]", src => Err(ParserError::new(
|
||||||
ParserErrorKind::UnmatchedBracket,
|
ParserErrorKind::UnmatchedClosingDelimiter,
|
||||||
Span::new(1..2, src),
|
Span::new(1..2, src),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(error_list_missing_close_paren: "(true", src => Err(ParserError::new(
|
test!(error_list_missing_close_paren: "(true", src => Err(ParserError::new(
|
||||||
ParserErrorKind::UnclosedBracket,
|
ParserErrorKind::UnclosedSequence,
|
||||||
Span::new(0..1, src),
|
Span::new(0..5, src),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(error_list_unexpected_close_paren: ")", src => Err(ParserError::new(
|
test!(error_list_unexpected_close_paren: ")", src => Err(ParserError::new(
|
||||||
ParserErrorKind::UnexpectedCloseBracket,
|
ParserErrorKind::UnexpectedClosingDelimiter,
|
||||||
Span::new(0..1, src)
|
Span::new(0..1, src)
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(map: "#{:a 0.0 :b 1.0}", src => Ok(vec![
|
test!(map: "#{:a 0.0 :b 1.0}", src => Ok(Ast::from(vec![
|
||||||
Node::new(
|
Node::new(
|
||||||
NodeKind::Map(vec![
|
Expr::Map(vec![
|
||||||
Node::new(Atom::Keyword(Symbol::from("a")).into(), Span::new(2..4, src.clone())),
|
Node::new(Atom::Keyword(Symbol::from("a")).into(), Span::new(2..4, src.clone())),
|
||||||
Node::new(Atom::Float(0.0).into(), Span::new(5..8, src.clone())),
|
Node::new(Atom::Float(0.0).into(), Span::new(5..8, src.clone())),
|
||||||
Node::new(Atom::Keyword(Symbol::from("b")).into(), Span::new(9..11, src.clone())),
|
Node::new(Atom::Keyword(Symbol::from("b")).into(), Span::new(9..11, src.clone())),
|
||||||
@ -217,7 +216,7 @@ mod tests {
|
|||||||
]),
|
]),
|
||||||
Span::new(0..16, src)
|
Span::new(0..16, src)
|
||||||
)
|
)
|
||||||
]));
|
])));
|
||||||
|
|
||||||
test!(error_map_missing_value: "#{:x}", src => Err(ParserError::new(
|
test!(error_map_missing_value: "#{:x}", src => Err(ParserError::new(
|
||||||
ParserErrorKind::MissingValueInMap,
|
ParserErrorKind::MissingValueInMap,
|
||||||
@ -225,74 +224,74 @@ mod tests {
|
|||||||
)));
|
)));
|
||||||
|
|
||||||
test!(error_map_unmatched_bracket: "#{)", src => Err(ParserError::new(
|
test!(error_map_unmatched_bracket: "#{)", src => Err(ParserError::new(
|
||||||
ParserErrorKind::UnmatchedBracket,
|
ParserErrorKind::UnmatchedClosingDelimiter,
|
||||||
Span::new(2..3, src),
|
Span::new(2..3, src),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(error_map_missing_close_brace: "#{", src => Err(ParserError::new(
|
test!(error_map_missing_close_brace: "#{", src => Err(ParserError::new(
|
||||||
ParserErrorKind::UnclosedBracket,
|
ParserErrorKind::UnclosedSequence,
|
||||||
Span::new(0..2, src),
|
Span::new(0..2, src),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(set: "{{} nil}", src => Ok(vec![
|
test!(error_map_set_unexpected_close_brace: "}", src => Err(ParserError::new(
|
||||||
|
ParserErrorKind::UnexpectedClosingDelimiter,
|
||||||
|
Span::new(0..1, src)
|
||||||
|
)));
|
||||||
|
|
||||||
|
test!(set: "{{} nil}", src => Ok(Ast::from(vec![
|
||||||
Node::new(
|
Node::new(
|
||||||
NodeKind::Set(vec![
|
Expr::Set(vec![
|
||||||
Node::new(NodeKind::Set(vec![]), Span::new(1..3, src.clone())),
|
Node::new(Expr::Set(vec![]), Span::new(1..3, src.clone())),
|
||||||
Node::new(NodeKind::Atom(Atom::Nil), Span::new(4..7, src.clone())),
|
Node::new(Expr::Atom(Atom::Nil), Span::new(4..7, src.clone())),
|
||||||
]),
|
]),
|
||||||
Span::new(0..8, src),
|
Span::new(0..8, src),
|
||||||
)
|
)
|
||||||
]));
|
])));
|
||||||
|
|
||||||
test!(error_set_unmatched_bracket: "{]", src => Err(ParserError::new(
|
test!(error_set_unmatched_bracket: "{]", src => Err(ParserError::new(
|
||||||
ParserErrorKind::UnmatchedBracket,
|
ParserErrorKind::UnmatchedClosingDelimiter,
|
||||||
Span::new(1..2, src),
|
Span::new(1..2, src),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(error_set_missing_close_brace: "{", src => Err(ParserError::new(
|
test!(error_set_missing_close_brace: "{", src => Err(ParserError::new(
|
||||||
ParserErrorKind::UnclosedBracket,
|
ParserErrorKind::UnclosedSequence,
|
||||||
Span::new(0..1, src),
|
Span::new(0..1, src),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(error_map_set_unexpected_close_brace: "}", src => Err(ParserError::new(
|
test!(vector: "['a' 'b' 'c']", src => Ok(Ast::from(vec![
|
||||||
ParserErrorKind::UnexpectedCloseBracket,
|
|
||||||
Span::new(0..1, src)
|
|
||||||
)));
|
|
||||||
|
|
||||||
test!(vector: "['a' 'b' 'c']", src => Ok(vec![
|
|
||||||
Node::new(
|
Node::new(
|
||||||
NodeKind::Vector(vec![
|
Expr::Vector(vec![
|
||||||
Node::new(NodeKind::Atom(Atom::Char('a')), Span::new(1..4, src.clone())),
|
Node::new(Expr::Atom(Atom::Char('a')), Span::new(1..4, src.clone())),
|
||||||
Node::new(NodeKind::Atom(Atom::Char('b')), Span::new(5..8, src.clone())),
|
Node::new(Expr::Atom(Atom::Char('b')), Span::new(5..8, src.clone())),
|
||||||
Node::new(NodeKind::Atom(Atom::Char('c')), Span::new(9..12, src.clone())),
|
Node::new(Expr::Atom(Atom::Char('c')), Span::new(9..12, src.clone())),
|
||||||
]),
|
]),
|
||||||
Span::new(0..13, src),
|
Span::new(0..13, src),
|
||||||
)
|
)
|
||||||
]));
|
])));
|
||||||
|
|
||||||
test!(error_vector_unmatched_bracket: "[}", src => Err(ParserError::new(
|
test!(error_vector_unmatched_bracket: "[}", src => Err(ParserError::new(
|
||||||
ParserErrorKind::UnmatchedBracket,
|
ParserErrorKind::UnmatchedClosingDelimiter,
|
||||||
Span::new(1..2, src),
|
Span::new(1..2, src),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(error_vector_missing_close_bracket: "{", src => Err(ParserError::new(
|
test!(error_vector_missing_close_bracket: "[", src => Err(ParserError::new(
|
||||||
ParserErrorKind::UnclosedBracket,
|
ParserErrorKind::UnclosedSequence,
|
||||||
Span::new(0..1, src),
|
Span::new(0..1, src),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(error_vector_unexpected_close_bracket: "]", src => Err(ParserError::new(
|
test!(error_vector_unexpected_close_bracket: "]", src => Err(ParserError::new(
|
||||||
ParserErrorKind::UnexpectedCloseBracket,
|
ParserErrorKind::UnexpectedClosingDelimiter,
|
||||||
Span::new(0..1, src)
|
Span::new(0..1, src)
|
||||||
)));
|
)));
|
||||||
|
|
||||||
test!(multiple_expressions: "(/ 6 3 (+ 1 2)) (* 2 5)\n(- 10 5)", src => Ok(vec![
|
test!(multiple_expressions: "(/ 6 3 (+ 1 2)) (* 2 5)\n(- 10 5)", src => Ok(Ast::from(vec![
|
||||||
Node::new(
|
Node::new(
|
||||||
NodeKind::List(vec![
|
Expr::List(vec![
|
||||||
Node::new(Atom::Symbol(Symbol::from("/")).into(), Span::new(1..2, src.clone())),
|
Node::new(Atom::Symbol(Symbol::from("/")).into(), Span::new(1..2, src.clone())),
|
||||||
Node::new(Atom::Integer(6).into(), Span::new(3..4, src.clone())),
|
Node::new(Atom::Integer(6).into(), Span::new(3..4, src.clone())),
|
||||||
Node::new(Atom::Integer(3).into(), Span::new(5..6, src.clone())),
|
Node::new(Atom::Integer(3).into(), Span::new(5..6, src.clone())),
|
||||||
Node::new(
|
Node::new(
|
||||||
NodeKind::List(vec![
|
Expr::List(vec![
|
||||||
Node::new(Atom::Symbol(Symbol::from("+")).into(), Span::new(8..9, src.clone())),
|
Node::new(Atom::Symbol(Symbol::from("+")).into(), Span::new(8..9, src.clone())),
|
||||||
Node::new(Atom::Integer(1).into(), Span::new(10..11, src.clone())),
|
Node::new(Atom::Integer(1).into(), Span::new(10..11, src.clone())),
|
||||||
Node::new(Atom::Integer(2).into(), Span::new(12..13, src.clone())),
|
Node::new(Atom::Integer(2).into(), Span::new(12..13, src.clone())),
|
||||||
@ -303,7 +302,7 @@ mod tests {
|
|||||||
Span::new(0..15, src.clone())
|
Span::new(0..15, src.clone())
|
||||||
),
|
),
|
||||||
Node::new(
|
Node::new(
|
||||||
NodeKind::List(vec![
|
Expr::List(vec![
|
||||||
Node::new(Atom::Symbol(Symbol::from("*")).into(), Span::new(17..18, src.clone())),
|
Node::new(Atom::Symbol(Symbol::from("*")).into(), Span::new(17..18, src.clone())),
|
||||||
Node::new(Atom::Integer(2).into(), Span::new(19..20, src.clone())),
|
Node::new(Atom::Integer(2).into(), Span::new(19..20, src.clone())),
|
||||||
Node::new(Atom::Integer(5).into(), Span::new(21..22, src.clone())),
|
Node::new(Atom::Integer(5).into(), Span::new(21..22, src.clone())),
|
||||||
@ -311,21 +310,21 @@ mod tests {
|
|||||||
Span::new(16..23, src.clone())
|
Span::new(16..23, src.clone())
|
||||||
),
|
),
|
||||||
Node::new(
|
Node::new(
|
||||||
NodeKind::List(vec![
|
Expr::List(vec![
|
||||||
Node::new(Atom::Symbol(Symbol::from("-")).into(), Span::new(25..26, src.clone())),
|
Node::new(Atom::Symbol(Symbol::from("-")).into(), Span::new(25..26, src.clone())),
|
||||||
Node::new(Atom::Integer(10).into(), Span::new(27..29, src.clone())),
|
Node::new(Atom::Integer(10).into(), Span::new(27..29, src.clone())),
|
||||||
Node::new(Atom::Integer(5).into(), Span::new(30..31, src.clone())),
|
Node::new(Atom::Integer(5).into(), Span::new(30..31, src.clone())),
|
||||||
]),
|
]),
|
||||||
Span::new(24..32, src)
|
Span::new(24..32, src)
|
||||||
),
|
),
|
||||||
]));
|
])));
|
||||||
|
|
||||||
test!(function_application: "(join \"foo\" \"bar\")", src => Ok(vec![Node::new(
|
test!(function_application: "(join \"foo\" \"bar\")", src => Ok(Ast::from(vec![Node::new(
|
||||||
NodeKind::List(vec![
|
Expr::List(vec![
|
||||||
Node::new(Atom::Symbol(Symbol::from("join")).into(), Span::new(1..5, src.clone())),
|
Node::new(Atom::Symbol(Symbol::from("join")).into(), Span::new(1..5, src.clone())),
|
||||||
Node::new(Atom::String("foo".into()).into(), Span::new(6..11, src.clone())),
|
Node::new(Atom::String("foo".into()).into(), Span::new(6..11, src.clone())),
|
||||||
Node::new(Atom::String("bar".into()).into(), Span::new(12..17, src.clone())),
|
Node::new(Atom::String("bar".into()).into(), Span::new(12..17, src.clone())),
|
||||||
]),
|
]),
|
||||||
Span::new(0..18, src)
|
Span::new(0..18, src)
|
||||||
)]));
|
)])));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user